From 2409d5a36e074fe237a734fa2053867fe62b5e01 Mon Sep 17 00:00:00 2001 From: alexeib Date: Fri, 23 Oct 2020 00:05:52 -0700 Subject: [PATCH 001/774] =?UTF-8?q?refactor=20dataclass=20related=20files,?= =?UTF-8?q?=20add=20proper=20types=20for=20static=20checkin=E2=80=A6=20(#1?= =?UTF-8?q?371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - refactor dataclass/ hierarchy to make it a bit more sane (while avoiding circular references) - add top level FairseqConfig - change typehints to reflect the correct config type if it is known Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1371 Reviewed By: myleott Differential Revision: D24469026 Pulled By: alexeib fbshipit-source-id: 01f68918f761d51ec5216286b8959ad35f41a7b2 --- fairseq/checkpoint_utils.py | 7 +- fairseq/criterions/adaptive_loss.py | 4 +- fairseq/data/indexed_dataset.py | 4 +- fairseq/dataclass/__init__.py | 3 +- .../dataclass/{data_class.py => configs.py} | 242 +++++++----------- fairseq/dataclass/constants.py | 24 +- fairseq/dataclass/initialize.py | 48 ++++ fairseq/dataclass/utils.py | 179 +++++++------ fairseq/distributed_utils.py | 16 +- fairseq/model_parallel/megatron_trainer.py | 4 +- fairseq/optim/bmuf.py | 34 +-- fairseq/options.py | 2 +- fairseq/scoring/tokenizer.py | 2 +- fairseq/trainer.py | 4 +- fairseq_cli/eval_lm.py | 2 +- fairseq_cli/generate.py | 2 +- fairseq_cli/interactive.py | 6 +- fairseq_cli/train.py | 2 +- fairseq_cli/validate.py | 2 +- 19 files changed, 306 insertions(+), 281 deletions(-) rename fairseq/dataclass/{data_class.py => configs.py} (84%) create mode 100644 fairseq/dataclass/initialize.py diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index f8a5855622..fdee84c181 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -13,6 +13,7 @@ from typing import Optional, Union import torch +from fairseq.dataclass.configs import CheckpointConfig, FairseqConfig from fairseq.dataclass.utils import ( convert_namespace_to_omegaconf, overwrite_args_by_name, @@ -26,7 +27,7 @@ logger = logging.getLogger(__name__) -def save_checkpoint(cfg: DictConfig, trainer, epoch_itr, val_loss): +def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): from fairseq import meters # only one worker should attempt to create the required dir @@ -130,7 +131,7 @@ def is_better(a, b): os.remove(old_chk) -def load_checkpoint(cfg: DictConfig, trainer, **passthrough_args): +def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): """ Load a checkpoint and restore the training iterator. @@ -339,7 +340,7 @@ def torch_persistent_save(obj, f): def save_state( filename, - cfg: DictConfig, + cfg: FairseqConfig, model_state_dict, criterion, optimizer, diff --git a/fairseq/criterions/adaptive_loss.py b/fairseq/criterions/adaptive_loss.py index 04832295ec..15ad9a15bf 100644 --- a/fairseq/criterions/adaptive_loss.py +++ b/fairseq/criterions/adaptive_loss.py @@ -11,7 +11,7 @@ from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.constants import DDP_BACKEND_CHOICES -from omegaconf import II, DictConfig +from omegaconf import II @dataclass @@ -31,7 +31,7 @@ def __init__(self, task, sentence_avg): self.sentence_avg = sentence_avg @classmethod - def build_criterion(cls, cfg: DictConfig, task): + def build_criterion(cls, cfg: AdaptiveLossConfig, task): if cfg.ddp_backend == "c10d": raise Exception( "AdaptiveLoss is not compatible with the c10d " diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index 3efecab3a6..827754d848 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -3,13 +3,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import os import shutil import struct from functools import lru_cache import numpy as np import torch +from fairseq.dataclass.constants import DATASET_IMPL_CHOICES from fairseq.data.fasta_dataset import FastaDataset from fairseq.file_io import PathManager @@ -24,7 +24,7 @@ def __best_fitting_dtype(vocab_size=None): def get_available_dataset_impl(): - return ["raw", "lazy", "cached", "mmap", "fasta"] + return list(map(str, DATASET_IMPL_CHOICES)) def infer_dataset_impl(path): diff --git a/fairseq/dataclass/__init__.py b/fairseq/dataclass/__init__.py index 32870814d5..5c9004d3ba 100644 --- a/fairseq/dataclass/__init__.py +++ b/fairseq/dataclass/__init__.py @@ -3,7 +3,8 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from .utils import ChoiceEnum, FairseqDataclass +from .configs import FairseqDataclass +from .constants import ChoiceEnum __all__ = ["FairseqDataclass", "ChoiceEnum"] diff --git a/fairseq/dataclass/data_class.py b/fairseq/dataclass/configs.py similarity index 84% rename from fairseq/dataclass/data_class.py rename to fairseq/dataclass/configs.py index bcb802e651..abcb9c4c48 100644 --- a/fairseq/dataclass/data_class.py +++ b/fairseq/dataclass/configs.py @@ -3,15 +3,14 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import logging import sys -from argparse import Namespace from dataclasses import _MISSING_TYPE, dataclass, field -from typing import Any, Dict, List, Optional, Tuple, Type +from typing import Any, List, Optional import torch -from fairseq.data.indexed_dataset import get_available_dataset_impl + from fairseq.dataclass.constants import ( + DATASET_IMPL_CHOICES, DDP_BACKEND_CHOICES, DISTRIBUTED_WRAPPER_CHOICES, GENERATION_CONSTRAINTS_CHOICES, @@ -20,16 +19,64 @@ PIPELINE_CHECKPOINT_CHOICES, ZERO_SHARDING_CHOICES, ) -from fairseq.dataclass.utils import ChoiceEnum, FairseqDataclass -from fairseq.models import ARCH_MODEL_REGISTRY, MODEL_DATACLASS_REGISTRY -from fairseq.optim.bmuf import FairseqBMUFConfig -from fairseq.registry import REGISTRIES -from fairseq.tasks import TASK_DATACLASS_REGISTRY -from hydra.core.config_store import ConfigStore + from omegaconf import II -logger = logging.getLogger(__name__) +@dataclass +class FairseqDataclass: + """fairseq base dataclass that supported fetching attributes and metas""" + + _name: Optional[str] = None + + @staticmethod + def name(): + return None + + def _get_all_attributes(self) -> List[str]: + return [k for k in self.__dataclass_fields__.keys()] + + def _get_meta( + self, attribute_name: str, meta: str, default: Optional[Any] = None + ) -> Any: + return self.__dataclass_fields__[attribute_name].metadata.get(meta, default) + + def _get_name(self, attribute_name: str) -> str: + return self.__dataclass_fields__[attribute_name].name + + def _get_default(self, attribute_name: str) -> Any: + if hasattr(self, attribute_name): + if str(getattr(self, attribute_name)).startswith("${"): + return str(getattr(self, attribute_name)) + elif str(self.__dataclass_fields__[attribute_name].default).startswith( + "${" + ): + return str(self.__dataclass_fields__[attribute_name].default) + elif ( + getattr(self, attribute_name) + != self.__dataclass_fields__[attribute_name].default + ): + return getattr(self, attribute_name) + + f = self.__dataclass_fields__[attribute_name] + if not isinstance(f.default_factory, _MISSING_TYPE): + return f.default_factory() + return f.default + + def _get_type(self, attribute_name: str) -> Any: + return self.__dataclass_fields__[attribute_name].type + + def _get_help(self, attribute_name: str) -> Any: + return self._get_meta(attribute_name, "help") + + def _get_argparse_const(self, attribute_name: str) -> Any: + return self._get_meta(attribute_name, "argparse_const") + + def _get_argparse_alias(self, attribute_name: str) -> Any: + return self._get_meta(attribute_name, "argparse_alias") + + def _get_choices(self, attribute_name: str) -> Any: + return self._get_meta(attribute_name, "choices") @dataclass @@ -311,7 +358,7 @@ class DatasetConfig(FairseqDataclass): "help": "maximum sequence length in batch will be a multiplier of this value" }, ) - dataset_impl: Optional[ChoiceEnum(get_available_dataset_impl())] = field( + dataset_impl: Optional[DATASET_IMPL_CHOICES] = field( default=None, metadata={"help": "output dataset implementation"} ) data_buffer_size: int = field( @@ -529,6 +576,33 @@ class CheckpointConfig(FairseqDataclass): distributed_rank: int = II("distributed_training.distributed_rank") +@dataclass +class FairseqBMUFConfig(FairseqDataclass): + block_lr: float = field( + default=1, metadata={"help": "block learning rate for bmuf"} + ) + block_momentum: float = field( + default=0.875, metadata={"help": "block momentum for bmuf"} + ) + global_sync_iter: int = field( + default=50, metadata={"help": "Iteration for syncing global model"} + ) + warmup_iterations: int = field( + default=500, metadata={"help": "warmup iterations for model to broadcast"} + ) + use_nbm: bool = field( + default=False, + metadata={"help": "Specify whether you want to use classical BM / Nesterov BM"}, + ) + average_sync: bool = field( + default=False, + metadata={ + "help": "Specify whether you want to average the local momentum after each sync" + }, + ) + distributed_world_size: int = II("distributed_training.distributed_world_size") + + @dataclass class GenerationConfig(FairseqDataclass): beam: int = field( @@ -788,135 +862,15 @@ class InteractiveConfig(FairseqDataclass): ) -CONFIGS = { - "common": CommonConfig, - "common_eval": CommonEvalConfig, - "distributed_training": DistributedTrainingConfig, - "dataset": DatasetConfig, - "optimization": OptimizationConfig, - "checkpoint": CheckpointConfig, - "bmuf": FairseqBMUFConfig, - "generation": GenerationConfig, - "eval_lm": EvalLMConfig, - "interactive": InteractiveConfig, -} - - -def register_module_dataclass( - cs: ConfigStore, registry: Dict[str, Any], group: str -) -> None: - """register dataclasses defined in modules in config store, for example, in migrated tasks, models, etc.""" - # note that if `group == model`, we register all model archs, not the model name. - for k, v in registry.items(): - node_ = v() - node_._name = k - cs.store(name=k, group=group, node=node_, provider="fairseq") - - -def register_hydra_cfg(cs: ConfigStore, name: str = "default") -> None: - """cs: config store instance, register common training configs""" - - for k, v in CONFIGS.items(): - try: - cs.store(name=k, node=v()) - except BaseException: - logger.error(f"{k} - {v()}") - raise - - register_module_dataclass(cs, TASK_DATACLASS_REGISTRY, "task") - register_module_dataclass(cs, MODEL_DATACLASS_REGISTRY, "model") - - for k, v in REGISTRIES.items(): - register_module_dataclass(cs, v["dataclass_registry"], k) - - -def _override_attr( - sub_node: str, data_class: Type[FairseqDataclass], args: Namespace -) -> List[str]: - overrides = [] - - def get_default(f): - if not isinstance(f.default_factory, _MISSING_TYPE): - return f.default_factory() - return f.default - - for k, v in data_class.__dataclass_fields__.items(): - if k.startswith("_"): - # private member, skip - continue - - val = get_default(v) if not hasattr(args, k) else getattr(args, k) - - if val is None: - overrides.append("{}.{}=null".format(sub_node, k)) - elif val == "": - overrides.append("{}.{}=''".format(sub_node, k)) - elif isinstance(val, str): - overrides.append("{}.{}='{}'".format(sub_node, k, val)) - else: - overrides.append("{}.{}={}".format(sub_node, k, val)) - return overrides - - -def migrate_registry( - name, value, registry, args, overrides, deletes, use_name_as_val=False -): - if value in registry: - overrides.append("{}={}".format(name, value)) - overrides.append("{}._name={}".format(name, value)) - overrides.extend(_override_attr(name, registry[value], args)) - elif use_name_as_val and value is not None: - overrides.append("{}={}".format(name, value)) - else: - deletes.append(name) - - -def override_module_args(args: Namespace) -> Tuple[List[str], List[str]]: - """use the field in args to overrides those in cfg""" - overrides = [] - deletes = [] - - for k, v in CONFIGS.items(): - overrides.extend(_override_attr(k, v, args)) - - if args is not None: - if hasattr(args, "task"): - migrate_registry( - "task", args.task, TASK_DATACLASS_REGISTRY, args, overrides, deletes - ) - else: - deletes.append("task") - - # these options will be set to "None" if they have not yet been migrated - # so we can populate them with the entire flat args - CORE_REGISTRIES = {"criterion", "optimizer", "lr_scheduler"} - - for k, v in REGISTRIES.items(): - if hasattr(args, k): - migrate_registry( - k, - getattr(args, k), - v["dataclass_registry"], - args, - overrides, - deletes, - use_name_as_val=k not in CORE_REGISTRIES, - ) - else: - deletes.append(k) - - no_dc = True - if hasattr(args, "arch"): - if args.arch in ARCH_MODEL_REGISTRY: - m_cls = ARCH_MODEL_REGISTRY[args.arch] - dc = getattr(m_cls, "__dataclass", None) - if dc is not None: - overrides.append("model={}".format(args.arch)) - overrides.append("model._name={}".format(args.arch)) - # override model params with those exist in args - overrides.extend(_override_attr("model", dc, args)) - no_dc = False - if no_dc: - deletes.append("model") - - return overrides, deletes +@dataclass +class FairseqConfig(object): + common: CommonConfig = CommonConfig() + common_eval: CommonEvalConfig = CommonEvalConfig() + distributed_training: DistributedTrainingConfig = DistributedTrainingConfig() + dataset: DatasetConfig = DatasetConfig() + optimization: OptimizationConfig = OptimizationConfig() + checkpoint: CheckpointConfig = CheckpointConfig() + bmuf: FairseqBMUFConfig = FairseqBMUFConfig() + generation: GenerationConfig = GenerationConfig() + eval_lm: EvalLMConfig = EvalLMConfig() + interactive: InteractiveConfig = InteractiveConfig() diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 2fd87f5fc4..3eb63ec609 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -3,13 +3,33 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from fairseq.dataclass.utils import ChoiceEnum +from enum import Enum +from typing import List + + +class StrEnum(Enum): + def __str__(self): + return self.value + + def __eq__(self, other: str): + return self.value == other + + def __repr__(self): + return self.value + + +def ChoiceEnum(choices: List[str]): + """return the Enum class used to enforce list of choices""" + return StrEnum("Choices", {k: k for k in choices}) LOG_FORMAT_CHOICES = ChoiceEnum(["json", "none", "simple", "tqdm"]) DDP_BACKEND_CHOICES = ChoiceEnum(["c10d", "no_c10d"]) +DATASET_IMPL_CHOICES = ChoiceEnum(["raw", "lazy", "cached", "mmap", "fasta"]) DISTRIBUTED_WRAPPER_CHOICES = ChoiceEnum(["DDP", "SlowMo"]) GENERATION_CONSTRAINTS_CHOICES = ChoiceEnum(["ordered", "unordered"]) -GENERATION_DECODING_FORMAT_CHOICES = ChoiceEnum(["unigram", "ensemble", "vote", "dp", "bs"]) +GENERATION_DECODING_FORMAT_CHOICES = ChoiceEnum( + ["unigram", "ensemble", "vote", "dp", "bs"] +) ZERO_SHARDING_CHOICES = ChoiceEnum(["none", "os"]) PIPELINE_CHECKPOINT_CHOICES = ChoiceEnum(["always", "never", "except_last"]) diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py new file mode 100644 index 0000000000..1f755d9807 --- /dev/null +++ b/fairseq/dataclass/initialize.py @@ -0,0 +1,48 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +from typing import Dict, Any + +from hydra.core.config_store import ConfigStore + +from fairseq.dataclass.configs import FairseqConfig + +from fairseq.models import MODEL_DATACLASS_REGISTRY +from fairseq.tasks import TASK_DATACLASS_REGISTRY +from fairseq.registry import REGISTRIES + + +logger = logging.getLogger(__name__) + + +def register_module_dataclass( + cs: ConfigStore, registry: Dict[str, Any], group: str +) -> None: + """register dataclasses defined in modules in config store, for example, in migrated tasks, models, etc.""" + # note that if `group == model`, we register all model archs, not the model name. + for k, v in registry.items(): + node_ = v() + node_._name = k + cs.store(name=k, group=group, node=node_, provider="fairseq") + + +def register_hydra_cfg(cs: ConfigStore, name: str = "default") -> None: + """cs: config store instance, register common training configs""" + + for k in FairseqConfig.__dataclass_fields__: + v = FairseqConfig.__dataclass_fields__[k].default + try: + cs.store(name=k, node=v) + except BaseException: + logger.error(f"{k} - {v}") + raise + + register_module_dataclass(cs, TASK_DATACLASS_REGISTRY, "task") + register_module_dataclass(cs, MODEL_DATACLASS_REGISTRY, "model") + + for k, v in REGISTRIES.items(): + register_module_dataclass(cs, v["dataclass_registry"], k) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 9c501c5b00..8dc51c01f5 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -5,10 +5,12 @@ import ast from argparse import ArgumentError, ArgumentParser, Namespace -from dataclasses import _MISSING_TYPE, MISSING, dataclass +from dataclasses import _MISSING_TYPE, MISSING from enum import Enum -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Tuple, Type +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.configs import FairseqConfig from hydra.core.global_hydra import GlobalHydra from hydra.experimental import compose, initialize from omegaconf import DictConfig, OmegaConf, open_dict @@ -27,78 +29,6 @@ def eval_str_list(x, x_type=float): return [x_type(x)] -class StrEnum(Enum): - def __str__(self): - return self.value - - def __eq__(self, other: str): - return self.value == other - - def __repr__(self): - return self.value - - -def ChoiceEnum(choices: List[str]): - """return the Enum class used to enforce list of choices""" - return StrEnum("Choices", {k: k for k in choices}) - - -@dataclass -class FairseqDataclass: - """fairseq base dataclass that supported fetching attributes and metas""" - - _name: Optional[str] = None - - @staticmethod - def name(): - return None - - def _get_all_attributes(self) -> List[str]: - return [k for k in self.__dataclass_fields__.keys()] - - def _get_meta( - self, attribute_name: str, meta: str, default: Optional[Any] = None - ) -> Any: - return self.__dataclass_fields__[attribute_name].metadata.get(meta, default) - - def _get_name(self, attribute_name: str) -> str: - return self.__dataclass_fields__[attribute_name].name - - def _get_default(self, attribute_name: str) -> Any: - if hasattr(self, attribute_name): - if str(getattr(self, attribute_name)).startswith("${"): - return str(getattr(self, attribute_name)) - elif str(self.__dataclass_fields__[attribute_name].default).startswith( - "${" - ): - return str(self.__dataclass_fields__[attribute_name].default) - elif ( - getattr(self, attribute_name) - != self.__dataclass_fields__[attribute_name].default - ): - return getattr(self, attribute_name) - - f = self.__dataclass_fields__[attribute_name] - if not isinstance(f.default_factory, _MISSING_TYPE): - return f.default_factory() - return f.default - - def _get_type(self, attribute_name: str) -> Any: - return self.__dataclass_fields__[attribute_name].type - - def _get_help(self, attribute_name: str) -> Any: - return self._get_meta(attribute_name, "help") - - def _get_argparse_const(self, attribute_name: str) -> Any: - return self._get_meta(attribute_name, "argparse_const") - - def _get_argparse_alias(self, attribute_name: str) -> Any: - return self._get_meta(attribute_name, "argparse_alias") - - def _get_choices(self, attribute_name: str) -> Any: - return self._get_meta(attribute_name, "choices") - - def gen_parser_from_dataclass( parser: ArgumentParser, dataclass_instance: FairseqDataclass, @@ -241,8 +171,107 @@ def _set_legacy_defaults(args, cls): setattr(args, key, default_value) +def _override_attr( + sub_node: str, data_class: Type[FairseqDataclass], args: Namespace +) -> List[str]: + overrides = [] + + def get_default(f): + if not isinstance(f.default_factory, _MISSING_TYPE): + return f.default_factory() + return f.default + + for k, v in data_class.__dataclass_fields__.items(): + if k.startswith("_"): + # private member, skip + continue + + val = get_default(v) if not hasattr(args, k) else getattr(args, k) + + if val is None: + overrides.append("{}.{}=null".format(sub_node, k)) + elif val == "": + overrides.append("{}.{}=''".format(sub_node, k)) + elif isinstance(val, str): + overrides.append("{}.{}='{}'".format(sub_node, k, val)) + else: + overrides.append("{}.{}={}".format(sub_node, k, val)) + return overrides + + +def migrate_registry( + name, value, registry, args, overrides, deletes, use_name_as_val=False +): + if value in registry: + overrides.append("{}={}".format(name, value)) + overrides.append("{}._name={}".format(name, value)) + overrides.extend(_override_attr(name, registry[value], args)) + elif use_name_as_val and value is not None: + overrides.append("{}={}".format(name, value)) + else: + deletes.append(name) + + +def override_module_args(args: Namespace) -> Tuple[List[str], List[str]]: + """use the field in args to overrides those in cfg""" + overrides = [] + deletes = [] + + for k in FairseqConfig.__dataclass_fields__.keys(): + overrides.extend( + _override_attr(k, FairseqConfig.__dataclass_fields__[k].type, args) + ) + + if args is not None: + if hasattr(args, "task"): + from fairseq.tasks import TASK_DATACLASS_REGISTRY + + migrate_registry( + "task", args.task, TASK_DATACLASS_REGISTRY, args, overrides, deletes + ) + else: + deletes.append("task") + + # these options will be set to "None" if they have not yet been migrated + # so we can populate them with the entire flat args + CORE_REGISTRIES = {"criterion", "optimizer", "lr_scheduler"} + + from fairseq.registry import REGISTRIES + + for k, v in REGISTRIES.items(): + if hasattr(args, k): + migrate_registry( + k, + getattr(args, k), + v["dataclass_registry"], + args, + overrides, + deletes, + use_name_as_val=k not in CORE_REGISTRIES, + ) + else: + deletes.append(k) + + no_dc = True + if hasattr(args, "arch"): + from fairseq.models import ARCH_MODEL_REGISTRY + + if args.arch in ARCH_MODEL_REGISTRY: + m_cls = ARCH_MODEL_REGISTRY[args.arch] + dc = getattr(m_cls, "__dataclass", None) + if dc is not None: + overrides.append("model={}".format(args.arch)) + overrides.append("model._name={}".format(args.arch)) + # override model params with those exist in args + overrides.extend(_override_attr("model", dc, args)) + no_dc = False + if no_dc: + deletes.append("model") + + return overrides, deletes + + def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: - from fairseq.dataclass.data_class import override_module_args # Here we are using field values provided in args to override counterparts inside config object overrides, deletes = override_module_args(args) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 23cdfc6938..83b6d4d9d6 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -18,18 +18,18 @@ import torch import torch.distributed as dist from fairseq import utils -from fairseq.dataclass.utils import convert_namespace_to_omegaconf -from omegaconf import DictConfig, open_dict +from fairseq.dataclass.configs import DistributedTrainingConfig, FairseqConfig +from omegaconf import open_dict logger = logging.getLogger(__name__) -def is_master(cfg: DictConfig): +def is_master(cfg: DistributedTrainingConfig): return cfg.distributed_rank == 0 -def infer_init_method(cfg: DictConfig, force_distributed=False): +def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False): if cfg.distributed_init_method is not None or cfg.tpu: return @@ -197,8 +197,10 @@ def infer_init_method(cfg: DictConfig, force_distributed=False): ) -def distributed_init(cfg: DictConfig): +def distributed_init(cfg: FairseqConfig): if isinstance(cfg, Namespace): + from fairseq.dataclass.utils import convert_namespace_to_omegaconf + cfg = convert_namespace_to_omegaconf(cfg) if not cfg.common.tpu: @@ -265,7 +267,7 @@ def distributed_init(cfg: DictConfig): return cfg.distributed_training.distributed_rank -def distributed_main(i, main, cfg: DictConfig, kwargs): +def distributed_main(i, main, cfg: FairseqConfig, kwargs): cfg.distributed_training.device_id = i if torch.cuda.is_available() and not cfg.common.cpu and not cfg.common.tpu: torch.cuda.set_device(cfg.distributed_training.device_id) @@ -281,7 +283,7 @@ def distributed_main(i, main, cfg: DictConfig, kwargs): main(cfg, **kwargs) -def call_main(cfg: DictConfig, main, **kwargs): +def call_main(cfg: FairseqConfig, main, **kwargs): if cfg.distributed_training.distributed_init_method is None: infer_init_method(cfg.distributed_training) diff --git a/fairseq/model_parallel/megatron_trainer.py b/fairseq/model_parallel/megatron_trainer.py index 258551c933..cf83685862 100644 --- a/fairseq/model_parallel/megatron_trainer.py +++ b/fairseq/model_parallel/megatron_trainer.py @@ -9,7 +9,7 @@ from fairseq import distributed_utils from fairseq.trainer import Trainer -from omegaconf import DictConfig +from fairseq.dataclass.configs import FairseqConfig try: @@ -29,7 +29,7 @@ class MegatronTrainer(Trainer): """Main class for model parallel with data parallel training.""" - def __init__(self, cfg: DictConfig, task, model, criterion, **kwargs): + def __init__(self, cfg: FairseqConfig, task, model, criterion, **kwargs): if not has_megatron_submodule: raise ImportError( "\n\nPlease install the megatron submodule:" diff --git a/fairseq/optim/bmuf.py b/fairseq/optim/bmuf.py index 55f225ba6a..d6d0e04e86 100644 --- a/fairseq/optim/bmuf.py +++ b/fairseq/optim/bmuf.py @@ -7,39 +7,9 @@ import torch import torch.distributed as dist -from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.configs import FairseqBMUFConfig from fairseq.dataclass.utils import gen_parser_from_dataclass from fairseq.optim.fairseq_optimizer import FairseqOptimizer -from omegaconf import II, DictConfig - - -@dataclass -class FairseqBMUFConfig(FairseqDataclass): - block_lr: float = field( - default=1, metadata={"help": "block learning rate for bmuf"} - ) - block_momentum: float = field( - default=0.875, metadata={"help": "block momentum for bmuf"} - ) - global_sync_iter: int = field( - default=50, metadata={"help": "Iteration for syncing global model"} - ) - warmup_iterations: int = field( - default=500, metadata={"help": "warmup iterations for model to broadcast"} - ) - use_nbm: bool = field( - default=False, - metadata={"help": "Specify whether you want to use classical BM / Nesterov BM"}, - ) - average_sync: bool = field( - default=False, - metadata={ - "help": "Specify whether you want to average the local momentum after each sync" - }, - ) - distributed_world_size: int = II( - "distributed_training.distributed_world_size" - ) class FairseqBMUF(FairseqOptimizer): @@ -52,7 +22,7 @@ class FairseqBMUF(FairseqOptimizer): model-update filtering """ - def __init__(self, cfg: DictConfig, optimizer): + def __init__(self, cfg: FairseqBMUFConfig, optimizer): super().__init__(cfg) self._optimizer = optimizer self._num_updates = 0 diff --git a/fairseq/options.py b/fairseq/options.py index 58e5e46190..f2a3e7cfb1 100644 --- a/fairseq/options.py +++ b/fairseq/options.py @@ -9,7 +9,7 @@ import torch from fairseq import utils from fairseq.data.indexed_dataset import get_available_dataset_impl -from fairseq.dataclass.data_class import ( +from fairseq.dataclass.configs import ( CheckpointConfig, CommonConfig, CommonEvalConfig, diff --git a/fairseq/scoring/tokenizer.py b/fairseq/scoring/tokenizer.py index 0d0702bf15..61cf6d4a7c 100644 --- a/fairseq/scoring/tokenizer.py +++ b/fairseq/scoring/tokenizer.py @@ -5,7 +5,7 @@ import unicodedata -from fairseq.dataclass.utils import ChoiceEnum +from fairseq.dataclass import ChoiceEnum class EvaluationTokenizer(object): diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 8b00e8b431..a4d273ca67 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -17,12 +17,12 @@ import torch from fairseq import checkpoint_utils, distributed_utils, models, optim, utils +from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.file_io import PathManager from fairseq.logging import meters, metrics from fairseq.nan_detector import NanDetector from fairseq.optim import lr_scheduler -from omegaconf import DictConfig logger = logging.getLogger(__name__) @@ -38,7 +38,7 @@ class Trainer(object): communication of the gradients across workers. """ - def __init__(self, cfg: DictConfig, task, model, criterion, quantizer=None): + def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): if isinstance(cfg, Namespace): logger.warning( diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index b70c0d3a77..a34e5e096e 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -16,7 +16,7 @@ import torch from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils from fairseq.data import LMContextWindowDataset -from fairseq.dataclass.data_class import register_hydra_cfg +from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar from fairseq.logging.meters import StopwatchMeter, TimeMeter diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index f7260e125e..82c23a3776 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -19,7 +19,7 @@ import torch from fairseq import checkpoint_utils, options, scoring, tasks, utils from fairseq.data import encoders -from fairseq.dataclass.data_class import register_hydra_cfg +from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar from fairseq.logging.meters import StopwatchMeter, TimeMeter diff --git a/fairseq_cli/interactive.py b/fairseq_cli/interactive.py index 85607d8f44..6921f551ca 100644 --- a/fairseq_cli/interactive.py +++ b/fairseq_cli/interactive.py @@ -21,13 +21,13 @@ import torch from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils from fairseq.data import encoders -from fairseq.dataclass.data_class import register_hydra_cfg +from fairseq.dataclass.configs import FairseqConfig +from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.token_generation_constraints import pack_constraints, unpack_constraints from fairseq_cli.generate import get_symbols_to_strip_from_output from hydra.core.config_store import ConfigStore from hydra.experimental import initialize -from omegaconf import DictConfig logging.basicConfig( @@ -115,7 +115,7 @@ def encode_fn_target(x): ) -def main(cfg: DictConfig): +def main(cfg: FairseqConfig): if isinstance(cfg, Namespace): cfg = convert_namespace_to_omegaconf(cfg) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 4c00761060..7e4e4e3071 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -32,7 +32,7 @@ from fairseq.model_parallel.megatron_trainer import MegatronTrainer from omegaconf import DictConfig from hydra.experimental import initialize -from fairseq.dataclass.data_class import register_hydra_cfg +from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.trainer import Trainer diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index 368c9cb581..90c2b84f73 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -13,7 +13,7 @@ import torch from fairseq import checkpoint_utils, distributed_utils, options, utils -from fairseq.dataclass.data_class import register_hydra_cfg +from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import metrics, progress_bar from hydra.core.config_store import ConfigStore From 4b0cf6649bc65093fe2d091ecdd4150bc00ec64f Mon Sep 17 00:00:00 2001 From: Shashank Jain Date: Fri, 23 Oct 2020 14:43:59 -0700 Subject: [PATCH 002/774] Revert "Fix deprecated usage of nonzero()" Summary: Reverting the diff because it has already been fixed in https://github.com/pytorch/pytorch/pull/45413 Reviewed By: myleott Differential Revision: D24511658 fbshipit-source-id: a5561dae50d69a03443ca8a60bebe2cd064e3ee0 --- fairseq/data/mask_tokens_dataset.py | 2 +- fairseq/models/bart/hub_interface.py | 2 +- fairseq/models/roberta/hub_interface.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fairseq/data/mask_tokens_dataset.py b/fairseq/data/mask_tokens_dataset.py index 9e2c7119d8..8ea86245f7 100644 --- a/fairseq/data/mask_tokens_dataset.py +++ b/fairseq/data/mask_tokens_dataset.py @@ -112,7 +112,7 @@ def __getitem__(self, index: int): if self.mask_whole_words is not None: word_begins_mask = self.mask_whole_words.gather(0, item) - word_begins_idx = word_begins_mask.nonzero(as_tuple=False).view(-1) + word_begins_idx = word_begins_mask.nonzero().view(-1) sz = len(word_begins_idx) words = np.split(word_begins_mask, word_begins_idx)[1:] assert len(words) == sz diff --git a/fairseq/models/bart/hub_interface.py b/fairseq/models/bart/hub_interface.py index 819ea8eeda..4c5fd0b585 100644 --- a/fairseq/models/bart/hub_interface.py +++ b/fairseq/models/bart/hub_interface.py @@ -69,7 +69,7 @@ def decode(self, tokens: torch.LongTensor): tokens = tokens[1:] # remove eos_mask = tokens == self.task.source_dictionary.eos() doc_mask = eos_mask[1:] & eos_mask[:-1] - sentences = np.split(tokens, doc_mask.nonzero(as_tuple=False)[0] + 1) + sentences = np.split(tokens, doc_mask.nonzero()[0] + 1) sentences = [ self.bpe.decode(self.task.source_dictionary.string(s)) for s in sentences ] diff --git a/fairseq/models/roberta/hub_interface.py b/fairseq/models/roberta/hub_interface.py index d6322c30e8..0c723f06dd 100644 --- a/fairseq/models/roberta/hub_interface.py +++ b/fairseq/models/roberta/hub_interface.py @@ -71,7 +71,7 @@ def decode(self, tokens: torch.LongTensor): tokens = tokens[1:] # remove eos_mask = tokens == self.task.source_dictionary.eos() doc_mask = eos_mask[1:] & eos_mask[:-1] - sentences = np.split(tokens, doc_mask.nonzero(as_tuple=False)[0] + 1) + sentences = np.split(tokens, doc_mask.nonzero()[0] + 1) sentences = [ self.bpe.decode(self.task.source_dictionary.string(s)) for s in sentences ] @@ -173,7 +173,7 @@ def fill_mask(self, masked_input: str, topk: int = 5): add_if_not_exist=False, ) - masked_index = (tokens == self.task.mask_idx).nonzero(as_tuple=False) + masked_index = (tokens == self.task.mask_idx).nonzero() if tokens.dim() == 1: tokens = tokens.unsqueeze(0) From c147060598f69385a1c2c05bc97dd43b56d73575 Mon Sep 17 00:00:00 2001 From: alexeib Date: Sat, 24 Oct 2020 10:20:07 -0700 Subject: [PATCH 003/774] add new w2v models (#1373) Summary: update readme to add new wav2vec models (incl w/ self training) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1373 Reviewed By: michaelauli Differential Revision: D24524182 Pulled By: alexeib fbshipit-source-id: c918971f8009b11855908e71bfcc247cf6776a8f --- examples/wav2vec/README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 518d8f86cb..22d2225fcd 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -2,6 +2,8 @@ wav2vec 2.0 learns speech representations on unlabeled data as described in [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](https://arxiv.org/abs/2006.11477). +We also combined wav2vec 2.0 with self-training in [Self-training and Pre-training are Complementary for Speech Recognition (Xu et al., 2020)](https://arxiv.org/abs/2010.11430). + ## Pre-trained models Model | Finetuning split | Dataset | Model @@ -14,10 +16,15 @@ Wav2Vec 2.0 Large | No finetuning | [Librispeech](http://www.openslr.org/12) | Wav2Vec 2.0 Large | 10 minutes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_10m.pt) Wav2Vec 2.0 Large | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_100h.pt) Wav2Vec 2.0 Large | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_960h.pt) -Wav2Vec 2.0 Large (LV-60) | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox.pt) -Wav2Vec 2.0 Large (LV-60) | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m.pt) -Wav2Vec 2.0 Large (LV-60) | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h.pt) -Wav2Vec 2.0 Large (LV-60) | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h.pt) +Wav2Vec 2.0 Large (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_new.pt) +Wav2Vec 2.0 Large (LV-60)* | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_new.pt) +Wav2Vec 2.0 Large (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_new.pt) +Wav2Vec 2.0 Large (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_new.pt) +Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_pl.pt) +Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) +Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_pl.pt) + +\* updated (Oct. 24, 2020) ## Training a new model with the CLI tools From 6ee0364685fca0ac5cc2721b193f396166a32646 Mon Sep 17 00:00:00 2001 From: alexeib Date: Sat, 24 Oct 2020 21:18:44 -0700 Subject: [PATCH 004/774] fix building components when no configuration is provided (#1374) Summary: see title, in particular fixes evaluating generate.py with --scoring wer Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1374 Reviewed By: kahne Differential Revision: D24527059 Pulled By: alexeib fbshipit-source-id: b01994441fda12eafd4e465d147047c6e84a8335 --- fairseq/registry.py | 2 ++ fairseq/scoring/__init__.py | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/fairseq/registry.py b/fairseq/registry.py index 4446084d4a..96994cb8d4 100644 --- a/fairseq/registry.py +++ b/fairseq/registry.py @@ -31,6 +31,8 @@ def build_x(cfg: Union[DictConfig, str, Namespace], *extra_args, **extra_kwargs) choice = cfg._name elif isinstance(cfg, str): choice = cfg + if choice in DATACLASS_REGISTRY: + cfg = DATACLASS_REGISTRY[choice]() else: choice = getattr(cfg, registry_name, None) if choice in DATACLASS_REGISTRY: diff --git a/fairseq/scoring/__init__.py b/fairseq/scoring/__init__.py index 8c706cb585..9163be87e7 100644 --- a/fairseq/scoring/__init__.py +++ b/fairseq/scoring/__init__.py @@ -18,10 +18,6 @@ def __init__(self, cfg): self.ref = [] self.pred = [] - @staticmethod - def add_args(parser): - pass - def add_string(self, ref, pred): self.ref.append(ref) self.pred.append(pred) From 3c414780837dd3506ea82a868ea92628d1fdd576 Mon Sep 17 00:00:00 2001 From: alexeib Date: Sun, 25 Oct 2020 12:53:07 -0700 Subject: [PATCH 005/774] fix loading emissions (#1375) Summary: broken in last change to infer.py Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1375 Reviewed By: xuqiantong Differential Revision: D24531499 Pulled By: alexeib fbshipit-source-id: fab60abf67a05c48e1ff750fac3ab6d4c0fa2770 --- examples/speech_recognition/infer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/speech_recognition/infer.py b/examples/speech_recognition/infer.py index 1570177cc6..68889463f4 100644 --- a/examples/speech_recognition/infer.py +++ b/examples/speech_recognition/infer.py @@ -269,6 +269,7 @@ def main(args, task=None, model_state=None): # Load ensemble if args.load_emissions: models, criterions = [], [] + task = tasks.setup_task(args) else: logger.info("| loading model(s) from {}".format(args.path)) models, criterions, task = load_models_and_criterions( @@ -282,6 +283,7 @@ def main(args, task=None, model_state=None): # Load dataset splits task.load_dataset(args.gen_subset) + # Set dictionary tgt_dict = task.target_dictionary From 81677d751de120f69eef0c3eb36e849c977f7814 Mon Sep 17 00:00:00 2001 From: Vladimir Smirnov Date: Mon, 26 Oct 2020 08:17:12 -0700 Subject: [PATCH 006/774] Update README.md (#2796) Summary: Fixed link. # Before submitting - [-] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [+] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [+] Did you make sure to update the docs? - [-] Did you write any new necessary tests? ## What does this PR do? Fixes link. Pull Request resolved: https://github.com/pytorch/fairseq/pull/2796 Reviewed By: nlaptev Differential Revision: D24538759 Pulled By: myleott fbshipit-source-id: af947f432c34ca2aec35c9fe59dd1214e363450b --- examples/wav2vec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 22d2225fcd..1da42f388a 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -22,7 +22,7 @@ Wav2Vec 2.0 Large (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebo Wav2Vec 2.0 Large (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_new.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) -Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_pl.pt) +Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) \* updated (Oct. 24, 2020) From beeac0ad68594b07594f565bfd5cb6f4f46cd816 Mon Sep 17 00:00:00 2001 From: Shruti Bhosale Date: Tue, 27 Oct 2020 02:13:47 -0700 Subject: [PATCH 007/774] Get 12B M2M-100 model generation to work correctly on exactly 2 32gb gpus (#1366) Summary: # What does this PR do? Addresses https://github.com/pytorch/fairseq/issues/2772 where external users can't generate using the model because the README is currently not accurate. This PR fixes the issues in the README Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1366 Reviewed By: edunov Differential Revision: D24455634 Pulled By: shruti-bh fbshipit-source-id: 480a11f8b95d1278162d585700e58d467a35d35a --- examples/m2m_100/README.md | 39 ++++++++++++----- .../pipeline_parallel_transformer/model.py | 42 +++++++------------ 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/examples/m2m_100/README.md b/examples/m2m_100/README.md index a87c0f5748..0bacd4c8b1 100644 --- a/examples/m2m_100/README.md +++ b/examples/m2m_100/README.md @@ -116,11 +116,25 @@ If you use any of the resources listed here, please cite: ## Trained Models -Looking for other trained models? Check back soon. +More models coming up soon. -Model | Description | Download ----|---|--- -`12b_last_checkpoint` | 12B parameter model trained on many-to-many training data for 100 languages | [12b_last_checkpoint](https://dl.fbaipublicfiles.com/m2m_100/12b_last_checkpoint.pt) +### 12B Model +12B parameter model trained on many-to-many training data for 100 languages. We include the last checkpoint, average of last 5 checkpoints, average of last 10 checkpoints. There isn't a universally best choice out of these three, but all three versions are pretty close in accuracy. You can either sweep over the 3 checkpoints on a dev test and use the best performing checkpoint for final testing. Or the last checkpoint can be a good default choice. + +**Model Download Links** +Configuration | 2 32GB GPUs | 4 16GB GPUs | 6 12GB GPUs | 8 8GB GPUs +:--|:--|:--|:--|:-- +Last Checkpoint | [12b_last_chk_2_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_last_chk_2_gpus.pt) | [12b_last_chk_4_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_last_chk_4_gpus.pt) | [12b_last_chk_6_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_last_chk_6_gpus.pt) | [12b_last_chk_8_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_last_chk_8_gpus.pt) +Average of last 5 checkpoints | [12b_avg5_chk_2_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg5_chk_2_gpus.pt) | [12b_avg5_chk_4_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg5_chk_4_gpus.pt) | [12b_avg5_chk_6_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg5_chk_6_gpus.pt) | [12b_avg5_chk_8_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg5_chk_8_gpus.pt) +Average of last 10 checkpoints | [12b_avg10_chk_2_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg10_chk_2_gpus.pt) | [12b_avg10_chk_4_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg10_chk_4_gpus.pt) | [12b_avg10_chk_6_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg10_chk_6_gpus.pt) | [12b_avg10_chk_8_gpus.pt](https://dl.fbaipublicfiles.com/m2m_100/12b_avg10_chk_8_gpus.pt) + +**Generation Arguments** +Configuration | 2 32GB GPUs | 4 16GB GPUs | 6 12GB GPUs | 8 8GB GPUs +:--|:--|:--|:--|:-- +`--pipeline-encoder-balance` | `[26]` | `[1,15,10]` | `[1,9,9,7]` | `[1,6,6,6,7]` +`--pipeline-encoder-devices` | `[0]` | `[0,1,0]` | `[0,1,2,0]` | `[0,4,5,1,0]` +`--pipeline-decoder-balance` | `[3,22,1]` | `[3,11,11,1]` | `[3,7,7,8,1]` | `[1,6,6,6,6,1]` +`--pipeline-decoder-devices` | `[0,1,0]` | `[0,2,3,0]` | `[0,3,4,5,0]` | `[0,2,6,7,3,0]` ## SentencePiece Model @@ -162,16 +176,19 @@ fairseq-preprocess \ --srcdict data_dict.128k.txt --tgtdict data_dict.128k.txt ``` -### Generation on a V100 GPU +### Generation for the 12B model + +Note that generation can currently be run using 2 32GB / 4 16GB / 6 12GB / 8 8GB GPUs, and the corresponding model checkpoints and pipeline arguments can be found in the [12B Model Section](#12b-model). +Generation on CPUs will be added in the future. ```bash wget https://dl.fbaipublicfiles.com/m2m_100/model_dict.128k.txt wget https://dl.fbaipublicfiles.com/m2m_100/language_pairs.txt -wget https://dl.fbaipublicfiles.com/m2m_100/12b_last_checkpoint.pt +wget https://dl.fbaipublicfiles.com/m2m_100/12b_last_chk_4_gpus.pt fairseq-generate \ data_bin \ --batch-size 1 \ - --path 12b_last_checkpoint.pt \ + --path 12b_last_chk_4_gpus.pt \ --fixed-dictionary model_dict.128k.txt \ -s de -t fr \ --remove-bpe 'sentencepiece' \ @@ -185,10 +202,10 @@ fairseq-generate \ --distributed-world-size 1 --distributed-no-spawn \ --pipeline-model-parallel \ --pipeline-chunks 1 \ - --pipeline-encoder-balance '[26]' \ - --pipeline-encoder-devices '[0]' \ - --pipeline-decoder-balance '[1,24,1]' \ - --pipeline-decoder-devices '[0,1,0]' > gen_out + --pipeline-encoder-balance '[1,15,10]' \ + --pipeline-encoder-devices '[0,1,0]' \ + --pipeline-decoder-balance '[3,11,11,1]' \ + --pipeline-decoder-devices '[0,2,3,0]' > gen_out ``` ## Evaluation with M2M-100 diff --git a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py index 76cfe3b0b4..7873611214 100644 --- a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py +++ b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py @@ -111,9 +111,9 @@ def prepare_for_inference_(self, cfg): decoder_module_list.append(module) module_count += 1 self.model = None - self.encoder = TransformerEncoder(cfg.model, None, None, encoder_module_list) + self.encoder = TransformerEncoder(cfg.distributed_training, None, None, encoder_module_list) self.decoder = TransformerDecoder( - cfg.model, None, None, decoder_module_list=decoder_module_list + cfg.distributed_training, None, None, decoder_module_list=decoder_module_list ) @staticmethod @@ -320,7 +320,7 @@ def max_decoder_positions(self): """Maximum length supported by the decoder.""" return self.decoder_max_positions - def load_state_dict(self, state_dict, strict=True, cfg=None): + def load_state_dict(self, state_dict, strict=True, model_cfg=None): """Copies parameters and buffers from *state_dict* into this module and its descendants. @@ -429,17 +429,16 @@ def __init__(self, args, dictionary, embed_tokens, encoder_module_list=None): from fairscale.nn import Pipe except ImportError: raise ImportError("Please install fairscale with: pip install fairscale") - if encoder_module_list is None: - embedding_layer = TransformerEncoderEmbedding(args, embed_tokens) - layers = [TransformerEncoderLayer(args) for i in range(args.encoder_layers)] + self.use_pipeline = encoder_module_list is not None + if not self.use_pipeline: + self.embedding_layer = TransformerEncoderEmbedding(args, embed_tokens) + self.encoder_layers = nn.Sequential(*[TransformerEncoderLayer(args) for i in range(args.encoder_layers)]) if isinstance(embed_tokens, nn.ModuleList): emb_dim = sum(e.embedding_dim for e in embed_tokens) else: emb_dim = embed_tokens.embedding_dim - final_layer_norm = TransformerEncoderLayerNorm(args, emb_dim) - encoder_module_list = [embedding_layer] + layers + [final_layer_norm] - self.use_pipeline = getattr(args, "pipeline_encoder_balance", None) is not None - if self.use_pipeline: + self.final_layer_norm = TransformerEncoderLayerNorm(args, emb_dim) + else: encoder_balance = utils.eval_str_list( args.pipeline_encoder_balance, type=int ) @@ -457,10 +456,6 @@ def __init__(self, args, dictionary, embed_tokens, encoder_module_list=None): chunks=args.pipeline_chunks, checkpoint=args.pipeline_checkpoint, ) - else: - self.embedding_layer = encoder_module_list[0] - self.encoder_layers = nn.Sequential(*encoder_module_list[1:-1]) - self.final_layer_norm = encoder_module_list[-1] def forward(self, src_tokens, src_lengths): """ @@ -570,18 +565,17 @@ def __init__( from fairscale.nn import Pipe except ImportError: raise ImportError("Please install fairscale with: pip install fairscale") - if decoder_module_list is None: - embedding_layer = TransformerDecoderEmbedding(args, embed_tokens) - layers = [ + self.use_pipeline = decoder_module_list is not None + if not self.use_pipeline: + self.embedding_layer = TransformerDecoderEmbedding(args, embed_tokens) + self.decoder_layers = nn.Sequential(*[ TransformerDecoderLayer(args, no_encoder_attn) for _ in range(args.decoder_layers) - ] - decoder_output_layer = TransformerDecoderOutputLayer( + ]) + self.decoder_output_layer = TransformerDecoderOutputLayer( args, embed_tokens, dictionary ) - decoder_module_list = [embedding_layer] + layers + [decoder_output_layer] - self.use_pipeline = getattr(args, "pipeline_decoder_balance", None) is not None - if self.use_pipeline: + else: decoder_balance = utils.eval_str_list( args.pipeline_decoder_balance, type=int ) @@ -599,10 +593,6 @@ def __init__( chunks=args.pipeline_chunks, checkpoint=args.pipeline_checkpoint, ) - else: - self.embedding_layer = decoder_module_list[0] - self.decoder_layers = nn.Sequential(*decoder_module_list[1:-1]) - self.decoder_output_layer = decoder_module_list[-1] def forward( self, From 01be083e46d2e4614dc274b0edf29d0ddd516186 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 27 Oct 2020 07:45:13 -0700 Subject: [PATCH 008/774] Centralize hydra init (and support packaged location of configs) (#2784) Summary: Configs can either be in `/fairseq/configs` (once the package is installed) or `/configs` (if using an editable installation). This centralizes the hydra init and supports these two possible config locations. Pull Request resolved: https://github.com/pytorch/fairseq/pull/2784 Reviewed By: alexeib Differential Revision: D24513586 Pulled By: myleott fbshipit-source-id: 8e10a88177ebcf809d5d37d448d2b384142febef --- fairseq/__init__.py | 4 ++++ fairseq/dataclass/initialize.py | 4 ++-- fairseq/dataclass/utils.py | 19 +++++++++++-------- fairseq_cli/eval_lm.py | 6 ------ fairseq_cli/generate.py | 6 ------ fairseq_cli/interactive.py | 6 ------ fairseq_cli/train.py | 6 ------ fairseq_cli/validate.py | 6 ------ 8 files changed, 17 insertions(+), 40 deletions(-) diff --git a/fairseq/__init__.py b/fairseq/__init__.py index 4ccfc90257..ccd45add79 100644 --- a/fairseq/__init__.py +++ b/fairseq/__init__.py @@ -23,6 +23,10 @@ sys.modules["fairseq.metrics"] = metrics sys.modules["fairseq.progress_bar"] = progress_bar +# initialize hydra +from fairseq.dataclass.initialize import hydra_init +hydra_init() + import fairseq.criterions # noqa import fairseq.models # noqa import fairseq.modules # noqa diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index 1f755d9807..b762af990f 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -30,8 +30,8 @@ def register_module_dataclass( cs.store(name=k, group=group, node=node_, provider="fairseq") -def register_hydra_cfg(cs: ConfigStore, name: str = "default") -> None: - """cs: config store instance, register common training configs""" +def hydra_init() -> None: + cs = ConfigStore.instance() for k in FairseqConfig.__dataclass_fields__: v = FairseqConfig.__dataclass_fields__[k].default diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 8dc51c01f5..5ce017d765 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import ast +import os from argparse import ArgumentError, ArgumentParser, Namespace from dataclasses import _MISSING_TYPE, MISSING from enum import Enum @@ -272,19 +273,21 @@ def override_module_args(args: Namespace) -> Tuple[List[str], List[str]]: def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: + """Convert a flat argparse.Namespace to a structured DictConfig.""" # Here we are using field values provided in args to override counterparts inside config object overrides, deletes = override_module_args(args) - cfg_name = "config" - cfg_path = f"../../{cfg_name}" + # configs will be in fairseq/config after installation + config_path = os.path.join("..", "config") + if not os.path.exists(config_path): + # in case of "--editable" installs we need to go one dir up + config_path = os.path.join("..", "..", "config") - if not GlobalHydra().is_initialized(): - initialize(config_path=cfg_path) - - composed_cfg = compose(cfg_name, overrides=overrides, strict=False) - for k in deletes: - composed_cfg[k] = None + with initialize(config_path=config_path, strict=True): + composed_cfg = compose("config", overrides=overrides, strict=False) + for k in deletes: + composed_cfg[k] = None cfg = OmegaConf.create( OmegaConf.to_container(composed_cfg, resolve=True, enum_to_str=True) diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index a34e5e096e..efc9c4b5aa 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -16,13 +16,10 @@ import torch from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils from fairseq.data import LMContextWindowDataset -from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar from fairseq.logging.meters import StopwatchMeter, TimeMeter from fairseq.sequence_scorer import SequenceScorer -from hydra.core.config_store import ConfigStore -from hydra.experimental import initialize from omegaconf import DictConfig @@ -288,7 +285,4 @@ def cli_main(): if __name__ == "__main__": - cs = ConfigStore.instance() - register_hydra_cfg(cs) - initialize(config_path="../config", strict=True) cli_main() diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 82c23a3776..79b9ed8bf0 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -19,12 +19,9 @@ import torch from fairseq import checkpoint_utils, options, scoring, tasks, utils from fairseq.data import encoders -from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar from fairseq.logging.meters import StopwatchMeter, TimeMeter -from hydra.core.config_store import ConfigStore -from hydra.experimental import initialize from omegaconf import DictConfig @@ -393,7 +390,4 @@ def cli_main(): if __name__ == "__main__": - cs = ConfigStore.instance() - register_hydra_cfg(cs) - initialize(config_path="../config", strict=True) cli_main() diff --git a/fairseq_cli/interactive.py b/fairseq_cli/interactive.py index 6921f551ca..530830d6b0 100644 --- a/fairseq_cli/interactive.py +++ b/fairseq_cli/interactive.py @@ -22,12 +22,9 @@ from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils from fairseq.data import encoders from fairseq.dataclass.configs import FairseqConfig -from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.token_generation_constraints import pack_constraints, unpack_constraints from fairseq_cli.generate import get_symbols_to_strip_from_output -from hydra.core.config_store import ConfigStore -from hydra.experimental import initialize logging.basicConfig( @@ -322,7 +319,4 @@ def cli_main(): if __name__ == "__main__": - cs = ConfigStore.instance() - register_hydra_cfg(cs) - initialize(config_path="../config", strict=True) cli_main() diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 7e4e4e3071..ec10028f03 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -16,7 +16,6 @@ import numpy as np import torch -from hydra.core.config_store import ConfigStore from fairseq import ( checkpoint_utils, @@ -31,8 +30,6 @@ from fairseq.logging import meters, metrics, progress_bar from fairseq.model_parallel.megatron_trainer import MegatronTrainer from omegaconf import DictConfig -from hydra.experimental import initialize -from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.trainer import Trainer @@ -353,7 +350,4 @@ def cli_main(modify_parser: Optional[Callable[[argparse.ArgumentParser], None]] if __name__ == '__main__': - cs = ConfigStore.instance() - register_hydra_cfg(cs) - initialize(config_path="../config", strict=True) cli_main() diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index 90c2b84f73..7315b14e2a 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -13,11 +13,8 @@ import torch from fairseq import checkpoint_utils, distributed_utils, options, utils -from fairseq.dataclass.initialize import register_hydra_cfg from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import metrics, progress_bar -from hydra.core.config_store import ConfigStore -from hydra.experimental import initialize from omegaconf import DictConfig @@ -140,7 +137,4 @@ def cli_main(): if __name__ == "__main__": - cs = ConfigStore.instance() - register_hydra_cfg(cs) - initialize(config_path="../config", strict=True) cli_main() From 1bc83c703ad70d7f62c1e54b197e29b95d07b1f0 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 27 Oct 2020 11:24:58 -0700 Subject: [PATCH 009/774] Misc fixes (#2786) Summary: - Rename type -> key in fairseq/tasks/sentence_prediction.py (fixes https://github.com/pytorch/fairseq/issues/2746) - Update preprocessing docs (fixes https://github.com/pytorch/fairseq/issues/2565) - Turn off logging in test_fp16_optimizer.TestGradientScaling - Documentation updates - Remove some unused code - Fix noisychannel example (fixes https://github.com/pytorch/fairseq/issues/2213) Pull Request resolved: https://github.com/pytorch/fairseq/pull/2786 Reviewed By: shruti-bh Differential Revision: D24515146 Pulled By: myleott fbshipit-source-id: 86b0f5516c57610fdca801c60e58158ef052fc3a --- docs/getting_started.rst | 15 ++++++++++++--- examples/noisychannel/rerank.py | 2 +- examples/noisychannel/rerank_generate.py | 2 +- examples/noisychannel/rerank_score_bw.py | 2 +- examples/noisychannel/rerank_score_lm.py | 2 +- examples/noisychannel/rerank_tune.py | 2 +- examples/roberta/README.md | 1 - fairseq/dataclass/configs.py | 2 +- fairseq/models/roberta/model.py | 5 ++++- fairseq/modules/transformer_layer.py | 9 --------- fairseq/options.py | 8 +++++--- fairseq/tasks/sentence_prediction.py | 10 +++++----- tests/test_fp16_optimizer.py | 5 +++++ 13 files changed, 37 insertions(+), 28 deletions(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index fa5971dd31..d227b95544 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -170,13 +170,14 @@ The easiest way to launch jobs is with the `torch.distributed.launch For example, to train a large English-German Transformer model on 2 nodes each with 8 GPUs (in total 16 GPUs), run the following command on each node, -replacing ``node_rank=0`` with ``node_rank=1`` on the second node: +replacing ``node_rank=0`` with ``node_rank=1`` on the second node and making +sure to update ``--master_addr`` to the IP address of the first node: .. code-block:: console > python -m torch.distributed.launch --nproc_per_node=8 \ --nnodes=2 --node_rank=0 --master_addr="192.168.1.1" \ - --master_port=1234 \ + --master_port=12345 \ $(which fairseq-train) data-bin/wmt16_en_de_bpe32k \ --arch transformer_vaswani_wmt_en_de_big --share-all-embeddings \ --optimizer adam --adam-betas '(0.9, 0.98)' --clip-norm 0.0 \ @@ -184,7 +185,15 @@ replacing ``node_rank=0`` with ``node_rank=1`` on the second node: --lr 0.0005 --min-lr 1e-09 \ --dropout 0.3 --weight-decay 0.0 --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --max-tokens 3584 \ - --fp16 --distributed-no-spawn + --fp16 + +On SLURM clusters, fairseq will automatically detect the number of nodes and +GPUs, but a port number must be provided: + +.. code-block:: console + + > salloc --gpus=16 --nodes 2 (...) + > srun fairseq-train --distributed-port 12345 (...). Sharding very large datasets ---------------------------- diff --git a/examples/noisychannel/rerank.py b/examples/noisychannel/rerank.py index b5ffd1ca34..bb80d11a67 100644 --- a/examples/noisychannel/rerank.py +++ b/examples/noisychannel/rerank.py @@ -11,7 +11,7 @@ from fairseq.data import dictionary from fairseq.scoring import bleu -from . import ( +from examples.noisychannel import ( rerank_generate, rerank_options, rerank_score_bw, diff --git a/examples/noisychannel/rerank_generate.py b/examples/noisychannel/rerank_generate.py index d512088de8..daeeae059a 100644 --- a/examples/noisychannel/rerank_generate.py +++ b/examples/noisychannel/rerank_generate.py @@ -15,7 +15,7 @@ from fairseq import options from fairseq_cli import generate, preprocess -from . import rerank_options, rerank_utils +from examples.noisychannel import rerank_options, rerank_utils def gen_and_reprocess_nbest(args): diff --git a/examples/noisychannel/rerank_score_bw.py b/examples/noisychannel/rerank_score_bw.py index 895673b1cc..b0bc913651 100644 --- a/examples/noisychannel/rerank_score_bw.py +++ b/examples/noisychannel/rerank_score_bw.py @@ -9,7 +9,7 @@ from fairseq import options from fairseq_cli import generate -from . import rerank_options, rerank_utils +from examples.noisychannel import rerank_options, rerank_utils def score_bw(args): diff --git a/examples/noisychannel/rerank_score_lm.py b/examples/noisychannel/rerank_score_lm.py index 89ebf61cce..e80948d78b 100644 --- a/examples/noisychannel/rerank_score_lm.py +++ b/examples/noisychannel/rerank_score_lm.py @@ -7,7 +7,7 @@ from fairseq import options -from . import rerank_options, rerank_utils +from examples.noisychannel import rerank_options, rerank_utils def score_lm(args): diff --git a/examples/noisychannel/rerank_tune.py b/examples/noisychannel/rerank_tune.py index 1be71744a3..b2e8b7594a 100644 --- a/examples/noisychannel/rerank_tune.py +++ b/examples/noisychannel/rerank_tune.py @@ -9,7 +9,7 @@ import numpy as np from fairseq import options -from . import rerank, rerank_options +from examples.noisychannel import rerank, rerank_options def random_search(args): diff --git a/examples/roberta/README.md b/examples/roberta/README.md index fdddd5b8d2..ca86131eea 100644 --- a/examples/roberta/README.md +++ b/examples/roberta/README.md @@ -276,7 +276,6 @@ print('| Accuracy: ', float(ncorrect)/float(nsamples)) - [Finetuning on custom classification tasks (e.g., IMDB)](README.custom_classification.md) - [Finetuning on Winograd Schema Challenge (WSC)](wsc/README.md) - [Finetuning on Commonsense QA (CQA)](commonsense_qa/README.md) -- Finetuning on SQuAD: coming soon ## Pretraining using your own data diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index abcb9c4c48..484d2526d7 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -400,7 +400,7 @@ class DatasetConfig(FairseqDataclass): batch_size_valid: Optional[int] = field( default=None, metadata={ - "help": "batch size of the validation batch" " (defaults to --batch-size)", + "help": "batch size of the validation batch (defaults to --batch-size)", "argparse_alias": "--max-sentences-valid", }, ) diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 5c9f92a149..0f6efe5b33 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -393,6 +393,9 @@ class RobertaEncoder(FairseqEncoder): def __init__(self, args, dictionary): super().__init__(dictionary) + + # set any missing default values + base_architecture(args) self.args = args if args.encoder_layers_to_keep: @@ -417,7 +420,6 @@ def __init__(self, args, dictionary): q_noise=args.quant_noise_pq, qn_block_size=args.quant_noise_pq_block_size, ) - args.untie_weights_roberta = getattr(args, "untie_weights_roberta", False) self.lm_head = RobertaLMHead( embed_dim=args.encoder_embed_dim, @@ -495,6 +497,7 @@ def base_architecture(args): args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) + args.untie_weights_roberta = getattr(args, "untie_weights_roberta", False) args.spectral_norm_classification_head = getattr( args, "spectral_norm_classification_head", False ) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 8775aa7766..6f3c79de7c 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -144,7 +144,6 @@ def forward(self, x, encoder_padding_mask, attn_mask: Optional[Tensor] = None): residual = x if self.normalize_before: x = self.final_layer_norm(x) - x = self.activation_fn(self.fc1(x)) x = self.activation_dropout_module(x) x = self.fc2(x) @@ -413,11 +412,3 @@ def forward( def make_generation_fast_(self, need_attn: bool = False, **kwargs): self.need_attn = need_attn - - -def Linear(in_features, out_features, bias=True): - m = nn.Linear(in_features, out_features, bias) - nn.init.xavier_uniform_(m.weight) - if bias: - nn.init.constant_(m.bias, 0.0) - return m diff --git a/fairseq/options.py b/fairseq/options.py index f2a3e7cfb1..b79443a177 100644 --- a/fairseq/options.py +++ b/fairseq/options.py @@ -249,11 +249,13 @@ def add_preprocess_args(parser): group.add_argument("-t", "--target-lang", default=None, metavar="TARGET", help="target language") group.add_argument("--trainpref", metavar="FP", default=None, - help="train file prefix") + help="train file prefix (also used to build dictionaries)") group.add_argument("--validpref", metavar="FP", default=None, - help="comma separated, valid file prefixes") + help="comma separated, valid file prefixes " + "(words missing from train set are replaced with )") group.add_argument("--testpref", metavar="FP", default=None, - help="comma separated, test file prefixes") + help="comma separated, test file prefixes " + "(words missing from train set are replaced with )") group.add_argument("--align-suffix", metavar="FP", default=None, help="alignment file suffix") group.add_argument("--destdir", metavar="DIR", default="data-bin", diff --git a/fairseq/tasks/sentence_prediction.py b/fairseq/tasks/sentence_prediction.py index 69dc996e6a..0ec3824d04 100644 --- a/fairseq/tasks/sentence_prediction.py +++ b/fairseq/tasks/sentence_prediction.py @@ -135,11 +135,11 @@ def setup_task(cls, args, **kwargs): def load_dataset(self, split, combine=False, **kwargs): """Load a given dataset split (e.g., train, valid, test).""" - def get_path(type, split): - return os.path.join(self.args.data, type, split) + def get_path(key, split): + return os.path.join(self.args.data, key, split) - def make_dataset(type, dictionary): - split_path = get_path(type, split) + def make_dataset(key, dictionary): + split_path = get_path(key, split) dataset = data_utils.load_indexed_dataset( split_path, @@ -151,7 +151,7 @@ def make_dataset(type, dictionary): input0 = make_dataset("input0", self.source_dictionary) assert input0 is not None, "could not find dataset: {}".format( - get_path(type, split) + get_path("input0", split) ) input1 = make_dataset("input1", self.source_dictionary) diff --git a/tests/test_fp16_optimizer.py b/tests/test_fp16_optimizer.py index aa6a863d32..8de8e28ce0 100644 --- a/tests/test_fp16_optimizer.py +++ b/tests/test_fp16_optimizer.py @@ -5,6 +5,7 @@ import argparse import copy +import logging import unittest import torch @@ -46,6 +47,10 @@ def setUp(self): }, } ) + logging.disable(logging.CRITICAL) + + def tearDown(self): + logging.disable(logging.NOTSET) def run_iter(self, model, params, optimizer): optimizer.zero_grad() From 3c726544d240f610cd35ea264d893d6a6ada074a Mon Sep 17 00:00:00 2001 From: Elijah Rippeth Date: Wed, 28 Oct 2020 14:52:54 -0700 Subject: [PATCH 010/774] fix issue where is_initialized is not available in single-worker paradigm (#2801) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/1205 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2801 Reviewed By: alexeib Differential Revision: D24579193 Pulled By: myleott fbshipit-source-id: bcb14bb588d4538398bff4114e0a387fd29818c5 --- fairseq/distributed_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 83b6d4d9d6..0d5804c8f7 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -204,7 +204,7 @@ def distributed_init(cfg: FairseqConfig): cfg = convert_namespace_to_omegaconf(cfg) if not cfg.common.tpu: - if torch.distributed.is_initialized(): + if torch.distributed.is_available() and torch.distributed.is_initialized(): warnings.warn( "Distributed is already initialized, cannot initialize twice!" ) From f6d9313092cf3bc5fa289123b6062b22e463a7da Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 28 Oct 2020 14:58:37 -0700 Subject: [PATCH 011/774] fix eval lm (#1380) Summary: fixes eval lm that wasnt parsing arguments correctly Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1380 Reviewed By: myleott Differential Revision: D24600415 Pulled By: alexeib fbshipit-source-id: eb56575bef4d20a3cd5cee3dcd279046f085d938 --- fairseq_cli/eval_lm.py | 8 ++------ fairseq_cli/validate.py | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index efc9c4b5aa..1197d6987b 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -14,7 +14,7 @@ from argparse import Namespace import torch -from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils +from fairseq import checkpoint_utils, distributed_utils, options, utils from fairseq.data import LMContextWindowDataset from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar @@ -277,11 +277,7 @@ def cli_main(): parser = options.get_eval_lm_parser() args = options.parse_args_and_arch(parser) - # only override args that are explicitly given on the command line - override_parser = options.get_validation_parser() - override_args = options.parse_args_and_arch(override_parser, suppress_defaults=True) - - distributed_utils.call_main(args, main, override_args=override_args) + distributed_utils.call_main(convert_namespace_to_omegaconf(args), main) if __name__ == "__main__": diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index 7315b14e2a..a1e577ed7a 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -133,7 +133,7 @@ def cli_main(): override_parser = options.get_validation_parser() override_args = options.parse_args_and_arch(override_parser, suppress_defaults=True) - distributed_utils.call_main(args, main, override_args=override_args) + distributed_utils.call_main(convert_namespace_to_omegaconf(args), main, override_args=override_args) if __name__ == "__main__": From 65b02d529a45f687da8bbc6ec37611b8a9c96297 Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 28 Oct 2020 17:16:56 -0700 Subject: [PATCH 012/774] fix wav2vec infer and finetuning (#1384) Summary: Fixes #2807, #2810, #2519 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1384 Reviewed By: myleott Differential Revision: D24605451 Pulled By: alexeib fbshipit-source-id: 46ec8f273ac2fab86bd444461e2706c35608b250 --- examples/speech_recognition/w2l_decoder.py | 2 +- fairseq/models/wav2vec/wav2vec2_asr.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/speech_recognition/w2l_decoder.py b/examples/speech_recognition/w2l_decoder.py index 2a1d8a779d..f760cd6df2 100644 --- a/examples/speech_recognition/w2l_decoder.py +++ b/examples/speech_recognition/w2l_decoder.py @@ -34,7 +34,6 @@ SmearingMode, Trie, LexiconDecoder, - LexiconFreeDecoder, ) except: warnings.warn( @@ -404,6 +403,7 @@ def __init__(self, args, tgt_dict): self.unit_lm, ) else: + from wav2letter.decoder import LexiconFreeDecoder self.decoder = LexiconFreeDecoder( self.decoder_opts, self.lm, self.silence, self.blank, [] ) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 52ca9a8007..1cbc6374fb 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -328,7 +328,7 @@ def __init__(self, args, tgt_dict=None): state = checkpoint_utils.load_checkpoint_to_cpu( args.w2v_path, arg_overrides ) - w2v_args = state["args"] + w2v_args = state.get("args", None) or state["cfg"].model else: state = None w2v_args = args.w2v_args From e4e01780f8a087f4a215199ddb83caca2dea16e7 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Wed, 28 Oct 2020 18:17:17 -0700 Subject: [PATCH 013/774] Fix dummy LM task (#1381) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1381 Reviewed By: alexeib Differential Revision: D24603479 Pulled By: myleott fbshipit-source-id: 5aae8da9c0f20d6526c98b0b37bf9b32a8c78393 --- fairseq/benchmark/dummy_lm.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/benchmark/dummy_lm.py b/fairseq/benchmark/dummy_lm.py index 6429d04de3..f3146b3581 100644 --- a/fairseq/benchmark/dummy_lm.py +++ b/fairseq/benchmark/dummy_lm.py @@ -28,6 +28,12 @@ def add_args(parser): help="max number of total tokens over all segments " "per sample for BERT dataset", ) + parser.add_argument("--add-bos-token", action="store_true", help="unused") + parser.add_argument( + "--max-target-positions", + default=None, + help="max number of tokens in the target sequence", + ) def __init__(self, args, dictionary): super().__init__(args) From 9c66ff54c4acd8fa3280a9a5ab6d5fe58d1a2cf3 Mon Sep 17 00:00:00 2001 From: freewym Date: Wed, 28 Oct 2020 18:19:37 -0700 Subject: [PATCH 014/774] =?UTF-8?q?build=5Fgenerator()=20in=20generator.py?= =?UTF-8?q?=20should=20accept=20cfg.generation=20instea=E2=80=A6=20(#2813)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: …d of cfg.task # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2813 Reviewed By: alexeib Differential Revision: D24604698 Pulled By: myleott fbshipit-source-id: e41996147203ec47274ded803bab910460a19eb3 --- fairseq_cli/generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 79b9ed8bf0..021f819ed7 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -163,7 +163,7 @@ def _main(cfg: DictConfig, output_file): extra_gen_cls_kwargs = {"lm_model": lms[0], "lm_weight": cfg.generation.lm_weight} generator = task.build_generator( - models, cfg.task, extra_gen_cls_kwargs=extra_gen_cls_kwargs + models, cfg.generation, extra_gen_cls_kwargs=extra_gen_cls_kwargs ) # Handle tokenization and BPE From b7d8b9dce2dd5ca6a76e1c6f540945da20922478 Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 28 Oct 2020 18:27:53 -0700 Subject: [PATCH 015/774] fix architecture params (#1382) Summary: fixes architectures not getting applied to migrated models Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1382 Reviewed By: myleott Differential Revision: D24603110 Pulled By: alexeib fbshipit-source-id: 18f44d3736853282466feed5e8896db95338b097 --- fairseq/models/fairseq_model.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 15c2c4ab2e..0c8d106be5 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -40,7 +40,8 @@ def add_args(cls, parser): """Add model-specific arguments to the parser.""" dc = getattr(cls, "__dataclass", None) if dc is not None: - gen_parser_from_dataclass(parser, dc()) + # do not set defaults so that settings defaults from various architectures still works + gen_parser_from_dataclass(parser, dc(), delete_default=True) @classmethod def build_model(cls, args, task): From 4cdc81f6f1b16cbb6e1016e3d06a6e4962edcec0 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Wed, 28 Oct 2020 18:34:13 -0700 Subject: [PATCH 016/774] Support activation checkpointing in Transformer (#1378) Summary: Without activation checkpointing (peak GPU memory usage: 7138MiB) ``` $ python train.py --task dummy_mt --arch transformer --dropout 0.1 --max-tokens 4096 --optimizer adam --lr 0.00001 --log-format simple --log-interval 25 --fp16 (...) 2020-10-28 08:03:03 | INFO | train_inner | epoch 001: 25 / 92 loss=12.67, ppl=6517.2, wps=281380, ups=8.61, wpb=32640, bsz=1088, num_updates=25, lr=1e-05, gnorm=8.541, clip=0, loss_scale=128, train_wall=5, wall=10 2020-10-28 08:03:05 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-10-28 08:03:06 | INFO | train_inner | epoch 001: 51 / 92 loss=8.938, ppl=490.52, wps=302975, ups=9.28, wpb=32640, bsz=1088, num_updates=50, lr=1e-05, gnorm=6.395, clip=0, loss_scale=64, train_wall=3, wall=12 2020-10-28 08:03:08 | INFO | train_inner | epoch 001: 76 / 92 loss=3.855, ppl=14.47, wps=316039, ups=9.68, wpb=32640, bsz=1088, num_updates=75, lr=1e-05, gnorm=9.078, clip=0, loss_scale=64, train_wall=3, wall=15 2020-10-28 08:03:10 | INFO | fairseq_cli.train | begin validation on "valid" subset 2020-10-28 08:03:17 | INFO | valid | epoch 001 | valid on 'valid' subset | loss 0.048 | ppl 1.03 | wps 1.09646e+06 | wpb 32640 | bsz 1088 | num_updates 91 ``` With activation checkpointing (peak GPU memory usage: 6466MiB) ``` $ python train.py --checkpoint-activations --task dummy_mt --arch transformer --dropout 0.1 --max-tokens 4096 --optimizer adam --lr 0.00001 --log-format simple --log-interval 25 --fp16 (...) 2020-10-28 08:01:50 | INFO | train_inner | epoch 001: 25 / 92 loss=12.67, ppl=6517.22, wps=291110, ups=8.91, wpb=32640, bsz=1088, num_updates=25, lr=1e-05, gnorm=8.541, clip=0, loss_scale=128, train_wall=4, wall=9 2020-10-28 08:01:51 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-10-28 08:01:52 | INFO | train_inner | epoch 001: 51 / 92 loss=8.938, ppl=490.54, wps=295438, ups=9.05, wpb=32640, bsz=1088, num_updates=50, lr=1e-05, gnorm=6.394, clip=0, loss_scale=64, train_wall=3, wall=12 2020-10-28 08:01:55 | INFO | train_inner | epoch 001: 76 / 92 loss=3.855, ppl=14.47, wps=308351, ups=9.45, wpb=32640, bsz=1088, num_updates=75, lr=1e-05, gnorm=9.082, clip=0, loss_scale=64, train_wall=3, wall=14 2020-10-28 08:01:57 | INFO | fairseq_cli.train | begin validation on "valid" subset ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1378 Reviewed By: min-xu-ai Differential Revision: D24593170 Pulled By: myleott fbshipit-source-id: 701254e603a2277d22f8b3bcc3ebbade54bb7479 --- fairseq/models/transformer.py | 15 +- fairseq/models/transformer_lm.py | 4 + fairseq/modules/checkpoint_activations.py | 205 ++++++++++++++++++++++ fairseq/utils.py | 53 ++++-- 4 files changed, 258 insertions(+), 19 deletions(-) create mode 100644 fairseq/modules/checkpoint_activations.py diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index f87fa50d29..7614c33f74 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -27,6 +27,7 @@ TransformerDecoderLayer, TransformerEncoderLayer, ) +from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ from torch import Tensor @@ -151,6 +152,9 @@ def add_args(parser): help='add layernorm to embedding') parser.add_argument('--no-scale-embedding', action='store_true', help='if True, dont scale embeddings') + parser.add_argument('--checkpoint-activations', action='store_true', + help='checkpoint activations at each layer, which saves GPU ' + 'memory usage at the cost of some additional compute') # args for "Cross+Self-Attention for Transformer Models" (Peitz et al., 2019) parser.add_argument('--no-cross-attention', default=False, action='store_true', help='do not perform cross-attention') @@ -362,7 +366,10 @@ def __init__(self, args, dictionary, embed_tokens): self.layer_norm = None def build_encoder_layer(self, args): - return TransformerEncoderLayer(args) + layer = TransformerEncoderLayer(args) + if getattr(args, "checkpoint_activations", False): + layer = checkpoint_wrapper(layer) + return layer def forward_embedding( self, src_tokens, token_embedding: Optional[torch.Tensor] = None @@ -649,7 +656,10 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): ) def build_decoder_layer(self, args, no_encoder_attn=False): - return TransformerDecoderLayer(args, no_encoder_attn) + layer = TransformerDecoderLayer(args, no_encoder_attn) + if getattr(args, "checkpoint_activations", False): + layer = checkpoint_wrapper(layer) + return layer def forward( self, @@ -961,6 +971,7 @@ def base_architecture(args): args.no_scale_embedding = getattr(args, "no_scale_embedding", False) args.layernorm_embedding = getattr(args, "layernorm_embedding", False) args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) + args.checkpoint_activations = getattr(args, "checkpoint_activations", False) args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) args.decoder_layers_to_keep = getattr(args, "decoder_layers_to_keep", None) diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index df809bdb19..9467b25efd 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -141,6 +141,9 @@ class TransformerLanguageModelConfig(FairseqDataclass): no_scale_embedding: bool = field( default=False, metadata={"help": "if True, dont scale embeddings"} ) + checkpoint_activations: bool = field( + default=False, metadata={"help": "checkpoint activations at each layer"} + ) quant_noise_pq: float = field( default=0.0, metadata={"help": "iterative PQ quantization noise at training time"}, @@ -304,6 +307,7 @@ def base_lm_architecture(args): args.no_scale_embedding = getattr(args, "no_scale_embedding", False) args.layernorm_embedding = getattr(args, "layernorm_embedding", False) + args.checkpoint_activations = getattr(args, "checkpoint_activations", False) @register_model_architecture("transformer_lm", "transformer_lm_big") diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py new file mode 100644 index 0000000000..a4341fe742 --- /dev/null +++ b/fairseq/modules/checkpoint_activations.py @@ -0,0 +1,205 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, Dict, List, Tuple, Union + +import torch + +from fairseq import utils + + +def checkpoint_wrapper(m): + """ + A friendlier wrapper for performing activation checkpointing. + + Compared to the PyTorch version, this version: + - wraps an nn.Module, so that all subsequent calls will use checkpointing + - handles keyword arguments in the forward + - handles non-Tensor outputs from the forward + + Usage:: + + checkpointed_module = checkpoint_wrapper(my_module) + a, b = checkpointed_module(x, y=3, z=torch.Tensor([1])) + """ + original_forward = m.forward + + def _checkpointed_forward(*args, **kwargs): + # Autograd Functions in PyTorch work best with positional args, since + # the backward must return gradients (or None) for every input argument. + # We can flatten keyword arguments to make this easier. + kwarg_keys, flat_args = pack_kwargs(*args, **kwargs) + parent_ctx_dict = {} + output = CheckpointFunction.apply( + original_forward, parent_ctx_dict, kwarg_keys, *flat_args + ) + if isinstance(output, torch.Tensor): + return output + else: + packed_non_tensor_outputs = parent_ctx_dict["packed_non_tensor_outputs"] + if packed_non_tensor_outputs: + output = unpack_non_tensors(output, packed_non_tensor_outputs) + return output + + m.forward = _checkpointed_forward + return m + + +def pack_kwargs(*args, **kwargs) -> Tuple[List[str], List[Any]]: + """ + Usage:: + + kwarg_keys, flat_args = pack_kwargs(1, 2, a=3, b=4) + args, kwargs = unpack_kwargs(kwarg_keys, flat_args) + assert args == [1, 2] + assert kwargs == {"a": 3, "b": 4} + """ + kwarg_keys = [] + flat_args = list(args) + for k, v in kwargs.items(): + kwarg_keys.append(k) + flat_args.append(v) + return kwarg_keys, flat_args + + +def unpack_kwargs( + kwarg_keys: List[str], flat_args: List[Any] +) -> Tuple[List[Any], Dict[str, Any]]: + if len(kwarg_keys) == 0: + return flat_args, {} + args = flat_args[: -len(kwarg_keys)] + kwargs = {k: v for k, v in zip(kwarg_keys, flat_args[-len(kwarg_keys) :])} + return args, kwargs + + +def split_non_tensors( + mixed: Union[torch.Tensor, Tuple[Any]] +) -> Tuple[Tuple[torch.Tensor], Dict[str, List[Any]]]: + """ + Usage:: + + x = torch.Tensor([1]) + y = torch.Tensor([2]) + tensors, packed_non_tensors = split_non_tensors((x, y, None, 3)) + recon = unpack_non_tensors(tensors, packed_non_tensors) + assert recon == (x, y, None, 3) + """ + if isinstance(mixed, torch.Tensor): + return (mixed,), None + assert isinstance(mixed, tuple) + tensors = [] + packed_non_tensors = {"is_tensor": [], "objects": []} + for o in mixed: + if isinstance(o, torch.Tensor): + packed_non_tensors["is_tensor"].append(True) + tensors.append(o) + else: + packed_non_tensors["is_tensor"].append(False) + packed_non_tensors["objects"].append(o) + return tuple(tensors), packed_non_tensors + + +def unpack_non_tensors( + tensors: Tuple[torch.Tensor], + packed_non_tensors: Dict[str, List[Any]], +) -> Tuple[Any]: + if packed_non_tensors is None: + return tensors + assert isinstance(packed_non_tensors, dict) + mixed = [] + is_tensor_list = packed_non_tensors["is_tensor"] + objects = packed_non_tensors["objects"] + assert len(tensors) + len(objects) == len(is_tensor_list) + obj_i = tnsr_i = 0 + for is_tensor in is_tensor_list: + if is_tensor: + mixed.append(tensors[tnsr_i]) + tnsr_i += 1 + else: + mixed.append(objects[obj_i]) + obj_i += 1 + return tuple(mixed) + + +class CheckpointFunction(torch.autograd.Function): + """Similar to the torch version, but support non-Tensor outputs. + + The caller is expected to provide a dict (*parent_ctx_dict*) that will hold + the non-Tensor outputs. These should be combined with the Tensor *outputs* + by calling ``unpack_non_tensors``. + """ + + @staticmethod + def forward(ctx, run_function, parent_ctx_dict, kwarg_keys, *args): + if torch.is_grad_enabled(): # grad may be disabled, e.g., during validation + torch.utils.checkpoint.check_backward_validity(args) + + ctx.run_function = run_function + ctx.kwarg_keys = kwarg_keys + ctx.fwd_rng_state = utils.get_rng_state() + + tensor_inputs, packed_non_tensor_inputs = split_non_tensors(args) + ctx.save_for_backward(*tensor_inputs) + ctx.packed_non_tensor_inputs = packed_non_tensor_inputs + + with torch.no_grad(): + unpacked_args, unpacked_kwargs = unpack_kwargs(kwarg_keys, args) + outputs = run_function(*unpacked_args, **unpacked_kwargs) + + if isinstance(outputs, torch.Tensor): + return outputs + else: + assert isinstance(outputs, tuple) + # Autograd Functions don't like non-Tensor outputs. We can split the + # non-Tensor and Tensor outputs, returning the former by reference + # through *parent_ctx_dict* and returning the latter directly. + outputs, packed_non_tensor_outputs = split_non_tensors(outputs) + parent_ctx_dict["packed_non_tensor_outputs"] = packed_non_tensor_outputs + return outputs + + @staticmethod + def backward(ctx, *args): + if not torch.autograd._is_checkpoint_valid(): + raise RuntimeError( + "Checkpointing is not compatible with .grad(), please use .backward() if possible" + ) + + tensor_inputs = ctx.saved_tensors + tensor_inputs = torch.utils.checkpoint.detach_variable(tensor_inputs) + inputs = unpack_non_tensors(tensor_inputs, ctx.packed_non_tensor_inputs) + + # Store the current states. + bwd_rng_state = utils.get_rng_state() + + # Set the states to what it used to be before the forward pass. + utils.set_rng_state(ctx.fwd_rng_state) + + with torch.enable_grad(): + unpacked_args, unpacked_kwargs = unpack_kwargs(ctx.kwarg_keys, inputs) + outputs = ctx.run_function(*unpacked_args, **unpacked_kwargs) + tensor_outputs, _ = split_non_tensors(outputs) + + # Set the states back to what it was at the start of this function. + utils.set_rng_state(bwd_rng_state) + + # Run backward() with only Tensors that require grad + outputs_with_grad = [] + args_with_grad = [] + for i in range(len(tensor_outputs)): + if tensor_outputs[i].requires_grad: + outputs_with_grad.append(tensor_outputs[i]) + args_with_grad.append(args[i]) + if len(outputs_with_grad) == 0: + raise RuntimeError( + "None of the outputs have requires_grad=True, " + "this checkpoint() is not necessary" + ) + + torch.autograd.backward(outputs_with_grad, args_with_grad) + + grads = tuple( + inp.grad if isinstance(inp, torch.Tensor) else None for inp in inputs + ) + return (None, None, None) + grads diff --git a/fairseq/utils.py b/fairseq/utils.py index 0044d76f3d..a0d8f89b6a 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -32,6 +32,11 @@ except ImportError: multi_tensor_l2norm_available = False +try: + import torch_xla.core.xla_model as xm +except ImportError: + xm = None + logger = logging.getLogger(__name__) @@ -535,23 +540,39 @@ def has_parameters(module): return False -def set_torch_seed(seed): - # Set seed based on args.seed and the update number so that we get - # reproducible results when resuming from checkpoints - assert isinstance(seed, int) - torch.manual_seed(seed) - torch.cuda.manual_seed(seed) +def get_rng_state(): + state = {"torch_rng_state": torch.get_rng_state()} + if xm is not None: + state["xla_rng_state"] = xm.get_rng_state() + if torch.cuda.is_available(): + state["cuda_rng_state"] = torch.cuda.get_rng_state() + return state -@contextlib.contextmanager -def with_torch_seed(seed): - assert isinstance(seed, int) - rng_state = torch.get_rng_state() - cuda_rng_state = torch.cuda.get_rng_state() - set_torch_seed(seed) - yield - torch.set_rng_state(rng_state) - torch.cuda.set_rng_state(cuda_rng_state) +def set_rng_state(state): + torch.set_rng_state(state["torch_rng_state"]) + if xm is not None: + xm.set_rng_state(state["xla_rng_state"]) + if torch.cuda.is_available(): + torch.cuda.set_rng_state(state["cuda_rng_state"]) + + +class set_torch_seed(object): + def __init__(self, seed): + assert isinstance(seed, int) + self.rng_state = get_rng_state() + + torch.manual_seed(seed) + if xm is not None: + xm.set_rng_state(seed) + if torch.cuda.is_available(): + torch.cuda.manual_seed(seed) + + def __enter__(self): + return self + + def __exit__(self, *exc): + set_rng_state(self.rng_state) def parse_alignment(line): @@ -618,8 +639,6 @@ def new_arange(x, *size): def get_tpu_device(args): - import torch_xla.core.xla_model as xm - return xm.xla_device() From 6debe29150204a3a98e61057cebf55e160ccb8b7 Mon Sep 17 00:00:00 2001 From: Anuroop Sriram Date: Thu, 29 Oct 2020 11:44:46 -0700 Subject: [PATCH 017/774] Compute WER for Wav2Vec 2.0 Seq2Seq models (#1376) Summary: # Before submitting - [X] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? ## What does this PR do? Adds support to compute WER for wav2vec2.0 seq2seq models. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1376 Reviewed By: alexeib Differential Revision: D24611516 Pulled By: anuroopsriram fbshipit-source-id: dd7daab73ebccc21367dd51f41a11e89c404977b --- fairseq/tasks/audio_pretraining.py | 102 ++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 298bdbe938..90eb7ca2d6 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -5,12 +5,17 @@ # the root directory of this source tree. An additional grant of patent rights # can be found in the PATENTS file in the same directory. +import editdistance import os import sys +import torch -from fairseq.data import AddTargetDataset, Dictionary, FileAudioDataset +from fairseq.data import AddTargetDataset, Dictionary, FileAudioDataset, encoders +from fairseq.data.data_utils import post_process from . import LegacyFairseqTask, register_task +from .. import utils +from ..logging import metrics class LabelEncoder(object): @@ -68,11 +73,26 @@ def add_args(parser): help="extension of the label file to load, if any", ) + # Options for reporting WER metrics during validation. Only applicable to + # Seq2Seq models during fine-tuning + parser.add_argument( + "--eval-wer", + action="store_true", + help="compute WER for Seq2Seq models", + ) + parser.add_argument( + "--eval-wer-remove-bpe", + default="letter", + help="remove BPE tokens before scoring (can be sentencepiece, letter, and more)", + ) + def __init__(self, args, source_dictionary=None, target_dictionary=None): super().__init__(args) self._target_dictionary = target_dictionary self._source_dictionary = source_dictionary self.is_ctc = args.criterion == "ctc" + if getattr(self.args, "eval_wer", False): + assert args.labels is not None, "eval_wer can only be set during fine-tuning" @classmethod def setup_task(cls, args, **kwargs): @@ -149,3 +169,83 @@ def filter_indices_by_size( ): # we do not need to filter by size in this task as dataloaders take care of this return indices + + def valid_step(self, sample, model, criterion): + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + + if getattr(self.args, "eval_wer", False) and not self.is_ctc: + metrics = self._inference_with_wer(self.sequence_generator, sample, model) + logging_output["_num_char_errors"] = metrics["num_char_errors"] + logging_output["_num_chars"] = metrics["num_chars"] + logging_output["_num_word_errors"] = metrics["num_word_errors"] + logging_output["_num_words"] = metrics["num_words"] + return loss, sample_size, logging_output + + def build_model(self, args): + model = super().build_model(args) + + if getattr(args, 'eval_wer', False) and not self.is_ctc: + self.sequence_generator = self.build_generator([model], args, ) + self.tokenizer = encoders.build_tokenizer(args) + return model + + def _inference_with_wer(self, generator, sample, model): + def decode(toks, escape_unk=True): + s = self.target_dictionary.string( + toks.int().cpu(), + self.args.eval_wer_remove_bpe, + escape_unk=escape_unk, + extra_symbols_to_ignore={generator.eos}, + ) + if self.tokenizer: + s = self.tokenizer.decode(s) + return s + + num_word_errors, num_char_errors = 0, 0 + num_chars, num_words = 0, 0 + gen_out = self.inference_step(generator, [model], sample, None) + for i in range(len(gen_out)): + hyp = decode(gen_out[i][0]["tokens"]) + ref = decode( + utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), + escape_unk=True, + ) + hyp = post_process(hyp, self.args.eval_wer_remove_bpe).strip("_") + ref = post_process(ref, self.args.eval_wer_remove_bpe).strip("_") + num_char_errors += editdistance.eval(hyp, ref) + num_chars += len(ref) + hyp_words = hyp.split("_") + ref_words = ref.split("_") + num_word_errors += editdistance.eval(hyp_words, ref_words) + num_words += len(ref_words) + + return { + "num_char_errors": num_char_errors, + "num_chars": num_chars, + "num_word_errors": num_word_errors, + "num_words": num_words, + } + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + zero = torch.scalar_tensor(0.) + num_char_errors = sum(log.get("_num_char_errors", zero) for log in logging_outputs) + num_chars = sum(log.get("_num_chars", zero) for log in logging_outputs) + num_word_errors = sum(log.get("_num_word_errors", zero) for log in logging_outputs) + num_words = sum(log.get("_num_words", zero) for log in logging_outputs) + metrics.log_scalar("_num_char_errors", num_char_errors) + metrics.log_scalar("_num_chars", num_chars) + metrics.log_scalar("_num_word_errors", num_word_errors) + metrics.log_scalar("_num_words", num_words) + if num_words > 0: + metrics.log_derived( + "uer", + lambda meters: meters["_num_char_errors"].sum * 100.0 / meters["_num_chars"].sum + if meters["_num_chars"].sum > 0 else float("nan") + ) + metrics.log_derived( + "wer", + lambda meters: meters["_num_word_errors"].sum * 100.0 / meters["_num_words"].sum + if meters["_num_words"].sum > 0 else float("nan") + ) From a4356b1da2b19ebd2e1be5c12ff882026ea4d7d2 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Thu, 29 Oct 2020 17:07:12 -0700 Subject: [PATCH 018/774] Simplify --user-dir and require user-dir module name to be globally unique (#2815) Summary: This PR reverts recent changes that attempted to make `--user-dir` work with non-unique module names. But that new approach introduced other issues (e.g., poor compatibility with multiprocessing and Windows), so let's revert to the previous simpler implementation. Pull Request resolved: https://github.com/pytorch/fairseq/pull/2815 Reviewed By: alexeib Differential Revision: D24611571 Pulled By: myleott fbshipit-source-id: cecfe28395585ca0401f844f10bd0d49d014c4d8 --- examples/latent_depth/README.md | 2 +- .../{src => latent_depth_src}/__init__.py | 0 .../loss/__init__.py | 0 .../loss/latent_depth.py | 0 .../models/__init__.py | 0 .../models/latent_multilingual_transformer.py | 0 .../models/latent_transformer.py | 0 .../modules/__init__.py | 0 .../modules/latent_layers.py | 0 .../multilingual_translation_latent_depth.py | 0 examples/linformer/README.md | 2 +- .../{src => linformer_src}/__init__.py | 0 .../{src => linformer_src}/models/__init__.py | 0 .../models/linformer_roberta.py | 0 .../modules/__init__.py | 0 .../modules/linformer_sentence_encoder.py | 0 .../linformer_sentence_encoder_layer.py | 0 .../modules/multihead_linear_attention.py | 0 examples/pointer_generator/README.xsum.md | 4 +-- .../__init__.py | 0 .../transformer_pg.py | 0 examples/rxf/README.md | 2 +- examples/rxf/__init__.py | 2 +- examples/rxf/{src => rxf_src}/__init__.py | 0 .../label_smoothed_cross_entropy_r3f.py | 0 .../sentence_prediction_r3f.py | 0 examples/translation_moe/README.md | 6 ++--- .../{src => translation_moe_src}/__init__.py | 0 .../logsumexp_moe.py | 0 .../mean_pool_gating_network.py | 0 .../translation_moe.py | 0 fairseq/utils.py | 27 ++++++++++--------- tests/test_binaries.py | 26 +++++++++--------- 33 files changed, 37 insertions(+), 34 deletions(-) rename examples/latent_depth/{src => latent_depth_src}/__init__.py (100%) rename examples/latent_depth/{src => latent_depth_src}/loss/__init__.py (100%) rename examples/latent_depth/{src => latent_depth_src}/loss/latent_depth.py (100%) rename examples/latent_depth/{src => latent_depth_src}/models/__init__.py (100%) rename examples/latent_depth/{src => latent_depth_src}/models/latent_multilingual_transformer.py (100%) rename examples/latent_depth/{src => latent_depth_src}/models/latent_transformer.py (100%) rename examples/latent_depth/{src => latent_depth_src}/modules/__init__.py (100%) rename examples/latent_depth/{src => latent_depth_src}/modules/latent_layers.py (100%) rename examples/latent_depth/{src => latent_depth_src}/multilingual_translation_latent_depth.py (100%) rename examples/linformer/{src => linformer_src}/__init__.py (100%) rename examples/linformer/{src => linformer_src}/models/__init__.py (100%) rename examples/linformer/{src => linformer_src}/models/linformer_roberta.py (100%) rename examples/linformer/{src => linformer_src}/modules/__init__.py (100%) rename examples/linformer/{src => linformer_src}/modules/linformer_sentence_encoder.py (100%) rename examples/linformer/{src => linformer_src}/modules/linformer_sentence_encoder_layer.py (100%) rename examples/linformer/{src => linformer_src}/modules/multihead_linear_attention.py (100%) rename examples/pointer_generator/{src => pointer_generator_src}/__init__.py (100%) rename examples/pointer_generator/{src => pointer_generator_src}/transformer_pg.py (100%) rename examples/rxf/{src => rxf_src}/__init__.py (100%) rename examples/rxf/{src => rxf_src}/label_smoothed_cross_entropy_r3f.py (100%) rename examples/rxf/{src => rxf_src}/sentence_prediction_r3f.py (100%) rename examples/translation_moe/{src => translation_moe_src}/__init__.py (100%) rename examples/translation_moe/{src => translation_moe_src}/logsumexp_moe.py (100%) rename examples/translation_moe/{src => translation_moe_src}/mean_pool_gating_network.py (100%) rename examples/translation_moe/{src => translation_moe_src}/translation_moe.py (100%) diff --git a/examples/latent_depth/README.md b/examples/latent_depth/README.md index bc78ca8055..a0ec55a3f6 100644 --- a/examples/latent_depth/README.md +++ b/examples/latent_depth/README.md @@ -14,7 +14,7 @@ lang_pairs_str="eng-aze,eng-bel,eng-ces,eng-glg,eng-por,eng-rus,eng-slk,eng-tur" databin_dir= fairseq-train ${databin_dir} \ - --user-dir, examples/latent_depth/src \ + --user-dir examples/latent_depth/latent_depth_src \ --lang-pairs "${lang_pairs_str}" \ --arch multilingual_transformer_iwslt_de_en \ --task multilingual_translation_latent_depth \ diff --git a/examples/latent_depth/src/__init__.py b/examples/latent_depth/latent_depth_src/__init__.py similarity index 100% rename from examples/latent_depth/src/__init__.py rename to examples/latent_depth/latent_depth_src/__init__.py diff --git a/examples/latent_depth/src/loss/__init__.py b/examples/latent_depth/latent_depth_src/loss/__init__.py similarity index 100% rename from examples/latent_depth/src/loss/__init__.py rename to examples/latent_depth/latent_depth_src/loss/__init__.py diff --git a/examples/latent_depth/src/loss/latent_depth.py b/examples/latent_depth/latent_depth_src/loss/latent_depth.py similarity index 100% rename from examples/latent_depth/src/loss/latent_depth.py rename to examples/latent_depth/latent_depth_src/loss/latent_depth.py diff --git a/examples/latent_depth/src/models/__init__.py b/examples/latent_depth/latent_depth_src/models/__init__.py similarity index 100% rename from examples/latent_depth/src/models/__init__.py rename to examples/latent_depth/latent_depth_src/models/__init__.py diff --git a/examples/latent_depth/src/models/latent_multilingual_transformer.py b/examples/latent_depth/latent_depth_src/models/latent_multilingual_transformer.py similarity index 100% rename from examples/latent_depth/src/models/latent_multilingual_transformer.py rename to examples/latent_depth/latent_depth_src/models/latent_multilingual_transformer.py diff --git a/examples/latent_depth/src/models/latent_transformer.py b/examples/latent_depth/latent_depth_src/models/latent_transformer.py similarity index 100% rename from examples/latent_depth/src/models/latent_transformer.py rename to examples/latent_depth/latent_depth_src/models/latent_transformer.py diff --git a/examples/latent_depth/src/modules/__init__.py b/examples/latent_depth/latent_depth_src/modules/__init__.py similarity index 100% rename from examples/latent_depth/src/modules/__init__.py rename to examples/latent_depth/latent_depth_src/modules/__init__.py diff --git a/examples/latent_depth/src/modules/latent_layers.py b/examples/latent_depth/latent_depth_src/modules/latent_layers.py similarity index 100% rename from examples/latent_depth/src/modules/latent_layers.py rename to examples/latent_depth/latent_depth_src/modules/latent_layers.py diff --git a/examples/latent_depth/src/multilingual_translation_latent_depth.py b/examples/latent_depth/latent_depth_src/multilingual_translation_latent_depth.py similarity index 100% rename from examples/latent_depth/src/multilingual_translation_latent_depth.py rename to examples/latent_depth/latent_depth_src/multilingual_translation_latent_depth.py diff --git a/examples/linformer/README.md b/examples/linformer/README.md index cedd667835..f8b36bc691 100644 --- a/examples/linformer/README.md +++ b/examples/linformer/README.md @@ -6,7 +6,7 @@ This example contains code to train Linformer models as described in our paper ## Training a new Linformer RoBERTa model You can mostly follow the [RoBERTa pretraining README](/examples/roberta/README.pretraining.md), -updating your training command with `--user-dir examples/linformer/src --arch linformer_roberta_base`. +updating your training command with `--user-dir examples/linformer/linformer_src --arch linformer_roberta_base`. ## Citation diff --git a/examples/linformer/src/__init__.py b/examples/linformer/linformer_src/__init__.py similarity index 100% rename from examples/linformer/src/__init__.py rename to examples/linformer/linformer_src/__init__.py diff --git a/examples/linformer/src/models/__init__.py b/examples/linformer/linformer_src/models/__init__.py similarity index 100% rename from examples/linformer/src/models/__init__.py rename to examples/linformer/linformer_src/models/__init__.py diff --git a/examples/linformer/src/models/linformer_roberta.py b/examples/linformer/linformer_src/models/linformer_roberta.py similarity index 100% rename from examples/linformer/src/models/linformer_roberta.py rename to examples/linformer/linformer_src/models/linformer_roberta.py diff --git a/examples/linformer/src/modules/__init__.py b/examples/linformer/linformer_src/modules/__init__.py similarity index 100% rename from examples/linformer/src/modules/__init__.py rename to examples/linformer/linformer_src/modules/__init__.py diff --git a/examples/linformer/src/modules/linformer_sentence_encoder.py b/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py similarity index 100% rename from examples/linformer/src/modules/linformer_sentence_encoder.py rename to examples/linformer/linformer_src/modules/linformer_sentence_encoder.py diff --git a/examples/linformer/src/modules/linformer_sentence_encoder_layer.py b/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py similarity index 100% rename from examples/linformer/src/modules/linformer_sentence_encoder_layer.py rename to examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py diff --git a/examples/linformer/src/modules/multihead_linear_attention.py b/examples/linformer/linformer_src/modules/multihead_linear_attention.py similarity index 100% rename from examples/linformer/src/modules/multihead_linear_attention.py rename to examples/linformer/linformer_src/modules/multihead_linear_attention.py diff --git a/examples/pointer_generator/README.xsum.md b/examples/pointer_generator/README.xsum.md index ab288afc0c..ac3a8c3ddc 100644 --- a/examples/pointer_generator/README.xsum.md +++ b/examples/pointer_generator/README.xsum.md @@ -77,7 +77,7 @@ update_freq=4 pointer_layer=-2 CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 fairseq-train bin \ - --user-dir examples/pointer_generator/src \ + --user-dir examples/pointer_generator/pointer_generator_src \ --max-tokens "$max_tokens" \ --task translation \ --source-lang src --target-lang tgt \ @@ -125,7 +125,7 @@ max_length=60 length_penalty=1.0 fairseq-interactive bin \ - --user-dir examples/pointer_generator/src \ + --user-dir examples/pointer_generator/pointer_generator_src \ --batch-size "$batch_size" \ --task translation \ --source-lang src --target-lang tgt \ diff --git a/examples/pointer_generator/src/__init__.py b/examples/pointer_generator/pointer_generator_src/__init__.py similarity index 100% rename from examples/pointer_generator/src/__init__.py rename to examples/pointer_generator/pointer_generator_src/__init__.py diff --git a/examples/pointer_generator/src/transformer_pg.py b/examples/pointer_generator/pointer_generator_src/transformer_pg.py similarity index 100% rename from examples/pointer_generator/src/transformer_pg.py rename to examples/pointer_generator/pointer_generator_src/transformer_pg.py diff --git a/examples/rxf/README.md b/examples/rxf/README.md index a09de63d33..22a1cc47df 100644 --- a/examples/rxf/README.md +++ b/examples/rxf/README.md @@ -38,7 +38,7 @@ CUDA_VISIBLE_DEVICES=0 fairseq-train RTE-bin \ --find-unused-parameters \ --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric \ --noise-type uniform --r3f-lambda 0.7 \ - --user-dir examples/rxf; + --user-dir examples/rxf/rxf_src ``` ## Citation diff --git a/examples/rxf/__init__.py b/examples/rxf/__init__.py index 63453f9333..b24cb6b797 100644 --- a/examples/rxf/__init__.py +++ b/examples/rxf/__init__.py @@ -3,4 +3,4 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from . import src # noqa +from . import rxf_src # noqa diff --git a/examples/rxf/src/__init__.py b/examples/rxf/rxf_src/__init__.py similarity index 100% rename from examples/rxf/src/__init__.py rename to examples/rxf/rxf_src/__init__.py diff --git a/examples/rxf/src/label_smoothed_cross_entropy_r3f.py b/examples/rxf/rxf_src/label_smoothed_cross_entropy_r3f.py similarity index 100% rename from examples/rxf/src/label_smoothed_cross_entropy_r3f.py rename to examples/rxf/rxf_src/label_smoothed_cross_entropy_r3f.py diff --git a/examples/rxf/src/sentence_prediction_r3f.py b/examples/rxf/rxf_src/sentence_prediction_r3f.py similarity index 100% rename from examples/rxf/src/sentence_prediction_r3f.py rename to examples/rxf/rxf_src/sentence_prediction_r3f.py diff --git a/examples/translation_moe/README.md b/examples/translation_moe/README.md index 33f1bee5cb..ef7abdb44b 100644 --- a/examples/translation_moe/README.md +++ b/examples/translation_moe/README.md @@ -18,7 +18,7 @@ The following command will train a `hMoElp` model with `3` experts: fairseq-train --ddp-backend='no_c10d' \ data-bin/wmt17_en_de \ --max-update 100000 \ - --task translation_moe --user-dir examples/translation_moe/src \ + --task translation_moe --user-dir examples/translation_moe/translation_moe_src \ --method hMoElp --mean-pool-gating-network \ --num-experts 3 \ --arch transformer_wmt_en_de --share-all-embeddings \ @@ -37,7 +37,7 @@ For example, to generate from expert 0: fairseq-generate data-bin/wmt17_en_de \ --path checkpoints/checkpoint_best.pt \ --beam 1 --remove-bpe \ - --task translation_moe --user-dir examples/translation_moe/src \ + --task translation_moe --user-dir examples/translation_moe/translation_moe_src \ --method hMoElp --mean-pool-gating-network \ --num-experts 3 \ --gen-expert 0 @@ -61,7 +61,7 @@ for EXPERT in $(seq 0 2); do \ --beam 1 \ --bpe subword_nmt --bpe-codes $BPE_CODE \ --buffer-size 500 --max-tokens 6000 \ - --task translation_moe --user-dir examples/translation_moe/src \ + --task translation_moe --user-dir examples/translation_moe/translation_moe_src \ --method hMoElp --mean-pool-gating-network \ --num-experts 3 \ --gen-expert $EXPERT ; \ diff --git a/examples/translation_moe/src/__init__.py b/examples/translation_moe/translation_moe_src/__init__.py similarity index 100% rename from examples/translation_moe/src/__init__.py rename to examples/translation_moe/translation_moe_src/__init__.py diff --git a/examples/translation_moe/src/logsumexp_moe.py b/examples/translation_moe/translation_moe_src/logsumexp_moe.py similarity index 100% rename from examples/translation_moe/src/logsumexp_moe.py rename to examples/translation_moe/translation_moe_src/logsumexp_moe.py diff --git a/examples/translation_moe/src/mean_pool_gating_network.py b/examples/translation_moe/translation_moe_src/mean_pool_gating_network.py similarity index 100% rename from examples/translation_moe/src/mean_pool_gating_network.py rename to examples/translation_moe/translation_moe_src/mean_pool_gating_network.py diff --git a/examples/translation_moe/src/translation_moe.py b/examples/translation_moe/translation_moe_src/translation_moe.py similarity index 100% rename from examples/translation_moe/src/translation_moe.py rename to examples/translation_moe/translation_moe_src/translation_moe.py diff --git a/fairseq/utils.py b/fairseq/utils.py index a0d8f89b6a..87c124b736 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -450,18 +450,21 @@ def import_user_module(args): else: raise FileNotFoundError(module_path) - # We want to import the module under a unique name so that it doesn't - # collide with existing modules. At the same time we don't want to - # import the module multiple times. The solution is to create a - # temporary directory and symlink the user_dir under a new name, which is - # a deterministic hash of the original module_path. - with tempfile.TemporaryDirectory() as tmpdirname: - unique_mod_name = "fairseq_user_dir_{}".format(hash(module_path) % 100000) - os.symlink(module_path, os.path.join(tmpdirname, unique_mod_name)) - - sys.path.insert(0, tmpdirname) - importlib.import_module(unique_mod_name) - sys.path.remove(tmpdirname) + # ensure that user modules are only imported once + import_user_module.memo = getattr(import_user_module, "memo", set()) + if module_path not in import_user_module.memo: + import_user_module.memo.add(module_path) + + module_parent, module_name = os.path.split(module_path) + if module_name not in sys.modules: + sys.path.insert(0, module_parent) + importlib.import_module(module_name) + else: + raise ImportError( + "Failed to import --user-dir={} because the corresponding module name " + "({}) is not globally unique. Please rename the directory to " + "something unique and try again.".format(module_path, module_name) + ) def softmax(x, dim: int, onnx_trace: bool = False): diff --git a/tests/test_binaries.py b/tests/test_binaries.py index c6722402a1..ca18adea04 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -320,7 +320,7 @@ def test_multilingual_translation_latent_depth(self): task="multilingual_translation_latent_depth", extra_flags=[ "--user-dir", - "examples/latent_depth/src", + "examples/latent_depth/latent_depth_src", "--encoder-layers", "2", "--decoder-layers", @@ -340,7 +340,7 @@ def test_multilingual_translation_latent_depth(self): run_validation=True, extra_valid_flags=[ "--user-dir", - "examples/latent_depth/src", + "examples/latent_depth/latent_depth_src", ] + enc_ll_flag + dec_ll_flag, @@ -349,7 +349,7 @@ def test_multilingual_translation_latent_depth(self): data_dir, extra_flags=[ "--user-dir", - "examples/latent_depth/src", + "examples/latent_depth/latent_depth_src", "--task", "multilingual_translation_latent_depth", "--lang-pairs", @@ -465,7 +465,7 @@ def test_transformer_pointer_generator(self): "transformer_pointer_generator", extra_flags=[ "--user-dir", - "examples/pointer_generator/src", + "examples/pointer_generator/pointer_generator_src", "--encoder-layers", "2", "--decoder-layers", @@ -482,11 +482,11 @@ def test_transformer_pointer_generator(self): "0", ], run_validation=True, - extra_valid_flags=["--user-dir", "examples/pointer_generator/src"], + extra_valid_flags=["--user-dir", "examples/pointer_generator/pointer_generator_src"], ) generate_main( data_dir, - extra_flags=["--user-dir", "examples/pointer_generator/src"], + extra_flags=["--user-dir", "examples/pointer_generator/pointer_generator_src"], ) def test_lightconv(self): @@ -700,7 +700,7 @@ def test_mixture_of_experts(self): "--task", "translation_moe", "--user-dir", - "examples/translation_moe/src", + "examples/translation_moe/translation_moe_src", "--method", "hMoElp", "--mean-pool-gating-network", @@ -722,7 +722,7 @@ def test_mixture_of_experts(self): "--task", "translation_moe", "--user-dir", - "examples/translation_moe/src", + "examples/translation_moe/translation_moe_src", "--method", "hMoElp", "--mean-pool-gating-network", @@ -1058,7 +1058,7 @@ def test_linformer_roberta_masked_lm(self): "linformer_roberta_base", extra_flags=[ "--user-dir", - "examples/linformer/src", + "examples/linformer/linformer_src", "--encoder-layers", "2", ], @@ -1075,7 +1075,7 @@ def test_linformer_roberta_sentence_prediction(self): data_dir, "linformer_roberta_base", num_classes=num_classes, - extra_flags=["--user-dir", "examples/linformer/src"], + extra_flags=["--user-dir", "examples/linformer/linformer_src"], ) def test_linformer_roberta_regression_single(self): @@ -1095,7 +1095,7 @@ def test_linformer_roberta_regression_single(self): extra_flags=[ "--regression-target", "--user-dir", - "examples/linformer/src", + "examples/linformer/linformer_src", ], ) @@ -1116,7 +1116,7 @@ def test_linformer_roberta_regression_multiple(self): extra_flags=[ "--regression-target", "--user-dir", - "examples/linformer/src", + "examples/linformer/linformer_src", ], ) @@ -1198,7 +1198,7 @@ def test_r4f_roberta(self): num_classes=num_classes, extra_flags=[ "--user-dir", - "examples/rxf/src", + "examples/rxf/rxf_src", "--criterion", "sentence_prediction_r3f", "--spectral-norm-classification-head", From de859692ff39cff1ecfd65e8e6860c621fb0e58a Mon Sep 17 00:00:00 2001 From: Yuqing Tang Date: Fri, 30 Oct 2020 18:23:14 -0700 Subject: [PATCH 019/774] Enable translation_multi_simple_epoch to have different source and target dictionaries Summary: In past, we always use shared dictionary for multilingual experiments. This diff renables different dictionaries for source and target languages by changing the assertion criteria and reverts back to use specific languages to return source_dict and target_dict. Reviewed By: chtran Differential Revision: D24637682 fbshipit-source-id: a982e4f1e48395cc5bf10dc03b98fbe970062f8d --- .../tasks/translation_multi_simple_epoch.py | 32 +++++++---- tests/test_binaries.py | 54 +++++++++++++++++++ 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/fairseq/tasks/translation_multi_simple_epoch.py b/fairseq/tasks/translation_multi_simple_epoch.py index 95a2d162c0..d871502a2c 100644 --- a/fairseq/tasks/translation_multi_simple_epoch.py +++ b/fairseq/tasks/translation_multi_simple_epoch.py @@ -96,25 +96,35 @@ def __init__(self, args, langs, dicts, training): # models.build_model(). This allows multitask type of sub-class can # build models other than the input lang_pairs self.model_lang_pairs = self.lang_pairs + self.source_langs = [d.split("-")[0] for d in self.lang_pairs] + self.target_langs = [d.split("-")[1] for d in self.lang_pairs] + self.check_dicts(self.dicts, self.source_langs, self.target_langs) + self.sampling_method = SamplingMethod.build_sampler(args, self) self.data_manager = MultilingualDatasetManager.setup_data_manager( args, self.lang_pairs, langs, dicts, self.sampling_method ) + @classmethod + def check_dicts(cls, dicts, source_langs, target_langs): + src_dict = dicts[source_langs[0]] + tgt_dict = dicts[target_langs[0]] + for src_lang in source_langs: + assert ( + src_dict == dicts[src_lang] + ), "Diffrent dictionary are specified for different source languages; " + "TranslationMultiSimpleEpochTask only supports one shared dictionary across all source languages" + for tgt_lang in target_langs: + assert ( + tgt_dict == dicts[tgt_lang] + ), "Diffrent dictionary are specified for different target languages; " + "TranslationMultiSimpleEpochTask only supports one shared dictionary across all target languages" + @classmethod def setup_task(cls, args, **kwargs): langs, dicts, training = MultilingualDatasetManager.prepare( cls.load_dictionary, args, **kwargs ) - dict0 = None - for _, lang_dict in dicts.items(): - if dict0 is None: - dict0 = lang_dict - else: - assert ( - dict0 == lang_dict - ), "Diffrent dictionary are specified for different languages; " - "TranslationMultiSimpleEpochTask only supports one shared dictionary across all languages" return cls(args, langs, dicts, training) def has_sharded_data(self, split): @@ -249,11 +259,11 @@ def max_positions(self): @property def source_dictionary(self): - return next(iter(self.dicts.values())) + return self.dicts[self.source_langs[0]] @property def target_dictionary(self): - return next(iter(self.dicts.values())) + return self.dicts[self.target_langs[0]] def create_batch_sampler_func( self, diff --git a/tests/test_binaries.py b/tests/test_binaries.py index ca18adea04..dae38dda0c 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -425,6 +425,60 @@ def test_translation_multi_simple_epoch(self): + dec_ltok_flag, ) + def test_translation_multi_simple_epoch_dicts(self): + # test with all combinations of encoder/decoder lang tokens + with contextlib.redirect_stdout(StringIO()): + enc_ltok_flag = ["--encoder-langtok", "src"] + dec_ltok_flag = ["--decoder-langtok"] + with tempfile.TemporaryDirectory( + "test_translation_multi_simple_epoch_dict" + ) as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data( + data_dir, extra_flags=[] + ) + train_translation_model( + data_dir, + arch="transformer", + task="translation_multi_simple_epoch", + extra_flags=[ + "--encoder-layers", + "2", + "--decoder-layers", + "2", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--sampling-method", + "temperature", + "--sampling-temperature", + "1.5", + "--virtual-epoch-size", + "1000", + ] + + enc_ltok_flag + + dec_ltok_flag, + lang_flags=["--lang-pairs", "in-out"], + run_validation=True, + extra_valid_flags=enc_ltok_flag + dec_ltok_flag, + ) + generate_main( + data_dir, + extra_flags=[ + "--task", + "translation_multi_simple_epoch", + "--lang-pairs", + "in-out", + "--source-lang", + "in", + "--target-lang", + "out", + ] + + enc_ltok_flag + + dec_ltok_flag, + ) + def test_transformer_cross_self_attention(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory( From de977736f91d23c53e6a60c45822973a615daa15 Mon Sep 17 00:00:00 2001 From: Shashank Jain Date: Mon, 2 Nov 2020 17:16:03 -0800 Subject: [PATCH 020/774] Support running batch of sentences together on GPU with BART fill_mask (#2833) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/2833 Add support for filling masks using BART on a batch of sentences. This will be helpful when running on GPU Reviewed By: myleott Differential Revision: D24687773 fbshipit-source-id: 1b8005c18a09be526f40e9e2b99207afa38e0f1a --- examples/bart/README.md | 18 +++++++++---- fairseq/models/bart/hub_interface.py | 38 ++++++++++++++-------------- fairseq/models/bart/model.py | 2 ++ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/examples/bart/README.md b/examples/bart/README.md index 76857a99a2..e891894a84 100644 --- a/examples/bart/README.md +++ b/examples/bart/README.md @@ -100,7 +100,7 @@ bart.predict('mnli', tokens).argmax() # 2: entailment ##### Register a new (randomly initialized) classification head: ```python bart.register_classification_head('new_task', num_classes=3) -logprobs = bart.predict('new_task', tokens) +logprobs = bart.predict('new_task', tokens) ``` ##### Batched prediction: @@ -137,15 +137,23 @@ BART can be used to fill multiple `` tokens in the input. ```python bart = torch.hub.load('pytorch/fairseq', 'bart.base') bart.eval() -bart.fill_mask('The cat on the .', topk=3, beam=10) -# [('The cat was on the ground.', tensor(-0.6183)), ('The cat was on the floor.', tensor(-0.6798)), ('The cat sleeps on the couch.', tensor(-0.6830))] +bart.fill_mask(['The cat on the .'], topk=3, beam=10) +# [[('The cat was on the ground.', tensor(-0.6183)), ('The cat was on the floor.', tensor(-0.6798)), ('The cat sleeps on the couch.', tensor(-0.6830))]] ``` Note that by default we enforce the output length to match the input length. This can be disabled by setting ``match_source_len=False``: ``` -bart.fill_mask('The cat on the .', topk=3, beam=10, match_source_len=False) -# [('The cat was on the ground.', tensor(-0.6185)), ('The cat was asleep on the couch.', tensor(-0.6276)), ('The cat was on the floor.', tensor(-0.6800))] +bart.fill_mask(['The cat on the .'], topk=3, beam=10, match_source_len=False) +# [[('The cat was on the ground.', tensor(-0.6185)), ('The cat was asleep on the couch.', tensor(-0.6276)), ('The cat was on the floor.', tensor(-0.6800))]] +``` + +Example code to fill masks for a batch of sentences using GPU +``` +bart.cuda() +bart.fill_mask(['The cat on the .', 'The dog on the .'], topk=3, beam=10) +# [[('The cat was on the ground.', tensor(-0.6183)), ('The cat was on the floor.', tensor(-0.6798)), ('The cat sleeps on the couch.', tensor(-0.6830))], [('The dog was on the ground.', tensor(-0.6190)), ('The dog lay on the ground.', tensor(-0.6711)), +('The dog was asleep on the couch', tensor(-0.6796))]] ``` #### Evaluating the `bart.large.mnli` model: diff --git a/fairseq/models/bart/hub_interface.py b/fairseq/models/bart/hub_interface.py index 4c5fd0b585..1ff170a782 100644 --- a/fairseq/models/bart/hub_interface.py +++ b/fairseq/models/bart/hub_interface.py @@ -165,27 +165,27 @@ def predict(self, head: str, tokens: torch.LongTensor, return_logits: bool = Fal def fill_mask( self, - masked_input: str, + masked_inputs: List[str], topk: int = 5, match_source_len: bool = True, **generate_kwargs ): masked_token = '' - assert masked_token in masked_input, \ - "please add one {} token for the input".format(masked_token) - - text_spans = masked_input.split(masked_token) - text_spans_bpe = (' {0} '.format(masked_token)).join( - [self.bpe.encode(text_span.rstrip()) for text_span in text_spans] - ).strip() - tokens = self.task.source_dictionary.encode_line( - ' ' + text_spans_bpe + ' ', - append_eos=False, - add_if_not_exist=False, - ).long() - - if tokens.dim() == 1: - tokens = tokens.unsqueeze(0) + batch_tokens = [] + for masked_input in masked_inputs: + assert masked_token in masked_input, \ + "please add one {} token for the input".format(masked_token) + + text_spans = masked_input.split(masked_token) + text_spans_bpe = (' {0} '.format(masked_token)).join( + [self.bpe.encode(text_span.rstrip()) for text_span in text_spans] + ).strip() + tokens = self.task.source_dictionary.encode_line( + ' ' + text_spans_bpe + ' ', + append_eos=False, + add_if_not_exist=False, + ).long() + batch_tokens.append(tokens) # ensure beam size is at least as big as topk generate_kwargs['beam'] = max( @@ -193,9 +193,9 @@ def fill_mask( generate_kwargs.get('beam', -1), ) generate_kwargs['match_source_len'] = match_source_len - hypos = self.generate(tokens, **generate_kwargs)[0] + batch_hypos = self.generate(batch_tokens, **generate_kwargs) return [ - (self.decode(hypo['tokens']), hypo['score']) - for hypo in hypos[:topk] + [(self.decode(hypo['tokens']), hypo['score']) for hypo in hypos[:topk]] + for hypos in batch_hypos ] diff --git a/fairseq/models/bart/model.py b/fairseq/models/bart/model.py index 7263a78dc2..e105d6fc46 100644 --- a/fairseq/models/bart/model.py +++ b/fairseq/models/bart/model.py @@ -108,6 +108,7 @@ def from_pretrained( checkpoint_file="model.pt", data_name_or_path=".", bpe="gpt2", + sample_break_mode="eos", **kwargs, ): from fairseq import hub_utils @@ -119,6 +120,7 @@ def from_pretrained( archive_map=cls.hub_models(), bpe=bpe, load_checkpoint_heads=True, + sample_break_mode=sample_break_mode, **kwargs, ) return BARTHubInterface(x["args"], x["task"], x["models"][0]) From b120fbbe8fdb6fc8412149916fe09c54757bdaf6 Mon Sep 17 00:00:00 2001 From: Joshua Meier Date: Tue, 3 Nov 2020 14:05:30 -0800 Subject: [PATCH 021/774] Fix correctness issue with megatron save/load checkpoints (#1386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/2681. Proof that it's working now: ``` python fairseq_train.py --task masked_lm /checkpoint/bioseq_nonsecure/model-parallel-data/tiny_sample_valid_ur50-bin --dataset-impl fasta --save-dir checkpoints/mp-fix4 --dropout 0.1 --optimizer adam --adam-betas '(0.9, 0.98)' --weight-decay 0.01 --clip-norm 0.0 --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-updates 4000 --warmup-init-lr 1e-07 --tokens-per-sample 128 --sample-break-mode none --max-tokens 128 --no-progress-bar --log-interval 1 --seed 4 --max-epoch 1 --max-update 50 --encoder-layers 4 --arch model_parallel_roberta_large --model-parallel-size 2 --update-freq 2 --save-interval-updates 10 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 11 / 78 loss=0.939, ppl=1.92, wps=116.7, ups=0.11, wpb=1024, bsz=8, num_updates=11, lr=1.47473e-06, gnorm=2.276, train_wall=0, wall=15 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 12 / 78 loss=0.938, ppl=1.92, wps=15769.2, ups=15.38, wpb=1024, bsz=8, num_updates=12, lr=1.5997e-06, gnorm=2.612, train_wall=0, wall=15 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 13 / 78 loss=0.877, ppl=1.84, wps=18658.8, ups=18.2, wpb=1024, bsz=8, num_updates=13, lr=1.72468e-06, gnorm=2.798, train_wall=0, wall=15 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 14 / 78 loss=0.887, ppl=1.85, wps=18324.5, ups=17.88, wpb=1024, bsz=8, num_updates=14, lr=1.84965e-06, gnorm=2.326, train_wall=0, wall=15 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 15 / 78 loss=0.867, ppl=1.82, wps=17616.5, ups=17.19, wpb=1024, bsz=8, num_updates=15, lr=1.97463e-06, gnorm=2.112, train_wall=0, wall=15 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 16 / 78 loss=0.891, ppl=1.85, wps=18624.5, ups=18.17, wpb=1024, bsz=8, num_updates=16, lr=2.0996e-06, gnorm=2.123, train_wall=0, wall=16 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 17 / 78 loss=0.887, ppl=1.85, wps=17972.5, ups=17.53, wpb=1024, bsz=8, num_updates=17, lr=2.22458e-06, gnorm=2.061, train_wall=0, wall=16 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 18 / 78 loss=0.862, ppl=1.82, wps=14672.4, ups=14.32, wpb=1024, bsz=8, num_updates=18, lr=2.34955e-06, gnorm=2.282, train_wall=0, wall=16 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 19 / 78 loss=0.876, ppl=1.83, wps=14398.6, ups=14.05, wpb=1024, bsz=8, num_updates=19, lr=2.47453e-06, gnorm=2.261, train_wall=0, wall=16 2020-10-29 18:42:08 | INFO | train_inner | epoch 001: 20 / 78 loss=0.818, ppl=1.76, wps=18652.2, ups=18.2, wpb=1024, bsz=8, num_updates=20, lr=2.5995e-06, gnorm=1.969, train_wall=0, wall=16 ...relaunch... 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 11 / 78 loss=0.939, ppl=1.92, wps=98.2, ups=0.1, wpb=1024, bsz=8, num_updates=11, lr=1.47473e-06, gnorm=2.276, train_wall=1, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 12 / 78 loss=0.938, ppl=1.92, wps=17137.8, ups=16.72, wpb=1024, bsz=8, num_updates=12, lr=1.5997e-06, gnorm=2.612, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 13 / 78 loss=0.877, ppl=1.84, wps=17239.6, ups=16.82, wpb=1024, bsz=8, num_updates=13, lr=1.72468e-06, gnorm=2.798, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 14 / 78 loss=0.887, ppl=1.85, wps=18132, ups=17.69, wpb=1024, bsz=8, num_updates=14, lr=1.84965e-06, gnorm=2.326, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 15 / 78 loss=0.867, ppl=1.82, wps=17795.1, ups=17.36, wpb=1024, bsz=8, num_updates=15, lr=1.97463e-06, gnorm=2.112, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 16 / 78 loss=0.891, ppl=1.85, wps=18021.3, ups=17.58, wpb=1024, bsz=8, num_updates=16, lr=2.0996e-06, gnorm=2.123, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 17 / 78 loss=0.887, ppl=1.85, wps=16452.9, ups=16.05, wpb=1024, bsz=8, num_updates=17, lr=2.22458e-06, gnorm=2.061, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 18 / 78 loss=0.862, ppl=1.82, wps=17563.3, ups=17.14, wpb=1024, bsz=8, num_updates=18, lr=2.34955e-06, gnorm=2.282, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 19 / 78 loss=0.876, ppl=1.83, wps=16770.3, ups=16.36, wpb=1024, bsz=8, num_updates=19, lr=2.47453e-06, gnorm=2.261, train_wall=0, wall=0 2020-10-29 18:47:20 | INFO | train_inner | epoch 001: 20 / 78 loss=0.818, ppl=1.76, wps=16808.2, ups=16.4, wpb=1024, bsz=8, num_updates=20, lr=2.5995e-06, gnorm=1.969, train_wall=0, wall=0 ``` ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1386 Reviewed By: myleott Differential Revision: D24640946 Pulled By: joshim5 fbshipit-source-id: cb141d92496b289a04d53f080ecd4d5ac6941672 --- fairseq/model_parallel/megatron_trainer.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/fairseq/model_parallel/megatron_trainer.py b/fairseq/model_parallel/megatron_trainer.py index cf83685862..a8c7bc9d98 100644 --- a/fairseq/model_parallel/megatron_trainer.py +++ b/fairseq/model_parallel/megatron_trainer.py @@ -11,7 +11,6 @@ from fairseq.trainer import Trainer from fairseq.dataclass.configs import FairseqConfig - try: from fairseq.model_parallel.megatron.mpu import ( get_data_parallel_group, @@ -19,6 +18,7 @@ get_data_parallel_world_size, get_model_parallel_group, get_model_parallel_src_rank, + get_cuda_rng_tracker, ) has_megatron_submodule = True @@ -65,3 +65,23 @@ def _aggregate_model_parallel_grad_norm(total_norm): clip_norm, aggregate_norm_fn=_aggregate_model_parallel_grad_norm, ) + + def save_checkpoint(self, filename, extra_state): + """Save all training state in a checkpoint file.""" + extra_state['rng_tracker_states'] \ + = get_cuda_rng_tracker().get_states() + super().save_checkpoint(filename, extra_state) + + def load_checkpoint( + self, + filename, + reset_optimizer=False, + reset_lr_scheduler=False, + optimizer_overrides=None, + reset_meters=False, + ): + extra_state = super().load_checkpoint(filename, reset_optimizer=reset_optimizer, reset_lr_scheduler=reset_lr_scheduler, optimizer_overrides=optimizer_overrides, reset_meters=reset_meters) + if extra_state is not None and 'rng_tracker_states' in extra_state: + get_cuda_rng_tracker().set_states( + extra_state['rng_tracker_states']) + return extra_state \ No newline at end of file From dd52ed0f3896639b3c04aa67c44775f689faf1a5 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 3 Nov 2020 20:44:09 -0800 Subject: [PATCH 022/774] Small fixes (#1392) Summary: - Set default value of clip-norm back to 0.0 (disabled) - Add comment explaining that we divide loss by log(2) to covert the base - Fix `--zero-optimizer=os` (fixes #2811) - Update requirements to PyTorch >= 1.5 - Fix bug in fixed LR schedule Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1392 Reviewed By: alexeib Differential Revision: D24714231 Pulled By: myleott fbshipit-source-id: 63dc8cfc74683bbccbf05b44228014eb12ddbfc7 --- README.md | 2 +- config/config.yaml | 2 +- fairseq/criterions/cross_entropy.py | 1 + fairseq/dataclass/configs.py | 2 +- fairseq/optim/fp16_optimizer.py | 3 ++- fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py | 4 ++++ fairseq/optim/lr_scheduler/fixed_schedule.py | 9 ++++----- fairseq/optim/lr_scheduler/polynomial_decay_schedule.py | 5 ++--- fairseq/trainer.py | 8 ++++++++ 9 files changed, 24 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 56ec16cdab..70e98fe395 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ and [RoBERTa](https://pytorch.org/hub/pytorch_fairseq_roberta/) for more example # Requirements and Installation -* [PyTorch](http://pytorch.org/) version >= 1.4.0 +* [PyTorch](http://pytorch.org/) version >= 1.5.0 * Python version >= 3.6 * For training new models, you'll also need an NVIDIA GPU and [NCCL](https://github.com/NVIDIA/nccl) * **To install fairseq** and develop locally: diff --git a/config/config.yaml b/config/config.yaml index b9ee6c74ac..dc0ca0fa60 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -63,7 +63,7 @@ dataset: optimization: max_epoch: 0 max_update: 0 - clip_norm: 25.0 + clip_norm: 0.0 sentence_avg: false update_freq: [ 1 ] lr: [ 0.25 ] diff --git a/fairseq/criterions/cross_entropy.py b/fairseq/criterions/cross_entropy.py index 758e727660..fe46106471 100644 --- a/fairseq/criterions/cross_entropy.py +++ b/fairseq/criterions/cross_entropy.py @@ -64,6 +64,7 @@ def reduce_metrics(logging_outputs) -> None: ntokens = sum(log.get("ntokens", 0) for log in logging_outputs) sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + # we divide by log(2) to convert the loss from base e to base 2 metrics.log_scalar( "loss", loss_sum / sample_size / math.log(2), sample_size, round=3 ) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 484d2526d7..ce07282422 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -434,7 +434,7 @@ class OptimizationConfig(FairseqDataclass): }, ) clip_norm: float = field( - default=25.0, metadata={"help": "clip threshold of gradients"} + default=0.0, metadata={"help": "clip threshold of gradients"} ) sentence_avg: bool = field( default=False, diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index b08a7237a9..aacd3e1d94 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -215,7 +215,8 @@ def zero_grad(self): raise RuntimeError("self.fp32_params must be a tensor or dict") else: for p32 in self.fp32_params: - p32.grad.zero_() + if p32.grad: + p32.grad.zero_() self._needs_sync = False if self.scaler is not None: diff --git a/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py b/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py index 569e448262..d0ac115829 100644 --- a/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py @@ -34,6 +34,10 @@ def load_state_dict(self, state_dict): """Load an LR scheduler state dict.""" self.best = state_dict["best"] + def step_begin_epoch(self, epoch): + """Update the learning rate at the beginning of the given epoch.""" + pass + def step(self, epoch, val_loss=None): """Update the learning rate at the end of the given epoch.""" if val_loss is not None: diff --git a/fairseq/optim/lr_scheduler/fixed_schedule.py b/fairseq/optim/lr_scheduler/fixed_schedule.py index 7ca7826ed2..e91ba86f8c 100644 --- a/fairseq/optim/lr_scheduler/fixed_schedule.py +++ b/fairseq/optim/lr_scheduler/fixed_schedule.py @@ -27,7 +27,7 @@ def add_args(parser): """Add arguments to the parser for this LR scheduler.""" # fmt: off parser.add_argument('--force-anneal', '--fa', type=int, metavar='N', - help='force annealing at specified epoch') + help='force annealing at specified epoch (epochs start at 1)') parser.add_argument('--lr-shrink', default=0.1, type=float, metavar='LS', help='shrink factor for annealing, lr_new = (lr * lr_shrink)') parser.add_argument('--warmup-updates', default=0, type=int, metavar='N', @@ -45,7 +45,7 @@ def get_next_lr(self, epoch): lrs = self.args.lr if self.args.force_anneal is None or epoch < self.args.force_anneal: # use fixed LR schedule - next_lr = lrs[min(epoch, len(lrs) - 1)] + next_lr = lrs[min(epoch - 1, len(lrs) - 1)] else: # annneal based on lr_shrink next_lr = lrs[-1] * self.args.lr_shrink ** ( @@ -53,9 +53,8 @@ def get_next_lr(self, epoch): ) return next_lr - def step(self, epoch, val_loss=None): - """Update the learning rate at the end of the given epoch.""" - super().step(epoch, val_loss) + def step_begin_epoch(self, epoch): + """Update the learning rate at the beginning of the given epoch.""" self.lr = self.get_next_lr(epoch) self.optimizer.set_lr(self.warmup_factor * self.lr) return self.optimizer.get_lr() diff --git a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py index ea8e647668..63adc740a9 100644 --- a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py +++ b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py @@ -57,9 +57,8 @@ def get_next_lr(self, epoch): next_lr = self.optimizer.get_lr() return next_lr - def step(self, epoch, val_loss=None): - """Update the learning rate at the end of the given epoch.""" - super().step(epoch, val_loss) + def step_begin_epoch(self, epoch): + """Update the learning rate at the beginning of the given epoch.""" self.lr = self.get_next_lr(epoch) self.optimizer.set_lr(self.warmup_factor * self.lr) return self.optimizer.get_lr() diff --git a/fairseq/trainer.py b/fairseq/trainer.py index a4d273ca67..5daf2e2e5b 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -429,6 +429,8 @@ def begin_epoch(self, epoch): """Called at the beginning of each epoch.""" logger.info("begin training epoch {}".format(epoch)) + self.lr_step_begin_epoch(epoch) + if self.quantizer is not None: self.quantizer.begin_epoch(epoch) @@ -782,6 +784,12 @@ def valid_step(self, sample, raise_oom=False): def zero_grad(self): self.optimizer.zero_grad() + def lr_step_begin_epoch(self, epoch): + """Adjust the learning rate at the beginning of the epoch.""" + self.lr_scheduler.step_begin_epoch(epoch) + # prefer updating the LR based on the number of steps + return self.lr_step_update() + def lr_step(self, epoch, val_loss=None): """Adjust the learning rate at the end of the epoch.""" self.lr_scheduler.step(epoch, val_loss) From 1a709b2a401ac8bd6d805c8a6a5f4d7f03b923ff Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 3 Nov 2020 20:46:45 -0800 Subject: [PATCH 023/774] Reproduce #1781. Add Weights and Biases support Summary: Fixes https://github.com/pytorch/fairseq/issues/1790. Reviewed By: alexeib Differential Revision: D24579153 fbshipit-source-id: 74a30effa164db9d6376554376e36b1f47618899 Co-authored-by: Nikolay Korolev Co-authored-by: Vlad Lyalin --- .gitignore | 3 ++ config/config.yaml | 1 + fairseq/dataclass/configs.py | 6 ++++ fairseq/logging/progress_bar.py | 51 +++++++++++++++++++++++++++++++++ fairseq_cli/train.py | 10 +++++-- 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9546cffd90..4112804793 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,6 @@ data-bin/ # Experimental Folder experimental/* + +# Weights and Biases logs +wandb/ diff --git a/config/config.yaml b/config/config.yaml index dc0ca0fa60..e3d26089f7 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -4,6 +4,7 @@ common: log_interval: 100 log_format: null tensorboard_logdir: null + wandb_project: null seed: 1 cpu: false tpu: false diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index ce07282422..3bdc6d16d4 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -102,6 +102,12 @@ class CommonConfig(FairseqDataclass): "of running tensorboard (default: no tensorboard logging)" }, ) + wandb_project: Optional[str] = field( + default=None, + metadata={ + "help": "Weights and Biases project name to use for logging" + }, + ) seed: int = field( default=1, metadata={"help": "pseudo random number generator seed"} ) diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index 63e5394815..3183d2f476 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -33,6 +33,7 @@ def progress_bar( prefix: Optional[str] = None, tensorboard_logdir: Optional[str] = None, default_log_format: str = "tqdm", + wandb_project: Optional[str] = None, ): if log_format is None: log_format = default_log_format @@ -60,6 +61,9 @@ def progress_bar( except ImportError: bar = TensorboardProgressBarWrapper(bar, tensorboard_logdir) + if wandb_project: + bar = WandBProgressBarWrapper(bar, wandb_project) + return bar @@ -353,3 +357,50 @@ def _log_to_tensorboard(self, stats, tag=None, step=None): elif isinstance(stats[key], Number): writer.add_scalar(key, stats[key], step) writer.flush() + + +try: + import wandb +except ImportError: + wandb = None + + +class WandBProgressBarWrapper(BaseProgressBar): + """Log to Weights & Biases.""" + + def __init__(self, wrapped_bar, wandb_project): + self.wrapped_bar = wrapped_bar + if wandb is None: + logger.warning('wandb not found, pip install wandb') + return + + # reinit=False to ensure if wandb.init() is called multiple times + # within one process it still references the same run + wandb.init(project=wandb_project, reinit=False) + + def __iter__(self): + return iter(self.wrapped_bar) + + def log(self, stats, tag=None, step=None): + """Log intermediate stats to tensorboard.""" + self._log_to_wandb(stats, tag, step) + self.wrapped_bar.log(stats, tag=tag, step=step) + + def print(self, stats, tag=None, step=None): + """Print end-of-epoch stats.""" + self._log_to_wandb(stats, tag, step) + self.wrapped_bar.print(stats, tag=tag, step=step) + + def _log_to_wandb(self, stats, tag=None, step=None): + if wandb is None: + return + if step is None: + step = stats['num_updates'] + + prefix = '' if tag is None else tag + '/' + + for key in stats.keys() - {'num_updates'}: + if isinstance(stats[key], AverageMeter): + wandb.log({prefix + key: stats[key].val}, step=step) + elif isinstance(stats[key], Number): + wandb.log({prefix + key: stats[key]}, step=step) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index ec10028f03..9eeca18e92 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -187,7 +187,10 @@ def train(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr) tensorboard_logdir=( cfg.common.tensorboard_logdir if distributed_utils.is_master(cfg.distributed_training) else None ), - default_log_format=('tqdm' if not cfg.common.no_progress_bar else 'simple'), + default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), + wandb_project=( + cfg.common.wandb_project if distributed_utils.is_master(cfg.distributed_training) else None + ), ) trainer.begin_epoch(epoch_itr.epoch) @@ -307,7 +310,10 @@ def validate(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_i tensorboard_logdir=( cfg.common.tensorboard_logdir if distributed_utils.is_master(cfg.distributed_training) else None ), - default_log_format=('tqdm' if not cfg.common.no_progress_bar else 'simple'), + default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), + wandb_project=( + cfg.common.wandb_project if distributed_utils.is_master(cfg.distributed_training) else None + ), ) # create a new root metrics aggregator so validation metrics From ea4ccd94de131d6b39163836418696369dd1d034 Mon Sep 17 00:00:00 2001 From: Alex Xiao Date: Wed, 4 Nov 2020 12:56:13 -0800 Subject: [PATCH 024/774] Load and broadcast fairseq checkpoints instead of having each rank load them individually Summary: This diff is based on feedback in D24379649 Before when loading checkpoints: Each rank loads the checkpoint from Manifold. Now: Rank 0 loads checkpoint from Manifold. This checkpoint is broadcasted to all other ranks. This saves IO. Furthermore, when doing zero-sharding, we only broadcast the relevant parts of the optimizer state to each node. This makes checkpoint loading more memory-efficient and should enable loading models beyond 2-3B parameters. Reviewed By: myleott Differential Revision: D24660791 fbshipit-source-id: e30b2ea5990083375e4549f0427a112346ba170d --- fairseq/distributed_utils.py | 42 +++++++++++++++++++++- fairseq/optim/fairseq_optimizer.py | 10 ++++++ fairseq/optim/shard.py | 58 +++++++++++++++++++++++++++++- fairseq/trainer.py | 45 ++++++++++++++++++++--- 4 files changed, 149 insertions(+), 6 deletions(-) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 0d5804c8f7..cbe6c6de5d 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import io import logging import os import pickle @@ -13,7 +14,7 @@ import warnings from argparse import Namespace from collections import OrderedDict -from typing import Any, Dict, Mapping +from typing import Any, Dict, Mapping, Optional import torch import torch.distributed as dist @@ -455,3 +456,42 @@ def get_from_stack(key): raise KeyError return OrderedDict([(key, get_from_stack(key)) for key in data_keys]) + + +# From fairscale/optim/utils.py +def broadcast_object( + obj: Any, + src_rank: int, + group: object = dist.group.WORLD, + dist_device: Optional[torch.device] = None, +) -> Any: + """ + Either broadcast from master to the fleet (default), + or use the src setting as the original rank. + """ + if dist_device is None: + if torch.distributed.get_backend(group) == "nccl": + dist_device = torch.device("cuda") + else: + dist_device = torch.device("cpu") + + if dist.get_rank() == src_rank: + # Emit data + buffer = io.BytesIO() + torch.save(obj, buffer) + data = bytearray(buffer.getbuffer()) + length_tensor = torch.LongTensor([len(data)]).to(dist_device) + data_send_tensor = torch.ByteTensor(data).to(dist_device) + dist.broadcast(length_tensor, src=src_rank, group=group, async_op=False) + dist.broadcast(data_send_tensor, src=src_rank, group=group, async_op=False) + else: + # Fetch from the source + length_tensor = torch.LongTensor([0]).to(dist_device) + dist.broadcast(length_tensor, src=src_rank, group=group, async_op=False) + data_recv_tensor = torch.empty( + [int(length_tensor.item())], dtype=torch.uint8, device=dist_device + ) + dist.broadcast(data_recv_tensor, src=src_rank, group=group, async_op=False) + buffer = io.BytesIO(data_recv_tensor.cpu().numpy()) + obj = torch.load(buffer, map_location=dist_device) + return obj diff --git a/fairseq/optim/fairseq_optimizer.py b/fairseq/optim/fairseq_optimizer.py index 9c0938331d..e91e9d3204 100644 --- a/fairseq/optim/fairseq_optimizer.py +++ b/fairseq/optim/fairseq_optimizer.py @@ -144,6 +144,16 @@ def supports_flat_params(self): def average_params(self): pass + def broadcast_global_state_dict(self, state_dict): + """ + Broadcasts a global state dict to all ranks. + Useful for optimizers that shard state between ranks. + """ + if hasattr(self.optimizer, "broadcast_global_state_dict"): + return self.optimizer.broadcast_global_state_dict(state_dict) + else: + return state_dict + class LegacyFairseqOptimizer(FairseqOptimizer): def __init__(self, args): diff --git a/fairseq/optim/shard.py b/fairseq/optim/shard.py index ecef05b442..3d025a23ca 100644 --- a/fairseq/optim/shard.py +++ b/fairseq/optim/shard.py @@ -3,9 +3,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from typing import Any, Dict + +import torch + try: - from fairscale.optim import OSS + from fairscale.optim import OSS, utils _has_fairscale = True except ImportError: @@ -30,6 +34,58 @@ def __getattr__(self, name): "'FairseqOSS' object has no attribute {0!r}".format(name) ) + def broadcast_global_state_dict( + self, state_dict: Dict[str, Any] + ) -> Dict[str, Any]: + """ + Broadcasts the relevant parts of a global state dict from rank 0 to + all other ranks. + """ + if self.rank == 0: + + # Create template state dict for all other keys not related to sharding + template_state_dict = { + key: state_dict[key] + for key in state_dict + if key not in ("param_groups", "state") + } + template_state_dict["local_state_dict"] = True + + for dst_rank in range(self.world_size): + # Get the dst_rank's param_groups shard + send_state = { + "param_groups": state_dict["param_groups"][ + state_dict["partition"][dst_rank][0] : state_dict[ + "partition" + ][dst_rank][1] + ], + "state": state_dict["state"][dst_rank], + } + send_state.update(template_state_dict) + + if dst_rank == 0: + recv_state = send_state + else: + utils.broadcast_object( + send_state, + src_rank=0, + group=self.group, + dist_device=self._device, + ) + else: + empty_buffer = torch.tensor([0], dtype=torch.uint8, device=self._device) + for dst_rank in range(1, self.world_size): + state = utils.broadcast_object( + empty_buffer, + src_rank=0, + group=self.group, + dist_device=self._device, + ) + if dst_rank == self.rank: + recv_state = state + + return recv_state + torch_optimizer = optimizer.optimizer optim_cls = type(torch_optimizer) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 5daf2e2e5b..657374aab7 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -289,12 +289,46 @@ def load_checkpoint( optimizer_overrides=None, reset_meters=False, ): - """Load all training state from a checkpoint file.""" + """ + Load all training state from a checkpoint file. + rank = 0 will load the checkpoint, and then broadcast it to all + other ranks. + """ extra_state, self._optim_history, last_optim_state = None, [], None bexists = PathManager.isfile(filename) if bexists: - state = checkpoint_utils.load_checkpoint_to_cpu(filename) + if self.data_parallel_rank == 0: + state = checkpoint_utils.load_checkpoint_to_cpu(filename) + last_optim_state = state.get("last_optimizer_state", None) + + # If doing zero_sharding, do not broadcast global optimizer + # state. Later we will broadcast sharded states to each rank + # to avoid memory from exploding. + if ( + self.cfg.distributed_training.zero_sharding == "os" + and "last_optimizer_state" in state + and self.data_parallel_world_size > 1 + ): + state["last_optimizer_state"] = "SHARDED" + else: + last_optim_state = None + state = None + + if self.data_parallel_world_size > 1: + group = ( + self.data_parallel_process_group + if self.data_parallel_process_group is not None + else torch.distributed.group.WORLD + ) + state = distributed_utils.broadcast_object( + state, + src_rank=0, + group=group, + ) + if self.data_parallel_rank > 0: + last_optim_state = state.get("last_optimizer_state", None) + # load model parameters try: self.get_model().load_state_dict( @@ -309,10 +343,8 @@ def load_checkpoint( "Cannot load model parameters from checkpoint {}; " "please ensure that the architectures match.".format(filename) ) - extra_state = state["extra_state"] self._optim_history = state["optimizer_history"] - last_optim_state = state.get("last_optimizer_state", None) if last_optim_state is not None and not reset_optimizer: # rebuild optimizer after loading model, since params may have changed @@ -329,6 +361,11 @@ def load_checkpoint( if not reset_lr_scheduler: self.lr_scheduler.load_state_dict(last_optim["lr_scheduler_state"]) + + if self.data_parallel_world_size > 1: + last_optim_state = self.optimizer.broadcast_global_state_dict( + last_optim_state + ) self.optimizer.load_state_dict(last_optim_state, optimizer_overrides) self.set_num_updates(last_optim["num_updates"]) From b58f4f017ed275aff327046943857b4259f64a47 Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 4 Nov 2020 18:19:10 -0800 Subject: [PATCH 025/774] end to end hydra configs (#1393) Summary: this adds a hydra_train binary that uses hydra configs/command line overrides instead of argparse use case 1: built in configs + overrides from command line ``` python fairseq_cli/hydra_train.py distributed_training.distributed_world_size=1 dataset.batch_size=2 task.data=/private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/ model=transformer_lm/transformer_lm_gpt task=language_modeling optimization.max_update=5000 ``` use case 2: use an external config that is used instead of bundled configs (but dataclass defaults still work) ``` python fairseq_cli/hydra_train.py --config-path ~/fairseq-py-dev/lm --config-name wiki103 ``` the config file contains this: ``` # package _group_ model: _name: transformer_lm distributed_training: distributed_world_size: 1 dataset: batch_size: 2 task: _name: language_modeling data: /private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/ add_bos_token: false max_target_positions: 1024 optimization: max_update: 50000 lr: [ 0.25 ] criterion: cross_entropy optimizer: adam lr_scheduler: _name: cosine ``` use case 3: use an external config directory that provides additional configs for e.g. models python fairseq_cli/hydra_train.py distributed_training.distributed_world_size=1 dataset.batch_size=2 task.data=/private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/ model=transformer_lm/2_layers task=language_modeling optimization.max_update=5000 --config-dir ~/fairseq-py-dev/lm/hydra where ~/fairseq-py-dev/lm/hydra has the following structure: - model -- transformer_lm --- 2_layers.yaml and inside 2_layers.yaml is a copy of transformer_lm_gpt.yaml but with decoder_layers set to 2 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1393 Reviewed By: myleott Differential Revision: D24722252 Pulled By: alexeib fbshipit-source-id: 758ea431fa099cd7c0e4daf41eff680df1d3b841 --- config/config.yaml | 105 +----------------- config/criterion/adaptive_loss.yaml | 3 - config/criterion/cross_entropy.yaml | 2 - config/lr_scheduler/cosine.yaml | 7 -- config/lr_scheduler/inverse_sqrt.yaml | 3 - config/model/transformer_lm.yaml | 36 ------ .../transformer_lm_baevski_gbw.yaml | 0 .../transformer_lm_baevski_wiki103.yaml | 0 .../transformer_lm_big.yaml | 0 .../transformer_lm_gbw.yaml | 0 .../transformer_lm_gpt.yaml | 0 .../transformer_lm_gpt2_big.yaml | 0 .../transformer_lm_gpt2_medium.yaml | 0 .../transformer_lm_gpt2_small.yaml | 0 .../transformer_lm_wiki103.yaml | 0 config/optimizer/adam.yaml | 5 - config/optimizer/nag.yaml | 3 - config/task/language_modeling.yaml | 10 -- fairseq/dataclass/__init__.py | 5 +- fairseq/dataclass/configs.py | 14 ++- fairseq/dataclass/constants.py | 3 + fairseq/dataclass/initialize.py | 15 ++- fairseq/dataclass/utils.py | 24 +++- fairseq/distributed_utils.py | 3 +- fairseq/models/__init__.py | 34 +++++- fairseq/optim/fp16_optimizer.py | 2 +- .../optim/lr_scheduler/cosine_lr_scheduler.py | 2 +- fairseq/registry.py | 14 ++- fairseq/tasks/__init__.py | 21 +++- fairseq/tasks/language_modeling.py | 5 +- fairseq_cli/hydra_train.py | 47 ++++++++ fairseq_cli/train.py | 101 +++++++++++------ tests/test_fp16_optimizer.py | 4 + 33 files changed, 240 insertions(+), 228 deletions(-) delete mode 100644 config/criterion/adaptive_loss.yaml delete mode 100644 config/criterion/cross_entropy.yaml delete mode 100644 config/lr_scheduler/cosine.yaml delete mode 100644 config/lr_scheduler/inverse_sqrt.yaml delete mode 100644 config/model/transformer_lm.yaml rename config/model/{ => transformer_lm}/transformer_lm_baevski_gbw.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_baevski_wiki103.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_big.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_gbw.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_gpt.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_gpt2_big.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_gpt2_medium.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_gpt2_small.yaml (100%) rename config/model/{ => transformer_lm}/transformer_lm_wiki103.yaml (100%) delete mode 100644 config/optimizer/adam.yaml delete mode 100644 config/optimizer/nag.yaml delete mode 100644 config/task/language_modeling.yaml create mode 100644 fairseq_cli/hydra_train.py diff --git a/config/config.yaml b/config/config.yaml index e3d26089f7..039609aece 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -1,109 +1,10 @@ # @package _group_ -common: - no_progress_bar: false - log_interval: 100 - log_format: null - tensorboard_logdir: null - wandb_project: null - seed: 1 - cpu: false - tpu: false - bf16: false - fp16: false - memory_efficient_fp16: false - memory_efficient_bf16: false - fp16_no_flatten_grads: false - fp16_init_scale: 128 - fp16_scale_window: null - fp16_scale_tolerance: 0.0 - min_loss_scale: 1.0e-4 - threshold_loss_scale: null - user_dir: null - empty_cache_freq: 0 - all_gather_list_size: 16384 - model_parallel_size: 1 - quantization_config_path: null - profile: false -distributed_training: - distributed_rank: 0 - distributed_backend: "nccl" - distributed_init_method: null - distributed_port: -1 - device_id: 0 - local_rank: 0 - distributed_no_spawn: false - ddp_backend: "c10d" - bucket_cap_mb: 25 - fix_batches_to_gpus: false - find_unused_parameters: false - fast_stat_sync: false - broadcast_buffers: false - distributed_wrapper: "DDP" - slowmo_momentum: null - slowmo_algorithm: "LocalSGD" - localsgd_frequency: 3 -dataset: - num_workers: 1 - skip_invalid_size_inputs_valid_test: false - max_tokens: null - batch_size: null - required_batch_size_multiple: 8 - dataset_impl: null - data_buffer_size: 10 - train_subset: "train" - valid_subset: "valid" - validate_interval: 1 - fixed_validation_seed: null - disable_validation: false - curriculum: 0 - gen_subset: "test" - num_shards: 1 - shard_id: 0 - max_tokens_valid: ${dataset.max_tokens} - batch_size_valid: ${dataset.batch_size} -optimization: - max_epoch: 0 - max_update: 0 - clip_norm: 0.0 - sentence_avg: false - update_freq: [ 1 ] - lr: [ 0.25 ] - min_lr: -1.0 - use_bmuf: false -checkpoint: - save_dir: "checkpoints" - restore_file: "checkpoint_last.pt" - reset_dataloader: false - reset_lr_scheduler: false - reset_meters: false - reset_optimizer: false - optimizer_overrides: "{}" - save_interval: 1 - save_interval_updates: 0 - keep_interval_updates: -1 - keep_last_epochs: -1 - keep_best_checkpoints: -1 - no_save: false - no_epoch_checkpoints: false - no_last_checkpoints: false - no_save_optimizer_state: false - best_checkpoint_metric: "loss" - maximize_best_checkpoint_metric: false - patience: -1 - checkpoint_suffix: "" -bmuf: - block_lr: 1 - block_momentum: 0.875 - global_sync_iter: 50 - warmup_iterations: 500 - use_nbm: false - average_sync: false defaults: - task: language_modeling - model: null - - criterion: null - - optimizer: null - - lr_scheduler: null + - criterion: cross_entropy + - optimizer: adam + - lr_scheduler: cosine - bpe: null - tokenizer: null - scoring: null diff --git a/config/criterion/adaptive_loss.yaml b/config/criterion/adaptive_loss.yaml deleted file mode 100644 index 7997b0766e..0000000000 --- a/config/criterion/adaptive_loss.yaml +++ /dev/null @@ -1,3 +0,0 @@ -# @package _group_ -sentence_avg: ${optimization.sentence_avg} -ddp_backend: ${distributed_training.ddp_backend} diff --git a/config/criterion/cross_entropy.yaml b/config/criterion/cross_entropy.yaml deleted file mode 100644 index ad3d4148c2..0000000000 --- a/config/criterion/cross_entropy.yaml +++ /dev/null @@ -1,2 +0,0 @@ -# @package _group_ -sentence_avg: ${optimization.sentence_avg} diff --git a/config/lr_scheduler/cosine.yaml b/config/lr_scheduler/cosine.yaml deleted file mode 100644 index 0f91e0d240..0000000000 --- a/config/lr_scheduler/cosine.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# @package _group_ -warmup_updates: 0 -warmup_init_lr: -1 -max_lr: 1.0 -t_mult: 1.0 -lr_period_updates: -1 -lr_shrink: 0.1 diff --git a/config/lr_scheduler/inverse_sqrt.yaml b/config/lr_scheduler/inverse_sqrt.yaml deleted file mode 100644 index 0eac7d88eb..0000000000 --- a/config/lr_scheduler/inverse_sqrt.yaml +++ /dev/null @@ -1,3 +0,0 @@ -# @package _group_ -warmup_updates: 4000 -warmup_init_lr: -1 diff --git a/config/model/transformer_lm.yaml b/config/model/transformer_lm.yaml deleted file mode 100644 index 3837ea54e1..0000000000 --- a/config/model/transformer_lm.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# @package _group_ -activation_fn: "relu" -dropout: 0.1 -attention_dropout: 0.0 -activation_dropout: 0.0 -relu_dropout: 0.0 -decoder_embed_dim: 512 -decoder_output_dim: 512 -decoder_input_dim: 512 -decoder_ffn_embed_dim: 2048 -decoder_layers: 6 -decoder_attention_heads: 8 -decoder_normalize_before: true -no_decoder_final_norm: false -adaptive_softmax_cutoff: null -adaptive_softmax_dropout: 0 -adaptive_softmax_factor: 4 -no_token_positional_embeddings: false -share_decoder_input_output_embed: false -character_embeddings: false -character_filters: "[(1, 64), (2, 128), (3, 192), (4, 256), (5, 256), (6, 256), (7, 256)]" -character_embedding_dim: 4 -char_embedder_highway_layers: 2 -adaptive_input: false -adaptive_input_factor: 4 -adaptive_input_cutoff: null -tie_adaptive_weights: false -tie_adaptive_proj: false -decoder_learned_pos: false -decoder_layerdrop: 0 -decoder_layers_to_keep: null -layernorm_embedding: false -no_scale_embedding: false -quant_noise_pq: 0 -quant_noise_pq_block_size: 8 -quant_noise_scalar: 0 diff --git a/config/model/transformer_lm_baevski_gbw.yaml b/config/model/transformer_lm/transformer_lm_baevski_gbw.yaml similarity index 100% rename from config/model/transformer_lm_baevski_gbw.yaml rename to config/model/transformer_lm/transformer_lm_baevski_gbw.yaml diff --git a/config/model/transformer_lm_baevski_wiki103.yaml b/config/model/transformer_lm/transformer_lm_baevski_wiki103.yaml similarity index 100% rename from config/model/transformer_lm_baevski_wiki103.yaml rename to config/model/transformer_lm/transformer_lm_baevski_wiki103.yaml diff --git a/config/model/transformer_lm_big.yaml b/config/model/transformer_lm/transformer_lm_big.yaml similarity index 100% rename from config/model/transformer_lm_big.yaml rename to config/model/transformer_lm/transformer_lm_big.yaml diff --git a/config/model/transformer_lm_gbw.yaml b/config/model/transformer_lm/transformer_lm_gbw.yaml similarity index 100% rename from config/model/transformer_lm_gbw.yaml rename to config/model/transformer_lm/transformer_lm_gbw.yaml diff --git a/config/model/transformer_lm_gpt.yaml b/config/model/transformer_lm/transformer_lm_gpt.yaml similarity index 100% rename from config/model/transformer_lm_gpt.yaml rename to config/model/transformer_lm/transformer_lm_gpt.yaml diff --git a/config/model/transformer_lm_gpt2_big.yaml b/config/model/transformer_lm/transformer_lm_gpt2_big.yaml similarity index 100% rename from config/model/transformer_lm_gpt2_big.yaml rename to config/model/transformer_lm/transformer_lm_gpt2_big.yaml diff --git a/config/model/transformer_lm_gpt2_medium.yaml b/config/model/transformer_lm/transformer_lm_gpt2_medium.yaml similarity index 100% rename from config/model/transformer_lm_gpt2_medium.yaml rename to config/model/transformer_lm/transformer_lm_gpt2_medium.yaml diff --git a/config/model/transformer_lm_gpt2_small.yaml b/config/model/transformer_lm/transformer_lm_gpt2_small.yaml similarity index 100% rename from config/model/transformer_lm_gpt2_small.yaml rename to config/model/transformer_lm/transformer_lm_gpt2_small.yaml diff --git a/config/model/transformer_lm_wiki103.yaml b/config/model/transformer_lm/transformer_lm_wiki103.yaml similarity index 100% rename from config/model/transformer_lm_wiki103.yaml rename to config/model/transformer_lm/transformer_lm_wiki103.yaml diff --git a/config/optimizer/adam.yaml b/config/optimizer/adam.yaml deleted file mode 100644 index e5264f895e..0000000000 --- a/config/optimizer/adam.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# @package _group_ -adam_betas: "(0.9, 0.999)" -adam_eps: 1.0e-8 -weight_decay: 0 -use_old_adam: false diff --git a/config/optimizer/nag.yaml b/config/optimizer/nag.yaml deleted file mode 100644 index 4ab2745686..0000000000 --- a/config/optimizer/nag.yaml +++ /dev/null @@ -1,3 +0,0 @@ -# @package _group_ -momentum: 0.99 -weight_decay: 0.0 diff --git a/config/task/language_modeling.yaml b/config/task/language_modeling.yaml deleted file mode 100644 index 58a2ad1358..0000000000 --- a/config/task/language_modeling.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# @package _group_ -data: ??? -sample_break_mode: "none" -tokens_per_sample: 1024 -output_dictionary_size: -1 -self_target: false -future_target: false -past_target: false -add_bos_token: false -max_target_positions: null diff --git a/fairseq/dataclass/__init__.py b/fairseq/dataclass/__init__.py index 5c9004d3ba..25408d28ec 100644 --- a/fairseq/dataclass/__init__.py +++ b/fairseq/dataclass/__init__.py @@ -7,4 +7,7 @@ from .constants import ChoiceEnum -__all__ = ["FairseqDataclass", "ChoiceEnum"] +__all__ = [ + "FairseqDataclass", + "ChoiceEnum", +] diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 3bdc6d16d4..a3c0d06a39 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -20,7 +20,7 @@ ZERO_SHARDING_CHOICES, ) -from omegaconf import II +from omegaconf import II, MISSING @dataclass @@ -781,7 +781,9 @@ class GenerationConfig(FairseqDataclass): default=False, metadata={"help": "Use dropout at inference time"}, ) - retain_dropout_modules: Optional[List[str]] = field( + # temporarily set to Any until https://github.com/facebookresearch/hydra/issues/1117 is fixed + # retain_dropout_modules: Optional[List[str]] = field( + retain_dropout_modules: Any = field( default=None, metadata={ "help": "if set, only retain dropout for the specified modules; " @@ -880,3 +882,11 @@ class FairseqConfig(object): generation: GenerationConfig = GenerationConfig() eval_lm: EvalLMConfig = EvalLMConfig() interactive: InteractiveConfig = InteractiveConfig() + model: Any = MISSING + task: Any = None + criterion: Any = None + optimizer: Any = None + lr_scheduler: Any = None + scoring: Any = None + bpe: Any = None + tokenizer: Any = None diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 3eb63ec609..fad04f3482 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -17,6 +17,9 @@ def __eq__(self, other: str): def __repr__(self): return self.value + def __hash__(self): + return hash(str(self)) + def ChoiceEnum(choices: List[str]): """return the Enum class used to enforce list of choices""" diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index b762af990f..24fedd52bf 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -2,15 +2,20 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +"""isort:skip_file""" import logging - from typing import Dict, Any - from hydra.core.config_store import ConfigStore - from fairseq.dataclass.configs import FairseqConfig +# the imports below are necessary so that "REGISTRIES" is correctly populated with all components +from fairseq.criterions import CRITERION_REGISTRY # noqa +from fairseq.optim import OPTIMIZER_REGISTRY # noqa +from fairseq.optim.lr_scheduler import LR_SCHEDULER_REGISTRY # noqa +from fairseq.scoring import SCORER_REGISTRY # noqa +from fairseq.data.encoders import BPE_REGISTRY, TOKENIZER_REGISTRY # noqa + from fairseq.models import MODEL_DATACLASS_REGISTRY from fairseq.tasks import TASK_DATACLASS_REGISTRY from fairseq.registry import REGISTRIES @@ -30,8 +35,10 @@ def register_module_dataclass( cs.store(name=k, group=group, node=node_, provider="fairseq") -def hydra_init() -> None: +def hydra_init(cfg_name="config") -> None: + cs = ConfigStore.instance() + cs.store(name=cfg_name, node=FairseqConfig) for k in FairseqConfig.__dataclass_fields__: v = FairseqConfig.__dataclass_fields__[k].default diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 5ce017d765..477a198d0f 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -8,11 +8,11 @@ from argparse import ArgumentError, ArgumentParser, Namespace from dataclasses import _MISSING_TYPE, MISSING from enum import Enum +import inspect from typing import Any, Dict, List, Tuple, Type from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.configs import FairseqConfig -from hydra.core.global_hydra import GlobalHydra from hydra.experimental import compose, initialize from omegaconf import DictConfig, OmegaConf, open_dict @@ -177,6 +177,9 @@ def _override_attr( ) -> List[str]: overrides = [] + if not inspect.isclass(data_class) or not issubclass(data_class, FairseqDataclass): + return overrides + def get_default(f): if not isinstance(f.default_factory, _MISSING_TYPE): return f.default_factory() @@ -189,6 +192,12 @@ def get_default(f): val = get_default(v) if not hasattr(args, k) else getattr(args, k) + if getattr(v.type, "__origin__", None) is List: + # if type is int but val is float, then we will crash later - try to convert here + t_args = v.type.__args__ + if len(t_args) == 1: + val = list(map(t_args[0], val)) + if val is None: overrides.append("{}.{}=null".format(sub_node, k)) elif val == "": @@ -255,13 +264,14 @@ def override_module_args(args: Namespace) -> Tuple[List[str], List[str]]: no_dc = True if hasattr(args, "arch"): - from fairseq.models import ARCH_MODEL_REGISTRY + from fairseq.models import ARCH_MODEL_REGISTRY, ARCH_MODEL_NAME_REGISTRY if args.arch in ARCH_MODEL_REGISTRY: m_cls = ARCH_MODEL_REGISTRY[args.arch] dc = getattr(m_cls, "__dataclass", None) if dc is not None: - overrides.append("model={}".format(args.arch)) + m_name = ARCH_MODEL_NAME_REGISTRY[args.arch] + overrides.append("model={}".format(m_name)) overrides.append("model._name={}".format(args.arch)) # override model params with those exist in args overrides.extend(_override_attr("model", dc, args)) @@ -358,3 +368,11 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): overwrite_args_by_name(cfg[k], overrides) elif k in overrides: cfg[k] = overrides[k] + + +def merge_with_parent(dc: FairseqDataclass, cfg: DictConfig): + dc_instance = DictConfig(dc) + dc_instance.__dict__["_parent"] = cfg.__dict__["_parent"] + cfg = OmegaConf.merge(dc_instance, cfg) + OmegaConf.set_struct(cfg, True) + return cfg diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index cbe6c6de5d..3439508c94 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -147,7 +147,8 @@ def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False): elif cfg.distributed_world_size > 1 or force_distributed: # fallback for single node with multiple GPUs - assert cfg.distributed_world_size <= torch.cuda.device_count() + assert cfg.distributed_world_size <= torch.cuda.device_count(), \ + f"world size is {cfg.distributed_world_size} but have {torch.cuda.device_count()} available devices" port = random.randint(10000, 20000) cfg.distributed_init_method = "tcp://localhost:{port}".format(port=port) diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 3b4fd51d6c..e8af024795 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -10,6 +10,7 @@ import fairseq from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.utils import merge_with_parent from omegaconf import DictConfig, OmegaConf from .composite_encoder import CompositeEncoder @@ -51,9 +52,36 @@ def build_model(cfg: DictConfig, task): - if isinstance(cfg, DictConfig): - return ARCH_MODEL_REGISTRY[cfg._name].build_model(cfg, task) - return ARCH_MODEL_REGISTRY[cfg.arch].build_model(cfg, task) + + model = None + model_type = getattr(cfg, "_name", None) or getattr(cfg, "arch", None) + + if not model_type and len(cfg) == 1: + # this is hit if config object is nested in directory that is named after model type + + model_type = next(iter(cfg)) + if model_type in MODEL_DATACLASS_REGISTRY: + cfg = cfg[model_type] + else: + raise Exception( + "Could not infer model type from directory. Please add _name field to indicate model type" + ) + + if model_type in ARCH_MODEL_REGISTRY: + # case 1: legacy models + model = ARCH_MODEL_REGISTRY[model_type] + elif model_type in MODEL_DATACLASS_REGISTRY: + # case 2: config-driven models + model = MODEL_REGISTRY[model_type] + + if model_type in MODEL_DATACLASS_REGISTRY: + # set defaults from dataclass. note that arch name and model name can be the same + dc = MODEL_DATACLASS_REGISTRY[model_type] + cfg = merge_with_parent(dc(), cfg) + + assert model is not None, f"Could not infer model type from {cfg}" + + return model.build_model(cfg, task) def register_model(name, dataclass=None): diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index aacd3e1d94..8ef61a6a7e 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -215,7 +215,7 @@ def zero_grad(self): raise RuntimeError("self.fp32_params must be a tensor or dict") else: for p32 in self.fp32_params: - if p32.grad: + if p32.grad is not None: p32.grad.zero_() self._needs_sync = False diff --git a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py index c3c6663ece..646ac66be9 100644 --- a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py @@ -74,7 +74,7 @@ def __init__( if isinstance(cfg.lr, Collection) and len(cfg.lr) > 1: raise ValueError( "Cannot use a fixed learning rate schedule with cosine." - " Consider --lr-scheduler=fixed instead." + f" Consider --lr-scheduler=fixed instead. ({cfg.lr})" ) warmup_end_lr = cfg.max_lr diff --git a/fairseq/registry.py b/fairseq/registry.py index 96994cb8d4..29631bb326 100644 --- a/fairseq/registry.py +++ b/fairseq/registry.py @@ -7,7 +7,7 @@ from typing import Union from fairseq.dataclass import FairseqDataclass -from fairseq.dataclass.utils import populate_dataclass +from fairseq.dataclass.utils import populate_dataclass, merge_with_parent from omegaconf import DictConfig REGISTRIES = {} @@ -24,11 +24,19 @@ def setup_registry(registry_name: str, base_class=None, default=None, required=F # maintain a registry of all registries if registry_name in REGISTRIES: return # registry already exists - REGISTRIES[registry_name] = {"registry": REGISTRY, "default": default, "dataclass_registry": DATACLASS_REGISTRY} + REGISTRIES[registry_name] = { + "registry": REGISTRY, + "default": default, + "dataclass_registry": DATACLASS_REGISTRY, + } def build_x(cfg: Union[DictConfig, str, Namespace], *extra_args, **extra_kwargs): if isinstance(cfg, DictConfig): choice = cfg._name + + if choice and choice in DATACLASS_REGISTRY: + dc = DATACLASS_REGISTRY[choice] + cfg = merge_with_parent(dc(), cfg) elif isinstance(cfg, str): choice = cfg if choice in DATACLASS_REGISTRY: @@ -40,7 +48,7 @@ def build_x(cfg: Union[DictConfig, str, Namespace], *extra_args, **extra_kwargs) if choice is None: if required: - raise ValueError('{} is required!'.format(registry_name)) + raise ValueError("{} is required!".format(registry_name)) return None cls = REGISTRY[choice] diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 41f461f802..7575ba429e 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -9,6 +9,7 @@ import os from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.utils import merge_with_parent from omegaconf import DictConfig from .fairseq_task import FairseqTask, LegacyFairseqTask # noqa @@ -21,9 +22,23 @@ def setup_task(cfg: DictConfig, **kwargs): - if isinstance(cfg, DictConfig): - return TASK_REGISTRY[cfg._name].setup_task(cfg, **kwargs) - return TASK_REGISTRY[cfg.task].setup_task(cfg, **kwargs) + task = None + task_name = getattr(cfg, "task", None) + + if isinstance(task_name, str): + # legacy tasks + task = TASK_REGISTRY[task_name] + else: + task_name = getattr(cfg, "_name", None) + + if task_name and task_name in TASK_DATACLASS_REGISTRY: + dc = TASK_DATACLASS_REGISTRY[task_name] + cfg = merge_with_parent(dc(), cfg) + task = TASK_REGISTRY[task_name] + + assert task is not None, f"Could not infer task type from {cfg}" + + return task.setup_task(cfg, **kwargs) def register_task(name, dataclass=None): diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index 6e85417ff5..79c225de6f 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -158,8 +158,8 @@ def setup_task(cls, args, **kwargs): dictionary, output_dictionary = cls.setup_dictionary(args, **kwargs) # upgrade old checkpoints - if hasattr(args, "exclude_self_target"): - args.self_target = not args.exclude_self_target + if getattr(args, "exclude_self_target", False): + args.self_target = False targets = [] if getattr(args, "self_target", False): @@ -176,7 +176,6 @@ def setup_task(cls, args, **kwargs): def build_model(self, args): model = super().build_model(args) - for target in self.targets: if target not in model.supported_targets: raise ValueError( diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py new file mode 100644 index 0000000000..24728c507f --- /dev/null +++ b/fairseq_cli/hydra_train.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import hydra +from omegaconf import OmegaConf + +from fairseq.dataclass.initialize import hydra_init +from fairseq_cli.train import main as pre_main +from fairseq import distributed_utils +from fairseq.dataclass.configs import FairseqConfig + +import logging +import torch + + +logger = logging.getLogger(__name__) + + +@hydra.main(config_path="../config", config_name="config") +def hydra_main(cfg: FairseqConfig) -> None: + + cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) + + OmegaConf.set_struct(cfg, True) + + if cfg.common.profile: + with torch.cuda.profiler.profile(): + with torch.autograd.profiler.emit_nvtx(): + distributed_utils.call_main(cfg, pre_main) + else: + distributed_utils.call_main(cfg, pre_main) + + +if __name__ == "__main__": + try: + from hydra._internal.utils import get_args + + cfg_name = get_args().config_name or "config" + except: + logger.warning("Failed to get config name from hydra args") + cfg_name = "config" + + hydra_init(cfg_name) + hydra_main() diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 9eeca18e92..e1af605348 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -48,8 +48,9 @@ def main(cfg: DictConfig) -> None: utils.import_user_module(cfg.common) - assert cfg.dataset.max_tokens is not None or cfg.dataset.batch_size is not None, \ - 'Must specify batch size either with --max-tokens or --batch-size' + assert ( + cfg.dataset.max_tokens is not None or cfg.dataset.batch_size is not None + ), "Must specify batch size either with --max-tokens or --batch-size" metrics.reset() np.random.seed(cfg.common.seed) @@ -64,22 +65,24 @@ def main(cfg: DictConfig) -> None: # Setup task, e.g., translation, language modeling, etc. task = tasks.setup_task(cfg.task) # Load valid dataset (we load training data below, based on the latest checkpoint) - for valid_sub_split in cfg.dataset.valid_subset.split(','): + for valid_sub_split in cfg.dataset.valid_subset.split(","): task.load_dataset(valid_sub_split, combine=False, epoch=1) + assert cfg.criterion, "Please specify criterion to train a model" + # Build model and criterion model = task.build_model(cfg.model) criterion = task.build_criterion(cfg.criterion) logger.info(model) - logger.info("task: {} ({})".format(cfg.task._name, task.__class__.__name__)) - logger.info("model: {} ({})".format(cfg.model._name, model.__class__.__name__)) + logger.info("task: {}".format(task.__class__.__name__)) + logger.info("model: {}".format(model.__class__.__name__)) + logger.info("criterion: {})".format(criterion.__class__.__name__)) logger.info( - "criterion: {} ({})".format(cfg.criterion._name, criterion.__class__.__name__) + "num. model params: {} (num. trained: {})".format( + sum(p.numel() for p in model.parameters()), + sum(p.numel() for p in model.parameters() if p.requires_grad), + ) ) - logger.info("num. model params: {} (num. trained: {})".format( - sum(p.numel() for p in model.parameters()), - sum(p.numel() for p in model.parameters() if p.requires_grad), - )) # (optionally) Configure quantization if cfg.common.quantization_config_path is not None: @@ -97,11 +100,17 @@ def main(cfg: DictConfig) -> None: else: trainer = MegatronTrainer(cfg, task, model, criterion) - logger.info('training on {} devices (GPUs/TPUs)'.format(cfg.distributed_training.distributed_world_size)) - logger.info('max tokens per GPU = {} and batch size per GPU = {}'.format( - cfg.dataset.max_tokens, - cfg.dataset.batch_size, - )) + logger.info( + "training on {} devices (GPUs/TPUs)".format( + cfg.distributed_training.distributed_world_size + ) + ) + logger.info( + "max tokens per GPU = {} and batch size per GPU = {}".format( + cfg.dataset.max_tokens, + cfg.dataset.batch_size, + ) + ) # Load the latest checkpoint if one is available and restore the # corresponding train iterator @@ -116,10 +125,7 @@ def main(cfg: DictConfig) -> None: lr = trainer.get_lr() train_meter = meters.StopwatchMeter() train_meter.start() - while ( - lr > cfg.optimization.min_lr - and epoch_itr.next_epoch_idx <= max_epoch - ): + while lr > cfg.optimization.min_lr and epoch_itr.next_epoch_idx <= max_epoch: # train for one epoch valid_losses, should_stop = train(cfg, trainer, task, epoch_itr) if should_stop: @@ -157,14 +163,20 @@ def is_better(a, b): else: should_stop_early.num_runs += 1 if should_stop_early.num_runs >= cfg.checkpoint.patience: - logger.info('early stop since valid performance hasn\'t improved for last {} runs'.format(cfg.checkpoint.patience)) + logger.info( + "early stop since valid performance hasn't improved for last {} runs".format( + cfg.checkpoint.patience + ) + ) return True else: return False @metrics.aggregate("train") -def train(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr) -> Tuple[List[Optional[float]], bool]: +def train( + cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr +) -> Tuple[List[Optional[float]], bool]: """Train the model for one epoch and return validation losses.""" # Initialize data iterator itr = epoch_itr.next_epoch_itr( @@ -185,7 +197,9 @@ def train(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr) log_interval=cfg.common.log_interval, epoch=epoch_itr.epoch, tensorboard_logdir=( - cfg.common.tensorboard_logdir if distributed_utils.is_master(cfg.distributed_training) else None + cfg.common.tensorboard_logdir + if distributed_utils.is_master(cfg.distributed_training) + else None ), default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), wandb_project=( @@ -195,7 +209,7 @@ def train(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr) trainer.begin_epoch(epoch_itr.epoch) - valid_subsets = cfg.dataset.valid_subset.split(',') + valid_subsets = cfg.dataset.valid_subset.split(",") should_stop = False num_updates = trainer.get_num_updates() for i, samples in enumerate(progress): @@ -233,7 +247,14 @@ def train(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr) return valid_losses, should_stop -def validate_and_save(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr, valid_subsets: List[str], end_of_epoch: bool) -> Tuple[List[Optional[float]], bool]: +def validate_and_save( + cfg: DictConfig, + trainer: Trainer, + task: tasks.FairseqTask, + epoch_itr, + valid_subsets: List[str], + end_of_epoch: bool, +) -> Tuple[List[Optional[float]], bool]: num_updates = trainer.get_num_updates() max_update = cfg.optimization.max_update or math.inf do_save = ( @@ -268,14 +289,17 @@ def validate_and_save(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask or num_updates >= max_update or ( cfg.optimization.stop_time_hours > 0 - and trainer.cumulative_training_time() / (60 * 60) > cfg.optimization.stop_time_hours + and trainer.cumulative_training_time() / (60 * 60) + > cfg.optimization.stop_time_hours ) ) # Save checkpoint if do_save or should_stop: logger.info("begin save checkpoint") - checkpoint_utils.save_checkpoint(cfg.checkpoint, trainer, epoch_itr, valid_losses[0]) + checkpoint_utils.save_checkpoint( + cfg.checkpoint, trainer, epoch_itr, valid_losses[0] + ) return valid_losses, should_stop @@ -285,7 +309,13 @@ def get_training_stats(stats: Dict[str, Any]) -> Dict[str, Any]: return stats -def validate(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_itr, subsets: List[str]) -> List[Optional[float]]: +def validate( + cfg: DictConfig, + trainer: Trainer, + task: tasks.FairseqTask, + epoch_itr, + subsets: List[str], +) -> List[Optional[float]]: """Evaluate the model on the validation set(s) and return the losses.""" if cfg.dataset.fixed_validation_seed is not None: @@ -308,7 +338,9 @@ def validate(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_i epoch=epoch_itr.epoch, prefix=f"valid on '{subset}' subset", tensorboard_logdir=( - cfg.common.tensorboard_logdir if distributed_utils.is_master(cfg.distributed_training) else None + cfg.common.tensorboard_logdir + if distributed_utils.is_master(cfg.distributed_training) + else None ), default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), wandb_project=( @@ -330,18 +362,23 @@ def validate(cfg: DictConfig, trainer: Trainer, task: tasks.FairseqTask, epoch_i return valid_losses -def get_valid_stats(cfg: DictConfig, trainer: Trainer, stats: Dict[str, Any]) -> Dict[str, Any]: +def get_valid_stats( + cfg: DictConfig, trainer: Trainer, stats: Dict[str, Any] +) -> Dict[str, Any]: stats["num_updates"] = trainer.get_num_updates() if hasattr(checkpoint_utils.save_checkpoint, "best"): key = "best_{0}".format(cfg.checkpoint.best_checkpoint_metric) best_function = max if cfg.checkpoint.maximize_best_checkpoint_metric else min stats[key] = best_function( - checkpoint_utils.save_checkpoint.best, stats[cfg.checkpoint.best_checkpoint_metric] + checkpoint_utils.save_checkpoint.best, + stats[cfg.checkpoint.best_checkpoint_metric], ) return stats -def cli_main(modify_parser: Optional[Callable[[argparse.ArgumentParser], None]] = None) -> None: +def cli_main( + modify_parser: Optional[Callable[[argparse.ArgumentParser], None]] = None +) -> None: parser = options.get_training_parser() args = options.parse_args_and_arch(parser, modify_parser=modify_parser) @@ -355,5 +392,5 @@ def cli_main(modify_parser: Optional[Callable[[argparse.ArgumentParser], None]] distributed_utils.call_main(cfg, main) -if __name__ == '__main__': +if __name__ == "__main__": cli_main() diff --git a/tests/test_fp16_optimizer.py b/tests/test_fp16_optimizer.py index 8de8e28ce0..ce4f1c055c 100644 --- a/tests/test_fp16_optimizer.py +++ b/tests/test_fp16_optimizer.py @@ -31,6 +31,9 @@ def setUp(self): self.cfg_dls = OmegaConf.create( { + "optimization": { + "lr": [0.1], + }, "optimizer": { "_name": "adam", "lr": [0.1], @@ -44,6 +47,7 @@ def setUp(self): "fp16_scale_tolerance": 1, "threshold_loss_scale": 1, "min_loss_scale": 1e-4, + "tpu": False, }, } ) From f57b14893837716bdaab4cb9a1430b19d4a6ccf7 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Thu, 5 Nov 2020 09:43:02 -0800 Subject: [PATCH 026/774] Require process group for all helpers in distributed_utils (#1395) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1395 Data parallel command: `python train.py --task dummy_lm --arch transformer_lm --tokens-per-sample 512 --max-sentences 8 --decoder-attention-heads 8 --dropout 0.0 --activation-dropout 0.0 --optimizer adam --lr 0.0001 --log-format simple --log-interval 1 --no-save --clip-norm 0.0` Data parallel before: ``` 2020-11-04 07:14:16 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 07:14:16 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 07:14:16 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last.pt 2020-11-04 07:14:16 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 07:14:16 | INFO | fairseq.trainer | NOTE: your device may support faster training with --fp16 2020-11-04 07:14:16 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 07:14:16 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 07:14:21 | INFO | train_inner | epoch 001: 1 / 1563 loss=16.297, ppl=80495, wps=0, ups=0, wpb=32768, bsz=64, num_updates=1, lr=0.0001, gnorm=2.501, train_wall=2, wall=5 2020-11-04 07:14:21 | INFO | train_inner | epoch 001: 2 / 1563 loss=15.399, ppl=43203.8, wps=101398, ups=3.09, wpb=32768, bsz=64, num_updates=2, lr=0.0001, gnorm=2.101, train_wall=0, wall=6 2020-11-04 07:14:21 | INFO | train_inner | epoch 001: 3 / 1563 loss=14.742, ppl=27411.2, wps=217567, ups=6.63, wpb=32768, bsz=64, num_updates=3, lr=0.0001, gnorm=1.888, train_wall=0, wall=6 2020-11-04 07:14:21 | INFO | train_inner | epoch 001: 4 / 1563 loss=14.206, ppl=18899.3, wps=219413, ups=6.69, wpb=32768, bsz=64, num_updates=4, lr=0.0001, gnorm=1.91, train_wall=0, wall=6 2020-11-04 07:14:22 | INFO | train_inner | epoch 001: 5 / 1563 loss=13.697, ppl=13282.1, wps=219446, ups=6.69, wpb=32768, bsz=64, num_updates=5, lr=0.0001, gnorm=1.98, train_wall=0, wall=6 2020-11-04 07:14:22 | INFO | train_inner | epoch 001: 6 / 1563 loss=13.179, ppl=9274.18, wps=220131, ups=6.71, wpb=32768, bsz=64, num_updates=6, lr=0.0001, gnorm=2.08, train_wall=0, wall=6 2020-11-04 07:14:22 | INFO | train_inner | epoch 001: 7 / 1563 loss=12.634, ppl=6358.37, wps=220236, ups=6.72, wpb=32768, bsz=64, num_updates=7, lr=0.0001, gnorm=2.195, train_wall=0, wall=6 2020-11-04 07:14:22 | INFO | train_inner | epoch 001: 8 / 1563 loss=12.056, ppl=4256.86, wps=220392, ups=6.72, wpb=32768, bsz=64, num_updates=8, lr=0.0001, gnorm=2.259, train_wall=0, wall=6 2020-11-04 07:14:22 | INFO | train_inner | epoch 001: 9 / 1563 loss=11.453, ppl=2804.05, wps=225842, ups=6.89, wpb=32768, bsz=64, num_updates=9, lr=0.0001, gnorm=2.287, train_wall=0, wall=7 2020-11-04 07:14:22 | INFO | train_inner | epoch 001: 10 / 1563 loss=10.842, ppl=1835, wps=238808, ups=7.28, wpb=32768, bsz=64, num_updates=10, lr=0.0001, gnorm=2.311, train_wall=0, wall=7 ``` Data parallel after: ``` 2020-11-04 07:14:47 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 07:14:47 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 07:14:47 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last.pt 2020-11-04 07:14:47 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 07:14:47 | INFO | fairseq.trainer | NOTE: your device may support faster training with --fp16 2020-11-04 07:14:47 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 07:14:47 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 07:14:52 | INFO | train_inner | epoch 001: 1 / 1563 loss=16.297, ppl=80495, wps=0, ups=0, wpb=32768, bsz=64, num_updates=1, lr=0.0001, gnorm=2.501, train_wall=2, wall=5 2020-11-04 07:14:52 | INFO | train_inner | epoch 001: 2 / 1563 loss=15.399, ppl=43203.8, wps=96089.4, ups=2.93, wpb=32768, bsz=64, num_updates=2, lr=0.0001, gnorm=2.101, train_wall=0, wall=5 2020-11-04 07:14:52 | INFO | train_inner | epoch 001: 3 / 1563 loss=14.742, ppl=27411.2, wps=239285, ups=7.3, wpb=32768, bsz=64, num_updates=3, lr=0.0001, gnorm=1.888, train_wall=0, wall=6 2020-11-04 07:14:53 | INFO | train_inner | epoch 001: 4 / 1563 loss=14.206, ppl=18899.3, wps=233039, ups=7.11, wpb=32768, bsz=64, num_updates=4, lr=0.0001, gnorm=1.91, train_wall=0, wall=6 2020-11-04 07:14:53 | INFO | train_inner | epoch 001: 5 / 1563 loss=13.697, ppl=13282.1, wps=237484, ups=7.24, wpb=32768, bsz=64, num_updates=5, lr=0.0001, gnorm=1.98, train_wall=0, wall=6 2020-11-04 07:14:53 | INFO | train_inner | epoch 001: 6 / 1563 loss=13.179, ppl=9274.18, wps=231683, ups=7.07, wpb=32768, bsz=64, num_updates=6, lr=0.0001, gnorm=2.08, train_wall=0, wall=6 2020-11-04 07:14:53 | INFO | train_inner | epoch 001: 7 / 1563 loss=12.634, ppl=6358.37, wps=233804, ups=7.13, wpb=32768, bsz=64, num_updates=7, lr=0.0001, gnorm=2.195, train_wall=0, wall=6 2020-11-04 07:14:53 | INFO | train_inner | epoch 001: 8 / 1563 loss=12.056, ppl=4256.86, wps=234025, ups=7.14, wpb=32768, bsz=64, num_updates=8, lr=0.0001, gnorm=2.259, train_wall=0, wall=6 2020-11-04 07:14:53 | INFO | train_inner | epoch 001: 9 / 1563 loss=11.453, ppl=2804.05, wps=238426, ups=7.27, wpb=32768, bsz=64, num_updates=9, lr=0.0001, gnorm=2.287, train_wall=0, wall=6 2020-11-04 07:14:53 | INFO | train_inner | epoch 001: 10 / 1563 loss=10.842, ppl=1835, wps=240069, ups=7.32, wpb=32768, bsz=64, num_updates=10, lr=0.0001, gnorm=2.311, train_wall=0, wall=6 ``` Model parallel command: `python train.py --task dummy_lm --arch transformer_lm_megatron --decoder-layers 2 --batch-size 2 --tokens-per-sample 512 --log-format simple --log-interval 1 --fp16 --optimizer adam --model-parallel-size 2 --share-decoder-input-output-embed --lr 0.0001` Model parallel before: ``` 2020-11-04 07:12:22 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 07:12:22 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 2 2020-11-04 07:12:22 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last-model_part-0.pt 2020-11-04 07:12:22 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 07:12:23 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 07:12:23 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 07:12:28 | INFO | train_inner | epoch 001: 1 / 12500 loss=60.017, ppl=1.16627e+18, wps=0, ups=0, wpb=4096, bsz=8, num_updates=1, lr=0.0001, gnorm=8.531, loss_scale=128, train_wall=2, wall=6 2020-11-04 07:12:28 | INFO | train_inner | epoch 001: 2 / 12500 loss=46.473, ppl=9.77028e+13, wps=48996.6, ups=11.95, wpb=4096, bsz=8, num_updates=2, lr=0.0001, gnorm=15.019, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:28 | INFO | train_inner | epoch 001: 3 / 12500 loss=30.525, ppl=1.54543e+09, wps=58424.2, ups=14.25, wpb=4096, bsz=8, num_updates=3, lr=0.0001, gnorm=13.936, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:28 | INFO | train_inner | epoch 001: 4 / 12500 loss=18.561, ppl=386799, wps=58399.5, ups=14.24, wpb=4096, bsz=8, num_updates=4, lr=0.0001, gnorm=7.251, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:28 | INFO | train_inner | epoch 001: 5 / 12500 loss=15.145, ppl=36230, wps=58275.6, ups=14.21, wpb=4096, bsz=8, num_updates=5, lr=0.0001, gnorm=2.392, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:28 | INFO | train_inner | epoch 001: 6 / 12500 loss=14.683, ppl=26304.2, wps=58704.8, ups=14.32, wpb=4096, bsz=8, num_updates=6, lr=0.0001, gnorm=2.487, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:28 | INFO | train_inner | epoch 001: 7 / 12500 loss=14.169, ppl=18418.9, wps=58449.2, ups=14.26, wpb=4096, bsz=8, num_updates=7, lr=0.0001, gnorm=2.45, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:29 | INFO | train_inner | epoch 001: 8 / 12500 loss=13.574, ppl=12197.4, wps=59106.5, ups=14.42, wpb=4096, bsz=8, num_updates=8, lr=0.0001, gnorm=2.393, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:29 | INFO | train_inner | epoch 001: 9 / 12500 loss=12.974, ppl=8047.87, wps=58619.6, ups=14.3, wpb=4096, bsz=8, num_updates=9, lr=0.0001, gnorm=2.317, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:12:29 | INFO | train_inner | epoch 001: 10 / 12500 loss=12.341, ppl=5187.55, wps=58166.5, ups=14.19, wpb=4096, bsz=8, num_updates=10, lr=0.0001, gnorm=2.213, loss_scale=128, train_wall=0, wall=6 ``` Model parallel after: ``` 2020-11-04 07:11:07 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 07:11:07 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 2 2020-11-04 07:11:07 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last-model_part-0.pt 2020-11-04 07:11:07 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 07:11:08 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 07:11:08 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 07:11:13 | INFO | train_inner | epoch 001: 1 / 12500 loss=60.017, ppl=1.16627e+18, wps=0, ups=0, wpb=4096, bsz=8, num_updates=1, lr=0.0001, gnorm=8.531, loss_scale=128, train_wall=2, wall=6 2020-11-04 07:11:13 | INFO | train_inner | epoch 001: 2 / 12500 loss=46.473, ppl=9.77028e+13, wps=47018.1, ups=11.47, wpb=4096, bsz=8, num_updates=2, lr=0.0001, gnorm=15.019, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:11:13 | INFO | train_inner | epoch 001: 3 / 12500 loss=30.525, ppl=1.54543e+09, wps=59292.6, ups=14.46, wpb=4096, bsz=8, num_updates=3, lr=0.0001, gnorm=13.936, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:11:13 | INFO | train_inner | epoch 001: 4 / 12500 loss=18.561, ppl=386799, wps=57708.9, ups=14.08, wpb=4096, bsz=8, num_updates=4, lr=0.0001, gnorm=7.251, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:11:14 | INFO | train_inner | epoch 001: 5 / 12500 loss=15.145, ppl=36230, wps=57427.4, ups=14.01, wpb=4096, bsz=8, num_updates=5, lr=0.0001, gnorm=2.392, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:11:14 | INFO | train_inner | epoch 001: 6 / 12500 loss=14.683, ppl=26304.2, wps=58730.2, ups=14.33, wpb=4096, bsz=8, num_updates=6, lr=0.0001, gnorm=2.487, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:11:14 | INFO | train_inner | epoch 001: 7 / 12500 loss=14.169, ppl=18418.9, wps=59523.2, ups=14.52, wpb=4096, bsz=8, num_updates=7, lr=0.0001, gnorm=2.45, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:11:14 | INFO | train_inner | epoch 001: 8 / 12500 loss=13.574, ppl=12197.4, wps=58945.2, ups=14.38, wpb=4096, bsz=8, num_updates=8, lr=0.0001, gnorm=2.393, loss_scale=128, train_wall=0, wall=6 2020-11-04 07:11:14 | INFO | train_inner | epoch 001: 9 / 12500 loss=12.974, ppl=8047.87, wps=59659.2, ups=14.55, wpb=4096, bsz=8, num_updates=9, lr=0.0001, gnorm=2.317, loss_scale=128, train_wall=0, wall=7 2020-11-04 07:11:14 | INFO | train_inner | epoch 001: 10 / 12500 loss=12.341, ppl=5187.55, wps=59681.4, ups=14.56, wpb=4096, bsz=8, num_updates=10, lr=0.0001, gnorm=2.213, loss_scale=128, train_wall=0, wall=7 ``` Test Plan: Imported from OSS Reviewed By: ngoyal2707 Differential Revision: D24728687 Pulled By: myleott fbshipit-source-id: 2d387d022ee889494f429b98df1942167896e306 --- .../multilingual/sampled_multi_dataset.py | 8 ++- fairseq/distributed_utils.py | 72 +++++++++++++------ fairseq/model_parallel/megatron_trainer.py | 12 ++-- fairseq/optim/fp16_optimizer.py | 5 +- fairseq/trainer.py | 7 +- fairseq_cli/validate.py | 1 + 6 files changed, 74 insertions(+), 31 deletions(-) diff --git a/fairseq/data/multilingual/sampled_multi_dataset.py b/fairseq/data/multilingual/sampled_multi_dataset.py index 3f544b099f..599f3a862b 100644 --- a/fairseq/data/multilingual/sampled_multi_dataset.py +++ b/fairseq/data/multilingual/sampled_multi_dataset.py @@ -160,9 +160,13 @@ def _sync_sample_ratios(self, ratios): ratios = torch.DoubleTensor(ratios) if torch.distributed.is_initialized(): if torch.cuda.is_available(): - distributed_utils.all_reduce(ratios.cuda()) + distributed_utils.all_reduce( + ratios.cuda(), group=distributed_utils.get_data_parallel_group() + ) else: - distributed_utils.all_reduce(ratios) + distributed_utils.all_reduce( + ratios, group=distributed_utils.get_data_parallel_group() + ) ret = ratios.cpu() ret = ret.numpy() return ret diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 3439508c94..9285f71e35 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -23,6 +23,11 @@ from omegaconf import open_dict +# Flag to indicate if we're using Megatron +# NOTE: this is a temporary hack until we move away from Megatron's model parallel init +_USE_MEGATRON = False + + logger = logging.getLogger(__name__) @@ -262,6 +267,8 @@ def distributed_init(cfg: FairseqConfig): "\n\n git submodule update --init " "fairseq/model_parallel/megatron" ) + global _USE_MEGATRON + _USE_MEGATRON = True initialize_model_parallel(cfg.common.model_parallel_size) model_parallel_cuda_manual_seed(cfg.common.seed) model_part_number = get_model_parallel_rank() @@ -319,26 +326,49 @@ def call_main(cfg: FairseqConfig, main, **kwargs): main(cfg, **kwargs) -def get_rank(): - return dist.get_rank() +def get_rank(group): + return dist.get_rank(group=group) + +def get_world_size(group): + return dist.get_world_size(group=group) -def get_world_size(): - return dist.get_world_size() + +def get_global_group(): + if torch.distributed.is_initialized(): + if not hasattr(get_global_group, "_global_group"): + # ideally we could use torch.distributed.group.WORLD, but it seems + # to cause random NCCL hangs in some cases + get_global_group._global_group = dist.new_group() + return get_global_group._global_group + else: + return None -def get_default_group(): - return dist.group.WORLD +def get_data_parallel_group(): + global _USE_MEGATRON + if _USE_MEGATRON: + from fairseq.model_parallel.megatron import mpu + return mpu.get_data_parallel_group() + else: + return get_global_group() + + +def get_model_parallel_group(): + global _USE_MEGATRON + if _USE_MEGATRON: + from fairseq.model_parallel.megatron import mpu + return mpu.get_model_parallel_group() + else: + return None -def all_reduce(tensor, group=None): +def all_reduce(tensor, group): if isinstance(group, tuple) and group[0] == "tpu": import torch_xla.core.xla_model as xm return xm.all_reduce("sum", [tensor], groups=group[1]) else: - if group is None: - group = get_default_group() return dist.all_reduce(tensor, group=group) @@ -350,12 +380,14 @@ def all_gather_list(data, group=None, max_size=16384): Args: data (Any): data from the local worker to be gathered on other workers - group (optional): group of the collective + group: group of the collective max_size (int, optional): maximum size of the data to be gathered across workers """ - rank = get_rank() - world_size = get_world_size() + if group is None: + group = get_global_group() + rank = get_rank(group=group) + world_size = get_world_size(group=group) buffer_size = max_size * world_size if ( @@ -410,7 +442,7 @@ def all_gather_list(data, group=None, max_size=16384): ) -def all_reduce_dict(data: Mapping[str, Any], device, group=None) -> Dict[str, Any]: +def all_reduce_dict(data: Mapping[str, Any], device, group) -> Dict[str, Any]: """ AllReduce a dictionary of values across workers. We separately reduce items that are already on the device and items on CPU for @@ -420,7 +452,7 @@ def all_reduce_dict(data: Mapping[str, Any], device, group=None) -> Dict[str, An data (Mapping[str, Any]): dictionary of data to all-reduce, but cannot be a nested dictionary device (torch.device): device for the reduction - group (optional): group of the collective + group: group of the collective """ data_keys = list(data.keys()) @@ -463,7 +495,7 @@ def get_from_stack(key): def broadcast_object( obj: Any, src_rank: int, - group: object = dist.group.WORLD, + group: object, dist_device: Optional[torch.device] = None, ) -> Any: """ @@ -476,23 +508,23 @@ def broadcast_object( else: dist_device = torch.device("cpu") - if dist.get_rank() == src_rank: + if get_rank(group) == src_rank: # Emit data buffer = io.BytesIO() torch.save(obj, buffer) data = bytearray(buffer.getbuffer()) - length_tensor = torch.LongTensor([len(data)]).to(dist_device) - data_send_tensor = torch.ByteTensor(data).to(dist_device) + length_tensor = torch.tensor([len(data)], dtype=torch.long, device=dist_device) + data_send_tensor = torch.tensor(data, dtype=torch.uint8, device=dist_device) dist.broadcast(length_tensor, src=src_rank, group=group, async_op=False) dist.broadcast(data_send_tensor, src=src_rank, group=group, async_op=False) else: # Fetch from the source - length_tensor = torch.LongTensor([0]).to(dist_device) + length_tensor = torch.tensor([0], dtype=torch.long, device=dist_device) dist.broadcast(length_tensor, src=src_rank, group=group, async_op=False) data_recv_tensor = torch.empty( [int(length_tensor.item())], dtype=torch.uint8, device=dist_device ) dist.broadcast(data_recv_tensor, src=src_rank, group=group, async_op=False) buffer = io.BytesIO(data_recv_tensor.cpu().numpy()) - obj = torch.load(buffer, map_location=dist_device) + obj = torch.load(buffer, map_location="cpu") return obj diff --git a/fairseq/model_parallel/megatron_trainer.py b/fairseq/model_parallel/megatron_trainer.py index a8c7bc9d98..b86b3d14de 100644 --- a/fairseq/model_parallel/megatron_trainer.py +++ b/fairseq/model_parallel/megatron_trainer.py @@ -13,10 +13,8 @@ try: from fairseq.model_parallel.megatron.mpu import ( - get_data_parallel_group, get_data_parallel_rank, get_data_parallel_world_size, - get_model_parallel_group, get_model_parallel_src_rank, get_cuda_rng_tracker, ) @@ -44,7 +42,7 @@ def data_parallel_world_size(self): @property def data_parallel_process_group(self): - return get_data_parallel_group() + return distributed_utils.get_data_parallel_group() @property def data_parallel_rank(self): @@ -57,7 +55,9 @@ def is_data_parallel_master(self): def clip_grad_norm(self, clip_norm): def _aggregate_model_parallel_grad_norm(total_norm): total_norm = total_norm ** 2 - distributed_utils.all_reduce(total_norm, group=get_model_parallel_group()) + distributed_utils.all_reduce( + total_norm, group=distributed_utils.get_model_parallel_group() + ) total_norm = total_norm ** 0.5 return total_norm @@ -71,7 +71,7 @@ def save_checkpoint(self, filename, extra_state): extra_state['rng_tracker_states'] \ = get_cuda_rng_tracker().get_states() super().save_checkpoint(filename, extra_state) - + def load_checkpoint( self, filename, @@ -84,4 +84,4 @@ def load_checkpoint( if extra_state is not None and 'rng_tracker_states' in extra_state: get_cuda_rng_tracker().set_states( extra_state['rng_tracker_states']) - return extra_state \ No newline at end of file + return extra_state diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index 8ef61a6a7e..2341f47077 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -127,7 +127,10 @@ def _sync_fp16_grads_to_fp32(self): if not p.requires_grad: continue if p.grad is not None: - p32.grad.data.copy_(p.grad.data) + if p32.grad is None: + p32.grad = p.grad.data.float() + else: + p32.grad.data.copy_(p.grad.data) else: p32.grad = torch.zeros_like(p.data, dtype=torch.float) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 657374aab7..c37ea5cbee 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -116,7 +116,9 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): if self.cuda: self.cuda_env = utils.CudaEnvironment() if self.data_parallel_world_size > 1: - self.cuda_env_arr = distributed_utils.all_gather_list(self.cuda_env) + self.cuda_env_arr = distributed_utils.all_gather_list( + self.cuda_env, group=distributed_utils.get_global_group() + ) else: self.cuda_env_arr = [self.cuda_env] if self.data_parallel_rank == 0: @@ -147,7 +149,7 @@ def data_parallel_process_group(self): if self.tpu: return ("tpu", None) else: - return None + return distributed_utils.get_data_parallel_group() @property def data_parallel_rank(self): @@ -325,6 +327,7 @@ def load_checkpoint( state, src_rank=0, group=group, + dist_device=self.device, ) if self.data_parallel_rank > 0: last_optim_state = state.get("last_optimizer_state", None) diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index a1e577ed7a..36e8bd16ca 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -115,6 +115,7 @@ def main(cfg: DictConfig, override_args=None): log_outputs = distributed_utils.all_gather_list( log_outputs, max_size=cfg.common.all_gather_list_size, + group=distributed_utils.get_data_parallel_group(), ) log_outputs = list(chain.from_iterable(log_outputs)) From b4d57c6d49682094efe22fbe2c03fa2c4973869f Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Thu, 5 Nov 2020 15:17:32 -0800 Subject: [PATCH 027/774] Move TPU grad reductions out of Trainer into TPUDistributedDataParallel (#1397) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1397 Data parallel command: `python train.py ~/data/data-bin/wikitext-103-roberta-bpe-bin/ --task language_modeling --arch transformer_lm --batch-size 8 --tokens-per-sample 512 --log-format simple --log-interval 1 --fp16 --optimizer adam --share-decoder-input-output-embed --lr 0.0001` Data parallel before: ``` 2020-11-04 08:20:13 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 08:20:13 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 08:20:13 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last.pt 2020-11-04 08:20:13 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 08:20:14 | INFO | fairseq.data.data_utils | loaded 1801350 examples from: /private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/train 2020-11-04 08:20:14 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 08:20:14 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 08:20:19 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-11-04 08:20:19 | INFO | train_inner | epoch 001: 2 / 3587 loss=19.682, ppl=841142, wps=0, ups=0, wpb=32768, bsz=64, num_updates=1, lr=0.0001, gnorm=13.17, loss_scale=64, train_wall=0, wall=5 2020-11-04 08:20:19 | INFO | train_inner | epoch 001: 3 / 3587 loss=16.721, ppl=108002, wps=160870, ups=4.91, wpb=32768, bsz=64, num_updates=2, lr=0.0001, gnorm=4.507, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:20:19 | INFO | train_inner | epoch 001: 4 / 3587 loss=16.07, ppl=68785.8, wps=517232, ups=15.77, wpb=32768, bsz=64, num_updates=3, lr=0.0001, gnorm=2.737, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:20:19 | INFO | train_inner | epoch 001: 5 / 3587 loss=15.714, ppl=53741.4, wps=537322, ups=16.38, wpb=32768, bsz=64, num_updates=4, lr=0.0001, gnorm=2.542, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:20:19 | INFO | train_inner | epoch 001: 6 / 3587 loss=15.441, ppl=44492.1, wps=540488, ups=16.48, wpb=32768, bsz=64, num_updates=5, lr=0.0001, gnorm=2.485, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:20:19 | INFO | train_inner | epoch 001: 7 / 3587 loss=15.199, ppl=37603.2, wps=543411, ups=16.57, wpb=32768, bsz=64, num_updates=6, lr=0.0001, gnorm=2.382, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:20:19 | INFO | train_inner | epoch 001: 8 / 3587 loss=14.984, ppl=32414, wps=540359, ups=16.47, wpb=32768, bsz=64, num_updates=7, lr=0.0001, gnorm=2.274, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:20:20 | INFO | train_inner | epoch 001: 9 / 3587 loss=14.7, ppl=26622.2, wps=533446, ups=16.26, wpb=32768, bsz=64, num_updates=8, lr=0.0001, gnorm=2.16, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:20:20 | INFO | train_inner | epoch 001: 10 / 3587 loss=14.482, ppl=22875.4, wps=539734, ups=16.46, wpb=32768, bsz=64, num_updates=9, lr=0.0001, gnorm=2.055, loss_scale=64, train_wall=0, wall=6 ``` Data parallel after: ``` 2020-11-04 08:14:02 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 08:14:02 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 08:14:02 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last.pt 2020-11-04 08:14:02 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 08:14:03 | INFO | fairseq.data.data_utils | loaded 1801350 examples from: /private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/train 2020-11-04 08:14:03 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 08:14:03 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 08:14:08 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-11-04 08:14:08 | INFO | train_inner | epoch 001: 2 / 3587 loss=19.682, ppl=841142, wps=0, ups=0, wpb=32768, bsz=64, num_updates=1, lr=0.0001, gnorm=13.17, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:08 | INFO | train_inner | epoch 001: 3 / 3587 loss=16.721, ppl=108002, wps=157099, ups=4.79, wpb=32768, bsz=64, num_updates=2, lr=0.0001, gnorm=4.507, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:08 | INFO | train_inner | epoch 001: 4 / 3587 loss=16.07, ppl=68785.8, wps=560049, ups=17.08, wpb=32768, bsz=64, num_updates=3, lr=0.0001, gnorm=2.737, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:08 | INFO | train_inner | epoch 001: 5 / 3587 loss=15.714, ppl=53741.4, wps=558507, ups=17.03, wpb=32768, bsz=64, num_updates=4, lr=0.0001, gnorm=2.542, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:08 | INFO | train_inner | epoch 001: 6 / 3587 loss=15.441, ppl=44492.1, wps=514194, ups=15.68, wpb=32768, bsz=64, num_updates=5, lr=0.0001, gnorm=2.485, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:08 | INFO | train_inner | epoch 001: 7 / 3587 loss=15.199, ppl=37603.2, wps=552676, ups=16.85, wpb=32768, bsz=64, num_updates=6, lr=0.0001, gnorm=2.382, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:09 | INFO | train_inner | epoch 001: 8 / 3587 loss=14.984, ppl=32414, wps=546402, ups=16.66, wpb=32768, bsz=64, num_updates=7, lr=0.0001, gnorm=2.274, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:09 | INFO | train_inner | epoch 001: 9 / 3587 loss=14.7, ppl=26622.2, wps=508472, ups=15.5, wpb=32768, bsz=64, num_updates=8, lr=0.0001, gnorm=2.16, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:09 | INFO | train_inner | epoch 001: 10 / 3587 loss=14.482, ppl=22875.4, wps=552493, ups=16.84, wpb=32768, bsz=64, num_updates=9, lr=0.0001, gnorm=2.055, loss_scale=64, train_wall=0, wall=6 ``` Data parallel command (no_c10d): `python train.py ~/data/data-bin/wikitext-103-roberta-bpe-bin/ --task language_modeling --arch transformer_lm --batch-size 8 --tokens-per-sample 512 --log-format simple --log-interval 1 --fp16 --optimizer adam --share-decoder-input-output-embed --lr 0.0001 --dp-backend no_c10d` Data parallel before: ``` 2020-11-04 08:19:25 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 08:19:25 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 08:19:25 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last.pt 2020-11-04 08:19:25 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 08:19:25 | INFO | fairseq.data.data_utils | loaded 1801350 examples from: /private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/train 2020-11-04 08:19:26 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 08:19:26 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 08:19:31 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-11-04 08:19:31 | INFO | train_inner | epoch 001: 2 / 3587 loss=19.682, ppl=841142, wps=0, ups=0, wpb=32768, bsz=64, num_updates=1, lr=0.0001, gnorm=13.17, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 3 / 3587 loss=16.721, ppl=108001, wps=141659, ups=4.32, wpb=32768, bsz=64, num_updates=2, lr=0.0001, gnorm=4.507, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 4 / 3587 loss=16.07, ppl=68785.9, wps=503762, ups=15.36, wpb=32768, bsz=64, num_updates=3, lr=0.0001, gnorm=2.737, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 5 / 3587 loss=15.714, ppl=53741.5, wps=488599, ups=14.9, wpb=32768, bsz=64, num_updates=4, lr=0.0001, gnorm=2.542, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 6 / 3587 loss=15.441, ppl=44492, wps=507855, ups=15.48, wpb=32768, bsz=64, num_updates=5, lr=0.0001, gnorm=2.485, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 7 / 3587 loss=15.199, ppl=37603, wps=503270, ups=15.34, wpb=32768, bsz=64, num_updates=6, lr=0.0001, gnorm=2.382, loss_scale=64, train_wall=0, wall=7 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 8 / 3587 loss=14.984, ppl=32414, wps=467778, ups=14.26, wpb=32768, bsz=64, num_updates=7, lr=0.0001, gnorm=2.274, loss_scale=64, train_wall=0, wall=7 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 9 / 3587 loss=14.7, ppl=26622.2, wps=503800, ups=15.36, wpb=32768, bsz=64, num_updates=8, lr=0.0001, gnorm=2.16, loss_scale=64, train_wall=0, wall=7 2020-11-04 08:19:32 | INFO | train_inner | epoch 001: 10 / 3587 loss=14.482, ppl=22875.3, wps=468486, ups=14.28, wpb=32768, bsz=64, num_updates=9, lr=0.0001, gnorm=2.055, loss_scale=64, train_wall=0, wall=7 ``` Data parallel after: ``` 2020-11-04 08:14:50 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 08:14:50 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 08:14:50 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last.pt 2020-11-04 08:14:50 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 08:14:50 | INFO | fairseq.data.data_utils | loaded 1801350 examples from: /private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/train 2020-11-04 08:14:51 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 08:14:51 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 08:14:56 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-11-04 08:14:56 | INFO | train_inner | epoch 001: 2 / 3587 loss=19.682, ppl=841142, wps=0, ups=0, wpb=32768, bsz=64, num_updates=1, lr=0.0001, gnorm=13.17, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:56 | INFO | train_inner | epoch 001: 3 / 3587 loss=16.721, ppl=108001, wps=137677, ups=4.2, wpb=32768, bsz=64, num_updates=2, lr=0.0001, gnorm=4.507, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:56 | INFO | train_inner | epoch 001: 4 / 3587 loss=16.07, ppl=68785.9, wps=519541, ups=15.84, wpb=32768, bsz=64, num_updates=3, lr=0.0001, gnorm=2.737, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:56 | INFO | train_inner | epoch 001: 5 / 3587 loss=15.714, ppl=53741.5, wps=517063, ups=15.76, wpb=32768, bsz=64, num_updates=4, lr=0.0001, gnorm=2.542, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:56 | INFO | train_inner | epoch 001: 6 / 3587 loss=15.441, ppl=44492, wps=490728, ups=14.95, wpb=32768, bsz=64, num_updates=5, lr=0.0001, gnorm=2.485, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:56 | INFO | train_inner | epoch 001: 7 / 3587 loss=15.199, ppl=37603, wps=505262, ups=15.41, wpb=32768, bsz=64, num_updates=6, lr=0.0001, gnorm=2.382, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:56 | INFO | train_inner | epoch 001: 8 / 3587 loss=14.984, ppl=32414, wps=508874, ups=15.52, wpb=32768, bsz=64, num_updates=7, lr=0.0001, gnorm=2.274, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:57 | INFO | train_inner | epoch 001: 9 / 3587 loss=14.7, ppl=26622.2, wps=518028, ups=15.79, wpb=32768, bsz=64, num_updates=8, lr=0.0001, gnorm=2.16, loss_scale=64, train_wall=0, wall=6 2020-11-04 08:14:57 | INFO | train_inner | epoch 001: 10 / 3587 loss=14.482, ppl=22875.3, wps=515996, ups=15.73, wpb=32768, bsz=64, num_updates=9, lr=0.0001, gnorm=2.055, loss_scale=64, train_wall=0, wall=7 ``` Model parallel command: `python train.py ~/data/data-bin/wikitext-103-roberta-bpe-bin/ --task language_modeling --arch transformer_lm_megatron --decoder-layers 4 --batch-size 8 --tokens-per-sample 512 --log-format simple --log-interval 1 --fp16 --optimizer adam --model-parallel-size 2 --share-decoder-input-output-embed --lr 0.0001` Model parallel before: ``` 2020-11-04 08:18:38 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 08:18:38 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 08:18:38 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last-model_part-0.pt 2020-11-04 08:18:38 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 08:18:38 | INFO | fairseq.data.data_utils | loaded 1801350 examples from: /private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/train 2020-11-04 08:18:39 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 08:18:39 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 08:18:44 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-11-04 08:18:45 | INFO | train_inner | epoch 001: 2 / 7173 loss=55.997, ppl=7.19017e+16, wps=0, ups=0, wpb=16384, bsz=32, num_updates=1, lr=0.0001, gnorm=14.03, loss_scale=64, train_wall=1, wall=7 2020-11-04 08:18:45 | INFO | train_inner | epoch 001: 3 / 7173 loss=28.372, ppl=3.47501e+08, wps=48371.7, ups=2.95, wpb=16384, bsz=32, num_updates=2, lr=0.0001, gnorm=15.339, loss_scale=64, train_wall=0, wall=8 2020-11-04 08:18:46 | INFO | train_inner | epoch 001: 4 / 7173 loss=15.855, ppl=59276.8, wps=72422.5, ups=4.42, wpb=16384, bsz=32, num_updates=3, lr=0.0001, gnorm=4.189, loss_scale=64, train_wall=0, wall=8 2020-11-04 08:18:46 | INFO | train_inner | epoch 001: 5 / 7173 loss=14.713, ppl=26858.7, wps=72933.5, ups=4.45, wpb=16384, bsz=32, num_updates=4, lr=0.0001, gnorm=4.751, loss_scale=64, train_wall=0, wall=8 2020-11-04 08:18:46 | INFO | train_inner | epoch 001: 6 / 7173 loss=13.901, ppl=15299.7, wps=71974.8, ups=4.39, wpb=16384, bsz=32, num_updates=5, lr=0.0001, gnorm=4.361, loss_scale=64, train_wall=0, wall=8 2020-11-04 08:18:46 | INFO | train_inner | epoch 001: 7 / 7173 loss=13.312, ppl=10169.5, wps=72897.8, ups=4.45, wpb=16384, bsz=32, num_updates=6, lr=0.0001, gnorm=3.307, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:18:47 | INFO | train_inner | epoch 001: 8 / 7173 loss=12.914, ppl=7720.21, wps=73044.6, ups=4.46, wpb=16384, bsz=32, num_updates=7, lr=0.0001, gnorm=5.473, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:18:47 | INFO | train_inner | epoch 001: 9 / 7173 loss=12.56, ppl=6036.72, wps=73453.1, ups=4.48, wpb=16384, bsz=32, num_updates=8, lr=0.0001, gnorm=6.112, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:18:47 | INFO | train_inner | epoch 001: 10 / 7173 loss=12.116, ppl=4437.77, wps=73442.6, ups=4.48, wpb=16384, bsz=32, num_updates=9, lr=0.0001, gnorm=4.415, loss_scale=64, train_wall=0, wall=9 ``` Model parallel after: ``` 2020-11-04 08:12:09 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) 2020-11-04 08:12:09 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 2020-11-04 08:12:09 | INFO | fairseq.trainer | no existing checkpoint found checkpoints/checkpoint_last-model_part-0.pt 2020-11-04 08:12:09 | INFO | fairseq.trainer | loading train data for epoch 1 2020-11-04 08:12:09 | INFO | fairseq.data.data_utils | loaded 1801350 examples from: /private/home/myleott/data/data-bin/wikitext-103-roberta-bpe-bin/train 2020-11-04 08:12:10 | INFO | fairseq.optim.adam | using FusedAdam 2020-11-04 08:12:10 | INFO | fairseq.trainer | begin training epoch 1 2020-11-04 08:12:16 | INFO | fairseq.trainer | NOTE: overflow detected, setting loss scale to: 64.0 2020-11-04 08:12:17 | INFO | train_inner | epoch 001: 2 / 7173 loss=55.997, ppl=7.19017e+16, wps=0, ups=0, wpb=16384, bsz=32, num_updates=1, lr=0.0001, gnorm=14.03, loss_scale=64, train_wall=1, wall=8 2020-11-04 08:12:17 | INFO | train_inner | epoch 001: 3 / 7173 loss=28.372, ppl=3.47501e+08, wps=53097, ups=3.24, wpb=16384, bsz=32, num_updates=2, lr=0.0001, gnorm=15.339, loss_scale=64, train_wall=0, wall=8 2020-11-04 08:12:17 | INFO | train_inner | epoch 001: 4 / 7173 loss=15.855, ppl=59276.8, wps=72355.5, ups=4.42, wpb=16384, bsz=32, num_updates=3, lr=0.0001, gnorm=4.189, loss_scale=64, train_wall=0, wall=8 2020-11-04 08:12:17 | INFO | train_inner | epoch 001: 5 / 7173 loss=14.713, ppl=26858.7, wps=70526.4, ups=4.3, wpb=16384, bsz=32, num_updates=4, lr=0.0001, gnorm=4.751, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:12:18 | INFO | train_inner | epoch 001: 6 / 7173 loss=13.901, ppl=15299.7, wps=73063.5, ups=4.46, wpb=16384, bsz=32, num_updates=5, lr=0.0001, gnorm=4.361, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:12:18 | INFO | train_inner | epoch 001: 7 / 7173 loss=13.312, ppl=10169.5, wps=73559.4, ups=4.49, wpb=16384, bsz=32, num_updates=6, lr=0.0001, gnorm=3.307, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:12:18 | INFO | train_inner | epoch 001: 8 / 7173 loss=12.914, ppl=7720.21, wps=72693.2, ups=4.44, wpb=16384, bsz=32, num_updates=7, lr=0.0001, gnorm=5.473, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:12:18 | INFO | train_inner | epoch 001: 9 / 7173 loss=12.56, ppl=6036.72, wps=73531.2, ups=4.49, wpb=16384, bsz=32, num_updates=8, lr=0.0001, gnorm=6.112, loss_scale=64, train_wall=0, wall=9 2020-11-04 08:12:19 | INFO | train_inner | epoch 001: 10 / 7173 loss=12.116, ppl=4437.77, wps=73187.6, ups=4.47, wpb=16384, bsz=32, num_updates=9, lr=0.0001, gnorm=4.415, loss_scale=64, train_wall=0, wall=10 ``` Test Plan: Imported from OSS Reviewed By: ngoyal2707 Differential Revision: D24729295 Pulled By: myleott fbshipit-source-id: beee8bdece3eaa0419a2e813990420411e507c75 --- README.md | 4 +- fairseq/checkpoint_utils.py | 8 +- fairseq/distributed_utils.py | 192 +++++++++++++++++--- fairseq/legacy_distributed_data_parallel.py | 12 +- fairseq/model_parallel/megatron_trainer.py | 16 -- fairseq/models/distributed_fairseq_model.py | 50 ++++- fairseq/optim/fairseq_optimizer.py | 5 + fairseq/optim/fp16_optimizer.py | 6 + fairseq/trainer.py | 64 +++---- fairseq/utils.py | 2 +- 10 files changed, 272 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index 70e98fe395..13b8223959 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ We provide reference implementations of various sequence modeling papers: - Attention Is All You Need (Vaswani et al., 2017) - [Scaling Neural Machine Translation (Ott et al., 2018)](examples/scaling_nmt/README.md) - [Understanding Back-Translation at Scale (Edunov et al., 2018)](examples/backtranslation/README.md) - - [Adaptive Input Representations for Neural Language Modeling (Baevski and Auli, 2018)](examples/language_model/transformer_lm/README.md) + - [Adaptive Input Representations for Neural Language Modeling (Baevski and Auli, 2018)](examples/language_model/README.adaptive_inputs.md) - [Lexically constrained decoding with dynamic beam allocation (Post & Vilar, 2018)](examples/constrained_decoding/README.md) - [Mixture Models for Diverse Machine Translation: Tricks of the Trade (Shen et al., 2019)](examples/translation_moe/README.md) - [RoBERTa: A Robustly Optimized BERT Pretraining Approach (Liu et al., 2019)](examples/roberta/README.md) @@ -171,7 +171,7 @@ We also have more detailed READMEs to reproduce results from specific papers: - [Hierarchical Neural Story Generation (Fan et al., 2018)](examples/stories/README.md) - [Scaling Neural Machine Translation (Ott et al., 2018)](examples/scaling_nmt/README.md) - [Convolutional Sequence to Sequence Learning (Gehring et al., 2017)](examples/conv_seq2seq/README.md) -- [Language Modeling with Gated Convolutional Networks (Dauphin et al., 2017)](examples/language_model/conv_lm/README.md) +- [Language Modeling with Gated Convolutional Networks (Dauphin et al., 2017)](examples/language_model/README.conv.md) # Join the fairseq community diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index fdee84c181..25d3e1e705 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -13,6 +13,7 @@ from typing import Optional, Union import torch +from fairseq import utils from fairseq.dataclass.configs import CheckpointConfig, FairseqConfig from fairseq.dataclass.utils import ( convert_namespace_to_omegaconf, @@ -225,9 +226,7 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): def load_checkpoint_to_cpu(path, arg_overrides=None): """Loads a checkpoint to CPU (with upgrading for backward compatibility).""" with open(PathManager.get_local_path(path), "rb") as f: - state = torch.load( - f, map_location=lambda s, l: default_restore_location(s, "cpu") - ) + state = torch.load(f, map_location=torch.device("cpu")) if "args" in state and state["args"] is not None and arg_overrides is not None: args = state["args"] @@ -385,6 +384,9 @@ def save_state( if not no_save_optimizer_state: state_dict["last_optimizer_state"] = optimizer.state_dict() + # keep everything on CPU + state_dict = utils.move_to_cpu(state_dict) + with PathManager.open(filename, "wb") as f: torch_persistent_save(state_dict, f) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 9285f71e35..9059d8aa2b 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -14,7 +14,7 @@ import warnings from argparse import Namespace from collections import OrderedDict -from typing import Any, Dict, Mapping, Optional +from typing import Any, Dict, List, Mapping, Optional import torch import torch.distributed as dist @@ -22,11 +22,19 @@ from fairseq.dataclass.configs import DistributedTrainingConfig, FairseqConfig from omegaconf import open_dict +try: + import torch_xla.core.xla_model as xm +except ImportError: + xm = None + # Flag to indicate if we're using Megatron # NOTE: this is a temporary hack until we move away from Megatron's model parallel init _USE_MEGATRON = False +# Whether to use XLA ops (e.g., on TPUs) instead of CUDA ops. +_USE_XLA = False + logger = logging.getLogger(__name__) @@ -241,9 +249,9 @@ def distributed_init(cfg: FairseqConfig): cfg.distributed_training.distributed_rank = torch.distributed.get_rank() else: - import torch_xla.core.xla_model as xm - assert xm.xrt_world_size() == cfg.distributed_training.distributed_world_size + global _USE_XLA + _USE_XLA = True cfg.distributed_training.device_id = xm.get_local_ordinal() cfg.distributed_training.distributed_rank = xm.get_ordinal() xm.rendezvous("distributed_init") # wait for all workers @@ -257,7 +265,6 @@ def distributed_init(cfg: FairseqConfig): if cfg.common.model_parallel_size > 1: try: from fairseq.model_parallel.megatron.mpu import ( - get_model_parallel_rank, initialize_model_parallel, model_parallel_cuda_manual_seed, ) @@ -273,6 +280,7 @@ def distributed_init(cfg: FairseqConfig): model_parallel_cuda_manual_seed(cfg.common.seed) model_part_number = get_model_parallel_rank() cfg.checkpoint.checkpoint_suffix += "-model_part-{0}".format(model_part_number) + return cfg.distributed_training.distributed_rank @@ -326,16 +334,55 @@ def call_main(cfg: FairseqConfig, main, **kwargs): main(cfg, **kwargs) +def use_xla(): + global _USE_XLA + return _USE_XLA + + +def new_groups(grouped_ranks: List[List[int]]): + if use_xla(): + return ("tpu", grouped_ranks) + else: + groups = [dist.new_group(g) for g in grouped_ranks] + my_group_idx = _find_my_group_index(grouped_ranks) + return groups[my_group_idx] + + +def _find_my_group_index(grouped_ranks): + my_rank = get_global_rank() + for i, group in enumerate(grouped_ranks): + if my_rank in group: + return i + raise RuntimeError + + +def _find_my_group(grouped_ranks): + index = _find_my_group_index(grouped_ranks) + return grouped_ranks[index] + + def get_rank(group): - return dist.get_rank(group=group) + if use_xla(): + assert group[0] == "tpu" + my_group = _find_my_group(group[1]) + return my_group.index(get_global_rank()) + else: + return dist.get_rank(group=group) def get_world_size(group): - return dist.get_world_size(group=group) + if use_xla(): + assert group[0] == "tpu" + my_group = _find_my_group(group[1]) + return len(my_group) + else: + return dist.get_world_size(group=group) def get_global_group(): - if torch.distributed.is_initialized(): + if use_xla(): + return new_groups([list(range(get_global_world_size()))]) + elif torch.distributed.is_initialized(): if not hasattr(get_global_group, "_global_group"): # ideally we could use torch.distributed.group.WORLD, but it seems # to cause random NCCL hangs in some cases @@ -345,7 +392,26 @@ def get_global_group(): return None +def get_global_rank(): + if use_xla(): + return xm.get_ordinal() + elif torch.distributed.is_initialized(): + return torch.distributed.get_rank() + else: + return 0 + + +def get_global_world_size(): + if use_xla(): + return xm.xrt_world_size() + elif torch.distributed.is_initialized(): + return torch.distributed.get_world_size() + else: + return 1 + + def get_data_parallel_group(): + """Get the data parallel group the caller rank belongs to.""" global _USE_MEGATRON if _USE_MEGATRON: from fairseq.model_parallel.megatron import mpu @@ -354,6 +420,16 @@ def get_data_parallel_group(): return get_global_group() +def get_data_parallel_rank(): + """Return my rank for the data parallel group.""" + return get_rank(get_data_parallel_group()) + + +def get_data_parallel_world_size(): + """Return world size for the data parallel group.""" + return get_world_size(get_data_parallel_group()) + + def get_model_parallel_group(): global _USE_MEGATRON if _USE_MEGATRON: @@ -363,13 +439,83 @@ def get_model_parallel_group(): return None -def all_reduce(tensor, group): - if isinstance(group, tuple) and group[0] == "tpu": - import torch_xla.core.xla_model as xm +def get_model_parallel_rank(): + """Return my rank for the model parallel group.""" + return get_rank(get_model_parallel_group()) + + +def get_model_parallel_world_size(): + """Return world size for the model parallel group.""" + return get_world_size(get_model_parallel_group()) - return xm.all_reduce("sum", [tensor], groups=group[1]) + +def all_reduce(tensor, group, op="sum"): + if use_xla(): + assert isinstance(group, tuple) and group[0] == "tpu" + tensor = [tensor] # wrap in a list to make xm.all_reduce in-place + return xm.all_reduce(op, tensor, groups=group[1])[0] else: - return dist.all_reduce(tensor, group=group) + if op == "sum": + op = dist.ReduceOp.SUM + elif op == "max": + op = dist.ReduceOp.MAX + else: + raise NotImplementedError + dist.all_reduce(tensor, op=op, group=group) + return tensor + + +def broadcast(tensor, src, group): + if use_xla(): + # XLA doesn't support broadcast, hack it with all_reduce + if get_rank(group) != src: + tensor.zero_() + all_reduce(tensor, group) + else: + dist.broadcast(tensor, src=src, group=group) + + +def all_to_all(tensor, group): + """Perform an all-to-all operation on a 1D Tensor.""" + assert tensor.dim() == 1 + split_count = get_world_size(group=group) + assert tensor.numel() % split_count == 0 + if use_xla(): + assert isinstance(group, tuple) and group[0] == "tpu" + return xm.all_to_all( + tensor, + split_dimension=0, + concat_dimension=0, + split_count=split_count, + groups=group[1], + ) + else: + output = torch.zeros_like(tensor) + dist.all_to_all_single(output, tensor, group=group) + return output + + +def all_gather(tensor, group, return_tensor=False): + """Perform an all-gather operation.""" + if use_xla(): + result = xm.all_gather(tensor, groups=group[1]) + world_size = get_world_size(group=group) + result = result.view(world_size, *tensor.size()) + if return_tensor: + return result + else: + return [result[i] for i in range(world_size)] + else: + world_size = get_world_size(group=group) + rank = get_rank(group=group) + tensor_list = [ + tensor if i == rank else torch.empty_like(tensor) for i in range(world_size) + ] + dist.all_gather(tensor_list, tensor, group=group) + if return_tensor: + return torch.stack(tensor_list, dim=0) + else: + return tensor_list def all_gather_list(data, group=None, max_size=16384): @@ -497,6 +643,8 @@ def broadcast_object( src_rank: int, group: object, dist_device: Optional[torch.device] = None, + dist_length_dtype: Optional[torch.dtype] = torch.long, + dist_dtype: Optional[torch.dtype] = torch.uint8, ) -> Any: """ Either broadcast from master to the fleet (default), @@ -513,18 +661,20 @@ def broadcast_object( buffer = io.BytesIO() torch.save(obj, buffer) data = bytearray(buffer.getbuffer()) - length_tensor = torch.tensor([len(data)], dtype=torch.long, device=dist_device) - data_send_tensor = torch.tensor(data, dtype=torch.uint8, device=dist_device) - dist.broadcast(length_tensor, src=src_rank, group=group, async_op=False) - dist.broadcast(data_send_tensor, src=src_rank, group=group, async_op=False) + length_tensor = torch.tensor( + [len(data)], dtype=dist_length_dtype, device=dist_device + ) + broadcast(length_tensor, src=src_rank, group=group) + data_send_tensor = torch.tensor(data, dtype=dist_dtype, device=dist_device) + broadcast(data_send_tensor, src=src_rank, group=group) else: # Fetch from the source - length_tensor = torch.tensor([0], dtype=torch.long, device=dist_device) - dist.broadcast(length_tensor, src=src_rank, group=group, async_op=False) - data_recv_tensor = torch.empty( - [int(length_tensor.item())], dtype=torch.uint8, device=dist_device + length_tensor = torch.tensor([0], dtype=dist_length_dtype, device=dist_device) + broadcast(length_tensor, src=src_rank, group=group) + data_recv_tensor = torch.zeros( + [int(length_tensor.item())], dtype=dist_dtype, device=dist_device ) - dist.broadcast(data_recv_tensor, src=src_rank, group=group, async_op=False) + broadcast(data_recv_tensor, src=src_rank, group=group) buffer = io.BytesIO(data_recv_tensor.cpu().numpy()) obj = torch.load(buffer, map_location="cpu") return obj diff --git a/fairseq/legacy_distributed_data_parallel.py b/fairseq/legacy_distributed_data_parallel.py index 44f87c7c42..7e176eaf3d 100644 --- a/fairseq/legacy_distributed_data_parallel.py +++ b/fairseq/legacy_distributed_data_parallel.py @@ -34,20 +34,18 @@ class LegacyDistributedDataParallel(nn.Module): Args: module (~torch.nn.Module): module to be parallelized - world_size (int): number of parallel workers - process_group (optional): the c10d process group to be used for - distributed data all-reduction. If None, the default process group - will be used. + process_group: the c10d process group to be used for distributed data + parallel all-reduction. buffer_size (int, optional): number of elements to buffer before performing all-reduce (default: 256M). """ - def __init__(self, module, world_size, process_group=None, buffer_size=2 ** 28): + def __init__(self, module, process_group, buffer_size=2 ** 28): super().__init__() self.module = module - self.world_size = world_size self.process_group = process_group + self.world_size = distributed_utils.get_world_size(self.process_group) # Never use a bigger buffer than the number of model params self.buffer_size = min(buffer_size, sum(p.numel() for p in module.parameters())) @@ -84,7 +82,7 @@ def no_sync(self): def forward(self, *inputs, **kwargs): return self.module(*inputs, **kwargs) - def all_reduce(self): + def all_reduce_grads(self): """ This function must be called explicitly after backward to reduce gradients. There is no automatic hook like c10d. diff --git a/fairseq/model_parallel/megatron_trainer.py b/fairseq/model_parallel/megatron_trainer.py index b86b3d14de..1a6e844aee 100644 --- a/fairseq/model_parallel/megatron_trainer.py +++ b/fairseq/model_parallel/megatron_trainer.py @@ -36,22 +36,6 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, **kwargs): ) super().__init__(cfg, task, model, criterion, **kwargs) - @property - def data_parallel_world_size(self): - return get_data_parallel_world_size() - - @property - def data_parallel_process_group(self): - return distributed_utils.get_data_parallel_group() - - @property - def data_parallel_rank(self): - return get_data_parallel_rank() - - @property - def is_data_parallel_master(self): - return get_model_parallel_src_rank() == 0 - def clip_grad_norm(self, clip_norm): def _aggregate_model_parallel_grad_norm(total_norm): total_norm = total_norm ** 2 diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index ece10c6333..b78a0125e3 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -5,7 +5,10 @@ import inspect +import torch import torch.nn as nn + +from fairseq import distributed_utils from fairseq.legacy_distributed_data_parallel import LegacyDistributedDataParallel @@ -16,7 +19,7 @@ _GOSSIP_DISABLED = True -def DistributedFairseqModel(args, model, process_group=None): +def DistributedFairseqModel(args, model, process_group): """ Wrap a *model* to support distributed data parallel training. @@ -28,10 +31,18 @@ def DistributedFairseqModel(args, model, process_group=None): Args: args (argparse.Namespace): fairseq args model (BaseFairseqModel): model to wrap + process_group: the c10d process group to be used for distributed data + parallel all-reduction. """ # determine which DDP class to extend assert isinstance(model, nn.Module) - if args.distributed_wrapper == "DDP" and args.ddp_backend == "c10d": + if args.tpu: + ddp_class = TPUDistributedDataParallel + init_kwargs = dict( + module=model, + process_group=process_group, + ) + elif args.distributed_wrapper == "DDP" and args.ddp_backend == "c10d": ddp_class = nn.parallel.DistributedDataParallel init_kwargs = dict( module=model, @@ -50,7 +61,6 @@ def DistributedFairseqModel(args, model, process_group=None): ddp_class = LegacyDistributedDataParallel init_kwargs = dict( module=model, - world_size=args.distributed_world_size, buffer_size=2 ** 28, process_group=process_group, ) @@ -101,3 +111,37 @@ def __getattr__(self, name): return super().__getattr__(name) return _DistributedFairseqModel(**init_kwargs) + + +class TPUDistributedDataParallel(nn.Module): + + def __init__(self, module, process_group): + super().__init__() + self.module = module + self.process_group = process_group + self.world_size = distributed_utils.get_world_size(self.process_group) + + def forward(self, *inputs, **kwargs): + return self.module(*inputs, **kwargs) + + def all_reduce_grads(self): + gradients = [] + for p in self.parameters(): + if not p.requires_grad: + continue + if p.grad is None: + p.grad = torch.zeros_like(p) + if p.grad.requires_grad: + raise RuntimeError( + "TPUDistributedDataParallel only works with gradients that don't " + "require grad" + ) + gradients.append(p.grad) + + import torch_xla.core.xla_model as xm + xm.all_reduce( + 'sum', + gradients, + scale=1. / self.world_size, + groups=self.process_group[1], + ) diff --git a/fairseq/optim/fairseq_optimizer.py b/fairseq/optim/fairseq_optimizer.py index e91e9d3204..f9864533b6 100644 --- a/fairseq/optim/fairseq_optimizer.py +++ b/fairseq/optim/fairseq_optimizer.py @@ -94,6 +94,11 @@ def backward(self, loss): """Computes the sum of gradients of the given tensor w.r.t. graph leaves.""" loss.backward() + def all_reduce_grads(self, module): + """Manually all-reduce gradients (if required).""" + if hasattr(module, "all_reduce_grads"): + module.all_reduce_grads() + def multiply_grads(self, c): """Multiplies grads by a constant *c*.""" for p in self.params: diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index 2341f47077..7fe3bdd5e5 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -304,6 +304,9 @@ def get_lr(self): def set_lr(self, lr): self.fp32_optimizer.set_lr(lr) + def all_reduce_grads(self, module): + self.fp32_optimizer.all_reduce_grads(module) + class _MemoryEfficientFP16OptimizerMixin(object): def __init__(self, *args, **kwargs): @@ -498,3 +501,6 @@ def get_lr(self): def set_lr(self, lr): self.wrapped_optimizer.set_lr(lr) + + def all_reduce_grads(self, module): + self.wrapped_optimizer.all_reduce_grads(module) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index c37ea5cbee..33207a4cc0 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -63,10 +63,6 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): # copy model and criterion to current device/dtype self._criterion = criterion self._model = model - if self.tpu: - import torch_xla.core.xla_model as xm - - self._model = xm.send_cpu_data_to_device(self._model, self.device) if cfg.common.fp16: self._criterion = self._criterion.half() self._model = self._model.half() @@ -142,22 +138,25 @@ def reinitialize(self): @property def data_parallel_world_size(self): - return self.cfg.distributed_training.distributed_world_size + if self.cfg.distributed_training.distributed_world_size == 1: + return 1 + return distributed_utils.get_data_parallel_world_size() @property def data_parallel_process_group(self): - if self.tpu: - return ("tpu", None) - else: - return distributed_utils.get_data_parallel_group() + return distributed_utils.get_data_parallel_group() @property def data_parallel_rank(self): - return self.cfg.distributed_training.distributed_rank + if self.cfg.distributed_training.distributed_world_size == 1: + return 0 + return distributed_utils.get_data_parallel_rank() @property def is_data_parallel_master(self): - return distributed_utils.is_master(self.cfg.distributed_training) + # NOTE: this returns true for all model parallel replicas with data + # parallel rank 0 + return self.data_parallel_rank == 0 @property def criterion(self): @@ -166,7 +165,6 @@ def criterion(self): utils.has_parameters(self._criterion) and self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf - and not self.tpu ): self._wrapped_criterion = models.DistributedFairseqModel( self.cfg.distributed_training, @@ -183,7 +181,6 @@ def model(self): if ( self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf - and not self.tpu ): self._wrapped_model = models.DistributedFairseqModel( self.cfg.distributed_training, @@ -300,7 +297,12 @@ def load_checkpoint( bexists = PathManager.isfile(filename) if bexists: - if self.data_parallel_rank == 0: + if ( + self.data_parallel_rank == 0 + # TPUs don't support broadcast yet, so load checkpoints + # on every worker for now + or self.tpu + ): state = checkpoint_utils.load_checkpoint_to_cpu(filename) last_optim_state = state.get("last_optimizer_state", None) @@ -317,16 +319,15 @@ def load_checkpoint( last_optim_state = None state = None - if self.data_parallel_world_size > 1: - group = ( - self.data_parallel_process_group - if self.data_parallel_process_group is not None - else torch.distributed.group.WORLD - ) + if ( + self.data_parallel_world_size > 1 + # disable on TPUs until they support broadcast + and not self.tpu + ): state = distributed_utils.broadcast_object( state, src_rank=0, - group=group, + group=self.data_parallel_process_group, dist_device=self.device, ) if self.data_parallel_rank > 0: @@ -607,23 +608,17 @@ def maybe_no_sync(): total_train_time / self.data_parallel_world_size ) - if hasattr(self.model, "all_reduce"): - self.model.all_reduce() - overflow = False try: - if self.tpu and self.data_parallel_world_size > 1: - import torch_xla.core.xla_model as xm - - gradients = xm._fetch_gradients(self.optimizer.optimizer) - xm.all_reduce( - "sum", gradients, scale=1.0 / self.data_parallel_world_size - ) + with torch.autograd.profiler.record_function("reduce-grads"): + self.optimizer.all_reduce_grads(self.model) + if utils.has_parameters(self.criterion): + self.optimizer.all_reduce_grads(self.criterion) with torch.autograd.profiler.record_function("multiply-grads"): - # multiply gradients by (# GPUs / sample_size) since DDP - # already normalizes by the number of GPUs. Thus we get - # (sum_of_gradients / sample_size). + # multiply gradients by (data_parallel_size / sample_size) since + # DDP already normalizes by the number of data parallel workers. + # Thus we get (sum_of_gradients / sample_size) at the end. if not self.cfg.optimization.use_bmuf: self.optimizer.multiply_grads( self.data_parallel_world_size / sample_size @@ -683,6 +678,7 @@ def maybe_no_sync(): self.optimizer.optimizer ) + logging_output = None if ( not overflow or self.cfg.distributed_training.distributed_wrapper == "SlowMo" diff --git a/fairseq/utils.py b/fairseq/utils.py index 87c124b736..8e9119124d 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -641,7 +641,7 @@ def new_arange(x, *size): return torch.arange(size[-1], device=x.device).expand(*size).contiguous() -def get_tpu_device(args): +def get_tpu_device(): return xm.xla_device() From 83c39c41388f2e7ba37647d2e8a0cbc97f6f8032 Mon Sep 17 00:00:00 2001 From: Alex Xiao Date: Thu, 5 Nov 2020 16:12:24 -0800 Subject: [PATCH 028/774] fix fd issues for ce training with extra splits Summary: Some folks are still reporiting errors like in P145050739, ``` ValueError: too many fds ``` This diff follows up with D24234470 (https://github.com/pytorch/fairseq/commit/a9baca376616bed56e5df5115d7adf8059c0d296), where we add support for `supports_fetch_outside_dataloader` to the rest of the datsets we use, including the sampling datasets enabled by --extra-splits. For why we need to add `supports_fetch_outside_dataloader` see D24234470 (https://github.com/pytorch/fairseq/commit/a9baca376616bed56e5df5115d7adf8059c0d296) Differential Revision: D24767506 fbshipit-source-id: 4e0252f70a9aa36155843677734f186fe03508c4 --- fairseq/data/multi_corpus_dataset.py | 7 +++++++ fairseq/data/multi_corpus_sampled_dataset.py | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index d2457666d6..9c7f1cb976 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -157,3 +157,10 @@ def set_epoch(self, epoch, **unused): @property def supports_prefetch(self): return False + + @property + def supports_fetch_outside_dataloader(self): + return all( + self.datasets[key].supports_fetch_outside_dataloader + for key in self.datasets + ) diff --git a/fairseq/data/multi_corpus_sampled_dataset.py b/fairseq/data/multi_corpus_sampled_dataset.py index ad8e951cc9..e2e9fdf004 100644 --- a/fairseq/data/multi_corpus_sampled_dataset.py +++ b/fairseq/data/multi_corpus_sampled_dataset.py @@ -143,3 +143,10 @@ def prefetch(self, indices): dataset.prefetch( [self._map_index_to_dataset(key, index) for index in indices] ) + + @property + def supports_fetch_outside_dataloader(self): + return all( + self.datasets[key].supports_fetch_outside_dataloader + for key in self.datasets + ) From 77c704dc866c1e85259153ec98917f5acc7c9d90 Mon Sep 17 00:00:00 2001 From: alexeib Date: Fri, 6 Nov 2020 10:23:11 -0800 Subject: [PATCH 029/774] Misc fixes2 (#1402) Summary: Fixes #2855 Fixes #2847 Fixes #2841 Fixes #2783 make omegaconf strict warning not show up Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1402 Reviewed By: myleott Differential Revision: D24777582 Pulled By: alexeib fbshipit-source-id: 389e110c9de90c4a0744d01982f8071a7a867f09 --- examples/speech_recognition/w2l_decoder.py | 18 +++++++++++++----- fairseq/dataclass/utils.py | 14 +++++++++++--- fairseq/models/wav2vec/wav2vec2_asr.py | 2 +- fairseq_cli/score.py | 2 +- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/examples/speech_recognition/w2l_decoder.py b/examples/speech_recognition/w2l_decoder.py index f760cd6df2..e2870df6a7 100644 --- a/examples/speech_recognition/w2l_decoder.py +++ b/examples/speech_recognition/w2l_decoder.py @@ -20,6 +20,8 @@ from examples.speech_recognition.data.replabels import unpack_replabels from fairseq import tasks from fairseq.utils import apply_to_sample +from omegaconf import open_dict +from fairseq.dataclass.utils import convert_namespace_to_omegaconf try: @@ -347,11 +349,17 @@ def __init__(self, args, tgt_dict): self.idx_to_wrd = {} checkpoint = torch.load(args.kenlm_model, map_location="cpu") - lm_args = checkpoint["args"] - lm_args.data = osp.dirname(args.kenlm_model) - print(lm_args) - task = tasks.setup_task(lm_args) - model = task.build_model(lm_args) + + if "cfg" in checkpoint and checkpoint["cfg"] is not None: + lm_args = checkpoint["cfg"] + else: + lm_args = convert_namespace_to_omegaconf(checkpoint["args"]) + + with open_dict(lm_args.task): + lm_args.task.data = osp.dirname(args.kenlm_model) + + task = tasks.setup_task(lm_args.task) + model = task.build_model(lm_args.model) model.load_state_dict(checkpoint["model"], strict=False) self.trie = Trie(self.vocab_size, self.silence) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 477a198d0f..d73977edaa 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -294,7 +294,7 @@ def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: # in case of "--editable" installs we need to go one dir up config_path = os.path.join("..", "..", "config") - with initialize(config_path=config_path, strict=True): + with initialize(config_path=config_path): composed_cfg = compose("config", overrides=overrides, strict=False) for k in deletes: composed_cfg[k] = None @@ -362,12 +362,20 @@ def populate_dataclass( def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): # this will be deprecated when we get rid of argparse and model_overrides logic + from fairseq.registry import REGISTRIES + with open_dict(cfg): for k in cfg.keys(): - if isinstance(cfg[k], DictConfig): + # "k in cfg" will return false if its a "mandatory value (e.g. ???)" + if k in cfg and isinstance(cfg[k], DictConfig): overwrite_args_by_name(cfg[k], overrides) elif k in overrides: - cfg[k] = overrides[k] + if k in REGISTRIES and overrides[k] in REGISTRIES[k]["dataclass_registry"]: + cfg[k] = DictConfig(REGISTRIES[k]["dataclass_registry"][overrides[k]]) + overwrite_args_by_name(cfg[k], overrides) + cfg[k]._name = overrides[k] + else: + cfg[k] = overrides[k] def merge_with_parent(dc: FairseqDataclass, cfg: DictConfig): diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 1cbc6374fb..14fa8ea5ed 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -328,7 +328,7 @@ def __init__(self, args, tgt_dict=None): state = checkpoint_utils.load_checkpoint_to_cpu( args.w2v_path, arg_overrides ) - w2v_args = state.get("args", None) or state["cfg"].model + args.w2v_args = w2v_args = state.get("args", None) or state["cfg"].model else: state = None w2v_args = args.w2v_args diff --git a/fairseq_cli/score.py b/fairseq_cli/score.py index e06d67259d..0b207be959 100644 --- a/fairseq_cli/score.py +++ b/fairseq_cli/score.py @@ -58,7 +58,7 @@ def readlines(fd): def score(fdsys): with open(args.ref) as fdref: - print(sacrebleu.corpus_bleu(fdsys, [fdref])) + print(sacrebleu.corpus_bleu(fdsys, [fdref]).format()) elif args.sentence_bleu: From b7a2e00958f647497d2980fd7980ae9fcd8a513e Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 6 Nov 2020 15:37:42 -0800 Subject: [PATCH 030/774] Avoid some device-to-host transfers (#1400) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1400 Reviewed By: msbaines Differential Revision: D24765749 Pulled By: myleott fbshipit-source-id: c242f59c88b0d8cb691948f0495af40ba415faff --- fairseq/optim/fp16_optimizer.py | 22 ++++++++++++++++++++-- fairseq/trainer.py | 4 +++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index 7fe3bdd5e5..4457023527 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -162,7 +162,16 @@ def _sync_fp32_params_to_fp16(self): def _unscale_grads(self): self._sync_fp16_grads_to_fp32() - if self._multiply_factor != 1.0: + if ( + # Skip the multiplication if it's a no-op (i.e., if _multiply_factor + # is 1.0). At the same time, we want to avoid the device-to-host + # transfer by comparing it to 1.0. Since _multiply_factor starts as + # a Python float, we roughly assume that if it's a tensor then it's + # probably not =1.0 anymore and we do the multiplication. Otherwise + # we can safely check the value without a D2H transfer. + torch.is_tensor(self._multiply_factor) + or self._multiply_factor != 1.0 + ): self.fp32_optimizer.multiply_grads(self._multiply_factor) self._multiply_factor = 1.0 @@ -370,7 +379,16 @@ def backward(self, loss): loss.backward() def _unscale_grads(self): - if self._multiply_factor != 1.0: + if ( + # Skip the multiplication if it's a no-op (i.e., if _multiply_factor + # is 1.0). At the same time, we want to avoid the device-to-host + # transfer by comparing it to 1.0. Since _multiply_factor starts as + # a Python float, we roughly assume that if it's a tensor then it's + # probably not =1.0 anymore and we do the multiplication. Otherwise + # we can safely check the value without a D2H transfer. + torch.is_tensor(self._multiply_factor) + or self._multiply_factor != 1.0 + ): self.wrapped_optimizer.multiply_grads(self._multiply_factor) self._multiply_factor = 1.0 diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 33207a4cc0..19ca213d55 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -1101,7 +1101,9 @@ def is_consistent(tensor): ) def _reduce_and_log_stats(self, logging_outputs, sample_size, grad_norm=None): - if grad_norm is not None: + if grad_norm is not None and ( + not torch.is_tensor(grad_norm) or torch.isfinite(grad_norm) + ): metrics.log_speed("ups", 1.0, priority=100, round=2) metrics.log_scalar("gnorm", grad_norm, priority=400, round=3) if self.cfg.optimization.clip_norm > 0: From 09a5d864fc5a79a0ec6fdf09fa0825f197060683 Mon Sep 17 00:00:00 2001 From: alexeib Date: Fri, 6 Nov 2020 22:51:29 -0800 Subject: [PATCH 031/774] move configs into fairseq dir (#1403) Summary: this way they get shipped together with fairseq package Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1403 Reviewed By: myleott Differential Revision: D24803076 Pulled By: alexeib fbshipit-source-id: a9aa6e47a8ef26fae4d54691f1616a721b8f6112 --- {config => fairseq/config}/config.yaml | 0 .../model/transformer_lm/transformer_lm_baevski_gbw.yaml | 0 .../transformer_lm/transformer_lm_baevski_wiki103.yaml | 0 .../config}/model/transformer_lm/transformer_lm_big.yaml | 0 .../config}/model/transformer_lm/transformer_lm_gbw.yaml | 0 .../config}/model/transformer_lm/transformer_lm_gpt.yaml | 0 .../model/transformer_lm/transformer_lm_gpt2_big.yaml | 0 .../model/transformer_lm/transformer_lm_gpt2_medium.yaml | 0 .../model/transformer_lm/transformer_lm_gpt2_small.yaml | 0 .../model/transformer_lm/transformer_lm_wiki103.yaml | 0 fairseq/dataclass/utils.py | 3 --- fairseq_cli/hydra_train.py | 3 ++- setup.py | 6 ++---- 13 files changed, 4 insertions(+), 8 deletions(-) rename {config => fairseq/config}/config.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_baevski_gbw.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_baevski_wiki103.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_big.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_gbw.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_gpt.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_gpt2_big.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_gpt2_medium.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_gpt2_small.yaml (100%) rename {config => fairseq/config}/model/transformer_lm/transformer_lm_wiki103.yaml (100%) diff --git a/config/config.yaml b/fairseq/config/config.yaml similarity index 100% rename from config/config.yaml rename to fairseq/config/config.yaml diff --git a/config/model/transformer_lm/transformer_lm_baevski_gbw.yaml b/fairseq/config/model/transformer_lm/transformer_lm_baevski_gbw.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_baevski_gbw.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_baevski_gbw.yaml diff --git a/config/model/transformer_lm/transformer_lm_baevski_wiki103.yaml b/fairseq/config/model/transformer_lm/transformer_lm_baevski_wiki103.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_baevski_wiki103.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_baevski_wiki103.yaml diff --git a/config/model/transformer_lm/transformer_lm_big.yaml b/fairseq/config/model/transformer_lm/transformer_lm_big.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_big.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_big.yaml diff --git a/config/model/transformer_lm/transformer_lm_gbw.yaml b/fairseq/config/model/transformer_lm/transformer_lm_gbw.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_gbw.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_gbw.yaml diff --git a/config/model/transformer_lm/transformer_lm_gpt.yaml b/fairseq/config/model/transformer_lm/transformer_lm_gpt.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_gpt.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_gpt.yaml diff --git a/config/model/transformer_lm/transformer_lm_gpt2_big.yaml b/fairseq/config/model/transformer_lm/transformer_lm_gpt2_big.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_gpt2_big.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_gpt2_big.yaml diff --git a/config/model/transformer_lm/transformer_lm_gpt2_medium.yaml b/fairseq/config/model/transformer_lm/transformer_lm_gpt2_medium.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_gpt2_medium.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_gpt2_medium.yaml diff --git a/config/model/transformer_lm/transformer_lm_gpt2_small.yaml b/fairseq/config/model/transformer_lm/transformer_lm_gpt2_small.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_gpt2_small.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_gpt2_small.yaml diff --git a/config/model/transformer_lm/transformer_lm_wiki103.yaml b/fairseq/config/model/transformer_lm/transformer_lm_wiki103.yaml similarity index 100% rename from config/model/transformer_lm/transformer_lm_wiki103.yaml rename to fairseq/config/model/transformer_lm/transformer_lm_wiki103.yaml diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index d73977edaa..1efcc5dca9 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -290,9 +290,6 @@ def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: # configs will be in fairseq/config after installation config_path = os.path.join("..", "config") - if not os.path.exists(config_path): - # in case of "--editable" installs we need to go one dir up - config_path = os.path.join("..", "..", "config") with initialize(config_path=config_path): composed_cfg = compose("config", overrides=overrides, strict=False) diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index 24728c507f..ffd3c5cd07 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -6,6 +6,7 @@ import hydra from omegaconf import OmegaConf +import os from fairseq.dataclass.initialize import hydra_init from fairseq_cli.train import main as pre_main @@ -19,7 +20,7 @@ logger = logging.getLogger(__name__) -@hydra.main(config_path="../config", config_name="config") +@hydra.main(config_path=os.path.join("..", "fairseq", "config"), config_name="config") def hydra_main(cfg: FairseqConfig) -> None: cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) diff --git a/setup.py b/setup.py index 7b13f13e4c..572d2b50de 100644 --- a/setup.py +++ b/setup.py @@ -222,15 +222,13 @@ def get_files(path, relative_to="fairseq"): try: - # symlink config and examples into fairseq package so package_data accepts them + # symlink examples into fairseq package so package_data accepts them if "build_ext" not in sys.argv[1:]: - os.symlink(os.path.join("..", "config"), "fairseq/config") os.symlink(os.path.join("..", "examples"), "fairseq/examples") package_data = { - "fairseq": get_files("fairseq/config") + get_files("fairseq/examples"), + "fairseq": get_files("fairseq/examples"), } do_setup(package_data) finally: if "build_ext" not in sys.argv[1:]: - os.unlink("fairseq/config") os.unlink("fairseq/examples") From 50422496ac7c3ef2e7dd3818a5126ab9ab37ae29 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sat, 7 Nov 2020 15:00:00 -0800 Subject: [PATCH 032/774] Automatically register components in ConfigStore via register_* functions (#1406) Summary: We can automatically register everything in ConfigStore on-the-fly. This avoids needing to worry about importing everything in the right order. It also better supports `--user-dir`, since those typically get imported later. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1406 Reviewed By: alexeib Differential Revision: D24814072 Pulled By: myleott fbshipit-source-id: 21cfc1a6c497fe98bf4429bfed138030d9999b6a --- fairseq/dataclass/initialize.py | 28 ---------------------------- fairseq/models/__init__.py | 6 ++++++ fairseq/optim/__init__.py | 4 +--- fairseq/registry.py | 10 +++++++++- fairseq/tasks/__init__.py | 6 ++++++ 5 files changed, 22 insertions(+), 32 deletions(-) diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index 24fedd52bf..7a1ebeff1c 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -9,32 +9,10 @@ from hydra.core.config_store import ConfigStore from fairseq.dataclass.configs import FairseqConfig -# the imports below are necessary so that "REGISTRIES" is correctly populated with all components -from fairseq.criterions import CRITERION_REGISTRY # noqa -from fairseq.optim import OPTIMIZER_REGISTRY # noqa -from fairseq.optim.lr_scheduler import LR_SCHEDULER_REGISTRY # noqa -from fairseq.scoring import SCORER_REGISTRY # noqa -from fairseq.data.encoders import BPE_REGISTRY, TOKENIZER_REGISTRY # noqa - -from fairseq.models import MODEL_DATACLASS_REGISTRY -from fairseq.tasks import TASK_DATACLASS_REGISTRY -from fairseq.registry import REGISTRIES - logger = logging.getLogger(__name__) -def register_module_dataclass( - cs: ConfigStore, registry: Dict[str, Any], group: str -) -> None: - """register dataclasses defined in modules in config store, for example, in migrated tasks, models, etc.""" - # note that if `group == model`, we register all model archs, not the model name. - for k, v in registry.items(): - node_ = v() - node_._name = k - cs.store(name=k, group=group, node=node_, provider="fairseq") - - def hydra_init(cfg_name="config") -> None: cs = ConfigStore.instance() @@ -47,9 +25,3 @@ def hydra_init(cfg_name="config") -> None: except BaseException: logger.error(f"{k} - {v}") raise - - register_module_dataclass(cs, TASK_DATACLASS_REGISTRY, "task") - register_module_dataclass(cs, MODEL_DATACLASS_REGISTRY, "model") - - for k, v in REGISTRIES.items(): - register_module_dataclass(cs, v["dataclass_registry"], k) diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index e8af024795..5336b0a052 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -11,6 +11,7 @@ import fairseq from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import merge_with_parent +from hydra.core.config_store import ConfigStore from omegaconf import DictConfig, OmegaConf from .composite_encoder import CompositeEncoder @@ -120,6 +121,11 @@ def register_model_cls(cls): cls.__dataclass = dataclass if dataclass is not None: MODEL_DATACLASS_REGISTRY[name] = dataclass + + cs = ConfigStore.instance() + node = dataclass() + node._name = name + cs.store(name=name, group="model", node=node, provider="fairseq") return cls return register_model_cls diff --git a/fairseq/optim/__init__.py b/fairseq/optim/__init__.py index d8e581729e..112c8ad10f 100644 --- a/fairseq/optim/__init__.py +++ b/fairseq/optim/__init__.py @@ -32,9 +32,7 @@ ) = registry.setup_registry("--optimizer", base_class=FairseqOptimizer, required=True) -def build_optimizer( - cfg: DictConfig, params, *extra_args, **extra_kwargs -): +def build_optimizer(cfg: DictConfig, params, *extra_args, **extra_kwargs): if all(isinstance(p, dict) for p in params): params = [t for p in params for t in p.values()] params = list(filter(lambda p: p.requires_grad, params)) diff --git a/fairseq/registry.py b/fairseq/registry.py index 29631bb326..7a3dd1d1bf 100644 --- a/fairseq/registry.py +++ b/fairseq/registry.py @@ -8,6 +8,7 @@ from typing import Union from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import populate_dataclass, merge_with_parent +from hydra.core.config_store import ConfigStore from omegaconf import DictConfig REGISTRIES = {} @@ -82,9 +83,16 @@ def register_x_cls(cls): ) cls.__dataclass = dataclass - REGISTRY[name] = cls if cls.__dataclass is not None: DATACLASS_REGISTRY[name] = cls.__dataclass + + cs = ConfigStore.instance() + node = dataclass() + node._name = name + cs.store(name=name, group=registry_name, node=node, provider="fairseq") + + REGISTRY[name] = cls + return cls return register_x_cls diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 7575ba429e..415f15e708 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -10,6 +10,7 @@ from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import merge_with_parent +from hydra.core.config_store import ConfigStore from omegaconf import DictConfig from .fairseq_task import FairseqTask, LegacyFairseqTask # noqa @@ -86,6 +87,11 @@ def register_task_cls(cls): if dataclass is not None: TASK_DATACLASS_REGISTRY[name] = dataclass + cs = ConfigStore.instance() + node = dataclass() + node._name = name + cs.store(name=name, group="task", node=node, provider="fairseq") + return cls return register_task_cls From bd2e804b9c2ff1fae202c00e227f1afece12420b Mon Sep 17 00:00:00 2001 From: alexeib Date: Sat, 7 Nov 2020 16:50:15 -0800 Subject: [PATCH 033/774] add and link hydra docs (#1405) Summary: updates hydra integration doc and links to it Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1405 Reviewed By: myleott Differential Revision: D24808779 Pulled By: alexeib fbshipit-source-id: a50160e196e469e30e39d6ee47440a569c0154bd --- README.md | 209 +++++++++-------- docs/hydra_integration.md | 285 ++++++++++++++++------- fairseq/data/encoders/moses_tokenizer.py | 2 +- 3 files changed, 318 insertions(+), 178 deletions(-) diff --git a/README.md b/README.md index 13b8223959..0648da15f7 100644 --- a/README.md +++ b/README.md @@ -13,100 +13,107 @@ Fairseq(-py) is a sequence modeling toolkit that allows researchers and developers to train custom models for translation, summarization, language modeling and other text generation tasks. + We provide reference implementations of various sequence modeling papers:
List of implemented papers

-- **Convolutional Neural Networks (CNN)** - - [Language Modeling with Gated Convolutional Networks (Dauphin et al., 2017)](examples/language_model/conv_lm/README.md) - - [Convolutional Sequence to Sequence Learning (Gehring et al., 2017)](examples/conv_seq2seq/README.md) - - [Classical Structured Prediction Losses for Sequence to Sequence Learning (Edunov et al., 2018)](https://github.com/pytorch/fairseq/tree/classic_seqlevel) - - [Hierarchical Neural Story Generation (Fan et al., 2018)](examples/stories/README.md) - - [wav2vec: Unsupervised Pre-training for Speech Recognition (Schneider et al., 2019)](examples/wav2vec/README.md) -- **LightConv and DynamicConv models** - - [Pay Less Attention with Lightweight and Dynamic Convolutions (Wu et al., 2019)](examples/pay_less_attention_paper/README.md) -- **Long Short-Term Memory (LSTM) networks** - - Effective Approaches to Attention-based Neural Machine Translation (Luong et al., 2015) -- **Transformer (self-attention) networks** - - Attention Is All You Need (Vaswani et al., 2017) - - [Scaling Neural Machine Translation (Ott et al., 2018)](examples/scaling_nmt/README.md) - - [Understanding Back-Translation at Scale (Edunov et al., 2018)](examples/backtranslation/README.md) - - [Adaptive Input Representations for Neural Language Modeling (Baevski and Auli, 2018)](examples/language_model/README.adaptive_inputs.md) - - [Lexically constrained decoding with dynamic beam allocation (Post & Vilar, 2018)](examples/constrained_decoding/README.md) - - [Mixture Models for Diverse Machine Translation: Tricks of the Trade (Shen et al., 2019)](examples/translation_moe/README.md) - - [RoBERTa: A Robustly Optimized BERT Pretraining Approach (Liu et al., 2019)](examples/roberta/README.md) - - [Facebook FAIR's WMT19 News Translation Task Submission (Ng et al., 2019)](examples/wmt19/README.md) - - [Jointly Learning to Align and Translate with Transformer Models (Garg et al., 2019)](examples/joint_alignment_translation/README.md ) - - [Multilingual Denoising Pre-training for Neural Machine Translation (Liu et at., 2020)](examples/mbart/README.md) - - [Neural Machine Translation with Byte-Level Subwords (Wang et al., 2020)](examples/byte_level_bpe/README.md) - - [Unsupervised Quality Estimation for Neural Machine Translation (Fomicheva et al., 2020)](examples/unsupervised_quality_estimation/README.md) - - [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](examples/wav2vec/README.md) - - [Generating Medical Reports from Patient-Doctor Conversations Using Sequence-to-Sequence Models (Enarvi et al., 2020)](examples/pointer_generator/README.md) - - [Linformer: Self-Attention with Linear Complexity (Wang et al., 2020)](examples/linformer/README.md) - - [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) - - [Deep Transformers with Latent Depth (Li et al., 2020)](examples/latent_depth/README.md) -- **Non-autoregressive Transformers** - - Non-Autoregressive Neural Machine Translation (Gu et al., 2017) - - Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement (Lee et al. 2018) - - Insertion Transformer: Flexible Sequence Generation via Insertion Operations (Stern et al. 2019) - - Mask-Predict: Parallel Decoding of Conditional Masked Language Models (Ghazvininejad et al., 2019) - - [Levenshtein Transformer (Gu et al., 2019)](examples/nonautoregressive_translation/README.md) -- **Finetuning** - - [Better Fine-Tuning by Reducing Representational Collapse (Aghajanyan et al. 2020)](examples/rxf/README.md) +* **Convolutional Neural Networks (CNN)** + + [Language Modeling with Gated Convolutional Networks (Dauphin et al., 2017)](examples/language_model/conv_lm/README.md) + + [Convolutional Sequence to Sequence Learning (Gehring et al., 2017)](examples/conv_seq2seq/README.md) + + [Classical Structured Prediction Losses for Sequence to Sequence Learning (Edunov et al., 2018)](https://github.com/pytorch/fairseq/tree/classic_seqlevel) + + [Hierarchical Neural Story Generation (Fan et al., 2018)](examples/stories/README.md) + + [wav2vec: Unsupervised Pre-training for Speech Recognition (Schneider et al., 2019)](examples/wav2vec/README.md) +* **LightConv and DynamicConv models** + + [Pay Less Attention with Lightweight and Dynamic Convolutions (Wu et al., 2019)](examples/pay_less_attention_paper/README.md) +* **Long Short-Term Memory (LSTM) networks** + + Effective Approaches to Attention-based Neural Machine Translation (Luong et al., 2015) +* **Transformer (self-attention) networks** + + Attention Is All You Need (Vaswani et al., 2017) + + [Scaling Neural Machine Translation (Ott et al., 2018)](examples/scaling_nmt/README.md) + + [Understanding Back-Translation at Scale (Edunov et al., 2018)](examples/backtranslation/README.md) + + [Adaptive Input Representations for Neural Language Modeling (Baevski and Auli, 2018)](examples/language_model/README.adaptive_inputs.md) + + [Lexically constrained decoding with dynamic beam allocation (Post & Vilar, 2018)](examples/constrained_decoding/README.md) + + [Mixture Models for Diverse Machine Translation: Tricks of the Trade (Shen et al., 2019)](examples/translation_moe/README.md) + + [RoBERTa: A Robustly Optimized BERT Pretraining Approach (Liu et al., 2019)](examples/roberta/README.md) + + [Facebook FAIR's WMT19 News Translation Task Submission (Ng et al., 2019)](examples/wmt19/README.md) + + [Jointly Learning to Align and Translate with Transformer Models (Garg et al., 2019)](examples/joint_alignment_translation/README.md ) + + [Multilingual Denoising Pre-training for Neural Machine Translation (Liu et at., 2020)](examples/mbart/README.md) + + [Neural Machine Translation with Byte-Level Subwords (Wang et al., 2020)](examples/byte_level_bpe/README.md) + + [Unsupervised Quality Estimation for Neural Machine Translation (Fomicheva et al., 2020)](examples/unsupervised_quality_estimation/README.md) + + [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](examples/wav2vec/README.md) + + [Generating Medical Reports from Patient-Doctor Conversations Using Sequence-to-Sequence Models (Enarvi et al., 2020)](examples/pointer_generator/README.md) + + [Linformer: Self-Attention with Linear Complexity (Wang et al., 2020)](examples/linformer/README.md) + + [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) + + [Deep Transformers with Latent Depth (Li et al., 2020)](examples/latent_depth/README.md) +* **Non-autoregressive Transformers** + + Non-Autoregressive Neural Machine Translation (Gu et al., 2017) + + Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement (Lee et al. 2018) + + Insertion Transformer: Flexible Sequence Generation via Insertion Operations (Stern et al. 2019) + + Mask-Predict: Parallel Decoding of Conditional Masked Language Models (Ghazvininejad et al., 2019) + + [Levenshtein Transformer (Gu et al., 2019)](examples/nonautoregressive_translation/README.md) +* **Finetuning** + + [Better Fine-Tuning by Reducing Representational Collapse (Aghajanyan et al. 2020)](examples/rxf/README.md)

### What's New: -- October 2020: [Added R3F/R4F (Better Fine-Tuning) code](examples/rxf/README.md) -- October 2020: [Deep Transformer with Latent Depth code released](examples/latent_depth/README.md) -- October 2020: [Added CRISS models and code](examples/criss/README.md) -- September 2020: [Added Linformer code](examples/linformer/README.md) -- September 2020: [Added pointer-generator networks](examples/pointer_generator/README.md) -- August 2020: [Added lexically constrained decoding](examples/constrained_decoding/README.md) -- August 2020: [wav2vec2 models and code released](examples/wav2vec/README.md) -- July 2020: [Unsupervised Quality Estimation code released](examples/unsupervised_quality_estimation/README.md) -- May 2020: [Follow fairseq on Twitter](https://twitter.com/fairseq) -- April 2020: [Monotonic Multihead Attention code released](examples/simultaneous_translation/README.md) -- April 2020: [Quant-Noise code released](examples/quant_noise/README.md) -- April 2020: [Initial model parallel support and 11B parameters unidirectional LM released](examples/megatron_11b/README.md) +* November 2020: Adopted [Hydra](https://github.com/facebookresearch/hydra) as a configuration framework; +[added documentation explaining how to use it for new and existing projects](docs/hydra_integration.md) +* October 2020: [Added R3F/R4F (Better Fine-Tuning) code](examples/rxf/README.md) +* October 2020: [Deep Transformer with Latent Depth code released](examples/latent_depth/README.md) +* October 2020: [Added CRISS models and code](examples/criss/README.md) +* September 2020: [Added Linformer code](examples/linformer/README.md) +* September 2020: [Added pointer-generator networks](examples/pointer_generator/README.md) +* August 2020: [Added lexically constrained decoding](examples/constrained_decoding/README.md) +* August 2020: [wav2vec2 models and code released](examples/wav2vec/README.md) +* July 2020: [Unsupervised Quality Estimation code released](examples/unsupervised_quality_estimation/README.md) +* May 2020: [Follow fairseq on Twitter](https://twitter.com/fairseq) +* April 2020: [Monotonic Multihead Attention code released](examples/simultaneous_translation/README.md) +* April 2020: [Quant-Noise code released](examples/quant_noise/README.md) +* April 2020: [Initial model parallel support and 11B parameters unidirectional LM released](examples/megatron_11b/README.md) +
Previous updates

-- March 2020: [Byte-level BPE code released](examples/byte_level_bpe/README.md) -- February 2020: [mBART model and code released](examples/mbart/README.md) -- February 2020: [Added tutorial for back-translation](https://github.com/pytorch/fairseq/tree/master/examples/backtranslation#training-your-own-model-wmt18-english-german) -- December 2019: [fairseq 0.9.0 released](https://github.com/pytorch/fairseq/releases/tag/v0.9.0) -- November 2019: [VizSeq released (a visual analysis toolkit for evaluating fairseq models)](https://facebookresearch.github.io/vizseq/docs/getting_started/fairseq_example) -- November 2019: [CamemBERT model and code released](examples/camembert/README.md) -- November 2019: [BART model and code released](examples/bart/README.md) -- November 2019: [XLM-R models and code released](examples/xlmr/README.md) -- September 2019: [Nonautoregressive translation code released](examples/nonautoregressive_translation/README.md) -- August 2019: [WMT'19 models released](examples/wmt19/README.md) -- July 2019: fairseq relicensed under MIT license -- July 2019: [RoBERTa models and code released](examples/roberta/README.md) -- June 2019: [wav2vec models and code released](examples/wav2vec/README.md) +* March 2020: [Byte-level BPE code released](examples/byte_level_bpe/README.md) +* February 2020: [mBART model and code released](examples/mbart/README.md) +* February 2020: [Added tutorial for back-translation](https://github.com/pytorch/fairseq/tree/master/examples/backtranslation#training-your-own-model-wmt18-english-german) +* December 2019: [fairseq 0.9.0 released](https://github.com/pytorch/fairseq/releases/tag/v0.9.0) +* November 2019: [VizSeq released (a visual analysis toolkit for evaluating fairseq models)](https://facebookresearch.github.io/vizseq/docs/getting_started/fairseq_example) +* November 2019: [CamemBERT model and code released](examples/camembert/README.md) +* November 2019: [BART model and code released](examples/bart/README.md) +* November 2019: [XLM-R models and code released](examples/xlmr/README.md) +* September 2019: [Nonautoregressive translation code released](examples/nonautoregressive_translation/README.md) +* August 2019: [WMT'19 models released](examples/wmt19/README.md) +* July 2019: fairseq relicensed under MIT license +* July 2019: [RoBERTa models and code released](examples/roberta/README.md) +* June 2019: [wav2vec models and code released](examples/wav2vec/README.md)

### Features: -- multi-GPU training on one machine or across multiple machines (data and model parallel) -- fast generation on both CPU and GPU with multiple search algorithms implemented: - - beam search - - Diverse Beam Search ([Vijayakumar et al., 2016](https://arxiv.org/abs/1610.02424)) - - sampling (unconstrained, top-k and top-p/nucleus) - - lexically constrained decoding ([Post & Vilar, 2018](examples/constrained_decoding/README.md)) -- large mini-batch training even on a single GPU via delayed updates -- mixed precision training (trains faster with less GPU memory on [NVIDIA tensor cores](https://developer.nvidia.com/tensor-cores)) -- extensible: easily register new models, criterions, tasks, optimizers and learning rate schedulers +* multi-GPU training on one machine or across multiple machines (data and model parallel) +* fast generation on both CPU and GPU with multiple search algorithms implemented: + + beam search + + Diverse Beam Search ([Vijayakumar et al., 2016](https://arxiv.org/abs/1610.02424)) + + sampling (unconstrained, top-k and top-p/nucleus) + + lexically constrained decoding ([Post & Vilar, 2018](examples/constrained_decoding/README.md)) +* large mini-batch training even on a single GPU via delayed updates +* mixed precision training (trains faster with less GPU memory on [NVIDIA tensor cores](https://developer.nvidia.com/tensor-cores)) +* extensible: easily register new models, criterions, tasks, optimizers and learning rate schedulers +* [flexible configuration](docs/hydra_integration.md) based on [Hydra](https://github.com/facebookresearch/hydra) allowing a combination of code, command-line and file based configuration We also provide [pre-trained models for translation and language modeling](#pre-trained-models-and-examples) with a convenient `torch.hub` interface: -```python + +``` python en2de = torch.hub.load('pytorch/fairseq', 'transformer.wmt19.en-de.single_model') en2de.translate('Hello world', beam=5) # 'Hallo Welt' ``` + See the PyTorch Hub tutorials for [translation](https://pytorch.org/hub/pytorch_fairseq_translation/) and [RoBERTa](https://pytorch.org/hub/pytorch_fairseq_roberta/) for more examples. @@ -116,7 +123,8 @@ and [RoBERTa](https://pytorch.org/hub/pytorch_fairseq_roberta/) for more example * Python version >= 3.6 * For training new models, you'll also need an NVIDIA GPU and [NCCL](https://github.com/NVIDIA/nccl) * **To install fairseq** and develop locally: -```bash + +``` bash git clone https://github.com/pytorch/fairseq cd fairseq pip install --editable ./ @@ -124,18 +132,20 @@ pip install --editable ./ # on MacOS: # CFLAGS="-stdlib=libc++" pip install --editable ./ ``` + * **For faster training** install NVIDIA's [apex](https://github.com/NVIDIA/apex) library: -```bash + +``` bash git clone https://github.com/NVIDIA/apex cd apex pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" \ --global-option="--deprecated_fused_adam" --global-option="--xentropy" \ --global-option="--fast_multihead_attn" ./ ``` -* **For large datasets** install [PyArrow](https://arrow.apache.org/docs/python/install.html#using-pip): `pip install pyarrow` -* If you use Docker make sure to increase the shared memory size either with -`--ipc=host` or `--shm-size` as command line options to `nvidia-docker run`. +* **For large datasets** install [PyArrow](https://arrow.apache.org/docs/python/install.html#using-pip): `pip install pyarrow` +* If you use Docker make sure to increase the shared memory size either with `--ipc=host` or `--shm-size` + as command line options to `nvidia-docker run` . # Getting Started @@ -148,30 +158,31 @@ types and tasks. We provide pre-trained models and pre-processed, binarized test sets for several tasks listed below, as well as example training and evaluation commands. -- [Translation](examples/translation/README.md): convolutional and transformer models are available -- [Language Modeling](examples/language_model/README.md): convolutional and transformer models are available +* [Translation](examples/translation/README.md): convolutional and transformer models are available +* [Language Modeling](examples/language_model/README.md): convolutional and transformer models are available We also have more detailed READMEs to reproduce results from specific papers: -- [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) -- [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](examples/wav2vec/README.md) -- [Unsupervised Quality Estimation for Neural Machine Translation (Fomicheva et al., 2020)](examples/unsupervised_quality_estimation/README.md) -- [Training with Quantization Noise for Extreme Model Compression ({Fan*, Stock*} et al., 2020)](examples/quant_noise/README.md) -- [Neural Machine Translation with Byte-Level Subwords (Wang et al., 2020)](examples/byte_level_bpe/README.md) -- [Multilingual Denoising Pre-training for Neural Machine Translation (Liu et at., 2020)](examples/mbart/README.md) -- [Reducing Transformer Depth on Demand with Structured Dropout (Fan et al., 2019)](examples/layerdrop/README.md) -- [Jointly Learning to Align and Translate with Transformer Models (Garg et al., 2019)](examples/joint_alignment_translation/README.md) -- [Levenshtein Transformer (Gu et al., 2019)](examples/nonautoregressive_translation/README.md) -- [Facebook FAIR's WMT19 News Translation Task Submission (Ng et al., 2019)](examples/wmt19/README.md) -- [RoBERTa: A Robustly Optimized BERT Pretraining Approach (Liu et al., 2019)](examples/roberta/README.md) -- [wav2vec: Unsupervised Pre-training for Speech Recognition (Schneider et al., 2019)](examples/wav2vec/README.md) -- [Mixture Models for Diverse Machine Translation: Tricks of the Trade (Shen et al., 2019)](examples/translation_moe/README.md) -- [Pay Less Attention with Lightweight and Dynamic Convolutions (Wu et al., 2019)](examples/pay_less_attention_paper/README.md) -- [Understanding Back-Translation at Scale (Edunov et al., 2018)](examples/backtranslation/README.md) -- [Classical Structured Prediction Losses for Sequence to Sequence Learning (Edunov et al., 2018)](https://github.com/pytorch/fairseq/tree/classic_seqlevel) -- [Hierarchical Neural Story Generation (Fan et al., 2018)](examples/stories/README.md) -- [Scaling Neural Machine Translation (Ott et al., 2018)](examples/scaling_nmt/README.md) -- [Convolutional Sequence to Sequence Learning (Gehring et al., 2017)](examples/conv_seq2seq/README.md) -- [Language Modeling with Gated Convolutional Networks (Dauphin et al., 2017)](examples/language_model/README.conv.md) + +* [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) +* [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](examples/wav2vec/README.md) +* [Unsupervised Quality Estimation for Neural Machine Translation (Fomicheva et al., 2020)](examples/unsupervised_quality_estimation/README.md) +* [Training with Quantization Noise for Extreme Model Compression ({Fan*, Stock*} et al., 2020)](examples/quant_noise/README.md) +* [Neural Machine Translation with Byte-Level Subwords (Wang et al., 2020)](examples/byte_level_bpe/README.md) +* [Multilingual Denoising Pre-training for Neural Machine Translation (Liu et at., 2020)](examples/mbart/README.md) +* [Reducing Transformer Depth on Demand with Structured Dropout (Fan et al., 2019)](examples/layerdrop/README.md) +* [Jointly Learning to Align and Translate with Transformer Models (Garg et al., 2019)](examples/joint_alignment_translation/README.md) +* [Levenshtein Transformer (Gu et al., 2019)](examples/nonautoregressive_translation/README.md) +* [Facebook FAIR's WMT19 News Translation Task Submission (Ng et al., 2019)](examples/wmt19/README.md) +* [RoBERTa: A Robustly Optimized BERT Pretraining Approach (Liu et al., 2019)](examples/roberta/README.md) +* [wav2vec: Unsupervised Pre-training for Speech Recognition (Schneider et al., 2019)](examples/wav2vec/README.md) +* [Mixture Models for Diverse Machine Translation: Tricks of the Trade (Shen et al., 2019)](examples/translation_moe/README.md) +* [Pay Less Attention with Lightweight and Dynamic Convolutions (Wu et al., 2019)](examples/pay_less_attention_paper/README.md) +* [Understanding Back-Translation at Scale (Edunov et al., 2018)](examples/backtranslation/README.md) +* [Classical Structured Prediction Losses for Sequence to Sequence Learning (Edunov et al., 2018)](https://github.com/pytorch/fairseq/tree/classic_seqlevel) +* [Hierarchical Neural Story Generation (Fan et al., 2018)](examples/stories/README.md) +* [Scaling Neural Machine Translation (Ott et al., 2018)](examples/scaling_nmt/README.md) +* [Convolutional Sequence to Sequence Learning (Gehring et al., 2017)](examples/conv_seq2seq/README.md) +* [Language Modeling with Gated Convolutional Networks (Dauphin et al., 2017)](examples/language_model/README.conv.md) # Join the fairseq community @@ -188,7 +199,7 @@ The license applies to the pre-trained models as well. Please cite as: -```bibtex +``` bibtex @inproceedings{ott2019fairseq, title = {fairseq: A Fast, Extensible Toolkit for Sequence Modeling}, author = {Myle Ott and Sergey Edunov and Alexei Baevski and Angela Fan and Sam Gross and Nathan Ng and David Grangier and Michael Auli}, diff --git a/docs/hydra_integration.md b/docs/hydra_integration.md index 0973cd279e..f924de961b 100644 --- a/docs/hydra_integration.md +++ b/docs/hydra_integration.md @@ -1,111 +1,240 @@ +## Hydra +[Hydra](https://github.com/facebookresearch/hydra) is an open-source Python framework that simplifies the development of +research and other complex applications. The key feature is the ability to dynamically create a hierarchical +configuration by composition and override it through config files and the command line. The name Hydra comes from its +ability to run multiple similar jobs - much like a Hydra with multiple heads. + +## Motivation + +Until recently, all components in fairseq were configured through a shared "args" namespace that was created at +application startup. Components declared their own "add_args" method to update the argparse parser, hoping that +the names would not clash with arguments from other components. While this model works for smaller applications, +as fairseq grew and became integrated into other applications, this became problematic. +In order to determine how to configure each component, one needed to a) examine what args were added by this component, and +b) read the code to figure out what shared arguments it is using that were added in other places. Reproducing +models involved sharing commands that often contained dozens of command line switches. + +The model described above is still supported by fairseq for backward compatibility, but will be deprecated some time +in the future. + +New components in fairseq should now create a dataclass that encapsulates all parameters required to configure this +component. The dataclass is registered along with the component, and fairseq takes care of constructing and +providing this configuration object to the component's constructor. Note that sharing parameters can optionally +still work, but one has to explicitly point to the "source of truth" (see inheritance example below). +These changes make components in fairseq +more independent and re-usable by other applications: all that is needed to create a component is to initialize its +dataclass and overwrite some of the defaults. + +While configuring fairseq through command line (using either the legacy argparse based or the new Hydra based entry points) is still +fully supported, you can now take advantage of configuring fairseq completely or piece-by-piece through +hierarchical YAML configuration files. These files can also be shipped as examples that others can use to run +an identically configured job. + +Additionally, Hydra has a rich and growing +[library of plugins](https://github.com/facebookresearch/hydra/tree/master/plugins) that provide functionality such as +hyperparameter sweeping (including using bayesian optimization through the [Ax](https://github.com/facebook/Ax) library), +job launching across various platforms, and more. + +## Creating or migrating components + +In general, each new (or updated) component should provide a companion [dataclass](https://www.python.org/dev/peps/pep-0557/). These dataclass are typically located in the same +file as the component and are passed as arguments to the register_*() functions. Top-level configs that should be +present in every fairseq application are placed in the [global](fairseq/dataclass/configs.py) config file and added +to the FairseqConfig object. + +Each dataclass is a plain-old-data object, similar to a NamedTuple. These classes are decorated with a @dataclass +decorator, and typically inherit from `FairseqDataclass` (which adds some functionality for backward compatibility). +Each field must have a type, and generally has metadata (such as a help string) and a default value. Only primitive types or other config objects are allowed as +data types for each field. + + Example: + + +``` python +from dataclasses import dataclass, field +from fairseq.dataclass import FairseqDataclass + +@dataclass +class InteractiveConfig(FairseqDataclass): + buffer_size: int = field( + default=0, + metadata={ + "help": "read this many sentences into a buffer before processing them" + }, + ) + input: str = field( + default="-", + metadata={"help": "file to read from; use - for stdin"}, + ) +``` -## Hydra +### Inherting values -Hydra is an open-source Python framework that simplifies the development of research and other complex applications. The key feature is the ability to dynamically create a hierarchical configuration by composition and override it through config files and the command line. The name Hydra comes from its ability to run multiple similar jobs - much like a Hydra with multiple heads. +Some components require sharing a value. For example, a learning rate scheduler and an optimizer may both need to +know the initial learning rate value. One can declare a field that, by default, will +inherit its value from another config node in the same hierarchy: -## Train models with hydra interface +``` python +@dataclass +FairseqAdamConfig(FairseqDataclass): + ... + lr: List[float] = II("optimization.lr") + ... +``` -#### Provide parameters in `.yaml` files -For example, if we'd like to train a language model with transformer, we could provide parameters in yaml files. Note that the modules used (task, model, criterion, optimizer, lr scheduler) in training must be migrated with hydra interface already (See session below). +`II("optimization.lr")` is syntactic sugar for `"${optimization.lr}"` , which is the value one can use in a YAML config file or through +command line to achieve the same effect. Note that this assumes that there is an "optimization" config object +in the root config and it has a field called "lr". -- Provide top level choices on which generic parameter file, and which modules to use: `config/config.yaml`, this will look like for example: +### Tasks and Models -``` -defaults: - - task: language_modeling - - model: transformer_lm - - criterion: cross_entropy - - optimizer: adam - - lr_scheduler: inverse_sqrt -``` +Creating Tasks and Models works same as before, except that legacy implementations now inherit from Legacy* base classes, +while new components inherit from FairseqTask and FairseqModel and provide a dataclass to the register_*() functions. -- Provide generic parameters common across different jobs: `config.yaml` -- Provide task parameters: `config/task/language_modeling.yaml` -- Provide model parameters: `config/model/transformer_lm.yaml` -- Provide criterion parameters: `config/criterion/cross_entropy.yaml` -- Provide optimizer parameters: `config/optimizer/adam.yaml` -- Provide lr_scheduler parameters `config/lr_scheduler/inverse_sqrt.yaml` +Task example: -#### Command line overriding -`train_hydra.py` is the main entry point for training with hydra interface. If we specify all parameters we want in `.yaml` files, then we could simply use command: +``` python +@dataclass +class LanguageModelingConfig(FairseqDataclass): + data: Optional[str] = field( + default=None, metadata={"help": "path to data directory"} + ) + ... +@register_task("language_modeling", dataclass=LanguageModelingConfig) +class LanguageModelingTask(LegacyFairseqTask): + ... + @classmethod + def setup_task(cls, cfg: LanguageModelingConfig): + ... ``` -# task.data is requested field marked by `???` in yaml -python fairseq_cli/train_hydra.py \ -task.data=/private/home/abaevski/data/wiki103 \ + +Model example: + +``` python +@dataclass +class TransformerLanguageModelConfig(FairseqDataclass): + activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( + default="relu", metadata={"help": "activation function to use"} + ) + dropout: float = field(default=0.1, metadata={"help": "dropout probability"}) + ... + +@register_model("transformer_lm", dataclass=TransformerLanguageModelConfig) +class TransformerLanguageModel(FairseqLanguageModel): + ... + @classmethod + def build_model(cls, cfg: TransformerLanguageModelConfig, task: FairseqTask): + ... ``` -Alternatively, if we need to override certain params from the command line, we could do so as below (note the structure of where each parameter sits) +### Other components + +Other components work as before, but they now take their configuration dataclass as the only constructor argument: +``` python +@dataclass +class MosesTokenizerConfig(FairseqDataclass): + source_lang: str = field(default="en", metadata={"help": "source language"}) + ... + +@register_tokenizer("moses", dataclass=MosesTokenizerConfig) +class MosesTokenizer(object): + def __init__(self, cfg: MosesTokenizerConfig): + ... ``` -python fairseq_cli/train_hydra.py -task=language_modeling \ -task.data=/private/home/abaevski/data/wiki103 \ -task.tokens_per_sample=512 \ -task.sample_break_mode=none \ -model=transformer_lm \ -model.share_decoder_input_output_embed=true \ -model.dropout=0.1 \ -optimizer=adam \ -optimizer.adam_betas="'(0.9, 0.98)'" \ -optimizer.weight_decay=0.01 \ -lr_scheduler=inverse_sqrt \ -lr_scheduler.warmup_updates=4000 \ -lr_scheduler.warmup_init_lr=1e-07 \ -criterion=cross_entropy \ -common.fp16=true \ -common.log_format=json \ -common.log_interval=1 \ -dataset.max_tokens=1024 \ -dataset.num_workers=4 \ -optimization.update_freq=[16] \ -optimization.max_update=50000 \ -optimization.clip_norm=0.0 \ -optimization.lr=[0.0005] \ -checkpoint.save_dir=/checkpoint/mtian/transformer_wikitext-103-hydra-args-cli \ -checkpoint.save_interval_updates=10 + +Note that if you are adding a new registry for a new set of components, you need to add it to the FairseqConfig object in +fairseq/dataclass/configs.py: + +``` python +@dataclass +class FairseqConfig(object): + ... + my_new_registry: Any = None ``` -## Migrate existing/Creating new modules to hydra interface +## Training with hydra_train.py -In each of the modules we want to migrated/create with hydra interface, fundamentally we need to +To fully take advantage of configuration flexibility offered by Hydra, you may want to train new models using the +hydra_train.py entry point located in the fairseq_cli directory. Legacy CLI tools such as train.py, +will remain supported for the foreseeable future but will be deprecated eventually. -- Provide a dataclass that layouts the parameters used in the module. +On startup, Hydra will create a configuration object that contains a hierarchy of all the necessary dataclasses +populated with their default values in the code. The default values are overwritten by values found in YAML files in +fairseq/config directory (which currently just set default task, optimizer, etc) and then further overwritten by values +provided through command line arguments. -- Modify the builder and/or constructor that previously takes `argparse.Namespace` argument `args`, into taking `omegaconf.DictConfig` config objects. At this moment we allow `Union[omegaconf.DictConfig, argparse.Namespace]` to support compatibility. +Some of the most common use cases are shown below: -- For `add_args()`, we need to extract argument from the dataclass defined in the same file, and append them into `parser`. This is also to support compatibility. This is simply supported with `gen_parser_from_dataclass` API, see examples files below. +### 1. Overwrite default values through command line: -#### Migrated examples: +```shell script +python fairseq_cli/hydra_train.py distributed_training.distributed_world_size=1 dataset.batch_size=2 task.data=data-bin \ +model=transformer_lm/transformer_lm_gpt task=language_modeling optimization.max_update=5000 -- Task: `fairseq/tasks/language_modeling.py` +``` -- Model: `fairseq/models/transformer_lm.py` +Note that along with explicitly providing values for parameters such as dataset.batch_size, this also tells Hydra to overlay configuration found in `fairseq/config/model/transformer_lm/transformer_lm_gpt.yaml` +over the default values in the dataclass. If you want to train a model without specifying a particular architecture +you can simply specify model=transformer_lm. This only works for migrated tasks and models. -- Criterion: `fairseq/criterions/adaptive_loss.py` and `fairseq/criterions/cross_entropy.py` +### 2. Replace bundled configs with an external config: -- Optimizer: `fairseq/optim/adam.py` and `fairseq/optim/nag.py` +```shell script +python fairseq_cli/hydra_train.py --config-path /path/to/external/configs --config-name wiki103 +``` + +where /path/to/external/configs/wiki103.yaml contains: + +``` yaml +# @package _group_ + +model: + _name: transformer_lm +distributed_training: + distributed_world_size: 1 +dataset: + batch_size: 2 +task: + _name: language_modeling + data: /path/to/data + add_bos_token: false + max_target_positions: 1024 +optimization: + max_update: 50000 + lr: [ 0.25 ] +criterion: cross_entropy +optimizer: adam +lr_scheduler: + _name: cosine +``` -- LR scheduler: `fairseq/optim/lr_scheduler/cosine_lr_scheduler.py` and `fairseq/optim/lr_scheduler/inverse_square_root_schedule.py` +Note that here bundled configs from `fairseq/config` directory are not used, however the defaults from each dataclass will still be used (unless overwritten by your external config). +Additionally you can choose to break up your configs by creating a directory structure in the same location as your main config file, with the names of the top-level fields +(such as "model", "dataset", etc), and placing config files with meaningful names that would populate that specific section of your +top-level config file (for example, you might have model/small_transformer_lm.yaml, model/big_transformer_lm.yaml, etc). You can then specify the correct configuration via command line, defaults in the main config, or even launch all of them as a sweep (see Hydra documentation on how to do this). -## Interpolate parameters across different places +### 3. Add an external config directory to Hydra search path: -## Support of legacy interface -If you still like to pass legacy style arguments in command line, `fairseq_cli/train.py` can support this. Internally it coverted `args` into hydra config objects whenever there are migrated modules aligned. +This allows combining default configuration (including using any bundled config files), while specifying your own config files for some parts of the configuration. +```shell script +python fairseq_cli/hydra_train.py distributed_training.distributed_world_size=1 dataset.batch_size=2 \ +task.data=/path/to/data/ model=transformer_lm/2_layers task=language_modeling optimization.max_update=5000 \ +--config-dir /path/to/external/configs + +``` + +where /path/to/external/configs has the following structure: ``` -python fairseq_cli/train.py --task language_modeling \ -/private/home/abaevski/data/wiki103 \ ---save-dir /checkpoint/mtian/transformer_wikitext-103-hydra-args-cli \ ---arch transformer_lm --share-decoder-input-output-embed \ ---dropout 0.1 \ ---optimizer adam --adam-betas '(0.9, 0.98)' --weight-decay 0.01 --clip-norm 0.0 \ ---lr 0.0005 --lr-scheduler inverse_sqrt --warmup-updates 4000 --warmup-init-lr 1e-07 \ ---tokens-per-sample 512 --sample-break-mode none \ ---max-tokens 1024 --update-freq 16 \ ---fp16 \ ---max-update 50000 --log-format json --log-interval 1 --num-workers 4 \ ---save-interval-updates 10 +. ++-- model +| +-- transformer_lm +| | +-- 2_layers.yaml ``` + +and 2_layers.yaml contains a copy of transformer_lm_gpt.yaml but with decoder_layers set to 2. You can add +other configs to configure other components as well. diff --git a/fairseq/data/encoders/moses_tokenizer.py b/fairseq/data/encoders/moses_tokenizer.py index fa004dd4af..e236dad167 100644 --- a/fairseq/data/encoders/moses_tokenizer.py +++ b/fairseq/data/encoders/moses_tokenizer.py @@ -24,7 +24,7 @@ class MosesTokenizerConfig(FairseqDataclass): @register_tokenizer("moses", dataclass=MosesTokenizerConfig) class MosesTokenizer(object): - def __init__(self, cfg): + def __init__(self, cfg: MosesTokenizerConfig): self.cfg = cfg try: From 108f7204f6ccddb676e6d52006da219ce96a02dc Mon Sep 17 00:00:00 2001 From: alexeib Date: Sat, 7 Nov 2020 23:13:14 -0800 Subject: [PATCH 034/774] add local_rank alias (#1408) Summary: Fixes #2859 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1408 Reviewed By: myleott Differential Revision: D24817281 Pulled By: alexeib fbshipit-source-id: 4c1a3c7d6b3b940e1293d316253b57e101f3f862 --- fairseq/dataclass/configs.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index a3c0d06a39..ec921a41d7 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -208,7 +208,10 @@ class DistributedTrainingConfig(FairseqDataclass): ) local_rank: int = field( default=0, - metadata={"help": "which GPU to use (usually configured automatically)"}, + metadata={ + "help": "which GPU to use (usually configured automatically)", + "argparse_alias": "--local_rank", + }, ) distributed_no_spawn: bool = field( default=False, From 18d3b5c8b0d71e0b828b5a0f5c54ee6769583669 Mon Sep 17 00:00:00 2001 From: UriSha Date: Mon, 9 Nov 2020 10:55:29 -0800 Subject: [PATCH 035/774] Update wikitext url (#2871) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Update WikiText-103 url ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2871 Reviewed By: myleott Differential Revision: D24835953 Pulled By: alexeib fbshipit-source-id: 890e911d528c04de0dc056e55866afb46a2bd87f --- examples/language_model/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/language_model/README.md b/examples/language_model/README.md index dc84d8c761..e78ea48e08 100644 --- a/examples/language_model/README.md +++ b/examples/language_model/README.md @@ -5,7 +5,7 @@ Model | Description | Dataset | Download ---|---|---|--- `transformer_lm.gbw.adaptive_huge` | Adaptive Inputs
([Baevski and Auli, 2018](https://arxiv.org/abs/1809.10853))
1026M params | [Google Billion Words](https://github.com/ciprian-chelba/1-billion-word-language-modeling-benchmark) | [download (.tar.bz2)](https://dl.fbaipublicfiles.com/fairseq/models/lm/adaptive_lm_gbw_huge.tar.bz2) -`transformer_lm.wiki103.adaptive` | Adaptive Inputs
([Baevski and Auli, 2018](https://arxiv.org/abs/1809.10853))
247M params | [WikiText-103](https://einstein.ai/research/the-wikitext-long-term-dependency-language-modeling-dataset) | [download (.tar.bz2)](https://dl.fbaipublicfiles.com/fairseq/models/lm/adaptive_lm_wiki103.v2.tar.bz2) +`transformer_lm.wiki103.adaptive` | Adaptive Inputs
([Baevski and Auli, 2018](https://arxiv.org/abs/1809.10853))
247M params | [WikiText-103](https://blog.einstein.ai/the-wikitext-long-term-dependency-language-modeling-dataset) | [download (.tar.bz2)](https://dl.fbaipublicfiles.com/fairseq/models/lm/adaptive_lm_wiki103.v2.tar.bz2) `transformer_lm.wmt19.en` | English LM
([Ng et al., 2019](https://arxiv.org/abs/1907.06616)) | [WMT News Crawl](http://data.statmt.org/news-crawl/) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt19.en.tar.gz) `transformer_lm.wmt19.de` | German LM
([Ng et al., 2019](https://arxiv.org/abs/1907.06616)) | [WMT News Crawl](http://data.statmt.org/news-crawl/) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt19.de.tar.gz) `transformer_lm.wmt19.ru` | Russian LM
([Ng et al., 2019](https://arxiv.org/abs/1907.06616)) | [WMT News Crawl](http://data.statmt.org/news-crawl/) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt19.ru.tar.gz) From d10fabd6971f51f59e3039accc248eae8945d6ff Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 9 Nov 2020 12:25:01 -0800 Subject: [PATCH 036/774] Make it easier to use non-FairseqDatasets (#1411) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1411 Test Plan: Imported from OSS Reviewed By: huihuifan Differential Revision: D24833475 Pulled By: myleott fbshipit-source-id: 5be599bd2b7d820a208321da53d594d5ae67bf2b --- fairseq/data/iterators.py | 18 +++++++++++---- fairseq/models/fairseq_model.py | 2 +- fairseq/models/huggingface/hf_gpt2.py | 33 ++++----------------------- 3 files changed, 19 insertions(+), 34 deletions(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 15796234db..ef41fed739 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -164,7 +164,8 @@ def next_epoch_idx(self): def next_epoch_itr(self, shuffle=True, fix_batches_to_gpus=False): self.epoch = self.next_epoch_idx - self.dataset.set_epoch(self.epoch) + if hasattr(self.dataset, "set_epoch"): + self.dataset.set_epoch(self.epoch) self._current_epoch_iterator = CountingIterator( iterable=ShardedIterator( iterable=self.dataset, @@ -225,7 +226,9 @@ class EpochBatchIterator(EpochBatchIterating): queue. Helps speeding up dataloading. When buffer_size is zero, the default torch.utils.data.DataLoader preloading is used. timeout (int, optional): if positive, the timeout value for collecting a batch - from workers. Should always be non-negative. (default: ``0``) + from workers. Should always be non-negative (default: ``0``). + disable_shuffling (bool, optional): force disable shuffling + (default: ``False``). """ def __init__( @@ -240,6 +243,7 @@ def __init__( epoch=1, buffer_size=0, timeout=0, + disable_shuffling=False, ): assert isinstance(dataset, torch.utils.data.Dataset) self.dataset = dataset @@ -256,9 +260,10 @@ def __init__( # in a shared computing environment. self.buffer_size = min(buffer_size, 20) self.timeout = timeout + self.disable_shuffling = disable_shuffling self.epoch = max(epoch, 1) # we use 1-based indexing for epochs - self.shuffle = True + self.shuffle = not disable_shuffling self._cur_epoch_itr = None self._next_epoch_itr = None self._supports_prefetch = getattr(dataset, "supports_prefetch", False) @@ -279,7 +284,7 @@ def first_batch(self): "a larger dataset." ) - if self.dataset.supports_fetch_outside_dataloader: + if getattr(self.dataset, "supports_fetch_outside_dataloader", True): return self.collate_fn([self.dataset[i] for i in self.frozen_batches[0]]) else: return "DUMMY" @@ -311,8 +316,11 @@ def next_epoch_itr(self, shuffle=True, fix_batches_to_gpus=False): allocated to the same shards across epochs. Requires that :attr:`dataset` supports prefetching (default: False). """ + if self.disable_shuffling: + shuffle = False self.epoch = self.next_epoch_idx - self.dataset.set_epoch(self.epoch) + if hasattr(self.dataset, "set_epoch"): + self.dataset.set_epoch(self.epoch) if self._next_epoch_itr is not None: self._cur_epoch_itr = self._next_epoch_itr self._next_epoch_itr = None diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 0c8d106be5..926d952f77 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -177,7 +177,7 @@ def make_generation_fast_(self, **kwargs): def apply_remove_weight_norm(module): try: nn.utils.remove_weight_norm(module) - except ValueError: # this module didn't have weight norm + except (AttributeError, ValueError): # this module didn't have weight norm return self.apply(apply_remove_weight_norm) diff --git a/fairseq/models/huggingface/hf_gpt2.py b/fairseq/models/huggingface/hf_gpt2.py index a823453794..3a8eb78198 100644 --- a/fairseq/models/huggingface/hf_gpt2.py +++ b/fairseq/models/huggingface/hf_gpt2.py @@ -17,20 +17,6 @@ ) -try: - # Prepend the transformers submodule to the path, so that - # it's prioritized over other installations. This allows - # making local changes in the submodule. - hf_path = os.path.join(os.path.dirname(__file__), "transformers", "src") - sys.path.insert(0, hf_path) - from transformers import GPT2Config, GPT2LMHeadModel - - sys.path.remove(hf_path) - has_hf = True -except ImportError: - has_hf = False - - logger = logging.getLogger(__name__) @@ -41,14 +27,6 @@ class HuggingFaceGPT2LanguageModel(FairseqLanguageModel): def __init__(self, decoder): super().__init__(decoder) - if not has_hf: - raise ImportError( - "\n\nPlease install huggingface/transformers with:" - "\n\n pip install transformers" - "\n\nOr to make local edits, install the submodule:" - "\n\n git submodule update --init " - "fairseq/models/huggingface/transformers" - ) @staticmethod def add_args(parser): @@ -76,17 +54,16 @@ def build_model(cls, args, task): class HuggingFaceGPT2Decoder(FairseqIncrementalDecoder): def __init__(self, args, task): - super().__init__(task.target_dictionary) - - if not has_hf: + try: + from transformers import GPT2Config, GPT2LMHeadModel + except ImportError: raise ImportError( "\n\nPlease install huggingface/transformers with:" "\n\n pip install transformers" - "\n\nOr to make local edits, install the submodule:" - "\n\n git submodule update --init " - "fairseq/models/huggingface/transformers" ) + super().__init__(task.target_dictionary) + config = GPT2Config( vocab_size=len(task.target_dictionary), n_positions=args.max_target_positions + 1, From 5cfc50627788fb517e29ccc14ea8f3f12b8068a6 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 9 Nov 2020 12:25:01 -0800 Subject: [PATCH 037/774] Fix eval_lm.py to use current cfg for task, also fix --model-overrides (#1412) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1412 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D24833478 Pulled By: myleott fbshipit-source-id: 4d0720a875541c016a00b28a4f0a9ad77e77e7a8 --- fairseq_cli/eval_lm.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index 1197d6987b..e8fd98c325 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -14,7 +14,7 @@ from argparse import Namespace import torch -from fairseq import checkpoint_utils, distributed_utils, options, utils +from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils from fairseq.data import LMContextWindowDataset from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar @@ -63,7 +63,7 @@ def __str__(self): ) -def main(cfg: DictConfig, override_args=None, **unused_kwargs): +def main(cfg: DictConfig, **unused_kwargs): if isinstance(cfg, Namespace): cfg = convert_namespace_to_omegaconf(cfg) @@ -75,12 +75,6 @@ def main(cfg: DictConfig, override_args=None, **unused_kwargs): if use_cuda: torch.cuda.set_device(cfg.distributed_training.device_id) - if override_args is not None: - overrides = vars(override_args) - overrides.update(eval(getattr(override_args, "model_overrides", "{}"))) - else: - overrides = None - logger.info(cfg) # Load ensemble @@ -89,12 +83,17 @@ def main(cfg: DictConfig, override_args=None, **unused_kwargs): # reduce tokens per sample by the required context window size cfg.task.tokens_per_sample -= cfg.eval_lm.context_window + # Initialize the task using the current *cfg* + task = tasks.setup_task(cfg.task) + + # Initialize the model (but not the task) using the checkpoint's *cfg* models, model_args, task = checkpoint_utils.load_model_ensemble_and_task( [cfg.common_eval.path], - arg_overrides=overrides, + arg_overrides=eval(cfg.common_eval.model_overrides), suffix=cfg.checkpoint.checkpoint_suffix, strict=(cfg.checkpoint.checkpoint_shard_count == 1), num_shards=cfg.checkpoint.checkpoint_shard_count, + task=task, ) # Load dataset splits @@ -193,7 +192,7 @@ def main(cfg: DictConfig, override_args=None, **unused_kwargs): tgt_len = tokens.numel() pos_scores = hypo["positional_scores"].float() - if cfg.task.add_bos_token: + if getattr(cfg.task, "add_bos_token", False): assert hypo["tokens"][0].item() == task.target_dictionary.bos() tokens = tokens[1:] pos_scores = pos_scores[1:] From c19dfe26160c6cee768b31eb6bb149781d9c6eac Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 9 Nov 2020 12:25:01 -0800 Subject: [PATCH 038/774] Make activation checkpointing interface less restrictive (#1413) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1413 Test Plan: Imported from OSS Reviewed By: ngoyal2707 Differential Revision: D24833476 Pulled By: myleott fbshipit-source-id: 380ea7e05c7b188086b2b10c15120ea6636e0a3e --- fairseq/modules/checkpoint_activations.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index a4341fe742..1f99c24ca1 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -88,7 +88,6 @@ def split_non_tensors( """ if isinstance(mixed, torch.Tensor): return (mixed,), None - assert isinstance(mixed, tuple) tensors = [] packed_non_tensors = {"is_tensor": [], "objects": []} for o in mixed: @@ -151,7 +150,6 @@ def forward(ctx, run_function, parent_ctx_dict, kwarg_keys, *args): if isinstance(outputs, torch.Tensor): return outputs else: - assert isinstance(outputs, tuple) # Autograd Functions don't like non-Tensor outputs. We can split the # non-Tensor and Tensor outputs, returning the former by reference # through *parent_ctx_dict* and returning the latter directly. From 74a59ada8c882b6a43eac190cb0608b3258ce165 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 9 Nov 2020 12:25:01 -0800 Subject: [PATCH 039/774] Upgrade DummyLMTask to Hydra (#1415) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1415 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D24833480 Pulled By: myleott fbshipit-source-id: 007623168467d18166b20ef99f54388eb9d8008a --- fairseq/benchmark/dummy_lm.py | 79 ++++++++++++++++------------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/fairseq/benchmark/dummy_lm.py b/fairseq/benchmark/dummy_lm.py index f3146b3581..d917e28837 100644 --- a/fairseq/benchmark/dummy_lm.py +++ b/fairseq/benchmark/dummy_lm.py @@ -4,82 +4,75 @@ # LICENSE file in the root directory of this source tree. import logging +from dataclasses import dataclass, field +from typing import Optional import numpy as np import torch from fairseq.data import Dictionary, FairseqDataset -from fairseq.tasks import LegacyFairseqTask, register_task +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task +from omegaconf import II logger = logging.getLogger(__name__) -@register_task("dummy_lm") -class DummyLMTask(LegacyFairseqTask): - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - parser.add_argument("--dict-size", default=49996, type=int) - parser.add_argument("--dataset-size", default=100000, type=int) - parser.add_argument( - "--tokens-per-sample", - default=512, - type=int, - help="max number of total tokens over all segments " - "per sample for BERT dataset", - ) - parser.add_argument("--add-bos-token", action="store_true", help="unused") - parser.add_argument( - "--max-target-positions", - default=None, - help="max number of tokens in the target sequence", - ) +@dataclass +class DummyLMConfig(FairseqDataclass): + dict_size: int = 49996 + dataset_size: int = 100000 + tokens_per_sample: int = field( + default=512, metadata={"help": "max sequence length"} + ) + add_bos_token: bool = False + batch_size: Optional[int] = II("dataset.batch_size") + max_tokens: Optional[int] = II("dataset.max_tokens") + max_target_positions: int = II("task.tokens_per_sample") + - def __init__(self, args, dictionary): - super().__init__(args) - self.dictionary = dictionary - self.seed = args.seed +@register_task("dummy_lm", dataclass=DummyLMConfig) +class DummyLMTask(FairseqTask): - dictionary.pad_to_multiple_(8) # often faster if divisible by 8 + def __init__(self, cfg: DummyLMConfig): + super().__init__(cfg) - seq = torch.arange(args.tokens_per_sample + 1) + dictionary.pad() + 1 + # load dictionary + self.dictionary = Dictionary() + for i in range(cfg.dict_size): + self.dictionary.add_symbol("word{}".format(i)) + self.dictionary.pad_to_multiple_(8) # often faster if divisible by 8 + logger.info("dictionary: {} types".format(len(self.dictionary))) + + seq = torch.arange(cfg.tokens_per_sample + 1) + self.dictionary.pad() + 1 self.dummy_src = seq[:-1] self.dummy_tgt = seq[1:] - @classmethod - def setup_task(cls, args, **kwargs): - """Setup the task. """ - dictionary = Dictionary() - for i in range(args.dict_size): - dictionary.add_symbol("word{}".format(i)) - logger.info("dictionary: {} types".format(len(dictionary))) - return cls(args, dictionary) - def load_dataset(self, split, epoch=1, combine=False, **kwargs): """Load a given dataset split. Args: split (str): name of the split (e.g., train, valid, test) """ - if self.args.batch_size is not None: - bsz = self.args.batch_size + if self.cfg.batch_size is not None: + bsz = self.cfg.batch_size else: - bsz = max(1, self.args.max_tokens // self.args.tokens_per_sample) + bsz = max(1, self.cfg.max_tokens // self.cfg.tokens_per_sample) self.datasets[split] = DummyDataset( { "id": 1, "net_input": { "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]), "src_lengths": torch.full( - (bsz,), self.args.tokens_per_sample, dtype=torch.long + (bsz,), self.cfg.tokens_per_sample, dtype=torch.long ), }, "target": torch.stack([self.dummy_tgt for _ in range(bsz)]), "nsentences": bsz, - "ntokens": bsz * self.args.tokens_per_sample, + "ntokens": bsz * self.cfg.tokens_per_sample, }, - num_items=self.args.dataset_size, - item_size=self.args.tokens_per_sample, + num_items=self.cfg.dataset_size, + item_size=self.cfg.tokens_per_sample, ) @property From b418e46c8b4fedeaf80ef41b4235af33d496ddd4 Mon Sep 17 00:00:00 2001 From: alexeib Date: Mon, 9 Nov 2020 15:44:32 -0800 Subject: [PATCH 040/774] migrate audio_pretraining task to hydra (#1407) Summary: see title Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1407 Reviewed By: myleott Differential Revision: D24821909 Pulled By: alexeib fbshipit-source-id: a58afdd17afab00062bef43cadae380998b23f29 --- fairseq/dataclass/utils.py | 12 +- fairseq/models/__init__.py | 2 +- fairseq/models/wav2vec/wav2vec2_asr.py | 22 ++- fairseq/tasks/audio_pretraining.py | 213 ++++++++++++++----------- fairseq/tasks/fairseq_task.py | 7 +- fairseq/tasks/language_modeling.py | 1 - 6 files changed, 151 insertions(+), 106 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 1efcc5dca9..5f4d200dfe 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -50,6 +50,10 @@ def argparse_name(name: str): def interpret_dc_type(field_type): if isinstance(field_type, str): raise RuntimeError("field should be a type") + + if field_type == Any: + return str + typestring = str(field_type) if re.match(r"(typing.|^)Union\[(.*), NoneType\]$", typestring): return field_type.__args__[0] @@ -127,8 +131,13 @@ def get_kwargs_from_dc( for k in dataclass_instance._get_all_attributes(): field_name = argparse_name(dataclass_instance._get_name(k)) + field_type = dataclass_instance._get_type(k) if field_name is None: continue + elif inspect.isclass(field_type) and issubclass(field_type, FairseqDataclass): + gen_parser_from_dataclass(parser, field_type(), delete_default) + continue + kwargs = get_kwargs_from_dc(dataclass_instance, k) field_args = [field_name] @@ -197,13 +206,14 @@ def get_default(f): t_args = v.type.__args__ if len(t_args) == 1: val = list(map(t_args[0], val)) - if val is None: overrides.append("{}.{}=null".format(sub_node, k)) elif val == "": overrides.append("{}.{}=''".format(sub_node, k)) elif isinstance(val, str): overrides.append("{}.{}='{}'".format(sub_node, k, val)) + elif isinstance(val, FairseqDataclass): + overrides += _override_attr(f"{sub_node}.{k}", type(val), args) else: overrides.append("{}.{}={}".format(sub_node, k, val)) return overrides diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 5336b0a052..d76e391499 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -52,7 +52,7 @@ ] -def build_model(cfg: DictConfig, task): +def build_model(cfg: FairseqDataclass, task): model = None model_type = getattr(cfg, "_name", None) or getattr(cfg, "arch", None) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 14fa8ea5ed..f62ec633b4 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from argparse import Namespace import contextlib import copy import math @@ -12,6 +13,7 @@ import torch.nn as nn import torch.nn.functional as F from fairseq import checkpoint_utils, tasks, utils +from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.models import ( BaseFairseqModel, FairseqEncoder, @@ -328,18 +330,24 @@ def __init__(self, args, tgt_dict=None): state = checkpoint_utils.load_checkpoint_to_cpu( args.w2v_path, arg_overrides ) - args.w2v_args = w2v_args = state.get("args", None) or state["cfg"].model + w2v_args = state.get("cfg", None) + if w2v_args is None: + w2v_args = convert_namespace_to_omegaconf(state["args"]) + args.w2v_args = w2v_args else: state = None w2v_args = args.w2v_args + if isinstance(w2v_args, Namespace): + args.w2v_args = w2v_args = convert_namespace_to_omegaconf(w2v_args) assert ( - args.normalize == w2v_args.normalize - ), "Fine-tuning works best when data normalization is the same" + args.normalize == w2v_args.task.normalize + ), "Fine-tuning works best when data normalization is the same. " \ + "Please check that --normalize is set or unset for both" - w2v_args.data = args.data - task = tasks.setup_task(w2v_args) - model = task.build_model(w2v_args) + w2v_args.task.data = args.data + task = tasks.setup_task(w2v_args.task) + model = task.build_model(w2v_args.model) if state is not None and not args.no_pretrained_weights: model.load_state_dict(state["model"], strict=True) @@ -348,7 +356,7 @@ def __init__(self, args, tgt_dict=None): super().__init__(task.source_dictionary) - d = w2v_args.encoder_embed_dim + d = w2v_args.model.encoder_embed_dim self.w2v_model = model diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 90eb7ca2d6..d1b6bf1c14 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -10,10 +10,16 @@ import sys import torch +from dataclasses import dataclass, field +from typing import Optional, Any +from omegaconf import MISSING + from fairseq.data import AddTargetDataset, Dictionary, FileAudioDataset, encoders from fairseq.data.data_utils import post_process +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.configs import GenerationConfig -from . import LegacyFairseqTask, register_task +from . import FairseqTask, register_task from .. import utils from ..logging import metrics @@ -28,87 +34,94 @@ def __call__(self, label): ) -@register_task("audio_pretraining") -class AudioPretrainingTask(LegacyFairseqTask): +@dataclass +class AudioPretrainingConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) + labels: Optional[str] = field( + default=None, + metadata={"help": "extension of the label file to load, used for fine-tuning"}, + ) + sample_rate: int = field( + default=16_000, + metadata={ + "help": "target sample rate. audio files will be up/down sampled to this rate" + }, + ) + normalize: bool = field( + default=False, + metadata={"help": "if set, normalizes input to have 0 mean and unit variance"}, + ) + enable_padding: bool = field( + default=False, metadata={"help": "pad shorter samples instead of cropping"} + ) + max_sample_size: Optional[int] = field( + default=None, metadata={"help": "max sample size to crop to for batching"} + ) + min_sample_size: Optional[int] = field( + default=None, metadata={"help": "min sample size to crop to for batching"} + ) + + # Options for reporting WER metrics during validation. Only applicable to + # Seq2Seq models during fine-tuning + eval_wer: bool = field( + default=False, metadata={"help": "compute WER for Seq2Seq models"} + ) + eval_wer_config: GenerationConfig = field( + default_factory=lambda: GenerationConfig(), + metadata={"help": "beam search config for evaluating wer during training"}, + ) + eval_wer_tokenizer: Any = field( + default="space", + metadata={"help": "tokenizer config for evaluating wer during training"}, + ) + eval_wer_post_process: str = field( + default="letter", + metadata={ + "help": "remove BPE tokens before scoring (can be sentencepiece, letter, and more)" + }, + ) + autoregressive: bool = field( + default=False, + metadata={ + "help": "required for autoregressive decoders (like seq2seq models); " + "adds 'prev_output_tokens' to input and appends eos to target" + }, + ) + + +@register_task("audio_pretraining", dataclass=AudioPretrainingConfig) +class AudioPretrainingTask(FairseqTask): """""" - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - parser.add_argument("data", help="path to data directory") - parser.add_argument( - "--sample-rate", - default=16000, - type=int, - help="target sample rate. audio files will be up/down sampled to this rate", - ) - parser.add_argument( - "--normalize", - action="store_true", - help="if set, normalizes input to have 0 mean and unit variance", - ) - parser.add_argument( - "--max-sample-size", - default=None, - type=int, - help="max sample size to crop to for batching. default = min sample length", - ) - parser.add_argument( - "--min-sample-size", - default=None, - type=int, - help="min sample size to crop to for batching. default = same as --max-sample-size", - ) - - parser.add_argument( - "--enable-padding", - action="store_true", - help="pad shorter samples instead of cropping", - ) - - parser.add_argument( - "--labels", - type=str, - default=None, - help="extension of the label file to load, if any", - ) - - # Options for reporting WER metrics during validation. Only applicable to - # Seq2Seq models during fine-tuning - parser.add_argument( - "--eval-wer", - action="store_true", - help="compute WER for Seq2Seq models", - ) - parser.add_argument( - "--eval-wer-remove-bpe", - default="letter", - help="remove BPE tokens before scoring (can be sentencepiece, letter, and more)", - ) + cfg: AudioPretrainingConfig - def __init__(self, args, source_dictionary=None, target_dictionary=None): - super().__init__(args) + def __init__( + self, + cfg: AudioPretrainingConfig, + source_dictionary=None, + target_dictionary=None, + ): + super().__init__(cfg) self._target_dictionary = target_dictionary self._source_dictionary = source_dictionary - self.is_ctc = args.criterion == "ctc" - if getattr(self.args, "eval_wer", False): - assert args.labels is not None, "eval_wer can only be set during fine-tuning" + if cfg.eval_wer: + assert cfg.labels is not None, "eval_wer can only be set during fine-tuning" @classmethod - def setup_task(cls, args, **kwargs): + def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): """Setup the task (e.g., load dictionaries). Args: - args (omegaconf.DictConfig): parsed command-line arguments + cfg (AudioPretrainingConfig): configuration of this task """ - if args.labels: - dict_path = os.path.join(args.data, f"dict.{args.labels}.txt") + if cfg.labels: + dict_path = os.path.join(cfg.data, f"dict.{cfg.labels}.txt") target_dictionary = Dictionary.load(dict_path) else: target_dictionary = None - return cls(args, target_dictionary=target_dictionary) + return cls(cfg, target_dictionary=target_dictionary) def load_dataset(self, split, **kwargs): """Load a given dataset split. @@ -116,19 +129,19 @@ def load_dataset(self, split, **kwargs): Args: split (str): name of the split (e.g., train, valid, test) """ - manifest = os.path.join(self.args.data, "{}.tsv".format(split)) + manifest = os.path.join(self.cfg.data, "{}.tsv".format(split)) self.datasets[split] = FileAudioDataset( manifest, - sample_rate=self.args.sample_rate, - max_sample_size=self.args.max_sample_size, - min_sample_size=self.args.max_sample_size, - min_length=self.args.min_sample_size, - pad=self.args.labels is not None or self.args.enable_padding, - normalize=self.args.normalize, + sample_rate=self.cfg.sample_rate, + max_sample_size=self.cfg.max_sample_size, + min_sample_size=self.cfg.max_sample_size, + min_length=self.cfg.min_sample_size, + pad=self.cfg.labels is not None or self.cfg.enable_padding, + normalize=self.cfg.normalize, ) - if self.args.labels: - label_path = os.path.join(self.args.data, f"{split}.{self.args.labels}") + if self.cfg.labels: + label_path = os.path.join(self.cfg.data, f"{split}.{self.cfg.labels}") labels = [] with open(label_path, "r") as f: for line in f: @@ -143,7 +156,7 @@ def load_dataset(self, split, **kwargs): eos=self.target_dictionary.eos(), batch_targets=True, process_label=process_label, - add_to_input=not self.is_ctc, + add_to_input=self.cfg.autoregressive, ) @property @@ -173,7 +186,7 @@ def filter_indices_by_size( def valid_step(self, sample, model, criterion): loss, sample_size, logging_output = super().valid_step(sample, model, criterion) - if getattr(self.args, "eval_wer", False) and not self.is_ctc: + if self.cfg.eval_wer and self.cfg.autoregressive: metrics = self._inference_with_wer(self.sequence_generator, sample, model) logging_output["_num_char_errors"] = metrics["num_char_errors"] logging_output["_num_chars"] = metrics["num_chars"] @@ -181,19 +194,23 @@ def valid_step(self, sample, model, criterion): logging_output["_num_words"] = metrics["num_words"] return loss, sample_size, logging_output - def build_model(self, args): - model = super().build_model(args) + def build_model(self, model_cfg: FairseqDataclass): + model = super().build_model(model_cfg) - if getattr(args, 'eval_wer', False) and not self.is_ctc: - self.sequence_generator = self.build_generator([model], args, ) - self.tokenizer = encoders.build_tokenizer(args) + if self.cfg.eval_wer and self.cfg.autoregressive: + self.sequence_generator = self.build_generator( + [model], + self.cfg.eval_wer_config, + ) + if self.cfg.eval_wer_tokenizer: + self.tokenizer = encoders.build_tokenizer(self.cfg.eval_wer_tokenizer) return model def _inference_with_wer(self, generator, sample, model): def decode(toks, escape_unk=True): s = self.target_dictionary.string( toks.int().cpu(), - self.args.eval_wer_remove_bpe, + self.cfg.eval_wer_post_process, escape_unk=escape_unk, extra_symbols_to_ignore={generator.eos}, ) @@ -210,15 +227,15 @@ def decode(toks, escape_unk=True): utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), escape_unk=True, ) - hyp = post_process(hyp, self.args.eval_wer_remove_bpe).strip("_") - ref = post_process(ref, self.args.eval_wer_remove_bpe).strip("_") + hyp = post_process(hyp, self.cfg.eval_wer_post_process).strip("_") + ref = post_process(ref, self.cfg.eval_wer_post_process).strip("_") num_char_errors += editdistance.eval(hyp, ref) num_chars += len(ref) hyp_words = hyp.split("_") ref_words = ref.split("_") num_word_errors += editdistance.eval(hyp_words, ref_words) num_words += len(ref_words) - + return { "num_char_errors": num_char_errors, "num_chars": num_chars, @@ -229,10 +246,14 @@ def decode(toks, escape_unk=True): def reduce_metrics(self, logging_outputs, criterion): super().reduce_metrics(logging_outputs, criterion) - zero = torch.scalar_tensor(0.) - num_char_errors = sum(log.get("_num_char_errors", zero) for log in logging_outputs) + zero = torch.scalar_tensor(0.0) + num_char_errors = sum( + log.get("_num_char_errors", zero) for log in logging_outputs + ) num_chars = sum(log.get("_num_chars", zero) for log in logging_outputs) - num_word_errors = sum(log.get("_num_word_errors", zero) for log in logging_outputs) + num_word_errors = sum( + log.get("_num_word_errors", zero) for log in logging_outputs + ) num_words = sum(log.get("_num_words", zero) for log in logging_outputs) metrics.log_scalar("_num_char_errors", num_char_errors) metrics.log_scalar("_num_chars", num_chars) @@ -241,11 +262,17 @@ def reduce_metrics(self, logging_outputs, criterion): if num_words > 0: metrics.log_derived( "uer", - lambda meters: meters["_num_char_errors"].sum * 100.0 / meters["_num_chars"].sum - if meters["_num_chars"].sum > 0 else float("nan") + lambda meters: meters["_num_char_errors"].sum + * 100.0 + / meters["_num_chars"].sum + if meters["_num_chars"].sum > 0 + else float("nan"), ) metrics.log_derived( "wer", - lambda meters: meters["_num_word_errors"].sum * 100.0 / meters["_num_words"].sum - if meters["_num_words"].sum > 0 else float("nan") + lambda meters: meters["_num_word_errors"].sum + * 100.0 + / meters["_num_words"].sum + if meters["_num_words"].sum > 0 + else float("nan"), ) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 3cdb64cfae..c47f9c4200 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -11,6 +11,7 @@ import torch from fairseq import metrics, search, tokenizer, utils from fairseq.data import Dictionary, FairseqDataset, data_utils, encoders, iterators +from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import gen_parser_from_dataclass from omegaconf import DictConfig @@ -40,7 +41,7 @@ def logging_outputs_can_be_summed(criterion) -> bool: """ return criterion.logging_outputs_can_be_summed() - def __init__(self, cfg: DictConfig, **kwargs): + def __init__(self, cfg: FairseqDataclass, **kwargs): self.cfg = cfg self.datasets = {} self.dataset_to_epoch_iter = {} @@ -255,13 +256,13 @@ def get_batch_iterator( return epoch_iter - def build_model(self, cfg: DictConfig): + def build_model(self, cfg: FairseqDataclass): """ Build the :class:`~fairseq.models.BaseFairseqModel` instance for this task. Args: - cfg (omegaconf.DictConfig): configuration object + cfg (FairseqDataclass): configuration object Returns: a :class:`~fairseq.models.BaseFairseqModel` instance diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index 79c225de6f..e0bf1f9b2b 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -39,7 +39,6 @@ @dataclass class LanguageModelingConfig(FairseqDataclass): - # TODO common var add to parent data: Optional[str] = field( default=None, metadata={"help": "path to data directory"} ) From 4ea1c1eee077cbf85b1110e6f25d691e53270a7b Mon Sep 17 00:00:00 2001 From: alexeib Date: Mon, 9 Nov 2020 15:44:32 -0800 Subject: [PATCH 041/774] migrate wav2vec2 model (#1409) Summary: see title also includes some minor bug fixes Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1409 Reviewed By: myleott Differential Revision: D24822219 Pulled By: alexeib fbshipit-source-id: b18f9a8af42ced37880c23dd6ad1ec4df3dfc040 --- fairseq/checkpoint_utils.py | 2 - fairseq/dataclass/utils.py | 21 +- fairseq/models/__init__.py | 24 +- fairseq/models/transformer_lm.py | 1 - fairseq/models/wav2vec/wav2vec2.py | 629 +++++++++++------------------ 5 files changed, 260 insertions(+), 417 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 25d3e1e705..3038a1ebcc 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -13,7 +13,6 @@ from typing import Optional, Union import torch -from fairseq import utils from fairseq.dataclass.configs import CheckpointConfig, FairseqConfig from fairseq.dataclass.utils import ( convert_namespace_to_omegaconf, @@ -22,7 +21,6 @@ from fairseq.file_io import PathManager from fairseq.models import FairseqDecoder, FairseqEncoder from omegaconf import DictConfig, open_dict -from torch.serialization import default_restore_location logger = logging.getLogger(__name__) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 5f4d200dfe..e817005bf3 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -86,9 +86,10 @@ def get_kwargs_from_dc( kwargs["required"] = True if field_choices is not None: kwargs["choices"] = field_choices - if (isinstance(inter_type, type) and issubclass(inter_type, List)) or ( - "List" in str(inter_type) - ): + if ( + isinstance(inter_type, type) + and (issubclass(inter_type, List) or issubclass(inter_type, Tuple)) + ) or ("List" in str(inter_type) or "Tuple" in str(inter_type)): if "int" in str(inter_type): kwargs["type"] = lambda x: eval_str_list(x, int) elif "float" in str(inter_type): @@ -96,7 +97,9 @@ def get_kwargs_from_dc( elif "str" in str(inter_type): kwargs["type"] = lambda x: eval_str_list(x, str) else: - raise NotImplementedError() + raise NotImplementedError( + "parsing of type " + str(inter_type) + " is not implemented" + ) if field_default is not MISSING: kwargs["default"] = ( ",".join(map(str, field_default)) @@ -216,6 +219,7 @@ def get_default(f): overrides += _override_attr(f"{sub_node}.{k}", type(val), args) else: overrides.append("{}.{}={}".format(sub_node, k, val)) + return overrides @@ -377,8 +381,13 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): if k in cfg and isinstance(cfg[k], DictConfig): overwrite_args_by_name(cfg[k], overrides) elif k in overrides: - if k in REGISTRIES and overrides[k] in REGISTRIES[k]["dataclass_registry"]: - cfg[k] = DictConfig(REGISTRIES[k]["dataclass_registry"][overrides[k]]) + if ( + k in REGISTRIES + and overrides[k] in REGISTRIES[k]["dataclass_registry"] + ): + cfg[k] = DictConfig( + REGISTRIES[k]["dataclass_registry"][overrides[k]] + ) overwrite_args_by_name(cfg[k], overrides) cfg[k]._name = overrides[k] else: diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index d76e391499..b987966749 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -126,6 +126,11 @@ def register_model_cls(cls): node = dataclass() node._name = name cs.store(name=name, group="model", node=node, provider="fairseq") + + @register_model_architecture(name, name) + def noop(_): + pass + return cls return register_model_cls @@ -155,15 +160,6 @@ def lstm_luong_wmt_en_de(cfg): arch_name (str): the name of the model architecture (``--arch``) """ - def arch_override_from_yaml(args, arch): - root_dir = os.path.dirname(os.path.dirname(fairseq.__file__)) - yaml_path = os.path.join(root_dir, "config/model/{}.yaml".format(arch)) - if not os.path.exists(yaml_path): - raise RuntimeError(f"yaml file {yaml_path} does not exist!") - arch_cfg = OmegaConf.load(yaml_path) - for k, v in arch_cfg.items(): - setattr(args, k, getattr(args, k, v)) - def register_model_arch_fn(fn): if model_name not in MODEL_REGISTRY: raise ValueError( @@ -182,15 +178,7 @@ def register_model_arch_fn(fn): ARCH_MODEL_REGISTRY[arch_name] = MODEL_REGISTRY[model_name] ARCH_MODEL_NAME_REGISTRY[arch_name] = model_name ARCH_MODEL_INV_REGISTRY.setdefault(model_name, []).append(arch_name) - if type(fn) is type and issubclass(fn, BaseFairseqModel): - # for model classes migrated with hydra - # in this case, we are using this decorator directly on model class since - # we do not need arch overriding functions. - ARCH_CONFIG_REGISTRY[arch_name] = lambda args: arch_override_from_yaml( - args, arch=arch_name - ) - else: - ARCH_CONFIG_REGISTRY[arch_name] = fn + ARCH_CONFIG_REGISTRY[arch_name] = fn return fn return register_model_arch_fn diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index 9467b25efd..35bfa6eb6f 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -249,7 +249,6 @@ def build_embedding(cls, args, dictionary, embed_dim, path=None): return embed_tokens -@register_model_architecture("transformer_lm", "transformer_lm") def base_lm_architecture(args): # backward compatibility for older model checkpoints if hasattr(args, "no_tie_adaptive_proj"): diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 6a0f787601..6ad59085f0 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -3,8 +3,8 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import logging import math +from dataclasses import dataclass, field from typing import List, Tuple import numpy as np @@ -13,6 +13,7 @@ import torch.nn.functional as F from fairseq import utils from fairseq.data.data_utils import compute_mask_indices +from fairseq.dataclass import ChoiceEnum, FairseqDataclass from fairseq.models import BaseFairseqModel, register_model, register_model_architecture from fairseq.modules import ( Fp32GroupNorm, @@ -28,333 +29,256 @@ from fairseq.utils import buffered_arange -@register_model("wav2vec2") +EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) +MASKING_DISTRIBUTION_CHOICES = ChoiceEnum(["static", "uniform", "normal", "poisson"]) + + +@dataclass +class Wav2Vec2Config(FairseqDataclass): + extractor_mode: EXTRACTOR_MODE_CHOICES = field( + default="default", + metadata={ + "help": "mode for feature extractor. default has a single group norm with d " + "groups in the first conv block, whereas layer_norm has layer norms in " + "every block (meant to use with normalize=True)" + }, + ) + encoder_layers: int = field( + default=12, metadata={"help": "num encoder layers in the transformer"} + ) + encoder_embed_dim: int = field( + default=768, metadata={"help": "encoder embedding dimension"} + ) + encoder_ffn_embed_dim: int = field( + default=3072, metadata={"help": "encoder embedding dimension for FFN"} + ) + encoder_attention_heads: int = field( + default=12, metadata={"help": "num encoder attention heads"} + ) + activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( + default="gelu", metadata={"help": "activation function to use"} + ) + + # dropouts + dropout: float = field( + default=0.1, metadata={"help": "dropout probability for the transformer"} + ) + attention_dropout: float = field( + default=0.1, metadata={"help": "dropout probability for attention weights"} + ) + activation_dropout: float = field( + default=0.0, metadata={"help": "dropout probability after activation in FFN"} + ) + encoder_layerdrop: float = field( + default=0.0, metadata={"help": "probability of dropping a tarnsformer layer"} + ) + dropout_input: float = field( + default=0.0, + metadata={"help": "dropout to apply to the input (after feat extr)"}, + ) + dropout_features: float = field( + default=0.0, + metadata={"help": "dropout to apply to the features (after feat extr)"}, + ) + + final_dim: int = field( + default=0, + metadata={ + "help": "project final representations and targets to this many dimensions." + "set to encoder_embed_dim is <= 0" + }, + ) + layer_norm_first: bool = field( + default=False, metadata={"help": "apply layernorm first in the transformer"} + ) + conv_feature_layers: str = field( + default="[(512, 10, 5), (512, 8, 4)] + [(512, 4, 2)] * 3 + [(512, 1, 1)]", + metadata={ + "help": "string describing convolutional feature extraction layers in form of a python list that contains " + "[(dim, kernel_size, stride), ...]" + }, + ) + conv_bias: bool = field( + default=False, metadata={"help": "include bias in conv encoder"} + ) + logit_temp: float = field( + default=0.1, metadata={"help": "temperature to divide logits by"} + ) + quantize_targets: bool = field( + default=False, metadata={"help": "use quantized targets"} + ) + quantize_input: bool = field( + default=False, metadata={"help": "use quantized inputs"} + ) + same_quantizer: bool = field( + default=False, metadata={"help": "use same quantizer for inputs and targets"} + ) + target_glu: bool = field( + default=False, metadata={"help": "adds projection + glu to targets"} + ) + feature_grad_mult: float = field( + default=1.0, metadata={"help": "multiply feature extractor var grads by this"} + ) + latent_vars: int = field( + default=320, + metadata={"help": "number of latent variables V in each group of the codebook"}, + ) + latent_groups: int = field( + default=2, + metadata={"help": "number of groups G of latent variables in the codebook"}, + ) + latent_dim: int = field( + default=0, + metadata={ + "help": "if > 0, uses this dimensionality for latent variables. " + "otherwise uses final_dim / latent_groups" + }, + ) + + # masking + mask_length: int = field(default=10, metadata={"help": "mask length"}) + mask_prob: float = field( + default=0.65, metadata={"help": "probability of replacing a token with mask"} + ) + mask_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose mask length"} + ) + mask_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument (used for more complex distributions), " + "see help in compute_mask_indicesh" + }, + ) + no_mask_overlap: bool = field( + default=False, metadata={"help": "whether to allow masks to overlap"} + ) + mask_min_space: int = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + + # channel masking + mask_channel_length: int = field( + default=10, metadata={"help": "length of the mask for features (channels)"} + ) + mask_channel_prob: float = field( + default=0.0, metadata={"help": "probability of replacing a feature with 0"} + ) + mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", + metadata={"help": "how to choose mask length for channel masking"}, + ) + mask_channel_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument (used for more complex distributions), " + "see help in compute_mask_indicesh" + }, + ) + no_mask_channel_overlap: bool = field( + default=False, metadata={"help": "whether to allow channel masks to overlap"} + ) + mask_channel_min_space: int = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + + # negative selection + num_negatives: int = field( + default=100, + metadata={"help": "number of negative examples from the same sample"}, + ) + negatives_from_everywhere: bool = field( + default=False, + metadata={"help": "sample negatives from everywhere, not just masked states"}, + ) + cross_sample_negatives: int = field( + default=0, metadata={"help": "number of negative examples from the any sample"} + ) + codebook_negatives: int = field( + default=0, metadata={"help": "number of negative examples codebook"} + ) + + # positional embeddings + conv_pos: int = field( + default=128, + metadata={"help": "number of filters for convolutional positional embeddings"}, + ) + conv_pos_groups: int = field( + default=16, + metadata={"help": "number of groups for convolutional positional embedding"}, + ) + + latent_temp: Tuple[float, float, float] = field( + default=(2, 0.5, 0.999995), + metadata={ + "help": "temperature for latent variable sampling. " + "can be tuple of 3 values (start, end, decay)" + }, + ) + + +@register_model("wav2vec2", dataclass=Wav2Vec2Config) class Wav2Vec2Model(BaseFairseqModel): - @staticmethod - def add_args(parser): - """Add model-specific arguments to the parser.""" - - parser.add_argument( - "--extractor-mode", - choices=["default", "layer_norm"], - help="mode for feature extractor. default has a single group norm with d groups in the first conv block, whereas layer_norm has layer norms in every block (meant to use with --normalize)", - ) - - parser.add_argument( - "--encoder-layers", - type=int, - metavar="L", - help="num encoder layers in the transformer", - ) - parser.add_argument( - "--encoder-embed-dim", - type=int, - metavar="H", - help="encoder embedding dimension", - ) - parser.add_argument( - "--encoder-ffn-embed-dim", - type=int, - metavar="F", - help="encoder embedding dimension for FFN", - ) - parser.add_argument( - "--encoder-attention-heads", - type=int, - metavar="A", - help="num encoder attention heads", - ) - parser.add_argument( - "--activation-fn", - choices=utils.get_available_activation_fns(), - help="activation function to use", - ) - - parser.add_argument( - "--dropout", - type=float, - metavar="D", - help="dropout probability for the transformer", - ) - - parser.add_argument( - "--attention-dropout", - type=float, - metavar="D", - help="dropout probability for attention weights", - ) - - parser.add_argument( - "--activation-dropout", - type=float, - metavar="D", - help="dropout probability after activation in FFN", - ) - - parser.add_argument( - "--final-dim", - type=int, - metavar="D", - help="project final representations and targets to this many dimensions", - ) - - parser.add_argument( - "--layer-norm-first", - action="store_true", - help="apply layernorm first in the transformer", - ) - - parser.add_argument( - "--encoder-layerdrop", - type=float, - help="probability of dropping a tarnsformer layer", - ) - - parser.add_argument( - "--conv-feature-layers", - type=str, - metavar="EXPR", - help="convolutional feature extraction layers [(dim, kernel_size, stride), ...]", - ) - - parser.add_argument( - "--logit-temp", type=float, help="temperature to divide logits by" - ) - - parser.add_argument( - "--quantize-targets", action="store_true", help="use quantized targets" - ) - - parser.add_argument( - "--quantize-input", action="store_true", help="use quantized inputs" - ) - - parser.add_argument( - "--same-quantizer", - action="store_true", - help="use same quantizer for inputs and targets", - ) - - parser.add_argument( - "--feature-grad-mult", - type=float, - help="multiply feature extractor var grads by this", - ) - - parser.add_argument( - "--latent-vars", - type=int, - metavar="N", - help="number of latent variables V in each group of the codebook", - ) - - parser.add_argument( - "--latent-groups", - type=int, - metavar="N", - help="number of groups G of latent variables in the codebook", - ) - - parser.add_argument( - "--latent-dim", - type=int, - metavar="N", - help="if set, uses this dimensionality for latent variables. otherwise uses final_dim / latent_groups", - ) - - parser.add_argument("--mask-length", type=int, help="mask length") - - parser.add_argument( - "--mask-prob", type=float, help="probability of replacing a token with mask" - ) - - parser.add_argument( - "--mask-selection", - type=str, - choices=["static", "uniform", "normal", "poisson"], - help="how to choose masks", - ) - - parser.add_argument( - "--mask-other", - type=float, - help="secondary mask argument (used for more complex distributions), see help in compute_mask_indices", - ) - - parser.add_argument( - "--no-mask-overlap", - action="store_true", - help="whether to allow masks to overlap", - ) - - parser.add_argument( - "--mask-min-space", - type=int, - help="min space between spans (if no overlap is enabled)", - ) - - parser.add_argument( - "--mask-channel-length", - type=int, - help="repeat the mask indices multiple times", - ) - - parser.add_argument( - "--mask-channel-prob", - type=float, - help="probability of replacing a token with mask", - ) - - parser.add_argument( - "--mask-channel-selection", - type=str, - choices=["static", "uniform", "normal", "poisson"], - help="how to choose masks", - ) - - parser.add_argument( - "--mask-channel-other", - type=float, - help="secondary mask argument (used for more complex distributions), see help in compute_mask_indices", - ) - - parser.add_argument( - "--no-mask-channel-overlap", - action="store_true", - help="whether to allow masks to overlap", - ) - - parser.add_argument( - "--mask-channel-min-space", - type=int, - help="min space between spans (if no overlap is enabled)", - ) - - parser.add_argument( - "--dropout-input", - type=float, - metavar="D", - help="dropout to apply to the input (after feat extr)", - ) - - parser.add_argument( - "--dropout-features", - type=float, - metavar="D", - help="dropout to apply to the features (after feat extr)", - ) - - parser.add_argument( - "--num-negatives", type=int, metavar="N", help="number of negative examples" - ) - - parser.add_argument( - "--negatives-from-everywhere", - action="store_true", - help="sample negatives from everywhere, not just masked states", - ) - - parser.add_argument( - "--cross-sample-negatives", - type=int, - metavar="N", - help="num of cross sampled negatives", - ) - - parser.add_argument( - "--codebook-negatives", - type=int, - metavar="N", - help="num of codebook sampled negatives", - ) - - parser.add_argument( - "--conv-pos", - type=int, - metavar="N", - help="number of filters for convolutional positional embeddings", - ) - - parser.add_argument( - "--conv-pos-groups", - type=int, - metavar="N", - help="number of groups for convolutional positional embedding", - ) - - parser.add_argument( - "--latent-temp", - type=str, - metavar="D", - help="temperature for latent variable sampling. can be tuple of 3 values (start, end, decay)", - ) - - parser.add_argument( - "--target-glu", action="store_true", help="adds projection + glu to targets" - ) - - parser.add_argument( - "--conv-bias", action="store_true", help="include bias in conv encoder" - ) - - def __init__(self, args): + def __init__(self, cfg: Wav2Vec2Config): super().__init__() - self.args = args + self.cfg = cfg - feature_enc_layers = eval(args.conv_feature_layers) + feature_enc_layers = eval(cfg.conv_feature_layers) self.embed = feature_enc_layers[-1][0] self.feature_extractor = ConvFeatureExtractionModel( conv_layers=feature_enc_layers, dropout=0.0, - mode=args.extractor_mode, - conv_bias=args.conv_bias, + mode=cfg.extractor_mode, + conv_bias=cfg.conv_bias, ) self.post_extract_proj = ( - nn.Linear(self.embed, args.encoder_embed_dim) - if self.embed != args.encoder_embed_dim and not args.quantize_input + nn.Linear(self.embed, cfg.encoder_embed_dim) + if self.embed != cfg.encoder_embed_dim and not cfg.quantize_input else None ) - self.mask_prob = args.mask_prob - self.mask_selection = args.mask_selection - self.mask_other = args.mask_other - self.mask_length = args.mask_length - self.no_mask_overlap = args.no_mask_overlap - self.mask_min_space = args.mask_min_space + self.mask_prob = cfg.mask_prob + self.mask_selection = cfg.mask_selection + self.mask_other = cfg.mask_other + self.mask_length = cfg.mask_length + self.no_mask_overlap = cfg.no_mask_overlap + self.mask_min_space = cfg.mask_min_space - self.mask_channel_prob = args.mask_channel_prob - self.mask_channel_selection = args.mask_channel_selection - self.mask_channel_other = args.mask_channel_other - self.mask_channel_length = args.mask_channel_length - self.no_mask_channel_overlap = args.no_mask_channel_overlap - self.mask_channel_min_space = args.mask_channel_min_space + self.mask_channel_prob = cfg.mask_channel_prob + self.mask_channel_selection = cfg.mask_channel_selection + self.mask_channel_other = cfg.mask_channel_other + self.mask_channel_length = cfg.mask_channel_length + self.no_mask_channel_overlap = cfg.no_mask_channel_overlap + self.mask_channel_min_space = cfg.mask_channel_min_space - self.dropout_input = nn.Dropout(args.dropout_input) - self.dropout_features = nn.Dropout(args.dropout_features) + self.dropout_input = nn.Dropout(cfg.dropout_input) + self.dropout_features = nn.Dropout(cfg.dropout_features) - self.feature_grad_mult = args.feature_grad_mult + self.feature_grad_mult = cfg.feature_grad_mult self.quantizer = None self.input_quantizer = None - self.n_negatives = args.num_negatives - self.cross_sample_negatives = args.cross_sample_negatives - self.codebook_negatives = args.codebook_negatives - self.negatives_from_everywhere = args.negatives_from_everywhere + self.n_negatives = cfg.num_negatives + self.cross_sample_negatives = cfg.cross_sample_negatives + self.codebook_negatives = cfg.codebook_negatives + self.negatives_from_everywhere = cfg.negatives_from_everywhere - self.logit_temp = args.logit_temp + self.logit_temp = cfg.logit_temp - final_dim = args.final_dim if args.final_dim > 0 else args.encoder_embed_dim + final_dim = cfg.final_dim if cfg.final_dim > 0 else cfg.encoder_embed_dim - if args.quantize_targets: - vq_dim = args.latent_dim if args.latent_dim > 0 else final_dim + if cfg.quantize_targets: + vq_dim = cfg.latent_dim if cfg.latent_dim > 0 else final_dim self.quantizer = GumbelVectorQuantizer( dim=self.embed, - num_vars=args.latent_vars, - temp=eval(args.latent_temp), - groups=args.latent_groups, + num_vars=cfg.latent_vars, + temp=cfg.latent_temp, + groups=cfg.latent_groups, combine_groups=False, vq_dim=vq_dim, time_first=True, @@ -363,39 +287,37 @@ def __init__(self, args): else: self.project_q = nn.Linear(self.embed, final_dim) - if args.quantize_input: - if args.same_quantizer and self.quantizer is not None: + if cfg.quantize_input: + if cfg.same_quantizer and self.quantizer is not None: vq_dim = final_dim self.input_quantizer = self.quantizer else: - vq_dim = ( - args.latent_dim if args.latent_dim > 0 else args.encoder_embed_dim - ) + vq_dim = cfg.latent_dim if cfg.latent_dim > 0 else cfg.encoder_embed_dim self.input_quantizer = GumbelVectorQuantizer( dim=self.embed, - num_vars=args.latent_vars, - temp=eval(args.latent_temp), - groups=args.latent_groups, + num_vars=cfg.latent_vars, + temp=eval(cfg.latent_temp), + groups=cfg.latent_groups, combine_groups=False, vq_dim=vq_dim, time_first=True, ) - self.project_inp = nn.Linear(vq_dim, args.encoder_embed_dim) + self.project_inp = nn.Linear(vq_dim, cfg.encoder_embed_dim) self.mask_emb = nn.Parameter( - torch.FloatTensor(args.encoder_embed_dim).uniform_() + torch.FloatTensor(cfg.encoder_embed_dim).uniform_() ) - self.encoder = TransformerEncoder(args) + self.encoder = TransformerEncoder(cfg) self.layer_norm = LayerNorm(self.embed) self.target_glu = None - if args.target_glu: + if cfg.target_glu: self.target_glu = nn.Sequential( nn.Linear(final_dim, final_dim * 2), nn.GLU() ) - self.final_proj = nn.Linear(args.encoder_embed_dim, final_dim) + self.final_proj = nn.Linear(cfg.encoder_embed_dim, final_dim) def upgrade_state_dict_named(self, state_dict, name): super().upgrade_state_dict_named(state_dict, name) @@ -403,13 +325,10 @@ def upgrade_state_dict_named(self, state_dict, name): return state_dict @classmethod - def build_model(cls, args, task=None): + def build_model(cls, cfg: Wav2Vec2Config, task=None): """Build a new model instance.""" - # make sure all arguments are present - base_architecture(args) - - return cls(args) + return cls(cfg) def apply_mask(self, x, padding_mask): B, T, C = x.shape @@ -957,73 +876,3 @@ def forward( x = self.final_layer_norm(x) return x, attn - - -@register_model_architecture("wav2vec2", "wav2vec2") -def base_architecture(args): - args.extractor_mode = getattr(args, "extractor_mode", "default") - - args.encoder_layers = getattr(args, "encoder_layers", 12) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 3072) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) - - args.activation_fn = getattr(args, "activation_fn", "gelu") - - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_dropout = getattr(args, "activation_dropout", 0.0) - - args.final_dim = getattr(args, "final_dim", 0) - - args.layer_norm_first = getattr(args, "layer_norm_first", False) - args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) - - conv_feature_layers = "[(512, 10, 5)]" - conv_feature_layers += " + [(512, 8, 4)]" - conv_feature_layers += " + [(512, 4, 2)] * 3" - conv_feature_layers += " + [(512, 1, 1)]" - args.conv_feature_layers = getattr(args, "conv_feature_layers", conv_feature_layers) - - args.logit_temp = getattr(args, "logit_temp", 0.1) - - args.quantize_targets = getattr(args, "quantize_targets", False) - args.quantize_input = getattr(args, "quantize_input", False) - args.same_quantizer = getattr(args, "same_quantizer", False) - - args.feature_grad_mult = getattr(args, "feature_grad_mult", 1.0) - - args.latent_vars = getattr(args, "latent_vars", 320) - args.latent_groups = getattr(args, "latent_groups", 2) - args.latent_dim = getattr(args, "latent_dim", 0) - - args.mask_length = getattr(args, "mask_length", 10) - args.mask_prob = getattr(args, "mask_prob", 0.65) - args.mask_selection = getattr(args, "mask_selection", "static") - args.mask_other = getattr(args, "mask_other", 0) - args.no_mask_overlap = getattr(args, "no_mask_overlap", False) - args.mask_min_space = getattr(args, "mask_min_space", 1) - - args.mask_channel_length = getattr(args, "mask_channel_length", 10) - args.mask_channel_prob = getattr(args, "mask_channel_prob", 0) - args.mask_channel_selection = getattr(args, "mask_channel_selection", "static") - args.mask_channel_other = getattr(args, "mask_channel_other", 0) - args.no_mask_channel_overlap = getattr(args, "no_mask_channel_overlap", False) - args.mask_channel_min_space = getattr(args, "mask_channel_min_space", 1) - - args.dropout_input = getattr(args, "dropout_input", 0) - args.dropout_features = getattr(args, "dropout_features", 0) - - args.num_negatives = getattr(args, "num_negatives", 100) - args.negatives_from_everywhere = getattr(args, "negatives_from_everywhere", False) - args.cross_sample_negatives = getattr(args, "cross_sample_negatives", 0) - args.codebook_negatives = getattr(args, "codebook_negatives", 0) - - args.conv_pos = getattr(args, "conv_pos", 128) - args.conv_pos_groups = getattr(args, "conv_pos_groups", 16) - - args.latent_temp = getattr(args, "latent_temp", "(2,0.5,0.999995)") - - args.target_glu = getattr(args, "target_glu", False) - - args.conv_bias = getattr(args, "conv_bias", False) From 6815772651fd639ed16360074aa23e238b29c6ce Mon Sep 17 00:00:00 2001 From: alexeib Date: Mon, 9 Nov 2020 19:21:13 -0800 Subject: [PATCH 042/774] fix wav2vec inference (#1418) Summary: see title Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1418 Reviewed By: michaelauli Differential Revision: D24847525 Pulled By: alexeib fbshipit-source-id: e9f5d562ad2ac2904a65852cb9a05af775bebab0 --- fairseq/dataclass/utils.py | 41 ++++++++++++++++++++---------- fairseq/models/wav2vec/wav2vec2.py | 2 +- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index e817005bf3..d73af240b9 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -5,6 +5,7 @@ import ast import os +import re from argparse import ArgumentError, ArgumentParser, Namespace from dataclasses import _MISSING_TYPE, MISSING from enum import Enum @@ -30,13 +31,25 @@ def eval_str_list(x, x_type=float): return [x_type(x)] +def interpret_dc_type(field_type): + if isinstance(field_type, str): + raise RuntimeError("field should be a type") + + if field_type == Any: + return str + + typestring = str(field_type) + if re.match(r"(typing.|^)Union\[(.*), NoneType\]$", typestring): + return field_type.__args__[0] + return field_type + + def gen_parser_from_dataclass( parser: ArgumentParser, dataclass_instance: FairseqDataclass, delete_default: bool = False, ) -> None: """convert a dataclass instance to tailing parser arguments""" - import re def argparse_name(name: str): if name == "data": @@ -47,18 +60,6 @@ def argparse_name(name: str): return None return "--" + name.replace("_", "-") - def interpret_dc_type(field_type): - if isinstance(field_type, str): - raise RuntimeError("field should be a type") - - if field_type == Any: - return str - - typestring = str(field_type) - if re.match(r"(typing.|^)Union\[(.*), NoneType\]$", typestring): - return field_type.__args__[0] - return field_type - def get_kwargs_from_dc( dataclass_instance: FairseqDataclass, k: str ) -> Dict[str, Any]: @@ -204,11 +205,25 @@ def get_default(f): val = get_default(v) if not hasattr(args, k) else getattr(args, k) + field_type = interpret_dc_type(v.type) + if ( + isinstance(val, str) + and not val.startswith("${") # not interpolation + and field_type != str + and not issubclass(field_type, Enum) # not choices enum + ): + # upgrade old models that stored complex parameters as string + val = ast.literal_eval(val) + + if isinstance(val, tuple): + val = list(val) + if getattr(v.type, "__origin__", None) is List: # if type is int but val is float, then we will crash later - try to convert here t_args = v.type.__args__ if len(t_args) == 1: val = list(map(t_args[0], val)) + if val is None: overrides.append("{}.{}=null".format(sub_node, k)) elif val == "": diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 6ad59085f0..e6fecdd4fe 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -296,7 +296,7 @@ def __init__(self, cfg: Wav2Vec2Config): self.input_quantizer = GumbelVectorQuantizer( dim=self.embed, num_vars=cfg.latent_vars, - temp=eval(cfg.latent_temp), + temp=cfg.latent_temp, groups=cfg.latent_groups, combine_groups=False, vq_dim=vq_dim, From a66cc28b14ca8ff95e3aadfd3ca77bfb5b00c136 Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 11 Nov 2020 10:06:10 -0800 Subject: [PATCH 043/774] fix more bugs incl generating from w2v models (#1419) Summary: fixes several bugs: - populating dataclasses from arg objects - generating from w2v seq2seq models -> fix post processing, and make sure that generate uses the "task" args saved in the model that contain important info about dataset (e.g. whether to normalize it or not) - use task's config object if it exists (so any new fields are picked up) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1419 Reviewed By: myleott Differential Revision: D24853592 Pulled By: alexeib fbshipit-source-id: 463762fa4c0de30e5bcbfca51df84714e4d1f464 --- fairseq/dataclass/utils.py | 12 ++++++++---- fairseq/models/__init__.py | 9 +++++---- fairseq/registry.py | 2 +- fairseq/sequence_generator.py | 2 +- fairseq/tasks/__init__.py | 8 +++++--- fairseq/tasks/audio_pretraining.py | 17 +++++++---------- fairseq_cli/eval_lm.py | 4 ++-- 7 files changed, 29 insertions(+), 25 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index d73af240b9..f8ed8f667f 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -210,7 +210,7 @@ def get_default(f): isinstance(val, str) and not val.startswith("${") # not interpolation and field_type != str - and not issubclass(field_type, Enum) # not choices enum + and inspect.isclass(field_type) and not issubclass(field_type, Enum) # not choices enum ): # upgrade old models that stored complex parameters as string val = ast.literal_eval(val) @@ -229,6 +229,7 @@ def get_default(f): elif val == "": overrides.append("{}.{}=''".format(sub_node, k)) elif isinstance(val, str): + val = val.replace("'", r"\'") overrides.append("{}.{}='{}'".format(sub_node, k, val)) elif isinstance(val, FairseqDataclass): overrides += _override_attr(f"{sub_node}.{k}", type(val), args) @@ -373,7 +374,7 @@ def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: def populate_dataclass( - args: Namespace, dataclass: FairseqDataclass + dataclass: FairseqDataclass, args: Namespace, ) -> FairseqDataclass: for k in dataclass.__dataclass_fields__.keys(): if k.startswith("_"): @@ -382,7 +383,7 @@ def populate_dataclass( if hasattr(args, k): setattr(dataclass, k, getattr(args, k)) - return dataclass + return dataclass def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): @@ -395,6 +396,9 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): # "k in cfg" will return false if its a "mandatory value (e.g. ???)" if k in cfg and isinstance(cfg[k], DictConfig): overwrite_args_by_name(cfg[k], overrides) + elif k in cfg and isinstance(cfg[k], Namespace): + for override_key, val in overrides.items(): + setattr(cfg[k], override_key, val) elif k in overrides: if ( k in REGISTRIES @@ -409,7 +413,7 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): cfg[k] = overrides[k] -def merge_with_parent(dc: FairseqDataclass, cfg: DictConfig): +def merge_with_parent(dc: FairseqDataclass, cfg: FairseqDataclass): dc_instance = DictConfig(dc) dc_instance.__dict__["_parent"] = cfg.__dict__["_parent"] cfg = OmegaConf.merge(dc_instance, cfg) diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index b987966749..600ca27c6a 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -8,11 +8,9 @@ import importlib import os -import fairseq from fairseq.dataclass import FairseqDataclass -from fairseq.dataclass.utils import merge_with_parent +from fairseq.dataclass.utils import merge_with_parent, populate_dataclass from hydra.core.config_store import ConfigStore -from omegaconf import DictConfig, OmegaConf from .composite_encoder import CompositeEncoder from .distributed_fairseq_model import DistributedFairseqModel @@ -78,7 +76,10 @@ def build_model(cfg: FairseqDataclass, task): if model_type in MODEL_DATACLASS_REGISTRY: # set defaults from dataclass. note that arch name and model name can be the same dc = MODEL_DATACLASS_REGISTRY[model_type] - cfg = merge_with_parent(dc(), cfg) + if isinstance(cfg, argparse.Namespace): + cfg = populate_dataclass(dc(), cfg) + else: + cfg = merge_with_parent(dc(), cfg) assert model is not None, f"Could not infer model type from {cfg}" diff --git a/fairseq/registry.py b/fairseq/registry.py index 7a3dd1d1bf..3fbaeac301 100644 --- a/fairseq/registry.py +++ b/fairseq/registry.py @@ -45,7 +45,7 @@ def build_x(cfg: Union[DictConfig, str, Namespace], *extra_args, **extra_kwargs) else: choice = getattr(cfg, registry_name, None) if choice in DATACLASS_REGISTRY: - cfg = populate_dataclass(cfg, DATACLASS_REGISTRY[choice]()) + cfg = populate_dataclass(DATACLASS_REGISTRY[choice](), cfg) if choice is None: if required: diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 9c5423e2b1..603c5b6821 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -420,7 +420,7 @@ def _generate( break if self.search.stop_on_max_len and step >= max_len: break - assert step < max_len + assert step < max_len, f"{step} < {max_len}" # Remove finalized sentences (ones for which {beam_size} # finished hypotheses have been generated) from the batch. diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 415f15e708..0e55d093b1 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -9,9 +9,8 @@ import os from fairseq.dataclass import FairseqDataclass -from fairseq.dataclass.utils import merge_with_parent +from fairseq.dataclass.utils import merge_with_parent, populate_dataclass from hydra.core.config_store import ConfigStore -from omegaconf import DictConfig from .fairseq_task import FairseqTask, LegacyFairseqTask # noqa @@ -22,13 +21,16 @@ TASK_CLASS_NAMES = set() -def setup_task(cfg: DictConfig, **kwargs): +def setup_task(cfg: FairseqDataclass, **kwargs): task = None task_name = getattr(cfg, "task", None) if isinstance(task_name, str): # legacy tasks task = TASK_REGISTRY[task_name] + if task_name in TASK_DATACLASS_REGISTRY: + dc = TASK_DATACLASS_REGISTRY[task_name] + cfg = populate_dataclass(dc(), cfg) else: task_name = getattr(cfg, "_name", None) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index d1b6bf1c14..0f891f1199 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -71,7 +71,7 @@ class AudioPretrainingConfig(FairseqDataclass): metadata={"help": "beam search config for evaluating wer during training"}, ) eval_wer_tokenizer: Any = field( - default="space", + default=None, metadata={"help": "tokenizer config for evaluating wer during training"}, ) eval_wer_post_process: str = field( @@ -185,7 +185,6 @@ def filter_indices_by_size( def valid_step(self, sample, model, criterion): loss, sample_size, logging_output = super().valid_step(sample, model, criterion) - if self.cfg.eval_wer and self.cfg.autoregressive: metrics = self._inference_with_wer(self.sequence_generator, sample, model) logging_output["_num_char_errors"] = metrics["num_char_errors"] @@ -204,15 +203,16 @@ def build_model(self, model_cfg: FairseqDataclass): ) if self.cfg.eval_wer_tokenizer: self.tokenizer = encoders.build_tokenizer(self.cfg.eval_wer_tokenizer) + else: + self.tokenizer = None return model def _inference_with_wer(self, generator, sample, model): - def decode(toks, escape_unk=True): + def decode(toks): s = self.target_dictionary.string( toks.int().cpu(), self.cfg.eval_wer_post_process, - escape_unk=escape_unk, - extra_symbols_to_ignore={generator.eos}, + escape_unk=True, ) if self.tokenizer: s = self.tokenizer.decode(s) @@ -225,14 +225,11 @@ def decode(toks, escape_unk=True): hyp = decode(gen_out[i][0]["tokens"]) ref = decode( utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), - escape_unk=True, ) - hyp = post_process(hyp, self.cfg.eval_wer_post_process).strip("_") - ref = post_process(ref, self.cfg.eval_wer_post_process).strip("_") num_char_errors += editdistance.eval(hyp, ref) num_chars += len(ref) - hyp_words = hyp.split("_") - ref_words = ref.split("_") + hyp_words = hyp.split() + ref_words = ref.split() num_word_errors += editdistance.eval(hyp_words, ref_words) num_words += len(ref_words) diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index e8fd98c325..d962a8145b 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -255,10 +255,10 @@ def main(cfg: DictConfig, **unused_kwargs): wps_meter.update(sample["ntokens"]) progress.log({"wps": round(wps_meter.avg)}) - avg_nll_loss = -score_sum / count / math.log(2) # convert to base 2 + avg_nll_loss = -score_sum / count / math.log(2) if count > 0 else 0 # convert to base 2 logger.info( "Evaluated {} tokens in {:.1f}s ({:.2f} tokens/s)".format( - gen_timer.n, gen_timer.sum, 1.0 / gen_timer.avg + gen_timer.n, gen_timer.sum, 1.0 / gen_timer.avg if gen_timer.avg > 0 else 0 ) ) logger.info( From 11ea91a33a5788b3b9e7a02cab4bcb158cac8778 Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 11 Nov 2020 10:14:04 -0800 Subject: [PATCH 044/774] load dataset with saved task config (optionally) (#1423) Summary: this adds an argument to load_dataset that provides task configuration from the checkpoint. different tasks can decide what to do with it afterwards. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1423 Reviewed By: myleott Differential Revision: D24875706 Pulled By: alexeib fbshipit-source-id: 5bb1e2b7495520c456024dc7b0751b65cb05b473 --- examples/speech_recognition/infer.py | 73 ++++++---------------------- fairseq/checkpoint_utils.py | 10 ++-- fairseq/tasks/audio_pretraining.py | 28 ++++++----- fairseq/tasks/fairseq_task.py | 11 ++++- fairseq_cli/generate.py | 7 ++- fairseq_cli/validate.py | 8 +-- 6 files changed, 57 insertions(+), 80 deletions(-) diff --git a/examples/speech_recognition/infer.py b/examples/speech_recognition/infer.py index 68889463f4..ddd3fd6340 100644 --- a/examples/speech_recognition/infer.py +++ b/examples/speech_recognition/infer.py @@ -8,6 +8,7 @@ Run inference for pre-processed data with a trained model. """ +import ast import logging import math import os @@ -18,7 +19,6 @@ import torch from fairseq import checkpoint_utils, options, progress_bar, tasks, utils from fairseq.data.data_utils import post_process -from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging.meters import StopwatchMeter, TimeMeter @@ -178,53 +178,6 @@ def get_res_file(file_prefix): } -def load_models_and_criterions( - filenames, data_path, arg_overrides=None, task=None, model_state=None -): - models = [] - criterions = [] - - if arg_overrides is None: - arg_overrides = {} - - arg_overrides["wer_args"] = None - arg_overrides["data"] = data_path - - if filenames is None: - assert model_state is not None - filenames = [0] - else: - filenames = filenames.split(":") - - for filename in filenames: - if model_state is None: - if not os.path.exists(filename): - raise IOError("Model file not found: {}".format(filename)) - state = checkpoint_utils.load_checkpoint_to_cpu(filename, arg_overrides) - else: - state = model_state - - if "cfg" in state: - cfg = state["cfg"] - else: - cfg = convert_namespace_to_omegaconf(state["args"]) - - if task is None: - if hasattr(cfg.task, 'data'): - cfg.task.data = data_path - task = tasks.setup_task(cfg.task) - - model = task.build_model(cfg.model) - model.load_state_dict(state["model"], strict=True) - models.append(model) - - criterion = task.build_criterion(cfg.criterion) - if "criterion" in state: - criterion.load_state_dict(state["criterion"], strict=True) - criterions.append(criterion) - return models, criterions, task - - def optimize_models(args, use_cuda, models): """Optimize ensemble for generation""" for model in models: @@ -266,23 +219,26 @@ def main(args, task=None, model_state=None): logger.info("| decoding with criterion {}".format(args.criterion)) + task = tasks.setup_task(args) + # Load ensemble if args.load_emissions: models, criterions = [], [] - task = tasks.setup_task(args) + task.load_dataset(args.gen_subset) else: logger.info("| loading model(s) from {}".format(args.path)) - models, criterions, task = load_models_and_criterions( - args.path, - data_path=args.data, - arg_overrides=eval(args.model_overrides), # noqa + models, saved_cfg = checkpoint_utils.load_model_ensemble( + utils.split_paths(args.path), + arg_overrides=ast.literal_eval(args.model_overrides), task=task, - model_state=model_state, + suffix=args.checkpoint_suffix, + strict=(args.checkpoint_shard_count == 1), + num_shards=args.checkpoint_shard_count, + state=model_state, ) optimize_models(args, use_cuda, models) + task.load_dataset(args.gen_subset, task_cfg=saved_cfg.task) - # Load dataset splits - task.load_dataset(args.gen_subset) # Set dictionary tgt_dict = task.target_dictionary @@ -295,8 +251,9 @@ def main(args, task=None, model_state=None): # hack to pass transitions to W2lDecoder if args.criterion == "asg_loss": - trans = criterions[0].asg.trans.data - args.asg_transitions = torch.flatten(trans).tolist() + raise NotImplementedError("asg_loss is currently not supported") + # trans = criterions[0].asg.trans.data + # args.asg_transitions = torch.flatten(trans).tolist() # Load dataset (possibly sharded) itr = get_dataset_itr(args, task, models) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 3038a1ebcc..5a0dc099b2 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -239,7 +239,7 @@ def load_checkpoint_to_cpu(path, arg_overrides=None): def load_model_ensemble( - filenames, arg_overrides=None, task=None, strict=True, suffix="", num_shards=1 + filenames, arg_overrides=None, task=None, strict=True, suffix="", num_shards=1, state=None ): """Loads an ensemble of models. @@ -259,12 +259,13 @@ def load_model_ensemble( strict, suffix, num_shards, + state, ) return ensemble, args def load_model_ensemble_and_task( - filenames, arg_overrides=None, task=None, strict=True, suffix="", num_shards=1 + filenames, arg_overrides=None, task=None, strict=True, suffix="", num_shards=1, state=None ): from fairseq import tasks @@ -272,8 +273,10 @@ def load_model_ensemble_and_task( strict and num_shards > 1 ), "Cannot load state dict with strict=True and checkpoint shards > 1" ensemble = [] + cfg = None for filename in filenames: orig_filename = filename + assert num_shards > 0 for shard_idx in range(num_shards): if num_shards == 1: filename = filename.replace(".pt", suffix + ".pt") @@ -282,7 +285,8 @@ def load_model_ensemble_and_task( if not PathManager.exists(filename): raise IOError("Model file not found: {}".format(filename)) - state = load_checkpoint_to_cpu(filename, arg_overrides) + if state is None: + state = load_checkpoint_to_cpu(filename, arg_overrides) if "args" in state and state["args"] is not None: cfg = convert_namespace_to_omegaconf(state["args"]) elif "cfg" in state and state["cfg"] is not None: diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 0f891f1199..90e667c80d 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -10,6 +10,7 @@ import sys import torch +from argparse import Namespace from dataclasses import dataclass, field from typing import Optional, Any from omegaconf import MISSING @@ -123,25 +124,28 @@ def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): return cls(cfg, target_dictionary=target_dictionary) - def load_dataset(self, split, **kwargs): - """Load a given dataset split. + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + data_path = self.cfg.data + task_cfg = task_cfg or self.cfg - Args: - split (str): name of the split (e.g., train, valid, test) - """ - manifest = os.path.join(self.cfg.data, "{}.tsv".format(split)) + # upgrade old task + if isinstance(task_cfg, Namespace): + if not hasattr(task_cfg, "autoregressive"): + task_cfg.autoregressive = not task_cfg.criterion == 'ctc' + + manifest = os.path.join(data_path, "{}.tsv".format(split)) self.datasets[split] = FileAudioDataset( manifest, - sample_rate=self.cfg.sample_rate, + sample_rate=task_cfg.sample_rate, max_sample_size=self.cfg.max_sample_size, min_sample_size=self.cfg.max_sample_size, min_length=self.cfg.min_sample_size, - pad=self.cfg.labels is not None or self.cfg.enable_padding, - normalize=self.cfg.normalize, + pad=task_cfg.labels is not None or task_cfg.enable_padding, + normalize=task_cfg.normalize, ) - if self.cfg.labels: - label_path = os.path.join(self.cfg.data, f"{split}.{self.cfg.labels}") + if task_cfg.labels: + label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") labels = [] with open(label_path, "r") as f: for line in f: @@ -156,7 +160,7 @@ def load_dataset(self, split, **kwargs): eos=self.target_dictionary.eos(), batch_targets=True, process_label=process_label, - add_to_input=self.cfg.autoregressive, + add_to_input=task_cfg.autoregressive, ) @property diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index c47f9c4200..f62973a534 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -91,11 +91,20 @@ def setup_task(cls, cfg: DictConfig, **kwargs): def has_sharded_data(self, split): return os.pathsep in getattr(self.cfg, "data", "") - def load_dataset(self, split, combine=False, **kwargs): + def load_dataset( + self, + split: str, + combine: bool = False, + task_cfg: FairseqDataclass = None, + **kwargs + ): """Load a given dataset split. Args: split (str): name of the split (e.g., train, valid, test) + combine (bool): combines a split segmented into pieces into one dataset + task_cfg (FairseqDataclass): optional task configuration stored in the checkpoint that can be used + to load datasets """ raise NotImplementedError diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 021f819ed7..6be8150cda 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -81,7 +81,7 @@ def _main(cfg: DictConfig, output_file): # Load dataset splits task = tasks.setup_task(cfg.task) - task.load_dataset(cfg.dataset.gen_subset) + # Set dictionaries try: @@ -94,7 +94,7 @@ def _main(cfg: DictConfig, output_file): # Load ensemble logger.info("loading model(s) from {}".format(cfg.common_eval.path)) - models, _model_args = checkpoint_utils.load_model_ensemble( + models, saved_cfg = checkpoint_utils.load_model_ensemble( utils.split_paths(cfg.common_eval.path), arg_overrides=overrides, task=task, @@ -103,6 +103,9 @@ def _main(cfg: DictConfig, output_file): num_shards=cfg.checkpoint.checkpoint_shard_count, ) + # loading the dataset should happen after the checkpoint has been loaded so we can give it the saved task config + task.load_dataset(cfg.dataset.gen_subset, task_cfg=saved_cfg.task) + if cfg.generation.lm_path is not None: overrides["data"] = cfg.task.data diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index 36e8bd16ca..f6f0c9265c 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -51,7 +51,7 @@ def main(cfg: DictConfig, override_args=None): # Load ensemble logger.info("loading model(s) from {}".format(cfg.common_eval.path)) - models, model_args, task = checkpoint_utils.load_model_ensemble_and_task( + models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( [cfg.common_eval.path], arg_overrides=overrides, suffix=cfg.checkpoint.checkpoint_suffix, @@ -66,15 +66,15 @@ def main(cfg: DictConfig, override_args=None): model.cuda() # Print args - logger.info(model_args) + logger.info(saved_cfg) # Build criterion - criterion = task.build_criterion(model_args.criterion) + criterion = task.build_criterion(saved_cfg.criterion) criterion.eval() for subset in cfg.dataset.valid_subset.split(","): try: - task.load_dataset(subset, combine=False, epoch=1) + task.load_dataset(subset, combine=False, epoch=1, task_cfg=saved_cfg) dataset = task.dataset(subset) except KeyError: raise Exception("Cannot find dataset: " + subset) From e607911dde205e2188d3e62dcde592a6d84b4c46 Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 11 Nov 2020 17:32:30 -0800 Subject: [PATCH 045/774] fix passing task config in validate.py (#1426) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1426 Reviewed By: aconneau Differential Revision: D24895299 Pulled By: alexeib fbshipit-source-id: 7af96952b857fa4616cdafd0268d8ab6cb94c61d --- fairseq_cli/validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index f6f0c9265c..c69bb94142 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -74,7 +74,7 @@ def main(cfg: DictConfig, override_args=None): for subset in cfg.dataset.valid_subset.split(","): try: - task.load_dataset(subset, combine=False, epoch=1, task_cfg=saved_cfg) + task.load_dataset(subset, combine=False, epoch=1, task_cfg=saved_cfg.task) dataset = task.dataset(subset) except KeyError: raise Exception("Cannot find dataset: " + subset) From b55053373fb8678361a45a1d2c1b462befd9ab1a Mon Sep 17 00:00:00 2001 From: Angela Fan Date: Fri, 13 Nov 2020 09:49:40 -0800 Subject: [PATCH 046/774] update m2m readme (#2890) Summary: adding smaller models Pull Request resolved: https://github.com/pytorch/fairseq/pull/2890 Reviewed By: ngoyal2707 Differential Revision: D24935146 Pulled By: huihuifan fbshipit-source-id: 2ba8e4083b9805d336154e3cc0d6d7bed71cca04 --- examples/m2m_100/README.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/examples/m2m_100/README.md b/examples/m2m_100/README.md index 0bacd4c8b1..f1b465c7b9 100644 --- a/examples/m2m_100/README.md +++ b/examples/m2m_100/README.md @@ -14,8 +14,8 @@ sacrebleu -t wmt14 -l fr-en --echo src > wmt.test.fr-en.fr sacrebleu -t wmt14 -l fr-en --echo ref > wmt.test.fr-en.en # WAT -wget http://lotus.kuee.kyoto-u.ac.jp/WAT/my-en-data/wat2019.my-en.zip -unzip wat2019.my-en.zip +wget http://lotus.kuee.kyoto-u.ac.jp/WAT/my-en-data/wat2020.my-en.zip +unzip wat2020.my-en.zip # FLORES # download from: https://github.com/facebookresearch/flores @@ -116,7 +116,22 @@ If you use any of the resources listed here, please cite: ## Trained Models -More models coming up soon. +### 418M and 1.2B Model +We include the last checkpoint for both of these models. + +```bash +wget https://dl.fbaipublicfiles.com/m2m_100/model_dict.128k.txt +wget https://dl.fbaipublicfiles.com/m2m_100/language_pairs_small_models.txt + +# 418M parameter model +wget https://dl.fbaipublicfiles.com/m2m_100/418M_last_checkpoint.pt + +# 1.2B parameter model +wget https://dl.fbaipublicfiles.com/m2m_100/1.2B_last_checkpoint.pt + +# Generation: +fairseq-generate $binarized_data_path --batch-size 32 --path $path_to_model -s en -t fr --remove-bpe 'sentencepiece' --beam 5 --task translation_multi_simple_epoch --lang-pairs language_pairs_small_models --decoder-langtok --encoder-langtok src --gen-subset test > gen_out +``` ### 12B Model 12B parameter model trained on many-to-many training data for 100 languages. We include the last checkpoint, average of last 5 checkpoints, average of last 10 checkpoints. There isn't a universally best choice out of these three, but all three versions are pretty close in accuracy. You can either sweep over the 3 checkpoints on a dev test and use the best performing checkpoint for final testing. Or the last checkpoint can be a good default choice. From dc6a84f1433beaf3f6332ea181231055249be684 Mon Sep 17 00:00:00 2001 From: Yuqing Tang Date: Fri, 13 Nov 2020 12:22:46 -0800 Subject: [PATCH 047/774] Make BART models compatiable with JIT Summary: Bart models are not compatible with JIT. This diff makes minor changes to enable its compabilitity Reviewed By: myleott Differential Revision: D24824963 fbshipit-source-id: 41cbcc46c14b0439f5763478b8efe98e5516dc95 --- fairseq/models/bart/model.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/fairseq/models/bart/model.py b/fairseq/models/bart/model.py index e105d6fc46..44f03b0162 100644 --- a/fairseq/models/bart/model.py +++ b/fairseq/models/bart/model.py @@ -6,6 +6,7 @@ BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension """ +from typing import Optional import logging @@ -24,6 +25,8 @@ @register_model("bart") class BARTModel(TransformerModel): + __jit_unused_properties__ = ["supported_targets"] + @classmethod def hub_models(cls): return { @@ -41,6 +44,8 @@ def __init__(self, args, encoder, decoder): self.apply(init_bert_params) self.classification_heads = nn.ModuleDict() + if hasattr(self.encoder, "dictionary"): + self.eos: int = self.encoder.dictionary.eos() @staticmethod def add_args(parser): @@ -71,10 +76,12 @@ def forward( src_tokens, src_lengths, prev_output_tokens, - features_only=False, - classification_head_name=None, - token_embeddings=None, - **kwargs, + features_only: bool = False, + classification_head_name: Optional[str] = None, + token_embeddings: Optional[torch.Tensor] = None, + return_all_hiddens: bool = True, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, ): if classification_head_name is not None: features_only = True @@ -83,22 +90,27 @@ def forward( src_tokens, src_lengths=src_lengths, token_embeddings=token_embeddings, - **kwargs, + return_all_hiddens=return_all_hiddens ) x, extra = self.decoder( prev_output_tokens, encoder_out=encoder_out, features_only=features_only, - **kwargs, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + src_lengths=src_lengths, + return_all_hiddens=return_all_hiddens, ) - + eos: int = self.eos if classification_head_name is not None: sentence_representation = x[ - src_tokens.eq(self.encoder.dictionary.eos()), : + src_tokens.eq(eos), : ].view(x.size(0), -1, x.size(-1))[:, -1, :] - x = self.classification_heads[classification_head_name]( - sentence_representation - ) + for k, head in self.classification_heads.items(): + # for torch script only supports iteration + if k == classification_head_name: + x = head(sentence_representation) + break return x, extra @classmethod From 3c5647cebf454c07b52a0fb899c920789381ebda Mon Sep 17 00:00:00 2001 From: Weiyi Zheng Date: Fri, 13 Nov 2020 16:11:44 -0800 Subject: [PATCH 048/774] add grad_norm infinity check Summary: add grad_norm check for fp32 cases and single node training as well. Triggers nan detector when the grad_norm check fails, should help debug nan/inf cases. also fixing a bug (i think) in the original check_grad_norm() where [float('inf'), float('inf')] can pass the check. Reviewed By: myleott Differential Revision: D24849271 fbshipit-source-id: 2382342cd549717f3ff178b9aa29933f486327c8 --- fairseq/trainer.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 19ca213d55..d7ba0be874 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -632,12 +632,16 @@ def maybe_no_sync(): grad_norm = self.clip_grad_norm(self.cfg.optimization.clip_norm) # check that grad norms are consistent across workers - if ( - not self.cfg.optimization.use_bmuf - and self.cfg.distributed_training.distributed_wrapper != "SlowMo" - and not self.tpu - ): - self._check_grad_norms(grad_norm) + # on tpu check tensor is slow + if not self.tpu: + if ( + not self.cfg.optimization.use_bmuf + and self.cfg.distributed_training.distributed_wrapper != "SlowMo" + ): + self._check_grad_norms(grad_norm) + if not torch.isfinite(grad_norm).all(): + # check local gradnorm single GPU case, trigger NanDetector + raise FloatingPointError("gradients are Nan/Inf") with torch.autograd.profiler.record_function("optimizer"): # take an optimization step @@ -1078,7 +1082,7 @@ def _check_grad_norms(self, grad_norm): def is_consistent(tensor): max_abs_diff = torch.max(torch.abs(tensor - tensor[0])) return ( - not torch.isfinite(tensor).any() + torch.isfinite(tensor).all() or (max_abs_diff / (tensor[0] + 1e-6) < 1e-6).all() ) @@ -1090,7 +1094,8 @@ def is_consistent(tensor): error_detail = "grad_norm across the workers:\n{}\n".format( pretty_detail ) - raise RuntimeError( + # use FloatingPointError to trigger NanDetector + raise FloatingPointError( "Fatal error: gradients are inconsistent between workers. " "Try --ddp-backend=no_c10d. " "Or are you mixing up different generation of GPUs in training?" From b987d30c69d773ccbf7d432e1cd0878aa9e50196 Mon Sep 17 00:00:00 2001 From: Pengzhi Gao Date: Sat, 14 Nov 2020 08:45:03 -0800 Subject: [PATCH 049/774] Delete duplicate code in RoBERTa model (#2891) Summary: Simple fix. Lines 498 and 499 are the same. Pull Request resolved: https://github.com/pytorch/fairseq/pull/2891 Reviewed By: alexeib Differential Revision: D24953450 Pulled By: myleott fbshipit-source-id: 7745d066ed1e431edc39e99dd72ec8937235f752 --- fairseq/models/roberta/model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 0f6efe5b33..96a7b9c8a2 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -496,7 +496,6 @@ def base_architecture(args): args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) - args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) args.untie_weights_roberta = getattr(args, "untie_weights_roberta", False) args.spectral_norm_classification_head = getattr( args, "spectral_norm_classification_head", False From 0d03fbedcf79b63901b8718b4c61c525464cb198 Mon Sep 17 00:00:00 2001 From: Stas Bekman Date: Sat, 14 Nov 2020 08:46:07 -0800 Subject: [PATCH 050/774] deprecation warning fixes (#2881) Summary: ## What does this PR do? Fixes: - 2x `DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working` - 1x `/fairseq/optim/adam.py:98: DeprecationWarning: invalid escape sequence \:` This is with py38. Pull Request resolved: https://github.com/pytorch/fairseq/pull/2881 Reviewed By: alexeib Differential Revision: D24959633 Pulled By: myleott fbshipit-source-id: ac563e194d5f07e3817de55729b0448366a6dc23 --- fairseq/optim/adam.py | 4 ++-- fairseq/optim/nag.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fairseq/optim/adam.py b/fairseq/optim/adam.py index 9b8ddffd7e..1a4f213707 100644 --- a/fairseq/optim/adam.py +++ b/fairseq/optim/adam.py @@ -5,7 +5,7 @@ import logging import math -from collections import Collection +from collections.abc import Collection from dataclasses import dataclass, field from typing import List @@ -95,7 +95,7 @@ def average_params(self): class Adam(torch.optim.Optimizer): - """Implements Adam algorithm. + r"""Implements Adam algorithm. This implementation is modified from torch.optim.Adam based on: `Fixed Weight Decay Regularization in Adam` diff --git a/fairseq/optim/nag.py b/fairseq/optim/nag.py index 3982a8271d..c612d812c9 100644 --- a/fairseq/optim/nag.py +++ b/fairseq/optim/nag.py @@ -3,7 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from collections import Collection +from collections.abc import Collection from dataclasses import dataclass, field from typing import List From 0a848245f3e00ee39a68fddf54f738de11dd8cc8 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sun, 15 Nov 2020 19:46:48 -0800 Subject: [PATCH 051/774] Add Truncated BPTT example + TransformerXL (#1410) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1410 Test Plan: - reproduced Transformer-XL results (see README) - added integration test Reviewed By: jingfeidu Differential Revision: D24928966 Pulled By: myleott fbshipit-source-id: 86376c17ab24d37e72e7c097b6dcec71b1a087a7 --- README.md | 23 +- examples/__init__.py | 5 +- examples/criss/mining/mine.py | 9 +- examples/truncated_bptt/README.md | 70 +++++ examples/truncated_bptt/__init__.py | 6 + .../truncated_bptt/transformer_xl_model.py | 146 +++++++++++ .../truncated_bptt/truncated_bptt_lm_task.py | 246 ++++++++++++++++++ fairseq/tasks/fairseq_task.py | 6 + tests/test_binaries.py | 86 +++++- 9 files changed, 576 insertions(+), 21 deletions(-) create mode 100644 examples/truncated_bptt/README.md create mode 100644 examples/truncated_bptt/__init__.py create mode 100644 examples/truncated_bptt/transformer_xl_model.py create mode 100644 examples/truncated_bptt/truncated_bptt_lm_task.py diff --git a/README.md b/README.md index 0648da15f7..3ae332b350 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ We provide reference implementations of various sequence modeling papers: + [Understanding Back-Translation at Scale (Edunov et al., 2018)](examples/backtranslation/README.md) + [Adaptive Input Representations for Neural Language Modeling (Baevski and Auli, 2018)](examples/language_model/README.adaptive_inputs.md) + [Lexically constrained decoding with dynamic beam allocation (Post & Vilar, 2018)](examples/constrained_decoding/README.md) + + [Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context](examples/truncated_bptt/README.md) + [Mixture Models for Diverse Machine Translation: Tricks of the Trade (Shen et al., 2019)](examples/translation_moe/README.md) + [RoBERTa: A Robustly Optimized BERT Pretraining Approach (Liu et al., 2019)](examples/roberta/README.md) + [Facebook FAIR's WMT19 News Translation Task Submission (Ng et al., 2019)](examples/wmt19/README.md) @@ -59,8 +60,9 @@ We provide reference implementations of various sequence modeling papers: ### What's New: -* November 2020: Adopted [Hydra](https://github.com/facebookresearch/hydra) as a configuration framework; -[added documentation explaining how to use it for new and existing projects](docs/hydra_integration.md) +* November 2020: Adopted the [Hydra](https://github.com/facebookresearch/hydra) configuration framework + * [see documentation explaining how to use it for new and existing projects](docs/hydra_integration.md) +* November 2020: [fairseq 0.10.0 released](https://github.com/pytorch/fairseq/releases/tag/v0.10.0) * October 2020: [Added R3F/R4F (Better Fine-Tuning) code](examples/rxf/README.md) * October 2020: [Deep Transformer with Latent Depth code released](examples/latent_depth/README.md) * October 2020: [Added CRISS models and code](examples/criss/README.md) @@ -69,13 +71,13 @@ We provide reference implementations of various sequence modeling papers: * August 2020: [Added lexically constrained decoding](examples/constrained_decoding/README.md) * August 2020: [wav2vec2 models and code released](examples/wav2vec/README.md) * July 2020: [Unsupervised Quality Estimation code released](examples/unsupervised_quality_estimation/README.md) + +
Previous updates

+ * May 2020: [Follow fairseq on Twitter](https://twitter.com/fairseq) * April 2020: [Monotonic Multihead Attention code released](examples/simultaneous_translation/README.md) * April 2020: [Quant-Noise code released](examples/quant_noise/README.md) * April 2020: [Initial model parallel support and 11B parameters unidirectional LM released](examples/megatron_11b/README.md) - -

Previous updates

- * March 2020: [Byte-level BPE code released](examples/byte_level_bpe/README.md) * February 2020: [mBART model and code released](examples/mbart/README.md) * February 2020: [Added tutorial for back-translation](https://github.com/pytorch/fairseq/tree/master/examples/backtranslation#training-your-own-model-wmt18-english-german) @@ -99,10 +101,10 @@ We provide reference implementations of various sequence modeling papers: + beam search + Diverse Beam Search ([Vijayakumar et al., 2016](https://arxiv.org/abs/1610.02424)) + sampling (unconstrained, top-k and top-p/nucleus) - + lexically constrained decoding ([Post & Vilar, 2018](examples/constrained_decoding/README.md)) -* large mini-batch training even on a single GPU via delayed updates -* mixed precision training (trains faster with less GPU memory on [NVIDIA tensor cores](https://developer.nvidia.com/tensor-cores)) -* extensible: easily register new models, criterions, tasks, optimizers and learning rate schedulers + + [lexically constrained decoding](examples/constrained_decoding/README.md) (Post & Vilar, 2018) +* [gradient accumulation](https://fairseq.readthedocs.io/en/latest/getting_started.html#large-mini-batch-training-with-delayed-updates) enables training with large mini-batches even on a single GPU +* [mixed precision training](https://fairseq.readthedocs.io/en/latest/getting_started.html#training-with-half-precision-floating-point-fp16) (trains faster with less GPU memory on [NVIDIA tensor cores](https://developer.nvidia.com/tensor-cores)) +* [extensible](https://fairseq.readthedocs.io/en/latest/overview.html): easily register new models, criterions, tasks, optimizers and learning rate schedulers * [flexible configuration](docs/hydra_integration.md) based on [Hydra](https://github.com/facebookresearch/hydra) allowing a combination of code, command-line and file based configuration We also provide [pre-trained models for translation and language modeling](#pre-trained-models-and-examples) @@ -131,6 +133,9 @@ pip install --editable ./ # on MacOS: # CFLAGS="-stdlib=libc++" pip install --editable ./ + +# to install the latest stable release (0.10.0) +# pip install fairseq==0.10.0 ``` * **For faster training** install NVIDIA's [apex](https://github.com/NVIDIA/apex) library: diff --git a/examples/__init__.py b/examples/__init__.py index 80d95f5fe7..44bb24ae61 100644 --- a/examples/__init__.py +++ b/examples/__init__.py @@ -3,4 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from fairseq.version import __version__ # noqa +try: + from fairseq.version import __version__ # noqa +except ImportError: + pass diff --git a/examples/criss/mining/mine.py b/examples/criss/mining/mine.py index c86f73ae87..c872da196f 100644 --- a/examples/criss/mining/mine.py +++ b/examples/criss/mining/mine.py @@ -7,7 +7,12 @@ import glob from subprocess import check_call -import faiss +try: + import faiss + + has_faiss = True +except ImportError: + has_faiss = False import numpy as np @@ -40,6 +45,8 @@ def load_batch(emb_file, dim): def knnGPU_sharded(x_batches_f, y_batches_f, dim, k, direction="x2y"): + if not has_faiss: + raise ImportError("Please install Faiss") sims = [] inds = [] xfrom = 0 diff --git a/examples/truncated_bptt/README.md b/examples/truncated_bptt/README.md new file mode 100644 index 0000000000..f5c6447f1c --- /dev/null +++ b/examples/truncated_bptt/README.md @@ -0,0 +1,70 @@ +# Truncated Backpropagation Through Time (BPTT) + +Truncated BPTT is a useful technique for training language models on very long +sequences. Typically a long sequences is split into chunks and a language model +is trained over the chunks sequentially. The LM may condition on previous +chunks, but gradients only flow through the current chunk. This technique was +the basis for the paper: [Transformer-XL: Attentive Language Models Beyond a +Fixed-Length Context](https://arxiv.org/abs/1901.02860), which achieved +state-of-the-art language modeling results at the time of publication. + +It is slightly tricky to implement Truncated BPTT efficiently in fairseq, since +we need to iterate over the data sequentially and disable any batch shuffling +logic. The code provided in this example illustrates how to implement Truncated +BPTT in fairseq by overriding ``FairseqTask::get_batch_iterator`` to iterate +over the data sequentially. Crucially, this example supports batching and +multi-GPU (data parallel) training. + +##### 0. Setup + +First, see the general [language modeling README](README.md) for instructions on +preprocessing the WikiText-103 data. + +##### 1. Train a Transformer-XL model on WikiText-103 + +We will train a 16-layer Transformer-XL model following the [hyperparameters +used in the original +paper](https://github.com/kimiyoung/transformer-xl/blob/master/pytorch/run_wt103_base.sh). + +The following command assumes 4 GPUs, so that the total batch size is 60 +sequences (15 x 4). Training should take ~24 hours on 4 V100 GPUs: +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 fairseq-train \ + --user-dir examples/truncated_bptt \ + data-bin/wikitext-103/ \ + --task truncated_bptt_lm --tokens-per-sample 150 \ + --batch-size 15 --max-update 200000 \ + --arch transformer_xl --n-layer 16 --d-model 410 --n-head 10 \ + --d-head 41 --d-inner 2100 --dropout 0.1 --dropatt 0.0 --mem-len 150 \ + --optimizer adam --clip-norm 0.25 \ + --lr-scheduler cosine --warmup-updates 0 --lr 0.0 --max-lr 0.00025 \ + --log-format json --log-interval 25 \ + --fp16 +``` + +If training on a single GPU, set `--update-freq=4` to accumulate 4x gradients +and simulate training on 4 GPUs. + +##### 2. Evaluate + +```bash +fairseq-eval-lm data-bin/wikitext-103/ \ + --path checkpoints/checkpoint_best.pt \ + --user-dir examples/truncated_bptt/ \ + --task truncated_bptt_lm \ + --batch-size 1 --required-batch-size-multiple 1 \ + --model-overrides '{"mem_len":640,"clamp_len":400,"same_length":True}' \ + --tokens-per-sample 64 +# ... | INFO | fairseq_cli.eval_lm | num. model params: 151123537 +# ... | INFO | fairseq_cli.eval_lm | Evaluated 245569 tokens in 83.1s (2956.82 tokens/s) +# ... | INFO | fairseq_cli.eval_lm | Loss (base 2): 4.5668, Perplexity: 23.70 +# Compare to 24.0 test perplexity from the paper +``` + +*Note:* During training the model saw 150 tokens of context +(``--tokens-per-sample=150``) and 150 extra memory tokens (``--mem-len=150``). +During evaluation we measure perplexity on sequences of 64 tokens +(``--tokens-per-sample=64``) and increase the memory length +(``--model-overrides='{"mem_len":640}'``). These settings match the evaluation +settings from [the original +paper](https://github.com/kimiyoung/transformer-xl/blob/master/pytorch/run_wt103_base.sh). diff --git a/examples/truncated_bptt/__init__.py b/examples/truncated_bptt/__init__.py new file mode 100644 index 0000000000..eee484d427 --- /dev/null +++ b/examples/truncated_bptt/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from . import transformer_xl_model, truncated_bptt_lm_task # noqa diff --git a/examples/truncated_bptt/transformer_xl_model.py b/examples/truncated_bptt/transformer_xl_model.py new file mode 100644 index 0000000000..7466c951ab --- /dev/null +++ b/examples/truncated_bptt/transformer_xl_model.py @@ -0,0 +1,146 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from dataclasses import dataclass, field +from typing import Dict, List, Optional + +import torch +from fairseq.dataclass import FairseqDataclass +from fairseq.models import ( + FairseqIncrementalDecoder, + FairseqLanguageModel, + register_model, +) +from fairseq.modules.checkpoint_activations import checkpoint_wrapper +from omegaconf import II + + +logger = logging.getLogger(__name__) + + +@dataclass +class TransformerXLConfig(FairseqDataclass): + # defaults come from the original Transformer-XL code + cutoffs: List[int] = field(default_factory=lambda: [20000, 40000, 200000]) + d_model: int = 500 + n_head: int = 10 + d_head: int = 50 + d_inner: int = 1000 + div_val: int = 1 + n_layer: int = 12 + mem_len: int = 0 + clamp_len: int = -1 + same_length: bool = False + dropout: float = 0.0 + dropatt: float = 0.0 + checkpoint_activations: bool = False + max_target_positions: int = II("task.max_target_positions") + + +@register_model("transformer_xl", dataclass=TransformerXLConfig) +class TransformerXLLanguageModel(FairseqLanguageModel): + @classmethod + def build_model(cls, cfg: TransformerXLConfig, task): + return cls(TransformerXLDecoder(cfg, task)) + + +class TransformerXLDecoder(FairseqIncrementalDecoder): + def __init__(self, cfg, task): + from transformers.configuration_transfo_xl import TransfoXLConfig + from transformers.modeling_transfo_xl import TransfoXLLMHeadModel + + super().__init__(task.target_dictionary) + self.cfg = cfg + + # remove any cutoffs larger than the vocab size + cutoffs = [ + cutoff for cutoff in cfg.cutoffs if cutoff < len(task.target_dictionary) + ] + + config = TransfoXLConfig( + vocab_size=len(task.target_dictionary), + cutoffs=cutoffs, + d_model=cfg.d_model, + d_embed=cfg.d_model, + n_head=cfg.n_head, + d_head=cfg.d_head, + d_inner=cfg.d_inner, + div_val=cfg.div_val, + n_layer=cfg.n_layer, + mem_len=cfg.mem_len, + clamp_len=cfg.clamp_len, + same_length=cfg.same_length, + dropout=cfg.dropout, + dropatt=cfg.dropatt, + ) + logger.info(config) + self.model = TransfoXLLMHeadModel(config) + + # Workaround a bug in huggingface's ``ProjectedAdaptiveLogSoftmax`` + # which adds ``None`` values to an ``nn.ParameterList``, which is not + # supported in PyTorch. Instead we can replace this with an + # ``nn.ModuleList``, which does support ``None`` values. + try: + if all(p is None for p in self.model.crit.out_projs._parameters.values()): + self.model.crit.out_projs = torch.nn.ModuleList( + [None] * len(self.model.crit.out_projs._parameters) + ) + except Exception: + pass + + if cfg.checkpoint_activations: + for i in range(len(self.model.transformer.layers)): + self.model.transformer.layers[i] = checkpoint_wrapper( + self.model.transformer.layers[i] + ) + + self._mems = None + + def forward( + self, + src_tokens, + src_lengths=None, # unused + incremental_state: Optional[Dict[str, List[torch.Tensor]]] = None, + encoder_out=None, + ): + if incremental_state is not None: # used during inference + mems = self.get_incremental_state(incremental_state, "mems") + src_tokens = src_tokens[:, -1:] # only keep the most recent token + else: + mems = self._mems + + output = self.model( + input_ids=src_tokens, + mems=mems, + return_dict=False, + ) + + if len(output) >= 2: + if incremental_state is not None: + self.set_incremental_state(incremental_state, "mems", output[1]) + else: + self._mems = output[1] + + return (output[0],) + + def max_positions(self): + return self.cfg.max_target_positions + + def reorder_incremental_state( + self, + incremental_state: Dict[str, Dict[str, Optional[torch.Tensor]]], + new_order: torch.Tensor, + ): + """Reorder incremental state. + + This will be called when the order of the input has changed from the + previous time step. A typical use case is beam search, where the input + order changes between time steps based on the selection of beams. + """ + mems = self.get_incremental_state(incremental_state, "mems") + if mems is not None: + new_mems = [mems_i.index_select(1, new_order) for mems_i in mems] + self.set_incremental_state(incremental_state, "mems", new_mems) diff --git a/examples/truncated_bptt/truncated_bptt_lm_task.py b/examples/truncated_bptt/truncated_bptt_lm_task.py new file mode 100644 index 0000000000..5f81ec4b84 --- /dev/null +++ b/examples/truncated_bptt/truncated_bptt_lm_task.py @@ -0,0 +1,246 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from dataclasses import dataclass, field +from typing import List, Optional, Tuple + +import torch +from fairseq import distributed_utils as dist_utils, utils +from fairseq.data import Dictionary, TokenBlockDataset, data_utils, iterators +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task +from omegaconf import II + + +logger = logging.getLogger(__name__) + + +@dataclass +class TruncatedBPTTLMConfig(FairseqDataclass): + data: str = field(default="???", metadata={"help": "path to data directory"}) + tokens_per_sample: int = field( + default=1024, + metadata={"help": "max number of tokens per sequence"}, + ) + batch_size: int = II("dataset.batch_size") + # Some models use *max_target_positions* to know how many positional + # embeddings to learn. We use II(...) to make it default to + # *tokens_per_sample*, but in principle there could be more positional + # embeddings than tokens in a single batch. This may also be irrelevant for + # custom model implementations. + max_target_positions: int = II("task.tokens_per_sample") + # these will be populated automatically if not provided + data_parallel_rank: Optional[int] = None + data_parallel_size: Optional[int] = None + + +@register_task("truncated_bptt_lm", dataclass=TruncatedBPTTLMConfig) +class TruncatedBPTTLMTask(FairseqTask): + def __init__(self, cfg: TruncatedBPTTLMConfig): + super().__init__(cfg) + + if cfg.data_parallel_rank is None or cfg.data_parallel_size is None: + if torch.distributed.is_initialized(): + cfg.data_parallel_rank = dist_utils.get_data_parallel_rank() + cfg.data_parallel_size = dist_utils.get_data_parallel_world_size() + else: + cfg.data_parallel_rank = 0 + cfg.data_parallel_size = 1 + + # load the dictionary + paths = utils.split_paths(cfg.data) + assert len(paths) > 0 + self.dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) + logger.info("dictionary: {} types".format(len(self.dictionary))) + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + """Load a given dataset split (e.g., train, valid, test)""" + + # support sharded datasets + paths = utils.split_paths(self.cfg.data) + assert len(paths) > 0 + data_path = paths[(epoch - 1) % len(paths)] + split_path = os.path.join(data_path, split) + + # each element of *data* will be a tensorized line from the original + # text dataset, similar to ``open(split_path).readlines()`` + data = data_utils.load_indexed_dataset( + split_path, self.dictionary, combine=combine + ) + if data is None: + raise FileNotFoundError( + "Dataset not found: {} ({})".format(split, split_path) + ) + + # this is similar to ``data.view(-1).split(tokens_per_sample)`` + data = TokenBlockDataset( + data, + data.sizes, + block_size=self.cfg.tokens_per_sample, + pad=None, # unused + eos=None, # unused + break_mode="none", + ) + + self.datasets[split] = TruncatedBPTTDataset( + data=data, + bsz_per_shard=self.cfg.batch_size, + shard_id=self.cfg.data_parallel_rank, + num_shards=self.cfg.data_parallel_size, + ) + + def dataset(self, split): + return self.datasets[split] + + def get_batch_iterator( + self, dataset, num_workers=0, epoch=1, data_buffer_size=0, **kwargs + ): + return iterators.EpochBatchIterator( + dataset=dataset, + collate_fn=self._collate_fn, + num_workers=num_workers, + epoch=epoch, + buffer_size=data_buffer_size, + # we don't use the batching functionality from EpochBatchIterator; + # instead every item in *dataset* is a whole batch + batch_sampler=[[i] for i in range(len(dataset))], + disable_shuffling=True, + ) + + def _collate_fn(self, items: List[List[torch.Tensor]]): + # we don't use fairseq's batching functionality, so we expect a single + # Tensor of type List[torch.Tensor] + assert len(items) == 1 + + # item will have shape B x T (the last batch may have length < T) + id, item = items[0] + item = data_utils.collate_tokens(item, pad_idx=self.source_dictionary.pad()) + B, T = item.size() + + # shift item one position over and append a padding token for the target + target = torch.nn.functional.pad( + item[:, 1:], (0, 1, 0, 0), value=self.target_dictionary.pad() + ) + + # fairseq expects batches to have the following structure + return { + "id": torch.tensor([id]*item.size(0)), + "net_input": { + "src_tokens": item, + }, + "target": target, + "nsentences": item.size(0), + "ntokens": item.numel(), + } + + def build_dataset_for_inference( + self, src_tokens: List[torch.Tensor], src_lengths: List[int], **kwargs + ) -> torch.utils.data.Dataset: + eos = self.source_dictionary.eos() + dataset = TokenBlockDataset( + src_tokens, + src_lengths, + block_size=None, # ignored for "eos" break mode + pad=self.source_dictionary.pad(), + eos=eos, + break_mode="eos", + ) + + class Dataset(torch.utils.data.Dataset): + def __getitem__(self, i): + item = dataset[i] + if item[-1] == eos: + # remove eos to support generating with a prefix + item = item[:-1] + return (i, [item]) + + def __len__(self): + return len(dataset) + + return Dataset() + + def inference_step( + self, generator, models, sample, prefix_tokens=None, constraints=None + ): + with torch.no_grad(): + if constraints is not None: + raise NotImplementedError + + # SequenceGenerator doesn't use *src_tokens* directly, we need to + # pass the *prefix_tokens* argument instead. + if prefix_tokens is None and sample["net_input"]["src_tokens"].nelement(): + prefix_tokens = sample["net_input"]["src_tokens"] + + # begin generation with the end-of-sentence token + bos_token = self.source_dictionary.eos() + + return generator.generate( + models, sample, prefix_tokens=prefix_tokens, bos_token=bos_token + ) + + @property + def source_dictionary(self): + return self.dictionary + + @property + def target_dictionary(self): + return self.dictionary + + +class TruncatedBPTTDataset(torch.utils.data.Dataset): + def __init__( + self, + data: List[torch.Tensor], # ordered list of items + bsz_per_shard, # number of items processed per GPUs per forward + shard_id, # current GPU ID + num_shards, # number of GPUs + ): + super().__init__() + self.data = data + + def batchify(data, bsz): + # Work out how cleanly we can divide the dataset into bsz parts. + nbatch = data.size(0) // bsz + # Trim off any extra elements that wouldn't cleanly fit (remainders). + data = data.narrow(0, 0, nbatch * bsz) + # Evenly divide the data across the bsz batches. + data = data.view(bsz, -1).contiguous() + return data + + # total number of sequences processed by all GPUs in each forward pass + global_batch_size = bsz_per_shard * num_shards + + """ + With a 16 item dataset, bsz_per_shard=2 and num_shards=3, + *indices* might look like: + + indices = [[0, 1], + [2, 3], + [4, 5], + [6, 7], + [8, 9], + [10, 11]] + + The size of the TruncatedBPTTDataset instance will be 2, + and shard 1 will see items: + + [(0, [data[4], data[6]]), + (1, [data[5], data[7]])] + """ + indices = batchify(torch.arange(len(data)), global_batch_size) + assert indices.size(0) == global_batch_size + + self.my_indices = indices[ + shard_id * bsz_per_shard : (shard_id + 1) * bsz_per_shard + ] + assert self.my_indices.size(0) == bsz_per_shard + + def __len__(self): + return self.my_indices.size(1) + + def __getitem__(self, i) -> Tuple[int, List[torch.Tensor]]: + return (i, [self.data[idx] for idx in self.my_indices[:, i]]) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index f62973a534..d34f09d1d7 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -7,6 +7,7 @@ import os import warnings from argparse import Namespace +from typing import List import torch from fairseq import metrics, search, tokenizer, utils @@ -437,6 +438,11 @@ def valid_step(self, sample, model, criterion): loss, sample_size, logging_output = criterion(model, sample) return loss, sample_size, logging_output + def build_dataset_for_inference( + self, src_tokens: List[torch.Tensor], src_lengths: List[int], **kwargs + ) -> torch.utils.data.Dataset: + raise NotImplementedError + def inference_step( self, generator, models, sample, prefix_tokens=None, constraints=None ): diff --git a/tests/test_binaries.py b/tests/test_binaries.py index dae38dda0c..4d3393ae40 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -25,6 +25,14 @@ ) +try: + import transformers # noqa + + has_hf_transformers = True +except ImportError: + has_hf_transformers = False + + class TestTranslation(unittest.TestCase): def setUp(self): logging.disable(logging.CRITICAL) @@ -963,6 +971,36 @@ def test_transformer_lm(self): ], ) + def test_transformer_lm_with_adaptive_softmax(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_transformer_lm_with_adaptive_softmax") as data_dir: + create_dummy_data(data_dir) + preprocess_lm_data(data_dir) + train_language_model( + data_dir, + "transformer_lm", + [ + "--add-bos-token", + "--criterion", + "adaptive_loss", + "--adaptive-softmax-cutoff", + "5,10,15", + ], + run_validation=True, + ) + eval_lm_main(data_dir) + generate_main( + data_dir, + [ + "--task", + "language_modeling", + "--sample-break-mode", + "eos", + "--tokens-per-sample", + "500", + ], + ) + def test_lightconv_lm(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_lightconv_lm") as data_dir: @@ -1035,6 +1073,35 @@ def test_lstm_lm_residuals(self): ], ) + @unittest.skipIf(not has_hf_transformers, "skip test if transformers is missing") + def test_transformer_xl_bptt_lm(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_transformer_xl_bptt_lm") as data_dir: + create_dummy_data(data_dir) + preprocess_lm_data(data_dir) + task_flags = [ + "--user-dir", + "examples/truncated_bptt", + "--task", + "truncated_bptt_lm", + "--batch-size", + "2", + "--tokens-per-sample", + "50", + ] + train_language_model( + data_dir=data_dir, + arch="transformer_xl", + extra_flags=task_flags + [ + "--n-layer", + "2", + ], + task="truncated_bptt_lm", + run_validation=True, + extra_valid_flags=task_flags, + ) + eval_lm_main(data_dir, extra_flags=task_flags) + class TestMaskedLanguageModel(unittest.TestCase): def setUp(self): @@ -1478,13 +1545,15 @@ def train_roberta_head(data_dir, arch, num_classes=2, extra_flags=None): train.main(train_args) -def train_language_model(data_dir, arch, extra_flags=None, run_validation=False): +def train_language_model( + data_dir, arch, extra_flags=None, run_validation=False, extra_valid_flags=None, task="language_modeling" +): train_parser = options.get_training_parser() train_args = options.parse_args_and_arch( train_parser, [ "--task", - "language_modeling", + task, data_dir, "--arch", arch, @@ -1492,10 +1561,6 @@ def train_language_model(data_dir, arch, extra_flags=None, run_validation=False) "adam", "--lr", "0.0001", - "--criterion", - "adaptive_loss", - "--adaptive-softmax-cutoff", - "5,10,15", "--max-tokens", "500", "--tokens-per-sample", @@ -1523,7 +1588,7 @@ def train_language_model(data_dir, arch, extra_flags=None, run_validation=False) validate_parser, [ "--task", - "language_modeling", + task, data_dir, "--path", os.path.join(data_dir, "checkpoint_last.pt"), @@ -1534,12 +1599,13 @@ def train_language_model(data_dir, arch, extra_flags=None, run_validation=False) "--no-progress-bar", "--num-workers", "0", - ], + ] + + (extra_valid_flags or []), ) validate.main(validate_args) -def eval_lm_main(data_dir): +def eval_lm_main(data_dir, extra_flags=None): eval_lm_parser = options.get_eval_lm_parser() eval_lm_args = options.parse_args_and_arch( eval_lm_parser, @@ -1550,7 +1616,7 @@ def eval_lm_main(data_dir): "--no-progress-bar", "--num-workers", "0", - ], + ] + (extra_flags or []), ) eval_lm.main(eval_lm_args) From dc1eaf3dde83494037a8727de5897a43c46e0b46 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 16 Nov 2020 09:10:56 -0800 Subject: [PATCH 052/774] Remove unused hf/transformers submodule (#1435) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1435 Reviewed By: huihuifan Differential Revision: D24973816 Pulled By: myleott fbshipit-source-id: 1565dfc3f7e8db65ded4af92d1afd7aff8d19294 --- .gitmodules | 4 ---- fairseq/models/huggingface/transformers | 1 - 2 files changed, 5 deletions(-) delete mode 160000 fairseq/models/huggingface/transformers diff --git a/.gitmodules b/.gitmodules index df0d3d3071..07a55d45d4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "fairseq/models/huggingface/transformers"] - path = fairseq/models/huggingface/transformers - url = https://github.com/myleott/transformers.git - branch = fairseq [submodule "fairseq/model_parallel/megatron"] path = fairseq/model_parallel/megatron url = https://github.com/ngoyal2707/Megatron-LM diff --git a/fairseq/models/huggingface/transformers b/fairseq/models/huggingface/transformers deleted file mode 160000 index 839f8a563c..0000000000 --- a/fairseq/models/huggingface/transformers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 839f8a563cefcb7f2048b310024c217e7829a198 From 52d774cda9e8926ab42210da05715789fc567d8e Mon Sep 17 00:00:00 2001 From: alexeib Date: Mon, 16 Nov 2020 11:08:13 -0800 Subject: [PATCH 053/774] fix gumbel temp arg (#1438) Summary: Fix #2897 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1438 Reviewed By: myleott Differential Revision: D24992106 Pulled By: alexeib fbshipit-source-id: 0cb15c2e865c3e8f7950e8f5e6c54c5000637af2 --- fairseq/modules/gumbel_vector_quantizer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fairseq/modules/gumbel_vector_quantizer.py b/fairseq/modules/gumbel_vector_quantizer.py index 47657bb0ab..7113438888 100644 --- a/fairseq/modules/gumbel_vector_quantizer.py +++ b/fairseq/modules/gumbel_vector_quantizer.py @@ -73,7 +73,10 @@ def block(input_dim, output_dim): nn.init.normal_(self.weight_proj.weight, mean=0, std=1) nn.init.zeros_(self.weight_proj.bias) - assert len(temp) == 3, temp + if isinstance(temp, str): + import ast + temp = ast.literal_eval(temp) + assert len(temp) == 3, f"{temp}, {len(temp)}" self.max_temp, self.min_temp, self.temp_decay = temp self.curr_temp = self.max_temp From add65adcc53a927f99a717d90a9672765237d937 Mon Sep 17 00:00:00 2001 From: Juan Miguel Pino Date: Mon, 16 Nov 2020 12:41:26 -0800 Subject: [PATCH 054/774] Replace encoder output type (#1281) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1281 The PyTorch Mobile lite interpreter does not support NamedTuple creation in forward. One workaround is to replace NamedTuple with a custom class that inherits nn.Module. This class could be initialized in `__init__` and updated in forward. However, lite interpreter does not support list construction with custom classes. So the final solution is to replace the NamedTuple with a dictionary. We cannot have mixed value types in that dictionary, otherwise, this breaks TorchScript export. So the type is List[Tensor] and an empty list corresponds to having a value of None. Reviewed By: myleott Differential Revision: D23752010 fbshipit-source-id: 0b152a534a165ce4f84bd4f580d7f29145cfd264 --- .../pointer_generator_src/transformer_pg.py | 18 +-- .../mean_pool_gating_network.py | 10 +- fairseq/models/nat/levenshtein_transformer.py | 13 +- .../nat/nonautoregressive_transformer.py | 34 +++-- fairseq/models/transformer.py | 116 +++++++++--------- fairseq/sequence_generator.py | 9 +- 6 files changed, 114 insertions(+), 86 deletions(-) diff --git a/examples/pointer_generator/pointer_generator_src/transformer_pg.py b/examples/pointer_generator/pointer_generator_src/transformer_pg.py index 079fdda581..fb40a80836 100644 --- a/examples/pointer_generator/pointer_generator_src/transformer_pg.py +++ b/examples/pointer_generator/pointer_generator_src/transformer_pg.py @@ -185,14 +185,14 @@ def forward(self, src_tokens, src_lengths, **kwargs): `(batch, src_len)` """ encoder_out = super().forward(src_tokens, src_lengths, **kwargs) - return EncoderOut( - encoder_out=encoder_out.encoder_out, # T x B x C - encoder_padding_mask=encoder_out.encoder_padding_mask, # B x T - encoder_embedding=encoder_out.encoder_embedding, # B x T x C - encoder_states=encoder_out.encoder_states, # List[T x B x C] - src_tokens=src_tokens, # B x T - src_lengths=None, - ) + return { + "encoder_out": encoder_out["encoder_out"], # T x B x C + "encoder_padding_mask": encoder_out["encoder_padding_mask"], # B x T + "encoder_embedding": encoder_out["encoder_embedding"], # B x T x C + "encoder_states": encoder_out["encoder_states"], # List[T x B x C] + "src_tokens": [src_tokens], # B x T + "src_lengths": [], + } class TransformerPointerGeneratorDecoder(TransformerDecoder): @@ -284,7 +284,7 @@ def forward( predictors = torch.cat((prev_output_embed, x), 2) p_gens = self.project_p_gens(predictors) p_gens = torch.sigmoid(p_gens) - x = self.output_layer(x, extra["attn"][0], encoder_out.src_tokens, p_gens) + x = self.output_layer(x, extra["attn"][0], encoder_out["src_tokens"][0], p_gens) return x, extra def output_layer(self, features, attn, src_tokens, p_gens, **kwargs): diff --git a/examples/translation_moe/translation_moe_src/mean_pool_gating_network.py b/examples/translation_moe/translation_moe_src/mean_pool_gating_network.py index 484b6ac912..efc7ae40bf 100644 --- a/examples/translation_moe/translation_moe_src/mean_pool_gating_network.py +++ b/examples/translation_moe/translation_moe_src/mean_pool_gating_network.py @@ -26,15 +26,15 @@ def __init__(self, embed_dim, num_experts, dropout=None): def forward(self, encoder_out): if not ( - hasattr(encoder_out, "encoder_out") - and hasattr(encoder_out, "encoder_padding_mask") - and encoder_out.encoder_out.size(2) == self.embed_dim + "encoder_out" in encoder_out + and "encoder_padding_mask" in encoder_out + and encoder_out["encoder_out"][0].size(2) == self.embed_dim ): raise ValueError("Unexpected format for encoder_out") # mean pooling over time - encoder_padding_mask = encoder_out.encoder_padding_mask # B x T - encoder_out = encoder_out.encoder_out.transpose(0, 1) # B x T x C + encoder_padding_mask = encoder_out["encoder_padding_mask"][0] # B x T + encoder_out = encoder_out["encoder_out"][0].transpose(0, 1) # B x T x C if encoder_padding_mask is not None: encoder_out = encoder_out.clone() # required because of transpose above encoder_out[encoder_padding_mask] = 0 diff --git a/fairseq/models/nat/levenshtein_transformer.py b/fairseq/models/nat/levenshtein_transformer.py index f7a3f003ca..17f1ee99be 100644 --- a/fairseq/models/nat/levenshtein_transformer.py +++ b/fairseq/models/nat/levenshtein_transformer.py @@ -256,7 +256,7 @@ def initialize_output_tokens(self, encoder_out, src_tokens): initial_output_scores = initial_output_tokens.new_zeros( *initial_output_tokens.size() - ).type_as(encoder_out.encoder_out) + ).type_as(encoder_out["encoder_out"][0]) return DecoderOut( output_tokens=initial_output_tokens, @@ -357,8 +357,15 @@ def extract_features( for _, layer in enumerate(layers[:early_exit]): x, attn, _ = layer( x, - encoder_out.encoder_out if encoder_out is not None else None, - encoder_out.encoder_padding_mask if encoder_out is not None else None, + encoder_out["encoder_out"][0] + if (encoder_out is not None and len(encoder_out["encoder_out"]) > 0) + else None, + encoder_out["encoder_padding_mask"][0] + if ( + encoder_out is not None + and len(encoder_out["encoder_padding_mask"]) > 0 + ) + else None, self_attn_mask=None, self_attn_padding_mask=decoder_padding_mask, ) diff --git a/fairseq/models/nat/nonautoregressive_transformer.py b/fairseq/models/nat/nonautoregressive_transformer.py index 735297fc29..d114202d25 100644 --- a/fairseq/models/nat/nonautoregressive_transformer.py +++ b/fairseq/models/nat/nonautoregressive_transformer.py @@ -163,7 +163,7 @@ def initialize_output_tokens(self, encoder_out, src_tokens): initial_output_scores = initial_output_tokens.new_zeros( *initial_output_tokens.size() - ).type_as(encoder_out.encoder_out) + ).type_as(encoder_out["encoder_out"][0]) return DecoderOut( output_tokens=initial_output_tokens, @@ -233,8 +233,11 @@ def forward(self, normalize, encoder_out, prev_output_tokens, step=0, **unused): @ensemble_decoder def forward_length(self, normalize, encoder_out): - enc_feats = encoder_out.encoder_out # T x B x C - src_masks = encoder_out.encoder_padding_mask # B x T or None + enc_feats = encoder_out["encoder_out"][0] # T x B x C + if len(encoder_out["encoder_padding_mask"]) > 0: + src_masks = encoder_out["encoder_padding_mask"][0] # B x T + else: + src_masks = None enc_feats = _mean_pooling(enc_feats, src_masks) if self.sg_length_pred: enc_feats = enc_feats.detach() @@ -264,8 +267,11 @@ def extract_features( """ # embedding if embedding_copy: - src_embd = encoder_out.encoder_embedding - src_mask = encoder_out.encoder_padding_mask + src_embd = encoder_out["encoder_embedding"][0] + if len(encoder_out["encoder_padding_mask"]) > 0: + src_mask = encoder_out["encoder_padding_mask"][0] + else: + src_mask = None src_mask = ( ~src_mask if src_mask is not None @@ -297,8 +303,15 @@ def extract_features( x, attn, _ = layer( x, - encoder_out.encoder_out if encoder_out is not None else None, - encoder_out.encoder_padding_mask if encoder_out is not None else None, + encoder_out["encoder_out"][0] + if (encoder_out is not None and len(encoder_out["encoder_out"]) > 0) + else None, + encoder_out["encoder_padding_mask"][0] + if ( + encoder_out is not None + and len(encoder_out["encoder_padding_mask"]) > 0 + ) + else None, self_attn_mask=None, self_attn_padding_mask=decoder_padding_mask, ) @@ -353,8 +366,11 @@ def forward_copying_source(self, src_embeds, src_masks, tgt_masks): return copied_embedding def forward_length_prediction(self, length_out, encoder_out, tgt_tokens=None): - enc_feats = encoder_out.encoder_out # T x B x C - src_masks = encoder_out.encoder_padding_mask # B x T or None + enc_feats = encoder_out["encoder_out"][0] # T x B x C + if len(encoder_out["encoder_padding_mask"]) > 0: + src_masks = encoder_out["encoder_padding_mask"][0] # B x T + else: + src_masks = None if self.pred_length_offset: if src_masks is None: src_lengs = enc_feats.new_ones(enc_feats.size(1)).fill_( diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 7614c33f74..70920ed779 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -16,7 +16,6 @@ register_model, register_model_architecture, ) -from fairseq.models.fairseq_encoder import EncoderOut from fairseq.modules import ( AdaptiveSoftmax, FairseqDropout, @@ -425,7 +424,7 @@ def forward( # compute padding mask encoder_padding_mask = src_tokens.eq(self.padding_idx) - encoder_states = [] if return_all_hiddens else None + encoder_states = [] # encoder layers for layer in self.layers: @@ -437,17 +436,21 @@ def forward( if self.layer_norm is not None: x = self.layer_norm(x) - return EncoderOut( - encoder_out=x, # T x B x C - encoder_padding_mask=encoder_padding_mask, # B x T - encoder_embedding=encoder_embedding, # B x T x C - encoder_states=encoder_states, # List[T x B x C] - src_tokens=None, - src_lengths=None, - ) + # The Pytorch Mobile lite interpreter does not supports returning NamedTuple in + # `foward` so we use a dictionary instead. + # TorchScript does not support mixed values so the values are all lists. + # The empty list is equivalent to None. + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [encoder_padding_mask], # B x T + "encoder_embedding": [encoder_embedding], # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } @torch.jit.export - def reorder_encoder_out(self, encoder_out: EncoderOut, new_order): + def reorder_encoder_out(self, encoder_out: Dict[str, List[Tensor]], new_order): """ Reorder encoder output according to *new_order*. @@ -458,50 +461,46 @@ def reorder_encoder_out(self, encoder_out: EncoderOut, new_order): Returns: *encoder_out* rearranged according to *new_order* """ - """ - Since encoder_padding_mask and encoder_embedding are both of type - Optional[Tensor] in EncoderOut, they need to be copied as local - variables for Torchscript Optional refinement - """ - encoder_padding_mask: Optional[Tensor] = encoder_out.encoder_padding_mask - encoder_embedding: Optional[Tensor] = encoder_out.encoder_embedding + if len(encoder_out["encoder_out"]) == 0: + new_encoder_out = [] + else: + new_encoder_out = [encoder_out["encoder_out"][0].index_select(1, new_order)] + if len(encoder_out["encoder_padding_mask"]) == 0: + new_encoder_padding_mask = [] + else: + new_encoder_padding_mask = [ + encoder_out["encoder_padding_mask"][0].index_select(0, new_order) + ] + if len(encoder_out["encoder_embedding"]) == 0: + new_encoder_embedding = [] + else: + new_encoder_embedding = [ + encoder_out["encoder_embedding"][0].index_select(0, new_order) + ] - new_encoder_out = ( - encoder_out.encoder_out - if encoder_out.encoder_out is None - else encoder_out.encoder_out.index_select(1, new_order) - ) - new_encoder_padding_mask = ( - encoder_padding_mask - if encoder_padding_mask is None - else encoder_padding_mask.index_select(0, new_order) - ) - new_encoder_embedding = ( - encoder_embedding - if encoder_embedding is None - else encoder_embedding.index_select(0, new_order) - ) - src_tokens = encoder_out.src_tokens - if src_tokens is not None: - src_tokens = src_tokens.index_select(0, new_order) + if len(encoder_out["src_tokens"]) == 0: + src_tokens = [] + else: + src_tokens = [(encoder_out["src_tokens"][0]).index_select(0, new_order)] - src_lengths = encoder_out.src_lengths - if src_lengths is not None: - src_lengths = src_lengths.index_select(0, new_order) + if len(encoder_out["src_lengths"]) == 0: + src_lengths = [] + else: + src_lengths = [(encoder_out["src_lengths"][0]).index_select(0, new_order)] - encoder_states = encoder_out.encoder_states - if encoder_states is not None: + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: for idx, state in enumerate(encoder_states): encoder_states[idx] = state.index_select(1, new_order) - return EncoderOut( - encoder_out=new_encoder_out, # T x B x C - encoder_padding_mask=new_encoder_padding_mask, # B x T - encoder_embedding=new_encoder_embedding, # B x T x C - encoder_states=encoder_states, # List[T x B x C] - src_tokens=src_tokens, # B x T - src_lengths=src_lengths, # B x 1 - ) + return { + "encoder_out": new_encoder_out, # T x B x C + "encoder_padding_mask": new_encoder_padding_mask, # B x T + "encoder_embedding": new_encoder_embedding, # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": src_tokens, # B x T + "src_lengths": src_lengths, # B x 1 + } def max_positions(self): """Maximum input length supported by the encoder.""" @@ -664,7 +663,7 @@ def build_decoder_layer(self, args, no_encoder_attn=False): def forward( self, prev_output_tokens, - encoder_out: Optional[EncoderOut] = None, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, features_only: bool = False, full_context_alignment: bool = False, @@ -706,7 +705,7 @@ def forward( def extract_features( self, prev_output_tokens, - encoder_out: Optional[EncoderOut] = None, + encoder_out: Optional[Dict[str, List[Tensor]]], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, full_context_alignment: bool = False, alignment_layer: Optional[int] = None, @@ -723,14 +722,14 @@ def extract_features( """ A scriptable subclass of this class has an extract_features method and calls - super().extract_features, but super() is not supported in torchscript. Aa copy of + super().extract_features, but super() is not supported in torchscript. A copy of this function is made to be used in the subclass instead. """ def extract_features_scriptable( self, prev_output_tokens, - encoder_out: Optional[EncoderOut] = None, + encoder_out: Optional[Dict[str, List[Tensor]]], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, full_context_alignment: bool = False, alignment_layer: Optional[int] = None, @@ -807,8 +806,15 @@ def extract_features_scriptable( x, layer_attn, _ = layer( x, - encoder_out.encoder_out if encoder_out is not None else None, - encoder_out.encoder_padding_mask if encoder_out is not None else None, + encoder_out["encoder_out"][0] + if (encoder_out is not None and len(encoder_out["encoder_out"]) > 0) + else None, + encoder_out["encoder_padding_mask"][0] + if ( + encoder_out is not None + and len(encoder_out["encoder_padding_mask"]) > 0 + ) + else None, incremental_state, self_attn_mask=self_attn_mask, self_attn_padding_mask=self_attn_padding_mask, diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 603c5b6821..47a20296cf 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -11,7 +11,6 @@ from fairseq import search, utils from fairseq.data import data_utils from fairseq.models import FairseqIncrementalDecoder -from fairseq.models.fairseq_encoder import EncoderOut from torch import Tensor @@ -806,13 +805,13 @@ def forward_encoder(self, net_input: Dict[str, Tensor]): def forward_decoder( self, tokens, - encoder_outs: List[EncoderOut], + encoder_outs: List[Dict[str, List[Tensor]]], incremental_states: List[Dict[str, Dict[str, Optional[Tensor]]]], temperature: float = 1.0, ): log_probs = [] avg_attn: Optional[Tensor] = None - encoder_out: Optional[EncoderOut] = None + encoder_out: Optional[Dict[str, List[Tensor]]] = None for i, model in enumerate(self.models): if self.has_encoder(): encoder_out = encoder_outs[i] @@ -868,7 +867,7 @@ def forward_decoder( return avg_probs, avg_attn @torch.jit.export - def reorder_encoder_out(self, encoder_outs: Optional[List[EncoderOut]], new_order): + def reorder_encoder_out(self, encoder_outs: Optional[List[Dict[str, List[Tensor]]]], new_order): """ Reorder encoder output according to *new_order*. @@ -879,7 +878,7 @@ def reorder_encoder_out(self, encoder_outs: Optional[List[EncoderOut]], new_orde Returns: *encoder_out* rearranged according to *new_order* """ - new_outs: List[EncoderOut] = [] + new_outs: List[Dict[str, List[Tensor]]] = [] if not self.has_encoder(): return new_outs for i, model in enumerate(self.models): From d7dd683b3bebcd3b3249db44d7faa7b670e44b8f Mon Sep 17 00:00:00 2001 From: Yuqing Tang Date: Mon, 16 Nov 2020 14:03:25 -0800 Subject: [PATCH 055/774] Add option to skip virtual epoch Summary: The current translation_multi_simple_epoch will add extrac layer of virtual epoch abstracts to load part of data and start training earlier. However, for smaller dataset this is not necessary. This diff makes it skip virtual epoch layer if --virtual-epoch-size is not specified. Reviewed By: pipibjc Differential Revision: D24962835 fbshipit-source-id: 7de4293a6996ed075a1ed0c1ff2de94c8ae3df14 --- .../multilingual/multilingual_data_manager.py | 37 ++++++++++++- .../tasks/translation_multi_simple_epoch.py | 18 ++++--- tests/test_binaries.py | 52 +++++++++++++++++++ 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/fairseq/data/multilingual/multilingual_data_manager.py b/fairseq/data/multilingual/multilingual_data_manager.py index 8c14f4e3ad..21fb23c047 100644 --- a/fairseq/data/multilingual/multilingual_data_manager.py +++ b/fairseq/data/multilingual/multilingual_data_manager.py @@ -236,7 +236,7 @@ def add_args(parser): ) parser.add_argument( "--virtual-epoch-size", - default=1000000, + default=None, type=int, help="virtual epoch size to speed up data loading", ) @@ -1040,3 +1040,38 @@ def load_sampled_multi_epoch_dataset( ) else: return self.load_into_concat_dataset(split, datasets, data_param_list) + + def load_sampled_multi_dataset( + self, split, training, epoch=0, combine=False, shard_epoch=None, **kwargs + ): + datasets, data_param_list = self.load_split_datasets( + split, training, epoch, combine, shard_epoch=shard_epoch, **kwargs + ) + if training and split == getattr(self.args, "train_subset", None): + sample_ratios = self.get_sampling_ratios(data_param_list, datasets, epoch) + return SampledMultiDataset( + OrderedDict(datasets), + epoch=epoch, + # valid and test datasets will be degerate to concating datasets: + sampling_ratios=sample_ratios, + eval_key=None, + collate_format=CollateFormat.single, + virtual_size=self.args.virtual_data_size, + split=split, + # if not using lang_tok altering, simplified to use the same collater + shared_collater=self._shared_collater(), + ) + else: + return self.load_into_concat_dataset(split, datasets, data_param_list) + + def load_dataset( + self, split, training, epoch=0, combine=False, shard_epoch=None, **kwargs + ): + if self.args.virtual_epoch_size is None: + return self.load_sampled_multi_dataset( + split, training, epoch, combine, shard_epoch, **kwargs + ) + else: + return self.load_sampled_multi_epoch_dataset( + split, training, epoch, combine, shard_epoch, **kwargs + ) diff --git a/fairseq/tasks/translation_multi_simple_epoch.py b/fairseq/tasks/translation_multi_simple_epoch.py index d871502a2c..34af9bf4a3 100644 --- a/fairseq/tasks/translation_multi_simple_epoch.py +++ b/fairseq/tasks/translation_multi_simple_epoch.py @@ -138,12 +138,16 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): """ if split in self.datasets: dataset = self.datasets[split] - if self.has_sharded_data(split) and dataset.load_next_shard: - shard_epoch = dataset.shard_epoch - else: - # no need to load next shard so skip loading - # also this avoid always loading from beginning of the data - return + if self.has_sharded_data(split): + if self.args.virtual_epoch_size is not None: + if dataset.load_next_shard: + shard_epoch = dataset.shard_epoch + else: + # no need to load next shard so skip loading + # also this avoid always loading from beginning of the data + return + else: + shard_epoch = epoch else: # estimate the shard epoch from virtual data size and virtual epoch size shard_epoch = self.data_manager.estimate_global_pass_epoch(epoch) @@ -153,7 +157,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): del self.datasets[split] logger.info("old dataset deleted manually") logger.info(f"mem usage: {data_utils.get_mem_usage()}") - self.datasets[split] = self.data_manager.load_sampled_multi_epoch_dataset( + self.datasets[split] = self.data_manager.load_dataset( split, self.training, epoch=epoch, diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 4d3393ae40..6dd95cb4a5 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -433,6 +433,58 @@ def test_translation_multi_simple_epoch(self): + dec_ltok_flag, ) + def test_translation_multi_simple_epoch_no_vepoch(self): + # test with all combinations of encoder/decoder lang tokens + with contextlib.redirect_stdout(StringIO()): + enc_ltok_flag = ["--encoder-langtok", "src"] + dec_ltok_flag = ["--decoder-langtok"] + with tempfile.TemporaryDirectory( + "test_translation_multi_simple_epoch_dict" + ) as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data( + data_dir, extra_flags=[] + ) + train_translation_model( + data_dir, + arch="transformer", + task="translation_multi_simple_epoch", + extra_flags=[ + "--encoder-layers", + "2", + "--decoder-layers", + "2", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--sampling-method", + "temperature", + "--sampling-temperature", + "1.5", + ] + + enc_ltok_flag + + dec_ltok_flag, + lang_flags=["--lang-pairs", "in-out"], + run_validation=True, + extra_valid_flags=enc_ltok_flag + dec_ltok_flag, + ) + generate_main( + data_dir, + extra_flags=[ + "--task", + "translation_multi_simple_epoch", + "--lang-pairs", + "in-out", + "--source-lang", + "in", + "--target-lang", + "out", + ] + + enc_ltok_flag + + dec_ltok_flag, + ) + def test_translation_multi_simple_epoch_dicts(self): # test with all combinations of encoder/decoder lang tokens with contextlib.redirect_stdout(StringIO()): From 0e13e2fddedbe569f33167c3aa090cc1aa28a499 Mon Sep 17 00:00:00 2001 From: alexeib Date: Tue, 17 Nov 2020 12:52:02 -0800 Subject: [PATCH 056/774] Wav2vec hydra (#1439) Summary: convert wav2vec 1.0 model to hydra Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1439 Reviewed By: myleott Differential Revision: D25010596 Pulled By: alexeib fbshipit-source-id: eb3ae81e7dad4789b217fca9bb4c6413835d75ab --- .../model/wav2vec/vq_wav2vec_gumbel.yaml | 5 + fairseq/criterions/wav2vec_criterion.py | 39 +- fairseq/models/wav2vec/wav2vec.py | 491 +++++++----------- fairseq/models/wav2vec/wav2vec2.py | 2 +- 4 files changed, 223 insertions(+), 314 deletions(-) create mode 100644 fairseq/config/model/wav2vec/vq_wav2vec_gumbel.yaml diff --git a/fairseq/config/model/wav2vec/vq_wav2vec_gumbel.yaml b/fairseq/config/model/wav2vec/vq_wav2vec_gumbel.yaml new file mode 100644 index 0000000000..ee1329bf46 --- /dev/null +++ b/fairseq/config/model/wav2vec/vq_wav2vec_gumbel.yaml @@ -0,0 +1,5 @@ +# @package _group_ +activation: gelu +vq_type: gumbel +vq_depth: 2 +combine_groups: true diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index 6ac7557dcc..3a58390088 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -4,33 +4,42 @@ # LICENSE file in the root directory of this source tree. import math +from dataclasses import dataclass, field +from typing import List, Optional import torch import torch.nn.functional as F from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass from fairseq.logging.meters import safe_round -@register_criterion("wav2vec") +@dataclass +class Wav2VecCriterionConfig(FairseqDataclass): + infonce: bool = field( + default=False, + metadata={ + "help": "if set, uses cross entropy instead of binary cross entropy (i.e. InfoNCE loss)" + }, + ) + loss_weights: Optional[List[float]] = field( + default=None, + metadata={"help": "weights for additional loss terms (not first one)"}, + ) + log_keys: List[str] = field( + default_factory=lambda: [], + metadata={"help": "output keys to log"}, + ) + + +@register_criterion("wav2vec", dataclass=Wav2VecCriterionConfig) class Wav2vecCriterion(FairseqCriterion): def __init__(self, task, infonce=False, loss_weights=None, log_keys=None): super().__init__(task) self.infonce = infonce - self.loss_weights = None if loss_weights is None else eval(loss_weights) - self.log_keys = [] if log_keys is None else eval(log_keys) - - @staticmethod - def add_args(parser): - """Add criterion-specific arguments to the parser.""" - # fmt: off - parser.add_argument('--infonce', action='store_true', - help='if set, uses cross entropy instead of binary cross entropy (i.e. InfoNCE loss)') - parser.add_argument('--loss-weights', type=str, default=None, - help='weights for additional loss terms (not first one)') - parser.add_argument('--log-keys', type=str, default=None, - help='output keys to log') - # fmt: on + self.loss_weights = loss_weights + self.log_keys = [] if log_keys is None else log_keys def forward(self, model, sample, reduce=True, log_pred=False): """Compute the loss for the given sample. diff --git a/fairseq/models/wav2vec/wav2vec.py b/fairseq/models/wav2vec/wav2vec.py index 772995b526..83b6461129 100644 --- a/fairseq/models/wav2vec/wav2vec.py +++ b/fairseq/models/wav2vec/wav2vec.py @@ -3,14 +3,18 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass, field import logging import math +from typing import Optional, Tuple +from omegaconf import II import sys import torch import torch.nn as nn import torch.nn.functional as F -from fairseq.models import BaseFairseqModel, register_model, register_model_architecture +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model from fairseq.modules import ( Fp32GroupNorm, Fp32LayerNorm, @@ -18,264 +22,208 @@ KmeansVectorQuantizer, TransposeLast, ) +from fairseq.tasks import FairseqTask from fairseq.utils import buffered_arange logger = logging.getLogger(__name__) -@register_model("wav2vec") -class Wav2VecModel(BaseFairseqModel): - @staticmethod - def add_args(parser): - """Add model-specific arguments to the parser.""" - parser.add_argument( - "--prediction-steps", - type=int, - metavar="N", - help="number of steps ahead to predict", - ) - parser.add_argument( - "--sample-distance", - type=int, - metavar="N", - help="sample distance from target. does not work properly with cross-sampling", - ) - parser.add_argument( - "--cross-sample-negatives", - type=int, - metavar="N", - help="num of cross sampled negatives", - ) - parser.add_argument( - "--num-negatives", type=int, metavar="N", help="number of negative examples" - ) - parser.add_argument( - "--conv-feature-layers", - type=str, - metavar="EXPR", - help="convolutional feature extraction layers [(dim, kernel_size, stride), ...]", - ) - parser.add_argument( - "--conv-aggregator-layers", - type=str, - metavar="EXPR", - help="convolutional feature extraction layers [(dim, kernel_size, stride), ...]", - ) - parser.add_argument( - "--dropout", - type=float, - metavar="D", - help="dropout to apply within the model", - ) - parser.add_argument( - "--dropout-features", - type=float, - metavar="D", - help="dropout to apply to the features", - ) - parser.add_argument( - "--dropout-agg", - type=float, - metavar="D", - help="dropout to apply after aggregation step", - ) - parser.add_argument( - "--encoder", type=str, choices=["cnn"], help="type of encoder to use" - ) - parser.add_argument( - "--aggregator", - type=str, - choices=["cnn", "gru"], - help="type of aggregator to use", - ) - parser.add_argument( - "--gru-dim", type=int, metavar="N", help="GRU dimensionality" - ) - - parser.add_argument( - "--no-conv-bias", - action="store_true", - help="if set, does not learn bias for conv layers", - ) - parser.add_argument( - "--agg-zero-pad", - action="store_true", - help="if set, zero pads in aggregator instead of repl pad", - ) +AGGREGATOR_CHOICES = ChoiceEnum(["cnn", "gru"]) +PROJECT_FEATURES_CHOICES = ChoiceEnum(["none", "same", "new"]) +ACTIVATION_CHOICES = ChoiceEnum(["relu", "gelu"]) +VQ_TYPE_CHOICES = ChoiceEnum(["none", "gumbel", "kmeans"]) - parser.add_argument( - "--skip-connections-feat", - action="store_true", - help="if set, adds skip connections to the feature extractor", - ) - parser.add_argument( - "--skip-connections-agg", - action="store_true", - help="if set, adds skip connections to the aggregator", - ) - parser.add_argument( - "--residual-scale", - type=float, - metavar="D", - help="scales residual by sqrt(value)", - ) - - parser.add_argument( - "--log-compression", - action="store_true", - help="if set, adds a log compression to feature extractor", - ) - - parser.add_argument( - "--balanced-classes", - action="store_true", - help="if set, loss is scaled to balance for number of negatives", - ) - parser.add_argument( - "--project-features", - choices=["none", "same", "new"], - help="if not none, features are projected using the (same or new) aggregator", - ) - - parser.add_argument( - "--non-affine-group-norm", - action="store_true", - help="if set, group norm is not affine", - ) - - parser.add_argument( - "--offset", - help="if set, introduces an offset from target to predictions. " - 'if set to "auto", it is computed automatically from the receptive field', - ) - - parser.add_argument( - "--activation", - type=str, - choices=["relu", "gelu"], - help="which activation function to use", - ) +@dataclass +class Wav2VecConfig(FairseqDataclass): + prediction_steps: int = field( + default=12, metadata={"help": "number of steps ahead to predict"} + ) + sample_distance: Optional[int] = field( + default=None, + metadata={ + "help": "sample distance from target. does not work properly with cross-sampling" + }, + ) + cross_sample_negatives: int = field( + default=0, metadata={"help": "num of cross sampled negatives"} + ) + num_negatives: int = field( + default=10, metadata={"help": "num of cross sampled negatives"} + ) + conv_feature_layers: str = field( + default="[(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1), (512, 1, 1)]", + metadata={ + "help": "convolutional feature extraction layers [(dim, kernel_size, stride), ...]" + }, + ) + conv_aggregator_layers: str = field( + default="[(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)]", + metadata={ + "help": "convolutional aggregator layers [(dim, kernel_size, stride), ...]" + }, + ) + dropout: float = field( + default=0.0, metadata={"help": "dropout to apply within the model"} + ) + dropout_features: float = field( + default=0.0, metadata={"help": "dropout to apply to the features"} + ) + dropout_agg: float = field( + default=0.0, metadata={"help": "dropout to apply after aggregation step"} + ) + aggregator: AGGREGATOR_CHOICES = field( + default="cnn", metadata={"help": "type of aggregator to use"} + ) + gru_dim: int = field(default=512, metadata={"help": "GRU dimensionality"}) + no_conv_bias: bool = field( + default=False, metadata={"help": "if set, does not learn bias for conv layers"} + ) + agg_zero_pad: bool = field( + default=False, + metadata={"help": "if set, zero pads in aggregator instead of repl pad"}, + ) + skip_connections_feat: bool = field( + default=False, + metadata={"help": "if set, adds skip connections to the feature extractor"}, + ) + skip_connections_agg: bool = field( + default=True, + metadata={"help": "if set, adds skip connections to the aggregator"}, + ) + residual_scale: float = field( + default=0.5, metadata={"help": "scales residual by sqrt(value)"} + ) + log_compression: bool = field( + default=True, + metadata={"help": "if set, adds a log compression to feature extractor"}, + ) + balanced_classes: bool = field( + default=False, + metadata={"help": "if set, loss is scaled to balance for number of negatives"}, + ) + project_features: PROJECT_FEATURES_CHOICES = field( + default="none", + metadata={ + "help": "if not none, features are projected using the (same or new) aggregator" + }, + ) + non_affine_group_norm: bool = field( + default=False, metadata={"help": "if set, group norm is not affine"} + ) + offset: str = field( + default="auto", + metadata={ + "help": "if set to 'auto', it is computed automatically from the receptive field, else set to int value" + }, + ) + activation: ACTIVATION_CHOICES = field( + default="relu", + metadata={ + "help": "if set to 'auto', it is computed automatically from the receptive field, else set to int value" + }, + ) + vq_type: VQ_TYPE_CHOICES = field( + default="none", metadata={"help": "which type of quantizer to use"} + ) + vq_vars: int = field( + default=320, + metadata={"help": "project to this many vector quantized variables per group"}, + ) + vq_groups: int = field( + default=2, metadata={"help": "number of groups of latent variables"} + ) + vq_dim: int = field( + default=0, + metadata={ + "help": "uses this dimensionality for quantized vectors. 0 to use model dim // groups" + }, + ) + vq_depth: int = field( + default=1, metadata={"help": "number of layers for vq weight projection"} + ) + combine_groups: bool = field( + default=False, metadata={"help": "if set, variables are shared among groups"} + ) + vq_temp: Tuple[float, float, float] = field( + default=(2.0, 0.5, 0.999995), + metadata={ + "help": "temperature for latent variable sampling with gumbel softmax. should be a tuple of 3 values (start, end, decay)" + }, + ) + vq_gamma: float = field( + default=0.25, + metadata={"help": "gamma parameter for kmeans style vector quantization"}, + ) + infonce: bool = II("criterion.infonce") - parser.add_argument( - "--vq-type", - type=str, - choices=["none", "gumbel", "kmeans"], - help="which type of quantizer to use", - ) - parser.add_argument( - "--vq-vars", - type=int, - metavar="N", - help="if set, project to this many vector quantized variables per group", - ) - parser.add_argument( - "--vq-groups", - type=int, - metavar="N", - help="number of groups of latent variables", - ) - parser.add_argument( - "--vq-dim", - type=int, - metavar="N", - help="uses this dimensionality for quantized vectors", - ) - parser.add_argument( - "--vq-depth", - type=int, - metavar="N", - help="number of layers for vq weight projection", - ) - parser.add_argument( - "--combine-groups", - action="store_true", - help="if set, variables are shared among groups", - ) - parser.add_argument( - "--vq-temp", - type=str, - metavar="TEMP", - help="temperature for latent variable sampling with gumbel softmax. should be a tuple of 3 values (start, end, decay)", - ) - parser.add_argument( - "--vq-gamma", - type=float, - metavar="D", - help="gamma parameter for kmeans style vector quantization", - ) +@register_model("wav2vec", dataclass=Wav2VecConfig) +class Wav2VecModel(BaseFairseqModel): @classmethod - def build_model(cls, args, task): + def build_model(cls, cfg: Wav2VecConfig, task: FairseqTask): """Build a new model instance.""" - # make sure all arguments are present in older models - base_wav2vec_architecture(args) - - model = Wav2VecModel(args) + model = Wav2VecModel(cfg) logger.info(model) return model - def __init__(self, args): + def __init__(self, cfg: Wav2VecConfig): super().__init__() - self.prediction_steps = args.prediction_steps - offset = args.offset + self.prediction_steps = cfg.prediction_steps + offset = cfg.offset - if args.activation == "relu": + if cfg.activation == "relu": activation = nn.ReLU() - elif args.activation == "gelu": + elif cfg.activation == "gelu": activation = nn.GELU() else: - raise Exception("unknown activation " + args.activation) - - if args.encoder == "cnn": - feature_enc_layers = eval(args.conv_feature_layers) - self.feature_extractor = ConvFeatureExtractionModel( - conv_layers=feature_enc_layers, - dropout=0.0, - log_compression=args.log_compression, - skip_connections=args.skip_connections_feat, - residual_scale=args.residual_scale, - non_affine_group_norm=args.non_affine_group_norm, - activation=activation, - ) - embed = feature_enc_layers[-1][0] - else: - raise Exception("unknown encoder type " + args.encoder) + raise Exception("unknown activation " + cfg.activation) + + feature_enc_layers = eval(cfg.conv_feature_layers) + self.feature_extractor = ConvFeatureExtractionModel( + conv_layers=feature_enc_layers, + dropout=0.0, + log_compression=cfg.log_compression, + skip_connections=cfg.skip_connections_feat, + residual_scale=cfg.residual_scale, + non_affine_group_norm=cfg.non_affine_group_norm, + activation=activation, + ) + embed = feature_enc_layers[-1][0] self.vector_quantizer = None - if args.vq_type == "gumbel": + if cfg.vq_type == "gumbel": self.vector_quantizer = GumbelVectorQuantizer( dim=embed, - num_vars=args.vq_vars, - temp=eval(args.vq_temp), - groups=args.vq_groups, - combine_groups=args.combine_groups, - vq_dim=args.vq_dim if args.vq_dim > 0 else embed, + num_vars=cfg.vq_vars, + temp=cfg.vq_temp, + groups=cfg.vq_groups, + combine_groups=cfg.combine_groups, + vq_dim=cfg.vq_dim if cfg.vq_dim > 0 else embed, time_first=False, activation=activation, - weight_proj_depth=args.vq_depth, + weight_proj_depth=cfg.vq_depth, weight_proj_factor=2, ) - elif args.vq_type == "kmeans": + elif cfg.vq_type == "kmeans": self.vector_quantizer = KmeansVectorQuantizer( dim=embed, - num_vars=args.vq_vars, - groups=args.vq_groups, - combine_groups=args.combine_groups, - vq_dim=args.vq_dim if args.vq_dim > 0 else embed, + num_vars=cfg.vq_vars, + groups=cfg.vq_groups, + combine_groups=cfg.combine_groups, + vq_dim=cfg.vq_dim if cfg.vq_dim > 0 else embed, time_first=False, - gamma=args.vq_gamma, + gamma=cfg.vq_gamma, ) else: assert ( - args.vq_type == "none" or args.vq_type is None + cfg.vq_type == "none" or cfg.vq_type is None ), "Unknown quantizer type" - if args.offset == "auto": - assert args.encoder == "cnn" + if cfg.offset == "auto": jin = 0 rin = 0 for _, k, stride in feature_enc_layers: @@ -291,34 +239,34 @@ def __init__(self, args): offset = int(offset) def make_aggregator(): - if args.aggregator == "cnn": - agg_layers = eval(args.conv_aggregator_layers) + if cfg.aggregator == "cnn": + agg_layers = eval(cfg.conv_aggregator_layers) agg_dim = agg_layers[-1][0] feature_aggregator = ConvAggegator( conv_layers=agg_layers, embed=embed, - dropout=args.dropout, - skip_connections=args.skip_connections_agg, - residual_scale=args.residual_scale, - non_affine_group_norm=args.non_affine_group_norm, - conv_bias=not args.no_conv_bias, - zero_pad=args.agg_zero_pad, + dropout=cfg.dropout, + skip_connections=cfg.skip_connections_agg, + residual_scale=cfg.residual_scale, + non_affine_group_norm=cfg.non_affine_group_norm, + conv_bias=not cfg.no_conv_bias, + zero_pad=cfg.agg_zero_pad, activation=activation, ) - elif args.aggregator == "gru": - agg_dim = args.gru_dim + elif cfg.aggregator == "gru": + agg_dim = cfg.gru_dim feature_aggregator = nn.Sequential( TransposeLast(), nn.GRU( input_size=embed, hidden_size=agg_dim, num_layers=1, - dropout=args.dropout, + dropout=cfg.dropout, ), TransposeLast(deconstruct_idx=0), ) else: - raise Exception("unknown aggregator type " + args.aggregator) + raise Exception("unknown aggregator type " + cfg.aggregator) return feature_aggregator, agg_dim @@ -327,24 +275,24 @@ def make_aggregator(): self.wav2vec_predictions = Wav2VecPredictionsModel( in_dim=agg_dim, out_dim=embed, - prediction_steps=args.prediction_steps, - n_negatives=args.num_negatives, - cross_sample_negatives=args.cross_sample_negatives, - sample_distance=args.sample_distance, - dropout=args.dropout, + prediction_steps=cfg.prediction_steps, + n_negatives=cfg.num_negatives, + cross_sample_negatives=cfg.cross_sample_negatives, + sample_distance=cfg.sample_distance, + dropout=cfg.dropout, offset=offset, - balanced_classes=args.balanced_classes, - infonce=args.infonce, + balanced_classes=cfg.balanced_classes, + infonce=cfg.infonce, ) - self.dropout_feats = nn.Dropout(p=args.dropout_features) - self.dropout_agg = nn.Dropout(p=args.dropout_agg) + self.dropout_feats = nn.Dropout(p=cfg.dropout_features) + self.dropout_agg = nn.Dropout(p=cfg.dropout_agg) - if args.project_features == "none": + if cfg.project_features == "none": self.project_features = None - elif args.project_features == "same": + elif cfg.project_features == "same": self.project_features = self.feature_aggregator - elif args.project_features == "new": + elif cfg.project_features == "new": self.project_features, _ = make_aggregator() def forward(self, source): @@ -680,56 +628,3 @@ def forward(self, x, y): labels = (labels, weights) return predictions, labels - - -@register_model_architecture("wav2vec", "wav2vec") -def base_wav2vec_architecture(args): - conv_feature_layers = "[(512, 10, 5)]" - conv_feature_layers += " + [(512, 8, 4)]" - conv_feature_layers += " + [(512, 4, 2)] * 3" - args.conv_feature_layers = getattr(args, "conv_feature_layers", conv_feature_layers) - - args.conv_aggregator_layers = getattr( - args, "conv_aggregator_layers", "[(512, 3, 1)] * 9" - ) - - args.prediction_steps = getattr(args, "prediction_steps", 12) - args.num_negatives = getattr(args, "num_negatives", 1) - args.sample_distance = getattr(args, "sample_distance", None) - args.cross_sample_negatives = getattr(args, "cross_sample_negatives", 0) - - args.dropout = getattr(args, "dropout", 0.0) - args.dropout_features = getattr(args, "dropout_features", 0.0) - args.dropout_agg = getattr(args, "dropout_agg", 0.0) - args.encoder = getattr(args, "encoder", "cnn") - args.aggregator = getattr(args, "aggregator", "cnn") - - args.skip_connections_feat = getattr(args, "skip_connections_feat", False) - args.skip_connections_agg = getattr(args, "skip_connections_agg", False) - args.residual_scale = getattr(args, "residual_scale", 0.5) - - args.gru_dim = getattr(args, "gru_dim", 512) - - args.no_conv_bias = getattr(args, "no_conv_bias", False) - args.agg_zero_pad = getattr(args, "agg_zero_pad", False) - - args.log_compression = getattr(args, "log_compression", False) - - args.balanced_classes = getattr(args, "balanced_classes", False) - args.infonce = getattr(args, "infonce", False) - args.project_features = getattr(args, "project_features", "none") - - args.non_affine_group_norm = getattr(args, "non_affine_group_norm", False) - - args.offset = getattr(args, "offset", "auto") - - args.activation = getattr(args, "activation", "relu") - - args.vq_type = getattr(args, "vq_type", "none") - args.vq_vars = getattr(args, "vq_vars", 320) - args.vq_groups = getattr(args, "vq_groups", 2) - args.vq_dim = getattr(args, "vq_dim", 0) - args.vq_depth = getattr(args, "vq_depth", 1) - args.combine_groups = getattr(args, "combine_groups", False) - args.vq_temp = getattr(args, "vq_temp", "(2.0, 0.5, 0.999995)") - args.vq_gamma = getattr(args, "vq_gamma", 0.25) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index e6fecdd4fe..a00dc4d915 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -14,7 +14,7 @@ from fairseq import utils from fairseq.data.data_utils import compute_mask_indices from fairseq.dataclass import ChoiceEnum, FairseqDataclass -from fairseq.models import BaseFairseqModel, register_model, register_model_architecture +from fairseq.models import BaseFairseqModel, register_model from fairseq.modules import ( Fp32GroupNorm, Fp32LayerNorm, From 43e379e59068fa472c847400b6c653c88b7ffd95 Mon Sep 17 00:00:00 2001 From: Shruti Bhosale Date: Tue, 17 Nov 2020 14:14:12 -0800 Subject: [PATCH 057/774] Fast Noisy Channel Online Decoding for Neural Machine Translation (#1436) Summary: This PR adds logic to generate translations using noisy channel decoding (i.e. with a channel model `P(source|target)` and language model `P(target)`, in addition to a direct model `P(target|source)` It also includes additional logic to make noisy channel decoding very fast, without much loss in accuracy. Most of the logic resides within `examples/fast_noisy_channel` - - `noisy_channel_translation.py`: Fairseq Task for noisy channel translation - `noisy_channel_sequence_generator.py`: Sequence Generator for noisy channel decoding - this contains the main logic for scoring the direct, channel and LM models at each step of beam search - `noisy_channel_beam_search.py`: A variant of beam search that chooses the top-K candidates based on the combined scores from the direct, channel and LM models TODO: add an integration test to ensure changes in the core fairseq files don't break the logic in fast_noisy_channel Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1436 Reviewed By: myleott, edunov Differential Revision: D24986498 Pulled By: shruti-bh fbshipit-source-id: 2ae3b7d68fe4a1cfb61493c363134ab7a16c8647 --- examples/fast_noisy_channel/README.md | 345 +++++++ examples/fast_noisy_channel/__init__.py | 8 + .../noisy_channel_beam_search.py | 71 ++ .../noisy_channel_sequence_generator.py | 842 ++++++++++++++++++ .../noisy_channel_translation.py | 127 +++ fairseq/data/dictionary.py | 3 +- 6 files changed, 1395 insertions(+), 1 deletion(-) create mode 100644 examples/fast_noisy_channel/README.md create mode 100644 examples/fast_noisy_channel/__init__.py create mode 100644 examples/fast_noisy_channel/noisy_channel_beam_search.py create mode 100644 examples/fast_noisy_channel/noisy_channel_sequence_generator.py create mode 100644 examples/fast_noisy_channel/noisy_channel_translation.py diff --git a/examples/fast_noisy_channel/README.md b/examples/fast_noisy_channel/README.md new file mode 100644 index 0000000000..a04151a796 --- /dev/null +++ b/examples/fast_noisy_channel/README.md @@ -0,0 +1,345 @@ +# Language Models not just for Pre-training: Fast Online Neural Noisy Channel Modeling + +## Introduction +- [Yee et al. (2019)](https://www.aclweb.org/anthology/D19-1571.pdf) introduce a simple and effective noisy channel modeling approach for neural machine translation. However, the noisy channel online decoding approach introduced in this paper is too slow to be practical. +- To address this, [Bhosale et al. (2020)](http://www.statmt.org/wmt20/pdf/2020.wmt-1.68.pdf) introduces 3 simple approximations to make this approach very fast and practical without much loss in accuracy. +- This README provides intructions on how to run online decoding or generation with the noisy channel modeling approach, including ways to make it very fast without much loss in accuracy. + +## Noisy Channel Modeling + +[Yee et al. (2019)](https://www.aclweb.org/anthology/D19-1571.pdf) applies the Bayes Rule to predict `P(y|x)`, the probability of the target `y` given the source `x`. +```P(y|x) = P(x|y) * P(y) / P(x)``` +- `P(x|y)` predicts the source `x` given the target `y` and is referred to as the **channel model** +- `P(y)` is a **language model** over the target `y` +- `P(x)` is generally not modeled since it is constant for all `y`. + +We use Transformer models to parameterize the direct model `P(y|x)`, the channel model `P(x|y)` and the language model `P(y)`. + +During online decoding with beam search, we generate the top `K2` candidates per beam and score them with the following linear combination of the channel model, the language model as well as the direct model scores. + +```(1 / t) * log(P(y|x) + (1 / s) * ( λ1 * log(P(x|y)) + λ2 * log(P(y) ) )``` +- `t` - Target Prefix Length +- `s` - Source Length +- `λ1` - Channel Model Weight +- `λ2` - Language Model Weight + +The top `beam_size` candidates based on the above combined scores are chosen to continue the beams in beam search. In beam search with a direct model alone, the scores from the direct model `P(y|x)` are used to choose the top candidates in beam search. + +This framework provides a great way to utlize strong target language models trained on large amounts of unlabeled data. Language models can prefer targets unrelated to the source, so we also need a channel model whose role is to ensure that the target preferred by the language model also translates back to the source. + +### Training Translation Models and Language Models + +For training Transformer models in fairseq for machine translation, refer to instructions [here](https://github.com/pytorch/fairseq/tree/master/examples/translation) + +For training Transformer models in fairseq for language modeling, refer to instructions [here](https://github.com/pytorch/fairseq/tree/master/examples/language_model) + +### Generation with Language Model for German-English translation with fairseq + +Here are instructions to generate using a direct model and a target-side language model. + +Note: +- Download and install fairseq as per instructions [here](https://github.com/pytorch/fairseq) +- Preprocess and binarize the dataset as per instructions in section [Test Data Preprocessing](#test-data-preprocessing) + +```sh +binarized_data=data_dir/binarized +direct_model=de_en_seed4.pt +lm_model=en_lm.pt +lm_data=lm_data +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/direct_models/seed4.pt -O ${direct_model} +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/transformer_lm.pt -O ${lm_model} +mkdir -p ${lm_data} +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/lm_dict/dict.txt -O ${lm_data}/dict.txt + +k2=10 +lenpen=0.16 +lm_wt=0.14 +fairseq-generate ${binarized_data} \ + --user-dir examples/fast_noisy_channel \ + --beam 5 \ + --path ${direct_model} \ + --lm-model ${lm_model} \ + --lm-data ${lm_data} \ + --k2 ${k2} \ + --combine-method lm_only \ + --task noisy_channel_translation \ + --lenpen ${lenpen} \ + --lm-wt ${lm_wt} \ + --gen-subset valid \ + --remove-bpe \ + --fp16 \ + --batch-size 10 +``` +### Noisy Channel Generation for German-English translation with fairseq + +Here are instructions for noisy channel generation with a direct model, channel model and language model as explained in section [Noisy Channel Modeling](#noisy-channel-modeling). + +Note: +- Download and install fairseq as per instructions [here](https://github.com/pytorch/fairseq) +- Preprocess and binarize the dataset as per instructions in section [Test Data Preprocessing](#test-data-preprocessing) + +```sh +binarized_data=data_dir/binarized +direct_model=de_en_seed4.pt +lm_model=en_lm.pt +lm_data=lm_data +ch_model=en_de.big.seed4.pt +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/direct_models/seed4.pt -O ${direct_model} +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/transformer_lm.pt -O ${lm_model} +mkdir -p ${lm_data} +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/lm_dict/dict.txt -O ${lm_data}/dict.txt +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/big.seed4.pt -O ${ch_model} + +k2=10 +lenpen=0.21 +lm_wt=0.50 +bw_wt=0.30 +fairseq-generate ${binarized_data} \ + --user-dir examples/fast_noisy_channel \ + --beam 5 \ + --path ${direct_model} \ + --lm-model ${lm_model} \ + --lm-data ${lm_data} \ + --channel-model ${ch_model} \ + --k2 ${k2} \ + --combine-method noisy_channel \ + --task noisy_channel_translation \ + --lenpen ${lenpen} \ + --lm-wt ${lm_wt} \ + --ch-wt ${bw_wt} \ + --gen-subset test \ + --remove-bpe \ + --fp16 \ + --batch-size 1 +``` +## Fast Noisy Channel Modeling + +[Bhosale et al. (2020)](http://www.statmt.org/wmt20/pdf/2020.wmt-1.68.pdf) introduces 3 approximations that speed up online noisy channel decoding - +- Smaller channel models (`Tranformer Base` with 1 encoder and decoder layer each vs. `Transformer Big`) + - This involves training a channel model that is possibly smaller and less accurate in terms of BLEU than a channel model of the same size as the direct model. + - Since the role of the channel model is mainly to assign low scores to generations from the language model if they don't translate back to the source, we may not need the most accurate channel model for this purpose. +- Smaller output vocabulary size for the channel model (~30,000 -> ~1000) + - The channel model doesn't need to score the full output vocabulary, it just needs to score the source tokens, which are completely known. + - This is specified using the arguments `--channel-scoring-type src_vocab --top-k-vocab 500` + - This means that the output vocabulary for the channel model will be the source tokens for all examples in the batch and the top-K most frequent tokens in the vocabulary + - This reduces the memory consumption needed to store channel model scores significantly +- Smaller number of candidates (`k2`) scored per beam + - This is specified by reducing the argument `--k2` + + +### Fast Noisy Channel Generation for German-English translation with fairseq + +Here are instructions for **fast** noisy channel generation with a direct model, channel model and language model as explained in section [Fast Noisy Channel Modeling](#fast-noisy-channel-modeling). The main differences are that we use a smaller channel model, reduce `--k2`, set `--channel-scoring-type src_vocab --top-k-vocab 500` and increase the `--batch-size`. + +Note: +- Download and install fairseq as per instructions [here](https://github.com/pytorch/fairseq) +- Preprocess and binarize the dataset as per instructions in section [Test Data Preprocessing](#test-data-preprocessing) + +```sh +binarized_data=data_dir/binarized +direct_model=de_en_seed4.pt +lm_model=en_lm.pt +lm_data=lm_data +small_ch_model=en_de.base_1_1.seed4.pt +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/direct_models/seed4.pt -O ${direct_model} +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/transformer_lm.pt -O ${lm_model} +mkdir -p ${lm_data} +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/lm_dict/dict.txt -O ${lm_data}/dict.txt +wget https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/base_1_1.seed4.pt -O ${small_ch_model} + +k2=3 +lenpen=0.23 +lm_wt=0.58 +bw_wt=0.26 +fairseq-generate ${binarized_data} \ + --user-dir examples/fast_noisy_channel \ + --beam 5 \ + --path ${direct_model} \ + --lm-model ${lm_model} \ + --lm-data ${lm_data} \ + --channel-model ${small_ch_model} \ + --k2 ${k2} \ + --combine-method noisy_channel \ + --task noisy_channel_translation \ + --lenpen ${lenpen} \ + --lm-wt ${lm_wt} \ + --ch-wt ${bw_wt} \ + --gen-subset test \ + --remove-bpe \ + --fp16 \ + --batch-size 50 \ + --channel-scoring-type src_vocab --top-k-vocab 500 +``` + +## Test Data Preprocessing + +For preprocessing and binarizing the test sets for Romanian-English and German-English translation, we use the following script - + +```sh +FAIRSEQ=/path/to/fairseq +cd $FAIRSEQ +SCRIPTS=$FAIRSEQ/mosesdecoder/scripts +if [ ! -d "${SCRIPTS}" ]; then + echo 'Cloning Moses github repository (for tokenization scripts)...' + git clone https://github.com/moses-smt/mosesdecoder.git +fi +TOKENIZER=$SCRIPTS/tokenizer/tokenizer.perl +NORMALIZE=$SCRIPTS/tokenizer/normalize-punctuation.perl + +s=de +t=en +test=wmt18 + +mkdir -p data_dir + +# Tokenization +if [ $s == "ro" ] ; then + # Note: Get normalise-romanian.py and remove-diacritics.py from + # https://github.com/rsennrich/wmt16-scripts/tree/master/preprocess + sacrebleu -t $test -l $s-$t --echo src | \ + $NORMALIZE -l $s | \ + python normalise-romanian.py | \ + python remove-diacritics.py | \ + $TOKENIZER -l $s -a -q > data_dir/$test.$s-$t.$s +else + sacrebleu -t $test -l $s-$t --echo src | perl $NORMALIZE -l $s | perl $TOKENIZER -threads 8 -a -l $s > data_dir/$test.$s-$t.$s +fi + +sacrebleu -t $test -l $s-$t --echo ref | perl $NORMALIZE -l $t | perl $TOKENIZER -threads 8 -a -l $t > data_dir/$test.$s-$t.$t + + +# Applying BPE +src_bpe_code=/path/to/source/language/bpe/code +tgt_bpe_code=/path/to/target/language/bpe/code +src_dict=/path/to/source/language/dict +tgt_dict=/path/to/target/language/dict + +FASTBPE=$FAIRSEQ/fastBPE +if [ ! -d "${FASTBPE}" ] ; then + git clone https://github.com/glample/fastBPE.git + # Follow compilation instructions at https://github.com/glample/fastBPE + g++ -std=c++11 -pthread -O3 fastBPE/main.cc -IfastBPE -o fast +fi + +${FASTBPE}/fast applybpe data_dir/bpe.$test.$s-$t.$s data_dir/$test.$s-$t.$s ${src_bpe_code} +${FASTBPE}/fast applybpe data_dir/bpe.$test.$s-$t.$s data_dir/$test.$s-$t.$s ${tgt_bpe_code} + +fairseq-preprocess -s $s -t $t \ + --testpref data_dir/bpe.$test.$s-$t \ + --destdir data_dir/binarized \ + --srcdict ${src_dict} \ + --tgtdict ${tgt_dict} +``` + +## Calculating BLEU + +```sh +DETOKENIZER=$SCRIPTS/tokenizer/detokenizer.perl +cat ${generation_output} | grep -P "^H" | sort -V | cut -f 3- | $DETOKENIZER -l $t -q -a | sacrebleu -t $test -l $s-$t +``` + + +## Romanian-English Translation + +The direct and channel models are trained using bitext data (WMT16) combined with backtranslated data (The monolingual data used for backtranslation comes from http://data.statmt.org/rsennrich/wmt16_backtranslations/ (Sennrich et al., 2016c)) + +The backtranslated data is generated using an ensemble of 3 English-Romanian models trained on bitext training data (WMT16) with unrestricted sampling. + +### BPE Codes and Dictionary + +We learn a joint BPE vocabulary of 18K types on the bitext training data which is used for both the source and target. +||Path| +|----------|------| +| BPE Code | [joint_bpe_18k](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/bpe_18k) | +| Dictionary | [dict](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/dict) | + +### Direct Models +For Ro-En with backtranslation, the direct and channel models use a Transformer-Big architecture. + +| Seed | Model | +|----|----| +| 2 | [ro_en_seed2.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/direct_models/seed2.pt) +| 4 | [ro_en_seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/direct_models/seed4.pt) +| 6 | [ro_en_seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/direct_models/seed6.pt) + +### Channel Models +For channel models, we follow the same steps as for the direct models. But backtranslated data is generated in the opposite direction using [this Romanian monolingual data](http://data.statmt.org/rsennrich/wmt16_backtranslations/). +The best lenpen, LM weight and CH weight are obtained by sweeping over the validation set (wmt16/dev) using beam 5. +| Model Size | Lenpen | LM Weight | CH Weight | Seed 2 | Seed 4 | Seed 6 | +|----|----|----|----|----|----|----| +| `big` | 0.84 | 0.64 | 0.56 | [big.seed2.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/channel_models/big.seed2.pt) | [big.seed2.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/channel_models/big.seed2.pt) | [big.seed2.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/channel_models/big.seed2.pt) | +| `base_1_1` | 0.63 | 0.40 | 0.37 | [base_1_1.seed2.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/channel_models/base_1_1.seed2.pt) | [base_1_1.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/channel_models/base_1_1.seed4.pt) | [base_1_1.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/channel_models/base_1_1.seed6.pt) | + +### Language Model +The model is trained on de-duplicated English Newscrawl data from 2007-2018 comprising 186 million sentences or 4.5B words after normalization and tokenization. +| | Path | +|----|----| +| `--lm-model` | [transformer_en_lm](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/lm_model/transformer_lm.pt) | +| `--lm-data` | [lm_data](https://dl.fbaipublicfiles.com/fast_noisy_channel/ro_en/lm_model/lm_dict) + +## German-English Translation + +### BPE Codes and Dictionaries + +| | Path| +|----------|------| +| Source BPE Code | [de_bpe_code_24K](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/de_bpe_code_24K) | +| Target BPE Code | [en_bpe_code_24K](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/en_bpe_code_24K) +| Source Dictionary | [de_dict](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/de_dict) | +| Target Dictionary | [en_dict](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/en_dict) | + +### Direct Models +We train on WMT’19 training data. Following [Ng et al., 2019](http://statmt.org/wmt19/pdf/53/WMT33.pdf), we apply language identification filtering and remove sentences longer than 250 tokens as well as sentence pairs with a source/target length ratio exceeding 1.5. This results in 26.8M sentence pairs. +We use the Transformer-Big architecture for the direct model. + +| Seed | Model | +|:----:|----| +| 4 | [de_en_seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/direct_models/seed4.pt) +| 5 | [de_en_seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/direct_models/seed5.pt) +| 6 | [de_en_seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/direct_models/seed6.pt) + +### Channel Models + +We train on WMT’19 training data. Following [Ng et al., 2019](http://statmt.org/wmt19/pdf/53/WMT33.pdf), we apply language identification filtering and remove sentences longer than 250 tokens as well as sentence pairs with a source/target length ratio exceeding 1.5. This results in 26.8M sentence pairs. + +| Model Size | Seed 4 | Seed 5 | Seed 6 | +|----|----|----|----| +| `big` | [big.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/big.seed4.pt) | [big.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/big.seed5.pt) | [big.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/big.seed6.pt) | +| `big_1_1` | [big_1_1.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/big_1_1.seed4.pt) | [big_1_1.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/big_1_1.seed5.pt) | [big_1_1.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/big_1_1.seed6.pt) | +| `base` | [base.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/base.seed4.pt) | [base.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/base.seed5.pt) | [base.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/base.seed6.pt) | +| `base_1_1` | [base_1_1.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/base_1_1.seed4.pt) | [base_1_1.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/base_1_1.seed5.pt) | [base_1_1.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/base_1_1.seed6.pt) | +| `half` | [half.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/half.seed4.pt) | [half.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/half.seed5.pt) | [half.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/half.seed6.pt) | +| `half_1_1` | [half_1_1.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/half_1_1.seed4.pt) | [half_1_1.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/half_1_1.seed5.pt) | [half_1_1.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/half_1_1.seed6.pt) | +| `quarter` | [quarter.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/quarter.seed4.pt) | [quarter.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/quarter.seed5.pt) | [quarter.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/quarter.seed6.pt) | +| `quarter_1_1` | [quarter_1_1.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/quarter_1_1.seed4.pt) | [quarter_1_1.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/quarter_1_1.seed5.pt) | [quarter_1_1.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/quarter_1_1.seed6.pt) | +| `8th` | [8th.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/8th.seed4.pt) | [8th.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/8th.seed5.pt) | [8th.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/8th.seed6.pt) | +| `8th_1_1` | [8th_1_1.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/8th_1_1.seed4.pt) | [8th_1_1.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/8th_1_1.seed5.pt) | [8th_1_1.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/8th_1_1.seed6.pt) | +| `16th` | [16th.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/16th.seed4.pt) | [16th.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/16th.seed5.pt) | [16th.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/16th.seed6.pt) | +| `16th_1_1` | [16th_1_1.seed4.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/16th_1_1.seed4.pt) | [16th_1_1.seed5.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/16th_1_1.seed5.pt) | [16th_1_1.seed6.pt](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/channel_models/16th_1_1.seed6.pt) | + +### Language Model +The model is trained on de-duplicated English Newscrawl data from 2007-2018 comprising 186 million sentences or 4.5B words after normalization and tokenization. +| | Path | +|----|----| +| `--lm-model` | [transformer_en_lm](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/transformer_lm.pt) | +| `--lm-data` | [lm_data](https://dl.fbaipublicfiles.com/fast_noisy_channel/de_en/lm_model/lm_dict/) + + +## Citation + +```bibtex +@inproceedings{bhosale2020language, + title={Language Models not just for Pre-training: Fast Online Neural Noisy Channel Modeling}, + author={Shruti Bhosale and Kyra Yee and Sergey Edunov and Michael Auli}, + booktitle={Proceedings of the Fifth Conference on Machine Translation (WMT)}, + year={2020}, +} + +@inproceedings{yee2019simple, + title={Simple and Effective Noisy Channel Modeling for Neural Machine Translation}, + author={Yee, Kyra and Dauphin, Yann and Auli, Michael}, + booktitle={Proceedings of the 2019 Conference on Empirical Methods in Natural Language Processing and the 9th International Joint Conference on Natural Language Processing (EMNLP-IJCNLP)}, + pages={5700--5705}, + year={2019} +} +``` diff --git a/examples/fast_noisy_channel/__init__.py b/examples/fast_noisy_channel/__init__.py new file mode 100644 index 0000000000..9b248c3a24 --- /dev/null +++ b/examples/fast_noisy_channel/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from . import noisy_channel_translation # noqa +from . import noisy_channel_sequence_generator # noqa +from . import noisy_channel_beam_search # noqa diff --git a/examples/fast_noisy_channel/noisy_channel_beam_search.py b/examples/fast_noisy_channel/noisy_channel_beam_search.py new file mode 100644 index 0000000000..23869ebcd0 --- /dev/null +++ b/examples/fast_noisy_channel/noisy_channel_beam_search.py @@ -0,0 +1,71 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from fairseq.search import Search + + +class NoisyChannelBeamSearch(Search): + + def __init__(self, tgt_dict): + super().__init__(tgt_dict) + self.fw_scores_buf = None + self.lm_scores_buf = None + + def _init_buffers(self, t): + # super()._init_buffers(t) + if self.fw_scores_buf is None: + self.scores_buf = t.new() + self.indices_buf = torch.LongTensor().to(device=t.device) + self.beams_buf = torch.LongTensor().to(device=t.device) + self.fw_scores_buf = t.new() + self.lm_scores_buf = t.new() + + def combine_fw_bw(self, combine_method, fw_cum, bw, step): + if combine_method == "noisy_channel": + fw_norm = fw_cum.div(step + 1) + lprobs = bw + fw_norm + elif combine_method == "lm_only": + lprobs = bw + fw_cum + + return lprobs + + def step(self, step, fw_lprobs, scores, bw_lprobs, lm_lprobs, combine_method): + self._init_buffers(fw_lprobs) + bsz, beam_size, vocab_size = fw_lprobs.size() + + if step == 0: + # at the first step all hypotheses are equally likely, so use + # only the first beam + fw_lprobs = fw_lprobs[:, ::beam_size, :].contiguous() + bw_lprobs = bw_lprobs[:, ::beam_size, :].contiguous() + # nothing to add since we are at the first step + fw_lprobs_cum = fw_lprobs + + else: + # make probs contain cumulative scores for each hypothesis + raw_scores = (scores[:, :, step - 1].unsqueeze(-1)) + fw_lprobs_cum = (fw_lprobs.add(raw_scores)) + + combined_lprobs = self.combine_fw_bw(combine_method, fw_lprobs_cum, bw_lprobs, step) + + # choose the top k according to the combined noisy channel model score + torch.topk( + combined_lprobs.view(bsz, -1), + k=min( + # Take the best 2 x beam_size predictions. We'll choose the first + # beam_size of these which don't predict eos to continue with. + beam_size * 2, + combined_lprobs.view(bsz, -1).size(1) - 1, # -1 so we never select pad + ), + out=(self.scores_buf, self.indices_buf), + ) + # save corresponding fw and lm scores + self.fw_scores_buf = torch.gather(fw_lprobs_cum.view(bsz, -1), 1, self.indices_buf) + self.lm_scores_buf = torch.gather(lm_lprobs.view(bsz, -1), 1, self.indices_buf) + # Project back into relative indices and beams + self.beams_buf = self.indices_buf // vocab_size + self.indices_buf.fmod_(vocab_size) + return self.scores_buf, self.fw_scores_buf, self.lm_scores_buf, self.indices_buf, self.beams_buf diff --git a/examples/fast_noisy_channel/noisy_channel_sequence_generator.py b/examples/fast_noisy_channel/noisy_channel_sequence_generator.py new file mode 100644 index 0000000000..ea8fae98e8 --- /dev/null +++ b/examples/fast_noisy_channel/noisy_channel_sequence_generator.py @@ -0,0 +1,842 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Optional + +import math +import numpy as np + +import torch +import torch.nn.functional as F +from torch import Tensor + +from .noisy_channel_beam_search import NoisyChannelBeamSearch +from fairseq.sequence_generator import EnsembleModel + + +class NoisyChannelSequenceGenerator(object): + def __init__( + self, + combine_method, + tgt_dict, + src_dict=None, + beam_size=1, + max_len_a=0, + max_len_b=200, + min_len=1, + len_penalty=1.0, + unk_penalty=0.0, + retain_dropout=False, + temperature=1.0, + match_source_len=False, + no_repeat_ngram_size=0, + normalize_scores=True, + channel_models=None, + k2=10, + ch_weight=1.0, + channel_scoring_type='log_norm', + top_k_vocab=0, + lm_models=None, + lm_dict=None, + lm_weight=1.0, + normalize_lm_scores_by_tgt_len=False, + ): + """Generates translations of a given source sentence, + using beam search with noisy channel decoding. + + Args: + combine_method (string, optional): Method to combine direct, LM and + channel model scores (default: None) + tgt_dict (~fairseq.data.Dictionary): target dictionary + src_dict (~fairseq.data.Dictionary): source dictionary + beam_size (int, optional): beam width (default: 1) + max_len_a/b (int, optional): generate sequences of maximum length + ax + b, where x is the source length + min_len (int, optional): the minimum length of the generated output + (not including end-of-sentence) + len_penalty (float, optional): length penalty, where <1.0 favors + shorter, >1.0 favors longer sentences (default: 1.0) + unk_penalty (float, optional): unknown word penalty, where <0 + produces more unks, >0 produces fewer (default: 0.0) + retain_dropout (bool, optional): use dropout when generating + (default: False) + temperature (float, optional): temperature, where values + >1.0 produce more uniform samples and values <1.0 produce + sharper samples (default: 1.0) + match_source_len (bool, optional): outputs should match the source + length (default: False) + no_repeat_ngram_size (int, optional): Size of n-grams that we avoid + repeating in the generation (default: 0) + normalize_scores (bool, optional): normalize scores by the length + of the output (default: True) + channel_models (List[~fairseq.models.FairseqModel]): ensemble of models + translating from the target to the source + k2 (int, optional): Top K2 candidates to score per beam at each step (default:10) + ch_weight (int, optional): Weight associated with the channel model score + assuming that the direct model score has weight 1.0 (default: 1.0) + channel_scoring_type (str, optional): String specifying how to score + the channel model (default: 'log_norm') + top_k_vocab (int, optional): If `channel_scoring_type` is `'src_vocab'` or + `'src_vocab_batched'`, then this parameter specifies the number of + most frequent tokens to include in the channel model output vocabulary, + in addition to the source tokens in the input batch (default: 0) + lm_models (List[~fairseq.models.FairseqModel]): ensemble of models + generating text in the target language + lm_dict (~fairseq.data.Dictionary): LM Model dictionary + lm_weight (int, optional): Weight associated with the LM model score + assuming that the direct model score has weight 1.0 (default: 1.0) + normalize_lm_scores_by_tgt_len (bool, optional): Should we normalize LM scores + by the target length? By default, we normalize the combination of + LM and channel model scores by the source length + """ + self.pad = tgt_dict.pad() + self.unk = tgt_dict.unk() + self.eos = tgt_dict.eos() + self.vocab_size = len(tgt_dict) + self.beam_size = beam_size + # the max beam size is the dictionary size - 1, since we never select pad + self.beam_size = min(beam_size, self.vocab_size - 1) + self.max_len_a = max_len_a + self.max_len_b = max_len_b + self.min_len = min_len + self.normalize_scores = normalize_scores + self.len_penalty = len_penalty + self.unk_penalty = unk_penalty + self.retain_dropout = retain_dropout + self.temperature = temperature + self.match_source_len = match_source_len + self.no_repeat_ngram_size = no_repeat_ngram_size + self.channel_models = channel_models + self.src_dict = src_dict + self.tgt_dict = tgt_dict + self.combine_method = combine_method + self.k2 = k2 + self.ch_weight = ch_weight + self.channel_scoring_type = channel_scoring_type + self.top_k_vocab = top_k_vocab + self.lm_models = lm_models + self.lm_dict = lm_dict + self.lm_weight = lm_weight + self.log_softmax_fn = torch.nn.LogSoftmax(dim=1) + self.normalize_lm_scores_by_tgt_len = normalize_lm_scores_by_tgt_len + + self.share_tgt_dict = (self.lm_dict == self.tgt_dict) + self.tgt_to_lm = make_dict2dict(tgt_dict, lm_dict) + + self.ch_scoring_bsz = 3072 + + assert temperature > 0, '--temperature must be greater than 0' + + self.search = NoisyChannelBeamSearch(tgt_dict) + + @torch.no_grad() + def generate( + self, + models, + sample, + prefix_tokens=None, + bos_token=None, + **kwargs + ): + """Generate a batch of translations. + Args: + models (List[~fairseq.models.FairseqModel]): ensemble of models + sample (dict): batch + prefix_tokens (torch.LongTensor, optional): force decoder to begin + with these tokens + """ + model = EnsembleModel(models) + incremental_states = torch.jit.annotate( + List[Dict[str, Dict[str, Optional[Tensor]]]], + [ + torch.jit.annotate(Dict[str, Dict[str, Optional[Tensor]]], {}) + for i in range(model.models_size) + ], + ) + if not self.retain_dropout: + model.eval() + + # model.forward normally channels prev_output_tokens into the decoder + # separately, but SequenceGenerator directly calls model.encoder + encoder_input = { + k: v for k, v in sample['net_input'].items() + if k != 'prev_output_tokens' + } + src_tokens = encoder_input['src_tokens'] + src_lengths_no_eos = (src_tokens.ne(self.eos) & src_tokens.ne(self.pad)).long().sum(dim=1) + input_size = src_tokens.size() + # batch dimension goes first followed by source lengths + bsz = input_size[0] + src_len = input_size[1] + beam_size = self.beam_size + + if self.match_source_len: + max_len = src_lengths_no_eos.max().item() + else: + max_len = min( + int(self.max_len_a * src_len + self.max_len_b), + # exclude the EOS marker + model.max_decoder_positions() - 1, + ) + + # compute the encoder output for each beam + encoder_outs = model.forward_encoder(encoder_input) + new_order = torch.arange(bsz).view(-1, 1).repeat(1, beam_size).view(-1) + new_order = new_order.to(src_tokens.device).long() + encoder_outs = model.reorder_encoder_out(encoder_outs, new_order) + + src_lengths = encoder_input['src_lengths'] + # initialize buffers + scores = src_tokens.new(bsz * beam_size, max_len + 1).float().fill_(0) + lm_prefix_scores = src_tokens.new(bsz * beam_size).float().fill_(0) + + scores_buf = scores.clone() + tokens = src_tokens.new(bsz * beam_size, max_len + 2).long().fill_(self.pad) + tokens_buf = tokens.clone() + tokens[:, 0] = self.eos if bos_token is None else bos_token + + # reorder source tokens so they may be used as a reference in generating P(S|T) + src_tokens = reorder_all_tokens(src_tokens, src_lengths, self.src_dict.eos_index) + + src_tokens = src_tokens.repeat(1, beam_size).view(-1, src_len) + src_lengths = src_lengths.view(bsz, -1).repeat(1, beam_size).view(bsz*beam_size, -1) + + attn, attn_buf = None, None + nonpad_idxs = None + + # The cands_to_ignore indicates candidates that should be ignored. + # For example, suppose we're sampling and have already finalized 2/5 + # samples. Then the cands_to_ignore would mark 2 positions as being ignored, + # so that we only finalize the remaining 3 samples. + cands_to_ignore = src_tokens.new_zeros(bsz, beam_size).eq(-1) # forward and backward-compatible False mask + + # list of completed sentences + finalized = [[] for i in range(bsz)] + finished = [False for i in range(bsz)] + num_remaining_sent = bsz + + # number of candidate hypos per step + cand_size = 2 * beam_size # 2 x beam size in case half are EOS + + # offset arrays for converting between different indexing schemes + bbsz_offsets = (torch.arange(0, bsz) * beam_size).unsqueeze(1).type_as(tokens) + cand_offsets = torch.arange(0, cand_size).type_as(tokens) + + # helper function for allocating buffers on the fly + buffers = {} + + def buffer(name, type_of=tokens): # noqa + if name not in buffers: + buffers[name] = type_of.new() + return buffers[name] + + def is_finished(sent, step, unfin_idx): + """ + Check whether we've finished generation for a given sentence, by + comparing the worst score among finalized hypotheses to the best + possible score among unfinalized hypotheses. + """ + assert len(finalized[sent]) <= beam_size + if len(finalized[sent]) == beam_size: + return True + return False + + def finalize_hypos(step, bbsz_idx, eos_scores, combined_noisy_channel_eos_scores): + """ + Finalize the given hypotheses at this step, while keeping the total + number of finalized hypotheses per sentence <= beam_size. + + Note: the input must be in the desired finalization order, so that + hypotheses that appear earlier in the input are preferred to those + that appear later. + + Args: + step: current time step + bbsz_idx: A vector of indices in the range [0, bsz*beam_size), + indicating which hypotheses to finalize + eos_scores: A vector of the same size as bbsz_idx containing + fw scores for each hypothesis + combined_noisy_channel_eos_scores: A vector of the same size as bbsz_idx containing + combined noisy channel scores for each hypothesis + """ + assert bbsz_idx.numel() == eos_scores.numel() + + # clone relevant token and attention tensors + tokens_clone = tokens.index_select(0, bbsz_idx) + tokens_clone = tokens_clone[:, 1:step + 2] # skip the first index, which is EOS + assert not tokens_clone.eq(self.eos).any() + tokens_clone[:, step] = self.eos + attn_clone = attn.index_select(0, bbsz_idx)[:, :, 1:step+2] if attn is not None else None + + # compute scores per token position + pos_scores = scores.index_select(0, bbsz_idx)[:, :step+1] + pos_scores[:, step] = eos_scores + # convert from cumulative to per-position scores + pos_scores[:, 1:] = pos_scores[:, 1:] - pos_scores[:, :-1] + + # normalize sentence-level scores + if self.normalize_scores: + combined_noisy_channel_eos_scores /= (step + 1) ** self.len_penalty + + cum_unfin = [] + prev = 0 + for f in finished: + if f: + prev += 1 + else: + cum_unfin.append(prev) + + sents_seen = set() + for i, (idx, score) in enumerate(zip(bbsz_idx.tolist(), combined_noisy_channel_eos_scores.tolist())): + unfin_idx = idx // beam_size + sent = unfin_idx + cum_unfin[unfin_idx] + + sents_seen.add((sent, unfin_idx)) + + if self.match_source_len and step > src_lengths_no_eos[unfin_idx]: + score = -math.inf + + def get_hypo(): + + if attn_clone is not None: + # remove padding tokens from attn scores + hypo_attn = attn_clone[i][nonpad_idxs[sent]] + _, alignment = hypo_attn.max(dim=0) + else: + hypo_attn = None + alignment = None + + return { + 'tokens': tokens_clone[i], + 'score': score, + 'attention': hypo_attn, # src_len x tgt_len + 'alignment': alignment, + 'positional_scores': pos_scores[i], + } + + if len(finalized[sent]) < beam_size: + finalized[sent].append(get_hypo()) + + newly_finished = [] + for sent, unfin_idx in sents_seen: + # check termination conditions for this sentence + if not finished[sent] and is_finished(sent, step, unfin_idx): + finished[sent] = True + newly_finished.append(unfin_idx) + return newly_finished + + def noisy_channel_rescoring(lprobs, beam_size, bsz, src_tokens, tokens, k): + """Rescore the top k hypothesis from each beam using noisy channel modeling + Returns: + new_fw_lprobs: the direct model probabilities after pruning the top k + new_ch_lm_lprobs: the combined channel and language model probabilities + new_lm_lprobs: the language model probabilities after pruning the top k + """ + with torch.no_grad(): + lprobs_size = lprobs.size() + if prefix_tokens is not None and step < prefix_tokens.size(1): + probs_slice = lprobs.view(bsz, -1, lprobs.size(-1))[:, 0, :] + cand_scores = torch.gather( + probs_slice, dim=1, + index=prefix_tokens[:, step].view(-1, 1).data + ).expand(-1, beam_size).contiguous().view(bsz*beam_size, 1) + cand_indices = prefix_tokens[:, step].view(-1, 1).expand(bsz, beam_size).data.contiguous().view(bsz*beam_size, 1) + + # need to calculate and save fw and lm probs for prefix tokens + fw_top_k = cand_scores + fw_top_k_idx = cand_indices + k = 1 + else: + # take the top k best words for every sentence in batch*beam + fw_top_k, fw_top_k_idx = torch.topk(lprobs.view(beam_size*bsz, -1), k=k) + eos_idx = torch.nonzero(fw_top_k_idx.view(bsz*beam_size*k, -1) == self.eos)[:, 0] + ch_scores = fw_top_k.new_full((beam_size*bsz*k, ), 0) + src_size = torch.sum(src_tokens[:, :] != self.src_dict.pad_index, dim=1, keepdim=True, dtype=fw_top_k.dtype) + + if self.combine_method != "lm_only": + temp_src_tokens_full = src_tokens[:, :].repeat(1, k).view(bsz*beam_size*k, -1) + not_padding = temp_src_tokens_full[:, 1:] != self.src_dict.pad_index + cur_tgt_size = step+2 + + # add eos to all candidate sentences except those that already end in eos + eos_tokens = tokens[:, 0].repeat(1, k).view(-1, 1) + eos_tokens[eos_idx] = self.tgt_dict.pad_index + + if step == 0: + channel_input = torch.cat((fw_top_k_idx.view(-1, 1), eos_tokens), 1) + else: + # move eos from beginning to end of target sentence + channel_input = torch.cat((tokens[:, 1:step + 1].repeat(1, k).view(-1, step), fw_top_k_idx.view(-1, 1), eos_tokens), 1) + + ch_input_lengths = torch.tensor(np.full(channel_input.size(0), cur_tgt_size)) + ch_input_lengths[eos_idx] = cur_tgt_size-1 + if self.channel_scoring_type == "unnormalized": + ch_encoder_output = channel_model.encoder(channel_input, src_lengths=ch_input_lengths) + ch_decoder_output, _ = channel_model.decoder(temp_src_tokens_full, encoder_out=ch_encoder_output, features_only=True) + del ch_encoder_output + ch_intermed_scores = channel_model.decoder.unnormalized_scores_given_target(ch_decoder_output, target_ids=temp_src_tokens_full[:, 1:]) + ch_intermed_scores = ch_intermed_scores.float() + ch_intermed_scores *= not_padding.float() + ch_scores = torch.sum(ch_intermed_scores, dim=1) + elif self.channel_scoring_type == "k2_separate": + for k_idx in range(k): + k_eos_tokens = eos_tokens[k_idx::k, :] + if step == 0: + k_ch_input = torch.cat((fw_top_k_idx[:, k_idx:k_idx+1], k_eos_tokens), 1) + else: + # move eos from beginning to end of target sentence + k_ch_input = torch.cat((tokens[:, 1:step + 1], fw_top_k_idx[:, k_idx:k_idx+1], k_eos_tokens), 1) + k_ch_input_lengths = ch_input_lengths[k_idx::k] + k_ch_output = channel_model(k_ch_input, k_ch_input_lengths, src_tokens) + k_ch_lprobs = channel_model.get_normalized_probs(k_ch_output, log_probs=True) + k_ch_intermed_scores = torch.gather(k_ch_lprobs[:, :-1, :], 2, src_tokens[:, 1:].unsqueeze(2)).squeeze(2) + k_ch_intermed_scores *= not_padding.float() + ch_scores[k_idx::k] = torch.sum(k_ch_intermed_scores, dim=1) + elif self.channel_scoring_type == "src_vocab": + ch_encoder_output = channel_model.encoder(channel_input, src_lengths=ch_input_lengths) + ch_decoder_output, _ = channel_model.decoder(temp_src_tokens_full, encoder_out=ch_encoder_output, features_only=True) + + del ch_encoder_output + ch_lprobs = normalized_scores_with_batch_vocab( + channel_model.decoder, + ch_decoder_output, src_tokens, k, bsz, beam_size, + self.src_dict.pad_index, top_k=self.top_k_vocab) + ch_scores = torch.sum(ch_lprobs, dim=1) + elif self.channel_scoring_type == "src_vocab_batched": + ch_bsz_size = temp_src_tokens_full.shape[0] + ch_lprobs_list = [None] * len(range(0, ch_bsz_size, self.ch_scoring_bsz)) + for i, start_idx in enumerate(range(0, ch_bsz_size, self.ch_scoring_bsz)): + end_idx = min(start_idx + self.ch_scoring_bsz, ch_bsz_size) + temp_src_tokens_full_batch = temp_src_tokens_full[start_idx:end_idx, :] + channel_input_batch = channel_input[start_idx:end_idx, :] + ch_input_lengths_batch = ch_input_lengths[start_idx:end_idx] + ch_encoder_output_batch = channel_model.encoder(channel_input_batch, src_lengths=ch_input_lengths_batch) + ch_decoder_output_batch, _ = channel_model.decoder(temp_src_tokens_full_batch, encoder_out=ch_encoder_output_batch, features_only=True) + ch_lprobs_list[i] = normalized_scores_with_batch_vocab( + channel_model.decoder, + ch_decoder_output_batch, src_tokens, k, bsz, beam_size, + self.src_dict.pad_index, top_k=self.top_k_vocab, + start_idx=start_idx, end_idx=end_idx) + ch_lprobs = torch.cat(ch_lprobs_list, dim=0) + ch_scores = torch.sum(ch_lprobs, dim=1) + else: + ch_output = channel_model(channel_input, ch_input_lengths, temp_src_tokens_full) + ch_lprobs = channel_model.get_normalized_probs(ch_output, log_probs=True) + ch_intermed_scores = torch.gather(ch_lprobs[:, :-1, :], 2, temp_src_tokens_full[:, 1:].unsqueeze(2)).squeeze().view(bsz*beam_size*k, -1) + ch_intermed_scores *= not_padding.float() + ch_scores = torch.sum(ch_intermed_scores, dim=1) + + else: + cur_tgt_size = 0 + ch_scores = ch_scores.view(bsz*beam_size, k) + expanded_lm_prefix_scores = lm_prefix_scores.unsqueeze(1).expand(-1, k).flatten() + + if self.share_tgt_dict: + lm_scores = get_lm_scores(lm, tokens[:, :step + 1].view(-1, step+1), lm_incremental_states, fw_top_k_idx.view(-1, 1), torch.tensor(np.full(tokens.size(0), step+1)), k) + else: + new_lm_input = dict2dict(tokens[:, :step + 1].view(-1, step+1), self.tgt_to_lm) + new_cands = dict2dict(fw_top_k_idx.view(-1, 1), self.tgt_to_lm) + lm_scores = get_lm_scores(lm, new_lm_input, lm_incremental_states, new_cands, torch.tensor(np.full(tokens.size(0), step+1)), k) + + lm_scores.add_(expanded_lm_prefix_scores) + ch_lm_scores = combine_ch_lm(self.combine_method, ch_scores, lm_scores, src_size, cur_tgt_size) + # initialize all as min value + new_fw_lprobs = ch_scores.new(lprobs_size).fill_(-1e17).view(bsz*beam_size, -1) + new_ch_lm_lprobs = ch_scores.new(lprobs_size).fill_(-1e17).view(bsz*beam_size, -1) + new_lm_lprobs = ch_scores.new(lprobs_size).fill_(-1e17).view(bsz*beam_size, -1) + new_fw_lprobs[:, self.pad] = -math.inf + new_ch_lm_lprobs[:, self.pad] = -math.inf + new_lm_lprobs[:, self.pad] = -math.inf + + new_fw_lprobs.scatter_(1, fw_top_k_idx, fw_top_k) + new_ch_lm_lprobs.scatter_(1, fw_top_k_idx, ch_lm_scores) + new_lm_lprobs.scatter_(1, fw_top_k_idx, lm_scores.view(-1, k)) + return new_fw_lprobs, new_ch_lm_lprobs, new_lm_lprobs + + def combine_ch_lm(combine_type, ch_scores, lm_scores1, src_size, tgt_size): + if self.channel_scoring_type == "unnormalized": + ch_scores = self.log_softmax_fn( + ch_scores.view(-1, self.beam_size * self.k2) + ).view(ch_scores.shape) + ch_scores = ch_scores * self.ch_weight + lm_scores1 = lm_scores1 * self.lm_weight + + if combine_type == "lm_only": + # log P(T|S) + log P(T) + ch_scores = lm_scores1.view(ch_scores.size()) + elif combine_type == "noisy_channel": + # 1/t log P(T|S) + 1/s log P(S|T) + 1/t log P(T) + if self.normalize_lm_scores_by_tgt_len: + ch_scores.div_(src_size) + lm_scores_norm = lm_scores1.view(ch_scores.size()).div(tgt_size) + ch_scores.add_(lm_scores_norm) + # 1/t log P(T|S) + 1/s log P(S|T) + 1/s log P(T) + else: + ch_scores.add_(lm_scores1.view(ch_scores.size())) + ch_scores.div_(src_size) + + return ch_scores + + if self.channel_models is not None: + channel_model = self.channel_models[0] # assume only one channel_model model + else: + channel_model = None + + lm = EnsembleModel(self.lm_models) + lm_incremental_states = torch.jit.annotate( + List[Dict[str, Dict[str, Optional[Tensor]]]], + [ + torch.jit.annotate(Dict[str, Dict[str, Optional[Tensor]]], {}) + for i in range(lm.models_size) + ], + ) + + reorder_state = None + batch_idxs = None + for step in range(max_len + 1): # one extra step for EOS marker + # reorder decoder internal states based on the prev choice of beams + if reorder_state is not None: + if batch_idxs is not None: + # update beam indices to take into account removed sentences + corr = batch_idxs - torch.arange(batch_idxs.numel()).type_as(batch_idxs) + reorder_state.view(-1, beam_size).add_(corr.unsqueeze(-1) * beam_size) + model.reorder_incremental_state(incremental_states, reorder_state) + encoder_outs = model.reorder_encoder_out(encoder_outs, reorder_state) + + lm.reorder_incremental_state(lm_incremental_states, reorder_state) + + fw_lprobs, avg_attn_scores = model.forward_decoder( + tokens[:, :step + 1], encoder_outs, incremental_states, temperature=self.temperature, + ) + + fw_lprobs[:, self.pad] = -math.inf # never select pad + fw_lprobs[:, self.unk] -= self.unk_penalty # apply unk penalty + fw_lprobs, ch_lm_lprobs, lm_lprobs = noisy_channel_rescoring(fw_lprobs, beam_size, bsz, src_tokens, tokens, self.k2) + + # handle min and max length constraints + if step >= max_len: + fw_lprobs[:, :self.eos] = -math.inf + fw_lprobs[:, self.eos + 1:] = -math.inf + elif step < self.min_len: + fw_lprobs[:, self.eos] = -math.inf + + # handle prefix tokens (possibly with different lengths) + if prefix_tokens is not None and step < prefix_tokens.size(1): + prefix_toks = prefix_tokens[:, step].unsqueeze(-1).repeat(1, beam_size).view(-1) + prefix_mask = prefix_toks.ne(self.pad) + + prefix_fw_lprobs = fw_lprobs.gather(-1, prefix_toks.unsqueeze(-1)) + fw_lprobs[prefix_mask] = -math.inf + fw_lprobs[prefix_mask] = fw_lprobs[prefix_mask].scatter_( + -1, prefix_toks[prefix_mask].unsqueeze(-1), prefix_fw_lprobs + ) + + prefix_ch_lm_lprobs = ch_lm_lprobs.gather(-1, prefix_toks.unsqueeze(-1)) + ch_lm_lprobs[prefix_mask] = -math.inf + ch_lm_lprobs[prefix_mask] = ch_lm_lprobs[prefix_mask].scatter_( + -1, prefix_toks[prefix_mask].unsqueeze(-1), prefix_ch_lm_lprobs + ) + + prefix_lm_lprobs = lm_lprobs.gather(-1, prefix_toks.unsqueeze(-1)) + lm_lprobs[prefix_mask] = -math.inf + lm_lprobs[prefix_mask] = lm_lprobs[prefix_mask].scatter_( + -1, prefix_toks[prefix_mask].unsqueeze(-1), prefix_lm_lprobs + ) + + # if prefix includes eos, then we should make sure tokens and + # scores are the same across all beams + eos_mask = prefix_toks.eq(self.eos) + if eos_mask.any(): + # validate that the first beam matches the prefix + first_beam = tokens[eos_mask].view(-1, beam_size, tokens.size(-1))[:, 0, 1:step + 1] + eos_mask_batch_dim = eos_mask.view(-1, beam_size)[:, 0] + target_prefix = prefix_tokens[eos_mask_batch_dim][:, :step] + assert (first_beam == target_prefix).all() + + def replicate_first_beam(tensor, mask): + tensor = tensor.view(-1, beam_size, tensor.size(-1)) + tensor[mask] = tensor[mask][:, :1, :] + return tensor.view(-1, tensor.size(-1)) + + # copy tokens, scores and lprobs from the first beam to all beams + tokens = replicate_first_beam(tokens, eos_mask_batch_dim) + scores = replicate_first_beam(scores, eos_mask_batch_dim) + + fw_lprobs = replicate_first_beam(fw_lprobs, eos_mask_batch_dim) + ch_lm_lprobs = replicate_first_beam(ch_lm_lprobs, eos_mask_batch_dim) + lm_lprobs = replicate_first_beam(lm_lprobs, eos_mask_batch_dim) + + if self.no_repeat_ngram_size > 0: + # for each beam and batch sentence, generate a list of previous ngrams + gen_ngrams = [{} for bbsz_idx in range(bsz * beam_size)] + for bbsz_idx in range(bsz * beam_size): + gen_tokens = tokens[bbsz_idx].tolist() + for ngram in zip(*[gen_tokens[i:] for i in range(self.no_repeat_ngram_size)]): + gen_ngrams[bbsz_idx][tuple(ngram[:-1])] = \ + gen_ngrams[bbsz_idx].get(tuple(ngram[:-1]), []) + [ngram[-1]] + + # Record attention scores + if avg_attn_scores is not None: + if attn is None: + attn = scores.new(bsz * beam_size, src_tokens.size(1), max_len + 2) + attn_buf = attn.clone() + nonpad_idxs = src_tokens.ne(self.pad) + attn[:, :, step + 1].copy_(avg_attn_scores) + + scores = scores.type_as(fw_lprobs) + scores_buf = scores_buf.type_as(fw_lprobs) + + self.search.set_src_lengths(src_lengths_no_eos) + + if self.no_repeat_ngram_size > 0: + def calculate_banned_tokens(bbsz_idx): + # before decoding the next token, prevent decoding of ngrams that have already appeared + ngram_index = tuple(tokens[bbsz_idx, step + 2 - self.no_repeat_ngram_size:step + 1].tolist()) + return gen_ngrams[bbsz_idx].get(ngram_index, []) + + if step + 2 - self.no_repeat_ngram_size >= 0: + # no banned tokens if we haven't generated no_repeat_ngram_size tokens yet + banned_tokens = [calculate_banned_tokens(bbsz_idx) for bbsz_idx in range(bsz * beam_size)] + else: + banned_tokens = [[] for bbsz_idx in range(bsz * beam_size)] + + for bbsz_idx in range(bsz * beam_size): + fw_lprobs[bbsz_idx, banned_tokens[bbsz_idx]] = -math.inf + + combined_noisy_channel_scores, fw_lprobs_top_k, lm_lprobs_top_k, cand_indices, cand_beams = self.search.step( + step, + fw_lprobs.view(bsz, -1, self.vocab_size), + scores.view(bsz, beam_size, -1)[:, :, :step], ch_lm_lprobs.view(bsz, -1, self.vocab_size), + lm_lprobs.view(bsz, -1, self.vocab_size), self.combine_method + ) + + # cand_bbsz_idx contains beam indices for the top candidate + # hypotheses, with a range of values: [0, bsz*beam_size), + # and dimensions: [bsz, cand_size] + cand_bbsz_idx = cand_beams.add(bbsz_offsets) + + # finalize hypotheses that end in eos (except for candidates to be ignored) + eos_mask = cand_indices.eq(self.eos) + eos_mask[:, :beam_size] &= ~cands_to_ignore + + # only consider eos when it's among the top beam_size indices + eos_bbsz_idx = torch.masked_select( + cand_bbsz_idx[:, :beam_size], mask=eos_mask[:, :beam_size] + ) + + finalized_sents = set() + if eos_bbsz_idx.numel() > 0: + eos_scores = torch.masked_select( + fw_lprobs_top_k[:, :beam_size], mask=eos_mask[:, :beam_size] + ) + combined_noisy_channel_eos_scores = torch.masked_select( + combined_noisy_channel_scores[:, :beam_size], + mask=eos_mask[:, :beam_size], + ) + + # finalize hypo using channel model score + finalized_sents = finalize_hypos( + step, eos_bbsz_idx, eos_scores, combined_noisy_channel_eos_scores) + + num_remaining_sent -= len(finalized_sents) + + assert num_remaining_sent >= 0 + if num_remaining_sent == 0: + break + + if len(finalized_sents) > 0: + new_bsz = bsz - len(finalized_sents) + + # construct batch_idxs which holds indices of batches to keep for the next pass + batch_mask = cand_indices.new_ones(bsz) + batch_mask[cand_indices.new(finalized_sents)] = 0 + batch_idxs = torch.nonzero(batch_mask).squeeze(-1) + + eos_mask = eos_mask[batch_idxs] + cand_beams = cand_beams[batch_idxs] + bbsz_offsets.resize_(new_bsz, 1) + cand_bbsz_idx = cand_beams.add(bbsz_offsets) + + lm_lprobs_top_k = lm_lprobs_top_k[batch_idxs] + + fw_lprobs_top_k = fw_lprobs_top_k[batch_idxs] + cand_indices = cand_indices[batch_idxs] + if prefix_tokens is not None: + prefix_tokens = prefix_tokens[batch_idxs] + src_lengths_no_eos = src_lengths_no_eos[batch_idxs] + cands_to_ignore = cands_to_ignore[batch_idxs] + + scores = scores.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, -1) + scores_buf.resize_as_(scores) + tokens = tokens.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, -1) + tokens_buf.resize_as_(tokens) + src_tokens = src_tokens.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, -1) + src_lengths = src_lengths.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, -1) + lm_prefix_scores = lm_prefix_scores.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, -1).squeeze() + + if attn is not None: + attn = attn.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, attn.size(1), -1) + attn_buf.resize_as_(attn) + bsz = new_bsz + else: + batch_idxs = None + + # Set active_mask so that values > cand_size indicate eos or + # ignored hypos and values < cand_size indicate candidate + # active hypos. After this, the min values per row are the top + # candidate active hypos. + eos_mask[:, :beam_size] |= cands_to_ignore + active_mask = torch.add( + eos_mask.type_as(cand_offsets) * cand_size, + cand_offsets[: eos_mask.size(1)], + ) + + # get the top beam_size active hypotheses, which are just the hypos + # with the smallest values in active_mask + active_hypos, new_cands_to_ignore = buffer('active_hypos'), buffer('new_cands_to_ignore') + torch.topk( + active_mask, k=beam_size, dim=1, largest=False, + out=(new_cands_to_ignore, active_hypos) + ) + + # update cands_to_ignore to ignore any finalized hypos + cands_to_ignore = new_cands_to_ignore.ge(cand_size)[:, :beam_size] + assert (~cands_to_ignore).any(dim=1).all() + + active_bbsz_idx = buffer('active_bbsz_idx') + torch.gather( + cand_bbsz_idx, dim=1, index=active_hypos, + out=active_bbsz_idx, + ) + active_scores = torch.gather( + fw_lprobs_top_k, dim=1, index=active_hypos, + out=scores[:, step].view(bsz, beam_size), + ) + + active_bbsz_idx = active_bbsz_idx.view(-1) + active_scores = active_scores.view(-1) + + # copy tokens and scores for active hypotheses + torch.index_select( + tokens[:, :step + 1], dim=0, index=active_bbsz_idx, + out=tokens_buf[:, :step + 1], + ) + torch.gather( + cand_indices, dim=1, index=active_hypos, + out=tokens_buf.view(bsz, beam_size, -1)[:, :, step + 1], + ) + if step > 0: + torch.index_select( + scores[:, :step], dim=0, index=active_bbsz_idx, + out=scores_buf[:, :step], + ) + torch.gather( + fw_lprobs_top_k, dim=1, index=active_hypos, + out=scores_buf.view(bsz, beam_size, -1)[:, :, step], + ) + torch.gather( + lm_lprobs_top_k, dim=1, index=active_hypos, + out=lm_prefix_scores.view(bsz, beam_size) + ) + + # copy attention for active hypotheses + if attn is not None: + torch.index_select( + attn[:, :, :step + 2], dim=0, index=active_bbsz_idx, + out=attn_buf[:, :, :step + 2], + ) + + # swap buffers + tokens, tokens_buf = tokens_buf, tokens + scores, scores_buf = scores_buf, scores + if attn is not None: + attn, attn_buf = attn_buf, attn + + # reorder incremental state in decoder + reorder_state = active_bbsz_idx + + # sort by score descending + for sent in range(len(finalized)): + finalized[sent] = sorted(finalized[sent], key=lambda r: r['score'], reverse=True) + + return finalized + + +def get_lm_scores(model, input_tokens, incremental_states, cand_tokens, input_len, k): + with torch.no_grad(): + lm_lprobs, avg_attn_scores = model.forward_decoder( + input_tokens, encoder_outs=None, incremental_states=incremental_states, + ) + + lm_lprobs_size = lm_lprobs.size(0) + probs_next_wrd = torch.gather(lm_lprobs.repeat(1, k).view(lm_lprobs_size*k, -1), 1, cand_tokens).squeeze().view(-1) + + return probs_next_wrd + + +def make_dict2dict(old_dict, new_dict): + dict2dict_map = {} + for sym in old_dict.symbols: + dict2dict_map[old_dict.index(sym)] = new_dict.index(sym) + return dict2dict_map + + +def dict2dict(tokens, dict2dict_map): + if tokens.device == torch.device('cpu'): + tokens_tmp = tokens + else: + tokens_tmp = tokens.cpu() + return tokens_tmp.map_( + tokens_tmp, + lambda _, val, dict2dict_map=dict2dict_map : dict2dict_map[float(val)] + ).to(tokens.device) + + +def reorder_tokens(tokens, lengths, eos): + # reorder source tokens so they may be used as reference for P(S|T) + return torch.cat((tokens.new([eos]), tokens[-lengths:-1], tokens[:-lengths]), 0) + + +def reorder_all_tokens(tokens, lengths, eos): + # used to reorder src tokens from [ .. ] to [ ...] + # so source tokens can be used to predict P(S|T) + return torch.stack([reorder_tokens(token, length, eos) for token, length in zip(tokens, lengths)]) + + +def normalized_scores_with_batch_vocab( + model_decoder, features, target_ids, k, bsz, beam_size, + pad_idx, top_k=0, vocab_size_meter=None, start_idx=None, + end_idx=None, **kwargs): + """ + Get normalized probabilities (or log probs) from a net's output + w.r.t. vocab consisting of target IDs in the batch + """ + if model_decoder.adaptive_softmax is None: + weight = model_decoder.output_projection.weight + vocab_ids = torch.unique( + torch.cat( + (torch.unique(target_ids), torch.arange(top_k, device=target_ids.device)) + ) + ) + id_map = dict(zip(vocab_ids.tolist(), range(len(vocab_ids)))) + mapped_target_ids = target_ids.cpu().apply_( + lambda x, id_map=id_map: id_map[x] + ).to(target_ids.device) + expanded_target_ids = mapped_target_ids[:, :].repeat(1, k).view(bsz*beam_size*k, -1) + if start_idx is not None and end_idx is not None: + expanded_target_ids = expanded_target_ids[start_idx:end_idx, :] + logits = F.linear(features, weight[vocab_ids, :]) + log_softmax = F.log_softmax(logits, dim=-1, dtype=torch.float32) + intermed_scores = torch.gather( + log_softmax[:, :-1, :], + 2, + expanded_target_ids[:, 1:].unsqueeze(2), + ).squeeze() + not_padding = expanded_target_ids[:, 1:] != pad_idx + intermed_scores *= not_padding.float() + return intermed_scores + else: + raise ValueError("adaptive softmax doesn't work with " + + "`normalized_scores_with_batch_vocab()`") diff --git a/examples/fast_noisy_channel/noisy_channel_translation.py b/examples/fast_noisy_channel/noisy_channel_translation.py new file mode 100644 index 0000000000..b74bdfd456 --- /dev/null +++ b/examples/fast_noisy_channel/noisy_channel_translation.py @@ -0,0 +1,127 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from fairseq.tasks.translation import TranslationTask +from fairseq.tasks.language_modeling import LanguageModelingTask +from fairseq import checkpoint_utils +import argparse +from fairseq.tasks import register_task +import torch + + +@register_task("noisy_channel_translation") +class NoisyChannelTranslation(TranslationTask): + """ + Rescore the top k candidates from each beam using noisy channel modeling + """ + + @staticmethod + def add_args(parser): + """Add task-specific arguments to the parser.""" + TranslationTask.add_args(parser) + # fmt: off + parser.add_argument('--channel-model', metavar='FILE', + help='path to P(S|T) model. P(S|T) and P(T|S) must share source and target dictionaries.') + parser.add_argument('--combine-method', default='lm_only', + choices=['lm_only', 'noisy_channel'], + help="""method for combining direct and channel model scores. + lm_only: decode with P(T|S)P(T) + noisy_channel: decode with 1/t P(T|S) + 1/s(P(S|T)P(T))""") + parser.add_argument('--normalize-lm-scores-by-tgt-len', action='store_true', default=False, + help='normalize lm score by target length instead of source length') + parser.add_argument('--channel-scoring-type', default='log_norm', choices=['unnormalized', 'log_norm', 'k2_separate', 'src_vocab', 'src_vocab_batched'], + help="Normalize bw scores with log softmax or return bw scores without log softmax") + parser.add_argument('--top-k-vocab', default=0, type=int, + help='top k vocab IDs to use with `src_vocab` in channel model scoring') + parser.add_argument('--k2', default=50, type=int, + help='the top k2 candidates to rescore with the noisy channel model for each beam') + parser.add_argument('--ch-wt', default=1, type=float, + help='weight for the channel model') + parser.add_argument('--lm-model', metavar='FILE', + help='path to lm model file, to model P(T). P(T) must share the same vocab as the direct model on the target side') + parser.add_argument('--lm-data', metavar='FILE', + help='path to lm model training data for target language, used to properly load LM with correct dictionary') + parser.add_argument('--lm-wt', default=1, type=float, + help='the weight of the lm in joint decoding') + # fmt: on + + def build_generator( + self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None + ): + if getattr(args, "score_reference", False): + raise NotImplementedError() + else: + from .noisy_channel_sequence_generator import NoisyChannelSequenceGenerator + use_cuda = torch.cuda.is_available() and not self.args.cpu + assert self.args.lm_model is not None, '--lm-model required for noisy channel generation!' + assert self.args.lm_data is not None, '--lm-data required for noisy channel generation to map between LM and bitext vocabs' + if self.args.channel_model is not None: + import copy + ch_args_task = copy.deepcopy(self.args) + tmp = ch_args_task.source_lang + ch_args_task.source_lang = ch_args_task.target_lang + ch_args_task.target_lang = tmp + ch_args_task._name = 'translation' + channel_task = TranslationTask.setup_task(ch_args_task) + + arg_dict = {} + arg_dict['task'] = 'language_modeling' + arg_dict['sample_break_mode'] = 'eos' + arg_dict['data'] = self.args.lm_data + arg_dict['output_dictionary_size'] = -1 + lm_args = argparse.Namespace(**arg_dict) + lm_task = LanguageModelingTask.setup_task(lm_args) + lm_dict = lm_task.output_dictionary + + if self.args.channel_model is not None: + channel_models, _ = checkpoint_utils.load_model_ensemble(self.args.channel_model.split(':'), task=channel_task) + + for model in channel_models: + model.make_generation_fast_( + beamable_mm_beam_size=None if args.no_beamable_mm else args.beam, + need_attn=args.print_alignment, + ) + if self.args.fp16: + model.half() + if use_cuda: + model.cuda() + else: + channel_models = None + + lm_models, _ = checkpoint_utils.load_model_ensemble(self.args.lm_model.split(':'), task=lm_task) + + for model in lm_models: + model.make_generation_fast_( + beamable_mm_beam_size=None if args.no_beamable_mm else args.beam, + need_attn=args.print_alignment, + ) + if self.args.fp16: + model.half() + if use_cuda: + model.cuda() + return NoisyChannelSequenceGenerator( + combine_method=self.args.combine_method, + tgt_dict=self.target_dictionary, + src_dict=self.source_dictionary, + beam_size=getattr(args, 'beam', 5), + max_len_a=getattr(args, 'max_len_a', 0), + max_len_b=getattr(args, 'max_len_b', 200), + min_len=getattr(args, 'min_len', 1), + len_penalty=getattr(args, 'lenpen', 1), + unk_penalty=getattr(args, 'unkpen', 0), + temperature=getattr(args, 'temperature', 1.), + match_source_len=getattr(args, 'match_source_len', False), + no_repeat_ngram_size=getattr(args, 'no_repeat_ngram_size', 0), + normalize_scores=(not getattr(args, 'unnormalized', False)), + channel_models=channel_models, + k2=getattr(self.args, 'k2', 50), + ch_weight=getattr(self.args, 'ch_wt', 1), + channel_scoring_type=self.args.channel_scoring_type, + top_k_vocab=self.args.top_k_vocab, + lm_models=lm_models, + lm_dict=lm_dict, + lm_weight=getattr(self.args, 'lm_wt', 1), + normalize_lm_scores_by_tgt_len=getattr(self.args, 'normalize_lm_scores_by_tgt_len', False), + ) diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index e2df08e092..efb5f1542c 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -69,6 +69,7 @@ def string( escape_unk=False, extra_symbols_to_ignore=None, unk_string=None, + include_eos=False, ): """Helper for converting a tensor of token indices to a string. @@ -76,7 +77,7 @@ def string( """ if torch.is_tensor(tensor) and tensor.dim() == 2: return "\n".join( - self.string(t, bpe_symbol, escape_unk, extra_symbols_to_ignore) + self.string(t, bpe_symbol, escape_unk, extra_symbols_to_ignore, include_eos=include_eos) for t in tensor ) From 265791b727b664d4d7da3abd918a3f6fb70d7337 Mon Sep 17 00:00:00 2001 From: alexeib Date: Tue, 17 Nov 2020 17:07:23 -0800 Subject: [PATCH 058/774] fix loading ensembles (#1442) Summary: fixes loading ensembles. previous change used the state of the first model for all models in the ensemble Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1442 Reviewed By: chtran Differential Revision: D25035706 Pulled By: alexeib fbshipit-source-id: 9029999be0f1703efb1df20bec2890de59449f1f --- fairseq/checkpoint_utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 5a0dc099b2..2bb055056e 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -267,6 +267,8 @@ def load_model_ensemble( def load_model_ensemble_and_task( filenames, arg_overrides=None, task=None, strict=True, suffix="", num_shards=1, state=None ): + assert state is None or len(filenames) == 1 + from fairseq import tasks assert not ( @@ -303,6 +305,10 @@ def load_model_ensemble_and_task( model = task.build_model(cfg.model) model.load_state_dict(state["model"], strict=strict, model_cfg=cfg.model) + + # reset state so it gets loaded for the next model in ensemble + state = None + ensemble.append(model) return ensemble, cfg, task From e931009a91c430a66583e80a91d1de9cea656bd2 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Wed, 18 Nov 2020 10:31:19 -0800 Subject: [PATCH 059/774] Fix boundary condition in token_block_utils_fast.pyx (#1445) Summary: In cases where the item size in the underlying dataset is 0, it's possible that `remaining` is initialized to 0. We can update the assert to reflect this. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1445 Reviewed By: alexeib Differential Revision: D25054723 Pulled By: myleott fbshipit-source-id: 1bb73cce34e973f407436c442b698ce706d97359 --- fairseq/data/token_block_utils_fast.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/data/token_block_utils_fast.pyx b/fairseq/data/token_block_utils_fast.pyx index 5a2f16ec34..08af4f3061 100644 --- a/fairseq/data/token_block_utils_fast.pyx +++ b/fairseq/data/token_block_utils_fast.pyx @@ -170,7 +170,7 @@ cdef class DatasetSearcher(object): self.current_offset += to_consume self.current_i += to_consume else: - assert remaining > 0 + assert remaining >= 0 self.current_i += remaining self.current_index += 1 self.current_offset = 0 From 41a61bd4e2835c7bed25cc9f52fe65714379322e Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Wed, 18 Nov 2020 14:30:02 -0800 Subject: [PATCH 060/774] Add GitHub Action to build Python wheels (+ minor cleanup in build scripts) (#1447) Summary: Here's an example run in a forked repo: https://github.com/fairseq/fairseq/runs/1419699104 We can upload the wheels to PyPI to make `pip install fairseq` easier for folks. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1447 Reviewed By: lematt1991 Differential Revision: D25060753 Pulled By: myleott fbshipit-source-id: 9fdc28cc7c8a172daac668dd09684ec43e2ff11a --- .github/workflows/build.yml | 14 +++++++--- .github/workflows/build_wheels.yml | 41 ++++++++++++++++++++++++++++++ fairseq/tasks/audio_pretraining.py | 3 ++- setup.py | 19 +++++++++----- 4 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/build_wheels.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6ae8093a8a..a2d44dd57f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,26 +19,32 @@ jobs: runs-on: ${{ matrix.platform }} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} + - name: Conditionally install pytorch if: matrix.platform == 'windows-latest' run: pip3 install torch -f https://download.pytorch.org/whl/torch_stable.html + - name: Install locally run: | python -m pip install --upgrade pip + git submodule update --init --recursive python setup.py build_ext --inplace python -m pip install --editable . + - name: Lint with flake8 run: | pip install flake8 # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --extend-exclude fairseq/model_parallel/megatron # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --extend-exclude fairseq/model_parallel/megatron + - name: Run tests run: | python setup.py test diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml new file mode 100644 index 0000000000..7261708596 --- /dev/null +++ b/.github/workflows/build_wheels.yml @@ -0,0 +1,41 @@ +name: build_wheels + +on: + push: + branches: + - v[0-9]+.[0-9]+.[x0-9]+ + tags: + - v* + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + + steps: + - uses: actions/checkout@v2 + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: '3.7' + + - name: Install cibuildwheel + run: | + python -m pip install cibuildwheel + + - name: Build wheels for CPython + run: | + python -m cibuildwheel --output-dir dist + env: + CIBW_BUILD: "cp36-*64 cp37-*64 cp38-*64" + CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 + CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . + + - uses: actions/upload-artifact@v2 + with: + name: wheels + path: ./dist/*.whl diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 90e667c80d..a2f7edc34d 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -5,7 +5,6 @@ # the root directory of this source tree. An additional grant of patent rights # can be found in the PATENTS file in the same directory. -import editdistance import os import sys import torch @@ -212,6 +211,8 @@ def build_model(self, model_cfg: FairseqDataclass): return model def _inference_with_wer(self, generator, sample, model): + import editdistance + def decode(toks): s = self.target_dictionary.string( toks.int().cpu(), diff --git a/setup.py b/setup.py index 572d2b50de..2aae720d7e 100644 --- a/setup.py +++ b/setup.py @@ -132,7 +132,7 @@ def include_dirs(self, dirs): # use CPU build of PyTorch dependency_links = [ - "https://download.pytorch.org/whl/cpu/torch-1.3.0%2Bcpu-cp36-cp36m-linux_x86_64.whl" + "https://download.pytorch.org/whl/cpu/torch-1.7.0%2Bcpu-cp36-cp36m-linux_x86_64.whl" ] else: dependency_links = [] @@ -149,6 +149,11 @@ def include_dirs(self, dirs): ) +extra_packages = [] +if os.path.exists(os.path.join("fairseq", "model_parallel", "megatron", "mpu")): + extra_packages.append("fairseq.model_parallel.megatron.mpu") + + def do_setup(package_data): setup( name="fairseq", @@ -172,7 +177,6 @@ def do_setup(package_data): "cffi", "cython", "dataclasses", - "editdistance", "hydra-core", "numpy", "regex", @@ -190,7 +194,7 @@ def do_setup(package_data): "tests", "tests.*", ] - ), + ) + extra_packages, package_data=package_data, ext_modules=extensions, test_suite="tests", @@ -223,12 +227,13 @@ def get_files(path, relative_to="fairseq"): try: # symlink examples into fairseq package so package_data accepts them - if "build_ext" not in sys.argv[1:]: - os.symlink(os.path.join("..", "examples"), "fairseq/examples") + fairseq_examples = os.path.join("fairseq", "examples") + if "build_ext" not in sys.argv[1:] and not os.path.exists(fairseq_examples): + os.symlink(os.path.join("..", "examples"), fairseq_examples) package_data = { "fairseq": get_files("fairseq/examples"), } do_setup(package_data) finally: - if "build_ext" not in sys.argv[1:]: - os.unlink("fairseq/examples") + if "build_ext" not in sys.argv[1:] and os.path.exists(fairseq_examples): + os.unlink(fairseq_examples) From 6d2cf0ddf64040543c346b3866eb636d14522dde Mon Sep 17 00:00:00 2001 From: alexeib Date: Wed, 18 Nov 2020 22:26:34 -0800 Subject: [PATCH 061/774] convert wav2vec2 asr to hydra (#1444) Summary: this completes wav2vec migration to hydra Test Plan: - training wav2vec2 models - training wav2vec2 ctc models - training wav2vec2 seq2seq models - infer.py eval of ctc models - generate.py eval of seq2seq models Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1444 Reviewed By: myleott Differential Revision: D25040041 Pulled By: alexeib fbshipit-source-id: 2aac3b9c659667f7e696628a4b016ee863da68cf --- examples/wav2vec/README.md | 62 +-- .../wav2vec/config/finetuning/base_100h.yaml | 59 ++ .../wav2vec/config/finetuning/base_10h.yaml | 64 +++ .../wav2vec/config/finetuning/base_10m.yaml | 64 +++ .../wav2vec/config/finetuning/base_1h.yaml | 64 +++ .../wav2vec/config/finetuning/base_960h.yaml | 58 ++ .../wav2vec/config/finetuning/vox_100h.yaml | 59 ++ .../wav2vec/config/finetuning/vox_10h.yaml | 64 +++ .../wav2vec/config/finetuning/vox_10m.yaml | 64 +++ .../wav2vec/config/finetuning/vox_1h.yaml | 64 +++ .../wav2vec/config/finetuning/vox_960h.yaml | 58 ++ .../wav2vec2_base_librispeech.yaml | 55 ++ .../pretraining/wav2vec2_large_librivox.yaml | 69 +++ .../config/model/wav2vec2/wav2vec2_base.yaml | 8 + .../config/model/wav2vec2/wav2vec2_large.yaml | 20 + fairseq/criterions/ctc.py | 106 ++-- fairseq/criterions/fairseq_criterion.py | 6 +- fairseq/dataclass/configs.py | 2 +- fairseq/dataclass/utils.py | 23 +- fairseq/models/wav2vec/wav2vec2.py | 4 +- fairseq/models/wav2vec/wav2vec2_asr.py | 518 ++++++++---------- .../lr_scheduler/polynomial_decay_schedule.py | 85 +-- .../lr_scheduler/tri_stage_lr_scheduler.py | 128 ++--- 23 files changed, 1209 insertions(+), 495 deletions(-) create mode 100644 examples/wav2vec/config/finetuning/base_100h.yaml create mode 100644 examples/wav2vec/config/finetuning/base_10h.yaml create mode 100644 examples/wav2vec/config/finetuning/base_10m.yaml create mode 100644 examples/wav2vec/config/finetuning/base_1h.yaml create mode 100644 examples/wav2vec/config/finetuning/base_960h.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_100h.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10h.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10m.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_1h.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_960h.yaml create mode 100644 examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml create mode 100644 examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml create mode 100644 fairseq/config/model/wav2vec2/wav2vec2_base.yaml create mode 100644 fairseq/config/model/wav2vec2/wav2vec2_large.yaml diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 1da42f388a..442a92553a 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -53,44 +53,27 @@ separately pre-processed manifest file. This configuration was used for the base model trained on the Librispeech dataset in the wav2vec 2.0 paper -Note that this was tested with pytorch 1.4.0 and the input is expected to be single channel, sampled at 16 kHz +Note that the input is expected to be single channel, sampled at 16 kHz ```shell script -$ python train.py --distributed-world-size 64 --distributed-port $PORT /manifest/path \ ---save-dir /model/path --fp16 --num-workers 6 --task audio_pretraining --criterion wav2vec --arch wav2vec2 \ ---log-keys '["prob_perplexity","code_perplexity","temp"]' --quantize-targets --extractor-mode default \ ---conv-feature-layers '[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] * 2' --final-dim 256 --latent-vars 320 \ ---latent-groups 2 --latent-temp '(2,0.5,0.999995)' --infonce --optimizer adam \ ---adam-betas '(0.9,0.98)' --adam-eps 1e-06 --lr-scheduler polynomial_decay --total-num-update 400000 \ ---lr 0.0005 --warmup-updates 32000 --mask-length 10 --mask-prob 0.65 --mask-selection static --mask-other 0 \ ---encoder-layerdrop 0.05 --dropout-input 0.1 --dropout-features 0.1 --feature-grad-mult 0.1 \ ---loss-weights '[0.1, 10]' --conv-pos 128 --conv-pos-groups 16 --num-negatives 100 --cross-sample-negatives 0 \ ---max-sample-size 250000 --min-sample-size 32000 --dropout 0.1 --attention-dropout 0.1 --weight-decay 0.01 \ ---max-tokens 1400000 --max-update 400000 --skip-invalid-size-inputs-valid-test --ddp-backend no_c10d +$ python fairseq_cli/hydra_train.py task.data=/path/to/data \ +--config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining --config-name wav2vec2_base_librispeech ``` -Note: you can simulate 64 GPUs by using k GPUs and setting --update-freq 64/k +Note: you can simulate 64 GPUs by using k GPUs and adding command line parameters (before --config-path) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 64/k ### Train a wav2vec 2.0 large model: This configuration was used for the large model trained on the Libri-light dataset in the wav2vec 2.0 paper ```shell script -$ python train.py --distributed-world-size 128 --distributed-port $PORT /manifest/path \ ---save-dir /model/path --fp16 --num-workers 6 --task audio_pretraining --criterion wav2vec --arch wav2vec2 \ ---log-keys '["prob_perplexity","code_perplexity","temp"]' --quantize-targets --extractor-mode default \ ---conv-feature-layers '[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] * 2' --final-dim 768 --latent-vars 320 \ ---latent-groups 2 --latent-temp '(2.0,0.1,0.999995)' --infonce --optimizer adam \ ---adam-betas '(0.9,0.98)' --adam-eps 1e-06 --lr-scheduler polynomial_decay --total-num-update 600000 \ ---lr 0.0003 --warmup-updates 32000 --mask-length 10 --mask-prob 0.65 --mask-selection static --mask-other 0 \ ---encoder-layerdrop 0.0 --dropout-input 0.1 --dropout-features 0.1 --feature-grad-mult 0.03 \ ---loss-weights '[0.1, 10]' --conv-pos 128 --conv-pos-groups 16 --encoder-layers 24 --encoder-embed-dim 1024 \ ---encoder-ffn-embed-dim 4096 --encoder-attention-heads 16 --num-negatives 100 --cross-sample-negatives 0 \ ---max-sample-size 320000 --min-sample-size 32000 --dropout 0.0 --attention-dropout 0.1 --weight-decay 0.01 \ ---max-tokens 1200000 --max-update 600000 --skip-invalid-size-inputs-valid-test --ddp-backend no_c10d +$ python fairseq_cli/hydra_train.py task.data=/path/to/data \ +--config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining --config-name wav2vec2_large_librivox ``` -Note: you can simulate 128 GPUs by using k GPUs and setting --update-freq 128/k +Note: you can simulate 128 GPUs by using k GPUs and adding command line parameters (before --config-path) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 128/k ### Fine-tune a pre-trained model with CTC: @@ -105,28 +88,19 @@ $ python libri_labels.py /path/to/tsv --output-dir /output/dir --output-name $sp Fine-tuning on 100h of Librispeech with letter targets: ```shell script -valid_subset=dev_other -python train.py --distributed-world-size 24 --distributed-port $PORT /path/to/training_data --save-dir /model/path --fp16 \ ---wer-args '("/path/to/lm/4-gram.bin","/path/to/lexicon",2,-1)' \ ---post-process letter --valid-subset $valid_subset --no-epoch-checkpoints --best-checkpoint-metric wer --num-workers 4 \ ---max-update 80000 --sentence-avg --task audio_pretraining --arch wav2vec_ctc --w2v-path /path/to/pretrained/model \ ---labels ltr --apply-mask --mask-selection static --mask-other 0 --mask-length 10 --mask-prob 0.5 --layerdrop 0.1 \ ---mask-channel-selection static --mask-channel-other 0 --mask-channel-length 64 --mask-channel-prob 0.5 --zero-infinity \ ---feature-grad-mult 0.0 --freeze-finetune-updates 10000 --validate-after-updates 10000 --optimizer adam \ ---adam-betas '(0.9, 0.98)' --adam-eps 1e-08 --lr 2e-05 --lr-scheduler tri_stage --warmup-steps 8000 --hold-steps 32000 \ ---decay-steps 40000 --final-lr-scale 0.05 --final-dropout 0.0 --dropout 0.0 --activation-dropout 0.1 --criterion ctc \ ---attention-dropout 0.0 --max-tokens 1280000 --seed 2337 --log-format json --log-interval 500 --ddp-backend no_c10d +python fairseq_cli/hydra_train.py distributed_training.distributed_port=$PORT task.data=/path/to/data \ +model.w2v_path=/path/to/model.pt --config-path /path/to/fairseq-py/examples/wav2vec/config/finetuning \ +--config-name base_100h ``` -Note: you can simulate 24 GPUs by using k GPUs and setting --update-freq 24/k +There are other config files in the config/finetuning directory that can be used to fine-tune on other splits. +You can specify the right config via the --config-name parameter. -Decoding with a language model during training requires wav2letter [python bindings](https://github.com/facebookresearch/wav2letter/wiki/Building-Python-bindings). -Alternatively, simply omit the --wer-args flag. - -For hyper-parameters to fine-tune other Librispeech splits (10 minutes, 1 hour, etc) please refer to the table in Appendix B in the wav2vec 2.0 paper. -The main changes to make are adjusting --max-update, and then adjusting --warmup-steps, --hold-steps, and --decay steps so that they use 0.1/0.4/0.5 of max-update respectively. You then need to adjust --mask-prob and --mask-channel-prob. This should be set to the mask-length * x where x is the number in the table and mask-length is what you use for --mask-length (10 in this example. Use --mask-channel-length value for --mask-channel-prob). +Note: you can simulate 24 GPUs by using k GPUs and adding command line parameters (before --config-path) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 24/k -For example, for 10 hours, we see in the paper that timestep mask prob should be 0.065, so we set --mask-prob to 10* 0.065 = 0.65. channel mask prob is 0.004, so we set it to 64 * 0.004 = 0.256. then we set --max-updates to 20000 and change --warmup-steps to 20000 * 0.1 = 2000, --hold-steps to 8000 and --decay-steps to 10000. +Decoding with a language model during training requires wav2letter [python bindings](https://github.com/facebookresearch/wav2letter/wiki/Building-Python-bindings). +If you want to use a language model, add `+criterion.wer_args='[/path/to/kenlm, /path/to/lexicon, 2, -1]'` to the command line. ### Evaluating a CTC model: diff --git a/examples/wav2vec/config/finetuning/base_100h.yaml b/examples/wav2vec/config/finetuning/base_100h.yaml new file mode 100644 index 0000000000..7d1664a184 --- /dev/null +++ b/examples/wav2vec/config/finetuning/base_100h.yaml @@ -0,0 +1,59 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: false + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 3200000 + skip_invalid_size_inputs_valid_test: true + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 2 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 80000 + lr: [0.00003] + sentence_avg: true + update_freq: [4] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_channel_prob: 0.5 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 0 + diff --git a/examples/wav2vec/config/finetuning/base_10h.yaml b/examples/wav2vec/config/finetuning/base_10h.yaml new file mode 100644 index 0000000000..31125947c0 --- /dev/null +++ b/examples/wav2vec/config/finetuning/base_10h.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval: 50 + save_interval_updates: 10000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: false + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 3200000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 50 + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 2 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 20000 + lr: [0.00005] + sentence_avg: true + update_freq: [4] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_channel_prob: 0.5 + mask_channel_length: 64 + layerdrop: 0.05 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/finetuning/base_10m.yaml b/examples/wav2vec/config/finetuning/base_10m.yaml new file mode 100644 index 0000000000..2235504489 --- /dev/null +++ b/examples/wav2vec/config/finetuning/base_10m.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval: 1000 + save_interval_updates: 50 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: false + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 3200000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 1000 + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 2 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 13000 + lr: [0.00005] + sentence_avg: true + update_freq: [4] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_channel_prob: 0.25 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/finetuning/base_1h.yaml b/examples/wav2vec/config/finetuning/base_1h.yaml new file mode 100644 index 0000000000..2235504489 --- /dev/null +++ b/examples/wav2vec/config/finetuning/base_1h.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval: 1000 + save_interval_updates: 50 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: false + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 3200000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 1000 + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 2 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 13000 + lr: [0.00005] + sentence_avg: true + update_freq: [4] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_channel_prob: 0.25 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/finetuning/base_960h.yaml b/examples/wav2vec/config/finetuning/base_960h.yaml new file mode 100644 index 0000000000..d742c94abf --- /dev/null +++ b/examples/wav2vec/config/finetuning/base_960h.yaml @@ -0,0 +1,58 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: false + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 3200000 + skip_invalid_size_inputs_valid_test: true + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 320000 + lr: [0.00001] + sentence_avg: true + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.5 + mask_channel_prob: 0.1 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 0 + diff --git a/examples/wav2vec/config/finetuning/vox_100h.yaml b/examples/wav2vec/config/finetuning/vox_100h.yaml new file mode 100644 index 0000000000..8885c78470 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_100h.yaml @@ -0,0 +1,59 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: true + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 80000 + lr: [0.00003] + sentence_avg: true + update_freq: [5] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.5 + mask_channel_prob: 0.5 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/finetuning/vox_10h.yaml b/examples/wav2vec/config/finetuning/vox_10h.yaml new file mode 100644 index 0000000000..c0957c0058 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10h.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval: 50 + save_interval_updates: 10000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: true + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 50 + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 20000 + lr: [0.0001] + sentence_avg: true + update_freq: [5] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.75 + mask_channel_prob: 0.25 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/finetuning/vox_10m.yaml b/examples/wav2vec/config/finetuning/vox_10m.yaml new file mode 100644 index 0000000000..0d567552d7 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10m.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval: 1000 + save_interval_updates: 50 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: true + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 1000 + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 13000 + lr: [0.0001] + sentence_avg: true + update_freq: [5] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_channel_prob: 0.25 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/finetuning/vox_1h.yaml b/examples/wav2vec/config/finetuning/vox_1h.yaml new file mode 100644 index 0000000000..10c45a52d8 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_1h.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval: 1000 + save_interval_updates: 50 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: true + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 1000 + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 13000 + lr: [0.0003] + sentence_avg: true + update_freq: [5] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.75 + mask_channel_prob: 0.25 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/finetuning/vox_960h.yaml b/examples/wav2vec/config/finetuning/vox_960h.yaml new file mode 100644 index 0000000000..6212a2e738 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_960h.yaml @@ -0,0 +1,58 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_pretraining + data: ??? + normalize: true + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + valid_subset: dev_other + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 24 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 320000 + lr: [0.00003] + sentence_avg: true + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.5 + mask_channel_prob: 0.25 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + diff --git a/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml b/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml new file mode 100644 index 0000000000..e2c2b7b0b3 --- /dev/null +++ b/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml @@ -0,0 +1,55 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: ??? + max_sample_size: 250000 + min_sample_size: 32000 + +dataset: + num_workers: 6 + max_tokens: 1400000 + skip_invalid_size_inputs_valid_test: true + +distributed_training: + distributed_world_size: 64 + ddp_backend: no_c10d + +criterion: + _name: wav2vec + infonce: true + log_keys: ["prob_perplexity","code_perplexity","temp"] + loss_weights: [0.1, 10] + +optimization: + max_update: 400000 + lr: [0.0005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: wav2vec2 + quantize_targets: true + final_dim: 256 + encoder_layerdrop: 0.05 + dropout_input: 0.1 + dropout_features: 0.1 + feature_grad_mult: 0.1 diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml new file mode 100644 index 0000000000..0c911b7491 --- /dev/null +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml @@ -0,0 +1,69 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: ??? + max_sample_size: 320000 + min_sample_size: 32000 + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1200000 + skip_invalid_size_inputs_valid_test: true + +distributed_training: + distributed_world_size: 128 + ddp_backend: no_c10d + +criterion: + _name: wav2vec + infonce: true + log_keys: ["prob_perplexity","code_perplexity","temp"] + loss_weights: [0.1, 0] + +optimization: + max_update: 1000000 + lr: [0.005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: wav2vec2 + quantize_targets: true + extractor_mode: layer_norm + layer_norm_first: true + final_dim: 768 + latent_temp: [2.0,0.1,0.999995] + encoder_layerdrop: 0.00 + dropout_input: 0.0 + dropout_features: 0.0 + dropout: 0.0 + attention_dropout: 0.0 + conv_bias: true + + encoder_layers: 24 + encoder_embed_dim: 1024 + encoder_ffn_embed_dim: 4096 + encoder_attention_heads: 16 + + feature_grad_mult: 1.0 + diff --git a/fairseq/config/model/wav2vec2/wav2vec2_base.yaml b/fairseq/config/model/wav2vec2/wav2vec2_base.yaml new file mode 100644 index 0000000000..ce65499b80 --- /dev/null +++ b/fairseq/config/model/wav2vec2/wav2vec2_base.yaml @@ -0,0 +1,8 @@ +# @package _group_ + +quantize_targets: true +final_dim: 256 +encoder_layerdrop: 0.05 +dropout_input: 0.1 +dropout_features: 0.1 +feature_grad_mult: 0.1 diff --git a/fairseq/config/model/wav2vec2/wav2vec2_large.yaml b/fairseq/config/model/wav2vec2/wav2vec2_large.yaml new file mode 100644 index 0000000000..5846f75243 --- /dev/null +++ b/fairseq/config/model/wav2vec2/wav2vec2_large.yaml @@ -0,0 +1,20 @@ +# @package _group_ + +quantize_targets: true +extractor_mode: layer_norm +layer_norm_first: true +final_dim: 768 +latent_temp: [2.0,0.1,0.999995] +encoder_layerdrop: 0.0 +dropout_input: 0.0 +dropout_features: 0.0 +dropout: 0.0 +attention_dropout: 0.0 +conv_bias: true + +encoder_layers: 24 +encoder_embed_dim: 1024 +encoder_ffn_embed_dim: 4096 +encoder_attention_heads: 16 + +feature_grad_mult: 1.0 diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index 6b77ce47eb..deab4f2650 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -6,39 +6,92 @@ import math from argparse import Namespace +from dataclasses import dataclass, field +from omegaconf import II +from typing import Optional, Tuple import torch import torch.nn.functional as F from fairseq import metrics, utils -from fairseq.criterions import LegacyFairseqCriterion, register_criterion +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass from fairseq.data.data_utils import post_process +from fairseq.tasks import FairseqTask from fairseq.logging.meters import safe_round -@register_criterion("ctc") -class CtcCriterion(LegacyFairseqCriterion): - def __init__(self, args, task): - super().__init__(args, task) +@dataclass +class CtcCriterionConfig(FairseqDataclass): + zero_infinity: bool = field( + default=False, + metadata={"help": "zero inf loss when source length <= target length"}, + ) + sentence_avg: bool = II("optimization.sentence_avg") + post_process: str = field( + default="letter", + metadata={ + "help": "how to post process predictions into words. can be letter, " + "wordpiece, BPE symbols, etc. " + "See fairseq.data.data_utils.post_process() for full list of options" + }, + ) + wer_kenlm_model: Optional[str] = field( + default=None, + metadata={ + "help": "if this is provided, use kenlm to compute wer (along with other wer_* args)" + }, + ) + wer_lexicon: Optional[str] = field( + default=None, + metadata={"help": "lexicon to use with wer_kenlm_model"}, + ) + wer_lm_weight: float = field( + default=2.0, + metadata={"help": "lm weight to use with wer_kenlm_model"}, + ) + wer_word_score: float = field( + default=-1.0, + metadata={"help": "lm word score to use with wer_kenlm_model"}, + ) + + wer_args: Optional[str] = field( + default=None, + metadata={ + "help": "DEPRECATED: tuple of (wer_kenlm_model, wer_lexicon, wer_lm_weight, wer_word_score)" + }, + ) + + +@register_criterion("ctc", dataclass=CtcCriterionConfig) +class CtcCriterion(FairseqCriterion): + def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): + super().__init__(task) self.blank_idx = task.target_dictionary.bos() self.pad_idx = task.target_dictionary.pad() self.eos_idx = task.target_dictionary.eos() - self.post_process = args.post_process if args.post_process else "letter" + self.post_process = cfg.post_process - if args.wer_args is not None: - from examples.speech_recognition.w2l_decoder import W2lKenLMDecoder + if cfg.wer_args is not None: + ( + cfg.wer_kenlm_model, + cfg.wer_lexicon, + cfg.wer_lm_weight, + cfg.wer_word_score, + ) = eval(cfg.wer_args) - wer_compute_kenlm, wer_lexicon, lm_w, ws_w = eval(args.wer_args) + if cfg.wer_kenlm_model is not None: + from examples.speech_recognition.w2l_decoder import W2lKenLMDecoder dec_args = Namespace() dec_args.nbest = 1 dec_args.criterion = "ctc" - dec_args.kenlm_model = wer_compute_kenlm - dec_args.lexicon = wer_lexicon + dec_args.kenlm_model = cfg.wer_kenlm_model + dec_args.lexicon = cfg.wer_lexicon dec_args.beam = 50 dec_args.beam_size_token = min(50, len(task.target_dictionary)) dec_args.beam_threshold = min(50, len(task.target_dictionary)) - dec_args.lm_weight = lm_w - dec_args.word_score = ws_w + dec_args.lm_weight = cfg.wer_lm_weight + dec_args.word_score = cfg.wer_word_score dec_args.unk_weight = -math.inf dec_args.sil_weight = 0 @@ -46,31 +99,8 @@ def __init__(self, args, task): else: self.w2l_decoder = None - self.zero_infinity = args.zero_infinity - self.sentence_avg = args.sentence_avg - - @staticmethod - def add_args(parser): - """Add criterion-specific arguments to the parser.""" - parser.add_argument( - "--zero-infinity", action="store_true", help="zero inf loss" - ) - try: - parser.add_argument( - "--post-process", - "--remove-bpe", - default="letter", - help="remove BPE tokens before scoring (can be set to sentencepiece, letter, and more)", - ) - except: - pass # this option might have been added from eval args - parser.add_argument( - "--wer-args", - type=str, - default=None, - help="options for wer computation on valid set using 4 gram lm. this should be a tuple of 4 elements: path to 4-gram lm, \ - path to lexicon, lm score, word score", - ) + self.zero_infinity = cfg.zero_infinity + self.sentence_avg = cfg.sentence_avg def forward(self, model, sample, reduce=True): net_output = model(**sample["net_input"]) diff --git a/fairseq/criterions/fairseq_criterion.py b/fairseq/criterions/fairseq_criterion.py index b2eda1a7e4..ff4beb0250 100644 --- a/fairseq/criterions/fairseq_criterion.py +++ b/fairseq/criterions/fairseq_criterion.py @@ -7,8 +7,8 @@ from typing import Any, Dict, List from fairseq import metrics, utils +from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import gen_parser_from_dataclass -from omegaconf import DictConfig from torch.nn.modules.loss import _Loss @@ -28,7 +28,7 @@ def add_args(cls, parser): gen_parser_from_dataclass(parser, dc()) @classmethod - def build_criterion(cls, cfg: DictConfig, task): + def build_criterion(cls, cfg: FairseqDataclass, task): """Construct a criterion from command-line args.""" # arguments in the __init__. init_args = {} @@ -46,6 +46,8 @@ def build_criterion(cls, cfg: DictConfig, task): if p.name == "task": init_args["task"] = task + elif p.name == "cfg": + init_args["cfg"] = cfg elif hasattr(cfg, p.name): init_args[p.name] = getattr(cfg, p.name) elif p.default != p.empty: diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index ec921a41d7..28dc8905c7 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -874,7 +874,7 @@ class InteractiveConfig(FairseqDataclass): @dataclass -class FairseqConfig(object): +class FairseqConfig(FairseqDataclass): common: CommonConfig = CommonConfig() common_eval: CommonEvalConfig = CommonEvalConfig() distributed_training: DistributedTrainingConfig = DistributedTrainingConfig() diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index f8ed8f667f..a3a6c43281 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -5,6 +5,7 @@ import ast import os +import logging import re from argparse import ArgumentError, ArgumentParser, Namespace from dataclasses import _MISSING_TYPE, MISSING @@ -15,8 +16,11 @@ from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.configs import FairseqConfig from hydra.experimental import compose, initialize +from hydra.core.global_hydra import GlobalHydra from omegaconf import DictConfig, OmegaConf, open_dict +logger = logging.getLogger(__name__) + def eval_str_list(x, x_type=float): if x is None: @@ -210,7 +214,8 @@ def get_default(f): isinstance(val, str) and not val.startswith("${") # not interpolation and field_type != str - and inspect.isclass(field_type) and not issubclass(field_type, Enum) # not choices enum + and inspect.isclass(field_type) + and not issubclass(field_type, Enum) # not choices enum ): # upgrade old models that stored complex parameters as string val = ast.literal_eval(val) @@ -233,6 +238,10 @@ def get_default(f): overrides.append("{}.{}='{}'".format(sub_node, k, val)) elif isinstance(val, FairseqDataclass): overrides += _override_attr(f"{sub_node}.{k}", type(val), args) + elif isinstance(val, Namespace): + sub_overrides, _ = override_module_args(val) + for so in sub_overrides: + overrides.append(f"{sub_node}.{k}.{so}") else: overrides.append("{}.{}={}".format(sub_node, k, val)) @@ -321,8 +330,15 @@ def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: # configs will be in fairseq/config after installation config_path = os.path.join("..", "config") + GlobalHydra.instance().clear() + with initialize(config_path=config_path): - composed_cfg = compose("config", overrides=overrides, strict=False) + try: + composed_cfg = compose("config", overrides=overrides, strict=False) + except: + logger.error("Error when composing. Overrides: " + str(overrides)) + raise + for k in deletes: composed_cfg[k] = None @@ -374,7 +390,8 @@ def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: def populate_dataclass( - dataclass: FairseqDataclass, args: Namespace, + dataclass: FairseqDataclass, + args: Namespace, ) -> FairseqDataclass: for k in dataclass.__dataclass_fields__.keys(): if k.startswith("_"): diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index a00dc4d915..783ebcfe6b 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -92,7 +92,7 @@ class Wav2Vec2Config(FairseqDataclass): default=False, metadata={"help": "apply layernorm first in the transformer"} ) conv_feature_layers: str = field( - default="[(512, 10, 5), (512, 8, 4)] + [(512, 4, 2)] * 3 + [(512, 1, 1)]", + default="[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]", metadata={ "help": "string describing convolutional feature extraction layers in form of a python list that contains " "[(dim, kernel_size, stride), ...]" @@ -147,7 +147,7 @@ class Wav2Vec2Config(FairseqDataclass): default=0, metadata={ "help": "secondary mask argument (used for more complex distributions), " - "see help in compute_mask_indicesh" + "see help in compute_mask_indices" }, ) no_mask_overlap: bool = field( diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index f62ec633b4..790b0a8ad1 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -7,166 +7,145 @@ import contextlib import copy import math - import numpy as np import torch import torch.nn as nn import torch.nn.functional as F +from dataclasses import dataclass, field +from omegaconf import MISSING, II, open_dict +from typing import Any + from fairseq import checkpoint_utils, tasks, utils +from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.tasks import FairseqTask from fairseq.models import ( BaseFairseqModel, FairseqEncoder, FairseqEncoderDecoderModel, FairseqIncrementalDecoder, register_model, - register_model_architecture, ) +from fairseq.models.wav2vec.wav2vec2 import MASKING_DISTRIBUTION_CHOICES from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerDecoderLayer -def add_common_args(parser): - parser.add_argument("--w2v-path", help="path to wav2vec 2.0 model") - parser.add_argument( - "--no-pretrained-weights", - action="store_true", - help="if true, does not load pretrained weights", +@dataclass +class Wav2Vec2AsrConfig(FairseqDataclass): + w2v_path: str = field( + default=MISSING, metadata={"help": "path to wav2vec 2.0 model"} ) - parser.add_argument( - "--dropout-input", - type=float, - metavar="D", - help="dropout to apply to the input (after feat extr)", + no_pretrained_weights: bool = field( + default=False, metadata={"help": "if true, does not load pretrained weights"} ) - parser.add_argument( - "--final-dropout", - type=float, - metavar="D", - help="dropout after transformer and before final projection", + dropout_input: float = field( + default=0.0, + metadata={"help": "dropout to apply to the input (after feat extr)"}, ) - parser.add_argument( - "--apply-mask", action="store_true", help="apply masking during fine-tuning" + final_dropout: float = field( + default=0.0, + metadata={"help": "dropout after transformer and before final projection"}, ) - parser.add_argument( - "--dropout", - type=float, - metavar="D", - help="dropout probability inside wav2vec 2.0 model", + dropout: float = field( + default=0.0, metadata={"help": "dropout probability inside wav2vec 2.0 model"} ) - parser.add_argument( - "--attention-dropout", - type=float, - metavar="D", - help="dropout probability for attention weights inside wav2vec 2.0 model", + attention_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability for attention weights inside wav2vec 2.0 model" + }, ) - parser.add_argument( - "--activation-dropout", - "--relu-dropout", - type=float, - metavar="D", - help="dropout probability after activation in FFN inside wav2vec 2.0 model", + activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN inside wav2vec 2.0 model" + }, ) - parser.add_argument( - "--mask-length", type=int, help="repeat the mask indices multiple times" + # masking + apply_mask: bool = field( + default=False, metadata={"help": "apply masking during fine-tuning"} ) - - parser.add_argument( - "--mask-prob", type=float, help="probability of replacing a token with mask" + mask_length: int = field( + default=10, metadata={"help": "repeat the mask indices multiple times"} ) - - parser.add_argument( - "--mask-selection", - type=str, - choices=["static", "uniform", "normal", "poisson"], - help="how to choose masks", + mask_prob: float = field( + default=0.5, + metadata={ + "help": "probability of replacing a token with mask (normalized by length)" + }, ) - - parser.add_argument( - "--mask-other", - type=float, - help="stdev of the mask length in case of 'normal' selection strategy", + mask_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose masks"} ) - - parser.add_argument( - "--no-mask-overlap", - action="store_true", - help="whether to allow masks to overlap", - ) - - parser.add_argument( - "--mask-channel-length", type=int, help="repeat the mask indices multiple times" + mask_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument (used for more complex distributions), " + "see help in compute_mask_indices" + }, ) - - parser.add_argument( - "--mask-channel-prob", - type=float, - help="probability of replacing a token with mask", + no_mask_overlap: bool = field( + default=False, metadata={"help": "whether to allow masks to overlap"} ) - parser.add_argument( - "--mask-channel-selection", - type=str, - choices=["static", "uniform", "normal", "poisson"], - help="how to choose masks", + # channel masking + mask_channel_length: int = field( + default=10, metadata={"help": "length of the mask for features (channels)"} ) - - parser.add_argument( - "--mask-channel-other", - type=float, - help="stdev of the mask length in case of 'normal' selection strategy", + mask_channel_prob: float = field( + default=0.0, metadata={"help": "probability of replacing a feature with 0"} ) - - parser.add_argument( - "--no-mask-channel-overlap", - action="store_true", - help="whether to allow masks to overlap", + mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", + metadata={"help": "how to choose mask length for channel masking"}, ) - - parser.add_argument( - "--freeze-finetune-updates", + mask_channel_other: float = field( default=0, - type=int, - help="dont finetune wav2vec for this many updates", + metadata={ + "help": "secondary mask argument (used for more complex distributions), " + "see help in compute_mask_indicesh" + }, ) - - parser.add_argument( - "--feature-grad-mult", - default=None, - type=float, - help="reset feature grad mult in wav2vec 2.0 to this", + no_mask_channel_overlap: bool = field( + default=False, metadata={"help": "whether to allow channel masks to overlap"} ) - - parser.add_argument( - "--layerdrop", - default=0.0, - type=float, - help="probability of dropping a layer in wav2vec 2.0", + freeze_finetune_updates: int = field( + default=0, metadata={"help": "dont finetune wav2vec for this many updates"} + ) + feature_grad_mult: float = field( + default=0.0, metadata={"help": "reset feature grad mult in wav2vec 2.0 to this"} ) + layerdrop: float = field( + default=0.0, metadata={"help": "probability of dropping a layer in wav2vec 2.0"} + ) + normalize: bool = II("task.normalize") + data: str = II("task.data") + # this holds the loaded wav2vec args + w2v_args: Any = None -@register_model("wav2vec_ctc") -class Wav2VecCtc(BaseFairseqModel): - @staticmethod - def add_args(parser): - """Add model-specific arguments to the parser.""" - add_common_args(parser) +@dataclass +class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): + pass - def __init__(self, w2v_encoder, args): + +@register_model("wav2vec_ctc", dataclass=Wav2Vec2CtcConfig) +class Wav2VecCtc(BaseFairseqModel): + def __init__(self, cfg: Wav2Vec2CtcConfig, w2v_encoder: BaseFairseqModel): super().__init__() + self.cfg = cfg self.w2v_encoder = w2v_encoder - self.args = args def upgrade_state_dict_named(self, state_dict, name): super().upgrade_state_dict_named(state_dict, name) return state_dict @classmethod - def build_model(cls, args, task): + def build_model(cls, cfg: Wav2Vec2CtcConfig, task: FairseqTask): """Build a new model instance.""" - base_architecture(args) - w2v_encoder = Wav2VecEncoder(args, task.target_dictionary) - return cls(w2v_encoder, args) + w2v_encoder = Wav2VecEncoder(cfg, task.target_dictionary) + return cls(cfg, w2v_encoder) def get_normalized_probs(self, net_output, log_probs): """Get normalized probabilities (or log probs) from a net's output.""" @@ -181,96 +160,67 @@ def forward(self, **kwargs): x = self.w2v_encoder(**kwargs) return x - # def max_positions(self): - # return None +@dataclass +class Wav2Vec2Seq2SeqConfig(Wav2Vec2AsrConfig): + decoder_embed_dim: int = field( + default=768, metadata={"help": "decoder embedding dimension"} + ) + decoder_ffn_embed_dim: int = field( + default=3072, metadata={"help": "decoder embedding dimension for FFN"} + ) + decoder_layers: int = field(default=6, metadata={"help": "num of decoder layers"}) + decoder_layerdrop: float = field( + default=0.0, metadata={"help": "decoder layerdrop chance"} + ) + decoder_attention_heads: int = field( + default=4, metadata={"help": "num decoder attention heads"} + ) + decoder_learned_pos: bool = field( + default=False, + metadata={"help": "use learned positional embeddings in the decoder"}, + ) + decoder_normalize_before: bool = field( + default=False, metadata={"help": "apply layernorm before each decoder block"} + ) + no_token_positional_embeddings: bool = field( + default=False, + metadata={ + "help": "if set, disables positional embeddings (outside self attention)" + }, + ) + decoder_dropout: float = field( + default=0.0, metadata={"help": "dropout probability in the decoder"} + ) + decoder_attention_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability for attention weights inside the decoder" + }, + ) + decoder_activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN inside the decoder" + }, + ) + max_target_positions: int = field( + default=2048, metadata={"help": "max target positions"} + ) + share_decoder_input_output_embed: bool = field( + default=False, metadata={"help": "share decoder input and output embeddings"} + ) -@register_model("wav2vec_seq2seq") -class TransformerModel(FairseqEncoderDecoderModel): - def __init__(self, args, encoder, decoder): - super().__init__(encoder, decoder) - - @staticmethod - def add_args(parser): - add_common_args(parser) - - parser.add_argument( - "--decoder-embed-dim", - type=int, - metavar="N", - help="decoder embedding dimension", - ) - parser.add_argument( - "--decoder-ffn-embed-dim", - type=int, - metavar="N", - help="decoder embedding dimension for FFN", - ) - parser.add_argument( - "--decoder-layers", type=int, metavar="N", help="num decoder layers" - ) - parser.add_argument( - "--decoder-layerdrop", - type=float, - metavar="D", - help="decoder layerdrop chance", - ) - parser.add_argument( - "--decoder-attention-heads", - type=int, - metavar="N", - help="num decoder attention heads", - ) - parser.add_argument( - "--decoder-learned-pos", - action="store_true", - help="use learned positional embeddings in the decoder", - ) - parser.add_argument( - "--decoder-normalize-before", - action="store_true", - help="apply layernorm before each decoder block", - ) - parser.add_argument( - "--no-token-positional-embeddings", - default=False, - action="store_true", - help="if set, disables positional embeddings (outside self attention)", - ) - - parser.add_argument( - "--decoder-dropout", - type=float, - metavar="D", - help="dropout probability in the decoder", - ) - parser.add_argument( - "--decoder-attention-dropout", - type=float, - metavar="D", - help="dropout probability for attention weights inside the decoder", - ) - parser.add_argument( - "--decoder-activation-dropout", - type=float, - metavar="D", - help="dropout probability after activation in FFN inside the decoder", - ) - # fmt: on +@register_model("wav2vec_seq2seq", dataclass=Wav2Vec2Seq2SeqConfig) +class Wav2Vec2Seq2SeqModel(FairseqEncoderDecoderModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) @classmethod - def build_model(cls, args, task): + def build_model(cls, cfg: Wav2Vec2Seq2SeqConfig, task: FairseqTask): """Build a new model instance.""" - # make sure all arguments are present in older models - base_architecture(args) - - if not hasattr(args, "max_source_positions"): - args.max_source_positions = 2048 - if not hasattr(args, "max_target_positions"): - args.max_target_positions = 2048 - src_dict, tgt_dict = task.source_dictionary, task.target_dictionary def build_embedding(dictionary, embed_dim): @@ -279,19 +229,20 @@ def build_embedding(dictionary, embed_dim): emb = Embedding(num_embeddings, embed_dim, padding_idx) return emb - decoder_embed_tokens = build_embedding(tgt_dict, args.decoder_embed_dim) + decoder_embed_tokens = build_embedding(tgt_dict, cfg.decoder_embed_dim) + + encoder = cls.build_encoder(cfg) + decoder = cls.build_decoder(cfg, tgt_dict, decoder_embed_tokens) - encoder = cls.build_encoder(args) - decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens) - return TransformerModel(args, encoder, decoder) + return Wav2Vec2Seq2SeqModel(encoder, decoder) @classmethod - def build_encoder(cls, args): - return Wav2VecEncoder(args) + def build_encoder(cls, cfg: Wav2Vec2AsrConfig): + return Wav2VecEncoder(cfg) @classmethod - def build_decoder(cls, args, tgt_dict, embed_tokens): - return TransformerDecoder(args, tgt_dict, embed_tokens) + def build_decoder(cls, cfg: Wav2Vec2Seq2SeqConfig, tgt_dict, embed_tokens): + return TransformerDecoder(cfg, tgt_dict, embed_tokens) def forward(self, **kwargs): encoder_out = self.encoder(tbc=False, **kwargs) @@ -304,52 +255,50 @@ def upgrade_state_dict_named(self, state_dict, name): class Wav2VecEncoder(FairseqEncoder): - def __init__(self, args, tgt_dict=None): - self.apply_mask = args.apply_mask + def __init__(self, cfg: Wav2Vec2AsrConfig, tgt_dict=None): + self.apply_mask = cfg.apply_mask arg_overrides = { - "dropout": args.dropout, - "activation_dropout": args.activation_dropout, - "dropout_input": args.dropout_input, - "attention_dropout": args.attention_dropout, - "mask_length": args.mask_length, - "mask_prob": args.mask_prob, - "mask_selection": args.mask_selection, - "mask_other": args.mask_other, - "no_mask_overlap": args.no_mask_overlap, - "mask_channel_length": args.mask_channel_length, - "mask_channel_prob": args.mask_channel_prob, - "mask_channel_selection": args.mask_channel_selection, - "mask_channel_other": args.mask_channel_other, - "no_mask_channel_overlap": args.no_mask_channel_overlap, - "encoder_layerdrop": args.layerdrop, - "feature_grad_mult": args.feature_grad_mult, + "dropout": cfg.dropout, + "activation_dropout": cfg.activation_dropout, + "dropout_input": cfg.dropout_input, + "attention_dropout": cfg.attention_dropout, + "mask_length": cfg.mask_length, + "mask_prob": cfg.mask_prob, + "mask_selection": cfg.mask_selection, + "mask_other": cfg.mask_other, + "no_mask_overlap": cfg.no_mask_overlap, + "mask_channel_length": cfg.mask_channel_length, + "mask_channel_prob": cfg.mask_channel_prob, + "mask_channel_selection": cfg.mask_channel_selection, + "mask_channel_other": cfg.mask_channel_other, + "no_mask_channel_overlap": cfg.no_mask_channel_overlap, + "encoder_layerdrop": cfg.layerdrop, + "feature_grad_mult": cfg.feature_grad_mult, } - if getattr(args, "w2v_args", None) is None: - state = checkpoint_utils.load_checkpoint_to_cpu( - args.w2v_path, arg_overrides - ) + if cfg.w2v_args is None: + state = checkpoint_utils.load_checkpoint_to_cpu(cfg.w2v_path, arg_overrides) w2v_args = state.get("cfg", None) if w2v_args is None: w2v_args = convert_namespace_to_omegaconf(state["args"]) - args.w2v_args = w2v_args + cfg.w2v_args = w2v_args else: state = None - w2v_args = args.w2v_args + w2v_args = cfg.w2v_args if isinstance(w2v_args, Namespace): - args.w2v_args = w2v_args = convert_namespace_to_omegaconf(w2v_args) + cfg.w2v_args = w2v_args = convert_namespace_to_omegaconf(w2v_args) - assert ( - args.normalize == w2v_args.task.normalize - ), "Fine-tuning works best when data normalization is the same. " \ - "Please check that --normalize is set or unset for both" + assert cfg.normalize == w2v_args.task.normalize, ( + "Fine-tuning works best when data normalization is the same. " + "Please check that --normalize is set or unset for both pre-training and here" + ) - w2v_args.task.data = args.data + w2v_args.task.data = cfg.data task = tasks.setup_task(w2v_args.task) model = task.build_model(w2v_args.model) - if state is not None and not args.no_pretrained_weights: + if state is not None and not cfg.no_pretrained_weights: model.load_state_dict(state["model"], strict=True) model.remove_pretraining_modules() @@ -360,14 +309,14 @@ def __init__(self, args, tgt_dict=None): self.w2v_model = model - self.final_dropout = nn.Dropout(args.final_dropout) - self.freeze_finetune_updates = args.freeze_finetune_updates + self.final_dropout = nn.Dropout(cfg.final_dropout) + self.freeze_finetune_updates = cfg.freeze_finetune_updates self.num_updates = 0 if tgt_dict is not None: self.proj = Linear(d, len(tgt_dict)) - elif getattr(args, "decoder_embed_dim", d) != d: - self.proj = Linear(d, args.decoder_embed_dim) + elif getattr(cfg, "decoder_embed_dim", d) != d: + self.proj = Linear(d, cfg.decoder_embed_dim) else: self.proj = None @@ -436,21 +385,26 @@ class TransformerDecoder(FairseqIncrementalDecoder): (default: False). """ - def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): + def __init__( + self, + cfg: Wav2Vec2Seq2SeqConfig, + dictionary, + embed_tokens, + no_encoder_attn=False, + ): super().__init__(dictionary) - self.dropout = args.decoder_dropout - self.share_input_output_embed = args.share_decoder_input_output_embed + self.dropout = cfg.decoder_dropout + self.share_input_output_embed = cfg.share_decoder_input_output_embed input_embed_dim = embed_tokens.embedding_dim - embed_dim = args.decoder_embed_dim - self.output_embed_dim = args.decoder_embed_dim - args.encoder_embed_dim = embed_dim + embed_dim = cfg.decoder_embed_dim + self.output_embed_dim = cfg.decoder_embed_dim - self.layerdrop = args.decoder_layerdrop + self.layerdrop = cfg.decoder_layerdrop padding_idx = embed_tokens.padding_idx - self.max_target_positions = args.max_target_positions + self.max_target_positions = cfg.max_target_positions self.embed_tokens = embed_tokens self.embed_scale = math.sqrt(embed_dim) # todo: try with input_embed_dim @@ -463,25 +417,31 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): self.embed_positions = ( PositionalEmbedding( - args.max_target_positions, + cfg.max_target_positions, embed_dim, padding_idx, - learned=args.decoder_learned_pos, + learned=cfg.decoder_learned_pos, ) - if not args.no_token_positional_embeddings + if not cfg.no_token_positional_embeddings else None ) - args = copy.deepcopy(args) - args.dropout = args.decoder_dropout - args.attention_dropout = args.decoder_attention_dropout - args.activation_dropout = args.decoder_activation_dropout + # TODO: update this when transformer gets converted to dataclass configs + transformer_cfg = copy.deepcopy(cfg) + with open_dict(transformer_cfg): + transformer_cfg.dropout = transformer_cfg.decoder_dropout + transformer_cfg.attention_dropout = ( + transformer_cfg.decoder_attention_dropout + ) + transformer_cfg.activation_dropout = ( + transformer_cfg.decoder_activation_dropout + ) self.layers = nn.ModuleList([]) self.layers.extend( [ - TransformerDecoderLayer(args, no_encoder_attn) - for _ in range(args.decoder_layers) + TransformerDecoderLayer(transformer_cfg, no_encoder_attn) + for _ in range(transformer_cfg.decoder_layers) ] ) @@ -491,9 +451,7 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): ) nn.init.normal_(self.embed_out, mean=0, std=self.output_embed_dim ** -0.5) - if args.decoder_normalize_before and not getattr( - args, "no_decoder_final_norm", False - ): + if transformer_cfg.decoder_normalize_before: self.layer_norm = LayerNorm(embed_dim) else: self.layer_norm = None @@ -633,51 +591,3 @@ def Linear(in_features, out_features, bias=True): if bias: nn.init.constant_(m.bias, 0.0) return m - - -@register_model_architecture("wav2vec_ctc", "wav2vec_ctc") -def base_architecture(args): - args.no_pretrained_weights = getattr(args, "no_pretrained_weights", False) - args.dropout_input = getattr(args, "dropout_input", 0) - args.final_dropout = getattr(args, "final_dropout", 0) - args.apply_mask = getattr(args, "apply_mask", False) - args.dropout = getattr(args, "dropout", 0) - args.attention_dropout = getattr(args, "attention_dropout", 0) - args.activation_dropout = getattr(args, "activation_dropout", 0) - - args.mask_length = getattr(args, "mask_length", 10) - args.mask_prob = getattr(args, "mask_prob", 0.5) - args.mask_selection = getattr(args, "mask_selection", "static") - args.mask_other = getattr(args, "mask_other", 0) - args.no_mask_overlap = getattr(args, "no_mask_overlap", False) - args.mask_channel_length = getattr(args, "mask_channel_length", 10) - args.mask_channel_prob = getattr(args, "mask_channel_prob", 0.5) - args.mask_channel_selection = getattr(args, "mask_channel_selection", "static") - args.mask_channel_other = getattr(args, "mask_channel_other", 0) - args.no_mask_channel_overlap = getattr(args, "no_mask_channel_overlap", False) - - args.freeze_finetune_updates = getattr(args, "freeze_finetune_updates", 0) - args.feature_grad_mult = getattr(args, "feature_grad_mult", 0) - args.layerdrop = getattr(args, "layerdrop", 0.0) - - -@register_model_architecture("wav2vec_seq2seq", "wav2vec_seq2seq") -def seq2seq_architecture(args): - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4096) - args.decoder_layers = getattr(args, "decoder_layers", 10) - args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) - args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) - args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) - args.no_token_positional_embeddings = getattr( - args, "no_token_positional_embeddings", False - ) - args.decoder_dropout = getattr(args, "decoder_dropout", 0) - args.decoder_attention_dropout = getattr(args, "decoder_attention_dropout", 0) - args.decoder_activation_dropout = getattr(args, "decoder_activation_dropout", 0) - args.share_decoder_input_output_embed = getattr( - args, "share_decoder_input_output_embed", False - ) - - base_architecture(args) diff --git a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py index 63adc740a9..be9c9aec1d 100644 --- a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py +++ b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py @@ -3,53 +3,60 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from . import LegacyFairseqLRScheduler, register_lr_scheduler +from dataclasses import dataclass, field +from typing import Optional, List +from omegaconf import II +from fairseq.dataclass import FairseqDataclass +from . import FairseqLRScheduler, register_lr_scheduler -@register_lr_scheduler("polynomial_decay") -class PolynomialDecaySchedule(LegacyFairseqLRScheduler): + +@dataclass +class PolynomialDecayScheduleConfig(FairseqDataclass): + warmup_updates: int = field( + default=0, + metadata={"help": "warmup the learning rate linearly for the first N updates"}, + ) + force_anneal: Optional[int] = field( + default=None, + metadata={"help": "force annealing at specified epoch"}, + ) + end_learning_rate: float = field( + default=0.0, + metadata={"help": "learning rate to decay to"}, + ) + power: float = field( + default=1.0, + metadata={"help": "decay exponent"}, + ) + total_num_update: float = II("optimization.max_update") + lr: List[float] = II("optimization.lr") + + +@register_lr_scheduler("polynomial_decay", dataclass=PolynomialDecayScheduleConfig) +class PolynomialDecaySchedule(FairseqLRScheduler): """Decay the LR on a fixed schedule.""" - def __init__(self, args, optimizer): - super().__init__(args, optimizer) + cfg: PolynomialDecayScheduleConfig - # set defaults - args.warmup_updates = getattr(args, "warmup_updates", 0) or 0 + def __init__(self, cfg: PolynomialDecayScheduleConfig, optimizer): + super().__init__(cfg, optimizer) - self.lr = args.lr[0] - if args.warmup_updates > 0: - self.warmup_factor = 1.0 / args.warmup_updates + assert cfg.total_num_update > 0 + + self.lr = cfg.lr[0] + if cfg.warmup_updates > 0: + self.warmup_factor = 1.0 / cfg.warmup_updates else: self.warmup_factor = 1 - self.end_learning_rate = args.end_learning_rate - self.total_num_update = args.total_num_update - self.power = args.power + self.end_learning_rate = cfg.end_learning_rate + self.total_num_update = cfg.total_num_update + self.power = cfg.power self.optimizer.set_lr(self.warmup_factor * self.lr) - @staticmethod - def add_args(parser): - """Add arguments to the parser for this LR scheduler.""" - parser.add_argument( - "--force-anneal", - "--fa", - type=int, - metavar="N", - help="force annealing at specified epoch", - ) - parser.add_argument( - "--warmup-updates", - default=0, - type=int, - metavar="N", - help="warmup the learning rate linearly for the first N updates", - ) - parser.add_argument("--end-learning-rate", default=0.0, type=float) - parser.add_argument("--power", default=1.0, type=float) - parser.add_argument("--total-num-update", default=1000000, type=int) - def get_next_lr(self, epoch): - lrs = self.args.lr - if self.args.force_anneal is None or epoch < self.args.force_anneal: + lrs = self.cfg.lr + if self.cfg.force_anneal is None or epoch < self.cfg.force_anneal: # use fixed LR schedule next_lr = lrs[min(epoch, len(lrs) - 1)] else: @@ -65,13 +72,13 @@ def step_begin_epoch(self, epoch): def step_update(self, num_updates): """Update the learning rate after each update.""" - if self.args.warmup_updates > 0 and num_updates <= self.args.warmup_updates: - self.warmup_factor = num_updates / float(self.args.warmup_updates) + if self.cfg.warmup_updates > 0 and num_updates <= self.cfg.warmup_updates: + self.warmup_factor = num_updates / float(self.cfg.warmup_updates) lr = self.warmup_factor * self.lr elif num_updates >= self.total_num_update: lr = self.end_learning_rate else: - warmup = self.args.warmup_updates + warmup = self.cfg.warmup_updates lr_range = self.lr - self.end_learning_rate pct_remaining = 1 - (num_updates - warmup) / ( self.total_num_update - warmup diff --git a/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py b/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py index c573237f11..f0576d2d5f 100644 --- a/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py @@ -5,11 +5,47 @@ import math -from . import LegacyFairseqLRScheduler, register_lr_scheduler - - -@register_lr_scheduler("tri_stage") -class TriStageLRSchedule(LegacyFairseqLRScheduler): +from dataclasses import dataclass, field +from typing import Optional, List, Tuple +from omegaconf import II + +from fairseq.dataclass import FairseqDataclass +from . import FairseqLRScheduler, register_lr_scheduler + + +@dataclass +class TriStageLRScheduleConfig(FairseqDataclass): + warmup_steps: int = field( + default=0, + metadata={"help": "warmup the learning rate linearly for the first N updates"}, + ) + hold_steps: int = field( + default=0, + metadata={"help": "steps in hold stage"}, + ) + decay_steps: int = field( + default=0, + metadata={"help": "steps in decay stages"}, + ) + phase_ratio: Optional[Tuple[float, float, float]] = field( + default=None, + metadata={"help": "if set, automatically sets warmup/hold/decay steps to the ratio specified here " + "from max_updates. the ratios must add up to 1.0"}, + ) + init_lr_scale: float = field( + default=0.01, + metadata={"help": "initial learning rate scale during warmup phase"}, + ) + final_lr_scale: float = field( + default=0.01, + metadata={"help": "final learning rate scale"}, + ) + max_update: float = II("optimization.max_update") + lr: List[float] = II("optimization.lr") + + +@register_lr_scheduler("tri_stage", dataclass=TriStageLRScheduleConfig) +class TriStageLRScheduleConfig(FairseqLRScheduler): """Tristage learning rate schedulr Implement the learning rate scheduler in https://arxiv.org/pdf/1904.08779.pdf @@ -29,92 +65,60 @@ class TriStageLRSchedule(LegacyFairseqLRScheduler): During warmup:: - init_lr = args.init_lr_scale * args.lr - lrs = torch.linspace(init_lr, args.lr, args.warmup_steps) + init_lr = cfg.init_lr_scale * cfg.lr + lrs = torch.linspace(init_lr, cfg.lr, cfg.warmup_steps) lr = lrs[update_num] During hold:: - lr = args.lr + lr = cfg.lr During decay:: - decay_factor = - math.log(args.final_lr_scale) / args.decay_steps - lr = args.lr * exp(- (update_num - warmup_steps - decay_steps) * decay_factor) + decay_factor = - math.log(cfg.final_lr_scale) / cfg.decay_steps + lr = cfg.lr * exp(- (update_num - warmup_steps - decay_steps) * decay_factor) After that:: - lr = args.lr * args.final_lr_scale + lr = cfg.lr * cfg.final_lr_scale """ - def __init__(self, args, optimizer): - super().__init__(args, optimizer) - if len(args.lr) > 1: + def __init__(self, cfg: TriStageLRScheduleConfig, optimizer): + super().__init__(cfg, optimizer) + if len(cfg.lr) > 1: raise ValueError( "Cannot use a fixed learning rate schedule with tri-stage lr." " Consider --lr-scheduler=fixed instead." ) # calculate LR at each point - self.peak_lr = args.lr[0] - self.init_lr = args.init_lr_scale * args.lr[0] - self.final_lr = args.final_lr_scale * args.lr[0] - - # remember the steps at each stage - self.warmup_steps = args.warmup_steps - self.hold_steps = args.hold_steps - self.decay_steps = args.decay_steps + self.peak_lr = cfg.lr[0] + self.init_lr = cfg.init_lr_scale * cfg.lr[0] + self.final_lr = cfg.final_lr_scale * cfg.lr[0] + + if cfg.phase_ratio is not None: + assert sum(cfg.phase_ratio) == 1, 'phase ratios must add up to 1' + self.warmup_steps = int(cfg.max_update * cfg.phase_ratio[0]) + self.hold_steps = int(cfg.max_update * cfg.phase_ratio[1]) + self.decay_steps = int(cfg.max_update * cfg.phase_ratio[2]) + else: + self.warmup_steps = cfg.warmup_steps + self.hold_steps = cfg.hold_steps + self.decay_steps = cfg.decay_steps + + assert self.warmup_steps + self.hold_steps + self.decay_steps > 0, "please specify steps or phase_ratio" self.warmup_rate = ( (self.peak_lr - self.init_lr) / self.warmup_steps if self.warmup_steps != 0 else 0 ) - self.decay_factor = -math.log(args.final_lr_scale) / args.decay_steps + self.decay_factor = -math.log(cfg.final_lr_scale) / self.decay_steps # initial learning rate self.lr = self.init_lr self.optimizer.set_lr(self.lr) - @staticmethod - def add_args(parser): - """Add arguments to the parser for this LR scheduler.""" - # fmt: off - parser.add_argument( - '--warmup-steps', - default=4000, - type=int, - metavar='N', - help='warmup the learning rate linearly for the first N updates' - ) - parser.add_argument( - '--hold-steps', - default=20000, - type=int, - metavar='N', - help='steps in hold stage.' - ) - parser.add_argument( - '--decay-steps', - default=60000, - type=int, - metavar='N', - help='steps in decay stages' - ) - parser.add_argument( - '--init-lr-scale', - default=0.01, - type=float, - help=""" - initial learning rate scale during warmup phase; default is 0.01""") - parser.add_argument( - '--final-lr-scale', - default=0.01, - type=float, - help="final learning rate scale; default to 0.01" - ) - # fmt: on - def _decide_stage(self, update_step): """ return stage, and the corresponding steps within the current stage From 6e280bff2aecf5e7fe92d46aa2507c6cae036fe3 Mon Sep 17 00:00:00 2001 From: Suyoun Kim Date: Thu, 19 Nov 2020 14:56:54 -0800 Subject: [PATCH 062/774] set lr for each epoch by using input dictionary parameter Summary: [Manual LR Scheduler] set lr for each epoch by using input dictionary parameter Differential Revision: D25047764 fbshipit-source-id: 4b8ccfa1b1f5db99d73fdb478caa2c6ea8d80a50 --- .../optim/lr_scheduler/manual_lr_scheduler.py | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 fairseq/optim/lr_scheduler/manual_lr_scheduler.py diff --git a/fairseq/optim/lr_scheduler/manual_lr_scheduler.py b/fairseq/optim/lr_scheduler/manual_lr_scheduler.py new file mode 100644 index 0000000000..7e06ec55c8 --- /dev/null +++ b/fairseq/optim/lr_scheduler/manual_lr_scheduler.py @@ -0,0 +1,106 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from . import LegacyFairseqLRScheduler, register_lr_scheduler +import logging +import ast + +logger = logging.getLogger(__name__) +logger.setLevel(logging.WARNING) + + +@register_lr_scheduler("manual") +class ManualSchedule(LegacyFairseqLRScheduler): + """Decay the LR on a manual schedule.""" + + def __init__(self, args, optimizer): + super().__init__(args, optimizer) + + self.epoch2lr = self.parse_manuallr_args(args.epoch2lr) + self.update2lr = self.parse_manuallr_args(args.update2lr) + logger.info("@@@ ManualSchedule epoch2lr={}".format(self.epoch2lr)) + logger.info("@@@ ManualSchedule update2lr={}".format(self.update2lr)) + + if 1 in self.epoch2lr: + self.lr = self.epoch2lr[1] + elif 1 in self.update2lr: + self.lr = self.update2lr[1] + else: + self.lr = args.lr[0] + + def parse_manuallr_args(self, lr_args_str): + lr_dict = ast.literal_eval(lr_args_str) + if not isinstance(lr_dict, dict): + raise ValueError("epoch2lr/update2lr must be abel to evaluated to a dict") + + lr_args = {} + logger.info("@@@ after parsing input dictionary lr_dict = {}".format(lr_dict)) + for key, val in lr_dict.items(): + if "," in key: + for k in key.split(","): + lr_args[int(k)] = float(val) + elif "-" in key: + s = int(key.split("-")[0]) + e = int(key.split("-")[1]) + for k in range(s, e + 1, 1): + lr_args[k] = float(val) + else: + lr_args[int(key)] = float(val) + + return lr_args + + @staticmethod + def add_args(parser): + """Add arguments to the parser for this LR scheduler.""" + # fmt: off + parser.add_argument( + "--epoch2lr", + type=str, + metavar="DICT", + default="{}", + help="a dictionary used to set lr for each epoch manually", + ) + parser.add_argument( + "--update2lr", + type=str, + metavar="DICT", + default="{}", + help="a dictionary used to set lr for each update manually", + ) + # fmt: on + + def state_dict(self): + return {"lr": self.lr} + + def load_state_dict(self, state_dict): + if "lr" in state_dict: + self.lr = state_dict["lr"] + + def get_next_lr(self, epoch): + manual_keys = [k for k in self.epoch2lr if k <= epoch] + if manual_keys: + manual_lr = self.epoch2lr[max(manual_keys)] + else: + logger.warning("@@@ epoch={} does not exist in manual lr input. epoch2lr={}".format(epoch, self.epoch2lr)) + manual_lr = self.optimizer.get_lr() + return manual_lr + + def step_begin_epoch(self, epoch): + """Update the learning rate at the beginning of the given epoch.""" + self.lr = self.get_next_lr(epoch) + self.optimizer.set_lr(self.lr) + return self.optimizer.get_lr() + + def step_update(self, num_updates): + """Update the learning rate after each update.""" + manual_keys = [k for k in self.update2lr if k <= num_updates] + if manual_keys: + manual_lr = self.update2lr[max(manual_keys)] + else: + logger.warning("epoch={} does not exist in manual lr input update2lr={}".format(num_updates, self.update2lr)) + manual_lr = self.optimizer.get_lr() + + self.optimizer.set_lr(manual_lr) + return self.optimizer.get_lr() From 7171cdec5b15b983764dacbc618c572546a8a692 Mon Sep 17 00:00:00 2001 From: alexeib Date: Thu, 19 Nov 2020 15:02:18 -0800 Subject: [PATCH 063/774] fix interpolated fields not being added to argparse (#1450) Summary: we were skipping fields that are interpolated from being added to argparse, but now we add them if they have their own help. this affected --total-num-updates for polynomial decay Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1450 Reviewed By: huihuifan Differential Revision: D25098158 Pulled By: alexeib fbshipit-source-id: 105bc67cb5ddfc86475f3b50c5d1b5cc00330d85 --- fairseq/dataclass/utils.py | 6 +++++- fairseq/optim/lr_scheduler/polynomial_decay_schedule.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index a3a6c43281..15b87b9e4d 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -157,7 +157,11 @@ def get_kwargs_from_dc( if isinstance(kwargs["default"], str) and kwargs["default"].startswith( "${" ): - continue + if kwargs["help"] is None: + # this is a field with a name that will be added elsewhere + continue + else: + del kwargs["default"] if delete_default: del kwargs["default"] try: diff --git a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py index be9c9aec1d..2f6ae25c88 100644 --- a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py +++ b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py @@ -29,7 +29,10 @@ class PolynomialDecayScheduleConfig(FairseqDataclass): default=1.0, metadata={"help": "decay exponent"}, ) - total_num_update: float = II("optimization.max_update") + total_num_update: float = field( + default=II("optimization.max_update"), + metadata={"help": "total number of updates over which to decay learning rate"}, + ) lr: List[float] = II("optimization.lr") From 40fbb3744304de0eaa164fc84dd736d9a202a427 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 20 Nov 2020 05:59:25 -0800 Subject: [PATCH 064/774] Migrate remaining LR schedulers (#1448) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1448 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25092150 Pulled By: myleott fbshipit-source-id: fd066a0eba388bb0c344082a8fa1132974d53d40 --- fairseq/dataclass/utils.py | 6 +- .../optim/lr_scheduler/cosine_lr_scheduler.py | 35 +++--- .../lr_scheduler/fairseq_lr_scheduler.py | 3 +- fairseq/optim/lr_scheduler/fixed_schedule.py | 65 ++++++----- .../inverse_square_root_schedule.py | 35 +++--- .../lr_scheduler/polynomial_decay_schedule.py | 12 +- .../lr_scheduler/reduce_lr_on_plateau.py | 110 +++++++++++------- .../lr_scheduler/tri_stage_lr_scheduler.py | 22 ++-- .../lr_scheduler/triangular_lr_scheduler.py | 61 +++++----- 9 files changed, 191 insertions(+), 158 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 15b87b9e4d..694d878308 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -227,7 +227,11 @@ def get_default(f): if isinstance(val, tuple): val = list(val) - if getattr(v.type, "__origin__", None) is List: + if ( + getattr(v.type, "__origin__", None) is List + # skip interpolation + and not (isinstance(val, str) and val.startswith("${")) + ): # if type is int but val is float, then we will crash later - try to convert here t_args = v.type.__args__ if len(t_args) == 1: diff --git a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py index 646ac66be9..ef8645cd58 100644 --- a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py @@ -8,14 +8,14 @@ from dataclasses import dataclass, field from typing import List -from fairseq.dataclass import FairseqDataclass -from omegaconf import II, DictConfig +from omegaconf import II -from . import FairseqLRScheduler, register_lr_scheduler +from fairseq.dataclass import FairseqDataclass +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler @dataclass -class CosineConfig(FairseqDataclass): +class CosineLRScheduleConfig(FairseqDataclass): warmup_updates: int = field( default=0, metadata={"help": "warmup the learning rate linearly for the first N updates"}, @@ -23,11 +23,11 @@ class CosineConfig(FairseqDataclass): warmup_init_lr: float = field( default=-1, metadata={ - "help": "initial learning rate during warmup phase; default is args.lr" + "help": "initial learning rate during warmup phase; default is cfg.lr" }, ) max_lr: float = field( - default=1.0, metadata={"help": "max learning rate, must be more than args.lr"} + default=1.0, metadata={"help": "max learning rate, must be more than cfg.lr"} ) t_mult: float = field( default=1.0, metadata={"help": "factor to grow the length of each period"} @@ -38,13 +38,12 @@ class CosineConfig(FairseqDataclass): lr_shrink: float = field( default=0.1, metadata={"help": "shrink factor for annealing"} ) - # TODO common var for parent class lr: List[float] = II("optimization.lr") max_update: int = II("optimization.max_update") -@register_lr_scheduler("cosine", dataclass=CosineConfig) -class CosineSchedule(FairseqLRScheduler): +@register_lr_scheduler("cosine", dataclass=CosineLRScheduleConfig) +class CosineLRSchedule(FairseqLRScheduler): """Assign LR based on a cyclical schedule that follows the cosine function. See https://arxiv.org/pdf/1608.03983.pdf for details. @@ -55,7 +54,7 @@ class CosineSchedule(FairseqLRScheduler): During warmup:: - lrs = torch.linspace(args.warmup_init_lr, args.lr, args.warmup_updates) + lrs = torch.linspace(cfg.warmup_init_lr, cfg.lr, cfg.warmup_updates) lr = lrs[update_num] After warmup:: @@ -67,9 +66,7 @@ class CosineSchedule(FairseqLRScheduler): after every iteration. """ - def __init__( - self, cfg: DictConfig, fairseq_optimizer - ): + def __init__(self, cfg: CosineLRScheduleConfig, fairseq_optimizer): super().__init__(cfg, fairseq_optimizer) if isinstance(cfg.lr, Collection) and len(cfg.lr) > 1: raise ValueError( @@ -78,11 +75,7 @@ def __init__( ) warmup_end_lr = cfg.max_lr - lr = ( - cfg.lr[0] - if isinstance(cfg.lr, Collection) - else cfg.lr - ) + lr = cfg.lr[0] if isinstance(cfg.lr, Collection) else cfg.lr if cfg.warmup_init_lr < 0: cfg.warmup_init_lr = lr @@ -100,10 +93,8 @@ def __init__( self.period = cfg.max_update - cfg.warmup_updates if cfg.warmup_updates > 0: - # linearly warmup for the first args.warmup_updates - self.lr_step = ( - warmup_end_lr - cfg.warmup_init_lr - ) / cfg.warmup_updates + # linearly warmup for the first cfg.warmup_updates + self.lr_step = (warmup_end_lr - cfg.warmup_init_lr) / cfg.warmup_updates else: self.lr_step = 1 diff --git a/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py b/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py index d0ac115829..dd75dc5e30 100644 --- a/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py @@ -6,8 +6,7 @@ from argparse import Namespace from fairseq.dataclass.utils import gen_parser_from_dataclass - -from .. import FairseqOptimizer +from fairseq.optim import FairseqOptimizer class FairseqLRScheduler(object): diff --git a/fairseq/optim/lr_scheduler/fixed_schedule.py b/fairseq/optim/lr_scheduler/fixed_schedule.py index e91ba86f8c..d0e7e14b7e 100644 --- a/fairseq/optim/lr_scheduler/fixed_schedule.py +++ b/fairseq/optim/lr_scheduler/fixed_schedule.py @@ -3,37 +3,44 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from . import LegacyFairseqLRScheduler, register_lr_scheduler +from dataclasses import dataclass, field +from typing import Optional, List +from omegaconf import II +from fairseq.dataclass import FairseqDataclass +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler -@register_lr_scheduler("fixed") -class FixedSchedule(LegacyFairseqLRScheduler): - """Decay the LR on a fixed schedule.""" - def __init__(self, args, optimizer): - super().__init__(args, optimizer) +@dataclass +class FixedLRScheduleConfig(FairseqDataclass): + force_anneal: Optional[int] = field( + default=None, + metadata={"help": "force annealing at specified epoch"}, + ) + lr_shrink: float = field( + default=0.1, + metadata={"help": "shrink factor for annealing, lr_new = (lr * lr_shrink)"}, + ) + warmup_updates: int = field( + default=0, + metadata={"help": "warmup the learning rate linearly for the first N updates"}, + ) + lr: List[float] = II("optimization.lr") + - # set defaults - args.warmup_updates = getattr(args, "warmup_updates", 0) or 0 +@register_lr_scheduler("fixed", dataclass=FixedLRScheduleConfig) +class FixedLRSchedule(FairseqLRScheduler): + """Decay the LR on a fixed schedule.""" - self.lr = args.lr[0] - if args.warmup_updates > 0: - self.warmup_factor = 1.0 / args.warmup_updates + def __init__(self, cfg: FixedLRScheduleConfig, optimizer): + super().__init__(cfg, optimizer) + + self.lr = cfg.lr[0] + if cfg.warmup_updates > 0: + self.warmup_factor = 1.0 / cfg.warmup_updates else: self.warmup_factor = 1 - @staticmethod - def add_args(parser): - """Add arguments to the parser for this LR scheduler.""" - # fmt: off - parser.add_argument('--force-anneal', '--fa', type=int, metavar='N', - help='force annealing at specified epoch (epochs start at 1)') - parser.add_argument('--lr-shrink', default=0.1, type=float, metavar='LS', - help='shrink factor for annealing, lr_new = (lr * lr_shrink)') - parser.add_argument('--warmup-updates', default=0, type=int, metavar='N', - help='warmup the learning rate linearly for the first N updates') - # fmt: on - def state_dict(self): return {"lr": self.lr} @@ -42,14 +49,14 @@ def load_state_dict(self, state_dict): self.lr = state_dict["lr"] def get_next_lr(self, epoch): - lrs = self.args.lr - if self.args.force_anneal is None or epoch < self.args.force_anneal: + lrs = self.cfg.lr + if self.cfg.force_anneal is None or epoch < self.cfg.force_anneal: # use fixed LR schedule next_lr = lrs[min(epoch - 1, len(lrs) - 1)] else: # annneal based on lr_shrink - next_lr = lrs[-1] * self.args.lr_shrink ** ( - epoch + 1 - self.args.force_anneal + next_lr = lrs[-1] * self.cfg.lr_shrink ** ( + epoch + 1 - self.cfg.force_anneal ) return next_lr @@ -61,8 +68,8 @@ def step_begin_epoch(self, epoch): def step_update(self, num_updates): """Update the learning rate after each update.""" - if self.args.warmup_updates > 0 and num_updates < self.args.warmup_updates: - self.warmup_factor = (num_updates + 1) / float(self.args.warmup_updates) + if self.cfg.warmup_updates > 0 and num_updates < self.cfg.warmup_updates: + self.warmup_factor = (num_updates + 1) / float(self.cfg.warmup_updates) self.optimizer.set_lr(self.warmup_factor * self.lr) else: self.optimizer.set_lr(self.lr) diff --git a/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py b/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py index c42e090677..d9321577bb 100644 --- a/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py +++ b/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py @@ -7,14 +7,14 @@ from dataclasses import dataclass, field from typing import List -from fairseq.dataclass import FairseqDataclass -from omegaconf import II, DictConfig +from omegaconf import II -from . import FairseqLRScheduler, register_lr_scheduler +from fairseq.dataclass import FairseqDataclass +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler @dataclass -class InverseSquareRootScheduleConfig(FairseqDataclass): +class InverseSquareRootLRScheduleConfig(FairseqDataclass): warmup_updates: int = field( default=4000, metadata={"help": "warmup the learning rate linearly for the first N updates"}, @@ -22,14 +22,13 @@ class InverseSquareRootScheduleConfig(FairseqDataclass): warmup_init_lr: float = field( default=-1, metadata={ - "help": "initial learning rate during warmup phase; default is args.lr" + "help": "initial learning rate during warmup phase; default is cfg.lr" }, ) - # TODO common vars at parent class lr: List[float] = II("optimization.lr") -@register_lr_scheduler("inverse_sqrt", dataclass=InverseSquareRootScheduleConfig) +@register_lr_scheduler("inverse_sqrt", dataclass=InverseSquareRootLRScheduleConfig) class InverseSquareRootSchedule(FairseqLRScheduler): """Decay the LR based on the inverse square root of the update number. @@ -40,36 +39,28 @@ class InverseSquareRootSchedule(FairseqLRScheduler): During warmup:: - lrs = torch.linspace(args.warmup_init_lr, args.lr, args.warmup_updates) + lrs = torch.linspace(cfg.warmup_init_lr, cfg.lr, cfg.warmup_updates) lr = lrs[update_num] After warmup:: - decay_factor = args.lr * sqrt(args.warmup_updates) + decay_factor = cfg.lr * sqrt(cfg.warmup_updates) lr = decay_factor / sqrt(update_num) """ - def __init__(self, cfg: DictConfig, optimizer): + def __init__(self, cfg: InverseSquareRootLRScheduleConfig, optimizer): super().__init__(cfg, optimizer) if isinstance(cfg.lr, Collection) and len(cfg.lr) > 1: raise ValueError( "Cannot use a fixed learning rate schedule with inverse_sqrt." " Consider --lr-scheduler=fixed instead." ) - warmup_end_lr = ( - cfg.lr[0] - if isinstance(cfg.lr, Collection) - else cfg.lr - ) + warmup_end_lr = cfg.lr[0] if isinstance(cfg.lr, Collection) else cfg.lr if cfg.warmup_init_lr < 0: - cfg.warmup_init_lr = ( - 0 if cfg.warmup_updates > 0 else warmup_end_lr - ) + cfg.warmup_init_lr = 0 if cfg.warmup_updates > 0 else warmup_end_lr - # linearly warmup for the first args.warmup_updates - self.lr_step = ( - warmup_end_lr - cfg.warmup_init_lr - ) / cfg.warmup_updates + # linearly warmup for the first cfg.warmup_updates + self.lr_step = (warmup_end_lr - cfg.warmup_init_lr) / cfg.warmup_updates # then, decay prop. to the inverse square root of the update number self.decay_factor = warmup_end_lr * cfg.warmup_updates ** 0.5 diff --git a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py index 2f6ae25c88..b8109a7c1e 100644 --- a/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py +++ b/fairseq/optim/lr_scheduler/polynomial_decay_schedule.py @@ -8,11 +8,11 @@ from omegaconf import II from fairseq.dataclass import FairseqDataclass -from . import FairseqLRScheduler, register_lr_scheduler +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler @dataclass -class PolynomialDecayScheduleConfig(FairseqDataclass): +class PolynomialDecayLRScheduleConfig(FairseqDataclass): warmup_updates: int = field( default=0, metadata={"help": "warmup the learning rate linearly for the first N updates"}, @@ -36,13 +36,11 @@ class PolynomialDecayScheduleConfig(FairseqDataclass): lr: List[float] = II("optimization.lr") -@register_lr_scheduler("polynomial_decay", dataclass=PolynomialDecayScheduleConfig) -class PolynomialDecaySchedule(FairseqLRScheduler): +@register_lr_scheduler("polynomial_decay", dataclass=PolynomialDecayLRScheduleConfig) +class PolynomialDecayLRSchedule(FairseqLRScheduler): """Decay the LR on a fixed schedule.""" - cfg: PolynomialDecayScheduleConfig - - def __init__(self, cfg: PolynomialDecayScheduleConfig, optimizer): + def __init__(self, cfg: PolynomialDecayLRScheduleConfig, optimizer): super().__init__(cfg, optimizer) assert cfg.total_num_update > 0 diff --git a/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py b/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py index 82bb36efe9..6e29ba79b6 100644 --- a/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py +++ b/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py @@ -3,13 +3,59 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass, field +from typing import List + import torch.optim.lr_scheduler +from omegaconf import II + +from fairseq.dataclass import FairseqDataclass +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler + -from . import LegacyFairseqLRScheduler, register_lr_scheduler +@dataclass +class ReduceLROnPlateauLRScheduleConfig(FairseqDataclass): + lr_shrink: float = field( + default=0.1, metadata={"help": "shrink factor for annealing"} + ) + lr_threshold: float = field( + default=1e-4, + metadata={ + "help": ( + "threshold for measuring the new optimum, to only focus on " + "significant changes" + ) + }, + ) + lr_patience: int = field( + default=0, + metadata={ + "help": ( + "number of epochs with no improvement after which learning rate will " + "be reduced" + ) + }, + ) + warmup_updates: int = field( + default=0, + metadata={"help": "warmup the learning rate linearly for the first N updates"}, + ) + warmup_init_lr: float = field( + default=-1, + metadata={ + "help": "initial learning rate during warmup phase; default is cfg.lr" + }, + ) + lr: List[float] = II("optimization.lr") + maximize_best_checkpoint_metric: bool = II( + "checkpoint.maximize_best_checkpoint_metric" + ) -@register_lr_scheduler("reduce_lr_on_plateau") -class ReduceLROnPlateau(LegacyFairseqLRScheduler): +@register_lr_scheduler( + "reduce_lr_on_plateau", dataclass=ReduceLROnPlateauLRScheduleConfig +) +class ReduceLROnPlateauLRSchedule(FairseqLRScheduler): """ Decay the LR by a factor every time the validation loss plateaus. Also comes with optional warmup phase, where we linearly increase @@ -21,61 +67,43 @@ class ReduceLROnPlateau(LegacyFairseqLRScheduler): During warmup:: lrs = torch.linspace( - args.warmup_init_lr, args.lr, args.warmup_updates + cfg.warmup_init_lr, cfg.lr, cfg.warmup_updates ) lr = lrs[update_num] """ - def __init__(self, args, optimizer): - super().__init__(args, optimizer) - if len(args.lr) > 1: + def __init__(self, cfg: ReduceLROnPlateauLRScheduleConfig, optimizer): + super().__init__(cfg, optimizer) + if len(cfg.lr) > 1: raise ValueError( "Cannot use a fixed learning rate schedule with reduce_lr_on_plateau." " Consider --lr-scheduler=fixed instead." ) self.lr_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau( self.optimizer.optimizer, - patience=args.lr_patience, - factor=args.lr_shrink, - mode="max" if args.maximize_best_checkpoint_metric else "min", - threshold=args.lr_threshold, + patience=cfg.lr_patience, + factor=cfg.lr_shrink, + mode="max" if cfg.maximize_best_checkpoint_metric else "min", + threshold=cfg.lr_threshold, ) - warmup_end_lr = args.lr[0] - # if no warm up, sets initial lr to be args.lr[0] - if args.warmup_init_lr < 0: - args.warmup_init_lr = 0 if args.warmup_updates > 0 else warmup_end_lr + warmup_end_lr = cfg.lr[0] + # if no warm up, sets initial lr to be cfg.lr[0] + if cfg.warmup_init_lr < 0: + cfg.warmup_init_lr = 0 if cfg.warmup_updates > 0 else warmup_end_lr - # linearly warmup for the first args.warmup_updates - if args.warmup_updates > 0: - self.lr_step = (warmup_end_lr - args.warmup_init_lr) / args.warmup_updates + # linearly warmup for the first cfg.warmup_updates + if cfg.warmup_updates > 0: + self.lr_step = (warmup_end_lr - cfg.warmup_init_lr) / cfg.warmup_updates # this flag is either set from arg when no warm up, or set by # step_update() when warmup finishes - self.warmup_end = True if args.warmup_updates <= 0 else False + self.warmup_end = True if cfg.warmup_updates <= 0 else False # initial learning rate # this self.lr is used only during init and/or warm up period - self.lr = args.warmup_init_lr + self.lr = cfg.warmup_init_lr self.optimizer.set_lr(self.lr) - @staticmethod - def add_args(parser): - """Add arguments to the parser for this LR scheduler.""" - # fmt: off - parser.add_argument('--lr-shrink', default=0.1, type=float, metavar='LS', - help='shrink factor for annealing, lr_new = (lr * lr_shrink)') - parser.add_argument('--lr-threshold', default=1e-4, type=float, metavar='LT', - help='threshold for measuring the new optimum, ' - 'to only focus on significant changes') - parser.add_argument('--lr-patience', default=0, type=int, - help='number of epochs with no improvement after which ' - 'learning rate will be reduced') - parser.add_argument('--warmup-updates', default=0, type=int, metavar='N', - help='warmup the learning rate linearly for the first N updates') - parser.add_argument('--warmup-init-lr', default=-1, type=float, metavar='LR', - help='initial learning rate during warmup phase; default is args.lr') - # fmt: on - def state_dict(self): """Return the LR scheduler state dict.""" return { @@ -104,9 +132,9 @@ def step_update(self, num_updates): """ Update the learning rate after each update.""" # if there is warmup - if self.args.warmup_updates > 0: - if num_updates <= self.args.warmup_updates: - self.lr = self.args.warmup_init_lr + num_updates * self.lr_step + if self.cfg.warmup_updates > 0: + if num_updates <= self.cfg.warmup_updates: + self.lr = self.cfg.warmup_init_lr + num_updates * self.lr_step self.optimizer.set_lr(self.lr) else: if self.warmup_end is False: diff --git a/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py b/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py index f0576d2d5f..403de77c80 100644 --- a/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py @@ -4,13 +4,12 @@ # LICENSE file in the root directory of this source tree. import math - from dataclasses import dataclass, field from typing import Optional, List, Tuple from omegaconf import II from fairseq.dataclass import FairseqDataclass -from . import FairseqLRScheduler, register_lr_scheduler +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler @dataclass @@ -29,8 +28,12 @@ class TriStageLRScheduleConfig(FairseqDataclass): ) phase_ratio: Optional[Tuple[float, float, float]] = field( default=None, - metadata={"help": "if set, automatically sets warmup/hold/decay steps to the ratio specified here " - "from max_updates. the ratios must add up to 1.0"}, + metadata={ + "help": ( + "if set, automatically sets warmup/hold/decay steps to the ratio " + "specified here from max_updates. the ratios must add up to 1.0" + ) + }, ) init_lr_scale: float = field( default=0.01, @@ -42,7 +45,7 @@ class TriStageLRScheduleConfig(FairseqDataclass): ) max_update: float = II("optimization.max_update") lr: List[float] = II("optimization.lr") - + @register_lr_scheduler("tri_stage", dataclass=TriStageLRScheduleConfig) class TriStageLRScheduleConfig(FairseqLRScheduler): @@ -90,6 +93,7 @@ def __init__(self, cfg: TriStageLRScheduleConfig, optimizer): "Cannot use a fixed learning rate schedule with tri-stage lr." " Consider --lr-scheduler=fixed instead." ) + assert cfg.max_update > 0 # calculate LR at each point self.peak_lr = cfg.lr[0] @@ -97,7 +101,7 @@ def __init__(self, cfg: TriStageLRScheduleConfig, optimizer): self.final_lr = cfg.final_lr_scale * cfg.lr[0] if cfg.phase_ratio is not None: - assert sum(cfg.phase_ratio) == 1, 'phase ratios must add up to 1' + assert sum(cfg.phase_ratio) == 1, "phase ratios must add up to 1" self.warmup_steps = int(cfg.max_update * cfg.phase_ratio[0]) self.hold_steps = int(cfg.max_update * cfg.phase_ratio[1]) self.decay_steps = int(cfg.max_update * cfg.phase_ratio[2]) @@ -105,8 +109,10 @@ def __init__(self, cfg: TriStageLRScheduleConfig, optimizer): self.warmup_steps = cfg.warmup_steps self.hold_steps = cfg.hold_steps self.decay_steps = cfg.decay_steps - - assert self.warmup_steps + self.hold_steps + self.decay_steps > 0, "please specify steps or phase_ratio" + + assert ( + self.warmup_steps + self.hold_steps + self.decay_steps > 0 + ), "please specify steps or phase_ratio" self.warmup_rate = ( (self.peak_lr - self.init_lr) / self.warmup_steps diff --git a/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py b/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py index 0f3193f2b8..bfe2a0d381 100644 --- a/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py @@ -4,52 +4,61 @@ # LICENSE file in the root directory of this source tree. import math +from dataclasses import dataclass, field +from typing import List -from . import LegacyFairseqLRScheduler, register_lr_scheduler +from omegaconf import II +from fairseq.dataclass import FairseqDataclass +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler -@register_lr_scheduler("triangular") -class TriangularSchedule(LegacyFairseqLRScheduler): + +@dataclass +class TriangularLRScheduleConfig(FairseqDataclass): + max_lr: float = field( + default="???", metadata={"help": "max learning rate, must be more than cfg.lr"} + ) + lr_period_updates: float = field( + default=5000, + metadata={"help": "initial number of updates per period (cycle length)"}, + ) + lr_shrink: float = field( + default=0.1, metadata={"help": "shrink factor for annealing"} + ) + shrink_min: bool = field( + default=False, metadata={"help": "if set, also shrinks min lr"} + ) + lr: List[float] = II("optimization.lr") + + +@register_lr_scheduler("triangular", dataclass=TriangularLRScheduleConfig) +class TriangularLRSchedule(FairseqLRScheduler): """Assign LR based on a triangular cyclical schedule. See https://arxiv.org/pdf/1506.01186.pdf for details. """ - def __init__(self, args, optimizer): - super().__init__(args, optimizer) - if len(args.lr) > 1: + def __init__(self, cfg: TriangularLRScheduleConfig, optimizer): + super().__init__(cfg, optimizer) + if len(cfg.lr) > 1: raise ValueError( "Cannot use a fixed learning rate schedule with triangular." " Consider --lr-scheduler=fixed instead." ) - lr = args.lr[0] + lr = cfg.lr[0] - assert args.max_lr > lr, "max_lr must be more than lr" + assert cfg.max_lr > lr, "max_lr must be more than lr" self.min_lr = lr - self.max_lr = args.max_lr - self.stepsize = args.lr_period_updates // 2 - self.lr_shrink = args.lr_shrink - self.shrink_min = args.shrink_min + self.max_lr = cfg.max_lr + self.stepsize = cfg.lr_period_updates // 2 + self.lr_shrink = cfg.lr_shrink + self.shrink_min = cfg.shrink_min # initial learning rate self.lr = self.min_lr self.optimizer.set_lr(self.lr) - @staticmethod - def add_args(parser): - """Add arguments to the parser for this LR scheduler.""" - # fmt: off - parser.add_argument('--max-lr', required=True, type=float, metavar='LR', - help='max learning rate, must be more than args.lr') - parser.add_argument('--lr-period-updates', default=5000, type=float, metavar='LR', - help='initial number of updates per period (cycle length)') - parser.add_argument('--lr-shrink', default=0.1, type=float, metavar='LS', - help='shrink factor for annealing') - parser.add_argument('--shrink-min', action='store_true', - help='if set, also shrinks min lr') - # fmt: on - def step(self, epoch, val_loss=None): """Update the learning rate at the end of the given epoch.""" super().step(epoch, val_loss) From 3b77a6160097408e01883c69e6f8fed017266311 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 20 Nov 2020 05:59:25 -0800 Subject: [PATCH 065/774] Add fairseq-hydra-train and update docs (#1449) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1449 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25094525 Pulled By: myleott fbshipit-source-id: 430387d11196d3292933bb168cf09ea16ebc0d3b --- docs/hydra_integration.md | 226 ++++++++++++++++++------------- examples/wav2vec/README.md | 21 ++- fairseq/config/config.yaml | 6 +- fairseq/dataclass/configs.py | 6 + fairseq/modules/cross_entropy.py | 6 +- fairseq_cli/hydra_train.py | 34 ++++- setup.py | 17 ++- 7 files changed, 203 insertions(+), 113 deletions(-) diff --git a/docs/hydra_integration.md b/docs/hydra_integration.md index f924de961b..8e4082cb24 100644 --- a/docs/hydra_integration.md +++ b/docs/hydra_integration.md @@ -1,57 +1,70 @@ ## Hydra -[Hydra](https://github.com/facebookresearch/hydra) is an open-source Python framework that simplifies the development of -research and other complex applications. The key feature is the ability to dynamically create a hierarchical -configuration by composition and override it through config files and the command line. The name Hydra comes from its -ability to run multiple similar jobs - much like a Hydra with multiple heads. +[Hydra](https://github.com/facebookresearch/hydra) is an open-source Python +framework that simplifies the development of research and other complex +applications. The key feature is the ability to dynamically create a +hierarchical configuration by composition and override it through config files +and the command line. The name Hydra comes from its ability to run multiple +similar jobs - much like a Hydra with multiple heads. ## Motivation -Until recently, all components in fairseq were configured through a shared "args" namespace that was created at -application startup. Components declared their own "add_args" method to update the argparse parser, hoping that -the names would not clash with arguments from other components. While this model works for smaller applications, -as fairseq grew and became integrated into other applications, this became problematic. -In order to determine how to configure each component, one needed to a) examine what args were added by this component, and -b) read the code to figure out what shared arguments it is using that were added in other places. Reproducing -models involved sharing commands that often contained dozens of command line switches. - -The model described above is still supported by fairseq for backward compatibility, but will be deprecated some time -in the future. - -New components in fairseq should now create a dataclass that encapsulates all parameters required to configure this -component. The dataclass is registered along with the component, and fairseq takes care of constructing and -providing this configuration object to the component's constructor. Note that sharing parameters can optionally -still work, but one has to explicitly point to the "source of truth" (see inheritance example below). -These changes make components in fairseq -more independent and re-usable by other applications: all that is needed to create a component is to initialize its -dataclass and overwrite some of the defaults. - -While configuring fairseq through command line (using either the legacy argparse based or the new Hydra based entry points) is still -fully supported, you can now take advantage of configuring fairseq completely or piece-by-piece through -hierarchical YAML configuration files. These files can also be shipped as examples that others can use to run -an identically configured job. - -Additionally, Hydra has a rich and growing -[library of plugins](https://github.com/facebookresearch/hydra/tree/master/plugins) that provide functionality such as -hyperparameter sweeping (including using bayesian optimization through the [Ax](https://github.com/facebook/Ax) library), -job launching across various platforms, and more. +Until recently, all components in fairseq were configured through a shared +`args` namespace that was created at application startup. Components declared +their own `add_args` method to update the argparse parser, hoping that the names +would not clash with arguments from other components. While this model works for +smaller applications, as fairseq grew and became integrated into other +applications, this became problematic. In order to determine how to configure +each component, one needed to a) examine what args were added by this component, +and b) read the code to figure out what shared arguments it is using that were +added in other places. Reproducing models involved sharing commands that often +contained dozens of command line switches. + +The model described above is still supported by fairseq for backward +compatibility, but will be deprecated some time in the future. + +New components in fairseq should now create a dataclass that encapsulates all +parameters required to configure this component. The dataclass is registered +along with the component, and fairseq takes care of constructing and providing +this configuration object to the component's constructor. Note that sharing +parameters can optionally still work, but one has to explicitly point to the +"source of truth" (see inheritance example below). These changes make components +in fairseq more independent and re-usable by other applications: all that is +needed to create a component is to initialize its dataclass and overwrite some +of the defaults. + +While configuring fairseq through command line (using either the legacy argparse +based or the new Hydra based entry points) is still fully supported, you can now +take advantage of configuring fairseq completely or piece-by-piece through +hierarchical YAML configuration files. These files can also be shipped as +examples that others can use to run an identically configured job. + +Additionally, Hydra has a rich and growing [library of +plugins](https://github.com/facebookresearch/hydra/tree/master/plugins) that +provide functionality such as hyperparameter sweeping (including using bayesian +optimization through the [Ax](https://github.com/facebook/Ax) library), job +launching across various platforms, and more. ## Creating or migrating components -In general, each new (or updated) component should provide a companion [dataclass](https://www.python.org/dev/peps/pep-0557/). These dataclass are typically located in the same -file as the component and are passed as arguments to the register_*() functions. Top-level configs that should be -present in every fairseq application are placed in the [global](fairseq/dataclass/configs.py) config file and added -to the FairseqConfig object. - -Each dataclass is a plain-old-data object, similar to a NamedTuple. These classes are decorated with a @dataclass -decorator, and typically inherit from `FairseqDataclass` (which adds some functionality for backward compatibility). -Each field must have a type, and generally has metadata (such as a help string) and a default value. Only primitive types or other config objects are allowed as +In general, each new (or updated) component should provide a companion +[dataclass](https://www.python.org/dev/peps/pep-0557/). These dataclass are +typically located in the same file as the component and are passed as arguments +to the `register_*()` functions. Top-level configs that should be present in +every fairseq application are placed in the +[global](fairseq/dataclass/configs.py) config file and added to the +`FairseqConfig` object. + +Each dataclass is a plain-old-data object, similar to a `NamedTuple`. These +classes are decorated with a `@dataclass` decorator, and typically inherit from +`FairseqDataclass` (which adds some functionality for backward compatibility). +Each field must have a type, and generally has metadata (such as a help string) +and a default value. Only primitive types or other config objects are allowed as data types for each field. - Example: - +#### Example: -``` python +```python from dataclasses import dataclass, field from fairseq.dataclass import FairseqDataclass @@ -71,11 +84,12 @@ class InteractiveConfig(FairseqDataclass): ### Inherting values -Some components require sharing a value. For example, a learning rate scheduler and an optimizer may both need to -know the initial learning rate value. One can declare a field that, by default, will -inherit its value from another config node in the same hierarchy: +Some components require sharing a value. For example, a learning rate scheduler +and an optimizer may both need to know the initial learning rate value. One can +declare a field that, by default, will inherit its value from another config +node in the same hierarchy: -``` python +```python @dataclass FairseqAdamConfig(FairseqDataclass): ... @@ -83,18 +97,21 @@ FairseqAdamConfig(FairseqDataclass): ... ``` -`II("optimization.lr")` is syntactic sugar for `"${optimization.lr}"` , which is the value one can use in a YAML config file or through -command line to achieve the same effect. Note that this assumes that there is an "optimization" config object -in the root config and it has a field called "lr". +`II("optimization.lr")` is syntactic sugar for `"${optimization.lr}"`, which is +the value one can use in a YAML config file or through command line to achieve +the same effect. Note that this assumes that there is an "optimization" config +object in the root config and it has a field called "lr". ### Tasks and Models -Creating Tasks and Models works same as before, except that legacy implementations now inherit from Legacy* base classes, -while new components inherit from FairseqTask and FairseqModel and provide a dataclass to the register_*() functions. +Creating Tasks and Models works same as before, except that legacy +implementations now inherit from `LegacyFairseq*` base classes, while new +components inherit from `FairseqTask` and `FairseqModel` and provide a dataclass +to the `register_*()` functions. -Task example: +#### Task example: -``` python +```python @dataclass class LanguageModelingConfig(FairseqDataclass): data: Optional[str] = field( @@ -110,9 +127,9 @@ class LanguageModelingTask(LegacyFairseqTask): ... ``` -Model example: +#### Model example: -``` python +```python @dataclass class TransformerLanguageModelConfig(FairseqDataclass): activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( @@ -131,9 +148,10 @@ class TransformerLanguageModel(FairseqLanguageModel): ### Other components -Other components work as before, but they now take their configuration dataclass as the only constructor argument: +Other components work as before, but they now take their configuration dataclass +as the only constructor argument: -``` python +```python @dataclass class MosesTokenizerConfig(FairseqDataclass): source_lang: str = field(default="en", metadata={"help": "source language"}) @@ -145,50 +163,61 @@ class MosesTokenizer(object): ... ``` -Note that if you are adding a new registry for a new set of components, you need to add it to the FairseqConfig object in -fairseq/dataclass/configs.py: +Note that if you are adding a new registry for a new set of components, you need +to add it to the `FairseqConfig` object in `fairseq/dataclass/configs.py`: -``` python +```python @dataclass class FairseqConfig(object): ... my_new_registry: Any = None ``` -## Training with hydra_train.py +## Training with `fairseq-hydra-train` -To fully take advantage of configuration flexibility offered by Hydra, you may want to train new models using the -hydra_train.py entry point located in the fairseq_cli directory. Legacy CLI tools such as train.py, -will remain supported for the foreseeable future but will be deprecated eventually. +To fully take advantage of configuration flexibility offered by Hydra, you may +want to train new models using the `fairseq-hydra-train` entry point. Legacy CLI +tools such as `fairseq-train` will remain supported for the foreseeable future +but will be deprecated eventually. -On startup, Hydra will create a configuration object that contains a hierarchy of all the necessary dataclasses -populated with their default values in the code. The default values are overwritten by values found in YAML files in -fairseq/config directory (which currently just set default task, optimizer, etc) and then further overwritten by values -provided through command line arguments. +On startup, Hydra will create a configuration object that contains a hierarchy +of all the necessary dataclasses populated with their default values in the +code. The default values are overwritten by values found in YAML files in +`fairseq/config` directory (which currently sets minimal defaults) and then +further overwritten by values provided through command line arguments. Some of the most common use cases are shown below: -### 1. Overwrite default values through command line: +### 1. Override default values through command line: ```shell script -python fairseq_cli/hydra_train.py distributed_training.distributed_world_size=1 dataset.batch_size=2 task.data=data-bin \ -model=transformer_lm/transformer_lm_gpt task=language_modeling optimization.max_update=5000 - +$ fairseq-hydra-train \ + distributed_training.distributed_world_size=1 \ + dataset.batch_size=2 \ + task.data=data-bin \ + model=transformer_lm/transformer_lm_gpt \ + task=language_modeling \ + optimization.max_update=5000 ``` -Note that along with explicitly providing values for parameters such as dataset.batch_size, this also tells Hydra to overlay configuration found in `fairseq/config/model/transformer_lm/transformer_lm_gpt.yaml` -over the default values in the dataclass. If you want to train a model without specifying a particular architecture -you can simply specify model=transformer_lm. This only works for migrated tasks and models. +Note that along with explicitly providing values for parameters such as +`dataset.batch_size`, this also tells Hydra to overlay configuration found in +`fairseq/config/model/transformer_lm/transformer_lm_gpt.yaml` over the default +values in the dataclass. If you want to train a model without specifying a +particular architecture you can simply specify `model=transformer_lm`. This only +works for migrated tasks and models. ### 2. Replace bundled configs with an external config: ```shell script -python fairseq_cli/hydra_train.py --config-path /path/to/external/configs --config-name wiki103 +$ fairseq-hydra-train \ + --config-path /path/to/external/configs \ + --config-name wiki103 ``` -where /path/to/external/configs/wiki103.yaml contains: +where `/path/to/external/configs/wiki103.yaml` contains: -``` yaml +```yaml # @package _group_ model: @@ -211,24 +240,38 @@ lr_scheduler: _name: cosine ``` -Note that here bundled configs from `fairseq/config` directory are not used, however the defaults from each dataclass will still be used (unless overwritten by your external config). +Note that here bundled configs from `fairseq/config` directory are not used, +however the defaults from each dataclass will still be used (unless overwritten +by your external config). -Additionally you can choose to break up your configs by creating a directory structure in the same location as your main config file, with the names of the top-level fields -(such as "model", "dataset", etc), and placing config files with meaningful names that would populate that specific section of your -top-level config file (for example, you might have model/small_transformer_lm.yaml, model/big_transformer_lm.yaml, etc). You can then specify the correct configuration via command line, defaults in the main config, or even launch all of them as a sweep (see Hydra documentation on how to do this). +Additionally you can choose to break up your configs by creating a directory +structure in the same location as your main config file, with the names of the +top-level fields (such as "model", "dataset", etc), and placing config files +with meaningful names that would populate that specific section of your +top-level config file (for example, you might have +`model/small_transformer_lm.yaml`, `model/big_transformer_lm.yaml`, etc). You +can then specify the correct configuration via command line, defaults in the +main config, or even launch all of them as a sweep (see Hydra documentation on +how to do this). ### 3. Add an external config directory to Hydra search path: -This allows combining default configuration (including using any bundled config files), while specifying your own config files for some parts of the configuration. +This allows combining default configuration (including using any bundled config +files), while specifying your own config files for some parts of the +configuration. ```shell script -python fairseq_cli/hydra_train.py distributed_training.distributed_world_size=1 dataset.batch_size=2 \ -task.data=/path/to/data/ model=transformer_lm/2_layers task=language_modeling optimization.max_update=5000 \ ---config-dir /path/to/external/configs - +$ fairseq-hydra-train \ + distributed_training.distributed_world_size=1 \ + dataset.batch_size=2 \ + task.data=/path/to/data/ \ + model=transformer_lm/2_layers \ + task=language_modeling \ + optimization.max_update=5000 \ + --config-dir /path/to/external/configs ``` -where /path/to/external/configs has the following structure: +where `/path/to/external/configs` has the following structure: ``` . +-- model @@ -236,5 +279,6 @@ where /path/to/external/configs has the following structure: | | +-- 2_layers.yaml ``` -and 2_layers.yaml contains a copy of transformer_lm_gpt.yaml but with decoder_layers set to 2. You can add -other configs to configure other components as well. +and `2_layers.yaml` contains a copy of `transformer_lm_gpt.yaml` but with +`decoder_layers` set to 2. You can add other configs to configure other +components as well. diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 442a92553a..fdbf844ec7 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -56,8 +56,10 @@ This configuration was used for the base model trained on the Librispeech datase Note that the input is expected to be single channel, sampled at 16 kHz ```shell script -$ python fairseq_cli/hydra_train.py task.data=/path/to/data \ ---config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining --config-name wav2vec2_base_librispeech +$ fairseq-hydra-train \ + task.data=/path/to/data \ + --config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_base_librispeech ``` Note: you can simulate 64 GPUs by using k GPUs and adding command line parameters (before --config-path) @@ -68,8 +70,10 @@ Note: you can simulate 64 GPUs by using k GPUs and adding command line parameter This configuration was used for the large model trained on the Libri-light dataset in the wav2vec 2.0 paper ```shell script -$ python fairseq_cli/hydra_train.py task.data=/path/to/data \ ---config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining --config-name wav2vec2_large_librivox +$ fairseq-hydra-train \ + task.data=/path/to/data \ + --config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_large_librivox ``` Note: you can simulate 128 GPUs by using k GPUs and adding command line parameters (before --config-path) @@ -88,9 +92,12 @@ $ python libri_labels.py /path/to/tsv --output-dir /output/dir --output-name $sp Fine-tuning on 100h of Librispeech with letter targets: ```shell script -python fairseq_cli/hydra_train.py distributed_training.distributed_port=$PORT task.data=/path/to/data \ -model.w2v_path=/path/to/model.pt --config-path /path/to/fairseq-py/examples/wav2vec/config/finetuning \ ---config-name base_100h +$ fairseq-hydra-train \ + distributed_training.distributed_port=$PORT \ + task.data=/path/to/data \ + model.w2v_path=/path/to/model.pt \ + --config-path /path/to/fairseq-py/examples/wav2vec/config/finetuning \ + --config-name base_100h ``` There are other config files in the config/finetuning directory that can be used to fine-tune on other splits. diff --git a/fairseq/config/config.yaml b/fairseq/config/config.yaml index 039609aece..9621baa5e9 100644 --- a/fairseq/config/config.yaml +++ b/fairseq/config/config.yaml @@ -1,10 +1,10 @@ # @package _group_ defaults: - - task: language_modeling + - task: null - model: null - criterion: cross_entropy - - optimizer: adam - - lr_scheduler: cosine + - optimizer: null + - lr_scheduler: fixed - bpe: null - tokenizer: null - scoring: null diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 28dc8905c7..36d88d83f7 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -173,6 +173,12 @@ class CommonConfig(FairseqDataclass): profile: bool = field( default=False, metadata={"help": "enable autograd profiler emit_nvtx"} ) + reset_logging: bool = field( + default=True, + metadata={ + "help": "when using Hydra, reset the logging at the beginning of training" + }, + ) @dataclass diff --git a/fairseq/modules/cross_entropy.py b/fairseq/modules/cross_entropy.py index 0d2beb44bb..6f33c24cb5 100644 --- a/fairseq/modules/cross_entropy.py +++ b/fairseq/modules/cross_entropy.py @@ -26,12 +26,14 @@ def _cross_entropy_pytorch(logits, target, ignore_index=None, reduction="mean"): import xentropy_cuda from apex.contrib import xentropy - logger.info("using fused cross entropy") - def cross_entropy(logits, target, ignore_index=-100, reduction="mean"): if logits.device == torch.device("cpu"): return _cross_entropy_pytorch(logits, target, ignore_index, reduction) else: + if not getattr(cross_entropy, "_has_logged_once", False): + logger.info("using fused cross entropy") + cross_entropy._has_logged_once = True + half_to_float = logits.dtype == torch.half losses = xentropy.SoftmaxCrossEntropyLoss.apply( logits, diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index ffd3c5cd07..b092ce14ee 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -4,29 +4,32 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import hydra -from omegaconf import OmegaConf +import logging import os +import sys from fairseq.dataclass.initialize import hydra_init from fairseq_cli.train import main as pre_main from fairseq import distributed_utils from fairseq.dataclass.configs import FairseqConfig -import logging +import hydra import torch +from omegaconf import OmegaConf -logger = logging.getLogger(__name__) +logger = logging.getLogger("fairseq_cli.hydra_train") @hydra.main(config_path=os.path.join("..", "fairseq", "config"), config_name="config") def hydra_main(cfg: FairseqConfig) -> None: - cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) OmegaConf.set_struct(cfg, True) + if cfg.common.reset_logging: + reset_logging() # Hydra hijacks logging, fix that + if cfg.common.profile: with torch.cuda.profiler.profile(): with torch.autograd.profiler.emit_nvtx(): @@ -35,7 +38,22 @@ def hydra_main(cfg: FairseqConfig) -> None: distributed_utils.call_main(cfg, pre_main) -if __name__ == "__main__": +def reset_logging(): + root = logging.getLogger() + for handler in root.handlers: + root.removeHandler(handler) + root.setLevel(os.environ.get("LOGLEVEL", "INFO").upper()) + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter( + logging.Formatter( + fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + ) + root.addHandler(handler) + + +def cli_main(): try: from hydra._internal.utils import get_args @@ -46,3 +64,7 @@ def hydra_main(cfg: FairseqConfig) -> None: hydra_init(cfg_name) hydra_main() + + +if __name__ == "__main__": + cli_main() diff --git a/setup.py b/setup.py index 2aae720d7e..6bc450a7fa 100644 --- a/setup.py +++ b/setup.py @@ -22,14 +22,18 @@ def write_version_py(): # append latest commit hash to version string try: - sha = subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii").strip() + sha = ( + subprocess.check_output(["git", "rev-parse", "HEAD"]) + .decode("ascii") + .strip() + ) version += "+" + sha[:7] except Exception: pass # write version info to fairseq/version.py with open(os.path.join("fairseq", "version.py"), "w") as f: - f.write("__version__ = \"{}\"\n".format(version)) + f.write('__version__ = "{}"\n'.format(version)) return version @@ -194,7 +198,8 @@ def do_setup(package_data): "tests", "tests.*", ] - ) + extra_packages, + ) + + extra_packages, package_data=package_data, ext_modules=extensions, test_suite="tests", @@ -202,6 +207,7 @@ def do_setup(package_data): "console_scripts": [ "fairseq-eval-lm = fairseq_cli.eval_lm:cli_main", "fairseq-generate = fairseq_cli.generate:cli_main", + "fairseq-hydra-train = fairseq_cli.hydra_train:cli_main", "fairseq-interactive = fairseq_cli.interactive:cli_main", "fairseq-preprocess = fairseq_cli.preprocess:cli_main", "fairseq-score = fairseq_cli.score:cli_main", @@ -230,8 +236,11 @@ def get_files(path, relative_to="fairseq"): fairseq_examples = os.path.join("fairseq", "examples") if "build_ext" not in sys.argv[1:] and not os.path.exists(fairseq_examples): os.symlink(os.path.join("..", "examples"), fairseq_examples) + package_data = { - "fairseq": get_files("fairseq/examples"), + "fairseq": ( + get_files(fairseq_examples) + get_files(os.path.join("fairseq", "config")) + ) } do_setup(package_data) finally: From 94f59bb67bf48d2913dc223fc20b8e94c7ed1bab Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 20 Nov 2020 12:40:49 -0800 Subject: [PATCH 066/774] Remove unused train_masked_language_model helper (#1452) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1452 Test Plan: Imported from OSS Reviewed By: lematt1991 Differential Revision: D25108462 Pulled By: myleott fbshipit-source-id: 3c17a9937a4c3edb69f64130dfd866c5f42a4aaf --- tests/test_binaries.py | 66 ------------------------------------------ 1 file changed, 66 deletions(-) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 6dd95cb4a5..a53d84118b 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -1673,71 +1673,5 @@ def eval_lm_main(data_dir, extra_flags=None): eval_lm.main(eval_lm_args) -def train_masked_language_model(data_dir, arch, extra_args=()): - train_parser = options.get_training_parser() - # TODO: langs should be in and out right? - train_args = options.parse_args_and_arch( - train_parser, - [ - "--task", - "cross_lingual_lm", - data_dir, - "--arch", - arch, - # Optimizer args - "--optimizer", - "adam", - "--lr-scheduler", - "reduce_lr_on_plateau", - "--lr-shrink", - "0.5", - "--lr", - "0.0001", - "--min-lr", - "1e-09", - # dropout, attention args - "--dropout", - "0.1", - "--attention-dropout", - "0.1", - # MLM args - "--criterion", - "masked_lm_loss", - "--masked-lm-only", - "--monolingual-langs", - "in,out", - "--num-segment", - "5", - # Transformer args: use a small transformer model for fast training - "--encoder-layers", - "1", - "--encoder-embed-dim", - "32", - "--encoder-attention-heads", - "1", - "--encoder-ffn-embed-dim", - "32", - # Other training args - "--max-tokens", - "500", - "--tokens-per-sample", - "500", - "--save-dir", - data_dir, - "--max-epoch", - "1", - "--no-progress-bar", - "--distributed-world-size", - "1", - "--dataset-impl", - "raw", - "--num-workers", - "0", - ] - + list(extra_args), - ) - train.main(train_args) - - if __name__ == "__main__": unittest.main() From fa113ff1dee60bf493b6e61820303ab9d72cabcb Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 20 Nov 2020 12:40:49 -0800 Subject: [PATCH 067/774] Add test for activation checkpointing (#1453) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1453 Test Plan: Imported from OSS Reviewed By: sshleifer Differential Revision: D25108463 Pulled By: myleott fbshipit-source-id: 3cebce9be7fe503401eabba3f483c26847e7a3c0 --- fairseq/modules/checkpoint_activations.py | 5 +++-- tests/test_binaries.py | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index 1f99c24ca1..e0e5679c5a 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List, Tuple, Union import torch +import torch.utils.checkpoint as checkpoint from fairseq import utils @@ -133,7 +134,7 @@ class CheckpointFunction(torch.autograd.Function): @staticmethod def forward(ctx, run_function, parent_ctx_dict, kwarg_keys, *args): if torch.is_grad_enabled(): # grad may be disabled, e.g., during validation - torch.utils.checkpoint.check_backward_validity(args) + checkpoint.check_backward_validity(args) ctx.run_function = run_function ctx.kwarg_keys = kwarg_keys @@ -165,7 +166,7 @@ def backward(ctx, *args): ) tensor_inputs = ctx.saved_tensors - tensor_inputs = torch.utils.checkpoint.detach_variable(tensor_inputs) + tensor_inputs = checkpoint.detach_variable(tensor_inputs) inputs = unpack_non_tensors(tensor_inputs, ctx.packed_non_tensor_inputs) # Store the current states. diff --git a/tests/test_binaries.py b/tests/test_binaries.py index a53d84118b..8235702383 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -249,6 +249,29 @@ def test_transformer(self): ) generate_main(data_dir) + def test_transformer_with_activation_checkpointing(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + train_translation_model( + data_dir, + "transformer_iwslt_de_en", + [ + "--encoder-layers", + "2", + "--decoder-layers", + "2", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--checkpoint-activations", + ], + run_validation=True, + ) + generate_main(data_dir) + def test_multilingual_transformer(self): # test with all combinations of encoder/decoder lang tokens encoder_langtok_flags = [ From d464af2feb4f5f7149e10241cf1d064071f404e1 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 20 Nov 2020 12:40:49 -0800 Subject: [PATCH 068/774] Fix NAT code (#1454) Summary: D23752010 (https://github.com/pytorch/fairseq/commit/add65adcc53a927f99a717d90a9672765237d937) broke some GPU-only tests for NAT. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1454 Test Plan: Imported from OSS Reviewed By: jmp84 Differential Revision: D25108461 Pulled By: myleott fbshipit-source-id: f32b890221578c421944d6f9a49f06ef1dc075c6 --- fairseq/models/nat/fairseq_nat_model.py | 33 ++++++++++++------- fairseq/models/nat/levenshtein_transformer.py | 8 ++--- .../models/nat/nonautoregressive_ensembles.py | 9 +++-- tests/gpu/test_binaries_gpu.py | 26 ++++++++++----- tests/utils.py | 6 ++-- 5 files changed, 51 insertions(+), 31 deletions(-) diff --git a/fairseq/models/nat/fairseq_nat_model.py b/fairseq/models/nat/fairseq_nat_model.py index 1dbc29d0f4..b09394112f 100644 --- a/fairseq/models/nat/fairseq_nat_model.py +++ b/fairseq/models/nat/fairseq_nat_model.py @@ -18,18 +18,23 @@ def ensemble_encoder(func): def wrapper(self, *args, **kwargs): if self.ensemble_models is None or len(self.ensemble_models) == 1: return func(self, *args, **kwargs) - encoder_outs = [func(model, *args, **kwargs) for model in self.ensemble_models] - _encoder_out = encoder_outs[0] + encoder_outs = [func(model, *args, **kwargs, return_all_hiddens=True) for model in self.ensemble_models] + _encoder_out = encoder_outs[0].copy() def stack(key): - outs = [getattr(e, key) for e in encoder_outs] - return torch.stack(outs, -1) if outs[0] is not None else None + outs = [e[key][0] for e in encoder_outs] + return [torch.stack(outs, -1) if outs[0] is not None else None] - return _encoder_out._replace( - encoder_out=stack("encoder_out"), - encoder_embedding=stack("encoder_embedding"), - encoder_states=stack("encoder_states"), - ) + _encoder_out["encoder_out"] = stack("encoder_out") + _encoder_out["encoder_embedding"] = stack("encoder_embedding") + + num_layers = len(_encoder_out["encoder_states"]) + if num_layers > 0: + _encoder_out["encoder_states"] = [ + torch.stack([e["encoder_states"][i] for e in encoder_outs], -1) + for i in range(num_layers) + ] + return _encoder_out return wrapper @@ -41,12 +46,18 @@ def wrapper(self, normalize=False, encoder_out=None, *args, **kwargs): self, normalize=normalize, encoder_out=encoder_out, *args, **kwargs ) + def _replace(encoder_out, new_val): + new_encoder_out = encoder_out.copy() + new_encoder_out["encoder_out"] = [new_val] + return new_encoder_out + action_outs = [ func( model, normalize=normalize, - encoder_out=encoder_out._replace( - encoder_out=encoder_out.encoder_out[:, :, :, i] + encoder_out=_replace( + encoder_out, + encoder_out["encoder_out"][0][:, :, :, i] ), *args, **kwargs diff --git a/fairseq/models/nat/levenshtein_transformer.py b/fairseq/models/nat/levenshtein_transformer.py index 17f1ee99be..9377c3c7f5 100644 --- a/fairseq/models/nat/levenshtein_transformer.py +++ b/fairseq/models/nat/levenshtein_transformer.py @@ -149,11 +149,11 @@ def forward_decoder( if max_ratio is None: max_lens = torch.zeros_like(output_tokens).fill_(255) else: - if encoder_out.encoder_padding_mask is None: - max_src_len = encoder_out.encoder_out.size(0) - src_lens = encoder_out.encoder_out.new(bsz).fill_(max_src_len) + if not encoder_out["encoder_padding_mask"]: + max_src_len = encoder_out["encoder_out"].size(0) + src_lens = encoder_out["encoder_out"].new(bsz).fill_(max_src_len) else: - src_lens = (~encoder_out.encoder_padding_mask).sum(1) + src_lens = (~encoder_out["encoder_padding_mask"][0]).sum(1) max_lens = (src_lens * max_ratio).clamp(min=10).long() # delete words diff --git a/fairseq/models/nat/nonautoregressive_ensembles.py b/fairseq/models/nat/nonautoregressive_ensembles.py index 46bb8aac43..705a04fb49 100644 --- a/fairseq/models/nat/nonautoregressive_ensembles.py +++ b/fairseq/models/nat/nonautoregressive_ensembles.py @@ -83,14 +83,13 @@ def forward_decoder( if max_ratio is None: max_lens = output_tokens.new().fill_(255) else: - if encoder_outs[0].encoder_padding_mask is None: + if not encoder_outs[0]["encoder_padding_mask"]: src_lens = ( - encoder_outs[0] - .encoder_out.new(bsz) - .fill_(encoder_outs[0].encoder_out.size(1)) + encoder_outs[0]["encoder_out"][0].new(bsz) + .fill_(encoder_outs[0]["encoder_out"][0].size(1)) ) else: - src_lens = (~encoder_outs[0].encoder_padding_mask).sum(1) + src_lens = (~encoder_outs[0]["encoder_padding_mask"][0]).sum(1) max_lens = (src_lens * max_ratio).clamp(min=10).long() # delete words diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 2ac60a0934..5690e73752 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -93,17 +93,25 @@ def test_levenshtein_transformer(self): ], task="translation_lev", ) + gen_config = [ + "--task", + "translation_lev", + "--iter-decode-max-iter", + "9", + "--iter-decode-eos-penalty", + "0", + "--print-step", + ] + # non-ensemble generation + generate_main(data_dir, gen_config) + # ensemble generation generate_main( data_dir, - [ - "--task", - "translation_lev", - "--iter-decode-max-iter", - "9", - "--iter-decode-eos-penalty", - "0", - "--print-step", - ], + gen_config, + path=os.pathsep.join([ + os.path.join(data_dir, "checkpoint_last.pt"), + os.path.join(data_dir, "checkpoint_last.pt"), + ]), ) diff --git a/tests/utils.py b/tests/utils.py index a145aa587d..178df5763e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -345,18 +345,20 @@ def train_translation_model( validate.main(validate_args) -def generate_main(data_dir, extra_flags=None): +def generate_main(data_dir, extra_flags=None, path=None): if extra_flags is None: extra_flags = [ "--print-alignment", ] + if path is None: + path = os.path.join(data_dir, "checkpoint_last.pt") generate_parser = options.get_generation_parser() generate_args = options.parse_args_and_arch( generate_parser, [ data_dir, "--path", - os.path.join(data_dir, "checkpoint_last.pt"), + path, "--beam", "3", "--batch-size", From e419db74e2ae557c60b6cbf304ae9f8cc812d9dd Mon Sep 17 00:00:00 2001 From: Wei Ho Date: Fri, 20 Nov 2020 14:45:04 -0800 Subject: [PATCH 069/774] Add extra logging before/after checkpointing Summary: Makes it easier for ppl to notice if things break in the middle of writing checkpoint (ex: OOMing) (Also helps provide timing stats for how long it took to write checkpoints) Reviewed By: donhusa Differential Revision: D25120107 fbshipit-source-id: 35a7e9b7fe22a1ffa25fb8b461e7b7bef09fa063 --- fairseq/trainer.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index d7ba0be874..e9ac3c6bb1 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -178,10 +178,7 @@ def criterion(self): @property def model(self): if self._wrapped_model is None: - if ( - self.data_parallel_world_size > 1 - and not self.cfg.optimization.use_bmuf - ): + if self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf: self._wrapped_model = models.DistributedFairseqModel( self.cfg.distributed_training, self._model, @@ -266,6 +263,10 @@ def consolidate_optimizer(self): def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" if self.is_data_parallel_master: # only save one checkpoint + logger.info( + f"Preparing to save checkpoint to {filename} after " + f"{self.get_num_updates()} updates" + ) extra_state["metrics"] = metrics.state_dict() extra_state["previous_training_time"] = self.cumulative_training_time() checkpoint_utils.save_state( @@ -279,6 +280,7 @@ def save_checkpoint(self, filename, extra_state): self._optim_history, extra_state, ) + logger.info(f"Finished saving checkpoint to {filename}") def load_checkpoint( self, From 521fccf93c821cabb3686b768f9d9152486b5bd6 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 20 Nov 2020 19:16:50 -0800 Subject: [PATCH 070/774] Fix torch.distributed.launch (fixes #2924) (#1456) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1456 Reviewed By: alexeib Differential Revision: D25133448 Pulled By: myleott fbshipit-source-id: 8a7573b69c471b237fffdfc7874f9f6b51143f5a --- fairseq/dataclass/configs.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 36d88d83f7..2cbfc9560a 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -209,10 +209,6 @@ class DistributedTrainingConfig(FairseqDataclass): }, ) device_id: int = field( - default=0, - metadata={"help": "which GPU to use (usually configured automatically)"}, - ) - local_rank: int = field( default=0, metadata={ "help": "which GPU to use (usually configured automatically)", From 2b854d8517c3398e576ff4bf8cc5f59c90af74c4 Mon Sep 17 00:00:00 2001 From: Kritika Singh Date: Sat, 21 Nov 2020 12:02:02 -0800 Subject: [PATCH 071/774] wav2vec in PySpeech Summary: Define `audio_pretraining_fb` task similar to [`audio_pretraining`](https://www.internalfb.com/intern/codesearch/path/fbsource/fbcode/deeplearning/projects/fairseq-py/fairseq/tasks/audio_pretraining.py) in fairseq. I was earlier trying to stay as close to the fairseq task as possible but sub-classing `FbSpeechRecognitionTask` from pyspeech made decoding much easier. The main differences between the fairseq and pyspeech end-to-end processes are: a. Inputs to the training `fairseq`: train.tsv, train.labels.txt, valid.tsv, valid.labels.txt, dict.labels.txt `pyspeech`: data.json. An example is: ```{ "fairseq_dict": "spm_char_32_fairseq.dict", "train": { "handles_file": "train_dataaug_full.tsv", "transforms": [ ["RawAudioDatasetTransform", {}], ["SentencePieceEncodeTransform", {"model_path": "spm_char_32.model", "append_eos": false}] ] }, "valid": { "handles_file": "valid_pages_10s_full.tsv", "transforms": [ ["RawAudioDatasetTransform", {}], ["SentencePieceEncodeTransform", {"model_path": "spm_char_32.model", "append_eos": false}] ] } } ``` The handles files follow the format `{handle}\t{length}\t{optional_ref}` b. Encoding the reference into target units: fairseq process was to use a dictionary file to specify the target units, an offline script [libri_labels.py](https://www.internalfb.com/intern/codesearch/path/fbsource/fbcode/deeplearning/projects/fairseq-py/examples/wav2vec/libri_labels.py) to split the reference and LabelEncoder to get the target unit sequence. This is replaced by [`SentencepieceEncodeTransform`](https://www.internalfb.com/intern/codesearch/path/fbsource/fbcode/deeplearning/projects/pyspeech/pyspeech/data/transforms/sentence_piece_encode_transform.py) such that when you pass a sentencepiece model and dictionary (from sentencepiece library) to the training, the transformations happen on the fly. c. FairseqDataset class: I use `FbEverstoreDataset` in place of `EverstoreAudioDataset` (from fairseq) to be able to use the existing pre-processing transforms like `SentencepieceEncodeTransform` and easier integration with CTC decoder. This required copying over the audio processing and collater code pieces from RawAudioDataset to new PySpeechTransform and collator classes. Reviewed By: alexeib Differential Revision: D24265820 fbshipit-source-id: 68e2fef38a0cc1cf316410d83ed405d62a810578 --- fairseq/criterions/ctc.py | 2 +- fairseq/tasks/audio_pretraining.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index deab4f2650..b218175f21 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -66,7 +66,7 @@ class CtcCriterionConfig(FairseqDataclass): class CtcCriterion(FairseqCriterion): def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): super().__init__(task) - self.blank_idx = task.target_dictionary.bos() + self.blank_idx = task.target_dictionary.index(task.blank_symbol) self.pad_idx = task.target_dictionary.pad() self.eos_idx = task.target_dictionary.eos() self.post_process = cfg.post_process diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index a2f7edc34d..6ea40a813f 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -106,6 +106,7 @@ def __init__( self._source_dictionary = source_dictionary if cfg.eval_wer: assert cfg.labels is not None, "eval_wer can only be set during fine-tuning" + self.blank_symbol = "" @classmethod def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): From b1b02a828fec708aea1718e5336dd941a24f4276 Mon Sep 17 00:00:00 2001 From: Tim Dettmers Date: Sat, 21 Nov 2020 18:39:00 -0800 Subject: [PATCH 072/774] Fixed min-lr / max-lr swap on cosine schedule. (#2916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? The cosine learning rate scheduler was implemented incorrectly. It annealed to the learning rate (`--lr`) instead of the minimum learning rate (`--min-lr`). This implementation is consistent with the PyTorch [CosineAnnealingLR](https://github.com/pytorch/pytorch/blob/master/torch/optim/lr_scheduler.py#L461). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2916 Reviewed By: alexeib Differential Revision: D25146468 Pulled By: myleott fbshipit-source-id: 8704b6954dd40692eb930b882fecfa799ea98b00 --- fairseq/optim/lr_scheduler/cosine_lr_scheduler.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py index ef8645cd58..d73c7cc7ed 100644 --- a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py @@ -79,8 +79,10 @@ def __init__(self, cfg: CosineLRScheduleConfig, fairseq_optimizer): if cfg.warmup_init_lr < 0: cfg.warmup_init_lr = lr - self.min_lr = lr - self.max_lr = cfg.max_lr + # default min_lr=-1 -> cosine anneale to lr=0.0 + # otherwise pick min_lr from config + self.min_lr = cfg.min_lr if cfg.min_lr > 0.0 else 0.0 + self.max_lr = lr assert self.max_lr > self.min_lr, "max_lr must be more than lr" self.t_mult = cfg.t_mult From 158bd0321c4b915e4bddf738f5cb9d72d192f969 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sat, 21 Nov 2020 18:43:09 -0800 Subject: [PATCH 073/774] Add .github/stale.yml (#2932) Summary: Mostly copied from https://github.com/facebook/react/blob/master/.github/stale.yml Pull Request resolved: https://github.com/pytorch/fairseq/pull/2932 Reviewed By: alexeib Differential Revision: D25146465 Pulled By: myleott fbshipit-source-id: c11d695dcbd2f18609c04af2e520317977797e0f --- .github/stale.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..b12867dab0 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,30 @@ +# Configuration for probot-stale - https://github.com/probot/stale +# Mostly copied from github.com/facebook/react/blob/master/.github/stale.yml +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 90 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - bug +# Label to use when marking an issue as stale +staleLabel: stale +issues: + # Comment to post when marking an issue as stale. + markComment: > + This issue has been automatically marked as stale. + **If this issue is still affecting you, please leave any comment** (for example, "bump"), and we'll keep it open. + We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment! + # Comment to post when closing a stale issue. + closeComment: > + Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please create a new issue with up-to-date information. Thank you! +pulls: + # Comment to post when marking a pull request as stale. + markComment: > + This pull request has been automatically marked as stale. + **If this pull request is still relevant, please leave any comment** (for example, "bump"), and we'll keep it open. + We are sorry that we haven't been able to prioritize reviewing it yet. Your contribution is very much appreciated. + # Comment to post when closing a stale pull request. + closeComment: > + Closing this pull request after a prolonged period of inactivity. If this issue is still present in the latest release, please ask for this pull request to be reopened. Thank you! + From b889b52ae9b91a0114112d00735df56c1aa36fad Mon Sep 17 00:00:00 2001 From: Xu Song Date: Sat, 21 Nov 2020 19:29:07 -0800 Subject: [PATCH 074/774] Update hub_utils.py (#2910) Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? has no attribute 'arg' Pull Request resolved: https://github.com/pytorch/fairseq/pull/2910 Reviewed By: alexeib Differential Revision: D25146481 Pulled By: myleott fbshipit-source-id: 11912bb2bcacd1d2f91da47bb0d868da90b38f17 --- fairseq/hub_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index 3be7078b7a..1819a9460a 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -180,7 +180,7 @@ def generate( if verbose: def getarg(name, default): - return getattr(gen_args, name, getattr(self.args, name, default)) + return getattr(gen_args, name, getattr(self.cfg, name, default)) for source_tokens, target_hypotheses in zip(tokenized_sentences, outputs): src_str_with_unk = self.string(source_tokens) From 8e328aec86a2afee83c77095d0b5bb2c449ed5c4 Mon Sep 17 00:00:00 2001 From: alexeib Date: Sat, 21 Nov 2020 22:50:04 -0800 Subject: [PATCH 075/774] minor fixes (#1457) Summary: - some minor fixes a) secondary loss logging in wav2vec criterion b) ability to have nested Dict[...] inside config objects c) remove debug param Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1457 Reviewed By: myleott Differential Revision: D25145151 Pulled By: alexeib fbshipit-source-id: 21e6422b91151b00b929447f0c73deced56450cb --- fairseq/criterions/ctc.py | 5 ++++- fairseq/criterions/wav2vec_criterion.py | 15 ++++++--------- fairseq/dataclass/utils.py | 3 ++- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index b218175f21..0e4e3577d2 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -118,7 +118,10 @@ def forward(self, model, sample, reduce=True): sample["target"] != self.eos_idx ) targets_flat = sample["target"].masked_select(pad_mask) - target_lengths = sample["target_lengths"] + if "target_lengths" in sample: + target_lengths = sample["target_lengths"] + else: + target_lengths = pad_mask.sum(-1) with torch.backends.cudnn.flags(enabled=False): loss = F.ctc_loss( diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index 3a58390088..8a1c348a58 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -41,7 +41,7 @@ def __init__(self, task, infonce=False, loss_weights=None, log_keys=None): self.loss_weights = loss_weights self.log_keys = [] if log_keys is None else log_keys - def forward(self, model, sample, reduce=True, log_pred=False): + def forward(self, model, sample, reduce=True): """Compute the loss for the given sample. Returns a tuple with three elements: @@ -125,9 +125,6 @@ def forward(self, model, sample, reduce=True, log_pred=False): logging_output["correct"] = corr logging_output["count"] = count - if log_pred: - logging_output["logits"] = logits.cpu().numpy() - logging_output["target"] = target.cpu().numpy() return loss, sample_size, logging_output @staticmethod @@ -175,13 +172,13 @@ def reduce_metrics(logging_outputs) -> None: for k in logging_outputs[0]: if k not in builtin_keys: - val = sum(log.get(k, 0) for log in logging_outputs) / len( - logging_outputs - ) + val = sum(log.get(k, 0) for log in logging_outputs) if k.startswith("loss"): - metrics.log_scalar(k, val / sample_size / math.log(2), sample_size) + metrics.log_scalar( + k, val / sample_size / math.log(2), sample_size, round=3 + ) else: - metrics.log_scalar(k, val, round=3) + metrics.log_scalar(k, val / len(logging_outputs), round=3) @staticmethod def logging_outputs_can_be_summed() -> bool: diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 694d878308..9bf4f7d09f 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -441,6 +441,7 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): def merge_with_parent(dc: FairseqDataclass, cfg: FairseqDataclass): dc_instance = DictConfig(dc) dc_instance.__dict__["_parent"] = cfg.__dict__["_parent"] - cfg = OmegaConf.merge(dc_instance, cfg) + with open_dict(dc_instance): + cfg = OmegaConf.merge(dc_instance, cfg) OmegaConf.set_struct(cfg, True) return cfg From 7cdef0a9bce575738ffb7b3c5fcad07181f149ac Mon Sep 17 00:00:00 2001 From: tuanh208 Date: Sat, 21 Nov 2020 23:00:33 -0800 Subject: [PATCH 076/774] Adding --mask-multiple-length and --mask-stdev options to masked_lm task (#2846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: NOTE: this implements span masking for RoBERTa as described in vq-wav2vec paper # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Adding --mask-multiple-length and --mask-stdev options to masked_lm task, allowing to mask sequences of multiple lengths when training a masked language model. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Yes � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2846 Reviewed By: myleott Differential Revision: D25007978 Pulled By: alexeib fbshipit-source-id: a8b3bcb260c8308641362c8c59706f08142e6be9 --- fairseq/data/mask_tokens_dataset.py | 43 +++++++++++++++++++++++++++-- fairseq/tasks/masked_lm.py | 11 ++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/fairseq/data/mask_tokens_dataset.py b/fairseq/data/mask_tokens_dataset.py index 8ea86245f7..b239013c80 100644 --- a/fairseq/data/mask_tokens_dataset.py +++ b/fairseq/data/mask_tokens_dataset.py @@ -39,6 +39,10 @@ class MaskTokensDataset(BaseWrapperDataset): over vocab indices, indicating whether it is the beginning of a word. We will extend any mask to encompass the whole word. bpe: BPE to use for whole-word masking. + mask_multiple_length : repeat each mask index multiple times. Default + value is 1. + mask_stdev : standard deviation of masks distribution in case of + multiple masking. Default value is 0. """ @classmethod @@ -63,11 +67,15 @@ def __init__( random_token_prob: float = 0.1, freq_weighted_replacement: bool = False, mask_whole_words: torch.Tensor = None, + mask_multiple_length: int = 1, + mask_stdev: float = 0.0, ): assert 0.0 < mask_prob < 1.0 assert 0.0 <= random_token_prob <= 1.0 assert 0.0 <= leave_unmasked_prob <= 1.0 assert random_token_prob + leave_unmasked_prob <= 1.0 + assert mask_multiple_length >= 1 + assert mask_stdev >= 0.0 self.dataset = dataset self.vocab = vocab @@ -79,6 +87,8 @@ def __init__( self.leave_unmasked_prob = leave_unmasked_prob self.random_token_prob = random_token_prob self.mask_whole_words = mask_whole_words + self.mask_multiple_length = mask_multiple_length + self.mask_stdev = mask_stdev if random_token_prob > 0.0: if freq_weighted_replacement: @@ -122,10 +132,39 @@ def __getitem__(self, index: int): mask = np.full(sz, False) num_mask = int( # add a random number for probabilistic rounding - self.mask_prob * sz + self.mask_prob * sz / float(self.mask_multiple_length) + np.random.rand() ) - mask[np.random.choice(sz, num_mask, replace=False)] = True + + # multiple masking as described in the vq-wav2vec paper (https://arxiv.org/abs/1910.05453) + mask_idc = np.random.choice(sz, num_mask, replace=False) + if self.mask_stdev > 0.0: + lengths = np.random.normal( + self.mask_multiple_length, self.mask_stdev, size=num_mask + ) + lengths = [max(0, int(round(x))) for x in lengths] + mask_idc = np.asarray( + [ + mask_idc[j] + offset + for j in range(len(mask_idc)) + for offset in range(lengths[j]) + ], + dtype=np.int64, + ) + else: + mask_idc = np.concatenate( + [mask_idc + i for i in range(self.mask_multiple_length)] + ) + mask_idc = mask_idc[mask_idc < len(mask)] + try: + mask[mask_idc] = True + except: # something wrong + print( + "Assigning mask indexes {} to mask {} failed!".format( + mask_idc, mask + ) + ) + raise if self.return_masked_tokens: # exit early if we're just returning the masked tokens diff --git a/fairseq/tasks/masked_lm.py b/fairseq/tasks/masked_lm.py index 56086f5e81..70208bc4d5 100644 --- a/fairseq/tasks/masked_lm.py +++ b/fairseq/tasks/masked_lm.py @@ -88,6 +88,15 @@ def add_args(parser): action="store_true", help="mask whole words; you may also want to set --bpe", ) + parser.add_argument( + "--mask-multiple-length", + default=1, + type=int, + help="repeat the mask indices multiple times", + ) + parser.add_argument( + "--mask-stdev", default=0.0, type=float, help="stdev of the mask length" + ) parser.add_argument( "--shorten-method", default="none", @@ -180,6 +189,8 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): random_token_prob=self.args.random_token_prob, freq_weighted_replacement=self.args.freq_weighted_replacement, mask_whole_words=mask_whole_words, + mask_multiple_length=self.args.mask_multiple_length, + mask_stdev=self.args.mask_stdev, ) with data_utils.numpy_seed(self.args.seed + epoch): From 1519c80aef44849713581afdd83475e832f0dc1c Mon Sep 17 00:00:00 2001 From: alexeib Date: Sun, 22 Nov 2020 09:33:02 -0800 Subject: [PATCH 077/774] workaround hydra + submit it not supporting custom enums (#1458) Summary: this allows using submitit launcher with hydra to launch fairseq jobs something like this now works: ``` python fairseq_cli/hydra_train.py --multirun hydra/launcher=submitit_slurm hydra.launcher.cpus_per_task=80 hydra.launcher.gpus_per_node=8 hydra.launcher.tasks_per_node=1 hydra.launcher.nodes=2 hydra.launcher.partition=dev hydra.launcher.mem_gb=400 distributed_training.distributed_world_size=16 distributed_training.distributed_port=33333 +optimization.update_freq='[2]' --config-path /private/home/abaevski/fairseq-py/examples/wav2vec/config/pretraining --config-name wav2vec2_base_librispeech ``` (note that one has to specify distributed_port for this to work) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1458 Reviewed By: myleott Differential Revision: D25150369 Pulled By: alexeib fbshipit-source-id: 63b74a437fb92afff8b0faa579d07f4539a2f1d8 --- fairseq/dataclass/constants.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index fad04f3482..858f77a863 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -3,11 +3,19 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from enum import Enum +from enum import Enum, EnumMeta from typing import List -class StrEnum(Enum): +class StrEnumMeta(EnumMeta): + # this is workaround for submitit pickling leading to instance checks failing in hydra for StrEnum, see + # https://github.com/facebookresearch/hydra/issues/1156 + @classmethod + def __instancecheck__(cls, other): + return "enum" in str(type(other)) + + +class StrEnum(Enum, metaclass=StrEnumMeta): def __str__(self): return self.value From 74fc8ccce1cfb7367cb57e6605e125030f2b0d31 Mon Sep 17 00:00:00 2001 From: alexeib Date: Sun, 22 Nov 2020 13:51:53 -0800 Subject: [PATCH 078/774] default max_tokens_valid and batch_size_valid correctly (#1459) Summary: max_tokens_valid and batch_size_valid were not getting defaulted properly, leading to ooms Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1459 Reviewed By: myleott Differential Revision: D25151434 Pulled By: alexeib fbshipit-source-id: 0dc0f099973e6abc8ba9b20516da26b4fb2e0e33 --- fairseq/dataclass/configs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 2cbfc9560a..d9ceb2a10b 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -402,14 +402,14 @@ class DatasetConfig(FairseqDataclass): default=False, metadata={"help": "disable validation"} ) max_tokens_valid: Optional[int] = field( - default=None, + default=II("dataset.max_tokens"), metadata={ "help": "maximum number of tokens in a validation batch" " (defaults to --max-tokens)" }, ) batch_size_valid: Optional[int] = field( - default=None, + default=II("dataset.batch_size"), metadata={ "help": "batch size of the validation batch (defaults to --batch-size)", "argparse_alias": "--max-sentences-valid", From 168480c9f11e2db0c1b0a40eb0a901133e05cb4a Mon Sep 17 00:00:00 2001 From: Alexei Baevski Date: Mon, 23 Nov 2020 14:41:25 -0800 Subject: [PATCH 079/774] add model criterion Summary: - add model criterion that allows one to define any kind of loss(es) within your model and then just have this criterion do the logging Reviewed By: myleott Differential Revision: D25145814 fbshipit-source-id: bb0f01935b96d5c77f8adad40e931689ce6e3391 --- fairseq/criterions/model_criterion.py | 134 ++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 fairseq/criterions/model_criterion.py diff --git a/fairseq/criterions/model_criterion.py b/fairseq/criterions/model_criterion.py new file mode 100644 index 0000000000..da37f899ea --- /dev/null +++ b/fairseq/criterions/model_criterion.py @@ -0,0 +1,134 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass, field +import logging +from typing import Dict, List + +from fairseq import metrics, utils +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass + + +logger = logging.getLogger(__name__) + + +@dataclass +class ModelCriterionConfig(FairseqDataclass): + loss_weights: Dict[str, float] = field( + default_factory=dict, + metadata={"help": "weights for the loss terms"}, + ) + log_keys: List[str] = field( + default_factory=list, + metadata={"help": "additional output keys to log"}, + ) + + +@register_criterion("model", dataclass=ModelCriterionConfig) +class ModelCriterion(FairseqCriterion): + """ + This criterion relies on the model to supply losses. + The losses should be a dictionary of name -> scalar returned by + the model either by including it in the net_output dict or by + implementing a get_losses(net_output, sample) method. The final loss is + a scaled sum of all losses according to weights in loss_weights. + If no weights are provided, then all losses are scaled by 1.0. + + The losses will be automatically logged. Additional keys from + net_output dict can be logged via the log_keys parameter. + """ + + def __init__(self, task, loss_weights=None, log_keys=None): + super().__init__(task) + self.loss_weights = loss_weights + self.log_keys = log_keys + + def forward(self, model, sample, reduce=True): + net_output = model(**sample["net_input"]) + + sample_size = net_output["sample_size"] + scaled_losses = {} + + if hasattr(model, "get_losses"): + losses = model.get_losses(net_output, sample) + elif isinstance(net_output, dict) and "losses" in net_output: + losses = net_output["losses"] + else: + raise Exception("Could not retrieve losses") + + for lk, p in losses.items(): + try: + coef = 1.0 if len(self.loss_weights) == 0 else self.loss_weights[lk] + except KeyError: + logger.error( + f"weight for loss {lk} is not in loss_weights ({self.loss_weights})" + ) + raise + if coef != 0 and p is not None: + scaled_losses[lk] = coef * p.float() + + loss = sum(scaled_losses.values()) + if reduce and loss.numel() > 1: + loss = loss.sum() + + logging_output = { + "loss": loss.data, + "ntokens": sample_size, + "nsentences": sample["id"].numel(), + "sample_size": sample_size, + } + + for lk in self.log_keys: + if lk in net_output: + logging_output[lk] = float((net_output[lk])) + + if len(scaled_losses) > 1: + for lk, l in scaled_losses.items(): + logging_output[f"loss_{lk}"] = l.item() + + return loss, sample_size, logging_output + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + loss_sum = utils.item(sum(log.get("loss", 0) for log in logging_outputs)) + ntokens = utils.item(sum(log.get("ntokens", 0) for log in logging_outputs)) + nsentences = utils.item( + sum(log.get("nsentences", 0) for log in logging_outputs) + ) + sample_size = utils.item( + sum(log.get("sample_size", 0) for log in logging_outputs) + ) + + metrics.log_scalar("loss", loss_sum / sample_size, sample_size, round=3) + metrics.log_scalar("ntokens", ntokens) + metrics.log_scalar("nsentences", nsentences) + + builtin_keys = { + "loss", + "ntokens", + "nsentences", + "sample_size", + "correct", + "count", + } + + for k in logging_outputs[0]: + if k not in builtin_keys: + val = sum(log.get(k, 0) for log in logging_outputs) + if k.startswith("loss_"): + metrics.log_scalar(k, val / sample_size, sample_size, round=3) + else: + metrics.log_scalar(k, val / len(logging_outputs), round=3) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return True From f13f2990935fce56f62a40b1243cac0ee4668433 Mon Sep 17 00:00:00 2001 From: alexeib Date: Mon, 23 Nov 2020 19:07:19 -0800 Subject: [PATCH 080/774] fix issubclass() call on python 3.7+ (#1462) Summary: Fixes #2897 Also updates readmes to use --config-dir instead of --config-path for hydra runs, and adds __init__.py to config dir Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1462 Reviewed By: myleott Differential Revision: D25163789 Pulled By: alexeib fbshipit-source-id: f45f432174771c5c458480f984aedf12130b8522 --- docs/hydra_integration.md | 2 +- examples/wav2vec/README.md | 18 +++++++++--------- examples/wav2vec/wav2vec_manifest.py | 3 +++ fairseq/config/__init__.py | 4 ++++ fairseq/config/config.yaml | 5 +++++ fairseq/dataclass/utils.py | 3 +-- 6 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 fairseq/config/__init__.py diff --git a/docs/hydra_integration.md b/docs/hydra_integration.md index 8e4082cb24..04c797fe50 100644 --- a/docs/hydra_integration.md +++ b/docs/hydra_integration.md @@ -211,7 +211,7 @@ works for migrated tasks and models. ```shell script $ fairseq-hydra-train \ - --config-path /path/to/external/configs \ + --config-dir /path/to/external/configs \ --config-name wiki103 ``` diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index fdbf844ec7..10d231ed69 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -58,12 +58,12 @@ Note that the input is expected to be single channel, sampled at 16 kHz ```shell script $ fairseq-hydra-train \ task.data=/path/to/data \ - --config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ --config-name wav2vec2_base_librispeech ``` -Note: you can simulate 64 GPUs by using k GPUs and adding command line parameters (before --config-path) -`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 64/k +Note: you can simulate 64 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 64/k ### Train a wav2vec 2.0 large model: @@ -72,12 +72,12 @@ This configuration was used for the large model trained on the Libri-light datas ```shell script $ fairseq-hydra-train \ task.data=/path/to/data \ - --config-path /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ --config-name wav2vec2_large_librivox ``` -Note: you can simulate 128 GPUs by using k GPUs and adding command line parameters (before --config-path) -`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 128/k +Note: you can simulate 128 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 128/k ### Fine-tune a pre-trained model with CTC: @@ -96,14 +96,14 @@ $ fairseq-hydra-train \ distributed_training.distributed_port=$PORT \ task.data=/path/to/data \ model.w2v_path=/path/to/model.pt \ - --config-path /path/to/fairseq-py/examples/wav2vec/config/finetuning \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/finetuning \ --config-name base_100h ``` There are other config files in the config/finetuning directory that can be used to fine-tune on other splits. -You can specify the right config via the --config-name parameter. +You can specify the right config via the `--config-name` parameter. -Note: you can simulate 24 GPUs by using k GPUs and adding command line parameters (before --config-path) +Note: you can simulate 24 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) `distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 24/k Decoding with a language model during training requires wav2letter [python bindings](https://github.com/facebookresearch/wav2letter/wiki/Building-Python-bindings). diff --git a/examples/wav2vec/wav2vec_manifest.py b/examples/wav2vec/wav2vec_manifest.py index 1d27f58afc..5417084554 100644 --- a/examples/wav2vec/wav2vec_manifest.py +++ b/examples/wav2vec/wav2vec_manifest.py @@ -47,6 +47,9 @@ def get_parser(): def main(args): assert args.valid_percent >= 0 and args.valid_percent <= 1.0 + if not os.path.exists(args.dest): + os.makedirs(args.dest) + dir_path = os.path.realpath(args.root) search_path = os.path.join(dir_path, "**/*." + args.ext) rand = random.Random(args.seed) diff --git a/fairseq/config/__init__.py b/fairseq/config/__init__.py new file mode 100644 index 0000000000..6264236915 --- /dev/null +++ b/fairseq/config/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/fairseq/config/config.yaml b/fairseq/config/config.yaml index 9621baa5e9..e20d914b9b 100644 --- a/fairseq/config/config.yaml +++ b/fairseq/config/config.yaml @@ -1,4 +1,9 @@ # @package _group_ + +hydra: + run: + dir: . + defaults: - task: null - model: null diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 9bf4f7d09f..beae592d1a 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -218,8 +218,7 @@ def get_default(f): isinstance(val, str) and not val.startswith("${") # not interpolation and field_type != str - and inspect.isclass(field_type) - and not issubclass(field_type, Enum) # not choices enum + and (not inspect.isclass(field_type) or not issubclass(field_type, Enum)) # not choices enum ): # upgrade old models that stored complex parameters as string val = ast.literal_eval(val) From dea66cc294a18dd4d9e59aa0af8d51f951e83884 Mon Sep 17 00:00:00 2001 From: Chau Tran Date: Wed, 25 Nov 2020 23:04:24 -0800 Subject: [PATCH 081/774] Fix mbart checkpoint Summary: activation_fn was hardcoded to 'gelu' when mbart was trained, and activation_fn was not saved to the checkpoint. The default on master is 'relu', so the old version would use 'relu'. I manually updated the activation_fn in the checkpoint to 'gelu' and uploaded to https://dl.fbaipublicfiles.com/fairseq/models/mbart/mbart.cc25.v2.tar.gz Reviewed By: myleott Differential Revision: D25163364 fbshipit-source-id: 365ebbd39ebb341c92b1c9ad71c8fbb2edffb7e6 --- examples/mbart/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mbart/README.md b/examples/mbart/README.md index 510edeff64..217c48867c 100644 --- a/examples/mbart/README.md +++ b/examples/mbart/README.md @@ -9,7 +9,7 @@ MBART is a sequence-to-sequence denoising auto-encoder pre-trained on large-scal Model | Description | # params | Download ---|---|---|--- -`mbart.CC25` | mBART model with 12 encoder and decoder layers trained on 25 languages' monolingual corpus | 610M | [mbart.CC25.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/mbart/mbart.CC25.tar.gz) +`mbart.CC25` | mBART model with 12 encoder and decoder layers trained on 25 languages' monolingual corpus | 610M | [mbart.CC25.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/mbart/mbart.cc25.v2.tar.gz) `mbart.ft.ro_en` | finetune mBART cc25 model on ro-en language pairs | 610M | [mbart.cc25.ft.enro.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/mbart/mbart.cc25.ft.enro.tar.gz) ## Results From 4ba5b4be98399c3c20d6e3c9b7750461afb83730 Mon Sep 17 00:00:00 2001 From: "Yuan Shangguan (June)" Date: Mon, 30 Nov 2020 11:38:53 -0800 Subject: [PATCH 082/774] Minor changes to manual LR scheduler Summary: 1. Update to make the learning rate at the beginning of training to be reasonable. Otherwise, job train_loss explodes like this f235003551 or f234959697 or f234961844. 2. Trivial update to avoid printing out massive update2lr dictionary that takes over the entire logging page, and makes logging difficult to see. Example: {F347075703} Differential Revision: D25146200 fbshipit-source-id: 071a591cf823e8c74a0380ec6850dc6b34d82ffc --- fairseq/optim/lr_scheduler/manual_lr_scheduler.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fairseq/optim/lr_scheduler/manual_lr_scheduler.py b/fairseq/optim/lr_scheduler/manual_lr_scheduler.py index 7e06ec55c8..0269a1e285 100644 --- a/fairseq/optim/lr_scheduler/manual_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/manual_lr_scheduler.py @@ -29,9 +29,10 @@ def __init__(self, args, optimizer): self.lr = self.update2lr[1] else: self.lr = args.lr[0] + self.optimizer.set_lr(self.lr) # Set the beginning of the epoch. def parse_manuallr_args(self, lr_args_str): - lr_dict = ast.literal_eval(lr_args_str) + lr_dict = ast.literal_eval(lr_args_str.replace(' ', '')) if not isinstance(lr_dict, dict): raise ValueError("epoch2lr/update2lr must be abel to evaluated to a dict") @@ -83,7 +84,9 @@ def get_next_lr(self, epoch): if manual_keys: manual_lr = self.epoch2lr[max(manual_keys)] else: - logger.warning("@@@ epoch={} does not exist in manual lr input. epoch2lr={}".format(epoch, self.epoch2lr)) + logger.warning("@@@ epoch={} does not exist in manual lr input. epoch2lr={}...".format( + epoch, list(self.epoch2lr.items())[:min(10, len(self.epoch2lr.keys())-1)] + )) manual_lr = self.optimizer.get_lr() return manual_lr @@ -99,7 +102,8 @@ def step_update(self, num_updates): if manual_keys: manual_lr = self.update2lr[max(manual_keys)] else: - logger.warning("epoch={} does not exist in manual lr input update2lr={}".format(num_updates, self.update2lr)) + logger.warning("epoch={} does not exist in manual lr input update2lr={}...".format( + num_updates, list(self.update2lr.items())[:min(10, len(self.update2lr.keys())-1)])) manual_lr = self.optimizer.get_lr() self.optimizer.set_lr(manual_lr) From 9cf0bd96d645df23dfbacf6ee28e3ddb441e8717 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 30 Nov 2020 14:19:25 -0800 Subject: [PATCH 083/774] Add/fix tests (#1468) Summary: - add test for loading ensemble checkpoints (and confirmed it fails if I revert: https://github.com/pytorch/fairseq/commit/265791b727b664d4d7da3abd918a3f6fb70d7337) - add test for LayerDrop (and fix it) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1468 Reviewed By: alexeib Differential Revision: D25223272 Pulled By: myleott fbshipit-source-id: 3f06f753605af251567c70d2961f5506ea423499 --- fairseq/checkpoint_utils.py | 24 +++++++-- tests/test_binaries.py | 32 ++++++++++++ tests/test_checkpoint_utils.py | 89 ++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 tests/test_checkpoint_utils.py diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 2bb055056e..235c660a5e 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -5,6 +5,7 @@ import ast import collections +import contextlib import logging import os import re @@ -239,7 +240,13 @@ def load_checkpoint_to_cpu(path, arg_overrides=None): def load_model_ensemble( - filenames, arg_overrides=None, task=None, strict=True, suffix="", num_shards=1, state=None + filenames, + arg_overrides=None, + task=None, + strict=True, + suffix="", + num_shards=1, + state=None, ): """Loads an ensemble of models. @@ -265,7 +272,13 @@ def load_model_ensemble( def load_model_ensemble_and_task( - filenames, arg_overrides=None, task=None, strict=True, suffix="", num_shards=1, state=None + filenames, + arg_overrides=None, + task=None, + strict=True, + suffix="", + num_shards=1, + state=None, ): assert state is None or len(filenames) == 1 @@ -563,8 +576,11 @@ def create_pruning_pass(layers_to_keep, layer_name): # Since layers are now pruned, *_layers_to_keep are no longer needed. # This is more of "It would make it work fix" rather than a proper fix. - - with open_dict(model_cfg): + if isinstance(model_cfg, DictConfig): + context = open_dict(model_cfg) + else: + context = contextlib.ExitStack() + with context: if hasattr(model_cfg, "encoder_layers_to_keep"): model_cfg.encoder_layers_to_keep = None if hasattr(model_cfg, "decoder_layers_to_keep"): diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 8235702383..cad6f1eba4 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -925,6 +925,38 @@ def test_alignment_full_context(self): ) generate_main(data_dir) + def test_transformer_layerdrop(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_transformer_layerdrop") as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + train_translation_model( + data_dir, + "transformer_iwslt_de_en", + [ + "--encoder-layers", + "3", + "--decoder-layers", + "3", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--encoder-layerdrop", + "0.01", + "--decoder-layerdrop", + "0.01", + ], + ) + generate_main(data_dir) + generate_main( + data_dir, + [ + "--model-overrides", + "{'encoder_layers_to_keep':'0,2','decoder_layers_to_keep':'1'}" + ], + ) + class TestStories(unittest.TestCase): def setUp(self): diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py new file mode 100644 index 0000000000..e3c685deec --- /dev/null +++ b/tests/test_checkpoint_utils.py @@ -0,0 +1,89 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import contextlib +import logging +import os +import tempfile +import unittest +from io import StringIO + +from fairseq import checkpoint_utils + +from tests.utils import ( + create_dummy_data, + preprocess_translation_data, + train_translation_model, +) + + +class TestCheckpointUtils(unittest.TestCase): + def setUp(self): + logging.disable(logging.CRITICAL) + + def tearDown(self): + logging.disable(logging.NOTSET) + + @contextlib.contextmanager + def _train_transformer(self, seed, extra_args=None): + if extra_args is None: + extra_args = [] + with tempfile.TemporaryDirectory(f"_train_transformer_seed{seed}") as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + train_translation_model( + data_dir, + "transformer_iwslt_de_en", + [ + "--encoder-layers", + "3", + "--decoder-layers", + "3", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--seed", + str(seed), + ] + + extra_args, + ) + yield os.path.join(data_dir, "checkpoint_last.pt") + + def test_load_model_ensemble_and_task(self): + with contextlib.redirect_stdout(StringIO()): + with self._train_transformer(seed=123) as model1: + with self._train_transformer(seed=456) as model2: + ensemble, cfg, task = checkpoint_utils.load_model_ensemble_and_task( + filenames=[model1, model2] + ) + self.assertEqual(len(ensemble), 2) + + # after Transformer has been migrated to Hydra, this will probably + # become cfg.common.seed + self.assertEqual(ensemble[0].args.seed, 123) + self.assertEqual(ensemble[1].args.seed, 456) + + # the task from the first model should be returned + self.assertEqual(task.args.seed, 123) + + def test_prune_state_dict(self): + with contextlib.redirect_stdout(StringIO()): + extra_args = ["--encoder-layerdrop", "0.01", "--decoder-layerdrop", "0.01"] + with self._train_transformer(seed=1, extra_args=extra_args) as model: + ensemble, cfg, task = checkpoint_utils.load_model_ensemble_and_task( + filenames=[model], + arg_overrides={ + "encoder_layers_to_keep": "0,2", + "decoder_layers_to_keep": "1", + }, + ) + self.assertEqual(len(ensemble), 1) + self.assertEqual(len(ensemble[0].encoder.layers), 2) + self.assertEqual(len(ensemble[0].decoder.layers), 1) + + +if __name__ == "__main__": + unittest.main() From f732b403ec15244c41a24b9e28d6c5a411a511df Mon Sep 17 00:00:00 2001 From: "Yuan Shangguan (June)" Date: Mon, 30 Nov 2020 14:45:20 -0800 Subject: [PATCH 084/774] Max_update is not backward compatible. Fix in this diff. Summary: max_update assertion in tri_stage_lr is introduced in D25040041 (https://github.com/pytorch/fairseq/commit/6d2cf0ddf64040543c346b3866eb636d14522dde). It requires max-update to be defined, and breaks the backward compatibility of existing recipes. Since max-update is ONLY used when phase-ratio is defined. We recommend this change to keep it from breaking existing model recipes. Reviewed By: myleott Differential Revision: D25204247 fbshipit-source-id: 01f6f2f0935dfaff9f23501158af608e5d507145 --- fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py b/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py index 403de77c80..4d5547c39b 100644 --- a/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/tri_stage_lr_scheduler.py @@ -48,7 +48,7 @@ class TriStageLRScheduleConfig(FairseqDataclass): @register_lr_scheduler("tri_stage", dataclass=TriStageLRScheduleConfig) -class TriStageLRScheduleConfig(FairseqLRScheduler): +class TriStageLRSchedule(FairseqLRScheduler): """Tristage learning rate schedulr Implement the learning rate scheduler in https://arxiv.org/pdf/1904.08779.pdf @@ -93,7 +93,6 @@ def __init__(self, cfg: TriStageLRScheduleConfig, optimizer): "Cannot use a fixed learning rate schedule with tri-stage lr." " Consider --lr-scheduler=fixed instead." ) - assert cfg.max_update > 0 # calculate LR at each point self.peak_lr = cfg.lr[0] @@ -101,6 +100,7 @@ def __init__(self, cfg: TriStageLRScheduleConfig, optimizer): self.final_lr = cfg.final_lr_scale * cfg.lr[0] if cfg.phase_ratio is not None: + assert cfg.max_update > 0 assert sum(cfg.phase_ratio) == 1, "phase ratios must add up to 1" self.warmup_steps = int(cfg.max_update * cfg.phase_ratio[0]) self.hold_steps = int(cfg.max_update * cfg.phase_ratio[1]) From 65d88f150c54f9549de0b565411684b52f4e2b50 Mon Sep 17 00:00:00 2001 From: Alex Xiao Date: Tue, 1 Dec 2020 11:16:33 -0800 Subject: [PATCH 085/774] more accurate nan detection Summary: I've been debugging some nan issues related to fp16. This diff adds some improvements to make it more accurate: 1. Zero grad before doing nan detection. This enables the gradients/grad norms calculated to be accurate 2. Account for update frequency when doing nan detection. Without this, infs/nans can go undetected. Reviewed By: myleott Differential Revision: D25225729 fbshipit-source-id: 4ffd1dcdf4a643459b814e24e74776b144a068a8 --- fairseq/trainer.py | 50 ++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index e9ac3c6bb1..4583abd133 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -508,16 +508,7 @@ def train_step(self, samples, raise_oom=False): # forward and backward pass logging_outputs, sample_size, ooms = [], 0, 0 for i, sample in enumerate(samples): - sample = self._prepare_sample(sample) - if sample is None: - # when sample is None, run forward/backward on a dummy batch - # and ignore the resulting gradients - sample = self._prepare_sample(self._dummy_batch) - is_dummy_batch = True - else: - if self._dummy_batch == "DUMMY": - self._dummy_batch = sample - is_dummy_batch = False + sample, is_dummy_batch = self._prepare_sample(sample) def maybe_no_sync(): """ @@ -652,15 +643,18 @@ def maybe_no_sync(): except FloatingPointError: # re-run the forward and backward pass with hooks attached to print # out where it fails + self.zero_grad() with NanDetector(self.get_model()): - self.task.train_step( - sample, - self.model, - self.criterion, - self.optimizer, - self.get_num_updates(), - ignore_grad=False, - ) + for _, sample in enumerate(samples): + sample, _ = self._prepare_sample(sample) + self.task.train_step( + sample, + self.model, + self.criterion, + self.optimizer, + self.get_num_updates(), + ignore_grad=False, + ) raise except OverflowError as e: overflow = True @@ -775,14 +769,7 @@ def valid_step(self, sample, raise_oom=False): self.model.eval() self.criterion.eval() - sample = self._prepare_sample(sample) - if sample is None: - sample = self._prepare_sample(self._dummy_batch) - is_dummy_batch = True - else: - if self._dummy_batch == "DUMMY": - self._dummy_batch = sample - is_dummy_batch = False + sample, is_dummy_batch = self._prepare_sample(sample) try: _loss, sample_size, logging_output = self.task.valid_step( @@ -932,7 +919,11 @@ def _prepare_sample(self, sample): ) if sample is None or len(sample) == 0: - return None + assert ( + self._dummy_batch is not None and len(self._dummy_batch) > 0 + ), "Invalid dummy batch: {}".format(self._dummy_batch) + sample, _ = self._prepare_sample(self._dummy_batch) + return sample, True if self.cuda: if self.pipeline_model_parallel: @@ -959,7 +950,10 @@ def apply_bfloat16(t): if self.cfg.common.bf16: sample = utils.apply_to_sample(apply_bfloat16, sample) - return sample + if self._dummy_batch == "DUMMY": + self._dummy_batch = sample + + return sample, False def _set_seed(self): # Set seed based on args.seed and the update number so that we get From 0db28cdd0e50cad9c36e5e47ffceff40beaf6f60 Mon Sep 17 00:00:00 2001 From: alexeib Date: Tue, 1 Dec 2020 17:44:23 -0800 Subject: [PATCH 086/774] fix generation config being properly passed (#1465) Summary: fixes #2961 Also fixes model criterion logging with world size > 1 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1465 Reviewed By: myleott Differential Revision: D25198394 Pulled By: alexeib fbshipit-source-id: fa52011a4d56eb41fe4bd59f9bd565632b87fba5 --- fairseq/criterions/model_criterion.py | 9 +++++---- fairseq/hub_utils.py | 2 +- fairseq/logging/progress_bar.py | 2 ++ fairseq_cli/interactive.py | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/fairseq/criterions/model_criterion.py b/fairseq/criterions/model_criterion.py index da37f899ea..c4f2c0b354 100644 --- a/fairseq/criterions/model_criterion.py +++ b/fairseq/criterions/model_criterion.py @@ -10,6 +10,7 @@ from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass +from fairseq.distributed_utils import get_data_parallel_world_size logger = logging.getLogger(__name__) @@ -83,7 +84,7 @@ def forward(self, model, sample, reduce=True): for lk in self.log_keys: if lk in net_output: - logging_output[lk] = float((net_output[lk])) + logging_output[lk] = float(net_output[lk]) if len(scaled_losses) > 1: for lk, l in scaled_losses.items(): @@ -112,17 +113,17 @@ def reduce_metrics(logging_outputs) -> None: "ntokens", "nsentences", "sample_size", - "correct", - "count", } + world_size = get_data_parallel_world_size() + for k in logging_outputs[0]: if k not in builtin_keys: val = sum(log.get(k, 0) for log in logging_outputs) if k.startswith("loss_"): metrics.log_scalar(k, val / sample_size, sample_size, round=3) else: - metrics.log_scalar(k, val / len(logging_outputs), round=3) + metrics.log_scalar(k, val / world_size, round=3) @staticmethod def logging_outputs_can_be_summed() -> bool: diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index 1819a9460a..b716884c78 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -157,7 +157,7 @@ def generate( )[0] # build generator using current args as well as any kwargs - gen_args = copy.copy(self.cfg) + gen_args = copy.copy(self.cfg.generation) with open_dict(gen_args): gen_args.beam = beam for k, v in kwargs.items(): diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index 3183d2f476..2b3873794e 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -356,6 +356,8 @@ def _log_to_tensorboard(self, stats, tag=None, step=None): writer.add_scalar(key, stats[key].val, step) elif isinstance(stats[key], Number): writer.add_scalar(key, stats[key], step) + elif torch.is_tensor(stats[key]) and stats[key].numel() == 1: + writer.add_scalar(key, stats[key].item(), step) writer.flush() diff --git a/fairseq_cli/interactive.py b/fairseq_cli/interactive.py index 530830d6b0..4785855985 100644 --- a/fairseq_cli/interactive.py +++ b/fairseq_cli/interactive.py @@ -173,7 +173,7 @@ def main(cfg: FairseqConfig): model.prepare_for_inference_(cfg) # Initialize generator - generator = task.build_generator(models, cfg.task) + generator = task.build_generator(models, cfg.generation) # Handle tokenization and BPE tokenizer = encoders.build_tokenizer(cfg.tokenizer) From ffa158ff0cf2aa6c104ae844bfde361f125478f6 Mon Sep 17 00:00:00 2001 From: Sathish Indurthi Date: Thu, 3 Dec 2020 07:45:54 -0800 Subject: [PATCH 087/774] fix for MMA criterion initialization (#2911) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [X ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ X] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ X] Did you make sure to update the docs? N/A - [ X] Did you write any new necessary tests? N/A ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/2122. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2911 Reviewed By: alexeib Differential Revision: D25146472 Pulled By: myleott fbshipit-source-id: 9cf02a9be679c2e1725dd3ae83aafef31900e640 --- ...moothed_cross_entropy_latency_augmented.py | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/examples/simultaneous_translation/criterions/label_smoothed_cross_entropy_latency_augmented.py b/examples/simultaneous_translation/criterions/label_smoothed_cross_entropy_latency_augmented.py index b3c8f6d53f..761cfe61a1 100644 --- a/examples/simultaneous_translation/criterions/label_smoothed_cross_entropy_latency_augmented.py +++ b/examples/simultaneous_translation/criterions/label_smoothed_cross_entropy_latency_augmented.py @@ -14,15 +14,30 @@ class LatencyAugmentedLabelSmoothedCrossEntropyCriterion( LabelSmoothedCrossEntropyCriterion ): - def __init__(self, args, task): - super().__init__(args, task) - self.eps = args.label_smoothing - self.latency_weight_avg = args.latency_weight_avg - self.latency_weight_avg_type = args.latency_weight_avg_type - self.latency_weight_var = args.latency_weight_var - self.latency_weight_var_type = args.latency_weight_var_type - self.mass_preservation = args.mass_preservation - self.average_method = args.average_method + def __init__( + self, + task, + sentence_avg, + label_smoothing, + ignore_prefix_size, + report_accuracy, + latency_weight_avg, + latency_weight_avg_type, + latency_weight_var, + latency_weight_var_type, + mass_preservation, + average_method, + ): + super().__init__( + task, sentence_avg, label_smoothing, ignore_prefix_size, report_accuracy + ) + self.eps = label_smoothing + self.latency_weight_avg = latency_weight_avg + self.latency_weight_avg_type = latency_weight_avg_type + self.latency_weight_var = latency_weight_var + self.latency_weight_var_type = latency_weight_var_type + self.mass_preservation = mass_preservation + self.average_method = average_method self.latency_train = LatencyTraining( self.latency_weight_avg, self.latency_weight_var, From d7e571c557e0f7833fa244ecb5cd0458ba28670c Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Thu, 3 Dec 2020 13:22:14 -0800 Subject: [PATCH 088/774] Small fixes for TPU (and support them in sweep) (#1433) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1433 Test Plan: Imported from OSS Reviewed By: huihuifan Differential Revision: D24959540 Pulled By: myleott fbshipit-source-id: a3b247be4ae7f4e09e571f972451e1e4ce76d5c5 --- fairseq/trainer.py | 7 +++++-- fairseq/utils.py | 2 +- fairseq_cli/train.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 4583abd133..04db13dce0 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -910,7 +910,7 @@ def _local_cumulative_training_time(self): """Aggregate training time in seconds.""" return time.time() - self._start_time + self._previous_training_time - def _prepare_sample(self, sample): + def _prepare_sample(self, sample, is_dummy=False): if sample == "DUMMY": raise Exception( "Trying to use an uninitialized 'dummy' batch. This usually indicates " @@ -922,7 +922,7 @@ def _prepare_sample(self, sample): assert ( self._dummy_batch is not None and len(self._dummy_batch) > 0 ), "Invalid dummy batch: {}".format(self._dummy_batch) - sample, _ = self._prepare_sample(self._dummy_batch) + sample, _ = self._prepare_sample(self._dummy_batch, is_dummy=True) return sample, True if self.cuda: @@ -933,6 +933,9 @@ def _prepare_sample(self, sample): ) else: sample = utils.move_to_cuda(sample) + elif self.tpu and is_dummy: + # the dummy batch may not be on the appropriate device + sample = utils.move_to_cuda(sample, device=self.device) def apply_half(t): if t.dtype is torch.float32: diff --git a/fairseq/utils.py b/fairseq/utils.py index 8e9119124d..4046f6696c 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -106,7 +106,7 @@ def move_to_cuda(sample, device=None): def _move_to_cuda(tensor): # non_blocking is ignored if tensor is not pinned, so we can always set # to True (see github.com/PyTorchLightning/pytorch-lightning/issues/620) - return tensor.cuda(device=device, non_blocking=True) + return tensor.to(device=device, non_blocking=True) return apply_to_sample(_move_to_cuda, sample) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index e1af605348..7739759693 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -189,7 +189,7 @@ def train( else cfg.optimization.update_freq[-1] ) itr = iterators.GroupedIterator(itr, update_freq) - if getattr(cfg.common, "tpu", False): + if cfg.common.tpu: itr = utils.tpu_data_loader(itr) progress = progress_bar.progress_bar( itr, From fa802c1034c4e6a38c80e7ab545b445aabd2d314 Mon Sep 17 00:00:00 2001 From: wei zhao Date: Thu, 3 Dec 2020 14:19:16 -0800 Subject: [PATCH 089/774] Fix another link to mbart checkpoint (#2976) Summary: Forget to update another model url after the fix https://github.com/pytorch/fairseq/commit/dea66cc294a18dd4d9e59aa0af8d51f951e83884. chtran Pull Request resolved: https://github.com/pytorch/fairseq/pull/2976 Reviewed By: tangyuq Differential Revision: D25257003 Pulled By: chtran fbshipit-source-id: 2fdb30547ed1fc82ff5cfa038a3b6d8fb9dc60ba --- examples/mbart/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mbart/README.md b/examples/mbart/README.md index 217c48867c..fa520a6825 100644 --- a/examples/mbart/README.md +++ b/examples/mbart/README.md @@ -26,7 +26,7 @@ Model | en-ro | ro-en ## BPE data # download model -wget https://dl.fbaipublicfiles.com/fairseq/models/mbart/mbart.CC25.tar.gz +wget https://dl.fbaipublicfiles.com/fairseq/models/mbart/mbart.cc25.v2.tar.gz tar -xzvf mbart.CC25.tar.gz # bpe data install SPM [here](https://github.com/google/sentencepiece) From 793ec2b19d63b70717a84293b45e583f6c0b9dd5 Mon Sep 17 00:00:00 2001 From: Arthur Guo Date: Thu, 3 Dec 2020 15:32:33 -0800 Subject: [PATCH 090/774] Enable JIT on LAS Model Differential Revision: D25290353 fbshipit-source-id: 18ce98d32e49e9cebe1aed14302613a00e8c3c99 --- fairseq/modules/linearized_convolution.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fairseq/modules/linearized_convolution.py b/fairseq/modules/linearized_convolution.py index 09a8f201c0..b36cea91fa 100644 --- a/fairseq/modules/linearized_convolution.py +++ b/fairseq/modules/linearized_convolution.py @@ -38,6 +38,7 @@ def upgrade_state_dict_named(self, state_dict, name): if prefix + "_linearized_weight" in state_dict: del state_dict[prefix + "_linearized_weight"] + @torch.jit.ignore def forward(self, input, incremental_state=None): """ Args: From bc4ebcafb4f1535c528aea589d14db56a13bd763 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Thu, 3 Dec 2020 18:17:09 -0800 Subject: [PATCH 091/774] Fix tests (#1482) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1482 Reviewed By: michaelauli Differential Revision: D25318618 Pulled By: myleott fbshipit-source-id: bed171ffe5ca10e8359be96a15d0fe9bb1a630ea --- setup.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 6bc450a7fa..0a4be4b0dd 100644 --- a/setup.py +++ b/setup.py @@ -174,15 +174,17 @@ def do_setup(package_data): long_description_content_type="text/markdown", setup_requires=[ "cython", - "numpy", + 'numpy<1.20.0; python_version<"3.7"', + 'numpy; python_version>="3.7"', "setuptools>=18.0", ], install_requires=[ "cffi", "cython", - "dataclasses", + 'dataclasses; python_version<"3.7"', "hydra-core", - "numpy", + 'numpy<1.20.0; python_version<"3.7"', + 'numpy; python_version>="3.7"', "regex", "sacrebleu>=1.4.12", "torch", From a700e14ea3cbf3e99ca729caa30b5b1c0305c4c4 Mon Sep 17 00:00:00 2001 From: Robert Verkuil Date: Fri, 4 Dec 2020 04:43:09 -0800 Subject: [PATCH 092/774] Increase plasma reconnect attempts (#1480) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Avoids run failures due to insufficient time allowed for plasma client -> server connection. I've been seeing many failures in my recent runs, which use data sharding, due to plasma connection errors: [train.stderr.33224323.txt](https://github.com/fairinternal/fairseq-py/files/5637976/train.stderr.33224323.txt) [train.stderr.33245371.txt](https://github.com/fairinternal/fairseq-py/files/5637980/train.stderr.33245371.txt) [train.stderr.33261567.txt](https://github.com/fairinternal/fairseq-py/files/5637981/train.stderr.33261567.txt) [train.stderr.33261589.txt](https://github.com/fairinternal/fairseq-py/files/5637982/train.stderr.33261589.txt) Currently plasma can attempt client -> server connection 20 times, for a total retry time of ≈8-10s. When sharding, epoch_itr's intentionally are *not* cached. Therefore, dataset-related plasma arrays must be remade. This makes plasma connect errors a persistent concern over training. Worse with many gpus+workers. For a single training run that I inspected, the number of retries needed to connect increases, and eventually exceeds 20. ![image](https://user-images.githubusercontent.com/4042063/101068717-10853100-3567-11eb-89ca-7d18a7ef0405.png) Best solution would be to increase the retry interval. Looking at plasma [source](https://github.com/apache/arrow/blob/016f76c8c02e769d58b3e785a87674d98ce83367/python/pyarrow/_plasma.pyx#L848-L868), this doesn't look possible. However, we can increase num_retries. Hopefully this isn't too annoying for the cluster file system? ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1480 Reviewed By: myleott Differential Revision: D25313114 Pulled By: joshim5 fbshipit-source-id: ad50c3b29e0698bf197e24f6392bda73b407a548 --- fairseq/data/plasma_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/data/plasma_utils.py b/fairseq/data/plasma_utils.py index 2b12646783..f4bb6472d7 100644 --- a/fairseq/data/plasma_utils.py +++ b/fairseq/data/plasma_utils.py @@ -60,7 +60,7 @@ def start_server(self): def client(self): if self._client is None: assert self.path is not None - self._client = self.plasma.connect(self.path) + self._client = self.plasma.connect(self.path, num_retries=200) return self._client def __getstate__(self): From 8be488ff6b7fc49346c94323085e71e72b6583ea Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 4 Dec 2020 05:43:50 -0800 Subject: [PATCH 093/774] Add --load-checkpoint-on-all-dp-ranks (#1478) Summary: A recent commit [1] made it so that checkpoints are loaded on rank 0 and then broadcast to other workers. This is valuable to reduce I/O and especially helpful when training with optimizer state sharding, so we don't need to load redundant optimizer state on every worker. This diff adds a new option (`--load-checkpoint-on-all-dp-ranks`) that optionally reverts to the old behavior. [1] https://github.com/pytorch/fairseq/commit/ea4ccd94de131d6b39163836418696369dd1d034 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1478 Test Plan: Imported from OSS Reviewed By: theweiho Differential Revision: D25291595 Pulled By: myleott fbshipit-source-id: 57b521c5e6a48f08140f9527162072ea1d4066db --- fairseq/dataclass/configs.py | 7 +++++++ fairseq/trainer.py | 19 +++++++++---------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index d9ceb2a10b..3ff177d969 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -583,6 +583,13 @@ class CheckpointConfig(FairseqDataclass): "the checkpoint" }, ) + load_checkpoint_on_all_dp_ranks: bool = field( + default=False, + metadata={ + "help": "load checkpoints on all data parallel devices " + "(default: only load on rank 0 and broadcast to other devices)" + }, + ) model_parallel_size: int = II("common.model_parallel_size") distributed_rank: int = II("distributed_training.distributed_rank") diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 04db13dce0..94684f051b 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -299,12 +299,14 @@ def load_checkpoint( bexists = PathManager.isfile(filename) if bexists: - if ( - self.data_parallel_rank == 0 + load_on_all_ranks = ( + self.cfg.checkpoint.load_checkpoint_on_all_dp_ranks # TPUs don't support broadcast yet, so load checkpoints # on every worker for now or self.tpu - ): + ) + + if load_on_all_ranks or self.data_parallel_rank == 0: state = checkpoint_utils.load_checkpoint_to_cpu(filename) last_optim_state = state.get("last_optimizer_state", None) @@ -312,7 +314,8 @@ def load_checkpoint( # state. Later we will broadcast sharded states to each rank # to avoid memory from exploding. if ( - self.cfg.distributed_training.zero_sharding == "os" + not load_on_all_ranks + and self.cfg.distributed_training.zero_sharding == "os" and "last_optimizer_state" in state and self.data_parallel_world_size > 1 ): @@ -321,11 +324,7 @@ def load_checkpoint( last_optim_state = None state = None - if ( - self.data_parallel_world_size > 1 - # disable on TPUs until they support broadcast - and not self.tpu - ): + if self.data_parallel_world_size > 1 and not load_on_all_ranks: state = distributed_utils.broadcast_object( state, src_rank=0, @@ -368,7 +367,7 @@ def load_checkpoint( if not reset_lr_scheduler: self.lr_scheduler.load_state_dict(last_optim["lr_scheduler_state"]) - if self.data_parallel_world_size > 1: + if not load_on_all_ranks and self.data_parallel_world_size > 1: last_optim_state = self.optimizer.broadcast_global_state_dict( last_optim_state ) From bb039fa2063dca1b388d6be2f64052b07fb556a2 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 4 Dec 2020 10:57:35 -0800 Subject: [PATCH 094/774] Improve performance of distributed_utils.broadcast_object (#1479) Summary: This diff dramatically speeds up and reduces memory usage of distributed_utils.broadcast_object. In particular, rather than pickling the whole state dict (and broadcasting it), we only pickle the non-tensors and broadcast the tensors directly. This improves speed (since pickling is expensive) and also saves RAM, since pickle duplicates the data and by separating out the tensors, we're only left with duplicate copies of non-tensor data in the state dict, which is quite small. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1479 Test Plan: Imported from OSS Differential Revision: D25291594 Pulled By: myleott fbshipit-source-id: 521102fae75a3bc71dcd5ac2bf238f7eb534a3d1 --- fairseq/distributed_utils.py | 126 +++++++++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 21 deletions(-) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 9059d8aa2b..fa70607fbc 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -14,6 +14,7 @@ import warnings from argparse import Namespace from collections import OrderedDict +from dataclasses import dataclass from typing import Any, Dict, List, Mapping, Optional import torch @@ -637,44 +638,127 @@ def get_from_stack(key): return OrderedDict([(key, get_from_stack(key)) for key in data_keys]) -# From fairscale/optim/utils.py +def broadcast_tensors( + tensors: Optional[List[torch.Tensor]], + src_rank: int, + group: object, + dist_device: Optional[torch.device] = None, +) -> List[torch.Tensor]: + """ + Broadcasts a list of tensors without other (non-src) ranks needing to know + the dtypes/shapes of the tensors. + """ + if dist_device is None: + if torch.distributed.get_backend(group) == "nccl": + dist_device = torch.device("cuda") + else: + dist_device = torch.device("cpu") + + # share metadata first to simplify transfer + is_src_rank = (get_rank(group) == src_rank) + if is_src_rank: + metadata = [ + {"size": t.size(), "dtype": t.dtype, "device": t.device} for t in tensors + ] + metadata = _broadcast_object_slow(metadata, src_rank, group, dist_device) + else: + metadata = _broadcast_object_slow(None, src_rank, group, dist_device) + + out_tensors = [] + for i, meta in enumerate(metadata): + if is_src_rank: + tensor = tensors[i] + broadcast(tensors[i].to(dist_device), src=src_rank, group=group) + else: + tensor = torch.zeros( + [meta["size"].numel()], dtype=meta["dtype"], device=dist_device + ) + broadcast(tensor, src=src_rank, group=group) + tensor = tensor.view(meta["size"]).to(meta["device"]) + out_tensors.append(tensor) + return out_tensors + + def broadcast_object( obj: Any, src_rank: int, group: object, dist_device: Optional[torch.device] = None, - dist_length_dtype: Optional[torch.dtype] = torch.long, - dist_dtype: Optional[torch.dtype] = torch.uint8, ) -> Any: - """ - Either broadcast from master to the fleet (default), - or use the src setting as the original rank. - """ + """Broadcast an arbitrary Python object to other workers.""" if dist_device is None: if torch.distributed.get_backend(group) == "nccl": dist_device = torch.device("cuda") else: dist_device = torch.device("cpu") + if get_rank(group) == src_rank: + # split the tensors from the non-tensors so we can broadcast them + # directly, avoiding unnecessary serialization/deserialization + tensors = [] + obj = _split_tensors_from_obj(obj, tensors) + obj = _broadcast_object_slow(obj, src_rank, group, dist_device) + tensors = broadcast_tensors(tensors, src_rank, group, dist_device) + else: + obj = _broadcast_object_slow(None, src_rank, group, dist_device) + tensors = broadcast_tensors(None, src_rank, group, dist_device) + return _put_tensors_in_obj(obj, tensors) + + +def _broadcast_object_slow( + obj: Any, src_rank: int, group: object, dist_device: torch.device, +) -> Any: if get_rank(group) == src_rank: # Emit data buffer = io.BytesIO() torch.save(obj, buffer) - data = bytearray(buffer.getbuffer()) - length_tensor = torch.tensor( - [len(data)], dtype=dist_length_dtype, device=dist_device - ) - broadcast(length_tensor, src=src_rank, group=group) - data_send_tensor = torch.tensor(data, dtype=dist_dtype, device=dist_device) - broadcast(data_send_tensor, src=src_rank, group=group) + buffer = torch.ByteTensor(buffer.getbuffer()).to(dist_device) + length = torch.LongTensor([len(buffer)]).to(dist_device) + broadcast(length, src=src_rank, group=group) + broadcast(buffer, src=src_rank, group=group) else: # Fetch from the source - length_tensor = torch.tensor([0], dtype=dist_length_dtype, device=dist_device) - broadcast(length_tensor, src=src_rank, group=group) - data_recv_tensor = torch.zeros( - [int(length_tensor.item())], dtype=dist_dtype, device=dist_device - ) - broadcast(data_recv_tensor, src=src_rank, group=group) - buffer = io.BytesIO(data_recv_tensor.cpu().numpy()) + length = torch.LongTensor([0]).to(dist_device) + broadcast(length, src=src_rank, group=group) + buffer = torch.ByteTensor(int(length.item())).to(dist_device) + broadcast(buffer, src=src_rank, group=group) + buffer = io.BytesIO(buffer.cpu().numpy()) obj = torch.load(buffer, map_location="cpu") return obj + + +@dataclass(frozen=True) +class _TensorPlaceholder: + index: int + + +def _split_tensors_from_obj(obj: Any, tensors: List[torch.Tensor]) -> Any: + if torch.is_tensor(obj): + placeholder = _TensorPlaceholder(index=len(tensors)) + tensors.append(obj) + return placeholder + elif isinstance(obj, dict): + return {k: _split_tensors_from_obj(v, tensors) for k, v in obj.items()} + elif isinstance(obj, list): + return [_split_tensors_from_obj(v, tensors) for v in obj] + elif isinstance(obj, tuple): + return tuple(_split_tensors_from_obj(v, tensors) for v in obj) + elif isinstance(obj, set): + return {_split_tensors_from_obj(v, tensors) for v in obj} + else: + return obj + + +def _put_tensors_in_obj(obj: Any, tensors: List[torch.Tensor]) -> Any: + if isinstance(obj, _TensorPlaceholder): + return tensors[obj.index] + elif isinstance(obj, dict): + return {k: _put_tensors_in_obj(v, tensors) for k, v in obj.items()} + elif isinstance(obj, list): + return [_put_tensors_in_obj(v, tensors) for v in obj] + elif isinstance(obj, tuple): + return tuple(_put_tensors_in_obj(v, tensors) for v in obj) + elif isinstance(obj, set): + return {_put_tensors_in_obj(v, tensors) for v in obj} + else: + return obj From 6f47704d4deb99061e7562710e1dbd0253b04ea4 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 4 Dec 2020 10:57:35 -0800 Subject: [PATCH 095/774] Add distributed tests (#1481) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1481 Test Plan: Imported from OSS Reviewed By: theweiho Differential Revision: D25313776 Pulled By: myleott fbshipit-source-id: 755bf4b77b2a7a3aee56e2344246ff2087a3af77 --- tests/distributed/__init__.py | 0 tests/distributed/test_distributed_utils.py | 69 +++++++++++++++++++++ tests/distributed/utils.py | 61 ++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 tests/distributed/__init__.py create mode 100644 tests/distributed/test_distributed_utils.py create mode 100644 tests/distributed/utils.py diff --git a/tests/distributed/__init__.py b/tests/distributed/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/distributed/test_distributed_utils.py b/tests/distributed/test_distributed_utils.py new file mode 100644 index 0000000000..161ee85eaa --- /dev/null +++ b/tests/distributed/test_distributed_utils.py @@ -0,0 +1,69 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import functools +import sys +import unittest + +import torch + +from fairseq import distributed_utils as dist_utils + +from .utils import objects_are_equal, spawn_and_init + + +class TestDistributedUtils(unittest.TestCase): + def setUp(self): + if not torch.cuda.is_available(): + raise unittest.SkipTest("CUDA not available, skipping test") + if sys.platform == "win32": + raise unittest.SkipTest("NCCL doesn't support Windows, skipping test") + if torch.cuda.device_count() < 2: + raise unittest.SkipTest("distributed tests require 2+ GPUs, skipping") + + def test_broadcast_object_python(self): + spawn_and_init( + functools.partial( + TestDistributedUtils._test_broadcast_object, + "hello world", + ), + world_size=2, + ) + + def test_broadcast_object_tensor(self): + spawn_and_init( + functools.partial( + TestDistributedUtils._test_broadcast_object, + torch.rand(5), + ), + world_size=2, + ) + + def test_broadcast_object_complex(self): + spawn_and_init( + functools.partial( + TestDistributedUtils._test_broadcast_object, + { + "a": "1", + "b": [2, torch.rand(2, 3), 3], + "c": (torch.rand(2, 3), 4), + "d": {5, torch.rand(5)}, + "e": torch.rand(5), + "f": torch.rand(5).int().cuda(), + }, + ), + world_size=2, + ) + + @staticmethod + def _test_broadcast_object(ref_obj, rank, group): + obj = dist_utils.broadcast_object( + ref_obj if rank == 0 else None, src_rank=0, group=group + ) + assert objects_are_equal(ref_obj, obj) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/distributed/utils.py b/tests/distributed/utils.py new file mode 100644 index 0000000000..d2b3ddb1ff --- /dev/null +++ b/tests/distributed/utils.py @@ -0,0 +1,61 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import functools +import tempfile + +import torch + + +def spawn_and_init(fn, world_size, args=None): + if args is None: + args = () + with tempfile.NamedTemporaryFile(delete=False) as tmp_file: + torch.multiprocessing.spawn( + fn=functools.partial(init_and_run, fn, args), + args=(world_size, tmp_file.name,), + nprocs=world_size, + ) + + +def distributed_init(rank, world_size, tmp_file): + torch.distributed.init_process_group( + backend="nccl", + init_method="file://{}".format(tmp_file), + world_size=world_size, + rank=rank, + ) + torch.cuda.set_device(rank) + + +def init_and_run(fn, args, rank, world_size, tmp_file): + distributed_init(rank, world_size, tmp_file) + group = torch.distributed.new_group() + fn(rank, group, *args) + + +def objects_are_equal(a, b) -> bool: + if type(a) is not type(b): + return False + if isinstance(a, dict): + if set(a.keys()) != set(b.keys()): + return False + for k in a.keys(): + if not objects_are_equal(a[k], b[k]): + return False + return True + elif isinstance(a, (list, tuple, set)): + if len(a) != len(b): + return False + return all(objects_are_equal(x, y) for x, y in zip(a, b)) + elif torch.is_tensor(a): + return ( + a.size() == b.size() + and a.dtype == b.dtype + and a.device == b.device + and torch.all(a == b) + ) + else: + return a == b From ba79f7b781929e04c827c6dda9048e4e6e86ba6a Mon Sep 17 00:00:00 2001 From: Alex Conneau Date: Fri, 4 Dec 2020 13:45:22 -0800 Subject: [PATCH 096/774] Adding XLSR-53 model to wav2vec README (#1483) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1483 Reviewed By: alexeib Differential Revision: D25326050 Pulled By: aconneau fbshipit-source-id: 7428244d328ea0bbbbaaf23f715cd6d44d329b94 --- examples/wav2vec/README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 10d231ed69..52dce362ab 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -2,6 +2,8 @@ wav2vec 2.0 learns speech representations on unlabeled data as described in [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](https://arxiv.org/abs/2006.11477). +We learned speech representations in multiple languages as well in [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979). + We also combined wav2vec 2.0 with self-training in [Self-training and Pre-training are Complementary for Speech Recognition (Xu et al., 2020)](https://arxiv.org/abs/2010.11430). ## Pre-trained models @@ -26,6 +28,21 @@ Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https:// \* updated (Oct. 24, 2020) +We also release multilingual pre-trained wav2vec 2.0 (XLSR) models: + +Model | Architecture | Hours | Languages | Datasets | Model +|---|---|---|---|---|--- +XLSR-53 | Large | 56k | 53 | MLS, CommonVoice, BABEL | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr_53_56k.pt) + +The XLSR model uses the following datasets for multilingual pretraining: + +* **[MLS: Multilingual LibriSpeech](https://indico2.conference4me.psnc.pl/event/35/contributions/3585/attachments/1060/1101/Wed-2-6-10.pdf)** (8 languages, 50.7k hours): *Dutch, English, French, German, Italian, Polish, Portuguese, Spanish* + +* **[CommonVoice](https://commonvoice.mozilla.org/en/languages)** (36 languages, 3.6k hours): *Arabic, Basque, Breton, Chinese (CN), Chinese (HK), Chinese (TW), Chuvash, Dhivehi, Dutch, English, Esperanto, Estonian, French, German, Hakh-Chin, Indonesian, Interlingua, Irish, Italian, Japanese, Kabyle, Kinyarwanda, Kyrgyz, Latvian, Mongolian, Persian, Portuguese, Russian, Sakha, Slovenian, Spanish, Swedish, Tamil, Tatar, Turkish, Welsh* (see also [finetuning splits]([https://dl.fbaipublicfiles.com/cpc_audio/common_voices_splits.tar.gz]) from [this paper](https://arxiv.org/abs/2002.02848)). + +* **[Babel](https://catalog.ldc.upenn.edu/byyear)** (17 languages, 1.7k hours): *Assamese, Bengali, Cantonese, Cebuano, Georgian, Haitian, Kazakh, Kurmanji, Lao, Pashto, Swahili, Tagalog, Tamil, Tok, Turkish, Vietnamese, Zulu* + + ## Training a new model with the CLI tools Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) From 579002a0ea7d3161660a7beeb8c56b1f0fc26b63 Mon Sep 17 00:00:00 2001 From: Rui Hou Date: Fri, 4 Dec 2020 13:55:37 -0800 Subject: [PATCH 097/774] Add a dummy first_batch to EpochBatchIterating Summary: Add a dummy first_batch to EpochBatchIterating Reviewed By: myleott Differential Revision: D25337800 fbshipit-source-id: c387c4c39533c161cb160a84ad4f99e71c66f73e --- fairseq/data/iterators.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index ef41fed739..0f55026ef8 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -138,6 +138,10 @@ def load_state_dict(self, state_dict): """Copies the state of the iterator from the given *state_dict*.""" raise NotImplementedError + @property + def first_batch(self): + return "DUMMY" + class StreamingEpochBatchIterator(EpochBatchIterating): def __init__( From d5218f88275fd57825819c6dab523e30a41b6866 Mon Sep 17 00:00:00 2001 From: dingjiajia Date: Fri, 4 Dec 2020 17:09:08 -0800 Subject: [PATCH 098/774] update sequence generator device change (#2989) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes Sequence Generator Reproduce the bug: 1. Background: **fairseq.utils.move_to_cuda** function support to change device. 2. When you change the file **fairseq_cli/generate.py** suppose `gpu_id = 1` - line 134 change from `model.cuda()` to `model.cuda(gpu_id)` - line 189 change from `sample = utils.move_to_cuda(sample) if use_cuda else sample` to `sample = utils.move_to_cuda(sample, gpu_id) if use_cuda else sample` 2. you will get an error ``` fairseq/sequence_generator.py, line 382, in generate cand_bbsz_idx = cand_beams.add(bbsz_offsets) RuntimeError: binary_op(): expected both inputs to be on same device, but input a is on cuda:1 and input b is on cuda:0 ``` The reason of this bug is that `bbsz_offsets` is not assigned to proper cuda device. Therefore, we need to change the line 281 and line 281 of the file **fairseq/sequence_generator.py** The test file for this fix is the file **tests/test_sequence_generator.py** ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � very happy {emoji:1f642} Pull Request resolved: https://github.com/pytorch/fairseq/pull/2989 Reviewed By: alexeib Differential Revision: D25344265 Pulled By: myleott fbshipit-source-id: 8cb8b389e59a9aa67aec84dbdadcfa2c08c9648f --- fairseq/sequence_generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 47a20296cf..afc1500090 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -278,8 +278,8 @@ def _generate( cand_size = 2 * beam_size # 2 x beam size in case half are EOS # offset arrays for converting between different indexing schemes - bbsz_offsets = (torch.arange(0, bsz) * beam_size).unsqueeze(1).type_as(tokens) - cand_offsets = torch.arange(0, cand_size).type_as(tokens) + bbsz_offsets = (torch.arange(0, bsz) * beam_size).unsqueeze(1).type_as(tokens).to(src_tokens.device) + cand_offsets = torch.arange(0, cand_size).type_as(tokens).to(src_tokens.device) reorder_state: Optional[Tensor] = None batch_idxs: Optional[Tensor] = None From ba4f54267af5c3f67f1b76a6e804b6ab593d1d39 Mon Sep 17 00:00:00 2001 From: Alexei Baevski Date: Fri, 4 Dec 2020 17:34:08 -0800 Subject: [PATCH 099/774] composite optimizer Summary: this adds a composite optimizer and pass through learning rate scheduler that allows fairseq models to have separate optimizers (that can optionally have separate lr schedulers) for different parameters. to use this, you add a "param_group" field to the parameters you wish to be optimized separately (the rest of the params get automatically placed into a "default" group), then specify a composite optimizer with nested optimizers (and, optionally, lr schedulers) for each group name (see example below). for fp16 training this requires setting fp16_no_flatten_grads to true one possible area for future improvement is to automatically create param groups based on module names, but this is to be discussed for example, i can modify wav2vec2 model and add ```python for p in self.pos_conv.parameters(): p.param_group = "pos_conv" ``` in the TransformerEncoder class, just after pos_conv is created then i create the following config: ```yaml # package _group_ hydra: run: dir: . job_logging: disable_existing_loggers: false common: fp16: true log_format: json log_interval: 10 fp16_no_flatten_grads: true checkpoint: save_interval_updates: 20 keep_interval_updates: 1 no_epoch_checkpoints: true no_save: false Reviewed By: myleott Differential Revision: D25152032 fbshipit-source-id: c73ff95146ecc2a04660c67bcad02b637c5c5098 --- fairseq/criterions/ctc.py | 2 +- fairseq/criterions/model_criterion.py | 9 +- fairseq/dataclass/utils.py | 20 +- fairseq/distributed_utils.py | 11 +- fairseq/models/__init__.py | 14 +- fairseq/modules/same_pad.py | 11 +- fairseq/optim/composite.py | 183 ++++++++++++++++++ fairseq/optim/fairseq_optimizer.py | 17 +- fairseq/optim/fp16_optimizer.py | 22 ++- .../lr_scheduler/fairseq_lr_scheduler.py | 2 +- fairseq/optim/lr_scheduler/pass_through.py | 39 ++++ fairseq/optim/nag.py | 2 +- fairseq/tasks/fairseq_task.py | 3 + fairseq/trainer.py | 11 +- 14 files changed, 311 insertions(+), 35 deletions(-) create mode 100644 fairseq/optim/composite.py create mode 100644 fairseq/optim/lr_scheduler/pass_through.py diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index 0e4e3577d2..8cb1331825 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -8,7 +8,7 @@ from argparse import Namespace from dataclasses import dataclass, field from omegaconf import II -from typing import Optional, Tuple +from typing import Optional import torch import torch.nn.functional as F diff --git a/fairseq/criterions/model_criterion.py b/fairseq/criterions/model_criterion.py index c4f2c0b354..8e366a5d85 100644 --- a/fairseq/criterions/model_criterion.py +++ b/fairseq/criterions/model_criterion.py @@ -3,14 +3,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from dataclasses import dataclass, field import logging +from dataclasses import dataclass, field from typing import Dict, List from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass -from fairseq.distributed_utils import get_data_parallel_world_size logger = logging.getLogger(__name__) @@ -80,6 +79,7 @@ def forward(self, model, sample, reduce=True): "ntokens": sample_size, "nsentences": sample["id"].numel(), "sample_size": sample_size, + "_world_size": 1, } for lk in self.log_keys: @@ -113,9 +113,12 @@ def reduce_metrics(logging_outputs) -> None: "ntokens", "nsentences", "sample_size", + "_world_size", } - world_size = get_data_parallel_world_size() + world_size = utils.item( + sum(log.get("_world_size", 0) for log in logging_outputs) + ) for k in logging_outputs[0]: if k not in builtin_keys: diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index beae592d1a..e25838400c 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -4,19 +4,19 @@ # LICENSE file in the root directory of this source tree. import ast -import os +import inspect import logging +import os import re from argparse import ArgumentError, ArgumentParser, Namespace from dataclasses import _MISSING_TYPE, MISSING from enum import Enum -import inspect from typing import Any, Dict, List, Tuple, Type from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.configs import FairseqConfig -from hydra.experimental import compose, initialize from hydra.core.global_hydra import GlobalHydra +from hydra.experimental import compose, initialize from omegaconf import DictConfig, OmegaConf, open_dict logger = logging.getLogger(__name__) @@ -218,7 +218,9 @@ def get_default(f): isinstance(val, str) and not val.startswith("${") # not interpolation and field_type != str - and (not inspect.isclass(field_type) or not issubclass(field_type, Enum)) # not choices enum + and ( + not inspect.isclass(field_type) or not issubclass(field_type, Enum) + ) # not choices enum ): # upgrade old models that stored complex parameters as string val = ast.literal_eval(val) @@ -438,9 +440,7 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): def merge_with_parent(dc: FairseqDataclass, cfg: FairseqDataclass): - dc_instance = DictConfig(dc) - dc_instance.__dict__["_parent"] = cfg.__dict__["_parent"] - with open_dict(dc_instance): - cfg = OmegaConf.merge(dc_instance, cfg) - OmegaConf.set_struct(cfg, True) - return cfg + merged_cfg = OmegaConf.merge(dc, cfg) + merged_cfg.__dict__["_parent"] = cfg.__dict__["_parent"] + OmegaConf.set_struct(merged_cfg, True) + return merged_cfg diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index fa70607fbc..8f98ac88f9 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -161,8 +161,9 @@ def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False): elif cfg.distributed_world_size > 1 or force_distributed: # fallback for single node with multiple GPUs - assert cfg.distributed_world_size <= torch.cuda.device_count(), \ - f"world size is {cfg.distributed_world_size} but have {torch.cuda.device_count()} available devices" + assert ( + cfg.distributed_world_size <= torch.cuda.device_count() + ), f"world size is {cfg.distributed_world_size} but have {torch.cuda.device_count()} available devices" port = random.randint(10000, 20000) cfg.distributed_init_method = "tcp://localhost:{port}".format(port=port) @@ -376,8 +377,10 @@ def get_world_size(group): assert group[0] == "tpu" my_group = _find_my_group(group[1]) return len(my_group) - else: + elif torch.distributed.is_initialized(): return dist.get_world_size(group=group) + else: + return 1 def get_global_group(): @@ -416,6 +419,7 @@ def get_data_parallel_group(): global _USE_MEGATRON if _USE_MEGATRON: from fairseq.model_parallel.megatron import mpu + return mpu.get_data_parallel_group() else: return get_global_group() @@ -435,6 +439,7 @@ def get_model_parallel_group(): global _USE_MEGATRON if _USE_MEGATRON: from fairseq.model_parallel.megatron import mpu + return mpu.get_model_parallel_group() else: return None diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 600ca27c6a..135530d5c0 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -63,7 +63,11 @@ def build_model(cfg: FairseqDataclass, task): cfg = cfg[model_type] else: raise Exception( - "Could not infer model type from directory. Please add _name field to indicate model type" + "Could not infer model type from directory. Please add _name field to indicate model type. " + "Available models: " + + str(MODEL_DATACLASS_REGISTRY.keys()) + + " Requested model type: " + + model_type ) if model_type in ARCH_MODEL_REGISTRY: @@ -81,7 +85,13 @@ def build_model(cfg: FairseqDataclass, task): else: cfg = merge_with_parent(dc(), cfg) - assert model is not None, f"Could not infer model type from {cfg}" + assert model is not None, ( + f"Could not infer model type from {cfg}. " + f"Available models: " + + str(MODEL_DATACLASS_REGISTRY.keys()) + + " Requested model type: " + + model_type + ) return model.build_model(cfg, task) diff --git a/fairseq/modules/same_pad.py b/fairseq/modules/same_pad.py index b46f94d635..4c04990ea6 100644 --- a/fairseq/modules/same_pad.py +++ b/fairseq/modules/same_pad.py @@ -8,11 +8,14 @@ class SamePad(nn.Module): - def __init__(self, kernel_size): + def __init__(self, kernel_size, causal=False): super().__init__() - self.remove = kernel_size % 2 == 0 + if causal: + self.remove = kernel_size - 1 + else: + self.remove = 1 if kernel_size % 2 == 0 else 0 def forward(self, x): - if self.remove: - x = x[:, :, :-1] + if self.remove > 0: + x = x[:, :, : -self.remove] return x diff --git a/fairseq/optim/composite.py b/fairseq/optim/composite.py new file mode 100644 index 0000000000..51e6999368 --- /dev/null +++ b/fairseq/optim/composite.py @@ -0,0 +1,183 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from collections import defaultdict +from dataclasses import dataclass, field +from typing import Dict, Any, List, Optional + +import torch.optim +from fairseq.dataclass import FairseqDataclass +from fairseq.optim import FairseqOptimizer, register_optimizer, _build_optimizer +from fairseq.optim.lr_scheduler import FairseqLRScheduler, build_lr_scheduler +from omegaconf import II, open_dict + + +logger = logging.getLogger(__name__) + + +@dataclass +class OptimizerAndSchedulerConfig(FairseqDataclass): + optimizer: Any = None + lr_scheduler: Optional[Any] = None + lr: List[float] = II("optimization.lr") + + +@dataclass +class CompositeOptimizerConfig(FairseqDataclass): + groups: Dict[str, OptimizerAndSchedulerConfig] = field( + default_factory=lambda: {}, + metadata={ + "help": "optimizer name -> optimizer OptimizerAndSchedulerConfig. " + "Configures a different optimizer and (optionally) lr scheduler for each parameter group" + }, + ) + + +@register_optimizer("composite", dataclass=CompositeOptimizerConfig) +class FairseqCompositeOptimizer(FairseqOptimizer): + + optimizers: Dict[str, FairseqOptimizer] = {} + lr_schedulers: Dict[str, FairseqLRScheduler] = {} + lr_scheduler: FairseqLRScheduler = None + _optimizer: torch.optim.Optimizer + + def __init__(self, cfg: CompositeOptimizerConfig, params): + super().__init__(cfg) + + assert ( + len(params) > 1 + ), "Composite optimizer only works when there are multiple parameter groups (try fp16_no_flatten_grads: true)" + + groupped_params = defaultdict(list) + for p in params: + group = getattr(p, "param_group", "default") + groupped_params[group].append(p) + + assert groupped_params.keys() == cfg.groups.keys(), ( + f"Parameter groups {groupped_params.keys()} and optimizer groups {cfg.groups.keys()} are not the same! " + "Try setting 'param_group' on your parameters in the model." + ) + + for group, group_params in groupped_params.items(): + group_cfg = cfg.groups[group] + with open_dict(group_cfg): + group_cfg.optimizer.lr = group_cfg.lr + group_cfg.lr_scheduler.lr = group_cfg.lr + self.optimizers[group] = _build_optimizer(group_cfg.optimizer, group_params) + if group_cfg.lr_scheduler is not None: + self.lr_schedulers[group] = build_lr_scheduler( + group_cfg.lr_scheduler, self.optimizers[group] + ) + + if len(self.lr_schedulers) > 0: + assert len(self.lr_schedulers) == len(self.optimizers), ( + f"Please provide an lr scheduler for each optimizer to use pass_through scheduler. " + f"Optimizers: {self.optimizers}; Lr scheds: {self.lr_schedulers}" + ) + self.lr_scheduler = CompositeLRScheduler(self.lr_schedulers) + + self._optimizer = CompositeOptimizer(self.optimizers) + + @property + def supports_groups(self): + return True + + @property + def param_groups(self): + for opt in self.optimizers.values(): + for group in opt.param_groups: + yield group + + def get_lr(self): + """Return the current learning rate.""" + k = ( + "default" + if "default" in self.optimizers + else next(iter(self.optimizers.keys())) + ) + return self.optimizers[k].param_groups[0]["lr"] + + def state_dict(self): + """Return the LR scheduler state dict.""" + return {k: s.state_dict() for k, s in self.optimizers.items()} + + def load_state_dict(self, state_dict, optimizer_overrides=None): + """Load an LR scheduler state dict.""" + for k, state in state_dict.items(): + if k not in self.optimizers: + # skip extra keys like "loss_scale" added by fp16 optimizer + continue + + overrides = ( + optimizer_overrides[k] + if isinstance(optimizer_overrides, dict) and k in optimizer_overrides + else None + ) + self.optimizers[k].load_state_dict(state, optimizer_overrides=overrides) + + +class CompositeOptimizer(torch.optim.Optimizer): + def __init__(self, optimizers: Dict[str, FairseqOptimizer]): + self.optimizers = optimizers + + @property + def supports_memory_efficient_fp16(self): + return all(o.supports_memory_efficient_fp16 for o in self.optimizers.values()) + + @property + def supports_flat_params(self): + return all(o.supports_flat_params for o in self.optimizers.values()) + + def step(self, closure=None, groups=None): + """Performs a single optimization step. + + Arguments: + closure (callable, optional): A closure that reevaluates the model + and returns the loss. + """ + loss = None + if closure is not None: + loss = closure() + + for k, opt in self.optimizers.items(): + if groups is None or k in groups: + opt.step() + + return loss + + def zero_grad(self): + for opt in self.optimizers.values(): + opt.zero_grad() + + +class CompositeLRScheduler(FairseqLRScheduler): + def __init__(self, lr_schedulers): + super().__init__(None, None) + + self.lr_schedulers = lr_schedulers + + def state_dict(self): + """Return the LR scheduler state dict.""" + return {k: s.state_dict() for k, s in self.lr_schedulers.items()} + + def load_state_dict(self, state_dict): + """Load an LR scheduler state dict.""" + for k, state in state_dict.items(): + self.lr_schedulers[k].load_state_dict(state) + + def step_begin_epoch(self, epoch): + """Update the learning rate at the beginning of the given epoch.""" + for s in self.lr_schedulers.values(): + s.step_begin_epoch(epoch) + + def step(self, epoch, val_loss=None): + """Update the learning rate at the end of the given epoch.""" + for s in self.lr_schedulers.values(): + s.step(epoch) + + def step_update(self, num_updates): + """Update the learning rate after each update.""" + return {k: s.step_update(num_updates) for k, s in self.lr_schedulers.items()} diff --git a/fairseq/optim/fairseq_optimizer.py b/fairseq/optim/fairseq_optimizer.py index f9864533b6..41c859355c 100644 --- a/fairseq/optim/fairseq_optimizer.py +++ b/fairseq/optim/fairseq_optimizer.py @@ -109,14 +109,21 @@ def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): """Clips gradient norm.""" return utils.clip_grad_norm_(self.params, max_norm, aggregate_norm_fn) - def step(self, closure=None, scale=1.0): + def step(self, closure=None, scale=1.0, groups=None): """Performs a single optimization step.""" if self.supports_step_with_scale: self.optimizer.step(closure, scale=scale) + if self.supports_groups: + self.optimizer.step(closure, scale=scale, groups=groups) + else: + self.optimizer.step(closure, scale=scale) else: if scale != 1.0: self.multiply_grads(1.0 / scale) - self.optimizer.step(closure) + if self.supports_groups: + self.optimizer.step(closure, groups=groups) + else: + self.optimizer.step(closure) def zero_grad(self): """Clears the gradients of all optimized parameters.""" @@ -136,6 +143,12 @@ def supports_step_with_scale(self): return self.optimizer.supports_step_with_scale return False + @property + def supports_groups(self): + if hasattr(self.optimizer, "supports_groups"): + return self.optimizer.supports_groups + return False + @property def supports_flat_params(self): """ diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index 4457023527..a0da4948c8 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -65,6 +65,8 @@ def build_fp32_params(cls, args, params, flatten=True): for p in params: p32 = torch.nn.Parameter(p.data.float()) p32.grad = torch.zeros_like(p32.data) + if hasattr(p, "param_group"): + p32.param_group = p.param_group fp32_params.append(p32) return fp32_params @@ -198,15 +200,15 @@ def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): return grad_norm - def step(self, closure=None): + def step(self, closure=None, groups=None): """Performs a single optimization step.""" self._sync_fp16_grads_to_fp32() if getattr(self, "supports_step_with_scale", False): - self.fp32_optimizer.step(closure, scale=(1.0 / self._multiply_factor)) + self.fp32_optimizer.step(closure, scale=(1.0 / self._multiply_factor), groups=groups) else: self._unscale_grads() - self.fp32_optimizer.step(closure) + self.fp32_optimizer.step(closure, groups=groups) if self.scaler is not None: self.scaler.update() @@ -303,6 +305,10 @@ def optimizer(self): def optimizer(self, optimizer): self.fp32_optimizer.optimizer = optimizer + @property + def lr_scheduler(self): + return getattr(self.fp32_optimizer, "lr_scheduler", None) + @property def optimizer_config(self): return self.fp32_optimizer.optimizer_config @@ -416,14 +422,14 @@ def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): return grad_norm - def step(self, closure=None): + def step(self, closure=None, groups=None): """Performs a single optimization step.""" if getattr(self, "supports_step_with_scale", False): # NOTE(msb) optimizer divides by scale factor - self.wrapped_optimizer.step(closure, scale=(1.0 / self._multiply_factor)) + self.wrapped_optimizer.step(closure, scale=(1.0 / self._multiply_factor), groups=groups) else: self._unscale_grads() - self.wrapped_optimizer.step(closure) + self.wrapped_optimizer.step(closure, groups=groups) if self.scaler is not None: self.scaler.update() @@ -514,6 +520,10 @@ def optimizer(self, optimizer): def optimizer_config(self): return self.wrapped_optimizer.optimizer_config + @property + def lr_scheduler(self): + return getattr(self.wrapped_optimizer, "lr_scheduler", None) + def get_lr(self): return self.wrapped_optimizer.get_lr() diff --git a/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py b/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py index dd75dc5e30..6c12fa56b8 100644 --- a/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/fairseq_lr_scheduler.py @@ -12,7 +12,7 @@ class FairseqLRScheduler(object): def __init__(self, cfg, optimizer): super().__init__() - if not isinstance(optimizer, FairseqOptimizer): + if optimizer is not None and not isinstance(optimizer, FairseqOptimizer): raise ValueError("optimizer must be an instance of FairseqOptimizer") self.cfg = cfg self.optimizer = optimizer diff --git a/fairseq/optim/lr_scheduler/pass_through.py b/fairseq/optim/lr_scheduler/pass_through.py new file mode 100644 index 0000000000..2f93db328c --- /dev/null +++ b/fairseq/optim/lr_scheduler/pass_through.py @@ -0,0 +1,39 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass + +from fairseq.dataclass import FairseqDataclass +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler + + +@dataclass +class PassThroughScheduleConfig(FairseqDataclass): + pass + + +@register_lr_scheduler("pass_through", dataclass=PassThroughScheduleConfig) +class PassThroughScheduleSchedule(FairseqLRScheduler): + """Delegate lr scheduling to the optimizer.""" + + def __init__(self, cfg: PassThroughScheduleConfig, optimizer): + super().__init__(cfg, optimizer) + assert ( + hasattr(optimizer, "lr_scheduler") and optimizer.lr_scheduler is not None + ), "Pass-through schedule can only be used with optimizers with their own schedulers" + + def state_dict(self): + return self.optimizer.lr_scheduler.state_dict() + + def load_state_dict(self, state_dict): + self.optimizer.lr_scheduler.load_state_dict(state_dict) + + def step_begin_epoch(self, epoch): + """Update the learning rate at the beginning of the given epoch.""" + return self.optimizer.lr_scheduler.step_begin_epoch(epoch) + + def step_update(self, num_updates): + """Update the learning rate after each update.""" + return self.optimizer.lr_scheduler.step_update(num_updates) diff --git a/fairseq/optim/nag.py b/fairseq/optim/nag.py index c612d812c9..4f652fe6d3 100644 --- a/fairseq/optim/nag.py +++ b/fairseq/optim/nag.py @@ -75,7 +75,7 @@ def step(self, closure=None): momentum = group["momentum"] lr = group["lr"] lr_old = group.get("lr_old", lr) - lr_correct = lr / lr_old + lr_correct = lr / lr_old if lr_old > 0 else lr for p in group["params"]: if p.grad is None: diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index d34f09d1d7..c9b7477ae7 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -438,6 +438,9 @@ def valid_step(self, sample, model, criterion): loss, sample_size, logging_output = criterion(model, sample) return loss, sample_size, logging_output + def optimizer_step(self, optimizer, model, update_num): + optimizer.step() + def build_dataset_for_inference( self, src_tokens: List[torch.Tensor], src_lengths: List[int], **kwargs ) -> torch.utils.data.Dataset: diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 94684f051b..cfeb63237b 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -637,7 +637,9 @@ def maybe_no_sync(): with torch.autograd.profiler.record_function("optimizer"): # take an optimization step - self.optimizer.step() + self.task.optimizer_step( + self.optimizer, model=self.model, update_num=self.get_num_updates() + ) except FloatingPointError: # re-run the forward and backward pass with hooks attached to print @@ -827,7 +829,12 @@ def lr_step(self, epoch, val_loss=None): def lr_step_update(self): """Update the learning rate after each update.""" new_lr = self.lr_scheduler.step_update(self.get_num_updates()) - metrics.log_scalar("lr", new_lr, weight=0, priority=300) + if isinstance(new_lr, dict): + for k, v in new_lr.items(): + metrics.log_scalar(f"lr_{k}", v, weight=0, priority=300) + new_lr = new_lr.get("default", next(iter(new_lr.values()))) + else: + metrics.log_scalar("lr", new_lr, weight=0, priority=300) return new_lr def get_lr(self): From 4df4d0af8d706952013f8edf7da811937b8384c8 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sat, 5 Dec 2020 07:36:28 -0800 Subject: [PATCH 100/774] Add missing `--optimizer` option to tutorial docs (fixes #2830) (#1485) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1485 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25342182 Pulled By: myleott fbshipit-source-id: 7eb2a4b2b7377da31d4f538053cc196437532db0 --- docs/getting_started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index d227b95544..5d1d2d6979 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -90,7 +90,7 @@ well for the IWSLT 2014 dataset: > mkdir -p checkpoints/fconv > CUDA_VISIBLE_DEVICES=0 fairseq-train data-bin/iwslt14.tokenized.de-en \ - --lr 0.25 --clip-norm 0.1 --dropout 0.2 --max-tokens 4000 \ + --optimizer nag --lr 0.25 --clip-norm 0.1 --dropout 0.2 --max-tokens 4000 \ --arch fconv_iwslt_de_en --save-dir checkpoints/fconv By default, :ref:`fairseq-train` will use all available GPUs on your machine. Use the From 72a25a4e52402b6f53aa98cfb739c075c0d6f7ee Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sat, 5 Dec 2020 07:36:28 -0800 Subject: [PATCH 101/774] Rename optimization.min_lr -> optimization.stop_min_lr (#1486) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1486 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25342181 Pulled By: myleott fbshipit-source-id: 7d1cfb26334fff26d688648724ab073e5fb956f5 --- docs/getting_started.rst | 3 ++- examples/cross_lingual_language_model/README.md | 2 +- examples/language_model/README.adaptive_inputs.md | 2 +- examples/latent_depth/README.md | 2 +- examples/mbart/README.md | 2 +- examples/multilingual/README.md | 4 ++-- examples/multilingual/finetune_multilingual_model.sh | 2 +- examples/multilingual/train_multilingual_model.sh | 2 +- examples/nonautoregressive_translation/README.md | 2 +- examples/nonautoregressive_translation/scripts.md | 12 ++++++------ examples/pay_less_attention_paper/README.md | 10 +++++----- examples/quant_noise/README.md | 4 ++-- examples/simultaneous_translation/README.md | 6 +++--- examples/translation/README.md | 2 +- examples/translation_moe/README.md | 2 +- examples/wav2vec/README.md | 4 ++-- fairseq/checkpoint_utils.py | 8 ++++++-- fairseq/dataclass/configs.py | 2 +- fairseq_cli/train.py | 10 +++++++++- tests/test_binaries.py | 2 +- 20 files changed, 48 insertions(+), 35 deletions(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 5d1d2d6979..745ad7763c 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -182,9 +182,10 @@ sure to update ``--master_addr`` to the IP address of the first node: --arch transformer_vaswani_wmt_en_de_big --share-all-embeddings \ --optimizer adam --adam-betas '(0.9, 0.98)' --clip-norm 0.0 \ --lr-scheduler inverse_sqrt --warmup-init-lr 1e-07 --warmup-updates 4000 \ - --lr 0.0005 --min-lr 1e-09 \ + --lr 0.0005 \ --dropout 0.3 --weight-decay 0.0 --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --max-tokens 3584 \ + --max-epoch 70 \ --fp16 On SLURM clusters, fairseq will automatically detect the number of nodes and diff --git a/examples/cross_lingual_language_model/README.md b/examples/cross_lingual_language_model/README.md index a78f86d8da..f4c76cfed5 100644 --- a/examples/cross_lingual_language_model/README.md +++ b/examples/cross_lingual_language_model/README.md @@ -61,7 +61,7 @@ fairseq-train \ --max-update 2400000 --save-interval 1 --no-epoch-checkpoints \ --arch xlm_base \ --optimizer adam --lr-scheduler reduce_lr_on_plateau \ ---lr-shrink 0.5 --lr 0.0001 --min-lr 1e-09 \ +--lr-shrink 0.5 --lr 0.0001 --stop-min-lr 1e-09 \ --dropout 0.1 \ --criterion legacy_masked_lm_loss \ --max-tokens 2048 --tokens-per-sample 256 --attention-dropout 0.1 \ diff --git a/examples/language_model/README.adaptive_inputs.md b/examples/language_model/README.adaptive_inputs.md index 6873467115..2ab3733018 100644 --- a/examples/language_model/README.adaptive_inputs.md +++ b/examples/language_model/README.adaptive_inputs.md @@ -20,7 +20,7 @@ fairseq-train --task language_modeling \ --save-dir checkpoints/transformer_wikitext-103 \ --arch transformer_lm_wiki103 \ --max-update 286000 --max-lr 1.0 --t-mult 2 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 \ - --warmup-updates 16000 --warmup-init-lr 1e-07 --min-lr 1e-09 --optimizer nag --lr 0.0001 --clip-norm 0.1 \ + --warmup-updates 16000 --warmup-init-lr 1e-07 --stop-min-lr 1e-09 --optimizer nag --lr 0.0001 --clip-norm 0.1 \ --criterion adaptive_loss --max-tokens 3072 --update-freq 3 --tokens-per-sample 3072 --seed 1 \ --sample-break-mode none --skip-invalid-size-inputs-valid-test --ddp-backend=no_c10d ``` diff --git a/examples/latent_depth/README.md b/examples/latent_depth/README.md index a0ec55a3f6..e70e16405c 100644 --- a/examples/latent_depth/README.md +++ b/examples/latent_depth/README.md @@ -25,7 +25,7 @@ fairseq-train ${databin_dir} \ --share-decoder-input-output-embed \ --dropout 0.3 --attention-dropout 0.3 \ --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ - --lr-scheduler inverse_sqrt --min-lr 1e-9 --warmup-init-lr 1e-7 --warmup-updates 8000 \ + --lr-scheduler inverse_sqrt --stop-min-lr 1e-9 --warmup-init-lr 1e-7 --warmup-updates 8000 \ --max-tokens 4096 --update-freq 1 \ --lr 0.0015 \ --clip-norm 1.0 \ diff --git a/examples/mbart/README.md b/examples/mbart/README.md index fa520a6825..8a3e22d425 100644 --- a/examples/mbart/README.md +++ b/examples/mbart/README.md @@ -73,7 +73,7 @@ fairseq-train path_2_data \ --source-lang en_XX --target-lang ro_RO \ --criterion label_smoothed_cross_entropy --label-smoothing 0.2 \ --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ - --lr-scheduler polynomial_decay --lr 3e-05 --min-lr -1 --warmup-updates 2500 --total-num-update 40000 \ + --lr-scheduler polynomial_decay --lr 3e-05 --warmup-updates 2500 --total-num-update 40000 \ --dropout 0.3 --attention-dropout 0.1 --weight-decay 0.0 \ --max-tokens 1024 --update-freq 2 \ --save-interval 1 --save-interval-updates 5000 --keep-interval-updates 10 --no-epoch-checkpoints \ diff --git a/examples/multilingual/README.md b/examples/multilingual/README.md index 3559c244e2..35eca89804 100644 --- a/examples/multilingual/README.md +++ b/examples/multilingual/README.md @@ -41,7 +41,7 @@ fairseq-train $path_2_data \ --lang-pairs "$lang_pairs" \ --criterion label_smoothed_cross_entropy --label-smoothing 0.2 \ --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ - --lr-scheduler inverse_sqrt --lr 3e-05 --min-lr -1 --warmup-updates 2500 --max-update 40000 \ + --lr-scheduler inverse_sqrt --lr 3e-05 --warmup-updates 2500 --max-update 40000 \ --dropout 0.3 --attention-dropout 0.1 --weight-decay 0.0 \ --max-tokens 1024 --update-freq 2 \ --save-interval 1 --save-interval-updates 5000 --keep-interval-updates 10 --no-epoch-checkpoints \ @@ -69,7 +69,7 @@ fairseq-train $path_2_data \ --lang-pairs "$lang_pairs" \ --criterion label_smoothed_cross_entropy --label-smoothing 0.2 \ --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ - --lr-scheduler inverse_sqrt --lr 3e-05 --min-lr -1 --warmup-updates 2500 --max-update 40000 \ + --lr-scheduler inverse_sqrt --lr 3e-05 --warmup-updates 2500 --max-update 40000 \ --dropout 0.3 --attention-dropout 0.1 --weight-decay 0.0 \ --max-tokens 1024 --update-freq 2 \ --save-interval 1 --save-interval-updates 5000 --keep-interval-updates 10 --no-epoch-checkpoints \ diff --git a/examples/multilingual/finetune_multilingual_model.sh b/examples/multilingual/finetune_multilingual_model.sh index cfa9a86113..ffcf1fc722 100644 --- a/examples/multilingual/finetune_multilingual_model.sh +++ b/examples/multilingual/finetune_multilingual_model.sh @@ -20,7 +20,7 @@ fairseq-train "$path_2_data" \ --lang-pairs "$lang_pairs" \ --criterion label_smoothed_cross_entropy --label-smoothing 0.2 \ --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ - --lr-scheduler inverse_sqrt --lr 3e-05 --min-lr -1 --warmup-updates 2500 --max-update 40000 \ + --lr-scheduler inverse_sqrt --lr 3e-05 --warmup-updates 2500 --max-update 40000 \ --dropout 0.3 --attention-dropout 0.1 --weight-decay 0.0 \ --max-tokens 1024 --update-freq 2 \ --save-interval 1 --save-interval-updates 5000 --keep-interval-updates 10 --no-epoch-checkpoints \ diff --git a/examples/multilingual/train_multilingual_model.sh b/examples/multilingual/train_multilingual_model.sh index 09014c8217..c41730dfcd 100644 --- a/examples/multilingual/train_multilingual_model.sh +++ b/examples/multilingual/train_multilingual_model.sh @@ -16,7 +16,7 @@ fairseq-train "$path_2_data" \ --lang-pairs "$lang_pairs" \ --criterion label_smoothed_cross_entropy --label-smoothing 0.2 \ --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ - --lr-scheduler inverse_sqrt --lr 3e-05 --min-lr -1 --warmup-updates 2500 --max-update 40000 \ + --lr-scheduler inverse_sqrt --lr 3e-05 --warmup-updates 2500 --max-update 40000 \ --dropout 0.3 --attention-dropout 0.1 --weight-decay 0.0 \ --max-tokens 1024 --update-freq 2 \ --save-interval 1 --save-interval-updates 5000 --keep-interval-updates 10 --no-epoch-checkpoints \ diff --git a/examples/nonautoregressive_translation/README.md b/examples/nonautoregressive_translation/README.md index dfc592f0a0..7b2d42a91d 100644 --- a/examples/nonautoregressive_translation/README.md +++ b/examples/nonautoregressive_translation/README.md @@ -44,7 +44,7 @@ fairseq-train \ --share-all-embeddings \ --optimizer adam --adam-betas '(0.9,0.98)' \ --lr 0.0005 --lr-scheduler inverse_sqrt \ - --min-lr '1e-09' --warmup-updates 10000 \ + --stop-min-lr '1e-09' --warmup-updates 10000 \ --warmup-init-lr '1e-07' --label-smoothing 0.1 \ --dropout 0.3 --weight-decay 0.01 \ --decoder-learned-pos \ diff --git a/examples/nonautoregressive_translation/scripts.md b/examples/nonautoregressive_translation/scripts.md index 63b945c1d3..a3a33e6e02 100644 --- a/examples/nonautoregressive_translation/scripts.md +++ b/examples/nonautoregressive_translation/scripts.md @@ -14,7 +14,7 @@ fairseq-train \ --share-all-embeddings \ --optimizer adam --adam-betas '(0.9,0.98)' \ --lr 0.0005 --lr-scheduler inverse_sqrt \ - --min-lr '1e-09' --warmup-updates 10000 \ + --stop-min-lr '1e-09' --warmup-updates 10000 \ --warmup-init-lr '1e-07' --label-smoothing 0.1 \ --dropout 0.3 --weight-decay 0.01 \ --decoder-learned-pos \ @@ -43,7 +43,7 @@ fairseq-train \ --share-all-embeddings \ --optimizer adam --adam-betas '(0.9,0.98)' \ --lr 0.0005 --lr-scheduler inverse_sqrt \ - --min-lr '1e-09' --warmup-updates 10000 \ + --stop-min-lr '1e-09' --warmup-updates 10000 \ --warmup-init-lr '1e-07' --label-smoothing 0.1 \ --dropout 0.3 --weight-decay 0.01 \ --decoder-learned-pos \ @@ -76,7 +76,7 @@ fairseq-train \ --share-all-embeddings \ --optimizer adam --adam-betas '(0.9,0.98)' \ --lr 0.0005 --lr-scheduler inverse_sqrt \ - --min-lr '1e-09' --warmup-updates 10000 \ + --stop-min-lr '1e-09' --warmup-updates 10000 \ --warmup-init-lr '1e-07' --label-smoothing 0.1 \ --dropout 0.3 --weight-decay 0.01 \ --decoder-learned-pos \ @@ -109,7 +109,7 @@ fairseq-train \ --share-all-embeddings \ --optimizer adam --adam-betas '(0.9,0.98)' \ --lr 0.0005 --lr-scheduler inverse_sqrt \ - --min-lr '1e-09' --warmup-updates 10000 \ + --stop-min-lr '1e-09' --warmup-updates 10000 \ --warmup-init-lr '1e-07' --label-smoothing 0.1 \ --dropout 0.3 --weight-decay 0.01 \ --decoder-learned-pos \ @@ -136,7 +136,7 @@ fairseq-train \ --share-all-embeddings \ --optimizer adam --adam-betas '(0.9,0.98)' \ --lr 0.0005 --lr-scheduler inverse_sqrt \ - --min-lr '1e-09' --warmup-updates 10000 \ + --stop-min-lr '1e-09' --warmup-updates 10000 \ --warmup-init-lr '1e-07' --label-smoothing 0.1 \ --dropout 0.3 --weight-decay 0.01 \ --decoder-learned-pos \ @@ -165,7 +165,7 @@ fairseq-train \ --share-all-embeddings \ --optimizer adam --adam-betas '(0.9,0.98)' \ --lr 0.0005 --lr-scheduler inverse_sqrt \ - --min-lr '1e-09' --warmup-updates 10000 \ + --stop-min-lr '1e-09' --warmup-updates 10000 \ --warmup-init-lr '1e-07' --label-smoothing 0.1 \ --dropout 0.3 --weight-decay 0.01 \ --decoder-learned-pos \ diff --git a/examples/pay_less_attention_paper/README.md b/examples/pay_less_attention_paper/README.md index 3fb93b23d1..537ca5f25b 100644 --- a/examples/pay_less_attention_paper/README.md +++ b/examples/pay_less_attention_paper/README.md @@ -110,7 +110,7 @@ mkdir -p $SAVE CUDA_VISIBLE_DEVICES=0 $(which fairseq-train) data-bin/iwslt14.tokenized.de-en \ --clip-norm 0 --optimizer adam --lr 0.0005 \ --source-lang de --target-lang en --max-tokens 4000 --no-progress-bar \ - --log-interval 100 --min-lr '1e-09' --weight-decay 0.0001 \ + --log-interval 100 --stop-min-lr '1e-09' --weight-decay 0.0001 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --lr-scheduler inverse_sqrt \ --ddp-backend=no_c10d \ @@ -137,10 +137,10 @@ python -m torch.distributed.launch --nproc_per_node 8 $(which fairseq-train) \ --max-update 30000 --share-all-embeddings --optimizer adam \ --adam-betas '(0.9, 0.98)' --clip-norm 0.0 --weight-decay 0.0 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ - --min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ + --stop-min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ --ddp-backend=no_c10d --max-tokens 3584 \ --lr-scheduler cosine --warmup-init-lr 1e-7 --warmup-updates 10000 \ - --lr-shrink 1 --max-lr 0.001 --lr 1e-7 --min-lr 1e-9 --warmup-init-lr 1e-07 \ + --lr-shrink 1 --max-lr 0.001 --lr 1e-7 --warmup-init-lr 1e-07 \ --t-mult 1 --lr-period-updates 20000 \ --arch lightconv_wmt_en_de_big --save-dir $SAVE \ --dropout 0.3 --attention-dropout 0.1 --weight-dropout 0.1 \ @@ -162,10 +162,10 @@ python -m torch.distributed.launch --nproc_per_node 8 $(which fairseq-train) \ --max-update 30000 --share-all-embeddings --optimizer adam \ --adam-betas '(0.9, 0.98)' --clip-norm 0.0 --weight-decay 0.0 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ - --min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ + --stop-min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ --ddp-backend=no_c10d --max-tokens 3584 \ --lr-scheduler cosine --warmup-init-lr 1e-7 --warmup-updates 10000 \ - --lr-shrink 1 --max-lr 0.001 --lr 1e-7 --min-lr 1e-9 --warmup-init-lr 1e-07 \ + --lr-shrink 1 --max-lr 0.001 --lr 1e-7 --warmup-init-lr 1e-07 \ --t-mult 1 --lr-period-updates 70000 \ --arch lightconv_wmt_en_fr_big --save-dir $SAVE \ --dropout 0.1 --attention-dropout 0.1 --weight-dropout 0.1 \ diff --git a/examples/quant_noise/README.md b/examples/quant_noise/README.md index 057ea620ab..9fe492d0cf 100644 --- a/examples/quant_noise/README.md +++ b/examples/quant_noise/README.md @@ -212,7 +212,7 @@ fairseq-train --task language_modeling /path/to/wikitext-103/data \ --max-tokens 3072 --tokens-per-sample 3072 --momentum 0.99 --optimizer nag \ --sample-break-mode none --update-freq 3 \ --warmup-init-lr 1e-07 --warmup-updates 16000 \ - --weight-decay 0 --seed 1 --min-lr 1e-09 \ + --weight-decay 0 --seed 1 --stop-min-lr 1e-09 \ --quant-noise-pq 0.05 --quant-noise-pq-block-size 8 ``` @@ -269,7 +269,7 @@ fairseq-train --task language_modeling /path/to/wikitext-103/data \ --ddp-backend no_c10d \ --decoder-attention-heads 8 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-input-dim 1024 --decoder-layers 16 --decoder-normalize-before --decoder-output-dim 1024 \ --fp16 --keep-last-epochs -1 \ - --lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --max-lr 0.05 --min-lr 1e-09 \ + --lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --max-lr 0.05 --stop-min-lr 1e-09 \ --max-tokens 2944 --tokens-per-sample 2944\ --momentum 0.99 --no-epoch-checkpoints --no-progress-bar --optimizer nag --required-batch-size-multiple 8 \ --sample-break-mode none --t-mult 2.0 --skip-invalid-size-inputs-valid-test \ diff --git a/examples/simultaneous_translation/README.md b/examples/simultaneous_translation/README.md index e27b65280e..bbc6dacdda 100644 --- a/examples/simultaneous_translation/README.md +++ b/examples/simultaneous_translation/README.md @@ -23,7 +23,7 @@ fairseq-train \ --optimizer adam --adam-betas '(0.9, 0.98)' \ --lr-scheduler 'inverse_sqrt' \ --warmup-init-lr 1e-7 --warmup-updates 4000 \ - --lr 5e-4 --min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ + --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ --dropout 0.3 \ --label-smoothing 0.1\ --max-tokens 3584 @@ -44,7 +44,7 @@ fairseq-train \ --optimizer adam --adam-betas '(0.9, 0.98)' \ --lr-scheduler 'inverse_sqrt' \ --warmup-init-lr 1e-7 --warmup-updates 4000 \ - --lr 5e-4 --min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ + --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ --dropout 0.3 \ --label-smoothing 0.1\ --max-tokens 3584 @@ -65,7 +65,7 @@ fairseq-train \ --optimizer adam --adam-betas '(0.9, 0.98)' \ --lr-scheduler 'inverse_sqrt' \ --warmup-init-lr 1e-7 --warmup-updates 4000 \ - --lr 5e-4 --min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ + --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ --dropout 0.3 \ --label-smoothing 0.1\ --max-tokens 3584 diff --git a/examples/translation/README.md b/examples/translation/README.md index 3eb8e01310..7b1fcc8de2 100644 --- a/examples/translation/README.md +++ b/examples/translation/README.md @@ -268,7 +268,7 @@ CUDA_VISIBLE_DEVICES=0 fairseq-train data-bin/iwslt17.de_fr.en.bpe16k/ \ --arch multilingual_transformer_iwslt_de_en \ --share-decoders --share-decoder-input-output-embed \ --optimizer adam --adam-betas '(0.9, 0.98)' \ - --lr 0.0005 --lr-scheduler inverse_sqrt --min-lr '1e-09' \ + --lr 0.0005 --lr-scheduler inverse_sqrt \ --warmup-updates 4000 --warmup-init-lr '1e-07' \ --label-smoothing 0.1 --criterion label_smoothed_cross_entropy \ --dropout 0.3 --weight-decay 0.0001 \ diff --git a/examples/translation_moe/README.md b/examples/translation_moe/README.md index ef7abdb44b..3cc3fb46dc 100644 --- a/examples/translation_moe/README.md +++ b/examples/translation_moe/README.md @@ -24,7 +24,7 @@ fairseq-train --ddp-backend='no_c10d' \ --arch transformer_wmt_en_de --share-all-embeddings \ --optimizer adam --adam-betas '(0.9, 0.98)' --clip-norm 0.0 \ --lr-scheduler inverse_sqrt --warmup-init-lr 1e-07 --warmup-updates 4000 \ - --lr 0.0007 --min-lr 1e-09 \ + --lr 0.0007 \ --dropout 0.1 --weight-decay 0.0 --criterion cross_entropy \ --max-tokens 3584 ``` diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 52dce362ab..bf501ab9af 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -186,7 +186,7 @@ $ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/pa ``` $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ ---arch wav2vec --task audio_pretraining --lr 1e-06 --min-lr 1e-09 --optimizer adam --max-lr 0.005 --lr-scheduler cosine \ +--arch wav2vec --task audio_pretraining --lr 1e-06 --stop-min-lr 1e-09 --optimizer adam --max-lr 0.005 --lr-scheduler cosine \ --conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1)] \ --conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ --skip-connections-agg --residual-scale 0.5 --log-compression --warmup-updates 500 --warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 \ @@ -244,7 +244,7 @@ $ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/pa ``` $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 \ ---save-interval 1 --no-epoch-checkpoints --arch wav2vec --task audio_pretraining --lr 1e-06 --min-lr 1e-09 \ +--save-interval 1 --no-epoch-checkpoints --arch wav2vec --task audio_pretraining --lr 1e-06 --stop-min-lr 1e-09 \ --optimizer adam --max-lr 1e-05 --lr-scheduler cosine \ --conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1), (512, 1, 1)] \ --conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 235c660a5e..f03875da50 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -458,7 +458,6 @@ def _upgrade_state_dict(state): "iterations_in_epoch": state["extra_state"].get("batch_offset", 0), } - # old model checkpoints may not have separate source/target positions # backward compatibility, cfg updates if "args" in state and state["args"] is not None: # default to translation task @@ -474,15 +473,20 @@ def _upgrade_state_dict(state): state["extra_state"]["train_iterator"]["epoch"] = max( state["extra_state"]["train_iterator"].get("epoch", 1), 1 ) - + # --remove-bpe ==> --postprocess if hasattr(state["args"], "remove_bpe"): state["args"].post_process = state["args"].remove_bpe + # --min-lr ==> --stop-min-lr + if hasattr(state["args"], "min_lr"): + state["args"].stop_min_lr = state["args"].min_lr + del state["args"].min_lr state["cfg"] = convert_namespace_to_omegaconf(state["args"]) if "cfg" in state and state["cfg"] is not None: with open_dict(state["cfg"]): if state["cfg"].task is not None: + # old model checkpoints may not have separate source/target positions if hasattr(state["cfg"].task, "max_positions") and not hasattr( state["cfg"].task, "max_source_positions" ): diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 3ff177d969..3992e3c2d5 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -465,7 +465,7 @@ class OptimizationConfig(FairseqDataclass): " (note: this may be interpreted differently depending on --lr-scheduler)" }, ) - min_lr: float = field( + stop_min_lr: float = field( default=-1.0, metadata={"help": "stop training when the learning rate reaches this minimum"}, ) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 7739759693..82c30321eb 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -125,7 +125,15 @@ def main(cfg: DictConfig) -> None: lr = trainer.get_lr() train_meter = meters.StopwatchMeter() train_meter.start() - while lr > cfg.optimization.min_lr and epoch_itr.next_epoch_idx <= max_epoch: + while epoch_itr.next_epoch_idx <= max_epoch: + if lr <= cfg.optimization.stop_min_lr: + logger.info( + f"stopping training because current learning rate ({lr}) is smaller " + "than or equal to minimum learning rate " + f"(--stop-min-lr={cfg.optimization.stop_min_lr})" + ) + break + # train for one epoch valid_losses, should_stop = train(cfg, trainer, task, epoch_itr) if should_stop: diff --git a/tests/test_binaries.py b/tests/test_binaries.py index cad6f1eba4..58f86484f7 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -1454,7 +1454,7 @@ def train_legacy_masked_language_model(data_dir, arch, extra_args=()): "0.5", "--lr", "0.0001", - "--min-lr", + "--stop-min-lr", "1e-09", # dropout, attention args "--dropout", From 4817a9142f49793ec2eedbd71fe5bd872e58e7b5 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sat, 5 Dec 2020 07:36:28 -0800 Subject: [PATCH 102/774] Cleanup CosineLRScheduler and change defaults (#1487) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1487 Here's the code for CosineLRScheduler that I used as a reference: https://github.com/pytorch/fairseq/blob/577e4fa78a295fd7cd3ee7e9fd4b936ca800ebea/fairseq/optim/lr_scheduler/cosine_lr_schedul In the reference: - `warmup_init_lr` defaults to `args.lr[0]` - `warmup_end_lr` defaults to `args.max_lr` - `min_lr` defaults to `args.lr[0]` (note that there's also a `args.min_lr` option defined in the global fairseq config, but this is unused by the cosine scheduler) - `max_lr` is a required option This diff removes `max_lr` and replaces it with `lr[0]` to be more consistent with other LR schedulers. We then add an explicit `min_lr` option to the Config. Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25342180 Pulled By: myleott fbshipit-source-id: 61281666e68839da8efc4714c2ce8c49dc4c8e6e --- .../language_model/README.adaptive_inputs.md | 4 +-- examples/pay_less_attention_paper/README.md | 4 +-- examples/quant_noise/README.md | 4 +-- examples/truncated_bptt/README.md | 2 +- examples/wav2vec/README.md | 6 ++-- .../optim/lr_scheduler/cosine_lr_scheduler.py | 32 +++++++++---------- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/language_model/README.adaptive_inputs.md b/examples/language_model/README.adaptive_inputs.md index 2ab3733018..98043c5377 100644 --- a/examples/language_model/README.adaptive_inputs.md +++ b/examples/language_model/README.adaptive_inputs.md @@ -19,8 +19,8 @@ fairseq-train --task language_modeling \ data-bin/wikitext-103 \ --save-dir checkpoints/transformer_wikitext-103 \ --arch transformer_lm_wiki103 \ - --max-update 286000 --max-lr 1.0 --t-mult 2 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 \ - --warmup-updates 16000 --warmup-init-lr 1e-07 --stop-min-lr 1e-09 --optimizer nag --lr 0.0001 --clip-norm 0.1 \ + --max-update 286000 --lr 1.0 --t-mult 2 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 \ + --warmup-updates 16000 --warmup-init-lr 1e-07 --stop-min-lr 1e-09 --optimizer nag --min-lr 0.0001 --clip-norm 0.1 \ --criterion adaptive_loss --max-tokens 3072 --update-freq 3 --tokens-per-sample 3072 --seed 1 \ --sample-break-mode none --skip-invalid-size-inputs-valid-test --ddp-backend=no_c10d ``` diff --git a/examples/pay_less_attention_paper/README.md b/examples/pay_less_attention_paper/README.md index 537ca5f25b..d5b19af6cc 100644 --- a/examples/pay_less_attention_paper/README.md +++ b/examples/pay_less_attention_paper/README.md @@ -140,7 +140,7 @@ python -m torch.distributed.launch --nproc_per_node 8 $(which fairseq-train) \ --stop-min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ --ddp-backend=no_c10d --max-tokens 3584 \ --lr-scheduler cosine --warmup-init-lr 1e-7 --warmup-updates 10000 \ - --lr-shrink 1 --max-lr 0.001 --lr 1e-7 --warmup-init-lr 1e-07 \ + --lr-shrink 1 --lr 0.001 --min-lr 1e-7 --warmup-init-lr 1e-07 \ --t-mult 1 --lr-period-updates 20000 \ --arch lightconv_wmt_en_de_big --save-dir $SAVE \ --dropout 0.3 --attention-dropout 0.1 --weight-dropout 0.1 \ @@ -165,7 +165,7 @@ python -m torch.distributed.launch --nproc_per_node 8 $(which fairseq-train) \ --stop-min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ --ddp-backend=no_c10d --max-tokens 3584 \ --lr-scheduler cosine --warmup-init-lr 1e-7 --warmup-updates 10000 \ - --lr-shrink 1 --max-lr 0.001 --lr 1e-7 --warmup-init-lr 1e-07 \ + --lr-shrink 1 --lr 0.001 --min-lr 1e-7 --warmup-init-lr 1e-07 \ --t-mult 1 --lr-period-updates 70000 \ --arch lightconv_wmt_en_fr_big --save-dir $SAVE \ --dropout 0.1 --attention-dropout 0.1 --weight-dropout 0.1 \ diff --git a/examples/quant_noise/README.md b/examples/quant_noise/README.md index 9fe492d0cf..7fe301f732 100644 --- a/examples/quant_noise/README.md +++ b/examples/quant_noise/README.md @@ -208,7 +208,7 @@ fairseq-train --task language_modeling /path/to/wikitext-103/data \ --ddp-backend no_c10d \ --decoder-attention-heads 8 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-input-dim 1024 \ --decoder-layers 16 --decoder-normalize-before --decoder-output-dim 1024 \ - --lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --max-lr 1.0 --t-mult 2.0 \ + --min-lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --lr 1.0 --t-mult 2.0 \ --max-tokens 3072 --tokens-per-sample 3072 --momentum 0.99 --optimizer nag \ --sample-break-mode none --update-freq 3 \ --warmup-init-lr 1e-07 --warmup-updates 16000 \ @@ -269,7 +269,7 @@ fairseq-train --task language_modeling /path/to/wikitext-103/data \ --ddp-backend no_c10d \ --decoder-attention-heads 8 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-input-dim 1024 --decoder-layers 16 --decoder-normalize-before --decoder-output-dim 1024 \ --fp16 --keep-last-epochs -1 \ - --lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --max-lr 0.05 --stop-min-lr 1e-09 \ + --min-lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --lr 0.05 --stop-min-lr 1e-09 \ --max-tokens 2944 --tokens-per-sample 2944\ --momentum 0.99 --no-epoch-checkpoints --no-progress-bar --optimizer nag --required-batch-size-multiple 8 \ --sample-break-mode none --t-mult 2.0 --skip-invalid-size-inputs-valid-test \ diff --git a/examples/truncated_bptt/README.md b/examples/truncated_bptt/README.md index f5c6447f1c..86518c9d5e 100644 --- a/examples/truncated_bptt/README.md +++ b/examples/truncated_bptt/README.md @@ -37,7 +37,7 @@ CUDA_VISIBLE_DEVICES=0,1,2,3 fairseq-train \ --arch transformer_xl --n-layer 16 --d-model 410 --n-head 10 \ --d-head 41 --d-inner 2100 --dropout 0.1 --dropatt 0.0 --mem-len 150 \ --optimizer adam --clip-norm 0.25 \ - --lr-scheduler cosine --warmup-updates 0 --lr 0.0 --max-lr 0.00025 \ + --lr-scheduler cosine --warmup-updates 0 --min-lr 0.0 --lr 0.00025 \ --log-format json --log-interval 25 \ --fp16 ``` diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index bf501ab9af..4089edf42b 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -186,7 +186,7 @@ $ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/pa ``` $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ ---arch wav2vec --task audio_pretraining --lr 1e-06 --stop-min-lr 1e-09 --optimizer adam --max-lr 0.005 --lr-scheduler cosine \ +--arch wav2vec --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 --optimizer adam --lr 0.005 --lr-scheduler cosine \ --conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1)] \ --conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ --skip-connections-agg --residual-scale 0.5 --log-compression --warmup-updates 500 --warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 \ @@ -244,8 +244,8 @@ $ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/pa ``` $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 \ ---save-interval 1 --no-epoch-checkpoints --arch wav2vec --task audio_pretraining --lr 1e-06 --stop-min-lr 1e-09 \ ---optimizer adam --max-lr 1e-05 --lr-scheduler cosine \ +--save-interval 1 --no-epoch-checkpoints --arch wav2vec --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 \ +--optimizer adam --lr 1e-05 --lr-scheduler cosine \ --conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1), (512, 1, 1)] \ --conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ --activation gelu --offset auto --skip-connections-agg --residual-scale 0.5 \ diff --git a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py index d73c7cc7ed..38b57fe54c 100644 --- a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py @@ -26,9 +26,11 @@ class CosineLRScheduleConfig(FairseqDataclass): "help": "initial learning rate during warmup phase; default is cfg.lr" }, ) - max_lr: float = field( - default=1.0, metadata={"help": "max learning rate, must be more than cfg.lr"} + lr: List[float] = field( + default=II("optimization.lr"), + metadata={"help": "max learning rate, must be more than cfg.min_lr"}, ) + min_lr: float = field(default=0.0, metadata={"help": "min learning rate"}) t_mult: float = field( default=1.0, metadata={"help": "factor to grow the length of each period"} ) @@ -38,7 +40,7 @@ class CosineLRScheduleConfig(FairseqDataclass): lr_shrink: float = field( default=0.1, metadata={"help": "shrink factor for annealing"} ) - lr: List[float] = II("optimization.lr") + # This is not required, but is for convenience in inferring lr_period_updates max_update: int = II("optimization.max_update") @@ -50,7 +52,7 @@ class CosineLRSchedule(FairseqLRScheduler): We also support a warmup phase where we linearly increase the learning rate from some initial learning rate (``--warmup-init-lr``) until the configured - max learning rate (``--max-lr``). + max learning rate (``--lr``). During warmup:: @@ -59,7 +61,7 @@ class CosineLRSchedule(FairseqLRScheduler): After warmup:: - lr = lr_min + 0.5*(lr_max - lr_min)*(1 + cos(t_curr / t_i)) + lr = cfg.min_lr + 0.5*(cfg.lr - cfg.min_lr)*(1 + cos(t_curr / t_i)) where ``t_curr`` is current percentage of updates within the current period range and ``t_i`` is the current period range, which is scaled by ``t_mul`` @@ -74,23 +76,21 @@ def __init__(self, cfg: CosineLRScheduleConfig, fairseq_optimizer): f" Consider --lr-scheduler=fixed instead. ({cfg.lr})" ) - warmup_end_lr = cfg.max_lr - lr = cfg.lr[0] if isinstance(cfg.lr, Collection) else cfg.lr - if cfg.warmup_init_lr < 0: - cfg.warmup_init_lr = lr + self.max_lr = cfg.lr[0] if isinstance(cfg.lr, Collection) else cfg.lr + assert ( + self.max_lr > cfg.min_lr + ), f"max_lr (={cfg.lr}) must be more than min_lr (={cfg.min_lr})" - # default min_lr=-1 -> cosine anneale to lr=0.0 - # otherwise pick min_lr from config - self.min_lr = cfg.min_lr if cfg.min_lr > 0.0 else 0.0 - self.max_lr = lr - assert self.max_lr > self.min_lr, "max_lr must be more than lr" + warmup_end_lr = self.max_lr + if cfg.warmup_init_lr < 0: + cfg.warmup_init_lr = cfg.min_lr self.t_mult = cfg.t_mult self.period = cfg.lr_period_updates if self.period <= 0: assert ( - cfg.max_update >= 0 + cfg.max_update > 0 ), "Either --max_update or --lr-period-updates must be set" self.period = cfg.max_update - cfg.warmup_updates @@ -136,7 +136,7 @@ def step_update(self, num_updates): t_curr = curr_updates - (self.period * i) lr_shrink = self.lr_shrink ** i - min_lr = self.min_lr * lr_shrink + min_lr = self.cfg.min_lr * lr_shrink max_lr = self.max_lr * lr_shrink self.lr = min_lr + 0.5 * (max_lr - min_lr) * ( From feb5f07ff4220b7908ff12c6692685784c7c9a71 Mon Sep 17 00:00:00 2001 From: alexeib Date: Tue, 8 Dec 2020 15:47:53 -0800 Subject: [PATCH 103/774] fix wav2vec scripts (#1494) Summary: fixes #2942 + docs + migration of old models Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1494 Reviewed By: myleott Differential Revision: D25404601 Pulled By: alexeib fbshipit-source-id: 092f145602522f8e7ea3eaa709bfe602a4d29d8b --- examples/wav2vec/README.md | 12 ++++++------ examples/wav2vec/vq-wav2vec_featurize.py | 11 ++++------- examples/wav2vec/wav2vec_featurize.py | 8 +++----- fairseq/checkpoint_utils.py | 9 +++++++++ fairseq/dataclass/utils.py | 5 +++++ 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 4089edf42b..05df59f214 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -160,11 +160,11 @@ Wav2Vec large | [Librispeech](http://www.openslr.org/12) | [download](https://dl #### Example usage: ```python import torch -from fairseq.models.wav2vec import Wav2VecModel +import fairseq cp = torch.load('/path/to/wav2vec.pt') -model = Wav2VecModel.build_model(cp['args'], task=None) -model.load_state_dict(cp['model']) +model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp]) +model = model[0] model.eval() wav_input_16khz = torch.randn(1,10000) @@ -217,11 +217,11 @@ Roberta on K-means codes | [Librispeech](http://www.openslr.org/12) | [download] #### Example usage: ```python import torch -from fairseq.models.wav2vec import Wav2VecModel +import fairseq cp = torch.load('/path/to/vq-wav2vec.pt') -model = Wav2VecModel.build_model(cp['args'], task=None) -model.load_state_dict(cp['model']) +model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp]) +model = model[0] model.eval() wav_input_16khz = torch.randn(1,10000) diff --git a/examples/wav2vec/vq-wav2vec_featurize.py b/examples/wav2vec/vq-wav2vec_featurize.py index baabc1d365..1adb52de1c 100644 --- a/examples/wav2vec/vq-wav2vec_featurize.py +++ b/examples/wav2vec/vq-wav2vec_featurize.py @@ -16,8 +16,7 @@ import soundfile as sf import torch -import tqdm -from fairseq.models.wav2vec.wav2vec import Wav2VecModel +import fairseq from torch import nn from torch.utils.data import DataLoader @@ -211,13 +210,11 @@ def load_data(self, fnames): return loader def load_model(self): - cp = torch.load(self.checkpoint, map_location=lambda x, _: x) + model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([self.checkpoint]) + model = model[0] - model = Wav2VecModel.build_model(cp["args"], None) + self.quantize_location = getattr(cfg.model, "vq", "encoder") - self.quantize_location = getattr(cp["args"], "vq", "encoder") - - model.load_state_dict(cp["model"]) model.eval().float() model.cuda() diff --git a/examples/wav2vec/wav2vec_featurize.py b/examples/wav2vec/wav2vec_featurize.py index 9283930587..b806316e5a 100644 --- a/examples/wav2vec/wav2vec_featurize.py +++ b/examples/wav2vec/wav2vec_featurize.py @@ -18,7 +18,7 @@ import soundfile as sf import torch import tqdm -from fairseq.models.wav2vec.wav2vec import Wav2VecModel +import fairseq from torch import nn @@ -35,10 +35,8 @@ class PretrainedWav2VecModel(nn.Module): def __init__(self, fname): super().__init__() - checkpoint = torch.load(fname) - self.args = checkpoint["args"] - model = Wav2VecModel.build_model(self.args, None) - model.load_state_dict(checkpoint["model"]) + model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([fname]) + model = model[0] model.eval() self.model = model diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index f03875da50..6209c71aef 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -480,6 +480,15 @@ def _upgrade_state_dict(state): if hasattr(state["args"], "min_lr"): state["args"].stop_min_lr = state["args"].min_lr del state["args"].min_lr + # binary_cross_entropy => wav2vec criterion + if hasattr(state["args"], "criterion") and state["args"].criterion == "binary_cross_entropy": + state["args"].criterion = "wav2vec" + # speech_pretraining => audio pretraining + if hasattr(state["args"], "task") and state["args"].task == "speech_pretraining": + state["args"].task = "audio_pretraining" + # audio_cpc => wav2vec + if hasattr(state["args"], "arch") and state["args"].arch == "audio_cpc": + state["args"].arch = "wav2vec" state["cfg"] = convert_namespace_to_omegaconf(state["args"]) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index e25838400c..9d52d45942 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -237,6 +237,11 @@ def get_default(f): t_args = v.type.__args__ if len(t_args) == 1: val = list(map(t_args[0], val)) + elif val is not None and (field_type is int or field_type is bool or field_type is float): + try: + val = field_type(val) + except: + pass # ignore errors here, they are often from interpolation args if val is None: overrides.append("{}.{}=null".format(sub_node, k)) From 606b3b8c8d7e15dad66b177cde66a04621349e6c Mon Sep 17 00:00:00 2001 From: Peng-Jen Chen Date: Thu, 10 Dec 2020 11:57:14 -0800 Subject: [PATCH 104/774] Release WMT20 MT/LM models Summary: Add README to expose wmt20 model paths to download and torch.hub examples. Reviewed By: ngoyal2707 Differential Revision: D25456298 fbshipit-source-id: 8c78bffb3f539963cbf61e508a56e421929925f0 --- fairseq/models/transformer.py | 13 +++++++++++++ fairseq/models/transformer_lm.py | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 70920ed779..9655578e52 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -71,6 +71,13 @@ def moses_fastbpe(path): 'bpe': 'fastbpe', } + def spm(path): + return { + 'path': path, + 'bpe': 'sentencepiece', + 'tokenizer': 'space', + } + return { 'transformer.wmt14.en-fr': moses_subword('https://dl.fbaipublicfiles.com/fairseq/models/wmt14.en-fr.joined-dict.transformer.tar.bz2'), 'transformer.wmt16.en-de': 'https://dl.fbaipublicfiles.com/fairseq/models/wmt16.en-de.joined-dict.transformer.tar.bz2', @@ -83,6 +90,12 @@ def moses_fastbpe(path): 'transformer.wmt19.en-ru.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-ru.single_model.tar.gz'), 'transformer.wmt19.de-en.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.de-en.joined-dict.single_model.tar.gz'), 'transformer.wmt19.ru-en.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.ru-en.single_model.tar.gz'), + 'transformer.wmt20.en-ta': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-ta.single.tar.gz'), + 'transformer.wmt20.en-iu.news': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.news.single.tar.gz'), + 'transformer.wmt20.en-iu.nh': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.nh.single.tar.gz'), + 'transformer.wmt20.ta-en': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta-en.single.tar.gz'), + 'transformer.wmt20.iu-en.news': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.news.single.tar.gz'), + 'transformer.wmt20.iu-en.nh': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.nh.single.tar.gz'), } # fmt: on diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index 35bfa6eb6f..d86b68b508 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -171,6 +171,8 @@ class TransformerLanguageModel(FairseqLanguageModel): def hub_models(cls): def moses_fastbpe(path): return {"path": path, "tokenizer": "moses", "bpe": "fastbpe"} + def spm(path): + return {"path": path, "tokenizer": "space", "bpe": "sentencepiece"} return { "transformer_lm.gbw.adaptive_huge": "https://dl.fbaipublicfiles.com/fairseq/models/lm/adaptive_lm_gbw_huge.tar.bz2", @@ -184,6 +186,18 @@ def moses_fastbpe(path): "transformer_lm.wmt19.ru": moses_fastbpe( "https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt19.ru.tar.bz2" ), + "transformer_lm.wmt20.en": spm( + "https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt20.en.tar.gz" + ), + "transformer_lm.wmt20.ta": spm( + "https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt20.ta.tar.gz" + ), + "transformer_lm.wmt20.iu.news": spm( + "https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt20.iu.news.tar.gz" + ), + "transformer_lm.wmt20.iu.nh": spm( + "https://dl.fbaipublicfiles.com/fairseq/models/lm/wmt20.iu.nh.tar.gz" + ), } def __init__(self, decoder): From 43e4db8cd77dab63836a9d6dbb239d27ee2641d7 Mon Sep 17 00:00:00 2001 From: Peng-Jen Chen Date: Fri, 11 Dec 2020 06:22:57 -0800 Subject: [PATCH 105/774] Add default dataclass to space_tokenizer and nltk_tokenizer Summary: The default dataclass of `space_tokenizer` is `None`, this somehow breaks when we load a model with space tokenizer from `torch.hub` (full message: P154020599): ``` ... hydra.errors.MissingConfigException: Could not load tokenizer/space. Available options: moses ``` Adding default dataclass to `FairseqDataclass` to solve the problem. Note: another fix might be setting the default dataclass to `FairseqDataclass` here: https://www.internalfb.com/intern/diffusion/FBS/browsefile/master/fbcode/deeplearning/projects/fairseq-py/fairseq/registry.py?commit=1ae2e67d969ca090b41a6fa33ca9aaf360a26d3f&lines=63 Reviewed By: myleott Differential Revision: D25466594 fbshipit-source-id: aa4ec23731081e266ce641ea3db179169233842c --- fairseq/data/encoders/nltk_tokenizer.py | 3 ++- fairseq/data/encoders/space_tokenizer.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fairseq/data/encoders/nltk_tokenizer.py b/fairseq/data/encoders/nltk_tokenizer.py index ee164710a0..0ab92377b3 100644 --- a/fairseq/data/encoders/nltk_tokenizer.py +++ b/fairseq/data/encoders/nltk_tokenizer.py @@ -4,9 +4,10 @@ # LICENSE file in the root directory of this source tree. from fairseq.data.encoders import register_tokenizer +from fairseq.dataclass import FairseqDataclass -@register_tokenizer("nltk") +@register_tokenizer("nltk", dataclass=FairseqDataclass) class NLTKTokenizer(object): def __init__(self, *unused): try: diff --git a/fairseq/data/encoders/space_tokenizer.py b/fairseq/data/encoders/space_tokenizer.py index 7c7f644d5c..925ad41b7c 100644 --- a/fairseq/data/encoders/space_tokenizer.py +++ b/fairseq/data/encoders/space_tokenizer.py @@ -6,9 +6,10 @@ import re from fairseq.data.encoders import register_tokenizer +from fairseq.dataclass import FairseqDataclass -@register_tokenizer("space") +@register_tokenizer("space", dataclass=FairseqDataclass) class SpaceTokenizer(object): def __init__(self, *unused): self.space_tok = re.compile(r"\s+") From 5430df004ff4a5928e0295f3c8ac0b29132bd6a8 Mon Sep 17 00:00:00 2001 From: Peng-Jen Chen Date: Fri, 11 Dec 2020 08:37:38 -0800 Subject: [PATCH 106/774] Add WMT20 page to fairseq-py/example Summary: Add WMT20 page to fairseq-py/example to release WMT20 models Reviewed By: myleott, ngoyal2707 Differential Revision: D25495578 fbshipit-source-id: 088a457e379b5227cf45a5db1901073499a2e4c1 --- examples/wmt20/README.md | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 examples/wmt20/README.md diff --git a/examples/wmt20/README.md b/examples/wmt20/README.md new file mode 100644 index 0000000000..7bfec0ee55 --- /dev/null +++ b/examples/wmt20/README.md @@ -0,0 +1,70 @@ +# WMT 20 + +This page provides pointers to the models of Facebook-FAIR's WMT'20 news translation task submission [(Chen et al., 2020)](https://arxiv.org/abs/2011.08298). + +## Single best MT models (after finetuning on part of WMT20 news dev set) + +Model | Description | Download +---|---|--- +`transformer.wmt20.ta-en` | Ta->En | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta-en.single.tar.gz) +`transformer.wmt20.en-ta` | En->Ta | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-ta.single.tar.gz) +`transformer.wmt20.iu-en.news` | Iu->En (News domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.news.single.tar.gz) +`transformer.wmt20.en-iu.news` | En->Iu (News domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.news.single.tar.gz) +`transformer.wmt20.iu-en.nh` | Iu->En (Nunavut Hansard domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.nh.single.tar.gz) +`transformer.wmt20.en-iu.nh` | En->Iu (Nunavut Hansard domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.nh.single.tar.gz) + +## Language models +`transformer_lm.wmt20.en` | En Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en.tar.gz) +`transformer_lm.wmt20.ta` | Ta Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta.tar.gz) +`transformer_lm.wmt20.iu.news` | Iu Language Model (News domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu.news.tar.gz) +`transformer_lm.wmt20.iu.nh` | Iu Language Model (Nunavut Hansard domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu.nh.tar.gz) + +## Example usage (torch.hub) + +#### Translation + +```python +import torch + +# English to Tamil translation +en2ta = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.en-ta') +en2ta.translate("Machine learning is great!") # 'இயந்திரக் கற்றல் அருமை!' + +# Tamil to English translation +ta2en = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.ta-en') +ta2en.translate("இயந்திரக் கற்றல் அருமை!") # 'Machine learning is great!' + +# English to Inuktitut translation +en2iu = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.en-iu.news') +en2iu.translate("machine learning is great!") # 'ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ ᐱᐅᔪᒻᒪᕆᒃ!' + +# Inuktitut to English translation +iu2en = torch.hub.load('pytorch/fairseq', 'transformer.wmt20.iu-en.news') +iu2en.translate("ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ ᐱᐅᔪᒻᒪᕆᒃ!") # 'Machine learning excellence!' +``` + +#### Language Modeling + +```python +# Sample from the English LM +en_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt20.en') +en_lm.sample("Machine learning is") # 'Machine learning is a type of artificial intelligence that uses machine learning to learn from data and make predictions.' + +# Sample from the Tamil LM +ta_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt20.ta') +ta_lm.sample("இயந்திரக் கற்றல் என்பது செயற்கை நுண்ணறிவின்") # 'இயந்திரக் கற்றல் என்பது செயற்கை நுண்ணறிவின் ஒரு பகுதியாகும்.' + +# Sample from the Inuktitut LM +iu_lm = torch.hub.load('pytorch/fairseq', 'transformer_lm.wmt20.iu.news') +iu_lm.sample("ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ") # 'ᖃᒧᑕᐅᔭᓄᑦ ᐃᓕᓐᓂᐊᕐᓂᖅ, ᐊᒻᒪᓗ ᓯᓚᐅᑉ ᐊᓯᙳᖅᐸᓪᓕᐊᓂᖓᓄᑦ ᖃᓄᐃᓕᐅᕈᑎᒃᓴᑦ, ᐃᓚᖃᖅᖢᑎᒃ ᐅᑯᓂᖓ:' +``` + +## Citation +```bibtex +@inproceedings{chen2020facebook + title={Facebook AI's WMT20 News Translation Task Submission}, + author={Peng-Jen Chen and Ann Lee and Changhan Wang and Naman Goyal and Angela Fan and Mary Williamson and Jiatao Gu}, + booktitle={Proc. of WMT}, + year={2020}, +} +``` From 3a2c0a2558aaf363c8ecc6967c9ae63f23a58502 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 11 Dec 2020 09:55:24 -0800 Subject: [PATCH 107/774] Back out "Improve performance of distributed_utils.broadcast_object" Summary: Original commit changeset: 521102fae75a Reviewed By: ngoyal2707 Differential Revision: D25494613 fbshipit-source-id: 64aead87ee84f4294fd37f2de12689b909e11ff1 --- fairseq/distributed_utils.py | 126 ++++++----------------------------- 1 file changed, 21 insertions(+), 105 deletions(-) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 8f98ac88f9..dd93cda35c 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -14,7 +14,6 @@ import warnings from argparse import Namespace from collections import OrderedDict -from dataclasses import dataclass from typing import Any, Dict, List, Mapping, Optional import torch @@ -643,127 +642,44 @@ def get_from_stack(key): return OrderedDict([(key, get_from_stack(key)) for key in data_keys]) -def broadcast_tensors( - tensors: Optional[List[torch.Tensor]], - src_rank: int, - group: object, - dist_device: Optional[torch.device] = None, -) -> List[torch.Tensor]: - """ - Broadcasts a list of tensors without other (non-src) ranks needing to know - the dtypes/shapes of the tensors. - """ - if dist_device is None: - if torch.distributed.get_backend(group) == "nccl": - dist_device = torch.device("cuda") - else: - dist_device = torch.device("cpu") - - # share metadata first to simplify transfer - is_src_rank = (get_rank(group) == src_rank) - if is_src_rank: - metadata = [ - {"size": t.size(), "dtype": t.dtype, "device": t.device} for t in tensors - ] - metadata = _broadcast_object_slow(metadata, src_rank, group, dist_device) - else: - metadata = _broadcast_object_slow(None, src_rank, group, dist_device) - - out_tensors = [] - for i, meta in enumerate(metadata): - if is_src_rank: - tensor = tensors[i] - broadcast(tensors[i].to(dist_device), src=src_rank, group=group) - else: - tensor = torch.zeros( - [meta["size"].numel()], dtype=meta["dtype"], device=dist_device - ) - broadcast(tensor, src=src_rank, group=group) - tensor = tensor.view(meta["size"]).to(meta["device"]) - out_tensors.append(tensor) - return out_tensors - - +# From fairscale/optim/utils.py def broadcast_object( obj: Any, src_rank: int, group: object, dist_device: Optional[torch.device] = None, + dist_length_dtype: Optional[torch.dtype] = torch.long, + dist_dtype: Optional[torch.dtype] = torch.uint8, ) -> Any: - """Broadcast an arbitrary Python object to other workers.""" + """ + Either broadcast from master to the fleet (default), + or use the src setting as the original rank. + """ if dist_device is None: if torch.distributed.get_backend(group) == "nccl": dist_device = torch.device("cuda") else: dist_device = torch.device("cpu") - if get_rank(group) == src_rank: - # split the tensors from the non-tensors so we can broadcast them - # directly, avoiding unnecessary serialization/deserialization - tensors = [] - obj = _split_tensors_from_obj(obj, tensors) - obj = _broadcast_object_slow(obj, src_rank, group, dist_device) - tensors = broadcast_tensors(tensors, src_rank, group, dist_device) - else: - obj = _broadcast_object_slow(None, src_rank, group, dist_device) - tensors = broadcast_tensors(None, src_rank, group, dist_device) - return _put_tensors_in_obj(obj, tensors) - - -def _broadcast_object_slow( - obj: Any, src_rank: int, group: object, dist_device: torch.device, -) -> Any: if get_rank(group) == src_rank: # Emit data buffer = io.BytesIO() torch.save(obj, buffer) - buffer = torch.ByteTensor(buffer.getbuffer()).to(dist_device) - length = torch.LongTensor([len(buffer)]).to(dist_device) - broadcast(length, src=src_rank, group=group) - broadcast(buffer, src=src_rank, group=group) + data = bytearray(buffer.getbuffer()) + length_tensor = torch.tensor( + [len(data)], dtype=dist_length_dtype, device=dist_device + ) + broadcast(length_tensor, src=src_rank, group=group) + data_send_tensor = torch.tensor(data, dtype=dist_dtype, device=dist_device) + broadcast(data_send_tensor, src=src_rank, group=group) else: # Fetch from the source - length = torch.LongTensor([0]).to(dist_device) - broadcast(length, src=src_rank, group=group) - buffer = torch.ByteTensor(int(length.item())).to(dist_device) - broadcast(buffer, src=src_rank, group=group) - buffer = io.BytesIO(buffer.cpu().numpy()) + length_tensor = torch.tensor([0], dtype=dist_length_dtype, device=dist_device) + broadcast(length_tensor, src=src_rank, group=group) + data_recv_tensor = torch.zeros( + [int(length_tensor.item())], dtype=dist_dtype, device=dist_device + ) + broadcast(data_recv_tensor, src=src_rank, group=group) + buffer = io.BytesIO(data_recv_tensor.cpu().numpy()) obj = torch.load(buffer, map_location="cpu") return obj - - -@dataclass(frozen=True) -class _TensorPlaceholder: - index: int - - -def _split_tensors_from_obj(obj: Any, tensors: List[torch.Tensor]) -> Any: - if torch.is_tensor(obj): - placeholder = _TensorPlaceholder(index=len(tensors)) - tensors.append(obj) - return placeholder - elif isinstance(obj, dict): - return {k: _split_tensors_from_obj(v, tensors) for k, v in obj.items()} - elif isinstance(obj, list): - return [_split_tensors_from_obj(v, tensors) for v in obj] - elif isinstance(obj, tuple): - return tuple(_split_tensors_from_obj(v, tensors) for v in obj) - elif isinstance(obj, set): - return {_split_tensors_from_obj(v, tensors) for v in obj} - else: - return obj - - -def _put_tensors_in_obj(obj: Any, tensors: List[torch.Tensor]) -> Any: - if isinstance(obj, _TensorPlaceholder): - return tensors[obj.index] - elif isinstance(obj, dict): - return {k: _put_tensors_in_obj(v, tensors) for k, v in obj.items()} - elif isinstance(obj, list): - return [_put_tensors_in_obj(v, tensors) for v in obj] - elif isinstance(obj, tuple): - return tuple(_put_tensors_in_obj(v, tensors) for v in obj) - elif isinstance(obj, set): - return {_put_tensors_in_obj(v, tensors) for v in obj} - else: - return obj From e8b195ac069600203da3e7d60ba29d0975dd0afd Mon Sep 17 00:00:00 2001 From: louismartin Date: Fri, 11 Dec 2020 10:18:23 -0800 Subject: [PATCH 108/774] Use deepcopy for copying cfg #3011 (#3022) Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3011. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3022 Reviewed By: myleott Differential Revision: D25495116 Pulled By: louismartin fbshipit-source-id: bcd3bc04b92f083882dfbc9110b14bb2ac7c8ce0 --- fairseq/hub_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index b716884c78..775d1f7aeb 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -157,7 +157,7 @@ def generate( )[0] # build generator using current args as well as any kwargs - gen_args = copy.copy(self.cfg.generation) + gen_args = copy.deepcopy(self.cfg.generation) with open_dict(gen_args): gen_args.beam = beam for k, v in kwargs.items(): From 13dbdf279887012ecf1bf955a114b952c8d00927 Mon Sep 17 00:00:00 2001 From: Robert Verkuil Date: Fri, 11 Dec 2020 11:44:25 -0800 Subject: [PATCH 109/774] Add S3 PathHandler to Fairseq (#1441) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## Description This PathHandler supports saving and loading from Amazon S3. For internal FB use. Intended for the use case of infrequent loading / saving (e.g. normal checkpoint reading and writing during training or when running an analysis script.) The PathHandler assumes the full contents of files to be saved / loaded can be stored temporarily in memory. Further optimizations could support streaming for handling large files. ## TODO: ~~- [ ] Switch to pid-based S3 client cache, to avoid multithreading problems.~~ - [x] Complete the test cases in test/file_io.py - [x] Unit tests complete - [x] Integration tested with the following command, to check for ability to save, resume from saved checkpoint, and re-download a file if local copy is stale. ```bash pyscrun fairseq-py/fairseq_cli/train.py \ /checkpoint/bioseq_nonsecure/rverkuil/aws/data \ --restore-file checkpoint_last.pt \ --dataset-impl fasta \ --task masked_lm --criterion masked_lm \ --arch roberta --dropout 0.0 --attention-dropout 0.0 \ --encoder-layers 2 \ --optimizer adam --lr 0.0001 \ --max-sentences 24 \ --log-format simple --log-interval 1 \ --fp16 \ --max-epoch 20 \ --max-update 20 \ --save-dir s3://fairusersglobal// ``` # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1441 Reviewed By: myleott Differential Revision: D25370388 Pulled By: robert-verkuil fbshipit-source-id: ffefbd7345f8d8ae72513f1cead94469a17c4459 --- fairseq/file_io.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fairseq/file_io.py b/fairseq/file_io.py index d667256922..d74a48591a 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -5,14 +5,29 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import logging import os import shutil from typing import List, Optional +logger = logging.getLogger(__file__) + + try: from fvcore.common.file_io import PathManager as FVCorePathManager + try: + # [FB only - for now] AWS PathHandler for PathManager + from .fb_pathhandlers import S3PathHandler + + FVCorePathManager.register_handler(S3PathHandler()) + except KeyError: + logging.warning("S3PathHandler already registered.") + except ImportError: + logging.debug( + "S3PathHandler couldn't be imported. Either missing fb-only files, or boto3 module.") + except ImportError: FVCorePathManager = None From fc7a787c01cca883330fc16d22b4693fb8277df8 Mon Sep 17 00:00:00 2001 From: Peng-Jen Chen Date: Fri, 11 Dec 2020 12:17:28 -0800 Subject: [PATCH 110/774] Update WMT20 README.md (#3027) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Fix the format # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3027 Reviewed By: ngoyal2707 Differential Revision: D25500155 Pulled By: pipibjc fbshipit-source-id: bf6298b0a4a1942e6e0e8aa632e0af7fd5c516a0 --- examples/wmt20/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/wmt20/README.md b/examples/wmt20/README.md index 7bfec0ee55..b4f2874652 100644 --- a/examples/wmt20/README.md +++ b/examples/wmt20/README.md @@ -14,6 +14,8 @@ Model | Description | Download `transformer.wmt20.en-iu.nh` | En->Iu (Nunavut Hansard domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.nh.single.tar.gz) ## Language models +Model | Description | Download +---|---|--- `transformer_lm.wmt20.en` | En Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en.tar.gz) `transformer_lm.wmt20.ta` | Ta Language Model | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta.tar.gz) `transformer_lm.wmt20.iu.news` | Iu Language Model (News domain) | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu.news.tar.gz) From d4788a9f7082c9b4a1bbe81c6e2c898e7e16ceb9 Mon Sep 17 00:00:00 2001 From: Sam Shleifer Date: Fri, 11 Dec 2020 15:20:10 -0800 Subject: [PATCH 111/774] wandb QOL: infer run name from environment or save_dir (#1500) Summary: As documented, in the , the name of a run can be controlled using either `wandb.init(name)` or the environment_variable `WANDB_NAME`. we set ```python wandb_run_name=os.environ.get("WANDB_NAME", cfg.checkpoint.save_dir) ``` to preserve the environment variable functionality documented [here](https://docs.wandb.com/library/environment-variables), and chose a sane default if this is not specified. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1500 Test Plan: ```bash WANDB_NAME=dummy2 CUDA_VISIBLE_DEVICES=0 python train.py --task dummy_lm --arch \ transformer_lm_gpt2_small --tokens-per-sample 512 --max-sentences 2 \ --lr 0.0001 --log-format simple --log-interval 1 --optimizer adam \ --fp16 --no-save --disable-validation --max-update 10 \ --restore-file x.pt --wandb-project dummy-lm ``` Reviewed By: myleott Differential Revision: D25497735 Pulled By: sshleifer fbshipit-source-id: fcd4e2a3263444e5759fae98641963fd3b9f6914 --- fairseq/logging/progress_bar.py | 15 ++++++++------- fairseq_cli/train.py | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index 2b3873794e..07ee26f4fc 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -34,6 +34,7 @@ def progress_bar( tensorboard_logdir: Optional[str] = None, default_log_format: str = "tqdm", wandb_project: Optional[str] = None, + wandb_run_name: Optional[str] = None, ): if log_format is None: log_format = default_log_format @@ -62,7 +63,7 @@ def progress_bar( bar = TensorboardProgressBarWrapper(bar, tensorboard_logdir) if wandb_project: - bar = WandBProgressBarWrapper(bar, wandb_project) + bar = WandBProgressBarWrapper(bar, wandb_project, run_name=wandb_run_name) return bar @@ -370,15 +371,15 @@ def _log_to_tensorboard(self, stats, tag=None, step=None): class WandBProgressBarWrapper(BaseProgressBar): """Log to Weights & Biases.""" - def __init__(self, wrapped_bar, wandb_project): + def __init__(self, wrapped_bar, wandb_project, run_name=None): self.wrapped_bar = wrapped_bar if wandb is None: - logger.warning('wandb not found, pip install wandb') + logger.warning("wandb not found, pip install wandb") return # reinit=False to ensure if wandb.init() is called multiple times # within one process it still references the same run - wandb.init(project=wandb_project, reinit=False) + wandb.init(project=wandb_project, reinit=False, name=run_name) def __iter__(self): return iter(self.wrapped_bar) @@ -397,11 +398,11 @@ def _log_to_wandb(self, stats, tag=None, step=None): if wandb is None: return if step is None: - step = stats['num_updates'] + step = stats["num_updates"] - prefix = '' if tag is None else tag + '/' + prefix = "" if tag is None else tag + "/" - for key in stats.keys() - {'num_updates'}: + for key in stats.keys() - {"num_updates"}: if isinstance(stats[key], AverageMeter): wandb.log({prefix + key: stats[key].val}, step=step) elif isinstance(stats[key], Number): diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 82c30321eb..11baf5a59b 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -211,7 +211,12 @@ def train( ), default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), wandb_project=( - cfg.common.wandb_project if distributed_utils.is_master(cfg.distributed_training) else None + cfg.common.wandb_project + if distributed_utils.is_master(cfg.distributed_training) + else None + ), + wandb_run_name=os.environ.get( + "WANDB_NAME", os.path.basename(cfg.checkpoint.save_dir) ), ) @@ -352,7 +357,12 @@ def validate( ), default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), wandb_project=( - cfg.common.wandb_project if distributed_utils.is_master(cfg.distributed_training) else None + cfg.common.wandb_project + if distributed_utils.is_master(cfg.distributed_training) + else None + ), + wandb_run_name=os.environ.get( + "WANDB_NAME", os.path.basename(cfg.checkpoint.save_dir) ), ) From 39e722ceabff11db00d9dd66998039236b40ae50 Mon Sep 17 00:00:00 2001 From: Davide Caroselli Date: Fri, 11 Dec 2020 18:54:40 -0800 Subject: [PATCH 112/774] Fix #3017: restore support for user modules in zip/jar files (#3018) Summary: ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3017 My original implementation of the function utils.import_user_module supported external user modules wrapped in zip/jar files (python natively support modules in zip/jar files). The new piece of code which checks for file existence breaks this functionality. This trivial fix can solve the problem! Pull Request resolved: https://github.com/pytorch/fairseq/pull/3018 Reviewed By: alexeib Differential Revision: D25485611 Pulled By: myleott fbshipit-source-id: 21667cd87e9e7a99095f8ad21d7b3bfdb547a993 --- fairseq/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/utils.py b/fairseq/utils.py index 4046f6696c..1b2e060650 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -437,7 +437,7 @@ def import_user_module(args): module_path = getattr(args, "user_dir", None) if module_path is not None: module_path = os.path.abspath(args.user_dir) - if not os.path.exists(module_path): + if not os.path.exists(module_path) and not os.path.isfile(os.path.dirname(module_path)): fairseq_rel_path = os.path.join(os.path.dirname(__file__), args.user_dir) if os.path.exists(fairseq_rel_path): module_path = fairseq_rel_path From 032a404d389307a0e8f7dd2a0d501c78afa78f39 Mon Sep 17 00:00:00 2001 From: Hiroyuki Deguchi Date: Fri, 11 Dec 2020 18:59:50 -0800 Subject: [PATCH 113/774] Add "soft" argument of "--print-alignment" (#2985) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: If the argument is set to "soft", print probability for each source token, like this: A-0 0.365083,0.328207,0.306710 0.442428,0.340282,0.217290 0.378712,0.367315,0.253973 0.321335,0.425601,0.253064 Each source token is separated from each other by a comma (,) and each target token is separated from each other by a space ( ). This option is based on the Marian NMT's option. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2985 Reviewed By: alexeib Differential Revision: D25344394 Pulled By: myleott fbshipit-source-id: 659eb8f7af1ccdafacaaa91ce5ddf5d71cb3e775 --- fairseq/dataclass/configs.py | 9 ++++++--- fairseq/dataclass/constants.py | 1 + fairseq/sequence_generator.py | 9 +++++++-- fairseq/tasks/fairseq_task.py | 4 +++- fairseq/utils.py | 17 +++++++++++++++++ fairseq_cli/generate.py | 15 ++++++++++++++- 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 3992e3c2d5..1a89560072 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -17,6 +17,7 @@ GENERATION_DECODING_FORMAT_CHOICES, LOG_FORMAT_CHOICES, PIPELINE_CHECKPOINT_CHOICES, + PRINT_ALIGNMENT_CHOICES, ZERO_SHARDING_CHOICES, ) @@ -737,10 +738,12 @@ class GenerationConfig(FairseqDataclass): default=-1.0, metadata={"help": "strength of diversity penalty for Diverse Siblings Search"}, ) - print_alignment: bool = field( - default=False, + print_alignment: Optional[PRINT_ALIGNMENT_CHOICES] = field( + default=None, metadata={ - "help": "if set, uses attention feedback to compute and print alignment to source tokens" + "help": "if set, uses attention feedback to compute and print alignment to source tokens " + "(valid options are: hard, soft, otherwise treated as hard alignment)", + "argparse_const": "hard", }, ) print_step: bool = field( diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 858f77a863..46881786a8 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -44,3 +44,4 @@ def ChoiceEnum(choices: List[str]): ) ZERO_SHARDING_CHOICES = ChoiceEnum(["none", "os"]) PIPELINE_CHECKPOINT_CHOICES = ChoiceEnum(["always", "never", "except_last"]) +PRINT_ALIGNMENT_CHOICES = ChoiceEnum(["hard", "soft"]) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index afc1500090..bd46f9e5b9 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -903,7 +903,7 @@ def reorder_incremental_state( class SequenceGeneratorWithAlignment(SequenceGenerator): - def __init__(self, models, tgt_dict, left_pad_target=False, **kwargs): + def __init__(self, models, tgt_dict, left_pad_target=False, print_alignment="hard", **kwargs): """Generates translations of a given source sentence. Produces alignments following "Jointly Learning to Align and @@ -917,6 +917,11 @@ def __init__(self, models, tgt_dict, left_pad_target=False, **kwargs): super().__init__(EnsembleModelWithAlignment(models), tgt_dict, **kwargs) self.left_pad_target = left_pad_target + if print_alignment == "hard": + self.extract_alignment = utils.extract_hard_alignment + elif print_alignment == "soft": + self.extract_alignment = utils.extract_soft_alignment + @torch.no_grad() def generate(self, models, sample, **kwargs): finalized = super()._generate(sample, **kwargs) @@ -945,7 +950,7 @@ def generate(self, models, sample, **kwargs): # Process the attn matrix to extract hard alignments. for i in range(bsz * beam_size): - alignment = utils.extract_hard_alignment( + alignment = self.extract_alignment( attn[i], src_tokens[i], tgt_tokens[i], self.pad, self.eos ) finalized[i // beam_size][i % beam_size]["alignment"] = alignment diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index c9b7477ae7..b99c511990 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -376,12 +376,14 @@ def build_generator( else: search_strategy = search.BeamSearch(self.target_dictionary) + extra_gen_cls_kwargs = extra_gen_cls_kwargs or {} if seq_gen_cls is None: if getattr(args, "print_alignment", False): seq_gen_cls = SequenceGeneratorWithAlignment + extra_gen_cls_kwargs['print_alignment'] = args.print_alignment else: seq_gen_cls = SequenceGenerator - extra_gen_cls_kwargs = extra_gen_cls_kwargs or {} + return seq_gen_cls( models, self.target_dictionary, diff --git a/fairseq/utils.py b/fairseq/utils.py index 1b2e060650..a20c83384c 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -631,6 +631,23 @@ def extract_hard_alignment(attn, src_sent, tgt_sent, pad, eos): return alignment +def extract_soft_alignment(attn, src_sent, tgt_sent, pad, eos): + tgt_valid = ( + ((tgt_sent != pad)).nonzero(as_tuple=False) + ) + src_valid = ( + ((src_sent != pad)).nonzero(as_tuple=False).squeeze(dim=-1) + ) + alignment = [] + if len(tgt_valid) != 0 and len(src_valid) != 0: + attn_valid = attn[tgt_valid, src_valid] + alignment = [ + ["{:.6f}".format(p) for p in src_probs.tolist()] + for src_probs in attn_valid + ] + return alignment + + def new_arange(x, *size): """ Return a Tensor of `size` filled with a range function on the device of x. diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 6be8150cda..4aeb4a56fa 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -299,7 +299,7 @@ def decode_fn(x): file=output_file, ) - if cfg.generation.print_alignment: + if cfg.generation.print_alignment == "hard": print( "A-{}\t{}".format( sample_id, @@ -312,6 +312,19 @@ def decode_fn(x): ), file=output_file, ) + if cfg.generation.print_alignment == "soft": + print( + "A-{}\t{}".format( + sample_id, + " ".join( + [ + ",".join(src_probs) + for src_probs in alignment + ] + ), + ), + file=output_file, + ) if cfg.generation.print_step: print( From f3d5045a71ae463bd3f05254d7c4216801a04bc2 Mon Sep 17 00:00:00 2001 From: Raphael Scheible Date: Fri, 11 Dec 2020 19:09:41 -0800 Subject: [PATCH 114/774] add German RoBERTa model (GottBERT) (#2992) Summary: # Before submitting - There is no related issue for this pull request. - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - We did not see any necessity for tests. ## What does this PR do? Add German RoBERTa model (GottBERT) Pull Request resolved: https://github.com/pytorch/fairseq/pull/2992 Reviewed By: alexeib Differential Revision: D25494927 Pulled By: myleott fbshipit-source-id: b6790124d7c3c8dc387c141706cd8a527cc950ab --- README.md | 1 + examples/gottbert/README.md | 64 ++++++++++++++++++++++++ examples/roberta/README.md | 1 + fairseq/data/encoders/hf_byte_bpe.py | 8 ++- fairseq/hub_utils.py | 2 + fairseq/models/roberta/__init__.py | 1 + fairseq/models/roberta/model_gottbert.py | 49 ++++++++++++++++++ 7 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 examples/gottbert/README.md create mode 100644 fairseq/models/roberta/model_gottbert.py diff --git a/README.md b/README.md index 3ae332b350..9cc5b7a559 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ We provide reference implementations of various sequence modeling papers: ### What's New: +* December 2020: [GottBERT model and code released](examples/gottbert/README.md) * November 2020: Adopted the [Hydra](https://github.com/facebookresearch/hydra) configuration framework * [see documentation explaining how to use it for new and existing projects](docs/hydra_integration.md) * November 2020: [fairseq 0.10.0 released](https://github.com/pytorch/fairseq/releases/tag/v0.10.0) diff --git a/examples/gottbert/README.md b/examples/gottbert/README.md new file mode 100644 index 0000000000..1d58feb279 --- /dev/null +++ b/examples/gottbert/README.md @@ -0,0 +1,64 @@ +# GottBERT: a pure German language model + +## Introduction + +[GottBERT](http://arxiv.org/abs/2012.02110) is a pretrained language model trained on 145GB of German text based on RoBERTa. + +## Example usage + +### fairseq +##### Load GottBERT from torch.hub (PyTorch >= 1.1): +```python +import torch +gottbert = torch.hub.load('pytorch/fairseq', 'gottbert-base') +gottbert.eval() # disable dropout (or leave in train mode to finetune) +``` + +##### Load GottBERT (for PyTorch 1.0 or custom models): +```python +# Download gottbert model +wget https://dl.gottbert.de/fairseq/models/gottbert-base.tar.gz +tar -xzvf gottbert.tar.gz + +# Load the model in fairseq +from fairseq.models.roberta import GottbertModel +gottbert = GottbertModel.from_pretrained('/path/to/gottbert') +gottbert.eval() # disable dropout (or leave in train mode to finetune) +``` + +##### Filling masks: +```python +masked_line = 'Gott ist ! :)' +gottbert.fill_mask(masked_line, topk=3) +# [('Gott ist gut ! :)', 0.3642110526561737, ' gut'), +# ('Gott ist überall ! :)', 0.06009674072265625, ' überall'), +# ('Gott ist großartig ! :)', 0.0370681993663311, ' großartig')] +``` + +##### Extract features from GottBERT + +```python +# Extract the last layer's features +line = "Der erste Schluck aus dem Becher der Naturwissenschaft macht atheistisch , aber auf dem Grunde des Bechers wartet Gott !" +tokens = gottbert.encode(line) +last_layer_features = gottbert.extract_features(tokens) +assert last_layer_features.size() == torch.Size([1, 27, 768]) + +# Extract all layer's features (layer 0 is the embedding layer) +all_layers = gottbert.extract_features(tokens, return_all_hiddens=True) +assert len(all_layers) == 13 +assert torch.all(all_layers[-1] == last_layer_features) +``` +## Citation +If you use our work, please cite: + +```bibtex +@misc{scheible2020gottbert, + title={GottBERT: a pure German Language Model}, + author={Raphael Scheible and Fabian Thomczyk and Patric Tippmann and Victor Jaravine and Martin Boeker}, + year={2020}, + eprint={2012.02110}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} +``` diff --git a/examples/roberta/README.md b/examples/roberta/README.md index ca86131eea..58091b2c7d 100644 --- a/examples/roberta/README.md +++ b/examples/roberta/README.md @@ -8,6 +8,7 @@ RoBERTa iterates on BERT's pretraining procedure, including training the model l ### What's New: +- December 2020: German model (GottBERT) is available: [GottBERT](https://github.com/pytorch/fairseq/tree/master/examples/gottbert). - January 2020: Italian model (UmBERTo) is available from Musixmatch Research: [UmBERTo](https://github.com/musixmatchresearch/umberto). - November 2019: French model (CamemBERT) is available: [CamemBERT](https://github.com/pytorch/fairseq/tree/master/examples/camembert). - November 2019: Multilingual encoder (XLM-RoBERTa) is available: [XLM-R](https://github.com/pytorch/fairseq/tree/master/examples/xlmr). diff --git a/fairseq/data/encoders/hf_byte_bpe.py b/fairseq/data/encoders/hf_byte_bpe.py index 92d2c3922c..c508578d41 100644 --- a/fairseq/data/encoders/hf_byte_bpe.py +++ b/fairseq/data/encoders/hf_byte_bpe.py @@ -7,6 +7,7 @@ from fairseq.data.encoders import register_bpe from fairseq.dataclass import FairseqDataclass +from fairseq import file_utils @dataclass @@ -28,9 +29,12 @@ def __init__(self, cfg): "Please install huggingface/tokenizers with: " "pip install tokenizers" ) + bpe_vocab = file_utils.cached_path(cfg.bpe_vocab) + bpe_merges = file_utils.cached_path(cfg.bpe_merges) + self.bpe = ByteLevelBPETokenizer( - cfg.bpe_vocab, - cfg.bpe_merges, + bpe_vocab, + bpe_merges, add_prefix_space=cfg.bpe_add_prefix_space, ) diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index 775d1f7aeb..7de2e2b0d4 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -60,6 +60,8 @@ def from_pretrained( "code": "bpe_codes", "bpecodes": "bpe_codes", "sentencepiece.bpe.model": "sentencepiece_model", + "merges.txt": "bpe_merges", + "vocab.json": "bpe_vocab", }.items(): path = os.path.join(model_path, file) if os.path.exists(path): diff --git a/fairseq/models/roberta/__init__.py b/fairseq/models/roberta/__init__.py index 56579e5915..cf16914fbc 100644 --- a/fairseq/models/roberta/__init__.py +++ b/fairseq/models/roberta/__init__.py @@ -6,4 +6,5 @@ from .hub_interface import * # noqa from .model import * # noqa from .model_camembert import * # noqa +from .model_gottbert import * # noqa from .model_xlmr import * # noqa diff --git a/fairseq/models/roberta/model_gottbert.py b/fairseq/models/roberta/model_gottbert.py new file mode 100644 index 0000000000..2e8c66354a --- /dev/null +++ b/fairseq/models/roberta/model_gottbert.py @@ -0,0 +1,49 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +""" +GottBERT: a pure German Language Model +""" + +from fairseq.models import register_model + +from .hub_interface import RobertaHubInterface +from .model import RobertaModel + + +@register_model('gottbert') +class GottbertModel(RobertaModel): + + @classmethod + def hub_models(cls): + return { + 'gottbert-base': 'https://dl.gottbert.de/fairseq/models/gottbert-base.tar.gz', + } + + @classmethod + def from_pretrained(cls, + model_name_or_path, + checkpoint_file='model.pt', + data_name_or_path='.', + bpe='hf_byte_bpe', + bpe_vocab='vocab.json', + bpe_merges='merges.txt', + bpe_add_prefix_space=False, + **kwargs + ): + from fairseq import hub_utils + + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + bpe=bpe, + load_checkpoint_heads=True, + bpe_vocab=bpe_vocab, + bpe_merges=bpe_merges, + bpe_add_prefix_space=bpe_add_prefix_space, + **kwargs, + ) + return RobertaHubInterface(x['args'], x['task'], x['models'][0]) From 881e9f8920bc3d9c3b526f6e52405f7059c926b4 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sat, 12 Dec 2020 07:18:45 -0800 Subject: [PATCH 115/774] Fix bug in FP16 training (#1503) Summary: Fix a critical bug in FP16 training (introduced on Dec 4: https://github.com/pytorch/fairseq/commit/ba4f54267af5c3f67f1b76a6e804b6ab593d1d39) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1503 Reviewed By: donhusa, daniellepintz Differential Revision: D25514055 Pulled By: myleott fbshipit-source-id: 38ebb1f41f365702ce7706846085c7c7cc24a98e --- fairseq/optim/fairseq_optimizer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fairseq/optim/fairseq_optimizer.py b/fairseq/optim/fairseq_optimizer.py index 41c859355c..a1c1d219a0 100644 --- a/fairseq/optim/fairseq_optimizer.py +++ b/fairseq/optim/fairseq_optimizer.py @@ -112,7 +112,6 @@ def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): def step(self, closure=None, scale=1.0, groups=None): """Performs a single optimization step.""" if self.supports_step_with_scale: - self.optimizer.step(closure, scale=scale) if self.supports_groups: self.optimizer.step(closure, scale=scale, groups=groups) else: From ac11107ed41cb06a758af850373c239309d1c961 Mon Sep 17 00:00:00 2001 From: Colin Clement Date: Sat, 12 Dec 2020 08:01:56 -0800 Subject: [PATCH 116/774] Azure ML Logging to view training/validation progress in AzureML workspace (#2999) Summary: # Before submitting - [no] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [yes] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [yes, the CLI flag has a help string] Did you make sure to update the docs? - [no, but the code was successfully tested in training] Did you write any new necessary tests? ## What does this PR do? Adds a CLI flag `--azureml-logging` to `fairseq-train` which allows fairseq to log to the default Azure ML context to improve training on Azure Machine Learning services. If `azureml-core` is not installed, it fails with a logging message like the `wandb` logging. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Always! Pull Request resolved: https://github.com/pytorch/fairseq/pull/2999 Reviewed By: alexeib Differential Revision: D25494986 Pulled By: myleott fbshipit-source-id: fadd7569aeb72b5b6f9db0508cbec3a138c332d3 --- fairseq/dataclass/configs.py | 6 ++++ fairseq/logging/progress_bar.py | 54 +++++++++++++++++++++++++++++++++ fairseq_cli/train.py | 3 ++ 3 files changed, 63 insertions(+) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 1a89560072..7d27dc0d4b 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -109,6 +109,12 @@ class CommonConfig(FairseqDataclass): "help": "Weights and Biases project name to use for logging" }, ) + azureml_logging: Optional[bool] = field( + default=False, + metadata={ + "help": "Log scalars to AzureML context" + }, + ) seed: int = field( default=1, metadata={"help": "pseudo random number generator seed"} ) diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index 07ee26f4fc..e2a1711121 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -35,6 +35,7 @@ def progress_bar( default_log_format: str = "tqdm", wandb_project: Optional[str] = None, wandb_run_name: Optional[str] = None, + azureml_logging: Optional[bool] = False, ): if log_format is None: log_format = default_log_format @@ -65,6 +66,9 @@ def progress_bar( if wandb_project: bar = WandBProgressBarWrapper(bar, wandb_project, run_name=wandb_run_name) + if azureml_logging: + bar = AzureMLProgressBarWrapper(bar) + return bar @@ -407,3 +411,53 @@ def _log_to_wandb(self, stats, tag=None, step=None): wandb.log({prefix + key: stats[key].val}, step=step) elif isinstance(stats[key], Number): wandb.log({prefix + key: stats[key]}, step=step) + + +try: + from azureml.core import Run +except ImportError: + Run = None + + +class AzureMLProgressBarWrapper(BaseProgressBar): + """Log to Azure ML""" + + def __init__(self, wrapped_bar): + self.wrapped_bar = wrapped_bar + if Run is None: + logger.warning("azureml.core not found, pip install azureml-core") + return + self.run = Run.get_context() + + def __exit__(self, *exc): + if Run is not None: + self.run.complete() + return False + + def __iter__(self): + return iter(self.wrapped_bar) + + def log(self, stats, tag=None, step=None): + """Log intermediate stats to AzureML""" + self._log_to_azureml(stats, tag, step) + self.wrapped_bar.log(stats, tag=tag, step=step) + + def print(self, stats, tag=None, step=None): + """Print end-of-epoch stats""" + self._log_to_azureml(stats, tag, step) + self.wrapped_bar.print(stats, tag=tag, step=step) + + def _log_to_azureml(self, stats, tag=None, step=None): + if Run is None: + return + if step is None: + step = stats['num_updates'] + + prefix = '' if tag is None else tag + '/' + + for key in stats.keys() - {'num_updates'}: + name = prefix + key + if isinstance(stats[key], AverageMeter): + self.run.log_row(name=name, **{'step': step, key: stats[key].val}) + elif isinstance(stats[key], Number): + self.run.log_row(name=name, **{'step': step, key: stats[key]}) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 11baf5a59b..81ecc80140 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -218,6 +218,9 @@ def train( wandb_run_name=os.environ.get( "WANDB_NAME", os.path.basename(cfg.checkpoint.save_dir) ), + azureml_logging=( + cfg.common.azureml_logging if distributed_utils.is_master(cfg.distributed_training) else False + ), ) trainer.begin_epoch(epoch_itr.epoch) From f49bb2c4d165d7c134e0dadc70c6fcda4ccd5e26 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 14 Dec 2020 10:45:36 -0800 Subject: [PATCH 117/774] Improve performance of distributed_utils.broadcast_object Summary: Recommit D25291594 (https://github.com/pytorch/fairseq/commit/bb039fa2063dca1b388d6be2f64052b07fb556a2) Original commit changeset: 64aead87ee84 Reviewed By: arendu Differential Revision: D25518027 fbshipit-source-id: 5da303f835eb4b598728c7c7ef7c07538ea3b9b4 --- fairseq/distributed_utils.py | 126 +++++++++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 21 deletions(-) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index dd93cda35c..8f98ac88f9 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -14,6 +14,7 @@ import warnings from argparse import Namespace from collections import OrderedDict +from dataclasses import dataclass from typing import Any, Dict, List, Mapping, Optional import torch @@ -642,44 +643,127 @@ def get_from_stack(key): return OrderedDict([(key, get_from_stack(key)) for key in data_keys]) -# From fairscale/optim/utils.py +def broadcast_tensors( + tensors: Optional[List[torch.Tensor]], + src_rank: int, + group: object, + dist_device: Optional[torch.device] = None, +) -> List[torch.Tensor]: + """ + Broadcasts a list of tensors without other (non-src) ranks needing to know + the dtypes/shapes of the tensors. + """ + if dist_device is None: + if torch.distributed.get_backend(group) == "nccl": + dist_device = torch.device("cuda") + else: + dist_device = torch.device("cpu") + + # share metadata first to simplify transfer + is_src_rank = (get_rank(group) == src_rank) + if is_src_rank: + metadata = [ + {"size": t.size(), "dtype": t.dtype, "device": t.device} for t in tensors + ] + metadata = _broadcast_object_slow(metadata, src_rank, group, dist_device) + else: + metadata = _broadcast_object_slow(None, src_rank, group, dist_device) + + out_tensors = [] + for i, meta in enumerate(metadata): + if is_src_rank: + tensor = tensors[i] + broadcast(tensors[i].to(dist_device), src=src_rank, group=group) + else: + tensor = torch.zeros( + [meta["size"].numel()], dtype=meta["dtype"], device=dist_device + ) + broadcast(tensor, src=src_rank, group=group) + tensor = tensor.view(meta["size"]).to(meta["device"]) + out_tensors.append(tensor) + return out_tensors + + def broadcast_object( obj: Any, src_rank: int, group: object, dist_device: Optional[torch.device] = None, - dist_length_dtype: Optional[torch.dtype] = torch.long, - dist_dtype: Optional[torch.dtype] = torch.uint8, ) -> Any: - """ - Either broadcast from master to the fleet (default), - or use the src setting as the original rank. - """ + """Broadcast an arbitrary Python object to other workers.""" if dist_device is None: if torch.distributed.get_backend(group) == "nccl": dist_device = torch.device("cuda") else: dist_device = torch.device("cpu") + if get_rank(group) == src_rank: + # split the tensors from the non-tensors so we can broadcast them + # directly, avoiding unnecessary serialization/deserialization + tensors = [] + obj = _split_tensors_from_obj(obj, tensors) + obj = _broadcast_object_slow(obj, src_rank, group, dist_device) + tensors = broadcast_tensors(tensors, src_rank, group, dist_device) + else: + obj = _broadcast_object_slow(None, src_rank, group, dist_device) + tensors = broadcast_tensors(None, src_rank, group, dist_device) + return _put_tensors_in_obj(obj, tensors) + + +def _broadcast_object_slow( + obj: Any, src_rank: int, group: object, dist_device: torch.device, +) -> Any: if get_rank(group) == src_rank: # Emit data buffer = io.BytesIO() torch.save(obj, buffer) - data = bytearray(buffer.getbuffer()) - length_tensor = torch.tensor( - [len(data)], dtype=dist_length_dtype, device=dist_device - ) - broadcast(length_tensor, src=src_rank, group=group) - data_send_tensor = torch.tensor(data, dtype=dist_dtype, device=dist_device) - broadcast(data_send_tensor, src=src_rank, group=group) + buffer = torch.ByteTensor(buffer.getbuffer()).to(dist_device) + length = torch.LongTensor([len(buffer)]).to(dist_device) + broadcast(length, src=src_rank, group=group) + broadcast(buffer, src=src_rank, group=group) else: # Fetch from the source - length_tensor = torch.tensor([0], dtype=dist_length_dtype, device=dist_device) - broadcast(length_tensor, src=src_rank, group=group) - data_recv_tensor = torch.zeros( - [int(length_tensor.item())], dtype=dist_dtype, device=dist_device - ) - broadcast(data_recv_tensor, src=src_rank, group=group) - buffer = io.BytesIO(data_recv_tensor.cpu().numpy()) + length = torch.LongTensor([0]).to(dist_device) + broadcast(length, src=src_rank, group=group) + buffer = torch.ByteTensor(int(length.item())).to(dist_device) + broadcast(buffer, src=src_rank, group=group) + buffer = io.BytesIO(buffer.cpu().numpy()) obj = torch.load(buffer, map_location="cpu") return obj + + +@dataclass(frozen=True) +class _TensorPlaceholder: + index: int + + +def _split_tensors_from_obj(obj: Any, tensors: List[torch.Tensor]) -> Any: + if torch.is_tensor(obj): + placeholder = _TensorPlaceholder(index=len(tensors)) + tensors.append(obj) + return placeholder + elif isinstance(obj, dict): + return {k: _split_tensors_from_obj(v, tensors) for k, v in obj.items()} + elif isinstance(obj, list): + return [_split_tensors_from_obj(v, tensors) for v in obj] + elif isinstance(obj, tuple): + return tuple(_split_tensors_from_obj(v, tensors) for v in obj) + elif isinstance(obj, set): + return {_split_tensors_from_obj(v, tensors) for v in obj} + else: + return obj + + +def _put_tensors_in_obj(obj: Any, tensors: List[torch.Tensor]) -> Any: + if isinstance(obj, _TensorPlaceholder): + return tensors[obj.index] + elif isinstance(obj, dict): + return {k: _put_tensors_in_obj(v, tensors) for k, v in obj.items()} + elif isinstance(obj, list): + return [_put_tensors_in_obj(v, tensors) for v in obj] + elif isinstance(obj, tuple): + return tuple(_put_tensors_in_obj(v, tensors) for v in obj) + elif isinstance(obj, set): + return {_put_tensors_in_obj(v, tensors) for v in obj} + else: + return obj From d740093bac8a6115b68ab5de9a6b63099a07497b Mon Sep 17 00:00:00 2001 From: Dexter Ju Date: Mon, 14 Dec 2020 11:34:21 -0800 Subject: [PATCH 118/774] Porting adaptive span to fairseq (#1428) Summary: ## What does this PR do? 1. We add an enwiki8 character level LM task sweep for transformer XL, which lands at 1.05 matches the performance (1.06): https://github.com/kimiyoung/transformer-xl/tree/master/pytorch Eval with ``` PYTHONPATH=. python fairseq_cli/eval_lm.py /private/home/daju/data/enwik8/eos-data-bin/ --path /checkpoint/daju/2020-11-19/enwiki8.transformer_xl.fp16.transformer_xl.adam.cl0.25.cosine.lr0.00025.s2.ngpu4/checkpoint_best.pt --user-dir examples/truncated_bptt/ --task truncated_bptt_lm --batch-size 8 --tokens-per-sample 80 --model-overrides '{"mem_len":2100,"clamp_len":820,"same_length":True}' ``` 2. Impalements adaptive span in fairseq code. It reproduces the enwiki8 result at 1.03 comparing to 1.02 (for the 12 L model) reported in https://github.com/facebookresearch/adaptive-span, which is a consistent improvement over the transformer XL baseline listed above with a smaller model. You can evaluate the example run with: ``` PYTHONPATH=. python fairseq_cli/eval_lm.py /private/home/daju/data/enwik8/eos-data-bin/ --path /checkpoint/daju/2020-11-20/enwiki8.adaptivespan.headwise.adaptive_span.adagrad_with_grad_clip.ag_cl0.03.fixed.wu32000.lr0.07.s2.loss5e-07.ngpu4/checkpoint_best.pt --user-dir examples/truncated_bptt/ --task truncated_bptt_lm --batch-size 8 --tokens-per-sample 512 --gen-subset test ``` Paper: https://arxiv.org/abs/1905.07799 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1428 Reviewed By: myleott Differential Revision: D25495754 Pulled By: dexterju fbshipit-source-id: 15a875a5f82d506a4964dea934a374132ce39f8b --- README.md | 3 +- examples/adaptive_span/README.md | 90 ++++++ examples/adaptive_span/__init__.py | 19 ++ .../adaptive_span/adagrad_with_grad_clip.py | 128 +++++++++ .../adaptive_span/adaptive_span_attention.py | 160 +++++++++++ examples/adaptive_span/adaptive_span_loss.py | 106 +++++++ examples/adaptive_span/adaptive_span_model.py | 263 ++++++++++++++++++ .../adaptive_span_model_wrapper.py | 145 ++++++++++ .../adaptive_span/truncated_bptt_lm_task.py | 1 + fairseq/optim/adagrad.py | 2 +- 10 files changed, 915 insertions(+), 2 deletions(-) create mode 100644 examples/adaptive_span/README.md create mode 100644 examples/adaptive_span/__init__.py create mode 100644 examples/adaptive_span/adagrad_with_grad_clip.py create mode 100644 examples/adaptive_span/adaptive_span_attention.py create mode 100644 examples/adaptive_span/adaptive_span_loss.py create mode 100644 examples/adaptive_span/adaptive_span_model.py create mode 100644 examples/adaptive_span/adaptive_span_model_wrapper.py create mode 120000 examples/adaptive_span/truncated_bptt_lm_task.py diff --git a/README.md b/README.md index 9cc5b7a559..cc1c76ec36 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ We provide reference implementations of various sequence modeling papers: + [Understanding Back-Translation at Scale (Edunov et al., 2018)](examples/backtranslation/README.md) + [Adaptive Input Representations for Neural Language Modeling (Baevski and Auli, 2018)](examples/language_model/README.adaptive_inputs.md) + [Lexically constrained decoding with dynamic beam allocation (Post & Vilar, 2018)](examples/constrained_decoding/README.md) - + [Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context](examples/truncated_bptt/README.md) + + [Transformer-XL: Attentive Language Models Beyond a Fixed-Length Context (Dai et al., 2019)](examples/truncated_bptt/README.md) + + [Adaptive Attention Span in Transformers (Sukhbaatar et al., 2019)](examples/adaptive_span/README.md) + [Mixture Models for Diverse Machine Translation: Tricks of the Trade (Shen et al., 2019)](examples/translation_moe/README.md) + [RoBERTa: A Robustly Optimized BERT Pretraining Approach (Liu et al., 2019)](examples/roberta/README.md) + [Facebook FAIR's WMT19 News Translation Task Submission (Ng et al., 2019)](examples/wmt19/README.md) diff --git a/examples/adaptive_span/README.md b/examples/adaptive_span/README.md new file mode 100644 index 0000000000..913a873386 --- /dev/null +++ b/examples/adaptive_span/README.md @@ -0,0 +1,90 @@ +# Adaptive Span + +Adaptive Span is a novel self-attention mechanism that can learn its optimal +attention span. This allows us to extend significantly the maximum context size +used in Transformer, while maintaining control over their memory footprint +and computational time. It uses the Truncated BPTT technique for training, +as in [transformerXL](https://github.com/pytorch/fairseq/blob/master/examples/truncated_bptt/README.md). + +Adaptive Span was introduced by paper: +[Adaptive Attention Span in Transformers](https://arxiv.org/abs/1905.07799), +which achieved state-of-the-art language modeling results at the time of publication. + +We manage to reproduce their result in fairseq and keep most of the +[original implementation](https://github.com/facebookresearch/adaptive-span) untouched. +You can refer to the their sweep file as well if any combination of hyperparameter is not clear. + +##### 0. Setup + +First you need to process the Enwik8 dataset, we use the pre-tokenized dataset +from [adaptive span paper](https://github.com/facebookresearch/adaptive-span/blob/master/get_data.sh). +You can download the dataset, and then run: +```bash +fairseq-preprocess --only-source --trainpref ~/data/enwik8/train.txt \ + --validpref ~/data/enwik8/valid.txt --testpref ~/data/enwik8/test.txt \ + --destdir ~/data/enwik8/data-bin/ --joined-dictionary --workers 20 +``` + +##### 1. Train a Adaptive Span model on Enwik8 + +We will train a 12-layer Adaptive Span model following the [hyperparameters +used in the original +paper](https://github.com/facebookresearch/adaptive-span/blob/master/experiments/enwik8.sh). + +The following command assumes 4 GPUs, so that the total batch size is 64 +sequences (4 x 16). Training should take 2-3 days on 4 V100 GPUs: +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 fairseq-train \ + --user-dir examples/adaptive_span \ + --data ~/data/enwik8/data-bin/ \ + --fp16 --fp16-no-flatten-grads --max-update 600000 \ + --task truncated_bptt_lm --tokens-per-sample 512 --arch adaptive_span \ + --n-layer 12 --d-model 512 --n-head 8 --d-inner 2048 --dropout 0.3 \ + --attn-span 8192 --optimizer adagrad_with_grad_clip --adagrad-clip 0.03 \ + --validate-interval-updates 1000 \ + --lr-scheduler fixed --warmup-updates 32000 --batch-size-valid 32 \ + --lr 0.07 --criterion adaptive_span_loss --batch-size 16 --update-freq 1 \ + --seed 2 --log-format json --log-interval 25 --aux-loss-scaler 5e-07 +``` +This should land around 1.05 on validation, 1.03 on test. You can lower the +--aux-loss-scaler for better performance (longer span). It gives ~0.03 bpc +improvement to the transformerXL baseline here. +If training on a single GPU, set `--update-freq=4` to accumulate 4x gradients +and simulate training on 4 GPUs. +You can also reproduce the transformerXL result on enwik8 using this code base. +It should land around 1.06 on test,matching the [original paper](https://github.com/kimiyoung/transformer-xl/blob/master/pytorch/run_enwik8_base.sh). +You can try by +```bash +CUDA_VISIBLE_DEVICES=0,1,2,3 fairseq-train \ + --user-dir examples/truncated_bptt \ + ~/data/enwik8/data-bin/ \ + --task truncated_bptt_lm --fp16 --max-update 400000 \ + --tokens-per-sample 512 --arch transformer_xl --n-layer 12 \ + --d-model 512 --n-head 8 --d-head 64 --d-inner 2048 --dropout 0.1 \ + --dropatt 0.0 --mem-len 512 --optimizer adam --clip-norm 0.25 \ + --lr-scheduler cosine --warmup-updates 0 \ + --lr 0.0 --lr 0.00025 --batch-size 15 \ + --update-freq 1 --seed 2 --log-format json --log-interval 25 \ + --fp16 +``` + +##### 2. Evaluate +For Adaptive Span: +```bash +fairseq-eval-lm ~/data/enwik8/data-bin/ --path model/checkpoint_best.pt \ + --user-dir examples/adaptive_span \ + --task truncated_bptt_lm --batch-size 8 --tokens-per-sample 512 --gen-subset test +``` +For Transformer-XL evaluation: +```bash +fairseq-eval-lm ~/data/enwik8/data-bin/ --path model/checkpoint_best.pt \ + --user-dir examples/truncated_bptt/ --task truncated_bptt_lm --batch-size 8 \ + --tokens-per-sample 80 \ + --model-overrides '{"mem_len":2100,"clamp_len":820,"same_length":True}' \ + --gen-subset valid +``` + +*Note:* During training the model saw 512 tokens of context +(``--tokens-per-sample=512``), with batch size 8. These settings match the evaluation +settings from [the original +paper](https://github.com/facebookresearch/adaptive-span/blob/master/experiments/enwik8.sh). diff --git a/examples/adaptive_span/__init__.py b/examples/adaptive_span/__init__.py new file mode 100644 index 0000000000..e0a142a769 --- /dev/null +++ b/examples/adaptive_span/__init__.py @@ -0,0 +1,19 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import importlib +import os + +# automatically import any Python files in the current directory +cur_dir = os.path.dirname(__file__) +for file in os.listdir(cur_dir): + path = os.path.join(cur_dir, file) + if ( + not file.startswith("_") + and not file.startswith(".") + and (file.endswith(".py") or os.path.isdir(path)) + ): + mod_name = file[: file.find(".py")] if file.endswith(".py") else file + module = importlib.import_module(__name__ + "." + mod_name) diff --git a/examples/adaptive_span/adagrad_with_grad_clip.py b/examples/adaptive_span/adagrad_with_grad_clip.py new file mode 100644 index 0000000000..585ce184ab --- /dev/null +++ b/examples/adaptive_span/adagrad_with_grad_clip.py @@ -0,0 +1,128 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from torch.optim import Adagrad + +from fairseq.optim import LegacyFairseqOptimizer, register_optimizer + + +@register_optimizer("adagrad_with_grad_clip") +class FairseqAdagradWithGradClip(LegacyFairseqOptimizer): + def __init__(self, args, params): + super().__init__(args) + self._optimizer = AdagradWithGradClip(params, **self.optimizer_config) + + @staticmethod + def add_args(parser): + """Add optimizer-specific arguments to the parser.""" + # fmt: off + parser.add_argument('--weight-decay', '--wd', default=0.0, type=float, metavar='WD', + help='weight decay') + parser.add_argument('--adagrad-clip', default=0.0, type=float, metavar='D', + help='internal grad clip') + # fmt: on + + @property + def optimizer_config(self): + """ + Return a kwarg dictionary that will be used to override optimizer + args stored in checkpoints. This allows us to load a checkpoint and + resume training using a different set of optimizer args, e.g., with a + different learning rate. + """ + return { + "lr": self.args.lr[0], + "weight_decay": self.args.weight_decay, + "grad_clip": self.args.adagrad_clip, + } + + @property + def supports_flat_params(self): + return False + + +def _clip_grad(clr, grad, group_grad_clip): + if group_grad_clip > 0: + norm = grad.norm(2).item() + if norm > group_grad_clip: + clr *= group_grad_clip / (norm + 1e-10) + return clr + + +class AdagradWithGradClip(Adagrad): + """Adagrad algorithm with custom gradient clipping""" + + def __init__( + self, + params, + lr=1e-2, + lr_decay=0, + weight_decay=0, + initial_accumulator_value=0, + grad_clip=0, + ): + Adagrad.__init__( + self, + params, + lr=lr, + lr_decay=lr_decay, + weight_decay=weight_decay, + initial_accumulator_value=initial_accumulator_value, + ) + self.defaults["grad_clip"] = grad_clip + self.param_groups[0].setdefault("grad_clip", grad_clip) + + def step(self, closure=None): + loss = None + if closure is not None: + loss = closure() + + for group in self.param_groups: + for p in group["params"]: + if p.grad is None: + continue + + grad = p.grad.data + state = self.state[p] + + state["step"] += 1 + + if group["weight_decay"] != 0: + if p.grad.data.is_sparse: + raise RuntimeError( + "weight_decay option is " + "not compatible with sparse " + "gradients" + ) + grad = grad.add(group["weight_decay"], p.data) + + clr = group["lr"] / (1 + (state["step"] - 1) * group["lr_decay"]) + + # clip + clr = _clip_grad(clr=clr, grad=grad, group_grad_clip=group["grad_clip"]) + + if grad.is_sparse: + # the update is non-linear so indices must be unique + grad = grad.coalesce() + grad_indices = grad._indices() + grad_values = grad._values() + size = grad.size() + + def make_sparse(values): + constructor = grad.new + if grad_indices.dim() == 0 or values.dim() == 0: + return constructor().resize_as_(grad) + return constructor(grad_indices, values, size) + + state["sum"].add_(make_sparse(grad_values.pow(2))) + std = state["sum"]._sparse_mask(grad) + std_values = std._values().sqrt_().add_(1e-10) + p.data.add_(-clr, make_sparse(grad_values / std_values)) + else: + state["sum"].addcmul_(1, grad, grad) + std = state["sum"].sqrt().add_(1e-10) + p.data.addcdiv_(-clr, grad, std) + + return loss diff --git a/examples/adaptive_span/adaptive_span_attention.py b/examples/adaptive_span/adaptive_span_attention.py new file mode 100644 index 0000000000..07f757bb8e --- /dev/null +++ b/examples/adaptive_span/adaptive_span_attention.py @@ -0,0 +1,160 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class AdaptiveMask(nn.Module): + """Soft masking function for adaptive size. + It masks out the last K values of an input. The masking value + goes from 1 to 0 gradually, so K can be learned with + back-propagation. + Args: + max_size: maximum size (i.e. input dimension) + ramp_size: size of the ramp going from 0 to 1 + init_val: initial size proportion not to be masked out + shape: learn multiple sizes independent of each other + """ + + def __init__(self, max_size, ramp_size, init_val=0, shape=(1,)): + nn.Module.__init__(self) + self._max_size = max_size + self._ramp_size = ramp_size + self.current_val = nn.Parameter(torch.zeros(*shape) + init_val) + mask_template = torch.linspace(1 - max_size, 0, steps=max_size) + self.register_buffer("mask_template", mask_template) + + def forward(self, x): + mask = self.mask_template.float() + self.current_val.float() * self._max_size + mask = mask / self._ramp_size + 1 + mask = mask.clamp(0, 1) + if x.size(-1) < self._max_size: + # the input could have been trimmed beforehand to save computation + mask = mask.narrow(-1, self._max_size - x.size(-1), x.size(-1)) + x = (x * mask).type_as(x) + return x + + def get_current_max_size(self, include_ramp=True): + current_size = math.ceil(self.current_val.max().item() * self._max_size) + if include_ramp: + current_size += self._ramp_size + current_size = max(0, min(self._max_size, current_size)) + return current_size + + def get_current_avg_size(self, include_ramp=True): + current_size = math.ceil( + self.current_val.float().mean().item() * self._max_size + ) + if include_ramp: + current_size += self._ramp_size + current_size = max(0, min(self._max_size, current_size)) + return current_size + + def clamp_param(self): + """this need to be called after each update""" + self.current_val.data.clamp_(0, 1) + + +class AdaptiveSpan(nn.Module): + """Adaptive attention span for Transformerself. + This module learns an attention span length from data for each + self-attention head. + Args: + attn_span: maximum attention span + adapt_span_loss: loss coefficient for the span length + adapt_span_ramp: length of the masking ramp + adapt_span_init: initial size ratio + adapt_span_cache: adapt cache size to reduce memory usage + """ + + def __init__( + self, + attn_span, + adapt_span_ramp, + adapt_span_init, + n_head, + adapt_span_layer, + **kargs + ): + nn.Module.__init__(self) + self._max_span = attn_span + self._n_head = n_head + self._adapt_span_layer = adapt_span_layer + if self._adapt_span_layer: + self._mask = AdaptiveMask( + max_size=self._max_span, + ramp_size=adapt_span_ramp, + init_val=adapt_span_init, + ) + else: + self._mask = AdaptiveMask( + max_size=self._max_span, + ramp_size=adapt_span_ramp, + init_val=adapt_span_init, + shape=(n_head, 1, 1), + ) + + def forward(self, attn, normalize=True): + """mask attention with the right span""" + # batch and head dimensions are merged together, so separate them first + self.clamp_param() + if self._adapt_span_layer: + attn = self._mask(attn) + else: + B = attn.size(0) # batch size + M = attn.size(1) # block size + attn = attn.reshape(B // self._n_head, self._n_head, M, -1) + attn = self._mask(attn) + attn = attn.view(B, M, -1) + return attn + + def get_trim_len(self): + """how much of memory can be trimmed to reduce computation""" + L = self._max_span + trim_len = min(L - 1, L - self._mask.get_current_max_size()) + # too fine granularity might be bad for the memory management + trim_len = math.floor(trim_len / 64) * 64 + return trim_len + + def trim_memory(self, query, key, value, key_pe): + """trim out unnecessary memory beforehand to reduce computation""" + trim_len = self.get_trim_len() + cache_size = key.size(1) - query.size(1) + trim_len_cache = trim_len - (self._max_span - cache_size) + if trim_len_cache > 0: + key = key[:, trim_len_cache:, :] + value = value[:, trim_len_cache:, :] + elif trim_len_cache < 0: + # cache is too short! this happens when validation resumes + # after a lot of updates. + key = F.pad(key, [0, 0, -trim_len_cache, 0]) + value = F.pad(value, [0, 0, -trim_len_cache, 0]) + if trim_len > 0: + if key_pe is not None: + key_pe = key_pe[:, :, trim_len:] + return key, value, key_pe + + def get_cache_size(self): + """determine how long the cache should be""" + trim_len = self.get_trim_len() + # give a buffer of 64 steps since a span might increase + # in future updates + return min(self._max_span, self._max_span - trim_len + 64) + + def get_loss(self): + """a loss term for regularizing the span length""" + return self._max_span * self._mask.current_val.float().mean() + + def get_current_max_span(self): + return self._mask.get_current_max_size() + + def get_current_avg_span(self): + return self._mask.get_current_avg_size() + + def clamp_param(self): + self._mask.clamp_param() diff --git a/examples/adaptive_span/adaptive_span_loss.py b/examples/adaptive_span/adaptive_span_loss.py new file mode 100644 index 0000000000..056245807e --- /dev/null +++ b/examples/adaptive_span/adaptive_span_loss.py @@ -0,0 +1,106 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from dataclasses import dataclass + +import torch.nn.functional as F +from fairseq import metrics, utils +from fairseq.criterions import register_criterion +from fairseq.criterions.cross_entropy import CrossEntropyCriterion +from fairseq.dataclass import FairseqDataclass +from omegaconf import II + + +@dataclass +class AdaptiveSpanCriterionConfig(FairseqDataclass): + sentence_avg: bool = II("optimization.sentence_avg") + + +@register_criterion("adaptive_span_loss", dataclass=AdaptiveSpanCriterionConfig) +class AdaptiveSpanCriterion(CrossEntropyCriterion): + def __init__(self, task, sentence_avg): + super().__init__(task, sentence_avg) + + def forward(self, model, sample, reduce=True): + """Compute the loss for the given sample. + + Returns a tuple with three elements: + 1) the loss here is summed, different from the adaptive span code + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + net_output = model(**sample["net_input"]) + loss, aux_loss, avg_span, max_span = self.compute_loss( + model, net_output, sample, reduce=reduce + ) + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + loss /= sample_size + total_loss = loss + aux_loss + sample_size = 1 + + logging_output = { + "loss": loss.data, + "ntokens": sample["ntokens"], + "nsentences": sample["target"].size(0), + "sample_size": sample_size, + "total_loss": total_loss.data, + "avg_span": avg_span * sample_size, + "max_span": max_span * sample_size, + } + return total_loss, sample_size, logging_output + + def compute_loss(self, model, net_output, sample, reduce=True): + loss, _ = super().compute_loss(model, net_output, sample, reduce) + aux_loss = model.get_aux_loss() + avg_span = model.get_current_avg_span() + max_span = model.get_current_max_span() + return loss, aux_loss, avg_span, max_span + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + loss_sum = sum(log.get("loss", 0) for log in logging_outputs) + ntokens = sum(log.get("ntokens", 0) for log in logging_outputs) + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + total_loss_sum = sum(log.get("total_loss", 0) for log in logging_outputs) + avg_span_sum = sum(log.get("avg_span", 0) for log in logging_outputs) + max_span_sum = sum(log.get("max_span", 0) for log in logging_outputs) + + # we divide by log(2) to convert the loss from base e to base 2 + metrics.log_scalar( + "loss", loss_sum / sample_size / math.log(2), sample_size, round=3 + ) + metrics.log_scalar("avg_span", avg_span_sum / sample_size, sample_size, round=3) + metrics.log_scalar("max_span", max_span_sum / sample_size, sample_size, round=3) + # total loss contains the L1 norm on adaptive-span + metrics.log_scalar( + "total_loss", + total_loss_sum / sample_size / math.log(2), + sample_size, + round=3, + ) + if sample_size != ntokens: + metrics.log_scalar( + "nll_loss", loss_sum / ntokens / math.log(2), ntokens, round=3 + ) + metrics.log_derived( + "ppl", lambda meters: utils.get_perplexity(meters["nll_loss"].avg) + ) + else: + metrics.log_derived( + "ppl", lambda meters: utils.get_perplexity(meters["loss"].avg) + ) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return True diff --git a/examples/adaptive_span/adaptive_span_model.py b/examples/adaptive_span/adaptive_span_model.py new file mode 100644 index 0000000000..d96c95b85d --- /dev/null +++ b/examples/adaptive_span/adaptive_span_model.py @@ -0,0 +1,263 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from fairseq.modules.layer_norm import LayerNorm + +from .adaptive_span_attention import AdaptiveSpan + +# Size notations: +# B = batch_size, H = d_model, M = block_size, L = attn_span + + +def _skew(X, pad_value): + """shift every row 1 step to right""" + # X = B x M x L + B, M, L = X.size() + X = F.pad(X, (0, M + 1), value=pad_value) # B x M x (L+M+1) + X = X.view(B, -1) # B x ML+MM+M + X = X[:, :-M] # B x ML+MM + X = X.view(B, M, M + L) # B x M x L+M + return X + + +def _unskew(X): + """reverse _skew operation""" + # X = B x M x L+M + B, M, L = X.size() + L -= M + X = X.view(B, -1) # B x ML+MM + X = F.pad(X, (0, M)) # B x ML+MM+M + X = X.view(B, M, M + L + 1) # B x M x L+M+1 + X = X[:, :, :L] # B x M x L + return X + + +class SeqAttention(nn.Module): + """Sequential self-attention layer. + Each token will attend to its previous fixed number of steps. + Note that attention doesn't include the current step itself. + """ + + def __init__(self, d_model, n_head, attn_span, dropout, adapt_span_layer, **kargs): + nn.Module.__init__(self) + self.dropout = nn.Dropout(dropout) + self.d_model = d_model # size of a single head + self.attn_span = attn_span + self.adaptive_span = AdaptiveSpan( + attn_span=attn_span, + n_head=n_head, + adapt_span_layer=adapt_span_layer, + **kargs + ) + + def forward(self, query, key, value, key_pe): + # query size = B x M x H + # key, value sizes = B x (M+L) x H + + key, value, key_pe = self.adaptive_span.trim_memory(query, key, value, key_pe) + + # compute attention from context + # B x M (dest) x (M+L) (src) + attn_cont = torch.matmul(query, key.transpose(-1, -2)) + attn_cont = _unskew(attn_cont) # B x M x L + + # compute the effect of position embedding + attn_pos = torch.matmul(query, key_pe) # B x M x L_pos + attn = attn_cont + attn_pos + + attn = attn / math.sqrt(self.d_model) # B x M X L_pos + + attn = F.softmax(attn.float(), dim=-1).type_as(attn) + + # trim attention lengths according to the learned span + attn = self.adaptive_span(attn) + + attn = self.dropout(attn) # B x M X L_pos + + attn_cont = _skew(attn, 0) # B x M X (L+M) + out = torch.matmul(attn_cont, value) # B x M x H + return out + + def get_cache_size(self): + return self.adaptive_span.get_cache_size() + + +class MultiHeadSeqAttention(nn.Module): + def __init__(self, d_model, n_head, **kargs): + nn.Module.__init__(self) + assert d_model % n_head == 0 + self.n_head = n_head + self.head_dim = d_model // n_head + self.attn = SeqAttention(d_model=self.head_dim, n_head=n_head, **kargs) + self.proj_query = nn.Linear(d_model, d_model, bias=False) + nn.init.xavier_normal_(self.proj_query.weight) + self.proj_out = nn.Linear(d_model, d_model, bias=False) + nn.init.xavier_normal_(self.proj_out.weight) + self.proj_val = nn.Linear(d_model, d_model, bias=False) + nn.init.xavier_normal_(self.proj_val.weight) + self.proj_key = nn.Linear(d_model, d_model, bias=False) + nn.init.xavier_normal_(self.proj_key.weight) + + def head_reshape(self, x): + K = self.n_head + D = self.head_dim + x = x.view(x.size()[:-1] + (K, D)) # B x (M+L) x K x D + x = x.transpose(1, 2).contiguous() # B x K x (M+L) x D + x = x.view(-1, x.size(-2), x.size(-1)) # B_K x (M+L) x D + return x + + def forward(self, query, key, value, key_pe): + B = query.size(0) + K = self.n_head + D = self.head_dim + M = query.size(1) + + query = self.proj_query(query) + query = self.head_reshape(query) + value = self.proj_val(value) + value = self.head_reshape(value) + key = self.proj_key(key) + key = self.head_reshape(key) + + out = self.attn(query, key, value, key_pe) # B_K x M x D + out = out.view(B, K, M, D) # B x K x M x D + out = out.transpose(1, 2).contiguous() # B x M x K x D + out = out.view(B, M, -1) # B x M x K_D + out = self.proj_out(out) + return out + + +class FeedForwardLayer(nn.Module): + def __init__(self, d_model, d_inner, dropout, **kargs): + nn.Module.__init__(self) + self.fc1 = nn.Linear(d_model, d_inner) + self.fc2 = nn.Linear(d_inner, d_model) + nn.init.xavier_uniform_(self.fc1.weight) + nn.init.xavier_uniform_(self.fc2.weight) + self.dropout = nn.Dropout(dropout) + + def forward(self, h): + h1 = F.relu(self.fc1(h)) + h1 = self.dropout(h1) + h2 = self.fc2(h1) + return h2 + + +class TransformerSeqLayer(nn.Module): + def __init__(self, d_model, **kargs): + nn.Module.__init__(self) + self.attn = MultiHeadSeqAttention(d_model=d_model, **kargs) + self.norm1 = LayerNorm(d_model) + self.ff = FeedForwardLayer(d_model=d_model, **kargs) + self.norm2 = LayerNorm(d_model) + + def forward(self, h, h_cache, key_pe): + # h = B x M x H + # h_cache = B x L x H + h_all = torch.cat([h_cache, h], dim=1) # B x (M+L) x H + attn_out = self.attn(h, h_all, h_all, key_pe) + h = self.norm1(h + attn_out) # B x M x H + if self.ff is not None: + ff_out = self.ff(h) + out = self.norm2(h + ff_out) # B x M x H + else: + out = h + return out + + def get_cache_size(self): + return self.attn.attn.get_cache_size() + + +class TransformerSeq(nn.Module): + def __init__( + self, + vocab_size, + d_model, + n_head, + n_layer, + attn_span, + emb_dropout, + aux_loss_scaler, + adapt_span_layer, + **kargs + ): + nn.Module.__init__(self) + # token embeddings + self.in_emb = nn.Embedding(vocab_size, d_model) + nn.init.normal_(self.in_emb.weight, mean=0, std=d_model ** -0.5) + self.out_emb = nn.Linear(d_model, vocab_size) + self.aux_loss_scaler = aux_loss_scaler + if emb_dropout > 0: + self.emb_dropout = nn.Dropout(emb_dropout) + else: + self.emb_dropout = None + # position embeddings + self.key_pe = nn.Parameter(torch.randn(1, d_model // n_head, attn_span)) + + self.layers = nn.ModuleList() + self.layers.extend( + TransformerSeqLayer( + d_model=d_model, + n_head=n_head, + attn_span=attn_span, + adapt_span_layer=adapt_span_layer, + **kargs + ) + for _ in range(n_layer) + ) + + def forward(self, x, h_cache, target=None): + # x size = B x M + block_size = x.size(1) + h = self.in_emb(x) # B x M x H + if self.emb_dropout is not None: + h = self.emb_dropout(h) + + h_cache_next = [] + for l, layer in enumerate(self.layers): + cache_size = layer.attn.attn.get_cache_size() + if cache_size > block_size: + h_cache_next_l = torch.cat( + [h_cache[l][:, -cache_size + block_size :, :], h], dim=1 + ).detach() + else: + h_cache_next_l = h[:, -cache_size:, :].detach() + h_cache_next.append(h_cache_next_l) + h = layer(h, h_cache[l], self.key_pe) # B x M x H + + if self.emb_dropout is not None: + h = self.emb_dropout(h) + + out = F.log_softmax(self.out_emb(h).float(), dim=-1).type_as(h) + dummy_loss = None + + return out, h_cache_next, dummy_loss + + def get_aux_loss(self): + loss = 0.0 + for layer in self.layers: + loss += layer.attn.attn.adaptive_span.get_loss() + return self.aux_loss_scaler * loss + + def get_current_max_span(self): + max_span = 0.0 + for layer in self.layers: + max_span = max( + max_span, layer.attn.attn.adaptive_span.get_current_max_span() + ) + return max_span + + def get_current_avg_span(self): + avg_span = 0.0 + for layer in self.layers: + avg_span += layer.attn.attn.adaptive_span.get_current_avg_span() + return avg_span / len(self.layers) diff --git a/examples/adaptive_span/adaptive_span_model_wrapper.py b/examples/adaptive_span/adaptive_span_model_wrapper.py new file mode 100644 index 0000000000..5b147fe11f --- /dev/null +++ b/examples/adaptive_span/adaptive_span_model_wrapper.py @@ -0,0 +1,145 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from dataclasses import dataclass +from typing import Dict, List, Optional + +import torch +from fairseq.dataclass import FairseqDataclass +from fairseq.models import ( + FairseqIncrementalDecoder, + FairseqLanguageModel, + register_model, +) +from .adaptive_span_model import TransformerSeq as AdaptiveSpanTransformerModel + + +logger = logging.getLogger(__name__) + + +@dataclass +class AdaptiveSpanSmallConfig(FairseqDataclass): + # defaults come from https://github.com/facebookresearch/adaptive-span/blob/master/experiments/enwik8_small.sh + vocab_size: int = 50 + d_model: int = 256 + n_head: int = 4 + d_inner: int = 1024 + n_layer: int = 8 + attn_span: int = 1024 + dropout: float = 0.0 + emb_dropout: float = 0.0 + adapt_span_ramp: int = 32 + adapt_span_init: float = 0.0 + aux_loss_scaler: float = 0.000002 + adapt_span_layer: bool = False + + +@register_model("adaptive_span", dataclass=AdaptiveSpanSmallConfig) +class AdaptiveSpanTransformer(FairseqLanguageModel): + @classmethod + def build_model(cls, cfg: AdaptiveSpanSmallConfig, task): + return cls(AdaptiveSpanDecoder(cfg, task)) + + def get_aux_loss(self): + return self.decoder.get_aux_loss() + + def get_current_max_span(self): + return self.decoder.get_current_max_span() + + def get_current_avg_span(self): + return self.decoder.get_current_avg_span() + + +class AdaptiveSpanDecoder(FairseqIncrementalDecoder): + def __init__(self, cfg, task): + + super().__init__(task.target_dictionary) + + self.config = cfg + config = AdaptiveSpanSmallConfig( + vocab_size=len(task.target_dictionary), + d_model=cfg.d_model, + n_head=cfg.n_head, + d_inner=cfg.d_inner, + n_layer=cfg.n_layer, + attn_span=cfg.attn_span, + dropout=cfg.dropout, + emb_dropout=cfg.emb_dropout, + adapt_span_ramp=cfg.adapt_span_ramp, + adapt_span_init=cfg.adapt_span_init, + aux_loss_scaler=cfg.aux_loss_scaler, + adapt_span_layer=cfg.adapt_span_layer, + ) + logger.info(config) + self.model = AdaptiveSpanTransformerModel(**config.__dict__) + + self._mems = None + + def forward( + self, + src_tokens, + incremental_state: Optional[Dict[str, List[torch.Tensor]]] = None, + encoder_out=None, + ): + bsz = src_tokens.size(0) + if incremental_state is not None: # used during inference + mems = self.get_incremental_state("mems") + src_tokens = src_tokens[:, -1:] # only keep the most recent token + else: + mems = self._mems + + if mems is None: + # first time init + mems = self.init_hid_cache(bsz) + output = self.model(x=src_tokens, h_cache=mems,) + if incremental_state is not None: + self.set_incremental_state(incremental_state, "mems", output[1]) + else: + self._mems = output[1] + return (output[0],) + + def max_positions(self): + return self.config.attn_span + + def init_hid_cache(self, batch_sz): + hid = [] + for layer in self.model.layers: + param = next(self.model.parameters()) + h = torch.zeros( + batch_sz, + layer.get_cache_size(), + self.config.d_model, + dtype=param.dtype, + device=param.device, + ) + hid.append(h) + return hid + + def get_aux_loss(self): + return self.model.get_aux_loss() + + def get_current_max_span(self): + return self.model.get_current_max_span() + + def get_current_avg_span(self): + return self.model.get_current_avg_span() + + def reorder_incremental_state( + self, + incremental_state: Dict[str, Dict[str, Optional[torch.Tensor]]], + new_order: torch.Tensor, + ): + """Reorder incremental state. + + This will be called when the order of the input has changed from the + previous time step. A typical use case is beam search, where the input + order changes between time steps based on the selection of beams. + """ + raise NotImplementedError("This is required for generation/beam search") + # mems = self.get_incremental_state(incremental_state, "mems") + # if mems is not None: + # new_mems = [mems_i.index_select(1, new_order) for mems_i in mems] + # self.set_incremental_state(incremental_state, "mems", new_mems) diff --git a/examples/adaptive_span/truncated_bptt_lm_task.py b/examples/adaptive_span/truncated_bptt_lm_task.py new file mode 120000 index 0000000000..a92da3a298 --- /dev/null +++ b/examples/adaptive_span/truncated_bptt_lm_task.py @@ -0,0 +1 @@ +../truncated_bptt/truncated_bptt_lm_task.py \ No newline at end of file diff --git a/fairseq/optim/adagrad.py b/fairseq/optim/adagrad.py index a79b6c39da..4f539541c1 100644 --- a/fairseq/optim/adagrad.py +++ b/fairseq/optim/adagrad.py @@ -37,4 +37,4 @@ def optimizer_config(self): @property def supports_flat_params(self): - return True + return False From 5a3e51d21187415a66632f65e92c71de61367a93 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 15 Dec 2020 17:19:53 -0800 Subject: [PATCH 119/774] Infer TPU flag automatically and deprecate prepare_for_tpu (#1514) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1514 Reviewed By: ngoyal2707 Differential Revision: D25568540 Pulled By: myleott fbshipit-source-id: 93cf2dfd55323bc396b893eb6d658f1c6283a88b --- .../modules/multihead_linear_attention.py | 4 ---- .../model_parallel/modules/multihead_attention.py | 9 +++------ fairseq/models/fairseq_model.py | 15 --------------- fairseq/modules/multihead_attention.py | 10 ++++------ fairseq/modules/transformer_sentence_encoder.py | 7 ++----- fairseq/tasks/fairseq_task.py | 4 ---- 6 files changed, 9 insertions(+), 40 deletions(-) diff --git a/examples/linformer/linformer_src/modules/multihead_linear_attention.py b/examples/linformer/linformer_src/modules/multihead_linear_attention.py index ba2c36b1ef..6be1007279 100644 --- a/examples/linformer/linformer_src/modules/multihead_linear_attention.py +++ b/examples/linformer/linformer_src/modules/multihead_linear_attention.py @@ -111,14 +111,10 @@ def __init__( self.compress_v.weight.requires_grad = False self.onnx_trace = False - self.tpu = False def prepare_for_onnx_export_(self): self.onnx_trace = True - def prepare_for_tpu_(self, **kwargs): - self.tpu = True - def reset_parameters(self): if self.qkv_same_dim: # Empirically observed the convergence to be much better with diff --git a/fairseq/model_parallel/modules/multihead_attention.py b/fairseq/model_parallel/modules/multihead_attention.py index 4164bf9131..8eb9d09dad 100644 --- a/fairseq/model_parallel/modules/multihead_attention.py +++ b/fairseq/model_parallel/modules/multihead_attention.py @@ -93,11 +93,6 @@ def __init__( embed_dim, embed_dim, bias=bias, input_is_parallel=True ) - self.tpu = False - - def prepare_for_tpu_(self, **kwargs): - self.tpu = True - def forward( self, query, @@ -123,6 +118,8 @@ def forward( assert embed_dim == self.embed_dim assert list(query.size()) == [tgt_len, bsz, embed_dim] + is_tpu = query.device.type == "xla" + if incremental_state is not None: saved_state = self._get_input_buffer(incremental_state) if saved_state is not None and "prev_key" in saved_state: @@ -250,7 +247,7 @@ def forward( attn_weights = attn_weights.view( bsz, self.num_heads_partition, tgt_len, src_len ) - if not self.tpu: + if not is_tpu: attn_weights = attn_weights.masked_fill( key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), float("-inf"), diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 926d952f77..244cbc0c66 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -223,21 +223,6 @@ def apply_prepare_for_onnx_export_(module): self.apply(apply_prepare_for_onnx_export_) - def prepare_for_tpu_(self, **kwargs): - """Optionally modify model for use on TPUs.""" - seen = set() - - def apply_prepare_for_tpu_(module): - if ( - module != self - and hasattr(module, "prepare_for_tpu_") - and module not in seen - ): - seen.add(module) - module.prepare_for_tpu_(**kwargs) - - self.apply(apply_prepare_for_tpu_) - @classmethod def from_pretrained( cls, diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 99f95deb5f..6ab86245d2 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -87,14 +87,10 @@ def __init__( self.reset_parameters() self.onnx_trace = False - self.tpu = False def prepare_for_onnx_export_(self): self.onnx_trace = True - def prepare_for_tpu_(self, **kwargs): - self.tpu = True - def reset_parameters(self): if self.qkv_same_dim: # Empirically observed the convergence to be much better with @@ -148,13 +144,15 @@ def forward( if need_head_weights: need_weights = True + is_tpu = query.device.type == "xla" + tgt_len, bsz, embed_dim = query.size() assert embed_dim == self.embed_dim assert list(query.size()) == [tgt_len, bsz, embed_dim] if ( not self.onnx_trace - and not self.tpu # don't use PyTorch version on TPUs + and not is_tpu # don't use PyTorch version on TPUs and incremental_state is None and not static_kv # A workaround for quantization to work. Otherwise JIT compilation @@ -337,7 +335,7 @@ def forward( if key_padding_mask is not None: # don't attend to padding symbols attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) - if not self.tpu: + if not is_tpu: attn_weights = attn_weights.masked_fill( key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), float("-inf"), diff --git a/fairseq/modules/transformer_sentence_encoder.py b/fairseq/modules/transformer_sentence_encoder.py index 208488f562..7a5dcbdde3 100644 --- a/fairseq/modules/transformer_sentence_encoder.py +++ b/fairseq/modules/transformer_sentence_encoder.py @@ -113,7 +113,6 @@ def __init__( self.apply_bert_init = apply_bert_init self.learned_pos_embedding = learned_pos_embedding self.traceable = traceable - self.tpu = False # whether we're on TPU self.embed_tokens = self.build_embedding( self.vocab_size, self.embedding_dim, self.padding_idx @@ -220,9 +219,6 @@ def build_transformer_sentence_encoder_layer( qn_block_size=qn_block_size, ) - def prepare_for_tpu_(self, **kwargs): - self.tpu = True - def forward( self, tokens: torch.Tensor, @@ -231,10 +227,11 @@ def forward( positions: Optional[torch.Tensor] = None, token_embeddings: Optional[torch.Tensor] = None, ) -> Tuple[torch.Tensor, torch.Tensor]: + is_tpu = tokens.device.type == "xla" # compute padding mask. This is needed for multi-head attention padding_mask = tokens.eq(self.padding_idx) - if not self.traceable and not self.tpu and not padding_mask.any(): + if not self.traceable and not is_tpu and not padding_mask.any(): padding_mask = None if token_embeddings is not None: diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index b99c511990..24116bfd52 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -280,8 +280,6 @@ def build_model(self, cfg: FairseqDataclass): from fairseq import models, quantization_utils model = models.build_model(cfg, self) - if getattr(cfg, "tpu", False): - model.prepare_for_tpu_() model = quantization_utils.quantize_model_scalar(model, cfg) return model @@ -567,8 +565,6 @@ def build_model(self, args: Namespace): from fairseq import models, quantization_utils model = models.build_model(args, self) - if getattr(args, "tpu", False): - model.prepare_for_tpu_() model = quantization_utils.quantize_model_scalar(model, args) return model From 8d7ee5bf813f1fc0a0685e0cb1ef58fcc63e7855 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 15 Dec 2020 17:46:37 -0800 Subject: [PATCH 120/774] Fix hydra with Python 3.8 (#1511) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1511 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25570468 Pulled By: myleott fbshipit-source-id: 98efc6983479e163e6cf0a7ef33decaa1bc429f1 --- fairseq/dataclass/utils.py | 3 ++- setup.py | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 9d52d45942..45e7ed9170 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -228,8 +228,9 @@ def get_default(f): if isinstance(val, tuple): val = list(val) + v_type = getattr(v.type, "__origin__", None) if ( - getattr(v.type, "__origin__", None) is List + (v_type is List or v_type is list) # skip interpolation and not (isinstance(val, str) and val.startswith("${")) ): diff --git a/setup.py b/setup.py index 0a4be4b0dd..1954298034 100644 --- a/setup.py +++ b/setup.py @@ -168,6 +168,8 @@ def do_setup(package_data): "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Topic :: Scientific/Engineering :: Artificial Intelligence", ], long_description=readme, @@ -182,7 +184,8 @@ def do_setup(package_data): "cffi", "cython", 'dataclasses; python_version<"3.7"', - "hydra-core", + "hydra-core<1.1", + "omegaconf<2.1", 'numpy<1.20.0; python_version<"3.7"', 'numpy; python_version>="3.7"', "regex", From 409032596bd80240f7fbc833b5d37485dee85b0e Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 15 Dec 2020 17:46:37 -0800 Subject: [PATCH 121/774] Fix loading of very old checkpoints (#1512) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1512 See https://github.com/pytorch/fairseq/issues/3032 for context Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25570470 Pulled By: myleott fbshipit-source-id: 9227b1ca36cd81ff72acdb5e03fd574e3e8769be --- fairseq/checkpoint_utils.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 6209c71aef..f178617b5a 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -451,6 +451,12 @@ def _upgrade_state_dict(state): # keep track of number of updates if "num_updates" not in state["optimizer_history"][-1]: state["optimizer_history"][-1]["num_updates"] = 0 + # old model checkpoints may not have separate source/target positions + if hasattr(state["args"], "max_positions") and not hasattr( + state["args"], "max_source_positions" + ): + state["args"].max_source_positions = state["args"].max_positions + state["args"].max_target_positions = state["args"].max_positions # use stateful training data iterator if "train_iterator" not in state["extra_state"]: state["extra_state"]["train_iterator"] = { @@ -489,22 +495,16 @@ def _upgrade_state_dict(state): # audio_cpc => wav2vec if hasattr(state["args"], "arch") and state["args"].arch == "audio_cpc": state["args"].arch = "wav2vec" + # convert legacy float learning rate to List[float] + if hasattr(state["args"], "lr") and isinstance(state["args"].lr, float): + state["args"].lr = [state["args"].lr] state["cfg"] = convert_namespace_to_omegaconf(state["args"]) if "cfg" in state and state["cfg"] is not None: with open_dict(state["cfg"]): - if state["cfg"].task is not None: - # old model checkpoints may not have separate source/target positions - if hasattr(state["cfg"].task, "max_positions") and not hasattr( - state["cfg"].task, "max_source_positions" - ): - state["cfg"].task.max_source_positions = state[ - "cfg" - ].task.max_positions - state["cfg"].task.max_target_positions = state[ - "cfg" - ].task.max_positions + # any upgrades for Hydra-based configs + pass return state From c8a0659be5cdc15caa102d5bbf72b872567c4859 Mon Sep 17 00:00:00 2001 From: Sam Shleifer Date: Wed, 16 Dec 2020 19:06:45 -0800 Subject: [PATCH 122/774] Stronger --checkpoint-activations test (#1505) Summary: - captures and inspects train and valid logs using unittest's `assert_logs_equal` - asserts that `--checkpoint-activations` does not change `train_loss` or `valid_loss`. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1505 Reviewed By: myleott Differential Revision: D25544991 Pulled By: sshleifer fbshipit-source-id: 2762095ab4e7c819a803b3556f5774db8c6b6f39 --- tests/test_binaries.py | 126 ++++++++++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 38 deletions(-) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 58f86484f7..2b57aa66da 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -5,13 +5,14 @@ import contextlib import logging +import json import os import random import sys import tempfile import unittest from io import StringIO - +from typing import List, Dict import torch from fairseq import options from fairseq_cli import eval_lm, train, validate @@ -249,29 +250,6 @@ def test_transformer(self): ) generate_main(data_dir) - def test_transformer_with_activation_checkpointing(self): - with contextlib.redirect_stdout(StringIO()): - with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: - create_dummy_data(data_dir) - preprocess_translation_data(data_dir) - train_translation_model( - data_dir, - "transformer_iwslt_de_en", - [ - "--encoder-layers", - "2", - "--decoder-layers", - "2", - "--encoder-embed-dim", - "8", - "--decoder-embed-dim", - "8", - "--checkpoint-activations", - ], - run_validation=True, - ) - generate_main(data_dir) - def test_multilingual_transformer(self): # test with all combinations of encoder/decoder lang tokens encoder_langtok_flags = [ @@ -326,7 +304,9 @@ def test_multilingual_transformer(self): + dec_ltok_flag, ) - @unittest.skipIf(sys.platform.lower() == "darwin", "skip latent depth test on MacOS") + @unittest.skipIf( + sys.platform.lower() == "darwin", "skip latent depth test on MacOS" + ) def test_multilingual_translation_latent_depth(self): # test with latent depth in encoder, decoder, or both encoder_latent_layer = [[], ["--encoder-latent-layer"]] @@ -465,9 +445,7 @@ def test_translation_multi_simple_epoch_no_vepoch(self): "test_translation_multi_simple_epoch_dict" ) as data_dir: create_dummy_data(data_dir) - preprocess_translation_data( - data_dir, extra_flags=[] - ) + preprocess_translation_data(data_dir, extra_flags=[]) train_translation_model( data_dir, arch="transformer", @@ -517,9 +495,7 @@ def test_translation_multi_simple_epoch_dicts(self): "test_translation_multi_simple_epoch_dict" ) as data_dir: create_dummy_data(data_dir) - preprocess_translation_data( - data_dir, extra_flags=[] - ) + preprocess_translation_data(data_dir, extra_flags=[]) train_translation_model( data_dir, arch="transformer", @@ -619,11 +595,17 @@ def test_transformer_pointer_generator(self): "0", ], run_validation=True, - extra_valid_flags=["--user-dir", "examples/pointer_generator/pointer_generator_src"], + extra_valid_flags=[ + "--user-dir", + "examples/pointer_generator/pointer_generator_src", + ], ) generate_main( data_dir, - extra_flags=["--user-dir", "examples/pointer_generator/pointer_generator_src"], + extra_flags=[ + "--user-dir", + "examples/pointer_generator/pointer_generator_src", + ], ) def test_lightconv(self): @@ -953,7 +935,7 @@ def test_transformer_layerdrop(self): data_dir, [ "--model-overrides", - "{'encoder_layers_to_keep':'0,2','decoder_layers_to_keep':'1'}" + "{'encoder_layers_to_keep':'0,2','decoder_layers_to_keep':'1'}", ], ) @@ -1080,7 +1062,9 @@ def test_transformer_lm(self): def test_transformer_lm_with_adaptive_softmax(self): with contextlib.redirect_stdout(StringIO()): - with tempfile.TemporaryDirectory("test_transformer_lm_with_adaptive_softmax") as data_dir: + with tempfile.TemporaryDirectory( + "test_transformer_lm_with_adaptive_softmax" + ) as data_dir: create_dummy_data(data_dir) preprocess_lm_data(data_dir) train_language_model( @@ -1199,7 +1183,8 @@ def test_transformer_xl_bptt_lm(self): train_language_model( data_dir=data_dir, arch="transformer_xl", - extra_flags=task_flags + [ + extra_flags=task_flags + + [ "--n-layer", "2", ], @@ -1537,6 +1522,65 @@ def test_optimizers(self): generate_main(data_dir) +def read_last_log_entry( + logs: List[logging.LogRecord], logger_name: str +) -> Dict[str, float]: + for x in reversed(logs): + if x.name == logger_name: + return json.loads(x.message) + raise ValueError(f"No entries from {logger_name} found in captured logs") + + +class TestActivationCheckpointing(unittest.TestCase): + def test_activation_checkpointing_does_not_change_metrics(self): + """--checkpoint-activations should not change loss""" + base_flags = [ + "--encoder-layers", + "2", + "--decoder-layers", + "2", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--restore-file", + "x.pt", + "--log-format", + "json", + "--log-interval", + "1", + "--max-update", + "2", + ] + + def _train(extra_flags): + with self.assertLogs() as logs: + train_translation_model( + data_dir, + "transformer_iwslt_de_en", + base_flags + extra_flags, + run_validation=True, + extra_valid_flags=["--log-format", "json"], + ) + return logs.records + + with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: + + create_dummy_data(data_dir, num_examples=20) + preprocess_translation_data(data_dir) + ckpt_logs = _train(["--checkpoint-activations"]) + baseline_logs = _train([]) + assert len(baseline_logs) == len(ckpt_logs) + + baseline_train_stats = read_last_log_entry(baseline_logs, "train") + ckpt_train_stats = read_last_log_entry(ckpt_logs, "train") + assert baseline_train_stats["train_loss"] == ckpt_train_stats["train_loss"] + + baseline_valid_stats = read_last_log_entry(baseline_logs, "valid") + ckpt_valid_stats = read_last_log_entry(ckpt_logs, "valid") + assert baseline_valid_stats["valid_loss"] == ckpt_valid_stats["valid_loss"] + + def create_dummy_roberta_head_data( data_dir, num_examples=100, maxlen=10, num_classes=2, regression=False ): @@ -1653,7 +1697,12 @@ def train_roberta_head(data_dir, arch, num_classes=2, extra_flags=None): def train_language_model( - data_dir, arch, extra_flags=None, run_validation=False, extra_valid_flags=None, task="language_modeling" + data_dir, + arch, + extra_flags=None, + run_validation=False, + extra_valid_flags=None, + task="language_modeling", ): train_parser = options.get_training_parser() train_args = options.parse_args_and_arch( @@ -1723,7 +1772,8 @@ def eval_lm_main(data_dir, extra_flags=None): "--no-progress-bar", "--num-workers", "0", - ] + (extra_flags or []), + ] + + (extra_flags or []), ) eval_lm.main(eval_lm_args) From edc321e767ca4e980463d7af7f3d5eb751f60962 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 18 Dec 2020 07:39:39 -0800 Subject: [PATCH 123/774] Support atomic saves for checkpoints (#1520) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1520 Test Plan: Imported from OSS Reviewed By: stephenroller Differential Revision: D25632782 Pulled By: myleott fbshipit-source-id: bdbe2aed6254d0b023b33f8027dfbd939f1fd271 --- .github/workflows/build.yml | 4 ++++ fairseq/checkpoint_utils.py | 11 +++++++++-- fairseq/file_io.py | 23 +++++++++++++++++++++-- tests/test_iopath.py | 29 +++++++++++++++++++++++++++++ tests/test_reproducibility.py | 2 +- 5 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 tests/test_iopath.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a2d44dd57f..29e5254d33 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,6 +37,10 @@ jobs: python setup.py build_ext --inplace python -m pip install --editable . + - name: Install optional test requirements + run: | + python -m pip install fairscale iopath transformers + - name: Lint with flake8 run: | pip install flake8 diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index f178617b5a..34fef13387 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -408,8 +408,15 @@ def save_state( # keep everything on CPU state_dict = utils.move_to_cpu(state_dict) - with PathManager.open(filename, "wb") as f: - torch_persistent_save(state_dict, f) + if PathManager.supports_rename(filename): + # do atomic save + with PathManager.open(filename + ".tmp", "wb") as f: + torch_persistent_save(state_dict, f) + PathManager.rename(filename + ".tmp", filename) + else: + # fallback to non-atomic save + with PathManager.open(filename, "wb") as f: + torch_persistent_save(state_dict, f) def _upgrade_state_dict(state): diff --git a/fairseq/file_io.py b/fairseq/file_io.py index d74a48591a..7d6c28dccd 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -26,7 +26,8 @@ logging.warning("S3PathHandler already registered.") except ImportError: logging.debug( - "S3PathHandler couldn't be imported. Either missing fb-only files, or boto3 module.") + "S3PathHandler couldn't be imported. Either missing fb-only files, or boto3 module." + ) except ImportError: FVCorePathManager = None @@ -112,7 +113,7 @@ def rm(path: str) -> None: @staticmethod def chmod(path: str, mode: int) -> None: - if "manifold" not in path: + if not PathManager.path_requires_pathmanager(path): os.chmod(path, mode) @staticmethod @@ -129,3 +130,21 @@ def copy_from_local( local_path=local_path, dst_path=dst_path, overwrite=overwrite, **kwargs ) return shutil.copyfile(local_path, dst_path) + + @staticmethod + def path_requires_pathmanager(path: str) -> bool: + """Do we require PathManager to access given path?""" + if FVCorePathManager: + for p in FVCorePathManager._path_handlers.keys(): + if path.startswith(p): + return True + return False + + @staticmethod + def supports_rename(path: str) -> bool: + # PathManager doesn't yet support renames + return not PathManager.path_requires_pathmanager(path) + + @staticmethod + def rename(src: str, dst: str): + os.rename(src, dst) diff --git a/tests/test_iopath.py b/tests/test_iopath.py new file mode 100644 index 0000000000..908261a661 --- /dev/null +++ b/tests/test_iopath.py @@ -0,0 +1,29 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from unittest import mock + + +class TestIOPath(unittest.TestCase): + + def test_no_iopath(self): + from .test_reproducibility import TestReproducibility + + with mock.patch.dict("sys.modules", {"iopath": None}): + # reuse reproducibility tests, which are e2e tests that should cover + # most checkpoint related functionality + TestReproducibility._test_reproducibility(self, "test_reproducibility") + + def test_no_supports_rename(self): + from .test_reproducibility import TestReproducibility + + with mock.patch("fairseq.file_io.PathManager.supports_rename") as mock_fn: + mock_fn.return_value = False + TestReproducibility._test_reproducibility(self, "test_reproducibility") + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_reproducibility.py b/tests/test_reproducibility.py index 517e23c39e..405d545593 100644 --- a/tests/test_reproducibility.py +++ b/tests/test_reproducibility.py @@ -26,7 +26,7 @@ def _test_reproducibility( ): def get_last_log_stats_containing_string(log_records, search_string): for log_record in logs.records[::-1]: - if search_string in log_record.msg: + if isinstance(log_record.msg, str) and search_string in log_record.msg: return json.loads(log_record.msg) if extra_flags is None: From a041e1ae9cd5d69af993f5da6561223ad407f5da Mon Sep 17 00:00:00 2001 From: Xu Song Date: Fri, 18 Dec 2020 07:40:57 -0800 Subject: [PATCH 124/774] Fix parameter (#3045) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? `src_lengths` is not a required parameter in `TransformerEncoder`. It is a dummy variable. Maybe more changes should be done to fix this issue in Class such as `Transformer`, `FairseqEncoderDecoderModel`, `BARTModel` etc. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3045 Reviewed By: ngoyal2707 Differential Revision: D25632992 Pulled By: myleott fbshipit-source-id: 762d595144b611e1a6c236248d7001049afed0ab --- fairseq/models/transformer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 9655578e52..fa4c29855b 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -402,7 +402,7 @@ def forward_embedding( def forward( self, src_tokens, - src_lengths, + src_lengths: Optional[torch.Tensor] = None, return_all_hiddens: bool = False, token_embeddings: Optional[torch.Tensor] = None, ): @@ -418,7 +418,7 @@ def forward( default `None` will recompute embeddings Returns: - namedtuple: + dict: - **encoder_out** (Tensor): the last encoder layer's output of shape `(src_len, batch, embed_dim)` - **encoder_padding_mask** (ByteTensor): the positions of From 3a597d11731c7b7949072856aa51dbf4581963b0 Mon Sep 17 00:00:00 2001 From: Yiding Tian Date: Fri, 18 Dec 2020 07:41:03 -0800 Subject: [PATCH 125/774] Removing an unwanted bracket character in logging message. (#3028) Summary: # Before submitting - [no] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [yes] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [no need] Did you make sure to update the docs? - [no need] Did you write any new necessary tests? ## What does this PR do? Just fixing a small typo of logging one additional bracket before starting training. ## PR review Anyone in the community is free to review the PR once the tests have passed. > If we didn't discuss your PR in Github issues there's a high chance it will not be merged. It's really a small change, no need to discuss. ## Did you have fun? Small change although, do have fun reading the code. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3028 Reviewed By: ngoyal2707 Differential Revision: D25632978 Pulled By: myleott fbshipit-source-id: 62c85a9727af523d4082678a12a71b78f3ea84c0 --- fairseq_cli/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 81ecc80140..245263402e 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -76,7 +76,7 @@ def main(cfg: DictConfig) -> None: logger.info(model) logger.info("task: {}".format(task.__class__.__name__)) logger.info("model: {}".format(model.__class__.__name__)) - logger.info("criterion: {})".format(criterion.__class__.__name__)) + logger.info("criterion: {}".format(criterion.__class__.__name__)) logger.info( "num. model params: {} (num. trained: {})".format( sum(p.numel() for p in model.parameters()), From 828960f5dace4787ad81aeadca60043c907adc67 Mon Sep 17 00:00:00 2001 From: Edresson Casanova Date: Fri, 18 Dec 2020 07:41:49 -0800 Subject: [PATCH 126/774] fix inconsistency in wav2vec documentation (#3039) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3039 Reviewed By: ngoyal2707 Differential Revision: D25632983 Pulled By: myleott fbshipit-source-id: 32a60da9d41e600d2b047171d548f954196c0560 --- examples/wav2vec/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 05df59f214..a0c95e9c34 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -162,8 +162,8 @@ Wav2Vec large | [Librispeech](http://www.openslr.org/12) | [download](https://dl import torch import fairseq -cp = torch.load('/path/to/wav2vec.pt') -model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp]) +cp_path = '/path/to/wav2vec.pt' +model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp_path]) model = model[0] model.eval() From 9693504a8a75bafd7bddd6caa47cc5aed6821a2b Mon Sep 17 00:00:00 2001 From: Tim Dettmers Date: Fri, 18 Dec 2020 07:42:44 -0800 Subject: [PATCH 127/774] Bugfix: Early exist in creating dictionaries due to unexpected f.tell() behavior (#2956) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? This PR fixes an issue with `f.tell()` when creating dictionaries. Before this bugfix, the dictionary generation had silently nondeterministic behavior which worsens with multiple workers. Please the comment in the commit for more details. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/2956 Reviewed By: ngoyal2707 Differential Revision: D25633020 Pulled By: myleott fbshipit-source-id: 08a4ae4a8d6e03f72484baafe012212a99003ada --- fairseq/binarizer.py | 8 +++++++- fairseq/data/dictionary.py | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/fairseq/binarizer.py b/fairseq/binarizer.py index 0255c084b5..c736c8754d 100644 --- a/fairseq/binarizer.py +++ b/fairseq/binarizer.py @@ -46,7 +46,13 @@ def replaced_consumer(word, idx): # next(f) breaks f.tell(), hence readline() must be used line = safe_readline(f) while line: - if end > 0 and f.tell() > end: + # f.tell() does not always give the byte position in the file + # sometimes it skips to a very large number + # it is unlikely that through a normal read we go from + # end bytes to end + 2**32 bytes (4 GB) and this makes it unlikely + # that the procedure breaks by the undeterministic behavior of + # f.tell() + if end > 0 and f.tell() > end and f.tell() < end + 2**32: break if already_numberized: id_strings = line.strip().split() diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index efb5f1542c..127d023f4c 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -335,7 +335,13 @@ def _add_file_to_dictionary_single_worker( for word in tokenize(line): counter.update([word]) counter.update([eos_word]) - if f.tell() > end: + # f.tell() returns only an opaque number which can + # return to the position in the file via f.seek() + # and does not necessarily represent a byte position + # in the file. However, f.tell() is faithful to the + # byte position _most of the time_. Thus we can just + # check against the file size to prevent early exit. + if f.tell() > end and f.tell() < size: break line = f.readline() return counter From 36c63c826d2292c9df56065b5816c02eefc87713 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Fri, 18 Dec 2020 11:44:05 -0800 Subject: [PATCH 128/774] Refactor eval_lm to support library usage (#1513) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1513 Test Plan: Imported from OSS Reviewed By: alexeib Differential Revision: D25570467 Pulled By: myleott fbshipit-source-id: 062f748e287797f4f01c605e0b544ef3e698851f --- .../truncated_bptt/transformer_xl_model.py | 9 +- .../truncated_bptt/truncated_bptt_lm_task.py | 36 +- fairseq/checkpoint_utils.py | 6 +- fairseq/data/data_utils.py | 8 +- fairseq/dataclass/configs.py | 8 +- fairseq/tasks/language_modeling.py | 37 ++ fairseq_cli/eval_lm.py | 344 ++++++++++-------- tests/test_binaries.py | 1 + 8 files changed, 294 insertions(+), 155 deletions(-) diff --git a/examples/truncated_bptt/transformer_xl_model.py b/examples/truncated_bptt/transformer_xl_model.py index 7466c951ab..83b248479e 100644 --- a/examples/truncated_bptt/transformer_xl_model.py +++ b/examples/truncated_bptt/transformer_xl_model.py @@ -49,8 +49,13 @@ def build_model(cls, cfg: TransformerXLConfig, task): class TransformerXLDecoder(FairseqIncrementalDecoder): def __init__(self, cfg, task): - from transformers.configuration_transfo_xl import TransfoXLConfig - from transformers.modeling_transfo_xl import TransfoXLLMHeadModel + try: + from transformers.models.transfo_xl import ( + TransfoXLConfig, TransfoXLLMHeadModel + ) + except ImportError: + from transformers.configuration_transfo_xl import TransfoXLConfig + from transformers.modeling_transfo_xl import TransfoXLLMHeadModel super().__init__(task.target_dictionary) self.cfg = cfg diff --git a/examples/truncated_bptt/truncated_bptt_lm_task.py b/examples/truncated_bptt/truncated_bptt_lm_task.py index 5f81ec4b84..34c4f03955 100644 --- a/examples/truncated_bptt/truncated_bptt_lm_task.py +++ b/examples/truncated_bptt/truncated_bptt_lm_task.py @@ -10,7 +10,12 @@ import torch from fairseq import distributed_utils as dist_utils, utils -from fairseq.data import Dictionary, TokenBlockDataset, data_utils, iterators +from fairseq.data import ( + Dictionary, + TokenBlockDataset, + data_utils, + iterators, +) from fairseq.dataclass import FairseqDataclass from fairseq.tasks import FairseqTask, register_task from omegaconf import II @@ -182,6 +187,35 @@ def inference_step( models, sample, prefix_tokens=prefix_tokens, bos_token=bos_token ) + def eval_lm_dataloader( + self, + dataset, + max_tokens: Optional[int] = 36000, + batch_size: Optional[int] = None, + max_positions: Optional[int] = None, + num_shards: int = 1, + shard_id: int = 0, + num_workers: int = 1, + data_buffer_size: int = 10, + context_window: int = 0, + ): + if context_window > 0: + raise NotImplementedError( + "Transformer-XL doesn't need --context-window, try " + "--model-overrides '{\"mem_len\":42}' instead " + ) + return self.get_batch_iterator( + dataset=dataset, + max_tokens=max_tokens, + max_sentences=batch_size, + max_positions=max_positions, + ignore_invalid_inputs=True, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + data_buffer_size=data_buffer_size, + ).next_epoch_itr(shuffle=False) + @property def source_dictionary(self): return self.dictionary diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 34fef13387..f3c2d8aa16 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -11,7 +11,7 @@ import re import traceback from collections import OrderedDict -from typing import Optional, Union +from typing import Any, Dict, Optional, Union import torch from fairseq.dataclass.configs import CheckpointConfig, FairseqConfig @@ -241,7 +241,7 @@ def load_checkpoint_to_cpu(path, arg_overrides=None): def load_model_ensemble( filenames, - arg_overrides=None, + arg_overrides: Optional[Dict[str, Any]] = None, task=None, strict=True, suffix="", @@ -273,7 +273,7 @@ def load_model_ensemble( def load_model_ensemble_and_task( filenames, - arg_overrides=None, + arg_overrides: Optional[Dict[str, Any]] = None, task=None, strict=True, suffix="", diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 81f457365a..1efe352dd2 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -346,8 +346,12 @@ def post_process(sentence: str, symbol: str): sentence = sentence.replace(" ", "").replace("|", " ").strip() elif symbol == "_EOW": sentence = sentence.replace(" ", "").replace("_EOW", " ").strip() - elif symbol is not None and symbol != "none": - sentence = (sentence + " ").replace(symbol, "").rstrip() + elif symbol in {"subword_nmt", "@@ "}: + sentence = (sentence + " ").replace("@@ ", "").rstrip() + elif symbol == "none": + pass + elif symbol is not None: + raise NotImplementedError(f"Unknown post_process option: {symbol}") return sentence diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 7d27dc0d4b..584e9201a3 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -831,9 +831,11 @@ class CommonEvalConfig(FairseqDataclass): post_process: Optional[str] = field( default=None, metadata={ - "help": "post-process text by removing pre-processing such as BPE, letter segmentation, etc " - "(valid options are: sentencepiece, wordpiece, letter, _EOW, none, otherwise treated as BPE symbol)", - "argparse_const": "@@ ", + "help": ( + "post-process text by removing BPE, letter segmentation, etc. " + "Valid options can be found in fairseq.data.utils.post_process." + ), + "argparse_const": "subword_nmt", "argparse_alias": "--remove-bpe", }, ) diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index e0bf1f9b2b..b68c4ad4d1 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -15,6 +15,7 @@ AppendTokenDataset, Dictionary, IdDataset, + LMContextWindowDataset, MonolingualDataset, NestedDictionaryDataset, NumelDataset, @@ -312,6 +313,42 @@ def inference_step( models, sample, prefix_tokens=prefix_tokens, bos_token=bos_token ) + def eval_lm_dataloader( + self, + dataset, + max_tokens: Optional[int] = 36000, + batch_size: Optional[int] = None, + max_positions: Optional[int] = None, + num_shards: int = 1, + shard_id: int = 0, + num_workers: int = 1, + data_buffer_size: int = 10, + # ensures that every evaluated token has access to a context of at least + # this size, if possible + context_window: int = 0, + ): + if context_window > 0: + assert self.args.tokens_per_sample > context_window + # reduce tokens per sample by the required context window size + tokens_per_sample = self.args.tokens_per_sample - context_window + dataset = LMContextWindowDataset( + dataset=dataset, + tokens_per_sample=tokens_per_sample, + context_window=context_window, + pad_idx=self.source_dictionary.pad(), + ) + return self.get_batch_iterator( + dataset=dataset, + max_tokens=max_tokens, + max_sentences=batch_size, + max_positions=max_positions, + ignore_invalid_inputs=True, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + data_buffer_size=data_buffer_size, + ).next_epoch_itr(shuffle=False) + @property def source_dictionary(self): """Return the :class:`~fairseq.data.Dictionary` for the language diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index d962a8145b..a872245881 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -11,14 +11,16 @@ import logging import math import os +import sys from argparse import Namespace +from typing import Iterable, List, Optional import torch +import fairseq from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils -from fairseq.data import LMContextWindowDataset from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar -from fairseq.logging.meters import StopwatchMeter, TimeMeter +from fairseq.logging.meters import StopwatchMeter from fairseq.sequence_scorer import SequenceScorer from omegaconf import DictConfig @@ -27,144 +29,74 @@ format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, ) logger = logging.getLogger("fairseq_cli.eval_lm") -class WordStat(object): - def __init__(self, word, is_bpe): - self.word = word - self.is_bpe = is_bpe - self.log_prob = 0 - self.next_word_prob = 0 - self.count = 0 - self.missing_next_words = 0 - - def add(self, log_prob, next_word_prob): - """increments counters for the sum of log probs of current word and next - word (given context ending at current word). Since the next word might be at the end of the example, - or it might be not counted because it is not an ending subword unit, - also keeps track of how many of those we have seen""" - if next_word_prob is not None: - self.next_word_prob += next_word_prob - else: - self.missing_next_words += 1 - self.log_prob += log_prob - self.count += 1 - - def __str__(self): - return "{}\t{}\t{}\t{}\t{}\t{}".format( - self.word, - self.count, - self.log_prob, - self.is_bpe, - self.next_word_prob, - self.count - self.missing_next_words, - ) - - -def main(cfg: DictConfig, **unused_kwargs): - if isinstance(cfg, Namespace): - cfg = convert_namespace_to_omegaconf(cfg) - - utils.import_user_module(cfg.common) - - use_fp16 = cfg.common.fp16 - use_cuda = torch.cuda.is_available() and not cfg.common.cpu - - if use_cuda: - torch.cuda.set_device(cfg.distributed_training.device_id) - - logger.info(cfg) - - # Load ensemble - logger.info("loading model(s) from {}".format(cfg.common_eval.path)) - - # reduce tokens per sample by the required context window size - cfg.task.tokens_per_sample -= cfg.eval_lm.context_window - - # Initialize the task using the current *cfg* - task = tasks.setup_task(cfg.task) - - # Initialize the model (but not the task) using the checkpoint's *cfg* - models, model_args, task = checkpoint_utils.load_model_ensemble_and_task( - [cfg.common_eval.path], - arg_overrides=eval(cfg.common_eval.model_overrides), - suffix=cfg.checkpoint.checkpoint_suffix, - strict=(cfg.checkpoint.checkpoint_shard_count == 1), - num_shards=cfg.checkpoint.checkpoint_shard_count, - task=task, - ) - - # Load dataset splits - gen_subset = cfg.dataset.gen_subset - task.load_dataset(gen_subset) - dataset = task.dataset(gen_subset) - if cfg.eval_lm.context_window > 0: - dataset = LMContextWindowDataset( - dataset=dataset, - tokens_per_sample=cfg.task.tokens_per_sample, - context_window=cfg.eval_lm.context_window, - pad_idx=task.source_dictionary.pad(), - ) - logger.info("{} {} {} examples".format(cfg.task.data, gen_subset, len(dataset))) - - # Optimize ensemble for generation and set the source and dest dicts on the model (required by scorer) - for model in models: - if use_fp16: - model.half() - if use_cuda and not cfg.distributed_training.pipeline_model_parallel: - model.cuda() - model.prepare_for_inference_(cfg) - - assert len(models) > 0 - - logger.info( - "num. model params: {}".format(sum(p.numel() for p in models[0].parameters())) - ) - - itr = task.get_batch_iterator( - dataset=dataset, - max_tokens=cfg.dataset.max_tokens or 36000, - max_sentences=cfg.dataset.batch_size, - max_positions=utils.resolve_max_positions( - *[model.max_positions() for model in models] - ), - ignore_invalid_inputs=True, - num_shards=max( - cfg.dataset.num_shards, - cfg.distributed_training.distributed_world_size, - ), - shard_id=max( - cfg.dataset.shard_id, - cfg.distributed_training.distributed_rank, - ), - num_workers=cfg.dataset.num_workers, - data_buffer_size=cfg.dataset.data_buffer_size, - ).next_epoch_itr(shuffle=False) - progress = progress_bar.progress_bar( - itr, - log_format=cfg.common.log_format, - log_interval=cfg.common.log_interval, - default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), - ) +def eval_lm( + models: List[fairseq.models.FairseqModel], + source_dictionary: fairseq.data.Dictionary, + batch_iterator: Iterable, + post_process: Optional[str] = None, + output_word_probs: bool = False, + output_word_stats: bool = False, + target_dictionary: Optional[fairseq.data.Dictionary] = None, + softmax_batch: int = False, + remove_bos_token: bool = False, + device: Optional[torch.device] = None, +): + """ + Args: + models (List[~fairseq.models.FairseqModel]): list of models to + evaluate. Models are essentially `nn.Module` instances, but + must be compatible with fairseq's `SequenceScorer`. + source_dictionary (~fairseq.data.Dictionary): dictionary for + applying any relevant post processing or outputing word + probs/stats. + batch_iterator (Iterable): yield batches of data + post_process (Optional[str]): post-process text by removing BPE, + letter segmentation, etc. Valid options can be found in + fairseq.data.utils.post_process, although not all options + are implemented here. + output_word_probs (Optional[bool]): output words and their + predicted log probabilities + output_word_stats (Optional[bool]): output word statistics such + as word count and average probability + target_dictionary (Optional[~fairseq.data.Dictionary]): output + dictionary (defaults to *source_dictionary*) + softmax_batch (Optional[bool]): if BxT is more than this, will + batch the softmax over vocab to this amount of tokens, in + order to fit into GPU memory + remove_bos_token (Optional[bool]): if True, confirm that the + first token is the beginning-of-sentence symbol (according + to the relevant dictionary) and remove it from the output + device (Optional[torch.device]): device to use for evaluation + (defaults to device of first model parameter) + """ + if target_dictionary is None: + target_dictionary = source_dictionary + if device is None: + device = next(models[0].parameters()).device gen_timer = StopwatchMeter() - scorer = SequenceScorer(task.target_dictionary, cfg.eval_lm.softmax_batch) + scorer = SequenceScorer(target_dictionary, softmax_batch) score_sum = 0.0 count = 0 - if cfg.common_eval.post_process is not None: - if cfg.common_eval.post_process == "sentencepiece": - raise NotImplementedError - else: - bpe_cont = cfg.common_eval.post_process.rstrip() + if post_process is not None: + if post_process in {"subword_nmt", "@@ "}: + bpe_cont = post_process.rstrip() bpe_toks = { i - for i in range(len(task.source_dictionary)) - if task.source_dictionary[i].endswith(bpe_cont) + for i in range(len(source_dictionary)) + if source_dictionary[i].endswith(bpe_cont) } + else: + raise NotImplementedError( + "--post-process={post_process} is not implemented" + ) bpe_len = len(bpe_cont) else: bpe_toks = None @@ -172,13 +104,11 @@ def main(cfg: DictConfig, **unused_kwargs): word_stats = dict() - wps_meter = TimeMeter() - - for sample in progress: + for sample in batch_iterator: if "net_input" not in sample: continue - sample = utils.move_to_cuda(sample) if use_cuda else sample + sample = utils.move_to_cuda(sample, device=device) gen_timer.start() hypos = scorer.generate(models, sample) @@ -192,8 +122,8 @@ def main(cfg: DictConfig, **unused_kwargs): tgt_len = tokens.numel() pos_scores = hypo["positional_scores"].float() - if getattr(cfg.task, "add_bos_token", False): - assert hypo["tokens"][0].item() == task.target_dictionary.bos() + if remove_bos_token: + assert hypo["tokens"][0].item() == target_dictionary.bos() tokens = tokens[1:] pos_scores = pos_scores[1:] @@ -209,19 +139,19 @@ def main(cfg: DictConfig, **unused_kwargs): if inf_scores.any(): logger.info( "skipping tokens with inf scores:", - task.target_dictionary.string(tokens[inf_scores.nonzero()]), + target_dictionary.string(tokens[inf_scores.nonzero()]), ) pos_scores = pos_scores[(~inf_scores).nonzero()] score_sum += pos_scores.sum().cpu() count += pos_scores.numel() - skipped_toks - if cfg.eval_lm.output_word_probs or cfg.eval_lm.output_word_stats: + if output_word_probs or output_word_stats: w = "" word_prob = [] is_bpe = False for i in range(len(tokens)): w_ind = tokens[i].item() - w += task.source_dictionary[w_ind] + w += source_dictionary[w_ind] if bpe_toks is not None and w_ind in bpe_toks: w = w[:-bpe_len] is_bpe = True @@ -241,7 +171,7 @@ def main(cfg: DictConfig, **unused_kwargs): ) is_bpe = False w = "" - if cfg.eval_lm.output_word_probs: + if output_word_probs: logger.info( str(int(sample_id)) + " " @@ -252,24 +182,150 @@ def main(cfg: DictConfig, **unused_kwargs): ) ) - wps_meter.update(sample["ntokens"]) - progress.log({"wps": round(wps_meter.avg)}) - avg_nll_loss = -score_sum / count / math.log(2) if count > 0 else 0 # convert to base 2 logger.info( "Evaluated {} tokens in {:.1f}s ({:.2f} tokens/s)".format( gen_timer.n, gen_timer.sum, 1.0 / gen_timer.avg if gen_timer.avg > 0 else 0 ) ) + + if output_word_stats: + for ws in sorted(word_stats.values(), key=lambda x: x.count, reverse=True): + logger.info(ws) + + return { + "loss": avg_nll_loss, + "perplexity": 2 ** avg_nll_loss, + } + + +class WordStat(object): + def __init__(self, word, is_bpe): + self.word = word + self.is_bpe = is_bpe + self.log_prob = 0 + self.next_word_prob = 0 + self.count = 0 + self.missing_next_words = 0 + + def add(self, log_prob, next_word_prob): + """increments counters for the sum of log probs of current word and next + word (given context ending at current word). Since the next word might be at the end of the example, + or it might be not counted because it is not an ending subword unit, + also keeps track of how many of those we have seen""" + if next_word_prob is not None: + self.next_word_prob += next_word_prob + else: + self.missing_next_words += 1 + self.log_prob += log_prob + self.count += 1 + + def __str__(self): + return "{}\t{}\t{}\t{}\t{}\t{}".format( + self.word, + self.count, + self.log_prob, + self.is_bpe, + self.next_word_prob, + self.count - self.missing_next_words, + ) + + +def main(cfg: DictConfig, **unused_kwargs): + if isinstance(cfg, Namespace): + cfg = convert_namespace_to_omegaconf(cfg) + + utils.import_user_module(cfg.common) + + logger.info(cfg) + + # Initialize the task using the current *cfg* + task = tasks.setup_task(cfg.task) + + # Load ensemble + logger.info("loading model(s) from {}".format(cfg.common_eval.path)) + models, model_args, task = checkpoint_utils.load_model_ensemble_and_task( + [cfg.common_eval.path], + arg_overrides=eval(cfg.common_eval.model_overrides), + suffix=cfg.checkpoint.checkpoint_suffix, + strict=(cfg.checkpoint.checkpoint_shard_count == 1), + num_shards=cfg.checkpoint.checkpoint_shard_count, + task=task, + ) + + use_fp16 = cfg.common.fp16 + use_cuda = torch.cuda.is_available() and not cfg.common.cpu + if use_cuda: + torch.cuda.set_device(cfg.distributed_training.device_id) + + # Optimize ensemble for generation and set the source and dest dicts on the model + # (required by scorer) + for model in models: + if use_fp16: + model.half() + if use_cuda and not cfg.distributed_training.pipeline_model_parallel: + model.cuda() + model.prepare_for_inference_(cfg) + + assert len(models) > 0 + + logger.info( + "num. model params: {}".format(sum(p.numel() for p in models[0].parameters())) + ) + + # Load dataset splits + task.load_dataset(cfg.dataset.gen_subset) + dataset = task.dataset(cfg.dataset.gen_subset) + logger.info( + "{} {} {} examples".format(cfg.task.data, cfg.dataset.gen_subset, len(dataset)) + ) + + itr = task.eval_lm_dataloader( + dataset=dataset, + max_tokens=cfg.dataset.max_tokens or 36000, + batch_size=cfg.dataset.batch_size, + max_positions=utils.resolve_max_positions( + *[model.max_positions() for model in models] + ), + num_shards=max( + cfg.dataset.num_shards, + cfg.distributed_training.distributed_world_size, + ), + shard_id=max( + cfg.dataset.shard_id, + cfg.distributed_training.distributed_rank, + ), + num_workers=cfg.dataset.num_workers, + data_buffer_size=cfg.dataset.data_buffer_size, + context_window=cfg.eval_lm.context_window, + ) + + itr = progress_bar.progress_bar( + itr, + log_format=cfg.common.log_format, + log_interval=cfg.common.log_interval, + default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), + ) + + results = eval_lm( + models=models, + source_dictionary=task.source_dictionary, + batch_iterator=itr, + post_process=cfg.common_eval.post_process, + output_word_probs=cfg.eval_lm.output_word_probs, + output_word_stats=cfg.eval_lm.output_word_stats, + target_dictionary=task.target_dictionary, + softmax_batch=cfg.eval_lm.softmax_batch, + remove_bos_token=getattr(cfg.task, "add_bos_token", False), + ) + logger.info( "Loss (base 2): {:.4f}, Perplexity: {:.2f}".format( - avg_nll_loss, 2 ** avg_nll_loss + results["loss"], results["perplexity"] ) ) - if cfg.eval_lm.output_word_stats: - for ws in sorted(word_stats.values(), key=lambda x: x.count, reverse=True): - logger.info(ws) + return results def cli_main(): diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 2b57aa66da..4e605bd0b1 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -1048,6 +1048,7 @@ def test_transformer_lm(self): run_validation=True, ) eval_lm_main(data_dir) + eval_lm_main(data_dir, extra_flags=["--context-window", "25"]) generate_main( data_dir, [ From 4af87e3c150191f12e6e023c65ec97e38859b7f9 Mon Sep 17 00:00:00 2001 From: Wei Ho Date: Tue, 22 Dec 2020 18:00:04 -0800 Subject: [PATCH 129/774] Fix validate_and_save logic so validation is done for training terminated by stop_time_hours Summary: Also improves stopping criteria logging The final validation step wasn't being done when training was terminated by stop_time_hours. This was more of an issue for toy test cases (ex: wanting training to terminate in just a few min in order to test subsequent pipeline logic) since that could result in no validation loss ever being produced - which can break the rest of our pipeline Reviewed By: chtran Differential Revision: D25630252 fbshipit-source-id: 32cadbf977b0c9775830c1e8eb7f26bac12fe9ae --- fairseq_cli/train.py | 45 +++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 245263402e..adf07729c5 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -16,7 +16,6 @@ import numpy as np import torch - from fairseq import ( checkpoint_utils, distributed_utils, @@ -29,8 +28,8 @@ from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import meters, metrics, progress_bar from fairseq.model_parallel.megatron_trainer import MegatronTrainer -from omegaconf import DictConfig from fairseq.trainer import Trainer +from omegaconf import DictConfig logging.basicConfig( @@ -219,7 +218,9 @@ def train( "WANDB_NAME", os.path.basename(cfg.checkpoint.save_dir) ), azureml_logging=( - cfg.common.azureml_logging if distributed_utils.is_master(cfg.distributed_training) else False + cfg.common.azureml_logging + if distributed_utils.is_master(cfg.distributed_training) + else False ), ) @@ -273,9 +274,32 @@ def validate_and_save( ) -> Tuple[List[Optional[float]], bool]: num_updates = trainer.get_num_updates() max_update = cfg.optimization.max_update or math.inf + + # Stopping conditions (and an additional one based on validation loss later + # on) + should_stop = False + if num_updates >= max_update: + should_stop = True + logger.info( + f"Stopping training due to " + f"num_updates: {num_updates} >= max_update: {max_update}" + ) + + training_time_hours = trainer.cumulative_training_time() / (60 * 60) + if ( + cfg.optimization.stop_time_hours > 0 + and training_time_hours > cfg.optimization.stop_time_hours + ): + should_stop = True + logger.info( + f"Stopping training due to " + f"cumulative_training_time: {training_time_hours} > " + f"stop_time_hours: {cfg.optimization.stop_time_hours} hour(s)" + ) + do_save = ( (end_of_epoch and epoch_itr.epoch % cfg.checkpoint.save_interval == 0) - or num_updates >= max_update + or should_stop or ( cfg.checkpoint.save_interval_updates > 0 and num_updates > 0 @@ -286,7 +310,7 @@ def validate_and_save( do_validate = ( (not end_of_epoch and do_save) # validate during mid-epoch saves or (end_of_epoch and epoch_itr.epoch % cfg.dataset.validate_interval == 0) - or num_updates >= max_update + or should_stop or ( cfg.dataset.validate_interval_updates > 0 and num_updates > 0 @@ -299,16 +323,7 @@ def validate_and_save( if do_validate: valid_losses = validate(cfg, trainer, task, epoch_itr, valid_subsets) - # Stopping conditions - should_stop = ( - should_stop_early(cfg, valid_losses[0]) - or num_updates >= max_update - or ( - cfg.optimization.stop_time_hours > 0 - and trainer.cumulative_training_time() / (60 * 60) - > cfg.optimization.stop_time_hours - ) - ) + should_stop |= should_stop_early(cfg, valid_losses[0]) # Save checkpoint if do_save or should_stop: From 16a5fca05d3bcb5c1116ca987fa41c86599dfdf3 Mon Sep 17 00:00:00 2001 From: Wei Ho Date: Wed, 23 Dec 2020 11:15:53 -0800 Subject: [PATCH 130/774] fairseq checkpoint improvements Reviewed By: myleott Differential Revision: D25677238 fbshipit-source-id: b43075034c953491211f19a5464148de4758df83 --- fairseq/checkpoint_utils.py | 24 +++++++++++++++++------- fairseq/trainer.py | 19 +++++++++---------- fairseq_cli/train.py | 1 - 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index f3c2d8aa16..36a28f35dc 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -47,9 +47,6 @@ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): if not trainer.is_data_parallel_master: return - def is_better(a, b): - return a >= b if cfg.maximize_best_checkpoint_metric else a <= b - write_timer = meters.StopwatchMeter() write_timer.start() @@ -57,6 +54,11 @@ def is_better(a, b): end_of_epoch = epoch_itr.end_of_epoch() updates = trainer.get_num_updates() + logger.info(f"Preparing to save checkpoint for epoch {epoch} @ {updates} updates") + + def is_better(a, b): + return a >= b if cfg.maximize_best_checkpoint_metric else a <= b + suffix = cfg.checkpoint_suffix or "" checkpoint_conds = collections.OrderedDict() checkpoint_conds["checkpoint{}{}.pt".format(epoch, suffix)] = ( @@ -91,11 +93,13 @@ def is_better(a, b): if len(checkpoints) > 0: trainer.save_checkpoint(checkpoints[0], extra_state) for cp in checkpoints[1:]: - PathManager.copy(checkpoints[0], cp, overwrite=True) + assert PathManager.copy( + checkpoints[0], cp, overwrite=True + ), f"Failed to copy {checkpoints[0]} to {cp}" write_timer.stop() logger.info( - "saved checkpoint {} (epoch {} @ {} updates, score {}) (writing took {} seconds)".format( + "Saved checkpoint {} (epoch {} @ {} updates, score {}) (writing took {} seconds)".format( checkpoints[0], epoch, updates, val_loss, write_timer.sum ) ) @@ -494,10 +498,16 @@ def _upgrade_state_dict(state): state["args"].stop_min_lr = state["args"].min_lr del state["args"].min_lr # binary_cross_entropy => wav2vec criterion - if hasattr(state["args"], "criterion") and state["args"].criterion == "binary_cross_entropy": + if ( + hasattr(state["args"], "criterion") + and state["args"].criterion == "binary_cross_entropy" + ): state["args"].criterion = "wav2vec" # speech_pretraining => audio pretraining - if hasattr(state["args"], "task") and state["args"].task == "speech_pretraining": + if ( + hasattr(state["args"], "task") + and state["args"].task == "speech_pretraining" + ): state["args"].task = "audio_pretraining" # audio_cpc => wav2vec if hasattr(state["args"], "arch") and state["args"].arch == "audio_cpc": diff --git a/fairseq/trainer.py b/fairseq/trainer.py index cfeb63237b..8f42743ac3 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -263,10 +263,6 @@ def consolidate_optimizer(self): def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" if self.is_data_parallel_master: # only save one checkpoint - logger.info( - f"Preparing to save checkpoint to {filename} after " - f"{self.get_num_updates()} updates" - ) extra_state["metrics"] = metrics.state_dict() extra_state["previous_training_time"] = self.cumulative_training_time() checkpoint_utils.save_state( @@ -297,6 +293,7 @@ def load_checkpoint( """ extra_state, self._optim_history, last_optim_state = None, [], None + logger.info(f"Preparing to load checkpoint {filename}") bexists = PathManager.isfile(filename) if bexists: load_on_all_ranks = ( @@ -377,11 +374,6 @@ def load_checkpoint( if extra_state is not None: epoch = extra_state["train_iterator"]["epoch"] - logger.info( - "loaded checkpoint {} (epoch {} @ {} updates)".format( - filename, epoch, self.get_num_updates() - ) - ) if "previous_training_time" in extra_state: self._previous_training_time = extra_state["previous_training_time"] @@ -396,8 +388,15 @@ def load_checkpoint( for meter in metrics.get_meters("default"): if isinstance(meter, meters.TimeMeter): meter.reset() + + logger.info( + "Loaded checkpoint {} (epoch {} @ {} updates)".format( + filename, epoch, self.get_num_updates() + ) + ) + else: - logger.info("no existing checkpoint found {}".format(filename)) + logger.info("No existing checkpoint found {}".format(filename)) return extra_state diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index adf07729c5..165ed86b58 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -327,7 +327,6 @@ def validate_and_save( # Save checkpoint if do_save or should_stop: - logger.info("begin save checkpoint") checkpoint_utils.save_checkpoint( cfg.checkpoint, trainer, epoch_itr, valid_losses[0] ) From 996ae207075db47f4061519c7dc39a86ab6d9535 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Wed, 23 Dec 2020 16:41:59 -0800 Subject: [PATCH 131/774] Add --heartbeat-timeout (#1527) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1527 Test Plan: Train roberta large with FP32 so step time is moderate: No timeout: ``` CUDA_VISIBLE_DEVICES=0,1 python train.py --task dummy_masked_lm --arch roberta_large --criterion masked_lm --max-sentences 8 --optimizer adam --lr 0.0001 --log-format simple --log-interval 1 --update-freq 16 2020-12-23 13:45:07 | INFO | train_inner | epoch 001: 1 / 391 loss=15.957, ppl=63597.8, wps=0, ups=0, wpb=131072, bsz=256, num_updates=1, lr=0.0001, gnorm=12.446, train_wall=19, wall=22 2020-12-23 13:45:07 | INFO | root | Reducer buckets have been rebuilt in this iteration. 2020-12-23 13:45:20 | INFO | train_inner | epoch 001: 2 / 391 loss=14.75, ppl=27553.9, wps=10635.6, ups=0.08, wpb=131072, bsz=256, num_updates=2, lr=0.0001, gnorm=8.173, train_wall=12, wall=35 2020-12-23 13:45:32 | INFO | train_inner | epoch 001: 3 / 391 loss=13.894, ppl=15223, wps=10653, ups=0.08, wpb=131072, bsz=256, num_updates=3, lr=0.0001, gnorm=5.141, train_wall=12, wall=47 ``` Timeout of 1 second (fails): ``` CUDA_VISIBLE_DEVICES=0,1 python train.py --task dummy_masked_lm --arch roberta_large --criterion masked_lm --max-sentences 8 --optimizer adam --lr 0.0001 --log-format simple --log-interval 1 --update-freq 16 --heartbeat-timeout 1 2020-12-23 13:50:11 | ERROR | fairseq.models.distributed_fairseq_model | Killing job for not making progress in 1 seconds. Set --heartbeat-timeout=-1 to disable this timeout. 2020-12-23 13:50:11 | ERROR | fairseq.models.distributed_fairseq_model | Killing job for not making progress in 1 seconds. Set --heartbeat-timeout=-1 to disable this timeout. ``` Timeout of 3 seconds (doesn't fail): ``` CUDA_VISIBLE_DEVICES=0,1 python train.py --task dummy_masked_lm --arch roberta_large --criterion masked_lm --max-sentences 8 --optimizer adam --lr 0.0001 --log-format simple --log-interval 1 --update-freq 16 --heartbeat-timeout 3 2020-12-23 13:55:25 | INFO | train_inner | epoch 001: 1 / 391 loss=15.957, ppl=63597.8, wps=0, ups=0, wpb=131072, bsz=256, num_updates=1, lr=0.0001, gnorm=12.446, train_wall=19, wall=21 2020-12-23 13:55:25 | INFO | root | Reducer buckets have been rebuilt in this iteration. 2020-12-23 13:55:37 | INFO | train_inner | epoch 001: 2 / 391 loss=14.75, ppl=27553.9, wps=10682, ups=0.08, wpb=131072, bsz=256, num_updates=2, lr=0.0001, gnorm=8.173, train_wall=12, wall=33 2020-12-23 13:55:50 | INFO | train_inner | epoch 001: 3 / 391 loss=13.894, ppl=15223, wps=10654.5, ups=0.08, wpb=131072, bsz=256, num_updates=3, lr=0.0001, gnorm=5.141, train_wall=12, wall=46 ``` Reviewed By: joshim5, ngoyal2707 Differential Revision: D25696904 Pulled By: myleott fbshipit-source-id: b2dbb7ddd8ce3ea83491f479314a0b3caa09b4b7 --- fairseq/dataclass/configs.py | 7 ++++ fairseq/models/distributed_fairseq_model.py | 45 ++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 584e9201a3..caf4a7a2b8 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -252,6 +252,13 @@ class DistributedTrainingConfig(FairseqDataclass): default=False, metadata={"help": "[deprecated] this is now defined per Criterion"}, ) + heartbeat_timeout: int = field( + default=-1, + metadata={ + "help": "kill the job if no progress is made in N seconds; " + "set to -1 to disable" + } + ) broadcast_buffers: bool = field( default=False, metadata={ diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index b78a0125e3..909b3757b2 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -4,6 +4,10 @@ # LICENSE file in the root directory of this source tree. import inspect +import logging +import os +import signal +import threading import torch import torch.nn as nn @@ -12,6 +16,9 @@ from fairseq.legacy_distributed_data_parallel import LegacyDistributedDataParallel +logger = logging.getLogger(__name__) + + _GOSSIP_DISABLED = False try: import gossip @@ -97,12 +104,41 @@ def DistributedFairseqModel(args, model, process_group): else: raise ValueError("Unknown --ddp-backend: " + args.ddp_backend) + heartbeat_timeout = getattr(args, "heartbeat_timeout", -1) + class _DistributedFairseqModel(ddp_class): - """Extend DistributedDataParallel to check for missing - attributes in the wrapped module.""" + """ + Extend DistributedDataParallel to check for missing attributes in the + wrapped module and to add a timeout to kill the job if no progress is + made (--heartbeat-timeout). + """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self._heartbeat_timeout = heartbeat_timeout + if self._heartbeat_timeout > 0: + self._heartbeat = threading.Event() + self._heartbeat_thread = threading.Thread( + target=self._check_heartbeat, + args=(os.getpid(),), + daemon=True, + ) + self._heartbeat_thread.start() + else: + self._heartbeat = None + + def _check_heartbeat(self, parent_pid): + self._heartbeat.wait() # wait for the first forward pass + while True: + self._heartbeat.clear() + success = self._heartbeat.wait(timeout=self._heartbeat_timeout) + if not success: + logger.error(( + "Killing job for not making progress in {} seconds. " + "Set --heartbeat-timeout=-1 to disable this timeout." + ).format(int(self._heartbeat_timeout))) + os.kill(parent_pid, signal.SIGKILL) + return def __getattr__(self, name): wrapped_module = super().__getattr__("module") @@ -110,6 +146,11 @@ def __getattr__(self, name): return getattr(wrapped_module, name) return super().__getattr__(name) + def forward(self, *args, **kwargs): + if self._heartbeat is not None: + self._heartbeat.set() + return super().forward(*args, **kwargs) + return _DistributedFairseqModel(**init_kwargs) From b8ea8a9b72c82192da07e3377adf4ebbde16716d Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Wed, 23 Dec 2020 18:34:59 -0800 Subject: [PATCH 132/774] Fix --context-window and add test (#1526) Summary: This was broken in the recent refactoring: https://github.com/pytorch/fairseq/commit/36c63c826d2292c9df56065b5816c02eefc87713 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1526 Reviewed By: sshleifer Differential Revision: D25697706 Pulled By: myleott fbshipit-source-id: 4d9a735c0071a0d71a4ae46e1c3fc3aba572117b --- fairseq/data/lm_context_window_dataset.py | 21 ++++++++-- fairseq/data/monolingual_dataset.py | 8 ++-- fairseq/tasks/language_modeling.py | 5 +-- fairseq_cli/eval_lm.py | 4 ++ tests/test_lm_context_window.py | 51 +++++++++++++++++++++++ 5 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 tests/test_lm_context_window.py diff --git a/fairseq/data/lm_context_window_dataset.py b/fairseq/data/lm_context_window_dataset.py index 29ad887b7d..39512797bc 100644 --- a/fairseq/data/lm_context_window_dataset.py +++ b/fairseq/data/lm_context_window_dataset.py @@ -11,10 +11,23 @@ class LMContextWindowDataset(FairseqDataset): - """Wraps a MonolingualDataset and provides more context for evaluation.""" - - def __init__(self, dataset, tokens_per_sample, context_window, pad_idx): - assert isinstance(dataset, MonolingualDataset) + """ + Wraps a MonolingualDataset and provides more context for evaluation. + + Each item in the new dataset will have a maximum size of + ``tokens_per_sample + context_window``. + + Args: + dataset: dataset to wrap + tokens_per_sample (int): the max number of tokens in each dataset item + context_window (int): the number of accumulated tokens to add to each + dataset item + pad_idx (int): padding symbol + """ + + def __init__( + self, dataset, tokens_per_sample: int, context_window: int, pad_idx: int + ): assert context_window > 0 self.dataset = dataset self.tokens_per_sample = tokens_per_sample diff --git a/fairseq/data/monolingual_dataset.py b/fairseq/data/monolingual_dataset.py index ec73f1fda8..bf7aa86f6c 100644 --- a/fairseq/data/monolingual_dataset.py +++ b/fairseq/data/monolingual_dataset.py @@ -70,16 +70,16 @@ def __init__( dataset, sizes, src_vocab, - tgt_vocab, - add_eos_for_other_targets, - shuffle, + tgt_vocab=None, + add_eos_for_other_targets=False, + shuffle=False, targets=None, add_bos_token=False, ): self.dataset = dataset self.sizes = np.array(sizes) self.vocab = src_vocab - self.tgt_vocab = tgt_vocab + self.tgt_vocab = tgt_vocab or src_vocab self.add_eos_for_other_targets = add_eos_for_other_targets self.shuffle = shuffle self.add_bos_token = add_bos_token diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index b68c4ad4d1..4a44d967b3 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -328,12 +328,9 @@ def eval_lm_dataloader( context_window: int = 0, ): if context_window > 0: - assert self.args.tokens_per_sample > context_window - # reduce tokens per sample by the required context window size - tokens_per_sample = self.args.tokens_per_sample - context_window dataset = LMContextWindowDataset( dataset=dataset, - tokens_per_sample=tokens_per_sample, + tokens_per_sample=self.args.tokens_per_sample, context_window=context_window, pad_idx=self.source_dictionary.pad(), ) diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index a872245881..f27e0258d0 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -239,6 +239,10 @@ def main(cfg: DictConfig, **unused_kwargs): logger.info(cfg) + if cfg.eval_lm.context_window > 0: + # reduce tokens per sample by the required context window size + cfg.task.tokens_per_sample -= cfg.eval_lm.context_window + # Initialize the task using the current *cfg* task = tasks.setup_task(cfg.task) diff --git a/tests/test_lm_context_window.py b/tests/test_lm_context_window.py new file mode 100644 index 0000000000..7415e86abd --- /dev/null +++ b/tests/test_lm_context_window.py @@ -0,0 +1,51 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import torch +from fairseq.data import MonolingualDataset +from fairseq.tasks.language_modeling import LanguageModelingTask, LanguageModelingConfig +from tests import utils as test_utils + + +class TestLMContextWindow(unittest.TestCase): + + def test_eval_dataloader(self): + dictionary = test_utils.dummy_dictionary(10) + assert len(dictionary) == 14 # 4 extra special symbols + assert dictionary.pad() == 1 + + dataset = test_utils.TestDataset([ + torch.tensor([4, 5, 6, 7], dtype=torch.long), + torch.tensor([8, 9, 10, 11], dtype=torch.long), + torch.tensor([12, 13], dtype=torch.long), + ]) + dataset = MonolingualDataset(dataset, sizes=[4, 4, 2], src_vocab=dictionary) + + config = LanguageModelingConfig(tokens_per_sample=4) + task = LanguageModelingTask(config, dictionary) + + eval_dataloader = task.eval_lm_dataloader( + dataset=dataset, + batch_size=1, + context_window=2, + ) + + batch = next(eval_dataloader) + assert batch["net_input"]["src_tokens"][0].tolist() == [4, 5, 6, 7, 1, 1] + assert batch["target"][0].tolist() == [4, 5, 6, 7, 1, 1] + + batch = next(eval_dataloader) + assert batch["net_input"]["src_tokens"][0].tolist() == [6, 7, 8, 9, 10, 11] + assert batch["target"][0].tolist() == [1, 1, 8, 9, 10, 11] + + batch = next(eval_dataloader) + assert batch["net_input"]["src_tokens"][0].tolist() == [10, 11, 12, 13] + assert batch["target"][0].tolist() == [1, 1, 12, 13] + + +if __name__ == "__main__": + unittest.main() From 982ec329769cd189ba3735eecc9687d072bcdb72 Mon Sep 17 00:00:00 2001 From: Sam Shleifer Date: Mon, 28 Dec 2020 15:46:51 -0800 Subject: [PATCH 133/774] logger: format big numbers with commas for readability (#1525) Summary: Before: ``` 2020-12-23 11:46:16 | INFO | fairseq_cli.eval_lm | num. model params: 353781760 2020-12-23 11:46:21 | INFO | fairseq.data.data_utils | loaded 89663978 examples from: /private/home/sshleifer/data-bin/new_hybrid_data/train ``` After: ``` 2020-12-23 11:46:16 | INFO | fairseq_cli.eval_lm | num. model params: 353,781,760 2020-12-23 11:46:21 | INFO | fairseq.data.data_utils | loaded 89,663,978 examples from: /private/home/sshleifer/data-bin/new_hybrid_data/train ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1525 Test Plan: Run `fairseq-eval-lm` or `fairseq-train` and look at logs. For example, ``` export dd2=/private/home/sshleifer/data-bin/new_hybrid_data export m=/private/home/myleott/models/public_models/LM/roberta_lm.me_fp16.bm_none.tps1024.transformer_lm_gpt2_small.share.adam.b2_0.98.eps1e-08.cl0.0.lr0.003.wu3000.dr0.1.atdr0.1.wd0.01.ms2.uf4.mu100000.s1.ngpu64/model.pt fairseq-eval-lm $dd2 \ --path $m \ --sample-break-mode complete --gen-subset train \ --tokens-per-sample 3072 --max-tokens 3072 --context-window 2560 --softmax-batch 1024 --fp16 ``` Reviewed By: myleott Differential Revision: D25693004 Pulled By: sshleifer fbshipit-source-id: bfeb93fc6607cca2cb7a6e820f51e174d02d1f62 --- fairseq/data/data_utils.py | 2 +- fairseq/tasks/fairseq_task.py | 4 ++-- fairseq_cli/eval_lm.py | 12 ++++++++---- fairseq_cli/generate.py | 2 +- fairseq_cli/train.py | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 1efe352dd2..cac11ed1f9 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -99,7 +99,7 @@ def load_indexed_dataset( ) if dataset is None: break - logger.info("loaded {} examples from: {}".format(len(dataset), path_k)) + logger.info("loaded {:,} examples from: {}".format(len(dataset), path_k)) datasets.append(dataset) if not combine: break diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 24116bfd52..eb5e6a7694 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -154,7 +154,7 @@ def filter_indices_by_size( ) logger.warning( ( - "{} samples have invalid sizes and will be skipped, " + "{:,} samples have invalid sizes and will be skipped, " "max_positions={}, first few sample ids={}" ).format(len(ignored), max_positions, ignored[:10]) ) @@ -378,7 +378,7 @@ def build_generator( if seq_gen_cls is None: if getattr(args, "print_alignment", False): seq_gen_cls = SequenceGeneratorWithAlignment - extra_gen_cls_kwargs['print_alignment'] = args.print_alignment + extra_gen_cls_kwargs["print_alignment"] = args.print_alignment else: seq_gen_cls = SequenceGenerator diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index f27e0258d0..4501cac67e 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -182,9 +182,11 @@ def eval_lm( ) ) - avg_nll_loss = -score_sum / count / math.log(2) if count > 0 else 0 # convert to base 2 + avg_nll_loss = ( + -score_sum / count / math.log(2) if count > 0 else 0 + ) # convert to base 2 logger.info( - "Evaluated {} tokens in {:.1f}s ({:.2f} tokens/s)".format( + "Evaluated {:,} tokens in {:.1f}s ({:.2f} tokens/s)".format( gen_timer.n, gen_timer.sum, 1.0 / gen_timer.avg if gen_timer.avg > 0 else 0 ) ) @@ -274,14 +276,16 @@ def main(cfg: DictConfig, **unused_kwargs): assert len(models) > 0 logger.info( - "num. model params: {}".format(sum(p.numel() for p in models[0].parameters())) + "num. model params: {:,}".format(sum(p.numel() for p in models[0].parameters())) ) # Load dataset splits task.load_dataset(cfg.dataset.gen_subset) dataset = task.dataset(cfg.dataset.gen_subset) logger.info( - "{} {} {} examples".format(cfg.task.data, cfg.dataset.gen_subset, len(dataset)) + "{} {} {:,} examples".format( + cfg.task.data, cfg.dataset.gen_subset, len(dataset) + ) ) itr = task.eval_lm_dataloader( diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 4aeb4a56fa..ff8369b539 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -370,7 +370,7 @@ def decode_fn(x): logger.info("NOTE: hypothesis and token scores are output in base 2") logger.info( - "Translated {} sentences ({} tokens) in {:.1f}s ({:.2f} sentences/s, {:.2f} tokens/s)".format( + "Translated {:,} sentences ({:,} tokens) in {:.1f}s ({:.2f} sentences/s, {:.2f} tokens/s)".format( num_sentences, gen_timer.n, gen_timer.sum, diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 165ed86b58..6069cf48fe 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -77,7 +77,7 @@ def main(cfg: DictConfig) -> None: logger.info("model: {}".format(model.__class__.__name__)) logger.info("criterion: {}".format(criterion.__class__.__name__)) logger.info( - "num. model params: {} (num. trained: {})".format( + "num. model params: {:,} (num. trained: {:,})".format( sum(p.numel() for p in model.parameters()), sum(p.numel() for p in model.parameters() if p.requires_grad), ) From 4e3895be1ccb59e36de85441cd049294cbad2d15 Mon Sep 17 00:00:00 2001 From: Ruslan Mavlyutov Date: Mon, 28 Dec 2020 21:03:59 -0800 Subject: [PATCH 134/774] batch_by_size refactoring: 100x speedup and optimization of memory footprint Summary: Refactoring batch_by_size. You may be required to rebuild Cython components with: `python setup.py build_ext --inplace`. Reviewed By: myleott Differential Revision: D25705733 fbshipit-source-id: a263505276e3d820a9e44b93354ee5ace70d7fc5 --- fairseq/data/data_utils.py | 35 +++-- fairseq/data/data_utils_fast.pyx | 144 ++++++++++++------ fairseq/data/fairseq_dataset.py | 14 ++ fairseq/data/language_pair_dataset.py | 8 + .../multilingual/sampled_multi_dataset.py | 5 + tests/test_data_utils.py | 136 +++++++++++++++++ 6 files changed, 287 insertions(+), 55 deletions(-) create mode 100644 tests/test_data_utils.py diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index cac11ed1f9..9a0580977d 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -80,8 +80,8 @@ def load_indexed_dataset( combine 'data-bin/train', 'data-bin/train1', ... and return a single ConcatDataset instance. """ - from fairseq.data.concat_dataset import ConcatDataset import fairseq.data.indexed_dataset as indexed_dataset + from fairseq.data.concat_dataset import ConcatDataset datasets = [] for k in itertools.count(): @@ -276,6 +276,7 @@ def filter_paired_dataset_indices_by_size(src_sizes, tgt_sizes, indices, max_siz def batch_by_size( indices, num_tokens_fn, + num_tokens_vec=None, max_tokens=None, max_sentences=None, required_batch_size_multiple=1, @@ -289,6 +290,8 @@ def batch_by_size( indices (List[int]): ordered list of dataset indices num_tokens_fn (callable): function that returns the number of tokens at a given index + num_tokens_vec (List[int], optional): precomputed vector of the number + of tokens for each index in indices (to enable faster batch generation) max_tokens (int, optional): max number of tokens in each batch (default: None). max_sentences (int, optional): max number of sentences in each @@ -301,7 +304,8 @@ def batch_by_size( """ try: from fairseq.data.data_utils_fast import ( - batch_by_size_fast, + batch_by_size_fn, + batch_by_size_vec, batch_fixed_shapes_fast, ) except ImportError: @@ -317,14 +321,27 @@ def batch_by_size( if not isinstance(indices, np.ndarray): indices = np.fromiter(indices, dtype=np.int64, count=-1) + if num_tokens_vec is not None and not isinstance(num_tokens_vec, np.ndarray): + num_tokens_vec = np.fromiter(num_tokens_vec, dtype=np.int64, count=-1) + if fixed_shapes is None: - return batch_by_size_fast( - indices, - num_tokens_fn, - max_tokens, - max_sentences, - bsz_mult, - ) + if num_tokens_vec is None: + return batch_by_size_fn( + indices, + num_tokens_fn, + max_tokens, + max_sentences, + bsz_mult, + ) + else: + return batch_by_size_vec( + indices, + num_tokens_vec, + max_tokens, + max_sentences, + bsz_mult, + ) + else: fixed_shapes = np.array(fixed_shapes, dtype=np.int64) sort_order = np.lexsort( diff --git a/fairseq/data/data_utils_fast.pyx b/fairseq/data/data_utils_fast.pyx index 38b4aa67dd..d197d3f00e 100644 --- a/fairseq/data/data_utils_fast.pyx +++ b/fairseq/data/data_utils_fast.pyx @@ -10,63 +10,115 @@ cimport cython cimport numpy as np from libc.stdint cimport int32_t, int64_t +from libcpp cimport bool as bool_t ctypedef int64_t DTYPE_t - -cdef _is_batch_full(int64_t num_sentences, int64_t num_tokens, int64_t max_tokens, int64_t max_sentences): - if num_sentences == 0: - return 0 - if max_sentences > 0 and num_sentences == max_sentences: - return 1 - if max_tokens > 0 and num_tokens > max_tokens: - return 1 - return 0 - - @cython.cdivision(True) -cpdef list batch_by_size_fast( +@cython.boundscheck(False) +@cython.wraparound(False) +cpdef list batch_by_size_vec( + np.ndarray[int64_t, ndim=1] indices, + np.ndarray[int64_t, ndim=1] num_tokens_vec, + int64_t max_tokens, + int64_t max_sentences, + int32_t bsz_mult, +): + assert max_tokens <= 0 or np.max(num_tokens_vec) <= max_tokens, ( + f"Sentences lengths should not exceed max_tokens={max_tokens}" + ) + + cdef int32_t indices_len = indices.shape[0] + cdef np.ndarray[int32_t, ndim=1] batches_ends = \ + np.zeros(indices_len, dtype=np.int32) + cdef int32_t[:] batches_ends_view = batches_ends + cdef int64_t[:] num_tokens_view = num_tokens_vec + + cdef int32_t pos = 0 + cdef int32_t new_batch_end = 0 + + cdef int64_t new_batch_max_tokens = 0 + cdef int32_t new_batch_sentences = 0 + cdef int64_t new_batch_num_tokens = 0 + + cdef bool_t overflow = False + cdef bool_t size_matches_with_bsz_mult = False + + cdef int32_t batches_count = 0 + cdef int32_t batch_start = 0 + cdef int64_t tail_max_tokens = 0 + cdef int64_t batch_max_tokens = 0 + + for pos in range(indices_len): + # At every pos we keep stats about the last complete batch [batch_start:batch_end), + # and tail [batch_end:pos]. + # 1) Every time when (batch + tail) forms a valid batch + # (according to max_tokens, max_sentences and bsz_mult) we append tail to batch. + # 2) When (batch+tail) violates max_tokens or max_sentences constraints + # we finalize running batch, and tail becomes a new batch. + # 3) There is a corner case when tail also violates constraints. + # In that situation [batch_end:pos-1] (tail without the current pos) + # gets added to the finalized batches, while [pos:pos] becomes a new tail. + # + # Important: For the sake of performance try to avoid using function calls within this loop. + + tail_max_tokens = tail_max_tokens \ + if tail_max_tokens > num_tokens_view[pos] \ + else num_tokens_view[pos] + new_batch_end = pos + 1 + new_batch_max_tokens = batch_max_tokens \ + if batch_max_tokens > tail_max_tokens \ + else tail_max_tokens + new_batch_sentences = new_batch_end - batch_start + new_batch_num_tokens = new_batch_sentences * new_batch_max_tokens + + overflow = (new_batch_sentences > max_sentences > 0 or + new_batch_num_tokens > max_tokens > 0) + size_matches_with_bsz_mult = (new_batch_sentences < bsz_mult or + new_batch_sentences % bsz_mult == 0) + + if overflow: + tail_num_tokens = tail_max_tokens * \ + (new_batch_end - batches_ends_view[batches_count]) + tail_overflow = tail_num_tokens > max_tokens > 0 + # In case of a tail overflow finalize two batches + if tail_overflow: + batches_count += 1 + batches_ends_view[batches_count] = pos + tail_max_tokens = num_tokens_view[pos] + batch_start = batches_ends_view[batches_count] + batches_count += 1 + new_batch_max_tokens = tail_max_tokens + + if overflow or size_matches_with_bsz_mult: + batches_ends_view[batches_count] = new_batch_end + batch_max_tokens = new_batch_max_tokens + tail_max_tokens = 0 + if batches_ends_view[batches_count] != indices_len: + batches_count += 1 + # Memory and time-efficient split + return np.split(indices, batches_ends[:batches_count]) + + +@cython.boundscheck(False) +@cython.wraparound(False) +cpdef list batch_by_size_fn( np.ndarray[DTYPE_t, ndim=1] indices, num_tokens_fn, int64_t max_tokens, int64_t max_sentences, int32_t bsz_mult, ): - cdef int64_t sample_len = 0 - cdef list sample_lens = [] - cdef list batch = [] - cdef list batches = [] - cdef int64_t mod_len - cdef int64_t i - cdef int64_t idx - cdef int64_t num_tokens + cdef int32_t indices_len = indices.shape[0] + cdef np.ndarray[int64_t, ndim=1] num_tokens_vec = np.zeros(indices_len, + dtype=np.int64) cdef DTYPE_t[:] indices_view = indices - - for i in range(len(indices_view)): - idx = indices_view[i] - num_tokens = num_tokens_fn(idx) - sample_lens.append(num_tokens) - sample_len = max(sample_len, num_tokens) - - assert max_tokens <= 0 or sample_len <= max_tokens, ( - "sentence at index {} of size {} exceeds max_tokens " - "limit of {}!".format(idx, sample_len, max_tokens) - ) - num_tokens = (len(batch) + 1) * sample_len - - if _is_batch_full(len(batch), num_tokens, max_tokens, max_sentences): - mod_len = max( - bsz_mult * (len(batch) // bsz_mult), - len(batch) % bsz_mult, - ) - batches.append(batch[:mod_len]) - batch = batch[mod_len:] - sample_lens = sample_lens[mod_len:] - sample_len = max(sample_lens) if len(sample_lens) > 0 else 0 - batch.append(idx) - if len(batch) > 0: - batches.append(batch) - return batches + cdef DTYPE_t[:] num_tokens_vec_view = num_tokens_vec + cdef int64_t pos + for pos in range(indices_len): + num_tokens_vec[pos] = num_tokens_fn(indices_view[pos]) + return batch_by_size_vec(indices, num_tokens_vec, max_tokens, + max_sentences, bsz_mult,) cdef _find_valid_shape( diff --git a/fairseq/data/fairseq_dataset.py b/fairseq/data/fairseq_dataset.py index ed08c1ba20..23e6992dba 100644 --- a/fairseq/data/fairseq_dataset.py +++ b/fairseq/data/fairseq_dataset.py @@ -3,10 +3,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import logging import numpy as np import torch.utils.data from fairseq.data import data_utils +logger = logging.getLogger(__name__) + class EpochListening: """Mixin for receiving updates whenever the epoch increments.""" @@ -54,6 +57,11 @@ def num_tokens(self, index): enforce ``--max-tokens`` during batching.""" raise NotImplementedError + def num_tokens_vec(self, indices): + """Return the number of tokens for a set of positions defined by indices. + This value is used to enforce ``--max-tokens`` during batching.""" + raise NotImplementedError + def size(self, index): """Return an example's size as a float or tuple. This value is used when filtering a dataset with ``--max-positions``.""" @@ -129,9 +137,15 @@ def adjust_bsz(bsz, num_tokens): ] ) + try: + num_tokens_vec = self.num_tokens_vec(indices).astype('int64') + except NotImplementedError: + num_tokens_vec = None + return data_utils.batch_by_size( indices, num_tokens_fn=self.num_tokens, + num_tokens_vec=num_tokens_vec, max_tokens=max_tokens, max_sentences=max_sentences, required_batch_size_multiple=required_batch_size_multiple, diff --git a/fairseq/data/language_pair_dataset.py b/fairseq/data/language_pair_dataset.py index 62e7109b33..8858cec84e 100644 --- a/fairseq/data/language_pair_dataset.py +++ b/fairseq/data/language_pair_dataset.py @@ -408,6 +408,14 @@ def num_tokens(self, index): self.tgt_sizes[index] if self.tgt_sizes is not None else 0, ) + def num_tokens_vec(self, indices): + """Return the number of tokens for a set of positions defined by indices. + This value is used to enforce ``--max-tokens`` during batching.""" + sizes = self.src_sizes[indices] + if self.tgt_sizes is not None: + sizes = np.maximum(sizes, self.tgt_sizes[indices]) + return sizes + def size(self, index): """Return an example's size as a float or tuple. This value is used when filtering a dataset with ``--max-positions``.""" diff --git a/fairseq/data/multilingual/sampled_multi_dataset.py b/fairseq/data/multilingual/sampled_multi_dataset.py index 599f3a862b..f74ec18141 100644 --- a/fairseq/data/multilingual/sampled_multi_dataset.py +++ b/fairseq/data/multilingual/sampled_multi_dataset.py @@ -238,6 +238,11 @@ def __getitem__(self, index): def num_tokens(self, index): return self.sizes[index].max() + def num_tokens_vec(self, indices): + sizes_vec = self.sizes[np.array(indices)] + # max across all dimensions but first one + return np.amax(sizes_vec, axis=tuple(range(1, len(sizes_vec.shape)))) + def size(self, index): return self.sizes[index] diff --git a/tests/test_data_utils.py b/tests/test_data_utils.py new file mode 100644 index 0000000000..2acfc8dc18 --- /dev/null +++ b/tests/test_data_utils.py @@ -0,0 +1,136 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import numpy as np +from fairseq.data.data_utils_fast import batch_by_size_fn +from fairseq.data.data_utils_fast import batch_by_size_vec + + +class TestBatchBySize(unittest.TestCase): + @classmethod + def batch_by_size_baseline( + cls, + indices, + num_tokens_vec, + max_tokens, + max_sentences, + bsz_mult, + ): + """Simple, reliable and slow implementation of batch by size """ + batches = [] + start = 0 + while start < len(indices): + for end in range(start + 1, len(indices) + 1): + max_val = max(num_tokens_vec[pos] for pos in range(start, end)) + sent_count = end - start + num_tokens = max_val * sent_count + overflow = num_tokens > max_tokens > 0 or sent_count > max_sentences > 0 + terminate = overflow or end == len(indices) + if overflow: + sent_count -= 1 + if terminate: + if sent_count > bsz_mult: + sent_count = sent_count - sent_count % bsz_mult + batches.append(indices[start : start + sent_count]) + start = start + sent_count + break + return batches + + @classmethod + def _get_error_message( + cls, max_sentences, max_tokens, bsz_mult, num_tokens_vec, validation, results + ): + return f"""Reference batch_by_size implementation should produce + same output as the baseline method. + Params: + max_sentences={max_sentences}, + max_tokens={max_tokens}, + bsz_mult={bsz_mult}, + num_tokens_vec={num_tokens_vec}, + expected_batches={validation}, + returned_batches={results}""" + + def _compare_results( + self, + indices_len, + batch_by_size_impl, + max_sentences, + max_tokens, + bsz_mult, + num_tokens_vec, + ): + indices = np.array(list(range(indices_len))) + validation = self.batch_by_size_baseline( + indices, + num_tokens_vec, + max_tokens=max_tokens, + max_sentences=max_sentences, + bsz_mult=bsz_mult, + ) + results = batch_by_size_impl( + indices, + num_tokens_vec, + max_tokens=max_tokens, + max_sentences=max_sentences, + bsz_mult=bsz_mult, + ) + error_msg = self._get_error_message( + max_sentences, max_tokens, bsz_mult, num_tokens_vec, validation, results + ) + self.assertEqual(len(validation), len(results), error_msg) + for first, second in zip(validation, results): + self.assertTrue(np.array_equal(first, second), error_msg) + + def _run_compare_with_baseline_sweep(self, batch_by_size_impl): + """Compare reference batch_by_size implementation with batch_by_size_baseline + across a dense grid of hyperparam values""" + MAX_MAX_TOKENS = 10 + NUM_TOKENS_VECS_COUNT = 5 + for indices_len in [10, 11]: # try odd and even len of indices + for max_sentences in range(0, indices_len + 2): + for max_tokens in range(0, MAX_MAX_TOKENS): + for bsz_mult in range(1, max(MAX_MAX_TOKENS, indices_len) + 2): + for _ in range(NUM_TOKENS_VECS_COUNT): + num_tokens_vec = np.random.randint( + 0, max_tokens + 1, size=indices_len + ) + self._compare_results( + indices_len, + batch_by_size_impl, + max_sentences, + max_tokens, + bsz_mult, + num_tokens_vec, + ) + + +class TestBatchBySizeVec(TestBatchBySize): + def test_compare_with_baseline(self): + self._run_compare_with_baseline_sweep(batch_by_size_vec) + + +class TestBatchBySizeFn(TestBatchBySize): + def test_compare_with_baseline(self): + def batch_by_size_fn_wrapper( + indices, + num_tokens_vec, + max_tokens, + max_sentences, + bsz_mult, + ): + def num_tokens_fn(idx): + return num_tokens_vec[idx] + + return batch_by_size_fn( + indices, num_tokens_fn, max_tokens, max_sentences, bsz_mult + ) + + self._run_compare_with_baseline_sweep(batch_by_size_fn_wrapper) + + +if __name__ == "__main__": + unittest.main() From e2e80c6f2dca01dd8c04b3e5b0b356abf4b429cf Mon Sep 17 00:00:00 2001 From: Samuel Marks <807580+SamuelMarks@users.noreply.github.com> Date: Tue, 29 Dec 2020 15:53:03 -0800 Subject: [PATCH 135/774] Rename "Arguments:" to "Args:" (#3060) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: I've written custom parsers and emitters for everything from docstrings to classes and functions. However, I recently came across an issue when I was parsing/generating from the TensorFlow—and now PyTorch—codebases: inconsistent use of `Args:` and `Arguments:` in its docstrings. It is easy enough to extend my parsers to support both variants, however it looks like `Arguments:` is wrong anyway, as per: - https://google.github.io/styleguide/pyguide.html#doc-function-args @ [`ddccc0f`](https://github.com/google/styleguide/blob/ddccc0f/pyguide.md) - https://chromium.googlesource.com/chromiumos/docs/+/master/styleguide/python.md#describing-arguments-in-docstrings @ [`9fc0fc0`](https://chromium.googlesource.com/chromiumos/docs/+/9fc0fc0/styleguide/python.md) - https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html @ [`c0ae8e3`](https://github.com/sphinx-contrib/napoleon/blob/c0ae8e3/docs/source/example_google.rst) Therefore, only `Args:` is valid. This PR replaces them throughout the codebase. PS: For related PRs, see pytorch/pytorch/pull/49736 Pull Request resolved: https://github.com/pytorch/fairseq/pull/3060 Reviewed By: ngoyal2707 Differential Revision: D25692815 Pulled By: myleott fbshipit-source-id: 461543ad3e2acd1fc475da799495841be73250bd --- fairseq/optim/adafactor.py | 4 ++-- fairseq/optim/adam.py | 4 ++-- fairseq/optim/adamax.py | 4 ++-- fairseq/optim/composite.py | 2 +- fairseq/optim/fused_adam.py | 4 ++-- fairseq/optim/nag.py | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fairseq/optim/adafactor.py b/fairseq/optim/adafactor.py index 91745ce10e..c969b9fbc0 100644 --- a/fairseq/optim/adafactor.py +++ b/fairseq/optim/adafactor.py @@ -76,7 +76,7 @@ class Adafactor(torch.optim.Optimizer): schedule you should set `scale_parameter=False` and `relative_step=False`. - Arguments: + Args: params (iterable): iterable of parameters to optimize or dicts defining parameter groups lr (float, optional): external learning rate (default: None) @@ -168,7 +168,7 @@ def _approx_sq_grad(self, exp_avg_sq_row, exp_avg_sq_col): def step(self, closure=None): """Performs a single optimization step. - Arguments: + Args: closure (callable, optional): A closure that reevaluates the model and returns the loss. """ diff --git a/fairseq/optim/adam.py b/fairseq/optim/adam.py index 1a4f213707..f73804718a 100644 --- a/fairseq/optim/adam.py +++ b/fairseq/optim/adam.py @@ -103,7 +103,7 @@ class Adam(torch.optim.Optimizer): It has been proposed in `Adam: A Method for Stochastic Optimization`_. - Arguments: + Args: params (iterable): iterable of parameters to optimize or dicts defining parameter groups lr (float, optional): learning rate (default: 1e-3) @@ -146,7 +146,7 @@ def supports_flat_params(self): def step(self, closure=None): """Performs a single optimization step. - Arguments: + Args: closure (callable, optional): A closure that reevaluates the model and returns the loss. """ diff --git a/fairseq/optim/adamax.py b/fairseq/optim/adamax.py index 577a688166..98ff8ad7ad 100644 --- a/fairseq/optim/adamax.py +++ b/fairseq/optim/adamax.py @@ -53,7 +53,7 @@ class Adamax(torch.optim.Optimizer): Compared to the version in PyTorch, this version implements a fix for weight decay. - Arguments: + Args: params (iterable): iterable of parameters to optimize or dicts defining parameter groups lr (float, optional): learning rate (default: 2e-3) @@ -107,7 +107,7 @@ def supports_flat_params(self): def step(self, closure=None): """Performs a single optimization step. - Arguments: + Args: closure (callable, optional): A closure that reevaluates the model and returns the loss. """ diff --git a/fairseq/optim/composite.py b/fairseq/optim/composite.py index 51e6999368..1a581bc010 100644 --- a/fairseq/optim/composite.py +++ b/fairseq/optim/composite.py @@ -134,7 +134,7 @@ def supports_flat_params(self): def step(self, closure=None, groups=None): """Performs a single optimization step. - Arguments: + Args: closure (callable, optional): A closure that reevaluates the model and returns the loss. """ diff --git a/fairseq/optim/fused_adam.py b/fairseq/optim/fused_adam.py index 1780f9c0bb..e2b8e1bcd1 100644 --- a/fairseq/optim/fused_adam.py +++ b/fairseq/optim/fused_adam.py @@ -47,7 +47,7 @@ class FusedAdamV1(torch.optim.Optimizer): Compared to the original version in Apex, the fairseq version casts grads and params to FP32 internally to support ``--memory-efficient-fp16``. - Arguments: + Args: params (iterable): iterable of parameters to optimize or dicts defining parameter groups. lr (float, optional): learning rate. (default: 1e-3) @@ -113,7 +113,7 @@ def supports_step_with_scale(self): def step(self, closure=None, grads=None, scale=1.0, grad_norms=None): """Performs a single optimization step. - Arguments: + Args: closure (callable, optional): A closure that reevaluates the model and returns the loss. grads (list of tensors, optional): weight gradient to use for the diff --git a/fairseq/optim/nag.py b/fairseq/optim/nag.py index 4f652fe6d3..c30a6c0fb1 100644 --- a/fairseq/optim/nag.py +++ b/fairseq/optim/nag.py @@ -62,7 +62,7 @@ def supports_flat_params(self): def step(self, closure=None): """Performs a single optimization step. - Arguments: + Args: closure (callable, optional): A closure that reevaluates the model and returns the loss. """ From 48a607527a8c2435c63795cca9a05348ef6e1f9d Mon Sep 17 00:00:00 2001 From: Xu Song Date: Tue, 29 Dec 2020 15:53:06 -0800 Subject: [PATCH 136/774] Reorganize self.emb_layer_norm (#3057) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Reorganize `self.emb_layer_norm` in order to keep right order while `print(model)` ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3057 Reviewed By: ngoyal2707 Differential Revision: D25692819 Pulled By: myleott fbshipit-source-id: d371955152e7fcb9e356351311f194a2418ca4b5 --- fairseq/modules/transformer_sentence_encoder.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fairseq/modules/transformer_sentence_encoder.py b/fairseq/modules/transformer_sentence_encoder.py index 7a5dcbdde3..6e9c32f467 100644 --- a/fairseq/modules/transformer_sentence_encoder.py +++ b/fairseq/modules/transformer_sentence_encoder.py @@ -145,6 +145,11 @@ def __init__( else None ) + if encoder_normalize_before: + self.emb_layer_norm = LayerNorm(self.embedding_dim, export=export) + else: + self.emb_layer_norm = None + if self.layerdrop > 0.0: self.layers = LayerDropModuleList(p=self.layerdrop) else: @@ -167,11 +172,6 @@ def __init__( ] ) - if encoder_normalize_before: - self.emb_layer_norm = LayerNorm(self.embedding_dim, export=export) - else: - self.emb_layer_norm = None - # Apply initialization of model params after building the model if self.apply_bert_init: self.apply(init_bert_params) From bff7f85206f6f64b9455035893d44d66b98e33b0 Mon Sep 17 00:00:00 2001 From: Sam Shleifer Date: Wed, 30 Dec 2020 12:57:02 -0800 Subject: [PATCH 137/774] fastseq ngram blocking (#1509) Summary: Command: ```bash fairseq-generate \ ~myleott/data/data-bin/wmt16_en_de_bpe32k/ \ --path /checkpoint/myleott/s3/models/wmt16.en-de.joined-dict.transformer/model.pt \ --beam 4 --remove-bpe --lenpen 0.6 --batch-size 256 --no-repeat-ngram-size 3 \ --gen-subset test --fp16 ``` master/devfair: 297.8s (10.08 sentences/s, 286.47 tokens/s) branch/devfair: 31.9s (94.27 sentences/s, 2678.66 tokens/s) master/v100: 227.4s (13.21 sentences/s, 375.24 tokens/s) branch/v100: 13.1s (228.68 sentences/s, 6497.99 tokens/s) (all BLEU4=29.17) ### ToDo: - tests ### Future Work - test other fastseq proposed improvements. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1509 Reviewed By: myleott Differential Revision: D25587857 Pulled By: sshleifer fbshipit-source-id: d42af5c50e3f94c90e878f92da5ce5ef3fc8b988 --- fairseq/clib/cuda/ngram_repeat_block_cuda.cpp | 47 ++++++ .../cuda/ngram_repeat_block_cuda_kernel.cu | 76 +++++++++ fairseq/ngram_repeat_block.py | 150 ++++++++++++++++++ fairseq/sequence_generator.py | 77 ++------- setup.py | 10 +- tests/test_sequence_generator.py | 128 +++++++++++++-- 6 files changed, 411 insertions(+), 77 deletions(-) create mode 100644 fairseq/clib/cuda/ngram_repeat_block_cuda.cpp create mode 100644 fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu create mode 100644 fairseq/ngram_repeat_block.py diff --git a/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp b/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp new file mode 100644 index 0000000000..4199cd6ea8 --- /dev/null +++ b/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp @@ -0,0 +1,47 @@ +/* +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. +*/ + +#include +#include + +/* +CPP Binding for CUDA OP +*/ + +// CUDA forward declarations +torch::Tensor ngram_repeat_block_cuda_forward(torch::Tensor tokens, + torch::Tensor lprobs, int bsz, + int step, int beam_size, + int no_repeat_ngram_size); + +#define CHECK_CUDA(x) \ + TORCH_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") +#define CHECK_CONTIGUOUS(x) \ + TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") +#define CHECK_INPUT(x) \ + CHECK_CUDA(x); \ + CHECK_CONTIGUOUS(x) + +// Input check and call to CUDA OP +// Backward method not required +torch::Tensor ngram_repeat_block_forward(torch::Tensor tokens, + torch::Tensor lprobs, int bsz, + int step, int beam_size, + int no_repeat_ngram_size) { + CHECK_INPUT(tokens); + CHECK_INPUT(lprobs); + assert(bsz > 0); + assert(step >= 0); + assert(beam_size > 0); + assert(no_repeat_ngram_size > 0); + + return ngram_repeat_block_cuda_forward(tokens, lprobs, bsz, step, beam_size, + no_repeat_ngram_size); +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("forward", &ngram_repeat_block_forward, + "No Repeat Ngram Block forward (CUDA)"); +} diff --git a/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu b/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu new file mode 100644 index 0000000000..b458b0916a --- /dev/null +++ b/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu @@ -0,0 +1,76 @@ +/* +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. +*/ + +/* +Kernel implementation for blocking repeated n-grams. +*/ + +#include +#include +#include +#include +#include + +// Ban repeated ngrams of length = 'no_repeat_ngram_size' +__global__ void banRepeatedTokens(long* __restrict__ tokens, + float* __restrict__ lprobs, + int max_predict_len, int vocab_size, + int no_repeat_ngram_size) { + auto row = blockIdx.x; + auto col = threadIdx.x; + auto start = row * (max_predict_len) + col; + // Each thread compares ngram starting from + // thread index with final ngram starting from + // step - no_repeat_ngram_size +2 + auto check_start_pos = blockDim.x; + auto lprob_start = row * vocab_size; + bool is_banned = true; + extern __shared__ long tokens_shm[]; + tokens_shm[col] = tokens[start]; + if (col == blockDim.x - 1) { + for (int i=1; i(); + auto lprob_ptr = lprobs.data_ptr(); + int blocks = bsz * beam_size; + int shared_mem_size = (step + 1) * sizeof(long); + + // Launching N blocks where N is number of samples in a batch (beams*bsz) + // Launching T threads where T is number of previous ngrams in a sample + // Allocating shared mem per block for fastser access of input tokens since + // each token will be accessed N times to compare with current Ngram where + // N is Ngram size. + banRepeatedTokens<<>>( + token_ptr, lprob_ptr, max_predict_len, vocab_size, no_repeat_ngram_size); + return lprobs; +} diff --git a/fairseq/ngram_repeat_block.py b/fairseq/ngram_repeat_block.py new file mode 100644 index 0000000000..856c9e64f7 --- /dev/null +++ b/fairseq/ngram_repeat_block.py @@ -0,0 +1,150 @@ +# Originally from Microsoft Corporation. +# Licensed under the MIT License. + +""" Wrapper for ngram_repeat_block cuda extension """ +import torch +from torch import nn + +import math +from typing import Dict, List, Optional +import warnings + +try: + from fairseq import ngram_repeat_block_cuda + + EXTENSION_BUILT = True +except ImportError: + EXTENSION_BUILT = False + + +def is_cuda_extension_usable() -> bool: + """Check whether ngram_repeat_block_cuda is built properly""" + if not EXTENSION_BUILT: + return False + bsz = 2 + tokens = torch.tensor([[4, 4, 3, 2], [1, 2, 3, 4]], dtype=torch.long, device="cuda") + lprobs = torch.rand((8, 12), device="cuda") + try: + outputs = ngram_repeat_block_cuda.forward(tokens, lprobs, bsz, 3, 4, 3) + outputs = outputs + 4 # This line breaks if the extension is built incorrectly. + return True + except RuntimeError: + warnings.warn( + "NGramRepeatBlock extension must be rebuilt." + 'Run TORCH_CUDA_ARCH_LIST="6.0;6.1;7.0" python setup.py build_ext --inplace' + ) + return False + + +class NGramRepeatBlock(nn.Module): + """ Wrapper class for calling ngram_repeat_block cuda extension """ + + def __init__(self, no_repeat_ngram_size: int, use_extension: bool = True): + super().__init__() + self.use_extension = is_cuda_extension_usable() if use_extension else False + self.no_repeat_ngram_size = no_repeat_ngram_size + + def reset_parameters(self): + pass + + @torch.jit.unused + def call_cuda_extension( + self, + tokens, + lprobs, + bsz: int, + beam_size: int, + step: int, + ): + return ngram_repeat_block_cuda.forward( + tokens, lprobs, bsz, step, beam_size, self.no_repeat_ngram_size + ) + + def forward( + self, + tokens, + lprobs, + bsz: int, + beam_size: int, + step: int, + ): + """ + Args: + tokens(Tensor): Input tokens(Bsz*beam, seq_len) + lprobs(Tensor): likelihood probability, + Expected to be updated in place.(Bsz*beam, vocab_size) + bsz(int): batch size + step(int): current step + beam_size(int): beam size + no_repeat_ngram_size(int): Ngram size + """ + msg = f"expected {bsz *beam_size} got" + assert tokens.size(0) == bsz * beam_size, f"{msg} {tokens.size(0)}" + assert lprobs.size(0) == bsz * beam_size, f"{msg} {lprobs.size(0)}" + if self.use_extension: + return self.call_cuda_extension(tokens, lprobs, bsz, beam_size, step) + + else: + return self._no_repeat_ngram( + tokens, + lprobs, + bsz, + beam_size, + step, + ) + + def _no_repeat_ngram(self, tokens, lprobs, bsz: int, beam_size: int, step: int): + """For each hypothesis generate a list of previous ngrams and set associated lprobs to -inf""" + gen_ngrams: List[Dict[str, List[int]]] = [ + torch.jit.annotate(Dict[str, List[int]], {}) + for bbsz_idx in range(bsz * beam_size) + ] + cpu_tokens = tokens.cpu() + for bbsz_idx in range(bsz * beam_size): + gen_tokens: List[int] = cpu_tokens[bbsz_idx].tolist() + for ngram in self.transpose_list( + [gen_tokens[i:] for i in range(self.no_repeat_ngram_size)] + ): + key = ",".join([str(x) for x in ngram[:-1]]) + gen_ngrams[bbsz_idx][key] = gen_ngrams[bbsz_idx].get( + key, torch.jit.annotate(List[int], []) + ) + [ngram[-1]] + if step + 2 - self.no_repeat_ngram_size >= 0: + # no banned tokens if we haven't generated no_repeat_ngram_size tokens yet + banned_tokens = [ + self.calculate_banned_tokens( + tokens, step, gen_ngrams, self.no_repeat_ngram_size, bbsz_idx + ) + for bbsz_idx in range(bsz * beam_size) + ] + else: + banned_tokens = [ + torch.jit.annotate(List[int], []) for bbsz_idx in range(bsz * beam_size) + ] + for bbsz_idx in range(bsz * beam_size): + lprobs[bbsz_idx][ + torch.tensor(banned_tokens[bbsz_idx]).long() + ] = torch.tensor(-math.inf).to(lprobs) + return lprobs + + @staticmethod + def calculate_banned_tokens( + tokens, + step: int, + gen_ngrams: List[Dict[str, List[int]]], + no_repeat_ngram_size: int, + bbsz_idx: int, + ): + tokens_list: List[int] = tokens[ + bbsz_idx, step + 2 - no_repeat_ngram_size : step + 1 + ].tolist() + # before decoding the next token, prevent decoding of ngrams that have already appeared + ngram_index = ",".join([str(x) for x in tokens_list]) + return gen_ngrams[bbsz_idx].get(ngram_index, torch.jit.annotate(List[int], [])) + + @staticmethod + def transpose_list(l: List[List[int]]): + # GeneratorExp aren't supported in TS so ignoring the lint + min_len = min([len(x) for x in l]) # noqa + l2 = [[row[i] for row in l] for i in range(min_len)] + return l2 diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index bd46f9e5b9..b0249888ce 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -12,6 +12,7 @@ from fairseq.data import data_utils from fairseq.models import FairseqIncrementalDecoder from torch import Tensor +from fairseq.ngram_repeat_block import NGramRepeatBlock class SequenceGenerator(nn.Module): @@ -84,7 +85,10 @@ def __init__( self.unk_penalty = unk_penalty self.temperature = temperature self.match_source_len = match_source_len + self.no_repeat_ngram_size = no_repeat_ngram_size + self.repeat_ngram_blocker = NGramRepeatBlock(no_repeat_ngram_size) + assert temperature > 0, "--temperature must be greater than 0" self.search = ( @@ -278,7 +282,12 @@ def _generate( cand_size = 2 * beam_size # 2 x beam size in case half are EOS # offset arrays for converting between different indexing schemes - bbsz_offsets = (torch.arange(0, bsz) * beam_size).unsqueeze(1).type_as(tokens).to(src_tokens.device) + bbsz_offsets = ( + (torch.arange(0, bsz) * beam_size) + .unsqueeze(1) + .type_as(tokens) + .to(src_tokens.device) + ) cand_offsets = torch.arange(0, cand_size).type_as(tokens).to(src_tokens.device) reorder_state: Optional[Tensor] = None @@ -365,7 +374,7 @@ def _generate( self.search.set_src_lengths(src_lengths) if self.no_repeat_ngram_size > 0: - lprobs = self._no_repeat_ngram(tokens, lprobs, bsz, beam_size, step) + lprobs = self.repeat_ngram_blocker(tokens, lprobs, bsz, beam_size, step) # Shape: (batch, cand_size) cand_scores, cand_indices, cand_beams = self.search.step( @@ -709,62 +718,6 @@ def is_finished( return True return False - def calculate_banned_tokens( - self, - tokens, - step: int, - gen_ngrams: List[Dict[str, List[int]]], - no_repeat_ngram_size: int, - bbsz_idx: int, - ): - tokens_list: List[int] = tokens[ - bbsz_idx, step + 2 - no_repeat_ngram_size : step + 1 - ].tolist() - # before decoding the next token, prevent decoding of ngrams that have already appeared - ngram_index = ",".join([str(x) for x in tokens_list]) - return gen_ngrams[bbsz_idx].get(ngram_index, torch.jit.annotate(List[int], [])) - - def transpose_list(self, l: List[List[int]]): - # GeneratorExp aren't supported in TS so ignoring the lint - min_len = min([len(x) for x in l]) # noqa - l2 = [[row[i] for row in l] for i in range(min_len)] - return l2 - - def _no_repeat_ngram(self, tokens, lprobs, bsz: int, beam_size: int, step: int): - # for each beam and batch sentence, generate a list of previous ngrams - gen_ngrams: List[Dict[str, List[int]]] = [ - torch.jit.annotate(Dict[str, List[int]], {}) - for bbsz_idx in range(bsz * beam_size) - ] - cpu_tokens = tokens.cpu() - for bbsz_idx in range(bsz * beam_size): - gen_tokens: List[int] = cpu_tokens[bbsz_idx].tolist() - for ngram in self.transpose_list( - [gen_tokens[i:] for i in range(self.no_repeat_ngram_size)] - ): - key = ",".join([str(x) for x in ngram[:-1]]) - gen_ngrams[bbsz_idx][key] = gen_ngrams[bbsz_idx].get( - key, torch.jit.annotate(List[int], []) - ) + [ngram[-1]] - - if step + 2 - self.no_repeat_ngram_size >= 0: - # no banned tokens if we haven't generated no_repeat_ngram_size tokens yet - banned_tokens = [ - self.calculate_banned_tokens( - tokens, step, gen_ngrams, self.no_repeat_ngram_size, bbsz_idx - ) - for bbsz_idx in range(bsz * beam_size) - ] - else: - banned_tokens = [ - torch.jit.annotate(List[int], []) for bbsz_idx in range(bsz * beam_size) - ] - for bbsz_idx in range(bsz * beam_size): - lprobs[bbsz_idx][ - torch.tensor(banned_tokens[bbsz_idx]).long() - ] = torch.tensor(-math.inf).to(lprobs) - return lprobs - class EnsembleModel(nn.Module): """A wrapper around an ensemble of models.""" @@ -867,7 +820,9 @@ def forward_decoder( return avg_probs, avg_attn @torch.jit.export - def reorder_encoder_out(self, encoder_outs: Optional[List[Dict[str, List[Tensor]]]], new_order): + def reorder_encoder_out( + self, encoder_outs: Optional[List[Dict[str, List[Tensor]]]], new_order + ): """ Reorder encoder output according to *new_order*. @@ -903,7 +858,9 @@ def reorder_incremental_state( class SequenceGeneratorWithAlignment(SequenceGenerator): - def __init__(self, models, tgt_dict, left_pad_target=False, print_alignment="hard", **kwargs): + def __init__( + self, models, tgt_dict, left_pad_target=False, print_alignment="hard", **kwargs + ): """Generates translations of a given source sentence. Produces alignments following "Jointly Learning to Align and diff --git a/setup.py b/setup.py index 1954298034..08fe0dcccc 100644 --- a/setup.py +++ b/setup.py @@ -109,7 +109,6 @@ def include_dirs(self, dirs): ) ] ) - if "CUDA_HOME" in os.environ: extensions.extend( [ @@ -119,7 +118,14 @@ def include_dirs(self, dirs): "fairseq/clib/libnat_cuda/edit_dist.cu", "fairseq/clib/libnat_cuda/binding.cpp", ], - ) + ), + cpp_extension.CppExtension( + "fairseq.ngram_repeat_block_cuda", + sources=[ + "fairseq/clib/cuda/ngram_repeat_block_cuda.cpp", + "fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu", + ], + ), ] ) cmdclass["build_ext"] = cpp_extension.BuildExtension diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index c890b655ff..afbdfb6c2c 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -6,6 +6,9 @@ import argparse import tempfile import unittest +import math +import numpy as np + import tests.utils as test_utils import torch @@ -13,6 +16,7 @@ from fairseq.data.dictionary import Dictionary from fairseq.models.transformer import TransformerModel from fairseq.sequence_generator import EnsembleModel, SequenceGenerator +from fairseq.ngram_repeat_block import NGramRepeatBlock from fairseq.tasks.fairseq_task import LegacyFairseqTask @@ -41,7 +45,7 @@ def get_dummy_dictionary(vocab_size=DEFAULT_TEST_VOCAB_SIZE): dummy_dict = Dictionary() # add dummy symbol to satisfy vocab size for id, _ in enumerate(range(vocab_size)): - dummy_dict.add_symbol("{}".format(id), 1000) + dummy_dict.add_symbol("{}".format(id), n=1000) return dummy_dict @@ -107,30 +111,27 @@ def _test_save_and_load(self, scripted_module): torch.jit.load(f.name) -class TestJitSequeneceGenerator(TestJitSequenceGeneratorBase): - @unittest.skipIf( - torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" - ) +JIT_MSG = "Targeting OSS scriptability for the 1.6 release" + + +@unittest.skipIf(torch.__version__ < "1.6.0", JIT_MSG) +class TestJitSequenceGenerator(TestJitSequenceGeneratorBase): def test_export_transformer(self): model = self.transformer_model torch.jit.script(model) - @unittest.skipIf( - torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" - ) def test_ensemble_sequence_generator(self): model = self.transformer_model generator = SequenceGenerator( - [model], self.task.tgt_dict, beam_size=2, no_repeat_ngram_size=2 + [model], + self.task.tgt_dict, + beam_size=2, + no_repeat_ngram_size=2, + max_len_b=10, ) scripted_model = torch.jit.script(generator) self._test_save_and_load(scripted_model) - -class TestJitEnsemble(TestJitSequenceGeneratorBase): - @unittest.skipIf( - torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" - ) def test_export_ensemble_model(self): model = self.transformer_model ensemble_models = EnsembleModel([model]) @@ -185,7 +186,7 @@ def assertTensorEqual(self, t1, t2): self.assertEqual(t1.ne(t2).long().sum(), 0) -class TestSequeneceGenerator(TestSequenceGeneratorBase): +class TestSequenceGenerator(TestSequenceGeneratorBase): def setUp(self): ( self.tgt_dict, @@ -326,6 +327,103 @@ def test_generation_with_additional_input(self): self.assertHypoScore(hypos[0][0], [0.9, 1.0]) +@unittest.skipUnless(torch.cuda.is_available(), "") +class TestRepeatNgramBlocking(TestSequenceGeneratorBase): + @classmethod + def setUpClass(cls): + ( + cls.tgt_dict, + cls.w1, + cls.w2, + src_tokens, + src_lengths, + cls.model, + ) = test_utils.sequence_generator_setup() + return cls + + def test_finds_repetitive_tokens(self): + bsz, vocab_size, beam_size, step = 2, 4, 1, 3 + generated_tok = torch.tensor( + [[2, 2, 2, 2], [3, 3, 3, 3]], dtype=torch.long, device="cuda" + ) + lprobs = torch.zeros((beam_size * bsz, vocab_size), device="cuda") + desired_result = lprobs.new_tensor( + [[0.0, 0.0, -math.inf, 0.0], [0.0, 0.0, 0.0, -math.inf]] + ) + + cuda_ext_result, baseline_result = self._compare_cuda_ext_to_default_implem( + bsz, beam_size, generated_tok, lprobs, step, 2 + ) + self.assertTensorEqual(cuda_ext_result, desired_result) + self.assertTensorEqual(baseline_result, desired_result) + + @unittest.skipIf(torch.__version__ < "1.6.0", JIT_MSG) + def test_jit_no_extension(self): + bsz, vocab_size, beam_size, step = 2, 4, 1, 3 + generated_tok = torch.tensor( + [[2, 2, 2, 2], [3, 3, 3, 3]], dtype=torch.long, device="cuda" + ) + lprobs = torch.zeros((beam_size * bsz, vocab_size), device="cuda") + blocker = NGramRepeatBlock(2, use_extension=False) + base_result = blocker(generated_tok, lprobs.clone(), bsz, beam_size, step) + scripted_blocker = torch.jit.script(blocker) + jit_result = scripted_blocker( + generated_tok, lprobs.clone(), bsz, beam_size, step + ) + self.assertTensorEqual(base_result, jit_result) + + def test_ngram_blocking_same_as_default_implem(self): + """Test that cuda extension returns same things as default impl in many settings.""" + vocab_size = 4 + step = 6 + for _ in range(2): + block_param = np.random.choice([1, 2, 3, 4]) + batch_size = np.random.randint(1, 8) + beam_size = np.random.choice([1, 2, 4, 8]) + lprobs = torch.zeros((beam_size * batch_size, vocab_size), device="cuda") + + generated_tok = torch.tensor( + np.random.randint( + 0, vocab_size, size=(batch_size * beam_size, step + 1) + ), + device="cuda", + dtype=torch.long, + ) + self._compare_cuda_ext_to_default_implem( + batch_size, + beam_size, + generated_tok, + lprobs, + step, + block_param, + ) + + def _compare_cuda_ext_to_default_implem( + self, bsz, beam_size, generated_tok, lprobs, step, block_param + ): + """Assert that cuda extension and default implem return the same thing.""" + blocker = NGramRepeatBlock(block_param) + assert blocker.use_extension, "Extension not compiled" + cuda_ext_result = blocker( + generated_tok, + lprobs.clone(), + bsz, + beam_size, + step, + ) + blocker.use_extension = False + baseline_result = blocker( + generated_tok, + lprobs.clone(), + bsz, + beam_size, + step, + ) + self.assertTensorEqual(cuda_ext_result, baseline_result) + blocker.use_extension = True + return cuda_ext_result, baseline_result + + class TestDiverseBeamSearch(TestSequenceGeneratorBase): def setUp(self): # construct dummy dictionary From 01fcec5fc3dcc695c59cf3fdf7f178c174edcf0d Mon Sep 17 00:00:00 2001 From: Wei Ho Date: Wed, 30 Dec 2020 20:15:58 -0800 Subject: [PATCH 138/774] Fix incorrect local cache for checkpoint_last.pt when training is restarted on the same host Reviewed By: myleott Differential Revision: D25719057 fbshipit-source-id: 2bf7dd93b6d223804da0326a0ed347e5e353f1f0 --- fairseq/checkpoint_utils.py | 37 ++++++++++++++++++++++++++++++++++--- fairseq/trainer.py | 11 +++++++---- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 36a28f35dc..79c811424a 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -226,9 +226,40 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): return extra_state, epoch_itr -def load_checkpoint_to_cpu(path, arg_overrides=None): - """Loads a checkpoint to CPU (with upgrading for backward compatibility).""" - with open(PathManager.get_local_path(path), "rb") as f: +def load_checkpoint_to_cpu(path, arg_overrides=None, load_on_all_ranks=False): + """Loads a checkpoint to CPU (with upgrading for backward compatibility). + + If doing single-GPU training or if the checkpoint is only being loaded by at + most one process on each node (current default behavior is for only rank 0 + to read the checkpoint from disk), load_on_all_ranks should be False to + avoid errors from torch.distributed not having been initialized or + torch.distributed.barrier() hanging. + + If all processes on each node may be loading the checkpoint + simultaneously, load_on_all_ranks should be set to True to avoid I/O + conflicts. + + There's currently no support for > 1 but < all processes loading the + checkpoint on each node. + """ + local_path = PathManager.get_local_path(path) + # The locally cached file returned by get_local_path() may be stale for + # remote files that are periodically updated/overwritten (ex: + # checkpoint_last.pt) - so we remove the local copy, sync across processes + # (if needed), and then download a fresh copy. + if local_path != path and PathManager.path_requires_pathmanager(path): + try: + os.remove(local_path) + except FileNotFoundError: + # With potentially multiple processes removing the same file, the + # file being missing is benign (missing_ok isn't available until + # Python 3.8). + pass + if load_on_all_ranks: + torch.distributed.barrier() + local_path = PathManager.get_local_path(path) + + with open(local_path, "rb") as f: state = torch.load(f, map_location=torch.device("cpu")) if "args" in state and state["args"] is not None and arg_overrides is not None: diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 8f42743ac3..a6c1013635 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -294,6 +294,7 @@ def load_checkpoint( extra_state, self._optim_history, last_optim_state = None, [], None logger.info(f"Preparing to load checkpoint {filename}") + is_distributed = self.data_parallel_world_size > 1 bexists = PathManager.isfile(filename) if bexists: load_on_all_ranks = ( @@ -304,7 +305,9 @@ def load_checkpoint( ) if load_on_all_ranks or self.data_parallel_rank == 0: - state = checkpoint_utils.load_checkpoint_to_cpu(filename) + state = checkpoint_utils.load_checkpoint_to_cpu( + filename, load_on_all_ranks=load_on_all_ranks + ) last_optim_state = state.get("last_optimizer_state", None) # If doing zero_sharding, do not broadcast global optimizer @@ -314,14 +317,14 @@ def load_checkpoint( not load_on_all_ranks and self.cfg.distributed_training.zero_sharding == "os" and "last_optimizer_state" in state - and self.data_parallel_world_size > 1 + and is_distributed ): state["last_optimizer_state"] = "SHARDED" else: last_optim_state = None state = None - if self.data_parallel_world_size > 1 and not load_on_all_ranks: + if is_distributed and not load_on_all_ranks: state = distributed_utils.broadcast_object( state, src_rank=0, @@ -364,7 +367,7 @@ def load_checkpoint( if not reset_lr_scheduler: self.lr_scheduler.load_state_dict(last_optim["lr_scheduler_state"]) - if not load_on_all_ranks and self.data_parallel_world_size > 1: + if not load_on_all_ranks and is_distributed: last_optim_state = self.optimizer.broadcast_global_state_dict( last_optim_state ) From 336942734c85791a90baa373c212d27e7c722662 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Sat, 2 Jan 2021 10:21:42 -0800 Subject: [PATCH 139/774] Better support for WandB (#1530) Summary: Logs full config Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1530 Reviewed By: sshleifer Differential Revision: D25723894 Pulled By: myleott fbshipit-source-id: bb4b168c774bef498e336bbb3ba92eda4b08df3b --- README.md | 4 +-- fairseq/logging/progress_bar.py | 28 ++++++++++++++++++--- fairseq/models/distributed_fairseq_model.py | 2 -- fairseq_cli/train.py | 16 +++++++++++- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index cc1c76ec36..c22abba8c0 100644 --- a/README.md +++ b/README.md @@ -136,8 +136,8 @@ pip install --editable ./ # on MacOS: # CFLAGS="-stdlib=libc++" pip install --editable ./ -# to install the latest stable release (0.10.0) -# pip install fairseq==0.10.0 +# to install the latest stable release (0.10.1) +# pip install fairseq==0.10.1 ``` * **For faster training** install NVIDIA's [apex](https://github.com/NVIDIA/apex) library: diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index e2a1711121..dc061a1821 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -145,6 +145,10 @@ def print(self, stats, tag=None, step=None): """Print end-of-epoch stats.""" raise NotImplementedError + def update_config(self, config): + """Log latest configuration.""" + pass + def _str_commas(self, stats): return ", ".join(key + "=" + stats[key].strip() for key in stats.keys()) @@ -303,9 +307,12 @@ def print(self, stats, tag=None, step=None): try: _tensorboard_writers = {} - from tensorboardX import SummaryWriter + from torch.utils.tensorboard import SummaryWriter except ImportError: - SummaryWriter = None + try: + from tensorboardX import SummaryWriter + except ImportError: + SummaryWriter = None def _close_writers(): @@ -325,7 +332,7 @@ def __init__(self, wrapped_bar, tensorboard_logdir): if SummaryWriter is None: logger.warning( - "tensorboard not found, please install with: pip install tensorboardX" + "tensorboard not found, please install with: pip install tensorboard" ) def _writer(self, key): @@ -350,6 +357,11 @@ def print(self, stats, tag=None, step=None): self._log_to_tensorboard(stats, tag, step) self.wrapped_bar.print(stats, tag=tag, step=step) + def update_config(self, config): + """Log latest configuration.""" + # TODO add hparams to Tensorboard + self.wrapped_bar.update_config(config) + def _log_to_tensorboard(self, stats, tag=None, step=None): writer = self._writer(tag or "") if writer is None: @@ -398,6 +410,12 @@ def print(self, stats, tag=None, step=None): self._log_to_wandb(stats, tag, step) self.wrapped_bar.print(stats, tag=tag, step=step) + def update_config(self, config): + """Log latest configuration.""" + if wandb is not None: + wandb.config.update(config) + self.wrapped_bar.update_config(config) + def _log_to_wandb(self, stats, tag=None, step=None): if wandb is None: return @@ -447,6 +465,10 @@ def print(self, stats, tag=None, step=None): self._log_to_azureml(stats, tag, step) self.wrapped_bar.print(stats, tag=tag, step=step) + def update_config(self, config): + """Log latest configuration.""" + self.wrapped_bar.update_config(config) + def _log_to_azureml(self, stats, tag=None, step=None): if Run is None: return diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index 909b3757b2..ffa3c37b19 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -60,8 +60,6 @@ def DistributedFairseqModel(args, model, process_group): process_group=process_group, ) # Maintain backward compatibility - if "check_reduction" in inspect.getargspec(ddp_class)[0]: - init_kwargs["check_reduction"] = True if "find_unused_parameters" in inspect.getargspec(ddp_class)[0]: init_kwargs["find_unused_parameters"] = args.find_unused_parameters elif args.distributed_wrapper == "DDP" and args.ddp_backend == "no_c10d": diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 6069cf48fe..1156222642 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -29,7 +29,7 @@ from fairseq.logging import meters, metrics, progress_bar from fairseq.model_parallel.megatron_trainer import MegatronTrainer from fairseq.trainer import Trainer -from omegaconf import DictConfig +from omegaconf import DictConfig, OmegaConf logging.basicConfig( @@ -223,6 +223,7 @@ def train( else False ), ) + progress.update_config(_flatten_config(cfg)) trainer.begin_epoch(epoch_itr.epoch) @@ -264,6 +265,19 @@ def train( return valid_losses, should_stop +def _flatten_config(cfg: DictConfig): + config = OmegaConf.to_container(cfg) + # remove any legacy Namespaces and replace with a single "args" + namespace = None + for k, v in list(config.items()): + if isinstance(v, argparse.Namespace): + namespace = v + del config[k] + if namespace is not None: + config["args"] = vars(namespace) + return config + + def validate_and_save( cfg: DictConfig, trainer: Trainer, From 7e5e45b483ec5896830231ebbd3ed26472bcff47 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 5 Jan 2021 11:27:00 -0800 Subject: [PATCH 140/774] Add omegaconf dependency to hubconf.py (fixes #3093) (#3102) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3102 Reviewed By: alexeib Differential Revision: D25784689 Pulled By: myleott fbshipit-source-id: 66b0755e7f8abca2a522266bd58881b789bae581 --- hubconf.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hubconf.py b/hubconf.py index ce7d76cfe1..4eb6998504 100644 --- a/hubconf.py +++ b/hubconf.py @@ -17,6 +17,7 @@ "dataclasses", "hydra", "numpy", + "omegaconf", "regex", "requests", "torch", From 540fb42c523e98f066989c3e3b61a18caaca24f5 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Tue, 5 Jan 2021 12:13:07 -0800 Subject: [PATCH 141/774] Move dep checks before fairseq imports in hubconf.py (fixes #3093) (#3104) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3104 Reviewed By: alexeib Differential Revision: D25786013 Pulled By: myleott fbshipit-source-id: 894b104f275573ce824d7f2318d043516f0e0c5c --- hubconf.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hubconf.py b/hubconf.py index 4eb6998504..5949e274ed 100644 --- a/hubconf.py +++ b/hubconf.py @@ -2,16 +2,11 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +"""isort:skip_file""" import functools import importlib -from fairseq.hub_utils import ( # noqa; noqa - BPEHubInterface as bpe, - TokenizerHubInterface as tokenizer, -) -from fairseq.models import MODEL_REGISTRY # noqa - dependencies = [ "dataclasses", @@ -40,6 +35,14 @@ raise RuntimeError("Missing dependencies: {}".format(", ".join(missing_deps))) +# only do fairseq imports after checking for dependencies +from fairseq.hub_utils import ( # noqa; noqa + BPEHubInterface as bpe, + TokenizerHubInterface as tokenizer, +) +from fairseq.models import MODEL_REGISTRY # noqa + + # torch.hub doesn't build Cython components, so if they are not found then try # to build them here try: From 70b3f529659099b1bfca4099b11fc6d5577f7b0e Mon Sep 17 00:00:00 2001 From: Alejandro Gaston Alvarez Franceschi Date: Tue, 5 Jan 2021 14:33:29 -0800 Subject: [PATCH 142/774] Migrate wav2letter to flashlight (#2876) Summary: With this PR we start using flashlight bindings instead of wav2letter. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? Pull Request resolved: https://github.com/pytorch/fairseq/pull/2876 Reviewed By: myleott Differential Revision: D25785525 Pulled By: alexeib fbshipit-source-id: 245b3cebffedfd7db26c002ae3d26a1fe66c7156 --- examples/speech_recognition/README.md | 43 +++----------- .../speech_recognition/criterions/ASG_loss.py | 2 +- .../speech_recognition/criterions/__init__.py | 4 +- examples/speech_recognition/data/replabels.py | 4 +- examples/speech_recognition/infer.py | 2 +- examples/speech_recognition/w2l_decoder.py | 57 +++++++++---------- examples/wav2vec/README.md | 4 +- examples/wav2vec/libri_labels.py | 2 +- examples/wav2vec/vq-wav2vec_featurize.py | 2 +- examples/wav2vec/wav2vec_featurize.py | 12 ++-- 10 files changed, 53 insertions(+), 79 deletions(-) diff --git a/examples/speech_recognition/README.md b/examples/speech_recognition/README.md index 19f7cc563e..8207fe257c 100644 --- a/examples/speech_recognition/README.md +++ b/examples/speech_recognition/README.md @@ -32,41 +32,16 @@ sclite -r ${RES_DIR}/ref.word-checkpoint_last.pt-${SET}.txt -h ${RES_DIR}/hypo.w ``` `Sum/Avg` row from first table of the report has WER -## Using wav2letter components -[wav2letter](https://github.com/facebookresearch/wav2letter) now has integration with fairseq. Currently this includes: +## Using flashlight (previously called [wav2letter](https://github.com/facebookresearch/wav2letter)) components +[flashlight](https://github.com/facebookresearch/flashlight) now has integration with fairseq. Currently this includes: * AutoSegmentationCriterion (ASG) -* wav2letter-style Conv/GLU model -* wav2letter's beam search decoder +* flashlight-style Conv/GLU model +* flashlight's beam search decoder -To use these, follow the instructions on [this page](https://github.com/facebookresearch/wav2letter/tree/master/bindings/python) to install python bindings. Please note that python bindings are for a *subset* of wav2letter and don't require its full dependencies (notably, `flashlight` and `ArrayFire` are *not* required). +To use these, follow the instructions on [this page](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) to install python bindings. -To quickly summarize the instructions: first, install [CUDA](https://developer.nvidia.com/cuda-downloads). Then follow these steps: -``` -# additional prerequisites - use equivalents for your distro -sudo apt-get install build-essential cmake libatlas-base-dev libfftw3-dev liblzma-dev libbz2-dev libzstd-dev -# install KenLM from source -git clone https://github.com/kpu/kenlm.git -cd kenlm -mkdir -p build && cd build -cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON -make -j16 -cd .. -export KENLM_ROOT_DIR=$(pwd) -cd .. -# install wav2letter python bindings -git clone https://github.com/facebookresearch/wav2letter.git -cd wav2letter/bindings/python -# make sure your python environment is active at this point -pip install torch packaging -pip install -e . -# try some examples to verify installation succeeded -python ./examples/criterion_example.py -python ./examples/decoder_example.py ../../src/decoder/test -python ./examples/feature_example.py ../../src/feature/test/data -``` - -## Training librispeech data (wav2letter style, Conv/GLU + ASG loss) +## Training librispeech data (flashlight style, Conv/GLU + ASG loss) Training command: ``` python train.py $DIR_FOR_PREPROCESSED_DATA --save-dir $MODEL_PATH --max-epoch 100 --task speech_recognition --arch w2l_conv_glu_enc --batch-size 4 --optimizer sgd --lr 0.3,0.8 --momentum 0.8 --clip-norm 0.2 --max-tokens 50000 --log-format json --log-interval 100 --num-workers 0 --sentence-avg --criterion asg_loss --asg-transitions-init 5 --max-replabel 2 --linseg-updates 8789 --user-dir examples/speech_recognition @@ -74,13 +49,13 @@ python train.py $DIR_FOR_PREPROCESSED_DATA --save-dir $MODEL_PATH --max-epoch 10 Note that ASG loss currently doesn't do well with word-pieces. You should prepare a dataset with character targets by setting `nbpe=31` in `prepare-librispeech.sh`. -## Inference for librispeech (wav2letter decoder, n-gram LM) +## Inference for librispeech (flashlight decoder, n-gram LM) Inference command: ``` python examples/speech_recognition/infer.py $DIR_FOR_PREPROCESSED_DATA --task speech_recognition --seed 1 --nbest 1 --path $MODEL_PATH/checkpoint_last.pt --gen-subset $SET --results-path $RES_DIR --w2l-decoder kenlm --kenlm-model $KENLM_MODEL_PATH --lexicon $LEXICON_PATH --beam 200 --beam-threshold 15 --lm-weight 1.5 --word-score 1.5 --sil-weight -0.3 --criterion asg_loss --max-replabel 2 --user-dir examples/speech_recognition ``` -`$KENLM_MODEL_PATH` should be a standard n-gram language model file. `$LEXICON_PATH` should be a wav2letter-style lexicon (list of known words and their spellings). For ASG inference, a lexicon line should look like this (note the repetition labels): +`$KENLM_MODEL_PATH` should be a standard n-gram language model file. `$LEXICON_PATH` should be a flashlight-style lexicon (list of known words and their spellings). For ASG inference, a lexicon line should look like this (note the repetition labels): ``` doorbell D O 1 R B E L 1 ▁ ``` @@ -99,7 +74,7 @@ doorbell ▁DO OR BE L L ``` Lowercase vs. uppercase matters: the *word* should match the case of the n-gram language model (i.e. `$KENLM_MODEL_PATH`), while the *spelling* should match the case of the token dictionary (i.e. `$DIR_FOR_PREPROCESSED_DATA/dict.txt`). -## Inference for librispeech (wav2letter decoder, viterbi only) +## Inference for librispeech (flashlight decoder, viterbi only) Inference command: ``` python examples/speech_recognition/infer.py $DIR_FOR_PREPROCESSED_DATA --task speech_recognition --seed 1 --nbest 1 --path $MODEL_PATH/checkpoint_last.pt --gen-subset $SET --results-path $RES_DIR --w2l-decoder viterbi --criterion asg_loss --max-replabel 2 --user-dir examples/speech_recognition diff --git a/examples/speech_recognition/criterions/ASG_loss.py b/examples/speech_recognition/criterions/ASG_loss.py index 7493654afc..41f50bbd70 100644 --- a/examples/speech_recognition/criterions/ASG_loss.py +++ b/examples/speech_recognition/criterions/ASG_loss.py @@ -46,7 +46,7 @@ def __init__( linseg_updates, hide_linseg_messages, ): - from wav2letter.criterion import ASGLoss, CriterionScaleMode + from flashlight.lib.sequence.criterion import ASGLoss, CriterionScaleMode super().__init__(task) self.tgt_dict = task.target_dictionary diff --git a/examples/speech_recognition/criterions/__init__.py b/examples/speech_recognition/criterions/__init__.py index 88af9f340f..a667b1c918 100644 --- a/examples/speech_recognition/criterions/__init__.py +++ b/examples/speech_recognition/criterions/__init__.py @@ -2,10 +2,10 @@ import os -# ASG loss requires wav2letter +# ASG loss requires flashlight bindings files_to_skip = set() try: - import wav2letter + import flashlight.lib.sequence.criterion except ImportError: files_to_skip.add("ASG_loss.py") diff --git a/examples/speech_recognition/data/replabels.py b/examples/speech_recognition/data/replabels.py index d76bda7aef..441f1bd432 100644 --- a/examples/speech_recognition/data/replabels.py +++ b/examples/speech_recognition/data/replabels.py @@ -6,13 +6,13 @@ # LICENSE file in the root directory of this source tree. """ -Replabel transforms for use with wav2letter's ASG criterion. +Replabel transforms for use with flashlight's ASG criterion. """ def replabel_symbol(i): """ - Replabel symbols used in wav2letter, currently just "1", "2", ... + Replabel symbols used in flashlight, currently just "1", "2", ... This prevents training with numeral tokens, so this might change in the future """ return str(i) diff --git a/examples/speech_recognition/infer.py b/examples/speech_recognition/infer.py index ddd3fd6340..5a582c54af 100644 --- a/examples/speech_recognition/infer.py +++ b/examples/speech_recognition/infer.py @@ -277,7 +277,7 @@ def build_generator(args): return W2lFairseqLMDecoder(args, task.target_dictionary) else: print( - "only wav2letter decoders with (viterbi, kenlm, fairseqlm) options are supported at the moment" + "only flashlight decoders with (viterbi, kenlm, fairseqlm) options are supported at the moment" ) # please do not touch this unless you test both generate.py and infer.py with audio_pretraining task diff --git a/examples/speech_recognition/w2l_decoder.py b/examples/speech_recognition/w2l_decoder.py index e2870df6a7..1fb20757d0 100644 --- a/examples/speech_recognition/w2l_decoder.py +++ b/examples/speech_recognition/w2l_decoder.py @@ -6,7 +6,7 @@ # LICENSE file in the root directory of this source tree. """ -Wav2letter decoders. +Flashlight decoders. """ import gc @@ -25,11 +25,11 @@ try: - from wav2letter.common import create_word_dict, load_words - from wav2letter.criterion import CpuViterbiPath, get_data_ptr_as_bytes - from wav2letter.decoder import ( + from flashlight.lib.text.dictionary import create_word_dict, load_words + from flashlight.lib.sequence.criterion import CpuViterbiPath, get_data_ptr_as_bytes + from flashlight.lib.text.decoder import ( CriterionType, - DecoderOptions, + LexiconDecoderOptions, KenLM, LM, LMState, @@ -39,7 +39,7 @@ ) except: warnings.warn( - "wav2letter python bindings are required to use this functionality. Please install from https://github.com/facebookresearch/wav2letter/wiki/Python-bindings" + "flashlight python bindings are required to use this functionality. Please install from https://github.com/facebookresearch/flashlight/tree/master/bindings/python" ) LM = object LMState = object @@ -156,19 +156,19 @@ def __init__(self, args, tgt_dict): self.trie.insert(spelling_idxs, word_idx, score) self.trie.smear(SmearingMode.MAX) - self.decoder_opts = DecoderOptions( - args.beam, - int(getattr(args, "beam_size_token", len(tgt_dict))), - args.beam_threshold, - args.lm_weight, - args.word_score, - args.unk_weight, - args.sil_weight, - 0, - False, - self.criterion_type, + self.decoder_opts = LexiconDecoderOptions( + beam_size=args.beam, + beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), + beam_threshold=args.beam_threshold, + lm_weight=args.lm_weight, + word_score=args.word_score, + unk_score=args.unk_weight, + sil_score=args.sil_weight, + log_add=False, + criterion_type=self.criterion_type, ) + if self.asg_transitions is None: N = 768 # self.asg_transitions = torch.FloatTensor(N, N).zero_() @@ -368,17 +368,16 @@ def __init__(self, args, tgt_dict): self.unk_word = self.word_dict.unk() self.lm = FairseqLM(self.word_dict, model) - self.decoder_opts = DecoderOptions( - args.beam, - int(getattr(args, "beam_size_token", len(tgt_dict))), - args.beam_threshold, - args.lm_weight, - args.word_score, - args.unk_weight, - args.sil_weight, - 0, - False, - self.criterion_type, + self.decoder_opts = LexiconDecoderOptions( + beam_size=args.beam, + beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), + beam_threshold=args.beam_threshold, + lm_weight=args.lm_weight, + word_score=args.word_score, + unk_score=args.unk_weight, + sil_score=args.sil_weight, + log_add=False, + criterion_type=self.criterion_type, ) if self.lexicon: @@ -411,7 +410,7 @@ def __init__(self, args, tgt_dict): self.unit_lm, ) else: - from wav2letter.decoder import LexiconFreeDecoder + from flashlight.lib.text.decoder import LexiconFreeDecoder self.decoder = LexiconFreeDecoder( self.decoder_opts, self.lm, self.silence, self.blank, [] ) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index a0c95e9c34..b3300a8ed8 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -123,12 +123,12 @@ You can specify the right config via the `--config-name` parameter. Note: you can simulate 24 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) `distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 24/k -Decoding with a language model during training requires wav2letter [python bindings](https://github.com/facebookresearch/wav2letter/wiki/Building-Python-bindings). +Decoding with a language model during training requires flashlight [python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter). If you want to use a language model, add `+criterion.wer_args='[/path/to/kenlm, /path/to/lexicon, 2, -1]'` to the command line. ### Evaluating a CTC model: -Evaluating a CTC model with a language model requires wav2letter [python bindings](https://github.com/facebookresearch/wav2letter/wiki/Building-Python-bindings) to be installed. +Evaluating a CTC model with a language model requires [flashlight python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter) to be installed. Fairseq transformer language model used in the wav2vec 2.0 paper can be obtained from the [wav2letter model repository](https://github.com/facebookresearch/wav2letter/tree/master/recipes/sota/2019). Be sure to upper-case the language model vocab after downloading it. diff --git a/examples/wav2vec/libri_labels.py b/examples/wav2vec/libri_labels.py index 3fa1ec4c8b..694a202604 100644 --- a/examples/wav2vec/libri_labels.py +++ b/examples/wav2vec/libri_labels.py @@ -5,7 +5,7 @@ # LICENSE file in the root directory of this source tree. """ -Helper script to pre-compute embeddings for a wav2letter++ dataset +Helper script to pre-compute embeddings for a flashlight (previously called wav2letter++) dataset """ import argparse diff --git a/examples/wav2vec/vq-wav2vec_featurize.py b/examples/wav2vec/vq-wav2vec_featurize.py index 1adb52de1c..627072ee17 100644 --- a/examples/wav2vec/vq-wav2vec_featurize.py +++ b/examples/wav2vec/vq-wav2vec_featurize.py @@ -5,7 +5,7 @@ # LICENSE file in the root directory of this source tree. """ -Helper script to pre-compute embeddings for a wav2letter++ dataset +Helper script to pre-compute embeddings for a flashlight (previously called wav2letter++) dataset """ import argparse diff --git a/examples/wav2vec/wav2vec_featurize.py b/examples/wav2vec/wav2vec_featurize.py index b806316e5a..588268b708 100644 --- a/examples/wav2vec/wav2vec_featurize.py +++ b/examples/wav2vec/wav2vec_featurize.py @@ -5,7 +5,7 @@ # LICENSE file in the root directory of this source tree. """ -Helper script to pre-compute embeddings for a wav2letter++ dataset +Helper script to pre-compute embeddings for a flashlight (previously called wav2letter++) dataset """ import argparse @@ -52,7 +52,7 @@ def forward(self, x): class EmbeddingWriterConfig(argparse.ArgumentParser): def __init__(self): - super().__init__("Pre-compute embeddings for wav2letter++ datasets") + super().__init__("Pre-compute embeddings for flashlight datasets") kwargs = {"action": "store", "type": str, "required": True} @@ -67,7 +67,7 @@ def __init__(self): self.add_argument( "--no-copy-labels", action="store_true", - help="Do not copy label files. Useful for large datasets, use --targetdir in wav2letter then.", + help="Do not copy label files. Useful for large datasets, use --targetdir in flashlight then.", ) self.add_argument( "--use-feat", @@ -93,7 +93,7 @@ def __call__(self, x): class H5Writer: - """ Write features as hdf5 file in wav2letter++ compatible format """ + """ Write features as hdf5 file in flashlight compatible format """ def __init__(self, fname): self.fname = fname @@ -109,11 +109,11 @@ def write(self, data): class EmbeddingDatasetWriter(object): - """Given a model and a wav2letter++ dataset, pre-compute and store embeddings + """Given a model and a flashlight dataset, pre-compute and store embeddings Args: input_root, str : - Path to the wav2letter++ dataset + Path to the flashlight dataset output_root, str : Desired output directory. Will be created if non-existent split, str : From 53b474f8ac071da5aad94d255aa698278a492923 Mon Sep 17 00:00:00 2001 From: alexeib Date: Tue, 5 Jan 2021 17:41:46 -0800 Subject: [PATCH 143/774] minor changes/fixes (#1536) Summary: - some minor guardrails - ability to suppress crashes (useful for sweepers) - hydra_train main method returns the best validation value (useful for sweepers) - add more typing checks to work with python 3.9 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1536 Reviewed By: myleott Differential Revision: D25768210 Pulled By: alexeib fbshipit-source-id: 3df421efb261eb61331a9af1da11b8ef34bfd8f9 --- fairseq/criterions/ctc.py | 2 +- fairseq/criterions/model_criterion.py | 2 +- fairseq/dataclass/configs.py | 7 ++++ fairseq/dataclass/utils.py | 13 +++---- .../sinusoidal_positional_embedding.py | 2 +- fairseq/tasks/__init__.py | 2 +- fairseq_cli/hydra_train.py | 35 ++++++++++++++----- 7 files changed, 45 insertions(+), 18 deletions(-) diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index 8cb1331825..543e796da3 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -66,7 +66,7 @@ class CtcCriterionConfig(FairseqDataclass): class CtcCriterion(FairseqCriterion): def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): super().__init__(task) - self.blank_idx = task.target_dictionary.index(task.blank_symbol) + self.blank_idx = task.target_dictionary.index(task.blank_symbol) if hasattr(task, 'blank_symbol') else 0 self.pad_idx = task.target_dictionary.pad() self.eos_idx = task.target_dictionary.eos() self.post_process = cfg.post_process diff --git a/fairseq/criterions/model_criterion.py b/fairseq/criterions/model_criterion.py index 8e366a5d85..30350f13b1 100644 --- a/fairseq/criterions/model_criterion.py +++ b/fairseq/criterions/model_criterion.py @@ -83,7 +83,7 @@ def forward(self, model, sample, reduce=True): } for lk in self.log_keys: - if lk in net_output: + if lk in net_output and net_output[lk] is not None: logging_output[lk] = float(net_output[lk]) if len(scaled_losses) > 1: diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index caf4a7a2b8..2968d2ab0f 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -186,6 +186,13 @@ class CommonConfig(FairseqDataclass): "help": "when using Hydra, reset the logging at the beginning of training" }, ) + suppress_crashes: bool = field( + default=False, + metadata={ + "help": "suppress crashes when training with the hydra_train entry point so that the " + "main method can return a value (useful for sweeps)" + }, + ) @dataclass diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 45e7ed9170..4dc978409e 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -11,7 +11,7 @@ from argparse import ArgumentError, ArgumentParser, Namespace from dataclasses import _MISSING_TYPE, MISSING from enum import Enum -from typing import Any, Dict, List, Tuple, Type +from typing import Any, Dict, List, Optional, Tuple, Type from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.configs import FairseqConfig @@ -43,7 +43,7 @@ def interpret_dc_type(field_type): return str typestring = str(field_type) - if re.match(r"(typing.|^)Union\[(.*), NoneType\]$", typestring): + if re.match(r"(typing.|^)Union\[(.*), NoneType\]$", typestring) or typestring.startswith("typing.Optional"): return field_type.__args__[0] return field_type @@ -230,14 +230,15 @@ def get_default(f): v_type = getattr(v.type, "__origin__", None) if ( - (v_type is List or v_type is list) + (v_type is List or v_type is list or v_type is Optional) # skip interpolation and not (isinstance(val, str) and val.startswith("${")) ): # if type is int but val is float, then we will crash later - try to convert here - t_args = v.type.__args__ - if len(t_args) == 1: - val = list(map(t_args[0], val)) + if hasattr(v.type, '__args__'): + t_args = v.type.__args__ + if len(t_args) == 1: + val = list(map(t_args[0], val)) elif val is not None and (field_type is int or field_type is bool or field_type is float): try: val = field_type(val) diff --git a/fairseq/modules/sinusoidal_positional_embedding.py b/fairseq/modules/sinusoidal_positional_embedding.py index 857830faf7..4793ecfb52 100644 --- a/fairseq/modules/sinusoidal_positional_embedding.py +++ b/fairseq/modules/sinusoidal_positional_embedding.py @@ -21,7 +21,7 @@ class SinusoidalPositionalEmbedding(nn.Module): def __init__(self, embedding_dim, padding_idx, init_size=1024): super().__init__() self.embedding_dim = embedding_dim - self.padding_idx = padding_idx + self.padding_idx = padding_idx if padding_idx is not None else 0 self.weights = SinusoidalPositionalEmbedding.get_embedding( init_size, embedding_dim, padding_idx ) diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 0e55d093b1..95b4a9647f 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -39,7 +39,7 @@ def setup_task(cfg: FairseqDataclass, **kwargs): cfg = merge_with_parent(dc(), cfg) task = TASK_REGISTRY[task_name] - assert task is not None, f"Could not infer task type from {cfg}" + assert task is not None, f"Could not infer task type from {cfg}. Available tasks: {TASK_REGISTRY.keys()}" return task.setup_task(cfg, **kwargs) diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index b092ce14ee..cf48337462 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -10,7 +10,7 @@ from fairseq.dataclass.initialize import hydra_init from fairseq_cli.train import main as pre_main -from fairseq import distributed_utils +from fairseq import distributed_utils, metrics from fairseq.dataclass.configs import FairseqConfig import hydra @@ -22,7 +22,7 @@ @hydra.main(config_path=os.path.join("..", "fairseq", "config"), config_name="config") -def hydra_main(cfg: FairseqConfig) -> None: +def hydra_main(cfg: FairseqConfig) -> float: cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) OmegaConf.set_struct(cfg, True) @@ -30,12 +30,31 @@ def hydra_main(cfg: FairseqConfig) -> None: if cfg.common.reset_logging: reset_logging() # Hydra hijacks logging, fix that - if cfg.common.profile: - with torch.cuda.profiler.profile(): - with torch.autograd.profiler.emit_nvtx(): - distributed_utils.call_main(cfg, pre_main) - else: - distributed_utils.call_main(cfg, pre_main) + try: + if cfg.common.profile: + with torch.cuda.profiler.profile(): + with torch.autograd.profiler.emit_nvtx(): + distributed_utils.call_main(cfg, pre_main) + else: + distributed_utils.call_main(cfg, pre_main) + except BaseException as e: + if not cfg.common.suppress_crashes: + raise + else: + logger.error("Crashed! " + str(e)) + + # get best val and return - useful for sweepers + try: + best_val = metrics.get_smoothed_value( + "valid", cfg.checkpoint.best_checkpoint_metric + ) + except: + best_val = None + + if best_val is None: + best_val = float("inf") + + return best_val def reset_logging(): From 4daa41bedcc8e3ac7fd35dd1ec27088ecc71ebec Mon Sep 17 00:00:00 2001 From: alexeib Date: Tue, 5 Jan 2021 17:41:46 -0800 Subject: [PATCH 144/774] migrate label smoothed cross entropy (#1537) Summary: migrate label smoothed cross entropy to hydra Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1537 Reviewed By: myleott Differential Revision: D25768702 Pulled By: alexeib fbshipit-source-id: a90fa40802ae67ad81a8f5b0735d5316d41fea2d --- .../label_smoothed_cross_entropy.py | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/fairseq/criterions/label_smoothed_cross_entropy.py b/fairseq/criterions/label_smoothed_cross_entropy.py index 2dc7f7a47d..cb47a1582f 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy.py +++ b/fairseq/criterions/label_smoothed_cross_entropy.py @@ -4,10 +4,30 @@ # LICENSE file in the root directory of this source tree. import math +from dataclasses import dataclass, field import torch from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass +from omegaconf import II + + +@dataclass +class LabelSmoothedCrossEntropyCriterionConfig(FairseqDataclass): + label_smoothing: float = field( + default=0.0, + metadata={"help": "epsilon for label smoothing, 0 means no label smoothing"}, + ) + report_accuracy: bool = field( + default=False, + metadata={"help": "report accuracy metric"}, + ) + ignore_prefix_size: int = field( + default=0, + metadata={"help": "Ignore first N tokens"}, + ) + sentence_avg: bool = II("optimization.sentence_avg") def label_smoothed_nll_loss(lprobs, target, epsilon, ignore_index=None, reduce=True): @@ -30,7 +50,9 @@ def label_smoothed_nll_loss(lprobs, target, epsilon, ignore_index=None, reduce=T return loss, nll_loss -@register_criterion("label_smoothed_cross_entropy") +@register_criterion( + "label_smoothed_cross_entropy", dataclass=LabelSmoothedCrossEntropyCriterionConfig +) class LabelSmoothedCrossEntropyCriterion(FairseqCriterion): def __init__( self, @@ -46,18 +68,6 @@ def __init__( self.ignore_prefix_size = ignore_prefix_size self.report_accuracy = report_accuracy - @staticmethod - def add_args(parser): - """Add criterion-specific arguments to the parser.""" - # fmt: off - parser.add_argument('--label-smoothing', default=0., type=float, metavar='D', - help='epsilon for label smoothing, 0 means no label smoothing') - parser.add_argument('--report-accuracy', action='store_true', - help='report accuracy metric') - parser.add_argument('--ignore-prefix-size', default=0, type=int, - help='Ignore first N tokens') - # fmt: on - def forward(self, model, sample, reduce=True): """Compute the loss for the given sample. From cb7398299b4a8c51eb195fc0c054068470e8a1c9 Mon Sep 17 00:00:00 2001 From: Arthur Guo Date: Tue, 5 Jan 2021 19:08:27 -0800 Subject: [PATCH 145/774] Add typing and JIT support for TransfomerDecoder and dependencies Reviewed By: zhengwy888 Differential Revision: D25451106 fbshipit-source-id: f9aa7f1ca6120f00c4938d4d72219471035211ca --- fairseq/modules/conv_tbc.py | 6 +++++- fairseq/modules/linearized_convolution.py | 23 ++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/fairseq/modules/conv_tbc.py b/fairseq/modules/conv_tbc.py index 2dc46c4b9b..79b2b2ad57 100644 --- a/fairseq/modules/conv_tbc.py +++ b/fairseq/modules/conv_tbc.py @@ -5,6 +5,7 @@ import torch from torch.nn.modules.utils import _single +from torch import Tensor class ConvTBC(torch.nn.Module): @@ -26,11 +27,14 @@ def __init__(self, in_channels, out_channels, kernel_size, padding=0): ) self.bias = torch.nn.Parameter(torch.Tensor(out_channels)) - def forward(self, input): + def conv_tbc(self, input: Tensor): return torch.conv_tbc( input.contiguous(), self.weight, self.bias, self.padding[0] ) + def forward(self, input: Tensor): + return self.conv_tbc(input) + def __repr__(self): s = ( "{name}({in_channels}, {out_channels}, kernel_size={kernel_size}" diff --git a/fairseq/modules/linearized_convolution.py b/fairseq/modules/linearized_convolution.py index b36cea91fa..f7e156cb0c 100644 --- a/fairseq/modules/linearized_convolution.py +++ b/fairseq/modules/linearized_convolution.py @@ -10,6 +10,8 @@ from .conv_tbc import ConvTBC +from typing import Dict, Optional +from torch import Tensor @with_incremental_state class LinearizedConvolution(ConvTBC): @@ -38,8 +40,8 @@ def upgrade_state_dict_named(self, state_dict, name): if prefix + "_linearized_weight" in state_dict: del state_dict[prefix + "_linearized_weight"] - @torch.jit.ignore - def forward(self, input, incremental_state=None): + @torch.jit.export + def forward(self, input, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None): """ Args: incremental_state: Used to buffer signal; if not None, then input is @@ -50,7 +52,7 @@ def forward(self, input, incremental_state=None): Batch x Time x Channel during inference """ if incremental_state is None: - output = super().forward(input) + output = self.conv_tbc(input) if self.kernel_size[0] > 1 and self.padding[0] > 0: # remove future timesteps added by padding output = output[: -self.padding[0], :, :] @@ -77,29 +79,32 @@ def forward(self, input, incremental_state=None): output = F.linear(input.view(bsz, -1), weight, self.bias) return output.view(bsz, 1, -1) - def reorder_incremental_state(self, incremental_state, new_order): + @torch.jit.unused + def reorder_incremental_state(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], new_order): input_buffer = self._get_input_buffer(incremental_state) if input_buffer is not None: input_buffer = input_buffer.index_select(0, new_order) self._set_input_buffer(incremental_state, input_buffer) - def _get_input_buffer(self, incremental_state): + @torch.jit.unused + def _get_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): return utils.get_incremental_state(self, incremental_state, "input_buffer") - def _set_input_buffer(self, incremental_state, new_buffer): + @torch.jit.unused + def _set_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], new_buffer): return utils.set_incremental_state( self, incremental_state, "input_buffer", new_buffer ) + @torch.jit.unused def _get_linearized_weight(self): if self._linearized_weight is None: kw = self.kernel_size[0] weight = self.weight.transpose(2, 1).transpose(1, 0).contiguous() assert weight.size() == (self.out_channels, kw, self.in_channels) - self._linearized_weight = torch.nn.Parameter( - weight.view(self.out_channels, -1) - ) + return weight.view(self.out_channels, -1) return self._linearized_weight + @torch.jit.unused def _clear_linearized_weight(self, *args): self._linearized_weight = None From 89a4d2bc70fd680c4768803d20707ef65df89b0f Mon Sep 17 00:00:00 2001 From: Changhan Wang Date: Tue, 5 Jan 2021 20:54:21 -0800 Subject: [PATCH 146/774] S2T bug fix for issue #3095 Summary: S2T bug fix for issue [#3095](https://github.com/pytorch/fairseq/issues/3095): - Revert the dropped S2T de-tokenization in `fairseq-generate` - Update S2T Transformer encoder output to dict type (following the updates on the text Transformer) Reviewed By: jmp84 Differential Revision: D25788341 fbshipit-source-id: f226fb9d5e001bbc7dd245293819e0a36d5a88e7 --- .../models/speech_to_text/s2t_transformer.py | 70 +++++++------------ fairseq_cli/generate.py | 4 +- 2 files changed, 28 insertions(+), 46 deletions(-) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index fc2f14fea6..afd43f1ec7 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -4,7 +4,6 @@ import math from typing import Dict, List, Optional, Tuple -import torch import torch.nn as nn from fairseq import checkpoint_utils, utils from fairseq.data.data_utils import lengths_to_padding_mask @@ -14,7 +13,6 @@ register_model, register_model_architecture, ) -from fairseq.models.fairseq_encoder import EncoderOut from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.modules import ( FairseqDropout, @@ -308,70 +306,54 @@ def forward(self, src_tokens, src_lengths): for layer in self.transformer_layers: x = layer(x, encoder_padding_mask) - if not encoder_padding_mask.any(): - encoder_padding_mask = None - if self.layer_norm is not None: x = self.layer_norm(x) - return EncoderOut( - encoder_out=x, - encoder_padding_mask=encoder_padding_mask, - encoder_embedding=None, - encoder_states=None, - src_tokens=None, - src_lengths=None, - ) - - @torch.jit.export - def reorder_encoder_out(self, encoder_out: EncoderOut, new_order): - """ - Since encoder_padding_mask and encoder_embedding are both of type - Optional[Tensor] in EncoderOut, they need to be copied as local - variables for Torchscript Optional refinement - """ - - encoder_padding_mask: Optional[Tensor] = encoder_out.encoder_padding_mask - encoder_embedding: Optional[Tensor] = encoder_out.encoder_embedding + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [encoder_padding_mask] if encoder_padding_mask.any() else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": [], # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + def reorder_encoder_out(self, encoder_out, new_order): new_encoder_out = ( - encoder_out.encoder_out - if encoder_out.encoder_out is None - else encoder_out.encoder_out.index_select(1, new_order) + [] if len(encoder_out["encoder_out"]) == 0 + else [x.index_select(1, new_order) for x in encoder_out["encoder_out"]] ) new_encoder_padding_mask = ( - encoder_padding_mask - if encoder_padding_mask is None - else encoder_padding_mask.index_select(0, new_order) + [] if len(encoder_out["encoder_padding_mask"]) == 0 + else [x.index_select(0, new_order) for x in encoder_out["encoder_padding_mask"]] ) new_encoder_embedding = ( - encoder_embedding - if encoder_embedding is None - else encoder_embedding.index_select(0, new_order) + [] if len(encoder_out["encoder_embedding"]) == 0 + else [x.index_select(0, new_order) for x in encoder_out["encoder_embedding"]] ) - encoder_states = encoder_out.encoder_states - if encoder_states is not None: + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: for idx, state in enumerate(encoder_states): encoder_states[idx] = state.index_select(1, new_order) - return EncoderOut( - encoder_out=new_encoder_out, # T x B x C - encoder_padding_mask=new_encoder_padding_mask, # B x T - encoder_embedding=new_encoder_embedding, # B x T x C - encoder_states=encoder_states, # List[T x B x C] - src_tokens=None, - src_lengths=None, - ) + return { + "encoder_out": new_encoder_out, # T x B x C + "encoder_padding_mask": new_encoder_padding_mask, # B x T + "encoder_embedding": new_encoder_embedding, # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], # B x T + "src_lengths": [], # B x 1 + } class TransformerDecoderScriptable(TransformerDecoder): def extract_features( self, prev_output_tokens, - encoder_out: Optional[EncoderOut] = None, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, full_context_alignment: bool = False, alignment_layer: Optional[int] = None, diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index ff8369b539..0a523680f0 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -170,8 +170,8 @@ def _main(cfg: DictConfig, output_file): ) # Handle tokenization and BPE - tokenizer = encoders.build_tokenizer(cfg.tokenizer) - bpe = encoders.build_bpe(cfg.bpe) + tokenizer = task.build_tokenizer(cfg.tokenizer) + bpe = task.build_bpe(cfg.bpe) def decode_fn(x): if bpe is not None: From d1d487395e8206c39640f07f3be5b2bce33edee6 Mon Sep 17 00:00:00 2001 From: Changhan Wang Date: Tue, 5 Jan 2021 22:08:51 -0800 Subject: [PATCH 147/774] bug fix for scorer config Summary: bug fix for scorer config - additional scorer arguments (e.g. WER punctuation removal) from cli are not passed into `build_scorer` properly Reviewed By: jmp84 Differential Revision: D25797236 fbshipit-source-id: 909e272931ca0fd1cad2d7d8a2ca7e79bd7dcd43 --- fairseq/scoring/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fairseq/scoring/__init__.py b/fairseq/scoring/__init__.py index 9163be87e7..2372727883 100644 --- a/fairseq/scoring/__init__.py +++ b/fairseq/scoring/__init__.py @@ -37,10 +37,9 @@ def result_string(self) -> str: def build_scorer(choice, tgt_dict): - if isinstance(choice, DictConfig): - choice = choice._name + _choice = choice._name if isinstance(choice, DictConfig) else choice - if choice == "bleu": + if _choice == "bleu": from fairseq.scoring import bleu return bleu.Scorer( From 2e649232d4455826f7110f7c321b1d5e193b891e Mon Sep 17 00:00:00 2001 From: Rui Hou Date: Wed, 6 Jan 2021 21:41:58 -0800 Subject: [PATCH 148/774] Make StreamingEpochBatchIterator work with batch size > 1 Summary: Previously, StreamingEpochBatchIterator only support batch_size = 1 for each GPU. This diff makes it possible to collate samples into a mini-batch such that batch_size can be greater than 1. Reviewed By: spencerp Differential Revision: D25295572 fbshipit-source-id: 398a4247701aa1ec71c1d16bba87430decf61ee6 --- fairseq/data/iterators.py | 69 ++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 0f55026ef8..00bf41375c 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -144,19 +144,46 @@ def first_batch(self): class StreamingEpochBatchIterator(EpochBatchIterating): + """A steaming-style iterator over a :class:`torch.utils.data.IterableDataset`. + + Args: + dataset (~torch.utils.data.Dataset): dataset from which to load the data + max_sentences: batch size + collate_fn (callable): merges a list of samples to form a mini-batch + num_workers (int, optional): how many subprocesses to use for data + loading. 0 means the data will be loaded in the main process + (default: 0). + epoch (int, optional): the epoch to start the iterator from + (default: 1). + buffer_size (int, optional): the number of batches to keep ready in the + queue. Helps speeding up dataloading. When buffer_size is zero, the + default torch.utils.data.DataLoader preloading is used. + timeout (int, optional): if positive, the timeout value for collecting a batch + from workers. Should always be non-negative (default: ``0``). + """ + def __init__( self, dataset, + max_sentences=1, + collate_fn=None, epoch=1, - num_shards=1, - shard_id=0, + num_workers=0, + buffer_size=0, + timeout=0, ): assert isinstance(dataset, torch.utils.data.IterableDataset) self.dataset = dataset + self.max_sentences = max_sentences + self.collate_fn = collate_fn self.epoch = max(epoch, 1) # we use 1-based indexing for epochs + self.num_workers = num_workers + # This upper limit here is to prevent people from abusing this feature + # in a shared computing environment. + self.buffer_size = min(buffer_size, 20) + self.timeout = timeout + self._current_epoch_iterator = None - self.num_shards = num_shards - self.shard_id = shard_id @property def next_epoch_idx(self): @@ -170,13 +197,7 @@ def next_epoch_itr(self, shuffle=True, fix_batches_to_gpus=False): self.epoch = self.next_epoch_idx if hasattr(self.dataset, "set_epoch"): self.dataset.set_epoch(self.epoch) - self._current_epoch_iterator = CountingIterator( - iterable=ShardedIterator( - iterable=self.dataset, - num_shards=self.num_shards, - shard_id=self.shard_id, - ), - ) + self._current_epoch_iterator = self._get_iterator_for_epoch(self.epoch, shuffle) return self._current_epoch_iterator def end_of_epoch(self) -> bool: @@ -196,6 +217,30 @@ def state_dict(self): def load_state_dict(self, state_dict): self.epoch = state_dict["epoch"] + def _get_iterator_for_epoch(self, epoch, shuffle, offset=0): + if self.num_workers > 0: + os.environ["PYTHONWARNINGS"] = "ignore:semaphore_tracker:UserWarning" + + # Create data loader + worker_init_fn = getattr(self.dataset, "worker_init_fn", None) + itr = torch.utils.data.DataLoader( + self.dataset, + batch_size=self.max_sentences, + collate_fn=self.collate_fn, + num_workers=self.num_workers, + timeout=self.timeout, + worker_init_fn=worker_init_fn, + ) + + # Wrap with a BufferedIterator if needed + if self.buffer_size > 0: + itr = BufferedIterator(self.buffer_size, itr) + + # Wrap with CountingIterator + itr = CountingIterator(itr, start=offset) + + return itr + class EpochBatchIterator(EpochBatchIterating): """A multi-epoch iterator over a :class:`torch.utils.data.Dataset`. @@ -442,7 +487,7 @@ def shuffle_batches(batches, seed): if self.buffer_size > 0: itr = BufferedIterator(self.buffer_size, itr) - # Wrap with CoutingIterator + # Wrap with CountingIterator itr = CountingIterator(itr, start=offset) return itr From a9f5741f58c05c581686b73465d7e3f9df5528f3 Mon Sep 17 00:00:00 2001 From: Changhan Wang Date: Fri, 8 Jan 2021 15:25:59 -0800 Subject: [PATCH 149/774] update S2T examples and small fixes for S2T Summary: - Update S2T examples: documentation (rendered version: https://github.com/fairinternal/fairseq-py/tree/v2_fairseq_s2t/examples/speech_to_text), bug fixes and pre-trained models - Revert `--share-decoder-input-output-embed`'s default value to `False` (for s2t_transformer) Reviewed By: yuntang Differential Revision: D25821616 fbshipit-source-id: 3dba2eb5566bff39305d0056daf1b9f5adf1a926 --- examples/speech_recognition/README.md | 4 +- examples/speech_to_text/README.md | 259 ++---------------- examples/speech_to_text/data_utils.py | 118 ++++---- .../speech_to_text/docs/covost_example.md | 93 +++++++ .../docs/librispeech_example.md | 61 +++++ examples/speech_to_text/docs/mustc_example.md | 155 +++++++++++ examples/speech_to_text/prep_covost_data.py | 96 +++---- .../speech_to_text/prep_librispeech_data.py | 37 ++- examples/speech_to_text/prep_mustc_data.py | 73 ++--- .../audio/feature_transforms/global_cmvn.py | 4 + .../models/speech_to_text/s2t_transformer.py | 4 +- fairseq_cli/generate.py | 1 - 12 files changed, 495 insertions(+), 410 deletions(-) create mode 100644 examples/speech_to_text/docs/covost_example.md create mode 100644 examples/speech_to_text/docs/librispeech_example.md create mode 100644 examples/speech_to_text/docs/mustc_example.md diff --git a/examples/speech_recognition/README.md b/examples/speech_recognition/README.md index 8207fe257c..17030bf0fd 100644 --- a/examples/speech_recognition/README.md +++ b/examples/speech_recognition/README.md @@ -1,3 +1,5 @@ +### 2021 Update: We are merging this example into the [S2T framework](../speech_to_text), which supports more generic speech-to-text tasks (e.g. speech translation) and more flexible data processing pipelines. Please stay tuned. + # Speech Recognition `examples/speech_recognition` is implementing ASR task in Fairseq, along with needed features, datasets, models and loss functions to train and infer model described in [Transformers with convolutional context for ASR (Abdelrahman Mohamed et al., 2019)](https://arxiv.org/abs/1904.11660). @@ -39,7 +41,7 @@ sclite -r ${RES_DIR}/ref.word-checkpoint_last.pt-${SET}.txt -h ${RES_DIR}/hypo.w * flashlight-style Conv/GLU model * flashlight's beam search decoder -To use these, follow the instructions on [this page](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) to install python bindings. +To use these, follow the instructions on [this page](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) to install python bindings. ## Training librispeech data (flashlight style, Conv/GLU + ASG loss) Training command: diff --git a/examples/speech_to_text/README.md b/examples/speech_to_text/README.md index 4030af0144..0bd8bfdac9 100644 --- a/examples/speech_to_text/README.md +++ b/examples/speech_to_text/README.md @@ -1,8 +1,8 @@ # Speech-to-Text (S2T) Modeling -[https://arxiv.org/abs/2010.05171](https://arxiv.org/abs/2010.05171) +[https://www.aclweb.org/anthology/2020.aacl-demo.6](https://www.aclweb.org/anthology/2020.aacl-demo.6.pdf) -Examples for speech recognition (ASR) and speech-to-text translation (ST) with fairseq. +Speech recognition (ASR) and speech-to-text translation (ST) with fairseq. ## Data Preparation S2T modeling data consists of source speech features, target text and other optional information @@ -21,239 +21,31 @@ temperature-based resampling, etc. ## Model Training & Evaluation Fairseq S2T uses the unified `fairseq-train`/`fairseq-generate` interface for model training and evaluation. -It requires arguments `--task speech_to_text` and `--arch `. +It requires arguments `--task speech_to_text` and `--arch `. -## Example 1: Speech Recognition (ASR) on LibriSpeech +## Examples +- [Speech Recognition (ASR) on LibriSpeech](docs/librispeech_example.md) -#### Data preparation -Download and preprocess [LibriSpeech](https://www.danielpovey.com/files/2015_icassp_librispeech.pdf) data with -```bash -python examples/speech_to_text/prep_librispeech_data.py --output-root ${LS_ROOT} --vocab-type unigram --vocab-size 10000 -``` -where `LS_ROOT` is the root path for downloaded data as well as generated manifest and feature files. - -#### Training -```bash -fairseq-train ${LS_ROOT} --train-subset train --valid-subset dev --save-dir ${SAVE_DIR} --num-workers 4 \ - --max-tokens 40000 --task speech_to_text --criterion label_smoothed_cross_entropy --max-update 300000 \ - --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt --warmup-updates 10000 \ - --clip-norm 10.0 --seed 1 --update-freq 8 -``` -where `SAVE_DIR` is the checkpoint root path. Here we use `--arch s2t_transformer_s` (31M parameters) as example. -You may switch to `s2t_transformer_m` (71M) or `s2t_transformer_l` (268M) for better performance. We set -`--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly when using more than 1 GPU. - -#### Inference & Evaluation -Average the last 10 checkpoints and evaluate on the 4 splits -(`dev-clean`, `dev-other`, `test-clean` and `test-other`): -```bash -CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt -python scripts/average_checkpoints.py --inputs ${SAVE_DIR} --num-epoch-checkpoints 10 \ - --output "${SAVE_DIR}/${CHECKPOINT_FILENAME}" -for SUBSET in dev-clean dev-other test-clean test-other; do - fairseq-generate ${LS_ROOT} --gen-subset ${SUBSET} --task speech_to_text \ - --path ${SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 --scoring wer -done -``` +- [Speech-to-Text Translation (ST) on MuST-C](docs/mustc_example.md) -#### Result +- [Speech-to-Text Translation (ST) on CoVoST 2](docs/covost_example.md) -| --arch | Params | dev-clean | dev-other | test-clean | test-other | -|---|---|---|---|---|---| -| s2t_transformer_s | 30M | 4.1 | 9.3 | 4.4 | 9.2 | -| s2t_transformer_sp | 35M | 3.9 | 9.3 | 4.3 | 8.8 | -| s2t_transformer_m | 71M | 3.5 | 8.1 | 3.7 | 8.1 | -| s2t_transformer_mp | 84M | 3.3 | 7.8 | 3.7 | 8.2 | -| s2t_transformer_l | 268M | 3.3 | 7.7 | 3.5 | 7.8 | -| s2t_transformer_lp | 318M | 3.1 | 7.5 | 3.4 | 7.6 | - - -## Example 2: Speech Translation (ST) on MuST-C - -#### Data Preparation -[Download](https://ict.fbk.eu/must-c) and unpack [MuST-C](https://www.aclweb.org/anthology/N19-1202) data -to a path `${MUSTC_ROOT}/en-${TARGET_LANG_ID}`, then preprocess it with -```bash -# Generate TSV manifests, features, vocabulary and configuration for each language -python examples/speech_to_text/prep_mustc_data.py --data-root ${MUSTC_ROOT} --task asr \ - --vocab-type unigram --vocab-size 5000 -python examples/speech_to_text/prep_mustc_data.py --data-root ${MUSTC_ROOT} --task st \ - --vocab-type unigram --vocab-size 8000 - -# Add vocabulary and configuration for joint data (based on the manifests and features generated above) -python examples/speech_to_text/prep_mustc_data.py --data-root ${MUSTC_ROOT} --task asr --joint \ - --vocab-type unigram --vocab-size 10000 -python examples/speech_to_text/prep_mustc_data.py --data-root ${MUSTC_ROOT} --task st --joint \ - --vocab-type unigram --vocab-size 10000 -``` -The generated files will be available under `${MUSTC_ROOT}/en-${TARGET_LANG_ID}` (per-language data) and -`MUSTC_ROOT` (joint data). - -#### ASR -###### Training -ASR data from En-De as example: -```bash -fairseq-train ${MUSTC_ROOT}/en-de --train-subset train_asr --valid-subset dev_asr --save-dir ${ASR_SAVE_DIR} \ - --num-workers 4 --max-tokens 40000 --task speech_to_text --criterion label_smoothed_cross_entropy \ - --report-accuracy --max-update 100000 --arch s2t_transformer_s --optimizer adam --lr 1e-3 \ - --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 -``` -Using joint data from all directions: -```bash -fairseq-train ${MUSTC_ROOT} \ - --train-subset train_de_asr,train_nl_asr,train_es_asr,train_fr_asr,train_it_asr,train_pt_asr,train_ro_asr,train_ru_asr \ - --valid-subset dev_de_asr,dev_nl_asr,dev_es_asr,dev_fr_asr,dev_it_asr,dev_pt_asr,dev_ro_asr,dev_ru_asr \ - --save-dir ${JOINT_ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --task speech_to_text --arch s2t_transformer_s \ - --criterion label_smoothed_cross_entropy --report-accuracy --max-update 100000 --optimizer adam --lr 1e-3 \ - --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 -``` -where `ASR_SAVE_DIR` (`JOINT_ASR_SAVE_DIR`) is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs -with 1 GPU. You may want to update it accordingly when using more than 1 GPU. - -###### Inference & Evaluation -```bash -CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt -python scripts/average_checkpoints.py --inputs ${ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ - --output "${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" -fairseq-generate ${MUSTC_ROOT}/en-de --gen-subset tst-COMMON_asr --task speech_to_text \ - --path ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ - --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct - -# For models trained on joint data -python scripts/average_checkpoints.py --inputs ${JOINT_ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ - --output "${JOINT_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" -for LANG in de nl es fr it pt ro ru; do - fairseq-generate ${MUSTC_ROOT} --gen-subset tst-COMMON_${LANG}_asr --task speech_to_text \ - --path ${JOINT_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ - --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct -done -``` -###### Result -| Data | --arch | Params | En-De | En-Nl | En-Es | En-Fr | En-It | En-Pt | En-Ro | En-Ru | -|---|---|---|---|---|---|---|---|---|---|---| -| Single | s2t_transformer_s | 31M | 18.2 | 17.6 | 17.7 | 17.2 | 17.9 | 19.1 | 18.1 | 17.7 | -| Joint | s2t_transformer_m | 76M | 16.8 | 16.7 | 16.9 | 16.9 | 17.0 | 17.4 | 17.0 | 16.9 | - -#### ST -###### Training -En-De as example: -```bash -fairseq-train ${MUSTC_ROOT}/en-de --train-subset train_st --valid-subset dev_st --save-dir ${ST_SAVE_DIR} \ - --num-workers 4 --max-tokens 40000 --task speech_to_text --criterion label_smoothed_cross_entropy \ - --report-accuracy --max-update 100000 --arch s2t_transformer_s --optimizer adam --lr 2e-3 \ - --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ - --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} -``` -Example for multilingual models: -```bash -fairseq-train ${MUSTC_ROOT} \ - --train-subset train_de_st,train_nl_st,train_es_st,train_fr_st,train_it_st,train_pt_st,train_ro_st,train_ru_st \ - --valid-subset dev_de_st,dev_nl_st,dev_es_st,dev_fr_st,dev_it_st,dev_pt_st,dev_ro_st,dev_ru_st \ - --save-dir ${MULTILINGUAL_ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --task speech_to_text \ - --arch s2t_transformer_s --criterion label_smoothed_cross_entropy --report-accuracy --ignore-prefix-size 1 \ - --max-update 100000 --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 \ - --seed 1 --update-freq 8 --load-pretrained-encoder-from ${JOINT_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} -``` -where `ST_SAVE_DIR` (`MULTILINGUAL_ST_SAVE_DIR`) is the checkpoint root path. The ST encoder is pre-trained by ASR -for faster training and better performance: `--load-pretrained-encoder-from <(JOINT_)ASR checkpoint path>`. We set -`--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly when using more than 1 GPU. -For multilingual models, we prepend target language ID token as target BOS, which should be excluded from -the training loss via `--ignore-prefix-size 1`. +## Updates +- 01/08/2021: Several fixes for S2T Transformer model, inference-time de-tokenization, scorer configuration and data + preparation scripts. We also add pre-trained models to the examples and revise the instructions. + Breaking changes: the data preparation scripts now extract filterbank features without CMVN. CMVN is instead applied + on-the-fly (defined in the config YAML). -###### Inference & Evaluation -Average the last 10 checkpoints and evaluate on the `tst-COMMON` split: -```bash -CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt -python scripts/average_checkpoints.py --inputs ${ST_SAVE_DIR} --num-epoch-checkpoints 10 \ - --output "${ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" -fairseq-generate ${MUSTC_ROOT} --gen-subset tst-COMMON_st --task speech_to_text \ - --path ${ST_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 --scoring sacrebleu - -# For multilingual models -python scripts/average_checkpoints.py --inputs ${MULTILINGUAL_ST_SAVE_DIR} --num-epoch-checkpoints 10 \ - --output "${MULTILINGUAL_ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" -for LANG in de nl es fr it pt ro ru; do - fairseq-generate ${MUSTC_ROOT} --gen-subset tst-COMMON_${LANG}_st --task speech_to_text --prefix-size 1 \ - --path ${MULTILINGUAL_ST_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 --scoring sacrebleu -done -``` -For multilingual models, we force decoding from the target language ID token (as BOS) via `--prefix-size 1`. - -###### Result -| Data | --arch | Params | En-De | En-Nl | En-Es | En-Fr | En-It | En-Pt | En-Ro | En-Ru | -|---|---|---|---|---|---|---|---|---|---|---| -| Bilingual | s2t_transformer_s | 31M | 22.7 | 27.3 | 27.2 | 32.9 | 22.7 | 28.1 | 21.9 | 15.3 | -| Multilingual | s2t_transformer_m | 76M | 24.5 | 28.6 | 28.2 | 34.9 | 24.6 | 31.1 | 23.8 | 16.0 | - - -## Example 3: ST on CoVoST -We replicate the experiments in -[CoVoST 2 and Massively Multilingual Speech-to-Text Translation (Wang et al., 2020)](https://arxiv.org/abs/2007.10310). - -#### Data Preparation -Download and preprocess [CoVoST (version 2)](https://arxiv.org/abs/2007.10310) data with -```bash -# En ASR -python examples/speech_to_text/prep_covost_data.py --data-root ${COVOST_ROOT} --vocab-type char --src-lang en -# ST -python examples/speech_to_text/prep_covost_data.py --data-root ${COVOST_ROOT} --vocab-type char \ - --src-lang fr --tgt-lang en -``` -where `COVOST_ROOT` is the root path for downloaded data as well as generated manifest and feature files. - -#### ASR -###### Training -```bash -fairseq-train ${COVOST_ROOT} --train-subset train_asr --valid-subset dev_asr --save-dir ${ASR_SAVE_DIR} \ - --num-workers 4 --max-tokens 40000 --task speech_to_text --criterion label_smoothed_cross_entropy \ - --report-accuracy --max-update 100000 --arch s2t_transformer_s --optimizer adam --lr 1e-3 \ - --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 -``` -where `ASR_SAVE_DIR` is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. -You may want to update it accordingly when using more than 1 GPU. - -###### Inference & Evaluation -```bash -CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt -python scripts/average_checkpoints.py --inputs ${ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ - --output "${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" -fairseq-generate ${COVOST_ROOT} --gen-subset test_asr_en --task speech_to_text \ - --path ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ - --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct -``` -###### Result -| --arch | Params | En | -|---|---|---| -| s2t_transformer_s | 31M | 25.6 | - -#### ST -###### Training -```bash -fairseq-train ${COVOST_ROOT} --train-subset train_st_fr_en --valid-subset dev_st_fr_en --save-dir ${ST_SAVE_DIR} \ - --num-workers 4 --max-tokens 40000 --task speech_to_text --criterion label_smoothed_cross_entropy \ - --report-accuracy --max-update 100000 --arch s2t_transformer_s --optimizer adam --lr 2e-3 \ - --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ - --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} -``` -where `ST_SAVE_DIR` is the checkpoint root path. The ST encoder is pre-trained by En ASR for faster training and better -performance: `--load-pretrained-encoder-from `. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. -You may want to update it accordingly when using more than 1 GPU. - -###### Inference & Evaluation -Average the last 10 checkpoints and evaluate on test split: -```bash -CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt -python scripts/average_checkpoints.py --inputs ${ST_SAVE_DIR} --num-epoch-checkpoints 10 \ - --output "${ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" -fairseq-generate ${COVOST_ROOT} --gen-subset test_st_fr_en --task speech_to_text \ - --path ${ST_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 --scoring sacrebleu -``` - -###### Result -| --arch | Params | Fr-En | De-En | Es-En | Ca-En | En-De | En-Ca | En-Fa | En-Et | -|---|---|---|---|---|---|---|---|---|---| -| s2t_transformer_s | 31M | 26.3 | 17.1 | 23.0 | 18.8 | 16.3 | 21.8 | 13.1 | 13.2 | +## What's Next +- We are migrating the old fairseq [ASR example](../speech_recognition) into this S2T framework and + merging the features from both sides. +- The following papers also base their experiments on fairseq S2T. We are adding more examples for replication. + - [Improving Cross-Lingual Transfer Learning for End-to-End Speech Recognition with Speech Translation (Wang et al., 2020)](https://arxiv.org/abs/2006.05474) + - [Self-Supervised Representations Improve End-to-End Speech Translation (Wu et al., 2020)](https://arxiv.org/abs/2006.12124) + - [Self-Training for End-to-End Speech Translation (Pino et al., 2020)](https://arxiv.org/abs/2006.02490) + - [CoVoST: A Diverse Multilingual Speech-To-Text Translation Corpus (Wang et al., 2020)](https://arxiv.org/abs/2002.01320) + - [Harnessing Indirect Training Data for End-to-End Automatic Speech Translation: Tricks of the Trade (Pino et al., 2019)](https://arxiv.org/abs/1909.06515) ## Citation Please cite as: @@ -272,12 +64,3 @@ Please cite as: year = {2019}, } ``` - -## More Paper Code -The following papers also base their experiments on fairseq S2T. We are adding more examples for replication. - -- [Improving Cross-Lingual Transfer Learning for End-to-End Speech Recognition with Speech Translation (Wang et al., 2020)](https://arxiv.org/abs/2006.05474) -- [Self-Supervised Representations Improve End-to-End Speech Translation (Wu et al., 2020)](https://arxiv.org/abs/2006.12124) -- [Self-Training for End-to-End Speech Translation (Pino et al., 2020)](https://arxiv.org/abs/2006.02490) -- [CoVoST: A Diverse Multilingual Speech-To-Text Translation Corpus (Wang et al., 2020)](https://arxiv.org/abs/2002.01320) -- [Harnessing Indirect Training Data for End-to-End Automatic Speech Translation: Tricks of the Trade (Pino et al., 2019)](https://arxiv.org/abs/1909.06515) diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index 083d7316cd..0d7c034419 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -5,19 +5,16 @@ # LICENSE file in the root directory of this source tree. import csv -import os -import os.path as op +from pathlib import Path import zipfile from functools import reduce -from glob import glob from multiprocessing import cpu_count -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional, Union import numpy as np import pandas as pd import sentencepiece as sp from fairseq.data.audio.audio_utils import _get_kaldi_fbank, _get_torchaudio_fbank -from fairseq.data.audio.feature_transforms.utterance_cmvn import UtteranceCMVN from tqdm import tqdm @@ -28,12 +25,13 @@ def gen_vocab( - input_path: str, output_path_prefix: str, model_type="bpe", vocab_size=1000, + input_path: Path, output_path_prefix: Path, model_type="bpe", + vocab_size=1000, special_symbols: Optional[List[str]] = None ): # Train SentencePiece Model arguments = [ - f"--input={input_path}", - f"--model_prefix={output_path_prefix}", + f"--input={input_path.as_posix()}", + f"--model_prefix={output_path_prefix.as_posix()}", f"--model_type={model_type}", f"--vocab_size={vocab_size}", "--character_coverage=1.0", @@ -43,10 +41,13 @@ def gen_vocab( f"--eos_id={EOS_TOKEN_ID}", f"--pad_id={PAD_TOKEN_ID}", ] + if special_symbols is not None: + _special_symbols = ",".join(special_symbols) + arguments.append(f"--user_defined_symbols={_special_symbols}") sp.SentencePieceTrainer.Train(" ".join(arguments)) # Export fairseq dictionary spm = sp.SentencePieceProcessor() - spm.Load(output_path_prefix + ".model") + spm.Load(output_path_prefix.as_posix() + ".model") vocab = {i: spm.IdToPiece(i) for i in range(spm.GetPieceSize())} assert ( vocab.get(UNK_TOKEN_ID) == UNK_TOKEN @@ -59,20 +60,19 @@ def gen_vocab( for i, s in vocab.items() if s not in {UNK_TOKEN, BOS_TOKEN, EOS_TOKEN, PAD_TOKEN} } - with open(output_path_prefix + ".txt", "w") as f_out: + with open(output_path_prefix.as_posix() + ".txt", "w") as f_out: for _, s in sorted(vocab.items(), key=lambda x: x[0]): f_out.write(f"{s} 1\n") def extract_fbank_features( waveform, - sample_rate, - output_path=None, - n_mel_bins=80, - apply_utterance_cmvn=True, - overwrite=False, + sample_rate: int, + output_path: Optional[Path] = None, + n_mel_bins: int = 80, + overwrite: bool = False, ): - if output_path is not None and op.exists(output_path) and not overwrite: + if output_path is not None and output_path.is_file() and not overwrite: return _waveform = waveform * (2 ** 15) # Kaldi compliance: 16-bit signed integers @@ -83,42 +83,36 @@ def extract_fbank_features( features = _get_torchaudio_fbank(_waveform, sample_rate, n_mel_bins) if features is None: raise ImportError( - "Please install pyKaldi or torchaudio to enable " - "online filterbank feature extraction" + "Please install pyKaldi or torchaudio to enable fbank feature extraction" ) - if apply_utterance_cmvn: - cmvn = UtteranceCMVN(norm_means=True, norm_vars=True) - features = cmvn(features) if output_path is not None: - np.save(output_path, features) + np.save(output_path.as_posix(), features) else: return features -def create_zip(data_root, zip_path): - cwd = os.path.abspath(os.curdir) - os.chdir(data_root) +def create_zip(data_root: Path, zip_path: Path): + paths = list(data_root.glob("*.npy")) with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_STORED) as f: - for filename in tqdm(glob("*.npy")): - f.write(filename) - os.chdir(cwd) + for path in tqdm(paths): + f.write(path, arcname=path.name) def is_npy_data(data: bytes) -> bool: return data[0] == 147 and data[1] == 78 -def get_zip_manifest(zip_root, zip_filename): - zip_path = op.join(zip_root, zip_filename) - with zipfile.ZipFile(zip_path, mode="r") as f: +def get_zip_manifest(zip_path: Path, zip_root: Optional[Path] = None): + _zip_path = zip_path if zip_root is None else Path.joinpath(zip_root, zip_path) + with zipfile.ZipFile(_zip_path, mode="r") as f: info = f.infolist() manifest = {} for i in tqdm(info): - utt_id = op.splitext(i.filename)[0] + utt_id = Path(i.filename).stem offset, file_size = i.header_offset + 30 + len(i.filename), i.file_size - manifest[utt_id] = f"{zip_filename}:{offset}:{file_size}" - with open(zip_path, "rb") as f: + manifest[utt_id] = f"{zip_path.as_posix()}:{offset}:{file_size}" + with open(_zip_path, "rb") as f: f.seek(offset) data = f.read(file_size) assert len(data) > 1 and is_npy_data(data) @@ -126,16 +120,16 @@ def get_zip_manifest(zip_root, zip_filename): def gen_config_yaml( - data_root, - spm_filename, - yaml_filename="config.yaml", - specaugment_policy="lb", - prepend_tgt_lang_tag=False, - sampling_alpha=1.0, + manifest_root: Path, + spm_filename: str, + yaml_filename: str = "config.yaml", + specaugment_policy: str = "lb", + prepend_tgt_lang_tag: bool = False, + sampling_alpha: float = 1.0, + audio_root: str = "" ): - data_root = op.abspath(data_root) - writer = S2TDataConfigWriter(op.join(data_root, yaml_filename)) - writer.set_audio_root(op.abspath(data_root)) + manifest_root = manifest_root.absolute() + writer = S2TDataConfigWriter(manifest_root / yaml_filename) writer.set_vocab_filename(spm_filename.replace(".model", ".txt")) writer.set_input_channels(1) writer.set_input_feat_per_channel(80) @@ -145,24 +139,29 @@ def gen_config_yaml( "sm": writer.set_specaugment_sm_policy, "ss": writer.set_specaugment_ss_policy, } - assert specaugment_policy in specaugment_setters - specaugment_setters[specaugment_policy]() + specaugment_setter = specaugment_setters.get(specaugment_policy, None) + if specaugment_setter is not None: + specaugment_setter() writer.set_bpe_tokenizer( { "bpe": "sentencepiece", - "sentencepiece_model": op.join(data_root, spm_filename), + "sentencepiece_model": (manifest_root / spm_filename).as_posix(), } ) if prepend_tgt_lang_tag: writer.set_prepend_tgt_lang_tag(True) writer.set_sampling_alpha(sampling_alpha) - writer.set_feature_transforms("_train", ["specaugment"]) + writer.set_feature_transforms("_train", ["utterance_cmvn", "specaugment"]) + writer.set_feature_transforms("*", ["utterance_cmvn"]) + if len(audio_root) > 0: + writer.set_audio_root(audio_root) writer.flush() -def load_df_from_tsv(path: str): +def load_df_from_tsv(path: Union[str, Path]): + _path = path if isinstance(path, str) else path.as_posix() return pd.read_csv( - path, + _path, sep="\t", header=0, encoding="utf-8", @@ -172,9 +171,10 @@ def load_df_from_tsv(path: str): ) -def save_df_to_tsv(dataframe, path): +def save_df_to_tsv(dataframe, path: Union[str, Path]): + _path = path if isinstance(path, str) else path.as_posix() dataframe.to_csv( - path, + _path, sep="\t", header=True, index=False, @@ -211,11 +211,11 @@ class S2TDataConfigWriter(object): DEFAULT_INPUT_FEAT_PER_CHANNEL = 80 DEFAULT_INPUT_CHANNELS = 1 - def __init__(self, yaml_path): + def __init__(self, yaml_path: Path): try: import yaml except ImportError: - print("Please install PyYAML to load YAML files for S2T data config") + print("Please install PyYAML for S2T data config YAML files") self.yaml = yaml self.yaml_path = yaml_path self.config = {} @@ -227,7 +227,7 @@ def flush(self): def set_audio_root(self, audio_root=""): self.config["audio_root"] = audio_root - def set_vocab_filename(self, vocab_filename="dict.txt"): + def set_vocab_filename(self, vocab_filename: str = "dict.txt"): self.config["vocab_filename"] = vocab_filename def set_specaugment( @@ -288,22 +288,22 @@ def set_specaugment_ss_policy(self): time_mask_p=0.2, ) - def set_input_channels(self, input_channels=1): + def set_input_channels(self, input_channels: int = 1): self.config["input_channels"] = input_channels - def set_input_feat_per_channel(self, input_feat_per_channel=80): + def set_input_feat_per_channel(self, input_feat_per_channel: int = 80): self.config["input_feat_per_channel"] = input_feat_per_channel def set_bpe_tokenizer(self, bpe_tokenizer: Dict[str, Any]): self.config["bpe_tokenizer"] = bpe_tokenizer - def set_feature_transforms(self, split, transforms: List[str]): + def set_feature_transforms(self, split: str, transforms: List[str]): if "transforms" not in self.config: self.config["transforms"] = {} self.config["transforms"][split] = transforms - def set_prepend_tgt_lang_tag(self, flag=True): + def set_prepend_tgt_lang_tag(self, flag: bool = True): self.config["prepend_tgt_lang_tag"] = flag - def set_sampling_alpha(self, sampling_alpha=1.0): + def set_sampling_alpha(self, sampling_alpha: float = 1.0): self.config["sampling_alpha"] = sampling_alpha diff --git a/examples/speech_to_text/docs/covost_example.md b/examples/speech_to_text/docs/covost_example.md new file mode 100644 index 0000000000..a4ce8a10e4 --- /dev/null +++ b/examples/speech_to_text/docs/covost_example.md @@ -0,0 +1,93 @@ +[[Back]](..) + +# S2T Example: ST on CoVoST +We replicate the experiments in +[CoVoST 2 and Massively Multilingual Speech-to-Text Translation (Wang et al., 2020)](https://arxiv.org/abs/2007.10310). + +## Data Preparation +[Download](https://commonvoice.mozilla.org/en/datasets) and unpack Common Voice v4 to a path +`${COVOST_ROOT}/${SOURCE_LANG_ID}`, then preprocess it with +```bash +# additional Python packages for S2T data processing/model training +pip install pandas torchaudio sentencepiece + +# En ASR +python examples/speech_to_text/prep_covost_data.py \ + --data-root ${COVOST_ROOT} --vocab-type char --src-lang en +# ST +python examples/speech_to_text/prep_covost_data.py \ + --data-root ${COVOST_ROOT} --vocab-type char \ + --src-lang fr --tgt-lang en +``` +The generated files (manifest, features, vocabulary and data configuration) will be added to +`${COVOST_ROOT}/${SOURCE_LANG_ID}`. + +Download our vocabulary files if you want to use our pre-trained models: +- ASR: [En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_asr_vocab_char.zip) +- ST: [Fr-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_vocab_char.zip), [De-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_vocab_char.zip), [Es-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_vocab_char.zip), [Ca-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_vocab_char.zip), [En-De](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_vocab_char.zip), [En-Ca](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_vocab_char.zip), [En-Fa](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_vocab_char.zip), [En-Et](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_vocab_char.zip) + +## ASR +#### Training +We train an En ASR model for encoder pre-training of all ST models: +```bash +fairseq-train ${COVOST_ROOT}/en \ + --config-yaml config_asr_en.yaml --train-subset train_asr_en --valid-subset dev_asr_en \ + --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 60000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 +``` +where `ASR_SAVE_DIR` is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. +You may want to update it accordingly when using more than 1 GPU. + +#### Inference & Evaluation +```bash +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py \ + --inputs ${ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" +fairseq-generate ${COVOST_ROOT}/en \ + --config-yaml config_asr_en.yaml --gen-subset test_asr_en --task speech_to_text \ + --path ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ + --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct +``` +#### Results +| --arch | Params | En | Model | +|---|---|---|---| +| s2t_transformer_s | 31M | 25.6 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_asr_transformer_s.pt) | + +## ST +#### Training +Fr-En as example: +```bash +fairseq-train ${COVOST_ROOT}/fr \ + --config-yaml config_st_fr_en.yaml --train-subset train_st_fr_en --valid-subset dev_st_fr_en \ + --save-dir ${ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 60000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ + --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} +``` +where `ST_SAVE_DIR` is the checkpoint root path. The ST encoder is pre-trained by En ASR for faster training and better +performance: `--load-pretrained-encoder-from `. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. +You may want to update it accordingly when using more than 1 GPU. + +#### Inference & Evaluation +Average the last 10 checkpoints and evaluate on test split: +```bash +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py \ + --inputs ${ST_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" +fairseq-generate ${COVOST_ROOT}/fr \ + --config-yaml config_st_fr_en.yaml --gen-subset test_st_fr_en --task speech_to_text \ + --path ${ST_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 50000 --beam 5 --scoring sacrebleu +``` + +#### Results +| --arch | Params | Fr-En | De-En | Es-En | Ca-En | En-De | En-Ca | En-Fa | En-Et | Model | +|---|---|---|---|---|---|---|---|---|---|---| +| s2t_transformer_s | 31M | [26.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_transformer_s.pt) | [17.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_transformer_s.pt) | [23.0](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_transformer_s.pt) | [18.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_transformer_s.pt) | [16.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_transformer_s.pt) | [21.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_transformer_s.pt) | [13.0](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_transformer_s.pt) | [13.2](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_transformer_s.pt) | (<-Download) | + +[[Back]](..) diff --git a/examples/speech_to_text/docs/librispeech_example.md b/examples/speech_to_text/docs/librispeech_example.md new file mode 100644 index 0000000000..21b754ee11 --- /dev/null +++ b/examples/speech_to_text/docs/librispeech_example.md @@ -0,0 +1,61 @@ +[[Back]](..) + +# S2T Example: Speech Recognition (ASR) on LibriSpeech +[LibriSpeech](https://www.danielpovey.com/files/2015_icassp_librispeech.pdf) is a de-facto standard English ASR +benchmark. We provide competitive +vanilla [Transformer](https://papers.nips.cc/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf) baselines. + +## Data preparation +Download and preprocess LibriSpeech data with +```bash +# additional Python packages for S2T data processing/model training +pip install pandas torchaudio sentencepiece + +python examples/speech_to_text/prep_librispeech_data.py \ + --output-root ${LS_ROOT} --vocab-type unigram --vocab-size 10000 +``` +where `LS_ROOT` is the root path for downloaded data as well as generated files (manifest, features, vocabulary and +data configuration). + +[Download](https://dl.fbaipublicfiles.com/fairseq/s2t/librispeech_vocab_unigram10000.zip) our vocabulary files +if you want to use our pre-trained models. + +## Training +```bash +fairseq-train ${LS_ROOT} --save-dir ${SAVE_DIR} \ + --config-yaml config.yaml --train-subset train --valid-subset dev \ + --num-workers 4 --max-tokens 40000 --max-update 300000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --share-decoder-input-output-embed \ + --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt --warmup-updates 10000 \ + --clip-norm 10.0 --seed 1 --update-freq 8 +``` +where `SAVE_DIR` is the checkpoint root path. Here we use `--arch s2t_transformer_s` (31M parameters) as example. +For better performance, you may switch to `s2t_transformer_m` (71M, with `--lr 1e-3`) or `s2t_transformer_l` +(268M, with `--lr 5e-4`). We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly +when using more than 1 GPU. + +## Inference & Evaluation +Average the last 10 checkpoints and evaluate on the 4 splits +(`dev-clean`, `dev-other`, `test-clean` and `test-other`): +```bash +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py --inputs ${SAVE_DIR} \ + --num-epoch-checkpoints 10 \ + --output "${SAVE_DIR}/${CHECKPOINT_FILENAME}" +for SUBSET in dev-clean dev-other test-clean test-other; do + fairseq-generate ${LS_ROOT} --config-yaml config.yaml --gen-subset ${SUBSET} \ + --task speech_to_text --path ${SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 50000 --beam 5 --scoring wer +done +``` + +## Results + +| --arch | Params | dev-clean | dev-other | test-clean | test-other | Model | +|---|---|---|---|---|---|---| +| s2t_transformer_s | 30M | 3.8 | 8.9 | 4.4 | 9.0 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/librispeech_transformer_s.pt) | +| s2t_transformer_m | 71M | 3.2 | 8.0 | 3.4 | 7.9 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/librispeech_transformer_m.pt) | +| s2t_transformer_l | 268M | 3.0 | 7.5 | 3.2 | 7.5 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/librispeech_transformer_l.pt) | + +[[Back]](..) diff --git a/examples/speech_to_text/docs/mustc_example.md b/examples/speech_to_text/docs/mustc_example.md new file mode 100644 index 0000000000..7628dc77ef --- /dev/null +++ b/examples/speech_to_text/docs/mustc_example.md @@ -0,0 +1,155 @@ +[[Back]](..) + +# S2T Example: Speech Translation (ST) on MuST-C + +[MuST-C](https://www.aclweb.org/anthology/N19-1202) is multilingual speech-to-text translation corpus with +8-language translations on English TED talks. We match the state-of-the-art performance in +[ESPNet-ST](https://arxiv.org/pdf/2004.10234.pdf) with a simpler model training pipeline. + +## Data Preparation +[Download](https://ict.fbk.eu/must-c) and unpack MuST-C data to a path +`${MUSTC_ROOT}/en-${TARGET_LANG_ID}`, then preprocess it with +```bash +# additional Python packages for S2T data processing/model training +pip install pandas torchaudio sentencepiece + +# Generate TSV manifests, features, vocabulary +# and configuration for each language +python examples/speech_to_text/prep_mustc_data.py \ + --data-root ${MUSTC_ROOT} --task asr \ + --vocab-type unigram --vocab-size 5000 +python examples/speech_to_text/prep_mustc_data.py \ + --data-root ${MUSTC_ROOT} --task st \ + --vocab-type unigram --vocab-size 8000 + +# Add vocabulary and configuration for joint data +# (based on the manifests and features generated above) +python examples/speech_to_text/prep_mustc_data.py \ + --data-root ${MUSTC_ROOT} --task asr --joint \ + --vocab-type unigram --vocab-size 10000 +python examples/speech_to_text/prep_mustc_data.py \ + --data-root ${MUSTC_ROOT} --task st --joint \ + --vocab-type unigram --vocab-size 10000 +``` +The generated files (manifest, features, vocabulary and data configuration) will be added to +`${MUSTC_ROOT}/en-${TARGET_LANG_ID}` (per-language data) and `MUSTC_ROOT` (joint data). + +Download our vocabulary files if you want to use our pre-trained models: +- ASR: [En-De](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_de_asr_vocab_unigram5000.zip), [En-Nl](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_nl_asr_vocab_unigram5000.zip), [En-Es](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_es_asr_vocab_unigram5000.zip), [En-Fr](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_fr_asr_vocab_unigram5000.zip), [En-It](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_it_asr_vocab_unigram5000.zip), [En-Pt](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_pt_asr_vocab_unigram5000.zip), [En-Ro](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ro_asr_vocab_unigram5000.zip), [En-Ru](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ru_asr_vocab_unigram5000.zip), [Joint](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_joint_asr_vocab_unigram10000.zip) +- ST: [En-De](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_de_st_vocab_unigram8000.zip), [En-Nl](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_nl_st_vocab_unigram8000.zip), [En-Es](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_es_st_vocab_unigram8000.zip), [En-Fr](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_fr_st_vocab_unigram8000.zip), [En-It](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_it_st_vocab_unigram8000.zip), [En-Pt](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_pt_st_vocab_unigram8000.zip), [En-Ro](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ro_st_vocab_unigram8000.zip), [En-Ru](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ru_st_vocab_unigram8000.zip), [Multilingual](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_multilingual_st_vocab_unigram10000.zip) + +## ASR +#### Training +En-De as example: +```bash +fairseq-train ${MUSTC_ROOT}/en-de \ + --config-yaml config_asr.yaml --train-subset train_asr --valid-subset dev_asr \ + --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --optimizer adam --lr 1e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 +``` +For joint model (using ASR data from all 8 directions): +```bash +fairseq-train ${MUSTC_ROOT} \ + --config-yaml config_asr.yaml \ + --train-subset train_de_asr,train_nl_asr,train_es_asr,train_fr_asr,train_it_asr,train_pt_asr,train_ro_asr,train_ru_asr \ + --valid-subset dev_de_asr,dev_nl_asr,dev_es_asr,dev_fr_asr,dev_it_asr,dev_pt_asr,dev_ro_asr,dev_ru_asr \ + --save-dir ${JOINT_ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --optimizer adam --lr 1e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 +``` +where `ASR_SAVE_DIR` (`JOINT_ASR_SAVE_DIR`) is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs +with 1 GPU. You may want to update it accordingly when using more than 1 GPU. + +#### Inference & Evaluation +```bash +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py \ + --inputs ${ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" +fairseq-generate ${MUSTC_ROOT}/en-de \ + --config-yaml config_asr.yaml --gen-subset tst-COMMON_asr --task speech_to_text \ + --path ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ + --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct + +# For models trained on joint data +python scripts/average_checkpoints.py \ + --inputs ${JOINT_ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${JOINT_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" +for LANG in de nl es fr it pt ro ru; do + fairseq-generate ${MUSTC_ROOT} \ + --config-yaml config_asr.yaml --gen-subset tst-COMMON_${LANG}_asr --task speech_to_text \ + --path ${JOINT_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ + --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct +done +``` +#### Results +| Data | --arch | Params | En-De | En-Nl | En-Es | En-Fr | En-It | En-Pt | En-Ro | En-Ru | Model | +|---|---|---|---|---|---|---|---|---|---|---|---| +| Single | s2t_transformer_s | 31M | [18.2](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_de_asr_transformer_s.pt) | [17.6](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_nl_asr_transformer_s.pt) | [17.7](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_es_asr_transformer_s.pt) | [17.2](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_fr_asr_transformer_s.pt) | [17.9](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_it_asr_transformer_s.pt) | [19.1](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_pt_asr_transformer_s.pt) | [18.1](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ro_asr_transformer_s.pt) | [17.7](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ru_asr_transformer_s.pt) | (<-Download) | +| Joint | s2t_transformer_m | 76M | 16.8 | 16.7 | 16.9 | 16.9 | 17.0 | 17.4 | 17.0 | 16.9 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_joint_asr_transformer_m.pt) | + +## ST +#### Training +En-De as example: +```bash +fairseq-train ${MUSTC_ROOT}/en-de \ + --config-yaml config_st.yaml --train-subset train_st --valid-subset dev_st \ + --save-dir ${ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ + --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} +``` +For multilingual model (all 8 directions): +```bash +fairseq-train ${MUSTC_ROOT} \ + --config-yaml config_st.yaml \ + --train-subset train_de_st,train_nl_st,train_es_st,train_fr_st,train_it_st,train_pt_st,train_ro_st,train_ru_st \ + --valid-subset dev_de_st,dev_nl_st,dev_es_st,dev_fr_st,dev_it_st,dev_pt_st,dev_ro_st,dev_ru_st \ + --save-dir ${MULTILINGUAL_ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --ignore-prefix-size 1 --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ + --load-pretrained-encoder-from ${JOINT_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} +``` +where `ST_SAVE_DIR` (`MULTILINGUAL_ST_SAVE_DIR`) is the checkpoint root path. The ST encoder is pre-trained by ASR +for faster training and better performance: `--load-pretrained-encoder-from <(JOINT_)ASR checkpoint path>`. We set +`--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly when using more than 1 GPU. +For multilingual models, we prepend target language ID token as target BOS, which should be excluded from +the training loss via `--ignore-prefix-size 1`. + +#### Inference & Evaluation +Average the last 10 checkpoints and evaluate on the `tst-COMMON` split: +```bash +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py \ + --inputs ${ST_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" +fairseq-generate ${MUSTC_ROOT}/en-de \ + --config-yaml config_st.yaml --gen-subset tst-COMMON_st --task speech_to_text \ + --path ${ST_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 50000 --beam 5 --scoring sacrebleu + +# For multilingual models +python scripts/average_checkpoints.py \ + --inputs ${MULTILINGUAL_ST_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${MULTILINGUAL_ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" +for LANG in de nl es fr it pt ro ru; do + fairseq-generate ${MUSTC_ROOT} \ + --config-yaml config_st.yaml --gen-subset tst-COMMON_${LANG}_st --task speech_to_text \ + --prefix-size 1 --path ${MULTILINGUAL_ST_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 50000 --beam 5 --scoring sacrebleu +done +``` +For multilingual models, we force decoding from the target language ID token (as BOS) via `--prefix-size 1`. + +#### Results +| Data | --arch | Params | En-De | En-Nl | En-Es | En-Fr | En-It | En-Pt | En-Ro | En-Ru | Model | +|---|---|---|---|---|---|---|---|---|---|---|---| +| Bilingual | s2t_transformer_s | 31M | [22.7](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_de_st_transformer_s.pt) | [27.3](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_nl_st_transformer_s.pt) | [27.2](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_es_st_transformer_s.pt) | [32.9](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_fr_st_transformer_s.pt) | [22.7](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_it_st_transformer_s.pt) | [28.1](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_pt_st_transformer_s.pt) | [21.9](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ro_st_transformer_s.pt) | [15.3](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_ru_st_transformer_s.pt) | (<-Download) | +| Multilingual | s2t_transformer_m | 76M | 24.5 | 28.6 | 28.2 | 34.9 | 24.6 | 31.1 | 23.8 | 16.0 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_multilingual_st_transformer_m.pt) | + +[[Back]](..) diff --git a/examples/speech_to_text/prep_covost_data.py b/examples/speech_to_text/prep_covost_data.py index e8a028b446..af1d3fc6b8 100644 --- a/examples/speech_to_text/prep_covost_data.py +++ b/examples/speech_to_text/prep_covost_data.py @@ -5,10 +5,8 @@ # LICENSE file in the root directory of this source tree. import argparse -import csv import logging -import os -import os.path as op +from pathlib import Path import shutil from tempfile import NamedTemporaryFile from typing import Optional, Tuple @@ -22,6 +20,7 @@ gen_config_yaml, gen_vocab, get_zip_manifest, + load_df_from_tsv, save_df_to_tsv, ) from torch import Tensor @@ -49,10 +48,6 @@ class CoVoST(Dataset): found at root path. (default: ``False``). """ - CV_URL_TEMPLATE = ( - "https://voice-prod-bundler-ee1969a6ce8178826482b88" - "e843c335139bd3fb4.s3.amazonaws.com/{ver}/{lang}.tar.gz" - ) COVOST_URL_TEMPLATE = ( "https://dl.fbaipublicfiles.com/covost/" "covost_v2.{src_lang}_{tgt_lang}.tsv.tar.gz" @@ -61,8 +56,6 @@ class CoVoST(Dataset): VERSIONS = {2} SPLITS = ["train", "dev", "test"] - CV_VERSION_ID = {1: "cv-corpus-3", 2: "cv-corpus-4-2019-12-10"} - XX_EN_LANGUAGES = { 1: ["fr", "de", "nl", "ru", "es", "it", "tr", "fa", "sv-SE", "mn", "zh-CN"], 2: [ @@ -117,7 +110,6 @@ def __init__( source_language: str, target_language: Optional[str] = None, version: int = 2, - download: bool = False, ) -> None: assert version in self.VERSIONS and split in self.SPLITS assert source_language is not None @@ -134,30 +126,22 @@ def __init__( # to Common Voice train split. target_language = "de" if source_language == "en" else "en" - self.root = os.path.join(root, "raw") - os.makedirs(self.root, exist_ok=True) + self.root: Path = Path(root) - cv_url = self.CV_URL_TEMPLATE.format( - ver=self.CV_VERSION_ID[version], lang=source_language - ) - cv_archive = os.path.join(self.root, os.path.basename(cv_url)) - if download: - if not os.path.isfile(cv_archive): - download_url(cv_url, self.root, hash_value=None) - extract_archive(cv_archive) + cv_tsv_path = self.root / "validated.tsv" + assert cv_tsv_path.is_file() covost_url = self.COVOST_URL_TEMPLATE.format( src_lang=source_language, tgt_lang=target_language ) - covost_archive = os.path.join(self.root, os.path.basename(covost_url)) - if download: - if not os.path.isfile(covost_archive): - download_url(covost_url, self.root, hash_value=None) - extract_archive(covost_archive) + covost_archive = self.root / Path(covost_url).name + if not covost_archive.is_file(): + download_url(covost_url, self.root.as_posix(), hash_value=None) + extract_archive(covost_archive.as_posix()) - cv_tsv = self.load_from_tsv(os.path.join(self.root, "validated.tsv")) - covost_tsv = self.load_from_tsv( - os.path.join(self.root, os.path.basename(covost_url).replace(".tar.gz", "")) + cv_tsv = load_df_from_tsv(cv_tsv_path) + covost_tsv = load_df_from_tsv( + self.root / Path(covost_url).name.replace(".tar.gz", "") ) df = pd.merge( left=cv_tsv[["path", "sentence", "client_id"]], @@ -169,20 +153,16 @@ def __init__( df = df[(df["split"] == split) | (df["split"] == f"{split}_covost")] else: df = df[df["split"] == split] - self.data = df.to_dict(orient="index").items() - self.data = [v for k, v in sorted(self.data, key=lambda x: x[0])] - - @classmethod - def load_from_tsv(cls, path: str): - return pd.read_csv( - path, - sep="\t", - header=0, - encoding="utf-8", - escapechar="\\", - quoting=csv.QUOTE_NONE, - na_filter=False, - ) + data = df.to_dict(orient="index").items() + data = [v for k, v in sorted(data, key=lambda x: x[0])] + self.data = [] + for e in data: + try: + path = self.root / "clips" / e["path"] + _ = torchaudio.info(path.as_posix()) + self.data.append(e) + except RuntimeError: + pass def __getitem__( self, n: int @@ -197,7 +177,7 @@ def __getitem__( sample_id)`` """ data = self.data[n] - path = os.path.join(self.root, "clips", data["path"]) + path = self.root / "clips" / data["path"] waveform, sample_rate = torchaudio.load(path) sentence = data["sentence"] translation = None if self.no_translation else data["translation"] @@ -210,26 +190,26 @@ def __len__(self) -> int: def process(args): - root = op.join(args.data_root, args.src_lang) - os.makedirs(root, exist_ok=True) + root = Path(args.data_root).absolute() / args.src_lang + if not root.is_dir(): + raise NotADirectoryError(f"{root} does not exist") # Extract features - feature_root = op.join(root, "fbank80") - os.makedirs(feature_root, exist_ok=True) + feature_root = root / "fbank80" + feature_root.mkdir(exist_ok=True) for split in CoVoST.SPLITS: print(f"Fetching split {split}...") - dataset = CoVoST(root, split, args.src_lang, args.tgt_lang, download=True) + dataset = CoVoST(root, split, args.src_lang, args.tgt_lang) print("Extracting log mel filter bank features...") for waveform, sample_rate, _, _, _, utt_id in tqdm(dataset): extract_fbank_features( - waveform, sample_rate, op.join(feature_root, f"{utt_id}.npy") + waveform, sample_rate, feature_root / f"{utt_id}.npy" ) # Pack features into ZIP - zip_filename = "fbank80.zip" - zip_path = op.join(root, zip_filename) + zip_path = root / "fbank80.zip" print("ZIPing features...") create_zip(feature_root, zip_path) print("Fetching ZIP manifest...") - zip_manifest = get_zip_manifest(args.data_root, f"{args.src_lang}/{zip_filename}") + zip_manifest = get_zip_manifest(zip_path) # Generate TSV manifest print("Generating manifest...") train_text = [] @@ -251,7 +231,7 @@ def process(args): train_text.extend(manifest["tgt_text"]) df = pd.DataFrame.from_dict(manifest) df = filter_manifest_df(df, is_train_split=is_train_split) - save_df_to_tsv(df, op.join(root, f"{split}_{task}.tsv")) + save_df_to_tsv(df, root / f"{split}_{task}.tsv") # Generate vocab vocab_size_str = "" if args.vocab_type == "char" else str(args.vocab_size) spm_filename_prefix = f"spm_{args.vocab_type}{vocab_size_str}_{task}" @@ -259,7 +239,10 @@ def process(args): for t in train_text: f.write(t + "\n") gen_vocab( - f.name, op.join(root, spm_filename_prefix), args.vocab_type, args.vocab_size + Path(f.name), + root / spm_filename_prefix, + args.vocab_type, + args.vocab_size ) # Generate config YAML gen_config_yaml( @@ -274,7 +257,10 @@ def process(args): def main(): parser = argparse.ArgumentParser() - parser.add_argument("--data-root", "-d", required=True, type=str) + parser.add_argument( + "--data-root", "-d", required=True, type=str, + help="data root with sub-folders for each language /" + ) parser.add_argument( "--vocab-type", default="unigram", diff --git a/examples/speech_to_text/prep_librispeech_data.py b/examples/speech_to_text/prep_librispeech_data.py index 95fcec8fe3..6a6f55ded4 100644 --- a/examples/speech_to_text/prep_librispeech_data.py +++ b/examples/speech_to_text/prep_librispeech_data.py @@ -6,8 +6,7 @@ import argparse import logging -import os -import os.path as op +from pathlib import Path import shutil from tempfile import NamedTemporaryFile @@ -40,34 +39,34 @@ def process(args): - os.makedirs(args.output_root, exist_ok=True) + out_root = Path(args.output_root).absolute() + out_root.mkdir(exist_ok=True) # Extract features - feature_root = op.join(args.output_root, "fbank80") - os.makedirs(feature_root, exist_ok=True) + feature_root = out_root / "fbank80" + feature_root.mkdir(exist_ok=True) for split in SPLITS: print(f"Fetching split {split}...") - dataset = LIBRISPEECH(args.output_root, url=split, download=True) + dataset = LIBRISPEECH(out_root.as_posix(), url=split, download=True) print("Extracting log mel filter bank features...") - for wav, sample_rate, _, spk_id, chapter_id, utt_id in tqdm(dataset): - sample_id = f"{spk_id}-{chapter_id}-{utt_id}" + for wav, sample_rate, _, spk_id, chapter_no, utt_no in tqdm(dataset): + sample_id = f"{spk_id}-{chapter_no}-{utt_no}" extract_fbank_features( - wav, sample_rate, op.join(feature_root, f"{sample_id}.npy") + wav, sample_rate, feature_root / f"{sample_id}.npy" ) # Pack features into ZIP - zip_filename = "fbank80.zip" - zip_path = op.join(args.output_root, zip_filename) + zip_path = out_root / "fbank80.zip" print("ZIPing features...") create_zip(feature_root, zip_path) print("Fetching ZIP manifest...") - zip_manifest = get_zip_manifest(args.output_root, zip_filename) + zip_manifest = get_zip_manifest(zip_path) # Generate TSV manifest print("Generating manifest...") train_text = [] for split in SPLITS: manifest = {c: [] for c in MANIFEST_COLUMNS} - dataset = LIBRISPEECH(args.output_root, url=split) - for wav, sample_rate, utt, spk_id, chapter_id, utt_id in tqdm(dataset): - sample_id = f"{spk_id}-{chapter_id}-{utt_id}" + dataset = LIBRISPEECH(out_root.as_posix(), url=split) + for wav, sample_rate, utt, spk_id, chapter_no, utt_no in tqdm(dataset): + sample_id = f"{spk_id}-{chapter_no}-{utt_no}" manifest["id"].append(sample_id) manifest["audio"].append(zip_manifest[sample_id]) duration_ms = int(wav.size(1) / sample_rate * 1000) @@ -75,7 +74,7 @@ def process(args): manifest["tgt_text"].append(utt) manifest["speaker"].append(spk_id) save_df_to_tsv( - pd.DataFrame.from_dict(manifest), op.join(args.output_root, f"{split}.tsv") + pd.DataFrame.from_dict(manifest), out_root / f"{split}.tsv" ) if split.startswith("train"): train_text.extend(manifest["tgt_text"]) @@ -86,14 +85,14 @@ def process(args): for t in train_text: f.write(t + "\n") gen_vocab( - f.name, - op.join(args.output_root, spm_filename_prefix), + Path(f.name), + out_root / spm_filename_prefix, args.vocab_type, args.vocab_size, ) # Generate config YAML gen_config_yaml( - args.output_root, spm_filename_prefix + ".model", specaugment_policy="ld" + out_root, spm_filename_prefix + ".model", specaugment_policy="ld" ) # Clean up shutil.rmtree(feature_root) diff --git a/examples/speech_to_text/prep_mustc_data.py b/examples/speech_to_text/prep_mustc_data.py index 59a42803f9..520968401c 100644 --- a/examples/speech_to_text/prep_mustc_data.py +++ b/examples/speech_to_text/prep_mustc_data.py @@ -7,7 +7,7 @@ import argparse import logging import os -import os.path as op +from pathlib import Path import shutil from itertools import groupby from tempfile import NamedTemporaryFile @@ -48,19 +48,19 @@ class MUSTC(Dataset): def __init__(self, root: str, lang: str, split: str) -> None: assert split in self.SPLITS and lang in self.LANGUAGES - _root = op.join(root, f"en-{lang}", "data", split) - wav_root, txt_root = op.join(_root, "wav"), op.join(_root, "txt") - assert op.isdir(_root) and op.isdir(wav_root) and op.isdir(txt_root) + _root = Path(root) / f"en-{lang}" / "data" / split + wav_root, txt_root = _root / "wav", _root / "txt" + assert _root.is_dir() and wav_root.is_dir() and txt_root.is_dir() # Load audio segments try: import yaml except ImportError: - print("Please install PyYAML to load YAML files for " "the MuST-C dataset") - with open(op.join(txt_root, f"{split}.yaml")) as f: + print("Please install PyYAML to load the MuST-C YAML files") + with open(txt_root / f"{split}.yaml") as f: segments = yaml.load(f, Loader=yaml.BaseLoader) # Load source and target utterances for _lang in ["en", lang]: - with open(op.join(txt_root, f"{split}.{_lang}")) as f: + with open(txt_root / f"{split}.{_lang}") as f: utterances = [r.strip() for r in f] assert len(segments) == len(utterances) for i, u in enumerate(utterances): @@ -68,16 +68,16 @@ def __init__(self, root: str, lang: str, split: str) -> None: # Gather info self.data = [] for wav_filename, _seg_group in groupby(segments, lambda x: x["wav"]): - wav_path = op.join(wav_root, wav_filename) - sample_rate = torchaudio.info(wav_path)[0].rate + wav_path = wav_root / wav_filename + sample_rate = torchaudio.info(wav_path.as_posix())[0].rate seg_group = sorted(_seg_group, key=lambda x: x["offset"]) for i, segment in enumerate(seg_group): offset = int(float(segment["offset"]) * sample_rate) n_frames = int(float(segment["duration"]) * sample_rate) - _id = f"{op.splitext(wav_filename)[0]}_{i}" + _id = f"{wav_path.stem}_{i}" self.data.append( ( - wav_path, + wav_path.as_posix(), offset, n_frames, sample_rate, @@ -98,29 +98,29 @@ def __len__(self) -> int: def process(args): + root = Path(args.data_root).absolute() for lang in MUSTC.LANGUAGES: - cur_root = op.join(args.data_root, f"en-{lang}") - if not op.isdir(cur_root): - print(f"{cur_root} does not exist. Skipped.") + cur_root = root / f"en-{lang}" + if not cur_root.is_dir(): + print(f"{cur_root.as_posix()} does not exist. Skipped.") continue # Extract features - feature_root = op.join(cur_root, "fbank80") - os.makedirs(feature_root, exist_ok=True) + feature_root = cur_root / "fbank80" + feature_root.mkdir(exist_ok=True) for split in MUSTC.SPLITS: print(f"Fetching split {split}...") - dataset = MUSTC(args.data_root, lang, split) + dataset = MUSTC(root.as_posix(), lang, split) print("Extracting log mel filter bank features...") for waveform, sample_rate, _, _, _, utt_id in tqdm(dataset): extract_fbank_features( - waveform, sample_rate, op.join(feature_root, f"{utt_id}.npy") + waveform, sample_rate, feature_root / f"{utt_id}.npy" ) # Pack features into ZIP - zip_filename = "fbank80.zip" - zip_path = op.join(cur_root, zip_filename) + zip_path = cur_root / "fbank80.zip" print("ZIPing features...") create_zip(feature_root, zip_path) print("Fetching ZIP manifest...") - zip_manifest = get_zip_manifest(args.data_root, f"en-{lang}/{zip_filename}") + zip_manifest = get_zip_manifest(zip_path) # Generate TSV manifest print("Generating manifest...") train_text = [] @@ -139,7 +139,7 @@ def process(args): train_text.extend(manifest["tgt_text"]) df = pd.DataFrame.from_dict(manifest) df = filter_manifest_df(df, is_train_split=is_train_split) - save_df_to_tsv(df, op.join(cur_root, f"{split}_{args.task}.tsv")) + save_df_to_tsv(df, cur_root / f"{split}_{args.task}.tsv") # Generate vocab v_size_str = "" if args.vocab_type == "char" else str(args.vocab_size) spm_filename_prefix = f"spm_{args.vocab_type}{v_size_str}_{args.task}" @@ -147,8 +147,8 @@ def process(args): for t in train_text: f.write(t + "\n") gen_vocab( - f.name, - op.join(cur_root, spm_filename_prefix), + Path(f.name), + cur_root / spm_filename_prefix, args.vocab_type, args.vocab_size, ) @@ -164,39 +164,42 @@ def process(args): def process_joint(args): - assert all( - op.isdir(op.join(args.data_root, f"en-{lang}")) for lang in MUSTC.LANGUAGES - ), "do not have downloaded data available for all 8 languages" - cur_root = args.data_root + cur_root = Path(args.data_root) + assert all((cur_root / f"en-{lang}").is_dir() for lang in MUSTC.LANGUAGES), \ + "do not have downloaded data available for all 8 languages" # Generate vocab vocab_size_str = "" if args.vocab_type == "char" else str(args.vocab_size) spm_filename_prefix = f"spm_{args.vocab_type}{vocab_size_str}_{args.task}" with NamedTemporaryFile(mode="w") as f: for lang in MUSTC.LANGUAGES: - tsv_path = op.join(cur_root, f"en-{lang}", f"train_{args.task}.tsv") + tsv_path = cur_root / f"en-{lang}" / f"train_{args.task}.tsv" df = load_df_from_tsv(tsv_path) for t in df["tgt_text"]: f.write(t + "\n") + special_symbols = None + if args.task == 'st': + special_symbols = [f'' for lang in MUSTC.LANGUAGES] gen_vocab( - f.name, - op.join(cur_root, spm_filename_prefix), + Path(f.name), + cur_root / spm_filename_prefix, args.vocab_type, args.vocab_size, + special_symbols=special_symbols ) # Generate config YAML gen_config_yaml( cur_root, spm_filename_prefix + ".model", yaml_filename=f"config_{args.task}.yaml", - specaugment_policy="lb", + specaugment_policy="ld", prepend_tgt_lang_tag=(args.task == "st"), ) # Make symbolic links to manifests for lang in MUSTC.LANGUAGES: for split in MUSTC.SPLITS: - src_path = op.join(cur_root, f"en-{lang}", f"{split}_{args.task}.tsv") - desc_path = op.join(cur_root, f"{split}_{lang}_{args.task}.tsv") - if not op.islink(desc_path): + src_path = cur_root / f"en-{lang}" / f"{split}_{args.task}.tsv" + desc_path = cur_root / f"{split}_{lang}_{args.task}.tsv" + if not desc_path.is_symlink(): os.symlink(src_path, desc_path) diff --git a/fairseq/data/audio/feature_transforms/global_cmvn.py b/fairseq/data/audio/feature_transforms/global_cmvn.py index d512fed300..e457ff176f 100644 --- a/fairseq/data/audio/feature_transforms/global_cmvn.py +++ b/fairseq/data/audio/feature_transforms/global_cmvn.py @@ -16,9 +16,13 @@ def from_config_dict(cls, config=None): return GlobalCMVN(_config.get("stats_npz_path")) def __init__(self, stats_npz_path): + self.stats_npz_path = stats_npz_path stats = np.load(stats_npz_path) self.mean, self.std = stats["mean"], stats["std"] + def __repr__(self): + return self.__class__.__name__ + f'(stats_npz_path="{self.stats_npz_path}")' + def __call__(self, x): x = np.subtract(x, self.mean) x = np.divide(x, self.std) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index afd43f1ec7..1f556107a2 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -251,7 +251,7 @@ def forward(self, src_tokens, src_lengths, prev_output_tokens): """ The forward method inherited from the base class has a **kwargs argument in its input, which is not supported in torchscript. This - method overrites the forward method definition without **kwargs. + method overwrites the forward method definition without **kwargs. """ encoder_out = self.encoder(src_tokens=src_tokens, src_lengths=src_lengths) decoder_out = self.decoder( @@ -397,7 +397,7 @@ def base_architecture(args): args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) args.share_decoder_input_output_embed = getattr( - args, "share_decoder_input_output_embed", True + args, "share_decoder_input_output_embed", False ) args.no_token_positional_embeddings = getattr( args, "no_token_positional_embeddings", False diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 0a523680f0..7bd582b256 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -18,7 +18,6 @@ import numpy as np import torch from fairseq import checkpoint_utils, options, scoring, tasks, utils -from fairseq.data import encoders from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar from fairseq.logging.meters import StopwatchMeter, TimeMeter From f32de63e69aceb966b84c7c515a016ec96439125 Mon Sep 17 00:00:00 2001 From: Myle Ott Date: Mon, 11 Jan 2021 12:30:55 -0800 Subject: [PATCH 150/774] Fix IWSLT'14 link (fixes #2984) (#3113) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3113 Reviewed By: pritamdamania87 Differential Revision: D25836423 Pulled By: myleott fbshipit-source-id: 0fe9cafcfd0f3edab2db1025d2fcc8dbb8af570a --- examples/translation/prepare-iwslt14.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/translation/prepare-iwslt14.sh b/examples/translation/prepare-iwslt14.sh index 0bf0dc2a2e..2fb6643fbc 100644 --- a/examples/translation/prepare-iwslt14.sh +++ b/examples/translation/prepare-iwslt14.sh @@ -15,7 +15,7 @@ CLEAN=$SCRIPTS/training/clean-corpus-n.perl BPEROOT=subword-nmt/subword_nmt BPE_TOKENS=10000 -URL="https://wit3.fbk.eu/archive/2014-01/texts/de/en/de-en.tgz" +URL="http://dl.fbaipublicfiles.com/fairseq/data/iwslt14/de-en.tgz" GZ=de-en.tgz if [ ! -d "$SCRIPTS" ]; then From 60d2da7055ad696ef037c98dacc931f79d4ce117 Mon Sep 17 00:00:00 2001 From: Alex Xiao Date: Mon, 11 Jan 2021 14:01:45 -0800 Subject: [PATCH 151/774] cast scale window to int for memory efficient fp16 Summary: In some of my runs I found loss scale to never increase {F358780650} This was because scale window when using 48 GPUs by default will not be a whole integer. Lets cast it like the default fp16 optimizer. Reviewed By: myleott Differential Revision: D25872832 fbshipit-source-id: 7ab5c01c555dca07bda72cae3633bb4b17709a77 --- fairseq/optim/fp16_optimizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index a0da4948c8..e0b069f172 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -480,7 +480,7 @@ def __init__(self, cfg: DictConfig, params, optimizer, **kwargs): cfg.distributed_training.distributed_world_size / cfg.common.model_parallel_size ) - scale_window = ( + scale_window = int( 2 ** 14 / data_parallel_size / cfg.optimization.update_freq[0] ) else: From 6f6f704d10fc00b89fb4a01e0a6857624132573e Mon Sep 17 00:00:00 2001 From: Yuqing Tang Date: Tue, 12 Jan 2021 11:26:11 -0800 Subject: [PATCH 152/774] added data scripts and model download links (#1554) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting ## What does this PR do? added data scripts and model download links for mBART 50 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1554 Reviewed By: pipibjc Differential Revision: D25871769 Pulled By: tangyuq fbshipit-source-id: 2c1b2f8c70e9cc4a083c87f76758fc472d42eaf0 --- examples/multilingual/ML50_langs.txt | 52 + examples/multilingual/README.md | 34 + examples/multilingual/data_scripts/README.md | 24 + .../multilingual/data_scripts/binarize.py | 200 ++++ .../data_scripts/check_iswlt_test_data.py | 67 ++ .../data_scripts/check_self_overlaps.py | 103 ++ .../data_scripts/check_valid_test_overlaps.py | 124 +++ .../multilingual/data_scripts/dedup_all.py | 52 + .../data_scripts/download_ML50_v1.sh | 30 + .../data_scripts/download_af_xh.sh | 164 ++++ .../data_scripts/download_flores_data.sh | 246 +++++ .../data_scripts/download_iitb.sh | 35 + .../download_iwslt_and_extract.sh | 225 +++++ .../data_scripts/download_lotus.sh | 46 + .../data_scripts/download_ted_and_extract.py | 338 +++++++ .../data_scripts/download_wat19_my.sh | 36 + .../data_scripts/download_wmt19_and_before.py | 899 ++++++++++++++++++ .../data_scripts/download_wmt20.sh | 547 +++++++++++ .../data_scripts/preprocess_ML50_v1.sh | 27 + .../remove_valid_test_in_train.py | 290 ++++++ .../multilingual/data_scripts/requirement.txt | 2 + .../multilingual/data_scripts/utils/dedup.py | 41 + .../utils/fasttext_multi_filter.py | 63 ++ .../data_scripts/utils/strip_sgm.sh | 1 + .../finetune_multilingual_model.sh | 5 + .../multilingual/multilingual_fairseq_gen.sh | 5 + .../multilingual/train_multilingual_model.sh | 5 + 27 files changed, 3661 insertions(+) create mode 100644 examples/multilingual/ML50_langs.txt create mode 100644 examples/multilingual/data_scripts/README.md create mode 100755 examples/multilingual/data_scripts/binarize.py create mode 100644 examples/multilingual/data_scripts/check_iswlt_test_data.py create mode 100644 examples/multilingual/data_scripts/check_self_overlaps.py create mode 100644 examples/multilingual/data_scripts/check_valid_test_overlaps.py create mode 100644 examples/multilingual/data_scripts/dedup_all.py create mode 100644 examples/multilingual/data_scripts/download_ML50_v1.sh create mode 100644 examples/multilingual/data_scripts/download_af_xh.sh create mode 100644 examples/multilingual/data_scripts/download_flores_data.sh create mode 100644 examples/multilingual/data_scripts/download_iitb.sh create mode 100644 examples/multilingual/data_scripts/download_iwslt_and_extract.sh create mode 100644 examples/multilingual/data_scripts/download_lotus.sh create mode 100644 examples/multilingual/data_scripts/download_ted_and_extract.py create mode 100644 examples/multilingual/data_scripts/download_wat19_my.sh create mode 100644 examples/multilingual/data_scripts/download_wmt19_and_before.py create mode 100644 examples/multilingual/data_scripts/download_wmt20.sh create mode 100644 examples/multilingual/data_scripts/preprocess_ML50_v1.sh create mode 100755 examples/multilingual/data_scripts/remove_valid_test_in_train.py create mode 100644 examples/multilingual/data_scripts/requirement.txt create mode 100644 examples/multilingual/data_scripts/utils/dedup.py create mode 100644 examples/multilingual/data_scripts/utils/fasttext_multi_filter.py create mode 100755 examples/multilingual/data_scripts/utils/strip_sgm.sh diff --git a/examples/multilingual/ML50_langs.txt b/examples/multilingual/ML50_langs.txt new file mode 100644 index 0000000000..558abbc785 --- /dev/null +++ b/examples/multilingual/ML50_langs.txt @@ -0,0 +1,52 @@ +ar_AR +cs_CZ +de_DE +en_XX +es_XX +et_EE +fi_FI +fr_XX +gu_IN +hi_IN +it_IT +ja_XX +kk_KZ +ko_KR +lt_LT +lv_LV +my_MM +ne_NP +nl_XX +ro_RO +ru_RU +si_LK +tr_TR +vi_VN +zh_CN +af_ZA +az_AZ +bn_IN +fa_IR +he_IL +hr_HR +id_ID +ka_GE +km_KH +mk_MK +ml_IN +mn_MN +mr_IN +pl_PL +ps_AF +pt_XX +sv_SE +sw_KE +ta_IN +te_IN +th_TH +tl_XX +uk_UA +ur_PK +xh_ZA +gl_ES +sl_SI \ No newline at end of file diff --git a/examples/multilingual/README.md b/examples/multilingual/README.md index 35eca89804..0076f5e8f0 100644 --- a/examples/multilingual/README.md +++ b/examples/multilingual/README.md @@ -108,7 +108,41 @@ cat {source_lang}_${target_lang}.txt | grep -P "^T" |sort -V |cut -f 2- |$TOK_CM sacrebleu -tok 'none' -s 'none' ${source_lang}_${target_lang}.ref < ${source_lang}_${target_lang}.hyp ``` +# mBART50 models + +* [mMBART 50 pretrained model](https://dl.fbaipublicfiles.com/fairseq/models/mbart50/mbart50.pretrained.tar.gz). +* [mMBART 50 finetuned many-to-one](https://dl.fbaipublicfiles.com/fairseq/models/mbart50/mbart50.ft.n1.tar.gz). +* [mMBART 50 finetuned one-to-many](https://dl.fbaipublicfiles.com/fairseq/models/mbart50/mbart50.ft.1n.tar.gz). +* [mMBART 50 finetuned many-to-many](https://dl.fbaipublicfiles.com/fairseq/models/mbart50/mbart50.ft.nn.tar.gz). + +Please download and extract from the above tarballs. Each tarball contains +* The fairseq model checkpoint: model.pt +* The list of supported languages: ML50_langs.txt +* Sentence piece model: sentence.bpe.model +* Fairseq dictionary of each language: dict.{lang}.txt (please replace lang with a language specified in ML50_langs.txt) + +To use the trained models, +* use the tool [binarize.py](./data_scripts/binarize.py) to binarize your data using sentence.bpe.model and dict.{lang}.txt, and copy the dictionaries to your data path +* then run the generation command: +```bash +path_2_data= +model=/model.pt +lang_list=/ML50_langs.txt +source_lang= +target_lang= +fairseq-generate $path_2_data \ + --path $model \ + --task translation_multi_simple_epoch \ + --gen-subset test \ + --source-lang $source_lang \ + --target-lang $target_lang + --sacrebleu --remove-bpe 'sentencepiece'\ + --batch-size 32 \ + --encoder-langtok "src" \ + --decoder-langtok \ + --lang-dict "$lang_list" +``` ## Citation diff --git a/examples/multilingual/data_scripts/README.md b/examples/multilingual/data_scripts/README.md new file mode 100644 index 0000000000..cc610c0c9e --- /dev/null +++ b/examples/multilingual/data_scripts/README.md @@ -0,0 +1,24 @@ + +# Install dependency +```bash +pip install -r requirement.txt +``` + +# Download the data set +```bash +export WORKDIR_ROOT= + +``` +The downloaded data will be at $WORKDIR_ROOT/ML50 + +# preprocess the data +Install SPM [here](https://github.com/google/sentencepiece) +```bash +export WORKDIR_ROOT= +export SPM_PATH= +``` +* $WORKDIR_ROOT/ML50/raw: extracted raw data +* $WORKDIR_ROOT/ML50/dedup: dedup data +* $WORKDIR_ROOT/ML50/clean: data with valid and test sentences removed from the dedup data + + diff --git a/examples/multilingual/data_scripts/binarize.py b/examples/multilingual/data_scripts/binarize.py new file mode 100755 index 0000000000..ee54c6aabf --- /dev/null +++ b/examples/multilingual/data_scripts/binarize.py @@ -0,0 +1,200 @@ +import shutil +import os, sys +from subprocess import check_call, check_output +import glob +import argparse +import shutil +import pathlib +import itertools + +def call_output(cmd): + print(f"Executing: {cmd}") + ret = check_output(cmd, shell=True) + print(ret) + return ret + +def call(cmd): + print(cmd) + check_call(cmd, shell=True) + + +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + +SPM_PATH = os.environ.get('SPM_PATH', None) + +if SPM_PATH is None or not SPM_PATH.strip(): + print("Please install sentence piecence from https://github.com/google/sentencepiece and set SPM_PATH pointing to the installed spm_encode.py. Exitting...") + sys.exit(-1) + + +SPM_MODEL = f'{WORKDIR_ROOT}/sentence.bpe.model' +SPM_VOCAB = f'{WORKDIR_ROOT}/dict_250k.txt' + +SPM_ENCODE = f'{SPM_PATH}' + +if not os.path.exists(SPM_MODEL): + call(f"wget https://dl.fbaipublicfiles.com/fairseq/models/mbart50/sentence.bpe.model -O {SPM_MODEL}") + + +if not os.path.exists(SPM_VOCAB): + call(f"wget https://dl.fbaipublicfiles.com/fairseq/models/mbart50/dict_250k.txt -O {SPM_VOCAB}") + + + +def get_data_size(raw): + cmd = f'wc -l {raw}' + ret = call_output(cmd) + return int(ret.split()[0]) + +def encode_spm(model, direction, prefix='', splits=['train', 'test', 'valid'], pairs_per_shard=None): + src, tgt = direction.split('-') + + for split in splits: + src_raw, tgt_raw = f'{RAW_DIR}/{split}{prefix}.{direction}.{src}', f'{RAW_DIR}/{split}{prefix}.{direction}.{tgt}' + if os.path.exists(src_raw) and os.path.exists(tgt_raw): + cmd = f"""python {SPM_ENCODE} \ + --model {model}\ + --output_format=piece \ + --inputs {src_raw} {tgt_raw} \ + --outputs {BPE_DIR}/{direction}{prefix}/{split}.bpe.{src} {BPE_DIR}/{direction}{prefix}/{split}.bpe.{tgt} """ + print(cmd) + call(cmd) + + +def binarize_( + bpe_dir, + databin_dir, + direction, spm_vocab=SPM_VOCAB, + splits=['train', 'test', 'valid'], +): + src, tgt = direction.split('-') + + try: + shutil.rmtree(f'{databin_dir}', ignore_errors=True) + os.mkdir(f'{databin_dir}') + except OSError as error: + print(error) + cmds = [ + "fairseq-preprocess", + f"--source-lang {src} --target-lang {tgt}", + f"--destdir {databin_dir}/", + f"--workers 8", + ] + if isinstance(spm_vocab, tuple): + src_vocab, tgt_vocab = spm_vocab + cmds.extend( + [ + f"--srcdict {src_vocab}", + f"--tgtdict {tgt_vocab}", + ] + ) + else: + cmds.extend( + [ + f"--joined-dictionary", + f"--srcdict {spm_vocab}", + ] + ) + input_options = [] + if 'train' in splits and glob.glob(f"{bpe_dir}/train.bpe*"): + input_options.append( + f"--trainpref {bpe_dir}/train.bpe", + ) + if 'valid' in splits and glob.glob(f"{bpe_dir}/valid.bpe*"): + input_options.append(f"--validpref {bpe_dir}/valid.bpe") + if 'test' in splits and glob.glob(f"{bpe_dir}/test.bpe*"): + input_options.append(f"--testpref {bpe_dir}/test.bpe") + if len(input_options) > 0: + cmd = " ".join(cmds + input_options) + print(cmd) + call(cmd) + + +def binarize( + databin_dir, + direction, spm_vocab=SPM_VOCAB, prefix='', + splits=['train', 'test', 'valid'], + pairs_per_shard=None, +): + def move_databin_files(from_folder, to_folder): + for bin_file in glob.glob(f"{from_folder}/*.bin") \ + + glob.glob(f"{from_folder}/*.idx") \ + + glob.glob(f"{from_folder}/dict*"): + try: + shutil.move(bin_file, to_folder) + except OSError as error: + print(error) + bpe_databin_dir = f"{BPE_DIR}/{direction}{prefix}_databin" + bpe_dir = f"{BPE_DIR}/{direction}{prefix}" + if pairs_per_shard is None: + binarize_(bpe_dir, bpe_databin_dir, direction, spm_vocab=spm_vocab, splits=splits) + move_databin_files(bpe_databin_dir, databin_dir) + else: + # binarize valid and test which will not be sharded + binarize_( + bpe_dir, bpe_databin_dir, direction, + spm_vocab=spm_vocab, splits=[s for s in splits if s != "train"]) + for shard_bpe_dir in glob.glob(f"{bpe_dir}/shard*"): + path_strs = os.path.split(shard_bpe_dir) + shard_str = path_strs[-1] + shard_folder = f"{bpe_databin_dir}/{shard_str}" + databin_shard_folder = f"{databin_dir}/{shard_str}" + print(f'working from {shard_folder} to {databin_shard_folder}') + os.makedirs(databin_shard_folder, exist_ok=True) + binarize_( + shard_bpe_dir, shard_folder, direction, + spm_vocab=spm_vocab, splits=["train"]) + + for test_data in glob.glob(f"{bpe_databin_dir}/valid.*") + glob.glob(f"{bpe_databin_dir}/test.*"): + filename = os.path.split(test_data)[-1] + try: + os.symlink(test_data, f"{databin_shard_folder}/{filename}") + except OSError as error: + print(error) + move_databin_files(shard_folder, databin_shard_folder) + + +def load_langs(path): + with open(path) as fr: + langs = [l.strip() for l in fr] + return langs + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("--data_root", default=f"{WORKDIR_ROOT}/ML50") + parser.add_argument("--raw-folder", default='raw') + parser.add_argument("--bpe-folder", default='bpe') + parser.add_argument("--databin-folder", default='databin') + + args = parser.parse_args() + + DATA_PATH = args.data_root #'/private/home/yuqtang/public_data/ML50' + RAW_DIR = f'{DATA_PATH}/{args.raw_folder}' + BPE_DIR = f'{DATA_PATH}/{args.bpe_folder}' + DATABIN_DIR = f'{DATA_PATH}/{args.databin_folder}' + os.makedirs(BPE_DIR, exist_ok=True) + + raw_files = itertools.chain( + glob.glob(f'{RAW_DIR}/train*'), + glob.glob(f'{RAW_DIR}/valid*'), + glob.glob(f'{RAW_DIR}/test*'), + ) + + directions = [os.path.split(file_path)[-1].split('.')[1] for file_path in raw_files] + + for direction in directions: + prefix = "" + splits = ['train', 'valid', 'test'] + try: + shutil.rmtree(f'{BPE_DIR}/{direction}{prefix}', ignore_errors=True) + os.mkdir(f'{BPE_DIR}/{direction}{prefix}') + os.makedirs(DATABIN_DIR, exist_ok=True) + except OSError as error: + print(error) + spm_model, spm_vocab = SPM_MODEL, SPM_VOCAB + encode_spm(spm_model, direction=direction, splits=splits) + binarize(DATABIN_DIR, direction, spm_vocab=spm_vocab, splits=splits) diff --git a/examples/multilingual/data_scripts/check_iswlt_test_data.py b/examples/multilingual/data_scripts/check_iswlt_test_data.py new file mode 100644 index 0000000000..f8e2eb0f15 --- /dev/null +++ b/examples/multilingual/data_scripts/check_iswlt_test_data.py @@ -0,0 +1,67 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import os, sys +import subprocess +import re +from subprocess import check_call, check_output + +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + + +BLEU_REGEX = re.compile("^BLEU\\S* = (\\S+) ") +def run_eval_bleu(cmd): + output = check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode("utf-8").strip() + print(output) + bleu = -1.0 + for line in output.strip().split('\n'): + m = BLEU_REGEX.search(line) + if m is not None: + bleu = m.groups()[0] + bleu = float(bleu) + break + return bleu + +def check_data_test_bleu(raw_folder, data_lang_pairs): + not_matchings = [] + for sacrebleu_set, src_tgts in data_lang_pairs: + for src_tgt in src_tgts: + print(f'checking test bleus for: {src_tgt} at {sacrebleu_set}') + src, tgt = src_tgt.split('-') + ssrc, stgt = src[:2], tgt[:2] + if os.path.exists(f'{raw_folder}/test.{tgt}-{src}.{src}'): + # reversed direction may have different test set + test_src = f'{raw_folder}/test.{tgt}-{src}.{src}' + else: + test_src = f'{raw_folder}/test.{src}-{tgt}.{src}' + cmd1 = f'cat {test_src} | sacrebleu -t "{sacrebleu_set}" -l {stgt}-{ssrc}; [ $? -eq 0 ] || echo ""' + test_tgt = f'{raw_folder}/test.{src}-{tgt}.{tgt}' + cmd2 = f'cat {test_tgt} | sacrebleu -t "{sacrebleu_set}" -l {ssrc}-{stgt}; [ $? -eq 0 ] || echo ""' + bleu1 = run_eval_bleu(cmd1) + if bleu1 != 100.0: + not_matchings.append(f'{sacrebleu_set}:{src_tgt} source side not matching: {test_src}') + bleu2 = run_eval_bleu(cmd2) + if bleu2 != 100.0: + not_matchings.append(f'{sacrebleu_set}:{src_tgt} target side not matching: {test_tgt}') + return not_matchings + +if __name__ == "__main__": + to_data_path = f'{WORKDIR_ROOT}/iwsltv2' + not_matching = check_data_test_bleu( + f'{to_data_path}/raw', + [ + ('iwslt17', ['en_XX-ar_AR', 'en_XX-ko_KR', 'ar_AR-en_XX', 'ko_KR-en_XX']), + ('iwslt17', ['en_XX-it_IT', 'en_XX-nl_XX', 'it_IT-en_XX', 'nl_XX-en_XX']), + ('iwslt17/tst2015', ['en_XX-vi_VN', "vi_VN-en_XX"]), + ] + ) + if len(not_matching) > 0: + print('the following datasets do not have matching test datasets:\n\t', '\n\t'.join(not_matching)) + diff --git a/examples/multilingual/data_scripts/check_self_overlaps.py b/examples/multilingual/data_scripts/check_self_overlaps.py new file mode 100644 index 0000000000..07b338dcfd --- /dev/null +++ b/examples/multilingual/data_scripts/check_self_overlaps.py @@ -0,0 +1,103 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import os +import glob +import argparse +from utils.dedup import deup +import sys + +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + +def get_directions(folder): + raw_files = glob.glob(f'{folder}/train*') + directions = [os.path.split(file_path)[-1].split('.')[1] for file_path in raw_files] + return directions + +def diff_list(lhs, rhs): + return set(lhs).difference(set(rhs)) + +def check_diff( + from_src_file, from_tgt_file, + to_src_file, to_tgt_file, +): + seen_in_from = set() + seen_src_in_from = set() + seen_tgt_in_from = set() + from_count = 0 + with open(from_src_file, encoding='utf-8') as fsrc, \ + open(from_tgt_file, encoding='utf-8') as ftgt: + for s, t in zip(fsrc, ftgt): + seen_in_from.add((s, t)) + seen_src_in_from.add(s) + seen_tgt_in_from.add(t) + from_count += 1 + common = 0 + common_src = 0 + common_tgt = 0 + to_count = 0 + seen = set() + + with open(to_src_file, encoding='utf-8') as fsrc, \ + open(to_tgt_file, encoding='utf-8') as ftgt: + for s, t in zip(fsrc, ftgt): + to_count += 1 + if (s, t) not in seen: + if (s, t) in seen_in_from: + common += 1 + if s in seen_src_in_from: + common_src += 1 + seen_src_in_from.remove(s) + if t in seen_tgt_in_from: + common_tgt += 1 + seen_tgt_in_from.remove(t) + seen.add((s, t)) + return common, common_src, common_tgt, from_count, to_count + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--folder", type=str, required=True, + help="the data folder ") + parser.add_argument("--split", type=str, default='test', + help="split (valid, test) to check against training data") + parser.add_argument('--directions', type=str, default=None, required=False) + + args = parser.parse_args() + + if args.directions is None: + directions = set(get_directions(args.folder)) + directions = sorted(directions) + else: + directions = args.directions.split(',') + directions = sorted(set(directions)) + + results = [] + print(f'checking where {args.split} split data are in training') + print(f'direction\tcommon_count\tsrc common\ttgt common\tfrom_size\tto_size') + + for direction in directions: + src, tgt = direction.split('-') + from_src_file = f'{args.folder}/{args.split}.{src}-{tgt}.{src}' + from_tgt_file = f'{args.folder}/{args.split}.{src}-{tgt}.{tgt}' + if not os.path.exists(from_src_file): + # some test/valid data might in reverse directinos: + from_src_file = f'{args.folder}/{args.split}.{tgt}-{src}.{src}' + from_tgt_file = f'{args.folder}/{args.split}.{tgt}-{src}.{tgt}' + to_src_file = f'{args.folder}/train.{src}-{tgt}.{src}' + to_tgt_file = f'{args.folder}/train.{src}-{tgt}.{tgt}' + if not os.path.exists(to_src_file) or not os.path.exists(from_src_file): + continue + r = check_diff(from_src_file, from_tgt_file, to_src_file, to_tgt_file) + results.append(r) + print(f'{direction}\t', '\t'.join(map(str, r))) + + +if __name__ == "__main__": + main() diff --git a/examples/multilingual/data_scripts/check_valid_test_overlaps.py b/examples/multilingual/data_scripts/check_valid_test_overlaps.py new file mode 100644 index 0000000000..40fa9aecdf --- /dev/null +++ b/examples/multilingual/data_scripts/check_valid_test_overlaps.py @@ -0,0 +1,124 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import os +import argparse +import pandas as pd +import sys + + +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + +def load_langs(path): + with open(path) as fr: + langs = [l.strip() for l in fr] + return langs + + + +def load_sentences(raw_data, split, direction): + src, tgt = direction.split('-') + src_path = f"{raw_data}/{split}.{direction}.{src}" + tgt_path = f"{raw_data}/{split}.{direction}.{tgt}" + if os.path.exists(src_path) and os.path.exists(tgt_path): + return [(src, open(src_path).read().splitlines()), (tgt, open(tgt_path).read().splitlines())] + else: + return [] + +def swap_direction(d): + src, tgt = d.split('-') + return f'{tgt}-{src}' + +def get_all_test_data(raw_data, directions, split='test'): + test_data = [ + x + for dd in directions + for d in [dd, swap_direction(dd)] + for x in load_sentences(raw_data, split, d) + ] + # all_test_data = {s for _, d in test_data for s in d} + all_test_data = {} + for lang, d in test_data: + for s in d: + s = s.strip() + lgs = all_test_data.get(s, set()) + lgs.add(lang) + all_test_data[s] = lgs + return all_test_data, test_data + + +def check_train_sentences(src_path, tgt_path, direction, all_test_data, mess_up_train={}): + # src, tgt = direction.split('-') + print(f'check training data for {direction} in {src_path} and {tgt_path}') + size = 0 + overlapped_size_counted_dup = 0 + if not os.path.exists(tgt_path) or not os.path.exists(src_path): + return mess_up_train, size, overlapped_size_counted_dup + + with open(src_path) as f, open(tgt_path) as g: + for src_line, tgt_line in zip(f, g): + s = src_line.strip() + t = tgt_line.strip() + size += 1 + if s in all_test_data: + langs = mess_up_train.get(s, set()) + langs.add(direction) + mess_up_train[s] = langs + overlapped_size_counted_dup += 1 + if t in all_test_data: + langs = mess_up_train.get(t, set()) + langs.add(direction) + mess_up_train[t] = langs + overlapped_size_counted_dup += 1 + print(f'{direction}: size={size}, overlapped={overlapped_size_counted_dup}') + return mess_up_train, size, overlapped_size_counted_dup + +def check_train_all(raw_data, directions, all_test_data): + mess_up_train = {} + data_sizes = {} + # raw_data = '~chau/data-bin/MineBART/multilingual_mined_100M/en_XX/et_EE-en_XX/all.{en_XX, et_EE}' + print(f'checking training data againsts # {len(all_test_data)} sentences') + print(f'example test data: ', [s for i, s in enumerate(all_test_data.keys()) if i < 10]) + for direction in directions: + src, tgt = direction.split('-') + path = f'{raw_data}/en_XX/{direction}/all' + src_path = f'{path}.{src}' + tgt_path = f'{path}.{tgt}' + print(f'checking {src_path} {tgt_path}') + _, size, overlapped_size_counted_dup = check_train_sentences(src_path, tgt_path, direction, all_test_data, mess_up_train) + data_sizes[direction] = (size, overlapped_size_counted_dup) + return mess_up_train, data_sizes + + + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--folder", type=str, required=True, + help="the data folder ") + parser.add_argument("--test-data", type=str, required=True, + help="the test data folder ") + parser.add_argument('--directions', type=str, default=None, required=False) + + args = parser.parse_args() + directions = args.directions.split(',') + directions = sorted(set(directions)) + + results = [] + # print(f'checking where {args.split} split data are in training') + # print(f'direction\tcommon_count\tsrc common\ttgt common\tfrom_size\tto_size') + raw_data = args.folder + all_test_data, test_data = get_all_test_data(args.test_data, directions, split='test') + mess_up_train, data_sizes = check_train_all(raw_data, directions, all_test_data) + print(data_sizes) + + +if __name__ == "__main__": + main() diff --git a/examples/multilingual/data_scripts/dedup_all.py b/examples/multilingual/data_scripts/dedup_all.py new file mode 100644 index 0000000000..ef39c05ee6 --- /dev/null +++ b/examples/multilingual/data_scripts/dedup_all.py @@ -0,0 +1,52 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + + +import os +import glob +import argparse +from utils.dedup import deup + +import sys +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--from-folder", type=str, required=True, + help="the data folder to be dedup") + parser.add_argument("--to-folder", type=str, required=True, + help="the data folder to save deduped data") + parser.add_argument('--directions', type=str, default=None, required=False) + + args = parser.parse_args() + + if args.directions is None: + raw_files = glob.glob(f'{args.from_folder}/train*') + + directions = [os.path.split(file_path)[-1].split('.')[1] for file_path in raw_files] + else: + directions = args.directions.split(',') + directions = sorted(set(directions)) + + for direction in directions: + src, tgt = direction.split('-') + src_file = f'{args.from_folder}/train.{src}-{tgt}.{src}' + tgt_file = f'{args.from_folder}/train.{src}-{tgt}.{tgt}' + src_file_out = f'{args.to_folder}/train.{src}-{tgt}.{src}' + tgt_file_out = f'{args.to_folder}/train.{src}-{tgt}.{tgt}' + assert src_file != src_file_out + assert tgt_file != tgt_file_out + print(f'deduping {src_file}, {tgt_file}') + deup(src_file, tgt_file, src_file_out, tgt_file_out) + + +if __name__ == "__main__": + main() diff --git a/examples/multilingual/data_scripts/download_ML50_v1.sh b/examples/multilingual/data_scripts/download_ML50_v1.sh new file mode 100644 index 0000000000..99fbc75920 --- /dev/null +++ b/examples/multilingual/data_scripts/download_ML50_v1.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + +# first run download_wmt20.sh; it will install a few useful tools for other scripts +# TODO: need to print out instructions on downloading a few files which requires manually authentication from the websites +bash ./download_wmt20.sh + +python ./download_wmt19_and_before.py +bash ./download_wat19_my.sh +python ./download_ted_and_extract.py +bash ./download_lotus.sh +bash ./download_iitb.sh +bash ./download_af_xh.sh + + +# IWSLT downloading URLs have changed in between; TODO: fix them: +bash ./download_iwslt_and_extract.sh + +# TODO: globalvoices URLs changed; need to be fixed +bash ./download_flores_data.sh diff --git a/examples/multilingual/data_scripts/download_af_xh.sh b/examples/multilingual/data_scripts/download_af_xh.sh new file mode 100644 index 0000000000..a78fbbbbcc --- /dev/null +++ b/examples/multilingual/data_scripts/download_af_xh.sh @@ -0,0 +1,164 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +# set -x -e + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + + +# put intermediate files +TMP_DIR=$WORKDIR_ROOT/temp/af_xhv2 +# output {train,valid,test} files to dest +DEST=${WORKDIR_ROOT}/ML50/raw + + + +ROOT=${WORKDIR_ROOT} +UTILS=$PWD/utils +TMX2CORPUS="${UTILS}/tmx2corpus" +TMX_TOOL="python ${TMX2CORPUS}/tmx2corpus.py" + +mkdir -p $TMP_DIR +mkdir -p $DEST +mkdir -p $UTILS + +function download_opus(){ + src=$1 + tgt=$2 + subset=$3 + ulr=$4 + + mkdir extract_$subset.$src-$tgt + pushd extract_$subset.$src-$tgt + if [ ! -f "$subset.$src-$tgt.tmx.gz" ]; then + wget $url -O "$subset.$src-$tgt.tmx.gz" + gzip -d "$subset.$src-$tgt.tmx.gz" + f=$subset.$src-$tgt.tmx + $TMX_TOOL $f + mv bitext.$src ../$subset.$src-$tgt.$src + mv bitext.$tgt ../$subset.$src-$tgt.$tgt + fi + popd +} + +function concat_subsets(){ + src=$1 + tgt=$2 + subsets=$3 + src_train=raw_train.$src-$tgt.$src + tgt_train=raw_train.$src-$tgt.$tgt + > $src_train + > $tgt_train + for subset in $subsets; do + cat $subset.$src-$tgt.$src >> $src_train + cat $subset.$src-$tgt.$tgt >> $tgt_train + done +} + + + +function get_seeded_random() +{ + seed="$1" + openssl enc -aes-256-ctr -pass pass:"$seed" -nosalt \ + /dev/null +} + +function split_train_valid(){ + src=$1 + tgt=$2 + raw_src_train=raw_train.$src-$tgt.$src + raw_tgt_train=raw_train.$src-$tgt.$tgt + + shuf --random-source=<(get_seeded_random 43) $raw_src_train > shuffled.$src-$tgt.$src + shuf --random-source=<(get_seeded_random 43) $raw_tgt_train > shuffled.$src-$tgt.$tgt + + head -n 1500 shuffled.$src-$tgt.$src > valid.$src-$tgt.$src + head -n 1500 shuffled.$src-$tgt.$tgt > valid.$src-$tgt.$tgt + + tail +1501 shuffled.$src-$tgt.$src > train.$src-$tgt.$src + tail +1501 shuffled.$src-$tgt.$tgt > train.$src-$tgt.$tgt +} + +function copy2dst(){ + lsrc=$1 + ltgt=$2 + src=${lsrc:0:2} + tgt=${ltgt:0:2} + + + cp valid.$src-$tgt.$src $DEST/valid.$lsrc-$ltgt.$lsrc + cp valid.$src-$tgt.$tgt $DEST/valid.$lsrc-$ltgt.$ltgt + + cp train.$src-$tgt.$src $DEST/train.$lsrc-$ltgt.$lsrc + cp train.$src-$tgt.$tgt $DEST/train.$lsrc-$ltgt.$ltgt +} + + + + +#for xh-en +declare -A xh_en_urls +xh_en_urls=( + [Tatoeba]=https://object.pouta.csc.fi/OPUS-Tatoeba/v20190709/tmx/en-xh.tmx.gz + [wikimedia]=https://object.pouta.csc.fi/OPUS-wikimedia/v20190628/tmx/en-xh.tmx.gz + [memat]=https://object.pouta.csc.fi/OPUS-memat/v1/tmx/en-xh.tmx.gz + [uedin]=https://object.pouta.csc.fi/OPUS-bible-uedin/v1/tmx/en-xh.tmx.gz + [GNOME]=https://object.pouta.csc.fi/OPUS-GNOME/v1/tmx/en-xh.tmx.gz + [XhosaNavy]=https://object.pouta.csc.fi/OPUS-XhosaNavy/v1/tmx/en-xh.tmx.gz + [KDE4]=https://object.pouta.csc.fi/OPUS-KDE4/v2/tmx/en-xh.tmx.gz + [Ubuntu]=https://object.pouta.csc.fi/OPUS-Ubuntu/v14.10/tmx/en-xh.tmx.gz +) + +mkdir $TMP_DIR/xh-en +pushd $TMP_DIR/xh-en +for k in "${!xh_en_urls[@]}" +do + name=$k + url=${xh_en_urls[$k]} + echo "$name: $url" + download_opus xh en $name $ulr +done +concat_subsets xh en "${!xh_en_urls[@]}" +split_train_valid xh en +copy2dst xh_ZA en_XX +popd + + +## +#for af-en +declare -A af_en_urls +af_en_urls=( + [Tatoeba]=https://object.pouta.csc.fi/OPUS-Tatoeba/v20190709/tmx/af-en.tmx.gz + [uedin]=https://object.pouta.csc.fi/OPUS-bible-uedin/v1/tmx/af-en.tmx.gz + [GNOME]=https://object.pouta.csc.fi/OPUS-GNOME/v1/tmx/af-en.tmx.gz + [QED]=https://object.pouta.csc.fi/OPUS-QED/v2.0a/tmx/af-en.tmx.gz + [KDE4]=https://object.pouta.csc.fi/OPUS-KDE4/v2/tmx/af-en.tmx.gz + [OpenSubtitles]=https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2018/tmx/af-en.tmx.gz + [SPC]=https://object.pouta.csc.fi/OPUS-SPC/v1/tmx/af-en.tmx.gz + [Ubuntu]=https://object.pouta.csc.fi/OPUS-Ubuntu/v14.10/tmx/af-en.tmx.gz +) + +mkdir $TMP_DIR/af-en +pushd $TMP_DIR/af-en +for k in "${!af_en_urls[@]}" +do + name=$k + url=${af_en_urls[$k]} + echo "$name: $url" + download_opus af en $name $ulr +done +concat_subsets af en "${!af_en_urls[@]}" +split_train_valid af en +copy2dst af_ZA en_XX +popd + + diff --git a/examples/multilingual/data_scripts/download_flores_data.sh b/examples/multilingual/data_scripts/download_flores_data.sh new file mode 100644 index 0000000000..e6175ce0c3 --- /dev/null +++ b/examples/multilingual/data_scripts/download_flores_data.sh @@ -0,0 +1,246 @@ +#!/bin/bash + +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +# + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + + +set -e +set -o pipefail + +SRC=en +SI_TGT=si +NE_TGT=ne + +DESTDIR=${WORKDIR_ROOT}/ML50/raw/ + +ROOT=${WORKDIR_ROOT}/tmp +mkdir -p $ROOT +DATA=$ROOT/data +NE_ROOT=$DATA/all-clean-ne +SI_ROOT=$DATA/all-clean-si + +mkdir -p $DATA $NE_ROOT $SI_ROOT + +SI_OPUS_DATASETS=( + "$SI_ROOT/GNOME.en-si" + "$SI_ROOT/Ubuntu.en-si" + "$SI_ROOT/KDE4.en-si" + "$SI_ROOT/OpenSubtitles.en-si" +) + +SI_OPUS_URLS=( + "https://object.pouta.csc.fi/OPUS-GNOME/v1/moses/en-si.txt.zip" + "https://object.pouta.csc.fi/OPUS-Ubuntu/v14.10/moses/en-si.txt.zip" + "https://object.pouta.csc.fi/OPUS-KDE4/v2/moses/en-si.txt.zip" + "https://object.pouta.csc.fi/OPUS-OpenSubtitles/v2018/moses/en-si.txt.zip" +) + +NE_OPUS_DATASETS=( + "$NE_ROOT/GNOME.en-ne" + "$NE_ROOT/Ubuntu.en-ne" + "$NE_ROOT/KDE4.en-ne" +) + +NE_OPUS_URLS=( + "https://object.pouta.csc.fi/OPUS-GNOME/v1/moses/en-ne.txt.zip" + "https://object.pouta.csc.fi/OPUS-Ubuntu/v14.10/moses/en-ne.txt.zip" + "https://object.pouta.csc.fi/OPUS-KDE4/v2/moses/en-ne.txt.zip" +) + +REMOVE_FILE_PATHS=() + +# Download data +download_data() { + CORPORA=$1 + URL=$2 + + if [ -f $CORPORA ]; then + echo "$CORPORA already exists, skipping download" + else + echo "Downloading $URL" + wget $URL -O $CORPORA --no-check-certificate || rm -f $CORPORA + if [ -f $CORPORA ]; then + echo "$URL successfully downloaded." + else + echo "$URL not successfully downloaded." + rm -f $CORPORA + exit -1 + fi + fi +} + +# Example: download_opus_data $LANG_ROOT $TGT +download_opus_data() { + LANG_ROOT=$1 + TGT=$2 + + if [ "$TGT" = "si" ]; then + URLS=("${SI_OPUS_URLS[@]}") + DATASETS=("${SI_OPUS_DATASETS[@]}") + else + URLS=("${NE_OPUS_URLS[@]}") + DATASETS=("${NE_OPUS_DATASETS[@]}") + fi + + # Download and extract data + for ((i=0;i<${#URLS[@]};++i)); do + URL=${URLS[i]} + CORPORA=${DATASETS[i]} + + download_data $CORPORA $URL + unzip -o $CORPORA -d $LANG_ROOT + REMOVE_FILE_PATHS+=( $CORPORA $CORPORA.xml $CORPORA.ids $LANG_ROOT/README $LANG_ROOT/LICENSE ) + done + + cat ${DATASETS[0]}.$SRC ${DATASETS[1]}.$SRC ${DATASETS[2]}.$SRC > $LANG_ROOT/GNOMEKDEUbuntu.$SRC-$TGT.$SRC + cat ${DATASETS[0]}.$TGT ${DATASETS[1]}.$TGT ${DATASETS[2]}.$TGT > $LANG_ROOT/GNOMEKDEUbuntu.$SRC-$TGT.$TGT + + REMOVE_FILE_PATHS+=( ${DATASETS[0]}.$SRC ${DATASETS[1]}.$SRC ${DATASETS[2]}.$SRC ) + REMOVE_FILE_PATHS+=( ${DATASETS[0]}.$TGT ${DATASETS[1]}.$TGT ${DATASETS[2]}.$TGT ) +} + +download_opus_data $SI_ROOT $SI_TGT +cp ${SI_OPUS_DATASETS[3]}.$SRC $SI_ROOT/OpenSubtitles2018.$SRC-$SI_TGT.$SRC +cp ${SI_OPUS_DATASETS[3]}.$SI_TGT $SI_ROOT/OpenSubtitles2018.$SRC-$SI_TGT.$SI_TGT +REMOVE_FILE_PATHS+=( ${SI_OPUS_DATASETS[3]}.$SRC ${SI_OPUS_DATASETS[3]}.$SI_TGT ) + +download_opus_data $NE_ROOT $NE_TGT + + +# Download and extract Global Voices data +GLOBAL_VOICES="$NE_ROOT/globalvoices.2018q4.ne-en" +GLOBAL_VOICES_URL="http://www.casmacat.eu/corpus/global-voices/globalvoices.ne-en.xliff.gz" + +download_data $GLOBAL_VOICES.gz $GLOBAL_VOICES_URL +gunzip -Nf $GLOBAL_VOICES.gz + +sed -ne 's?.*\(.*\).*?\1?p' $GLOBAL_VOICES > $GLOBAL_VOICES.$NE_TGT +sed -ne 's?.*]*>\(.*\).*?\1?p' $GLOBAL_VOICES > $GLOBAL_VOICES.$SRC + +REMOVE_FILE_PATHS+=( $GLOBAL_VOICES ) + +# Download and extract the bible dataset +BIBLE_TOOLS=bible-corpus-tools +XML_BIBLES=XML_Bibles +XML_BIBLES_DUP=XML_Bibles_dup + +if [ ! -e $BIBLE_TOOLS ]; then + echo "Cloning bible-corpus-tools repository..." + git clone https://github.com/christos-c/bible-corpus-tools.git +fi + +mkdir -p $BIBLE_TOOLS/bin $XML_BIBLES $XML_BIBLES_DUP +javac -cp "$BIBLE_TOOLS/lib/*" -d $BIBLE_TOOLS/bin $BIBLE_TOOLS/src/bible/readers/*.java $BIBLE_TOOLS/src/bible/*.java + +download_data bible.tar.gz "https://github.com/christos-c/bible-corpus/archive/v1.2.1.tar.gz" +tar xvzf bible.tar.gz + +cp bible-corpus-1.2.1/bibles/{Greek.xml,English.xml,Nepali.xml} $XML_BIBLES/ +cp bible-corpus-1.2.1/bibles/{Greek.xml,English-WEB.xml,Nepali.xml} $XML_BIBLES_DUP/ + +java -cp $BIBLE_TOOLS/lib/*:$BIBLE_TOOLS/bin bible.CreateMLBooks $XML_BIBLES +java -cp $BIBLE_TOOLS/lib/*:$BIBLE_TOOLS/bin bible.CreateMLBooks $XML_BIBLES_DUP +java -cp $BIBLE_TOOLS/lib/*:$BIBLE_TOOLS/bin bible.CreateVerseAlignedBooks $XML_BIBLES +java -cp $BIBLE_TOOLS/lib/*:$BIBLE_TOOLS/bin bible.CreateVerseAlignedBooks $XML_BIBLES_DUP + +cat $XML_BIBLES/aligned/*/English.txt > $NE_ROOT/bible.$SRC-$NE_TGT.$SRC +cat $XML_BIBLES/aligned/*/Nepali.txt > $NE_ROOT/bible.$SRC-$NE_TGT.$NE_TGT +cat $XML_BIBLES_DUP/aligned/*/English-WEB.txt > $NE_ROOT/bible_dup.$SRC-$NE_TGT.$SRC +cat $XML_BIBLES_DUP/aligned/*/Nepali.txt > $NE_ROOT/bible_dup.$SRC-$NE_TGT.$NE_TGT +REMOVE_FILE_PATHS+=( bible-corpus-1.2.1 bible.tar.gz $BIBLE_TOOLS $XML_BIBLES $XML_BIBLES_DUP ) + +# Download and extract the Penn Treebank dataset +NE_TAGGED=$ROOT/new_submissions_parallel_corpus_project_Nepal +NE_TAGGED_URL="http://www.cle.org.pk/Downloads/ling_resources/parallelcorpus/NepaliTaggedCorpus.zip" +EN_TAGGED_PATCH_URL="https://dl.fbaipublicfiles.com/fairseq/data/nepali-penn-treebank.en.patch" +NE_TAGGED_PATCH_URL="https://dl.fbaipublicfiles.com/fairseq/data/nepali-penn-treebank.ne.patch" +MOSES=mosesdecoder +MOSES_TOK=$MOSES/scripts/tokenizer +EN_PATCH_REGEX="{s:\\\/:\/:g;s/\*\T\*\-\n+//g;s/\-LCB\-/\{/g;s/\-RCB\-/\}/g; s/\-LSB\-/\[/g; s/\-RSB\-/\]/g;s/\-LRB\-/\(/g; s/\-RRB\-/\)/g; s/\'\'/\"/g; s/\`\`/\"/g; s/\ +\'s\ +/\'s /g; s/\ +\'re\ +/\'re /g; s/\"\ +/\"/g; s/\ +\"/\"/g; s/\ n't([\ \.\"])/n't\1/g; s/\r+(.)/\1/g;}" +NE_PATCH_REGEX="{s:\p{Cf}::g;s:\\\/:\/:g;s/\*\T\*\-\n+//g;s/\-LCB\-/\{/g;s/\-RCB\-/\}/g; s/\-LSB\-/\[/g; s/\-RSB\-/\]/g;s/\-LRB\-/\(/g; s/\-RRB\-/\)/g; s/\'\'/\"/g; s/\`\`/\"/g; s/\ +\'s\ +/\'s /g; s/\ +\'re\ +/\'re /g; s/\"\ +/\"/g; s/\ +\"/\"/g; s/\ n't([\ \.\"])/n't\1/g; s/\r+(.)/\1/g;}" + +download_data $DATA/nepali-penn-treebank.$SRC.patch $EN_TAGGED_PATCH_URL +download_data $DATA/nepali-penn-treebank.$NE_TGT.patch $NE_TAGGED_PATCH_URL +download_data original.zip $NE_TAGGED_URL +unzip -o original.zip -d $ROOT + +cat $NE_TAGGED/00.txt $NE_TAGGED/01.txt $NE_TAGGED/02.txt > $NE_TAGGED/nepali-penn-treebank.$SRC +cat $NE_TAGGED/00ne_revised.txt $NE_TAGGED/01ne_revised.txt $NE_TAGGED/02ne_revised.txt > $NE_TAGGED/nepali-penn-treebank.$NE_TGT + +patch $NE_TAGGED/nepali-penn-treebank.$SRC -i $DATA/nepali-penn-treebank.$SRC.patch -o $NE_TAGGED/nepali-penn-treebank-patched.$SRC +patch $NE_TAGGED/nepali-penn-treebank.$NE_TGT -i $DATA/nepali-penn-treebank.$NE_TGT.patch -o $NE_TAGGED/nepali-penn-treebank-patched.$NE_TGT + +if [ ! -e $MOSES ]; then + echo "Cloning moses repository..." + git clone https://github.com/moses-smt/mosesdecoder.git +fi + +cat $NE_TAGGED/nepali-penn-treebank-patched.$SRC | \ + perl -anpe "$EN_PATCH_REGEX" | \ + $MOSES_TOK/tokenizer.perl -l $SRC | \ + $MOSES_TOK/detokenizer.perl -l $SRC > $NE_ROOT/nepali-penn-treebank.$SRC + +cat $NE_TAGGED/nepali-penn-treebank-patched.$NE_TGT | \ + perl -CIO -anpe "$NE_PATCH_REGEX" | \ + $MOSES_TOK/detokenizer.perl -l $SRC > $NE_ROOT/nepali-penn-treebank.$NE_TGT + + +# Download nepali dictionary data +NE_DICT=$NE_ROOT/dictionaries +download_data $NE_DICT "http://www.seas.upenn.edu/~nlp/resources/TACL-data-release/dictionaries.tar.gz" +tar xvzf $NE_DICT +cp dictionaries/dict.ne $NE_ROOT/dictionary.$NE_TGT-$SRC +REMOVE_FILE_PATHS+=( $NE_DICT dictionaries ) + +REMOVE_FILE_PATHS+=( $MOSES $NE_TAGGED original.zip $DATA/nepali-penn-treebank.$SRC.patch $DATA/nepali-penn-treebank.$NE_TGT.patch ) + + +# Remove the temporary files +for ((i=0;i<${#REMOVE_FILE_PATHS[@]};++i)); do + rm -rf ${REMOVE_FILE_PATHS[i]} +done + +# Copy the training data +si=si_LK +ne=ne_NP +en=en_XX +cat $SI_ROOT/GNOMEKDEUbuntu.en-si.si $SI_ROOT/OpenSubtitles2018.en-si.si > $DESTDIR/train.$si-$en.$si +cat $SI_ROOT/GNOMEKDEUbuntu.en-si.en $SI_ROOT/OpenSubtitles2018.en-si.en > $DESTDIR/train.$si-$en.$en + +cat $NE_ROOT/bible_dup.en-ne.ne $NE_ROOT/bible.en-ne.ne $NE_ROOT/globalvoices.2018q4.ne-en.ne $NE_ROOT/GNOMEKDEUbuntu.en-ne.ne $NE_ROOT/nepali-penn-treebank.ne > $DESTDIR/train.$ne-$en.$ne +cat $NE_ROOT/bible_dup.en-ne.en $NE_ROOT/bible.en-ne.en $NE_ROOT/globalvoices.2018q4.ne-en.en $NE_ROOT/GNOMEKDEUbuntu.en-ne.en $NE_ROOT/nepali-penn-treebank.en > $DESTDIR/train.$ne-$en.$en + + +#Download the test sets +wget https://github.com/facebookresearch/flores/raw/master/data/wikipedia_en_ne_si_test_sets.tgz +tar -xvzf wikipedia_en_ne_si_test_sets.tgz + +cp wikipedia_en_ne_si_test_sets/wikipedia.dev.ne-en.ne $DESTDIR/valid.$ne-$en.$ne +cp wikipedia_en_ne_si_test_sets/wikipedia.dev.ne-en.en $DESTDIR/valid.$ne-$en.$en + +cp wikipedia_en_ne_si_test_sets/wikipedia.dev.si-en.si $DESTDIR/valid.$si-$en.$si +cp wikipedia_en_ne_si_test_sets/wikipedia.dev.si-en.en $DESTDIR/valid.$si-$en.$en + +cp wikipedia_en_ne_si_test_sets/wikipedia.devtest.ne-en.ne $DESTDIR/devtest.$ne-$en.$ne +cp wikipedia_en_ne_si_test_sets/wikipedia.devtest.ne-en.en $DESTDIR/devtest.$ne-$en.$en + +cp wikipedia_en_ne_si_test_sets/wikipedia.devtest.si-en.si $DESTDIR/devtest.$si-$en.$si +cp wikipedia_en_ne_si_test_sets/wikipedia.devtest.si-en.en $DESTDIR/devtest.$si-$en.$en + +cp wikipedia_en_ne_si_test_sets/wikipedia.test.ne-en.ne $DESTDIR/test.$ne-$en.$ne +cp wikipedia_en_ne_si_test_sets/wikipedia.test.ne-en.en $DESTDIR/test.$ne-$en.$en + +cp wikipedia_en_ne_si_test_sets/wikipedia.test.si-en.si $DESTDIR/test.$si-$en.$si +cp wikipedia_en_ne_si_test_sets/wikipedia.test.si-en.en $DESTDIR/test.$si-$en.$en + +rm -rf wikipedia_en_ne_si_test_sets.tgz wikipedia_en_ne_si_test_sets diff --git a/examples/multilingual/data_scripts/download_iitb.sh b/examples/multilingual/data_scripts/download_iitb.sh new file mode 100644 index 0000000000..a884e20839 --- /dev/null +++ b/examples/multilingual/data_scripts/download_iitb.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + +IITB=$WORKDIR_ROOT/IITB +mkdir -p $IITB +pushd $IITB + +wget http://www.cfilt.iitb.ac.in/~moses/iitb_en_hi_parallel/iitb_corpus_download/parallel.tgz +tar -xvzf parallel.tgz + +wget http://www.cfilt.iitb.ac.in/~moses/iitb_en_hi_parallel/iitb_corpus_download/dev_test.tgz +tar -xvzf dev_test.tgz + +DESTDIR=${WORKDIR_ROOT}/ML50/raw/ + +cp parallel/IITB.en-hi.en $DESTDIR/train.hi_IN-en_XX.en_XX +cp parallel/IITB.en-hi.hi $DESTDIR/train.hi_IN-en_XX.hi_IN + +cp dev_test/dev.en $DESTDIR/valid.hi_IN-en_XX.en_XX +cp dev_test/dev.hi $DESTDIR/valid.hi_IN-en_XX.hi_IN + +cp dev_test/test.en $DESTDIR/test.hi_IN-en_XX.en_XX +cp dev_test/test.hi $DESTDIR/test.hi_IN-en_XX.hi_IN +popd \ No newline at end of file diff --git a/examples/multilingual/data_scripts/download_iwslt_and_extract.sh b/examples/multilingual/data_scripts/download_iwslt_and_extract.sh new file mode 100644 index 0000000000..ca3591b3db --- /dev/null +++ b/examples/multilingual/data_scripts/download_iwslt_and_extract.sh @@ -0,0 +1,225 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +#echo 'Cloning Moses github repository (for tokenization scripts)...' +#git clone https://github.com/moses-smt/mosesdecoder.git + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + + + +data_root=${WORKDIR_ROOT}/iwsltv2 +DESTDIR=${WORKDIR_ROOT}/ML50/raw + + +langs="ar_AR it_IT nl_XX ko_KR vi_VN" +echo "data_root: $data_root" + +download_path=${data_root}/downloads +raw=${DESTDIR} +tmp=${data_root}/tmp +orig=${data_root}/orig + +mkdir -p $download_path $orig $raw $tmp +####################### +download_iwslt(){ + iwslt_key=$1 + src=$2 + tgt=$3 + save_prefix=$4 + pushd ${download_path} + if [[ ! -f ${save_prefix}$src-$tgt.tgz ]]; then + wget https://wit3.fbk.eu/archive/${iwslt_key}/texts/$src/$tgt/$src-$tgt.tgz -O ${save_prefix}$src-$tgt.tgz + [ $? -eq 0 ] && return 0 + fi + popd +} + +extract_iwslt(){ + src=$1 + tgt=$2 + prefix=$3 + pushd $orig + tar zxvf ${download_path}/${prefix}$src-${tgt}.tgz + popd +} + +generate_train(){ + lsrc=$1 + ltgt=$2 + src=${lsrc:0:2} + tgt=${ltgt:0:2} + for ll in $lsrc $ltgt; do + l=${ll:0:2} + f="$orig/*/train.tags.$src-$tgt.$l" + f_raw=$raw/train.$lsrc-$ltgt.$ll + cat $f \ + | grep -v '' \ + | grep -v '' \ + | grep -v '' \ + | grep -v '' \ + | grep -v '' \ + | sed -e 's///g' \ + | sed -e 's/<\/title>//g' \ + | sed -e 's/<description>//g' \ + | sed -e 's/<\/description>//g' \ + | sed 's/^\s*//g' \ + | sed 's/\s*$//g' \ + > $f_raw + [ $? -eq 0 ] && echo "extracted $f to $f_raw" + done + return 0 +} + +convert_valid_test(){ + src=$1 + tgt=$2 + for l in $src $tgt; do + echo "lang: ${l}" + for o in `ls $orig/*/IWSLT*.TED*.$src-$tgt.$l.xml`; do + fname=${o##*/} + f=$tmp/${fname%.*} + echo "$o => $f" + grep '<seg id' $o \ + | sed -e 's/<seg id="[0-9]*">\s*//g' \ + | sed -e 's/\s*<\/seg>\s*//g' \ + | sed -e "s/\’/\'/g" \ + > $f + echo "" + done + done +} + +generate_subset(){ + lsrc=$1 + ltgt=$2 + src=${lsrc:0:2} + tgt=${ltgt:0:2} + subset=$3 + prefix=$4 + for ll in $lsrc $ltgt; do + l=${ll:0:2} + f=$tmp/$prefix.${src}-${tgt}.$l + if [[ -f $f ]]; then + cp $f $raw/$subset.${lsrc}-$ltgt.${ll} + fi + done +} +################# + +echo "downloading iwslt training and dev data" +# using multilingual for it, nl +download_iwslt "2017-01-trnmted" DeEnItNlRo DeEnItNlRo +download_iwslt "2017-01-trnted" ar en +download_iwslt "2017-01-trnted" en ar +download_iwslt "2017-01-trnted" ko en +download_iwslt "2017-01-trnted" en ko +download_iwslt "2015-01" vi en +download_iwslt "2015-01" en vi + +echo "donwloading iwslt test data" +download_iwslt "2017-01-mted-test" it en "test." +download_iwslt "2017-01-mted-test" en it "test." +download_iwslt "2017-01-mted-test" nl en "test." +download_iwslt "2017-01-mted-test" en nl "test." + +download_iwslt "2017-01-ted-test" ar en "test." +download_iwslt "2017-01-ted-test" en ar "test." +download_iwslt "2017-01-ted-test" ko en "test." +download_iwslt "2017-01-ted-test" en ko "test." +download_iwslt "2015-01-test" vi en "test." +download_iwslt "2015-01-test" en vi "test." + +echo "extract training data tar balls" +extract_iwslt DeEnItNlRo DeEnItNlRo +extract_iwslt ar en +extract_iwslt en ar +extract_iwslt ko en +extract_iwslt en ko +extract_iwslt vi en +extract_iwslt en vi + + +echo "extracting iwslt test data" +for lang in $langs; do + l=${lang:0:2} + extract_iwslt $l en "test." + extract_iwslt en $l "test." +done + +echo "convert dev and test data" +for lang in $langs; do + s_lang=${lang:0:2} + convert_valid_test $s_lang en + convert_valid_test en $s_lang +done + + + +echo "creating training data into $raw" +for lang in $langs; do + generate_train $lang en_XX + generate_train en_XX $lang +done + +echo "creating iwslt dev data into raw" +generate_subset en_XX vi_VN valid "IWSLT15.TED.tst2013" +generate_subset vi_VN en_XX valid "IWSLT15.TED.tst2013" + +generate_subset en_XX ar_AR valid "IWSLT17.TED.tst2016" +generate_subset ar_AR en_XX valid "IWSLT17.TED.tst2016" +generate_subset en_XX ko_KR valid "IWSLT17.TED.tst2016" +generate_subset ko_KR en_XX valid "IWSLT17.TED.tst2016" + + +generate_subset en_XX it_IT valid "IWSLT17.TED.tst2010" +generate_subset it_IT en_XX valid "IWSLT17.TED.tst2010" +generate_subset en_XX nl_XX valid "IWSLT17.TED.tst2010" +generate_subset nl_XX en_XX valid "IWSLT17.TED.tst2010" + +echo "creating iswslt test data into raw" +generate_subset en_XX vi_VN test "IWSLT15.TED.tst2015" +generate_subset vi_VN en_XX test "IWSLT15.TED.tst2015" + +generate_subset en_XX ar_AR test "IWSLT17.TED.tst2017" +generate_subset ar_AR en_XX test "IWSLT17.TED.tst2017" +generate_subset en_XX ko_KR test "IWSLT17.TED.tst2017" +generate_subset ko_KR en_XX test "IWSLT17.TED.tst2017" + +generate_subset en_XX it_IT test "IWSLT17.TED.tst2017.mltlng" +generate_subset it_IT en_XX test "IWSLT17.TED.tst2017.mltlng" +generate_subset en_XX nl_XX test "IWSLT17.TED.tst2017.mltlng" +generate_subset nl_XX en_XX test "IWSLT17.TED.tst2017.mltlng" + +# normalze iwslt directions into x-en +pushd $raw +for lang in $langs; do + for split in test valid; do + x_en_f1=$split.$lang-en_XX.en_XX + x_en_f2=$split.$lang-en_XX.${lang} + + en_x_f1=$split.en_XX-$lang.en_XX + en_x_f2=$split.en_XX-$lang.${lang} + + if [ -f $en_x_f1 ] && [ ! -f $x_en_f1 ]; then + echo "cp $en_x_f1 $x_en_f1" + cp $en_x_f1 $x_en_f1 + fi + if [ -f $x_en_f2 ] && [ ! -f $x_en_f2 ]; then + echo "cp $en_x_f2 $x_en_f2" + cp $en_x_f2 $x_en_f2 + fi + done +done +popd \ No newline at end of file diff --git a/examples/multilingual/data_scripts/download_lotus.sh b/examples/multilingual/data_scripts/download_lotus.sh new file mode 100644 index 0000000000..c08c701314 --- /dev/null +++ b/examples/multilingual/data_scripts/download_lotus.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + + +SRCDIR=$WORKDIR_ROOT/indic_languages_corpus +DESTDIR=${WORKDIR_ROOT}/ML50/raw/ +mkdir -p $SRCDIR +mkdir -p $DESTDIR + +cd $SRCDIR +wget http://lotus.kuee.kyoto-u.ac.jp/WAT/indic-multilingual/indic_languages_corpus.tar.gz +tar -xvzf indic_languages_corpus.tar.gz + +SRC_EXTRACT_DIR=$SRCDIR/indic_languages_corpus/bilingual + +cp $SRC_EXTRACT_DIR/ml-en/train.ml $DESTDIR/train.ml_IN-en_XX.ml_IN +cp $SRC_EXTRACT_DIR/ml-en/train.en $DESTDIR/train.ml_IN-en_XX.en_XX +cp $SRC_EXTRACT_DIR/ml-en/dev.ml $DESTDIR/valid.ml_IN-en_XX.ml_IN +cp $SRC_EXTRACT_DIR/ml-en/dev.en $DESTDIR/valid.ml_IN-en_XX.en_XX +cp $SRC_EXTRACT_DIR/ml-en/test.ml $DESTDIR/test.ml_IN-en_XX.ml_IN +cp $SRC_EXTRACT_DIR/ml-en/test.en $DESTDIR/test.ml_IN-en_XX.en_XX + +cp $SRC_EXTRACT_DIR/ur-en/train.ur $DESTDIR/train.ur_PK-en_XX.ur_PK +cp $SRC_EXTRACT_DIR/ur-en/train.en $DESTDIR/train.ur_PK-en_XX.en_XX +cp $SRC_EXTRACT_DIR/ur-en/dev.ur $DESTDIR/valid.ur_PK-en_XX.ur_PK +cp $SRC_EXTRACT_DIR/ur-en/dev.en $DESTDIR/valid.ur_PK-en_XX.en_XX +cp $SRC_EXTRACT_DIR/ur-en/test.ur $DESTDIR/test.ur_PK-en_XX.ur_PK +cp $SRC_EXTRACT_DIR/ur-en/test.en $DESTDIR/test.ur_PK-en_XX.en_XX + +cp $SRC_EXTRACT_DIR/te-en/train.te $DESTDIR/train.te_IN-en_XX.te_IN +cp $SRC_EXTRACT_DIR/te-en/train.en $DESTDIR/train.te_IN-en_XX.en_XX +cp $SRC_EXTRACT_DIR/te-en/dev.te $DESTDIR/valid.te_IN-en_XX.te_IN +cp $SRC_EXTRACT_DIR/te-en/dev.en $DESTDIR/valid.te_IN-en_XX.en_XX +cp $SRC_EXTRACT_DIR/te-en/test.te $DESTDIR/test.te_IN-en_XX.te_IN +cp $SRC_EXTRACT_DIR/te-en/test.en $DESTDIR/test.te_IN-en_XX.en_XX diff --git a/examples/multilingual/data_scripts/download_ted_and_extract.py b/examples/multilingual/data_scripts/download_ted_and_extract.py new file mode 100644 index 0000000000..eb756680fa --- /dev/null +++ b/examples/multilingual/data_scripts/download_ted_and_extract.py @@ -0,0 +1,338 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import itertools +import os +import csv +from collections import defaultdict +from six.moves import zip +import io +import wget +import sys + +from subprocess import check_call, check_output + +# scripts and data locations +CWD = os.getcwd() +UTILS = f"{CWD}/utils" + +MOSES = f"{UTILS}/mosesdecoder" + +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + + +# please donwload mosesdecoder here: +detok_cmd = f'{MOSES}/scripts/tokenizer/detokenizer.perl' + + +def call(cmd): + print(f"Executing: {cmd}") + check_call(cmd, shell=True) + +class MultiLingualAlignedCorpusReader(object): + """A class to read TED talk dataset + """ + + def __init__(self, corpus_path, delimiter='\t', + target_token=True, bilingual=True, corpus_type='file', + lang_dict={'source': ['fr'], 'target': ['en']}, + eval_lang_dict=None, zero_shot=False, + detok=True, + ): + + self.empty_line_flag = 'NULL' + self.corpus_path = corpus_path + self.delimiter = delimiter + self.bilingual = bilingual + self.lang_dict = lang_dict + self.lang_set = set() + self.target_token = target_token + self.zero_shot = zero_shot + self.eval_lang_dict = eval_lang_dict + self.corpus_type = corpus_type + self.detok = detok + + for list_ in self.lang_dict.values(): + for lang in list_: + self.lang_set.add(lang) + + self.data = dict() + self.data['train'] = self.read_aligned_corpus(split_type='train') + self.data['test'] = self.read_aligned_corpus(split_type='test') + self.data['dev'] = self.read_aligned_corpus(split_type='dev') + + def read_data(self, file_loc_): + data_list = list() + with io.open(file_loc_, 'r', encoding='utf8') as fp: + for line in fp: + try: + text = line.strip() + except IndexError: + text = self.empty_line_flag + data_list.append(text) + return data_list + + def filter_text(self, dict_): + if self.target_token: + field_index = 1 + else: + field_index = 0 + data_dict = defaultdict(list) + list1 = dict_['source'] + list2 = dict_['target'] + for sent1, sent2 in zip(list1, list2): + try: + src_sent = ' '.join(sent1.split()[field_index: ]) + except IndexError: + src_sent = 'NULL' + + if src_sent.find(self.empty_line_flag) != -1 or len(src_sent) == 0: + continue + + elif sent2.find(self.empty_line_flag) != -1 or len(sent2) == 0: + continue + + else: + data_dict['source'].append(sent1) + data_dict['target'].append(sent2) + return data_dict + + def read_file(self, split_type, data_type): + return self.data[split_type][data_type] + + def save_file(self, path_, split_type, data_type, lang): + tok_file = tok_file_name(path_, lang) + with io.open(tok_file, 'w', encoding='utf8') as fp: + for line in self.data[split_type][data_type]: + fp.write(line + '\n') + if self.detok: + de_tok(tok_file, lang) + + def add_target_token(self, list_, lang_id): + new_list = list() + token = '__' + lang_id + '__' + for sent in list_: + new_list.append(token + ' ' + sent) + return new_list + + def read_from_single_file(self, path_, s_lang, t_lang): + data_dict = defaultdict(list) + with io.open(path_, 'r', encoding='utf8') as fp: + reader = csv.DictReader(fp, delimiter='\t', quoting=csv.QUOTE_NONE) + for row in reader: + data_dict['source'].append(row[s_lang]) + data_dict['target'].append(row[t_lang]) + + if self.target_token: + text = self.add_target_token(data_dict['source'], t_lang) + data_dict['source'] = text + + return data_dict['source'], data_dict['target'] + + def read_aligned_corpus(self, split_type='train'): + data_dict = defaultdict(list) + iterable = [] + s_list = [] + t_list = [] + + if self.zero_shot: + if split_type == "train": + iterable = zip(self.lang_dict['source'], self.lang_dict['target']) + else: + iterable = zip(self.eval_lang_dict['source'], self.eval_lang_dict['target']) + + elif self.bilingual: + iterable = itertools.product(self.lang_dict['source'], self.lang_dict['target']) + + for s_lang, t_lang in iterable: + if s_lang == t_lang: + continue + if self.corpus_type == 'file': + split_type_file_path = os.path.join(self.corpus_path, + "all_talks_{}.tsv".format(split_type)) + s_list, t_list = self.read_from_single_file(split_type_file_path, + s_lang=s_lang, + t_lang=t_lang) + data_dict['source'] += s_list + data_dict['target'] += t_list + new_data_dict = self.filter_text(data_dict) + return new_data_dict + + +def read_langs(corpus_path): + split_type_file_path = os.path.join(corpus_path, 'extracted', + "all_talks_dev.tsv") + with io.open(split_type_file_path, 'r', encoding='utf8') as fp: + reader = csv.DictReader(fp, delimiter='\t', quoting=csv.QUOTE_NONE) + header = next(reader) + return [k for k in header.keys() if k != 'talk_name'] + +def extra_english(corpus_path, split): + split_type_file_path = os.path.join(corpus_path, + f"all_talks_{split}.tsv") + output_split_type_file_path = os.path.join(corpus_path, + f"all_talks_{split}.en") + with io.open(split_type_file_path, 'r', encoding='utf8') as fp, io.open(output_split_type_file_path, 'w', encoding='utf8') as fw: + reader = csv.DictReader(fp, delimiter='\t', quoting=csv.QUOTE_NONE) + for row in reader: + line = row['en'] + fw.write(line + '\n') + de_tok(output_split_type_file_path, 'en') + + + +def tok_file_name(filename, lang): + seps = filename.split('.') + seps.insert(-1, 'tok') + tok_file = '.'.join(seps) + return tok_file + +def de_tok(tok_file, lang): + # seps = tok_file.split('.') + # seps.insert(-1, 'detok') + # de_tok_file = '.'.join(seps) + de_tok_file = tok_file.replace('.tok.', '.') + cmd = 'perl {detok_cmd} -l {lang} < {tok_file} > {de_tok_file}'.format( + detok_cmd=detok_cmd, tok_file=tok_file, + de_tok_file=de_tok_file, lang=lang[:2]) + call(cmd) + +def extra_bitex( + ted_data_path, + lsrc_lang, + ltrg_lang, + target_token, + output_data_path, +): + def get_ted_lang(lang): + long_langs = ['pt-br', 'zh-cn', 'zh-tw', 'fr-ca'] + if lang[:5] in long_langs: + return lang[:5] + elif lang[:4] =='calv': + return lang[:5] + elif lang in ['pt_BR', 'zh_CN', 'zh_TW', 'fr_CA']: + return lang.lower().replace('_', '-') + return lang[:2] + src_lang = get_ted_lang(lsrc_lang) + trg_lang = get_ted_lang(ltrg_lang) + train_lang_dict={'source': [src_lang], 'target': [trg_lang]} + eval_lang_dict = {'source': [src_lang], 'target': [trg_lang]} + + obj = MultiLingualAlignedCorpusReader(corpus_path=ted_data_path, + lang_dict=train_lang_dict, + target_token=target_token, + corpus_type='file', + eval_lang_dict=eval_lang_dict, + zero_shot=False, + bilingual=True) + + os.makedirs(output_data_path, exist_ok=True) + lsrc_lang = lsrc_lang.replace('-', '_') + ltrg_lang = ltrg_lang.replace('-', '_') + obj.save_file(output_data_path + f"/train.{lsrc_lang}-{ltrg_lang}.{lsrc_lang}", + split_type='train', data_type='source', lang=src_lang) + obj.save_file(output_data_path + f"/train.{lsrc_lang}-{ltrg_lang}.{ltrg_lang}", + split_type='train', data_type='target', lang=trg_lang) + + obj.save_file(output_data_path + f"/test.{lsrc_lang}-{ltrg_lang}.{lsrc_lang}", + split_type='test', data_type='source', lang=src_lang) + obj.save_file(output_data_path + f"/test.{lsrc_lang}-{ltrg_lang}.{ltrg_lang}", + split_type='test', data_type='target', lang=trg_lang) + + obj.save_file(output_data_path + f"/valid.{lsrc_lang}-{ltrg_lang}.{lsrc_lang}", + split_type='dev', data_type='source', lang=src_lang) + obj.save_file(output_data_path + f"/valid.{lsrc_lang}-{ltrg_lang}.{ltrg_lang}", + split_type='dev', data_type='target', lang=trg_lang) + + +def bar_custom(current, total, width=80): + print("Downloading: %d%% [%d / %d] Ks" % (current / total * 100, current / 1000, total / 1000), end='\r') + + +def download_and_extract(download_to, extract_to): + url = 'http://phontron.com/data/ted_talks.tar.gz' + filename = f"{download_to}/ted_talks.tar.gz" + if os.path.exists(filename): + print(f'{filename} has already been downloaded so skip') + else: + filename = wget.download(url, filename, bar=bar_custom) + if os.path.exists(f'{extract_to}/all_talks_train.tsv'): + print(f'Already extracted so skip') + else: + extract_cmd = f'tar xzfv "{filename}" -C "{extract_to}"' + call(extract_cmd) + + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('--ted_data_path', type=str, default=WORKDIR_ROOT, required=False) + parser.add_argument( + '--direction-list', + type=str, + # default=None, + #for ML50 + default=( + "bn_IN-en_XX,he_IL-en_XX,fa_IR-en_XX,id_ID-en_XX,sv_SE-en_XX,pt_XX-en_XX,ka_GE-en_XX,ka_GE-en_XX,th_TH-en_XX," + "mr_IN-en_XX,hr_HR-en_XX,uk_UA-en_XX,az_AZ-en_XX,mk_MK-en_XX,gl_ES-en_XX,sl_SI-en_XX,mn_MN-en_XX," + #non-english directions + # "fr_XX-de_DE," # replaced with wmt20 + # "ja_XX-ko_KR,es_XX-pt_XX,ru_RU-sv_SE,hi_IN-bn_IN,id_ID-ar_AR,cs_CZ-pl_PL,ar_AR-tr_TR" + ), + required=False) + parser.add_argument('--target-token', action='store_true', default=False) + parser.add_argument('--extract-all-english', action='store_true', default=False) + + args = parser.parse_args() + + import sys + import json + + # TED Talks data directory + ted_data_path = args.ted_data_path + + download_to = f'{ted_data_path}/downloads' + extract_to = f'{ted_data_path}/extracted' + + #DESTDIR=${WORKDIR_ROOT}/ML50/raw/ + output_path = f'{ted_data_path}/ML50/raw' + os.makedirs(download_to, exist_ok=True) + os.makedirs(extract_to, exist_ok=True) + os.makedirs(output_path, exist_ok=True) + download_and_extract(download_to, extract_to) + + + if args.extract_all_english: + for split in ['train', 'dev', 'test']: + extra_english(ted_data_path, split) + exit(0) + if args.direction_list is not None: + directions = args.direction_list.strip().split(',') + directions = [tuple(d.strip().split('-', 1)) for d in directions if d] + else: + langs = read_langs(ted_data_path) + # directions = [ + # '{}.{}'.format(src, tgt) + # for src in langs + # for tgt in langs + # if src < tgt + # ] + directions = [('en', tgt) for tgt in langs if tgt != 'en'] + print(f'num directions={len(directions)}: {directions}') + + for src_lang, trg_lang in directions: + print('--working on {}-{}'.format(src_lang, trg_lang)) + extra_bitex( + extract_to, + src_lang, + trg_lang, + target_token=args.target_token, + output_data_path=output_path + ) diff --git a/examples/multilingual/data_scripts/download_wat19_my.sh b/examples/multilingual/data_scripts/download_wat19_my.sh new file mode 100644 index 0000000000..c1e2d47287 --- /dev/null +++ b/examples/multilingual/data_scripts/download_wat19_my.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + + +SRCDIR=$WORKDIR_ROOT/indic_languages_corpus +DESTDIR=$WORKDIR_ROOT/ML50/raw +mkdir -p $SRCDIR +mkdir -p $DESTDIR + +WAT_MY_EN=wat2020.my-en.zip +cd $SRCDIR +# please refer to http://lotus.kuee.kyoto-u.ac.jp/WAT/my-en-data/ for latest URL if the following url expired +#- The data used for WAT2020 are identical to those used in WAT2019. +wget http://lotus.kuee.kyoto-u.ac.jp/WAT/my-en-data/$WAT_MY_EN +unzip $WAT_MY_EN + + +SRC_EXTRACT_DIR=$SRCDIR/wat2020.my-en/alt + +cp $SRC_EXTRACT_DIR/train.alt.en $DESTDIR/train.my_MM-en_XX.en_XX +cp $SRC_EXTRACT_DIR/train.alt.my $DESTDIR/train.my_MM-en_XX.my_MM +cp $SRC_EXTRACT_DIR/dev.alt.en $DESTDIR/valid.my_MM-en_XX.en_XX +cp $SRC_EXTRACT_DIR/dev.alt.my $DESTDIR/valid.my_MM-en_XX.my_MM +cp $SRC_EXTRACT_DIR/test.alt.en $DESTDIR/test.my_MM-en_XX.en_XX +cp $SRC_EXTRACT_DIR/test.alt.my $DESTDIR/test.my_MM-en_XX.my_MM diff --git a/examples/multilingual/data_scripts/download_wmt19_and_before.py b/examples/multilingual/data_scripts/download_wmt19_and_before.py new file mode 100644 index 0000000000..3465731eb3 --- /dev/null +++ b/examples/multilingual/data_scripts/download_wmt19_and_before.py @@ -0,0 +1,899 @@ +from typing import NamedTuple, List +from urllib.parse import urlparse +import os, sys +import subprocess +from subprocess import check_call, check_output +import glob +import wget +import re +import multiprocessing as mp +from functools import partial +import pathlib +from collections import OrderedDict + +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + +# scripts and data locations +CWD = os.getcwd() +UTILS = f"{CWD}/utils" + +MOSES = f"{UTILS}/mosesdecoder" +SGM_TOOL = f'{MOSES}/scripts/ems/support/input-from-sgm.perl' + +TMX2CORPUS = f"{UTILS}/tmx2corpus" +TMX_TOOL = f'python {TMX2CORPUS}/tmx2corpus.py' + +to_data_path = f'{WORKDIR_ROOT}/wmt' +download_to = f'{to_data_path}/downloads' +manually_downloads = f'{to_data_path}/downloads' +extract_to = f'{to_data_path}/extracted' +#DESTDIR=${WORKDIR_ROOT}/ML50/raw/ +raw_data = f'{WORKDIR_ROOT}/ML50/raw' +#### + +class DLDataset(NamedTuple): + name: str + train_urls: List[str] + valid_urls: List[str] + test_urls: List[str] + train_files_patterns: List[str] = [] + valid_files_patterns: List[str] = [] + test_files_patterns: List[str] = [] + + + +def bar_custom(current, total, width=80): + print("Downloading: %d%% [%d / %d] Ks" % (current / total * 100, current / 1000, total / 1000), end='\r') + +def get_downloaded_file(dl_folder, url): + if isinstance(url, tuple): + url, f = url + else: + url_f = urlparse(url) + # f = os.path.split(url_f.path)[-1] + f = '_'.join(url_f.path.split('/')[1:]) + return url, f"{dl_folder}/{f}" + +def download_parts_and_combine(dl_folder, urls, filename): + parts = [] + for url_record in urls: + url, part_file = get_downloaded_file(dl_folder, url_record) + if os.path.exists(part_file): + print(f'{part_file} has already been downloaded so skip') + else: + part_file = wget.download(url, part_file, bar=bar_custom) + parts.append(part_file) + + def get_combine_cmd(parts): + #default as tar.gz.?? + return f'cat {" ".join(parts)} > {filename}' + + combine_cmd = get_combine_cmd(parts) + call(combine_cmd, debug=True) + return filename + +def download_a_url(dl_folder, url): + url, filename = get_downloaded_file(dl_folder, url) + if os.path.exists(filename): + print(f'{filename} has already been downloaded so skip') + return filename + + print(f'downloading {url} to {filename}') + if isinstance(url, list) or isinstance(url, tuple): + download_parts_and_combine(dl_folder, url, filename) + else: + wget.download(url, filename, bar=bar_custom) + print(f'dowloaded: {filename}') + return filename + +def download_files(dl_folder, urls, completed_urls={}): + for url_record in urls: + url, _ = get_downloaded_file(dl_folder, url_record) + filename = download_a_url(dl_folder, url_record) + completed_urls[str(url)] = filename + return completed_urls + +def check_need_manual_downalod(dl_folder, to_manually_download_urls): + to_be_manually_dowloaded = [] + manually_completed_urls = {} + for url_record, instruction in to_manually_download_urls: + url, filename = get_downloaded_file(dl_folder, url_record) + if not os.path.exists(filename): + print(f'{url} need to be download manually, please download it manually following {instruction}; and copy it to {filename}') + to_be_manually_dowloaded.append((url, filename)) + else: + manually_completed_urls[url] = filename + # if len(to_be_manually_dowloaded) > 0: + # raise ValueError('Missing files that need to be downloaded manually; stop the process now.') + return to_be_manually_dowloaded + +def download_dataset(to_folder, dl_dataset, completed_urls={}): + download_files(to_folder, dl_dataset.train_urls, completed_urls) + download_files(to_folder, dl_dataset.valid_urls, completed_urls) + download_files(to_folder, dl_dataset.test_urls, completed_urls) + print('completed downloading') + return completed_urls + +def call(cmd, debug=False): + if debug: + print(cmd) + check_call(cmd, shell=True) + + +def get_extract_name(file_path): + path = os.path.split(file_path) + return path[-1] + '_extract' #.split('.')[0] + +def extract_file(downloaded_file, extract_folder, get_extract_name=get_extract_name, debug=False): + extract_name = get_extract_name(downloaded_file) + extract_to = f'{extract_folder}/{extract_name}' + os.makedirs(extract_to, exist_ok=True) + if os.path.exists(f'{extract_to}/DONE'): + print(f'{downloaded_file} has already been extracted to {extract_to} so skip') + return extract_to + def get_extract_cmd(filename): + if filename.endswith('.tgz') or filename.endswith('tar.gz'): + return f'tar xzfv {filename} -C {extract_to}' + elif filename.endswith('.gz.tar'): + return f'tar xfv {filename} -C {extract_to}; (cd {extract_to}; gzip -d *.gz; [ $? -eq 0 ] || gzip -d */*.gz)' + elif filename.endswith('.tar'): + return f'tar xfv {filename} -C {extract_to}' + elif filename.endswith('.gz'): + return f'cp {filename} {extract_to}; (cd {extract_to}; gzip -d *.gz)' + elif filename.endswith('.zip'): + return f'unzip {filename} -d {extract_to}' + extract_cmd = get_extract_cmd(downloaded_file) + print(f'extracting {downloaded_file}') + if isinstance(extract_cmd, list): + for c in extract_cmd: + call(c, debug=debug) + else: + call(extract_cmd, debug=debug) + call(f'echo DONE > {extract_to}/DONE') + return extract_to + + +def extract_all_files( + completed_urls, extract_folder, + get_extract_name=get_extract_name, + completed_extraction={}, + debug=False): + extracted_folders = OrderedDict() + for url, downloaded_file in set(completed_urls.items()): + if downloaded_file in completed_extraction: + print(f'{downloaded_file} is already extracted; so skip') + continue + folder = extract_file(downloaded_file, extract_folder, get_extract_name, debug) + extracted_folders[url] = folder + return extracted_folders + + +def my_glob(folder): + for p in [f'{folder}/*', f'{folder}/*/*', f'{folder}/*/*/*']: + for f in glob.glob(p): + yield f + + +def sgm2raw(sgm, debug): + to_file = sgm[0:len(sgm) - len('.sgm')] + if os.path.exists(to_file): + debug and print(f'{sgm} already converted to {to_file}; so skip') + return to_file + cmd = f'{SGM_TOOL} < {sgm} > {to_file}' + call(cmd, debug) + return to_file + +def tmx2raw(tmx, debug): + to_file = tmx[0:len(tmx) - len('.tmx')] + to_folder = os.path.join(*os.path.split(tmx)[:-1]) + if os.path.exists(f'{to_folder}/bitext.en'): + debug and print(f'{tmx} already extracted to {to_file}; so skip') + return to_file + cmd = f'(cd {to_folder}; {TMX_TOOL} {tmx})' + call(cmd, debug) + return to_file + +CZENG16_REGEX = re.compile(r'.*?data.plaintext-format/0[0-9]train$') +WMT19_WIKITITLES_REGEX = re.compile(r'.*?wikititles-v1.(\w\w)-en.tsv.gz') +TSV_REGEX = re.compile(r'.*?(\w\w)-(\w\w).tsv$') + + + +def cut_wikitles(wiki_file, debug): + # different languages have different file names: + if wiki_file.endswith('wiki/fi-en/titles.fi-en'): + to_file1 = f'{wiki_file}.fi' + to_file2 = f'{wiki_file}.en' + BACKSLASH = '\\' + cmd1 = f"cat {wiki_file} | sed 's/|||/{BACKSLASH}t/g' |cut -f1 |awk '{{$1=$1}};1' > {to_file1}" + cmd2 = f"cat {wiki_file} | sed 's/|||/{BACKSLASH}t/g' |cut -f2 |awk '{{$1=$1}};1' > {to_file2}" +# elif WMT19_WIKITITLES_REGEX.match(wiki_file): +# src = WMT19_WIKITITLES_REGEX.match(wiki_file).groups()[0] +# to_file1 = f'{wiki_file}.{src}' +# to_file2 = f'{wiki_file}.en' +# cmd1 = f"cat {wiki_file} | cut -f1 |awk '{{$1=$1}};1' > {to_file1}" +# cmd2 = f"cat {wiki_file} | cut -f2 |awk '{{$1=$1}};1' > {to_file2}" + else: + return None + if os.path.exists(to_file1) and os.path.exists(to_file2): + debug and print(f'{wiki_file} already processed to {to_file1} and {to_file2}; so skip') + return wiki_file + + call(cmd1, debug=debug) + call(cmd2, debug=debug) + return wiki_file + +def cut_tsv(file, debug): + m = TSV_REGEX.match(file) + if m is None: + raise ValueError(f'{file} is not matching tsv pattern') + src = m.groups()[0] + tgt = m.groups()[1] + + to_file1 = f'{file}.{src}' + to_file2 = f'{file}.{tgt}' + cmd1 = f"cat {file} | cut -f1 |awk '{{$1=$1}};1' > {to_file1}" + cmd2 = f"cat {file} | cut -f2 |awk '{{$1=$1}};1' > {to_file2}" + if os.path.exists(to_file1) and os.path.exists(to_file2): + debug and print(f'{file} already processed to {to_file1} and {to_file2}; so skip') + return file + + call(cmd1, debug=debug) + call(cmd2, debug=debug) + return file + + +def convert_file_if_needed(file, debug): + if file.endswith('.sgm'): + return sgm2raw(file, debug) + elif file.endswith('.tmx'): + return tmx2raw(file, debug) + elif file.endswith('wiki/fi-en/titles.fi-en'): + return cut_wikitles(file, debug) +# elif WMT19_WIKITITLES_REGEX.match(file): +# return cut_wikitles(file, debug) + elif file.endswith('.tsv'): + return cut_tsv(file, debug) + elif CZENG16_REGEX.match(file): + return convert2czeng17(file, debug) + else: + return file + + +def convert_files_if_needed(extracted_foldrs, my_glob=my_glob, debug=False): + return { + url: list(sorted(set(convert_file_if_needed(f, debug)) for f in sorted(set(my_glob(folder))))) + for url, folder in extracted_foldrs.items() + } + +def match_patt(file_path, file_pattern, src, tgt, lang): + return file_pattern.format(src=src, tgt=tgt, lang=lang) in file_path + +def match_patts(file_path, file_patterns, src, tgt, lang): + for file_pattern in file_patterns: + params = { k: v for k, v in [('src', src), ('tgt', tgt), ('lang', lang)] if k in file_pattern} + matching = file_pattern.format(**params) + + if isinstance(file_pattern, tuple): + pattern, directions = file_pattern + if f'{src}-{tgt}' in directions and matching in file_path: + return True + else: + if matching in file_path: + return True + return False + +def extracted_glob(extracted_folder, file_patterns, src, tgt, lang): + def get_matching_pattern(file_pattern): + params = { + k: v + for k, v in [('src', src), ('tgt', tgt), ('lang', lang)] + if '{' + k + '}' in file_pattern + } + file_pattern = re.sub(r'{src:(.*?)}', r'\1' if lang == src else '', file_pattern) + file_pattern = re.sub(r'{tgt:(.*?)}', r'\1' if lang == tgt else '', file_pattern) + file_pattern = file_pattern.format(**params) + return file_pattern + for file_pattern in file_patterns: + if isinstance(file_pattern, tuple): + file_pattern, lang_pairs = file_pattern + if f'{src}-{tgt}' not in lang_pairs: + continue +# print('working on pattern: ', file_pattern, lang_pairs ) + matching_pattern = get_matching_pattern(file_pattern) + if matching_pattern is None: + continue + glob_patterns = f'{extracted_folder}/{matching_pattern}' +# print('glob_patterns: ', glob_patterns) + for f in glob.glob(glob_patterns): + yield f + +# for debug usage +def all_extracted_files(split, src, tgt, extracted_folders, split_urls): + def get_url(url): + if isinstance(url, tuple): + url, downloaded_file = url + return url + return [ + f + for url in split_urls + for f in my_glob(extracted_folders[str(get_url(url))]) + ] + +def concat_files(split, src, tgt, extracted_folders, split_urls, path_patterns, to_folder, debug=False): +# if debug: +# print('extracted files to be filtered by patterns: ', +# '\n\t'.join(sorted(all_extracted_files(split, src, tgt, extracted_folders, split_urls)))) + for lang in [src, tgt]: + to_file = f'{to_folder}/{split}.{src}-{tgt}.{lang}' + s_src, s_tgt, s_lang = src.split('_')[0], tgt.split('_')[0], lang.split('_')[0] + files = [] + for url in split_urls: + if isinstance(url, tuple): + url, downloaded_file = url + if str(url) not in extracted_folders: + print(f'warning: {url} not in extracted files') + for extracted_file in set( + extracted_glob( + extracted_folders[str(url)], path_patterns, + s_src, s_tgt, s_lang)): + files.append(extracted_file) + if len(files) == 0: + print('warning: ', f'No files found for split {to_file}') + continue + files = sorted(set(files)) + print(f'concating {len(files)} files into {to_file}') + cmd = ['cat'] + [f'"{f}"' for f in files] + [f'>{to_file}'] + cmd = " ".join(cmd) + call(cmd, debug=debug) + +UTILS = os.path.join(pathlib.Path(__file__).parent, 'utils') +LID_MODEL = f'{download_to}/lid.176.bin' +LID_MULTI = f'{UTILS}/fasttext_multi_filter.py' + +def lid_filter(split, src, tgt, from_folder, to_folder, debug=False): + if not os.path.exists(LID_MODEL): + call(f'wget -nc https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin -O {LID_MODEL}') + from_prefix = f'{from_folder}/{split}.{src}-{tgt}' + to_prefix = f'{to_folder}/{split}.{src}-{tgt}' + if os.path.exists(f'{from_prefix}.{src}') and os.path.exists(f'{from_prefix}.{tgt}'): + s_src, s_tgt = src.split('_')[0], tgt.split('_')[0] + cmd = ( + f'python {LID_MULTI} --model {LID_MODEL} --inputs {from_prefix}.{src} {from_prefix}.{tgt} ' + f'--langs {s_src} {s_tgt} --outputs {to_prefix}.{src} {to_prefix}.{tgt}' + ) + print(f'filtering {from_prefix}') + call(cmd, debug=debug) + +def concat_into_splits(dl_dataset, src, tgt, extracted_folders, to_folder, debug): + to_folder_tmp = f"{to_folder}_tmp" + os.makedirs(to_folder_tmp, exist_ok=True) + concat_files('train', src, tgt, + extracted_folders, + split_urls=dl_dataset.train_urls, + path_patterns=dl_dataset.train_files_patterns, + to_folder=to_folder_tmp, debug=debug) + lid_filter('train', src, tgt, to_folder_tmp, to_folder, debug) + + concat_files('valid', src, tgt, + extracted_folders, + split_urls=dl_dataset.valid_urls, + path_patterns=dl_dataset.valid_files_patterns, + to_folder=to_folder, debug=debug) + concat_files('test', src, tgt, + extracted_folders, + split_urls=dl_dataset.test_urls, + path_patterns=dl_dataset.test_files_patterns, + to_folder=to_folder, debug=debug) + + +def download_multi(dl_folder, extract_folder, urls, num_processes=8, debug=False): + pool = mp.Pool(processes=num_processes) + download_f = partial(download_a_url, dl_folder) + downloaded_files = pool.imap_unordered(download_f, urls) + pool.close() + pool.join() + +BLEU_REGEX = re.compile("^BLEU\\S* = (\\S+) ") +def run_eval_bleu(cmd): + output = check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode("utf-8").strip() + print(output) + bleu = -1.0 + for line in output.strip().split('\n'): + m = BLEU_REGEX.search(line) + if m is not None: + bleu = m.groups()[0] + bleu = float(bleu) + break + return bleu + +def check_wmt_test_bleu(raw_folder, wmt_lang_pairs): + not_matchings = [] + for wmt, src_tgts in wmt_lang_pairs: + for src_tgt in src_tgts: + print(f'checking test bleus for: {src_tgt} at {wmt}') + src, tgt = src_tgt.split('-') + ssrc, stgt = src[:2], tgt[:2] + if os.path.exists(f'{raw_folder}/test.{tgt}-{src}.{src}'): + # reversed direction may have different test set + test_src = f'{raw_folder}/test.{tgt}-{src}.{src}' + else: + test_src = f'{raw_folder}/test.{src}-{tgt}.{src}' + cmd1 = f'cat {test_src} | sacrebleu -t "{wmt}" -l {stgt}-{ssrc}; [ $? -eq 0 ] || echo ""' + test_tgt = f'{raw_folder}/test.{src}-{tgt}.{tgt}' + cmd2 = f'cat {test_tgt} | sacrebleu -t "{wmt}" -l {ssrc}-{stgt}; [ $? -eq 0 ] || echo ""' + bleu1 = run_eval_bleu(cmd1) + if bleu1 != 100.0: + not_matchings.append(f'{wmt}:{src_tgt} source side not matching: {test_src}') + bleu2 = run_eval_bleu(cmd2) + if bleu2 != 100.0: + not_matchings.append(f'{wmt}:{src_tgt} target side not matching: {test_tgt}') + return not_matchings + +def download_and_extract( + to_folder, lang_pairs, dl_dataset, + to_manually_download_urls, + completed_urls={}, completed_extraction={}, + debug=False): + + dl_folder = f'{to_folder}/downloads' + extract_folder = f'{to_folder}/extracted' + raw_folder = f'{to_folder}/raw' + lid_filtered = f'{to_folder}/lid_filtered' + + os.makedirs(extract_folder, exist_ok=True) + os.makedirs(raw_folder, exist_ok=True) + os.makedirs(lid_filtered, exist_ok=True) + + + to_be_manually_dowloaded = check_need_manual_downalod(dl_folder, to_manually_download_urls) + + completed_urls = download_dataset( + dl_folder, dl_dataset, completed_urls) + if debug: + print('completed urls: ', completed_urls) + + + extracted_folders = extract_all_files( + completed_urls, + extract_folder=extract_folder, + completed_extraction=completed_extraction, + debug=debug) + if debug: + print('download files have been extracted to folders: ', extracted_folders) + + converted_files = convert_files_if_needed(extracted_folders, debug=False) + for src_tgt in lang_pairs: + print(f'working on {dl_dataset.name}: {src_tgt}') + src, tgt = src_tgt.split('-') + concat_into_splits(dl_dataset, + src=src, tgt=tgt, + extracted_folders=extracted_folders, + to_folder=raw_folder, debug=debug) + print('completed data into: ', raw_folder) + +def download_czang16(download_to, username=None): + wgets = [ + f'wget --user={username} --password=czeng -P {download_to} http://ufallab.ms.mff.cuni.cz/~bojar/czeng16-data/data-plaintext-format.{i}.tar' + for i in range(10)] + cmds = [] + for i, cmd in enumerate(wgets): + filename = f'{download_to}/data-plaintext-format.{i}.tar' + if os.path.exists(filename): + print(f'{filename} has already been downloaded; so skip') + continue + cmds.append(cmd) + if cmds and username is None: + raise ValueError('No czeng username is given; please register at http://ufal.mff.cuni.cz/czeng/czeng16 to obtain username to download') + for cmd in cmds: + call(cmd) + print('done with downloading czeng1.6') + +def download_czeng17_script(download_to, extract_folder, debug=False): + url = 'http://ufal.mff.cuni.cz/czeng/download.php?f=convert_czeng16_to_17.pl.zip' + filename = f'{download_to}/convert_czeng16_to_17.pl.zip' + extract_to = f'{extract_folder}/{get_extract_name(filename)}' + script_path = f'{extract_to}/convert_czeng16_to_17.pl' + + if not os.path.exists(script_path): + wget.download(url, filename, bar=bar_custom) + extract_to = extract_file(f'{download_to}/convert_czeng16_to_17.pl.zip', extract_folder, get_extract_name=get_extract_name, debug=debug) + return script_path + +czeng17_script_path = "" +def convert2czeng17(file, debug): + en_file = f'{file}.en' + cs_file = f'{file}.cs' + + if not os.path.exists(en_file) or not os.path.exists(cs_file): + cs_cmd = f'cat {file} | perl {czeng17_script_path} | cut -f3 > {cs_file}' + en_cmd = f'cat {file} | perl {czeng17_script_path} | cut -f4 > {en_file}' + call(cs_cmd, debug) + call(en_cmd, debug) + else: + print(f'already extracted: {en_file} and {cs_file}') + return file + +def extract_czeng17(extract_folder, debug=False): + url = 'http://ufal.mff.cuni.cz/czeng/download.php?f=convert_czeng16_to_17.pl.zip' + filename = f'{download_to}/convert_czeng16_to_17.pl.zip' + extract_to = f'{extract_folder}/{get_extract_name(filename)}' + script_path = f'{extract_to}/convert_czeng16_to_17.pl' + + if not os.path.exists(script_path): + wget.download(url, filename, bar=bar_custom) + extract_to = extract_file(f'{download_to}/convert_czeng16_to_17.pl.zip', extract_folder, get_extract_name=get_extract_name, debug=debug) + return script_path + +######### +# definitions of wmt data sources +# for es-en +# Punctuation in the official test sets will be encoded with ASCII characters (not complex Unicode characters) as much as possible. You may want to normalize your system's output before submission. You are able able to use a rawer version of the test sets that does not have this normalization. +# script to normalize punctuation: http://www.statmt.org/wmt11/normalize-punctuation.perl +wmt13_es_en = DLDataset( + name='wmt13_es-en', + train_urls=[ + 'http://www.statmt.org/wmt13/training-parallel-europarl-v7.tgz', + 'http://www.statmt.org/wmt13/training-parallel-commoncrawl.tgz', + 'http://www.statmt.org/wmt13/training-parallel-un.tgz', + 'http://www.statmt.org/wmt13/training-parallel-nc-v8.tgz', + ], + valid_urls=[ + ('http://www.statmt.org/wmt13/dev.tgz', 'wmt13_dev.tgz') + ], + test_urls=[ + ('http://www.statmt.org/wmt13/test.tgz', 'wmt13_test.tgz') + ], + train_files_patterns=[ + ('*/europarl-v7.{src}-{tgt}.{lang}', ['es-en']), + ('*commoncrawl.{src}-{tgt}.{lang}', ['es-en']), + ('*/news-commentary-v8.{src}-{tgt}.{lang}', ['es-en']), + ('un/*undoc.2000.{src}-{tgt}.{lang}', ['es-en']), + ] , + valid_files_patterns=[ + ('dev/newstest2012.{lang}', ['es-en']) + ], + test_files_patterns=[ + ('test/newstest*.{lang}', ['es-en']) + ], +) + +wmt14_de_fr_en = DLDataset( + name='wmt14_de_fr_en', + train_urls=[ + 'http://www.statmt.org/wmt13/training-parallel-europarl-v7.tgz', + 'http://www.statmt.org/wmt13/training-parallel-commoncrawl.tgz', + 'http://www.statmt.org/wmt13/training-parallel-un.tgz', + 'http://www.statmt.org/wmt14/training-parallel-nc-v9.tgz', + ('http://www.statmt.org/wmt10/training-giga-fren.tar', 'training-giga-fren.gz.tar'), #it is actuall a gz.tar + ], + valid_urls=[ + ('http://www.statmt.org/wmt14/dev.tgz', 'wmt14_dev.tgz'), + ], + test_urls=[ + ('http://www.statmt.org/wmt14/test-full.tgz', 'wmt14_test_full.tgz'), # cleaned test sets + ], + train_files_patterns=[ + ('*/europarl-v7.{src}-{tgt}.{lang}', ['fr-en', 'de-en']), + ('*commoncrawl.{src}-{tgt}.{lang}', ['fr-en', 'de-en']), + ('*/*news-commentary-v9.{src}-{tgt}.{lang}', ['fr-en', 'de-en']), + ('un/undoc.2000.{src}-{tgt}.{lang}', ['fr-en']), + ('*giga-{src}{tgt}*{lang}', ['fr-en']) + ], + valid_files_patterns=[ + ('dev/newstest2013.{lang}', ['fr-en', 'de-en']) + ], + test_files_patterns=[ + ('test-full/newstest*{src}{tgt}-{src:src}{tgt:ref}.{lang}', ['en-de', 'de-en', 'fr-en', 'en-fr']), + ], +) + +# pip install git+https://github.com/amake/tmx2corpus.git +wmt16_ro_en = DLDataset( + name='wmt16_ro-en', + train_urls=[ + ('http://data.statmt.org/wmt16/translation-task/training-parallel-ep-v8.tgz', 'wmt16_training-parallel-ep-v8.tgz'), + ('http://opus.nlpl.eu/download.php?f=SETIMES/v2/tmx/en-ro.tmx.gz', 'en-ro.tmx.gz'), + ], + valid_urls=[ + ('http://data.statmt.org/wmt16/translation-task/dev-romanian-updated.tgz', 'wmt16_dev.tgz') + ], + test_urls=[ + ('http://data.statmt.org/wmt16/translation-task/test.tgz', 'wmt16_test.tgz') + ], + train_files_patterns=[ + ('*/*europarl-v8.{src}-{tgt}.{lang}', ['ro-en']), + ('bitext.{lang}', ['ro-en']) #setimes from tmux + ] , + valid_files_patterns=[ + ('dev/newsdev2016*{src}{tgt}*.{lang}', ['ro-en', 'ro-en']) + ], + test_files_patterns=[ + ('test/newstest*{src}{tgt}*.{lang}', ['ro-en', 'en-ro']) + ], +) + +cwmt_wmt_instruction = 'cwmt download instruction at: http://nlp.nju.edu.cn/cwmt-wmt' +wmt17_fi_lv_tr_zh_en_manual_downloads = [ + # fake urls to have unique keys for the data + ( ('http://nlp.nju.edu.cn/cwmt-wmt/CASIA2015.zip', 'CASIA2015.zip'), cwmt_wmt_instruction), + ( ('http://nlp.nju.edu.cn/cwmt-wmt/CASICT2011.zip', 'CASICT2011.zip'), cwmt_wmt_instruction), + ( ('http://nlp.nju.edu.cn/cwmt-wmt/CASICT2015.zip', 'CASICT2015.zip'), cwmt_wmt_instruction), + ( ('http://nlp.nju.edu.cn/cwmt-wmt/Datum2015.zip', 'Datum2015.zip'), cwmt_wmt_instruction), + ( ('http://nlp.nju.edu.cn/cwmt-wmt/Datum2017.zip', 'Datum2017.zip'), cwmt_wmt_instruction), + ( ('http://nlp.nju.edu.cn/cwmt-wmt/NEU2017.zip', 'NEU2017.zip'), cwmt_wmt_instruction), +] +wmt17_fi_lv_tr_zh_en = DLDataset( + name='wmt17_fi_lv_tr_zh_en', + train_urls=[ + ('http://data.statmt.org/wmt17/translation-task/training-parallel-ep-v8.tgz', 'wmt17_training-parallel-ep-v8.tgz'), + 'http://data.statmt.org/wmt17/translation-task/training-parallel-nc-v12.tgz', + 'http://www.statmt.org/wmt15/wiki-titles.tgz', + ('http://opus.nlpl.eu/download.php?f=SETIMES/v2/tmx/en-tr.tmx.gz', 'en-tr.tmx.gz'), + ('http://data.statmt.org/wmt17/translation-task/rapid2016.tgz', 'wmt17_rapid2016.tgz'), + 'http://data.statmt.org/wmt17/translation-task/leta.v1.tgz', + 'http://data.statmt.org/wmt17/translation-task/dcep.lv-en.v1.tgz', + 'http://data.statmt.org/wmt17/translation-task/books.lv-en.v1.tgz', + (('https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-zh.tar.gz.00', + 'https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-zh.tar.gz.01',), 'UNv1.0.en-zh.tar.gz'), + #manually download files: + ('http://nlp.nju.edu.cn/cwmt-wmt/CASIA2015.zip', 'CASIA2015.zip'), + ('http://nlp.nju.edu.cn/cwmt-wmt/CASICT2011.zip', 'CASICT2011.zip'), + ('http://nlp.nju.edu.cn/cwmt-wmt/CASICT2015.zip', 'CASICT2015.zip'), + ('http://nlp.nju.edu.cn/cwmt-wmt/Datum2015.zip', 'Datum2015.zip'), + ('http://nlp.nju.edu.cn/cwmt-wmt/Datum2017.zip', 'Datum2017.zip'), + ('http://nlp.nju.edu.cn/cwmt-wmt/NEU2017.zip', 'NEU2017.zip'), + ], + valid_urls=[ + ('http://data.statmt.org/wmt17/translation-task/dev.tgz', 'wmt17_dev.tgz'), + ], + test_urls=[ + #NEW: Improved translations for zh test sets + ('http://data.statmt.org/wmt17/translation-task/test-update-1.tgz', 'wmt17_test_zh_en.tgz'), + ('http://data.statmt.org/wmt17/translation-task/test.tgz', 'wmt17_test_others.tgz') + ], + train_files_patterns=[ + ('casict*/cas*{src:ch}{tgt:en}.txt', ['zh-en', 'zh-en'] ), + ('casia*/cas*{src:ch}{tgt:en}.txt', ['zh-en', 'zh-en'] ), + ('dataum*/Book*{src:cn}{tgt:en}.txt', ['zh-en', 'zh-en']), + ('neu*/NEU*{src:cn}{tgt:en}.txt', ['zh-en', 'zh-en'] ), + ('*/*UNv1.0.en-zh.{src:zh}{tgt:en}', ['zh-en']), + ('training/*news-commentary-v12.{src}-{tgt}.{lang}', ['zh-en', ]), + + ('*/*europarl-v8.{src}-{tgt}.{lang}', ['fi-en', 'lv-en']), + ('wiki/fi-en/titles.{src}-{tgt}.{lang}', ['fi-en', ]), + ('rapid2016.{tgt}-{src}.{lang}', ['fi-en', 'lv-en']), + ('*/leta.{lang}', ['lv-en']), + ('*/dcep.{lang}', ['lv-en']), + ('*/farewell.{lang}', ['lv-en']), + ('bitext.{lang}', ['tr-en']), + ] , + valid_files_patterns=[ + ('dev/newsdev2017*{src}{tgt}-{src:src}{tgt:ref}.{lang}', + [ + 'fi-en', 'lv-en', 'tr-en', 'zh-en', + 'en-fi', 'en-lv', 'en-tr', 'en-zh' + ]), + ('dev/newstest2016*{src}{tgt}-{src:src}{tgt:ref}.{lang}', + [ + 'fi-en', 'tr-en', + 'en-fi', 'en-tr', + ]), + ], + test_files_patterns=[ + ('test/newstest2017-{src}{tgt}-{src:src}{tgt:ref}.{lang}', + [ + 'fi-en', 'lv-en', 'tr-en', + 'en-fi', 'en-lv', 'en-tr', + ]), + ('newstest2017-{src}{tgt}-{src:src}{tgt:ref}.{lang}', + [ + 'zh-en', + 'en-zh' + ]), + ], +) + +czeng_instruction = 'download instruction at: http://ufal.mff.cuni.cz/czeng/czeng16' +#alternative: use the prepared data but detokenize it? +wmt18_cs_et_en_manual_downloads = [ +#for cs, need to register and download; Register and download CzEng 1.6. +#Better results can be obtained by using a subset of sentences, released under a new version name CzEng 1.7. + # ((f'http://ufallab.ms.mff.cuni.cz/~bojar/czeng16-data/data-plaintext-format.{i}.tar', + # f'data-plaintext-format.{i}.tar'), czeng_instruction) + # for i in range(10) +] + +wmt18_cs_et_en = DLDataset( + name='wmt18_cs_et_en', + train_urls=[ + 'http://www.statmt.org/wmt13/training-parallel-europarl-v7.tgz', + 'http://data.statmt.org/wmt18/translation-task/training-parallel-ep-v8.tgz', + 'https://s3.amazonaws.com/web-language-models/paracrawl/release1/paracrawl-release1.en-cs.zipporah0-dedup-clean.tgz', + 'https://s3.amazonaws.com/web-language-models/paracrawl/release1/paracrawl-release1.en-et.zipporah0-dedup-clean.tgz', + 'http://www.statmt.org/wmt13/training-parallel-commoncrawl.tgz', + 'http://data.statmt.org/wmt18/translation-task/training-parallel-nc-v13.tgz', + ('http://data.statmt.org/wmt18/translation-task/rapid2016.tgz', 'wmt18_rapid2016.tgz'), + # (tuple( + # (f'http://ufallab.ms.mff.cuni.cz/~bojar/czeng16-data/data-plaintext-format.{i}.tar', + # f'data-plaintext-format.{i}.tar') + # for i in range(10) + # ), + # 'czeng16_data_plaintext.gz.tar'), + ], + valid_urls=[ + ('http://data.statmt.org/wmt18/translation-task/dev.tgz', 'wmt18_dev.tgz'), + ], + test_urls=[ + ('http://data.statmt.org/wmt18/translation-task/test.tgz', 'wmt18_test.tgz'), + ], + train_files_patterns=[ + # ('*/*europarl-v7.{src}-{tgt}.{lang}', ['cs-en']), + ('*/*europarl-v8.{src}-{tgt}.{lang}', ['et-en']), + # ('*paracrawl-release1.{tgt}-{src}.zipporah0-dedup-clean.{lang}', ['cs-en', 'et-en']), + ('*paracrawl-release1.{tgt}-{src}.zipporah0-dedup-clean.{lang}', ['et-en']), + # ('*commoncrawl.{src}-{tgt}.{lang}', ['cs-en']), + # ('*/news-commentary-v13.{src}-{tgt}.{lang}', ['cs-en']), + # ('data.plaintext-format/*train.{lang}', ['cs-en']), + ('rapid2016.{tgt}-{src}.{lang}', ['et-en']), + ] , + valid_files_patterns=[ + ('dev/newsdev2018*{src}{tgt}-{src:src}{tgt:ref}.{lang}', ['et-en']), + # ('dev/newstest2017*{src}{tgt}-{src:src}{tgt:ref}.{lang}', ['cs-en']) + ], + test_files_patterns=[ + ('test/newstest2018-{src}{tgt}-{src:src}{tgt:ref}.{lang}', + # ['cs-en', 'et-en']), + ['et-en']), + ] +) + +ru_en_yandex_instruction = 'Yandex Corpus download instruction at: https://translate.yandex.ru/corpus?lang=en' +wmt19_ru_gu_kk_lt_manual_downloads = [ + (('https://translate.yandex.ru/corpus?lang=en', 'wmt19_1mcorpus.zip'), ru_en_yandex_instruction) +] +wmt19_ru_gu_kk_lt = DLDataset( + name='wmt19_ru_gu_kk_lt', + train_urls=[ + 'http://www.statmt.org/europarl/v9/training/europarl-v9.lt-en.tsv.gz', + 'https://s3.amazonaws.com/web-language-models/paracrawl/release3/en-lt.bicleaner07.tmx.gz', + 'https://s3.amazonaws.com/web-language-models/paracrawl/release1/paracrawl-release1.en-ru.zipporah0-dedup-clean.tgz', + 'http://www.statmt.org/wmt13/training-parallel-commoncrawl.tgz', + 'http://data.statmt.org/news-commentary/v14/training/news-commentary-v14-wmt19.en-kk.tsv.gz', + 'http://data.statmt.org/news-commentary/v14/training/news-commentary-v14.en-ru.tsv.gz', + 'http://data.statmt.org/wikititles/v1/wikititles-v1.kk-en.tsv.gz', + 'http://data.statmt.org/wikititles/v1/wikititles-v1.ru-en.tsv.gz', + 'http://data.statmt.org/wikititles/v1/wikititles-v1.kk-en.tsv.gz', + 'http://data.statmt.org/wikititles/v1/wikititles-v1.lt-en.tsv.gz', + 'http://data.statmt.org/wikititles/v1/wikititles-v1.gu-en.tsv.gz', + (('https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-ru.tar.gz.00', + 'https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-ru.tar.gz.01', + 'https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-ru.tar.gz.02',), + 'wmt19_UNv1.0.en-ru.tar.gz'), + 'https://tilde-model.s3-eu-west-1.amazonaws.com/rapid2016.en-lt.tmx.zip', + ('https://translate.yandex.ru/corpus?lang=en', 'wmt19_1mcorpus.zip'), + ], + valid_urls=[ + ('http://data.statmt.org/wmt19/translation-task/dev.tgz', 'wmt19_dev.tgz'), + ], + test_urls=[ + ('http://data.statmt.org/wmt19/translation-task/test.tgz', 'wmt19_test.tgz'), + ], + train_files_patterns=[ + ('*europarl-v9.{src}-{tgt}.tsv.{lang}', ['lt-en']), + #paracrawl + ('*paracrawl-release1.{tgt}-{src}.zipporah0-dedup-clean.{lang}', ['ru-en']), + ('bitext.{lang}', ['lt-en',]), + ('*commoncrawl.{src}-{tgt}.{lang}', ['ru-en',]), + ('*news-commentary-v14-wmt19.{tgt}-{src}.tsv.{lang}', ['kk-en', ]), + ('*news-commentary-v14.{tgt}-{src}.tsv.{lang}', ['ru-en']), + #yandex + ('corpus.{tgt}_{src}.1m.{lang}', ['ru-en']), + ('wikititles_v1_wikititles-v1.{src}-{tgt}.tsv.{lang}', ['ru-en', 'kk-en', 'lt-en', 'gu-en']), + ('*/UNv1.0.{tgt}-{src}.{lang}', ['ru-en']), + #rapid + ('bitext.{lang}', ['lt-en']) + ], + valid_files_patterns=[ + ('dev/newsdev2019*{src}{tgt}-{src:src}{tgt:ref}.{lang}', ['gu-en', 'kk-en', 'lt-en']), + ('dev/newstest2018*{src}{tgt}-{src:src}{tgt:ref}.{lang}', ['ru-en']), + ], + test_files_patterns=[ + ('sgm/newstest2019-{src}{tgt}-{src:src}{tgt:ref}.{lang}', + ['ru-en', 'gu-en', 'kk-en', 'lt-en', 'en-ru', 'en-gu', 'en-kk', 'en-lt']), + ] +) + + +######### + +if __name__ == "__main__": + # speed up the downloads with multiple processing + dl_folder = f'{to_data_path}/downloads' + extract_folder = f'{to_data_path}/extracted' + + urls = [ + url + for dataset in [wmt13_es_en, wmt14_de_fr_en, wmt16_ro_en, wmt18_cs_et_en, wmt19_ru_gu_kk_lt] + for urls in [dataset.train_urls, dataset.valid_urls, dataset.test_urls] + for url in urls + ] + urls = set(urls) + download_multi(dl_folder, extract_folder, urls, num_processes=8, debug=True) + + # check manually downlaods + to_manually_download_urls = ( + wmt17_fi_lv_tr_zh_en_manual_downloads + wmt18_cs_et_en_manual_downloads + wmt19_ru_gu_kk_lt_manual_downloads + ) + to_be_manually_dowloaded = check_need_manual_downalod(dl_folder, to_manually_download_urls) + if len(to_be_manually_dowloaded) > 0: + print('Missing files that need to be downloaded manually; stop the process now.') + exit(-1) + + completed_urls = {} + completed_extraction = {} + def work_on_wmt(directions, wmt_data): + download_and_extract( + to_data_path, + directions, + wmt_data, + to_manually_download_urls=to_manually_download_urls, + completed_urls=completed_urls, completed_extraction=completed_extraction, debug=True) + + work_on_wmt( + ['es_XX-en_XX'], + wmt13_es_en,) + work_on_wmt( + [ + 'fr_XX-en_XX', 'en_XX-fr_XX', + # 'en_XX-de_DE', 'de_DE-en_XX', + ], + wmt14_de_fr_en,) + work_on_wmt( + ['ro_RO-en_XX', 'en_XX-ro_XX'], + wmt16_ro_en,) + work_on_wmt( + [ + # 'zh_CN-en_XX', + 'lv_LV-en_XX', 'fi_FI-en_XX', 'tr_TR-en_XX', + #in case the reversed directions have different train/valid/test data + # 'en_XX-zh_CN', + 'en_XX-lv_LV', 'en_XX-fi_FI', 'en_XX-tr_TR', + ], + wmt17_fi_lv_tr_zh_en, ) + # czeng17_script_path = download_czeng17_script(download_to, extract_to, debug=False) + # cz_username = None + work_on_wmt( + [ + # 'cs_CZ-en_XX', + 'et_EE-en_XX'], + wmt18_cs_et_en,) + work_on_wmt( + [ + # 'ru_RU-en_XX', 'en_XX-ru_RU', + 'gu_IN-en_XX', 'kk_KZ-en_XX', 'lt_LT-en_XX', + #in case the reversed directions have different train/valid/test data + 'en_XX-gu_IN', 'en_XX-kk_KZ', 'en_XX-lt_LT' + ], + wmt19_ru_gu_kk_lt,) + + not_matching = check_wmt_test_bleu( + f'{to_data_path}/raw', + [ + ('wmt13', ['es_XX-en_XX']), + ('wmt14/full', ['fr_XX-en_XX',]), + ('wmt16', ['ro_RO-en_XX',]), + # ('wmt17/improved', ['zh_CN-en_XX']), + ('wmt17', [ 'lv_LV-en_XX', 'fi_FI-en_XX', 'tr_TR-en_XX']), + ('wmt18', ['cs_CZ-en_XX', 'et_EE-en_XX']), + ('wmt19', ['gu_IN-en_XX', 'kk_KZ-en_XX', 'lt_LT-en_XX']), + #'ru_RU-en_XX', + ] + ) + if len(not_matching) > 0: + print('the following datasets do not have matching test datasets:\n\t', '\n\t'.join(not_matching)) + diff --git a/examples/multilingual/data_scripts/download_wmt20.sh b/examples/multilingual/data_scripts/download_wmt20.sh new file mode 100644 index 0000000000..31cd5c76b7 --- /dev/null +++ b/examples/multilingual/data_scripts/download_wmt20.sh @@ -0,0 +1,547 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + + + +set -x -e + +# TODO update the workdir and dest dir name +# put fasttext model +WORKDIR=$WORKDIR_ROOT +# put intermediate files +TMP_DIR=$WORKDIR_ROOT/tmp/tmp_wmt20_lowres_download +# output {train,valid,test} files to dest +DEST=$WORKDIR_ROOT/ML50/raw + +UTILS=$PWD/utils + +# per dataset locations +COMMONCRAWL_DIR=$TMP_DIR/commoncrawl +YANDEX_CORPUS=$WORKDIR_ROOT/wmt20/official/ru/yandex/1mcorpus.zip +# unzipped +CZENG_CORPUS=$WORKDIR_ROOT/wmt20/official/cs/czeng/czeng20-train +CCMT_DIR=$WORKDIR_ROOT/wmt20/official/zh/ccmt/parallel + +download_and_select() { + SUBFOLDER=$1 + URL=$2 + UNCOMPRESS_CMD=$3 + LANG=$4 + INPUT_FILEPATH=$5 + if [[ $# -gt 5 ]]; then + LANG_COL=$6 + EN_COL=$7 + fi + + mkdir -p $SUBFOLDER + cd $SUBFOLDER + wget -nc --content-disposition $URL + $UNCOMPRESS_CMD + + if [[ $# -gt 5 ]]; then + cut -f$LANG_COL $INPUT_FILEPATH > $INPUT_FILEPATH.$LANG + cut -f$EN_COL $INPUT_FILEPATH > $INPUT_FILEPATH.en + fi + cd .. + + ln -sf $SUBFOLDER/$INPUT_FILEPATH.$LANG $SUBFOLDER.$LANG + ln -sf $SUBFOLDER/$INPUT_FILEPATH.en $SUBFOLDER.en +} + +prepare_lid() { + pip install fasttext + + # TODO specify global workdir + MODEL=$WORKDIR/fasttext/lid.176.bin + LID_MULTI=$UTILS/fasttext_multi_filter.py + + if [ ! -f "$MODEL" ]; then + echo "downloading fasttext lid model..." + mkdir -p $WORKDIR/fasttext + wget -nc https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin -O $MODEL + fi +} + +prepare_moses() { + pushd $UTILS + echo 'Cloning Moses github repository (for tokenization scripts)...' + git clone https://github.com/moses-smt/mosesdecoder.git + popd +} + +lid_filter() { + # TODO specify global workdir + MODEL=$WORKDIR/fasttext/lid.176.bin + LID_MULTI=$UTILS/fasttext_multi_filter.py + + prepare_lid + + SRC=$1 + SRC_FILE=$2 + SRC_OUTPUT=$3 + TGT=$4 + TGT_FILE=$5 + TGT_OUTPUT=$6 + python $LID_MULTI --model $MODEL --inputs $SRC_FILE $TGT_FILE --langs $SRC $TGT --outputs $SRC_OUTPUT $TGT_OUTPUT +} + +prepare_ja_ted() { + mkdir -p ted + cd ted + + wget -nc https://wit3.fbk.eu/archive/2017-01-trnted//texts/en/ja/en-ja.tgz + tar -zxvf en-ja.tgz + cat en-ja/train.tags.en-ja.en | grep -v -P "^[ ]*\<" | sed 's/^[ \t]*//g' | sed 's/[ \t]*$//g' > en-ja/train.en-ja.en + cat en-ja/train.tags.en-ja.ja | grep -v -P "^[ ]*\<" | sed 's/^[ \t]*//g' | sed 's/[ \t]*$//g' > en-ja/train.en-ja.ja + + cd .. + ln -sf ted/en-ja/train.en-ja.ja ted.ja + ln -sf ted/en-ja/train.en-ja.en ted.en +} + +prepare_ja() { + OUTPUT_DIR=$TMP_DIR/ja + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select paracrawl "http://www.kecl.ntt.co.jp/icl/lirg/jparacrawl/release/2.0/bitext/en-ja.tar.gz" "tar -zxvf en-ja.tar.gz" ja en-ja/en-ja.bicleaner05.txt 4 3 & + download_and_select newscommentary "http://data.statmt.org/news-commentary/v15/training/news-commentary-v15.en-ja.tsv.gz" "gunzip -f news-commentary-v15.en-ja.tsv.gz" ja news-commentary-v15.en-ja.tsv 2 1 & + download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.ja-en.tsv.gz" "gunzip -f wikititles-v2.ja-en.tsv.gz" ja wikititles-v2.ja-en.tsv 1 2 & + download_and_select wikimatrix "http://data.statmt.org/wmt20/translation-task/WikiMatrix/WikiMatrix.v1.en-ja.langid.tsv.gz" "gunzip -f WikiMatrix.v1.en-ja.langid.tsv.gz" ja WikiMatrix.v1.en-ja.langid.tsv 3 2 & + download_and_select subtitle "https://nlp.stanford.edu/projects/jesc/data/split.tar.gz" "tar -zxvf split.tar.gz" ja split/train 2 1 & + download_and_select kftt "http://www.phontron.com/kftt/download/kftt-data-1.0.tar.gz" "tar -zxvf kftt-data-1.0.tar.gz" ja kftt-data-1.0/data/orig/kyoto-train & + + prepare_ja_ted & + + # ted data needs to + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.ja" | sort -V | xargs cat > all.ja + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter ja all.ja $DEST/train.ja_XX-en_XX.ja_XX en all.en $DEST/train.ja_XX-en_XX.en_XX +} + +prepare_ta() { + OUTPUT_DIR=$TMP_DIR/ta + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.ta-en.tsv.gz" "gunzip -f wikititles-v2.ta-en.tsv.gz" ta wikititles-v2.ta-en.tsv 1 2 & + download_and_select wikimatrix "http://data.statmt.org/wmt20/translation-task/WikiMatrix/WikiMatrix.v1.en-ta.langid.tsv.gz" "gunzip -f WikiMatrix.v1.en-ta.langid.tsv.gz" ta WikiMatrix.v1.en-ta.langid.tsv 3 2 & + download_and_select pmindia "http://data.statmt.org/pmindia/v1/parallel/pmindia.v1.ta-en.tsv" "" ta pmindia.v1.ta-en.tsv 2 1 & + download_and_select tanzil "https://object.pouta.csc.fi/OPUS-Tanzil/v1/moses/en-ta.txt.zip" "unzip en-ta.txt.zip" ta Tanzil.en-ta & + download_and_select pib "http://preon.iiit.ac.in/~jerin/resources/datasets/pib-v0.tar" "tar -xvf pib-v0.tar" ta pib/en-ta/train & + download_and_select mkb "http://preon.iiit.ac.in/~jerin/resources/datasets/mkb-v0.tar" "tar -xvf mkb-v0.tar" ta mkb/en-ta/mkb & + download_and_select ufal "http://ufal.mff.cuni.cz/~ramasamy/parallel/data/v2/en-ta-parallel-v2.tar.gz" "tar -zxvf en-ta-parallel-v2.tar.gz" ta en-ta-parallel-v2/corpus.bcn.train & + + wait + + # need special handling for nlpc + mkdir -p nlpc + cd nlpc + wget -nc https://raw.githubusercontent.com/nlpc-uom/English-Tamil-Parallel-Corpus/master/En-Ta%20Corpus/En-Ta%20English.txt + wget -nc https://github.com/nlpc-uom/English-Tamil-Parallel-Corpus/raw/master/En-Ta%20Corpus/En-Ta%20Tamil.txt + tail -n +4 "En-Ta English.txt" > en-ta.en + tail -n +4 "En-Ta Tamil.txt" > en-ta.ta + cd .. + ln -sf nlpc/en-ta.en nlpc.en + ln -sf nlpc/en-ta.ta nlpc.ta + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.ta" | sort -V | xargs cat > all.ta + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter ta all.ta $DEST/train.ta_IN-en_XX.ta_IN en all.en $DEST/train.ta_IN-en_XX.en_XX +} + +prepare_iu() { + OUTPUT_DIR=$TMP_DIR/iu + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select nh "https://nrc-digital-repository.canada.ca/eng/view/dataset/?id=c7e34fa7-7629-43c2-bd6d-19b32bf64f60" "tar -zxvf Nunavut-Hansard-Inuktitut-English-Parallel-Corpus-3.0.1.tgz" iu Nunavut-Hansard-Inuktitut-English-Parallel-Corpus-3.0/NunavutHansard > /dev/null & + download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.iu-en.tsv.gz" "gunzip -f wikititles-v2.iu-en.tsv.gz" iu wikititles-v2.iu-en.tsv 1 2 & + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.iu" | sort -V | xargs cat | nh/Nunavut-Hansard-Inuktitut-English-Parallel-Corpus-3.0/scripts/normalize-iu-spelling.pl > all.iu + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + paste all.iu all.en | awk -F $'\t' '$1!=""&&$2!=""' > all.iuen + cut -f1 all.iuen > $DEST/train.iu_CA-en_XX.iu_CA + cut -f2 all.iuen > $DEST/train.iu_CA-en_XX.en_XX +} + +prepare_km() { + OUTPUT_DIR=$TMP_DIR/km + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select paracrawl "http://data.statmt.org/wmt20/translation-task/ps-km/wmt20-sent.en-km.xz" "unxz wmt20-sent.en-km.zx" km wmt20-sent.en-km 2 1 & + + # km-parallel has multiple sets, concat all of them together + mkdir -p opus + cd opus + wget -nc "http://data.statmt.org/wmt20/translation-task/ps-km/km-parallel.tgz" + tar -zxvf km-parallel.tgz + find ./km-parallel -maxdepth 1 -name "*.km" | sort -V | xargs cat > opus.km + find ./km-parallel -maxdepth 1 -name "*.en" | sort -V | xargs cat > opus.en + cd .. + ln -sf opus/opus.km . + ln -sf opus/opus.en . + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.km" | sort -V | xargs cat > all.km + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter km all.km $DEST/train.km_KH-en_XX.km_KH en all.en $DEST/train.km_KH-en_XX.en_XX +} + +prepare_ps() { + OUTPUT_DIR=$TMP_DIR/ps + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select paracrawl "http://data.statmt.org/wmt20/translation-task/ps-km/wmt20-sent.en-ps.xz" "unxz wmt20-sent.en-ps.xz" ps wmt20-sent.en-ps 2 1 & + download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.ps-en.tsv.gz" "gunzip -f wikititles-v2.ps-en.tsv.gz" ps wikititles-v2.ps-en.tsv 1 2 & + # ps-parallel has multiple sets, concat all of them together + mkdir -p opus + cd opus + wget -nc "http://data.statmt.org/wmt20/translation-task/ps-km/ps-parallel.tgz" + tar -zxvf ps-parallel.tgz + find ./ps-parallel -maxdepth 1 -name "*.ps" | sort -V | xargs cat > opus.ps + find ./ps-parallel -maxdepth 1 -name "*.en" | sort -V | xargs cat > opus.en + cd .. + ln -sf opus/opus.ps opus.ps + ln -sf opus/opus.en opus.en + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.ps" | sort -V | xargs cat > all.ps + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter ps all.ps $DEST/train.ps_AF-en_XX.ps_AF en all.en $DEST/train.ps_AF-en_XX.en_XX +} + +download_commoncrawl() { + mkdir -p $COMMONCRAWL_DIR + cd $COMMONCRAWL_DIR + + wget -nc "http://www.statmt.org/wmt13/training-parallel-commoncrawl.tgz" + tar -zxvf training-parallel-commoncrawl.tgz +} +link_commoncrawl() { + LANG=$1 + ln -sf $COMMONCRAWL_DIR/commoncrawl.$LANG-en.en commoncrawl.en + ln -sf $COMMONCRAWL_DIR/commoncrawl.$LANG-en.$LANG commoncrawl.$LANG +} + +strip_xlf() { + INPUT_FILE=$1 + SRC=$2 + TGT=$3 + grep '<source xml:lang=' $INPUT_FILE | sed 's/^<[^<>]*>//g' | sed 's/<[^<>]*>$//g' > $INPUT_FILE.$SRC + grep '<target xml:lang=' $INPUT_FILE | sed 's/^<[^<>]*>//g' | sed 's/<[^<>]*>$//g' > $INPUT_FILE.$TGT +} + +download_and_process_tilde() { + URL=$1 + UNCOMPRESS_CMD=$2 + FILENAME=$3 + LANG=$4 + PROCESS_CMD=$5 + + mkdir -p tilde + cd tilde + wget -nc $URL + $UNCOMPRESS_CMD + echo "executing cmd" + echo $PROCESS_CMD + $PROCESS_CMD + cd .. + ln -sf tilde/$FILENAME.$LANG tilde.$LANG + ln -sf tilde/$FILENAME.en tilde.en +} + +prepare_cs() { + OUTPUT_DIR=$TMP_DIR/cs + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + #download_and_select europarl "http://www.statmt.org/europarl/v10/training/europarl-v10.cs-en.tsv.gz" "gunzip europarl-v10.cs-en.tsv.gz" cs europarl-v10.cs-en.tsv 1 2 & + #download_and_select paracrawl "https://s3.amazonaws.com/web-language-models/paracrawl/release5.1/en-cs.txt.gz" "gunzip en-cs.txt.gz" cs en-cs.txt 2 1 & + #link_commoncrawl cs + #download_and_select newscommentary "http://data.statmt.org/news-commentary/v15/training/news-commentary-v15.cs-en.tsv.gz" "gunzip news-commentary-v15.cs-en.tsv.gz" cs news-commentary-v15.cs-en.tsv 1 2 & + #download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.cs-en.tsv.gz" "gunzip wikititles-v2.cs-en.tsv.gz" cs wikititles-v2.cs-en.tsv 1 2 & + #download_and_process_tilde "http://data.statmt.org/wmt20/translation-task/rapid/RAPID_2019.cs-en.xlf.gz" "gunzip RAPID_2019.cs-en.xlf.gz" RAPID_2019.cs-en.xlf cs "strip_xlf RAPID_2019.cs-en.xlf cs en" & + #download_and_select wikimatrix "http://data.statmt.org/wmt20/translation-task/WikiMatrix/WikiMatrix.v1.cs-en.langid.tsv.gz" "gunzip WikiMatrix.v1.cs-en.langid.tsv.gz" cs WikiMatrix.v1.cs-en.langid.tsv 2 3 & + + #wait + + # remove previous results + #rm -f all.?? + #find ./ -maxdepth 1 -name "*.cs" | sort -V | xargs cat > all.cs + #find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + if [ -z $CZENG_CORPUS ] ; + then + echo "Please download CZENG_CORPUS manually and place them at $CZENG_CORPUS. Exitting..." + exit + fi + cat $CZENG_CORPUS | sed '/^$/d' | cut -f5 > all.cs + cat $CZENG_CORPUS | sed '/^$/d' | cut -f6 > all.en + + lid_filter cs all.cs $DEST/train.cs_CZ-en_XX.cs_CZ en all.en $DEST/train.cs_CZ-en_XX.en_XX +} + +prepare_de() { + OUTPUT_DIR=$TMP_DIR/de + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select europarl "http://www.statmt.org/europarl/v10/training/europarl-v10.de-en.tsv.gz" "gunzip europarl-v10.de-en.tsv.gz" de europarl-v10.de-en.tsv 1 2 & + download_and_select paracrawl "https://s3.amazonaws.com/web-language-models/paracrawl/release5.1/en-de.txt.gz" "gunzip en-de.txt.gz" de en-de.txt 2 1 & + link_commoncrawl de + download_and_select newscommentary "http://data.statmt.org/news-commentary/v15/training/news-commentary-v15.de-en.tsv.gz" "gunzip news-commentary-v15.de-en.tsv.gz" de news-commentary-v15.de-en.tsv 1 2 & + download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.de-en.tsv.gz" "gunzip wikititles-v2.de-en.tsv.gz" de wikititles-v2.de-en.tsv 1 2 & + download_and_process_tilde "http://data.statmt.org/wmt20/translation-task/rapid/RAPID_2019.de-en.xlf.gz" "gunzip RAPID_2019.de-en.xlf.gz" RAPID_2019.de-en.xlf de "strip_xlf RAPID_2019.de-en.xlf de en" & + download_and_select wikimatrix "http://data.statmt.org/wmt20/translation-task/WikiMatrix/WikiMatrix.v1.de-en.langid.tsv.gz" "gunzip WikiMatrix.v1.de-en.langid.tsv.gz" de WikiMatrix.v1.de-en.langid.tsv 2 3 & + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.de" | sort -V | xargs cat > all.de + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter de all.de $DEST/train.de_DE-en_XX.de_DE en all.en $DEST/train.de_DE-en_XX.en_XX +} + +prepare_tmx() { + TMX_FILE=$1 + git clone https://github.com/amake/TMX2Corpus $UTILS/tmx2corpus + pip install tinysegmenter + + python $UTILS/tmx2corpus/tmx2corpus.py $TMX_FILE +} + +prepare_pl() { + OUTPUT_DIR=$TMP_DIR/pl + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + # download_and_select europarl "http://www.statmt.org/europarl/v10/training/europarl-v10.pl-en.tsv.gz" "gunzip europarl-v10.pl-en.tsv.gz" pl europarl-v10.pl-en.tsv 1 2 & + # download_and_select paracrawl "https://s3.amazonaws.com/web-language-models/paracrawl/release5.1/en-pl.txt.gz" "gunzip en-pl.txt.gz" pl en-pl.txt 2 1 & + # download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.pl-en.tsv.gz" "gunzip wikititles-v2.pl-en.tsv.gz" pl wikititles-v2.pl-en.tsv 1 2 & + download_and_select tilde "https://tilde-model.s3-eu-west-1.amazonaws.com/rapid2019.en-pl.tmx.zip" "gunzip rapid2019.en-pl.tmx.zip" bitext pl "prepare_tmx RAPID_2019.UNIQUE.en-pl.tmx" & + # download_and_select wikimatrix "http://data.statmt.org/wmt20/translation-task/WikiMatrix/WikiMatrix.v1.en-pl.langid.tsv.gz" "gunzip WikiMatrix.v1.en-pl.langid.tsv.gz" pl WikiMatrix.v1.en-pl.langid.tsv 3 2 & + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.pl" | sort -V | xargs cat > all.pl + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter pl all.pl $DEST/train.pl_PL-en_XX.pl_PL en all.en $DEST/train.pl_PL-en_XX.en_XX +} + +prepare_uncorpus() { + $URLS=$1 + $FILES=$2 + + mkdir -p uncorpus + cd uncorpus + + for URL in $URLS; do + wget -nc $URL + done + cat $FILES > uncorpus.tar.gz + tar -zxvf uncorpus.tar.gz + + cd .. + ln -sf uncorpus/en-$LANG/UNv1.0.en-$LANG.$LANG uncorpus.$LANG + ln -sf uncorpus/en-$LANG/UNv1.0.en-$LANG.en uncorpus.en +} + +prepare_yandex() { + mkdir -p yandex + cd yandex + unzip $YANDEX_CORPUS ./ + cd .. + ln -s yandex/corpus.en_ru.1m.en yandex.en + ln -s yandex/corpus.en_ru.1m.ru yandex.ru +} + +prepare_ru() { + OUTPUT_DIR=$TMP_DIR/ru + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select paracrawl "https://s3.amazonaws.com/web-language-models/paracrawl/release1/paracrawl-release1.en-ru.zipporah0-dedup-clean.tgz" "tar -zxvf paracrawl-release1.en-ru.zipporah0-dedup-clean.tgz" ru paracrawl-release1.en-ru.zipporah0-dedup-clean & + link_commoncrawl ru + download_and_select newscommentary "http://data.statmt.org/news-commentary/v15/training/news-commentary-v15.en-ru.tsv.gz" "gunzip news-commentary-v15.en-ru.tsv.gz" ru news-commentary-v15.en-ru.tsv 2 1 & + prepare_yandex & + download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.ru-en.tsv.gz" "gunzip wikititles-v2.ru-en.tsv.gz" ru wikititles-v2.ru-en.tsv 1 2 & + prepare_uncorpus "https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-ru.tar.gz.00 https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-ru.tar.gz.01 https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-ru.tar.gz.02" "UNv1.0.en-ru.tar.gz.00 UNv1.0.en-ru.tar.gz.01 UNv1.0.en-ru.tar.gz.02" & + download_and_select wikimatrix "http://data.statmt.org/wmt20/translation-task/WikiMatrix/WikiMatrix.v1.en-ru.langid.tsv.gz" "gunzip WikiMatrix.v1.en-ru.langid.tsv.gz" ru WikiMatrix.v1.en-ru.langid.tsv 3 2 & + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.ru" | sort -V | xargs cat > all.ru + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter ru all.ru $DEST/train.ru_RU-en_XX.ru_RU en all.en $DEST/train.ru_RU-en_XX.en_XX +} + +prepare_ccmt() { + mkdir -p ccmt + cd ccmt + # assume ccmt data is already unzipped under CCMT_DIR folder + cat $CCMT_DIR/datum2017/Book*_cn.txt | sed 's/ //g' > datum2017.detok.zh + cat $CCMT_DIR/datum2017/Book*_en.txt > datum2017.detok.en + cat $CCMT_DIR/casict2011/casict-A_ch.txt $CCMT_DIR/casict2011/casict-B_ch.txt $CCMT_DIR/casict2015/casict2015_ch.txt $CCMT_DIR/datum2015/datum_ch.txt $CCMT_DIR/neu2017/NEU_cn.txt datum2017.detok.zh > ccmt.zh + cat $CCMT_DIR/casict2011/casict-A_en.txt $CCMT_DIR/casict2011/casict-B_en.txt $CCMT_DIR/casict2015/casict2015_en.txt $CCMT_DIR/datum2015/datum_en.txt $CCMT_DIR/neu2017/NEU_en.txt datum2017.detok.en > ccmt.en + cd .. + ln -sf ccmt/ccmt.zh ccmt.zh + ln -sf ccmt/ccmt.en ccmt.en +} + +prepare_zh() { + OUTPUT_DIR=$TMP_DIR/zh + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + + download_and_select newscommentary "http://data.statmt.org/news-commentary/v15/training/news-commentary-v15.en-zh.tsv.gz" "gunzip news-commentary-v15.en-zh.tsv.gz" zh news-commentary-v15.en-zh.tsv 2 1 & + download_and_select wikititles "http://data.statmt.org/wikititles/v2/wikititles-v2.zh-en.tsv.gz" "gunzip wikititles-v2.zh-en.tsv.gz" zh wikititles-v2.zh-en.tsv 1 2 & + prepare_uncorpus "https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-zh.tar.gz.00 https://stuncorpusprod.blob.core.windows.net/corpusfiles/UNv1.0.en-zh.tar.gz.01" "UNv1.0.en-zh.tar.gz.00 UNv1.0.en-zh.tar.gz.01" & + prepare_ccmt & + download_and_select wikimatrix "http://data.statmt.org/wmt20/translation-task/WikiMatrix/WikiMatrix.v1.en-zh.langid.tsv.gz" "gunzip WikiMatrix.v1.en-zh.langid.tsv.gz" zh WikiMatrix.v1.en-zh.langid.tsv 3 2 & + + wait + + # remove previous results + rm -f all.?? + find ./ -maxdepth 1 -name "*.zh" | sort -V | xargs cat > all.zh + find ./ -maxdepth 1 -name "*.en" | sort -V | xargs cat > all.en + lid_filter zh all.zh $DEST/train.zh_CN-en_XX.zh_CN en all.en $DEST/train.zh_CN-en_XX.en_XX +} + +prepare_tests() { + OUTPUT_DIR=$TMP_DIR + mkdir -p $OUTPUT_DIR + cd $OUTPUT_DIR + wget -nc http://data.statmt.org/wmt20/translation-task/dev.tgz + tar -zxvf dev.tgz + cd dev + + cat newsdev2020-jaen-src.ja.sgm | $UTILS/strip_sgm.sh > newsdev2020-jaen.ja + cat newsdev2020-jaen-ref.en.sgm | $UTILS/strip_sgm.sh > newsdev2020-jaen.en + split newsdev2020-jaen.ja -a 0 -n r/1/2 > $DEST/valid.ja_XX-en_XX.ja_XX + split newsdev2020-jaen.en -a 0 -n r/1/2 > $DEST/valid.ja_XX-en_XX.en_XX + split newsdev2020-jaen.ja -a 0 -n r/2/2 > $DEST/test.ja_XX-en_XX.ja_XX + split newsdev2020-jaen.en -a 0 -n r/2/2 > $DEST/test.ja_XX-en_XX.en_XX + + cat newsdev2020-iuen-src.iu.sgm | strip_sgm.sh > newsdev2020-iuen.iu + cat newsdev2020-iuen-ref.en.sgm | strip_sgm.sh > newsdev2020-iuen.en + split newsdev2020-iuen.iu -a 0 -n r/1/2 > $DEST/valid.iu_CA-en_XX.iu_CA + split newsdev2020-iuen.en -a 0 -n r/1/2 > $DEST/valid.iu_CA-en_XX.en_XX + split newsdev2020-iuen.iu -a 0 -n r/2/2 > $DEST/test.iu_CA-en_XX.iu_CA + split newsdev2020-iuen.en -a 0 -n r/2/2 > $DEST/test.iu_CA-en_XX.en_XX + + cat newsdev2020-taen-src.ta.sgm | strip_sgm.sh > newsdev2020-taen.ta + cat newsdev2020-taen-ref.en.sgm | strip_sgm.sh > newsdev2020-taen.en + split newsdev2020-taen.ta -a 0 -n r/1/2 > $DEST/valid.ta_IN-en_XX.ta_IN + split newsdev2020-taen.en -a 0 -n r/1/2 > $DEST/valid.ta_IN-en_XX.en_XX + split newsdev2020-taen.ta -a 0 -n r/2/2 > $DEST/test.ta_IN-en_XX.ta_IN + split newsdev2020-taen.en -a 0 -n r/2/2 > $DEST/test.ta_IN-en_XX.en_XX + + cp wikipedia.dev.km-en.km $DEST/valid.km_KH-en_XX.km_KH + cp wikipedia.dev.km-en.en $DEST/valid.km_KH-en_XX.en_XX + cp wikipedia.devtest.km-en.km $DEST/test.km_KH-en_XX.km_KH + cp wikipedia.devtest.km-en.en $DEST/test.km_KH-en_XX.en_XX + + cp wikipedia.dev.ps-en.ps $DEST/valid.ps_AF-en_XX.ps_AF + cp wikipedia.dev.ps-en.en $DEST/valid.ps_AF-en_XX.en_XX + cp wikipedia.devtest.ps-en.ps $DEST/test.ps_AF-en_XX.ps_AF + cp wikipedia.devtest.ps-en.en $DEST/test.ps_AF-en_XX.en_XX + + cat newsdev2020-plen-src.pl.sgm | strip_sgm.sh > newsdev2020-plen.pl + cat newsdev2020-plen-ref.en.sgm | strip_sgm.sh > newsdev2020-plen.en + split newsdev2020-plen.pl -a 0 -n r/1/2 > $DEST/valid.pl_PL-en_XX.pl_PL + split newsdev2020-plen.en -a 0 -n r/1/2 > $DEST/valid.pl_PL-en_XX.en_XX + split newsdev2020-plen.pl -a 0 -n r/2/2 > $DEST/test.pl_PL-en_XX.pl_PL + split newsdev2020-plen.en -a 0 -n r/2/2 > $DEST/test.pl_PL-en_XX.en_XX + + cat newstest2018-encs-src.en.sgm | strip_sgm.sh > $DEST/valid.en_XX-cs_CZ.en_XX + cat newstest2018-encs-ref.cs.sgm | strip_sgm.sh > $DEST/valid.en_XX-cs_CZ.cs_CZ + cat newstest2019-encs-src.en.sgm | strip_sgm.sh > $DEST/test.en_XX-cs_CZ.en_XX + cat newstest2019-encs-ref.cs.sgm | strip_sgm.sh > $DEST/test.en_XX-cs_CZ.cs_CZ + + cat newstest2018-deen-src.de.sgm | strip_sgm.sh > $DEST/valid.de_DE-en_XX.de_DE + cat newstest2018-deen-ref.en.sgm | strip_sgm.sh > $DEST/valid.de_DE-en_XX.en_XX + cat newstest2018-ende-src.en.sgm | strip_sgm.sh > $DEST/valid.en_XX-de_DE.en_XX + cat newstest2018-ende-ref.de.sgm | strip_sgm.sh > $DEST/valid.en_XX-de_DE.de_DE + cat newstest2019-deen-src.de.sgm | strip_sgm.sh > $DEST/test.de_DE-en_XX.de_DE + cat newstest2019-deen-ref.en.sgm | strip_sgm.sh > $DEST/test.de_DE-en_XX.en_XX + cat newstest2019-ende-src.en.sgm | strip_sgm.sh > $DEST/test.en_XX-de_DE.en_XX + cat newstest2019-ende-ref.de.sgm | strip_sgm.sh > $DEST/test.en_XX-de_DE.de_DE + + cat newstest2018-ruen-src.ru.sgm | strip_sgm.sh > $DEST/valid.ru_RU-en_XX.ru_RU + cat newstest2018-ruen-ref.en.sgm | strip_sgm.sh > $DEST/valid.ru_RU-en_XX.en_XX + cat newstest2018-enru-src.en.sgm | strip_sgm.sh > $DEST/valid.en_XX-ru_RU.en_XX + cat newstest2018-enru-ref.ru.sgm | strip_sgm.sh > $DEST/valid.en_XX-ru_RU.ru_RU + cat newstest2019-ruen-src.ru.sgm | strip_sgm.sh > $DEST/test.ru_RU-en_XX.ru_RU + cat newstest2019-ruen-ref.en.sgm | strip_sgm.sh > $DEST/test.ru_RU-en_XX.en_XX + cat newstest2019-enru-src.en.sgm | strip_sgm.sh > $DEST/test.en_XX-ru_RU.en_XX + cat newstest2019-enru-ref.ru.sgm | strip_sgm.sh > $DEST/test.en_XX-ru_RU.ru_RU + + cat newstest2018-zhen-src.zh.sgm | strip_sgm.sh > $DEST/valid.zh_CN-en_XX.zh_CN + cat newstest2018-zhen-ref.en.sgm | strip_sgm.sh > $DEST/valid.zh_CN-en_XX.en_XX + cat newstest2018-enzh-src.en.sgm | strip_sgm.sh > $DEST/valid.en_XX-zh_CN.en_XX + cat newstest2018-enzh-ref.zh.sgm | strip_sgm.sh > $DEST/valid.en_XX-zh_CN.zh_CN + cat newstest2019-zhen-src.zh.sgm | strip_sgm.sh > $DEST/test.zh_CN-en_XX.zh_CN + cat newstest2019-zhen-ref.en.sgm | strip_sgm.sh > $DEST/test.zh_CN-en_XX.en_XX + cat newstest2019-enzh-src.en.sgm | strip_sgm.sh > $DEST/test.en_XX-zh_CN.en_XX + cat newstest2019-enzh-ref.zh.sgm | strip_sgm.sh > $DEST/test.en_XX-zh_CN.zh_CN +} + +mkdir -p $DEST + +prepare_lid +prepare_moses +download_commoncrawl + +prepare_ja & +prepare_ta & +prepare_km & +prepare_ps & +prepare_iu & +prepare_cs & +prepare_de & +prepare_pl & +prepare_ru & +prepare_zh & + +# prepare valid/test set +prepare_tests & + +# wait + +# TODO remove intermediate files +# rm -rf $TMP_DIR diff --git a/examples/multilingual/data_scripts/preprocess_ML50_v1.sh b/examples/multilingual/data_scripts/preprocess_ML50_v1.sh new file mode 100644 index 0000000000..4655936149 --- /dev/null +++ b/examples/multilingual/data_scripts/preprocess_ML50_v1.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. + +if [ -z $WORKDIR_ROOT ] ; +then + echo "please specify your working directory root in environment variable WORKDIR_ROOT. Exitting..." + exit +fi + +if [ -z $SPM_PATH ] ; +then + echo "Please install sentence piecence from https://github.com/google/sentencepiece and set SPM_PATH pointing to the installed spm_encode.py. Exitting..." + exit +fi + +ML50=${WORKDIR_ROOT}/ML50 + +mkdir -p $ML50/dedup +mkdir -p $ML50/cleaned_dedup + +python ./dedup_all.py --from-folder $ML50/raw --to-folder $ML50/dedup +python ./remove_valid_test_in_train.py --from-folder $ML50/dedup --to-folder $ML50/clean +python ./binarize.py --raw-folder $ML50/clean \ No newline at end of file diff --git a/examples/multilingual/data_scripts/remove_valid_test_in_train.py b/examples/multilingual/data_scripts/remove_valid_test_in_train.py new file mode 100755 index 0000000000..ef618adef7 --- /dev/null +++ b/examples/multilingual/data_scripts/remove_valid_test_in_train.py @@ -0,0 +1,290 @@ +import os, sys +import glob, itertools +import pandas as pd + +WORKDIR_ROOT = os.environ.get('WORKDIR_ROOT', None) + +if WORKDIR_ROOT is None or not WORKDIR_ROOT.strip(): + print('please specify your working directory root in OS environment variable WORKDIR_ROOT. Exitting..."') + sys.exit(-1) + + +def load_langs(path): + with open(path) as fr: + langs = [l.strip() for l in fr] + return langs + + + +def load_sentences(raw_data, split, direction): + src, tgt = direction.split('-') + src_path = f"{raw_data}/{split}.{direction}.{src}" + tgt_path = f"{raw_data}/{split}.{direction}.{tgt}" + if os.path.exists(src_path) and os.path.exists(tgt_path): + return [(src, open(src_path).read().splitlines()), (tgt, open(tgt_path).read().splitlines())] + else: + return [] + +def swap_direction(d): + src, tgt = d.split('-') + return f'{tgt}-{src}' + +def get_all_test_data(raw_data, directions, split='test'): + test_data = [ + x + for dd in directions + for d in [dd, swap_direction(dd)] + for x in load_sentences(raw_data, split, d) + ] + # all_test_data = {s for _, d in test_data for s in d} + all_test_data = {} + for lang, d in test_data: + for s in d: + s = s.strip() + lgs = all_test_data.get(s, set()) + lgs.add(lang) + all_test_data[s] = lgs + return all_test_data, test_data + +def check_train_sentences(raw_data, direction, all_test_data, mess_up_train={}): + src, tgt = direction.split('-') + tgt_path = f"{raw_data}/train.{direction}.{tgt}" + src_path = f"{raw_data}/train.{direction}.{src}" + print(f'check training data in {raw_data}/train.{direction}') + size = 0 + if not os.path.exists(tgt_path) or not os.path.exists(src_path): + return mess_up_train, size + with open(src_path) as f, open(tgt_path) as g: + for src_line, tgt_line in zip(f, g): + s = src_line.strip() + t = tgt_line.strip() + size += 1 + if s in all_test_data: + langs = mess_up_train.get(s, set()) + langs.add(direction) + mess_up_train[s] = langs + if t in all_test_data: + langs = mess_up_train.get(t, set()) + langs.add(direction) + mess_up_train[t] = langs + return mess_up_train, size + +def check_train_all(raw_data, directions, all_test_data): + mess_up_train = {} + data_sizes = {} + for direction in directions: + _, size = check_train_sentences(raw_data, direction, all_test_data, mess_up_train) + data_sizes[direction] = size + return mess_up_train, data_sizes + +def count_train_in_other_set(mess_up_train): + train_in_others = [(direction, s) for s, directions in mess_up_train.items() for direction in directions] + counts = {} + for direction, s in train_in_others: + counts[direction] = counts.get(direction, 0) + 1 + return counts + +def train_size_if_remove_in_otherset(data_sizes, mess_up_train): + counts_in_other = count_train_in_other_set(mess_up_train) + remain_sizes = [] + for direction, count in counts_in_other.items(): + remain_sizes.append((direction, data_sizes[direction] - count, data_sizes[direction], count, 100 * count / data_sizes[direction] )) + return remain_sizes + + +def remove_messed_up_sentences(raw_data, direction, mess_up_train, mess_up_train_pairs, corrected_langs): + split = 'train' + src_lang, tgt_lang = direction.split('-') + + tgt = f"{raw_data}/{split}.{direction}.{tgt_lang}" + src = f"{raw_data}/{split}.{direction}.{src_lang}" + print(f'working on {direction}: ', src, tgt) + if not os.path.exists(tgt) or not os.path.exists(src) : + return + + corrected_tgt = f"{to_folder}/{split}.{direction}.{tgt_lang}" + corrected_src = f"{to_folder}/{split}.{direction}.{src_lang}" + line_num = 0 + keep_num = 0 + with open(src, encoding='utf8',) as fsrc, \ + open(tgt, encoding='utf8',) as ftgt, \ + open(corrected_src, 'w', encoding='utf8') as fsrc_corrected, \ + open(corrected_tgt, 'w', encoding='utf8') as ftgt_corrected: + for s, t in zip(fsrc, ftgt): + s = s.strip() + t = t.strip() + if t not in mess_up_train \ + and s not in mess_up_train \ + and (s, t) not in mess_up_train_pairs \ + and (t, s) not in mess_up_train_pairs: + corrected_langs.add(direction) + print(s, file=fsrc_corrected) + print(t, file=ftgt_corrected) + keep_num += 1 + line_num += 1 + if line_num % 1000 == 0: + print(f'completed {line_num} lines', end='\r') + return line_num, keep_num + +########## + + +def merge_valid_test_messup(mess_up_train_valid, mess_up_train_test): + merged_mess = [] + for s in set(list(mess_up_train_valid.keys()) + list(mess_up_train_test.keys())): + if not s: + continue + valid = mess_up_train_valid.get(s, set()) + test = mess_up_train_test.get(s, set()) + merged_mess.append((s, valid | test)) + return dict(merged_mess) + + + +######### +def check_train_pairs(raw_data, direction, all_test_data, mess_up_train={}): + src, tgt = direction.split('-') + #a hack; TODO: check the reversed directions + path1 = f"{raw_data}/train.{src}-{tgt}.{src}" + path2 = f"{raw_data}/train.{src}-{tgt}.{tgt}" + if not os.path.exists(path1) or not os.path.exists(path2) : + return + + with open(path1) as f1, open(path2) as f2: + for src_line, tgt_line in zip(f1, f2): + s = src_line.strip() + t = tgt_line.strip() + if (s, t) in all_test_data or (t, s) in all_test_data: + langs = mess_up_train.get( (s, t), set()) + langs.add(src) + langs.add(tgt) + mess_up_train[(s, t)] = langs + + +def load_pairs(raw_data, split, direction): + src, tgt = direction.split('-') + src_f = f"{raw_data}/{split}.{direction}.{src}" + tgt_f = f"{raw_data}/{split}.{direction}.{tgt}" + if tgt != 'en_XX': + src_f, tgt_f = tgt_f, src_f + if os.path.exists(src_f) and os.path.exists(tgt_f): + return list(zip(open(src_f).read().splitlines(), + open(tgt_f).read().splitlines(), + )) + else: + return [] + +# skip_langs = ['cs_CZ', 'en_XX', 'tl_XX', 'tr_TR'] +def get_messed_up_test_pairs(split, directions): + test_pairs = [ + (d, load_pairs(raw_data, split, d)) + for d in directions + ] + # all_test_data = {s for _, d in test_data for s in d} + all_test_pairs = {} + for direction, d in test_pairs: + src, tgt = direction.split('-') + for s in d: + langs = all_test_pairs.get(s, set()) + langs.add(src) + langs.add(tgt) + all_test_pairs[s] = langs + mess_up_train_pairs = {} + for direction in directions: + check_train_pairs(raw_data, direction, all_test_pairs, mess_up_train_pairs) + return all_test_pairs, mess_up_train_pairs + + + +if __name__ == "__main__": + ####### + import argparse + parser = argparse.ArgumentParser() + parser.add_argument( + '--from-folder', + required=True, + type=str) + parser.add_argument( + '--to-folder', + required=True, + type=str) + parser.add_argument( + '--directions', + default=None, + type=str) + + + args = parser.parse_args() + raw_data = args.from_folder + to_folder = args.to_folder + os.makedirs(to_folder, exist_ok=True) + + if args.directions: + directions = args.directions.split(',') + else: + raw_files = itertools.chain( + glob.glob(f'{raw_data}/train*'), + glob.glob(f'{raw_data}/valid*'), + glob.glob(f'{raw_data}/test*'), + ) + directions = [os.path.split(file_path)[-1].split('.')[1] for file_path in raw_files] + print('working on directions: ', directions) + + ########## + + + + all_test_data, test_data = get_all_test_data(raw_data, directions, 'test') + print('==loaded test data==') + all_valid_data, valid_data = get_all_test_data(raw_data, directions, 'valid') + print('==loaded valid data==') + all_valid_test_data = merge_valid_test_messup(all_test_data, all_valid_data) + mess_up_train, data_sizes = check_train_all(raw_data, directions, all_valid_test_data) + print('training messing up with valid, test data:', len(mess_up_train)) + data_situation = train_size_if_remove_in_otherset(data_sizes, mess_up_train) + df = pd.DataFrame(data_situation, columns=['direction', 'train_size_after_remove', 'orig_size', 'num_to_remove', 'remove_percent']) + df.sort_values('remove_percent', ascending=False) + df.to_csv(f'{raw_data}/clean_summary.tsv', sep='\t') + print(f'projected data clean summary in: {raw_data}/clean_summary.tsv') + + # correct the dataset: + all_test_pairs, mess_up_test_train_pairs = get_messed_up_test_pairs('test', directions) + all_valid_pairs, mess_up_valid_train_pairs = get_messed_up_test_pairs('valid', directions) + + all_messed_pairs = set(mess_up_test_train_pairs.keys()).union(set(mess_up_valid_train_pairs.keys())) + corrected_directions = set() + + real_data_situation = [] + for direction in directions: + org_size, new_size = remove_messed_up_sentences(raw_data, direction, mess_up_train, all_messed_pairs, corrected_directions) + if org_size == 0: + print(f"{direction} has size 0") + continue + real_data_situation.append( + (direction, new_size, org_size, org_size - new_size, (org_size - new_size) / org_size * 100) + ) + print('corrected directions: ', corrected_directions) + df = pd.DataFrame(real_data_situation, columns=['direction', 'train_size_after_remove', 'orig_size', 'num_to_remove', 'remove_percent']) + df.sort_values('remove_percent', ascending=False) + df.to_csv(f'{raw_data}/actual_clean_summary.tsv', sep='\t') + print(f'actual data clean summary (which can be different from the projected one because of duplications) in: {raw_data}/actual_clean_summary.tsv') + + import shutil + for direction in directions: + src_lang, tgt_lang = direction.split('-') + for split in ['train', 'valid', 'test']: + # copying valid, test and uncorrected train + if direction in corrected_directions and split == 'train': + continue + tgt = f"{raw_data}/{split}.{direction}.{tgt_lang}" + src = f"{raw_data}/{split}.{direction}.{src_lang}" + if not (os.path.exists(src) and os.path.exists(tgt)): + continue + corrected_tgt = f"{to_folder}/{split}.{direction}.{tgt_lang}" + corrected_src = f"{to_folder}/{split}.{direction}.{src_lang}" + print(f'copying {src} to {corrected_src}') + shutil.copyfile(src, corrected_src) + print(f'copying {tgt} to {corrected_tgt}') + shutil.copyfile(tgt, corrected_tgt) + + print('completed') \ No newline at end of file diff --git a/examples/multilingual/data_scripts/requirement.txt b/examples/multilingual/data_scripts/requirement.txt new file mode 100644 index 0000000000..e85d7d540e --- /dev/null +++ b/examples/multilingual/data_scripts/requirement.txt @@ -0,0 +1,2 @@ +wget +pandas \ No newline at end of file diff --git a/examples/multilingual/data_scripts/utils/dedup.py b/examples/multilingual/data_scripts/utils/dedup.py new file mode 100644 index 0000000000..d6fed8c695 --- /dev/null +++ b/examples/multilingual/data_scripts/utils/dedup.py @@ -0,0 +1,41 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import argparse + +def deup(src_file, tgt_file, src_file_out, tgt_file_out): + seen = set() + dup_count = 0 + with open(src_file, encoding='utf-8') as fsrc, \ + open(tgt_file, encoding='utf-8') as ftgt, \ + open(src_file_out, 'w', encoding='utf-8') as fsrc_out, \ + open(tgt_file_out, 'w', encoding='utf-8') as ftgt_out: + for s, t in zip(fsrc, ftgt): + if (s, t) not in seen: + fsrc_out.write(s) + ftgt_out.write(t) + seen.add((s, t)) + else: + dup_count += 1 + print(f'number of duplication: {dup_count}') + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--src-file", type=str, required=True, + help="src file") + parser.add_argument("--tgt-file", type=str, required=True, + help="tgt file") + parser.add_argument("--src-file-out", type=str, required=True, + help="src ouptut file") + parser.add_argument("--tgt-file-out", type=str, required=True, + help="tgt ouput file") + args = parser.parse_args() + deup(args.src_file, args.tgt_file, args.src_file_out, args.tgt_file_out) + + +if __name__ == "__main__": + main() diff --git a/examples/multilingual/data_scripts/utils/fasttext_multi_filter.py b/examples/multilingual/data_scripts/utils/fasttext_multi_filter.py new file mode 100644 index 0000000000..41b38ba5be --- /dev/null +++ b/examples/multilingual/data_scripts/utils/fasttext_multi_filter.py @@ -0,0 +1,63 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +#!/bin/python + +import fasttext +from multiprocessing import Pool +import contextlib +import sys +import argparse +from functools import partial +import io + +model = None +def init(model_path): + global model + model = fasttext.load_model(model_path) + +def pred(lines): + return lines, [model.predict(line.strip())[0][0][9:] for line in lines] + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--model", type=str, required=True, + help="model to load") + parser.add_argument("--inputs", nargs="+", default=['-'], + help="input files to filter") + parser.add_argument("--langs", nargs="+", required=True, + help="lang ids of each input file") + parser.add_argument("--outputs", nargs="+", default=['-'], + help="path to save lid filtered outputs") + parser.add_argument("--num-workers", type=int, metavar="N", default=10, + help="number of processes in parallel") + args = parser.parse_args() + + assert len(args.inputs) == len(args.langs) and len(args.inputs) == len(args.outputs) + + with contextlib.ExitStack() as stack: + inputs = [ + stack.enter_context(open(input, "r", encoding="utf-8", newline="\n", errors="replace")) + if input != "-" else io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8', errors="replace") + for input in args.inputs + ] + outputs = [ + stack.enter_context(open(output, "w", encoding="utf-8", newline="\n")) + if output != "-" else sys.stdout + for output in args.outputs + ] + with Pool(args.num_workers, initializer=partial(init, args.model)) as p: + skip_cnt = 0 + for lines, preds in p.imap(pred, list(zip(*inputs)), chunksize=500): + if not all(a == b for a, b in zip(preds, args.langs)): + skip_cnt += 1 + continue + for line, output_h in zip(lines, outputs): + print(line.strip(), file=output_h) + print(f"Skipped {skip_cnt} lines.") + +if __name__ == "__main__": + main() diff --git a/examples/multilingual/data_scripts/utils/strip_sgm.sh b/examples/multilingual/data_scripts/utils/strip_sgm.sh new file mode 100755 index 0000000000..7f4f61d7b1 --- /dev/null +++ b/examples/multilingual/data_scripts/utils/strip_sgm.sh @@ -0,0 +1 @@ +grep "seg id" | sed 's/<seg id="[0-9]\+">//g' | sed 's/<\/seg>//g' diff --git a/examples/multilingual/finetune_multilingual_model.sh b/examples/multilingual/finetune_multilingual_model.sh index ffcf1fc722..25960c5dc8 100644 --- a/examples/multilingual/finetune_multilingual_model.sh +++ b/examples/multilingual/finetune_multilingual_model.sh @@ -1,4 +1,9 @@ #!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. path_2_data=$1 # <path to data> which contains binarized data for each directions lang_list=$2 # <path to a file which contains a list of languages separted by new lines> diff --git a/examples/multilingual/multilingual_fairseq_gen.sh b/examples/multilingual/multilingual_fairseq_gen.sh index 8c2c7703b2..65aa322d7d 100644 --- a/examples/multilingual/multilingual_fairseq_gen.sh +++ b/examples/multilingual/multilingual_fairseq_gen.sh @@ -1,4 +1,9 @@ #!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. lang_pairs="en-fr,en-cs,fr-en,cs-en" path_2_data=$1 # <path to data> diff --git a/examples/multilingual/train_multilingual_model.sh b/examples/multilingual/train_multilingual_model.sh index c41730dfcd..cc050bd3f0 100644 --- a/examples/multilingual/train_multilingual_model.sh +++ b/examples/multilingual/train_multilingual_model.sh @@ -1,4 +1,9 @@ #!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. path_2_data=$1 # <path to data> which contains binarized data for each directions lang_list=$2 # <path to a file which contains a list of languages separted by new lines> From 8c7793b9d9ad272a4bee080839357539743a99d4 Mon Sep 17 00:00:00 2001 From: Yuqing Tang <yuqtang@fb.com> Date: Tue, 12 Jan 2021 21:37:26 -0800 Subject: [PATCH 153/774] Enable translation_multi_simple_epoch to load only two dictionaries for source and target only Summary: In the default settings, the translation_multi_simple_epoch task load a dictionary per language which can result in huge amount of memory consumption if all languages share the same dictionary. Reviewed By: shruti-bh Differential Revision: D25265741 fbshipit-source-id: c5bc3664efd800b120f015b2525c9fba2b1be3c5 --- .../multilingual/multilingual_data_manager.py | 106 +++++++++++++----- .../tasks/translation_multi_simple_epoch.py | 12 +- tests/test_binaries.py | 56 +++++++++ 3 files changed, 143 insertions(+), 31 deletions(-) diff --git a/fairseq/data/multilingual/multilingual_data_manager.py b/fairseq/data/multilingual/multilingual_data_manager.py index 21fb23c047..a2fae5bf52 100644 --- a/fairseq/data/multilingual/multilingual_data_manager.py +++ b/fairseq/data/multilingual/multilingual_data_manager.py @@ -39,6 +39,9 @@ logger = logging.getLogger(__name__) +SRC_DICT_NAME = 'src' +TGT_DICT_NAME = 'tgt' + def _lang_id(dic: Dictionary, lang: str): """Return language ID index.""" @@ -59,6 +62,15 @@ def __init__(self, args, lang_pairs, langs, dicts, sampling_method): self.args = args self.seed = args.seed self.lang_pairs = lang_pairs + self.extra_lang_pairs = ( + list( + {p for _, v in args.extra_lang_pairs.items() for p in v.split(",")} + ) + if args.extra_lang_pairs + else [] + ) + self.src_langs = {p.split("-")[0] for p in args.lang_pairs + self.extra_lang_pairs} + self.tgt_langs = {p.split("-")[1] for p in args.lang_pairs + self.extra_lang_pairs} self.langs = langs self.dicts = dicts self.lang_dict = self.create_lang_dictionary(self.langs) @@ -98,6 +110,10 @@ def add_args(parser): "note that the ordering determines language token IDs; " "--langs and --lang-dict are two exclusive options", ) + parser.add_argument('--source-dict', default=None, type=str, + help='path to source dictionary; if specified it will override per language dictionary loading') + parser.add_argument('--target-dict', default=None, type=str, + help='path to target dictionary; if specified it will override per language dictionary loading') parser.add_argument( "--lang-tok-style", default=LangTokStyle.multilingual.value, @@ -346,7 +362,28 @@ def check_langs(langs, pairs): ), ) - # load dictionaries + def load_dictionary_and_postproc(path): + d = load_dictionary(path) + augment_dictionary( + dictionary=d, + language_list=language_list, + lang_tok_style=args.lang_tok_style, + langtoks_specs=args.langtoks_specs, + extra_data=args.extra_data, + ) + return d + + dicts = cls.load_all_dictionaries(args, language_list, load_dictionary_and_postproc, training) + return language_list, dicts, training + + @classmethod + def load_all_dictionaries(cls, args, language_list, load_dictionary, training): + dicts = OrderedDict() + if args.source_dict is not None: + dicts[SRC_DICT_NAME] = load_dictionary(args.source_dict) + if args.target_dict is not None: + dicts[TGT_DICT_NAME] = load_dictionary(args.target_dict) + if training: extra_lang_pairs = ( list( @@ -355,35 +392,52 @@ def check_langs(langs, pairs): if args.extra_lang_pairs else [] ) - langs_to_load_dicts = sorted( - {x for p in args.lang_pairs + extra_lang_pairs for x in p.split("-")} + src_langs_to_load_dicts = sorted( + {p.split("-")[0] for p in (args.lang_pairs + extra_lang_pairs)} + ) + tgt_langs_to_load_dicts = sorted( + {p.split("-")[1] for p in (args.lang_pairs + extra_lang_pairs)} ) else: - langs_to_load_dicts = sorted([args.source_lang, args.target_lang]) + src_langs_to_load_dicts = [args.source_lang] + tgt_langs_to_load_dicts = [args.target_lang] - dicts = OrderedDict() paths = utils.split_paths(args.data) assert len(paths) > 0 - for lang in langs_to_load_dicts: - if args.fixed_dictionary is not None: - dicts[lang] = load_dictionary(args.fixed_dictionary) - else: + + def load_dicts(langs_to_load_dicts): + for lang in langs_to_load_dicts: dicts[lang] = load_dictionary( os.path.join(paths[0], "dict.{}.txt".format(lang)) ) - augment_dictionary( - dictionary=dicts[lang], - language_list=language_list, - lang_tok_style=args.lang_tok_style, - langtoks_specs=args.langtoks_specs, - extra_data=args.extra_data, - ) if len(dicts) > 0: - assert dicts[lang].pad() == dicts[langs_to_load_dicts[0]].pad() - assert dicts[lang].eos() == dicts[langs_to_load_dicts[0]].eos() - assert dicts[lang].unk() == dicts[langs_to_load_dicts[0]].unk() + dict0 = next(iter(dicts.values())) + assert dicts[lang].pad() == dict0.pad() + assert dicts[lang].eos() == dict0.eos() + assert dicts[lang].unk() == dict0.unk() logger.info("[{}] dictionary: {} types".format(lang, len(dicts[lang]))) - return language_list, dicts, training + + if args.fixed_dictionary is not None: + fixed_dict = load_dictionary(args.fixed_dictionary) + dicts = {lang: fixed_dict for lang in src_langs_to_load_dicts + tgt_langs_to_load_dicts} + else: + if args.source_dict is None: + load_dicts(src_langs_to_load_dicts) + if args.target_dict is None: + load_dicts(tgt_langs_to_load_dicts) + return dicts + + def get_source_dictionary(self, lang): + if self.args.source_dict is not None: + return self.dicts[SRC_DICT_NAME] + else: + return self.dicts[lang] + + def get_target_dictionary(self, lang): + if self.args.target_dict is not None: + return self.dicts[TGT_DICT_NAME] + else: + return self.dicts[lang] @classmethod def create_lang_dictionary(cls, langs): @@ -418,7 +472,7 @@ def get_encoder_langtok(self, src_lang, tgt_lang, spec=None): lang=tgt_lang, lang_tok_style=self.args.lang_tok_style, spec=spec ) return self.get_langtok_index( - langtok, self.dicts[src_lang if src_lang else tgt_lang] + langtok, self.get_source_dictionary(src_lang) if src_lang else self.get_target_dictionary(tgt_lang) ) def get_decoder_langtok(self, tgt_lang, spec=None): @@ -427,7 +481,7 @@ def get_decoder_langtok(self, tgt_lang, spec=None): langtok = get_lang_tok( lang=tgt_lang, lang_tok_style=self.args.lang_tok_style, spec=spec ) - return self.get_langtok_index(langtok, self.dicts[tgt_lang]) + return self.get_langtok_index(langtok, self.get_target_dictionary(tgt_lang)) @classmethod def load_data(cls, path, vdict, impl): @@ -760,9 +814,9 @@ def load_a_dataset( if self.args.lang_tok_replacing_bos_eos: ds = self.alter_dataset_langtok( langpair_ds, - src_eos=self.dicts[src if src else tgt].eos(), + src_eos=self.get_source_dictionary(src).eos() if src else self.get_target_dictionary(tgt).eos(), src_lang=src, - tgt_eos=self.dicts[tgt].eos(), + tgt_eos=self.get_target_dictionary(tgt).eos(), tgt_lang=tgt, src_langtok_spec=src_langtok_spec, tgt_langtok_spec=tgt_langtok_spec, @@ -906,11 +960,11 @@ def get_split_data_param_list(self, split, epoch, shard_epoch=None): "data_path": data_path, "split": split, "src": src, - "src_dict": self.dicts[src] + "src_dict": self.get_source_dictionary(src) if src and data_category != "mono_dae" else None, "tgt": tgt, - "tgt_dict": self.dicts[tgt], + "tgt_dict": self.get_target_dictionary(tgt), "data_category": data_category, "langtok_spec": lang_tok_spec, } diff --git a/fairseq/tasks/translation_multi_simple_epoch.py b/fairseq/tasks/translation_multi_simple_epoch.py index 34af9bf4a3..6f36e5b93e 100644 --- a/fairseq/tasks/translation_multi_simple_epoch.py +++ b/fairseq/tasks/translation_multi_simple_epoch.py @@ -105,8 +105,10 @@ def __init__(self, args, langs, dicts, training): args, self.lang_pairs, langs, dicts, self.sampling_method ) - @classmethod - def check_dicts(cls, dicts, source_langs, target_langs): + def check_dicts(self, dicts, source_langs, target_langs): + if self.args.source_dict is not None or self.args.target_dict is not None: + # no need to check whether the source side and target side are sharing dictionaries + return src_dict = dicts[source_langs[0]] tgt_dict = dicts[target_langs[0]] for src_lang in source_langs: @@ -123,7 +125,7 @@ def check_dicts(cls, dicts, source_langs, target_langs): @classmethod def setup_task(cls, args, **kwargs): langs, dicts, training = MultilingualDatasetManager.prepare( - cls.load_dictionary, args, **kwargs + cls.load_dictionary, args, **kwargs ) return cls(args, langs, dicts, training) @@ -263,11 +265,11 @@ def max_positions(self): @property def source_dictionary(self): - return self.dicts[self.source_langs[0]] + return self.data_manager.get_source_dictionary(self.source_langs[0]) @property def target_dictionary(self): - return self.dicts[self.target_langs[0]] + return self.data_manager.get_target_dictionary(self.target_langs[0]) def create_batch_sampler_func( self, diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 4e605bd0b1..ddfc1c4db5 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -538,6 +538,62 @@ def test_translation_multi_simple_epoch_dicts(self): + dec_ltok_flag, ) + def test_translation_multi_simple_epoch_src_tgt_dict_spec(self): + # test the specification of explicit --src-dict and --tgt-dict + with contextlib.redirect_stdout(StringIO()): + enc_ltok_flag = ["--encoder-langtok", "src"] + dec_ltok_flag = ["--decoder-langtok"] + with tempfile.TemporaryDirectory( + "test_translation_multi_simple_epoch_dict" + ) as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data( + data_dir, extra_flags=[] + ) + train_translation_model( + data_dir, + arch="transformer", + task="translation_multi_simple_epoch", + extra_flags=[ + "--source-dict", f"{data_dir}/dict.in.txt", + "--target-dict", f"{data_dir}/dict.out.txt", + "--encoder-layers", + "2", + "--decoder-layers", + "2", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--sampling-method", + "temperature", + "--sampling-temperature", + "1.5", + "--virtual-epoch-size", + "1000", + ] + + enc_ltok_flag + + dec_ltok_flag, + lang_flags=["--lang-pairs", "in-out"], + run_validation=True, + extra_valid_flags=enc_ltok_flag + dec_ltok_flag, + ) + generate_main( + data_dir, + extra_flags=[ + "--task", + "translation_multi_simple_epoch", + "--lang-pairs", + "in-out", + "--source-lang", + "in", + "--target-lang", + "out", + ] + + enc_ltok_flag + + dec_ltok_flag, + ) + def test_transformer_cross_self_attention(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory( From 4a6f89d373dafc50b416092b41c070c304b31698 Mon Sep 17 00:00:00 2001 From: Frank Seide <seide@fb.com> Date: Wed, 13 Jan 2021 00:02:05 -0800 Subject: [PATCH 154/774] Make Fairseq trainer multiply_grads resilient to sample_size 0 Summary: The Fairseq `Trainer` class does not always guard its `multiply_grads` step to the special case of `sample_size` of 0, which may happen in edge cases. This diff now guards in all conditions. Reviewed By: myleott Differential Revision: D25814612 fbshipit-source-id: 4974ee0148ab2a86f60980f3bf248878b2ebbb36 --- fairseq/trainer.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index a6c1013635..fec60f7742 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -508,7 +508,7 @@ def train_step(self, samples, raise_oom=False): # forward and backward pass logging_outputs, sample_size, ooms = [], 0, 0 - for i, sample in enumerate(samples): + for i, sample in enumerate(samples): # delayed update loop sample, is_dummy_batch = self._prepare_sample(sample) def maybe_no_sync(): @@ -605,21 +605,29 @@ def maybe_no_sync(): overflow = False try: with torch.autograd.profiler.record_function("reduce-grads"): + # reduce gradients across workers self.optimizer.all_reduce_grads(self.model) if utils.has_parameters(self.criterion): self.optimizer.all_reduce_grads(self.criterion) with torch.autograd.profiler.record_function("multiply-grads"): # multiply gradients by (data_parallel_size / sample_size) since - # DDP already normalizes by the number of data parallel workers. + # DDP normalizes by the number of data parallel workers for + # improved fp16 precision. # Thus we get (sum_of_gradients / sample_size) at the end. - if not self.cfg.optimization.use_bmuf: - self.optimizer.multiply_grads( - self.data_parallel_world_size / sample_size - ) - elif sample_size > 0: # BMUF needs to check sample size - num = self.data_parallel_world_size if self._sync_stats() else 1 - self.optimizer.multiply_grads(num / sample_size) + # In case of fp16, this step also undoes loss scaling. + # (Debugging note: Some optimizers perform this scaling on the + # fly, so inspecting model.parameters() or optimizer.params may + # still show the original, unscaled gradients.) + numer = ( + self.data_parallel_world_size + if not self.cfg.optimization.use_bmuf or self._sync_stats() + else 1 + ) + self.optimizer.multiply_grads(numer / (sample_size or 1.0)) + # Note: (sample_size or 1.0) handles the case of a zero gradient, in a + # way that avoids CPU/device transfers in case sample_size is a GPU or + # TPU object. The assumption is that the gradient itself is also 0. with torch.autograd.profiler.record_function("clip-grads"): # clip grads @@ -661,7 +669,7 @@ def maybe_no_sync(): raise except OverflowError as e: overflow = True - logger.info("NOTE: overflow detected, " + str(e)) + logger.info(f"NOTE: gradient overflow detected, ignoring gradient, {str(e)}") grad_norm = torch.tensor(0.0).cuda() self.zero_grad() except RuntimeError as e: From cb84694c195afced474d17318b5e746d1a9d20a3 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Sat, 16 Jan 2021 19:08:50 -0800 Subject: [PATCH 155/774] fixes regression in lm decoding with flashlight (#1557) Summary: before: ``` PYTHONPATH=. python examples/speech_recognition/infer.py /checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw --task audio_pretraining --nbest 1 --path /private/home/abaevski/models/wav2vec2/960h_scratch.pt --gen-subset test_clean --w2l-decoder kenlm --lm-model /checkpoint/abaevski/data/speech/libri/4-gram.bin --lexicon /checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw/lexicon_ltr.lst --lm-weight 2.601664188829183 --word-score -1.4825337752451184 --sil-weight 0 --criterion ctc --labels ltr --max-tokens 4000000 --remove-bpe letter INFO:__main__:Namespace(no_progress_bar=False, log_interval=100, log_format=None, tensorboard_logdir=None, wandb_project=None, azureml_logging=False, seed=1, cpu=False, tpu=False, bf16=False, memory_efficient_bf16=False, fp16=False, memory_efficient_fp16=False, fp16_no_flatten_grads=False, fp16_init_scale=128, fp16_scale_window=None, fp16_scale_tolerance=0.0, min_loss_scale=0.0001, threshold_loss_scale=None, user_dir=None, empty_cache_freq=0, all_gather_list_size=16384, model_parallel_size=1, quantization_config_path=None, profile=False, reset_logging=True, suppress_crashes=False, criterion='ctc', tokenizer=None, bpe=None, optimizer=None, lr_scheduler='fixed', scoring='bleu', task='audio_pretraining', num_workers=1, skip_invalid_size_inputs_valid_test=False, max_tokens=4000000, batch_size=None, required_batch_size_multiple=8, required_seq_len_multiple=1, dataset_impl=None, data_buffer_size=10, train_subset='train', valid_subset='valid', validate_interval=1, validate_interval_updates=0, validate_after_updates=0, fixed_validation_seed=None, disable_validation=False, max_tokens_valid=4000000, batch_size_valid=None, curriculum=0, gen_subset='test_clean', num_shards=1, shard_id=0, distributed_world_size=1, distributed_rank=0, distributed_backend='nccl', distributed_init_method=None, distributed_port=-1, device_id=0, distributed_no_spawn=False, ddp_backend='c10d', bucket_cap_mb=25, fix_batches_to_gpus=False, find_unused_parameters=False, fast_stat_sync=False, heartbeat_timeout=-1, broadcast_buffers=False, distributed_wrapper='DDP', slowmo_momentum=None, slowmo_algorithm='LocalSGD', localsgd_frequency=3, nprocs_per_node=2, pipeline_model_parallel=False, pipeline_balance=None, pipeline_devices=None, pipeline_chunks=0, pipeline_encoder_balance=None, pipeline_encoder_devices=None, pipeline_decoder_balance=None, pipeline_decoder_devices=None, pipeline_checkpoint='never', zero_sharding='none', path='/private/home/abaevski/models/wav2vec2/960h_scratch.pt', post_process='letter', quiet=False, model_overrides='{}', results_path=None, beam=5, nbest=1, max_len_a=0, max_len_b=200, min_len=1, match_source_len=False, unnormalized=False, no_early_stop=False, no_beamable_mm=False, lenpen=1, unkpen=0, replace_unk=None, sacrebleu=False, score_reference=False, prefix_size=0, no_repeat_ngram_size=0, sampling=False, sampling_topk=-1, sampling_topp=-1.0, constraints=None, temperature=1.0, diverse_beam_groups=-1, diverse_beam_strength=0.5, diversity_rate=-1.0, print_alignment=None, print_step=False, lm_path=None, lm_weight=2.601664188829183, iter_decode_eos_penalty=0.0, iter_decode_max_iter=10, iter_decode_force_max_iter=False, iter_decode_with_beam=1, iter_decode_with_external_reranker=False, retain_iter_history=False, retain_dropout=False, retain_dropout_modules=None, decoding_format=None, no_seed_provided=False, save_dir='checkpoints', restore_file='checkpoint_last.pt', finetune_from_model=None, reset_dataloader=False, reset_lr_scheduler=False, reset_meters=False, reset_optimizer=False, optimizer_overrides='{}', save_interval=1, save_interval_updates=0, keep_interval_updates=-1, keep_last_epochs=-1, keep_best_checkpoints=-1, no_save=False, no_epoch_checkpoints=False, no_last_checkpoints=False, no_save_optimizer_state=False, best_checkpoint_metric='loss', maximize_best_checkpoint_metric=False, patience=-1, checkpoint_suffix='', checkpoint_shard_count=1, load_checkpoint_on_all_dp_ranks=False, kspmodel=None, wfstlm=None, rnnt_decoding_type='greedy', rnnt_len_penalty=-0.5, w2l_decoder='kenlm', lexicon='/checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw/lexicon_ltr.lst', unit_lm=False, kenlm_model='/checkpoint/abaevski/data/speech/libri/4-gram.bin', beam_threshold=25.0, beam_size_token=100, word_score=-1.4825337752451184, unk_weight=-inf, sil_weight=0.0, dump_emissions=None, dump_features=None, load_emissions=None, data='/checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw', labels='ltr', sample_rate=16000, normalize=False, enable_padding=False, max_sample_size=None, min_sample_size=None, eval_wer=False, eval_wer_tokenizer=None, eval_wer_post_process='letter', autoregressive=False, zero_infinity=False, wer_kenlm_model=None, wer_lexicon=None, wer_lm_weight=2.0, wer_word_score=-1.0, wer_args=None, force_anneal=None, lr_shrink=0.1, warmup_updates=0, pad=1, eos=2, unk=3) INFO:__main__:| decoding with criterion ctc INFO:__main__:| loading model(s) from /private/home/abaevski/models/wav2vec2/960h_scratch.pt INFO:fairseq.data.audio.raw_audio_dataset:loaded 2620, skipped 0 samples INFO:__main__:| /checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw test_clean 2620 examples INFO:__main__:WER: 10.415398660986002 INFO:__main__:| Processed 2620 sentences (291252 tokens) in 130.4s (20.09sentences/s, 2233.70 tokens/s) INFO:__main__:| Generate test_clean with beam=5 ``` after: ``` PYTHONPATH=. python examples/speech_recognition/infer.py /checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw --task audio_pretraining --nbest 1 --path /private/home/abaevski/models/wav2vec2/960h_scratch.pt --gen-subset test_clean --w2l-decoder kenlm --lm-model /checkpoint/abaevski/data/speech/libri/4-gram.bin --lexicon /checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw/lexicon_ltr.lst --lm-weight 2.601664188829183 --word-score -1.4825337752451184 --sil-weight 0 --criterion ctc --labels ltr --max-tokens 5000000 --remove-bpe letter INFO:__main__:Namespace(no_progress_bar=False, log_interval=100, log_format=None, tensorboard_logdir=None, wandb_project=None, azureml_logging=False, seed=1, cpu=False, tpu=False, bf16=False, memory_efficient_bf16=False, fp16=False, memory_efficient_fp16=False, fp16_no_flatten_grads=False, fp16_init_scale=128, fp16_scale_window=None, fp16_scale_tolerance=0.0, min_loss_scale=0.0001, threshold_loss_scale=None, user_dir=None, empty_cache_freq=0, all_gather_list_size=16384, model_parallel_size=1, quantization_config_path=None, profile=False, reset_logging=True, suppress_crashes=False, criterion='ctc', tokenizer=None, bpe=None, optimizer=None, lr_scheduler='fixed', scoring='bleu', task='audio_pretraining', num_workers=1, skip_invalid_size_inputs_valid_test=False, max_tokens=5000000, batch_size=None, required_batch_size_multiple=8, required_seq_len_multiple=1, dataset_impl=None, data_buffer_size=10, train_subset='train', valid_subset='valid', validate_interval=1, validate_interval_updates=0, validate_after_updates=0, fixed_validation_seed=None, disable_validation=False, max_tokens_valid=5000000, batch_size_valid=None, curriculum=0, gen_subset='test_clean', num_shards=1, shard_id=0, distributed_world_size=1, distributed_rank=0, distributed_backend='nccl', distributed_init_method=None, distributed_port=-1, device_id=0, distributed_no_spawn=False, ddp_backend='c10d', bucket_cap_mb=25, fix_batches_to_gpus=False, find_unused_parameters=False, fast_stat_sync=False, heartbeat_timeout=-1, broadcast_buffers=False, distributed_wrapper='DDP', slowmo_momentum=None, slowmo_algorithm='LocalSGD', localsgd_frequency=3, nprocs_per_node=2, pipeline_model_parallel=False, pipeline_balance=None, pipeline_devices=None, pipeline_chunks=0, pipeline_encoder_balance=None, pipeline_encoder_devices=None, pipeline_decoder_balance=None, pipeline_decoder_devices=None, pipeline_checkpoint='never', zero_sharding='none', path='/private/home/abaevski/models/wav2vec2/960h_scratch.pt', post_process='letter', quiet=False, model_overrides='{}', results_path=None, beam=5, nbest=1, max_len_a=0, max_len_b=200, min_len=1, match_source_len=False, unnormalized=False, no_early_stop=False, no_beamable_mm=False, lenpen=1, unkpen=0, replace_unk=None, sacrebleu=False, score_reference=False, prefix_size=0, no_repeat_ngram_size=0, sampling=False, sampling_topk=-1, sampling_topp=-1.0, constraints=None, temperature=1.0, diverse_beam_groups=-1, diverse_beam_strength=0.5, diversity_rate=-1.0, print_alignment=None, print_step=False, lm_path=None, lm_weight=2.601664188829183, iter_decode_eos_penalty=0.0, iter_decode_max_iter=10, iter_decode_force_max_iter=False, iter_decode_with_beam=1, iter_decode_with_external_reranker=False, retain_iter_history=False, retain_dropout=False, retain_dropout_modules=None, decoding_format=None, no_seed_provided=False, save_dir='checkpoints', restore_file='checkpoint_last.pt', finetune_from_model=None, reset_dataloader=False, reset_lr_scheduler=False, reset_meters=False, reset_optimizer=False, optimizer_overrides='{}', save_interval=1, save_interval_updates=0, keep_interval_updates=-1, keep_last_epochs=-1, keep_best_checkpoints=-1, no_save=False, no_epoch_checkpoints=False, no_last_checkpoints=False, no_save_optimizer_state=False, best_checkpoint_metric='loss', maximize_best_checkpoint_metric=False, patience=-1, checkpoint_suffix='', checkpoint_shard_count=1, load_checkpoint_on_all_dp_ranks=False, kspmodel=None, wfstlm=None, rnnt_decoding_type='greedy', rnnt_len_penalty=-0.5, w2l_decoder='kenlm', lexicon='/checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw/lexicon_ltr.lst', unit_lm=False, kenlm_model='/checkpoint/abaevski/data/speech/libri/4-gram.bin', beam_threshold=25.0, beam_size_token=100, word_score=-1.4825337752451184, unk_weight=-inf, sil_weight=0.0, dump_emissions=None, dump_features=None, load_emissions=None, data='/checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw', labels='ltr', sample_rate=16000, normalize=False, enable_padding=False, max_sample_size=None, min_sample_size=None, eval_wer=False, eval_wer_tokenizer=None, eval_wer_post_process='letter', autoregressive=False, zero_infinity=False, wer_kenlm_model=None, wer_lexicon=None, wer_lm_weight=2.0, wer_word_score=-1.0, wer_args=None, force_anneal=None, lr_shrink=0.1, warmup_updates=0, pad=1, eos=2, unk=3) INFO:__main__:| decoding with criterion ctc INFO:__main__:| loading model(s) from /private/home/abaevski/models/wav2vec2/960h_scratch.pt INFO:fairseq.data.audio.raw_audio_dataset:loaded 2620, skipped 0 samples INFO:__main__:| /checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw test_clean 2620 examples INFO:__main__:WER: 2.991859403530128 INFO:__main__:| Processed 2620 sentences (288370 tokens) in 129.8s (20.18sentences/s, 2220.83 tokens/s) INFO:__main__:| Generate test_clean with beam=5 ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1557 Reviewed By: wnhsu Differential Revision: D25935711 Pulled By: alexeib fbshipit-source-id: 36c1c9b9ba32a60b2c04275036514646d2fb33f5 --- examples/speech_recognition/w2l_decoder.py | 173 +++++++++++++-------- fairseq/models/wav2vec/wav2vec2_asr.py | 10 ++ 2 files changed, 116 insertions(+), 67 deletions(-) diff --git a/examples/speech_recognition/w2l_decoder.py b/examples/speech_recognition/w2l_decoder.py index 1fb20757d0..706d9f1433 100644 --- a/examples/speech_recognition/w2l_decoder.py +++ b/examples/speech_recognition/w2l_decoder.py @@ -59,10 +59,17 @@ def __init__(self, args, tgt_dict): if "<ctc_blank>" in tgt_dict.indices else tgt_dict.bos() ) + if "<sep>" in tgt_dict.indices: + self.silence = tgt_dict.index("<sep>") + elif "|" in tgt_dict.indices: + self.silence = tgt_dict.index("|") + else: + self.silence = tgt_dict.eos() self.asg_transitions = None elif args.criterion == "asg_loss": self.criterion_type = CriterionType.ASG self.blank = -1 + self.silence = -1 self.asg_transitions = args.asg_transitions self.max_replabel = args.max_replabel assert len(self.asg_transitions) == self.vocab_size ** 2 @@ -81,10 +88,13 @@ def generate(self, models, sample, **unused): def get_emissions(self, models, encoder_input): """Run encoder and normalize emissions""" - # encoder_out = models[0].encoder(**encoder_input) - encoder_out = models[0](**encoder_input) + model = models[0] + encoder_out = model(**encoder_input) if self.criterion_type == CriterionType.CTC: - emissions = models[0].get_normalized_probs(encoder_out, log_probs=True) + if hasattr(model, "get_logits"): + emissions = model.get_logits(encoder_out) # no need to normalize emissions + else: + emissions = model.get_normalized_probs(encoder_out, log_probs=True) elif self.criterion_type == CriterionType.ASG: emissions = encoder_out["encoder_out"] return emissions.transpose(0, 1).float().cpu().contiguous() @@ -132,58 +142,75 @@ class W2lKenLMDecoder(W2lDecoder): def __init__(self, args, tgt_dict): super().__init__(args, tgt_dict) - self.silence = ( - tgt_dict.index("<ctc_blank>") - if "<ctc_blank>" in tgt_dict.indices - else tgt_dict.bos() - ) - self.lexicon = load_words(args.lexicon) - self.word_dict = create_word_dict(self.lexicon) - self.unk_word = self.word_dict.get_index("<unk>") + self.unit_lm = getattr(args, "unit_lm", False) - self.lm = KenLM(args.kenlm_model, self.word_dict) - self.trie = Trie(self.vocab_size, self.silence) + if args.lexicon: + self.lexicon = load_words(args.lexicon) + self.word_dict = create_word_dict(self.lexicon) + self.unk_word = self.word_dict.get_index("<unk>") - start_state = self.lm.start(False) - for i, (word, spellings) in enumerate(self.lexicon.items()): - word_idx = self.word_dict.get_index(word) - _, score = self.lm.score(start_state, word_idx) - for spelling in spellings: - spelling_idxs = [tgt_dict.index(token) for token in spelling] - assert ( - tgt_dict.unk() not in spelling_idxs - ), f"{spelling} {spelling_idxs}" - self.trie.insert(spelling_idxs, word_idx, score) - self.trie.smear(SmearingMode.MAX) - - self.decoder_opts = LexiconDecoderOptions( - beam_size=args.beam, - beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), - beam_threshold=args.beam_threshold, - lm_weight=args.lm_weight, - word_score=args.word_score, - unk_score=args.unk_weight, - sil_score=args.sil_weight, - log_add=False, - criterion_type=self.criterion_type, - ) + self.lm = KenLM(args.kenlm_model, self.word_dict) + self.trie = Trie(self.vocab_size, self.silence) + start_state = self.lm.start(False) + for i, (word, spellings) in enumerate(self.lexicon.items()): + word_idx = self.word_dict.get_index(word) + _, score = self.lm.score(start_state, word_idx) + for spelling in spellings: + spelling_idxs = [tgt_dict.index(token) for token in spelling] + assert ( + tgt_dict.unk() not in spelling_idxs + ), f"{spelling} {spelling_idxs}" + self.trie.insert(spelling_idxs, word_idx, score) + self.trie.smear(SmearingMode.MAX) + + self.decoder_opts = LexiconDecoderOptions( + beam_size=args.beam, + beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), + beam_threshold=args.beam_threshold, + lm_weight=args.lm_weight, + word_score=args.word_score, + unk_score=args.unk_weight, + sil_score=args.sil_weight, + log_add=False, + criterion_type=self.criterion_type, + ) + + if self.asg_transitions is None: + N = 768 + # self.asg_transitions = torch.FloatTensor(N, N).zero_() + self.asg_transitions = [] + + self.decoder = LexiconDecoder( + self.decoder_opts, + self.trie, + self.lm, + self.silence, + self.blank, + self.unk_word, + self.asg_transitions, + self.unit_lm, + ) + else: + assert args.unit_lm, "lexicon free decoding can only be done with a unit language model" + from flashlight.lib.text.decoder import LexiconFreeDecoder, LexiconFreeDecoderOptions + + d = {w: [[w]] for w in tgt_dict.symbols} + self.word_dict = create_word_dict(d) + self.lm = KenLM(args.kenlm_model, self.word_dict) + self.decoder_opts = LexiconFreeDecoderOptions( + beam_size=args.beam, + beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), + beam_threshold=args.beam_threshold, + lm_weight=args.lm_weight, + sil_score=args.sil_weight, + log_add=False, + criterion_type=self.criterion_type, + ) + self.decoder = LexiconFreeDecoder( + self.decoder_opts, self.lm, self.silence, self.blank, [] + ) - if self.asg_transitions is None: - N = 768 - # self.asg_transitions = torch.FloatTensor(N, N).zero_() - self.asg_transitions = [] - - self.decoder = LexiconDecoder( - self.decoder_opts, - self.trie, - self.lm, - self.silence, - self.blank, - self.unk_word, - self.asg_transitions, - False, - ) def decode(self, emissions): B, T, N = emissions.size() @@ -341,8 +368,6 @@ class W2lFairseqLMDecoder(W2lDecoder): def __init__(self, args, tgt_dict): super().__init__(args, tgt_dict) - self.silence = tgt_dict.bos() - self.unit_lm = getattr(args, "unit_lm", False) self.lexicon = load_words(args.lexicon) if args.lexicon else None @@ -368,18 +393,6 @@ def __init__(self, args, tgt_dict): self.unk_word = self.word_dict.unk() self.lm = FairseqLM(self.word_dict, model) - self.decoder_opts = LexiconDecoderOptions( - beam_size=args.beam, - beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), - beam_threshold=args.beam_threshold, - lm_weight=args.lm_weight, - word_score=args.word_score, - unk_score=args.unk_weight, - sil_score=args.sil_weight, - log_add=False, - criterion_type=self.criterion_type, - ) - if self.lexicon: start_state = self.lm.start(False) for i, (word, spellings) in enumerate(self.lexicon.items()): @@ -399,6 +412,18 @@ def __init__(self, args, tgt_dict): self.trie.insert(spelling_idxs, word_idx, score) self.trie.smear(SmearingMode.MAX) + self.decoder_opts = LexiconDecoderOptions( + beam_size=args.beam, + beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), + beam_threshold=args.beam_threshold, + lm_weight=args.lm_weight, + word_score=args.word_score, + unk_score=args.unk_weight, + sil_score=args.sil_weight, + log_add=False, + criterion_type=self.criterion_type, + ) + self.decoder = LexiconDecoder( self.decoder_opts, self.trie, @@ -406,11 +431,25 @@ def __init__(self, args, tgt_dict): self.silence, self.blank, self.unk_word, - [], + self.asg_transitions, self.unit_lm, ) else: - from flashlight.lib.text.decoder import LexiconFreeDecoder + assert args.unit_lm, "lexicon free decoding can only be done with a unit language model" + from flashlight.lib.text.decoder import LexiconFreeDecoder, LexiconFreeDecoderOptions + + d = {w: [[w]] for w in tgt_dict.symbols} + self.word_dict = create_word_dict(d) + self.lm = KenLM(args.kenlm_model, self.word_dict) + self.decoder_opts = LexiconFreeDecoderOptions( + beam_size=args.beam, + beam_size_token=int(getattr(args, "beam_size_token", len(tgt_dict))), + beam_threshold=args.beam_threshold, + lm_weight=args.lm_weight, + sil_score=args.sil_weight, + log_add=False, + criterion_type=self.criterion_type, + ) self.decoder = LexiconFreeDecoder( self.decoder_opts, self.lm, self.silence, self.blank, [] ) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 790b0a8ad1..bbd2ab9ec5 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -156,6 +156,16 @@ def get_normalized_probs(self, net_output, log_probs): else: return utils.softmax(logits.float(), dim=-1) + def get_logits(self, net_output): + logits = net_output["encoder_out"] + padding = net_output["encoder_padding_mask"] + if padding is not None and padding.any(): + padding = padding.T + logits[padding][...,0] = 0 + logits[padding][...,1:] = float('-inf') + + return logits + def forward(self, **kwargs): x = self.w2v_encoder(**kwargs) return x From d927d69beefd695738eff0f5c9d9b0d6dc6abcb4 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Sun, 17 Jan 2021 10:01:00 -0800 Subject: [PATCH 156/774] allows overwriting nested properties with model-overrrides (#1558) Summary: without this, it is not possible to use --model-overrides to override properties nested within a config Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1558 Reviewed By: myleott Differential Revision: D25935778 Pulled By: alexeib fbshipit-source-id: 1466f04b8e67842b91299ec88f1370ca0200c6a0 --- fairseq/dataclass/utils.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 4dc978409e..401c212ecc 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -428,7 +428,14 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): for k in cfg.keys(): # "k in cfg" will return false if its a "mandatory value (e.g. ???)" if k in cfg and isinstance(cfg[k], DictConfig): - overwrite_args_by_name(cfg[k], overrides) + if k in overrides and isinstance(overrides[k], dict): + for ok, ov in overrides[k].items(): + if isinstance(ov, dict): + overwrite_args_by_name(cfg[k][ok], ov) + else: + cfg[k][ok] = ov + else: + overwrite_args_by_name(cfg[k], overrides) elif k in cfg and isinstance(cfg[k], Namespace): for override_key, val in overrides.items(): setattr(cfg[k], override_key, val) From 9f5eda48edfad4cb33610f272cb503dedf60ab67 Mon Sep 17 00:00:00 2001 From: Lior Deutsch <sliorde@gmail.com> Date: Sun, 17 Jan 2021 10:03:32 -0800 Subject: [PATCH 157/774] fixed dynamic convolution wrapper function unused arguments (#3136) Summary: The bug that this pull request addresses was discussed [in this GitHub issue](https://github.com/pytorch/fairseq/issues/3085#issue-777177450), and myleott has [asked for the pull request](https://github.com/pytorch/fairseq/issues/3085#issuecomment-754854074). As you can see from the diff, the pull request is very simple. However, I did not run any tests (I don't have a suitable environment, I think). Also: I did not add any tests, I did not change any documentation, I did not check linting. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3136 Reviewed By: myleott Differential Revision: D25935770 Pulled By: alexeib fbshipit-source-id: b338e7cfb409fd14dac653121256276550f53b21 --- fairseq/modules/dynamic_convolution.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/modules/dynamic_convolution.py b/fairseq/modules/dynamic_convolution.py index 5999a04539..9f2d28da65 100644 --- a/fairseq/modules/dynamic_convolution.py +++ b/fairseq/modules/dynamic_convolution.py @@ -37,7 +37,10 @@ def DynamicConv( num_heads=num_heads, weight_dropout=weight_dropout, weight_softmax=weight_softmax, + renorm_padding=renorm_padding, bias=bias, + conv_bias=conv_bias, + query_size=query_size, ) except ImportError as e: print(e) @@ -48,7 +51,10 @@ def DynamicConv( num_heads=num_heads, weight_dropout=weight_dropout, weight_softmax=weight_softmax, + renorm_padding=renorm_padding, bias=bias, + conv_bias=conv_bias, + query_size=query_size, ) From 1164a7fc432a188d401895018eaa85175fb06f9d Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Sun, 17 Jan 2021 23:25:04 -0800 Subject: [PATCH 158/774] Fix time warping for SpecAugment Summary: Fix time warping for SpecAugment Github issue: https://github.com/pytorch/fairseq/issues/3141 Reviewed By: jmp84 Differential Revision: D25941870 fbshipit-source-id: 97f9c67a49212556156b33aee0056a86ec990db4 --- fairseq/data/audio/feature_transforms/specaugment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/data/audio/feature_transforms/specaugment.py b/fairseq/data/audio/feature_transforms/specaugment.py index 2ef4778b85..ce5802b41a 100644 --- a/fairseq/data/audio/feature_transforms/specaugment.py +++ b/fairseq/data/audio/feature_transforms/specaugment.py @@ -98,7 +98,7 @@ def __call__(self, spectrogram): import cv2 w0 = np.random.randint(self.time_warp_w, num_frames - self.time_warp_w) - w = np.random.randint(0, self.time_warp_w) + w = np.random.randint(-self.time_warp_w + 1, self.time_warp_w) upper, lower = distorted[:w0, :], distorted[w0:, :] upper = cv2.resize( upper, dsize=(num_freqs, w0 + w), interpolation=cv2.INTER_LINEAR From ecf0b60e124e1e795e30004ced00883bf8ba5192 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Tue, 19 Jan 2021 12:34:09 -0800 Subject: [PATCH 159/774] add defaults to configs (#1564) Summary: previously, when using the hydra_train entry point, the config object that got created would only contain things explicitly specified in config files/command line. normally this is not a problem as we load defaults when creating any object for a particular config, but in fact this config was getting stored in checkpoints. the checkpoints would then have incomplete config that would be incorrect if defaults got changed in the code. this PR adds defaults into configs for all config objects that hydra doesn't know about before: ``` {'_name': None, 'common': {'_name': None, 'no_progress_bar': False, 'log_interval': 200, 'log_format': 'json', 'tensorboard_logdir': None, 'wandb_project': None, 'azureml_logging': False, 'seed': 1, 'cpu': False, 'tpu': False, 'bf16': False, 'memory_efficient_bf16': False, 'fp16': True, 'memory_efficient_fp16': False, 'fp16_no_flatten_grads': False, 'fp16_init_scale': 128, 'fp16_scale_window': None, 'fp16_scale_tolerance': 0.0, 'min_loss_scale': 0.0001, 'threshold_loss_scale': None, 'user_dir': None, 'empty_cache_freq': 0, 'all_gather_list_size': 16384, 'model_parallel_size': 1, 'quantization_config_path': None, 'profile': False, 'reset_logging': True, 'suppress_crashes': False}, 'common_eval': {'_name': None, 'path': None, 'post_process': None, 'quiet': False, 'model_overrides': '{}', 'results_path': None}, 'distributed_training': {'_name': None, 'distributed_world_size': 2, 'distributed_rank': 0, 'distributed_backend': 'nccl', 'distributed_init_method': None, 'distributed_port': -1, 'device_id': 0, 'distributed_no_spawn': False, 'ddp_backend': 'no_c10d', 'bucket_cap_mb': 25, 'fix_batches_to_gpus': False, 'find_unused_parameters': False, 'fast_stat_sync': False, 'heartbeat_timeout': -1, 'broadcast_buffers': False, 'distributed_wrapper': 'DDP', 'slowmo_momentum': None, 'slowmo_algorithm': 'LocalSGD', 'localsgd_frequency': 3, 'nprocs_per_node': 2, 'pipeline_model_parallel': False, 'pipeline_balance': None, 'pipeline_devices': None, 'pipeline_chunks': 0, 'pipeline_encoder_balance': None, 'pipeline_encoder_devices': None, 'pipeline_decoder_balance': None, 'pipeline_decoder_devices': None, 'pipeline_checkpoint': 'never', 'zero_sharding': 'none', 'tpu': False}, 'dataset': {'_name': None, 'num_workers': 6, 'skip_invalid_size_inputs_valid_test': True, 'max_tokens': 3200000, 'batch_size': None, 'required_batch_size_multiple': 8, 'required_seq_len_multiple': 1, 'dataset_impl': None, 'data_buffer_size': 10, 'train_subset': 'train', 'valid_subset': 'dev_other', 'validate_interval': 50, 'validate_interval_updates': 0, 'validate_after_updates': 10000, 'fixed_validation_seed': None, 'disable_validation': False, 'max_tokens_valid': 3200000, 'batch_size_valid': None, 'curriculum': 0, 'gen_subset': 'test', 'num_shards': 1, 'shard_id': 0}, 'optimization': {'_name': None, 'max_epoch': 0, 'max_update': 20000, 'stop_time_hours': 0.0, 'clip_norm': 0.0, 'sentence_avg': True, 'update_freq': [4], 'lr': [5e-05], 'stop_min_lr': -1.0, 'use_bmuf': False}, 'checkpoint': {'_name': None, 'save_dir': 'checkpoints', 'restore_file': 'checkpoint_last.pt', 'finetune_from_model': None, 'reset_dataloader': False, 'reset_lr_scheduler': False, 'reset_meters': False, 'reset_optimizer': False, 'optimizer_overrides': '{}', 'save_interval': 50, 'save_interval_updates': 10000, 'keep_interval_updates': 1, 'keep_last_epochs': -1, 'keep_best_checkpoints': -1, 'no_save': False, 'no_epoch_checkpoints': True, 'no_last_checkpoints': False, 'no_save_optimizer_state': False, 'best_checkpoint_metric': 'wer', 'maximize_best_checkpoint_metric': False, 'patience': -1, 'checkpoint_suffix': '', 'checkpoint_shard_count': 1, 'load_checkpoint_on_all_dp_ranks': False, 'model_parallel_size': 1, 'distributed_rank': 0}, 'bmuf': {'_name': None, 'block_lr': 1.0, 'block_momentum': 0.875, 'global_sync_iter': 50, 'warmup_iterations': 500, 'use_nbm': False, 'average_sync': False, 'distributed_world_size': 2}, 'generation': {'_name': None, 'beam': 5, 'nbest': 1, 'max_len_a': 0.0, 'max_len_b': 200, 'min_len': 1, 'match_source_len': False, 'unnormalized': False, 'no_early_stop': False, 'no_beamable_mm': False, 'lenpen': 1.0, 'unkpen': 0.0, 'replace_unk': None, 'sacrebleu': False, 'score_reference': False, 'prefix_size': 0, 'no_repeat_ngram_size': 0, 'sampling': False, 'sampling_topk': -1, 'sampling_topp': -1.0, 'constraints': None, 'temperature': 1.0, 'diverse_beam_groups': -1, 'diverse_beam_strength': 0.5, 'diversity_rate': -1.0, 'print_alignment': None, 'print_step': False, 'lm_path': None, 'lm_weight': 0.0, 'iter_decode_eos_penalty': 0.0, 'iter_decode_max_iter': 10, 'iter_decode_force_max_iter': False, 'iter_decode_with_beam': 1, 'iter_decode_with_external_reranker': False, 'retain_iter_history': False, 'retain_dropout': False, 'retain_dropout_modules': None, 'decoding_format': None, 'no_seed_provided': False}, 'eval_lm': {'_name': None, 'output_word_probs': False, 'output_word_stats': False, 'context_window': 0, 'softmax_batch': 9223372036854775807}, 'interactive': {'_name': None, 'buffer_size': 0, 'input': '-'}, 'model': {'_name': 'wav2vec_ctc', 'w2v_path': '/private/home/abaevski/models/wav2vec2/wav2vec_small.pt', 'apply_mask': True, 'mask_prob': 0.65, 'mask_channel_prob': 0.5, 'mask_channel_length': 64, 'layerdrop': 0.05, 'activation_dropout': 0.1, 'feature_grad_mult': 0.0, 'freeze_finetune_updates': 10000}, 'task': {'_name': 'audio_pretraining', 'data': '/checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw', 'normalize': False, 'labels': 'ltr'}, 'criterion': {'_name': 'ctc', 'zero_infinity': True}, 'optimizer': {'_name': 'adam', 'adam_betas': '(0.9,0.98)', 'adam_eps': 1e-08}, 'lr_scheduler': {'_name': 'tri_stage', 'phase_ratio': [0.1, 0.4, 0.5], 'final_lr_scale': 0.05}, 'scoring': None, 'bpe': None, 'tokenizer': None} ``` after: ``` {'_name': None, 'common': {'_name': None, 'no_progress_bar': False, 'log_interval': 200, 'log_format': 'json', 'tensorboard_logdir': None, 'wandb_project': None, 'azureml_logging': False, 'seed': 1, 'cpu': False, 'tpu': False, 'bf16': False, 'memory_efficient_bf16': False, 'fp16': True, 'memory_efficient_fp16': False, 'fp16_no_flatten_grads': False, 'fp16_init_scale': 128, 'fp16_scale_window': None, 'fp16_scale_tolerance': 0.0, 'min_loss_scale': 0.0001, 'threshold_loss_scale': None, 'user_dir': None, 'empty_cache_freq': 0, 'all_gather_list_size': 16384, 'model_parallel_size': 1, 'quantization_config_path': None, 'profile': False, 'reset_logging': True, 'suppress_crashes': False}, 'common_eval': {'_name': None, 'path': None, 'post_process': None, 'quiet': False, 'model_overrides': '{}', 'results_path': None}, 'distributed_training': {'_name': None, 'distributed_world_size': 2, 'distributed_rank': 0, 'distributed_backend': 'nccl', 'distributed_init_method': 'tcp://localhost:16054', 'distributed_port': -1, 'device_id': 0, 'distributed_no_spawn': False, 'ddp_backend': 'no_c10d', 'bucket_cap_mb': 25, 'fix_batches_to_gpus': False, 'find_unused_parameters': False, 'fast_stat_sync': False, 'heartbeat_timeout': -1, 'broadcast_buffers': False, 'distributed_wrapper': 'DDP', 'slowmo_momentum': None, 'slowmo_algorithm': 'LocalSGD', 'localsgd_frequency': 3, 'nprocs_per_node': 2, 'pipeline_model_parallel': False, 'pipeline_balance': None, 'pipeline_devices': None, 'pipeline_chunks': 0, 'pipeline_encoder_balance': None, 'pipeline_encoder_devices': None, 'pipeline_decoder_balance': None, 'pipeline_decoder_devices': None, 'pipeline_checkpoint': 'never', 'zero_sharding': 'none', 'tpu': False, 'distributed_num_procs': 2}, 'dataset': {'_name': None, 'num_workers': 6, 'skip_invalid_size_inputs_valid_test': True, 'max_tokens': 3200000, 'batch_size': None, 'required_batch_size_multiple': 8, 'required_seq_len_multiple': 1, 'dataset_impl': None, 'data_buffer_size': 10, 'train_subset': 'train', 'valid_subset': 'dev_other', 'validate_interval': 50, 'validate_interval_updates': 0, 'validate_after_updates': 0, 'fixed_validation_seed': None, 'disable_validation': False, 'max_tokens_valid': 3200000, 'batch_size_valid': None, 'curriculum': 0, 'gen_subset': 'test', 'num_shards': 1, 'shard_id': 0}, 'optimization': {'_name': None, 'max_epoch': 0, 'max_update': 20000, 'stop_time_hours': 0.0, 'clip_norm': 0.0, 'sentence_avg': True, 'update_freq': [4], 'lr': [5e-05], 'stop_min_lr': -1.0, 'use_bmuf': False}, 'checkpoint': {'_name': None, 'save_dir': 'checkpoints', 'restore_file': 'checkpoint_last.pt', 'finetune_from_model': None, 'reset_dataloader': False, 'reset_lr_scheduler': False, 'reset_meters': False, 'reset_optimizer': False, 'optimizer_overrides': '{}', 'save_interval': 50, 'save_interval_updates': 20, 'keep_interval_updates': 1, 'keep_last_epochs': -1, 'keep_best_checkpoints': -1, 'no_save': False, 'no_epoch_checkpoints': True, 'no_last_checkpoints': False, 'no_save_optimizer_state': False, 'best_checkpoint_metric': 'wer', 'maximize_best_checkpoint_metric': False, 'patience': -1, 'checkpoint_suffix': '', 'checkpoint_shard_count': 1, 'load_checkpoint_on_all_dp_ranks': False, 'model_parallel_size': 1, 'distributed_rank': 0}, 'bmuf': {'_name': None, 'block_lr': 1.0, 'block_momentum': 0.875, 'global_sync_iter': 50, 'warmup_iterations': 500, 'use_nbm': False, 'average_sync': False, 'distributed_world_size': 2}, 'generation': {'_name': None, 'beam': 5, 'nbest': 1, 'max_len_a': 0.0, 'max_len_b': 200, 'min_len': 1, 'match_source_len': False, 'unnormalized': False, 'no_early_stop': False, 'no_beamable_mm': False, 'lenpen': 1.0, 'unkpen': 0.0, 'replace_unk': None, 'sacrebleu': False, 'score_reference': False, 'prefix_size': 0, 'no_repeat_ngram_size': 0, 'sampling': False, 'sampling_topk': -1, 'sampling_topp': -1.0, 'constraints': None, 'temperature': 1.0, 'diverse_beam_groups': -1, 'diverse_beam_strength': 0.5, 'diversity_rate': -1.0, 'print_alignment': None, 'print_step': False, 'lm_path': None, 'lm_weight': 0.0, 'iter_decode_eos_penalty': 0.0, 'iter_decode_max_iter': 10, 'iter_decode_force_max_iter': False, 'iter_decode_with_beam': 1, 'iter_decode_with_external_reranker': False, 'retain_iter_history': False, 'retain_dropout': False, 'retain_dropout_modules': None, 'decoding_format': None, 'no_seed_provided': False}, 'eval_lm': {'_name': None, 'output_word_probs': False, 'output_word_stats': False, 'context_window': 0, 'softmax_batch': 9223372036854775807}, 'interactive': {'_name': None, 'buffer_size': 0, 'input': '-'}, 'model': {'_name': 'wav2vec_ctc', 'w2v_path': '/private/home/abaevski/models/wav2vec2/wav2vec_small.pt', 'no_pretrained_weights': False, 'dropout_input': 0.0, 'final_dropout': 0.0, 'dropout': 0.0, 'attention_dropout': 0.0, 'activation_dropout': 0.1, 'apply_mask': True, 'mask_length': 10, 'mask_prob': 0.65, 'mask_selection': 'static', 'mask_other': 0.0, 'no_mask_overlap': False, 'mask_channel_length': 64, 'mask_channel_prob': 0.5, 'mask_channel_selection': 'static', 'mask_channel_other': 0.0, 'no_mask_channel_overlap': False, 'freeze_finetune_updates': 0, 'feature_grad_mult': 0.0, 'layerdrop': 0.05, 'normalize': False, 'data': '/checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw', 'w2v_args': None}, 'task': {'_name': 'audio_pretraining', 'data': '/checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw', 'labels': 'ltr', 'sample_rate': 16000, 'normalize': False, 'enable_padding': False, 'max_sample_size': None, 'min_sample_size': None, 'eval_wer': False, 'eval_wer_config': {'_name': None, 'beam': 5, 'nbest': 1, 'max_len_a': 0.0, 'max_len_b': 200, 'min_len': 1, 'match_source_len': False, 'unnormalized': False, 'no_early_stop': False, 'no_beamable_mm': False, 'lenpen': 1.0, 'unkpen': 0.0, 'replace_unk': None, 'sacrebleu': False, 'score_reference': False, 'prefix_size': 0, 'no_repeat_ngram_size': 0, 'sampling': False, 'sampling_topk': -1, 'sampling_topp': -1.0, 'constraints': None, 'temperature': 1.0, 'diverse_beam_groups': -1, 'diverse_beam_strength': 0.5, 'diversity_rate': -1.0, 'print_alignment': None, 'print_step': False, 'lm_path': None, 'lm_weight': 0.0, 'iter_decode_eos_penalty': 0.0, 'iter_decode_max_iter': 10, 'iter_decode_force_max_iter': False, 'iter_decode_with_beam': 1, 'iter_decode_with_external_reranker': False, 'retain_iter_history': False, 'retain_dropout': False, 'retain_dropout_modules': None, 'decoding_format': None, 'no_seed_provided': False}, 'eval_wer_tokenizer': None, 'eval_wer_post_process': 'letter', 'autoregressive': False}, 'criterion': {'_name': 'ctc', 'zero_infinity': True, 'sentence_avg': True, 'post_process': 'letter', 'wer_kenlm_model': None, 'wer_lexicon': None, 'wer_lm_weight': 2.0, 'wer_word_score': -1.0, 'wer_args': None}, 'optimizer': {'_name': 'adam', 'adam_betas': '(0.9,0.98)', 'adam_eps': 1e-08, 'weight_decay': 0.0, 'use_old_adam': False, 'tpu': False, 'lr': [5e-05]}, 'lr_scheduler': {'_name': 'tri_stage', 'warmup_steps': 0, 'hold_steps': 0, 'decay_steps': 0, 'phase_ratio': [0.1, 0.4, 0.5], 'init_lr_scale': 0.01, 'final_lr_scale': 0.05, 'max_update': 20000, 'lr': [5e-05]}, 'scoring': None, 'bpe': None, 'tokenizer': None} ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1564 Reviewed By: myleott Differential Revision: D25938221 Pulled By: alexeib fbshipit-source-id: e088667accf974ad6d9898a63f7c33722837fcfb --- fairseq/dataclass/initialize.py | 34 ++++++++++++++++++++++++++++++++- fairseq_cli/hydra_train.py | 4 ++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index 7a1ebeff1c..385624f19b 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -5,9 +5,9 @@ """isort:skip_file""" import logging -from typing import Dict, Any from hydra.core.config_store import ConfigStore from fairseq.dataclass.configs import FairseqConfig +from omegaconf import DictConfig, open_dict logger = logging.getLogger(__name__) @@ -25,3 +25,35 @@ def hydra_init(cfg_name="config") -> None: except BaseException: logger.error(f"{k} - {v}") raise + + +def add_defaults(cfg: DictConfig) -> None: + """This function adds default values that are stored in dataclasses that hydra doesn't know about """ + + from fairseq.registry import REGISTRIES + from fairseq.tasks import TASK_DATACLASS_REGISTRY + from fairseq.models import ARCH_MODEL_NAME_REGISTRY, MODEL_DATACLASS_REGISTRY + from fairseq.dataclass.utils import merge_with_parent + from typing import Any + + for k, v in FairseqConfig.__dataclass_fields__.items(): + field_cfg = cfg.get(k) + if field_cfg is not None and v.type == Any: + dc = None + + if isinstance(field_cfg, str): + field_cfg = DictConfig({"_name": field_cfg}) + field_cfg.__dict__["_parent"] = field_cfg.__dict__["_parent"] + + name = field_cfg.get("_name") + + if k == "task": + dc = TASK_DATACLASS_REGISTRY.get(name) + elif k == "model": + name = ARCH_MODEL_NAME_REGISTRY.get(name, name) + dc = MODEL_DATACLASS_REGISTRY.get(name) + elif k in REGISTRIES: + dc = REGISTRIES[k]["dataclass_registry"].get(name) + + if dc is not None: + cfg[k] = merge_with_parent(dc, field_cfg) diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index cf48337462..6754f9483d 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -8,7 +8,7 @@ import os import sys -from fairseq.dataclass.initialize import hydra_init +from fairseq.dataclass.initialize import add_defaults, hydra_init from fairseq_cli.train import main as pre_main from fairseq import distributed_utils, metrics from fairseq.dataclass.configs import FairseqConfig @@ -23,8 +23,8 @@ @hydra.main(config_path=os.path.join("..", "fairseq", "config"), config_name="config") def hydra_main(cfg: FairseqConfig) -> float: + add_defaults(cfg) cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) - OmegaConf.set_struct(cfg, True) if cfg.common.reset_logging: From 1e21f7e462e53a3bf2f881632f15548ddaa43464 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Tue, 19 Jan 2021 19:10:05 -0800 Subject: [PATCH 160/774] track loaded lines in raw_audio_dataset and load corresponding labels in audio_pretraining (#1566) Summary: Bug: `AudioPretrainingTask` is not aware of what samples have been skipped by `FileAudioDataset`, and hence would load labels of utterances that were skipped, causing `AddTargetDataset` to misalign utterances with labels. This PR tracks line line indices loaded by the `FileAudioDataset` to filter labels correspondingly in `AudioPretrainingTask` Before: ``` INFO:__main__:| decoding with criterion ctc INFO:__main__:| loading model(s) from ... INFO:fairseq.data.audio.raw_audio_dataset:loaded 284, skipped 223 samples INFO:__main__:| /private/home/wnhsu/wav2vec2_robust/data/joint_swbd ted_dev 284 examples INFO:__main__:WER: 152.15605749486653 INFO:__main__:| Processed 284 sentences (72405 tokens) in 20.5s (13.88sentences/s, 3538.01 tokens/s) ``` After ``` INFO:__main__:| decoding with criterion ctc INFO:__main__:| loading model(s) from ... INFO:fairseq.data.audio.raw_audio_dataset:loaded 284, skipped 223 samples INFO:__main__:WER: 9.904153354632587 INFO:__main__:| Processed 284 sentences (72405 tokens) in 20.7s (13.70sentences/s, 3492.20 tokens/s) ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1566 Reviewed By: alexeib Differential Revision: D25963317 Pulled By: wnhsu fbshipit-source-id: c9748f5dad1ff787642ba0bc28698c4ecfbcd221 --- fairseq/data/audio/raw_audio_dataset.py | 4 +++- fairseq/tasks/audio_pretraining.py | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 8d6ce85ecc..ac5acd03bb 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -153,11 +153,12 @@ def __init__( ) self.fnames = [] + self.line_inds = set() skipped = 0 with open(manifest_path, "r") as f: self.root_dir = f.readline().strip() - for line in f: + for i, line in enumerate(f): items = line.strip().split("\t") assert len(items) == 2, line sz = int(items[1]) @@ -165,6 +166,7 @@ def __init__( skipped += 1 continue self.fnames.append(items[0]) + self.line_inds.add(i) self.sizes.append(sz) logger.info(f"loaded {len(self.fnames)}, skipped {skipped} samples") diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 6ea40a813f..7c82777331 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -148,8 +148,14 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") labels = [] with open(label_path, "r") as f: - for line in f: - labels.append(line) + labels = [ + line for i, line in enumerate(f) + if i in self.datasets[split].line_inds + ] + + assert len(labels) == len(self.datasets[split]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.datasets[split])}) do not match") process_label = LabelEncoder(self.target_dictionary) From bf54551cafa13678c0254d2c20354cc026cc0bac Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 20 Jan 2021 05:49:22 -0800 Subject: [PATCH 161/774] Fix param sharing in Linformer (#1561) Summary: Parameter sharing (both `--untie-weights-roberta` and `--shared-layer-kv-compressed`) was broken by one of my earlier refactors (D22411012 (https://github.com/pytorch/fairseq/commit/d73e543e3853bb813d8f7955a06ce19359810707)). This fixes it. Note: it was correct in the original version of the code for the paper. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1561 Test Plan: - confirmed that training gives identical losses as before when not using any param sharing (including `--untie-weights-roberta`): ``` CUDA_VISIBLE_DEVICES=0 python train.py --task dummy_masked_lm --arch linformer_roberta_base --untie-weights-roberta --user-dir examples/linformer/linformer_src/ --criterion masked_lm --batch-size 8 --optimizer adam --lr 0.0001 --log-format json --log-interval 1 --max-update 5 --disable-validation --no-save before: 2021-01-19 06:37:21 | INFO | fairseq_cli.train | num. model params: 164,465,744 (num. trained: 164,465,744) (...) 2021-01-19 06:41:56 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "15.893", "ppl": "60870.7", "wps": "0", "ups": "0", "wpb": "4096", "bsz": "8", "num_updates": "1", "lr": "0.0001", "gnorm": "7.716", "train_wall": "1", "wall": "1"} 2021-01-19 06:41:56 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "13.176", "ppl": "9252.9", "wps": "11813.8", "ups": "2.88", "wpb": "4096", "bsz": "8", "num_updates": "2", "lr": "0.0001", "gnorm": "6.988", "train_wall": "0", "wall": "1"} 2021-01-19 06:41:57 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "11.049", "ppl": "2119.22", "wps": "12002.2", "ups": "2.93", "wpb": "4096", "bsz": "8", "num_updates": "3", "lr": "0.0001", "gnorm": "8.008", "train_wall": "0", "wall": "1"} 2021-01-19 06:41:57 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "9.044", "ppl": "527.7", "wps": "11894.2", "ups": "2.9", "wpb": "4096", "bsz": "8", "num_updates": "4", "lr": "0.0001", "gnorm": "7.893", "train_wall": "0", "wall": "2"} 2021-01-19 06:41:57 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "7.526", "ppl": "184.27", "wps": "11834.9", "ups": "2.89", "wpb": "4096", "bsz": "8", "num_updates": "5", "lr": "0.0001", "gnorm": "6.949", "train_wall": "0", "wall": "2"} after: 2021-01-19 06:39:20 | INFO | fairseq_cli.train | num. model params: 164,465,744 (num. trained: 164,465,744) (...) 2021-01-19 06:39:22 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "15.893", "ppl": "60870.7", "wps": "0", "ups": "0", "wpb": "4096", "bsz": "8", "num_updates": "1", "lr": "0.0001", "gnorm": "7.716", "train_wall": "1", "wall": "1"} 2021-01-19 06:39:23 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "13.176", "ppl": "9252.9", "wps": "12094.7", "ups": "2.95", "wpb": "4096", "bsz": "8", "num_updates": "2", "lr": "0.0001", "gnorm": "6.988", "train_wall": "0", "wall": "1"} 2021-01-19 06:39:23 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "11.049", "ppl": "2119.22", "wps": "12290", "ups": "3", "wpb": "4096", "bsz": "8", "num_updates": "3", "lr": "0.0001", "gnorm": "8.008", "train_wall": "0", "wall": "1"} 2021-01-19 06:39:23 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "9.044", "ppl": "527.7", "wps": "11990.4", "ups": "2.93", "wpb": "4096", "bsz": "8", "num_updates": "4", "lr": "0.0001", "gnorm": "7.893", "train_wall": "0", "wall": "2"} 2021-01-19 06:39:24 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "7.526", "ppl": "184.27", "wps": "12073.8", "ups": "2.95", "wpb": "4096", "bsz": "8", "num_updates": "5", "lr": "0.0001", "gnorm": "6.949", "train_wall": "0", "wall": "2"} ``` - with input embedding and output LM head param sharing, the `num. model params` now goes down (as expected), whereas before it stayed constant: ``` CUDA_VISIBLE_DEVICES=0 python train.py --task dummy_masked_lm --arch linformer_roberta_base --user-dir examples/linformer/linformer_src/ --criterion masked_lm --batch-size 8 --optimizer adam --lr 0.0001 --log-format json --log-interval 1 --max-update 5 --disable-validation --no-save before: 2021-01-19 06:44:58 | INFO | fairseq_cli.train | num. model params: 164,465,744 (num. trained: 164,465,744) (...) after: 2021-01-19 06:43:03 | INFO | fairseq_cli.train | num. model params: 126,065,744 (num. trained: 126,065,744) (...) ``` - confirmed that old checkpoints can be loaded and produce identical valid ppl: ``` python -m fairseq_cli.validate --path $MODEL --user-dir examples/linformer/linformer_src/ --task dummy_masked_lm --criterion masked_lm --max-sentences 8 --dataset-size 100 no sharing: before: 2021-01-19 07:07:54 | INFO | valid | | valid on 'valid' subset | loss 5.485 | ppl 44.8 | wps 0 | wpb 53248 | bsz 104 after: 2021-01-19 07:30:10 | INFO | valid | | valid on 'valid' subset | loss 5.485 | ppl 44.8 | wps 0 | wpb 53248 | bsz 104 shared_kv_compressed: before: 2021-01-19 07:08:50 | INFO | valid | | valid on 'valid' subset | loss 5.355 | ppl 40.94 | wps 0 | wpb 53248 | bsz 104 after: 2021-01-19 07:30:45 | INFO | valid | | valid on 'valid' subset | loss 5.355 | ppl 40.94 | wps 0 | wpb 53248 | bsz 104 shared_kv_compressed + shared_layer_kv_compressed: before: 2021-01-19 07:09:26 | INFO | valid | | valid on 'valid' subset | loss 5.482 | ppl 44.7 | wps 0 | wpb 53248 | bsz 104 after: 2021-01-19 08:09:36 | INFO | valid | | valid on 'valid' subset | loss 5.482 | ppl 44.7 | wps 0 | wpb 53248 | bsz 104 using a really old checkpoint with sharing (trained on commit cf4219b048d31f55970356520860b2543ee97570): before: | valid on 'valid' subset | loss 5.548 | ppl 46.8 | wps 0 | wpb 53248 | bsz 104 after: 2021-01-19 08:34:07 | INFO | valid | | valid on 'valid' subset | loss 5.548 | ppl 46.8 | wps 0 | wpb 53248 | bsz 104 ``` Reviewed By: madian9 Differential Revision: D25938236 Pulled By: myleott fbshipit-source-id: 4d515e5c8e0601476856ae27eb46c64c30033c88 --- .../linformer_src/models/linformer_roberta.py | 28 ++++++++++++- .../modules/linformer_sentence_encoder.py | 2 +- .../linformer_sentence_encoder_layer.py | 42 ++++++++++++++++--- fairseq/models/fairseq_decoder.py | 4 +- fairseq/models/fairseq_encoder.py | 4 +- fairseq/models/roberta/model.py | 28 ++++++++----- fairseq/modules/transformer_layer.py | 1 + .../transformer_sentence_encoder_layer.py | 5 +++ 8 files changed, 92 insertions(+), 22 deletions(-) diff --git a/examples/linformer/linformer_src/models/linformer_roberta.py b/examples/linformer/linformer_src/models/linformer_roberta.py index 913351f238..be5d8e85ec 100644 --- a/examples/linformer/linformer_src/models/linformer_roberta.py +++ b/examples/linformer/linformer_src/models/linformer_roberta.py @@ -8,6 +8,8 @@ import logging +import torch +from fairseq import utils from fairseq.models import register_model, register_model_architecture from fairseq.models.roberta import RobertaEncoder, RobertaModel @@ -62,8 +64,10 @@ class LinformerEncoder(RobertaEncoder): def __init__(self, args, dictionary): super().__init__(args, dictionary) + self.register_buffer("version", torch.tensor(2)) - self.sentence_encoder = LinformerSentenceEncoder( + def build_encoder(self, args, dictionary): + return LinformerSentenceEncoder( padding_idx=dictionary.pad(), vocab_size=len(dictionary), num_encoder_layers=args.encoder_layers, @@ -87,6 +91,27 @@ def __init__(self, args, dictionary): freeze_compress=args.freeze_compress, ) + def upgrade_state_dict_named(self, state_dict, name): + super().upgrade_state_dict_named(state_dict, name) + prefix = name + "." if name != "" else "" + + # some old checkpoints had weight sharing implemented incorrectly + # (note: this was correct in the original paper code) + if utils.item(state_dict.get(f"{prefix}version", torch.tensor(1))) < 2: + state_dict[f"{prefix}version"] = torch.tensor(1) + # check if input embeddings and output embeddings were tied + if not torch.allclose( + state_dict[f"{prefix}sentence_encoder.embed_tokens.weight"], + state_dict[f"{prefix}lm_head.weight"], + ): + # they weren't tied, re-init the LM head without weight sharing + self.lm_head = self.build_lm_head( + embed_dim=self.args.encoder_embed_dim, + output_dim=len(self.dictionary), + activation_fn=self.args.activation_fn, + weight=None, # don't share weights + ) + @register_model_architecture("linformer_roberta", "linformer_roberta") def base_architecture(args): @@ -104,6 +129,7 @@ def base_architecture(args): args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) + args.compressed = getattr(args, "compressed", 4) args.shared_kv_compressed = getattr(args, "shared_kv_compressed", 0) args.shared_layer_kv_compressed = getattr(args, "shared_layer_kv_compressed", 0) diff --git a/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py b/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py index d6de9eeaae..3cdca01235 100644 --- a/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py +++ b/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py @@ -116,7 +116,7 @@ def build_transformer_sentence_encoder_layer( q_noise, qn_block_size, ): - if self.shared_layer_kv_compressed == 1: + if self.shared_layer_kv_compressed == 1 and self.compress_layer is None: compress_layer = nn.Linear( self.max_seq_len, self.max_seq_len // self.compressed ) diff --git a/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py b/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py index d27c5afd09..0b80fabefe 100644 --- a/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py +++ b/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py @@ -5,6 +5,8 @@ from typing import Callable +import torch +from fairseq import utils from fairseq.modules import TransformerSentenceEncoderLayer from .multihead_linear_attention import MultiheadLinearAttention @@ -42,9 +44,8 @@ def __init__( self.shared_kv_compressed = shared_kv_compressed self.freeze_compress = freeze_compress - def init_fn(): - # This needs to be set after nn.Module.__init__ is called - self.shared_compress_layer = shared_compress_layer + # wrap in a list so it's not automatically registered by PyTorch + self.shared_compress_layer = [shared_compress_layer] super().__init__( embedding_dim=embedding_dim, @@ -57,8 +58,8 @@ def init_fn(): export=export, q_noise=q_noise, qn_block_size=qn_block_size, - init_fn=init_fn, ) + self.register_buffer("version", torch.tensor(2)) def build_self_attention( self, @@ -79,6 +80,37 @@ def build_self_attention( compressed=self.compressed, max_seq_len=self.max_seq_len, shared_kv_compressed=self.shared_kv_compressed, - shared_compress_layer=self.shared_compress_layer, + shared_compress_layer=self.shared_compress_layer[0], freeze_compress=self.freeze_compress, ) + + def upgrade_state_dict_named(self, state_dict, name): + prefix = name + "." if name != "" else "" + + # some old checkpoints had weight sharing implemented incorrectly + # (note: this was correct in the original paper code) + if utils.item(state_dict.get(f"{prefix}version", torch.tensor(1))) < 2: + state_dict[f"{prefix}version"] = torch.tensor(1) + # check compression layer sharing + if f"{prefix}shared_compress_layer.weight" in state_dict: + # reinitialize block without sharing compression layer to match + # old behavior + self.shared_compress_layer = [ + torch.nn.Linear( + self.shared_compress_layer[0].weight.size(1), + self.shared_compress_layer[0].weight.size(0), + ) + ] + self.self_attn = self.build_self_attention( + self.embedding_dim, + self.num_attention_heads, + dropout=self.attention_dropout, + self_attention=True, + q_noise=self.q_noise, + qn_block_size=self.qn_block_size, + ) + # delete shared_compress_layer, since it's already copied to + # self_attn.compress_k.weight + del state_dict[f"{prefix}shared_compress_layer.weight"] + if f"{prefix}shared_compress_layer.bias" in state_dict: + del state_dict[f"{prefix}shared_compress_layer.bias"] diff --git a/fairseq/models/fairseq_decoder.py b/fairseq/models/fairseq_decoder.py index fb6c52dc7f..35a349fa5f 100644 --- a/fairseq/models/fairseq_decoder.py +++ b/fairseq/models/fairseq_decoder.py @@ -82,8 +82,8 @@ def max_positions(self): """Maximum input length supported by the decoder.""" return 1e6 # an arbitrary large number - def upgrade_state_dict(self, state_dict): - """Upgrade a (possibly old) state dict for new versions of fairseq.""" + def upgrade_state_dict_named(self, state_dict, name): + """Upgrade old state dicts to work with newer code.""" return state_dict def prepare_for_onnx_export_(self): diff --git a/fairseq/models/fairseq_encoder.py b/fairseq/models/fairseq_encoder.py index c8873daa28..08cbde15a4 100644 --- a/fairseq/models/fairseq_encoder.py +++ b/fairseq/models/fairseq_encoder.py @@ -78,8 +78,8 @@ def max_positions(self): """Maximum input length supported by the encoder.""" return 1e6 # an arbitrary large number - def upgrade_state_dict(self, state_dict): - """Upgrade a (possibly old) state dict for new versions of fairseq.""" + def upgrade_state_dict_named(self, state_dict, name): + """Upgrade old state dicts to work with newer code.""" return state_dict def set_num_updates(self, num_updates): diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 96a7b9c8a2..00a5a5485f 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -401,7 +401,21 @@ def __init__(self, args, dictionary): if args.encoder_layers_to_keep: args.encoder_layers = len(args.encoder_layers_to_keep.split(",")) - self.sentence_encoder = TransformerSentenceEncoder( + self.sentence_encoder = self.build_encoder(args, dictionary) + + self.lm_head = self.build_lm_head( + embed_dim=args.encoder_embed_dim, + output_dim=len(dictionary), + activation_fn=args.activation_fn, + weight=( + self.sentence_encoder.embed_tokens.weight + if not args.untie_weights_roberta + else None + ), + ) + + def build_encoder(self, args, dictionary): + return TransformerSentenceEncoder( padding_idx=dictionary.pad(), vocab_size=len(dictionary), num_encoder_layers=args.encoder_layers, @@ -421,16 +435,8 @@ def __init__(self, args, dictionary): qn_block_size=args.quant_noise_pq_block_size, ) - self.lm_head = RobertaLMHead( - embed_dim=args.encoder_embed_dim, - output_dim=len(dictionary), - activation_fn=args.activation_fn, - weight=( - self.sentence_encoder.embed_tokens.weight - if not args.untie_weights_roberta - else None - ), - ) + def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): + return RobertaLMHead(embed_dim, output_dim, activation_fn, weight) def forward( self, diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 6f3c79de7c..03e70f4279 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -31,6 +31,7 @@ class TransformerEncoderLayer(nn.Module): def __init__(self, args): super().__init__() + self.args = args self.embed_dim = args.encoder_embed_dim self.quant_noise = getattr(args, 'quant_noise_pq', 0) self.quant_noise_block_size = getattr(args, 'quant_noise_pq_block_size', 8) or 8 diff --git a/fairseq/modules/transformer_sentence_encoder_layer.py b/fairseq/modules/transformer_sentence_encoder_layer.py index 3589c60fe6..f869c4b2f8 100644 --- a/fairseq/modules/transformer_sentence_encoder_layer.py +++ b/fairseq/modules/transformer_sentence_encoder_layer.py @@ -40,6 +40,11 @@ def __init__( # Initialize parameters self.embedding_dim = embedding_dim + self.num_attention_heads = num_attention_heads + self.attention_dropout = attention_dropout + self.q_noise = q_noise + self.qn_block_size = qn_block_size + self.dropout_module = FairseqDropout( dropout, module_name=self.__class__.__name__ ) From 338aa57966b11a31120e87840d6bb68e74257182 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 20 Jan 2021 07:37:50 -0800 Subject: [PATCH 162/774] Add test for activation checkpointing (#1563) Summary: Forgot to merge this with the original code Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1563 Reviewed By: sshleifer Differential Revision: D25948393 Pulled By: myleott fbshipit-source-id: b083001015e97f7e21cfa02d4126eba79cc34bfa --- tests/test_activation_checkpointing.py | 72 ++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/test_activation_checkpointing.py diff --git a/tests/test_activation_checkpointing.py b/tests/test_activation_checkpointing.py new file mode 100644 index 0000000000..4b86211bde --- /dev/null +++ b/tests/test_activation_checkpointing.py @@ -0,0 +1,72 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import torch +import torch.nn as nn +from fairseq.modules.checkpoint_activations import checkpoint_wrapper +from torch.utils.checkpoint import checkpoint + + +class Model(nn.Module): + def __init__(self, use_pytorch_checkpoint=False, use_fairseq_checkpoint=False): + super().__init__() + torch.manual_seed(0) + self.use_pytorch_checkpoint = use_pytorch_checkpoint + self.ffn = nn.Sequential( + nn.Linear(32, 128), + # add a Dropout layer to test RNG save/restore + nn.Dropout(p=0.5), + nn.Linear(128, 32), + ) + if use_fairseq_checkpoint: + self.ffn = checkpoint_wrapper(self.ffn) + self.out = nn.Linear(32, 1) + + def forward(self, x): + if self.use_pytorch_checkpoint: + x = checkpoint(self.ffn, x) + else: + x = self.ffn(x) + return self.out(x) + + +class TestActivationCheckpointing(unittest.TestCase): + def _test_checkpoint_wrapper(self, device, log_memory_usage=False): + def get_loss_and_gnorm(model): + torch.manual_seed(1) + input = torch.rand(2, 16, 32).requires_grad_(True).to(device) + model.zero_grad() + loss = model(input).sum() + loss.backward() + gnorm = torch.norm( + torch.stack([torch.norm(p.grad.detach()) for p in model.parameters()]) + ) + return {"loss": loss, "gnorm": gnorm} + + model = Model().to(device) + no_cpt = get_loss_and_gnorm(model) + + model = Model(use_pytorch_checkpoint=True).to(device) + pyt_cpt = get_loss_and_gnorm(model) + torch.testing.assert_allclose(no_cpt["loss"], pyt_cpt["loss"]) + torch.testing.assert_allclose(no_cpt["gnorm"], pyt_cpt["gnorm"]) + + model = Model(use_fairseq_checkpoint=True).to(device) + fairseq_cpt = get_loss_and_gnorm(model) + torch.testing.assert_allclose(no_cpt["loss"], fairseq_cpt["loss"]) + torch.testing.assert_allclose(no_cpt["gnorm"], fairseq_cpt["gnorm"]) + + def test_checkpoint_wrapper_cpu(self): + self._test_checkpoint_wrapper(device=torch.device("cpu")) + + @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") + def test_checkpoint_wrapper_cuda(self): + self._test_checkpoint_wrapper(device=torch.device("cuda")) + + +if __name__ == "__main__": + unittest.main() From 9fc53d62177b8465b1eca2dd00185540dcd2fb92 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 20 Jan 2021 10:46:20 -0800 Subject: [PATCH 163/774] Support --post-process="@@" (#1571) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1571 Differential Revision: D25974834 Pulled By: myleott fbshipit-source-id: 8cf4c4874087408f76d9d47a6b5bee46c52ac33b --- fairseq/data/data_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 9a0580977d..d98c58a2f4 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -363,8 +363,10 @@ def post_process(sentence: str, symbol: str): sentence = sentence.replace(" ", "").replace("|", " ").strip() elif symbol == "_EOW": sentence = sentence.replace(" ", "").replace("_EOW", " ").strip() - elif symbol in {"subword_nmt", "@@ "}: - sentence = (sentence + " ").replace("@@ ", "").rstrip() + elif symbol in {"subword_nmt", "@@ ", "@@"}: + if symbol == "subword_nmt": + symbol = "@@ " + sentence = (sentence + " ").replace(symbol, "").rstrip() elif symbol == "none": pass elif symbol is not None: From 15867e12841cf16b3e6a60d5efccc169f728b70a Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Wed, 20 Jan 2021 17:59:39 -0800 Subject: [PATCH 164/774] migrate translation task (#1569) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1569 Test Plan: Imported from OSS tests + ran ``` python fairseq_cli/train.py \  18:08:56 ~/data/iwslt14.de-en \ --arch transformer_iwslt_de_en --share-decoder-input-output-embed \ --optimizer adam --adam-betas '(0.9, 0.98)' --clip-norm 0.0 \ --lr 5e-4 --lr-scheduler inverse_sqrt --warmup-updates 4000 \ --dropout 0.3 --weight-decay 0.0001 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --max-tokens 4096 \ --eval-bleu \ --eval-bleu-args '{"beam": 5, "max_len_a": 1.2, "max_len_b": 10}' \ --eval-bleu-detok moses \ --eval-bleu-remove-bpe \ --eval-bleu-print-samples \ --best-checkpoint-metric bleu --maximize-best-checkpoint-metric ``` Reviewed By: myleott Differential Revision: D25967217 Pulled By: alexeib fbshipit-source-id: 808f3cb0939fa13e1e05f39bfa02a7fb0b152940 --- .../translation_moe_src/translation_moe.py | 107 +++++--- fairseq/tasks/translation.py | 253 ++++++++++-------- .../tasks/translation_from_pretrained_xlm.py | 12 +- fairseq/tasks/translation_lev.py | 54 ++-- tests/test_checkpoint_utils.py | 7 +- 5 files changed, 248 insertions(+), 185 deletions(-) diff --git a/examples/translation_moe/translation_moe_src/translation_moe.py b/examples/translation_moe/translation_moe_src/translation_moe.py index ae458aaad3..7f28c32dd6 100644 --- a/examples/translation_moe/translation_moe_src/translation_moe.py +++ b/examples/translation_moe/translation_moe_src/translation_moe.py @@ -3,16 +3,52 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass, field import torch +from omegaconf import II + from fairseq import metrics, utils +from fairseq.dataclass import ChoiceEnum from fairseq.tasks import register_task -from fairseq.tasks.translation import TranslationTask +from fairseq.tasks.translation import TranslationConfig, TranslationTask from .logsumexp_moe import LogSumExpMoE from .mean_pool_gating_network import MeanPoolGatingNetwork -@register_task("translation_moe") +METHOD_CHOICES = ChoiceEnum(["sMoElp", "sMoEup", "hMoElp", "hMoEup"]) + + +@dataclass +class TranslationMoEConfig(TranslationConfig): + method: METHOD_CHOICES = field( + default="hMoEup", + metadata={"help": "MoE method"}, + ) + num_experts: int = field( + default=3, + metadata={"help": "number of experts"}, + ) + mean_pool_gating_network: bool = field( + default=False, + metadata={"help": "use a simple mean-pooling gating network"}, + ) + mean_pool_gating_network_dropout: float = field( + default=0, + metadata={"help": "dropout for mean-pooling gating network"}, + ) + mean_pool_gating_network_encoder_dim: int = field( + default=0, + metadata={"help": "encoder output dim for mean-pooling gating network"}, + ) + gen_expert: int = field( + default=0, + metadata={"help": "which expert to use for generation"}, + ) + sentence_avg: bool = II("optimization.sentence_avg") + + +@register_task("translation_moe", dataclass=TranslationMoEConfig) class TranslationMoETask(TranslationTask): """ Translation task for Mixture of Experts (MoE) models. @@ -37,77 +73,60 @@ class TranslationMoETask(TranslationTask): :prog: """ - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - # fmt: off - TranslationTask.add_args(parser) - parser.add_argument('--method', default='hMoEup', - choices=['sMoElp', 'sMoEup', 'hMoElp', 'hMoEup']) - parser.add_argument('--num-experts', default=3, type=int, metavar='N', - help='number of experts') - parser.add_argument('--mean-pool-gating-network', action='store_true', - help='use a simple mean-pooling gating network') - parser.add_argument('--mean-pool-gating-network-dropout', type=float, - help='dropout for mean-pooling gating network') - parser.add_argument('--mean-pool-gating-network-encoder-dim', type=float, - help='encoder output dim for mean-pooling gating network') - parser.add_argument('--gen-expert', type=int, default=0, - help='which expert to use for generation') - # fmt: on - - def __init__(self, args, src_dict, tgt_dict): - if args.method == "sMoElp": + cfg: TranslationMoEConfig + + def __init__(self, cfg: TranslationMoEConfig, src_dict, tgt_dict): + if cfg.method == "sMoElp": # soft MoE with learned prior self.uniform_prior = False self.hard_selection = False - elif args.method == "sMoEup": + elif cfg.method == "sMoEup": # soft MoE with uniform prior self.uniform_prior = True self.hard_selection = False - elif args.method == "hMoElp": + elif cfg.method == "hMoElp": # hard MoE with learned prior self.uniform_prior = False self.hard_selection = True - elif args.method == "hMoEup": + elif cfg.method == "hMoEup": # hard MoE with uniform prior self.uniform_prior = True self.hard_selection = True # add indicator tokens for each expert - for i in range(args.num_experts): + for i in range(cfg.num_experts): # add to both dictionaries in case we're sharing embeddings src_dict.add_symbol("<expert_{}>".format(i)) tgt_dict.add_symbol("<expert_{}>".format(i)) - super().__init__(args, src_dict, tgt_dict) + super().__init__(cfg, src_dict, tgt_dict) - def build_model(self, args): + def build_model(self, cfg): from fairseq import models - model = models.build_model(args, self) + model = models.build_model(cfg, self) if not self.uniform_prior and not hasattr(model, "gating_network"): - if self.args.mean_pool_gating_network: - if getattr(args, "mean_pool_gating_network_encoder_dim", None): - encoder_dim = args.mean_pool_gating_network_encoder_dim - elif getattr(args, "encoder_embed_dim", None): + if self.cfg.mean_pool_gating_network: + if self.cfg.mean_pool_gating_network_encoder_dim > 0: + encoder_dim = self.cfg.mean_pool_gating_network_encoder_dim + elif getattr(cfg, "encoder_embed_dim", None): # assume that encoder_embed_dim is the encoder's output dimension - encoder_dim = args.encoder_embed_dim + encoder_dim = cfg.encoder_embed_dim else: raise ValueError( "Must specify --mean-pool-gating-network-encoder-dim" ) - if getattr(args, "mean_pool_gating_network_dropout", None): - dropout = args.mean_pool_gating_network_dropout - elif getattr(args, "dropout", None): - dropout = args.dropout + if self.cfg.mean_pool_gating_network_dropout > 0: + dropout = self.cfg.mean_pool_gating_network_dropout + elif getattr(cfg, "dropout", None): + dropout = cfg.dropout else: - raise ValueError("Must specify --mean-pool-gating-network-dropout") + raise ValueError("Must specify task.mean_pool_gating_network_dropout") model.gating_network = MeanPoolGatingNetwork( encoder_dim, - args.num_experts, + self.cfg.num_experts, dropout, ) else: @@ -125,7 +144,7 @@ def _get_loss(self, sample, model, criterion): criterion, "compute_loss" ), "translation_moe task requires the criterion to implement the compute_loss() method" - k = self.args.num_experts + k = self.cfg.num_experts bsz = sample["target"].size(0) def get_lprob_y(encoder_out, prev_output_tokens_k): @@ -185,7 +204,7 @@ def get_lprob_yz(winners=None): loss = loss.sum() sample_size = ( - sample["target"].size(0) if self.args.sentence_avg else sample["ntokens"] + sample["target"].size(0) if self.cfg.sentence_avg else sample["ntokens"] ) logging_output = { "loss": utils.item(loss.data), @@ -221,7 +240,7 @@ def inference_step( expert=None, constraints=None, ): - expert = expert or self.args.gen_expert + expert = expert or self.cfg.gen_expert with torch.no_grad(): return generator.generate( models, diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 79007a6d9f..d975fd49d2 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -3,14 +3,17 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass, field import itertools import json import logging import os +from typing import Optional from argparse import Namespace +from omegaconf import II import numpy as np -from fairseq import metrics, options, utils +from fairseq import metrics, utils from fairseq.data import ( AppendTokenDataset, ConcatDataset, @@ -22,7 +25,9 @@ encoders, indexed_dataset, ) -from fairseq.tasks import LegacyFairseqTask, register_task +from fairseq.data.indexed_dataset import get_available_dataset_impl +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.tasks import FairseqTask, register_task EVAL_BLEU_ORDER = 4 @@ -161,8 +166,102 @@ def split_exists(split, src, tgt, lang, data_path): ) -@register_task("translation") -class TranslationTask(LegacyFairseqTask): +@dataclass +class TranslationConfig(FairseqDataclass): + data: Optional[str] = field( + default=None, + metadata={ + "help": "colon separated path to data directories list, will be iterated upon during epochs " + "in round-robin manner; however, valid and test data are always in the first directory " + "to avoid the need for repeating them in all directories" + }, + ) + source_lang: Optional[str] = field( + default=None, + metadata={ + "help": "source language", + "argparse_alias": "-s", + }, + ) + target_lang: Optional[str] = field( + default=None, + metadata={ + "help": "target language", + "argparse_alias": "-t", + }, + ) + load_alignments: bool = field( + default=False, metadata={"help": "load the binarized alignments"} + ) + left_pad_source: bool = field( + default=True, metadata={"help": "pad the source on the left"} + ) + left_pad_target: bool = field( + default=False, metadata={"help": "pad the target on the left"} + ) + max_source_positions: int = field( + default=1024, metadata={"help": "max number of tokens in the source sequence"} + ) + max_target_positions: int = field( + default=1024, metadata={"help": "max number of tokens in the target sequence"} + ) + upsample_primary: int = field( + default=-1, metadata={"help": "the amount of upsample primary dataset"} + ) + truncate_source: bool = field( + default=False, metadata={"help": "truncate source to max-source-positions"} + ) + num_batch_buckets: int = field( + default=0, + metadata={ + "help": "if >0, then bucket source and target lengths into " + "N buckets and pad accordingly; this is useful on TPUs to minimize the number of compilations" + }, + ) + train_subset: str = II("dataset.train_subset") + dataset_impl: Optional[ChoiceEnum(get_available_dataset_impl())] = II( + "dataset.dataset_impl" + ) + required_seq_len_multiple: int = II("dataset.required_seq_len_multiple") + + # options for reporting BLEU during validation + eval_bleu: bool = field( + default=False, metadata={"help": "evaluation with BLEU scores"} + ) + eval_bleu_args: str = field( + default="{}", + metadata={ + "help": 'generation args for BLUE scoring, e.g., \'{"beam": 4, "lenpen": 0.6}\', as JSON string' + }, + ) + eval_bleu_detok: str = field( + default="space", + metadata={ + "help": "detokenize before computing BLEU (e.g., 'moses'); required if using --eval-bleu; " + "use 'space' to disable detokenization; see fairseq.data.encoders for other options" + }, + ) + eval_bleu_detok_args: str = field( + default="{}", + metadata={"help": "args for building the tokenizer, if needed, as JSON string"}, + ) + eval_tokenized_bleu: bool = field( + default=False, metadata={"help": "compute tokenized BLEU instead of sacrebleu"} + ) + eval_bleu_remove_bpe: Optional[str] = field( + default=None, + metadata={ + "help": "remove BPE before computing BLEU", + "argparse_const": "@@ ", + }, + ) + eval_bleu_print_samples: bool = field( + default=False, metadata={"help": "print sample generations during validation"} + ) + + +@register_task("translation", dataclass=TranslationConfig) +class TranslationTask(FairseqTask): """ Translate from one (source) language to another (target) language. @@ -174,108 +273,47 @@ class TranslationTask(LegacyFairseqTask): The translation task is compatible with :mod:`fairseq-train`, :mod:`fairseq-generate` and :mod:`fairseq-interactive`. - - The translation task provides the following additional command-line - arguments: - - .. argparse:: - :ref: fairseq.tasks.translation_parser - :prog: """ - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - # fmt: off - parser.add_argument('data', help='colon separated path to data directories list, \ - will be iterated upon during epochs in round-robin manner; \ - however, valid and test data are always in the first directory to \ - avoid the need for repeating them in all directories') - parser.add_argument('-s', '--source-lang', default=None, metavar='SRC', - help='source language') - parser.add_argument('-t', '--target-lang', default=None, metavar='TARGET', - help='target language') - parser.add_argument('--load-alignments', action='store_true', - help='load the binarized alignments') - parser.add_argument('--left-pad-source', default='True', type=str, metavar='BOOL', - help='pad the source on the left') - parser.add_argument('--left-pad-target', default='False', type=str, metavar='BOOL', - help='pad the target on the left') - parser.add_argument('--max-source-positions', default=1024, type=int, metavar='N', - help='max number of tokens in the source sequence') - parser.add_argument('--max-target-positions', default=1024, type=int, metavar='N', - help='max number of tokens in the target sequence') - parser.add_argument('--upsample-primary', default=1, type=int, - help='amount to upsample primary dataset') - parser.add_argument('--truncate-source', action='store_true', default=False, - help='truncate source to max-source-positions') - parser.add_argument('--num-batch-buckets', default=0, type=int, metavar='N', - help='if >0, then bucket source and target lengths into N ' - 'buckets and pad accordingly; this is useful on TPUs ' - 'to minimize the number of compilations') - - # options for reporting BLEU during validation - parser.add_argument('--eval-bleu', action='store_true', - help='evaluation with BLEU scores') - parser.add_argument('--eval-bleu-detok', type=str, default="space", - help='detokenize before computing BLEU (e.g., "moses"); ' - 'required if using --eval-bleu; use "space" to ' - 'disable detokenization; see fairseq.data.encoders ' - 'for other options') - parser.add_argument('--eval-bleu-detok-args', type=str, metavar='JSON', - help='args for building the tokenizer, if needed') - parser.add_argument('--eval-tokenized-bleu', action='store_true', default=False, - help='compute tokenized BLEU instead of sacrebleu') - parser.add_argument('--eval-bleu-remove-bpe', nargs='?', const='@@ ', default=None, - help='remove BPE before computing BLEU') - parser.add_argument('--eval-bleu-args', type=str, metavar='JSON', - help='generation args for BLUE scoring, ' - 'e.g., \'{"beam": 4, "lenpen": 0.6}\'') - parser.add_argument('--eval-bleu-print-samples', action='store_true', - help='print sample generations during validation') - # fmt: on - - def __init__(self, args, src_dict, tgt_dict): - super().__init__(args) + cfg: TranslationConfig + + def __init__(self, cfg: TranslationConfig, src_dict, tgt_dict): + super().__init__(cfg) self.src_dict = src_dict self.tgt_dict = tgt_dict @classmethod - def setup_task(cls, args, **kwargs): + def setup_task(cls, cfg: TranslationConfig, **kwargs): """Setup the task (e.g., load dictionaries). Args: args (argparse.Namespace): parsed command-line arguments """ - args.left_pad_source = utils.eval_bool(args.left_pad_source) - args.left_pad_target = utils.eval_bool(args.left_pad_target) - paths = utils.split_paths(args.data) + paths = utils.split_paths(cfg.data) assert len(paths) > 0 # find language pair automatically - if args.source_lang is None or args.target_lang is None: - args.source_lang, args.target_lang = data_utils.infer_language_pair( - paths[0] - ) - if args.source_lang is None or args.target_lang is None: + if cfg.source_lang is None or cfg.target_lang is None: + cfg.source_lang, cfg.target_lang = data_utils.infer_language_pair(paths[0]) + if cfg.source_lang is None or cfg.target_lang is None: raise Exception( "Could not infer language pair, please provide it explicitly" ) # load dictionaries src_dict = cls.load_dictionary( - os.path.join(paths[0], "dict.{}.txt".format(args.source_lang)) + os.path.join(paths[0], "dict.{}.txt".format(cfg.source_lang)) ) tgt_dict = cls.load_dictionary( - os.path.join(paths[0], "dict.{}.txt".format(args.target_lang)) + os.path.join(paths[0], "dict.{}.txt".format(cfg.target_lang)) ) assert src_dict.pad() == tgt_dict.pad() assert src_dict.eos() == tgt_dict.eos() assert src_dict.unk() == tgt_dict.unk() - logger.info("[{}] dictionary: {} types".format(args.source_lang, len(src_dict))) - logger.info("[{}] dictionary: {} types".format(args.target_lang, len(tgt_dict))) + logger.info("[{}] dictionary: {} types".format(cfg.source_lang, len(src_dict))) + logger.info("[{}] dictionary: {} types".format(cfg.target_lang, len(tgt_dict))) - return cls(args, src_dict, tgt_dict) + return cls(cfg, src_dict, tgt_dict) def load_dataset(self, split, epoch=1, combine=False, **kwargs): """Load a given dataset split. @@ -283,15 +321,15 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): Args: split (str): name of the split (e.g., train, valid, test) """ - paths = utils.split_paths(self.args.data) + paths = utils.split_paths(self.cfg.data) assert len(paths) > 0 - if split != getattr(self.args, "train_subset", None): + if split != self.cfg.train_subset: # if not training data set, use the first shard for valid and test paths = paths[:1] data_path = paths[(epoch - 1) % len(paths)] # infer langcode - src, tgt = self.args.source_lang, self.args.target_lang + src, tgt = self.cfg.source_lang, self.cfg.target_lang self.datasets[split] = load_langpair_dataset( data_path, @@ -301,17 +339,17 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): tgt, self.tgt_dict, combine=combine, - dataset_impl=self.args.dataset_impl, - upsample_primary=self.args.upsample_primary, - left_pad_source=self.args.left_pad_source, - left_pad_target=self.args.left_pad_target, - max_source_positions=self.args.max_source_positions, - max_target_positions=self.args.max_target_positions, - load_alignments=self.args.load_alignments, - truncate_source=self.args.truncate_source, - num_buckets=self.args.num_batch_buckets, + dataset_impl=self.cfg.dataset_impl, + upsample_primary=self.cfg.upsample_primary, + left_pad_source=self.cfg.left_pad_source, + left_pad_target=self.cfg.left_pad_target, + max_source_positions=self.cfg.max_source_positions, + max_target_positions=self.cfg.max_target_positions, + load_alignments=self.cfg.load_alignments, + truncate_source=self.cfg.truncate_source, + num_buckets=self.cfg.num_batch_buckets, shuffle=(split != "test"), - pad_to_multiple=self.args.required_seq_len_multiple, + pad_to_multiple=self.cfg.required_seq_len_multiple, ) def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None): @@ -323,22 +361,15 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None) constraints=constraints, ) - def build_model(self, args): - model = super().build_model(args) - if getattr(args, "eval_bleu", False): - assert getattr(args, "eval_bleu_detok", None) is not None, ( - "--eval-bleu-detok is required if using --eval-bleu; " - "try --eval-bleu-detok=moses (or --eval-bleu-detok=space " - "to disable detokenization, e.g., when using sentencepiece)" - ) - detok_args = json.loads(getattr(args, "eval_bleu_detok_args", "{}") or "{}") + def build_model(self, cfg): + model = super().build_model(cfg) + if self.cfg.eval_bleu: + detok_args = json.loads(self.cfg.eval_bleu_detok_args) self.tokenizer = encoders.build_tokenizer( - Namespace( - tokenizer=getattr(args, "eval_bleu_detok", None), **detok_args - ) + Namespace(tokenizer=self.cfg.eval_bleu_detok, **detok_args) ) - gen_args = json.loads(getattr(args, "eval_bleu_args", "{}") or "{}") + gen_args = json.loads(self.cfg.eval_bleu_args) self.sequence_generator = self.build_generator( [model], Namespace(**gen_args) ) @@ -346,7 +377,7 @@ def build_model(self, args): def valid_step(self, sample, model, criterion): loss, sample_size, logging_output = super().valid_step(sample, model, criterion) - if self.args.eval_bleu: + if self.cfg.eval_bleu: bleu = self._inference_with_bleu(self.sequence_generator, sample, model) logging_output["_bleu_sys_len"] = bleu.sys_len logging_output["_bleu_ref_len"] = bleu.ref_len @@ -360,7 +391,7 @@ def valid_step(self, sample, model, criterion): def reduce_metrics(self, logging_outputs, criterion): super().reduce_metrics(logging_outputs, criterion) - if self.args.eval_bleu: + if self.cfg.eval_bleu: def sum_logs(key): return sum(log.get(key, 0) for log in logging_outputs) @@ -399,7 +430,7 @@ def compute_bleu(meters): def max_positions(self): """Return the max sentence length allowed by the task.""" - return (self.args.max_source_positions, self.args.max_target_positions) + return (self.cfg.max_source_positions, self.cfg.max_target_positions) @property def source_dictionary(self): @@ -417,7 +448,7 @@ def _inference_with_bleu(self, generator, sample, model): def decode(toks, escape_unk=False): s = self.tgt_dict.string( toks.int().cpu(), - self.args.eval_bleu_remove_bpe, + self.cfg.eval_bleu_remove_bpe, # The default unknown string in fairseq is `<unk>`, but # this is tokenized by sacrebleu as `< unk >`, inflating # BLEU scores. Instead, we use a somewhat more verbose @@ -439,10 +470,10 @@ def decode(toks, escape_unk=False): escape_unk=True, # don't count <unk> as matches to the hypo ) ) - if self.args.eval_bleu_print_samples: + if self.cfg.eval_bleu_print_samples: logger.info("example hypothesis: " + hyps[0]) logger.info("example reference: " + refs[0]) - if self.args.eval_tokenized_bleu: + if self.cfg.eval_tokenized_bleu: return sacrebleu.corpus_bleu(hyps, [refs], tokenize="none") else: return sacrebleu.corpus_bleu(hyps, [refs]) diff --git a/fairseq/tasks/translation_from_pretrained_xlm.py b/fairseq/tasks/translation_from_pretrained_xlm.py index 347a6eccb7..a05f289152 100644 --- a/fairseq/tasks/translation_from_pretrained_xlm.py +++ b/fairseq/tasks/translation_from_pretrained_xlm.py @@ -3,13 +3,21 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass from fairseq.data.legacy.masked_lm_dictionary import MaskedLMDictionary -from fairseq.tasks.translation import TranslationTask +from fairseq.tasks.translation import TranslationConfig, TranslationTask from . import register_task -@register_task("translation_from_pretrained_xlm") +@dataclass +class TranslationFromPretrainedXLMConfig(TranslationConfig): + pass + + +@register_task( + "translation_from_pretrained_xlm", dataclass=TranslationFromPretrainedXLMConfig +) class TranslationFromPretrainedXLMTask(TranslationTask): """ Same as TranslationTask except use the MaskedLMDictionary class so that diff --git a/fairseq/tasks/translation_lev.py b/fairseq/tasks/translation_lev.py index 4678774922..041279305d 100644 --- a/fairseq/tasks/translation_lev.py +++ b/fairseq/tasks/translation_lev.py @@ -3,33 +3,35 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import os - +from dataclasses import dataclass, field import torch from fairseq import utils from fairseq.data import LanguagePairDataset +from fairseq.dataclass import ChoiceEnum from fairseq.tasks import register_task -from fairseq.tasks.translation import TranslationTask, load_langpair_dataset +from fairseq.tasks.translation import TranslationConfig, TranslationTask, load_langpair_dataset from fairseq.utils import new_arange -@register_task("translation_lev") +NOISE_CHOICES = ChoiceEnum(["random_delete", "random_mask", "no_noise", "full_mask"]) + +@dataclass +class TranslationLevenshteinConfig(TranslationConfig): + noise: NOISE_CHOICES = field( + default="random_delete", + metadata={ + "help": "type of noise" + }, + ) + +@register_task("translation_lev", dataclass=TranslationLevenshteinConfig) class TranslationLevenshteinTask(TranslationTask): """ Translation (Sequence Generation) task for Levenshtein Transformer See `"Levenshtein Transformer" <https://arxiv.org/abs/1905.11006>`_. """ - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - # fmt: off - TranslationTask.add_args(parser) - parser.add_argument( - '--noise', - default='random_delete', - choices=['random_delete', 'random_mask', 'no_noise', 'full_mask']) - # fmt: on + cfg: TranslationLevenshteinConfig def load_dataset(self, split, epoch=1, combine=False, **kwargs): """Load a given dataset split. @@ -37,12 +39,12 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): Args: split (str): name of the split (e.g., train, valid, test) """ - paths = utils.split_paths(self.args.data) + paths = utils.split_paths(self.cfg.data) assert len(paths) > 0 data_path = paths[(epoch - 1) % len(paths)] # infer langcode - src, tgt = self.args.source_lang, self.args.target_lang + src, tgt = self.cfg.source_lang, self.cfg.target_lang self.datasets[split] = load_langpair_dataset( data_path, @@ -52,12 +54,12 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): tgt, self.tgt_dict, combine=combine, - dataset_impl=self.args.dataset_impl, - upsample_primary=self.args.upsample_primary, - left_pad_source=self.args.left_pad_source, - left_pad_target=self.args.left_pad_target, - max_source_positions=self.args.max_source_positions, - max_target_positions=self.args.max_target_positions, + dataset_impl=self.cfg.dataset_impl, + upsample_primary=self.cfg.upsample_primary, + left_pad_source=self.cfg.left_pad_source, + left_pad_target=self.cfg.left_pad_target, + max_source_positions=self.cfg.max_source_positions, + max_target_positions=self.cfg.max_target_positions, prepend_bos=True, ) @@ -133,13 +135,13 @@ def _full_mask(target_tokens): ) return target_tokens.masked_fill(~target_mask, unk) - if self.args.noise == "random_delete": + if self.cfg.noise == "random_delete": return _random_delete(target_tokens) - elif self.args.noise == "random_mask": + elif self.cfg.noise == "random_mask": return _random_mask(target_tokens) - elif self.args.noise == "full_mask": + elif self.cfg.noise == "full_mask": return _full_mask(target_tokens) - elif self.args.noise == "no_noise": + elif self.cfg.noise == "no_noise": return target_tokens else: raise NotImplementedError diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py index e3c685deec..617a5f7c84 100644 --- a/tests/test_checkpoint_utils.py +++ b/tests/test_checkpoint_utils.py @@ -53,7 +53,7 @@ def _train_transformer(self, seed, extra_args=None): yield os.path.join(data_dir, "checkpoint_last.pt") def test_load_model_ensemble_and_task(self): - with contextlib.redirect_stdout(StringIO()): + # with contextlib.redirect_stdout(StringIO()): with self._train_transformer(seed=123) as model1: with self._train_transformer(seed=456) as model2: ensemble, cfg, task = checkpoint_utils.load_model_ensemble_and_task( @@ -67,7 +67,10 @@ def test_load_model_ensemble_and_task(self): self.assertEqual(ensemble[1].args.seed, 456) # the task from the first model should be returned - self.assertEqual(task.args.seed, 123) + self.assertTrue("seed123" in task.cfg.data) + + # last cfg is saved + self.assertEqual(cfg.common.seed, 456) def test_prune_state_dict(self): with contextlib.redirect_stdout(StringIO()): From fc989279647666d7ae537345954556f76ef326c1 Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Wed, 20 Jan 2021 19:14:14 -0800 Subject: [PATCH 165/774] TALNet Training: Log `logits` and `target` in Wav2VecCriterion Summary: TALNet needs to log the `logits` and `target` arrays in `Wav2VecCriterion` to compute the MAP and MAUC metrics on the validation set, which are used to decide when to reduce the learning rate. Reviewed By: alexeib Differential Revision: D25957415 fbshipit-source-id: 9c8ccfc408dd0747611b36f430d9f0796bc5340d --- fairseq/criterions/wav2vec_criterion.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index 8a1c348a58..cc454b9309 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -102,8 +102,16 @@ def forward(self, model, sample, reduce=True): } for lk in self.log_keys: - if lk in net_output: - logging_output[lk] = float((net_output[lk])) + # Only store "logits" and "target" for computing MAP and MAUC + # during validation + if lk == "logits": + if not self.training: + logging_output["logits"] = logits.cpu().numpy() + elif lk == "target": + if not self.training: + logging_output["target"] = target.cpu().numpy() + elif lk in net_output: + logging_output[lk] = float(net_output[lk]) if len(losses) > 1: for i, l in enumerate(losses): From 9a1c49706b35bdfc0e4de1a905298113eb236603 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Wed, 20 Jan 2021 20:40:52 -0800 Subject: [PATCH 166/774] Make Hydra logging work with DDP (#1568) Summary: without this pr, when launching hydra based sweeps via "hydra_train.py", logging would only go to standard out/error files, rather than into "hydra_train.log" file. The problem is that the standard out/err files are placed in a different folder by submitit without a clear way to modify this behavior, while hydra_train.log is always empty (except when training on one gpu) because either a) reset_logging will remove hydra logging hooks, or b) hydra logging does not work properly with ddp based training. to address a) we do not remove hydra logging by default (although it is optionally still possible) to address b) we reconfigure the loggers in the train method which will be called by each spawned process Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1568 Reviewed By: myleott Differential Revision: D25965658 Pulled By: alexeib fbshipit-source-id: 77cbd4d310fe2d291fb1003c6a3e27e619d571aa --- fairseq/dataclass/configs.py | 2 +- fairseq/dataclass/initialize.py | 4 +++- fairseq/distributed_utils.py | 4 ++++ fairseq_cli/hydra_train.py | 12 +++++++++--- fairseq_cli/train.py | 8 +++++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 2968d2ab0f..2ed27284dc 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -181,7 +181,7 @@ class CommonConfig(FairseqDataclass): default=False, metadata={"help": "enable autograd profiler emit_nvtx"} ) reset_logging: bool = field( - default=True, + default=False, metadata={ "help": "when using Hydra, reset the logging at the beginning of training" }, diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index 385624f19b..479aeb8b16 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -7,7 +7,7 @@ import logging from hydra.core.config_store import ConfigStore from fairseq.dataclass.configs import FairseqConfig -from omegaconf import DictConfig, open_dict +from omegaconf import DictConfig, OmegaConf logger = logging.getLogger(__name__) @@ -36,6 +36,8 @@ def add_defaults(cfg: DictConfig) -> None: from fairseq.dataclass.utils import merge_with_parent from typing import Any + OmegaConf.set_struct(cfg, False) + for k, v in FairseqConfig.__dataclass_fields__.items(): field_cfg = cfg.get(k) if field_cfg is not None and v.type == Any: diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 8f98ac88f9..79deba5b98 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -301,6 +301,10 @@ def distributed_main(i, main, cfg: FairseqConfig, kwargs): main(cfg, **kwargs) + # make sure checkpoints finish saving + if torch.distributed.is_initialized(): + torch.distributed.barrier() + def call_main(cfg: FairseqConfig, main, **kwargs): if cfg.distributed_training.distributed_init_method is None: diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index 6754f9483d..180bd40717 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -14,8 +14,9 @@ from fairseq.dataclass.configs import FairseqConfig import hydra +from hydra.core.hydra_config import HydraConfig import torch -from omegaconf import OmegaConf +from omegaconf import OmegaConf, open_dict logger = logging.getLogger("fairseq_cli.hydra_train") @@ -24,11 +25,16 @@ @hydra.main(config_path=os.path.join("..", "fairseq", "config"), config_name="config") def hydra_main(cfg: FairseqConfig) -> float: add_defaults(cfg) - cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) - OmegaConf.set_struct(cfg, True) if cfg.common.reset_logging: reset_logging() # Hydra hijacks logging, fix that + else: + with open_dict(cfg): + # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) + cfg.job_logging_cfg = OmegaConf.to_container(HydraConfig.get().job_logging, resolve=True) + + cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) + OmegaConf.set_struct(cfg, True) try: if cfg.common.profile: diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 1156222642..5f3fff8e7f 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -25,7 +25,9 @@ utils, ) from fairseq.data import iterators +from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.distributed_utils import is_master from fairseq.logging import meters, metrics, progress_bar from fairseq.model_parallel.megatron_trainer import MegatronTrainer from fairseq.trainer import Trainer @@ -41,12 +43,16 @@ logger = logging.getLogger("fairseq_cli.train") -def main(cfg: DictConfig) -> None: +def main(cfg: FairseqConfig) -> None: if isinstance(cfg, argparse.Namespace): cfg = convert_namespace_to_omegaconf(cfg) utils.import_user_module(cfg.common) + if is_master(cfg.distributed_training) and "job_logging_cfg" in cfg: + # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) + logging.config.dictConfig(OmegaConf.to_container(cfg.job_logging_cfg)) + assert ( cfg.dataset.max_tokens is not None or cfg.dataset.batch_size is not None ), "Must specify batch size either with --max-tokens or --batch-size" From cfbf0dddbc2f06b4d2975655a3959d13e5ba6667 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 21 Jan 2021 07:32:08 -0800 Subject: [PATCH 167/774] Small changes to make tests more reliable (#1572) Summary: After this, `python setup.py test` should be more reliable (including when multiple GPUs are present) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1572 Reviewed By: alexeib Differential Revision: D25984113 Pulled By: myleott fbshipit-source-id: 7fef27ae90c079c07f592ed9fb350ccf8b56d23d --- README.md | 4 ++-- fairseq/data/data_utils_fast.pyx | 3 +++ fairseq/distributed_utils.py | 5 +--- fairseq/models/roberta/hub_interface.py | 2 +- fairseq/ngram_repeat_block.py | 2 +- fairseq/sequence_generator.py | 12 ++++++---- setup.py | 31 +++++++++++++------------ tests/distributed/utils.py | 1 + tests/test_binaries.py | 5 ++-- tests/test_bmuf.py | 17 ++++++-------- 10 files changed, 43 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index c22abba8c0..5fedac7eec 100644 --- a/README.md +++ b/README.md @@ -136,8 +136,8 @@ pip install --editable ./ # on MacOS: # CFLAGS="-stdlib=libc++" pip install --editable ./ -# to install the latest stable release (0.10.1) -# pip install fairseq==0.10.1 +# to install the latest stable release (0.10.x) +# pip install fairseq ``` * **For faster training** install NVIDIA's [apex](https://github.com/NVIDIA/apex) library: diff --git a/fairseq/data/data_utils_fast.pyx b/fairseq/data/data_utils_fast.pyx index d197d3f00e..c61f31d6b2 100644 --- a/fairseq/data/data_utils_fast.pyx +++ b/fairseq/data/data_utils_fast.pyx @@ -24,6 +24,9 @@ cpdef list batch_by_size_vec( int64_t max_sentences, int32_t bsz_mult, ): + if indices.shape[0] == 0: + return [] + assert max_tokens <= 0 or np.max(num_tokens_vec) <= max_tokens, ( f"Sentences lengths should not exceed max_tokens={max_tokens}" ) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 79deba5b98..37822362d4 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -301,10 +301,6 @@ def distributed_main(i, main, cfg: FairseqConfig, kwargs): main(cfg, **kwargs) - # make sure checkpoints finish saving - if torch.distributed.is_initialized(): - torch.distributed.barrier() - def call_main(cfg: FairseqConfig, main, **kwargs): if cfg.distributed_training.distributed_init_method is None: @@ -323,6 +319,7 @@ def call_main(cfg: FairseqConfig, main, **kwargs): torch.cuda.device_count(), cfg.distributed_training.distributed_world_size, ), + join=True, ) else: distributed_main(cfg.distributed_training.device_id, main, cfg, kwargs) diff --git a/fairseq/models/roberta/hub_interface.py b/fairseq/models/roberta/hub_interface.py index 0c723f06dd..c9af434bde 100644 --- a/fairseq/models/roberta/hub_interface.py +++ b/fairseq/models/roberta/hub_interface.py @@ -173,7 +173,7 @@ def fill_mask(self, masked_input: str, topk: int = 5): add_if_not_exist=False, ) - masked_index = (tokens == self.task.mask_idx).nonzero() + masked_index = (tokens == self.task.mask_idx).nonzero(as_tuple=False) if tokens.dim() == 1: tokens = tokens.unsqueeze(0) diff --git a/fairseq/ngram_repeat_block.py b/fairseq/ngram_repeat_block.py index 856c9e64f7..ed2d744635 100644 --- a/fairseq/ngram_repeat_block.py +++ b/fairseq/ngram_repeat_block.py @@ -19,7 +19,7 @@ def is_cuda_extension_usable() -> bool: """Check whether ngram_repeat_block_cuda is built properly""" - if not EXTENSION_BUILT: + if not EXTENSION_BUILT or not torch.cuda.is_available(): return False bsz = 2 tokens = torch.tensor([[4, 4, 3, 2], [1, 2, 3, 4]], dtype=torch.long, device="cuda") diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index b0249888ce..117c6116fb 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -86,8 +86,10 @@ def __init__( self.temperature = temperature self.match_source_len = match_source_len - self.no_repeat_ngram_size = no_repeat_ngram_size - self.repeat_ngram_blocker = NGramRepeatBlock(no_repeat_ngram_size) + if no_repeat_ngram_size > 0: + self.repeat_ngram_blocker = NGramRepeatBlock(no_repeat_ngram_size) + else: + self.repeat_ngram_blocker = None assert temperature > 0, "--temperature must be greater than 0" @@ -373,8 +375,10 @@ def _generate( if self.should_set_src_lengths: self.search.set_src_lengths(src_lengths) - if self.no_repeat_ngram_size > 0: - lprobs = self.repeat_ngram_blocker(tokens, lprobs, bsz, beam_size, step) + if self.repeat_ngram_blocker is not None: + lprobs = self.repeat_ngram_blocker( + tokens, lprobs, bsz, beam_size, step + ) # Shape: (batch, cand_size) cand_scores, cand_indices, cand_beams = self.search.step( diff --git a/setup.py b/setup.py index 08fe0dcccc..d1a976104e 100644 --- a/setup.py +++ b/setup.py @@ -242,18 +242,19 @@ def get_files(path, relative_to="fairseq"): return all_files -try: - # symlink examples into fairseq package so package_data accepts them - fairseq_examples = os.path.join("fairseq", "examples") - if "build_ext" not in sys.argv[1:] and not os.path.exists(fairseq_examples): - os.symlink(os.path.join("..", "examples"), fairseq_examples) - - package_data = { - "fairseq": ( - get_files(fairseq_examples) + get_files(os.path.join("fairseq", "config")) - ) - } - do_setup(package_data) -finally: - if "build_ext" not in sys.argv[1:] and os.path.exists(fairseq_examples): - os.unlink(fairseq_examples) +if __name__ == "__main__": + try: + # symlink examples into fairseq package so package_data accepts them + fairseq_examples = os.path.join("fairseq", "examples") + if "build_ext" not in sys.argv[1:] and not os.path.exists(fairseq_examples): + os.symlink(os.path.join("..", "examples"), fairseq_examples) + + package_data = { + "fairseq": ( + get_files(fairseq_examples) + get_files(os.path.join("fairseq", "config")) + ) + } + do_setup(package_data) + finally: + if "build_ext" not in sys.argv[1:] and os.path.exists(fairseq_examples): + os.unlink(fairseq_examples) diff --git a/tests/distributed/utils.py b/tests/distributed/utils.py index d2b3ddb1ff..c8040392a8 100644 --- a/tests/distributed/utils.py +++ b/tests/distributed/utils.py @@ -17,6 +17,7 @@ def spawn_and_init(fn, world_size, args=None): fn=functools.partial(init_and_run, fn, args), args=(world_size, tmp_file.name,), nprocs=world_size, + join=True, ) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index ddfc1c4db5..967b1bf7ba 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -1623,8 +1623,9 @@ def _train(extra_flags): with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: - create_dummy_data(data_dir, num_examples=20) - preprocess_translation_data(data_dir) + with self.assertLogs(): + create_dummy_data(data_dir, num_examples=20) + preprocess_translation_data(data_dir) ckpt_logs = _train(["--checkpoint-activations"]) baseline_logs = _train([]) assert len(baseline_logs) == len(ckpt_logs) diff --git a/tests/test_bmuf.py b/tests/test_bmuf.py index e7aa6da1ca..785da37bc2 100644 --- a/tests/test_bmuf.py +++ b/tests/test_bmuf.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import argparse +import functools import random import unittest from multiprocessing import Manager @@ -141,16 +142,12 @@ class TestBMUF(unittest.TestCase): def bmuf_process(self, cfg, args, iterations): processes = [] results = Manager().dict() - ctx = torch.multiprocessing.get_context("spawn") - for rank in range(args.distributed_world_size): - p = ctx.Process( - target=single_gpu_training, args=(cfg, args, rank, iterations, results) - ) - p.start() - processes.append(p) - - for p in processes: - p.join() + torch.multiprocessing.spawn( + fn=functools.partial(single_gpu_training, cfg, args), + args=(iterations, results), + nprocs=args.distributed_world_size, + join=True, + ) return results def test_bmuf_sync(self): From bfcc13e20a6cfa18fb25daaae39644f9b7872699 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Sat, 23 Jan 2021 03:28:48 -0800 Subject: [PATCH 168/774] add return type hints for readability (#1575) Summary: As I was going through the dataset/preprocessing code, knowing return types would have made my life easier. Also I don't think you need to inherit from object in python3. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1575 Reviewed By: myleott Differential Revision: D25999257 Pulled By: sshleifer fbshipit-source-id: 818a623c68fb7812306c760f3ae6346a14937c51 --- fairseq/binarizer.py | 11 +++++++---- fairseq/data/dictionary.py | 4 ++-- fairseq/data/indexed_dataset.py | 12 ++++++------ fairseq/data/lm_context_window_dataset.py | 11 ++++++++--- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/fairseq/binarizer.py b/fairseq/binarizer.py index c736c8754d..18ae67bf25 100644 --- a/fairseq/binarizer.py +++ b/fairseq/binarizer.py @@ -9,6 +9,7 @@ import torch from fairseq.file_io import PathManager from fairseq.tokenizer import tokenize_line +from typing import List, Dict def safe_readline(f): @@ -33,7 +34,7 @@ def binarize( offset=0, end=-1, already_numberized=False, - ): + ) -> Dict[str, int]: nseq, ntok = 0, 0 replaced = Counter() @@ -52,7 +53,7 @@ def replaced_consumer(word, idx): # end bytes to end + 2**32 bytes (4 GB) and this makes it unlikely # that the procedure breaks by the undeterministic behavior of # f.tell() - if end > 0 and f.tell() > end and f.tell() < end + 2**32: + if end > 0 and f.tell() > end and f.tell() < end + 2 ** 32: break if already_numberized: id_strings = line.strip().split() @@ -83,7 +84,9 @@ def replaced_consumer(word, idx): } @staticmethod - def binarize_alignments(filename, alignment_parser, consumer, offset=0, end=-1): + def binarize_alignments( + filename, alignment_parser, consumer, offset=0, end=-1 + ) -> Dict[str, int]: nseq = 0 with open(PathManager.get_local_path(filename), "r") as f: @@ -99,7 +102,7 @@ def binarize_alignments(filename, alignment_parser, consumer, offset=0, end=-1): return {"nseq": nseq} @staticmethod - def find_offsets(filename, num_chunks): + def find_offsets(filename, num_chunks) -> List[int]: with open(PathManager.get_local_path(filename), "r", encoding="utf-8") as f: size = os.fstat(f.fileno()).st_size chunk_size = size // num_chunks diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index 127d023f4c..8d219e20ef 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -15,7 +15,7 @@ from fairseq.tokenizer import tokenize_line -class Dictionary(object): +class Dictionary: """A mapping from symbols to consecutive integers""" def __init__( @@ -298,7 +298,7 @@ def encode_line( consumer=None, append_eos=True, reverse_order=False, - ): + ) -> torch.IntTensor: words = line_tokenizer(line) if reverse_order: words = list(reversed(words)) diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index 827754d848..a821417321 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -159,7 +159,7 @@ def __del__(self): self.data_file.close() @lru_cache(maxsize=8) - def __getitem__(self, i): + def __getitem__(self, i) -> torch.Tensor: if not self.data_file: self.read_data(self.path) self.check_index(i) @@ -296,7 +296,7 @@ def exists(path): return PathManager.exists(path) -class IndexedDatasetBuilder(object): +class IndexedDatasetBuilder: element_sizes = { np.uint8: 1, np.int8: 1, @@ -363,12 +363,12 @@ def _warmup_mmap_file(path): class MMapIndexedDataset(torch.utils.data.Dataset): - class Index(object): + class Index: _HDR_MAGIC = b"MMIDIDX\x00\x00" @classmethod def writer(cls, path, dtype): - class _Writer(object): + class _Writer: def __enter__(self): self._file = open(path, "wb") @@ -517,7 +517,7 @@ def exists(path): ) -def get_indexed_dataset_to_local(path): +def get_indexed_dataset_to_local(path) -> str: local_index_path = PathManager.get_local_path(index_file_path(path)) local_data_path = PathManager.get_local_path(data_file_path(path)) @@ -531,7 +531,7 @@ def get_indexed_dataset_to_local(path): return local_path -class MMapIndexedDatasetBuilder(object): +class MMapIndexedDatasetBuilder: def __init__(self, out_file, dtype=np.int64): self._data_file = open(out_file, "wb") self._dtype = dtype diff --git a/fairseq/data/lm_context_window_dataset.py b/fairseq/data/lm_context_window_dataset.py index 39512797bc..1a945927cf 100644 --- a/fairseq/data/lm_context_window_dataset.py +++ b/fairseq/data/lm_context_window_dataset.py @@ -5,6 +5,8 @@ import numpy as np import torch +from typing import Dict + from fairseq.data.monolingual_dataset import MonolingualDataset from . import FairseqDataset @@ -26,7 +28,11 @@ class LMContextWindowDataset(FairseqDataset): """ def __init__( - self, dataset, tokens_per_sample: int, context_window: int, pad_idx: int + self, + dataset: MonolingualDataset, + tokens_per_sample: int, + context_window: int, + pad_idx: int, ): assert context_window > 0 self.dataset = dataset @@ -41,7 +47,7 @@ def __getitem__(self, index): def __len__(self): return len(self.dataset) - def collater(self, samples): + def collater(self, samples) -> Dict: sample = self.dataset.collater(samples) pad = self.pad_idx @@ -71,7 +77,6 @@ def collater(self, samples): sample["net_input"]["src_tokens"] = torch.from_numpy(new_toks) sample["target"] = torch.from_numpy(new_tgt) sample["start_indices"] = start_idxs - return sample def num_tokens(self, index): From 1e6323e9346c172225f20415735c33f96dd9aad1 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@fb.com> Date: Mon, 25 Jan 2021 09:22:08 -0800 Subject: [PATCH 169/774] Offload inputs to CPU (V2) Reviewed By: myleott Differential Revision: D26035523 fbshipit-source-id: 7dc08a38c10d1f26a871106f143f92fd11f6073c --- .../truncated_bptt/transformer_xl_model.py | 10 +- fairseq/models/transformer.py | 26 +++- fairseq/models/transformer_lm.py | 8 ++ fairseq/modules/checkpoint_activations.py | 23 +++- tests/test_binaries.py | 116 ++++++++++++------ 5 files changed, 131 insertions(+), 52 deletions(-) diff --git a/examples/truncated_bptt/transformer_xl_model.py b/examples/truncated_bptt/transformer_xl_model.py index 83b248479e..a6c8b25a07 100644 --- a/examples/truncated_bptt/transformer_xl_model.py +++ b/examples/truncated_bptt/transformer_xl_model.py @@ -37,6 +37,7 @@ class TransformerXLConfig(FairseqDataclass): dropout: float = 0.0 dropatt: float = 0.0 checkpoint_activations: bool = False + offload_activations: bool = False max_target_positions: int = II("task.max_target_positions") @@ -51,7 +52,8 @@ class TransformerXLDecoder(FairseqIncrementalDecoder): def __init__(self, cfg, task): try: from transformers.models.transfo_xl import ( - TransfoXLConfig, TransfoXLLMHeadModel + TransfoXLConfig, + TransfoXLLMHeadModel, ) except ImportError: from transformers.configuration_transfo_xl import TransfoXLConfig @@ -96,11 +98,13 @@ def __init__(self, cfg, task): except Exception: pass - if cfg.checkpoint_activations: + if cfg.checkpoint_activations or cfg.offload_activations: for i in range(len(self.model.transformer.layers)): self.model.transformer.layers[i] = checkpoint_wrapper( - self.model.transformer.layers[i] + self.model.transformer.layers[i], + offload_to_cpu=cfg.offload_activations, ) + # TODO: may save mem to wrap(layer.pos_ff.CoreNet[3]) self._mems = None diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index fa4c29855b..362d9b28d6 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -167,6 +167,8 @@ def add_args(parser): parser.add_argument('--checkpoint-activations', action='store_true', help='checkpoint activations at each layer, which saves GPU ' 'memory usage at the cost of some additional compute') + parser.add_argument('--offload-activations', action='store_true', + help='checkpoint activations at each layer, then save to gpu. Sets --checkpoint-activations.') # args for "Cross+Self-Attention for Transformer Models" (Peitz et al., 2019) parser.add_argument('--no-cross-attention', default=False, action='store_true', help='do not perform cross-attention') @@ -234,7 +236,8 @@ def build_model(cls, args, task): decoder_embed_tokens = cls.build_embedding( args, tgt_dict, args.decoder_embed_dim, args.decoder_embed_path ) - + if getattr(args, "offload_activations", False): + args.checkpoint_activations = True # offloading implies checkpointing encoder = cls.build_encoder(args, src_dict, encoder_embed_tokens) decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens) return cls(args, encoder, decoder) @@ -380,7 +383,8 @@ def __init__(self, args, dictionary, embed_tokens): def build_encoder_layer(self, args): layer = TransformerEncoderLayer(args) if getattr(args, "checkpoint_activations", False): - layer = checkpoint_wrapper(layer) + offload_to_cpu = getattr(args, "offload_activations", False) + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) return layer def forward_embedding( @@ -670,7 +674,8 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): def build_decoder_layer(self, args, no_encoder_attn=False): layer = TransformerDecoderLayer(args, no_encoder_attn) if getattr(args, "checkpoint_activations", False): - layer = checkpoint_wrapper(layer) + offload_to_cpu = getattr(args, "offload_activations", False) + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) return layer def forward( @@ -947,6 +952,17 @@ def Linear(in_features, out_features, bias=True): return m +@register_model_architecture("transformer", "transformer_tiny") +def tiny_architecture(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 64) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 64) + args.encoder_layers = getattr(args, "encoder_layers", 2) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 2) + args.decoder_layers = getattr(args, "decoder_layers", 2) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 2) + return base_architecture(args) + + @register_model_architecture("transformer", "transformer") def base_architecture(args): args.encoder_embed_path = getattr(args, "encoder_embed_path", None) @@ -991,7 +1007,9 @@ def base_architecture(args): args.layernorm_embedding = getattr(args, "layernorm_embedding", False) args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) args.checkpoint_activations = getattr(args, "checkpoint_activations", False) - + args.offload_activations = getattr(args, "offload_activations", False) + if args.offload_activations: + args.checkpoint_activations = True args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) args.decoder_layers_to_keep = getattr(args, "decoder_layers_to_keep", None) args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0) diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index d86b68b508..edf62b12b3 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -144,6 +144,10 @@ class TransformerLanguageModelConfig(FairseqDataclass): checkpoint_activations: bool = field( default=False, metadata={"help": "checkpoint activations at each layer"} ) + offload_activations: bool = field( + default=False, + metadata={"help": "move checkpointed activations to CPU after they are used."}, + ) quant_noise_pq: float = field( default=0.0, metadata={"help": "iterative PQ quantization noise at training time"}, @@ -171,6 +175,7 @@ class TransformerLanguageModel(FairseqLanguageModel): def hub_models(cls): def moses_fastbpe(path): return {"path": path, "tokenizer": "moses", "bpe": "fastbpe"} + def spm(path): return {"path": path, "tokenizer": "space", "bpe": "sentencepiece"} @@ -321,6 +326,9 @@ def base_lm_architecture(args): args.no_scale_embedding = getattr(args, "no_scale_embedding", False) args.layernorm_embedding = getattr(args, "layernorm_embedding", False) args.checkpoint_activations = getattr(args, "checkpoint_activations", False) + args.offload_activations = getattr(args, "offload_activations", False) + if args.offload_activations: + args.checkpoint_activations = True @register_model_architecture("transformer_lm", "transformer_lm_big") diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index e0e5679c5a..c84e70bf7b 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -11,7 +11,7 @@ from fairseq import utils -def checkpoint_wrapper(m): +def checkpoint_wrapper(m, offload_to_cpu=False): """ A friendlier wrapper for performing activation checkpointing. @@ -22,7 +22,7 @@ def checkpoint_wrapper(m): Usage:: - checkpointed_module = checkpoint_wrapper(my_module) + checkpointed_module = checkpoint_wrapper(my_module, offload_to_cpu=True) a, b = checkpointed_module(x, y=3, z=torch.Tensor([1])) """ original_forward = m.forward @@ -32,7 +32,7 @@ def _checkpointed_forward(*args, **kwargs): # the backward must return gradients (or None) for every input argument. # We can flatten keyword arguments to make this easier. kwarg_keys, flat_args = pack_kwargs(*args, **kwargs) - parent_ctx_dict = {} + parent_ctx_dict = {"offload": offload_to_cpu} output = CheckpointFunction.apply( original_forward, parent_ctx_dict, kwarg_keys, *flat_args ) @@ -141,6 +141,14 @@ def forward(ctx, run_function, parent_ctx_dict, kwarg_keys, *args): ctx.fwd_rng_state = utils.get_rng_state() tensor_inputs, packed_non_tensor_inputs = split_non_tensors(args) + if parent_ctx_dict["offload"]: + ctx.fwd_device = tuple(x.device for x in tensor_inputs) + ctx.grad_requirements = tuple(x.requires_grad for x in tensor_inputs) + tensor_inputs = tuple(x.cpu() for x in tensor_inputs) + + else: + ctx.fwd_device, ctx.grad_requirements = None, None + ctx.save_for_backward(*tensor_inputs) ctx.packed_non_tensor_inputs = packed_non_tensor_inputs @@ -165,8 +173,14 @@ def backward(ctx, *args): "Checkpointing is not compatible with .grad(), please use .backward() if possible" ) - tensor_inputs = ctx.saved_tensors + tensor_inputs: Tuple = ctx.saved_tensors tensor_inputs = checkpoint.detach_variable(tensor_inputs) + if ctx.fwd_device is not None: + tensor_inputs = [ + t.to(ctx.fwd_device[i]) for i, t in enumerate(tensor_inputs) + ] + for i, need_grad in enumerate(ctx.grad_requirements): + tensor_inputs[i].requires_grad = need_grad inputs = unpack_non_tensors(tensor_inputs, ctx.packed_non_tensor_inputs) # Store the current states. @@ -179,7 +193,6 @@ def backward(ctx, *args): unpacked_args, unpacked_kwargs = unpack_kwargs(ctx.kwarg_keys, inputs) outputs = ctx.run_function(*unpacked_args, **unpacked_kwargs) tensor_outputs, _ = split_non_tensors(outputs) - # Set the states back to what it was at the start of this function. utils.set_rng_state(bwd_rng_state) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 967b1bf7ba..981ffd49cd 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -547,16 +547,16 @@ def test_translation_multi_simple_epoch_src_tgt_dict_spec(self): "test_translation_multi_simple_epoch_dict" ) as data_dir: create_dummy_data(data_dir) - preprocess_translation_data( - data_dir, extra_flags=[] - ) + preprocess_translation_data(data_dir, extra_flags=[]) train_translation_model( data_dir, arch="transformer", task="translation_multi_simple_epoch", extra_flags=[ - "--source-dict", f"{data_dir}/dict.in.txt", - "--target-dict", f"{data_dir}/dict.out.txt", + "--source-dict", + f"{data_dir}/dict.in.txt", + "--target-dict", + f"{data_dir}/dict.out.txt", "--encoder-layers", "2", "--decoder-layers", @@ -1250,6 +1250,20 @@ def test_transformer_xl_bptt_lm(self): extra_valid_flags=task_flags, ) eval_lm_main(data_dir, extra_flags=task_flags) + # Train with activation offloading + train_language_model( + data_dir=data_dir, + arch="transformer_xl", + extra_flags=task_flags + + [ + "--n-layer", + "2", + "--offload-activations", + ], + task="truncated_bptt_lm", + run_validation=True, + extra_valid_flags=task_flags, + ) class TestMaskedLanguageModel(unittest.TestCase): @@ -1589,45 +1603,67 @@ def read_last_log_entry( class TestActivationCheckpointing(unittest.TestCase): + base_flags = [ + "--encoder-layers", + "2", + "--decoder-layers", + "2", + "--encoder-embed-dim", + "8", + "--decoder-embed-dim", + "8", + "--restore-file", + "x.pt", + "--log-format", + "json", + "--log-interval", + "1", + "--max-update", + "2", + ] + + def _train(self, data_dir, extra_flags): + with self.assertLogs() as logs: + train_translation_model( + data_dir, + "transformer_iwslt_de_en", + self.base_flags + extra_flags, + run_validation=True, + extra_valid_flags=["--log-format", "json"], + ) + return logs.records + + def test_activation_offloading_does_not_change_metrics(self): + """Neither ----checkpoint-activations nor --offload-activations should change loss""" + with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: + + create_dummy_data(data_dir, num_examples=20) + preprocess_translation_data(data_dir) + offload_logs = self._train(data_dir, ["--offload-activations"]) + baseline_logs = self._train(data_dir, []) + + assert len(baseline_logs) == len(offload_logs) + + baseline_valid_stats = read_last_log_entry(baseline_logs, "valid") + offload_valid_stats = read_last_log_entry(offload_logs, "valid") + baseline_train_stats = read_last_log_entry(baseline_logs, "train") + offload_train_stats = read_last_log_entry(offload_logs, "train") + + assert ( + baseline_train_stats["train_loss"] == offload_train_stats["train_loss"] + ) + assert ( + baseline_valid_stats["valid_loss"] == offload_valid_stats["valid_loss"] + ) + def test_activation_checkpointing_does_not_change_metrics(self): """--checkpoint-activations should not change loss""" - base_flags = [ - "--encoder-layers", - "2", - "--decoder-layers", - "2", - "--encoder-embed-dim", - "8", - "--decoder-embed-dim", - "8", - "--restore-file", - "x.pt", - "--log-format", - "json", - "--log-interval", - "1", - "--max-update", - "2", - ] - - def _train(extra_flags): - with self.assertLogs() as logs: - train_translation_model( - data_dir, - "transformer_iwslt_de_en", - base_flags + extra_flags, - run_validation=True, - extra_valid_flags=["--log-format", "json"], - ) - return logs.records with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: - - with self.assertLogs(): - create_dummy_data(data_dir, num_examples=20) - preprocess_translation_data(data_dir) - ckpt_logs = _train(["--checkpoint-activations"]) - baseline_logs = _train([]) + create_dummy_data(data_dir, num_examples=20) + preprocess_translation_data(data_dir) + ckpt_logs = self._train(data_dir, ["--checkpoint-activations"]) + baseline_logs = self._train(data_dir, []) assert len(baseline_logs) == len(ckpt_logs) baseline_train_stats = read_last_log_entry(baseline_logs, "train") From 1f23d83fcff3718805447b8d83edd666cf586850 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 27 Jan 2021 10:45:38 -0800 Subject: [PATCH 170/774] Fix masked_lm task to be more deterministic when reloading checkpoints (#1581) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1581 Test Plan: Imported from OSS Reviewed By: joshim5 Differential Revision: D26018994 Pulled By: myleott fbshipit-source-id: 9013b2795936bd5877fb9e8a8397c9b0ea35ef60 --- fairseq/data/mask_tokens_dataset.py | 5 ++++- fairseq/tasks/masked_lm.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fairseq/data/mask_tokens_dataset.py b/fairseq/data/mask_tokens_dataset.py index b239013c80..9123235594 100644 --- a/fairseq/data/mask_tokens_dataset.py +++ b/fairseq/data/mask_tokens_dataset.py @@ -108,8 +108,11 @@ def set_epoch(self, epoch, **unused): super().set_epoch(epoch) self.epoch = epoch - @lru_cache(maxsize=8) def __getitem__(self, index: int): + return self.__getitem_cached__(self.seed, self.epoch, index) + + @lru_cache(maxsize=8) + def __getitem_cached__(self, seed: int, epoch: int, index: int): with data_utils.numpy_seed(self.seed, self.epoch, index): item = self.dataset[index] sz = len(item) diff --git a/fairseq/tasks/masked_lm.py b/fairseq/tasks/masked_lm.py index 70208bc4d5..fd2ea6ade1 100644 --- a/fairseq/tasks/masked_lm.py +++ b/fairseq/tasks/masked_lm.py @@ -193,7 +193,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): mask_stdev=self.args.mask_stdev, ) - with data_utils.numpy_seed(self.args.seed + epoch): + with data_utils.numpy_seed(self.args.seed): shuffle = np.random.permutation(len(src_dataset)) self.datasets[split] = SortDataset( From c4a4562299eb58f295426b9b81b36701390e883e Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 27 Jan 2021 10:45:38 -0800 Subject: [PATCH 171/774] Reset meters when reloading an end-of-epoch checkpoint (#1582) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1582 Test Plan: Imported from OSS Reviewed By: joshim5 Differential Revision: D26018993 Pulled By: myleott fbshipit-source-id: a0e988d8a2d720443571814d8d9f51acc571f98f --- fairseq/trainer.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index fec60f7742..5035751741 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -376,7 +376,8 @@ def load_checkpoint( self.set_num_updates(last_optim["num_updates"]) if extra_state is not None: - epoch = extra_state["train_iterator"]["epoch"] + itr_state = extra_state["train_iterator"] + epoch = itr_state["epoch"] if "previous_training_time" in extra_state: self._previous_training_time = extra_state["previous_training_time"] @@ -384,6 +385,10 @@ def load_checkpoint( self.lr_step(epoch) + if itr_state["version"] >= 2 and itr_state["iterations_in_epoch"] == 0: + # reset meters at start of epoch + reset_meters = True + if "metrics" in extra_state and not reset_meters: metrics.load_state_dict(extra_state["metrics"]) From 6225dccb989ebfb268274bad36a794b27e4dd43f Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 27 Jan 2021 10:45:38 -0800 Subject: [PATCH 172/774] Use a fixed epoch (=1) when creating validation batch iterators (#1583) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1583 Test Plan: Imported from OSS Reviewed By: joshim5 Differential Revision: D26018992 Pulled By: myleott fbshipit-source-id: f4908358f8db79b6034639419d47698f933ddf91 --- fairseq/data/iterators.py | 24 +++++++++++++++++------- fairseq/trainer.py | 3 +++ fairseq_cli/train.py | 4 +++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 00bf41375c..66eaf875cb 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -109,15 +109,19 @@ def __len__(self) -> int: def next_epoch_idx(self): raise NotImplementedError - def next_epoch_itr(self, shuffle=True, fix_batches_to_gpus=False): + def next_epoch_itr( + self, shuffle=True, fix_batches_to_gpus=False, set_dataset_epoch=True + ): """Return a new iterator over the dataset. Args: shuffle (bool, optional): shuffle batches before returning the iterator (default: True). - fix_batches_to_gpus: ensure that batches are always + fix_batches_to_gpus (bool, optional): ensure that batches are always allocated to the same shards across epochs. Requires that :attr:`dataset` supports prefetching (default: False). + set_dataset_epoch (bool, optional): update the wrapped Dataset with + the new epoch number (default: True). """ raise NotImplementedError @@ -193,9 +197,11 @@ def next_epoch_idx(self): else: return self.epoch - def next_epoch_itr(self, shuffle=True, fix_batches_to_gpus=False): + def next_epoch_itr( + self, shuffle=True, fix_batches_to_gpus=False, set_dataset_epoch=True + ): self.epoch = self.next_epoch_idx - if hasattr(self.dataset, "set_epoch"): + if set_dataset_epoch and hasattr(self.dataset, "set_epoch"): self.dataset.set_epoch(self.epoch) self._current_epoch_iterator = self._get_iterator_for_epoch(self.epoch, shuffle) return self._current_epoch_iterator @@ -355,20 +361,24 @@ def next_epoch_idx(self): else: return self.epoch - def next_epoch_itr(self, shuffle=True, fix_batches_to_gpus=False): + def next_epoch_itr( + self, shuffle=True, fix_batches_to_gpus=False, set_dataset_epoch=True + ): """Return a new iterator over the dataset. Args: shuffle (bool, optional): shuffle batches before returning the iterator (default: True). - fix_batches_to_gpus: ensure that batches are always + fix_batches_to_gpus (bool, optional): ensure that batches are always allocated to the same shards across epochs. Requires that :attr:`dataset` supports prefetching (default: False). + set_dataset_epoch (bool, optional): update the wrapped Dataset with + the new epoch number (default: True). """ if self.disable_shuffling: shuffle = False self.epoch = self.next_epoch_idx - if hasattr(self.dataset, "set_epoch"): + if set_dataset_epoch and hasattr(self.dataset, "set_epoch"): self.dataset.set_epoch(self.epoch) if self._next_epoch_itr is not None: self._cur_epoch_itr = self._next_epoch_itr diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 5035751741..eea194b950 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -468,6 +468,9 @@ def get_valid_iterator( num_shards=self.data_parallel_world_size, shard_id=self.data_parallel_rank, num_workers=self.cfg.dataset.num_workers, + # always pass a fixed "epoch" to keep validation data consistent + # across training epochs + epoch=1, data_buffer_size=self.cfg.dataset.data_buffer_size, disable_iterator_cache=disable_iterator_cache, ) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 5f3fff8e7f..9af7568a77 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -378,7 +378,9 @@ def validate( logger.info('begin validation on "{}" subset'.format(subset)) # Initialize data iterator - itr = trainer.get_valid_iterator(subset).next_epoch_itr(shuffle=False) + itr = trainer.get_valid_iterator(subset).next_epoch_itr( + shuffle=False, set_dataset_epoch=False # use a fixed valid set + ) if cfg.common.tpu: itr = utils.tpu_data_loader(itr) progress = progress_bar.progress_bar( From 96da4d38eb60c3971ca88df9383e09d53493cf1e Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 28 Jan 2021 14:18:48 -0800 Subject: [PATCH 173/774] Small Hydra fix (#1543) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1543 Test Plan: Imported from OSS Reviewed By: girifb Differential Revision: D25836852 Pulled By: myleott fbshipit-source-id: 7fda711d21f2d1b7bac26792233997e8dea2f835 --- fairseq/dataclass/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 401c212ecc..a4d4a412dd 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -162,7 +162,7 @@ def get_kwargs_from_dc( continue else: del kwargs["default"] - if delete_default: + if delete_default and "default" in kwargs: del kwargs["default"] try: parser.add_argument(*field_args, **kwargs) From 5e343f5f23b4a90cca2beec416b87d4dd7a4264f Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 28 Jan 2021 14:18:48 -0800 Subject: [PATCH 174/774] Remove --distributed-wrapper (consolidate to --ddp-backend) (#1544) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1544 Test Plan: Imported from OSS Reviewed By: girifb Differential Revision: D25836856 Pulled By: myleott fbshipit-source-id: eb0a6a02f4d9fe2b6b12a456ef95208dd92c97cb --- examples/cross_lingual_language_model/README.md | 2 +- examples/language_model/README.adaptive_inputs.md | 2 +- examples/language_model/README.conv.md | 2 +- examples/latent_depth/README.md | 2 +- examples/mbart/README.md | 2 +- examples/nonautoregressive_translation/README.md | 2 +- examples/nonautoregressive_translation/scripts.md | 12 ++++++------ examples/pay_less_attention_paper/README.md | 6 +++--- examples/quant_noise/README.md | 10 +++++----- examples/roberta/README.race.md | 2 +- examples/roberta/commonsense_qa/README.md | 2 +- examples/roberta/wsc/README.md | 4 ++-- examples/translation/README.md | 2 +- examples/translation_moe/README.md | 2 +- examples/wav2vec/config/finetuning/base_100h.yaml | 2 +- examples/wav2vec/config/finetuning/base_10h.yaml | 2 +- examples/wav2vec/config/finetuning/base_10m.yaml | 2 +- examples/wav2vec/config/finetuning/base_1h.yaml | 2 +- examples/wav2vec/config/finetuning/base_960h.yaml | 2 +- examples/wav2vec/config/finetuning/vox_100h.yaml | 2 +- examples/wav2vec/config/finetuning/vox_10h.yaml | 2 +- examples/wav2vec/config/finetuning/vox_10m.yaml | 2 +- examples/wav2vec/config/finetuning/vox_1h.yaml | 2 +- examples/wav2vec/config/finetuning/vox_960h.yaml | 2 +- .../pretraining/wav2vec2_base_librispeech.yaml | 2 +- .../config/pretraining/wav2vec2_large_librivox.yaml | 2 +- fairseq/criterions/adaptive_loss.py | 6 +++--- fairseq/dataclass/configs.py | 8 ++------ fairseq/dataclass/constants.py | 9 +++++++-- fairseq/distributed_utils.py | 2 +- fairseq/models/distributed_fairseq_model.py | 6 +++--- fairseq/trainer.py | 9 +++++---- 32 files changed, 59 insertions(+), 57 deletions(-) diff --git a/examples/cross_lingual_language_model/README.md b/examples/cross_lingual_language_model/README.md index f4c76cfed5..af9128e39e 100644 --- a/examples/cross_lingual_language_model/README.md +++ b/examples/cross_lingual_language_model/README.md @@ -68,7 +68,7 @@ fairseq-train \ --dataset-impl lazy --seed 0 \ --masked-lm-only \ --monolingual-langs 'ar,de,en,hi,fr' --num-segment 5 \ ---ddp-backend=no_c10d +--ddp-backend=legacy_ddp ``` Some Notes: diff --git a/examples/language_model/README.adaptive_inputs.md b/examples/language_model/README.adaptive_inputs.md index 98043c5377..6650d58f37 100644 --- a/examples/language_model/README.adaptive_inputs.md +++ b/examples/language_model/README.adaptive_inputs.md @@ -22,7 +22,7 @@ fairseq-train --task language_modeling \ --max-update 286000 --lr 1.0 --t-mult 2 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 \ --warmup-updates 16000 --warmup-init-lr 1e-07 --stop-min-lr 1e-09 --optimizer nag --min-lr 0.0001 --clip-norm 0.1 \ --criterion adaptive_loss --max-tokens 3072 --update-freq 3 --tokens-per-sample 3072 --seed 1 \ - --sample-break-mode none --skip-invalid-size-inputs-valid-test --ddp-backend=no_c10d + --sample-break-mode none --skip-invalid-size-inputs-valid-test --ddp-backend=legacy_ddp ``` ## Citation diff --git a/examples/language_model/README.conv.md b/examples/language_model/README.conv.md index f0b6a3a921..1ff8635906 100644 --- a/examples/language_model/README.conv.md +++ b/examples/language_model/README.conv.md @@ -17,7 +17,7 @@ fairseq-train --task language_modeling \ --optimizer nag --clip-norm 0.1 --weight-decay 5e-06 \ --lr 1.0 --lr-scheduler reduce_lr_on_plateau --lr-shrink 0.5 \ --max-tokens 1024 --tokens-per-sample 1024 \ - --ddp-backend no_c10d \ + --ddp-backend legacy_ddp \ --max-epoch 35 ``` diff --git a/examples/latent_depth/README.md b/examples/latent_depth/README.md index e70e16405c..7774c33305 100644 --- a/examples/latent_depth/README.md +++ b/examples/latent_depth/README.md @@ -30,7 +30,7 @@ fairseq-train ${databin_dir} \ --lr 0.0015 \ --clip-norm 1.0 \ --seed 2 \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --encoder-layers 12 \ --decoder-layers 24 \ --decoder-latent-layer \ diff --git a/examples/mbart/README.md b/examples/mbart/README.md index 8a3e22d425..a45e37243c 100644 --- a/examples/mbart/README.md +++ b/examples/mbart/README.md @@ -81,7 +81,7 @@ fairseq-train path_2_data \ --restore-file $PRETRAIN \ --reset-optimizer --reset-meters --reset-dataloader --reset-lr-scheduler \ --langs $langs \ - --ddp-backend no_c10d + --ddp-backend legacy_ddp ``` ## Generate on EN-RO Get sacrebleu on finetuned en-ro model diff --git a/examples/nonautoregressive_translation/README.md b/examples/nonautoregressive_translation/README.md index 7b2d42a91d..8793e225c9 100644 --- a/examples/nonautoregressive_translation/README.md +++ b/examples/nonautoregressive_translation/README.md @@ -36,7 +36,7 @@ The following command will train a *Levenshtein Transformer* on the binarized da fairseq-train \ data-bin/wmt14_en_de_distill \ --save-dir checkpoints \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task translation_lev \ --criterion nat_loss \ --arch levenshtein_transformer \ diff --git a/examples/nonautoregressive_translation/scripts.md b/examples/nonautoregressive_translation/scripts.md index a3a33e6e02..9d3d7b67dc 100644 --- a/examples/nonautoregressive_translation/scripts.md +++ b/examples/nonautoregressive_translation/scripts.md @@ -6,7 +6,7 @@ Note that we need to have an additional module to perform "length prediction" (` fairseq-train \ data-bin/wmt14_en_de_distill \ --save-dir checkpoints \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task translation_lev \ --criterion nat_loss \ --arch nonautoregressive_transformer \ @@ -35,7 +35,7 @@ Note that we implemented a low-rank appromixated CRF model by setting `--crf-low fairseq-train \ data-bin/wmt14_en_de_distill \ --save-dir checkpoints \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task translation_lev \ --criterion nat_loss \ --arch nacrf_transformer \ @@ -68,7 +68,7 @@ Note that `--train-step` means how many iterations of refinement we used during fairseq-train \ data-bin/wmt14_en_de_distill \ --save-dir checkpoints \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task translation_lev \ --criterion nat_loss \ --arch iterative_nonautoregressive_transformer \ @@ -101,7 +101,7 @@ Note that we need to specify the "slot-loss" (uniform or balanced tree) describe fairseq-train \ data-bin/wmt14_en_de_distill \ --save-dir checkpoints \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task translation_lev \ --criterion nat_loss \ --arch insertion_transformer \ @@ -128,7 +128,7 @@ fairseq-train \ fairseq-train \ data-bin/wmt14_en_de_distill \ --save-dir checkpoints \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task translation_lev \ --criterion nat_loss \ --arch cmlm_transformer \ @@ -157,7 +157,7 @@ fairseq-train \ fairseq-train \ data-bin/wmt14_en_de_distill \ --save-dir checkpoints \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task translation_lev \ --criterion nat_loss \ --arch levenshtein_transformer \ diff --git a/examples/pay_less_attention_paper/README.md b/examples/pay_less_attention_paper/README.md index d5b19af6cc..5adab11f4d 100644 --- a/examples/pay_less_attention_paper/README.md +++ b/examples/pay_less_attention_paper/README.md @@ -113,7 +113,7 @@ CUDA_VISIBLE_DEVICES=0 $(which fairseq-train) data-bin/iwslt14.tokenized.de-en \ --log-interval 100 --stop-min-lr '1e-09' --weight-decay 0.0001 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --lr-scheduler inverse_sqrt \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --max-update 50000 --warmup-updates 4000 --warmup-init-lr '1e-07' \ --adam-betas '(0.9, 0.98)' --keep-last-epochs 10 \ -a lightconv_iwslt_de_en --save-dir $SAVE \ @@ -138,7 +138,7 @@ python -m torch.distributed.launch --nproc_per_node 8 $(which fairseq-train) \ --adam-betas '(0.9, 0.98)' --clip-norm 0.0 --weight-decay 0.0 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --stop-min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ - --ddp-backend=no_c10d --max-tokens 3584 \ + --ddp-backend=legacy_ddp --max-tokens 3584 \ --lr-scheduler cosine --warmup-init-lr 1e-7 --warmup-updates 10000 \ --lr-shrink 1 --lr 0.001 --min-lr 1e-7 --warmup-init-lr 1e-07 \ --t-mult 1 --lr-period-updates 20000 \ @@ -163,7 +163,7 @@ python -m torch.distributed.launch --nproc_per_node 8 $(which fairseq-train) \ --adam-betas '(0.9, 0.98)' --clip-norm 0.0 --weight-decay 0.0 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --stop-min-lr 1e-09 --update-freq 16 --attention-dropout 0.1 --keep-last-epochs 10 \ - --ddp-backend=no_c10d --max-tokens 3584 \ + --ddp-backend=legacy_ddp --max-tokens 3584 \ --lr-scheduler cosine --warmup-init-lr 1e-7 --warmup-updates 10000 \ --lr-shrink 1 --lr 0.001 --min-lr 1e-7 --warmup-init-lr 1e-07 \ --t-mult 1 --lr-period-updates 70000 \ diff --git a/examples/quant_noise/README.md b/examples/quant_noise/README.md index 7fe301f732..539c3d5af9 100644 --- a/examples/quant_noise/README.md +++ b/examples/quant_noise/README.md @@ -154,7 +154,7 @@ fairseq-train $DATA_DIR \ --batch-size $MAX_SENTENCES \ --update-freq $UPDATE_FREQ --max-update $TOTAL_UPDATES \ --save-dir checkpoint/roberta \ - --ddp-backend no_c10d --encoder-layerdrop 0.2 \ + --ddp-backend legacy_ddp --encoder-layerdrop 0.2 \ --quant-noise-pq 0.2 --quant-noise-pq-block-size 8 --untie-weights-roberta ``` @@ -189,7 +189,7 @@ fairseq-train /path/to/rte/data/ \ --max-epoch 10 \ --find-unused-parameters \ --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric \ - --ddp-backend no_c10d \ + --ddp-backend legacy_ddp \ --quant-noise-pq 0.2 --quant-noise-pq-block-size 8 ``` @@ -205,7 +205,7 @@ fairseq-train --task language_modeling /path/to/wikitext-103/data \ --arch transformer_lm_gbw \ --attention-dropout 0.1 --dropout 0.2 --relu-dropout 0.1 \ --clip-norm 0.1 --criterion adaptive_loss \ - --ddp-backend no_c10d \ + --ddp-backend legacy_ddp \ --decoder-attention-heads 8 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-input-dim 1024 \ --decoder-layers 16 --decoder-normalize-before --decoder-output-dim 1024 \ --min-lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --lr 1.0 --t-mult 2.0 \ @@ -252,7 +252,7 @@ fairseq-train --task sentence_prediction /path/to/data/ \ --weight-decay 0.1 --optimizer adam --adam-betas "(0.9, 0.98)" --adam-eps 1e-06 \ --clip-norm 0.0 --lr-scheduler polynomial_decay \ --fp16 --fp16-init-scale 4 --threshold-loss-scale 1 --fp16-scale-window 128 \ - --no-progress-bar --skip-invalid-size-inputs-valid-test --ddp-backend no_c10d \ + --no-progress-bar --skip-invalid-size-inputs-valid-test --ddp-backend legacy_ddp \ --quantization-config-path /path/to/config/yaml ``` @@ -266,7 +266,7 @@ fairseq-train --task language_modeling /path/to/wikitext-103/data \ --attention-dropout 0.1 --dropout 0.2 --relu-dropout 0.1 \ --bucket-cap-mb 25 --char-embedder-highway-layers 2 --character-embedding-dim 4 \ --clip-norm 0.1 --criterion adaptive_loss \ - --ddp-backend no_c10d \ + --ddp-backend legacy_ddp \ --decoder-attention-heads 8 --decoder-embed-dim 1024 --decoder-ffn-embed-dim 4096 --decoder-input-dim 1024 --decoder-layers 16 --decoder-normalize-before --decoder-output-dim 1024 \ --fp16 --keep-last-epochs -1 \ --min-lr 0.0001 --lr-period-updates 270000 --lr-scheduler cosine --lr-shrink 0.75 --lr 0.05 --stop-min-lr 1e-09 \ diff --git a/examples/roberta/README.race.md b/examples/roberta/README.race.md index 527a0bce14..13c917e8ec 100644 --- a/examples/roberta/README.race.md +++ b/examples/roberta/README.race.md @@ -19,7 +19,7 @@ UPDATE_FREQ=8 # Accumulate gradients to simulate training on 8 GPUs. DATA_DIR=/path/to/race-output-dir ROBERTA_PATH=/path/to/roberta/model.pt -CUDA_VISIBLE_DEVICES=0,1 fairseq-train $DATA_DIR --ddp-backend=no_c10d \ +CUDA_VISIBLE_DEVICES=0,1 fairseq-train $DATA_DIR --ddp-backend=legacy_ddp \ --restore-file $ROBERTA_PATH \ --reset-optimizer --reset-dataloader --reset-meters \ --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric \ diff --git a/examples/roberta/commonsense_qa/README.md b/examples/roberta/commonsense_qa/README.md index 4f371f8b30..05c6f841a8 100644 --- a/examples/roberta/commonsense_qa/README.md +++ b/examples/roberta/commonsense_qa/README.md @@ -39,7 +39,7 @@ DATA_DIR=data/CommonsenseQA FAIRSEQ_PATH=/path/to/fairseq FAIRSEQ_USER_DIR=${FAIRSEQ_PATH}/examples/roberta/commonsense_qa -CUDA_VISIBLE_DEVICES=0 fairseq-train --fp16 --ddp-backend=no_c10d \ +CUDA_VISIBLE_DEVICES=0 fairseq-train --fp16 --ddp-backend=legacy_ddp \ $DATA_DIR \ --user-dir $FAIRSEQ_USER_DIR \ --restore-file $ROBERTA_PATH \ diff --git a/examples/roberta/wsc/README.md b/examples/roberta/wsc/README.md index d40da6a5fd..21a045d999 100644 --- a/examples/roberta/wsc/README.md +++ b/examples/roberta/wsc/README.md @@ -51,7 +51,7 @@ CUDA_VISIBLE_DEVICES=0,1,2,3 fairseq-train WSC/ \ --no-epoch-checkpoints --no-last-checkpoints --no-save-optimizer-state \ --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric \ --valid-subset val \ - --fp16 --ddp-backend no_c10d \ + --fp16 --ddp-backend legacy_ddp \ --user-dir $FAIRSEQ_USER_DIR \ --task wsc --criterion wsc --wsc-cross-entropy \ --arch roberta_large --bpe gpt2 --max-positions 512 \ @@ -110,7 +110,7 @@ CUDA_VISIBLE_DEVICES=0 fairseq-train winogrande_1.0/ \ --no-epoch-checkpoints --no-last-checkpoints --no-save-optimizer-state \ --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric \ --valid-subset val \ - --fp16 --ddp-backend no_c10d \ + --fp16 --ddp-backend legacy_ddp \ --user-dir $FAIRSEQ_USER_DIR \ --task winogrande --criterion winogrande \ --wsc-margin-alpha 5.0 --wsc-margin-beta 0.4 \ diff --git a/examples/translation/README.md b/examples/translation/README.md index 7b1fcc8de2..2941f5eb84 100644 --- a/examples/translation/README.md +++ b/examples/translation/README.md @@ -263,7 +263,7 @@ fairseq-preprocess --source-lang fr --target-lang en \ mkdir -p checkpoints/multilingual_transformer CUDA_VISIBLE_DEVICES=0 fairseq-train data-bin/iwslt17.de_fr.en.bpe16k/ \ --max-epoch 50 \ - --ddp-backend=no_c10d \ + --ddp-backend=legacy_ddp \ --task multilingual_translation --lang-pairs de-en,fr-en \ --arch multilingual_transformer_iwslt_de_en \ --share-decoders --share-decoder-input-output-embed \ diff --git a/examples/translation_moe/README.md b/examples/translation_moe/README.md index 3cc3fb46dc..2e5c8af617 100644 --- a/examples/translation_moe/README.md +++ b/examples/translation_moe/README.md @@ -15,7 +15,7 @@ The model is trained with online responsibility assignment and shared parameteri The following command will train a `hMoElp` model with `3` experts: ```bash -fairseq-train --ddp-backend='no_c10d' \ +fairseq-train --ddp-backend='legacy_ddp' \ data-bin/wmt17_en_de \ --max-update 100000 \ --task translation_moe --user-dir examples/translation_moe/translation_moe_src \ diff --git a/examples/wav2vec/config/finetuning/base_100h.yaml b/examples/wav2vec/config/finetuning/base_100h.yaml index 7d1664a184..539dabb047 100644 --- a/examples/wav2vec/config/finetuning/base_100h.yaml +++ b/examples/wav2vec/config/finetuning/base_100h.yaml @@ -22,7 +22,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 2 criterion: diff --git a/examples/wav2vec/config/finetuning/base_10h.yaml b/examples/wav2vec/config/finetuning/base_10h.yaml index 31125947c0..16a3c4d96c 100644 --- a/examples/wav2vec/config/finetuning/base_10h.yaml +++ b/examples/wav2vec/config/finetuning/base_10h.yaml @@ -27,7 +27,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 2 criterion: diff --git a/examples/wav2vec/config/finetuning/base_10m.yaml b/examples/wav2vec/config/finetuning/base_10m.yaml index 2235504489..3ceb77a252 100644 --- a/examples/wav2vec/config/finetuning/base_10m.yaml +++ b/examples/wav2vec/config/finetuning/base_10m.yaml @@ -27,7 +27,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 2 criterion: diff --git a/examples/wav2vec/config/finetuning/base_1h.yaml b/examples/wav2vec/config/finetuning/base_1h.yaml index 2235504489..3ceb77a252 100644 --- a/examples/wav2vec/config/finetuning/base_1h.yaml +++ b/examples/wav2vec/config/finetuning/base_1h.yaml @@ -27,7 +27,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 2 criterion: diff --git a/examples/wav2vec/config/finetuning/base_960h.yaml b/examples/wav2vec/config/finetuning/base_960h.yaml index d742c94abf..e393805ad8 100644 --- a/examples/wav2vec/config/finetuning/base_960h.yaml +++ b/examples/wav2vec/config/finetuning/base_960h.yaml @@ -22,7 +22,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 8 criterion: diff --git a/examples/wav2vec/config/finetuning/vox_100h.yaml b/examples/wav2vec/config/finetuning/vox_100h.yaml index 8885c78470..2fdb0c568c 100644 --- a/examples/wav2vec/config/finetuning/vox_100h.yaml +++ b/examples/wav2vec/config/finetuning/vox_100h.yaml @@ -22,7 +22,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 4 criterion: diff --git a/examples/wav2vec/config/finetuning/vox_10h.yaml b/examples/wav2vec/config/finetuning/vox_10h.yaml index c0957c0058..f1a979e05d 100644 --- a/examples/wav2vec/config/finetuning/vox_10h.yaml +++ b/examples/wav2vec/config/finetuning/vox_10h.yaml @@ -27,7 +27,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 4 criterion: diff --git a/examples/wav2vec/config/finetuning/vox_10m.yaml b/examples/wav2vec/config/finetuning/vox_10m.yaml index 0d567552d7..d12439bb28 100644 --- a/examples/wav2vec/config/finetuning/vox_10m.yaml +++ b/examples/wav2vec/config/finetuning/vox_10m.yaml @@ -27,7 +27,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 4 criterion: diff --git a/examples/wav2vec/config/finetuning/vox_1h.yaml b/examples/wav2vec/config/finetuning/vox_1h.yaml index 10c45a52d8..7f3b04c034 100644 --- a/examples/wav2vec/config/finetuning/vox_1h.yaml +++ b/examples/wav2vec/config/finetuning/vox_1h.yaml @@ -27,7 +27,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 4 criterion: diff --git a/examples/wav2vec/config/finetuning/vox_960h.yaml b/examples/wav2vec/config/finetuning/vox_960h.yaml index 6212a2e738..0633915bb2 100644 --- a/examples/wav2vec/config/finetuning/vox_960h.yaml +++ b/examples/wav2vec/config/finetuning/vox_960h.yaml @@ -22,7 +22,7 @@ dataset: valid_subset: dev_other distributed_training: - ddp_backend: no_c10d + ddp_backend: legacy_ddp distributed_world_size: 24 criterion: diff --git a/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml b/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml index e2c2b7b0b3..767aee2852 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml @@ -23,7 +23,7 @@ dataset: distributed_training: distributed_world_size: 64 - ddp_backend: no_c10d + ddp_backend: legacy_ddp criterion: _name: wav2vec diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml index 0c911b7491..bee41157a9 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml @@ -24,7 +24,7 @@ dataset: distributed_training: distributed_world_size: 128 - ddp_backend: no_c10d + ddp_backend: legacy_ddp criterion: _name: wav2vec diff --git a/fairseq/criterions/adaptive_loss.py b/fairseq/criterions/adaptive_loss.py index 15ad9a15bf..6209ceaedb 100644 --- a/fairseq/criterions/adaptive_loss.py +++ b/fairseq/criterions/adaptive_loss.py @@ -32,11 +32,11 @@ def __init__(self, task, sentence_avg): @classmethod def build_criterion(cls, cfg: AdaptiveLossConfig, task): - if cfg.ddp_backend == "c10d": + if cfg.ddp_backend in {"c10d", "pytorch_ddp"}: raise Exception( - "AdaptiveLoss is not compatible with the c10d " + "AdaptiveLoss is not compatible with the PyTorch " "version of DistributedDataParallel. Please use " - "`--ddp-backend=no_c10d` instead." + "`--ddp-backend=legacy_ddp` instead." ) return cls(task, cfg.sentence_avg) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 2ed27284dc..f66e98fe83 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -12,7 +12,6 @@ from fairseq.dataclass.constants import ( DATASET_IMPL_CHOICES, DDP_BACKEND_CHOICES, - DISTRIBUTED_WRAPPER_CHOICES, GENERATION_CONSTRAINTS_CHOICES, GENERATION_DECODING_FORMAT_CHOICES, LOG_FORMAT_CHOICES, @@ -236,7 +235,7 @@ class DistributedTrainingConfig(FairseqDataclass): }, ) ddp_backend: DDP_BACKEND_CHOICES = field( - default="c10d", metadata={"help": "DistributedDataParallel backend"} + default="pytorch_ddp", metadata={"help": "DistributedDataParallel backend"} ) bucket_cap_mb: int = field( default=25, metadata={"help": "bucket size for reduction"} @@ -252,7 +251,7 @@ class DistributedTrainingConfig(FairseqDataclass): default=False, metadata={ "help": "disable unused parameter detection (not applicable to " - "no_c10d ddp-backend" + "--ddp-backend=legacy_ddp)" }, ) fast_stat_sync: bool = field( @@ -273,9 +272,6 @@ class DistributedTrainingConfig(FairseqDataclass): "batchnorm population statistics" }, ) - distributed_wrapper: DISTRIBUTED_WRAPPER_CHOICES = field( - default="DDP", metadata={"help": "DistributedDataParallel backend"} - ) slowmo_momentum: Optional[float] = field( default=None, metadata={ diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 46881786a8..93bc6d03cb 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -35,9 +35,14 @@ def ChoiceEnum(choices: List[str]): LOG_FORMAT_CHOICES = ChoiceEnum(["json", "none", "simple", "tqdm"]) -DDP_BACKEND_CHOICES = ChoiceEnum(["c10d", "no_c10d"]) +DDP_BACKEND_CHOICES = ChoiceEnum([ + "c10d", # alias for pytorch_ddp + "legacy_ddp", + "no_c10d", # alias for legacy_ddp + "pytorch_ddp", + "slow_mo", +]) DATASET_IMPL_CHOICES = ChoiceEnum(["raw", "lazy", "cached", "mmap", "fasta"]) -DISTRIBUTED_WRAPPER_CHOICES = ChoiceEnum(["DDP", "SlowMo"]) GENERATION_CONSTRAINTS_CHOICES = ChoiceEnum(["ordered", "unordered"]) GENERATION_DECODING_FORMAT_CHOICES = ChoiceEnum( ["unigram", "ensemble", "vote", "dp", "bs"] diff --git a/fairseq/distributed_utils.py b/fairseq/distributed_utils.py index 37822362d4..3b5fe6e7a8 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed_utils.py @@ -591,7 +591,7 @@ def all_gather_list(data, group=None, max_size=16384): "sync if one of them runs out of memory, or if there are other conditions " "in your training script that can cause one worker to finish an epoch " "while other workers are still iterating over their portions of the data. " - "Try rerunning with --ddp-backend=no_c10d and see if that helps." + "Try rerunning with --ddp-backend=legacy_ddp and see if that helps." ) diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index ffa3c37b19..b8fbc37793 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -49,7 +49,7 @@ def DistributedFairseqModel(args, model, process_group): module=model, process_group=process_group, ) - elif args.distributed_wrapper == "DDP" and args.ddp_backend == "c10d": + elif args.ddp_backend in {"c10d", "pytorch_ddp"}: ddp_class = nn.parallel.DistributedDataParallel init_kwargs = dict( module=model, @@ -62,14 +62,14 @@ def DistributedFairseqModel(args, model, process_group): # Maintain backward compatibility if "find_unused_parameters" in inspect.getargspec(ddp_class)[0]: init_kwargs["find_unused_parameters"] = args.find_unused_parameters - elif args.distributed_wrapper == "DDP" and args.ddp_backend == "no_c10d": + elif args.ddp_backend in {"no_c10d", "legacy_ddp"}: ddp_class = LegacyDistributedDataParallel init_kwargs = dict( module=model, buffer_size=2 ** 28, process_group=process_group, ) - elif args.distributed_wrapper == "SlowMo": + elif args.ddp_backend == "slow_mo": if _GOSSIP_DISABLED: raise ImportError( "Cannot find gossip library. Please install from: " diff --git a/fairseq/trainer.py b/fairseq/trainer.py index eea194b950..d893518fea 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -646,7 +646,7 @@ def maybe_no_sync(): if not self.tpu: if ( not self.cfg.optimization.use_bmuf - and self.cfg.distributed_training.distributed_wrapper != "SlowMo" + and self.cfg.distributed_training.ddp_backend != "slow_mo" ): self._check_grad_norms(grad_norm) if not torch.isfinite(grad_norm).all(): @@ -686,7 +686,8 @@ def maybe_no_sync(): logger.error("OOM during optimization, irrecoverable") raise e - # Some distributed wrappers (e.g., SlowMo) need access to the optimizer after the step + # Some distributed wrappers (e.g., SlowMo) need access to the optimizer + # after the step if hasattr(self.model, "perform_additional_optimizer_actions"): if hasattr(self.optimizer, "fp32_params"): self.model.perform_additional_optimizer_actions( @@ -700,7 +701,7 @@ def maybe_no_sync(): logging_output = None if ( not overflow - or self.cfg.distributed_training.distributed_wrapper == "SlowMo" + or self.cfg.distributed_training.ddp_backend == "slow_mo" ): self.set_num_updates(self.get_num_updates() + 1) @@ -1120,7 +1121,7 @@ def is_consistent(tensor): # use FloatingPointError to trigger NanDetector raise FloatingPointError( "Fatal error: gradients are inconsistent between workers. " - "Try --ddp-backend=no_c10d. " + "Try --ddp-backend=legacy_ddp. " "Or are you mixing up different generation of GPUs in training?" + "\n" + "-" * 80 From 922528d58feea5ada68094df117c1cdbe67aec45 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 28 Jan 2021 14:18:48 -0800 Subject: [PATCH 175/774] Log amount of free GPU memory (#1545) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1545 Test Plan: Imported from OSS Reviewed By: girifb Differential Revision: D25836854 Pulled By: myleott fbshipit-source-id: 6bb5cb69a90022aa206618ee7a903a653fb1ed09 --- fairseq/trainer.py | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index d893518fea..274d556ea2 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -600,11 +600,7 @@ def maybe_no_sync(): ooms, total_train_time, ) = self._aggregate_logging_outputs( - logging_outputs, - sample_size, - ooms, - train_time, - ignore=is_dummy_batch, + logging_outputs, sample_size, ooms, train_time, ignore=is_dummy_batch ) self._cumulative_training_time = ( total_train_time / self.data_parallel_world_size @@ -699,10 +695,7 @@ def maybe_no_sync(): ) logging_output = None - if ( - not overflow - or self.cfg.distributed_training.ddp_backend == "slow_mo" - ): + if not overflow or self.cfg.distributed_training.ddp_backend == "slow_mo": self.set_num_updates(self.get_num_updates() + 1) if self.tpu: @@ -720,24 +713,14 @@ def maybe_no_sync(): gb_free = mem_info["kb_free"] / 1024 / 1024 gb_total = mem_info["kb_total"] / 1024 / 1024 metrics.log_scalar( - "gb_free", - gb_free, - priority=1500, - round=1, - weight=0, + "gb_free", gb_free, priority=1500, round=1, weight=0 ) metrics.log_scalar( - "gb_total", - gb_total, - priority=1600, - round=1, - weight=0, + "gb_total", gb_total, priority=1600, round=1, weight=0 ) logging_output = self._reduce_and_log_stats( - logging_outputs, - sample_size, - grad_norm, + logging_outputs, sample_size, grad_norm ) # log whenever there's an XLA compilation, since these @@ -745,11 +728,18 @@ def maybe_no_sync(): # optimization self._check_xla_compilation() else: + if self.cuda and self.cuda_env is not None: + # log minimum free memory over the iteration + gb_used = torch.cuda.max_memory_allocated() / 1024 / 1024 / 1024 + torch.cuda.reset_peak_memory_stats() + gb_free = self.cuda_env.total_memory_in_GB - gb_used + metrics.log_scalar( + "gb_free", gb_free, priority=1500, round=1, weight=0 + ) + # log stats logging_output = self._reduce_and_log_stats( - logging_outputs, - sample_size, - grad_norm, + logging_outputs, sample_size, grad_norm ) # clear CUDA cache to reduce memory fragmentation From d68a3530dda7f8275e490864b28974ef30fe854b Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 28 Jan 2021 14:18:48 -0800 Subject: [PATCH 176/774] Refactor distributed code under fairseq.distributed (#1546) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1546 Test Plan: Imported from OSS Reviewed By: girifb Differential Revision: D25836853 Pulled By: myleott fbshipit-source-id: c5076615d49774633ecfaf0aa68b68e8b2331bd9 --- fairseq/__init__.py | 1 + fairseq/distributed/__init__.py | 17 +++ .../distributed_timeout_wrapper.py | 94 +++++++++++++ .../legacy_distributed_data_parallel.py | 11 +- fairseq/distributed/module_proxy_wrapper.py | 55 ++++++++ .../tpu_distributed_data_parallel.py | 43 ++++++ fairseq/models/distributed_fairseq_model.py | 131 +++++------------- fairseq/trainer.py | 27 +++- .../test_distributed_timeout_wrapper.py | 54 ++++++++ .../distributed/test_module_proxy_wrapper.py | 75 ++++++++++ 10 files changed, 391 insertions(+), 117 deletions(-) create mode 100644 fairseq/distributed/__init__.py create mode 100644 fairseq/distributed/distributed_timeout_wrapper.py rename fairseq/{ => distributed}/legacy_distributed_data_parallel.py (96%) create mode 100644 fairseq/distributed/module_proxy_wrapper.py create mode 100644 fairseq/distributed/tpu_distributed_data_parallel.py create mode 100644 tests/distributed/test_distributed_timeout_wrapper.py create mode 100644 tests/distributed/test_module_proxy_wrapper.py diff --git a/fairseq/__init__.py b/fairseq/__init__.py index ccd45add79..8e51b61be0 100644 --- a/fairseq/__init__.py +++ b/fairseq/__init__.py @@ -28,6 +28,7 @@ hydra_init() import fairseq.criterions # noqa +import fairseq.distributed # noqa import fairseq.models # noqa import fairseq.modules # noqa import fairseq.optim # noqa diff --git a/fairseq/distributed/__init__.py b/fairseq/distributed/__init__.py new file mode 100644 index 0000000000..7f4016e38c --- /dev/null +++ b/fairseq/distributed/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .distributed_timeout_wrapper import DistributedTimeoutWrapper +from .legacy_distributed_data_parallel import LegacyDistributedDataParallel +from .module_proxy_wrapper import ModuleProxyWrapper +from .tpu_distributed_data_parallel import TPUDistributedDataParallel + + +__all__ = [ + "DistributedTimeoutWrapper", + "LegacyDistributedDataParallel", + "ModuleProxyWrapper", + "TPUDistributedDataParallel", +] diff --git a/fairseq/distributed/distributed_timeout_wrapper.py b/fairseq/distributed/distributed_timeout_wrapper.py new file mode 100644 index 0000000000..c8ab477073 --- /dev/null +++ b/fairseq/distributed/distributed_timeout_wrapper.py @@ -0,0 +1,94 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import signal +import threading + +from torch import nn + + +logger = logging.getLogger(__name__) + + +class DistributedTimeoutWrapper(nn.Module): + """ + A wrapper that kills the process if no progress is made within a given + *timeout*. The timer is reset every time :func:`forward` is called. + + Usage:: + + module = DistributedTimeoutWrapper(module, timeout=30) + x = module(input) + time.sleep(20) # safe + x = module(input) + time.sleep(45) # job will be killed before this returns + + Args: + module (nn.Module): module to wrap + timeout (int): number of seconds before killing the process + (set to a value <= 0 to disable the timeout) + signal (Optional): signal to send once timeout is triggered + """ + def __init__(self, module: nn.Module, timeout: int, signal=signal.SIGKILL): + super().__init__() + self.module = module + self.timeout = timeout + self.signal = signal + + if timeout > 0: + self._heartbeat = threading.Event() + self._heartbeat_thread = threading.Thread( + target=self._check_heartbeat, + args=(os.getpid(),), + daemon=True, + ) + self._heartbeat_thread.start() + self._terminated = False + else: + self._heartbeat = None + self._heartbeat_thread = None + + def __del__(self): + self.stop_timeout() + + def __getattr__(self, name): + """Forward missing attributes to wrapped module.""" + try: + return super().__getattr__(name) # defer to nn.Module's logic + except AttributeError: + return getattr(self.module, name) + + def stop_timeout(self): + if self._heartbeat_thread is not None: + self._terminated = True + self._heartbeat_thread.join() + + def state_dict(self, *args, **kwargs): + return self.module.state_dict(*args, **kwargs) + + def load_state_dict(self, *args, **kwargs): + return self.module.load_state_dict(*args, **kwargs) + + def forward(self, *args, **kwargs): + if self._heartbeat is not None: + self._heartbeat.set() + return self.module(*args, **kwargs) + + def _check_heartbeat(self, parent_pid): + self._heartbeat.wait() # wait for the first forward pass + while True: + self._heartbeat.clear() + success = self._heartbeat.wait(timeout=self.timeout) + if self._terminated: + break + elif not success: + logger.error(( + "Killing job for not making progress in {} seconds. " + "Set --heartbeat-timeout=-1 to disable this timeout." + ).format(int(self.timeout))) + os.kill(parent_pid, self.signal) + return diff --git a/fairseq/legacy_distributed_data_parallel.py b/fairseq/distributed/legacy_distributed_data_parallel.py similarity index 96% rename from fairseq/legacy_distributed_data_parallel.py rename to fairseq/distributed/legacy_distributed_data_parallel.py index 7e176eaf3d..35de179b2f 100644 --- a/fairseq/legacy_distributed_data_parallel.py +++ b/fairseq/distributed/legacy_distributed_data_parallel.py @@ -14,15 +14,13 @@ training with `--update-freq`. """ -import copy from collections import OrderedDict from contextlib import contextmanager import torch from torch import nn -from torch.autograd import Variable -from . import distributed_utils +from fairseq import distributed_utils class LegacyDistributedDataParallel(nn.Module): @@ -64,13 +62,6 @@ def __init__(self, module, process_group, buffer_size=2 ** 28): paramlists[device] += [param] self.per_device_params = list(paramlists.values()) - def __getstate__(self): - attrs = copy.copy(self.__dict__) - return attrs - - def __setstate__(self, state): - super().__setstate__(state) - @contextmanager def no_sync(self): """A context manager to disable gradient synchronization.""" diff --git a/fairseq/distributed/module_proxy_wrapper.py b/fairseq/distributed/module_proxy_wrapper.py new file mode 100644 index 0000000000..fc2c6f8c71 --- /dev/null +++ b/fairseq/distributed/module_proxy_wrapper.py @@ -0,0 +1,55 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from torch import nn + + +class ModuleProxyWrapper(nn.Module): + """ + Wrap a DistributedDataParallel module and forward requests for missing + attributes to the module wrapped by DDP (the twice-wrapped module). + Also forward calls to :func:`state_dict` and :func:`load_state_dict`. + + Usage:: + + module.xyz = "hello world" + wrapped_module = DistributedDataParallel(module, **ddp_args) + wrapped_module = ModuleProxyWrapper(wrapped_module) + assert wrapped_module.xyz == "hello world" + assert wrapped_module.state_dict().keys() == module.state_dict().keys() + + Args: + module (nn.Module): module to wrap + """ + + def __init__(self, module: nn.Module): + super().__init__() + assert hasattr(module, "module"), \ + "ModuleProxyWrapper expects input to wrap another module" + self.module = module + + def __getattr__(self, name): + """Forward missing attributes to twice-wrapped module.""" + try: + # defer to nn.Module's logic + return super().__getattr__(name) + except AttributeError: + try: + # forward to the once-wrapped module + return getattr(self.module, name) + except AttributeError: + # forward to the twice-wrapped module + return getattr(self.module.module, name) + + def state_dict(self, *args, **kwargs): + """Forward to the twice-wrapped module.""" + return self.module.module.state_dict(*args, **kwargs) + + def load_state_dict(self, *args, **kwargs): + """Forward to the twice-wrapped module.""" + return self.module.module.load_state_dict(*args, **kwargs) + + def forward(self, *args, **kwargs): + return self.module(*args, **kwargs) diff --git a/fairseq/distributed/tpu_distributed_data_parallel.py b/fairseq/distributed/tpu_distributed_data_parallel.py new file mode 100644 index 0000000000..2adcf1cb58 --- /dev/null +++ b/fairseq/distributed/tpu_distributed_data_parallel.py @@ -0,0 +1,43 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from torch import nn + +from fairseq import distributed_utils + + +class TPUDistributedDataParallel(nn.Module): + + def __init__(self, module, process_group): + super().__init__() + self.module = module + self.process_group = process_group + self.world_size = distributed_utils.get_world_size(self.process_group) + + def forward(self, *inputs, **kwargs): + return self.module(*inputs, **kwargs) + + def all_reduce_grads(self): + gradients = [] + for p in self.parameters(): + if not p.requires_grad: + continue + if p.grad is None: + p.grad = torch.zeros_like(p) + if p.grad.requires_grad: + raise RuntimeError( + "TPUDistributedDataParallel only works with gradients that don't " + "require grad" + ) + gradients.append(p.grad) + + import torch_xla.core.xla_model as xm + xm.all_reduce( + 'sum', + gradients, + scale=1. / self.world_size, + groups=self.process_group[1], + ) diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index b8fbc37793..bee1033110 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -3,7 +3,6 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import inspect import logging import os import signal @@ -11,9 +10,15 @@ import torch import torch.nn as nn +from torch.nn.parallel import DistributedDataParallel from fairseq import distributed_utils -from fairseq.legacy_distributed_data_parallel import LegacyDistributedDataParallel +from fairseq.distributed import ( + DistributedTimeoutWrapper, + LegacyDistributedDataParallel, + ModuleProxyWrapper, + TPUDistributedDataParallel, +) logger = logging.getLogger(__name__) @@ -26,7 +31,7 @@ _GOSSIP_DISABLED = True -def DistributedFairseqModel(args, model, process_group): +def DistributedFairseqModel(args, model, process_group, device): """ Wrap a *model* to support distributed data parallel training. @@ -40,42 +45,42 @@ def DistributedFairseqModel(args, model, process_group): model (BaseFairseqModel): model to wrap process_group: the c10d process group to be used for distributed data parallel all-reduction. + device: device to move model to """ - # determine which DDP class to extend assert isinstance(model, nn.Module) if args.tpu: - ddp_class = TPUDistributedDataParallel - init_kwargs = dict( - module=model, + wrapped_model = TPUDistributedDataParallel( + module=model.to(device), process_group=process_group, ) + # forward missing getattr and state_dict/load_state_dict to orig model + wrapped_model = ModuleProxyWrapper(wrapped_model) elif args.ddp_backend in {"c10d", "pytorch_ddp"}: - ddp_class = nn.parallel.DistributedDataParallel - init_kwargs = dict( - module=model, + wrapped_model = DistributedDataParallel( + module=model.to(device), device_ids=[args.device_id], output_device=args.device_id, broadcast_buffers=args.broadcast_buffers, bucket_cap_mb=args.bucket_cap_mb, process_group=process_group, + find_unused_parameters=args.find_unused_parameters, ) - # Maintain backward compatibility - if "find_unused_parameters" in inspect.getargspec(ddp_class)[0]: - init_kwargs["find_unused_parameters"] = args.find_unused_parameters + # forward missing getattr and state_dict/load_state_dict to orig model + wrapped_model = ModuleProxyWrapper(wrapped_model) elif args.ddp_backend in {"no_c10d", "legacy_ddp"}: - ddp_class = LegacyDistributedDataParallel - init_kwargs = dict( - module=model, + wrapped_model = LegacyDistributedDataParallel( + module=model.to(device), buffer_size=2 ** 28, process_group=process_group, ) + # forward missing getattr and state_dict/load_state_dict to orig model + wrapped_model = ModuleProxyWrapper(wrapped_model) elif args.ddp_backend == "slow_mo": if _GOSSIP_DISABLED: raise ImportError( "Cannot find gossip library. Please install from: " "github.com/facebookresearch/stochastic_gradient_push" ) - ddp_class = gossip.GossipDataParallel # The values of slowmo_momentum below were obtained by tuning on the # En-De 16 dataset by training the transformer_wmt_en_de_large model @@ -89,8 +94,8 @@ def DistributedFairseqModel(args, model, process_group): else: args.slowmo_momentum = 0.6 - init_kwargs = dict( - module=model, + wrapped_model = gossip.GossipDataParallel( + module=model.to(device), device_ids=[args.device_id], output_device=args.device_id, broadcast_buffers=args.broadcast_buffers, @@ -99,88 +104,14 @@ def DistributedFairseqModel(args, model, process_group): localsgd=(args.slowmo_algorithm == "LocalSGD"), localsgd_frequency=args.localsgd_frequency, ) + # forward missing getattr and state_dict/load_state_dict to orig model + wrapped_model = ModuleProxyWrapper(wrapped_model) else: raise ValueError("Unknown --ddp-backend: " + args.ddp_backend) - heartbeat_timeout = getattr(args, "heartbeat_timeout", -1) + # kill hung distributed jobs after a timeout + wrapped_model = DistributedTimeoutWrapper( + wrapped_model, timeout=getattr(args, "heartbeat_timeout", -1) + ) - class _DistributedFairseqModel(ddp_class): - """ - Extend DistributedDataParallel to check for missing attributes in the - wrapped module and to add a timeout to kill the job if no progress is - made (--heartbeat-timeout). - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._heartbeat_timeout = heartbeat_timeout - if self._heartbeat_timeout > 0: - self._heartbeat = threading.Event() - self._heartbeat_thread = threading.Thread( - target=self._check_heartbeat, - args=(os.getpid(),), - daemon=True, - ) - self._heartbeat_thread.start() - else: - self._heartbeat = None - - def _check_heartbeat(self, parent_pid): - self._heartbeat.wait() # wait for the first forward pass - while True: - self._heartbeat.clear() - success = self._heartbeat.wait(timeout=self._heartbeat_timeout) - if not success: - logger.error(( - "Killing job for not making progress in {} seconds. " - "Set --heartbeat-timeout=-1 to disable this timeout." - ).format(int(self._heartbeat_timeout))) - os.kill(parent_pid, signal.SIGKILL) - return - - def __getattr__(self, name): - wrapped_module = super().__getattr__("module") - if hasattr(wrapped_module, name): - return getattr(wrapped_module, name) - return super().__getattr__(name) - - def forward(self, *args, **kwargs): - if self._heartbeat is not None: - self._heartbeat.set() - return super().forward(*args, **kwargs) - - return _DistributedFairseqModel(**init_kwargs) - - -class TPUDistributedDataParallel(nn.Module): - - def __init__(self, module, process_group): - super().__init__() - self.module = module - self.process_group = process_group - self.world_size = distributed_utils.get_world_size(self.process_group) - - def forward(self, *inputs, **kwargs): - return self.module(*inputs, **kwargs) - - def all_reduce_grads(self): - gradients = [] - for p in self.parameters(): - if not p.requires_grad: - continue - if p.grad is None: - p.grad = torch.zeros_like(p) - if p.grad.requires_grad: - raise RuntimeError( - "TPUDistributedDataParallel only works with gradients that don't " - "require grad" - ) - gradients.append(p.grad) - - import torch_xla.core.xla_model as xm - xm.all_reduce( - 'sum', - gradients, - scale=1. / self.world_size, - groups=self.process_group[1], - ) + return wrapped_model diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 274d556ea2..b441eaa4d2 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -69,7 +69,12 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): elif cfg.common.bf16: self._criterion = self._criterion.to(dtype=torch.bfloat16) self._model = self._model.to(dtype=torch.bfloat16) - if not cfg.distributed_training.pipeline_model_parallel: + if ( + not cfg.distributed_training.pipeline_model_parallel + # the DistributedFairseqModel wrapper will handle moving to device, + # so only handle cases which don't use the wrapper + and not self.use_distributed_wrapper + ): self._criterion = self._criterion.to(device=self.device) self._model = self._model.to(device=self.device) self.pipeline_model_parallel = cfg.distributed_training.pipeline_model_parallel @@ -158,18 +163,25 @@ def is_data_parallel_master(self): # parallel rank 0 return self.data_parallel_rank == 0 + @property + def use_distributed_wrapper(self) -> bool: + return ( + self.data_parallel_world_size > 1 + and not self.cfg.optimization.use_bmuf + ) + @property def criterion(self): if self._wrapped_criterion is None: if ( utils.has_parameters(self._criterion) - and self.data_parallel_world_size > 1 - and not self.cfg.optimization.use_bmuf + and self.use_distributed_wrapper ): self._wrapped_criterion = models.DistributedFairseqModel( self.cfg.distributed_training, self._criterion, process_group=self.data_parallel_process_group, + device=self.device, ) else: self._wrapped_criterion = self._criterion @@ -178,11 +190,12 @@ def criterion(self): @property def model(self): if self._wrapped_model is None: - if self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf: + if self.use_distributed_wrapper: self._wrapped_model = models.DistributedFairseqModel( self.cfg.distributed_training, self._model, process_group=self.data_parallel_process_group, + device=self.device, ) else: self._wrapped_model = self._model @@ -268,8 +281,8 @@ def save_checkpoint(self, filename, extra_state): checkpoint_utils.save_state( filename, self.cfg, - self.get_model().state_dict(), - self.get_criterion(), + self.model.state_dict(), + self.criterion, self.optimizer, self.lr_scheduler, self.get_num_updates(), @@ -336,7 +349,7 @@ def load_checkpoint( # load model parameters try: - self.get_model().load_state_dict( + self.model.load_state_dict( state["model"], strict=True, model_cfg=self.cfg.model ) if utils.has_parameters(self.get_criterion()): diff --git a/tests/distributed/test_distributed_timeout_wrapper.py b/tests/distributed/test_distributed_timeout_wrapper.py new file mode 100644 index 0000000000..27908b9d3f --- /dev/null +++ b/tests/distributed/test_distributed_timeout_wrapper.py @@ -0,0 +1,54 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import signal +import time +import unittest + +import torch +from torch import nn + +from fairseq.distributed import DistributedTimeoutWrapper + + +class ModuleWithDelay(nn.Module): + + def __init__(self, delay): + super().__init__() + self.delay = delay + + def forward(self, x): + time.sleep(self.delay) + return x + + +class TestDistributedTimeoutWrapper(unittest.TestCase): + + def setUp(self): + logging.disable(logging.CRITICAL) + + def tearDown(self): + logging.disable(logging.NOTSET) + + def test_no_timeout(self): + module = DistributedTimeoutWrapper(ModuleWithDelay(1), 0, signal.SIGINT) + module(torch.rand(5)) + module.stop_timeout() + + def test_timeout_safe(self): + module = DistributedTimeoutWrapper(ModuleWithDelay(1), 10, signal.SIGINT) + module(torch.rand(5)) + module.stop_timeout() + + def test_timeout_killed(self): + with self.assertRaises(KeyboardInterrupt): + module = DistributedTimeoutWrapper(ModuleWithDelay(5), 1, signal.SIGINT) + module(torch.rand(5)) + module.stop_timeout() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/distributed/test_module_proxy_wrapper.py b/tests/distributed/test_module_proxy_wrapper.py new file mode 100644 index 0000000000..2803a044cd --- /dev/null +++ b/tests/distributed/test_module_proxy_wrapper.py @@ -0,0 +1,75 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import torch +from torch import nn + +from fairseq.distributed import ModuleProxyWrapper + +from .utils import objects_are_equal + + +class MockDDPWrapper(nn.Module): + """A simple wrapper with an interface similar to DistributedDataParallel.""" + + def __init__(self, module): + super().__init__() + self.module = module + + def forward(self, x): + return self.module(x) + + +class Model(nn.Module): + def __init__(self): + super().__init__() + self.linear = nn.Linear(5, 10) + self.xyz = "hello" + + def forward(self, x): + return self.linear(x) + + def get_xyz(self): + return self.xyz + + +class TestModuleProxyWrapper(unittest.TestCase): + + def _get_module(self): + module = Model() + wrapped_module = MockDDPWrapper(module) + wrapped_module = ModuleProxyWrapper(wrapped_module) + return wrapped_module, module + + def test_getattr_forwarding(self): + wrapped_module, module = self._get_module() + assert module.xyz == "hello" + assert module.get_xyz() == "hello" + assert wrapped_module.xyz == "hello" + + wrapped_module.xyz = "world" + assert wrapped_module.xyz == "world" + assert module.get_xyz() == "hello" + + def test_state_dict(self): + wrapped_module, module = self._get_module() + assert objects_are_equal(wrapped_module.state_dict(), module.state_dict()) + + def test_load_state_dict(self): + wrapped_module, module = self._get_module() + wrapped_module.load_state_dict(module.state_dict()) + input = torch.rand(4, 5) + torch.testing.assert_allclose(wrapped_module(input), module(input)) + + def test_forward(self): + wrapped_module, module = self._get_module() + input = torch.rand(4, 5) + torch.testing.assert_allclose(wrapped_module(input), module(input)) + + +if __name__ == "__main__": + unittest.main() From 27b96eb698610d6ca8835b7bdf47528230ebfd00 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 28 Jan 2021 14:18:48 -0800 Subject: [PATCH 177/774] Move fairseq.distributed_utils -> fairseq.distributed.utils (#1547) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1547 Test Plan: Imported from OSS Reviewed By: girifb Differential Revision: D25836855 Pulled By: myleott fbshipit-source-id: addd8a7fe8dac43252b100d7331e04e95f555781 --- .../truncated_bptt/truncated_bptt_lm_task.py | 3 +- fairseq/__init__.py | 4 +- .../multilingual/sampled_multi_dataset.py | 2 +- .../legacy_distributed_data_parallel.py | 6 +- .../tpu_distributed_data_parallel.py | 4 +- .../utils.py} | 321 ++++++++++-------- fairseq/model_parallel/megatron_trainer.py | 4 +- fairseq/models/distributed_fairseq_model.py | 1 - fairseq/trainer.py | 3 +- fairseq/utils.py | 11 +- tests/{ => distributed}/test_bmuf.py | 4 +- ...est_distributed_utils.py => test_utils.py} | 2 +- 12 files changed, 199 insertions(+), 166 deletions(-) rename fairseq/{distributed_utils.py => distributed/utils.py} (73%) rename tests/{ => distributed}/test_bmuf.py (98%) rename tests/distributed/{test_distributed_utils.py => test_utils.py} (97%) diff --git a/examples/truncated_bptt/truncated_bptt_lm_task.py b/examples/truncated_bptt/truncated_bptt_lm_task.py index 34c4f03955..02be0e7fb4 100644 --- a/examples/truncated_bptt/truncated_bptt_lm_task.py +++ b/examples/truncated_bptt/truncated_bptt_lm_task.py @@ -9,7 +9,7 @@ from typing import List, Optional, Tuple import torch -from fairseq import distributed_utils as dist_utils, utils +from fairseq import utils from fairseq.data import ( Dictionary, TokenBlockDataset, @@ -17,6 +17,7 @@ iterators, ) from fairseq.dataclass import FairseqDataclass +from fairseq.distributed import utils as dist_utils from fairseq.tasks import FairseqTask, register_task from omegaconf import II diff --git a/fairseq/__init__.py b/fairseq/__init__.py index 8e51b61be0..dc9fd1886d 100644 --- a/fairseq/__init__.py +++ b/fairseq/__init__.py @@ -16,9 +16,11 @@ __all__ = ["pdb"] -# backwards compatibility to support `from fairseq.meters import AverageMeter` +# backwards compatibility to support `from fairseq.X import Y` +from fairseq.distributed import utils as distributed_utils from fairseq.logging import meters, metrics, progress_bar # noqa +sys.modules["fairseq.distributed_utils"] = distributed_utils sys.modules["fairseq.meters"] = meters sys.modules["fairseq.metrics"] = metrics sys.modules["fairseq.progress_bar"] = progress_bar diff --git a/fairseq/data/multilingual/sampled_multi_dataset.py b/fairseq/data/multilingual/sampled_multi_dataset.py index f74ec18141..b0a617424e 100644 --- a/fairseq/data/multilingual/sampled_multi_dataset.py +++ b/fairseq/data/multilingual/sampled_multi_dataset.py @@ -14,8 +14,8 @@ import numpy as np import torch -from fairseq import distributed_utils from fairseq.data import FairseqDataset, data_utils +from fairseq.distributed import utils as distributed_utils def get_time_gap(s, e): diff --git a/fairseq/distributed/legacy_distributed_data_parallel.py b/fairseq/distributed/legacy_distributed_data_parallel.py index 35de179b2f..b586e76b7f 100644 --- a/fairseq/distributed/legacy_distributed_data_parallel.py +++ b/fairseq/distributed/legacy_distributed_data_parallel.py @@ -20,7 +20,7 @@ import torch from torch import nn -from fairseq import distributed_utils +from fairseq.distributed import utils class LegacyDistributedDataParallel(nn.Module): @@ -43,7 +43,7 @@ def __init__(self, module, process_group, buffer_size=2 ** 28): self.module = module self.process_group = process_group - self.world_size = distributed_utils.get_world_size(self.process_group) + self.world_size = utils.get_world_size(self.process_group) # Never use a bigger buffer than the number of model params self.buffer_size = min(buffer_size, sum(p.numel() for p in module.parameters())) @@ -107,7 +107,7 @@ def all_reduce_params(params): if nonzero_buffer: buffer.div_(self.world_size) - distributed_utils.all_reduce(buffer, self.process_group) + utils.all_reduce(buffer, self.process_group) # copy all-reduced grads back into their original place offset = 0 diff --git a/fairseq/distributed/tpu_distributed_data_parallel.py b/fairseq/distributed/tpu_distributed_data_parallel.py index 2adcf1cb58..e971cf07c5 100644 --- a/fairseq/distributed/tpu_distributed_data_parallel.py +++ b/fairseq/distributed/tpu_distributed_data_parallel.py @@ -6,7 +6,7 @@ import torch from torch import nn -from fairseq import distributed_utils +from fairseq.distributed import utils class TPUDistributedDataParallel(nn.Module): @@ -15,7 +15,7 @@ def __init__(self, module, process_group): super().__init__() self.module = module self.process_group = process_group - self.world_size = distributed_utils.get_world_size(self.process_group) + self.world_size = utils.get_world_size(self.process_group) def forward(self, *inputs, **kwargs): return self.module(*inputs, **kwargs) diff --git a/fairseq/distributed_utils.py b/fairseq/distributed/utils.py similarity index 73% rename from fairseq/distributed_utils.py rename to fairseq/distributed/utils.py index 3b5fe6e7a8..e3c17859f4 100644 --- a/fairseq/distributed_utils.py +++ b/fairseq/distributed/utils.py @@ -19,7 +19,6 @@ import torch import torch.distributed as dist -from fairseq import utils from fairseq.dataclass.configs import DistributedTrainingConfig, FairseqConfig from omegaconf import open_dict @@ -49,169 +48,193 @@ def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False): return if cfg.pipeline_model_parallel: - balance_exists = ( - cfg.pipeline_balance is not None - or cfg.pipeline_encoder_balance is not None - or cfg.pipeline_decoder_balance is not None - ) - devices_exist = ( - cfg.pipeline_devices is not None - or cfg.pipeline_encoder_devices is not None - or cfg.pipeline_decoder_devices is not None - ) - if not balance_exists: - raise ValueError( - "--pipeline-balance is currently required for pipeline model parallelism" - ) - if not devices_exist: - raise ValueError( - "--pipeline-devices is currently required for pipeline model parallelism" - ) + num_pipeline_devices, num_pipelines_per_node = _pipeline_parallel_pre_init(cfg) - cfg.pipeline_balance = utils.eval_str_list(cfg.pipeline_balance, type=int) - if cfg.pipeline_devices is not None: - cfg.pipeline_devices = utils.eval_str_list(cfg.pipeline_devices, type=int) - num_pipeline_devices = len(set(cfg.pipeline_devices)) - else: - cfg.pipeline_encoder_devices = utils.eval_str_list( - cfg.pipeline_encoder_devices, type=int - ) - cfg.pipeline_decoder_devices = utils.eval_str_list( - cfg.pipeline_decoder_devices, type=int - ) - num_pipeline_devices = len( - set(cfg.pipeline_encoder_devices + cfg.pipeline_decoder_devices) - ) - gpus_per_node = torch.cuda.device_count() - assert ( - gpus_per_node >= num_pipeline_devices - and gpus_per_node % num_pipeline_devices == 0 - ), ( - "the number of unique device IDs in --pipeline-devices must evenly divide " - "the number of GPUs per node (multi-node pipelining is not yet supported)" - ) - num_pipelines_per_node = gpus_per_node // num_pipeline_devices - - # support torch.distributed.launch if all( key in os.environ for key in ["MASTER_ADDR", "MASTER_PORT", "WORLD_SIZE", "RANK"] ): - cfg.distributed_init_method = "env://" - cfg.distributed_world_size = int(os.environ["WORLD_SIZE"]) - cfg.distributed_rank = int(os.environ["RANK"]) - # processes are created by torch.distributed.launch - cfg.distributed_no_spawn = True - - # we can determine the init method automatically for Slurm + # support torch.distributed.launch + _infer_torch_distributed_launch_init(cfg) elif cfg.distributed_port > 0: - node_list = os.environ.get("SLURM_STEP_NODELIST") - if node_list is None: - node_list = os.environ.get("SLURM_JOB_NODELIST") - if node_list is not None: - try: - hostnames = subprocess.check_output( - ["scontrol", "show", "hostnames", node_list] - ) - cfg.distributed_init_method = "tcp://{host}:{port}".format( - host=hostnames.split()[0].decode("utf-8"), - port=cfg.distributed_port, - ) - nnodes = int(os.environ.get("SLURM_NNODES")) - ntasks_per_node = os.environ.get("SLURM_NTASKS_PER_NODE") - if ntasks_per_node is not None: - ntasks_per_node = int(ntasks_per_node) - else: - ntasks = int(os.environ.get("SLURM_NTASKS")) - nnodes = int(os.environ.get("SLURM_NNODES")) - assert ntasks % nnodes == 0 - ntasks_per_node = int(ntasks / nnodes) - if ntasks_per_node == 1: - gpus_per_node = torch.cuda.device_count() - node_id = int(os.environ.get("SLURM_NODEID")) - cfg.distributed_rank = node_id * gpus_per_node - cfg.distributed_world_size = nnodes * gpus_per_node - elif cfg.pipeline_model_parallel: - assert ntasks_per_node == num_pipelines_per_node, ( - "SLURM --ntasks-per-node must match number of pipelines per " - "node (={})".format(num_pipelines_per_node) - ) - cfg.distributed_no_spawn = True - # For 4-way MP on nodes with 8 GPUs, ranks will be [0, 1] on - # the first node, [1, 2] on the second node, etc. This - # matches torch.distributed.launch. - node_id = int(os.environ.get("SLURM_NODEID")) - local_id = int(os.environ.get("SLURM_LOCALID")) - cfg.distributed_rank = node_id * num_pipelines_per_node + local_id - # In the above example, device_id will always be in [0, 1], - # which also matches torch.distributed.launch. - cfg.device_id = local_id - # We also want to set distributed_world_size to be the total - # number of pipelines across all nodes. - cfg.distributed_world_size = nnodes * num_pipelines_per_node - else: - assert ntasks_per_node == cfg.distributed_world_size // nnodes - cfg.distributed_no_spawn = True - cfg.distributed_rank = int(os.environ.get("SLURM_PROCID")) - cfg.device_id = int(os.environ.get("SLURM_LOCALID")) - except subprocess.CalledProcessError as e: # scontrol failed - raise e - except FileNotFoundError: # Slurm is not installed - pass - + # we can determine the init method automatically for Slurm + _infer_slurm_init(cfg, num_pipelines_per_node) elif cfg.distributed_world_size > 1 or force_distributed: # fallback for single node with multiple GPUs - assert ( - cfg.distributed_world_size <= torch.cuda.device_count() - ), f"world size is {cfg.distributed_world_size} but have {torch.cuda.device_count()} available devices" - port = random.randint(10000, 20000) - cfg.distributed_init_method = "tcp://localhost:{port}".format(port=port) + _infer_single_node_init(cfg) if cfg.pipeline_model_parallel: - if not cfg.distributed_no_spawn: - # When distributed_no_spawn is False, we expect distributed_rank and - # distributed_world_size to be based on the total number of GPUs, so - # we need to correct them to be based on the number of pipelines. - assert cfg.distributed_world_size % num_pipeline_devices == 0 - cfg.distributed_world_size = ( - cfg.distributed_world_size // num_pipeline_devices + _pipeline_parallel_post_init(cfg, num_pipeline_devices, num_pipelines_per_node) + elif not cfg.distributed_no_spawn: + with open_dict(cfg): + cfg.distributed_num_procs = min( + torch.cuda.device_count(), cfg.distributed_world_size ) - # In the case of 4-way MP on nodes with 8 GPUs, we want - # distributed_rank to be the starting GPU index for each pipeline - # i.e., 0, 2, ... - assert cfg.distributed_rank % gpus_per_node == 0 - assert cfg.distributed_rank % num_pipeline_devices == 0 - - with open_dict(cfg): - cfg.distributed_rank = cfg.distributed_rank // num_pipeline_devices - # launch one process per pipeline - cfg.distributed_num_procs = num_pipelines_per_node - - # if we have 4-way MP on a node with 8 GPUs, we want device_ids to be 0 - # and 4, indicating the starting device IDs for each pipeline - cfg.device_id *= num_pipeline_devices - - if cfg.device_id > 0: - # if there's multiple pipelines on a node (e.g., 4-way MP on an 8 - # GPU node), we need to adjust pipeline_devices accordingly - logger.debug( - "setting CUDA device={} on rank {}".format( - cfg.device_id, cfg.distributed_rank - ) + + +def _infer_torch_distributed_launch_init(cfg: DistributedTrainingConfig): + cfg.distributed_init_method = "env://" + cfg.distributed_world_size = int(os.environ["WORLD_SIZE"]) + cfg.distributed_rank = int(os.environ["RANK"]) + # processes are created by torch.distributed.launch + cfg.distributed_no_spawn = True + + +def _infer_slurm_init(cfg: DistributedTrainingConfig, num_pipelines_per_node): + node_list = os.environ.get("SLURM_STEP_NODELIST") + if node_list is None: + node_list = os.environ.get("SLURM_JOB_NODELIST") + if node_list is not None: + try: + hostnames = subprocess.check_output( + ["scontrol", "show", "hostnames", node_list] ) - torch.cuda.set_device(cfg.device_id) - with open_dict(cfg): - cfg.pipeline_devices = [cfg.device_id + d for d in cfg.pipeline_devices] - logger.info( - "setting pipeline_devices={} on rank {}".format( - cfg.pipeline_devices, cfg.distributed_rank + cfg.distributed_init_method = "tcp://{host}:{port}".format( + host=hostnames.split()[0].decode("utf-8"), + port=cfg.distributed_port, + ) + nnodes = int(os.environ.get("SLURM_NNODES")) + ntasks_per_node = os.environ.get("SLURM_NTASKS_PER_NODE") + if ntasks_per_node is not None: + ntasks_per_node = int(ntasks_per_node) + else: + ntasks = int(os.environ.get("SLURM_NTASKS")) + nnodes = int(os.environ.get("SLURM_NNODES")) + assert ntasks % nnodes == 0 + ntasks_per_node = int(ntasks / nnodes) + if ntasks_per_node == 1: + gpus_per_node = torch.cuda.device_count() + node_id = int(os.environ.get("SLURM_NODEID")) + cfg.distributed_rank = node_id * gpus_per_node + cfg.distributed_world_size = nnodes * gpus_per_node + elif cfg.pipeline_model_parallel: + assert ntasks_per_node == num_pipelines_per_node, ( + "SLURM --ntasks-per-node must match number of pipelines per " + "node (={})".format(num_pipelines_per_node) ) + cfg.distributed_no_spawn = True + # For 4-way MP on nodes with 8 GPUs, ranks will be [0, 1] on + # the first node, [1, 2] on the second node, etc. This + # matches torch.distributed.launch. + node_id = int(os.environ.get("SLURM_NODEID")) + local_id = int(os.environ.get("SLURM_LOCALID")) + cfg.distributed_rank = node_id * num_pipelines_per_node + local_id + # In the above example, device_id will always be in [0, 1], + # which also matches torch.distributed.launch. + cfg.device_id = local_id + # We also want to set distributed_world_size to be the total + # number of pipelines across all nodes. + cfg.distributed_world_size = nnodes * num_pipelines_per_node + else: + assert ntasks_per_node == cfg.distributed_world_size // nnodes + cfg.distributed_no_spawn = True + cfg.distributed_rank = int(os.environ.get("SLURM_PROCID")) + cfg.device_id = int(os.environ.get("SLURM_LOCALID")) + except subprocess.CalledProcessError as e: # scontrol failed + raise e + except FileNotFoundError: # Slurm is not installed + pass + + +def _infer_single_node_init(cfg: DistributedTrainingConfig): + assert ( + cfg.distributed_world_size <= torch.cuda.device_count() + ), f"world size is {cfg.distributed_world_size} but have {torch.cuda.device_count()} available devices" + port = random.randint(10000, 20000) + cfg.distributed_init_method = "tcp://localhost:{port}".format(port=port) + + +def _pipeline_parallel_pre_init(cfg: DistributedTrainingConfig): + from fairseq import utils + + balance_exists = ( + cfg.pipeline_balance is not None + or cfg.pipeline_encoder_balance is not None + or cfg.pipeline_decoder_balance is not None + ) + devices_exist = ( + cfg.pipeline_devices is not None + or cfg.pipeline_encoder_devices is not None + or cfg.pipeline_decoder_devices is not None + ) + if not balance_exists: + raise ValueError( + "--pipeline-balance is currently required for pipeline model parallelism" + ) + if not devices_exist: + raise ValueError( + "--pipeline-devices is currently required for pipeline model parallelism" + ) + + cfg.pipeline_balance = utils.eval_str_list(cfg.pipeline_balance, type=int) + if cfg.pipeline_devices is not None: + cfg.pipeline_devices = utils.eval_str_list(cfg.pipeline_devices, type=int) + num_pipeline_devices = len(set(cfg.pipeline_devices)) + else: + cfg.pipeline_encoder_devices = utils.eval_str_list( + cfg.pipeline_encoder_devices, type=int + ) + cfg.pipeline_decoder_devices = utils.eval_str_list( + cfg.pipeline_decoder_devices, type=int + ) + num_pipeline_devices = len( + set(cfg.pipeline_encoder_devices + cfg.pipeline_decoder_devices) + ) + gpus_per_node = torch.cuda.device_count() + assert ( + gpus_per_node >= num_pipeline_devices + and gpus_per_node % num_pipeline_devices == 0 + ), ( + "the number of unique device IDs in --pipeline-devices must evenly divide " + "the number of GPUs per node (multi-node pipelining is not yet supported)" + ) + num_pipelines_per_node = gpus_per_node // num_pipeline_devices + return num_pipeline_devices, num_pipelines_per_node + + +def _pipeline_parallel_post_init( + cfg: DistributedTrainingConfig, num_pipeline_devices, num_pipelines_per_node +): + if not cfg.distributed_no_spawn: + # When distributed_no_spawn is False, we expect distributed_rank and + # distributed_world_size to be based on the total number of GPUs, so + # we need to correct them to be based on the number of pipelines. + assert cfg.distributed_world_size % num_pipeline_devices == 0 + cfg.distributed_world_size = ( + cfg.distributed_world_size // num_pipeline_devices + ) + # In the case of 4-way MP on nodes with 8 GPUs, we want + # distributed_rank to be the starting GPU index for each pipeline + # i.e., 0, 2, ... + gpus_per_node = torch.cuda.device_count() + assert cfg.distributed_rank % gpus_per_node == 0 + assert cfg.distributed_rank % num_pipeline_devices == 0 + + with open_dict(cfg): + cfg.distributed_rank = cfg.distributed_rank // num_pipeline_devices + # launch one process per pipeline + cfg.distributed_num_procs = num_pipelines_per_node + + # if we have 4-way MP on a node with 8 GPUs, we want device_ids to be 0 + # and 4, indicating the starting device IDs for each pipeline + cfg.device_id *= num_pipeline_devices + + if cfg.device_id > 0: + # if there's multiple pipelines on a node (e.g., 4-way MP on an 8 + # GPU node), we need to adjust pipeline_devices accordingly + logger.debug( + "setting CUDA device={} on rank {}".format( + cfg.device_id, cfg.distributed_rank ) - elif not cfg.distributed_no_spawn: + ) + torch.cuda.set_device(cfg.device_id) with open_dict(cfg): - cfg.distributed_num_procs = min( - torch.cuda.device_count(), cfg.distributed_world_size + cfg.pipeline_devices = [cfg.device_id + d for d in cfg.pipeline_devices] + logger.info( + "setting pipeline_devices={} on rank {}".format( + cfg.pipeline_devices, cfg.distributed_rank ) + ) def distributed_init(cfg: FairseqConfig): @@ -537,6 +560,8 @@ def all_gather_list(data, group=None, max_size=16384): max_size (int, optional): maximum size of the data to be gathered across workers """ + from fairseq import utils + if group is None: group = get_global_group() rank = get_rank(group=group) diff --git a/fairseq/model_parallel/megatron_trainer.py b/fairseq/model_parallel/megatron_trainer.py index 1a6e844aee..8ab4657f73 100644 --- a/fairseq/model_parallel/megatron_trainer.py +++ b/fairseq/model_parallel/megatron_trainer.py @@ -7,9 +7,9 @@ Train a network across multiple GPUs. """ -from fairseq import distributed_utils -from fairseq.trainer import Trainer from fairseq.dataclass.configs import FairseqConfig +from fairseq.distributed import utils as distributed_utils +from fairseq.trainer import Trainer try: from fairseq.model_parallel.megatron.mpu import ( diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index bee1033110..ca157f06e9 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -12,7 +12,6 @@ import torch.nn as nn from torch.nn.parallel import DistributedDataParallel -from fairseq import distributed_utils from fairseq.distributed import ( DistributedTimeoutWrapper, LegacyDistributedDataParallel, diff --git a/fairseq/trainer.py b/fairseq/trainer.py index b441eaa4d2..49129a7fb0 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -16,9 +16,10 @@ from typing import Any, Dict, List import torch -from fairseq import checkpoint_utils, distributed_utils, models, optim, utils +from fairseq import checkpoint_utils, models, optim, utils from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.distributed import utils as distributed_utils from fairseq.file_io import PathManager from fairseq.logging import meters, metrics from fairseq.nan_detector import NanDetector diff --git a/fairseq/utils.py b/fairseq/utils.py index a20c83384c..d4bf73648b 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -17,10 +17,6 @@ import torch import torch.nn.functional as F -from fairseq.data import iterators -from fairseq.file_io import PathManager -from fairseq.logging.meters import safe_round -from fairseq.modules import gelu, gelu_accurate from fairseq.modules.multihead_attention import MultiheadAttention from torch import Tensor @@ -51,6 +47,8 @@ def __init__(self, option_strings, dest, nargs=None, **kwargs): super(FileContentsAction, self).__init__(option_strings, dest, **kwargs) def __call__(self, parser, namespace, values, option_string=None): + from fairseq.file_io import PathManager + if PathManager.isfile(values): with PathManager.open(values) as f: argument = f.read().strip() @@ -482,6 +480,8 @@ def log_softmax(x, dim: int, onnx_trace: bool = False): def get_perplexity(loss, round=2, base=2): + from fairseq.logging.meters import safe_round + if loss is None: return 0.0 try: @@ -497,6 +497,8 @@ def deprecation_warning(message, stacklevel=3): def get_activation_fn(activation: str) -> Callable: """ Returns the activation function corresponding to `activation` """ + from fairseq.modules import gelu, gelu_accurate + if activation == "relu": return F.relu elif activation == "gelu": @@ -665,6 +667,7 @@ def get_tpu_device(): def tpu_data_loader(itr): import torch_xla.core.xla_model as xm import torch_xla.distributed.parallel_loader as pl + from fairseq.data import iterators xm.rendezvous("tpu_data_loader") # wait for all workers xm.mark_step() diff --git a/tests/test_bmuf.py b/tests/distributed/test_bmuf.py similarity index 98% rename from tests/test_bmuf.py rename to tests/distributed/test_bmuf.py index 785da37bc2..8b7cadb094 100644 --- a/tests/test_bmuf.py +++ b/tests/distributed/test_bmuf.py @@ -11,9 +11,11 @@ import torch import torch.nn as nn -from fairseq import distributed_utils, optim +from fairseq import optim +from fairseq.distributed import utils as distributed_utils from omegaconf import OmegaConf + class Model(nn.Module): def __init__(self, input_size, output_size): super(Model, self).__init__() diff --git a/tests/distributed/test_distributed_utils.py b/tests/distributed/test_utils.py similarity index 97% rename from tests/distributed/test_distributed_utils.py rename to tests/distributed/test_utils.py index 161ee85eaa..0a5d665068 100644 --- a/tests/distributed/test_distributed_utils.py +++ b/tests/distributed/test_utils.py @@ -9,7 +9,7 @@ import torch -from fairseq import distributed_utils as dist_utils +from fairseq.distributed import utils as dist_utils from .utils import objects_are_equal, spawn_and_init From 148327d8c1e3a5f9d17a11bbb1973a7cf3f955d3 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 28 Jan 2021 14:18:48 -0800 Subject: [PATCH 178/774] Add tests for fairseq.distributed.utils.all_gather_list (#1548) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1548 Test Plan: Imported from OSS Reviewed By: girifb Differential Revision: D25836857 Pulled By: myleott fbshipit-source-id: 3fb844fa21640cbda989dafa6592ef3e5c59bfa7 --- fairseq/distributed/utils.py | 3 +- tests/distributed/test_utils.py | 71 +++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index e3c17859f4..c39dc6d912 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -552,7 +552,8 @@ def all_gather_list(data, group=None, max_size=16384): """Gathers arbitrary data from all nodes into a list. Similar to :func:`~torch.distributed.all_gather` but for arbitrary Python - data. Note that *data* must be picklable. + data. Note that *data* must be picklable and any CUDA tensors will be moved + to CPU and returned on CPU as well. Args: data (Any): data from the local worker to be gathered on other workers diff --git a/tests/distributed/test_utils.py b/tests/distributed/test_utils.py index 0a5d665068..30f995b67a 100644 --- a/tests/distributed/test_utils.py +++ b/tests/distributed/test_utils.py @@ -14,7 +14,7 @@ from .utils import objects_are_equal, spawn_and_init -class TestDistributedUtils(unittest.TestCase): +class DistributedTest(unittest.TestCase): def setUp(self): if not torch.cuda.is_available(): raise unittest.SkipTest("CUDA not available, skipping test") @@ -23,28 +23,29 @@ def setUp(self): if torch.cuda.device_count() < 2: raise unittest.SkipTest("distributed tests require 2+ GPUs, skipping") - def test_broadcast_object_python(self): + +class TestBroadcastObject(DistributedTest): + def test_str(self): spawn_and_init( functools.partial( - TestDistributedUtils._test_broadcast_object, - "hello world", + TestBroadcastObject._test_broadcast_object, "hello world" ), world_size=2, ) - def test_broadcast_object_tensor(self): + def test_tensor(self): spawn_and_init( functools.partial( - TestDistributedUtils._test_broadcast_object, + TestBroadcastObject._test_broadcast_object, torch.rand(5), ), world_size=2, ) - def test_broadcast_object_complex(self): + def test_complex(self): spawn_and_init( functools.partial( - TestDistributedUtils._test_broadcast_object, + TestBroadcastObject._test_broadcast_object, { "a": "1", "b": [2, torch.rand(2, 3), 3], @@ -65,5 +66,59 @@ def _test_broadcast_object(ref_obj, rank, group): assert objects_are_equal(ref_obj, obj) +class TestAllGatherList(DistributedTest): + def test_str_equality(self): + spawn_and_init( + functools.partial( + TestAllGatherList._test_all_gather_list_equality, + "hello world", + ), + world_size=2, + ) + + def test_tensor_equality(self): + spawn_and_init( + functools.partial( + TestAllGatherList._test_all_gather_list_equality, + torch.rand(5), + ), + world_size=2, + ) + + def test_complex_equality(self): + spawn_and_init( + functools.partial( + TestAllGatherList._test_all_gather_list_equality, + { + "a": "1", + "b": [2, torch.rand(2, 3), 3], + "c": (torch.rand(2, 3), 4), + "d": {5, torch.rand(5)}, + "e": torch.rand(5), + "f": torch.rand(5).int(), + }, + ), + world_size=2, + ) + + @staticmethod + def _test_all_gather_list_equality(ref_obj, rank, group): + objs = dist_utils.all_gather_list(ref_obj, group) + for obj in objs: + assert objects_are_equal(ref_obj, obj) + + def test_rank_tensor(self): + spawn_and_init( + TestAllGatherList._test_all_gather_list_rank_tensor, world_size=2 + ) + + @staticmethod + def _test_all_gather_list_rank_tensor(rank, group): + obj = torch.tensor([rank]) + objs = dist_utils.all_gather_list(obj, group) + for i, obj in enumerate(objs): + assert obj.item() == i + + if __name__ == "__main__": unittest.main() From da83e2f3568fa6c93edb528859eef7135be75c2a Mon Sep 17 00:00:00 2001 From: Guillaume Wenzek <gwenzek@users.noreply.github.com> Date: Tue, 2 Feb 2021 09:23:27 -0800 Subject: [PATCH 179/774] add fast filter_indices_by_size for RoundRobinZipDatasets (#1555) Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? this has been extracted from https://github.com/fairinternal/fairseq-py/issues/1538 - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Implements a fast RoundRobinZipDataset.filter_indices_by_size. Instead of filtering the dataset sample by sample, the different datasets that are part of the RoundRobinZipDataset, are now filtered before being zipped together. This might generate slightly different datasets. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1555 Reviewed By: myleott Differential Revision: D25924464 Pulled By: gwenzek fbshipit-source-id: bc64d9dc35eee62da7e3e17fd75a7f9facb60452 --- fairseq/data/data_utils.py | 6 --- fairseq/data/round_robin_zip_datasets.py | 67 +++++++++++++++++++----- tests/test_dataset.py | 59 +++++++++++++++++++++ 3 files changed, 114 insertions(+), 18 deletions(-) create mode 100644 tests/test_dataset.py diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index d98c58a2f4..1a83063542 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -164,12 +164,6 @@ def check_size(idx): for key in intersect_keys ) else: - # Hacky as heck, for the specific case of multilingual training with RoundRobin. - if isinstance(size_fn(idx), dict) and isinstance(max_positions, tuple): - return all( - a is None or b is None or compare_leq(a, b) - for a, b in zip(size_fn(idx).values(), max_positions) - ) # For MultiCorpusSampledDataset, will generalize it later if not isinstance(size_fn(idx), Iterable): return all(size_fn(idx) <= b for b in max_positions) diff --git a/fairseq/data/round_robin_zip_datasets.py b/fairseq/data/round_robin_zip_datasets.py index 690823fc86..d710335b81 100644 --- a/fairseq/data/round_robin_zip_datasets.py +++ b/fairseq/data/round_robin_zip_datasets.py @@ -3,11 +3,15 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import logging from collections import OrderedDict +from typing import Dict, Sequence import numpy as np -from . import FairseqDataset +from . import FairseqDataset, LanguagePairDataset + +logger = logging.getLogger(__name__) class RoundRobinZipDatasets(FairseqDataset): @@ -25,25 +29,26 @@ class RoundRobinZipDatasets(FairseqDataset): def __init__(self, datasets, eval_key=None): super().__init__() + if isinstance(datasets, dict): + datasets = OrderedDict(datasets) assert isinstance(datasets, OrderedDict) + assert datasets, "Can't make a RoundRobinZipDatasets out of nothing" + for dataset in datasets.values(): + assert isinstance(dataset, FairseqDataset) + self.datasets = datasets self.eval_key = eval_key - self.longest_dataset = None - self.longest_dataset_key = None - for key, dataset in datasets.items(): - assert isinstance(dataset, FairseqDataset) - if self.longest_dataset is None or len(dataset) > len(self.longest_dataset): - self.longest_dataset = dataset - self.longest_dataset_key = key - - self._ordered_indices = None + self.longest_dataset_key = max(datasets, key=lambda k: len(datasets[k])) + self.longest_dataset = datasets[self.longest_dataset_key] + self._ordered_indices: Dict[str, Sequence[int]] = None def _map_index(self, key, index): assert ( self._ordered_indices is not None ), "Must call RoundRobinZipDatasets.ordered_indices() first" - return self._ordered_indices[key][index % len(self.datasets[key])] + o = self._ordered_indices[key] + return o[index % len(o)] def __getitem__(self, index): if self.eval_key is None: @@ -58,6 +63,8 @@ def __getitem__(self, index): return self.datasets[self.eval_key][self._map_index(self.eval_key, index)] def __len__(self): + if self._ordered_indices is not None: + return len(self._ordered_indices[self.longest_dataset_key]) return len(self.longest_dataset) def collater(self, samples): @@ -96,7 +103,7 @@ def ordered_indices(self): if self._ordered_indices is None: # Call the underlying dataset's ordered_indices() here, so that we # get the same random ordering as we would have from using the - # underlying dataset directly. + # underlying sub-datasets directly. self._ordered_indices = OrderedDict( [ (key, dataset.ordered_indices()) @@ -105,6 +112,42 @@ def ordered_indices(self): ) return np.arange(len(self)) + def filter_indices_by_size(self, indices, max_positions=None): + """ + Filter each sub-dataset independently, then update the round robin to work + on the filtered sub-datasets. + """ + + def _deep_until_language_pair(dataset): + if isinstance(dataset, LanguagePairDataset): + return dataset + if hasattr(dataset, "tgt_dataset"): + return _deep_until_language_pair(dataset.tgt_dataset) + if hasattr(dataset, "dataset"): + return _deep_until_language_pair(dataset.dataset) + raise Exception(f"Don't know how to unwrap this dataset: {dataset}") + + if not isinstance(max_positions, dict): + max_positions = {k: max_positions for k in self.datasets.keys()} + ignored_some = False + for key, dataset in self.datasets.items(): + dataset = _deep_until_language_pair(dataset) + self._ordered_indices[key], ignored = dataset.filter_indices_by_size( + self._ordered_indices[key], max_positions[key] + ) + if len(ignored) > 0: + ignored_some = True + logger.warning( + f"{len(ignored)} samples from {key} have invalid sizes and will be skipped, " + f"max_positions={max_positions[key]}, first few sample ids={ignored[:10]}" + ) + # Since we are modifiying in place the _ordered_indices, + # it's not possible anymore to return valid ignored indices. + # Hopefully the extra debug information print above should be enough to debug. + # Ideally we would receive ignore_invalid_inputs so that we could have + # a proper error message. + return (np.arange(len(self)), [0] if ignored_some else []) + @property def supports_prefetch(self): return all( diff --git a/tests/test_dataset.py b/tests/test_dataset.py new file mode 100644 index 0000000000..9fb69a5f77 --- /dev/null +++ b/tests/test_dataset.py @@ -0,0 +1,59 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from typing import Sequence + +from fairseq.data import LanguagePairDataset, ListDataset, RoundRobinZipDatasets +from tests.test_train import mock_dict + + +def lang_pair_dataset(lengths: Sequence[int]) -> LanguagePairDataset: + tokens = [[i] * l for i, l in enumerate(lengths)] + return LanguagePairDataset(ListDataset(tokens), lengths, mock_dict()) + + +def sample(id: int, length: int): + return {"id": id, "source": [id] * length, "target": None} + + +class TestDataset(unittest.TestCase): + def test_round_robin_zip_datasets(self): + long_dataset = lang_pair_dataset([10, 9, 8, 11]) + short_dataset = lang_pair_dataset([11, 9]) + + dataset = RoundRobinZipDatasets({"a": long_dataset, "b": short_dataset}) + # Dataset is now sorted by sentence length + dataset.ordered_indices() + assert dataset.longest_dataset is long_dataset + self.assertEqual(dict(dataset[0]), {"a": sample(2, 8), "b": sample(1, 9)}) + # The item 2 of dataset 'a' is with item (2 % 2 = 0) of dataset 'b' + self.assertEqual(dict(dataset[2]), {"a": sample(0, 10), "b": sample(1, 9)}) + + def test_round_robin_zip_datasets_filtered(self): + long_dataset = lang_pair_dataset([10, 20, 8, 11, 1000, 7, 12]) + short_dataset = lang_pair_dataset([11, 20, 9, 1000]) + + dataset = RoundRobinZipDatasets({"a": long_dataset, "b": short_dataset}) + # Dataset is now sorted by sentence length + idx = dataset.ordered_indices() + idx, _ = dataset.filter_indices_by_size(idx, {"a": 19, "b": 900}) + self.assertEqual(list(idx), [0, 1, 2, 3, 4]) + self.assertEqual(dict(dataset[0]), {"a": sample(5, 7), "b": sample(2, 9)}) + self.assertEqual(dict(dataset[2]), {"a": sample(0, 10), "b": sample(1, 20)}) + self.assertEqual(dict(dataset[4]), {"a": sample(6, 12), "b": sample(0, 11)}) + + def test_round_robin_zip_datasets_filtered_with_tuple(self): + long_dataset = lang_pair_dataset([10, 20, 8, 11, 1000, 7, 12]) + short_dataset = lang_pair_dataset([11, 20, 9, 1000]) + + dataset = RoundRobinZipDatasets({"a": long_dataset, "b": short_dataset}) + # Dataset is now sorted by sentence length + idx = dataset.ordered_indices() + idx, _ = dataset.filter_indices_by_size(idx, 19) + self.assertEqual(list(idx), [0, 1, 2, 3, 4]) + self.assertEqual(dict(dataset[0]), {"a": sample(5, 7), "b": sample(2, 9)}) + self.assertEqual(dict(dataset[2]), {"a": sample(0, 10), "b": sample(2, 9)}) + self.assertEqual(dict(dataset[4]), {"a": sample(6, 12), "b": sample(2, 9)}) From 4b152cbdc029b8a4b1aa8c4189afc16bd289a0ba Mon Sep 17 00:00:00 2001 From: Benjamin Bolte <ben@bolte.cc> Date: Tue, 2 Feb 2021 14:22:48 -0800 Subject: [PATCH 180/774] Speech recognition sharded infer script (#1587) Summary: Wrote a sharded version of `examples/speech_recognition/infer.py` (in a new `examples/speech_recognition/hydra/` folder) which uses the Hydra entry point for launching Slurm jobs. Tested by decoding a fine-tuned HUBERT model and got a reasonable WER. Also tested using Ax sweeper to sweep WER and it seems to work fine. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1587 Reviewed By: wnhsu Differential Revision: D26208091 Pulled By: codekansas fbshipit-source-id: 82671514a85394036b670fe9f7b299236d6c767a --- examples/speech_recognition/hydra/README.md | 45 ++ .../hydra/conf/hydra/sweeper/ax.yaml | 26 + .../speech_recognition/hydra/conf/infer.yaml | 22 + examples/speech_recognition/hydra/decoder.py | 599 ++++++++++++++++++ examples/speech_recognition/hydra/infer.py | 445 +++++++++++++ 5 files changed, 1137 insertions(+) create mode 100644 examples/speech_recognition/hydra/README.md create mode 100644 examples/speech_recognition/hydra/conf/hydra/sweeper/ax.yaml create mode 100644 examples/speech_recognition/hydra/conf/infer.yaml create mode 100644 examples/speech_recognition/hydra/decoder.py create mode 100644 examples/speech_recognition/hydra/infer.py diff --git a/examples/speech_recognition/hydra/README.md b/examples/speech_recognition/hydra/README.md new file mode 100644 index 0000000000..17d5946675 --- /dev/null +++ b/examples/speech_recognition/hydra/README.md @@ -0,0 +1,45 @@ +# Flashlight Decoder + +This script runs decoding for pre-trained speech recognition models. + +## Usage + +Assuming a few variables: + +```bash +exp_dir=<path-to-experiment-directory> +data=<path-to-data-directory> +lm_model=<path-to-language-model> +lexicon=<path-to-lexicon> +``` + +Example usage for decoding a fine-tuned Wav2Vec model: + +```bash +python $FAIRSEQ_ROOT/examples/speech_recognition/hydra/infer.py --multirun \ + task=audio_pretraining \ + task.data=$data \ + task.labels=ltr \ + decoding.exp_dir=$exp_dir \ + decoding.decoder.name=kenlm \ + decoding.decoder.lexicon=$lexicon \ + decoding.decoder.lmpath=$lm_model \ + dataset.gen_subset=dev_clean,dev_other,test_clean,test_other +``` + +Example usage for using Ax to sweep WER parameters (requires `pip install hydra-ax-sweeper`): + +```bash +python $FAIRSEQ_ROOT/examples/speech_recognition/hydra/infer.py --multirun \ + hydra/sweeper=ax \ + task=audio_pretraining \ + task.data=$data \ + task.labels=ltr \ + decoding.exp_dir=$exp_dir \ + decoding.decoder.name=kenlm \ + decoding.decoder.lexicon=$lexicon \ + decoding.decoder.lmpath=$lm_model \ + decoding.write_sentences=false \ + decoding.unique_wer_file=true \ + dataset.gen_subset=dev_other +``` diff --git a/examples/speech_recognition/hydra/conf/hydra/sweeper/ax.yaml b/examples/speech_recognition/hydra/conf/hydra/sweeper/ax.yaml new file mode 100644 index 0000000000..7700712ea0 --- /dev/null +++ b/examples/speech_recognition/hydra/conf/hydra/sweeper/ax.yaml @@ -0,0 +1,26 @@ +# @package hydra.sweeper +_target_: hydra_plugins.hydra_ax_sweeper.ax_sweeper.AxSweeper +max_batch_size: null +ax_config: + max_trials: 100 + early_stop: + minimize: true + max_epochs_without_improvement: 10 + epsilon: 1.0e-05 + experiment: + name: ${dataset.gen_subset} + objective_name: wer + minimize: true + parameter_constraints: null + outcome_constraints: null + status_quo: null + client: + verbose_logging: false + random_seed: null + params: + decoding.decoder.lmweight: + type: range + bounds: [0.0, 5.0] + decoding.decoder.wordscore: + type: range + bounds: [-5.0, 5.0] diff --git a/examples/speech_recognition/hydra/conf/infer.yaml b/examples/speech_recognition/hydra/conf/infer.yaml new file mode 100644 index 0000000000..1d78ba14cb --- /dev/null +++ b/examples/speech_recognition/hydra/conf/infer.yaml @@ -0,0 +1,22 @@ +# @package _group_ + +defaults: + - task: null + - model: null + +hydra: + run: + dir: ${common_eval.results_path}/${dataset.gen_subset} + sweep: + dir: ${common_eval.results_path} + subdir: ${dataset.gen_subset} +common_eval: + results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name} + path: ${decoding.exp_dir}/checkpoint_best.pt + post_process: letter +generation: + nbest: 1 + beam: 500 +dataset: + max_tokens: 1000000 + gen_subset: test diff --git a/examples/speech_recognition/hydra/decoder.py b/examples/speech_recognition/hydra/decoder.py new file mode 100644 index 0000000000..41fcbd7087 --- /dev/null +++ b/examples/speech_recognition/hydra/decoder.py @@ -0,0 +1,599 @@ +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import gc +import itertools as it +import math +import os.path as osp +import warnings +from collections import deque, namedtuple +from dataclasses import dataclass, field +from typing import Any, Dict, List, Optional, Tuple + +import numpy as np +import torch +from examples.speech_recognition.data.replabels import unpack_replabels +from fairseq import tasks +from fairseq.data.dictionary import Dictionary +from fairseq.dataclass.configs import FairseqDataclass +from fairseq.dataclass.constants import ChoiceEnum +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.models.fairseq_model import FairseqModel +from fairseq.utils import apply_to_sample +from omegaconf import MISSING, open_dict + +try: + from flashlight.lib.sequence.criterion import (CpuViterbiPath, + get_data_ptr_as_bytes) + from flashlight.lib.text.decoder import (LM, CriterionType, DecodeResult, + KenLM, LexiconDecoder, + LexiconDecoderOptions, + LexiconFreeDecoder, + LexiconFreeDecoderOptions, + LMState, SmearingMode, Trie) + from flashlight.lib.text.dictionary import create_word_dict, load_words +except ImportError: + warnings.warn( + "flashlight python bindings are required to use this functionality. " + "Please install from " + "https://github.com/facebookresearch/flashlight/tree/master/bindings/python" + ) + LM = object + LMState = object + + +CRITERION_CHOICES = ChoiceEnum(["ctc", "asg"]) +DECODER_CHOICES = ChoiceEnum(["viterbi", "kenlm", "fairseqlm"]) + + +@dataclass +class DecoderConfig(FairseqDataclass): + name: DECODER_CHOICES = field( + default="viterbi", + metadata={"help": "The type of decoder to use"}, + ) + nbest: int = field( + default=1, + metadata={"help": "Number of decodings to return"}, + ) + criterion: CRITERION_CHOICES = field( + default="ctc", + metadata={"help": "Criterion to use"}, + ) + asgtransitions: List[int] = field( + default=MISSING, + metadata={"help": "ASG transition indices"}, + ) + maxreplabel: int = field( + default=2, + metadata={"help": "Maximum repeated labels for ASG criterion"}, + ) + unitlm: bool = field( + default=False, + metadata={"help": "If set, use unit language model"}, + ) + lmpath: str = field( + default=MISSING, + metadata={"help": "Language model for KenLM decoder"}, + ) + lexicon: Optional[str] = field( + default=None, + metadata={"help": "Lexicon for Flashlight decoder"}, + ) + beam: int = field( + default=50, + metadata={"help": "Number of beams to use for decoding"}, + ) + beamthreshold: float = field( + default=15.0, + metadata={"help": "Threshold for beam search decoding"}, + ) + beamsizetoken: Optional[int] = field( + default=None, + metadata={"help": "Beam size to use"} + ) + wordscore: float = field( + default=1.5, + metadata={"help": "Word score for KenLM decoder"}, + ) + unkweight: float = field( + default=-math.inf, + metadata={"help": "Unknown weight for KenLM decoder"}, + ) + silweight: float = field( + default=-0.3, + metadata={"help": "Silence weight for KenLM decoder"}, + ) + lmweight: float = field( + default=1.5, + metadata={"help": "Weight for LM while interpolating score"}, + ) + unitlm: bool = field( + default=False, + metadata={"help": "If using a unit language model"}, + ) + + +class BaseDecoder: + def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: + self.tgt_dict = tgt_dict + self.vocab_size = len(tgt_dict) + self.nbest = cfg.nbest + self.unitlm = cfg.unitlm + + if cfg.criterion == "ctc": + self.criterion_type = CriterionType.CTC + self.blank = ( + tgt_dict.index("<ctc_blank>") + if "<ctc_blank>" in tgt_dict.indices + else tgt_dict.bos() + ) + if "<sep>" in tgt_dict.indices: + self.silence = tgt_dict.index("<sep>") + elif "|" in tgt_dict.indices: + self.silence = tgt_dict.index("|") + else: + self.silence = tgt_dict.eos() + self.asgtransitions = None + elif cfg.criterion == "asg_loss": + self.criterion_type = CriterionType.ASG + self.blank = -1 + self.silence = -1 + self.asgtransitions = cfg.asgtransitions + self.maxreplabel = cfg.maxreplabel + assert len(self.asgtransitions) == self.vocab_size ** 2 + else: + raise RuntimeError(f"unknown criterion: {cfg.criterion}") + + def generate( + self, + models: List[FairseqModel], + sample: Dict[str, Any], + **unused + ) -> List[List[Dict[str, torch.LongTensor]]]: + encoder_input = { + k: v + for k, v in sample["net_input"].items() + if k != "prev_output_tokens" + } + emissions = self.get_emissions(models, encoder_input) + return self.decode(emissions) + + def get_emissions( + self, + models: List[FairseqModel], + encoder_input: Dict[str, Any], + ) -> torch.FloatTensor: + model = models[0] + encoder_out = model(**encoder_input) + if self.criterion_type == CriterionType.CTC: + if hasattr(model, "get_logits"): + emissions = model.get_logits(encoder_out) + else: + emissions = model.get_normalized_probs( + encoder_out, log_probs=True) + elif self.criterion_type == CriterionType.ASG: + emissions = encoder_out["encoder_out"] + else: + raise ValueError("Criterion not implemented: " + f"{self.criterion_type}") + return emissions.transpose(0, 1).float().cpu().contiguous() + + def get_tokens(self, idxs: torch.IntTensor) -> torch.LongTensor: + idxs = (g[0] for g in it.groupby(idxs)) + if self.criterion_type == CriterionType.CTC: + idxs = filter(lambda x: x != self.blank, idxs) + elif self.criterion_type == CriterionType.ASG: + idxs = filter(lambda x: x >= 0, idxs) + idxs = unpack_replabels( + list(idxs), self.tgt_dict, self.maxreplabel) + return torch.LongTensor(list(idxs)) + + def decode( + self, + emissions: torch.FloatTensor, + ) -> List[List[Dict[str, torch.LongTensor]]]: + raise NotImplementedError + + +class ViterbiDecoder(BaseDecoder): + def decode( + self, + emissions: torch.FloatTensor, + ) -> List[List[Dict[str, torch.LongTensor]]]: + B, T, N = emissions.size() + if self.asgtransitions is None: + transitions = torch.FloatTensor(N, N).zero_() + else: + transitions = torch.FloatTensor(self.asgtransitions).view(N, N) + viterbi_path = torch.IntTensor(B, T) + workspace = torch.ByteTensor( + CpuViterbiPath.get_workspace_size(B, T, N)) + CpuViterbiPath.compute( + B, + T, + N, + get_data_ptr_as_bytes(emissions), + get_data_ptr_as_bytes(transitions), + get_data_ptr_as_bytes(viterbi_path), + get_data_ptr_as_bytes(workspace), + ) + return [ + [{"tokens": self.get_tokens(viterbi_path[b].tolist()), "score": 0}] + for b in range(B) + ] + + +class KenLMDecoder(BaseDecoder): + def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: + super().__init__(cfg, tgt_dict) + + if cfg.lexicon: + self.lexicon = load_words(cfg.lexicon) + self.word_dict = create_word_dict(self.lexicon) + self.unk_word = self.word_dict.get_index("<unk>") + + self.lm = KenLM(cfg.lmpath, self.word_dict) + self.trie = Trie(self.vocab_size, self.silence) + + start_state = self.lm.start(False) + for word, spellings in self.lexicon.items(): + word_idx = self.word_dict.get_index(word) + _, score = self.lm.score(start_state, word_idx) + for spelling in spellings: + spelling_idxs = [ + tgt_dict.index(token) + for token in spelling + ] + assert tgt_dict.unk() not in spelling_idxs, \ + f"{spelling} {spelling_idxs}" + self.trie.insert(spelling_idxs, word_idx, score) + self.trie.smear(SmearingMode.MAX) + + self.decoder_opts = LexiconDecoderOptions( + beam_size=cfg.beam, + beam_size_token=cfg.beamsizetoken or len(tgt_dict), + beam_threshold=cfg.beamthreshold, + lm_weight=cfg.lmweight, + word_score=cfg.wordscore, + unk_score=cfg.unkweight, + sil_score=cfg.silweight, + log_add=False, + criterion_type=self.criterion_type, + ) + + if self.asgtransitions is None: + self.asgtransitions = [] + + self.decoder = LexiconDecoder( + self.decoder_opts, + self.trie, + self.lm, + self.silence, + self.blank, + self.unk_word, + self.asgtransitions, + self.unitlm, + ) + else: + assert self.unitlm, "Lexicon-free decoding requires unit LM" + + d = {w: [[w]] for w in tgt_dict.symbols} + self.word_dict = create_word_dict(d) + self.lm = KenLM(cfg.lmpath, self.word_dict) + self.decoder_opts = LexiconFreeDecoderOptions( + beam_size=cfg.beam, + beam_size_token=cfg.beamsizetoken or len(tgt_dict), + beam_threshold=cfg.beamthreshold, + lm_weight=cfg.lmweight, + sil_score=cfg.silweight, + log_add=False, + criterion_type=self.criterion_type, + ) + self.decoder = LexiconFreeDecoder( + self.decoder_opts, self.lm, self.silence, self.blank, [] + ) + + def decode( + self, + emissions: torch.FloatTensor, + ) -> List[List[Dict[str, torch.LongTensor]]]: + B, T, N = emissions.size() + hypos = [] + for b in range(B): + emissions_ptr = emissions.data_ptr() + 4 * b * emissions.stride(0) + results = self.decoder.decode(emissions_ptr, T, N) + + nbest_results = results[: self.nbest] + hypos.append([ + { + "tokens": self.get_tokens(result.tokens), + "score": result.score, + "words": [ + self.word_dict.get_entry(x) + for x in result.words if x >= 0 + ], + } for result in nbest_results + ]) + return hypos + + +FairseqLMState = namedtuple( + "FairseqLMState", + [ + "prefix", + "incremental_state", + "probs", + ] +) + + +class FairseqLM(LM): + def __init__(self, dictionary: Dictionary, model: FairseqModel) -> None: + super().__init__() + + self.dictionary = dictionary + self.model = model + self.unk = self.dictionary.unk() + + self.save_incremental = False # this currently does not work properly + self.max_cache = 20_000 + + model.cuda() + model.eval() + model.make_generation_fast_() + + self.states = {} + self.stateq = deque() + + def start(self, start_with_nothing: bool) -> LMState: + state = LMState() + prefix = torch.LongTensor([[self.dictionary.eos()]]) + incremental_state = {} if self.save_incremental else None + with torch.no_grad(): + res = self.model( + prefix.cuda(), incremental_state=incremental_state) + probs = self.model.get_normalized_probs( + res, log_probs=True, sample=None) + + if incremental_state is not None: + incremental_state = apply_to_sample( + lambda x: x.cpu(), incremental_state) + self.states[state] = FairseqLMState( + prefix.numpy(), incremental_state, probs[0, -1].cpu().numpy() + ) + self.stateq.append(state) + + return state + + def score( + self, + state: LMState, + token_index: int, + no_cache: bool = False, + ) -> Tuple[LMState, int]: + """ + Evaluate language model based on the current lm state and new word + Parameters: + ----------- + state: current lm state + token_index: index of the word + (can be lexicon index then you should store inside LM the + mapping between indices of lexicon and lm, or lm index of a word) + Returns: + -------- + (LMState, float): pair of (new state, score for the current word) + """ + curr_state = self.states[state] + + def trim_cache(targ_size: int) -> None: + while len(self.stateq) > targ_size: + rem_k = self.stateq.popleft() + rem_st = self.states[rem_k] + rem_st = FairseqLMState(rem_st.prefix, None, None) + self.states[rem_k] = rem_st + + if curr_state.probs is None: + new_incremental_state = ( + curr_state.incremental_state.copy() + if curr_state.incremental_state is not None + else None + ) + with torch.no_grad(): + if new_incremental_state is not None: + new_incremental_state = apply_to_sample( + lambda x: x.cuda(), new_incremental_state + ) + elif self.save_incremental: + new_incremental_state = {} + + res = self.model( + torch.from_numpy(curr_state.prefix).cuda(), + incremental_state=new_incremental_state, + ) + probs = self.model.get_normalized_probs( + res, log_probs=True, sample=None + ) + + if new_incremental_state is not None: + new_incremental_state = apply_to_sample( + lambda x: x.cpu(), new_incremental_state + ) + + curr_state = FairseqLMState( + curr_state.prefix, new_incremental_state, probs[0, -1].cpu( + ).numpy() + ) + + if not no_cache: + self.states[state] = curr_state + self.stateq.append(state) + + score = curr_state.probs[token_index].item() + + trim_cache(self.max_cache) + + outstate = state.child(token_index) + if outstate not in self.states and not no_cache: + prefix = np.concatenate( + [curr_state.prefix, torch.LongTensor([[token_index]])], -1 + ) + incr_state = curr_state.incremental_state + + self.states[outstate] = FairseqLMState(prefix, incr_state, None) + + if token_index == self.unk: + score = float("-inf") + + return outstate, score + + def finish(self, state: LMState) -> Tuple[LMState, int]: + """ + Evaluate eos for language model based on the current lm state + Returns: + -------- + (LMState, float): pair of (new state, score for the current word) + """ + return self.score(state, self.dictionary.eos()) + + def empty_cache(self) -> None: + self.states = {} + self.stateq = deque() + gc.collect() + + +class FairseqLMDecoder(BaseDecoder): + def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: + super().__init__(cfg, tgt_dict) + + self.lexicon = load_words(cfg.lexicon) if cfg.lexicon else None + self.idx_to_wrd = {} + + checkpoint = torch.load(cfg.lmpath, map_location="cpu") + + if "cfg" in checkpoint and checkpoint["cfg"] is not None: + lm_args = checkpoint["cfg"] + else: + lm_args = convert_namespace_to_omegaconf(checkpoint["args"]) + + with open_dict(lm_args.task): + lm_args.task.data = osp.dirname(cfg.lmpath) + + task = tasks.setup_task(lm_args.task) + model = task.build_model(lm_args.model) + model.load_state_dict(checkpoint["model"], strict=False) + + self.trie = Trie(self.vocab_size, self.silence) + + self.word_dict = task.dictionary + self.unk_word = self.word_dict.unk() + self.lm = FairseqLM(self.word_dict, model) + + if self.lexicon: + start_state = self.lm.start(False) + for i, (word, spellings) in enumerate(self.lexicon.items()): + if self.unitlm: + word_idx = i + self.idx_to_wrd[i] = word + score = 0 + else: + word_idx = self.word_dict.index(word) + _, score = self.lm.score( + start_state, word_idx, no_cache=True) + + for spelling in spellings: + spelling_idxs = [ + tgt_dict.index(token) + for token in spelling + ] + assert tgt_dict.unk() not in spelling_idxs, \ + f"{spelling} {spelling_idxs}" + self.trie.insert(spelling_idxs, word_idx, score) + self.trie.smear(SmearingMode.MAX) + + self.decoder_opts = LexiconDecoderOptions( + beam_size=cfg.beam, + beam_size_token=cfg.beamsizetoken or len(tgt_dict), + beam_threshold=cfg.beamthreshold, + lm_weight=cfg.lmweight, + word_score=cfg.wordscore, + unk_score=cfg.unkweight, + sil_score=cfg.silweight, + log_add=False, + criterion_type=self.criterion_type, + ) + + if self.asgtransitions is None: + self.asgtransitions = [] + + self.decoder = LexiconDecoder( + self.decoder_opts, + self.trie, + self.lm, + self.silence, + self.blank, + self.unk_word, + self.asgtransitions, + self.unitlm, + ) + else: + assert self.unitlm, "Lexicon-free decoding requires unit LM" + + d = {w: [[w]] for w in tgt_dict.symbols} + self.word_dict = create_word_dict(d) + self.lm = KenLM(cfg.lmpath, self.word_dict) + self.decoder_opts = LexiconFreeDecoderOptions( + beam_size=cfg.beam, + beam_size_token=cfg.beamsizetoken or len(tgt_dict), + beam_threshold=cfg.beamthreshold, + lm_weight=cfg.lmweight, + sil_score=cfg.silweight, + log_add=False, + criterion_type=self.criterion_type, + ) + self.decoder = LexiconFreeDecoder( + self.decoder_opts, self.lm, self.silence, self.blank, [] + ) + + def decode( + self, + emissions: torch.FloatTensor, + ) -> List[List[Dict[str, torch.LongTensor]]]: + B, T, N = emissions.size() + hypos = [] + + def make_hypo(result: DecodeResult) -> Dict[str, Any]: + hypo = { + "tokens": self.get_tokens(result.tokens), + "score": result.score, + } + if self.lexicon: + hypo["words"] = [ + self.idx_to_wrd[x] if self.unitlm else self.word_dict[x] + for x in result.words if x >= 0 + ] + return hypo + + for b in range(B): + emissions_ptr = emissions.data_ptr() + 4 * b * emissions.stride(0) + results = self.decoder.decode(emissions_ptr, T, N) + + nbest_results = results[:self.nbest] + hypos.append([make_hypo(result) for result in nbest_results]) + self.lm.empty_cache() + + return hypos + + +def Decoder(cfg: DecoderConfig, tgt_dict: Dictionary) -> BaseDecoder: + if cfg.name == "viterbi": + return ViterbiDecoder(cfg, tgt_dict) + if cfg.name == "kenlm": + return KenLMDecoder(cfg, tgt_dict) + if cfg.name == "fairseqlm": + return FairseqLMDecoder(cfg, tgt_dict) + raise NotImplementedError(f"Invalid decoder name: {cfg.name}") diff --git a/examples/speech_recognition/hydra/infer.py b/examples/speech_recognition/hydra/infer.py new file mode 100644 index 0000000000..6afa066f25 --- /dev/null +++ b/examples/speech_recognition/hydra/infer.py @@ -0,0 +1,445 @@ +#!/usr/bin/env python -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import ast +import hashlib +import logging +import os +import shutil +import sys +from argparse import Namespace +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Callable, Dict, List, Optional, Tuple + +import editdistance +import torch +import torch.distributed as dist +from examples.speech_recognition.hydra.decoder import Decoder, DecoderConfig +from fairseq import (checkpoint_utils, distributed_utils, progress_bar, tasks, + utils) +from fairseq.data.data_utils import post_process +from fairseq.dataclass.configs import (CheckpointConfig, CommonConfig, + CommonEvalConfig, DatasetConfig, + DistributedTrainingConfig, + FairseqDataclass, GenerationConfig) +from fairseq.dataclass.initialize import hydra_init +from fairseq.logging.meters import StopwatchMeter, TimeMeter +from fairseq.logging.progress_bar import BaseProgressBar +from fairseq.models.fairseq_model import FairseqModel +from omegaconf import MISSING, OmegaConf + +import hydra +from hydra.core.config_store import ConfigStore + +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +config_path = Path(__file__).resolve().parent / "conf" + + +@dataclass +class DecodingConfig(FairseqDataclass): + exp_dir: str = field( + default=MISSING, + metadata={"help": "Path to the experiment directory"}, + ) + unique_wer_file: bool = field( + default=False, + metadata={"help": "If set, use a unique file for storing WER"}, + ) + write_sentences: bool = field( + default=True, + metadata={"help": "If set, write hypothesis and reference sentences"}, + ) + decoder: DecoderConfig = DecoderConfig() + + +@dataclass +class InferConfig(FairseqDataclass): + task: Any = None + decoding: DecodingConfig = DecodingConfig() + common: CommonConfig = CommonConfig() + common_eval: CommonEvalConfig = CommonEvalConfig() + checkpoint: CheckpointConfig = CheckpointConfig() + generation: GenerationConfig = GenerationConfig() + distributed_training: DistributedTrainingConfig = DistributedTrainingConfig() + dataset: DatasetConfig = DatasetConfig() + + +def reset_logging(): + root = logging.getLogger() + for handler in root.handlers: + root.removeHandler(handler) + root.setLevel(os.environ.get("LOGLEVEL", "INFO").upper()) + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter( + logging.Formatter( + fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + ) + root.addHandler(handler) + + +class InferenceProcessor: + def __init__(self, cfg: InferConfig) -> None: + self.cfg = cfg + self.task = tasks.setup_task(cfg.task) + self.tgt_dict = self.task.target_dictionary + + models, saved_cfg = self.load_model_ensemble() + self.models = models + self.saved_cfg = saved_cfg + + self.task.load_dataset( + self.cfg.dataset.gen_subset, + task_cfg=saved_cfg.task, + ) + self.generator = Decoder(cfg.decoding.decoder, self.tgt_dict) + self.gen_timer = StopwatchMeter() + self.wps_meter = TimeMeter() + self.num_sentences = 0 + self.total_errors = 0 + self.total_length = 0 + + self.hypo_words_file = None + self.hypo_units_file = None + self.ref_words_file = None + self.ref_units_file = None + + self.progress_bar = self.build_progress_bar() + + def __enter__(self) -> "InferenceProcessor": + if self.cfg.decoding.write_sentences: + self.hypo_words_file = self.get_res_file("hypo.word") + self.hypo_units_file = self.get_res_file("hypo.units") + self.ref_words_file = self.get_res_file("ref.word") + self.ref_units_file = self.get_res_file("ref.units") + return self + + def __exit__(self, *exc) -> bool: + if self.cfg.decoding.write_sentences: + self.hypo_words_file.close() + self.hypo_units_file.close() + self.ref_words_file.close() + self.ref_units_file.close() + return False + + def __iter__(self) -> Any: + for sample in self.progress_bar: + if not self.cfg.common.cpu: + sample = utils.move_to_cuda(sample) + + # Happens on the last batch. + if "net_input" not in sample: + continue + yield sample + + def log(self, *args, **kwargs): + self.progress_bar.log(*args, **kwargs) + + def print(self, *args, **kwargs): + self.progress_bar.print(*args, **kwargs) + + def get_res_file(self, fname: str) -> None: + if self.data_parallel_world_size > 1: + fname = f"{fname}.{self.data_parallel_rank}" + return open(fname, "w", buffering=1) + + def merge_shards(self) -> None: + """Merges all shard files into shard 0, then removes shard suffix.""" + + shard_id = self.data_parallel_rank + num_shards = self.data_parallel_world_size + + def merge_shards_with_root(fname: str) -> None: + logger.info("Merging %s on shard %d", fname, shard_id) + base_fpath = Path(f"{fname}.0") + with open(base_fpath, "a") as out_file: + for s in range(1, num_shards): + shard_fpath = Path(f"{fname}.{s}") + with open(shard_fpath, "r") as in_file: + for line in in_file: + out_file.write(line) + shard_fpath.unlink() + shutil.move(f"{fname}.0", fname) + + if shard_id == (0 % num_shards): + merge_shards_with_root("hypo.word") + if shard_id == (1 % num_shards): + merge_shards_with_root("hypo.units") + if shard_id == (2 % num_shards): + merge_shards_with_root("ref.word") + if shard_id == (3 % num_shards): + merge_shards_with_root("ref.units") + dist.barrier() + + def optimize_model(self, model: FairseqModel) -> None: + gcfg = self.cfg.generation + model.make_generation_fast_( + beamable_mm_beam_size=None if gcfg.no_beamable_mm else gcfg.beam, + need_attn=gcfg.print_alignment, + ) + if self.cfg.common.fp16: + model.half() + if not self.cfg.common.cpu: + model.cuda() + + def load_model_ensemble(self) -> Tuple[List[FairseqModel], FairseqDataclass]: + arg_overrides = ast.literal_eval(self.cfg.common_eval.model_overrides) + models, saved_cfg = checkpoint_utils.load_model_ensemble( + utils.split_paths(self.cfg.common_eval.path), + arg_overrides=arg_overrides, + task=self.task, + suffix=self.cfg.checkpoint.checkpoint_suffix, + strict=(self.cfg.checkpoint.checkpoint_shard_count == 1), + num_shards=self.cfg.checkpoint.checkpoint_shard_count, + ) + for model in models: + self.optimize_model(model) + return models, saved_cfg + + def get_dataset_itr(self, disable_iterator_cache: bool = False) -> None: + return self.task.get_batch_iterator( + dataset=self.task.dataset(self.cfg.dataset.gen_subset), + max_tokens=self.cfg.dataset.max_tokens, + max_sentences=self.cfg.dataset.batch_size, + max_positions=(sys.maxsize, sys.maxsize), + ignore_invalid_inputs=self.cfg.dataset.skip_invalid_size_inputs_valid_test, + required_batch_size_multiple=self.cfg.dataset.required_batch_size_multiple, + seed=self.cfg.common.seed, + num_shards=self.data_parallel_world_size, + shard_id=self.data_parallel_rank, + num_workers=self.cfg.dataset.num_workers, + data_buffer_size=self.cfg.dataset.data_buffer_size, + disable_iterator_cache=disable_iterator_cache, + ).next_epoch_itr(shuffle=False) + + def build_progress_bar( + self, + epoch: Optional[int] = None, + prefix: Optional[str] = None, + default_log_format: str = "tqdm", + ) -> BaseProgressBar: + return progress_bar.progress_bar( + iterator=self.get_dataset_itr(), + log_format=self.cfg.common.log_format, + log_interval=self.cfg.common.log_interval, + epoch=epoch, + prefix=prefix, + tensorboard_logdir=self.cfg.common.tensorboard_logdir, + default_log_format=default_log_format, + ) + + @property + def data_parallel_world_size(self): + if self.cfg.distributed_training.distributed_world_size == 1: + return 1 + return distributed_utils.get_data_parallel_world_size() + + @property + def data_parallel_rank(self): + if self.cfg.distributed_training.distributed_world_size == 1: + return 0 + return distributed_utils.get_data_parallel_rank() + + def process_sentence( + self, + sample: Dict[str, Any], + hypo: Dict[str, Any], + sid: int, + batch_id: int, + ) -> Tuple[int, int]: + speaker = None # Speaker can't be parsed from dataset. + + if "target_label" in sample: + toks = sample["target_label"] + else: + toks = sample["target"] + toks = toks[batch_id, :] + + # Processes hypothesis. + hyp_pieces = self.tgt_dict.string(hypo["tokens"].int().cpu()) + if "words" in hypo: + hyp_words = " ".join(hypo["words"]) + else: + hyp_words = post_process(hyp_pieces, + self.cfg.common_eval.post_process) + + # Processes target. + target_tokens = utils.strip_pad(toks, self.tgt_dict.pad()) + tgt_pieces = self.tgt_dict.string(target_tokens.int().cpu()) + tgt_words = post_process(tgt_pieces, + self.cfg.common_eval.post_process) + + if self.cfg.decoding.write_sentences: + print(f"{hyp_pieces} ({speaker}-{sid})", file=self.hypo_units_file) + print(f"{hyp_words} ({speaker}-{sid})", file=self.hypo_words_file) + print(f"{tgt_pieces} ({speaker}-{sid})", file=self.ref_units_file) + print(f"{tgt_words} ({speaker}-{sid})", file=self.ref_words_file) + + hyp_words, tgt_words = hyp_words.split(), tgt_words.split() + + return editdistance.eval(hyp_words, tgt_words), len(tgt_words) + + def process_sample(self, sample: Dict[str, Any]) -> None: + self.gen_timer.start() + hypos = self.task.inference_step( + generator=self.generator, + models=self.models, + sample=sample, + ) + num_generated_tokens = sum(len(h[0]["tokens"]) for h in hypos) + self.gen_timer.stop(num_generated_tokens) + self.wps_meter.update(num_generated_tokens) + + for batch_id, sample_id in enumerate(sample["id"].tolist()): + errs, length = self.process_sentence( + sample=sample, + sid=sample_id, + batch_id=batch_id, + hypo=hypos[batch_id][0], + ) + self.total_errors += errs + self.total_length += length + + self.log({"wps": round(self.wps_meter.avg)}) + if "nsentences" in sample: + self.num_sentences += sample["nsentences"] + else: + self.num_sentences += sample["id"].numel() + + def log_generation_time(self) -> None: + logger.info("Processed %d sentences (%d tokens) in %.1fs %.2f " + "sentences per second, %.2f tokens per second)", + self.num_sentences, self.gen_timer.n, self.gen_timer.sum, + self.num_sentences / self.gen_timer.sum, + 1.0 / self.gen_timer.avg) + + +def parse_wer(wer_file: Path) -> float: + with open(wer_file, "r") as f: + return float(f.readline().strip().split(" ")[1]) + + +def get_wer_file(cfg: InferConfig) -> Path: + """Hashes the decoding parameters to a unique file ID.""" + if cfg.decoding.unique_wer_file: + yaml_str = OmegaConf.to_yaml(cfg.decoding) + fid = int(hashlib.md5(yaml_str.encode("utf-8")).hexdigest(), 16) + return Path(f"wer.{fid % 1000000}") + else: + return Path("wer") + + +def main(cfg: InferConfig) -> float: + """Entry point for main processing logic. + + Args: + cfg: The inferance configuration to use. + wer: Optional shared memory pointer for returning the WER. If not None, + the final WER value will be written here instead of being returned. + + Returns: + The final WER if `wer` is None, otherwise None. + """ + + yaml_str, wer_file = OmegaConf.to_yaml(cfg.decoding), get_wer_file(cfg) + + # Validates the provided configuration. + if cfg.dataset.max_tokens is None and cfg.dataset.batch_size is None: + cfg.dataset.max_tokens = 4000000 + if not cfg.common.cpu and not torch.cuda.is_available(): + raise ValueError("CUDA not found; set `cpu=True` to run without CUDA") + if cfg.generation.nbest > 1: + raise ValueError("`nbest > 1` not implemented yet") + + with InferenceProcessor(cfg) as processor: + for sample in processor: + processor.process_sample(sample) + + processor.log_generation_time() + + if cfg.decoding.write_sentences: + processor.merge_shards() + + errs_t, leng_t = processor.total_errors, processor.total_length + + if cfg.common.cpu: + logger.warning("Merging WER requires CUDA.") + else: + stats = torch.LongTensor([errs_t, leng_t]).cuda() + dist.all_reduce(stats, op=dist.ReduceOp.SUM) + errs_t, leng_t = stats[0].item(), stats[1].item() + + wer = errs_t * 100.0 / leng_t + + if distributed_utils.is_master(cfg.distributed_training): + with open(wer_file, "w") as f: + f.write(f"WER: {wer}\n\n{yaml_str}") + + return wer + + +@hydra.main(config_path=config_path, config_name="infer") +def hydra_main(cfg: InferConfig) -> None: + container = OmegaConf.to_container(cfg, resolve=True, enum_to_str=True) + cfg = OmegaConf.create(container) + OmegaConf.set_struct(cfg, True) + + if cfg.common.reset_logging: + reset_logging() + + logger.info("Config:\n%s", OmegaConf.to_yaml(cfg)) + logger.info("Working directory: %s", Path.cwd()) + wer = float("inf") + + try: + if cfg.common.profile: + with torch.cuda.profiler.profile(): + with torch.autograd.profiler.emit_nvtx(): + distributed_utils.call_main(cfg, main) + else: + distributed_utils.call_main(cfg, main) + + wer = parse_wer(get_wer_file(cfg)) + except BaseException as e: # pylint: disable=broad-except + if not cfg.common.suppress_crashes: + raise + else: + logger.error("Crashed! %s", str(e)) + + logger.info("Word error rate: %.4f", wer) + return wer + + +def cli_main() -> None: + try: + from hydra._internal.utils import \ + get_args # pylint: disable=import-outside-toplevel + cfg_name = get_args().config_name or "infer" + except ImportError: + logger.warning("Failed to get config name from hydra args") + cfg_name = "infer" + + cs = ConfigStore.instance() + cs.store(name=cfg_name, node=InferConfig) + + for k in InferConfig.__dataclass_fields__: + v = InferConfig.__dataclass_fields__[k].default + try: + cs.store(name=k, node=v) + except BaseException: + logger.error(f"{k} - {v}") + raise + + hydra_main() # pylint: disable=no-value-for-parameter + + +if __name__ == "__main__": + cli_main() From 82ec2e722f6fe75686ab2abc872b487ca748f1ce Mon Sep 17 00:00:00 2001 From: Pranav Deshpande <pranavcd@fb.com> Date: Tue, 2 Feb 2021 15:49:39 -0800 Subject: [PATCH 181/774] Fix the task data arg conversion to string. Summary: We were getting some test failures on our end due to incompatibility of task data argument type. The actual exception is defined in this task: T83395097 and T83395052. Fixing the task data arg to be a string instead of list of strings. Reviewed By: myleott Differential Revision: D26205482 fbshipit-source-id: d29d1ee7c469177e8bdad7ca603938f8450bd81c --- fairseq/checkpoint_utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 79c811424a..2f209b6b39 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -546,6 +546,9 @@ def _upgrade_state_dict(state): # convert legacy float learning rate to List[float] if hasattr(state["args"], "lr") and isinstance(state["args"].lr, float): state["args"].lr = [state["args"].lr] + # convert task data arg to a string instead of List[string] + if hasattr(state["args"], "data") and isinstance(state["args"].data, list) and len(state["args"].data) > 0: + state["args"].data = state["args"].data[0] state["cfg"] = convert_namespace_to_omegaconf(state["args"]) From 62c1bb307582a481629662cca4ce7005d8c0c236 Mon Sep 17 00:00:00 2001 From: Giri Anantharaman <giriman@learnfair6000.h2.fair> Date: Wed, 3 Feb 2021 04:48:27 -0800 Subject: [PATCH 182/774] Adding initialization for `num_pipelines_per_node` (#1599) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: …hod` to avoid unbounded local error. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Adding initialization for `num_pipelines_per_node` in `infer_init_method` in `distributed/utils.py` ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1599 Reviewed By: myleott Differential Revision: D26208044 Pulled By: girifb fbshipit-source-id: 98d3c0b70b59a5e0abb027850baa3bc44d9c3c78 --- fairseq/distributed/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index c39dc6d912..e3d8e1e0d3 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -47,6 +47,7 @@ def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False): if cfg.distributed_init_method is not None or cfg.tpu: return + num_pipelines_per_node = None if cfg.pipeline_model_parallel: num_pipeline_devices, num_pipelines_per_node = _pipeline_parallel_pre_init(cfg) From 83391858c9ca951bb243d60ba3f5f23b87e99cf8 Mon Sep 17 00:00:00 2001 From: Yuriy Nazarov <nazarov.yuriy.pavlovich@gmail.com> Date: Wed, 3 Feb 2021 08:59:55 -0800 Subject: [PATCH 183/774] Update lang-pairs path and add fixed-dictionary for small models (#3084) Summary: With missing file extension in --lang-pairs option generation from 418M and 1.2B Models fails with the following error ``` ValueError: language pair en-fr contains languages that are not in the language dictionary; langs: ['language_pairs_small_models'] ``` However generation still fails after restoring file extension with following error: ``` RuntimeError: Error(s) in loading state_dict for TransformerModel: size mismatch for encoder.embed_tokens.weight: copying a param with shape torch.Size([128112, 1024]) from checkpoint, the shape in current model is torch.Size([128104, 1024]). size mismatch for decoder.embed_tokens.weight: copying a param with shape torch.Size([128112, 1024]) from checkpoint, the shape in current model is torch.Size([128104, 1024]). size mismatch for decoder.output_projection.weight: copying a param with shape torch.Size([128112, 1024]) from checkpoint, the shape in current model is torch.Size([128104, 1024]). ``` This could be resolved by adding --fixed-dictionary model_dict.128k.txt like in Generation for the 12B model section. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3084 Reviewed By: huihuifan Differential Revision: D26225960 Pulled By: myleott fbshipit-source-id: 0cabe1fd074e45484264d551117704180c7ade9f --- examples/m2m_100/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/m2m_100/README.md b/examples/m2m_100/README.md index f1b465c7b9..05801584d6 100644 --- a/examples/m2m_100/README.md +++ b/examples/m2m_100/README.md @@ -130,7 +130,7 @@ wget https://dl.fbaipublicfiles.com/m2m_100/418M_last_checkpoint.pt wget https://dl.fbaipublicfiles.com/m2m_100/1.2B_last_checkpoint.pt # Generation: -fairseq-generate $binarized_data_path --batch-size 32 --path $path_to_model -s en -t fr --remove-bpe 'sentencepiece' --beam 5 --task translation_multi_simple_epoch --lang-pairs language_pairs_small_models --decoder-langtok --encoder-langtok src --gen-subset test > gen_out +fairseq-generate $binarized_data_path --batch-size 32 --path $path_to_model --fixed-dictionary model_dict.128k.txt -s en -t fr --remove-bpe 'sentencepiece' --beam 5 --task translation_multi_simple_epoch --lang-pairs language_pairs_small_models.txt --decoder-langtok --encoder-langtok src --gen-subset test > gen_out ``` ### 12B Model From e802a30bffdad0b22ad6efc413230ca348f8f50b Mon Sep 17 00:00:00 2001 From: Xu Song <xusong.vip@gmail.com> Date: Wed, 3 Feb 2021 09:43:42 -0800 Subject: [PATCH 184/774] Fix hyperlink (#3193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fix hyperlink ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3193 Reviewed By: ngoyal2707 Differential Revision: D26225560 Pulled By: myleott fbshipit-source-id: a67a11cf76d1f003d8408b15edbe30f3f7b4fd5b --- examples/bart/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/bart/README.md b/examples/bart/README.md index e891894a84..013a809be6 100644 --- a/examples/bart/README.md +++ b/examples/bart/README.md @@ -1,6 +1,6 @@ # BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension -[https://arxiv.org/pdf/1910.13461.pdf] +[https://arxiv.org/abs/1910.13461](https://arxiv.org/abs/1910.13461) ## Introduction From 6ec7ed9920c64ae99a787c0885c543896b525df0 Mon Sep 17 00:00:00 2001 From: Xu Song <xusong.vip@gmail.com> Date: Wed, 3 Feb 2021 11:25:52 -0800 Subject: [PATCH 185/774] Fix logger error (#3184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fix logger error ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3184 Reviewed By: ngoyal2707 Differential Revision: D26225518 Pulled By: myleott fbshipit-source-id: eeffc5ede7de1b335148d9a2a2a9cf69fc7630ad --- fairseq/models/bart/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/models/bart/model.py b/fairseq/models/bart/model.py index 44f03b0162..71d0b27cd2 100644 --- a/fairseq/models/bart/model.py +++ b/fairseq/models/bart/model.py @@ -277,7 +277,7 @@ def truncate_emb(key): cur_state = self.classification_heads.state_dict() for k, v in cur_state.items(): if prefix + "classification_heads." + k not in state_dict: - logger.info("Overwriting", prefix + "classification_heads." + k) + logger.info("Overwriting " + prefix + "classification_heads." + k) state_dict[prefix + "classification_heads." + k] = v From fd624018bf3e834c09cc03695a8fa0bcaa4a10f3 Mon Sep 17 00:00:00 2001 From: Xu Song <xusong.vip@gmail.com> Date: Wed, 3 Feb 2021 11:31:36 -0800 Subject: [PATCH 186/774] Fix AttributeError: 'Namespace' object has no attribute 'max_positions' (#3183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fix AttributeError: 'Namespace' object has no attribute 'max_positions' https://github.com/pytorch/fairseq/blob/master/examples/bart/README.glue.md#3-fine-tuning-on-glue-task ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3183 Reviewed By: ngoyal2707 Differential Revision: D26225511 Pulled By: myleott fbshipit-source-id: 29e219b3d9be552aa3f17963b1095c9aa610f4a1 --- fairseq/tasks/sentence_prediction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/tasks/sentence_prediction.py b/fairseq/tasks/sentence_prediction.py index 0ec3824d04..f5bead972f 100644 --- a/fairseq/tasks/sentence_prediction.py +++ b/fairseq/tasks/sentence_prediction.py @@ -174,7 +174,7 @@ def make_dataset(key, dictionary): split, self.args.shorten_data_split_list, self.args.shorten_method, - self.args.max_positions, + self.max_positions(), self.args.seed, ) From 51c312a30f33e3366b1bb61084d037a90aa1d4a0 Mon Sep 17 00:00:00 2001 From: Sugiyama <h.sugi@ieee.org> Date: Wed, 3 Feb 2021 11:55:02 -0800 Subject: [PATCH 187/774] Modify eval_bleu_args to Optional (#3175) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3158 . ## PR review Fixes bug of loading previously trained translation-task model. It is not necessary to define eval_bleu_args and eval_bleu_detok_args when we use eval_bleu=False. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3175 Reviewed By: alexeib Differential Revision: D26225882 Pulled By: myleott fbshipit-source-id: ec5908179560cc44c31bac29831beb62dd81305d --- fairseq/tasks/translation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index d975fd49d2..90635d882f 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -228,7 +228,7 @@ class TranslationConfig(FairseqDataclass): eval_bleu: bool = field( default=False, metadata={"help": "evaluation with BLEU scores"} ) - eval_bleu_args: str = field( + eval_bleu_args: Optional[str] = field( default="{}", metadata={ "help": 'generation args for BLUE scoring, e.g., \'{"beam": 4, "lenpen": 0.6}\', as JSON string' @@ -241,7 +241,7 @@ class TranslationConfig(FairseqDataclass): "use 'space' to disable detokenization; see fairseq.data.encoders for other options" }, ) - eval_bleu_detok_args: str = field( + eval_bleu_detok_args: Optional[str] = field( default="{}", metadata={"help": "args for building the tokenizer, if needed, as JSON string"}, ) From 791ab7c20831a76a9196aaf0db3a2cb1cf906dde Mon Sep 17 00:00:00 2001 From: Hongfei XU <anoidgit@users.noreply.github.com> Date: Wed, 3 Feb 2021 12:03:15 -0800 Subject: [PATCH 188/774] More accurate label smoothing loss computation (#3182) Summary: It seems that the current implementation uses a slightly larger label smoothing value, for a large vocabulary, it is fine, but it can be more different with a small vocabulary size. By changing these 2 lines, the computation of label smoothing loss shall be consistent with the standard. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3182 Reviewed By: glample Differential Revision: D26225506 Pulled By: myleott fbshipit-source-id: 75447275e32336ae3b52e732e6124e15d0043b74 --- fairseq/criterions/label_smoothed_cross_entropy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/criterions/label_smoothed_cross_entropy.py b/fairseq/criterions/label_smoothed_cross_entropy.py index cb47a1582f..56d63e3e1b 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy.py +++ b/fairseq/criterions/label_smoothed_cross_entropy.py @@ -45,8 +45,8 @@ def label_smoothed_nll_loss(lprobs, target, epsilon, ignore_index=None, reduce=T if reduce: nll_loss = nll_loss.sum() smooth_loss = smooth_loss.sum() - eps_i = epsilon / lprobs.size(-1) - loss = (1.0 - epsilon) * nll_loss + eps_i * smooth_loss + eps_i = epsilon / (lprobs.size(-1) - 1) + loss = (1.0 - epsilon - eps_i) * nll_loss + eps_i * smooth_loss return loss, nll_loss From 81e38ed39da02b5104939cef941bd848b87f9e26 Mon Sep 17 00:00:00 2001 From: Tim Gates <tim.gates@iress.com> Date: Wed, 3 Feb 2021 12:04:25 -0800 Subject: [PATCH 189/774] docs: fix simple typo, efficieny -> efficiency (#3070) Summary: There is a small typo in fairseq/modules/dynamic_convolution.py, fairseq/modules/dynamicconv_layer/dynamicconv_layer.py. Should read `efficiency` rather than `efficieny`. Semi-automated pull request generated by https://github.com/timgates42/meticulous/blob/master/docs/NOTE.md Pull Request resolved: https://github.com/pytorch/fairseq/pull/3070 Reviewed By: huihuifan Differential Revision: D26225968 Pulled By: myleott fbshipit-source-id: fb7479f9678bc420e80fbb72c5389a54ad4d4c1d --- fairseq/modules/dynamic_convolution.py | 2 +- fairseq/modules/dynamicconv_layer/dynamicconv_layer.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/modules/dynamic_convolution.py b/fairseq/modules/dynamic_convolution.py index 9f2d28da65..0121d453b9 100644 --- a/fairseq/modules/dynamic_convolution.py +++ b/fairseq/modules/dynamic_convolution.py @@ -263,7 +263,7 @@ def _forward_expanded(self, x, incremental_stat, query): weight_expanded = self.weight_dropout_module(weight_expanded, inplace=False) else: P = self.padding_l - # For efficieny, we cut the kernel size and reduce the padding when the kernel is larger than the length + # For efficiency, we cut the kernel size and reduce the padding when the kernel is larger than the length if K > T and P == K - 1: weight = weight.narrow(2, K - T, T) K, P = T, T - 1 diff --git a/fairseq/modules/dynamicconv_layer/dynamicconv_layer.py b/fairseq/modules/dynamicconv_layer/dynamicconv_layer.py index 4a683d2690..711ed03483 100644 --- a/fairseq/modules/dynamicconv_layer/dynamicconv_layer.py +++ b/fairseq/modules/dynamicconv_layer/dynamicconv_layer.py @@ -212,7 +212,7 @@ def _forward_expanded(self, x, incremental_stat, query): weight_expanded = self.weight_dropout_module(weight_expanded, inplace=False) else: P = self.padding_l - # For efficieny, we cut the kernel size and reduce the padding when the kernel is larger than the length + # For efficiency, we cut the kernel size and reduce the padding when the kernel is larger than the length if K > T and P == K - 1: weight = weight.narrow(2, K - T, T) K, P = T, T - 1 From e996bddcd7b244b1e22d476bc6f402e4ff86167c Mon Sep 17 00:00:00 2001 From: zzxn <zzxnhackman@foxmail.com> Date: Wed, 3 Feb 2021 12:07:16 -0800 Subject: [PATCH 190/774] A small fix on a problem on Windows: AttributeError: module 'signal' has no attribute 'SIGKILL' (#3188) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3187 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3188 Reviewed By: lematt1991 Differential Revision: D26225553 Pulled By: myleott fbshipit-source-id: 7aff636f9ba3392bee6cdf305e849aa5c8994a5b --- fairseq/distributed/distributed_timeout_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/distributed/distributed_timeout_wrapper.py b/fairseq/distributed/distributed_timeout_wrapper.py index c8ab477073..18107ef27e 100644 --- a/fairseq/distributed/distributed_timeout_wrapper.py +++ b/fairseq/distributed/distributed_timeout_wrapper.py @@ -33,7 +33,7 @@ class DistributedTimeoutWrapper(nn.Module): (set to a value <= 0 to disable the timeout) signal (Optional): signal to send once timeout is triggered """ - def __init__(self, module: nn.Module, timeout: int, signal=signal.SIGKILL): + def __init__(self, module: nn.Module, timeout: int, signal=signal.SIGINT): super().__init__() self.module = module self.timeout = timeout From de3e0fc65158fecf7e6ffa464003839c70a7494f Mon Sep 17 00:00:00 2001 From: Muhammad Khalifa <moyle2010@gmail.com> Date: Wed, 3 Feb 2021 12:11:31 -0800 Subject: [PATCH 191/774] Added shorten dataset to denoising task (#3148) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/2318 The denoising task had no truncate option, which caused errors with longer sentences. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3148 Reviewed By: joshim5 Differential Revision: D26225934 Pulled By: myleott fbshipit-source-id: 338194e570501293bc5d3b61b8522416d1e6cf07 --- fairseq/tasks/denoising.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/fairseq/tasks/denoising.py b/fairseq/tasks/denoising.py index 41bddc1a05..cbf01e14df 100644 --- a/fairseq/tasks/denoising.py +++ b/fairseq/tasks/denoising.py @@ -21,6 +21,7 @@ data_utils, ) from fairseq.data.encoders.utils import get_whole_word_mask +from fairseq.data.shorten_dataset import maybe_shorten_dataset from fairseq.tasks import LegacyFairseqTask, register_task import numpy as np @@ -121,6 +122,20 @@ def add_args(parser): help="max number of tokens in the target sequence", ) + parser.add_argument( + "--shorten-method", + default="none", + choices=["none", "truncate", "random_crop"], + help="if not none, shorten sequences that exceed --tokens-per-sample", + ) + parser.add_argument( + "--shorten-data-split-list", + default="", + help="comma-separated list of dataset splits to apply shortening to, " + 'e.g., "train,valid" (default: all dataset splits)', + ) + + def __init__(self, args, dictionary): super().__init__(args) self.dictionary = dictionary @@ -162,6 +177,15 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): dataset = StripTokenDataset(dataset, self.dictionary.eos()) + dataset = maybe_shorten_dataset( + dataset, + split, + self.args.shorten_data_split_list, + self.args.shorten_method, + self.args.tokens_per_sample, + self.args.seed, + ) + # create continuous blocks of tokens dataset = TokenBlockDataset( dataset, From 4c197de87f92b0bd7e427aa3e094d05112b325a0 Mon Sep 17 00:00:00 2001 From: Harveen Singh Chadha <30959215+harveenchadha@users.noreply.github.com> Date: Wed, 3 Feb 2021 12:15:10 -0800 Subject: [PATCH 192/774] Fixes #3005 (#3122) Summary: The normalize and encoder_embed_dim are not present in base pretraining config which leads to errors during finetuning. ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3005 Pull Request resolved: https://github.com/pytorch/fairseq/pull/3122 Reviewed By: alexeib Differential Revision: D26225929 Pulled By: myleott fbshipit-source-id: 38067492b0241a30f84dc439f704324a032e054b --- .../wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml b/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml index 767aee2852..b686e21ab1 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_base_librispeech.yaml @@ -15,6 +15,7 @@ task: data: ??? max_sample_size: 250000 min_sample_size: 32000 + normalize: false dataset: num_workers: 6 @@ -53,3 +54,4 @@ model: dropout_input: 0.1 dropout_features: 0.1 feature_grad_mult: 0.1 + encoder_embed_dim: 768 From 8629245b0329a7e704ebc7ec05b94ac094468c1b Mon Sep 17 00:00:00 2001 From: markaa <oma654@yandex.ru> Date: Wed, 3 Feb 2021 12:25:02 -0800 Subject: [PATCH 193/774] Added weight initialization for ConvTBC (#3179) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3131 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3179 Reviewed By: huihuifan Differential Revision: D26225878 Pulled By: myleott fbshipit-source-id: 52267d10db6ec86be1c89207a768ae8b54ae1f82 --- fairseq/modules/conv_tbc.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fairseq/modules/conv_tbc.py b/fairseq/modules/conv_tbc.py index 79b2b2ad57..65e17ec94f 100644 --- a/fairseq/modules/conv_tbc.py +++ b/fairseq/modules/conv_tbc.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import torch +from torch import nn from torch.nn.modules.utils import _single from torch import Tensor @@ -27,6 +28,12 @@ def __init__(self, in_channels, out_channels, kernel_size, padding=0): ) self.bias = torch.nn.Parameter(torch.Tensor(out_channels)) + self.reset_parameters() + + def reset_parameters(self): + nn.init.xavier_normal_(self.weight) + nn.init.zeros_(self.bias) + def conv_tbc(self, input: Tensor): return torch.conv_tbc( input.contiguous(), self.weight, self.bias, self.padding[0] From b4843681b4d5af442febf8caba58ca9600b01656 Mon Sep 17 00:00:00 2001 From: Xu Song <xusong.vip@gmail.com> Date: Wed, 3 Feb 2021 12:27:18 -0800 Subject: [PATCH 194/774] Update sentence_prediction.py (#3165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes warning local variable `label_dict` is not used https://github.com/pytorch/fairseq/blob/bfcc13e20a6cfa18fb25daaae39644f9b7872699/fairseq/tasks/sentence_prediction.py#L122-L132 ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3165 Reviewed By: ngoyal2707 Differential Revision: D26225892 Pulled By: myleott fbshipit-source-id: f4fe0ceb6f0959112a61c119cf437405d01179ed --- fairseq/tasks/sentence_prediction.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq/tasks/sentence_prediction.py b/fairseq/tasks/sentence_prediction.py index f5bead972f..67acf7d377 100644 --- a/fairseq/tasks/sentence_prediction.py +++ b/fairseq/tasks/sentence_prediction.py @@ -119,9 +119,8 @@ def setup_task(cls, args, **kwargs): ) logger.info("[input] dictionary: {} types".format(len(data_dict))) - label_dict = None + # load label dictionary if not args.regression_target: - # load label dictionary label_dict = cls.load_dictionary( args, os.path.join(args.data, "label", "dict.txt"), From 4f9831bf847b8595f5590faf30b2f0af6a03bac4 Mon Sep 17 00:00:00 2001 From: Patrick von Platen <patrick.v.platen@gmail.com> Date: Thu, 4 Feb 2021 18:34:37 -0800 Subject: [PATCH 195/774] Add small section for wav2vec 2.0 HF Transformers implementation (#3216) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3216 Reviewed By: aconneau Differential Revision: D26269645 Pulled By: alexeib fbshipit-source-id: 239af3a16ef39b90fc7fe71b2e02e068b7727040 --- examples/wav2vec/README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index b3300a8ed8..663adf97dc 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -147,6 +147,35 @@ python examples/speech_recognition/infer.py /checkpoint/abaevski/data/speech/lib To get raw numbers, use --w2l-decoder viterbi and omit the lexicon. To use the transformer language model, use --w2l-decoder fairseqlm. +## Use wav2vec 2.0 with 🤗Transformers: + +Wav2Vec2 is also available in the [🤗Transformers library](https://github.com/huggingface/transformers) since vesion 4.3. + +Pretrained Models can be found on the [hub](https://huggingface.co/models?filter=wav2vec2) +and documentation can be found [here](https://huggingface.co/transformers/master/model_doc/wav2vec2.html). + +Usage example: + +```python +# !pip install transformers +import soundfile as sf +import torch +from transformers import Wav2Vec2ForMaskedLM, Wav2Vec2Tokenizer + +# load pretrained model +tokenizer = Wav2Vec2Tokenizer.from_pretrained("facebook/wav2vec2-base-960h") +model = Wav2Vec2ForMaskedLM.from_pretrained("facebook/wav2vec2-base-960h") + +# load audio +audio_input, _ = sf.read("path/to/audio/file") + +# transcribe +input_values = tokenizer(audio_input, return_tensors="pt").input_values +logits = model(input_values).logits +predicted_ids = torch.argmax(logits, dim=-1) +transcription = tokenizer.batch_decode(predicted_ids)[0] +``` + # wav2vec Example to train a wav2vec model as described in [wav2vec: Unsupervised Pre-training for Speech Recognition (Schneider et al., 2019)](https://arxiv.org/abs/1904.05862). From 9316f13ad53fa532c7306c7261e4d76c58e38b48 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 4 Feb 2021 21:36:18 -0800 Subject: [PATCH 196/774] Add interactive.py support for S2T Summary: Add interactive.py support for S2T Github issue: https://github.com/pytorch/fairseq/issues/3146 Reviewed By: jmp84 Differential Revision: D26260681 fbshipit-source-id: 7f2f6e49f8e4b7767550665a3cfe12c962469a7d --- examples/speech_to_text/README.md | 14 +++++++++++--- examples/speech_to_text/docs/covost_example.md | 9 +++++++++ .../speech_to_text/docs/librispeech_example.md | 8 ++++++++ fairseq/tasks/fairseq_task.py | 10 ++++++++++ fairseq/tasks/speech_to_text.py | 12 +++++++++--- fairseq_cli/interactive.py | 16 +++++----------- 6 files changed, 52 insertions(+), 17 deletions(-) diff --git a/examples/speech_to_text/README.md b/examples/speech_to_text/README.md index 0bd8bfdac9..4b6f89d105 100644 --- a/examples/speech_to_text/README.md +++ b/examples/speech_to_text/README.md @@ -19,9 +19,14 @@ Fairseq S2T also employs a YAML file for data related configurations: tokenizer for the target text, feature transforms such as CMVN (cepstral mean and variance normalization) and SpecAugment, temperature-based resampling, etc. -## Model Training & Evaluation -Fairseq S2T uses the unified `fairseq-train`/`fairseq-generate` interface for model training and evaluation. -It requires arguments `--task speech_to_text` and `--arch <model architecture in fairseq.models.speech_to_text.*>`. +## Model Training +Fairseq S2T uses the unified `fairseq-train` interface for model training. It requires arguments `--task speech_to_text`, + `--arch <model architecture in fairseq.models.speech_to_text.*>` and `--config-yaml <config YAML filename>`. + +## Inference & Evaluation +Fairseq S2T uses the unified `fairseq-generate`/`fairseq-interactive` interface for inference and evaluation. It +requires arguments `--task speech_to_text` and `--config-yaml <config YAML filename>`. The interactive console takes +audio paths (one per line) as inputs. ## Examples @@ -32,6 +37,9 @@ It requires arguments `--task speech_to_text` and `--arch <model architecture in - [Speech-to-Text Translation (ST) on CoVoST 2](docs/covost_example.md) ## Updates +- 02/04/2021: Added interactive decoding (`fairseq-interactive`) support. Examples: + [ASR (LibriSpeech)](docs/librispeech_example.md#interactive-decoding) + and [ST (CoVoST 2)](docs/covost_example.md#interactive-decoding). - 01/08/2021: Several fixes for S2T Transformer model, inference-time de-tokenization, scorer configuration and data preparation scripts. We also add pre-trained models to the examples and revise the instructions. Breaking changes: the data preparation scripts now extract filterbank features without CMVN. CMVN is instead applied diff --git a/examples/speech_to_text/docs/covost_example.md b/examples/speech_to_text/docs/covost_example.md index a4ce8a10e4..55cd134c16 100644 --- a/examples/speech_to_text/docs/covost_example.md +++ b/examples/speech_to_text/docs/covost_example.md @@ -85,6 +85,15 @@ fairseq-generate ${COVOST_ROOT}/fr \ --max-tokens 50000 --beam 5 --scoring sacrebleu ``` +## Interactive Decoding +Launch the interactive console via +```bash +fairseq-interactive ${COVOST_ROOT}/fr --config-yaml config_st_fr_en.yaml \ + --task speech_to_text --path ${SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 50000 --beam 5 +``` +Type in WAV/FLAC/OGG audio paths (one per line) after the prompt. + #### Results | --arch | Params | Fr-En | De-En | Es-En | Ca-En | En-De | En-Ca | En-Fa | En-Et | Model | |---|---|---|---|---|---|---|---|---|---|---| diff --git a/examples/speech_to_text/docs/librispeech_example.md b/examples/speech_to_text/docs/librispeech_example.md index 21b754ee11..4749e6cecc 100644 --- a/examples/speech_to_text/docs/librispeech_example.md +++ b/examples/speech_to_text/docs/librispeech_example.md @@ -50,6 +50,14 @@ for SUBSET in dev-clean dev-other test-clean test-other; do done ``` +## Interactive Decoding +Launch the interactive console via +```bash +fairseq-interactive ${LS_ROOT} --config-yaml config.yaml --task speech_to_text \ + --path ${SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 +``` +Type in WAV/FLAC/OGG audio paths (one per line) after the prompt. + ## Results | --arch | Params | dev-clean | dev-other | test-clean | test-other | Model | diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index eb5e6a7694..3fe3ac995c 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -532,6 +532,16 @@ def build_bpe(self, args): """Build the tokenizer for this task.""" return encoders.build_bpe(args) + def get_interactive_tokens_and_lengths(self, lines, encode_fn): + tokens = [ + self.source_dictionary.encode_line( + encode_fn(src_str), add_if_not_exist=False + ).long() + for src_str in lines + ] + lengths = [t.numel() for t in tokens] + return tokens, lengths + class LegacyFairseqTask(FairseqTask): def __init__(self, args: Namespace): diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 8fb341b0c5..8bdf215643 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -12,6 +12,7 @@ S2TDataConfig, SpeechToTextDataset, SpeechToTextDatasetCreator, + get_features_or_waveform ) from fairseq.tasks import LegacyFairseqTask, register_task @@ -138,6 +139,11 @@ def build_bpe(self, args): logger.info(f"tokenizer: {self.data_cfg.bpe_tokenizer}") return encoders.build_bpe(Namespace(**self.data_cfg.bpe_tokenizer)) - @classmethod - def build_dataset_for_inference(cls, audio_paths, n_frames): - return SpeechToTextDataset("interactive", False, {}, audio_paths, n_frames) + def get_interactive_tokens_and_lengths(self, lines, encode_fn): + n_frames = [get_features_or_waveform(p).shape[0] for p in lines] + return lines, n_frames + + def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): + return SpeechToTextDataset( + "interactive", False, self.data_cfg, src_tokens, src_lengths + ) diff --git a/fairseq_cli/interactive.py b/fairseq_cli/interactive.py index 4785855985..cadef2821a 100644 --- a/fairseq_cli/interactive.py +++ b/fairseq_cli/interactive.py @@ -20,7 +20,6 @@ import numpy as np import torch from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils -from fairseq.data import encoders from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.token_generation_constraints import pack_constraints, unpack_constraints @@ -76,19 +75,13 @@ def encode_fn_target(x): for constraint in constraint_list ] - tokens = [ - task.source_dictionary.encode_line( - encode_fn(src_str), add_if_not_exist=False - ).long() - for src_str in lines - ] - if cfg.generation.constraints: constraints_tensor = pack_constraints(batch_constraints) else: constraints_tensor = None - lengths = [t.numel() for t in tokens] + tokens, lengths = task.get_interactive_tokens_and_lengths(lines, encode_fn) + itr = task.get_batch_iterator( dataset=task.build_dataset_for_inference( tokens, lengths, constraints=constraints_tensor @@ -176,8 +169,8 @@ def main(cfg: FairseqConfig): generator = task.build_generator(models, cfg.generation) # Handle tokenization and BPE - tokenizer = encoders.build_tokenizer(cfg.tokenizer) - bpe = encoders.build_bpe(cfg.bpe) + tokenizer = task.build_tokenizer(cfg.tokenizer) + bpe = task.build_bpe(cfg.bpe) def encode_fn(x): if tokenizer is not None: @@ -256,6 +249,7 @@ def decode_fn(x): # sort output to match input order for id_, src_tokens, hypos, info in sorted(results, key=lambda x: x[0]): + src_str = '' if src_dict is not None: src_str = src_dict.string(src_tokens, cfg.common_eval.post_process) print("S-{}\t{}".format(id_, src_str)) From 0f93bd1a7d451944b77804aaf25e40696510411b Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Fri, 5 Feb 2021 15:42:02 -0800 Subject: [PATCH 197/774] Implement Mixup as a batch transform in PySpeech Summary: This diff implements the Mixup data augmentation in PySpeech. It is implemented as `MixupBatchTransform`, which acts on batches of data instead of single instances. Such a batch transform should be called by the collater, after it collates samples into a batch and before it converts the batch from numpy arrays to PyTorch tensors. See `TALNetTask` for an example of how to use it. Sometimes we may want to apply SpecAugment after Mixup, when data instances have already been collated into batches. The class `Batchify` is a wrapper that turns an instance transform into a batch transform, by applying the instance transform to every instance in a batch. Reviewed By: nayansinghal Differential Revision: D26228942 fbshipit-source-id: b5784d8acab840d6ae6fa636d01cd7c68955d606 --- fairseq/criterions/wav2vec_criterion.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index cc454b9309..859177f2b6 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -148,7 +148,7 @@ def reduce_metrics(logging_outputs) -> None: ) metrics.log_scalar( - "loss", loss_sum / sample_size / math.log(2), sample_size, round=3 + "loss", loss_sum / (sample_size or 1) / math.log(2), sample_size, round=3 ) metrics.log_scalar("ntokens", ntokens) metrics.log_scalar("nsentences", nsentences) @@ -183,7 +183,7 @@ def reduce_metrics(logging_outputs) -> None: val = sum(log.get(k, 0) for log in logging_outputs) if k.startswith("loss"): metrics.log_scalar( - k, val / sample_size / math.log(2), sample_size, round=3 + k, val / (sample_size or 1) / math.log(2), sample_size, round=3 ) else: metrics.log_scalar(k, val / len(logging_outputs), round=3) From 5a170841f2faba7413a2d59c792bee6a3ff38838 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Sat, 6 Feb 2021 08:05:41 -0800 Subject: [PATCH 198/774] Make checkpoint wrapper pickleable (#1603) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1603 Test Plan: Imported from OSS Reviewed By: sshleifer Differential Revision: D26237760 Pulled By: myleott fbshipit-source-id: 73c67bdea4b5b16e3159a5d4f0151e514e853357 --- fairseq/modules/checkpoint_activations.py | 44 ++++++++++++----------- tests/test_activation_checkpointing.py | 11 ++++-- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index c84e70bf7b..ae07dcfaa0 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import functools from typing import Any, Dict, List, Tuple, Union import torch @@ -25,29 +26,32 @@ def checkpoint_wrapper(m, offload_to_cpu=False): checkpointed_module = checkpoint_wrapper(my_module, offload_to_cpu=True) a, b = checkpointed_module(x, y=3, z=torch.Tensor([1])) """ - original_forward = m.forward - - def _checkpointed_forward(*args, **kwargs): - # Autograd Functions in PyTorch work best with positional args, since - # the backward must return gradients (or None) for every input argument. - # We can flatten keyword arguments to make this easier. - kwarg_keys, flat_args = pack_kwargs(*args, **kwargs) - parent_ctx_dict = {"offload": offload_to_cpu} - output = CheckpointFunction.apply( - original_forward, parent_ctx_dict, kwarg_keys, *flat_args - ) - if isinstance(output, torch.Tensor): - return output - else: - packed_non_tensor_outputs = parent_ctx_dict["packed_non_tensor_outputs"] - if packed_non_tensor_outputs: - output = unpack_non_tensors(output, packed_non_tensor_outputs) - return output - - m.forward = _checkpointed_forward + m.forward = functools.partial( + _checkpointed_forward, + m.forward, # original_forward + offload_to_cpu, + ) return m +def _checkpointed_forward(original_forward, offload_to_cpu, *args, **kwargs): + # Autograd Functions in PyTorch work best with positional args, since + # the backward must return gradients (or None) for every input argument. + # We can flatten keyword arguments to make this easier. + kwarg_keys, flat_args = pack_kwargs(*args, **kwargs) + parent_ctx_dict = {"offload": offload_to_cpu} + output = CheckpointFunction.apply( + original_forward, parent_ctx_dict, kwarg_keys, *flat_args + ) + if isinstance(output, torch.Tensor): + return output + else: + packed_non_tensor_outputs = parent_ctx_dict["packed_non_tensor_outputs"] + if packed_non_tensor_outputs: + output = unpack_non_tensors(output, packed_non_tensor_outputs) + return output + + def pack_kwargs(*args, **kwargs) -> Tuple[List[str], List[Any]]: """ Usage:: diff --git a/tests/test_activation_checkpointing.py b/tests/test_activation_checkpointing.py index 4b86211bde..647a957288 100644 --- a/tests/test_activation_checkpointing.py +++ b/tests/test_activation_checkpointing.py @@ -12,7 +12,9 @@ class Model(nn.Module): - def __init__(self, use_pytorch_checkpoint=False, use_fairseq_checkpoint=False): + def __init__( + self, use_pytorch_checkpoint=False, use_fairseq_checkpoint=False, **kwargs + ): super().__init__() torch.manual_seed(0) self.use_pytorch_checkpoint = use_pytorch_checkpoint @@ -23,7 +25,7 @@ def __init__(self, use_pytorch_checkpoint=False, use_fairseq_checkpoint=False): nn.Linear(128, 32), ) if use_fairseq_checkpoint: - self.ffn = checkpoint_wrapper(self.ffn) + self.ffn = checkpoint_wrapper(self.ffn, **kwargs) self.out = nn.Linear(32, 1) def forward(self, x): @@ -60,6 +62,11 @@ def get_loss_and_gnorm(model): torch.testing.assert_allclose(no_cpt["loss"], fairseq_cpt["loss"]) torch.testing.assert_allclose(no_cpt["gnorm"], fairseq_cpt["gnorm"]) + model = Model(use_fairseq_checkpoint=True, offload_to_cpu=True).to(device) + fairseq_cpt_offload = get_loss_and_gnorm(model) + torch.testing.assert_allclose(no_cpt["loss"], fairseq_cpt_offload["loss"]) + torch.testing.assert_allclose(no_cpt["gnorm"], fairseq_cpt_offload["gnorm"]) + def test_checkpoint_wrapper_cpu(self): self._test_checkpoint_wrapper(device=torch.device("cpu")) From 7aa999f2a8084428a9675ee9d9b782bb797fd6ce Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Sat, 6 Feb 2021 08:05:41 -0800 Subject: [PATCH 199/774] Add --optimizer=cpu_adam (#1604) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1604 Test Plan: Imported from OSS Reviewed By: shruti-bh Differential Revision: D26237761 Pulled By: myleott fbshipit-source-id: 2deb78a93ca23c261c38370ac810c317e4ec20ee --- fairseq/optim/cpu_adam.py | 187 +++++++++++++++++++++++++++++ fairseq/optim/fairseq_optimizer.py | 2 + 2 files changed, 189 insertions(+) create mode 100644 fairseq/optim/cpu_adam.py diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py new file mode 100644 index 0000000000..fad5a64ecb --- /dev/null +++ b/fairseq/optim/cpu_adam.py @@ -0,0 +1,187 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import importlib +from collections.abc import Collection +from dataclasses import dataclass, field +from typing import List + +import torch +from fairseq.dataclass import FairseqDataclass +from fairseq.optim import FairseqOptimizer, register_optimizer +from omegaconf import II, DictConfig + + +try: + from deepspeed.ops.op_builder import CPUAdamBuilder + has_deepspeed_cpu_adam = True +except ImportError: + has_deepspeed_cpu_adam = False + + +@dataclass +class FairseqCPUAdamConfig(FairseqDataclass): + adam_betas: str = field( + default="(0.9, 0.999)", metadata={"help": "betas for Adam optimizer"} + ) + adam_eps: float = field( + default=1e-8, metadata={"help": "epsilon for Adam optimizer"} + ) + weight_decay: float = field(default=0.0, metadata={"help": "weight decay"}) + fp16_adam_stats: bool = field( + default=False, metadata={"help": "use FP16 stats (with automatic scaling)"} + ) + # TODO common vars below in parent + lr: List[float] = II("optimization.lr") + + +@register_optimizer("cpu_adam", dataclass=FairseqCPUAdamConfig) +class FairseqCPUAdam(FairseqOptimizer): + """Adam optimizer for fairseq, optimized for CPU tensors. + + Important note: this optimizer corresponds to the "AdamW" variant of + Adam in its weight decay behavior. As such, it is most closely + analogous to torch.optim.AdamW from PyTorch. + """ + + def __init__(self, cfg: DictConfig, params): + super().__init__(cfg) + self._optimizer = CPUAdam(params, **self.optimizer_config) + + @property + def optimizer_config(self): + """ + Return a kwarg dictionary that will be used to override optimizer + args stored in checkpoints. This allows us to load a checkpoint and + resume training using a different set of optimizer args, e.g., with a + different learning rate. + """ + return { + "lr": self.cfg.lr[0] + if isinstance(self.cfg.lr, Collection) + else self.cfg.lr, + "betas": eval(self.cfg.adam_betas), + "eps": self.cfg.adam_eps, + "weight_decay": self.cfg.weight_decay, + "use_fp16_stats": self.cfg.fp16_adam_stats, + } + + +class CPUAdam(torch.optim.Optimizer): + + optimizer_id = 0 + + def __init__( + self, + params, + lr=1e-3, + bias_correction=True, + betas=(0.9, 0.999), + eps=1e-8, + weight_decay=0, + use_fp16_stats=False, + ): + defaults = { + "lr": lr, + "bias_correction": bias_correction, + "betas": betas, + "eps": eps, + "weight_decay": weight_decay, + } + super().__init__(params, defaults) + + self.use_fp16_stats = use_fp16_stats + self.FLOAT16_MAX = 65504.0 + + if not has_deepspeed_cpu_adam: + raise ImportError("Please install DeepSpeed: pip install deepspeed") + + self.opt_id = CPUAdam.optimizer_id + CPUAdam.optimizer_id = CPUAdam.optimizer_id + 1 + + self.ds_opt_adam = CPUAdamBuilder().load() + adamw_mode = True + self.ds_opt_adam.create_adam( + self.opt_id, lr, betas[0], betas[1], eps, weight_decay, adamw_mode + ) + + @torch.no_grad() + def step(self, closure=None): + loss = None + if closure is not None: + with torch.enable_grad(): + loss = closure() + + for group_id, group in enumerate(self.param_groups): + for param_id, p in enumerate(group["params"]): + if p.grad is None: + continue + + state = self.state[p] + if len(state) == 0: + state["step"] = 0 + dtype = torch.float16 if self.use_fp16_stats else p.data.dtype + # gradient momentums + state["exp_avg"] = torch.zeros_like( + p.data, dtype=dtype, device="cpu" + ) + # gradient variances + state["exp_avg_sq"] = torch.zeros_like( + p.data, dtype=dtype, device="cpu" + ) + if self.use_fp16_stats: + assert torch.is_floating_point(p.data) + state["exp_avg_scale"] = 1.0 + state["exp_avg_sq_scale"] = 1.0 + + exp_avg, exp_avg_sq = state["exp_avg"], state["exp_avg_sq"] + + p_data_bak = p.data # backup of the original data pointer + + p.data = p.data.to(dtype=torch.float32, device="cpu") + p.grad.data = p.grad.data.to(dtype=torch.float32, device="cpu") + + if self.use_fp16_stats: + exp_avg = exp_avg.float() * state["exp_avg_scale"] + exp_avg_sq = exp_avg_sq.float() * state["exp_avg_sq_scale"] + + state["step"] += 1 + beta1, beta2 = group["betas"] + + self.ds_opt_adam.adam_update( + self.opt_id, + state["step"], + group["lr"], + beta1, + beta2, + group["eps"], + group["weight_decay"], + group["bias_correction"], + p.data, + p.grad.data, + exp_avg, + exp_avg_sq, + ) + + if p_data_bak.data_ptr() != p.data.data_ptr(): + p_data_bak.copy_(p.data) + p.data = p_data_bak + + if self.use_fp16_stats: + + def inf_norm(t): + return torch.norm(t, float("inf")) + + # from github.com/openai/jukebox/blob/master/jukebox/utils/fp16.py + state["exp_avg_scale"], state["exp_avg_sq_scale"] = ( + 1e-8 + inf_norm(exp_avg) / self.FLOAT16_MAX, + 1e-8 + inf_norm(exp_avg_sq) / self.FLOAT16_MAX, + ) + state["exp_avg"], state["exp_avg_sq"] = ( + (exp_avg / state["exp_avg_scale"]).half(), + (exp_avg_sq / state["exp_avg_sq_scale"]).half(), + ) + + return loss diff --git a/fairseq/optim/fairseq_optimizer.py b/fairseq/optim/fairseq_optimizer.py index a1c1d219a0..7e5411753a 100644 --- a/fairseq/optim/fairseq_optimizer.py +++ b/fairseq/optim/fairseq_optimizer.py @@ -103,6 +103,8 @@ def multiply_grads(self, c): """Multiplies grads by a constant *c*.""" for p in self.params: if p.grad is not None: + if torch.is_tensor(c): + c = c.to(p.grad.device) p.grad.data.mul_(c) def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): From 5605d6fbb44d7ee8240048b6a172385ce3c07c6f Mon Sep 17 00:00:00 2001 From: Arthur Guo <arthurguo@fb.com> Date: Mon, 8 Feb 2021 12:13:39 -0800 Subject: [PATCH 200/774] Refactor Python LAS Rescoring Inference Summary: This diff cleans up the code in D26195511 Differential Revision: D25857284 fbshipit-source-id: 6b445c3d263078bf711a429130d9f983421e6a10 --- fairseq/models/fairseq_decoder.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fairseq/models/fairseq_decoder.py b/fairseq/models/fairseq_decoder.py index 35a349fa5f..7eeb5c652f 100644 --- a/fairseq/models/fairseq_decoder.py +++ b/fairseq/models/fairseq_decoder.py @@ -17,6 +17,8 @@ def __init__(self, dictionary): super().__init__() self.dictionary = dictionary self.onnx_trace = False + self.adaptive_softmax = None + def forward(self, prev_output_tokens, encoder_out=None, **kwargs): """ From 6381aa2bb24f125d271e241c726a2fea581bc3c4 Mon Sep 17 00:00:00 2001 From: Ruslan Mavlyutov <mavlyutov@fb.com> Date: Mon, 8 Feb 2021 14:13:34 -0800 Subject: [PATCH 201/774] Adding FBSequenceGenerator Reviewed By: mikekgfb Differential Revision: D26228721 fbshipit-source-id: b7a83bbc719d50d677d9b4c8a74f3c20def85357 --- fairseq/tasks/fairseq_task.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 3fe3ac995c..34264bdc01 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -313,6 +313,10 @@ def build_generator( SequenceGenerator, SequenceGeneratorWithAlignment, ) + try: + from fairseq.fb_sequence_generator import FBSequenceGenerator + except ModuleNotFoundError: + pass # Choose search strategy. Defaults to Beam Search. sampling = getattr(args, "sampling", False) @@ -379,6 +383,8 @@ def build_generator( if getattr(args, "print_alignment", False): seq_gen_cls = SequenceGeneratorWithAlignment extra_gen_cls_kwargs["print_alignment"] = args.print_alignment + elif getattr(args, "fb_seq_gen", False): + seq_gen_cls = FBSequenceGenerator else: seq_gen_cls = SequenceGenerator From 3aeb8fe1007f098f629bb20cc31c339dcbf5ad57 Mon Sep 17 00:00:00 2001 From: Ning Dong <dnn@fb.com> Date: Mon, 8 Feb 2021 16:18:00 -0800 Subject: [PATCH 202/774] Explicitly annotate attn_scores as Optional[Tensor] Summary: The behavior of ternary if's type inference changed a bit with D26278969. Need to annotate explicitly for it to work. Otherwise tests fail as in T84436394. Reviewed By: nikithamalgifb Differential Revision: D26320452 fbshipit-source-id: ad61f8ba5ea730150350cb839f5d9c73d476aed4 --- fairseq/models/lstm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/models/lstm.py b/fairseq/models/lstm.py index 1a9dca3c75..12e3aff85d 100644 --- a/fairseq/models/lstm.py +++ b/fairseq/models/lstm.py @@ -535,7 +535,7 @@ def extract_features( assert ( srclen > 0 or self.attention is None ), "attention is not supported if there are no encoder outputs" - attn_scores = ( + attn_scores: Optional[Tensor] = ( x.new_zeros(srclen, seqlen, bsz) if self.attention is not None else None ) outs = [] From 4fed0beca64a52aa718371dc3b2cf1fd979197a4 Mon Sep 17 00:00:00 2001 From: Patrick von Platen <patrick.v.platen@gmail.com> Date: Wed, 10 Feb 2021 14:03:24 -0800 Subject: [PATCH 203/774] Fix padding mask for new architectures (#3228) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3227 All models that do **not** make use of group norm, such as - Wav2Vec 2.0 Large (LV-60)* - Wav2Vec 2.0 Large (LV-60) + Self Training * do need this fix IMO to able to correctly run batches through the model. Before this PR, the following code snippet failed: ```python import fairseq import torch # get model wav2vec_path = "data/wav2vec2_vox_960h_new.pt" model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task( [wav2vec_path], arg_overrides={"data": "./data"} ) model = model[0] model.eval() # create single input input_wav_0 = torch.randn((1, 2000)) input_wav_1 = torch.randn((1, 3000)) # create batched input batch_input_wav = torch.zeros((2, 3000)) batch_input_wav[0, :input_wav_0.shape[-1]] = input_wav_0 batch_input_wav[1, :input_wav_1.shape[-1]] = input_wav_1 # create padding mask padding_mask = torch.zeros((2, 3000), dtype=torch.bool) padding_mask[0, input_wav_0.shape[-1]:] = True # run batch & single output = model(source=input_wav_0, padding_mask=None)["encoder_out"] batch_output = model(source=batch_input_wav, padding_mask=padding_mask)["encoder_out"] # is equal? print("Is batched forward and simple forward equal?", torch.allclose(output[:,0], batch_output[:output.shape[0], 0], atol=1e-3)) ``` Note: It is assumed that both https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt and https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_new.pt were downloaded and stored in the folder data. Also, see [this](https://colab.research.google.com/drive/1ASZ4lVZbKkj-dvRHDl1lo0mCcsaOERlG?usp=sharing) notebook for reproducibility. This PR should fix the behavior and make the above code snippet / notebook run succesfully. ## PR review Gently pinging alexeib for Wav2Vec2 Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3228 Reviewed By: aconneau Differential Revision: D26373721 Pulled By: alexeib fbshipit-source-id: 3d5aca2f8136d1a8c4b5b4bc9c03cd05a69a3b52 --- fairseq/models/wav2vec/wav2vec2.py | 32 +++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 783ebcfe6b..644add7b17 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -443,6 +443,21 @@ def compute_preds(self, x, y, negatives): return logits + def _get_feat_extract_output_lengths(self, input_lengths: torch.LongTensor): + """ + Computes the output length of the convolutional layers + """ + + def _conv_out_length(input_length, kernel_size, stride): + return torch.floor((input_length - kernel_size) / stride + 1) + + conv_cfg_list = eval(self.cfg.conv_feature_layers) + + for i in range(len(conv_cfg_list)): + input_lengths = _conv_out_length(input_lengths, conv_cfg_list[i][1], conv_cfg_list[i][2]) + + return input_lengths.to(torch.long) + def forward(self, source, padding_mask=None, mask=True, features_only=False): if self.feature_grad_mult > 0: @@ -460,11 +475,18 @@ def forward(self, source, padding_mask=None, mask=True, features_only=False): unmasked_features = features.clone() if padding_mask is not None: - extra = padding_mask.size(1) % features.size(1) - if extra > 0: - padding_mask = padding_mask[:, :-extra] - padding_mask = padding_mask.view(padding_mask.size(0), features.size(1), -1) - padding_mask = padding_mask.all(-1) + input_lengths = (1 - padding_mask.long()).sum(-1) + # apply conv formula to get real output_lengths + output_lengths = self._get_feat_extract_output_lengths(input_lengths) + + padding_mask = torch.zeros( + features.shape[:2], dtype=features.dtype, device=features.device + ) + + # these two operations makes sure that all values + # before the output lengths indices are attended to + padding_mask[(torch.arange(padding_mask.shape[0], device=padding_mask.device), output_lengths - 1)] = 1 + padding_mask = (1 - padding_mask.flip([-1]).cumsum(-1).flip([-1])).bool() if self.post_extract_proj is not None: features = self.post_extract_proj(features) From ac90cb3085439d15af1a33cf0a0b1a6703f07413 Mon Sep 17 00:00:00 2001 From: Ruslan Mavlyutov <mavlyutov@fb.com> Date: Wed, 10 Feb 2021 14:57:17 -0800 Subject: [PATCH 204/774] Extra logging to confirm OOM source Reviewed By: myleott, chtran Differential Revision: D26348808 fbshipit-source-id: 010ef00024e02c09ec35b624f0713ce5f1f387b4 --- fairseq/trainer.py | 1 + fairseq_cli/train.py | 1 + 2 files changed, 2 insertions(+) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 49129a7fb0..24f72e2f9a 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -277,6 +277,7 @@ def consolidate_optimizer(self): def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" if self.is_data_parallel_master: # only save one checkpoint + logger.info(f"Saving checkpoint to {filename}") extra_state["metrics"] = metrics.state_dict() extra_state["previous_training_time"] = self.cumulative_training_time() checkpoint_utils.save_state( diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 9af7568a77..ec4890b9e6 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -236,6 +236,7 @@ def train( valid_subsets = cfg.dataset.valid_subset.split(",") should_stop = False num_updates = trainer.get_num_updates() + logger.info("Start iterating over samples") for i, samples in enumerate(progress): with metrics.aggregate("train_inner"), torch.autograd.profiler.record_function( "train_step-%d" % i From 7061a0ff83872ac491ba5963eb7fc04cb10d57c4 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Wed, 10 Feb 2021 16:25:25 -0800 Subject: [PATCH 205/774] better error handling for expired handles Summary: At the start of the half there were some expired handles and it was annoying to track down which datasets were responsible when sampling data among multiple datasets and which flows were running them. Lets improve the error message to address several pain points 1. Explicitly tell the user which dataset has expired handles 2. Link to a scuba query to enable the user to find all flows that have expired handles 3. Fail job if 10k handles have expired, rather than if 10k handles in a row have expired. This can detect failures from datasets that have for example 50% expired handles 4. add logging when handles fail Reviewed By: cruvadom Differential Revision: D26187820 fbshipit-source-id: 771a359ea01de80b38932921346e98cff812f2f7 --- fairseq/data/multi_corpus_dataset.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index 9c7f1cb976..7207174bf3 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -126,7 +126,11 @@ def __len__(self): def __getitem__(self, index): index, key = self._map_index(index) - return self.datasets[key][index] + try: + return self.datasets[key][index] + except Exception as e: + e.args = (f"Error from {key} dataset", *e.args) + raise def collater(self, samples): """ From ee48d1b95835a0e5fa2129219d205f8d9e748b76 Mon Sep 17 00:00:00 2001 From: pritam <pritam.damania@fb.com> Date: Thu, 11 Feb 2021 09:41:54 -0800 Subject: [PATCH 206/774] Use torch pipe if available in fairseq. (#3149) Summary: fairscale.nn.Pipe has been ported to PyTorch: https://github.com/pytorch/pytorch/blob/master/torch/distributed/pipeline/sync/pipe.py#L138. As a result, modifying the pipeline transformer to use PyTorch pipe if available. This change depends on https://github.com/pytorch/pytorch/pull/50860. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3149 Test Plan: ``` python train.py ru_en_bin/ --arch transformer_iwslt_de_en_pipeline_parallel --share-decoder-input-output-embed --optimizer adam --adam-betas '(0.9, 0.98)' --clip-norm 0.0 --lr 5e-4 --lr-scheduler inverse_sqrt --warmup-updates 4000 --dropout 0.3 --weight-decay 0.0001 --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --max-tokens 4096 --eval-bleu --eval-bleu-args '{"beam": 5, "max_len_a": 1.2, "max_len_b": 10}' --eval-bleu-detok moses --eval-bleu-remove-bpe --eval-bleu-print-samples --best-checkpoint-metric bleu --maximize-best-checkpoint-metric --pipeline-model-parallel --pipeline-balance '[1,3,5,3,3,1]' --pipeline-devices '[0,1,0,2,3,0]' --pipeline-chunks 16 --distributed-world-size 1 --distributed-no-spawn --disable-validation --max-epoch 1 ``` Output with torch pipe: ``` 2021-01-20 16:13:35 | INFO | train | epoch 001 | loss 12.676 | nll_loss 12.331 | ppl 5151.97 | wps 5108 | ups 1.66 | wpb 3081.6 | bsz 131.6 | num_updates 380 | lr 4.75e-05 | gnorm 2.08 | train_wall 229 | wall 233 2021-01-20 16:13:36 | INFO | fairseq_cli.train | done training in 233.1 seconds ``` Output with fairscale pipe: ``` 2021-01-20 14:13:59 | INFO | train | epoch 001 | loss 12.677 | nll_loss 12.331 | ppl 5152.07 | wps 5198.9 | ups 1.69 | wpb 3081.6 | bsz 131.6 | num_updates 380 | lr 4.75e-05 | gnorm 2.08 | train_wall 224 | wall 228 2021-01-20 14:13:59 | INFO | fairseq_cli.train | done training in 228.0 seconds ``` Reviewed By: myleott Differential Revision: D26204633 Pulled By: shruti-bh fbshipit-source-id: 535f816e8d149b47fc6ba8385981accf67257257 --- .../pipeline_parallel_transformer/model.py | 128 +++++++++++++----- 1 file changed, 92 insertions(+), 36 deletions(-) diff --git a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py index 7873611214..7f30dd98bb 100644 --- a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py +++ b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py @@ -39,15 +39,47 @@ DEFAULT_MAX_SOURCE_POSITIONS = 1024 DEFAULT_MAX_TARGET_POSITIONS = 1024 +TORCH_PIPE = False +RPC_INIT = False + +def import_pipe(): + global TORCH_PIPE + global RPC_INIT + try: + from torch.distributed.pipeline.sync import Pipe # noqa + global Pipe + from torch.distributed.pipeline.sync.utils import partition_model + global partition_model + from torch.distributed import rpc + import tempfile + TORCH_PIPE = True + # Initialize single process RPC agent since TORCH_PIPE requires + # RRef. RRef depends on RPC being initialized and as a result we initialize + # RPC with a single node. + tmpfile = tempfile.NamedTemporaryFile() + if not RPC_INIT: + rpc.init_rpc( + name="worker", + rank=0, + world_size=1, + rpc_backend_options=rpc.TensorPipeRpcBackendOptions( + init_method="file://{}".format(tmpfile.name), + ) + ) + RPC_INIT = True + logger.info('Using torch pipe') + except ImportError: + try: + from fairscale.nn import Pipe # noqa + logger.info('Using fairscale pipe') + except ImportError: + raise ImportError("Please install fairscale with: pip install fairscale") @register_model("pipeline_parallel_transformer") class PipelineParallelTransformerModel(BaseFairseqModel): def __init__(self, encoder, decoder, balance, devices, chunks, checkpoint): - try: - from fairscale.nn import Pipe - except ImportError: - raise ImportError("Please install fairscale with: pip install fairscale") + import_pipe() super().__init__() assert isinstance(encoder, FairseqEncoder) assert isinstance(decoder, FairseqDecoder) @@ -65,13 +97,20 @@ def __init__(self, encoder, decoder, balance, devices, chunks, checkpoint): self.num_decoder_modules = len(decoder_module_list) module_list = encoder_module_list + decoder_module_list self.devices = devices - self.model = Pipe( - nn.Sequential(*module_list), - balance=balance, - devices=devices, - chunks=chunks, - checkpoint=checkpoint, - ) + if TORCH_PIPE: + self.model = Pipe( + partition_model(nn.Sequential(*module_list), balance, devices), + chunks=chunks, + checkpoint=checkpoint, + ) + else: + self.model = Pipe( + nn.Sequential(*module_list), + balance=balance, + devices=devices, + chunks=chunks, + checkpoint=checkpoint, + ) self.encoder_max_positions = self.max_positions_helper( encoder.embedding_layer, "max_source_positions" ) @@ -87,7 +126,10 @@ def forward(self, src_tokens, src_lengths, prev_output_tokens): if self.training: input_lst = [src_tokens, src_lengths, prev_output_tokens] input = tuple(i.to(self.devices[0], non_blocking=True) for i in input_lst) - return self.model(input) + if TORCH_PIPE: + return self.model(input).local_value() + else: + return self.model(input) else: assert self.encoder is not None and self.decoder is not None, ( "encoder and decoder need to be initialized by " @@ -425,10 +467,7 @@ class TransformerEncoder(FairseqEncoder): def __init__(self, args, dictionary, embed_tokens, encoder_module_list=None): super().__init__(dictionary) self.register_buffer("version", torch.Tensor([3])) - try: - from fairscale.nn import Pipe - except ImportError: - raise ImportError("Please install fairscale with: pip install fairscale") + import_pipe() self.use_pipeline = encoder_module_list is not None if not self.use_pipeline: self.embedding_layer = TransformerEncoderEmbedding(args, embed_tokens) @@ -449,13 +488,20 @@ def __init__(self, args, dictionary, embed_tokens, encoder_module_list=None): f"Sum of encoder_balance={encoder_balance} is not equal " + f"to num_encoder_modules={len(encoder_module_list)}" ) - self.model = Pipe( - module=nn.Sequential(*encoder_module_list), - balance=encoder_balance, - devices=encoder_devices, - chunks=args.pipeline_chunks, - checkpoint=args.pipeline_checkpoint, - ) + if TORCH_PIPE: + self.model = Pipe( + module=partition_model(nn.Sequential(*encoder_module_list), encoder_balance, encoder_devices), + chunks=args.pipeline_chunks, + checkpoint=args.pipeline_checkpoint, + ) + else: + self.model = Pipe( + module=nn.Sequential(*encoder_module_list), + balance=encoder_balance, + devices=encoder_devices, + chunks=args.pipeline_chunks, + checkpoint=args.pipeline_checkpoint, + ) def forward(self, src_tokens, src_lengths): """ @@ -485,7 +531,10 @@ def forward(self, src_tokens, src_lengths): input_tuple = (src_tokens, src_lengths, dummy_prev_output_tokens) if self.use_pipeline: input_tuple = tuple(i.to(self.model.devices[0]) for i in input_tuple) - encoder_out = self.model(input_tuple) + if TORCH_PIPE: + encoder_out = self.model(input_tuple).local_value() + else: + encoder_out = self.model(input_tuple) else: encoder_embed_output_tuple = self.embedding_layer(input_tuple) encoder_layers_output = self.encoder_layers(encoder_embed_output_tuple) @@ -561,10 +610,7 @@ def __init__( ): super().__init__(dictionary) self.register_buffer("version", torch.Tensor([3])) - try: - from fairscale.nn import Pipe - except ImportError: - raise ImportError("Please install fairscale with: pip install fairscale") + import_pipe() self.use_pipeline = decoder_module_list is not None if not self.use_pipeline: self.embedding_layer = TransformerDecoderEmbedding(args, embed_tokens) @@ -586,13 +632,20 @@ def __init__( f"Sum of decoder_balance={decoder_balance} is not equal " + f"to num_decoder_modules={len(decoder_module_list)}" ) - self.model = Pipe( - module=nn.Sequential(*decoder_module_list), - balance=decoder_balance, - devices=decoder_devices, - chunks=args.pipeline_chunks, - checkpoint=args.pipeline_checkpoint, - ) + if TORCH_PIPE: + self.model = Pipe( + module=partition_model(nn.Sequential(*decoder_module_list), decoder_balance, decoder_devices), + chunks=args.pipeline_chunks, + checkpoint=args.pipeline_checkpoint, + ) + else: + self.model = Pipe( + module=nn.Sequential(*decoder_module_list), + balance=decoder_balance, + devices=decoder_devices, + chunks=args.pipeline_chunks, + checkpoint=args.pipeline_checkpoint, + ) def forward( self, @@ -622,7 +675,10 @@ def forward( ) if self.use_pipeline: input_tuple = tuple(i.to(self.model.devices[0]) for i in input_tuple) - return (self.model(input_tuple),) + if TORCH_PIPE: + return (self.model(input_tuple).local_value(),) + else: + return (self.model(input_tuple),) else: embed_layer_output = self.embedding_layer(input_tuple) state = self.decoder_layers(embed_layer_output) From fd7c2a8b371c2abf645f558282221eba6833f35f Mon Sep 17 00:00:00 2001 From: Mary Williamson <marywilliamson@fb.com> Date: Thu, 11 Feb 2021 13:53:33 -0800 Subject: [PATCH 207/774] More informative exception when numpy version changes (#3231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: More informative exception when numpy version changes to ask the user to recompile Cython files # Before submitting - [With myleott ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [N/A ] Did you make sure to update the docs? - [N/A ] Did you write any new necessary tests? ## What does this PR do? Raises a more informative error to tell the user to recompile Cython files after an update to the numpy version. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3231 Reviewed By: myleott Differential Revision: D26375174 Pulled By: mwillwork fbshipit-source-id: f0a93e162bc4cf84619581110d21bea907baf7fc --- fairseq/data/data_utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 1a83063542..47d8492ec9 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -307,6 +307,11 @@ def batch_by_size( "Please build Cython components with: `pip install --editable .` " "or `python setup.py build_ext --inplace`" ) + except ValueError: + raise ValueError( + "Please build (or rebuild) Cython components with: `pip install " + " --editable .` or `python setup.py build_ext --inplace`." + ) max_tokens = max_tokens if max_tokens is not None else -1 max_sentences = max_sentences if max_sentences is not None else -1 From 66e1803c60272602c719a5ba75acef1c530066ef Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 11 Feb 2021 13:59:08 -0800 Subject: [PATCH 208/774] save task state in the checkpoint (#1562) Summary: this allows tasks to declare some properties they'd like to save in the checkpoint (such as a dictionary), which are loaded when checkpoint is restored. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1562 Test Plan: tested by training a new wav2vec model, then finetuning it, then decoding it and making sure the dict only loaded once, during fine tuning process (and was obtained from checkpoint for decoding) Reviewed By: myleott, gwenzek Differential Revision: D25937974 Pulled By: alexeib fbshipit-source-id: b9908042f76ec8cda943f33885eb9b1f121662ae --- examples/speech_recognition/hydra/infer.py | 4 +- examples/speech_recognition/infer.py | 13 +++--- fairseq/checkpoint_utils.py | 5 +++ fairseq/distributed/utils.py | 3 ++ fairseq/tasks/audio_pretraining.py | 28 ++++++------ fairseq/tasks/fairseq_task.py | 50 ++++++++++++++++++++-- fairseq/trainer.py | 5 ++- 7 files changed, 77 insertions(+), 31 deletions(-) diff --git a/examples/speech_recognition/hydra/infer.py b/examples/speech_recognition/hydra/infer.py index 6afa066f25..b1c985bc0d 100644 --- a/examples/speech_recognition/hydra/infer.py +++ b/examples/speech_recognition/hydra/infer.py @@ -10,10 +10,9 @@ import os import shutil import sys -from argparse import Namespace from dataclasses import dataclass, field from pathlib import Path -from typing import Any, Callable, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple import editdistance import torch @@ -26,7 +25,6 @@ CommonEvalConfig, DatasetConfig, DistributedTrainingConfig, FairseqDataclass, GenerationConfig) -from fairseq.dataclass.initialize import hydra_init from fairseq.logging.meters import StopwatchMeter, TimeMeter from fairseq.logging.progress_bar import BaseProgressBar from fairseq.models.fairseq_model import FairseqModel diff --git a/examples/speech_recognition/infer.py b/examples/speech_recognition/infer.py index 5a582c54af..f4efbf39c8 100644 --- a/examples/speech_recognition/infer.py +++ b/examples/speech_recognition/infer.py @@ -144,11 +144,11 @@ def process_predictions( print( "{} ({}-{})".format(tgt_words, speaker, id), file=res_files["ref.words"] ) - # only score top hypothesis - if not args.quiet: - logger.debug("HYPO:" + hyp_words) - logger.debug("TARGET:" + tgt_words) - logger.debug("___________________") + + if not args.quiet: + logger.info("HYPO:" + hyp_words) + logger.info("TARGET:" + tgt_words) + logger.info("___________________") hyp_words = hyp_words.split() tgt_words = tgt_words.split() @@ -216,7 +216,6 @@ def main(args, task=None, model_state=None): use_cuda = torch.cuda.is_available() and not args.cpu - logger.info("| decoding with criterion {}".format(args.criterion)) task = tasks.setup_task(args) @@ -227,7 +226,7 @@ def main(args, task=None, model_state=None): task.load_dataset(args.gen_subset) else: logger.info("| loading model(s) from {}".format(args.path)) - models, saved_cfg = checkpoint_utils.load_model_ensemble( + models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( utils.split_paths(args.path), arg_overrides=ast.literal_eval(args.model_overrides), task=task, diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 2f209b6b39..55a546356e 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -349,6 +349,9 @@ def load_model_ensemble_and_task( if task is None: task = tasks.setup_task(cfg.task) + if "task_state" in state: + task.load_state_dict(state["task_state"]) + # build model for ensemble model = task.build_model(cfg.model) @@ -403,6 +406,7 @@ def save_state( num_updates, optim_history=None, extra_state=None, + task=None, **kwargs, ): from fairseq import utils @@ -425,6 +429,7 @@ def save_state( } ], "extra_state": extra_state, + "task_state": task.state_dict() if task is not None else {} } if utils.has_parameters(criterion): state_dict["criterion"] = criterion.state_dict() diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index e3d8e1e0d3..710ca18628 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -325,6 +325,9 @@ def distributed_main(i, main, cfg: FairseqConfig, kwargs): main(cfg, **kwargs) + if torch.distributed.is_initialized(): + torch.distributed.barrier(get_global_group()) + def call_main(cfg: FairseqConfig, main, **kwargs): if cfg.distributed_training.distributed_init_method is None: diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 7c82777331..92685160d4 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -15,7 +15,6 @@ from omegaconf import MISSING from fairseq.data import AddTargetDataset, Dictionary, FileAudioDataset, encoders -from fairseq.data.data_utils import post_process from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.configs import GenerationConfig @@ -98,16 +97,14 @@ class AudioPretrainingTask(FairseqTask): def __init__( self, cfg: AudioPretrainingConfig, - source_dictionary=None, - target_dictionary=None, ): super().__init__(cfg) - self._target_dictionary = target_dictionary - self._source_dictionary = source_dictionary if cfg.eval_wer: assert cfg.labels is not None, "eval_wer can only be set during fine-tuning" self.blank_symbol = "<s>" + self.state.add_factory("target_dictionary", self.load_target_dictionary) + @classmethod def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): """Setup the task (e.g., load dictionaries). @@ -116,13 +113,13 @@ def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): cfg (AudioPretrainingConfig): configuration of this task """ - if cfg.labels: - dict_path = os.path.join(cfg.data, f"dict.{cfg.labels}.txt") - target_dictionary = Dictionary.load(dict_path) - else: - target_dictionary = None + return cls(cfg) - return cls(cfg, target_dictionary=target_dictionary) + def load_target_dictionary(self): + if self.cfg.labels: + dict_path = os.path.join(self.cfg.data, f"dict.{self.cfg.labels}.txt") + return Dictionary.load(dict_path) + return None def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): data_path = self.cfg.data @@ -136,7 +133,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): manifest = os.path.join(data_path, "{}.tsv".format(split)) self.datasets[split] = FileAudioDataset( manifest, - sample_rate=task_cfg.sample_rate, + sample_rate=task_cfg.get('sample_rate', self.cfg.sample_rate), max_sample_size=self.cfg.max_sample_size, min_sample_size=self.cfg.max_sample_size, min_length=self.cfg.min_sample_size, @@ -146,7 +143,6 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): if task_cfg.labels: label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") - labels = [] with open(label_path, "r") as f: labels = [ line for i, line in enumerate(f) @@ -166,18 +162,18 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): eos=self.target_dictionary.eos(), batch_targets=True, process_label=process_label, - add_to_input=task_cfg.autoregressive, + add_to_input=task_cfg.get('autoregressive', False), ) @property def source_dictionary(self): - return self._source_dictionary + return None @property def target_dictionary(self): """Return the :class:`~fairseq.data.Dictionary` for the language model.""" - return self._target_dictionary + return self.state.target_dictionary def max_positions(self): """Maximum input length supported by the encoder.""" diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 34264bdc01..04025023fa 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -7,7 +7,7 @@ import os import warnings from argparse import Namespace -from typing import List +from typing import Any, Callable, Dict, List import torch from fairseq import metrics, search, tokenizer, utils @@ -20,10 +20,45 @@ logger = logging.getLogger(__name__) +class StatefulContainer(object): + + _state: Dict[str, Any] = dict() + _factories: Dict[str, Callable[[], Any]] = dict() + + def add_factory(self, name, factory: Callable[[], Any]): + self._factories[name] = factory + + def merge_state_dict(self, state_dict: Dict[str, Any]): + self._state.update(state_dict) + + @property + def state_dict(self) -> Dict[str, Any]: + return self._state + + def __getattr__(self, name): + if name not in self._state and name in self._factories: + self._state[name] = self._factories[name]() + + if name in self._state: + return self._state[name] + + raise AttributeError(f"Task state has no factory for attribute {name}") + + class FairseqTask(object): """ Tasks store dictionaries and provide helpers for loading/iterating over Datasets, initializing the Model/Criterion and calculating the loss. + + Tasks have limited statefulness. In particular, state that needs to be + saved to/loaded from checkpoints needs to be stored in the `self.state` + :class:`StatefulContainer` object. For example:: + + self.state.add_factory("dictionary", self.load_dictionary) + print(self.state.dictionary) # calls self.load_dictionary() + + This is necessary so that when loading checkpoints, we can properly + recreate the task state after initializing the task instance. """ @classmethod @@ -42,10 +77,13 @@ def logging_outputs_can_be_summed(criterion) -> bool: """ return criterion.logging_outputs_can_be_summed() + cfg: FairseqDataclass + datasets: Dict[str, FairseqDataset] = dict() + dataset_to_epoch_iter: Dict[FairseqDataset, Any] = dict() + state: StatefulContainer = StatefulContainer() + def __init__(self, cfg: FairseqDataclass, **kwargs): self.cfg = cfg - self.datasets = {} - self.dataset_to_epoch_iter = {} @classmethod def load_dictionary(cls, filename): @@ -514,6 +552,12 @@ def reduce_metrics(self, logging_outputs, criterion): criterion.__class__.reduce_metrics(logging_outputs) + def state_dict(self): + return self.state.state_dict + + def load_state_dict(self, state_dict: Dict[str, Any]): + self.state.merge_state_dict(state_dict) + def max_positions(self): """Return the max input length allowed by the task.""" return None diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 24f72e2f9a..e860fb1832 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -288,8 +288,9 @@ def save_checkpoint(self, filename, extra_state): self.optimizer, self.lr_scheduler, self.get_num_updates(), - self._optim_history, - extra_state, + optim_history=self._optim_history, + extra_state=extra_state, + task=self.task, ) logger.info(f"Finished saving checkpoint to {filename}") From 138265ce15d198e6baceae334effed8fb384a286 Mon Sep 17 00:00:00 2001 From: Kritika Singh <skritika@fb.com> Date: Thu, 11 Feb 2021 15:39:32 -0800 Subject: [PATCH 209/774] Make wav2vec_asr encoder compatible with pyspeech fst decoder Summary: - I don't think there is a convention for the shapes of `encoder_out` and `encoder_padding_mask` in fairseq but `fst_external_decoder.py` expects `encoder_padding_mask` to be of shape T x B. `encoder_padding_mask` also seems unused in the fairseq [CTC criterion and w2l decoder integration](https://fburl.com/diffusion/ms1zi2px) so taking the easy way out and changing its shape. - Also checking in some changes to the pyspeech audio_pretraining task required to make decoding work Reviewed By: alexeib Differential Revision: D26382442 fbshipit-source-id: 87c8f9433026c0e011847f4e2e094beb2cd2182c --- fairseq/models/wav2vec/wav2vec2_asr.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index bbd2ab9ec5..9cd17b635c 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -158,7 +158,7 @@ def get_normalized_probs(self, net_output, log_probs): def get_logits(self, net_output): logits = net_output["encoder_out"] - padding = net_output["encoder_padding_mask"] + padding = net_output["padding_mask"] if padding is not None and padding.any(): padding = padding.T logits[padding][...,0] = 0 @@ -359,7 +359,7 @@ def forward(self, source, padding_mask, tbc=True, **kwargs): return { "encoder_out": x, # T x B x C - "encoder_padding_mask": padding_mask, # B x T + "encoder_padding_mask": padding_mask.transpose(0, 1), # T x B "padding_mask": padding_mask, } @@ -539,7 +539,7 @@ def extract_features( x, attn, _ = layer( x, encoder_out["encoder_out"] if encoder_out is not None else None, - encoder_out["encoder_padding_mask"] + encoder_out["padding_mask"] if encoder_out is not None else None, incremental_state, From 1d5b075e3f30fd3f28af4c8851e8659285ded230 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 11 Feb 2021 18:12:11 -0800 Subject: [PATCH 210/774] fix fairseqlm decoder with flashlight chnages (#1617) Summary: fixes fairseqlm integration with flashlight (formerly wav2letter) decoder Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1617 Reviewed By: xuqiantong Differential Revision: D26415650 Pulled By: alexeib fbshipit-source-id: 813684ba55047e92378f508101ff1eec55754420 --- examples/speech_recognition/w2l_decoder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_recognition/w2l_decoder.py b/examples/speech_recognition/w2l_decoder.py index 706d9f1433..8b158293a0 100644 --- a/examples/speech_recognition/w2l_decoder.py +++ b/examples/speech_recognition/w2l_decoder.py @@ -431,7 +431,7 @@ def __init__(self, args, tgt_dict): self.silence, self.blank, self.unk_word, - self.asg_transitions, + [], self.unit_lm, ) else: From 506a8e0f45c1206b1306276fed9cec92c7061dd0 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 11 Feb 2021 21:22:42 -0800 Subject: [PATCH 211/774] seq2seq autoregressive flag check (#1618) Summary: raise an exception if trying to use wav2vec seq2seq finetuning without autoregressive flag Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1618 Reviewed By: xuqiantong Differential Revision: D26417249 Pulled By: alexeib fbshipit-source-id: 777b6d170b0f8196746e03b399e4d7c21ac0b837 --- fairseq/models/wav2vec/wav2vec2_asr.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 9cd17b635c..afa51299b6 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -220,6 +220,7 @@ class Wav2Vec2Seq2SeqConfig(Wav2Vec2AsrConfig): share_decoder_input_output_embed: bool = field( default=False, metadata={"help": "share decoder input and output embeddings"} ) + autoregressive: bool = II("task.autoregressive") @register_model("wav2vec_seq2seq", dataclass=Wav2Vec2Seq2SeqConfig) @@ -231,6 +232,8 @@ def __init__(self, encoder, decoder): def build_model(cls, cfg: Wav2Vec2Seq2SeqConfig, task: FairseqTask): """Build a new model instance.""" + assert cfg.autoregressive, "Please set task.autoregressive=true for seq2seq asr models" + src_dict, tgt_dict = task.source_dictionary, task.target_dictionary def build_embedding(dictionary, embed_dim): From 7ffb40d9c8e33b272e85604892a0935d8e57bb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Megid=20Carrilho?= <joaopedro@nindoo.ai> Date: Fri, 12 Feb 2021 00:26:03 -0800 Subject: [PATCH 212/774] Fix typo Wav2Vec2 README.md (#3240) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3240 Reviewed By: aconneau Differential Revision: D26420073 Pulled By: alexeib fbshipit-source-id: 5939535b945a64e61d655cd36dc955ae46410bfb --- examples/wav2vec/README.md | 294 ------------------------------------- 1 file changed, 294 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 663adf97dc..e69de29bb2 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -1,294 +0,0 @@ -# wav2vec 2.0 - -wav2vec 2.0 learns speech representations on unlabeled data as described in [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](https://arxiv.org/abs/2006.11477). - -We learned speech representations in multiple languages as well in [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979). - -We also combined wav2vec 2.0 with self-training in [Self-training and Pre-training are Complementary for Speech Recognition (Xu et al., 2020)](https://arxiv.org/abs/2010.11430). - -## Pre-trained models - -Model | Finetuning split | Dataset | Model -|---|---|---|--- -Wav2Vec 2.0 Base | No finetuning | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small.pt) -Wav2Vec 2.0 Base | 10 minutes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small_10m.pt) -Wav2Vec 2.0 Base | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small_100h.pt) -Wav2Vec 2.0 Base | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small_960h.pt) -Wav2Vec 2.0 Large | No finetuning | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/libri960_big.pt) -Wav2Vec 2.0 Large | 10 minutes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_10m.pt) -Wav2Vec 2.0 Large | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_100h.pt) -Wav2Vec 2.0 Large | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_960h.pt) -Wav2Vec 2.0 Large (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_new.pt) -Wav2Vec 2.0 Large (LV-60)* | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_new.pt) -Wav2Vec 2.0 Large (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_new.pt) -Wav2Vec 2.0 Large (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_new.pt) -Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_pl.pt) -Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) -Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) - -\* updated (Oct. 24, 2020) - -We also release multilingual pre-trained wav2vec 2.0 (XLSR) models: - -Model | Architecture | Hours | Languages | Datasets | Model -|---|---|---|---|---|--- -XLSR-53 | Large | 56k | 53 | MLS, CommonVoice, BABEL | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr_53_56k.pt) - -The XLSR model uses the following datasets for multilingual pretraining: - -* **[MLS: Multilingual LibriSpeech](https://indico2.conference4me.psnc.pl/event/35/contributions/3585/attachments/1060/1101/Wed-2-6-10.pdf)** (8 languages, 50.7k hours): *Dutch, English, French, German, Italian, Polish, Portuguese, Spanish* - -* **[CommonVoice](https://commonvoice.mozilla.org/en/languages)** (36 languages, 3.6k hours): *Arabic, Basque, Breton, Chinese (CN), Chinese (HK), Chinese (TW), Chuvash, Dhivehi, Dutch, English, Esperanto, Estonian, French, German, Hakh-Chin, Indonesian, Interlingua, Irish, Italian, Japanese, Kabyle, Kinyarwanda, Kyrgyz, Latvian, Mongolian, Persian, Portuguese, Russian, Sakha, Slovenian, Spanish, Swedish, Tamil, Tatar, Turkish, Welsh* (see also [finetuning splits]([https://dl.fbaipublicfiles.com/cpc_audio/common_voices_splits.tar.gz]) from [this paper](https://arxiv.org/abs/2002.02848)). - -* **[Babel](https://catalog.ldc.upenn.edu/byyear)** (17 languages, 1.7k hours): *Assamese, Bengali, Cantonese, Cebuano, Georgian, Haitian, Kazakh, Kurmanji, Lao, Pashto, Swahili, Tagalog, Tamil, Tok, Turkish, Vietnamese, Zulu* - - -## Training a new model with the CLI tools - -Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) - -### Prepare training data manifest: - -First, install the `soundfile` library: -```shell script -pip install soundfile -``` - -Next, run: - -```shell script -$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext $ext --valid-percent $valid -``` - -$ext should be set to flac, wav, or whatever format your dataset happens to use that soundfile can read. - -$valid should be set to some reasonable percentage (like 0.01) of training data to use for validation. -To use a pre-defined validation set (like dev-other from librispeech), set to it 0 and then overwrite valid.tsv with a -separately pre-processed manifest file. - -### Train a wav2vec 2.0 base model: - -This configuration was used for the base model trained on the Librispeech dataset in the wav2vec 2.0 paper - -Note that the input is expected to be single channel, sampled at 16 kHz - -```shell script -$ fairseq-hydra-train \ - task.data=/path/to/data \ - --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ - --config-name wav2vec2_base_librispeech -``` - -Note: you can simulate 64 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) -`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 64/k - -### Train a wav2vec 2.0 large model: - -This configuration was used for the large model trained on the Libri-light dataset in the wav2vec 2.0 paper - -```shell script -$ fairseq-hydra-train \ - task.data=/path/to/data \ - --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ - --config-name wav2vec2_large_librivox -``` - -Note: you can simulate 128 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) -`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 128/k - -### Fine-tune a pre-trained model with CTC: - -Fine-tuning a model requires parallel audio and labels file, as well as a vocabulary file in fairseq format. -A letter vocabulary can be downloaded [here](https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt). -An example [script](libri_labels.py) that generates labels for the Librispeech dataset from the tsv file produced by wav2vec_manifest.py can be used as follows: - -```shell script -split=train -$ python libri_labels.py /path/to/tsv --output-dir /output/dir --output-name $split -``` - -Fine-tuning on 100h of Librispeech with letter targets: -```shell script -$ fairseq-hydra-train \ - distributed_training.distributed_port=$PORT \ - task.data=/path/to/data \ - model.w2v_path=/path/to/model.pt \ - --config-dir /path/to/fairseq-py/examples/wav2vec/config/finetuning \ - --config-name base_100h -``` - -There are other config files in the config/finetuning directory that can be used to fine-tune on other splits. -You can specify the right config via the `--config-name` parameter. - -Note: you can simulate 24 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) -`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 24/k - -Decoding with a language model during training requires flashlight [python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter). -If you want to use a language model, add `+criterion.wer_args='[/path/to/kenlm, /path/to/lexicon, 2, -1]'` to the command line. - -### Evaluating a CTC model: - -Evaluating a CTC model with a language model requires [flashlight python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter) to be installed. - -Fairseq transformer language model used in the wav2vec 2.0 paper can be obtained from the [wav2letter model repository](https://github.com/facebookresearch/wav2letter/tree/master/recipes/sota/2019). -Be sure to upper-case the language model vocab after downloading it. - -Letter dictionary for pre-trained models can be found [here](https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt). - -Next, run the evaluation command: - -```shell script -$subset=dev_other -python examples/speech_recognition/infer.py /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw --task audio_pretraining \ ---nbest 1 --path /path/to/model --gen-subset $subset --results-path /path/to/save/results/for/sclite --w2l-decoder kenlm \ ---lm-model /path/to/kenlm.bin --lm-weight 2 --word-score -1 --sil-weight 0 --criterion ctc --labels ltr --max-tokens 4000000 \ ---post-process letter -``` - -To get raw numbers, use --w2l-decoder viterbi and omit the lexicon. To use the transformer language model, use --w2l-decoder fairseqlm. - -## Use wav2vec 2.0 with 🤗Transformers: - -Wav2Vec2 is also available in the [🤗Transformers library](https://github.com/huggingface/transformers) since vesion 4.3. - -Pretrained Models can be found on the [hub](https://huggingface.co/models?filter=wav2vec2) -and documentation can be found [here](https://huggingface.co/transformers/master/model_doc/wav2vec2.html). - -Usage example: - -```python -# !pip install transformers -import soundfile as sf -import torch -from transformers import Wav2Vec2ForMaskedLM, Wav2Vec2Tokenizer - -# load pretrained model -tokenizer = Wav2Vec2Tokenizer.from_pretrained("facebook/wav2vec2-base-960h") -model = Wav2Vec2ForMaskedLM.from_pretrained("facebook/wav2vec2-base-960h") - -# load audio -audio_input, _ = sf.read("path/to/audio/file") - -# transcribe -input_values = tokenizer(audio_input, return_tensors="pt").input_values -logits = model(input_values).logits -predicted_ids = torch.argmax(logits, dim=-1) -transcription = tokenizer.batch_decode(predicted_ids)[0] -``` - -# wav2vec - -Example to train a wav2vec model as described in [wav2vec: Unsupervised Pre-training for Speech Recognition (Schneider et al., 2019)](https://arxiv.org/abs/1904.05862). - -## Pre-trained models - -Description | Dataset | Model ----|---|--- -Wav2Vec large | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_large.pt) - -#### Example usage: -```python -import torch -import fairseq - -cp_path = '/path/to/wav2vec.pt' -model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp_path]) -model = model[0] -model.eval() - -wav_input_16khz = torch.randn(1,10000) -z = model.feature_extractor(wav_input_16khz) -c = model.feature_aggregator(z) -``` - -## Training a new model with the CLI tools - -Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate files 10 to 30 seconds in length) - -### Prepare training data manifest: - -``` -$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav -``` - -### Train a wav2vec model: - -``` -$ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ ---arch wav2vec --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 --optimizer adam --lr 0.005 --lr-scheduler cosine \ ---conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1)] \ ---conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ ---skip-connections-agg --residual-scale 0.5 --log-compression --warmup-updates 500 --warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 \ ---max-sample-size 150000 --max-tokens 1500000 --skip-invalid-size-inputs-valid-test -``` - -### Extract embeddings from the downstream task data: - -``` -$ PYTHONPATH=/path/to/fairseq python examples/wav2vec/wav2vec_featurize.py --input /path/to/task/waves --output /path/to/output \ ---model /model/path/checkpoint_best.pt --split train valid test -``` - -# vq-wav2vec - -Example to train a vq-wav2vec model as described in [vq-wav2vec: Self-Supervised Learning of Discrete Speech Representations (Baevski et al., 2019)](https://arxiv.org/abs/1910.05453). - -These models are also used in [Effectiveness of self-supervised pre-training for speech recognition (Baevski et al., 2019)](https://arxiv.org/abs/1911.03912). - -## Pre-trained models - -Description | Dataset | Model ----|---|--- -vq-wav2vec Gumbel | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/vq-wav2vec.pt) -vq-wav2vec K-means | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/vq-wav2vec_kmeans.pt) -Roberta on K-means codes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/bert_kmeans.tar) - -#### Example usage: -```python -import torch -import fairseq - -cp = torch.load('/path/to/vq-wav2vec.pt') -model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp]) -model = model[0] -model.eval() - -wav_input_16khz = torch.randn(1,10000) -z = model.feature_extractor(wav_input_16khz) -_, idxs = model.vector_quantizer.forward_idx(z) -print(idxs.shape) # output: torch.Size([1, 60, 2]), 60 timesteps with 2 indexes corresponding to 2 groups in the model -``` - -## Training a new model with the CLI tools - -Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) - -### Prepare training data manifest: - -``` -$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav -``` - -### Train a gumbel vq-wav2vec model: - -``` -$ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 \ ---save-interval 1 --no-epoch-checkpoints --arch wav2vec --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 \ ---optimizer adam --lr 1e-05 --lr-scheduler cosine \ ---conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1), (512, 1, 1)] \ ---conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ ---activation gelu --offset auto --skip-connections-agg --residual-scale 0.5 \ ---log-keys ["prob_perplexity","code_perplexity","temp"] --vq-type gumbel --vq-groups 2 --vq-depth 2 \ ---combine-groups --vq-vars 320 --vq-temp (2,0.5,0.999995) --prediction-steps 12 --warmup-updates 1000 \ ---warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 --max-sample-size 150000 \ ---max-tokens 300000 --cross-sample-negatives 0 --update-freq 1 --seed 2 --skip-invalid-size-inputs-valid-test -``` - -for k-means training, set vq-type with "kmeans" and add --loss-weights [1] argument. Pre-trained models were trained on 16 GPUs. - -### Tokenize audio data (e.g. for BERT training): - -``` -$ PYTHONPATH=/path/to/fairseq python examples/wav2vec/vq-wav2vec_featurize.py --data-dir /manifest/path --output-dir /path/to/output \ ---checkpoint /model/path/checkpoint_best.pt --split train valid test --extension tsv -``` From f3b6f5817fbee59057ae2506f01502ea3c301b4b Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Fri, 12 Feb 2021 11:32:52 -0800 Subject: [PATCH 213/774] Fix w2v readme (#1621) Summary: somehow merging previous pull request deleted the readme Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1621 Reviewed By: michaelauli Differential Revision: D26429893 Pulled By: alexeib fbshipit-source-id: 3e6ed1e4698e67e56e0b88d304f42907a4f6cf41 --- examples/wav2vec/README.md | 294 +++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index e69de29bb2..e95f292b51 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -0,0 +1,294 @@ +# wav2vec 2.0 + +wav2vec 2.0 learns speech representations on unlabeled data as described in [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](https://arxiv.org/abs/2006.11477). + +We learned speech representations in multiple languages as well in [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979). + +We also combined wav2vec 2.0 with self-training in [Self-training and Pre-training are Complementary for Speech Recognition (Xu et al., 2020)](https://arxiv.org/abs/2010.11430). + +## Pre-trained models + +Model | Finetuning split | Dataset | Model +|---|---|---|--- +Wav2Vec 2.0 Base | No finetuning | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small.pt) +Wav2Vec 2.0 Base | 10 minutes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small_10m.pt) +Wav2Vec 2.0 Base | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small_100h.pt) +Wav2Vec 2.0 Base | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small_960h.pt) +Wav2Vec 2.0 Large | No finetuning | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/libri960_big.pt) +Wav2Vec 2.0 Large | 10 minutes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_10m.pt) +Wav2Vec 2.0 Large | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_100h.pt) +Wav2Vec 2.0 Large | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_960h.pt) +Wav2Vec 2.0 Large (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_new.pt) +Wav2Vec 2.0 Large (LV-60)* | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_new.pt) +Wav2Vec 2.0 Large (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_new.pt) +Wav2Vec 2.0 Large (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_new.pt) +Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_pl.pt) +Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) +Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) + +\* updated (Oct. 24, 2020) + +We also release multilingual pre-trained wav2vec 2.0 (XLSR) models: + +Model | Architecture | Hours | Languages | Datasets | Model +|---|---|---|---|---|--- +XLSR-53 | Large | 56k | 53 | MLS, CommonVoice, BABEL | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr_53_56k.pt) + +The XLSR model uses the following datasets for multilingual pretraining: + +* **[MLS: Multilingual LibriSpeech](https://indico2.conference4me.psnc.pl/event/35/contributions/3585/attachments/1060/1101/Wed-2-6-10.pdf)** (8 languages, 50.7k hours): *Dutch, English, French, German, Italian, Polish, Portuguese, Spanish* + +* **[CommonVoice](https://commonvoice.mozilla.org/en/languages)** (36 languages, 3.6k hours): *Arabic, Basque, Breton, Chinese (CN), Chinese (HK), Chinese (TW), Chuvash, Dhivehi, Dutch, English, Esperanto, Estonian, French, German, Hakh-Chin, Indonesian, Interlingua, Irish, Italian, Japanese, Kabyle, Kinyarwanda, Kyrgyz, Latvian, Mongolian, Persian, Portuguese, Russian, Sakha, Slovenian, Spanish, Swedish, Tamil, Tatar, Turkish, Welsh* (see also [finetuning splits]([https://dl.fbaipublicfiles.com/cpc_audio/common_voices_splits.tar.gz]) from [this paper](https://arxiv.org/abs/2002.02848)). + +* **[Babel](https://catalog.ldc.upenn.edu/byyear)** (17 languages, 1.7k hours): *Assamese, Bengali, Cantonese, Cebuano, Georgian, Haitian, Kazakh, Kurmanji, Lao, Pashto, Swahili, Tagalog, Tamil, Tok, Turkish, Vietnamese, Zulu* + + +## Training a new model with the CLI tools + +Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) + +### Prepare training data manifest: + +First, install the `soundfile` library: +```shell script +pip install soundfile +``` + +Next, run: + +```shell script +$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext $ext --valid-percent $valid +``` + +$ext should be set to flac, wav, or whatever format your dataset happens to use that soundfile can read. + +$valid should be set to some reasonable percentage (like 0.01) of training data to use for validation. +To use a pre-defined validation set (like dev-other from librispeech), set to it 0 and then overwrite valid.tsv with a +separately pre-processed manifest file. + +### Train a wav2vec 2.0 base model: + +This configuration was used for the base model trained on the Librispeech dataset in the wav2vec 2.0 paper + +Note that the input is expected to be single channel, sampled at 16 kHz + +```shell script +$ fairseq-hydra-train \ + task.data=/path/to/data \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_base_librispeech +``` + +Note: you can simulate 64 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 64/k + +### Train a wav2vec 2.0 large model: + +This configuration was used for the large model trained on the Libri-light dataset in the wav2vec 2.0 paper + +```shell script +$ fairseq-hydra-train \ + task.data=/path/to/data \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_large_librivox +``` + +Note: you can simulate 128 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 128/k + +### Fine-tune a pre-trained model with CTC: + +Fine-tuning a model requires parallel audio and labels file, as well as a vocabulary file in fairseq format. +A letter vocabulary can be downloaded [here](https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt). +An example [script](libri_labels.py) that generates labels for the Librispeech dataset from the tsv file produced by wav2vec_manifest.py can be used as follows: + +```shell script +split=train +$ python libri_labels.py /path/to/tsv --output-dir /output/dir --output-name $split +``` + +Fine-tuning on 100h of Librispeech with letter targets: +```shell script +$ fairseq-hydra-train \ + distributed_training.distributed_port=$PORT \ + task.data=/path/to/data \ + model.w2v_path=/path/to/model.pt \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/finetuning \ + --config-name base_100h +``` + +There are other config files in the config/finetuning directory that can be used to fine-tune on other splits. +You can specify the right config via the `--config-name` parameter. + +Note: you can simulate 24 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 24/k + +Decoding with a language model during training requires flashlight [python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter). +If you want to use a language model, add `+criterion.wer_args='[/path/to/kenlm, /path/to/lexicon, 2, -1]'` to the command line. + +### Evaluating a CTC model: + +Evaluating a CTC model with a language model requires [flashlight python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter) to be installed. + +Fairseq transformer language model used in the wav2vec 2.0 paper can be obtained from the [wav2letter model repository](https://github.com/facebookresearch/wav2letter/tree/master/recipes/sota/2019). +Be sure to upper-case the language model vocab after downloading it. + +Letter dictionary for pre-trained models can be found [here](https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt). + +Next, run the evaluation command: + +```shell script +$subset=dev_other +python examples/speech_recognition/infer.py /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw --task audio_pretraining \ +--nbest 1 --path /path/to/model --gen-subset $subset --results-path /path/to/save/results/for/sclite --w2l-decoder kenlm \ +--lm-model /path/to/kenlm.bin --lm-weight 2 --word-score -1 --sil-weight 0 --criterion ctc --labels ltr --max-tokens 4000000 \ +--post-process letter +``` + +To get raw numbers, use --w2l-decoder viterbi and omit the lexicon. To use the transformer language model, use --w2l-decoder fairseqlm. + +## Use wav2vec 2.0 with 🤗Transformers: + +Wav2Vec2 is also available in the [🤗Transformers library](https://github.com/huggingface/transformers) since version 4.3. + +Pretrained Models can be found on the [hub](https://huggingface.co/models?filter=wav2vec2) +and documentation can be found [here](https://huggingface.co/transformers/master/model_doc/wav2vec2.html). + +Usage example: + +```python +# !pip install transformers +import soundfile as sf +import torch +from transformers import Wav2Vec2ForMaskedLM, Wav2Vec2Tokenizer + +# load pretrained model +tokenizer = Wav2Vec2Tokenizer.from_pretrained("facebook/wav2vec2-base-960h") +model = Wav2Vec2ForMaskedLM.from_pretrained("facebook/wav2vec2-base-960h") + +# load audio +audio_input, _ = sf.read("path/to/audio/file") + +# transcribe +input_values = tokenizer(audio_input, return_tensors="pt").input_values +logits = model(input_values).logits +predicted_ids = torch.argmax(logits, dim=-1) +transcription = tokenizer.batch_decode(predicted_ids)[0] +``` + +# wav2vec + +Example to train a wav2vec model as described in [wav2vec: Unsupervised Pre-training for Speech Recognition (Schneider et al., 2019)](https://arxiv.org/abs/1904.05862). + +## Pre-trained models + +Description | Dataset | Model +---|---|--- +Wav2Vec large | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_large.pt) + +#### Example usage: +```python +import torch +import fairseq + +cp_path = '/path/to/wav2vec.pt' +model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp_path]) +model = model[0] +model.eval() + +wav_input_16khz = torch.randn(1,10000) +z = model.feature_extractor(wav_input_16khz) +c = model.feature_aggregator(z) +``` + +## Training a new model with the CLI tools + +Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate files 10 to 30 seconds in length) + +### Prepare training data manifest: + +``` +$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav +``` + +### Train a wav2vec model: + +``` +$ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ +--arch wav2vec --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 --optimizer adam --lr 0.005 --lr-scheduler cosine \ +--conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1)] \ +--conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ +--skip-connections-agg --residual-scale 0.5 --log-compression --warmup-updates 500 --warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 \ +--max-sample-size 150000 --max-tokens 1500000 --skip-invalid-size-inputs-valid-test +``` + +### Extract embeddings from the downstream task data: + +``` +$ PYTHONPATH=/path/to/fairseq python examples/wav2vec/wav2vec_featurize.py --input /path/to/task/waves --output /path/to/output \ +--model /model/path/checkpoint_best.pt --split train valid test +``` + +# vq-wav2vec + +Example to train a vq-wav2vec model as described in [vq-wav2vec: Self-Supervised Learning of Discrete Speech Representations (Baevski et al., 2019)](https://arxiv.org/abs/1910.05453). + +These models are also used in [Effectiveness of self-supervised pre-training for speech recognition (Baevski et al., 2019)](https://arxiv.org/abs/1911.03912). + +## Pre-trained models + +Description | Dataset | Model +---|---|--- +vq-wav2vec Gumbel | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/vq-wav2vec.pt) +vq-wav2vec K-means | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/vq-wav2vec_kmeans.pt) +Roberta on K-means codes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/bert_kmeans.tar) + +#### Example usage: +```python +import torch +import fairseq + +cp = torch.load('/path/to/vq-wav2vec.pt') +model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([cp]) +model = model[0] +model.eval() + +wav_input_16khz = torch.randn(1,10000) +z = model.feature_extractor(wav_input_16khz) +_, idxs = model.vector_quantizer.forward_idx(z) +print(idxs.shape) # output: torch.Size([1, 60, 2]), 60 timesteps with 2 indexes corresponding to 2 groups in the model +``` + +## Training a new model with the CLI tools + +Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) + +### Prepare training data manifest: + +``` +$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav +``` + +### Train a gumbel vq-wav2vec model: + +``` +$ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 \ +--save-interval 1 --no-epoch-checkpoints --arch wav2vec --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 \ +--optimizer adam --lr 1e-05 --lr-scheduler cosine \ +--conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1), (512, 1, 1)] \ +--conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ +--activation gelu --offset auto --skip-connections-agg --residual-scale 0.5 \ +--log-keys ["prob_perplexity","code_perplexity","temp"] --vq-type gumbel --vq-groups 2 --vq-depth 2 \ +--combine-groups --vq-vars 320 --vq-temp (2,0.5,0.999995) --prediction-steps 12 --warmup-updates 1000 \ +--warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 --max-sample-size 150000 \ +--max-tokens 300000 --cross-sample-negatives 0 --update-freq 1 --seed 2 --skip-invalid-size-inputs-valid-test +``` + +for k-means training, set vq-type with "kmeans" and add --loss-weights [1] argument. Pre-trained models were trained on 16 GPUs. + +### Tokenize audio data (e.g. for BERT training): + +``` +$ PYTHONPATH=/path/to/fairseq python examples/wav2vec/vq-wav2vec_featurize.py --data-dir /manifest/path --output-dir /path/to/output \ +--checkpoint /model/path/checkpoint_best.pt --split train valid test --extension tsv +``` From 02803a1be45642b4c2f9c2970a4f4ae645a2dccf Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Fri, 12 Feb 2021 14:04:21 -0800 Subject: [PATCH 214/774] broadcast the whole optimizer state to each rank Summary: OSS removed the 'partition' key in their state dict to accommodate for changing partition size. This requires an update on the fairseq side to not look into the parameter partition, just broadcast everything, and let the optimizer on each rank decides which parameters are relevant. This diff also needs D26419095 to function completely, and blefaudeux has made fixes upstream in https://github.com/facebookresearch/fairscale/pull/383 Reviewed By: myleott Differential Revision: D26382917 fbshipit-source-id: 95af1022be59e88814748acaee36a1a350f7dc5b --- fairseq/optim/shard.py | 58 ++++++++---------------------------------- 1 file changed, 10 insertions(+), 48 deletions(-) diff --git a/fairseq/optim/shard.py b/fairseq/optim/shard.py index 3d025a23ca..3c1b34ae60 100644 --- a/fairseq/optim/shard.py +++ b/fairseq/optim/shard.py @@ -5,11 +5,11 @@ from typing import Any, Dict -import torch +from fairseq.distributed import utils try: - from fairscale.optim import OSS, utils + from fairscale.optim import OSS _has_fairscale = True except ImportError: @@ -38,53 +38,15 @@ def broadcast_global_state_dict( self, state_dict: Dict[str, Any] ) -> Dict[str, Any]: """ - Broadcasts the relevant parts of a global state dict from rank 0 to - all other ranks. + Broadcasts the entire state_dict to all other ranks + each rank is responsible to load their own partition of data """ - if self.rank == 0: - - # Create template state dict for all other keys not related to sharding - template_state_dict = { - key: state_dict[key] - for key in state_dict - if key not in ("param_groups", "state") - } - template_state_dict["local_state_dict"] = True - - for dst_rank in range(self.world_size): - # Get the dst_rank's param_groups shard - send_state = { - "param_groups": state_dict["param_groups"][ - state_dict["partition"][dst_rank][0] : state_dict[ - "partition" - ][dst_rank][1] - ], - "state": state_dict["state"][dst_rank], - } - send_state.update(template_state_dict) - - if dst_rank == 0: - recv_state = send_state - else: - utils.broadcast_object( - send_state, - src_rank=0, - group=self.group, - dist_device=self._device, - ) - else: - empty_buffer = torch.tensor([0], dtype=torch.uint8, device=self._device) - for dst_rank in range(1, self.world_size): - state = utils.broadcast_object( - empty_buffer, - src_rank=0, - group=self.group, - dist_device=self._device, - ) - if dst_rank == self.rank: - recv_state = state - - return recv_state + return utils.broadcast_object( + state_dict, + src_rank=0, + group=self.group, + dist_device=self._device, + ) torch_optimizer = optimizer.optimizer optim_cls = type(torch_optimizer) From 09945b45d4e2608563b1b18c3bbe289bf9351529 Mon Sep 17 00:00:00 2001 From: cordercorder <2205722269@qq.com> Date: Fri, 12 Feb 2021 14:35:55 -0800 Subject: [PATCH 215/774] Fixes bugs of evaluation with BLEU score when training with multi-gpus. (#3237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: …ith BLEU scores # Before submitting - [no] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [yes] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [no need] Did you make sure to update the docs? - [no need] Did you write any new necessary tests? ## What does this PR do? Fixes bugs of evaluation with BLEU score when training with multi-gpus. But no error will happend if there is no distributed training. when --eval-bleu is set to be `True` (default it is `False` and the best checkpoint is selected according to loss) and training with multi-gpus (when the number of gpu which participate in distributed training is greater than 1), following error will happend. ```bash Traceback (most recent call last): Traceback (most recent call last): File "/data/cordercorder/anaconda3/envs/nmt/bin/fairseq-train", line 33, in <module> File "/data/cordercorder/anaconda3/envs/nmt/bin/fairseq-train", line 33, in <module> Traceback (most recent call last): File "/data/cordercorder/anaconda3/envs/nmt/bin/fairseq-train", line 33, in <module> sys.exit(load_entry_point('fairseq', 'console_scripts', 'fairseq-train')())sys.exit(load_entry_point('fairseq', 'console_scripts', 'fairseq-train')()) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 450, in cli_main File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 450, in cli_main sys.exit(load_entry_point('fairseq', 'console_scripts', 'fairseq-train')()) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 450, in cli_main distributed_utils.call_main(cfg, main)distributed_utils.call_main(cfg, main) File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 349, in call_main File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 349, in call_main distributed_utils.call_main(cfg, main) File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 349, in call_main distributed_main(cfg.distributed_training.device_id, main, cfg, kwargs) distributed_main(cfg.distributed_training.device_id, main, cfg, kwargs) File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 326, in distributed_main File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 326, in distributed_main distributed_main(cfg.distributed_training.device_id, main, cfg, kwargs) File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 326, in distributed_main main(cfg, **kwargs) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 143, in main main(cfg, **kwargs) main(cfg, **kwargs)rder/fairseq/fairseq_cli/train.py", line 143, in main File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 143, in main valid_losses, should_stop = train(cfg, trainer, task, epoch_itr) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner valid_losses, should_stop = train(cfg, trainer, task, epoch_itr) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner valid_losses, should_stop = train(cfg, trainer, task, epoch_itr) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner return func(*args, **kwds) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 259, in train Traceback (most recent call last): File "/data/cordercorder/anaconda3/envs/nmt/bin/fairseq-train", line 33, in <module> return func(*args, **kwds) return func(*args, **kwds) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 259, in train File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 259, in train cfg, trainer, task, epoch_itr, valid_subsets, end_of_epoch File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 345, in validate_and_save cfg, trainer, task, epoch_itr, valid_subsets, end_of_epoch File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 345, in validate_and_save cfg, trainer, task, epoch_itr, valid_subsets, end_of_epochsys.exit(load_entry_point('fairseq', 'console_scripts', 'fairseq-train')()) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 345, in validate_and_save File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 450, in cli_main valid_losses = validate(cfg, trainer, task, epoch_itr, valid_subsets) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 413, in validate valid_losses = validate(cfg, trainer, task, epoch_itr, valid_subsets) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 413, in validate valid_losses = validate(cfg, trainer, task, epoch_itr, valid_subsets) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 413, in validate trainer.valid_step(sample) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner distributed_utils.call_main(cfg, main) File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 349, in call_main trainer.valid_step(sample) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner return func(*args, **kwds) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 834, in valid_step trainer.valid_step(sample) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner return func(*args, **kwds) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 834, in valid_step return func(*args, **kwds)distributed_main(cfg.distributed_training.device_id, main, cfg, kwargs) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 834, in valid_step File "/data1/cordercorder/fairseq/fairseq/distributed/utils.py", line 326, in distributed_main main(cfg, **kwargs) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 143, in main logging_output = self._reduce_and_log_stats(logging_outputs, sample_size) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 1157, in _reduce_and_log_stats logging_output = self._reduce_and_log_stats(logging_outputs, sample_size) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 1157, in _reduce_and_log_stats valid_losses, should_stop = train(cfg, trainer, task, epoch_itr) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner logging_output = self._reduce_and_log_stats(logging_outputs, sample_size) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 1157, in _reduce_and_log_stats return func(*args, **kwds) File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 259, in train cfg, trainer, task, epoch_itr, valid_subsets, end_of_epoch File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 345, in validate_and_save self.task.reduce_metrics(logging_outputs, self.get_criterion()) File "/data1/cordercorder/fairseq/fairseq/tasks/translation.py", line 410, in reduce_metrics self.task.reduce_metrics(logging_outputs, self.get_criterion())valid_losses = validate(cfg, trainer, task, epoch_itr, valid_subsets) File "/data1/cordercorder/fairseq/fairseq/tasks/translation.py", line 410, in reduce_metrics File "/data1/cordercorder/fairseq/fairseq_cli/train.py", line 413, in validate self.task.reduce_metrics(logging_outputs, self.get_criterion()) File "/data1/cordercorder/fairseq/fairseq/tasks/translation.py", line 410, in reduce_metrics metrics.log_scalar("_bleu_counts", np.array(counts)) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/site-packages/torch/tensor.py", line 480, in __array__ trainer.valid_step(sample) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/contextlib.py", line 74, in inner metrics.log_scalar("_bleu_counts", np.array(counts)) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/site-packages/torch/tensor.py", line 480, in __array__ return func(*args, **kwds)metrics.log_scalar("_bleu_counts", np.array(counts)) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 834, in valid_step File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/site-packages/torch/tensor.py", line 480, in __array__ return self.numpy() TypeError: can't convert cuda:2 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. return self.numpy() TypeError: can't convert cuda:3 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. return self.numpy() TypeError: can't convert cuda:1 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. logging_output = self._reduce_and_log_stats(logging_outputs, sample_size) File "/data1/cordercorder/fairseq/fairseq/trainer.py", line 1157, in _reduce_and_log_stats self.task.reduce_metrics(logging_outputs, self.get_criterion()) File "/data1/cordercorder/fairseq/fairseq/tasks/translation.py", line 410, in reduce_metrics metrics.log_scalar("_bleu_counts", np.array(counts)) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/site-packages/torch/tensor.py", line 480, in __array__ return self.numpy() TypeError: can't convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first. Traceback (most recent call last): File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/runpy.py", line 85, in _run_code exec(code, run_globals) File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/site-packages/torch/distributed/launch.py", line 261, in <module> main() File "/data/cordercorder/anaconda3/envs/nmt/lib/python3.7/site-packages/torch/distributed/launch.py", line 257, in main cmd=cmd) subprocess.CalledProcessError: Command '['/data/cordercorder/anaconda3/envs/nmt/bin/python', '-u', '/data/cordercorder/anaconda3/envs/nmt/bin/fairseq-train', '--local_rank=3', 'tiny_data_bin', '--distributed-world-size', '4', '--arch', 'transformer', '--share-decoder-input-output-embed', '--optimizer', 'adam', '--adam-betas', '(0.9, 0.98)', '--clip-norm', '0.0', '--lr-scheduler', 'inverse_sqrt', '--warmup-init-lr', '1e-07', '--warmup-updates', '3000', '--lr', '0.0005', '--stop-min-lr', '1e-09', '--dropout', '0.25', '--weight-decay', '0.0001', '--criterion', 'label_smoothed_cross_entropy', '--label-smoothing', '0.1', '--max-tokens', '5000', '--batch-size', '64', '--update-freq', '4', '--max-epoch', '30', '--save-dir', 'checkpoint', '--skip-invalid-size-inputs-valid-test', '--eval-bleu', '--eval-bleu-args', '{"beam": 5}', '--eval-bleu-remove-bpe', 'sentencepiece', '--eval-bleu-print-samples', '--eval-tokenized-bleu', '--best-checkpoint-metric', 'bleu', '--maximize-best-checkpoint-metric', '--validate-interval-updates', '1']' returned non-zero exit status 1. ``` The error is cased by the fact that the numpy of version 1.20.1 does't support codes like following: ```python import torch import numpy as np a = torch.tensor(0, device="cuda:0") b = np.array([a]) ``` The above codes will lead to error: "TypeError: can't convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.", but the codes run well if the numpy version is 1.18.1 or 1.17.0 (when the numpy version is below 1.20.0, it is ok, I guess). However, it seems like that the latest version of fairseq need a numpy package of version 1.20.0 or higher (issue https://github.com/pytorch/fairseq/issues/3203 ). ### Reproduce the error Download the source code of fairseq (commit ID: 7061a0ff83872ac491ba5963eb7fc04cb10d57c4) and run following code: ```bash export CUDA_VISIBLE_DEVICES=0,1,2,3 data_bin_dir=tiny_data_bin python -m torch.distributed.launch --nproc_per_node=4 \ --master_addr="127.0.0.1" \ --master_port=12345 \ $(which fairseq-train) ${data_bin_dir} \ --distributed-world-size 4 \ --arch transformer \ --share-decoder-input-output-embed \ --optimizer adam \ --adam-betas '(0.9, 0.98)' \ --clip-norm 0.0 \ --lr-scheduler inverse_sqrt \ --warmup-init-lr 1e-07 \ --warmup-updates 3000 \ --lr 0.0005 \ --stop-min-lr 1e-09 \ --dropout 0.25 \ --weight-decay 0.0001 \ --criterion label_smoothed_cross_entropy \ --label-smoothing 0.1 \ --max-tokens 5000 \ --batch-size 64 \ --update-freq 4 \ --max-epoch 30 \ --save-dir checkpoint \ --skip-invalid-size-inputs-valid-test \ --eval-bleu \ --eval-bleu-args '{"beam": 5}' \ --eval-bleu-remove-bpe sentencepiece \ --eval-bleu-print-samples \ --eval-tokenized-bleu \ --best-checkpoint-metric bleu \ --maximize-best-checkpoint-metric \ --validate-interval-updates 1 ``` ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3237 Reviewed By: myleott Differential Revision: D26429732 Pulled By: alexeib fbshipit-source-id: bc887ce952d28541cb07dbbdc7e80e99428a6b34 --- fairseq/tasks/translation.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 90635d882f..331f685495 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -394,7 +394,11 @@ def reduce_metrics(self, logging_outputs, criterion): if self.cfg.eval_bleu: def sum_logs(key): - return sum(log.get(key, 0) for log in logging_outputs) + import torch + result = sum(log.get(key, 0) for log in logging_outputs) + if torch.is_tensor(result): + result = result.cpu() + return result counts, totals = [], [] for i in range(EVAL_BLEU_ORDER): From 5ac5e8a20a7a914698f9970c2a384f14015ece3d Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Fri, 12 Feb 2021 21:18:23 -0800 Subject: [PATCH 216/774] fix sharing objects between tasks (#1623) Summary: fixes previous change that changes state/dataset/etc to class variables instead of instance variables Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1623 Reviewed By: michaelauli Differential Revision: D26439560 Pulled By: alexeib fbshipit-source-id: ab9e75a425a47ac7ace006419259e254770e560e --- fairseq/tasks/fairseq_task.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 04025023fa..375b5277b9 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -78,12 +78,15 @@ def logging_outputs_can_be_summed(criterion) -> bool: return criterion.logging_outputs_can_be_summed() cfg: FairseqDataclass - datasets: Dict[str, FairseqDataset] = dict() - dataset_to_epoch_iter: Dict[FairseqDataset, Any] = dict() - state: StatefulContainer = StatefulContainer() + datasets: Dict[str, FairseqDataset] + dataset_to_epoch_iter: Dict[FairseqDataset, Any] + state: StatefulContainer = None def __init__(self, cfg: FairseqDataclass, **kwargs): self.cfg = cfg + self.datasets = dict() + self.dataset_to_epoch_iter = dict() + self.state = StatefulContainer() @classmethod def load_dictionary(cls, filename): @@ -553,10 +556,13 @@ def reduce_metrics(self, logging_outputs, criterion): criterion.__class__.reduce_metrics(logging_outputs) def state_dict(self): - return self.state.state_dict + if self.state is not None: + return self.state.state_dict + return {} def load_state_dict(self, state_dict: Dict[str, Any]): - self.state.merge_state_dict(state_dict) + if self.state is not None: + self.state.merge_state_dict(state_dict) def max_positions(self): """Return the max input length allowed by the task.""" From 43415b44781af6ac9c10adce0ae2a7d26d611bd1 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Tue, 16 Feb 2021 15:50:46 -0800 Subject: [PATCH 217/774] Prepend embedding layer when return_all_hiddens=True in TransformerEncoder (#1559) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1559 This matches the behavior of RobertaEncoder. Test Plan: Imported from OSS Reviewed By: gwenzek Differential Revision: D25936937 Pulled By: myleott fbshipit-source-id: 795ec8d50298a41d9e9638101436faa01cdf1586 --- fairseq/models/transformer.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 362d9b28d6..78762ef924 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -435,14 +435,21 @@ def forward( """ x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) - # B x T x C -> T x B x C - x = x.transpose(0, 1) - # compute padding mask encoder_padding_mask = src_tokens.eq(self.padding_idx) + # account for padding while computing the representation + if encoder_padding_mask is not None: + x = x * (1 - encoder_padding_mask.unsqueeze(-1).type_as(x)) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + encoder_states = [] + if return_all_hiddens: + encoder_states.append(x) + # encoder layers for layer in self.layers: x = layer(x, encoder_padding_mask) @@ -454,7 +461,7 @@ def forward( x = self.layer_norm(x) # The Pytorch Mobile lite interpreter does not supports returning NamedTuple in - # `foward` so we use a dictionary instead. + # `forward` so we use a dictionary instead. # TorchScript does not support mixed values so the values are all lists. # The empty list is equivalent to None. return { From 54423d3b22a3e7f536e02e9e5445cef9becbd60d Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Tue, 16 Feb 2021 15:50:46 -0800 Subject: [PATCH 218/774] refactor RobertaEncoder (#1560) Summary: This is long overdue, but finally deprecating the RobertaEncoder components and just using TransformerEncoder directly. This will make it easier for some upcoming online backtranslation changes, and will eventually make migrating it to dataclasses/Hydra easier too. It also fixes some longstanding inconsistencies in layernorm placement in the model parallel roberta code. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1560 Test Plan: - confirmed that training gives identical losses as before: https://gist.github.com/myleott/9a4d213fb88a02b00094ea074f5a2e2d - confirmed that old roberta models can be loaded and produce identical results - confirmed that old linformer models can be loaded and produce identical results (reran commands from D25938236 (https://github.com/pytorch/fairseq/commit/bf54551cafa13678c0254d2c20354cc026cc0bac)) - confirmed that old model parallel models can be loaded and produce identical results: ``` python -m fairseq_cli.validate --path checkpoint.mp1/checkpoint_last.pt --task dummy_masked_lm --criterion masked_lm --max-sentences 8 --dataset-size 100 --model-parallel-size 2 --distributed-world-size 2 before: 2021-01-19 19:04:14 | INFO | valid | | valid on 'valid' subset | loss 14.62 | ppl 25174.3 | wps 0 | wpb 53248 | bsz 104 after: 2021-01-19 19:06:59 | INFO | valid | | valid on 'valid' subset | loss 14.62 | ppl 25174.3 | wps 0 | wpb 53248 | bsz 104 ``` Reviewed By: gwenzek, ngoyal2707 Differential Revision: D25937145 Pulled By: myleott fbshipit-source-id: 1ce0bc93e28e03fb926534ea4134684a49232599 --- .../linformer_src/models/linformer_roberta.py | 71 ++------- .../modules/linformer_sentence_encoder.py | 137 ++-------------- .../linformer_sentence_encoder_layer.py | 83 ++-------- .../model_parallel/models/roberta/model.py | 148 +++++------------- fairseq/model_parallel/models/transformer.py | 7 +- fairseq/model_parallel/modules/__init__.py | 6 - .../modules/transformer_sentence_encoder.py | 59 ------- .../transformer_sentence_encoder_layer.py | 77 --------- fairseq/models/roberta/model.py | 100 ++++++++---- fairseq/models/transformer.py | 1 + 10 files changed, 161 insertions(+), 528 deletions(-) delete mode 100644 fairseq/model_parallel/modules/transformer_sentence_encoder.py delete mode 100644 fairseq/model_parallel/modules/transformer_sentence_encoder_layer.py diff --git a/examples/linformer/linformer_src/models/linformer_roberta.py b/examples/linformer/linformer_src/models/linformer_roberta.py index be5d8e85ec..18ad44f079 100644 --- a/examples/linformer/linformer_src/models/linformer_roberta.py +++ b/examples/linformer/linformer_src/models/linformer_roberta.py @@ -11,9 +11,15 @@ import torch from fairseq import utils from fairseq.models import register_model, register_model_architecture -from fairseq.models.roberta import RobertaEncoder, RobertaModel +from fairseq.models.roberta import ( + init_bert_params, + roberta_base_architecture, + roberta_large_architecture, + RobertaEncoder, + RobertaModel, +) -from ..modules.linformer_sentence_encoder import LinformerSentenceEncoder +from ..modules.linformer_sentence_encoder import LinformerTransformerEncoder logger = logging.getLogger(__name__) @@ -66,30 +72,10 @@ def __init__(self, args, dictionary): super().__init__(args, dictionary) self.register_buffer("version", torch.tensor(2)) - def build_encoder(self, args, dictionary): - return LinformerSentenceEncoder( - padding_idx=dictionary.pad(), - vocab_size=len(dictionary), - num_encoder_layers=args.encoder_layers, - embedding_dim=args.encoder_embed_dim, - ffn_embedding_dim=args.encoder_ffn_embed_dim, - num_attention_heads=args.encoder_attention_heads, - dropout=args.dropout, - attention_dropout=args.attention_dropout, - activation_dropout=args.activation_dropout, - layerdrop=args.encoder_layerdrop, - max_seq_len=args.max_positions, - num_segments=0, - encoder_normalize_before=True, - apply_bert_init=True, - activation_fn=args.activation_fn, - q_noise=args.quant_noise_pq, - qn_block_size=args.quant_noise_pq_block_size, - compressed=args.compressed, - shared_kv_compressed=args.shared_kv_compressed, - shared_layer_kv_compressed=args.shared_layer_kv_compressed, - freeze_compress=args.freeze_compress, - ) + def build_encoder(self, args, dictionary, embed_tokens): + encoder = LinformerTransformerEncoder(args, dictionary, embed_tokens) + encoder.apply(init_bert_params) + return encoder def upgrade_state_dict_named(self, state_dict, name): super().upgrade_state_dict_named(state_dict, name) @@ -115,25 +101,11 @@ def upgrade_state_dict_named(self, state_dict, name): @register_model_architecture("linformer_roberta", "linformer_roberta") def base_architecture(args): - args.encoder_layers = getattr(args, "encoder_layers", 12) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 3072) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) - - args.activation_fn = getattr(args, "activation_fn", "gelu") - args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") - - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_dropout = getattr(args, "activation_dropout", 0.0) - args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) - args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) - args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) - args.compressed = getattr(args, "compressed", 4) args.shared_kv_compressed = getattr(args, "shared_kv_compressed", 0) args.shared_layer_kv_compressed = getattr(args, "shared_layer_kv_compressed", 0) args.freeze_compress = getattr(args, "freeze_compress", 0) + roberta_base_architecture(args) @register_model_architecture("linformer_roberta", "linformer_roberta_base") @@ -143,18 +115,5 @@ def linformer_roberta_base_architecture(args): @register_model_architecture("linformer_roberta", "linformer_roberta_large") def linformer_roberta_large_architecture(args): - args.encoder_layers = getattr(args, "encoder_layers", 24) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) - - args.activation_fn = getattr(args, "activation_fn", "gelu") - args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") - - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_dropout = getattr(args, "activation_dropout", 0.0) - args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) - args.compressed = getattr(args, "compressed", 4) - args.shared_kv_compressed = getattr(args, "shared_kv_compressed", 0) - args.shared_layer_kv_compressed = getattr(args, "shared_layer_kv_compressed", 0) + roberta_large_architecture(args) + base_architecture(args) diff --git a/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py b/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py index 3cdca01235..44f7989bd8 100644 --- a/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py +++ b/examples/linformer/linformer_src/modules/linformer_sentence_encoder.py @@ -6,12 +6,12 @@ import math import torch.nn as nn -from fairseq.modules import TransformerSentenceEncoder +from fairseq.models.transformer import TransformerEncoder -from .linformer_sentence_encoder_layer import LinformerSentenceEncoderLayer +from .linformer_sentence_encoder_layer import LinformerTransformerEncoderLayer -class LinformerSentenceEncoder(TransformerSentenceEncoder): +class LinformerTransformerEncoder(TransformerEncoder): """ Implementation for a Bi-directional Linformer based Sentence Encoder used in BERT/XLM style pre-trained models. @@ -35,135 +35,20 @@ class LinformerSentenceEncoder(TransformerSentenceEncoder): in format B x C. """ - def __init__( - self, - padding_idx: int, - vocab_size: int, - num_encoder_layers: int = 6, - embedding_dim: int = 768, - ffn_embedding_dim: int = 3072, - num_attention_heads: int = 8, - dropout: float = 0.1, - attention_dropout: float = 0.1, - activation_dropout: float = 0.1, - layerdrop: float = 0.0, - max_seq_len: int = 256, - num_segments: int = 2, - use_position_embeddings: bool = True, - offset_positions_by_padding: bool = True, - encoder_normalize_before: bool = False, - apply_bert_init: bool = False, - activation_fn: str = "relu", - learned_pos_embedding: bool = True, - embed_scale: float = None, - freeze_embeddings: bool = False, - n_trans_layers_to_freeze: int = 0, - export: bool = False, - traceable: bool = False, - q_noise: float = 0.0, - qn_block_size: int = 8, - compressed: int = 4, - shared_kv_compressed: int = 0, - shared_layer_kv_compressed: int = 0, - freeze_compress: int = 0, - ) -> None: - - # Initialize linformer parameters - self.compressed = compressed - self.shared_kv_compressed = shared_kv_compressed - self.shared_layer_kv_compressed = shared_layer_kv_compressed + def __init__(self, args, dictionary, embed_tokens): self.compress_layer = None - self.freeze_compress = freeze_compress - - super().__init__( - padding_idx=padding_idx, - vocab_size=vocab_size, - num_encoder_layers=num_encoder_layers, - embedding_dim=embedding_dim, - ffn_embedding_dim=ffn_embedding_dim, - num_attention_heads=num_attention_heads, - dropout=dropout, - attention_dropout=attention_dropout, - activation_dropout=activation_dropout, - layerdrop=layerdrop, - max_seq_len=max_seq_len, - num_segments=num_segments, - use_position_embeddings=use_position_embeddings, - offset_positions_by_padding=offset_positions_by_padding, - encoder_normalize_before=encoder_normalize_before, - apply_bert_init=apply_bert_init, - activation_fn=activation_fn, - learned_pos_embedding=learned_pos_embedding, - embed_scale=embed_scale, - freeze_embeddings=freeze_embeddings, - n_trans_layers_to_freeze=n_trans_layers_to_freeze, - export=export, - traceable=traceable, - q_noise=q_noise, - qn_block_size=qn_block_size, - ) + super().__init__(args, dictionary, embed_tokens) - def build_transformer_sentence_encoder_layer( - self, - embedding_dim, - ffn_embedding_dim, - num_attention_heads, - dropout, - attention_dropout, - activation_dropout, - activation_fn, - export, - q_noise, - qn_block_size, - ): - if self.shared_layer_kv_compressed == 1 and self.compress_layer is None: + def build_encoder_layer(self, args): + if self.args.shared_layer_kv_compressed == 1 and self.compress_layer is None: compress_layer = nn.Linear( - self.max_seq_len, self.max_seq_len // self.compressed + self.args.max_positions, + self.args.max_positions // self.args.compressed, ) # intialize parameters for compressed layer nn.init.xavier_uniform_(compress_layer.weight, gain=1 / math.sqrt(2)) - if self.freeze_compress == 1: + if self.args.freeze_compress == 1: compress_layer.weight.requires_grad = False self.compress_layer = compress_layer - return LinformerSentenceEncoderLayer( - embedding_dim=embedding_dim, - ffn_embedding_dim=ffn_embedding_dim, - num_attention_heads=num_attention_heads, - dropout=dropout, - attention_dropout=attention_dropout, - activation_dropout=activation_dropout, - activation_fn=activation_fn, - export=export, - q_noise=q_noise, - qn_block_size=qn_block_size, - compressed=self.compressed, - max_seq_len=self.max_seq_len, - shared_kv_compressed=self.shared_kv_compressed, - shared_compress_layer=( - None if self.shared_layer_kv_compressed == 0 else self.compress_layer - ), - freeze_compress=self.freeze_compress, - ) - - def upgrade_state_dict_named(self, state_dict, name): - prefix = name + "." if name != "" else "" - items_to_add = {} - keys_to_remove = [] - - # update key name for shared layer in new version of code - for k in state_dict.keys(): - if k.startswith(prefix + "compress_layer"): - if self.shared_layer_kv_compressed: - for layer_idx in range(len(self.layers)): - new_k = prefix + "layers.{0}.shared_compress_layer.{1}".format( - layer_idx, - k[len(prefix + "compress_layer.") :], - ) - items_to_add[new_k] = state_dict[k] - - for k in keys_to_remove: - del state_dict[k] - - for key, value in items_to_add.items(): - state_dict[key] = value + return LinformerTransformerEncoderLayer(args, self.compress_layer) diff --git a/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py b/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py index 0b80fabefe..7e2caa0340 100644 --- a/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py +++ b/examples/linformer/linformer_src/modules/linformer_sentence_encoder_layer.py @@ -3,88 +3,44 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from typing import Callable - import torch from fairseq import utils -from fairseq.modules import TransformerSentenceEncoderLayer +from fairseq.modules import TransformerEncoderLayer from .multihead_linear_attention import MultiheadLinearAttention -class LinformerSentenceEncoderLayer(TransformerSentenceEncoderLayer): +class LinformerTransformerEncoderLayer(TransformerEncoderLayer): """ Implements a Linformer Encoder Layer used in BERT/XLM style pre-trained models. """ - def __init__( - self, - embedding_dim: int = 768, - ffn_embedding_dim: int = 3072, - num_attention_heads: int = 8, - dropout: float = 0.1, - attention_dropout: float = 0.1, - activation_dropout: float = 0.1, - activation_fn: str = "relu", - export: bool = False, - q_noise: float = 0.0, - qn_block_size: int = 8, - init_fn: Callable = None, - compressed: int = 1, - max_seq_len: int = 256, - shared_kv_compressed: int = 0, - shared_compress_layer: any = None, - freeze_compress: int = 0, - ) -> None: - - # Initialize linformer parameters - self.compressed = compressed - self.max_seq_len = max_seq_len - self.shared_kv_compressed = shared_kv_compressed - self.freeze_compress = freeze_compress - + def __init__(self, args, shared_compress_layer): # wrap in a list so it's not automatically registered by PyTorch self.shared_compress_layer = [shared_compress_layer] - super().__init__( - embedding_dim=embedding_dim, - ffn_embedding_dim=ffn_embedding_dim, - num_attention_heads=num_attention_heads, - dropout=dropout, - attention_dropout=attention_dropout, - activation_dropout=activation_dropout, - activation_fn=activation_fn, - export=export, - q_noise=q_noise, - qn_block_size=qn_block_size, - ) + super().__init__(args) + self.register_buffer("version", torch.tensor(2)) - def build_self_attention( - self, - embed_dim, - num_attention_heads, - dropout, - self_attention, - q_noise, - qn_block_size, - ): + def build_self_attention(self, embed_dim, args): return MultiheadLinearAttention( embed_dim, - num_attention_heads, - dropout=dropout, + args.encoder_attention_heads, + dropout=args.dropout, self_attention=True, - q_noise=q_noise, - qn_block_size=qn_block_size, - compressed=self.compressed, - max_seq_len=self.max_seq_len, - shared_kv_compressed=self.shared_kv_compressed, + q_noise=args.quant_noise_pq, + qn_block_size=args.quant_noise_pq_block_size, + compressed=args.compressed, + max_seq_len=args.max_positions, + shared_kv_compressed=args.shared_kv_compressed, shared_compress_layer=self.shared_compress_layer[0], - freeze_compress=self.freeze_compress, + freeze_compress=args.freeze_compress, ) def upgrade_state_dict_named(self, state_dict, name): + super().upgrade_state_dict_named(state_dict, name) prefix = name + "." if name != "" else "" # some old checkpoints had weight sharing implemented incorrectly @@ -101,14 +57,7 @@ def upgrade_state_dict_named(self, state_dict, name): self.shared_compress_layer[0].weight.size(0), ) ] - self.self_attn = self.build_self_attention( - self.embedding_dim, - self.num_attention_heads, - dropout=self.attention_dropout, - self_attention=True, - q_noise=self.q_noise, - qn_block_size=self.qn_block_size, - ) + self.self_attn = self.build_self_attention(self.embed_dim, self.args) # delete shared_compress_layer, since it's already copied to # self_attn.compress_k.weight del state_dict[f"{prefix}shared_compress_layer.weight"] diff --git a/fairseq/model_parallel/models/roberta/model.py b/fairseq/model_parallel/models/roberta/model.py index 68ad88d2a5..77a80ef720 100644 --- a/fairseq/model_parallel/models/roberta/model.py +++ b/fairseq/model_parallel/models/roberta/model.py @@ -12,16 +12,15 @@ import torch.nn as nn import torch.nn.functional as F from fairseq import utils -from fairseq.model_parallel.modules import ModelParallelTransformerSentenceEncoder -from fairseq.models import FairseqEncoder, register_model, register_model_architecture +from fairseq.model_parallel.models.transformer import ModelParallelTransformerEncoder +from fairseq.models import register_model, register_model_architecture from fairseq.models.roberta import ( - RobertaClassificationHead, + roberta_base_architecture, + roberta_prenorm_architecture, RobertaEncoder, - RobertaLMHead, RobertaModel, ) -from fairseq.modules import LayerNorm, TransformerSentenceEncoder -from fairseq.modules.transformer_sentence_encoder import init_bert_params +from fairseq.modules import LayerNorm try: @@ -29,7 +28,7 @@ copy_to_model_parallel_region, gather_from_model_parallel_region, ColumnParallelLinear, - RowParallelLinear, + VocabParallelEmbedding, ) has_megatron_submodule = True @@ -48,7 +47,15 @@ def __init__(self, args, encoder): @staticmethod def add_args(parser): - super(ModelParallelRobertaModel, ModelParallelRobertaModel).add_args(parser) + RobertaModel.add_args(parser) + parser.add_argument( + "--no-final-layer-norm", + action="store_true", + help=( + "don't add final layernorm (only applicable when " + "--encoder-normalize-before=True" + ), + ) @classmethod def build_model(cls, args, task): @@ -165,121 +172,52 @@ def forward(self, features, **kwargs): return x -class ModelParallelRobertaEncoder(FairseqEncoder): - """RoBERTa encoder. - - Implements the :class:`~fairseq.models.FairseqDecoder` interface required - by :class:`~fairseq.models.FairseqLanguageModel`. - """ +class ModelParallelRobertaEncoder(RobertaEncoder): + """RoBERTa encoder.""" def __init__(self, args, dictionary): - super().__init__(dictionary) - self.args = args - - # RoBERTa is a sentence encoder model, so users will intuitively trim - # encoder layers. However, the implementation uses the fairseq decoder, - # so we fix here. - if args.encoder_layers_to_keep: - args.encoder_layers = len(args.encoder_layers_to_keep.split(",")) - args.decoder_layers_to_keep = args.encoder_layers_to_keep - args.encoder_layers_to_keep = None - - self.sentence_encoder = ModelParallelTransformerSentenceEncoder( - padding_idx=dictionary.pad(), - vocab_size=len(dictionary), - num_encoder_layers=args.encoder_layers, - embedding_dim=args.encoder_embed_dim, - ffn_embedding_dim=args.encoder_ffn_embed_dim, - num_attention_heads=args.encoder_attention_heads, - dropout=args.dropout, - attention_dropout=args.attention_dropout, - activation_dropout=args.activation_dropout, - layerdrop=args.encoder_layerdrop, - max_seq_len=args.max_positions, - num_segments=0, - encoder_normalize_before=False, - apply_bert_init=False, - activation_fn=args.activation_fn, - ) - self.lm_head = ModelParallelRobertaLMHead( - embed_dim=args.encoder_embed_dim, - output_dim=len(dictionary), - activation_fn=args.activation_fn, - weight=self.sentence_encoder.embed_tokens.weight, - ) - - def forward( - self, - src_tokens, - features_only=False, - return_all_hiddens=False, - masked_tokens=None, - **unused - ): - """ - Args: - src_tokens (LongTensor): input tokens of shape `(batch, src_len)` - features_only (bool, optional): skip LM head and just return - features. If True, the output will be of shape - `(batch, src_len, embed_dim)`. - return_all_hiddens (bool, optional): also return all of the - intermediate hidden states (default: False). - - Returns: - tuple: - - the LM output of shape `(batch, src_len, vocab)` - - a dictionary of additional data, where 'inner_states' - is a list of hidden states. Note that the hidden - states have shape `(src_len, batch, vocab)`. - """ - x, extra = self.extract_features( - src_tokens, return_all_hiddens=return_all_hiddens - ) - if not features_only: - x = self.output_layer(x, masked_tokens=masked_tokens) - return x, extra + super().__init__(args, dictionary) + assert not self.args.untie_weights_roberta - def extract_features(self, src_tokens, return_all_hiddens=False, **unused): - inner_states, _ = self.sentence_encoder( - src_tokens, - last_state_only=not return_all_hiddens, - ) - features = inner_states[-1].transpose(0, 1) # T x B x C -> B x T x C - return features, {"inner_states": inner_states if return_all_hiddens else None} + def build_embedding(self, vocab_size, embedding_dim, padding_idx): + return VocabParallelEmbedding(vocab_size, embedding_dim, padding_idx) - def output_layer(self, features, masked_tokens=None, **unused): - return self.lm_head(features, masked_tokens) + def build_encoder(self, args, dictionary, embed_tokens): + return ModelParallelTransformerEncoder(args, dictionary, embed_tokens) - def max_positions(self): - """Maximum output length supported by the encoder.""" - return self.args.max_positions + def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): + return ModelParallelRobertaLMHead(embed_dim, output_dim, activation_fn, weight) @register_model_architecture("model_parallel_roberta", "model_parallel_roberta") def base_architecture(args): - args.encoder_layers = getattr(args, "encoder_layers", 12) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 3072) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) + args.no_final_layer_norm = getattr(args, "no_final_layer_norm", False) + # model parallel RoBERTa defaults to "Pre-LN" formulation + roberta_prenorm_architecture(args) - args.activation_fn = getattr(args, "activation_fn", "gelu") - args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_dropout = getattr(args, "activation_dropout", 0.0) - args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) - args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) - args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) +# earlier versions of model parallel RoBERTa removed the final layer norm +@register_model_architecture("model_parallel_roberta", "model_parallel_roberta_v1") +def model_parallel_roberta_v1_architecture(args): + args.no_final_layer_norm = getattr(args, "no_final_layer_norm", True) + base_architecture(args) + + +@register_model_architecture( + "model_parallel_roberta", "model_parallel_roberta_postnorm" +) +def model_parallel_roberta_postnorm_architecture(args): + # the original BERT/RoBERTa uses the "Post-LN" formulation + roberta_base_architecture(args) @register_model_architecture("model_parallel_roberta", "model_parallel_roberta_base") -def roberta_base_architecture(args): +def model_parallel_roberta_base_architecture(args): base_architecture(args) @register_model_architecture("model_parallel_roberta", "model_parallel_roberta_large") -def roberta_large_architecture(args): +def model_parallel_roberta_large_architecture(args): args.encoder_layers = getattr(args, "encoder_layers", 24) args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096) diff --git a/fairseq/model_parallel/models/transformer.py b/fairseq/model_parallel/models/transformer.py index 4f34645226..6b330ef1b7 100644 --- a/fairseq/model_parallel/models/transformer.py +++ b/fairseq/model_parallel/models/transformer.py @@ -6,7 +6,6 @@ import logging import torch.nn as nn -import torch.nn.functional as F from fairseq.model_parallel.modules import ( ModelParallelTransformerDecoderLayer, ModelParallelTransformerEncoderLayer, @@ -86,6 +85,12 @@ class ModelParallelTransformerEncoder(TransformerEncoder): is a :class:`ModelParallelTransformerEncoderLayer`. """ + def __init__(self, args, dictionary, embed_tokens): + super().__init__(args, dictionary, embed_tokens) + + if args.no_final_layer_norm: + self.layer_norm = None + def build_encoder_layer(self, args): return ModelParallelTransformerEncoderLayer(args) diff --git a/fairseq/model_parallel/modules/__init__.py b/fairseq/model_parallel/modules/__init__.py index fb45b3c9e0..11603217a1 100644 --- a/fairseq/model_parallel/modules/__init__.py +++ b/fairseq/model_parallel/modules/__init__.py @@ -9,15 +9,9 @@ ModelParallelTransformerEncoderLayer, ModelParallelTransformerDecoderLayer, ) -from .transformer_sentence_encoder_layer import ( - ModelParallelTransformerSentenceEncoderLayer, -) -from .transformer_sentence_encoder import ModelParallelTransformerSentenceEncoder __all__ = [ "ModelParallelMultiheadAttention", "ModelParallelTransformerEncoderLayer", "ModelParallelTransformerDecoderLayer", - "ModelParallelTransformerSentenceEncoder", - "ModelParallelTransformerSentenceEncoderLayer", ] diff --git a/fairseq/model_parallel/modules/transformer_sentence_encoder.py b/fairseq/model_parallel/modules/transformer_sentence_encoder.py deleted file mode 100644 index a5d50a33c6..0000000000 --- a/fairseq/model_parallel/modules/transformer_sentence_encoder.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import random -from typing import Optional, Tuple - -import torch -import torch.nn as nn -import torch.nn.functional as F -from fairseq.model_parallel.modules import ModelParallelTransformerSentenceEncoderLayer -from fairseq.modules import ( - LayerNorm, - MultiheadAttention, - PositionalEmbedding, - TransformerSentenceEncoder, -) - - -try: - from fairseq.model_parallel.megatron.mpu import VocabParallelEmbedding - - has_megatron_submodule = True -except (ImportError, ModuleNotFoundError): - has_megatron_submodule = False - - -class ModelParallelTransformerSentenceEncoder(TransformerSentenceEncoder): - """ - Implementation for a Model Parallel Bi-directional Transformer based - Sentence Encoder used in BERT/XLM style pre-trained models. - """ - - def build_embedding(self, vocab_size, embedding_dim, padding_idx): - return VocabParallelEmbedding(vocab_size, embedding_dim, padding_idx) - - def build_transformer_sentence_encoder_layer( - self, - embedding_dim, - ffn_embedding_dim, - num_attention_heads, - dropout, - attention_dropout, - activation_dropout, - activation_fn, - export, - **unused, - ): - return ModelParallelTransformerSentenceEncoderLayer( - embedding_dim=embedding_dim, - ffn_embedding_dim=ffn_embedding_dim, - num_attention_heads=num_attention_heads, - dropout=dropout, - attention_dropout=attention_dropout, - activation_dropout=activation_dropout, - activation_fn=activation_fn, - export=export, - ) diff --git a/fairseq/model_parallel/modules/transformer_sentence_encoder_layer.py b/fairseq/model_parallel/modules/transformer_sentence_encoder_layer.py deleted file mode 100644 index e10bf52332..0000000000 --- a/fairseq/model_parallel/modules/transformer_sentence_encoder_layer.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import torch -import torch.nn.functional as F -from fairseq import utils -from fairseq.model_parallel.modules import ModelParallelMultiheadAttention -from fairseq.modules import TransformerSentenceEncoderLayer - - -try: - from fairseq.model_parallel.megatron.mpu import ( - ColumnParallelLinear, - RowParallelLinear, - ) - - has_megatron_submodule = True -except (ImportError, ModuleNotFoundError): - has_megatron_submodule = False - - -class ModelParallelTransformerSentenceEncoderLayer(TransformerSentenceEncoderLayer): - """ - Implements a Model Parallel Transformer Encoder Layer used in - BERT/XLM style pre-trained models. - """ - - def build_fc1(self, input_dim, output_dim, **unused): - return ColumnParallelLinear(input_dim, output_dim, gather_output=False) - - def build_fc2(self, input_dim, output_dim, **unused): - return RowParallelLinear(input_dim, output_dim, input_is_parallel=True) - - def build_self_attention( - self, - embed_dim, - num_attention_heads, - dropout, - **kwargs, - ): - return ModelParallelMultiheadAttention( - embed_dim, num_attention_heads, dropout=dropout, self_attention=True - ) - - def forward( - self, - x: torch.Tensor, - self_attn_mask: torch.Tensor = None, - self_attn_padding_mask: torch.Tensor = None, - ): - """ - LayerNorm is applied either before or after the self-attention/ffn - modules similar to the original Transformer imlementation. - """ - residual = x - x = self.self_attn_layer_norm(x) - x, attn = self.self_attn( - query=x, - key=x, - value=x, - key_padding_mask=self_attn_padding_mask, - need_weights=False, - attn_mask=self_attn_mask, - ) - x = self.dropout_module(x) - x = residual + x - - residual = x - x = self.final_layer_norm(x) - x = self.activation_fn(self.fc1(x)) - x = self.activation_dropout_module(x) - x = self.fc2(x) - x = self.dropout_module(x) - x = residual + x - return x, None diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 00a5a5485f..a2a40ba6e2 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -18,7 +18,8 @@ register_model, register_model_architecture, ) -from fairseq.modules import LayerNorm, TransformerSentenceEncoder +from fairseq.models.transformer import TransformerEncoder +from fairseq.modules import LayerNorm from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ from fairseq.modules.transformer_sentence_encoder import init_bert_params @@ -87,6 +88,11 @@ def add_args(parser): action="store_true", help="apply layernorm before each encoder block", ) + parser.add_argument( + "--layernorm-embedding", + action="store_true", + help="add layernorm to embedding", + ) parser.add_argument( "--dropout", type=float, metavar="D", help="dropout probability" ) @@ -264,6 +270,13 @@ def upgrade_state_dict_named(self, state_dict, name): state_dict[new_k] = state_dict[k] del state_dict[k] + # rename emb_layer_norm -> layernorm_embedding + for k in list(state_dict.keys()): + if ".emb_layer_norm." in k: + new_k = k.replace(".emb_layer_norm.", ".layernorm_embedding.") + state_dict[new_k] = state_dict[k] + del state_dict[k] + # upgrade children modules super().upgrade_state_dict_named(state_dict, name) @@ -401,7 +414,11 @@ def __init__(self, args, dictionary): if args.encoder_layers_to_keep: args.encoder_layers = len(args.encoder_layers_to_keep.split(",")) - self.sentence_encoder = self.build_encoder(args, dictionary) + embed_tokens = self.build_embedding( + len(dictionary), args.encoder_embed_dim, dictionary.pad() + ) + + self.sentence_encoder = self.build_encoder(args, dictionary, embed_tokens) self.lm_head = self.build_lm_head( embed_dim=args.encoder_embed_dim, @@ -414,26 +431,16 @@ def __init__(self, args, dictionary): ), ) - def build_encoder(self, args, dictionary): - return TransformerSentenceEncoder( - padding_idx=dictionary.pad(), - vocab_size=len(dictionary), - num_encoder_layers=args.encoder_layers, - embedding_dim=args.encoder_embed_dim, - ffn_embedding_dim=args.encoder_ffn_embed_dim, - num_attention_heads=args.encoder_attention_heads, - dropout=args.dropout, - attention_dropout=args.attention_dropout, - activation_dropout=args.activation_dropout, - layerdrop=args.encoder_layerdrop, - max_seq_len=args.max_positions, - num_segments=0, - encoder_normalize_before=True, - apply_bert_init=True, - activation_fn=args.activation_fn, - q_noise=args.quant_noise_pq, - qn_block_size=args.quant_noise_pq_block_size, - ) + def build_embedding(self, vocab_size, embedding_dim, padding_idx): + return nn.Embedding(vocab_size, embedding_dim, padding_idx) + + def build_encoder(self, args, dictionary, embed_tokens): + encoder = TransformerEncoder(args, dictionary, embed_tokens) + encoder.apply(init_bert_params) + return encoder + + def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): + return RobertaLMHead(embed_dim, output_dim, activation_fn, weight) def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): return RobertaLMHead(embed_dim, output_dim, activation_fn, weight) @@ -470,13 +477,15 @@ def forward( return x, extra def extract_features(self, src_tokens, return_all_hiddens=False, **kwargs): - inner_states, _ = self.sentence_encoder( + encoder_out = self.sentence_encoder( src_tokens, - last_state_only=not return_all_hiddens, + return_all_hiddens=return_all_hiddens, token_embeddings=kwargs.get("token_embeddings", None), ) - features = inner_states[-1].transpose(0, 1) # T x B x C -> B x T x C - return features, {"inner_states": inner_states if return_all_hiddens else None} + # T x B x C -> B x T x C + features = encoder_out["encoder_out"][0].transpose(0, 1) + inner_states = encoder_out["encoder_states"] if return_all_hiddens else None + return features, {"inner_states": inner_states} def output_layer(self, features, masked_tokens=None, **unused): return self.lm_head(features, masked_tokens) @@ -493,21 +502,50 @@ def base_architecture(args): args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 3072) args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) - args.activation_fn = getattr(args, "activation_fn", "gelu") - args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") - args.dropout = getattr(args, "dropout", 0.1) args.attention_dropout = getattr(args, "attention_dropout", 0.1) args.activation_dropout = getattr(args, "activation_dropout", 0.0) args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) - args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) - args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) + + args.max_source_positions = getattr(args, "max_positions", 512) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + + # BERT has a few structural differences compared to the original Transformer + args.encoder_learned_pos = getattr(args, "encoder_learned_pos", True) + args.layernorm_embedding = getattr(args, "layernorm_embedding", True) + args.no_scale_embedding = getattr(args, "no_scale_embedding", True) + args.activation_fn = getattr(args, "activation_fn", "gelu") + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) + args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") args.untie_weights_roberta = getattr(args, "untie_weights_roberta", False) + + # Adaptive input config + args.adaptive_input = getattr(args, "adaptive_input", False) + + # LayerDrop config + args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) + args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) + + # Quantization noise config + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8) + args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0) + + # R4F config args.spectral_norm_classification_head = getattr( args, "spectral_norm_classification_head", False ) +@register_model_architecture("roberta", "roberta_prenorm") +def roberta_prenorm_architecture(args): + args.layernorm_embedding = getattr(args, "layernorm_embedding", False) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) + base_architecture(args) + + @register_model_architecture("roberta", "roberta_base") def roberta_base_architecture(args): base_architecture(args) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 78762ef924..4960fd143d 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -325,6 +325,7 @@ class TransformerEncoder(FairseqEncoder): """ def __init__(self, args, dictionary, embed_tokens): + self.args = args super().__init__(dictionary) self.register_buffer("version", torch.Tensor([3])) From 7096ac35870aa24735bd0cc850beefa07784a668 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Tue, 16 Feb 2021 15:50:46 -0800 Subject: [PATCH 219/774] Make validate.py work with model parallel (#1570) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1570 Test Plan: Imported from OSS Reviewed By: gwenzek, ngoyal2707 Differential Revision: D25967675 Pulled By: myleott fbshipit-source-id: 7c7f8d25b87ef9b4f0a85331548bb3a2886a1e92 --- fairseq/logging/progress_bar.py | 2 +- fairseq_cli/validate.py | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index dc061a1821..0ae2bc006d 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -123,7 +123,7 @@ def __init__(self, iterable, epoch=None, prefix=None): if epoch is not None: self.prefix += "epoch {:03d}".format(epoch) if prefix is not None: - self.prefix += " | {}".format(prefix) + self.prefix += (" | " if self.prefix != "" else "") + prefix def __len__(self): return len(self.iterable) diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index c69bb94142..90d7e4c6a9 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -u -# !/usr/bin/env python3 -u # Copyright (c) Facebook, Inc. and its affiliates. # # This source code is licensed under the MIT license found in the @@ -43,6 +42,13 @@ def main(cfg: DictConfig, override_args=None): if use_cuda: torch.cuda.set_device(cfg.distributed_training.device_id) + if cfg.distributed_training.distributed_world_size > 1: + data_parallel_world_size = distributed_utils.get_data_parallel_world_size() + data_parallel_rank = distributed_utils.get_data_parallel_rank() + else: + data_parallel_world_size = 1 + data_parallel_rank = 0 + if override_args is not None: overrides = vars(override_args) overrides.update(eval(getattr(override_args, "model_overrides", "{}"))) @@ -91,8 +97,8 @@ def main(cfg: DictConfig, override_args=None): ignore_invalid_inputs=cfg.dataset.skip_invalid_size_inputs_valid_test, required_batch_size_multiple=cfg.dataset.required_batch_size_multiple, seed=cfg.common.seed, - num_shards=cfg.distributed_training.distributed_world_size, - shard_id=cfg.distributed_training.distributed_rank, + num_shards=data_parallel_world_size, + shard_id=data_parallel_rank, num_workers=cfg.dataset.num_workers, data_buffer_size=cfg.dataset.data_buffer_size, ).next_epoch_itr(shuffle=False) @@ -111,7 +117,7 @@ def main(cfg: DictConfig, override_args=None): progress.log(log_output, step=i) log_outputs.append(log_output) - if cfg.distributed_training.distributed_world_size > 1: + if data_parallel_world_size > 1: log_outputs = distributed_utils.all_gather_list( log_outputs, max_size=cfg.common.all_gather_list_size, @@ -132,9 +138,13 @@ def cli_main(): # only override args that are explicitly given on the command line override_parser = options.get_validation_parser() - override_args = options.parse_args_and_arch(override_parser, suppress_defaults=True) + override_args = options.parse_args_and_arch( + override_parser, suppress_defaults=True + ) - distributed_utils.call_main(convert_namespace_to_omegaconf(args), main, override_args=override_args) + distributed_utils.call_main( + convert_namespace_to_omegaconf(args), main, override_args=override_args + ) if __name__ == "__main__": From e0788f7007a8473a76db573985031f3c94201e79 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 17 Feb 2021 10:54:25 -0800 Subject: [PATCH 220/774] fix bart generation bug (#1629) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1629 Reviewed By: myleott Differential Revision: D26484942 Pulled By: sshleifer fbshipit-source-id: 9dcbab5c404c14d8f35628d823102ad9ce59dffd --- fairseq/models/bart/hub_interface.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/fairseq/models/bart/hub_interface.py b/fairseq/models/bart/hub_interface.py index 1ff170a782..2ddeb763a3 100644 --- a/fairseq/models/bart/hub_interface.py +++ b/fairseq/models/bart/hub_interface.py @@ -92,22 +92,27 @@ def generate( tokenized_sentences: List[torch.LongTensor], *args, inference_step_args=None, + skip_invalid_size_inputs=False, **kwargs ) -> List[List[Dict[str, torch.Tensor]]]: inference_step_args = inference_step_args or {} if "prefix_tokens" in inference_step_args: raise NotImplementedError("prefix generation not implemented for BART") - else: - bsz = len(tokenized_sentences) - inference_step_args["prefix_tokens"] = tokenized_sentences[0].new_full( - (bsz, 1), fill_value=self.task.source_dictionary.bos() + res = [] + for batch in self._build_batches(tokenized_sentences, skip_invalid_size_inputs): + src_tokens = batch['net_input']['src_tokens'] + inference_step_args["prefix_tokens"] =src_tokens.new_full( + (src_tokens.size(0), 1), fill_value=self.task.source_dictionary.bos() ).to(device=self.device) - return super().generate( - tokenized_sentences, - *args, - inference_step_args=inference_step_args, - **kwargs - ) + results = super().generate( + src_tokens, + *args, + inference_step_args=inference_step_args, + skip_invalid_size_inputs=skip_invalid_size_inputs, + **kwargs + ) + res.extend(results) + return res def extract_features( self, tokens: torch.LongTensor, return_all_hiddens: bool = False From 7040ce71f3e0e84730adc267df764f48dc483dac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20=C3=87elebi?= <celebio@fb.com> Date: Thu, 18 Feb 2021 03:09:14 -0800 Subject: [PATCH 221/774] LASER training code (#1207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Integrating LASER (Language-Agnostic SEntence Representations) training code - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ Y] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ N/A] Did you make sure to update the docs? - [ Y] Did you write any new necessary tests? => an additional test in `test_iterators.py` ## What does this PR do? This diff introduces the training code for LASER. It includes a specific `laser` task in `laser_task.py` which reads a json configuration file describing the binarized datasets of language pairs. `multitask_data_utils.py` defines dataset wrappers and iterators used by `laser` task. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Yes. � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1207 Reviewed By: myleott Differential Revision: D26454296 Pulled By: Celebio fbshipit-source-id: c987672aa66abf31b039ee11867b06912d3486e5 --- examples/laser/README.md | 144 +++++ examples/laser/laser_src/__init__.py | 8 + examples/laser/laser_src/laser_lstm.py | 585 ++++++++++++++++++ examples/laser/laser_src/laser_task.py | 326 ++++++++++ examples/laser/laser_src/laser_transformer.py | 354 +++++++++++ .../laser/laser_src/multitask_data_utils.py | 143 +++++ tests/test_binaries.py | 60 ++ tests/utils.py | 38 ++ 8 files changed, 1658 insertions(+) create mode 100644 examples/laser/README.md create mode 100644 examples/laser/laser_src/__init__.py create mode 100644 examples/laser/laser_src/laser_lstm.py create mode 100644 examples/laser/laser_src/laser_task.py create mode 100644 examples/laser/laser_src/laser_transformer.py create mode 100644 examples/laser/laser_src/multitask_data_utils.py diff --git a/examples/laser/README.md b/examples/laser/README.md new file mode 100644 index 0000000000..66acada04f --- /dev/null +++ b/examples/laser/README.md @@ -0,0 +1,144 @@ +# LASER Language-Agnostic SEntence Representations + +LASER is a library to calculate and use multilingual sentence embeddings. + +You can find more information about LASER and how to use it on the official [LASER repository](https://github.com/facebookresearch/LASER). + +This folder contains source code for training LASER embeddings. + + +## Prepare data and configuration file + +Binarize your data with fairseq, as described [here](https://fairseq.readthedocs.io/en/latest/getting_started.html#data-pre-processing). + +Create a json config file with this format: +``` +{ + "src_vocab": "/path/to/spm.src.cvocab", + "tgt_vocab": "/path/to/spm.tgt.cvocab", + "train": [ + { + "type": "translation", + "id": 0, + "src": "/path/to/srclang1-tgtlang0/train.srclang1", + "tgt": "/path/to/srclang1-tgtlang0/train.tgtlang0" + }, + { + "type": "translation", + "id": 1, + "src": "/path/to/srclang1-tgtlang1/train.srclang1", + "tgt": "/path/to/srclang1-tgtlang1/train.tgtlang1" + }, + { + "type": "translation", + "id": 0, + "src": "/path/to/srclang2-tgtlang0/train.srclang2", + "tgt": "/path/to/srclang2-tgtlang0/train.tgtlang0" + }, + { + "type": "translation", + "id": 1, + "src": "/path/to/srclang2-tgtlang1/train.srclang2", + "tgt": "/path/to/srclang2-tgtlang1/train.tgtlang1" + }, + ... + ], + "valid": [ + { + "type": "translation", + "id": 0, + "src": "/unused", + "tgt": "/unused" + } + ] +} +``` +where paths are paths to binarized indexed fairseq dataset files. +`id` represents the target language id. + + +## Training Command Line Example + +``` +fairseq-train \ + /path/to/configfile_described_above.json \ + --user-dir examples/laser/laser_src \ + --log-interval 100 --log-format simple \ + --task laser --arch laser_lstm \ + --save-dir . \ + --optimizer adam \ + --lr 0.001 \ + --lr-scheduler inverse_sqrt \ + --clip-norm 5 \ + --warmup-updates 90000 \ + --update-freq 2 \ + --dropout 0.0 \ + --encoder-dropout-out 0.1 \ + --max-tokens 2000 \ + --max-epoch 50 \ + --encoder-bidirectional \ + --encoder-layers 5 \ + --encoder-hidden-size 512 \ + --decoder-layers 1 \ + --decoder-hidden-size 2048 \ + --encoder-embed-dim 320 \ + --decoder-embed-dim 320 \ + --decoder-lang-embed-dim 32 \ + --warmup-init-lr 0.001 \ + --disable-validation +``` + + +## Applications + +We showcase several applications of multilingual sentence embeddings +with code to reproduce our results (in the directory "tasks"). + +* [**Cross-lingual document classification**](https://github.com/facebookresearch/LASER/tree/master/tasks/mldoc) using the + [*MLDoc*](https://github.com/facebookresearch/MLDoc) corpus [2,6] +* [**WikiMatrix**](https://github.com/facebookresearch/LASER/tree/master/tasks/WikiMatrix) + Mining 135M Parallel Sentences in 1620 Language Pairs from Wikipedia [7] +* [**Bitext mining**](https://github.com/facebookresearch/LASER/tree/master/tasks/bucc) using the + [*BUCC*](https://comparable.limsi.fr/bucc2018/bucc2018-task.html) corpus [3,5] +* [**Cross-lingual NLI**](https://github.com/facebookresearch/LASER/tree/master/tasks/xnli) + using the [*XNLI*](https://www.nyu.edu/projects/bowman/xnli/) corpus [4,5,6] +* [**Multilingual similarity search**](https://github.com/facebookresearch/LASER/tree/master/tasks/similarity) [1,6] +* [**Sentence embedding of text files**](https://github.com/facebookresearch/LASER/tree/master/tasks/embed) + example how to calculate sentence embeddings for arbitrary text files in any of the supported language. + +**For all tasks, we use exactly the same multilingual encoder, without any task specific optimization or fine-tuning.** + + + +## References + +[1] Holger Schwenk and Matthijs Douze, + [*Learning Joint Multilingual Sentence Representations with Neural Machine Translation*](https://aclanthology.info/papers/W17-2619/w17-2619), + ACL workshop on Representation Learning for NLP, 2017 + +[2] Holger Schwenk and Xian Li, + [*A Corpus for Multilingual Document Classification in Eight Languages*](http://www.lrec-conf.org/proceedings/lrec2018/pdf/658.pdf), + LREC, pages 3548-3551, 2018. + +[3] Holger Schwenk, + [*Filtering and Mining Parallel Data in a Joint Multilingual Space*](http://aclweb.org/anthology/P18-2037) + ACL, July 2018 + +[4] Alexis Conneau, Guillaume Lample, Ruty Rinott, Adina Williams, Samuel R. Bowman, Holger Schwenk and Veselin Stoyanov, + [*XNLI: Cross-lingual Sentence Understanding through Inference*](https://aclweb.org/anthology/D18-1269), + EMNLP, 2018. + +[5] Mikel Artetxe and Holger Schwenk, + [*Margin-based Parallel Corpus Mining with Multilingual Sentence Embeddings*](https://arxiv.org/abs/1811.01136) + arXiv, Nov 3 2018. + +[6] Mikel Artetxe and Holger Schwenk, + [*Massively Multilingual Sentence Embeddings for Zero-Shot Cross-Lingual Transfer and Beyond*](https://arxiv.org/abs/1812.10464) + arXiv, Dec 26 2018. + +[7] Holger Schwenk, Vishrav Chaudhary, Shuo Sun, Hongyu Gong and Paco Guzman, + [*WikiMatrix: Mining 135M Parallel Sentences in 1620 Language Pairs from Wikipedia*](https://arxiv.org/abs/1907.05791) + arXiv, July 11 2019. + +[8] Holger Schwenk, Guillaume Wenzek, Sergey Edunov, Edouard Grave and Armand Joulin + [*CCMatrix: Mining Billions of High-Quality Parallel Sentences on the WEB*](https://arxiv.org/abs/1911.04944) diff --git a/examples/laser/laser_src/__init__.py b/examples/laser/laser_src/__init__.py new file mode 100644 index 0000000000..9ffbd656d8 --- /dev/null +++ b/examples/laser/laser_src/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .laser_task import * # noqa +from .laser_lstm import * # noqa +from .laser_transformer import * # noqa diff --git a/examples/laser/laser_src/laser_lstm.py b/examples/laser/laser_src/laser_lstm.py new file mode 100644 index 0000000000..10df90e002 --- /dev/null +++ b/examples/laser/laser_src/laser_lstm.py @@ -0,0 +1,585 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from fairseq import options, utils + +from fairseq.models import ( + FairseqEncoder, + FairseqIncrementalDecoder, + FairseqEncoderDecoderModel, + register_model, + register_model_architecture, +) + + +@register_model("laser_lstm") +class LSTMModel(FairseqEncoderDecoderModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens=None, + tgt_tokens=None, + tgt_lengths=None, + target_language_id=None, + dataset_name="", + ): + assert target_language_id is not None + + src_encoder_out = self.encoder(src_tokens, src_lengths, dataset_name) + return self.decoder( + prev_output_tokens, src_encoder_out, lang_id=target_language_id + ) + + @staticmethod + def add_args(parser): + """Add model-specific arguments to the parser.""" + parser.add_argument( + "--dropout", + default=0.1, + type=float, + metavar="D", + help="dropout probability", + ) + parser.add_argument( + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension", + ) + parser.add_argument( + "--encoder-embed-path", + default=None, + type=str, + metavar="STR", + help="path to pre-trained encoder embedding", + ) + parser.add_argument( + "--encoder-hidden-size", type=int, metavar="N", help="encoder hidden size" + ) + parser.add_argument( + "--encoder-layers", type=int, metavar="N", help="number of encoder layers" + ) + parser.add_argument( + "--encoder-bidirectional", + action="store_true", + help="make all layers of encoder bidirectional", + ) + parser.add_argument( + "--decoder-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension", + ) + parser.add_argument( + "--decoder-embed-path", + default=None, + type=str, + metavar="STR", + help="path to pre-trained decoder embedding", + ) + parser.add_argument( + "--decoder-hidden-size", type=int, metavar="N", help="decoder hidden size" + ) + parser.add_argument( + "--decoder-layers", type=int, metavar="N", help="number of decoder layers" + ) + parser.add_argument( + "--decoder-out-embed-dim", + type=int, + metavar="N", + help="decoder output embedding dimension", + ) + parser.add_argument( + "--decoder-zero-init", + type=str, + metavar="BOOL", + help="initialize the decoder hidden/cell state to zero", + ) + parser.add_argument( + "--decoder-lang-embed-dim", + type=int, + metavar="N", + help="decoder language embedding dimension", + ) + parser.add_argument( + "--fixed-embeddings", + action="store_true", + help="keep embeddings fixed (ENCODER ONLY)", + ) # TODO Also apply to decoder embeddings? + + # Granular dropout settings (if not specified these default to --dropout) + parser.add_argument( + "--encoder-dropout-in", + type=float, + metavar="D", + help="dropout probability for encoder input embedding", + ) + parser.add_argument( + "--encoder-dropout-out", + type=float, + metavar="D", + help="dropout probability for encoder output", + ) + parser.add_argument( + "--decoder-dropout-in", + type=float, + metavar="D", + help="dropout probability for decoder input embedding", + ) + parser.add_argument( + "--decoder-dropout-out", + type=float, + metavar="D", + help="dropout probability for decoder output", + ) + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + # make sure that all args are properly defaulted (in case there are any new ones) + base_architecture(args) + + def load_pretrained_embedding_from_file(embed_path, dictionary, embed_dim): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + embed_tokens = Embedding(num_embeddings, embed_dim, padding_idx) + embed_dict = utils.parse_embedding(embed_path) + utils.print_embed_overlap(embed_dict, dictionary) + return utils.load_embedding(embed_dict, dictionary, embed_tokens) + + pretrained_encoder_embed = None + if args.encoder_embed_path: + pretrained_encoder_embed = load_pretrained_embedding_from_file( + args.encoder_embed_path, task.source_dictionary, args.encoder_embed_dim + ) + pretrained_decoder_embed = None + if args.decoder_embed_path: + pretrained_decoder_embed = load_pretrained_embedding_from_file( + args.decoder_embed_path, task.target_dictionary, args.decoder_embed_dim + ) + + num_langs = task.num_tasks if hasattr(task, "num_tasks") else 0 + + encoder = LSTMEncoder( + dictionary=task.source_dictionary, + embed_dim=args.encoder_embed_dim, + hidden_size=args.encoder_hidden_size, + num_layers=args.encoder_layers, + dropout_in=args.encoder_dropout_in, + dropout_out=args.encoder_dropout_out, + bidirectional=args.encoder_bidirectional, + pretrained_embed=pretrained_encoder_embed, + fixed_embeddings=args.fixed_embeddings, + ) + decoder = LSTMDecoder( + dictionary=task.target_dictionary, + embed_dim=args.decoder_embed_dim, + hidden_size=args.decoder_hidden_size, + out_embed_dim=args.decoder_out_embed_dim, + num_layers=args.decoder_layers, + dropout_in=args.decoder_dropout_in, + dropout_out=args.decoder_dropout_out, + zero_init=options.eval_bool(args.decoder_zero_init), + encoder_embed_dim=args.encoder_embed_dim, + encoder_output_units=encoder.output_units, + pretrained_embed=pretrained_decoder_embed, + num_langs=num_langs, + lang_embed_dim=args.decoder_lang_embed_dim, + ) + return cls(encoder, decoder) + + +class LSTMEncoder(FairseqEncoder): + """LSTM encoder.""" + + def __init__( + self, + dictionary, + embed_dim=512, + hidden_size=512, + num_layers=1, + dropout_in=0.1, + dropout_out=0.1, + bidirectional=False, + left_pad=True, + pretrained_embed=None, + padding_value=0.0, + fixed_embeddings=False, + ): + super().__init__(dictionary) + self.num_layers = num_layers + self.dropout_in = dropout_in + self.dropout_out = dropout_out + self.bidirectional = bidirectional + self.hidden_size = hidden_size + + num_embeddings = len(dictionary) + self.padding_idx = dictionary.pad() + if pretrained_embed is None: + self.embed_tokens = Embedding(num_embeddings, embed_dim, self.padding_idx) + else: + self.embed_tokens = pretrained_embed + if fixed_embeddings: + self.embed_tokens.weight.requires_grad = False + + self.lstm = LSTM( + input_size=embed_dim, + hidden_size=hidden_size, + num_layers=num_layers, + dropout=self.dropout_out if num_layers > 1 else 0.0, + bidirectional=bidirectional, + ) + self.left_pad = left_pad + self.padding_value = padding_value + + self.output_units = hidden_size + if bidirectional: + self.output_units *= 2 + + def forward(self, src_tokens, src_lengths, dataset_name): + if self.left_pad: + # convert left-padding to right-padding + src_tokens = utils.convert_padding_direction( + src_tokens, + self.padding_idx, + left_to_right=True, + ) + + bsz, seqlen = src_tokens.size() + + # embed tokens + x = self.embed_tokens(src_tokens) + x = F.dropout(x, p=self.dropout_in, training=self.training) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + # pack embedded source tokens into a PackedSequence + try: + packed_x = nn.utils.rnn.pack_padded_sequence(x, src_lengths.data.tolist()) + except BaseException: + raise Exception(f"Packing failed in dataset {dataset_name}") + + # apply LSTM + if self.bidirectional: + state_size = 2 * self.num_layers, bsz, self.hidden_size + else: + state_size = self.num_layers, bsz, self.hidden_size + h0 = x.data.new(*state_size).zero_() + c0 = x.data.new(*state_size).zero_() + packed_outs, (final_hiddens, final_cells) = self.lstm(packed_x, (h0, c0)) + + # unpack outputs and apply dropout + x, _ = nn.utils.rnn.pad_packed_sequence( + packed_outs, padding_value=self.padding_value + ) + x = F.dropout(x, p=self.dropout_out, training=self.training) + assert list(x.size()) == [seqlen, bsz, self.output_units] + + if self.bidirectional: + + def combine_bidir(outs): + return torch.cat( + [ + torch.cat([outs[2 * i], outs[2 * i + 1]], dim=0).view( + 1, bsz, self.output_units + ) + for i in range(self.num_layers) + ], + dim=0, + ) + + final_hiddens = combine_bidir(final_hiddens) + final_cells = combine_bidir(final_cells) + + encoder_padding_mask = src_tokens.eq(self.padding_idx).t() + + # Set padded outputs to -inf so they are not selected by max-pooling + padding_mask = src_tokens.eq(self.padding_idx).t().unsqueeze(-1) + if padding_mask.any(): + x = x.float().masked_fill_(padding_mask, float("-inf")).type_as(x) + + # Build the sentence embedding by max-pooling over the encoder outputs + sentemb = x.max(dim=0)[0] + + return { + "sentemb": sentemb, + "encoder_out": (x, final_hiddens, final_cells), + "encoder_padding_mask": encoder_padding_mask + if encoder_padding_mask.any() + else None, + } + + def reorder_encoder_out(self, encoder_out_dict, new_order): + encoder_out_dict["sentemb"] = encoder_out_dict["sentemb"].index_select( + 0, new_order + ) + encoder_out_dict["encoder_out"] = tuple( + eo.index_select(1, new_order) for eo in encoder_out_dict["encoder_out"] + ) + if encoder_out_dict["encoder_padding_mask"] is not None: + encoder_out_dict["encoder_padding_mask"] = encoder_out_dict[ + "encoder_padding_mask" + ].index_select(1, new_order) + return encoder_out_dict + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return int(1e5) # an arbitrary large number + + +class LSTMDecoder(FairseqIncrementalDecoder): + """LSTM decoder.""" + + def __init__( + self, + dictionary, + embed_dim=512, + hidden_size=512, + out_embed_dim=512, + num_layers=1, + dropout_in=0.1, + dropout_out=0.1, + zero_init=False, + encoder_embed_dim=512, + encoder_output_units=512, + pretrained_embed=None, + num_langs=1, + lang_embed_dim=0, + ): + super().__init__(dictionary) + self.dropout_in = dropout_in + self.dropout_out = dropout_out + self.hidden_size = hidden_size + + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + if pretrained_embed is None: + self.embed_tokens = Embedding(num_embeddings, embed_dim, padding_idx) + else: + self.embed_tokens = pretrained_embed + + self.layers = nn.ModuleList( + [ + LSTMCell( + input_size=encoder_output_units + embed_dim + lang_embed_dim + if layer == 0 + else hidden_size, + hidden_size=hidden_size, + ) + for layer in range(num_layers) + ] + ) + if hidden_size != out_embed_dim: + self.additional_fc = Linear(hidden_size, out_embed_dim) + self.fc_out = Linear(out_embed_dim, num_embeddings, dropout=dropout_out) + + if zero_init: + self.sentemb2init = None + else: + self.sentemb2init = Linear( + encoder_output_units, 2 * num_layers * hidden_size + ) + + if lang_embed_dim == 0: + self.embed_lang = None + else: + self.embed_lang = nn.Embedding(num_langs, lang_embed_dim) + nn.init.uniform_(self.embed_lang.weight, -0.1, 0.1) + + def forward( + self, prev_output_tokens, encoder_out_dict, incremental_state=None, lang_id=0 + ): + sentemb = encoder_out_dict["sentemb"] + encoder_out = encoder_out_dict["encoder_out"] + + if incremental_state is not None: + prev_output_tokens = prev_output_tokens[:, -1:] + bsz, seqlen = prev_output_tokens.size() + + # get outputs from encoder + encoder_outs, _, _ = encoder_out[:3] + srclen = encoder_outs.size(0) + + # embed tokens + x = self.embed_tokens(prev_output_tokens) + x = F.dropout(x, p=self.dropout_in, training=self.training) + + # embed language identifier + if self.embed_lang is not None: + lang_ids = prev_output_tokens.data.new_full((bsz,), lang_id) + langemb = self.embed_lang(lang_ids) + # TODO Should we dropout here??? + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + # initialize previous states (or get from cache during incremental generation) + cached_state = utils.get_incremental_state( + self, incremental_state, "cached_state" + ) + if cached_state is not None: + prev_hiddens, prev_cells, input_feed = cached_state + else: + num_layers = len(self.layers) + if self.sentemb2init is None: + prev_hiddens = [ + x.data.new(bsz, self.hidden_size).zero_() for i in range(num_layers) + ] + prev_cells = [ + x.data.new(bsz, self.hidden_size).zero_() for i in range(num_layers) + ] + else: + init = self.sentemb2init(sentemb) + prev_hiddens = [ + init[:, (2 * i) * self.hidden_size : (2 * i + 1) * self.hidden_size] + for i in range(num_layers) + ] + prev_cells = [ + init[ + :, + (2 * i + 1) * self.hidden_size : (2 * i + 2) * self.hidden_size, + ] + for i in range(num_layers) + ] + input_feed = x.data.new(bsz, self.hidden_size).zero_() + + attn_scores = x.data.new(srclen, seqlen, bsz).zero_() + outs = [] + for j in range(seqlen): + if self.embed_lang is None: + input = torch.cat((x[j, :, :], sentemb), dim=1) + else: + input = torch.cat((x[j, :, :], sentemb, langemb), dim=1) + + for i, rnn in enumerate(self.layers): + # recurrent cell + hidden, cell = rnn(input, (prev_hiddens[i], prev_cells[i])) + + # hidden state becomes the input to the next layer + input = F.dropout(hidden, p=self.dropout_out, training=self.training) + + # save state for next time step + prev_hiddens[i] = hidden + prev_cells[i] = cell + + out = hidden + out = F.dropout(out, p=self.dropout_out, training=self.training) + + # input feeding + input_feed = out + + # save final output + outs.append(out) + + # cache previous states (no-op except during incremental generation) + utils.set_incremental_state( + self, + incremental_state, + "cached_state", + (prev_hiddens, prev_cells, input_feed), + ) + + # collect outputs across time steps + x = torch.cat(outs, dim=0).view(seqlen, bsz, self.hidden_size) + + # T x B x C -> B x T x C + x = x.transpose(1, 0) + + # srclen x tgtlen x bsz -> bsz x tgtlen x srclen + attn_scores = attn_scores.transpose(0, 2) + + # project back to size of vocabulary + if hasattr(self, "additional_fc"): + x = self.additional_fc(x) + x = F.dropout(x, p=self.dropout_out, training=self.training) + x = self.fc_out(x) + + return x, attn_scores + + def reorder_incremental_state(self, incremental_state, new_order): + super().reorder_incremental_state(incremental_state, new_order) + cached_state = utils.get_incremental_state( + self, incremental_state, "cached_state" + ) + if cached_state is None: + return + + def reorder_state(state): + if isinstance(state, list): + return [reorder_state(state_i) for state_i in state] + return state.index_select(0, new_order) + + new_state = tuple(map(reorder_state, cached_state)) + utils.set_incremental_state(self, incremental_state, "cached_state", new_state) + + def max_positions(self): + """Maximum output length supported by the decoder.""" + return int(1e5) # an arbitrary large number + + +def Embedding(num_embeddings, embedding_dim, padding_idx): + m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) + nn.init.uniform_(m.weight, -0.1, 0.1) + nn.init.constant_(m.weight[padding_idx], 0) + return m + + +def LSTM(input_size, hidden_size, **kwargs): + m = nn.LSTM(input_size, hidden_size, **kwargs) + for name, param in m.named_parameters(): + if "weight" in name or "bias" in name: + param.data.uniform_(-0.1, 0.1) + return m + + +def LSTMCell(input_size, hidden_size, **kwargs): + m = nn.LSTMCell(input_size, hidden_size, **kwargs) + for name, param in m.named_parameters(): + if "weight" in name or "bias" in name: + param.data.uniform_(-0.1, 0.1) + return m + + +def Linear(in_features, out_features, bias=True, dropout=0): + """Weight-normalized Linear layer (input: N x T x C)""" + m = nn.Linear(in_features, out_features, bias=bias) + m.weight.data.uniform_(-0.1, 0.1) + if bias: + m.bias.data.uniform_(-0.1, 0.1) + return m + + +@register_model_architecture("laser_lstm", "laser_lstm") +def base_architecture(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_embed_path = getattr(args, "encoder_embed_path", None) + args.encoder_hidden_size = getattr( + args, "encoder_hidden_size", args.encoder_embed_dim + ) + args.encoder_layers = getattr(args, "encoder_layers", 1) + args.encoder_bidirectional = getattr(args, "encoder_bidirectional", False) + args.encoder_dropout_in = getattr(args, "encoder_dropout_in", args.dropout) + args.encoder_dropout_out = getattr(args, "encoder_dropout_out", args.dropout) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) + args.decoder_embed_path = getattr(args, "decoder_embed_path", None) + args.decoder_hidden_size = getattr( + args, "decoder_hidden_size", args.decoder_embed_dim + ) + args.decoder_layers = getattr(args, "decoder_layers", 1) + args.decoder_out_embed_dim = getattr(args, "decoder_out_embed_dim", 512) + args.decoder_dropout_in = getattr(args, "decoder_dropout_in", args.dropout) + args.decoder_dropout_out = getattr(args, "decoder_dropout_out", args.dropout) + args.decoder_zero_init = getattr(args, "decoder_zero_init", "0") + args.decoder_lang_embed_dim = getattr(args, "decoder_lang_embed_dim", 0) + args.fixed_embeddings = getattr(args, "fixed_embeddings", False) diff --git a/examples/laser/laser_src/laser_task.py b/examples/laser/laser_src/laser_task.py new file mode 100644 index 0000000000..c8ac805f54 --- /dev/null +++ b/examples/laser/laser_src/laser_task.py @@ -0,0 +1,326 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +from collections import OrderedDict, defaultdict +import json +import os +import logging + +from fairseq import options, models +from fairseq.data import ( + data_utils, + Dictionary, + LanguagePairDataset, + IndexedDataset, + FairseqDataset, +) +from .multitask_data_utils import ( + MultitaskDatasetWrapper, + MultidatasetEpochBatchIterator, +) + + +from fairseq.tasks import LegacyFairseqTask, register_task + +logger = logging.getLogger(__name__) + + +@register_task("laser") +class LaserTask(LegacyFairseqTask): + @staticmethod + def add_args(parser): + """Add task-specific arguments to the parser.""" + parser.add_argument( + "configfile", metavar="PATH", help="dataset configuration file in json" + ) + parser.add_argument( + "--weighting-alpha", + type=float, + default=None, + help="alpha for automatic weighting", + ) + parser.add_argument( + "--raw-text", action="store_true", help="load raw text dataset" + ) + parser.add_argument( + "--left-pad-source", + default="True", + type=str, + metavar="BOOL", + help="pad the source on the left (default: True)", + ) + parser.add_argument( + "--left-pad-target", + default="False", + type=str, + metavar="BOOL", + help="pad the target on the left (default: False)", + ) + parser.add_argument( + "--max-source-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the source sequence", + ) + parser.add_argument( + "--max-target-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the target sequence", + ) + + def __init__(self, args, config, src_dictionary, tgt_dictionary, num_tasks): + super().__init__(args) + self.config = config + self.src_dictionary = src_dictionary + self.tgt_dictionary = tgt_dictionary + self.num_tasks = num_tasks + + @classmethod + def setup_task(cls, args, **kwargs): + with open(args.configfile, "r") as f: + config = json.load(f) + num_tasks = max(dataset["id"] for dataset in config["train"]) + 1 + + args.left_pad_source = options.eval_bool(args.left_pad_source) + args.left_pad_target = options.eval_bool(args.left_pad_target) + + src_dictionary = Dictionary.load(config["src_vocab"]) + tgt_dictionary = Dictionary.load(config["tgt_vocab"]) + + logger.info( + "| src Dictionary {} : {} types".format( + config["src_vocab"], len(src_dictionary) + ) + ) + logger.info( + "| tgt Dictionary {} : {} types".format( + config["tgt_vocab"], len(tgt_dictionary) + ) + ) + + return cls(args, config, src_dictionary, tgt_dictionary, num_tasks) + + # Experimental overriding for backtranslation + def build_model(self, args): + model = models.build_model(args, self) + return model + + def dataset(self, split): + if split not in self.datasets: + raise KeyError("Dataset not loaded: " + split) + return self.datasets[split] + + def load_dataset(self, split, epoch=1, **kwargs): + """Load a dataset split.""" + + def indexed_dataset(path, dictionary): + if self.args.raw_text: + raise Exception("Unable to handle raw text.") + dataset = IndexedDataset(path, fix_lua_indexing=True) + + return dataset + + pair_datasets = OrderedDict() + + if split == "valid": + self.datasets[split] = pair_datasets + return + + if split not in self.config: + raise FileNotFoundError( + "Dataset not found in config file: {}".format(split) + ) + + size_by_corpus = defaultdict(int) + size_sum = 0 + size_sum_with_subsampling = 0 + init_pair_datasets = {} + + for dataset_config in self.config[split]: + src_path = os.path.dirname(dataset_config["src"]) + corpus_name = src_path.split("/")[-2] + language_pair_name = src_path.split("/")[-1] + pair_datasets_key = corpus_name + "-" + language_pair_name + + logger.info(f"loading... {pair_datasets_key}") + if "src" in dataset_config: + src_dataset = indexed_dataset( + dataset_config["src"], self.src_dictionary + ) + else: + src_dataset = None + + if "tgt" in dataset_config: + tgt_dataset = indexed_dataset( + dataset_config["tgt"], self.tgt_dictionary + ) + else: + tgt_dataset = None + + dataset = LanguagePairDataset( + src_dataset, + src_dataset.sizes, + self.src_dictionary, + tgt_dataset, + tgt_dataset.sizes, + self.tgt_dictionary, + left_pad_source=self.args.left_pad_source, + left_pad_target=self.args.left_pad_target, + ) + + if pair_datasets_key in init_pair_datasets: + logger.warning( + f"Ignoring already added {pair_datasets_key}. " + f"Consider using `sample` key in order to upsample." + ) + else: + init_pair_datasets[pair_datasets_key] = { + "dataset": dataset, + "sample": dataset_config.get("sample", None), + "id": dataset_config.get("id", None), + "len": len(dataset), + } + + length_sum = 0 + weighted_freqs_sum = 0 + freq_per_dataset = {} + vmax = 0 + vmin = 1 + weighted_freq_per_dataset = {} + + if self.args.weighting_alpha: + for key in init_pair_datasets: + if init_pair_datasets[key]["sample"] is None: + length_sum += len(init_pair_datasets[key]["dataset"]) + + for key in init_pair_datasets: + if init_pair_datasets[key]["sample"] is None: + val = float(init_pair_datasets[key]["len"]) / length_sum + freq_per_dataset[key] = val + weighted_freqs_sum += val ** self.args.weighting_alpha + + for key in freq_per_dataset: + val = ( + freq_per_dataset[key] ** self.args.weighting_alpha + / weighted_freqs_sum + ) + vmin = min(vmin, val) + vmax = max(vmax, val) + weighted_freq_per_dataset[key] = val + + for pair_datasets_key in init_pair_datasets: + dataset_config = init_pair_datasets[pair_datasets_key] + dataset = dataset_config["dataset"] + sample = dataset_config["sample"] + if sample is None: + sample = 1.0 + + if pair_datasets_key in weighted_freq_per_dataset: + w = vmax / weighted_freq_per_dataset[pair_datasets_key] + sample = w + + sample = round(sample) + + initial_sample = sample + initial_pair_datasets_key = pair_datasets_key + + while sample >= 1.0: + assert ( + pair_datasets_key not in pair_datasets + ), f"{pair_datasets_key} already in" + size_sum_with_subsampling += len(dataset) + pair_datasets[pair_datasets_key] = MultitaskDatasetWrapper( + dataset, dataset_config.get("id", 0), 1.0, name=pair_datasets_key + ) + size_sum += len(dataset) + sample -= 1.0 + pair_datasets_key += "-up" + + assert sample < 1e-6, f"sample remains > 0 {pair_datasets_key}" + + logger.info( + f"added pair {initial_pair_datasets_key} length {len(dataset)} new_length = {len(dataset)*initial_sample}" + ) + size_by_corpus[corpus_name] += len(dataset) + + self.datasets[split] = pair_datasets + logger.info( + f"Datasets number = {len(self.datasets[split])} size = {size_sum} size_sum_with_subsampling = {size_sum_with_subsampling}" + ) + + @property + def source_dictionary(self): + return self.src_dictionary + + @property + def target_dictionary(self): + return self.tgt_dictionary + + def get_batch_iterator( + self, + dataset, + max_tokens=None, + max_sentences=None, + max_positions=None, + ignore_invalid_inputs=False, + required_batch_size_multiple=1, + seed=1, + num_shards=1, + shard_id=0, + num_workers=0, + epoch=1, + data_buffer_size=0, + disable_iterator_cache=False, + ): + + assert isinstance(dataset, OrderedDict) + assert len(dataset) + assert isinstance(dataset[next(iter(dataset))], FairseqDataset) + + # initialize the dataset with the correct starting epoch + for _, dt in dataset.items(): + dt.set_epoch(epoch) + + indices = OrderedDict() + batch_sampler = OrderedDict() + + with data_utils.numpy_seed(seed + epoch): + for key, dt in dataset.items(): + logger.info(f"\t ordered_indices {key}") + indices[key] = dt.ordered_indices() + + # filter examples that are too large + if max_positions is not None: + for key, dt in dataset.items(): + logger.info(f"\t filter_by_size {key}") + indices[key], ignored = dt.filter_indices_by_size( + indices[key], max_positions + ) + + for key, dt in dataset.items(): + logger.info(f"\t batch_by_size {key}") + batch_sampler[key] = data_utils.batch_by_size( + indices[key], + dt.num_tokens, + max_tokens=max_tokens, + max_sentences=max_sentences, + required_batch_size_multiple=required_batch_size_multiple, + ) + + epoch_iter = MultidatasetEpochBatchIterator( + dataset=dataset, + batch_sampler=batch_sampler, + seed=seed, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + epoch=epoch, + ) + + return epoch_iter diff --git a/examples/laser/laser_src/laser_transformer.py b/examples/laser/laser_src/laser_transformer.py new file mode 100644 index 0000000000..0be030994f --- /dev/null +++ b/examples/laser/laser_src/laser_transformer.py @@ -0,0 +1,354 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +from typing import Any, Dict, List, Optional +from torch import Tensor + +import torch +import torch.nn as nn + +from fairseq.models import ( + FairseqEncoderDecoderModel, + register_model, + register_model_architecture, +) +from fairseq.models.transformer import ( + base_architecture, + Embedding, + TransformerModel, + TransformerEncoder, + TransformerDecoder, +) +from fairseq.modules import ( + TransformerDecoderLayer, +) + +logger = logging.getLogger(__name__) + + +@register_model("laser_transformer") +class LaserTransformerModel(FairseqEncoderDecoderModel): + """Train Transformer for LASER task + + Requires --task laser + """ + + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens=None, + tgt_tokens=None, + tgt_lengths=None, + target_language_id=-1, + dataset_name="", + ): + laser_encoder_out = self.encoder(src_tokens, src_lengths) + return self.decoder( + prev_output_tokens, laser_encoder_out, lang_id=target_language_id + ) + + @staticmethod + def add_args(parser): + """Add model-specific arguments to the parser.""" + TransformerModel.add_args(parser) + parser.add_argument( + "--decoder-lang-embed-dim", + type=int, + metavar="N", + help="decoder language embedding dimension", + ) + + @classmethod + def build_model(cls, args, task): + base_laser_transformer_architecture(args) + + num_langs = task.num_tasks if hasattr(task, "num_tasks") else 0 + + def load_embed_tokens(dictionary, embed_dim): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + + return Embedding(num_embeddings, embed_dim, padding_idx) + + encoder_embed_tokens = load_embed_tokens( + task.source_dictionary, args.encoder_embed_dim + ) + decoder_embed_tokens = load_embed_tokens( + task.target_dictionary, args.decoder_embed_dim + ) + num_langs = task.num_tasks if hasattr(task, "num_tasks") else 0 + + encoder = LaserTransformerEncoder( + args, task.source_dictionary, encoder_embed_tokens + ) + + decoder = LaserTransformerDecoder( + args, + task.target_dictionary, + decoder_embed_tokens, + num_langs=num_langs, + lang_embed_dim=args.decoder_lang_embed_dim, + ) + + return cls(encoder, decoder) + + +class LaserTransformerEncoder(TransformerEncoder): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def forward(self, src_tokens, *args, **kwargs): + encoder_out = super().forward(src_tokens, *args, **kwargs) + + x = encoder_out["encoder_out"][0] # T x B x C + padding_mask = src_tokens.eq(self.padding_idx).t().unsqueeze(-1) + + if padding_mask.any(): + x = x.float().masked_fill_(padding_mask, float("-inf")).type_as(x) + + # Build the sentence embedding by max-pooling over the encoder outputs + sentemb = x.max(dim=0)[0] + + # The Pytorch Mobile lite interpreter does not supports returning NamedTuple in + # `foward` so we use a dictionary instead. + # TorchScript does not support mixed values so the values are all lists. + # The empty list is equivalent to None. + return {"sentemb": [sentemb]} # B x C + + @torch.jit.export + def reorder_encoder_out(self, encoder_out: Dict[str, List[Tensor]], new_order): + """ + Same as the one in transformer.py, with new_sentemb + """ + if len(encoder_out["sentemb"]) == 0: + new_sentemb = [] + else: + new_sentemb = [encoder_out["sentemb"][0].index_select(0, new_order)] + + return { + "sentemb": new_sentemb, # B x C + } + + +class LaserTransformerDecoder(TransformerDecoder): + def __init__(self, args, dictionary, *kargs, **kwargs): + self.num_langs = kwargs.get("num_langs", 1) + self.lang_embed_dim = kwargs.get("lang_embed_dim", 0) + kwargs.pop("num_langs", None) + kwargs.pop("lang_embed_dim", None) + + super().__init__(args, dictionary, *kargs, **kwargs, no_encoder_attn=True) + + if self.lang_embed_dim == 0: + self.embed_lang = None + else: + self.embed_lang = nn.Embedding(self.num_langs, self.lang_embed_dim) + nn.init.uniform_(self.embed_lang.weight, -0.1, 0.1) + + if self.output_projection is not None: + laser_output_embed_dim = ( + self.output_embed_dim + self.lang_embed_dim + args.encoder_embed_dim + ) + self.output_projection = nn.Linear( + laser_output_embed_dim, len(dictionary), bias=False + ) + nn.init.normal_( + self.output_projection.weight, + mean=0, + std=laser_output_embed_dim ** -0.5, + ) + + def build_decoder_layer(self, args, no_encoder_attn=False): + decoder_embed_dim = args.decoder_embed_dim + args.decoder_embed_dim = ( + decoder_embed_dim + self.lang_embed_dim + args.encoder_embed_dim + ) + res = TransformerDecoderLayer(args, no_encoder_attn=True) + args.decoder_embed_dim = decoder_embed_dim + + return res + + def extract_features( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + lang_id: Optional[int] = None, + ): + """ + Similar to *forward* but only return features. + + Includes several features from "Jointly Learning to Align and + Translate with Transformer Models" (Garg et al., EMNLP 2019). + + Args: + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + alignment_layer (int, optional): return mean alignment over + heads at this layer (default: last layer). + alignment_heads (int, optional): only average alignment over + this many heads (default: all heads). + + Returns: + tuple: + - the decoder's features of shape `(batch, tgt_len, embed_dim)` + - a dictionary with any model-specific outputs + """ + if alignment_layer is None: + alignment_layer = self.num_layers - 1 + + # embed positions + positions = ( + self.embed_positions( + prev_output_tokens, incremental_state=incremental_state + ) + if self.embed_positions is not None + else None + ) + + if incremental_state is not None: + prev_output_tokens = prev_output_tokens[:, -1:] + if positions is not None: + positions = positions[:, -1:] + + bsz, seqlen = prev_output_tokens.size() + + # embed tokens and positions + x = self.embed_scale * self.embed_tokens(prev_output_tokens) + + if self.quant_noise is not None: + x = self.quant_noise(x) + + if self.project_in_dim is not None: + x = self.project_in_dim(x) + + if positions is not None: + x += positions + + if self.layernorm_embedding is not None: + x = self.layernorm_embedding(x) + + x = self.dropout_module(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + if self.embed_lang is not None: + lang_ids = prev_output_tokens.data.new_full((bsz,), lang_id) + langemb = self.embed_lang(lang_ids) + langemb = langemb.unsqueeze(0) + repeat_vals = [x.shape[0] // langemb.shape[0]] + [-1] * ( + len(langemb.shape) - 1 + ) + x = torch.cat((x, langemb.expand(*repeat_vals)), dim=-1) + + sentemb = encoder_out["sentemb"][0] + sentemb = sentemb.unsqueeze(0) + + repeat_vals = [x.shape[0] // sentemb.shape[0]] + [-1] * (len(sentemb.shape) - 1) + x = torch.cat((x, sentemb.expand(*repeat_vals)), dim=-1) + + self_attn_padding_mask: Optional[Tensor] = None + if self.cross_self_attention or prev_output_tokens.eq(self.padding_idx).any(): + self_attn_padding_mask = prev_output_tokens.eq(self.padding_idx) + + # decoder layers + attn: Optional[Tensor] = None + inner_states: List[Optional[Tensor]] = [x] + for idx, layer in enumerate(self.layers): + if incremental_state is None and not full_context_alignment: + self_attn_mask = self.buffered_future_mask(x) + else: + self_attn_mask = None + + x, layer_attn, _ = layer( + x, + None, + None, + incremental_state, + self_attn_mask=self_attn_mask, + self_attn_padding_mask=self_attn_padding_mask, + need_attn=bool((idx == alignment_layer)), + need_head_weights=bool((idx == alignment_layer)), + ) + inner_states.append(x) + if layer_attn is not None and idx == alignment_layer: + attn = layer_attn.float().to(x) + + if attn is not None: + if alignment_heads is not None: + attn = attn[:alignment_heads] + + # average probabilities over heads + attn = attn.mean(dim=0) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + if self.project_out_dim is not None: + x = self.project_out_dim(x) + + return x, {"attn": [attn], "inner_states": inner_states} + + def forward( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + features_only: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + src_lengths: Optional[Any] = None, + return_all_hiddens: bool = False, + lang_id: Optional[int] = None, + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + encoder_out (optional): output from the encoder, used for + encoder-side attention + incremental_state (dict): dictionary used for storing state during + :ref:`Incremental decoding` + features_only (bool, optional): only return features without + applying output layer (default: False). + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + + assert lang_id is not None + + x, extra = self.extract_features( + prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + lang_id=lang_id, + ) + if not features_only: + x = self.output_layer(x) + return x, extra + + +@register_model_architecture("laser_transformer", "laser_transformer") +def base_laser_transformer_architecture(args): + base_architecture(args) + args.decoder_lang_embed_dim = getattr(args, "decoder_lang_embed_dim", 0) diff --git a/examples/laser/laser_src/multitask_data_utils.py b/examples/laser/laser_src/multitask_data_utils.py new file mode 100644 index 0000000000..b05caea267 --- /dev/null +++ b/examples/laser/laser_src/multitask_data_utils.py @@ -0,0 +1,143 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from collections import OrderedDict + +import numpy as np + +from fairseq.data import BaseWrapperDataset, FairseqDataset, iterators + + +class MultiItr(object): + def __init__(self, itr): + self.itr = itr + self._counts = [0 for x in itr] + + def __len__(self): + return sum(len(itr) for itr in self.itr) + + def __iter__(self): + return self + + def __next__(self): + ratios = [count / len(itr) for count, itr in zip(self._counts, self.itr)] + idx = ratios.index(min(ratios)) + self._counts[idx] += 1 + return next(self.itr[idx]) + + +class MultidatasetEpochBatchIterator(iterators.EpochBatchIterating): + """A wrapper around multiple epoch batch iterators.""" + + def __init__( + self, + dataset, + batch_sampler, + seed=1, + num_shards=1, + shard_id=0, + num_workers=0, + epoch=1, + ): + + assert isinstance(dataset, OrderedDict) + assert len(dataset) + assert isinstance(dataset[next(iter(dataset))], FairseqDataset) + + self.iterators = [] + + self.epoch = epoch + for key, dt in dataset.items(): + epoch_iter = iterators.EpochBatchIterator( + dataset=dt, + collate_fn=dt.collater, + batch_sampler=batch_sampler[key], + seed=seed, + num_shards=num_shards, + shard_id=shard_id, + num_workers=0, + epoch=epoch, + ) + self.iterators.append(epoch_iter) + + def __len__(self): + return sum(len(itr) for itr in self.iterators) + + def next_epoch_itr(self, shuffle=True, fix_batches_to_gpus=False): + # `self.epoch += 1` should be handled by underlying `EpochBatchIterator`s. + return MultiItr( + [ + itr.next_epoch_itr( + shuffle=shuffle, fix_batches_to_gpus=fix_batches_to_gpus + ) + for itr in self.iterators + ] + ) + + def end_of_epoch(self): + return all(itr.end_of_epoch() for itr in self.iterators) + + @property + def next_epoch_idx(self): + """Return the epoch index after *next_epoch_itr* is called.""" + + epochs = [itr.next_epoch_idx for itr in self.iterators] + self.epoch = epochs[0] + assert all(epoch == self.epoch for epoch in epochs) + + return self.epoch + + @property + def iterations_in_epoch(self): + return sum(itr.iterations_in_epoch for itr in self.iterators) + + def state_dict(self): + return { + "iterators": [it.state_dict() for it in self.iterators], + "epoch": self.epoch, + } + + def load_state_dict(self, state_dict): + self.epoch = state_dict["epoch"] + for it, d in zip(self.iterators, state_dict["iterators"]): + it.load_state_dict(d) + + +class MultitaskDatasetWrapper(BaseWrapperDataset): + """A wrapper for a multitask dataset.""" + + def __init__(self, dataset, target_language_id, sample=1.0, name=""): + super().__init__(dataset) + self.target_language_id = target_language_id + self.sample = sample + self.name = name + + def collater(self, *args, **kwargs): + ans = self.dataset.collater(*args, **kwargs) + if "net_input" in ans: + ans["net_input"]["target_language_id"] = self.target_language_id + ans["net_input"]["dataset_name"] = self.name + return ans + + def num_tokens(self, *args, **kwargs): + return self.dataset.num_tokens(*args, **kwargs) + + def ordered_indices(self, *args, **kwargs): + indices = self.dataset.ordered_indices(*args, **kwargs) + # Hacky solution for sampling + size = int(self.sample * indices.shape[0]) + + return indices.take(np.sort(np.random.permutation(indices.shape[0])[:size])) + + def size(self, index: int): + return self.dataset.size(index) + + @property + def supports_prefetch(self): + """Whether this dataset supports prefetching.""" + return getattr(self.dataset, "supports_prefetch", False) + + def prefetch(self, indices): + return self.dataset.prefetch(indices) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 981ffd49cd..3cb98897bf 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -22,6 +22,7 @@ preprocess_lm_data, preprocess_summarization_data, preprocess_translation_data, + create_laser_data_and_config_json, train_translation_model, ) @@ -935,6 +936,65 @@ def test_alignment(self): ) generate_main(data_dir) + def test_laser_lstm(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_laser_lstm") as data_dir: + laser_config_file = create_laser_data_and_config_json(data_dir) + train_translation_model( + laser_config_file.name, + "laser_lstm", + [ + "--user-dir", + "examples/laser/laser_src", + "--weighting-alpha", + "0.3", + "--encoder-bidirectional", + "--encoder-hidden-size", + "512", + "--encoder-layers", + "5", + "--decoder-layers", + "1", + "--encoder-embed-dim", + "320", + "--decoder-embed-dim", + "320", + "--decoder-lang-embed-dim", + "32", + "--save-dir", + data_dir, + "--disable-validation", + ], + task="laser", + lang_flags=[], + ) + + def test_laser_transformer(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_laser_transformer") as data_dir: + laser_config_file = create_laser_data_and_config_json(data_dir) + train_translation_model( + laser_config_file.name, + "laser_transformer", + [ + "--user-dir", + "examples/laser/laser_src", + "--weighting-alpha", + "0.3", + "--encoder-embed-dim", + "320", + "--decoder-embed-dim", + "320", + "--decoder-lang-embed-dim", + "32", + "--save-dir", + data_dir, + "--disable-validation", + ], + task="laser", + lang_flags=[], + ) + def test_alignment_full_context(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_alignment") as data_dir: diff --git a/tests/utils.py b/tests/utils.py index 178df5763e..1bf6f8d7f3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import argparse +import json import os import random import sys @@ -274,6 +275,43 @@ def preprocess_summarization_data(data_dir, extra_flags=None): preprocess.main(preprocess_args) +def create_laser_data_and_config_json(data_dir): + src_langs = ["de", "fr", "ru", "tr", "zh"] + tgt_langs = ["en", "es"] + config_json = {} + config_train_json = [] + src_vocab = None + tgt_vocab = None + + for src_lang in src_langs: + for tgt_lang in tgt_langs: + langpair_folder = f"{src_lang}-{tgt_lang}" + + langpair_path = os.path.join(data_dir, langpair_folder) + os.mkdir(langpair_path) + create_dummy_data(langpair_path) + preprocess_translation_data(langpair_path, ["--dataset-impl", "cached"]) + + src_vocab = os.path.join(langpair_path, "dict.in.txt") + tgt_vocab = os.path.join(langpair_path, "dict.out.txt") + config_train_json.append( + { + "id": 0 if tgt_lang == "en" else 1, + "src": os.path.join(langpair_path, "train.in-out.in"), + "tgt": os.path.join(langpair_path, "train.in-out.out"), + } + ) + + config_json["src_vocab"] = src_vocab + config_json["tgt_vocab"] = tgt_vocab + config_json["train"] = config_train_json + + with open(os.path.join(data_dir, "laserconfig.json"), "w") as config_file: + json.dump(config_json, config_file) + + return config_file + + def train_translation_model( data_dir, arch, From 3bc43c17d14c4b9f6b052a915f9589cd538bc8b6 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 18 Feb 2021 13:10:02 -0800 Subject: [PATCH 222/774] Fix speed regression after RobertaEncoder refactor (#1626) Summary: Add back a couple speed optimizations in the original roberta code that got lost in the refactor Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1626 Reviewed By: gwenzek Differential Revision: D26478534 Pulled By: myleott fbshipit-source-id: b945de5e9bffd51cd63630cc3aa1f0078a41cca8 --- fairseq/models/transformer.py | 9 ++++++--- fairseq/modules/transformer_layer.py | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 4960fd143d..605cfa65e8 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -434,10 +434,11 @@ def forward( hidden states of shape `(src_len, batch, embed_dim)`. Only populated if *return_all_hiddens* is True. """ - x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) - # compute padding mask encoder_padding_mask = src_tokens.eq(self.padding_idx) + has_pads = (src_tokens.device.type == "xla" or encoder_padding_mask.any()) + + x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) # account for padding while computing the representation if encoder_padding_mask is not None: @@ -453,7 +454,9 @@ def forward( # encoder layers for layer in self.layers: - x = layer(x, encoder_padding_mask) + x = layer( + x, encoder_padding_mask=encoder_padding_mask if has_pads else None + ) if return_all_hiddens: assert encoder_states is not None encoder_states.append(x) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 03e70f4279..f9ada37bde 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -103,7 +103,7 @@ def upgrade_state_dict_named(self, state_dict, name): state_dict["{}.{}.{}".format(name, new, m)] = state_dict[k] del state_dict[k] - def forward(self, x, encoder_padding_mask, attn_mask: Optional[Tensor] = None): + def forward(self, x, encoder_padding_mask: Optional[Tensor], attn_mask: Optional[Tensor] = None): """ Args: x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)` @@ -135,6 +135,7 @@ def forward(self, x, encoder_padding_mask, attn_mask: Optional[Tensor] = None): key=x, value=x, key_padding_mask=encoder_padding_mask, + need_weights=False, attn_mask=attn_mask, ) x = self.dropout_module(x) From da9eaba12d82b9bfc1442f0e2c6fc1b895f4d35d Mon Sep 17 00:00:00 2001 From: Elizabeth Salesky <elizabeth.salesky@gmail.com> Date: Thu, 18 Feb 2021 13:58:56 -0800 Subject: [PATCH 223/774] Add support for multi-channel audio and example for mTEDx data (#3253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? - updates audio_utils to handle multi-channel audio as well as mono, with no change needed for existing recipes - adds speech-to-text example for Multilingual TEDx (http://openslr.org/100) data ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3253 Reviewed By: yuntang Differential Revision: D26514419 Pulled By: kahne fbshipit-source-id: 699e428affda5b1347f96a8310691ab152dd6769 --- examples/speech_to_text/README.md | 2 + examples/speech_to_text/docs/mtedx_example.md | 200 +++++++++++++++ examples/speech_to_text/prep_mtedx_data.py | 235 ++++++++++++++++++ fairseq/data/audio/audio_utils.py | 10 +- .../models/speech_to_text/s2t_transformer.py | 9 + 5 files changed, 455 insertions(+), 1 deletion(-) create mode 100644 examples/speech_to_text/docs/mtedx_example.md create mode 100644 examples/speech_to_text/prep_mtedx_data.py diff --git a/examples/speech_to_text/README.md b/examples/speech_to_text/README.md index 4b6f89d105..988ed83d77 100644 --- a/examples/speech_to_text/README.md +++ b/examples/speech_to_text/README.md @@ -36,6 +36,8 @@ audio paths (one per line) as inputs. - [Speech-to-Text Translation (ST) on CoVoST 2](docs/covost_example.md) +- [Speech-to-Text Translation (ST) on Multilingual TEDx](docs/mtedx_example.md) + ## Updates - 02/04/2021: Added interactive decoding (`fairseq-interactive`) support. Examples: [ASR (LibriSpeech)](docs/librispeech_example.md#interactive-decoding) diff --git a/examples/speech_to_text/docs/mtedx_example.md b/examples/speech_to_text/docs/mtedx_example.md new file mode 100644 index 0000000000..c0e17db9a2 --- /dev/null +++ b/examples/speech_to_text/docs/mtedx_example.md @@ -0,0 +1,200 @@ +[[Back]](..) + +# S2T Example: Speech Translation (ST) on Multilingual TEDx + +[Multilingual TEDx](https://arxiv.org/abs/2102.01757) is multilingual corpus for speech recognition and +speech translation. The data is derived from TEDx talks in 8 source languages +with translations to a subset of 5 target languages. + +## Data Preparation +[Download](http://openslr.org/100/) and unpack Multilingual TEDx data to a path +`${MTEDX_ROOT}/${LANG_PAIR}`, then preprocess it with +```bash +# additional Python packages for S2T data processing/model training +pip install pandas torchaudio sentencepiece + +# Generate TSV manifests, features, vocabulary +# and configuration for each language +python examples/speech_to_text/prep_mtedx_data.py \ + --data-root ${MTEDX_ROOT} --task asr \ + --vocab-type unigram --vocab-size 1000 +python examples/speech_to_text/prep_mtedx_data.py \ + --data-root ${MTEDX_ROOT} --task st \ + --vocab-type unigram --vocab-size 1000 + +# Add vocabulary and configuration for joint data +# (based on the manifests and features generated above) +python examples/speech_to_text/prep_mtedx_data.py \ + --data-root ${MTEDX_ROOT} --task asr --joint \ + --vocab-type unigram --vocab-size 8000 +python examples/speech_to_text/prep_mtedx_data.py \ + --data-root ${MTEDX_ROOT} --task st --joint \ + --vocab-type unigram --vocab-size 8000 +``` +The generated files (manifest, features, vocabulary and data configuration) will be added to +`${MTEDX_ROOT}/${LANG_PAIR}` (per-language data) and `MTEDX_ROOT` (joint data). + + +## ASR +#### Training +Spanish as example: +```bash +fairseq-train ${MTEDX_ROOT}/es-es \ + --config-yaml config_asr.yaml --train-subset train_asr --valid-subset valid_asr \ + --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-epoch 200 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_xs --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --dropout 0.3 --label-smoothing 0.1 \ + --load-pretrained-encoder-from ${PRETRAINED_ENCODER} \ + --skip-invalid-size-inputs-valid-test \ + --keep-last-epochs 10 --update-freq 8 --patience 10 +``` +For joint model (using ASR data from all 8 languages): +```bash +fairseq-train ${MTEDX_ROOT} \ + --config-yaml config_asr.yaml \ + --train-subset train_es-es_asr,train_fr-fr_asr,train_pt-pt_asr,train_it-it_asr,train_ru-ru_asr,train_el-el_asr,train_ar-ar_asr,train_de-de_asr \ + --valid-subset valid_es-es_asr,valid_fr-fr_asr,valid_pt-pt_asr,valid_it-it_asr,valid_ru-ru_asr,valid_el-el_asr,valid_ar-ar_asr,valid_de-de_asr \ + --save-dir ${MULTILINGUAL_ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-epoch 200 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --dropout 0.3 --label-smoothing 0.1 \ + --skip-invalid-size-inputs-valid-test \ + --keep-last-epochs 10 --update-freq 8 --patience 10 \ + --ignore-prefix-size 1 +``` +where `MULTILINGUAL_ASR_SAVE_DIR` is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs +with 1 GPU. You may want to update it accordingly when using more than 1 GPU. +For multilingual models, we prepend target language ID token as target BOS, which should be excluded from +the training loss via `--ignore-prefix-size 1`. + +#### Inference & Evaluation +```bash +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py \ + --inputs ${ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" + +fairseq-generate ${MTEDX_ROOT}/es-es \ + --config-yaml config_asr.yaml --gen-subset test --task speech_to_text \ + --path ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ + --skip-invalid-size-inputs-valid-test \ + --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct --remove-bpe + +# For models trained on joint data +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py \ + --inputs ${MULTILINGUAL_ASR_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${MULTILINGUAL_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME}" + +for LANG in es fr pt it ru el ar de; do + fairseq-generate ${MTEDX_ROOT} \ + --config-yaml config_asr.yaml --gen-subset test_${LANG}-${LANG}_asr --task speech_to_text \ + --prefix-size 1 --path ${MULTILINGUAL_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 40000 --beam 5 \ + --skip-invalid-size-inputs-valid-test \ + --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct --remove-bpe +done +``` +#### Results +| Data | --arch | Params | Es | Fr | Pt | It | Ru | El | Ar | De | +|--------------|--------------------|--------|------|------|------|------|------|-------|-------|-------| +| Monolingual | s2t_transformer_xs | 10M | 46.4 | 45.6 | 54.8 | 48.0 | 74.7 | 109.5 | 104.4 | 111.1 | + + +## ST +#### Training +Es-En as example: +```bash +fairseq-train ${MTEDX_ROOT}/es-en \ + --config-yaml config_st.yaml --train-subset train_st --valid-subset valid_st \ + --save-dir ${ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-epoch 200 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_xs --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --dropout 0.3 --label-smoothing 0.1 \ + --load-pretrained-encoder-from ${PRETRAINED_ENCODER} \ + --skip-invalid-size-inputs-valid-test \ + --keep-last-epochs 10 --update-freq 8 --patience 10 +``` +For multilingual model (all 12 directions): +```bash +fairseq-train ${MTEDX_ROOT} \ + --config-yaml config_st.yaml \ + --train-subset train_el-en_st,train_es-en_st,train_es-fr_st,train_es-it_st,train_es-pt_st,train_fr-en_st,train_fr-es_st,train_fr-pt_st,train_it-en_st,train_it-es_st,train_pt-en_st,train_pt-es_st,train_ru-en_st \ + --valid-subset valid_el-en_st,valid_es-en_st,valid_es-fr_st,valid_es-it_st,valid_es-pt_st,valid_fr-en_st,valid_fr-es_st,valid_fr-pt_st,valid_it-en_st,valid_it-es_st,valid_pt-en_st,valid_pt-es_st,valid_ru-en_st \ + --save-dir ${MULTILINGUAL_ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-epoch 200 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --dropout 0.3 --label-smoothing 0.1 \ + --skip-invalid-size-inputs-valid-test \ + --keep-last-epochs 10 --update-freq 8 --patience 10 \ + --ignore-prefix-size 1 \ + --load-pretrained-encoder-from ${PRETRAINED_ENCODER} +``` +where `ST_SAVE_DIR` (`MULTILINGUAL_ST_SAVE_DIR`) is the checkpoint root path. The ST encoder is pre-trained by ASR +for faster training and better performance: `--load-pretrained-encoder-from <(JOINT_)ASR checkpoint path>`. We set +`--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly when using more than 1 GPU. +For multilingual models, we prepend target language ID token as target BOS, which should be excluded from +the training loss via `--ignore-prefix-size 1`. + +#### Inference & Evaluation +Average the last 10 checkpoints and evaluate on the `test` split: +```bash +CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt +python scripts/average_checkpoints.py \ + --inputs ${ST_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" + +fairseq-generate ${MTEDX_ROOT}/es-en \ + --config-yaml config_st.yaml --gen-subset test --task speech_to_text \ + --path ${ST_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 50000 --beam 5 --scoring sacrebleu --remove-bpe + +# For multilingual models +python scripts/average_checkpoints.py \ + --inputs ${MULTILINGUAL_ST_SAVE_DIR} --num-epoch-checkpoints 10 \ + --output "${MULTILINGUAL_ST_SAVE_DIR}/${CHECKPOINT_FILENAME}" + +for LANGPAIR in es-en es-fr es-pt fr-en fr-es fr-pt pt-en pt-es it-en it-es ru-en el-en; do + fairseq-generate ${MTEDX_ROOT} \ + --config-yaml config_st.yaml --gen-subset test_${LANGPAIR}_st --task speech_to_text \ + --prefix-size 1 --path ${MULTILINGUAL_ST_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --max-tokens 40000 --beam 5 \ + --skip-invalid-size-inputs-valid-test \ + --scoring sacrebleu --remove-bpe +done +``` +For multilingual models, we force decoding from the target language ID token (as BOS) via `--prefix-size 1`. + +#### Results +| Data | --arch | Params | Es-En | Es-Pt | Es-Fr | Fr-En | Fr-Es | Fr-Pt | Pt-En | Pt-Es | It-En | It-Es | Ru-En | El-En | +|--------------|--------------------|-----|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------|-------| +| Bilingual | s2t_transformer_xs | 10M | 7.0 | 12.2 | 1.7 | 8.9 | 10.6 | 7.9 | 8.1 | 8.7 | 6.4 | 1.0 | 0.7 | 0.6 | +| Multilingual | s2t_transformer_s | 31M | 12.3 | 17.4 | 6.1 | 12.0 | 13.6 | 13.2 | 12.0 | 13.7 | 10.7 | 13.1 | 0.6 | 0.8 | + + +## Citation +Please cite as: +``` +@misc{salesky2021mtedx, + title={Multilingual TEDx Corpus for Speech Recognition and Translation}, + author={Elizabeth Salesky and Matthew Wiesner and Jacob Bremerman and Roldano Cattoni and Matteo Negri and Marco Turchi and Douglas W. Oard and Matt Post}, + year={2021}, +} + +@inproceedings{wang2020fairseqs2t, + title = {fairseq S2T: Fast Speech-to-Text Modeling with fairseq}, + author = {Changhan Wang and Yun Tang and Xutai Ma and Anne Wu and Dmytro Okhonko and Juan Pino}, + booktitle = {Proceedings of the 2020 Conference of the Asian Chapter of the Association for Computational Linguistics (AACL): System Demonstrations}, + year = {2020}, +} + +@inproceedings{ott2019fairseq, + title = {fairseq: A Fast, Extensible Toolkit for Sequence Modeling}, + author = {Myle Ott and Sergey Edunov and Alexei Baevski and Angela Fan and Sam Gross and Nathan Ng and David Grangier and Michael Auli}, + booktitle = {Proceedings of NAACL-HLT 2019: Demonstrations}, + year = {2019}, +} +``` + +[[Back]](..) diff --git a/examples/speech_to_text/prep_mtedx_data.py b/examples/speech_to_text/prep_mtedx_data.py new file mode 100644 index 0000000000..6c37398fcc --- /dev/null +++ b/examples/speech_to_text/prep_mtedx_data.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import os +from pathlib import Path +import shutil +from itertools import groupby +from tempfile import NamedTemporaryFile +from typing import Tuple + +import pandas as pd +import torchaudio +from examples.speech_to_text.data_utils import ( + create_zip, + extract_fbank_features, + filter_manifest_df, + gen_config_yaml, + gen_vocab, + get_zip_manifest, + load_df_from_tsv, + save_df_to_tsv, +) +from torch import Tensor +from torch.utils.data import Dataset +from tqdm import tqdm + + +log = logging.getLogger(__name__) + + +MANIFEST_COLUMNS = ["id", "audio", "n_frames", "tgt_text", "speaker", "tgt_lang"] + + +class mTEDx(Dataset): + """ + Create a Dataset for Multilingual TEDx. + Each item is a tuple of the form: waveform, sample_rate, source utterance, + target utterance, speaker_id, utterance_id + """ + + SPLITS = ["train", "valid", "test"] + LANGPAIRS = ["es-es", "fr-fr", "pt-pt", "it-it", "ru-ru", "el-el", "ar-ar", "de-de", + "es-en", "es-fr", "es-pt", "es-it", "fr-en", "fr-es", "fr-pt", + "pt-en", "pt-es", "it-en", "it-es", "ru-en", "el-en"] + + def __init__(self, root: str, lang: str, split: str) -> None: + assert split in self.SPLITS and lang in self.LANGPAIRS + _root = Path(root) / f"{lang}" / "data" / split + wav_root, txt_root = _root / "wav", _root / "txt" + assert _root.is_dir() and wav_root.is_dir() and txt_root.is_dir() + # Load audio segments + try: + import yaml + except ImportError: + print("Please install PyYAML to load the Multilingual TEDx YAML files") + with open(txt_root / f"{split}.yaml") as f: + segments = yaml.load(f, Loader=yaml.BaseLoader) + # Load source and target utterances + src, tgt = lang.split("-") + for _lang in [src, tgt]: + with open(txt_root / f"{split}.{_lang}") as f: + utterances = [r.strip() for r in f] + assert len(segments) == len(utterances) + for i, u in enumerate(utterances): + segments[i][_lang] = u + # Gather info + self.data = [] + for wav_filename, _seg_group in groupby(segments, lambda x: x["wav"]): + wav_filename = wav_filename.replace(".wav", ".flac") + wav_path = wav_root / wav_filename + sample_rate = torchaudio.info(wav_path.as_posix())[0].rate + seg_group = sorted(_seg_group, key=lambda x: float(x["offset"])) + for i, segment in enumerate(seg_group): + offset = int(float(segment["offset"]) * sample_rate) + n_frames = int(float(segment["duration"]) * sample_rate) + _id = f"{wav_path.stem}_{i}" + self.data.append( + ( + wav_path.as_posix(), + offset, + n_frames, + sample_rate, + segment[src], + segment[tgt], + segment["speaker_id"], + tgt, + _id, + ) + ) + + def __getitem__(self, n: int) -> Tuple[Tensor, int, str, str, str, str, str]: + wav_path, offset, n_frames, sr, src_utt, tgt_utt, spk_id, tgt_lang, utt_id = self.data[n] + waveform, _ = torchaudio.load(wav_path, offset=offset, num_frames=n_frames) + return waveform, sr, src_utt, tgt_utt, spk_id, tgt_lang, utt_id + + def __len__(self) -> int: + return len(self.data) + + +def process(args): + root = Path(args.data_root).absolute() + for lang in mTEDx.LANGPAIRS: + cur_root = root / f"{lang}" + if not cur_root.is_dir(): + print(f"{cur_root.as_posix()} does not exist. Skipped.") + continue + # Extract features + feature_root = cur_root / "fbank80" + feature_root.mkdir(exist_ok=True) + for split in mTEDx.SPLITS: + print(f"Fetching split {split}...") + dataset = mTEDx(root.as_posix(), lang, split) + print("Extracting log mel filter bank features...") + for waveform, sample_rate, _, _, _, _, utt_id in tqdm(dataset): + extract_fbank_features( + waveform, sample_rate, feature_root / f"{utt_id}.npy" + ) + # Pack features into ZIP + zip_path = cur_root / "fbank80.zip" + print("ZIPing features...") + create_zip(feature_root, zip_path) + print("Fetching ZIP manifest...") + zip_manifest = get_zip_manifest(zip_path) + # Generate TSV manifest + print("Generating manifest...") + train_text = [] + for split in mTEDx.SPLITS: + is_train_split = split.startswith("train") + manifest = {c: [] for c in MANIFEST_COLUMNS} + dataset = mTEDx(args.data_root, lang, split) + for wav, sr, src_utt, tgt_utt, speaker_id, tgt_lang, utt_id in tqdm(dataset): + manifest["id"].append(utt_id) + manifest["audio"].append(zip_manifest[utt_id]) + duration_ms = int(wav.size(1) / sr * 1000) + manifest["n_frames"].append(int(1 + (duration_ms - 25) / 10)) + manifest["tgt_text"].append(src_utt if args.task == "asr" else tgt_utt) + manifest["speaker"].append(speaker_id) + manifest["tgt_lang"].append(tgt_lang) + if is_train_split: + train_text.extend(manifest["tgt_text"]) + df = pd.DataFrame.from_dict(manifest) + df = filter_manifest_df(df, is_train_split=is_train_split) + save_df_to_tsv(df, cur_root / f"{split}_{args.task}.tsv") + # Generate vocab + v_size_str = "" if args.vocab_type == "char" else str(args.vocab_size) + spm_filename_prefix = f"spm_{args.vocab_type}{v_size_str}_{args.task}" + with NamedTemporaryFile(mode="w") as f: + for t in train_text: + f.write(t + "\n") + gen_vocab( + Path(f.name), + cur_root / spm_filename_prefix, + args.vocab_type, + args.vocab_size, + ) + # Generate config YAML + gen_config_yaml( + cur_root, + spm_filename_prefix + ".model", + yaml_filename=f"config_{args.task}.yaml", + specaugment_policy="lb", + ) + # Clean up + shutil.rmtree(feature_root) + + +def process_joint(args): + cur_root = Path(args.data_root) + assert all((cur_root / f"{lang}").is_dir() for lang in mTEDx.LANGPAIRS), \ + "do not have downloaded data available for all languages" + # Generate vocab + vocab_size_str = "" if args.vocab_type == "char" else str(args.vocab_size) + spm_filename_prefix = f"spm_{args.vocab_type}{vocab_size_str}_{args.task}" + with NamedTemporaryFile(mode="w") as f: + for lang in mTEDx.LANGPAIRS: + tsv_path = cur_root / f"{lang}" / f"train_{args.task}.tsv" + df = load_df_from_tsv(tsv_path) + for t in df["tgt_text"]: + f.write(t + "\n") + special_symbols = None + if args.joint: + # Add tgt_lang tags to dict + special_symbols = list({f'<lang:{lang.split("-")[1]}>' for lang in mTEDx.LANGPAIRS}) + gen_vocab( + Path(f.name), + cur_root / spm_filename_prefix, + args.vocab_type, + args.vocab_size, + special_symbols=special_symbols + ) + # Generate config YAML + gen_config_yaml( + cur_root, + spm_filename_prefix + ".model", + yaml_filename=f"config_{args.task}.yaml", + specaugment_policy="ld", + prepend_tgt_lang_tag=(args.joint), + ) + # Make symbolic links to manifests + for lang in mTEDx.LANGPAIRS: + for split in mTEDx.SPLITS: + src_path = cur_root / f"{lang}" / f"{split}_{args.task}.tsv" + desc_path = cur_root / f"{split}_{lang}_{args.task}.tsv" + if not desc_path.is_symlink(): + os.symlink(src_path, desc_path) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--data-root", "-d", required=True, type=str) + parser.add_argument( + "--vocab-type", + default="unigram", + required=True, + type=str, + choices=["bpe", "unigram", "char"], + ), + parser.add_argument("--vocab-size", default=8000, type=int) + parser.add_argument("--task", type=str, choices=["asr", "st"]) + parser.add_argument("--joint", action="store_true", help="") + args = parser.parse_args() + + if args.joint: + process_joint(args) + else: + process(args) + + +if __name__ == "__main__": + main() diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index de08669851..f0e75b1d65 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -56,8 +56,16 @@ def _get_torchaudio_fbank(waveform, sample_rate, n_bins=80) -> Optional[np.ndarr try: import torch import torchaudio.compliance.kaldi as ta_kaldi + import torchaudio.sox_effects as ta_sox + + waveform = torch.from_numpy(waveform) + if len(waveform.shape) == 1: + # Mono channel: D -> 1 x D + waveform = waveform.unsqueeze(0) + else: + # Merge multiple channels to one: C x D -> 1 x D + waveform, _ = ta_sox.apply_effects_tensor(waveform, sample_rate, ['channels', '1']) - waveform = torch.from_numpy(waveform).unsqueeze(0) features = ta_kaldi.fbank( waveform, num_mel_bins=n_bins, sample_frequency=sample_rate ) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 1f556107a2..814924ec97 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -422,6 +422,15 @@ def s2t_transformer_s(args): base_architecture(args) +@register_model_architecture("s2t_transformer", "s2t_transformer_xs") +def s2t_transformer_xs(args): + args.encoder_layers = getattr(args, "encoder_layers", 6) + args.decoder_layers = getattr(args, "decoder_layers", 3) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 256 * 4) + args.dropout = getattr(args, "dropout", 0.3) + s2t_transformer_s(args) + + @register_model_architecture("s2t_transformer", "s2t_transformer_sp") def s2t_transformer_sp(args): args.encoder_layers = getattr(args, "encoder_layers", 16) From 284a86a49a054dcace1e66ee4c65dfb4adb5a39f Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Thu, 18 Feb 2021 16:35:02 -0800 Subject: [PATCH 224/774] remove the missing _device property Summary: after D26382917 (https://github.com/pytorch/fairseq/commit/02803a1be45642b4c2f9c2970a4f4ae645a2dccf) shipped somehow the self._device was removed in optimizer, (or maybe I didn't test it the right way in the previous diff?) fortunately OSS doesn't need it any way. Reviewed By: myleott Differential Revision: D26523538 fbshipit-source-id: 637c1e344670340ae40b32635ef51f5501966b0c --- fairseq/optim/shard.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fairseq/optim/shard.py b/fairseq/optim/shard.py index 3c1b34ae60..9d7f2eb9e5 100644 --- a/fairseq/optim/shard.py +++ b/fairseq/optim/shard.py @@ -45,7 +45,6 @@ def broadcast_global_state_dict( state_dict, src_rank=0, group=self.group, - dist_device=self._device, ) torch_optimizer = optimizer.optimizer From d2ee5883e774700c41b1eaddd0326e9afa6d3cd2 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutai_ma@jhu.edu> Date: Thu, 18 Feb 2021 22:41:32 -0800 Subject: [PATCH 225/774] Simultaneous Speech Translation Model (#1607) Summary: This is the pull request for the code for the paper [SimulMT to SimulST: Adapting Simultaneous Text Translation to End-to-End Simultaneous Speech Translation](https://www.aclweb.org/anthology/2020.aacl-main.58/) The model will also be used for [IWSLT 2021 shared task on simultaneous translation ](https://iwslt.org/2021/simultaneous) This pull request includes - Convtransformer offline model - Convtransformer simultaneous translation model with fixed pre-decision module - The agent files for inference for the convtransformer simultaneous translation model jmp84 The README is still missing. Just curious where should I place it? Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1607 Test Plan: Imported from GitHub, without a `Test Plan:` line. ********** One of the failing landing integration tests ``` buck test mode/dev //multimo/fb/models/test:multimo_fb_model_test https://fburl.com/testinfra/oxq2cn5n ``` Reviewed By: jmp84 Differential Revision: D26439663 Pulled By: sravyapopuri388 fbshipit-source-id: b127cb4962756af221b65e3ccb6598a42fc75f7f --- .../models/transformer_monotonic_attention.py | 28 +- .../modules/fixed_pre_decision.py | 170 +++++++ .../modules/monotonic_multihead_attention.py | 343 ++++++------- .../modules/monotonic_transformer_layer.py | 8 + .../utils/data_utils.py | 100 ++++ examples/speech_to_text/README.md | 1 + .../docs/simulst_mustc_example.md | 52 ++ .../agents/fairseq_simul_st_agent.py | 331 +++++++++++++ .../agents/simul_trans_agent.py | 200 ++++++++ fairseq/models/speech_to_text/__init__.py | 2 + .../models/speech_to_text/convtransformer.py | 452 ++++++++++++++++++ .../convtransformer_simul_trans.py | 49 ++ 12 files changed, 1560 insertions(+), 176 deletions(-) create mode 100644 examples/simultaneous_translation/modules/fixed_pre_decision.py create mode 100644 examples/simultaneous_translation/utils/data_utils.py create mode 100644 examples/speech_to_text/docs/simulst_mustc_example.md create mode 100644 examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py create mode 100644 examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py create mode 100644 fairseq/models/speech_to_text/convtransformer.py create mode 100644 fairseq/models/speech_to_text/convtransformer_simul_trans.py diff --git a/examples/simultaneous_translation/models/transformer_monotonic_attention.py b/examples/simultaneous_translation/models/transformer_monotonic_attention.py index ab8adf3aab..dd3895f0eb 100644 --- a/examples/simultaneous_translation/models/transformer_monotonic_attention.py +++ b/examples/simultaneous_translation/models/transformer_monotonic_attention.py @@ -10,17 +10,20 @@ TransformerMonotonicDecoderLayer, TransformerMonotonicEncoderLayer, ) -from fairseq.models import register_model, register_model_architecture +from fairseq.models import ( + register_model, + register_model_architecture, +) from fairseq.models.transformer import ( - TransformerDecoder, - TransformerEncoder, TransformerModel, + TransformerEncoder, + TransformerDecoder, base_architecture, transformer_iwslt_de_en, transformer_vaswani_wmt_en_de_big, + transformer_vaswani_wmt_en_fr_big, ) - DEFAULT_MAX_SOURCE_POSITIONS = 1024 DEFAULT_MAX_TARGET_POSITIONS = 1024 @@ -33,7 +36,7 @@ def build_encoder(cls, args, src_dict, embed_tokens): @register_model("transformer_monotonic") -class TransformerMonotonicModel(TransformerModel): +class TransformerModelSimulTrans(TransformerModel): @classmethod def build_encoder(cls, args, src_dict, embed_tokens): return TransformerMonotonicEncoder(args, src_dict, embed_tokens) @@ -178,13 +181,18 @@ def pre_attention( if positions is not None: x += positions + x = self.dropout_module(x) # B x T x C -> T x B x C x = x.transpose(0, 1) - encoder_out = encoder_out_dict.encoder_out - encoder_padding_mask = encoder_out_dict.encoder_padding_mask + encoder_out = encoder_out_dict["encoder_out"][0] + encoder_padding_mask = ( + encoder_out_dict["encoder_padding_mask"][0] + if len(encoder_out_dict["encoder_padding_mask"]) > 0 + else None + ) return x, encoder_out, encoder_padding_mask @@ -236,7 +244,7 @@ def extract_features( attn_list.append(attn) if incremental_state is not None: - curr_steps = layer.get_steps(incremental_state) + curr_steps = layer.get_head_steps(incremental_state) step_list.append(curr_steps) if incremental_state.get("online", False): @@ -287,7 +295,7 @@ def reorder_incremental_state(self, incremental_state, new_order): @register_model_architecture("transformer_monotonic", "transformer_monotonic") -def base_monotonic_rchitecture(args): +def base_monotonic_architecture(args): base_architecture(args) args.encoder_unidirectional = getattr(args, "encoder_unidirectional", False) @@ -297,7 +305,7 @@ def base_monotonic_rchitecture(args): ) def transformer_monotonic_iwslt_de_en(args): transformer_iwslt_de_en(args) - base_monotonic_rchitecture(args) + base_monotonic_architecture(args) # parameters used in the "Attention Is All You Need" paper (Vaswani et al., 2017) diff --git a/examples/simultaneous_translation/modules/fixed_pre_decision.py b/examples/simultaneous_translation/modules/fixed_pre_decision.py new file mode 100644 index 0000000000..2cde55b35e --- /dev/null +++ b/examples/simultaneous_translation/modules/fixed_pre_decision.py @@ -0,0 +1,170 @@ +from functools import partial + +import torch +import torch.nn.functional as F + +from . import register_monotonic_attention +from .monotonic_multihead_attention import ( + MonotonicMultiheadAttentionWaitK, + MonotonicMultiheadAttentionHardAligned, + MonotonicMultiheadAttentionInfiniteLookback, +) + + +def fixed_pooling_monotonic_attention(monotonic_attention): + def create_model(monotonic_attention, klass): + class FixedStrideMonotonicAttention(monotonic_attention): + def __init__(self, args): + super().__init__(args) + self.pre_decision_type = args.fixed_pre_decision_type + self.pre_decision_ratio = args.fixed_pre_decision_ratio + self.pre_decision_pad_threshold = args.fixed_pre_decision_pad_threshold + if self.pre_decision_ratio == 1: + return + + if args.fixed_pre_decision_type == "average": + self.pooling_layer = torch.nn.AvgPool1d( + kernel_size=self.pre_decision_ratio, + stride=self.pre_decision_ratio, + ceil_mode=True, + ) + elif args.fixed_pre_decision_type == "last": + + def last(key): + if key.size(2) < self.pre_decision_ratio: + return key + else: + k = key[ + :, + :, + self.pre_decision_ratio - 1 :: self.pre_decision_ratio, + ].contiguous() + if key.size(-1) % self.pre_decision_ratio != 0: + k = torch.cat([k, key[:, :, -1:]], dim=-1).contiguous() + return k + + self.pooling_layer = last + else: + raise NotImplementedError + + @staticmethod + def add_args(parser): + super( + FixedStrideMonotonicAttention, FixedStrideMonotonicAttention + ).add_args(parser) + parser.add_argument( + "--fixed-pre-decision-ratio", + type=int, + required=True, + help=( + "Ratio for the fixed pre-decision," + "indicating how many encoder steps will start" + "simultaneous decision making process." + ), + ) + parser.add_argument( + "--fixed-pre-decision-type", + default="average", + choices=["average", "last"], + help="Pooling type", + ) + parser.add_argument( + "--fixed-pre-decision-pad-threshold", + type=float, + default=0.3, + help="If a part of the sequence has pad" + ",the threshold the pooled part is a pad.", + ) + + def insert_zeros(self, x): + bsz_num_heads, tgt_len, src_len = x.size() + stride = self.pre_decision_ratio + weight = F.pad(x.new_ones(1, 1, 1), (stride - 1, 0)) + x_upsample = F.conv_transpose1d( + x.view(-1, src_len).unsqueeze(1), + weight, + stride=stride, + padding=0, + ) + return x_upsample.squeeze(1).view(bsz_num_heads, tgt_len, -1) + + def p_choose( + self, + query, + key, + key_padding_mask=None, + incremental_state=None, + **extra_args + ): + + if self.pre_decision_ratio == 1: + return super().p_choose( + self, + query, + key, + key_padding_mask=None, + incremental_state=None, + **extra_args + ) + + key_pool = self.pooling_layer(key.transpose(0, 2)).transpose(0, 2) + + if key_padding_mask is not None: + key_padding_mask_pool = ( + self.pooling_layer(key_padding_mask.unsqueeze(0).float()) + .squeeze(0) + .gt(self.pre_decision_pad_threshold) + ) + # Make sure at least one element is not pad + key_padding_mask_pool[:, 0] = 0 + else: + key_padding_mask_pool = None + + p_choose_pooled = super().p_choose( + query, + key_pool, + key_padding_mask_pool, + incremental_state=incremental_state, + ) + + # Upsample, interpolate zeros + p_choose = self.insert_zeros(p_choose_pooled) + + # can be larger than src_len because we used ceil before + src_len = key.size(0) + p_choose = p_choose[:, :, :src_len] + p_choose[:, :, -1] = p_choose_pooled[:, :, -1] + + tgt_len = query.size(0) + batch_size = query.size(1) + + assert list(p_choose.size()) == [ + batch_size * self.num_heads, + tgt_len, + src_len, + ] + + return p_choose + + FixedStrideMonotonicAttention.__name__ = klass.__name__ + return FixedStrideMonotonicAttention + + return partial(create_model, monotonic_attention) + + +@register_monotonic_attention("waitk_fixed_pre_decision") +@fixed_pooling_monotonic_attention(MonotonicMultiheadAttentionWaitK) +class MonotonicMultiheadAttentionWaitkFixedStride: + pass + + +@register_monotonic_attention("hard_aligned_fixed_pre_decision") +@fixed_pooling_monotonic_attention(MonotonicMultiheadAttentionHardAligned) +class MonotonicMultiheadAttentionHardFixedStride: + pass + + +@register_monotonic_attention("infinite_lookback_fixed_pre_decision") +@fixed_pooling_monotonic_attention(MonotonicMultiheadAttentionInfiniteLookback) +class MonotonicMultiheadAttentionInfiniteLookbackFixedStride: + pass diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index c09725ac9a..5423f26c34 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -7,6 +7,7 @@ import torch import torch.nn as nn + import torch.nn.functional as F from examples.simultaneous_translation.utils.functions import ( exclusive_cumprod, @@ -30,6 +31,7 @@ def __init__(self, args): self.eps = args.attention_eps self.mass_preservation = args.mass_preservation + self.noise_type = args.noise_type self.noise_mean = args.noise_mean self.noise_var = args.noise_var @@ -43,23 +45,26 @@ def __init__(self, args): @staticmethod def add_args(parser): # fmt: off - parser.add_argument('--no-mass-preservation', action="store_false", dest="mass_preservation", + parser.add_argument('--no-mass-preservation', action="store_false", + dest="mass_preservation", help='Do not stay on the last token when decoding') - parser.add_argument('--mass-preservation', action="store_true", dest="mass_preservation", + parser.add_argument('--mass-preservation', action="store_true", + dest="mass_preservation", help='Stay on the last token when decoding') parser.set_defaults(mass_preservation=True) - parser.add_argument('--noise-var', type=float, default=1.0, help='Variance of discretness noise') parser.add_argument('--noise-mean', type=float, default=0.0, help='Mean of discretness noise') - parser.add_argument('--energy-bias', action="store_true", default=False, + parser.add_argument('--noise-type', type=str, default="flat", + help='Type of discretness noise') + parser.add_argument('--energy-bias', action="store_true", + default=False, help='Bias for energy') parser.add_argument('--energy-bias-init', type=float, default=-2.0, help='Initial value of the bias for energy') parser.add_argument('--attention-eps', type=float, default=1e-6, help='Epsilon when calculating expected attention') - # fmt: on def p_choose(self, *args): raise NotImplementedError @@ -67,7 +72,9 @@ def p_choose(self, *args): def input_projections(self, *args): raise NotImplementedError - def attn_energy(self, q_proj, k_proj, key_padding_mask=None): + def attn_energy( + self, q_proj, k_proj, key_padding_mask=None, attn_mask=None + ): """ Calculating monotonic energies @@ -82,7 +89,13 @@ def attn_energy(self, q_proj, k_proj, key_padding_mask=None): bsz = bsz // self.num_heads src_len = k_proj.size(1) - attn_energy = torch.bmm(q_proj, k_proj.transpose(1, 2)) + self.energy_bias + attn_energy = ( + torch.bmm(q_proj, k_proj.transpose(1, 2)) + self.energy_bias + ) + + if attn_mask is not None: + attn_mask = attn_mask.unsqueeze(0) + attn_energy += attn_mask attn_energy = attn_energy.view(bsz, self.num_heads, tgt_len, src_len) @@ -102,7 +115,7 @@ def expected_alignment_train(self, p_choose, key_padding_mask): q_ij = (1 − p_{ij−1})q_{ij−1} + a+{i−1j} a_ij = p_ij q_ij - parellel solution: + Parallel solution: ai = p_i * cumprod(1 − pi) * cumsum(a_i / cumprod(1 − pi)) ============================================================ @@ -139,21 +152,40 @@ def expected_alignment_train(self, p_choose, key_padding_mask): if self.mass_preservation: # Last token has the residual probabilities - alpha[:, :, -1] = 1 - alpha[:, :, :-1].sum(dim=-1).clamp(0.0, 1.0) - - assert not torch.isnan(alpha).any(), "NaN detected in alpha." + if key_padding_mask is not None and key_padding_mask[:, -1].any(): + # right padding + batch_size = key_padding_mask.size(0) + residuals = 1 - alpha.sum(dim=-1, keepdim=True).clamp(0.0, 1.0) + src_lens = src_len - key_padding_mask.sum(dim=1, keepdim=True) + src_lens = src_lens.expand( + batch_size, self.num_heads + ).contiguous().view(-1, 1) + src_lens = src_lens.expand(-1, tgt_len).contiguous() + # add back the last value + residuals += alpha.gather(2, src_lens.unsqueeze(-1) - 1) + alpha = alpha.scatter(2, src_lens.unsqueeze(-1) - 1, residuals) + else: + residuals = 1 - alpha[:, :, :-1].sum(dim=-1).clamp(0.0, 1.0) + alpha[:, :, -1] = residuals + + if torch.isnan(alpha).any(): + # Something is wrong + raise RuntimeError("NaN in alpha.") return alpha - def expected_alignment_infer(self, p_choose, key_padding_mask, incremental_state): + def expected_alignment_infer( + self, p_choose, encoder_padding_mask, incremental_state + ): + # TODO modify this function """ Calculating mo alignment for MMA during inference time ============================================================ Expected input size p_choose: bsz * num_heads, tgt_len, src_len - key_padding_mask: bsz * src_len incremental_state: dict + encodencoder_padding_mask: bsz * src_len """ # p_choose: bsz * self.num_heads, src_len bsz_num_heads, tgt_len, src_len = p_choose.size() @@ -166,7 +198,8 @@ def expected_alignment_infer(self, p_choose, key_padding_mask, incremental_state # prev_monotonic_step: bsz, num_heads bsz = bsz_num_heads // self.num_heads prev_monotonic_step = monotonic_cache.get( - "step", p_choose.new_zeros([bsz, self.num_heads]).long() + "head_step", + p_choose.new_zeros([bsz, self.num_heads]).long() ) bsz, num_heads = prev_monotonic_step.size() assert num_heads == self.num_heads @@ -175,8 +208,9 @@ def expected_alignment_infer(self, p_choose, key_padding_mask, incremental_state # p_choose: bsz, num_heads, src_len p_choose = p_choose.view(bsz, num_heads, src_len) - if key_padding_mask is not None: - src_lengths = src_len - key_padding_mask.sum(dim=1, keepdim=True).long() + if encoder_padding_mask is not None: + src_lengths = src_len - \ + encoder_padding_mask.sum(dim=1, keepdim=True).long() else: src_lengths = prev_monotonic_step.new_ones(bsz, 1) * src_len @@ -186,16 +220,16 @@ def expected_alignment_infer(self, p_choose, key_padding_mask, incremental_state new_monotonic_step = prev_monotonic_step step_offset = 0 - if key_padding_mask is not None: - if key_padding_mask[:, 0].any(): + if encoder_padding_mask is not None: + if encoder_padding_mask[:, 0].any(): # left_pad_source = True: - step_offset = key_padding_mask.sum(dim=-1, keepdim=True) + step_offset = encoder_padding_mask.sum(dim=-1, keepdim=True) max_steps = src_lengths - 1 if self.mass_preservation else src_lengths # finish_read: bsz, num_heads finish_read = new_monotonic_step.eq(max_steps) - + p_choose_i = 1 while finish_read.sum().item() < bsz * self.num_heads: # p_choose: bsz * self.num_heads, src_len # only choose the p at monotonic steps @@ -224,23 +258,34 @@ def expected_alignment_infer(self, p_choose, key_padding_mask, incremental_state new_monotonic_step += action finish_read = new_monotonic_step.eq(max_steps) | (action == 0) - # finish_read = (~ (finish_read.sum(dim=1, keepdim=True) < self.num_heads / 2)) | finish_read - monotonic_cache["step"] = new_monotonic_step + if p_choose_i is None: + import pdb;pdb.set_trace() + + monotonic_cache["head_step"] = new_monotonic_step + # Whether a head is looking for new input + monotonic_cache["head_read"] = ( + new_monotonic_step.eq(max_steps) & (p_choose_i < 0.5) + ) # alpha: bsz * num_heads, 1, src_len # new_monotonic_step: bsz, num_heads - alpha = p_choose.new_zeros([bsz * self.num_heads, src_len]).scatter( - 1, - (step_offset + new_monotonic_step) - .view(bsz * self.num_heads, 1) - .clamp(0, src_len - 1), - 1, + alpha = ( + p_choose + .new_zeros([bsz * self.num_heads, src_len]) + .scatter( + 1, + (step_offset + new_monotonic_step) + .view(bsz * self.num_heads, 1).clamp(0, src_len - 1), + 1 + ) ) if not self.mass_preservation: alpha = alpha.masked_fill( - (new_monotonic_step == max_steps).view(bsz * self.num_heads, 1), 0 + (new_monotonic_step == max_steps) + .view(bsz * self.num_heads, 1), + 0 ) alpha = alpha.unsqueeze(1) @@ -249,18 +294,28 @@ def expected_alignment_infer(self, p_choose, key_padding_mask, incremental_state return alpha + def _get_monotonic_buffer(self, incremental_state): + return utils.get_incremental_state( + self, + incremental_state, + 'monotonic', + ) or {} + + def _set_monotonic_buffer(self, incremental_state, buffer): + utils.set_incremental_state( + self, + incremental_state, + 'monotonic', + buffer, + ) + def v_proj_output(self, value): raise NotImplementedError def forward( - self, - query, - key, - value, - key_padding_mask=None, - incremental_state=None, - *args, - **kwargs, + self, query, key, value, + key_padding_mask=None, attn_mask=None, incremental_state=None, + need_weights=True, static_kv=False, *args, **kwargs ): tgt_len, bsz, embed_dim = query.size() @@ -268,26 +323,31 @@ def forward( # stepwise prob # p_choose: bsz * self.num_heads, tgt_len, src_len - p_choose = self.p_choose(query, key, key_padding_mask) + p_choose = self.p_choose( + query, key, key_padding_mask, incremental_state, + ) # expected alignment alpha # bsz * self.num_heads, tgt_len, src_len if incremental_state is not None: alpha = self.expected_alignment_infer( - p_choose, key_padding_mask, incremental_state - ) + p_choose, key_padding_mask, incremental_state) else: - alpha = self.expected_alignment_train(p_choose, key_padding_mask) + alpha = self.expected_alignment_train( + p_choose, key_padding_mask) # expected attention beta # bsz * self.num_heads, tgt_len, src_len beta = self.expected_attention( - alpha, query, key, value, key_padding_mask, incremental_state + alpha, query, key, value, + key_padding_mask, attn_mask, + incremental_state ) attn_weights = beta v_proj = self.v_proj_output(value) + attn = torch.bmm(attn_weights.type_as(v_proj), v_proj) attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) @@ -298,67 +358,17 @@ def forward( alpha = alpha.view(bsz, self.num_heads, tgt_len, src_len) p_choose = p_choose.view(bsz, self.num_heads, tgt_len, src_len) - return attn, {"alpha": alpha, "beta": beta, "p_choose": p_choose} - - def reorder_incremental_state(self, incremental_state, new_order): - """Reorder buffered internal state (for incremental generation).""" - super().reorder_incremental_state(incremental_state, new_order) - input_buffer = self._get_monotonic_buffer(incremental_state) - if input_buffer is not None: - for k in input_buffer.keys(): - input_buffer[k] = input_buffer[k].index_select(0, new_order) - self._set_monotonic_buffer(incremental_state, input_buffer) - - def _get_monotonic_buffer(self, incremental_state): - return ( - utils.get_incremental_state( - self, - incremental_state, - "monotonic", - ) - or {} - ) - - def _set_monotonic_buffer(self, incremental_state, buffer): - utils.set_incremental_state( - self, - incremental_state, - "monotonic", - buffer, - ) - - def get_pointer(self, incremental_state): - return ( - utils.get_incremental_state( - self, - incremental_state, - "monotonic", - ) - or {} - ) - - def get_fastest_pointer(self, incremental_state): - return self.get_pointer(incremental_state)["step"].max(0)[0] - - def set_pointer(self, incremental_state, p_choose): - curr_pointer = self.get_pointer(incremental_state) - if len(curr_pointer) == 0: - buffer = torch.zeros_like(p_choose) - else: - buffer = self.get_pointer(incremental_state)["step"] - - buffer += (p_choose < 0.5).type_as(buffer) - - utils.set_incremental_state( - self, - incremental_state, - "monotonic", - {"step": buffer}, - ) + return attn, { + "alpha": alpha, + "beta": beta, + "p_choose": p_choose, + } @register_monotonic_attention("hard_aligned") -class MonotonicMultiheadAttentionHard(MonotonicAttention, MultiheadAttention): +class MonotonicMultiheadAttentionHardAligned( + MonotonicAttention, MultiheadAttention +): def __init__(self, args): MultiheadAttention.__init__( self, @@ -392,39 +402,36 @@ def input_projections(self, query, key, value, name): bsz = query.size(1) q = self.q_in_proj[name](query) q *= self.scaling - q = ( - q.contiguous() - .view(-1, bsz * self.num_heads, self.head_dim) - .transpose(0, 1) - ) + q = q.contiguous().view( + -1, bsz * self.num_heads, self.head_dim + ).transpose(0, 1) else: q = None if key is not None: bsz = key.size(1) k = self.k_in_proj[name](key) - k = ( - k.contiguous() - .view(-1, bsz * self.num_heads, self.head_dim) - .transpose(0, 1) - ) + k = k.contiguous().view( + -1, bsz * self.num_heads, self.head_dim + ).transpose(0, 1) else: k = None if value is not None: bsz = value.size(1) v = self.v_in_proj[name](value) - v = ( - v.contiguous() - .view(-1, bsz * self.num_heads, self.head_dim) - .transpose(0, 1) - ) + v = v.contiguous().view( + -1, bsz * self.num_heads, self.head_dim + ).transpose(0, 1) else: v = None return q, k, v - def p_choose(self, query, key, key_padding_mask=None): + def p_choose( + self, query, key, key_padding_mask=None, + incremental_state=None, *extra_args + ): """ Calculating step wise prob for reading and writing 1 to read, 0 to write @@ -440,7 +447,9 @@ def p_choose(self, query, key, key_padding_mask=None): """ # prepare inputs - q_proj, k_proj, _ = self.input_projections(query, key, None, "monotonic") + q_proj, k_proj, _ = self.input_projections( + query, key, None, "monotonic" + ) # attention energy attn_energy = self.attn_energy(q_proj, k_proj, key_padding_mask) @@ -473,7 +482,9 @@ def v_proj_output(self, value): @register_monotonic_attention("infinite_lookback") -class MonotonicMultiheadAttentionInfiniteLookback(MonotonicMultiheadAttentionHard): +class MonotonicMultiheadAttentionInfiniteLookback( + MonotonicMultiheadAttentionHardAligned +): def __init__(self, args): super().__init__(args) self.init_soft_attention() @@ -498,30 +509,33 @@ def init_soft_attention(self): nn.init.xavier_uniform_(self.q_in_proj["soft"].weight) def expected_attention( - self, alpha, query, key, value, key_padding_mask, incremental_state + self, alpha, query, key, value, + key_padding_mask, attn_mask, incremental_state ): # monotonic attention, we will calculate milk here bsz_x_num_heads, tgt_len, src_len = alpha.size() bsz = int(bsz_x_num_heads / self.num_heads) q, k, _ = self.input_projections(query, key, None, "soft") - soft_energy = self.attn_energy(q, k, key_padding_mask) + soft_energy = self.attn_energy(q, k, key_padding_mask, attn_mask) - assert list(soft_energy.size()) == [bsz, self.num_heads, tgt_len, src_len] + assert list(soft_energy.size()) == \ + [bsz, self.num_heads, tgt_len, src_len] soft_energy = soft_energy.view(bsz * self.num_heads, tgt_len, src_len) if incremental_state is not None: monotonic_cache = self._get_monotonic_buffer(incremental_state) - monotonic_step = monotonic_cache["step"] + 1 + monotonic_length = monotonic_cache["head_step"] + 1 step_offset = 0 if key_padding_mask is not None: if key_padding_mask[:, 0].any(): # left_pad_source = True: step_offset = key_padding_mask.sum(dim=-1, keepdim=True) - monotonic_step += step_offset + monotonic_length += step_offset mask = lengths_to_mask( - monotonic_step.view(-1), soft_energy.size(2), 1 + monotonic_length.view(-1), + soft_energy.size(2), 1 ).unsqueeze(1) soft_energy = soft_energy.masked_fill(~mask.bool(), float("-inf")) @@ -531,84 +545,81 @@ def expected_attention( beta = exp_soft_energy / exp_soft_energy_sum.unsqueeze(2) else: - # bsz * num_heads, tgt_len, src_len soft_energy = soft_energy - soft_energy.max(dim=2, keepdim=True)[0] - exp_soft_energy = torch.exp(soft_energy) - exp_soft_energy_cumsum = torch.cumsum(exp_soft_energy, dim=2) + exp_soft_energy = torch.exp(soft_energy) + self.eps + inner_items = alpha / (torch.cumsum(exp_soft_energy, dim=2)) + + beta = ( + exp_soft_energy + * torch.cumsum(inner_items.flip(dims=[2]), dim=2) + .flip(dims=[2]) + ) + + beta = beta.view(bsz, self.num_heads, tgt_len, src_len) if key_padding_mask is not None: - if key_padding_mask.any(): - exp_soft_energy_cumsum = ( - exp_soft_energy_cumsum.view( - -1, self.num_heads, tgt_len, src_len - ) - .masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(1), self.eps - ) - .view(-1, tgt_len, src_len) - ) - - inner_items = alpha / exp_soft_energy_cumsum - - beta = exp_soft_energy * torch.cumsum( - inner_items.flip(dims=[2]), dim=2 - ).flip(dims=[2]) + beta = beta.masked_fill( + key_padding_mask.unsqueeze(1).unsqueeze(2).bool(), 0) + beta = beta / beta.sum(dim=3, keepdim=True) + beta = beta.view(bsz * self.num_heads, tgt_len, src_len) beta = self.dropout_module(beta) - assert not torch.isnan(beta).any(), "NaN detected in beta." + if torch.isnan(beta).any(): + # Something is wrong + raise RuntimeError("NaN in beta.") return beta @register_monotonic_attention("waitk") -class MonotonicMultiheadAttentionWaitk(MonotonicMultiheadAttentionInfiniteLookback): +class MonotonicMultiheadAttentionWaitK( + MonotonicMultiheadAttentionInfiniteLookback +): def __init__(self, args): super().__init__(args) self.q_in_proj["soft"] = self.q_in_proj["monotonic"] self.k_in_proj["soft"] = self.k_in_proj["monotonic"] self.waitk_lagging = args.waitk_lagging - assert ( - self.waitk_lagging > 0 - ), f"Lagging has to been larger than 0, get {self.waitk_lagging}." + assert self.waitk_lagging > 0, ( + f"Lagging has to been larger than 0, get {self.waitk_lagging}." + ) @staticmethod def add_args(parser): super( - MonotonicMultiheadAttentionWaitk, - MonotonicMultiheadAttentionWaitk, + MonotonicMultiheadAttentionWaitK, + MonotonicMultiheadAttentionWaitK, ).add_args(parser) parser.add_argument( - "--waitk-lagging", type=int, required=True, help="Wait k lagging" + "--waitk-lagging", type=int, required=True, help="Wait K lagging" ) def p_choose( - self, query, key, key_padding_mask=None, attn_mask=None, incremental_state=None + self, query, key, key_padding_mask=None, + incremental_state=None, *extra_args ): """ query: bsz, tgt_len key: bsz, src_len key_padding_mask: bsz, src_len """ - src_len, bsz, _ = key.size() - tgt_len, bsz, _ = query.size() + if incremental_state is not None: + tgt_len = int(incremental_state["steps"]["tgt"]) + src_len = int(incremental_state["steps"]["src"]) + bsz = 1 + else: + src_len, bsz, _ = key.size() + tgt_len, bsz, _ = query.size() + p_choose = query.new_ones(bsz, tgt_len, src_len) p_choose = torch.tril(p_choose, diagonal=self.waitk_lagging - 1) p_choose = torch.triu(p_choose, diagonal=self.waitk_lagging - 1) - if key_padding_mask is not None and key_padding_mask[:, 0].eq(1).any(): - # Left pad source - # add -1 to the end - p_choose = p_choose.masked_fill( - key_padding_mask.float().flip(1).unsqueeze(1).bool(), -1 - ) - p_choose = convert_padding_direction( - p_choose.view(-1, src_len).long(), padding_idx=-1, right_to_left=True - ) - p_choose = p_choose.view(bsz, tgt_len, src_len).type_as(query) - # remove -1 - p_choose[p_choose.eq(-1)] = 0 + if incremental_state is not None: + p_choose = p_choose[:, -1:] + tgt_len = 1 # Extend to each head p_choose = ( diff --git a/examples/simultaneous_translation/modules/monotonic_transformer_layer.py b/examples/simultaneous_translation/modules/monotonic_transformer_layer.py index 442b7d487d..e6e1850a18 100644 --- a/examples/simultaneous_translation/modules/monotonic_transformer_layer.py +++ b/examples/simultaneous_translation/modules/monotonic_transformer_layer.py @@ -26,11 +26,19 @@ def __init__( add_bias_kv=add_bias_kv, add_zero_attn=add_zero_attn, ) + + assert args.simul_type is not None, "A --simul-type is needed." + self.encoder_attn = build_monotonic_attention(args) self.encoder_attn_layer_norm = LayerNorm( self.embed_dim, export=getattr(args, "char_inputs", False) ) + def get_head_steps(self, incremental_state): + return self.encoder_attn._get_monotonic_buffer(incremental_state).get( + "head_step" + ) + def prune_incremental_state(self, incremental_state): def prune(module): input_buffer = module._get_input_buffer(incremental_state) diff --git a/examples/simultaneous_translation/utils/data_utils.py b/examples/simultaneous_translation/utils/data_utils.py new file mode 100644 index 0000000000..cc4729e63c --- /dev/null +++ b/examples/simultaneous_translation/utils/data_utils.py @@ -0,0 +1,100 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + + +def calc_mean_invstddev(feature): + if len(feature.size()) != 2: + raise ValueError("We expect the input feature to be 2-D tensor") + mean = feature.mean(0) + var = feature.var(0) + # avoid division by ~zero + eps = 1e-8 + if (var < eps).any(): + return mean, 1.0 / (torch.sqrt(var) + eps) + return mean, 1.0 / torch.sqrt(var) + + +def apply_mv_norm(features): + # If there is less than 2 spectrograms, the variance cannot be computed (is NaN) + # and normalization is not possible, so return the item as it is + if features.size(0) < 2: + return features + mean, invstddev = calc_mean_invstddev(features) + res = (features - mean) * invstddev + return res + + +def lengths_to_encoder_padding_mask(lengths, batch_first=False): + """ + convert lengths (a 1-D Long/Int tensor) to 2-D binary tensor + + Args: + lengths: a (B, )-shaped tensor + + Return: + max_length: maximum length of B sequences + encoder_padding_mask: a (max_length, B) binary mask, where + [t, b] = 0 for t < lengths[b] and 1 otherwise + + TODO: + kernelize this function if benchmarking shows this function is slow + """ + max_lengths = torch.max(lengths).item() + bsz = lengths.size(0) + encoder_padding_mask = torch.arange( + max_lengths + ).to( # a (T, ) tensor with [0, ..., T-1] + lengths.device + ).view( # move to the right device + 1, max_lengths + ).expand( # reshape to (1, T)-shaped tensor + bsz, -1 + ) >= lengths.view( # expand to (B, T)-shaped tensor + bsz, 1 + ).expand( + -1, max_lengths + ) + if not batch_first: + return encoder_padding_mask.t(), max_lengths + else: + return encoder_padding_mask, max_lengths + + +def encoder_padding_mask_to_lengths( + encoder_padding_mask, max_lengths, batch_size, device +): + """ + convert encoder_padding_mask (2-D binary tensor) to a 1-D tensor + + Conventionally, encoder output contains a encoder_padding_mask, which is + a 2-D mask in a shape (T, B), whose (t, b) element indicate whether + encoder_out[t, b] is a valid output (=0) or not (=1). Occasionally, we + need to convert this mask tensor to a 1-D tensor in shape (B, ), where + [b] denotes the valid length of b-th sequence + + Args: + encoder_padding_mask: a (T, B)-shaped binary tensor or None; if None, + indicating all are valid + Return: + seq_lengths: a (B,)-shaped tensor, where its (b, )-th element is the + number of valid elements of b-th sequence + + max_lengths: maximum length of all sequence, if encoder_padding_mask is + not None, max_lengths must equal to encoder_padding_mask.size(0) + + batch_size: batch size; if encoder_padding_mask is + not None, max_lengths must equal to encoder_padding_mask.size(1) + + device: which device to put the result on + """ + if encoder_padding_mask is None: + return torch.Tensor([max_lengths] * batch_size).to(torch.int32).to(device) + + assert encoder_padding_mask.size(0) == max_lengths, "max_lengths does not match" + assert encoder_padding_mask.size(1) == batch_size, "batch_size does not match" + + return max_lengths - torch.sum(encoder_padding_mask, dim=0) diff --git a/examples/speech_to_text/README.md b/examples/speech_to_text/README.md index 988ed83d77..f639d300d3 100644 --- a/examples/speech_to_text/README.md +++ b/examples/speech_to_text/README.md @@ -37,6 +37,7 @@ audio paths (one per line) as inputs. - [Speech-to-Text Translation (ST) on CoVoST 2](docs/covost_example.md) - [Speech-to-Text Translation (ST) on Multilingual TEDx](docs/mtedx_example.md) +- [Simultaneous Speech-to-Text Translation (SimulST) on MuST-C](docs/simulst_mustc_example.md) ## Updates - 02/04/2021: Added interactive decoding (`fairseq-interactive`) support. Examples: diff --git a/examples/speech_to_text/docs/simulst_mustc_example.md b/examples/speech_to_text/docs/simulst_mustc_example.md new file mode 100644 index 0000000000..5dea0d8475 --- /dev/null +++ b/examples/speech_to_text/docs/simulst_mustc_example.md @@ -0,0 +1,52 @@ +# Simultaneous Speech Translation (SimulST) on MuST-C + +[MuST-C](https://www.aclweb.org/anthology/N19-1202) is multilingual speech-to-text translation corpus with 8-language translations on English TED talks. + +## Data Preparation & ASR +Please follow the steps in offline [speech-to-text](../mustc_example.md) translation for data preparation and ASR pretraining. + +## Training + +#### Wait-K(K=3) with fixed pre-decision module +``` + fairseq-train ${MUSTC_ROOT}/en-de \ + --config-yaml config_st.yaml --train-subset train_st --valid-subset dev_st \ + --save-dir ${ST_SAVE_DIR} --num-workers 8 \ + --optimizer adam --lr 0.0001 --lr-scheduler inverse_sqrt --clip-norm 10.0 \ + --criterion label_smoothed_cross_entropy \ + --warmup-updates 4000 --max-update 100000 --max-tokens 40000 --seed 2 \ + --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --task speech_to_text \ + --arch convtransformer_simul_trans_espnet \ + --simul-type waitk_fixed_pre_decision \ + --waitk-lagging 3 \ + --fixed-pre-decision-ratio 7 +``` +#### Monotonic multihead attention with fixed pre-decision module +``` + fairseq-train ${MUSTC_ROOT}/en-de \ + --config-yaml config_st.yaml --train-subset train_st --valid-subset dev_st \ + --save-dir ${ST_SAVE_DIR} --num-workers 8 \ + --optimizer adam --lr 0.0001 --lr-scheduler inverse_sqrt --clip-norm 10.0 \ + --warmup-updates 4000 --max-update 100000 --max-tokens 40000 --seed 2 \ + --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --task speech_to_text \ + --criterion latency_augmented_label_smoothed_cross_entropy \ + --latency-weight-avg 0.1 \ + --arch convtransformer_simul_trans_espnet \ + --simul-type infinite_lookback_fixed_pre_decision \ + --fixed-pre-decision-ratio 7 +``` +## Inference & Evaluation +[SimulEval](https://github.com/facebookresearch/SimulEval) is used for evaluation. +``` +simuleval \ + --agent ${FAIRSEQ}/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py + --src-file ${SRC_LIST_OF_AUDIO} + --tgt-file ${TGT_FILE} + --data-bin ${MUSTC_ROOT}/en-de \ + --model-path ${ST_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --tgt-splitter-type SentencePieceModel \ + --tgt-splitter-path ${MUSTC_ROOT}/en-de/spm.model \ + --scores +``` diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py new file mode 100644 index 0000000000..cbe8bc4322 --- /dev/null +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -0,0 +1,331 @@ +import math +import os + +import numpy as np +import torch +import torchaudio.compliance.kaldi as kaldi +import yaml +from fairseq import checkpoint_utils, tasks + +try: + from simuleval import READ_ACTION, WRITE_ACTION, DEFAULT_EOS + from simuleval.agents import SpeechAgent + from simuleval.states import ListEntry +except ImportError: + print("Please install simuleval 'pip install simuleval'") + + +SHIFT_SIZE = 10 +WINDOW_SIZE = 25 +SAMPLE_RATE = 16000 +FEATURE_DIM = 80 +BOW_PREFIX = "\u2581" + + +class OnlineFeatureExtractor: + """ + Extract speech feature on the fly. + """ + + def __init__( + self, + shift_size=SHIFT_SIZE, + window_size=WINDOW_SIZE, + sample_rate=SAMPLE_RATE, + feature_dim=FEATURE_DIM, + global_cmvn=None, + ): + self.shift_size = shift_size + self.window_size = window_size + assert self.window_size >= self.shift_size + + self.sample_rate = sample_rate + self.feature_dim = feature_dim + self.num_samples_per_shift = int(SHIFT_SIZE * SAMPLE_RATE / 1000) + self.num_samples_per_window = int(WINDOW_SIZE * SAMPLE_RATE / 1000) + self.len_ms_to_samples = lambda x: x * self.sample_rate / 1000 + self.previous_residual_samples = [] + self.global_cmvn = global_cmvn + + def clear_cache(self): + self.previous_residual_samples = [] + + def __call__(self, new_samples): + samples = self.previous_residual_samples + new_samples + if len(samples) < self.num_samples_per_window: + self.previous_residual_samples = samples + return + + # num_frames is the number of frames from the new segment + num_frames = math.floor( + (len(samples) - self.len_ms_to_samples(self.window_size - self.shift_size)) + / self.num_samples_per_shift + ) + + # the number of frames used for feature extraction + # including some part of thte previous segment + effective_num_samples = int( + num_frames * self.len_ms_to_samples(self.shift_size) + + self.len_ms_to_samples(self.window_size - self.shift_size) + ) + + input_samples = samples[:effective_num_samples] + self.previous_residual_samples = samples[ + num_frames * self.num_samples_per_shift : + ] + + torch.manual_seed(1) + output = kaldi.fbank( + torch.FloatTensor(input_samples).unsqueeze(0), + num_mel_bins=self.feature_dim, + frame_length=self.window_size, + frame_shift=self.shift_size, + ).numpy() + + output = self.transform(output) + + return torch.from_numpy(output) + + def transform(self, input): + if self.global_cmvn is None: + return input + + mean = self.global_cmvn["mean"] + std = self.global_cmvn["std"] + + x = np.subtract(input, mean) + x = np.divide(x, std) + return x + + +class TensorListEntry(ListEntry): + """ + Data structure to store a list of tensor. + """ + + def append(self, value): + + if len(self.value) == 0: + self.value = value + return + + self.value = torch.cat([self.value] + [value], dim=0) + + def info(self): + return { + "type": str(self.new_value_type), + "length": self.__len__(), + "value": "" if type(self.value) is list else self.value.size(), + } + + +class FairseqSimulSTAgent(SpeechAgent): + + speech_segment_size = 40 # in ms, 4 pooling ratio * 10 ms step size + + def __init__(self, args): + super().__init__(args) + + self.eos = DEFAULT_EOS + + self.gpu = getattr(args, "gpu", False) + + self.args = args + + self.load_model_vocab(args) + + config_yaml = os.path.join(args.data_bin, "config.yaml") + with open(config_yaml, "r") as f: + config = yaml.load(f) + + if "global_cmvn" in config: + global_cmvn = np.load(config["global_cmvn"]["stats_npz_path"]) + else: + global_cmvn = None + + self.feature_extractor = OnlineFeatureExtractor(global_cmvn=global_cmvn) + + self.max_len = args.max_len + + self.force_finish = args.force_finish + + torch.set_grad_enabled(False) + + def to_device(self, tensor): + if self.gpu: + return tensor.cuda() + else: + return tensor.cpu() + + @staticmethod + def add_args(parser): + # fmt: off + parser.add_argument('--model-path', type=str, required=True, + help='path to your pretrained model.') + parser.add_argument("--data-bin", type=str, required=True, + help="Path of data binary") + parser.add_argument("--tgt-splitter-type", type=str, default="SentencePiece", + help="Subword splitter type for target text") + parser.add_argument("--tgt-splitter-path", type=str, default=None, + help="Subword splitter model path for target text") + parser.add_argument("--user-dir", type=str, default="examples/simultaneous_translation", + help="User directory for simultaneous translation") + parser.add_argument("--max-len", type=int, default=200, + help="Max length of translation") + parser.add_argument("--force-finish", default=False, action="store_true", + help="") + # fmt: on + return parser + + def load_model_vocab(self, args): + + filename = args.model_path + if not os.path.exists(filename): + raise IOError("Model file not found: {}".format(filename)) + + state = checkpoint_utils.load_checkpoint_to_cpu(filename) + + task_args = state["cfg"]["task"] + task_args.data = args.data_bin + + task = tasks.setup_task(task_args) + + # build model for ensemble + self.model = task.build_model(state["cfg"]["model"]) + self.model.load_state_dict(state["model"], strict=True) + self.model.eval() + self.model.share_memory() + + if self.gpu: + self.model.cuda() + + # Set dictionary + self.dict = {} + self.dict["tgt"] = task.target_dictionary + + def initialize_states(self, states): + self.feature_extractor.clear_cache() + states.units.source = TensorListEntry() + states.units.target = ListEntry() + states.incremental_states = dict() + + def segment_to_units(self, segment, states): + # Convert speech samples to features + features = self.feature_extractor(segment) + if features is not None: + return [features] + else: + return [] + + def units_to_segment(self, units, states): + # Merge sub word to full word. + if self.model.decoder.dictionary.eos() == units[0]: + return DEFAULT_EOS + + segment = [] + if None in units.value: + units.value.remove(None) + + for index in units: + if index is None: + units.pop() + token = self.model.decoder.dictionary.string([index]) + if token.startswith(BOW_PREFIX): + if len(segment) == 0: + segment += [token.replace(BOW_PREFIX, "")] + else: + for j in range(len(segment)): + units.pop() + + string_to_return = ["".join(segment)] + + if self.model.decoder.dictionary.eos() == units[0]: + string_to_return += [DEFAULT_EOS] + + return string_to_return + else: + segment += [token.replace(BOW_PREFIX, "")] + + if ( + len(units) > 0 + and self.model.decoder.dictionary.eos() == units[-1] + or len(states.units.target) > self.max_len + ): + tokens = [self.model.decoder.dictionary.string([unit]) for unit in units] + return ["".join(tokens).replace(BOW_PREFIX, "")] + [DEFAULT_EOS] + + return None + + def update_model_encoder(self, states): + if len(states.units.source) == 0: + return + src_indices = self.to_device(states.units.source.value.unsqueeze(0)) + src_lengths = self.to_device( + torch.LongTensor([states.units.source.value.size(0)]) + ) + print(src_lengths) + + states.encoder_states = self.model.encoder(src_indices, src_lengths) + torch.cuda.empty_cache() + + def update_states_read(self, states): + # Happens after a read action. + self.update_model_encoder(states) + + def policy(self, states): + if not getattr(states, "encoder_states", None): + return READ_ACTION + + tgt_indices = self.to_device( + torch.LongTensor( + [self.model.decoder.dictionary.eos()] + + [x for x in states.units.target.value if x is not None] + ).unsqueeze(0) + ) + + states.incremental_states["steps"] = { + "src": states.encoder_states["encoder_out"][0].size(0), + "tgt": 1 + len(states.units.target), + } + + states.incremental_states["online"] = True + + x, outputs = self.model.decoder.forward( + prev_output_tokens=tgt_indices, + encoder_out=states.encoder_states, + incremental_state=states.incremental_states, + # features_only=True, + ) + + states.decoder_out = x + + states.decoder_out_extra = outputs + + torch.cuda.empty_cache() + + if outputs["action"] == 0: + return READ_ACTION + else: + return WRITE_ACTION + + def predict(self, states): + decoder_states = states.decoder_out + + lprobs = self.model.get_normalized_probs( + [decoder_states[:, -1:]], log_probs=True + ) + + index = lprobs.argmax(dim=-1) + + torch.cuda.empty_cache() + + index = index[0, 0].item() + + if ( + self.force_finish + and index == self.model.decoder.dictionary.eos() + and not states.finish_read() + ): + index = None + + return index diff --git a/examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py b/examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py new file mode 100644 index 0000000000..45df5fa227 --- /dev/null +++ b/examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py @@ -0,0 +1,200 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import json +import os + +from fairseq import checkpoint_utils, utils, tasks + +from . import DEFAULT_EOS, GET, SEND +from .agent import Agent + + +class SimulTransAgent(Agent): + def __init__(self, args): + # Load Model + self.load_model(args) + + # build word spliter + self.build_word_splitter(args) + + self.max_len = args.max_len + + self.eos = DEFAULT_EOS + + @staticmethod + def add_args(parser): + parser.add_argument( + "--model-path", + type=str, + required=True, + help="path to your pretrained model.", + ) + parser.add_argument( + "--data-bin", type=str, required=True, help="Path of data binary" + ) + parser.add_argument( + "--user-dir", + type=str, + default="example/simultaneous_translation", + help="User directory for simultaneous translation", + ) + parser.add_argument( + "--src-splitter-type", + type=str, + default=None, + help="Subword splitter type for source text", + ) + parser.add_argument( + "--tgt-splitter-type", + type=str, + default=None, + help="Subword splitter type for target text", + ) + parser.add_argument( + "--src-splitter-path", + type=str, + default=None, + help="Subword splitter model path for source text", + ) + parser.add_argument( + "--tgt-splitter-path", + type=str, + default=None, + help="Subword splitter model path for target text", + ) + parser.add_argument( + "--max-len", + type=int, + default=150, + help="Maximum length difference between source and target prediction", + ) + parser.add_argument( + "--model-overrides", + default="{}", + type=str, + metavar="DICT", + help="A dictionary used to override model args at generation " + "that were used during model training", + ) + # fmt: on + return parser + + def load_dictionary(self, task): + raise NotImplementedError + + def load_model(self, args): + args.user_dir = os.path.join(os.path.dirname(__file__), "..", "..") + utils.import_user_module(args) + filename = args.model_path + if not os.path.exists(filename): + raise IOError("Model file not found: {}".format(filename)) + + state = checkpoint_utils.load_checkpoint_to_cpu( + filename, json.loads(args.model_overrides) + ) + + saved_args = state["args"] + saved_args.data = args.data_bin + + task = tasks.setup_task(saved_args) + + # build model for ensemble + self.model = task.build_model(saved_args) + self.model.load_state_dict(state["model"], strict=True) + + # Set dictionary + self.load_dictionary(task) + + def init_states(self): + return { + "indices": {"src": [], "tgt": []}, + "tokens": {"src": [], "tgt": []}, + "segments": {"src": [], "tgt": []}, + "steps": {"src": 0, "tgt": 0}, + "finished": False, + "finish_read": False, + "model_states": {}, + } + + def update_states(self, states, new_state): + raise NotImplementedError + + def policy(self, states): + # Read and Write policy + action = None + + while action is None: + if states["finished"]: + # Finish the hypo by sending eos to server + return self.finish_action() + + # Model make decision given current states + decision = self.model.decision_from_states(states) + + if decision == 0 and not self.finish_read(states): + # READ + action = self.read_action(states) + else: + # WRITE + action = self.write_action(states) + + # None means we make decision again but not sending server anything + # This happened when read a buffered token + # Or predict a subword + return action + + def finish_read(self, states): + raise NotImplementedError + + def write_action(self, states): + token, index = self.model.predict_from_states(states) + + if ( + index == self.dict["tgt"].eos() + or len(states["tokens"]["tgt"]) > self.max_len + ): + # Finish this sentence is predict EOS + states["finished"] = True + end_idx_last_full_word = self._target_length(states) + + else: + states["tokens"]["tgt"] += [token] + end_idx_last_full_word = self.word_splitter["tgt"].end_idx_last_full_word( + states["tokens"]["tgt"] + ) + self._append_indices(states, [index], "tgt") + + if end_idx_last_full_word > states["steps"]["tgt"]: + # Only sent detokenized full words to the server + word = self.word_splitter["tgt"].merge( + states["tokens"]["tgt"][states["steps"]["tgt"] : end_idx_last_full_word] + ) + states["steps"]["tgt"] = end_idx_last_full_word + states["segments"]["tgt"] += [word] + + return {"key": SEND, "value": word} + else: + return None + + def read_action(self, states): + return {"key": GET, "value": None} + + def finish_action(self): + return {"key": SEND, "value": DEFAULT_EOS} + + def reset(self): + pass + + def finish_eval(self, states, new_state): + if len(new_state) == 0 and len(states["indices"]["src"]) == 0: + return True + return False + + def _append_indices(self, states, new_indices, key): + states["indices"][key] += new_indices + + def _target_length(self, states): + return len(states["tokens"]["tgt"]) diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index 5d7f59b3a6..28e3bb720f 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -4,4 +4,6 @@ # LICENSE file in the root directory of this source tree. from .berard import * # noqa +from .convtransformer import * # noqa +from .convtransformer_simul_trans import * # noqa from .s2t_transformer import * # noqa diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py new file mode 100644 index 0000000000..512ee78be0 --- /dev/null +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -0,0 +1,452 @@ +#!/usr/bin/env python3 + +import logging +import math +from typing import Dict, List, Optional, Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F +from examples.simultaneous_translation.utils.data_utils import ( + lengths_to_encoder_padding_mask, +) +from fairseq import checkpoint_utils, utils +from fairseq.models import ( + FairseqEncoder, + FairseqEncoderDecoderModel, + register_model, + register_model_architecture, +) +from fairseq.models.transformer import Embedding, TransformerDecoder +from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerEncoderLayer +from torch import Tensor + +logger = logging.getLogger(__name__) + + +@register_model("convtransformer") +class ConvTransformerModel(FairseqEncoderDecoderModel): + """ + Transformer-based Speech translation model from ESPNet-ST + https://arxiv.org/abs/2004.10234 + """ + + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @staticmethod + def add_args(parser): + """Add model-specific arguments to the parser.""" + parser.add_argument( + "--input-feat-per-channel", + type=int, + metavar="N", + help="encoder input dimension per input channel", + ) + parser.add_argument( + "--activation-fn", + choices=utils.get_available_activation_fns(), + help="activation function to use", + ) + parser.add_argument( + "--dropout", type=float, metavar="D", help="dropout probability" + ) + parser.add_argument( + "--attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights", + ) + parser.add_argument( + "--activation-dropout", + "--relu-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN.", + ) + parser.add_argument( + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension", + ) + parser.add_argument( + "--encoder-ffn-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension for FFN", + ) + parser.add_argument( + "--encoder-layers", type=int, metavar="N", help="num encoder layers" + ) + parser.add_argument( + "--encoder-attention-heads", + type=int, + metavar="N", + help="num encoder attention heads", + ) + parser.add_argument( + "--encoder-normalize-before", + action="store_true", + help="apply layernorm before each encoder block", + ) + parser.add_argument( + "--decoder-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension", + ) + parser.add_argument( + "--decoder-ffn-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension for FFN", + ) + parser.add_argument( + "--decoder-layers", type=int, metavar="N", help="num decoder layers" + ) + parser.add_argument( + "--decoder-attention-heads", + type=int, + metavar="N", + help="num decoder attention heads", + ) + parser.add_argument( + "--decoder-normalize-before", + action="store_true", + help="apply layernorm before each decoder block", + ) + parser.add_argument( + "--decoder-output-dim", + type=int, + metavar="N", + help="decoder output dimension (extra linear layer if different from decoder embed dim)", + ) + parser.add_argument( + "--share-decoder-input-output-embed", + action="store_true", + help="share decoder input and output embeddings", + ) + parser.add_argument( + "--layernorm-embedding", + action="store_true", + help="add layernorm to embedding", + ) + parser.add_argument( + "--no-scale-embedding", + action="store_true", + help="if True, dont scale embeddings", + ) + parser.add_argument( + "--load-pretrained-encoder-from", + type=str, + metavar="STR", + help="model to take encoder weights from (for initialization)", + ) + parser.add_argument( + "--load-pretrained-decoder-from", + type=str, + metavar="STR", + help="model to take decoder weights from (for initialization)", + ) + parser.add_argument( + "--conv-out-channels", + type=int, + metavar="INT", + help="the number of output channels of conv layer", + ) + + @classmethod + def build_encoder(cls, args): + encoder = ConvTransformerEncoder(args) + if getattr(args, "load_pretrained_encoder_from", None): + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=args.load_pretrained_encoder_from + ) + return encoder + + @classmethod + def build_decoder(cls, args, task, embed_tokens): + decoder = TransformerDecoderNoExtra(args, task.target_dictionary, embed_tokens) + if getattr(args, "load_pretrained_decoder_from", None): + decoder = checkpoint_utils.load_pretrained_component_from_model( + component=decoder, checkpoint=args.load_pretrained_decoder_from + ) + return decoder + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + + # make sure all arguments are present in older models + base_architecture(args) + + def build_embedding(dictionary, embed_dim): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + return Embedding(num_embeddings, embed_dim, padding_idx) + + decoder_embed_tokens = build_embedding( + task.target_dictionary, args.decoder_embed_dim + ) + encoder = cls.build_encoder(args) + decoder = cls.build_decoder(args, task, decoder_embed_tokens) + return cls(encoder, decoder) + + @staticmethod + @torch.jit.unused + def set_batch_first(lprobs): + lprobs.batch_first = True + + def get_normalized_probs( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): + # net_output['encoder_out'] is a (B, T, D) tensor + lprobs = self.get_normalized_probs_scriptable(net_output, log_probs, sample) + if self.training: + self.set_batch_first(lprobs) + return lprobs + + def output_layout(self): + return "BTD" + + """ + The forward method inherited from the base class has a **kwargs argument in + its input, which is not supported in torchscript. This method overrites the forward + method definition without **kwargs. + """ + + def forward(self, src_tokens, src_lengths, prev_output_tokens): + encoder_out = self.encoder(src_tokens=src_tokens, src_lengths=src_lengths) + decoder_out = self.decoder( + prev_output_tokens=prev_output_tokens, encoder_out=encoder_out + ) + return decoder_out + + +class ConvTransformerEncoder(FairseqEncoder): + """Conv + Transformer encoder""" + + def __init__(self, args): + """Construct an Encoder object.""" + super().__init__(None) + + self.dropout = args.dropout + self.embed_scale = ( + 1.0 if args.no_scale_embedding else math.sqrt(args.encoder_embed_dim) + ) + self.padding_idx = 1 + self.in_channels = 1 + self.input_dim = args.input_feat_per_channel + self.conv = torch.nn.Sequential( + torch.nn.Conv2d(1, args.conv_out_channels, 3, stride=2, padding=3 // 2), + torch.nn.ReLU(), + torch.nn.Conv2d( + args.conv_out_channels, + args.conv_out_channels, + 3, + stride=2, + padding=3 // 2, + ), + torch.nn.ReLU(), + ) + transformer_input_dim = self.infer_conv_output_dim( + self.in_channels, self.input_dim, args.conv_out_channels + ) + self.out = torch.nn.Linear(transformer_input_dim, args.encoder_embed_dim) + self.embed_positions = PositionalEmbedding( + args.max_source_positions, + args.encoder_embed_dim, + self.padding_idx, + learned=False, + ) + + self.transformer_layers = nn.ModuleList([]) + self.transformer_layers.extend( + [TransformerEncoderLayer(args) for i in range(args.encoder_layers)] + ) + if args.encoder_normalize_before: + self.layer_norm = LayerNorm(args.encoder_embed_dim) + else: + self.layer_norm = None + + def pooling_ratio(self): + return 4 + + def infer_conv_output_dim(self, in_channels, input_dim, out_channels): + sample_seq_len = 200 + sample_bsz = 10 + x = torch.randn(sample_bsz, in_channels, sample_seq_len, input_dim) + x = torch.nn.Conv2d(1, out_channels, 3, stride=2, padding=3 // 2)(x) + x = torch.nn.Conv2d(out_channels, out_channels, 3, stride=2, padding=3 // 2)(x) + x = x.transpose(1, 2) + mb, seq = x.size()[:2] + return x.contiguous().view(mb, seq, -1).size(-1) + + def forward(self, src_tokens, src_lengths): + """Encode input sequence. + :param torch.Tensor xs: input tensor + :param torch.Tensor masks: input mask + :return: position embedded tensor and mask + :rtype Tuple[torch.Tensor, torch.Tensor]: + """ + bsz, max_seq_len, _ = src_tokens.size() + x = ( + src_tokens.view(bsz, max_seq_len, self.in_channels, self.input_dim) + .transpose(1, 2) + .contiguous() + ) + x = self.conv(x) + bsz, _, output_seq_len, _ = x.size() + x = x.transpose(1, 2).transpose(0, 1).contiguous().view(output_seq_len, bsz, -1) + x = self.out(x) + x = self.embed_scale * x + + subsampling_factor = int(max_seq_len * 1.0 / output_seq_len + 0.5) + + input_lengths = min( + (src_lengths.float() / subsampling_factor).ceil().long(), + x.size(0) * src_lengths.new_ones([1]), + ) + + encoder_padding_mask, _ = lengths_to_encoder_padding_mask( + input_lengths, batch_first=True + ) + + positions = self.embed_positions(encoder_padding_mask).transpose(0, 1) + x += positions + x = F.dropout(x, p=self.dropout, training=self.training) + + for layer in self.transformer_layers: + x = layer(x, encoder_padding_mask) + + if not encoder_padding_mask.any(): + maybe_encoder_padding_mask = None + else: + maybe_encoder_padding_mask = encoder_padding_mask + + return { + "encoder_out": [x], + "encoder_padding_mask": [maybe_encoder_padding_mask] + if maybe_encoder_padding_mask is not None + else [], + "encoder_embedding": [], + "encoder_states": [], + "src_tokens": [], + "src_lengths": [], + } + + @torch.jit.export + def reorder_encoder_out(self, encoder_out: Dict[str, List[Tensor]], new_order): + """ + Reorder encoder output according to *new_order*. + + Args: + encoder_out: output from the ``forward()`` method + new_order (LongTensor): desired order + + Returns: + *encoder_out* rearranged according to *new_order* + """ + new_encoder_out = [encoder_out["encoder_out"][0].index_select(1, new_order)] + if len(encoder_out["encoder_padding_mask"]) == 0: + new_encoder_padding_mask = [] + else: + new_encoder_padding_mask = [ + (encoder_out["encoder_padding_mask"][0]).index_select(0, new_order) + ] + if len(encoder_out["encoder_embedding"]) == 0: + new_encoder_embedding = [] + else: + new_encoder_embedding = [ + (encoder_out["encoder_embedding"][0]).index_select(0, new_order) + ] + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: + for idx, state in enumerate(encoder_states): + encoder_states[idx] = state.index_select(1, new_order) + + return { + "encoder_out": new_encoder_out, + "encoder_padding_mask": new_encoder_padding_mask, + "encoder_embedding": new_encoder_embedding, + "encoder_states": encoder_states, + "src_tokens": [], + "src_lengths": [], + } + + +class TransformerDecoderNoExtra(TransformerDecoder): + def extract_features( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + # call scriptable method from parent class + x, _ = self.extract_features_scriptable( + prev_output_tokens, + encoder_out, + incremental_state, + full_context_alignment, + alignment_layer, + alignment_heads, + ) + return x, None + + +@register_model_architecture(model_name="convtransformer", arch_name="convtransformer") +def base_architecture(args): + args.input_feat_per_channel = getattr(args, "input_feat_per_channel", 80) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_layers = getattr(args, "encoder_layers", 6) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 8) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim + ) + args.decoder_layers = getattr(args, "decoder_layers", 6) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.attention_dropout = getattr(args, "attention_dropout", 0.0) + args.activation_dropout = getattr(args, "activation_dropout", 0.0) + args.activation_fn = getattr(args, "activation_fn", "relu") + args.dropout = getattr(args, "dropout", 0.1) + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + args.adaptive_input = getattr(args, "adaptive_input", False) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + args.max_source_positions = getattr(args, "max_source_positions", 3000) + args.max_target_positions = getattr(args, "max_target_positions", 1024) + args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) + args.conv_out_channels = getattr(args, "conv_out_channels", args.encoder_embed_dim) + + +@register_model_architecture("convtransformer", "convtransformer_espnet") +def convtransformer_espnet(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_layers = getattr(args, "encoder_layers", 12) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) diff --git a/fairseq/models/speech_to_text/convtransformer_simul_trans.py b/fairseq/models/speech_to_text/convtransformer_simul_trans.py new file mode 100644 index 0000000000..e5dd771e03 --- /dev/null +++ b/fairseq/models/speech_to_text/convtransformer_simul_trans.py @@ -0,0 +1,49 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +from examples.simultaneous_translation.models.transformer_monotonic_attention import ( + TransformerMonotonicDecoder, +) +from fairseq import checkpoint_utils +from fairseq.models import ( + register_model, + register_model_architecture, +) + +from .convtransformer import ConvTransformerModel, convtransformer_espnet + + +@register_model("convtransformer_simul_trans") +class SimulConvTransformerModel(ConvTransformerModel): + @staticmethod + def add_args(parser): + super(SimulConvTransformerModel, SimulConvTransformerModel).add_args(parser) + parser.add_argument( + "--train-monotonic-only", + action="store_true", + default=False, + help="Only train monotonic attention", + ) + + @classmethod + def build_decoder(cls, args, task, embed_tokens): + tgt_dict = task.tgt_dict + + decoder = TransformerMonotonicDecoder(args, tgt_dict, embed_tokens) + + if getattr(args, "load_pretrained_decoder_from", None): + decoder = checkpoint_utils.load_pretrained_component_from_model( + component=decoder, checkpoint=args.load_pretrained_decoder_from + ) + return decoder + + +@register_model_architecture( + "convtransformer_simul_trans", "convtransformer_simul_trans_espnet" +) +def convtransformer_simul_trans_espnet(args): + convtransformer_espnet(args) From 523fe83828e6374439a6203330ed0e8c13e86b62 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Thu, 18 Feb 2021 22:41:32 -0800 Subject: [PATCH 226/774] Integrate Simul ST model into pyspeech Summary: This diff integrates simul ST training into pyspeech with very minor modifications to the open sourced code. Specific changes made are - In fixed_pre_decision.py remove self as argument to p_choose function as it is already called with super in line 101 - In monotonic_multihead_attention.py remove pdb.set_trace() - Move label_smoothed_cross_entropy_latency_augmented.py to fairseq/criterions folder and add missing arguments to parser - In fairseq/data/data_utils.py type cast max_tokens to int to avoid type error. - Update fairseq/convtransformer.py to pyspeech/convtransformer.py # Next steps: - Verify decoding using the model trained - Support everstore handle based decoding in simuleval and integrate it into pyspeech. Reviewed By: jmp84 Differential Revision: D26478861 fbshipit-source-id: 3b02b2aee757e5464b71dbdd7ebdba42659faee5 --- .../modules/fixed_pre_decision.py | 1 - .../modules/monotonic_multihead_attention.py | 2 -- ...moothed_cross_entropy_latency_augmented.py | 22 ++++++++++++++++++- fairseq/data/data_utils.py | 5 ++++- .../models/speech_to_text/convtransformer.py | 6 +---- 5 files changed, 26 insertions(+), 10 deletions(-) rename {examples/simultaneous_translation => fairseq}/criterions/label_smoothed_cross_entropy_latency_augmented.py (86%) diff --git a/examples/simultaneous_translation/modules/fixed_pre_decision.py b/examples/simultaneous_translation/modules/fixed_pre_decision.py index 2cde55b35e..725be1a983 100644 --- a/examples/simultaneous_translation/modules/fixed_pre_decision.py +++ b/examples/simultaneous_translation/modules/fixed_pre_decision.py @@ -99,7 +99,6 @@ def p_choose( if self.pre_decision_ratio == 1: return super().p_choose( - self, query, key, key_padding_mask=None, diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index 5423f26c34..3e25957cd6 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -259,8 +259,6 @@ def expected_alignment_infer( finish_read = new_monotonic_step.eq(max_steps) | (action == 0) - if p_choose_i is None: - import pdb;pdb.set_trace() monotonic_cache["head_step"] = new_monotonic_step # Whether a head is looking for new input diff --git a/examples/simultaneous_translation/criterions/label_smoothed_cross_entropy_latency_augmented.py b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py similarity index 86% rename from examples/simultaneous_translation/criterions/label_smoothed_cross_entropy_latency_augmented.py rename to fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py index 761cfe61a1..aa3dba31e2 100644 --- a/examples/simultaneous_translation/criterions/label_smoothed_cross_entropy_latency_augmented.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py @@ -53,8 +53,28 @@ def add_args(parser): LatencyAugmentedLabelSmoothedCrossEntropyCriterion, LatencyAugmentedLabelSmoothedCrossEntropyCriterion, ).add_args(parser) - """Add criterion-specific arguments to the parser.""" # fmt: off + + """Add criterion-specific arguments to the parser.""" + parser.add_argument( + "--label-smoothing", + default=0.0, + type=float, + metavar="D", + help="epsilon for label smoothing, 0 means no label smoothing", + ) + parser.add_argument( + "--ignore_prefix_size", + default=0, + type=int, + help="ignore first N tokens", + ) + parser.add_argument( + "--report-accuracy", + default=False, + type=bool, + help="report accuracy metric", + ) parser.add_argument("--latency-weight-avg", default=0., type=float, metavar='D', help="Average loss weight") parser.add_argument("--latency-weight-var", default=0., type=float, metavar='D', diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 47d8492ec9..3042358f2f 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -313,7 +313,10 @@ def batch_by_size( " --editable .` or `python setup.py build_ext --inplace`." ) - max_tokens = max_tokens if max_tokens is not None else -1 + # added int() to avoid TypeError: an integer is required + max_tokens = ( + int(max_tokens) if max_tokens is not None else -1 + ) max_sentences = max_sentences if max_sentences is not None else -1 bsz_mult = required_batch_size_multiple diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py index 512ee78be0..06276e636a 100644 --- a/fairseq/models/speech_to_text/convtransformer.py +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -307,11 +307,7 @@ def forward(self, src_tokens, src_lengths): subsampling_factor = int(max_seq_len * 1.0 / output_seq_len + 0.5) - input_lengths = min( - (src_lengths.float() / subsampling_factor).ceil().long(), - x.size(0) * src_lengths.new_ones([1]), - ) - + input_lengths = (src_lengths.float() / subsampling_factor).ceil().long() encoder_padding_mask, _ = lengths_to_encoder_padding_mask( input_lengths, batch_first=True ) From 675f608915a216ac32777928a0b1e8210cb66df6 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Fri, 19 Feb 2021 08:59:37 -0800 Subject: [PATCH 227/774] Fix LibriSpeech data prep script Summary: Fix LibriSpeech data prep script * Lowercasing transcript to be consistent with the pre-trained models Reviewed By: jmp84 Differential Revision: D26538845 fbshipit-source-id: 0885f99e2c85f0e722a24f3cb83f2635ce9429bc --- examples/speech_to_text/prep_librispeech_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_to_text/prep_librispeech_data.py b/examples/speech_to_text/prep_librispeech_data.py index 6a6f55ded4..7b08447190 100644 --- a/examples/speech_to_text/prep_librispeech_data.py +++ b/examples/speech_to_text/prep_librispeech_data.py @@ -71,7 +71,7 @@ def process(args): manifest["audio"].append(zip_manifest[sample_id]) duration_ms = int(wav.size(1) / sample_rate * 1000) manifest["n_frames"].append(int(1 + (duration_ms - 25) / 10)) - manifest["tgt_text"].append(utt) + manifest["tgt_text"].append(utt.lower()) manifest["speaker"].append(spk_id) save_df_to_tsv( pd.DataFrame.from_dict(manifest), out_root / f"{split}.tsv" From 2909ee1852cdae7ad4115a1a04520b0522265dd2 Mon Sep 17 00:00:00 2001 From: "joseph.suh" <joseph.suh@netmarble.com> Date: Fri, 19 Feb 2021 10:07:43 -0800 Subject: [PATCH 228/774] Fix bug for issue (#3211) (#3212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes KeyError mentioned in # (3211). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3212 Reviewed By: alexeib Differential Revision: D26513255 Pulled By: myleott fbshipit-source-id: 5a11cb369c9d4202fab6998d269e7da5f3d3e534 --- fairseq/trainer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index e860fb1832..f66dc25e40 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -401,7 +401,7 @@ def load_checkpoint( self.lr_step(epoch) - if itr_state["version"] >= 2 and itr_state["iterations_in_epoch"] == 0: + if itr_state.get("version", 1) >= 2 and itr_state["iterations_in_epoch"] == 0: # reset meters at start of epoch reset_meters = True From 3ef18886d0a802a8c8d90b57d858df3da7e75202 Mon Sep 17 00:00:00 2001 From: Alex Gaziev <alex.gaziev@gmail.com> Date: Fri, 19 Feb 2021 10:10:13 -0800 Subject: [PATCH 229/774] Remove extra arg min_length and fix min_sample_size behavior (#3249) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3178 (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � (I did ;) Pull Request resolved: https://github.com/pytorch/fairseq/pull/3249 Reviewed By: alexeib Differential Revision: D26513275 Pulled By: myleott fbshipit-source-id: 2785098a945404c07eb72c079177654b1739a7a2 --- fairseq/data/audio/raw_audio_dataset.py | 10 +++------- fairseq/tasks/audio_pretraining.py | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index ac5acd03bb..1d92e4966b 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -23,9 +23,8 @@ def __init__( self, sample_rate, max_sample_size=None, - min_sample_size=None, + min_sample_size=0, shuffle=True, - min_length=0, pad=False, normalize=False, ): @@ -37,7 +36,6 @@ def __init__( max_sample_size if max_sample_size is not None else sys.maxsize ) self.min_sample_size = min_sample_size - self.min_length = min_length self.pad = pad self.shuffle = shuffle self.normalize = normalize @@ -136,9 +134,8 @@ def __init__( manifest_path, sample_rate, max_sample_size=None, - min_sample_size=None, + min_sample_size=0, shuffle=True, - min_length=0, pad=False, normalize=False, ): @@ -147,7 +144,6 @@ def __init__( max_sample_size=max_sample_size, min_sample_size=min_sample_size, shuffle=shuffle, - min_length=min_length, pad=pad, normalize=normalize, ) @@ -162,7 +158,7 @@ def __init__( items = line.strip().split("\t") assert len(items) == 2, line sz = int(items[1]) - if min_length is not None and sz < min_length: + if min_sample_size is not None and sz < min_sample_size: skipped += 1 continue self.fnames.append(items[0]) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 92685160d4..b7b5429819 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -57,7 +57,7 @@ class AudioPretrainingConfig(FairseqDataclass): default=None, metadata={"help": "max sample size to crop to for batching"} ) min_sample_size: Optional[int] = field( - default=None, metadata={"help": "min sample size to crop to for batching"} + default=None, metadata={"help": "min sample size to skip small examples"} ) # Options for reporting WER metrics during validation. Only applicable to @@ -135,8 +135,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): manifest, sample_rate=task_cfg.get('sample_rate', self.cfg.sample_rate), max_sample_size=self.cfg.max_sample_size, - min_sample_size=self.cfg.max_sample_size, - min_length=self.cfg.min_sample_size, + min_sample_size=self.cfg.min_sample_size, pad=task_cfg.labels is not None or task_cfg.enable_padding, normalize=task_cfg.normalize, ) From c6b5c00312dc23f473c66ba3016cc9e3decfd317 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Fri, 19 Feb 2021 10:31:08 -0800 Subject: [PATCH 230/774] fix criterion name check when resuming from checkpoint Summary: I tried resuming a run from a checkpoint in f250883864, but ran into: AssertionError: Criterion does not match; please reset the optimizer (--reset-optimizer). DistributedTimeoutWrapper vs ContrastiveLabelsCriterion Based on this, I believe since D25836853 (https://github.com/pytorch/fairseq/commit/d68a3530dda7f8275e490864b28974ef30fe854b) we are no longer saving the actual criterion's name, but DistributedTimeoutWrapper in the checkpoint. This is kind of weird though, as I would expect more people to run into this issue. Not sure if I am doing something wrong, let me know if so, thanks! Reviewed By: myleott Differential Revision: D26478656 fbshipit-source-id: bc3c7c925f5505140d9df4438af3a73d65d4f531 --- fairseq/trainer.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index f66dc25e40..891155f162 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -284,7 +284,7 @@ def save_checkpoint(self, filename, extra_state): filename, self.cfg, self.model.state_dict(), - self.criterion, + self.get_criterion(), self.optimizer, self.lr_scheduler, self.get_num_updates(), @@ -375,10 +375,10 @@ def load_checkpoint( last_optim = self._optim_history[-1] assert ( last_optim["criterion_name"] == self.get_criterion().__class__.__name__ - ), "Criterion does not match; please reset the optimizer (--reset-optimizer)." + ), f"Criterion does not match; please reset the optimizer (--reset-optimizer). {last_optim['criterion_name']} vs {self.get_criterion().__class__.__name__}" assert ( last_optim["optimizer_name"] == self.optimizer.__class__.__name__ - ), "Optimizer does not match; please reset the optimizer (--reset-optimizer)." + ), f"Optimizer does not match; please reset the optimizer (--reset-optimizer). {last_optim['optimizer_name']} vs {self.optimizer.__class__.__name__}" if not reset_lr_scheduler: self.lr_scheduler.load_state_dict(last_optim["lr_scheduler_state"]) From ae22da652d63bd6e05a9a035f6a9dcabb1a39c73 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Fri, 19 Feb 2021 21:52:31 -0800 Subject: [PATCH 231/774] Correct the estimation of cnn output lengths in convtransformer (#1636) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1636 Reviewed By: xutaima Differential Revision: D26562816 Pulled By: jmp84 fbshipit-source-id: 4e6efd0b4236d7187bd365d790f260bd5297aed5 --- fairseq/models/speech_to_text/convtransformer.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py index 06276e636a..622b5e6df8 100644 --- a/fairseq/models/speech_to_text/convtransformer.py +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -30,7 +30,6 @@ class ConvTransformerModel(FairseqEncoderDecoderModel): Transformer-based Speech translation model from ESPNet-ST https://arxiv.org/abs/2004.10234 """ - def __init__(self, encoder, decoder): super().__init__(encoder, decoder) @@ -307,7 +306,11 @@ def forward(self, src_tokens, src_lengths): subsampling_factor = int(max_seq_len * 1.0 / output_seq_len + 0.5) - input_lengths = (src_lengths.float() / subsampling_factor).ceil().long() + input_lengths = torch.min( + (src_lengths.float() / subsampling_factor).ceil().long(), + x.size(0) * src_lengths.new_ones([src_lengths.size(0)]).long() + ) + encoder_padding_mask, _ = lengths_to_encoder_padding_mask( input_lengths, batch_first=True ) From 61e46bb99758e05bc990e3687c69b507a8ebf185 Mon Sep 17 00:00:00 2001 From: Frankie Robertson <frankie@robertson.name> Date: Sat, 20 Feb 2021 06:21:45 -0800 Subject: [PATCH 232/774] Fix attempt to unlink directory copied into source package (Python 3.9) (#3235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [N/A] Did you make sure to update the docs? - [N/A] Did you write any new necessary tests? ## What does this PR do? Currently when installing the newest source package from PyPI I get an error like so: ``` Collecting fairseq Using cached fairseq-0.10.2.tar.gz (938 kB) Installing build dependencies ... done Getting requirements to build wheel ... error ERROR: Command errored out with exit status 1: command: /home/frankier/sources/datasets/.venv/bin/python3 /tmp/tmp_ujftsgi_in_process.py get_requires_for_build_wheel /tmp/tmpmn0eumq2 cwd: /tmp/pip-install-dg5d6q9y/fairseq Complete output (31 lines): Traceback (most recent call last): File "setup.py", line 214, in <module> do_setup(package_data) File "setup.py", line 136, in do_setup setup( File "/tmp/pip-build-env-hag0sxvp/overlay/lib/python3.9/site-packages/setuptools/__init__.py", line 152, in setup _install_setup_requires(attrs) File "/tmp/pip-build-env-hag0sxvp/overlay/lib/python3.9/site-packages/setuptools/__init__.py", line 147, in _install_setup_requires dist.fetch_build_eggs(dist.setup_requires) File "/tmp/pip-build-env-hag0sxvp/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 60, in fetch_build_eggs raise SetupRequirementsError(specifier_list) setuptools.build_meta.SetupRequirementsError: ['cython', 'numpy', 'setuptools>=18.0'] During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/tmp/tmp_ujftsgi_in_process.py", line 280, in <module> main() File "/tmp/tmp_ujftsgi_in_process.py", line 263, in main json_out['return_val'] = hook(**hook_input['kwargs']) File "/tmp/tmp_ujftsgi_in_process.py", line 114, in get_requires_for_build_wheel return hook(config_settings) File "/tmp/pip-build-env-hag0sxvp/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 149, in get_requires_for_build_wheel return self._get_build_requires( File "/tmp/pip-build-env-hag0sxvp/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 130, in _get_build_requires self.run_setup() File "/tmp/pip-build-env-hag0sxvp/overlay/lib/python3.9/site-packages/setuptools/build_meta.py", line 145, in run_setup exec(compile(code, __file__, 'exec'), locals()) File "setup.py", line 217, in <module> os.unlink(fairseq_examples) IsADirectoryError: [Errno 21] Is a directory: 'fairseq/examples' ---------------------------------------- ERROR: Command errored out with exit status 1: /home/frankier/sources/datasets/.venv/bin/python3 /tmp/tmp_ujftsgi_in_process.py get_requires_for_build_wheel /tmp/tmpmn0eumq2 Check the logs for full command output. ``` I believe the reason for this is that the source package contains the examples directory because it was put there during package creation (it seems the symlink because a directory). Now, when setup.py is run again, it seems the setup.py attempts to unlink the directory, which is not possible because only symlinks can be unlinked. This PR therefore only attempts to unlink it if it is a symlink. I have not thoroughly tested whether my proposed cause is the true cause, but this should fix it in any case. Note that the source package is fetched because there is no wheel for Python 3.9, so most users will not see this because they will use the wheel. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3235 Reviewed By: alexeib Differential Revision: D26513259 Pulled By: myleott fbshipit-source-id: 775d6c636a5867b9983bb6419829f13ee414e2fd --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d1a976104e..3670ff3cfc 100644 --- a/setup.py +++ b/setup.py @@ -256,5 +256,5 @@ def get_files(path, relative_to="fairseq"): } do_setup(package_data) finally: - if "build_ext" not in sys.argv[1:] and os.path.exists(fairseq_examples): + if "build_ext" not in sys.argv[1:] and os.path.islink(fairseq_examples): os.unlink(fairseq_examples) From 4cf7d76114d50008cdd98a7fde250d4ef99b66fe Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Sat, 20 Feb 2021 06:23:41 -0800 Subject: [PATCH 233/774] Hydra Integration doc should refer to non legacy task (#1619) Summary: # Before submitting - [NO] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [YES] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [YES] Did you make sure to update the docs? - [NO] Did you write any new necessary tests? ## What does this PR do? This is a typo fix to the Hydra Integration doc where the example with dataclass config should user `FairseqTask` and not `LegacyFairseqTask`. Didn't make an issue for this as it's a trivial doc change for the example to match the actual doc. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1619 Reviewed By: huihuifan Differential Revision: D26448855 Pulled By: Mortimerp9 fbshipit-source-id: 467323101b8425370f6bd7c0532e70abb319b337 --- docs/hydra_integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hydra_integration.md b/docs/hydra_integration.md index 04c797fe50..6a15298382 100644 --- a/docs/hydra_integration.md +++ b/docs/hydra_integration.md @@ -120,7 +120,7 @@ class LanguageModelingConfig(FairseqDataclass): ... @register_task("language_modeling", dataclass=LanguageModelingConfig) -class LanguageModelingTask(LegacyFairseqTask): +class LanguageModelingTask(FairseqTask): ... @classmethod def setup_task(cls, cfg: LanguageModelingConfig): From 38258a79a42f3ccfa596cc51bbf269cf13c3d799 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Mon, 22 Feb 2021 13:55:06 -0800 Subject: [PATCH 234/774] Update FairseqSimulSTAgent to make it generic and reusable internally Summary: This diff 1. Updates FairseqSimulSTAgent to make it generic and reusable internally [Touches OSS] 2. Adds FBFairseqSimulSTAgent inheriting FairseqSimulSTAgent 3. Add TARGETS file in examples/speech_to_text 4. Update simuleval TARGETS and add a bento kernel for easy testing Reviewed By: jmp84 Differential Revision: D26573214 fbshipit-source-id: f4b71f90693cc878cc771b46a006bcbc83a50124 --- .../agents/fairseq_simul_st_agent.py | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index cbe8bc4322..32cd0a1f61 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -27,25 +27,18 @@ class OnlineFeatureExtractor: Extract speech feature on the fly. """ - def __init__( - self, - shift_size=SHIFT_SIZE, - window_size=WINDOW_SIZE, - sample_rate=SAMPLE_RATE, - feature_dim=FEATURE_DIM, - global_cmvn=None, - ): - self.shift_size = shift_size - self.window_size = window_size + def __init__(self, args): + self.shift_size = args.shift_size + self.window_size = args.window_size assert self.window_size >= self.shift_size - self.sample_rate = sample_rate - self.feature_dim = feature_dim - self.num_samples_per_shift = int(SHIFT_SIZE * SAMPLE_RATE / 1000) - self.num_samples_per_window = int(WINDOW_SIZE * SAMPLE_RATE / 1000) + self.sample_rate = args.sample_rate + self.feature_dim = args.feature_dim + self.num_samples_per_shift = int(self.shift_size * self.sample_rate / 1000) + self.num_samples_per_window = int(self.window_size * self.sample_rate / 1000) self.len_ms_to_samples = lambda x: x * self.sample_rate / 1000 self.previous_residual_samples = [] - self.global_cmvn = global_cmvn + self.global_cmvn = args.global_cmvn def clear_cache(self): self.previous_residual_samples = [] @@ -134,16 +127,15 @@ def __init__(self, args): self.load_model_vocab(args) - config_yaml = os.path.join(args.data_bin, "config.yaml") - with open(config_yaml, "r") as f: + with open(args.config, "r") as f: config = yaml.load(f) if "global_cmvn" in config: - global_cmvn = np.load(config["global_cmvn"]["stats_npz_path"]) + args.global_cmvn = np.load(config["global_cmvn"]["stats_npz_path"]) else: - global_cmvn = None + args.global_cmvn = None - self.feature_extractor = OnlineFeatureExtractor(global_cmvn=global_cmvn) + self.feature_extractor = OnlineFeatureExtractor(args) self.max_len = args.max_len @@ -164,6 +156,8 @@ def add_args(parser): help='path to your pretrained model.') parser.add_argument("--data-bin", type=str, required=True, help="Path of data binary") + parser.add_argument("--config", type=str, required=True, + help="Path to config yaml file") parser.add_argument("--tgt-splitter-type", type=str, default="SentencePiece", help="Subword splitter type for target text") parser.add_argument("--tgt-splitter-path", type=str, default=None, @@ -174,9 +168,21 @@ def add_args(parser): help="Max length of translation") parser.add_argument("--force-finish", default=False, action="store_true", help="") + parser.add_argument("--shift-size", type=int, default=SHIFT_SIZE, + help="") + parser.add_argument("--window-size", type=int, default=WINDOW_SIZE, + help="") + parser.add_argument("--sample-rate", type=int, default=SAMPLE_RATE, + help="") + parser.add_argument("--feature-dim", type=int, default=FEATURE_DIM, + help="") + # fmt: on return parser + def set_up_task(self, task_args): + return tasks.setup_task(task_args) + def load_model_vocab(self, args): filename = args.model_path @@ -188,7 +194,7 @@ def load_model_vocab(self, args): task_args = state["cfg"]["task"] task_args.data = args.data_bin - task = tasks.setup_task(task_args) + task = self.set_up_task(task_args) # build model for ensemble self.model = task.build_model(state["cfg"]["model"]) From 808b751597d85c098990080d21fd450877dcb242 Mon Sep 17 00:00:00 2001 From: Miguel Del-Agua <miguel.delagua@nuance.com> Date: Mon, 22 Feb 2021 14:21:36 -0800 Subject: [PATCH 235/774] Improve torchscript compatibility of transfomer and transformer pg (#3247) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3246 Fixes https://github.com/pytorch/fairseq/issues/3248 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3247 Reviewed By: myleott Differential Revision: D26513267 Pulled By: lematt1991 fbshipit-source-id: 958de0b3a58a0dd2a56bd6c6d7fb2644a89f6746 --- .../pointer_generator_src/transformer_pg.py | 80 +++++++++++++++---- fairseq/models/fairseq_decoder.py | 13 +++ fairseq/models/transformer.py | 47 +++++++++-- tests/test_export.py | 13 +++ 4 files changed, 133 insertions(+), 20 deletions(-) diff --git a/examples/pointer_generator/pointer_generator_src/transformer_pg.py b/examples/pointer_generator/pointer_generator_src/transformer_pg.py index fb40a80836..e109a8e269 100644 --- a/examples/pointer_generator/pointer_generator_src/transformer_pg.py +++ b/examples/pointer_generator/pointer_generator_src/transformer_pg.py @@ -4,13 +4,12 @@ # LICENSE file in the root directory of this source tree. import logging -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, List, Tuple import torch import torch.nn as nn from fairseq import metrics, utils from fairseq.models import register_model, register_model_architecture -from fairseq.models.fairseq_encoder import EncoderOut from fairseq.models.transformer import ( DEFAULT_MAX_SOURCE_POSITIONS, DEFAULT_MAX_TARGET_POSITIONS, @@ -155,7 +154,13 @@ class TransformerPointerGeneratorEncoder(TransformerEncoder): to the decoder. """ - def forward(self, src_tokens, src_lengths, **kwargs): + def forward( + self, + src_tokens, + src_lengths: Optional[Tensor] = None, + return_all_hiddens: bool = False, + token_embeddings: Optional[Tensor] = None + ): """ Runs the `forward()` method of the parent Transformer class. Then adds the source tokens into the encoder output tuple. @@ -169,6 +174,10 @@ def forward(self, src_tokens, src_lengths, **kwargs): shape `(batch, src_len)` src_lengths (torch.LongTensor): lengths of each source sentence of shape `(batch)` + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + token_embeddings (torch.Tensor, optional): precomputed embeddings + default `None` will recompute embeddings Returns: namedtuple: @@ -184,7 +193,15 @@ def forward(self, src_tokens, src_lengths, **kwargs): - **src_tokens** (Tensor): input token ids of shape `(batch, src_len)` """ - encoder_out = super().forward(src_tokens, src_lengths, **kwargs) + encoder_out = self.forward_scriptable(src_tokens, + src_lengths, + return_all_hiddens, + token_embeddings) + + # The Pytorch Mobile lite interpreter does not supports returning NamedTuple in + # `forward` so we use a dictionary instead. + # TorchScript does not support mixed values so the values are all lists. + # The empty list is equivalent to None. return { "encoder_out": encoder_out["encoder_out"], # T x B x C "encoder_padding_mask": encoder_out["encoder_padding_mask"], # B x T @@ -236,7 +253,7 @@ def __init__(self, args, dictionary, embed_tokens): def forward( self, prev_output_tokens, - encoder_out: Optional[EncoderOut] = None, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, features_only: bool = False, alignment_layer: Optional[int] = 0, @@ -248,8 +265,8 @@ def forward( Args: prev_output_tokens (LongTensor): previous decoder outputs of shape `(batch, tgt_len)`, for teacher forcing - encoder_out (EncoderOut, optional): output from the encoder, used - for encoder-side attention + encoder_out (optional): output from the encoder, used for + encoder-side attention incremental_state (dict, optional): dictionary used for storing state during :ref:`Incremental decoding` features_only (bool, optional): only return features without @@ -284,10 +301,21 @@ def forward( predictors = torch.cat((prev_output_embed, x), 2) p_gens = self.project_p_gens(predictors) p_gens = torch.sigmoid(p_gens) - x = self.output_layer(x, extra["attn"][0], encoder_out["src_tokens"][0], p_gens) + # Torchscript complains if encoder_out or attn are None because + # `output_layer()` signature expects tensors instead + attn: Optional[Tensor] = extra["attn"][0] + assert encoder_out is not None + assert attn is not None + x = self.output_layer(x, attn, encoder_out["src_tokens"][0], p_gens) return x, extra - def output_layer(self, features, attn, src_tokens, p_gens, **kwargs): + def output_layer( + self, + features: Tensor, + attn: Tensor, + src_tokens: Tensor, + p_gens: Tensor + ) -> Tensor: """ Project features to the vocabulary size and mix with the attention distributions. @@ -296,7 +324,10 @@ def output_layer(self, features, attn, src_tokens, p_gens, **kwargs): p_gens = self.force_p_gen # project back to size of vocabulary - logits = super().output_layer(features, **kwargs) + if self.adaptive_softmax is None: + logits = self.output_projection(features) + else: + logits = features batch_size = logits.shape[0] output_length = logits.shape[1] @@ -306,7 +337,7 @@ def output_layer(self, features, attn, src_tokens, p_gens, **kwargs): # The final output distribution will be a mixture of the normal output # distribution (softmax of logits) and attention weights. - gen_dists = super().get_normalized_probs( + gen_dists = self.get_normalized_probs_scriptable( (logits, None), log_probs=False, sample=None ) gen_dists = torch.mul(gen_dists, p_gens) @@ -330,7 +361,12 @@ def output_layer(self, features, attn, src_tokens, p_gens, **kwargs): # Final distributions, [batch_size, output_length, num_types]. return gen_dists + attn_dists - def get_normalized_probs(self, net_output, log_probs, sample): + def get_normalized_probs( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): """ Get normalized probabilities (or log probs) from a net's output. Pointer-generator network output is already normalized. @@ -375,8 +411,19 @@ class Embedding(nn.Embedding): """ __constants__ = ["unk_idx"] - def __init__(self, num_embeddings, embedding_dim, padding_idx, unk_idx): - super().__init__(num_embeddings, embedding_dim, padding_idx=padding_idx) + # Torchscript: Inheriting from Embedding class produces an error when exporting to Torchscript + # -> RuntimeError: Unable to cast Python instance to C++ type (compile in debug mode for details + # It's happening because max_norm attribute from nn.Embedding is None by default and it cannot be + # cast to a C++ type + def __init__( + self, + num_embeddings: int, + embedding_dim: int, + padding_idx: Optional[int], + unk_idx: int, + max_norm: Optional[float] = float("inf"), + ): + super().__init__(num_embeddings, embedding_dim, padding_idx=padding_idx, max_norm=max_norm) self.unk_idx = unk_idx nn.init.normal_(self.weight, mean=0, std=embedding_dim ** -0.5) nn.init.constant_(self.weight[padding_idx], 0) @@ -385,7 +432,10 @@ def forward(self, input): input = torch.where( input >= self.num_embeddings, torch.ones_like(input) * self.unk_idx, input ) - return super().forward(input) + return nn.functional.embedding( + input, self.weight, self.padding_idx, self.max_norm, + self.norm_type, self.scale_grad_by_freq, self.sparse + ) @register_model_architecture( diff --git a/fairseq/models/fairseq_decoder.py b/fairseq/models/fairseq_decoder.py index 7eeb5c652f..4f1e8b52a2 100644 --- a/fairseq/models/fairseq_decoder.py +++ b/fairseq/models/fairseq_decoder.py @@ -64,6 +64,19 @@ def get_normalized_probs( sample: Optional[Dict[str, Tensor]] = None, ): """Get normalized probabilities (or log probs) from a net's output.""" + return self.get_normalized_probs_scriptable(net_output, log_probs, sample) + + # TorchScript doesn't support super() method so that the scriptable Subclass + # can't access the base class model in Torchscript. + # Current workaround is to add a helper function with different name and + # call the helper function from scriptable Subclass. + def get_normalized_probs_scriptable( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): + """Get normalized probabilities (or log probs) from a net's output.""" if hasattr(self, "adaptive_softmax") and self.adaptive_softmax is not None: if sample is not None: diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 605cfa65e8..f2f36baf3e 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -422,6 +422,45 @@ def forward( token_embeddings (torch.Tensor, optional): precomputed embeddings default `None` will recompute embeddings + Returns: + dict: + - **encoder_out** (Tensor): the last encoder layer's output of + shape `(src_len, batch, embed_dim)` + - **encoder_padding_mask** (ByteTensor): the positions of + padding elements of shape `(batch, src_len)` + - **encoder_embedding** (Tensor): the (scaled) embedding lookup + of shape `(batch, src_len, embed_dim)` + - **encoder_states** (List[Tensor]): all intermediate + hidden states of shape `(src_len, batch, embed_dim)`. + Only populated if *return_all_hiddens* is True. + """ + return self.forward_scriptable(src_tokens, + src_lengths, + return_all_hiddens, + token_embeddings) + + # TorchScript doesn't support super() method so that the scriptable Subclass + # can't access the base class model in Torchscript. + # Current workaround is to add a helper function with different name and + # call the helper function from scriptable Subclass. + def forward_scriptable( + self, + src_tokens, + src_lengths: Optional[torch.Tensor] = None, + return_all_hiddens: bool = False, + token_embeddings: Optional[torch.Tensor] = None, + ): + """ + Args: + src_tokens (LongTensor): tokens in the source language of shape + `(batch, src_len)` + src_lengths (torch.LongTensor): lengths of each source sentence of + shape `(batch)` + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + token_embeddings (torch.Tensor, optional): precomputed embeddings + default `None` will recompute embeddings + Returns: dict: - **encoder_out** (Tensor): the last encoder layer's output of @@ -787,13 +826,11 @@ def extract_features_scriptable( alignment_layer = self.num_layers - 1 # embed positions - positions = ( - self.embed_positions( + positions = None + if self.embed_positions is not None: + positions = self.embed_positions( prev_output_tokens, incremental_state=incremental_state ) - if self.embed_positions is not None - else None - ) if incremental_state is not None: prev_output_tokens = prev_output_tokens[:, -1:] diff --git a/tests/test_export.py b/tests/test_export.py index 87e52bd7c1..b380697b9a 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -103,6 +103,19 @@ def test_export_transformer(self): scripted = torch.jit.script(model) _test_save_and_load(scripted) + @unittest.skipIf( + torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" + ) + def test_export_transformer_no_token_pos_emb(self): + task, parser = get_dummy_task_and_parser() + TransformerModel.add_args(parser) + args = parser.parse_args([]) + args.no_token_positional_embeddings = True + model = TransformerModel.build_model(args, task) + scripted = torch.jit.script(model) + _test_save_and_load(scripted) + + if __name__ == "__main__": unittest.main() From 89cd70c0f0c096bdbfcfb2ab339a9c8f23540bc0 Mon Sep 17 00:00:00 2001 From: m_fomicheva <mari.fomicheva@gmail.com> Date: Mon, 22 Feb 2021 14:55:33 -0800 Subject: [PATCH 236/774] Fixed scripts and instructions for reproducing the results. (#3264) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [N] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [Y] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [Y] Did you make sure to update the docs? - [N] Did you write any new necessary tests? ## What does this PR do? Small fixes in the script and documentation for correctly reproducing the results in the corresponding paper. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3264 Reviewed By: lematt1991 Differential Revision: D26587397 Pulled By: myleott fbshipit-source-id: 3675ec4d4388cafa224d395e08b53667f142cb27 --- examples/unsupervised_quality_estimation/README.md | 6 +++--- examples/unsupervised_quality_estimation/meteor.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/unsupervised_quality_estimation/README.md b/examples/unsupervised_quality_estimation/README.md index aeb96a14b1..e86a0d13b8 100644 --- a/examples/unsupervised_quality_estimation/README.md +++ b/examples/unsupervised_quality_estimation/README.md @@ -55,7 +55,7 @@ Translate ``` CUDA_VISIBLE_DEVICES=$GPU fairseq-generate $TMP/bin --path ${MODEL_DIR}/${SRC_LANG}-${TGT_LANG}.pt --beam 5 --source-lang $SRC_LANG --target-lang $TGT_LANG --no-progress-bar --unkpen 5 > $TMP/fairseq.out -grep ^H $TMP/fairseq.out | cut -f3- > $TMP/mt.out +grep ^H $TMP/fairseq.out | cut -d- -f2- | sort -n | cut -f3- > $TMP/mt.out ``` Post-process @@ -88,7 +88,7 @@ CUDA_VISIBLE_DEVICES=${GPU} fairseq-generate ${TMP}/bin-repeated --path ${MODEL_ --retain-dropout-modules '["TransformerModel","TransformerEncoder","TransformerDecoder","TransformerEncoderLayer"]' TransformerDecoderLayer --seed 46 > $TMP/dropout.scoring.out -grep ^H $TMP/dropout.scoring.out | cut -f2- > $TMP/dropout.scores +grep ^H $TMP/dropout.scoring.out | cut -d- -f2- | sort -n | cut -f2 > $TMP/dropout.scores ``` @@ -112,7 +112,7 @@ CUDA_VISIBLE_DEVICES=${GPU} fairseq-generate ${TMP}/bin-repeated --path ${MODEL_ --unkpen 5 --retain-dropout-modules TransformerModel TransformerEncoder TransformerDecoder TransformerEncoderLayer TransformerDecoderLayer --seed 46 > $TMP/dropout.generation.out -grep ^H $TMP/dropout.generation.out | cut -f3- > $TMP/dropout.hypotheses_ +grep ^H $TMP/dropout.generation.out | cut -d- -f2- | sort -n | cut -f3- > $TMP/dropout.hypotheses_ sed -r 's/(@@ )| (@@ ?$)//g' < $TMP/dropout.hypotheses_ | perl $MOSES_DECODER/scripts/tokenizer/detokenizer.perl -l $TGT_LANG > $TMP/dropout.hypotheses diff --git a/examples/unsupervised_quality_estimation/meteor.py b/examples/unsupervised_quality_estimation/meteor.py index 4a214e794d..2ee0448cf1 100644 --- a/examples/unsupervised_quality_estimation/meteor.py +++ b/examples/unsupervised_quality_estimation/meteor.py @@ -85,19 +85,19 @@ def read_output(meteor_output_path, n_repeats): def main(): parser = argparse.ArgumentParser() - parser.add_argument("-i", "--input") + parser.add_argument("-i", "--infile") parser.add_argument("-n", "--repeat_times", type=int) parser.add_argument("-m", "--meteor") parser.add_argument("-o", "--output") args = parser.parse_args() - translations = read_translations(args.infile, args.repetitions) + translations = read_translations(args.infile, args.repeat_times) sys.stderr.write("\nGenerating input for Meteor...") - ref_path, mt_path = generate_input(translations, args.repetitions) + ref_path, mt_path = generate_input(translations, args.repeat_times) sys.stderr.write("\nRunning Meteor...") out_path = run_meteor(ref_path, mt_path, args.meteor) sys.stderr.write("\nReading output...") - scores = read_output(out_path, args.repetitions) + scores = read_output(out_path, args.repeat_times) sys.stderr.write("\nWriting results...") with open(args.output, "w") as o: for scr in scores: From b9778da42643f5b20fa0a555834d49537ce165c0 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Mon, 22 Feb 2021 15:00:15 -0800 Subject: [PATCH 237/774] Small fixes for flow-cli usage Summary: - Use `PathManager.ls` instead of `os.listdir` - Add version.txt to fairseq TARGETS Reviewed By: vishrav Differential Revision: D26579091 fbshipit-source-id: 20d57dc19335a3006cd5fa6d1a3d5e878b105874 --- fairseq/data/data_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 3042358f2f..6f7561afbe 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -17,6 +17,8 @@ import numpy as np import torch +from fairseq.file_io import PathManager + logger = logging.getLogger(__name__) @@ -24,7 +26,7 @@ def infer_language_pair(path): """Infer language pair from filename: <split>.<lang1>-<lang2>.(...).idx""" src, dst = None, None - for filename in os.listdir(path): + for filename in PathManager.ls(path): parts = filename.split(".") if len(parts) >= 3 and len(parts[1].split("-")) == 2: return parts[1].split("-") From ab560669cd9baaa4009e1fd01c970f8ffccd1ee0 Mon Sep 17 00:00:00 2001 From: freewym <freewym@gmail.com> Date: Mon, 22 Feb 2021 15:36:56 -0800 Subject: [PATCH 238/774] Fixes circular import as complained by python (#3257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? fixes circular import as complained by python ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3257 Reviewed By: jmp84 Differential Revision: D26587382 Pulled By: myleott fbshipit-source-id: a8a6e7bee4dcfa6baf934c257958b7d7592205c8 --- .../models/speech_to_text/convtransformer_simul_trans.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fairseq/models/speech_to_text/convtransformer_simul_trans.py b/fairseq/models/speech_to_text/convtransformer_simul_trans.py index e5dd771e03..7e77330a0c 100644 --- a/fairseq/models/speech_to_text/convtransformer_simul_trans.py +++ b/fairseq/models/speech_to_text/convtransformer_simul_trans.py @@ -5,9 +5,6 @@ # the root directory of this source tree. An additional grant of patent rights # can be found in the PATENTS file in the same directory. -from examples.simultaneous_translation.models.transformer_monotonic_attention import ( - TransformerMonotonicDecoder, -) from fairseq import checkpoint_utils from fairseq.models import ( register_model, @@ -33,6 +30,10 @@ def add_args(parser): def build_decoder(cls, args, task, embed_tokens): tgt_dict = task.tgt_dict + from examples.simultaneous_translation.models.transformer_monotonic_attention import ( + TransformerMonotonicDecoder, + ) + decoder = TransformerMonotonicDecoder(args, tgt_dict, embed_tokens) if getattr(args, "load_pretrained_decoder_from", None): From c3d2beec96bd609f87d8da14cc2dffdbbd843b54 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Tue, 23 Feb 2021 23:32:40 -0800 Subject: [PATCH 239/774] efficient batch level sampling Summary: Batch level sampling (each batch comes from a dataset sampled from some distribution) is useful in cases where we have a criterion that makes this assumption or a unique collator per dataset. However, the current implementation in fairseq `MultiCorpusSampledDataset` is inefficient, because it packs batches by assuming the size of item i is `max(dataset.size(i % len(dataset)) for dataset in datasets)`, which often significantly overestimates the actual sampled item's size, especially with many datasets. We can make this more efficient by modifying `MultiCorpusDataset`, which can do efficient batch sampling by: 1. Every epoch, sampling the indices/dataset to train on. 2. When creating batches, create per-dataset batches and merge them together Reviewed By: jay-mahadeokar Differential Revision: D26601515 fbshipit-source-id: a3273f88d86d7922f9ba004e7324e909ecc6ecf7 --- fairseq/data/multi_corpus_dataset.py | 49 +++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index 7207174bf3..6563713489 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -35,6 +35,7 @@ class MultiCorpusDataset(FairseqDataset): corresponding dataset seed: random seed for sampling the datsets sort_indices: if true, will sort the ordered indices by size + batch_sample: if true, will ensure each batch is from a single dataset """ def __init__( @@ -43,6 +44,7 @@ def __init__( distribution: List[float], seed: int, sort_indices: bool = False, + batch_sample: bool = False, ): super().__init__() assert isinstance(datasets, OrderedDict) @@ -51,6 +53,7 @@ def __init__( self.distribution = distribution self.seed = seed self.sort_indices = sort_indices + self.batch_sample = batch_sample # Avoid repeated conversions to list later self.dataset_list = list(datasets.values()) @@ -80,6 +83,7 @@ def ordered_indices(self): ] if self.sort_indices: sampled_indices.sort(key=lambda i: self.num_tokens(i)) + return np.array(sampled_indices, dtype=np.int64) def _sample(self, indices, counters): @@ -125,22 +129,26 @@ def __len__(self): return self.total_num_instances def __getitem__(self, index): - index, key = self._map_index(index) + new_index, key = self._map_index(index) try: - return self.datasets[key][index] + item = self.datasets[key][new_index] + item["full_id"] = index + return item except Exception as e: e.args = (f"Error from {key} dataset", *e.args) raise def collater(self, samples): """ - Since we enforce all datsets to be the same, collating is just - picking the first one and doing collate. + If we are doing batch sampling, then pick the right collater to use. + + Otherwise we assume all collaters are the same. """ if len(samples) == 0: return None + _, key = self._map_index(samples[0]["full_id"]) - return list(self.datasets.values())[0].collater(samples) + return self.datasets[key].collater(samples) def num_tokens(self, index: int): index, key = self._map_index(index) @@ -168,3 +176,34 @@ def supports_fetch_outside_dataloader(self): self.datasets[key].supports_fetch_outside_dataloader for key in self.datasets ) + + def batch_by_size( + self, + indices, + max_tokens=None, + max_sentences=None, + required_batch_size_multiple=1, + ): + if not self.batch_sample: + return super().batch_by_size( + indices, max_tokens, max_sentences, required_batch_size_multiple + ) + + dataset_indices = {key: [] for key in self.datasets} + for i in indices: + _, key = self._map_index(i) + dataset_indices[key].append(i) + + batches = [] + for key in dataset_indices: + cur_batches = super().batch_by_size( + np.array(dataset_indices[key], dtype=np.int64), + max_tokens, + max_sentences, + required_batch_size_multiple, + ) + logger.info(f"Created {len(cur_batches)} batches for dataset {key}") + batches += cur_batches + + # Assume shuffling is handled in fairseq/data/iterators.py + return batches From 55e48f18fee765fc4d528650570b8af0133ac074 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 24 Feb 2021 11:22:27 -0800 Subject: [PATCH 240/774] downcast indices in TokenBlockDataset (#1647) Summary: ### Measurements TLDR: This saves ~8% CPU RAM for training tiny model on medium sized dataset (11GB on disk) Command below: ``` +---------------------+----------------+---------+--------+ | fname | cpu_mem_used | wps | ppl | +=====================+================+=========+========+ +---------------------+----------------+---------+--------+ | branch_nw8_2gpu.log | 25.41 | 54721 | 429.1 | +---------------------+----------------+---------+--------+ +---------------------+----------------+---------+--------+ | master_nw8_2gpu.log | 27.53 | 52833.1 | 429.1 | +---------------------+----------------+---------+--------+ ``` ### Command ``` base_cmd () { dd=$1 shift fairseq-train --fp16 $dd \ --task language_modeling \ --arch transformer_lm_gpt2_tiny \ --sample-break-mode complete --tokens-per-sample 512 \ --optimizer adam --clip-norm 0.0 --lr 0.0005 \ --batch-size 1 \ --max-update 200 --max-epoch 1 \ --log-format simple --log-interval 100 \ --restore-file x.pt --no-save \ --skip-invalid-size-inputs-valid-test --disable-validation $@ } CUDA_VISIBLE_DEVICES=0,1 base_cmd /private/home/sshleifer/data-bin/stories_mmap --num-workers 8 ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1647 Reviewed By: myleott Differential Revision: D26628861 Pulled By: sshleifer fbshipit-source-id: 142afe0358d1c4cae448828ba811b211406509d7 --- fairseq/data/indexed_dataset.py | 37 +++++++++++++++++++---------- fairseq/data/token_block_dataset.py | 11 +++++---- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index a821417321..066f4dcd4f 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -15,12 +15,21 @@ from . import FairseqDataset +from typing import Union -def __best_fitting_dtype(vocab_size=None): - if vocab_size is not None and vocab_size < 65500: + +def best_fitting_uint_dtype( + max_int_to_represent, +) -> Union[np.uint16, np.uint32, np.uint64]: + + if max_int_to_represent is None: + return np.uint32 # Safe guess + elif max_int_to_represent < 65500: return np.uint16 + elif max_int_to_represent < 4294967295: + return np.uint32 else: - return np.int32 + return np.uint64 def get_available_dataset_impl(): @@ -48,7 +57,7 @@ def infer_dataset_impl(path): def make_builder(out_file, impl, vocab_size=None): if impl == "mmap": return MMapIndexedDatasetBuilder( - out_file, dtype=__best_fitting_dtype(vocab_size) + out_file, dtype=best_fitting_uint_dtype(vocab_size) ) elif impl == "fasta": raise NotImplementedError @@ -92,7 +101,7 @@ def write_longs(f, a): f.write(np.array(a, dtype=np.int64)) -dtypes = { +_code_to_dtype = { 1: np.uint8, 2: np.int8, 3: np.int16, @@ -101,12 +110,14 @@ def write_longs(f, a): 6: np.float, 7: np.double, 8: np.uint16, + 9: np.uint32, + 10: np.uint64, } -def code(dtype): - for k in dtypes.keys(): - if dtypes[k] == dtype: +def _dtype_header_code(dtype) -> int: + for k in _code_to_dtype.keys(): + if _code_to_dtype[k] == dtype: return k raise ValueError(dtype) @@ -141,7 +152,7 @@ def read_index(self, path): version = f.read(8) assert struct.unpack("<Q", version) == (1,) code, self.element_size = struct.unpack("<QQ", f.read(16)) - self.dtype = dtypes[code] + self.dtype = _code_to_dtype[code] self._len, self.s = struct.unpack("<QQ", f.read(16)) self.dim_offsets = read_longs(f, self._len + 1) self.data_offsets = read_longs(f, self._len + 1) @@ -348,7 +359,9 @@ def finalize(self, index_file): index = open(index_file, "wb") index.write(b"TNTIDX\x00\x00") index.write(struct.pack("<Q", 1)) - index.write(struct.pack("<QQ", code(self.dtype), self.element_size)) + index.write( + struct.pack("<QQ", _dtype_header_code(self.dtype), self.element_size) + ) index.write(struct.pack("<QQ", len(self.data_offsets) - 1, len(self.sizes))) write_longs(index, self.dim_offsets) write_longs(index, self.data_offsets) @@ -374,7 +387,7 @@ def __enter__(self): self._file.write(cls._HDR_MAGIC) self._file.write(struct.pack("<Q", 1)) - self._file.write(struct.pack("<B", code(dtype))) + self._file.write(struct.pack("<B", _dtype_header_code(dtype))) return self @@ -419,7 +432,7 @@ def __init__(self, path): assert (1,) == version (dtype_code,) = struct.unpack("<B", stream.read(1)) - self._dtype = dtypes[dtype_code] + self._dtype = _code_to_dtype[dtype_code] self._dtype_size = self._dtype().itemsize self._len = struct.unpack("<Q", stream.read(8))[0] diff --git a/fairseq/data/token_block_dataset.py b/fairseq/data/token_block_dataset.py index aa33f9d06f..038f1c81d7 100644 --- a/fairseq/data/token_block_dataset.py +++ b/fairseq/data/token_block_dataset.py @@ -6,7 +6,7 @@ import numpy as np import torch from fairseq.data import FairseqDataset, plasma_utils - +from fairseq.data.indexed_dataset import best_fitting_uint_dtype class TokenBlockDataset(FairseqDataset): """Break a Dataset of tokens into blocks. @@ -98,9 +98,12 @@ def __init__( sizes, slice_indices, ) - self._slice_indices = plasma_utils.PlasmaArray(slice_indices) - self._sizes = plasma_utils.PlasmaArray(self._sizes) - self._block_to_dataset_index = plasma_utils.PlasmaArray(block_to_dataset_index) + size_dtype = np.uint16 if block_size < 65535 else np.uint32 + slice_indices_dtype = best_fitting_uint_dtype(slice_indices[-1].max()) + + self._slice_indices = plasma_utils.PlasmaArray(slice_indices.astype(slice_indices_dtype)) + self._sizes = plasma_utils.PlasmaArray(self._sizes.astype(size_dtype)) + self._block_to_dataset_index = plasma_utils.PlasmaArray(block_to_dataset_index.astype(slice_indices_dtype)) @property def slice_indices(self): From 5c008e0c339ba932b551d18b0801c201e8fdf5a9 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 24 Feb 2021 11:25:41 -0800 Subject: [PATCH 241/774] make LanguageModelingTask 1% simpler (#1641) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1641 Reviewed By: myleott Differential Revision: D26607648 Pulled By: sshleifer fbshipit-source-id: 9d7f9d7a0825e3124c181b651a126842e5de6109 --- fairseq/tasks/language_modeling.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index 4a44d967b3..579bf69785 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -184,7 +184,9 @@ def build_model(self, args): return model - def load_dataset(self, split, epoch=1, combine=False, **kwargs): + def load_dataset( + self, split: str, epoch=1, combine=False, **kwargs + ) -> MonolingualDataset: """Load a given dataset split. Args: @@ -228,7 +230,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): and self.args.sample_break_mode != "none" ) - self.datasets[split] = self._initialize_dataset( + self.datasets[split] = MonolingualDataset( dataset=dataset, sizes=dataset.sizes, src_vocab=self.dictionary, @@ -239,9 +241,6 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): add_bos_token=self.args.add_bos_token, ) - def _initialize_dataset(self, **kwargs): - return MonolingualDataset(**kwargs) - def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): """ Generate batches for inference. We prepend an eos token to src_tokens From 52daa1b29b35c93ffb950e56507c9c1d17aa2369 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 24 Feb 2021 14:21:24 -0800 Subject: [PATCH 242/774] move code to .py files, document usage (#1637) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1637 Test Plan: ```bash python examples/bart/summarize.py --model-dir pytorch/fairseq --model-file bart.large.cnn --src $HOME/data-bin/cnn_dm/test.source --n 12 --out hub_hypo.txt python examples/bart/summarize.py \ --model-dir pytorch/fairseq \ --model-file bart.large.cnn \ --src cnn_dm/test.source \ --out cnn_dm/test.hypo --xsum-kwargs ``` Reviewed By: ngoyal2707 Differential Revision: D26581703 Pulled By: sshleifer fbshipit-source-id: 80eb28012f7770eee01ed50a1163c5a2c5cc6d37 --- examples/bart/README.md | 47 +++++------- examples/bart/README.summarization.md | 55 +++++--------- examples/bart/summarize.py | 100 ++++++++++++++++++++++++++ fairseq/sequence_generator.py | 6 +- 4 files changed, 136 insertions(+), 72 deletions(-) create mode 100644 examples/bart/summarize.py diff --git a/examples/bart/README.md b/examples/bart/README.md index 013a809be6..4050a724ee 100644 --- a/examples/bart/README.md +++ b/examples/bart/README.md @@ -179,38 +179,23 @@ with open('glue_data/MNLI/dev_matched.tsv') as fin: ``` #### Evaluating the `bart.large.cnn` model: -Follow instructions [here](https://github.com/abisee/cnn-dailymail) to download and process into data-files such that `test.source` and `test.target` has one line for each non-tokenized sample. +- Follow instructions [here](https://github.com/abisee/cnn-dailymail) to download and process into data-files such that `test.source` and `test.target` has one line for each non-tokenized sample. +- For simpler preprocessing, you can also `wget https://cdn-datasets.huggingface.co/summarization/cnn_dm_v2.tgz`, although there is no guarantee of identical scores +- `huggingface/transformers` has a simpler interface that supports [single-gpu](https://github.com/huggingface/transformers/blob/master/examples/legacy/seq2seq/run_eval.py) and [multi-gpu](https://github.com/huggingface/transformers/blob/master/examples/legacy/seq2seq/run_distributed_eval.py) beam search. + In `huggingface/transformers`, the BART models' paths are `facebook/bart-large-cnn` and `facebook/bart-large-xsum`. -```python -bart = torch.hub.load('pytorch/fairseq', 'bart.large.cnn') -bart.cuda() -bart.eval() -bart.half() -count = 1 -bsz = 32 -with open('test.source') as source, open('test.hypo', 'w') as fout: - sline = source.readline().strip() - slines = [sline] - for sline in source: - if count % bsz == 0: - with torch.no_grad(): - hypotheses_batch = bart.sample(slines, beam=4, lenpen=2.0, max_len_b=140, min_len=55, no_repeat_ngram_size=3) - - for hypothesis in hypotheses_batch: - fout.write(hypothesis + '\n') - fout.flush() - slines = [] - - slines.append(sline.strip()) - count += 1 - if slines != []: - hypotheses_batch = bart.sample(slines, beam=4, lenpen=2.0, max_len_b=140, min_len=55, no_repeat_ngram_size=3) - for hypothesis in hypotheses_batch: - fout.write(hypothesis + '\n') - fout.flush() -``` - -Install `files2rouge` from [here](https://github.com/pltrdy/files2rouge). +In `fairseq`, summaries can be generated using: + +```bash +cp data-bin/cnn_dm/dict.source.txt checkpoints/ +python examples/bart/summarize.py \ + --model-dir pytorch/fairseq \ + --model-file bart.large.cnn \ + --src cnn_dm/test.source \ + --out cnn_dm/test.hypo +``` + +For calculating rouge, install `files2rouge` from [here](https://github.com/pltrdy/files2rouge). ```bash export CLASSPATH=/path/to/stanford-corenlp-full-2016-10-31/stanford-corenlp-3.7.0.jar diff --git a/examples/bart/README.summarization.md b/examples/bart/README.summarization.md index d7fecc9ce6..8727584f2b 100644 --- a/examples/bart/README.summarization.md +++ b/examples/bart/README.summarization.md @@ -80,42 +80,23 @@ Expected training time is about `5 hours`. Training time can be reduced with dis Use TOTAL_NUM_UPDATES=15000 UPDATE_FREQ=2 for Xsum task ### Inference for CNN-DM test data using above trained checkpoint. -After training the model as mentioned in previous step, you can perform inference with checkpoints in `checkpoints/` directory using following python code snippet: +After training the model as mentioned in previous step, you can perform inference with checkpoints in `checkpoints/` directory using `eval_cnn.py`, for example -```python -import torch -from fairseq.models.bart import BARTModel - -bart = BARTModel.from_pretrained( - 'checkpoints/', - checkpoint_file='checkpoint_best.pt', - data_name_or_path='cnn_dm-bin' -) - -bart.cuda() -bart.eval() -bart.half() -count = 1 -bsz = 32 -with open('cnn_dm/test.source') as source, open('cnn_dm/test.hypo', 'w') as fout: - sline = source.readline().strip() - slines = [sline] - for sline in source: - if count % bsz == 0: - with torch.no_grad(): - hypotheses_batch = bart.sample(slines, beam=4, lenpen=2.0, max_len_b=140, min_len=55, no_repeat_ngram_size=3) - - for hypothesis in hypotheses_batch: - fout.write(hypothesis + '\n') - fout.flush() - slines = [] - - slines.append(sline.strip()) - count += 1 - if slines != []: - hypotheses_batch = bart.sample(slines, beam=4, lenpen=2.0, max_len_b=140, min_len=55, no_repeat_ngram_size=3) - for hypothesis in hypotheses_batch: - fout.write(hypothesis + '\n') - fout.flush() +```bash +cp data-bin/cnn_dm/dict.source.txt checkpoints/ +python examples/bart/summarize.py \ + --model-dir checkpoints \ + --model-file checkpoint_best.pt \ + --src cnn_dm/test.source \ + --out cnn_dm/test.hypo +``` +For XSUM, which uses beam=6, lenpen=1.0, max_len_b=60, min_len=10: +```bash +cp data-bin/cnn_dm/dict.source.txt checkpoints/ +python examples/bart/summarize.py \ + --model-dir checkpoints \ + --model-file checkpoint_best.pt \ + --src cnn_dm/test.source \ + --out cnn_dm/test.hypo \ + --xsum-kwargs ``` -Use beam=6, lenpen=1.0, max_len_b=60, min_len=10 for Xsum Generation diff --git a/examples/bart/summarize.py b/examples/bart/summarize.py new file mode 100644 index 0000000000..04435f80e3 --- /dev/null +++ b/examples/bart/summarize.py @@ -0,0 +1,100 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from fairseq.models.bart import BARTModel +import argparse + +XSUM_KWARGS = dict(beam=6, lenpen=1.0, max_len_b=60, min_len=10, no_repeat_ngram_size=3) +CNN_KWARGS = dict(beam=4, lenpen=2.0, max_len_b=140, min_len=55, no_repeat_ngram_size=3) + + +@torch.no_grad() +def generate(bart, infile, outfile="bart_hypo.txt", bsz=32, n_obs=None, **eval_kwargs): + count = 1 + + # if n_obs is not None: bsz = min(bsz, n_obs) + + with open(infile) as source, open(outfile, "w") as fout: + sline = source.readline().strip() + slines = [sline] + for sline in source: + if n_obs is not None and count > n_obs: + break + if count % bsz == 0: + hypotheses_batch = bart.sample(slines, **eval_kwargs) + for hypothesis in hypotheses_batch: + fout.write(hypothesis + "\n") + fout.flush() + slines = [] + + slines.append(sline.strip()) + count += 1 + + if slines != []: + hypotheses_batch = bart.sample(slines, **eval_kwargs) + for hypothesis in hypotheses_batch: + fout.write(hypothesis + "\n") + fout.flush() + + +def main(): + """ + Usage:: + + python examples/bart/summarize.py \ + --model-dir $HOME/bart.large.cnn \ + --model-file model.pt \ + --src $HOME/data-bin/cnn_dm/test.source + """ + parser = argparse.ArgumentParser() + parser.add_argument( + "--model-dir", + required=True, + type=str, + default="bart.large.cnn/", + help="path containing model file and src_dict.txt", + ) + parser.add_argument( + "--model-file", + default="checkpoint_best.pt", + help="where in model_dir are weights saved", + ) + parser.add_argument( + "--src", default="test.source", help="text to summarize", type=str + ) + parser.add_argument( + "--out", default="test.hypo", help="where to save summaries", type=str + ) + parser.add_argument("--bsz", default=32, help="where to save summaries", type=int) + parser.add_argument( + "--n", default=None, help="how many examples to summarize", type=int + ) + parser.add_argument( + "--xsum-kwargs", + action="store_true", + default=False, + help="if true use XSUM_KWARGS else CNN_KWARGS", + ) + args = parser.parse_args() + eval_kwargs = XSUM_KWARGS if args.xsum_kwargs else CNN_KWARGS + if args.model_dir == "pytorch/fairseq": + bart = torch.hub.load("pytorch/fairseq", args.model_file) + else: + bart = BARTModel.from_pretrained( + args.model_dir, + checkpoint_file=args.model_file, + data_name_or_path=args.model_dir, + ) + bart = bart.eval() + if torch.cuda.is_available(): + bart = bart.cuda().half() + generate( + bart, args.src, bsz=args.bsz, n_obs=args.n, outfile=args.out, **eval_kwargs + ) + + +if __name__ == "__main__": + main() diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 117c6116fb..2574ab13f0 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -214,7 +214,7 @@ def _generate( raise Exception("expected src_tokens or source in net input") # bsz: total number of sentences in beam - # Note that src_tokens may have more than 2 dimenions (i.e. audio features) + # Note that src_tokens may have more than 2 dimensions (i.e. audio features) bsz, src_len = src_tokens.size()[:2] beam_size = self.beam_size @@ -376,9 +376,7 @@ def _generate( self.search.set_src_lengths(src_lengths) if self.repeat_ngram_blocker is not None: - lprobs = self.repeat_ngram_blocker( - tokens, lprobs, bsz, beam_size, step - ) + lprobs = self.repeat_ngram_blocker(tokens, lprobs, bsz, beam_size, step) # Shape: (batch, cand_size) cand_scores, cand_indices, cand_beams = self.search.step( From fb3fadbb159d8af6d83a5680674d20f7b7635766 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 24 Feb 2021 15:41:02 -0800 Subject: [PATCH 243/774] Set DynamicLossScaler class defaults to match CLI defaults (#1649) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1649 Reviewed By: stephenroller Differential Revision: D26639303 Pulled By: myleott fbshipit-source-id: 7def925cd7885cfe85d542464316cbc0f2ba6d2c --- fairseq/optim/dynamic_loss_scaler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/optim/dynamic_loss_scaler.py b/fairseq/optim/dynamic_loss_scaler.py index c5da604220..43f9be37b9 100644 --- a/fairseq/optim/dynamic_loss_scaler.py +++ b/fairseq/optim/dynamic_loss_scaler.py @@ -10,7 +10,7 @@ def __init__( init_scale=2.0 ** 15, scale_factor=2.0, scale_window=2000, - tolerance=0.05, + tolerance=0.0, threshold=None, min_loss_scale=1e-4, ): From b8651bc984413e7e45f44294dffcc85692ba89c1 Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Wed, 24 Feb 2021 15:48:38 -0800 Subject: [PATCH 244/774] actually checking gradnorm consistency Summary: D24849271 (https://github.com/pytorch/fairseq/commit/3c5647cebf454c07b52a0fb899c920789381ebda) fixed finite check, but the 'or' condition means as long as all gradients are finite, the check will pass. This diff adds back the consistency check, the norm can't differ from each other much. Reviewed By: myleott Differential Revision: D26640459 fbshipit-source-id: 3e23e13841372aa04461dcde245b893715480c3c --- fairseq/trainer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 891155f162..680a7ee953 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -1113,7 +1113,7 @@ def is_consistent(tensor): max_abs_diff = torch.max(torch.abs(tensor - tensor[0])) return ( torch.isfinite(tensor).all() - or (max_abs_diff / (tensor[0] + 1e-6) < 1e-6).all() + and (max_abs_diff / (tensor[0] + 1e-6) < 1e-6).all() ) if not is_consistent(self._grad_norm_buf): From d3890e593398c485f6593ab8512ac51d37dedc9c Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Wed, 24 Feb 2021 22:55:37 -0800 Subject: [PATCH 245/774] Add HiveScorer to read data from hive and EverstoreAudioInstance to load audio from everstore Summary: This diff - Refactors utils/agent_finder.py to reduce the complexity of find_agent_cls function - Refactors cli.py and server.py to remove unnecessary argument parser function calls - Adds fb_hive_scorer.py with HiveScorer to read data from hive and process everstore handles - Adds fb_options.py to add necessary arguments for HiveScorer - Updates other parts of the code to include the new scorer Reviewed By: jmp84 Differential Revision: D26575148 fbshipit-source-id: ae6e12d2adf5f393f807d5238f0d78a2f64a77a3 --- .../simultaneous_translation/agents/fairseq_simul_st_agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index 32cd0a1f61..5793609095 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -128,7 +128,7 @@ def __init__(self, args): self.load_model_vocab(args) with open(args.config, "r") as f: - config = yaml.load(f) + config = yaml.load(f, Loader=yaml.BaseLoader) if "global_cmvn" in config: args.global_cmvn = np.load(config["global_cmvn"]["stats_npz_path"]) From f569c024ae6ee3e8c37c3b9dca975a3df50f7a03 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Thu, 25 Feb 2021 22:33:48 -0800 Subject: [PATCH 246/774] Relocate simultaneous translation code (#1639) Summary: Relocate simultaneous translation code from example/simultaneous_translation to fairseq/model/simultaneous_translation, only keep the documents Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1639 Reviewed By: jmp84 Differential Revision: D26599346 Pulled By: xutaima fbshipit-source-id: 4f708d172696a430bd4e7b14871f5c8862a20489 --- examples/simultaneous_translation/__init__.py | 2 +- .../criterions/__init__.py | 15 --------------- .../models}/convtransformer_simul_trans.py | 10 +++++++++- fairseq/models/speech_to_text/__init__.py | 1 - fairseq/models/speech_to_text/convtransformer.py | 8 ++------ 5 files changed, 12 insertions(+), 24 deletions(-) delete mode 100644 examples/simultaneous_translation/criterions/__init__.py rename {fairseq/models/speech_to_text => examples/simultaneous_translation/models}/convtransformer_simul_trans.py (83%) diff --git a/examples/simultaneous_translation/__init__.py b/examples/simultaneous_translation/__init__.py index 446fc86c8a..5835316ba9 100644 --- a/examples/simultaneous_translation/__init__.py +++ b/examples/simultaneous_translation/__init__.py @@ -3,4 +3,4 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from . import criterions, eval, models # noqa +from . import models # noqa diff --git a/examples/simultaneous_translation/criterions/__init__.py b/examples/simultaneous_translation/criterions/__init__.py deleted file mode 100644 index 08791bfff3..0000000000 --- a/examples/simultaneous_translation/criterions/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import importlib -import os - - -for file in os.listdir(os.path.dirname(__file__)): - if file.endswith(".py") and not file.startswith("_"): - criterion_name = file[: file.find(".py")] - importlib.import_module( - "examples.simultaneous_translation.criterions." + criterion_name - ) diff --git a/fairseq/models/speech_to_text/convtransformer_simul_trans.py b/examples/simultaneous_translation/models/convtransformer_simul_trans.py similarity index 83% rename from fairseq/models/speech_to_text/convtransformer_simul_trans.py rename to examples/simultaneous_translation/models/convtransformer_simul_trans.py index 7e77330a0c..84ba4d0d3f 100644 --- a/fairseq/models/speech_to_text/convtransformer_simul_trans.py +++ b/examples/simultaneous_translation/models/convtransformer_simul_trans.py @@ -11,11 +11,19 @@ register_model_architecture, ) -from .convtransformer import ConvTransformerModel, convtransformer_espnet +from fairseq.models.speech_to_text import ConvTransformerModel, convtransformer_espnet @register_model("convtransformer_simul_trans") class SimulConvTransformerModel(ConvTransformerModel): + """ + Implementation of the paper: + + SimulMT to SimulST: Adapting Simultaneous Text Translation to + End-to-End Simultaneous Speech Translation + + https://www.aclweb.org/anthology/2020.aacl-main.58.pdf + """ @staticmethod def add_args(parser): super(SimulConvTransformerModel, SimulConvTransformerModel).add_args(parser) diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index 28e3bb720f..c6ae9b17ba 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -5,5 +5,4 @@ from .berard import * # noqa from .convtransformer import * # noqa -from .convtransformer_simul_trans import * # noqa from .s2t_transformer import * # noqa diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py index 622b5e6df8..a4cbbcdeeb 100644 --- a/fairseq/models/speech_to_text/convtransformer.py +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -7,9 +7,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -from examples.simultaneous_translation.utils.data_utils import ( - lengths_to_encoder_padding_mask, -) +from fairseq.data.data_utils import lengths_to_padding_mask from fairseq import checkpoint_utils, utils from fairseq.models import ( FairseqEncoder, @@ -311,9 +309,7 @@ def forward(self, src_tokens, src_lengths): x.size(0) * src_lengths.new_ones([src_lengths.size(0)]).long() ) - encoder_padding_mask, _ = lengths_to_encoder_padding_mask( - input_lengths, batch_first=True - ) + encoder_padding_mask = lengths_to_padding_mask(input_lengths) positions = self.embed_positions(encoder_padding_mask).transpose(0, 1) x += positions From 4f881a760e1cd7e11ecce2332b6ee9a435f233a5 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Fri, 26 Feb 2021 20:59:22 -0800 Subject: [PATCH 247/774] TokenBlockDataset np type promotion issue (#1658) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1658 Reviewed By: jxmsML Differential Revision: D26701840 Pulled By: sshleifer fbshipit-source-id: 90d631c3cd775ab847366fe7a05136c29d90cd63 --- fairseq/data/indexed_dataset.py | 10 ++++++---- fairseq/data/token_block_dataset.py | 16 ++++++++++------ fairseq/models/transformer_lm.py | 12 ++++++++++++ tests/test_token_block_dataset.py | 13 +++++++++++++ 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index 066f4dcd4f..802e37a7ff 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -18,9 +18,9 @@ from typing import Union -def best_fitting_uint_dtype( +def best_fitting_int_dtype( max_int_to_represent, -) -> Union[np.uint16, np.uint32, np.uint64]: +) -> Union[np.uint16, np.uint32, np.int64]: if max_int_to_represent is None: return np.uint32 # Safe guess @@ -29,7 +29,9 @@ def best_fitting_uint_dtype( elif max_int_to_represent < 4294967295: return np.uint32 else: - return np.uint64 + return np.int64 + # we avoid np.uint64 because it doesn't save space and its type promotion behaves unexpectedly + # https://github.com/numpy/numpy/issues/5745 def get_available_dataset_impl(): @@ -57,7 +59,7 @@ def infer_dataset_impl(path): def make_builder(out_file, impl, vocab_size=None): if impl == "mmap": return MMapIndexedDatasetBuilder( - out_file, dtype=best_fitting_uint_dtype(vocab_size) + out_file, dtype=best_fitting_int_dtype(vocab_size) ) elif impl == "fasta": raise NotImplementedError diff --git a/fairseq/data/token_block_dataset.py b/fairseq/data/token_block_dataset.py index 038f1c81d7..4617466234 100644 --- a/fairseq/data/token_block_dataset.py +++ b/fairseq/data/token_block_dataset.py @@ -6,7 +6,8 @@ import numpy as np import torch from fairseq.data import FairseqDataset, plasma_utils -from fairseq.data.indexed_dataset import best_fitting_uint_dtype +from fairseq.data.indexed_dataset import best_fitting_int_dtype + class TokenBlockDataset(FairseqDataset): """Break a Dataset of tokens into blocks. @@ -95,15 +96,18 @@ def __init__( ) else: block_to_dataset_index = _get_block_to_dataset_index_fast( - sizes, - slice_indices, + sizes, slice_indices, ) size_dtype = np.uint16 if block_size < 65535 else np.uint32 - slice_indices_dtype = best_fitting_uint_dtype(slice_indices[-1].max()) + slice_indices_dtype = best_fitting_int_dtype(slice_indices[-1].max()) - self._slice_indices = plasma_utils.PlasmaArray(slice_indices.astype(slice_indices_dtype)) + self._slice_indices = plasma_utils.PlasmaArray( + slice_indices.astype(slice_indices_dtype) + ) self._sizes = plasma_utils.PlasmaArray(self._sizes.astype(size_dtype)) - self._block_to_dataset_index = plasma_utils.PlasmaArray(block_to_dataset_index.astype(slice_indices_dtype)) + self._block_to_dataset_index = plasma_utils.PlasmaArray( + block_to_dataset_index.astype(slice_indices_dtype) + ) @property def slice_indices(self): diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index edf62b12b3..f12470d033 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -394,6 +394,18 @@ def transformer_lm_gpt2_small(args): base_lm_architecture(args) +@register_model_architecture("transformer_lm", "transformer_lm_gpt2_tiny") +def transformer_lm_gpt2_tiny(args): + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 64) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 64) + args.decoder_layers = getattr(args, "decoder_layers", 2) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 1) + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", 0.1) + args.activation_fn = getattr(args, "activation_fn", "gelu") + base_lm_architecture(args) + + @register_model_architecture("transformer_lm", "transformer_lm_gpt2_medium") def transformer_lm_gpt2_medium(args): args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1280) diff --git a/tests/test_token_block_dataset.py b/tests/test_token_block_dataset.py index ea315b4e67..c4d7b76dcd 100644 --- a/tests/test_token_block_dataset.py +++ b/tests/test_token_block_dataset.py @@ -74,6 +74,19 @@ def test_complete_break_mode(self): self.assertEqual(ds[1].tolist(), [5, 1, 1]) self.assertEqual(ds[2].tolist(), [6, 1]) + def test_4billion_tokens(self): + """Regression test for numpy type promotion issue https://github.com/numpy/numpy/issues/5745""" + data = [torch.tensor(list(range(10000)), dtype=torch.long)] * 430000 + ds = self._build_dataset( + data, block_size=6, pad=0, eos=1, break_mode="complete" + ) + ds[-1] # __getitem__ works + start, end = ds.slice_indices[-1] + assert end > 4294967295 # data must be sufficiently large to overflow uint32 + assert not isinstance( + end + 1, float + ) # this would also raise, since np.uint64(1) + 1 => 2.0 + if __name__ == "__main__": unittest.main() From 5354aa3a6ec80092cc7bb9aecfad7077bb50b47e Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@fb.com> Date: Sun, 28 Feb 2021 12:44:23 -0800 Subject: [PATCH 248/774] github CI install pyarrow Reviewed By: myleott Differential Revision: D26643358 fbshipit-source-id: 8d7e1082c6e11f9bbab4b34de078cf05197297a5 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 29e5254d33..0af8bad95d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,7 +39,7 @@ jobs: - name: Install optional test requirements run: | - python -m pip install fairscale iopath transformers + python -m pip install fairscale iopath transformers pyarrow - name: Lint with flake8 run: | From e5e8b3fee1e57a7abf35ad1a3ff223a2b7190c65 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Sun, 28 Feb 2021 12:49:20 -0800 Subject: [PATCH 249/774] Fix nearly all unit-test warnings (#1652) Summary: 2 types of warnings fixed: ``` `np.long` is a deprecated alias for `np.compat.long`. Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1652 Reviewed By: myleott Differential Revision: D26643344 Pulled By: sshleifer fbshipit-source-id: 960bccc94f299bd8a8c58a87acd80694e9d5c363 --- fairseq/data/language_pair_dataset.py | 12 +++--------- fairseq/data/token_block_dataset.py | 2 +- fairseq/optim/lr_scheduler/cosine_lr_scheduler.py | 2 +- .../lr_scheduler/inverse_square_root_schedule.py | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/fairseq/data/language_pair_dataset.py b/fairseq/data/language_pair_dataset.py index 8858cec84e..9d36cbd4ce 100644 --- a/fairseq/data/language_pair_dataset.py +++ b/fairseq/data/language_pair_dataset.py @@ -114,10 +114,7 @@ def compute_alignment_weights(alignments): "id": id, "nsentences": len(samples), "ntokens": ntokens, - "net_input": { - "src_tokens": src_tokens, - "src_lengths": src_lengths, - }, + "net_input": {"src_tokens": src_tokens, "src_lengths": src_lengths,}, "target": target, } if prev_output_tokens is not None: @@ -289,7 +286,7 @@ def __init__( # determine bucket sizes using self.num_tokens, which will return # the padded lengths (thanks to BucketPadLengthDataset) - num_tokens = np.vectorize(self.num_tokens, otypes=[np.long]) + num_tokens = np.vectorize(self.num_tokens, otypes=[np.compat.long]) self.bucketed_num_tokens = num_tokens(np.arange(len(self.src))) self.buckets = [ (None, num_tokens) for num_tokens in np.unique(self.bucketed_num_tokens) @@ -470,8 +467,5 @@ def filter_indices_by_size(self, indices, max_sizes): list: list of removed indices """ return data_utils.filter_paired_dataset_indices_by_size( - self.src_sizes, - self.tgt_sizes, - indices, - max_sizes, + self.src_sizes, self.tgt_sizes, indices, max_sizes, ) diff --git a/fairseq/data/token_block_dataset.py b/fairseq/data/token_block_dataset.py index 4617466234..ce0a0d1114 100644 --- a/fairseq/data/token_block_dataset.py +++ b/fairseq/data/token_block_dataset.py @@ -88,7 +88,7 @@ def __init__( [ np.arange(len(sizes)), # starting index in dataset np.zeros( - len(sizes), dtype=np.long + len(sizes), dtype=np.compat.long ), # starting offset within starting index np.arange(len(sizes)), # ending index in dataset ], diff --git a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py index 38b57fe54c..51f58359ed 100644 --- a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py @@ -4,7 +4,7 @@ # LICENSE file in the root directory of this source tree. import math -from collections import Collection +from collections.abc import Collection from dataclasses import dataclass, field from typing import List diff --git a/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py b/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py index d9321577bb..0f87bb5d7e 100644 --- a/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py +++ b/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py @@ -3,7 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from collections import Collection +from collections.abc import Collection from dataclasses import dataclass, field from typing import List From 39e55139ea05da36e9ab9837c4943f660b79dcbe Mon Sep 17 00:00:00 2001 From: Hiromu Yakura <hiromu1996@gmail.com> Date: Mon, 1 Mar 2021 12:36:18 -0800 Subject: [PATCH 250/774] Fix the order of constraints in LanguagePairDataset (#3280) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3279. This change modifies the output of `echo -e "Ja, wer hat, wenn du willst, Götter gebildet, uns zu ihnen erhoben, sie zu uns herniedergebracht, als der Dichter?\tbard\nZu vollenden ist nicht die Sache des Schülers, es ist genug, wenn er sich übt\tstudent" | python normalize.py | python tok.py | fairseq-interactive --constraints -s de -t en --beam 10 --batch-size 2 --buffer-size 2 --bpe fastbpe --bpe-codes ../../../models/ende30k.fastbpe.code --path ../../../models/wmt19.de-en.ffn8192.pt ../../../models/` as follows. Before: ``` S-0 Ja , wer hat , wenn du will@@ st , Gö@@ tter gebildet , uns zu ihnen erhoben , sie zu uns her@@ nieder@@ gebracht , als der Dich@@ ter ? W-0 1.755 seconds C-0 student H-0 -1.1425577402114868 Yes , who , if you will , has formed go@@ ds , raised us up to them , brought them down to us , but the po@@ et student ? D-0 -1.1425577402114868 Yes , who , if you will , has formed gods , raised us up to them , brought them down to us , but the poet student ? P-0 -1.8768 -0.2214 -0.4671 -1.2521 -0.2101 -0.3053 -1.2077 -0.1496 -1.8780 -1.4195 -0.4071 -0.1347 -0.3726 -1.1306 -0.1665 -1.4588 -0.2837 -0.1722 -0.2330 -0.2840 -0.1806 -0.1432 -0.2263 -0.1395 -0.7261 -1.4593 -0.3639 -0.4030 -0.1083 -18.7577 -0.2396 -0.1837 S-1 Zu voll@@ enden ist nicht die Sache des Sch@@ ül@@ ers , es ist genug , wenn er sich übt W-1 1.755 seconds C-1 b@@ ard H-1 -1.9625756740570068 It is not up to the b@@ ard to complete , it is enough if he practi@@ ses D-1 -1.9625756740570068 It is not up to the bard to complete , it is enough if he practises P-1 -1.2630 -0.3364 -0.1634 -2.7070 -0.1734 -0.2815 -17.3978 -6.0238 -0.4888 -1.7563 -0.8708 -0.6773 -0.2027 -0.2456 -1.6366 -0.2911 -2.0235 -0.1961 -0.5538 ``` After: ``` S-0 Ja , wer hat , wenn du will@@ st , Gö@@ tter gebildet , uns zu ihnen erhoben , sie zu uns her@@ nieder@@ gebracht , als der Dich@@ ter ? W-0 1.740 seconds C-0 b@@ ard H-0 -1.2060465812683105 Yes , who , if you will , formed go@@ ds , raised us up to them , brought them down to us , but the b@@ ard ? D-0 -1.2060465812683105 Yes , who , if you will , formed gods , raised us up to them , brought them down to us , but the bard ? P-0 -1.8768 -0.2214 -0.4671 -1.2521 -0.2101 -0.3053 -1.2077 -0.1496 -2.2551 -0.5702 -0.1331 -0.3940 -1.0268 -0.1750 -1.4635 -0.2821 -0.1725 -0.2404 -0.3575 -0.1833 -0.1441 -0.2250 -0.1419 -0.7020 -1.5215 -0.3700 -16.8578 -2.7290 -0.3405 -0.2060 S-1 Zu voll@@ enden ist nicht die Sache des Sch@@ ül@@ ers , es ist genug , wenn er sich übt W-1 1.740 seconds C-1 student H-1 -0.8064212203025818 It is not up to the student to complete , it is enough if he practi@@ ses D-1 -0.8064212203025818 It is not up to the student to complete , it is enough if he practises P-1 -1.2630 -0.3364 -0.1634 -2.7070 -0.1734 -0.2815 -1.5556 -0.2831 -1.3885 -0.7310 -0.6367 -0.1824 -0.2386 -1.5320 -0.2728 -2.0003 -0.2163 -0.5536 ``` ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3280 Reviewed By: myleott Differential Revision: D26725013 Pulled By: lematt1991 fbshipit-source-id: 2275fcf146cb8cd9ca21f847e10a4dacdee996f9 --- fairseq/data/language_pair_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/data/language_pair_dataset.py b/fairseq/data/language_pair_dataset.py index 9d36cbd4ce..ff3e14bf14 100644 --- a/fairseq/data/language_pair_dataset.py +++ b/fairseq/data/language_pair_dataset.py @@ -157,7 +157,7 @@ def compute_alignment_weights(alignments): constraints = torch.zeros((len(samples), max(lens))).long() for i, sample in enumerate(samples): constraints[i, 0 : lens[i]] = samples[i].get("constraints") - batch["constraints"] = constraints + batch["constraints"] = constraints.index_select(0, sort_order) return batch From 1c0439b7dabe62d39c6e7f1c8ebc86311e042b5a Mon Sep 17 00:00:00 2001 From: freewym <freewym@gmail.com> Date: Mon, 1 Mar 2021 16:21:05 -0800 Subject: [PATCH 251/774] fixes circular imports incurred by a recent commit (#3286) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes circular imports incurred by a recent commit ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3286 Reviewed By: lematt1991 Differential Revision: D26725255 Pulled By: myleott fbshipit-source-id: 5572f733b83bdfadcce3188c0789fc6d70a3bad3 --- fairseq/models/fairseq_model.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 244cbc0c66..186f3d2464 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -14,7 +14,6 @@ import torch.nn as nn import torch.nn.functional as F from fairseq import utils -from fairseq.checkpoint_utils import prune_state_dict from fairseq.data import Dictionary from fairseq.dataclass.utils import ( convert_namespace_to_omegaconf, @@ -111,6 +110,9 @@ def load_state_dict( model_cfg = convert_namespace_to_omegaconf(args).model self.upgrade_state_dict(state_dict) + + from fairseq.checkpoint_utils import prune_state_dict + new_state_dict = prune_state_dict(state_dict, model_cfg) return super().load_state_dict(new_state_dict, strict) @@ -450,6 +452,9 @@ def load_state_dict( model_cfg = convert_namespace_to_omegaconf(args).model self.upgrade_state_dict(state_dict) + + from fairseq.checkpoint_utils import prune_state_dict + new_state_dict = prune_state_dict(state_dict, model_cfg) return super().load_state_dict(new_state_dict, strict) From 3100d0b8e5bb5e61b4d73b9c058389aa2c06784a Mon Sep 17 00:00:00 2001 From: Eric Lou <ericlou@fb.com> Date: Tue, 2 Mar 2021 09:24:03 -0800 Subject: [PATCH 252/774] ioPath async - opt-in Fairseq integration (#1635) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1635 **Summary:** Integrate ioPath's async writes feature into Fairseq checkpoint writing. **Details:** - Created new checkpoint config param `--write-checkpoints-asynchronously` with default value `False`. Aliased to `--save-async`. - Added to `PathManager` class in `file_io.py` to include `PathManager.opena(...)` and `PathManager.async_close()`. These new methods use ioPath's async `PathManager`. **Usage:** ``` python train.py --save-async ``` --------- NOTE: **QUESTIONS** 1. In the current implementation, we don't save `checkpoint_best` and `checkpoint_latest` since ioPath doesn't yet have a "wait until a file is written and then copy/move it to another path" feature. Is this okay for now? 2. Should I mimic the atomic vs non-atomic save structure that synchronous Fairseq checkpoint writes have? **Note to Eric:** Keep this integration in check with D26375501. Reviewed By: myleott Differential Revision: D26467815 fbshipit-source-id: 50068ef7bf9a6d5cea4d5e0d13d672604dc4a6b0 --- fairseq/checkpoint_utils.py | 42 ++++++++++++++++++++++---------- fairseq/dataclass/configs.py | 10 ++++++++ fairseq/file_io.py | 46 ++++++++++++++++++++++++++++++++++++ fairseq_cli/train.py | 20 ++++++++++++++++ 4 files changed, 105 insertions(+), 13 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 55a546356e..d6618fbb62 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -93,9 +93,17 @@ def is_better(a, b): if len(checkpoints) > 0: trainer.save_checkpoint(checkpoints[0], extra_state) for cp in checkpoints[1:]: - assert PathManager.copy( - checkpoints[0], cp, overwrite=True - ), f"Failed to copy {checkpoints[0]} to {cp}" + if cfg.write_checkpoints_asynchronously: + # TODO[ioPath]: Need to implement a delayed asynchronous + # file copying/moving feature. + logger.warning( + f"ioPath is not copying {checkpoints[0]} to {cp} " + "since async write mode is on." + ) + else: + assert PathManager.copy( + checkpoints[0], cp, overwrite=True + ), f"Failed to copy {checkpoints[0]} to {cp}" write_timer.stop() logger.info( @@ -383,7 +391,23 @@ def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt"): return [os.path.join(path, x[1]) for x in sorted(entries, reverse=True)] -def torch_persistent_save(obj, f): +def torch_persistent_save(cfg: CheckpointConfig, obj, filename): + if cfg.write_checkpoints_asynchronously: + with PathManager.opena(filename, "wb") as f: + _torch_persistent_save(obj, f) + else: + if PathManager.supports_rename(filename): + # do atomic save + with PathManager.open(filename + ".tmp", "wb") as f: + _torch_persistent_save(obj, f) + PathManager.rename(filename + ".tmp", filename) + else: + # fallback to non-atomic save + with PathManager.open(filename, "wb") as f: + _torch_persistent_save(obj, f) + + +def _torch_persistent_save(obj, f): if isinstance(f, str): with PathManager.open(f, "wb") as h: torch_persistent_save(obj, h) @@ -448,15 +472,7 @@ def save_state( # keep everything on CPU state_dict = utils.move_to_cpu(state_dict) - if PathManager.supports_rename(filename): - # do atomic save - with PathManager.open(filename + ".tmp", "wb") as f: - torch_persistent_save(state_dict, f) - PathManager.rename(filename + ".tmp", filename) - else: - # fallback to non-atomic save - with PathManager.open(filename, "wb") as f: - torch_persistent_save(state_dict, f) + torch_persistent_save(cfg.checkpoint, state_dict, filename) def _upgrade_state_dict(state): diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index f66e98fe83..39355b1caf 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -607,6 +607,16 @@ class CheckpointConfig(FairseqDataclass): "(default: only load on rank 0 and broadcast to other devices)" }, ) + write_checkpoints_asynchronously: bool = field( + default=False, + metadata={ + "help": ( + "Write checkpoints asynchronously in a separate " + "thread. NOTE: This feature is currently being tested." + ), + "argparse_alias": "--save-async", + }, + ) model_parallel_size: int = II("common.model_parallel_size") distributed_rank: int = II("distributed_training.distributed_rank") diff --git a/fairseq/file_io.py b/fairseq/file_io.py index 7d6c28dccd..731fef3570 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -32,6 +32,8 @@ except ImportError: FVCorePathManager = None +IOPathPathManager = None + class PathManager: """ @@ -148,3 +150,47 @@ def supports_rename(path: str) -> bool: @staticmethod def rename(src: str, dst: str): os.rename(src, dst) + + """ + ioPath async PathManager methods: + """ + @staticmethod + def opena( + path: str, + mode: str = "r", + buffering: int = -1, + encoding: Optional[str] = None, + errors: Optional[str] = None, + newline: Optional[str] = None, + ): + """ + Return file descriptor with asynchronous write operations. + """ + global IOPathPathManager + if not IOPathPathManager: + logging.info("ioPath is initializing PathManager.") + try: + from iopath import PathManager + IOPathPathManager = PathManager() + except Exception: + logging.exception("Failed to initialize ioPath PathManager object.") + return IOPathPathManager.opena( + path=path, + mode=mode, + buffering=buffering, + encoding=encoding, + errors=errors, + newline=newline, + ) + + @staticmethod + def async_close() -> bool: + """ + Wait for files to be written and clean up asynchronous PathManager. + NOTE: `PathManager.async_close()` must be called at the end of any + script that uses `PathManager.opena(...)`. + """ + global IOPathPathManager + if IOPathPathManager: + return IOPathPathManager.async_close() + return False diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index ec4890b9e6..80ad57acd1 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -28,6 +28,7 @@ from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.distributed_utils import is_master +from fairseq.file_io import PathManager from fairseq.logging import meters, metrics, progress_bar from fairseq.model_parallel.megatron_trainer import MegatronTrainer from fairseq.trainer import Trainer @@ -67,6 +68,16 @@ def main(cfg: FairseqConfig) -> None: # Print args logger.info(cfg) + if cfg.checkpoint.write_checkpoints_asynchronously: + try: + import iopath # noqa: F401 + except ImportError: + logging.exception( + "Asynchronous checkpoint writing is specified but iopath is " + "not installed: `pip install iopath`" + ) + return + # Setup task, e.g., translation, language modeling, etc. task = tasks.setup_task(cfg.task) # Load valid dataset (we load training data below, based on the latest checkpoint) @@ -157,6 +168,15 @@ def main(cfg: FairseqConfig) -> None: train_meter.stop() logger.info("done training in {:.1f} seconds".format(train_meter.sum)) + # ioPath implementation to wait for all asynchronous file writes to complete. + if cfg.checkpoint.write_checkpoints_asynchronously: + logger.info( + "ioPath PathManager waiting for all asynchronous checkpoint " + "writes to finish." + ) + PathManager.async_close() + logger.info("ioPath PathManager finished waiting.") + def should_stop_early(cfg: DictConfig, valid_loss: float) -> bool: # skip check if no validation was done in the current epoch From 12e21b9a6e7262fa1af2090e22c301bc0b5d1399 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Tue, 2 Mar 2021 13:28:53 -0800 Subject: [PATCH 253/774] Add global cmvn for mustc data preparation (#1660) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1660 Reviewed By: jmp84, kahne Differential Revision: D26708521 Pulled By: xutaima fbshipit-source-id: c53e9052298c559706ceffeb359dadfede2f1a09 --- examples/speech_to_text/data_utils.py | 32 +++++++++++++++++-- examples/speech_to_text/prep_mustc_data.py | 37 ++++++++++++++++++++-- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index 0d7c034419..fa0d459611 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -126,7 +126,9 @@ def gen_config_yaml( specaugment_policy: str = "lb", prepend_tgt_lang_tag: bool = False, sampling_alpha: float = 1.0, - audio_root: str = "" + audio_root: str = "", + cmvn_type: str = "utterance", + gcmvn_path: Optional[Path] = None, ): manifest_root = manifest_root.absolute() writer = S2TDataConfigWriter(manifest_root / yaml_filename) @@ -151,8 +153,19 @@ def gen_config_yaml( if prepend_tgt_lang_tag: writer.set_prepend_tgt_lang_tag(True) writer.set_sampling_alpha(sampling_alpha) - writer.set_feature_transforms("_train", ["utterance_cmvn", "specaugment"]) - writer.set_feature_transforms("*", ["utterance_cmvn"]) + + if cmvn_type not in ["global", "utterance"]: + raise NotImplementedError + + writer.set_feature_transforms("_train", [f"{cmvn_type}_cmvn", "specaugment"]) + writer.set_feature_transforms("*", [f"{cmvn_type}_cmvn"]) + + if cmvn_type == "global": + assert gcmvn_path is not None, ( + 'Please provide path of global cmvn file.' + ) + writer.set_global_cmvn(gcmvn_path) + if len(audio_root) > 0: writer.set_audio_root(audio_root) writer.flush() @@ -206,6 +219,16 @@ def filter_manifest_df( return df[valid] +def cal_gcmvn_stats(features_list): + features = np.concatenate(features_list) + square_sums = (features ** 2).sum(axis=0) + mean = features.mean(axis=0) + features = np.subtract(features, mean) + var = square_sums / features.shape[0] - mean ** 2 + std = np.sqrt(np.maximum(var, 1e-8)) + return {"mean": mean.astype("float32"), "std": std.astype("float32")} + + class S2TDataConfigWriter(object): DEFAULT_VOCAB_FILENAME = "dict.txt" DEFAULT_INPUT_FEAT_PER_CHANNEL = 80 @@ -297,6 +320,9 @@ def set_input_feat_per_channel(self, input_feat_per_channel: int = 80): def set_bpe_tokenizer(self, bpe_tokenizer: Dict[str, Any]): self.config["bpe_tokenizer"] = bpe_tokenizer + def set_global_cmvn(self, stats_npz_path: str): + self.config["stats_npz_path"] = stats_npz_path + def set_feature_transforms(self, split: str, transforms: List[str]): if "transforms" not in self.config: self.config["transforms"] = {} diff --git a/examples/speech_to_text/prep_mustc_data.py b/examples/speech_to_text/prep_mustc_data.py index 520968401c..4e410bcb18 100644 --- a/examples/speech_to_text/prep_mustc_data.py +++ b/examples/speech_to_text/prep_mustc_data.py @@ -13,6 +13,7 @@ from tempfile import NamedTemporaryFile from typing import Tuple +import numpy as np import pandas as pd import torchaudio from examples.speech_to_text.data_utils import ( @@ -24,6 +25,7 @@ get_zip_manifest, load_df_from_tsv, save_df_to_tsv, + cal_gcmvn_stats, ) from torch import Tensor from torch.utils.data import Dataset @@ -111,10 +113,28 @@ def process(args): print(f"Fetching split {split}...") dataset = MUSTC(root.as_posix(), lang, split) print("Extracting log mel filter bank features...") + if split == 'train' and args.cmvn_type == "global": + print("And estimating cepstral mean and variance stats...") + gcmvn_feature_list = [] + for waveform, sample_rate, _, _, _, utt_id in tqdm(dataset): - extract_fbank_features( - waveform, sample_rate, feature_root / f"{utt_id}.npy" + features = extract_fbank_features(waveform, sample_rate) + + np.save( + (feature_root / f"{utt_id}.npy").as_posix(), + features ) + + if split == 'train' and args.cmvn_type == "global": + if len(gcmvn_feature_list) < args.gcmvn_max_num: + gcmvn_feature_list.append(features) + + if split == 'train' and args.cmvn_type == "global": + # Estimate and save cmv + stats = cal_gcmvn_stats(gcmvn_feature_list) + with open(cur_root / "gcmvn.npz", "wb") as f: + np.savez(f, mean=stats["mean"], std=stats["std"]) + # Pack features into ZIP zip_path = cur_root / "fbank80.zip" print("ZIPing features...") @@ -158,6 +178,11 @@ def process(args): spm_filename_prefix + ".model", yaml_filename=f"config_{args.task}.yaml", specaugment_policy="lb", + cmvn_type=args.cmvn_type, + gcmvn_cmvn_path=( + cur_root / "gcmvn.npz" if args.cmvn_type == "global" + else None + ), ) # Clean up shutil.rmtree(feature_root) @@ -216,6 +241,14 @@ def main(): parser.add_argument("--vocab-size", default=8000, type=int) parser.add_argument("--task", type=str, choices=["asr", "st"]) parser.add_argument("--joint", action="store_true", help="") + parser.add_argument("--cmvn-type", default="utterance", + choices=["global", "utterance"], + help="The type of cepstral mean and variance normalization") + parser.add_argument("--gcmvn-max-num", default=150000, type=int, + help=( + "Maximum number of sentences to use to estimate" + "global mean and variance" + )) args = parser.parse_args() if args.joint: From c58af189957eb15b47e507473b4da3e83dfbdf2e Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Tue, 2 Mar 2021 17:08:45 -0800 Subject: [PATCH 254/774] Several update on simultaneous translation inference. (#1655) Summary: Fix some issues in some corner cases. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1655 Reviewed By: jmp84 Differential Revision: D26651362 Pulled By: sravyapopuri388 fbshipit-source-id: 160d75be8d49f8263c14af225c90fe7997171a43 --- .../models/convtransformer_simul_trans.py | 2 +- .../models/transformer_monotonic_attention.py | 90 ++++--------------- .../modules/fixed_pre_decision.py | 38 ++++++-- .../modules/monotonic_multihead_attention.py | 7 +- .../agents/fairseq_simul_st_agent.py | 32 ++++--- 5 files changed, 76 insertions(+), 93 deletions(-) diff --git a/examples/simultaneous_translation/models/convtransformer_simul_trans.py b/examples/simultaneous_translation/models/convtransformer_simul_trans.py index 84ba4d0d3f..760a48168d 100644 --- a/examples/simultaneous_translation/models/convtransformer_simul_trans.py +++ b/examples/simultaneous_translation/models/convtransformer_simul_trans.py @@ -10,7 +10,6 @@ register_model, register_model_architecture, ) - from fairseq.models.speech_to_text import ConvTransformerModel, convtransformer_espnet @@ -24,6 +23,7 @@ class SimulConvTransformerModel(ConvTransformerModel): https://www.aclweb.org/anthology/2020.aacl-main.58.pdf """ + @staticmethod def add_args(parser): super(SimulConvTransformerModel, SimulConvTransformerModel).add_args(parser) diff --git a/examples/simultaneous_translation/models/transformer_monotonic_attention.py b/examples/simultaneous_translation/models/transformer_monotonic_attention.py index dd3895f0eb..65c12c6f5b 100644 --- a/examples/simultaneous_translation/models/transformer_monotonic_attention.py +++ b/examples/simultaneous_translation/models/transformer_monotonic_attention.py @@ -65,60 +65,6 @@ def _indices_from_states(self, states): return src_indices, None, tgt_indices - def predict_from_states(self, states): - decoder_states = self.decoder.output_layer(states["decoder_features"]) - lprobs = self.get_normalized_probs([decoder_states[:, -1:]], log_probs=True) - - index = lprobs.argmax(dim=-1) - - token = self.decoder.dictionary.string(index) - - return token, index[0, 0].item() - - def decision_from_states(self, states): - """ - This funcion take states dictionary as input, and gives the agent - a decision of whether read a token from server. Moreover, the decoder - states are also calculated here so we can directly generate a target - token without recompute every thing - """ - - self.eval() - - if len(states["tokens"]["src"]) == 0: - return 0 - - src_indices, src_lengths, tgt_indices = self._indices_from_states(states) - - # Update encoder states if needed - if ( - "encoder_states" not in states - or states["encoder_states"][0].size(1) <= states["steps"]["src"] - ): - encoder_out_dict = self.encoder(src_indices, src_lengths) - states["encoder_states"] = encoder_out_dict - else: - encoder_out_dict = states["encoder_states"] - - # online means we still need tokens to feed the model - states["model_states"]["online"] = not ( - states["finish_read"] - and len(states["tokens"]["src"]) == states["steps"]["src"] - ) - - states["model_states"]["steps"] = states["steps"] - - x, outputs = self.decoder.forward( - prev_output_tokens=tgt_indices, - encoder_out=encoder_out_dict, - incremental_state=states["model_states"], - features_only=True, - ) - - states["decoder_features"] = x - - return outputs["action"] - class TransformerMonotonicEncoder(TransformerEncoder): def __init__(self, args, dictionary, embed_tokens): @@ -208,6 +154,18 @@ def post_attention(self, x): return x + def clear_cache(self, incremental_state, end_id=None): + """ + Clear cache in the monotonic layers. + The cache is generated because of a forward pass of decode but no prediction. + end_id is the last idx of the layers + """ + if end_id is None: + end_id = len(self.layers) + + for j in range(end_id): + self.layers[j].prune_incremental_state(incremental_state) + def extract_features( self, prev_output_tokens, encoder_out, incremental_state=None, **unused ): @@ -247,9 +205,13 @@ def extract_features( curr_steps = layer.get_head_steps(incremental_state) step_list.append(curr_steps) - if incremental_state.get("online", False): + if incremental_state.get("online", True): + # Online indicates that the encoder states are still changing p_choose = ( - attn["p_choose"].squeeze(0).squeeze(1).gather(1, curr_steps.t()) + attn["p_choose"] + .squeeze(0) + .squeeze(1) + .gather(1, curr_steps.t()) ) new_steps = curr_steps + (p_choose < 0.5).t().type_as(curr_steps) @@ -258,24 +220,10 @@ def extract_features( # We need to prune the last self_attn saved_state # if model decide not to read # otherwise there will be duplicated saved_state - for j in range(i + 1): - self.layers[j].prune_incremental_state(incremental_state) + self.clear_cache(incremental_state, i + 1) return x, {"action": 0} - if incremental_state is not None and not incremental_state.get("online", False): - # Here is for fast evaluation - fastest_step = ( - torch.max(torch.cat(step_list, dim=1), dim=1, keepdim=True)[0] + 1 - ) - - if "fastest_step" in incremental_state: - incremental_state["fastest_step"] = torch.cat( - [incremental_state["fastest_step"], fastest_step], dim=1 - ) - else: - incremental_state["fastest_step"] = fastest_step - x = self.post_attention(x) return x, { diff --git a/examples/simultaneous_translation/modules/fixed_pre_decision.py b/examples/simultaneous_translation/modules/fixed_pre_decision.py index 725be1a983..cc5e7ad532 100644 --- a/examples/simultaneous_translation/modules/fixed_pre_decision.py +++ b/examples/simultaneous_translation/modules/fixed_pre_decision.py @@ -1,6 +1,7 @@ from functools import partial import torch +import math import torch.nn.functional as F from . import register_monotonic_attention @@ -96,6 +97,9 @@ def p_choose( incremental_state=None, **extra_args ): + src_len = key.size(0) + tgt_len = query.size(0) + batch_size = query.size(1) if self.pre_decision_ratio == 1: return super().p_choose( @@ -119,6 +123,16 @@ def p_choose( else: key_padding_mask_pool = None + if incremental_state is not None: + # The floor instead of ceil is used for inference + # But make sure the length key_pool at least 1 + if ( + max(1, math.floor(key.size(0) / self.pre_decision_ratio)) + ) < key_pool.size(0): + key_pool = key_pool[:-1] + if key_padding_mask_pool is not None: + key_padding_mask_pool = key_padding_mask_pool[:-1] + p_choose_pooled = super().p_choose( query, key_pool, @@ -129,13 +143,23 @@ def p_choose( # Upsample, interpolate zeros p_choose = self.insert_zeros(p_choose_pooled) - # can be larger than src_len because we used ceil before - src_len = key.size(0) - p_choose = p_choose[:, :, :src_len] - p_choose[:, :, -1] = p_choose_pooled[:, :, -1] - - tgt_len = query.size(0) - batch_size = query.size(1) + if p_choose.size(-1) < src_len: + # Append zeros if the upsampled p_choose is shorter than src_len + p_choose = torch.cat( + [ + p_choose, + p_choose.new_zeros( + p_choose.size(0), + tgt_len, + src_len - p_choose.size(-1) + ) + ], + dim=2 + ) + else: + # can be larger than src_len because we used ceil before + p_choose = p_choose[:, :, :src_len] + p_choose[:, :, -1] = p_choose_pooled[:, :, -1] assert list(p_choose.size()) == [ batch_size * self.num_heads, diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index 3e25957cd6..49882afcd8 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -604,13 +604,14 @@ def p_choose( key_padding_mask: bsz, src_len """ if incremental_state is not None: + # Retrieve target length from incremental states + # For inference the length of query is always 1 tgt_len = int(incremental_state["steps"]["tgt"]) - src_len = int(incremental_state["steps"]["src"]) - bsz = 1 else: - src_len, bsz, _ = key.size() tgt_len, bsz, _ = query.size() + src_len, bsz, _ = key.size() + p_choose = query.new_ones(bsz, tgt_len, src_len) p_choose = torch.tril(p_choose, diagonal=self.waitk_lagging - 1) p_choose = torch.triu(p_choose, diagonal=self.waitk_lagging - 1) diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index 5793609095..f944203785 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -127,6 +127,15 @@ def __init__(self, args): self.load_model_vocab(args) + if getattr( + self.model.decoder.layers[0].encoder_attn, + 'pre_decision_ratio', + None + ) is not None: + self.speech_segment_size *= ( + self.model.decoder.layers[0].encoder_attn.pre_decision_ratio + ) + with open(args.config, "r") as f: config = yaml.load(f, Loader=yaml.BaseLoader) @@ -167,15 +176,15 @@ def add_args(parser): parser.add_argument("--max-len", type=int, default=200, help="Max length of translation") parser.add_argument("--force-finish", default=False, action="store_true", - help="") + help="Force the model to finish the hypothsis if the source is not finished") parser.add_argument("--shift-size", type=int, default=SHIFT_SIZE, - help="") + help="Shift size of feature extraction window.") parser.add_argument("--window-size", type=int, default=WINDOW_SIZE, - help="") + help="Window size of feature extraction window.") parser.add_argument("--sample-rate", type=int, default=SAMPLE_RATE, - help="") + help="Sample rate") parser.add_argument("--feature-dim", type=int, default=FEATURE_DIM, - help="") + help="Acoustic feature dimension.") # fmt: on return parser @@ -265,11 +274,12 @@ def units_to_segment(self, units, states): def update_model_encoder(self, states): if len(states.units.source) == 0: return - src_indices = self.to_device(states.units.source.value.unsqueeze(0)) + src_indices = self.to_device( + states.units.source.value.unsqueeze(0) + ) src_lengths = self.to_device( torch.LongTensor([states.units.source.value.size(0)]) ) - print(src_lengths) states.encoder_states = self.model.encoder(src_indices, src_lengths) torch.cuda.empty_cache() @@ -294,13 +304,12 @@ def policy(self, states): "tgt": 1 + len(states.units.target), } - states.incremental_states["online"] = True + states.incremental_states["online"] = not states.finish_read() x, outputs = self.model.decoder.forward( prev_output_tokens=tgt_indices, encoder_out=states.encoder_states, incremental_state=states.incremental_states, - # features_only=True, ) states.decoder_out = x @@ -323,8 +332,6 @@ def predict(self, states): index = lprobs.argmax(dim=-1) - torch.cuda.empty_cache() - index = index[0, 0].item() if ( @@ -332,6 +339,9 @@ def predict(self, states): and index == self.model.decoder.dictionary.eos() and not states.finish_read() ): + # If we want to force finish the translation + # (don't stop before finish reading), return a None + # self.model.decoder.clear_cache(states.incremental_states) index = None return index From ddc483ff3d3a70f3abc33fc4d10bb29871c73d73 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Tue, 2 Mar 2021 17:08:45 -0800 Subject: [PATCH 255/774] Streaming models for simul ST (#1552) Summary: `fairseq/models/speech_to_text/modules/emformer.py` mostly contains the code from Yangyang. I did a little modification to make it run on fairseq. `fairseq/models/speech_to_text/modules/augmented_memory_attention.py` contains code for the old streaming models `fairseq/models/speech_to_text/modules/convtransformer_simul_trans.py` contaons three convtransformer based simultaneous translation models. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1552 Reviewed By: jmp84 Differential Revision: D26563864 Pulled By: sravyapopuri388 fbshipit-source-id: a91a6247559861977cbc22db00ba9511f6b21c69 --- .../modules/augmented_memory_attention.py | 486 +++++ .../models/speech_to_text/modules/emformer.py | 1838 +++++++++++++++++ fairseq/models/speech_to_text/utils.py | 564 +++++ 3 files changed, 2888 insertions(+) create mode 100644 fairseq/models/speech_to_text/modules/augmented_memory_attention.py create mode 100644 fairseq/models/speech_to_text/modules/emformer.py create mode 100644 fairseq/models/speech_to_text/utils.py diff --git a/fairseq/models/speech_to_text/modules/augmented_memory_attention.py b/fairseq/models/speech_to_text/modules/augmented_memory_attention.py new file mode 100644 index 0000000000..5d31524b76 --- /dev/null +++ b/fairseq/models/speech_to_text/modules/augmented_memory_attention.py @@ -0,0 +1,486 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Tuple, List + +import torch +import torch.nn.functional as F +from fairseq.models import FairseqEncoder +from fairseq.models.fairseq_encoder import EncoderOut +from fairseq.models.speech_to_text import ( + ConvTransformerEncoder, +) +from fairseq.models.speech_to_text.utils import attention_suppression +from fairseq.models.speech_to_text.utils import ( + lengths_to_encoder_padding_mask, + segments_to_sequence, + sequence_to_segments, +) +from fairseq.modules import MultiheadAttention, TransformerEncoderLayer +from torch import nn, Tensor + +# ------------------------------------------------------------------------------ +# AugmentedMemoryConvTransformerEncoder +# ------------------------------------------------------------------------------ + + +class AugmentedMemoryConvTransformerEncoder(ConvTransformerEncoder): + def __init__(self, args): + super().__init__(args) + + args.encoder_stride = self.stride() + + self.left_context = args.left_context // args.encoder_stride + + self.right_context = args.right_context // args.encoder_stride + + self.left_context_after_stride = args.left_context // args.encoder_stride + self.right_context_after_stride = args.right_context // args.encoder_stride + + self.transformer_layers = nn.ModuleList([]) + self.transformer_layers.extend( + [ + AugmentedMemoryTransformerEncoderLayer(args) + for i in range(args.encoder_layers) + ] + ) + + def stride(self): + # Hard coded here. Should infer from convs in future + stride = 4 + return stride + + def forward(self, src_tokens, src_lengths, states=None): + """Encode input sequence. + :param torch.Tensor xs: input tensor + :param torch.Tensor masks: input mask + :return: position embedded tensor and mask + :rtype Tuple[torch.Tensor, torch.Tensor]: + """ + bsz, max_seq_len, _ = src_tokens.size() + x = ( + src_tokens.view(bsz, max_seq_len, self.in_channels, self.input_dim) + .transpose(1, 2) + .contiguous() + ) + x = self.conv(x) + bsz, _, output_seq_len, _ = x.size() + x = x.transpose(1, 2).transpose(0, 1).contiguous().view(output_seq_len, bsz, -1) + x = self.out(x) + x = self.embed_scale * x + + subsampling_factor = 1.0 * max_seq_len / output_seq_len + input_lengths = (src_lengths.float() / subsampling_factor).round().long() + + encoder_padding_mask, _ = lengths_to_encoder_padding_mask( + input_lengths, batch_first=True + ) + + # TODO: fix positional embedding + positions = self.embed_positions(encoder_padding_mask).transpose(0, 1) + + x += positions + x = F.dropout(x, p=self.dropout, training=self.training) + + # State to store memory banks etc. + if states is None: + states = [ + {"memory_banks": None, "encoder_states": None} + for i in range(len(self.transformer_layers)) + ] + + for i, layer in enumerate(self.transformer_layers): + # x size: + # (self.left_size + self.segment_size + self.right_size) + # / self.stride, num_heads, dim + # TODO: Consider mask here + x = layer(x, states[i]) + states[i]["encoder_states"] = x[ + self.left_context_after_stride : -self.right_context_after_stride + ] + + lengths = ( + ( + ~encoder_padding_mask[ + :, self.left_context_after_stride : -self.right_context_after_stride + ] + ) + .sum(dim=1, keepdim=True) + .long() + ) + + return states[-1]["encoder_states"], lengths, states + + +# ------------------------------------------------------------------------------ +# AugmentedMemoryTransformerEncoderLayer +# ------------------------------------------------------------------------------ +class AugmentedMemoryTransformerEncoderLayer(TransformerEncoderLayer): + def __init__(self, args): + super().__init__(args) + + self.left_context = args.left_context // args.encoder_stride + self.right_context = args.right_context // args.encoder_stride + + def forward(self, x, state): + + length, batch_size, x_dim = x.size() + + residual = x + + if self.normalize_before: + x = self.self_attn_layer_norm(x) + + # init_state + if state.get("memory_banks", None) is None: + state["memory_banks"] = [] + + # TODO reseach new sum_query method + seg_start = self.left_context + seg_end = length - self.right_context + if seg_start < seg_end: + summarization_query = torch.mean(x[seg_start:seg_end], keepdim=True, dim=0) + else: + summarization_query = x.new_zeros(1, batch_size, x_dim) + + x = torch.cat([x, summarization_query], dim=0) + + x = self.self_attn(input_and_summary=x, state=state) + + x = self.dropout_module(x) + x = residual + x + + if not self.normalize_before: + x = self.self_attn_layer_norm(x) + + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) + x = self.dropout_module(x) + x = residual + x + if not self.normalize_before: + x = self.final_layer_norm(x) + + return x + + def build_self_attention(self, embed_dim, args): + return AugmentedMemoryMultiheadAttention( + embed_dim=embed_dim, + num_heads=args.encoder_attention_heads, + dropout=args.attention_dropout, + self_attention=True, + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + tanh_on_mem=True, + max_memory_size=args.max_memory_size, + ) + + +# ------------------------------------------------------------------------------ +# AugmentedMemoryMultiheadAttention +# ------------------------------------------------------------------------------ +class AugmentedMemoryMultiheadAttention(MultiheadAttention): + """ + Augmented Memory Attention from + Streaming Transformer-based Acoustic Models + Using Self-attention with Augmented Memory + https://arxiv.org/abs/2005.08042 + """ + + def __init__( + self, + embed_dim, + num_heads, + kdim=None, + vdim=None, + dropout=0.0, + bias=True, + add_bias_kv=False, + add_zero_attn=False, + self_attention=False, + encoder_decoder_attention=False, + q_noise=0.0, + qn_block_size=8, + tanh_on_mem=False, + memory_dim=None, + std_scale=0.5, # 0.5 based on https://arxiv.org/abs/2005.09137 + max_memory_size=-1, + disable_mem_on_mem_attn=True, + ): + super().__init__( + embed_dim, + num_heads, + kdim, + vdim, + dropout, + bias, + add_bias_kv, + add_zero_attn, + self_attention, + encoder_decoder_attention, + q_noise, + qn_block_size, + ) + + self.memory_dim = memory_dim if memory_dim is not None else embed_dim + self.std_scale = std_scale + self.disable_mem_on_mem_attn = disable_mem_on_mem_attn + + # This Operator was used for factorization in PySpeech + self.v2e = lambda x: x + + if tanh_on_mem: + self.squash_mem = torch.tanh + self.nonlinear_squash_mem = True + else: + self.squash_mem = lambda x: x + self.nonlinear_squash_mem = False + + self.max_memory_size = max_memory_size + + def forward(self, input_and_summary, state): + """ + input: Encoder states of current segment with left or right context, + plus one summarization query + + """ + + length, batch_size, _ = input_and_summary.shape + length = length - 1 # not include sum_query, last index + + memory = state["memory_banks"] + # TODO: positional embedding on memory + + if self.max_memory_size > -1 and len(memory) > self.max_memory_size: + # TODO: need to fix here + if self.max_memory_size == 0: + memory = memory.new_zeros(1, memory.size(1), self.memory_dim) + else: + memory = memory[-self.max_memory_size :] + + memory_and_input = torch.cat(memory + [input_and_summary[:-1]], dim=0) + input_and_sum_query = input_and_summary + + q = self.q_proj(self.v2e(input_and_sum_query)) + k = self.k_proj(self.v2e(memory_and_input)) + v = self.v_proj(self.v2e(memory_and_input)) + + q = ( + q.contiguous() + .view(-1, batch_size * self.num_heads, self.head_dim) + .transpose(0, 1) + * self.scaling + ) + k = ( + k.contiguous() + .view(-1, batch_size * self.num_heads, self.head_dim) + .transpose(0, 1) + ) + + v = ( + v.contiguous() + .view(-1, batch_size * self.num_heads, self.head_dim) + .transpose(0, 1) + ) + + attention_weights = torch.bmm(q, k.transpose(1, 2)) + + if self.disable_mem_on_mem_attn: + attention_weights = self.suppress_mem_on_mem_attention( + batch_size, self.num_heads, len(memory), attention_weights + ) + + if self.std_scale is not None: + attention_weights = attention_suppression(attention_weights, self.std_scale) + + assert list(attention_weights.shape) == [ + batch_size * self.num_heads, + length + 1, + length + len(memory), + ] + + attention_weights = torch.nn.functional.softmax( + attention_weights.float(), dim=-1 + ).type_as(attention_weights) + + attention_probs = self.dropout_module(attention_weights) + + # [T, T, B, n_head] + [T, B, n_head, d_head] -> [T, B, n_head, d_head] + attention = torch.bmm(attention_probs, v) + + assert list(attention.shape) == [ + batch_size * self.num_heads, + length + 1, + self.head_dim, + ] + + attention = ( + attention.transpose(0, 1) + .contiguous() + .view(length + 1, batch_size, self.embed_dim) + ) + + output_and_memory = self.out_proj(attention) + + next_m = output_and_memory[-1:] + next_m = self.squash_mem(next_m) + output = output_and_memory[:-1] + + state["memory_banks"].append(next_m) + + return output + + def suppress_mem_on_mem_attention( + self, B: int, num_heads: int, mem_size: int, attention_weight: Tensor + ): + """ + Arguments: + - B: batch size + - num_heads: number of attention heads + - mem_size: size of memory bank + - attention_weight: a [B*num_heads, T + 1, T + mem_size] vector + + Return: + modified attention_weight with [B*num_heads, -1, :mem_size] = -inf + """ + attention_weight[:, -1, :mem_size] = float("-inf") + return attention_weight + + +# ------------------------------------------------------------------------------ +# SequenceEncoder +# ------------------------------------------------------------------------------ +class SequenceEncoder(FairseqEncoder): + """ + SequenceEncoder encodes sequences. + + More specifically, `src_tokens` and `src_lengths` in `forward()` should + describe a batch of "complete" sequences rather than segments. + + Segment-by-segment inference can be triggered by `segment_size`: + 1) `segment_size` is None: + SequenceEncoder treats the input sequence as one single segment. + 2) `segment_size` is not None (some int instead): + SequenceEncoder does the following: + 1. breaks the input sequence into several segments + 2. inference on each segment and collect the outputs + 3. concatanete segment outputs into the output sequence. + Note that `segment_size` here shouldn't include additional left/right + contexts needed, for example if we wish to infer with LC-BLSTM where the + middle chunk size is 100 and right context is 20, `segment_size` should be + 100. + """ + + def __init__(self, args, module): + super().__init__(None) + + self.module = module + self.input_time_axis = 1 + self.output_time_axis = 0 + self.segment_size = args.segment_size + self.left_context = args.left_context + self.right_context = args.right_context + + def forward( + self, + src_tokens: Tensor, + src_lengths: Tensor, + states=None, + ): + + seg_src_tokens_lengths = sequence_to_segments( + sequence=src_tokens, + time_axis=self.input_time_axis, + lengths=src_lengths, + segment_size=self.segment_size, + extra_left_context=self.left_context, + extra_right_context=self.right_context, + ) + + seg_encoder_states_lengths: List[Tuple[Tensor, Tensor]] = [] + + for seg_src_tokens, seg_src_lengths in seg_src_tokens_lengths: + (seg_encoder_states, seg_enc_lengths, states) = self.module( + seg_src_tokens, + seg_src_lengths, + states=states, + ) + + seg_encoder_states_lengths.append((seg_encoder_states, seg_enc_lengths)) + + encoder_out, enc_lengths = segments_to_sequence( + segments=seg_encoder_states_lengths, time_axis=self.output_time_axis + ) + + encoder_padding_mask, _ = lengths_to_encoder_padding_mask( + enc_lengths, batch_first=True + ) + + if not encoder_padding_mask.any(): + encoder_padding_mask = None + + return EncoderOut( + encoder_out=encoder_out, + encoder_padding_mask=encoder_padding_mask, + encoder_embedding=None, + encoder_states=states, + src_tokens=None, + src_lengths=None, + ) + + def incremental_encode( + self, + seg_src_tokens: Tensor, + seg_src_lengths: Tensor, + states=None, + ): + """ + Different from forward function, this function takes segmented speech + as input, and append encoder states to previous states + """ + (seg_encoder_states, seg_enc_lengths, states) = self.module( + seg_src_tokens, + seg_src_lengths, + states=states, + ) + return seg_encoder_states, seg_enc_lengths, states + + +# ------------------------------------------------------------------------------ +# Augmented memory model decorator +# ------------------------------------------------------------------------------ +def augmented_memory(klass): + class StreamSeq2SeqModel(klass): + @staticmethod + def add_args(parser): + super(StreamSeq2SeqModel, StreamSeq2SeqModel).add_args(parser) + parser.add_argument( + "--segment-size", type=int, required=True, help="Length of the segment." + ) + parser.add_argument( + "--left-context", + type=int, + default=0, + help="Left context for the segment.", + ) + parser.add_argument( + "--right-context", + type=int, + default=0, + help="Right context for the segment.", + ) + parser.add_argument( + "--max-memory-size", + type=int, + default=-1, + help="Right context for the segment.", + ) + + StreamSeq2SeqModel.__name__ = klass.__name__ + return StreamSeq2SeqModel diff --git a/fairseq/models/speech_to_text/modules/emformer.py b/fairseq/models/speech_to_text/modules/emformer.py new file mode 100644 index 0000000000..42b157b766 --- /dev/null +++ b/fairseq/models/speech_to_text/modules/emformer.py @@ -0,0 +1,1838 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + + +import math +import re +from functools import partial +from typing import List, Optional, Tuple + +import torch +import torch.nn as nn +from fairseq.models import ( + FairseqEncoder, +) +from fairseq.models.fairseq_encoder import EncoderOut +from fairseq.models.speech_to_text.utils import ( + NoOp, + lengths_to_padding_mask, + segments_to_sequence, +) +from fairseq.models.speech_to_text.utils import ( + attention_suppression, + layer_norm_backward_hook, +) +from torch import Tensor, device as Device +from torch.quantization.qconfig import ( + default_dynamic_qconfig, + per_channel_dynamic_qconfig, +) + + +class RelativePositionEmbedding(nn.Module): + """ + Implementation according to https://arxiv.org/abs/1803.02155 + """ + + def __init__(self, head_dim, max_position, norm_init=True): + super().__init__() + self.head_dim = head_dim + self.max_position = max_position + self.embeddings = nn.Parameter(torch.Tensor(max_position * 2 + 1, head_dim)) + if norm_init: + nn.init.xavier_normal_(self.embeddings) + else: + nn.init.xavier_uniform_(self.embeddings) + + def forward(self, input: Tensor): + output = nn.functional.embedding(input.long(), self.embeddings) + return output + + +class Fp32LayerNorm(nn.Module): + def __init__( + self, + input_dim, + clamp_grad=True, + max_grad_value=256, + eps=1e-5, + elementwise_affine=True, + ): + super().__init__() + self.torch_module = torch.nn.LayerNorm( + input_dim, eps=eps, elementwise_affine=elementwise_affine + ) + if clamp_grad: + hook = partial(layer_norm_backward_hook, clamp_value=max_grad_value) + self.torch_module.register_backward_hook(hook) + + def forward(self, input): + output = torch.nn.functional.layer_norm( + input.float(), + self.torch_module.normalized_shape, + self.torch_module.weight.float() + if self.torch_module.weight is not None + else None, + self.torch_module.bias.float() + if self.torch_module.bias is not None + else None, + self.torch_module.eps, + ).type_as(input) + return output + + +# ------------------------------------------------------------------------------ +# PositionwiseFF +# ------------------------------------------------------------------------------ + + +class PositionwiseFF(nn.Module): + """ + FFN layer in transformer. + + Args: + input_dim: input embedding dimension + ffn_dim: FFN layer inner dimension + dropout_on_fc1: dropout for first linear layer + dropout_on_fc2: dropout fr second linear layer + activation_fn: activation function used after first linear layer. \ + Only relu or gelu is supported. + + """ + + def __init__( + self, input_dim, ffn_dim, dropout_on_fc1, dropout_on_fc2, activation_fn + ): + super(PositionwiseFF, self).__init__() + + self.input_dim = input_dim + self.ffn_dim = ffn_dim + if activation_fn == "relu": + ac = nn.ReLU() + elif activation_fn == "gelu": + ac = nn.GELU() + else: + raise ValueError("Unsupported activation_fn = ({})".format(activation_fn)) + + # fc1 -> ac -> dropout -> fc2 -> dropout + self.module = nn.Sequential( + nn.Linear(input_dim, ffn_dim), + ac, + nn.Dropout(dropout_on_fc1), + nn.Linear(ffn_dim, input_dim), + nn.Dropout(dropout_on_fc2), + ) + + self.layer_norm = Fp32LayerNorm(input_dim) + + def forward(self, input): + module_out = self.module(self.layer_norm(input)) + output = module_out + input + + return output + + def quantize_(self, params=None): + if params and "per_channel" in params and params["per_channel"]: + qconfig = per_channel_dynamic_qconfig + else: + qconfig = default_dynamic_qconfig + torch.quantization.quantize_dynamic( + self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True + ) + return self + + +# ------------------------------------------------------------------------------ +# SummarizationLayer +# ------------------------------------------------------------------------------ + + +class SummarizationLayer(nn.Module): + def __init__(self, method, segment_size, embedding_dim): + super(SummarizationLayer, self).__init__() + self.segment_size = segment_size + self.embedding_dim = embedding_dim + nonlin_match = re.match(r"nonlinear\((?P<act>[a-z]+),(?P<dim>[0-9]+)\)", method) + self.method = method + if method == "mean": + self.module = nn.AvgPool1d( + kernel_size=segment_size, + stride=segment_size, + ceil_mode=True, + ) + elif method == "max": + self.module = nn.MaxPool1d( + kernel_size=segment_size, + stride=segment_size, + ceil_mode=True, + ) + elif method == "linear": + self.module = nn.Linear(segment_size, 1) + elif nonlin_match: + nonlin_args = nonlin_match.groupdict() + act_type = nonlin_args["act"] + hid_dim = int(nonlin_args["dim"]) + if act_type == "relu": + act = nn.ReLU() + elif act_type == "gelu": + act = nn.GELU() + else: + raise ValueError("Unsupported activation_fn = ({})".format(act_type)) + self.module = nn.Sequential( + nn.Linear(segment_size, hid_dim), + act, + nn.Linear(hid_dim, 1), + ) + else: + raise ValueError("Unsupported summarization method = ({})".format(method)) + + def forward(self, input): + # T, B, D -> B, D, T + input = input.permute(1, 2, 0) + + if self.method == "mean" or self.method == "max": + output = self.module(input) + output = output.permute(2, 0, 1) + return output + + full_seg_length = input.size(2) // self.segment_size * self.segment_size + if full_seg_length > 0: + # at least one seg is full + B = input.size(0) + D = input.size(1) + input_todo = ( + input[:, :, :full_seg_length] + .contiguous() + .view(B, -1, self.segment_size) + ) + output = self.module(input_todo) + output = output.view(B, D, -1) + else: + output = input.new_zeros(input.size(0), input.size(1), 0) + left = input.size(2) - full_seg_length + if left > 0: + # when last seg is not full, use zeros as last memory placeholder + zeros = input.new_zeros(input.size(0), input.size(1), 1) + output = torch.cat([output, zeros], dim=2) + output = output.permute(2, 0, 1) + return output + + +# ------------------------------------------------------------------------------ +# NoSegAugmentedMemoryMultiheadAttentionBmm +# ------------------------------------------------------------------------------ + + +class NoSegAugmentedMemoryMultiheadAttentionBmm(nn.Module): + """ + Whole utterance augmented memory multihead attention using BMM. + + Different with previous augmented memory multihead attention where + the utterance is chunked into segments. Here we use attention mask + achieve so. The input embedding [right_context, utterance, summary] + is a concatenation of right context, utterance and summary. + + Right context block is the concatenation of all the right context for + each segments. [right_context_0, right_context_1, ..., right_context_n] + For example, if we have utterance = [v0, v1, v2, ...., v20]. segment + size 8, right_context size 4. Then the right context blocks = + [v8, v9, v10, v11, v16, v17, v18, v19, 0, 0, 0, 0], where v8, v9, v10, + and v11 are the right context for first segment. v16, v17, v18 and v19 + are the right context for second segment. 0, 0, 0 and 0 are right context + for the last segment. + + utterance is corresponding to input embedding sequence + + summary is concatenation of average of each segments. [summary_0, + summary_1, ..., ]. + + In augmented memory multihead attention, the query is [right_context, + utterance, summary], key is [memory, right_context, utterance]. Different + with AugmentedMemoryMultiheadAttentionBmm, memory here is passed from + previous attention layer. For the first attention layer, memory is average + of each segment. + + Memory is a concatenation of memory from each segments in previous attention + layer. For example, current layer is i, then memory is [m_0, m_1, ..., m_n]. + Each m_k is the output from seg_k in layer i-1. + + args: + input_dim: input embedding dimension + num_heads: number of heads in multihead self-attention + dropout: attention dropout + std_scale: if std_scale is not None. The weak attention suppression is + turned on. For std_scale = 0.5, all the attention smaller than + mean + 0.5 * std will be suppressed. + scaled_init: whether to use scaled init for linear weight + tanh_on_mem: whether to use tanh on memory output + use_mem: whether to use memory or not. When max_memory_size is 0, then + we don't have memory anymore. + layer_index: current self-attention layer index that is used in depth + initialization + max_relative_position: max relative position used in relative position + embedding + rpe_old_option: To be compatible with previous model. The previous model + was trained with attention += attention + rpe. The correct equation + should be attention = attention + rpe + + """ + + def __init__( + self, + input_dim, + num_heads, + dropout=0.0, + std_scale=None, + scaled_init=False, + tanh_on_mem=False, + use_mem=True, + mini_batches=False, + negative_inf="-inf", + layer_index=-1, + max_relative_position=0, + rpe_old_option=True, + ): + if input_dim % num_heads: + raise ValueError( + "input_dim ({}) must be divisible by num_heads ({})".format( + input_dim, num_heads + ) + ) + + super().__init__() + + embed_dim = input_dim + self.e2h_kv = torch.nn.Linear(input_dim, 2 * input_dim, bias=True) + self.e2h_q = torch.nn.Linear(input_dim, input_dim, bias=True) + self.rpe_old_option = rpe_old_option + if max_relative_position > 0: + self.use_rpe = True + self.rpe_k = RelativePositionEmbedding( + head_dim=input_dim // num_heads, + max_position=max_relative_position, + ) + self.rpe_v = RelativePositionEmbedding( + head_dim=input_dim // num_heads, + max_position=max_relative_position, + ) + else: + self.use_rpe = False + self.rpe_k = None + self.rpe_v = None + if scaled_init: + if layer_index == -1: + gain = 1.0 / math.sqrt(2) + else: + # https://arxiv.org/abs/2005.09684 depthwise initialization + # stablize the training greatly. Use depthwise initialization to + # replace incremental loss. + gain = 1.0 / math.sqrt(layer_index + 1) + torch.nn.init.xavier_uniform_(self.e2h_kv.weight, gain=gain) + torch.nn.init.xavier_uniform_(self.e2h_q.weight, gain=gain) + + self.out_proj = torch.nn.Linear(embed_dim, embed_dim, bias=True) + + self.embed_dim = embed_dim + self.num_heads = num_heads + self.dropout = dropout + + self.head_dim = embed_dim // num_heads + self.scaling = self.head_dim ** -0.5 + + self.std_scale = std_scale + self.use_mem = use_mem + self.mini_batches = mini_batches + self.negative_inf = negative_inf + + if tanh_on_mem: + self.squash_mem = torch.tanh + self.nonlinear_squash_mem = True + else: + self.squash_mem = NoOp() + self.nonlinear_squash_mem = False + + def prepare_qkv( + self, + input: Tensor, + mems: Tensor, + lengths: Tensor, + summary_length: int, + lc_length: int, + ): + # T: right_context length + utterance_length + summary_length + T, B, D = input.shape + mem_length = mems.size(0) + utterance_length = torch.max(lengths) + + right_context_blocks_length = T - utterance_length - summary_length + rc_block = input[:right_context_blocks_length, :, :] + utterance_block = input[right_context_blocks_length : T - summary_length, :, :] + + if B == 1: + padding_mask = None + else: + klengths = lengths + mem_length + right_context_blocks_length + lc_length + padding_mask = lengths_to_padding_mask(lengths=klengths) + + mem_rc_input = torch.cat([mems, rc_block, utterance_block], dim=0) + + # In training lc_length = 0 + key_length = mem_rc_input.size(0) + lc_length + rc_input_sum = input + q = self.e2h_q(rc_input_sum) + kv = self.e2h_kv(mem_rc_input) + k, v = kv.chunk(chunks=2, dim=2) + result_qkv = (q, k, v) + input_shape = (T, B, D) + result_lengths_info = ( + mem_length, + utterance_length, + right_context_blocks_length, + key_length, + ) + if padding_mask is not None: + assert padding_mask.size(0) == B + assert padding_mask.size(1) == key_length + + return result_qkv, input_shape, result_lengths_info, padding_mask + + def prepare_attention_weights( + self, + q: Tensor, + new_k: Tensor, + new_v: Tensor, + input_shape: Tuple[int, int, int], + rpe: Optional[Tensor], + ) -> Tuple[Tensor, Tensor, Tensor]: + T, B, D = input_shape + q = ( + q.contiguous().view(-1, B * self.num_heads, self.head_dim).transpose(0, 1) + * self.scaling + ) + + k = ( + new_k.contiguous() + .view(-1, B * self.num_heads, self.head_dim) + .transpose(0, 1) + ) + + v = ( + new_v.contiguous() + .view(-1, B * self.num_heads, self.head_dim) + .transpose(0, 1) + ) + + attention_weights = torch.bmm(q, k.transpose(1, 2)) + if self.use_rpe and rpe is not None and self.rpe_v is not None: + r_k = self.rpe_k(rpe) + # [q, B*h, d] * [q, k, d] -> [B*h, q, k] + attention_weights_rpe = torch.matmul( + q.transpose(0, 1), r_k.transpose(1, 2) + ).transpose(0, 1) + attention_weights = attention_weights + attention_weights_rpe + attention_weights_float = attention_weights.float() + + return attention_weights, attention_weights_float, v + + def prepare_attention_output( + self, + attention_weights: Tensor, + attention_weights_float: Tensor, + v: Tensor, + input_shape: Tuple[int, int, int], + key_length: int, + padding_mask: Optional[Tensor], + rpe: Optional[Tensor], + ) -> Tensor: + T, B, D = input_shape + if padding_mask is not None: + attention_weights_float = attention_weights_float.view( + B, self.num_heads, T, key_length + ) + attention_weights_float = attention_weights_float.masked_fill( + padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), float("-inf") + ) + attention_weights_float = attention_weights_float.view( + B * self.num_heads, T, key_length + ) + + if self.std_scale is not None: + attention_weights_float = attention_suppression( + attention_weights_float, self.std_scale + ) + + attention_weights_float = torch.nn.functional.softmax( + attention_weights_float, dim=-1 + ) + attention_weights = attention_weights_float.type_as(attention_weights) + + attention_probs = torch.nn.functional.dropout( + attention_weights, p=self.dropout, training=self.training + ) + + # [T, key_length, B, n_head]+ [key_length, B, n_head, d_head] + # -> [T, B, n_head, d_head] + attention = torch.bmm(attention_probs, v) + if self.use_rpe and rpe is not None and self.rpe_v is not None: + r_v = self.rpe_v(rpe) + attention_rpe = torch.matmul( + attention_probs.transpose(0, 1), r_v + ).transpose(0, 1) + + if self.rpe_old_option: + attention += attention + attention_rpe + else: + attention = attention + attention_rpe + + assert list(attention.shape) == [B * self.num_heads, T, self.head_dim] + + attention = attention.transpose(0, 1).contiguous().view(T, B, self.embed_dim) + + rc_output_memory = self.out_proj(attention) + return rc_output_memory + + @torch.jit.unused + def forward( + self, + input: Tensor, + lengths: Tensor, + mems: Tensor, + attention_mask: Tensor, + pre_mems: Optional[Tensor] = None, + left_context_key: Optional[Tensor] = None, + left_context_val: Optional[Tensor] = None, + rpe: Optional[Tensor] = None, + ) -> Tuple[Tensor, Tensor, Tensor, Tensor]: + """ + forward function for NoSegAugmentedMemoryMultiheadAttentionBmm in training. + + args: + input: formed in the following way + [right_context_0, right_contex_1, ..., seg_0, seg_1, + ..., summary_0, summary_1,..] + lengths: the length of query which is [seg_0, seg_1, ....] + mems: [mem_0, mem_1, ...]. + attention_mask: attention mask for query = [right_context, query, summary] + key = [mem, right_context, query]. This is only used for traing. + + """ + if self.use_mem: + mem_length = mems.size(0) + summary_length = mem_length + 1 + if pre_mems is not None: + mems = torch.cat([pre_mems, mems], dim=0) + else: + mem_length = 0 + summary_length = 0 + + # In training, lc_length = 0 + if left_context_key is not None: + lc_length = left_context_key.size(0) + else: + lc_length = 0 + results = self.prepare_qkv( + input=input, + mems=mems, + lengths=lengths, + summary_length=summary_length, + lc_length=lc_length, + ) + result_qkv, input_shape, result_lengths_info, padding_mask = results + q, k, v = result_qkv + ( + mem_length, + utterance_length, + right_context_blocks_length, + key_length, + ) = result_lengths_info + + if left_context_key is not None: + # add the cache key and value + new_k = torch.cat( + [ + k[: mem_length + right_context_blocks_length, :, :], + left_context_key, + k[-utterance_length:, :, :], + ], + dim=0, + ) + new_v = torch.cat( + [ + v[: mem_length + right_context_blocks_length, :, :], + left_context_val, + v[-utterance_length:, :, :], + ], + dim=0, + ) + next_k = new_k[mem_length + right_context_blocks_length :, :, :] + next_v = new_v[mem_length + right_context_blocks_length :, :, :] + else: + new_k = k + new_v = v + next_k = None + next_v = None + + attention_weights, attention_weights_float, v = self.prepare_attention_weights( + q=q, + new_k=new_k, + new_v=new_v, + input_shape=input_shape, + rpe=rpe, + ) + + # mask attention + attention_mask = attention_mask.unsqueeze(0) + attention_weights_float = attention_weights_float.masked_fill( + attention_mask, float(self.negative_inf) + ) + + rc_output_memory = self.prepare_attention_output( + attention_weights=attention_weights, + attention_weights_float=attention_weights_float, + v=v, + input_shape=input_shape, + key_length=key_length, + padding_mask=padding_mask, + rpe=rpe, + ) + + if self.use_mem: + # next_m length equals to summary length - 1 + # last memory is ignored + if self.mini_batches: + next_m = rc_output_memory[-summary_length:] + else: + next_m = rc_output_memory[-summary_length:-1] + + next_m = self.squash_mem(next_m) + # rc and output + rc_output = rc_output_memory[:-summary_length] + if not self.nonlinear_squash_mem: + next_m = torch.clamp(next_m, min=-10, max=10) + else: + next_m = mems + rc_output = rc_output_memory + + return rc_output, next_m, next_k, next_v + + @torch.jit.export + def forward_jit( + self, + input: Tensor, + lengths: Tensor, + mems: Tensor, + left_context_key: Tensor, + left_context_val: Tensor, + rpe: Optional[Tensor], + ) -> Tuple[Tensor, Tensor, Tensor, Tensor]: + """ + forward function for NoSegAugmentedMemoryMultiheadAttentionBmm in decoding. + + args: + input: formed in the following way + [right_context_0, right_contex_1, ..., seg_0, seg_1, + ..., summary_0, summary_1,..] + lengths: the length of query which is [seg_0, seg_1, ....] + mems: [mem_0, mem_1, ...]. + left_context_key: left_context for key part. This is only used for online + decoding. In training, this is empty tensor + left_context_val: left_context for value part. This is only used for online + decoding. In training, this is empty tensor + + """ + lc_length = left_context_key.size(0) + + # In decoding, summary_length = 1 or 0 + if self.use_mem: + summary_length = 1 + else: + summary_length = 0 + + results = self.prepare_qkv( + input=input, + mems=mems, + lengths=lengths, + summary_length=summary_length, + lc_length=lc_length, + ) + result_qkv, input_shape, result_lengths_info, padding_mask = results + q, k, v = result_qkv + ( + mem_length, + utterance_length, + right_context_blocks_length, + key_length, + ) = result_lengths_info + + # add the cache key and value + new_k = torch.cat( + [ + k[: mem_length + right_context_blocks_length, :, :], + left_context_key, + k[-utterance_length:, :, :], + ], + dim=0, + ) + new_v = torch.cat( + [ + v[: mem_length + right_context_blocks_length, :, :], + left_context_val, + v[-utterance_length:, :, :], + ], + dim=0, + ) + next_k = new_k[mem_length + right_context_blocks_length :, :, :] + next_v = new_v[mem_length + right_context_blocks_length :, :, :] + + attention_weights, attention_weights_float, v = self.prepare_attention_weights( + q=q, + new_k=new_k, + new_v=new_v, + input_shape=input_shape, + rpe=rpe, + ) + # In online decoding, we don't have attention mask. But we still need + # to disable the attention from summary query to memory + attention_weights_float[:, -1, :mem_length] = float(self.negative_inf) + rc_output_memory = self.prepare_attention_output( + attention_weights=attention_weights, + attention_weights_float=attention_weights_float, + v=v, + input_shape=input_shape, + key_length=key_length, + padding_mask=padding_mask, + rpe=rpe, + ) + + # In decoding, summary length is 1 + if self.use_mem: + next_m = rc_output_memory[-1:] + next_m = self.squash_mem(next_m) + # rc and output + rc_output = rc_output_memory[:-1] + if not self.nonlinear_squash_mem: + next_m = torch.clamp(next_m, min=-10, max=10) + else: + rc_output = rc_output_memory + # empty tensor as input mems + next_m = mems + + return rc_output, next_m, next_k, next_v + + def quantize_(self, params=None): + if params and "per_channel" in params and params["per_channel"]: + qconfig = per_channel_dynamic_qconfig + else: + qconfig = default_dynamic_qconfig + torch.quantization.quantize_dynamic( + self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True + ) + return self + + +class NoSegAugmentedMemoryTransformer(nn.Module): + """ + Whole utterance augmented memory transformer. + + This is not pyspeech nn layer. It is used as a module in a master layer where + multiple transformers is used. + """ + + def __init__( + self, + input_dim, + num_heads, + ffn_dim, + dropout_in_attn=0.0, + dropout_on_attn=None, + dropout_on_fc1=None, + dropout_on_fc2=None, + activation_fn="relu", + tanh_on_mem=False, + std_scale=None, + scaled_init=False, + segment_size=128, + use_mem=True, + mini_batches=False, + negative_inf="-inf", + layer_index=-1, + summarization_method="mean", + max_relative_position=0, + rpe_old_option=True, + ): + super(NoSegAugmentedMemoryTransformer, self).__init__() + + self.attention = NoSegAugmentedMemoryMultiheadAttentionBmm( + input_dim=input_dim, + num_heads=num_heads, + dropout=dropout_in_attn, + scaled_init=scaled_init, + tanh_on_mem=tanh_on_mem, + std_scale=std_scale, + use_mem=use_mem, + mini_batches=mini_batches, + negative_inf=negative_inf, + layer_index=layer_index, + max_relative_position=max_relative_position, + ) + self.dropout = nn.Dropout(dropout_on_attn) + self.pos_ff = PositionwiseFF( + input_dim=input_dim, + ffn_dim=ffn_dim, + dropout_on_fc1=dropout_on_fc1, + dropout_on_fc2=dropout_on_fc2, + activation_fn=activation_fn, + ) + self.layer_norm_pre = Fp32LayerNorm(input_dim) + self.layer_norm = Fp32LayerNorm(input_dim) + self.segment_size = segment_size + self.use_mem = use_mem + + self.memory_op = SummarizationLayer( + summarization_method, segment_size, input_dim + ) + + def set_mini_batches(self, mini_batches): + self.attention.mini_batches = mini_batches + + def gen_summary_queries(self, input): + sum_input = self.memory_op(input) + return sum_input + + def pre_attention_ops(self, input, right_context_blocks): + rc_length = right_context_blocks.size(0) + input_length = input.size(0) + + rc_and_input = torch.cat([right_context_blocks, input], dim=0) + residual_input = rc_and_input + rc_and_input = self.layer_norm_pre(rc_and_input) + + query_input = rc_and_input[-input_length:, :, :] + return rc_length, input_length, residual_input, query_input, rc_and_input + + def after_attention_ops(self, attention_output, residual_input): + output = self.dropout(attention_output) + output = output + residual_input + output = self.pos_ff(output) + output = self.layer_norm(output) + return output + + @torch.jit.export + def forward_jit( + self, + input: Tensor, + lengths: Tensor, + mems: Tensor, + left_context_key: Tensor, + left_context_val: Tensor, + right_context_blocks: Tensor, + rpe: Optional[Tensor], + ) -> Tuple[Tensor, Tensor, Tensor, Tensor, Tensor]: + + results = self.pre_attention_ops(input, right_context_blocks) + rc_length, input_length, residual_input, query_input, rc_and_input = results + + # In online decoding, the summary query size is always 1 or 0 + if self.use_mem: + summary_query = self.gen_summary_queries(query_input) + summary_query = summary_query[0:1, :, :] + rc_qu_su = torch.cat([rc_and_input, summary_query], dim=0) + else: + rc_qu_su = rc_and_input + + rc_output, next_m, next_k, next_v = self.attention.forward_jit( + input=rc_qu_su, + lengths=lengths, + mems=mems, + left_context_key=left_context_key, + left_context_val=left_context_val, + rpe=rpe, + ) + rc_output = self.after_attention_ops(rc_output, residual_input) + results = ( + rc_output[-input_length:, :, :], + next_m, + rc_output[0:rc_length, :, :], + next_k, + next_v, + ) + return results + + @torch.jit.unused + def forward( + self, + input, + lengths, + mems, + right_context_blocks, + attention_mask, + pre_mems, + left_context_key, + left_context_val, + rpe, + ): + + results = self.pre_attention_ops(input, right_context_blocks) + rc_length, input_length, residual_input, query_input, rc_and_input = results + if self.use_mem: + summary_query = self.gen_summary_queries(query_input) + rc_qu_su = torch.cat([rc_and_input, summary_query], dim=0) + else: + rc_qu_su = rc_and_input + + rc_output, next_m, next_k, next_v = self.attention( + input=rc_qu_su, + lengths=lengths, + mems=mems, + attention_mask=attention_mask, + pre_mems=pre_mems, + left_context_key=left_context_key, + left_context_val=left_context_val, + rpe=rpe, + ) + + # [TODO] Note memory did not go through pos_ff. What happen if we pass + # memory through the pos_ff as well? + rc_output = self.after_attention_ops(rc_output, residual_input) + results = ( + rc_output[-input_length:, :, :], + next_m, + rc_output[0:rc_length, :, :], + next_k, + next_v, + ) + + return results + + +class NoSegAugmentedMemoryTransformerEncoderLayer(FairseqEncoder): + """ + Whole utterance augmented memory transformer encoder layer. This is a master layer + where we can define multiple augmented memory transformers. There are two reasons + to setup the master layer. + 1. We only need to define once about the attention mask. All the layers in the master + layer share the same mask. + 2. pyspeech nn layer has special input and output format. Defining one master layer is + easier to passing memory between different layes inside the master layer + + args: + input_dim: input embedding dimension + num_heads: number of heads in multihead self-attention + ffn_dim: ffn dimension in FFN layer + num_layers: number of augmented memory transformer layers + dropout_in_attn: dropout used in multi-head self-attention + dropout_on_attn: dropout used for output from te multihead self-attention + dropout_on_fc1: dropout used in FFN layer for the first linear layer + dropout_on_fc2: dropout used in FFN layer for the second linear layer + segment_size: segment size for each segment + context_config: (left_context_size, right_context_size) defines the surround context size + for each segment + max_memory_size: maximum memory size used for each segment + scaled_init: whether use scaled init for weight initialization in attention layer + std_scale: if std_scale is not None. The weak attention suppression is + turned on. For std_scale = 0.5, all the attention smaller than + mean + 0.5 * std will be suppressed. + activation_fn: activation function used in FFN layer. [ReLU, GELU] supported + tanh_on_mem: whether use tanh on memory + mini_batches: use mini-btach training + negative_inf: the negative infinity value used in attention masking. default is "-inf". + For some situation, e.g. LM. it is better to use "-1e8" to avoid nan issue. + summarization_method: method to generate segment summrization embedding + max_relative_position: max relatie position for relative position embedding + rpe_old_option: To be compatible with previous model. The previous model + was trained with attention += attention + rpe. The correct equation + should be attention = attention + rpe + [TODO]: remove the rpe_old_option by the end of 2021 Q1. + + """ + + def __init__( + self, + input_dim, + num_heads, + ffn_dim, + num_layers=1, + dropout_in_attn=0.0, + dropout_on_attn=0.0, + dropout_on_fc1=0.0, + dropout_on_fc2=0.0, + segment_size=128, + context_config=(0, 0), + max_memory_size=0, + scaled_init=True, + std_scale=None, + activation_fn="relu", + tanh_on_mem=False, + mini_batches=False, + negative_inf="-inf", + deep_init=True, + summarization_method="mean", + max_relative_position=0, + rpe_old_option=True, + ): + super().__init__(None) + if input_dim % num_heads: + raise ValueError( + "input_dim ({}) must be divisible by num_heads ({})".format( + input_dim, num_heads + ) + ) + + # we used to support growing memory size. However, it will cause + # cross stream batching failure. Now we need to have exact max memory size + if max_memory_size < 0: + raise ValueError("max_memory_size must be >= 0") + + # Only assign right_context. In decoding, left context will be cached. + # No need to let the online decoder to re-assign the left context + self.left_context, self.right_context = context_config + self.segment_size = segment_size + self.memory_dim = input_dim + self.max_memory_size = max_memory_size + self.mini_batches = mini_batches + if self.max_memory_size != 0: + self.use_mem = True + else: + self.use_mem = False + + self.memory_op = SummarizationLayer( + summarization_method, segment_size, input_dim + ) + + self.layers = torch.nn.ModuleList() + self.num_layers = num_layers + self.max_relative_position = max_relative_position + if self.max_relative_position > 0: + self.use_rpe = True + else: + self.use_rpe = False + for i in range(self.num_layers): + if deep_init: + layer_index = i + else: + layer_index = -1 + + self.layers.append( + NoSegAugmentedMemoryTransformer( + num_heads=num_heads, + input_dim=input_dim, + ffn_dim=ffn_dim, + dropout_in_attn=dropout_in_attn, + dropout_on_attn=dropout_on_attn, + dropout_on_fc1=dropout_on_fc1, + dropout_on_fc2=dropout_on_fc2, + segment_size=segment_size, + std_scale=std_scale, + activation_fn=activation_fn, + tanh_on_mem=tanh_on_mem, + scaled_init=scaled_init, + use_mem=self.use_mem, + mini_batches=mini_batches, + negative_inf=negative_inf, + layer_index=layer_index, + summarization_method=summarization_method, + max_relative_position=max_relative_position, + rpe_old_option=rpe_old_option, + ) + ) + + def set_mini_batches(self, mini_batches): + # handy function only used for unit test + self.mini_batches = mini_batches + for layer in self.layers: + layer.set_mini_batches(mini_batches) + + def _get_relative_position( + self, + input: Tensor, + max_relative_position: int, + left_context_length: int, + past_length: int, + is_decoding: bool, + ): + # For training, we copy the right context to the start of the utterance + # First dimension in distance is corresponding to query. + # [right context, utterance, summary vector] + # Second dimension in distance is corresponding to key. + # [Memory bank, right context, utterance] + # For summary vector in query part, the distance with + # all other position is 2*max_position. For memory bank in key, + # the distance with all other positions is 0. + + T, B, D = input.shape + num_segs = math.ceil((T - self.right_context) / self.segment_size) + + # utterance + u_st = past_length * self.segment_size + u_ed = u_st + T + utterance_ranges = torch.arange(u_st, u_ed - self.right_context) + + # left context. Only in minibatch or decoding + left_context_ranges = torch.arange(u_st - left_context_length, u_st) + + # Right context block + # right context + utterance + right_context_blocks = [] + for i in range(0, num_segs - 1): + st = (i + 1) * self.segment_size + u_st + ed = st + self.right_context + assert ed < u_ed + temp = torch.arange(st, ed) + right_context_blocks.append(temp) + right_context_blocks.append(torch.arange(u_ed - self.right_context, u_ed)) + right_context_ranges = torch.cat(right_context_blocks) + + if self.use_mem: + # Memory bank + # The position for memory -n, .., -1 + if is_decoding: + memory_size = min(past_length, self.max_memory_size) + else: + memory_size = num_segs + past_length - 1 + memory_bank_ranges = torch.arange( + -max_relative_position - 1, -max_relative_position - 1 - memory_size, -1 + ) + + # summary vector + # The position for summary vector as the T+max_relative_position+1. + # After the clamping, the relative position is max_relative_position + summary_pos_st = u_ed + max_relative_position + 1 + summary_vector_ranges = torch.arange( + summary_pos_st, summary_pos_st + num_segs + ) + + key_ranges = torch.cat( + [ + memory_bank_ranges, + right_context_ranges, + left_context_ranges, + utterance_ranges, + ] + ) + + query_ranges = torch.cat( + [right_context_ranges, utterance_ranges, summary_vector_ranges] + ) + else: + key_ranges = torch.cat( + [right_context_ranges, left_context_ranges, utterance_ranges] + ) + + query_ranges = torch.cat([right_context_ranges, utterance_ranges]) + + distance = key_ranges[None, :] - query_ranges[:, None] + distance_clamp = ( + torch.clamp(distance, -max_relative_position, max_relative_position) + + max_relative_position + ) + distance_clamp = distance_clamp.to(input.device).long().detach() + return distance_clamp + + def _get_attention_mask(self, input, past_length=0, left_context_cache=0): + # attention mask for each query contains three parts: + # 1. memory part + # 2. left_context + segment + # 3. right_context_block + # so for each segment and its correspoinding right context block, + # the attention matrix is formed by 9 parts: + # [0, m, 0, 0, right_context, 0, 0, seg, 0] + # [before memory, memory, after memory, before right context, right_context, + # after right context, before seg, seg, after seg] + # + # Query is formed in the way as [right_context_blocks, utterance, summary] + # + # Note: put m and right_context before segment is convenient + # for padding_mask operation. + # Key lengths = m_length + right_context_block_length + lengths + utterance_length, batch_size, _ = input.shape + summary_length = math.ceil(utterance_length / self.segment_size) + num_segs = summary_length + rc_length = self.right_context * num_segs + rc = self.right_context + lc = self.left_context + + # using mini-batches, there is left context cache available for current + # sequence. + lcc = left_context_cache + + # max_memory_size is 0 then we don't have memory and summary + # past_length is the memory carry from previous sequence + if self.use_mem: + mem_length = num_segs - 1 + past_length + else: + mem_length = 0 + rc_mask = [] + query_mask = [] + summary_mask = [] + for j in range(0, num_segs): + ssize = min(self.segment_size, utterance_length - j * self.segment_size) + + rc_size = rc + rc_mat = [] + q_mat = [] + s_mat = [] + m_start = max(j + past_length - self.max_memory_size, 0) + + # max_memory_size is 0, then we don't use memory + if self.use_mem: + # part 0: before memory + rc_mat.append(input.new_zeros(rc_size, m_start)) + q_mat.append(input.new_zeros(ssize, m_start)) + s_mat.append(input.new_zeros(1, m_start)) + + # part 1: memory + col_1 = j + past_length - m_start + rc_mat.append(torch.ones(rc_size, col_1, device=input.device)) + q_mat.append(torch.ones(ssize, col_1, device=input.device)) + # based on D22875746, disable summary query attention + # on memeory is better for long form utterance + s_mat.append(input.new_zeros(1, col_1)) + + # part 2: after memory + col_2 = mem_length - (j + past_length) + rc_mat.append(input.new_zeros(rc_size, col_2)) + q_mat.append(input.new_zeros(ssize, col_2)) + s_mat.append(input.new_zeros(1, col_2)) + + # part 3: before right context + rc_start = j * rc + rc_mat.append(input.new_zeros(rc_size, rc_start)) + q_mat.append(input.new_zeros(ssize, rc_start)) + s_mat.append(input.new_zeros(1, rc_start)) + + # part 4: right context + rc_end = rc_start + rc + col_4 = rc + rc_mat.append(torch.ones(rc_size, col_4, device=input.device)) + q_mat.append(torch.ones(ssize, col_4, device=input.device)) + s_mat.append(torch.ones(1, col_4, device=input.device)) + + # part 5: after right context + col_5 = rc_length - rc_end + rc_mat.append(input.new_zeros(rc_size, col_5)) + q_mat.append(input.new_zeros(ssize, col_5)) + s_mat.append(input.new_zeros(1, col_5)) + + # part 6: before query segment + seg_start = max(j * self.segment_size + lcc - lc, 0) + rc_mat.append(input.new_zeros(rc_size, seg_start)) + q_mat.append(input.new_zeros(ssize, seg_start)) + s_mat.append(input.new_zeros(1, seg_start)) + + # part 7: query segment + # note: right context is put in right context block + # here we only need to consider about left context + seg_end = min((j + 1) * self.segment_size + lcc, utterance_length + lcc) + col_7 = seg_end - seg_start + rc_mat.append(torch.ones(rc_size, col_7, device=input.device)) + q_mat.append(torch.ones(ssize, col_7, device=input.device)) + s_mat.append(torch.ones(1, col_7, device=input.device)) + + # part 8: after query segment + col_8 = utterance_length + lcc - seg_end + rc_mat.append(input.new_zeros(rc_size, col_8)) + q_mat.append(input.new_zeros(ssize, col_8)) + s_mat.append(input.new_zeros(1, col_8)) + + rc_mask.append(torch.cat(rc_mat, dim=1)) + query_mask.append(torch.cat(q_mat, dim=1)) + summary_mask.append(torch.cat(s_mat, dim=1)) + + # no memory, then we don't need summary either + if self.use_mem: + attention_mask = ( + 1 + - torch.cat( + [ + torch.cat(rc_mask, dim=0), + torch.cat(query_mask, dim=0), + torch.cat(summary_mask, dim=0), + ], + dim=0, + ) + ).to(torch.bool) + else: + attention_mask = ( + 1 + - torch.cat( + [torch.cat(rc_mask, dim=0), torch.cat(query_mask, dim=0)], dim=0 + ) + ).to(torch.bool) + + return attention_mask + + @torch.jit.export + def init_state( + self, batch_size: int, device: Optional[Device] = None + ) -> List[Tensor]: + empty_memory = torch.zeros( + self.num_layers, + self.max_memory_size, + batch_size, + self.memory_dim, + device=device, + ) + left_context_key = torch.zeros( + self.num_layers, + self.left_context, + batch_size, + self.memory_dim, + device=device, + ) + left_context_val = torch.zeros( + self.num_layers, + self.left_context, + batch_size, + self.memory_dim, + device=device, + ) + past_length = torch.zeros(1, batch_size, dtype=torch.int32, device=device) + + return [empty_memory, left_context_key, left_context_val, past_length] + + @torch.jit.export + def batch_state(self, states: List[List[Tensor]]) -> List[Tensor]: + if len(states) == 0: + return [] + batched_m = [] + batched_lc_key = [] + batched_lc_val = [] + batched_past_length = [] + for state in states: + if len(state) == 0: + continue + m, lc_key, lc_val, past_length = state + batched_m.append(m) + batched_lc_key.append(lc_key) + batched_lc_val.append(lc_val) + batched_past_length.append(past_length) + + if ( + (len(batched_m) == 0) + or (len(batched_lc_key) == 0) + or (len(batched_lc_val) == 0) + or (len(batched_past_length) == 0) + ): + return [ + torch.tensor([]), + torch.tensor([]), + torch.tensor([]), + torch.tensor([]), + ] + + batched_m = torch.cat(batched_m, dim=2) + batched_lc_key = torch.cat(batched_lc_key, dim=2) + batched_lc_val = torch.cat(batched_lc_val, dim=2) + batched_past_length = torch.cat(batched_past_length, dim=1) + return [batched_m, batched_lc_key, batched_lc_val, batched_past_length] + + @torch.jit.export + def reorder_state(self, state: List[Tensor], indices: Tensor) -> List[Tensor]: + if len(state) == 0: + return [] + m, lc_key, lc_val, past_length = state + indices = indices.to(device=m.device) + reord_m = torch.index_select(m, 2, indices) + reord_lc_key = torch.index_select(lc_key, 2, indices) + reord_lc_val = torch.index_select(lc_val, 2, indices) + reord_past_length = torch.index_select(past_length, 1, indices) + return [reord_m, reord_lc_key, reord_lc_val, reord_past_length] + + @torch.jit.export + def reset_state(self, state: List[Tensor], indices: Tensor) -> List[Tensor]: + m, lc_key, lc_val, past_length = state + m = m.index_fill(dim=2, index=indices, value=0.0) + lc_key = lc_key.index_fill(dim=2, index=indices, value=0.0) + lc_val = lc_val.index_fill(dim=2, index=indices, value=0.0) + past_length = past_length.index_fill(dim=1, index=indices, value=0) + + return [m, lc_key, lc_val, past_length] + + @torch.jit.export + def state_size(self) -> int: + return 4 + + @torch.jit.export + def batch_size_in_state( + self, state: Optional[List[Tensor]], sloppy: bool = True + ) -> Optional[int]: + if state is None: + return None + return state[0].size(2) + + def gen_summary_queries(self, input): + sum_input = self.memory_op(input) + return sum_input + + def _gen_right_context_padded_input(self, input): + # This function deals with input that is already + # padded with right context (e.g. minibatch training) + right_context_blocks = [] + T, B, D = input.shape + num_segs = math.ceil((T - self.right_context) / self.segment_size) + for i in range(0, num_segs - 1): + st = (i + 1) * self.segment_size + ed = st + self.right_context + assert ed < T + temp = input[st:ed, :, :] + right_context_blocks.append(temp) + + # last segment right context is already available + right_context_blocks.append(input[T - self.right_context :, :, :]) + return torch.cat(right_context_blocks, dim=0) + + def _gen_segs_right_context(self, input, lengths): + segments = [] + T, B, D = input.size() + nT = T - self.right_context + + # assume input is right context padded + num_segs = math.ceil(nT / self.segment_size) + # pad zeros to the utterance to make sure each + # segment has the same right context. For the + for i in range(0, num_segs - 1): + st = i * self.segment_size + ed = min(T, st + self.segment_size + self.right_context) + temp = input[st:ed, :, :] + rest_lengths = torch.clamp( + lengths - self.segment_size, min=0, max=nT - (i + 1) * self.segment_size + ) + segments.append((temp, lengths - rest_lengths + self.right_context)) + lengths = rest_lengths + + last_seg = input[st + self.segment_size :, :, :] + segments.append((last_seg, rest_lengths + self.right_context)) + + return segments + + @torch.jit.unused + def forward( + self, input: Tensor, padding_masks: Tensor, state: Optional[List[Tensor]] = None + ) -> Tuple[Tensor, Tensor, List[Tensor], List[Tensor]]: + # Xutai: originally the second argument is lengths. + lengths = (~padding_masks).sum(dim=1).long() + # mini batch training. + if self.mini_batches: + return self.forward_mini_batches(input, lengths, state) + + # regular full sequence training. Note, assume the right context in provided + # in the input. + T, B, D = input.size() + right_context_blocks = self._gen_right_context_padded_input(input) + + # generate the relative positional embedding + if self.use_rpe: + rpe = self._get_relative_position( + input=input, + max_relative_position=self.max_relative_position, + left_context_length=0, + past_length=0, + is_decoding=False, + ) + else: + rpe = None + input = input[: T - self.right_context, :, :] + + attention_mask = self._get_attention_mask(input) + + # firt layer use each segment mean as memory + # ignore the last one seg average + if self.use_mem: + mems = self.gen_summary_queries(input)[:-1, :, :] + else: + mems = torch.zeros(0, input.size(1), input.size(2), device=input.device) + mems = mems.type_as(input) + + output = input + all_outputs = [] + + for layer in self.layers: + output, mems, right_context_blocks, _, _ = layer( + input=output, + lengths=lengths, + attention_mask=attention_mask, + mems=mems, + right_context_blocks=right_context_blocks, + pre_mems=None, + left_context_key=None, + left_context_val=None, + rpe=rpe, + ) + all_outputs.append(output) + return output, padding_masks, [], all_outputs + + def forward_jit_mini_batch_init( + self, + seg: Tensor, + state: Optional[List[Tensor]] = None, + is_decoding: bool = False, + ): + # Prepare state. In whole sequence training, state is ignored. + # For minibatch training, we need to prepare state + if state is None: + state = self.init_state(batch_size=seg.size(1), device=seg.device) + if seg.dtype == torch.half: + state = [state[0].half(), state[1].half(), state[2].half(), state[3]] + + if self.use_mem: + # note input average only on seg, not on right context + # first layer use each segmetn mean as memory. the last + # one segment average is used in state + full_mems = self.gen_summary_queries(seg) + if is_decoding: + mems = full_mems[0:1, :, :] + state_mems = torch.cat([state[0][0], mems], dim=0) + else: + mems = full_mems[:-1, :, :] + state_mems = torch.cat([state[0][0], full_mems], dim=0) + else: + mems = state[0][0] + state_mems = mems + + # track processed segment number or memory number + # the same batch as the same bumber of past length + past_length = state[3][0][0].item() + past_left_context = min(past_length * self.segment_size, self.left_context) + past_length = min(self.max_memory_size, past_length) + + return state, mems, state_mems, past_length, past_left_context + + def state_update_before( + self, layer: int, state: List[Tensor], past_length: int, past_left_context: int + ): + pre_mems = state[0][layer][self.max_memory_size - past_length :, :, :] + lc_key = state[1][layer][self.left_context - past_left_context :, :, :] + lc_val = state[2][layer][self.left_context - past_left_context :, :, :] + return pre_mems, lc_key, lc_val + + def state_update_after( + self, + layer: int, + state: List[Tensor], + mems: Tensor, + next_key: Tensor, + next_val: Tensor, + mems_list: List[Tensor], + lc_key_list: List[Tensor], + lc_val_list: List[Tensor], + ): + # mems is used for next layer + if layer < self.num_layers - 1: + state_mems = torch.cat([state[0][layer + 1], mems], dim=0) + mems_list.append(state_mems[-self.max_memory_size :, :, :]) + + # when mems pass to next sequence, we need the last memory. when mems + # use for the next layer, we can ignore the last memory + mems = mems[:-1, :, :] + + # note state[1][i] and state[2][i] original length equals to self.left_context + new_k = torch.cat([state[1][layer], next_key], dim=0) + new_v = torch.cat([state[2][layer], next_val], dim=0) + lc_key_list.append(new_k[-self.left_context :, :, :]) + lc_val_list.append(new_v[-self.left_context :, :, :]) + return mems_list, lc_key_list, lc_val_list, mems + + def state_update_after_loop( + self, + state: List[Tensor], + mems_list: List[Tensor], + lc_key_list: List[Tensor], + lc_val_list: List[Tensor], + update_length: int, + ): + state[0] = torch.stack(mems_list, dim=0) + state[1] = torch.stack(lc_key_list, dim=0) + state[2] = torch.stack(lc_val_list, dim=0) + state[3] = state[3] + update_length + return state + + @torch.jit.unused + def forward_mini_batches( + self, input: Tensor, lengths: Tensor, state: Optional[List[Tensor]] = None + ) -> Tuple[Tensor, Tensor, List[Tensor], List[Tensor]]: + T, B, D = input.size() + + # input without right context + seg = input[: T - self.right_context, :, :] + + # get right context blocks + right_context_blocks = self._gen_right_context_padded_input(input) + + mems_list = [] + lc_key_list = [] + lc_val_list = [] + results = self.forward_jit_mini_batch_init(seg, state, False) + state, mems, state_mems, past_length, past_left_context = results + + # relative position embedding + if self.use_rpe: + rpe = self._get_relative_position( + input=input, + max_relative_position=self.max_relative_position, + left_context_length=past_left_context, + past_length=past_length, + is_decoding=False, + ) + else: + rpe = None + + # get attention mask based on seg (not include right context) and available + # left context + attention_mask = self._get_attention_mask(seg, past_length, past_left_context) + mems_list.append(state_mems[-self.max_memory_size :, :, :]) + output = seg + i = 0 + all_outputs = [] + for layer in self.layers: + # In order to make cross stream batching work, mem, left context key + # and left context value in the state should always be the same shape. + # We use the past length to track the processed segment number. In this + # way, we take out the essential memory, left context key and left + # context val from the state. After finish the forward for current segment + # we add the new memory, left context key and left context value into the + # staate and trim out the oldest part to keep the shape consistent. + pre_mems, lc_key, lc_val = self.state_update_before( + i, state, past_length, past_left_context + ) + + output, mems, right_context_blocks, next_key, next_val = layer.forward( + input=output, + lengths=lengths, + attention_mask=attention_mask, + mems=mems, + right_context_blocks=right_context_blocks, + pre_mems=pre_mems, + left_context_key=lc_key, + left_context_val=lc_val, + rpe=rpe, + ) + all_outputs.append(output) + mems_list, lc_key_list, lc_val_list, mems = self.state_update_after( + layer=i, + state=state, + mems=mems, + next_key=next_key, + next_val=next_val, + mems_list=mems_list, + lc_key_list=lc_key_list, + lc_val_list=lc_val_list, + ) + + i += 1 + + # update state + update_length = math.ceil((T - self.right_context) / self.segment_size) + state = self.state_update_after_loop( + state=state, + mems_list=mems_list, + lc_key_list=lc_key_list, + lc_val_list=lc_val_list, + update_length=update_length, + ) + + return output, lengths, state, all_outputs + + def forward_jit_test( + self, input: Tensor, lengths: Tensor, state: Optional[List[Tensor]] = None + ) -> Tuple[Tensor, Tensor, List[Tensor]]: + """ + This one simulate sequence encoder forward jit. This is for unit test purpose. + It is not used in training or decoding. Note, extra_right_context is set in + the model. In unit test, input = [utterance, right_context], lengths = + [utterance_length]. + args: + input: input utterance + lengths: utterance input length + state: None here. input is whole utterance + """ + # [TODO] sequence_to_segment has bug in lengths. + seg_src_tokens_lengths = self._gen_segs_right_context(input, lengths) + + seg_enc_tokens_lengths: List[Tuple[Tensor, Tensor]] = [] + state: Optional[List[Tensor]] = None + for seg_src_tokens, seg_src_lengths in seg_src_tokens_lengths: + seg_enc_tokens, seg_enc_lengths, state = self.forward_jit( + input=seg_src_tokens, lengths=seg_src_lengths, state=state + ) + seg_enc_tokens_lengths.append((seg_enc_tokens, seg_enc_lengths)) + + enc_tokens, enc_lengths = segments_to_sequence( + segments=seg_enc_tokens_lengths, time_axis=0 + ) + + state = [] # returns trivial state + + return enc_tokens, enc_lengths, state + + @torch.jit.export + def forward_jit( + self, input: Tensor, lengths: Tensor, state: Optional[List[Tensor]] = None + ) -> Tuple[Tensor, Tensor, List[Tensor]]: + """ + Forward helper for online decoding. + + args: + input: [seg, right_context]. We assume in online we + always padding the right context to the preset right context size. + For the last segment, we may have short segment size, but right + context size is the same as other segments + lengths: utterance input length is the utterance segment length and + right context size + state: [memory, left_context_key, left_context_val]. To improve throughput, + in addition to memory, we also cache key and value for left_context in + multihead self-attention + """ + # In online decoding, input = [segment, right_context] + # Lengths = [segment_length, right_context_length] + # so we need strip right context in output + T, B, D = input.size() + rc_str = T - self.right_context + rc_end = T + right_context_blocks = input[rc_str:rc_end, :, :] + seg = input[:rc_str, :, :] + lengths = torch.clamp(lengths - self.right_context, min=0) + mems_list = [] + lc_key_list = [] + lc_val_list = [] + + results = self.forward_jit_mini_batch_init(seg, state, True) + state, mems, state_mems, past_length, past_left_context = results + + # relative position embedding + if self.use_rpe: + rpe = self._get_relative_position( + input=input, + max_relative_position=self.max_relative_position, + left_context_length=past_left_context, + past_length=past_length, + is_decoding=True, + ) + else: + rpe = None + + # memory for first layer. + mems_list.append(state_mems[-self.max_memory_size :, :, :]) + output = seg + i = 0 + for layer in self.layers: + # In order to make cross stream batching work, mem, left context key + # and left context value in the state should always be the same shape. + # We use the past length to track the processed segment number. In this + # way, we take out the essential memory, left context key and left + # context val from the state. After finish the forward for current segment + # we add the new memory, left context key and left context value into the + # staate and trim out the oldest part to keep the shape consistent. + true_mems, lc_key, lc_val = self.state_update_before( + layer=i, + state=state, + past_length=past_length, + past_left_context=past_left_context, + ) + + output, mems, right_context_blocks, next_key, next_val = layer.forward_jit( + input=output, + lengths=lengths, + mems=true_mems, + right_context_blocks=right_context_blocks, + left_context_key=lc_key, + left_context_val=lc_val, + rpe=rpe, + ) + # mems is used for next layer + mems_list, lc_key_list, lc_val_list, _ = self.state_update_after( + layer=i, + state=state, + mems_list=mems_list, + mems=mems, + next_key=next_key, + next_val=next_val, + lc_key_list=lc_key_list, + lc_val_list=lc_val_list, + ) + i += 1 + + # update state + state = self.state_update_after_loop( + state=state, + mems_list=mems_list, + lc_key_list=lc_key_list, + lc_val_list=lc_val_list, + update_length=1, + ) + + return output, lengths, state + + def quantize_(self, params=None): + if params and "per_channel" in params and params["per_channel"]: + qconfig = per_channel_dynamic_qconfig + else: + qconfig = default_dynamic_qconfig + torch.quantization.quantize_dynamic( + self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True + ) + return self + + +# ------------------------------------------------------------------------------ +# Emformer encoder for seq2seq model +# This is a wrapper over the original emformer +# ------------------------------------------------------------------------------ +def emformer_encoder(klass): + class SpeechEncoder(klass): + def __init__(self, args): + super().__init__(args) + stride = SpeechEncoder.conv_layer_stride(args) + trf_left_context = args.segment_left_context // stride + trf_right_context = args.segment_right_context // stride + context_config = [trf_left_context, trf_right_context] + self.transformer_layers = nn.ModuleList( + [ + NoSegAugmentedMemoryTransformerEncoderLayer( + input_dim=args.encoder_embed_dim, + num_heads=args.encoder_attention_heads, + ffn_dim=args.encoder_ffn_embed_dim, + num_layers=args.encoder_layers, + dropout_in_attn=args.dropout, + dropout_on_attn=args.dropout, + dropout_on_fc1=args.dropout, + dropout_on_fc2=args.dropout, + activation_fn=args.activation_fn, + context_config=context_config, + segment_size=args.segment_length, + max_memory_size=args.max_memory_size, + scaled_init=True, # TODO: use constant for now. + tanh_on_mem=args.amtrf_tanh_on_mem, + ) + ] + ) + + def forward(self, *args, **kwargs): + encoder_out = super().forward(*args, **kwargs) + (output, encoder_padding_masks, [], all_outputs) = encoder_out.encoder_out + + # This is because that in the original implementation + # the output didn't consider the last segment as right context. + encoder_padding_masks = encoder_padding_masks[:, : output.size(0)] + # import pdb;pdb.set_trace() + + return EncoderOut( + encoder_out=output, + encoder_padding_mask=encoder_padding_masks, + encoder_embedding=None, + encoder_states=None, + src_tokens=None, + src_lengths=None, + ) + + @staticmethod + def conv_layer_stride(args): + # TODO: make it configurable from the args + return 4 + + SpeechEncoder.__name__ = klass.__name__ + return SpeechEncoder diff --git a/fairseq/models/speech_to_text/utils.py b/fairseq/models/speech_to_text/utils.py new file mode 100644 index 0000000000..573f8537c9 --- /dev/null +++ b/fairseq/models/speech_to_text/utils.py @@ -0,0 +1,564 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + + +import logging +from collections.abc import Iterable +from itertools import repeat +from typing import List, Optional, Tuple + +import torch +from torch import Tensor + + +# ------------------------------------------------------------------------------ +# assert_equal() +# ------------------------------------------------------------------------------ + + +def assert_equal(value1, value2, name1=None, name2=None): + """Asserts two values are equal otherwise raise an error.""" + + str_name1 = "" if name1 is None else "{} ".format(name1) + str_name2 = "" if name2 is None else "{} ".format(name2) + if value1 != value2: + str_value1 = "{}" if name1 is None else "({})" + str_value1 = str_value1.format(value1) + str_value2 = "{}" if name2 is None else "({})" + str_value2 = str_value2.format(value2) + raise ValueError( + "Expected {}{} == {}{}".format(str_name1, str_value1, str_name2, str_value2) + ) + + +def fill_config(config, key, value): + if value is not None: + if key not in config or config[key] is None: + config[key] = value + assert_equal(value, config[key], "value", f'config["{key}"]') + + +# ------------------------------------------------------------------------------ +# check_and_return_expected() +# ------------------------------------------------------------------------------ + + +def check_and_return_expected(value, undefined_value, expected_value, name=None): + """ + Return the expected value while checking if the given value is undefined or + equal to the expected value. + """ + if (undefined_value is None and value is None) or (undefined_value == value): + return expected_value + if value != expected_value: + str_name = "" if name is None else "{} ".format(name) + str_value = "{}" if name is None else "({})" + str_value = str_value.format(value) + raise ValueError( + "Expected {}{} == {}".format(str_name, str_value, expected_value) + ) + return expected_value + + +# ------------------------------------------------------------------------------ +# get_time_axis() +# ------------------------------------------------------------------------------ + + +def get_time_axis(layout): + """ + Extract the time axis from the layout, for example for breaking sequence into + segments. + """ + if layout in ["TB", "TBD"]: + return 0 + if layout in ["BT", "BTD"]: + return 1 + if layout in ["BCTD"]: + return 2 + raise ValueError("Unsupported layout = {}".format(layout)) + + +# ------------------------------------------------------------------------------ +# get_batch_axis() +# ------------------------------------------------------------------------------ + + +def get_batch_axis(layout): + """ + Extract the batch axis from the layout + """ + if layout in ["TB", "TBD"]: + return 1 + if layout in ["BT", "BTD", "BCTD"]: + return 0 + raise ValueError("Unsupported layout = {}".format(layout)) + + +# ------------------------------------------------------------------------------ +# monotonically_increasing_and_bounded() +# ------------------------------------------------------------------------------ + + +def monotonically_increasing_and_bounded(iterable, min=None, max=None): + """ + Check if the elements in the given iterable are monotonically increasing and + bounded by upper/lower bounds. + """ + if not isinstance(iterable, Iterable): + raise TypeError( + "Expected iterable to be of type Iterable, got ({})".format( + iterable.__class__.__name__ + ) + ) + for i in range(len(iterable)): + if min is not None and iterable[i] < min: + return False + if max is not None and iterable[i] > max: + return False + if i > 0 and iterable[i] <= iterable[i - 1]: + return False + return True + + +# ------------------------------------------------------------------------------ +# to_pair() +# ------------------------------------------------------------------------------ + + +def to_pair(value, name): + """Make a pair (of type tuple) of given value.""" + if isinstance(value, Iterable): + if len(value) != 2: + raise ValueError( + "Expected `{}` to have exactly 2 elements, got: ({})".format( + name, value + ) + ) + return value + return tuple(repeat(value, 2)) + + +# ------------------------------------------------------------------------------ +# infer_conv_output_attrs() +# ------------------------------------------------------------------------------ + + +# TODO(cfyeh): figure out if we can get `output_dim` without calling the module. +def infer_conv_output_attrs( + module, input_channels, input_dim, batch_size=1, max_length=8 +): + """Get output attributes of a module with input.""" + input = torch.randn(batch_size, input_channels, max_length, input_dim) + output = module(input) + output_channels = output.shape[1] + output_dim = output.shape[-1] + return output_channels, output_dim + + +# ------------------------------------------------------------------------------ +# NoOp +# ------------------------------------------------------------------------------ + + +class NoOp(torch.nn.Module): + """ + NoOp simply passes the input as the output. + """ + + def __init__(self): + super().__init__() + + def forward(self, input: Tensor) -> Tensor: + return input + + +# ------------------------------------------------------------------------------ +# Permute: a torch.nn.Module applies permutation on the input tensor. +# ------------------------------------------------------------------------------ + + +class Permute(torch.nn.Module): + def __init__(self, dims): + super().__init__() + self.dims = dims + + def forward(self, input: Tensor) -> Tensor: + return input.permute(self.dims).contiguous() + + +# ------------------------------------------------------------------------------ +# lengths_to_padding_mask() +# ------------------------------------------------------------------------------ + + +def lengths_to_padding_mask(lengths: Tensor) -> Tensor: + """Convert lengths of shape (B, ) to padding mask.""" + batch_size = lengths.shape[0] + max_length = int(torch.max(lengths).item()) + padding_mask = torch.arange( # [0, ..., T-1] + max_length, device=lengths.device, dtype=lengths.dtype + ).expand(batch_size, max_length) >= lengths.unsqueeze(1) + + return padding_mask + + +# ------------------------------------------------------------------------------ +# lengths_to_attention_mask() +# ------------------------------------------------------------------------------ + + +def lengths_to_attention_mask( + lengths: Tensor, + left_context: Optional[int] = None, + right_context: Optional[int] = None, +) -> Optional[Tensor]: + """ + Generate attention mask based on (lengths, left_context, right_context). + left_context is None means unlimited left context. + right_context is None means unlimited right context. + """ + + if left_context is None and right_context is None: + return None + + max_length = int(torch.max(lengths).item()) + + # For example, with `max_length` == 5, + # indices = tensor([ + # [ 0, 1, 2, 3, 4, 5], + # [-1, 0, 1, 2, 3, 4], + # [-2, -1, 0, 1, 2, 3], + # [-3, -2, -1, 0, 1, 2], + # [-4, -3, -2, -1, 0, 1], + # [-5, -4, -3, -2, -1, 0], + # ]) + + # In some cases the second torch.arange is created on cpu which causes a + # failure. Adding the device option to guard against it. + indices = torch.arange( + max_length, device=lengths.device, dtype=lengths.dtype + ).expand(max_length, max_length) - torch.arange( + max_length, device=lengths.device + ).view( + max_length, -1 + ) + + # For example, with `max_length` == 5, + # bool_mask = tensor([ + # [True, True, True, True, True], + # [True, True, True, True, True], + # [True, True, True, True, True], + # [True, True, True, True, True], + # [True, True, True, True, True], + # ]) + bool_mask = ( + torch.tensor([True]).to(device=lengths.device).expand(max_length, max_length) + ) + + # For example, with `max_length` == 5, left_context == 2 + # left_mask = tensor([ + # [ True, True, True, True, True], + # [ True, True, True, True, True], + # [ True, True, True, True, True], + # [False, True, True, True, True], + # [False, False, True, True, True], + # ]) + if left_context is not None: + left_mask = indices >= -left_context + bool_mask = bool_mask & left_mask + + # For example, with `max_length` == 5, right_context == 1 + # right_mask = tensor([ + # [True, True, False, False, False], + # [True, True, True, False, False], + # [True, True, True, True, False], + # [True, True, True, True, True], + # [True, True, True, True, True], + # ]) + if right_context is not None: + right_mask = indices <= right_context + bool_mask = bool_mask & right_mask + + bool_mask = (~bool_mask).to(device=lengths.device) + return bool_mask + + +# ------------------------------------------------------------------------------ +# infer_output_norm() +# ------------------------------------------------------------------------------ + + +def infer_output_norm(module, output_norm=None): + """ + Infer the output norm (string and module) needed on the module gvien desired + output normalization. + """ + if output_norm == module.output_norm(): + # output_norm already matches module.output_norm(). + return (None, NoOp()) + + if output_norm is None and module.output_norm() is not None: + logger = logging.getLogger("infer_output_norm()") + logger.warning( + "trying to set output_norm ({}) ".format(output_norm) + + "but got module.output_norm() ({}), ".format(module.output_norm()) + + "the combined output_norm() will be ({})".format(module.output_norm()) + ) + return (None, NoOp()) + + if output_norm == "log_softmax": + if module.output_norm() is not None: + raise ValueError( + "incompatible output_norm ({}) ".format(output_norm) + + "and module.output_norm() ({})".format(module.output_norm()) + ) + else: + return ("log_softmax", torch.nn.LogSoftmax(dim=-1)) + + if output_norm == "softmax": + if module.output_norm() is not None: + raise ValueError( + "incompatible output_norm ({}) ".format(output_norm) + + "and module.output_norm() ({})".format(module.output_norm()) + ) + else: + return ("softmax", torch.nn.Softmax(dim=-1)) + + raise ValueError( + "output_norm ({}) not in ".format(output_norm) + + "supported list = [None, softmax, log_softmax]" + ) + + +# ------------------------------------------------------------------------------ +# infer_channels_from_layout() +# ------------------------------------------------------------------------------ + + +def infer_channels_from_layout(layout, channels): + """Extract the number of channels from the layout.""" + if layout in ("TBD", "BTD"): + if channels is not None and channels != 1: + raise ValueError( + "Expected channels ({}) to be 1 for layout = {}".format( + channels, layout + ) + ) + if channels is None: + return 1 + return channels + + +# ------------------------------------------------------------------------------ +# pad_sequence() +# ------------------------------------------------------------------------------ + + +@torch.jit.export +def pad_sequence( + sequence: Tensor, + time_axis: int, + extra_left_context: int = 0, + extra_right_context: int = 0, +) -> Tensor: + """Pad extra left/right contexts to the sequence.""" + + if extra_left_context == 0 and extra_right_context == 0: + return sequence + + tensors_to_concat = [] + + if extra_left_context: + size = (extra_left_context,) + fill_value = 0 + indices = torch.full( + size=size, + fill_value=fill_value, + dtype=torch.long, + device=sequence.device, + ) + left_padding = torch.index_select(sequence, time_axis, indices) + tensors_to_concat.append(left_padding) + + tensors_to_concat.append(sequence) + + # NOTE(cfyeh): for efficiency reason we pad 0 instead of the last frame for + # extra right contexts. + if extra_right_context: + size = list(sequence.shape) + size[time_axis] = extra_right_context + right_padding = torch.zeros(size, dtype=sequence.dtype, device=sequence.device) + tensors_to_concat.append(right_padding) + + padded_sequence = torch.cat(tensors_to_concat, dim=time_axis) + return padded_sequence + + +# ------------------------------------------------------------------------------ +# sequence_to_segments() +# ------------------------------------------------------------------------------ + + +@torch.jit.export +def sequence_to_segments( + sequence: Tensor, + time_axis: int, + lengths: Tensor, + segment_size: Optional[int] = None, + extra_left_context: int = 0, + extra_right_context: int = 0, +) -> List[Tuple[Tensor, Tensor]]: + """Breaks sequence into segments.""" + + sequence = pad_sequence( + sequence=sequence, + time_axis=time_axis, + extra_left_context=extra_left_context, + extra_right_context=extra_right_context, + ) + + lengths = lengths + extra_left_context + extra_right_context + + segments: List[Tuple[Tensor, Tensor]] = [] + + if segment_size is None: + segments.append((sequence, lengths)) + return segments + + offset = 0 + end = sequence.shape[time_axis] + step = segment_size + size = extra_left_context + segment_size + extra_right_context + + while offset + extra_left_context + extra_right_context < end: + clamped_size = min(size, end - offset) + segment_lengths = torch.clamp(lengths - offset, min=0, max=clamped_size) + indices = torch.arange( + start=offset, + end=(offset + clamped_size), + step=1, + dtype=torch.long, + device=sequence.device, + ) + segment_tensor = torch.index_select(sequence, time_axis, indices) + segments.append((segment_tensor, segment_lengths)) + offset = offset + step + + return segments + + +# ------------------------------------------------------------------------------ +# segments_to_sequence() +# ------------------------------------------------------------------------------ + + +@torch.jit.export +def segments_to_sequence( + segments: List[Tuple[Tensor, Tensor]], time_axis: int +) -> Tuple[Tensor, Tensor]: + """Concatenate segments into a full sequence.""" + if len(segments) == 1: + return segments[0] + + tensors_to_concat: List[Tensor] = [] + lengths_to_stack: List[Tensor] = [] + + for tensor, lengths in segments: + tensors_to_concat.append(tensor) + lengths_to_stack.append(lengths) + + sequence = torch.cat(tensors_to_concat, dim=time_axis) + lengths = torch.stack(lengths_to_stack, dim=0) + lengths = torch.sum(lengths, dim=0) + + return sequence, lengths + + +def lengths_to_encoder_padding_mask(lengths, batch_first: bool = False): + """ + convert lengths (a 1-D Long/Int tensor) to 2-D binary tensor + + Args: + lengths: a (B, )-shaped tensor + batch_first: whether to return a (B, T) tensor + + Return: + max_length: maximum length of B sequences + encoder_padding_mask: a (max_length, B) binary mask, where + [t, b] = False for t < lengths[b] and True otherwise + + TODO: + kernelize this function if benchmarking shows this function is slow + """ + max_lengths = torch.max(lengths).item() + bsz = lengths.size(0) + encoder_padding_mask = torch.arange( + max_lengths + ).to( # a (T, ) tensor with [0, ..., T-1] + lengths.device + ).view( # move to the right device + 1, max_lengths + ).expand( # reshape to (1, T)-shaped tensor + bsz, -1 + ) > lengths.view( # expand to (B, T)-shaped tensor + bsz, 1 + ).expand( + -1, max_lengths + ) + if not batch_first: + return encoder_padding_mask.t(), max_lengths + else: + return encoder_padding_mask, max_lengths + + +# ------------------------------------------------------------------------------ +# attention suppression +# ------------------------------------------------------------------------------ + + +def attention_suppression(attention_weights: Tensor, scale: float): + # B, H, qlen, klen -> B, H, qlen, 1 + attention_prob = torch.nn.functional.softmax(attention_weights.float(), dim=-1) + attention_nozeros = attention_prob.to(torch.bool) + nozeros_sum = torch.sum(attention_nozeros.to(torch.float), dim=-1, keepdim=True) + + # For very sparse situation, we need get round about 0s + key_sum = torch.sum(attention_prob, dim=-1, keepdim=True) + + # nozeros_sum should > 1 + key_mean = key_sum / (nozeros_sum + 1e-8) + + # std calculation + dis = (attention_prob - key_mean) * (attention_prob - key_mean) + + # if attention_prob[i] < threshold, then dis_masked[i] = 0; for all i + dis_masked = torch.where( + attention_nozeros, dis, attention_prob.new_zeros(attention_prob.size()) + ) + + key_var = torch.sum(dis_masked, dim=-1, keepdim=True) + key_var = key_var / (nozeros_sum - 1.0 + 1e-8) + key_std = torch.sqrt(key_var) + key_thread = key_mean - scale * key_std + + # if attention_prob[i] >= key_thread, then attention_prob[i] + # , otherwise "-inf" + inf_tensor = attention_prob.new_zeros(attention_prob.size()).detach() + inf_tensor[:] = float("-inf") + attention_weights_float = torch.where( + attention_prob < key_thread, + inf_tensor, + attention_weights.float(), + ) + + return attention_weights_float.type_as(attention_weights) + + +def layer_norm_backward_hook(module, grad_input, grad_output, clamp_value): + return tuple(torch.clamp(v, min=-clamp_value, max=clamp_value) for v in grad_input) From b8786dc2aadb56bb549f92ed542875096868bdd5 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Tue, 2 Mar 2021 17:08:45 -0800 Subject: [PATCH 256/774] Integrate Augmented memory transformer and emformer based augmented memory transformer into fbcode Summary: Integrate Augmented memory transformer and emformer based augmented memory transformer into fbcode. This diff - Modifies the way encoder_out_dict variable is accessed in transformer_monotonic_attention.py - Fix dimension issues in augmented_memory_attention.py - Modifies the way encoder_out is accessed in emformer.py Reviewed By: jmp84 Differential Revision: D26567899 fbshipit-source-id: 9b298ad0bdf78de00b1182001813b0513d32a119 --- .../models/convtransformer_simul_trans.py | 99 ++++++++++++++++++- .../modules/augmented_memory_attention.py | 22 +++-- .../models/speech_to_text/modules/emformer.py | 26 +++-- 3 files changed, 122 insertions(+), 25 deletions(-) diff --git a/examples/simultaneous_translation/models/convtransformer_simul_trans.py b/examples/simultaneous_translation/models/convtransformer_simul_trans.py index 760a48168d..0b15e93fea 100644 --- a/examples/simultaneous_translation/models/convtransformer_simul_trans.py +++ b/examples/simultaneous_translation/models/convtransformer_simul_trans.py @@ -10,7 +10,17 @@ register_model, register_model_architecture, ) -from fairseq.models.speech_to_text import ConvTransformerModel, convtransformer_espnet +from fairseq.models.speech_to_text import ( + ConvTransformerModel, + convtransformer_espnet, + ConvTransformerEncoder, +) +from fairseq.models.speech_to_text.modules.augmented_memory_attention import ( + augmented_memory, + SequenceEncoder, + AugmentedMemoryConvTransformerEncoder, +) +from fairseq.models.speech_to_text.modules.emformer import emformer_encoder @register_model("convtransformer_simul_trans") @@ -56,3 +66,90 @@ def build_decoder(cls, args, task, embed_tokens): ) def convtransformer_simul_trans_espnet(args): convtransformer_espnet(args) + + +@register_model("convtransformer_augmented_memory") +@augmented_memory +class AugmentedMemoryConvTransformerModel(SimulConvTransformerModel): + @classmethod + def build_encoder(cls, args): + encoder = SequenceEncoder(args, AugmentedMemoryConvTransformerEncoder(args)) + + if getattr(args, "load_pretrained_encoder_from", None) is not None: + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=args.load_pretrained_encoder_from + ) + + return encoder + + +@register_model_architecture( + "convtransformer_augmented_memory", "convtransformer_augmented_memory" +) +def augmented_memory_convtransformer_espnet(args): + convtransformer_espnet(args) + + +# ============================================================================ # +# Convtransformer +# with monotonic attention decoder +# with emformer encoder +# ============================================================================ # + + +@emformer_encoder +class ConvTransformerEmformerEncoder(ConvTransformerEncoder): + pass + + +@register_model("convtransformer_emformer") +class ConvtransformerEmformer(SimulConvTransformerModel): + @staticmethod + def add_args(parser): + super(ConvtransformerEmformer, ConvtransformerEmformer).add_args(parser) + + parser.add_argument( + "--segment-length", + type=int, + metavar="N", + help="length of each segment (not including left context / right context)", + ) + parser.add_argument( + "--segment-left-context", + type=int, + help="length of left context in a segment", + ) + parser.add_argument( + "--segment-right-context", + type=int, + help="length of right context in a segment", + ) + parser.add_argument( + "--max-memory-size", + type=int, + default=-1, + help="Right context for the segment.", + ) + parser.add_argument( + "--amtrf-tanh-on-mem", + default=False, + action="store_true", + help="whether to use tanh on memory vector", + ) + + @classmethod + def build_encoder(cls, args): + encoder = ConvTransformerEmformerEncoder(args) + if getattr(args, "load_pretrained_encoder_from", None): + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=args.load_pretrained_encoder_from + ) + return encoder + + +@register_model_architecture( + "convtransformer_emformer", + "convtransformer_emformer", +) +def convtransformer_emformer_base(args): + convtransformer_espnet(args) diff --git a/fairseq/models/speech_to_text/modules/augmented_memory_attention.py b/fairseq/models/speech_to_text/modules/augmented_memory_attention.py index 5d31524b76..e7465bc889 100644 --- a/fairseq/models/speech_to_text/modules/augmented_memory_attention.py +++ b/fairseq/models/speech_to_text/modules/augmented_memory_attention.py @@ -8,7 +8,6 @@ import torch import torch.nn.functional as F from fairseq.models import FairseqEncoder -from fairseq.models.fairseq_encoder import EncoderOut from fairseq.models.speech_to_text import ( ConvTransformerEncoder, ) @@ -72,7 +71,10 @@ def forward(self, src_tokens, src_lengths, states=None): x = self.embed_scale * x subsampling_factor = 1.0 * max_seq_len / output_seq_len - input_lengths = (src_lengths.float() / subsampling_factor).round().long() + input_lengths = torch.max( + (src_lengths.float() / subsampling_factor).ceil().long(), + x.size(0) * src_lengths.new_ones([src_lengths.size(0)]).long(), + ) encoder_padding_mask, _ = lengths_to_encoder_padding_mask( input_lengths, batch_first=True @@ -425,14 +427,14 @@ def forward( if not encoder_padding_mask.any(): encoder_padding_mask = None - return EncoderOut( - encoder_out=encoder_out, - encoder_padding_mask=encoder_padding_mask, - encoder_embedding=None, - encoder_states=states, - src_tokens=None, - src_lengths=None, - ) + return { + "encoder_out": [encoder_out], + "encoder_padding_mask": [encoder_padding_mask], + "encoder_embedding": [], + "encoder_states": [states], + "src_tokens": [], + "src_lengths": [], + } def incremental_encode( self, diff --git a/fairseq/models/speech_to_text/modules/emformer.py b/fairseq/models/speech_to_text/modules/emformer.py index 42b157b766..e026b86847 100644 --- a/fairseq/models/speech_to_text/modules/emformer.py +++ b/fairseq/models/speech_to_text/modules/emformer.py @@ -17,7 +17,6 @@ from fairseq.models import ( FairseqEncoder, ) -from fairseq.models.fairseq_encoder import EncoderOut from fairseq.models.speech_to_text.utils import ( NoOp, lengths_to_padding_mask, @@ -1811,23 +1810,22 @@ def __init__(self, args): ] ) - def forward(self, *args, **kwargs): - encoder_out = super().forward(*args, **kwargs) - (output, encoder_padding_masks, [], all_outputs) = encoder_out.encoder_out + def forward(self, src_tokens, src_lengths): + encoder_out = super().forward(src_tokens, src_lengths) + (output, encoder_padding_masks, [], _) = encoder_out["encoder_out"][0] # This is because that in the original implementation # the output didn't consider the last segment as right context. encoder_padding_masks = encoder_padding_masks[:, : output.size(0)] - # import pdb;pdb.set_trace() - - return EncoderOut( - encoder_out=output, - encoder_padding_mask=encoder_padding_masks, - encoder_embedding=None, - encoder_states=None, - src_tokens=None, - src_lengths=None, - ) + + return { + "encoder_out": [output], + "encoder_padding_mask": [encoder_padding_masks], + "encoder_embedding": [], + "encoder_states": [], + "src_tokens": [], + "src_lengths": [], + } @staticmethod def conv_layer_stride(args): From 0c32e251e29dc6f10755addd37c5f9d963693df9 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Wed, 3 Mar 2021 09:59:23 -0800 Subject: [PATCH 257/774] Update Simultaneous Translation doc (#1659) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1659 Reviewed By: jmp84, kahne Differential Revision: D26708524 Pulled By: xutaima fbshipit-source-id: 0f34e5e9e3bec2360e098c9c272105c793bfa7b7 --- .../simultaneous_translation/docs/baseline.md | 178 ------------------ .../docs/evaluation.md | 115 ----------- .../docs/simulst_mustc_example.md | 60 +++++- 3 files changed, 54 insertions(+), 299 deletions(-) delete mode 100644 examples/simultaneous_translation/docs/baseline.md delete mode 100644 examples/simultaneous_translation/docs/evaluation.md diff --git a/examples/simultaneous_translation/docs/baseline.md b/examples/simultaneous_translation/docs/baseline.md deleted file mode 100644 index d9bf1a1117..0000000000 --- a/examples/simultaneous_translation/docs/baseline.md +++ /dev/null @@ -1,178 +0,0 @@ -# **Baseline Simultaneous Translation** ---- - -This is an instruction of training and evaluating a *wait-k* simultanoes LSTM model on MUST-C English-Gernam Dataset. - -[STACL: Simultaneous Translation with Implicit Anticipation and Controllable Latency using Prefix-to-Prefix Framework](https://https://www.aclweb.org/anthology/P19-1289/) - - -## **Requirements** -Install fairseq (make sure to use the correct branch): -``` -git clone --branch simulastsharedtask git@github.com:pytorch/fairseq.git -cd fairseq -pip install -e . -``` - -Assuming that fairseq is installed in a directory called `FAIRSEQ`. - -Install SentencePiece. One easy way is to use anaconda: - -``` -conda install -c powerai sentencepiece -``` - -Download the MuST-C data for English-German available at https://ict.fbk.eu/must-c/. -We will assume that the data is downloaded in a directory called `DATA_ROOT`. - - -## **Text-to-text Model** ---- -### Data Preparation -Train a SentencePiece model: -```shell -for lang in en de; do - python $FAIRSEQ/examples/simultaneous_translation/data/train_spm.py \ - --data-path $DATA_ROOT/data \ - --vocab-size 10000 \ - --max-frame 3000 \ - --model-type unigram \ - --lang $lang \ - --out-path . -``` - -Process the data with the SentencePiece model: -```shell -proc_dir=proc -mkdir -p $proc_dir -for split in train dev tst-COMMON tst-HE; do - for lang in en de; do - spm_encode \ - --model unigram-$lang-10000-3000/spm.model \ - < $DATA_ROOT/data/$split/txt/$split.$lang \ - > $proc_dir/$split.spm.$lang - done -done -``` - -Binarize the data: - -```shell -proc_dir=proc -fairseq-preprocess \ - --source-lang en --target-lang de \ - --trainpref $proc_dir/train.spm \ - --validpref $proc_dir/dev.spm \ - --testpref $proc_dir/tst-COMMON.spm \ - --thresholdtgt 0 \ - --thresholdsrc 0 \ - --workers 20 \ - --destdir ./data-bin/mustc_en_de \ -``` - -### Training - - -```shell -mkdir -p checkpoints -CUDA_VISIBLE_DEVICES=1 python $FAIRSEQ/train.py data-bin/mustc_en_de \ - --save-dir checkpoints \ - --arch berard_simul_text_iwslt \ - --simul-type waitk \ - --waitk-lagging 2 \ - --optimizer adam \ - --max-epoch 100 \ - --lr 0.001 \ - --clip-norm 5.0 \ - --batch-size 128 \ - --log-format json \ - --log-interval 10 \ - --criterion cross_entropy_acc \ - --user-dir $FAIRSEQ/examples/simultaneous_translation -``` - -## **Speech-to-text Model** ---- -### Data Preparation -First, segment wav files. -```shell -python $FAIRSEQ/examples/simultaneous_translation/data/segment_wav.py \ - --datapath $DATA_ROOT -``` -Similar to text-to-text model, train a Sentencepiecemodel, but only train on German -```Shell -python $FAIRSEQ/examples/simultaneous_translation/data/train_spm.py \ - --data-path $DATA_ROOT/data \ - --vocab-size 10000 \ - --max-frame 3000 \ - --model-type unigram \ - --lang $lang \ - --out-path . -``` -## Training -```shell -mkdir -p checkpoints -CUDA_VISIBLE_DEVICES=1 python $FAIRSEQ/train.py data-bin/mustc_en_de \ - --save-dir checkpoints \ - --arch berard_simul_text_iwslt \ - --waitk-lagging 2 \ - --waitk-stride 10 \ - --input-feat-per-channel 40 \ - --encoder-hidden-size 512 \ - --output-layer-dim 128 \ - --decoder-num-layers 3 \ - --task speech_translation \ - --user-dir $FAIRSEQ/examples/simultaneous_translation - --optimizer adam \ - --max-epoch 100 \ - --lr 0.001 \ - --clip-norm 5.0 \ - --batch-size 128 \ - --log-format json \ - --log-interval 10 \ - --criterion cross_entropy_acc \ - --user-dir $FAIRSEQ/examples/simultaneous_translation -``` - -## Evaluation ---- -### Evaluation Server -For text translation models, the server is set up as follow give input file and reference file. - -``` shell -python ./eval/server.py \ - --hostname localhost \ - --port 12321 \ - --src-file $DATA_ROOT/data/dev/txt/dev.en \ - --ref-file $DATA_ROOT/data/dev/txt/dev.de -``` -For speech translation models, the input is the data direcrory. -``` shell -python ./eval/server.py \ - --hostname localhost \ - --port 12321 \ - --ref-file $DATA_ROOT \ - --data-type speech -``` - -### Decode and Evaluate with Client -Once the server is set up, run client to evaluate translation quality and latency. -```shell -# TEXT -python $fairseq_dir/examples/simultaneous_translation/evaluate.py \ - data-bin/mustc_en_de \ - --user-dir $FAIRSEQ/examples/simultaneous_translation \ - --src-spm unigram-en-10000-3000/spm.model\ - --tgt-spm unigram-de-10000-3000/spm.model\ - -s en -t de \ - --path checkpoints/checkpoint_best.pt - -# SPEECH -python $fairseq_dir/examples/simultaneous_translation/evaluate.py \ - data-bin/mustc_en_de \ - --user-dir $FAIRSEQ/examples/simultaneous_translation \ - --data-type speech \ - --tgt-spm unigram-de-10000-3000/spm.model\ - -s en -t de \ - --path checkpoints/checkpoint_best.pt -``` diff --git a/examples/simultaneous_translation/docs/evaluation.md b/examples/simultaneous_translation/docs/evaluation.md deleted file mode 100644 index c53407354e..0000000000 --- a/examples/simultaneous_translation/docs/evaluation.md +++ /dev/null @@ -1,115 +0,0 @@ -# Introduction to evaluation interface -The simultaneous translation models from sharedtask participents are evaluated under a server-client protocol. The participents are requisted to plug in their own model API in the protocol, and submit a docker file. - -## Server-Client Protocol -An server-client protocol that will be used in evaluation. For example, when a *wait-k* model (k=3) translate the English sentence "Alice and Bob are good friends" to Genman sentence "Alice und Bob sind gute Freunde." , the evaluation process is shown as following figure. - -While every time client needs to read a new state (word or speech utterence), a "GET" request is supposed to sent over to server. Whenever a new token is generated, a "SEND" request with the word predicted (untokenized word) will be sent to server immediately. The server can hence calculate both latency and BLEU score of the sentence. - -### Server -The server code is provided and can be set up directly locally for development purpose. For example, to evaluate a text simultaneous test set, - -```shell - - python fairseq/examples/simultaneous_translation/eval/server.py \ - --hostname local_host \ - --port 1234 \ - --src-file SRC_FILE \ - --ref-file REF_FILE \ - --data-type text \ -``` -The state that server sent to client is has the following format -```json -{ - 'sent_id': Int, - 'segment_id': Int, - 'segment': String -} -``` - -### Client -The client will handle the evaluation process mentioned above. It should be out-of-box as well. The client's protocol is as following table - -|Action|Content| -|:---:|:---:| -|Request new word / utterence| ```{key: "Get", value: None}```| -|Predict word "W"| ```{key: "SEND", value: "W"}```| - - - -The core of the client module is the agent, which needs to be modified to different models accordingly. The abstract class of agent is as follow, the evaluation process happens in the `decode()` function. -```python -class Agent(object): - "an agent needs to follow this pattern" - def __init__(self, *args, **kwargs): - ... - - def init_states(self): - # Initializing states - ... - - def update_states(self, states, new_state): - # Update states with given new state from server - # TODO (describe the states) - ... - - def finish_eval(self, states, new_state): - # Check if evaluation is finished - ... - - def policy(self, state: list) -> dict: - # Provide a action given current states - # The action can only be either - # {key: "GET", value: NONE} - # or - # {key: "SEND", value: W} - ... - - def reset(self): - # Reset agent - ... - - def decode(self, session): - - states = self.init_states() - self.reset() - - # Evaluataion protocol happens here - while True: - # Get action from the current states according to self.policy() - action = self.policy(states) - - if action['key'] == GET: - # Read a new state from server - new_state = session.get_src() - states = self.update_states(states, new_state) - - if self.finish_eval(states, new_state): - # End of document - break - - elif action['key'] == SEND: - # Send a new prediction to server - session.send_hypo(action['value']) - - # Clean the history, wait for next sentence - if action['value'] == DEFAULT_EOS: - states = self.init_states() - self.reset() - else: - raise NotImplementedError - - -``` -Here an implementation of agent of text [*wait-k* model](somelink). Notice that the tokenization is not considered. - -## Quality -The quality is measured by detokenized BLEU. So make sure that the predicted words sent to server are detokenized. An implementation is can be find [here](some link) - -## Latency -The latency metrics are -* Average Proportion -* Average Lagging -* Differentiable Average Lagging -Again Thery will also be evaluated on detokenized text. - diff --git a/examples/speech_to_text/docs/simulst_mustc_example.md b/examples/speech_to_text/docs/simulst_mustc_example.md index 5dea0d8475..0144fcb766 100644 --- a/examples/speech_to_text/docs/simulst_mustc_example.md +++ b/examples/speech_to_text/docs/simulst_mustc_example.md @@ -1,13 +1,46 @@ # Simultaneous Speech Translation (SimulST) on MuST-C +This is an instruction of training and evaluating a transformer *wait-k* simultaneous model on MUST-C English-Germen Dataset, from [SimulMT to SimulST: Adapting Simultaneous Text Translation to End-to-End Simultaneous Speech Translation](https://www.aclweb.org/anthology/2020.aacl-main.58.pdf). + [MuST-C](https://www.aclweb.org/anthology/N19-1202) is multilingual speech-to-text translation corpus with 8-language translations on English TED talks. -## Data Preparation & ASR -Please follow the steps in offline [speech-to-text](../mustc_example.md) translation for data preparation and ASR pretraining. +## Data Preparation +[Download](https://ict.fbk.eu/must-c) and unpack MuST-C data to a path +`${MUSTC_ROOT}/en-${TARGET_LANG_ID}`, then preprocess it with +```bash +# Additional Python packages for S2T data processing/model training +pip install pandas torchaudio sentencepiece + +# Generate TSV manifests, features, vocabulary, +# global cepstral and mean estimation, +# and configuration for each language +python examples/speech_to_text/prep_mustc_data.py \ + --data-root ${MUSTC_ROOT} --task asr \ + --vocab-type unigram --vocab-size 10000 \ + --cmvn-type global +python examples/speech_to_text/prep_mustc_data.py \ + --data-root ${MUSTC_ROOT} --task st \ + --vocab-type unigram --vocab-size 10000 + --cmvn-type global +``` + +## ASR Pretraining +We just need a pretrained offline ASR model +``` +fairseq-train ${MUSTC_ROOT}/en-de \ + --config-yaml config_asr.yaml --train-subset train_asr --valid-subset dev_asr \ + --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --arch convtransformer_espnet --optimizer adam --lr 0.0005 --lr-scheduler inverse_sqrt \ + --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 +``` -## Training +## Simultaneous Speech Translation Training -#### Wait-K(K=3) with fixed pre-decision module +### Wait-K with fixed pre-decision module +Fixed pre-decision indicates that the model operate simultaneous policy on the boundaries of fixed chunks. +Here is a example of fixed pre-decision ratio 7 (the simultaneous decision is made every 7 encoder states) and +a wait-3 policy model ``` fairseq-train ${MUSTC_ROOT}/en-de \ --config-yaml config_st.yaml --train-subset train_st --valid-subset dev_st \ @@ -21,8 +54,9 @@ Please follow the steps in offline [speech-to-text](../mustc_example.md) transla --simul-type waitk_fixed_pre_decision \ --waitk-lagging 3 \ --fixed-pre-decision-ratio 7 + ``` -#### Monotonic multihead attention with fixed pre-decision module +### Monotonic multihead attention with fixed pre-decision module ``` fairseq-train ${MUSTC_ROOT}/en-de \ --config-yaml config_st.yaml --train-subset train_st --valid-subset dev_st \ @@ -39,9 +73,13 @@ Please follow the steps in offline [speech-to-text](../mustc_example.md) transla ``` ## Inference & Evaluation [SimulEval](https://github.com/facebookresearch/SimulEval) is used for evaluation. +The source file is a list of paths of audio files, +while target file is the corresponding translations. ``` +pip install simuleval + simuleval \ - --agent ${FAIRSEQ}/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py + --agent examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py --src-file ${SRC_LIST_OF_AUDIO} --tgt-file ${TGT_FILE} --data-bin ${MUSTC_ROOT}/en-de \ @@ -50,3 +88,13 @@ simuleval \ --tgt-splitter-path ${MUSTC_ROOT}/en-de/spm.model \ --scores ``` + +A pretrained checkpoint can be downloaded from [here](https://dl.fbaipublicfiles.com/simultaneous_translation/convtransformer_wait5_pre7), which is a wait-5 model with a pre-decision of 280 ms. The databin (containing dictionary, gcmvn file and sentencepiece model) can be found [here](https://dl.fbaipublicfiles.com/simultaneous_translation/must_c_v1.0_en_de_databin). + +The quality is measured by detokenized BLEU. So make sure that the predicted words sent to the server are detokenized. + +The latency metrics are +* Average Proportion +* Average Lagging +* Differentiable Average Lagging +Again they will also be evaluated on detokenized text. From 7d2394b56f1cbdcdede9c7a8cf6de1df022e0a17 Mon Sep 17 00:00:00 2001 From: Eric Lou <ericlou@fb.com> Date: Wed, 3 Mar 2021 10:48:42 -0800 Subject: [PATCH 258/774] ioPath async - Fairseq unittests (#1669) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1669 Unit tests for async writes integration done in D26467815 (https://github.com/pytorch/fairseq/commit/3100d0b8e5bb5e61b4d73b9c058389aa2c06784a). Ongoing performance tests: https://fb.quip.com/kjM7Atb1kKbO Reviewed By: myleott Differential Revision: D26732660 fbshipit-source-id: faf8cac67b9167af4195358c1a2592804c13562c --- fairseq/file_io.py | 2 +- tests/test_checkpoint_utils.py | 15 +++++++++++++++ tests/test_file_io.py | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/fairseq/file_io.py b/fairseq/file_io.py index 731fef3570..9a78ab505d 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -170,7 +170,7 @@ def opena( if not IOPathPathManager: logging.info("ioPath is initializing PathManager.") try: - from iopath import PathManager + from iopath.common.file_io import PathManager IOPathPathManager = PathManager() except Exception: logging.exception("Failed to initialize ioPath PathManager object.") diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py index 617a5f7c84..3278de6b9f 100644 --- a/tests/test_checkpoint_utils.py +++ b/tests/test_checkpoint_utils.py @@ -9,8 +9,10 @@ import tempfile import unittest from io import StringIO +from unittest.mock import patch from fairseq import checkpoint_utils +from omegaconf import OmegaConf from tests.utils import ( create_dummy_data, @@ -87,6 +89,19 @@ def test_prune_state_dict(self): self.assertEqual(len(ensemble[0].encoder.layers), 2) self.assertEqual(len(ensemble[0].decoder.layers), 1) + def test_torch_persistent_save_async(self): + cfg = OmegaConf.create() + cfg.dataset = OmegaConf.create() + cfg.dataset.write_checkpoints_asynchronously = True + state_dict = {} + filename = "async_checkpoint.pt" + + with patch(f"{checkpoint_utils.__name__}.PathManager.opena") as mock_opena: + with patch(f"{checkpoint_utils.__name__}._torch_persistent_save") as mock_save: + checkpoint_utils.torch_persistent_save(cfg.dataset, state_dict, filename) + mock_opena.assert_called_with(filename, "wb") + mock_save.assert_called() + if __name__ == "__main__": unittest.main() diff --git a/tests/test_file_io.py b/tests/test_file_io.py index aef5b80d18..8ebbba4a2e 100644 --- a/tests/test_file_io.py +++ b/tests/test_file_io.py @@ -45,3 +45,18 @@ def test_file_io_oss(self): with PathManager.open(os.path.join(self._tmpdir, "test.txt"), "r") as f: s = f.read() self.assertEqual(s, self._tmpfile_contents) + + def test_file_io_async(self): + # ioPath `PathManager` is initialized after the first `opena` call. + try: + from fairseq.file_io import IOPathPathManager, PathManager + + self.assertIsNone(IOPathPathManager) + _asyncfile = os.path.join(self._tmpdir, "async.txt") + f = PathManager.opena(_asyncfile, "wb") + f.close() + + from fairseq.file_io import IOPathPathManager + self.assertIsNotNone(IOPathPathManager) + finally: + self.assertTrue(PathManager.async_close()) From 1fed7a8426e8c548196add0d65d77857ab224705 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Wed, 3 Mar 2021 19:29:55 -0800 Subject: [PATCH 259/774] add unit test for multi_corpus_dataset Reviewed By: vimalmanohar Differential Revision: D26220694 fbshipit-source-id: ed13f8527a1b203e1a9d004fa8a86e1ad6423d60 --- tests/test_multi_corpus_dataset.py | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/test_multi_corpus_dataset.py diff --git a/tests/test_multi_corpus_dataset.py b/tests/test_multi_corpus_dataset.py new file mode 100644 index 0000000000..a1fafe489b --- /dev/null +++ b/tests/test_multi_corpus_dataset.py @@ -0,0 +1,69 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from collections import OrderedDict + +import torch +from fairseq.data import LanguagePairDataset, TokenBlockDataset +from fairseq.data.multi_corpus_dataset import MultiCorpusDataset +from tests.test_train import mock_dict + + +class TestMultiCorpusDataset(unittest.TestCase): + def setUp(self): + d = mock_dict() + tokens_1 = torch.LongTensor([i for i in range(1, 5000, 2)]).view(1, -1) + tokens_ds1 = TokenBlockDataset( + tokens_1, + sizes=[tokens_1.size(-1)], + block_size=1, + pad=0, + eos=1, + include_targets=False, + ) + self.dataset_1 = LanguagePairDataset( + tokens_ds1, tokens_ds1.sizes, d, shuffle=False + ) + tokens_2 = torch.LongTensor([i for i in range(2, 5000, 2)]).view(1, -1) + tokens_ds2 = TokenBlockDataset( + tokens_2, + sizes=[tokens_2.size(-1)], + block_size=1, + pad=0, + eos=1, + include_targets=False, + ) + self.dataset_2 = LanguagePairDataset( + tokens_ds2, tokens_ds2.sizes, d, shuffle=False + ) + + def _test_sample_helper( + self, + distribution, + ): + m = MultiCorpusDataset( + OrderedDict({0: self.dataset_1, 1: self.dataset_2}), + distribution=distribution, + seed=0, + sort_indices=True, + ) + m.set_epoch(1) + indices = m.ordered_indices() + count_sample_from_first_dataset = 0 + for i in indices: + if m[i]["source"].item() % 2 == 1: + count_sample_from_first_dataset += 1 + sample_from_first_ds_percentage = ( + 1.0 * count_sample_from_first_dataset / len(indices) + ) + self.assertLess( + abs(sample_from_first_ds_percentage - distribution[0]), + 0.01, + ) + + def test_multi_corpus_dataset(self): + for distribution in [[0.5, 0.5], [0.1, 0.9], [0.9, 0.1]]: + self._test_sample_helper(distribution=distribution) From fc2840de58b06f381626332153203fb32588c23d Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Wed, 3 Mar 2021 19:29:55 -0800 Subject: [PATCH 260/774] optimize sampling process of multi_corpus_dataset Summary: The sampling process in multi_corpus_dataset is very inefficient. Turns out we can signficantly optimize it by sampling in batches rather than one by one. this allows: 1. fast local development and iteration with corpus sampling, as the turnaround time was long before 2. makes it take less time for our jobs can start training, enabling earlier signal if for example there is a configuration issue Reviewed By: zhengwy888 Differential Revision: D26187821 fbshipit-source-id: b4f7f6b7c187b3785499308226e2af671a6c354f --- fairseq/data/multi_corpus_dataset.py | 85 +++++++++++++++++----------- tests/test_multi_corpus_dataset.py | 14 ++++- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index 6563713489..00e464ed31 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import logging +import time from collections import OrderedDict from typing import Dict, List @@ -12,7 +13,6 @@ from . import FairseqDataset - logger = logging.getLogger(__name__) @@ -49,6 +49,7 @@ def __init__( super().__init__() assert isinstance(datasets, OrderedDict) assert len(datasets) == len(distribution) + assert sum(distribution) == 1 self.datasets = datasets self.distribution = distribution self.seed = seed @@ -69,43 +70,61 @@ def __init__( self.total_num_instances += len(dataset) def ordered_indices(self): + start = time.time() with data_utils.numpy_seed(self.seed, self.epoch): - # Used to store the order of indices of each dataset to use - indices = [ - np.random.permutation(len(dataset)) - for dataset in self.datasets.values() - ] - # Keep track of which samples we've used for each dataset - counters = [0 for _ in self.datasets] - - sampled_indices = [ - self._sample(indices, counters) for _ in range(self.total_num_instances) - ] + sampled_indices = [] + num_selected_instances = 0 + + # For each dataset i, sample self.distribution[i] * self.total_num_instances + for i, key in enumerate(self.datasets): + + if i < len(self.datasets) - 1: + num_instances = int(self.distribution[i] * self.total_num_instances) + high = self.dataset_offsets[i + 1] + else: + num_instances = self.total_num_instances - num_selected_instances + high = self.total_num_instances + + logger.info(f"sampling {num_instances} from {key} dataset") + num_selected_instances += num_instances + + # First, add k copies of the dataset where k = num_instances // len(dataset). + # This ensures an equal distribution of the data points as much as possible. + # For the remaining entries randomly sample them + dataset_size = len(self.datasets[key]) + num_copies = num_instances // dataset_size + dataset_indices = ( + np.random.permutation(high - self.dataset_offsets[i]) + + self.dataset_offsets[i] + )[: num_instances - num_copies * dataset_size] + if num_copies > 0: + sampled_indices += list( + np.concatenate( + ( + np.repeat( + np.arange(self.dataset_offsets[i], high), num_copies + ), + dataset_indices, + ) + ) + ) + else: + sampled_indices += list(dataset_indices) + + assert ( + len(sampled_indices) == self.total_num_instances + ), f"{len(sampled_indices)} vs {self.total_num_instances}" + + np.random.shuffle(sampled_indices) if self.sort_indices: sampled_indices.sort(key=lambda i: self.num_tokens(i)) - return np.array(sampled_indices, dtype=np.int64) - - def _sample(self, indices, counters): - # First pick dataset - dataset_idx = np.random.choice(len(self.distribution), p=self.distribution) - - # Then get dataset internal index - idx = indices[dataset_idx][counters[dataset_idx]] - - # Convert to multi-datasets index - idx += self.dataset_offsets[dataset_idx] - - counters[dataset_idx] += 1 - - # Reset if we reach end - if counters[dataset_idx] == len(self.dataset_list[dataset_idx]): - counters[dataset_idx] = 0 - indices[dataset_idx] = np.random.permutation( - len(self.dataset_list[dataset_idx]) + logger.info( + "multi_corpus_dataset ordered_indices took {}s".format( + time.time() - start + ) ) - - return idx + return np.array(sampled_indices, dtype=np.int64) def _map_index(self, index: int): """ diff --git a/tests/test_multi_corpus_dataset.py b/tests/test_multi_corpus_dataset.py index a1fafe489b..5a79f4b680 100644 --- a/tests/test_multi_corpus_dataset.py +++ b/tests/test_multi_corpus_dataset.py @@ -27,7 +27,7 @@ def setUp(self): self.dataset_1 = LanguagePairDataset( tokens_ds1, tokens_ds1.sizes, d, shuffle=False ) - tokens_2 = torch.LongTensor([i for i in range(2, 5000, 2)]).view(1, -1) + tokens_2 = torch.LongTensor([i for i in range(0, 5000, 2)]).view(1, -1) tokens_ds2 = TokenBlockDataset( tokens_2, sizes=[tokens_2.size(-1)], @@ -53,9 +53,13 @@ def _test_sample_helper( m.set_epoch(1) indices = m.ordered_indices() count_sample_from_first_dataset = 0 + items = set() for i in indices: - if m[i]["source"].item() % 2 == 1: + item = m[i]["source"].item() + if item % 2 == 1: count_sample_from_first_dataset += 1 + + items.add(item) sample_from_first_ds_percentage = ( 1.0 * count_sample_from_first_dataset / len(indices) ) @@ -63,6 +67,12 @@ def _test_sample_helper( abs(sample_from_first_ds_percentage - distribution[0]), 0.01, ) + self.assertEqual( + len(items), + int(min(len(self.dataset_1), len(indices) * distribution[0]) + + min(len(self.dataset_1), len(indices) * distribution[1])) + ) + print(distribution) def test_multi_corpus_dataset(self): for distribution in [[0.5, 0.5], [0.1, 0.9], [0.9, 0.1]]: From f6d60e2fee9fe8982e3c9de1e6bb77680978e749 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Wed, 3 Mar 2021 21:15:01 -0800 Subject: [PATCH 261/774] minor fixes and improvements (#1671) Summary: there are a few changes here: - convert config persisted in checkpoints into a plain dict when saving and back to omegaconf config when loading: this helps avoid compatibility issues between different versions of python, omegaconf, etc - update checkpoints that have old print_alignment saved - add lr_float to composite optimizer to enable sweeping on lr with auto sweepers like ax - fixing some edge cases for config loading Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1671 Reviewed By: myleott Differential Revision: D26791583 Pulled By: alexeib fbshipit-source-id: 124dec74932052925c43b6a93130f4428803cb46 --- fairseq/checkpoint_utils.py | 54 +++++++++++++++++++++++++++++++------ fairseq/dataclass/utils.py | 16 ++++++----- fairseq/optim/composite.py | 13 ++++++--- 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index d6618fbb62..97f22041bc 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -21,7 +21,7 @@ ) from fairseq.file_io import PathManager from fairseq.models import FairseqDecoder, FairseqEncoder -from omegaconf import DictConfig, open_dict +from omegaconf import Container, DictConfig, open_dict, OmegaConf logger = logging.getLogger(__name__) @@ -275,8 +275,22 @@ def load_checkpoint_to_cpu(path, arg_overrides=None, load_on_all_ranks=False): for arg_name, arg_val in arg_overrides.items(): setattr(args, arg_name, arg_val) - if "cfg" in state and state["cfg"] is not None and arg_overrides is not None: - overwrite_args_by_name(state["cfg"], arg_overrides) + if "cfg" in state and state["cfg"] is not None: + + # hack to be able to set Namespace in dict config. this should be removed when we update to newer + # omegaconf version that supports object flags, or when we migrate all existing models + from omegaconf import _utils + + old_primitive = _utils.is_primitive_type + _utils.is_primitive_type = lambda _: True + + state["cfg"] = OmegaConf.create(state["cfg"]) + + _utils.is_primitive_type = old_primitive + OmegaConf.set_struct(state["cfg"], True) + + if arg_overrides is not None: + overwrite_args_by_name(state["cfg"], arg_overrides) state = _upgrade_state_dict(state) return state @@ -440,7 +454,7 @@ def save_state( if extra_state is None: extra_state = {} state_dict = { - "cfg": cfg, + "cfg": OmegaConf.to_container(cfg) if OmegaConf.is_config(cfg) else cfg, "args": kwargs.get("args", None), "model": model_state_dict or {}, "optimizer_history": optim_history @@ -453,7 +467,7 @@ def save_state( } ], "extra_state": extra_state, - "task_state": task.state_dict() if task is not None else {} + "task_state": task.state_dict() if task is not None else {}, } if utils.has_parameters(criterion): state_dict["criterion"] = criterion.state_dict() @@ -568,15 +582,39 @@ def _upgrade_state_dict(state): if hasattr(state["args"], "lr") and isinstance(state["args"].lr, float): state["args"].lr = [state["args"].lr] # convert task data arg to a string instead of List[string] - if hasattr(state["args"], "data") and isinstance(state["args"].data, list) and len(state["args"].data) > 0: + if ( + hasattr(state["args"], "data") + and isinstance(state["args"].data, list) + and len(state["args"].data) > 0 + ): state["args"].data = state["args"].data[0] state["cfg"] = convert_namespace_to_omegaconf(state["args"]) if "cfg" in state and state["cfg"] is not None: - with open_dict(state["cfg"]): + cfg = state["cfg"] + with open_dict(cfg): # any upgrades for Hydra-based configs - pass + if ( + "task" in cfg + and "eval_wer_config" in cfg.task + and isinstance(cfg.task.eval_wer_config.print_alignment, bool) + ): + cfg.task.eval_wer_config.print_alignment = "hard" + if "generation" in cfg and isinstance(cfg.generation.print_alignment, bool): + cfg.generation.print_alignment = "hard" + if ( + "model" in cfg + and "w2v_args" in cfg.model + and cfg.model.w2v_args is not None + and ( + hasattr(cfg.model.w2v_args, "task") or "task" in cfg.model.w2v_args + ) + and isinstance( + cfg.model.w2v_args.task.eval_wer_config.print_alignment, bool + ) + ): + cfg.model.w2v_args.task.eval_wer_config.print_alignment = "hard" return state diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index a4d4a412dd..27c9006fdb 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -43,7 +43,9 @@ def interpret_dc_type(field_type): return str typestring = str(field_type) - if re.match(r"(typing.|^)Union\[(.*), NoneType\]$", typestring) or typestring.startswith("typing.Optional"): + if re.match( + r"(typing.|^)Union\[(.*), NoneType\]$", typestring + ) or typestring.startswith("typing.Optional"): return field_type.__args__[0] return field_type @@ -235,15 +237,17 @@ def get_default(f): and not (isinstance(val, str) and val.startswith("${")) ): # if type is int but val is float, then we will crash later - try to convert here - if hasattr(v.type, '__args__'): + if hasattr(v.type, "__args__"): t_args = v.type.__args__ - if len(t_args) == 1: + if len(t_args) == 1 and (t_args[0] is float or t_args[0] is int): val = list(map(t_args[0], val)) - elif val is not None and (field_type is int or field_type is bool or field_type is float): + elif val is not None and ( + field_type is int or field_type is bool or field_type is float + ): try: val = field_type(val) except: - pass # ignore errors here, they are often from interpolation args + pass # ignore errors here, they are often from interpolation args if val is None: overrides.append("{}.{}=null".format(sub_node, k)) @@ -430,7 +434,7 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): if k in cfg and isinstance(cfg[k], DictConfig): if k in overrides and isinstance(overrides[k], dict): for ok, ov in overrides[k].items(): - if isinstance(ov, dict): + if isinstance(ov, dict) and cfg[k][ok] is not None: overwrite_args_by_name(cfg[k][ok], ov) else: cfg[k][ok] = ov diff --git a/fairseq/optim/composite.py b/fairseq/optim/composite.py index 1a581bc010..a5366d6243 100644 --- a/fairseq/optim/composite.py +++ b/fairseq/optim/composite.py @@ -22,12 +22,13 @@ class OptimizerAndSchedulerConfig(FairseqDataclass): optimizer: Any = None lr_scheduler: Optional[Any] = None - lr: List[float] = II("optimization.lr") + lr: List = II("optimization.lr") + lr_float: Optional[float] = None # this makes it easier to sweep on learning rate with auto sweepers @dataclass class CompositeOptimizerConfig(FairseqDataclass): - groups: Dict[str, OptimizerAndSchedulerConfig] = field( + groups: Dict[str, Any] = field( default_factory=lambda: {}, metadata={ "help": "optimizer name -> optimizer OptimizerAndSchedulerConfig. " @@ -64,8 +65,12 @@ def __init__(self, cfg: CompositeOptimizerConfig, params): for group, group_params in groupped_params.items(): group_cfg = cfg.groups[group] with open_dict(group_cfg): - group_cfg.optimizer.lr = group_cfg.lr - group_cfg.lr_scheduler.lr = group_cfg.lr + if group_cfg.lr_float is not None: + group_cfg.optimizer.lr = [group_cfg.lr_float] + group_cfg.lr_scheduler.lr = [group_cfg.lr_float] + else: + group_cfg.optimizer.lr = group_cfg.lr + group_cfg.lr_scheduler.lr = group_cfg.lr self.optimizers[group] = _build_optimizer(group_cfg.optimizer, group_params) if group_cfg.lr_scheduler is not None: self.lr_schedulers[group] = build_lr_scheduler( From f1c595beb8acd2a6dc8c9fa9f7fb60ca23c61899 Mon Sep 17 00:00:00 2001 From: Kaushik Rangadurai <krangadu@fb.com> Date: Thu, 4 Mar 2021 11:48:27 -0800 Subject: [PATCH 262/774] Ability to pass attn_mask to TransformerSentenceEncoder Summary: Provide an ability to pass attn_mask to TransformerSentenceEncoder. The default is None and hence this is backwards compatible. The attention mask can either be a 2D tensor (of shape [tgt_seq_len, src_seq_len]) or a 3D tensor of shape (bcz * num_heads, tgt_seq_len, src_seq_len). In case of self attention, tgt_seq_len = src_seq_len. Reviewed By: myleott Differential Revision: D26790767 fbshipit-source-id: 937d6c6cf08790c7d43d33fda97a30425f31ea06 --- fairseq/modules/transformer_sentence_encoder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/modules/transformer_sentence_encoder.py b/fairseq/modules/transformer_sentence_encoder.py index 6e9c32f467..a7fb198779 100644 --- a/fairseq/modules/transformer_sentence_encoder.py +++ b/fairseq/modules/transformer_sentence_encoder.py @@ -226,6 +226,7 @@ def forward( last_state_only: bool = False, positions: Optional[torch.Tensor] = None, token_embeddings: Optional[torch.Tensor] = None, + attn_mask: Optional[torch.Tensor] = None, ) -> Tuple[torch.Tensor, torch.Tensor]: is_tpu = tokens.device.type == "xla" @@ -268,7 +269,7 @@ def forward( inner_states.append(x) for layer in self.layers: - x, _ = layer(x, self_attn_padding_mask=padding_mask) + x, _ = layer(x, self_attn_padding_mask=padding_mask, self_attn_mask=attn_mask) if not last_state_only: inner_states.append(x) From 6d23cc7e7c32d1a6aa1d2d4a4c94abe50c980126 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 4 Mar 2021 13:31:02 -0800 Subject: [PATCH 263/774] Move checkpoint state_dict creation into Trainer (#1666) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1666 Context: the checkpoint saving call stack has become a bit convoluted: ``` train.py + checkpoint_utils.save_checkpoint + trainer.save_checkpoint + checkpoint_utils.save_state + checkpoint_utils.torch_persistent_save ``` This diff slightly simplifies the checkpoint saving logic by exposing a `state_dict` method inside the Trainer. This simplifies the call stack to: ``` train.py + checkpoint_utils.save_checkpoint + trainer.save_checkpoint + checkpoint_utils.torch_persistent_save ``` This new structure is important for the FullyShardedDataParallel diff (next diff in the stack), since it enables the Trainer to save multiple checkpoints for the different optimizer state shards. Test Plan: - unit tests - trained WMT En-De models; confirmed checkpoints save/load properly, resuming from a checkpoint gives identical results - `buck test fblearner/flow/projects/langtech/translation:tests` (2 failures are in trunk too): https://www.internalfb.com/intern/testinfra/testconsole/testrun/2533274840914654/ Reviewed By: zhengwy888 Differential Revision: D26771146 Pulled By: myleott fbshipit-source-id: 10f91979cd42205c1d8abcaa9ab56f63eba31e93 --- fairseq/checkpoint_utils.py | 71 ++++------------------------------ fairseq/dataclass/configs.py | 1 - fairseq/trainer.py | 67 +++++++++++++++++++++++++------- tests/test_checkpoint_utils.py | 7 ++-- tests/test_train.py | 1 + 5 files changed, 64 insertions(+), 83 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 97f22041bc..5a98dad2aa 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -31,7 +31,7 @@ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): from fairseq import meters # only one worker should attempt to create the required dir - if cfg.distributed_rank == 0: + if trainer.data_parallel_rank == 0: os.makedirs(cfg.save_dir, exist_ok=True) prev_best = getattr(save_checkpoint, "best", val_loss) @@ -44,7 +44,7 @@ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): trainer.consolidate_optimizer() - if not trainer.is_data_parallel_master: + if not trainer.should_save_checkpoint_on_current_rank: return write_timer = meters.StopwatchMeter() @@ -59,7 +59,7 @@ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): def is_better(a, b): return a >= b if cfg.maximize_best_checkpoint_metric else a <= b - suffix = cfg.checkpoint_suffix or "" + suffix = trainer.checkpoint_suffix checkpoint_conds = collections.OrderedDict() checkpoint_conds["checkpoint{}{}.pt".format(epoch, suffix)] = ( end_of_epoch and not cfg.no_epoch_checkpoints and epoch % cfg.save_interval == 0 @@ -165,7 +165,7 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): " or reset_lr_scheduler or reset_meters or reset_dataloader" ) - suffix = cfg.checkpoint_suffix + suffix = trainer.checkpoint_suffix if ( cfg.restore_file == "checkpoint_last.pt" ): # default value of restore_file is 'checkpoint_last.pt' @@ -190,7 +190,7 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): raise ValueError( f"--funetune-from-model {cfg.finetune_from_model} does not exist" ) - elif cfg.model_parallel_size > 1: + elif suffix is not None: checkpoint_path = cfg.restore_file.replace(".pt", suffix + ".pt") else: checkpoint_path = cfg.restore_file @@ -405,8 +405,8 @@ def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt"): return [os.path.join(path, x[1]) for x in sorted(entries, reverse=True)] -def torch_persistent_save(cfg: CheckpointConfig, obj, filename): - if cfg.write_checkpoints_asynchronously: +def torch_persistent_save(obj, filename, async_write: bool = False): + if async_write: with PathManager.opena(filename, "wb") as f: _torch_persistent_save(obj, f) else: @@ -434,61 +434,6 @@ def _torch_persistent_save(obj, f): logger.error(traceback.format_exc()) -def save_state( - filename, - cfg: FairseqConfig, - model_state_dict, - criterion, - optimizer, - lr_scheduler, - num_updates, - optim_history=None, - extra_state=None, - task=None, - **kwargs, -): - from fairseq import utils - - if optim_history is None: - optim_history = [] - if extra_state is None: - extra_state = {} - state_dict = { - "cfg": OmegaConf.to_container(cfg) if OmegaConf.is_config(cfg) else cfg, - "args": kwargs.get("args", None), - "model": model_state_dict or {}, - "optimizer_history": optim_history - + [ - { - "criterion_name": criterion.__class__.__name__, - "optimizer_name": optimizer.__class__.__name__, - "lr_scheduler_state": lr_scheduler.state_dict(), - "num_updates": num_updates, - } - ], - "extra_state": extra_state, - "task_state": task.state_dict() if task is not None else {}, - } - if utils.has_parameters(criterion): - state_dict["criterion"] = criterion.state_dict() - - if cfg is None: - cfg = state_dict["args"] - assert cfg is not None, "must provide cfg or args" - - if isinstance(cfg, DictConfig): - no_save_optimizer_state = cfg.checkpoint.no_save_optimizer_state - else: - no_save_optimizer_state = cfg.no_save_optimizer_state - if not no_save_optimizer_state: - state_dict["last_optimizer_state"] = optimizer.state_dict() - - # keep everything on CPU - state_dict = utils.move_to_cpu(state_dict) - - torch_persistent_save(cfg.checkpoint, state_dict, filename) - - def _upgrade_state_dict(state): """Helper for upgrading old model checkpoints.""" from fairseq import models, registry, tasks @@ -529,7 +474,7 @@ def _upgrade_state_dict(state): if "num_updates" not in state["optimizer_history"][-1]: state["optimizer_history"][-1]["num_updates"] = 0 # old model checkpoints may not have separate source/target positions - if hasattr(state["args"], "max_positions") and not hasattr( + if "args" in state and hasattr(state["args"], "max_positions") and not hasattr( state["args"], "max_source_positions" ): state["args"].max_source_positions = state["args"].max_positions diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 39355b1caf..4d3c60bfd6 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -618,7 +618,6 @@ class CheckpointConfig(FairseqDataclass): }, ) model_parallel_size: int = II("common.model_parallel_size") - distributed_rank: int = II("distributed_training.distributed_rank") @dataclass diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 680a7ee953..45d9591d7c 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -25,6 +25,8 @@ from fairseq.nan_detector import NanDetector from fairseq.optim import lr_scheduler +from omegaconf import OmegaConf + logger = logging.getLogger(__name__) @@ -171,6 +173,16 @@ def use_distributed_wrapper(self) -> bool: and not self.cfg.optimization.use_bmuf ) + @property + def should_save_checkpoint_on_current_rank(self) -> bool: + """Indicates whether to save checkpoints on the current DDP rank.""" + return self.is_data_parallel_master + + @property + def checkpoint_suffix(self) -> str: + """Suffix to add to the checkpoint file name.""" + return self.cfg.checkpoint.checkpoint_suffix or "" + @property def criterion(self): if self._wrapped_criterion is None: @@ -274,25 +286,50 @@ def consolidate_optimizer(self): if hasattr(self.optimizer.optimizer, "consolidate_state_dict"): self.optimizer.optimizer.consolidate_state_dict() + def state_dict(self): + state_dict = { + "args": None, # legacy + "cfg": ( + OmegaConf.to_container(self.cfg) + if OmegaConf.is_config(self.cfg) else self.cfg + ), + "model": self.model.state_dict(), + "criterion": ( + self.criterion.state_dict() + if utils.has_parameters(self.criterion) else None + ), + "optimizer_history": (self._optim_history or []) + + [ + { + "criterion_name": self.get_criterion().__class__.__name__, + "optimizer_name": self.optimizer.__class__.__name__, + "lr_scheduler_state": self.lr_scheduler.state_dict(), + "num_updates": self.get_num_updates(), + } + ], + "task_state": self.task.state_dict() if self.task is not None else {}, + "extra_state": { + "metrics": metrics.state_dict(), + "previous_training_time": self.cumulative_training_time(), + } + } + if not self.cfg.checkpoint.no_save_optimizer_state: + state_dict["last_optimizer_state"] = self.optimizer.state_dict() + return state_dict + def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" - if self.is_data_parallel_master: # only save one checkpoint - logger.info(f"Saving checkpoint to {filename}") - extra_state["metrics"] = metrics.state_dict() - extra_state["previous_training_time"] = self.cumulative_training_time() - checkpoint_utils.save_state( + logger.info(f"Saving checkpoint to {filename}") + # call state_dict on all ranks in case it needs internal communication + state_dict = utils.move_to_cpu(self.state_dict()) + state_dict["extra_state"].update(extra_state) + if self.should_save_checkpoint_on_current_rank: + checkpoint_utils.torch_persistent_save( + state_dict, filename, - self.cfg, - self.model.state_dict(), - self.get_criterion(), - self.optimizer, - self.lr_scheduler, - self.get_num_updates(), - optim_history=self._optim_history, - extra_state=extra_state, - task=self.task, + async_write=self.cfg.checkpoint.write_checkpoints_asynchronously, ) - logger.info(f"Finished saving checkpoint to {filename}") + logger.info(f"Finished saving checkpoint to {filename}") def load_checkpoint( self, diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py index 3278de6b9f..0f28222633 100644 --- a/tests/test_checkpoint_utils.py +++ b/tests/test_checkpoint_utils.py @@ -90,15 +90,14 @@ def test_prune_state_dict(self): self.assertEqual(len(ensemble[0].decoder.layers), 1) def test_torch_persistent_save_async(self): - cfg = OmegaConf.create() - cfg.dataset = OmegaConf.create() - cfg.dataset.write_checkpoints_asynchronously = True state_dict = {} filename = "async_checkpoint.pt" with patch(f"{checkpoint_utils.__name__}.PathManager.opena") as mock_opena: with patch(f"{checkpoint_utils.__name__}._torch_persistent_save") as mock_save: - checkpoint_utils.torch_persistent_save(cfg.dataset, state_dict, filename) + checkpoint_utils.torch_persistent_save( + state_dict, filename, async_write=True + ) mock_opena.assert_called_with(filename, "wb") mock_save.assert_called() diff --git a/tests/test_train.py b/tests/test_train.py index 57daa194b2..65f4683bc6 100644 --- a/tests/test_train.py +++ b/tests/test_train.py @@ -68,6 +68,7 @@ def get_mock_cfg(finetune_from_model): "reset_lr_scheduler": False, "finetune_from_model": finetune_from_model, "model_parallel_size": 1, + "restore_file": "checkpoint_last.pt", }, "common": { "model_parallel_size": 1, From 656d7e5779a9ec4ccf0ad45d86a4ce589c597588 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Thu, 4 Mar 2021 13:31:02 -0800 Subject: [PATCH 264/774] Add support for FullyShardedDataParallel (--ddp-backend=fully_sharded) (#1667) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1667 Add support for FullyShardedDataParallel (--ddp-backend=fully_sharded) This enables fully parameter + optimizer state sharding by using FullyShardedDataParallel (FSDP) from fairscale. The user just needs to provide `--ddp-backend=fully_sharded` to enable. Other common options work out-of-the-box (e.g., `--fp16`, `--memory-efficient-fp16`, `--update-freq`, etc.). This should be a drop-in replacement for the "c10d" backend. This yields pretty big speedups for small models and enables training ~13B parameter models on 8 GPUs and 175B parameter models on 128 GPUs, without model parallelism. This also adds a new option `--cpu-offload` that offloads the optimizer state and FP32 model copy to CPU, which is particularly useful when combined with `--optimizer=cpu_adam`. Note: after enabling this, each GPU will save a checkpoint file, since the optimizer state is sharded. Each checkpoint will contain a single shard of the optimizer state and the rank 0 checkpoint will contain the full model weights. Note: a known limitation of the current implementation is that you cannot resume training on a different world_size. This constraint will be relaxed in future iterations. Test Plan: Imported from OSS Reviewed By: sshleifer Differential Revision: D26771144 Pulled By: myleott fbshipit-source-id: 74c2f46f57719e24e2dcfc9d9ee7c2fc0aeedb46 --- fairseq/dataclass/configs.py | 15 +++ fairseq/dataclass/constants.py | 1 + fairseq/distributed/__init__.py | 4 + .../fully_sharded_data_parallel.py | 122 ++++++++++++++++++ fairseq/models/distributed_fairseq_model.py | 21 ++- fairseq/models/fairseq_model.py | 20 ++- fairseq/models/transformer.py | 6 + fairseq/optim/cpu_adam.py | 4 + fairseq/optim/fp16_optimizer.py | 14 +- fairseq/trainer.py | 84 ++++++++++-- fairseq_cli/train.py | 15 ++- tests/test_binaries.py | 10 +- tests/test_dataset.py | 7 + 13 files changed, 292 insertions(+), 31 deletions(-) create mode 100644 fairseq/distributed/fully_sharded_data_parallel.py diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 4d3c60bfd6..5d6aee157a 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -355,7 +355,22 @@ class DistributedTrainingConfig(FairseqDataclass): zero_sharding: ZERO_SHARDING_CHOICES = field( default="none", metadata={"help": "ZeRO sharding"} ) + fp16: bool = II("common.fp16") + memory_efficient_fp16: bool = II("common.memory_efficient_fp16") tpu: bool = II("common.tpu") + # configuration for --ddp-backend=fully_sharded + no_reshard_after_forward: bool = field( + default=False, + metadata={"help": "don't reshard parameters after forward pass"}, + ) + fp32_reduce_scatter: bool = field( + default=False, + metadata={"help": "reduce-scatter grads in FP32"}, + ) + cpu_offload: bool = field( + default=False, + metadata={"help": "offload FP32 params to CPU"} + ) @dataclass diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 93bc6d03cb..faba0862fa 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -37,6 +37,7 @@ def ChoiceEnum(choices: List[str]): LOG_FORMAT_CHOICES = ChoiceEnum(["json", "none", "simple", "tqdm"]) DDP_BACKEND_CHOICES = ChoiceEnum([ "c10d", # alias for pytorch_ddp + "fully_sharded", # FullyShardedDataParallel from fairscale "legacy_ddp", "no_c10d", # alias for legacy_ddp "pytorch_ddp", diff --git a/fairseq/distributed/__init__.py b/fairseq/distributed/__init__.py index 7f4016e38c..d0b96b734c 100644 --- a/fairseq/distributed/__init__.py +++ b/fairseq/distributed/__init__.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. from .distributed_timeout_wrapper import DistributedTimeoutWrapper +from .fully_sharded_data_parallel import fsdp_enable_wrap, fsdp_wrap, FullyShardedDataParallel from .legacy_distributed_data_parallel import LegacyDistributedDataParallel from .module_proxy_wrapper import ModuleProxyWrapper from .tpu_distributed_data_parallel import TPUDistributedDataParallel @@ -11,6 +12,9 @@ __all__ = [ "DistributedTimeoutWrapper", + "fsdp_enable_wrap", + "fsdp_wrap", + "FullyShardedDataParallel", "LegacyDistributedDataParallel", "ModuleProxyWrapper", "TPUDistributedDataParallel", diff --git a/fairseq/distributed/fully_sharded_data_parallel.py b/fairseq/distributed/fully_sharded_data_parallel.py new file mode 100644 index 0000000000..9d74398325 --- /dev/null +++ b/fairseq/distributed/fully_sharded_data_parallel.py @@ -0,0 +1,122 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import contextlib +from typing import Optional + +import torch + +from fairseq.dataclass.configs import DistributedTrainingConfig +from fairseq.distributed import utils as dist_utils + + +try: + from fairscale.nn.data_parallel import FullyShardedDataParallel as FSDP + has_FSDP = True +except ImportError: + FSDP = torch.nn.Module + has_FSDP = False + + +class FullyShardedDataParallel(FSDP): + """ + A small wrapper around fairscale's FullyShardedDataParallel (FSDP) with some + fairseq-specific checkpoint saving/loading logic. + + Args: + use_sharded_state (bool): if True, then ``state_dict`` will return + ``FSDP.local_state_dict`` and ``load_state_dict`` will call + ``FSDP.load_local_state_dict``. Otherwise, ``state_dict`` will + return the full model weights on data parallel rank 0 (empty on + other ranks) and ``load_state_dict`` will broadcast model weights + from rank 0 to other ranks. + """ + + def __init__(self, *args, use_sharded_state: bool = False, **kwargs): + if not has_FSDP: + raise ImportError( + "Cannot find FullyShardedDataParallel. " + "Please install fairscale with: pip install fairscale" + ) + super().__init__(*args, **kwargs) + self.use_sharded_state = use_sharded_state + + def state_dict(self, destination=None, prefix='', keep_vars=False): + if self.use_sharded_state: + return super().local_state_dict( + destination=destination, prefix=prefix, keep_vars=keep_vars + ) + else: + if self.rank == 0: + return super().state_dict( + destination=destination, prefix=prefix, keep_vars=keep_vars + ) + else: + # We must call state_dict() due to use of communication + # primitives. But we don't use the result. + super().state_dict() + return destination or {} + + def load_state_dict(self, state_dict, strict=True, model_cfg=None): + if self.use_sharded_state: + return super().load_local_state_dict(state_dict, strict=strict) + else: + state_dict = dist_utils.broadcast_object( + state_dict, src_rank=0, group=self.process_group + ) + return super().load_state_dict(state_dict, strict=strict) + + +@contextlib.contextmanager +def fsdp_enable_wrap(cfg: DistributedTrainingConfig, use_sharded_state: bool = False): + try: + from fairscale.nn import enable_wrap + except ImportError: + raise ImportError( + "Cannot find FullyShardedDataParallel. " + "Please install fairscale with: pip install fairscale" + ) + if cfg.memory_efficient_fp16: + assert cfg.fp16 # memory_efficient_fp16 should imply fp16 + group = dist_utils.get_data_parallel_group() + if group is None and cfg.distributed_world_size == 1: + from fairscale.utils.testing import DummyProcessGroup + group = DummyProcessGroup(rank=0, size=1) + fsdp_config = { + "process_group": group, + "reshard_after_forward": not cfg.no_reshard_after_forward, + "mixed_precision": cfg.fp16 and not cfg.memory_efficient_fp16, + "fp32_reduce_scatter": cfg.fp32_reduce_scatter, + "flatten_parameters": True, + "cpu_offload": cfg.cpu_offload, + "compute_dtype": torch.float16 if cfg.fp16 else torch.float32, + "bucket_cap_mb": cfg.bucket_cap_mb, + } + with enable_wrap(use_sharded_state=use_sharded_state, **fsdp_config): + yield + + +def fsdp_wrap(module, min_num_params: Optional[int] = None, **kwargs): + """ + Helper to wrap layers/modules in FSDP. This falls back to a no-op if + fairscale is not available. + + Args: + module (nn.Module): module to (maybe) wrap + min_num_params (int, Optional): minimum number of layer params to wrap + """ + try: + from fairscale.nn import wrap + cls = FullyShardedDataParallel + if min_num_params is not None: + num_params = sum(p.numel() for p in module.parameters()) + if num_params >= min_num_params: + return wrap(module, cls=cls, **kwargs) + else: + return module + else: + return wrap(module, cls=cls, **kwargs) + except ImportError: + return module diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index ca157f06e9..3422faea74 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -105,12 +105,27 @@ def DistributedFairseqModel(args, model, process_group, device): ) # forward missing getattr and state_dict/load_state_dict to orig model wrapped_model = ModuleProxyWrapper(wrapped_model) + elif args.ddp_backend == "fully_sharded": + try: + from fairscale.nn.data_parallel import FullyShardedDataParallel as FSDP + except ImportError: + raise ImportError( + "Cannot find FullyShardedDataParallel. " + "Please install fairscale with: pip install fairscale" + ) + assert isinstance(model, FSDP), "expected model to already be wrapped in FSDP" + wrapped_model = model + if args.memory_efficient_fp16: + wrapped_model = wrapped_model.half() + if not args.cpu_offload: + wrapped_model = wrapped_model.to(device=device) else: raise ValueError("Unknown --ddp-backend: " + args.ddp_backend) # kill hung distributed jobs after a timeout - wrapped_model = DistributedTimeoutWrapper( - wrapped_model, timeout=getattr(args, "heartbeat_timeout", -1) - ) + if getattr(args, "heartbeat_timeout", -1) > 0: + wrapped_model = DistributedTimeoutWrapper( + wrapped_model, timeout=getattr(args, "heartbeat_timeout", -1) + ) return wrapped_model diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 186f3d2464..d393c02ae6 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -27,6 +27,13 @@ logger = logging.getLogger(__name__) +def check_type(module, expected_type): + if hasattr(module, "unwrapped_module"): + assert isinstance(module.unwrapped_module, expected_type) + else: + assert isinstance(module, expected_type) + + class BaseFairseqModel(nn.Module): """Base class for fairseq models.""" @@ -284,8 +291,9 @@ def __init__(self, encoder, decoder): self.encoder = encoder self.decoder = decoder - assert isinstance(self.encoder, FairseqEncoder) - assert isinstance(self.decoder, FairseqDecoder) + + check_type(self.encoder, FairseqEncoder) + check_type(self.decoder, FairseqDecoder) def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): """ @@ -365,8 +373,8 @@ def __init__(self, encoders, decoders): assert encoders.keys() == decoders.keys() self.keys = list(encoders.keys()) for key in self.keys: - assert isinstance(encoders[key], FairseqEncoder) - assert isinstance(decoders[key], FairseqDecoder) + check_type(encoders[key], FairseqEncoder) + check_type(decoders[key], FairseqDecoder) self.models = nn.ModuleDict( { @@ -469,7 +477,7 @@ class FairseqLanguageModel(BaseFairseqModel): def __init__(self, decoder): super().__init__() self.decoder = decoder - assert isinstance(self.decoder, FairseqDecoder) + check_type(self.decoder, FairseqDecoder) def forward(self, src_tokens, **kwargs): """ @@ -530,7 +538,7 @@ class FairseqEncoderModel(BaseFairseqModel): def __init__(self, encoder): super().__init__() self.encoder = encoder - assert isinstance(self.encoder, FairseqEncoder) + check_type(self.encoder, FairseqEncoder) def forward(self, src_tokens, src_lengths, **kwargs): """ diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index f2f36baf3e..a0a0b8dcd5 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -9,6 +9,7 @@ import torch import torch.nn as nn from fairseq import utils +from fairseq.distributed import fsdp_wrap from fairseq.models import ( FairseqEncoder, FairseqEncoderDecoderModel, @@ -240,6 +241,9 @@ def build_model(cls, args, task): args.checkpoint_activations = True # offloading implies checkpointing encoder = cls.build_encoder(args, src_dict, encoder_embed_tokens) decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens) + if not args.share_all_embeddings: + encoder = fsdp_wrap(encoder, min_num_params=1e8) + decoder = fsdp_wrap(decoder, min_num_params=1e8) return cls(args, encoder, decoder) @classmethod @@ -386,6 +390,7 @@ def build_encoder_layer(self, args): if getattr(args, "checkpoint_activations", False): offload_to_cpu = getattr(args, "offload_activations", False) layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + layer = fsdp_wrap(layer, min_num_params=1e8) return layer def forward_embedding( @@ -726,6 +731,7 @@ def build_decoder_layer(self, args, no_encoder_attn=False): if getattr(args, "checkpoint_activations", False): offload_to_cpu = getattr(args, "offload_activations", False) layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + layer = fsdp_wrap(layer, min_num_params=1e8) return layer def forward( diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py index fad5a64ecb..5e935df1a5 100644 --- a/fairseq/optim/cpu_adam.py +++ b/fairseq/optim/cpu_adam.py @@ -107,6 +107,10 @@ def __init__( self.opt_id, lr, betas[0], betas[1], eps, weight_decay, adamw_mode ) + @property + def supports_flat_params(self): + return True + @torch.no_grad() def step(self, closure=None): loss = None diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index e0b069f172..00ea1bbb76 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -322,6 +322,10 @@ def set_lr(self, lr): def all_reduce_grads(self, module): self.fp32_optimizer.all_reduce_grads(module) + @property + def supports_flat_params(self): + return self.fp32_optimizer.supports_flat_params + class _MemoryEfficientFP16OptimizerMixin(object): def __init__(self, *args, **kwargs): @@ -442,6 +446,10 @@ def zero_grad(self): else: self._multiply_factor = 1.0 + @property + def supports_flat_params(self): + return self.wrapped_optimizer.supports_flat_params + class MemoryEfficientFP16Optimizer( _MemoryEfficientFP16OptimizerMixin, optim.FairseqOptimizer @@ -461,8 +469,10 @@ class MemoryEfficientFP16Optimizer( *supports_memory_efficient_fp16* property. """ - def __init__(self, cfg: DictConfig, params, optimizer, **kwargs): - if not optimizer.supports_memory_efficient_fp16: + def __init__( + self, cfg: DictConfig, params, optimizer, allow_unsupported=False, **kwargs + ): + if not allow_unsupported and not optimizer.supports_memory_efficient_fp16: raise ValueError( "Unsupported optimizer: {}".format(optimizer.__class__.__name__) ) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 45d9591d7c..4d47d39897 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -63,15 +63,31 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): else: self.device = torch.device("cpu") + if self.cfg.distributed_training.ddp_backend == "fully_sharded": + if self.cfg.common.bf16: + raise ValueError( + "FullyShardedDataParallel is not compatible with --bf16 or " + "--memory-efficient-bf16" + ) + if self.cfg.distributed_training.zero_sharding != "none": + raise ValueError( + "FullyShardedDataParallel is not compatible with --zero-sharding " + "option (it's already built in)" + ) + else: + if self.cfg.distributed_training.cpu_offload: + raise ValueError("--cpu-offload requires --ddp-backend=fully_sharded") + # copy model and criterion to current device/dtype self._criterion = criterion self._model = model - if cfg.common.fp16: - self._criterion = self._criterion.half() - self._model = self._model.half() - elif cfg.common.bf16: - self._criterion = self._criterion.to(dtype=torch.bfloat16) - self._model = self._model.to(dtype=torch.bfloat16) + if cfg.distributed_training.ddp_backend != "fully_sharded": + if cfg.common.fp16: + self._criterion = self._criterion.half() + self._model = self._model.half() + elif cfg.common.bf16: + self._criterion = self._criterion.to(dtype=torch.bfloat16) + self._model = self._model.to(dtype=torch.bfloat16) if ( not cfg.distributed_training.pipeline_model_parallel # the DistributedFairseqModel wrapper will handle moving to device, @@ -171,17 +187,26 @@ def use_distributed_wrapper(self) -> bool: return ( self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf + ) or ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and self.cfg.distributed_training.cpu_offload ) @property def should_save_checkpoint_on_current_rank(self) -> bool: """Indicates whether to save checkpoints on the current DDP rank.""" - return self.is_data_parallel_master + if self.cfg.distributed_training.ddp_backend == "fully_sharded": + return True + else: + return self.is_data_parallel_master @property def checkpoint_suffix(self) -> str: """Suffix to add to the checkpoint file name.""" - return self.cfg.checkpoint.checkpoint_suffix or "" + if self.cfg.distributed_training.ddp_backend == "fully_sharded": + return self.cfg.checkpoint.checkpoint_suffix + "-shard{0}".format(self.data_parallel_rank) + else: + return self.cfg.checkpoint.checkpoint_suffix or "" @property def criterion(self): @@ -234,7 +259,20 @@ def _build_optimizer(self): ) ) - if self.cfg.common.fp16 or self.cfg.common.bf16: + if ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and self.cfg.common.fp16 + ): + # FullyShardedDataParallel always uses MemoryEfficientFP16 wrapper, + # mostly for the grad scaling. But if we don't have the + # --memory-efficient-fp16 flag set, then we're effectively doing + # regular --fp16 and can allow the use of optimizers that would + # otherwise be unsupported by MemoryEfficientFP16Optimizer. + allow_unsupported = not self.cfg.common.memory_efficient_fp16 + self._optimizer = optim.MemoryEfficientFP16Optimizer.build_optimizer( + self.cfg, params, allow_unsupported=allow_unsupported + ) + elif self.cfg.common.fp16 or self.cfg.common.bf16: if self.cuda and torch.cuda.get_device_capability(0)[0] < 7: logger.info( "NOTE: your device does NOT support faster training with --fp16, " @@ -254,6 +292,16 @@ def _build_optimizer(self): logger.info("NOTE: your device may support faster training with --fp16") self._optimizer = optim.build_optimizer(self.cfg.optimizer, params) + if self.cfg.distributed_training.ddp_backend == "fully_sharded": + assert not self.cfg.optimization.use_bmuf, \ + "--ddp-backend=fully_sharded is not compatible with BMUF" + assert self._optimizer.supports_flat_params, ( + "--ddp-backend=fully_sharded is only compatible with pointwise " + "optimizers (e.g., Adam, AdamW, Adadelta, Adamax, SGD, etc.). " + "However, the sharding will result in slightly different results when " + "using non-pointwise optimizers (e.g., Adagrad, Adafactor, LAMB)" + ) + if self.cfg.optimization.use_bmuf: self._optimizer = optim.FairseqBMUF( self.cfg.bmuf, @@ -355,6 +403,8 @@ def load_checkpoint( # TPUs don't support broadcast yet, so load checkpoints # on every worker for now or self.tpu + # FSDP requires loading checkpoint shards on all ranks + or self.cfg.distributed_training.ddp_backend == "fully_sharded" ) if load_on_all_ranks or self.data_parallel_rank == 0: @@ -965,7 +1015,21 @@ def set_num_updates(self, num_updates): metrics.log_scalar("num_updates", self._num_updates, weight=0, priority=200) def clip_grad_norm(self, clip_norm): - return self.optimizer.clip_grad_norm(clip_norm, aggregate_norm_fn=None) + + def agg_norm_fn(total_norm): + if self.cfg.distributed_training.ddp_backend == "fully_sharded": + total_norm = total_norm ** 2 + if ( + self.data_parallel_process_group is not None + or torch.distributed.is_initialized() + ): + total_norm = distributed_utils.all_reduce( + total_norm.cuda(), group=self.data_parallel_process_group + ) + total_norm = total_norm ** 0.5 + return total_norm + + return self.optimizer.clip_grad_norm(clip_norm, aggregate_norm_fn=agg_norm_fn) def cumulative_training_time(self): if self._cumulative_training_time is None: diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 80ad57acd1..d770e4e4ec 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -18,7 +18,6 @@ import torch from fairseq import ( checkpoint_utils, - distributed_utils, options, quantization_utils, tasks, @@ -27,7 +26,7 @@ from fairseq.data import iterators from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf -from fairseq.distributed_utils import is_master +from fairseq.distributed import fsdp_enable_wrap, fsdp_wrap, utils as distributed_utils from fairseq.file_io import PathManager from fairseq.logging import meters, metrics, progress_bar from fairseq.model_parallel.megatron_trainer import MegatronTrainer @@ -50,7 +49,7 @@ def main(cfg: FairseqConfig) -> None: utils.import_user_module(cfg.common) - if is_master(cfg.distributed_training) and "job_logging_cfg" in cfg: + if distributed_utils.is_master(cfg.distributed_training) and "job_logging_cfg" in cfg: # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) logging.config.dictConfig(OmegaConf.to_container(cfg.job_logging_cfg)) @@ -87,7 +86,11 @@ def main(cfg: FairseqConfig) -> None: assert cfg.criterion, "Please specify criterion to train a model" # Build model and criterion - model = task.build_model(cfg.model) + if cfg.distributed_training.ddp_backend == "fully_sharded": + with fsdp_enable_wrap(cfg.distributed_training): + model = fsdp_wrap(task.build_model(cfg.model)) + else: + model = task.build_model(cfg.model) criterion = task.build_criterion(cfg.criterion) logger.info(model) logger.info("task: {}".format(task.__class__.__name__)) @@ -95,8 +98,8 @@ def main(cfg: FairseqConfig) -> None: logger.info("criterion: {}".format(criterion.__class__.__name__)) logger.info( "num. model params: {:,} (num. trained: {:,})".format( - sum(p.numel() for p in model.parameters()), - sum(p.numel() for p in model.parameters() if p.requires_grad), + sum(getattr(p, "_orig_size", p).numel() for p in model.parameters()), + sum(getattr(p, "_orig_size", p).numel() for p in model.parameters() if p.requires_grad), ) ) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 3cb98897bf..e10cc767b8 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -1697,8 +1697,9 @@ def test_activation_offloading_does_not_change_metrics(self): """Neither ----checkpoint-activations nor --offload-activations should change loss""" with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: - create_dummy_data(data_dir, num_examples=20) - preprocess_translation_data(data_dir) + with self.assertLogs(): + create_dummy_data(data_dir, num_examples=20) + preprocess_translation_data(data_dir) offload_logs = self._train(data_dir, ["--offload-activations"]) baseline_logs = self._train(data_dir, []) @@ -1720,8 +1721,9 @@ def test_activation_checkpointing_does_not_change_metrics(self): """--checkpoint-activations should not change loss""" with tempfile.TemporaryDirectory("test_transformer_with_act_cpt") as data_dir: - create_dummy_data(data_dir, num_examples=20) - preprocess_translation_data(data_dir) + with self.assertLogs(): + create_dummy_data(data_dir, num_examples=20) + preprocess_translation_data(data_dir) ckpt_logs = self._train(data_dir, ["--checkpoint-activations"]) baseline_logs = self._train(data_dir, []) assert len(baseline_logs) == len(ckpt_logs) diff --git a/tests/test_dataset.py b/tests/test_dataset.py index 9fb69a5f77..a3e3970028 100644 --- a/tests/test_dataset.py +++ b/tests/test_dataset.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import logging import unittest from typing import Sequence @@ -20,6 +21,12 @@ def sample(id: int, length: int): class TestDataset(unittest.TestCase): + def setUp(self): + logging.disable(logging.CRITICAL) + + def tearDown(self): + logging.disable(logging.NOTSET) + def test_round_robin_zip_datasets(self): long_dataset = lang_pair_dataset([10, 9, 8, 11]) short_dataset = lang_pair_dataset([11, 9]) From 73886ac228f8f0368871237f7498ec8b07444322 Mon Sep 17 00:00:00 2001 From: Ning Dong <dnn@fb.com> Date: Thu, 4 Mar 2021 14:20:00 -0800 Subject: [PATCH 265/774] Refactor FairseqSimulSTAgent Summary: 1. In fblearner flow we are dumping cmvn stats into json file (e.g. f253830726) Previously there's only --config option taking .npz path from a yaml file, and it's the only usage for the config. This diff adds an option --global-stats to import from json. 2. Inherit FairseqSimulSTAgent from nn.Module instead of SpeechAgent whose root class is object to prepare for scripting methods. Copy over / simplify all the necessary methods from SpeechAgent/Agent. Reviewed By: jmp84 Differential Revision: D26800957 fbshipit-source-id: 74be527f8473c13405a60bb16ce6da5a7dc0b888 --- .../agents/fairseq_simul_st_agent.py | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index f944203785..2b5fdc2d3f 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -1,19 +1,20 @@ import math import os - +import json import numpy as np import torch import torchaudio.compliance.kaldi as kaldi import yaml from fairseq import checkpoint_utils, tasks +from fairseq.file_io import PathManager try: from simuleval import READ_ACTION, WRITE_ACTION, DEFAULT_EOS - from simuleval.agents import SpeechAgent - from simuleval.states import ListEntry + from simuleval.states import ListEntry, SpeechStates except ImportError: print("Please install simuleval 'pip install simuleval'") +from torch import nn SHIFT_SIZE = 10 WINDOW_SIZE = 25 @@ -112,12 +113,12 @@ def info(self): } -class FairseqSimulSTAgent(SpeechAgent): +class FairseqSimulSTAgent(nn.Module): speech_segment_size = 40 # in ms, 4 pooling ratio * 10 ms step size def __init__(self, args): - super().__init__(args) + super().__init__() self.eos = DEFAULT_EOS @@ -136,13 +137,18 @@ def __init__(self, args): self.model.decoder.layers[0].encoder_attn.pre_decision_ratio ) - with open(args.config, "r") as f: - config = yaml.load(f, Loader=yaml.BaseLoader) + args.global_cmvn = None + if args.config: + with open(args.config, "r") as f: + config = yaml.load(f, Loader=yaml.BaseLoader) - if "global_cmvn" in config: - args.global_cmvn = np.load(config["global_cmvn"]["stats_npz_path"]) - else: - args.global_cmvn = None + if "global_cmvn" in config: + args.global_cmvn = np.load(config["global_cmvn"]["stats_npz_path"]) + + if args.global_stats: + with PathManager.open(args.global_stats, "r") as f: + global_cmvn = json.loads(f.read()) + self.global_cmvn = {"mean": global_cmvn["mean"], "std": global_cmvn["stddev"]} self.feature_extractor = OnlineFeatureExtractor(args) @@ -152,6 +158,13 @@ def __init__(self, args): torch.set_grad_enabled(False) + def build_states(self, args, client, sentence_id): + # Initialize states here, for example add customized entry to states + # This function will be called at beginning of every new sentence + states = SpeechStates(args, client, sentence_id, self) + self.initialize_states(states) + return states + def to_device(self, tensor): if self.gpu: return tensor.cuda() @@ -165,8 +178,10 @@ def add_args(parser): help='path to your pretrained model.') parser.add_argument("--data-bin", type=str, required=True, help="Path of data binary") - parser.add_argument("--config", type=str, required=True, + parser.add_argument("--config", type=str, default=None, help="Path to config yaml file") + parser.add_argument("--global-stats", type=str, default=None, + help="Path to json file containing cmvn stats") parser.add_argument("--tgt-splitter-type", type=str, default="SentencePiece", help="Subword splitter type for target text") parser.add_argument("--tgt-splitter-path", type=str, default=None, From 7c95746a7e5e4a087399d186590815e45ae775c8 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 4 Mar 2021 17:17:11 -0800 Subject: [PATCH 266/774] fix bug on converting stereo audio in audio_utils.py Summary: Fix bug on converting stereo audio in audio_utils.py - Github issue: https://github.com/pytorch/fairseq/issues/3303 Reviewed By: jmp84 Differential Revision: D26825964 fbshipit-source-id: 26905e71540bc52e98d76996b199ac0fbe78357b --- fairseq/data/audio/audio_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index f0e75b1d65..f8cc80f5e2 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -63,8 +63,8 @@ def _get_torchaudio_fbank(waveform, sample_rate, n_bins=80) -> Optional[np.ndarr # Mono channel: D -> 1 x D waveform = waveform.unsqueeze(0) else: - # Merge multiple channels to one: C x D -> 1 x D - waveform, _ = ta_sox.apply_effects_tensor(waveform, sample_rate, ['channels', '1']) + # Merge multiple channels to one: D x C -> 1 x D + waveform, _ = ta_sox.apply_effects_tensor(waveform.T, sample_rate, [['channels', '1']]) features = ta_kaldi.fbank( waveform, num_mel_bins=n_bins, sample_frequency=sample_rate From 16c1a200f87a2adb6395e353345c19bbe990d1dd Mon Sep 17 00:00:00 2001 From: sarapapi <57095209+sarapapi@users.noreply.github.com> Date: Mon, 8 Mar 2021 14:10:29 -0800 Subject: [PATCH 267/774] Fix Global CMVN path of MustC data preprocessing (#3307) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fix a typo in gcmv_path given for config yaml generation (actual: gcvmn_cvmn_path, correct: gcmvn_path) ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3307 Reviewed By: jmp84 Differential Revision: D26826231 Pulled By: kahne fbshipit-source-id: 6b60f2a8a8b4ba1c0c088299a08ef04fdfe870a8 --- examples/speech_to_text/prep_mustc_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_to_text/prep_mustc_data.py b/examples/speech_to_text/prep_mustc_data.py index 4e410bcb18..45fd43533d 100644 --- a/examples/speech_to_text/prep_mustc_data.py +++ b/examples/speech_to_text/prep_mustc_data.py @@ -179,7 +179,7 @@ def process(args): yaml_filename=f"config_{args.task}.yaml", specaugment_policy="lb", cmvn_type=args.cmvn_type, - gcmvn_cmvn_path=( + gcmvn_path=( cur_root / "gcmvn.npz" if args.cmvn_type == "global" else None ), From 00d5b7adbeaf64e02c53a591d637efe4c8cad923 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Tue, 9 Mar 2021 06:28:23 -0800 Subject: [PATCH 268/774] Add README/tutorial for Fully Sharded Data Parallel (#3327) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3327 Reviewed By: sshleifer Differential Revision: D26899416 Pulled By: myleott fbshipit-source-id: bbb493a5c4e0a51f3b26fe8f94e3962b6206d6f6 --- .github/workflows/build.yml | 3 +- README.md | 11 +- .../fully_sharded_data_parallel/README.md | 164 ++++++++++++++++++ .../fully_sharded_data_parallel.py | 18 +- fairseq/models/fairseq_model.py | 5 +- fairseq/models/roberta/model.py | 26 ++- fairseq/models/transformer.py | 40 ++++- fairseq/models/transformer_lm.py | 121 +++++++++++-- fairseq/trainer.py | 16 +- 9 files changed, 363 insertions(+), 41 deletions(-) create mode 100644 examples/fully_sharded_data_parallel/README.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0af8bad95d..105c42a503 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,7 +39,8 @@ jobs: - name: Install optional test requirements run: | - python -m pip install fairscale iopath transformers pyarrow + python -m pip install iopath transformers pyarrow + python -m pip install git+https://github.com/facebookresearch/fairscale.git@master - name: Lint with flake8 run: | diff --git a/README.md b/README.md index 5fedac7eec..839dd8e1de 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ We provide reference implementations of various sequence modeling papers: ### What's New: +* March 2021 [Added full parameter and optimizer state sharding + CPU offloading](examples/fully_sharded_data_parallel/README.md) +* February 2021 [Added LASER training code](examples/laser/README.md) +* December 2020: [Added Adaptive Attention Span code](examples/adaptive_span/README.md) * December 2020: [GottBERT model and code released](examples/gottbert/README.md) * November 2020: Adopted the [Hydra](https://github.com/facebookresearch/hydra) configuration framework * [see documentation explaining how to use it for new and existing projects](docs/hydra_integration.md) @@ -68,14 +71,14 @@ We provide reference implementations of various sequence modeling papers: * October 2020: [Added R3F/R4F (Better Fine-Tuning) code](examples/rxf/README.md) * October 2020: [Deep Transformer with Latent Depth code released](examples/latent_depth/README.md) * October 2020: [Added CRISS models and code](examples/criss/README.md) + +<details><summary>Previous updates</summary><p> + * September 2020: [Added Linformer code](examples/linformer/README.md) * September 2020: [Added pointer-generator networks](examples/pointer_generator/README.md) * August 2020: [Added lexically constrained decoding](examples/constrained_decoding/README.md) * August 2020: [wav2vec2 models and code released](examples/wav2vec/README.md) * July 2020: [Unsupervised Quality Estimation code released](examples/unsupervised_quality_estimation/README.md) - -<details><summary>Previous updates</summary><p> - * May 2020: [Follow fairseq on Twitter](https://twitter.com/fairseq) * April 2020: [Monotonic Multihead Attention code released](examples/simultaneous_translation/README.md) * April 2020: [Quant-Noise code released](examples/quant_noise/README.md) @@ -108,6 +111,8 @@ We provide reference implementations of various sequence modeling papers: * [mixed precision training](https://fairseq.readthedocs.io/en/latest/getting_started.html#training-with-half-precision-floating-point-fp16) (trains faster with less GPU memory on [NVIDIA tensor cores](https://developer.nvidia.com/tensor-cores)) * [extensible](https://fairseq.readthedocs.io/en/latest/overview.html): easily register new models, criterions, tasks, optimizers and learning rate schedulers * [flexible configuration](docs/hydra_integration.md) based on [Hydra](https://github.com/facebookresearch/hydra) allowing a combination of code, command-line and file based configuration +* [full parameter and optimizer state sharding](examples/fully_sharded_data_parallel/README.md) +* [offloading parameters to CPU](examples/fully_sharded_data_parallel/README.md) We also provide [pre-trained models for translation and language modeling](#pre-trained-models-and-examples) with a convenient `torch.hub` interface: diff --git a/examples/fully_sharded_data_parallel/README.md b/examples/fully_sharded_data_parallel/README.md new file mode 100644 index 0000000000..bc98670968 --- /dev/null +++ b/examples/fully_sharded_data_parallel/README.md @@ -0,0 +1,164 @@ +# Fully Sharded Data Parallel (FSDP) + +## Overview +Recent work by [Microsoft](https://arxiv.org/abs/1910.02054) and +[Google](https://arxiv.org/abs/2004.13336) has shown that data parallel +training can be made significantly more efficient by sharding the model +parameters and optimizer state across data parallel workers. These ideas are +encapsulated in the new **`FullyShardedDataParallel` (FSDP)** wrapper provided +by [fairscale](https://github.com/facebookresearch/fairscale/). + +Compared to PyTorch DDP: +* FSDP produces identical results as PyTorch DDP (it's still synchronous data parallel training) +* FSDP shards parameters (FP16 + FP32) and optimizer state across data parallel GPUs +* FSDP is faster than PyTorch DDP because the optimizer step is sharded, and the communication can be overlapped with the forward pass +* FSDP enables training 13B parameter models on 8 GPUs and 175B parameter models on 128 GPUs + +FSDP is fully supported in fairseq via the following new arguments: +* `--ddp-backend=fully_sharded`: enables full sharding via FSDP +* `--cpu-offload`: offloads the optimizer state and FP32 model copy to CPU (combine with `--optimizer=cpu_adam`) +* `--no-reshard-after-forward`: increases training speed for some models and is similar to ZeRO stage 2 +* other popular options (`--fp16`, `--update-freq`, `--checkpoint-activations`, `--offload-activations`, etc.) continue to work as normal + +<details><summary>Limitations</summary><p> + +FSDP currently has several limitations compared to fairseq's default DDP backend (PyTorch DDP): +* while FSDP is full compatible with pointwise Optimizers (e.g., Adam, AdamW, Adadelta, Adamax, SGD, etc.), it is not currently compatible with non-pointwise Optimizers (e.g., Adagrad, Adafactor, LAMB, etc.) +* FSDP depends on flattening the parameters, so models that currently require `--fp16-no-flatten-grads` may not be supported + +See the [fairscale docs](https://fairscale.readthedocs.io/en/latest/api/nn/fsdp_tips.html) for a more detailed +explanation of these and other limitations. + +</p></details> + +<details><summary>How it works</summary><p> + +<img width="800" alt="Fully Sharded Data Parallel" src="https://user-images.githubusercontent.com/231798/110406775-c2de0000-8050-11eb-9718-fbfc4510a76a.png"> + +See the [fairscale docs](https://fairscale.readthedocs.io/en/latest/api/nn/fsdp_tips.html) for a more detailed +explanation of how FSDP works. + +</p></details> + +## Example usage + +The following examples illustrate how to train a very large language model with +13 billion parameters on 1 GPU by offloading parameters and optimizer states to +CPU, or on 8 GPUs by fully sharding the params and optimizer states across GPUs. + +These examples use the WikiText-103 dataset for demonstration purposes, but +in practice a much larger dataset will be needed to achieve good results. +Follow the [instructions here](https://github.com/pytorch/fairseq/blob/master/examples/roberta/README.pretraining.md#1-preprocess-the-data) +to preprocess the WikiText-103 dataset using the GPT-2/RoBERTa vocabulary. + +### 13B params on 1 V100 GPU (with CPU offloading) + +The following command trains a 13B parameter GPT-3 model on a single V100 GPU +using the `--cpu-offload` feature to offload parameters and optimizer states to +CPU. In this setting, the optimizer step (Adam) happens on CPU. We also use the +`--checkpoint-activations` feature (sometimes called [gradient checkpointing](https://pytorch.org/docs/stable/checkpoint.html)), +which further saves memory in exchange for a small increase in computation. + +Requirements: +- You'll need 32GB of GPU memory and 256GB of system memory. +- We use the CPU Adam optimizer from [DeepSpeed](https://github.com/microsoft/DeepSpeed), so you'll need to `pip install deepspeed` before running the command. + +Some notes: +- The command will take ~5 minutes to start training, during which time it will appear to be hung, since randomly initializing 13B weights can be slow. +- The `--cpu-offload` feature requires training in mixed precision (`--fp16`). +- Tune the `OMP_NUM_THREADS` env variable for best performance with CPU offloading. +- The example command below stops training after 10 steps (`--max-update 10`) and does not save checkpoints (`--no-save`). + +```bash +OMP_NUM_THREADS=20 CUDA_VISIBLE_DEVICES=0 \ + fairseq-train data-bin/wikitext-103-roberta-bpe-bin \ + --ddp-backend fully_sharded --fp16 --fp16-init-scale 4 \ + --cpu-offload --checkpoint-activations \ + --task language_modeling --tokens-per-sample 2048 --batch-size 8 \ + --arch transformer_lm_gpt3_13 \ + --optimizer cpu_adam --adam-betas "(0.9,0.98)" \ + --lr 0.0001 --lr-scheduler polynomial_decay --warmup-updates 5 --total-num-update 10 \ + --max-update 10 --no-save --log-format json --log-interval 1 + +# Example output: +# (...) +# 2021-03-08 12:29:51 | INFO | fairseq_cli.train | num. model params: 13,110,865,920 (num. trained: 13,110,865,920) +# (...) +# 2021-03-08 12:29:51 | INFO | fairseq_cli.train | training on 1 devices (GPUs/TPUs) +# 2021-03-08 12:29:51 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 +# (...) +# Adam Optimizer #0 is created with AVX2 arithmetic capability. +# Config: alpha=0.000100, betas=(0.900000, 0.980000), weight_decay=0.000000, adam_w=1 +# (...) +# 2021-03-08 12:31:36 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "16.475", "ppl": "91120.8", "wps": "0", "ups": "0", "wpb": "16384", "bsz": "8", "num_updates": "1", "lr": "2e-05", "gnorm": "20.751", "loss_scale": "4", "train_wall": "99", "gb_free": "9.3", "wall": "105"} +# 2021-03-08 12:32:33 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "16.446", "ppl": "89281.6", "wps": "288.7", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "2", "lr": "4e-05", "gnorm": "19.777", "loss_scale": "4", "train_wall": "57", "gb_free": "9.3", "wall": "161"} +# 2021-03-08 12:33:12 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 2.0 +# 2021-03-08 12:33:51 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 1.0 +# 2021-03-08 12:34:45 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "25.22", "ppl": "3.90691e+07", "wps": "123.4", "ups": "0.01", "wpb": "16384", "bsz": "8", "num_updates": "3", "lr": "6e-05", "gnorm": "131.281", "loss_scale": "1", "train_wall": "133", "gb_free": "9.3", "wall": "294"} +# 2021-03-08 12:35:43 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.079", "ppl": "276809", "wps": "285.5", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "4", "lr": "8e-05", "gnorm": "13.776", "loss_scale": "1", "train_wall": "57", "gb_free": "9.3", "wall": "351"} +# 2021-03-08 12:36:35 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "23.729", "ppl": "1.39088e+07", "wps": "316.7", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "5", "lr": "0.0001", "gnorm": "72.774", "loss_scale": "1", "train_wall": "52", "gb_free": "9.3", "wall": "403"} +# 2021-03-08 12:37:28 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "20.429", "ppl": "1.41203e+06", "wps": "307.6", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "6", "lr": "8e-05", "gnorm": "60.846", "loss_scale": "1", "train_wall": "53", "gb_free": "9.3", "wall": "456"} +# 2021-03-08 12:38:27 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.965", "ppl": "511684", "wps": "279.4", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "7", "lr": "6e-05", "gnorm": "22.687", "loss_scale": "1", "train_wall": "59", "gb_free": "9.3", "wall": "515"} +# 2021-03-08 12:39:18 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.345", "ppl": "332887", "wps": "319.1", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "8", "lr": "4e-05", "gnorm": "8.451", "loss_scale": "1", "train_wall": "51", "gb_free": "9.3", "wall": "566"} +# 2021-03-08 12:40:11 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "18.262", "ppl": "314336", "wps": "305.9", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "9", "lr": "2e-05", "gnorm": "6.457", "loss_scale": "1", "train_wall": "54", "gb_free": "9.3", "wall": "620"} +# 2021-03-08 12:41:04 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "17.556", "ppl": "192686", "wps": "311.8", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "10", "lr": "0", "gnorm": "5.796", "loss_scale": "1", "train_wall": "53", "gb_free": "9.3", "wall": "673"} +# 2021-03-08 12:41:04 | INFO | fairseq_cli.train | Stopping training due to num_updates: 10 >= max_update: 10 +# 2021-03-08 12:41:04 | INFO | fairseq_cli.train | begin validation on "valid" subset +# 2021-03-08 12:43:15 | INFO | valid | {"epoch": 1, "valid_loss": "17.953", "valid_ppl": "253807", "valid_wps": "1868.4", "valid_wpb": "15400.2", "valid_bsz": "7.6", "valid_num_updates": "10"} +# 2021-03-08 12:43:15 | INFO | fairseq_cli.train | end of epoch 1 (average epoch stats below) +# 2021-03-08 12:43:15 | INFO | train | {"epoch": 1, "train_loss": "19.351", "train_ppl": "668509", "train_wps": "210.9", "train_ups": "0.01", "train_wpb": "16384", "train_bsz": "8", "train_num_updates": "10", "train_lr": "0", "train_gnorm": "36.26", "train_loss_scale": "1", "train_train_wall": "667", "train_gb_free": "9.3", "train_wall": "804"} +# 2021-03-08 12:43:15 | INFO | fairseq_cli.train | done training in 798.6 seconds +``` + +### 13B params on 8 V100 GPUs (with full parameter + optimizer state sharding) + +FSDP can also shard the parameters and optimizer states across multiple GPUs, +reducing memory requirements significantly. On 8 GPUs, sharding enables +training the same 13B parameter model *without offloading the parameters to +CPU*. However, without CPU offloading we'd only be able to fit a batch size of +1 per GPU, which would cause training speed to suffer. + +We obtain the best performance on 8 GPUs by combining full sharding and CPU +offloading. The following command trains the same 13B parameter GPT-3 model as +before on 8 GPUs; training speed increases from ~310 -> ~3200 words per second. + +```bash +OMP_NUM_THREADS=20 CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ + fairseq-train data-bin/wikitext-103-roberta-bpe-bin \ + --ddp-backend fully_sharded --fp16 --fp16-init-scale 4 \ + --cpu-offload --checkpoint-activations \ + --task language_modeling --tokens-per-sample 2048 --batch-size 8 \ + --arch transformer_lm_gpt3_13 \ + --optimizer cpu_adam --adam-betas "(0.9,0.98)" \ + --lr 0.0001 --lr-scheduler polynomial_decay --warmup-updates 5 --total-num-update 10 \ + --max-update 10 --no-save --log-format json --log-interval 1 + +# Example output: +# (...) +# 2021-03-08 18:04:09 | INFO | fairseq_cli.train | num. model params: 13,110,865,920 (num. trained: 13,110,865,920) +# (...) +# 2021-03-08 18:04:09 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) +# 2021-03-08 18:04:09 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 +# (...) +# Adam Optimizer #0 is created with AVX2 arithmetic capability. +# Config: alpha=0.000100, betas=(0.900000, 0.980000), weight_decay=0.000000, adam_w=1 +# (...) +# 2021-03-08 18:05:06 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "16.408", "ppl": "86945.6", "wps": "0", "ups": "0", "wpb": "131072", "bsz": "64", "num_updates": "1", "lr": "2e-05", "gnorm": "18.27", "loss_scale": "4", "train_wall": "47", "gb_free": "9.3", "wall": "56"} +# 2021-03-08 18:05:45 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "16.352", "ppl": "83644.3", "wps": "3283.4", "ups": "0.03", "wpb": "131072", "bsz": "64", "num_updates": "2", "lr": "4e-05", "gnorm": "18.411", "loss_scale": "4", "train_wall": "40", "gb_free": "9.3", "wall": "96"} +# 2021-03-08 18:06:21 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 2.0 +# 2021-03-08 18:06:56 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 1.0 +# 2021-03-08 18:07:37 | INFO | train_inner | {"epoch": 1, "update": 0.006, "loss": "23.682", "ppl": "1.34537e+07", "wps": "1176.6", "ups": "0.01", "wpb": "131072", "bsz": "64", "num_updates": "3", "lr": "6e-05", "gnorm": "119.682", "loss_scale": "1", "train_wall": "111", "gb_free": "9.3", "wall": "208"} +# 2021-03-08 18:08:18 | INFO | train_inner | {"epoch": 1, "update": 0.007, "loss": "18.988", "ppl": "519921", "wps": "3189.1", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "4", "lr": "8e-05", "gnorm": "14.934", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "249"} +# 2021-03-08 18:08:59 | INFO | train_inner | {"epoch": 1, "update": 0.008, "loss": "20.08", "ppl": "1.10798e+06", "wps": "3223.1", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "5", "lr": "0.0001", "gnorm": "59.92", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "289"} +# 2021-03-08 18:09:39 | INFO | train_inner | {"epoch": 1, "update": 0.009, "loss": "18.323", "ppl": "327980", "wps": "3256.6", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "6", "lr": "8e-05", "gnorm": "37.425", "loss_scale": "1", "train_wall": "40", "gb_free": "9.3", "wall": "330"} +# 2021-03-08 18:10:20 | INFO | train_inner | {"epoch": 1, "update": 0.01, "loss": "17.264", "ppl": "157354", "wps": "3188.7", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "7", "lr": "6e-05", "gnorm": "10.824", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "371"} +# 2021-03-08 18:11:01 | INFO | train_inner | {"epoch": 1, "update": 0.011, "loss": "16.794", "ppl": "113647", "wps": "3230", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "8", "lr": "4e-05", "gnorm": "5.616", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "411"} +# 2021-03-08 18:11:39 | INFO | train_inner | {"epoch": 1, "update": 0.012, "loss": "16.706", "ppl": "106938", "wps": "3384", "ups": "0.03", "wpb": "131072", "bsz": "64", "num_updates": "9", "lr": "2e-05", "gnorm": "5.318", "loss_scale": "1", "train_wall": "39", "gb_free": "9.3", "wall": "450"} +# 2021-03-08 18:12:19 | INFO | train_inner | {"epoch": 1, "update": 0.013, "loss": "16.548", "ppl": "95796.2", "wps": "3274.4", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "10", "lr": "0", "gnorm": "5.22", "loss_scale": "1", "train_wall": "40", "gb_free": "9.3", "wall": "490"} +# 2021-03-08 18:12:19 | INFO | fairseq_cli.train | Stopping training due to num_updates: 10 >= max_update: 10 +# 2021-03-08 18:12:19 | INFO | fairseq_cli.train | begin validation on "valid" subset +# 2021-03-08 18:12:45 | INFO | valid | {"epoch": 1, "valid_loss": "16.624", "valid_ppl": "101000", "valid_wps": "10855.9", "valid_wpb": "123202", "valid_bsz": "60.5", "valid_num_updates": "10"} +# 2021-03-08 18:12:45 | INFO | fairseq_cli.train | end of epoch 1 (average epoch stats below) +# 2021-03-08 18:12:45 | INFO | train | {"epoch": 1, "train_loss": "18.114", "train_ppl": "283776", "train_wps": "2567.8", "train_ups": "0.02", "train_wpb": "131072", "train_bsz": "64", "train_num_updates": "10", "train_lr": "0", "train_gnorm": "29.562", "train_loss_scale": "1", "train_train_wall": "480", "train_gb_free": "9.3", "train_wall": "516"} +# 2021-03-08 18:12:45 | INFO | fairseq_cli.train | done training in 509.9 seconds +``` diff --git a/fairseq/distributed/fully_sharded_data_parallel.py b/fairseq/distributed/fully_sharded_data_parallel.py index 9d74398325..9c290b3fda 100644 --- a/fairseq/distributed/fully_sharded_data_parallel.py +++ b/fairseq/distributed/fully_sharded_data_parallel.py @@ -43,6 +43,13 @@ def __init__(self, *args, use_sharded_state: bool = False, **kwargs): super().__init__(*args, **kwargs) self.use_sharded_state = use_sharded_state + @property + def unwrapped_module(self) -> torch.nn.Module: + if self.flatten_parameters: + return self.module.module + else: + return self.module + def state_dict(self, destination=None, prefix='', keep_vars=False): if self.use_sharded_state: return super().local_state_dict( @@ -94,7 +101,11 @@ def fsdp_enable_wrap(cfg: DistributedTrainingConfig, use_sharded_state: bool = F "compute_dtype": torch.float16 if cfg.fp16 else torch.float32, "bucket_cap_mb": cfg.bucket_cap_mb, } - with enable_wrap(use_sharded_state=use_sharded_state, **fsdp_config): + with enable_wrap( + wrapper_cls=FullyShardedDataParallel, + use_sharded_state=use_sharded_state, + **fsdp_config, + ): yield @@ -109,14 +120,13 @@ def fsdp_wrap(module, min_num_params: Optional[int] = None, **kwargs): """ try: from fairscale.nn import wrap - cls = FullyShardedDataParallel if min_num_params is not None: num_params = sum(p.numel() for p in module.parameters()) if num_params >= min_num_params: - return wrap(module, cls=cls, **kwargs) + return wrap(module, **kwargs) else: return module else: - return wrap(module, cls=cls, **kwargs) + return wrap(module, **kwargs) except ImportError: return module diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index d393c02ae6..171a8a40f1 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -29,9 +29,10 @@ def check_type(module, expected_type): if hasattr(module, "unwrapped_module"): - assert isinstance(module.unwrapped_module, expected_type) + assert isinstance(module.unwrapped_module, expected_type), \ + f"{type(module.unwrapped_module)} != {expected_type}" else: - assert isinstance(module, expected_type) + assert isinstance(module, expected_type), f"{type(module)} != {expected_type}" class BaseFairseqModel(nn.Module): diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index a2a40ba6e2..c79d4faf79 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -18,7 +18,7 @@ register_model, register_model_architecture, ) -from fairseq.models.transformer import TransformerEncoder +from fairseq.models.transformer import DEFAULT_MIN_PARAMS_TO_WRAP, TransformerEncoder from fairseq.modules import LayerNorm from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ from fairseq.modules.transformer_sentence_encoder import init_bert_params @@ -122,6 +122,11 @@ def add_args(parser): action="store_true", help="(re-)register and load heads when loading checkpoints", ) + parser.add_argument( + "--untie-weights-roberta", + action="store_true", + help="Untie weights between embeddings and classifiers in RoBERTa", + ) # args for "Reducing Transformer Depth on Demand with Structured Dropout" (Fan et al., 2019) parser.add_argument( "--encoder-layerdrop", @@ -157,17 +162,26 @@ def add_args(parser): default=0, help="scalar quantization noise and scalar quantization at training time", ) - parser.add_argument( - "--untie-weights-roberta", - action="store_true", - help="Untie weights between embeddings and classifiers in RoBERTa", - ) + # args for "Better Fine-Tuning by Reducing Representational Collapse" (Aghajanyan et al. 2020) parser.add_argument( "--spectral-norm-classification-head", action="store_true", default=False, help="Apply spectral normalization on the classification head", ) + # args for Fully Sharded Data Parallel (FSDP) training + parser.add_argument( + "--min-params-to-wrap", + type=int, + metavar="D", + default=DEFAULT_MIN_PARAMS_TO_WRAP, + help=( + "minimum number of params for a layer to be wrapped with FSDP() when " + "training with --ddp-backend=fully_sharded. Smaller values will " + "improve memory efficiency, but may make torch.distributed " + "communication less efficient due to smaller input sizes." + ) + ) @classmethod def build_model(cls, args, task): diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index a0a0b8dcd5..d39e9ec7ed 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -36,6 +36,9 @@ DEFAULT_MAX_TARGET_POSITIONS = 1024 +DEFAULT_MIN_PARAMS_TO_WRAP = int(1e8) + + @register_model("transformer") class TransformerModel(FairseqEncoderDecoderModel): """ @@ -191,6 +194,16 @@ def add_args(parser): help='block size of quantization noise at training time') parser.add_argument('--quant-noise-scalar', type=float, metavar='D', default=0, help='scalar quantization noise and scalar quantization at training time') + # args for Fully Sharded Data Parallel (FSDP) training + parser.add_argument( + '--min-params-to-wrap', type=int, metavar='D', default=DEFAULT_MIN_PARAMS_TO_WRAP, + help=( + 'minimum number of params for a layer to be wrapped with FSDP() when ' + 'training with --ddp-backend=fully_sharded. Smaller values will ' + 'improve memory efficiency, but may make torch.distributed ' + 'communication less efficient due to smaller input sizes.' + ) + ) # fmt: on @classmethod @@ -242,8 +255,11 @@ def build_model(cls, args, task): encoder = cls.build_encoder(args, src_dict, encoder_embed_tokens) decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens) if not args.share_all_embeddings: - encoder = fsdp_wrap(encoder, min_num_params=1e8) - decoder = fsdp_wrap(decoder, min_num_params=1e8) + min_params_to_wrap = getattr( + args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP + ) + encoder = fsdp_wrap(encoder, min_num_params=min_params_to_wrap) + decoder = fsdp_wrap(decoder, min_num_params=min_params_to_wrap) return cls(args, encoder, decoder) @classmethod @@ -387,10 +403,16 @@ def __init__(self, args, dictionary, embed_tokens): def build_encoder_layer(self, args): layer = TransformerEncoderLayer(args) - if getattr(args, "checkpoint_activations", False): + checkpoint = getattr(args, "checkpoint_activations", False) + if checkpoint: offload_to_cpu = getattr(args, "offload_activations", False) layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) - layer = fsdp_wrap(layer, min_num_params=1e8) + # checkpointing requires alignment to FSDP wrap boundaries + min_params_to_wrap = ( + getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) + if not checkpoint else 0 + ) + layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) return layer def forward_embedding( @@ -728,10 +750,16 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): def build_decoder_layer(self, args, no_encoder_attn=False): layer = TransformerDecoderLayer(args, no_encoder_attn) - if getattr(args, "checkpoint_activations", False): + checkpoint = getattr(args, "checkpoint_activations", False) + if checkpoint: offload_to_cpu = getattr(args, "offload_activations", False) layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) - layer = fsdp_wrap(layer, min_num_params=1e8) + # checkpointing requires alignment to FSDP wrap boundaries + min_params_to_wrap = ( + getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) + if not checkpoint else 0 + ) + layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) return layer def forward( diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index f12470d033..09c99b96f6 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -14,7 +14,9 @@ register_model, register_model_architecture, ) -from fairseq.models.transformer import Embedding, TransformerDecoder +from fairseq.models.transformer import ( + DEFAULT_MIN_PARAMS_TO_WRAP, Embedding, TransformerDecoder +) from fairseq.modules import AdaptiveInput, CharacterTokenEmbedder from omegaconf import II @@ -126,15 +128,6 @@ class TransformerLanguageModelConfig(FairseqDataclass): default=False, metadata={"help": "use learned positional embeddings in the decoder"}, ) - decoder_layerdrop: float = field( - default=0.0, metadata={"help": "LayerDrop probability for decoder"} - ) - decoder_layers_to_keep: Optional[str] = field( - default=None, - metadata={ - "help": "which layers to *keep* when pruning as a comma-separated list" - }, - ) layernorm_embedding: bool = field( default=False, metadata={"help": "add layernorm to embedding"} ) @@ -148,6 +141,17 @@ class TransformerLanguageModelConfig(FairseqDataclass): default=False, metadata={"help": "move checkpointed activations to CPU after they are used."}, ) + # config for "Reducing Transformer Depth on Demand with Structured Dropout" (Fan et al., 2019) + decoder_layerdrop: float = field( + default=0.0, metadata={"help": "LayerDrop probability for decoder"} + ) + decoder_layers_to_keep: Optional[str] = field( + default=None, + metadata={ + "help": "which layers to *keep* when pruning as a comma-separated list" + }, + ) + # config for Training with Quantization Noise for Extreme Model Compression ({Fan*, Stock*} et al., 2020) quant_noise_pq: float = field( default=0.0, metadata={"help": "iterative PQ quantization noise at training time"}, @@ -156,13 +160,25 @@ class TransformerLanguageModelConfig(FairseqDataclass): default=8, metadata={"help": "block size of quantization noise at training time"}, ) - # TODO common var add to parent quant_noise_scalar: float = field( default=0.0, metadata={ "help": "scalar quantization noise and scalar quantization at training time" }, ) + # config for Fully Sharded Data Parallel (FSDP) training + min_params_to_wrap: int = field( + default=DEFAULT_MIN_PARAMS_TO_WRAP, + metadata={ + "help": ( + "minimum number of params for a layer to be wrapped with FSDP() when " + "training with --ddp-backend=fully_sharded. Smaller values will " + "improve memory efficiency, but may make torch.distributed " + "communication less efficient due to smaller input sizes." + ) + } + ) + # options from other parts of the config add_bos_token: bool = II("task.add_bos_token") tokens_per_sample: int = II("task.tokens_per_sample") max_target_positions: Optional[int] = II("task.max_target_positions") @@ -289,7 +305,7 @@ def base_lm_architecture(args): args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) args.adaptive_softmax_factor = getattr(args, "adaptive_softmax_factor", 4) - args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) args.activation_fn = getattr(args, "activation_fn", "relu") args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0) @@ -428,3 +444,84 @@ def transformer_lm_gpt2_big(args): args.attention_dropout = getattr(args, "attention_dropout", 0.1) args.activation_fn = getattr(args, "activation_fn", "gelu") base_lm_architecture(args) + + +def base_gpt3_architecture(args): + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", args.decoder_embed_dim * 4) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) + args.dropout = getattr(args, "dropout", 0.0) + args.attention_dropout = getattr(args, "attention_dropout", 0.0) + args.activation_fn = getattr(args, "activation_fn", "gelu") + base_lm_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_small") +def transformer_lm_gpt3_small(args): + # 125M params + args.decoder_layers = getattr(args, "decoder_layers", 12) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 768) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 12) + base_gpt3_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_medium") +def transformer_lm_gpt3_medium(args): + # 350M params + args.decoder_layers = getattr(args, "decoder_layers", 24) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + base_gpt3_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_large") +def transformer_lm_gpt3_large(args): + # 760M params + args.decoder_layers = getattr(args, "decoder_layers", 24) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1536) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + base_gpt3_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_xl") +def transformer_lm_gpt3_xl(args): + # 1.3B params + args.decoder_layers = getattr(args, "decoder_layers", 24) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 2048) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 24) + base_gpt3_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_2_7") +def transformer_lm_gpt3_2_7(args): + # 2.7B params + args.decoder_layers = getattr(args, "decoder_layers", 32) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 2560) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) + base_gpt3_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_6_7") +def transformer_lm_gpt3_6_7(args): + # 6.7B params + args.decoder_layers = getattr(args, "decoder_layers", 32) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 4096) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) + base_gpt3_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_13") +def transformer_lm_gpt3_13(args): + # 13B params + args.decoder_layers = getattr(args, "decoder_layers", 40) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 5120) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 40) + base_gpt3_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt3_175") +def transformer_lm_gpt3_175(args): + # 175B params + args.decoder_layers = getattr(args, "decoder_layers", 96) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 12288) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 96) + base_gpt3_architecture(args) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 4d47d39897..9435558157 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -1017,15 +1017,17 @@ def set_num_updates(self, num_updates): def clip_grad_norm(self, clip_norm): def agg_norm_fn(total_norm): - if self.cfg.distributed_training.ddp_backend == "fully_sharded": - total_norm = total_norm ** 2 - if ( + if ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and ( self.data_parallel_process_group is not None or torch.distributed.is_initialized() - ): - total_norm = distributed_utils.all_reduce( - total_norm.cuda(), group=self.data_parallel_process_group - ) + ) + ): + total_norm = total_norm.cuda().float() ** 2 + total_norm = distributed_utils.all_reduce( + total_norm, group=self.data_parallel_process_group + ) total_norm = total_norm ** 0.5 return total_norm From c6006678261bf5d52e2c744508b5ddd306cafebd Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Tue, 9 Mar 2021 09:38:01 -0800 Subject: [PATCH 269/774] Update README for Fully Sharded Data Parallel (#3331) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3331 Reviewed By: sshleifer Differential Revision: D26912554 Pulled By: myleott fbshipit-source-id: b45a161fbd52a12da13d7e011d562d35a5b5a1a7 --- .../fully_sharded_data_parallel/README.md | 137 ++++++++++-------- fairseq/models/roberta/model.py | 4 +- fairseq/models/transformer.py | 11 +- fairseq/models/transformer_lm.py | 4 +- fairseq/trainer.py | 29 ++-- 5 files changed, 104 insertions(+), 81 deletions(-) diff --git a/examples/fully_sharded_data_parallel/README.md b/examples/fully_sharded_data_parallel/README.md index bc98670968..d620f0e4f1 100644 --- a/examples/fully_sharded_data_parallel/README.md +++ b/examples/fully_sharded_data_parallel/README.md @@ -17,7 +17,7 @@ Compared to PyTorch DDP: FSDP is fully supported in fairseq via the following new arguments: * `--ddp-backend=fully_sharded`: enables full sharding via FSDP * `--cpu-offload`: offloads the optimizer state and FP32 model copy to CPU (combine with `--optimizer=cpu_adam`) -* `--no-reshard-after-forward`: increases training speed for some models and is similar to ZeRO stage 2 +* `--no-reshard-after-forward`: increases training speed for large models (1B+ params) and is similar to ZeRO stage 2 * other popular options (`--fp16`, `--update-freq`, `--checkpoint-activations`, `--offload-activations`, etc.) continue to work as normal <details><summary>Limitations</summary><p> @@ -59,11 +59,13 @@ CPU. In this setting, the optimizer step (Adam) happens on CPU. We also use the `--checkpoint-activations` feature (sometimes called [gradient checkpointing](https://pytorch.org/docs/stable/checkpoint.html)), which further saves memory in exchange for a small increase in computation. -Requirements: -- You'll need 32GB of GPU memory and 256GB of system memory. +**Requirements:** +- Install the latest master version of fairscale: `pip install git+https://github.com/facebookresearch/fairscale.git@master` +- You'll need 32GB of GPU memory and ~256GB of system memory to train the 13B param model. +- If you have less system memory, the 6.7B param model can be trained with ~128GB of system memory, just set `--arch transformer_lm_gpt3_6_7` - We use the CPU Adam optimizer from [DeepSpeed](https://github.com/microsoft/DeepSpeed), so you'll need to `pip install deepspeed` before running the command. -Some notes: +**Notes:** - The command will take ~5 minutes to start training, during which time it will appear to be hung, since randomly initializing 13B weights can be slow. - The `--cpu-offload` feature requires training in mixed precision (`--fp16`). - Tune the `OMP_NUM_THREADS` env variable for best performance with CPU offloading. @@ -79,48 +81,54 @@ OMP_NUM_THREADS=20 CUDA_VISIBLE_DEVICES=0 \ --optimizer cpu_adam --adam-betas "(0.9,0.98)" \ --lr 0.0001 --lr-scheduler polynomial_decay --warmup-updates 5 --total-num-update 10 \ --max-update 10 --no-save --log-format json --log-interval 1 +``` + +<details><summary>Example output</summary><p> -# Example output: -# (...) -# 2021-03-08 12:29:51 | INFO | fairseq_cli.train | num. model params: 13,110,865,920 (num. trained: 13,110,865,920) -# (...) -# 2021-03-08 12:29:51 | INFO | fairseq_cli.train | training on 1 devices (GPUs/TPUs) -# 2021-03-08 12:29:51 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 -# (...) -# Adam Optimizer #0 is created with AVX2 arithmetic capability. -# Config: alpha=0.000100, betas=(0.900000, 0.980000), weight_decay=0.000000, adam_w=1 -# (...) -# 2021-03-08 12:31:36 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "16.475", "ppl": "91120.8", "wps": "0", "ups": "0", "wpb": "16384", "bsz": "8", "num_updates": "1", "lr": "2e-05", "gnorm": "20.751", "loss_scale": "4", "train_wall": "99", "gb_free": "9.3", "wall": "105"} -# 2021-03-08 12:32:33 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "16.446", "ppl": "89281.6", "wps": "288.7", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "2", "lr": "4e-05", "gnorm": "19.777", "loss_scale": "4", "train_wall": "57", "gb_free": "9.3", "wall": "161"} -# 2021-03-08 12:33:12 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 2.0 -# 2021-03-08 12:33:51 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 1.0 -# 2021-03-08 12:34:45 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "25.22", "ppl": "3.90691e+07", "wps": "123.4", "ups": "0.01", "wpb": "16384", "bsz": "8", "num_updates": "3", "lr": "6e-05", "gnorm": "131.281", "loss_scale": "1", "train_wall": "133", "gb_free": "9.3", "wall": "294"} -# 2021-03-08 12:35:43 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.079", "ppl": "276809", "wps": "285.5", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "4", "lr": "8e-05", "gnorm": "13.776", "loss_scale": "1", "train_wall": "57", "gb_free": "9.3", "wall": "351"} -# 2021-03-08 12:36:35 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "23.729", "ppl": "1.39088e+07", "wps": "316.7", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "5", "lr": "0.0001", "gnorm": "72.774", "loss_scale": "1", "train_wall": "52", "gb_free": "9.3", "wall": "403"} -# 2021-03-08 12:37:28 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "20.429", "ppl": "1.41203e+06", "wps": "307.6", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "6", "lr": "8e-05", "gnorm": "60.846", "loss_scale": "1", "train_wall": "53", "gb_free": "9.3", "wall": "456"} -# 2021-03-08 12:38:27 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.965", "ppl": "511684", "wps": "279.4", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "7", "lr": "6e-05", "gnorm": "22.687", "loss_scale": "1", "train_wall": "59", "gb_free": "9.3", "wall": "515"} -# 2021-03-08 12:39:18 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.345", "ppl": "332887", "wps": "319.1", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "8", "lr": "4e-05", "gnorm": "8.451", "loss_scale": "1", "train_wall": "51", "gb_free": "9.3", "wall": "566"} -# 2021-03-08 12:40:11 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "18.262", "ppl": "314336", "wps": "305.9", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "9", "lr": "2e-05", "gnorm": "6.457", "loss_scale": "1", "train_wall": "54", "gb_free": "9.3", "wall": "620"} -# 2021-03-08 12:41:04 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "17.556", "ppl": "192686", "wps": "311.8", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "10", "lr": "0", "gnorm": "5.796", "loss_scale": "1", "train_wall": "53", "gb_free": "9.3", "wall": "673"} -# 2021-03-08 12:41:04 | INFO | fairseq_cli.train | Stopping training due to num_updates: 10 >= max_update: 10 -# 2021-03-08 12:41:04 | INFO | fairseq_cli.train | begin validation on "valid" subset -# 2021-03-08 12:43:15 | INFO | valid | {"epoch": 1, "valid_loss": "17.953", "valid_ppl": "253807", "valid_wps": "1868.4", "valid_wpb": "15400.2", "valid_bsz": "7.6", "valid_num_updates": "10"} -# 2021-03-08 12:43:15 | INFO | fairseq_cli.train | end of epoch 1 (average epoch stats below) -# 2021-03-08 12:43:15 | INFO | train | {"epoch": 1, "train_loss": "19.351", "train_ppl": "668509", "train_wps": "210.9", "train_ups": "0.01", "train_wpb": "16384", "train_bsz": "8", "train_num_updates": "10", "train_lr": "0", "train_gnorm": "36.26", "train_loss_scale": "1", "train_train_wall": "667", "train_gb_free": "9.3", "train_wall": "804"} -# 2021-03-08 12:43:15 | INFO | fairseq_cli.train | done training in 798.6 seconds ``` +(...) +2021-03-08 12:29:51 | INFO | fairseq_cli.train | num. model params: 13,110,865,920 (num. trained: 13,110,865,920) +(...) +2021-03-08 12:29:51 | INFO | fairseq_cli.train | training on 1 devices (GPUs/TPUs) +2021-03-08 12:29:51 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 +(...) +Adam Optimizer #0 is created with AVX2 arithmetic capability. +Config: alpha=0.000100, betas=(0.900000, 0.980000), weight_decay=0.000000, adam_w=1 +(...) +2021-03-08 12:31:36 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "16.475", "ppl": "91120.8", "wps": "0", "ups": "0", "wpb": "16384", "bsz": "8", "num_updates": "1", "lr": "2e-05", "gnorm": "20.751", "loss_scale": "4", "train_wall": "99", "gb_free": "9.3", "wall": "105"} +2021-03-08 12:32:33 | INFO | train_inner | {"epoch": 1, "update": 0.0, "loss": "16.446", "ppl": "89281.6", "wps": "288.7", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "2", "lr": "4e-05", "gnorm": "19.777", "loss_scale": "4", "train_wall": "57", "gb_free": "9.3", "wall": "161"} +2021-03-08 12:33:12 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 2.0 +2021-03-08 12:33:51 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 1.0 +2021-03-08 12:34:45 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "25.22", "ppl": "3.90691e+07", "wps": "123.4", "ups": "0.01", "wpb": "16384", "bsz": "8", "num_updates": "3", "lr": "6e-05", "gnorm": "131.281", "loss_scale": "1", "train_wall": "133", "gb_free": "9.3", "wall": "294"} +2021-03-08 12:35:43 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.079", "ppl": "276809", "wps": "285.5", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "4", "lr": "8e-05", "gnorm": "13.776", "loss_scale": "1", "train_wall": "57", "gb_free": "9.3", "wall": "351"} +2021-03-08 12:36:35 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "23.729", "ppl": "1.39088e+07", "wps": "316.7", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "5", "lr": "0.0001", "gnorm": "72.774", "loss_scale": "1", "train_wall": "52", "gb_free": "9.3", "wall": "403"} +2021-03-08 12:37:28 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "20.429", "ppl": "1.41203e+06", "wps": "307.6", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "6", "lr": "8e-05", "gnorm": "60.846", "loss_scale": "1", "train_wall": "53", "gb_free": "9.3", "wall": "456"} +2021-03-08 12:38:27 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.965", "ppl": "511684", "wps": "279.4", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "7", "lr": "6e-05", "gnorm": "22.687", "loss_scale": "1", "train_wall": "59", "gb_free": "9.3", "wall": "515"} +2021-03-08 12:39:18 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "18.345", "ppl": "332887", "wps": "319.1", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "8", "lr": "4e-05", "gnorm": "8.451", "loss_scale": "1", "train_wall": "51", "gb_free": "9.3", "wall": "566"} +2021-03-08 12:40:11 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "18.262", "ppl": "314336", "wps": "305.9", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "9", "lr": "2e-05", "gnorm": "6.457", "loss_scale": "1", "train_wall": "54", "gb_free": "9.3", "wall": "620"} +2021-03-08 12:41:04 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "17.556", "ppl": "192686", "wps": "311.8", "ups": "0.02", "wpb": "16384", "bsz": "8", "num_updates": "10", "lr": "0", "gnorm": "5.796", "loss_scale": "1", "train_wall": "53", "gb_free": "9.3", "wall": "673"} +2021-03-08 12:41:04 | INFO | fairseq_cli.train | Stopping training due to num_updates: 10 >= max_update: 10 +2021-03-08 12:41:04 | INFO | fairseq_cli.train | begin validation on "valid" subset +2021-03-08 12:43:15 | INFO | valid | {"epoch": 1, "valid_loss": "17.953", "valid_ppl": "253807", "valid_wps": "1868.4", "valid_wpb": "15400.2", "valid_bsz": "7.6", "valid_num_updates": "10"} +2021-03-08 12:43:15 | INFO | fairseq_cli.train | end of epoch 1 (average epoch stats below) +2021-03-08 12:43:15 | INFO | train | {"epoch": 1, "train_loss": "19.351", "train_ppl": "668509", "train_wps": "210.9", "train_ups": "0.01", "train_wpb": "16384", "train_bsz": "8", "train_num_updates": "10", "train_lr": "0", "train_gnorm": "36.26", "train_loss_scale": "1", "train_train_wall": "667", "train_gb_free": "9.3", "train_wall": "804"} +2021-03-08 12:43:15 | INFO | fairseq_cli.train | done training in 798.6 seconds +``` + +</p></details> ### 13B params on 8 V100 GPUs (with full parameter + optimizer state sharding) FSDP can also shard the parameters and optimizer states across multiple GPUs, -reducing memory requirements significantly. On 8 GPUs, sharding enables +reducing memory requirements significantly. On 8 x 32GB GPUs, sharding enables training the same 13B parameter model *without offloading the parameters to CPU*. However, without CPU offloading we'd only be able to fit a batch size of 1 per GPU, which would cause training speed to suffer. We obtain the best performance on 8 GPUs by combining full sharding and CPU offloading. The following command trains the same 13B parameter GPT-3 model as -before on 8 GPUs; training speed increases from ~310 -> ~3200 words per second. +before on 8 x 32GB V100 GPUs; training speed increases superlinearly from ~310 +words per second to ~3200 words per second. ```bash OMP_NUM_THREADS=20 CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ @@ -132,33 +140,38 @@ OMP_NUM_THREADS=20 CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ --optimizer cpu_adam --adam-betas "(0.9,0.98)" \ --lr 0.0001 --lr-scheduler polynomial_decay --warmup-updates 5 --total-num-update 10 \ --max-update 10 --no-save --log-format json --log-interval 1 +``` + +<details><summary>Example output</summary><p> -# Example output: -# (...) -# 2021-03-08 18:04:09 | INFO | fairseq_cli.train | num. model params: 13,110,865,920 (num. trained: 13,110,865,920) -# (...) -# 2021-03-08 18:04:09 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) -# 2021-03-08 18:04:09 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 -# (...) -# Adam Optimizer #0 is created with AVX2 arithmetic capability. -# Config: alpha=0.000100, betas=(0.900000, 0.980000), weight_decay=0.000000, adam_w=1 -# (...) -# 2021-03-08 18:05:06 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "16.408", "ppl": "86945.6", "wps": "0", "ups": "0", "wpb": "131072", "bsz": "64", "num_updates": "1", "lr": "2e-05", "gnorm": "18.27", "loss_scale": "4", "train_wall": "47", "gb_free": "9.3", "wall": "56"} -# 2021-03-08 18:05:45 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "16.352", "ppl": "83644.3", "wps": "3283.4", "ups": "0.03", "wpb": "131072", "bsz": "64", "num_updates": "2", "lr": "4e-05", "gnorm": "18.411", "loss_scale": "4", "train_wall": "40", "gb_free": "9.3", "wall": "96"} -# 2021-03-08 18:06:21 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 2.0 -# 2021-03-08 18:06:56 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 1.0 -# 2021-03-08 18:07:37 | INFO | train_inner | {"epoch": 1, "update": 0.006, "loss": "23.682", "ppl": "1.34537e+07", "wps": "1176.6", "ups": "0.01", "wpb": "131072", "bsz": "64", "num_updates": "3", "lr": "6e-05", "gnorm": "119.682", "loss_scale": "1", "train_wall": "111", "gb_free": "9.3", "wall": "208"} -# 2021-03-08 18:08:18 | INFO | train_inner | {"epoch": 1, "update": 0.007, "loss": "18.988", "ppl": "519921", "wps": "3189.1", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "4", "lr": "8e-05", "gnorm": "14.934", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "249"} -# 2021-03-08 18:08:59 | INFO | train_inner | {"epoch": 1, "update": 0.008, "loss": "20.08", "ppl": "1.10798e+06", "wps": "3223.1", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "5", "lr": "0.0001", "gnorm": "59.92", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "289"} -# 2021-03-08 18:09:39 | INFO | train_inner | {"epoch": 1, "update": 0.009, "loss": "18.323", "ppl": "327980", "wps": "3256.6", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "6", "lr": "8e-05", "gnorm": "37.425", "loss_scale": "1", "train_wall": "40", "gb_free": "9.3", "wall": "330"} -# 2021-03-08 18:10:20 | INFO | train_inner | {"epoch": 1, "update": 0.01, "loss": "17.264", "ppl": "157354", "wps": "3188.7", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "7", "lr": "6e-05", "gnorm": "10.824", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "371"} -# 2021-03-08 18:11:01 | INFO | train_inner | {"epoch": 1, "update": 0.011, "loss": "16.794", "ppl": "113647", "wps": "3230", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "8", "lr": "4e-05", "gnorm": "5.616", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "411"} -# 2021-03-08 18:11:39 | INFO | train_inner | {"epoch": 1, "update": 0.012, "loss": "16.706", "ppl": "106938", "wps": "3384", "ups": "0.03", "wpb": "131072", "bsz": "64", "num_updates": "9", "lr": "2e-05", "gnorm": "5.318", "loss_scale": "1", "train_wall": "39", "gb_free": "9.3", "wall": "450"} -# 2021-03-08 18:12:19 | INFO | train_inner | {"epoch": 1, "update": 0.013, "loss": "16.548", "ppl": "95796.2", "wps": "3274.4", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "10", "lr": "0", "gnorm": "5.22", "loss_scale": "1", "train_wall": "40", "gb_free": "9.3", "wall": "490"} -# 2021-03-08 18:12:19 | INFO | fairseq_cli.train | Stopping training due to num_updates: 10 >= max_update: 10 -# 2021-03-08 18:12:19 | INFO | fairseq_cli.train | begin validation on "valid" subset -# 2021-03-08 18:12:45 | INFO | valid | {"epoch": 1, "valid_loss": "16.624", "valid_ppl": "101000", "valid_wps": "10855.9", "valid_wpb": "123202", "valid_bsz": "60.5", "valid_num_updates": "10"} -# 2021-03-08 18:12:45 | INFO | fairseq_cli.train | end of epoch 1 (average epoch stats below) -# 2021-03-08 18:12:45 | INFO | train | {"epoch": 1, "train_loss": "18.114", "train_ppl": "283776", "train_wps": "2567.8", "train_ups": "0.02", "train_wpb": "131072", "train_bsz": "64", "train_num_updates": "10", "train_lr": "0", "train_gnorm": "29.562", "train_loss_scale": "1", "train_train_wall": "480", "train_gb_free": "9.3", "train_wall": "516"} -# 2021-03-08 18:12:45 | INFO | fairseq_cli.train | done training in 509.9 seconds ``` +(...) +2021-03-08 18:04:09 | INFO | fairseq_cli.train | num. model params: 13,110,865,920 (num. trained: 13,110,865,920) +(...) +2021-03-08 18:04:09 | INFO | fairseq_cli.train | training on 8 devices (GPUs/TPUs) +2021-03-08 18:04:09 | INFO | fairseq_cli.train | max tokens per GPU = None and batch size per GPU = 8 +(...) +Adam Optimizer #0 is created with AVX2 arithmetic capability. +Config: alpha=0.000100, betas=(0.900000, 0.980000), weight_decay=0.000000, adam_w=1 +(...) +2021-03-08 18:05:06 | INFO | train_inner | {"epoch": 1, "update": 0.001, "loss": "16.408", "ppl": "86945.6", "wps": "0", "ups": "0", "wpb": "131072", "bsz": "64", "num_updates": "1", "lr": "2e-05", "gnorm": "18.27", "loss_scale": "4", "train_wall": "47", "gb_free": "9.3", "wall": "56"} +2021-03-08 18:05:45 | INFO | train_inner | {"epoch": 1, "update": 0.002, "loss": "16.352", "ppl": "83644.3", "wps": "3283.4", "ups": "0.03", "wpb": "131072", "bsz": "64", "num_updates": "2", "lr": "4e-05", "gnorm": "18.411", "loss_scale": "4", "train_wall": "40", "gb_free": "9.3", "wall": "96"} +2021-03-08 18:06:21 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 2.0 +2021-03-08 18:06:56 | INFO | fairseq.trainer | NOTE: gradient overflow detected, ignoring gradient, setting loss scale to: 1.0 +2021-03-08 18:07:37 | INFO | train_inner | {"epoch": 1, "update": 0.006, "loss": "23.682", "ppl": "1.34537e+07", "wps": "1176.6", "ups": "0.01", "wpb": "131072", "bsz": "64", "num_updates": "3", "lr": "6e-05", "gnorm": "119.682", "loss_scale": "1", "train_wall": "111", "gb_free": "9.3", "wall": "208"} +2021-03-08 18:08:18 | INFO | train_inner | {"epoch": 1, "update": 0.007, "loss": "18.988", "ppl": "519921", "wps": "3189.1", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "4", "lr": "8e-05", "gnorm": "14.934", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "249"} +2021-03-08 18:08:59 | INFO | train_inner | {"epoch": 1, "update": 0.008, "loss": "20.08", "ppl": "1.10798e+06", "wps": "3223.1", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "5", "lr": "0.0001", "gnorm": "59.92", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "289"} +2021-03-08 18:09:39 | INFO | train_inner | {"epoch": 1, "update": 0.009, "loss": "18.323", "ppl": "327980", "wps": "3256.6", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "6", "lr": "8e-05", "gnorm": "37.425", "loss_scale": "1", "train_wall": "40", "gb_free": "9.3", "wall": "330"} +2021-03-08 18:10:20 | INFO | train_inner | {"epoch": 1, "update": 0.01, "loss": "17.264", "ppl": "157354", "wps": "3188.7", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "7", "lr": "6e-05", "gnorm": "10.824", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "371"} +2021-03-08 18:11:01 | INFO | train_inner | {"epoch": 1, "update": 0.011, "loss": "16.794", "ppl": "113647", "wps": "3230", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "8", "lr": "4e-05", "gnorm": "5.616", "loss_scale": "1", "train_wall": "41", "gb_free": "9.3", "wall": "411"} +2021-03-08 18:11:39 | INFO | train_inner | {"epoch": 1, "update": 0.012, "loss": "16.706", "ppl": "106938", "wps": "3384", "ups": "0.03", "wpb": "131072", "bsz": "64", "num_updates": "9", "lr": "2e-05", "gnorm": "5.318", "loss_scale": "1", "train_wall": "39", "gb_free": "9.3", "wall": "450"} +2021-03-08 18:12:19 | INFO | train_inner | {"epoch": 1, "update": 0.013, "loss": "16.548", "ppl": "95796.2", "wps": "3274.4", "ups": "0.02", "wpb": "131072", "bsz": "64", "num_updates": "10", "lr": "0", "gnorm": "5.22", "loss_scale": "1", "train_wall": "40", "gb_free": "9.3", "wall": "490"} +2021-03-08 18:12:19 | INFO | fairseq_cli.train | Stopping training due to num_updates: 10 >= max_update: 10 +2021-03-08 18:12:19 | INFO | fairseq_cli.train | begin validation on "valid" subset +2021-03-08 18:12:45 | INFO | valid | {"epoch": 1, "valid_loss": "16.624", "valid_ppl": "101000", "valid_wps": "10855.9", "valid_wpb": "123202", "valid_bsz": "60.5", "valid_num_updates": "10"} +2021-03-08 18:12:45 | INFO | fairseq_cli.train | end of epoch 1 (average epoch stats below) +2021-03-08 18:12:45 | INFO | train | {"epoch": 1, "train_loss": "18.114", "train_ppl": "283776", "train_wps": "2567.8", "train_ups": "0.02", "train_wpb": "131072", "train_bsz": "64", "train_num_updates": "10", "train_lr": "0", "train_gnorm": "29.562", "train_loss_scale": "1", "train_train_wall": "480", "train_gb_free": "9.3", "train_wall": "516"} +2021-03-08 18:12:45 | INFO | fairseq_cli.train | done training in 509.9 seconds +``` + +</p></details> diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index c79d4faf79..5d2ed4902d 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -179,7 +179,9 @@ def add_args(parser): "minimum number of params for a layer to be wrapped with FSDP() when " "training with --ddp-backend=fully_sharded. Smaller values will " "improve memory efficiency, but may make torch.distributed " - "communication less efficient due to smaller input sizes." + "communication less efficient due to smaller input sizes. This option " + "is set to 0 (i.e., always wrap) when --checkpoint-activations or " + "--offload-activations are passed." ) ) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index d39e9ec7ed..297807c31a 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -201,7 +201,9 @@ def add_args(parser): 'minimum number of params for a layer to be wrapped with FSDP() when ' 'training with --ddp-backend=fully_sharded. Smaller values will ' 'improve memory efficiency, but may make torch.distributed ' - 'communication less efficient due to smaller input sizes.' + 'communication less efficient due to smaller input sizes. This option ' + 'is set to 0 (i.e., always wrap) when --checkpoint-activations or ' + '--offload-activations are passed.' ) ) # fmt: on @@ -258,6 +260,7 @@ def build_model(cls, args, task): min_params_to_wrap = getattr( args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP ) + # fsdp_wrap is a no-op when --ddp-backend != fully_sharded encoder = fsdp_wrap(encoder, min_num_params=min_params_to_wrap) decoder = fsdp_wrap(decoder, min_num_params=min_params_to_wrap) return cls(args, encoder, decoder) @@ -407,7 +410,8 @@ def build_encoder_layer(self, args): if checkpoint: offload_to_cpu = getattr(args, "offload_activations", False) layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) - # checkpointing requires alignment to FSDP wrap boundaries + # if we are checkpointing, enforce that FSDP always wraps the + # checkpointed layer, regardless of layer size min_params_to_wrap = ( getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) if not checkpoint else 0 @@ -754,7 +758,8 @@ def build_decoder_layer(self, args, no_encoder_attn=False): if checkpoint: offload_to_cpu = getattr(args, "offload_activations", False) layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) - # checkpointing requires alignment to FSDP wrap boundaries + # if we are checkpointing, enforce that FSDP always wraps the + # checkpointed layer, regardless of layer size min_params_to_wrap = ( getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) if not checkpoint else 0 diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index 09c99b96f6..fca9470e5e 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -174,7 +174,9 @@ class TransformerLanguageModelConfig(FairseqDataclass): "minimum number of params for a layer to be wrapped with FSDP() when " "training with --ddp-backend=fully_sharded. Smaller values will " "improve memory efficiency, but may make torch.distributed " - "communication less efficient due to smaller input sizes." + "communication less efficient due to smaller input sizes. This option " + "is set to 0 (i.e., always wrap) when --checkpoint-activations or " + "--offload-activations are passed." ) } ) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 9435558157..dcf5305455 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -1017,21 +1017,22 @@ def set_num_updates(self, num_updates): def clip_grad_norm(self, clip_norm): def agg_norm_fn(total_norm): - if ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and ( - self.data_parallel_process_group is not None - or torch.distributed.is_initialized() - ) - ): - total_norm = total_norm.cuda().float() ** 2 - total_norm = distributed_utils.all_reduce( - total_norm, group=self.data_parallel_process_group - ) - total_norm = total_norm ** 0.5 - return total_norm + total_norm = total_norm.cuda().float() ** 2 + total_norm = distributed_utils.all_reduce( + total_norm, group=self.data_parallel_process_group + ) + return total_norm ** 0.5 - return self.optimizer.clip_grad_norm(clip_norm, aggregate_norm_fn=agg_norm_fn) + should_agg_norm = ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and ( + self.data_parallel_process_group is not None + or torch.distributed.is_initialized() + ) + ) + return self.optimizer.clip_grad_norm( + clip_norm, aggregate_norm_fn=agg_norm_fn if should_agg_norm else None + ) def cumulative_training_time(self): if self._cumulative_training_time is None: From 05255f96410e5b1eaf3bf59b767d5b4b7e2c3a35 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Tue, 9 Mar 2021 16:26:05 -0800 Subject: [PATCH 270/774] update audio_utils and fix mTEDx example Summary: update audio_utils and fix mTEDx example - Updated `audio_utils` - Added support for OGG Vorbis (the only supported lossy compressed format) - Added a separate `convert_to_mono()` helper function - Updated `get_waveform()` - added new arguments `frames` and `start` for reading part of audios - added new argument `mono` for auto conversion to mono-channel audio - unified returned waveform shape to channels x length (same as torchaudio default) - Updated mTEDx and MUST-C data prep scripts - Replaced `torchaudio.info()` with `soundfile.info()` (the latter is faster and the former has incompatible interface between <0.8 and the latest 0.8) - Replaced `torchaudio.load()` with `get_waveform` for auto conversion to mono channel Reviewed By: jmp84 Differential Revision: D26901114 fbshipit-source-id: fa9560c9714d51a91157d5141564574d4eee454d --- examples/speech_to_text/data_utils.py | 12 ++- examples/speech_to_text/docs/mtedx_example.md | 2 +- examples/speech_to_text/docs/mustc_example.md | 2 +- examples/speech_to_text/prep_mtedx_data.py | 13 +-- examples/speech_to_text/prep_mustc_data.py | 13 +-- fairseq/data/audio/audio_utils.py | 83 ++++++++++++++----- fairseq/data/audio/speech_to_text_dataset.py | 5 +- 7 files changed, 89 insertions(+), 41 deletions(-) diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index fa0d459611..3f96ffc427 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -14,7 +14,10 @@ import numpy as np import pandas as pd import sentencepiece as sp -from fairseq.data.audio.audio_utils import _get_kaldi_fbank, _get_torchaudio_fbank +from fairseq.data.audio.audio_utils import ( + _convert_to_mono, _get_kaldi_fbank, _get_torchaudio_fbank +) +import torch from tqdm import tqdm @@ -66,7 +69,7 @@ def gen_vocab( def extract_fbank_features( - waveform, + waveform: torch.FloatTensor, sample_rate: int, output_path: Optional[Path] = None, n_mel_bins: int = 80, @@ -75,8 +78,9 @@ def extract_fbank_features( if output_path is not None and output_path.is_file() and not overwrite: return - _waveform = waveform * (2 ** 15) # Kaldi compliance: 16-bit signed integers - _waveform = _waveform.squeeze().numpy() + _waveform = _convert_to_mono(waveform, sample_rate) + _waveform = _waveform * (2 ** 15) # Kaldi compliance: 16-bit signed integers + _waveform = _waveform.numpy() features = _get_kaldi_fbank(_waveform, sample_rate, n_mel_bins) if features is None: diff --git a/examples/speech_to_text/docs/mtedx_example.md b/examples/speech_to_text/docs/mtedx_example.md index c0e17db9a2..25b4556aff 100644 --- a/examples/speech_to_text/docs/mtedx_example.md +++ b/examples/speech_to_text/docs/mtedx_example.md @@ -11,7 +11,7 @@ with translations to a subset of 5 target languages. `${MTEDX_ROOT}/${LANG_PAIR}`, then preprocess it with ```bash # additional Python packages for S2T data processing/model training -pip install pandas torchaudio sentencepiece +pip install pandas torchaudio soundfile sentencepiece # Generate TSV manifests, features, vocabulary # and configuration for each language diff --git a/examples/speech_to_text/docs/mustc_example.md b/examples/speech_to_text/docs/mustc_example.md index 7628dc77ef..79df0aafdc 100644 --- a/examples/speech_to_text/docs/mustc_example.md +++ b/examples/speech_to_text/docs/mustc_example.md @@ -11,7 +11,7 @@ `${MUSTC_ROOT}/en-${TARGET_LANG_ID}`, then preprocess it with ```bash # additional Python packages for S2T data processing/model training -pip install pandas torchaudio sentencepiece +pip install pandas torchaudio soundfile sentencepiece # Generate TSV manifests, features, vocabulary # and configuration for each language diff --git a/examples/speech_to_text/prep_mtedx_data.py b/examples/speech_to_text/prep_mtedx_data.py index 6c37398fcc..34b1c398c8 100644 --- a/examples/speech_to_text/prep_mtedx_data.py +++ b/examples/speech_to_text/prep_mtedx_data.py @@ -14,7 +14,7 @@ from typing import Tuple import pandas as pd -import torchaudio +import soundfile as sf from examples.speech_to_text.data_utils import ( create_zip, extract_fbank_features, @@ -25,10 +25,12 @@ load_df_from_tsv, save_df_to_tsv, ) -from torch import Tensor +import torch from torch.utils.data import Dataset from tqdm import tqdm +from fairseq.data.audio.audio_utils import get_waveform + log = logging.getLogger(__name__) @@ -73,7 +75,7 @@ def __init__(self, root: str, lang: str, split: str) -> None: for wav_filename, _seg_group in groupby(segments, lambda x: x["wav"]): wav_filename = wav_filename.replace(".wav", ".flac") wav_path = wav_root / wav_filename - sample_rate = torchaudio.info(wav_path.as_posix())[0].rate + sample_rate = sf.info(wav_path.as_posix()).samplerate seg_group = sorted(_seg_group, key=lambda x: float(x["offset"])) for i, segment in enumerate(seg_group): offset = int(float(segment["offset"]) * sample_rate) @@ -93,9 +95,10 @@ def __init__(self, root: str, lang: str, split: str) -> None: ) ) - def __getitem__(self, n: int) -> Tuple[Tensor, int, str, str, str, str, str]: + def __getitem__(self, n: int) -> Tuple[torch.Tensor, int, str, str, str, str, str]: wav_path, offset, n_frames, sr, src_utt, tgt_utt, spk_id, tgt_lang, utt_id = self.data[n] - waveform, _ = torchaudio.load(wav_path, offset=offset, num_frames=n_frames) + waveform, _ = get_waveform(wav_path, frames=n_frames, start=offset) + waveform = torch.from_numpy(waveform) return waveform, sr, src_utt, tgt_utt, spk_id, tgt_lang, utt_id def __len__(self) -> int: diff --git a/examples/speech_to_text/prep_mustc_data.py b/examples/speech_to_text/prep_mustc_data.py index 45fd43533d..0ee204e651 100644 --- a/examples/speech_to_text/prep_mustc_data.py +++ b/examples/speech_to_text/prep_mustc_data.py @@ -15,7 +15,7 @@ import numpy as np import pandas as pd -import torchaudio +import soundfile as sf from examples.speech_to_text.data_utils import ( create_zip, extract_fbank_features, @@ -27,10 +27,12 @@ save_df_to_tsv, cal_gcmvn_stats, ) -from torch import Tensor +import torch from torch.utils.data import Dataset from tqdm import tqdm +from fairseq.data.audio.audio_utils import get_waveform + log = logging.getLogger(__name__) @@ -71,7 +73,7 @@ def __init__(self, root: str, lang: str, split: str) -> None: self.data = [] for wav_filename, _seg_group in groupby(segments, lambda x: x["wav"]): wav_path = wav_root / wav_filename - sample_rate = torchaudio.info(wav_path.as_posix())[0].rate + sample_rate = sf.info(wav_path.as_posix()).samplerate seg_group = sorted(_seg_group, key=lambda x: x["offset"]) for i, segment in enumerate(seg_group): offset = int(float(segment["offset"]) * sample_rate) @@ -90,9 +92,10 @@ def __init__(self, root: str, lang: str, split: str) -> None: ) ) - def __getitem__(self, n: int) -> Tuple[Tensor, int, str, str, str, str]: + def __getitem__(self, n: int) -> Tuple[torch.Tensor, int, str, str, str, str]: wav_path, offset, n_frames, sr, src_utt, tgt_utt, spk_id, utt_id = self.data[n] - waveform, _ = torchaudio.load(wav_path, offset=offset, num_frames=n_frames) + waveform, _ = get_waveform(wav_path, frames=n_frames, start=offset) + waveform = torch.from_numpy(waveform) return waveform, sr, src_utt, tgt_utt, spk_id, utt_id def __len__(self) -> int: diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index f8cc80f5e2..ddd5642c7e 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -1,35 +1,80 @@ -import os.path as op +from pathlib import Path from typing import BinaryIO, Optional, Tuple, Union import numpy as np +import torch + + +SF_AUDIO_FILE_EXTENSIONS = {".wav", ".flac", ".ogg"} + + +def _convert_to_mono( + waveform: torch.FloatTensor, sample_rate: int +) -> torch.FloatTensor: + if waveform.shape[0] > 1: + try: + import torchaudio.sox_effects as ta_sox + except ImportError: + raise ImportError( + "Please install torchaudio to convert multi-channel audios" + ) + effects = [['channels', '1']] + return ta_sox.apply_effects_tensor(waveform, sample_rate, effects)[0] + return waveform + + +def convert_to_mono(waveform: np.ndarray, sample_rate: int) -> np.ndarray: + if waveform.shape[0] > 1: + _waveform = torch.from_numpy(waveform) + return _convert_to_mono(_waveform, sample_rate).numpy() + return waveform def get_waveform( - path_or_fp: Union[str, BinaryIO], normalization=True + path_or_fp: Union[str, BinaryIO], normalization=True, mono=True, + frames=-1, start=0, always_2d=True ) -> Tuple[np.ndarray, int]: - """Get the waveform and sample rate of a 16-bit mono-channel WAV or FLAC. + """Get the waveform and sample rate of a 16-bit WAV/FLAC/OGG Vorbis audio. Args: path_or_fp (str or BinaryIO): the path or file-like object normalization (bool): Normalize values to [-1, 1] (Default: True) + mono (bool): convert multi-channel audio to mono-channel one + frames (int): the number of frames to read. (-1 for reading all) + start (int): Where to start reading. A negative value counts from the end. + always_2d (bool): always return 2D array even for mono-channel audios + Returns: + waveform (numpy.ndarray): 1D or 2D waveform (channels x length) + sample_rate (float): sample rate """ if isinstance(path_or_fp, str): - ext = op.splitext(op.basename(path_or_fp))[1] - if ext not in {".flac", ".wav"}: + ext = Path(path_or_fp).suffix + if ext not in SF_AUDIO_FILE_EXTENSIONS: raise ValueError(f"Unsupported audio format: {ext}") try: import soundfile as sf except ImportError: - raise ImportError("Please install soundfile to load WAV/FLAC file") + raise ImportError( + "Please install soundfile to load WAV/FLAC/OGG Vorbis audios" + ) - waveform, sample_rate = sf.read(path_or_fp, dtype="float32") + waveform, sample_rate = sf.read( + path_or_fp, dtype="float32", always_2d=True, frames=frames, start=start + ) + waveform = waveform.T # T x C -> C x T + if mono and waveform.shape[0] > 1: + waveform = convert_to_mono(waveform, sample_rate) if not normalization: waveform *= 2 ** 15 # denormalized to 16-bit signed integers + if not always_2d: + waveform = waveform.squeeze(axis=0) return waveform, sample_rate -def _get_kaldi_fbank(waveform, sample_rate, n_bins=80) -> Optional[np.ndarray]: +def _get_kaldi_fbank( + waveform: np.ndarray, sample_rate: int, n_bins=80 +) -> Optional[np.ndarray]: """Get mel-filter bank features via PyKaldi.""" try: from kaldi.feat.mel import MelBanksOptions @@ -45,27 +90,19 @@ def _get_kaldi_fbank(waveform, sample_rate, n_bins=80) -> Optional[np.ndarray]: opts.mel_opts = mel_opts opts.frame_opts = frame_opts fbank = Fbank(opts=opts) - features = fbank.compute(Vector(waveform), 1.0).numpy() + features = fbank.compute(Vector(waveform.squeeze()), 1.0).numpy() return features except ImportError: return None -def _get_torchaudio_fbank(waveform, sample_rate, n_bins=80) -> Optional[np.ndarray]: +def _get_torchaudio_fbank( + waveform: np.ndarray, sample_rate, n_bins=80 +) -> Optional[np.ndarray]: """Get mel-filter bank features via TorchAudio.""" try: - import torch import torchaudio.compliance.kaldi as ta_kaldi - import torchaudio.sox_effects as ta_sox - waveform = torch.from_numpy(waveform) - if len(waveform.shape) == 1: - # Mono channel: D -> 1 x D - waveform = waveform.unsqueeze(0) - else: - # Merge multiple channels to one: D x C -> 1 x D - waveform, _ = ta_sox.apply_effects_tensor(waveform.T, sample_rate, [['channels', '1']]) - features = ta_kaldi.fbank( waveform, num_mel_bins=n_bins, sample_frequency=sample_rate ) @@ -79,11 +116,11 @@ def get_fbank(path_or_fp: Union[str, BinaryIO], n_bins=80) -> np.ndarray: (faster CPP implementation) to TorchAudio (Python implementation). Note that Kaldi/TorchAudio requires 16-bit signed integers as inputs and hence the waveform should not be normalized.""" - sound, sample_rate = get_waveform(path_or_fp, normalization=False) + waveform, sample_rate = get_waveform(path_or_fp, normalization=False) - features = _get_kaldi_fbank(sound, sample_rate, n_bins) + features = _get_kaldi_fbank(waveform, sample_rate, n_bins) if features is None: - features = _get_torchaudio_fbank(sound, sample_rate, n_bins) + features = _get_torchaudio_fbank(waveform, sample_rate, n_bins) if features is None: raise ImportError( "Please install pyKaldi or torchaudio to enable " diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index 39d22c7a5e..c6c64db084 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -153,7 +153,8 @@ def get_features_or_waveform_from_uncompressed_zip( if is_npy_data(data): features_or_waveform = np.load(f) elif is_flac_or_wav_data(data): - features_or_waveform = get_waveform(f)[0] if need_waveform else get_fbank(f) + features_or_waveform = \ + get_waveform(f, always_2d=False)[0] if need_waveform else get_fbank(f) else: raise ValueError(f'Unknown file format for "{path}"') return features_or_waveform @@ -178,7 +179,7 @@ def get_features_or_waveform(path: str, need_waveform=False): if len(extra) == 0: if need_waveform: - return get_waveform(_path) + return get_waveform(_path, always_2d=False) return get_features_from_npy_or_audio(_path) elif len(extra) == 2: extra = [int(i) for i in extra] From d031611ce49cb231653cf9246667ac237cbbdaff Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Wed, 10 Mar 2021 20:32:49 -0800 Subject: [PATCH 271/774] Update simul trans doc (#1683) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1683 Reviewed By: jmp84 Differential Revision: D26914869 Pulled By: xutaima fbshipit-source-id: a5d2efdcff1852e56304e77838840b3aad5124b0 --- .../docs/simulst_mustc_example.md | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/examples/speech_to_text/docs/simulst_mustc_example.md b/examples/speech_to_text/docs/simulst_mustc_example.md index 0144fcb766..3452806a1c 100644 --- a/examples/speech_to_text/docs/simulst_mustc_example.md +++ b/examples/speech_to_text/docs/simulst_mustc_example.md @@ -1,6 +1,6 @@ # Simultaneous Speech Translation (SimulST) on MuST-C -This is an instruction of training and evaluating a transformer *wait-k* simultaneous model on MUST-C English-Germen Dataset, from [SimulMT to SimulST: Adapting Simultaneous Text Translation to End-to-End Simultaneous Speech Translation](https://www.aclweb.org/anthology/2020.aacl-main.58.pdf). +This is a tutorial of training and evaluating a transformer *wait-k* simultaneous model on MUST-C English-Germen Dataset, from [SimulMT to SimulST: Adapting Simultaneous Text Translation to End-to-End Simultaneous Speech Translation](https://www.aclweb.org/anthology/2020.aacl-main.58.pdf). [MuST-C](https://www.aclweb.org/anthology/N19-1202) is multilingual speech-to-text translation corpus with 8-language translations on English TED talks. @@ -14,18 +14,21 @@ pip install pandas torchaudio sentencepiece # Generate TSV manifests, features, vocabulary, # global cepstral and mean estimation, # and configuration for each language +cd fairseq + python examples/speech_to_text/prep_mustc_data.py \ --data-root ${MUSTC_ROOT} --task asr \ --vocab-type unigram --vocab-size 10000 \ --cmvn-type global + python examples/speech_to_text/prep_mustc_data.py \ --data-root ${MUSTC_ROOT} --task st \ - --vocab-type unigram --vocab-size 10000 + --vocab-type unigram --vocab-size 10000 \ --cmvn-type global ``` ## ASR Pretraining -We just need a pretrained offline ASR model +We need a pretrained offline ASR model. Assuming the save directory of the ASR model is `${ASR_SAVE_DIR}` ``` fairseq-train ${MUSTC_ROOT}/en-de \ --config-yaml config_asr.yaml --train-subset train_asr --valid-subset dev_asr \ @@ -34,21 +37,22 @@ fairseq-train ${MUSTC_ROOT}/en-de \ --arch convtransformer_espnet --optimizer adam --lr 0.0005 --lr-scheduler inverse_sqrt \ --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 ``` +A pretrained ASR checkpoint can be downloaded [here](https://dl.fbaipublicfiles.com/simultaneous_translation/must_c_v1_en_de_pretrained_asr) ## Simultaneous Speech Translation Training ### Wait-K with fixed pre-decision module Fixed pre-decision indicates that the model operate simultaneous policy on the boundaries of fixed chunks. Here is a example of fixed pre-decision ratio 7 (the simultaneous decision is made every 7 encoder states) and -a wait-3 policy model -``` +a wait-3 policy model. Assuming the save directory is `${ST_SAVE_DIR}` +```bash fairseq-train ${MUSTC_ROOT}/en-de \ --config-yaml config_st.yaml --train-subset train_st --valid-subset dev_st \ --save-dir ${ST_SAVE_DIR} --num-workers 8 \ --optimizer adam --lr 0.0001 --lr-scheduler inverse_sqrt --clip-norm 10.0 \ --criterion label_smoothed_cross_entropy \ --warmup-updates 4000 --max-update 100000 --max-tokens 40000 --seed 2 \ - --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --load-pretrained-encoder-from ${ASR_SAVE_DIR}/checkpoint_best.pt \ --task speech_to_text \ --arch convtransformer_simul_trans_espnet \ --simul-type waitk_fixed_pre_decision \ @@ -76,7 +80,9 @@ a wait-3 policy model The source file is a list of paths of audio files, while target file is the corresponding translations. ``` -pip install simuleval +git clone https://github.com/facebookresearch/SimulEval.git +cd SimulEval +pip install -e . simuleval \ --agent examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -89,7 +95,24 @@ simuleval \ --scores ``` -A pretrained checkpoint can be downloaded from [here](https://dl.fbaipublicfiles.com/simultaneous_translation/convtransformer_wait5_pre7), which is a wait-5 model with a pre-decision of 280 ms. The databin (containing dictionary, gcmvn file and sentencepiece model) can be found [here](https://dl.fbaipublicfiles.com/simultaneous_translation/must_c_v1.0_en_de_databin). +A pretrained checkpoint can be downloaded from [here](https://dl.fbaipublicfiles.com/simultaneous_translation/convtransformer_wait5_pre7), which is a wait-5 model with a pre-decision of 280 ms. The databin (containing dictionary, gcmvn file and sentencepiece model) can be found [here](https://dl.fbaipublicfiles.com/simultaneous_translation/must_c_v1.0_en_de_databin.tgz). + +The output should be similar as follow: +```bash +{ + "Quality": { + "BLEU": 12.79214535384013 + }, + "Latency": { + "AL": 1669.5778120018108, + "AL_CA": 2077.9027656104813, + "AP": 0.7652936521983029, + "AP_CA": 0.8891561507382866, + "DAL": 2028.1566141735727, + "DAL_CA": 2497.336430059716 + } +} +``` The quality is measured by detokenized BLEU. So make sure that the predicted words sent to the server are detokenized. From 2235f86b40da5915cd801c4f2f29de4c17c9804b Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Fri, 12 Mar 2021 12:29:40 -0800 Subject: [PATCH 272/774] PlasmaView: don't materialize array in memory (#1645) Summary: ### Changes: - `PlasmaArray` saves the underlying data to `self.array`, `PlasmaView` never does that, instead it fetches the data from `plasma_store` shared memory when it is needed. - `PlasmaArray` starts a new, ephemeral plasma_store and puts a new array in it when it is pickled. If `--use-plasma-view`, there is one server started before `spawn` and arrays are only put into it once, in `PlasmaArray.__init__` to accommodate this. - user can now pass `--plasma-path` to explicitly control where server is started. - We now make plasma keys based on `(split_path, (block_size, document_sep_len, str(break_mode), len(dataset)))`, so two jobs sharing plasma server but with different datasets, or same dataset but different clargs, will read each the other's array. ### Results [pre March 1] This saves some CPU memory (5-15%), according to both `psutil` and `psrecord`: here we run base_cmd (below) with num_workers=0,2,8, 2 GPUS and collect the logs. `branch` refers to `--use-plasma-view`, `master` uses `PlasmaArray` ``` +-------------------------+----------------+---------+-------+ | setting | cpu_mem_used | wps | ppl | +=========================+================+=========+=======+ | branch_nw0_gpu2_ddm.log | 12 | 55143.2 | 429.1 | +-------------------------+----------------+---------+-------+ | branch_nw2_gpu2_ddm.log | 13.67 | 43377.6 | 429.1 | +-------------------------+----------------+---------+-------+ | branch_nw8_gpu2_ddm.log | 18.36 | 53019.9 | 429.1 | +-------------------------+----------------+---------+-------+ | master_nw0_gpu2_ddm.log | 12.26 | 56733 | 429.1 | +-------------------------+----------------+---------+-------+ | master_nw2_gpu2_ddm.log | 14.58 | 53337.9 | 429.1 | +-------------------------+----------------+---------+-------+ | master_nw8_gpu2_ddm.log | 21.1 | 53217.2 | 429.1 | +-------------------------+----------------+---------+-------+ ``` ### Replication 1) get this branch ```bash git fetch && git checkout share-plasma-server ``` 2) Train tiny model and save logs ```bash base_cmd () { fairseq-train --fp16 /private/home/sshleifer/data-bin/stories_mmap \ --task language_modeling \ --arch transformer_lm_gpt2_tiny \ --sample-break-mode complete --tokens-per-sample 512 \ --optimizer adam --clip-norm 0.0 --lr 0.0005 \ --batch-size 1 \ --max-update 200 --max-epoch 1 \ --log-format simple --log-interval 100 \ --restore-file x.pt --no-save \ --skip-invalid-size-inputs-valid-test --disable-validation $@ } USE_LOCK=1 CUDA_VISIBLE_DEVICES=0,1 base_cmd --num-workers 0 --use-plasma-view | tee branch_nw0_gpu2_ddm.log ``` ### TODO: - [x] test larger dataset - [x] make it optional, cleanup - [x] 1 GPU - [x] unit-tests - [x] ask hashing Q on stackoverflow https://stackoverflow.com/questions/66354598/deterministic-method-to-hash-np-array-int - [ ] measure whether `PlasmaArray` disable for small array's logic helps - [ x] test with fb_sweep - [ x] measure 4 GPU savings Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1645 Test Plan: Read github PR description: https://github.com/fairinternal/fairseq-py/pull/1645 Reviewed By: myleott Differential Revision: D26630365 Pulled By: sshleifer fbshipit-source-id: b0c4163fbc97a7aefb116de70265fba11f6d7b42 --- fairseq/data/plasma_utils.py | 134 +++++++++++++++++++++++++--- fairseq/data/token_block_dataset.py | 67 +++++++++----- fairseq/dataclass/configs.py | 83 +++++++---------- fairseq/tasks/language_modeling.py | 11 ++- fairseq/trainer.py | 5 +- fairseq_cli/train.py | 9 +- tests/test_plasma_utils.py | 127 ++++++++++++++++++++++++++ 7 files changed, 343 insertions(+), 93 deletions(-) create mode 100644 tests/test_plasma_utils.py diff --git a/fairseq/data/plasma_utils.py b/fairseq/data/plasma_utils.py index f4bb6472d7..b9fab3b739 100644 --- a/fairseq/data/plasma_utils.py +++ b/fairseq/data/plasma_utils.py @@ -3,11 +3,23 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. + import subprocess +import json import tempfile +import hashlib +from typing import Hashable + +try: + import pyarrow.plasma as plasma + + PYARROW_AVAILABLE = True +except ImportError: + plasma = None + PYARROW_AVAILABLE = False -class PlasmaArray(object): +class PlasmaArray: """ Wrapper around numpy arrays that automatically moves the data to shared memory upon serialization. This is particularly helpful when passing numpy @@ -31,12 +43,7 @@ def __init__(self, array): @property def plasma(self): if self._plasma is None and not self.disable: - try: - import pyarrow.plasma as plasma - - self._plasma = plasma - except ImportError: - self._plasma = None + self._plasma = plasma return self._plasma def start_server(self): @@ -47,13 +54,7 @@ def start_server(self): self._server_tmp = tempfile.NamedTemporaryFile() self.path = self._server_tmp.name self._server = subprocess.Popen( - [ - "plasma_store", - "-m", - str(int(1.05 * self.array.nbytes)), - "-s", - self.path, - ] + ["plasma_store", "-m", str(int(1.05 * self.array.nbytes)), "-s", self.path] ) @property @@ -64,6 +65,7 @@ def client(self): return self._client def __getstate__(self): + """Called on pickle load""" if self.plasma is None: return self.__dict__ if self.object_id is None: @@ -78,6 +80,7 @@ def __getstate__(self): return state def __setstate__(self, state): + """Called on pickle save""" self.__dict__.update(state) if self.plasma is None: return @@ -89,3 +92,106 @@ def __del__(self): self._server = None self._server_tmp.close() self._server_tmp = None + + +DEFAULT_PLASMA_PATH = "/tmp/plasma" + + +class PlasmaView: + """Interface to write and read from shared memory. Whereas PlasmaArray writes to plasma on serialization, + PlasmaView writes to shared memory on instantiation.""" + + def __init__(self, array, split_path: str, hash_data: Hashable, plasma_path=None): + """ + Args: + array: numpy array to store. This can be read with ``PlasmaView().array`` + split_path: the path whence the data was read, used for hashing + hash_data: other metadata about the array that can be used to create a unique key. + as of writing, the 3 callers in ``TokenBlockDataset`` use:: + + hash_data = ((block_size, document_sep_len, str(break_mode), len(dataset)), 0|1|2) + + + """ + assert PYARROW_AVAILABLE + assert split_path is not None + if plasma_path is None: + plasma_path = DEFAULT_PLASMA_PATH + + self.path = plasma_path + self.split_path = split_path + self._client = None # Initialize lazily for pickle. plasma clients should not be deep copied or serialized. + self._n = None + + self.object_id = self.get_object_id(self.split_path, hash_data) + try: + self.client.put(array, object_id=self.object_id) + except plasma.PlasmaObjectExists: + pass + + @property + def client(self): + if self._client is None: + self._client = plasma.connect(self.path, num_retries=200) + return self._client + + @property + def array(self): + """Fetch a read only view of an np.array, stored in plasma.""" + ret = self.client.get(self.object_id) + return ret + + @staticmethod + def get_object_id(split_path: str, hash_data: Hashable): + """Returns plasma.ObjectID from hashing split_path and object_num.""" + hash = hashlib.blake2b(bytes(split_path, "utf-8"), digest_size=20) + harg = json.dumps(hash_data).encode("utf-8") + hash.update(harg) + return plasma.ObjectID(hash.digest()) + + def __getstate__(self): + """Called on pickle save""" + self.disconnect() + state = self.__dict__.copy() + assert state["_client"] is None + assert "object_id" in state + return state + + def __setstate__(self, state): + """Called on pickle load""" + self.__dict__.update(state) + + def __del__(self): + self.disconnect() + + def disconnect(self): + if self._client is not None: + self._client.disconnect() + self._client = None + + def __len__(self): + """Save reads by caching len""" + if self._n is None: + self._n = len(self.array) + return self._n + + +GB100 = (1024 ** 3) * 100 + + +class PlasmaStore: + def __init__(self, path=DEFAULT_PLASMA_PATH, nbytes: int = GB100): + + self.server = self.start(path, nbytes) + + def __del__(self): + self.server.kill() + + @staticmethod + def start(path=DEFAULT_PLASMA_PATH, nbytes: int = GB100) -> subprocess.Popen: + if not PYARROW_AVAILABLE: + raise ImportError("please run pip install pyarrow to use --use_plasma_view") + # best practice is to allocate more space than we need. The limitation seems to be the size of /dev/shm + _server = subprocess.Popen(["plasma_store", "-m", str(nbytes), "-s", path]) + plasma.connect(path, num_retries=200) # If we can't connect we fail immediately + return _server diff --git a/fairseq/data/token_block_dataset.py b/fairseq/data/token_block_dataset.py index ce0a0d1114..d2c65fd7e0 100644 --- a/fairseq/data/token_block_dataset.py +++ b/fairseq/data/token_block_dataset.py @@ -7,6 +7,7 @@ import torch from fairseq.data import FairseqDataset, plasma_utils from fairseq.data.indexed_dataset import best_fitting_int_dtype +from typing import Tuple class TokenBlockDataset(FairseqDataset): @@ -42,7 +43,46 @@ def __init__( break_mode=None, include_targets=False, document_sep_len=1, + use_plasma_view=False, + split_path=None, + plasma_path=None, ): + + super().__init__() + self.dataset = dataset + self.pad = pad + self.eos = eos + self.include_targets = include_targets + + assert len(dataset) > 0 + + assert len(dataset) == len(sizes) + _sizes, block_to_dataset_index, slice_indices = self._build_slice_indices( + sizes, break_mode, document_sep_len, block_size + ) + if use_plasma_view: + plasma_id = (block_size, document_sep_len, str(break_mode), len(dataset)) + self._slice_indices = plasma_utils.PlasmaView( + slice_indices, split_path, (plasma_id, 0), plasma_path=plasma_path + ) + self._sizes = plasma_utils.PlasmaView( + _sizes, split_path, (plasma_id, 1), plasma_path=plasma_path + ) + self._block_to_dataset_index = plasma_utils.PlasmaView( + block_to_dataset_index, split_path, (plasma_id, 2), plasma_path=plasma_path, + ) + else: + self._slice_indices = plasma_utils.PlasmaArray(slice_indices) + self._sizes = plasma_utils.PlasmaArray(_sizes) + self._block_to_dataset_index = plasma_utils.PlasmaArray( + block_to_dataset_index + ) + + @staticmethod + def _build_slice_indices( + sizes, break_mode, document_sep_len, block_size + ) -> Tuple[np.ndarray]: + """Use token_block_utils_fast to build arrays for indexing into self.dataset""" try: from fairseq.data.token_block_utils_fast import ( _get_slice_indices_fast, @@ -54,15 +94,6 @@ def __init__( "or `python setup.py build_ext --inplace`" ) - super().__init__() - self.dataset = dataset - self.pad = pad - self.eos = eos - self.include_targets = include_targets - - assert len(dataset) == len(sizes) - assert len(dataset) > 0 - if isinstance(sizes, list): sizes = np.array(sizes, dtype=np.int64) else: @@ -79,7 +110,7 @@ def __init__( slice_indices = _get_slice_indices_fast( sizes, str(break_mode), block_size, document_sep_len ) - self._sizes = slice_indices[:, 1] - slice_indices[:, 0] + _sizes = slice_indices[:, 1] - slice_indices[:, 0] # build index mapping block indices to the underlying dataset indices if break_mode == "eos": @@ -99,15 +130,12 @@ def __init__( sizes, slice_indices, ) size_dtype = np.uint16 if block_size < 65535 else np.uint32 - slice_indices_dtype = best_fitting_int_dtype(slice_indices[-1].max()) - - self._slice_indices = plasma_utils.PlasmaArray( - slice_indices.astype(slice_indices_dtype) - ) - self._sizes = plasma_utils.PlasmaArray(self._sizes.astype(size_dtype)) - self._block_to_dataset_index = plasma_utils.PlasmaArray( - block_to_dataset_index.astype(slice_indices_dtype) - ) + num_tokens = slice_indices[-1].max() + slice_indices_dtype = best_fitting_int_dtype(num_tokens) + slice_indices = slice_indices.astype(slice_indices_dtype) + _sizes = _sizes.astype(size_dtype) + block_to_dataset_index = block_to_dataset_index.astype(slice_indices_dtype) + return _sizes, block_to_dataset_index, slice_indices @property def slice_indices(self): @@ -131,7 +159,6 @@ def __getitem__(self, index): buffer = torch.cat( [self.dataset[idx] for idx in range(start_ds_idx, end_ds_idx + 1)] ) - slice_s, slice_e = self.slice_indices[index] length = slice_e - slice_s s, e = start_offset, start_offset + length diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 5d6aee157a..3c29be9197 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -104,15 +104,10 @@ class CommonConfig(FairseqDataclass): ) wandb_project: Optional[str] = field( default=None, - metadata={ - "help": "Weights and Biases project name to use for logging" - }, + metadata={"help": "Weights and Biases project name to use for logging"}, ) azureml_logging: Optional[bool] = field( - default=False, - metadata={ - "help": "Log scalars to AzureML context" - }, + default=False, metadata={"help": "Log scalars to AzureML context"}, ) seed: int = field( default=1, metadata={"help": "pseudo random number generator seed"} @@ -192,6 +187,15 @@ class CommonConfig(FairseqDataclass): "main method can return a value (useful for sweeps)" }, ) + use_plasma_view: bool = field( + default=False, metadata={"help": "Store indices and sizes in shared memory"} + ) + plasma_path: Optional[str] = field( + default="/tmp/plasma", + metadata={ + "help": "path to run plasma_store, defaults to /tmp/plasma. Paths outside /tmp tend to fail." + }, + ) @dataclass @@ -263,7 +267,7 @@ class DistributedTrainingConfig(FairseqDataclass): metadata={ "help": "kill the job if no progress is made in N seconds; " "set to -1 to disable" - } + }, ) broadcast_buffers: bool = field( default=False, @@ -360,16 +364,13 @@ class DistributedTrainingConfig(FairseqDataclass): tpu: bool = II("common.tpu") # configuration for --ddp-backend=fully_sharded no_reshard_after_forward: bool = field( - default=False, - metadata={"help": "don't reshard parameters after forward pass"}, + default=False, metadata={"help": "don't reshard parameters after forward pass"}, ) fp32_reduce_scatter: bool = field( - default=False, - metadata={"help": "reduce-scatter grads in FP32"}, + default=False, metadata={"help": "reduce-scatter grads in FP32"}, ) cpu_offload: bool = field( - default=False, - metadata={"help": "offload FP32 params to CPU"} + default=False, metadata={"help": "offload FP32 params to CPU"} ) @@ -665,12 +666,10 @@ class FairseqBMUFConfig(FairseqDataclass): @dataclass class GenerationConfig(FairseqDataclass): beam: int = field( - default=5, - metadata={"help": "beam size"}, + default=5, metadata={"help": "beam size"}, ) nbest: int = field( - default=1, - metadata={"help": "number of hypotheses to output"}, + default=1, metadata={"help": "number of hypotheses to output"}, ) max_len_a: float = field( default=0, @@ -685,24 +684,19 @@ class GenerationConfig(FairseqDataclass): }, ) min_len: int = field( - default=1, - metadata={"help": "minimum generation length"}, + default=1, metadata={"help": "minimum generation length"}, ) match_source_len: bool = field( - default=False, - metadata={"help": "generations should match the source length"}, + default=False, metadata={"help": "generations should match the source length"}, ) unnormalized: bool = field( - default=False, - metadata={"help": "compare unnormalized hypothesis scores"}, + default=False, metadata={"help": "compare unnormalized hypothesis scores"}, ) no_early_stop: bool = field( - default=False, - metadata={"help": "deprecated"}, + default=False, metadata={"help": "deprecated"}, ) no_beamable_mm: bool = field( - default=False, - metadata={"help": "don't use BeamableMM in attention layers"}, + default=False, metadata={"help": "don't use BeamableMM in attention layers"}, ) lenpen: float = field( default=1, @@ -724,12 +718,10 @@ class GenerationConfig(FairseqDataclass): }, ) sacrebleu: bool = field( - default=False, - metadata={"help": "score with sacrebleu"}, + default=False, metadata={"help": "score with sacrebleu"}, ) score_reference: bool = field( - default=False, - metadata={"help": "just score the reference translation"}, + default=False, metadata={"help": "just score the reference translation"}, ) prefix_size: int = field( default=0, @@ -763,12 +755,10 @@ class GenerationConfig(FairseqDataclass): }, ) temperature: float = field( - default=1.0, - metadata={"help": "temperature for generation"}, + default=1.0, metadata={"help": "temperature for generation"}, ) diverse_beam_groups: int = field( - default=-1, - metadata={"help": "number of groups for Diverse Beam Search"}, + default=-1, metadata={"help": "number of groups for Diverse Beam Search"}, ) diverse_beam_strength: float = field( default=0.5, @@ -787,16 +777,13 @@ class GenerationConfig(FairseqDataclass): }, ) print_step: bool = field( - default=False, - metadata={"help": "print steps"}, + default=False, metadata={"help": "print steps"}, ) lm_path: Optional[str] = field( - default=None, - metadata={"help": "path to lm checkpoint for lm fusion"}, + default=None, metadata={"help": "path to lm checkpoint for lm fusion"}, ) lm_weight: float = field( - default=0.0, - metadata={"help": "weight for lm probs for lm fusion"}, + default=0.0, metadata={"help": "weight for lm probs for lm fusion"}, ) # arguments for iterative refinement generator @@ -805,8 +792,7 @@ class GenerationConfig(FairseqDataclass): metadata={"help": "if > 0.0, it penalized early-stopping in decoding."}, ) iter_decode_max_iter: int = field( - default=10, - metadata={"help": "maximum iterations for iterative refinement."}, + default=10, metadata={"help": "maximum iterations for iterative refinement."}, ) iter_decode_force_max_iter: bool = field( default=False, @@ -833,8 +819,7 @@ class GenerationConfig(FairseqDataclass): }, ) retain_dropout: bool = field( - default=False, - metadata={"help": "Use dropout at inference time"}, + default=False, metadata={"help": "Use dropout at inference time"}, ) # temporarily set to Any until https://github.com/facebookresearch/hydra/issues/1117 is fixed # retain_dropout_modules: Optional[List[str]] = field( @@ -859,8 +844,7 @@ class GenerationConfig(FairseqDataclass): @dataclass class CommonEvalConfig(FairseqDataclass): path: Optional[str] = field( - default=None, - metadata={"help": "path(s) to model file(s), colon separated"}, + default=None, metadata={"help": "path(s) to model file(s), colon separated"}, ) post_process: Optional[str] = field( default=None, @@ -922,8 +906,7 @@ class InteractiveConfig(FairseqDataclass): }, ) input: str = field( - default="-", - metadata={"help": "file to read from; use - for stdin"}, + default="-", metadata={"help": "file to read from; use - for stdin"}, ) diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index 579bf69785..a3847733a1 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -91,6 +91,8 @@ class LanguageModelingConfig(FairseqDataclass): ) data_buffer_size: int = II("dataset.data_buffer_size") tpu: bool = II("common.tpu") + use_plasma_view: bool = II("common.use_plasma_view") + plasma_path: str = II("common.plasma_path") @register_task("language_modeling", dataclass=LanguageModelingConfig) @@ -198,13 +200,12 @@ def load_dataset( data_path = paths[(epoch - 1) % len(paths)] split_path = os.path.join(data_path, split) + # each process has its own copy of the raw data (likely to be an np.memmap) dataset = data_utils.load_indexed_dataset( split_path, self.dictionary, self.args.dataset_impl, combine=combine ) if dataset is None: - raise FileNotFoundError( - "Dataset not found: {} ({})".format(split, split_path) - ) + raise FileNotFoundError(f"Dataset not found: {split} ({split_path})") dataset = maybe_shorten_dataset( dataset, @@ -214,7 +215,6 @@ def load_dataset( self.args.tokens_per_sample, self.args.seed, ) - dataset = TokenBlockDataset( dataset, dataset.sizes, @@ -223,6 +223,9 @@ def load_dataset( eos=self.dictionary.eos(), break_mode=self.args.sample_break_mode, include_targets=True, + use_plasma_view=self.args.use_plasma_view, + split_path=split_path, + plasma_path=self.args.plasma_path, ) add_eos_for_other_targets = ( diff --git a/fairseq/trainer.py b/fairseq/trainer.py index dcf5305455..ee29ed65a8 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -1165,10 +1165,7 @@ def _all_gather_list_sync( return logging_outputs, extra_stats_to_sum def _fast_stat_sync_sum( - self, - logging_outputs: List[Dict[str, Any]], - *extra_stats_to_sum, - ignore=False, + self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, ): """ Sync logging outputs across workers. fast_stat_sync_sum is diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index d770e4e4ec..d618817e46 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -24,6 +24,7 @@ utils, ) from fairseq.data import iterators +from fairseq.data.plasma_utils import PlasmaStore from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.distributed import fsdp_enable_wrap, fsdp_wrap, utils as distributed_utils @@ -118,7 +119,6 @@ def main(cfg: FairseqConfig) -> None: trainer = Trainer(cfg, task, model, criterion, quantizer) else: trainer = MegatronTrainer(cfg, task, model, criterion) - logger.info( "training on {} devices (GPUs/TPUs)".format( cfg.distributed_training.distributed_world_size @@ -465,6 +465,10 @@ def cli_main( cfg = convert_namespace_to_omegaconf(args) + if cfg.common.use_plasma_view: + server = PlasmaStore(path=cfg.common.plasma_path) + logger.info(f"Started plasma server pid {server.server.pid} {cfg.common.plasma_path}") + if args.profile: with torch.cuda.profiler.profile(): with torch.autograd.profiler.emit_nvtx(): @@ -472,6 +476,9 @@ def cli_main( else: distributed_utils.call_main(cfg, main) + # if cfg.common.use_plasma_view: + # server.server.kill() + if __name__ == "__main__": cli_main() diff --git a/tests/test_plasma_utils.py b/tests/test_plasma_utils.py new file mode 100644 index 0000000000..5737530e3d --- /dev/null +++ b/tests/test_plasma_utils.py @@ -0,0 +1,127 @@ +import contextlib +import unittest +import tempfile +from io import StringIO + +import numpy as np + +from tests.test_binaries import train_language_model +from tests.utils import create_dummy_data, preprocess_lm_data + +try: + from pyarrow import plasma + from fairseq.data.plasma_utils import PlasmaView, PlasmaStore + + PYARROW_AVAILABLE = True +except ImportError: + PYARROW_AVAILABLE = False + +dummy_path = 'dummy' + + +@unittest.skipUnless(PYARROW_AVAILABLE, "") +class TestPlasmaView(unittest.TestCase): + def setUp(self) -> None: + self.tmp_file = tempfile.NamedTemporaryFile() # noqa: P201 + self.path = self.tmp_file.name + self.server = PlasmaStore.start(path=self.path) + self.client = plasma.connect(self.path, num_retries=10) + + def tearDown(self) -> None: + self.client.disconnect() + self.tmp_file.close() + self.server.kill() + + def test_two_servers_do_not_share_object_id_space(self): + data_server_1 = np.array([0, 1]) + data_server_2 = np.array([2, 3]) + server_2_path = self.path + with tempfile.NamedTemporaryFile() as server_1_path: + server = PlasmaStore.start(path=server_1_path.name, nbytes=10000) + arr1 = PlasmaView( + data_server_1, dummy_path, 1, plasma_path=server_1_path.name + ) + assert len(arr1.client.list()) == 1 + assert (arr1.array == data_server_1).all() + arr2 = PlasmaView(data_server_2, dummy_path, 1, plasma_path=server_2_path) + assert (arr2.array == data_server_2).all() + assert (arr1.array == data_server_1).all() + server.kill() + + def test_hash_collision(self): + data_server_1 = np.array([0, 1]) + data_server_2 = np.array([2, 3]) + arr1 = PlasmaView(data_server_1, dummy_path, 1, plasma_path=self.path) + assert len(arr1.client.list()) == 1 + arr2 = PlasmaView(data_server_2, dummy_path, 1, plasma_path=self.path) + assert len(arr1.client.list()) == 1 + assert len(arr2.client.list()) == 1 + assert (arr2.array == data_server_1).all() + # New hash key based on tuples + arr3 = PlasmaView( + data_server_2, dummy_path, (1, 12312312312, None), plasma_path=self.path + ) + assert ( + len(arr2.client.list()) == 2 + ), "No new object was created by using a novel hash key" + assert ( + arr3.object_id in arr2.client.list() + ), "No new object was created by using a novel hash key" + assert ( + arr3.object_id in arr3.client.list() + ), "No new object was created by using a novel hash key" + del arr3, arr2, arr1 + + @staticmethod + def _assert_view_equal(pv1, pv2): + np.testing.assert_array_equal(pv1.array, pv2.array) + + def test_putting_same_array_twice(self): + data = np.array([4, 4, 4]) + arr1 = PlasmaView(data, dummy_path, 1, plasma_path=self.path) + assert len(self.client.list()) == 1 + arr1b = PlasmaView( + data, dummy_path, 1, plasma_path=self.path + ) # should not change contents of store + arr1c = PlasmaView( + None, dummy_path, 1, plasma_path=self.path + ) # should not change contents of store + + assert len(self.client.list()) == 1 + self._assert_view_equal(arr1, arr1b) + self._assert_view_equal(arr1, arr1c) + PlasmaView( + data, dummy_path, 2, plasma_path=self.path + ) # new object id, adds new entry + assert len(self.client.list()) == 2 + + new_client = plasma.connect(self.path) + assert len(new_client.list()) == 2 # new client can access same objects + assert isinstance(arr1.object_id, plasma.ObjectID) + del arr1b + del arr1c + + def test_plasma_store_full_raises(self): + with tempfile.NamedTemporaryFile() as new_path: + server = PlasmaStore.start(path=new_path.name, nbytes=10000) + with self.assertRaises(plasma.PlasmaStoreFull): + # 2000 floats is more than 2000 bytes + PlasmaView( + np.random.rand(10000, 1), dummy_path, 1, plasma_path=new_path.name + ) + server.kill() + + def test_object_id_overflow(self): + PlasmaView.get_object_id("", 2 ** 21) + + def test_training_lm_plasma(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_transformer_lm") as data_dir: + create_dummy_data(data_dir) + preprocess_lm_data(data_dir) + train_language_model( + data_dir, + "transformer_lm", + ["--use-plasma-view", "--plasma-path", self.path], + run_validation=True, + ) From 252d5a9ae93e68254cfb1896fb5624cf11cda15e Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Fri, 12 Mar 2021 16:45:40 -0800 Subject: [PATCH 273/774] Fix a bug that FairseqSimulSTAgent is not an agent (#1690) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1690 Reviewed By: jmp84 Differential Revision: D27025669 Pulled By: xutaima fbshipit-source-id: 8125365adedfdc938813d08e911e1f6ebe4f584b --- .../agents/fairseq_simul_st_agent.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index 2b5fdc2d3f..8b8003e1d5 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -10,12 +10,11 @@ try: from simuleval import READ_ACTION, WRITE_ACTION, DEFAULT_EOS + from simuleval.agents import SpeechAgent from simuleval.states import ListEntry, SpeechStates except ImportError: print("Please install simuleval 'pip install simuleval'") -from torch import nn - SHIFT_SIZE = 10 WINDOW_SIZE = 25 SAMPLE_RATE = 16000 @@ -65,7 +64,7 @@ def __call__(self, new_samples): input_samples = samples[:effective_num_samples] self.previous_residual_samples = samples[ - num_frames * self.num_samples_per_shift : + num_frames * self.num_samples_per_shift: ] torch.manual_seed(1) @@ -113,12 +112,12 @@ def info(self): } -class FairseqSimulSTAgent(nn.Module): +class FairseqSimulSTAgent(SpeechAgent): speech_segment_size = 40 # in ms, 4 pooling ratio * 10 ms step size def __init__(self, args): - super().__init__() + super().__init__(args) self.eos = DEFAULT_EOS @@ -218,6 +217,9 @@ def load_model_vocab(self, args): task_args = state["cfg"]["task"] task_args.data = args.data_bin + if args.config is not None: + task_args.config_yaml = args.config + task = self.set_up_task(task_args) # build model for ensemble From 965240c784910895b05e66d7ef7e15321050b414 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Sun, 14 Mar 2021 20:55:46 -0700 Subject: [PATCH 274/774] optimize memory when loading large checkpoints by deleting state dict early Summary: I had some issues with loading checkpoints from 5B parameter models (60 GB checkpoint files) due to OOM. Reviewed By: myleott Differential Revision: D27027616 fbshipit-source-id: 2b816e8e46ec80f0ec721aa7a6702cee531b94eb --- fairseq/trainer.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index ee29ed65a8..1c4c532dd0 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -442,10 +442,14 @@ def load_checkpoint( self.model.load_state_dict( state["model"], strict=True, model_cfg=self.cfg.model ) + # save memory for later steps + del state["model"] if utils.has_parameters(self.get_criterion()): self.get_criterion().load_state_dict( state["criterion"], strict=True ) + del state["criterion"] + except Exception: raise Exception( "Cannot load model parameters from checkpoint {}; " From dd74992d0d143155998e9ed4076826bcea80fb06 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Mon, 15 Mar 2021 23:44:19 -0700 Subject: [PATCH 275/774] Several updates for simul speech transition example (#1703) Summary: Fix sever issues in simul speech transition example, including - Load pretrained encoder with when loading model. - Generating broken config.yaml when using gcvm. - Fix the preprocessed databin. - Fix some errors in the instructions. - Add detailed instructions on evaluation a pretrained model. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1703 Reviewed By: jmp84 Differential Revision: D27071600 Pulled By: xutaima fbshipit-source-id: bfe72005190d7936caeef4f805bd99c8d2cf9c37 --- examples/speech_to_text/data_utils.py | 4 +- .../docs/simulst_mustc_example.md | 72 ++++++++++++++++--- .../agents/fairseq_simul_st_agent.py | 9 ++- 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index 3f96ffc427..2bcff046f7 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -168,7 +168,7 @@ def gen_config_yaml( assert gcmvn_path is not None, ( 'Please provide path of global cmvn file.' ) - writer.set_global_cmvn(gcmvn_path) + writer.set_global_cmvn(str(gcmvn_path)) if len(audio_root) > 0: writer.set_audio_root(audio_root) @@ -325,7 +325,7 @@ def set_bpe_tokenizer(self, bpe_tokenizer: Dict[str, Any]): self.config["bpe_tokenizer"] = bpe_tokenizer def set_global_cmvn(self, stats_npz_path: str): - self.config["stats_npz_path"] = stats_npz_path + self.config["global_cmvn"] = {"stats_npz_path": stats_npz_path} def set_feature_transforms(self, split: str, transforms: List[str]): if "transforms" not in self.config: diff --git a/examples/speech_to_text/docs/simulst_mustc_example.md b/examples/speech_to_text/docs/simulst_mustc_example.md index 3452806a1c..22f359abe3 100644 --- a/examples/speech_to_text/docs/simulst_mustc_example.md +++ b/examples/speech_to_text/docs/simulst_mustc_example.md @@ -5,6 +5,9 @@ This is a tutorial of training and evaluating a transformer *wait-k* simultaneou [MuST-C](https://www.aclweb.org/anthology/N19-1202) is multilingual speech-to-text translation corpus with 8-language translations on English TED talks. ## Data Preparation +This section introduces the data preparation for training and evaluation. +If you only want to evaluate the model, please jump to [Inference & Evaluation](#inference-&-evaluation) + [Download](https://ict.fbk.eu/must-c) and unpack MuST-C data to a path `${MUSTC_ROOT}/en-${TARGET_LANG_ID}`, then preprocess it with ```bash @@ -77,25 +80,74 @@ a wait-3 policy model. Assuming the save directory is `${ST_SAVE_DIR}` ``` ## Inference & Evaluation [SimulEval](https://github.com/facebookresearch/SimulEval) is used for evaluation. -The source file is a list of paths of audio files, -while target file is the corresponding translations. +The following command is for evaluation. + ``` git clone https://github.com/facebookresearch/SimulEval.git cd SimulEval pip install -e . simuleval \ - --agent examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py - --src-file ${SRC_LIST_OF_AUDIO} - --tgt-file ${TGT_FILE} + --agent ${FAIRSEQ}/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py + --source ${SRC_LIST_OF_AUDIO} + --target ${TGT_FILE} --data-bin ${MUSTC_ROOT}/en-de \ + --config config_st.yaml \ --model-path ${ST_SAVE_DIR}/${CHECKPOINT_FILENAME} \ - --tgt-splitter-type SentencePieceModel \ - --tgt-splitter-path ${MUSTC_ROOT}/en-de/spm.model \ + --output ${OUTPUT} \ --scores ``` -A pretrained checkpoint can be downloaded from [here](https://dl.fbaipublicfiles.com/simultaneous_translation/convtransformer_wait5_pre7), which is a wait-5 model with a pre-decision of 280 ms. The databin (containing dictionary, gcmvn file and sentencepiece model) can be found [here](https://dl.fbaipublicfiles.com/simultaneous_translation/must_c_v1.0_en_de_databin.tgz). +The source file `${SRC_LIST_OF_AUDIO}` is a list of paths of audio files. Assuming your audio files stored at `/home/user/data`, +it should look like this + +```bash +/home/user/data/audio-1.wav +/home/user/data/audio-2.wav +``` + +Each line of target file `${TGT_FILE}` is the translation for each audio file input. +```bash +Translation_1 +Translation_2 +``` + +The `--data-bin` and `--config` should be the same in previous section if you prepare the data from the scratch. +If only for evaluation, a prepared data directory can be found [here](https://dl.fbaipublicfiles.com/simultaneous_translation/must_c_v1.0_en_de_databin.tgz). It contains +- `spm_unigram10000_st.model`: a sentencepiece model binary. +- `spm_unigram10000_st.txt`: the dictionary file generated by the sentencepiece model. +- `gcmvn.npz`: the binary for global cepstral mean and variance. +- `config_st.yaml`: the config yaml file. It looks like this. +You will need to set the absolute paths for `sentencepiece_model` and `stats_npz_path` if the data directory is downloaded. +```yaml +bpe_tokenizer: + bpe: sentencepiece + sentencepiece_model: ABS_PATH_TO_SENTENCEPIECE_MODEL +global_cmvn: + stats_npz_path: ABS_PATH_TO_GCMVN_FILE +input_channels: 1 +input_feat_per_channel: 80 +sampling_alpha: 1.0 +specaugment: + freq_mask_F: 27 + freq_mask_N: 1 + time_mask_N: 1 + time_mask_T: 100 + time_mask_p: 1.0 + time_wrap_W: 0 +transforms: + '*': + - global_cmvn + _train: + - global_cmvn + - specaugment +vocab_filename: spm_unigram10000_st.txt +``` + +Notice that once a `--data-bin` is set, the `--config` is the base name of the config yaml, not the full path. + +Set `--model-path` to the model checkpoint. +A pretrained checkpoint can be downloaded from [here](https://dl.fbaipublicfiles.com/simultaneous_translation/convtransformer_wait5_pre7), which is a wait-5 model with a pre-decision of 280 ms. The output should be similar as follow: ```bash @@ -114,10 +166,14 @@ The output should be similar as follow: } ``` +If `--output ${OUTPUT}` option is used, the detailed log and scores will be stored under the `${OUTPUT}` directory. + + The quality is measured by detokenized BLEU. So make sure that the predicted words sent to the server are detokenized. The latency metrics are * Average Proportion * Average Lagging * Differentiable Average Lagging + Again they will also be evaluated on detokenized text. diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index 8b8003e1d5..9ff07775da 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -138,7 +138,7 @@ def __init__(self, args): args.global_cmvn = None if args.config: - with open(args.config, "r") as f: + with open(os.path.join(args.data_bin, args.config), "r") as f: config = yaml.load(f, Loader=yaml.BaseLoader) if "global_cmvn" in config: @@ -203,9 +203,6 @@ def add_args(parser): # fmt: on return parser - def set_up_task(self, task_args): - return tasks.setup_task(task_args) - def load_model_vocab(self, args): filename = args.model_path @@ -220,9 +217,11 @@ def load_model_vocab(self, args): if args.config is not None: task_args.config_yaml = args.config - task = self.set_up_task(task_args) + task = tasks.setup_task(task_args) # build model for ensemble + state["cfg"]["model"].load_pretrained_encoder_from = None + state["cfg"]["model"].load_pretrained_decoder_from = None self.model = task.build_model(state["cfg"]["model"]) self.model.load_state_dict(state["model"], strict=True) self.model.eval() From edcef1306b48e7fa9bf84dcbec25171a1e57a5dc Mon Sep 17 00:00:00 2001 From: Jongsoo Park <jongsoo@fb.com> Date: Wed, 17 Mar 2021 20:02:30 -0700 Subject: [PATCH 276/774] make deepspeed cpu_adam works in fbcode Summary: To test cpu-offload + fsdp in fairseq Differential Revision: D26873232 fbshipit-source-id: 8d4dee874713a055bb6b6541cddcbfd722eef9f8 --- fairseq/optim/cpu_adam.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py index 5e935df1a5..9637a78666 100644 --- a/fairseq/optim/cpu_adam.py +++ b/fairseq/optim/cpu_adam.py @@ -12,12 +12,14 @@ from fairseq.dataclass import FairseqDataclass from fairseq.optim import FairseqOptimizer, register_optimizer from omegaconf import II, DictConfig +import logging try: - from deepspeed.ops.op_builder import CPUAdamBuilder + import deepspeed.op_extensions.cpu_adam as ds_opt_adam has_deepspeed_cpu_adam = True -except ImportError: +except ImportError as e: + logging.warning(e) has_deepspeed_cpu_adam = False @@ -101,7 +103,7 @@ def __init__( self.opt_id = CPUAdam.optimizer_id CPUAdam.optimizer_id = CPUAdam.optimizer_id + 1 - self.ds_opt_adam = CPUAdamBuilder().load() + self.ds_opt_adam = ds_opt_adam adamw_mode = True self.ds_opt_adam.create_adam( self.opt_id, lr, betas[0], betas[1], eps, weight_decay, adamw_mode From 53b781caad3d58cd7fefed80e17faf147d15da66 Mon Sep 17 00:00:00 2001 From: Juan Miguel Pino <juancarabina@fb.com> Date: Fri, 19 Mar 2021 09:35:09 -0700 Subject: [PATCH 277/774] Add --update-freq 8 to simulst tutorial (#3374) Summary: Clarify that training is done on 1 GPU. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3374 Reviewed By: kahne Differential Revision: D27183474 Pulled By: jmp84 fbshipit-source-id: 330ec9b6510dcbd1f38a7c1c954d7504c6de3dda --- examples/speech_to_text/docs/simulst_mustc_example.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/speech_to_text/docs/simulst_mustc_example.md b/examples/speech_to_text/docs/simulst_mustc_example.md index 22f359abe3..d83ec086f9 100644 --- a/examples/speech_to_text/docs/simulst_mustc_example.md +++ b/examples/speech_to_text/docs/simulst_mustc_example.md @@ -31,7 +31,8 @@ python examples/speech_to_text/prep_mustc_data.py \ ``` ## ASR Pretraining -We need a pretrained offline ASR model. Assuming the save directory of the ASR model is `${ASR_SAVE_DIR}` +We need a pretrained offline ASR model. Assuming the save directory of the ASR model is `${ASR_SAVE_DIR}`. +The following command (and the subsequent training commands in this tutorial) assume training on 1 GPU (you can also train on 8 GPUs and remove the `--update-freq 8` option). ``` fairseq-train ${MUSTC_ROOT}/en-de \ --config-yaml config_asr.yaml --train-subset train_asr --valid-subset dev_asr \ @@ -60,7 +61,8 @@ a wait-3 policy model. Assuming the save directory is `${ST_SAVE_DIR}` --arch convtransformer_simul_trans_espnet \ --simul-type waitk_fixed_pre_decision \ --waitk-lagging 3 \ - --fixed-pre-decision-ratio 7 + --fixed-pre-decision-ratio 7 \ + --update-freq 8 ``` ### Monotonic multihead attention with fixed pre-decision module @@ -76,7 +78,8 @@ a wait-3 policy model. Assuming the save directory is `${ST_SAVE_DIR}` --latency-weight-avg 0.1 \ --arch convtransformer_simul_trans_espnet \ --simul-type infinite_lookback_fixed_pre_decision \ - --fixed-pre-decision-ratio 7 + --fixed-pre-decision-ratio 7 \ + --update-freq 8 ``` ## Inference & Evaluation [SimulEval](https://github.com/facebookresearch/SimulEval) is used for evaluation. From 5c87bb5ce81dbc051a37e50bca3da40633149f26 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Sat, 20 Mar 2021 15:00:56 -0700 Subject: [PATCH 278/774] Fix RoBERTa + FSDP (also minor fix for GPT-3 configs) (#1724) Summary: There will also be a fix on the fairscale side to fix the segfault with FSDP. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1724 Reviewed By: sshleifer Differential Revision: D27189594 Pulled By: myleott fbshipit-source-id: 7a0ccadf8e2104cc782faccb55756deddb2dd346 --- fairseq/models/roberta/model.py | 3 --- fairseq/models/transformer.py | 2 +- fairseq/models/transformer_lm.py | 5 ++++- fairseq/modules/fairseq_dropout.py | 2 +- fairseq/modules/transformer_sentence_encoder.py | 17 ++++++++++++----- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 5d2ed4902d..5b9ba8105f 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -458,9 +458,6 @@ def build_encoder(self, args, dictionary, embed_tokens): def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): return RobertaLMHead(embed_dim, output_dim, activation_fn, weight) - def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): - return RobertaLMHead(embed_dim, output_dim, activation_fn, weight) - def forward( self, src_tokens, diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 297807c31a..1e47d102f9 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -511,7 +511,7 @@ def forward_scriptable( x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) # account for padding while computing the representation - if encoder_padding_mask is not None: + if has_pads: x = x * (1 - encoder_padding_mask.unsqueeze(-1).type_as(x)) # B x T x C -> T x B x C diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index fca9470e5e..d2c0cff493 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -449,11 +449,14 @@ def transformer_lm_gpt2_big(args): def base_gpt3_architecture(args): + args.decoder_input_dim = args.decoder_embed_dim + args.decoder_output_dim = args.decoder_embed_dim args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", args.decoder_embed_dim * 4) args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) args.dropout = getattr(args, "dropout", 0.0) args.attention_dropout = getattr(args, "attention_dropout", 0.0) args.activation_fn = getattr(args, "activation_fn", "gelu") + args.share_decoder_input_output_embed = True base_lm_architecture(args) @@ -489,7 +492,7 @@ def transformer_lm_gpt3_xl(args): # 1.3B params args.decoder_layers = getattr(args, "decoder_layers", 24) args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 2048) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 24) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) base_gpt3_architecture(args) diff --git a/fairseq/modules/fairseq_dropout.py b/fairseq/modules/fairseq_dropout.py index f070a804e6..3cddca7718 100644 --- a/fairseq/modules/fairseq_dropout.py +++ b/fairseq/modules/fairseq_dropout.py @@ -21,7 +21,7 @@ def __init__(self, p, module_name=None): self.apply_during_inference = False def forward(self, x, inplace: bool = False): - if self.training or self.apply_during_inference: + if self.p > 0 and (self.training or self.apply_during_inference): return F.dropout(x, p=self.p, training=True, inplace=inplace) else: return x diff --git a/fairseq/modules/transformer_sentence_encoder.py b/fairseq/modules/transformer_sentence_encoder.py index a7fb198779..d0540d6922 100644 --- a/fairseq/modules/transformer_sentence_encoder.py +++ b/fairseq/modules/transformer_sentence_encoder.py @@ -32,18 +32,25 @@ def init_bert_params(module): the normal distribution (to be validated). """ + def normal_(data): + # with FSDP, module params will be on CUDA, so we cast them back to CPU + # so that the RNG is consistent with and without FSDP + data.copy_( + data.cpu().normal_(mean=0.0, std=0.02).to(data.device) + ) + if isinstance(module, nn.Linear): - module.weight.data.normal_(mean=0.0, std=0.02) + normal_(module.weight.data) if module.bias is not None: module.bias.data.zero_() if isinstance(module, nn.Embedding): - module.weight.data.normal_(mean=0.0, std=0.02) + normal_(module.weight.data) if module.padding_idx is not None: module.weight.data[module.padding_idx].zero_() if isinstance(module, MultiheadAttention): - module.q_proj.weight.data.normal_(mean=0.0, std=0.02) - module.k_proj.weight.data.normal_(mean=0.0, std=0.02) - module.v_proj.weight.data.normal_(mean=0.0, std=0.02) + normal_(module.q_proj.weight.data) + normal_(module.k_proj.weight.data) + normal_(module.v_proj.weight.data) class TransformerSentenceEncoder(nn.Module): From 8f77e24cf184c9762ed48acb43e9bd5daba550b1 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Sat, 20 Mar 2021 16:40:08 -0700 Subject: [PATCH 279/774] Deepspeed can be used outside of fbcode (#1727) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1727 Reviewed By: myleott Differential Revision: D27213955 Pulled By: sshleifer fbshipit-source-id: be84e7f7c1c55c407ee7445fad9b3026a79763fb --- fairseq/optim/cpu_adam.py | 20 ++++++++++++++------ scripts/test_fsdp.sh | 13 +++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100755 scripts/test_fsdp.sh diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py index 9637a78666..21336ef59b 100644 --- a/fairseq/optim/cpu_adam.py +++ b/fairseq/optim/cpu_adam.py @@ -16,13 +16,21 @@ try: - import deepspeed.op_extensions.cpu_adam as ds_opt_adam - has_deepspeed_cpu_adam = True + import deepspeed + has_deepspeed = True except ImportError as e: - logging.warning(e) - has_deepspeed_cpu_adam = False + has_deepspeed = False +def _get_cpu_adam(): + try: + from deepspeed.ops.op_builder import CPUAdamBuilder + return CPUAdamBuilder().load() + except ImportError: + # fbcode + from deepspeed.ops.adam import DeepSpeedCPUAdam as ds_opt_adam + return ds_opt_adam + @dataclass class FairseqCPUAdamConfig(FairseqDataclass): adam_betas: str = field( @@ -97,13 +105,13 @@ def __init__( self.use_fp16_stats = use_fp16_stats self.FLOAT16_MAX = 65504.0 - if not has_deepspeed_cpu_adam: + if not has_deepspeed: raise ImportError("Please install DeepSpeed: pip install deepspeed") self.opt_id = CPUAdam.optimizer_id CPUAdam.optimizer_id = CPUAdam.optimizer_id + 1 - self.ds_opt_adam = ds_opt_adam + self.ds_opt_adam = _get_cpu_adam() adamw_mode = True self.ds_opt_adam.create_adam( self.opt_id, lr, betas[0], betas[1], eps, weight_decay, adamw_mode diff --git a/scripts/test_fsdp.sh b/scripts/test_fsdp.sh new file mode 100755 index 0000000000..0f4d6c420b --- /dev/null +++ b/scripts/test_fsdp.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +rm -rf fsdp_dummy +mkdir -p fsdp_dummy +fairseq-train /private/home/sshleifer/data-bin/stories_mmap \ + --ddp-backend fully_sharded --fp16 --fp16-init-scale 4 \ + --cpu-offload --checkpoint-activations \ + --task language_modeling --tokens-per-sample 256 --batch-size 8 \ + --arch transformer_lm_gpt2_tiny \ + --optimizer cpu_adam --adam-betas "(0.9,0.98)" \ + --lr 0.0001 --lr-scheduler polynomial_decay --warmup-updates 5 --total-num-update 10 \ + --max-update 10 --log-format json --log-interval 1 \ + --save-interval-updates 10 --save-dir fsdp_dummy \ + --restore-file x.pt "$@" From 5273bbb7c18a9b147e3f0cfc97121cc945a962bd Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Sat, 20 Mar 2021 19:25:54 -0700 Subject: [PATCH 280/774] Fix transformer LM arg upgrade logic (#1717) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1717 Reviewed By: alexeib Differential Revision: D27156919 Pulled By: myleott fbshipit-source-id: af3c2e41464c04a7808f40894e7b0106798e4822 --- fairseq/models/transformer_lm.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index d2c0cff493..70354a228d 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -230,9 +230,6 @@ def __init__(self, decoder): def build_model(cls, args, task): """Build a new model instance.""" - # make sure all arguments are present in older models - base_lm_architecture(args) - if args.decoder_layers_to_keep: args.decoder_layers = len(args.decoder_layers_to_keep.split(",")) From bd0109cdc66edbd01e7362d41e5997f85afbde7d Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Mon, 22 Mar 2021 13:45:48 -0700 Subject: [PATCH 281/774] Revert change in defaults for LMs to learned pos embeddings (#1734) Summary: This was premature. Leaving it to ``True`` for GPT-3 configs, but reverting back to ``False`` in general. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1734 Reviewed By: shruti-bh Differential Revision: D27233834 Pulled By: myleott fbshipit-source-id: 597b36f94f28d59834f1d68ab1dd2991e82c1e32 --- fairseq/models/transformer_lm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index 70354a228d..b616a923d4 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -304,7 +304,7 @@ def base_lm_architecture(args): args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) args.adaptive_softmax_factor = getattr(args, "adaptive_softmax_factor", 4) - args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) args.activation_fn = getattr(args, "activation_fn", "relu") args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0) @@ -449,6 +449,7 @@ def base_gpt3_architecture(args): args.decoder_input_dim = args.decoder_embed_dim args.decoder_output_dim = args.decoder_embed_dim args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", args.decoder_embed_dim * 4) + # GPT-3 used learned positional embeddings, rather than sinusoidal args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) args.dropout = getattr(args, "dropout", 0.0) args.attention_dropout = getattr(args, "attention_dropout", 0.0) From 8c14a8f7dfcd18abd983491fc2207ac634d25759 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Mon, 22 Mar 2021 20:51:32 -0700 Subject: [PATCH 282/774] --nval only validate for a few steps (#1735) Summary: Afaict, it's easy to set --max-update 4 to run training quickly, but it's hard to control validation without changing the data. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1735 Reviewed By: myleott Differential Revision: D27246062 Pulled By: sshleifer fbshipit-source-id: 30a210cbbb45791647a050f49e6f38fbacd0d988 --- fairseq/dataclass/configs.py | 2 ++ fairseq_cli/train.py | 4 +++- tests/test_binaries.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 3c29be9197..be9f7c5af3 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -448,6 +448,8 @@ class DatasetConfig(FairseqDataclass): "argparse_alias": "--max-sentences-valid", }, ) + max_valid_steps: Optional[int] = field(default=None, metadata={'help': 'How many batches to evaluate', + "argparse_alias": "--nval"}) curriculum: int = field( default=0, metadata={"help": "don't shuffle batches for first N epochs"} ) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index d618817e46..8b5ca89cee 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -432,7 +432,9 @@ def validate( # create a new root metrics aggregator so validation metrics # don't pollute other aggregators (e.g., train meters) with metrics.aggregate(new_root=True) as agg: - for sample in progress: + for i, sample in enumerate(progress): + if cfg.dataset.max_valid_steps is not None and i > cfg.dataset.max_valid_steps: + break trainer.valid_step(sample) # log validation stats diff --git a/tests/test_binaries.py b/tests/test_binaries.py index e10cc767b8..49e6dcd9f8 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -1160,7 +1160,7 @@ def test_transformer_lm(self): train_language_model( data_dir, "transformer_lm", - ["--add-bos-token"], + ["--add-bos-token", '--nval', '1'], run_validation=True, ) eval_lm_main(data_dir) From 1bba712622b8ae4efb3eb793a8a40da386fe11d0 Mon Sep 17 00:00:00 2001 From: Taylan Bilal <taylanbil@gmail.com> Date: Mon, 22 Mar 2021 21:29:42 -0700 Subject: [PATCH 283/774] Enable w2v2 tpu (#3328) Summary: This enables training wav2vec 2.0 models on TPUs courtesy of taylanbil Pull Request resolved: https://github.com/pytorch/fairseq/pull/3328 Reviewed By: myleott Differential Revision: D27127542 Pulled By: alexeib fbshipit-source-id: b402c58f812c3c36edaaa88fdbe20e37fae3d4f3 --- examples/wav2vec/README.md | 52 +++++++ .../wav2vec2_large_librivox_tpu-pod.yaml | 71 +++++++++ .../wav2vec2_large_librivox_tpu.yaml | 71 +++++++++ fairseq/criterions/wav2vec_criterion.py | 65 ++++++--- fairseq/data/audio/raw_audio_dataset.py | 123 +++++++++++++++- fairseq/data/bucket_pad_length_dataset.py | 46 +++--- fairseq/data/data_utils.py | 22 +++ fairseq/distributed/utils.py | 6 +- fairseq/logging/metrics.py | 8 + fairseq/models/wav2vec/wav2vec2.py | 137 +++++++++++------- fairseq/models/wav2vec/wav2vec2_asr.py | 24 ++- fairseq/tasks/audio_pretraining.py | 79 +++++++++- fairseq/trainer.py | 22 ++- fairseq/utils.py | 36 +++++ fairseq_cli/train.py | 5 +- 15 files changed, 658 insertions(+), 109 deletions(-) create mode 100644 examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml create mode 100644 examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index e95f292b51..bfed3913cf 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -222,6 +222,58 @@ $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 - --max-sample-size 150000 --max-tokens 1500000 --skip-invalid-size-inputs-valid-test ``` +### Run wav2vec2 pre-training on Google Cloud TPUs: + +Wav2Vec2 is now supported on TPUs! It's currently pre-training only. + +#### Using hydra on a v3-8: + +``` +$ OMP_NUM_THREADS=1 fairseq-hydra-train \ + task.data=/manifest/path \ + --config-dir /PATH/TO/FAIRSEQ/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_large_librivox_tpu.yaml +``` + +#### Using command line arguments on a v3-8: + +``` +$ OMP_NUM_THREADS=1 python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ +--arch wav2vec2 --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 --optimizer adam --lr 0.005 --lr-scheduler cosine \ +--conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1)] \ +--conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ +--skip-connections-agg --residual-scale 0.5 --log-compression --warmup-updates 500 --warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 \ +--max-sample-size 150000 --max-tokens 1500000 --skip-invalid-size-inputs-valid-test \ +--tpu --distributed-world-size 8 --num-batch-buckets 3 --enable-padding \ +--encoder-layerdrop 0 --mask-channel-prob 0.1 +``` + +#### Using hydra on a pod slice (v3-N with N > 8): + +``` +$ OMP_NUM_THREADS=1 fairseq-hydra-train \ + task.data=/manifest/path \ + --config-dir /PATH/TO/FAIRSEQ/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_large_librivox_tpu-pod.yaml # edit distributed-world-size accordingly +``` + +#### Using command line arguments on a pod slice (v3-N with N > 8): + + +``` +$ python -m torch_xla.distributed.xla_dist \ + --tpu ${TPUNAME} --conda-env=torch-xla-${TORCH_XLA_VERSION} --env OMP_NUM_THREADS=1 \ + -- \ +python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ +--arch wav2vec2 --task audio_pretraining --min-lr 1e-06 --stop-min-lr 1e-09 --optimizer adam --lr 0.005 --lr-scheduler cosine \ +--conv-feature-layers [(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1)] \ +--conv-aggregator-layers [(512, 2, 1), (512, 3, 1), (512, 4, 1), (512, 5, 1), (512, 6, 1), (512, 7, 1), (512, 8, 1), (512, 9, 1), (512, 10, 1), (512, 11, 1), (512, 12, 1), (512, 13, 1)] \ +--skip-connections-agg --residual-scale 0.5 --log-compression --warmup-updates 500 --warmup-init-lr 1e-07 --criterion wav2vec --num-negatives 10 \ +--max-sample-size 150000 --max-tokens 1500000 --skip-invalid-size-inputs-valid-test \ +--tpu --distributed-world-size ${WORLD_SIZE} --num-batch-buckets 3 --enable-padding \ +--encoder-layerdrop 0 --mask-channel-prob 0.1 +``` + ### Extract embeddings from the downstream task data: ``` diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml new file mode 100644 index 0000000000..676c9fe339 --- /dev/null +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml @@ -0,0 +1,71 @@ +# @package _group_ + +common: + tpu: true + fp16: false + log_format: json + log_interval: 10 + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: ??? + max_sample_size: 250000 + min_sample_size: 32000 + normalize: true + num_batch_buckets: 3 + precompute_mask_indices: true + enable_padding: true + +dataset: + num_workers: 6 + max_tokens: 1200000 + skip_invalid_size_inputs_valid_test: true + +distributed_training: + distributed_world_size: 128 + ddp_backend: legacy_ddp + +criterion: + _name: wav2vec + infonce: true + log_keys: ["prob_perplexity","code_perplexity","temp"] + loss_weights: [0.1, 0] + +optimization: + max_update: 1000000 + lr: [0.005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: wav2vec2 + quantize_targets: true + extractor_mode: layer_norm + layer_norm_first: true + final_dim: 256 + latent_temp: [2.0,0.1,0.999995] + encoder_layerdrop: 0.00 + dropout_input: 0.0 + dropout_features: 0.0 + dropout: 0.0 + attention_dropout: 0.0 + conv_bias: true + + mask_channel_prob: 0.1 + mask_prob: 0.1 + + feature_grad_mult: 1.0 + diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml new file mode 100644 index 0000000000..c45c4d9117 --- /dev/null +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml @@ -0,0 +1,71 @@ +# @package _group_ + +common: + tpu: true + fp16: false + log_format: json + log_interval: 10 + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: ??? + max_sample_size: 250000 + min_sample_size: 32000 + normalize: true + num_batch_buckets: 3 + precompute_mask_indices: true + enable_padding: true + +dataset: + num_workers: 6 + max_tokens: 1200000 + skip_invalid_size_inputs_valid_test: true + +distributed_training: + distributed_world_size: 8 + ddp_backend: legacy_ddp + +criterion: + _name: wav2vec + infonce: true + log_keys: ["prob_perplexity","code_perplexity","temp"] + loss_weights: [0.1, 0] + +optimization: + max_update: 1000000 + lr: [0.005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: wav2vec2 + quantize_targets: true + extractor_mode: layer_norm + layer_norm_first: true + final_dim: 256 + latent_temp: [2.0,0.1,0.999995] + encoder_layerdrop: 0.00 + dropout_input: 0.0 + dropout_features: 0.0 + dropout: 0.0 + attention_dropout: 0.0 + conv_bias: true + + mask_channel_prob: 0.1 + mask_prob: 0.1 + + feature_grad_mult: 1.0 + diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index 859177f2b6..f682508cb1 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -31,7 +31,7 @@ class Wav2VecCriterionConfig(FairseqDataclass): default_factory=lambda: [], metadata={"help": "output keys to log"}, ) - +from fairseq.utils import index_put, is_xla_tensor @register_criterion("wav2vec", dataclass=Wav2VecCriterionConfig) class Wav2vecCriterion(FairseqCriterion): @@ -52,7 +52,9 @@ def forward(self, model, sample, reduce=True): net_output = model(**sample["net_input"]) logits = model.get_logits(net_output).float() target = model.get_targets(sample, net_output) + self.xla = is_xla_tensor(logits) + # XXX: handle weights on xla. weights = None if hasattr(model, "get_target_weights") and not self.infonce: weights = model.get_target_weights(target, net_output) @@ -61,21 +63,31 @@ def forward(self, model, sample, reduce=True): losses = [] + reduction = "none" if ((not reduce) or self.xla) else "sum" if self.infonce: - loss = F.cross_entropy( - logits, - target, - reduction="sum" if reduce else "none", - ) + loss = F.cross_entropy(logits, target, reduction=reduction) else: loss = F.binary_cross_entropy_with_logits( - logits, - target.float(), - weights, - reduction="sum" if reduce else "none", + logits, target.float(), weights, reduction=reduction + ) + + if self.xla: + # tpu-comment: since dynamic shapes lead to recompilations on xla, + # we don't shrink tensors using mask_indices. + # Instead, we use mask indices to adjust loss. + mi = ( + sample['net_input']['mask_indices'] + .transpose(0, 1) # logits are transposed in `model.get_logits` + .reshape(logits.size(0)) ) + loss = (loss * mi).sum() if reduce else (loss * mi) - sample_size = target.numel() if self.infonce else target.long().sum().item() + if 'sample_size' in sample and self.infonce: + sample_size = sample['sample_size'] + elif 'mask_indices' in sample['net_input']: + sample_size = sample['net_input']['mask_indices'].sum() + else: + sample_size = target.numel() if self.infonce else target.long().sum().item() losses.append(loss.detach().clone()) if self.loss_weights is not None: @@ -95,7 +107,7 @@ def forward(self, model, sample, reduce=True): losses.append(p) logging_output = { - "loss": loss.item() if reduce else loss, + "loss": loss.item() if (reduce and not self.xla) else loss.detach(), "ntokens": sample_size, "nsentences": sample["id"].numel(), "sample_size": sample_size, @@ -111,11 +123,14 @@ def forward(self, model, sample, reduce=True): if not self.training: logging_output["target"] = target.cpu().numpy() elif lk in net_output: - logging_output[lk] = float(net_output[lk]) + value = net_output[lk] + if not is_xla_tensor(value): + value = float(value) + logging_output[lk] = value if len(losses) > 1: for i, l in enumerate(losses): - logging_output[f"loss_{i}"] = l.item() + logging_output[f"loss_{i}"] = l.item() if not self.xla else l.detach() if self.infonce: with torch.no_grad(): @@ -126,9 +141,15 @@ def forward(self, model, sample, reduce=True): assert logits.dim() > 1, logits.shape max = logits.argmax(-1) == 0 min = logits.argmin(-1) == 0 - both = max & min - corr = max.long().sum().item() - both.long().sum().item() - count = max.numel() + if is_xla_tensor(logits): + max, min = max * mi, min * mi + both = max & min + corr = max.long().sum() - both.long().sum() + count = mi.sum() + else: + both = max & min + corr = max.long().sum().item() - both.long().sum().item() + count = float(max.numel()) logging_output["correct"] = corr logging_output["count"] = count @@ -188,11 +209,15 @@ def reduce_metrics(logging_outputs) -> None: else: metrics.log_scalar(k, val / len(logging_outputs), round=3) - @staticmethod - def logging_outputs_can_be_summed() -> bool: + # FIXME: revert when gather based xla reduction is implemented + #@staticmethod + #def logging_outputs_can_be_summed() -> bool: + def logging_outputs_can_be_summed(self) -> bool: """ Whether the logging outputs returned by `forward` can be summed across workers prior to calling `reduce_metrics`. Setting this to True will improves distributed training speed. """ - return False + # XXX: Gather based reduction not implemented for xla yet. + # So we fall to sum based reduction for xla. + return self.xla diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 1d92e4966b..d0ff604e2b 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -12,7 +12,8 @@ import torch import torch.nn.functional as F -from .. import FairseqDataset +from .. import FairseqDataset, BaseWrapperDataset +from ..data_utils import compute_mask_indices, get_buckets, get_bucketed_sizes logger = logging.getLogger(__name__) @@ -27,6 +28,8 @@ def __init__( shuffle=True, pad=False, normalize=False, + compute_mask_indices=False, + **mask_compute_kwargs, ): super().__init__() @@ -39,6 +42,14 @@ def __init__( self.pad = pad self.shuffle = shuffle self.normalize = normalize + self.compute_mask_indices = compute_mask_indices + if self.compute_mask_indices: + self.mask_compute_kwargs = mask_compute_kwargs + self._features_size_map = {} + self._C = mask_compute_kwargs['encoder_embed_dim'] + self._conv_feature_layers = eval( + mask_compute_kwargs['conv_feature_layers'] + ) def __getitem__(self, index): raise NotImplementedError() @@ -70,6 +81,45 @@ def crop_to_max_size(self, wav, target_size): end = size - diff + start return wav[start:end] + def _compute_mask_indices(self, dims, padding_mask): + B, T, C = dims + mask_indices, mask_channel_indices = None, None + if self.mask_compute_kwargs['mask_prob'] > 0: + mask_indices = compute_mask_indices( + (B, T), + padding_mask, + self.mask_compute_kwargs['mask_prob'], + self.mask_compute_kwargs['mask_length'], + self.mask_compute_kwargs['mask_selection'], + self.mask_compute_kwargs['mask_other'], + min_masks=2, + no_overlap=self.mask_compute_kwargs['no_mask_overlap'], + min_space=self.mask_compute_kwargs['mask_min_space'], + ) + mask_indices = torch.from_numpy(mask_indices) + if self.mask_compute_kwargs['mask_channel_prob'] > 0: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_compute_kwargs['mask_channel_prob'], + self.mask_compute_kwargs['mask_channel_length'], + self.mask_compute_kwargs['mask_channel_selection'], + self.mask_compute_kwargs['mask_channel_other'], + no_overlap=self.mask_compute_kwargs['no_mask_channel_overlap'], + min_space=self.mask_compute_kwargs['mask_channel_min_space'], + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .unsqueeze(1) + .expand(-1, T, -1) + ) + + return mask_indices, mask_channel_indices + + @staticmethod + def _bucket_tensor(tensor, num_pad, value): + return F.pad(tensor, (0, num_pad), value=value) + def collater(self, samples): samples = [s for s in samples if s["source"] is not None] if len(samples) == 0: @@ -101,9 +151,55 @@ def collater(self, samples): collated_sources[i] = self.crop_to_max_size(source, target_size) input = {"source": collated_sources} + out = {"id": torch.LongTensor([s["id"] for s in samples])} if self.pad: input["padding_mask"] = padding_mask - return {"id": torch.LongTensor([s["id"] for s in samples]), "net_input": input} + + if hasattr(self, 'num_buckets') and self.num_buckets > 0: + assert self.pad, "Cannot bucket without padding first." + bucket = max(self._bucketed_sizes[s['id']] for s in samples) + num_pad = bucket - collated_sources.size(-1) + if num_pad: + input['source'] = self._bucket_tensor( + collated_sources, num_pad, 0 + ) + input['padding_mask'] = self._bucket_tensor( + padding_mask, num_pad, True + ) + + if self.compute_mask_indices: + B = input['source'].size(0) + T = self._get_mask_indices_dims(input['source'].size(-1)) + padding_mask_reshaped = input['padding_mask'].clone() + extra = padding_mask_reshaped.size(1) % T + if extra > 0: + padding_mask_reshaped = padding_mask_reshaped[:, :-extra] + padding_mask_reshaped = padding_mask_reshaped.view( + padding_mask_reshaped.size(0), T, -1 + ) + padding_mask_reshaped = padding_mask_reshaped.all(-1) + input['padding_count'] = ( + padding_mask_reshaped.sum(-1).max().item() + ) + mask_indices, mask_channel_indices = self._compute_mask_indices( + (B, T, self._C), padding_mask_reshaped, + ) + input["mask_indices"] = mask_indices + input["mask_channel_indices"] = mask_channel_indices + out['sample_size'] = mask_indices.sum().item() + + out["net_input"] = input + return out + + def _get_mask_indices_dims(self, size, padding=0, dilation=1): + if size not in self._features_size_map: + L_in = size + for (_, kernel_size, stride) in self._conv_feature_layers: + L_out = L_in + 2*padding - dilation*(kernel_size-1) - 1 + L_out = 1 + L_out // stride + L_in = L_out + self._features_size_map[size] = L_out + return self._features_size_map[size] def num_tokens(self, index): return self.size(index) @@ -138,6 +234,9 @@ def __init__( shuffle=True, pad=False, normalize=False, + num_buckets=0, + compute_mask_indices=False, + **mask_compute_kwargs, ): super().__init__( sample_rate=sample_rate, @@ -146,6 +245,8 @@ def __init__( shuffle=shuffle, pad=pad, normalize=normalize, + compute_mask_indices=compute_mask_indices, + **mask_compute_kwargs, ) self.fnames = [] @@ -164,8 +265,26 @@ def __init__( self.fnames.append(items[0]) self.line_inds.add(i) self.sizes.append(sz) + self.set_bucket_info(num_buckets) logger.info(f"loaded {len(self.fnames)}, skipped {skipped} samples") + def set_bucket_info(self, num_buckets): + self.num_buckets = num_buckets + if self.num_buckets > 0: + self._collated_sizes = np.minimum( + np.array(self.sizes), self.max_sample_size, + ) + self.buckets = get_buckets( + self._collated_sizes, self.num_buckets, + ) + self._bucketed_sizes = get_bucketed_sizes( + self._collated_sizes, self.buckets + ) + logger.info( + f"{len(self.buckets)} bucket(s) for the audio dataset: " + f"{self.buckets}" + ) + def __getitem__(self, index): import soundfile as sf diff --git a/fairseq/data/bucket_pad_length_dataset.py b/fairseq/data/bucket_pad_length_dataset.py index cda8834ac8..0f94100148 100644 --- a/fairseq/data/bucket_pad_length_dataset.py +++ b/fairseq/data/bucket_pad_length_dataset.py @@ -6,6 +6,7 @@ import numpy as np import torch.nn.functional as F from fairseq.data import BaseWrapperDataset +from fairseq.data.data_utils import get_buckets, get_bucketed_sizes class BucketPadLengthDataset(BaseWrapperDataset): @@ -29,42 +30,43 @@ def __init__( num_buckets, pad_idx, left_pad, + tensor_key=None, ): super().__init__(dataset) self.pad_idx = pad_idx self.left_pad = left_pad assert num_buckets > 0 - self.buckets = np.unique( - np.percentile( - sizes, - np.linspace(0, 100, num_buckets + 1), - interpolation="lower", - )[1:] - ) + self.buckets = get_buckets(sizes, num_buckets) + self._bucketed_sizes = get_bucketed_sizes(sizes, self.buckets) + self._tensor_key = tensor_key - def get_bucketed_sizes(orig_sizes, buckets): - sizes = np.copy(orig_sizes) - assert np.min(sizes) >= 0 - start_val = -1 - for end_val in buckets: - mask = (sizes > start_val) & (sizes <= end_val) - sizes[mask] = end_val - start_val = end_val - return sizes + def _set_tensor(self, item, val): + if self._tensor_key is None: + return val + item[self._tensor_key] = val + return item - self._bucketed_sizes = get_bucketed_sizes(sizes, self.buckets) + def _get_tensor(self, item): + if self._tensor_key is None: + return item + return item[self._tensor_key] - def __getitem__(self, index): - item = self.dataset[index] - bucket_size = self._bucketed_sizes[index] - num_pad = bucket_size - item.size(-1) + def _pad(self, tensor, bucket_size, dim=-1): + num_pad = bucket_size - tensor.size(dim) return F.pad( - item, + tensor, (num_pad if self.left_pad else 0, 0 if self.left_pad else num_pad), value=self.pad_idx, ) + def __getitem__(self, index): + item = self.dataset[index] + bucket_size = self._bucketed_sizes[index] + tensor = self._get_tensor(item) + padded = self._pad(tensor, bucket_size) + return self._set_tensor(item, padded) + @property def sizes(self): return self._bucketed_sizes diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 6f7561afbe..01c743c3e8 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -524,3 +524,25 @@ def lengths_to_padding_mask(lens: torch.LongTensor) -> torch.BoolTensor: def lengths_to_mask(lens: torch.LongTensor) -> torch.BoolTensor: return ~lengths_to_padding_mask(lens) + + +def get_buckets(sizes, num_buckets): + buckets = np.unique( + np.percentile( + sizes, + np.linspace(0, 100, num_buckets + 1), + interpolation='lower', + )[1:] + ) + return buckets + + +def get_bucketed_sizes(orig_sizes, buckets): + sizes = np.copy(orig_sizes) + assert np.min(sizes) >= 0 + start_val = -1 + for end_val in buckets: + mask = (sizes > start_val) & (sizes <= end_val) + sizes[mask] = end_val + start_val = end_val + return sizes diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index 710ca18628..970b784915 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -281,7 +281,6 @@ def distributed_init(cfg: FairseqConfig): cfg.distributed_training.device_id = xm.get_local_ordinal() cfg.distributed_training.distributed_rank = xm.get_ordinal() xm.rendezvous("distributed_init") # wait for all workers - xm.mark_step() if is_master(cfg.distributed_training): logging.getLogger().setLevel(logging.INFO) @@ -357,7 +356,10 @@ def call_main(cfg: FairseqConfig, main, **kwargs): xmp.spawn( fn=distributed_main, args=(main, cfg, kwargs), - nprocs=8, # use all 8 TPU cores + # tpu-comment: + # 8 devices in one TPU VM, is the max processes to be spawned. + # The rest is driven by xm.distributed.xla_dist + nprocs=min(cfg.distributed_training.distributed_world_size, 8), ) else: # single GPU main diff --git a/fairseq/logging/metrics.py b/fairseq/logging/metrics.py index 7b56e31592..2bb1da086f 100644 --- a/fairseq/logging/metrics.py +++ b/fairseq/logging/metrics.py @@ -286,3 +286,11 @@ def load_state_dict(state_dict): for name, agg_state in state_dict.items(): _aggregators[name] = MetersDict() _aggregators[name].load_state_dict(agg_state) + + +def xla_metrics_report(): + try: + import torch_xla.debug.metrics as met + print(met.metrics_report()) + except ImportError: + return diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 644add7b17..6999dca2d9 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -26,7 +26,7 @@ TransposeLast, ) from fairseq.modules.transformer_sentence_encoder import init_bert_params -from fairseq.utils import buffered_arange +from fairseq.utils import buffered_arange, index_put, is_xla_tensor EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) @@ -330,47 +330,52 @@ def build_model(cls, cfg: Wav2Vec2Config, task=None): return cls(cfg) - def apply_mask(self, x, padding_mask): + def apply_mask( + self, x, padding_mask, + mask_indices=None, mask_channel_indices=None, + ): B, T, C = x.shape if self.mask_prob > 0: - mask_indices = compute_mask_indices( - (B, T), - padding_mask, - self.mask_prob, - self.mask_length, - self.mask_selection, - self.mask_other, - min_masks=2, - no_overlap=self.no_mask_overlap, - min_space=self.mask_min_space, - ) - mask_indices = torch.from_numpy(mask_indices).to(x.device) - x[mask_indices] = self.mask_emb + if mask_indices is None: + mask_indices = compute_mask_indices( + (B, T), + padding_mask, + self.mask_prob, + self.mask_length, + self.mask_selection, + self.mask_other, + min_masks=2, + no_overlap=self.no_mask_overlap, + min_space=self.mask_min_space, + ) + mask_indices = torch.from_numpy(mask_indices).to(x.device) + x = index_put(x, mask_indices, self.mask_emb) else: mask_indices = None if self.mask_channel_prob > 0: - mask_channel_indices = compute_mask_indices( - (B, C), - None, - self.mask_channel_prob, - self.mask_channel_length, - self.mask_channel_selection, - self.mask_channel_other, - no_overlap=self.no_mask_channel_overlap, - min_space=self.mask_channel_min_space, - ) - mask_channel_indices = ( - torch.from_numpy(mask_channel_indices) - .to(x.device) - .unsqueeze(1) - .expand(-1, T, -1) - ) - x[mask_channel_indices] = 0 + if mask_channel_indices is None: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_channel_prob, + self.mask_channel_length, + self.mask_channel_selection, + self.mask_channel_other, + no_overlap=self.no_mask_channel_overlap, + min_space=self.mask_channel_min_space, + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x = index_put(x, mask_channel_indices, 0) return x, mask_indices - def sample_negatives(self, y, num): + def sample_negatives(self, y, num, padding_count=None): if self.n_negatives == 0 and self.cross_sample_negatives == 0: return y.new(0) @@ -378,8 +383,9 @@ def sample_negatives(self, y, num): bsz, tsz, fsz = y.shape y = y.view(-1, fsz) # BTC => (BxT)C + # FIXME: what happens if padding_count is specified? cross_high = tsz * bsz - high = tsz + high = tsz - (padding_count or 0) with torch.no_grad(): assert high > 1, f"{bsz,tsz,fsz}" @@ -436,10 +442,17 @@ def compute_preds(self, x, y, negatives): logits = torch.cosine_similarity(x.float(), targets.float(), dim=-1).type_as(x) - logits /= self.logit_temp + logits = logits / self.logit_temp - if neg_is_pos.any(): - logits[1:][neg_is_pos] = float("-inf") + if is_xla_tensor(logits) or neg_is_pos.any(): + fillval = -float(2**30) + if not hasattr(self, '_inftensor'): + self._inftensor = ( + torch.tensor(fillval).to(x.device) + if is_xla_tensor(logits) else + float("-inf") + ) + logits[1:] = index_put(logits[1:], neg_is_pos, self._inftensor) return logits @@ -458,7 +471,11 @@ def _conv_out_length(input_length, kernel_size, stride): return input_lengths.to(torch.long) - def forward(self, source, padding_mask=None, mask=True, features_only=False): + def forward( + self, source, padding_mask=None, mask=True, features_only=False, + mask_indices=None, mask_channel_indices=None, + padding_count=None, + ): if self.feature_grad_mult > 0: features = self.feature_extractor(source) @@ -509,8 +526,14 @@ def forward(self, source, padding_mask=None, mask=True, features_only=False): features = self.project_inp(features) if mask: - x, mask_indices = self.apply_mask(features, padding_mask) - if mask_indices is not None: + x, mask_indices = self.apply_mask( + features, padding_mask, + mask_indices=mask_indices, + mask_channel_indices=mask_channel_indices, + ) + if not is_xla_tensor(x) and mask_indices is not None: + # tpu-comment: reducing the size in a dynamic way causes + # too many recompilations on xla. y = unmasked_features[mask_indices].view( unmasked_features.size(0), -1, unmasked_features.size(-1) ) @@ -537,12 +560,18 @@ def forward(self, source, padding_mask=None, mask=True, features_only=False): y = self.project_q(y) if self.negatives_from_everywhere: - neg_cands, *_ = self.quantizer(unmasked_features, produce_targets=False) - negs, _ = self.sample_negatives(neg_cands, y.size(1)) + neg_cands = self.quantizer( + unmasked_features, produce_targets=False + )["x"] + negs, _ = self.sample_negatives( + neg_cands, y.size(1), padding_count=padding_count, + ) negs = self.project_q(negs) else: - negs, _ = self.sample_negatives(y, y.size(1)) + negs, _ = self.sample_negatives( + y, y.size(1), padding_count=padding_count, + ) if self.codebook_negatives > 0: cb_negs = self.quantizer.sample_from_codebook( @@ -557,12 +586,20 @@ def forward(self, source, padding_mask=None, mask=True, features_only=False): y = self.project_q(y) if self.negatives_from_everywhere: - negs, _ = self.sample_negatives(unmasked_features, y.size(1)) + negs, _ = self.sample_negatives( + unmasked_features, y.size(1), + padding_count=padding_count, + ) negs = self.project_q(negs) else: - negs, _ = self.sample_negatives(y, y.size(1)) + negs, _ = self.sample_negatives( + y, y.size(1), padding_count=padding_count, + ) - x = x[mask_indices].view(x.size(0), -1, x.size(-1)) + if not is_xla_tensor(x): + # tpu-comment: reducing the size in a dynamic way causes + # too many recompilations on xla. + x = x[mask_indices].view(x.size(0), -1, x.size(-1)) if self.target_glu: y = self.target_glu(y) @@ -571,7 +608,9 @@ def forward(self, source, padding_mask=None, mask=True, features_only=False): x = self.final_proj(x) x = self.compute_preds(x, y, negs) - result = {"x": x, "padding_mask": padding_mask, "features_pen": features_pen} + result = { + "x": x, "padding_mask": padding_mask, "features_pen": features_pen, + } if prob_ppl is not None: result["prob_perplexity"] = prob_ppl @@ -759,11 +798,11 @@ def forward(self, x, padding_mask=None): def extract_features(self, x, padding_mask=None): if padding_mask is not None: - x[padding_mask] = 0 + x = index_put(x, padding_mask, 0) x_conv = self.pos_conv(x.transpose(1, 2)) x_conv = x_conv.transpose(1, 2) - x += x_conv + x = x + x_conv if not self.layer_norm_first: x = self.layer_norm(x) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index afa51299b6..e8a1d03eb2 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -13,7 +13,7 @@ import torch.nn.functional as F from dataclasses import dataclass, field from omegaconf import MISSING, II, open_dict -from typing import Any +from typing import Optional, Any from fairseq import checkpoint_utils, tasks, utils from fairseq.dataclass import FairseqDataclass @@ -127,7 +127,27 @@ class Wav2Vec2AsrConfig(FairseqDataclass): @dataclass class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): - pass + mask_min_space: Optional[int] = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + mask_channel_min_space: Optional[int] = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + conv_feature_layers: Optional[str] = field( + default="[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]", + metadata={ + "help": ( + "string describing convolutional feature extraction " + "layers in form of a python list that contains " + "[(dim, kernel_size, stride), ...]" + ), + }, + ) + encoder_embed_dim: Optional[int] = field( + default=768, metadata={"help": "encoder embedding dimension"} + ) @register_model("wav2vec_ctc", dataclass=Wav2Vec2CtcConfig) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index b7b5429819..df073a1814 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -5,6 +5,7 @@ # the root directory of this source tree. An additional grant of patent rights # can be found in the PATENTS file in the same directory. +import logging import os import sys import torch @@ -12,7 +13,7 @@ from argparse import Namespace from dataclasses import dataclass, field from typing import Optional, Any -from omegaconf import MISSING +from omegaconf import MISSING, II from fairseq.data import AddTargetDataset, Dictionary, FileAudioDataset, encoders from fairseq.dataclass import FairseqDataclass @@ -23,6 +24,9 @@ from ..logging import metrics +logger = logging.getLogger(__name__) + + class LabelEncoder(object): def __init__(self, dictionary): self.dictionary = dictionary @@ -86,6 +90,37 @@ class AudioPretrainingConfig(FairseqDataclass): "adds 'prev_output_tokens' to input and appends eos to target" }, ) + num_batch_buckets: int = field( + default=0, + metadata={ + "help": "number of buckets" + }, + ) + precompute_mask_indices: bool = field( + default=False, + metadata={ + "help": "flag to compute mask indices in data preparation.", + }, + ) + # The following are needed to precompute mask and mask channel indices + # before model's forward. + mask_length: Optional[int] = II("model.mask_length") + mask_prob: Optional[float] = II("model.mask_prob") + mask_selection: Optional[str] = II("model.mask_selection") + mask_other: Optional[float] = II("model.mask_other") + no_mask_overlap: Optional[bool] = II("model.no_mask_overlap") + mask_min_space: Optional[int] = II("model.mask_min_space") + mask_channel_length: Optional[int] = II("model.mask_channel_length") + mask_channel_prob: Optional[float] = II("model.mask_channel_prob") + mask_channel_selection: Optional[str] = II("model.mask_channel_selection") + mask_channel_other: Optional[float] = II("model.mask_channel_other") + no_mask_channel_overlap: Optional[bool] = II("model.no_mask_channel_overlap") + mask_channel_min_space: Optional[int] = II("model.mask_channel_min_space") + + conv_feature_layers: Optional[str] = II("model.conv_feature_layers") + encoder_embed_dim: Optional[int] = II("model.encoder_embed_dim") + + tpu: bool = II("common.tpu") @register_task("audio_pretraining", dataclass=AudioPretrainingConfig) @@ -117,11 +152,37 @@ def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): def load_target_dictionary(self): if self.cfg.labels: - dict_path = os.path.join(self.cfg.data, f"dict.{self.cfg.labels}.txt") + dict_path = os.path.join( + self.cfg.data, f"dict.{self.cfg.labels}.txt" + ) return Dictionary.load(dict_path) return None - def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + def _get_mask_precompute_kwargs(self, cfg): + if self.cfg.precompute_mask_indices or self.cfg.tpu: + args = [ + 'mask_length', + 'mask_prob', + 'mask_selection', + 'mask_other', + 'no_mask_overlap', + 'mask_min_space', + 'mask_channel_length', + 'mask_channel_prob', + 'mask_channel_selection', + 'mask_channel_other', + 'no_mask_channel_overlap', + 'mask_channel_min_space', + 'encoder_embed_dim', + 'conv_feature_layers', + ] + return {arg: cfg[arg] for arg in args} + else: + return {} + + def load_dataset( + self, split: str, task_cfg: FairseqDataclass = None, **kwargs + ): data_path = self.cfg.data task_cfg = task_cfg or self.cfg @@ -138,8 +199,20 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): min_sample_size=self.cfg.min_sample_size, pad=task_cfg.labels is not None or task_cfg.enable_padding, normalize=task_cfg.normalize, + num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), + compute_mask_indices=( + self.cfg.precompute_mask_indices or self.cfg.tpu + ), + **self._get_mask_precompute_kwargs(task_cfg), ) + if self.cfg.tpu and task_cfg['mask_channel_prob'] == 0.0: + logger.info( + "Pretraining on TPUs may suffer convergence " + "issues when training with `mask_channel_prob` value of " + "0. You may want to set this to a low value close to 0." + ) + if task_cfg.labels: label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") with open(label_path, "r") as f: diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 1c4c532dd0..f7897070c7 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -532,6 +532,7 @@ def get_train_iterator( epoch=epoch, combine=combine, data_selector=data_selector, + tpu=self.tpu, ) batch_iterator = self.task.get_batch_iterator( dataset=self.task.dataset(self.cfg.dataset.train_subset), @@ -684,9 +685,7 @@ def maybe_no_sync(): # before marking step can lead to OOM errors. # To handle gradient accumulation use case, we explicitly # mark step here for every forward pass without a backward pass - import torch_xla.core.xla_model as xm - - xm.mark_step() + self._xla_markstep_and_send_to_cpu() if is_dummy_batch: if torch.is_tensor(sample_size): @@ -806,10 +805,10 @@ def maybe_no_sync(): self.set_num_updates(self.get_num_updates() + 1) if self.tpu: - # mark step on TPUs import torch_xla.core.xla_model as xm - xm.mark_step() + # mark step on TPUs + self._xla_markstep_and_send_to_cpu() # only log stats every log_interval steps # this causes wps to be misreported when log_interval > 1 @@ -825,7 +824,7 @@ def maybe_no_sync(): metrics.log_scalar( "gb_total", gb_total, priority=1600, round=1, weight=0 ) - + logging_outputs = self._xla_markstep_and_send_to_cpu(logging_outputs) logging_output = self._reduce_and_log_stats( logging_outputs, sample_size, grad_norm ) @@ -878,9 +877,7 @@ def valid_step(self, sample, raise_oom=False): """Do forward pass in evaluation mode.""" if self.tpu: import torch_xla.core.xla_model as xm - xm.rendezvous("valid_step") # wait for all workers - xm.mark_step() with torch.no_grad(): self.model.eval() @@ -923,6 +920,8 @@ def valid_step(self, sample, raise_oom=False): ) # log validation stats + if self.tpu: + logging_outputs = self._xla_markstep_and_send_to_cpu(logging_outputs) logging_output = self._reduce_and_log_stats(logging_outputs, sample_size) return logging_output @@ -1300,6 +1299,13 @@ def _check_xla_compilation(self): ) self._num_xla_compiles = num_xla_compiles + def _xla_markstep_and_send_to_cpu(self, data=None): + import torch_xla.core.xla_model as xm + xm.mark_step() + if data is not None: + from fairseq.utils import xla_device_to_cpu + return xla_device_to_cpu(data) + def _catalog_shared_params(module, memo=None, prefix=""): if memo is None: diff --git a/fairseq/utils.py b/fairseq/utils.py index d4bf73648b..90bb8369f2 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -110,6 +110,7 @@ def _move_to_cuda(tensor): def move_to_cpu(sample): + def _move_to_cpu(tensor): # PyTorch has poor support for half tensors (float16) on CPU. # Move any such tensors to float32. @@ -120,6 +121,17 @@ def _move_to_cpu(tensor): return apply_to_sample(_move_to_cpu, sample) +def move_to_tpu(sample): + + import torch_xla.core.xla_model as xm + device = xm.xla_device() + + def _move_to_tpu(tensor): + return tensor.to(device) + + return apply_to_sample(_move_to_tpu, sample) + + def get_incremental_state( module: MultiheadAttention, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], @@ -289,6 +301,9 @@ def convert_padding_direction( def item(tensor): + # tpu-comment: making this a no-op for xla devices. + if torch.is_tensor(tensor) and tensor.device.type == 'xla': + return tensor.detach() if hasattr(tensor, "item"): return tensor.item() if hasattr(tensor, "__getitem__"): @@ -679,6 +694,27 @@ def tpu_data_loader(itr): ) +def is_xla_tensor(tensor): + return torch.is_tensor(tensor) and tensor.device.type == 'xla' + + +def index_put(tensor, indices, value): + if is_xla_tensor(tensor): + for _ in range(indices.dim(), tensor.dim()): + indices = indices.unsqueeze(-1) + if indices.size(-1) < tensor.size(-1): + indices = indices.expand_as(tensor) + tensor = torch.mul(tensor, ~indices) + torch.mul(value, indices) + else: + tensor[indices] = value + return tensor + + +def xla_device_to_cpu(dat): + import torch_xla.core.xla_model as xm + return xm._maybe_convert_to_cpu(dat) + + class CudaEnvironment(object): def __init__(self): cur_device = torch.cuda.current_device() diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 8b5ca89cee..6924dfe5c8 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -125,7 +125,7 @@ def main(cfg: FairseqConfig) -> None: ) ) logger.info( - "max tokens per GPU = {} and batch size per GPU = {}".format( + "max tokens per device = {} and max sentences per device = {}".format( cfg.dataset.max_tokens, cfg.dataset.batch_size, ) @@ -139,6 +139,9 @@ def main(cfg: FairseqConfig) -> None: # don't cache epoch iterators for sharded datasets disable_iterator_cache=task.has_sharded_data("train"), ) + if cfg.common.tpu: + import torch_xla.core.xla_model as xm + xm.rendezvous("load_checkpoint") # wait for all workers max_epoch = cfg.optimization.max_epoch or math.inf lr = trainer.get_lr() From 25dd9266809429c41833c151c5c09398f9f9ca9e Mon Sep 17 00:00:00 2001 From: Liang Tan <liangtan@fb.com> Date: Wed, 24 Mar 2021 20:28:29 -0700 Subject: [PATCH 284/774] Fix the issue that manifold raises error when reading non-existing file Summary: 1. Fairseq's expected reading behavior is "return None when accessing non-existing file" 2. However, when reading from manifold, manifold will raises error when accessing non-existing file 3. Here I add try-except block to bypass the manifold error Reviewed By: myleott Differential Revision: D27300619 fbshipit-source-id: 252606c82e9810516ccfb0705e08297f646b3708 --- fairseq/data/data_utils.py | 8 +++++++- fairseq/tasks/sentence_prediction.py | 19 +++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 01c743c3e8..097ea09f76 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -88,7 +88,13 @@ def load_indexed_dataset( datasets = [] for k in itertools.count(): path_k = path + (str(k) if k > 0 else "") - path_k = indexed_dataset.get_indexed_dataset_to_local(path_k) + try: + path_k = indexed_dataset.get_indexed_dataset_to_local(path_k) + except Exception as e: + if "StorageException: [404] Path not found" in str(e): + logger.warning(f"path_k: {e} not found") + else: + raise e dataset_impl_k = dataset_impl if dataset_impl_k is None: diff --git a/fairseq/tasks/sentence_prediction.py b/fairseq/tasks/sentence_prediction.py index 67acf7d377..6732728de9 100644 --- a/fairseq/tasks/sentence_prediction.py +++ b/fairseq/tasks/sentence_prediction.py @@ -140,12 +140,19 @@ def get_path(key, split): def make_dataset(key, dictionary): split_path = get_path(key, split) - dataset = data_utils.load_indexed_dataset( - split_path, - dictionary, - self.args.dataset_impl, - combine=combine, - ) + try: + dataset = data_utils.load_indexed_dataset( + split_path, + dictionary, + self.args.dataset_impl, + combine=combine, + ) + except Exception as e: + if "StorageException: [404] Path not found" in str(e): + logger.warning(f"dataset {e} not found") + dataset = None + else: + raise e return dataset input0 = make_dataset("input0", self.source_dictionary) From 06c9cefed73cfd43f9453c616e1b9d3ef63f58cf Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 25 Mar 2021 15:25:07 -0700 Subject: [PATCH 285/774] update CoVoST2 recipe; pretrained S2T encoder loading Summary: - Update CoVoST2 recipe - Add back label smoothing and increase dropout for En ASR - Update pretrained S2T encoder loading - Omit non-existing pre-training checkpoint (this occurs when we distribute only the ST checkpoint without the ASR checkpoint it leverages for pre-training) Related github issue: https://github.com/pytorch/fairseq/issues/3364 Reviewed By: jmp84 Differential Revision: D27159799 fbshipit-source-id: 3759926d68bd3f41f9f8e5fe5004f508eb24c2c0 --- .../speech_to_text/docs/covost_example.md | 18 ++++---- .../models/speech_to_text/s2t_transformer.py | 46 +++++++++++++++---- 2 files changed, 46 insertions(+), 18 deletions(-) diff --git a/examples/speech_to_text/docs/covost_example.md b/examples/speech_to_text/docs/covost_example.md index 55cd134c16..16447f041e 100644 --- a/examples/speech_to_text/docs/covost_example.md +++ b/examples/speech_to_text/docs/covost_example.md @@ -32,10 +32,10 @@ We train an En ASR model for encoder pre-training of all ST models: ```bash fairseq-train ${COVOST_ROOT}/en \ --config-yaml config_asr_en.yaml --train-subset train_asr_en --valid-subset dev_asr_en \ - --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 60000 \ - --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ - --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ - --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 + --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 50000 --max-update 60000 \ + --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ + --report-accuracy --arch s2t_transformer_s --dropout 0.15 --optimizer adam --lr 2e-3 \ + --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 ``` where `ASR_SAVE_DIR` is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly when using more than 1 GPU. @@ -62,10 +62,10 @@ Fr-En as example: ```bash fairseq-train ${COVOST_ROOT}/fr \ --config-yaml config_st_fr_en.yaml --train-subset train_st_fr_en --valid-subset dev_st_fr_en \ - --save-dir ${ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 60000 \ - --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ - --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ - --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ + --save-dir ${ST_SAVE_DIR} --num-workers 4 --max-update 30000 --max-tokens 40000 \ # --max-tokens 50000 for en-* + --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --report-accuracy \ + --arch s2t_transformer_s --encoder-freezing-updates 1000 --optimizer adam --lr 2e-3 \ + --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} ``` where `ST_SAVE_DIR` is the checkpoint root path. The ST encoder is pre-trained by En ASR for faster training and better @@ -97,6 +97,6 @@ Type in WAV/FLAC/OGG audio paths (one per line) after the prompt. #### Results | --arch | Params | Fr-En | De-En | Es-En | Ca-En | En-De | En-Ca | En-Fa | En-Et | Model | |---|---|---|---|---|---|---|---|---|---|---| -| s2t_transformer_s | 31M | [26.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_transformer_s.pt) | [17.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_transformer_s.pt) | [23.0](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_transformer_s.pt) | [18.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_transformer_s.pt) | [16.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_transformer_s.pt) | [21.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_transformer_s.pt) | [13.0](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_transformer_s.pt) | [13.2](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_transformer_s.pt) | (<-Download) | +| s2t_transformer_s | 31M | [27.2](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_transformer_s.pt) | [17.7](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_transformer_s.pt) | [23.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_transformer_s.pt) | [19.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_transformer_s.pt) | [16.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_transformer_s.pt) | [21.6](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_transformer_s.pt) | [12.9](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_transformer_s.pt) | [12.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_transformer_s.pt) | (<-Download) | [[Back]](..) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 814924ec97..7480dc7967 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -3,7 +3,9 @@ import logging import math from typing import Dict, List, Optional, Tuple +from pathlib import Path +import torch import torch.nn as nn from fairseq import checkpoint_utils, utils from fairseq.data.data_utils import lengths_to_padding_mask @@ -199,18 +201,28 @@ def add_args(parser): metavar="STR", help="model to take encoder weights from (for initialization)", ) + parser.add_argument( + '--encoder-freezing-updates', + default=None, + type=int, + metavar='N', + help='freeze encoder for first N updates' + ) @classmethod def build_encoder(cls, args): encoder = S2TTransformerEncoder(args) - if getattr(args, "load_pretrained_encoder_from", None): - encoder = checkpoint_utils.load_pretrained_component_from_model( - component=encoder, checkpoint=args.load_pretrained_encoder_from - ) - logger.info( - f"loaded pretrained encoder from: " - f"{args.load_pretrained_encoder_from}" - ) + pretraining_path = getattr(args, "load_pretrained_encoder_from", None) + if pretraining_path is not None: + if not Path(pretraining_path).exists(): + logger.warning( + f"skipped pretraining because {pretraining_path} does not exist" + ) + else: + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=pretraining_path + ) + logger.info(f"loaded pretrained encoder from: {pretraining_path}") return encoder @classmethod @@ -267,6 +279,9 @@ class S2TTransformerEncoder(FairseqEncoder): def __init__(self, args): super().__init__(None) + self.encoder_freezing_updates = args.encoder_freezing_updates + self.num_updates = 0 + self.dropout_module = FairseqDropout( p=args.dropout, module_name=self.__class__.__name__ ) @@ -294,7 +309,7 @@ def __init__(self, args): else: self.layer_norm = None - def forward(self, src_tokens, src_lengths): + def _forward(self, src_tokens, src_lengths): x, input_lengths = self.subsample(src_tokens, src_lengths) x = self.embed_scale * x @@ -318,6 +333,14 @@ def forward(self, src_tokens, src_lengths): "src_lengths": [], } + def forward(self, src_tokens, src_lengths): + if self.num_updates < self.encoder_freezing_updates: + with torch.no_grad(): + x = self._forward(src_tokens, src_lengths) + else: + x = self._forward(src_tokens, src_lengths) + return x + def reorder_encoder_out(self, encoder_out, new_order): new_encoder_out = ( [] if len(encoder_out["encoder_out"]) == 0 @@ -348,6 +371,10 @@ def reorder_encoder_out(self, encoder_out, new_order): "src_lengths": [], # B x 1 } + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + self.num_updates = num_updates + class TransformerDecoderScriptable(TransformerDecoder): def extract_features( @@ -373,6 +400,7 @@ def extract_features( @register_model_architecture(model_name="s2t_transformer", arch_name="s2t_transformer") def base_architecture(args): + args.encoder_freezing_updates = getattr(args, "encoder_freezing_updates", 0) # Convolutional subsampler args.conv_kernel_sizes = getattr(args, "conv_kernel_sizes", "5,5") args.conv_channels = getattr(args, "conv_channels", 1024) From 2d5eaa0e7b795633b7efd2645f26ab40b9b520d5 Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Thu, 25 Mar 2021 16:04:59 -0700 Subject: [PATCH 286/774] restore original module forward() during jit Summary: checkpoint_wrapper replaces m.forward with functools.partial(), but functools.partial is not compatible with jit. so we need to find a way to restore the original forward function for jit to pick it up correctly. I decided to add one extra attribute 'precheckpoint_forward' to the module. and then it's up to the jit workflow to restore this 'precheckpoint_forward' function to the original forward location for jitting. Also added a check that checkpoint_wrapper can't be called twice on the same module. Reviewed By: myleott Differential Revision: D27303905 fbshipit-source-id: 75bf3b5858ed130598dcc21d85a48b43c661818c --- fairseq/modules/checkpoint_activations.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index ae07dcfaa0..f4a277f349 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -8,7 +8,6 @@ import torch import torch.utils.checkpoint as checkpoint - from fairseq import utils @@ -26,9 +25,14 @@ def checkpoint_wrapper(m, offload_to_cpu=False): checkpointed_module = checkpoint_wrapper(my_module, offload_to_cpu=True) a, b = checkpointed_module(x, y=3, z=torch.Tensor([1])) """ + # should I check whether original_forward has already been set? + assert not hasattr( + m, "precheckpoint_forward" + ), "checkpoint function has already been applied?" + m.precheckpoint_forward = m.forward m.forward = functools.partial( _checkpointed_forward, - m.forward, # original_forward + m.precheckpoint_forward, # original_forward offload_to_cpu, ) return m From 6e91e226441fc3c68adf91bdef9f39d9d9dc2c9c Mon Sep 17 00:00:00 2001 From: Ning Dong <dnn@fb.com> Date: Thu, 25 Mar 2021 23:29:35 -0700 Subject: [PATCH 287/774] Script monotonic attention and related modules Summary: Add types and rewrite some part of the model so JIT compiler likes it Reviewed By: jmp84, sravyapopuri388 Differential Revision: D27194261 fbshipit-source-id: 594532212c907ed97fc711e4f6a2a211d7e2b67e --- .../models/transformer_monotonic_attention.py | 84 ++-- .../modules/fixed_pre_decision.py | 68 +++- .../modules/monotonic_multihead_attention.py | 374 ++++++++++++++++-- 3 files changed, 463 insertions(+), 63 deletions(-) diff --git a/examples/simultaneous_translation/models/transformer_monotonic_attention.py b/examples/simultaneous_translation/models/transformer_monotonic_attention.py index 65c12c6f5b..d7aeca5ea5 100644 --- a/examples/simultaneous_translation/models/transformer_monotonic_attention.py +++ b/examples/simultaneous_translation/models/transformer_monotonic_attention.py @@ -3,6 +3,8 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from typing import Dict, List, NamedTuple, Optional + import torch import torch.nn as nn import torch.nn.functional as F @@ -23,10 +25,22 @@ transformer_vaswani_wmt_en_de_big, transformer_vaswani_wmt_en_fr_big, ) +from torch import Tensor DEFAULT_MAX_SOURCE_POSITIONS = 1024 DEFAULT_MAX_TARGET_POSITIONS = 1024 +TransformerMonotonicDecoderOut = NamedTuple( + "TransformerMonotonicDecoderOut", + [ + ("action", int), + ("attn_list", Optional[List[Optional[Dict[str, Tensor]]]]), + ("step_list", Optional[List[Optional[Tensor]]]), + ("encoder_out", Optional[Dict[str, List[Tensor]]]), + ("encoder_padding_mask", Optional[Tensor]), + ], +) + @register_model("transformer_unidirectional") class TransformerUnidirectionalModel(TransformerModel): @@ -103,7 +117,10 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): ) def pre_attention( - self, prev_output_tokens, encoder_out_dict, incremental_state=None + self, + prev_output_tokens, + encoder_out_dict: Dict[str, List[Tensor]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, ): positions = ( self.embed_positions( @@ -118,7 +135,6 @@ def pre_attention( prev_output_tokens = prev_output_tokens[:, -1:] if positions is not None: positions = positions[:, -1:] - # embed tokens and positions x = self.embed_scale * self.embed_tokens(prev_output_tokens) @@ -143,7 +159,7 @@ def pre_attention( return x, encoder_out, encoder_padding_mask def post_attention(self, x): - if self.layer_norm: + if self.layer_norm is not None: x = self.layer_norm(x) # T x B x C -> B x T x C @@ -154,7 +170,11 @@ def post_attention(self, x): return x - def clear_cache(self, incremental_state, end_id=None): + def clear_cache( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + end_id: Optional[int] = None, + ): """ Clear cache in the monotonic layers. The cache is generated because of a forward pass of decode but no prediction. @@ -163,11 +183,18 @@ def clear_cache(self, incremental_state, end_id=None): if end_id is None: end_id = len(self.layers) - for j in range(end_id): - self.layers[j].prune_incremental_state(incremental_state) + for index, layer in enumerate(self.layers): + if index < end_id: + layer.prune_incremental_state(incremental_state) def extract_features( - self, prev_output_tokens, encoder_out, incremental_state=None, **unused + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, # unused + alignment_layer: Optional[int] = None, # unused + alignment_heads: Optional[int] = None, # unsed ): """ Similar to *forward* but only return features. @@ -178,13 +205,14 @@ def extract_features( - a dictionary with any model-specific outputs """ # incremental_state = None + assert encoder_out is not None (x, encoder_outs, encoder_padding_mask) = self.pre_attention( prev_output_tokens, encoder_out, incremental_state ) attn = None inner_states = [x] - attn_list = [] - step_list = [] + attn_list: List[Optional[Dict[str, Tensor]]] = [] + step_list: List[Optional[Tensor]] = [] for i, layer in enumerate(self.layers): @@ -204,35 +232,43 @@ def extract_features( if incremental_state is not None: curr_steps = layer.get_head_steps(incremental_state) step_list.append(curr_steps) - - if incremental_state.get("online", True): + if_online = incremental_state["online"]["only"] + assert if_online is not None + if if_online.to(torch.bool): # Online indicates that the encoder states are still changing + assert attn is not None + assert curr_steps is not None p_choose = ( - attn["p_choose"] - .squeeze(0) - .squeeze(1) - .gather(1, curr_steps.t()) + attn["p_choose"].squeeze(0).squeeze(1).gather(1, curr_steps.t()) ) new_steps = curr_steps + (p_choose < 0.5).t().type_as(curr_steps) + src = incremental_state["steps"]["src"] + assert src is not None - if (new_steps >= incremental_state["steps"]["src"]).any(): + if (new_steps >= src).any(): # We need to prune the last self_attn saved_state # if model decide not to read # otherwise there will be duplicated saved_state self.clear_cache(incremental_state, i + 1) - return x, {"action": 0} + return x, TransformerMonotonicDecoderOut( + action=0, + attn_list=None, + step_list=None, + encoder_out=None, + encoder_padding_mask=None, + ) x = self.post_attention(x) - return x, { - "action": 1, - "attn_list": attn_list, - "step_list": step_list, - "encoder_out": encoder_out, - "encoder_padding_mask": encoder_padding_mask, - } + return x, TransformerMonotonicDecoderOut( + action=1, + attn_list=attn_list, + step_list=step_list, + encoder_out=encoder_out, + encoder_padding_mask=encoder_padding_mask, + ) def reorder_incremental_state(self, incremental_state, new_order): super().reorder_incremental_state(incremental_state, new_order) diff --git a/examples/simultaneous_translation/modules/fixed_pre_decision.py b/examples/simultaneous_translation/modules/fixed_pre_decision.py index cc5e7ad532..0e9dfb6dfd 100644 --- a/examples/simultaneous_translation/modules/fixed_pre_decision.py +++ b/examples/simultaneous_translation/modules/fixed_pre_decision.py @@ -1,6 +1,7 @@ from functools import partial import torch +from torch import Tensor import math import torch.nn.functional as F @@ -10,7 +11,7 @@ MonotonicMultiheadAttentionHardAligned, MonotonicMultiheadAttentionInfiniteLookback, ) - +from typing import Dict, Optional def fixed_pooling_monotonic_attention(monotonic_attention): def create_model(monotonic_attention, klass): @@ -80,7 +81,7 @@ def add_args(parser): def insert_zeros(self, x): bsz_num_heads, tgt_len, src_len = x.size() stride = self.pre_decision_ratio - weight = F.pad(x.new_ones(1, 1, 1), (stride - 1, 0)) + weight = F.pad(torch.ones(1, 1, 1).to(x), (stride - 1, 0)) x_upsample = F.conv_transpose1d( x.view(-1, src_len).unsqueeze(1), weight, @@ -89,25 +90,64 @@ def insert_zeros(self, x): ) return x_upsample.squeeze(1).view(bsz_num_heads, tgt_len, -1) + def p_choose_waitk( + self, query, key, key_padding_mask: Optional[Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None + ): + """ + query: bsz, tgt_len + key: bsz, src_len + key_padding_mask: bsz, src_len + """ + if incremental_state is not None: + # Retrieve target length from incremental states + # For inference the length of query is always 1 + tgt = incremental_state["steps"]["tgt"] + assert tgt is not None + tgt_len = int(tgt) + else: + tgt_len, bsz, _ = query.size() + + src_len, bsz, _ = key.size() + + p_choose = torch.ones(bsz, tgt_len, src_len).to(query) + p_choose = torch.tril(p_choose, diagonal=self.waitk_lagging - 1) + p_choose = torch.triu(p_choose, diagonal=self.waitk_lagging - 1) + + if incremental_state is not None: + p_choose = p_choose[:, -1:] + tgt_len = 1 + + # Extend to each head + p_choose = ( + p_choose.contiguous() + .unsqueeze(1) + .expand(-1, self.num_heads, -1, -1) + .contiguous() + .view(-1, tgt_len, src_len) + ) + + return p_choose + def p_choose( self, - query, - key, - key_padding_mask=None, - incremental_state=None, - **extra_args + query: Optional[Tensor], + key: Optional[Tensor], + key_padding_mask: Optional[Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, ): + assert key is not None + assert query is not None src_len = key.size(0) tgt_len = query.size(0) batch_size = query.size(1) if self.pre_decision_ratio == 1: - return super().p_choose( + return self.p_choose_waitk( query, key, - key_padding_mask=None, - incremental_state=None, - **extra_args + key_padding_mask, + incremental_state=incremental_state, ) key_pool = self.pooling_layer(key.transpose(0, 2)).transpose(0, 2) @@ -133,7 +173,7 @@ def p_choose( if key_padding_mask_pool is not None: key_padding_mask_pool = key_padding_mask_pool[:-1] - p_choose_pooled = super().p_choose( + p_choose_pooled = self.p_choose_waitk( query, key_pool, key_padding_mask_pool, @@ -148,11 +188,11 @@ def p_choose( p_choose = torch.cat( [ p_choose, - p_choose.new_zeros( + torch.zeros( p_choose.size(0), tgt_len, src_len - p_choose.size(-1) - ) + ).to(p_choose) ], dim=2 ) diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index 49882afcd8..2e3ce8742f 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -6,6 +6,7 @@ import math import torch +from torch import Tensor import torch.nn as nn import torch.nn.functional as F @@ -19,6 +20,7 @@ from fairseq.utils import convert_padding_direction from . import register_monotonic_attention +from typing import Dict, Optional @with_incremental_state @@ -101,13 +103,13 @@ def attn_energy( if key_padding_mask is not None: attn_energy = attn_energy.masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(2).bool(), + key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), float("-inf"), ) return attn_energy - def expected_alignment_train(self, p_choose, key_padding_mask): + def expected_alignment_train(self, p_choose, key_padding_mask: Optional[Tensor]): """ Calculating expected alignment for MMA Mask is not need because p_choose will be 0 if masked @@ -175,7 +177,7 @@ def expected_alignment_train(self, p_choose, key_padding_mask): return alpha def expected_alignment_infer( - self, p_choose, encoder_padding_mask, incremental_state + self, p_choose, encoder_padding_mask: Optional[Tensor], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] ): # TODO modify this function """ @@ -201,6 +203,7 @@ def expected_alignment_infer( "head_step", p_choose.new_zeros([bsz, self.num_heads]).long() ) + assert prev_monotonic_step is not None bsz, num_heads = prev_monotonic_step.size() assert num_heads == self.num_heads assert bsz * num_heads == bsz_num_heads @@ -292,16 +295,14 @@ def expected_alignment_infer( return alpha - def _get_monotonic_buffer(self, incremental_state): - return utils.get_incremental_state( - self, + def _get_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): + return self.get_incremental_state( incremental_state, 'monotonic', ) or {} - def _set_monotonic_buffer(self, incremental_state, buffer): - utils.set_incremental_state( - self, + def _set_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], buffer: Dict[str, Optional[Tensor]]): + self.set_incremental_state( incremental_state, 'monotonic', buffer, @@ -312,8 +313,8 @@ def v_proj_output(self, value): def forward( self, query, key, value, - key_padding_mask=None, attn_mask=None, incremental_state=None, - need_weights=True, static_kv=False, *args, **kwargs + key_padding_mask=None, attn_mask=None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + need_weights=True, static_kv=False ): tgt_len, bsz, embed_dim = query.size() @@ -384,7 +385,328 @@ def __init__(self, args): self.q_in_proj = {"monotonic": self.q_proj} self.v_in_proj = {"output": self.v_proj} - def input_projections(self, query, key, value, name): + @staticmethod + def add_args(parser): + # fmt: off + parser.add_argument('--no-mass-preservation', action="store_false", + dest="mass_preservation", + help='Do not stay on the last token when decoding') + parser.add_argument('--mass-preservation', action="store_true", + dest="mass_preservation", + help='Stay on the last token when decoding') + parser.set_defaults(mass_preservation=True) + parser.add_argument('--noise-var', type=float, default=1.0, + help='Variance of discretness noise') + parser.add_argument('--noise-mean', type=float, default=0.0, + help='Mean of discretness noise') + parser.add_argument('--noise-type', type=str, default="flat", + help='Type of discretness noise') + parser.add_argument('--energy-bias', action="store_true", + default=False, + help='Bias for energy') + parser.add_argument('--energy-bias-init', type=float, default=-2.0, + help='Initial value of the bias for energy') + parser.add_argument('--attention-eps', type=float, default=1e-6, + help='Epsilon when calculating expected attention') + + def p_choose(self, *args): + raise NotImplementedError + + def attn_energy( + self, q_proj: Optional[Tensor], k_proj: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, attn_mask: Optional[Tensor] = None + ): + """ + Calculating monotonic energies + + ============================================================ + Expected input size + q_proj: bsz * num_heads, tgt_len, self.head_dim + k_proj: bsz * num_heads, src_len, self.head_dim + key_padding_mask: bsz, src_len + attn_mask: tgt_len, src_len + """ + assert q_proj is not None # Optional[Tensor] annotations in the signature above are to make the JIT compiler happy + assert k_proj is not None + bsz, tgt_len, embed_dim = q_proj.size() + bsz = bsz // self.num_heads + src_len = k_proj.size(1) + + attn_energy = ( + torch.bmm(q_proj, k_proj.transpose(1, 2)) + self.energy_bias + ) + + if attn_mask is not None: + attn_mask = attn_mask.unsqueeze(0) + attn_energy += attn_mask + + attn_energy = attn_energy.view(bsz, self.num_heads, tgt_len, src_len) + + if key_padding_mask is not None: + attn_energy = attn_energy.masked_fill( + key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), + float("-inf"), + ) + + return attn_energy + + def expected_alignment_train(self, p_choose, key_padding_mask: Optional[Tensor]): + """ + Calculating expected alignment for MMA + Mask is not need because p_choose will be 0 if masked + + q_ij = (1 − p_{ij−1})q_{ij−1} + a+{i−1j} + a_ij = p_ij q_ij + + Parallel solution: + ai = p_i * cumprod(1 − pi) * cumsum(a_i / cumprod(1 − pi)) + + ============================================================ + Expected input size + p_choose: bsz * num_heads, tgt_len, src_len + """ + + # p_choose: bsz * num_heads, tgt_len, src_len + bsz_num_heads, tgt_len, src_len = p_choose.size() + + # cumprod_1mp : bsz * num_heads, tgt_len, src_len + cumprod_1mp = exclusive_cumprod(1 - p_choose, dim=2, eps=self.eps) + cumprod_1mp_clamp = torch.clamp(cumprod_1mp, self.eps, 1.0) + + init_attention = p_choose.new_zeros([bsz_num_heads, 1, src_len]) + init_attention[:, :, 0] = 1.0 + + previous_attn = [init_attention] + + for i in range(tgt_len): + # p_choose: bsz * num_heads, tgt_len, src_len + # cumprod_1mp_clamp : bsz * num_heads, tgt_len, src_len + # previous_attn[i]: bsz * num_heads, 1, src_len + # alpha_i: bsz * num_heads, src_len + alpha_i = ( + p_choose[:, i] + * cumprod_1mp[:, i] + * torch.cumsum(previous_attn[i][:, 0] / cumprod_1mp_clamp[:, i], dim=1) + ).clamp(0, 1.0) + previous_attn.append(alpha_i.unsqueeze(1)) + + # alpha: bsz * num_heads, tgt_len, src_len + alpha = torch.cat(previous_attn[1:], dim=1) + + if self.mass_preservation: + # Last token has the residual probabilities + if key_padding_mask is not None and key_padding_mask[:, -1].any(): + # right padding + batch_size = key_padding_mask.size(0) + residuals = 1 - alpha.sum(dim=-1, keepdim=True).clamp(0.0, 1.0) + src_lens = src_len - key_padding_mask.sum(dim=1, keepdim=True) + src_lens = src_lens.expand( + batch_size, self.num_heads + ).contiguous().view(-1, 1) + src_lens = src_lens.expand(-1, tgt_len).contiguous() + # add back the last value + residuals += alpha.gather(2, src_lens.unsqueeze(-1) - 1) + alpha = alpha.scatter(2, src_lens.unsqueeze(-1) - 1, residuals) + else: + residuals = 1 - alpha[:, :, :-1].sum(dim=-1).clamp(0.0, 1.0) + alpha[:, :, -1] = residuals + + if torch.isnan(alpha).any(): + # Something is wrong + raise RuntimeError("NaN in alpha.") + + return alpha + + def expected_alignment_infer( + self, p_choose, encoder_padding_mask: Optional[Tensor], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] + ): + # TODO modify this function + """ + Calculating mo alignment for MMA during inference time + + ============================================================ + Expected input size + p_choose: bsz * num_heads, tgt_len, src_len + incremental_state: dict + encodencoder_padding_mask: bsz * src_len + """ + # p_choose: bsz * self.num_heads, src_len + bsz_num_heads, tgt_len, src_len = p_choose.size() + # One token at a time + assert tgt_len == 1 + p_choose = p_choose[:, 0, :] + + monotonic_cache = self._get_monotonic_buffer(incremental_state) + + # prev_monotonic_step: bsz, num_heads + bsz = bsz_num_heads // self.num_heads + prev_monotonic_step = monotonic_cache.get( + "head_step", + p_choose.new_zeros([bsz, self.num_heads]).long() + ) + assert prev_monotonic_step is not None + bsz, num_heads = prev_monotonic_step.size() + assert num_heads == self.num_heads + assert bsz * num_heads == bsz_num_heads + + # p_choose: bsz, num_heads, src_len + p_choose = p_choose.view(bsz, num_heads, src_len) + + if encoder_padding_mask is not None: + src_lengths = src_len - \ + encoder_padding_mask.sum(dim=1, keepdim=True).long() + else: + src_lengths = torch.ones(bsz, 1).to(prev_monotonic_step) * src_len + + # src_lengths: bsz, num_heads + src_lengths = src_lengths.expand_as(prev_monotonic_step) + # new_monotonic_step: bsz, num_heads + new_monotonic_step = prev_monotonic_step + + step_offset = torch.tensor(0) + if encoder_padding_mask is not None: + if encoder_padding_mask[:, 0].any(): + # left_pad_source = True: + step_offset = encoder_padding_mask.sum(dim=-1, keepdim=True) + + max_steps = src_lengths - 1 if self.mass_preservation else src_lengths + + # finish_read: bsz, num_heads + finish_read = new_monotonic_step.eq(max_steps) + p_choose_i = torch.tensor(1) + while finish_read.sum().item() < bsz * self.num_heads: + # p_choose: bsz * self.num_heads, src_len + # only choose the p at monotonic steps + # p_choose_i: bsz , self.num_heads + p_choose_i = ( + p_choose.gather( + 2, + (step_offset + new_monotonic_step) + .unsqueeze(2) + .clamp(0, src_len - 1), + ) + ).squeeze(2) + + action = ( + (p_choose_i < 0.5) + .type_as(prev_monotonic_step) + .masked_fill(finish_read, 0) + ) + # 1 x bsz + # sample actions on unfinished seq + # 1 means stay, finish reading + # 0 means leave, continue reading + # dist = torch.distributions.bernoulli.Bernoulli(p_choose) + # action = dist.sample().type_as(finish_read) * (1 - finish_read) + + new_monotonic_step += action + + finish_read = new_monotonic_step.eq(max_steps) | (action == 0) + + monotonic_cache["head_step"] = new_monotonic_step + # Whether a head is looking for new input + monotonic_cache["head_read"] = ( + new_monotonic_step.eq(max_steps) & (p_choose_i < 0.5) + ) + + # alpha: bsz * num_heads, 1, src_len + # new_monotonic_step: bsz, num_heads + alpha = ( + p_choose + .new_zeros([bsz * self.num_heads, src_len]) + .scatter( + 1, + (step_offset + new_monotonic_step) + .view(bsz * self.num_heads, 1).clamp(0, src_len - 1), + 1 + ) + ) + + if not self.mass_preservation: + alpha = alpha.masked_fill( + (new_monotonic_step == max_steps) + .view(bsz * self.num_heads, 1), + 0 + ) + + alpha = alpha.unsqueeze(1) + + self._set_monotonic_buffer(incremental_state, monotonic_cache) + + return alpha + + def _get_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): + maybe_incremental_state = self.get_incremental_state( + incremental_state, + 'monotonic', + ) + if maybe_incremental_state is None: + typed_empty_dict: Dict[str, Optional[Tensor]] = {} + return typed_empty_dict + else: + return maybe_incremental_state + + def _set_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], buffer: Dict[str, Optional[Tensor]]): + self.set_incremental_state( + incremental_state, + 'monotonic', + buffer, + ) + + def forward( + self, query: Optional[Tensor], key: Optional[Tensor], value: Optional[Tensor], + key_padding_mask: Optional[Tensor] = None, attn_mask: Optional[Tensor] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + need_weights: bool = True, static_kv: bool = False, need_head_weights: bool = False, + ): + assert query is not None + assert value is not None + tgt_len, bsz, embed_dim = query.size() + src_len = value.size(0) + + # stepwise prob + # p_choose: bsz * self.num_heads, tgt_len, src_len + p_choose = self.p_choose( + query, key, key_padding_mask, incremental_state, + ) + + # expected alignment alpha + # bsz * self.num_heads, tgt_len, src_len + if incremental_state is not None: + alpha = self.expected_alignment_infer( + p_choose, key_padding_mask, incremental_state) + else: + alpha = self.expected_alignment_train( + p_choose, key_padding_mask) + + # expected attention beta + # bsz * self.num_heads, tgt_len, src_len + beta = self.expected_attention( + alpha, query, key, value, + key_padding_mask, attn_mask, + incremental_state + ) + + attn_weights = beta + + v_proj = self.v_proj_output(value) + assert v_proj is not None + + attn = torch.bmm(attn_weights.type_as(v_proj), v_proj) + + attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) + + attn = self.out_proj(attn) + + beta = beta.view(bsz, self.num_heads, tgt_len, src_len) + alpha = alpha.view(bsz, self.num_heads, tgt_len, src_len) + p_choose = p_choose.view(bsz, self.num_heads, tgt_len, src_len) + + return attn, { + "alpha": alpha, + "beta": beta, + "p_choose": p_choose, + } + + def input_projections(self, query: Optional[Tensor], key: Optional[Tensor], value: Optional[Tensor], name: str): """ Prepare inputs for multihead attention @@ -398,7 +720,7 @@ def input_projections(self, query, key, value, name): if query is not None: bsz = query.size(1) - q = self.q_in_proj[name](query) + q = self.q_proj(query) q *= self.scaling q = q.contiguous().view( -1, bsz * self.num_heads, self.head_dim @@ -408,7 +730,7 @@ def input_projections(self, query, key, value, name): if key is not None: bsz = key.size(1) - k = self.k_in_proj[name](key) + k = self.k_proj(key) k = k.contiguous().view( -1, bsz * self.num_heads, self.head_dim ).transpose(0, 1) @@ -417,7 +739,7 @@ def input_projections(self, query, key, value, name): if value is not None: bsz = value.size(1) - v = self.v_in_proj[name](value) + v = self.v_proj(value) v = v.contiguous().view( -1, bsz * self.num_heads, self.head_dim ).transpose(0, 1) @@ -427,8 +749,8 @@ def input_projections(self, query, key, value, name): return q, k, v def p_choose( - self, query, key, key_padding_mask=None, - incremental_state=None, *extra_args + self, query: Optional[Tensor], key: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None ): """ Calculating step wise prob for reading and writing @@ -507,8 +829,8 @@ def init_soft_attention(self): nn.init.xavier_uniform_(self.q_in_proj["soft"].weight) def expected_attention( - self, alpha, query, key, value, - key_padding_mask, attn_mask, incremental_state + self, alpha, query: Optional[Tensor], key: Optional[Tensor], value: Optional[Tensor], + key_padding_mask: Optional[Tensor], attn_mask: Optional[Tensor], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] ): # monotonic attention, we will calculate milk here bsz_x_num_heads, tgt_len, src_len = alpha.size() @@ -524,7 +846,9 @@ def expected_attention( if incremental_state is not None: monotonic_cache = self._get_monotonic_buffer(incremental_state) - monotonic_length = monotonic_cache["head_step"] + 1 + head_step = monotonic_cache["head_step"] + assert head_step is not None + monotonic_length = head_step + 1 step_offset = 0 if key_padding_mask is not None: if key_padding_mask[:, 0].any(): @@ -536,7 +860,7 @@ def expected_attention( soft_energy.size(2), 1 ).unsqueeze(1) - soft_energy = soft_energy.masked_fill(~mask.bool(), float("-inf")) + soft_energy = soft_energy.masked_fill(~mask.to(torch.bool), float("-inf")) soft_energy = soft_energy - soft_energy.max(dim=2, keepdim=True)[0] exp_soft_energy = torch.exp(soft_energy) exp_soft_energy_sum = exp_soft_energy.sum(dim=2) @@ -557,7 +881,7 @@ def expected_attention( if key_padding_mask is not None: beta = beta.masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(2).bool(), 0) + key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), 0) beta = beta / beta.sum(dim=3, keepdim=True) beta = beta.view(bsz * self.num_heads, tgt_len, src_len) @@ -595,8 +919,8 @@ def add_args(parser): ) def p_choose( - self, query, key, key_padding_mask=None, - incremental_state=None, *extra_args + self, query: Optional[Tensor], key: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, ): """ query: bsz, tgt_len @@ -612,7 +936,7 @@ def p_choose( src_len, bsz, _ = key.size() - p_choose = query.new_ones(bsz, tgt_len, src_len) + p_choose = torch.ones(bsz, tgt_len, src_len).to(query) p_choose = torch.tril(p_choose, diagonal=self.waitk_lagging - 1) p_choose = torch.triu(p_choose, diagonal=self.waitk_lagging - 1) From 93bb1905ac56a687d9a550537704cb339b226a9e Mon Sep 17 00:00:00 2001 From: Ning Dong <dnn@fb.com> Date: Thu, 25 Mar 2021 23:29:35 -0700 Subject: [PATCH 288/774] Script SimulConvTransformerModel Summary: Copy & paste forward function from parent classes to ConvTransformerEmformerEncoder / TransformerMonotonicDecoderLayer, and modify slightly to make JIT compiler happy. TS in general doesn't work well with polymorphism+inheritance. Reviewed By: jmp84, sravyapopuri388 Differential Revision: D27194275 fbshipit-source-id: 5248f017ac86adcb09f398038c10a0d20bc03453 --- .../models/convtransformer_simul_trans.py | 55 +++++- .../modules/monotonic_transformer_layer.py | 168 ++++++++++++++++-- 2 files changed, 207 insertions(+), 16 deletions(-) diff --git a/examples/simultaneous_translation/models/convtransformer_simul_trans.py b/examples/simultaneous_translation/models/convtransformer_simul_trans.py index 0b15e93fea..4a26422f65 100644 --- a/examples/simultaneous_translation/models/convtransformer_simul_trans.py +++ b/examples/simultaneous_translation/models/convtransformer_simul_trans.py @@ -20,8 +20,10 @@ SequenceEncoder, AugmentedMemoryConvTransformerEncoder, ) -from fairseq.models.speech_to_text.modules.emformer import emformer_encoder +from torch import nn, Tensor +from typing import Dict, List +from fairseq.models.speech_to_text.modules.emformer import NoSegAugmentedMemoryTransformerEncoderLayer @register_model("convtransformer_simul_trans") class SimulConvTransformerModel(ConvTransformerModel): @@ -97,9 +99,56 @@ def augmented_memory_convtransformer_espnet(args): # ============================================================================ # -@emformer_encoder class ConvTransformerEmformerEncoder(ConvTransformerEncoder): - pass + def __init__(self, args): + super().__init__(args) + stride = self.conv_layer_stride(args) + trf_left_context = args.segment_left_context // stride + trf_right_context = args.segment_right_context // stride + context_config = [trf_left_context, trf_right_context] + self.transformer_layers = nn.ModuleList( + [ + NoSegAugmentedMemoryTransformerEncoderLayer( + input_dim=args.encoder_embed_dim, + num_heads=args.encoder_attention_heads, + ffn_dim=args.encoder_ffn_embed_dim, + num_layers=args.encoder_layers, + dropout_in_attn=args.dropout, + dropout_on_attn=args.dropout, + dropout_on_fc1=args.dropout, + dropout_on_fc2=args.dropout, + activation_fn=args.activation_fn, + context_config=context_config, + segment_size=args.segment_length, + max_memory_size=args.max_memory_size, + scaled_init=True, # TODO: use constant for now. + tanh_on_mem=args.amtrf_tanh_on_mem, + ) + ] + ) + self.conv_transformer_encoder = ConvTransformerEncoder(args) + + def forward(self, src_tokens, src_lengths): + encoder_out: Dict[str, List[Tensor]] = self.conv_transformer_encoder(src_tokens, src_lengths.to(src_tokens.device)) + output = encoder_out["encoder_out"][0] + encoder_padding_masks = encoder_out["encoder_padding_mask"] + + return { + "encoder_out": [output], + # This is because that in the original implementation + # the output didn't consider the last segment as right context. + "encoder_padding_mask": [encoder_padding_masks[0][:, : output.size(0)]] if len(encoder_padding_masks) > 0 + else [], + "encoder_embedding": [], + "encoder_states": [], + "src_tokens": [], + "src_lengths": [], + } + + @staticmethod + def conv_layer_stride(args): + # TODO: make it configurable from the args + return 4 @register_model("convtransformer_emformer") diff --git a/examples/simultaneous_translation/modules/monotonic_transformer_layer.py b/examples/simultaneous_translation/modules/monotonic_transformer_layer.py index e6e1850a18..bcd45aa8a6 100644 --- a/examples/simultaneous_translation/modules/monotonic_transformer_layer.py +++ b/examples/simultaneous_translation/modules/monotonic_transformer_layer.py @@ -7,6 +7,11 @@ from . import build_monotonic_attention +from typing import Dict, List, Optional + +import torch +from torch import Tensor + class TransformerMonotonicEncoderLayer(TransformerEncoderLayer): def forward(self, x, encoder_padding_mask): @@ -34,23 +39,160 @@ def __init__( self.embed_dim, export=getattr(args, "char_inputs", False) ) - def get_head_steps(self, incremental_state): + def get_head_steps(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): return self.encoder_attn._get_monotonic_buffer(incremental_state).get( "head_step" ) - def prune_incremental_state(self, incremental_state): - def prune(module): - input_buffer = module._get_input_buffer(incremental_state) - for key in ["prev_key", "prev_value"]: - if input_buffer[key].size(2) > 1: - input_buffer[key] = input_buffer[key][:, :, :-1, :] - else: - input_buffer = {} - break - module._set_input_buffer(incremental_state, input_buffer) - - prune(self.self_attn) + def prune_incremental_state(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): + input_buffer = self.self_attn._get_input_buffer(incremental_state) + for key in ["prev_key", "prev_value"]: + input_buffer_key = input_buffer[key] + assert input_buffer_key is not None + if input_buffer_key.size(2) > 1: + input_buffer[key] = input_buffer_key[:, :, :-1, :] + else: + typed_empty_dict: Dict[str, Optional[Tensor]] = {} + input_buffer = typed_empty_dict + break + assert incremental_state is not None + self.self_attn._set_input_buffer(incremental_state, input_buffer) def get_steps(self, incremental_state): return self.encoder_attn._get_monotonic_buffer(incremental_state).get("step", 0) + + def forward( + self, + x, + encoder_out: Optional[torch.Tensor] = None, + encoder_padding_mask: Optional[torch.Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + prev_self_attn_state: Optional[List[torch.Tensor]] = None, + prev_attn_state: Optional[List[torch.Tensor]] = None, + self_attn_mask: Optional[torch.Tensor] = None, + self_attn_padding_mask: Optional[torch.Tensor] = None, + need_attn: bool = False, + need_head_weights: bool = False, + ): + """ + Args: + x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)` + encoder_padding_mask (ByteTensor, optional): binary + ByteTensor of shape `(batch, src_len)` where padding + elements are indicated by ``1``. + need_attn (bool, optional): return attention weights + need_head_weights (bool, optional): return attention weights + for each head (default: return average over heads). + + Returns: + encoded output of shape `(seq_len, batch, embed_dim)` + """ + if need_head_weights: + need_attn = True + + residual = x + if self.normalize_before: + x = self.self_attn_layer_norm(x) + if prev_self_attn_state is not None: + prev_key, prev_value = prev_self_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_self_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_self_attn_state[2] + assert incremental_state is not None + self.self_attn._set_input_buffer(incremental_state, saved_state) + _self_attn_input_buffer = self.self_attn._get_input_buffer(incremental_state) + if self.cross_self_attention and not ( + incremental_state is not None + and _self_attn_input_buffer is not None + and "prev_key" in _self_attn_input_buffer + ): + if self_attn_mask is not None: + assert encoder_out is not None + self_attn_mask = torch.cat( + (x.new_zeros(x.size(0), encoder_out.size(0)), self_attn_mask), dim=1 + ) + if self_attn_padding_mask is not None: + if encoder_padding_mask is None: + assert encoder_out is not None + encoder_padding_mask = self_attn_padding_mask.new_zeros( + encoder_out.size(1), encoder_out.size(0) + ) + self_attn_padding_mask = torch.cat( + (encoder_padding_mask, self_attn_padding_mask), dim=1 + ) + assert encoder_out is not None + y = torch.cat((encoder_out, x), dim=0) + else: + y = x + + x, attn = self.self_attn( + query=x, + key=y, + value=y, + key_padding_mask=self_attn_padding_mask, + incremental_state=incremental_state, + need_weights=False, + attn_mask=self_attn_mask, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) + + assert self.encoder_attn is not None + residual = x + if self.normalize_before: + x = self.encoder_attn_layer_norm(x) + if prev_attn_state is not None: + prev_key, prev_value = prev_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_attn_state[2] + assert incremental_state is not None + self.encoder_attn._set_input_buffer(incremental_state, saved_state) + + x, attn = self.encoder_attn( + query=x, + key=encoder_out, + value=encoder_out, + key_padding_mask=encoder_padding_mask, + incremental_state=incremental_state, + static_kv=True, + need_weights=need_attn or (not self.training and self.need_attn), + need_head_weights=need_head_weights, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.encoder_attn_layer_norm(x) + + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) + if self.onnx_trace and incremental_state is not None: + saved_state = self.self_attn._get_input_buffer(incremental_state) + assert saved_state is not None + if self_attn_padding_mask is not None: + self_attn_state = [ + saved_state["prev_key"], + saved_state["prev_value"], + saved_state["prev_key_padding_mask"], + ] + else: + self_attn_state = [saved_state["prev_key"], saved_state["prev_value"]] + return x, attn, self_attn_state + return x, attn, None From a28511d43d2310226086c5fee82042fcdcf4cff0 Mon Sep 17 00:00:00 2001 From: Ning Dong <dnn@fb.com> Date: Thu, 25 Mar 2021 23:29:35 -0700 Subject: [PATCH 289/774] Ad-hoc changes Summary: Some ad-hoc changes to address errors when torchscripting simul ST models. Not sure if all of them are necessary and what the best practice is (yet) but having this diff to temporarily unblock. Reviewed By: sravyapopuri388 Differential Revision: D27194569 fbshipit-source-id: 8936f3edb408df7e1a3fd97c0e07b2356ff0d9b4 --- .../utils/data_utils.py | 2 +- .../agents/fairseq_simul_st_agent.py | 2 +- fairseq/data/data_utils.py | 20 +++++++++++-------- .../models/speech_to_text/convtransformer.py | 7 ++++--- .../models/speech_to_text/modules/emformer.py | 3 ++- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/examples/simultaneous_translation/utils/data_utils.py b/examples/simultaneous_translation/utils/data_utils.py index cc4729e63c..a763ea6686 100644 --- a/examples/simultaneous_translation/utils/data_utils.py +++ b/examples/simultaneous_translation/utils/data_utils.py @@ -28,7 +28,7 @@ def apply_mv_norm(features): return res -def lengths_to_encoder_padding_mask(lengths, batch_first=False): +def lengths_to_encoder_padding_mask(lengths, batch_first: bool = False): """ convert lengths (a 1-D Long/Int tensor) to 2-D binary tensor diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index 9ff07775da..58e38963b5 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -320,7 +320,7 @@ def policy(self, states): "tgt": 1 + len(states.units.target), } - states.incremental_states["online"] = not states.finish_read() + states.incremental_states["online"] = {"only": torch.tensor(not states.finish_read())} x, outputs = self.model.decoder.forward( prev_output_tokens=tgt_indices, diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 097ea09f76..de1d2edf11 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -512,23 +512,27 @@ def arrange(s, e, length, keep_length): def get_mem_usage(): - try: - import psutil + # try: + import psutil - mb = 1024 * 1024 - return f"used={psutil.virtual_memory().used / mb}Mb; avail={psutil.virtual_memory().available / mb}Mb" - except ImportError: - return "N/A" + mb = 1024 * 1024 + return f"used={psutil.virtual_memory().used / mb}Mb; avail={psutil.virtual_memory().available / mb}Mb" + # except ImportError: + # return "N/A" -def lengths_to_padding_mask(lens: torch.LongTensor) -> torch.BoolTensor: +# lens: torch.LongTensor +# returns: torch.BoolTensor +def lengths_to_padding_mask(lens): bsz, max_lens = lens.size(0), torch.max(lens).item() mask = torch.arange(max_lens).to(lens.device).view(1, max_lens) mask = mask.expand(bsz, -1) >= lens.view(bsz, 1).expand(-1, max_lens) return mask -def lengths_to_mask(lens: torch.LongTensor) -> torch.BoolTensor: +# lens: torch.LongTensor +# returns: torch.BoolTensor +def lengths_to_mask(lens): return ~lengths_to_padding_mask(lens) diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py index a4cbbcdeeb..40e6dd3f4e 100644 --- a/fairseq/models/speech_to_text/convtransformer.py +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -303,10 +303,10 @@ def forward(self, src_tokens, src_lengths): x = self.embed_scale * x subsampling_factor = int(max_seq_len * 1.0 / output_seq_len + 0.5) - + input_len_0 = (src_lengths.float() / subsampling_factor).ceil().long() + input_len_1 = x.size(0) * torch.ones([src_lengths.size(0)]).long().to(input_len_0.device) input_lengths = torch.min( - (src_lengths.float() / subsampling_factor).ceil().long(), - x.size(0) * src_lengths.new_ones([src_lengths.size(0)]).long() + input_len_0, input_len_1 ) encoder_padding_mask = lengths_to_padding_mask(input_lengths) @@ -323,6 +323,7 @@ def forward(self, src_tokens, src_lengths): else: maybe_encoder_padding_mask = encoder_padding_mask + return { "encoder_out": [x], "encoder_padding_mask": [maybe_encoder_padding_mask] diff --git a/fairseq/models/speech_to_text/modules/emformer.py b/fairseq/models/speech_to_text/modules/emformer.py index e026b86847..6ef76bd012 100644 --- a/fairseq/models/speech_to_text/modules/emformer.py +++ b/fairseq/models/speech_to_text/modules/emformer.py @@ -1812,7 +1812,8 @@ def __init__(self, args): def forward(self, src_tokens, src_lengths): encoder_out = super().forward(src_tokens, src_lengths) - (output, encoder_padding_masks, [], _) = encoder_out["encoder_out"][0] + output = encoder_out["encoder_out"][0] + encoder_padding_masks = encoder_out["encoder_padding_mask"][0] # This is because that in the original implementation # the output didn't consider the last segment as right context. From be1d186fa59aa19d7a0735a32af88b5a2bacc5ae Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Fri, 26 Mar 2021 07:18:08 -0700 Subject: [PATCH 290/774] FSDP uses new optimizer gathering to save optimizer state (#1744) Summary: - Full unflattened optimizer state dict is in `checkpoints/shard_0.pt`, other checkpoint files do not have the `last_optimizer_state` key. - requires master version of fairscale (eventually fairscale>=0.3.3) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1744 Reviewed By: myleott Differential Revision: D27342305 Pulled By: sshleifer fbshipit-source-id: 7442b8c6ed01599d8ab0050213e84051f4e98acd --- fairseq/checkpoint_utils.py | 2 +- fairseq/data/data_utils.py | 7 +++---- fairseq/trainer.py | 15 ++++++++++++++- scripts/test_fsdp.sh | 17 ++++++++++++++--- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 5a98dad2aa..86e00a7714 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -42,7 +42,7 @@ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): if cfg.no_save: return - trainer.consolidate_optimizer() + trainer.consolidate_optimizer() # TODO(SS): do we need this if no_save_optimizer_state if not trainer.should_save_checkpoint_on_current_rank: return diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index de1d2edf11..4424d1dc53 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -312,13 +312,12 @@ def batch_by_size( ) except ImportError: raise ImportError( - "Please build Cython components with: `pip install --editable .` " - "or `python setup.py build_ext --inplace`" + "Please build Cython components with: " + "`python setup.py build_ext --inplace`" ) except ValueError: raise ValueError( - "Please build (or rebuild) Cython components with: `pip install " - " --editable .` or `python setup.py build_ext --inplace`." + "Please build (or rebuild) Cython components with `python setup.py build_ext --inplace`." ) # added int() to avoid TypeError: an integer is required diff --git a/fairseq/trainer.py b/fairseq/trainer.py index f7897070c7..4535e9bda7 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -331,9 +331,15 @@ def _build_optimizer(self): def consolidate_optimizer(self): """For OSS, we need to consolidate the state dict.""" + self._gathered_optim_state = None if hasattr(self.optimizer.optimizer, "consolidate_state_dict"): self.optimizer.optimizer.consolidate_state_dict() + elif self.cfg.distributed_training.ddp_backend == 'fully_sharded': + self._gathered_optim_state = self.model.gather_full_optim_state_dict(self.optimizer, + recipient_rank=0) + + def state_dict(self): state_dict = { "args": None, # legacy @@ -362,7 +368,11 @@ def state_dict(self): } } if not self.cfg.checkpoint.no_save_optimizer_state: - state_dict["last_optimizer_state"] = self.optimizer.state_dict() + if self._gathered_optim_state is not None: + state_dict["last_optimizer_state"] = self._gathered_optim_state + self._gathered_optim_state = None + else: + state_dict["last_optimizer_state"] = self.optimizer.state_dict() return state_dict def save_checkpoint(self, filename, extra_state): @@ -478,6 +488,9 @@ def load_checkpoint( last_optim_state = self.optimizer.broadcast_global_state_dict( last_optim_state ) + elif self.cfg.distributed_training.ddp_backend == 'fully_sharded': + last_optim_state = self.model.get_shard_from_optim_state_dict(last_optim_state) + self.optimizer.load_state_dict(last_optim_state, optimizer_overrides) self.set_num_updates(last_optim["num_updates"]) diff --git a/scripts/test_fsdp.sh b/scripts/test_fsdp.sh index 0f4d6c420b..1f428a035e 100755 --- a/scripts/test_fsdp.sh +++ b/scripts/test_fsdp.sh @@ -1,13 +1,24 @@ #!/usr/bin/env bash rm -rf fsdp_dummy mkdir -p fsdp_dummy -fairseq-train /private/home/sshleifer/data-bin/stories_mmap \ +CUDA_VISIBLE_DEVICES=0,1,2,3 fairseq-train /private/home/sshleifer/data-bin/stories_mmap \ --ddp-backend fully_sharded --fp16 --fp16-init-scale 4 \ --cpu-offload --checkpoint-activations \ --task language_modeling --tokens-per-sample 256 --batch-size 8 \ --arch transformer_lm_gpt2_tiny \ --optimizer cpu_adam --adam-betas "(0.9,0.98)" \ --lr 0.0001 --lr-scheduler polynomial_decay --warmup-updates 5 --total-num-update 10 \ - --max-update 10 --log-format json --log-interval 1 \ - --save-interval-updates 10 --save-dir fsdp_dummy \ + --max-update 5 --log-format json --log-interval 1 \ + --save-interval-updates 5 --save-dir fsdp_dummy --disable-validation \ --restore-file x.pt "$@" + +# Now we try to load the checkpoint +CUDA_VISIBLE_DEVICES=0,1 fairseq-train /private/home/sshleifer/data-bin/stories_mmap \ + --ddp-backend fully_sharded --fp16 --fp16-init-scale 4 \ + --cpu-offload --checkpoint-activations \ + --task language_modeling --tokens-per-sample 256 --batch-size 8 \ + --arch transformer_lm_gpt2_tiny \ + --optimizer cpu_adam --adam-betas "(0.9,0.98)" \ + --lr 0.0001 --lr-scheduler polynomial_decay --warmup-updates 5 --total-num-update 10 \ + --max-update 2 --log-format json --log-interval 1 \ + --save-interval-updates 2 --save-dir fsdp_dummy From 0975816a853eed81059db9ca02ddd3c73ea64926 Mon Sep 17 00:00:00 2001 From: Ning Dong <dnn@fb.com> Date: Fri, 26 Mar 2021 21:59:51 -0700 Subject: [PATCH 291/774] Add back try/except in data_utils Summary: Accidentally removed try/except block in D27194569 (https://github.com/pytorch/fairseq/commit/a28511d43d2310226086c5fee82042fcdcf4cff0) and caused OSS unit test failure. Reviewed By: myleott Differential Revision: D27374072 fbshipit-source-id: 154c92eae106aa3bf6b406d52a8647db140dc6b3 --- fairseq/data/data_utils.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 4424d1dc53..79df6f3769 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -511,13 +511,13 @@ def arrange(s, e, length, keep_length): def get_mem_usage(): - # try: - import psutil + try: + import psutil - mb = 1024 * 1024 - return f"used={psutil.virtual_memory().used / mb}Mb; avail={psutil.virtual_memory().available / mb}Mb" - # except ImportError: - # return "N/A" + mb = 1024 * 1024 + return f"used={psutil.virtual_memory().used / mb}Mb; avail={psutil.virtual_memory().available / mb}Mb" + except ImportError: + return "N/A" # lens: torch.LongTensor From 1c9738c6e9ae2e6612e3f8e4f841d22fbfbfa68c Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <31931787+wnhsu@users.noreply.github.com> Date: Mon, 29 Mar 2021 12:09:59 -0700 Subject: [PATCH 292/774] fix speech_recognition hydra decoder bugs (#1742) Summary: ## What does this PR do? Bug 1: generated hypotheses and references transcripts are incomplete when using data_parallel_world_size > 1 Reason: lack of barrier to ensure all workers completes dumping transcripts before starting merging transcripts Bug 2: program failed when using data_parallel_world_size == 1 Reason: unnecessary reduce operation is introduced / transcripts do not need to be merged Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1742 Reviewed By: alexeib Differential Revision: D27403362 Pulled By: wnhsu fbshipit-source-id: b74889660c7253264b986ea35c248d80e0e32358 --- examples/speech_recognition/hydra/decoder.py | 2 +- examples/speech_recognition/hydra/infer.py | 52 +++++++++++--------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/examples/speech_recognition/hydra/decoder.py b/examples/speech_recognition/hydra/decoder.py index 41fcbd7087..d182b95a32 100644 --- a/examples/speech_recognition/hydra/decoder.py +++ b/examples/speech_recognition/hydra/decoder.py @@ -250,7 +250,7 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: for token in spelling ] assert tgt_dict.unk() not in spelling_idxs, \ - f"{spelling} {spelling_idxs}" + f"{word} {spelling} {spelling_idxs}" self.trie.insert(spelling_idxs, word_idx, score) self.trie.smear(SmearingMode.MAX) diff --git a/examples/speech_recognition/hydra/infer.py b/examples/speech_recognition/hydra/infer.py index b1c985bc0d..1b49823553 100644 --- a/examples/speech_recognition/hydra/infer.py +++ b/examples/speech_recognition/hydra/infer.py @@ -155,27 +155,29 @@ def merge_shards(self) -> None: shard_id = self.data_parallel_rank num_shards = self.data_parallel_world_size - def merge_shards_with_root(fname: str) -> None: - logger.info("Merging %s on shard %d", fname, shard_id) - base_fpath = Path(f"{fname}.0") - with open(base_fpath, "a") as out_file: - for s in range(1, num_shards): - shard_fpath = Path(f"{fname}.{s}") - with open(shard_fpath, "r") as in_file: - for line in in_file: - out_file.write(line) - shard_fpath.unlink() - shutil.move(f"{fname}.0", fname) - - if shard_id == (0 % num_shards): - merge_shards_with_root("hypo.word") - if shard_id == (1 % num_shards): - merge_shards_with_root("hypo.units") - if shard_id == (2 % num_shards): - merge_shards_with_root("ref.word") - if shard_id == (3 % num_shards): - merge_shards_with_root("ref.units") - dist.barrier() + if self.data_parallel_world_size > 1: + def merge_shards_with_root(fname: str) -> None: + logger.info("Merging %s on shard %d", fname, shard_id) + base_fpath = Path(f"{fname}.0") + with open(base_fpath, "a") as out_file: + for s in range(1, num_shards): + shard_fpath = Path(f"{fname}.{s}") + with open(shard_fpath, "r") as in_file: + for line in in_file: + out_file.write(line) + shard_fpath.unlink() + shutil.move(f"{fname}.0", fname) + + dist.barrier() # ensure all shards finished writing + if shard_id == (0 % num_shards): + merge_shards_with_root("hypo.word") + if shard_id == (1 % num_shards): + merge_shards_with_root("hypo.units") + if shard_id == (2 % num_shards): + merge_shards_with_root("ref.word") + if shard_id == (3 % num_shards): + merge_shards_with_root("ref.units") + dist.barrier() def optimize_model(self, model: FairseqModel) -> None: gcfg = self.cfg.generation @@ -370,7 +372,7 @@ def main(cfg: InferConfig) -> float: if cfg.common.cpu: logger.warning("Merging WER requires CUDA.") - else: + elif processor.data_parallel_world_size > 1: stats = torch.LongTensor([errs_t, leng_t]).cuda() dist.all_reduce(stats, op=dist.ReduceOp.SUM) errs_t, leng_t = stats[0].item(), stats[1].item() @@ -379,7 +381,11 @@ def main(cfg: InferConfig) -> float: if distributed_utils.is_master(cfg.distributed_training): with open(wer_file, "w") as f: - f.write(f"WER: {wer}\n\n{yaml_str}") + f.write(( + f"WER: {wer}\n" + f"err / num_ref_words = {errs_t} / {leng_t}\n\n" + f"{yaml_str}" + )) return wer From 7dafb05754fe268bb5f76a1c97cf3a14062f44e5 Mon Sep 17 00:00:00 2001 From: Michael Lewis <mikelewis@fb.com> Date: Mon, 29 Mar 2021 18:02:07 -0700 Subject: [PATCH 293/774] BASE layers (#1654) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1654 Reviewed By: myleott Differential Revision: D27128074 Pulled By: shruti-bh fbshipit-source-id: ac86d383cd53c9c9bdd946fea839a37b719d95e3 --- fairseq/checkpoint_utils.py | 8 +- fairseq/clib/libbase/balanced_assignment.cpp | 95 ++++++++++++ fairseq/data/data_utils.py | 5 +- fairseq/data/monolingual_dataset.py | 27 +++- .../legacy_distributed_data_parallel.py | 5 + fairseq/distributed/utils.py | 3 + fairseq/models/transformer.py | 5 + fairseq/models/transformer_lm.py | 14 ++ fairseq/modules/__init__.py | 2 + fairseq/modules/base_layer.py | 135 ++++++++++++++++++ fairseq/optim/fp16_optimizer.py | 2 + fairseq/tasks/language_modeling.py | 18 +++ fairseq/trainer.py | 3 +- fairseq/utils.py | 8 +- fairseq_cli/train.py | 13 +- setup.py | 11 ++ 16 files changed, 341 insertions(+), 13 deletions(-) create mode 100644 fairseq/clib/libbase/balanced_assignment.cpp create mode 100644 fairseq/modules/base_layer.py diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 86e00a7714..7e1b8479d1 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -115,7 +115,7 @@ def is_better(a, b): if not end_of_epoch and cfg.keep_interval_updates > 0: # remove old checkpoints; checkpoints are sorted in descending order checkpoints = checkpoint_paths( - cfg.save_dir, pattern=r"checkpoint_\d+_(\d+)\.pt" + cfg.save_dir, pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix) ) for old_chk in checkpoints[cfg.keep_interval_updates :]: if os.path.lexists(old_chk): @@ -123,7 +123,7 @@ def is_better(a, b): if cfg.keep_last_epochs > 0: # remove old epoch checkpoints; checkpoints are sorted in descending order - checkpoints = checkpoint_paths(cfg.save_dir, pattern=r"checkpoint(\d+)\.pt") + checkpoints = checkpoint_paths(cfg.save_dir, pattern=r"checkpoint(\d+){}\.pt".format(suffix)) for old_chk in checkpoints[cfg.keep_last_epochs :]: if os.path.lexists(old_chk): os.remove(old_chk) @@ -132,8 +132,8 @@ def is_better(a, b): # only keep the best N checkpoints according to validation metric checkpoints = checkpoint_paths( cfg.save_dir, - pattern=r"checkpoint\.best_{}_(\d+\.?\d*)\.pt".format( - cfg.best_checkpoint_metric + pattern=r"checkpoint\.best_{}_(\d+\.?\d*){}\.pt".format( + cfg.best_checkpoint_metric, suffix ), ) if not cfg.maximize_best_checkpoint_metric: diff --git a/fairseq/clib/libbase/balanced_assignment.cpp b/fairseq/clib/libbase/balanced_assignment.cpp new file mode 100644 index 0000000000..296f03b6ae --- /dev/null +++ b/fairseq/clib/libbase/balanced_assignment.cpp @@ -0,0 +1,95 @@ +/** + * Copyright 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE file in the root directory of this source tree. + */ + +/* +C++ code for solving the linear assignment problem. +Based on the Auction Algorithm from https://dspace.mit.edu/bitstream/handle/1721.1/3265/P-2108-26912652.pdf and the implementation from: +https://github.com/bkj/auction-lap +Adapted to be more efficient when each worker is looking for k jobs instead of 1. +*/ +#include <torch/extension.h> +#include <iostream> +using namespace torch::indexing; +torch::Tensor balanced_assignment(torch::Tensor job_and_worker_to_score) { + int max_iterations = 100; + torch::Tensor epsilon = (job_and_worker_to_score.max() - job_and_worker_to_score.min()) / 50; + epsilon.clamp_min_(1e-04); + torch::Tensor worker_and_job_to_score = job_and_worker_to_score.detach().transpose(0,1).contiguous(); + int num_workers = worker_and_job_to_score.size(0); + int num_jobs = worker_and_job_to_score.size(1); + auto device = worker_and_job_to_score.device(); + int jobs_per_worker = num_jobs / num_workers; + torch::Tensor value = worker_and_job_to_score.clone(); + int counter = 0; + torch::Tensor max_value = worker_and_job_to_score.max(); + + torch::Tensor bid_indices; + torch::Tensor cost = worker_and_job_to_score.new_zeros({1, num_jobs}); + torch::Tensor bids = worker_and_job_to_score.new_empty({num_workers, num_jobs}); + torch::Tensor bid_increments = worker_and_job_to_score.new_empty({num_workers, jobs_per_worker}); + torch::Tensor top_values = worker_and_job_to_score.new_empty({num_workers, jobs_per_worker + 1}); + torch::Tensor high_bids = worker_and_job_to_score.new_empty({num_jobs}); + + torch::Tensor top_index = top_values.to(torch::kLong); + torch::Tensor high_bidders = top_index.new_empty({num_jobs}); + torch::Tensor have_bids = high_bidders.to(torch::kBool); + torch::Tensor jobs_indices = torch::arange({num_jobs}, torch::dtype(torch::kLong).device(device)); + torch::Tensor true_tensor = torch::ones({1}, torch::dtype(torch::kBool).device(device)); + + while (true) { + bids.zero_(); + torch::topk_out(top_values, top_index, value, jobs_per_worker + 1, 1); + + // Each worker bids the difference in value between that job and the k+1th job + torch::sub_out(bid_increments, + top_values.index({Slice(None, None), Slice(0, jobs_per_worker)}), + top_values.index({Slice(None, None), jobs_per_worker}).unsqueeze(1)); + + bid_increments.add_(epsilon); + bids.scatter_(1, + top_index.index({Slice(None, None),Slice(0, jobs_per_worker)}), + bid_increments); + + if (counter < max_iterations && counter > 0) { + // Put in a minimal bid to retain items from the last round if no-one else bids for them this round + bids.view(-1).index_put_({bid_indices}, epsilon); + } + + // Find the highest bidding worker per job + torch::max_out(high_bids, high_bidders, bids, 0); + torch::gt_out(have_bids, high_bids, 0); + + if (have_bids.all().item<bool>()) { + // All jobs were bid for + break; + } + + // Make popular items more expensive + cost.add_(high_bids); + torch::sub_out(value, worker_and_job_to_score, cost); + + bid_indices = ((high_bidders * num_jobs) + jobs_indices).index({have_bids}); + + if (counter < max_iterations) { + // Make sure that this item will be in the winning worker's top-k next time. + value.view(-1).index_put_({bid_indices}, max_value); + } + else { + // Suboptimal approximation that converges quickly from current solution + value.view(-1).index_put_({bid_indices}, worker_and_job_to_score.view(-1).index({bid_indices})); + } + + counter += 1; + } + + return top_index.index({Slice(None, None), Slice(0, jobs_per_worker)}).reshape(-1); +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def("balanced_assignment", &balanced_assignment, "Balanced Assignment"); +} diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 79df6f3769..63c7fcd118 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -41,13 +41,16 @@ def collate_tokens( move_eos_to_beginning=False, pad_to_length=None, pad_to_multiple=1, + pad_to_bsz=None, ): """Convert a list of 1d tensors into a padded 2d tensor.""" size = max(v.size(0) for v in values) size = size if pad_to_length is None else max(size, pad_to_length) if pad_to_multiple != 1 and size % pad_to_multiple != 0: size = int(((size - 0.1) // pad_to_multiple + 1) * pad_to_multiple) - res = values[0].new(len(values), size).fill_(pad_idx) + + batch_size = len(values) if pad_to_bsz is None else max(len(values), pad_to_bsz) + res = values[0].new(batch_size, size).fill_(pad_idx) def copy_tensor(src, dst): assert dst.numel() == src.numel() diff --git a/fairseq/data/monolingual_dataset.py b/fairseq/data/monolingual_dataset.py index bf7aa86f6c..54fd583b64 100644 --- a/fairseq/data/monolingual_dataset.py +++ b/fairseq/data/monolingual_dataset.py @@ -9,7 +9,7 @@ from . import FairseqDataset, data_utils -def collate(samples, pad_idx, eos_idx): +def collate(samples, pad_idx, eos_idx, fixed_pad_length=None, pad_to_bsz=None): if len(samples) == 0: return {} @@ -23,6 +23,8 @@ def merge(key, is_list=False): pad_idx, eos_idx, left_pad=False, + pad_to_length=fixed_pad_length, + pad_to_bsz=pad_to_bsz, ) ) return res @@ -32,6 +34,8 @@ def merge(key, is_list=False): pad_idx, eos_idx, left_pad=False, + pad_to_length=fixed_pad_length, + pad_to_bsz=pad_to_bsz, ) src_tokens = merge("source") @@ -75,6 +79,10 @@ def __init__( shuffle=False, targets=None, add_bos_token=False, + fixed_pad_length=None, + pad_to_bsz=None, + src_lang_idx=None, + tgt_lang_idx=None, ): self.dataset = dataset self.sizes = np.array(sizes) @@ -83,6 +91,10 @@ def __init__( self.add_eos_for_other_targets = add_eos_for_other_targets self.shuffle = shuffle self.add_bos_token = add_bos_token + self.fixed_pad_length = fixed_pad_length + self.pad_to_bsz = pad_to_bsz + self.src_lang_idx = src_lang_idx + self.tgt_lang_idx = tgt_lang_idx assert targets is None or all( t in {"self", "future", "past"} for t in targets @@ -165,6 +177,11 @@ def _maybe_add_bos(self, source, target): target = torch.cat([target.new([self.tgt_vocab.bos()]), target]) return source, target + def num_tokens_vec(self, indices): + """Return the number of tokens for a set of positions defined by indices. + This value is used to enforce ``--max-tokens`` during batching.""" + return self.sizes[indices] + def _filter_vocab(self, target): if len(self.tgt_vocab) != len(self.vocab): @@ -200,7 +217,13 @@ def collater(self, samples): target sentence of shape `(bsz, tgt_len)`. Padding will appear on the right. """ - return collate(samples, self.vocab.pad(), self.vocab.eos()) + return collate( + samples, + self.vocab.pad(), + self.vocab.eos(), + self.fixed_pad_length, + self.pad_to_bsz, + ) def num_tokens(self, index): """Return the number of tokens in a sample. This value is used to diff --git a/fairseq/distributed/legacy_distributed_data_parallel.py b/fairseq/distributed/legacy_distributed_data_parallel.py index b586e76b7f..f2308f87c5 100644 --- a/fairseq/distributed/legacy_distributed_data_parallel.py +++ b/fairseq/distributed/legacy_distributed_data_parallel.py @@ -136,6 +136,11 @@ def reduction_fn(): continue if param.grad is None: param.grad = torch.zeros_like(param) + + if hasattr(param, 'expert'): + # Skip gradient sync for unshared parameters + continue + if param.grad.requires_grad: raise RuntimeError( "DistributedDataParallel only works " diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index 970b784915..b09e87fe09 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -306,6 +306,9 @@ def distributed_init(cfg: FairseqConfig): model_part_number = get_model_parallel_rank() cfg.checkpoint.checkpoint_suffix += "-model_part-{0}".format(model_part_number) + if getattr(cfg.model, "base_layers", 0) > 0: + cfg.checkpoint.checkpoint_suffix = f"-rank-{cfg.distributed_training.distributed_rank}" + return cfg.distributed_training.distributed_rank diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 1e47d102f9..8da5beb3aa 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -19,6 +19,7 @@ ) from fairseq.modules import ( AdaptiveSoftmax, + BaseLayer, FairseqDropout, LayerDropModuleList, LayerNorm, @@ -751,6 +752,10 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): nn.init.normal_( self.output_projection.weight, mean=0, std=self.output_embed_dim ** -0.5 ) + num_base_layers = getattr(args, "base_layers", 0) + for i in range(num_base_layers): + self.layers.insert(((i+1) * args.decoder_layers) // (num_base_layers + 1), BaseLayer(args)) + def build_decoder_layer(self, args, no_encoder_attn=False): layer = TransformerDecoderLayer(args, no_encoder_attn) diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index b616a923d4..a546776912 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -180,6 +180,16 @@ class TransformerLanguageModelConfig(FairseqDataclass): ) } ) + # config for "BASE Layers: Simplifying Training of Large, Sparse Models" + base_layers: Optional[int] = field( + default=0, metadata={"help": "number of BASE layers in total"} + ) + base_sublayers: Optional[int] = field( + default=1, metadata={"help": "number of sublayers in each BASE layer"} + ) + base_shuffle: Optional[int] = field( + default=1, metadata={"help": "shuffle tokens between workers before computing assignment"} + ) # options from other parts of the config add_bos_token: bool = II("task.add_bos_token") tokens_per_sample: int = II("task.tokens_per_sample") @@ -313,6 +323,10 @@ def base_lm_architecture(args): args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8) args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0) + args.base_layers = getattr(args, "base_layers", 0) + args.base_sublayers = getattr(args, "base_sublayers", 1) + args.base_shuffle = getattr(args, "base_shuffle", False) + args.add_bos_token = getattr(args, "add_bos_token", False) args.no_token_positional_embeddings = getattr( args, "no_token_positional_embeddings", False diff --git a/fairseq/modules/__init__.py b/fairseq/modules/__init__.py index e2326ac6e3..81930aa71c 100644 --- a/fairseq/modules/__init__.py +++ b/fairseq/modules/__init__.py @@ -6,6 +6,7 @@ from .adaptive_input import AdaptiveInput from .adaptive_softmax import AdaptiveSoftmax +from .base_layer import BaseLayer from .beamable_mm import BeamableMM from .character_token_embedder import CharacterTokenEmbedder from .conv_tbc import ConvTBC @@ -39,6 +40,7 @@ __all__ = [ "AdaptiveInput", "AdaptiveSoftmax", + "BaseLayer", "BeamableMM", "CharacterTokenEmbedder", "ConvTBC", diff --git a/fairseq/modules/base_layer.py b/fairseq/modules/base_layer.py new file mode 100644 index 0000000000..e7ef155b25 --- /dev/null +++ b/fairseq/modules/base_layer.py @@ -0,0 +1,135 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch.nn as nn +import torch +import sys +from fairseq import utils +from fairseq.distributed import utils as distributed_utils +from fairseq.modules.layer_norm import LayerNorm + + +class BaseLayer(nn.Module): + + def __init__(self, args): + super().__init__() + self.num_workers = distributed_utils.get_data_parallel_world_size() + expert_centroids = torch.empty(self.num_workers, args.decoder_embed_dim) + torch.nn.init.orthogonal_(expert_centroids, gain=0.1) + self.register_parameter("expert_centroids", torch.nn.Parameter(expert_centroids)) + self.expert_network = nn.Sequential(*([BaseSublayer(args) for _ in range(args.base_sublayers)])) + self.expert_id = distributed_utils.get_data_parallel_rank() + self.shuffle = args.base_shuffle + self.cpp = self.load_assignment() + + # Add a special attribute to the expert parameters, so we know not to sync their gradients + for param in self.expert_network.parameters(): + param.expert = True + + def forward(self, input_features, *args, **kwargs): + features = input_features.reshape(-1, input_features.size(-1)) + is_training = input_features.requires_grad + + if self.shuffle and is_training: + # Send each token to a random worker, to break correlations within the batch + shuffle_sort = torch.randperm(features.size(0), device=features.device) + features = All2All.apply(features[shuffle_sort]) + + with torch.no_grad(): + # Compute similarity of each token to each expert, for routing + token_expert_affinities = features.matmul(self.expert_centroids.transpose(0, 1)) + + # Compute which token goes to which expert + sort_by_expert, input_splits, output_splits = self.balanced_assignment(token_expert_affinities) \ + if is_training else self.greedy_assignment(token_expert_affinities) + # Swap these tokens for the right ones for our expert + routed_features = All2All.apply(features[sort_by_expert], output_splits, input_splits) + + if routed_features.size(0) > 0: + # Mix in the expert network based on how appropriate it is for these tokens + alpha = torch.sigmoid(routed_features.mv(self.expert_centroids[self.expert_id])).unsqueeze(1) + routed_features = alpha * self.expert_network(routed_features) + (1 - alpha) * routed_features + # Return to original worker and ordering + result = All2All.apply(routed_features, input_splits, output_splits)[self.inverse_sort(sort_by_expert)] + + if self.shuffle and is_training: + # Undo shuffling + result = All2All.apply(result)[self.inverse_sort(shuffle_sort)] + + # Return additional Nones for compatibility with TransformerDecoderLayer + return result.view(input_features.size()), None, None + + def inverse_sort(self, order): + # Creates an index that undoes a sort: xs==xs[order][inverse_sort(order)] + return torch.empty_like(order).scatter_(0, order, torch.arange(0, order.size(0), device=order.device)) + + def balanced_assignment(self, scores): + ok = scores.isfinite() + if not ok.all(): + # NaNs here can break the assignment algorithm + scores[~ok] = scores[ok].min() + return self.cpp.balanced_assignment(scores), None, None + + # Assigns each token to the top k experts + def greedy_assignment(self, scores, k=1): + token_to_workers = torch.topk(scores, dim=1, k=k, largest=True).indices.view(-1) + token_to_workers, sort_ordering = torch.sort(token_to_workers) + worker2token = sort_ordering // k + + # Find how many tokens we're sending to each other worker (being careful for sending 0 tokens to some workers) + output_splits = torch.zeros((self.num_workers,), dtype=torch.long, device=scores.device) + workers, counts = torch.unique_consecutive(token_to_workers, return_counts=True) + output_splits[workers] = counts + # Tell other workers how many tokens to expect from us + input_splits = All2All.apply(output_splits) + return worker2token, input_splits.tolist(), output_splits.tolist() + + def load_assignment(self): + try: + from fairseq import libbase + + return libbase + + except ImportError as e: + sys.stderr.write( + "ERROR: missing libbase. run `python setup.py build_ext --inplace`\n" + ) + raise e + + +class BaseSublayer(nn.Module): + def __init__(self, args): + super().__init__() + self.activation_fn = utils.get_activation_fn( + activation=getattr(args, 'activation_fn', 'relu') or "relu" + ) + self.norm = LayerNorm(args.decoder_embed_dim, export=False) + self.ff1 = torch.nn.Linear(args.decoder_embed_dim, args.decoder_ffn_embed_dim) + self.ff2 = torch.nn.Linear(args.decoder_ffn_embed_dim, args.decoder_embed_dim) + self.ff2.weight.data.zero_() + + def forward(self, xs): + return xs + self.ff2(self.activation_fn(self.ff1(self.norm(xs)))) + + +# Wraps torch.distributed.all_to_all_single as a function that supports autograd +class All2All(torch.autograd.Function): + @staticmethod + def forward(ctx, xs, input_splits=None, output_splits=None): + ctx.input_splits = input_splits + ctx.output_splits = output_splits + + ys = torch.empty_like(xs) if output_splits is None else \ + xs.new_empty(size=[sum(output_splits)] + list(xs.size()[1:])) + torch.distributed.all_to_all_single(ys, xs, output_split_sizes=output_splits, input_split_sizes=input_splits) + return ys + + @staticmethod + def backward(ctx, grad_output): + result = torch.empty_like(grad_output) if ctx.input_splits is None else \ + grad_output.new_empty(size=[sum(ctx.input_splits)] + list(grad_output.size()[1:])) + torch.distributed.all_to_all_single(result, grad_output, + output_split_sizes=ctx.input_splits, input_split_sizes=ctx.output_splits) + return result, None, None diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index 00ea1bbb76..370a910102 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -64,6 +64,8 @@ def build_fp32_params(cls, args, params, flatten=True): fp32_params = [] for p in params: p32 = torch.nn.Parameter(p.data.float()) + if hasattr(p, 'expert'): + p32.expert = True p32.grad = torch.zeros_like(p32.data) if hasattr(p, "param_group"): p32.param_group = p.param_group diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index a3847733a1..3069490fdc 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -84,8 +84,17 @@ class LanguageModelingConfig(FairseqDataclass): 'e.g., "train,valid" (default: all dataset splits)' }, ) + pad_to_fixed_length: Optional[bool] = field( + default=False, metadata={"help": "pad to fixed length"}, + ) + pad_to_fixed_bsz: Optional[bool] = field( + default=False, metadata={"help": "boolean to pad to fixed batch size"}, + ) + # TODO common vars below add to parent seed: int = II("common.seed") + batch_size: Optional[int] = II("dataset.batch_size") + batch_size_valid: Optional[int] = II("dataset.batch_size_valid") dataset_impl: Optional[ChoiceEnum(get_available_dataset_impl())] = II( "dataset.dataset_impl" ) @@ -232,6 +241,13 @@ def load_dataset( self.args.sample_break_mode is not None and self.args.sample_break_mode != "none" ) + fixed_pad_length = None + if self.args.pad_to_fixed_length: + fixed_pad_length = self.args.tokens_per_sample + + pad_to_bsz = None + if self.args.pad_to_fixed_bsz: + pad_to_bsz = self.args.batch_size_valid if 'valid' in split else self.args.batch_size self.datasets[split] = MonolingualDataset( dataset=dataset, @@ -242,6 +258,8 @@ def load_dataset( shuffle=True, targets=self.targets, add_bos_token=self.args.add_bos_token, + fixed_pad_length=fixed_pad_length, + pad_to_bsz=pad_to_bsz, ) def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 4535e9bda7..6195afb4a6 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -195,7 +195,7 @@ def use_distributed_wrapper(self) -> bool: @property def should_save_checkpoint_on_current_rank(self) -> bool: """Indicates whether to save checkpoints on the current DDP rank.""" - if self.cfg.distributed_training.ddp_backend == "fully_sharded": + if self.cfg.distributed_training.ddp_backend == "fully_sharded" or getattr(self.cfg.model, "base_layers", 0) > 0: return True else: return self.is_data_parallel_master @@ -415,6 +415,7 @@ def load_checkpoint( or self.tpu # FSDP requires loading checkpoint shards on all ranks or self.cfg.distributed_training.ddp_backend == "fully_sharded" + or getattr(self.cfg.model, "base_layers", 0) > 0 ) if load_on_all_ranks or self.data_parallel_rank == 0: diff --git a/fairseq/utils.py b/fairseq/utils.py index 90bb8369f2..03826d18d0 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -339,10 +339,14 @@ def multi_tensor_total_norm(grads, chunk_size=2048 * 32) -> torch.Tensor: @torch.no_grad() def clip_grad_norm_(params, max_norm, aggregate_norm_fn=None) -> torch.Tensor: + def grad_exists(p): + return p is not None and getattr(p, "grad", None) is not None if isinstance(params, torch.Tensor): params = [params] params = list(params) - grads = [p.grad.detach() for p in filter(lambda p: p.grad is not None, params)] + grads = [p.grad.detach() for p in params if grad_exists(p) and not hasattr(p, 'expert')] + expert_grads = [p.grad.detach() for p in params if grad_exists(p) and hasattr(p, 'expert')] + if len(grads) == 0: if len(params) > 0: return params[0].new_tensor(0.0) @@ -377,7 +381,7 @@ def clip_grad_norm_(params, max_norm, aggregate_norm_fn=None) -> torch.Tensor: if max_norm > 0: max_norm = float(max_norm) clip_coef = (max_norm / (total_norm + 1e-6)).clamp_(max=1) - for g in grads: + for g in grads + expert_grads: g.mul_(clip_coef) return total_norm diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 6924dfe5c8..1cca64d988 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -98,9 +98,16 @@ def main(cfg: FairseqConfig) -> None: logger.info("model: {}".format(model.__class__.__name__)) logger.info("criterion: {}".format(criterion.__class__.__name__)) logger.info( - "num. model params: {:,} (num. trained: {:,})".format( - sum(getattr(p, "_orig_size", p).numel() for p in model.parameters()), - sum(getattr(p, "_orig_size", p).numel() for p in model.parameters() if p.requires_grad), + "num. shared model params: {:,} (num. trained: {:,})".format( + sum(p.numel() for p in model.parameters() if not getattr(p, "expert", False)), + sum(p.numel() for p in model.parameters() if not getattr(p, "expert", False) and p.requires_grad) + ) + ) + + logger.info( + "num. expert model params: {} (num. trained: {})".format( + sum(p.numel() for p in model.parameters() if getattr(p, "expert", False)), + sum(p.numel() for p in model.parameters() if getattr(p, "expert", False) and p.requires_grad), ) ) diff --git a/setup.py b/setup.py index 3670ff3cfc..51e555229c 100644 --- a/setup.py +++ b/setup.py @@ -99,6 +99,17 @@ def include_dirs(self, dirs): # torch is not available when generating docs from torch.utils import cpp_extension + extensions.extend( + [ + cpp_extension.CppExtension( + "fairseq.libbase", + sources=[ + "fairseq/clib/libbase/balanced_assignment.cpp", + ], + ) + ] + ) + extensions.extend( [ cpp_extension.CppExtension( From c2e8904b6072d8eddab362ac50b324e374b5951d Mon Sep 17 00:00:00 2001 From: Guillaume Wenzek <guw@fb.com> Date: Tue, 30 Mar 2021 09:54:22 -0700 Subject: [PATCH 294/774] Obt 2 (#1614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.m)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? too many of them actually ^^ ## What does this PR do? This is a rewrite of https://github.com/fairinternal/fairseq-py/issues/1538 following the discussion there, and taking into account the proposed https://github.com/fairinternal/fairseq-py/issues/1560 from Myle. it brings online backtranslation to fairseq. It adds a RobertaEncDec to fairseq. RobertaEncDec can be built from a pretrained Roberta model allowing to do transfer learning. This is crucial for backtranslation. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1614 Reviewed By: myleott Differential Revision: D27157296 Pulled By: gwenzek fbshipit-source-id: 43020bc27743419bd4b138716165bf5764117c21 --- fairseq/data/noising.py | 2 + fairseq/data/round_robin_zip_datasets.py | 2 +- .../data/transform_eos_lang_pair_dataset.py | 3 + fairseq/models/roberta/__init__.py | 1 + fairseq/models/roberta/enc_dec.py | 192 +++++ fairseq/models/roberta/model.py | 6 +- fairseq/models/transformer.py | 40 +- fairseq/modules/multihead_attention.py | 11 +- fairseq/options.py | 18 +- fairseq/sequence_generator.py | 14 +- fairseq/tasks/online_backtranslation.py | 677 ++++++++++++++++++ fairseq/tasks/translation.py | 4 + .../tasks/translation_from_pretrained_bart.py | 2 +- fairseq_cli/train.py | 8 +- tests/test_online_backtranslation.py | 206 ++++++ tests/test_roberta.py | 314 ++++++++ 16 files changed, 1472 insertions(+), 28 deletions(-) create mode 100644 fairseq/models/roberta/enc_dec.py create mode 100644 fairseq/tasks/online_backtranslation.py create mode 100644 tests/test_online_backtranslation.py create mode 100644 tests/test_roberta.py diff --git a/fairseq/data/noising.py b/fairseq/data/noising.py index 9643d1aa6a..2b1cc34720 100644 --- a/fairseq/data/noising.py +++ b/fairseq/data/noising.py @@ -296,6 +296,8 @@ def __init__( **kwargs, ) ) + self.sizes = src_dataset.sizes + def __getitem__(self, index): """ diff --git a/fairseq/data/round_robin_zip_datasets.py b/fairseq/data/round_robin_zip_datasets.py index d710335b81..2cb7447ea9 100644 --- a/fairseq/data/round_robin_zip_datasets.py +++ b/fairseq/data/round_robin_zip_datasets.py @@ -141,7 +141,7 @@ def _deep_until_language_pair(dataset): f"{len(ignored)} samples from {key} have invalid sizes and will be skipped, " f"max_positions={max_positions[key]}, first few sample ids={ignored[:10]}" ) - # Since we are modifiying in place the _ordered_indices, + # Since we are modifying in place the _ordered_indices, # it's not possible anymore to return valid ignored indices. # Hopefully the extra debug information print above should be enough to debug. # Ideally we would receive ignore_invalid_inputs so that we could have diff --git a/fairseq/data/transform_eos_lang_pair_dataset.py b/fairseq/data/transform_eos_lang_pair_dataset.py index 1dd3d93d2b..07ebdd5f38 100644 --- a/fairseq/data/transform_eos_lang_pair_dataset.py +++ b/fairseq/data/transform_eos_lang_pair_dataset.py @@ -50,6 +50,9 @@ def __len__(self): def collater(self, samples, **extra_args): samples = self.dataset.collater(samples, **extra_args) + if 'net_input' not in samples: + return samples + if self.new_src_eos is not None: if self.dataset.left_pad_source: assert ( diff --git a/fairseq/models/roberta/__init__.py b/fairseq/models/roberta/__init__.py index cf16914fbc..4cd723ae96 100644 --- a/fairseq/models/roberta/__init__.py +++ b/fairseq/models/roberta/__init__.py @@ -5,6 +5,7 @@ from .hub_interface import * # noqa from .model import * # noqa +from .enc_dec import * # noqa from .model_camembert import * # noqa from .model_gottbert import * # noqa from .model_xlmr import * # noqa diff --git a/fairseq/models/roberta/enc_dec.py b/fairseq/models/roberta/enc_dec.py new file mode 100644 index 0000000000..e538dee0aa --- /dev/null +++ b/fairseq/models/roberta/enc_dec.py @@ -0,0 +1,192 @@ +import argparse +import logging + +import torch.nn as nn +import fairseq.checkpoint_utils +from fairseq.models import ( + FairseqEncoderDecoderModel, + register_model, + register_model_architecture, +) +from fairseq.models.transformer import TransformerDecoder +from fairseq.models.roberta import model as roberta + +logger = logging.getLogger(__name__) + + +@register_model("roberta_enc_dec") +class RobertaEncDecModel(FairseqEncoderDecoderModel): + @staticmethod + def add_args(parser): + parser.add_argument( + "--pretrained-mlm-checkpoint", + default=None, + type=str, + metavar="PRETRAINED", + help="path to pretrained mlm checkpoint", + ) + parser.add_argument( + "--pretrained-decoder", action="store_true", help="reload decoder" + ) + parser.add_argument( + "--hack-layernorm-embedding", + action="store_true", + help="hack to reload old models trained with encoder-normalize-before=False (no equivalent to encoder-normalize-before=False and layernorm_embedding=False", + ) + parser.add_argument( + "--share-decoder-input-output-embed", + action="store_true", + help="share decoder input and output embeddings", + ) + parser.add_argument( + "--share-all-embeddings", + action="store_true", + help="share encoder, decoder and output embeddings" + " (requires shared dictionary and embed dim)", + ) + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + + # make sure all arguments are present + base_enc_dec_architecture(args) + if args.pretrained_mlm_checkpoint: + arg_overrides = None + if args.hack_layernorm_embedding: + arg_overrides = {"layernorm_embedding": False} + loaded = fairseq.checkpoint_utils.load_model_ensemble_and_task( + [args.pretrained_mlm_checkpoint], arg_overrides=arg_overrides + ) + ([roberta_enc], _cfg, _task) = loaded + else: + # Do we need to edit untie_weights here ? + share_in_out = ( + args.share_decoder_input_output_embed or args.share_all_embeddings + ) + args.untie_weights_roberta = not share_in_out + if args.hack_layernorm_embedding: + args.layernorm_embedding = False + args.encoder_normalize_before = False + roberta_enc = roberta.RobertaModel.build_model(args, task) + + return cls.from_roberta(roberta_enc, args, task.source_dictionary) + + @staticmethod + def from_roberta(roberta_enc: roberta.RobertaModel, args, dictionary): + encoder = roberta_enc.encoder.sentence_encoder + vocab_size, embed_dim = encoder.embed_tokens.weight.shape + + if args.share_all_embeddings: + lm_head = roberta_enc.encoder.lm_head + assert encoder.embed_tokens.weight is lm_head.weight, ( + "Can't use --share-all-embeddings with a model " + "that was pretraiend with --untie-weights-roberta_enc" + ) + else: + lm_head = roberta.RobertaLMHead( + embed_dim, vocab_size, roberta_enc.args.activation_fn + ) + + dec_embs = nn.Embedding(vocab_size, embed_dim, dictionary.pad()) + if args.share_all_embeddings or args.share_decoder_input_output_embed: + # Note: I wasn't able to use Embedding _weight parameter to achive this sharing. + dec_embs.weight = lm_head.weight + + decoder = TransformerDecoder( + RobertaEncDecModel.read_args_from_roberta(roberta_enc.args), + dictionary, + dec_embs, + no_encoder_attn=False, + output_projection=lm_head, + ) + if getattr(args, "pretrained_decoder", False): + decoder_dict = encoder.state_dict() + + # TODO: hide setting "encoder_attn" layers behind a flag. + for k, w in list(decoder_dict.items()): + if ".self_attn" in k: + k_enc_attn = k.replace(".self_attn", ".encoder_attn") + decoder_dict[k_enc_attn] = w.detach().clone() + + for k, w in lm_head.state_dict().items(): + decoder_dict["output_projection." + k] = w + + missing_keys, unexpected_keys = decoder.load_state_dict( + decoder_dict, strict=False + ) + # missing_keys = [m for m in missing_keys if ".encoder_attn" not in m] + assert not missing_keys and not unexpected_keys, ( + "Failed to load state dict. " + f"Missing keys: {missing_keys}. " + f"Unexpected keys: {unexpected_keys}." + ) + + if args.share_all_embeddings: + assert decoder.output_projection.weight is decoder.embed_tokens.weight + assert encoder.embed_tokens.weight is decoder.embed_tokens.weight + elif args.share_decoder_input_output_embed: + assert decoder.output_projection.weight is decoder.embed_tokens.weight + assert encoder.embed_tokens.weight is not decoder.embed_tokens.weight + else: + assert decoder.output_projection.weight is not decoder.embed_tokens.weight + assert encoder.embed_tokens.weight is not decoder.embed_tokens.weight + + return RobertaEncDecModel(encoder, decoder) + + @staticmethod + def read_args_from_roberta(roberta_args: argparse.Namespace): + # TODO: this would become easier if encoder/decoder where using a similar + # TransformerConfig object + args = argparse.Namespace(**vars(roberta_args)) + attr_map = [ + ("encoder_attention_heads", "decoder_attention_heads"), + ("encoder_embed_dim", "decoder_embed_dim"), + ("encoder_embed_dim", "decoder_output_dim"), + ("encoder_normalize_before", "decoder_normalize_before"), + ("encoder_layers_to_keep", "decoder_layers_to_keep"), + ("encoder_ffn_embed_dim", "decoder_ffn_embed_dim"), + ("encoder_layerdrop", "decoder_layerdrop"), + ("encoder_layers", "decoder_layers"), + ("encoder_learned_pos", "decoder_learned_pos"), + # should this be set from here ? + ("max_positions", "max_target_positions"), + ] + for k1, k2 in attr_map: + setattr(args, k2, getattr(roberta_args, k1)) + + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + args.share_decoder_input_output_embed = not roberta_args.untie_weights_roberta + return args + + def upgrade_state_dict_named(self, state_dict, name): + prefix = name + "." if name != "" else "" + super().upgrade_state_dict_named(state_dict, name) + old_keys = list(state_dict.keys()) + + # rename decoder -> encoder before upgrading children modules + for k in old_keys: + if k.startswith(prefix + "encoder.lm_head"): + state_dict.pop(k) + continue + new_k = k + new_k = new_k.replace(".sentence_encoder.", ".") + new_k = new_k.replace("decoder.lm_head.", "decoder.output_projection.") + if k == new_k: + continue + # print(k, "->", new_k) + state_dict[new_k] = state_dict.pop(k) + + +@register_model_architecture("roberta_enc_dec", "roberta_enc_dec") +def base_enc_dec_architecture(args): + args.hack_layernorm_embedding = getattr(args, "hack_layernorm_embedding", False) + args.pretrained_mlm_checkpoint = getattr(args, "pretrained_mlm_checkpoint", None) + args.pretrained_decoder = getattr(args, "pretrained_decoder", None) + args.share_all_embeddings = getattr(args, "share_all_embeddings", False) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + + roberta.base_architecture(args) diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 5b9ba8105f..d9d0f324cf 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -204,7 +204,7 @@ def forward( features_only=False, return_all_hiddens=False, classification_head_name=None, - **kwargs + **kwargs, ): if classification_head_name is not None: features_only = True @@ -259,7 +259,7 @@ def from_pretrained( checkpoint_file="model.pt", data_name_or_path=".", bpe="gpt2", - **kwargs + **kwargs, ): from fairseq import hub_utils @@ -464,7 +464,7 @@ def forward( features_only=False, return_all_hiddens=False, masked_tokens=None, - **unused + **unused, ): """ Args: diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 8da5beb3aa..eff5ba7b8f 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -645,7 +645,14 @@ class TransformerDecoder(FairseqIncrementalDecoder): (default: False). """ - def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): + def __init__( + self, + args, + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=None, + ): self.args = args super().__init__(dictionary) self.register_buffer("version", torch.Tensor([3])) @@ -727,7 +734,11 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): ) self.adaptive_softmax = None - self.output_projection = None + self.output_projection = output_projection + if self.output_projection is None: + self.build_output_projection(args, dictionary, embed_tokens) + + def build_output_projection(self, args, dictionary, embed_tokens): if args.adaptive_softmax_cutoff is not None: self.adaptive_softmax = AdaptiveSoftmax( len(dictionary), @@ -789,7 +800,7 @@ def forward( prev_output_tokens (LongTensor): previous decoder outputs of shape `(batch, tgt_len)`, for teacher forcing encoder_out (optional): output from the encoder, used for - encoder-side attention + encoder-side attention, should be of size T x B x C incremental_state (dict): dictionary used for storing state during :ref:`Incremental decoding` features_only (bool, optional): only return features without @@ -802,6 +813,7 @@ def forward( - the decoder's output of shape `(batch, tgt_len, vocab)` - a dictionary with any model-specific outputs """ + x, extra = self.extract_features( prev_output_tokens, encoder_out=encoder_out, @@ -810,6 +822,7 @@ def forward( alignment_layer=alignment_layer, alignment_heads=alignment_heads, ) + if not features_only: x = self.output_layer(x) return x, extra @@ -866,9 +879,19 @@ def extract_features_scriptable( - the decoder's features of shape `(batch, tgt_len, embed_dim)` - a dictionary with any model-specific outputs """ + bs, slen = prev_output_tokens.size() if alignment_layer is None: alignment_layer = self.num_layers - 1 + enc: Optional[Tensor] = None + padding_mask: Optional[Tensor] = None + if encoder_out is not None: + enc = encoder_out["encoder_out"][0] + padding_mask = encoder_out["encoder_padding_mask"][0] + assert ( + enc.size()[1] == bs + ), f"Expected enc.shape == (t, {bs}, c) got {enc.shape}" + # embed positions positions = None if self.embed_positions is not None: @@ -916,15 +939,8 @@ def extract_features_scriptable( x, layer_attn, _ = layer( x, - encoder_out["encoder_out"][0] - if (encoder_out is not None and len(encoder_out["encoder_out"]) > 0) - else None, - encoder_out["encoder_padding_mask"][0] - if ( - encoder_out is not None - and len(encoder_out["encoder_padding_mask"]) > 0 - ) - else None, + enc, + padding_mask, incremental_state, self_attn_mask=self_attn_mask, self_attn_padding_mask=self_attn_padding_mask, diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 6ab86245d2..d84c7e078d 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -147,8 +147,16 @@ def forward( is_tpu = query.device.type == "xla" tgt_len, bsz, embed_dim = query.size() + src_len = tgt_len assert embed_dim == self.embed_dim assert list(query.size()) == [tgt_len, bsz, embed_dim] + if key is not None: + src_len, key_bsz, key_embed_dim = key.size() + if not torch.jit.is_scripting(): + assert (key_bsz, key_embed_dim) == (bsz, embed_dim) + assert value is not None + assert (src_len, bsz, embed_dim) == value.shape + if ( not self.onnx_trace @@ -262,6 +270,7 @@ def forward( else: assert k is not None k = torch.cat([prev_key, k], dim=1) + src_len = k.size(1) if "prev_value" in saved_state: _prev_value = saved_state["prev_value"] assert _prev_value is not None @@ -290,7 +299,7 @@ def forward( assert incremental_state is not None incremental_state = self._set_input_buffer(incremental_state, saved_state) assert k is not None - src_len = k.size(1) + assert k.size(1) == src_len # This is part of a workaround to get around fork/join parallelism # not supporting Optional types. diff --git a/fairseq/options.py b/fairseq/options.py index b79443a177..7558264fce 100644 --- a/fairseq/options.py +++ b/fairseq/options.py @@ -4,7 +4,8 @@ # LICENSE file in the root directory of this source tree. import argparse -from typing import Callable, List, Optional +from pathlib import Path +from typing import Callable, List, Optional, Union import torch from fairseq import utils @@ -361,3 +362,18 @@ def add_model_args(parser): help='model architecture') # fmt: on return group + + +def get_args( + data: Union[str, Path], + task: str = "translation", + arch: str = "transformer", + **overrides +): + parser = get_training_parser(task) + args = parse_args_and_arch(parser, [str(data), "--task", task, "--arch", arch]) + + for k, v in overrides.items(): + setattr(args, k, v) + + return args diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 2574ab13f0..ddef3d58d2 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -23,6 +23,7 @@ def __init__( beam_size=1, max_len_a=0, max_len_b=200, + max_len=0, min_len=1, normalize_scores=True, len_penalty=1.0, @@ -44,6 +45,8 @@ def __init__( beam_size (int, optional): beam width (default: 1) max_len_a/b (int, optional): generate sequences of maximum length ax + b, where x is the source length + max_len (int, optional): the maximum length of the generated output + (not including end-of-sentence) min_len (int, optional): the minimum length of the generated output (not including end-of-sentence) normalize_scores (bool, optional): normalize scores by the length @@ -79,6 +82,7 @@ def __init__( self.max_len_a = max_len_a self.max_len_b = max_len_b self.min_len = min_len + self.max_len = max_len or self.model.max_decoder_positions() self.normalize_scores = normalize_scores self.len_penalty = len_penalty @@ -166,7 +170,7 @@ def generate_batched_itr(self, data_itr, beam_size=None, cuda=False, timer=None) yield id, src, ref, hypos[i] @torch.no_grad() - def generate(self, models, sample: Dict[str, Dict[str, Tensor]], **kwargs): + def generate(self, models, sample: Dict[str, Dict[str, Tensor]], **kwargs) -> List[List[Dict[str, Tensor]]]: """Generate translations. Match the api of other fairseq generators. Args: @@ -232,8 +236,7 @@ def _generate( else: max_len = min( int(self.max_len_a * src_len + self.max_len_b), - # exclude the EOS marker - self.model.max_decoder_positions() - 1, + self.max_len - 1, ) assert ( self.min_len <= max_len @@ -275,9 +278,8 @@ def _generate( [torch.jit.annotate(List[Dict[str, Tensor]], []) for i in range(bsz)], ) # contains lists of dictionaries of infomation about the hypothesis being finalized at each step - finished = [ - False for i in range(bsz) - ] # a boolean array indicating if the sentence at the index is finished or not + # a boolean array indicating if the sentence at the index is finished or not + finished = [False for i in range(bsz)] num_remaining_sent = bsz # number of sentences remaining # number of candidate hypos per step diff --git a/fairseq/tasks/online_backtranslation.py b/fairseq/tasks/online_backtranslation.py new file mode 100644 index 0000000000..2545624cd4 --- /dev/null +++ b/fairseq/tasks/online_backtranslation.py @@ -0,0 +1,677 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import contextlib +import json +import logging +import math +import os +from argparse import Namespace +from collections import OrderedDict, defaultdict +from pathlib import Path +from typing import Dict, Sequence, Tuple + +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F + +import fairseq +from fairseq import metrics, options, utils +from fairseq.data import ( + FairseqDataset, + LanguagePairDataset, + NoisingDataset, + PrependTokenDataset, + RoundRobinZipDatasets, + TransformEosLangPairDataset, + data_utils, + encoders, +) +from fairseq.sequence_generator import SequenceGenerator +from fairseq.tasks import register_task +from fairseq.tasks.translation import TranslationTask, load_langpair_dataset + +logger = logging.getLogger(__name__) + + +class PiecewiseLinearFn: + """Piecewise linear function. Can be configured with a string.""" + + def __init__(self, pieces: Sequence[Tuple[int, float]]): + assert pieces == sorted( + pieces + ), f"PiecewiseLinearFn configuration should be sorted, received: {pieces}" + + self.pieces = pieces + + def __call__(self, x: int) -> float: + for i, (x_a, y_a) in enumerate(self.pieces[:-1]): + x_b, y_b = self.pieces[i + 1] + if x_a <= x <= x_b: + return y_a + (x - x_a) * (y_b - y_a) / (x_b - x_a) + + return self.pieces[-1][1] + + @staticmethod + def from_string(configuration: str) -> "PiecewiseLinearFn": + """ + Parse the configuration of lambda coefficient (for scheduling). + x = "3" # lambda will be a constant equal to x + x = "0:1,1000:0" # lambda will start from 1 and linearly decrease + # to 0 during the first 1000 iterations + x = "0:0,1000:0,2000:1" # lambda will be equal to 0 for the first 1000 + # iterations, then will linearly increase to 1 until iteration 2000 + """ + if isinstance(configuration, float): + return PiecewiseLinearFn([(0, configuration)]) + + try: + parts = configuration.split(",") + if len(parts) == 1: + v = float(configuration) + return PiecewiseLinearFn([(0, v)]) + + split = [s.split(":") for s in parts] + pieces = [(int(t), float(v)) for t, v in split] + return PiecewiseLinearFn(pieces) + except Exception: + raise ValueError( + f"Invalid PiecewiseLinearFn configuration: {configuration!r}" + ) + + @staticmethod + def one() -> "PiecewiseLinearFn": + return PiecewiseLinearFn([(0, 1.0)]) + + +@register_task("online_backtranslation") +class OnlineBackTranslationTask(TranslationTask): + @staticmethod + def add_args(parser): + """Add task-specific arguments to the parser.""" + # fmt: off + # Generic translation args + parser.add_argument('data', help='colon separated path to data directories list, \ + will be iterated upon during epochs in round-robin manner; \ + however, valid and test data are always in the first directory to \ + avoid the need for repeating them in all directories') + parser.add_argument('--mono-langs', metavar='MONO_LANGS', + help='monolingual languages for training') + parser.add_argument('--valid-lang-pairs', default=None, metavar='VALID_LANG_PAIRS', + help='language pairs for validation') + parser.add_argument('--load-alignments', action='store_true', + help='load the binarized alignments') + parser.add_argument('--left-pad-source', default='False', type=str, metavar='BOOL', + help='pad the source on the left') + parser.add_argument('--left-pad-target', default='False', type=str, metavar='BOOL', + help='pad the target on the left') + parser.add_argument('--upsample-primary', default=1, type=int, + help='amount to upsample primary dataset') + parser.add_argument('--max-source-positions', default=1024, type=int, metavar='N', + help='max number of tokens in the source sequence') + parser.add_argument('--max-target-positions', default=1024, type=int, metavar='N', + help='max number of tokens in the target sequence') + parser.add_argument('--truncate-source', action='store_true', default=False, + help='truncate source to max-source-positions') + parser.add_argument('--num-batch-buckets', default=0, type=int, metavar='N', + help='if >0, then bucket source and target lengths into N ' + 'buckets and pad accordingly; this is useful on TPUs ' + 'to minimize the number of compilations') + + # Denoising args + parser.add_argument('--max-word-shuffle-distance', default=3.0, type=float, metavar='N', + help='maximum word shuffle distance for denoising autoencoding data generation') + parser.add_argument('--word-dropout-prob', default=0.1, type=float, metavar='N', + help='word dropout probability for denoising autoencoding data generation') + parser.add_argument('--word-blanking-prob', default=0.2, type=float, metavar='N', + help='word blanking probability for denoising autoencoding data generation') + + # Backtranslation args + parser.add_argument('--lambda-bt', default="1.0", type=str, metavar='N', + help='back-translation weight') + parser.add_argument('--lambda-dae', default="1.0", type=str, metavar='N', + help='denoising auto-encoder weight') + + # Evaluation args + parser.add_argument('--generate-one-by-one', action='store_true', + help='generate one sentence at a time for backtranslation') + + parser.add_argument('--eval-bleu', action='store_true', + help='evaluation with BLEU scores') + parser.add_argument('--eval-bleu-detok', type=str, default="space", + help='detokenize before computing BLEU (e.g., "moses"); ' + 'required if using --eval-bleu; use "space" to ' + 'disable detokenization; see fairseq.data.encoders ' + 'for other options') + parser.add_argument('--eval-bleu-detok-args', type=str, metavar='JSON', + help='args for building the tokenizer, if needed') + parser.add_argument('--eval-tokenized-bleu', action='store_true', default=False, + help='compute tokenized BLEU instead of sacrebleu') + parser.add_argument('--eval-bleu-remove-bpe', nargs='?', const='@@ ', default=None, + help='remove BPE before computing BLEU') + parser.add_argument('--eval-bleu-args', type=str, metavar='JSON', + help='generation args for BLUE scoring, ' + 'e.g., \'{"beam": 4, "lenpen": 0.6}\'') + parser.add_argument('--eval-bleu-print-samples', action='store_true', + help='print sample generations during validation') + # fmt: on + + def __init__(self, args, common_dict, mono_langs, valid_lang_pairs): + super().__init__(args, common_dict, common_dict) + self.common_dict = common_dict + self.mono_langs = mono_langs + self.valid_lang_pairs = valid_lang_pairs + + self.SHOW_SAMPLES_INTERVAL = 1000 + # Start by showing samples + self._show_samples_ctr = self.SHOW_SAMPLES_INTERVAL + self.SHOW_SAMPLES_NUMBER = 5 + self.lambda_bt = PiecewiseLinearFn.from_string(args.lambda_bt) + self.lambda_dae = PiecewiseLinearFn.from_string(args.lambda_dae) + + self.args = args + self.data = utils.split_paths(self.args.data) + if len(self.data) == 1: + shards = list(Path(self.data[0]).glob("shard*")) + if len(shards) > 0: + # keep this as strings, since it can also be a manifold path + old_data = self.data + self.data = [str(shard) for shard in shards] + logging.warning(f"Expanded data directory {old_data} to {self.data}") + + @classmethod + def setup_task(cls, args, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + args (argparse.Namespace): parsed command-line arguments + """ + args.left_pad_source = options.eval_bool(args.left_pad_source) + args.left_pad_target = options.eval_bool(args.left_pad_target) + + paths = utils.split_paths(args.data) + assert len(paths) > 0 + assert args.mono_langs is not None + + mono_langs = args.mono_langs.split(",") + valid_lang_pairs = args.valid_lang_pairs.split(",") + + # load dictionary + dict_path = os.path.join(paths[0], "dict.txt") + common_dict = cls.load_dictionary(dict_path) + + return cls(args, common_dict, mono_langs, valid_lang_pairs) + + def load_dataset(self, split, epoch=1, combine=False, **kwargs) -> FairseqDataset: + """Load a given dataset split. + + Args: + split (str): name of the split (e.g., train, valid, test) + """ + if split == "train": + data_path = self.data[(epoch - 1) % len(self.data)] + dataset = self.load_train_dataset(data_path) + else: + # valid/test should always be the same. + dataset = self.load_translation_dataset(split, self.data[0]) + + self.datasets[split] = dataset + return dataset + + def load_train_dataset(self, data_path: str) -> FairseqDataset: + """The training dataset is made of backtranslation dataset and denoising dataset.""" + data = [] + for lang in self.mono_langs: + train_path = os.path.join(data_path, lang, "train") + # TODO: could we do the BT using denoise sample ? + # this would half the data loading work + data.append((f"{lang}-BT", self.load_bt_dataset(train_path, lang))) + data.append( + (f"{lang}-DENOISE", self.load_denoise_dataset(train_path, lang)) + ) + + return RoundRobinZipDatasets(OrderedDict(data)) + + def _langpair_dataset( + self, src: FairseqDataset, tgt: FairseqDataset + ) -> LanguagePairDataset: + return LanguagePairDataset( + src, + src.sizes, + self.dictionary, + tgt=tgt, + tgt_sizes=tgt.sizes, + tgt_dict=self.dictionary, + left_pad_source=self.args.left_pad_source, + left_pad_target=self.args.left_pad_target, + # TODO: should we shuffle ? we are already sorting batch by sizes so ? + # shuffle=True, + ) + + def _prepend_lang_bos_to_target( + self, dataset: LanguagePairDataset, lang: str + ) -> LanguagePairDataset: + bos = _lang_token_index(self.dictionary, lang) + return TransformEosLangPairDataset( + dataset, + src_eos=self.dictionary.eos(), + new_src_eos=self.dictionary.eos(), + tgt_bos=self.dictionary.eos(), + new_tgt_bos=bos, + ) + + def load_bt_dataset(self, data_path: str, lang: str) -> FairseqDataset: + """The BT dataset is generated with (tgt, tgt) pairs. + The actual translation to a (generated_src, tgt) pair + is done on the fly during training. + """ + mono_dataset = data_utils.load_indexed_dataset( + data_path, self.common_dict, self.args.dataset_impl + ) + assert mono_dataset is not None, f"No dataset found for {lang}" + + mono_dataset_src = PrependTokenDataset( + mono_dataset, _lang_token_index(self.dictionary, lang) + ) + + mono_dataset_bt = self._langpair_dataset(mono_dataset_src, mono_dataset) + logger.info( + f"mono_lang = {lang} " + f"lang token index = {_lang_token_index(self.dictionary, lang)} " + f"lang token = {_lang_token(lang)}" + ) + + mono_dataset_bt = self._prepend_lang_bos_to_target(mono_dataset_bt, lang) + return mono_dataset_bt + + def load_denoise_dataset(self, data_path: str, lang: str) -> FairseqDataset: + """Classic denoising dataset""" + dataset = data_utils.load_indexed_dataset( + data_path, self.common_dict, self.args.dataset_impl + ) + noisy_dataset = NoisingDataset( + dataset, + self.dictionary, + seed=1, + max_word_shuffle_distance=self.args.max_word_shuffle_distance, + word_dropout_prob=self.args.word_dropout_prob, + word_blanking_prob=self.args.word_blanking_prob, + ) + noisy_dataset = PrependTokenDataset( + noisy_dataset, _lang_token_index(self.dictionary, lang) + ) + + clean_dataset = data_utils.load_indexed_dataset( + data_path, self.common_dict, self.args.dataset_impl + ) + denoising_dataset = self._langpair_dataset(noisy_dataset, clean_dataset) + denoising_dataset = self._prepend_lang_bos_to_target(denoising_dataset, lang) + return denoising_dataset + + def load_translation_dataset( + self, split: str, data_path: str, combine: bool = False + ): + # only judging with one language pair for the moment, + # since ConcatDataset doesn't work as expected + assert len(self.valid_lang_pairs) == 1, "For now..." + valid_lang_pair = self.valid_lang_pairs[0] + src, tgt = valid_lang_pair.split("-") + + # use the same function than TranslationTask + src_tgt_dt = load_langpair_dataset( + data_path, + split, + src, + self.common_dict, + tgt, + self.common_dict, + combine=combine, + dataset_impl=self.args.dataset_impl, + upsample_primary=self.args.upsample_primary, + left_pad_source=self.args.left_pad_source, + left_pad_target=self.args.left_pad_target, + max_source_positions=self.args.max_source_positions, + max_target_positions=self.args.max_target_positions, + load_alignments=self.args.load_alignments, + truncate_source=self.args.truncate_source, + num_buckets=self.args.num_batch_buckets, + shuffle=(split != "test"), + prepend_bos_src=_lang_token_index(self.dictionary, src), + ) + + src_tgt_eos_dt = self._prepend_lang_bos_to_target(src_tgt_dt, tgt) + src_tgt_eos_dt.args = self.args + return src_tgt_eos_dt + + def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None): + raise NotImplementedError + + def build_model(self, args): + # torch.autograd.set_detect_anomaly(True) + model = super().build_model(args) + + add_secial_tokens_to_dict_and_model(self.common_dict, model, self.mono_langs) + + self.sequence_generators = {} + for mono_lang in self.mono_langs: + self.sequence_generators[mono_lang] = SequenceGenerator( + [model], + tgt_dict=self.dictionary, + beam_size=1, + max_len_a=1.3, + max_len_b=5, + min_len=5, + # keep 1 to be able to prepend bos + max_len=model.max_decoder_positions() - 1, + ) + + if getattr(args, "eval_bleu", False): + assert getattr(args, "eval_bleu_detok", None) is not None, ( + "--eval-bleu-detok is required if using --eval-bleu; " + "try --eval-bleu-detok=moses (or --eval-bleu-detok=space " + "to disable detokenization, e.g., when using sentencepiece)" + ) + detok_args = json.loads(getattr(args, "eval_bleu_detok_args", "{}") or "{}") + self.tokenizer = encoders.build_tokenizer( + Namespace( + tokenizer=getattr(args, "eval_bleu_detok", None), **detok_args + ) + ) + + gen_args = json.loads(getattr(args, "eval_bleu_args", "{}") or "{}") + self.bleu_sequence_generator = self.build_generator( + [model], Namespace(**gen_args) + ) + + return model + + def max_positions(self): + """Return the max sentence length allowed by the task.""" + return (self.args.max_source_positions, self.args.max_target_positions) + + @property + def dictionary(self): + """Return the source :class:`~fairseq.data.Dictionary`.""" + return self.common_dict + + def display_samples_once_in_a_while(self, smp, mono_lang, other_lang): + self._show_samples_ctr += 1 + if self._show_samples_ctr < self.SHOW_SAMPLES_INTERVAL: + return + self._show_samples_ctr = 0 + + ln = smp["net_input"]["src_tokens"].shape[0] + + logger.info( + f"(r:{self.args.distributed_rank}) : " + f"{other_lang} ---> {mono_lang} " + f"({other_lang} was generated by back-translation.) {ln} samples" + ) + + for i in range(min(ln, self.SHOW_SAMPLES_NUMBER)): + src_tokens = smp["net_input"]["src_tokens"][i] + tgt_tokens = smp["target"][i] + + src_str = self.dictionary.string(src_tokens, "sentencepiece") + tgt_str = self.dictionary.string(tgt_tokens, "sentencepiece") + logger.info( + f"\n{i}\t\t[{other_lang} generated] {src_str}\n" + f"\t\t[{mono_lang} original ] {tgt_str}\n" + f"\t\t[ src tokens] {src_tokens}\n" + ) + + def backtranslate_sample(self, smp, orig_lang, other_lang) -> None: + """ + * WARNING: smp is modified in place. + * At the start of this function, `smp` has the same input and target: + |--------------------------------------------------------| + | smp['net_input']['src_tokens'] | smp['target'] | + | (from data) __en__ hello world | __en__ hello world | + |--------------------------------------------------------| + + * We call generator.generate(smp, bos_token = token("ro")), + and copy the result as input + * At the end, `smp` has the translation to other language. + |--------------------------------------------------------| + | smp['net_input']['src_tokens'] | smp['target'] | + | (generated) __ro__ salut lume | __en__ hello world | + |--------------------------------------------------------| + + """ + bos_token = _lang_token_index(self.dictionary, other_lang) + generated = self.sequence_generators[orig_lang].generate( + models=[], sample=smp, bos_token=bos_token + ) + + max_lngth = max([gn[0]["tokens"].size(0) for gn in generated]) + net_input = smp["net_input"] + n_src_tokens = torch.empty( + size=(len(generated), max_lngth + 1), dtype=net_input["src_tokens"].dtype + ) + n_src_lengths = torch.empty( + len(generated), dtype=net_input["src_lengths"].dtype + ) + + for i, gn in enumerate(generated): + tokens = gn[0]["tokens"] + tokens_size = tokens.size(0) + padding_needed = max_lngth - tokens_size + tokens = torch.cat([tokens.new([bos_token]), tokens]) + tokens = F.pad(tokens, (0, padding_needed), value=self.dictionary.pad()) + n_src_tokens[i] = tokens + n_src_lengths[i] = tokens_size + 1 + + device = net_input["src_tokens"].device + # This seems to be important + del net_input["src_tokens"] + del net_input["src_lengths"] + net_input["src_tokens"] = n_src_tokens.to(device) + net_input["src_lengths"] = n_src_lengths.to(device) + + def generate(self, smp, model): + model.eval() + orig_lang = ( + self.dictionary[smp["net_input"]["src_tokens"][0][0]] + .replace(" ", "") + .replace("_", "") + ) + bos_token = smp["net_input"]["prev_output_tokens"][0][0] + with torch.no_grad(): + generated = self.sequence_generators[orig_lang].generate( + models=[model], sample=smp, bos_token=bos_token + ) + return generated + + def get_other_lang(self, lang): + # TODO: allow more complex mapping + if lang != self.mono_langs[0]: + return self.mono_langs[0] + if len(self.mono_langs) == 2: + return self.mono_langs[1] + return self.mono_langs[np.random.randint(1, len(self.mono_langs))] + + def train_step( + self, sample, model, criterion, optimizer, update_num, ignore_grad=False + ): + + model.train() + model.set_num_updates(update_num) + + agg_loss, agg_sample_size = 0.0, 0.0 + agg_logging_output: Dict[str, float] = defaultdict(float) + + dataset_keys = self.datasets["train"].datasets.keys() + + weights = { + "BT": self.lambda_bt(update_num), + "DENOISE": self.lambda_dae(update_num), + } + log_keys = {"BT": "bt_", "DENOISE": "dae_"} + + for dataset_key in dataset_keys: + smp = sample[dataset_key] + mono_lang, task_subtype = dataset_key.split("-") + if weights[task_subtype] == 0: + continue + + if task_subtype == "BT": + with torch.autograd.profiler.record_function("backtranslation"): + model.eval() + # TODO: Could we translate to several language at once ? + # this would allow to share encoder_out and maximize GPU usage. + other_lang = self.get_other_lang(mono_lang) + self.backtranslate_sample(smp, mono_lang, other_lang) + self.display_samples_once_in_a_while(smp, mono_lang, other_lang) + model.train() + + # Like in FairseqTask.train_step + with torch.autograd.profiler.record_function("forward"): + loss, sample_size, logging_output = criterion(model, smp) + loss *= weights[task_subtype] + if ignore_grad: + loss *= 0 + with torch.autograd.profiler.record_function("backward"): + optimizer.backward(loss) + + agg_loss += loss.item() + agg_sample_size += sample_size + for k in logging_output: + agg_logging_output[log_keys[task_subtype] + k] += logging_output[k] + agg_logging_output[k] += logging_output[k] + + return agg_loss, agg_sample_size, agg_logging_output + + def get_bos_token_from_sample(self, sample): + net_input = sample["net_input"] + source_lang_token_id = torch.unique(net_input["src_tokens"][:, 0]).item() + source_lang_token = self.dictionary[source_lang_token_id].replace("_", "") + target_lang_token_id = _lang_token_index( + self.dictionary, self.get_other_lang(source_lang_token) + ) + + return target_lang_token_id + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + bt_sample_size = sum(x.get("bt_sample_size", 0) for x in logging_outputs) + if bt_sample_size: + bt_loss_sum = sum(x.get("bt_loss", 0) for x in logging_outputs) + bt_loss_sum *= 1 / bt_sample_size / math.log(2) + metrics.log_scalar("bt_loss", bt_loss_sum, bt_sample_size, round=3) + + bt_nll_loss_sum = sum(x.get("bt_nll_loss", 0) for x in logging_outputs) + bt_ntokens = sum(x.get("bt_ntokens", 0) for x in logging_outputs) + bt_nll_loss_sum *= 1 / bt_ntokens / math.log(2) + metrics.log_scalar("bt_nll_loss", bt_nll_loss_sum, bt_ntokens, round=3) + metrics.log_derived( + "bt_ppl", lambda meters: utils.get_perplexity(meters["bt_nll_loss"].avg) + ) + + dae_sample_size = sum(x.get("dae_sample_size", 0) for x in logging_outputs) + if dae_sample_size: + dae_loss_sum = sum(x.get("dae_loss", 0) for x in logging_outputs) + dae_loss_sum *= 1 / dae_sample_size / math.log(2) + metrics.log_scalar("dae_loss", dae_loss_sum, dae_sample_size, round=3) + + dae_nll_loss_sum = sum(x.get("dae_nll_loss", 0) for x in logging_outputs) + dae_ntokens = sum(x.get("dae_ntokens", 0) for x in logging_outputs) + dae_nll_loss_sum *= 1 / dae_ntokens / math.log(2) + metrics.log_scalar("dae_nll_loss", dae_nll_loss_sum, dae_ntokens, round=3) + metrics.log_derived( + "dae_ppl", + lambda meters: utils.get_perplexity(meters["dae_nll_loss"].avg), + ) + + +@torch.no_grad() +def extend_embedding( + emb: nn.Module, new_vocab_size: int, copy_from_token_id: int +) -> None: + old_emb_data = emb.weight.data + (old_vocab_size, dim) = old_emb_data.shape + assert new_vocab_size >= old_vocab_size + + if new_vocab_size > old_vocab_size: + emb.weight.data = torch.zeros((new_vocab_size, dim)) + emb.weight.data[:old_vocab_size, :] = old_emb_data + # initialize new embeddings + emb.weight.data[old_vocab_size:, :] = old_emb_data[copy_from_token_id] + if hasattr(emb, "num_embeddings"): + emb.num_embeddings = new_vocab_size + if hasattr(emb, "out_features"): + emb.out_features = new_vocab_size + + if getattr(emb, "bias", None) is None: + return + + # Fix the bias. + # Bias shape can be different from the previous vocab size + # if the weight matrix was shared and alread extended but not the bias. + (old_vocab_size,) = emb.bias.shape + assert new_vocab_size >= old_vocab_size + if new_vocab_size > old_vocab_size: + old_bias = emb.bias.data + new_bias = torch.zeros( + (new_vocab_size,), dtype=old_bias.dtype, device=old_bias.device + ) + new_bias[:old_vocab_size] = old_bias + emb.bias.data = new_bias + + +def add_secial_tokens_to_dict_and_model( + dictionary: "fairseq.data.Dictionary", + model: nn.Module, + mono_langs: Sequence[str], +) -> None: + embs = model.encoder.embed_tokens + vocab_size, embedding_dim = embs.weight.shape + + # The model may or may not have a '<mask>' embedding yet + assert ( + len(dictionary) <= vocab_size <= len(dictionary) + 1 + ), f"Dictionary len ({len(dictionary)}) doesn't match embs shape ({embs.weight.shape})" + # TODO: we should reuse the pretrained model dict which already has <mask> + dictionary.add_symbol("<mask>") + + for lang in mono_langs: + lang_token = _lang_token(lang) + dictionary.add_symbol(lang_token) + logger.info( + f"dictionary: {len(dictionary)} -> {vocab_size} tokens " + f"after adding {len(mono_langs)} lang tokens." + ) + + if len(dictionary) <= vocab_size: + return + + extend_embedding(embs, len(dictionary), dictionary.bos()) + dec_embs = model.decoder.embed_tokens + extend_embedding(dec_embs, len(dictionary), dictionary.bos()) + lm_head = model.decoder.output_projection + extend_embedding(lm_head, len(dictionary), dictionary.bos()) + assert lm_head.weight.shape == (len(dictionary), embedding_dim) + + +def _lang_token(lang: str) -> str: + return f"__{lang}__" + + +def _lang_token_index(dictionary, lang: str) -> int: + return dictionary.index(_lang_token(lang)) + + +@contextlib.contextmanager +def assert_weights_have_changed(model: nn.Module): + def checksum(model: nn.Module) -> float: + return sum(p.sum().item() for p in model.parameters()) + + initial_checksum = checksum(model) + yield model + final_checksum = checksum(model) + logger.info( + f"initial_checksum={initial_checksum} -> final_checksum={final_checksum}" + ) + assert initial_checksum != final_checksum, "Model hasn't changed !" diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 331f685495..ea80fa2e73 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -57,6 +57,7 @@ def load_langpair_dataset( num_buckets=0, shuffle=True, pad_to_multiple=1, + prepend_bos_src=None, ): def split_exists(split, src, tgt, lang, data_path): filename = os.path.join(data_path, "{}.{}-{}.{}".format(split, src, tgt, lang)) @@ -128,6 +129,9 @@ def split_exists(split, src, tgt, lang, data_path): src_dataset = PrependTokenDataset(src_dataset, src_dict.bos()) if tgt_dataset is not None: tgt_dataset = PrependTokenDataset(tgt_dataset, tgt_dict.bos()) + elif prepend_bos_src is not None: + logger.info(f"prepending src bos: {prepend_bos_src}") + src_dataset = PrependTokenDataset(src_dataset, prepend_bos_src) eos = None if append_source_id: diff --git a/fairseq/tasks/translation_from_pretrained_bart.py b/fairseq/tasks/translation_from_pretrained_bart.py index 8710b7fe7d..0fd7a5b29f 100644 --- a/fairseq/tasks/translation_from_pretrained_bart.py +++ b/fairseq/tasks/translation_from_pretrained_bart.py @@ -38,7 +38,7 @@ def add_args(parser): """Add task-specific arguments to the parser.""" # fmt: off TranslationTask.add_args(parser) - parser.add_argument('--langs', required=True, metavar='LANG', + parser.add_argument('--langs', type=str, metavar='LANG', help='comma-separated list of monolingual language, ' 'for example, "en,de,fr". These should match the ' 'langs from pretraining (and be in the same order). ' diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 1cca64d988..f736e67d0d 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -80,9 +80,6 @@ def main(cfg: FairseqConfig) -> None: # Setup task, e.g., translation, language modeling, etc. task = tasks.setup_task(cfg.task) - # Load valid dataset (we load training data below, based on the latest checkpoint) - for valid_sub_split in cfg.dataset.valid_subset.split(","): - task.load_dataset(valid_sub_split, combine=False, epoch=1) assert cfg.criterion, "Please specify criterion to train a model" @@ -111,6 +108,11 @@ def main(cfg: FairseqConfig) -> None: ) ) + # Load valid dataset (we load training data below, based on the latest checkpoint) + # We load the valid dataset AFTER building the model + for valid_sub_split in cfg.dataset.valid_subset.split(","): + task.load_dataset(valid_sub_split, combine=False, epoch=1) + # (optionally) Configure quantization if cfg.common.quantization_config_path is not None: quantizer = quantization_utils.Quantizer( diff --git a/tests/test_online_backtranslation.py b/tests/test_online_backtranslation.py new file mode 100644 index 0000000000..0ae7e773da --- /dev/null +++ b/tests/test_online_backtranslation.py @@ -0,0 +1,206 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import tempfile +import unittest +from pathlib import Path +from typing import Any, Dict, Sequence + +import fairseq.data.indexed_dataset as indexed_dataset +import fairseq.options +import fairseq.tasks.online_backtranslation as obt +import torch +from tests import utils + + +def mk_sample(tokens: Sequence[int], batch_size: int = 2) -> Dict[str, Any]: + batch = torch.stack([torch.tensor(tokens, dtype=torch.long)] * batch_size) + sample = { + "net_input": { + "src_tokens": batch, + "prev_output_tokens": batch, + "src_lengths": torch.tensor([len(tokens)] * batch_size, dtype=torch.long), + }, + "target": batch[:, 1:], + } + return sample + + +def mk_dataset(num_samples: int, max_len: int, output: Path): + output.parent.mkdir(exist_ok=True) + idx = indexed_dataset.IndexedDatasetBuilder(str(output)) + data = torch.randint(5, 100, (num_samples, max_len)) + lengths = torch.randint(3, max_len, (num_samples,)) + for d, l in zip(data, lengths): + d[0] = 0 + idx.add_item(d[:l]) + idx.finalize(output.with_suffix(".idx")) + assert output.exists() + assert output.with_suffix(".idx").exists() + + +class OnlineBacktranslationTest(unittest.TestCase): + + tmp_dir = Path(tempfile.mkdtemp(suffix="OnlineBacktranslationTest")) + + @classmethod + def obt_task( + cls, languages: Sequence[str], data: Path = None, language_mapping: str = None + ): + dict_path = cls.tmp_dir / "dict.txt" + if not dict_path.exists(): + dictionary = utils.dummy_dictionary(100) + dictionary.save(str(dict_path)) + + if data is not None: + (data / "dict.txt").write_text(dict_path.read_text()) + else: + data = cls.tmp_dir + assert len(languages) >= 2 + + kwargs = { + "arch": "transformer", + # --max-sentences=1 for better predictability of batches + "max_sentences": 1, + # Use characteristics dimensions + "encoder_layers": 3, + "encoder_embed_dim": 12, + "encoder_ffn_embed_dim": 14, + "encoder_attention_heads": 4, + "decoder_layers": 3, + "decoder_embed_dim": 12, + "decoder_output_dim": 12, + "decoder_ffn_embed_dim": 14, + "decoder_attention_heads": 4, + # Disable dropout so we have comparable tests. + "dropout": 0, + "attention_dropout": 0, + "activation_dropout": 0, + "encoder_layerdrop": 0, + } + + args = fairseq.options.get_args( + data, + task="online_backtranslation", + mono_langs=",".join(languages), + valid_lang_pairs=f"{languages[0]}-{languages[1]}", + tokens_per_sample=256, + language_mapping=language_mapping, + **kwargs, + ) + task = obt.OnlineBackTranslationTask.setup_task(args) + # we need to build the model to have the correct dictionary + model = task.build_model(task.args) + return task, model + + def tmp_path(self, test_case: str) -> Path: + return Path(tempfile.mkdtemp(test_case, dir=self.tmp_dir)) + + def test_lang_tokens(self): + task, model = self.obt_task(["en", "ro", "zh"]) + assert obt._lang_token("en") in task.dictionary + assert obt._lang_token("ro") in task.dictionary + assert obt._lang_token("zh") in task.dictionary + + en_bos = obt._lang_token_index(task.common_dict, "en") + assert "en" == task.common_dict[en_bos].strip("_") + zh_bos = obt._lang_token_index(task.common_dict, "zh") + assert "zh" == task.common_dict[zh_bos].strip("_") + zh_sample = mk_sample([zh_bos, 16, 14, 12, 10]) + + # we expect to receive the bos token for translation + assert task.get_bos_token_from_sample(zh_sample) == en_bos + + def test_backtranslate_sample(self): + task, model = self.obt_task(["en", "ro", "zh"]) + + en_bos = obt._lang_token_index(task.common_dict, "en") + zh_bos = obt._lang_token_index(task.common_dict, "zh") + sample = mk_sample([zh_bos, 16, 14, 12, 10]) + + task.backtranslate_sample(sample, "zh", "en") + target_zh = list(sample["target"][0]) + assert target_zh == [16, 14, 12, 10] # original zh sentence + generated_en = sample["net_input"]["src_tokens"][0] + assert generated_en[0] == en_bos + + def test_train_dataset(self): + data = self.tmp_path("test_train_dataset") + mk_dataset(20, 10, data / "en" / "train.bin") + mk_dataset(10, 10, data / "zh" / "train.bin") + task, model = self.obt_task(["en", "zh"], data) + task.load_dataset("train") + + en_bos = obt._lang_token_index(task.common_dict, "en") + zh_bos = obt._lang_token_index(task.common_dict, "zh") + + train = task.datasets["train"] + train.ordered_indices() + train.prefetch([0, 19]) + sample_0 = train[0] + sample_19 = train[19] + self.assertEqual( + set(sample_0.keys()), {"en-BT", "en-DENOISE", "zh-BT", "zh-DENOISE"} + ) + for sample in (sample_0, sample_19): + self.assertEqual(sample["en-BT"]["source"][0], en_bos) + # bt target isn't ready to look at. + self.assertEqual(sample["en-DENOISE"]["source"][0], en_bos) + # TODO What could we check on the target side ? + + for i in range(10): + # Zh dataset is shorter, and is wrapped around En dataset. + train.prefetch([i, i + 10]) + self.assertEqual( + list(train[i]["zh-DENOISE"]["source"]), + list(train[i + 10]["zh-DENOISE"]["source"]), + ) + self.assertEqual(train[i]["zh-DENOISE"]["source"][0].item(), zh_bos) + + # Sorted by increasing len + self.assertLess( + len(sample_0["en-BT"]["source"]), len(sample_19["en-BT"]["source"]) + ) + + def test_valid_dataset(self): + data = self.tmp_path("test_valid_dataset") + mk_dataset(10, 21, data / "valid.en-zh.en.bin") + mk_dataset(10, 21, data / "valid.en-zh.zh.bin") + + task, model = self.obt_task(["en", "zh"], data) + valid = task.load_dataset("valid") + en_bos = obt._lang_token_index(task.common_dict, "en") + + assert valid is not None + valid.prefetch(range(10)) + sample_0 = valid[0] + sample_9 = valid[9] + self.assertEqual(sample_0["id"], 0) + self.assertEqual(sample_9["id"], 9) + self.assertEqual(sample_0["source"][0], en_bos) + self.assertEqual(sample_9["source"][0], en_bos) + # TODO: could we test the target side ? + + def assertFnMatch(self, fn, values): + for x, y in values.items(): + fn_x = fn(x) + self.assertEqual(fn_x, y, f"Fn has wrong value: fn({x}) = {fn_x} != {y}") + + def test_piecewise_linear_fn(self): + self.assertFnMatch( + obt.PiecewiseLinearFn.from_string("1.0"), {0: 1, 100: 1, 500: 1, 1000: 1} + ) + self.assertFnMatch( + obt.PiecewiseLinearFn.from_string("0:1,1000:0"), + {0: 1, 500: 0.5, 1000: 0, 2000: 0}, + ) + self.assertFnMatch( + obt.PiecewiseLinearFn.from_string("0:0,1000:1"), + {0: 0, 500: 0.5, 1000: 1, 2000: 1}, + ) + self.assertFnMatch( + obt.PiecewiseLinearFn.from_string("0:0,1000:1,2000:0"), + {0: 0, 500: 0.5, 1000: 1, 1500: 0.5, 2000: 0, 3000: 0}, + ) diff --git a/tests/test_roberta.py b/tests/test_roberta.py new file mode 100644 index 0000000000..b0b9cfd31e --- /dev/null +++ b/tests/test_roberta.py @@ -0,0 +1,314 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import functools +import unittest +from typing import Any, Dict, Sequence + +import fairseq +import fairseq.options +import fairseq.tasks +import torch +from tests.utils import dummy_dictionary + +VOCAB_SIZE = 100 + + +@fairseq.tasks.register_task("fake_task") +class FakeTask(fairseq.tasks.LegacyFairseqTask): + def __init__(self, args): + super().__init__(args) + self.dictionary = dummy_dictionary(VOCAB_SIZE - 4) + assert len(self.dictionary) == VOCAB_SIZE + + @property + def source_dictionary(self): + return self.dictionary + + @property + def target_dictionary(self): + return self.dictionary + + +@functools.lru_cache() +def get_toy_model( + device: str, + architecture: str = "roberta_enc_dec", + **extra_args: Any, +): + assert device in ("gpu", "cpu") + kwargs = { + "arch": architecture, + # Use characteristics dimensions + "encoder_layers": 3, + "encoder_embed_dim": 12, + "encoder_ffn_embed_dim": 14, + "encoder_attention_heads": 4, + "decoder_layers": 3, + "decoder_embed_dim": 12, + "decoder_ffn_embed_dim": 14, + "decoder_attention_heads": 4, + # Disable dropout so we have comparable tests. + "dropout": 0, + "attention_dropout": 0, + "activation_dropout": 0, + "encoder_layerdrop": 0, + # required args + "tokens_per_sample": 256, + "data": "/tmp/test_roberta", + } + kwargs.update(extra_args) + fake_task = FakeTask(kwargs) + args = fairseq.options.get_args( + task="online_backtranslation", + mono_langs="en,ro", + valid_lang_pairs="en-ro", + **kwargs, + ) + torch.manual_seed(0) + model = fake_task.build_model(args) + if device == "gpu": + model.cuda() + return fake_task, model + + +def mk_sample( + lang: str, device: str, tok: Sequence[int] = None, batch_size: int = 2 +) -> Dict[str, Any]: + assert device in ("gpu", "cpu") + if not tok: + if lang == "en": + tok = [10, 11, 12, 13, 14, 15, 2] + else: + tok = [20, 21, 22, 23, 24, 25, 26, 27, 2] + + batch = torch.stack([torch.tensor(tok, dtype=torch.long)] * batch_size) + if device == "gpu": + batch = batch.cuda() + sample = { + "net_input": { + "src_tokens": batch, + "prev_output_tokens": batch, + "src_lengths": torch.tensor( + [len(tok)] * batch_size, dtype=torch.long, device=batch.device + ), + }, + "target": batch[:, 1:], + } + return sample + + +def cpu_gpu(fn): + def helper(self): + fn(self, "cpu") + if torch.cuda.is_available(): + fn(self, "gpu") + + return helper + + +def architectures(fn): + def helper(self): + for arch in ["roberta_enc_dec", "transformer"]: + fn(self, arch) + + return helper + + +class RobertaTest(unittest.TestCase): + def assertTensorEqual(self, t1, t2, delta: float = 1e-6): + self.assertEqual(t1.size(), t2.size(), "size mismatch") + if delta == 0.0: + self.assertEqual(t1.ne(t2).long().sum(), 0) + else: + self.assertEqual(((t2 - t1).abs() > delta).long().sum(), 0) + + def assertSharing(self, model, link_groups: Sequence[Sequence[str]]): + ids = {} + for group in link_groups: + group_ids = {name: id(params(model, name)) for name in group} + shared_id = group_ids[group[0]] + self.assertEqual(group_ids, {name: shared_id for name in group}) + self.assertNotIn(shared_id, ids) + ids[shared_id] = group + + def test_roberta_shared_params(self): + _, roberta = get_toy_model("cpu", architecture="roberta") + self.assertSharing( + roberta, + [ + [ + "encoder.sentence_encoder.embed_tokens.weight", + "encoder.lm_head.weight", + ] + ], + ) + + _, roberta = get_toy_model( + "cpu", architecture="roberta", untie_weights_roberta=True + ) + self.assertSharing( + roberta, + [ + ["encoder.sentence_encoder.embed_tokens.weight"], + ["encoder.lm_head.weight"], + ], + ) + + def test_roberta_enc_dec_shared_params(self): + # 3 distinct embeddings + _, enc_dec = get_toy_model("cpu", architecture="roberta_enc_dec") + self.assertSharing( + enc_dec, + [ + ["encoder.embed_tokens.weight"], + ["decoder.embed_tokens.weight"], + ["decoder.output_projection.weight"], + ], + ) + + # 2 distinct embeddings, one for encoder, one for decoder + _, enc_dec = get_toy_model( + "cpu", architecture="roberta_enc_dec", share_decoder_input_output_embed=True + ) + self.assertSharing( + enc_dec, + [ + ["encoder.embed_tokens.weight"], + [ + "decoder.embed_tokens.weight", + "decoder.output_projection.weight", + ], + ], + ) + + # shared embeddings + _, enc_dec = get_toy_model( + "cpu", architecture="roberta_enc_dec", share_all_embeddings=True + ) + self.assertSharing( + enc_dec, + [ + [ + "encoder.embed_tokens.weight", + "decoder.embed_tokens.weight", + "decoder.output_projection.weight", + ] + ], + ) + + def test_roberta_max_positions_is_correctly_set(self): + device = "cpu" + task, model = get_toy_model(device) + max_pos = model.max_decoder_positions() + self.assertEqual(max_pos, 256) + self.assertEqual(max_pos, model.decoder.max_positions()) + self.assertEqual(max_pos, model.encoder.max_positions()) + self.assertEqual(max_pos, model.encoder.embed_positions.max_positions) + + sentence = [31 for _ in range(max_pos)] + sample = mk_sample("en", device, sentence, batch_size=1) + self.assertEqual(list(sample["net_input"]["src_lengths"]), [max_pos]) + self.assertEqual(len(sample["net_input"]["src_tokens"][0]), max_pos) + x, _ = model.forward(**sample["net_input"]) + self.assertEqual(x.shape, (1, max_pos, VOCAB_SIZE)) + + @cpu_gpu + def test_roberta_forward_backward(self, device: str): + _, model = get_toy_model(device) + sample = mk_sample("en", device) + en_tokens = sample["net_input"]["src_tokens"] + (bs, l) = en_tokens.shape + # Forward + logits, _ = model(**sample["net_input"]) + self.assertEqual(logits.shape, (bs, l, VOCAB_SIZE)) + + # Backward + loss = logits.sum() + loss.backward() + + @cpu_gpu + def test_roberta_forward_backward_bs1(self, device: str): + _, model = get_toy_model(device) + sample = mk_sample("en", device, batch_size=1) + o, _ = model.forward(**sample["net_input"]) + loss = o.sum() + sample2 = mk_sample("ro", device, batch_size=1) + o, _ = model.forward(**sample2["net_input"]) + loss += o.sum() + loss.backward() + + @cpu_gpu + def test_roberta_batching(self, device: str): + """ + Checks that the batch of size 2 give twice the same results than the batch of size 1. + """ + _, model = get_toy_model(device) + sample = mk_sample("en", device, batch_size=1) + slen = sample["net_input"]["src_lengths"][0] + sample2 = mk_sample("en", device, batch_size=2) + with torch.no_grad(): + z = model.encoder.forward( + sample["net_input"]["src_tokens"], sample["net_input"]["src_lengths"] + ) + z = z["encoder_out"][-1] + logits, _ = model.forward(**sample["net_input"]) + + z2 = model.encoder.forward( + sample2["net_input"]["src_tokens"], sample["net_input"]["src_lengths"] + ) + z2 = z2["encoder_out"][-1] + logits2, _ = model.forward(**sample2["net_input"]) + + self.assertEqual(z.shape, (slen, 1, 12)) + self.assertEqual(z2.shape, (slen, 2, 12)) + self.assertTensorEqual(logits2[0], logits2[1]) + self.assertTensorEqual(logits[0], logits2[0]) + + @cpu_gpu + def test_roberta_incremental_decoder(self, device: str): + """ + Checks that incremental decoding yields the same result than non incremental one. + """ + task, model = get_toy_model(device) + + en_sample = mk_sample("en", device) + en_tokens = en_sample["net_input"]["src_tokens"] + ro_sample = mk_sample("ro", device) + ro_tokens = ro_sample["net_input"]["src_tokens"] + + en_enc = model.encoder.forward( + en_tokens, src_lengths=en_sample["net_input"]["src_lengths"] + ) + (bs, tgt_len) = ro_tokens.shape + + # Decode without incremental state + ro_dec, _ = model.decoder.forward(ro_tokens, encoder_out=en_enc) + self.assertEqual(ro_dec.shape, (bs, tgt_len, VOCAB_SIZE)) + self.assertTensorEqual(ro_dec[0], ro_dec[1]) + + # Decode with incremental state + inc_state = {} + ro_dec_inc = [] + for l in range(tgt_len): + ro, _ = model.decoder.forward( + ro_tokens[:, : l + 1], encoder_out=en_enc, incremental_state=inc_state + ) + self.assertEqual(ro.shape, (bs, 1, VOCAB_SIZE)) + ro_dec_inc.append(ro) + + for l in range(tgt_len): + # Intra-batch + self.assertTensorEqual(ro_dec_inc[l][0], ro_dec_inc[l][1]) + # Incremental vs non-incremental + self.assertTensorEqual(ro_dec_inc[l][:, 0], ro_dec[:, l]) + + +def params(model, name): + if "." not in name: + return getattr(model, name) + + prefix, name = name.split(".", 1) + return params(getattr(model, prefix), name) From 229de0087f599e31986c85c8106456f0adf44812 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Tue, 30 Mar 2021 10:09:30 -0700 Subject: [PATCH 295/774] Fix an issue for waitk when left_pad_source is set (#1752) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1752 Reviewed By: jmp84 Differential Revision: D27370799 Pulled By: xutaima fbshipit-source-id: 1ba1ef529af5dbf6608d3029b7545392458bd827 --- .../modules/monotonic_multihead_attention.py | 79 ++++++++++++++++--- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index 2e3ce8742f..b487f14a98 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -9,15 +9,12 @@ from torch import Tensor import torch.nn as nn -import torch.nn.functional as F from examples.simultaneous_translation.utils.functions import ( exclusive_cumprod, lengths_to_mask, ) -from fairseq import utils from fairseq.incremental_decoding_utils import with_incremental_state from fairseq.modules import MultiheadAttention -from fairseq.utils import convert_padding_direction from . import register_monotonic_attention from typing import Dict, Optional @@ -262,7 +259,6 @@ def expected_alignment_infer( finish_read = new_monotonic_step.eq(max_steps) | (action == 0) - monotonic_cache["head_step"] = new_monotonic_step # Whether a head is looking for new input monotonic_cache["head_read"] = ( @@ -409,9 +405,6 @@ def add_args(parser): parser.add_argument('--attention-eps', type=float, default=1e-6, help='Epsilon when calculating expected attention') - def p_choose(self, *args): - raise NotImplementedError - def attn_energy( self, q_proj: Optional[Tensor], k_proj: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, attn_mask: Optional[Tensor] = None ): @@ -934,11 +927,73 @@ def p_choose( else: tgt_len, bsz, _ = query.size() - src_len, bsz, _ = key.size() + max_src_len, bsz, _ = key.size() + + if max_src_len < self.waitk_lagging: + return query.new_zeros( + bsz * self.num_heads, tgt_len, max_src_len + ) + + # Assuming the p_choose looks like this for wait k=3 + # src_len = 6, tgt_len = 5 + # [0, 0, 1, 0, 0, 0, 0] + # [0, 0, 0, 1, 0, 0, 0] + # [0, 0, 0, 0, 1, 0, 0] + # [0, 0, 0, 0, 0, 1, 0] + # [0, 0, 0, 0, 0, 0, 1] + # linearize the p_choose matrix: + # [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0...] + # The indices of linearized matrix that equals 1 is + # 2 + 6 * 0 + # 3 + 6 * 1 + # ... + # n + src_len * n + k - 1 = n * (src_len + 1) + k - 1 + # n from 0 to tgt_len - 1 + # + # First, generate the indices (activate_indices_offset: bsz, tgt_len) + # Second, scatter a zeros tensor (bsz, tgt_len * src_len) + # with activate_indices_offset + # Third, resize the tensor to (bsz, tgt_len, src_len) + + activate_indices_offset = ( + ( + torch.arange(tgt_len) * (max_src_len + 1) + + self.waitk_lagging - 1 + ) + .unsqueeze(0) + .expand(bsz, tgt_len) + .to(query) + .long() + ) + + if key_padding_mask is not None: + if key_padding_mask[:, 0].any(): + # Left padding + activate_indices_offset += ( + key_padding_mask.sum(dim=1, keepdim=True) + ) + + # Need to clamp the indices that are too large + activate_indices_offset = ( + activate_indices_offset + .clamp( + 0, + min( + [ + tgt_len, + max_src_len - self.waitk_lagging + 1 + ] + ) * max_src_len - 1 + ) + ) + + p_choose = torch.zeros(bsz, tgt_len * max_src_len).to(query) - p_choose = torch.ones(bsz, tgt_len, src_len).to(query) - p_choose = torch.tril(p_choose, diagonal=self.waitk_lagging - 1) - p_choose = torch.triu(p_choose, diagonal=self.waitk_lagging - 1) + p_choose = p_choose.scatter( + 1, + activate_indices_offset, + 1.0 + ).view(bsz, tgt_len, max_src_len) if incremental_state is not None: p_choose = p_choose[:, -1:] @@ -950,7 +1005,7 @@ def p_choose( .unsqueeze(1) .expand(-1, self.num_heads, -1, -1) .contiguous() - .view(-1, tgt_len, src_len) + .view(-1, tgt_len, max_src_len) ) return p_choose From 579a48f4be3876082ea646880061a98c94357af1 Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Tue, 30 Mar 2021 10:34:40 -0700 Subject: [PATCH 296/774] pull unwrap_checkpoint() into library for reuse Summary: there was not a central place that model.jit() calls into, so we had to pull the logic out of pyspeech, and make it available in fairseq library. Reviewed By: myleott Differential Revision: D27349919 fbshipit-source-id: f486c11fc840d4d13a4b9265ec2e7f5cc770216c --- fairseq/modules/checkpoint_activations.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index f4a277f349..b44fc346ce 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -38,6 +38,17 @@ def checkpoint_wrapper(m, offload_to_cpu=False): return m +def unwrap_checkpoint(m: torch.nn.Module): + """ + unwrap a module and its children from checkpoint_wrapper + """ + for module in m.modules(): + if hasattr(module, "precheckpoint_forward"): + module.forward = module.precheckpoint_forward + del module.precheckpoint_forward + return m + + def _checkpointed_forward(original_forward, offload_to_cpu, *args, **kwargs): # Autograd Functions in PyTorch work best with positional args, since # the backward must return gradients (or None) for every input argument. From 14807a361202ba34dbbd3a533899db57a0ebda19 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Wed, 31 Mar 2021 17:08:08 -0700 Subject: [PATCH 297/774] Update simultaneous translation docs (#1767) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1767 Test Plan: Imported from GitHub, without a `Test Plan:` line. This pull request contains - An example of EN_JA simul t2t model - Reorganizing simul trans docs - Removal of out-of-date files Reviewed By: jmp84 Differential Revision: D27467907 Pulled By: xutaima fbshipit-source-id: 137165b007cf5301bdc51a0a277ba91cbf733092 --- examples/simultaneous_translation/README.md | 111 +-------- .../simultaneous_translation/docs/ende-mma.md | 74 ++++++ .../docs/enja-waitk.md | 106 ++++++++ .../simultaneous_translation/eval/__init__.py | 4 - .../eval/agents/__init__.py | 24 -- .../eval/agents/agent.py | 67 ------ .../eval/agents/simul_t2t_enja.py | 226 ++++++++++++++++++ .../eval/agents/simul_trans_agent.py | 167 ------------- .../eval/agents/simul_trans_text_agent.py | 81 ------- .../eval/agents/word_splitter.py | 91 ------- .../simultaneous_translation/eval/client.py | 100 -------- .../eval/eval_latency.py | 78 ------ .../simultaneous_translation/eval/evaluate.py | 81 ------- .../eval/scorers/__init__.py | 19 -- .../eval/scorers/scorer.py | 175 -------------- .../eval/scorers/text_scorer.py | 41 ---- .../simultaneous_translation/eval/server.py | 89 ------- .../agents/simul_trans_agent.py | 200 ---------------- ...moothed_cross_entropy_latency_augmented.py | 2 +- fairseq/tasks/simultaneous_translation.py | 42 ++++ 20 files changed, 454 insertions(+), 1324 deletions(-) create mode 100644 examples/simultaneous_translation/docs/ende-mma.md create mode 100644 examples/simultaneous_translation/docs/enja-waitk.md delete mode 100644 examples/simultaneous_translation/eval/__init__.py delete mode 100644 examples/simultaneous_translation/eval/agents/__init__.py delete mode 100644 examples/simultaneous_translation/eval/agents/agent.py create mode 100644 examples/simultaneous_translation/eval/agents/simul_t2t_enja.py delete mode 100644 examples/simultaneous_translation/eval/agents/simul_trans_agent.py delete mode 100644 examples/simultaneous_translation/eval/agents/simul_trans_text_agent.py delete mode 100644 examples/simultaneous_translation/eval/agents/word_splitter.py delete mode 100644 examples/simultaneous_translation/eval/client.py delete mode 100644 examples/simultaneous_translation/eval/eval_latency.py delete mode 100644 examples/simultaneous_translation/eval/evaluate.py delete mode 100644 examples/simultaneous_translation/eval/scorers/__init__.py delete mode 100644 examples/simultaneous_translation/eval/scorers/scorer.py delete mode 100644 examples/simultaneous_translation/eval/scorers/text_scorer.py delete mode 100644 examples/simultaneous_translation/eval/server.py delete mode 100644 examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py create mode 100644 fairseq/tasks/simultaneous_translation.py diff --git a/examples/simultaneous_translation/README.md b/examples/simultaneous_translation/README.md index bbc6dacdda..62a005e0ec 100644 --- a/examples/simultaneous_translation/README.md +++ b/examples/simultaneous_translation/README.md @@ -1,106 +1,5 @@ -# Simultaneous Machine Translation - -This directory contains the code for the paper [Monotonic Multihead Attention](https://openreview.net/forum?id=Hyg96gBKPS) - -## Prepare Data - -[Please follow the instructions to download and preprocess the WMT'15 En-De dataset.](https://github.com/pytorch/fairseq/tree/simulastsharedtask/examples/translation#prepare-wmt14en2desh) - -## Training - -- MMA-IL - -```shell -fairseq-train \ - data-bin/wmt15_en_de_32k \ - --simul-type infinite_lookback \ - --user-dir $FAIRSEQ/example/simultaneous_translation \ - --mass-preservation \ - --criterion latency_augmented_label_smoothed_cross_entropy \ - --latency-weight-avg 0.1 \ - --max-update 50000 \ - --arch transformer_monotonic_iwslt_de_en save_dir_key=lambda \ - --optimizer adam --adam-betas '(0.9, 0.98)' \ - --lr-scheduler 'inverse_sqrt' \ - --warmup-init-lr 1e-7 --warmup-updates 4000 \ - --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ - --dropout 0.3 \ - --label-smoothing 0.1\ - --max-tokens 3584 -``` - -- MMA-H - -```shell -fairseq-train \ - data-bin/wmt15_en_de_32k \ - --simul-type hard_aligned \ - --user-dir $FAIRSEQ/example/simultaneous_translation \ - --mass-preservation \ - --criterion latency_augmented_label_smoothed_cross_entropy \ - --latency-weight-var 0.1 \ - --max-update 50000 \ - --arch transformer_monotonic_iwslt_de_en save_dir_key=lambda \ - --optimizer adam --adam-betas '(0.9, 0.98)' \ - --lr-scheduler 'inverse_sqrt' \ - --warmup-init-lr 1e-7 --warmup-updates 4000 \ - --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ - --dropout 0.3 \ - --label-smoothing 0.1\ - --max-tokens 3584 -``` - -- wait-k - -```shell -fairseq-train \ - data-bin/wmt15_en_de_32k \ - --simul-type wait-k \ - --waitk-lagging 3 \ - --user-dir $FAIRSEQ/example/simultaneous_translation \ - --mass-preservation \ - --criterion latency_augmented_label_smoothed_cross_entropy \ - --max-update 50000 \ - --arch transformer_monotonic_iwslt_de_en save_dir_key=lambda \ - --optimizer adam --adam-betas '(0.9, 0.98)' \ - --lr-scheduler 'inverse_sqrt' \ - --warmup-init-lr 1e-7 --warmup-updates 4000 \ - --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ - --dropout 0.3 \ - --label-smoothing 0.1\ - --max-tokens 3584 -``` - - -## Evaluation - -More details on evaluation can be found [here](https://github.com/pytorch/fairseq/blob/simulastsharedtask/examples/simultaneous_translation/docs/evaluation.md) - -### Start the server - -```shell -python ./eval/server.py \ - --src-file $SRC_FILE \ - --ref-file $TGT_FILE -``` - -### Run the client - -```shell -python ./evaluate.py \ - --data-bin data-bin/wmt15_en_de_32k \ - --model-path ./checkpoints/checkpoint_best.pt - --scores --output $RESULT_DIR -``` - -### Run evaluation locally without server - -```shell -python ./eval/evaluate.py - --local \ - --src-file $SRC_FILE \ - --tgt-file $TGT_FILE \ - --data-bin data-bin/wmt15_en_de_32k \ - --model-path ./checkpoints/checkpoint_best.pt \ - --scores --output $RESULT_DIR -``` +# Simultaneous Translation +Examples of simultaneous translation in fairseq +- [English-to-Japanese text-to-text wait-k model](docs/enja-waitk.md) +- [English-to-Germen text-to-text monotonic multihead attention model](docs/ende-mma.md) +- [English-to-Germen speech-to-text simultaneous translation model](../speech_to_text/docs/simulst_mustc_example.md) diff --git a/examples/simultaneous_translation/docs/ende-mma.md b/examples/simultaneous_translation/docs/ende-mma.md new file mode 100644 index 0000000000..241d604a3b --- /dev/null +++ b/examples/simultaneous_translation/docs/ende-mma.md @@ -0,0 +1,74 @@ +# Simultaneous Machine Translation + +This directory contains the code for the paper [Monotonic Multihead Attention](https://openreview.net/forum?id=Hyg96gBKPS) + +## Prepare Data + +[Please follow the instructions to download and preprocess the WMT'15 En-De dataset.](https://github.com/pytorch/fairseq/tree/simulastsharedtask/examples/translation#prepare-wmt14en2desh) + +Another example of training an English to Japanese model can be found [here](docs/enja.md) + +## Training + +- MMA-IL + +```shell +fairseq-train \ + data-bin/wmt15_en_de_32k \ + --simul-type infinite_lookback \ + --user-dir $FAIRSEQ/example/simultaneous_translation \ + --mass-preservation \ + --criterion latency_augmented_label_smoothed_cross_entropy \ + --latency-weight-avg 0.1 \ + --max-update 50000 \ + --arch transformer_monotonic_iwslt_de_en save_dir_key=lambda \ + --optimizer adam --adam-betas '(0.9, 0.98)' \ + --lr-scheduler 'inverse_sqrt' \ + --warmup-init-lr 1e-7 --warmup-updates 4000 \ + --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ + --dropout 0.3 \ + --label-smoothing 0.1\ + --max-tokens 3584 +``` + +- MMA-H + +```shell +fairseq-train \ + data-bin/wmt15_en_de_32k \ + --simul-type hard_aligned \ + --user-dir $FAIRSEQ/example/simultaneous_translation \ + --mass-preservation \ + --criterion latency_augmented_label_smoothed_cross_entropy \ + --latency-weight-var 0.1 \ + --max-update 50000 \ + --arch transformer_monotonic_iwslt_de_en save_dir_key=lambda \ + --optimizer adam --adam-betas '(0.9, 0.98)' \ + --lr-scheduler 'inverse_sqrt' \ + --warmup-init-lr 1e-7 --warmup-updates 4000 \ + --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ + --dropout 0.3 \ + --label-smoothing 0.1\ + --max-tokens 3584 +``` + +- wait-k + +```shell +fairseq-train \ + data-bin/wmt15_en_de_32k \ + --simul-type wait-k \ + --waitk-lagging 3 \ + --user-dir $FAIRSEQ/example/simultaneous_translation \ + --mass-preservation \ + --criterion latency_augmented_label_smoothed_cross_entropy \ + --max-update 50000 \ + --arch transformer_monotonic_iwslt_de_en save_dir_key=lambda \ + --optimizer adam --adam-betas '(0.9, 0.98)' \ + --lr-scheduler 'inverse_sqrt' \ + --warmup-init-lr 1e-7 --warmup-updates 4000 \ + --lr 5e-4 --stop-min-lr 1e-9 --clip-norm 0.0 --weight-decay 0.0001\ + --dropout 0.3 \ + --label-smoothing 0.1\ + --max-tokens 3584 +``` diff --git a/examples/simultaneous_translation/docs/enja-waitk.md b/examples/simultaneous_translation/docs/enja-waitk.md new file mode 100644 index 0000000000..fb9d82576f --- /dev/null +++ b/examples/simultaneous_translation/docs/enja-waitk.md @@ -0,0 +1,106 @@ +# An example of English to Japaneses Simultaneous Translation System + +This is an example of training and evaluating a transformer *wait-k* English to Japanese simultaneous text-to-text translation model. + +## Data Preparation +This section introduces the data preparation for training and evaluation. +If you only want to evaluate the model, please jump to [Inference & Evaluation](#inference-&-evaluation) + +For illustration, we only use the following subsets of the available data from [WMT20 news translation task](http://www.statmt.org/wmt20/translation-task.html), which results in 7,815,391 sentence pairs. +- News Commentary v16 +- Wiki Titles v3 +- WikiMatrix V1 +- Japanese-English Subtitle Corpus +- The Kyoto Free Translation Task Corpus + +We use WMT20 development data as development set. Training `transformer_vaswani_wmt_en_de_big` model on such amount of data will result in 17.3 BLEU with greedy search and 19.7 with beam (10) search. Notice that a better performance can be achieved with the full WMT training data. + +We use [sentencepiece](https://github.com/google/sentencepiece) toolkit to tokenize the data with a vocabulary size of 32000. +Additionally, we filtered out the sentences longer than 200 words after tokenization. +Assuming the tokenized text data is saved at `${DATA_DIR}`, +we prepare the data binary with the following command. + +```bash +fairseq-preprocess \ + --source-lang en --target-lang ja \ + --trainpref ${DATA_DIR}/train \ + --validpref ${DATA_DIR}/dev \ + --testpref ${DATA_DIR}/test \ + --destdir ${WMT20_ENJA_DATA_BIN} \ + --nwordstgt 32000 --nwordssrc 32000 \ + --workers 20 +``` + +## Simultaneous Translation Model Training +To train a wait-k `(k=10)` model. +```bash +fairseq-train ${WMT20_ENJA_DATA_BIN} \ + --save-dir ${SAVEDIR} + --simul-type waitk \ + --waitk-lagging 10 \ + --max-epoch 70 \ + --arch transformer_monotonic_vaswani_wmt_en_de_big \ + --optimizer adam \ + --adam-betas '(0.9, 0.98)' \ + --lr-scheduler inverse_sqrt \ + --warmup-init-lr 1e-07 \ + --warmup-updates 4000 \ + --lr 0.0005 \ + --stop-min-lr 1e-09 \ + --clip-norm 10.0 \ + --dropout 0.3 \ + --weight-decay 0.0 \ + --criterion label_smoothed_cross_entropy \ + --label-smoothing 0.1 \ + --max-tokens 3584 +``` +This command is for training on 8 GPUs. Equivalently, the model can be trained on one GPU with `--update-freq 8`. + +## Inference & Evaluation +First of all, install [SimulEval](https://github.com/facebookresearch/SimulEval) for evaluation. + +```bash +git clone https://github.com/facebookresearch/SimulEval.git +cd SimulEval +pip install -e . +``` + +The following command is for the evaluation. +Assuming the source and reference files are `${SRC_FILE}` and `${REF_FILE}`, the sentencepiece model file for English is saved at `${SRC_SPM_PATH}` + + +```bash +simuleval \ + --source ${SRC_FILE} \ + --target ${TGT_FILE} \ + --data-bin ${WMT20_ENJA_DATA_BIN} \ + --sacrebleu-tokenizer ja-mecab \ + --eval-latency-unit char \ + --no-space \ + --src-splitter-type sentencepiecemodel \ + --src-splitter-path ${SRC_SPM_PATH} \ + --agent ${FAIRSEQ}/examples/simultaneous_translation/agents/simul_trans_text_agent_enja.py \ + --model-path ${SAVE_DIR}/${CHECKPOINT_FILENAME} \ + --output ${OUTPUT} \ + --scores +``` + +The `--data-bin` should be the same in previous sections if you prepare the data from the scratch. +If only for evaluation, a prepared data directory can be found [here](https://dl.fbaipublicfiles.com/simultaneous_translation/wmt20_enja_medium_databin.tgz) and a pretrained checkpoint (wait-k=10 model) can be downloaded from [here](https://dl.fbaipublicfiles.com/simultaneous_translation/wmt20_enja_medium_wait10_ckpt.pt). + +The output should look like this: +```bash +{ + "Quality": { + "BLEU": 11.442253287568398 + }, + "Latency": { + "AL": 8.6587861866951, + "AP": 0.7863304776251316, + "DAL": 9.477850951194764 + } +} +``` +The latency is evaluated by characters (`--eval-latency-unit`) on the target side. The latency is evaluated with `sacrebleu` with `MeCab` tokenizer `--sacrebleu-tokenizer ja-mecab`. `--no-space` indicates that do not add space when merging the predicted words. + +If `--output ${OUTPUT}` option is used, the detailed log and scores will be stored under the `${OUTPUT}` directory. diff --git a/examples/simultaneous_translation/eval/__init__.py b/examples/simultaneous_translation/eval/__init__.py deleted file mode 100644 index 6264236915..0000000000 --- a/examples/simultaneous_translation/eval/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. diff --git a/examples/simultaneous_translation/eval/agents/__init__.py b/examples/simultaneous_translation/eval/agents/__init__.py deleted file mode 100644 index 511e7b2474..0000000000 --- a/examples/simultaneous_translation/eval/agents/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import importlib -import os - -from fairseq import registry - - -build_agent, register_agent, MONOTONIC_AGENT, _ = registry.setup_registry( - "--agent-type" -) - - -DEFAULT_EOS = "</s>" -GET = 0 -SEND = 1 - -for file in os.listdir(os.path.dirname(__file__)): - if file.endswith(".py") and not file.startswith("_"): - module = file[: file.find(".py")] - importlib.import_module("agents." + module) diff --git a/examples/simultaneous_translation/eval/agents/agent.py b/examples/simultaneous_translation/eval/agents/agent.py deleted file mode 100644 index 997392cf9b..0000000000 --- a/examples/simultaneous_translation/eval/agents/agent.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import time -from functools import partial -from multiprocessing.pool import ThreadPool as Pool - -from . import DEFAULT_EOS, GET, SEND - - -class Agent(object): - "an agent needs to follow this pattern" - - def __init__(self, *args, **kwargs): - pass - - def init_states(self, *args, **kwargs): - raise NotImplementedError - - def update_states(self, states, new_state): - raise NotImplementedError - - def finish_eval(self, states, new_state): - raise NotImplementedError - - def policy(self, state): - raise NotImplementedError - - def reset(self): - raise NotImplementedError - - def decode(self, session, low=0, high=100000, num_thread=10): - corpus_info = session.corpus_info() - high = min(corpus_info["num_sentences"] - 1, high) - if low >= high: - return - - t0 = time.time() - if num_thread > 1: - with Pool(10) as p: - p.map( - partial(self._decode_one, session), - [sent_id for sent_id in range(low, high + 1)], - ) - else: - for sent_id in range(low, high + 1): - self._decode_one(session, sent_id) - - print(f"Finished {low} to {high} in {time.time() - t0}s") - - def _decode_one(self, session, sent_id): - action = {} - self.reset() - states = self.init_states() - while action.get("value", None) != DEFAULT_EOS: - # take an action - action = self.policy(states) - - if action["key"] == GET: - new_states = session.get_src(sent_id, action["value"]) - states = self.update_states(states, new_states) - - elif action["key"] == SEND: - session.send_hypo(sent_id, action["value"]) - print(" ".join(states["tokens"]["tgt"])) diff --git a/examples/simultaneous_translation/eval/agents/simul_t2t_enja.py b/examples/simultaneous_translation/eval/agents/simul_t2t_enja.py new file mode 100644 index 0000000000..8f3c8703ca --- /dev/null +++ b/examples/simultaneous_translation/eval/agents/simul_t2t_enja.py @@ -0,0 +1,226 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os + +from fairseq import checkpoint_utils, tasks +import sentencepiece as spm +import torch + +try: + from simuleval import READ_ACTION, WRITE_ACTION, DEFAULT_EOS + from simuleval.agents import TextAgent +except ImportError: + print("Please install simuleval 'pip install simuleval'") + + +BOS_PREFIX = "\u2581" + + +class SimulTransTextAgentJA(TextAgent): + """ + Simultaneous Translation + Text agent for Japanese + """ + def __init__(self, args): + + # Whether use gpu + self.gpu = getattr(args, "gpu", False) + + # Max len + self.max_len = args.max_len + + # Load Model + self.load_model_vocab(args) + + # build word splitter + self.build_word_splitter(args) + + self.eos = DEFAULT_EOS + + def initialize_states(self, states): + states.incremental_states = dict() + states.incremental_states["online"] = dict() + + def to_device(self, tensor): + if self.gpu: + return tensor.cuda() + else: + return tensor.cpu() + + def load_model_vocab(self, args): + + filename = args.model_path + if not os.path.exists(filename): + raise IOError("Model file not found: {}".format(filename)) + + state = checkpoint_utils.load_checkpoint_to_cpu(filename) + + task_args = state["cfg"]["task"] + task_args.data = args.data_bin + + task = tasks.setup_task(task_args) + + # build model for ensemble + state["cfg"]["model"].load_pretrained_encoder_from = None + state["cfg"]["model"].load_pretrained_decoder_from = None + + self.model = task.build_model(state["cfg"]["model"]) + self.model.load_state_dict(state["model"], strict=True) + self.model.eval() + self.model.share_memory() + + if self.gpu: + self.model.cuda() + + # Set dictionary + self.dict = {} + self.dict["tgt"] = task.target_dictionary + self.dict["src"] = task.source_dictionary + + @staticmethod + def add_args(parser): + # fmt: off + parser.add_argument('--model-path', type=str, required=True, + help='path to your pretrained model.') + parser.add_argument("--data-bin", type=str, required=True, + help="Path of data binary") + parser.add_argument("--max-len", type=int, default=100, + help="Max length of translation") + parser.add_argument("--tgt-splitter-type", type=str, default="SentencePiece", + help="Subword splitter type for target text.") + parser.add_argument("--tgt-splitter-path", type=str, default=None, + help="Subword splitter model path for target text.") + parser.add_argument("--src-splitter-type", type=str, default="SentencePiece", + help="Subword splitter type for source text.") + parser.add_argument("--src-splitter-path", type=str, default=None, + help="Subword splitter model path for source text.") + # fmt: on + return parser + + def build_word_splitter(self, args): + self.spm = {} + for lang in ['src', 'tgt']: + if getattr(args, f'{lang}_splitter_type', None): + path = getattr(args, f'{lang}_splitter_path', None) + if path: + self.spm[lang] = spm.SentencePieceProcessor() + self.spm[lang].Load(path) + + def segment_to_units(self, segment, states): + # Split a full word (segment) into subwords (units) + return self.spm['src'].EncodeAsPieces(segment) + + def update_model_encoder(self, states): + if len(states.units.source) == 0: + return + + src_indices = [ + self.dict['src'].index(x) + for x in states.units.source.value + ] + + if states.finish_read(): + # Append the eos index when the prediction is over + src_indices += [self.dict["tgt"].eos_index] + + src_indices = self.to_device( + torch.LongTensor(src_indices).unsqueeze(0) + ) + src_lengths = self.to_device( + torch.LongTensor([src_indices.size(1)]) + ) + + states.encoder_states = self.model.encoder(src_indices, src_lengths) + + torch.cuda.empty_cache() + + def update_states_read(self, states): + # Happens after a read action. + self.update_model_encoder(states) + + def units_to_segment(self, units, states): + # Merge sub words (units) to full word (segment). + # For Japanese, we can directly send + # the untokenized token to server except the BOS token + # with following option + # --sacrebleu-tokenizer MeCab + # --eval-latency-unit char + # --no-space + token = units.value.pop() + + if ( + token == self.dict["tgt"].eos_word + or len(states.segments.target) > self.max_len + ): + return DEFAULT_EOS + + if BOS_PREFIX == token: + return None + if token[0] == BOS_PREFIX: + return token[1:] + else: + return token + + def policy(self, states): + + if not getattr(states, "encoder_states", None): + # No encoder states, read a token first + return READ_ACTION + + # encode previous predicted target tokens + tgt_indices = self.to_device( + torch.LongTensor( + [self.model.decoder.dictionary.eos()] + + [ + self.dict['tgt'].index(x) + for x in states.units.target.value + if x is not None + ] + ).unsqueeze(0) + ) + + # Current steps + states.incremental_states["steps"] = { + "src": states.encoder_states["encoder_out"][0].size(0), + "tgt": 1 + len(states.units.target), + } + + # Online only means the reading is not finished + states.incremental_states["online"]["only"] = ( + torch.BoolTensor([not states.finish_read()]) + ) + + x, outputs = self.model.decoder.forward( + prev_output_tokens=tgt_indices, + encoder_out=states.encoder_states, + incremental_state=states.incremental_states, + ) + + states.decoder_out = x + + torch.cuda.empty_cache() + + if outputs.action == 0: + return READ_ACTION + else: + return WRITE_ACTION + + def predict(self, states): + # Predict target token from decoder states + decoder_states = states.decoder_out + + lprobs = self.model.get_normalized_probs( + [decoder_states[:, -1:]], log_probs=True + ) + + index = lprobs.argmax(dim=-1)[0, 0].item() + + if index != self.dict['tgt'].eos_index: + token = self.dict['tgt'].string([index]) + else: + token = self.dict['tgt'].eos_word + + return token diff --git a/examples/simultaneous_translation/eval/agents/simul_trans_agent.py b/examples/simultaneous_translation/eval/agents/simul_trans_agent.py deleted file mode 100644 index 071b9e89ce..0000000000 --- a/examples/simultaneous_translation/eval/agents/simul_trans_agent.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import json -import os - -from fairseq import checkpoint_utils, tasks, utils - -from . import DEFAULT_EOS, GET, SEND -from .agent import Agent - - -class SimulTransAgent(Agent): - def __init__(self, args): - # Load Model - self.load_model(args) - - # build word spliter - self.build_word_splitter(args) - - self.max_len = args.max_len - - self.eos = DEFAULT_EOS - - @staticmethod - def add_args(parser): - # fmt: off - parser.add_argument('--model-path', type=str, required=True, - help='path to your pretrained model.') - parser.add_argument("--data-bin", type=str, required=True, - help="Path of data binary") - parser.add_argument("--user-dir", type=str, default="example/simultaneous_translation", - help="User directory for simultaneous translation") - parser.add_argument("--src-splitter-type", type=str, default=None, - help="Subword splitter type for source text") - parser.add_argument("--tgt-splitter-type", type=str, default=None, - help="Subword splitter type for target text") - parser.add_argument("--src-splitter-path", type=str, default=None, - help="Subword splitter model path for source text") - parser.add_argument("--tgt-splitter-path", type=str, default=None, - help="Subword splitter model path for target text") - parser.add_argument("--max-len", type=int, default=150, - help="Maximum length difference between source and target prediction") - parser.add_argument('--model-overrides', default="{}", type=str, metavar='DICT', - help='A dictionary used to override model args at generation ' - 'that were used during model training') - # fmt: on - return parser - - def load_dictionary(self, task): - raise NotImplementedError - - def load_model(self, args): - args.user_dir = os.path.join(os.path.dirname(__file__), "..", "..") - utils.import_user_module(args) - filename = args.model_path - if not os.path.exists(filename): - raise IOError("Model file not found: {}".format(filename)) - - state = checkpoint_utils.load_checkpoint_to_cpu( - filename, json.loads(args.model_overrides) - ) - - saved_args = state["args"] - saved_args.data = args.data_bin - - task = tasks.setup_task(saved_args) - - # build model for ensemble - self.model = task.build_model(saved_args) - self.model.load_state_dict(state["model"], strict=True) - - # Set dictionary - self.load_dictionary(task) - - def init_states(self): - return { - "indices": {"src": [], "tgt": []}, - "tokens": {"src": [], "tgt": []}, - "segments": {"src": [], "tgt": []}, - "steps": {"src": 0, "tgt": 0}, - "finished": False, - "finish_read": False, - "model_states": {}, - } - - def update_states(self, states, new_state): - raise NotImplementedError - - def policy(self, states): - # Read and Write policy - action = None - - while action is None: - if states["finished"]: - # Finish the hypo by sending eos to server - return self.finish_action() - - # Model make decision given current states - decision = self.model.decision_from_states(states) - - if decision == 0 and not self.finish_read(states): - # READ - action = self.read_action(states) - else: - # WRITE - action = self.write_action(states) - - # None means we make decision again but not sending server anything - # This happened when read a bufffered token - # Or predict a subword - return action - - def finish_read(self, states): - raise NotImplementedError - - def write_action(self, states): - token, index = self.model.predict_from_states(states) - - if ( - index == self.dict["tgt"].eos() - or len(states["tokens"]["tgt"]) > self.max_len - ): - # Finish this sentence is predict EOS - states["finished"] = True - end_idx_last_full_word = self._target_length(states) - - else: - states["tokens"]["tgt"] += [token] - end_idx_last_full_word = self.word_splitter["tgt"].end_idx_last_full_word( - states["tokens"]["tgt"] - ) - self._append_indices(states, [index], "tgt") - - if end_idx_last_full_word > states["steps"]["tgt"]: - # Only sent detokenized full words to the server - word = self.word_splitter["tgt"].merge( - states["tokens"]["tgt"][states["steps"]["tgt"] : end_idx_last_full_word] - ) - states["steps"]["tgt"] = end_idx_last_full_word - states["segments"]["tgt"] += [word] - - return {"key": SEND, "value": word} - else: - return None - - def read_action(self, states): - return {"key": GET, "value": None} - - def finish_action(self): - return {"key": SEND, "value": DEFAULT_EOS} - - def reset(self): - pass - - def finish_eval(self, states, new_state): - if len(new_state) == 0 and len(states["indices"]["src"]) == 0: - return True - return False - - def _append_indices(self, states, new_indices, key): - states["indices"][key] += new_indices - - def _target_length(self, states): - return len(states["tokens"]["tgt"]) diff --git a/examples/simultaneous_translation/eval/agents/simul_trans_text_agent.py b/examples/simultaneous_translation/eval/agents/simul_trans_text_agent.py deleted file mode 100644 index 7c34817bf6..0000000000 --- a/examples/simultaneous_translation/eval/agents/simul_trans_text_agent.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from . import DEFAULT_EOS, GET, register_agent -from .simul_trans_agent import SimulTransAgent -from .word_splitter import SPLITTER_DICT - - -@register_agent("simul_trans_text") -class SimulTransTextAgent(SimulTransAgent): - def build_word_splitter(self, args): - self.word_splitter = {} - - self.word_splitter["src"] = SPLITTER_DICT[args.src_splitter_type]( - getattr(args, f"src_splitter_path") - ) - self.word_splitter["tgt"] = SPLITTER_DICT[args.tgt_splitter_type]( - getattr(args, f"tgt_splitter_path") - ) - - def load_dictionary(self, task): - self.dict = {} - self.dict["tgt"] = task.target_dictionary - self.dict["src"] = task.source_dictionary - - def update_states(self, states, new_state): - if states["finish_read"]: - return states - - new_word = new_state["segment"] - - # Split words and index the token - if new_word not in [DEFAULT_EOS]: - tokens = self.word_splitter["src"].split(new_word) - # Get indices from dictionary - # You can change to you own dictionary - indices = ( - self.dict["src"] - .encode_line( - tokens, - line_tokenizer=lambda x: x, - add_if_not_exist=False, - append_eos=False, - ) - .tolist() - ) - else: - tokens = [new_word] - indices = [self.dict["src"].eos()] - states["finish_read"] = True - - # Update states - states["segments"]["src"] += [new_word] - states["tokens"]["src"] += tokens - self._append_indices(states, indices, "src") - - return states - - def read_action(self, states): - # Increase source step by one - states["steps"]["src"] += 1 - - # At leat one word is read - if len(states["tokens"]["src"]) == 0: - return {"key": GET, "value": None} - - # Only request new word if there is no buffered tokens - if len(states["tokens"]["src"]) <= states["steps"]["src"]: - return {"key": GET, "value": None} - - return None - - def finish_read(self, states): - # The first means all segments (full words) has been read from server - # The second means all tokens (subwords) has been read locally - return ( - states["finish_read"] - and len(states["tokens"]["src"]) == states["steps"]["src"] - ) diff --git a/examples/simultaneous_translation/eval/agents/word_splitter.py b/examples/simultaneous_translation/eval/agents/word_splitter.py deleted file mode 100644 index c3f71200a5..0000000000 --- a/examples/simultaneous_translation/eval/agents/word_splitter.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - - -class SubwordSplitter(object): - def process_line(self, string): - raise NotImplementedError - - def split(self, string): - raise NotImplementedError - - -class NoneWordSplitter(object): - def __init__(self, model): - pass - - def split(self, string): - return [string] - - def process_line(self, string): - return [string] - - def finished_word(self, string): - return True - - def merge(self, list_of_string): - return "".join(list_of_string) - - def last_full_word_step(self, tokens, step): - return len(tokens) - - def end_idx_last_full_word(self, tokens): - return len(tokens) - - -class BPEWordSplitter(object): - # TODO: lock back here - def __init__(self, model_path): - super().__init__() - from subword_nmt.apply_bpe import BPE - - with open(model_path) as f: - self.model = BPE(f) - - def split(self, string): - return self.model.process_line(string).split() - - def end_idx_last_full_word(self, tokens): - # Begin of word indices - bow_indices = [0] + [i + 1 for i, t in enumerate(tokens[1:]) if t[-2:] != "@@"] - - if len(bow_indices) < 2: - return 0 - else: - return bow_indices[-1] - - def merge(self, list_of_string): - return " ".join([item.replace("@@", "") for item in list_of_string]) - - -class SentencePieceModelWordSplitter(object): - def __init__(self, model_path): - super().__init__() - import sentencepiece as spm - - self.model = spm.SentencePieceProcessor() - self.model.Load(model_path) - - def split(self, string): - return self.model.EncodeAsPieces(string) - - def end_idx_last_full_word(self, tokens): - # Begin of word indices - bow_indices = [i for i, t in enumerate(tokens) if t[0] == "\u2581"] - - if len(bow_indices) < 2: - return 0 - else: - return bow_indices[-1] - - def merge(self, list_of_string): - return self.model.DecodePieces(list_of_string) - - -SPLITTER_DICT = { - None: NoneWordSplitter, - "BPE": BPEWordSplitter, - "SentencePieceModel": SentencePieceModelWordSplitter, -} diff --git a/examples/simultaneous_translation/eval/client.py b/examples/simultaneous_translation/eval/client.py deleted file mode 100644 index 3ca4ea73b8..0000000000 --- a/examples/simultaneous_translation/eval/client.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from typing import Optional - -import requests -from scorers import build_scorer - - -class SimulSTEvaluationService(object): - DEFAULT_HOSTNAME = "localhost" - DEFAULT_PORT = 12321 - - def __init__(self, hostname=DEFAULT_HOSTNAME, port=DEFAULT_PORT): - self.hostname = hostname - self.port = port - self.base_url = f"http://{self.hostname}:{self.port}" - - def __enter__(self): - self.new_session() - - def __exit__(self, exc_type, exc_val, exc_tb): - pass - - def new_session(self): - # start eval session - url = f"{self.base_url}" - - try: - _ = requests.post(url) - except Exception as e: - print(f"Failed to start an evaluation session: {e}") - - print("Evaluation session started.") - return self - - def get_scores(self): - # end eval session - url = f"{self.base_url}/result" - try: - r = requests.get(url) - print("Scores: {}".format(r.json())) - print("Evaluation session finished.") - except Exception as e: - print(f"Failed to end an evaluation session: {e}") - - def get_src(self, sent_id: int, extra_params: Optional[dict] = None) -> str: - url = f"{self.base_url}/src" - params = {"sent_id": sent_id} - if extra_params is not None: - for key in extra_params.keys(): - params[key] = extra_params[key] - try: - r = requests.get(url, params=params) - except Exception as e: - print(f"Failed to request a source segment: {e}") - return r.json() - - def send_hypo(self, sent_id: int, hypo: str) -> None: - url = f"{self.base_url}/hypo" - params = {"sent_id": sent_id} - - try: - requests.put(url, params=params, data=hypo.encode("utf-8")) - except Exception as e: - print(f"Failed to send a translated segment: {e}") - - def corpus_info(self): - url = f"{self.base_url}" - try: - r = requests.get(url) - except Exception as e: - print(f"Failed to request corpus information: {e}") - - return r.json() - - -class SimulSTLocalEvaluationService(object): - def __init__(self, args): - self.scorer = build_scorer(args) - - def get_scores(self): - return self.scorer.score() - - def get_src(self, sent_id: int, extra_params: Optional[dict] = None) -> str: - if extra_params is not None: - segment_size = extra_params.get("segment_size", None) - else: - segment_size = None - - return self.scorer.send_src(int(sent_id), segment_size) - - def send_hypo(self, sent_id: int, hypo: str) -> None: - list_of_tokens = hypo.strip().split() - self.scorer.recv_hyp(sent_id, list_of_tokens) - - def corpus_info(self): - return self.scorer.get_info() diff --git a/examples/simultaneous_translation/eval/eval_latency.py b/examples/simultaneous_translation/eval/eval_latency.py deleted file mode 100644 index 50021de47c..0000000000 --- a/examples/simultaneous_translation/eval/eval_latency.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import argparse -import json - -import torch -from examples.simultaneous_translation.utils.latency import LatencyInference - - -LATENCY_METRICS = [ - "differentiable_average_lagging", - "average_lagging", - "average_proportion", -] - - -class LatencyScorer: - def __init__(self, start_from_zero=True): - self.recorder = [] - self.scores = {} - self.scorer = LatencyInference() - self.start_from_zero = start_from_zero - - def update_reorder(self, list_of_dict): - self.recorder = [] - for info in list_of_dict: - delays = [int(x) - int(not self.start_from_zero) for x in info["delays"]] - delays = torch.LongTensor(delays).unsqueeze(0) - src_len = torch.LongTensor([info["src_len"]]).unsqueeze(0) - - self.recorder.append(self.scorer(delays, src_len)) - - def cal_latency(self): - self.scores = {} - for metric in LATENCY_METRICS: - self.scores[metric] = sum( - [x[metric][0, 0].item() for x in self.recorder] - ) / len(self.recorder) - return self.scores - - @classmethod - def score(cls, list_of_dict, start_from_zero=True): - scorer_to_return = cls(start_from_zero) - scorer_to_return.update_reorder(list_of_dict) - scorer_to_return.cal_latency() - return scorer_to_return.scores - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument("--input", required=True) - parser.add_argument("--start-from-zero", action="store_true") - args = parser.parse_args() - - scorer = LatencyInference() - recorder = [] - with open(args.input, "r") as f: - for line in f: - info = json.loads(line) - - delays = [int(x) - int(not args.start_from_zero) for x in info["delays"]] - - delays = torch.LongTensor(delays).unsqueeze(0) - - src_len = torch.LongTensor([info["src_len"]]).unsqueeze(0) - - recorder.append(scorer(delays, src_len)) - - average_results = {} - - for metric in LATENCY_METRICS: - average_results[metric] = sum([x[metric][0, 0].item() for x in recorder]) / len( - recorder - ) - print(f"{metric}: {average_results[metric]}") diff --git a/examples/simultaneous_translation/eval/evaluate.py b/examples/simultaneous_translation/eval/evaluate.py deleted file mode 100644 index 2f7474621a..0000000000 --- a/examples/simultaneous_translation/eval/evaluate.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import argparse - -from agents import build_agent -from client import SimulSTEvaluationService, SimulSTLocalEvaluationService -from fairseq.registry import REGISTRIES - - -DEFAULT_HOSTNAME = "localhost" -DEFAULT_PORT = 12321 - - -def get_args(): - parser = argparse.ArgumentParser() - - parser.add_argument( - "--hostname", type=str, default=DEFAULT_HOSTNAME, help="server hostname" - ) - parser.add_argument( - "--port", type=int, default=DEFAULT_PORT, help="server port number" - ) - parser.add_argument("--agent-type", default="simul_trans_text", help="Agent type") - parser.add_argument("--scorer-type", default="text", help="Scorer type") - parser.add_argument( - "--start-idx", - type=int, - default=0, - help="Start index of the sentence to evaluate", - ) - parser.add_argument( - "--end-idx", - type=int, - default=float("inf"), - help="End index of the sentence to evaluate", - ) - parser.add_argument( - "--scores", action="store_true", help="Request scores from server" - ) - parser.add_argument("--reset-server", action="store_true", help="Reset the server") - parser.add_argument( - "--num-threads", type=int, default=10, help="Number of threads used by agent" - ) - parser.add_argument( - "--local", action="store_true", default=False, help="Local evaluation" - ) - - args, _ = parser.parse_known_args() - - for registry_name, REGISTRY in REGISTRIES.items(): - choice = getattr(args, registry_name, None) - if choice is not None: - cls = REGISTRY["registry"][choice] - if hasattr(cls, "add_args"): - cls.add_args(parser) - args = parser.parse_args() - - return args - - -if __name__ == "__main__": - args = get_args() - - if args.local: - session = SimulSTLocalEvaluationService(args) - else: - session = SimulSTEvaluationService(args.hostname, args.port) - - if args.reset_server: - session.new_session() - - if args.agent_type is not None: - agent = build_agent(args) - agent.decode(session, args.start_idx, args.end_idx, args.num_threads) - - if args.scores: - session.get_scores() - print(session.get_scores()) diff --git a/examples/simultaneous_translation/eval/scorers/__init__.py b/examples/simultaneous_translation/eval/scorers/__init__.py deleted file mode 100644 index 0a0e0a0518..0000000000 --- a/examples/simultaneous_translation/eval/scorers/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import importlib -import os - -from fairseq import registry - - -(build_scorer, register_scorer, SCORER_REGISTRIES, _) = registry.setup_registry( - "--scorer-type" -) - -for file in os.listdir(os.path.dirname(__file__)): - if file.endswith(".py") and not file.startswith("_"): - module = file[: file.find(".py")] - importlib.import_module("scorers." + module) diff --git a/examples/simultaneous_translation/eval/scorers/scorer.py b/examples/simultaneous_translation/eval/scorers/scorer.py deleted file mode 100644 index d6d3e30aef..0000000000 --- a/examples/simultaneous_translation/eval/scorers/scorer.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import json -import os -from collections import defaultdict - -from examples.simultaneous_translation.eval.eval_latency import LatencyScorer -from vizseq.scorers.bleu import BLEUScorer -from vizseq.scorers.meteor import METEORScorer -from vizseq.scorers.ter import TERScorer - - -DEFAULT_EOS = "</s>" - - -class SimulScorer(object): - def __init__(self, args): - self.tokenizer = args.tokenizer - self.output_dir = args.output - if args.output is not None: - self.output_files = { - "text": os.path.join(args.output, "text"), - "delay": os.path.join(args.output, "delay"), - "scores": os.path.join(args.output, "scores"), - } - else: - self.output_files = None - self.eos = DEFAULT_EOS - self.data = {"tgt": []} - self.reset() - - def get_info(self): - return {"num_sentences": len(self)} - - @staticmethod - def add_args(parser): - # fmt: off - parser.add_argument('--src-file', type=str, required=True, - help='Source input file') - parser.add_argument('--tgt-file', type=str, required=True, - help='Target reference file') - parser.add_argument('--tokenizer', default="13a", choices=["none", "13a"], - help='Tokenizer used for sacrebleu') - parser.add_argument('--output', type=str, default=None, - help='Path for output directory') - # fmt: on - - def send_src(self, sent_id, *args): - raise NotImplementedError - - def recv_hyp(self, sent_id, list_of_tokens): - for token in list_of_tokens: - self.translations[sent_id].append((token, self.steps[sent_id])) - - def reset(self): - self.steps = defaultdict(int) - self.translations = defaultdict(list) - - def src_lengths(self): - raise NotImplementedError - - def score(self): - translations = [] - delays = [] - for i in range(1 + max(self.translations.keys())): - translations += [" ".join(t[0] for t in self.translations[i][:-1])] - delays += [[t[1] for t in self.translations[i]]] - - bleu_score = BLEUScorer( - sent_level=False, - corpus_level=True, - extra_args={"bleu_tokenizer": self.tokenizer}, - ).score(translations, [self.data["tgt"]]) - - ter_score = TERScorer(sent_level=False, corpus_level=True).score( - translations, [self.data["tgt"]] - ) - meteor_score = METEORScorer(sent_level=False, corpus_level=True).score( - translations, [self.data["tgt"]] - ) - - latency_score = LatencyScorer().score( - [ - {"src_len": src_len, "delays": delay} - for src_len, delay in zip(self.src_lengths(), delays) - ], - start_from_zero=False, - ) - - scores = { - "BLEU": bleu_score[0], - "TER": ter_score[0], - "METEOR": meteor_score[0], - "DAL": latency_score["differentiable_average_lagging"], - "AL": latency_score["average_lagging"], - "AP": latency_score["average_proportion"], - } - - if self.output_files is not None: - try: - os.makedirs(self.output_dir, exist_ok=True) - self.write_results_to_file(translations, delays, scores) - except BaseException as be: - print(f"Failed to write results to {self.output_dir}.") - print(be) - print("Skip writing predictions") - - return scores - - def write_results_to_file(self, translations, delays, scores): - if self.output_files["text"] is not None: - with open(self.output_files["text"], "w") as f: - for line in translations: - f.write(line + "\n") - - if self.output_files["delay"] is not None: - with open(self.output_files["delay"], "w") as f: - for i, delay in enumerate(delays): - f.write( - json.dumps({"src_len": self.src_lengths()[i], "delays": delay}) - + "\n" - ) - - with open(self.output_files["scores"], "w") as f: - for key, value in scores.items(): - f.write(f"{key}, {value}\n") - - @classmethod - def _load_text_file(cls, file, split=False): - with open(file) as f: - if split: - return [r.strip().split() for r in f] - else: - return [r.strip() for r in f] - - @classmethod - def _load_text_from_json(cls, file): - list_to_return = [] - with open(file) as f: - content = json.load(f) - for item in content["utts"].values(): - list_to_return.append(item["output"]["text"].strip()) - return list_to_return - - @classmethod - def _load_wav_info_from_json(cls, file): - list_to_return = [] - with open(file) as f: - content = json.load(f) - for item in content["utts"].values(): - list_to_return.append( - { - "path": item["input"]["path"].strip(), - "length": item["input"]["length_ms"], - } - ) - return list_to_return - - @classmethod - def _load_wav_info_from_list(cls, file): - list_to_return = [] - with open(file) as f: - for line in f: - list_to_return.append( - { - "path": line.strip(), - } - ) - return list_to_return - - def __len__(self): - return len(self.data["tgt"]) diff --git a/examples/simultaneous_translation/eval/scorers/text_scorer.py b/examples/simultaneous_translation/eval/scorers/text_scorer.py deleted file mode 100644 index 649a2c7e5c..0000000000 --- a/examples/simultaneous_translation/eval/scorers/text_scorer.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -from . import register_scorer -from .scorer import SimulScorer - - -@register_scorer("text") -class SimulTextScorer(SimulScorer): - def __init__(self, args): - super().__init__(args) - self.data = { - "src": self._load_text_file(args.src_file, split=True), - "tgt": self._load_text_file(args.tgt_file, split=False), - } - - def send_src(self, sent_id, *args): - if self.steps[sent_id] >= len(self.data["src"][sent_id]): - dict_to_return = { - "sent_id": sent_id, - "segment_id": self.steps[sent_id], - "segment": self.eos, - } - # Consider EOS - self.steps[sent_id] = len(self.data["src"][sent_id]) + 1 - else: - dict_to_return = { - "sent_id": sent_id, - "segment_id": self.steps[sent_id], - "segment": self.data["src"][sent_id][self.steps[sent_id]], - } - - self.steps[sent_id] += 1 - - return dict_to_return - - def src_lengths(self): - # +1 for eos - return [len(sent) + 1 for sent in self.data["src"]] diff --git a/examples/simultaneous_translation/eval/server.py b/examples/simultaneous_translation/eval/server.py deleted file mode 100644 index e44ceaff85..0000000000 --- a/examples/simultaneous_translation/eval/server.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. -import argparse -import json -import sys - -from scorers import build_scorer -from tornado import ioloop, web - - -DEFAULT_HOSTNAME = "localhost" -DEFAULT_PORT = 12321 - - -class ScorerHandler(web.RequestHandler): - def initialize(self, scorer): - self.scorer = scorer - - -class EvalSessionHandler(ScorerHandler): - def post(self): - self.scorer.reset() - - def get(self): - r = json.dumps(self.scorer.get_info()) - self.write(r) - - -class ResultHandler(ScorerHandler): - def get(self): - r = json.dumps(self.scorer.score()) - self.write(r) - - -class SourceHandler(ScorerHandler): - def get(self): - sent_id = int(self.get_argument("sent_id")) - segment_size = None - if "segment_size" in self.request.arguments: - string = self.get_argument("segment_size") - if len(string) > 0: - segment_size = int(string) - - r = json.dumps(self.scorer.send_src(int(sent_id), segment_size)) - - self.write(r) - - -class HypothesisHandler(ScorerHandler): - def put(self): - sent_id = int(self.get_argument("sent_id")) - list_of_tokens = self.request.body.decode("utf-8").strip().split() - self.scorer.recv_hyp(sent_id, list_of_tokens) - - -def add_args(): - parser = argparse.ArgumentParser() - # fmt: off - parser.add_argument('--hostname', type=str, default=DEFAULT_HOSTNAME, - help='Server hostname') - parser.add_argument('--port', type=int, default=DEFAULT_PORT, - help='Server port number') - - args, _ = parser.parse_known_args() - # fmt: on - return args - - -def start_server(scorer, hostname=DEFAULT_HOSTNAME, port=DEFAULT_PORT, debug=False): - app = web.Application( - [ - (r"/result", ResultHandler, dict(scorer=scorer)), - (r"/src", SourceHandler, dict(scorer=scorer)), - (r"/hypo", HypothesisHandler, dict(scorer=scorer)), - (r"/", EvalSessionHandler, dict(scorer=scorer)), - ], - debug=debug, - ) - app.listen(port, max_buffer_size=1024 ** 3) - sys.stdout.write(f"Evaluation Server Started. Listening to port {port}\n") - ioloop.IOLoop.current().start() - - -if __name__ == "__main__": - args = add_args() - scorer = build_scorer(args) - start_server(scorer, args.hostname, args.port, args.debug) diff --git a/examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py b/examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py deleted file mode 100644 index 45df5fa227..0000000000 --- a/examples/speech_to_text/simultaneous_translation/agents/simul_trans_agent.py +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import json -import os - -from fairseq import checkpoint_utils, utils, tasks - -from . import DEFAULT_EOS, GET, SEND -from .agent import Agent - - -class SimulTransAgent(Agent): - def __init__(self, args): - # Load Model - self.load_model(args) - - # build word spliter - self.build_word_splitter(args) - - self.max_len = args.max_len - - self.eos = DEFAULT_EOS - - @staticmethod - def add_args(parser): - parser.add_argument( - "--model-path", - type=str, - required=True, - help="path to your pretrained model.", - ) - parser.add_argument( - "--data-bin", type=str, required=True, help="Path of data binary" - ) - parser.add_argument( - "--user-dir", - type=str, - default="example/simultaneous_translation", - help="User directory for simultaneous translation", - ) - parser.add_argument( - "--src-splitter-type", - type=str, - default=None, - help="Subword splitter type for source text", - ) - parser.add_argument( - "--tgt-splitter-type", - type=str, - default=None, - help="Subword splitter type for target text", - ) - parser.add_argument( - "--src-splitter-path", - type=str, - default=None, - help="Subword splitter model path for source text", - ) - parser.add_argument( - "--tgt-splitter-path", - type=str, - default=None, - help="Subword splitter model path for target text", - ) - parser.add_argument( - "--max-len", - type=int, - default=150, - help="Maximum length difference between source and target prediction", - ) - parser.add_argument( - "--model-overrides", - default="{}", - type=str, - metavar="DICT", - help="A dictionary used to override model args at generation " - "that were used during model training", - ) - # fmt: on - return parser - - def load_dictionary(self, task): - raise NotImplementedError - - def load_model(self, args): - args.user_dir = os.path.join(os.path.dirname(__file__), "..", "..") - utils.import_user_module(args) - filename = args.model_path - if not os.path.exists(filename): - raise IOError("Model file not found: {}".format(filename)) - - state = checkpoint_utils.load_checkpoint_to_cpu( - filename, json.loads(args.model_overrides) - ) - - saved_args = state["args"] - saved_args.data = args.data_bin - - task = tasks.setup_task(saved_args) - - # build model for ensemble - self.model = task.build_model(saved_args) - self.model.load_state_dict(state["model"], strict=True) - - # Set dictionary - self.load_dictionary(task) - - def init_states(self): - return { - "indices": {"src": [], "tgt": []}, - "tokens": {"src": [], "tgt": []}, - "segments": {"src": [], "tgt": []}, - "steps": {"src": 0, "tgt": 0}, - "finished": False, - "finish_read": False, - "model_states": {}, - } - - def update_states(self, states, new_state): - raise NotImplementedError - - def policy(self, states): - # Read and Write policy - action = None - - while action is None: - if states["finished"]: - # Finish the hypo by sending eos to server - return self.finish_action() - - # Model make decision given current states - decision = self.model.decision_from_states(states) - - if decision == 0 and not self.finish_read(states): - # READ - action = self.read_action(states) - else: - # WRITE - action = self.write_action(states) - - # None means we make decision again but not sending server anything - # This happened when read a buffered token - # Or predict a subword - return action - - def finish_read(self, states): - raise NotImplementedError - - def write_action(self, states): - token, index = self.model.predict_from_states(states) - - if ( - index == self.dict["tgt"].eos() - or len(states["tokens"]["tgt"]) > self.max_len - ): - # Finish this sentence is predict EOS - states["finished"] = True - end_idx_last_full_word = self._target_length(states) - - else: - states["tokens"]["tgt"] += [token] - end_idx_last_full_word = self.word_splitter["tgt"].end_idx_last_full_word( - states["tokens"]["tgt"] - ) - self._append_indices(states, [index], "tgt") - - if end_idx_last_full_word > states["steps"]["tgt"]: - # Only sent detokenized full words to the server - word = self.word_splitter["tgt"].merge( - states["tokens"]["tgt"][states["steps"]["tgt"] : end_idx_last_full_word] - ) - states["steps"]["tgt"] = end_idx_last_full_word - states["segments"]["tgt"] += [word] - - return {"key": SEND, "value": word} - else: - return None - - def read_action(self, states): - return {"key": GET, "value": None} - - def finish_action(self): - return {"key": SEND, "value": DEFAULT_EOS} - - def reset(self): - pass - - def finish_eval(self, states, new_state): - if len(new_state) == 0 and len(states["indices"]["src"]) == 0: - return True - return False - - def _append_indices(self, states, new_indices, key): - states["indices"][key] += new_indices - - def _target_length(self, states): - return len(states["tokens"]["tgt"]) diff --git a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py index aa3dba31e2..051785238f 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py @@ -3,7 +3,6 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from examples.simultaneous_translation.utils.latency import LatencyTraining from fairseq.criterions import register_criterion from fairseq.criterions.label_smoothed_cross_entropy import ( LabelSmoothedCrossEntropyCriterion, @@ -31,6 +30,7 @@ def __init__( super().__init__( task, sentence_avg, label_smoothing, ignore_prefix_size, report_accuracy ) + from examples.simultaneous_translation.utils.latency import LatencyTraining self.eps = label_smoothing self.latency_weight_avg = latency_weight_avg self.latency_weight_avg_type = latency_weight_avg_type diff --git a/fairseq/tasks/simultaneous_translation.py b/fairseq/tasks/simultaneous_translation.py new file mode 100644 index 0000000000..11c7dc1ea9 --- /dev/null +++ b/fairseq/tasks/simultaneous_translation.py @@ -0,0 +1,42 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from fairseq.tasks import register_task +from fairseq.tasks.speech_to_text import SpeechToTextTask +from fairseq.tasks.translation import ( + TranslationTask, TranslationConfig +) + +try: + import examples.simultaneous_translation # noqa + import_successful = True +except BaseException: + import_successful = False + + +logger = logging.getLogger(__name__) + + +def check_import(flag): + if not flag: + raise ImportError( + "'examples.simultaneous_translation' is not correctly imported. " + "Please considering `pip install -e $FAIRSEQ_DIR`." + ) + + +@register_task("simul_speech_to_text") +class SimulSpeechToTextTask(SpeechToTextTask): + def __init__(self, args, tgt_dict): + check_import(import_successful) + super().__init__(args, tgt_dict) + + +@register_task("simul_text_to_text", dataclass=TranslationConfig) +class SimulTextToTextTask(TranslationTask): + def __init__(self, cfg, src_dict, tgt_dict): + check_import(import_successful) + super().__init__(cfg, src_dict, tgt_dict) From a20dc364647c94417f493ba0b0c8d1e1834e67eb Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Fri, 2 Apr 2021 14:44:20 -0700 Subject: [PATCH 298/774] Several updates on simul st (#1774) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1774 Reviewed By: jmp84 Differential Revision: D27529935 Pulled By: xutaima fbshipit-source-id: 35433cc1d862440ea110e084007ba187149bc193 --- .../docs/simulst_mustc_example.md | 24 ++++++--- examples/speech_to_text/seg_mustc_data.py | 54 +++++++++++++++++++ .../agents/fairseq_simul_st_agent.py | 2 +- 3 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 examples/speech_to_text/seg_mustc_data.py diff --git a/examples/speech_to_text/docs/simulst_mustc_example.md b/examples/speech_to_text/docs/simulst_mustc_example.md index d83ec086f9..52ca9ac062 100644 --- a/examples/speech_to_text/docs/simulst_mustc_example.md +++ b/examples/speech_to_text/docs/simulst_mustc_example.md @@ -114,6 +114,14 @@ Each line of target file `${TGT_FILE}` is the translation for each audio file in Translation_1 Translation_2 ``` +The evaluation runs on the original MUSTC segmentation. +The following command will generate the wav list and text file for a evaluation set `${SPLIT}` (chose from `dev`, `tst-COMMON` and `tst-HE`) in MUSTC to `${EVAL_DATA}`. +```bash +python ${FAIRSEQ}/examples/speech_to_text/seg_mustc_data.py \ + --data-root ${MUSTC_ROOT} --lang de \ + --split ${SPLIT} --task st \ + --output ${EVAL_DATA} +``` The `--data-bin` and `--config` should be the same in previous section if you prepare the data from the scratch. If only for evaluation, a prepared data directory can be found [here](https://dl.fbaipublicfiles.com/simultaneous_translation/must_c_v1.0_en_de_databin.tgz). It contains @@ -152,19 +160,19 @@ Notice that once a `--data-bin` is set, the `--config` is the base name of the c Set `--model-path` to the model checkpoint. A pretrained checkpoint can be downloaded from [here](https://dl.fbaipublicfiles.com/simultaneous_translation/convtransformer_wait5_pre7), which is a wait-5 model with a pre-decision of 280 ms. -The output should be similar as follow: +The result of this model on `tst-COMMON` is: ```bash { "Quality": { - "BLEU": 12.79214535384013 + "BLEU": 13.94974229366959 }, "Latency": { - "AL": 1669.5778120018108, - "AL_CA": 2077.9027656104813, - "AP": 0.7652936521983029, - "AP_CA": 0.8891561507382866, - "DAL": 2028.1566141735727, - "DAL_CA": 2497.336430059716 + "AL": 1751.8031870037803, + "AL_CA": 2338.5911762796536, + "AP": 0.7931395378788959, + "AP_CA": 0.9405103863210942, + "DAL": 1987.7811616943081, + "DAL_CA": 2425.2751560926167 } } ``` diff --git a/examples/speech_to_text/seg_mustc_data.py b/examples/speech_to_text/seg_mustc_data.py new file mode 100644 index 0000000000..1ee665d639 --- /dev/null +++ b/examples/speech_to_text/seg_mustc_data.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +from pathlib import Path +import soundfile as sf +from examples.speech_to_text.prep_mustc_data import ( + MUSTC +) + +from tqdm import tqdm + +log = logging.getLogger(__name__) + + +def main(args): + root = Path(args.data_root).absolute() + lang = args.lang + split = args.split + + cur_root = root / f"en-{lang}" + assert cur_root.is_dir(), ( + f"{cur_root.as_posix()} does not exist. Skipped." + ) + + dataset = MUSTC(root.as_posix(), lang, split) + output = Path(args.output).absolute() + output.mkdir(exist_ok=True) + f_text = open(output / f"{split}.{lang}", "w") + f_wav_list = open(output / f"{split}.wav_list", "w") + for waveform, sample_rate, _, text, _, utt_id in tqdm(dataset): + sf.write( + output / f"{utt_id}.wav", + waveform.squeeze(0).numpy(), + samplerate=int(sample_rate) + ) + f_text.write(text + "\n") + f_wav_list.write(str(output / f"{utt_id}.wav") + "\n") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--data-root", "-d", required=True, type=str) + parser.add_argument("--task", required=True, type=str, choices=["asr", "st"]) + parser.add_argument("--lang", required=True, type=str) + parser.add_argument("--output", required=True, type=str) + parser.add_argument("--split", required=True, choices=MUSTC.SPLITS) + args = parser.parse_args() + + main(args) diff --git a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py index 58e38963b5..61617a1739 100644 --- a/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py +++ b/examples/speech_to_text/simultaneous_translation/agents/fairseq_simul_st_agent.py @@ -334,7 +334,7 @@ def policy(self, states): torch.cuda.empty_cache() - if outputs["action"] == 0: + if outputs.action == 0: return READ_ACTION else: return WRITE_ACTION From aa5f0119a383e013e56ae5d88e4a7aff0e67f0f9 Mon Sep 17 00:00:00 2001 From: Jongsoo Park <jongsoo@fb.com> Date: Fri, 2 Apr 2021 19:51:12 -0700 Subject: [PATCH 299/774] remove import logging (#1779) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1779 Pull Request resolved: https://github.com/pytorch/fairseq/pull/3436 Remove residue of changes not meant to be landed in D26873232 (https://github.com/pytorch/fairseq/commit/edcef1306b48e7fa9bf84dcbec25171a1e57a5dc) Reviewed By: myleott Differential Revision: D27543742 fbshipit-source-id: ebe47baba27ec2446ef0b855d700b68373f738d8 --- fairseq/optim/cpu_adam.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py index 21336ef59b..e36bccf123 100644 --- a/fairseq/optim/cpu_adam.py +++ b/fairseq/optim/cpu_adam.py @@ -12,7 +12,6 @@ from fairseq.dataclass import FairseqDataclass from fairseq.optim import FairseqOptimizer, register_optimizer from omegaconf import II, DictConfig -import logging try: From 8a42c243a7835f1f0da06efd323ddf6201eb1272 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 7 Apr 2021 16:03:55 -0700 Subject: [PATCH 300/774] Fix memory regression when using FSDP (#1788) Summary: FSDP overloads nn.Module.apply and inserts a step where it all-gathers params before calling apply (added in https://github.com/facebookresearch/fairscale/commit/fa1b85fbbe75f058b39f1bcf027de42e6ddbd487). This is important for the typical use case of nn.Module.apply -- weight initialization. But here we were using apply totally unnecessarily. It's easier to just loop over all the modules and call set_num_updates directly Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1788 Reviewed By: sshleifer Differential Revision: D27622168 Pulled By: myleott fbshipit-source-id: f5462107ad251cf7834b20a0eaccbe2f685da8f8 --- fairseq/models/fairseq_model.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 171a8a40f1..e55c7ba1ad 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -153,13 +153,10 @@ def do_upgrade(m, prefix): def set_num_updates(self, num_updates): """State from trainer to pass along to model at every update.""" - - def _apply(m): + for m in self.modules(): if hasattr(m, "set_num_updates") and m != self: m.set_num_updates(num_updates) - self.apply(_apply) - def prepare_for_inference_(self, cfg: DictConfig): """Prepare model for inference.""" kwargs = {} From ee0d5a0f65a25e5f5372776402aac5cb9c4adbf1 Mon Sep 17 00:00:00 2001 From: Guillaume Wenzek <guw@fb.com> Date: Wed, 7 Apr 2021 19:57:12 -0700 Subject: [PATCH 301/774] fixup Obt 2 (#1614) (#1791) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: restore len() checking that was lost in a merge # Before submitting - [x] Was this discussed/approved via a Github issue? This is a fix for https://github.com/fairinternal/fairseq-py/issues/1614. The regression was identified in https://github.com/pytorch/fairseq/issues/3364 - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes regression in https://github.com/fairinternal/fairseq-py/pull/1614/files#diff-6e65327f729a8658d627b762ec14902e25927698f35e5495e6b8e3a1bfcfd7afR886-R943 This changes was meant to be a no-op but I forgot the len checking. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1791 Reviewed By: jmp84 Differential Revision: D27629177 Pulled By: gwenzek fbshipit-source-id: fe6fdd486b1a61f86547d1214180d7fd3042e51b --- fairseq/models/transformer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index eff5ba7b8f..29fdeb70bf 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -885,12 +885,13 @@ def extract_features_scriptable( enc: Optional[Tensor] = None padding_mask: Optional[Tensor] = None - if encoder_out is not None: + if encoder_out is not None and len(encoder_out["encoder_out"]) > 0: enc = encoder_out["encoder_out"][0] - padding_mask = encoder_out["encoder_padding_mask"][0] assert ( enc.size()[1] == bs ), f"Expected enc.shape == (t, {bs}, c) got {enc.shape}" + if encoder_out is not None and len(encoder_out["encoder_padding_mask"]) > 0: + padding_mask = encoder_out["encoder_padding_mask"][0] # embed positions positions = None From acf312418e4718996a103d67bd57516938137a7d Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Mon, 12 Apr 2021 09:26:40 -0700 Subject: [PATCH 302/774] 'Fix a bug when src len is smaller than wait k lagging (#1795) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1795 Reviewed By: jmp84 Differential Revision: D27701022 Pulled By: xutaima fbshipit-source-id: 2267402077fbc7c560e260f1ca730ba102d0c7cd --- .../modules/monotonic_multihead_attention.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index b487f14a98..71c818e5cc 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -930,6 +930,8 @@ def p_choose( max_src_len, bsz, _ = key.size() if max_src_len < self.waitk_lagging: + if incremental_state is not None: + tgt_len = 1 return query.new_zeros( bsz * self.num_heads, tgt_len, max_src_len ) From 57560cb52c3a86fadbf315e24bc4ec174056a444 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Wed, 14 Apr 2021 01:49:14 -0700 Subject: [PATCH 303/774] enable manifold checkpoints with --keep-interval-updates Summary: Useful to enable --keep-interval-updates with Manifold checkpoints Reviewed By: myleott Differential Revision: D27577116 fbshipit-source-id: 6d4ae5aaccc07ecaed8ba6a333b6ab78b148187a --- fairseq/checkpoint_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 7e1b8479d1..4e02883e57 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -120,6 +120,8 @@ def is_better(a, b): for old_chk in checkpoints[cfg.keep_interval_updates :]: if os.path.lexists(old_chk): os.remove(old_chk) + elif PathManager.exists(old_chk): + PathManager.rm(old_chk) if cfg.keep_last_epochs > 0: # remove old epoch checkpoints; checkpoints are sorted in descending order @@ -394,7 +396,7 @@ def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt"): descending order. """ pt_regexp = re.compile(pattern) - files = os.listdir(path) + files = PathManager.ls(path) entries = [] for i, f in enumerate(files): From dbfb7103bdc41cdaa9bfea4cf5dedd10c9750647 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Wed, 14 Apr 2021 01:49:14 -0700 Subject: [PATCH 304/774] add keep_interval_updates_pattern Summary: Motivation: I want to save checkpoints frequently, due to unreliable jobs in FB cluster that restart frequently. I want to do this without spamming Manifold storage, but still save some historical checkpoints (i.e. every 10k updates), so I can track how WER evolves over time. To save frequently, I can use a small --save-interval-updates. To delete old checkpoints to save storage, I can use --keep-interval-updates. However, this deletes all old checkpoints. This is where --keep-interval-updates-pattern comes in. If I now do: ``` --save-interval-updates 1000 --keep-interval-updates 1 --keep-interval-updates-pattern 10000 ``` This will: 1. checkpoint every 1000 updates so that job restarts don't impact us significantly 2. keep only the latest checkpoint to avoid saving a bunch of huge models in manifold 3. make an exception for #2 for every 10k updates so we can track WER over time Reviewed By: myleott Differential Revision: D27578403 fbshipit-source-id: 5aec2dc9a22778015f7a3daa017210190af81240 --- fairseq/checkpoint_utils.py | 20 +++++++++++++++----- fairseq/dataclass/configs.py | 8 ++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 4e02883e57..ac6c7339d4 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -114,9 +114,16 @@ def is_better(a, b): if not end_of_epoch and cfg.keep_interval_updates > 0: # remove old checkpoints; checkpoints are sorted in descending order - checkpoints = checkpoint_paths( - cfg.save_dir, pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix) - ) + if cfg.keep_interval_updates_pattern == -1: + checkpoints = checkpoint_paths( + cfg.save_dir, pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix) + ) + else: + checkpoints = checkpoint_paths( + cfg.save_dir, pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix), keep_match=True + ) + checkpoints = [x[0] for x in checkpoints if x[1] % cfg.keep_interval_updates_pattern != 0] + for old_chk in checkpoints[cfg.keep_interval_updates :]: if os.path.lexists(old_chk): os.remove(old_chk) @@ -388,7 +395,7 @@ def load_model_ensemble_and_task( return ensemble, cfg, task -def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt"): +def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt", keep_match=False): """Retrieves all checkpoints found in `path` directory. Checkpoints are identified by matching filename to the specified pattern. If @@ -404,7 +411,10 @@ def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt"): if m is not None: idx = float(m.group(1)) if len(m.groups()) > 0 else i entries.append((idx, m.group(0))) - return [os.path.join(path, x[1]) for x in sorted(entries, reverse=True)] + if keep_match: + return [(os.path.join(path, x[1]), x[0]) for x in sorted(entries, reverse=True)] + else: + return [os.path.join(path, x[1]) for x in sorted(entries, reverse=True)] def torch_persistent_save(obj, filename, async_write: bool = False): diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index be9f7c5af3..f1ca26514e 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -568,6 +568,14 @@ class CheckpointConfig(FairseqDataclass): "help": "keep the last N checkpoints saved with --save-interval-updates" }, ) + keep_interval_updates_pattern: int = field( + default=-1, + metadata={ + "help": "when used with --keep-interval-updates, skips deleting " + "any checkpoints with update X where " + "X % keep_interval_updates_pattern == 0" + }, + ) keep_last_epochs: int = field( default=-1, metadata={"help": "keep last N epoch checkpoints"} ) From 436166a00c2ecd1215df258f022608947cca2aa8 Mon Sep 17 00:00:00 2001 From: Guillaume Wenzek <guw@fb.com> Date: Wed, 14 Apr 2021 04:59:04 -0700 Subject: [PATCH 305/774] fix MultiHeadAttention assert (#1798) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/fairinternal/fairseq-py/issues/1538. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1798 Reviewed By: myleott Differential Revision: D27710902 Pulled By: gwenzek fbshipit-source-id: 2efdf645bb30e4cf6653c48371bfca8df6f94eaf --- fairseq/modules/multihead_attention.py | 7 ++- tests/test_transformer.py | 65 ++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 tests/test_transformer.py diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index d84c7e078d..b168a890ae 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -151,12 +151,11 @@ def forward( assert embed_dim == self.embed_dim assert list(query.size()) == [tgt_len, bsz, embed_dim] if key is not None: - src_len, key_bsz, key_embed_dim = key.size() + src_len, key_bsz, _ = key.size() if not torch.jit.is_scripting(): - assert (key_bsz, key_embed_dim) == (bsz, embed_dim) + assert key_bsz == bsz assert value is not None - assert (src_len, bsz, embed_dim) == value.shape - + assert src_len, bsz == value.shape[:2] if ( not self.onnx_trace diff --git a/tests/test_transformer.py b/tests/test_transformer.py new file mode 100644 index 0000000000..de5c5bdbd4 --- /dev/null +++ b/tests/test_transformer.py @@ -0,0 +1,65 @@ +import argparse +import unittest +from typing import Any, Dict, Sequence + +import torch +from fairseq.models import transformer + +from tests.test_roberta import FakeTask + + +def mk_sample(tok: Sequence[int] = None, batch_size: int = 2) -> Dict[str, Any]: + if not tok: + tok = [10, 11, 12, 13, 14, 15, 2] + + batch = torch.stack([torch.tensor(tok, dtype=torch.long)] * batch_size) + sample = { + "net_input": { + "src_tokens": batch, + "prev_output_tokens": batch, + "src_lengths": torch.tensor( + [len(tok)] * batch_size, dtype=torch.long, device=batch.device + ), + }, + "target": batch[:, 1:], + } + return sample + + +def mk_transformer(**extra_args: Any): + overrides = { + # Use characteristics dimensions + "encoder_embed_dim": 12, + "encoder_ffn_embed_dim": 14, + "decoder_embed_dim": 12, + "decoder_ffn_embed_dim": 14, + # Disable dropout so we have comparable tests. + "dropout": 0, + "attention_dropout": 0, + "activation_dropout": 0, + "encoder_layerdrop": 0, + } + overrides.update(extra_args) + # Overrides the defaults from the parser + args = argparse.Namespace(**overrides) + transformer.tiny_architecture(args) + + torch.manual_seed(0) + task = FakeTask(args) + return transformer.TransformerModel.build_model(args, task) + + +class TransformerTestCase(unittest.TestCase): + def test_forward_backward(self): + model = mk_transformer(encoder_embed_dim=12, decoder_embed_dim=12) + sample = mk_sample() + o, _ = model.forward(**sample["net_input"]) + loss = o.sum() + loss.backward() + + def test_different_encoder_decoder_embed_dim(self): + model = mk_transformer(encoder_embed_dim=12, decoder_embed_dim=16) + sample = mk_sample() + o, _ = model.forward(**sample["net_input"]) + loss = o.sum() + loss.backward() From fc90910314ce02fe168bdbe127e08a14e944a6fd Mon Sep 17 00:00:00 2001 From: Sujit Verma <sujitv@fb.com> Date: Wed, 14 Apr 2021 21:53:25 -0700 Subject: [PATCH 306/774] Migrating fairseq-py from fvcore to iopath. Summary: Migrating fairseq-py from fvcore to iopath. Reviewed By: myleott Differential Revision: D27109864 fbshipit-source-id: 041177c1bc9b5793b2ce0ecab87692097f3f353b --- fairseq/file_io.py | 68 +++++++++++++++++++++---------------------- tests/test_file_io.py | 10 +++---- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/fairseq/file_io.py b/fairseq/file_io.py index 9a78ab505d..93c931093c 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -15,13 +15,13 @@ try: - from fvcore.common.file_io import PathManager as FVCorePathManager + from iopath.common.file_io import g_pathmgr as IOPathManager try: # [FB only - for now] AWS PathHandler for PathManager from .fb_pathhandlers import S3PathHandler - FVCorePathManager.register_handler(S3PathHandler()) + IOPathManager.register_handler(S3PathHandler()) except KeyError: logging.warning("S3PathHandler already registered.") except ImportError: @@ -30,15 +30,15 @@ ) except ImportError: - FVCorePathManager = None + IOPathManager = None -IOPathPathManager = None +IOPathManager = None class PathManager: """ Wrapper for insulating OSS I/O (using Python builtin operations) from - fvcore's PathManager abstraction (for transparently handling various + iopath's PathManager abstraction (for transparently handling various internal backends). """ @@ -51,8 +51,8 @@ def open( errors: Optional[str] = None, newline: Optional[str] = None, ): - if FVCorePathManager: - return FVCorePathManager.open( + if IOPathManager: + return IOPathManager.open( path=path, mode=mode, buffering=buffering, @@ -71,46 +71,46 @@ def open( @staticmethod def copy(src_path: str, dst_path: str, overwrite: bool = False) -> bool: - if FVCorePathManager: - return FVCorePathManager.copy( + if IOPathManager: + return IOPathManager.copy( src_path=src_path, dst_path=dst_path, overwrite=overwrite ) return shutil.copyfile(src_path, dst_path) @staticmethod def get_local_path(path: str, **kwargs) -> str: - if FVCorePathManager: - return FVCorePathManager.get_local_path(path, **kwargs) + if IOPathManager: + return IOPathManager.get_local_path(path, **kwargs) return path @staticmethod def exists(path: str) -> bool: - if FVCorePathManager: - return FVCorePathManager.exists(path) + if IOPathManager: + return IOPathManager.exists(path) return os.path.exists(path) @staticmethod def isfile(path: str) -> bool: - if FVCorePathManager: - return FVCorePathManager.isfile(path) + if IOPathManager: + return IOPathManager.isfile(path) return os.path.isfile(path) @staticmethod def ls(path: str) -> List[str]: - if FVCorePathManager: - return FVCorePathManager.ls(path) + if IOPathManager: + return IOPathManager.ls(path) return os.listdir(path) @staticmethod def mkdirs(path: str) -> None: - if FVCorePathManager: - return FVCorePathManager.mkdirs(path) + if IOPathManager: + return IOPathManager.mkdirs(path) os.makedirs(path, exist_ok=True) @staticmethod def rm(path: str) -> None: - if FVCorePathManager: - return FVCorePathManager.rm(path) + if IOPathManager: + return IOPathManager.rm(path) os.remove(path) @staticmethod @@ -120,15 +120,15 @@ def chmod(path: str, mode: int) -> None: @staticmethod def register_handler(handler) -> None: - if FVCorePathManager: - return FVCorePathManager.register_handler(handler=handler) + if IOPathManager: + return IOPathManager.register_handler(handler=handler) @staticmethod def copy_from_local( local_path: str, dst_path: str, overwrite: bool = False, **kwargs ) -> None: - if FVCorePathManager: - return FVCorePathManager.copy_from_local( + if IOPathManager: + return IOPathManager.copy_from_local( local_path=local_path, dst_path=dst_path, overwrite=overwrite, **kwargs ) return shutil.copyfile(local_path, dst_path) @@ -136,8 +136,8 @@ def copy_from_local( @staticmethod def path_requires_pathmanager(path: str) -> bool: """Do we require PathManager to access given path?""" - if FVCorePathManager: - for p in FVCorePathManager._path_handlers.keys(): + if IOPathManager: + for p in IOPathManager._path_handlers.keys(): if path.startswith(p): return True return False @@ -166,15 +166,15 @@ def opena( """ Return file descriptor with asynchronous write operations. """ - global IOPathPathManager - if not IOPathPathManager: + global IOPathManager + if not IOPathManager: logging.info("ioPath is initializing PathManager.") try: from iopath.common.file_io import PathManager - IOPathPathManager = PathManager() + IOPathManager = PathManager() except Exception: logging.exception("Failed to initialize ioPath PathManager object.") - return IOPathPathManager.opena( + return IOPathManager.opena( path=path, mode=mode, buffering=buffering, @@ -190,7 +190,7 @@ def async_close() -> bool: NOTE: `PathManager.async_close()` must be called at the end of any script that uses `PathManager.opena(...)`. """ - global IOPathPathManager - if IOPathPathManager: - return IOPathPathManager.async_close() + global IOPathManager + if IOPathManager: + return IOPathManager.async_close() return False diff --git a/tests/test_file_io.py b/tests/test_file_io.py index 8ebbba4a2e..f39e2e1d58 100644 --- a/tests/test_file_io.py +++ b/tests/test_file_io.py @@ -38,8 +38,8 @@ def test_file_io(self): self.assertEqual(s, self._tmpfile_contents) def test_file_io_oss(self): - # Mock fvcore to simulate oss environment. - sys.modules["fvcore"] = MagicMock() + # Mock iopath to simulate oss environment. + sys.modules["iopath"] = MagicMock() from fairseq.file_io import PathManager with PathManager.open(os.path.join(self._tmpdir, "test.txt"), "r") as f: @@ -49,14 +49,12 @@ def test_file_io_oss(self): def test_file_io_async(self): # ioPath `PathManager` is initialized after the first `opena` call. try: - from fairseq.file_io import IOPathPathManager, PathManager + from fairseq.file_io import IOPathManager, PathManager - self.assertIsNone(IOPathPathManager) + self.assertIsNone(IOPathManager) _asyncfile = os.path.join(self._tmpdir, "async.txt") f = PathManager.opena(_asyncfile, "wb") f.close() - from fairseq.file_io import IOPathPathManager - self.assertIsNotNone(IOPathPathManager) finally: self.assertTrue(PathManager.async_close()) From 069763813097aa814c8c4e12d4cab4b321575b8d Mon Sep 17 00:00:00 2001 From: Sujit Verma <sujitv@fb.com> Date: Thu, 15 Apr 2021 16:59:08 -0700 Subject: [PATCH 307/774] Fix bug from iopath migration. Summary: Fix bug from iopath migration. Reviewed By: myleott, shuliuncsu Differential Revision: D27808039 fbshipit-source-id: 14b6c9ca3a461b00c2528d55b7269980324b3e10 --- fairseq/file_io.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/fairseq/file_io.py b/fairseq/file_io.py index 93c931093c..dba663d4aa 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -32,8 +32,6 @@ except ImportError: IOPathManager = None -IOPathManager = None - class PathManager: """ From 3a90a859d4dfdbf13f15399be12a1928aa2c54ff Mon Sep 17 00:00:00 2001 From: Shu Liu <shuliu@fb.com> Date: Fri, 16 Apr 2021 15:11:19 -0700 Subject: [PATCH 308/774] Add manifold support for fairseq file_io Summary: Recently fairseq file_io migrated to iopath in D27109864 (https://github.com/pytorch/fairseq/commit/fc90910314ce02fe168bdbe127e08a14e944a6fd). New IOPathManager doesn't have manifold support by default. Add manifold handler to fix the issue. Reviewed By: myleott Differential Revision: D27809504 fbshipit-source-id: 5cbf4440ed734132f865096c45cd3e47ccb6142d --- fairseq/file_io.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fairseq/file_io.py b/fairseq/file_io.py index dba663d4aa..6266e6a1d8 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -29,6 +29,14 @@ "S3PathHandler couldn't be imported. Either missing fb-only files, or boto3 module." ) + try: + # [FB only] Add extra FB only PathHandlers for PathManager + import fairseq.fb_file_io as fb_file_io + + fb_file_io.update_path_manager(IOPathManager) + except ImportError: + pass + except ImportError: IOPathManager = None From 89371294e54ef8c306f19733f2e8bab8233c401e Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Sat, 17 Apr 2021 02:02:52 -0700 Subject: [PATCH 309/774] TALNet: Consistency loss Summary: During training, for each batch, apply two different data augmentations, and require the model output to be similar. The dissimilarity between the output is used as an extra loss term. To apply two different augmentations to the same batch, we need to create batches containing two copies of the same indices, like [a, b, c, a, b, c]. I make this the responsibility of the **batch sampler**. TALNet uses a `DataBalancingEpochBatchIterator` to generate batches. This iterator creates a `_batch_sampler` within itself; this diff adds a `dups` argument to generate duplicate indices. If you're using the generic `EpochBatchIterator`, which accepts a batch sampler directly as input, you will need to modify the code of your own batch sampler to generate duplicate indices. This is actually quite easy: if `batch_sampler(n)` creates a generator that returns n indices at a time, then `(batch * 2 for batch in batch_sampler(n // 2))` creates a generator that returns two copies of n/2 indices at a time. The consistency loss is implemented by the `consistency_loss` function. To use it, call it in your model's `forward` method and put the result in the return dict. Then expose the loss in the `get_losses` or `get_extra_losses` method of your model, so criterion objects can read them. Two types of consistency losses are provided: 1. KL divergence; 2. Squared difference of the probabilities. I've observed significant gains in TALNet's MAP with both types; KL divergence is slightly better. Reviewed By: nayansinghal Differential Revision: D27179650 fbshipit-source-id: 76899335b029fab67bbd7941429c9bd1baf52d65 --- fairseq/criterions/wav2vec_criterion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index f682508cb1..521d0cf1ad 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -13,6 +13,7 @@ from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.logging.meters import safe_round +from fairseq.utils import is_xla_tensor @dataclass @@ -31,7 +32,6 @@ class Wav2VecCriterionConfig(FairseqDataclass): default_factory=lambda: [], metadata={"help": "output keys to log"}, ) -from fairseq.utils import index_put, is_xla_tensor @register_criterion("wav2vec", dataclass=Wav2VecCriterionConfig) class Wav2vecCriterion(FairseqCriterion): From 3dd3940dc6105c8bf50f3a1be810cc035d2f105d Mon Sep 17 00:00:00 2001 From: Ning Dong <dnn@fb.com> Date: Mon, 19 Apr 2021 03:50:13 -0700 Subject: [PATCH 310/774] Support more p_choose strategies in FixedStrideMonotonicAttention Summary: Earlier polymorphism worked in the class by inheritance (calling into super().p_choose) however super() is not TS friendly. This diff moves p_choose() methods to a separate util file and uses a variable to toggle between different strategies. Reviewed By: jmp84, sravyapopuri388 Differential Revision: D27827168 fbshipit-source-id: 3e85028796e3af0c02f1d77b93a2a3896825b9b1 --- .../modules/fixed_pre_decision.py | 33 ++++- .../modules/monotonic_multihead_attention.py | 109 +-------------- .../utils/p_choose_strategy.py | 124 ++++++++++++++++++ 3 files changed, 154 insertions(+), 112 deletions(-) create mode 100644 examples/simultaneous_translation/utils/p_choose_strategy.py diff --git a/examples/simultaneous_translation/modules/fixed_pre_decision.py b/examples/simultaneous_translation/modules/fixed_pre_decision.py index 0e9dfb6dfd..dd29c031b3 100644 --- a/examples/simultaneous_translation/modules/fixed_pre_decision.py +++ b/examples/simultaneous_translation/modules/fixed_pre_decision.py @@ -12,11 +12,16 @@ MonotonicMultiheadAttentionInfiniteLookback, ) from typing import Dict, Optional +from examples.simultaneous_translation.utils import p_choose_strategy def fixed_pooling_monotonic_attention(monotonic_attention): def create_model(monotonic_attention, klass): class FixedStrideMonotonicAttention(monotonic_attention): def __init__(self, args): + self.waitk_lagging = 0 + self.num_heads = 0 + self.noise_mean = 0.0 + self.noise_var = 0.0 super().__init__(args) self.pre_decision_type = args.fixed_pre_decision_type self.pre_decision_ratio = args.fixed_pre_decision_ratio @@ -24,6 +29,8 @@ def __init__(self, args): if self.pre_decision_ratio == 1: return + self.strategy = args.simul_type + if args.fixed_pre_decision_type == "average": self.pooling_layer = torch.nn.AvgPool1d( kernel_size=self.pre_decision_ratio, @@ -143,12 +150,26 @@ def p_choose( batch_size = query.size(1) if self.pre_decision_ratio == 1: - return self.p_choose_waitk( - query, - key, - key_padding_mask, - incremental_state=incremental_state, - ) + if self.strategy == "waitk": + return p_choose_strategy.waitk( + query, + key, + self.waitk_lagging, + self.num_heads, + key_padding_mask, + incremental_state=incremental_state, + ) + else: # hard_aligned or infinite_lookback + q_proj, k_proj, _ = self.input_projections(query, key, None, "monotonic") + attn_energy = self.attn_energy(q_proj, k_proj, key_padding_mask) + return p_choose_strategy.hard_aligned( + q_proj, + k_proj, + attn_energy, + self.noise_mean, + self.noise_var, + self.training + ) key_pool = self.pooling_layer(key.transpose(0, 2)).transpose(0, 2) diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index 71c818e5cc..f49b1daa2f 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -19,6 +19,7 @@ from . import register_monotonic_attention from typing import Dict, Optional +from examples.simultaneous_translation.utils import p_choose_strategy @with_incremental_state class MonotonicAttention(nn.Module): @@ -767,21 +768,7 @@ def p_choose( # attention energy attn_energy = self.attn_energy(q_proj, k_proj, key_padding_mask) - noise = 0 - - if self.training: - # add noise here to encourage discretness - noise = ( - torch.normal(self.noise_mean, self.noise_var, attn_energy.size()) - .type_as(attn_energy) - .to(attn_energy.device) - ) - - p_choose = torch.sigmoid(attn_energy + noise) - _, _, tgt_len, src_len = p_choose.size() - - # p_choose: bsz * self.num_heads, tgt_len, src_len - return p_choose.view(-1, tgt_len, src_len) + return p_choose_strategy.hard_aligned(q_proj, k_proj, attn_energy, self.noise_mean, self.noise_var, self.training) def expected_attention(self, alpha, *args): """ @@ -920,94 +907,4 @@ def p_choose( key: bsz, src_len key_padding_mask: bsz, src_len """ - if incremental_state is not None: - # Retrieve target length from incremental states - # For inference the length of query is always 1 - tgt_len = int(incremental_state["steps"]["tgt"]) - else: - tgt_len, bsz, _ = query.size() - - max_src_len, bsz, _ = key.size() - - if max_src_len < self.waitk_lagging: - if incremental_state is not None: - tgt_len = 1 - return query.new_zeros( - bsz * self.num_heads, tgt_len, max_src_len - ) - - # Assuming the p_choose looks like this for wait k=3 - # src_len = 6, tgt_len = 5 - # [0, 0, 1, 0, 0, 0, 0] - # [0, 0, 0, 1, 0, 0, 0] - # [0, 0, 0, 0, 1, 0, 0] - # [0, 0, 0, 0, 0, 1, 0] - # [0, 0, 0, 0, 0, 0, 1] - # linearize the p_choose matrix: - # [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0...] - # The indices of linearized matrix that equals 1 is - # 2 + 6 * 0 - # 3 + 6 * 1 - # ... - # n + src_len * n + k - 1 = n * (src_len + 1) + k - 1 - # n from 0 to tgt_len - 1 - # - # First, generate the indices (activate_indices_offset: bsz, tgt_len) - # Second, scatter a zeros tensor (bsz, tgt_len * src_len) - # with activate_indices_offset - # Third, resize the tensor to (bsz, tgt_len, src_len) - - activate_indices_offset = ( - ( - torch.arange(tgt_len) * (max_src_len + 1) - + self.waitk_lagging - 1 - ) - .unsqueeze(0) - .expand(bsz, tgt_len) - .to(query) - .long() - ) - - if key_padding_mask is not None: - if key_padding_mask[:, 0].any(): - # Left padding - activate_indices_offset += ( - key_padding_mask.sum(dim=1, keepdim=True) - ) - - # Need to clamp the indices that are too large - activate_indices_offset = ( - activate_indices_offset - .clamp( - 0, - min( - [ - tgt_len, - max_src_len - self.waitk_lagging + 1 - ] - ) * max_src_len - 1 - ) - ) - - p_choose = torch.zeros(bsz, tgt_len * max_src_len).to(query) - - p_choose = p_choose.scatter( - 1, - activate_indices_offset, - 1.0 - ).view(bsz, tgt_len, max_src_len) - - if incremental_state is not None: - p_choose = p_choose[:, -1:] - tgt_len = 1 - - # Extend to each head - p_choose = ( - p_choose.contiguous() - .unsqueeze(1) - .expand(-1, self.num_heads, -1, -1) - .contiguous() - .view(-1, tgt_len, max_src_len) - ) - - return p_choose + return p_choose_strategy.waitk(query, key, self.waitk_lagging, self.num_heads, key_padding_mask, incremental_state) diff --git a/examples/simultaneous_translation/utils/p_choose_strategy.py b/examples/simultaneous_translation/utils/p_choose_strategy.py new file mode 100644 index 0000000000..308227ed96 --- /dev/null +++ b/examples/simultaneous_translation/utils/p_choose_strategy.py @@ -0,0 +1,124 @@ +from typing import Optional, Dict +from torch import Tensor +import torch + + +def waitk( + query, key, waitk_lagging: int, num_heads: int, key_padding_mask: Optional[Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None +): + if incremental_state is not None: + # Retrieve target length from incremental states + # For inference the length of query is always 1 + tgt_len = incremental_state["steps"]["tgt"] + assert tgt_len is not None + tgt_len = int(tgt_len) + else: + tgt_len, bsz, _ = query.size() + + max_src_len, bsz, _ = key.size() + + if max_src_len < waitk_lagging: + if incremental_state is not None: + tgt_len = 1 + return query.new_zeros( + bsz * num_heads, tgt_len, max_src_len + ) + + # Assuming the p_choose looks like this for wait k=3 + # src_len = 6, tgt_len = 5 + # [0, 0, 1, 0, 0, 0, 0] + # [0, 0, 0, 1, 0, 0, 0] + # [0, 0, 0, 0, 1, 0, 0] + # [0, 0, 0, 0, 0, 1, 0] + # [0, 0, 0, 0, 0, 0, 1] + # linearize the p_choose matrix: + # [0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0...] + # The indices of linearized matrix that equals 1 is + # 2 + 6 * 0 + # 3 + 6 * 1 + # ... + # n + src_len * n + k - 1 = n * (src_len + 1) + k - 1 + # n from 0 to tgt_len - 1 + # + # First, generate the indices (activate_indices_offset: bsz, tgt_len) + # Second, scatter a zeros tensor (bsz, tgt_len * src_len) + # with activate_indices_offset + # Third, resize the tensor to (bsz, tgt_len, src_len) + + activate_indices_offset = ( + ( + torch.arange(tgt_len) * (max_src_len + 1) + + waitk_lagging - 1 + ) + .unsqueeze(0) + .expand(bsz, tgt_len) + .to(query) + .long() + ) + + if key_padding_mask is not None: + if key_padding_mask[:, 0].any(): + # Left padding + activate_indices_offset += ( + key_padding_mask.sum(dim=1, keepdim=True) + ) + + # Need to clamp the indices that are too large + activate_indices_offset = ( + activate_indices_offset + .clamp( + 0, + min( + [ + tgt_len, + max_src_len - waitk_lagging + 1 + ] + ) * max_src_len - 1 + ) + ) + + p_choose = torch.zeros(bsz, tgt_len * max_src_len).to(query) + + p_choose = p_choose.scatter( + 1, + activate_indices_offset, + 1.0 + ).view(bsz, tgt_len, max_src_len) + + if incremental_state is not None: + p_choose = p_choose[:, -1:] + tgt_len = 1 + + # Extend to each head + p_choose = ( + p_choose.contiguous() + .unsqueeze(1) + .expand(-1, num_heads, -1, -1) + .contiguous() + .view(-1, tgt_len, max_src_len) + ) + + return p_choose + + +def hard_aligned(q_proj: Optional[Tensor], k_proj: Optional[Tensor], attn_energy, noise_mean: float = 0.0, noise_var: float = 0.0, training: bool = True): + """ + Calculating step wise prob for reading and writing + 1 to read, 0 to write + """ + + noise = 0 + if training: + # add noise here to encourage discretness + noise = ( + torch.normal(noise_mean, noise_var, attn_energy.size()) + .type_as(attn_energy) + .to(attn_energy.device) + ) + + p_choose = torch.sigmoid(attn_energy + noise) + _, _, tgt_len, src_len = p_choose.size() + + # p_choose: bsz * self.num_heads, tgt_len, src_len + return p_choose.view(-1, tgt_len, src_len) From 4fc9f2be952d8f0cd476832911dc71f59b4079da Mon Sep 17 00:00:00 2001 From: Robin Jia <robinjia@fb.com> Date: Mon, 19 Apr 2021 15:51:59 -0700 Subject: [PATCH 311/774] Fix order issue in batched BART generation (#1785) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1785 Reviewed By: robinjia Differential Revision: D27831673 Pulled By: sshleifer fbshipit-source-id: 1acf142151853d24138889c956df4531dae794a2 --- fairseq/models/bart/hub_interface.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fairseq/models/bart/hub_interface.py b/fairseq/models/bart/hub_interface.py index 2ddeb763a3..9afe385b9d 100644 --- a/fairseq/models/bart/hub_interface.py +++ b/fairseq/models/bart/hub_interface.py @@ -111,7 +111,9 @@ def generate( skip_invalid_size_inputs=skip_invalid_size_inputs, **kwargs ) - res.extend(results) + for id, hypos in zip(batch['id'].tolist(), results): + res.append((id, hypos)) + res = [hypos for _, hypos in sorted(res, key=lambda x: x[0])] return res def extract_features( From f6f220e917a0745bad5cc2dffdb35590f5feed8e Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Mon, 19 Apr 2021 16:30:32 -0700 Subject: [PATCH 312/774] Delete line that breaks gh ci (#1814) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1814 Reviewed By: myleott Differential Revision: D27867552 Pulled By: sshleifer fbshipit-source-id: ed30e02c962b31797e003cb810c085934a53202c --- tests/test_file_io.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_file_io.py b/tests/test_file_io.py index f39e2e1d58..425812bf16 100644 --- a/tests/test_file_io.py +++ b/tests/test_file_io.py @@ -50,8 +50,6 @@ def test_file_io_async(self): # ioPath `PathManager` is initialized after the first `opena` call. try: from fairseq.file_io import IOPathManager, PathManager - - self.assertIsNone(IOPathManager) _asyncfile = os.path.join(self._tmpdir, "async.txt") f = PathManager.opena(_asyncfile, "wb") f.close() From 801a64683164680562c77b688d9ca77fc3e0cea7 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Tue, 20 Apr 2021 12:17:11 -0700 Subject: [PATCH 313/774] allow subclasses of multi corpus dataset to not specify full_id Summary: This diff allow subclasses of multi corpus dataset to not specify full_id, which is only a useful feature for sampling batches between datasets. This is not possible for certain cases, such as minibatch CE training. Reviewed By: zdavid1995 Differential Revision: D27833104 fbshipit-source-id: e60f6ad200c0ca69915b9588405320ba2ecfbd0a --- fairseq/data/multi_corpus_dataset.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index 00e464ed31..acb91f3df6 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -165,9 +165,12 @@ def collater(self, samples): """ if len(samples) == 0: return None - _, key = self._map_index(samples[0]["full_id"]) - - return self.datasets[key].collater(samples) + if "full_id" in samples[0]: + _, key = self._map_index(samples[0]["full_id"]) + return self.datasets[key].collater(samples) + else: + # Subclasses may override __getitem__ to not specify full_id + return list(self.datasets.values())[0].collater(samples) def num_tokens(self, index: int): index, key = self._map_index(index) From da0432a3cd1ddf8f9797af83880570822265620b Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 21 Apr 2021 06:38:03 -0700 Subject: [PATCH 314/774] MultiGPU test and --log-file workaround (#1793) Summary: The initial problem I set out to solve was that it's not easy to add a multigpu test. I solved that problem but it ruined log capturing, both with `self.assertLogs` and `with contextlib.redirect_stdout(StringIO())`. After some brief digging, I gave up on trying to get those to work, and added support for `--log-file AGI_v0.log` which will write the `progress_bar.log()` statements to `log-file` as well as `stdout`. This functionality is used by the resumption test. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1793 Reviewed By: myleott Differential Revision: D27671192 Pulled By: sshleifer fbshipit-source-id: bcba5f9df7a965889a4cd6993f7eeb0f14b770c6 --- fairseq/dataclass/configs.py | 3 ++ fairseq/logging/progress_bar.py | 15 ++++-- fairseq_cli/train.py | 5 ++ tests/gpu/test_binaries_gpu.py | 90 ++++++++++++++++++++++++++++----- tests/test_binaries.py | 68 +------------------------ tests/test_plasma_utils.py | 5 +- tests/utils.py | 81 ++++++++++++++++++++++++++--- 7 files changed, 175 insertions(+), 92 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index f1ca26514e..89d83b5b6b 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -95,6 +95,9 @@ class CommonConfig(FairseqDataclass): log_format: Optional[LOG_FORMAT_CHOICES] = field( default=None, metadata={"help": "log format to use"} ) + log_file: Optional[str] = field( + default=None, metadata={"help": "log file to copy metrics to."} + ) tensorboard_logdir: Optional[str] = field( default=None, metadata={ diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index 0ae2bc006d..061082caef 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -29,6 +29,7 @@ def progress_bar( iterator, log_format: Optional[str] = None, log_interval: int = 100, + log_file: Optional[str] = None, epoch: Optional[int] = None, prefix: Optional[str] = None, tensorboard_logdir: Optional[str] = None, @@ -39,6 +40,10 @@ def progress_bar( ): if log_format is None: log_format = default_log_format + if log_file is not None: + handler = logging.FileHandler(filename=log_file) + logger.addHandler(handler) + if log_format == "tqdm" and not sys.stderr.isatty(): log_format = "simple" @@ -473,13 +478,13 @@ def _log_to_azureml(self, stats, tag=None, step=None): if Run is None: return if step is None: - step = stats['num_updates'] + step = stats["num_updates"] - prefix = '' if tag is None else tag + '/' + prefix = "" if tag is None else tag + "/" - for key in stats.keys() - {'num_updates'}: + for key in stats.keys() - {"num_updates"}: name = prefix + key if isinstance(stats[key], AverageMeter): - self.run.log_row(name=name, **{'step': step, key: stats[key].val}) + self.run.log_row(name=name, **{"step": step, key: stats[key].val}) elif isinstance(stats[key], Number): - self.run.log_row(name=name, **{'step': step, key: stats[key]}) + self.run.log_row(name=name, **{"step": step, key: stats[key]}) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index f736e67d0d..c1f2fbb4c7 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -59,6 +59,10 @@ def main(cfg: FairseqConfig) -> None: ), "Must specify batch size either with --max-tokens or --batch-size" metrics.reset() + if cfg.common.log_file is not None: + handler = logging.FileHandler(filename=cfg.common.log_file) + logger.addHandler(handler) + np.random.seed(cfg.common.seed) utils.set_torch_seed(cfg.common.seed) @@ -242,6 +246,7 @@ def train( progress = progress_bar.progress_bar( itr, log_format=cfg.common.log_format, + log_file=cfg.common.log_file, log_interval=cfg.common.log_interval, epoch=epoch_itr.epoch, tensorboard_logdir=( diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 5690e73752..5f879a7a27 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -5,6 +5,7 @@ import contextlib import logging +import json import os import tempfile import unittest @@ -22,6 +23,7 @@ ) +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") class TestTranslationGPU(unittest.TestCase): def setUp(self): logging.disable(logging.CRITICAL) @@ -29,16 +31,80 @@ def setUp(self): def tearDown(self): logging.disable(logging.NOTSET) - @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") - def test_fp16(self): + def test_fp16_multigpu(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_fp16") as data_dir: + log = os.path.join(data_dir, "train.log") create_dummy_data(data_dir) preprocess_translation_data(data_dir) - train_translation_model(data_dir, "fconv_iwslt_de_en", ["--fp16"]) + train_translation_model( + data_dir, + "fconv_iwslt_de_en", + ["--fp16", "--log-file", log], + world_size=min(torch.cuda.device_count(), 2), + ) generate_main(data_dir) + assert os.path.exists(log) + + @staticmethod + def parse_logs(logfile): + logs = [] + for ln in open(logfile, "r").readlines(): + try: + logs.append(json.loads(ln)) + except json.JSONDecodeError: + continue + return logs + + def test_resume_training(self): + flags = [ + "--fp16", + "--log-format", + "json", + "--max-update", + "10", + "--save-interval-updates", + "2", + "--log-interval", + "1", + "--log-file", + ] + world_size = min(torch.cuda.device_count(), 2) + arch = "fconv_iwslt_de_en" + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_fp16") as data_dir: + log = os.path.join(data_dir, "train.log") + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + train_translation_model( + data_dir, arch, flags + [log], world_size=world_size, + ) + log2 = os.path.join(data_dir, "resume.log") + restore_file = os.path.join(data_dir, "checkpoint_1_2.pt") + assert os.path.exists( + restore_file + ), f"{restore_file} not written. Choices: {os.listdir(data_dir)}" + train_translation_model( + data_dir, + arch, + flags + [log2, "--restore-file", restore_file], + world_size=world_size, + ) + + l1 = self.parse_logs(log) + l2 = self.parse_logs(log2) + assert int(l2[0]["num_updates"]) == 3, f"{l1}\n\n {l2}" + for k in [ + "train_loss", + "train_num_updates", + "train_ppl", + "train_gnorm", + ]: + from_scratch, resumed = l1[-1][k], l2[-1][k] + assert ( + from_scratch == resumed + ), f"difference at {k} {from_scratch} != {resumed}" - @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") def test_memory_efficient_fp16(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_memory_efficient_fp16") as data_dir: @@ -49,7 +115,6 @@ def test_memory_efficient_fp16(self): ) generate_main(data_dir) - @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") def test_transformer_fp16(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_transformer") as data_dir: @@ -73,7 +138,6 @@ def test_transformer_fp16(self): ) generate_main(data_dir) - @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") def test_levenshtein_transformer(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory( @@ -108,10 +172,12 @@ def test_levenshtein_transformer(self): generate_main( data_dir, gen_config, - path=os.pathsep.join([ - os.path.join(data_dir, "checkpoint_last.pt"), - os.path.join(data_dir, "checkpoint_last.pt"), - ]), + path=os.pathsep.join( + [ + os.path.join(data_dir, "checkpoint_last.pt"), + os.path.join(data_dir, "checkpoint_last.pt"), + ] + ), ) @@ -237,6 +303,7 @@ def _quantize_language_model(data_dir, arch, extra_flags=None, run_validation=Fa train.main(quantize_args) +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") class TestQuantization(unittest.TestCase): def setUp(self): logging.disable(logging.CRITICAL) @@ -244,7 +311,6 @@ def setUp(self): def tearDown(self): logging.disable(logging.NOTSET) - @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") def test_quantization(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_quantization") as data_dir: @@ -254,6 +320,7 @@ def test_quantization(self): _quantize_language_model(data_dir, "transformer_lm") +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") class TestOptimizersGPU(unittest.TestCase): def setUp(self): logging.disable(logging.CRITICAL) @@ -261,7 +328,6 @@ def setUp(self): def tearDown(self): logging.disable(logging.NOTSET) - @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") def test_flat_grads(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_flat_grads") as data_dir: diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 49e6dcd9f8..4e20774262 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -15,7 +15,7 @@ from typing import List, Dict import torch from fairseq import options -from fairseq_cli import eval_lm, train, validate +from fairseq_cli import eval_lm, train from tests.utils import ( create_dummy_data, generate_main, @@ -24,6 +24,7 @@ preprocess_translation_data, create_laser_data_and_config_json, train_translation_model, + train_language_model, ) @@ -1852,71 +1853,6 @@ def train_roberta_head(data_dir, arch, num_classes=2, extra_flags=None): train.main(train_args) -def train_language_model( - data_dir, - arch, - extra_flags=None, - run_validation=False, - extra_valid_flags=None, - task="language_modeling", -): - train_parser = options.get_training_parser() - train_args = options.parse_args_and_arch( - train_parser, - [ - "--task", - task, - data_dir, - "--arch", - arch, - "--optimizer", - "adam", - "--lr", - "0.0001", - "--max-tokens", - "500", - "--tokens-per-sample", - "500", - "--save-dir", - data_dir, - "--max-epoch", - "1", - "--no-progress-bar", - "--distributed-world-size", - "1", - "--ddp-backend", - "no_c10d", - "--num-workers", - "0", - ] - + (extra_flags or []), - ) - train.main(train_args) - - if run_validation: - # test validation - validate_parser = options.get_validation_parser() - validate_args = options.parse_args_and_arch( - validate_parser, - [ - "--task", - task, - data_dir, - "--path", - os.path.join(data_dir, "checkpoint_last.pt"), - "--valid-subset", - "valid", - "--max-tokens", - "500", - "--no-progress-bar", - "--num-workers", - "0", - ] - + (extra_valid_flags or []), - ) - validate.main(validate_args) - - def eval_lm_main(data_dir, extra_flags=None): eval_lm_parser = options.get_eval_lm_parser() eval_lm_args = options.parse_args_and_arch( diff --git a/tests/test_plasma_utils.py b/tests/test_plasma_utils.py index 5737530e3d..a5cf386b86 100644 --- a/tests/test_plasma_utils.py +++ b/tests/test_plasma_utils.py @@ -5,8 +5,7 @@ import numpy as np -from tests.test_binaries import train_language_model -from tests.utils import create_dummy_data, preprocess_lm_data +from tests.utils import create_dummy_data, preprocess_lm_data, train_language_model try: from pyarrow import plasma @@ -16,7 +15,7 @@ except ImportError: PYARROW_AVAILABLE = False -dummy_path = 'dummy' +dummy_path = "dummy" @unittest.skipUnless(PYARROW_AVAILABLE, "") diff --git a/tests/utils.py b/tests/utils.py index 1bf6f8d7f3..6e0c709517 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -23,6 +23,8 @@ from fairseq.models.fairseq_encoder import EncoderOut from fairseq.tasks import LegacyFairseqTask from fairseq_cli import generate, interactive, preprocess, train, validate +import fairseq.distributed.utils as distributed_utils +from fairseq.dataclass.utils import convert_namespace_to_omegaconf def dummy_dictionary(vocab_size, prefix="token_"): @@ -35,10 +37,7 @@ def dummy_dictionary(vocab_size, prefix="token_"): def dummy_dataloader( - samples, - padding_idx=1, - eos_idx=2, - batch_size=None, + samples, padding_idx=1, eos_idx=2, batch_size=None, ): if batch_size is None: batch_size = len(samples) @@ -320,6 +319,7 @@ def train_translation_model( run_validation=False, lang_flags=None, extra_valid_flags=None, + world_size=1, ): if lang_flags is None: lang_flags = [ @@ -349,14 +349,16 @@ def train_translation_model( "1", "--no-progress-bar", "--distributed-world-size", - "1", + str(world_size), "--num-workers", "0", ] + lang_flags + (extra_flags or []), ) - train.main(train_args) + + cfg = convert_namespace_to_omegaconf(train_args) + distributed_utils.call_main(cfg, train.main) if run_validation: # test validation @@ -646,3 +648,70 @@ def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): prev_output_tokens, encoder_out=encoder_out, **kwargs ) return decoder_out + + +def train_language_model( + data_dir, + arch, + extra_flags=None, + run_validation=False, + extra_valid_flags=None, + task="language_modeling", + world_size=1, +): + train_parser = options.get_training_parser() + train_args = options.parse_args_and_arch( + train_parser, + [ + "--task", + task, + data_dir, + "--arch", + arch, + "--optimizer", + "adam", + "--lr", + "0.0001", + "--max-tokens", + "500", + "--tokens-per-sample", + "500", + "--save-dir", + data_dir, + "--max-epoch", + "1", + "--no-progress-bar", + "--distributed-world-size", + str(world_size), + "--ddp-backend", + "no_c10d", + "--num-workers", + "0", + ] + + (extra_flags or []), + ) + cfg = convert_namespace_to_omegaconf(train_args) + distributed_utils.call_main(cfg, train.main) + + if run_validation: + # test validation + validate_parser = options.get_validation_parser() + validate_args = options.parse_args_and_arch( + validate_parser, + [ + "--task", + task, + data_dir, + "--path", + os.path.join(data_dir, "checkpoint_last.pt"), + "--valid-subset", + "valid", + "--max-tokens", + "500", + "--no-progress-bar", + "--num-workers", + "0", + ] + + (extra_valid_flags or []), + ) + validate.main(validate_args) From 2af4ffe77b230a0a228af9be09e1c0e9d4731906 Mon Sep 17 00:00:00 2001 From: Sujit Verma <sujitv@fb.com> Date: Wed, 21 Apr 2021 09:04:56 -0700 Subject: [PATCH 315/774] Supporting PathManager in cached_path util. Summary: Supporting PathManager in cached_path util. Reviewed By: myleott Differential Revision: D27895813 fbshipit-source-id: 68d7345ebb50737c53a72dcd467536f86b61e1dd --- fairseq/file_utils.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fairseq/file_utils.py b/fairseq/file_utils.py index ec6de37f77..d1d5ea6574 100644 --- a/fairseq/file_utils.py +++ b/fairseq/file_utils.py @@ -139,6 +139,19 @@ def filename_to_url(filename, cache_dir=None): return url, etag +def cached_path_from_pm(url_or_filename): + """ + Tries to cache the specified URL using PathManager class. + Returns the cached path if success otherwise failure. + """ + try: + from fairseq.file_io import PathManager + local_path = PathManager.get_local_path(url_or_filename) + return local_path + except Exception: + return None + + def cached_path(url_or_filename, cache_dir=None): """ Given something that might be a URL (or might be a local path), @@ -165,6 +178,9 @@ def cached_path(url_or_filename, cache_dir=None): # File, but it doesn't exist. raise EnvironmentError("file {} not found".format(url_or_filename)) else: + cached_path = cached_path_from_pm(url_or_filename) + if cached_path: + return cached_path # Something unknown raise ValueError( "unable to parse {} as a URL or as a local path".format(url_or_filename) From 207254bf56374831d08c20064ca7a2740a871ce5 Mon Sep 17 00:00:00 2001 From: Michael Anderson <anderso2@fb.com> Date: Wed, 21 Apr 2021 09:08:06 -0700 Subject: [PATCH 316/774] Adding check for filler size (#3495) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3495 Avoid creating size-0 tensor "filler" in case src_len is the same as key_padding_mask_size or prev_key_padding_mask_size Reviewed By: jackm321 Differential Revision: D27897778 fbshipit-source-id: 26fd95852da2cd932717c7abcac3e1fb43deaf77 --- fairseq/modules/multihead_attention.py | 34 +++++++++++++++----------- tests/test_multihead_attention.py | 12 +++++++++ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index b168a890ae..9bdca0f6af 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -403,21 +403,27 @@ def _append_prev_key_padding_mask( # leaves the frame, there will be a time when prev or current # is None elif prev_key_padding_mask is not None: - filler = torch.zeros( - (batch_size, src_len - prev_key_padding_mask.size(1)), - device=prev_key_padding_mask.device, - ) - new_key_padding_mask = torch.cat( - [prev_key_padding_mask.float(), filler.float()], dim=1 - ) + if src_len > prev_key_padding_mask.size(1): + filler = torch.zeros( + (batch_size, src_len - prev_key_padding_mask.size(1)), + device=prev_key_padding_mask.device, + ) + new_key_padding_mask = torch.cat( + [prev_key_padding_mask.float(), filler.float()], dim=1 + ) + else: + new_key_padding_mask = prev_key_padding_mask.float() elif key_padding_mask is not None: - filler = torch.zeros( - (batch_size, src_len - key_padding_mask.size(1)), - device=key_padding_mask.device, - ) - new_key_padding_mask = torch.cat( - [filler.float(), key_padding_mask.float()], dim=1 - ) + if src_len > key_padding_mask.size(1): + filler = torch.zeros( + (batch_size, src_len - key_padding_mask.size(1)), + device=key_padding_mask.device, + ) + new_key_padding_mask = torch.cat( + [filler.float(), key_padding_mask.float()], dim=1 + ) + else: + new_key_padding_mask = key_padding_mask.float() else: new_key_padding_mask = prev_key_padding_mask return new_key_padding_mask diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index 9aa9cb2f87..620a2d6791 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -35,6 +35,18 @@ def test_append_prev_key_padding_mask(self): torch.tensor([[0, 1, 0]]).bool(), torch.tensor([[0, 1, 0, 1]]).bool(), ), + # prev_key_padding_mask already full + ( + torch.tensor([[0, 1, 0, 1]]).bool(), + None, + torch.tensor([[0, 1, 0, 1]]).bool(), + ), + # key_padding_mask already full + ( + None, + torch.tensor([[0, 1, 0, 1]]).bool(), + torch.tensor([[0, 1, 0, 1]]).bool(), + ), ] for c in cases: key_padding_mask = MultiheadAttention._append_prev_key_padding_mask( From 05b86005bcca0155319fa9b81abfd69f63c06906 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 21 Apr 2021 15:49:03 -0700 Subject: [PATCH 317/774] Fix FSDP optim state loading (#1819) Summary: ### Problem: - if we consolidate optim state dict on rank 0, rank 1+ save `optimizer.state_dict()`. When they try to load, they call get_shard(last_optim_state), which is wrong since the optim state is already shared. They should find the global consolidated optimizer state dict and load that. ### Possible Solutions: - if world size is the same, you could just reuse the local OSD. - [this PR] rank 1+ load optim state from the rank0 file and call get_shard - separate file for optim_state that every rank loads. (like 'shared.pt' on `gshard-azure`). This will save some CPU Ram. ### Note: - I don't think it's possible to pass `--use-sharded-state` from the command line. It should be I think. ### Implementation here + if FSDP saves -1 as state['last_optimizer_key'], it means that, on load, rank 0's optim state must be loaded. + regression test Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1819 Reviewed By: zhengwy888 Differential Revision: D27910281 Pulled By: sshleifer fbshipit-source-id: d34987008f77ce7e0cb28b7224dd2aabed38a70c --- fairseq/trainer.py | 16 +++++++++++----- tests/gpu/test_binaries_gpu.py | 19 ++++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 6195afb4a6..5e87b573f1 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -26,7 +26,7 @@ from fairseq.optim import lr_scheduler from omegaconf import OmegaConf - +import re logger = logging.getLogger(__name__) @@ -331,14 +331,17 @@ def _build_optimizer(self): def consolidate_optimizer(self): """For OSS, we need to consolidate the state dict.""" + if self.cfg.checkpoint.no_save_optimizer_state: + return self._gathered_optim_state = None if hasattr(self.optimizer.optimizer, "consolidate_state_dict"): self.optimizer.optimizer.consolidate_state_dict() - elif self.cfg.distributed_training.ddp_backend == 'fully_sharded': - self._gathered_optim_state = self.model.gather_full_optim_state_dict(self.optimizer, - recipient_rank=0) - + elif self.cfg.distributed_training.ddp_backend == 'fully_sharded' and not self.model.use_sharded_state: + st = self.model.gather_full_optim_state_dict(self.optimizer) # only returns on rank 0 + if st is None: + st = -1 # sentinel so that workers do not save optimizer.state_dict() + self._gathered_optim_state = st def state_dict(self): state_dict = { @@ -423,6 +426,9 @@ def load_checkpoint( filename, load_on_all_ranks=load_on_all_ranks ) last_optim_state = state.get("last_optimizer_state", None) + if last_optim_state == -1: + master_path = re.sub("shard[0-9]+", "shard0", filename) + last_optim_state = torch.load(master_path, map_location='cpu')['last_optimizer_state'] # If doing zero_sharding, do not broadcast global optimizer # state. Later we will broadcast sharded states to each rank diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 5f879a7a27..45417c7eb7 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -56,7 +56,13 @@ def parse_logs(logfile): continue return logs - def test_resume_training(self): + def test_resume_training_fsdp(self): + self._test_resume_training(["--ddp-backend", "fully_sharded"]) + + def test_resume_training_noc10d(self): + self._test_resume_training([]) + + def _test_resume_training(self, extra_clargs, arch="fconv_iwslt_de_en"): flags = [ "--fp16", "--log-format", @@ -67,27 +73,22 @@ def test_resume_training(self): "2", "--log-interval", "1", - "--log-file", - ] + ] + extra_clargs world_size = min(torch.cuda.device_count(), 2) - arch = "fconv_iwslt_de_en" with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_fp16") as data_dir: log = os.path.join(data_dir, "train.log") create_dummy_data(data_dir) preprocess_translation_data(data_dir) train_translation_model( - data_dir, arch, flags + [log], world_size=world_size, + data_dir, arch, flags + ["--log-file", log], world_size=world_size, ) log2 = os.path.join(data_dir, "resume.log") restore_file = os.path.join(data_dir, "checkpoint_1_2.pt") - assert os.path.exists( - restore_file - ), f"{restore_file} not written. Choices: {os.listdir(data_dir)}" train_translation_model( data_dir, arch, - flags + [log2, "--restore-file", restore_file], + flags + ["--log-file", log2, "--restore-file", restore_file], world_size=world_size, ) From 40f6c758b361adc7b87fa553f6f439daa4ee9501 Mon Sep 17 00:00:00 2001 From: Jeffrey Karres <jkarres@fb.com> Date: Thu, 22 Apr 2021 21:32:09 -0700 Subject: [PATCH 318/774] sorting os.listdir outputs to ensure consistent import ordering Summary: There's a common idiom of doing imports based on the output of `os.listdir(os.path.dirname(__file__))`. In this idiom, imports are performed based on the order of directories in that output. This is dangerous, because the behavior of your program depends on the order of those files, but the order of those files is not guaranteed. Reviewed By: zhengwy888 Differential Revision: D27951383 fbshipit-source-id: 97dc9a0b7d853886e19a9643c33508f146c71617 --- examples/simultaneous_translation/models/__init__.py | 2 +- examples/simultaneous_translation/modules/__init__.py | 2 +- examples/simultaneous_translation/utils/__init__.py | 2 +- examples/speech_recognition/criterions/__init__.py | 2 +- examples/speech_recognition/models/__init__.py | 2 +- examples/speech_recognition/tasks/__init__.py | 2 +- fairseq/criterions/__init__.py | 2 +- fairseq/data/encoders/__init__.py | 2 +- fairseq/model_parallel/criterions/__init__.py | 2 +- fairseq/optim/__init__.py | 2 +- fairseq/optim/lr_scheduler/__init__.py | 2 +- fairseq/scoring/__init__.py | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/simultaneous_translation/models/__init__.py b/examples/simultaneous_translation/models/__init__.py index 083da43732..257a96593f 100644 --- a/examples/simultaneous_translation/models/__init__.py +++ b/examples/simultaneous_translation/models/__init__.py @@ -7,7 +7,7 @@ import os -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): model_name = file[: file.find(".py")] importlib.import_module( diff --git a/examples/simultaneous_translation/modules/__init__.py b/examples/simultaneous_translation/modules/__init__.py index ad64774de4..c695850c04 100644 --- a/examples/simultaneous_translation/modules/__init__.py +++ b/examples/simultaneous_translation/modules/__init__.py @@ -16,7 +16,7 @@ _, ) = registry.setup_registry("--simul-type") -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): model_name = file[: file.find(".py")] importlib.import_module( diff --git a/examples/simultaneous_translation/utils/__init__.py b/examples/simultaneous_translation/utils/__init__.py index be0ba4d99a..1e9ce844f5 100644 --- a/examples/simultaneous_translation/utils/__init__.py +++ b/examples/simultaneous_translation/utils/__init__.py @@ -8,7 +8,7 @@ # automatically import any Python files in the criterions/ directory -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): module = file[: file.find(".py")] importlib.import_module("examples.simultaneous_translation.utils." + module) diff --git a/examples/speech_recognition/criterions/__init__.py b/examples/speech_recognition/criterions/__init__.py index a667b1c918..579abd2ace 100644 --- a/examples/speech_recognition/criterions/__init__.py +++ b/examples/speech_recognition/criterions/__init__.py @@ -9,7 +9,7 @@ except ImportError: files_to_skip.add("ASG_loss.py") -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_") and file not in files_to_skip: criterion_name = file[: file.find(".py")] importlib.import_module( diff --git a/examples/speech_recognition/models/__init__.py b/examples/speech_recognition/models/__init__.py index 0ad9663f11..54b5a1c312 100644 --- a/examples/speech_recognition/models/__init__.py +++ b/examples/speech_recognition/models/__init__.py @@ -2,7 +2,7 @@ import os -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): model_name = file[: file.find(".py")] importlib.import_module("examples.speech_recognition.models." + model_name) diff --git a/examples/speech_recognition/tasks/__init__.py b/examples/speech_recognition/tasks/__init__.py index ffa5f3bd8c..7ac3b8dc69 100644 --- a/examples/speech_recognition/tasks/__init__.py +++ b/examples/speech_recognition/tasks/__init__.py @@ -2,7 +2,7 @@ import os -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): task_name = file[: file.find(".py")] importlib.import_module("examples.speech_recognition.tasks." + task_name) diff --git a/fairseq/criterions/__init__.py b/fairseq/criterions/__init__.py index 8cc6c0f043..4dbf46a1cb 100644 --- a/fairseq/criterions/__init__.py +++ b/fairseq/criterions/__init__.py @@ -30,7 +30,7 @@ def build_criterion(cfg: DictConfig, task): # automatically import any Python files in the criterions/ directory -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): file_name = file[: file.find(".py")] importlib.import_module("fairseq.criterions." + file_name) diff --git a/fairseq/data/encoders/__init__.py b/fairseq/data/encoders/__init__.py index 2e807d8ae7..7cbe00a105 100644 --- a/fairseq/data/encoders/__init__.py +++ b/fairseq/data/encoders/__init__.py @@ -23,7 +23,7 @@ # automatically import any Python files in the encoders/ directory -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): module = file[: file.find(".py")] importlib.import_module("fairseq.data.encoders." + module) diff --git a/fairseq/model_parallel/criterions/__init__.py b/fairseq/model_parallel/criterions/__init__.py index 6239b50362..5fae7bd4c2 100644 --- a/fairseq/model_parallel/criterions/__init__.py +++ b/fairseq/model_parallel/criterions/__init__.py @@ -8,7 +8,7 @@ # automatically import any Python files in the criterions/ directory -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): module = file[: file.find(".py")] importlib.import_module("fairseq.model_parallel.criterions." + module) diff --git a/fairseq/optim/__init__.py b/fairseq/optim/__init__.py index 112c8ad10f..01c08c98d2 100644 --- a/fairseq/optim/__init__.py +++ b/fairseq/optim/__init__.py @@ -40,7 +40,7 @@ def build_optimizer(cfg: DictConfig, params, *extra_args, **extra_kwargs): # automatically import any Python files in the optim/ directory -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): file_name = file[: file.find(".py")] importlib.import_module("fairseq.optim." + file_name) diff --git a/fairseq/optim/lr_scheduler/__init__.py b/fairseq/optim/lr_scheduler/__init__.py index f07d43c7c3..5b3dbc023a 100644 --- a/fairseq/optim/lr_scheduler/__init__.py +++ b/fairseq/optim/lr_scheduler/__init__.py @@ -30,7 +30,7 @@ def build_lr_scheduler(cfg: DictConfig, optimizer): # automatically import any Python files in the optim/lr_scheduler/ directory -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): file_name = file[: file.find(".py")] importlib.import_module("fairseq.optim.lr_scheduler." + file_name) diff --git a/fairseq/scoring/__init__.py b/fairseq/scoring/__init__.py index 2372727883..58f2f563e4 100644 --- a/fairseq/scoring/__init__.py +++ b/fairseq/scoring/__init__.py @@ -49,7 +49,7 @@ def build_scorer(choice, tgt_dict): # automatically import any Python files in the current directory -for file in os.listdir(os.path.dirname(__file__)): +for file in sorted(os.listdir(os.path.dirname(__file__))): if file.endswith(".py") and not file.startswith("_"): module = file[: file.find(".py")] importlib.import_module("fairseq.scoring." + module) From b0ae834d528a4a466202107a22356aed71bb6161 Mon Sep 17 00:00:00 2001 From: ngoyal2707 <ngoyal2707@users.noreply.github.com> Date: Mon, 26 Apr 2021 13:14:41 -0700 Subject: [PATCH 319/774] Flores pretrained model release (#1825) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1825 Reviewed By: huihuifan Differential Revision: D28002947 fbshipit-source-id: 2ba69a72431db5aa7aef890309eefb0fb31c7ad6 --- examples/flores101/README.md | 223 +++++++++++++++++++++++++++++ examples/flores101/flores_logo.png | Bin 0 -> 33184 bytes fairseq/models/transformer.py | 2 + 3 files changed, 225 insertions(+) create mode 100644 examples/flores101/README.md create mode 100644 examples/flores101/flores_logo.png diff --git a/examples/flores101/README.md b/examples/flores101/README.md new file mode 100644 index 0000000000..58d9c05aff --- /dev/null +++ b/examples/flores101/README.md @@ -0,0 +1,223 @@ +<p align="center"> +<img src="flores_logo.png" width="500"> +</p> + +# Flores101: Large-Scale Multilingual Machine Translation + +## Introduction + +Baseline pretrained models for small and large tracks of WMT 21 Large-Scale Multilingual Machine Translation competition. + +Flores Task at WMT 21: http://www.statmt.org/wmt21/large-scale-multilingual-translation-task.html + +Flores announement blog post: https://ai.facebook.com/blog/flores-researchers-kick-off-multilingual-translation-challenge-at-wmt-and-call-for-compute-grants/ + + + +## Pretrained models + +Model | Num layers | Embed dimension | FFN dimension| Vocab Size | #params | Download +---|---|---|---|---|---|--- +`flores101_mm100_615M` | 12 | 1024 | 4096 | 256,000 | 615M | https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_615M.tar.gz +`flores101_mm100_175M` | 6 | 512 | 2048 | 256,000 | 175M | https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_175M.tar.tgz + + +These models are trained similar to [M2M-100](https://arxiv.org/abs/2010.11125) with additional support for the languages that are part of the WMT Large-Scale Multilingual Machine Translation track. Full list of languages can be found at the bottom. + + +## Example Generation code + +### Download model, sentencepiece vocab + +```bash +fairseq=/path/to/fairseq +cd $fairseq + +# Download 615M param model. +wget https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_615M.tar.gz + +# Extract +tar -xvzf flores101_mm100_615M.tar.gz +``` + +### Encode using our SentencePiece Model +Note: Install SentencePiece from [here](https://github.com/google/sentencepiece) + + +```bash +fairseq=/path/to/fairseq +cd $fairseq + +# Download example dataset From German to French +sacrebleu --echo src -l de-fr -t wmt19 | head -n 20 > raw_input.de-fr.de +sacrebleu --echo ref -l de-fr -t wmt19 | head -n 20 > raw_input.de-fr.fr + +for lang in de fr ; do + python scripts/spm_encode.py \ + --model flores101_mm100_615M/sentencepiece.bpe.model \ + --output_format=piece \ + --inputs=raw_input.de-fr.${lang} \ + --outputs=spm.de-fr.${lang} +done +``` + +### Binarization + +```bash +fairseq-preprocess \ + --source-lang de --target-lang fr \ + --testpref spm.de-fr \ + --thresholdsrc 0 --thresholdtgt 0 \ + --destdir data_bin \ + --srcdict flores101_mm100_615M/dict.txt --tgtdict flores101_mm100_615M/dict.txt +``` + +### Generation + + +```bash +fairseq-generate \ + data_bin \ + --batch-size 1 \ + --path flores101_mm100_615M/model.pt \ + --fixed-dictionary flores101_mm100_615M/dict.txt \ + -s de -t fr \ + --remove-bpe 'sentencepiece' \ + --beam 5 \ + --task translation_multi_simple_epoch \ + --lang-pairs flores101_mm100_615M/language_pairs.txt \ + --decoder-langtok --encoder-langtok src \ + --gen-subset test \ + --fp16 \ + --dataset-impl mmap \ + --distributed-world-size 1 --distributed-no-spawn +``` + +### Supported Languages and lang code + +Language | lang code +---|--- +Akrikaans | af +Amharic | am +Arabic | ar +Assamese | as +Asturian | ast +Aymara | ay +Azerbaijani | az +Bashkir | ba +Belarusian | be +Bulgarian | bg +Bengali | bn +Breton | br +Bosnian | bs +Catalan | ca +Cebuano | ceb +Chokwe | cjk +Czech | cs +Welsh | cy +Danish | da +German | de +Dyula| dyu +Greek | el +English | en +Spanish | es +Estonian | et +Persian | fa +Fulah | ff +Finnish | fi +French | fr +Western Frisian | fy +Irish | ga +Scottish Gaelic | gd +Galician | gl +Gujarati | gu +Hausa | ha +Hebrew | he +Hindi | hi +Croatian | hr +Haitian Creole | ht +Hungarian | hu +Armenian | hy +Indonesian | id +Igbo | ig +Iloko | ilo +Icelandic | is +Italian | it +Japanese | ja +Javanese | jv +Georgian | ka +Kachin | kac +Kamba | kam +Kabuverdianu | kea +Kongo | kg +Kazakh | kk +Central Khmer | km +Kimbundu | kmb +Northern Kurdish | kmr +Kannada | kn +Korean | ko +Kurdish | ku +Kyrgyz | ky +Luxembourgish | lb +Ganda | lg +Lingala | ln +Lao | lo +Lithuanian | lt +Luo | luo +Latvian | lv +Malagasy | mg +Maori | mi +Macedonian | mk +Malayalam | ml +Mongolian | mn +Marathi | mr +Malay | ms +Maltese | mt +Burmese | my +Nepali | ne +Dutch | nl +Norwegian | no +Northern Sotho | ns +Nyanja | ny +Occitan | oc +Oromo | om +Oriya | or +Punjabi | pa +Polish | pl +Pashto | ps +Portuguese | pt +Quechua | qu +Romanian | ro +Russian | ru +Sindhi | sd +Shan | shn +Sinhala | si +Slovak | sk +Slovenian | sl +Shona | sn +Somali | so +Albanian | sq +Serbian | sr +Swati | ss +Sundanese | su +Swedish | sv +Swahili | sw +Tamil | ta +Telugu | te +Tajik | tg +Thai | th +Tigrinya | ti +Tagalog | tl +Tswana | tn +Turkish | tr +Ukrainian | uk +Umbundu | umb +Urdu | ur +Uzbek | uz +Vietnamese | vi +Wolof | wo +Xhosa | xh +Yiddish | yi +Yoruba | yo +Chinese| zh +Zulu | zu \ No newline at end of file diff --git a/examples/flores101/flores_logo.png b/examples/flores101/flores_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d4d1455c6eab608ff5317ce885183cd213564273 GIT binary patch literal 33184 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%0AfAGxmXw!$3%t zPaHzbr!&=|&zd<`j?;K=n*Do9vj0izq!E3IaVq8in5@{}wPiccKi(%(MGrv15Km5X zV40LZTh+9$fI#A5#|y}}Jg%B4P|EpWR9eTS=CT+UG?45NH}J#AMK7u5Zq=j|>Z_9M zPv(WTD^0@e9MKE;Mhg>NtodHPlX?3@gQ9kKtA7v1hI^LSes|PpLveH>D^k>ab7@qF zUjmuY=BKuO#kY$;8cpVPiOWHKjZx{@<mWZuoE6ZE=}?-S9u((qI>{zsg9G=x!XL3N z>N(FA-r(71Z9%t?%Jlc(X>O+B$`q?}^k2uJ|1`f=eNTD+XnLzil=B7PvusaAxj&SH zAp0h54~IY2445O2Tm8E-Dn!K_m{OVW-@Zvw7LvNeConI-*_YH?_856BPREW}9xj$~ zCStW!-^F}Xo{XjgBWH>`jE}{Rn;&;MnX_#A1TtY-Gd#^vMX-||qrf@;1BbYJk@0`p zn;|^K(H9I)J%(~75t760M$Zs+>CfeP$R2NYqHwfT62u29TiG9JYF(~7by^)Rezd{1 zpZjv!Yr|WcK>XO^SN+^}cR!%|0i_C4y#0Dt<kr6}%VlFjcZkLzm?)-*SIO3ugb%~? zA04BzTKum(A2$7GyQuA}V0!s5I9TJ~uZD;JJQMYY|1|PKy!HQ?N<jVWzyGP}pGh~= zkHCztf4)H=Q~xxAQ-Aosj^F<G@xW*Q=kW6V|6ch&4YrVo;QwCvpZ;*_Mcyj@_sakF z1%uCiWc|<b{%808pR)IODd+_dOc^Z=RTHWxfy2=LM-KmgwU~Uez_Q$ivbk7F-8ik= LdKwjK4w3&0wn$FJ literal 0 HcmV?d00001 diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 29fdeb70bf..f5d1af4477 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -101,6 +101,8 @@ def spm(path): 'transformer.wmt20.ta-en': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta-en.single.tar.gz'), 'transformer.wmt20.iu-en.news': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.news.single.tar.gz'), 'transformer.wmt20.iu-en.nh': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.nh.single.tar.gz'), + 'transformer.flores101.mm100.615M': spm('https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_615M.tar.gz'), + 'transformer.flores101.mm100.175M': spm('https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_175M.tar.gz'), } # fmt: on From 8b861beae282ec5dd5051686440948a3f893c3ec Mon Sep 17 00:00:00 2001 From: lematt1991 <lematt1991@gmail.com> Date: Wed, 28 Apr 2021 05:56:31 -0700 Subject: [PATCH 320/774] Escape % in `keep_interval_updates_pattern` help description (#3514) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This leads to the following error: ``` ValueError: unsupported format character 'k' (0x6b) at index 95 ``` Resolves https://github.com/pytorch/fairseq/issues/3491 Pull Request resolved: https://github.com/pytorch/fairseq/pull/3514 Test Plan: `fairseq-train --help` Produces: ``` ... --keep-interval-updates-pattern KEEP_INTERVAL_UPDATES_PATTERN when used with --keep-interval-updates, skips deleting any checkpoints with update X where X % keep_interval_updates_pattern == 0 ... ``` # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). https://github.com/pytorch/fairseq/issues/3491 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Reviewed By: myleott Differential Revision: D28037028 Pulled By: lematt1991 fbshipit-source-id: b237a151b82e851954ad3ea51a0c4a14c572ffab --- fairseq/dataclass/configs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 89d83b5b6b..902756bfff 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -576,7 +576,7 @@ class CheckpointConfig(FairseqDataclass): metadata={ "help": "when used with --keep-interval-updates, skips deleting " "any checkpoints with update X where " - "X % keep_interval_updates_pattern == 0" + "X %% keep_interval_updates_pattern == 0" }, ) keep_last_epochs: int = field( From 1305008e97872335d4ae8de4d015ddf8c43e87df Mon Sep 17 00:00:00 2001 From: Naman Goyal <namangoyal@learnfair0732.h2.fair> Date: Wed, 28 Apr 2021 10:44:50 -0700 Subject: [PATCH 321/774] fixed typo in flores model download link (#1827) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1827 Reviewed By: ngoyal2707 Differential Revision: D28060291 Pulled By: lematt1991 fbshipit-source-id: 2540eb2a7d6a1fe37af9a3e9b4ed3df9e05a0823 --- examples/flores101/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/flores101/README.md b/examples/flores101/README.md index 58d9c05aff..635c13f40b 100644 --- a/examples/flores101/README.md +++ b/examples/flores101/README.md @@ -19,7 +19,7 @@ Flores announement blog post: https://ai.facebook.com/blog/flores-researchers-ki Model | Num layers | Embed dimension | FFN dimension| Vocab Size | #params | Download ---|---|---|---|---|---|--- `flores101_mm100_615M` | 12 | 1024 | 4096 | 256,000 | 615M | https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_615M.tar.gz -`flores101_mm100_175M` | 6 | 512 | 2048 | 256,000 | 175M | https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_175M.tar.tgz +`flores101_mm100_175M` | 6 | 512 | 2048 | 256,000 | 175M | https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_175M.tar.gz These models are trained similar to [M2M-100](https://arxiv.org/abs/2010.11125) with additional support for the languages that are part of the WMT Large-Scale Multilingual Machine Translation track. Full list of languages can be found at the bottom. @@ -220,4 +220,4 @@ Xhosa | xh Yiddish | yi Yoruba | yo Chinese| zh -Zulu | zu \ No newline at end of file +Zulu | zu From c6409c029dc9b3af5308a269ec5c68dbdbafdc78 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Wed, 28 Apr 2021 23:22:25 -0700 Subject: [PATCH 322/774] Fix issue with encoder padding mask Summary: - Fix issue with encoder padding mask - Also add lengths as a field in encoder_out of encode_src method - Add a conditional clause in transformer_monotonic_attention.py to handle the case where encoder_padding_mask is None Reviewed By: jmp84 Differential Revision: D28080936 fbshipit-source-id: 99f78c5e3fe5644960ade44210ea78280ef53b8c --- .../models/transformer_monotonic_attention.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/simultaneous_translation/models/transformer_monotonic_attention.py b/examples/simultaneous_translation/models/transformer_monotonic_attention.py index d7aeca5ea5..1062e9b955 100644 --- a/examples/simultaneous_translation/models/transformer_monotonic_attention.py +++ b/examples/simultaneous_translation/models/transformer_monotonic_attention.py @@ -152,7 +152,8 @@ def pre_attention( encoder_out = encoder_out_dict["encoder_out"][0] encoder_padding_mask = ( encoder_out_dict["encoder_padding_mask"][0] - if len(encoder_out_dict["encoder_padding_mask"]) > 0 + if encoder_out_dict["encoder_padding_mask"] + and len(encoder_out_dict["encoder_padding_mask"]) > 0 else None ) From 9cb6fe4c93c17f1d4e327ea345cd1c653432c76c Mon Sep 17 00:00:00 2001 From: Ruslan Mavlyutov <mavlyutov@fb.com> Date: Thu, 29 Apr 2021 10:24:58 -0700 Subject: [PATCH 323/774] Copy to local before loading checkpoint Summary: Follow-up for "Fix FSDP optim state loading (#1819)". Update for remote file systems. Reviewed By: sshleifer Differential Revision: D28088088 fbshipit-source-id: 5d2f3ea5084fbbb21564d053317d2c07565cf2bc --- fairseq/trainer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 5e87b573f1..0b70a97356 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -428,7 +428,8 @@ def load_checkpoint( last_optim_state = state.get("last_optimizer_state", None) if last_optim_state == -1: master_path = re.sub("shard[0-9]+", "shard0", filename) - last_optim_state = torch.load(master_path, map_location='cpu')['last_optimizer_state'] + local_master_path = PathManager.get_local_path(master_path) + last_optim_state = torch.load(local_master_path, map_location='cpu')['last_optimizer_state'] # If doing zero_sharding, do not broadcast global optimizer # state. Later we will broadcast sharded states to each rank From d6855baec88f99ac776962027b91d404fe917eea Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Thu, 29 Apr 2021 16:16:09 -0700 Subject: [PATCH 324/774] Simplify CountingIterator Summary: Simplify the implementation of `CountingIterator`, and added test cases. The old implementation could fail on such a test case: ``` ref = list(range(10)) itr = CountingIterator(ref) first_item = next(itr) # consume one item remaining_items = list(itr) # raises exception because of "length mismatch" ``` This happens because `list(itr)` invokes `itr.__iter__` and reiterate the underlying list from the start, but `itr.n` has been already incremented by `next(itr)`. The new implementation is simpler and avoids such an error. Reviewed By: myleott Differential Revision: D27802505 fbshipit-source-id: c97fd0a27d865c0ff3b24016fa6aa0afabbf0a73 --- fairseq/data/iterators.py | 72 ++++++++++++++------------------------- tests/test_iterators.py | 58 +++++++++++++++++++------------ 2 files changed, 61 insertions(+), 69 deletions(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 66eaf875cb..293d853822 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -31,74 +31,52 @@ class CountingIterator(object): iterable (iterable): iterable to wrap start (int): starting iteration count. Note that this doesn't actually advance the iterator. - total (int): override the iterator length returned by - ``__len__``. This can be used to truncate *iterator*. + total (int): override the iterator length returned by ``__len``. + This can be used to truncate *iterator*. Attributes: n (int): number of elements consumed from this iterator """ def __init__(self, iterable, start=None, total=None): - self.iterable = iterable - self.itr = iter(self) - - if start is None: - self.n = getattr(iterable, "n", 0) - else: - self.n = start - - if total is None: - self.total = self.n + len(iterable) - else: - self.total = total + self._itr = iter(iterable) + self.n = start or getattr(iterable, "n", 0) + self.total = total or self.n + len(iterable) def __len__(self): return self.total def __iter__(self): - for x in self.iterable: - if self.n >= self.total: - raise RuntimeError( - "Mismatch between actual and expected iterable length. " - "This may be caused by resuming training from a checkpoint using " - "a different number of GPUs, in which case you can try the " - "--reset-dataloader option. Alternatively you may have a train or " - "validation set that is smaller than the number of GPUs. If none " - "of these apply, please report this to the fairseq developers." - ) - self.n += 1 - yield x + return self def __next__(self): - return next(self.itr) + if not self.has_next(): + raise StopIteration + try: + x = next(self._itr) + except StopIteration: + raise IndexError(f"Iterator expected to have length {self.total}, " + "but exhausted at position {self.n}.") + self.n += 1 + return x def has_next(self): """Whether the iterator has been exhausted.""" - return self.n < len(self) + return self.n < self.total - def skip(self, num_to_skip): - """Fast-forward the iterator by skipping *num_to_skip* elements.""" - next(itertools.islice(self.itr, num_to_skip, num_to_skip), None) + def skip(self, n): + """Fast-forward the iterator by skipping n elements.""" + for _ in range(n): + next(self) return self def take(self, n): - """ - Truncates the iterator to n elements at most. - """ + """Truncate the iterator to n elements at most.""" self.total = min(self.total, n) - # Propagate this change to the underlying iterator - # Only take after what we have already consumed (i.e. after restarting - # from checkpoint mid epoch, we have to subtract self.n which is the - # starting point) - # - # This to maintain the invariant self.total = self.n + len(iterable), - # before calling __next__ or __iter__ - propagated_take = max(n - self.n, 0) - if hasattr(self.iterable, "take"): - self.iterable.take(propagated_take) - else: - self.iterable = itertools.islice(self.iterable, propagated_take) + if hasattr(self._itr, "take"): + self._itr.take(max(n - self.n, 0)) + return self class EpochBatchIterating(object): @@ -620,10 +598,10 @@ def __len__(self): def take(self, n): self.total = min(self.total, n) - # Propagate this change to the underlying iterator if hasattr(self._iterable, "take"): self._iterable.take(n) + return self def __next__(self): # Create consumer if not created yet diff --git a/tests/test_iterators.py b/tests/test_iterators.py index 3d2c4d6251..7b3dd48485 100644 --- a/tests/test_iterators.py +++ b/tests/test_iterators.py @@ -9,7 +9,8 @@ class TestIterators(unittest.TestCase): - def test_counting_iterator(self, ref=None, itr=None): + def test_counting_iterator_index(self, ref=None, itr=None): + # Test the indexing functionality of CountingIterator if ref is None: assert itr is None ref = list(range(10)) @@ -17,6 +18,7 @@ def test_counting_iterator(self, ref=None, itr=None): else: assert len(ref) == 10 assert itr is not None + self.assertTrue(itr.has_next()) self.assertEqual(itr.n, 0) self.assertEqual(next(itr), ref[0]) @@ -26,9 +28,36 @@ def test_counting_iterator(self, ref=None, itr=None): itr.skip(3) self.assertEqual(itr.n, 5) self.assertEqual(next(itr), ref[5]) - itr.skip(3) - self.assertEqual(itr.n, 9) - self.assertEqual(next(itr), ref[9]) + itr.skip(2) + self.assertEqual(itr.n, 8) + self.assertEqual(list(itr), [ref[8], ref[9]]) + self.assertFalse(itr.has_next()) + + def test_counting_iterator_length_mismatch(self): + ref = list(range(10)) + # When the underlying iterable is longer than the CountingIterator, + # the remaining items in the iterable should be ignored + itr = iterators.CountingIterator(ref, total=8) + self.assertEqual(list(itr), ref[:8]) + # When the underlying iterable is shorter than the CountingIterator, + # raise an IndexError when the underlying iterable is exhausted + itr = iterators.CountingIterator(ref, total=12) + self.assertRaises(IndexError, list, itr) + + def test_counting_iterator_take(self): + # Test the "take" method of CountingIterator + ref = list(range(10)) + itr = iterators.CountingIterator(ref) + itr.take(5) + self.assertEqual(len(itr), len(list(iter(itr)))) + self.assertEqual(len(itr), 5) + + itr = iterators.CountingIterator(ref) + itr.take(5) + self.assertEqual(next(itr), ref[0]) + self.assertEqual(next(itr), ref[1]) + itr.skip(2) + self.assertEqual(next(itr), ref[4]) self.assertFalse(itr.has_next()) def test_grouped_iterator(self): @@ -41,11 +70,11 @@ def test_grouped_iterator(self): itr = iterators.GroupedIterator(x, 5) self.assertEqual(list(itr), [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) - # test CountingIterator functionality + # test the GroupIterator also works correctly as a CountingIterator x = list(range(30)) ref = list(iterators.GroupedIterator(x, 3)) itr = iterators.GroupedIterator(x, 3) - self.test_counting_iterator(ref, itr) + self.test_counting_iterator_index(ref, itr) def test_sharded_iterator(self): # test correctness @@ -67,22 +96,7 @@ def test_sharded_iterator(self): x = list(range(30)) ref = list(iterators.ShardedIterator(x, num_shards=3, shard_id=0)) itr = iterators.ShardedIterator(x, num_shards=3, shard_id=0) - self.test_counting_iterator(ref, itr) - - def test_counting_iterator_take(self): - ref = list(range(10)) - itr = iterators.CountingIterator(ref) - itr.take(5) - self.assertEqual(len(itr), len(list(iter(itr)))) - self.assertEqual(len(itr), 5) - - itr = iterators.CountingIterator(ref) - itr.take(5) - self.assertEqual(next(itr), ref[0]) - self.assertEqual(next(itr), ref[1]) - itr.skip(2) - self.assertEqual(next(itr), ref[4]) - self.assertFalse(itr.has_next()) + self.test_counting_iterator_index(ref, itr) def test_counting_iterator_buffered_iterator_take(self): ref = list(range(10)) From a4e1d4a3daf4f6f5557505026fd94b8716fba7b3 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Sun, 2 May 2021 19:24:59 -0700 Subject: [PATCH 325/774] add binarized audio dataset for large datasets (#1840) Summary: adds a binarized audio dataset to prevent oom when training with very large datasets Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1840 Reviewed By: arbabu123 Differential Revision: D28137756 Pulled By: alexeib fbshipit-source-id: bfe58e9d2bc9909b38876d78cc2e8aea783b3fed --- .../wav2vec2_large_librivox_tpu-pod.yaml | 9 +- .../wav2vec2_large_librivox_tpu.yaml | 9 +- examples/wav2vec/scripts/binarize_manifest.sh | 33 +++ fairseq/data/__init__.py | 3 +- fairseq/data/audio/raw_audio_dataset.py | 191 ++++++++++++------ fairseq/data/dictionary.py | 3 +- fairseq/tasks/audio_pretraining.py | 113 ++++++----- 7 files changed, 246 insertions(+), 115 deletions(-) create mode 100644 examples/wav2vec/scripts/binarize_manifest.sh diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml index 676c9fe339..ff35a95b65 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu-pod.yaml @@ -55,7 +55,7 @@ model: quantize_targets: true extractor_mode: layer_norm layer_norm_first: true - final_dim: 256 + final_dim: 768 latent_temp: [2.0,0.1,0.999995] encoder_layerdrop: 0.00 dropout_input: 0.0 @@ -64,8 +64,9 @@ model: attention_dropout: 0.0 conv_bias: true - mask_channel_prob: 0.1 - mask_prob: 0.1 + encoder_layers: 24 + encoder_embed_dim: 1024 + encoder_ffn_embed_dim: 4096 + encoder_attention_heads: 16 feature_grad_mult: 1.0 - diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml index c45c4d9117..2036e23c6b 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml @@ -55,7 +55,7 @@ model: quantize_targets: true extractor_mode: layer_norm layer_norm_first: true - final_dim: 256 + final_dim: 768 latent_temp: [2.0,0.1,0.999995] encoder_layerdrop: 0.00 dropout_input: 0.0 @@ -64,8 +64,9 @@ model: attention_dropout: 0.0 conv_bias: true - mask_channel_prob: 0.1 - mask_prob: 0.1 + encoder_layers: 24 + encoder_embed_dim: 1024 + encoder_ffn_embed_dim: 4096 + encoder_attention_heads: 16 feature_grad_mult: 1.0 - diff --git a/examples/wav2vec/scripts/binarize_manifest.sh b/examples/wav2vec/scripts/binarize_manifest.sh new file mode 100644 index 0000000000..6f201bdb52 --- /dev/null +++ b/examples/wav2vec/scripts/binarize_manifest.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# usage: bash binarize_manifest <dest_dir> <train_split> <valid_split> + +DEST_DIR=$1 +TRAIN_SPLIT=$2 +VALID_SPLIT=$3 +FAIRSEQ_ROOT=$4 + +mkdir -p $DEST_DIR + +# split file path and lengths into separate files +cut -f1 $TRAIN_SPLIT.tsv > $DEST_DIR/train_fnames.txt +cut -f1 $VALID_SPLIT.tsv > $DEST_DIR/valid_fnames.txt +cut -f2 $TRAIN_SPLIT.tsv > $DEST_DIR/train.lengths +cut -f2 $VALID_SPLIT.tsv > $DEST_DIR/valid.lengths + +# copy root directory +head -1 $TRAIN_SPLIT.tsv > $DEST_DIR/train.root +head -1 $VALID_SPLIT.tsv > $DEST_DIR/valid.root + +# remove root directory +sed -i '1d' $DEST_DIR/train_fnames.txt +sed -i '1d' $DEST_DIR/valid_fnames.txt +sed -i '1d' $DEST_DIR/train.lengths +sed -i '1d' $DEST_DIR/valid.lengths + +# insert spaces between characters +sed -i -e 's/\(.\)/\1 /g' $DEST_DIR/train_fnames.txt +sed -i -e 's/\(.\)/\1 /g' $DEST_DIR/valid_fnames.txt + +# run preprocessor +PYTHONPATH=$FAIRSEQ_ROOT python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $DEST_DIR/train_fnames.txt --validpref $DEST_DIR/valid_fnames.txt --workers 60 --only-source --destdir $DEST_DIR diff --git a/fairseq/data/__init__.py b/fairseq/data/__init__.py index 9b30813955..30af792185 100644 --- a/fairseq/data/__init__.py +++ b/fairseq/data/__init__.py @@ -12,7 +12,7 @@ from .add_target_dataset import AddTargetDataset from .append_token_dataset import AppendTokenDataset -from .audio.raw_audio_dataset import FileAudioDataset +from .audio.raw_audio_dataset import BinarizedAudioDataset, FileAudioDataset from .backtranslation_dataset import BacktranslationDataset from .bucket_pad_length_dataset import BucketPadLengthDataset from .colorize_dataset import ColorizeDataset @@ -69,6 +69,7 @@ "AppendTokenDataset", "BacktranslationDataset", "BaseWrapperDataset", + "BinarizedAudioDataset", "BucketPadLengthDataset", "ColorizeDataset", "ConcatDataset", diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index d0ff604e2b..2d3dd238a6 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -46,10 +46,8 @@ def __init__( if self.compute_mask_indices: self.mask_compute_kwargs = mask_compute_kwargs self._features_size_map = {} - self._C = mask_compute_kwargs['encoder_embed_dim'] - self._conv_feature_layers = eval( - mask_compute_kwargs['conv_feature_layers'] - ) + self._C = mask_compute_kwargs["encoder_embed_dim"] + self._conv_feature_layers = eval(mask_compute_kwargs["conv_feature_layers"]) def __getitem__(self, index): raise NotImplementedError() @@ -84,34 +82,32 @@ def crop_to_max_size(self, wav, target_size): def _compute_mask_indices(self, dims, padding_mask): B, T, C = dims mask_indices, mask_channel_indices = None, None - if self.mask_compute_kwargs['mask_prob'] > 0: + if self.mask_compute_kwargs["mask_prob"] > 0: mask_indices = compute_mask_indices( (B, T), padding_mask, - self.mask_compute_kwargs['mask_prob'], - self.mask_compute_kwargs['mask_length'], - self.mask_compute_kwargs['mask_selection'], - self.mask_compute_kwargs['mask_other'], + self.mask_compute_kwargs["mask_prob"], + self.mask_compute_kwargs["mask_length"], + self.mask_compute_kwargs["mask_selection"], + self.mask_compute_kwargs["mask_other"], min_masks=2, - no_overlap=self.mask_compute_kwargs['no_mask_overlap'], - min_space=self.mask_compute_kwargs['mask_min_space'], + no_overlap=self.mask_compute_kwargs["no_mask_overlap"], + min_space=self.mask_compute_kwargs["mask_min_space"], ) mask_indices = torch.from_numpy(mask_indices) - if self.mask_compute_kwargs['mask_channel_prob'] > 0: + if self.mask_compute_kwargs["mask_channel_prob"] > 0: mask_channel_indices = compute_mask_indices( (B, C), None, - self.mask_compute_kwargs['mask_channel_prob'], - self.mask_compute_kwargs['mask_channel_length'], - self.mask_compute_kwargs['mask_channel_selection'], - self.mask_compute_kwargs['mask_channel_other'], - no_overlap=self.mask_compute_kwargs['no_mask_channel_overlap'], - min_space=self.mask_compute_kwargs['mask_channel_min_space'], + self.mask_compute_kwargs["mask_channel_prob"], + self.mask_compute_kwargs["mask_channel_length"], + self.mask_compute_kwargs["mask_channel_selection"], + self.mask_compute_kwargs["mask_channel_other"], + no_overlap=self.mask_compute_kwargs["no_mask_channel_overlap"], + min_space=self.mask_compute_kwargs["mask_channel_min_space"], ) mask_channel_indices = ( - torch.from_numpy(mask_channel_indices) - .unsqueeze(1) - .expand(-1, T, -1) + torch.from_numpy(mask_channel_indices).unsqueeze(1).expand(-1, T, -1) ) return mask_indices, mask_channel_indices @@ -155,22 +151,18 @@ def collater(self, samples): if self.pad: input["padding_mask"] = padding_mask - if hasattr(self, 'num_buckets') and self.num_buckets > 0: + if hasattr(self, "num_buckets") and self.num_buckets > 0: assert self.pad, "Cannot bucket without padding first." - bucket = max(self._bucketed_sizes[s['id']] for s in samples) + bucket = max(self._bucketed_sizes[s["id"]] for s in samples) num_pad = bucket - collated_sources.size(-1) if num_pad: - input['source'] = self._bucket_tensor( - collated_sources, num_pad, 0 - ) - input['padding_mask'] = self._bucket_tensor( - padding_mask, num_pad, True - ) + input["source"] = self._bucket_tensor(collated_sources, num_pad, 0) + input["padding_mask"] = self._bucket_tensor(padding_mask, num_pad, True) if self.compute_mask_indices: - B = input['source'].size(0) - T = self._get_mask_indices_dims(input['source'].size(-1)) - padding_mask_reshaped = input['padding_mask'].clone() + B = input["source"].size(0) + T = self._get_mask_indices_dims(input["source"].size(-1)) + padding_mask_reshaped = input["padding_mask"].clone() extra = padding_mask_reshaped.size(1) % T if extra > 0: padding_mask_reshaped = padding_mask_reshaped[:, :-extra] @@ -178,15 +170,14 @@ def collater(self, samples): padding_mask_reshaped.size(0), T, -1 ) padding_mask_reshaped = padding_mask_reshaped.all(-1) - input['padding_count'] = ( - padding_mask_reshaped.sum(-1).max().item() - ) + input["padding_count"] = padding_mask_reshaped.sum(-1).max().item() mask_indices, mask_channel_indices = self._compute_mask_indices( - (B, T, self._C), padding_mask_reshaped, + (B, T, self._C), + padding_mask_reshaped, ) input["mask_indices"] = mask_indices input["mask_channel_indices"] = mask_channel_indices - out['sample_size'] = mask_indices.sum().item() + out["sample_size"] = mask_indices.sum().item() out["net_input"] = input return out @@ -195,7 +186,7 @@ def _get_mask_indices_dims(self, size, padding=0, dilation=1): if size not in self._features_size_map: L_in = size for (_, kernel_size, stride) in self._conv_feature_layers: - L_out = L_in + 2*padding - dilation*(kernel_size-1) - 1 + L_out = L_in + 2 * padding - dilation * (kernel_size - 1) - 1 L_out = 1 + L_out // stride L_in = L_out self._features_size_map[size] = L_out @@ -223,6 +214,25 @@ def ordered_indices(self): order.append(self.sizes) return np.lexsort(order)[::-1] + def set_bucket_info(self, num_buckets): + self.num_buckets = num_buckets + if self.num_buckets > 0: + self._collated_sizes = np.minimum( + np.array(self.sizes), + self.max_sample_size, + ) + self.buckets = get_buckets( + self._collated_sizes, + self.num_buckets, + ) + self._bucketed_sizes = get_bucketed_sizes( + self._collated_sizes, self.buckets + ) + logger.info( + f"{len(self.buckets)} bucket(s) for the audio dataset: " + f"{self.buckets}" + ) + class FileAudioDataset(RawAudioDataset): def __init__( @@ -249,10 +259,9 @@ def __init__( **mask_compute_kwargs, ) - self.fnames = [] - self.line_inds = set() - skipped = 0 + self.fnames = [] + sizes = [] with open(manifest_path, "r") as f: self.root_dir = f.readline().strip() for i, line in enumerate(f): @@ -263,32 +272,94 @@ def __init__( skipped += 1 continue self.fnames.append(items[0]) - self.line_inds.add(i) - self.sizes.append(sz) - self.set_bucket_info(num_buckets) + sizes.append(sz) logger.info(f"loaded {len(self.fnames)}, skipped {skipped} samples") - def set_bucket_info(self, num_buckets): - self.num_buckets = num_buckets - if self.num_buckets > 0: - self._collated_sizes = np.minimum( - np.array(self.sizes), self.max_sample_size, - ) - self.buckets = get_buckets( - self._collated_sizes, self.num_buckets, - ) - self._bucketed_sizes = get_bucketed_sizes( - self._collated_sizes, self.buckets - ) - logger.info( - f"{len(self.buckets)} bucket(s) for the audio dataset: " - f"{self.buckets}" + self.sizes = np.array(sizes, dtype=np.int64) + + try: + import pyarrow + + self.fnames = pyarrow.array(self.fnames) + except: + logger.debug( + "Could not create a pyarrow array. Please install pyarrow for better performance" ) + pass + + self.set_bucket_info(num_buckets) def __getitem__(self, index): import soundfile as sf - fname = os.path.join(self.root_dir, self.fnames[index]) + fname = os.path.join(self.root_dir, str(self.fnames[index])) + wav, curr_sample_rate = sf.read(fname) + feats = torch.from_numpy(wav).float() + feats = self.postprocess(feats, curr_sample_rate) + return {"id": index, "source": feats} + + +class BinarizedAudioDataset(RawAudioDataset): + def __init__( + self, + data_dir, + split, + sample_rate, + max_sample_size=None, + min_sample_size=0, + shuffle=True, + pad=False, + normalize=False, + num_buckets=0, + compute_mask_indices=False, + **mask_compute_kwargs, + ): + super().__init__( + sample_rate=sample_rate, + max_sample_size=max_sample_size, + min_sample_size=min_sample_size, + shuffle=shuffle, + pad=pad, + normalize=normalize, + compute_mask_indices=compute_mask_indices, + **mask_compute_kwargs, + ) + + from fairseq.data import data_utils, Dictionary + + self.fnames_dict = Dictionary.load(os.path.join(data_dir, "dict.txt")) + + root_path = os.path.join(data_dir, f"{split}.root") + if os.path.exists(root_path): + with open(root_path, "r") as f: + self.root_dir = next(f).strip() + else: + self.root_dir = None + + fnames_path = os.path.join(data_dir, split) + self.fnames = data_utils.load_indexed_dataset(fnames_path, self.fnames_dict) + lengths_path = os.path.join(data_dir, f"{split}.lengths") + + with open(lengths_path, "r") as f: + for line in f: + sz = int(line.rstrip()) + assert ( + sz >= min_sample_size + ), f"Min sample size is not supported for binarized dataset, but found a sample with size {sz}" + self.sizes.append(sz) + + self.sizes = np.array(self.sizes, dtype=np.int64) + + self.set_bucket_info(num_buckets) + logger.info(f"loaded {len(self.fnames)} samples") + + def __getitem__(self, index): + import soundfile as sf + + fname = self.fnames_dict.string(self.fnames[index], separator="") + if self.root_dir: + fname = os.path.join(self.root_dir, fname) + wav, curr_sample_rate = sf.read(fname) feats = torch.from_numpy(wav).float() feats = self.postprocess(feats, curr_sample_rate) diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index 8d219e20ef..0d8308a811 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -70,6 +70,7 @@ def string( extra_symbols_to_ignore=None, unk_string=None, include_eos=False, + separator=" ", ): """Helper for converting a tensor of token indices to a string. @@ -96,7 +97,7 @@ def token_string(i): if hasattr(self, "bos_index"): extra_symbols_to_ignore.add(self.bos()) - sent = " ".join( + sent = separator.join( token_string(i) for i in tensor if utils.item(i) not in extra_symbols_to_ignore diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index df073a1814..a84798d076 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -12,10 +12,17 @@ from argparse import Namespace from dataclasses import dataclass, field +import numpy as np from typing import Optional, Any from omegaconf import MISSING, II -from fairseq.data import AddTargetDataset, Dictionary, FileAudioDataset, encoders +from fairseq.data import ( + AddTargetDataset, + BinarizedAudioDataset, + Dictionary, + FileAudioDataset, + encoders, +) from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.configs import GenerationConfig @@ -44,6 +51,13 @@ class AudioPretrainingConfig(FairseqDataclass): default=None, metadata={"help": "extension of the label file to load, used for fine-tuning"}, ) + binarized_dataset: bool = field( + default=False, + metadata={ + "help": "if true, loads binarized dataset (useful for very large datasets). " + "See examples/wav2vec/scripts/binarize_manifest.sh" + }, + ) sample_rate: int = field( default=16_000, metadata={ @@ -92,9 +106,7 @@ class AudioPretrainingConfig(FairseqDataclass): ) num_batch_buckets: int = field( default=0, - metadata={ - "help": "number of buckets" - }, + metadata={"help": "number of buckets"}, ) precompute_mask_indices: bool = field( default=False, @@ -152,61 +164,70 @@ def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): def load_target_dictionary(self): if self.cfg.labels: - dict_path = os.path.join( - self.cfg.data, f"dict.{self.cfg.labels}.txt" - ) + dict_path = os.path.join(self.cfg.data, f"dict.{self.cfg.labels}.txt") return Dictionary.load(dict_path) return None def _get_mask_precompute_kwargs(self, cfg): if self.cfg.precompute_mask_indices or self.cfg.tpu: args = [ - 'mask_length', - 'mask_prob', - 'mask_selection', - 'mask_other', - 'no_mask_overlap', - 'mask_min_space', - 'mask_channel_length', - 'mask_channel_prob', - 'mask_channel_selection', - 'mask_channel_other', - 'no_mask_channel_overlap', - 'mask_channel_min_space', - 'encoder_embed_dim', - 'conv_feature_layers', + "mask_length", + "mask_prob", + "mask_selection", + "mask_other", + "no_mask_overlap", + "mask_min_space", + "mask_channel_length", + "mask_channel_prob", + "mask_channel_selection", + "mask_channel_other", + "no_mask_channel_overlap", + "mask_channel_min_space", + "encoder_embed_dim", + "conv_feature_layers", ] return {arg: cfg[arg] for arg in args} else: return {} - def load_dataset( - self, split: str, task_cfg: FairseqDataclass = None, **kwargs - ): + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): data_path = self.cfg.data task_cfg = task_cfg or self.cfg # upgrade old task if isinstance(task_cfg, Namespace): if not hasattr(task_cfg, "autoregressive"): - task_cfg.autoregressive = not task_cfg.criterion == 'ctc' - - manifest = os.path.join(data_path, "{}.tsv".format(split)) - self.datasets[split] = FileAudioDataset( - manifest, - sample_rate=task_cfg.get('sample_rate', self.cfg.sample_rate), - max_sample_size=self.cfg.max_sample_size, - min_sample_size=self.cfg.min_sample_size, - pad=task_cfg.labels is not None or task_cfg.enable_padding, - normalize=task_cfg.normalize, - num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), - compute_mask_indices=( - self.cfg.precompute_mask_indices or self.cfg.tpu - ), - **self._get_mask_precompute_kwargs(task_cfg), - ) + task_cfg.autoregressive = not task_cfg.criterion == "ctc" + + if task_cfg.binarized_dataset: + self.datasets[split] = BinarizedAudioDataset( + data_path, + split=split, + sample_rate=task_cfg.get("sample_rate", self.cfg.sample_rate), + max_sample_size=self.cfg.max_sample_size, + min_sample_size=self.cfg.min_sample_size, + pad=task_cfg.labels is not None or task_cfg.enable_padding, + normalize=task_cfg.normalize, + num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), + compute_mask_indices=(self.cfg.precompute_mask_indices or self.cfg.tpu), + **self._get_mask_precompute_kwargs(task_cfg), + ) + else: + manifest_path = os.path.join(data_path, "{}.tsv".format(split)) + + self.datasets[split] = FileAudioDataset( + manifest_path=manifest_path, + sample_rate=task_cfg.get("sample_rate", self.cfg.sample_rate), + max_sample_size=self.cfg.max_sample_size, + min_sample_size=self.cfg.min_sample_size, + pad=task_cfg.labels is not None or task_cfg.enable_padding, + normalize=task_cfg.normalize, + num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), + compute_mask_indices=(self.cfg.precompute_mask_indices or self.cfg.tpu), + **self._get_mask_precompute_kwargs(task_cfg), + ) - if self.cfg.tpu and task_cfg['mask_channel_prob'] == 0.0: + if self.cfg.tpu and task_cfg["mask_channel_prob"] == 0.0: logger.info( "Pretraining on TPUs may suffer convergence " "issues when training with `mask_channel_prob` value of " @@ -217,13 +238,15 @@ def load_dataset( label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") with open(label_path, "r") as f: labels = [ - line for i, line in enumerate(f) + line + for i, line in enumerate(f) if i in self.datasets[split].line_inds ] assert len(labels) == len(self.datasets[split]), ( - f"labels length ({len(labels)}) and dataset length " - f"({len(self.datasets[split])}) do not match") + f"labels length ({len(labels)}) and dataset length " + f"({len(self.datasets[split])}) do not match" + ) process_label = LabelEncoder(self.target_dictionary) @@ -234,7 +257,7 @@ def load_dataset( eos=self.target_dictionary.eos(), batch_targets=True, process_label=process_label, - add_to_input=task_cfg.get('autoregressive', False), + add_to_input=task_cfg.get("autoregressive", False), ) @property From a8c8f0be177649f8178fdcbae519c17894efd4d7 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Tue, 4 May 2021 18:27:48 -0700 Subject: [PATCH 326/774] fix wav2vec finetuning (#1848) Summary: fixes a regression from previous PR that removed line_inds from the raw audio dataset this time we dont store line indices (which can be very large for big datasets) but instead store indices of skipped examples where applicable Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1848 Reviewed By: arbabu123 Differential Revision: D28198764 Pulled By: alexeib fbshipit-source-id: 49580e09e6c1145b45c18802f4481d6df3de8cd2 --- fairseq/data/audio/raw_audio_dataset.py | 3 +++ fairseq/tasks/audio_pretraining.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 2d3dd238a6..1f945993a8 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -262,6 +262,8 @@ def __init__( skipped = 0 self.fnames = [] sizes = [] + self.skipped_indices = set() + with open(manifest_path, "r") as f: self.root_dir = f.readline().strip() for i, line in enumerate(f): @@ -270,6 +272,7 @@ def __init__( sz = int(items[1]) if min_sample_size is not None and sz < min_sample_size: skipped += 1 + self.skipped_indices.add(i) continue self.fnames.append(items[0]) sizes.append(sz) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index a84798d076..c27668439b 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -236,11 +236,12 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): if task_cfg.labels: label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") + skipped_indices = getattr(self.datasets[split], 'skipped_indices', set()) with open(label_path, "r") as f: labels = [ line for i, line in enumerate(f) - if i in self.datasets[split].line_inds + if i not in skipped_indices ] assert len(labels) == len(self.datasets[split]), ( From 374fdc5cd94d361bb9b1089fe2c1d30a2eb15fdd Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Wed, 5 May 2021 17:35:54 -0700 Subject: [PATCH 327/774] fix eval of older checkpoints (fixes #3528) (#1851) Summary: see title Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1851 Reviewed By: michaelauli, arbabu123 Differential Revision: D28226892 Pulled By: alexeib fbshipit-source-id: e07641dda46be2708e1f9d0c0cbc5b8dedaa92e7 --- fairseq/tasks/audio_pretraining.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index c27668439b..071331a10a 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -199,7 +199,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): if not hasattr(task_cfg, "autoregressive"): task_cfg.autoregressive = not task_cfg.criterion == "ctc" - if task_cfg.binarized_dataset: + if getattr(task_cfg, 'binarized_dataset', False): self.datasets[split] = BinarizedAudioDataset( data_path, split=split, From eb228ee74c6bc9803eb7dbd398d8cda16c55ccd2 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Wed, 5 May 2021 23:41:04 -0700 Subject: [PATCH 328/774] do per gpu seeding for shuffling batches with batch level sampling, fix bug with not disabling iterator cache Summary: we want to avoid the case where each gpu has a batch from the same dataset. not sure if this is happening right now, but to avoid this we can seed a shuffle by the GPU rank. also fixed a bug where we need to reset iterator for the new batch sampling Differential Revision: D28085750 fbshipit-source-id: 1643738b397d850f737fcd27c6398c216342464a --- fairseq/data/multi_corpus_dataset.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index acb91f3df6..1bd61c32eb 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -45,6 +45,7 @@ def __init__( seed: int, sort_indices: bool = False, batch_sample: bool = False, + distributed_rank=None, ): super().__init__() assert isinstance(datasets, OrderedDict) @@ -55,6 +56,7 @@ def __init__( self.seed = seed self.sort_indices = sort_indices self.batch_sample = batch_sample + self.distributed_rank = distributed_rank # Avoid repeated conversions to list later self.dataset_list = list(datasets.values()) @@ -72,6 +74,7 @@ def __init__( def ordered_indices(self): start = time.time() with data_utils.numpy_seed(self.seed, self.epoch): + logger.info(f"sampling new dataset with seed {self.seed} epoch {self.epoch}") sampled_indices = [] num_selected_instances = 0 @@ -186,6 +189,7 @@ def can_reuse_epoch_itr_across_epochs(self): def set_epoch(self, epoch, **unused): super().set_epoch(epoch) + logger.info(f"setting epoch of multi_corpus_dataset to {epoch}") self.epoch = epoch @property @@ -227,5 +231,10 @@ def batch_by_size( logger.info(f"Created {len(cur_batches)} batches for dataset {key}") batches += cur_batches - # Assume shuffling is handled in fairseq/data/iterators.py + # If this dataset is used in a distributed training setup, + # then shuffle such that the order is seeded by the distributed rank + # as well + if self.distributed_rank is not None: + with data_utils.numpy_seed(self.seed, self.epoch, self.distributed_rank): + np.random.shuffle(batches) return batches From 14439b12ad37bd8b9e2b1383209603df996bd3f5 Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Fri, 7 May 2021 12:31:59 -0700 Subject: [PATCH 329/774] add fp16 comm hook Summary: speed up fp32 distributed training runs. Reviewed By: myleott Differential Revision: D28128720 fbshipit-source-id: 7855e4ecd43e194fd79e95bf9f35d4377a98779a --- fairseq/dataclass/configs.py | 4 ++++ fairseq/dataclass/constants.py | 1 + fairseq/models/distributed_fairseq_model.py | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 902756bfff..f5a405ec76 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -12,6 +12,7 @@ from fairseq.dataclass.constants import ( DATASET_IMPL_CHOICES, DDP_BACKEND_CHOICES, + DDP_COMM_HOOK_CHOICES, GENERATION_CONSTRAINTS_CHOICES, GENERATION_DECODING_FORMAT_CHOICES, LOG_FORMAT_CHOICES, @@ -244,6 +245,9 @@ class DistributedTrainingConfig(FairseqDataclass): ddp_backend: DDP_BACKEND_CHOICES = field( default="pytorch_ddp", metadata={"help": "DistributedDataParallel backend"} ) + ddp_comm_hook: DDP_COMM_HOOK_CHOICES = field( + default="none", metadata={"help": "communication hook"} + ) bucket_cap_mb: int = field( default=25, metadata={"help": "bucket size for reduction"} ) diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index faba0862fa..442c25982b 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -43,6 +43,7 @@ def ChoiceEnum(choices: List[str]): "pytorch_ddp", "slow_mo", ]) +DDP_COMM_HOOK_CHOICES = ChoiceEnum(["none", "fp16"]) DATASET_IMPL_CHOICES = ChoiceEnum(["raw", "lazy", "cached", "mmap", "fasta"]) GENERATION_CONSTRAINTS_CHOICES = ChoiceEnum(["ordered", "unordered"]) GENERATION_DECODING_FORMAT_CHOICES = ChoiceEnum( diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index 3422faea74..6af288b10e 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -18,6 +18,7 @@ ModuleProxyWrapper, TPUDistributedDataParallel, ) +from torch.distributed.algorithms.ddp_comm_hooks import register_ddp_comm_hook, DDPCommHookType logger = logging.getLogger(__name__) @@ -64,6 +65,9 @@ def DistributedFairseqModel(args, model, process_group, device): process_group=process_group, find_unused_parameters=args.find_unused_parameters, ) + if args.ddp_comm_hook == 'fp16': + logger.info("enable fp16 communication hook in DDP") + register_ddp_comm_hook(DDPCommHookType.FP16_COMPRESS, wrapped_model) # forward missing getattr and state_dict/load_state_dict to orig model wrapped_model = ModuleProxyWrapper(wrapped_model) elif args.ddp_backend in {"no_c10d", "legacy_ddp"}: From a2314b4e8a2a769eca073e87cef9e52f0e01ec08 Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Mon, 10 May 2021 02:24:17 -0700 Subject: [PATCH 330/774] offload state_dict to cpu Summary: state_dict is summoned during checkpoint to GPU0. unfortunately with large models this will exceed single GPU memory limit. Moving it to cpu. Question for Myle: should we set this option as default? when saving checkpoint the state_dict would eventually be moved to CPU any way. Reviewed By: myleott Differential Revision: D28203587 fbshipit-source-id: e738f48c83e35873c46bcec3471d105f2b4f4d8e --- fairseq/distributed/fully_sharded_data_parallel.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fairseq/distributed/fully_sharded_data_parallel.py b/fairseq/distributed/fully_sharded_data_parallel.py index 9c290b3fda..ff66c0b1d1 100644 --- a/fairseq/distributed/fully_sharded_data_parallel.py +++ b/fairseq/distributed/fully_sharded_data_parallel.py @@ -7,13 +7,13 @@ from typing import Optional import torch - from fairseq.dataclass.configs import DistributedTrainingConfig from fairseq.distributed import utils as dist_utils try: from fairscale.nn.data_parallel import FullyShardedDataParallel as FSDP + has_FSDP = True except ImportError: FSDP = torch.nn.Module @@ -50,7 +50,7 @@ def unwrapped_module(self) -> torch.nn.Module: else: return self.module - def state_dict(self, destination=None, prefix='', keep_vars=False): + def state_dict(self, destination=None, prefix="", keep_vars=False): if self.use_sharded_state: return super().local_state_dict( destination=destination, prefix=prefix, keep_vars=keep_vars @@ -90,6 +90,7 @@ def fsdp_enable_wrap(cfg: DistributedTrainingConfig, use_sharded_state: bool = F group = dist_utils.get_data_parallel_group() if group is None and cfg.distributed_world_size == 1: from fairscale.utils.testing import DummyProcessGroup + group = DummyProcessGroup(rank=0, size=1) fsdp_config = { "process_group": group, @@ -100,6 +101,7 @@ def fsdp_enable_wrap(cfg: DistributedTrainingConfig, use_sharded_state: bool = F "cpu_offload": cfg.cpu_offload, "compute_dtype": torch.float16 if cfg.fp16 else torch.float32, "bucket_cap_mb": cfg.bucket_cap_mb, + "state_dict_device": torch.device("cpu"), # reduce GPU mem usage } with enable_wrap( wrapper_cls=FullyShardedDataParallel, @@ -120,6 +122,7 @@ def fsdp_wrap(module, min_num_params: Optional[int] = None, **kwargs): """ try: from fairscale.nn import wrap + if min_num_params is not None: num_params = sum(p.numel() for p in module.parameters()) if num_params >= min_num_params: From 97969ac5f52090fd172f508975a3e9069c57e1af Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Mon, 10 May 2021 23:42:41 -0700 Subject: [PATCH 331/774] --combine-valid-sets (#1843) Summary: - `--combine-valid-sets` causes valid.bin, valid1.bin, ... to be concatenated. All metrics will be reported together. - `--valid-subsets` works the same. If you pass `--valid-subsets valid1,valid2` you get valid1_loss and valid2_loss logged separately. - if user passes `--valid-subset valid` (the default) and we see files named valid1, valid2 we raise an error. User must pass `--ignore-unused-valid-sets` to override. This previously led to valid1, valid2 being silently ignored. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1843 Reviewed By: myleott Differential Revision: D28323815 Pulled By: sshleifer fbshipit-source-id: dfd46076d3f684e36f8dacfadd38fd0038ce6755 --- fairseq/data/data_utils.py | 36 +++++++- fairseq/dataclass/configs.py | 13 +++ fairseq/tasks/language_modeling.py | 2 +- fairseq_cli/train.py | 10 ++- tests/test_valid_subset_checks.py | 128 +++++++++++++++++++++++++++++ 5 files changed, 182 insertions(+), 7 deletions(-) create mode 100644 tests/test_valid_subset_checks.py diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 63c7fcd118..8c5e5a490d 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -10,7 +10,7 @@ import contextlib import itertools import logging -import os +import re import warnings from typing import Optional, Tuple @@ -18,7 +18,8 @@ import torch from fairseq.file_io import PathManager - +from fairseq import utils +import os logger = logging.getLogger(__name__) @@ -68,7 +69,6 @@ def copy_tensor(src, dst): copy_tensor(v, res[i][size - len(v) :] if left_pad else res[i][: len(v)]) return res - def load_indexed_dataset( path, dictionary=None, dataset_impl=None, combine=False, default="cached" ): @@ -558,3 +558,33 @@ def get_bucketed_sizes(orig_sizes, buckets): sizes[mask] = end_val start_val = end_val return sizes + + + +def _find_extra_valid_paths(dataset_path: str) -> set: + paths = utils.split_paths(dataset_path) + all_valid_paths = set() + for sub_dir in paths: + contents = PathManager.ls(sub_dir) + valid_paths = [c for c in contents if re.match("valid*[0-9].*", c) is not None] + all_valid_paths |= {os.path.basename(p) for p in valid_paths} + # Remove .bin, .idx etc + roots = {os.path.splitext(p)[0] for p in all_valid_paths} + return roots + + +def raise_if_valid_subsets_unintentionally_ignored(train_cfg) -> None: + """Raises if there are paths matching 'valid*[0-9].*' which are not combined or ignored.""" + if ( + train_cfg.dataset.ignore_unused_valid_subsets + or train_cfg.dataset.combine_valid_subsets + or train_cfg.dataset.disable_validation + ): + return + other_paths = _find_extra_valid_paths(train_cfg.task.data) + specified_subsets = train_cfg.dataset.valid_subset.split(",") + ignored_paths = [p for p in other_paths if p not in specified_subsets] + if ignored_paths: + advice = "Set --combine-val to combine them or --ignore-unused-valid-subsets to ignore them." + msg = f"Valid paths {ignored_paths} will be ignored. {advice}" + raise ValueError(msg) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index f5a405ec76..8bd246c8c4 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -426,6 +426,19 @@ class DatasetConfig(FairseqDataclass): " (e.g. train, valid, test)" }, ) + combine_valid_subsets: Optional[bool] = field( + default=None, + metadata={ + "help": "comma separated list of data subsets to use for validation" + " (e.g. train, valid, test)", + "argparse_alias": "--combine-val", + }, + ) + ignore_unused_valid_subsets: Optional[bool] = field( + default=False, + metadata={"help": "do not raise error if valid subsets are ignored"}, + ) + validate_interval: int = field( default=1, metadata={"help": "validate every N epochs"} ) diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index 3069490fdc..4b76a51c61 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -201,7 +201,7 @@ def load_dataset( """Load a given dataset split. Args: - split (str): name of the split (e.g., train, valid, test) + split (str): name of the split (e.g., train, valid, valid1, test) """ paths = utils.split_paths(self.args.data) assert len(paths) > 0 diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index c1f2fbb4c7..cb49915827 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -23,7 +23,7 @@ tasks, utils, ) -from fairseq.data import iterators +from fairseq.data import iterators, data_utils from fairseq.data.plasma_utils import PlasmaStore from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf @@ -114,8 +114,12 @@ def main(cfg: FairseqConfig) -> None: # Load valid dataset (we load training data below, based on the latest checkpoint) # We load the valid dataset AFTER building the model - for valid_sub_split in cfg.dataset.valid_subset.split(","): - task.load_dataset(valid_sub_split, combine=False, epoch=1) + data_utils.raise_if_valid_subsets_unintentionally_ignored(cfg) + if cfg.dataset.combine_valid_subsets: + task.load_dataset("valid", combine=True, epoch=1) + else: + for valid_sub_split in cfg.dataset.valid_subset.split(","): + task.load_dataset(valid_sub_split, combine=False, epoch=1) # (optionally) Configure quantization if cfg.common.quantization_config_path is not None: diff --git a/tests/test_valid_subset_checks.py b/tests/test_valid_subset_checks.py new file mode 100644 index 0000000000..ab778fb3fa --- /dev/null +++ b/tests/test_valid_subset_checks.py @@ -0,0 +1,128 @@ +import os +import shutil +import tempfile +import unittest + +from fairseq import options +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.data.data_utils import raise_if_valid_subsets_unintentionally_ignored +from .utils import create_dummy_data, preprocess_lm_data, train_language_model + + +def make_lm_config( + data_dir, + extra_flags=None, + task="language_modeling", + arch="transformer_lm_gpt2_tiny", +): + train_parser = options.get_training_parser() + train_args = options.parse_args_and_arch( + train_parser, + [ + "--task", + task, + data_dir, + "--arch", + arch, + "--optimizer", + "adam", + "--lr", + "0.0001", + "--max-tokens", + "500", + "--tokens-per-sample", + "500", + "--save-dir", + data_dir, + "--max-epoch", + "1", + ] + + (extra_flags or []), + ) + cfg = convert_namespace_to_omegaconf(train_args) + return cfg + + +def write_empty_file(path): + with open(path, "w"): + pass + assert os.path.exists(path) + + +class TestValidSubsetsErrors(unittest.TestCase): + """Test various filesystem, clarg combinations and ensure that error raising happens as expected""" + + def _test_case(self, paths, extra_flags): + with tempfile.TemporaryDirectory() as data_dir: + [ + write_empty_file(os.path.join(data_dir, f"{p}.bin")) + for p in paths + ["train"] + ] + cfg = make_lm_config(data_dir, extra_flags=extra_flags) + raise_if_valid_subsets_unintentionally_ignored(cfg) + + def test_default_raises(self): + with self.assertRaises(ValueError): + self._test_case(["valid", "valid1"], []) + with self.assertRaises(ValueError): + self._test_case( + ["valid", "valid1", "valid2"], ["--valid-subset", "valid,valid1"] + ) + + def partially_specified_valid_subsets(self): + with self.assertRaises(ValueError): + self._test_case( + ["valid", "valid1", "valid2"], ["--valid-subset", "valid,valid1"] + ) + # Fix with ignore unused + self._test_case( + ["valid", "valid1", "valid2"], + ["--valid-subset", "valid,valid1", "--ignore-unused-valid-subsets"], + ) + + def test_legal_configs(self): + self._test_case(["valid"], []) + self._test_case(["valid", "valid1"], ["--ignore-unused-valid-subsets"]) + self._test_case(["valid", "valid1"], ["--combine-val"]) + self._test_case(["valid", "valid1"], ["--valid-subset", "valid,valid1"]) + self._test_case(["valid", "valid1"], ["--valid-subset", "valid1"]) + self._test_case( + ["valid", "valid1"], ["--combine-val", "--ignore-unused-valid-subsets"] + ) + self._test_case( + ["valid1"], ["--valid-subset", "valid1"] + ) # valid.bin doesn't need to be ignored. + + def test_disable_validation(self): + self._test_case([], ["--disable-validation"]) + self._test_case(["valid", "valid1"], ["--disable-validation"]) + + +class TestCombineValidSubsets(unittest.TestCase): + def _train(self, extra_flags): + with self.assertLogs() as logs: + with tempfile.TemporaryDirectory("test_transformer_lm") as data_dir: + create_dummy_data(data_dir, num_examples=20) + preprocess_lm_data(data_dir) + + shutil.copyfile(f"{data_dir}/valid.bin", f"{data_dir}/valid1.bin") + shutil.copyfile(f"{data_dir}/valid.idx", f"{data_dir}/valid1.idx") + train_language_model( + data_dir, + "transformer_lm", + ["--max-update", "0", "--log-format", "json"] + extra_flags, + run_validation=False, + ) + return [x.message for x in logs.records] + + def test_combined(self): + flags = ["--combine-valid-subsets"] + logs = self._train(flags) + assert any(["valid1" in x for x in logs]) # loaded 100 examples from valid1 + assert not any(["valid1_ppl" in x for x in logs]) # metrics are combined + + def test_subsets(self): + flags = ["--valid-subset", "valid,valid1"] + logs = self._train(flags) + assert any(["valid_ppl" in x for x in logs]) # loaded 100 examples from valid1 + assert any(["valid1_ppl" in x for x in logs]) # metrics are combined From 8f1a34af7cb6e92fa3c443e61803e0ff347a784e Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Wed, 12 May 2021 09:01:06 -0700 Subject: [PATCH 332/774] add zip file support to raw_audio_dataset Summary: Add zip file support to raw_audio_dataset - Allow reading WAV/FLAC/OGG audios from stored zip file with given byte offset and length - Path format in the manifest TSV: `[zip_path]:[byte_offset]:[byte_length]` (e.g. `en/flac.zip:33255867035:212288`) - Packing audios in small number of zip files facilitates file management and improves loading speed (avoiding random access of many small audio files) Reviewed By: jmp84 Differential Revision: D28343999 fbshipit-source-id: a9cd2fbeb6e318cf9787065beb3bbddac25d0aba --- fairseq/data/audio/audio_utils.py | 46 +++++++++++++++++++- fairseq/data/audio/raw_audio_dataset.py | 15 ++++++- fairseq/data/audio/speech_to_text_dataset.py | 44 ++++++------------- 3 files changed, 71 insertions(+), 34 deletions(-) diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index ddd5642c7e..f51cb0cddc 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -1,11 +1,12 @@ from pathlib import Path -from typing import BinaryIO, Optional, Tuple, Union +from typing import BinaryIO, Optional, Tuple, Union, List import numpy as np import torch SF_AUDIO_FILE_EXTENSIONS = {".wav", ".flac", ".ogg"} +FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS = {".npy", ".wav", ".flac", ".ogg"} def _convert_to_mono( @@ -128,3 +129,46 @@ def get_fbank(path_or_fp: Union[str, BinaryIO], n_bins=80) -> np.ndarray: ) return features + + +def is_npy_data(data: bytes) -> bool: + return data[0] == 147 and data[1] == 78 + + +def is_sf_audio_data(data: bytes) -> bool: + is_wav = (data[0] == 82 and data[1] == 73 and data[2] == 70) + is_flac = (data[0] == 102 and data[1] == 76 and data[2] == 97) + is_ogg = (data[0] == 79 and data[1] == 103 and data[2] == 103) + return is_wav or is_flac or is_ogg + + +def read_from_stored_zip(zip_path: str, offset: int, file_size: int) -> bytes: + with open(zip_path, "rb") as f: + f.seek(offset) + data = f.read(file_size) + return data + + +def parse_path(path: str) -> Tuple[str, List[int]]: + """Parse data path which is either a path to + 1. a .npy/.wav/.flac/.ogg file + 2. a stored ZIP file with slicing info: "[zip_path]:[offset]:[length]" + + Args: + path (str): the data path to parse + + Returns: + file_path (str): the file path + slice_ptr (list of int): empty in case 1; + byte offset and length for the slice in case 2 + """ + + if Path(path).suffix in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: + _path, slice_ptr = path, [] + else: + _path, *slice_ptr = path.split(":") + if not Path(_path).is_file(): + raise FileNotFoundError(f"File not found: {_path}") + assert len(slice_ptr) in {0, 2}, f"Invalid path: {path}" + slice_ptr = [int(i) for i in slice_ptr] + return _path, slice_ptr diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 1f945993a8..1ceef8ce06 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -7,6 +7,7 @@ import logging import os import sys +import io import numpy as np import torch @@ -14,6 +15,9 @@ from .. import FairseqDataset, BaseWrapperDataset from ..data_utils import compute_mask_indices, get_buckets, get_bucketed_sizes +from fairseq.data.audio.audio_utils import ( + parse_path, read_from_stored_zip, is_sf_audio_data +) logger = logging.getLogger(__name__) @@ -295,8 +299,15 @@ def __init__( def __getitem__(self, index): import soundfile as sf - fname = os.path.join(self.root_dir, str(self.fnames[index])) - wav, curr_sample_rate = sf.read(fname) + path_or_fp = os.path.join(self.root_dir, self.fnames[index]) + _path, slice_ptr = parse_path(path_or_fp) + if len(slice_ptr) == 2: + byte_data = read_from_stored_zip(_path, slice_ptr[0], slice_ptr[1]) + assert is_sf_audio_data(byte_data) + path_or_fp = io.BytesIO(byte_data) + + wav, curr_sample_rate = sf.read(path_or_fp, dtype="float32") + feats = torch.from_numpy(wav).float() feats = self.postprocess(feats, curr_sample_rate) return {"id": index, "source": feats} diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index c6c64db084..b889ff5356 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -19,7 +19,10 @@ ResamplingDataset, data_utils as fairseq_data_utils, ) -from fairseq.data.audio.audio_utils import get_fbank, get_waveform +from fairseq.data.audio.audio_utils import ( + get_fbank, get_waveform, read_from_stored_zip, is_npy_data, + is_sf_audio_data, parse_path, FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS +) from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform @@ -120,39 +123,22 @@ def get_feature_transforms(self, split, is_train): return cfg -def is_npy_data(data: bytes) -> bool: - return data[0] == 147 and data[1] == 78 - - -def is_flac_or_wav_data(data: bytes) -> bool: - is_flac = data[0] == 102 and data[1] == 76 - is_wav = data[0] == 82 and data[1] == 73 - return is_flac or is_wav - - -def read_from_uncompressed_zip(file_path, offset, file_size) -> bytes: - with open(file_path, "rb") as f: - f.seek(offset) - data = f.read(file_size) - return data - - def get_features_from_npy_or_audio(path): ext = op.splitext(op.basename(path))[1] - if ext not in {".npy", ".flac", ".wav"}: + if ext not in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: raise ValueError(f'Unsupported file format for "{path}"') return np.load(path) if ext == ".npy" else get_fbank(path) -def get_features_or_waveform_from_uncompressed_zip( +def get_features_or_waveform_from_stored_zip( path, byte_offset, byte_size, need_waveform=False ): assert path.endswith(".zip") - data = read_from_uncompressed_zip(path, byte_offset, byte_size) + data = read_from_stored_zip(path, byte_offset, byte_size) f = io.BytesIO(data) if is_npy_data(data): features_or_waveform = np.load(f) - elif is_flac_or_wav_data(data): + elif is_sf_audio_data(data): features_or_waveform = \ get_waveform(f, always_2d=False)[0] if need_waveform else get_fbank(f) else: @@ -173,18 +159,14 @@ def get_features_or_waveform(path: str, need_waveform=False): Returns: features_or_waveform (numpy.ndarray): speech features or waveform. """ - _path, *extra = path.split(":") - if not op.exists(_path): - raise FileNotFoundError(f"File not found: {_path}") - - if len(extra) == 0: + _path, slice_ptr = parse_path(path) + if len(slice_ptr) == 0: if need_waveform: return get_waveform(_path, always_2d=False) return get_features_from_npy_or_audio(_path) - elif len(extra) == 2: - extra = [int(i) for i in extra] - features_or_waveform = get_features_or_waveform_from_uncompressed_zip( - _path, extra[0], extra[1], need_waveform=need_waveform + elif len(slice_ptr) == 2: + features_or_waveform = get_features_or_waveform_from_stored_zip( + _path, slice_ptr[0], slice_ptr[1], need_waveform=need_waveform ) else: raise ValueError(f"Invalid path: {path}") From d151f2787240cca4e3c7e47640e647f8ae028c37 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Wed, 12 May 2021 18:03:01 -0700 Subject: [PATCH 333/774] S2T example bug fixes Summary: S2T example bug fixes Reviewed By: jmp84 Differential Revision: D27930414 fbshipit-source-id: 14edc85a34094a4fff53646390d366b39ffd8206 --- examples/speech_to_text/docs/librispeech_example.md | 4 ++-- examples/speech_to_text/docs/mustc_example.md | 8 ++++---- fairseq/data/audio/speech_to_text_dataset.py | 4 ++-- fairseq/models/speech_to_text/s2t_transformer.py | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/speech_to_text/docs/librispeech_example.md b/examples/speech_to_text/docs/librispeech_example.md index 4749e6cecc..4040fda942 100644 --- a/examples/speech_to_text/docs/librispeech_example.md +++ b/examples/speech_to_text/docs/librispeech_example.md @@ -23,9 +23,9 @@ if you want to use our pre-trained models. ## Training ```bash fairseq-train ${LS_ROOT} --save-dir ${SAVE_DIR} \ - --config-yaml config.yaml --train-subset train --valid-subset dev \ + --config-yaml config.yaml --train-subset train-clean-100,train-clean-360,train-other-500 --valid-subset dev-clean,dev-other \ --num-workers 4 --max-tokens 40000 --max-update 300000 \ - --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --report-accuracy \ --arch s2t_transformer_s --share-decoder-input-output-embed \ --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt --warmup-updates 10000 \ --clip-norm 10.0 --seed 1 --update-freq 8 diff --git a/examples/speech_to_text/docs/mustc_example.md b/examples/speech_to_text/docs/mustc_example.md index 79df0aafdc..c95ef3e156 100644 --- a/examples/speech_to_text/docs/mustc_example.md +++ b/examples/speech_to_text/docs/mustc_example.md @@ -45,7 +45,7 @@ En-De as example: fairseq-train ${MUSTC_ROOT}/en-de \ --config-yaml config_asr.yaml --train-subset train_asr --valid-subset dev_asr \ --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ - --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --report-accuracy \ --arch s2t_transformer_s --optimizer adam --lr 1e-3 --lr-scheduler inverse_sqrt \ --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 ``` @@ -56,7 +56,7 @@ fairseq-train ${MUSTC_ROOT} \ --train-subset train_de_asr,train_nl_asr,train_es_asr,train_fr_asr,train_it_asr,train_pt_asr,train_ro_asr,train_ru_asr \ --valid-subset dev_de_asr,dev_nl_asr,dev_es_asr,dev_fr_asr,dev_it_asr,dev_pt_asr,dev_ro_asr,dev_ru_asr \ --save-dir ${JOINT_ASR_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ - --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --report-accuracy \ --arch s2t_transformer_s --optimizer adam --lr 1e-3 --lr-scheduler inverse_sqrt \ --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 ``` @@ -98,7 +98,7 @@ En-De as example: fairseq-train ${MUSTC_ROOT}/en-de \ --config-yaml config_st.yaml --train-subset train_st --valid-subset dev_st \ --save-dir ${ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ - --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --report-accuracy \ --arch s2t_transformer_s --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} @@ -110,7 +110,7 @@ fairseq-train ${MUSTC_ROOT} \ --train-subset train_de_st,train_nl_st,train_es_st,train_fr_st,train_it_st,train_pt_st,train_ro_st,train_ru_st \ --valid-subset dev_de_st,dev_nl_st,dev_es_st,dev_fr_st,dev_it_st,dev_pt_st,dev_ro_st,dev_ru_st \ --save-dir ${MULTILINGUAL_ST_SAVE_DIR} --num-workers 4 --max-tokens 40000 --max-update 100000 \ - --task speech_to_text --criterion label_smoothed_cross_entropy --report-accuracy \ + --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --report-accuracy \ --arch s2t_transformer_s --ignore-prefix-size 1 --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt \ --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ --load-pretrained-encoder-from ${JOINT_ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index b889ff5356..d4b5668d8f 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -43,9 +43,9 @@ def __init__(self, yaml_path): with open(yaml_path) as f: self.config = yaml.load(f, Loader=yaml.FullLoader) except Exception as e: - logger.info(f"Failed to load config from {yaml_path}: {e}") + raise Exception(f"Failed to load config from {yaml_path}: {e}") else: - logger.info(f"Cannot find {yaml_path}") + raise FileNotFoundError(f"{yaml_path} not found") @property def vocab_filename(self): diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 7480dc7967..ff3d2100c7 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -279,7 +279,7 @@ class S2TTransformerEncoder(FairseqEncoder): def __init__(self, args): super().__init__(None) - self.encoder_freezing_updates = args.encoder_freezing_updates + self.encoder_freezing_updates = getattr(args, "encoder_freezing_updates", 0) self.num_updates = 0 self.dropout_module = FairseqDropout( From 425c36eafff535fe7337f8bdd5ace22ebacc78cb Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Fri, 14 May 2021 18:52:06 -0700 Subject: [PATCH 334/774] support use_sharded_state on command line Summary: we wanted to use sharded_state because 1. to save memory 2. support sharded state loading, which allows MoE models's weight to live on their respective shard I just added the use_sharded_state as a config option, and added unit test to make sure it runs fine. old revision's comment: fairseq.FSDP has a flag use_sharded_state, but I had to address a couple problems before being able to use it. 1. fairscale FSDP (FSDP for short) calls self.state_dict/load_state_dict, which has been overwritten by fairseq.FSDP, this is not a desired behavior 2. the optimizer states shouldn't be sharded again when use_sharded_state is True 3. expose this option on the command line. Reviewed By: sshleifer Differential Revision: D28375035 fbshipit-source-id: c2f59a9c62163405033f34ed595ba78528aea850 --- fairseq/dataclass/configs.py | 3 +++ fairseq/distributed/fully_sharded_data_parallel.py | 4 ++-- fairseq/trainer.py | 3 ++- tests/gpu/test_binaries_gpu.py | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 8bd246c8c4..f41cfcd94f 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -379,6 +379,9 @@ class DistributedTrainingConfig(FairseqDataclass): cpu_offload: bool = field( default=False, metadata={"help": "offload FP32 params to CPU"} ) + use_sharded_state: bool = field( + default=False, metadata={"help": "use sharded checkpoint files"}, + ) @dataclass diff --git a/fairseq/distributed/fully_sharded_data_parallel.py b/fairseq/distributed/fully_sharded_data_parallel.py index ff66c0b1d1..8a96bfc765 100644 --- a/fairseq/distributed/fully_sharded_data_parallel.py +++ b/fairseq/distributed/fully_sharded_data_parallel.py @@ -77,7 +77,7 @@ def load_state_dict(self, state_dict, strict=True, model_cfg=None): @contextlib.contextmanager -def fsdp_enable_wrap(cfg: DistributedTrainingConfig, use_sharded_state: bool = False): +def fsdp_enable_wrap(cfg: DistributedTrainingConfig): try: from fairscale.nn import enable_wrap except ImportError: @@ -105,7 +105,7 @@ def fsdp_enable_wrap(cfg: DistributedTrainingConfig, use_sharded_state: bool = F } with enable_wrap( wrapper_cls=FullyShardedDataParallel, - use_sharded_state=use_sharded_state, + use_sharded_state=cfg.use_sharded_state, **fsdp_config, ): yield diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 0b70a97356..dc06928dfc 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -496,7 +496,8 @@ def load_checkpoint( last_optim_state = self.optimizer.broadcast_global_state_dict( last_optim_state ) - elif self.cfg.distributed_training.ddp_backend == 'fully_sharded': + elif self.cfg.distributed_training.ddp_backend == 'fully_sharded' and not self.model.use_sharded_state: + # if use_sharded_state, the last_optim_state is already sharded, skip this last_optim_state = self.model.get_shard_from_optim_state_dict(last_optim_state) self.optimizer.load_state_dict(last_optim_state, optimizer_overrides) diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 45417c7eb7..a0824c23ad 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -59,6 +59,9 @@ def parse_logs(logfile): def test_resume_training_fsdp(self): self._test_resume_training(["--ddp-backend", "fully_sharded"]) + def test_resume_training_fsdp_sharded_state(self): + self._test_resume_training(["--ddp-backend", "fully_sharded", "--use-sharded-state"]) + def test_resume_training_noc10d(self): self._test_resume_training([]) From a1fea2eb0e5a68c9f91b18a344056675332181a3 Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines <mandeep.baines@gmail.com> Date: Thu, 20 May 2021 14:04:37 -0700 Subject: [PATCH 335/774] enable pin_memory for DataLoaders (#3560) Summary: To avoid the creation of a cuda:0 context, I needed to make sure that the `BackgroundConsumer` thread had its cuda device context set to the correct GPU. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3560 Reviewed By: myleott Differential Revision: D28573071 Pulled By: msbaines fbshipit-source-id: c2bedf67d8f356a29fa82eb4d8f15983efce3ffc --- fairseq/data/iterators.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 293d853822..8321a49b54 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -214,6 +214,7 @@ def _get_iterator_for_epoch(self, epoch, shuffle, offset=0): num_workers=self.num_workers, timeout=self.timeout, worker_init_fn=worker_init_fn, + pin_memory=True, ) # Wrap with a BufferedIterator if needed @@ -469,6 +470,7 @@ def shuffle_batches(batches, seed): batch_sampler=batches[offset:], num_workers=self.num_workers, timeout=self.timeout, + pin_memory=True, ) # Wrap with a BufferedIterator if needed @@ -546,15 +548,20 @@ def __init__(self, iterable, num_shards, shard_id, fill_value=None): class BackgroundConsumer(Thread): - def __init__(self, queue, source, max_len): + def __init__(self, queue, source, max_len, cuda_device): Thread.__init__(self) self._queue = queue self._source = source self._max_len = max_len self.count = 0 + self.cuda_device = cuda_device def run(self): + # set_device to avoid creation of GPU0 context when using pin_memory + if self.cuda_device is not None: + torch.cuda.set_device(self.cuda_device) + try: for item in self._source: self._queue.put(item) @@ -586,6 +593,7 @@ def _create_consumer(self): self._queue, self._iterable, self.total, + torch.cuda.current_device() if torch.cuda.is_available() else None ) self._consumer.daemon = True self._consumer.start() From f68de08a7326d1915461b84ad8e6ccb979d39578 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Thu, 20 May 2021 21:39:31 -0700 Subject: [PATCH 336/774] Auto formatting changes Summary: TSIA Reviewed By: jmp84 Differential Revision: D28523558 fbshipit-source-id: 97a90050e426be071f59127596a84bf71ede476d --- .../models/speech_to_text/convtransformer.py | 10 ++++----- fairseq/models/transformer.py | 21 +++++++++++-------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py index 40e6dd3f4e..eba000d7b0 100644 --- a/fairseq/models/speech_to_text/convtransformer.py +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -7,8 +7,8 @@ import torch import torch.nn as nn import torch.nn.functional as F -from fairseq.data.data_utils import lengths_to_padding_mask from fairseq import checkpoint_utils, utils +from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import ( FairseqEncoder, FairseqEncoderDecoderModel, @@ -28,6 +28,7 @@ class ConvTransformerModel(FairseqEncoderDecoderModel): Transformer-based Speech translation model from ESPNet-ST https://arxiv.org/abs/2004.10234 """ + def __init__(self, encoder, decoder): super().__init__(encoder, decoder) @@ -304,10 +305,10 @@ def forward(self, src_tokens, src_lengths): subsampling_factor = int(max_seq_len * 1.0 / output_seq_len + 0.5) input_len_0 = (src_lengths.float() / subsampling_factor).ceil().long() - input_len_1 = x.size(0) * torch.ones([src_lengths.size(0)]).long().to(input_len_0.device) - input_lengths = torch.min( - input_len_0, input_len_1 + input_len_1 = x.size(0) * torch.ones([src_lengths.size(0)]).long().to( + input_len_0.device ) + input_lengths = torch.min(input_len_0, input_len_1) encoder_padding_mask = lengths_to_padding_mask(input_lengths) @@ -323,7 +324,6 @@ def forward(self, src_tokens, src_lengths): else: maybe_encoder_padding_mask = encoder_padding_mask - return { "encoder_out": [x], "encoder_padding_mask": [maybe_encoder_padding_mask] diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index f5d1af4477..b7b8783fa2 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -417,7 +417,8 @@ def build_encoder_layer(self, args): # checkpointed layer, regardless of layer size min_params_to_wrap = ( getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) - if not checkpoint else 0 + if not checkpoint + else 0 ) layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) return layer @@ -468,10 +469,9 @@ def forward( hidden states of shape `(src_len, batch, embed_dim)`. Only populated if *return_all_hiddens* is True. """ - return self.forward_scriptable(src_tokens, - src_lengths, - return_all_hiddens, - token_embeddings) + return self.forward_scriptable( + src_tokens, src_lengths, return_all_hiddens, token_embeddings + ) # TorchScript doesn't support super() method so that the scriptable Subclass # can't access the base class model in Torchscript. @@ -509,7 +509,7 @@ def forward_scriptable( """ # compute padding mask encoder_padding_mask = src_tokens.eq(self.padding_idx) - has_pads = (src_tokens.device.type == "xla" or encoder_padding_mask.any()) + has_pads = src_tokens.device.type == "xla" or encoder_padding_mask.any() x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) @@ -767,8 +767,10 @@ def build_output_projection(self, args, dictionary, embed_tokens): ) num_base_layers = getattr(args, "base_layers", 0) for i in range(num_base_layers): - self.layers.insert(((i+1) * args.decoder_layers) // (num_base_layers + 1), BaseLayer(args)) - + self.layers.insert( + ((i + 1) * args.decoder_layers) // (num_base_layers + 1), + BaseLayer(args), + ) def build_decoder_layer(self, args, no_encoder_attn=False): layer = TransformerDecoderLayer(args, no_encoder_attn) @@ -780,7 +782,8 @@ def build_decoder_layer(self, args, no_encoder_attn=False): # checkpointed layer, regardless of layer size min_params_to_wrap = ( getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) - if not checkpoint else 0 + if not checkpoint + else 0 ) layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) return layer From a5df5de926838c2d3b890c7b97fd68d7883cec2a Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 20 May 2021 23:20:14 -0700 Subject: [PATCH 337/774] wav2vec_u_readme (#1888) Summary: initial wav2vec-U readme to be updated Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1888 Reviewed By: michaelauli Differential Revision: D28595427 Pulled By: alexeib fbshipit-source-id: 8e1baca8a367f9b38a66e58489ad127341214f58 --- examples/wav2vec/unsupervised/README.md | 175 ++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 examples/wav2vec/unsupervised/README.md diff --git a/examples/wav2vec/unsupervised/README.md b/examples/wav2vec/unsupervised/README.md new file mode 100644 index 0000000000..fdfcc04d26 --- /dev/null +++ b/examples/wav2vec/unsupervised/README.md @@ -0,0 +1,175 @@ + +# wav2vec Unsupervised (wav2vec-U) + +Wav2vec Unsupervised (wav2vec-U) is a framework for building speech recognition systems without any labeled training data as described in [Unsupervised Speech Recognition (Baevski et al., 2021)](https://ai.facebook.com/research/publications/unsupervised-speech-recognition). The model takes as input wav2vec 2.0 or XLSR representations (see [pretrained models](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec)) as well as unlabeled speech and text data. + + The wav2vec-U training procedure consists of three consecutive main steps: +* Preparation of speech representations and text data +* Generative adversarial training (GAN) +* Iterative self-training + Kaldi LM-decoding + + +## Preparation of speech and text data +Similar to [wav2vec 2.0](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec/README.md), data folders contain {train,valid,test}.{tsv,wrd,phn} files, where audio paths are stored in tsv files, and word, letter or phoneme transcriptions are stored in .{wrd,ltr,phn}. + + +In **/path/to/data/with_silence** you need a *train.tsv* file as well as *{valid,test}.{tsv,wrd,phn}*. It is nice to have *10h.{tsv,phn}* files there too for reproducing the ablation study on layer selection. In **/path/to/data/without_silence** you have the same files, except *.tsv* files contain audios with silences removed using rVAD. + +Here is how you can create new audio files without silences from a list of input audio files: +``` +python scripts/unsupervised/remove_silences.py /path/to/data/with_silence/train.tsv \ + --save-dir /path/to/data/without_silence/audio \ + --output /path/to/data/without_silence/train.tsv & +``` + + +In this first part, we use mostly phonemized text. Here is how you can transform a text file into its phonemized .phn version: +``` +# Will phonemize word dictionary and then phonemize text using dict lookup (for language $lg) + +python scripts/unsupervised/phonemize.py $path_to_wrd_dict $lg < text.wrd > text.phn & + +``` +Next, you can reproduce Figure 2/3 of the wav2vec-U paper by training linear models on top of each layer's frozen wav2vec 2.0 representations, using supervised data. You can observe that certain layers provide lower PER, which shows the closeness of their representations to phoneme outputs. Note that this step requires supervision and is thus not necessary. + +``` +# Learn linear model on top of layer N(=15) using supervised data + +fairseq-hydra-train \ + distributed_training.distributed_port=$PORT \ + task.data=/path/to/data/without_silence \ + model.w2v_path=/path/to/model.pt \ + model.layer=15 \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/finetuning \ + --config-name vox_10h_phn +``` + + + +We can extract features of layer *N* using the following: +``` +# Extract features from layer N +split=train # valid test +python scripts/unsupervised/fb_wav2vec_ctc_filter.py \ + /path/to/data/without_silence \ + --split $split \ + --layer=15 \ + --checkpoint /path/to/model.pt \ + --save-dir /path/to/features & +``` + + + +Next we perform clustering of wav2vec representations (step 2 in the paper): +``` +# Identify clusters in the representations with k-means + +python scripts/unsupervised/fb_wav2vec_cluster_faiss.py \ + /path/to/data/train.tsv \ + -f "CLUS128" \ + --sample-pct 0.5 \ + --layer 15 \ + --checkpoint /path/to/model.pt \ + --save-dir /path/to/features/clustering/segmented & +``` + +And use those clusters to segment the audio data (step 3 in the paper): +``` +# Transcribe cluster ids of audio data +python scripts/unsupervised/fb_wav2vec_apply_cluster_faiss.py \ + /path/to/data \ + --split $split \ + --checkpoint /path/to/model.pt \ + --path /path/to/features/clustering/segmented/CLUS128 & +``` + + Learn and apply PCA to the representations to retain important features +``` +# Compute PCA +python scripts/pca.py \ + /path/to/features/unfiltered/train.npy \ + --dim 512 \ + --output /path/to/features/unfiltered/unfiltered_pca + +# Apply PCA +python scripts/apply_pca.py \ + $outdir \ + --split $split \ + --pca-path /path/to/features/unfiltered/unfiltered_pca/512_pca \ + --batch-size 1048000 \ + --save-dir /path/to/features/unfiltered/precompute_unfiltered_pca${dim} +``` + +Then we build segment representations by mean-pooling representations according to clusters: + + + +``` +# Build segment representations + +python scripts/unsupervised/merge_clusters.py \ + /path/to/features/unfiltered/precompute_unfiltered_pca512 \ + --split $split \ + --cluster-dir /path/to/features/clustering/segmented/CLUS128 \ + --pooling mean \ + --save-dir /path/to/features/unfiltered/precompute_unfiltered_pca512_cls128_mean & + +``` +Finally, we found that segment boundaries are noisy due to the lack of supervision and we therefore found it useful to also mean-pool pairs of adjacent segment representations to increase robustness: +``` +# Mean-pool adjacent time steps + +python scripts/unsupervised/mean_pool.py \ + /path/to/features/unfiltered/precompute_unfiltered_pca512_cls128_mean \ + --split $split & + --save-dir $savedir & +``` + +For adversarial training, we preprocess the text data by adding silence tokens. +``` +# Add <SIL> tokens on text in preparation for GAN training +python scripts/unsupervised/fb_wrd_to_phonemizer.py \ + -s 0.25 --surround < /path/to/data/gan.txt > /path/to/data/gan.txt_s0.25.phns & + +# Binarize with fairseq-preprocess +fairseq-preprocess --dataset-impl mmap \ + --trainpref /path/to/data/gan.txt_s0.25.phns \ + --workers 6 --thresholdsrc 0 --only-source \ + --destdir /path/to/data --srcdict /path/to/data/dict.phn.txt & +``` + + +## Generative adversarial training (GAN) + +We then use a GAN model to build a first unsupervised ASR model. The data preparation above of both speech features and text data is a necessary procedure that enables the generator to match speech to text in an unsupervised way. + +Launching GAN training on top of preprocessed features, with default hyperparameters can be done with: + +``` +PREFIX=w2v_unsup_gan_xp +TASK_DATA=/path/to/features/unfiltered/precompute_unfiltered_pca512_cls128_mean_pooled +TEXT_DATA=/path/to/data # path to fairseq-preprocessed GAN data +KENLM_PATH=/path/to/data/kenlm.phn.o4.bin # KenLM 4-gram phoneme language model (LM data = GAN data here) + +PREFIX=$PREFIX fairseq-hydra-train \ + distributed_training.distributed_port=$PORT \ + -m --config-dir configs/unsup \ + --config-name gan_feats_by_label \ + dataset.valid_subset=valid \ + task.data=${TASK_DATA} \ + task.text_data=${TEXT_DATA} \ + task.kenlm_path=${KENLM_PATH} \ + 'common.seed=range(0,5)' & +``` +However, this step requires an hyperparameter search, which can be launched with: +``` + +``` + +Note that hyperparameter search and model/epoch selection are done using a fully unsupervised metric (see Section 4.3). + +## Iterative self-training + Kaldi LM-decoding +After the GAN training provides a first unsupervised model, we can then progressively refine the quality of transcriptions using several iterations of semi-supervised learning. We perform two iterations: first, pseudo-label the training data with the unsupervised GAN model and train an HMM on the pseudo-labels. Second, we relabel the training data with the HMM and then fine-tune the original wav2vec 2.0 model using the HMM pseudo-labels with a CTC loss. Note that HMM models use phonemes as output, while wav2vec 2.0 use letter. Both are decoded using WFST decoders into words. + + +Please see [this README](http://github.com/pytorch/fairseq/tree/master/examples/wav2vec/unsupervised/kaldi_st) for more instructions on how to do iterative self-training + Kaldi LM-decoding. From f9edd9f9b919b5fe77255296c69e052e4a930b2b Mon Sep 17 00:00:00 2001 From: freewym <freewym@gmail.com> Date: Fri, 21 May 2021 00:39:54 -0700 Subject: [PATCH 338/774] fix the error when using pyarrow for raw_audio_dataset (#3561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [X] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [X] Did you write any new necessary tests? ## What does this PR do? fix the error when using pyarrow for raw_audio_dataset, Currently there is an error `TypeError: join() argument must be str, bytes, or os.PathLike object, not 'StringScalar'`. In this PR I just convert the type to string in `__getitem__()` for `os.path.join()` ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3561 Reviewed By: jmp84 Differential Revision: D28594620 Pulled By: kahne fbshipit-source-id: fd2daa992df85ac0919ba30fa9afa67a0c89d956 --- fairseq/data/audio/raw_audio_dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 1ceef8ce06..4cb5193bde 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -299,7 +299,7 @@ def __init__( def __getitem__(self, index): import soundfile as sf - path_or_fp = os.path.join(self.root_dir, self.fnames[index]) + path_or_fp = os.path.join(self.root_dir, str(self.fnames[index])) _path, slice_ptr = parse_path(path_or_fp) if len(slice_ptr) == 2: byte_data = read_from_stored_zip(_path, slice_ptr[0], slice_ptr[1]) From 649af635f40dfdd4ab47e26c5183e69a62f8c49c Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Fri, 21 May 2021 07:33:12 -0700 Subject: [PATCH 339/774] Wav2vec u (#1889) Summary: Wav2vec-U implementation Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1889 Reviewed By: michaelauli Differential Revision: D28596815 Pulled By: alexeib fbshipit-source-id: bb09d081d167d5d10968acc6e056044bf96679ac --- examples/speech_recognition/kaldi/__init__.py | 0 .../kaldi/add-self-loop-simple.cc | 94 +++ .../speech_recognition/kaldi/kaldi_decoder.py | 244 ++++++ .../kaldi/kaldi_initializer.py | 698 +++++++++++++++++ examples/wav2vec/__init__.py | 0 .../wav2vec/config/finetuning/base_960h.yaml | 2 +- examples/wav2vec/unsupervised/README.md | 148 +--- examples/wav2vec/unsupervised/__init__.py | 0 .../config/finetuning/w2v_finetune.yaml | 62 ++ .../wav2vec/unsupervised/config/gan/w2vu.yaml | 108 +++ .../unsupervised/config/generate/viterbi.yaml | 22 + .../wav2vec/unsupervised/data/__init__.py | 13 + .../data/extracted_features_dataset.py | 144 ++++ .../unsupervised/data/random_input_dataset.py | 62 ++ .../unsupervised/kaldi_self_train/README.md | 56 ++ .../unsupervised/kaldi_self_train/st/cmd.sh | 15 + .../kaldi_self_train/st/decode_phone.sh | 33 + .../kaldi_self_train/st/decode_word_step1.sh | 46 ++ .../kaldi_self_train/st/decode_word_step2.sh | 30 + .../st/local/copy_aligned_text.py | 4 + .../kaldi_self_train/st/local/decode.sh | 38 + .../st/local/prepare_data_from_w2v.py | 56 ++ .../kaldi_self_train/st/local/prepare_lang.sh | 37 + .../st/local/prepare_lang_word.sh | 35 + .../kaldi_self_train/st/local/prepare_lm.sh | 35 + .../kaldi_self_train/st/local/score.sh | 63 ++ .../kaldi_self_train/st/local/show_wer.sh | 52 ++ .../st/local/train_subset_lgbeam.sh | 129 ++++ .../kaldi_self_train/st/local/unsup_select.py | 135 ++++ .../st/local/unsup_select_decode.sh | 37 + .../st/local/unsup_select_decode_word.sh | 35 + .../unsupervised/kaldi_self_train/st/path.sh | 5 + .../unsupervised/kaldi_self_train/st/steps | 1 + .../st/steps_gan/train_deltas.sh | 175 +++++ .../st/steps_gan/train_lda_mllt.sh | 239 ++++++ .../st/steps_gan/train_sat.sh | 281 +++++++ .../unsupervised/kaldi_self_train/st/train.sh | 43 ++ .../unsupervised/kaldi_self_train/st/utils | 1 + .../wav2vec/unsupervised/models/__init__.py | 11 + .../wav2vec/unsupervised/models/wav2vec_u.py | 658 ++++++++++++++++ .../wav2vec/unsupervised/scripts/apply_pca.py | 72 ++ .../unsupervised/scripts/copy_labels.py | 10 + .../unsupervised/scripts/filter_lexicon.py | 40 + .../unsupervised/scripts/filter_tsv.py | 37 + .../unsupervised/scripts/g2p_wrd_to_phn.py | 41 + .../unsupervised/scripts/ltr_to_wrd.py | 16 + .../wav2vec/unsupervised/scripts/mean_pool.py | 90 +++ .../unsupervised/scripts/merge_clusters.py | 112 +++ .../scripts/normalize_and_filter_text.py | 57 ++ .../unsupervised/scripts/normalize_text.py | 22 + examples/wav2vec/unsupervised/scripts/pca.py | 53 ++ .../scripts/phonemize_with_sil.py | 83 ++ .../unsupervised/scripts/prepare_audio.sh | 57 ++ .../unsupervised/scripts/prepare_text.sh | 56 ++ .../unsupervised/scripts/remove_silence.py | 64 ++ examples/wav2vec/unsupervised/scripts/vads.py | 81 ++ .../scripts/wav2vec_apply_cluster_faiss.py | 111 +++ .../scripts/wav2vec_cluster_faiss.py | 210 ++++++ .../scripts/wav2vec_extract_features.py | 117 +++ examples/wav2vec/unsupervised/scripts/wer.py | 82 ++ .../unsupervised/scripts/wrd_to_ltr.py | 16 + .../wav2vec/unsupervised/tasks/__init__.py | 11 + .../unsupervised/tasks/unpaired_audio_text.py | 437 +++++++++++ .../wav2vec/unsupervised/w2vu_generate.py | 706 ++++++++++++++++++ examples/wav2vec/wav2vec_manifest.py | 16 +- fairseq/data/audio/raw_audio_dataset.py | 18 +- fairseq/data/data_utils.py | 4 + fairseq/logging/meters.py | 32 + fairseq/logging/metrics.py | 24 +- fairseq/models/distributed_fairseq_model.py | 14 +- fairseq/models/wav2vec/wav2vec2.py | 133 +++- fairseq/models/wav2vec/wav2vec2_asr.py | 88 ++- fairseq/optim/adam.py | 10 +- fairseq/options.py | 2 + fairseq/sequence_generator.py | 18 +- fairseq/tasks/audio_pretraining.py | 15 +- fairseq/utils.py | 48 +- fairseq_cli/eval_lm.py | 2 +- fairseq_cli/hydra_train.py | 17 +- fairseq_cli/preprocess.py | 3 + fairseq_cli/train.py | 7 +- fairseq_cli/validate.py | 1 + 82 files changed, 6625 insertions(+), 255 deletions(-) create mode 100644 examples/speech_recognition/kaldi/__init__.py create mode 100644 examples/speech_recognition/kaldi/add-self-loop-simple.cc create mode 100644 examples/speech_recognition/kaldi/kaldi_decoder.py create mode 100644 examples/speech_recognition/kaldi/kaldi_initializer.py create mode 100644 examples/wav2vec/__init__.py create mode 100644 examples/wav2vec/unsupervised/__init__.py create mode 100644 examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml create mode 100644 examples/wav2vec/unsupervised/config/gan/w2vu.yaml create mode 100644 examples/wav2vec/unsupervised/config/generate/viterbi.yaml create mode 100644 examples/wav2vec/unsupervised/data/__init__.py create mode 100644 examples/wav2vec/unsupervised/data/extracted_features_dataset.py create mode 100644 examples/wav2vec/unsupervised/data/random_input_dataset.py create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/README.md create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/cmd.sh create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/decode_phone.sh create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step1.sh create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step2.sh create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/local/copy_aligned_text.py create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/decode.sh create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_data_from_w2v.py create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang_word.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lm.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/score.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/show_wer.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/train_subset_lgbeam.sh create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select.py create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode_word.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/path.sh create mode 120000 examples/wav2vec/unsupervised/kaldi_self_train/st/steps create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_deltas.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_lda_mllt.sh create mode 100755 examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_sat.sh create mode 100644 examples/wav2vec/unsupervised/kaldi_self_train/st/train.sh create mode 120000 examples/wav2vec/unsupervised/kaldi_self_train/st/utils create mode 100644 examples/wav2vec/unsupervised/models/__init__.py create mode 100644 examples/wav2vec/unsupervised/models/wav2vec_u.py create mode 100644 examples/wav2vec/unsupervised/scripts/apply_pca.py create mode 100644 examples/wav2vec/unsupervised/scripts/copy_labels.py create mode 100644 examples/wav2vec/unsupervised/scripts/filter_lexicon.py create mode 100644 examples/wav2vec/unsupervised/scripts/filter_tsv.py create mode 100644 examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py create mode 100644 examples/wav2vec/unsupervised/scripts/ltr_to_wrd.py create mode 100644 examples/wav2vec/unsupervised/scripts/mean_pool.py create mode 100644 examples/wav2vec/unsupervised/scripts/merge_clusters.py create mode 100644 examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py create mode 100644 examples/wav2vec/unsupervised/scripts/normalize_text.py create mode 100644 examples/wav2vec/unsupervised/scripts/pca.py create mode 100644 examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py create mode 100644 examples/wav2vec/unsupervised/scripts/prepare_audio.sh create mode 100644 examples/wav2vec/unsupervised/scripts/prepare_text.sh create mode 100644 examples/wav2vec/unsupervised/scripts/remove_silence.py create mode 100644 examples/wav2vec/unsupervised/scripts/vads.py create mode 100644 examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py create mode 100644 examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py create mode 100644 examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py create mode 100644 examples/wav2vec/unsupervised/scripts/wer.py create mode 100644 examples/wav2vec/unsupervised/scripts/wrd_to_ltr.py create mode 100644 examples/wav2vec/unsupervised/tasks/__init__.py create mode 100644 examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py create mode 100644 examples/wav2vec/unsupervised/w2vu_generate.py diff --git a/examples/speech_recognition/kaldi/__init__.py b/examples/speech_recognition/kaldi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/speech_recognition/kaldi/add-self-loop-simple.cc b/examples/speech_recognition/kaldi/add-self-loop-simple.cc new file mode 100644 index 0000000000..89754b925e --- /dev/null +++ b/examples/speech_recognition/kaldi/add-self-loop-simple.cc @@ -0,0 +1,94 @@ +/* +* Copyright (c) Facebook, Inc. and its affiliates. +* +* This source code is licensed under the MIT license found in the +* LICENSE file in the root directory of this source tree. +*/ + +#include <iostream> +#include "fstext/fstext-lib.h" // @manual +#include "util/common-utils.h" // @manual + +/* + * This program is to modify a FST without self-loop by: + * for each incoming arc with non-eps input symbol, add a self-loop arc + * with that non-eps symbol as input and eps as output. + * + * This is to make sure the resultant FST can do deduplication for repeated + * symbols, which is very common in acoustic model + * + */ +namespace { +int32 AddSelfLoopsSimple(fst::StdVectorFst* fst) { + typedef fst::MutableArcIterator<fst::StdVectorFst> IterType; + + int32 num_states_before = fst->NumStates(); + fst::MakePrecedingInputSymbolsSame(false, fst); + int32 num_states_after = fst->NumStates(); + KALDI_LOG << "There are " << num_states_before + << " states in the original FST; " + << " after MakePrecedingInputSymbolsSame, there are " + << num_states_after << " states " << std::endl; + + auto weight_one = fst::StdArc::Weight::One(); + + int32 num_arc_added = 0; + + fst::StdArc self_loop_arc; + self_loop_arc.weight = weight_one; + + int32 num_states = fst->NumStates(); + std::vector<std::set<int32>> incoming_non_eps_label_per_state(num_states); + + for (int32 state = 0; state < num_states; state++) { + for (IterType aiter(fst, state); !aiter.Done(); aiter.Next()) { + fst::StdArc arc(aiter.Value()); + if (arc.ilabel != 0) { + incoming_non_eps_label_per_state[arc.nextstate].insert(arc.ilabel); + } + } + } + + for (int32 state = 0; state < num_states; state++) { + if (!incoming_non_eps_label_per_state[state].empty()) { + auto& ilabel_set = incoming_non_eps_label_per_state[state]; + for (auto it = ilabel_set.begin(); it != ilabel_set.end(); it++) { + self_loop_arc.ilabel = *it; + self_loop_arc.olabel = 0; + self_loop_arc.nextstate = state; + fst->AddArc(state, self_loop_arc); + num_arc_added++; + } + } + } + return num_arc_added; +} + +void print_usage() { + std::cout << "add-self-loop-simple usage:\n" + "\tadd-self-loop-simple <in-fst> <out-fst> \n"; +} +} // namespace + +int main(int argc, char** argv) { + if (argc != 3) { + print_usage(); + exit(1); + } + + auto input = argv[1]; + auto output = argv[2]; + + auto fst = fst::ReadFstKaldi(input); + auto num_states = fst->NumStates(); + KALDI_LOG << "Loading FST from " << input << " with " << num_states + << " states." << std::endl; + + int32 num_arc_added = AddSelfLoopsSimple(fst); + KALDI_LOG << "Adding " << num_arc_added << " self-loop arcs " << std::endl; + + fst::WriteFstKaldi(*fst, std::string(output)); + KALDI_LOG << "Writing FST to " << output << std::endl; + + delete fst; +} \ No newline at end of file diff --git a/examples/speech_recognition/kaldi/kaldi_decoder.py b/examples/speech_recognition/kaldi/kaldi_decoder.py new file mode 100644 index 0000000000..5f62cc58ae --- /dev/null +++ b/examples/speech_recognition/kaldi/kaldi_decoder.py @@ -0,0 +1,244 @@ +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from concurrent.futures import ThreadPoolExecutor +import logging +from omegaconf import MISSING +import os +import torch +from typing import Optional +import warnings + + +from dataclasses import dataclass +from fairseq.dataclass import FairseqDataclass +from .kaldi_initializer import KaldiInitializerConfig, initalize_kaldi + + +logger = logging.getLogger(__name__) + + +@dataclass +class KaldiDecoderConfig(FairseqDataclass): + hlg_graph_path: Optional[str] = None + output_dict: str = MISSING + + kaldi_initializer_config: Optional[KaldiInitializerConfig] = None + + acoustic_scale: float = 0.5 + max_active: int = 10000 + beam_delta: float = 0.5 + hash_ratio: float = 2.0 + + is_lattice: bool = False + lattice_beam: float = 10.0 + prune_interval: int = 25 + determinize_lattice: bool = True + prune_scale: float = 0.1 + max_mem: int = 0 + phone_determinize: bool = True + word_determinize: bool = True + minimize: bool = True + + num_threads: int = 1 + + +class KaldiDecoder(object): + def __init__( + self, + cfg: KaldiDecoderConfig, + beam: int, + nbest: int = 1, + ): + try: + from kaldi.asr import FasterRecognizer, LatticeFasterRecognizer + from kaldi.base import set_verbose_level + from kaldi.decoder import ( + FasterDecoder, + FasterDecoderOptions, + LatticeFasterDecoder, + LatticeFasterDecoderOptions, + ) + from kaldi.lat.functions import DeterminizeLatticePhonePrunedOptions + from kaldi.fstext import read_fst_kaldi, SymbolTable + except: + warnings.warn( + "pykaldi is required for this functionality. Please install from https://github.com/pykaldi/pykaldi" + ) + + # set_verbose_level(2) + + self.acoustic_scale = cfg.acoustic_scale + self.nbest = nbest + + if cfg.hlg_graph_path is None: + assert ( + cfg.kaldi_initializer_config is not None + ), "Must provide hlg graph path or kaldi initializer config" + cfg.hlg_graph_path = initalize_kaldi(cfg.kaldi_initializer_config) + + assert os.path.exists(cfg.hlg_graph_path), cfg.hlg_graph_path + + if cfg.is_lattice: + self.dec_cls = LatticeFasterDecoder + opt_cls = LatticeFasterDecoderOptions + self.rec_cls = LatticeFasterRecognizer + else: + assert self.nbest == 1, "nbest > 1 requires lattice decoder" + self.dec_cls = FasterDecoder + opt_cls = FasterDecoderOptions + self.rec_cls = FasterRecognizer + + self.decoder_options = opt_cls() + self.decoder_options.beam = beam + self.decoder_options.max_active = cfg.max_active + self.decoder_options.beam_delta = cfg.beam_delta + self.decoder_options.hash_ratio = cfg.hash_ratio + + if cfg.is_lattice: + self.decoder_options.lattice_beam = cfg.lattice_beam + self.decoder_options.prune_interval = cfg.prune_interval + self.decoder_options.determinize_lattice = cfg.determinize_lattice + self.decoder_options.prune_scale = cfg.prune_scale + det_opts = DeterminizeLatticePhonePrunedOptions() + det_opts.max_mem = cfg.max_mem + det_opts.phone_determinize = cfg.phone_determinize + det_opts.word_determinize = cfg.word_determinize + det_opts.minimize = cfg.minimize + self.decoder_options.det_opts = det_opts + + self.output_symbols = {} + with open(cfg.output_dict, "r") as f: + for line in f: + items = line.rstrip().split() + assert len(items) == 2 + self.output_symbols[int(items[1])] = items[0] + + logger.info(f"Loading FST from {cfg.hlg_graph_path}") + self.fst = read_fst_kaldi(cfg.hlg_graph_path) + self.symbol_table = SymbolTable.read_text(cfg.output_dict) + + self.executor = ThreadPoolExecutor(max_workers=cfg.num_threads) + + def generate(self, models, sample, **unused): + """Generate a batch of inferences.""" + # model.forward normally channels prev_output_tokens into the decoder + # separately, but SequenceGenerator directly calls model.encoder + encoder_input = { + k: v for k, v in sample["net_input"].items() if k != "prev_output_tokens" + } + emissions, padding = self.get_emissions(models, encoder_input) + return self.decode(emissions, padding) + + def get_emissions(self, models, encoder_input): + """Run encoder and normalize emissions""" + model = models[0] + + all_encoder_out = [m(**encoder_input) for m in models] + + if len(all_encoder_out) > 1: + + if "encoder_out" in all_encoder_out[0]: + encoder_out = { + "encoder_out": sum(e["encoder_out"] for e in all_encoder_out) + / len(all_encoder_out), + "encoder_padding_mask": all_encoder_out[0]["encoder_padding_mask"], + } + padding = encoder_out["encoder_padding_mask"] + else: + encoder_out = { + "logits": sum(e["logits"] for e in all_encoder_out) + / len(all_encoder_out), + "padding_mask": all_encoder_out[0]["padding_mask"], + } + padding = encoder_out["padding_mask"] + else: + encoder_out = all_encoder_out[0] + padding = ( + encoder_out["padding_mask"] + if "padding_mask" in encoder_out + else encoder_out["encoder_padding_mask"] + ) + + if hasattr(model, "get_logits"): + emissions = model.get_logits(encoder_out, normalize=True) + else: + emissions = model.get_normalized_probs(encoder_out, log_probs=True) + + return ( + emissions.cpu().float().transpose(0, 1), + padding.cpu() if padding is not None and padding.any() else None, + ) + + def decode_one(self, logits, padding): + from kaldi.matrix import Matrix + + decoder = self.dec_cls(self.fst, self.decoder_options) + asr = self.rec_cls( + decoder, self.symbol_table, acoustic_scale=self.acoustic_scale + ) + + if padding is not None: + logits = logits[~padding] + + mat = Matrix(logits.numpy()) + + out = asr.decode(mat) + + if self.nbest > 1: + from kaldi.fstext import shortestpath + from kaldi.fstext.utils import ( + convert_compact_lattice_to_lattice, + convert_lattice_to_std, + convert_nbest_to_list, + get_linear_symbol_sequence, + ) + + lat = out["lattice"] + + sp = shortestpath(lat, nshortest=self.nbest) + + sp = convert_compact_lattice_to_lattice(sp) + sp = convert_lattice_to_std(sp) + seq = convert_nbest_to_list(sp) + + results = [] + for s in seq: + _, o, w = get_linear_symbol_sequence(s) + words = list(self.output_symbols[z] for z in o) + results.append( + { + "tokens": words, + "words": words, + "score": w.value, + "emissions": logits, + } + ) + return results + else: + words = out["text"].split() + return [ + { + "tokens": words, + "words": words, + "score": out["likelihood"], + "emissions": logits, + } + ] + + def decode(self, emissions, padding): + if padding is None: + padding = [None] * len(emissions) + + ret = list( + map( + lambda e, p: self.executor.submit(self.decode_one, e, p), + emissions, + padding, + ) + ) + return ret diff --git a/examples/speech_recognition/kaldi/kaldi_initializer.py b/examples/speech_recognition/kaldi/kaldi_initializer.py new file mode 100644 index 0000000000..6d2a2a4b6b --- /dev/null +++ b/examples/speech_recognition/kaldi/kaldi_initializer.py @@ -0,0 +1,698 @@ +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass +import hydra +from hydra.core.config_store import ConfigStore +import logging +from omegaconf import MISSING, OmegaConf +import os +import os.path as osp +from pathlib import Path +import subprocess +from typing import Optional + +from fairseq.data.dictionary import Dictionary +from fairseq.dataclass import FairseqDataclass + +script_dir = Path(__file__).resolve().parent +config_path = script_dir / "config" + + +logger = logging.getLogger(__name__) + + +@dataclass +class KaldiInitializerConfig(FairseqDataclass): + data_dir: str = MISSING + fst_dir: Optional[str] = None + in_labels: str = MISSING + out_labels: Optional[str] = None + wav2letter_lexicon: Optional[str] = None + lm_arpa: str = MISSING + kaldi_root: str = MISSING + blank_symbol: str = "<s>" + silence_symbol: Optional[str] = None + + +def create_units(fst_dir: Path, in_labels: str, vocab: Dictionary) -> Path: + in_units_file = fst_dir / f"kaldi_dict.{in_labels}.txt" + if not in_units_file.exists(): + + logger.info(f"Creating {in_units_file}") + + with open(in_units_file, "w") as f: + print("<eps> 0", file=f) + i = 1 + for symb in vocab.symbols[vocab.nspecial :]: + if not symb.startswith("madeupword"): + print(f"{symb} {i}", file=f) + i += 1 + return in_units_file + + +def create_lexicon( + cfg: KaldiInitializerConfig, + fst_dir: Path, + unique_label: str, + in_units_file: Path, + out_words_file: Path, +) -> (Path, Path): + + disambig_in_units_file = fst_dir / f"kaldi_dict.{cfg.in_labels}_disambig.txt" + lexicon_file = fst_dir / f"kaldi_lexicon.{unique_label}.txt" + disambig_lexicon_file = fst_dir / f"kaldi_lexicon.{unique_label}_disambig.txt" + if ( + not lexicon_file.exists() + or not disambig_lexicon_file.exists() + or not disambig_in_units_file.exists() + ): + logger.info(f"Creating {lexicon_file} (in units file: {in_units_file})") + + assert cfg.wav2letter_lexicon is not None or cfg.in_labels == cfg.out_labels + + if cfg.wav2letter_lexicon is not None: + lm_words = set() + with open(out_words_file, "r") as lm_dict_f: + for line in lm_dict_f: + lm_words.add(line.split()[0]) + + num_skipped = 0 + total = 0 + with open(cfg.wav2letter_lexicon, "r") as w2l_lex_f, open( + lexicon_file, "w" + ) as out_f: + for line in w2l_lex_f: + items = line.rstrip().split("\t") + assert len(items) == 2, items + if items[0] in lm_words: + print(items[0], items[1], file=out_f) + else: + num_skipped += 1 + logger.debug( + f"Skipping word {items[0]} as it was not found in LM" + ) + total += 1 + if num_skipped > 0: + logger.warning( + f"Skipped {num_skipped} out of {total} words as they were not found in LM" + ) + else: + with open(in_units_file, "r") as in_f, open(lexicon_file, "w") as out_f: + for line in in_f: + symb = line.split()[0] + if symb != "<eps>" and symb != "<ctc_blank>" and symb != "<SIL>": + print(symb, symb, file=out_f) + + lex_disambig_path = ( + Path(cfg.kaldi_root) / "egs/wsj/s5/utils/add_lex_disambig.pl" + ) + res = subprocess.run( + [lex_disambig_path, lexicon_file, disambig_lexicon_file], + check=True, + capture_output=True, + ) + ndisambig = int(res.stdout) + disamib_path = Path(cfg.kaldi_root) / "egs/wsj/s5/utils/add_disambig.pl" + res = subprocess.run( + [disamib_path, "--include-zero", in_units_file, str(ndisambig)], + check=True, + capture_output=True, + ) + with open(disambig_in_units_file, "wb") as f: + f.write(res.stdout) + + return disambig_lexicon_file, disambig_in_units_file + + +def create_G( + kaldi_root: Path, fst_dir: Path, lm_arpa: Path, arpa_base: str +) -> (Path, Path): + + out_words_file = fst_dir / f"kaldi_dict.{arpa_base}.txt" + grammar_graph = fst_dir / f"G_{arpa_base}.fst" + if not grammar_graph.exists() or not out_words_file.exists(): + logger.info(f"Creating {grammar_graph}") + arpa2fst = kaldi_root / "src/lmbin/arpa2fst" + subprocess.run( + [ + arpa2fst, + "--disambig-symbol=#0", + f"--write-symbol-table={out_words_file}", + lm_arpa, + grammar_graph, + ], + check=True, + ) + return grammar_graph, out_words_file + + +def create_L( + kaldi_root: Path, + fst_dir: Path, + unique_label: str, + lexicon_file: Path, + in_units_file: Path, + out_words_file: Path, +) -> Path: + lexicon_graph = fst_dir / f"L.{unique_label}.fst" + + if not lexicon_graph.exists(): + logger.info(f"Creating {lexicon_graph} (in units: {in_units_file})") + make_lex = kaldi_root / "egs/wsj/s5/utils/make_lexicon_fst.pl" + fstcompile = kaldi_root / "tools/openfst-1.6.7/bin/fstcompile" + fstaddselfloops = kaldi_root / "src/fstbin/fstaddselfloops" + fstarcsort = kaldi_root / "tools/openfst-1.6.7/bin/fstarcsort" + + def write_disambig_symbol(file): + with open(file, "r") as f: + for line in f: + items = line.rstrip().split() + if items[0] == "#0": + out_path = str(file) + "_disamig" + with open(out_path, "w") as out_f: + print(items[1], file=out_f) + return out_path + + return None + + in_disambig_sym = write_disambig_symbol(in_units_file) + assert in_disambig_sym is not None + out_disambig_sym = write_disambig_symbol(out_words_file) + assert out_disambig_sym is not None + + try: + with open(lexicon_graph, "wb") as out_f: + res = subprocess.run( + [make_lex, lexicon_file], capture_output=True, check=True + ) + assert len(res.stderr) == 0, res.stderr.decode("utf-8") + res = subprocess.run( + [ + fstcompile, + f"--isymbols={in_units_file}", + f"--osymbols={out_words_file}", + "--keep_isymbols=false", + "--keep_osymbols=false", + ], + input=res.stdout, + capture_output=True, + ) + assert len(res.stderr) == 0, res.stderr.decode("utf-8") + res = subprocess.run( + [fstaddselfloops, in_disambig_sym, out_disambig_sym], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstarcsort, "--sort_type=olabel"], + input=res.stdout, + capture_output=True, + check=True, + ) + out_f.write(res.stdout) + except subprocess.CalledProcessError as e: + logger.error(f"cmd: {e.cmd}, err: {e.stderr.decode('utf-8')}") + os.remove(lexicon_graph) + raise + except AssertionError: + os.remove(lexicon_graph) + raise + + return lexicon_graph + + +def create_LG( + kaldi_root: Path, + fst_dir: Path, + unique_label: str, + lexicon_graph: Path, + grammar_graph: Path, +) -> Path: + lg_graph = fst_dir / f"LG.{unique_label}.fst" + + if not lg_graph.exists(): + logger.info(f"Creating {lg_graph}") + + fsttablecompose = kaldi_root / "src/fstbin/fsttablecompose" + fstdeterminizestar = kaldi_root / "src/fstbin/fstdeterminizestar" + fstminimizeencoded = kaldi_root / "src/fstbin/fstminimizeencoded" + fstpushspecial = kaldi_root / "src/fstbin/fstpushspecial" + fstarcsort = kaldi_root / "tools/openfst-1.6.7/bin/fstarcsort" + + try: + with open(lg_graph, "wb") as out_f: + res = subprocess.run( + [fsttablecompose, lexicon_graph, grammar_graph], + capture_output=True, + check=True, + ) + res = subprocess.run( + [ + fstdeterminizestar, + "--use-log=true", + ], + input=res.stdout, + capture_output=True, + ) + res = subprocess.run( + [fstminimizeencoded], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstpushspecial], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstarcsort, "--sort_type=ilabel"], + input=res.stdout, + capture_output=True, + check=True, + ) + out_f.write(res.stdout) + except subprocess.CalledProcessError as e: + logger.error(f"cmd: {e.cmd}, err: {e.stderr.decode('utf-8')}") + os.remove(lg_graph) + raise + + return lg_graph + + +def create_H( + kaldi_root: Path, + fst_dir: Path, + disambig_out_units_file: Path, + in_labels: str, + vocab: Dictionary, + blk_sym: str, + silence_symbol: Optional[str], +) -> (Path, Path, Path): + h_graph = ( + fst_dir / f"H.{in_labels}{'_' + silence_symbol if silence_symbol else ''}.fst" + ) + h_out_units_file = fst_dir / f"kaldi_dict.h_out.{in_labels}.txt" + disambig_in_units_file_int = Path(str(h_graph) + "isym_disambig.int") + disambig_out_units_file_int = Path(str(disambig_out_units_file) + ".int") + if ( + not h_graph.exists() + or not h_out_units_file.exists() + or not disambig_in_units_file_int.exists() + ): + logger.info(f"Creating {h_graph}") + eps_sym = "<eps>" + + num_disambig = 0 + osymbols = [] + + with open(disambig_out_units_file, "r") as f, open( + disambig_out_units_file_int, "w" + ) as out_f: + for line in f: + symb, id = line.rstrip().split() + if line.startswith("#"): + num_disambig += 1 + print(id, file=out_f) + else: + if len(osymbols) == 0: + assert symb == eps_sym, symb + osymbols.append((symb, id)) + + i_idx = 0 + isymbols = [(eps_sym, 0)] + + imap = {} + + for i, s in enumerate(vocab.symbols): + i_idx += 1 + isymbols.append((s, i_idx)) + imap[s] = i_idx + + fst_str = [] + + node_idx = 0 + root_node = node_idx + + special_symbols = [blk_sym] + if silence_symbol is not None: + special_symbols.append(silence_symbol) + + for ss in special_symbols: + fst_str.append("{} {} {} {}".format(root_node, root_node, ss, eps_sym)) + + for symbol, _ in osymbols: + if symbol == eps_sym or symbol.startswith("#"): + continue + + node_idx += 1 + # 1. from root to emitting state + fst_str.append("{} {} {} {}".format(root_node, node_idx, symbol, symbol)) + # 2. from emitting state back to root + fst_str.append("{} {} {} {}".format(node_idx, root_node, eps_sym, eps_sym)) + # 3. from emitting state to optional blank state + pre_node = node_idx + node_idx += 1 + for ss in special_symbols: + fst_str.append("{} {} {} {}".format(pre_node, node_idx, ss, eps_sym)) + # 4. from blank state back to root + fst_str.append("{} {} {} {}".format(node_idx, root_node, eps_sym, eps_sym)) + + fst_str.append("{}".format(root_node)) + + fst_str = "\n".join(fst_str) + h_str = str(h_graph) + isym_file = h_str + ".isym" + + with open(isym_file, "w") as f: + for sym, id in isymbols: + f.write("{} {}\n".format(sym, id)) + + with open(h_out_units_file, "w") as f: + for sym, id in osymbols: + f.write("{} {}\n".format(sym, id)) + + with open(disambig_in_units_file_int, "w") as f: + disam_sym_id = len(isymbols) + for _ in range(num_disambig): + f.write("{}\n".format(disam_sym_id)) + disam_sym_id += 1 + + fstcompile = kaldi_root / "tools/openfst-1.6.7/bin/fstcompile" + fstaddselfloops = kaldi_root / "src/fstbin/fstaddselfloops" + fstarcsort = kaldi_root / "tools/openfst-1.6.7/bin/fstarcsort" + + try: + with open(h_graph, "wb") as out_f: + res = subprocess.run( + [ + fstcompile, + f"--isymbols={isym_file}", + f"--osymbols={h_out_units_file}", + "--keep_isymbols=false", + "--keep_osymbols=false", + ], + input=str.encode(fst_str), + capture_output=True, + check=True, + ) + res = subprocess.run( + [ + fstaddselfloops, + disambig_in_units_file_int, + disambig_out_units_file_int, + ], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstarcsort, "--sort_type=olabel"], + input=res.stdout, + capture_output=True, + check=True, + ) + out_f.write(res.stdout) + except subprocess.CalledProcessError as e: + logger.error(f"cmd: {e.cmd}, err: {e.stderr.decode('utf-8')}") + os.remove(h_graph) + raise + return h_graph, h_out_units_file, disambig_in_units_file_int + + +def create_HLGa( + kaldi_root: Path, + fst_dir: Path, + unique_label: str, + h_graph: Path, + lg_graph: Path, + disambig_in_words_file_int: Path, +) -> Path: + hlga_graph = fst_dir / f"HLGa.{unique_label}.fst" + + if not hlga_graph.exists(): + logger.info(f"Creating {hlga_graph}") + + fsttablecompose = kaldi_root / "src/fstbin/fsttablecompose" + fstdeterminizestar = kaldi_root / "src/fstbin/fstdeterminizestar" + fstrmsymbols = kaldi_root / "src/fstbin/fstrmsymbols" + fstrmepslocal = kaldi_root / "src/fstbin/fstrmepslocal" + fstminimizeencoded = kaldi_root / "src/fstbin/fstminimizeencoded" + + try: + with open(hlga_graph, "wb") as out_f: + res = subprocess.run( + [ + fsttablecompose, + h_graph, + lg_graph, + ], + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstdeterminizestar, "--use-log=true"], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstrmsymbols, disambig_in_words_file_int], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstrmepslocal], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstminimizeencoded], + input=res.stdout, + capture_output=True, + check=True, + ) + out_f.write(res.stdout) + except subprocess.CalledProcessError as e: + logger.error(f"cmd: {e.cmd}, err: {e.stderr.decode('utf-8')}") + os.remove(hlga_graph) + raise + + return hlga_graph + + +def create_HLa( + kaldi_root: Path, + fst_dir: Path, + unique_label: str, + h_graph: Path, + l_graph: Path, + disambig_in_words_file_int: Path, +) -> Path: + hla_graph = fst_dir / f"HLa.{unique_label}.fst" + + if not hla_graph.exists(): + logger.info(f"Creating {hla_graph}") + + fsttablecompose = kaldi_root / "src/fstbin/fsttablecompose" + fstdeterminizestar = kaldi_root / "src/fstbin/fstdeterminizestar" + fstrmsymbols = kaldi_root / "src/fstbin/fstrmsymbols" + fstrmepslocal = kaldi_root / "src/fstbin/fstrmepslocal" + fstminimizeencoded = kaldi_root / "src/fstbin/fstminimizeencoded" + + try: + with open(hla_graph, "wb") as out_f: + res = subprocess.run( + [ + fsttablecompose, + h_graph, + l_graph, + ], + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstdeterminizestar, "--use-log=true"], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstrmsymbols, disambig_in_words_file_int], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstrmepslocal], + input=res.stdout, + capture_output=True, + check=True, + ) + res = subprocess.run( + [fstminimizeencoded], + input=res.stdout, + capture_output=True, + check=True, + ) + out_f.write(res.stdout) + except subprocess.CalledProcessError as e: + logger.error(f"cmd: {e.cmd}, err: {e.stderr.decode('utf-8')}") + os.remove(hla_graph) + raise + + return hla_graph + + +def create_HLG( + kaldi_root: Path, + fst_dir: Path, + unique_label: str, + hlga_graph: Path, + prefix: str = "HLG", +) -> Path: + hlg_graph = fst_dir / f"{prefix}.{unique_label}.fst" + + if not hlg_graph.exists(): + logger.info(f"Creating {hlg_graph}") + + add_self_loop = script_dir / "add-self-loop-simple" + kaldi_src = kaldi_root / "src" + kaldi_lib = kaldi_src / "lib" + + try: + if not add_self_loop.exists(): + fst_include = kaldi_root / "tools/openfst-1.6.7/include" + add_self_loop_src = script_dir / "add-self-loop-simple.cc" + + subprocess.run( + [ + "c++", + f"-I{kaldi_src}", + f"-I{fst_include}", + f"-L{kaldi_lib}", + add_self_loop_src, + "-lkaldi-base", + "-lkaldi-fstext", + "-o", + add_self_loop, + ], + check=True, + ) + + my_env = os.environ.copy() + my_env["LD_LIBRARY_PATH"] = f"{kaldi_lib}:{my_env['LD_LIBRARY_PATH']}" + + subprocess.run( + [ + add_self_loop, + hlga_graph, + hlg_graph, + ], + check=True, + capture_output=True, + env=my_env, + ) + except subprocess.CalledProcessError as e: + logger.error(f"cmd: {e.cmd}, err: {e.stderr.decode('utf-8')}") + raise + + return hlg_graph + + +def initalize_kaldi(cfg: KaldiInitializerConfig) -> Path: + if cfg.fst_dir is None: + cfg.fst_dir = osp.join(cfg.data_dir, "kaldi") + if cfg.out_labels is None: + cfg.out_labels = cfg.in_labels + + kaldi_root = Path(cfg.kaldi_root) + data_dir = Path(cfg.data_dir) + fst_dir = Path(cfg.fst_dir) + fst_dir.mkdir(parents=True, exist_ok=True) + + arpa_base = osp.splitext(osp.basename(cfg.lm_arpa))[0] + unique_label = f"{cfg.in_labels}.{arpa_base}" + + with open(data_dir / f"dict.{cfg.in_labels}.txt", "r") as f: + vocab = Dictionary.load(f) + + in_units_file = create_units(fst_dir, cfg.in_labels, vocab) + + grammar_graph, out_words_file = create_G( + kaldi_root, fst_dir, Path(cfg.lm_arpa), arpa_base + ) + + disambig_lexicon_file, disambig_L_in_units_file = create_lexicon( + cfg, fst_dir, unique_label, in_units_file, out_words_file + ) + + h_graph, h_out_units_file, disambig_in_units_file_int = create_H( + kaldi_root, + fst_dir, + disambig_L_in_units_file, + cfg.in_labels, + vocab, + cfg.blank_symbol, + cfg.silence_symbol, + ) + lexicon_graph = create_L( + kaldi_root, + fst_dir, + unique_label, + disambig_lexicon_file, + disambig_L_in_units_file, + out_words_file, + ) + lg_graph = create_LG( + kaldi_root, fst_dir, unique_label, lexicon_graph, grammar_graph + ) + hlga_graph = create_HLGa( + kaldi_root, fst_dir, unique_label, h_graph, lg_graph, disambig_in_units_file_int + ) + hlg_graph = create_HLG(kaldi_root, fst_dir, unique_label, hlga_graph) + + # for debugging + # hla_graph = create_HLa(kaldi_root, fst_dir, unique_label, h_graph, lexicon_graph, disambig_in_units_file_int) + # hl_graph = create_HLG(kaldi_root, fst_dir, unique_label, hla_graph, prefix="HL_looped") + # create_HLG(kaldi_root, fst_dir, "phnc", h_graph, prefix="H_looped") + + return hlg_graph + + +@hydra.main(config_path=config_path, config_name="kaldi_initializer") +def cli_main(cfg: KaldiInitializerConfig) -> None: + container = OmegaConf.to_container(cfg, resolve=True, enum_to_str=True) + cfg = OmegaConf.create(container) + OmegaConf.set_struct(cfg, True) + initalize_kaldi(cfg) + + +if __name__ == "__main__": + + logging.root.setLevel(logging.INFO) + logging.basicConfig(level=logging.INFO) + + try: + from hydra._internal.utils import ( + get_args, + ) # pylint: disable=import-outside-toplevel + + cfg_name = get_args().config_name or "kaldi_initializer" + except ImportError: + logger.warning("Failed to get config name from hydra args") + cfg_name = "kaldi_initializer" + + cs = ConfigStore.instance() + cs.store(name=cfg_name, node=KaldiInitializerConfig) + + cli_main() diff --git a/examples/wav2vec/__init__.py b/examples/wav2vec/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/wav2vec/config/finetuning/base_960h.yaml b/examples/wav2vec/config/finetuning/base_960h.yaml index e393805ad8..2d38211e91 100644 --- a/examples/wav2vec/config/finetuning/base_960h.yaml +++ b/examples/wav2vec/config/finetuning/base_960h.yaml @@ -31,7 +31,7 @@ criterion: optimization: max_update: 320000 - lr: [0.00001] + lr: [0.0001] sentence_avg: true optimizer: diff --git a/examples/wav2vec/unsupervised/README.md b/examples/wav2vec/unsupervised/README.md index fdfcc04d26..2277e65ffb 100644 --- a/examples/wav2vec/unsupervised/README.md +++ b/examples/wav2vec/unsupervised/README.md @@ -1,4 +1,3 @@ - # wav2vec Unsupervised (wav2vec-U) Wav2vec Unsupervised (wav2vec-U) is a framework for building speech recognition systems without any labeled training data as described in [Unsupervised Speech Recognition (Baevski et al., 2021)](https://ai.facebook.com/research/publications/unsupervised-speech-recognition). The model takes as input wav2vec 2.0 or XLSR representations (see [pretrained models](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec)) as well as unlabeled speech and text data. @@ -8,135 +7,35 @@ Wav2vec Unsupervised (wav2vec-U) is a framework for building speech recognition * Generative adversarial training (GAN) * Iterative self-training + Kaldi LM-decoding - ## Preparation of speech and text data Similar to [wav2vec 2.0](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec/README.md), data folders contain {train,valid,test}.{tsv,wrd,phn} files, where audio paths are stored in tsv files, and word, letter or phoneme transcriptions are stored in .{wrd,ltr,phn}. - -In **/path/to/data/with_silence** you need a *train.tsv* file as well as *{valid,test}.{tsv,wrd,phn}*. It is nice to have *10h.{tsv,phn}* files there too for reproducing the ablation study on layer selection. In **/path/to/data/without_silence** you have the same files, except *.tsv* files contain audios with silences removed using rVAD. +In **/path/to/data/with_silence** you need a *train.tsv* file as well as (optionally) *{valid,test}.{tsv,wrd,phn}*. It is nice to have *10h.{tsv,phn}* files there too for reproducing the ablation study on layer selection. In **/path/to/data/without_silence** you have the same files, except *.tsv* files contain audios with silences removed using rVAD. Here is how you can create new audio files without silences from a list of input audio files: -``` -python scripts/unsupervised/remove_silences.py /path/to/data/with_silence/train.tsv \ - --save-dir /path/to/data/without_silence/audio \ - --output /path/to/data/without_silence/train.tsv & -``` +```shell +python scripts/vads.py < /path/to/train.tsv > train.vads +python scripts/remove_silence.py --tsv /path/to/train.tsv --vads train.vads --out /dir/to/save/audio/files -In this first part, we use mostly phonemized text. Here is how you can transform a text file into its phonemized .phn version: +python $FAIRSEQ_ROOT/examples/wav2vec/wav2vec_manifest.py /dir/to/save/audio/files --ext wav --dest /path/to/new/train.tsv --valid-percent 0 ``` -# Will phonemize word dictionary and then phonemize text using dict lookup (for language $lg) -python scripts/unsupervised/phonemize.py $path_to_wrd_dict $lg < text.wrd > text.phn & - -``` -Next, you can reproduce Figure 2/3 of the wav2vec-U paper by training linear models on top of each layer's frozen wav2vec 2.0 representations, using supervised data. You can observe that certain layers provide lower PER, which shows the closeness of their representations to phoneme outputs. Note that this step requires supervision and is thus not necessary. - -``` -# Learn linear model on top of layer N(=15) using supervised data - -fairseq-hydra-train \ - distributed_training.distributed_port=$PORT \ - task.data=/path/to/data/without_silence \ - model.w2v_path=/path/to/model.pt \ - model.layer=15 \ - --config-dir /path/to/fairseq-py/examples/wav2vec/config/finetuning \ - --config-name vox_10h_phn -``` - - - -We can extract features of layer *N* using the following: -``` -# Extract features from layer N -split=train # valid test -python scripts/unsupervised/fb_wav2vec_ctc_filter.py \ - /path/to/data/without_silence \ - --split $split \ - --layer=15 \ - --checkpoint /path/to/model.pt \ - --save-dir /path/to/features & -``` - - - -Next we perform clustering of wav2vec representations (step 2 in the paper): -``` -# Identify clusters in the representations with k-means - -python scripts/unsupervised/fb_wav2vec_cluster_faiss.py \ - /path/to/data/train.tsv \ - -f "CLUS128" \ - --sample-pct 0.5 \ - --layer 15 \ - --checkpoint /path/to/model.pt \ - --save-dir /path/to/features/clustering/segmented & -``` - -And use those clusters to segment the audio data (step 3 in the paper): -``` -# Transcribe cluster ids of audio data -python scripts/unsupervised/fb_wav2vec_apply_cluster_faiss.py \ - /path/to/data \ - --split $split \ - --checkpoint /path/to/model.pt \ - --path /path/to/features/clustering/segmented/CLUS128 & -``` - - Learn and apply PCA to the representations to retain important features -``` -# Compute PCA -python scripts/pca.py \ - /path/to/features/unfiltered/train.npy \ - --dim 512 \ - --output /path/to/features/unfiltered/unfiltered_pca - -# Apply PCA -python scripts/apply_pca.py \ - $outdir \ - --split $split \ - --pca-path /path/to/features/unfiltered/unfiltered_pca/512_pca \ - --batch-size 1048000 \ - --save-dir /path/to/features/unfiltered/precompute_unfiltered_pca${dim} -``` +You will need to add the path to rVAD directory to vads.py. -Then we build segment representations by mean-pooling representations according to clusters: - - +Next, we need to preprocess the audio data to better match phonemized text data: +```shell +zsh scripts/prepare_audio.sh /dir/with/{train,test,valid}.tsv /output/dir /path/to/wav2vec2/model.pt ``` -# Build segment representations - -python scripts/unsupervised/merge_clusters.py \ - /path/to/features/unfiltered/precompute_unfiltered_pca512 \ - --split $split \ - --cluster-dir /path/to/features/clustering/segmented/CLUS128 \ - --pooling mean \ - --save-dir /path/to/features/unfiltered/precompute_unfiltered_pca512_cls128_mean & +Note that if you have splits different than train/valid/test, you will need to modify this script. +Now we need to prepare text data: +```shell +zsh scripts/prepare_text.sh language /path/to/text/file /output/dir ``` -Finally, we found that segment boundaries are noisy due to the lack of supervision and we therefore found it useful to also mean-pool pairs of adjacent segment representations to increase robustness: -``` -# Mean-pool adjacent time steps -python scripts/unsupervised/mean_pool.py \ - /path/to/features/unfiltered/precompute_unfiltered_pca512_cls128_mean \ - --split $split & - --save-dir $savedir & -``` - -For adversarial training, we preprocess the text data by adding silence tokens. -``` -# Add <SIL> tokens on text in preparation for GAN training -python scripts/unsupervised/fb_wrd_to_phonemizer.py \ - -s 0.25 --surround < /path/to/data/gan.txt > /path/to/data/gan.txt_s0.25.phns & - -# Binarize with fairseq-preprocess -fairseq-preprocess --dataset-impl mmap \ - --trainpref /path/to/data/gan.txt_s0.25.phns \ - --workers 6 --thresholdsrc 0 --only-source \ - --destdir /path/to/data --srcdict /path/to/data/dict.phn.txt & -``` +Note that if you want to use a different phonemizer, such as G2P, you will need to modify this script. ## Generative adversarial training (GAN) @@ -152,24 +51,25 @@ TEXT_DATA=/path/to/data # path to fairseq-preprocessed GAN data KENLM_PATH=/path/to/data/kenlm.phn.o4.bin # KenLM 4-gram phoneme language model (LM data = GAN data here) PREFIX=$PREFIX fairseq-hydra-train \ - distributed_training.distributed_port=$PORT \ - -m --config-dir configs/unsup \ - --config-name gan_feats_by_label \ - dataset.valid_subset=valid \ + -m --config-dir configs/gan \ + --config-name w2vu \ task.data=${TASK_DATA} \ task.text_data=${TEXT_DATA} \ task.kenlm_path=${KENLM_PATH} \ 'common.seed=range(0,5)' & ``` -However, this step requires an hyperparameter search, which can be launched with: -``` -``` - -Note that hyperparameter search and model/epoch selection are done using a fully unsupervised metric (see Section 4.3). +Once we find the best checkpoint (chosen using unsupervised metric that combined language model perplexity and vocabulary usage), we can use it to generate phone labels (or word labels with an appropriate kaldi WFST): +```shell +python w2vu_generate.py --config-dir config/generate --config-name viterbi \ +fairseq.task.data=/path/to/dir/with/tsvs fairseq.common_eval.path=/path/to/gan/checkpoint \ +fairseq.dataset.gen_subset=valid results_path=/where/to/save/transcriptions +``` ## Iterative self-training + Kaldi LM-decoding After the GAN training provides a first unsupervised model, we can then progressively refine the quality of transcriptions using several iterations of semi-supervised learning. We perform two iterations: first, pseudo-label the training data with the unsupervised GAN model and train an HMM on the pseudo-labels. Second, we relabel the training data with the HMM and then fine-tune the original wav2vec 2.0 model using the HMM pseudo-labels with a CTC loss. Note that HMM models use phonemes as output, while wav2vec 2.0 use letter. Both are decoded using WFST decoders into words. Please see [this README](http://github.com/pytorch/fairseq/tree/master/examples/wav2vec/unsupervised/kaldi_st) for more instructions on how to do iterative self-training + Kaldi LM-decoding. + +*** Note: these instructions are a work in progress and will be updated over the next few days diff --git a/examples/wav2vec/unsupervised/__init__.py b/examples/wav2vec/unsupervised/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml b/examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml new file mode 100644 index 0000000000..e94da2ba4e --- /dev/null +++ b/examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml @@ -0,0 +1,62 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + +checkpoint: + no_epoch_checkpoints: true + save_interval_updates: 20000 + +task: + _name: audio_pretraining + data: ??? + normalize: true + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 800000 + skip_invalid_size_inputs_valid_test: true + train_subset: train + valid_subset: valid + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + find_unused_parameters: True + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + +optimization: + max_update: 80000 + lr: [0.00003] + sentence_avg: true + update_freq: [1] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.25 + mask_channel_prob: 0.1 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 0 diff --git a/examples/wav2vec/unsupervised/config/gan/w2vu.yaml b/examples/wav2vec/unsupervised/config/gan/w2vu.yaml new file mode 100644 index 0000000000..d168a11e19 --- /dev/null +++ b/examples/wav2vec/unsupervised/config/gan/w2vu.yaml @@ -0,0 +1,108 @@ +# @package _group_ + +common: + fp16: false + fp16_no_flatten_grads: true + log_format: json + log_interval: 100 + tensorboard_logdir: tb + reset_logging: false + suppress_crashes: false + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: weighted_lm_ppl + save_dir: . + +task: + _name: unpaired_audio_text + data: ??? + text_data: ??? + labels: phn + sort_by_length: false + unfiltered: false + max_length: null + append_eos: false + kenlm_path: ??? + +dataset: + num_workers: 6 + batch_size: 160 + skip_invalid_size_inputs_valid_test: true + valid_subset: valid + +criterion: + _name: model + log_keys: + - accuracy_dense + - accuracy_token + - temp + - code_ppl + +optimization: + max_update: 150000 + clip_norm: 5.0 + lr: [0] + +optimizer: + _name: composite + groups: + generator: + lr: [0.0004] + lr_float: null + optimizer: + _name: adam + adam_betas: [0.5,0.98] + adam_eps: 1e-06 + weight_decay: 0 + amsgrad: false + lr_scheduler: + _name: fixed + warmup_updates: 0 + discriminator: + lr: [ 0.0005 ] + lr_float: null + optimizer: + _name: adam + adam_betas: [0.5,0.98] + adam_eps: 1e-06 + weight_decay: 0.0001 + amsgrad: false + lr_scheduler: + _name: fixed + warmup_updates: 0 + +lr_scheduler: pass_through + +model: + _name: wav2vec_u + + discriminator_dim: 384 + discriminator_depth: 2 + discriminator_kernel: 6 + discriminator_linear_emb: false + discriminator_causal: true + discriminator_max_pool: false + discriminator_act_after_linear: false + discriminator_dropout: 0.0 + discriminator_weight_norm: false + + generator_stride: 1 + generator_kernel: 4 + generator_bias: false + generator_dropout: 0.1 + + smoothness_weight: 0.5 + smoothing: 0 + smoothing_one_sided: false + gumbel: false + hard_gumbel: false + gradient_penalty: 1.5 + code_penalty: 4.0 + temp: [ 2,0.1,0.99995 ] + input_dim: 512 + + segmentation: + type: JOIN + mean_pool_join: false + remove_zeros: false diff --git a/examples/wav2vec/unsupervised/config/generate/viterbi.yaml b/examples/wav2vec/unsupervised/config/generate/viterbi.yaml new file mode 100644 index 0000000000..0f850bb3e7 --- /dev/null +++ b/examples/wav2vec/unsupervised/config/generate/viterbi.yaml @@ -0,0 +1,22 @@ +# @package _group_ + +fairseq: + task: + _name: unpaired_audio_text + labels: phn + data: ??? + sort_by_length: false + shuffle: false + text_data: '' + + common_eval: + path: ??? + quiet: true + + dataset: + gen_subset: valid + batch_size: 1 + +w2l_decoder: VITERBI +lm_model: ??? +post_process: silence diff --git a/examples/wav2vec/unsupervised/data/__init__.py b/examples/wav2vec/unsupervised/data/__init__.py new file mode 100644 index 0000000000..d0545627ef --- /dev/null +++ b/examples/wav2vec/unsupervised/data/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .extracted_features_dataset import ExtractedFeaturesDataset +from .random_input_dataset import RandomInputDataset + + +__all__ = [ + "ExtractedFeaturesDataset", + "RandomInputDataset", +] diff --git a/examples/wav2vec/unsupervised/data/extracted_features_dataset.py b/examples/wav2vec/unsupervised/data/extracted_features_dataset.py new file mode 100644 index 0000000000..d6ee9c4a36 --- /dev/null +++ b/examples/wav2vec/unsupervised/data/extracted_features_dataset.py @@ -0,0 +1,144 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +import os +import contextlib + +import numpy as np +import torch + +from fairseq.data import FairseqDataset, data_utils + + +logger = logging.getLogger(__name__) + + +class ExtractedFeaturesDataset(FairseqDataset): + def __init__( + self, + path, + split, + min_length=3, + max_length=None, + labels=None, + label_dict=None, + shuffle=True, + sort_by_length=True, + ): + super().__init__() + + self.min_length = min_length + self.max_length = max_length + self.shuffle = shuffle + self.sort_by_length = sort_by_length + self.label_dict = label_dict + + if labels is not None: + assert label_dict is not None + + self.sizes = [] + self.offsets = [] + self.labels = [] + + path = os.path.join(path, split) + data_path = path + self.data = np.load(data_path + ".npy", mmap_mode="r") + + offset = 0 + skipped = 0 + + if not os.path.exists(path + f".{labels}"): + labels = None + + with open(data_path + ".lengths", "r") as len_f, open( + path + f".{labels}", "r" + ) if labels is not None else contextlib.ExitStack() as lbl_f: + for line in len_f: + length = int(line.rstrip()) + lbl = None if labels is None else next(lbl_f).rstrip().split() + if length >= min_length and ( + max_length is None or length <= max_length + ): + self.sizes.append(length) + self.offsets.append(offset) + if lbl is not None: + self.labels.append(lbl) + offset += length + + self.sizes = np.asarray(self.sizes) + self.offsets = np.asarray(self.offsets) + + logger.info(f"loaded {len(self.offsets)}, skipped {skipped} samples") + + def __getitem__(self, index): + offset = self.offsets[index] + end = self.sizes[index] + offset + feats = torch.from_numpy(self.data[offset:end].copy()).float() + + res = {"id": index, "features": feats} + if len(self.labels) > 0: + res["target"] = self.label_dict.encode_line( + self.labels[index], + line_tokenizer=lambda x: x, + append_eos=False, + ) + + return res + + def __len__(self): + return len(self.sizes) + + def collater(self, samples): + if len(samples) == 0: + return {} + + features = [s["features"] for s in samples] + sizes = [len(s) for s in features] + + target_size = max(sizes) + + collated_features = features[0].new_zeros( + len(features), target_size, features[0].size(-1) + ) + padding_mask = torch.BoolTensor(collated_features.shape[:-1]).fill_(False) + for i, (f, size) in enumerate(zip(features, sizes)): + collated_features[i, :size] = f + padding_mask[i, size:] = True + + res = { + "id": torch.LongTensor([s["id"] for s in samples]), + "net_input": {"features": collated_features, "padding_mask": padding_mask}, + } + + if len(self.labels) > 0: + target = data_utils.collate_tokens( + [s["target"] for s in samples], + pad_idx=self.label_dict.pad(), + left_pad=False, + ) + res["target"] = target + return res + + def num_tokens(self, index): + return self.size(index) + + def size(self, index): + return self.sizes[index] + + def ordered_indices(self): + """Return an ordered list of indices. Batches will be constructed based + on this order.""" + if self.shuffle: + order = [np.random.permutation(len(self))] + else: + order = [np.arange(len(self))] + + if self.sort_by_length: + order.append(self.sizes) + return np.lexsort(order)[::-1] + else: + return order[0] diff --git a/examples/wav2vec/unsupervised/data/random_input_dataset.py b/examples/wav2vec/unsupervised/data/random_input_dataset.py new file mode 100644 index 0000000000..886505616c --- /dev/null +++ b/examples/wav2vec/unsupervised/data/random_input_dataset.py @@ -0,0 +1,62 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import random +from typing import List + +from fairseq.data import BaseWrapperDataset, data_utils + + +class RandomInputDataset(BaseWrapperDataset): + def __init__( + self, + dataset, + random_input_dataset, + input_key_path: List[str], + add_to_input, + pad_idx, + ): + super().__init__(dataset) + self.random_input_dataset = random_input_dataset + if isinstance(input_key_path, str): + input_key_path = [input_key_path] + assert len(input_key_path) > 0 + self.input_key_path = input_key_path + self.add_to_input = add_to_input + self.pad_idx = pad_idx + + def get_target(self, item): + target_loc = item + for p in self.input_key_path[:-1]: + target_loc = target_loc[p] + return self.input_key_path[-1], target_loc + + def get_target_value(self, item): + k, target_loc = self.get_target(item) + return target_loc[k] + + def __getitem__(self, index): + item = self.dataset[index] + k, target_loc = self.get_target(item) + target_loc[k] = random.choice(self.random_input_dataset) + return item + + def collater(self, samples): + collated = self.dataset.collater(samples) + if len(collated) == 0: + return collated + indices = set(collated["id"].tolist()) + + random_inputs = data_utils.collate_tokens( + [self.get_target_value(s) for s in samples if s["id"] in indices], + pad_idx=self.pad_idx, + left_pad=False, + ) + k, target_loc = self.get_target( + collated if not self.add_to_input else collated["net_input"] + ) + target_loc[k] = random_inputs + + return collated diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/README.md b/examples/wav2vec/unsupervised/kaldi_self_train/README.md new file mode 100644 index 0000000000..314984fcbb --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/README.md @@ -0,0 +1,56 @@ +# Self-Training with Kaldi HMM Models +This folder contains recipes for self-training on pseudo phone transcripts and +decoding into phones or words with [kaldi](https://github.com/kaldi-asr/kaldi). + +To start, download and install kaldi follow its instruction, and place this +folder in `path/to/kaldi/egs`. + +## Training +Assuming the following has been prepared: +- `w2v_dir`: contains features `{train,valid}.{npy,lengths}`, real transcripts `{train,valid}.${label}`, and dict `dict.${label}.txt` +- `lab_dir`: contains pseudo labels `{train,valid}.txt` +- `arpa_lm`: Arpa-format n-gram phone LM for decoding +- `arpa_lm_bin`: Arpa-format n-gram phone LM for unsupervised model selection to be used with KenLM + +Set these variables in `train.sh`, as well as `out_dir`, the output directory, +and then run it. + +The output will be: +``` +==== WER w.r.t. real transcript (select based on unsupervised metric) +INFO:root:./out/exp/mono/decode_valid/scoring/14.0.0.tra.txt: score 0.9178 wer 28.71% lm_ppl 24.4500 gt_wer 25.57% +INFO:root:./out/exp/tri1/decode_valid/scoring/17.1.0.tra.txt: score 0.9257 wer 26.99% lm_ppl 30.8494 gt_wer 21.90% +INFO:root:./out/exp/tri2b/decode_valid/scoring/8.0.0.tra.txt: score 0.7506 wer 23.15% lm_ppl 25.5944 gt_wer 15.78% +``` +where `wer` is the word eror rate with respect to the pseudo label, `gt_wer` to +the ground truth label, `lm_ppl` the language model perplexity of HMM prediced +transcripts, and `score` is the unsupervised metric for model selection. We +choose the model and the LM parameter of the one with the lowest score. In the +example above, it is `tri2b`, `8.0.0`. + + +## Decoding into Phones +In `decode_phone.sh`, set `out_dir` the same as used in `train.sh`, set +`dec_exp` and `dec_lmparam` to the selected model and LM parameter (e.g. +`tri2b` and `8.0.0` in the above example). `dec_script` needs to be set +according to `dec_exp`: for mono/tri1/tri2b, use `decode.sh`; for tri3b, use +`decode_fmllr.sh`. + +The output will be saved at `out_dir/dec_data` + + +## Decoding into Words +`decode_word_step1.sh` prepares WFSTs for word decoding. Besides the variables +mentioned above, set +- `wrd_arpa_lm`: Arpa-format n-gram word LM for decoding +- `wrd_arpa_lm_bin`: Arpa-format n-gram word LM for unsupervised model selection + +`decode_word_step1.sh` decodes the `train` and `valid` split into word and runs +unsupervised model selection using the `valid` split. The output is like: +``` +INFO:root:./out/exp/tri2b/decodeword_valid/scoring/17.0.0.tra.txt: score 1.8693 wer 24.97% lm_ppl 1785.5333 gt_wer 31.45% +``` + +After determining the LM parameter (`17.0.0` in the example above), set it in +`decode_word_step2.sh` and run it. The output will be saved at +`out_dir/dec_data_word`. diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/cmd.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/cmd.sh new file mode 100644 index 0000000000..e74953194d --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/cmd.sh @@ -0,0 +1,15 @@ +# you can change cmd.sh depending on what type of queue you are using. +# If you have no queueing system and want to run on a local machine, you +# can change all instances 'queue.pl' to run.pl (but be careful and run +# commands one by one: most recipes will exhaust the memory on your +# machine). queue.pl works with GridEngine (qsub). slurm.pl works +# with slurm. Different queues are configured differently, with different +# queue names and different ways of specifying things like memory; +# to account for these differences you can create and edit the file +# conf/queue.conf to match your queue's configuration. Search for +# conf/queue.conf in http://kaldi-asr.org/doc/queue.html for more information, +# or search for the string 'default_config' in utils/queue.pl or utils/slurm.pl. + +export train_cmd="run.pl --mem 2G" +export decode_cmd="run.pl --mem 4G" +export mkgraph_cmd="run.pl --mem 8G" diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_phone.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_phone.sh new file mode 100644 index 0000000000..947342a0b7 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_phone.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# decode into phones (and prepare a new data directory for HMM outputs) + +. ./path.sh + +set -eu + +out_dir= # same as in train.sh +dec_lmparam= # LM hyperparameters (e.g., 7.0.0) +dec_exp= +dec_script= +dec_splits="train valid" +dec_data_dir=$out_dir/dec_data # where to write HMM output + +data_dir=${out_dir}/data + +local/decode.sh --nj 40 --graph_name graph \ + --val_sets "$dec_splits" --decode_script $dec_script \ + $out_dir/exp/$dec_exp $data_dir $data_dir/lang_test + +if [ ! -z $dec_lmparam ]; then + for x in $dec_splits; do + mkdir -p $dec_data_dir/$x + cp $data_dir/$x/{feats.scp,cmvn.scp,utt2spk,spk2utt} $dec_data_dir/$x/ + + tra=$out_dir/exp/$dec_exp/decode_${x}/scoring/${dec_lmparam}.tra + cat $tra | utils/int2sym.pl -f 2- $data_dir/lang/words.txt | \ + sed 's:<UNK>::g' | sed 's:<SIL>::g' > $dec_data_dir/${x}/text + utils/fix_data_dir.sh $dec_data_dir/${x} + echo "WER on ${x} is" $(compute-wer ark:$data_dir/${x}_gt/text ark:$dec_data_dir/$x/text | cut -d" " -f2-) + done +fi diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step1.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step1.sh new file mode 100644 index 0000000000..c1276bbe4d --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step1.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# prepare word WFSTs, reference data, and decode + +set -eu + +w2v_dir= # same as in train.sh +out_dir= # same as in train.sh +lexicon= # word to phone mapping +wrd_arpa_lm= # word LM +wrd_arpa_lm_bin= # word LM for KenLM, used in unsupervised selection + +dec_exp= # what HMM stage to decode (e.g., tri3b) +dec_script= # what decoding script to use (e.g., steps/decode_fmllr.sh) +phn_label=phnc +wrd_label=wrd +dec_suffix=word +dec_splits="train valid" +valid_split="valid" + +data_dir=$out_dir/data +wrd_data_dir=$out_dir/data_word + +lexicon_clean=$(mktemp) +cat $lexicon | sort | uniq > $lexicon_clean +local/prepare_lang_word.sh $w2v_dir/dict.${phn_label}.txt $data_dir $lexicon_clean && rm $lexicon_clean +local/prepare_lm.sh --langdir $data_dir/lang_word --lmdir $data_dir/lang_test_word $wrd_arpa_lm $data_dir + +for x in $dec_splits; do + x_gt=${x}_gt + mkdir -p $wrd_data_dir/$x_gt + cp $data_dir/$x_gt/{feats.scp,cmvn.scp,utt2spk,spk2utt} $wrd_data_dir/$x_gt/ + python local/copy_aligned_text.py < $w2v_dir/$x.$wrd_label > $wrd_data_dir/$x_gt/text +done + +local/decode.sh --nj 40 --graph_name graph${dec_suffix} --decode_suffix $dec_suffix \ + --val_sets "$dec_splits" --decode_script $dec_script \ + $out_dir/exp/$dec_exp $data_dir $data_dir/lang_test_word + +local/unsup_select_decode_word.sh \ + --split $valid_split --kenlm_path $wrd_arpa_lm_bin \ + --ref_txt $wrd_data_dir/${valid_split}_gt/text \ + --psd_txt $data_dir/${valid_split}/text \ + --dec_name decode${dec_suffix} --graph_name graph${dec_suffix} \ + --phonemize_lexicon $data_dir/local/dict_word/lexicon.txt \ + $out_dir/exp diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step2.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step2.sh new file mode 100644 index 0000000000..59a6cbb125 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/decode_word_step2.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# prepare a new data directory of HMM word output + +. ./path.sh + +set -eu + +out_dir= # same as in train.sh +dec_lmparam= # LM hyperparameters (e.g., 7.0.0) + +dec_exp=tri3b # what HMM stage to decode (e.g., tri3b) +dec_suffix=word +dec_splits="train valid" +dec_data_dir=$out_dir/dec_data_word # where to write HMM output + +data_dir=$out_dir/data +wrd_data_dir=$out_dir/data_word + +for x in $dec_splits; do + mkdir -p $dec_data_dir/$x + cp $data_dir/$x/{feats.scp,cmvn.scp,utt2spk,spk2utt} $dec_data_dir/$x/ + + tra=$out_dir/exp/$dec_exp/decode${dec_suffix}_${x}/scoring/${dec_lmparam}.tra + cat $tra | utils/int2sym.pl -f 2- $data_dir/lang_word/words.txt | \ + sed 's:<UNK>::g' | sed 's:<SIL>::g' > $dec_data_dir/$x/text + utils/fix_data_dir.sh $dec_data_dir/$x + echo "WER on $x is" $(compute-wer ark:$wrd_data_dir/${x}_gt/text ark:$dec_data_dir/$x/text | cut -d" " -f2-) +done + diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/copy_aligned_text.py b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/copy_aligned_text.py new file mode 100644 index 0000000000..5f4faa9921 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/copy_aligned_text.py @@ -0,0 +1,4 @@ +import sys + +for idx, line in enumerate(sys.stdin): + print(f"utt{idx:010d} {line}", end='') \ No newline at end of file diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/decode.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/decode.sh new file mode 100755 index 0000000000..811cb63c88 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/decode.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +set -u + +val_sets="dev_other" +graph_name=graph +decode_suffix="" +decode_script="steps/decode_fmllr.sh" +decode_args="" +nj=60 + +. ./cmd.sh +. ./path.sh +. parse_options.sh + +set -x +exp_dir=$1 +data_root=$2 +lang_test=$3 + +graph=$exp_dir/$graph_name + +if [ ! -d $graph ]; then + utils/mkgraph.sh $lang_test $exp_dir $graph +fi + +for part in $val_sets; do + dec_dir=$exp_dir/decode${decode_suffix}_${part} + if [ ! -d $dec_dir ]; then + echo "decoding $part for $exp_dir" + $decode_script --nj $nj --cmd "$decode_cmd" $decode_args \ + $graph $data_root/$part $dec_dir & + else + echo "$dec_dir exists. skip" + fi +done + +wait diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_data_from_w2v.py b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_data_from_w2v.py new file mode 100644 index 0000000000..66954ea5c9 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_data_from_w2v.py @@ -0,0 +1,56 @@ +import kaldi_io +import numpy as np +import os + + +def get_parser(): + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("w2v_dir", help="wav2vec feature and text directory") + parser.add_argument("tar_root", help="output data directory in kaldi's format") + parser.add_argument("split", help="name of the subset") + parser.add_argument("--label", default="", help="if specified, copy labels too") + return parser + +def main(): + parser = get_parser() + args = parser.parse_args() + + tar_dir = os.path.join(args.tar_root, args.split) + os.makedirs(tar_dir, exist_ok=True) + + lengths_path = os.path.join(args.w2v_dir, f"{args.split}.lengths") + with open(lengths_path) as f: + lengths = [int(line.rstrip()) for line in f] + offsets = [0] + np.cumsum(lengths[:-1]).tolist() + feats = np.load( + os.path.join(args.w2v_dir, f"{args.split}.npy"), + mmap_mode="r" + ) + assert feats.shape[0] == sum(lengths), \ + f"lengths mismatch {feats.shape[0]} != {sum(lengths)}" + + ark_path = os.path.join(tar_dir, "feats.ark") + scp_path = os.path.join(tar_dir, "feats.scp") + wspec = f"ark:| copy-feats --compress=true ark:- ark,scp:{ark_path},{scp_path}" + with kaldi_io.open_or_fd(wspec, "wb") as f: + for idx, (offset, length) in enumerate(zip(offsets, lengths)): + feat = feats[offset:offset+length] + kaldi_io.write_mat(f, feat, key=f"utt{idx:010d}") + + u2s_path = os.path.join(tar_dir, "utt2spk") + s2u_path = os.path.join(tar_dir, "spk2utt") + with open(u2s_path, "w") as f_u2s, open(s2u_path, "w") as f_s2u: + for idx in range(len(lengths)): + f_u2s.write(f"utt{idx:010d} utt{idx:010d}\n") + f_s2u.write(f"utt{idx:010d} utt{idx:010d}\n") + + if bool(args.label): + lab_path = os.path.join(args.w2v_dir, f"{args.split}.{args.label}") + txt_path = os.path.join(tar_dir, "text") + with open(lab_path) as f_lab, open(txt_path, "w") as f_txt: + for idx, line in enumerate(f_lab): + f_txt.write(f"utt{idx:010d} {line}") + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang.sh new file mode 100755 index 0000000000..e9a80001eb --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +sil_prob=0.5 +num_sil_states=3 +num_nonsil_states=1 + +. ./cmd.sh +. ./path.sh +. parse_options.sh + +set -eux + +dict=$1 +data_dir=$2 + +dict_dir=$data_dir/local/dict +tmplm_dir=$data_dir/local/lang_tmp +lm_dir=$data_dir/lang + +mkdir -p $dict_dir $tmplm_dir $lm_dir + +# prepare dict +echo "SIL" > $dict_dir/silence_phones.txt +echo "SIL" > $dict_dir/optional_silence.txt +awk '{print $1}' $dict > $dict_dir/nonsilence_phones.txt + +echo "SIL SIL" > $dict_dir/lexicon.txt +echo "<UNK> SIL" >> $dict_dir/lexicon.txt +awk '{print $1" "$1}' $dict >> $dict_dir/lexicon.txt + +echo "SIL" > $dict_dir/extra_questions.txt +awk '{printf $1" "} END {printf "\n"}' $dict >> $dict_dir/extra_questions.txt + +# prepare lang +utils/prepare_lang.sh --sil-prob $sil_prob --position-dependent-phones false \ + --num_sil_states $num_sil_states --num_nonsil_states $num_nonsil_states \ + $dict_dir "<UNK>" $tmplm_dir $lm_dir diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang_word.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang_word.sh new file mode 100755 index 0000000000..a7ea3877be --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lang_word.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +num_sil_states=3 +num_nonsil_states=1 + +. ./cmd.sh +. ./path.sh +. parse_options.sh + +set -eux + +dict=$1 +data_dir=$2 +lexicon=$3 + +dict_dir=$data_dir/local/dict_word +tmplm_dir=$data_dir/local/lang_tmp_word +lm_dir=$data_dir/lang_word + +mkdir -p $dict_dir $tmplm_dir $lm_dir + +# prepare dict +echo "SIL" > $dict_dir/silence_phones.txt +echo "SIL" > $dict_dir/optional_silence.txt +awk '{print $1}' $dict > $dict_dir/nonsilence_phones.txt + +(echo "!SIL SIL"; echo "<UNK> SIL";) | cat - $lexicon > $dict_dir/lexicon.txt + +echo "SIL" > $dict_dir/extra_questions.txt +awk '{printf $1" "} END {printf "\n"}' $dict >> $dict_dir/extra_questions.txt + +# prepare lang +utils/prepare_lang.sh --position-dependent-phones false \ + --num_sil_states $num_sil_states --num_nonsil_states $num_nonsil_states \ + $dict_dir "<UNK>" $tmplm_dir $lm_dir diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lm.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lm.sh new file mode 100755 index 0000000000..c2edcefede --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/prepare_lm.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +langdir="" +lmdir="" + +. ./cmd.sh +. ./path.sh +. parse_options.sh + +arpa_lm=$1 +data=$2 + +if [ -z $langdir ]; then + langdir=$data/lang +fi +if [ -z $lmdir ]; then + lmdir=$data/lang_test +fi + +if [ ! -d $langdir ]; then + echo "$langdir not found. run local/prepare_lang.sh first" && exit 1 +fi + +mkdir -p $lmdir +cp -r $langdir/* $lmdir + +if [[ "$arpa_lm" == *.gz ]]; then + gunzip -c $arpa_lm | arpa2fst --disambig-symbol=#0 --read-symbol-table=$lmdir/words.txt - $lmdir/G.fst +else + arpa2fst --disambig-symbol=#0 --read-symbol-table=$lmdir/words.txt $arpa_lm $lmdir/G.fst +fi +fstisstochastic $lmdir/G.fst +utils/validate_lang.pl $lmdir || exit 1 + +echo "done preparing lm ($lmdir)" diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/score.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/score.sh new file mode 100755 index 0000000000..cb5bbb7277 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/score.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash +# Copyright 2012 Johns Hopkins University (Author: Daniel Povey) +# 2014 Guoguo Chen +# Apache 2.0 + +[ -f ./path.sh ] && . ./path.sh + +# begin configuration section. +cmd=run.pl +stage=0 +decode_mbr=true +word_ins_penalty=0.0,0.5,1.0 +min_lmwt=7 +max_lmwt=17 +iter=final +#end configuration section. + +[ -f ./path.sh ] && . ./path.sh +. parse_options.sh || exit 1; + +if [ $# -ne 3 ]; then + echo "Usage: local/score.sh [--cmd (run.pl|queue.pl...)] <data-dir> <lang-dir|graph-dir> <decode-dir>" + echo " Options:" + echo " --cmd (run.pl|queue.pl...) # specify how to run the sub-processes." + echo " --stage (0|1|2) # start scoring script from part-way through." + echo " --decode_mbr (true/false) # maximum bayes risk decoding (confusion network)." + echo " --min_lmwt <int> # minumum LM-weight for lattice rescoring " + echo " --max_lmwt <int> # maximum LM-weight for lattice rescoring " + exit 1; +fi + +data=$1 +lang_or_graph=$2 +dir=$3 + +symtab=$lang_or_graph/words.txt + +for f in $symtab $dir/lat.1.gz $data/text; do + [ ! -f $f ] && echo "score.sh: no such file $f" && exit 1; +done + +mkdir -p $dir/scoring/log + +cat $data/text | sed 's:<NOISE>::g' | sed 's:<SPOKEN_NOISE>::g' > $dir/scoring/test_filt.txt + +for wip in $(echo $word_ins_penalty | sed 's/,/ /g'); do + $cmd LMWT=$min_lmwt:$max_lmwt $dir/scoring/log/best_path.LMWT.$wip.log \ + lattice-scale --inv-acoustic-scale=LMWT "ark:gunzip -c $dir/lat.*.gz|" ark:- \| \ + lattice-add-penalty --word-ins-penalty=$wip ark:- ark:- \| \ + lattice-best-path --word-symbol-table=$symtab \ + ark:- ark,t:$dir/scoring/LMWT.$wip.tra || exit 1; +done + +# Note: the double level of quoting for the sed command +for wip in $(echo $word_ins_penalty | sed 's/,/ /g'); do + $cmd LMWT=$min_lmwt:$max_lmwt $dir/scoring/log/score.LMWT.$wip.log \ + cat $dir/scoring/LMWT.$wip.tra \| \ + utils/int2sym.pl -f 2- $symtab \| sed 's:\<UNK\>::g' \| \ + compute-wer --text --mode=present \ + ark:$dir/scoring/test_filt.txt ark,p:- ">&" $dir/wer_LMWT_$wip || exit 1; +done + +exit 0; diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/show_wer.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/show_wer.sh new file mode 100755 index 0000000000..9ecf1690c6 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/show_wer.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +split="dev_other" +ref_data="" +get_best_wer=true +dec_name="decode" +graph_name="graph" + +. ./cmd.sh +. ./path.sh +. parse_options.sh + +exp_root=$1 + +set -eu + +echo "==== WER w.r.t. pseudo transcript" +for x in $exp_root/*/${dec_name}_${split}*; do grep WER $x/wer_* 2>/dev/null | utils/best_wer.sh; done + + +if [ ! -z $ref_data ]; then + echo "==== WER w.r.t. real transcript (select based on pseudo WER)" + ref_txt=$ref_data/$split/text + for x in $exp_root/*/${dec_name}_${split}*; do + lang=$(dirname $x)/$graph_name + + lmwt=$( + grep WER $x/wer_* 2>/dev/null | utils/best_wer.sh | + sed 's/.*wer_\(.*\)$/\1/g' | sed 's/_/./g' + ) + tra=$x/scoring/$lmwt.tra + cat $tra | utils/int2sym.pl -f 2- $lang/words.txt | sed 's:<UNK>::g' | sed 's:<SIL>::g' | \ + compute-wer --text --mode=present \ + ark:$ref_txt ark,p:- 2> /dev/null | grep WER | xargs -I{} echo {} $tra + done +fi + +if [ ! -z $ref_data ] && $get_best_wer; then + echo "==== WER w.r.t. real transcript (select based on true WER)" + ref_txt=$ref_data/$split/text + for x in $exp_root/*/${dec_name}_${split}*; do + lang=$(dirname $x)/$graph_name + + for tra in $x/scoring/*.tra; do + cat $tra | utils/int2sym.pl -f 2- $lang/words.txt | sed 's:<UNK>::g' | sed 's:<SIL>::g' | \ + compute-wer --text --mode=present \ + ark:$ref_txt ark,p:- 2> /dev/null | grep WER | xargs -I{} echo {} $tra + done | sort -k2n | head -n1 + done +fi + +exit 0; diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/train_subset_lgbeam.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/train_subset_lgbeam.sh new file mode 100755 index 0000000000..913c1d8e43 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/train_subset_lgbeam.sh @@ -0,0 +1,129 @@ +#!/usr/bin/env bash + +out_root=/tmp +out_name=train_${RANDOM} +num_nonsil_states=1 + +valid="dev_other" +train="train" +mono_size="-1" # 2000 +tri1_size="-1" # 5000 +tri2b_size="-1" # 10000 +tri3b_size="-1" # 10000 + +# Acoustic model parameters +numLeavesTri1=2000 +numGaussTri1=10000 +numLeavesMLLT=2500 +numGaussMLLT=15000 +numLeavesSAT=2500 +numGaussSAT=15000 + +stage=1 +max_stage=1 + +. ./cmd.sh +. ./path.sh +. parse_options.sh + +data=$1 +lang=$2 +lang_test=$3 + +exp_root=$out_root/$out_name + +# you might not want to do this for interactive shells. +set -e + + +if [ $stage -le 1 ] && [ $max_stage -ge 1 ]; then + # train a monophone system + if [ ! $mono_size -eq -1 ]; then + utils/subset_data_dir.sh $data/$train $mono_size $data/${train}_${mono_size} + mono_train=${train}_${mono_size} + else + mono_train=${train} + fi + + steps/train_mono.sh --boost-silence 1.25 --nj 20 --cmd "$train_cmd" \ + --initial-beam 40 --regular-beam 60 --retry-beam 120 \ + $data/$mono_train $lang $exp_root/mono + + utils/mkgraph.sh $lang_test $exp_root/mono $exp_root/mono/graph + steps/decode.sh --nj 20 --cmd "$decode_cmd" \ + $exp_root/mono/graph $data/$valid $exp_root/mono/decode_$valid & +fi + + +if [ $stage -le 2 ] && [ $max_stage -ge 2 ]; then + # train a first delta + delta-delta triphone system on a subset of 5000 utterances + if [ ! $tri1_size -eq -1 ]; then + utils/subset_data_dir.sh $data/$train $tri1_size $data/${train}_${tri1_size} + tri1_train=${train}_${tri1_size} + else + tri1_train=${train} + fi + + steps/align_si.sh --boost-silence 1.25 --nj 10 --cmd "$train_cmd" \ + $data/$tri1_train $lang \ + $exp_root/mono $exp_root/mono_ali_${tri1_train} + + steps_gan/train_deltas.sh --boost-silence 1.25 --cmd "$train_cmd" \ + --num_nonsil_states $num_nonsil_states $numLeavesTri1 $numGaussTri1 \ + $data/$tri1_train $lang \ + $exp_root/mono_ali_${tri1_train} $exp_root/tri1 + + utils/mkgraph.sh $lang_test $exp_root/tri1 $exp_root/tri1/graph + steps/decode.sh --nj 20 --cmd "$decode_cmd" \ + $exp_root/tri1/graph $data/$valid $exp_root/tri1/decode_$valid & +fi + +if [ $stage -le 3 ] && [ $max_stage -ge 3 ]; then + # train an LDA+MLLT system. + if [ ! $tri2b_size -eq -1 ]; then + utils/subset_data_dir.sh $data/$train $tri2b_size $data/${train}_${tri2b_size} + tri2b_train=${train}_${tri2b_size} + else + tri2b_train=${train} + fi + + steps/align_si.sh --nj 10 --cmd "$train_cmd" \ + $data/$tri2b_train $lang \ + $exp_root/tri1 $exp_root/tri1_ali_${tri2b_train} + + steps_gan/train_lda_mllt.sh --cmd "$train_cmd" \ + --num_nonsil_states $num_nonsil_states \ + --splice-opts "--left-context=3 --right-context=3" $numLeavesMLLT $numGaussMLLT \ + $data/$tri2b_train $lang \ + $exp_root/tri1_ali_${tri2b_train} $exp_root/tri2b + + utils/mkgraph.sh $lang_test $exp_root/tri2b $exp_root/tri2b/graph + steps/decode.sh --nj 20 --cmd "$decode_cmd" \ + $exp_root/tri2b/graph $data/$valid $exp_root/tri2b/decode_$valid & +fi + + +if [ $stage -le 4 ] && [ $max_stage -ge 4 ]; then + # Train tri3b, which is LDA+MLLT+SAT on 10k utts + if [ ! $tri3b_size -eq -1 ]; then + utils/subset_data_dir.sh $data/$train $tri3b_size $data/${train}_${tri3b_size} + tri3b_train=${train}_${tri3b_size} + else + tri3b_train=${train} + fi + + steps/align_si.sh --nj 10 --cmd "$train_cmd" --use-graphs true \ + $data/$tri3b_train $lang \ + $exp_root/tri2b $exp_root/tri2b_ali_${tri2b_train} + + steps_gan/train_sat.sh --cmd "$train_cmd" \ + --num_nonsil_states $num_nonsil_states $numLeavesSAT $numGaussSAT \ + $data/$tri3b_train $lang \ + $exp_root/tri2b_ali_${tri2b_train} $exp_root/tri3b + + utils/mkgraph.sh $lang_test $exp_root/tri3b $exp_root/tri3b/graph + steps/decode_fmllr.sh --nj 20 --cmd "$decode_cmd" \ + $exp_root/tri3b/graph $data/$valid $exp_root/tri3b/decode_$valid & +fi + +wait diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select.py b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select.py new file mode 100644 index 0000000000..1122c88c19 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select.py @@ -0,0 +1,135 @@ +""" +Implement unsupervised metric for decoding hyperparameter selection: + $$ alpha * LM_PPL + ViterbitUER(%) * 100 $$ +""" +import argparse +import logging +import math +import sys + +import kenlm +import editdistance +from g2p_en import G2p + +logging.root.setLevel(logging.INFO) +logging.basicConfig(stream=sys.stdout, level=logging.INFO) +logger = logging.getLogger(__name__) + + +def get_parser(): + parser = argparse.ArgumentParser() + parser.add_argument("ref_tra", help="reference pseudo labels") + parser.add_argument("hyp_tra", help="decoded pseudo labels to be assess") + parser.add_argument("--kenlm_path", default="/checkpoint/abaevski/data/speech/libri/librispeech_lm_novox.phnc_o5.bin", help="") + parser.add_argument("--uppercase", action="store_true", help="") + parser.add_argument("--skipwords", default="", help="") + parser.add_argument("--gt_tra", default="", help="ground truth pseudo labels for computing oracle WER") + parser.add_argument("--min_vt_uer", default=0.0, type=float) + parser.add_argument("--phonemize", action="store_true", help="phonemize word hypotheses, used when reference is phone transcript") + parser.add_argument("--phonemize_lexicon", default="", type=str, help="use a lexicon for phonemizing") + return parser + +def load_tra(tra_path): + with open(tra_path, "r") as f: + uid_to_tra = {} + for line in f: + toks = line.rstrip().split() + uid, tra = toks[0], " ".join(toks[1:]) + uid_to_tra[uid] = tra + logger.debug(f"loaded {len(uid_to_tra)} utterances from {tra_path}") + return uid_to_tra + +def load_lex(lex_path): + with open(lex_path, "r") as f: + w2p = {} + for line in f: + w, p = line.rstrip().split(None, 1) + w2p[w] = p.split() + return w2p + +def compute_wer(ref_uid_to_tra, hyp_uid_to_tra, g2p, g2p_dict): + d_cnt = 0 + w_cnt = 0 + w_cnt_h = 0 + for uid in hyp_uid_to_tra: + ref = ref_uid_to_tra[uid].split() + if g2p_dict is not None: + hyp = [] + for word in hyp_uid_to_tra[uid].split(): + if word in g2p_dict: + hyp = hyp + g2p_dict[word] + else: + logger.warning(f"{word} not in g2p_dict") + elif g2p is not None: + hyp = g2p(hyp_uid_to_tra[uid]) + hyp = [p for p in hyp if p != "'" and p != " "] + hyp = [p[:-1] if p[-1].isnumeric() else p for p in hyp] + else: + hyp = hyp_uid_to_tra[uid].split() + logger.debug(( + f"======================\n" + f"HYP: {' '.join(hyp)}\n" + f"REF: {' '.join(ref)}" + )) + d_cnt += editdistance.eval(ref, hyp) + w_cnt += len(ref) + w_cnt_h += len(hyp) + wer = float(d_cnt) / w_cnt + logger.debug(( + f"wer = {wer*100:.2f}%; num. of ref words = {w_cnt}; " + f"num. of hyp words = {w_cnt_h}; num. of sentences = {len(ref_uid_to_tra)}" + )) + return wer + +def compute_lm_ppl(hyp_uid_to_tra, score_fn): + lm_score = 0. + w_cnt = 0 + for hyp in hyp_uid_to_tra.values(): + cur_score = score_fn(hyp) + cur_cnt = len(hyp.split()) + 1 # plus one for </s> + lm_score += cur_score + w_cnt += cur_cnt + logger.debug(( + f"======================\n" + f"score sum/avg = {cur_score:.2f}/{cur_score/cur_cnt:.2f}\n" + f"hyp = {hyp}" + )) + lm_ppl = math.pow(10, -lm_score / w_cnt) + logger.debug(f"lm ppl = {lm_ppl:.2f}; num. of words = {w_cnt}") + return lm_ppl + +def main(): + args = get_parser().parse_args() + logger.debug(f"Args: {args}") + + ref_uid_to_tra = load_tra(args.ref_tra) + hyp_uid_to_tra = load_tra(args.hyp_tra) + assert not bool(set(hyp_uid_to_tra.keys()) - set(ref_uid_to_tra.keys())) + + lm = kenlm.Model(args.kenlm_path) + skipwords = set(args.skipwords.split(",")) + def compute_lm_score(s): + s = " ".join(w for w in s.split() if w not in skipwords) + s = s.upper() if args.uppercase else s + return lm.score(s) + + g2p, g2p_dict = None, None + if args.phonemize: + if args.phonemize_lexicon: + g2p_dict = load_lex(args.phonemize_lexicon) + else: + g2p = G2p() + + wer = compute_wer(ref_uid_to_tra, hyp_uid_to_tra, g2p, g2p_dict) + lm_ppl = compute_lm_ppl(hyp_uid_to_tra, compute_lm_score) + + gt_wer = -math.inf + if args.gt_tra: + gt_uid_to_tra = load_tra(args.gt_tra) + gt_wer = compute_wer(gt_uid_to_tra, hyp_uid_to_tra, None, None) + + score = math.log(lm_ppl) * max(wer, args.min_vt_uer) + logging.info(f"{args.hyp_tra}: score={score:.4f}; wer={wer*100:.2f}%; lm_ppl={lm_ppl:.4f}; gt_wer={gt_wer*100:.2f}%") + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode.sh new file mode 100755 index 0000000000..b34c5b6e06 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +split="dev_other" +ref_txt="" # ground truth transcript path +psd_txt="" # pseudo transcript path +get_best_wer=true +dec_name="decode" +graph_name="graph" +kenlm_path=/checkpoint/abaevski/data/speech/libri/librispeech_lm_novox.phnc_o6.bin + +. ./cmd.sh +. ./path.sh +. parse_options.sh + +exp_root=$1 +unsup_args="" +if [ $# -ge 2 ]; then + unsup_args=$2 +fi + +set -eu + +if [ ! -z $ref_txt ] && $get_best_wer; then + echo "==== WER w.r.t. real transcript (select based on unsupervised metric)" + for x in $exp_root/*/${dec_name}_${split}*; do + lang=$(dirname $x)/$graph_name + + ( + for tra in $x/scoring/*.tra; do + cat $tra | utils/int2sym.pl -f 2- $lang/words.txt | sed 's:<UNK>::g' | sed 's:<SIL>::g' > $tra.txt + python local/unsup_select.py $psd_txt $tra.txt --kenlm_path $kenlm_path --gt_tra $ref_txt $unsup_args + done 2>/dev/null | grep "score=" | sed 's/=/ /g' | sed 's/;//g' | sort -k3n | head -n1 + ) & + done +fi +wait + diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode_word.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode_word.sh new file mode 100755 index 0000000000..c10a6b8809 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/local/unsup_select_decode_word.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +split="dev_other" +ref_txt="" # ground truth transcript path +psd_txt="" # pseudo transcript path +get_best_wer=true +dec_name="decode" +graph_name="graph" +kenlm_path=/checkpoint/abaevski/data/speech/libri/librispeech_lm_novox.phnc_o6.bin +phonemize_lexicon="" + +. ./cmd.sh +. ./path.sh +. parse_options.sh +. /private/home/wnhsu/unsup_asr/fairseq-py-unsup/env.sh + +exp_root=$1 + +set -eu + +if [ ! -z $ref_txt ] && $get_best_wer; then + echo "==== WER w.r.t. real transcript (select based on unsupervised metric)" + for x in $exp_root/*/${dec_name}_${split}*; do + lang=$(dirname $x)/$graph_name + + for tra in $x/scoring/*.tra; do + cat $tra | utils/int2sym.pl -f 2- $lang/words.txt | sed 's:\<UNK\>::g' > $tra.txt + python local/unsup_select.py $psd_txt $tra.txt \ + --kenlm_path $kenlm_path --gt_tra $ref_txt --phonemize \ + --phonemize_lexicon "$phonemize_lexicon" + done | grep "score=" | sed 's/=/ /g' | sed 's/;//g' | sort -k3n | head -n1 + done +fi + + diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/path.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/path.sh new file mode 100755 index 0000000000..1a6fb5f891 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/path.sh @@ -0,0 +1,5 @@ +export KALDI_ROOT=`pwd`/../../.. +export PATH=$PWD/utils/:$KALDI_ROOT/tools/openfst/bin:$PWD:$PATH +[ ! -f $KALDI_ROOT/tools/config/common_path.sh ] && echo >&2 "The standard file $KALDI_ROOT/tools/config/common_path.sh is not present -> Exit!" && exit 1 +. $KALDI_ROOT/tools/config/common_path.sh +export LC_ALL=C diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/steps b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps new file mode 120000 index 0000000000..6e99bf5b5a --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps @@ -0,0 +1 @@ +../../wsj/s5/steps \ No newline at end of file diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_deltas.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_deltas.sh new file mode 100755 index 0000000000..af68715ab0 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_deltas.sh @@ -0,0 +1,175 @@ +#!/usr/bin/env bash + +# Copyright 2012 Johns Hopkins University (Author: Daniel Povey) +# Apache 2.0 + +# Begin configuration. +stage=-4 # This allows restarting after partway, when something when wrong. +config= +cmd=run.pl +scale_opts="--transition-scale=1.0 --acoustic-scale=0.1 --self-loop-scale=0.1" +realign_iters="10 20 30"; +num_iters=35 # Number of iterations of training +max_iter_inc=25 # Last iter to increase #Gauss on. +beam=10 +careful=false +retry_beam=40 +boost_silence=1.0 # Factor by which to boost silence likelihoods in alignment +power=0.25 # Exponent for number of gaussians according to occurrence counts +cluster_thresh=-1 # for build-tree control final bottom-up clustering of leaves +norm_vars=false # deprecated. Prefer --cmvn-opts "--norm-vars=true" + # use the option --cmvn-opts "--norm-means=false" +cmvn_opts= +delta_opts= +context_opts= # use"--context-width=5 --central-position=2" for quinphone +num_nonsil_states=3 +# End configuration. + +echo "$0 $@" # Print the command line for logging + +[ -f path.sh ] && . ./path.sh; +. parse_options.sh || exit 1; + +if [ $# != 6 ]; then + echo "Usage: steps/train_deltas.sh <num-leaves> <tot-gauss> <data-dir> <lang-dir> <alignment-dir> <exp-dir>" + echo "e.g.: steps/train_deltas.sh 2000 10000 data/train_si84_half data/lang exp/mono_ali exp/tri1" + echo "main options (for others, see top of script file)" + echo " --cmd (utils/run.pl|utils/queue.pl <queue opts>) # how to run jobs." + echo " --config <config-file> # config containing options" + echo " --stage <stage> # stage to do partial re-run from." + exit 1; +fi + +numleaves=$1 +totgauss=$2 +data=$3 +lang=$4 +alidir=$5 +dir=$6 + +for f in $alidir/final.mdl $alidir/ali.1.gz $data/feats.scp $lang/phones.txt; do + [ ! -f $f ] && echo "train_deltas.sh: no such file $f" && exit 1; +done + +numgauss=$numleaves +incgauss=$[($totgauss-$numgauss)/$max_iter_inc] # per-iter increment for #Gauss +oov=`cat $lang/oov.int` || exit 1; +ciphonelist=`cat $lang/phones/context_indep.csl` || exit 1; +nj=`cat $alidir/num_jobs` || exit 1; +mkdir -p $dir/log +echo $nj > $dir/num_jobs + +utils/lang/check_phones_compatible.sh $lang/phones.txt $alidir/phones.txt || exit 1; +cp $lang/phones.txt $dir || exit 1; + +sdata=$data/split$nj; +split_data.sh $data $nj || exit 1; + + +[ $(cat $alidir/cmvn_opts 2>/dev/null | wc -c) -gt 1 ] && [ -z "$cmvn_opts" ] && \ + echo "$0: warning: ignoring CMVN options from source directory $alidir" +$norm_vars && cmvn_opts="--norm-vars=true $cmvn_opts" +echo $cmvn_opts > $dir/cmvn_opts # keep track of options to CMVN. +[ ! -z $delta_opts ] && echo $delta_opts > $dir/delta_opts + +feats="ark,s,cs:apply-cmvn $cmvn_opts --utt2spk=ark:$sdata/JOB/utt2spk scp:$sdata/JOB/cmvn.scp scp:$sdata/JOB/feats.scp ark:- | add-deltas $delta_opts ark:- ark:- |" + +rm $dir/.error 2>/dev/null + +if [ $stage -le -3 ]; then + echo "$0: accumulating tree stats" + $cmd JOB=1:$nj $dir/log/acc_tree.JOB.log \ + acc-tree-stats $context_opts \ + --ci-phones=$ciphonelist $alidir/final.mdl "$feats" \ + "ark:gunzip -c $alidir/ali.JOB.gz|" $dir/JOB.treeacc || exit 1; + sum-tree-stats $dir/treeacc $dir/*.treeacc 2>$dir/log/sum_tree_acc.log || exit 1; + rm $dir/*.treeacc +fi + +if [ $stage -le -2 ]; then + echo "$0: getting questions for tree-building, via clustering" + # preparing questions, roots file... + cluster-phones --pdf-class-list=$(($num_nonsil_states / 2)) $context_opts \ + $dir/treeacc $lang/phones/sets.int \ + $dir/questions.int 2> $dir/log/questions.log || exit 1; + cat $lang/phones/extra_questions.int >> $dir/questions.int + compile-questions $context_opts $lang/topo $dir/questions.int \ + $dir/questions.qst 2>$dir/log/compile_questions.log || exit 1; + + echo "$0: building the tree" + $cmd $dir/log/build_tree.log \ + build-tree $context_opts --verbose=1 --max-leaves=$numleaves \ + --cluster-thresh=$cluster_thresh $dir/treeacc $lang/phones/roots.int \ + $dir/questions.qst $lang/topo $dir/tree || exit 1; + + $cmd $dir/log/init_model.log \ + gmm-init-model --write-occs=$dir/1.occs \ + $dir/tree $dir/treeacc $lang/topo $dir/1.mdl || exit 1; + if grep 'no stats' $dir/log/init_model.log; then + echo "** The warnings above about 'no stats' generally mean you have phones **" + echo "** (or groups of phones) in your phone set that had no corresponding data. **" + echo "** You should probably figure out whether something went wrong, **" + echo "** or whether your data just doesn't happen to have examples of those **" + echo "** phones. **" + fi + + gmm-mixup --mix-up=$numgauss $dir/1.mdl $dir/1.occs $dir/1.mdl 2>$dir/log/mixup.log || exit 1; + rm $dir/treeacc +fi + +if [ $stage -le -1 ]; then + # Convert the alignments. + echo "$0: converting alignments from $alidir to use current tree" + $cmd JOB=1:$nj $dir/log/convert.JOB.log \ + convert-ali $alidir/final.mdl $dir/1.mdl $dir/tree \ + "ark:gunzip -c $alidir/ali.JOB.gz|" "ark:|gzip -c >$dir/ali.JOB.gz" || exit 1; +fi + +if [ $stage -le 0 ]; then + echo "$0: compiling graphs of transcripts" + $cmd JOB=1:$nj $dir/log/compile_graphs.JOB.log \ + compile-train-graphs --read-disambig-syms=$lang/phones/disambig.int $dir/tree $dir/1.mdl $lang/L.fst \ + "ark:utils/sym2int.pl --map-oov $oov -f 2- $lang/words.txt < $sdata/JOB/text |" \ + "ark:|gzip -c >$dir/fsts.JOB.gz" || exit 1; +fi + +x=1 +while [ $x -lt $num_iters ]; do + echo "$0: training pass $x" + if [ $stage -le $x ]; then + if echo $realign_iters | grep -w $x >/dev/null; then + echo "$0: aligning data" + mdl="gmm-boost-silence --boost=$boost_silence `cat $lang/phones/optional_silence.csl` $dir/$x.mdl - |" + $cmd JOB=1:$nj $dir/log/align.$x.JOB.log \ + gmm-align-compiled $scale_opts --beam=$beam --retry-beam=$retry_beam --careful=$careful "$mdl" \ + "ark:gunzip -c $dir/fsts.JOB.gz|" "$feats" \ + "ark:|gzip -c >$dir/ali.JOB.gz" || exit 1; + fi + $cmd JOB=1:$nj $dir/log/acc.$x.JOB.log \ + gmm-acc-stats-ali $dir/$x.mdl "$feats" \ + "ark,s,cs:gunzip -c $dir/ali.JOB.gz|" $dir/$x.JOB.acc || exit 1; + $cmd $dir/log/update.$x.log \ + gmm-est --mix-up=$numgauss --power=$power \ + --write-occs=$dir/$[$x+1].occs $dir/$x.mdl \ + "gmm-sum-accs - $dir/$x.*.acc |" $dir/$[$x+1].mdl || exit 1; + rm $dir/$x.mdl $dir/$x.*.acc + rm $dir/$x.occs + fi + [ $x -le $max_iter_inc ] && numgauss=$[$numgauss+$incgauss]; + x=$[$x+1]; +done + +rm $dir/final.mdl $dir/final.occs 2>/dev/null +ln -s $x.mdl $dir/final.mdl +ln -s $x.occs $dir/final.occs + +steps/diagnostic/analyze_alignments.sh --cmd "$cmd" $lang $dir + +# Summarize warning messages... +utils/summarize_warnings.pl $dir/log + +steps/info/gmm_dir_info.pl $dir + +echo "$0: Done training system with delta+delta-delta features in $dir" + +exit 0 diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_lda_mllt.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_lda_mllt.sh new file mode 100755 index 0000000000..9d8c319ce8 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_lda_mllt.sh @@ -0,0 +1,239 @@ +#!/usr/bin/env bash + +# Copyright 2012 Johns Hopkins University (Author: Daniel Povey) +# +# LDA+MLLT refers to the way we transform the features after computing +# the MFCCs: we splice across several frames, reduce the dimension (to 40 +# by default) using Linear Discriminant Analysis), and then later estimate, +# over multiple iterations, a diagonalizing transform known as MLLT or STC. +# See http://kaldi-asr.org/doc/transform.html for more explanation. +# +# Apache 2.0. + +# Begin configuration. +cmd=run.pl +config= +stage=-5 +scale_opts="--transition-scale=1.0 --acoustic-scale=0.1 --self-loop-scale=0.1" +realign_iters="10 20 30"; +mllt_iters="2 4 6 12"; +num_iters=35 # Number of iterations of training +max_iter_inc=25 # Last iter to increase #Gauss on. +dim=40 +beam=10 +retry_beam=40 +careful=false +boost_silence=1.0 # Factor by which to boost silence likelihoods in alignment +power=0.25 # Exponent for number of gaussians according to occurrence counts +randprune=4.0 # This is approximately the ratio by which we will speed up the + # LDA and MLLT calculations via randomized pruning. +splice_opts= +cluster_thresh=-1 # for build-tree control final bottom-up clustering of leaves +norm_vars=false # deprecated. Prefer --cmvn-opts "--norm-vars=false" +cmvn_opts= +context_opts= # use "--context-width=5 --central-position=2" for quinphone. +# End configuration. +train_tree=true # if false, don't actually train the tree. +use_lda_mat= # If supplied, use this LDA[+MLLT] matrix. +num_nonsil_states=3 + +echo "$0 $@" # Print the command line for logging + +[ -f path.sh ] && . ./path.sh +. parse_options.sh || exit 1; + +if [ $# != 6 ]; then + echo "Usage: steps/train_lda_mllt.sh [options] <#leaves> <#gauss> <data> <lang> <alignments> <dir>" + echo " e.g.: steps/train_lda_mllt.sh 2500 15000 data/train_si84 data/lang exp/tri1_ali_si84 exp/tri2b" + echo "Main options (for others, see top of script file)" + echo " --cmd (utils/run.pl|utils/queue.pl <queue opts>) # how to run jobs." + echo " --config <config-file> # config containing options" + echo " --stage <stage> # stage to do partial re-run from." + exit 1; +fi + +numleaves=$1 +totgauss=$2 +data=$3 +lang=$4 +alidir=$5 +dir=$6 + +for f in $alidir/final.mdl $alidir/ali.1.gz $data/feats.scp $lang/phones.txt; do + [ ! -f $f ] && echo "train_lda_mllt.sh: no such file $f" && exit 1; +done + +numgauss=$numleaves +incgauss=$[($totgauss-$numgauss)/$max_iter_inc] # per-iter #gauss increment +oov=`cat $lang/oov.int` || exit 1; +nj=`cat $alidir/num_jobs` || exit 1; +silphonelist=`cat $lang/phones/silence.csl` || exit 1; +ciphonelist=`cat $lang/phones/context_indep.csl` || exit 1; + +mkdir -p $dir/log + +utils/lang/check_phones_compatible.sh $lang/phones.txt $alidir/phones.txt || exit 1; +cp $lang/phones.txt $dir || exit 1; + +echo $nj >$dir/num_jobs +echo "$splice_opts" >$dir/splice_opts # keep track of frame-splicing options + # so that later stages of system building can know what they were. + + +[ $(cat $alidir/cmvn_opts 2>/dev/null | wc -c) -gt 1 ] && [ -z "$cmvn_opts" ] && \ + echo "$0: warning: ignoring CMVN options from source directory $alidir" +$norm_vars && cmvn_opts="--norm-vars=true $cmvn_opts" +echo $cmvn_opts > $dir/cmvn_opts # keep track of options to CMVN. + +sdata=$data/split$nj; +split_data.sh $data $nj || exit 1; + +splicedfeats="ark,s,cs:apply-cmvn $cmvn_opts --utt2spk=ark:$sdata/JOB/utt2spk scp:$sdata/JOB/cmvn.scp scp:$sdata/JOB/feats.scp ark:- | splice-feats $splice_opts ark:- ark:- |" +# Note: $feats gets overwritten later in the script. +feats="$splicedfeats transform-feats $dir/0.mat ark:- ark:- |" + + + +if [ $stage -le -5 ]; then + if [ -z "$use_lda_mat" ]; then + echo "$0: Accumulating LDA statistics." + rm $dir/lda.*.acc 2>/dev/null + $cmd JOB=1:$nj $dir/log/lda_acc.JOB.log \ + ali-to-post "ark:gunzip -c $alidir/ali.JOB.gz|" ark:- \| \ + weight-silence-post 0.0 $silphonelist $alidir/final.mdl ark:- ark:- \| \ + acc-lda --rand-prune=$randprune $alidir/final.mdl "$splicedfeats" ark,s,cs:- \ + $dir/lda.JOB.acc || exit 1; + est-lda --write-full-matrix=$dir/full.mat --dim=$dim $dir/0.mat $dir/lda.*.acc \ + 2>$dir/log/lda_est.log || exit 1; + rm $dir/lda.*.acc + else + echo "$0: Using supplied LDA matrix $use_lda_mat" + cp $use_lda_mat $dir/0.mat || exit 1; + [ ! -z "$mllt_iters" ] && \ + echo "$0: Warning: using supplied LDA matrix $use_lda_mat but we will do MLLT," && \ + echo " which you might not want; to disable MLLT, specify --mllt-iters ''" && \ + sleep 5 + fi +fi + +cur_lda_iter=0 + +if [ $stage -le -4 ] && $train_tree; then + echo "$0: Accumulating tree stats" + $cmd JOB=1:$nj $dir/log/acc_tree.JOB.log \ + acc-tree-stats $context_opts \ + --ci-phones=$ciphonelist $alidir/final.mdl "$feats" \ + "ark:gunzip -c $alidir/ali.JOB.gz|" $dir/JOB.treeacc || exit 1; + [ `ls $dir/*.treeacc | wc -w` -ne "$nj" ] && echo "$0: Wrong #tree-accs" && exit 1; + $cmd $dir/log/sum_tree_acc.log \ + sum-tree-stats $dir/treeacc $dir/*.treeacc || exit 1; + rm $dir/*.treeacc +fi + + +if [ $stage -le -3 ] && $train_tree; then + echo "$0: Getting questions for tree clustering." + # preparing questions, roots file... + cluster-phones --pdf-class-list=$(($num_nonsil_states / 2)) $context_opts $dir/treeacc $lang/phones/sets.int \ + $dir/questions.int 2> $dir/log/questions.log || exit 1; + cat $lang/phones/extra_questions.int >> $dir/questions.int + compile-questions $context_opts $lang/topo $dir/questions.int \ + $dir/questions.qst 2>$dir/log/compile_questions.log || exit 1; + + echo "$0: Building the tree" + $cmd $dir/log/build_tree.log \ + build-tree $context_opts --verbose=1 --max-leaves=$numleaves \ + --cluster-thresh=$cluster_thresh $dir/treeacc $lang/phones/roots.int \ + $dir/questions.qst $lang/topo $dir/tree || exit 1; +fi + +if [ $stage -le -2 ]; then + echo "$0: Initializing the model" + if $train_tree; then + gmm-init-model --write-occs=$dir/1.occs \ + $dir/tree $dir/treeacc $lang/topo $dir/1.mdl 2> $dir/log/init_model.log || exit 1; + grep 'no stats' $dir/log/init_model.log && echo "This is a bad warning."; + rm $dir/treeacc + else + cp $alidir/tree $dir/ || exit 1; + $cmd JOB=1 $dir/log/init_model.log \ + gmm-init-model-flat $dir/tree $lang/topo $dir/1.mdl \ + "$feats subset-feats ark:- ark:-|" || exit 1; + fi +fi + + +if [ $stage -le -1 ]; then + # Convert the alignments. + echo "$0: Converting alignments from $alidir to use current tree" + $cmd JOB=1:$nj $dir/log/convert.JOB.log \ + convert-ali $alidir/final.mdl $dir/1.mdl $dir/tree \ + "ark:gunzip -c $alidir/ali.JOB.gz|" "ark:|gzip -c >$dir/ali.JOB.gz" || exit 1; +fi + +if [ $stage -le 0 ] && [ "$realign_iters" != "" ]; then + echo "$0: Compiling graphs of transcripts" + $cmd JOB=1:$nj $dir/log/compile_graphs.JOB.log \ + compile-train-graphs --read-disambig-syms=$lang/phones/disambig.int $dir/tree $dir/1.mdl $lang/L.fst \ + "ark:utils/sym2int.pl --map-oov $oov -f 2- $lang/words.txt < $data/split$nj/JOB/text |" \ + "ark:|gzip -c >$dir/fsts.JOB.gz" || exit 1; +fi + + +x=1 +while [ $x -lt $num_iters ]; do + echo Training pass $x + if echo $realign_iters | grep -w $x >/dev/null && [ $stage -le $x ]; then + echo Aligning data + mdl="gmm-boost-silence --boost=$boost_silence `cat $lang/phones/optional_silence.csl` $dir/$x.mdl - |" + $cmd JOB=1:$nj $dir/log/align.$x.JOB.log \ + gmm-align-compiled $scale_opts --beam=$beam --retry-beam=$retry_beam --careful=$careful "$mdl" \ + "ark:gunzip -c $dir/fsts.JOB.gz|" "$feats" \ + "ark:|gzip -c >$dir/ali.JOB.gz" || exit 1; + fi + if echo $mllt_iters | grep -w $x >/dev/null; then + if [ $stage -le $x ]; then + echo "$0: Estimating MLLT" + $cmd JOB=1:$nj $dir/log/macc.$x.JOB.log \ + ali-to-post "ark:gunzip -c $dir/ali.JOB.gz|" ark:- \| \ + weight-silence-post 0.0 $silphonelist $dir/$x.mdl ark:- ark:- \| \ + gmm-acc-mllt --rand-prune=$randprune $dir/$x.mdl "$feats" ark:- $dir/$x.JOB.macc \ + || exit 1; + est-mllt $dir/$x.mat.new $dir/$x.*.macc 2> $dir/log/mupdate.$x.log || exit 1; + gmm-transform-means $dir/$x.mat.new $dir/$x.mdl $dir/$x.mdl \ + 2> $dir/log/transform_means.$x.log || exit 1; + compose-transforms --print-args=false $dir/$x.mat.new $dir/$cur_lda_iter.mat $dir/$x.mat || exit 1; + rm $dir/$x.*.macc + fi + feats="$splicedfeats transform-feats $dir/$x.mat ark:- ark:- |" + cur_lda_iter=$x + fi + + if [ $stage -le $x ]; then + $cmd JOB=1:$nj $dir/log/acc.$x.JOB.log \ + gmm-acc-stats-ali $dir/$x.mdl "$feats" \ + "ark,s,cs:gunzip -c $dir/ali.JOB.gz|" $dir/$x.JOB.acc || exit 1; + $cmd $dir/log/update.$x.log \ + gmm-est --write-occs=$dir/$[$x+1].occs --mix-up=$numgauss --power=$power \ + $dir/$x.mdl "gmm-sum-accs - $dir/$x.*.acc |" $dir/$[$x+1].mdl || exit 1; + rm $dir/$x.mdl $dir/$x.*.acc $dir/$x.occs + fi + [ $x -le $max_iter_inc ] && numgauss=$[$numgauss+$incgauss]; + x=$[$x+1]; +done + +rm $dir/final.{mdl,mat,occs} 2>/dev/null +ln -s $x.mdl $dir/final.mdl +ln -s $x.occs $dir/final.occs +ln -s $cur_lda_iter.mat $dir/final.mat + +steps/diagnostic/analyze_alignments.sh --cmd "$cmd" $lang $dir + +# Summarize warning messages... +utils/summarize_warnings.pl $dir/log + +steps/info/gmm_dir_info.pl $dir + +echo "$0: Done training system with LDA+MLLT features in $dir" + +exit 0 diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_sat.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_sat.sh new file mode 100755 index 0000000000..f75afafb1c --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/steps_gan/train_sat.sh @@ -0,0 +1,281 @@ +#!/usr/bin/env bash +# Copyright 2012 Johns Hopkins University (Author: Daniel Povey). Apache 2.0. + + +# This does Speaker Adapted Training (SAT), i.e. train on +# fMLLR-adapted features. It can be done on top of either LDA+MLLT, or +# delta and delta-delta features. If there are no transforms supplied +# in the alignment directory, it will estimate transforms itself before +# building the tree (and in any case, it estimates transforms a number +# of times during training). + + +# Begin configuration section. +stage=-5 +exit_stage=-100 # you can use this to require it to exit at the + # beginning of a specific stage. Not all values are + # supported. +fmllr_update_type=full +cmd=run.pl +scale_opts="--transition-scale=1.0 --acoustic-scale=0.1 --self-loop-scale=0.1" +beam=10 +retry_beam=40 +careful=false +boost_silence=1.0 # Factor by which to boost silence likelihoods in alignment +context_opts= # e.g. set this to "--context-width 5 --central-position 2" for quinphone. +realign_iters="10 20 30"; +fmllr_iters="2 4 6 12"; +silence_weight=0.0 # Weight on silence in fMLLR estimation. +num_iters=35 # Number of iterations of training +max_iter_inc=25 # Last iter to increase #Gauss on. +power=0.2 # Exponent for number of gaussians according to occurrence counts +cluster_thresh=-1 # for build-tree control final bottom-up clustering of leaves +phone_map= +train_tree=true +tree_stats_opts= +cluster_phones_opts= +compile_questions_opts= +# End configuration section. +num_nonsil_states=3 + +echo "$0 $@" # Print the command line for logging + +[ -f path.sh ] && . ./path.sh +. parse_options.sh || exit 1; + +if [ $# != 6 ]; then + echo "Usage: steps/train_sat.sh <#leaves> <#gauss> <data> <lang> <ali-dir> <exp-dir>" + echo " e.g.: steps/train_sat.sh 2500 15000 data/train_si84 data/lang exp/tri2b_ali_si84 exp/tri3b" + echo "Main options (for others, see top of script file)" + echo " --cmd (utils/run.pl|utils/queue.pl <queue opts>) # how to run jobs." + echo " --config <config-file> # config containing options" + echo " --stage <stage> # stage to do partial re-run from." + exit 1; +fi + +numleaves=$1 +totgauss=$2 +data=$3 +lang=$4 +alidir=$5 +dir=$6 + +for f in $data/feats.scp $lang/phones.txt $alidir/final.mdl $alidir/ali.1.gz; do + [ ! -f $f ] && echo "train_sat.sh: no such file $f" && exit 1; +done + +numgauss=$numleaves +incgauss=$[($totgauss-$numgauss)/$max_iter_inc] # per-iter #gauss increment +oov=`cat $lang/oov.int` +nj=`cat $alidir/num_jobs` || exit 1; +silphonelist=`cat $lang/phones/silence.csl` +ciphonelist=`cat $lang/phones/context_indep.csl` || exit 1; +sdata=$data/split$nj; +splice_opts=`cat $alidir/splice_opts 2>/dev/null` # frame-splicing options. +cmvn_opts=`cat $alidir/cmvn_opts 2>/dev/null` +delta_opts=`cat $alidir/delta_opts 2>/dev/null` +phone_map_opt= +[ ! -z "$phone_map" ] && phone_map_opt="--phone-map='$phone_map'" + +mkdir -p $dir/log +cp $alidir/splice_opts $dir 2>/dev/null # frame-splicing options. +cp $alidir/cmvn_opts $dir 2>/dev/null # cmn/cmvn option. +cp $alidir/delta_opts $dir 2>/dev/null # delta option. + +utils/lang/check_phones_compatible.sh $lang/phones.txt $alidir/phones.txt || exit 1; +cp $lang/phones.txt $dir || exit 1; + +echo $nj >$dir/num_jobs +[[ -d $sdata && $data/feats.scp -ot $sdata ]] || split_data.sh $data $nj || exit 1; + +# Set up features. + +if [ -f $alidir/final.mat ]; then feat_type=lda; else feat_type=delta; fi +echo "$0: feature type is $feat_type" + +## Set up speaker-independent features. +case $feat_type in + delta) sifeats="ark,s,cs:apply-cmvn $cmvn_opts --utt2spk=ark:$sdata/JOB/utt2spk scp:$sdata/JOB/cmvn.scp scp:$sdata/JOB/feats.scp ark:- | add-deltas $delta_opts ark:- ark:- |";; + lda) sifeats="ark,s,cs:apply-cmvn $cmvn_opts --utt2spk=ark:$sdata/JOB/utt2spk scp:$sdata/JOB/cmvn.scp scp:$sdata/JOB/feats.scp ark:- | splice-feats $splice_opts ark:- ark:- | transform-feats $alidir/final.mat ark:- ark:- |" + cp $alidir/final.mat $dir + cp $alidir/full.mat $dir 2>/dev/null + ;; + *) echo "$0: invalid feature type $feat_type" && exit 1; +esac + +## Get initial fMLLR transforms (possibly from alignment dir) +if [ -f $alidir/trans.1 ]; then + echo "$0: Using transforms from $alidir" + feats="$sifeats transform-feats --utt2spk=ark:$sdata/JOB/utt2spk ark,s,cs:$alidir/trans.JOB ark:- ark:- |" + cur_trans_dir=$alidir +else + if [ $stage -le -5 ]; then + echo "$0: obtaining initial fMLLR transforms since not present in $alidir" + # The next line is necessary because of $silphonelist otherwise being incorrect; would require + # old $lang dir which would require another option. Not needed anyway. + [ ! -z "$phone_map" ] && \ + echo "$0: error: you must provide transforms if you use the --phone-map option." && exit 1; + $cmd JOB=1:$nj $dir/log/fmllr.0.JOB.log \ + ali-to-post "ark:gunzip -c $alidir/ali.JOB.gz|" ark:- \| \ + weight-silence-post $silence_weight $silphonelist $alidir/final.mdl ark:- ark:- \| \ + gmm-est-fmllr --fmllr-update-type=$fmllr_update_type \ + --spk2utt=ark:$sdata/JOB/spk2utt $alidir/final.mdl "$sifeats" \ + ark:- ark:$dir/trans.JOB || exit 1; + fi + feats="$sifeats transform-feats --utt2spk=ark:$sdata/JOB/utt2spk ark,s,cs:$dir/trans.JOB ark:- ark:- |" + cur_trans_dir=$dir +fi + +if [ $stage -le -4 ] && $train_tree; then + # Get tree stats. + echo "$0: Accumulating tree stats" + $cmd JOB=1:$nj $dir/log/acc_tree.JOB.log \ + acc-tree-stats $context_opts $tree_stats_opts $phone_map_opt --ci-phones=$ciphonelist $alidir/final.mdl "$feats" \ + "ark:gunzip -c $alidir/ali.JOB.gz|" $dir/JOB.treeacc || exit 1; + [ "`ls $dir/*.treeacc | wc -w`" -ne "$nj" ] && echo "$0: Wrong #tree-accs" && exit 1; + $cmd $dir/log/sum_tree_acc.log \ + sum-tree-stats $dir/treeacc $dir/*.treeacc || exit 1; + rm $dir/*.treeacc +fi + +if [ $stage -le -3 ] && $train_tree; then + echo "$0: Getting questions for tree clustering." + # preparing questions, roots file... + cluster-phones --pdf-class-list=$(($num_nonsil_states / 2)) \ + $cluster_phones_opts $context_opts \ + $dir/treeacc $lang/phones/sets.int $dir/questions.int 2>$dir/log/questions.log || exit 1; + cat $lang/phones/extra_questions.int >> $dir/questions.int + compile-questions $context_opts $compile_questions_opts $lang/topo $dir/questions.int $dir/questions.qst 2>$dir/log/compile_questions.log || exit 1; + + echo "$0: Building the tree" + $cmd $dir/log/build_tree.log \ + build-tree $context_opts --verbose=1 --max-leaves=$numleaves \ + --cluster-thresh=$cluster_thresh $dir/treeacc $lang/phones/roots.int \ + $dir/questions.qst $lang/topo $dir/tree || exit 1; +fi + +if [ $stage -le -2 ]; then + echo "$0: Initializing the model" + if $train_tree; then + gmm-init-model --write-occs=$dir/1.occs \ + $dir/tree $dir/treeacc $lang/topo $dir/1.mdl 2> $dir/log/init_model.log || exit 1; + grep 'no stats' $dir/log/init_model.log && echo "This is a bad warning."; + rm $dir/treeacc + else + cp $alidir/tree $dir/ || exit 1; + $cmd JOB=1 $dir/log/init_model.log \ + gmm-init-model-flat $dir/tree $lang/topo $dir/1.mdl \ + "$feats subset-feats ark:- ark:-|" || exit 1; + fi +fi + +if [ $stage -le -1 ]; then + # Convert the alignments. + echo "$0: Converting alignments from $alidir to use current tree" + $cmd JOB=1:$nj $dir/log/convert.JOB.log \ + convert-ali $phone_map_opt $alidir/final.mdl $dir/1.mdl $dir/tree \ + "ark:gunzip -c $alidir/ali.JOB.gz|" "ark:|gzip -c >$dir/ali.JOB.gz" || exit 1; +fi + +[ "$exit_stage" -eq 0 ] && echo "$0: Exiting early: --exit-stage $exit_stage" && exit 0; + +if [ $stage -le 0 ] && [ "$realign_iters" != "" ]; then + echo "$0: Compiling graphs of transcripts" + $cmd JOB=1:$nj $dir/log/compile_graphs.JOB.log \ + compile-train-graphs --read-disambig-syms=$lang/phones/disambig.int $dir/tree $dir/1.mdl $lang/L.fst \ + "ark:utils/sym2int.pl --map-oov $oov -f 2- $lang/words.txt < $sdata/JOB/text |" \ + "ark:|gzip -c >$dir/fsts.JOB.gz" || exit 1; +fi + +x=1 +while [ $x -lt $num_iters ]; do + echo Pass $x + if echo $realign_iters | grep -w $x >/dev/null && [ $stage -le $x ]; then + echo Aligning data + mdl="gmm-boost-silence --boost=$boost_silence `cat $lang/phones/optional_silence.csl` $dir/$x.mdl - |" + $cmd JOB=1:$nj $dir/log/align.$x.JOB.log \ + gmm-align-compiled $scale_opts --beam=$beam --retry-beam=$retry_beam --careful=$careful "$mdl" \ + "ark:gunzip -c $dir/fsts.JOB.gz|" "$feats" \ + "ark:|gzip -c >$dir/ali.JOB.gz" || exit 1; + fi + + if echo $fmllr_iters | grep -w $x >/dev/null; then + if [ $stage -le $x ]; then + echo Estimating fMLLR transforms + # We estimate a transform that's additional to the previous transform; + # we'll compose them. + $cmd JOB=1:$nj $dir/log/fmllr.$x.JOB.log \ + ali-to-post "ark:gunzip -c $dir/ali.JOB.gz|" ark:- \| \ + weight-silence-post $silence_weight $silphonelist $dir/$x.mdl ark:- ark:- \| \ + gmm-est-fmllr --fmllr-update-type=$fmllr_update_type \ + --spk2utt=ark:$sdata/JOB/spk2utt $dir/$x.mdl \ + "$feats" ark:- ark:$dir/tmp_trans.JOB || exit 1; + for n in `seq $nj`; do + ! ( compose-transforms --b-is-affine=true \ + ark:$dir/tmp_trans.$n ark:$cur_trans_dir/trans.$n ark:$dir/composed_trans.$n \ + && mv $dir/composed_trans.$n $dir/trans.$n && \ + rm $dir/tmp_trans.$n ) 2>$dir/log/compose_transforms.$x.log \ + && echo "$0: Error composing transforms" && exit 1; + done + fi + feats="$sifeats transform-feats --utt2spk=ark:$sdata/JOB/utt2spk ark:$dir/trans.JOB ark:- ark:- |" + cur_trans_dir=$dir + fi + + if [ $stage -le $x ]; then + $cmd JOB=1:$nj $dir/log/acc.$x.JOB.log \ + gmm-acc-stats-ali $dir/$x.mdl "$feats" \ + "ark,s,cs:gunzip -c $dir/ali.JOB.gz|" $dir/$x.JOB.acc || exit 1; + [ `ls $dir/$x.*.acc | wc -w` -ne "$nj" ] && echo "$0: Wrong #accs" && exit 1; + $cmd $dir/log/update.$x.log \ + gmm-est --power=$power --write-occs=$dir/$[$x+1].occs --mix-up=$numgauss $dir/$x.mdl \ + "gmm-sum-accs - $dir/$x.*.acc |" $dir/$[$x+1].mdl || exit 1; + rm $dir/$x.mdl $dir/$x.*.acc + rm $dir/$x.occs + fi + [ $x -le $max_iter_inc ] && numgauss=$[$numgauss+$incgauss]; + x=$[$x+1]; +done + + +if [ $stage -le $x ]; then + # Accumulate stats for "alignment model"-- this model is + # computed with the speaker-independent features, but matches Gaussian-for-Gaussian + # with the final speaker-adapted model. + $cmd JOB=1:$nj $dir/log/acc_alimdl.JOB.log \ + ali-to-post "ark:gunzip -c $dir/ali.JOB.gz|" ark:- \| \ + gmm-acc-stats-twofeats $dir/$x.mdl "$feats" "$sifeats" \ + ark,s,cs:- $dir/$x.JOB.acc || exit 1; + [ `ls $dir/$x.*.acc | wc -w` -ne "$nj" ] && echo "$0: Wrong #accs" && exit 1; + # Update model. + $cmd $dir/log/est_alimdl.log \ + gmm-est --power=$power --remove-low-count-gaussians=false $dir/$x.mdl \ + "gmm-sum-accs - $dir/$x.*.acc|" $dir/$x.alimdl || exit 1; + rm $dir/$x.*.acc +fi + +rm $dir/final.{mdl,alimdl,occs} 2>/dev/null +ln -s $x.mdl $dir/final.mdl +ln -s $x.occs $dir/final.occs +ln -s $x.alimdl $dir/final.alimdl + + +steps/diagnostic/analyze_alignments.sh --cmd "$cmd" $lang $dir + +utils/summarize_warnings.pl $dir/log +( + echo "$0: Likelihood evolution:" + for x in `seq $[$num_iters-1]`; do + tail -n 30 $dir/log/acc.$x.*.log | awk '/Overall avg like/{l += $(NF-3)*$(NF-1); t += $(NF-1); } + /Overall average logdet/{d += $(NF-3)*$(NF-1); t2 += $(NF-1);} + END{ d /= t2; l /= t; printf("%s ", d+l); } ' + done + echo +) | tee $dir/log/summary.log + + +steps/info/gmm_dir_info.pl $dir + +echo "$0: done training SAT system in $dir" + +exit 0 diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/train.sh b/examples/wav2vec/unsupervised/kaldi_self_train/st/train.sh new file mode 100644 index 0000000000..f3a3d3fc7c --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/train.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +set -eu + +w2v_dir= # contains features `{train,valid}.{npy,lengths}`, real transcripts `{train,valid}.${label}`, and dict `dict.${label}.txt` +lab_dir= # contains pseudo labels `{train,valid}.txt` +out_dir= # output root +arpa_lm= # phone LM +arpa_lm_bin= # (binary) phone LM for KenLM, used in unsupervised selection + +label=phnc +train_name="train" +valid_name="valid" +data_dir=${out_dir}/data + +mkdir -p ${out_dir}/exp +local/prepare_lang.sh $w2v_dir/dict.${label}.txt $data_dir +local/prepare_lm.sh $arpa_lm $data_dir + +for x in $train_name $valid_name; do + x_gt=${x}_gt + + # prepare pseudo data + python local/prepare_data_from_w2v.py $w2v_dir $data_dir $x + steps/compute_cmvn_stats.sh $data_dir/$x $out_dir/exp/make_feat/$x $out_dir/feats/$x + python local/copy_aligned_text.py < $lab_dir/$x.txt > $data_dir/$x/text + + # prepare ground truth data + mkdir $data_dir/$x_gt + cp $data_dir/$x/{feats.scp,cmvn.scp,utt2spk,spk2utt} $data_dir/$x_gt/ + python local/copy_aligned_text.py < $w2v_dir/$x.$label > $data_dir/$x_gt/text +done + +local/train_subset_lgbeam.sh \ + --out_root ${out_dir} --out_name exp --train $train_name --valid $valid_name \ + --mono_size 2000 --tri1_size 5000 --tri2b_size -1 --tri3b_size -1 \ + --stage 1 --max_stage 3 $data_dir $data_dir/lang $data_dir/lang_test + +local/unsup_select_decode.sh \ + --split $valid_name --kenlm_path $arpa_lm_bin \ + --ref_txt $data_dir/${valid_name}_gt/text \ + --psd_txt $data_dir/${valid_name}/text \ + $out_dir/exp diff --git a/examples/wav2vec/unsupervised/kaldi_self_train/st/utils b/examples/wav2vec/unsupervised/kaldi_self_train/st/utils new file mode 120000 index 0000000000..b240885218 --- /dev/null +++ b/examples/wav2vec/unsupervised/kaldi_self_train/st/utils @@ -0,0 +1 @@ +../../wsj/s5/utils \ No newline at end of file diff --git a/examples/wav2vec/unsupervised/models/__init__.py b/examples/wav2vec/unsupervised/models/__init__.py new file mode 100644 index 0000000000..3e3039b708 --- /dev/null +++ b/examples/wav2vec/unsupervised/models/__init__.py @@ -0,0 +1,11 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .wav2vec_u import Wav2vec_U + + +__all__ = [ + "Wav2vec_U", +] diff --git a/examples/wav2vec/unsupervised/models/wav2vec_u.py b/examples/wav2vec/unsupervised/models/wav2vec_u.py new file mode 100644 index 0000000000..d3f195b94e --- /dev/null +++ b/examples/wav2vec/unsupervised/models/wav2vec_u.py @@ -0,0 +1,658 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass +from enum import Enum, auto +import math +import numpy as np +from typing import Tuple, List, Optional, Dict + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch import autograd + +from fairseq import checkpoint_utils, utils +from fairseq.dataclass import FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model +from fairseq.modules import ( + SamePad, + TransposeLast, +) + + +class SegmentationType(Enum): + NONE = auto() + RANDOM = auto() + UNIFORM_RANDOM = auto() + UNIFORM_RANDOM_JOIN = auto() + JOIN = auto() + + +@dataclass +class SegmentationConfig(FairseqDataclass): + type: SegmentationType = SegmentationType.NONE + subsample_rate: float = 0.25 + mean_pool: bool = True + mean_pool_join: bool = False + remove_zeros: bool = False + + +@dataclass +class Wav2vec_UConfig(FairseqDataclass): + + discriminator_kernel: int = 3 + discriminator_dilation: int = 1 + discriminator_dim: int = 256 + discriminator_causal: bool = True + discriminator_linear_emb: bool = False + discriminator_depth: int = 1 + discriminator_max_pool: bool = False + discriminator_act_after_linear: bool = False + discriminator_dropout: float = 0.0 + discriminator_spectral_norm: bool = False + discriminator_weight_norm: bool = False + + generator_kernel: int = 4 + generator_dilation: int = 1 + generator_stride: int = 1 + generator_bias: bool = False + generator_dropout: float = 0.0 + + blank_weight: float = 0 + blank_mode: str = "add" + blank_is_sil: bool = False + no_softmax: bool = False + + smoothness_weight: float = 0.0 + smoothing: float = 0.0 + smoothing_one_sided: bool = False + gradient_penalty: float = 0.0 + probabilistic_grad_penalty_slicing: bool = False + code_penalty: float = 0.0 + gumbel: bool = False + hard_gumbel: bool = True + temp: Tuple[float, float, float] = (2, 0.1, 0.99995) + input_dim: int = 128 + wgan_loss: bool = False + + segmentation: SegmentationConfig = SegmentationConfig() + + +class Segmenter(nn.Module): + cfg: SegmentationConfig + + def __init__(self, cfg: SegmentationConfig): + super().__init__() + self.cfg = cfg + self.subsample_rate = cfg.subsample_rate + + def pre_segment(self, dense_x, dense_padding_mask): + return dense_x, dense_padding_mask + + def logit_segment(self, logits, padding_mask): + return logits, padding_mask + + +class RandomSegmenter(Segmenter): + def pre_segment(self, dense_x, dense_padding_mask): + target_num = math.ceil(dense_x.size(1) * self.subsample_rate) + ones = torch.ones(dense_x.shape[:-1], device=dense_x.device) + indices, _ = ones.multinomial(target_num).sort(dim=-1) + indices_ld = indices.unsqueeze(-1).expand(-1, -1, dense_x.size(-1)) + dense_x = dense_x.gather(1, indices_ld) + dense_padding_mask = dense_padding_mask.gather(1, index=indices) + return dense_x, dense_padding_mask + + +class UniformRandomSegmenter(Segmenter): + def pre_segment(self, dense_x, dense_padding_mask): + bsz, tsz, fsz = dense_x.shape + + target_num = math.ceil(tsz * self.subsample_rate) + + rem = tsz % target_num + + if rem > 0: + dense_x = F.pad(dense_x, [0, 0, 0, target_num - rem]) + dense_padding_mask = F.pad( + dense_padding_mask, [0, target_num - rem], value=True + ) + + dense_x = dense_x.view(bsz, target_num, -1, fsz) + dense_padding_mask = dense_padding_mask.view(bsz, target_num, -1) + + if self.cfg.mean_pool: + dense_x = dense_x.mean(dim=-2) + dense_padding_mask = dense_padding_mask.all(dim=-1) + else: + ones = torch.ones((bsz, dense_x.size(2)), device=dense_x.device) + indices = ones.multinomial(1) + indices = indices.unsqueeze(-1).expand(-1, target_num, -1) + indices_ld = indices.unsqueeze(-1).expand(-1, -1, -1, fsz) + dense_x = dense_x.gather(2, indices_ld).reshape(bsz, -1, fsz) + dense_padding_mask = dense_padding_mask.gather(2, index=indices).reshape( + bsz, -1 + ) + return dense_x, dense_padding_mask + + +class JoinSegmenter(Segmenter): + def logit_segment(self, logits, padding_mask): + preds = logits.argmax(dim=-1) + + if padding_mask.any(): + preds[padding_mask] = -1 # mark pad + uniques = [] + + bsz, tsz, csz = logits.shape + + for p in preds: + uniques.append( + p.cpu().unique_consecutive(return_inverse=True, return_counts=True) + ) + + new_tsz = max(u[0].numel() for u in uniques) + new_logits = logits.new_zeros(bsz, new_tsz, csz) + new_pad = padding_mask.new_zeros(bsz, new_tsz) + + for b in range(bsz): + u, idx, c = uniques[b] + keep = u != -1 + + if self.cfg.remove_zeros: + keep.logical_and_(u != 0) + + if self.training and not self.cfg.mean_pool_join: + u[0] = 0 + u[1:] = c.cumsum(0)[:-1] + m = c > 1 + r = torch.rand(m.sum()) + o = (c[m] * r).long() + u[m] += o + new_logits[b, : u.numel()] = logits[b, u] + else: + new_logits[b].index_add_( + dim=0, index=idx.to(new_logits.device), source=logits[b] + ) + new_logits[b, : c.numel()] /= c.unsqueeze(-1).to(new_logits.device) + + new_sz = keep.sum() + if not keep.all(): + kept_logits = new_logits[b, : c.numel()][keep] + new_logits[b, :new_sz] = kept_logits + + if new_sz < new_tsz: + pad = new_tsz - new_sz + new_logits[b, -pad:] = 0 + new_pad[b, -pad:] = True + + return new_logits, new_pad + + +class UniformRandomJoinSegmenter(UniformRandomSegmenter, JoinSegmenter): + pass + + +SEGMENT_FACTORY = { + SegmentationType.NONE: Segmenter, + SegmentationType.RANDOM: RandomSegmenter, + SegmentationType.UNIFORM_RANDOM: UniformRandomSegmenter, + SegmentationType.UNIFORM_RANDOM_JOIN: UniformRandomJoinSegmenter, + SegmentationType.JOIN: JoinSegmenter, +} + + +class Discriminator(nn.Module): + def __init__(self, dim, cfg: Wav2vec_UConfig): + super().__init__() + + inner_dim = cfg.discriminator_dim + kernel = cfg.discriminator_kernel + dilation = cfg.discriminator_dilation + self.max_pool = cfg.discriminator_max_pool + + if cfg.discriminator_causal: + padding = kernel - 1 + else: + padding = kernel // 2 + + def make_conv(in_d, out_d, k, p=0, has_dilation=True): + conv = nn.Conv1d( + in_d, + out_d, + kernel_size=k, + padding=p, + dilation=dilation if has_dilation else 1, + ) + if cfg.discriminator_spectral_norm: + conv = nn.utils.spectral_norm(conv) + elif cfg.discriminator_weight_norm: + conv = nn.utils.weight_norm(conv) + return conv + + inner_net = [ + nn.Sequential( + make_conv(inner_dim, inner_dim, kernel, padding), + SamePad(kernel_size=kernel, causal=cfg.discriminator_causal), + nn.Dropout(cfg.discriminator_dropout), + nn.GELU(), + ) + for _ in range(cfg.discriminator_depth - 1) + ] + [ + make_conv(inner_dim, 1, kernel, padding, has_dilation=False), + SamePad(kernel_size=kernel, causal=cfg.discriminator_causal), + ] + + if cfg.discriminator_linear_emb: + emb_net = [make_conv(dim, inner_dim, 1)] + else: + emb_net = [ + make_conv(dim, inner_dim, kernel, padding), + SamePad(kernel_size=kernel, causal=cfg.discriminator_causal), + ] + + if cfg.discriminator_act_after_linear: + emb_net.append(nn.GELU()) + + self.net = nn.Sequential( + *emb_net, + nn.Dropout(cfg.discriminator_dropout), + *inner_net, + ) + + def forward(self, x, padding_mask): + x = x.transpose(1, 2) # BTC -> BCT + x = self.net(x) + x = x.transpose(1, 2) + x_sz = x.size(1) + if padding_mask is not None and padding_mask.any() and padding_mask.dim() > 1: + padding_mask = padding_mask[:, : x.size(1)] + x[padding_mask] = float("-inf") if self.max_pool else 0 + x_sz = x_sz - padding_mask.sum(dim=-1) + x = x.squeeze(-1) + if self.max_pool: + x, _ = x.max(dim=-1) + else: + x = x.sum(dim=-1) + x = x / x_sz + return x + + +class Generator(nn.Module): + def __init__(self, input_dim, output_dim, cfg: Wav2vec_UConfig): + super().__init__() + + self.cfg = cfg + self.output_dim = output_dim + self.stride = cfg.generator_stride + self.dropout = nn.Dropout(cfg.generator_dropout) + + padding = cfg.generator_kernel // 2 + self.proj = nn.Sequential( + TransposeLast(), + nn.Conv1d( + input_dim, + output_dim, + kernel_size=cfg.generator_kernel, + stride=cfg.generator_stride, + dilation=cfg.generator_dilation, + padding=padding, + bias=cfg.generator_bias, + ), + TransposeLast(), + ) + + def forward(self, dense_x, tokens, dense_padding_mask): + dense_x = self.dropout(dense_x) + + dense_x = self.proj(dense_x) + if self.stride > 1: + dense_padding_mask = dense_padding_mask[:, :: self.stride] + + if dense_padding_mask.size(1) != dense_x.size(1): + new_padding = dense_padding_mask.new_zeros(dense_x.shape[:-1]) + diff = new_padding.size(1) - dense_padding_mask.size(1) + assert ( + diff > 0 + ), f"{new_padding.shape}, {dense_padding_mask.shape}, {dense_x.shape}, {diff}" + if diff > 0: + new_padding[:, diff:] = dense_padding_mask + else: + assert diff < 0 + new_padding = dense_padding_mask[:, :diff] + + dense_padding_mask = new_padding + + result = {} + + token_x = None + if tokens is not None: + token_x = dense_x.new_zeros(tokens.numel(), self.output_dim) + token_x.scatter_(1, tokens.view(-1, 1).long(), 1) + token_x = token_x.view(tokens.shape + (self.output_dim,)) + + result["dense_x"] = dense_x + result["token_x"] = token_x + result["dense_padding_mask"] = dense_padding_mask + + return result + + +@register_model("wav2vec_u", dataclass=Wav2vec_UConfig) +class Wav2vec_U(BaseFairseqModel): + def calc_gradient_penalty(self, real_data, fake_data): + + b_size = min(real_data.size(0), fake_data.size(0)) + t_size = min(real_data.size(1), fake_data.size(1)) + + if self.cfg.probabilistic_grad_penalty_slicing: + + def get_slice(data, dim, target_size): + + size = data.size(dim) + diff = size - target_size + if diff <= 0: + return data + + start = np.random.randint(0, diff + 1) + return data.narrow(dim=dim, start=start, length=target_size) + + real_data = get_slice(real_data, 0, b_size) + real_data = get_slice(real_data, 1, t_size) + fake_data = get_slice(fake_data, 0, b_size) + fake_data = get_slice(fake_data, 1, t_size) + + else: + real_data = real_data[:b_size, :t_size] + fake_data = fake_data[:b_size, :t_size] + + alpha = torch.rand(real_data.size(0), 1, 1) + alpha = alpha.expand(real_data.size()) + alpha = alpha.to(real_data.device) + + interpolates = alpha * real_data + ((1 - alpha) * fake_data) + + disc_interpolates = self.discriminator(interpolates, None) + + gradients = autograd.grad( + outputs=disc_interpolates, + inputs=interpolates, + grad_outputs=torch.ones(disc_interpolates.size(), device=real_data.device), + create_graph=True, + retain_graph=True, + only_inputs=True, + )[0] + + gradient_penalty = (gradients.norm(2, dim=1) - 1) ** 2 + return gradient_penalty + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + self.update_num = num_updates + self.curr_temp = max( + self.max_temp * self.temp_decay ** num_updates, self.min_temp + ) + + def discrim_step(self, num_updates): + if num_updates < self.zero_pretrain_updates: + return False + if self.dynamic_step_thresh <= 0 or self.last_acc is None: + return num_updates % 2 == 1 + else: + return self.last_acc < self.dynamic_step_thresh + + def get_groups_for_update(self, num_updates): + return "discriminator" if self.discrim_step(num_updates) else "generator" + + def __init__(self, cfg: Wav2vec_UConfig, target_dict): + super().__init__() + + self.cfg = cfg + self.zero_index = target_dict.index("<SIL>") if "<SIL>" in target_dict else 0 + self.smoothness_weight = cfg.smoothness_weight + self.wgan_loss = cfg.wgan_loss + + output_size = len(target_dict) + self.pad = target_dict.pad() + self.eos = target_dict.eos() + self.smoothing = cfg.smoothing + self.smoothing_one_sided = cfg.smoothing_one_sided + self.no_softmax = cfg.no_softmax + self.gumbel = cfg.gumbel + self.hard_gumbel = cfg.hard_gumbel + self.last_acc = None + + self.gradient_penalty = cfg.gradient_penalty + self.code_penalty = cfg.code_penalty + self.blank_weight = cfg.blank_weight + self.blank_mode = cfg.blank_mode + self.blank_index = target_dict.index("<SIL>") if cfg.blank_is_sil else 0 + assert self.blank_index != target_dict.unk() + + self.discriminator = self.Discriminator(output_size, cfg) + for p in self.discriminator.parameters(): + p.param_group = "discriminator" + + self.pca_A = self.pca_b = None + d = cfg.input_dim + + self.segmenter = SEGMENT_FACTORY[cfg.segmentation.type](cfg.segmentation) + + self.generator = self.Generator( + d, output_size, cfg, lambda x: self.normalize(x)[0] + ) + + for p in self.generator.parameters(): + p.param_group = "generator" + + for p in self.segmenter.parameters(): + p.param_group = "generator" + + self.max_temp, self.min_temp, self.temp_decay = cfg.temp + self.curr_temp = self.max_temp + self.update_num = 0 + + @classmethod + def build_model(cls, cfg, task): + return cls(cfg, task.target_dictionary) + + def get_logits( + self, + net_output: Optional[Dict[str, List[Optional[torch.Tensor]]]], + normalize: bool = False, + ): + logits = net_output["logits"] + + if self.blank_weight != 0: + if self.blank_mode == "add": + logits[..., self.blank_index] += self.blank_weight + elif self.blank_mode == "set": + logits[..., self.blank_index] = self.blank_weight + else: + raise Exception(f"invalid blank mode {self.blank_mode}") + + padding = net_output["padding_mask"] + if padding.any(): + logits[padding] = float("-inf") + logits[padding][..., self.blank_index] = float("inf") + + if normalize: + logits = utils.log_softmax(logits.float(), dim=-1) + + return logits.transpose(0, 1) + + def get_normalized_probs( + self, + net_output: Tuple[ + torch.Tensor, Optional[Dict[str, List[Optional[torch.Tensor]]]] + ], + log_probs: bool, + sample: Optional[Dict[str, torch.Tensor]] = None, + ): + logits = self.get_logits(net_output) + + probs = super().get_normalized_probs(logits, log_probs, sample) + # BTC -> TBC for ctc + probs = probs.transpose(0, 1) + return probs + + def normalize(self, dense_x): + + bsz, tsz, csz = dense_x.shape + + if dense_x.numel() == 0: + raise Exception(dense_x.shape) + _, k = dense_x.max(-1) + hard_x = ( + dense_x.new_zeros(bsz * tsz, csz) + .scatter_(-1, k.view(-1, 1), 1.0) + .view(-1, csz) + ) + hard_probs = torch.mean(hard_x.float(), dim=0) + code_perplexity = torch.exp( + -torch.sum(hard_probs * torch.log(hard_probs + 1e-7), dim=-1) + ) + + avg_probs = torch.softmax(dense_x.reshape(-1, csz).float(), dim=-1).mean(dim=0) + prob_perplexity = torch.exp( + -torch.sum(avg_probs * torch.log(avg_probs + 1e-7), dim=-1) + ) + + if not self.no_softmax: + if self.training and self.gumbel: + dense_x = F.gumbel_softmax( + dense_x.float(), tau=self.curr_temp, hard=self.hard_gumbel + ).type_as(dense_x) + else: + dense_x = dense_x.softmax(-1) + + return dense_x, code_perplexity, prob_perplexity + + def forward( + self, + features, + padding_mask, + random_label=None, + dense_x_only=False, + segment=True, + ): + if segment: + features, padding_mask = self.segmenter.pre_segment(features, padding_mask) + + orig_size = features.size(0) * features.size(1) - padding_mask.sum() + + gen_result = self.generator(features, random_label, padding_mask) + + orig_dense_x, token_x = gen_result["dense_x"], gen_result["token_x"] + orig_dense_padding_mask = gen_result["dense_padding_mask"] + + if segment: + dense_x, dense_padding_mask = self.segmenter.logit_segment( + orig_dense_x, orig_dense_padding_mask + ) + else: + dense_x = orig_dense_x + dense_padding_mask = orig_dense_padding_mask + + dense_logits = dense_x + prob_perplexity = None + code_perplexity = None + + if not (self.no_softmax and dense_x_only): + dense_x, code_perplexity, prob_perplexity = self.normalize(dense_logits) + + if dense_x_only or self.discriminator is None: + return { + "logits": dense_x, + "padding_mask": dense_padding_mask, + } + + token_padding_mask = random_label == self.pad + + dense_y = self.discriminator(dense_x, dense_padding_mask) + token_y = self.discriminator(token_x, token_padding_mask) + + sample_size = features.size(0) + + d_step = self.discrim_step(self.update_num) + + fake_smooth = self.smoothing + real_smooth = self.smoothing + if self.smoothing_one_sided: + fake_smooth = 0 + + zero_loss = None + smoothness_loss = None + code_pen = None + + if d_step: + if self.wgan_loss: + loss_dense = dense_y.sum() + loss_token = -1 * token_y.sum() + else: + loss_dense = F.binary_cross_entropy_with_logits( + dense_y, + dense_y.new_ones(dense_y.shape) - fake_smooth, + reduction="sum", + ) + loss_token = F.binary_cross_entropy_with_logits( + token_y, + token_y.new_zeros(token_y.shape) + real_smooth, + reduction="sum", + ) + if self.training and self.gradient_penalty > 0: + grad_pen = self.calc_gradient_penalty(token_x, dense_x) + grad_pen = grad_pen.sum() * self.gradient_penalty + else: + grad_pen = None + else: + grad_pen = None + loss_token = None + if self.update_num >= self.zero_pretrain_updates: + if self.wgan_loss: + loss_dense = -1 * dense_y.sum() + else: + loss_dense = F.binary_cross_entropy_with_logits( + dense_y, + dense_y.new_zeros(dense_y.shape) + fake_smooth, + reduction="sum", + ) + num_vars = dense_x.size(-1) + if prob_perplexity is not None: + code_pen = (num_vars - prob_perplexity) / num_vars + if self.exponential_code_pen: + code_pen = (1 - 1 / code_pen ** 2).exp() + code_pen = code_pen * sample_size * self.code_penalty + else: + loss_dense = None + + if self.smoothness_weight > 0: + smoothness_loss = F.mse_loss( + dense_logits[:, :-1], dense_logits[:, 1:], reduction="none" + ) + smoothness_loss[dense_padding_mask[:, 1:]] = 0 + smoothness_loss = ( + smoothness_loss.mean() * sample_size * self.smoothness_weight + ) + + result = { + "losses": { + "grad_pen": grad_pen, + "code_pen": code_pen, + "smoothness": smoothness_loss, + }, + "temp": self.curr_temp, + "code_ppl": code_perplexity, + "prob_ppl": prob_perplexity, + "d_steps": int(d_step), + "sample_size": sample_size, + } + + suff = "_d" if d_step else "_g" + result["losses"]["dense" + suff] = loss_dense + result["losses"]["token" + suff] = loss_token + + return result diff --git a/examples/wav2vec/unsupervised/scripts/apply_pca.py b/examples/wav2vec/unsupervised/scripts/apply_pca.py new file mode 100644 index 0000000000..0cddd20001 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/apply_pca.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os +import os.path as osp +import math +import numpy as np +import tqdm +import torch +from shutil import copyfile + +from npy_append_array import NpyAppendArray + + +def get_parser(): + parser = argparse.ArgumentParser( + description="transforms features via a given pca and stored them in target dir" + ) + # fmt: off + parser.add_argument('source', help='directory with features') + parser.add_argument('--split', help='which split to read', required=True) + parser.add_argument('--save-dir', help='where to save the output', required=True) + parser.add_argument('--pca-path', type=str, help='pca location. will append _A.npy and _b.npy', required=True) + parser.add_argument('--batch-size', type=int, default=2048000, help='batch size') + parser.add_argument('--unfiltered', action='store_true', help='process the unfiltered version') + # fmt: on + + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + + source_path = osp.join(args.source, args.split) + data_poth = source_path + "_unfiltered" if args.unfiltered else source_path + + print(f"data path: {data_poth}") + + features = np.load(data_poth + ".npy", mmap_mode="r") + pca_A = torch.from_numpy(np.load(args.pca_path + "_A.npy")).cuda() + pca_b = torch.from_numpy(np.load(args.pca_path + "_b.npy")).cuda() + + os.makedirs(args.save_dir, exist_ok=True) + save_path = osp.join(args.save_dir, args.split) + + copyfile(source_path + ".tsv", save_path + ".tsv") + copyfile(data_poth + ".lengths", save_path + ".lengths") + copyfile(source_path + ".phn", save_path + ".phn") + copyfile(source_path + ".wrd", save_path + ".wrd") + + if osp.exists(save_path + ".npy"): + os.remove(save_path + ".npy") + npaa = NpyAppendArray(save_path + ".npy") + + batches = math.ceil(features.shape[0] / args.batch_size) + + with torch.no_grad(): + for b in tqdm.trange(batches): + start = b * args.batch_size + end = start + args.batch_size + x = torch.from_numpy(features[start:end]).cuda() + x = torch.matmul(x, pca_A) + pca_b + npaa.append(x.cpu().numpy()) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/copy_labels.py b/examples/wav2vec/unsupervised/scripts/copy_labels.py new file mode 100644 index 0000000000..989868388e --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/copy_labels.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import sys + +for idx, line in enumerate(sys.stdin): + print(f"utt{idx:010d} {line}", end="") diff --git a/examples/wav2vec/unsupervised/scripts/filter_lexicon.py b/examples/wav2vec/unsupervised/scripts/filter_lexicon.py new file mode 100644 index 0000000000..5bf3e51e7a --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/filter_lexicon.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import sys + +from fairseq.data import Dictionary + + +def get_parser(): + parser = argparse.ArgumentParser( + description="filters a lexicon given a unit dictionary" + ) + parser.add_argument("-d", "--unit-dict", help="unit dictionary", required=True) + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + + d = Dictionary.load(args.unit_dict) + symbols = set(d.symbols) + + for line in sys.stdin: + items = line.rstrip().split() + skip = len(items) < 2 + for x in items[1:]: + if x not in symbols: + skip = True + break + if not skip: + print(line, end="") + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/filter_tsv.py b/examples/wav2vec/unsupervised/scripts/filter_tsv.py new file mode 100644 index 0000000000..a09d79acf3 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/filter_tsv.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import argparse +import sys + + +parser = argparse.ArgumentParser() +parser.add_argument("--tsv", required=True, type=str) +parser.add_argument("--no-skip", action="store_true") +parser.add_argument("--keep", action="store_true") +params = parser.parse_args() + + +def get_fname(line): + p = os.path.basename(line.split("\t")[0]) + p = os.path.splitext(p)[0] + return p + + +# filenames to exclude +seen = set() +with open(params.tsv) as f: + if not params.no_skip: + root = next(f).rstrip() + for line in f: + seen.add(get_fname(line)) + +for i, line in enumerate(sys.stdin): + exists = get_fname(line) in seen + keep = (exists and params.keep) or (not exists and not params.keep) + if i == 0 or keep: + print(line, end="") diff --git a/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py b/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py new file mode 100644 index 0000000000..8c3138e55b --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import sys + +from g2p_en import G2p + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("root_dirs", nargs="*") + parser.add_argument("--insert-silence", "-s", action="store_true") + args = parser.parse_args() + sil = "<s>" + + wrd_to_phn = {} + g2p = G2p() + for line in sys.stdin: + words = line.strip().split() + phones = [] + if args.insert_silence: + phones.append(sil) + for w in words: + if w not in wrd_to_phn: + wrd_to_phn[w] = g2p(w) + phones.extend(wrd_to_phn[w]) + if args.insert_silence: + phones.append(sil) + try: + print(" ".join(phones)) + except: + print(wrd_to_phn, w, phones, file=sys.stderr) + raise + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/ltr_to_wrd.py b/examples/wav2vec/unsupervised/scripts/ltr_to_wrd.py new file mode 100644 index 0000000000..36c85d1e2f --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/ltr_to_wrd.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import sys + + +def main(): + for line in sys.stdin: + print(line.replace(" ", "").replace("|", " ").strip()) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/mean_pool.py b/examples/wav2vec/unsupervised/scripts/mean_pool.py new file mode 100644 index 0000000000..1145e774eb --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/mean_pool.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os +import os.path as osp +import math +import numpy as np +import tqdm +import torch +import torch.nn.functional as F +from shutil import copyfile + +from npy_append_array import NpyAppendArray + + +def get_parser(): + parser = argparse.ArgumentParser( + description="mean pools representations by compressing uniform splits of the data" + ) + # fmt: off + parser.add_argument('source', help='directory with features') + parser.add_argument('--split', help='which split to read', required=True) + parser.add_argument('--save-dir', help='where to save the output', required=True) + parser.add_argument('--subsample-rate', type=float, default=0.5, help='size to subsample data to') + + parser.add_argument('--remove-extra', action='store_true', help='if true, removes extra states that cant be pooled, otherwise pads with 0s') + # fmt: on + + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + + source_path = osp.join(args.source, args.split) + + print(f"data path: {source_path}") + + features = np.load(source_path + ".npy", mmap_mode="r") + + os.makedirs(args.save_dir, exist_ok=True) + save_path = osp.join(args.save_dir, args.split) + + copyfile(source_path + ".tsv", save_path + ".tsv") + copyfile(source_path + ".phn", save_path + ".phn") + copyfile(source_path + ".wrd", save_path + ".wrd") + + if osp.exists(save_path + ".npy"): + os.remove(save_path + ".npy") + npaa = NpyAppendArray(save_path + ".npy") + + with open(source_path + ".lengths", "r") as lf: + lengths = lf.readlines() + + fsz = features.shape[-1] + start = 0 + with torch.no_grad(): + with open(save_path + ".lengths", "w") as lengths_out: + for length in tqdm.tqdm(lengths): + length = int(length) + end = start + length + feats = features[start:end] + start += length + x = torch.from_numpy(feats).cuda() + target_num = math.ceil(length * args.subsample_rate) + rem = length % target_num + + if rem > 0: + if args.remove_extra: + to_rem = target_num - rem + target_num -= 1 + x = x[:-to_rem] + else: + to_add = target_num - rem + x = F.pad(x, [0, 0, 0, to_add]) + x[-to_add:] = x[-to_add - 1] + + x = x.view(target_num, -1, fsz) + x = x.mean(dim=-2) + print(target_num, file=lengths_out) + npaa.append(x.cpu().numpy()) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/merge_clusters.py b/examples/wav2vec/unsupervised/scripts/merge_clusters.py new file mode 100644 index 0000000000..6502ed5718 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/merge_clusters.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os +import os.path as osp +import numpy as np +import tqdm +import torch +import random +from shutil import copyfile + +from npy_append_array import NpyAppendArray + + +def get_parser(): + parser = argparse.ArgumentParser( + description="transforms features via a given pca and stored them in target dir" + ) + # fmt: off + parser.add_argument('source', help='directory with features') + parser.add_argument('--split', help='which split to read', required=True) + parser.add_argument('--save-dir', help='where to save the output', required=True) + parser.add_argument('--cluster-dir', help='where the clusters are') + parser.add_argument('--pooling', type=str, default='mean', choices=['mean', 'sample'], help='how to pool') + # fmt: on + + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + + source_path = osp.join(args.source, args.split) + cluster_path = osp.join(args.cluster_dir, args.split + ".src") + print(f"data path: {source_path}") + + features = np.load(source_path + ".npy", mmap_mode="r") + sizes = [] + offsets = [] + offset = 0 + with open(source_path + ".lengths", "r") as len_f: + for line in len_f: + length = int(line.rstrip()) + sizes.append(length) + offsets.append(offset) + offset += length + + clusters = [] + with open(cluster_path, "r") as cf: + for line in cf: + line = line.rstrip() + items = line.split() + items = list(map(int, items)) + clusters.append(items) + + os.makedirs(args.save_dir, exist_ok=True) + save_path = osp.join(args.save_dir, args.split) + + copyfile(source_path + ".tsv", save_path + ".tsv") + copyfile(source_path + ".phn", save_path + ".phn") + if os.path.exists(source_path + ".phnsc"): + copyfile(source_path + ".phnsc", save_path + ".phnsc") + copyfile( + osp.join(args.source, "dict.phnsc.txt"), + osp.join(args.save_dir, "dict.phnsc.txt"), + ) + copyfile(source_path + ".wrd", save_path + ".wrd") + + if osp.exists(save_path + ".npy"): + os.remove(save_path + ".npy") + npaa = NpyAppendArray(save_path + ".npy") + + def merge(feats, clust): + feats = torch.from_numpy(feats.copy()) + clust = torch.LongTensor(clust) + _, counts = clust.unique_consecutive(return_counts=True) + curr = 0 + + merged = [] + for c in counts: + c = c.item() + start = curr + end = curr + c + curr += c + if args.pooling == "mean": + new_x = feats[start:end].mean(dim=0) + elif args.pooling == "sample": + new_x = feats[start + int(random.random() * c)] + else: + raise NotImplementedError() + merged.append(new_x) + + return torch.stack(merged, dim=0).numpy() + + with open(save_path + ".lengths", "w") as l_f: + for size, offset, clust in tqdm.tqdm( + zip(sizes, offsets, clusters), total=len(sizes) + ): + end = size + offset + feats = features[offset:end] + feats = merge(feats, clust) + print(len(feats), file=l_f) + npaa.append(feats) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py b/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py new file mode 100644 index 0000000000..1284747795 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import fasttext as ft +import regex +import sys + + +def get_parser(): + parser = argparse.ArgumentParser( + description="reads text from stdin and outputs normalized, lid-filtered version to stdout" + ) + parser.add_argument( + "--fasttext-model", + help="path to fasttext model", + default="lid.187.bin", + ) + parser.add_argument("--lang", help="language id", required=True) + parser.add_argument( + "--lid-threshold", + type=float, + help="threshold for this lang id probability", + default=0.4, + ) + + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + filter_r = regex.compile(r"[^\p{L}\p{N}\p{M}\' \-]") + + lg = args.lang.lower() + lg_label = f"__label__{lg}" + thresh = args.lid_threshold + + model = ft.load_model(args.fasttext_model) + for line in sys.stdin: + line = line.strip() + line = filter_r.sub(" ", line) + line = " ".join(line.split()) + lid, prob = model.predict(line, k=100) + try: + target_idx = lid.index(lg_label) + except ValueError: + continue + if target_idx == 0 or prob[target_idx] >= thresh: + print(line) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/normalize_text.py b/examples/wav2vec/unsupervised/scripts/normalize_text.py new file mode 100644 index 0000000000..9d0ffeb27d --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/normalize_text.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import regex +import sys + + +def main(): + filter_r = regex.compile(r"[^\p{L}\p{N}\p{M}\' \-]") + + for line in sys.stdin: + line = line.strip() + line = filter_r.sub(" ", line) + line = " ".join(line.split()) + print(line) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/pca.py b/examples/wav2vec/unsupervised/scripts/pca.py new file mode 100644 index 0000000000..948cf5319f --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/pca.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os +import os.path as osp +import numpy as np + +import faiss + + + +def get_parser(): + parser = argparse.ArgumentParser( + description="compute a pca matrix given an array of numpy features" + ) + # fmt: off + parser.add_argument('data', help='numpy file containing features') + parser.add_argument('--output', help='where to save the pca matrix', required=True) + parser.add_argument('--dim', type=int, help='dim for pca reduction', required=True) + parser.add_argument('--eigen-power', type=float, default=0, help='eigen power, -0.5 for whitening') + + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + + print("Reading features") + x = np.load(args.data, mmap_mode="r") + + print("Computing PCA") + pca = faiss.PCAMatrix(x.shape[-1], args.dim, args.eigen_power) + pca.train(x) + b = faiss.vector_to_array(pca.b) + A = faiss.vector_to_array(pca.A).reshape(pca.d_out, pca.d_in) + + os.makedirs(args.output, exist_ok=True) + + prefix = str(args.dim) + if args.eigen_power != 0: + prefix += f"_{args.eigen_power}" + + np.save(osp.join(args.output, f"{prefix}_pca_A"), A.T) + np.save(osp.join(args.output, f"{prefix}_pca_b"), b) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py b/examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py new file mode 100644 index 0000000000..c6512d7322 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import numpy as np +import sys + + +def get_parser(): + parser = argparse.ArgumentParser( + description="converts words to phones adding optional silences around in between words" + ) + parser.add_argument( + "--sil-prob", + "-s", + type=float, + default=0, + help="probability of inserting silence between each word", + ) + parser.add_argument( + "--surround", + action="store_true", + help="if set, surrounds each example with silence", + ) + parser.add_argument( + "--lexicon", + help="lexicon to convert to phones", + required=True, + ) + + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + + sil_prob = args.sil_prob + surround = args.surround + sil = "<SIL>" + + wrd_to_phn = {} + + with open(args.lexicon, "r") as lf: + for line in lf: + items = line.rstrip().split() + assert len(items) > 1, line + assert items[0] not in wrd_to_phn, items + wrd_to_phn[items[0]] = items[1:] + + for line in sys.stdin: + words = line.strip().split() + + if not all(w in wrd_to_phn for w in words): + continue + + phones = [] + if surround: + phones.append(sil) + + sample_sil_probs = None + if sil_prob > 0 and len(words) > 1: + sample_sil_probs = np.random.random(len(words) - 1) + + for i, w in enumerate(words): + phones.extend(wrd_to_phn[w]) + if ( + sample_sil_probs is not None + and i < len(sample_sil_probs) + and sample_sil_probs[i] < sil_prob + ): + phones.append(sil) + + if surround: + phones.append(sil) + print(" ".join(phones)) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/prepare_audio.sh b/examples/wav2vec/unsupervised/scripts/prepare_audio.sh new file mode 100644 index 0000000000..893c9fda1a --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/prepare_audio.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env zsh +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +source_dir=$1 +tgt_dir=$2 +model=$3 + +if [ -z "$4" ] + then + dim=512 + else + dim=$4 +fi + +echo "using $dim dim for PCA" + +train_split=train +valid_split=valid +test_split=test + +mkdir -p $tgt_dir + +cp $source_dir/*.tsv $tgt_dir +cp $source_dir/*.wrd $tgt_dir +cp $source_dir/*.ltr $tgt_dir +cp $source_dir/*.phn $tgt_dir +cp $source_dir/dict* $tgt_dir + +setopt shwordsplit + +for split in $train_split $valid_split $test_split; do + python wav2vec_extract_features.py $source_dir --split $split \ + --save-dir $tgt_dir --checkpoint $model +done + +python wav2vec_cluster_faiss.py $tgt_dir/${train_split}.tsv \ +--checkpoint $model --save-dir $tgt_dir -f "CLUS128" --sample-pct 1.0 + +for split in $train_split $valid_split $test_split; do + python wav2vec_apply_cluster_faiss.py $tgt_dir \ + --checkpoint $model --path $tgt_dir/CLUS128 --split $split +done + +python pca.py $tgt_dir/${train_split}.npy --output $tgt_dir/pca --dim $dim + +for split in $train_split $valid_split $test_split; do + python apply_pca.py $tgt_dir --split $split --save-dir $tgt_dir/precompute_pca$dim --pca-path $tgt_dir/pca/${dim}_pca --batch-size 1048000 + + python merge_clusters.py $tgt_dir/precompute_pca$dim --cluster-dir $tgt_dir/CLUS128 \ + --split $split --save-dir $tgt_dir/precompute_pca${dim}_cls128_mean --pooling mean + + python mean_pool.py $tgt_dir/precompute_pca${dim}_cls128_mean \ + --save-dir $tgt_dir/precompute_pca${dim}_cls128_mean_pooled --split $split +done \ No newline at end of file diff --git a/examples/wav2vec/unsupervised/scripts/prepare_text.sh b/examples/wav2vec/unsupervised/scripts/prepare_text.sh new file mode 100644 index 0000000000..e9090a3d80 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/prepare_text.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env zsh +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +lg=$1 +text_path=$2 +target_dir=$3 + +ph_lg=${lg:l} +if test "$lg" = 'fr'; then + ph_lg='fr-fr' +elif test "$lg" = 'en'; then + ph_lg='en-us' +elif test "$lg" = 'pt'; then + ph_lg='pt-br' +fi + +echo $lg +echo $ph_lg +echo $text_path +echo $target_dir + +mkdir -p $target_dir +python normalize_and_filter_text.py --lang $lg < $text_path | grep -v '\-\-\-' >! $target_dir/lm.upper.lid.txt +python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/lm.upper.lid.txt --only-source --destdir $target_dir --thresholdsrc 2 --padding-factor 1 --dict-only +cut -f1 -d' ' $target_dir/dict.txt | grep -v -x '[[:punct:]]*' | grep -Pv '\d\d\d\d\d+' >! $target_dir/words.txt + +one=$(echo "1" | PHONEMIZER_ESPEAK_PATH=$(which espeak) phonemize -p ' ' -w '' -l $ph_lg --language-switch remove-flags) +sed 's/$/ 1/' $target_dir/words.txt | PHONEMIZER_ESPEAK_PATH=$(which espeak) phonemize -o $target_dir/phones.txt -p ' ' -w '' -l $ph_lg -j 70 --language-switch remove-flags + +echo "one is ${one}" + +sed -i "s/${one}$//" $target_dir/phones.txt +paste $target_dir/words.txt $target_dir/phones.txt >! $target_dir/lexicon.lst + +python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones.txt --only-source --destdir $target_dir/phones --thresholdsrc 1000 --padding-factor 1 --dict-only + +python filter_lexicon.py -d $target_dir/phones/dict.txt < $target_dir/lexicon.lst >! $target_dir/lexicon_filtered.lst +python phonemize_with_sil.py -s 0.25 --surround --lexicon $target_dir/lexicon_filtered.lst < $target_dir/lm.upper.lid.txt >! $target_dir/phones/lm.phones.filtered.txt +cp $target_dir/phones/dict.txt $target_dir/phones/dict.phn.txt +echo "<SIL> 0" >> $target_dir/phones/dict.phn.txt +python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones/lm.phones.filtered.txt --workers 70 --only-source --destdir $target_dir/phones --srcdict $target_dir/phones/dict.phn.txt + +lmplz -o 4 < $target_dir/lm.upper.lid.txt --discount_fallback --prune 0 0 0 3 >! $target_dir/kenlm.wrd.o40003.arpa +build_binary $target_dir/kenlm.wrd.o40003.arpa $target_dir/kenlm.wrd.o40003.bin +lg=$lg python examples/speech_recognition/kaldi/kaldi_initializer.py fst_dir=$target_dir/fst/phn_to_words_sil lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones "blank_symbol='<SIL>'" +lg=$lg python examples/speech_recognition/kaldi/kaldi_initializer.py fst_dir=$target_dir/fst/phn_to_words lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones + +lmplz -o 4 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.04.arpa +build_binary $target_dir/phones/lm.phones.filtered.04.arpa $target_dir/phones/lm.phones.filtered.04.bin +lmplz -o 6 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.06.arpa +build_binary $target_dir/phones/lm.phones.filtered.06.arpa $target_dir/phones/lm.phones.filtered.06.bin + +lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py fst_dir=$target_dir/fst/phn_to_phn_sil lm_arpa=$target_dir/phones/lm.phones.filtered.06.arpa data_dir=$target_dir/phones "blank_symbol='<SIL>'" diff --git a/examples/wav2vec/unsupervised/scripts/remove_silence.py b/examples/wav2vec/unsupervised/scripts/remove_silence.py new file mode 100644 index 0000000000..417b703de8 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/remove_silence.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +get intervals from .vads file, specify output data, and this script removes silences and saves the audio data in out path folder +paths=shards/train.tsv +vads=shards/train.vads +python remove_silence.py --paths $paths --vads $vads +""" + +import os +import argparse +import torch +import torchaudio +import tqdm + + +parser = argparse.ArgumentParser() +parser.add_argument("--tsv", default="", type=str) +parser.add_argument("--vads", default="", type=str) +parser.add_argument("--out", type=str) +params = parser.parse_args() + +# load paths +paths = [] +with open(params.tsv) as f: + root = next(f).rstrip() + for line in f: + paths.append(os.path.join(root, line.rstrip().split("\t")[0])) + +# load vads +list_intervals = [] +with open(params.vads) as f: + for line in f: + interval = [ + [int(w.split(":")[0]), int(w.split(":")[1])] for w in line.rstrip().split() + ] + list_intervals.append(interval) + + +# load audio and keep only intervals (i.e. remove silences) +for i in tqdm.trange(len(paths)): + data, _ = torchaudio.load(paths[i]) + if len(list_intervals[i]) > 0: + data_filtered = torch.cat( + [data[0][int(it[0]) : int(it[1])] for it in list_intervals[i]] + ).unsqueeze(0) + else: + data_filtered = data + + # YOU MAY NEED TO MODIFY THIS TO GET THE RIGHT SUBPATH + # outpath = params.out + '/'.join(paths[i].split('/')[-1]) + outpath = params.out + "/" + "/".join(paths[i].split("/")[-2:]) + + if not os.path.isdir("/".join(outpath.split("/")[:-1])): + os.makedirs("/".join(outpath.split("/")[:-1])) + if not os.path.exists(outpath): + print(outpath) + torchaudio.save(outpath, data_filtered, sample_rate=16000) + else: + print(outpath, "exists!") diff --git a/examples/wav2vec/unsupervised/scripts/vads.py b/examples/wav2vec/unsupervised/scripts/vads.py new file mode 100644 index 0000000000..1acd95369c --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/vads.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import sys + +sys.path.append("/path/to/rVADfast_py_2.0") +import speechproc +from copy import deepcopy +from scipy.signal import lfilter + +import numpy as np +from tqdm import tqdm +import soundfile as sf +import os.path as osp + + +def rvad(path): + winlen, ovrlen, pre_coef, nfilter, nftt = 0.025, 0.01, 0.97, 20, 512 + ftThres = 0.5 + vadThres = 0.4 + opts = 1 + + data, fs = sf.read(path) + assert fs == 16_000, "sample rate must be 16khz" + ft, flen, fsh10, nfr10 = speechproc.sflux(data, fs, winlen, ovrlen, nftt) + + # --spectral flatness -- + pv01 = np.zeros(ft.shape[0]) + pv01[np.less_equal(ft, ftThres)] = 1 + pitch = deepcopy(ft) + + pvblk = speechproc.pitchblockdetect(pv01, pitch, nfr10, opts) + + # --filtering-- + ENERGYFLOOR = np.exp(-50) + b = np.array([0.9770, -0.9770]) + a = np.array([1.0000, -0.9540]) + fdata = lfilter(b, a, data, axis=0) + + # --pass 1-- + noise_samp, noise_seg, n_noise_samp = speechproc.snre_highenergy( + fdata, nfr10, flen, fsh10, ENERGYFLOOR, pv01, pvblk + ) + + # sets noisy segments to zero + for j in range(n_noise_samp): + fdata[range(int(noise_samp[j, 0]), int(noise_samp[j, 1]) + 1)] = 0 + + vad_seg = speechproc.snre_vad( + fdata, nfr10, flen, fsh10, ENERGYFLOOR, pv01, pvblk, vadThres + ) + return vad_seg, data + + +def main(): + stride = 160 + lines = sys.stdin.readlines() + root = lines[0].rstrip() + for fpath in tqdm(lines[1:]): + path = osp.join(root, fpath.split()[0]) + vads, wav = rvad(path) + + start = None + vad_segs = [] + for i, v in enumerate(vads): + if start is None and v == 1: + start = i * stride + elif start is not None and v == 0: + vad_segs.append((start, i * stride)) + start = None + if start is not None: + vad_segs.append((start, len(wav))) + + print(" ".join(f"{v[0]}:{v[1]}" for v in vad_segs)) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py b/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py new file mode 100644 index 0000000000..25bc4e41ac --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os.path as osp +import numpy as np +import tqdm +import torch +import sys + +import faiss +import torch.nn.functional as F + +from wav2vec_cluster_faiss import parse_faiss_specs, Wav2VecFeatureReader + + +def get_parser(): + parser = argparse.ArgumentParser(description="apply clusters") + # fmt: off + parser.add_argument('data', help='location of tsv files') + parser.add_argument('--split', help='split to process', required=True) + parser.add_argument('--labels', help='split to process', default="phn") + parser.add_argument('--path', help='path to pca and centroids', required=True) + parser.add_argument('--checkpoint', type=str, help='checkpoint for wav2vec model (if using wav2vec features)', required=True) + parser.add_argument('--layer', '-l', type=int, help='which layer to read', default=14) + parser.add_argument('--max-tsz', type=int, help='batch kmeans up to this much', default=14) + # fmt: on + + return parser + + +def get_iterator(args): + with open(osp.join(args.data, f"{args.split}.tsv"), "r") as fp, open( + osp.join(args.data, f"{args.split}.{args.labels}"), "r" + ) as lp: + lines = fp.read().split("\n") + root = lines.pop(0).strip() + files = [line.rstrip() for line in lines if len(line) > 0] + lbls = [line.rstrip() for line in lp] + + num = len(files) + reader = Wav2VecFeatureReader(args.checkpoint, args.layer) + + def iterate(): + for fname, lbl in zip(files, lbls): + file = osp.join(root, fname.split("\t")[0]) + feats = reader.get_feats(file) + yield feats.data, fname, lbl + + return iterate, num, root + + +def main(): + parser = get_parser() + args = parser.parse_args() + + spec = osp.basename(args.path) + + try: + faiss_spec = parse_faiss_specs(spec.rstrip("/"))[0] + except: + print(spec) + raise + + print("Faiss Spec:", faiss_spec, file=sys.stderr) + + if faiss_spec.pca: + A = torch.from_numpy(np.load(osp.join(args.path, "pca_A.npy"))).cuda() + b = torch.from_numpy(np.load(osp.join(args.path, "pca_b.npy"))).cuda() + print("Loaded PCA", file=sys.stderr) + + centroids = np.load(osp.join(args.path, "centroids.npy")) + print("Loaded centroids", centroids.shape, file=sys.stderr) + + res = faiss.StandardGpuResources() + index_flat = ( + faiss.IndexFlatL2(centroids.shape[1]) + if not faiss_spec.sphere + else faiss.IndexFlatIP(centroids.shape[1]) + ) + faiss_index = faiss.index_cpu_to_gpu(res, 0, index_flat) + faiss_index.add(centroids) + + generator, num, root = get_iterator(args) + iterator = generator() + + with torch.no_grad(): + with open(osp.join(args.path, f"{args.split}.src"), "w") as fp, open( + osp.join(args.path, f"{args.split}.tsv"), "w" + ) as pp, open(osp.join(args.path, f"{args.split}.{args.labels}"), "w") as lp: + print(root, file=pp) + for f, fname, lbl in tqdm.tqdm(iterator, total=num): + if faiss_spec.pca: + f = torch.mm(f, A) + b + if faiss_spec.norm: + f = F.normalize(f, p=2, dim=-1) + + f = f.cpu().numpy() + + _, z = faiss_index.search(f, 1) + + print(" ".join(str(x.item()) for x in z), file=fp) + print(fname, file=pp) + print(lbl, file=lp) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py b/examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py new file mode 100644 index 0000000000..632a69e9f4 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import gc +import os +import os.path as osp +import random +import numpy as np +import tqdm +import torch + +from collections import namedtuple + +import faiss + +import fairseq +import soundfile as sf + + +def get_parser(): + parser = argparse.ArgumentParser( + description="compute kmeans codebook from kaldi-computed feats" + ) + # fmt: off + parser.add_argument('data', help='location of tsv files') + parser.add_argument('--save-dir', help='where to save the output', required=True) + parser.add_argument('--checkpoint', type=str, help='checkpoint for wav2vec model (if using wav2vec features)', required=True) + parser.add_argument('--sample-pct', '-r', type=float, help='percentage of timesteps to sample', default=0) + parser.add_argument('--layer', '-l', type=int, help='which layer to read', default=14) + parser.add_argument('--faiss-specs', '-f', type=str, + help='faiss index specs; separated by space ' + 'format is: PCAx_NORM_CLUSx_SPHERICAL -> ' + 'PCAx if exists first apply PCA ' + 'NORM if exists, normalize the vector by L2 norm ' + 'CLUSx must exist, cluster to x clusters ' + 'SPEHRICAL if exists, apply spherical kmeans', + default='l2') + # fmt: on + + return parser + + +faiss_spec = namedtuple("faiss_spec", ["pca", "norm", "n_clus", "sphere", "spec_str"]) + + +def parse_faiss_specs(specs_str): + specs = [] + for ss in specs_str.split(): + comps = ss.split("_") + pca = 0 + norm = False + n_clus = 0 + sphere = False + for c in comps: + if c.startswith("PCA"): + pca = int(c[3:]) + elif c == "NORM": + norm = True + elif c.startswith("CLUS"): + n_clus = int(c[4:]) + elif c == "SPHERICAL": + sphere = True + assert n_clus > 0 + specs.append( + faiss_spec(pca=pca, norm=norm, n_clus=n_clus, sphere=sphere, spec_str=ss) + ) + return specs + + +class Wav2VecFeatureReader(object): + def __init__(self, cp_file, layer): + state = fairseq.checkpoint_utils.load_checkpoint_to_cpu(cp_file) + + self.layer = layer + + if "cfg" in state: + w2v_args = state["cfg"] + task = fairseq.tasks.setup_task(w2v_args.task) + model = task.build_model(w2v_args.model) + else: + w2v_args = state["args"] + task = fairseq.tasks.setup_task(w2v_args) + model = task.build_model(w2v_args) + model.load_state_dict(state["model"], strict=True) + model.eval() + model.cuda() + self.model = model + + def read_audio(self, fname): + """Load an audio file and return PCM along with the sample rate""" + wav, sr = sf.read(fname) + assert sr == 16e3 + + return wav + + def get_feats(self, loc): + x = self.read_audio(loc) + with torch.no_grad(): + source = torch.from_numpy(x).view(1, -1).float().cuda() + res = self.model( + source=source, mask=False, features_only=True, layer=self.layer + ) + return res["layer_results"][self.layer][0].squeeze(1) + + +def get_iterator(args): + with open(args.data, "r") as fp: + lines = fp.read().split("\n") + root = lines.pop(0).strip() + files = [osp.join(root, line.split("\t")[0]) for line in lines if len(line) > 0] + + if getattr(args, "sample_pct", 0) > 0: + files = random.sample(files, int(args.sample_pct * len(files))) + num = len(files) + reader = Wav2VecFeatureReader(args.checkpoint, args.layer) + + def iterate(): + for fname in files: + feats = reader.get_feats(fname) + yield feats.cpu().numpy() + + return iterate, num + + +def main(): + parser = get_parser() + args = parser.parse_args() + + faiss_specs = parse_faiss_specs(args.faiss_specs) + print("Faiss Specs:", faiss_specs) + + feat_path = osp.join(args.save_dir, "features") + if osp.exists(feat_path + ".npy"): + feats = np.load(feat_path + ".npy") + else: + generator, num = get_iterator(args) + iterator = generator() + + feats = [] + for f in tqdm.tqdm(iterator, total=num): + feats.append(f) + + del iterator + del generator + + feats = np.concatenate(feats) + + print(feats.shape) + + os.makedirs(args.save_dir, exist_ok=True) + # np.save(feat_path, feats) + + gc.collect() + torch.cuda.empty_cache() + + reload = False + for spec in faiss_specs: + print("Processing spec", spec) + + if reload: + print("Reloading...") + del feats + gc.collect() + feats = np.load(feat_path + ".npy") + + save_path = osp.join(args.save_dir, spec.spec_str) + os.makedirs(save_path, exist_ok=True) + d = feats.shape[-1] + x = feats + if spec.pca > 0: + print("Computing PCA") + pca = faiss.PCAMatrix(d, spec.pca) + pca.train(x) + d = spec.pca + b = faiss.vector_to_array(pca.b) + A = faiss.vector_to_array(pca.A).reshape(pca.d_out, pca.d_in) + np.save(osp.join(save_path, "pca_A"), A.T) + np.save(osp.join(save_path, "pca_b"), b) + print("Applying PCA") + x = pca.apply_py(x) + + if spec.norm: + reload = spec.pca <= 0 + print("Normalizing") + faiss.normalize_L2(x) + + print("Computing kmeans") + kmeans = faiss.Kmeans( + d, + spec.n_clus, + niter=50, + verbose=True, + spherical=spec.sphere, + max_points_per_centroid=feats.shape[0], + gpu=True, + nredo=3, + ) + kmeans.train(x) + np.save(osp.join(save_path, "centroids"), kmeans.centroids) + del kmeans + del x + gc.collect() + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py b/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py new file mode 100644 index 0000000000..023dd1aaa5 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os +import os.path as osp +import tqdm +import torch +import torch.nn.functional as F +from shutil import copyfile + +from npy_append_array import NpyAppendArray + +import fairseq +import soundfile as sf + + +def get_parser(): + parser = argparse.ArgumentParser( + description="compute kmeans codebook from kaldi-computed feats" + ) + # fmt: off + parser.add_argument('data', help='location of tsv files') + parser.add_argument('--split', help='which split to read', required=True) + parser.add_argument('--save-dir', help='where to save the output', required=True) + parser.add_argument('--checkpoint', type=str, help='checkpoint for wav2vec ctc model', required=True) + # fmt: on + + return parser + + +class Wav2VecFeatureReader(object): + def __init__(self, cp_file): + model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task( + [cp_file] + ) + model = model[0] + model.eval() + model.cuda() + self.model = model + self.task = task + + def read_audio(self, fname): + """Load an audio file and return PCM along with the sample rate""" + wav, sr = sf.read(fname) + assert sr == 16e3 + + return wav + + def get_feats(self, loc): + x = self.read_audio(loc) + with torch.no_grad(): + source = torch.from_numpy(x).float().cuda() + if self.task.cfg.normalize: + assert source.dim() == 1, source.dim() + with torch.no_grad(): + source = F.layer_norm(source, source.shape) + source = source.view(1, -1) + + m_res = self.model(source=source, mask=False, features_only=True, layer=14) + return m_res["x"].squeeze(0).cpu() + + +def get_iterator(args): + with open(osp.join(args.data, args.split) + ".tsv", "r") as fp: + lines = fp.read().split("\n") + root = lines.pop(0).strip() + files = [osp.join(root, line.split("\t")[0]) for line in lines if len(line) > 0] + + num = len(files) + reader = Wav2VecFeatureReader(args.checkpoint) + + def iterate(): + for fname in files: + w2v_feats = reader.get_feats(fname) + yield w2v_feats + + return iterate, num + + +def main(): + parser = get_parser() + args = parser.parse_args() + + os.makedirs(args.save_dir, exist_ok=True) + + def create_files(dest): + copyfile(osp.join(args.data, args.split) + ".tsv", dest + ".tsv") + if osp.exists(osp.join(args.data, args.split) + ".wrd"): + copyfile(osp.join(args.data, args.split) + ".wrd", dest + ".wrd") + if osp.exists(osp.join(args.data, args.split) + ".phn"): + copyfile(osp.join(args.data, args.split) + ".phn", dest + ".phn") + + if osp.exists(dest + ".npy"): + os.remove(dest + ".npy") + npaa = NpyAppendArray(dest + ".npy") + return npaa + + save_path = osp.join(args.save_dir, args.split) + npaa = create_files(save_path) + + generator, num = get_iterator(args) + iterator = generator() + + with open(save_path + ".lengths", "w") as l_f: + for w2v_feats in tqdm.tqdm(iterator, total=num): + print(len(w2v_feats), file=l_f) + + if len(w2v_feats) > 0: + npaa.append(w2v_feats.numpy()) + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/scripts/wer.py b/examples/wav2vec/unsupervised/scripts/wer.py new file mode 100644 index 0000000000..613ab50d39 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/wer.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +Implement unsupervised metric for decoding hyperparameter selection: + $$ alpha * LM_PPL + ViterbitUER(%) * 100 $$ +""" +import argparse +import logging +import sys + +import editdistance + +logging.root.setLevel(logging.INFO) +logging.basicConfig(stream=sys.stdout, level=logging.INFO) +logger = logging.getLogger(__name__) + + +def get_parser(): + parser = argparse.ArgumentParser() + parser.add_argument("-s", "--hypo", help="hypo transcription", required=True) + parser.add_argument( + "-r", "--reference", help="reference transcription", required=True + ) + return parser + + +def compute_wer(ref_uid_to_tra, hyp_uid_to_tra, g2p): + d_cnt = 0 + w_cnt = 0 + w_cnt_h = 0 + for uid in hyp_uid_to_tra: + ref = ref_uid_to_tra[uid].split() + if g2p is not None: + hyp = g2p(hyp_uid_to_tra[uid]) + hyp = [p for p in hyp if p != "'" and p != " "] + hyp = [p[:-1] if p[-1].isnumeric() else p for p in hyp] + else: + hyp = hyp_uid_to_tra[uid].split() + d_cnt += editdistance.eval(ref, hyp) + w_cnt += len(ref) + w_cnt_h += len(hyp) + wer = float(d_cnt) / w_cnt + logger.debug( + ( + f"wer = {wer * 100:.2f}%; num. of ref words = {w_cnt}; " + f"num. of hyp words = {w_cnt_h}; num. of sentences = {len(ref_uid_to_tra)}" + ) + ) + return wer + + +def main(): + args = get_parser().parse_args() + + errs = 0 + count = 0 + with open(args.hypo, "r") as hf, open(args.reference, "r") as rf: + for h, r in zip(hf, rf): + h = h.rstrip().split() + r = r.rstrip().split() + errs += editdistance.eval(r, h) + count += len(r) + + logger.info(f"UER: {errs / count * 100:.2f}%") + + +if __name__ == "__main__": + main() + + +def load_tra(tra_path): + with open(tra_path, "r") as f: + uid_to_tra = {} + for line in f: + uid, tra = line.split(None, 1) + uid_to_tra[uid] = tra + logger.debug(f"loaded {len(uid_to_tra)} utterances from {tra_path}") + return uid_to_tra diff --git a/examples/wav2vec/unsupervised/scripts/wrd_to_ltr.py b/examples/wav2vec/unsupervised/scripts/wrd_to_ltr.py new file mode 100644 index 0000000000..f83471409a --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/wrd_to_ltr.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import sys + + +def main(): + for line in sys.stdin: + print(" ".join(list(line.strip().replace(" ", "|"))) + " |") + + +if __name__ == "__main__": + main() diff --git a/examples/wav2vec/unsupervised/tasks/__init__.py b/examples/wav2vec/unsupervised/tasks/__init__.py new file mode 100644 index 0000000000..6d7dd625e0 --- /dev/null +++ b/examples/wav2vec/unsupervised/tasks/__init__.py @@ -0,0 +1,11 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .unpaired_audio_text import UnpairedAudioText + + +__all__ = [ + "UnpairedAudioText", +] diff --git a/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py new file mode 100644 index 0000000000..0b770a1509 --- /dev/null +++ b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py @@ -0,0 +1,437 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +from dataclasses import dataclass, field +import logging +import math +import os +from typing import Optional +import torch + +from fairseq.logging import metrics +from fairseq.tasks import FairseqTask, register_task +from ..data import ExtractedFeaturesDataset, RandomInputDataset + +from fairseq.data import ( + Dictionary, + data_utils, + StripTokenDataset, +) +from fairseq.dataclass import FairseqDataclass +from fairseq.distributed.utils import get_data_parallel_world_size +from omegaconf import MISSING + +from examples.speech_recognition.kaldi.kaldi_decoder import ( + KaldiDecoder, + KaldiDecoderConfig, +) + + +logger = logging.getLogger(__name__) + + +@dataclass +class DecodingConfig(FairseqDataclass): + kenlm_path: Optional[str] = None + lm_weight: float = 0 + blank_weight: float = 0 + + +@dataclass +class UnpairedAudioTextConfig(FairseqDataclass): + data: str = field( + default=MISSING, metadata={"help": "path to data directory containing audio"} + ) + text_data: str = field( + default=MISSING, metadata={"help": "path to data directory containing text"} + ) + max_length: Optional[int] = None + labels: Optional[str] = field( + default=None, + metadata={"help": "extension of the label file to load, used for fine-tuning"}, + ) + unfiltered: bool = field( + default=False, metadata={"help": "load data with _unfiltered suffix"} + ) + ctc_eval: bool = field( + default=False, metadata={"help": "eval UER as if computed by CTC"} + ) + sort_by_length: bool = field( + default=True, metadata={"help": "sort examples by length of audio timesteps"} + ) + shuffle: bool = field(default=True, metadata={"help": "shuffle examples"}) + append_eos: bool = field(default=False, metadata={"help": "append eos"}) + uppercase: Optional[bool] = field( + default=False, metadata={"help": "uppercase for LM score computation"} + ) + skipwords: Optional[str] = field( + default="", + metadata={ + "help": "comma-separated words to be removed for LM score computation" + }, + ) + kenlm_path: Optional[str] = None + vocab_usage_power: float = 2 + + word_decoder_config: Optional[KaldiDecoderConfig] = None + word_kenlm_path: Optional[str] = None + + decoding_config: DecodingConfig = DecodingConfig() + + +@register_task("gan_audio_pretraining_feats", dataclass=UnpairedAudioTextConfig) +class UnpairedAudioText(FairseqTask): + """ """ + + cfg: UnpairedAudioTextConfig + + def __init__( + self, + cfg: UnpairedAudioTextConfig, + source_dictionary=None, + target_dictionary=None, + ): + super().__init__(cfg) + + self._target_dictionary = target_dictionary + self._source_dictionary = source_dictionary + self.num_symbols = ( + len([s for s in target_dictionary.symbols if not s.startswith("madeup")]) + - target_dictionary.nspecial + ) + self.sil_id = ( + target_dictionary.index("<SIL>") if "<SIL>" in target_dictionary else -1 + ) + self.kenlm = None + if cfg.kenlm_path is not None: + import kenlm + + self.kenlm = kenlm.Model(cfg.kenlm_path) + + self.word_kenlm = None + if cfg.word_kenlm_path is not None: + import kenlm + + self.word_kenlm = kenlm.Model(cfg.word_kenlm_path) + + self.uppercase = cfg.uppercase + self.skipwords = set(cfg.skipwords.split(",")) + + def str_postprocess(s): + s = " ".join(w for w in s.split() if w not in self.skipwords) + s = s.upper() if self.uppercase else s + return s + + self.str_postprocess = str_postprocess + self.compute_lm_score = lambda s: self.kenlm.score(self.str_postprocess(s)) + + self.compute_word_score = None + if cfg.word_decoder_config is not None: + self.kaldi_decoder = KaldiDecoder(cfg.word_decoder_config, beam=10) + + def compute_word_score(logits, padding): + res = self.kaldi_decoder.decode(logits, padding) + for r in res: + r = r.result() + assert len(r) == 1 + r = r[0] + yield r["score"], r["words"] + + self.compute_word_score = compute_word_score + + @classmethod + def setup_task(cls, cfg: UnpairedAudioTextConfig, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + cfg (AudioPretrainingConfig): configuration of this task + """ + + dict_path = os.path.join(cfg.text_data, "dict.txt") + if os.path.exists(dict_path): + target_dictionary = Dictionary.load(dict_path) + else: + dict_path = os.path.join(cfg.data, f"dict.{cfg.labels}.txt") + target_dictionary = Dictionary.load(dict_path) + + return cls(cfg, target_dictionary=target_dictionary) + + def optimizer_step(self, optimizer, model, update_num): + if hasattr(model, "get_groups_for_update"): + groups = model.get_groups_for_update(update_num) + optimizer.step(groups={groups}) + else: + optimizer.step() + + def valid_step(self, sample, model, criterion): + res = model( + **sample["net_input"], + dense_x_only=True, + ) + + dense_x = res["logits"] + padding_mask = res["padding_mask"] + + word_scores = None + if self.compute_word_score is not None: + word_scores = self.compute_word_score(dense_x.cpu(), padding_mask.cpu()) + + z = dense_x.argmax(-1) + z[padding_mask] = self.target_dictionary.pad() + + vocab_seen = torch.zeros(self.num_symbols, dtype=torch.bool) + + import editdistance + + c_err = 0 + c_len = 0 + pred_c_len = 0 + lm_score_sum = 0 + for i, (x, t, id) in enumerate( + zip( + z, + sample["target"], + sample["id"], + ) + ): + + t = t[(t >= self.target_dictionary.nspecial)] + x = x[ + (x >= self.target_dictionary.nspecial) + & (x < (self.num_symbols + self.target_dictionary.nspecial)) + ] + if self.sil_id >= 0: + x = x[x != self.sil_id] + + vocab_seen[x - self.target_dictionary.nspecial] = True + + pred_units_arr = x + if self.cfg.ctc_eval: + pred_units_arr = pred_units_arr.unique_consecutive() + pred_units_arr = pred_units_arr[pred_units_arr != 0] + + if id == 0: + logger.info(f"REF: {self.target_dictionary.string(t)}") + logger.info(f"HYP: {self.target_dictionary.string(pred_units_arr)}") + + if self.kenlm is not None: + ref_lm_s = self.compute_lm_score(self.target_dictionary.string(t)) + hyp_lm_s = self.compute_lm_score( + self.target_dictionary.string(pred_units_arr) + ) + logger.info( + f"LM [REF]: {ref_lm_s}, {math.pow(10, ref_lm_s / (len(t) + 1))}" + ) + logger.info( + f"LM [HYP]: {hyp_lm_s}, {math.pow(10, hyp_lm_s / (len(pred_units_arr) + 1))}" + ) + + pred_units_arr = pred_units_arr.tolist() + + t = t.tolist() + c_err += editdistance.eval(pred_units_arr, t) + c_len += len(t) + pred_c_len += len(pred_units_arr) + + if self.kenlm is not None: + pred_str = self.target_dictionary.string(pred_units_arr) + lm_score = self.compute_lm_score(pred_str) + lm_score_sum += lm_score + + kaldi_score_sum = 0 + word_lm_sum = 0 + num_words = 0 + if word_scores is not None: + for score, words in word_scores: + kaldi_score_sum += score + num_words += len(words) + if self.word_kenlm is not None: + word_lm_sum += self.kenlm.score(" ".join(words)) + + try: + world_size = get_data_parallel_world_size() + except: + world_size = 1 + + logging_output = { + "loss": c_err, + "_num_char_errors": c_err, + "_num_chars": c_len, + "_num_pred_chars": pred_c_len, + "ntokens": c_len, + "nsentences": z.size(0), + "sample_size": c_len, + "_world_size": world_size, + "_lm_score_sum": lm_score_sum, + "_kaldi_score_sum": kaldi_score_sum, + "_word_lm_sum": word_lm_sum, + "_num_words": num_words, + "_vocab_seen": vocab_seen, + } + + return c_err, c_len, logging_output + + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + data_path = self.cfg.data + task_cfg = task_cfg or self.cfg + + has_unpaired_text = os.path.exists( + os.path.join(self.cfg.text_data, f"{split}.idx") + ) + + self.datasets[split] = ExtractedFeaturesDataset( + path=data_path, + split=split, + min_length=3, + max_length=task_cfg.max_length, + labels=None if has_unpaired_text else task_cfg.labels, + label_dict=self.target_dictionary, + shuffle=getattr(task_cfg, "shuffle", True), + sort_by_length=task_cfg.sort_by_length, + ) + + logger.info(f"split {split} has unpaired text? {has_unpaired_text}") + if has_unpaired_text: + text_dataset = data_utils.load_indexed_dataset( + os.path.join(self.cfg.text_data, split), self.target_dictionary + ) + text_dataset = StripTokenDataset(text_dataset, self.target_dictionary.eos()) + self.datasets[split] = RandomInputDataset( + self.datasets[split], + text_dataset, + ["random_label"], + add_to_input=True, + pad_idx=self.target_dictionary.pad(), + ) + + @property + def source_dictionary(self): + return self._source_dictionary + + @property + def target_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self._target_dictionary + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return None + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + zero = torch.scalar_tensor(0.0) + num_char_errors = sum( + log.get("_num_char_errors", zero) for log in logging_outputs + ) + num_chars = sum(log.get("_num_chars", zero) for log in logging_outputs) + num_word_errors = sum( + log.get("_num_word_errors", zero) for log in logging_outputs + ) + num_words = sum(log.get("_num_words", zero) for log in logging_outputs) + num_pred_chars = sum( + log.get("_num_pred_chars", zero) for log in logging_outputs + ) + + lm_score_sum = sum(log.get("_lm_score_sum", zero) for log in logging_outputs) + vocab_seen = ( + sum(log.get("_vocab_seen", zero) for log in logging_outputs) + .bool() + .sum() + .item() + ) + kaldi_score_sum = sum( + log.get("_kaldi_score_sum", zero) for log in logging_outputs + ) + word_lm_sum = sum(log.get("_word_lm_sum", zero) for log in logging_outputs) + + metrics.log_scalar_sum("_num_char_errors", num_char_errors) + metrics.log_scalar_sum("_num_chars", num_chars) + metrics.log_scalar_sum("_num_word_errors", num_word_errors) + metrics.log_scalar_sum("_num_words", num_words) + + metrics.log_scalar_sum("lm_score_sum", lm_score_sum) + metrics.log_scalar_sum("num_pred_chars", num_pred_chars) + + if self.cfg.word_kenlm_path is not None: + metrics.log_scalar_sum("kaldi_score_sum", kaldi_score_sum) + metrics.log_scalar_sum("word_lm_sum", word_lm_sum) + + if num_chars > 0: + metrics.log_derived( + "uer", + lambda meters: meters["_num_char_errors"].sum + * 100.0 + / meters["_num_chars"].sum + if meters["_num_chars"].sum > 0 + else float("nan"), + ) + + if lm_score_sum < 0 and vocab_seen > 0: + metrics.log_scalar("vocab_seen_pct", vocab_seen / self.num_symbols) + + metrics.log_derived( + "weighted_lm_ppl", + lambda meters: math.pow( + 10, + -meters["lm_score_sum"].sum + / ( + meters["num_pred_chars"].sum + meters["nsentences"].sum + ), # account for </s> + ) + / meters["vocab_seen_pct"].avg ** self.cfg.vocab_usage_power, + ) + + metrics.log_derived( + "lm_ppl", + lambda meters: math.pow( + 10, + -meters["lm_score_sum"].sum + / ( + meters["num_pred_chars"].sum + meters["nsentences"].sum + ), # account for </s> + ), + ) + else: + metrics.log_derived("weighted_lm_ppl", lambda meters: float("inf")) + + if num_words > 0: + if word_lm_sum != 0: + metrics.log_derived( + "word_lm_ppl", + lambda meters: math.pow( + 10, + -meters["word_lm_sum"].sum + / ( + meters["_num_words"].sum + meters["nsentences"].sum + ), # account for </s> + ), + ) + metrics.log_derived( + "weighted_word_lm_ppl", + lambda meters: math.pow( + 10, + -meters["word_lm_sum"].sum + / ( + meters["_num_words"].sum + meters["nsentences"].sum + ), # account for </s> + ) + / meters["vocab_seen_pct"].avg ** self.cfg.vocab_usage_power, + ) + + if self.cfg.word_kenlm_path is not None: + metrics.log_derived( + "kaldi_score", + lambda meters: meters["kaldi_score_sum"].sum + / meters["nsentences"].sum, + ) + + def build_model(self, cfg: FairseqDataclass): + model = super().build_model(cfg) + + return model diff --git a/examples/wav2vec/unsupervised/w2vu_generate.py b/examples/wav2vec/unsupervised/w2vu_generate.py new file mode 100644 index 0000000000..a1bc0ec706 --- /dev/null +++ b/examples/wav2vec/unsupervised/w2vu_generate.py @@ -0,0 +1,706 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +Run inference for pre-processed data with a trained model. +""" + +import ast +from collections import namedtuple +from dataclasses import dataclass, field +from enum import Enum, auto +import hydra +from hydra.core.config_store import ConfigStore +import logging +import math +import os +from omegaconf import OmegaConf +from typing import Optional +import sys + +import editdistance +import torch + +from hydra.core.hydra_config import HydraConfig + +from fairseq import checkpoint_utils, progress_bar, tasks, utils +from fairseq.data.data_utils import post_process +from fairseq.dataclass.configs import FairseqDataclass, FairseqConfig +from fairseq.logging.meters import StopwatchMeter +from omegaconf import open_dict + +from examples.speech_recognition.kaldi.kaldi_decoder import KaldiDecoderConfig + +logging.root.setLevel(logging.INFO) +logging.basicConfig(stream=sys.stdout, level=logging.INFO) +logger = logging.getLogger(__name__) + + +class DecoderType(Enum): + VITERBI = auto() + KENLM = auto() + FAIRSEQ = auto() + KALDI = auto() + + +@dataclass +class UnsupGenerateConfig(FairseqDataclass): + fairseq: FairseqConfig = FairseqConfig() + lm_weight: float = field( + default=2.0, + metadata={"help": "language model weight"}, + ) + w2l_decoder: DecoderType = field( + default=DecoderType.VITERBI, + metadata={"help": "type of decoder to use"}, + ) + kaldi_decoder_config: Optional[KaldiDecoderConfig] = None + lexicon: Optional[str] = field( + default=None, + metadata={ + "help": "path to lexicon. This is also used to 'phonemize' for unsupvised param tuning" + }, + ) + lm_model: Optional[str] = field( + default=None, + metadata={"help": "path to language model (kenlm or fairseq)"}, + ) + unit_lm: bool = field( + default=False, + metadata={"help": "whether to use unit lm"}, + ) + beam_threshold: float = field( + default=50.0, + metadata={"help": "beam score threshold"}, + ) + beam_size_token: float = field( + default=100.0, + metadata={"help": "max tokens per beam"}, + ) + beam: int = field( + default=5, + metadata={"help": "decoder beam size"}, + ) + nbest: int = field( + default=1, + metadata={"help": "number of results to return"}, + ) + word_score: float = field( + default=1.0, + metadata={"help": "word score to add at end of word"}, + ) + unk_weight: float = field( + default=-math.inf, + metadata={"help": "unknown token weight"}, + ) + sil_weight: float = field( + default=0.0, + metadata={"help": "silence token weight"}, + ) + targets: Optional[str] = field( + default=None, + metadata={"help": "extension of ground truth labels to compute UER"}, + ) + results_path: Optional[str] = field( + default=None, + metadata={"help": "where to store results"}, + ) + post_process: Optional[str] = field( + default=None, + metadata={"help": "how to post process results"}, + ) + vocab_usage_power: float = field( + default=2, + metadata={"help": "for unsupervised param tuning"}, + ) + + viterbi_transcript: Optional[str] = field( + default=None, + metadata={"help": "for unsupervised param tuning"}, + ) + min_lm_ppl: float = field( + default=0, + metadata={"help": "for unsupervised param tuning"}, + ) + min_vt_uer: float = field( + default=0, + metadata={"help": "for unsupervised param tuning"}, + ) + + blank_weight: float = field( + default=0, + metadata={"help": "value to add or set for blank emission"}, + ) + blank_mode: str = field( + default="set", + metadata={ + "help": "can be add or set, how to modify blank emission with blank weight" + }, + ) + sil_is_blank: bool = field( + default=False, + metadata={"help": "if true, <SIL> token is same as blank token"}, + ) + + unsupervised_tuning: bool = field( + default=False, + metadata={ + "help": "if true, returns a score based on unsupervised param selection metric instead of UER" + }, + ) + is_ax: bool = field( + default=False, + metadata={ + "help": "if true, assumes we are using ax for tuning and returns a tuple for ax to consume" + }, + ) + + +def get_dataset_itr(cfg, task): + return task.get_batch_iterator( + dataset=task.dataset(cfg.fairseq.dataset.gen_subset), + max_tokens=cfg.fairseq.dataset.max_tokens, + max_sentences=cfg.fairseq.dataset.batch_size, + max_positions=(sys.maxsize, sys.maxsize), + ignore_invalid_inputs=cfg.fairseq.dataset.skip_invalid_size_inputs_valid_test, + required_batch_size_multiple=cfg.fairseq.dataset.required_batch_size_multiple, + num_shards=cfg.fairseq.dataset.num_shards, + shard_id=cfg.fairseq.dataset.shard_id, + num_workers=cfg.fairseq.dataset.num_workers, + data_buffer_size=cfg.fairseq.dataset.data_buffer_size, + ).next_epoch_itr(shuffle=False) + + +def process_predictions( + cfg: UnsupGenerateConfig, + hypos, + tgt_dict, + target_tokens, + res_files, +): + retval = [] + word_preds = [] + transcriptions = [] + dec_scores = [] + + for i, hypo in enumerate(hypos[: min(len(hypos), cfg.nbest)]): + if torch.is_tensor(hypo["tokens"]): + tokens = hypo["tokens"].int().cpu() + tokens = tokens[tokens >= tgt_dict.nspecial] + hyp_pieces = tgt_dict.string(tokens) + else: + hyp_pieces = " ".join(hypo["tokens"]) + + if "words" in hypo and len(hypo["words"]) > 0: + hyp_words = " ".join(hypo["words"]) + else: + hyp_words = post_process(hyp_pieces, cfg.post_process) + + to_write = {} + if res_files is not None: + to_write[res_files["hypo.units"]] = hyp_pieces + to_write[res_files["hypo.words"]] = hyp_words + + tgt_words = "" + if target_tokens is not None: + if isinstance(target_tokens, str): + tgt_pieces = tgt_words = target_tokens + else: + tgt_pieces = tgt_dict.string(target_tokens) + tgt_words = post_process(tgt_pieces, cfg.post_process) + + if res_files is not None: + to_write[res_files["ref.units"]] = tgt_pieces + to_write[res_files["ref.words"]] = tgt_words + + if not cfg.fairseq.common_eval.quiet: + logger.info(f"HYPO {i}:" + hyp_words) + if tgt_words: + logger.info("TARGET:" + tgt_words) + + if "am_score" in hypo and "lm_score" in hypo: + logger.info( + f"DECODER AM SCORE: {hypo['am_score']}, DECODER LM SCORE: {hypo['lm_score']}, DECODER SCORE: {hypo['score']}" + ) + elif "score" in hypo: + logger.info(f"DECODER SCORE: {hypo['score']}") + + logger.info("___________________") + + hyp_words_arr = hyp_words.split() + tgt_words_arr = tgt_words.split() + + retval.append( + ( + editdistance.eval(hyp_words_arr, tgt_words_arr), + len(hyp_words_arr), + len(tgt_words_arr), + hyp_pieces, + hyp_words, + ) + ) + word_preds.append(hyp_words_arr) + transcriptions.append(to_write) + dec_scores.append(-hypo.get("score", 0)) # negate cuz kaldi returns NLL + + if len(retval) > 1: + best = None + for r, t in zip(retval, transcriptions): + if best is None or r[0] < best[0][0]: + best = r, t + for dest, tran in best[1].items(): + print(tran, file=dest) + dest.flush() + return best[0] + + assert len(transcriptions) == 1 + for dest, tran in transcriptions[0].items(): + print(tran, file=dest) + + return retval[0] + + +def prepare_result_files(cfg: UnsupGenerateConfig): + def get_res_file(file_prefix): + if cfg.fairseq.dataset.num_shards > 1: + file_prefix = f"{cfg.fairseq.dataset.shard_id}_{file_prefix}" + path = os.path.join( + cfg.results_path, + "{}{}.txt".format( + cfg.fairseq.dataset.gen_subset, + file_prefix, + ), + ) + return open(path, "w", buffering=1) + + if not cfg.results_path: + return None + + return { + "hypo.words": get_res_file(""), + "hypo.units": get_res_file("_units"), + "ref.words": get_res_file("_ref"), + "ref.units": get_res_file("_ref_units"), + "hypo.nbest.words": get_res_file("_nbest_words"), + } + + +def optimize_models(cfg: UnsupGenerateConfig, use_cuda, models): + """Optimize ensemble for generation""" + for model in models: + model.eval() + if cfg.fairseq.common.fp16: + model.half() + if use_cuda: + model.cuda() + + +GenResult = namedtuple( + "GenResult", + [ + "count", + "errs_t", + "gen_timer", + "lengths_hyp_unit_t", + "lengths_hyp_t", + "lengths_t", + "lm_score_t", + "num_feats", + "num_sentences", + "num_symbols", + "vt_err_t", + "vt_length_t", + ], +) + + +def generate(cfg: UnsupGenerateConfig, models, saved_cfg, use_cuda): + task = tasks.setup_task(cfg.fairseq.task) + saved_cfg.task.labels = cfg.fairseq.task.labels + task.load_dataset(cfg.fairseq.dataset.gen_subset, task_cfg=saved_cfg.task) + # Set dictionary + tgt_dict = task.target_dictionary + logger.info( + "| {} {} {} examples".format( + cfg.fairseq.task.data, + cfg.fairseq.dataset.gen_subset, + len(task.dataset(cfg.fairseq.dataset.gen_subset)), + ) + ) + # Load dataset (possibly sharded) + itr = get_dataset_itr(cfg, task) + # Initialize generator + gen_timer = StopwatchMeter() + + def build_generator(cfg: UnsupGenerateConfig): + w2l_decoder = cfg.w2l_decoder + if w2l_decoder == DecoderType.VITERBI: + from examples.speech_recognition.w2l_decoder import W2lViterbiDecoder + + return W2lViterbiDecoder(cfg, task.target_dictionary) + elif w2l_decoder == DecoderType.KENLM: + from examples.speech_recognition.w2l_decoder import W2lKenLMDecoder + + return W2lKenLMDecoder(cfg, task.target_dictionary) + elif w2l_decoder == DecoderType.FAIRSEQ: + from examples.speech_recognition.w2l_decoder import W2lFairseqLMDecoder + + return W2lFairseqLMDecoder(cfg, task.target_dictionary) + elif w2l_decoder == DecoderType.KALDI: + from examples.speech_recognition.kaldi.kaldi_decoder import KaldiDecoder + + assert cfg.kaldi_decoder_config is not None + + return KaldiDecoder( + cfg.kaldi_decoder_config, + cfg.beam, + ) + else: + raise NotImplementedError( + "only wav2letter decoders with (viterbi, kenlm, fairseqlm) options are supported at the moment but found " + + str(w2l_decoder) + ) + + generator = build_generator(cfg) + + kenlm = None + fairseq_lm = None + if cfg.lm_model is not None: + import kenlm + + kenlm = kenlm.Model(cfg.lm_model) + + num_sentences = 0 + if cfg.results_path is not None and not os.path.exists(cfg.results_path): + os.makedirs(cfg.results_path) + + res_files = prepare_result_files(cfg) + errs_t = 0 + lengths_hyp_t = 0 + lengths_hyp_unit_t = 0 + lengths_t = 0 + count = 0 + num_feats = 0 + all_hyp_pieces = [] + all_hyp_words = [] + + num_symbols = ( + len([s for s in tgt_dict.symbols if not s.startswith("madeup")]) + - tgt_dict.nspecial + ) + targets = None + if cfg.targets is not None: + tgt_path = os.path.join( + cfg.fairseq.task.data, cfg.fairseq.dataset.gen_subset + "." + cfg.targets + ) + if os.path.exists(tgt_path): + with open(tgt_path, "r") as f: + targets = f.read().splitlines() + viterbi_transcript = None + if cfg.viterbi_transcript is not None and len(cfg.viterbi_transcript) > 0: + logger.info(f"loading viterbi transcript from {cfg.viterbi_transcript}") + with open(cfg.viterbi_transcript, "r") as vf: + viterbi_transcript = vf.readlines() + viterbi_transcript = [v.rstrip().split() for v in viterbi_transcript] + + gen_timer.start() + + start = 0 + end = len(itr) + + hypo_futures = None + if cfg.w2l_decoder == DecoderType.KALDI: + logger.info("Extracting features") + hypo_futures = [] + samples = [] + with progress_bar.build_progress_bar(cfg.fairseq.common, itr) as t: + for i, sample in enumerate(t): + if "net_input" not in sample or i < start or i >= end: + continue + if "padding_mask" not in sample["net_input"]: + sample["net_input"]["padding_mask"] = None + + hypos, num_feats = gen_hypos( + generator, models, num_feats, sample, task, use_cuda + ) + hypo_futures.append(hypos) + samples.append(sample) + if cfg.debug: + break + itr = list(zip(hypo_futures, samples)) + start = 0 + end = len(itr) + logger.info("Finished extracting features") + + with progress_bar.build_progress_bar(cfg.fairseq.common, itr) as t: + for i, sample in enumerate(t): + if i < start or i >= end: + continue + + if hypo_futures is not None: + hypos, sample = sample + hypos = [h.result() for h in hypos] + else: + if "net_input" not in sample: + continue + + hypos, num_feats = gen_hypos( + generator, models, num_feats, sample, task, use_cuda + ) + + for i, sample_id in enumerate(sample["id"].tolist()): + if targets is not None: + target_tokens = targets[sample_id] + elif "target" in sample or "target_label" in sample: + toks = ( + sample["target"][i, :] + if "target_label" not in sample + else sample["target_label"][i, :] + ) + + target_tokens = utils.strip_pad(toks, tgt_dict.pad()).int().cpu() + else: + target_tokens = None + + # Process top predictions + ( + errs, + length_hyp, + length, + hyp_pieces, + hyp_words, + ) = process_predictions( + cfg, + hypos[i], + tgt_dict, + target_tokens, + res_files, + ) + errs_t += errs + lengths_hyp_t += length_hyp + lengths_hyp_unit_t += ( + len(hyp_pieces) if len(hyp_pieces) > 0 else len(hyp_words) + ) + lengths_t += length + count += 1 + all_hyp_pieces.append(hyp_pieces) + all_hyp_words.append(hyp_words) + + num_sentences += ( + sample["nsentences"] if "nsentences" in sample else sample["id"].numel() + ) + + lm_score_sum = 0 + if kenlm is not None: + + if cfg.unit_lm: + lm_score_sum = sum(kenlm.score(w) for w in all_hyp_pieces) + else: + lm_score_sum = sum(kenlm.score(w) for w in all_hyp_words) + elif fairseq_lm is not None: + lm_score_sum = sum(fairseq_lm.score([h.split() for h in all_hyp_words])[0]) + + vt_err_t = 0 + vt_length_t = 0 + if viterbi_transcript is not None: + unit_hyps = [] + if cfg.targets is not None and cfg.lexicon is not None: + lex = {} + with open(cfg.lexicon, "r") as lf: + for line in lf: + items = line.rstrip().split() + lex[items[0]] = items[1:] + for h in all_hyp_pieces: + hyp_ws = [] + for w in h.split(): + assert w in lex, w + hyp_ws.extend(lex[w]) + unit_hyps.append(hyp_ws) + + else: + unit_hyps.extend([h.split() for h in all_hyp_words]) + + vt_err_t = sum( + editdistance.eval(vt, h) for vt, h in zip(viterbi_transcript, unit_hyps) + ) + + vt_length_t = sum(len(h) for h in viterbi_transcript) + + if res_files is not None: + for r in res_files.values(): + r.close() + + gen_timer.stop(lengths_hyp_t) + + return GenResult( + count, + errs_t, + gen_timer, + lengths_hyp_unit_t, + lengths_hyp_t, + lengths_t, + lm_score_sum, + num_feats, + num_sentences, + num_symbols, + vt_err_t, + vt_length_t, + ) + + +def gen_hypos(generator, models, num_feats, sample, task, use_cuda): + sample = utils.move_to_cuda(sample) if use_cuda else sample + + if "features" in sample["net_input"]: + sample["net_input"]["dense_x_only"] = True + num_feats += ( + sample["net_input"]["features"].shape[0] + * sample["net_input"]["features"].shape[1] + ) + hypos = task.inference_step(generator, models, sample, None) + return hypos, num_feats + + +def main(cfg: UnsupGenerateConfig, model=None): + if ( + cfg.fairseq.dataset.max_tokens is None + and cfg.fairseq.dataset.batch_size is None + ): + cfg.fairseq.dataset.max_tokens = 1024000 + + use_cuda = torch.cuda.is_available() and not cfg.fairseq.common.cpu + + task = tasks.setup_task(cfg.fairseq.task) + + overrides = ast.literal_eval(cfg.fairseq.common_eval.model_overrides) + + if cfg.fairseq.task._name == "gan_audio_pretraining_feats": + overrides["model"] = { + "blank_weight": cfg.blank_weight, + "blank_mode": cfg.blank_mode, + "blank_is_sil": cfg.sil_is_blank, + "no_softmax": True, + "segmentation": { + "type": "NONE", + }, + } + else: + overrides["model"] = { + "blank_weight": cfg.blank_weight, + "blank_mode": cfg.blank_mode, + } + + if model is None: + # Load ensemble + logger.info("| loading model(s) from {}".format(cfg.fairseq.common_eval.path)) + models, saved_cfg = checkpoint_utils.load_model_ensemble( + cfg.fairseq.common_eval.path.split("\\"), + arg_overrides=overrides, + task=task, + suffix=cfg.fairseq.checkpoint.checkpoint_suffix, + strict=(cfg.fairseq.checkpoint.checkpoint_shard_count == 1), + num_shards=cfg.fairseq.checkpoint.checkpoint_shard_count, + ) + optimize_models(cfg, use_cuda, models) + else: + models = [model] + saved_cfg = cfg.fairseq + + with open_dict(saved_cfg.task): + saved_cfg.task.shuffle = False + saved_cfg.task.sort_by_length = False + + gen_result = generate(cfg, models, saved_cfg, use_cuda) + + wer = None + if gen_result.lengths_t > 0: + wer = gen_result.errs_t * 100.0 / gen_result.lengths_t + logger.info(f"WER: {wer}") + + lm_ppl = float("inf") + + if gen_result.lm_score_t != 0 and gen_result.lengths_hyp_t > 0: + hyp_len = gen_result.lengths_hyp_t + lm_ppl = math.pow( + 10, -gen_result.lm_score_t / (hyp_len + gen_result.num_sentences) + ) + logger.info(f"LM PPL: {lm_ppl}") + + logger.info( + "| Processed {} sentences ({} tokens) in {:.1f}s ({:.2f}" + " sentences/s, {:.2f} tokens/s)".format( + gen_result.num_sentences, + gen_result.gen_timer.n, + gen_result.gen_timer.sum, + gen_result.num_sentences / gen_result.gen_timer.sum, + 1.0 / gen_result.gen_timer.avg, + ) + ) + + vt_diff = None + if gen_result.vt_length_t > 0: + vt_diff = gen_result.vt_err_t / gen_result.vt_length_t + vt_diff = max(cfg.min_vt_uer, vt_diff) + + lm_ppl = max(cfg.min_lm_ppl, lm_ppl) + + if not cfg.unsupervised_tuning == 0: + weighted_score = wer + else: + weighted_score = math.log(lm_ppl) * (vt_diff or 1.0) + + res = ( + f"| Generate {cfg.fairseq.dataset.gen_subset} with beam={cfg.beam}, " + f"lm_weight={cfg.kaldi_decoder_config.acoustic_scale if cfg.kaldi_decoder_config else cfg.lm_weight}, " + f"word_score={cfg.word_score}, sil_weight={cfg.sil_weight}, blank_weight={cfg.blank_weight}, " + f"WER: {wer}, LM_PPL: {lm_ppl}, num feats: {gen_result.num_feats}, " + f"length: {gen_result.lengths_hyp_t}, UER to viterbi: {(vt_diff or 0) * 100}, score: {weighted_score}" + ) + + logger.info(res) + # print(res) + + return task, weighted_score + + +@hydra.main( + config_path=os.path.join("../../..", "fairseq", "config"), config_name="config" +) +def hydra_main(cfg): + with open_dict(cfg): + # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) + cfg.job_logging_cfg = OmegaConf.to_container( + HydraConfig.get().job_logging, resolve=True + ) + + cfg = OmegaConf.create( + OmegaConf.to_container(cfg, resolve=False, enum_to_str=False) + ) + OmegaConf.set_struct(cfg, True) + logger.info(cfg) + _, score = main(cfg) + + if cfg.is_ax: + return score, None + return score + + +def cli_main(): + try: + from hydra._internal.utils import get_args + + cfg_name = get_args().config_name or "config" + except: + logger.warning("Failed to get config name from hydra args") + cfg_name = "config" + + cs = ConfigStore.instance() + cs.store(name=cfg_name, node=UnsupGenerateConfig) + hydra_main() + + +if __name__ == "__main__": + cli_main() diff --git a/examples/wav2vec/wav2vec_manifest.py b/examples/wav2vec/wav2vec_manifest.py index 5417084554..9b8aa180e8 100644 --- a/examples/wav2vec/wav2vec_manifest.py +++ b/examples/wav2vec/wav2vec_manifest.py @@ -54,11 +54,17 @@ def main(args): search_path = os.path.join(dir_path, "**/*." + args.ext) rand = random.Random(args.seed) - with open(os.path.join(args.dest, "train.tsv"), "w") as train_f, open( - os.path.join(args.dest, "valid.tsv"), "w" - ) as valid_f: + valid_f = ( + open(os.path.join(args.dest, "valid.tsv"), "w") + if args.valid_percent > 0 + else None + ) + + with open(os.path.join(args.dest, "train.tsv"), "w") as train_f: print(dir_path, file=train_f) - print(dir_path, file=valid_f) + + if valid_f is not None: + print(dir_path, file=valid_f) for fname in glob.iglob(search_path, recursive=True): file_path = os.path.realpath(fname) @@ -71,6 +77,8 @@ def main(args): print( "{}\t{}".format(os.path.relpath(file_path, dir_path), frames), file=dest ) + if valid_f is not None: + valid_f.close() if __name__ == "__main__": diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 4cb5193bde..9ce3f7e39d 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -13,10 +13,12 @@ import torch import torch.nn.functional as F -from .. import FairseqDataset, BaseWrapperDataset +from .. import FairseqDataset from ..data_utils import compute_mask_indices, get_buckets, get_bucketed_sizes from fairseq.data.audio.audio_utils import ( - parse_path, read_from_stored_zip, is_sf_audio_data + parse_path, + read_from_stored_zip, + is_sf_audio_data, ) @@ -212,11 +214,15 @@ def ordered_indices(self): if self.shuffle: order = [np.random.permutation(len(self))] + order.append( + np.minimum( + np.array(self.sizes), + self.max_sample_size, + ) + ) + return np.lexsort(order)[::-1] else: - order = [np.arange(len(self))] - - order.append(self.sizes) - return np.lexsort(order)[::-1] + return np.arange(len(self)) def set_bucket_info(self, num_buckets): self.num_buckets = num_buckets diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 8c5e5a490d..70a4086cd0 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -373,6 +373,10 @@ def post_process(sentence: str, symbol: str): sentence = sentence.replace(" ", "").replace("_", " ").strip() elif symbol == "letter": sentence = sentence.replace(" ", "").replace("|", " ").strip() + elif symbol == "silence": + import re + sentence = sentence.replace("<SIL>", "") + sentence = re.sub(' +', ' ', sentence).strip() elif symbol == "_EOW": sentence = sentence.replace(" ", "").replace("_EOW", " ").strip() elif symbol in {"subword_nmt", "@@ ", "@@"}: diff --git a/fairseq/logging/meters.py b/fairseq/logging/meters.py index 6793ef54e6..2100b1fa0b 100644 --- a/fairseq/logging/meters.py +++ b/fairseq/logging/meters.py @@ -109,6 +109,38 @@ def smoothed_value(self) -> float: return val +class SumMeter(Meter): + """Computes and stores the sum""" + + def __init__(self, round: Optional[int] = None): + self.round = round + self.reset() + + def reset(self): + self.sum = 0 # sum from all updates + + def update(self, val): + if val is not None: + self.sum = type_as(self.sum, val) + val + + def state_dict(self): + return { + "sum": self.sum, + "round": self.round, + } + + def load_state_dict(self, state_dict): + self.sum = state_dict["sum"] + self.round = state_dict.get("round", None) + + @property + def smoothed_value(self) -> float: + val = self.sum + if self.round is not None and val is not None: + val = safe_round(val, self.round) + return val + + class TimeMeter(Meter): """Computes the average occurrence of some event per second""" diff --git a/fairseq/logging/metrics.py b/fairseq/logging/metrics.py index 2bb1da086f..58c2fb64e1 100644 --- a/fairseq/logging/metrics.py +++ b/fairseq/logging/metrics.py @@ -12,10 +12,9 @@ """ import contextlib -import time import uuid -from collections import OrderedDict, defaultdict -from typing import Callable, Dict, List, Optional +from collections import defaultdict +from typing import Callable, List, Optional from .meters import * @@ -131,6 +130,25 @@ def log_scalar( agg.add_meter(key, AverageMeter(round=round), priority) agg[key].update(value, weight) +def log_scalar_sum( + key: str, + value: float, + priority: int = 10, + round: Optional[int] = None, +): + """Log a scalar value that is summed for reporting. + + Args: + key (str): name of the field to log + value (float): value to log + priority (int): smaller values are logged earlier in the output + round (Optional[int]): number of digits to round to when displaying + """ + for agg in get_active_aggregators(): + if key not in agg: + agg.add_meter(key, SumMeter(round=round), priority) + agg[key].update(value) + def log_derived(key: str, fn: Callable[[MetersDict], float], priority: int = 20): """Log a scalar value derived from other meters. diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index 6af288b10e..06905455fd 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -18,7 +18,6 @@ ModuleProxyWrapper, TPUDistributedDataParallel, ) -from torch.distributed.algorithms.ddp_comm_hooks import register_ddp_comm_hook, DDPCommHookType logger = logging.getLogger(__name__) @@ -65,8 +64,19 @@ def DistributedFairseqModel(args, model, process_group, device): process_group=process_group, find_unused_parameters=args.find_unused_parameters, ) - if args.ddp_comm_hook == 'fp16': + if args.ddp_comm_hook == "fp16": logger.info("enable fp16 communication hook in DDP") + try: + from torch.distributed.algorithms.ddp_comm_hooks import ( + register_ddp_comm_hook, + DDPCommHookType, + ) + except: + logger.error( + "Could not import from torch.distributed.algorithms.ddp_comm_hooks; you may need to update your pytorch version" + ) + raise + register_ddp_comm_hook(DDPCommHookType.FP16_COMPRESS, wrapped_model) # forward missing getattr and state_dict/load_state_dict to orig model wrapped_model = ModuleProxyWrapper(wrapped_model) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 6999dca2d9..6002d28438 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -165,6 +165,7 @@ class Wav2Vec2Config(FairseqDataclass): mask_channel_prob: float = field( default=0.0, metadata={"help": "probability of replacing a feature with 0"} ) + mask_channel_before: bool = False mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( default="static", metadata={"help": "how to choose mask length for channel masking"}, @@ -249,6 +250,7 @@ def __init__(self, cfg: Wav2Vec2Config): self.mask_min_space = cfg.mask_min_space self.mask_channel_prob = cfg.mask_channel_prob + self.mask_channel_before = cfg.mask_channel_before self.mask_channel_selection = cfg.mask_channel_selection self.mask_channel_other = cfg.mask_channel_other self.mask_channel_length = cfg.mask_channel_length @@ -331,10 +333,33 @@ def build_model(cls, cfg: Wav2Vec2Config, task=None): return cls(cfg) def apply_mask( - self, x, padding_mask, - mask_indices=None, mask_channel_indices=None, + self, + x, + padding_mask, + mask_indices=None, + mask_channel_indices=None, ): B, T, C = x.shape + + if self.mask_channel_prob > 0 and self.mask_channel_before: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_channel_prob, + self.mask_channel_length, + self.mask_channel_selection, + self.mask_channel_other, + no_overlap=self.no_mask_channel_overlap, + min_space=self.mask_channel_min_space, + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x[mask_channel_indices] = 0 + if self.mask_prob > 0: if mask_indices is None: mask_indices = compute_mask_indices( @@ -353,7 +378,7 @@ def apply_mask( else: mask_indices = None - if self.mask_channel_prob > 0: + if self.mask_channel_prob > 0 and not self.mask_channel_before: if mask_channel_indices is None: mask_channel_indices = compute_mask_indices( (B, C), @@ -445,12 +470,12 @@ def compute_preds(self, x, y, negatives): logits = logits / self.logit_temp if is_xla_tensor(logits) or neg_is_pos.any(): - fillval = -float(2**30) - if not hasattr(self, '_inftensor'): + fillval = -float(2 ** 30) + if not hasattr(self, "_inftensor"): self._inftensor = ( torch.tensor(fillval).to(x.device) - if is_xla_tensor(logits) else - float("-inf") + if is_xla_tensor(logits) + else float("-inf") ) logits[1:] = index_put(logits[1:], neg_is_pos, self._inftensor) @@ -467,13 +492,21 @@ def _conv_out_length(input_length, kernel_size, stride): conv_cfg_list = eval(self.cfg.conv_feature_layers) for i in range(len(conv_cfg_list)): - input_lengths = _conv_out_length(input_lengths, conv_cfg_list[i][1], conv_cfg_list[i][2]) + input_lengths = _conv_out_length( + input_lengths, conv_cfg_list[i][1], conv_cfg_list[i][2] + ) return input_lengths.to(torch.long) def forward( - self, source, padding_mask=None, mask=True, features_only=False, - mask_indices=None, mask_channel_indices=None, + self, + source, + padding_mask=None, + mask=True, + features_only=False, + layer=None, + mask_indices=None, + mask_channel_indices=None, padding_count=None, ): @@ -491,7 +524,7 @@ def forward( features = self.layer_norm(features) unmasked_features = features.clone() - if padding_mask is not None: + if padding_mask is not None and padding_mask.any(): input_lengths = (1 - padding_mask.long()).sum(-1) # apply conv formula to get real output_lengths output_lengths = self._get_feat_extract_output_lengths(input_lengths) @@ -502,8 +535,15 @@ def forward( # these two operations makes sure that all values # before the output lengths indices are attended to - padding_mask[(torch.arange(padding_mask.shape[0], device=padding_mask.device), output_lengths - 1)] = 1 + padding_mask[ + ( + torch.arange(padding_mask.shape[0], device=padding_mask.device), + output_lengths - 1, + ) + ] = 1 padding_mask = (1 - padding_mask.flip([-1]).cumsum(-1).flip([-1])).bool() + else: + padding_mask = None if self.post_extract_proj is not None: features = self.post_extract_proj(features) @@ -527,7 +567,8 @@ def forward( if mask: x, mask_indices = self.apply_mask( - features, padding_mask, + features, + padding_mask, mask_indices=mask_indices, mask_channel_indices=mask_channel_indices, ) @@ -544,10 +585,15 @@ def forward( y = unmasked_features mask_indices = None - x = self.encoder(x, padding_mask=padding_mask) + x, layer_results = self.encoder(x, padding_mask=padding_mask, layer=layer) if features_only: - return {"x": x, "padding_mask": padding_mask} + return { + "x": x, + "padding_mask": padding_mask, + "features": unmasked_features, + "layer_results": layer_results, + } if self.quantizer: q = self.quantizer(y, produce_targets=False) @@ -560,17 +606,21 @@ def forward( y = self.project_q(y) if self.negatives_from_everywhere: - neg_cands = self.quantizer( - unmasked_features, produce_targets=False - )["x"] + neg_cands = self.quantizer(unmasked_features, produce_targets=False)[ + "x" + ] negs, _ = self.sample_negatives( - neg_cands, y.size(1), padding_count=padding_count, + neg_cands, + y.size(1), + padding_count=padding_count, ) negs = self.project_q(negs) else: negs, _ = self.sample_negatives( - y, y.size(1), padding_count=padding_count, + y, + y.size(1), + padding_count=padding_count, ) if self.codebook_negatives > 0: @@ -587,13 +637,16 @@ def forward( if self.negatives_from_everywhere: negs, _ = self.sample_negatives( - unmasked_features, y.size(1), + unmasked_features, + y.size(1), padding_count=padding_count, ) negs = self.project_q(negs) else: negs, _ = self.sample_negatives( - y, y.size(1), padding_count=padding_count, + y, + y.size(1), + padding_count=padding_count, ) if not is_xla_tensor(x): @@ -609,7 +662,9 @@ def forward( x = self.compute_preds(x, y, negs) result = { - "x": x, "padding_mask": padding_mask, "features_pen": features_pen, + "x": x, + "padding_mask": padding_mask, + "features_pen": features_pen, } if prob_ppl is not None: @@ -627,9 +682,11 @@ def quantize(self, x): x = self.layer_norm(x) return self.quantizer.forward_idx(x) - def extract_features(self, source, padding_mask, mask=False): - res = self.forward(source, padding_mask, mask=mask, features_only=True) - return res["x"], res["padding_mask"] + def extract_features(self, source, padding_mask, mask=False, layer=None): + res = self.forward( + source, padding_mask, mask=mask, features_only=True, layer=layer + ) + return res def get_logits(self, net_output): logits = net_output["x"] @@ -787,15 +844,15 @@ def __init__(self, args): self.apply(init_bert_params) - def forward(self, x, padding_mask=None): - x = self.extract_features(x, padding_mask) + def forward(self, x, padding_mask=None, layer=None): + x, layer_results = self.extract_features(x, padding_mask, layer) - if self.layer_norm_first: + if self.layer_norm_first and layer is None: x = self.layer_norm(x) - return x + return x, layer_results - def extract_features(self, x, padding_mask=None): + def extract_features(self, x, padding_mask=None, tgt_layer=None): if padding_mask is not None: x = index_put(x, padding_mask, 0) @@ -813,16 +870,24 @@ def extract_features(self, x, padding_mask=None): x = x.transpose(0, 1) layer_results = [] + r = None for i, layer in enumerate(self.layers): dropout_probability = np.random.random() if not self.training or (dropout_probability > self.layerdrop): x, z = layer(x, self_attn_padding_mask=padding_mask, need_weights=False) - layer_results.append(x) + if tgt_layer is not None: + layer_results.append((x, z)) + if i == tgt_layer: + r = x + break + + if r is not None: + x = r # T x B x C -> B x T x C x = x.transpose(0, 1) - return x + return x, layer_results def max_positions(self): """Maximum output length supported by the encoder.""" @@ -901,7 +966,6 @@ def forward( key=x, value=x, key_padding_mask=self_attn_padding_mask, - need_weights=False, attn_mask=self_attn_mask, ) x = self.dropout1(x) @@ -920,7 +984,6 @@ def forward( key=x, value=x, key_padding_mask=self_attn_padding_mask, - need_weights=need_weights, ) x = self.dropout1(x) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index e8a1d03eb2..abae9d1ab3 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -13,7 +13,7 @@ import torch.nn.functional as F from dataclasses import dataclass, field from omegaconf import MISSING, II, open_dict -from typing import Optional, Any +from typing import Any, Optional from fairseq import checkpoint_utils, tasks, utils from fairseq.dataclass import FairseqDataclass @@ -27,7 +27,12 @@ register_model, ) from fairseq.models.wav2vec.wav2vec2 import MASKING_DISTRIBUTION_CHOICES -from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerDecoderLayer +from fairseq.modules import ( + LayerNorm, + PositionalEmbedding, + TransformerDecoderLayer, + SamePad, +) @dataclass @@ -119,6 +124,7 @@ class Wav2Vec2AsrConfig(FairseqDataclass): layerdrop: float = field( default=0.0, metadata={"help": "probability of dropping a layer in wav2vec 2.0"} ) + mask_channel_before: bool = False normalize: bool = II("task.normalize") data: str = II("task.data") # this holds the loaded wav2vec args @@ -127,6 +133,8 @@ class Wav2Vec2AsrConfig(FairseqDataclass): @dataclass class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): + blank_weight: float = 0 + blank_mode: str = "add" mask_min_space: Optional[int] = field( default=1, metadata={"help": "min space between spans (if no overlap is enabled)"}, @@ -156,6 +164,8 @@ def __init__(self, cfg: Wav2Vec2CtcConfig, w2v_encoder: BaseFairseqModel): super().__init__() self.cfg = cfg self.w2v_encoder = w2v_encoder + self.blank_weight = cfg.blank_weight + self.blank_mode = cfg.blank_mode def upgrade_state_dict_named(self, state_dict, name): super().upgrade_state_dict_named(state_dict, name) @@ -164,28 +174,38 @@ def upgrade_state_dict_named(self, state_dict, name): @classmethod def build_model(cls, cfg: Wav2Vec2CtcConfig, task: FairseqTask): """Build a new model instance.""" - w2v_encoder = Wav2VecEncoder(cfg, task.target_dictionary) + w2v_encoder = Wav2VecEncoder(cfg, len(task.target_dictionary)) return cls(cfg, w2v_encoder) + def get_logits(self, net_output, normalize=False): + logits = net_output["encoder_out"] + if self.blank_weight != 0: + if self.blank_mode == "add": + logits[..., 0] += self.blank_weight + elif self.blank_mode == "set": + logits[..., 0] = self.blank_weight + else: + raise Exception(f"invalid blank mode {self.blank_mode}") + + if net_output["padding_mask"] is not None and net_output["padding_mask"].any(): + logits[net_output["padding_mask"].T][..., 0] = float("inf") + logits[net_output["padding_mask"].T][..., 1:] = float("-inf") + + if normalize: + logits = utils.log_softmax(logits.float(), dim=-1) + + return logits + def get_normalized_probs(self, net_output, log_probs): """Get normalized probabilities (or log probs) from a net's output.""" - logits = net_output["encoder_out"] + logits = self.get_logits(net_output) + if log_probs: return utils.log_softmax(logits.float(), dim=-1) else: return utils.softmax(logits.float(), dim=-1) - def get_logits(self, net_output): - logits = net_output["encoder_out"] - padding = net_output["padding_mask"] - if padding is not None and padding.any(): - padding = padding.T - logits[padding][...,0] = 0 - logits[padding][...,1:] = float('-inf') - - return logits - def forward(self, **kwargs): x = self.w2v_encoder(**kwargs) return x @@ -237,7 +257,7 @@ class Wav2Vec2Seq2SeqConfig(Wav2Vec2AsrConfig): max_target_positions: int = field( default=2048, metadata={"help": "max target positions"} ) - share_decoder_input_output_embed: bool = field( + share_decoder_input_output_embed: bool = field( default=False, metadata={"help": "share decoder input and output embeddings"} ) autoregressive: bool = II("task.autoregressive") @@ -252,7 +272,9 @@ def __init__(self, encoder, decoder): def build_model(cls, cfg: Wav2Vec2Seq2SeqConfig, task: FairseqTask): """Build a new model instance.""" - assert cfg.autoregressive, "Please set task.autoregressive=true for seq2seq asr models" + assert ( + cfg.autoregressive + ), "Please set task.autoregressive=true for seq2seq asr models" src_dict, tgt_dict = task.source_dictionary, task.target_dictionary @@ -288,7 +310,7 @@ def upgrade_state_dict_named(self, state_dict, name): class Wav2VecEncoder(FairseqEncoder): - def __init__(self, cfg: Wav2Vec2AsrConfig, tgt_dict=None): + def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): self.apply_mask = cfg.apply_mask arg_overrides = { @@ -303,6 +325,7 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, tgt_dict=None): "no_mask_overlap": cfg.no_mask_overlap, "mask_channel_length": cfg.mask_channel_length, "mask_channel_prob": cfg.mask_channel_prob, + "mask_channel_before": cfg.mask_channel_before, "mask_channel_selection": cfg.mask_channel_selection, "mask_channel_other": cfg.mask_channel_other, "no_mask_channel_overlap": cfg.no_mask_channel_overlap, @@ -346,12 +369,16 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, tgt_dict=None): self.freeze_finetune_updates = cfg.freeze_finetune_updates self.num_updates = 0 - if tgt_dict is not None: - self.proj = Linear(d, len(tgt_dict)) + targ_d = None + self.proj = None + + if output_size is not None: + targ_d = output_size elif getattr(cfg, "decoder_embed_dim", d) != d: - self.proj = Linear(d, cfg.decoder_embed_dim) - else: - self.proj = None + targ_d = cfg.decoder_embed_dim + + if targ_d is not None: + self.proj = Linear(d, targ_d) def set_num_updates(self, num_updates): """Set the number of parameters updates.""" @@ -359,7 +386,6 @@ def set_num_updates(self, num_updates): self.num_updates = num_updates def forward(self, source, padding_mask, tbc=True, **kwargs): - w2v_args = { "source": source, "padding_mask": padding_mask, @@ -369,10 +395,13 @@ def forward(self, source, padding_mask, tbc=True, **kwargs): ft = self.freeze_finetune_updates <= self.num_updates with torch.no_grad() if not ft else contextlib.ExitStack(): - x, padding_mask = self.w2v_model.extract_features(**w2v_args) + res = self.w2v_model.extract_features(**w2v_args) + + x = res["x"] + padding_mask = res["padding_mask"] if tbc: - # B x T x C -> T x B x C + # BTC -> TBC x = x.transpose(0, 1) x = self.final_dropout(x) @@ -382,8 +411,11 @@ def forward(self, source, padding_mask, tbc=True, **kwargs): return { "encoder_out": x, # T x B x C - "encoder_padding_mask": padding_mask.transpose(0, 1), # T x B + "encoder_padding_mask": padding_mask.transpose(0, 1) + if padding_mask is not None + else None, # T x B "padding_mask": padding_mask, + "layer_results": res["layer_results"], } def reorder_encoder_out(self, encoder_out, new_order): @@ -562,9 +594,7 @@ def extract_features( x, attn, _ = layer( x, encoder_out["encoder_out"] if encoder_out is not None else None, - encoder_out["padding_mask"] - if encoder_out is not None - else None, + encoder_out["padding_mask"] if encoder_out is not None else None, incremental_state, self_attn_mask=self.buffered_future_mask(x) if incremental_state is None diff --git a/fairseq/optim/adam.py b/fairseq/optim/adam.py index f73804718a..cfe948a194 100644 --- a/fairseq/optim/adam.py +++ b/fairseq/optim/adam.py @@ -7,7 +7,7 @@ import math from collections.abc import Collection from dataclasses import dataclass, field -from typing import List +from typing import Any, List import torch import torch.distributed as dist @@ -23,8 +23,8 @@ @dataclass class FairseqAdamConfig(FairseqDataclass): - adam_betas: str = field( - default="(0.9, 0.999)", metadata={"help": "betas for Adam optimizer"} + adam_betas: Any = field( + default=(0.9, 0.999), metadata={"help": "betas for Adam optimizer"} ) adam_eps: float = field( default=1e-8, metadata={"help": "epsilon for Adam optimizer"} @@ -47,7 +47,7 @@ class FairseqAdam(FairseqOptimizer): analogous to torch.optim.AdamW from PyTorch. """ - def __init__(self, cfg: DictConfig, params): + def __init__(self, cfg: FairseqAdamConfig, params): super().__init__(cfg) fused_adam_cls = get_fused_adam_class() use_fused_adam = ( @@ -77,7 +77,7 @@ def optimizer_config(self): "lr": self.cfg.lr[0] if isinstance(self.cfg.lr, Collection) else self.cfg.lr, - "betas": eval(self.cfg.adam_betas), + "betas": eval(self.cfg.adam_betas) if isinstance(self.cfg.adam_betas, str) else self.cfg.adam_betas, "eps": self.cfg.adam_eps, "weight_decay": self.cfg.weight_decay, } diff --git a/fairseq/options.py b/fairseq/options.py index 7558264fce..2d9f8381a7 100644 --- a/fairseq/options.py +++ b/fairseq/options.py @@ -286,6 +286,8 @@ def add_preprocess_args(parser): help="Pad dictionary size to be multiple of N") group.add_argument("--workers", metavar="N", default=1, type=int, help="number of parallel workers") + group.add_argument("--dict-only", action='store_true', + help="if true, only builds a dictionary and then exits") # fmt: on return parser diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index ddef3d58d2..8a3858563e 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -5,6 +5,7 @@ import math from typing import Dict, List, Optional +import sys import torch import torch.nn as nn @@ -214,8 +215,15 @@ def _generate( if net_input["padding_mask"] is not None else torch.tensor(src_tokens.size(-1)).to(src_tokens) ) + elif "features" in net_input: + src_tokens = net_input["features"] + src_lengths = ( + net_input["padding_mask"].size(-1) - net_input["padding_mask"].sum(-1) + if net_input["padding_mask"] is not None + else torch.tensor(src_tokens.size(-1)).to(src_tokens) + ) else: - raise Exception("expected src_tokens or source in net input") + raise Exception("expected src_tokens or source in net input. input keys: " + str(net_input.keys())) # bsz: total number of sentences in beam # Note that src_tokens may have more than 2 dimensions (i.e. audio features) @@ -750,7 +758,7 @@ def has_incremental_states(self): return self.has_incremental def max_decoder_positions(self): - return min([m.max_decoder_positions() for m in self.models]) + return min([m.max_decoder_positions() for m in self.models if hasattr(m, "max_decoder_positions")] + [sys.maxsize]) @torch.jit.export def forward_encoder(self, net_input: Dict[str, Tensor]): @@ -780,7 +788,10 @@ def forward_decoder( incremental_state=incremental_states[i], ) else: - decoder_out = model.decoder.forward(tokens, encoder_out=encoder_out) + if hasattr(model, "decoder"): + decoder_out = model.decoder.forward(tokens, encoder_out=encoder_out) + else: + decoder_out = model.forward(tokens) attn: Optional[Tensor] = None decoder_len = len(decoder_out) @@ -800,7 +811,6 @@ def forward_decoder( decoder_out[0][:, -1:, :].div_(temperature), None if decoder_len <= 1 else decoder_out[1], ) - probs = model.get_normalized_probs( decoder_out_tuple, log_probs=True, sample=None ) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 071331a10a..e0b001b667 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -137,7 +137,7 @@ class AudioPretrainingConfig(FairseqDataclass): @register_task("audio_pretraining", dataclass=AudioPretrainingConfig) class AudioPretrainingTask(FairseqTask): - """""" + """ """ cfg: AudioPretrainingConfig @@ -199,7 +199,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): if not hasattr(task_cfg, "autoregressive"): task_cfg.autoregressive = not task_cfg.criterion == "ctc" - if getattr(task_cfg, 'binarized_dataset', False): + if getattr(task_cfg, "binarized_dataset", False): self.datasets[split] = BinarizedAudioDataset( data_path, split=split, @@ -236,13 +236,9 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): if task_cfg.labels: label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") - skipped_indices = getattr(self.datasets[split], 'skipped_indices', set()) + skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) with open(label_path, "r") as f: - labels = [ - line - for i, line in enumerate(f) - if i not in skipped_indices - ] + labels = [line for i, line in enumerate(f) if i not in skipped_indices] assert len(labels) == len(self.datasets[split]), ( f"labels length ({len(labels)}) and dataset length " @@ -360,7 +356,7 @@ def reduce_metrics(self, logging_outputs, criterion): metrics.log_scalar("_num_chars", num_chars) metrics.log_scalar("_num_word_errors", num_word_errors) metrics.log_scalar("_num_words", num_words) - if num_words > 0: + if num_chars > 0: metrics.log_derived( "uer", lambda meters: meters["_num_char_errors"].sum @@ -369,6 +365,7 @@ def reduce_metrics(self, logging_outputs, criterion): if meters["_num_chars"].sum > 0 else float("nan"), ) + if num_words > 0: metrics.log_derived( "wer", lambda meters: meters["_num_word_errors"].sum diff --git a/fairseq/utils.py b/fairseq/utils.py index 03826d18d0..d0ce16ae6b 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -110,7 +110,6 @@ def _move_to_cuda(tensor): def move_to_cpu(sample): - def _move_to_cpu(tensor): # PyTorch has poor support for half tensors (float16) on CPU. # Move any such tensors to float32. @@ -124,6 +123,7 @@ def _move_to_cpu(tensor): def move_to_tpu(sample): import torch_xla.core.xla_model as xm + device = xm.xla_device() def _move_to_tpu(tensor): @@ -302,7 +302,7 @@ def convert_padding_direction( def item(tensor): # tpu-comment: making this a no-op for xla devices. - if torch.is_tensor(tensor) and tensor.device.type == 'xla': + if torch.is_tensor(tensor) and tensor.device.type == "xla": return tensor.detach() if hasattr(tensor, "item"): return tensor.item() @@ -341,11 +341,16 @@ def multi_tensor_total_norm(grads, chunk_size=2048 * 32) -> torch.Tensor: def clip_grad_norm_(params, max_norm, aggregate_norm_fn=None) -> torch.Tensor: def grad_exists(p): return p is not None and getattr(p, "grad", None) is not None + if isinstance(params, torch.Tensor): params = [params] params = list(params) - grads = [p.grad.detach() for p in params if grad_exists(p) and not hasattr(p, 'expert')] - expert_grads = [p.grad.detach() for p in params if grad_exists(p) and hasattr(p, 'expert')] + grads = [ + p.grad.detach() for p in params if grad_exists(p) and not hasattr(p, "expert") + ] + expert_grads = [ + p.grad.detach() for p in params if grad_exists(p) and hasattr(p, "expert") + ] if len(grads) == 0: if len(params) > 0: @@ -454,7 +459,9 @@ def import_user_module(args): module_path = getattr(args, "user_dir", None) if module_path is not None: module_path = os.path.abspath(args.user_dir) - if not os.path.exists(module_path) and not os.path.isfile(os.path.dirname(module_path)): + if not os.path.exists(module_path) and not os.path.isfile( + os.path.dirname(module_path) + ): fairseq_rel_path = os.path.join(os.path.dirname(__file__), args.user_dir) if os.path.exists(fairseq_rel_path): module_path = fairseq_rel_path @@ -515,7 +522,7 @@ def deprecation_warning(message, stacklevel=3): def get_activation_fn(activation: str) -> Callable: - """ Returns the activation function corresponding to `activation` """ + """Returns the activation function corresponding to `activation`""" from fairseq.modules import gelu, gelu_accurate if activation == "relu": @@ -653,18 +660,13 @@ def extract_hard_alignment(attn, src_sent, tgt_sent, pad, eos): def extract_soft_alignment(attn, src_sent, tgt_sent, pad, eos): - tgt_valid = ( - ((tgt_sent != pad)).nonzero(as_tuple=False) - ) - src_valid = ( - ((src_sent != pad)).nonzero(as_tuple=False).squeeze(dim=-1) - ) + tgt_valid = ((tgt_sent != pad)).nonzero(as_tuple=False) + src_valid = ((src_sent != pad)).nonzero(as_tuple=False).squeeze(dim=-1) alignment = [] if len(tgt_valid) != 0 and len(src_valid) != 0: attn_valid = attn[tgt_valid, src_valid] alignment = [ - ["{:.6f}".format(p) for p in src_probs.tolist()] - for src_probs in attn_valid + ["{:.6f}".format(p) for p in src_probs.tolist()] for src_probs in attn_valid ] return alignment @@ -699,7 +701,7 @@ def tpu_data_loader(itr): def is_xla_tensor(tensor): - return torch.is_tensor(tensor) and tensor.device.type == 'xla' + return torch.is_tensor(tensor) and tensor.device.type == "xla" def index_put(tensor, indices, value): @@ -716,6 +718,7 @@ def index_put(tensor, indices, value): def xla_device_to_cpu(dat): import torch_xla.core.xla_model as xm + return xm._maybe_convert_to_cpu(dat) @@ -778,3 +781,18 @@ def eval_bool(x, default=False): return bool(eval(x)) except TypeError: return default + + +def reset_logging(): + root = logging.getLogger() + for handler in root.handlers: + root.removeHandler(handler) + root.setLevel(os.environ.get("LOGLEVEL", "INFO").upper()) + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter( + logging.Formatter( + fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + ) + root.addHandler(handler) diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index 4501cac67e..ab6e77029e 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -42,7 +42,7 @@ def eval_lm( output_word_probs: bool = False, output_word_stats: bool = False, target_dictionary: Optional[fairseq.data.Dictionary] = None, - softmax_batch: int = False, + softmax_batch: int = 0, remove_bos_token: bool = False, device: Optional[torch.device] = None, ): diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index 180bd40717..9de01084ba 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -6,12 +6,12 @@ import logging import os -import sys from fairseq.dataclass.initialize import add_defaults, hydra_init from fairseq_cli.train import main as pre_main from fairseq import distributed_utils, metrics from fairseq.dataclass.configs import FairseqConfig +from fairseq.utils import reset_logging import hydra from hydra.core.hydra_config import HydraConfig @@ -63,21 +63,6 @@ def hydra_main(cfg: FairseqConfig) -> float: return best_val -def reset_logging(): - root = logging.getLogger() - for handler in root.handlers: - root.removeHandler(handler) - root.setLevel(os.environ.get("LOGLEVEL", "INFO").upper()) - handler = logging.StreamHandler(sys.stdout) - handler.setFormatter( - logging.Formatter( - fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - ) - ) - root.addHandler(handler) - - def cli_main(): try: from hydra._internal.utils import get_args diff --git a/fairseq_cli/preprocess.py b/fairseq_cli/preprocess.py index fa77da8dba..b788900d30 100644 --- a/fairseq_cli/preprocess.py +++ b/fairseq_cli/preprocess.py @@ -117,6 +117,9 @@ def build_dictionary(filenames, src=False, tgt=False): if target and tgt_dict is not None: tgt_dict.save(dict_path(args.target_lang)) + if args.dict_only: + return + def make_binary_dataset(vocab, input_prefix, output_prefix, lang, num_workers): logger.info("[{}] Dictionary: {} types".format(lang, len(vocab))) n_seq_tok = [0, 0] diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index cb49915827..a1b7cb58e2 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -162,6 +162,7 @@ def main(cfg: FairseqConfig) -> None: max_epoch = cfg.optimization.max_epoch or math.inf lr = trainer.get_lr() + train_meter = meters.StopwatchMeter() train_meter.start() while epoch_itr.next_epoch_idx <= max_epoch: @@ -381,7 +382,7 @@ def validate_and_save( and num_updates > 0 and num_updates % cfg.dataset.validate_interval_updates == 0 ) - ) and not cfg.dataset.disable_validation + ) and not cfg.dataset.disable_validation and num_updates >= cfg.dataset.validate_after_updates # Validate valid_losses = [None] @@ -460,6 +461,10 @@ def validate( # log validation stats stats = get_valid_stats(cfg, trainer, agg.get_smoothed_values()) + + if hasattr(task, "post_validate"): + task.post_validate(trainer.get_model(), stats, agg) + progress.print(stats, tag=subset, step=trainer.get_num_updates()) valid_losses.append(stats[cfg.checkpoint.best_checkpoint_metric]) diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index 90d7e4c6a9..f0d983ee6b 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -66,6 +66,7 @@ def main(cfg: DictConfig, override_args=None): # Move models to GPU for model in models: + model.eval() if use_fp16: model.half() if use_cuda: From a8fe9434adeb6caea65b34ca968f4e5cd1d75be6 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Fri, 21 May 2021 12:11:57 -0700 Subject: [PATCH 340/774] fix readme link (#1890) Summary: fix link to self training readme Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1890 Reviewed By: arbabu123, ArmenAg Differential Revision: D28609910 Pulled By: alexeib fbshipit-source-id: 4cbbb75cfec876938d80c8d7bc0df4ba93d4f54d --- examples/wav2vec/unsupervised/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wav2vec/unsupervised/README.md b/examples/wav2vec/unsupervised/README.md index 2277e65ffb..e9ec59f06d 100644 --- a/examples/wav2vec/unsupervised/README.md +++ b/examples/wav2vec/unsupervised/README.md @@ -70,6 +70,6 @@ fairseq.dataset.gen_subset=valid results_path=/where/to/save/transcriptions After the GAN training provides a first unsupervised model, we can then progressively refine the quality of transcriptions using several iterations of semi-supervised learning. We perform two iterations: first, pseudo-label the training data with the unsupervised GAN model and train an HMM on the pseudo-labels. Second, we relabel the training data with the HMM and then fine-tune the original wav2vec 2.0 model using the HMM pseudo-labels with a CTC loss. Note that HMM models use phonemes as output, while wav2vec 2.0 use letter. Both are decoded using WFST decoders into words. -Please see [this README](http://github.com/pytorch/fairseq/tree/master/examples/wav2vec/unsupervised/kaldi_st) for more instructions on how to do iterative self-training + Kaldi LM-decoding. +Please see [this README](kaldi_self_train/README.md) for more instructions on how to do iterative self-training + Kaldi LM-decoding. *** Note: these instructions are a work in progress and will be updated over the next few days From 78e75fa3edf4a4ce02f9aa59ded01d814036dc81 Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Fri, 21 May 2021 16:17:21 -0700 Subject: [PATCH 341/774] attempt to make non-sharded FSDP checkpoint behave like regular checkpoint Summary: overall just wondering if feature is desirable. if it is, the next diff which supports loading sharded checkpoint into a consolidated state dict cleaner. a couple advantages 1. allows resuming from other DDP trainers. 2. allows resuming into other DDP trainers. or FSDP of a different configuration. 3. none-sharded FSDP checkpoint can be loaded with regular load_model_ensemble_and_task() For old training workflow that's not using `--use-sharded-state`, please rename the checkpoint to remove the "-shard0" for resuming training. Reviewed By: sshleifer Differential Revision: D28563032 fbshipit-source-id: ced72bed969319ab6306059721f56e29b2c3d892 --- fairseq/checkpoint_utils.py | 2 + fairseq/trainer.py | 103 ++++++++++++++++++++++++------------ 2 files changed, 71 insertions(+), 34 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index ac6c7339d4..23677be83d 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -45,6 +45,8 @@ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): trainer.consolidate_optimizer() # TODO(SS): do we need this if no_save_optimizer_state if not trainer.should_save_checkpoint_on_current_rank: + if trainer.always_call_state_dict_during_save_checkpoint: + trainer.state_dict() return write_timer = meters.StopwatchMeter() diff --git a/fairseq/trainer.py b/fairseq/trainer.py index dc06928dfc..d3da876c29 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -24,9 +24,7 @@ from fairseq.logging import meters, metrics from fairseq.nan_detector import NanDetector from fairseq.optim import lr_scheduler - from omegaconf import OmegaConf -import re logger = logging.getLogger(__name__) @@ -185,8 +183,7 @@ def is_data_parallel_master(self): @property def use_distributed_wrapper(self) -> bool: return ( - self.data_parallel_world_size > 1 - and not self.cfg.optimization.use_bmuf + self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf ) or ( self.cfg.distributed_training.ddp_backend == "fully_sharded" and self.cfg.distributed_training.cpu_offload @@ -195,26 +192,42 @@ def use_distributed_wrapper(self) -> bool: @property def should_save_checkpoint_on_current_rank(self) -> bool: """Indicates whether to save checkpoints on the current DDP rank.""" - if self.cfg.distributed_training.ddp_backend == "fully_sharded" or getattr(self.cfg.model, "base_layers", 0) > 0: + if ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and self.cfg.distributed_training.use_sharded_state + ) or getattr(self.cfg.model, "base_layers", 0) > 0: return True else: return self.is_data_parallel_master + @property + def always_call_state_dict_during_save_checkpoint(self) -> bool: + if ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and not self.cfg.distributed_training.use_sharded_state + ): + # FSDP calls communication collective when consolidating checkpoints + return True + else: + return False + @property def checkpoint_suffix(self) -> str: """Suffix to add to the checkpoint file name.""" - if self.cfg.distributed_training.ddp_backend == "fully_sharded": - return self.cfg.checkpoint.checkpoint_suffix + "-shard{0}".format(self.data_parallel_rank) + if ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and self.cfg.distributed_training.use_sharded_state + ): + return self.cfg.checkpoint.checkpoint_suffix + "-shard{0}".format( + self.data_parallel_rank + ) else: return self.cfg.checkpoint.checkpoint_suffix or "" @property def criterion(self): if self._wrapped_criterion is None: - if ( - utils.has_parameters(self._criterion) - and self.use_distributed_wrapper - ): + if utils.has_parameters(self._criterion) and self.use_distributed_wrapper: self._wrapped_criterion = models.DistributedFairseqModel( self.cfg.distributed_training, self._criterion, @@ -293,8 +306,9 @@ def _build_optimizer(self): self._optimizer = optim.build_optimizer(self.cfg.optimizer, params) if self.cfg.distributed_training.ddp_backend == "fully_sharded": - assert not self.cfg.optimization.use_bmuf, \ - "--ddp-backend=fully_sharded is not compatible with BMUF" + assert ( + not self.cfg.optimization.use_bmuf + ), "--ddp-backend=fully_sharded is not compatible with BMUF" assert self._optimizer.supports_flat_params, ( "--ddp-backend=fully_sharded is only compatible with pointwise " "optimizers (e.g., Adam, AdamW, Adadelta, Adamax, SGD, etc.). " @@ -337,10 +351,13 @@ def consolidate_optimizer(self): if hasattr(self.optimizer.optimizer, "consolidate_state_dict"): self.optimizer.optimizer.consolidate_state_dict() - elif self.cfg.distributed_training.ddp_backend == 'fully_sharded' and not self.model.use_sharded_state: - st = self.model.gather_full_optim_state_dict(self.optimizer) # only returns on rank 0 - if st is None: - st = -1 # sentinel so that workers do not save optimizer.state_dict() + elif ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and not self.model.use_sharded_state + ): + st = self.model.gather_full_optim_state_dict( + self.optimizer + ) # only returns on rank 0 self._gathered_optim_state = st def state_dict(self): @@ -348,12 +365,14 @@ def state_dict(self): "args": None, # legacy "cfg": ( OmegaConf.to_container(self.cfg) - if OmegaConf.is_config(self.cfg) else self.cfg + if OmegaConf.is_config(self.cfg) + else self.cfg ), "model": self.model.state_dict(), "criterion": ( self.criterion.state_dict() - if utils.has_parameters(self.criterion) else None + if utils.has_parameters(self.criterion) + else None ), "optimizer_history": (self._optim_history or []) + [ @@ -368,7 +387,7 @@ def state_dict(self): "extra_state": { "metrics": metrics.state_dict(), "previous_training_time": self.cumulative_training_time(), - } + }, } if not self.cfg.checkpoint.no_save_optimizer_state: if self._gathered_optim_state is not None: @@ -417,7 +436,10 @@ def load_checkpoint( # on every worker for now or self.tpu # FSDP requires loading checkpoint shards on all ranks - or self.cfg.distributed_training.ddp_backend == "fully_sharded" + or ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and self.cfg.distributed_training.use_sharded_state + ) or getattr(self.cfg.model, "base_layers", 0) > 0 ) @@ -426,10 +448,6 @@ def load_checkpoint( filename, load_on_all_ranks=load_on_all_ranks ) last_optim_state = state.get("last_optimizer_state", None) - if last_optim_state == -1: - master_path = re.sub("shard[0-9]+", "shard0", filename) - local_master_path = PathManager.get_local_path(master_path) - last_optim_state = torch.load(local_master_path, map_location='cpu')['last_optimizer_state'] # If doing zero_sharding, do not broadcast global optimizer # state. Later we will broadcast sharded states to each rank @@ -492,13 +510,18 @@ def load_checkpoint( if not reset_lr_scheduler: self.lr_scheduler.load_state_dict(last_optim["lr_scheduler_state"]) - if not load_on_all_ranks and is_distributed: + if ( + self.cfg.distributed_training.ddp_backend == "fully_sharded" + and not self.model.use_sharded_state + ): + # if use_sharded_state, the last_optim_state is already sharded, skip this + last_optim_state = self.model.get_shard_from_optim_state_dict( + last_optim_state + ) + elif not load_on_all_ranks and is_distributed: last_optim_state = self.optimizer.broadcast_global_state_dict( last_optim_state ) - elif self.cfg.distributed_training.ddp_backend == 'fully_sharded' and not self.model.use_sharded_state: - # if use_sharded_state, the last_optim_state is already sharded, skip this - last_optim_state = self.model.get_shard_from_optim_state_dict(last_optim_state) self.optimizer.load_state_dict(last_optim_state, optimizer_overrides) @@ -514,7 +537,10 @@ def load_checkpoint( self.lr_step(epoch) - if itr_state.get("version", 1) >= 2 and itr_state["iterations_in_epoch"] == 0: + if ( + itr_state.get("version", 1) >= 2 + and itr_state["iterations_in_epoch"] == 0 + ): # reset meters at start of epoch reset_meters = True @@ -801,7 +827,9 @@ def maybe_no_sync(): raise except OverflowError as e: overflow = True - logger.info(f"NOTE: gradient overflow detected, ignoring gradient, {str(e)}") + logger.info( + f"NOTE: gradient overflow detected, ignoring gradient, {str(e)}" + ) grad_norm = torch.tensor(0.0).cuda() self.zero_grad() except RuntimeError as e: @@ -846,7 +874,9 @@ def maybe_no_sync(): metrics.log_scalar( "gb_total", gb_total, priority=1600, round=1, weight=0 ) - logging_outputs = self._xla_markstep_and_send_to_cpu(logging_outputs) + logging_outputs = self._xla_markstep_and_send_to_cpu( + logging_outputs + ) logging_output = self._reduce_and_log_stats( logging_outputs, sample_size, grad_norm ) @@ -899,6 +929,7 @@ def valid_step(self, sample, raise_oom=False): """Do forward pass in evaluation mode.""" if self.tpu: import torch_xla.core.xla_model as xm + xm.rendezvous("valid_step") # wait for all workers with torch.no_grad(): @@ -1040,7 +1071,6 @@ def set_num_updates(self, num_updates): metrics.log_scalar("num_updates", self._num_updates, weight=0, priority=200) def clip_grad_norm(self, clip_norm): - def agg_norm_fn(total_norm): total_norm = total_norm.cuda().float() ** 2 total_norm = distributed_utils.all_reduce( @@ -1190,7 +1220,10 @@ def _all_gather_list_sync( return logging_outputs, extra_stats_to_sum def _fast_stat_sync_sum( - self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, + self, + logging_outputs: List[Dict[str, Any]], + *extra_stats_to_sum, + ignore=False, ): """ Sync logging outputs across workers. fast_stat_sync_sum is @@ -1323,9 +1356,11 @@ def _check_xla_compilation(self): def _xla_markstep_and_send_to_cpu(self, data=None): import torch_xla.core.xla_model as xm + xm.mark_step() if data is not None: from fairseq.utils import xla_device_to_cpu + return xla_device_to_cpu(data) From 4aef9036cef814a24193dff3a678ce0f5c27309f Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushall@fb.com> Date: Fri, 21 May 2021 18:40:01 -0700 Subject: [PATCH 342/774] Merge Hubert to master (#1877) Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ X] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ X] Did you make sure to update the docs? - [ X] Did you write any new necessary tests? ## What does this PR do? This PR adds relevant code for pre-training HuBERT and fine-tuning a pretrained HuBERT for ASR. It also shared trained models of different sizes. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1877 Reviewed By: wnhsu Differential Revision: D28513359 Pulled By: hikushalhere fbshipit-source-id: 8755862f236b7d840105b0fa8f5461ac053d79cc --- examples/hubert/README.md | 108 ++++ .../hubert/config/decode/ax_sweep/ngram.yaml | 33 + .../config/decode/ax_sweep/transformer.yaml | 33 + .../hubert/config/decode/infer_fsqlm.yaml | 41 ++ .../hubert/config/decode/infer_kenlm.yaml | 41 ++ .../hubert/config/decode/infer_viterbi.yaml | 34 ++ .../config/decode/run/submitit_slurm.yaml | 17 + .../decode/run/submitit_slurm_8gpu.yaml | 17 + examples/hubert/config/finetune/base_10h.yaml | 99 +++ examples/hubert/config/finetune/ckpt/it1.yaml | 7 + .../hubert/config/finetune/lm/ls_4gram.yaml | 7 + .../config/finetune/run/submitit_reg.yaml | 20 + .../hubert/config/pretrain/data/iter1.yaml | 8 + .../hubert/config/pretrain/data/iter2.yaml | 8 + .../pretrain/hubert_base_librispeech.yaml | 97 +++ .../pretrain/hubert_large_librivox.yaml | 101 ++++ .../pretrain/hubert_xlarge_librivox.yaml | 101 ++++ .../config/pretrain/run/submitit_reg.yaml | 20 + examples/hubert/measure_teacher_quality.py | 241 ++++++++ examples/hubert/simple_kmeans/README.md | 71 +++ .../simple_kmeans/dump_hubert_feature.py | 133 +++++ .../simple_kmeans/dump_hubert_feature_s2t.py | 126 ++++ .../hubert/simple_kmeans/dump_km_label.py | 98 +++ .../hubert/simple_kmeans/dump_mfcc_feature.py | 116 ++++ examples/hubert/simple_kmeans/learn_kmeans.py | 146 +++++ examples/hubert/update_ckpt.py | 22 + fairseq/criterions/hubert_criterion.py | 177 ++++++ fairseq/data/__init__.py | 9 +- fairseq/data/audio/hubert_dataset.py | 358 +++++++++++ fairseq/distributed/utils.py | 2 +- fairseq/models/hubert/__init__.py | 7 + fairseq/models/hubert/hubert.py | 563 ++++++++++++++++++ fairseq/models/hubert/hubert_asr.py | 373 ++++++++++++ fairseq/tasks/hubert_pretraining.py | 189 ++++++ 34 files changed, 3419 insertions(+), 4 deletions(-) create mode 100644 examples/hubert/README.md create mode 100644 examples/hubert/config/decode/ax_sweep/ngram.yaml create mode 100644 examples/hubert/config/decode/ax_sweep/transformer.yaml create mode 100644 examples/hubert/config/decode/infer_fsqlm.yaml create mode 100644 examples/hubert/config/decode/infer_kenlm.yaml create mode 100644 examples/hubert/config/decode/infer_viterbi.yaml create mode 100644 examples/hubert/config/decode/run/submitit_slurm.yaml create mode 100644 examples/hubert/config/decode/run/submitit_slurm_8gpu.yaml create mode 100644 examples/hubert/config/finetune/base_10h.yaml create mode 100644 examples/hubert/config/finetune/ckpt/it1.yaml create mode 100644 examples/hubert/config/finetune/lm/ls_4gram.yaml create mode 100644 examples/hubert/config/finetune/run/submitit_reg.yaml create mode 100644 examples/hubert/config/pretrain/data/iter1.yaml create mode 100644 examples/hubert/config/pretrain/data/iter2.yaml create mode 100644 examples/hubert/config/pretrain/hubert_base_librispeech.yaml create mode 100644 examples/hubert/config/pretrain/hubert_large_librivox.yaml create mode 100644 examples/hubert/config/pretrain/hubert_xlarge_librivox.yaml create mode 100644 examples/hubert/config/pretrain/run/submitit_reg.yaml create mode 100644 examples/hubert/measure_teacher_quality.py create mode 100644 examples/hubert/simple_kmeans/README.md create mode 100644 examples/hubert/simple_kmeans/dump_hubert_feature.py create mode 100644 examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py create mode 100644 examples/hubert/simple_kmeans/dump_km_label.py create mode 100644 examples/hubert/simple_kmeans/dump_mfcc_feature.py create mode 100644 examples/hubert/simple_kmeans/learn_kmeans.py create mode 100644 examples/hubert/update_ckpt.py create mode 100644 fairseq/criterions/hubert_criterion.py create mode 100644 fairseq/data/audio/hubert_dataset.py create mode 100644 fairseq/models/hubert/__init__.py create mode 100644 fairseq/models/hubert/hubert.py create mode 100644 fairseq/models/hubert/hubert_asr.py create mode 100644 fairseq/tasks/hubert_pretraining.py diff --git a/examples/hubert/README.md b/examples/hubert/README.md new file mode 100644 index 0000000000..88973c22f2 --- /dev/null +++ b/examples/hubert/README.md @@ -0,0 +1,108 @@ +# HuBERT + +## Pre-trained and fine-tuned (ASR) models +Model | Pretraining Data | Finetuning Dataset | Model +|---|---|---|--- +HuBERT Base | [Librispeech](http://www.openslr.org/12) 960 hr | No finetuning | [download](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) +HuBERT Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k.pt) +HuBERT Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k_finetune_ls960.pt) +HuBERT Extra Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k.pt) +HuBERT Extra Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k_finetune_ls960.pt) + +## Train a new model + +### Data preparation + +Follow the steps in `./simple_kmeans` to create: +- `{train,valid}.tsv` waveform list files +- `{train,valid}.km` frame-aligned pseudo label files. +The `label_rate` is the same as the feature frame rate used for clustering, +which is 100Hz for MFCC features and 50Hz for HuBERT features by default. + +### Pre-train a HuBERT model + +Suppose `{train,valid}.tsv` are saved at `/path/to/data`, `{train,valid}.km` +are saved at `/path/to/labels`, and the label rate is 100Hz. + +To train a base model (12 layer transformer), run: +```sh +$ python fairseq_cli/hydra_train.py \ + --config-dir /path/to/fairseq-py/examples/hubert/config/pretrain \ + --config-name hubert_base_librispeech \ + task.data=/path/to/data task.label_dir=/path/to/labels model.label_rate=100 +``` + +### Fine-tune a HuBERT model with a CTC loss + +Suppose `{train,valid}.tsv` are saved at `/path/to/data`, and their +corresponding character transcripts `{train,valid}.ltr` are saved at +`/path/to/trans`. + +To fine-tune a pre-trained HuBERT model at `/path/to/checkpoint`, run +```sh +$ python fairseq_cli/hydra_train.py \ + --config-dir /path/to/fairseq-py/examples/hubert/config/finetune \ + --config-name base_10h \ + task.data=/path/to/data task.label_dir=/path/to/trans \ + model.w2v_path=/path/to/checkpoint +``` + +### Decode a HuBERT model + +Suppose the `test.tsv` and `test.ltr` are the waveform list and transcripts of +the split to be decoded, saved at `/path/to/data`, and the fine-tuned model is +saved at `/path/to/checkpoint`. We support three decoding modes: +- Viterbi decoding: greedy decoding without a language model +- KenLM decoding: decoding with an arpa-format KenLM n-gram language model +- Fairseq-LM deocding: decoding with a Fairseq neural language model + + +#### Viterbi decoding + +`task.normalize` needs to be consistent with the value used during fine-tuning. +Decoding results will be saved at +`/path/to/experiment/directory/decode/viterbi/test`. + +```sh +$ python examples/speech_recognition/hydra/infer.py \ + --config-dir /path/to/fairseq-py/examples/hubert/config/decode \ + --config-name infer_viterbi \ + task.data=/path/to/data \ + task.normalize=[true|false] \ + decoding.exp_dir=/path/to/experiment/directory \ + common_eval.path=/path/to/checkpoint + dataset.gen_subset=test \ +``` + +#### KenLM / Fairseq-LM decoding + +Suppose the pronunciation lexicon and the n-gram LM are saved at +`/path/to/lexicon` and `/path/to/arpa`, respectively. Decoding results will be +saved at `/path/to/experiment/directory/decode/kenlm/test`. + +```sh +$ python examples/speech_recognition/hydra/infer.py \ + --config-dir /path/to/fairseq-py/examples/hubert/config/decode \ + --config-name infer_kenlm \ + task.data=/path/to/data \ + task.normalize=[true|false] \ + decoding.exp_dir=/path/to/experiment/directory \ + common_eval.path=/path/to/checkpoint + dataset.gen_subset=test \ + decoding.decoder.lexicon=/path/to/lexicon \ + decoding.decoder.lmpath=/path/to/arpa +``` + +The command above uses the default decoding hyperparameter, which can be found +in `examples/speech_recognition/hydra/decoder.py`. These parameters can be +configured from the command line. For example, to search with a beam size of +500, we can append the command above with `decoding.decoder.beam=500`. +Important parameters include: +- decoding.decoder.beam +- decoding.decoder.beamthreshold +- decoding.decoder.lmweight +- decoding.decoder.wordscore +- decoding.decoder.silweight + +To decode with a Fairseq LM, use `--config-name infer_fsqlm` instead, and +change the path of lexicon and LM accordingly. diff --git a/examples/hubert/config/decode/ax_sweep/ngram.yaml b/examples/hubert/config/decode/ax_sweep/ngram.yaml new file mode 100644 index 0000000000..5a02df1f7d --- /dev/null +++ b/examples/hubert/config/decode/ax_sweep/ngram.yaml @@ -0,0 +1,33 @@ +# @package _global_ + +common_eval: + results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}_ax/${dataset.gen_subset} + +hydra: + sweeper: + ax_config: + max_trials: 60 + early_stop: + minimize: true + max_epochs_without_improvement: 10 + epsilon: 0.025 + experiment: + name: ${dataset.gen_subset} + objective_name: wer + minimize: true + parameter_constraints: null + outcome_constraints: null + status_quo: null + client: + verbose_logging: false + random_seed: null + params: + decoding.decoder.lmweight: + type: range + bounds: [0.0, 8.0] + decoding.decoder.wordscore: + type: range + bounds: [-5.0, 5.0] + decoding.decoder.silweight: + type: range + bounds: [-10.0, 0.0] diff --git a/examples/hubert/config/decode/ax_sweep/transformer.yaml b/examples/hubert/config/decode/ax_sweep/transformer.yaml new file mode 100644 index 0000000000..85ed3bd1a5 --- /dev/null +++ b/examples/hubert/config/decode/ax_sweep/transformer.yaml @@ -0,0 +1,33 @@ +# @package _global_ + +common_eval: + results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}_ax/${dataset.gen_subset} + +hydra: + sweeper: + ax_config: + max_trials: 60 + early_stop: + minimize: true + max_epochs_without_improvement: 10 + epsilon: 0.025 + experiment: + name: ${dataset.gen_subset} + objective_name: wer + minimize: true + parameter_constraints: null + outcome_constraints: null + status_quo: null + client: + verbose_logging: false + random_seed: null + params: + decoding.decoder.lmweight: + type: range + bounds: [0.0, 4.0] + decoding.decoder.wordscore: + type: range + bounds: [-5.0, 5.0] + decoding.decoder.silweight: + type: range + bounds: [-8.0, 0.0] diff --git a/examples/hubert/config/decode/infer_fsqlm.yaml b/examples/hubert/config/decode/infer_fsqlm.yaml new file mode 100644 index 0000000000..b9fb845066 --- /dev/null +++ b/examples/hubert/config/decode/infer_fsqlm.yaml @@ -0,0 +1,41 @@ +# @package _group_ + +defaults: + - model: null + +hydra: + run: + dir: ${common_eval.results_path}/beam${decoding.decoder.beam}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + sweep: + dir: ${common_eval.results_path} + subdir: beam${decoding.decoder.beam}_th${decoding.decoder.beamthreshold}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + +task: + _name: hubert_pretraining + single_target: true + data: ??? + normalize: ??? + +decoding: + exp_dir: ??? + decoder: + name: fairseqlm + lexicon: ??? + lmpath: ??? + beamthreshold: 25 # 100 + beam: 500 + lmweight: 2 + wordscore: -1 + silweight: 0 + write_sentences: true + unique_wer_file: true +common_eval: + results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}/${dataset.gen_subset} + path: ??? + post_process: letter +generation: + nbest: 1 + beam: 500 +dataset: + max_tokens: 1100000 + gen_subset: ??? diff --git a/examples/hubert/config/decode/infer_kenlm.yaml b/examples/hubert/config/decode/infer_kenlm.yaml new file mode 100644 index 0000000000..fe464eaae5 --- /dev/null +++ b/examples/hubert/config/decode/infer_kenlm.yaml @@ -0,0 +1,41 @@ +# @package _group_ + +defaults: + - model: null + +hydra: + run: + dir: ${common_eval.results_path}/beam${decoding.decoder.beam}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + sweep: + dir: ${common_eval.results_path} + subdir: beam${decoding.decoder.beam}_th${decoding.decoder.beamthreshold}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + +task: + _name: hubert_pretraining + single_target: true + data: ??? + normalize: ??? + +decoding: + exp_dir: ??? + decoder: + name: kenlm + lexicon: ??? + lmpath: ??? + beamthreshold: 100 + beam: 500 + lmweight: 2 + wordscore: -1 + silweight: 0 + write_sentences: true + unique_wer_file: true +common_eval: + results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}/${dataset.gen_subset} + path: ??? + post_process: letter +generation: + nbest: 1 + beam: 500 +dataset: + max_tokens: 1100000 + gen_subset: ??? diff --git a/examples/hubert/config/decode/infer_viterbi.yaml b/examples/hubert/config/decode/infer_viterbi.yaml new file mode 100644 index 0000000000..d0de9cfd26 --- /dev/null +++ b/examples/hubert/config/decode/infer_viterbi.yaml @@ -0,0 +1,34 @@ +# @package _group_ + +defaults: + - model: null + +hydra: + run: + dir: ${common_eval.results_path}/beam${decoding.decoder.beam}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + sweep: + dir: ${common_eval.results_path} + subdir: beam${decoding.decoder.beam}_th${decoding.decoder.beamthreshold}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + +task: + _name: hubert_pretraining + single_target: true + data: ??? + normalize: ??? + +decoding: + exp_dir: ??? + decoder: + name: viterbi + write_sentences: true + unique_wer_file: true +common_eval: + results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}/${dataset.gen_subset} + path: ??? + post_process: letter +generation: + nbest: 1 + beam: 500 +dataset: + max_tokens: 1100000 + gen_subset: ??? diff --git a/examples/hubert/config/decode/run/submitit_slurm.yaml b/examples/hubert/config/decode/run/submitit_slurm.yaml new file mode 100644 index 0000000000..0b8065832e --- /dev/null +++ b/examples/hubert/config/decode/run/submitit_slurm.yaml @@ -0,0 +1,17 @@ +# @package _global_ +hydra: + launcher: + cpus_per_task: ${distributed_training.distributed_world_size} + gpus_per_node: ${distributed_training.distributed_world_size} + tasks_per_node: ${hydra.launcher.gpus_per_node} + nodes: 1 + mem_gb: 200 + timeout_min: 4320 + max_num_timeout: 50 + name: ${hydra.job.config_name} + submitit_folder: ${hydra.sweep.dir}/submitit + +distributed_training: + distributed_world_size: 1 + distributed_no_spawn: true + distributed_port: 29761 diff --git a/examples/hubert/config/decode/run/submitit_slurm_8gpu.yaml b/examples/hubert/config/decode/run/submitit_slurm_8gpu.yaml new file mode 100644 index 0000000000..2f669f3763 --- /dev/null +++ b/examples/hubert/config/decode/run/submitit_slurm_8gpu.yaml @@ -0,0 +1,17 @@ +# @package _global_ +hydra: + launcher: + cpus_per_task: ${distributed_training.distributed_world_size} + gpus_per_node: ${distributed_training.distributed_world_size} + tasks_per_node: ${hydra.launcher.gpus_per_node} + nodes: 1 + mem_gb: 200 + timeout_min: 4320 + max_num_timeout: 50 + name: ${hydra.job.config_name} + submitit_folder: ${hydra.sweep.dir}/submitit + +distributed_training: + distributed_world_size: 8 + distributed_no_spawn: true + distributed_port: 29761 diff --git a/examples/hubert/config/finetune/base_10h.yaml b/examples/hubert/config/finetune/base_10h.yaml new file mode 100644 index 0000000000..844484d7fb --- /dev/null +++ b/examples/hubert/config/finetune/base_10h.yaml @@ -0,0 +1,99 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tblog + seed: 1337 + +checkpoint: + save_interval: 5 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +distributed_training: + ddp_backend: c10d + find_unused_parameters: true + distributed_world_size: 1 + distributed_port: 29671 + nprocs_per_node: 8 + +task: + _name: hubert_pretraining + data: ??? + label_dir: ??? + normalize: false # must be consistent with pre-training + labels: ["ltr"] + single_target: true + +dataset: + num_workers: 0 + max_tokens: 3200000 + validate_after_updates: ${model.freeze_finetune_updates} + validate_interval: 5 + train_subset: train + valid_subset: valid + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 25000 + lr: [2e-5] + sentence_avg: true + update_freq: [1] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 72000 + final_lr_scale: 0.05 + +model: + _name: hubert_ctc + w2v_path: ??? + apply_mask: true + mask_selection: static + mask_length: 10 + mask_other: 0 + mask_prob: 0.75 + mask_channel_selection: static + mask_channel_length: 64 + mask_channel_other: 0 + mask_channel_prob: 0.5 + layerdrop: 0.1 + dropout: 0.0 + activation_dropout: 0.1 + attention_dropout: 0.0 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + - model.w2v_path + - dataset.train_subset + - dataset.valid_subset + - criterion.wer_kenlm_model + - criterion.wer_lexicon + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/hubert/config/finetune/ckpt/it1.yaml b/examples/hubert/config/finetune/ckpt/it1.yaml new file mode 100644 index 0000000000..2af96b3f72 --- /dev/null +++ b/examples/hubert/config/finetune/ckpt/it1.yaml @@ -0,0 +1,7 @@ +# @package _global_ + +task: + normalize: false + +model: + w2v_path: /checkpoint/wnhsu/w2v/hubert_final/iter1/hubert.km.randcrop.pmw1_0.puw0_0.grpnorm.ml10.mp0_8.untie.mxsz250000.ufreq1.maxtok1400000.MU400k.s1337.ngpu32/checkpoint_last.pt diff --git a/examples/hubert/config/finetune/lm/ls_4gram.yaml b/examples/hubert/config/finetune/lm/ls_4gram.yaml new file mode 100644 index 0000000000..8c7728ad29 --- /dev/null +++ b/examples/hubert/config/finetune/lm/ls_4gram.yaml @@ -0,0 +1,7 @@ +# @package _global_ + +criterion: + wer_kenlm_model: /checkpoint/abdo/old_checkpoint02/datasets/librispeech/4-gram.bin + wer_lexicon: /checkpoint/abdo/old_checkpoint02/datasets/librispeech/10h/raw/lexicon_ltr.lst + wer_lm_weight: 2.0 + wer_word_score: -1.0 diff --git a/examples/hubert/config/finetune/run/submitit_reg.yaml b/examples/hubert/config/finetune/run/submitit_reg.yaml new file mode 100644 index 0000000000..27509503e7 --- /dev/null +++ b/examples/hubert/config/finetune/run/submitit_reg.yaml @@ -0,0 +1,20 @@ +# @package _global_ + +hydra: + launcher: + cpus_per_task: 8 + gpus_per_node: 8 + tasks_per_node: ${hydra.launcher.gpus_per_node} + nodes: 1 + comment: null + mem_gb: 384 + timeout_min: 4320 + max_num_timeout: 100 + constraint: volta32gb + name: ${hydra.job.config_name}/${hydra.job.override_dirname} + submitit_folder: ${hydra.sweep.dir}/submitit/%j + +distributed_training: + distributed_world_size: 8 + distributed_port: 29671 + nprocs_per_node: 8 diff --git a/examples/hubert/config/pretrain/data/iter1.yaml b/examples/hubert/config/pretrain/data/iter1.yaml new file mode 100644 index 0000000000..0a1b65d802 --- /dev/null +++ b/examples/hubert/config/pretrain/data/iter1.yaml @@ -0,0 +1,8 @@ +# @package _global_ + +task: + label_dir: ??? + labels: ["km"] + +model: + label_rate: 100 diff --git a/examples/hubert/config/pretrain/data/iter2.yaml b/examples/hubert/config/pretrain/data/iter2.yaml new file mode 100644 index 0000000000..2d4bfe61cc --- /dev/null +++ b/examples/hubert/config/pretrain/data/iter2.yaml @@ -0,0 +1,8 @@ +# @package _global_ + +task: + label_dir: ??? + labels: ["km"] + +model: + label_rate: 50 diff --git a/examples/hubert/config/pretrain/hubert_base_librispeech.yaml b/examples/hubert/config/pretrain/hubert_base_librispeech.yaml new file mode 100644 index 0000000000..bd84461a16 --- /dev/null +++ b/examples/hubert/config/pretrain/hubert_base_librispeech.yaml @@ -0,0 +1,97 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + seed: 1337 + tensorboard_logdir: tblog + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + + +distributed_training: + ddp_backend: no_c10d + distributed_backend: 'nccl' + distributed_world_size: 32 + distributed_port: 29671 + nprocs_per_node: 8 + find_unused_parameters: true + +task: + _name: hubert_pretraining + data: ??? + label_dir: ??? + labels: ??? + label_rate: ${model.label_rate} + sample_rate: 16000 + max_sample_size: 250000 + min_sample_size: 32000 + pad_audio: false + random_crop: true + normalize: false # must be consistent with extractor + +dataset: + num_workers: 6 + max_tokens: 1400000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + validate_interval_updates: 10000 + +criterion: + _name: hubert + pred_masked_weight: 1.0 + pred_nomask_weight: 0.0 + loss_weights: [10,] + +optimization: + max_update: 400000 + lr: [0.0005] + clip_norm: 10.0 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: hubert + label_rate: ??? + skip_masked: false + skip_nomask: false + mask_prob: 0.80 + extractor_mode: default + conv_feature_layers: '[(512,10,5)] + [(512,3,2)] * 4 + [(512,2,2)] * 2' + final_dim: 256 + encoder_layerdrop: 0.05 + dropout_input: 0.1 + dropout_features: 0.1 + dropout: 0.1 + attention_dropout: 0.1 + feature_grad_mult: 0.1 + untie_final_proj: true + activation_dropout: 0.0 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/hubert/config/pretrain/hubert_large_librivox.yaml b/examples/hubert/config/pretrain/hubert_large_librivox.yaml new file mode 100644 index 0000000000..a5192b5f29 --- /dev/null +++ b/examples/hubert/config/pretrain/hubert_large_librivox.yaml @@ -0,0 +1,101 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + seed: 1337 + tensorboard_logdir: tblog + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + + +distributed_training: + ddp_backend: no_c10d + distributed_backend: 'nccl' + distributed_world_size: 128 + distributed_port: 29671 + nprocs_per_node: 8 + find_unused_parameters: true + +task: + _name: hubert_pretraining + data: ??? + label_dir: ??? + labels: ??? + label_rate: ${model.label_rate} + sample_rate: 16000 + max_sample_size: 250000 + min_sample_size: 32000 + pad_audio: false + random_crop: true + normalize: true # must be consistent with extractor + +dataset: + num_workers: 6 + max_tokens: 900000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + validate_interval_updates: 10000 + +criterion: + _name: hubert + pred_masked_weight: 1.0 + pred_nomask_weight: 0.0 + loss_weights: [10,] + +optimization: + max_update: 400000 + lr: [0.0015] + clip_norm: 1.0 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: hubert + label_rate: ??? + encoder_layers: 24 + encoder_embed_dim: 1024 + encoder_ffn_embed_dim: 4096 + encoder_attention_heads: 16 + final_dim: 768 + skip_masked: false + skip_nomask: false + mask_prob: 0.80 + extractor_mode: layer_norm + conv_feature_layers: '[(512,10,5)] + [(512,3,2)] * 4 + [(512,2,2)] * 2' + encoder_layerdrop: 0.0 + dropout_input: 0.0 + dropout_features: 0.0 + dropout: 0.0 + attention_dropout: 0.0 + layer_norm_first: true + feature_grad_mult: 1.0 + untie_final_proj: true + activation_dropout: 0.0 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + run: + dir: /checkpoint/wnhsu/w2v/hubert_final/hydra_pt + sweep: + dir: /checkpoint/wnhsu/w2v/hubert_final/hydra_pt + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/hubert/config/pretrain/hubert_xlarge_librivox.yaml b/examples/hubert/config/pretrain/hubert_xlarge_librivox.yaml new file mode 100644 index 0000000000..34e8f2bfb9 --- /dev/null +++ b/examples/hubert/config/pretrain/hubert_xlarge_librivox.yaml @@ -0,0 +1,101 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + seed: 1337 + tensorboard_logdir: tblog + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + + +distributed_training: + ddp_backend: no_c10d + distributed_backend: 'nccl' + distributed_world_size: 256 + distributed_port: 29671 + nprocs_per_node: 8 + find_unused_parameters: true + +task: + _name: hubert_pretraining + data: ??? + label_dir: ??? + labels: ??? + label_rate: ${model.label_rate} + sample_rate: 16000 + max_sample_size: 250000 + min_sample_size: 32000 + pad_audio: false + random_crop: true + normalize: true # must be consistent with extractor + +dataset: + num_workers: 6 + max_tokens: 360000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + validate_interval_updates: 10000 + +criterion: + _name: hubert + pred_masked_weight: 1.0 + pred_nomask_weight: 0.0 + loss_weights: [10,] + +optimization: + max_update: 400000 + lr: [0.003] + clip_norm: 1.0 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: hubert + label_rate: ??? + encoder_layers: 48 + encoder_embed_dim: 1280 + encoder_ffn_embed_dim: 5120 + encoder_attention_heads: 16 + final_dim: 1024 + skip_masked: false + skip_nomask: false + mask_prob: 0.80 + extractor_mode: layer_norm + conv_feature_layers: '[(512,10,5)] + [(512,3,2)] * 4 + [(512,2,2)] * 2' + encoder_layerdrop: 0.0 + dropout_input: 0.0 + dropout_features: 0.0 + dropout: 0.0 + attention_dropout: 0.0 + layer_norm_first: true + feature_grad_mult: 1.0 + untie_final_proj: true + activation_dropout: 0.0 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + run: + dir: /checkpoint/wnhsu/w2v/hubert_final/hydra_pt + sweep: + dir: /checkpoint/wnhsu/w2v/hubert_final/hydra_pt + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/hubert/config/pretrain/run/submitit_reg.yaml b/examples/hubert/config/pretrain/run/submitit_reg.yaml new file mode 100644 index 0000000000..46c979cd28 --- /dev/null +++ b/examples/hubert/config/pretrain/run/submitit_reg.yaml @@ -0,0 +1,20 @@ +# @package _global_ + +hydra: + launcher: + cpus_per_task: 8 + gpus_per_node: 8 + tasks_per_node: ${hydra.launcher.gpus_per_node} + nodes: 4 + comment: null + mem_gb: 384 + timeout_min: 4320 + max_num_timeout: 100 + constraint: volta32gb + name: ${hydra.job.config_name}/${hydra.job.override_dirname} + submitit_folder: ${hydra.sweep.dir}/submitit/%j + +distributed_training: + distributed_world_size: 32 + distributed_port: 29671 + nprocs_per_node: 8 diff --git a/examples/hubert/measure_teacher_quality.py b/examples/hubert/measure_teacher_quality.py new file mode 100644 index 0000000000..92279b2214 --- /dev/null +++ b/examples/hubert/measure_teacher_quality.py @@ -0,0 +1,241 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +import os.path as op +import re +from tabulate import tabulate +from collections import Counter + + +def comp_purity(p_xy, axis): + max_p = p_xy.max(axis=axis) + marg_p = p_xy.sum(axis=axis) + indv_pur = max_p / marg_p + aggr_pur = max_p.sum() + return indv_pur, aggr_pur + + +def comp_entropy(p): + return (-p * np.log(p + 1e-8)).sum() + + +def comp_norm_mutual_info(p_xy): + p_x = p_xy.sum(axis=1, keepdims=True) + p_y = p_xy.sum(axis=0, keepdims=True) + pmi = np.log(p_xy / np.matmul(p_x, p_y) + 1e-8) + mi = (p_xy * pmi).sum() + h_x = comp_entropy(p_x) + h_y = comp_entropy(p_y) + return mi, mi / h_x, mi / h_y, h_x, h_y + + +def pad(labs, n): + if n == 0: + return np.array(labs) + return np.concatenate([[labs[0]] * n, labs, [labs[-1]] * n]) + + +def comp_avg_seg_dur(labs_list): + n_frms = 0 + n_segs = 0 + for labs in labs_list: + labs = np.array(labs) + edges = np.zeros(len(labs)).astype(bool) + edges[0] = True + edges[1:] = labs[1:] != labs[:-1] + n_frms += len(edges) + n_segs += edges.astype(int).sum() + return n_frms / n_segs + + +def comp_joint_prob(uid2refs, uid2hyps): + """ + Args: + pad: padding for spliced-feature derived labels + """ + cnts = Counter() + skipped = [] + abs_frmdiff = 0 + for uid in uid2refs: + if uid not in uid2hyps: + skipped.append(uid) + continue + refs = uid2refs[uid] + hyps = uid2hyps[uid] + abs_frmdiff += abs(len(refs) - len(hyps)) + min_len = min(len(refs), len(hyps)) + refs = refs[:min_len] + hyps = hyps[:min_len] + cnts.update(zip(refs, hyps)) + tot = sum(cnts.values()) + + ref_set = sorted({ref for ref, _ in cnts.keys()}) + hyp_set = sorted({hyp for _, hyp in cnts.keys()}) + ref2pid = dict(zip(ref_set, range(len(ref_set)))) + hyp2lid = dict(zip(hyp_set, range(len(hyp_set)))) + # print(hyp_set) + p_xy = np.zeros((len(ref2pid), len(hyp2lid)), dtype=float) + for (ref, hyp), cnt in cnts.items(): + p_xy[ref2pid[ref], hyp2lid[hyp]] = cnt + p_xy /= p_xy.sum() + return p_xy, ref2pid, hyp2lid, tot, abs_frmdiff, skipped + + +def read_phn(tsv_path, rm_stress=True): + uid2phns = {} + with open(tsv_path) as f: + for line in f: + uid, phns = line.rstrip().split("\t") + phns = phns.split(",") + if rm_stress: + phns = [re.sub("[0-9]", "", phn) for phn in phns] + uid2phns[uid] = phns + return uid2phns + + +def read_lab(tsv_path, lab_path, pad_len=0, upsample=1): + """ + tsv is needed to retrieve the uids for the labels + """ + with open(tsv_path) as f: + f.readline() + uids = [op.splitext(op.basename(line.rstrip().split()[0]))[0] for line in f] + with open(lab_path) as f: + labs_list = [pad(line.rstrip().split(), pad_len).repeat(upsample) for line in f] + assert len(uids) == len(labs_list) + return dict(zip(uids, labs_list)) + + +def main_lab_lab( + tsv_dir, + lab_dir, + lab_name, + lab_sets, + ref_dir, + ref_name, + pad_len=0, + upsample=1, + verbose=False, +): + # assume tsv_dir is the same for both the reference and the hypotheses + tsv_dir = lab_dir if tsv_dir is None else tsv_dir + + uid2refs = {} + for s in lab_sets: + uid2refs.update(read_lab(f"{tsv_dir}/{s}.tsv", f"{ref_dir}/{s}.{ref_name}")) + + uid2hyps = {} + for s in lab_sets: + uid2hyps.update( + read_lab( + f"{tsv_dir}/{s}.tsv", f"{lab_dir}/{s}.{lab_name}", pad_len, upsample + ) + ) + _main(uid2refs, uid2hyps, verbose) + + +def main_phn_lab( + tsv_dir, + lab_dir, + lab_name, + lab_sets, + phn_dir, + phn_sets, + pad_len=0, + upsample=1, + verbose=False, +): + uid2refs = {} + for s in phn_sets: + uid2refs.update(read_phn(f"{phn_dir}/{s}.tsv")) + + uid2hyps = {} + tsv_dir = lab_dir if tsv_dir is None else tsv_dir + for s in lab_sets: + uid2hyps.update( + read_lab( + f"{tsv_dir}/{s}.tsv", f"{lab_dir}/{s}.{lab_name}", pad_len, upsample + ) + ) + _main(uid2refs, uid2hyps, verbose) + + +def _main(uid2refs, uid2hyps, verbose): + (p_xy, ref2pid, hyp2lid, tot, frmdiff, skipped) = comp_joint_prob( + uid2refs, uid2hyps + ) + ref_pur_by_hyp, ref_pur = comp_purity(p_xy, axis=0) + hyp_pur_by_ref, hyp_pur = comp_purity(p_xy, axis=1) + (mi, mi_norm_by_ref, mi_norm_by_hyp, h_ref, h_hyp) = comp_norm_mutual_info(p_xy) + outputs = { + "ref pur": ref_pur, + "hyp pur": hyp_pur, + "H(ref)": h_ref, + "H(hyp)": h_hyp, + "MI": mi, + "MI/H(ref)": mi_norm_by_ref, + "ref segL": comp_avg_seg_dur(uid2refs.values()), + "hyp segL": comp_avg_seg_dur(uid2hyps.values()), + "p_xy shape": p_xy.shape, + "frm tot": tot, + "frm diff": frmdiff, + "utt tot": len(uid2refs), + "utt miss": len(skipped), + } + print(tabulate([outputs.values()], outputs.keys(), floatfmt=".4f")) + + +if __name__ == "__main__": + """ + compute quality of labels with respect to phone or another labels if set + """ + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("tsv_dir") + parser.add_argument("lab_dir") + parser.add_argument("lab_name") + parser.add_argument("--lab_sets", default=["valid"], type=str, nargs="+") + parser.add_argument( + "--phn_dir", + default="/checkpoint/wnhsu/data/librispeech/960h/fa/raw_phn/phone_frame_align_v1", + ) + parser.add_argument( + "--phn_sets", default=["dev-clean", "dev-other"], type=str, nargs="+" + ) + parser.add_argument("--pad_len", default=0, type=int, help="padding for hypotheses") + parser.add_argument( + "--upsample", default=1, type=int, help="upsample factor for hypotheses" + ) + parser.add_argument("--ref_lab_dir", default="") + parser.add_argument("--ref_lab_name", default="") + parser.add_argument("--verbose", action="store_true") + args = parser.parse_args() + + if args.ref_lab_dir and args.ref_lab_name: + main_lab_lab( + args.tsv_dir, + args.lab_dir, + args.lab_name, + args.lab_sets, + args.ref_lab_dir, + args.ref_lab_name, + args.pad_len, + args.upsample, + args.verbose, + ) + else: + main_phn_lab( + args.tsv_dir, + args.lab_dir, + args.lab_name, + args.lab_sets, + args.phn_dir, + args.phn_sets, + args.pad_len, + args.upsample, + args.verbose, + ) diff --git a/examples/hubert/simple_kmeans/README.md b/examples/hubert/simple_kmeans/README.md new file mode 100644 index 0000000000..cd17da3b3e --- /dev/null +++ b/examples/hubert/simple_kmeans/README.md @@ -0,0 +1,71 @@ +# Sharded Feature Extraction and K-means Application + +This folder contains scripts for preparing HUBERT labels from tsv files, the +steps are: +1. feature extraction +2. k-means clustering +3. k-means application + + +## Data preparation + +`*.tsv` files contains a list of audio, where each line is the root, and +following lines are the subpath for each audio: +``` +<root-dir> +<audio-path-1> +<audio-path-2> +... +``` + + +## Feature extraction + +### MFCC feature +Suppose the tsv file is at `${tsv_dir}/${split}.tsv`. To extract 39-D +mfcc+delta+ddelta features for the 1st iteration HUBERT training, run: +```sh +python dump_mfcc_feature.py ${tsv_dir} ${split} ${nshard} ${rank} ${feat_dir} +``` +This would shard the tsv file into `${nshard}` and extract features for the +`${rank}`-th shard, where rank is an integer in `[0, nshard-1]`. Features would +be saved at `${feat_dir}/${split}_${rank}_${nshard}.{npy,len}`. + + +### HUBERT feature +To extract features from the `${layer}`-th transformer layer of a trained +HUBERT model saved at `${ckpt_path}`, run: +```sh +python dump_hubert_feature.py ${tsv_dir} ${split} ${ckpt_path} ${layer} ${nshard} ${rank} ${feat_dir} +``` +Features would also be saved at `${feat_dir}/${split}_${rank}_${nshard}.{npy,len}`. + +- if out-of-memory, decrease the chunk size with `--max_chunk` + + +## K-means clustering +To fit a k-means model with `${n_clusters}` clusters on 10% of the `${split}` data, run +```sh +python learn_kmeans.py ${feat_dir} ${split} ${nshard} ${km_path} ${n_cluster} --percent 0.1 +``` +This saves the k-means model to `${km_path}`. + +- set `--precent -1` to use all data +- more kmeans options can be found with `-h` flag + + +## K-means application +To apply a trained k-means model `${km_path}` to obtain labels for `${split}`, run +```sh +python dump_km_label.py ${feat_dir} ${split} ${km_path} ${nshard} ${rank} ${lab_dir} +``` +This would extract labels for the `${rank}`-th shard out of `${nshard}` shards +and dump them to `${lab_dir}/${split}_${rank}_${shard}.km` + + +Finally, merge shards for `${split}` by running +```sh +for rank in $(seq 0 $((nshard - 1))); do + cat $lab_dir/${split}_${rank}_${nshard}.km +done > $lab_dir/${split}.km +``` diff --git a/examples/hubert/simple_kmeans/dump_hubert_feature.py b/examples/hubert/simple_kmeans/dump_hubert_feature.py new file mode 100644 index 0000000000..cd242890e5 --- /dev/null +++ b/examples/hubert/simple_kmeans/dump_hubert_feature.py @@ -0,0 +1,133 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import math +import os +import sys + +import fairseq +import soundfile as sf +import torch +import torch.nn.functional as F +import tqdm +from npy_append_array import NpyAppendArray + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("dump_hubert_feature") + + +class HubertFeatureReader(object): + def __init__(self, ckpt_path, layer, max_chunk=1600000): + ( + model, + cfg, + task, + ) = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path]) + self.model = model[0].eval().cuda() + self.task = task + self.layer = layer + self.max_chunk = max_chunk + logger.info(f"TASK CONFIG:\n{self.task.cfg}") + logger.info(f" max_chunk = {self.max_chunk}") + + def read_audio(self, path, ref_len=None): + wav, sr = sf.read(path) + assert sr == self.task.cfg.sample_rate, sr + if wav.ndim == 2: + wav = wav.mean(-1) + assert wav.ndim == 1, wav.ndim + if ref_len is not None and abs(ref_len - len(wav)) > 160: + logging.warning(f"ref {ref_len} != read {len(wav)} ({path})") + return wav + + def get_feats(self, path, ref_len=None): + x = self.read_audio(path, ref_len) + with torch.no_grad(): + x = torch.from_numpy(x).float().cuda() + if self.task.cfg.normalize: + x = F.layer_norm(x, x.shape) + x = x.view(1, -1) + + feat = [] + for start in range(0, x.size(1), self.max_chunk): + x_chunk = x[:, start: start + self.max_chunk] + feat_chunk, _ = self.model.extract_features( + source=x_chunk, + padding_mask=None, + mask=False, + output_layer=self.layer, + ) + feat.append(feat_chunk) + return torch.cat(feat, 1).squeeze(0) + + +def get_path_iterator(tsv, nshard, rank): + with open(tsv, "r") as f: + root = f.readline().rstrip() + lines = [line.rstrip() for line in f] + tot = len(lines) + shard_size = math.ceil(tot / nshard) + start, end = rank * shard_size, min((rank + 1) * shard_size, tot) + assert start < end, "start={start}, end={end}" + logger.info( + f"rank {rank} of {nshard}, process {end-start} " + f"({start}-{end}) out of {tot}" + ) + + lines = lines[start:end] + + def iterate(): + for line in lines: + subpath, nsample = line.split("\t") + yield f"{root}/{subpath}", int(nsample) + + return iterate, len(lines) + + +def dump_feature( + tsv_dir, split, ckpt_path, layer, nshard, rank, feat_dir, max_chunk +): + reader = HubertFeatureReader(ckpt_path, layer, max_chunk) + generator, num = get_path_iterator(f"{tsv_dir}/{split}.tsv", nshard, rank) + iterator = generator() + + feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy" + leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len" + + os.makedirs(feat_dir, exist_ok=True) + if os.path.exists(feat_path): + os.remove(feat_path) + + feat_f = NpyAppendArray(feat_path) + with open(leng_path, "w") as leng_f: + for path, nsample in tqdm.tqdm(iterator, total=num): + feat = reader.get_feats(path, nsample) + feat_f.append(feat.cpu().numpy()) + leng_f.write(f"{len(feat)}\n") + logger.info("finished successfully") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("tsv_dir") + parser.add_argument("split") + parser.add_argument("ckpt_path") + parser.add_argument("layer", type=int) + parser.add_argument("nshard", type=int) + parser.add_argument("rank", type=int) + parser.add_argument("feat_dir") + parser.add_argument("--max_chunk", type=int, default=1600000) + args = parser.parse_args() + logger.info(args) + + dump_feature(**vars(args)) diff --git a/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py b/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py new file mode 100644 index 0000000000..7ec8a7311b --- /dev/null +++ b/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py @@ -0,0 +1,126 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import csv +import io +import logging +import math +import os +import os.path as op +import sys + +import tqdm +from dump_hubert_feature import HubertFeatureReader +from fairseq.data.audio.audio_utils import get_waveform +from fairseq.data.audio.speech_to_text_dataset import ( + read_from_uncompressed_zip, +) +from npy_append_array import NpyAppendArray + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("dump_hubert_feature_s2t") + + +class HubertFeatureReaderS2T(HubertFeatureReader): + def read_audio(self, path, ref_len=None): + path, *extra = path.split(":") + assert len(extra) == 2 + assert path.endswith(".zip") + + data = read_from_uncompressed_zip(path, int(extra[0]), int(extra[1])) + f = io.BytesIO(data) + wav, sr = get_waveform(f) + assert sr == self.task.cfg.sample_rate, sr + if wav.ndim == 2: + wav = wav.mean(-1) + assert wav.ndim == 1, wav.ndim + if ref_len is not None and abs(ref_len - len(wav)) > 160: + logging.warning(f"ref {ref_len} != read {len(wav)} ({path})") + return wav + + +def get_path_iterator(root, tsv, nshard, rank): + with open(tsv) as f: + reader = csv.DictReader( + f, + delimiter="\t", + quotechar=None, + doublequote=False, + lineterminator="\n", + quoting=csv.QUOTE_NONE, + ) + subpaths = [op.join(root, e["audio"]) for e in reader] + + tot = len(subpaths) + shard_size = math.ceil(tot / nshard) + start, end = rank * shard_size, min((rank + 1) * shard_size, tot) + assert start < end, "start={start}, end={end}" + logger.info( + f"rank {rank} of {nshard}, process {end-start} " + f"({start}-{end}) out of {tot}" + ) + + subpaths = subpaths[start:end] + + def iterate(): + for subpath in subpaths: + yield op.join(root, subpath) + + return iterate, len(subpaths) + + +def dump_feature( + root, + tsv_path, + ckpt_path, + layer, + nshard, + rank, + feat_dir, + feat_name, + max_chunk, +): + reader = HubertFeatureReaderS2T(ckpt_path, layer, max_chunk) + generator, num = get_path_iterator(root, tsv_path, nshard, rank) + iterator = generator() + + feat_path = f"{feat_dir}/{feat_name}_{rank}_{nshard}.npy" + leng_path = f"{feat_dir}/{feat_name}_{rank}_{nshard}.len" + + os.makedirs(feat_dir, exist_ok=True) + if op.exists(feat_path): + os.remove(feat_path) + + feat_f = NpyAppendArray(feat_path) + with open(leng_path, "w") as leng_f: + for path in tqdm.tqdm(iterator, total=num): + feat = reader.get_feats(path) + feat_f.append(feat.cpu().numpy()) + leng_f.write(f"{len(feat)}\n") + logger.info("finished successfully") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("root") + parser.add_argument("tsv_path") + parser.add_argument("ckpt_path") + parser.add_argument("layer", type=int) + parser.add_argument("nshard", type=int) + parser.add_argument("rank", type=int) + parser.add_argument("feat_dir") + parser.add_argument("feat_name") + parser.add_argument("--max_chunk", type=int, default=1600000) + args = parser.parse_args() + logger.info(args) + + dump_feature(**vars(args)) diff --git a/examples/hubert/simple_kmeans/dump_km_label.py b/examples/hubert/simple_kmeans/dump_km_label.py new file mode 100644 index 0000000000..8871307804 --- /dev/null +++ b/examples/hubert/simple_kmeans/dump_km_label.py @@ -0,0 +1,98 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import sys + +import numpy as np + +import joblib +import torch +import tqdm + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("dump_km_label") + + +class ApplyKmeans(object): + def __init__(self, km_path): + self.km_model = joblib.load(km_path) + self.C_np = self.km_model.cluster_centers_.transpose() + self.Cnorm_np = (self.C_np ** 2).sum(0, keepdims=True) + + self.C = torch.from_numpy(self.C_np) + self.Cnorm = torch.from_numpy(self.Cnorm_np) + if torch.cuda.is_available(): + self.C = self.C.cuda() + self.Cnorm = self.Cnorm.cuda() + + def __call__(self, x): + if isinstance(x, torch.Tensor): + dist = ( + x.pow(2).sum(1, keepdim=True) + - 2 * torch.matmul(x, self.C) + + self.Cnorm + ) + return dist.argmin(dim=1).cpu().numpy() + else: + dist = ( + (x ** 2).sum(1, keepdims=True) + - 2 * np.matmul(x, self.C_np) + + self.Cnorm_np + ) + return np.argmin(dist, axis=1) + + +def get_feat_iterator(feat_dir, split, nshard, rank): + feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy" + leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len" + with open(leng_path, "r") as f: + lengs = [int(line.rstrip()) for line in f] + offsets = [0] + np.cumsum(lengs[:-1]).tolist() + + def iterate(): + feat = np.load(feat_path, mmap_mode="r") + assert feat.shape[0] == (offsets[-1] + lengs[-1]) + for offset, leng in zip(offsets, lengs): + yield feat[offset: offset + leng] + + return iterate, len(lengs) + + +def dump_label(feat_dir, split, km_path, nshard, rank, lab_dir): + apply_kmeans = ApplyKmeans(km_path) + generator, num = get_feat_iterator(feat_dir, split, nshard, rank) + iterator = generator() + + lab_path = f"{lab_dir}/{split}_{rank}_{nshard}.km" + os.makedirs(lab_dir, exist_ok=True) + with open(lab_path, "w") as f: + for feat in tqdm.tqdm(iterator, total=num): + # feat = torch.from_numpy(feat).cuda() + lab = apply_kmeans(feat).tolist() + f.write(" ".join(map(str, lab)) + "\n") + logger.info("finished successfully") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("feat_dir") + parser.add_argument("split") + parser.add_argument("km_path") + parser.add_argument("nshard", type=int) + parser.add_argument("rank", type=int) + parser.add_argument("lab_dir") + args = parser.parse_args() + logging.info(str(args)) + + dump_label(**vars(args)) diff --git a/examples/hubert/simple_kmeans/dump_mfcc_feature.py b/examples/hubert/simple_kmeans/dump_mfcc_feature.py new file mode 100644 index 0000000000..a36fa643bd --- /dev/null +++ b/examples/hubert/simple_kmeans/dump_mfcc_feature.py @@ -0,0 +1,116 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import math +import os +import sys + +import soundfile as sf +import torch +import torchaudio +import tqdm +from npy_append_array import NpyAppendArray + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("dump_mfcc_feature") + + +class MfccFeatureReader(object): + def __init__(self, sample_rate): + self.sample_rate = sample_rate + + def read_audio(self, path, ref_len=None): + wav, sr = sf.read(path) + assert sr == self.sample_rate, sr + if wav.ndim == 2: + wav = wav.mean(-1) + assert wav.ndim == 1, wav.ndim + if ref_len is not None and abs(ref_len - len(wav)) > 160: + logging.warning(f"ref {ref_len} != read {len(wav)} ({path})") + return wav + + def get_feats(self, path, ref_len=None): + x = self.read_audio(path, ref_len) + with torch.no_grad(): + x = torch.from_numpy(x).float() + x = x.view(1, -1) + + mfccs = torchaudio.compliance.kaldi.mfcc( + waveform=x, + sample_frequency=self.sample_rate, + use_energy=False, + ) # (time, freq) + mfccs = mfccs.transpose(0, 1) # (freq, time) + deltas = torchaudio.functional.compute_deltas(mfccs) + ddeltas = torchaudio.functional.compute_deltas(deltas) + concat = torch.cat([mfccs, deltas, ddeltas], dim=0) + concat = concat.transpose(0, 1).contiguous() # (freq, time) + return concat + + +def get_path_iterator(tsv, nshard, rank): + with open(tsv, "r") as f: + root = f.readline().rstrip() + lines = [line.rstrip() for line in f] + tot = len(lines) + shard_size = math.ceil(tot / nshard) + start, end = rank * shard_size, min((rank + 1) * shard_size, tot) + assert start < end, "start={start}, end={end}" + logger.info( + f"rank {rank} of {nshard}, process {end-start} " + f"({start}-{end}) out of {tot}" + ) + + lines = lines[start:end] + + def iterate(): + for line in lines: + subpath, nsample = line.split("\t") + yield f"{root}/{subpath}", int(nsample) + + return iterate, len(lines) + + +def dump_feature(tsv_dir, split, sample_rate, nshard, rank, feat_dir): + reader = MfccFeatureReader(sample_rate) + generator, num = get_path_iterator(f"{tsv_dir}/{split}.tsv", nshard, rank) + iterator = generator() + + feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy" + leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len" + + os.makedirs(feat_dir, exist_ok=True) + if os.path.exists(feat_path): + os.remove(feat_path) + + feat_f = NpyAppendArray(feat_path) + with open(leng_path, "w") as leng_f: + for path, nsample in tqdm.tqdm(iterator, total=num): + feat = reader.get_feats(path, nsample) + feat_f.append(feat.cpu().numpy()) + leng_f.write(f"{len(feat)}\n") + logger.info("finished successfully") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("tsv_dir") + parser.add_argument("split") + parser.add_argument("nshard", type=int) + parser.add_argument("rank", type=int) + parser.add_argument("feat_dir") + parser.add_argument("--sample_rate", type=int, default=16000) + args = parser.parse_args() + logger.info(args) + + dump_feature(**vars(args)) diff --git a/examples/hubert/simple_kmeans/learn_kmeans.py b/examples/hubert/simple_kmeans/learn_kmeans.py new file mode 100644 index 0000000000..113ac655b8 --- /dev/null +++ b/examples/hubert/simple_kmeans/learn_kmeans.py @@ -0,0 +1,146 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import sys + +import numpy as np +from sklearn.cluster import MiniBatchKMeans + +import joblib + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("learn_kmeans") + + +def get_km_model( + n_clusters, + init, + max_iter, + batch_size, + tol, + max_no_improvement, + n_init, + reassignment_ratio, +): + return MiniBatchKMeans( + n_clusters=n_clusters, + init=init, + max_iter=max_iter, + batch_size=batch_size, + verbose=1, + compute_labels=False, + tol=tol, + max_no_improvement=max_no_improvement, + init_size=None, + n_init=n_init, + reassignment_ratio=reassignment_ratio, + ) + + +def load_feature_shard(feat_dir, split, nshard, rank, percent): + feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy" + leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len" + with open(leng_path, "r") as f: + lengs = [int(line.rstrip()) for line in f] + offsets = [0] + np.cumsum(lengs[:-1]).tolist() + + if percent < 0: + return np.load(feat_path, mmap_mode="r") + else: + nsample = int(np.ceil(len(lengs) * percent)) + indices = np.random.choice(len(lengs), nsample, replace=False) + feat = np.load(feat_path, mmap_mode="r") + sampled_feat = np.concatenate( + [feat[offsets[i]: offsets[i] + lengs[i]] for i in indices], axis=0 + ) + logger.info( + ( + f"sampled {nsample} utterances, {len(sampled_feat)} frames " + f"from shard {rank}/{nshard}" + ) + ) + return sampled_feat + + +def load_feature(feat_dir, split, nshard, seed, percent): + assert percent <= 1.0 + feat = np.concatenate( + [ + load_feature_shard(feat_dir, split, nshard, r, percent) + for r in range(nshard) + ], + axis=0, + ) + logging.info(f"loaded feature with dimension {feat.shape}") + return feat + + +def learn_kmeans( + feat_dir, + split, + nshard, + km_path, + n_clusters, + seed, + percent, + init, + max_iter, + batch_size, + tol, + n_init, + reassignment_ratio, + max_no_improvement, +): + np.random.seed(seed) + feat = load_feature(feat_dir, split, nshard, seed, percent) + km_model = get_km_model( + n_clusters, + init, + max_iter, + batch_size, + tol, + max_no_improvement, + n_init, + reassignment_ratio, + ) + km_model.fit(feat) + joblib.dump(km_model, km_path) + + inertia = -km_model.score(feat) / len(feat) + logger.info("total intertia: %.5f", inertia) + logger.info("finished successfully") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("feat_dir", type=str) + parser.add_argument("split", type=str) + parser.add_argument("nshard", type=int) + parser.add_argument("km_path", type=str) + parser.add_argument("n_clusters", type=int) + parser.add_argument("--seed", default=0, type=int) + parser.add_argument( + "--percent", default=-1, type=float, help="sample a subset; -1 for all" + ) + parser.add_argument("--init", default="k-means++") + parser.add_argument("--max_iter", default=100, type=int) + parser.add_argument("--batch_size", default=10000, type=int) + parser.add_argument("--tol", default=0.0, type=float) + parser.add_argument("--max_no_improvement", default=100, type=int) + parser.add_argument("--n_init", default=20, type=int) + parser.add_argument("--reassignment_ratio", default=0.0, type=float) + args = parser.parse_args() + logging.info(str(args)) + + learn_kmeans(**vars(args)) diff --git a/examples/hubert/update_ckpt.py b/examples/hubert/update_ckpt.py new file mode 100644 index 0000000000..53c9e74ea6 --- /dev/null +++ b/examples/hubert/update_ckpt.py @@ -0,0 +1,22 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + +src_ckpt = "/checkpoint/wnhsu/w2v/archived/hubert_base_ls960_it2.pt" +ref_ckpt = "/checkpoint/wnhsu/w2v/hubert_icassp_oss_v3/iter2_km100-400k-grp-L6/oss.km500_p0_1_s334.pmw1_0.puw0_0.grpnorm.ml10.mp0_8.untie.mxsz250000.ufreq1.maxtok1400000.MU100k.s1337.ngpu32/checkpoint_last.pt" +new_ckpt = "/checkpoint/wnhsu/w2v/archived/hubert_base_ls960_it2_updated.pt" + + +def update_state(state): + state["model"]["label_embs_concat"] = state["model"].pop("label_embs") + state["args"].task = "hubert_pretraining" + state["args"].labels = f"['{state['args'].labels}']" + return state + + +src_state = torch.load(src_ckpt) +src_state = update_state(src_state) +torch.save(src_state, new_ckpt) diff --git a/fairseq/criterions/hubert_criterion.py b/fairseq/criterions/hubert_criterion.py new file mode 100644 index 0000000000..68cb24e6f1 --- /dev/null +++ b/fairseq/criterions/hubert_criterion.py @@ -0,0 +1,177 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +import re +from dataclasses import dataclass, field +from typing import List, Optional + +import torch +import torch.nn.functional as F +from fairseq import metrics, utils +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass + + +@dataclass +class HubertCriterionConfig(FairseqDataclass): + pred_masked_weight: float = field( + default=1.0, + metadata={"help": "weight for predictive loss for masked frames"}, + ) + pred_nomask_weight: float = field( + default=0.0, + metadata={"help": "weight for predictive loss for unmasked frames"}, + ) + loss_weights: Optional[List[float]] = field( + default=None, + metadata={"help": "weights for additional loss terms (not first one)"}, + ) + log_keys: List[str] = field( + default_factory=lambda: [], + metadata={"help": "output keys to log"}, + ) + + +@register_criterion("hubert", dataclass=HubertCriterionConfig) +class HubertCriterion(FairseqCriterion): + def __init__(self, task, pred_masked_weight, pred_nomask_weight, loss_weights=None, log_keys=None): + super().__init__(task) + self.pred_masked_weight = pred_masked_weight + self.pred_nomask_weight = pred_nomask_weight + self.loss_weights = loss_weights + self.log_keys = [] if log_keys is None else log_keys + + def forward(self, model, sample, reduce=True, log_pred=False): + """Compute the loss for the given sample. + Returns a tuple with three elements: + 1) the loss + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + net_output = model(target_list=sample["target_list"], **sample["net_input"]) + loss = 0. + sample_size = 0 + logging_output = {} + reduction = "sum" if reduce else "none" + + loss_m_list = [] + logp_m_list = model.get_logits(net_output, True) + targ_m_list = model.get_targets(net_output, True) + assert self.pred_masked_weight == 0 or len(logp_m_list) > 0 + for i, (logp_m, targ_m) in enumerate(zip(logp_m_list, targ_m_list)): + loss_m = F.cross_entropy(logp_m, targ_m, reduction=reduction) + loss_m_list.append(loss_m) + logging_output[f"loss_m_{i}"] = loss_m.detach().item() + if self.pred_masked_weight > 0: + loss += self.pred_masked_weight * sum(loss_m_list) + sample_size += targ_m_list[0].numel() + + loss_u_list = [] + logp_u_list = model.get_logits(net_output, False) + targ_u_list = model.get_targets(net_output, False) + assert self.pred_nomask_weight == 0 or len(logp_u_list) > 0 + for i, (logp_u, targ_u) in enumerate(zip(logp_u_list, targ_u_list)): + loss_u = F.cross_entropy(logp_u, targ_u, reduction=reduction) + loss_u_list.append(loss_u) + logging_output[f"loss_u_{i}"] = loss_u.detach().item() + if self.pred_nomask_weight > 0: + loss += self.pred_nomask_weight * sum(loss_u_list) + sample_size += targ_u_list[0].numel() + + if self.loss_weights is not None: + assert hasattr(model, "get_extra_losses") + extra_losses, names = model.get_extra_losses(net_output) + if torch.is_tensor(extra_losses): + extra_losses = [extra_losses] + names = [names] + if len(self.loss_weights) == 1 and len(extra_losses) != 1: + self.loss_weights = [self.loss_weights[0]] * len(extra_losses) + assert len(extra_losses) == len(self.loss_weights), f"{len(extra_losses)}, {len(self.loss_weights)}" + for p, n, coef in zip(extra_losses, names, self.loss_weights): + if coef != 0 and p is not None: + p = coef * p.float() * sample_size + loss += p + logging_output[f"loss_{n}"] = p.item() + + logging_output = { + "loss": loss.item() if reduce else loss, + "ntokens": sample_size, + "nsentences": sample["id"].numel(), + "sample_size": sample_size, + **logging_output, + } + + for lk in self.log_keys: + if lk in net_output: + logging_output[lk] = float((net_output[lk])) + + def compute_correct(logits): + if logits.numel() == 0: + return 0, 0 + else: + assert logits.dim() > 1, logits.shape + max = logits.argmax(-1) == 0 + min = logits.argmin(-1) == 0 + both = max & min + corr = max.long().sum().item() - both.long().sum().item() + count = max.numel() + return corr, count + + with torch.no_grad(): + for i, logp_m in enumerate(logp_m_list): + corr_m, count_m = compute_correct(logp_m) + logging_output[f"correct_m_{i}"] = corr_m + logging_output[f"count_m_{i}"] = count_m + + for i, logp_u in enumerate(logp_u_list): + corr_u, count_u = compute_correct(logp_u) + logging_output[f"correct_u_{i}"] = corr_u + logging_output[f"count_u_{i}"] = count_u + + return loss, sample_size, logging_output + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training (copied from normal cross entropy).""" + loss_sum = sum(log.get("loss", 0) for log in logging_outputs) + ntokens = sum(log.get("ntokens", 0) for log in logging_outputs) + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + + metrics.log_scalar("loss", loss_sum / sample_size / math.log(2), sample_size, round=3) + if sample_size != ntokens: + metrics.log_scalar("nll_loss", loss_sum / ntokens / math.log(2), ntokens, round=3) + metrics.log_derived("ppl", lambda meters: utils.get_perplexity(meters["nll_loss"].avg)) + else: + metrics.log_derived("ppl", lambda meters: utils.get_perplexity(meters["loss"].avg)) + + counts = {} + for lk in logging_outputs[0].keys(): + if lk.startswith("count_"): + val = sum(log[lk] for log in logging_outputs) + metrics.log_scalar(lk, val) + counts[lk] = val + + for lk in logging_outputs[0].keys(): + if lk.startswith("loss_"): + val = sum(log[lk] for log in logging_outputs) + metrics.log_scalar(lk, val / sample_size / math.log(2), round=3) + elif lk.startswith("correct_"): + val = sum(log[lk] for log in logging_outputs) + metrics.log_scalar(lk, val / counts[re.sub("correct", "count", lk)]) + + @staticmethod + def aggregate_logging_outputs(logging_outputs): + """Aggregate logging outputs from data parallel training.""" + raise NotImplementedError() + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return False diff --git a/fairseq/data/__init__.py b/fairseq/data/__init__.py index 30af792185..8b7eb2ec4f 100644 --- a/fairseq/data/__init__.py +++ b/fairseq/data/__init__.py @@ -13,6 +13,7 @@ from .add_target_dataset import AddTargetDataset from .append_token_dataset import AppendTokenDataset from .audio.raw_audio_dataset import BinarizedAudioDataset, FileAudioDataset +from .audio.hubert_dataset import HubertDataset from .backtranslation_dataset import BacktranslationDataset from .bucket_pad_length_dataset import BucketPadLengthDataset from .colorize_dataset import ColorizeDataset @@ -82,7 +83,9 @@ "FairseqDataset", "FairseqIterableDataset", "FastaDataset", + "FileAudioDataset", "GroupedIterator", + "HubertDataset", "IdDataset", "IndexedCachedDataset", "IndexedDataset", @@ -104,12 +107,12 @@ "PadDataset", "PrependDataset", "PrependTokenDataset", - "ReplaceDataset", - "RollDataset", - "FileAudioDataset", + "RandomCropDataset", "RawLabelDataset", "ResamplingDataset", + "ReplaceDataset", "RightPadDataset", + "RollDataset", "RoundRobinZipDatasets", "SampledMultiDataset", "SampledMultiEpochDataset", diff --git a/fairseq/data/audio/hubert_dataset.py b/fairseq/data/audio/hubert_dataset.py new file mode 100644 index 0000000000..f00fe301a6 --- /dev/null +++ b/fairseq/data/audio/hubert_dataset.py @@ -0,0 +1,358 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import itertools +import logging +import os +import sys +from typing import Any, List, Optional, Union + +import numpy as np + +import torch +import torch.nn.functional as F +from fairseq.data import data_utils +from fairseq.data.fairseq_dataset import FairseqDataset + +logger = logging.getLogger(__name__) + + +def load_audio(manifest_path, max_keep, min_keep): + n_long, n_short = 0, 0 + names, inds, sizes = [], [], [] + with open(manifest_path) as f: + root = f.readline().strip() + for ind, line in enumerate(f): + items = line.strip().split("\t") + assert len(items) == 2, line + sz = int(items[1]) + if min_keep is not None and sz < min_keep: + n_short += 1 + elif max_keep is not None and sz > max_keep: + n_long += 1 + else: + names.append(items[0]) + inds.append(ind) + sizes.append(sz) + tot = ind + 1 + logger.info( + ( + f"max_keep={max_keep}, min_keep={min_keep}, " + f"loaded {len(names)}, skipped {n_short} short and {n_long} long, " + f"longest-loaded={max(sizes)}, shortest-loaded={min(sizes)}" + ) + ) + return root, names, inds, tot, sizes + + +def load_label(label_path, inds, tot): + with open(label_path) as f: + labels = [line.rstrip() for line in f] + assert ( + len(labels) == tot + ), f"number of labels does not match ({len(labels)} != {tot})" + labels = [labels[i] for i in inds] + return labels + + +def load_label_offset(label_path, inds, tot): + with open(label_path) as f: + code_lengths = [len(line.encode("utf-8")) for line in f] + assert ( + len(code_lengths) == tot + ), f"number of labels does not match ({len(code_lengths)} != {tot})" + offsets = list(itertools.accumulate([0] + code_lengths)) + offsets = [(offsets[i], offsets[i + 1]) for i in inds] + return offsets + + +def verify_label_lengths( + audio_sizes, + audio_rate, + label_path, + label_rate, + inds, + tot, + tol=0.1, # tolerance in seconds +): + if label_rate < 0: + logger.info(f"{label_path} is sequence label. skipped") + return + + with open(label_path) as f: + lengths = [len(line.rstrip().split()) for line in f] + assert len(lengths) == tot + lengths = [lengths[i] for i in inds] + num_invalid = 0 + for i, ind in enumerate(inds): + dur_from_audio = audio_sizes[i] / audio_rate + dur_from_label = lengths[i] / label_rate + if abs(dur_from_audio - dur_from_label) > tol: + logger.warning( + ( + f"audio and label duration differ too much " + f"(|{dur_from_audio} - {dur_from_label}| > {tol}) " + f"in line {ind+1} of {label_path}. Check if `label_rate` " + f"is correctly set (currently {label_rate}). " + f"num. of samples = {audio_sizes[i]}; " + f"label length = {lengths[i]}" + ) + ) + num_invalid += 1 + if num_invalid > 0: + logger.warning( + f"total {num_invalid} (audio, label) pairs with mismatched lengths" + ) + + +class HubertDataset(FairseqDataset): + def __init__( + self, + manifest_path: str, + sample_rate: float, + label_paths: List[str], + label_rates: Union[List[float], float], # -1 for sequence labels + pad_list: List[str], + eos_list: List[str], + label_processors: Optional[List[Any]] = None, + max_keep_sample_size: Optional[int] = None, + min_keep_sample_size: Optional[int] = None, + max_sample_size: Optional[int] = None, + shuffle: bool = True, + pad_audio: bool = False, + normalize: bool = False, + store_labels: bool = True, + random_crop: bool = False, + single_target: bool = False, + ): + self.audio_root, self.audio_names, inds, tot, self.sizes = load_audio( + manifest_path, max_keep_sample_size, min_keep_sample_size + ) + self.sample_rate = sample_rate + self.shuffle = shuffle + self.random_crop = random_crop + + self.num_labels = len(label_paths) + self.pad_list = pad_list + self.eos_list = eos_list + self.label_processors = label_processors + self.single_target = single_target + self.label_rates = ( + [label_rates for _ in range(len(label_paths))] + if isinstance(label_rates, int) + else label_rates + ) + self.store_labels = store_labels + if store_labels: + self.label_list = [load_label(p, inds, tot) for p in label_paths] + else: + self.label_paths = label_paths + self.label_offsets_list = [ + load_label_offset(p, inds, tot) for p in label_paths + ] + assert ( + label_processors is None + or len(label_processors) == self.num_labels + ) + for label_path, label_rate in zip(label_paths, self.label_rates): + verify_label_lengths( + self.sizes, sample_rate, label_path, label_rate, inds, tot + ) + + self.max_sample_size = ( + max_sample_size if max_sample_size is not None else sys.maxsize + ) + self.pad_audio = pad_audio + self.normalize = normalize + logger.info( + f"pad_audio={pad_audio}, random_crop={random_crop}, " + f"normalize={normalize}, max_sample_size={self.max_sample_size}" + ) + + def get_audio(self, index): + import soundfile as sf + + wav_path = os.path.join(self.audio_root, self.audio_names[index]) + wav, cur_sample_rate = sf.read(wav_path) + wav = torch.from_numpy(wav).float() + wav = self.postprocess(wav, cur_sample_rate) + return wav + + def get_label(self, index, label_idx): + if self.store_labels: + label = self.label_list[label_idx][index] + else: + with open(self.label_paths[label_idx]) as f: + offset_s, offset_e = self.label_offsets_list[label_idx][index] + f.seek(offset_s) + label = f.read(offset_e - offset_s) + + if self.label_processors is not None: + label = self.label_processors[label_idx](label) + return label + + def get_labels(self, index): + return [self.get_label(index, i) for i in range(self.num_labels)] + + def __getitem__(self, index): + wav = self.get_audio(index) + labels = self.get_labels(index) + return {"id": index, "source": wav, "label_list": labels} + + def __len__(self): + return len(self.sizes) + + def crop_to_max_size(self, wav, target_size): + size = len(wav) + diff = size - target_size + if diff <= 0: + return wav, 0 + + start, end = 0, target_size + if self.random_crop: + start = np.random.randint(0, diff + 1) + end = size - diff + start + return wav[start:end], start + + def collater(self, samples): + # target = max(sizes) -> random_crop not used + # target = max_sample_size -> random_crop used for long + samples = [s for s in samples if s["source"] is not None] + if len(samples) == 0: + return {} + + audios = [s["source"] for s in samples] + audio_sizes = [len(s) for s in audios] + if self.pad_audio: + audio_size = min(max(audio_sizes), self.max_sample_size) + else: + audio_size = min(min(audio_sizes), self.max_sample_size) + collated_audios, padding_mask, audio_starts = self.collater_audio( + audios, audio_size + ) + + targets_by_label = [ + [s["label_list"][i] for s in samples] + for i in range(self.num_labels) + ] + targets_list, lengths_list, ntokens_list = self.collater_label( + targets_by_label, audio_size, audio_starts + ) + + net_input = {"source": collated_audios, "padding_mask": padding_mask} + batch = { + "id": torch.LongTensor([s["id"] for s in samples]), + "net_input": net_input, + } + + if self.single_target: + batch["target_lengths"] = lengths_list[0] + batch["ntokens"] = ntokens_list[0] + batch["target"] = targets_list[0] + else: + batch["target_lengths_list"] = lengths_list + batch["ntokens_list"] = ntokens_list + batch["target_list"] = targets_list + return batch + + def collater_audio(self, audios, audio_size): + collated_audios = audios[0].new_zeros(len(audios), audio_size) + padding_mask = ( + torch.BoolTensor(collated_audios.shape).fill_(False) + # if self.pad_audio else None + ) + audio_starts = [0 for _ in audios] + for i, audio in enumerate(audios): + diff = len(audio) - audio_size + if diff == 0: + collated_audios[i] = audio + elif diff < 0: + assert self.pad_audio + collated_audios[i] = torch.cat( + [audio, audio.new_full((-diff,), 0.0)] + ) + padding_mask[i, diff:] = True + else: + collated_audios[i], audio_starts[i] = self.crop_to_max_size( + audio, audio_size + ) + return collated_audios, padding_mask, audio_starts + + def collater_frm_label( + self, targets, audio_size, audio_starts, label_rate, pad + ): + assert label_rate > 0 + s2f = label_rate / self.sample_rate + frm_starts = [int(round(s * s2f)) for s in audio_starts] + frm_size = int(round(audio_size * s2f)) + if not self.pad_audio: + rem_size = [len(t) - s for t, s in zip(targets, frm_starts)] + frm_size = min(frm_size, *rem_size) + targets = [t[s: s + frm_size] for t, s in zip(targets, frm_starts)] + logger.debug(f"audio_starts={audio_starts}") + logger.debug(f"frame_starts={frm_starts}") + logger.debug(f"frame_size={frm_size}") + + lengths = torch.LongTensor([len(t) for t in targets]) + ntokens = lengths.sum().item() + targets = data_utils.collate_tokens( + targets, pad_idx=pad, left_pad=False + ) + return targets, lengths, ntokens + + def collater_seq_label(self, targets, pad): + lengths = torch.LongTensor([len(t) for t in targets]) + ntokens = lengths.sum().item() + targets = data_utils.collate_tokens( + targets, pad_idx=pad, left_pad=False + ) + return targets, lengths, ntokens + + def collater_label(self, targets_by_label, audio_size, audio_starts): + targets_list, lengths_list, ntokens_list = [], [], [] + itr = zip(targets_by_label, self.label_rates, self.pad_list) + for targets, label_rate, pad in itr: + if label_rate == -1: + targets, lengths, ntokens = self.collater_seq_label( + targets, pad + ) + else: + targets, lengths, ntokens = self.collater_frm_label( + targets, audio_size, audio_starts, label_rate, pad + ) + targets_list.append(targets) + lengths_list.append(lengths) + ntokens_list.append(ntokens) + return targets_list, lengths_list, ntokens_list + + def num_tokens(self, index): + return self.size(index) + + def size(self, index): + if self.pad_audio: + return self.sizes[index] + return min(self.sizes[index], self.max_sample_size) + + def ordered_indices(self): + if self.shuffle: + order = [np.random.permutation(len(self))] + else: + order = [np.arange(len(self))] + + order.append(self.sizes) + return np.lexsort(order)[::-1] + + def postprocess(self, wav, cur_sample_rate): + if wav.dim() == 2: + wav = wav.mean(-1) + assert wav.dim() == 1, wav.dim() + + if cur_sample_rate != self.sample_rate: + raise Exception(f"sr {cur_sample_rate} != {self.sample_rate}") + + if self.normalize: + with torch.no_grad(): + wav = F.layer_norm(wav, wav.shape) + return wav diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index b09e87fe09..b7736116f9 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -306,7 +306,7 @@ def distributed_init(cfg: FairseqConfig): model_part_number = get_model_parallel_rank() cfg.checkpoint.checkpoint_suffix += "-model_part-{0}".format(model_part_number) - if getattr(cfg.model, "base_layers", 0) > 0: + if hasattr(cfg, "model") and getattr(cfg.model, "base_layers", 0) > 0: cfg.checkpoint.checkpoint_suffix = f"-rank-{cfg.distributed_training.distributed_rank}" return cfg.distributed_training.distributed_rank diff --git a/fairseq/models/hubert/__init__.py b/fairseq/models/hubert/__init__.py new file mode 100644 index 0000000000..a1b0eabbdb --- /dev/null +++ b/fairseq/models/hubert/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .hubert import * # noqa +from .hubert_asr import * # noqa diff --git a/fairseq/models/hubert/hubert.py b/fairseq/models/hubert/hubert.py new file mode 100644 index 0000000000..232a5e402a --- /dev/null +++ b/fairseq/models/hubert/hubert.py @@ -0,0 +1,563 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Dict, List, Optional, Tuple + +import numpy as np + +import torch +import torch.nn as nn +from dataclasses import dataclass, field +from fairseq import utils +from fairseq.data.data_utils import compute_mask_indices +from fairseq.data.dictionary import Dictionary +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model +from fairseq.models.wav2vec.wav2vec2 import ( + ConvFeatureExtractionModel, + TransformerEncoder, +) +from fairseq.modules import GradMultiply, LayerNorm +from fairseq.tasks.hubert_pretraining import ( + HubertPretrainingConfig, + HubertPretrainingTask, +) +from omegaconf import II + +logger = logging.getLogger(__name__) + +EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) +MASKING_DISTRIBUTION_CHOICES = ChoiceEnum( + ["static", "uniform", "normal", "poisson"] +) + + +@dataclass +class HubertConfig(FairseqDataclass): + label_rate: int = II("task.label_rate") + + extractor_mode: EXTRACTOR_MODE_CHOICES = field( + default="default", + metadata={ + "help": "mode for feature extractor. default has a single group " + "norm with d groups in the first conv block, whereas layer_norm " + "has layer norms in every block (meant to use with normalize=True)" + }, + ) + encoder_layers: int = field( + default=12, metadata={"help": "num encoder layers in the transformer"} + ) + encoder_embed_dim: int = field( + default=768, metadata={"help": "encoder embedding dimension"} + ) + encoder_ffn_embed_dim: int = field( + default=3072, metadata={"help": "encoder embedding dimension for FFN"} + ) + encoder_attention_heads: int = field( + default=12, metadata={"help": "num encoder attention heads"} + ) + activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( + default="gelu", metadata={"help": "activation function to use"} + ) + + # dropouts + dropout: float = field( + default=0.1, + metadata={"help": "dropout probability for the transformer"}, + ) + attention_dropout: float = field( + default=0.1, + metadata={"help": "dropout probability for attention weights"}, + ) + activation_dropout: float = field( + default=0.0, + metadata={"help": "dropout probability after activation in FFN"}, + ) + encoder_layerdrop: float = field( + default=0.0, + metadata={"help": "probability of dropping a tarnsformer layer"}, + ) + dropout_input: float = field( + default=0.0, + metadata={"help": "dropout to apply to the input (after feat extr)"}, + ) + dropout_features: float = field( + default=0.0, + metadata={ + "help": "dropout to apply to the features (after feat extr)" + }, + ) + + final_dim: int = field( + default=0, + metadata={ + "help": "project final representations and targets to this many " + "dimensions. set to encoder_embed_dim is <= 0" + }, + ) + untie_final_proj: bool = field( + default=False, + metadata={"help": "use separate projection for each target"}, + ) + layer_norm_first: bool = field( + default=False, + metadata={"help": "apply layernorm first in the transformer"}, + ) + conv_feature_layers: str = field( + default="[(512,10,5)] + [(512,3,2)] * 4 + [(512,2,2)] * 2", + metadata={ + "help": "string describing convolutional feature extraction " + "layers in form of a python list that contains " + "[(dim, kernel_size, stride), ...]" + }, + ) + conv_bias: bool = field( + default=False, metadata={"help": "include bias in conv encoder"} + ) + logit_temp: float = field( + default=0.1, metadata={"help": "temperature to divide logits by"} + ) + target_glu: bool = field( + default=False, metadata={"help": "adds projection + glu to targets"} + ) + feature_grad_mult: float = field( + default=1.0, + metadata={"help": "multiply feature extractor var grads by this"}, + ) + + # masking + mask_length: int = field(default=10, metadata={"help": "mask length"}) + mask_prob: float = field( + default=0.65, + metadata={"help": "probability of replacing a token with mask"}, + ) + mask_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose mask length"} + ) + mask_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indicesh" + }, + ) + no_mask_overlap: bool = field( + default=False, metadata={"help": "whether to allow masks to overlap"} + ) + mask_min_space: int = field( + default=1, + metadata={ + "help": "min space between spans (if no overlap is enabled)" + }, + ) + + # channel masking + mask_channel_length: int = field( + default=10, + metadata={"help": "length of the mask for features (channels)"}, + ) + mask_channel_prob: float = field( + default=0.0, + metadata={"help": "probability of replacing a feature with 0"}, + ) + mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", + metadata={"help": "how to choose mask length for channel masking"}, + ) + mask_channel_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indicesh" + }, + ) + no_mask_channel_overlap: bool = field( + default=False, + metadata={"help": "whether to allow channel masks to overlap"}, + ) + mask_channel_min_space: int = field( + default=1, + metadata={ + "help": "min space between spans (if no overlap is enabled)" + }, + ) + + # positional embeddings + conv_pos: int = field( + default=128, + metadata={ + "help": "number of filters for convolutional positional embeddings" + }, + ) + conv_pos_groups: int = field( + default=16, + metadata={ + "help": "number of groups for convolutional positional embedding" + }, + ) + + latent_temp: Tuple[float, float, float] = field( + default=(2, 0.5, 0.999995), + metadata={"help": "legacy (to be removed)"}, + ) + + # loss computation + skip_masked: bool = field( + default=False, + metadata={"help": "skip computing losses over masked frames"}, + ) + skip_nomask: bool = field( + default=False, + metadata={"help": "skip computing losses over unmasked frames"}, + ) + + +@register_model("hubert", dataclass=HubertConfig) +class HubertModel(BaseFairseqModel): + def __init__( + self, + cfg: HubertConfig, + task_cfg: HubertPretrainingConfig, + dictionaries: List[Dictionary], + ) -> None: + super().__init__() + logger.info(f"HubertModel Config: {cfg}") + + feature_enc_layers = eval(cfg.conv_feature_layers) # noqa + self.embed = feature_enc_layers[-1][0] + + self.feature_extractor = ConvFeatureExtractionModel( + conv_layers=feature_enc_layers, + dropout=0.0, + mode=cfg.extractor_mode, + conv_bias=cfg.conv_bias, + ) + feature_ds_rate = np.prod([s for _, _, s in feature_enc_layers]) + self.feat2tar_ratio = ( + cfg.label_rate * feature_ds_rate / task_cfg.sample_rate + ) + + self.post_extract_proj = ( + nn.Linear(self.embed, cfg.encoder_embed_dim) + if self.embed != cfg.encoder_embed_dim + else None + ) + + self.mask_prob = cfg.mask_prob + self.mask_selection = cfg.mask_selection + self.mask_other = cfg.mask_other + self.mask_length = cfg.mask_length + self.no_mask_overlap = cfg.no_mask_overlap + self.mask_min_space = cfg.mask_min_space + + self.mask_channel_prob = cfg.mask_channel_prob + self.mask_channel_selection = cfg.mask_channel_selection + self.mask_channel_other = cfg.mask_channel_other + self.mask_channel_length = cfg.mask_channel_length + self.no_mask_channel_overlap = cfg.no_mask_channel_overlap + self.mask_channel_min_space = cfg.mask_channel_min_space + + self.dropout_input = nn.Dropout(cfg.dropout_input) + self.dropout_features = nn.Dropout(cfg.dropout_features) + + self.feature_grad_mult = cfg.feature_grad_mult + self.logit_temp = cfg.logit_temp + self.skip_masked = cfg.skip_masked + self.skip_nomask = cfg.skip_nomask + + final_dim = ( + cfg.final_dim if cfg.final_dim > 0 else cfg.encoder_embed_dim + ) + + self.mask_emb = nn.Parameter( + torch.FloatTensor(cfg.encoder_embed_dim).uniform_() + ) + + self.encoder = TransformerEncoder(cfg) + self.layer_norm = LayerNorm(self.embed) + + self.target_glu = None + if cfg.target_glu: + self.target_glu = nn.Sequential( + nn.Linear(final_dim, final_dim * 2), nn.GLU() + ) + + self.untie_final_proj = cfg.untie_final_proj + if self.untie_final_proj: + self.final_proj = nn.Linear( + cfg.encoder_embed_dim, final_dim * len(dictionaries) + ) + else: + self.final_proj = nn.Linear(cfg.encoder_embed_dim, final_dim) + + # modules below are not needed during fine-tuning + if any([d is None for d in dictionaries]): + logger.info( + "cannot find dictionary. assume will be used for fine-tuning" + ) + else: + self.num_classes = [len(d) for d in dictionaries] + self.label_embs_concat = nn.Parameter( + torch.FloatTensor(sum(self.num_classes), final_dim) + ) + nn.init.uniform_(self.label_embs_concat) + + def upgrade_state_dict_named(self, state_dict, name): + """Upgrade a (possibly old) state dict for new versions of fairseq.""" + + super().upgrade_state_dict_named(state_dict, name) + return state_dict + + @classmethod + def build_model(cls, cfg: HubertConfig, task: HubertPretrainingTask): + """Build a new model instance.""" + + model = HubertModel(cfg, task.cfg, task.dictionaries) + return model + + def apply_mask(self, x, padding_mask, target_list): + B, T, C = x.shape + if self.mask_prob > 0: + mask_indices = compute_mask_indices( + (B, T), + padding_mask, + self.mask_prob, + self.mask_length, + self.mask_selection, + self.mask_other, + min_masks=2, + no_overlap=self.no_mask_overlap, + min_space=self.mask_min_space, + ) + mask_indices = torch.from_numpy(mask_indices).to(x.device) + x[mask_indices] = self.mask_emb + else: + mask_indices = None + + if self.mask_channel_prob > 0: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_channel_prob, + self.mask_channel_length, + self.mask_channel_selection, + self.mask_channel_other, + no_overlap=self.no_mask_channel_overlap, + min_space=self.mask_channel_min_space, + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x[mask_channel_indices] = 0 + + return x, mask_indices + + def compute_nce(self, x, pos, negs): + neg_is_pos = (pos == negs).all(-1) + pos = pos.unsqueeze(0) + targets = torch.cat([pos, negs], dim=0) + + logits = torch.cosine_similarity( + x.float(), targets.float(), dim=-1 + ).type_as(x) + logits /= self.logit_temp + if neg_is_pos.any(): + logits[1:][neg_is_pos] = float("-inf") + logits = logits.transpose(0, 1) # (num_x, num_cls+1) + return logits + + def forward_features(self, source: torch.Tensor) -> torch.Tensor: + if self.feature_grad_mult > 0: + features = self.feature_extractor(source) + if self.feature_grad_mult != 1.0: + features = GradMultiply.apply(features, self.feature_grad_mult) + else: + with torch.no_grad(): + features = self.feature_extractor(source) + return features + + def forward_targets( + self, features: torch.Tensor, target_list: List[torch.Tensor], + ) -> Tuple[torch.Tensor, torch.Tensor]: + # Trim features to ensure labels exist and then get aligned labels + feat_tsz = features.size(2) + targ_tsz = min([t.size(1) for t in target_list]) + if self.feat2tar_ratio * feat_tsz > targ_tsz: + feat_tsz = int(targ_tsz / self.feat2tar_ratio) + features = features[..., :feat_tsz] + target_inds = torch.arange(feat_tsz).float() * self.feat2tar_ratio + target_list = [t[:, target_inds.long()] for t in target_list] + return features, target_list + + def forward_padding_mask( + self, features: torch.Tensor, padding_mask: torch.Tensor, + ) -> torch.Tensor: + extra = padding_mask.size(1) % features.size(1) + if extra > 0: + padding_mask = padding_mask[:, :-extra] + padding_mask = padding_mask.view( + padding_mask.size(0), features.size(1), -1 + ) + padding_mask = padding_mask.all(-1) + return padding_mask + + def forward( + self, + source: torch.Tensor, + target_list: Optional[List[torch.Tensor]] = None, + padding_mask: Optional[torch.Tensor] = None, + mask: bool = True, + features_only: bool = False, + output_layer: Optional[int] = None, + ) -> Dict[str, torch.Tensor]: + """output layer is 1-based""" + features = self.forward_features(source) + if target_list is not None: + features, target_list = self.forward_targets(features, target_list) + + features_pen = features.float().pow(2).mean() + + features = features.transpose(1, 2) + features = self.layer_norm(features) + unmasked_features = features.clone() + + if padding_mask is not None: + padding_mask = self.forward_padding_mask(features, padding_mask) + + if self.post_extract_proj is not None: + features = self.post_extract_proj(features) + + features = self.dropout_input(features) + unmasked_features = self.dropout_features(unmasked_features) + + if mask: + x, mask_indices = self.apply_mask( + features, padding_mask, target_list + ) + else: + x = features + mask_indices = None + + # feature: (B, T, D), float + # target: (B, T), long + # x: (B, T, D), float + # padding_mask: (B, T), bool + # mask_indices: (B, T), bool + x, _ = self.encoder( + x, + padding_mask=padding_mask, + layer=None if output_layer is None else output_layer - 1 + ) + + if features_only: + return {"x": x, "padding_mask": padding_mask, "features": features} + + def compute_pred(proj_x, target, label_embs): + # compute logits for the i-th label set + y = torch.index_select(label_embs, 0, target.long()) + negs = label_embs.unsqueeze(1).expand(-1, proj_x.size(0), -1) + if self.target_glu: + y = self.target_glu(y) + negs = self.target_glu(negs) + # proj_x: (S, D) + # y: (S, D) + # negs: (Neg, S, D) + return self.compute_nce(proj_x, y, negs) + + label_embs_list = self.label_embs_concat.split(self.num_classes, 0) + + if not self.skip_masked: + masked_indices = torch.logical_and(~padding_mask, mask_indices) + proj_x_m = self.final_proj(x[masked_indices]) + if self.untie_final_proj: + proj_x_m_list = proj_x_m.chunk(len(target_list), dim=-1) + else: + proj_x_m_list = [proj_x_m for _ in range(len(target_list))] + logit_m_list = [ + compute_pred(proj_x_m, t[masked_indices], label_embs_list[i]) + for i, (proj_x_m, t) in enumerate( + zip(proj_x_m_list, target_list) + ) + ] + else: + logit_m_list = [None for _ in target_list] + + if not self.skip_nomask: + nomask_indices = torch.logical_and(~padding_mask, ~mask_indices) + proj_x_u = self.final_proj(x[nomask_indices]) + if self.untie_final_proj: + proj_x_u_list = proj_x_u.chunk(len(target_list), dim=-1) + else: + proj_x_u_list = [proj_x_u for _ in range(len(target_list))] + + logit_u_list = [ + compute_pred(proj_x_u, t[nomask_indices], label_embs_list[i]) + for i, (proj_x_u, t) in enumerate( + zip(proj_x_u_list, target_list) + ) + ] + else: + logit_u_list = [None for _ in target_list] + + result = { + "logit_m_list": logit_m_list, + "logit_u_list": logit_u_list, + "padding_mask": padding_mask, + "features_pen": features_pen, + } + return result + + def extract_features( + self, + source: torch.Tensor, + padding_mask: Optional[torch.Tensor] = None, + mask: bool = False, + ret_conv: bool = False, + output_layer: Optional[int] = None, + ) -> Tuple[torch.Tensor, torch.Tensor]: + res = self.forward( + source, + padding_mask=padding_mask, + mask=mask, + features_only=True, + output_layer=output_layer, + ) + feature = res["features"] if ret_conv else res["x"] + return feature, res["padding_mask"] + + def get_logits(self, net_output, is_masked=True): + if is_masked: + logits_list = net_output["logit_m_list"] + else: + logits_list = net_output["logit_u_list"] + logits_list = [x.float() for x in logits_list if x is not None] + return logits_list + + def get_targets(self, net_output, is_masked=True): + logits_list = self.get_logits(net_output, is_masked) + targets_list = [ + x.new_zeros(x.size(0), dtype=torch.long) for x in logits_list + ] + return targets_list + + def get_extra_losses(self, net_output): + extra_losses = [] + names = [] + + if "features_pen" in net_output: + extra_losses.append(net_output["features_pen"]) + names.append("features_pen") + + return extra_losses, names + + def remove_pretraining_modules(self): + self.target_glu = None + self.final_proj = None diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py new file mode 100644 index 0000000000..4cb3fb7153 --- /dev/null +++ b/fairseq/models/hubert/hubert_asr.py @@ -0,0 +1,373 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import contextlib +from argparse import Namespace +from typing import Any + +import torch +import torch.nn as nn +from dataclasses import dataclass, field +from fairseq import checkpoint_utils, tasks, utils +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.models import BaseFairseqModel, FairseqEncoder, register_model +from fairseq.models.hubert.hubert import MASKING_DISTRIBUTION_CHOICES +from fairseq.tasks import FairseqTask +from omegaconf import II, MISSING + + +@dataclass +class HubertAsrConfig(FairseqDataclass): + w2v_path: str = field( + default=MISSING, metadata={"help": "path to hubert model"} + ) + no_pretrained_weights: bool = field( + default=False, + metadata={"help": "if true, does not load pretrained weights"}, + ) + dropout_input: float = field( + default=0.0, + metadata={"help": "dropout to apply to the input (after feat extr)"}, + ) + final_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout after transformer and before final projection" + }, + ) + dropout: float = field( + default=0.0, + metadata={"help": "dropout probability inside hubert model"}, + ) + attention_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability for attention weights " + "inside hubert model" + }, + ) + activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN " + "inside hubert model" + }, + ) + + # masking + apply_mask: bool = field( + default=False, metadata={"help": "apply masking during fine-tuning"} + ) + mask_length: int = field( + default=10, metadata={"help": "repeat the mask indices multiple times"} + ) + mask_prob: float = field( + default=0.5, + metadata={ + "help": "probability of replacing a token with mask " + "(normalized by length)" + }, + ) + mask_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose masks"} + ) + mask_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indices" + }, + ) + no_mask_overlap: bool = field( + default=False, metadata={"help": "whether to allow masks to overlap"} + ) + + # channel masking + mask_channel_length: int = field( + default=10, + metadata={"help": "length of the mask for features (channels)"}, + ) + mask_channel_prob: float = field( + default=0.0, + metadata={"help": "probability of replacing a feature with 0"}, + ) + mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", + metadata={"help": "how to choose mask length for channel masking"}, + ) + mask_channel_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indices" + }, + ) + no_mask_channel_overlap: bool = field( + default=False, + metadata={"help": "whether to allow channel masks to overlap"}, + ) + freeze_finetune_updates: int = field( + default=0, + metadata={"help": "dont finetune hubert for this many updates"}, + ) + feature_grad_mult: float = field( + default=0.0, + metadata={"help": "reset feature grad mult in hubert to this"}, + ) + layerdrop: float = field( + default=0.0, + metadata={"help": "probability of dropping a layer in hubert"}, + ) + normalize: bool = II("task.normalize") + data: str = II("task.data") + + # this holds the loaded hubert args + w2v_args: Any = None + + +@dataclass +class HubertCtcConfig(HubertAsrConfig): + pass + + +@register_model("hubert_ctc", dataclass=HubertCtcConfig) +class HubertCtc(BaseFairseqModel): + def __init__(self, cfg: HubertCtcConfig, w2v_encoder: BaseFairseqModel): + super().__init__() + self.cfg = cfg + self.w2v_encoder = w2v_encoder + + def upgrade_state_dict_named(self, state_dict, name): + super().upgrade_state_dict_named(state_dict, name) + return state_dict + + @classmethod + def build_model(cls, cfg: HubertCtcConfig, task: FairseqTask): + """Build a new model instance.""" + w2v_encoder = HubertEncoder(cfg, task.target_dictionary) + return cls(cfg, w2v_encoder) + + def get_normalized_probs(self, net_output, log_probs): + """Get normalized probabilities (or log probs) from a net's output.""" + + logits = net_output["encoder_out"] + if log_probs: + return utils.log_softmax(logits.float(), dim=-1) + else: + return utils.softmax(logits.float(), dim=-1) + + def get_logits(self, net_output): + logits = net_output["encoder_out"] + padding = net_output["encoder_padding_mask"] + if padding is not None and padding.any(): + padding = padding.T + logits[padding][..., 0] = 0 + logits[padding][..., 1:] = float("-inf") + + return logits + + def forward(self, **kwargs): + x = self.w2v_encoder(**kwargs) + return x + + +@dataclass +class HubertSeq2SeqConfig(HubertAsrConfig): + decoder_embed_dim: int = field( + default=768, metadata={"help": "decoder embedding dimension"} + ) + decoder_ffn_embed_dim: int = field( + default=3072, metadata={"help": "decoder embedding dimension for FFN"} + ) + decoder_layers: int = field( + default=6, metadata={"help": "num of decoder layers"} + ) + decoder_layerdrop: float = field( + default=0.0, metadata={"help": "decoder layerdrop chance"} + ) + decoder_attention_heads: int = field( + default=4, metadata={"help": "num decoder attention heads"} + ) + decoder_learned_pos: bool = field( + default=False, + metadata={"help": "use learned positional embeddings in the decoder"}, + ) + decoder_normalize_before: bool = field( + default=False, + metadata={"help": "apply layernorm before each decoder block"}, + ) + no_token_positional_embeddings: bool = field( + default=False, + metadata={ + "help": "if set, disables positional embeddings " + "(outside self attention)" + }, + ) + decoder_dropout: float = field( + default=0.0, metadata={"help": "dropout probability in the decoder"} + ) + decoder_attention_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability for attention weights " + "inside the decoder" + }, + ) + decoder_activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN " + "inside the decoder" + }, + ) + max_target_positions: int = field( + default=2048, metadata={"help": "max target positions"} + ) + share_decoder_input_output_embed: bool = field( + default=False, + metadata={"help": "share decoder input and output embeddings"}, + ) + + +class HubertEncoder(FairseqEncoder): + def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): + self.apply_mask = cfg.apply_mask + + arg_overrides = { + "dropout": cfg.dropout, + "activation_dropout": cfg.activation_dropout, + "dropout_input": cfg.dropout_input, + "attention_dropout": cfg.attention_dropout, + "mask_length": cfg.mask_length, + "mask_prob": cfg.mask_prob, + "mask_selection": cfg.mask_selection, + "mask_other": cfg.mask_other, + "no_mask_overlap": cfg.no_mask_overlap, + "mask_channel_length": cfg.mask_channel_length, + "mask_channel_prob": cfg.mask_channel_prob, + "mask_channel_selection": cfg.mask_channel_selection, + "mask_channel_other": cfg.mask_channel_other, + "no_mask_channel_overlap": cfg.no_mask_channel_overlap, + "encoder_layerdrop": cfg.layerdrop, + "feature_grad_mult": cfg.feature_grad_mult, + } + + if cfg.w2v_args is None: + state = checkpoint_utils.load_checkpoint_to_cpu( + cfg.w2v_path, arg_overrides + ) + w2v_args = state.get("cfg", None) + if w2v_args is None: + w2v_args = convert_namespace_to_omegaconf(state["args"]) + cfg.w2v_args = w2v_args + else: + state = None + w2v_args = cfg.w2v_args + if isinstance(w2v_args, Namespace): + cfg.w2v_args = w2v_args = convert_namespace_to_omegaconf( + w2v_args + ) + + assert cfg.normalize == w2v_args.task.normalize, ( + "Fine-tuning works best when data normalization is the same. " + "Please check that --normalize is set or unset for " + "both pre-training and here" + ) + + w2v_args.task.data = cfg.data + task = tasks.setup_task(w2v_args.task) + model = task.build_model(w2v_args.model) + + if state is not None and not cfg.no_pretrained_weights: + # set strict=False because we omit some modules + model.load_state_dict(state["model"], strict=False) + + model.remove_pretraining_modules() + + super().__init__(task.source_dictionary) + + d = w2v_args.model.encoder_embed_dim + + self.w2v_model = model + + self.final_dropout = nn.Dropout(cfg.final_dropout) + self.freeze_finetune_updates = cfg.freeze_finetune_updates + self.num_updates = 0 + + if tgt_dict is not None: + self.proj = Linear(d, len(tgt_dict)) + elif getattr(cfg, "decoder_embed_dim", d) != d: + self.proj = Linear(d, cfg.decoder_embed_dim) + else: + self.proj = None + + def set_num_updates(self, num_updates): + """Set the number of parameters updates.""" + super().set_num_updates(num_updates) + self.num_updates = num_updates + + def forward(self, source, padding_mask, tbc=True, **kwargs): + + w2v_args = { + "source": source, + "padding_mask": padding_mask, + "mask": self.apply_mask and self.training, + } + + ft = self.freeze_finetune_updates <= self.num_updates + + with torch.no_grad() if not ft else contextlib.ExitStack(): + x, padding_mask = self.w2v_model.extract_features(**w2v_args) + + if tbc: + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + x = self.final_dropout(x) + + if self.proj: + x = self.proj(x) + + return { + "encoder_out": x, # T x B x C + "encoder_padding_mask": padding_mask, # B x T + "padding_mask": padding_mask, + } + + def reorder_encoder_out(self, encoder_out, new_order): + if encoder_out["encoder_out"] is not None: + encoder_out["encoder_out"] = encoder_out[ + "encoder_out" + ].index_select(1, new_order) + if encoder_out["encoder_padding_mask"] is not None: + encoder_out["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ].index_select(0, new_order) + return encoder_out + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return None + + def upgrade_state_dict_named(self, state_dict, name): + return state_dict + + +def Embedding(num_embeddings, embedding_dim, padding_idx): + m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) + nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.constant_(m.weight[padding_idx], 0) + return m + + +def Linear(in_features, out_features, bias=True): + m = nn.Linear(in_features, out_features, bias) + nn.init.xavier_uniform_(m.weight) + if bias: + nn.init.constant_(m.bias, 0.0) + return m diff --git a/fairseq/tasks/hubert_pretraining.py b/fairseq/tasks/hubert_pretraining.py new file mode 100644 index 0000000000..aff4100bb8 --- /dev/null +++ b/fairseq/tasks/hubert_pretraining.py @@ -0,0 +1,189 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import os +import sys +from typing import Dict, List, Optional, Tuple + +import numpy as np + +from dataclasses import dataclass, field +from fairseq.data import Dictionary, HubertDataset +from fairseq.dataclass.configs import FairseqDataclass +from fairseq.tasks import register_task +from fairseq.tasks.fairseq_task import FairseqTask +from omegaconf import MISSING + +logger = logging.getLogger(__name__) + + +class LabelEncoder(object): + def __init__(self, dictionary: Dictionary) -> None: + self.dictionary = dictionary + + def __call__(self, label: str) -> List[str]: + return self.dictionary.encode_line( + label, append_eos=False, add_if_not_exist=False, + ) + + +@dataclass +class HubertPretrainingConfig(FairseqDataclass): + data: str = field( + default=MISSING, metadata={"help": "path to data directory"} + ) + labels: List[str] = field( + default_factory=lambda: ["ltr"], + metadata={ + "help": ( + "extension of the label files to load, frame-level labels for" + " pre-training, and sequence-level label for fine-tuning" + ) + }, + ) + label_dir: Optional[str] = field( + default=None, + metadata={ + "help": "if set, looks for labels in this directory instead", + }, + ) + label_rate: int = field( + default=-1, + metadata={"help": "label frame rate. -1 for sequence label"}, + ) + + sample_rate: int = field( + default=16_000, + metadata={ + "help": "target sample rate. audio files will be up/down " + "sampled to this rate" + }, + ) + normalize: bool = field( + default=False, + metadata={ + "help": "if set, normalizes input to have 0 mean and unit variance" + }, + ) + enable_padding: bool = field( + default=False, + metadata={"help": "pad shorter samples instead of cropping"}, + ) + max_sample_size: Optional[int] = field( + default=None, + metadata={"help": "max sample size to crop to for batching"}, + ) + min_sample_size: Optional[int] = field( + default=None, + metadata={"help": "min sample size to crop to for batching"}, + ) + single_target: Optional[bool] = field( + default=False, + metadata={ + "help": "if set, AddTargetDatasets outputs same keys " + "as AddTargetDataset" + }, + ) + random_crop: Optional[bool] = field( + default=True, + metadata={"help": "always crop from the beginning if false"}, + ) + pad_audio: Optional[bool] = field( + default=False, + metadata={"help": "pad audio to the longest one in the batch if true"}, + ) + + +@register_task("hubert_pretraining", dataclass=HubertPretrainingConfig) +class HubertPretrainingTask(FairseqTask): + + cfg: HubertPretrainingConfig + + def __init__( + self, + cfg: HubertPretrainingConfig, + dictionaries: Dict[str, Dictionary], + ) -> None: + super().__init__(cfg) + + logger.info(f"current directory is {os.getcwd()}") + logger.info(f"HubertPretrainingTask Config {cfg}") + self._dictionaries = dictionaries + + self._source_dictionary = None + self._target_dictionary = None + + if len(self.dictionaries) == 1: + self._target_dictionary = self.dictionaries[0] + self.blank_symbol = "<s>" + + @property + def source_dictionary(self) -> Optional[Dictionary]: + return self._source_dictionary + + @property + def target_dictionary(self) -> Optional[Dictionary]: + return self._target_dictionary + + @property + def dictionaries(self) -> List[Dictionary]: + return [self._dictionaries[l] for l in self.cfg.labels] + + @classmethod + def setup_task( + cls, cfg: HubertPretrainingConfig, **kwargs + ) -> "HubertPretrainingTask": + label_dir = cfg.data if cfg.label_dir is None else cfg.label_dir + dictionaries = { + label: Dictionary.load(f"{label_dir}/dict.{label}.txt") + if os.path.exists(f"{label_dir}/dict.{label}.txt") + else None + for label in cfg.labels + } + return cls(cfg, dictionaries) + + def get_label_dir(self) -> str: + if self.cfg.label_dir is None: + return self.cfg.data + return self.cfg.label_dir + + def load_dataset(self, split: str, **kwargs) -> None: + manifest = f"{self.cfg.data}/{split}.tsv" + pad_list = [self._dictionaries[l].pad() for l in self.cfg.labels] + eos_list = [self._dictionaries[l].eos() for l in self.cfg.labels] + procs = [LabelEncoder(self._dictionaries[l]) for l in self.cfg.labels] + paths = [ + f"{self.get_label_dir()}/{split}.{l}" for l in self.cfg.labels + ] + + # hubert v1: pad_audio=True, random_crop=False; + self.datasets[split] = HubertDataset( + manifest, + sample_rate=self.cfg.sample_rate, + label_paths=paths, + label_rates=self.cfg.label_rate, + pad_list=pad_list, + eos_list=eos_list, + label_processors=procs, + max_keep_sample_size=None, + min_keep_sample_size=self.cfg.min_sample_size, + max_sample_size=self.cfg.max_sample_size, + pad_audio=self.cfg.pad_audio, + normalize=self.cfg.normalize, + store_labels=False, + random_crop=self.cfg.random_crop, + single_target=self.cfg.single_target, + ) + + def max_positions(self) -> Tuple[int, int]: + return (sys.maxsize, sys.maxsize) + + def filter_indices_by_size( + self, indices: np.array, *args, **kwargs + ) -> np.array: + return indices From 49cf3e0bc389f0c704f7540c7d45100066ce7f7c Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Sat, 22 May 2021 00:21:06 -0700 Subject: [PATCH 343/774] fixing s2t transformer and N-best checkpoint saving Summary: - fixing the default value for `encoder_freezing_updates` in s2t transformer - fixing N-best checkpoint saving: the previous implementation compares the new checkpoint with only the previous best one but not the previous N best ones. This leads to suboptimal results on N-best checkpoint averaging. Reviewed By: jmp84 Differential Revision: D28546493 fbshipit-source-id: 44ec6d5ab49347f392d71269c5dcfd154b00c11e --- fairseq/checkpoint_utils.py | 20 +++++++++++++++---- .../models/speech_to_text/s2t_transformer.py | 3 +-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 23677be83d..b1a19d8515 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -12,6 +12,7 @@ import traceback from collections import OrderedDict from typing import Any, Dict, Optional, Union +from random import randint import torch from fairseq.dataclass.configs import CheckpointConfig, FairseqConfig @@ -76,11 +77,22 @@ def is_better(a, b): or is_better(val_loss, save_checkpoint.best) ) if val_loss is not None and cfg.keep_best_checkpoints > 0: - checkpoint_conds[ - "checkpoint.best_{}_{:.2f}.pt".format(cfg.best_checkpoint_metric, val_loss) - ] = not hasattr(save_checkpoint, "best") or is_better( - val_loss, save_checkpoint.best + worst_best = getattr(save_checkpoint, "best", None) + chkpts = checkpoint_paths( + cfg.save_dir, + pattern=r"checkpoint\.best_{}_(\d+\.?\d*)\.pt".format( + cfg.best_checkpoint_metric + ), ) + if len(chkpts) > 0: + p = chkpts[-1] if cfg.maximize_best_checkpoint_metric else chkpts[0] + worst_best = float(p.rsplit("_")[-1].replace(".pt", "")) + # add random digits to resolve ties + rand_sfx = randint(0, cfg.keep_best_checkpoints) + checkpoint_conds[ + "checkpoint.best_{}_{:.3f}{}.pt".format(cfg.best_checkpoint_metric, + val_loss, rand_sfx) + ] = worst_best is None or is_better(val_loss, worst_best) checkpoint_conds[ "checkpoint_last{}.pt".format(suffix) ] = not cfg.no_last_checkpoints diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index ff3d2100c7..5c935efaf5 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -203,7 +203,6 @@ def add_args(parser): ) parser.add_argument( '--encoder-freezing-updates', - default=None, type=int, metavar='N', help='freeze encoder for first N updates' @@ -279,7 +278,7 @@ class S2TTransformerEncoder(FairseqEncoder): def __init__(self, args): super().__init__(None) - self.encoder_freezing_updates = getattr(args, "encoder_freezing_updates", 0) + self.encoder_freezing_updates = args.encoder_freezing_updates self.num_updates = 0 self.dropout_module = FairseqDropout( From 366974d9817138d1618693f021ea1690f9e53f33 Mon Sep 17 00:00:00 2001 From: Patrick von Platen <patrick.v.platen@gmail.com> Date: Sun, 23 May 2021 16:18:55 -0700 Subject: [PATCH 344/774] HF Wav2Vec2 Example (#3502) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## What does this PR do? This PR updates some outdated code from the Hugging Face Transformers library to the new, better format. ## PR review alexeib ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3502 Reviewed By: arbabu123 Differential Revision: D28140574 Pulled By: alexeib fbshipit-source-id: f03643e7ebba04015d942a3aa9529f7f6600c734 --- examples/wav2vec/README.md | 41 +++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index bfed3913cf..238639a9ba 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -149,31 +149,54 @@ To get raw numbers, use --w2l-decoder viterbi and omit the lexicon. To use the t ## Use wav2vec 2.0 with 🤗Transformers: -Wav2Vec2 is also available in the [🤗Transformers library](https://github.com/huggingface/transformers) since version 4.3. +Wav2Vec2 is also available in the [🤗Transformers library](https://github.com/huggingface/transformers) since version 4.4. -Pretrained Models can be found on the [hub](https://huggingface.co/models?filter=wav2vec2) +Pretrained Models can be found on the [hub](https://huggingface.co/models?filter=wav2vec2) and documentation can be found [here](https://huggingface.co/transformers/master/model_doc/wav2vec2.html). Usage example: ```python # !pip install transformers +# !pip install datasets import soundfile as sf import torch -from transformers import Wav2Vec2ForMaskedLM, Wav2Vec2Tokenizer +from datasets import load_dataset +from transformers import Wav2Vec2ForCTC, Wav2Vec2Processor # load pretrained model -tokenizer = Wav2Vec2Tokenizer.from_pretrained("facebook/wav2vec2-base-960h") -model = Wav2Vec2ForMaskedLM.from_pretrained("facebook/wav2vec2-base-960h") +processor = Wav2Vec2Processor.from_pretrained("facebook/wav2vec2-base-960h") +model = Wav2Vec2ForCTC.from_pretrained("facebook/wav2vec2-base-960h") + + +librispeech_samples_ds = load_dataset("patrickvonplaten/librispeech_asr_dummy", "clean", split="validation") # load audio -audio_input, _ = sf.read("path/to/audio/file") +audio_input, sample_rate = sf.read(librispeech_samples_ds[0]["file"]) -# transcribe -input_values = tokenizer(audio_input, return_tensors="pt").input_values +# pad input values and return pt tensor +input_values = processor(audio_input, sampling_rate=sample_rate, return_tensors="pt").input_values + +# INFERENCE + +# retrieve logits & take argmax logits = model(input_values).logits predicted_ids = torch.argmax(logits, dim=-1) -transcription = tokenizer.batch_decode(predicted_ids)[0] + +# transcribe +transcription = processor.decode(predicted_ids[0]) + +# FINE-TUNE + +target_transcription = "A MAN SAID TO THE UNIVERSE I EXIST" + +# encode labels +with processor.as_target_processor(): + labels = processor(target_transcription, return_tensors="pt").input_ids + +# compute loss by passing labels +loss = model(input_values, labels=labels).loss +loss.backward() ``` # wav2vec From 342d5daf34acaf34c93b5a0a313f46bc4104c7fc Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Sun, 23 May 2021 21:24:38 -0700 Subject: [PATCH 345/774] propagate quantizer depth and factor args through w2v (#1892) Summary: makes quantizer larger which helps accuracy in certain cases Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1892 Reviewed By: arbabu123 Differential Revision: D28630035 Pulled By: alexeib fbshipit-source-id: ba5a902ff1623025e7566e901aa81cdf377a7aa0 --- fairseq/models/wav2vec/wav2vec2.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 6002d28438..714fd3ab50 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -119,6 +119,16 @@ class Wav2Vec2Config(FairseqDataclass): feature_grad_mult: float = field( default=1.0, metadata={"help": "multiply feature extractor var grads by this"} ) + quantizer_depth: int = field( + default=1, + metadata={"help": "number of quantizer layers"}, + ) + quantizer_factor: int = field( + default=3, + metadata={ + "help": "dimensionality increase for inner quantizer layers (if depth > 1)" + }, + ) latent_vars: int = field( default=320, metadata={"help": "number of latent variables V in each group of the codebook"}, @@ -284,6 +294,8 @@ def __init__(self, cfg: Wav2Vec2Config): combine_groups=False, vq_dim=vq_dim, time_first=True, + weight_proj_depth=cfg.quantizer_depth, + weight_proj_factor=cfg.quantizer_factor, ) self.project_q = nn.Linear(vq_dim, final_dim) else: @@ -303,6 +315,8 @@ def __init__(self, cfg: Wav2Vec2Config): combine_groups=False, vq_dim=vq_dim, time_first=True, + weight_proj_depth=cfg.quantizer_depth, + weight_proj_factor=cfg.quantizer_factor, ) self.project_inp = nn.Linear(vq_dim, cfg.encoder_embed_dim) From 2be2f3c7c1ba9ec3ee6ef929f7edce13052b6844 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Mon, 24 May 2021 08:58:56 -0700 Subject: [PATCH 346/774] Plasma tests: ask for less disk (#1893) Summary: Old logs: ``` /arrow/cpp/src/plasma/store.cc:1274: Allowing the Plasma store to use up to 107.374GB of memory. ``` New logs: ``` ... up to 1e-05GB of memory. ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1893 Reviewed By: myleott Differential Revision: D28641488 Pulled By: sshleifer fbshipit-source-id: 3373526042cdcbf434c61790be62a09f15e6ad06 --- tests/test_plasma_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_plasma_utils.py b/tests/test_plasma_utils.py index a5cf386b86..e6344c2a5a 100644 --- a/tests/test_plasma_utils.py +++ b/tests/test_plasma_utils.py @@ -23,7 +23,7 @@ class TestPlasmaView(unittest.TestCase): def setUp(self) -> None: self.tmp_file = tempfile.NamedTemporaryFile() # noqa: P201 self.path = self.tmp_file.name - self.server = PlasmaStore.start(path=self.path) + self.server = PlasmaStore.start(path=self.path, nbytes=10000) self.client = plasma.connect(self.path, num_retries=10) def tearDown(self) -> None: From 30003ba4192f173d84cb0dbfee678296d8af6378 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Mon, 24 May 2021 19:09:23 -0700 Subject: [PATCH 347/774] fix serialization on python 3.6 (#1894) Summary: fixes serialization errors when using python 3.6 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1894 Reviewed By: arbabu123 Differential Revision: D28655932 Pulled By: alexeib fbshipit-source-id: df40f972966e828817a2861e6e907835fe1d9573 --- fairseq/optim/adam.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fairseq/optim/adam.py b/fairseq/optim/adam.py index cfe948a194..6a31e53a62 100644 --- a/fairseq/optim/adam.py +++ b/fairseq/optim/adam.py @@ -15,7 +15,7 @@ from fairseq.dataclass import FairseqDataclass from fairseq.optim import FairseqOptimizer, register_optimizer from fairseq.optim.fused_adam import get_fused_adam_class -from omegaconf import II, DictConfig +from omegaconf import II, OmegaConf logger = logging.getLogger(__name__) @@ -77,7 +77,9 @@ def optimizer_config(self): "lr": self.cfg.lr[0] if isinstance(self.cfg.lr, Collection) else self.cfg.lr, - "betas": eval(self.cfg.adam_betas) if isinstance(self.cfg.adam_betas, str) else self.cfg.adam_betas, + "betas": eval(self.cfg.adam_betas) + if isinstance(self.cfg.adam_betas, str) + else OmegaConf.to_container(self.cfg.adam_betas), "eps": self.cfg.adam_eps, "weight_decay": self.cfg.weight_decay, } From 5a75b079bf8911a327940c28794608e003a9fa52 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Mon, 24 May 2021 19:56:14 -0700 Subject: [PATCH 348/774] fix saving w2v args in config (#1896) Summary: previous changes broke saving updating w2v_args in config as the model had a copy of the config. this change makes the task copy over the field to save. not the nicest approach, but it works for now Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1896 Reviewed By: arbabu123 Differential Revision: D28658802 Pulled By: alexeib fbshipit-source-id: a13866c42c3b88c48b8b91864c1bf1aeaeba4e8a --- fairseq/tasks/audio_pretraining.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index e0b001b667..71cefcfcaa 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -303,6 +303,12 @@ def build_model(self, model_cfg: FairseqDataclass): self.tokenizer = encoders.build_tokenizer(self.cfg.eval_wer_tokenizer) else: self.tokenizer = None + + actualized_cfg = getattr(model, "cfg") + if actualized_cfg is not None: + if "w2v_args" in actualized_cfg: + model_cfg.w2v_args = actualized_cfg.w2v_args + return model def _inference_with_wer(self, generator, sample, model): From 95cf58056dc30a9fa653dd8adcbd5b76a180a63d Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushall@fb.com> Date: Tue, 25 May 2021 13:43:42 -0700 Subject: [PATCH 349/774] Update model table in README (#1901) Summary: ## What does this PR do? Updated the models' table in README to show the model sizes and groups pretrained models followed by fine tuned models. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1901 Reviewed By: wnhsu Differential Revision: D28688952 Pulled By: hikushalhere fbshipit-source-id: 8621398a785caa3d7bdc68367789ad7f48499d0d --- examples/hubert/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/hubert/README.md b/examples/hubert/README.md index 88973c22f2..ca714469c6 100644 --- a/examples/hubert/README.md +++ b/examples/hubert/README.md @@ -3,12 +3,13 @@ ## Pre-trained and fine-tuned (ASR) models Model | Pretraining Data | Finetuning Dataset | Model |---|---|---|--- -HuBERT Base | [Librispeech](http://www.openslr.org/12) 960 hr | No finetuning | [download](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) -HuBERT Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k.pt) +HuBERT Base (~95M params) | [Librispeech](http://www.openslr.org/12) 960 hr | No finetuning (Pretrained Model) | [download](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) +HuBERT Large (~316M params) | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning (Pretrained Model) | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k.pt) +HuBERT Extra Large (~1B params) | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning (Pretrained Model) | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k.pt) HuBERT Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k_finetune_ls960.pt) -HuBERT Extra Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k.pt) HuBERT Extra Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k_finetune_ls960.pt) + ## Train a new model ### Data preparation From 8df9e3a4a55bad55078967e97e8a8f31d90ec987 Mon Sep 17 00:00:00 2001 From: Weiyi Zheng <wyz@fb.com> Date: Tue, 25 May 2021 17:45:04 -0700 Subject: [PATCH 350/774] support FSDP sharded_state checkpoint loading during inference Summary: using the very useful feature added by QuentinDuval https://github.com/facebookresearch/fairscale/pull/683/files , we can consolidate sharded states into a full regular states. this allows inferences on sharded state almost transparently. The main complexity comes from trying to be smart about what kind of checkpoint the user wants to load. not sure if this is over-engineering 1. if the file checkpoint-shard0.pt exists, and `--checkpoint-shard-count` is > 1, then we load sharded FSDP checkpoint 2. if checkpoint-shard0.pt exists but --checkpoint-shard-count=1, we load consolidated FSDP checkpoint 3. if checkpoint-shard0.pt does not exist, but --checkpoint-shard-count > 1, we load model parallel checkpoint 4. otherwise we are loading a single, plain checkpoint. In theory we could be even smarter and load shard0.pt to check how many more checkpoints are needed. this is not implemented, though it will save the user having to specify --checkpoint-shard-count. Reviewed By: sshleifer Differential Revision: D28563441 fbshipit-source-id: dcafcaa7c9eaf5c9ff94f55c16bb3424c98dfa59 --- fairseq/checkpoint_utils.py | 78 ++++++++++++++++++++++++++++------ fairseq/trainer.py | 3 ++ tests/gpu/test_binaries_gpu.py | 32 ++++++++++++++ 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index b1a19d8515..ecc45f4351 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -9,6 +9,7 @@ import logging import os import re +import time import traceback from collections import OrderedDict from typing import Any, Dict, Optional, Union @@ -20,6 +21,7 @@ convert_namespace_to_omegaconf, overwrite_args_by_name, ) +from fairseq.distributed.fully_sharded_data_parallel import FSDP, has_FSDP from fairseq.file_io import PathManager from fairseq.models import FairseqDecoder, FairseqEncoder from omegaconf import Container, DictConfig, open_dict, OmegaConf @@ -134,9 +136,15 @@ def is_better(a, b): ) else: checkpoints = checkpoint_paths( - cfg.save_dir, pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix), keep_match=True + cfg.save_dir, + pattern=r"checkpoint_\d+_(\d+){}\.pt".format(suffix), + keep_match=True, ) - checkpoints = [x[0] for x in checkpoints if x[1] % cfg.keep_interval_updates_pattern != 0] + checkpoints = [ + x[0] + for x in checkpoints + if x[1] % cfg.keep_interval_updates_pattern != 0 + ] for old_chk in checkpoints[cfg.keep_interval_updates :]: if os.path.lexists(old_chk): @@ -146,7 +154,9 @@ def is_better(a, b): if cfg.keep_last_epochs > 0: # remove old epoch checkpoints; checkpoints are sorted in descending order - checkpoints = checkpoint_paths(cfg.save_dir, pattern=r"checkpoint(\d+){}\.pt".format(suffix)) + checkpoints = checkpoint_paths( + cfg.save_dir, pattern=r"checkpoint(\d+){}\.pt".format(suffix) + ) for old_chk in checkpoints[cfg.keep_last_epochs :]: if os.path.lexists(old_chk): os.remove(old_chk) @@ -351,6 +361,21 @@ def load_model_ensemble( return ensemble, args +def get_maybe_sharded_checkpoint_filename( + filename: str, suffix: str, shard_idx: int, num_shards: int +) -> str: + orig_filename = filename + filename = filename.replace(".pt", suffix + ".pt") + fsdp_filename = filename[:-3] + f"-shard{shard_idx}.pt" + model_parallel_filename = orig_filename[:-3] + f"_part{shard_idx}.pt" + if PathManager.exists(fsdp_filename): + return fsdp_filename + elif num_shards > 1: + return model_parallel_filename + else: + return filename + + def load_model_ensemble_and_task( filenames, arg_overrides: Optional[Dict[str, Any]] = None, @@ -371,12 +396,13 @@ def load_model_ensemble_and_task( cfg = None for filename in filenames: orig_filename = filename + model_shard_state = {"shard_weights": [], "shard_metadata": []} assert num_shards > 0 + st = time.time() for shard_idx in range(num_shards): - if num_shards == 1: - filename = filename.replace(".pt", suffix + ".pt") - else: - filename = orig_filename[:-3] + f"_part{shard_idx}.pt" + filename = get_maybe_sharded_checkpoint_filename( + orig_filename, suffix, shard_idx, num_shards + ) if not PathManager.exists(filename): raise IOError("Model file not found: {}".format(filename)) @@ -397,14 +423,38 @@ def load_model_ensemble_and_task( if "task_state" in state: task.load_state_dict(state["task_state"]) - # build model for ensemble - model = task.build_model(cfg.model) - - model.load_state_dict(state["model"], strict=strict, model_cfg=cfg.model) + if "fsdp_metadata" in state and num_shards > 1: + model_shard_state["shard_weights"].append(state["model"]) + model_shard_state["shard_metadata"].append(state["fsdp_metadata"]) + # check FSDP import before the code goes too far + if not has_FSDP: + raise ImportError( + "Cannot find FullyShardedDataParallel. " + "Please install fairscale with: pip install fairscale" + ) + if shard_idx == num_shards - 1: + consolidated_model_state = FSDP.consolidate_shard_weights( + shard_weights=model_shard_state["shard_weights"], + shard_metadata=model_shard_state["shard_metadata"], + ) + model = task.build_model(cfg.model) + model.load_state_dict( + consolidated_model_state, strict=strict, model_cfg=cfg.model + ) + else: + # model parallel checkpoint or unsharded checkpoint + model = task.build_model(cfg.model) + model.load_state_dict( + state["model"], strict=strict, model_cfg=cfg.model + ) # reset state so it gets loaded for the next model in ensemble state = None + if shard_idx % 10 == 0 and shard_idx > 0: + elapsed = time.time() - st + logger.info(f"Loaded {shard_idx} shards in {elapsed:.2f}s, {elapsed / (shard_idx+1):.2f}s/shard") + # build model for ensemble ensemble.append(model) return ensemble, cfg, task @@ -500,8 +550,10 @@ def _upgrade_state_dict(state): if "num_updates" not in state["optimizer_history"][-1]: state["optimizer_history"][-1]["num_updates"] = 0 # old model checkpoints may not have separate source/target positions - if "args" in state and hasattr(state["args"], "max_positions") and not hasattr( - state["args"], "max_source_positions" + if ( + "args" in state + and hasattr(state["args"], "max_positions") + and not hasattr(state["args"], "max_source_positions") ): state["args"].max_source_positions = state["args"].max_positions state["args"].max_target_positions = state["args"].max_positions diff --git a/fairseq/trainer.py b/fairseq/trainer.py index d3da876c29..924b2b6b34 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -395,6 +395,9 @@ def state_dict(self): self._gathered_optim_state = None else: state_dict["last_optimizer_state"] = self.optimizer.state_dict() + if self.cfg.distributed_training.ddp_backend == "fully_sharded": + # save meta data for recombining checkpoint upon loading + state_dict["fsdp_metadata"] = self.model.local_metadata_dict() return state_dict def save_checkpoint(self, filename, extra_state): diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index a0824c23ad..54dc96079f 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -184,6 +184,38 @@ def test_levenshtein_transformer(self): ), ) + def test_fsdp_checkpoint_generate(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_fsdp_sharded") as data_dir: + log = os.path.join(data_dir, "train.log") + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + world_size = min(torch.cuda.device_count(), 2) + train_translation_model( + data_dir, + "fconv_iwslt_de_en", + ["--log-file", log, "--ddp-backend", "fully_sharded"], + world_size=world_size, + ) + generate_main(data_dir) + assert os.path.exists(log) + + def test_fsdp_sharded_checkpoint_generate(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_fsdp_sharded") as data_dir: + log = os.path.join(data_dir, "train.log") + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + world_size = min(torch.cuda.device_count(), 2) + train_translation_model( + data_dir, + "fconv_iwslt_de_en", + ["--log-file", log, "--ddp-backend", "fully_sharded", "--use-sharded-state"], + world_size=world_size, + ) + generate_main(data_dir, ["--checkpoint-shard-count", str(world_size)]) + assert os.path.exists(log) + def _quantize_language_model(data_dir, arch, extra_flags=None, run_validation=False): train_parser = options.get_training_parser() From 237184e5222b347475456f4a44f31a510c64ca35 Mon Sep 17 00:00:00 2001 From: Gagandeep Singh <gagandeep.singh1@nuance.com> Date: Wed, 26 May 2021 14:38:16 -0700 Subject: [PATCH 351/774] Add torch.cuda.amp support (#3460) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3282 Add support for `torch.cuda.amp` AMP can be enabled by `--amp`, instead of using `--fp16` for the already present full fp16 support. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3460 Reviewed By: sshleifer, msbaines Differential Revision: D27932253 Pulled By: myleott fbshipit-source-id: 21637aefb5e788c59bf4f3c5de6c4a80f7319543 --- .../pointer_generator_src/transformer_pg.py | 10 +- fairseq/dataclass/configs.py | 14 ++- fairseq/optim/__init__.py | 2 + fairseq/optim/amp_optimizer.py | 105 ++++++++++++++++++ fairseq/tasks/fairseq_task.py | 4 +- fairseq/trainer.py | 42 +++++-- tests/gpu/test_binaries_gpu.py | 34 ++++++ tests/test_amp_optimizer.py | 78 +++++++++++++ tests/test_reproducibility.py | 12 ++ 9 files changed, 285 insertions(+), 16 deletions(-) create mode 100644 fairseq/optim/amp_optimizer.py create mode 100644 tests/test_amp_optimizer.py diff --git a/examples/pointer_generator/pointer_generator_src/transformer_pg.py b/examples/pointer_generator/pointer_generator_src/transformer_pg.py index e109a8e269..4ccf30f4eb 100644 --- a/examples/pointer_generator/pointer_generator_src/transformer_pg.py +++ b/examples/pointer_generator/pointer_generator_src/transformer_pg.py @@ -8,7 +8,7 @@ import torch import torch.nn as nn -from fairseq import metrics, utils +from fairseq import utils from fairseq.models import register_model, register_model_architecture from fairseq.models.transformer import ( DEFAULT_MAX_SOURCE_POSITIONS, @@ -300,7 +300,7 @@ def forward( prev_output_embed *= self.embed_scale predictors = torch.cat((prev_output_embed, x), 2) p_gens = self.project_p_gens(predictors) - p_gens = torch.sigmoid(p_gens) + p_gens = torch.sigmoid(p_gens.float()) # Torchscript complains if encoder_out or attn are None because # `output_layer()` signature expects tensors instead attn: Optional[Tensor] = extra["attn"][0] @@ -351,18 +351,18 @@ def output_layer( # vocab_size]. Each attention weight will be written into a location # that is for other dimensions the same as in the index tensor, but for # the third dimension it's the value of the index tensor (the token ID). - attn = torch.mul(attn, 1 - p_gens) + attn = torch.mul(attn.float(), 1 - p_gens) index = src_tokens[:, None, :] index = index.expand(batch_size, output_length, src_length) attn_dists_size = (batch_size, output_length, self.num_types) attn_dists = attn.new_zeros(attn_dists_size) - attn_dists.scatter_add_(2, index, attn) + attn_dists.scatter_add_(2, index, attn.float()) # Final distributions, [batch_size, output_length, num_types]. return gen_dists + attn_dists def get_normalized_probs( - self, + self, net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], log_probs: bool, sample: Optional[Dict[str, Tensor]] = None, diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index f41cfcd94f..70d7476d31 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -150,11 +150,23 @@ class CommonConfig(FairseqDataclass): ) min_loss_scale: float = field( default=1e-4, - metadata={"help": "minimum FP16 loss scale, after which training is stopped"}, + metadata={"help": "minimum FP16/AMP loss scale, after which training is stopped"}, ) threshold_loss_scale: Optional[float] = field( default=None, metadata={"help": "threshold FP16 loss scale from below"} ) + amp: bool = field(default=False, metadata={"help": "use automatic mixed precision"}) + amp_batch_retries: int = field( + default=2, + metadata={"help": "number of retries of same batch after reducing loss scale with AMP"}, + ) + amp_init_scale: int = field( + default=2 ** 7, metadata={"help": "default AMP loss scale"} + ) + amp_scale_window: Optional[int] = field( + default=None, + metadata={"help": "number of updates before increasing AMP loss scale"}, + ) user_dir: Optional[str] = field( default=None, metadata={ diff --git a/fairseq/optim/__init__.py b/fairseq/optim/__init__.py index 01c08c98d2..be783be896 100644 --- a/fairseq/optim/__init__.py +++ b/fairseq/optim/__init__.py @@ -13,11 +13,13 @@ FairseqOptimizer, LegacyFairseqOptimizer, ) +from fairseq.optim.amp_optimizer import AMPOptimizer from fairseq.optim.fp16_optimizer import FP16Optimizer, MemoryEfficientFP16Optimizer from fairseq.optim.shard import shard_ from omegaconf import DictConfig __all__ = [ + "AMPOptimizer", "FairseqOptimizer", "FP16Optimizer", "MemoryEfficientFP16Optimizer", diff --git a/fairseq/optim/amp_optimizer.py b/fairseq/optim/amp_optimizer.py new file mode 100644 index 0000000000..3b7958e50c --- /dev/null +++ b/fairseq/optim/amp_optimizer.py @@ -0,0 +1,105 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +import torch +from fairseq import optim +from omegaconf import DictConfig + +logger = logging.getLogger(__name__) + + +class AMPOptimizer(optim.FairseqOptimizer): + """ + Wrap an *optimizer* to support AMP (automatic mixed precision) training. + """ + + def __init__(self, cfg: DictConfig, params, fp32_optimizer, **kwargs): + super().__init__(cfg.optimizer) + self.fp32_optimizer = fp32_optimizer + amp_kwargs = {"init_scale": cfg.common.fp16_init_scale} + if getattr(cfg.common, "amp_scale_window", None) is not None: + amp_kwargs["growth_interval"] = cfg.common.amp_init_scale + self._grad_scaler = torch.cuda.amp.GradScaler(**amp_kwargs) + self.min_loss_scale = cfg.common.min_loss_scale + + @classmethod + def build_optimizer(cls, cfg: DictConfig, params, **kwargs): + """ + Args: + cfg (omegaconf.DictConfig): fairseq args + params (iterable): iterable of parameters to optimize + """ + fp32_optimizer = optim.build_optimizer(cfg.optimizer, params) + return cls(cfg, params, fp32_optimizer, **kwargs) + + def backward(self, loss): + """Computes the sum of gradients of the given tensor w.r.t. graph leaves. + + Compared to :func:`fairseq.optim.FairseqOptimizer.backward`, this + function additionally dynamically scales the loss to avoid gradient + underflow. + """ + self._grad_scaler.scale(loss).backward() + + def step(self): + self.scaler.step(self.fp32_optimizer) + self.scaler.update() + + def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): + """Clips gradient norm.""" + self.scaler.unscale_(self.optimizer) + grad_norm = self.fp32_optimizer.clip_grad_norm(max_norm, aggregate_norm_fn) + if not torch.isfinite(grad_norm).all(): + new_loss_scale = self.next_loss_scale + if new_loss_scale <= self.min_loss_scale: + raise FloatingPointError( + ( + "AMP: Minimum loss scale reached ({}). Your loss is probably exploding. " + "Try restarting training or use fp32. {}" + ).format(self.min_loss_scale, new_loss_scale) + ) + else: + logger.info("AMP: overflow detected, setting scale to " + f"to {new_loss_scale}") + return grad_norm + + @property + def scaler(self): + return self._grad_scaler + + @property + def next_loss_scale(self): + return self.scaler.get_scale() * self.scaler.get_backoff_factor() + + @property + def optimizer(self): + return self.fp32_optimizer.optimizer + + @optimizer.setter + def optimizer(self, optimizer): + self.fp32_optimizer.optimizer = optimizer + + @property + def lr_scheduler(self): + return getattr(self.fp32_optimizer, "lr_scheduler", None) + + @property + def optimizer_config(self): + return self.fp32_optimizer.optimizer_config + + def get_lr(self): + return self.fp32_optimizer.get_lr() + + def set_lr(self, lr): + self.fp32_optimizer.set_lr(lr) + + def all_reduce_grads(self, module): + self.fp32_optimizer.all_reduce_grads(module) + + @property + def supports_flat_params(self): + return self.fp32_optimizer.supports_flat_params diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 375b5277b9..e30b2cd985 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -14,6 +14,7 @@ from fairseq.data import Dictionary, FairseqDataset, data_utils, encoders, iterators from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import gen_parser_from_dataclass +from fairseq.optim.amp_optimizer import AMPOptimizer from omegaconf import DictConfig @@ -472,7 +473,8 @@ def train_step( model.train() model.set_num_updates(update_num) with torch.autograd.profiler.record_function("forward"): - loss, sample_size, logging_output = criterion(model, sample) + with torch.cuda.amp.autocast(enabled=(isinstance(optimizer, AMPOptimizer))): + loss, sample_size, logging_output = criterion(model, sample) if ignore_grad: loss *= 0 with torch.autograd.profiler.record_function("backward"): diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 924b2b6b34..d1d08025f6 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -81,11 +81,14 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): self._model = model if cfg.distributed_training.ddp_backend != "fully_sharded": if cfg.common.fp16: + assert not cfg.common.amp, "Cannot use fp16 and AMP together" self._criterion = self._criterion.half() self._model = self._model.half() elif cfg.common.bf16: self._criterion = self._criterion.to(dtype=torch.bfloat16) self._model = self._model.to(dtype=torch.bfloat16) + elif cfg.common.amp: + self._amp_retries = 0 if ( not cfg.distributed_training.pipeline_model_parallel # the DistributedFairseqModel wrapper will handle moving to device, @@ -285,10 +288,10 @@ def _build_optimizer(self): self._optimizer = optim.MemoryEfficientFP16Optimizer.build_optimizer( self.cfg, params, allow_unsupported=allow_unsupported ) - elif self.cfg.common.fp16 or self.cfg.common.bf16: + elif self.cfg.common.fp16 or self.cfg.common.bf16 or self.cfg.common.amp: if self.cuda and torch.cuda.get_device_capability(0)[0] < 7: logger.info( - "NOTE: your device does NOT support faster training with --fp16, " + "NOTE: your device does NOT support faster training with --fp16 or --amp, " "please switch to FP32 which is likely to be faster" ) if ( @@ -298,11 +301,13 @@ def _build_optimizer(self): self._optimizer = optim.MemoryEfficientFP16Optimizer.build_optimizer( self.cfg, params ) + elif self.cfg.common.amp: + self._optimizer = optim.AMPOptimizer.build_optimizer(self.cfg, params) else: self._optimizer = optim.FP16Optimizer.build_optimizer(self.cfg, params) else: if self.cuda and torch.cuda.get_device_capability(0)[0] >= 7: - logger.info("NOTE: your device may support faster training with --fp16") + logger.info("NOTE: your device may support faster training with --fp16 or --amp") self._optimizer = optim.build_optimizer(self.cfg.optimizer, params) if self.cfg.distributed_training.ddp_backend == "fully_sharded": @@ -803,14 +808,26 @@ def maybe_no_sync(): ): self._check_grad_norms(grad_norm) if not torch.isfinite(grad_norm).all(): - # check local gradnorm single GPU case, trigger NanDetector - raise FloatingPointError("gradients are Nan/Inf") + # in case of AMP, if gradients are Nan/Inf then + # optimizer step is still required + if self.cfg.common.amp: + overflow = True + else: + # check local gradnorm single GPU case, trigger NanDetector + raise FloatingPointError("gradients are Nan/Inf") with torch.autograd.profiler.record_function("optimizer"): # take an optimization step self.task.optimizer_step( self.optimizer, model=self.model, update_num=self.get_num_updates() ) + if self.cfg.common.amp and overflow: + if self._amp_retries == self.cfg.common.amp_batch_retries: + logger.info("AMP: skipping this batch.") + self._amp_retries = 0 + else: + self._amp_retries += 1 + return self.train_step(samples, raise_oom) # recursion to feed in same batch except FloatingPointError: # re-run the forward and backward pass with hooks attached to print @@ -915,10 +932,14 @@ def maybe_no_sync(): ): torch.cuda.empty_cache() - if self.cfg.common.fp16: + if self.cfg.common.fp16 or self.cfg.common.amp: metrics.log_scalar( "loss_scale", - self.optimizer.scaler.loss_scale, + ( + self.optimizer.scaler.loss_scale + if self.cfg.common.fp16 + else self.optimizer.scaler.get_scale() + ), priority=700, round=4, weight=0, @@ -1274,8 +1295,11 @@ def _check_grad_norms(self, grad_norm): def is_consistent(tensor): max_abs_diff = torch.max(torch.abs(tensor - tensor[0])) return ( - torch.isfinite(tensor).all() - and (max_abs_diff / (tensor[0] + 1e-6) < 1e-6).all() + (torch.isfinite(tensor).all() + and (max_abs_diff / (tensor[0] + 1e-6) < 1e-6).all()) + or + (self.cfg.common.amp and not torch.isfinite(tensor).all()) + # in case of amp non-finite grads are fine ) if not is_consistent(self._grad_norm_buf): diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 54dc96079f..de8c242613 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -142,6 +142,40 @@ def test_transformer_fp16(self): ) generate_main(data_dir) + @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") + def test_amp(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_amp") as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + train_translation_model(data_dir, "fconv_iwslt_de_en", ["--amp"]) + generate_main(data_dir) + + @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") + def test_transformer_amp(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_transformer") as data_dir: + create_dummy_data(data_dir) + preprocess_translation_data(data_dir) + train_translation_model( + data_dir, + "transformer_iwslt_de_en", + [ + "--encoder-layers", + "2", + "--decoder-layers", + "2", + "--encoder-embed-dim", + "64", + "--decoder-embed-dim", + "64", + "--amp", + ], + run_validation=True, + ) + generate_main(data_dir) + + @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") def test_levenshtein_transformer(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory( diff --git a/tests/test_amp_optimizer.py b/tests/test_amp_optimizer.py new file mode 100644 index 0000000000..3a785e1830 --- /dev/null +++ b/tests/test_amp_optimizer.py @@ -0,0 +1,78 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import copy +import unittest + +import torch +from torch.cuda.amp import autocast, GradScaler +from fairseq.optim import build_optimizer + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestGradientScalingAMP(unittest.TestCase): + def setUp(self): + self.x = torch.tensor([2.0]).cuda().half() + weight = 3.0 + bias = 5.0 + self.error = 1.0 + self.target = torch.tensor([self.x * weight + bias + self.error]).cuda() + self.loss_fn = torch.nn.L1Loss() + + self.model = torch.nn.Linear(1, 1) + self.model.weight.data = torch.tensor([[weight]]) + self.model.bias.data = torch.tensor([bias]) + self.model.cuda() + self.params = list(self.model.parameters()) + + self.namespace_dls = argparse.Namespace( + optimizer="adam", + lr=[0.1], + adam_betas="(0.9, 0.999)", + adam_eps=1e-8, + weight_decay=0.0, + threshold_loss_scale=1, + min_loss_scale=1e-4, + ) + self.scaler = GradScaler( + init_scale=1, + growth_interval=1, + ) + + def run_iter(self, model, params, optimizer): + optimizer.zero_grad() + with autocast(): + y = model(self.x) + loss = self.loss_fn(y, self.target) + self.scaler.scale(loss).backward() + self.assertEqual(loss, torch.tensor(1.0, device="cuda:0", dtype=torch.float16)) + + self.scaler.unscale_(optimizer) + grad_norm = optimizer.clip_grad_norm(0) + self.assertAlmostEqual(grad_norm.item(), 2.2361, 4) + + self.scaler.step(optimizer) + self.scaler.update() + self.assertEqual( + model.weight, + torch.tensor( + [[3.1]], device="cuda:0", requires_grad=True + ), + ) + self.assertEqual( + model.bias, + torch.tensor( + [5.1], device="cuda:0", requires_grad=True + ), + ) + self.assertEqual(self.scaler.get_scale(), 2.0) + + def test_automatic_mixed_precision(self): + model = copy.deepcopy(self.model) + params = list(model.parameters()) + optimizer = build_optimizer(self.namespace_dls, params) + + self.run_iter(model, params, optimizer) diff --git a/tests/test_reproducibility.py b/tests/test_reproducibility.py index 405d545593..94931b2a07 100644 --- a/tests/test_reproducibility.py +++ b/tests/test_reproducibility.py @@ -125,6 +125,18 @@ def test_reproducibility_memory_efficient_fp16(self): ], ) + @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") + def test_reproducibility_amp(self): + self._test_reproducibility( + "test_reproducibility_amp", + [ + "--amp", + "--fp16-init-scale", + "4096", + ], + delta=0.011, + ) + def test_mid_epoch_reproducibility(self): self._test_reproducibility( "test_mid_epoch_reproducibility", From e6eddd805ebbc5c17bf5100c2fde6e0dfc946d2c Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Wed, 26 May 2021 16:27:59 -0700 Subject: [PATCH 352/774] =?UTF-8?q?make=20hydra/infer.py=20work;=20also=20?= =?UTF-8?q?dont=20break=20if=20something=20is=20removed=20fro=E2=80=A6=20(?= =?UTF-8?q?#1903)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: previously hydra/infer.py did not always work for several reasons which are addressed here new example usage: PYTHONPATH=. python examples/speech_recognition/new/infer.py --config-dir examples/speech_recognition/hydra/conf --config-name infer task=audio_pretraining task.data=/path/to/data task.labels=ltr decoding.type=kenlm decoding.lexicon=/path/to/lexicon decoding.lmpath=/path/to/lm dataset.gen_subset=dev_other common_eval.path=/path/to/model.pt decoding.beam=5 decoding.lmweight=2 decoding.wordscore=-1 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1903 Reviewed By: arbabu123 Differential Revision: D28700795 Pulled By: alexeib fbshipit-source-id: 66fe454de49c1bf511b3529ac683f1c8cb08e579 --- examples/hubert/README.md | 4 +- .../hubert/config/decode/infer_fsqlm.yaml | 25 +- .../hubert/config/decode/infer_kenlm.yaml | 25 +- .../hubert/config/decode/infer_viterbi.yaml | 7 +- examples/speech_recognition/infer.py | 2 +- .../{hydra => new}/README.md | 24 +- examples/speech_recognition/new/__init__.py | 0 .../{hydra => new}/conf/hydra/sweeper/ax.yaml | 8 +- .../{hydra => new}/conf/infer.yaml | 13 +- .../new/decoders/__init__.py | 0 .../new/decoders/base_decoder.py | 62 ++++ .../new/decoders/decoder.py | 32 ++ .../new/decoders/decoder_config.py | 70 ++++ .../decoders/flashlight_decoder.py} | 326 ++++-------------- .../new/decoders/viterbi_decoder.py | 24 ++ .../{hydra => new}/infer.py | 140 ++++---- fairseq/criterions/ctc.py | 15 +- fairseq/dataclass/utils.py | 16 +- fairseq/models/wav2vec/wav2vec2_asr.py | 1 - fairseq/tasks/audio_pretraining.py | 69 ++-- fairseq/utils.py | 4 +- fairseq_cli/validate.py | 3 + 22 files changed, 450 insertions(+), 420 deletions(-) rename examples/speech_recognition/{hydra => new}/README.md (54%) create mode 100644 examples/speech_recognition/new/__init__.py rename examples/speech_recognition/{hydra => new}/conf/hydra/sweeper/ax.yaml (80%) rename examples/speech_recognition/{hydra => new}/conf/infer.yaml (67%) create mode 100644 examples/speech_recognition/new/decoders/__init__.py create mode 100644 examples/speech_recognition/new/decoders/base_decoder.py create mode 100644 examples/speech_recognition/new/decoders/decoder.py create mode 100644 examples/speech_recognition/new/decoders/decoder_config.py rename examples/speech_recognition/{hydra/decoder.py => new/decoders/flashlight_decoder.py} (54%) create mode 100644 examples/speech_recognition/new/decoders/viterbi_decoder.py rename examples/speech_recognition/{hydra => new}/infer.py (80%) diff --git a/examples/hubert/README.md b/examples/hubert/README.md index ca714469c6..c0b1125cb5 100644 --- a/examples/hubert/README.md +++ b/examples/hubert/README.md @@ -65,7 +65,7 @@ Decoding results will be saved at `/path/to/experiment/directory/decode/viterbi/test`. ```sh -$ python examples/speech_recognition/hydra/infer.py \ +$ python examples/speech_recognition/new/infer.py \ --config-dir /path/to/fairseq-py/examples/hubert/config/decode \ --config-name infer_viterbi \ task.data=/path/to/data \ @@ -82,7 +82,7 @@ Suppose the pronunciation lexicon and the n-gram LM are saved at saved at `/path/to/experiment/directory/decode/kenlm/test`. ```sh -$ python examples/speech_recognition/hydra/infer.py \ +$ python examples/speech_recognition/new/infer.py \ --config-dir /path/to/fairseq-py/examples/hubert/config/decode \ --config-name infer_kenlm \ task.data=/path/to/data \ diff --git a/examples/hubert/config/decode/infer_fsqlm.yaml b/examples/hubert/config/decode/infer_fsqlm.yaml index b9fb845066..bc77cab32e 100644 --- a/examples/hubert/config/decode/infer_fsqlm.yaml +++ b/examples/hubert/config/decode/infer_fsqlm.yaml @@ -17,25 +17,20 @@ task: normalize: ??? decoding: - exp_dir: ??? - decoder: - name: fairseqlm - lexicon: ??? - lmpath: ??? - beamthreshold: 25 # 100 - beam: 500 - lmweight: 2 - wordscore: -1 - silweight: 0 - write_sentences: true + type: fairseqlm + lexicon: ??? + lmpath: ??? + beamthreshold: 25 # 100 + beam: 500 + lmweight: 2 + wordscore: -1 + silweight: 0 unique_wer_file: true + beam: 500 common_eval: - results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}/${dataset.gen_subset} + results_path: ??? path: ??? post_process: letter -generation: - nbest: 1 - beam: 500 dataset: max_tokens: 1100000 gen_subset: ??? diff --git a/examples/hubert/config/decode/infer_kenlm.yaml b/examples/hubert/config/decode/infer_kenlm.yaml index fe464eaae5..26f5c48928 100644 --- a/examples/hubert/config/decode/infer_kenlm.yaml +++ b/examples/hubert/config/decode/infer_kenlm.yaml @@ -17,25 +17,20 @@ task: normalize: ??? decoding: - exp_dir: ??? - decoder: - name: kenlm - lexicon: ??? - lmpath: ??? - beamthreshold: 100 - beam: 500 - lmweight: 2 - wordscore: -1 - silweight: 0 - write_sentences: true + type: kenlm + lexicon: ??? + lmpath: ??? + beamthreshold: 100 + beam: 500 + lmweight: 2 + wordscore: -1 + silweight: 0 unique_wer_file: true + beam: 500 common_eval: - results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}/${dataset.gen_subset} + results_path: ??? path: ??? post_process: letter -generation: - nbest: 1 - beam: 500 dataset: max_tokens: 1100000 gen_subset: ??? diff --git a/examples/hubert/config/decode/infer_viterbi.yaml b/examples/hubert/config/decode/infer_viterbi.yaml index d0de9cfd26..935d7d1d01 100644 --- a/examples/hubert/config/decode/infer_viterbi.yaml +++ b/examples/hubert/config/decode/infer_viterbi.yaml @@ -17,13 +17,10 @@ task: normalize: ??? decoding: - exp_dir: ??? - decoder: - name: viterbi - write_sentences: true + type: viterbi unique_wer_file: true common_eval: - results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name}/${dataset.gen_subset} + results_path: ??? path: ??? post_process: letter generation: diff --git a/examples/speech_recognition/infer.py b/examples/speech_recognition/infer.py index f4efbf39c8..6e9a878af4 100644 --- a/examples/speech_recognition/infer.py +++ b/examples/speech_recognition/infer.py @@ -227,7 +227,7 @@ def main(args, task=None, model_state=None): else: logger.info("| loading model(s) from {}".format(args.path)) models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( - utils.split_paths(args.path), + utils.split_paths(args.path, separator="\\"), arg_overrides=ast.literal_eval(args.model_overrides), task=task, suffix=args.checkpoint_suffix, diff --git a/examples/speech_recognition/hydra/README.md b/examples/speech_recognition/new/README.md similarity index 54% rename from examples/speech_recognition/hydra/README.md rename to examples/speech_recognition/new/README.md index 17d5946675..5fa0e97245 100644 --- a/examples/speech_recognition/hydra/README.md +++ b/examples/speech_recognition/new/README.md @@ -7,7 +7,7 @@ This script runs decoding for pre-trained speech recognition models. Assuming a few variables: ```bash -exp_dir=<path-to-experiment-directory> +checkpoint=<path-to-checkpoint> data=<path-to-data-directory> lm_model=<path-to-language-model> lexicon=<path-to-lexicon> @@ -16,30 +16,28 @@ lexicon=<path-to-lexicon> Example usage for decoding a fine-tuned Wav2Vec model: ```bash -python $FAIRSEQ_ROOT/examples/speech_recognition/hydra/infer.py --multirun \ +python $FAIRSEQ_ROOT/examples/speech_recognition/new/infer.py --multirun \ task=audio_pretraining \ task.data=$data \ task.labels=ltr \ - decoding.exp_dir=$exp_dir \ - decoding.decoder.name=kenlm \ - decoding.decoder.lexicon=$lexicon \ - decoding.decoder.lmpath=$lm_model \ + common_eval.path=$checkpoint \ + decoding.type=kenlm \ + decoding.lexicon=$lexicon \ + decoding.lmpath=$lm_model \ dataset.gen_subset=dev_clean,dev_other,test_clean,test_other ``` Example usage for using Ax to sweep WER parameters (requires `pip install hydra-ax-sweeper`): ```bash -python $FAIRSEQ_ROOT/examples/speech_recognition/hydra/infer.py --multirun \ +python $FAIRSEQ_ROOT/examples/speech_recognition/new/infer.py --multirun \ hydra/sweeper=ax \ task=audio_pretraining \ task.data=$data \ task.labels=ltr \ - decoding.exp_dir=$exp_dir \ - decoding.decoder.name=kenlm \ - decoding.decoder.lexicon=$lexicon \ - decoding.decoder.lmpath=$lm_model \ - decoding.write_sentences=false \ - decoding.unique_wer_file=true \ + common_eval.path=$checkpoint \ + decoding.type=kenlm \ + decoding.lexicon=$lexicon \ + decoding.lmpath=$lm_model \ dataset.gen_subset=dev_other ``` diff --git a/examples/speech_recognition/new/__init__.py b/examples/speech_recognition/new/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/speech_recognition/hydra/conf/hydra/sweeper/ax.yaml b/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml similarity index 80% rename from examples/speech_recognition/hydra/conf/hydra/sweeper/ax.yaml rename to examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml index 7700712ea0..fbeff17ca6 100644 --- a/examples/speech_recognition/hydra/conf/hydra/sweeper/ax.yaml +++ b/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml @@ -2,10 +2,10 @@ _target_: hydra_plugins.hydra_ax_sweeper.ax_sweeper.AxSweeper max_batch_size: null ax_config: - max_trials: 100 + max_trials: 128 early_stop: minimize: true - max_epochs_without_improvement: 10 + max_epochs_without_improvement: 32 epsilon: 1.0e-05 experiment: name: ${dataset.gen_subset} @@ -18,9 +18,9 @@ ax_config: verbose_logging: false random_seed: null params: - decoding.decoder.lmweight: + decoding.lmweight: type: range bounds: [0.0, 5.0] - decoding.decoder.wordscore: + decoding.wordscore: type: range bounds: [-5.0, 5.0] diff --git a/examples/speech_recognition/hydra/conf/infer.yaml b/examples/speech_recognition/new/conf/infer.yaml similarity index 67% rename from examples/speech_recognition/hydra/conf/infer.yaml rename to examples/speech_recognition/new/conf/infer.yaml index 1d78ba14cb..f176228082 100644 --- a/examples/speech_recognition/hydra/conf/infer.yaml +++ b/examples/speech_recognition/new/conf/infer.yaml @@ -11,12 +11,15 @@ hydra: dir: ${common_eval.results_path} subdir: ${dataset.gen_subset} common_eval: - results_path: ${decoding.exp_dir}/decode/${decoding.decoder.name} - path: ${decoding.exp_dir}/checkpoint_best.pt + results_path: null + path: null post_process: letter -generation: - nbest: 1 - beam: 500 + quiet: true dataset: max_tokens: 1000000 gen_subset: test +distributed_training: + distributed_world_size: 1 +decoding: + beam: 5 + type: viterbi diff --git a/examples/speech_recognition/new/decoders/__init__.py b/examples/speech_recognition/new/decoders/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/speech_recognition/new/decoders/base_decoder.py b/examples/speech_recognition/new/decoders/base_decoder.py new file mode 100644 index 0000000000..a097969b3c --- /dev/null +++ b/examples/speech_recognition/new/decoders/base_decoder.py @@ -0,0 +1,62 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import itertools as it +from typing import Any, Dict, List + +import torch +from fairseq.data.dictionary import Dictionary +from fairseq.models.fairseq_model import FairseqModel + + +class BaseDecoder: + def __init__(self, tgt_dict: Dictionary) -> None: + self.tgt_dict = tgt_dict + self.vocab_size = len(tgt_dict) + + self.blank = ( + tgt_dict.index("<ctc_blank>") + if "<ctc_blank>" in tgt_dict.indices + else tgt_dict.bos() + ) + if "<sep>" in tgt_dict.indices: + self.silence = tgt_dict.index("<sep>") + elif "|" in tgt_dict.indices: + self.silence = tgt_dict.index("|") + else: + self.silence = tgt_dict.eos() + + def generate( + self, models: List[FairseqModel], sample: Dict[str, Any], **unused + ) -> List[List[Dict[str, torch.LongTensor]]]: + encoder_input = { + k: v for k, v in sample["net_input"].items() if k != "prev_output_tokens" + } + emissions = self.get_emissions(models, encoder_input) + return self.decode(emissions) + + def get_emissions( + self, + models: List[FairseqModel], + encoder_input: Dict[str, Any], + ) -> torch.FloatTensor: + model = models[0] + encoder_out = model(**encoder_input) + if hasattr(model, "get_logits"): + emissions = model.get_logits(encoder_out) + else: + emissions = model.get_normalized_probs(encoder_out, log_probs=True) + return emissions.transpose(0, 1).float().cpu().contiguous() + + def get_tokens(self, idxs: torch.IntTensor) -> torch.LongTensor: + idxs = (g[0] for g in it.groupby(idxs)) + idxs = filter(lambda x: x != self.blank, idxs) + return torch.LongTensor(list(idxs)) + + def decode( + self, + emissions: torch.FloatTensor, + ) -> List[List[Dict[str, torch.LongTensor]]]: + raise NotImplementedError diff --git a/examples/speech_recognition/new/decoders/decoder.py b/examples/speech_recognition/new/decoders/decoder.py new file mode 100644 index 0000000000..b5bec8cf70 --- /dev/null +++ b/examples/speech_recognition/new/decoders/decoder.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Union + +from fairseq.data.dictionary import Dictionary + +from .decoder_config import DecoderConfig, FlashlightDecoderConfig +from .base_decoder import BaseDecoder + + +def Decoder( + cfg: Union[DecoderConfig, FlashlightDecoderConfig], tgt_dict: Dictionary +) -> BaseDecoder: + + if cfg.type == "viterbi": + from .viterbi_decoder import ViterbiDecoder + + return ViterbiDecoder(tgt_dict) + if cfg.type == "kenlm": + from .flashlight_decoder import KenLMDecoder + + return KenLMDecoder(cfg, tgt_dict) + if cfg.type == "fairseqlm": + from .flashlight_decoder import FairseqLMDecoder + + return FairseqLMDecoder(cfg, tgt_dict) + raise NotImplementedError(f"Invalid decoder name: {cfg.name}") diff --git a/examples/speech_recognition/new/decoders/decoder_config.py b/examples/speech_recognition/new/decoders/decoder_config.py new file mode 100644 index 0000000000..659eb94a9b --- /dev/null +++ b/examples/speech_recognition/new/decoders/decoder_config.py @@ -0,0 +1,70 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from dataclasses import dataclass, field +from typing import Optional + +from fairseq.dataclass.configs import FairseqDataclass +from fairseq.dataclass.constants import ChoiceEnum +from omegaconf import MISSING + + +DECODER_CHOICES = ChoiceEnum(["viterbi", "kenlm", "fairseqlm"]) + + +@dataclass +class DecoderConfig(FairseqDataclass): + type: DECODER_CHOICES = field( + default="viterbi", + metadata={"help": "The type of decoder to use"}, + ) + + +@dataclass +class FlashlightDecoderConfig(FairseqDataclass): + nbest: int = field( + default=1, + metadata={"help": "Number of decodings to return"}, + ) + unitlm: bool = field( + default=False, + metadata={"help": "If set, use unit language model"}, + ) + lmpath: str = field( + default=MISSING, + metadata={"help": "Language model for KenLM decoder"}, + ) + lexicon: Optional[str] = field( + default=None, + metadata={"help": "Lexicon for Flashlight decoder"}, + ) + beam: int = field( + default=50, + metadata={"help": "Number of beams to use for decoding"}, + ) + beamthreshold: float = field( + default=50.0, + metadata={"help": "Threshold for beam search decoding"}, + ) + beamsizetoken: Optional[int] = field( + default=None, metadata={"help": "Beam size to use"} + ) + wordscore: float = field( + default=-1, + metadata={"help": "Word score for KenLM decoder"}, + ) + unkweight: float = field( + default=-math.inf, + metadata={"help": "Unknown weight for KenLM decoder"}, + ) + silweight: float = field( + default=0, + metadata={"help": "Silence weight for KenLM decoder"}, + ) + lmweight: float = field( + default=2, + metadata={"help": "Weight for LM while interpolating score"}, + ) diff --git a/examples/speech_recognition/hydra/decoder.py b/examples/speech_recognition/new/decoders/flashlight_decoder.py similarity index 54% rename from examples/speech_recognition/hydra/decoder.py rename to examples/speech_recognition/new/decoders/flashlight_decoder.py index d182b95a32..8a548bdf66 100644 --- a/examples/speech_recognition/hydra/decoder.py +++ b/examples/speech_recognition/new/decoders/flashlight_decoder.py @@ -6,35 +6,39 @@ # LICENSE file in the root directory of this source tree. import gc -import itertools as it -import math import os.path as osp import warnings from collections import deque, namedtuple -from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, Tuple import numpy as np import torch -from examples.speech_recognition.data.replabels import unpack_replabels from fairseq import tasks from fairseq.data.dictionary import Dictionary -from fairseq.dataclass.configs import FairseqDataclass -from fairseq.dataclass.constants import ChoiceEnum from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.models.fairseq_model import FairseqModel from fairseq.utils import apply_to_sample -from omegaconf import MISSING, open_dict +from omegaconf import open_dict, OmegaConf + +from typing import List + +from .decoder_config import FlashlightDecoderConfig +from .base_decoder import BaseDecoder try: - from flashlight.lib.sequence.criterion import (CpuViterbiPath, - get_data_ptr_as_bytes) - from flashlight.lib.text.decoder import (LM, CriterionType, DecodeResult, - KenLM, LexiconDecoder, - LexiconDecoderOptions, - LexiconFreeDecoder, - LexiconFreeDecoderOptions, - LMState, SmearingMode, Trie) + from flashlight.lib.text.decoder import ( + LM, + CriterionType, + DecodeResult, + KenLM, + LexiconDecoder, + LexiconDecoderOptions, + LexiconFreeDecoder, + LexiconFreeDecoderOptions, + LMState, + SmearingMode, + Trie, + ) from flashlight.lib.text.dictionary import create_word_dict, load_words except ImportError: warnings.warn( @@ -46,192 +50,13 @@ LMState = object -CRITERION_CHOICES = ChoiceEnum(["ctc", "asg"]) -DECODER_CHOICES = ChoiceEnum(["viterbi", "kenlm", "fairseqlm"]) - - -@dataclass -class DecoderConfig(FairseqDataclass): - name: DECODER_CHOICES = field( - default="viterbi", - metadata={"help": "The type of decoder to use"}, - ) - nbest: int = field( - default=1, - metadata={"help": "Number of decodings to return"}, - ) - criterion: CRITERION_CHOICES = field( - default="ctc", - metadata={"help": "Criterion to use"}, - ) - asgtransitions: List[int] = field( - default=MISSING, - metadata={"help": "ASG transition indices"}, - ) - maxreplabel: int = field( - default=2, - metadata={"help": "Maximum repeated labels for ASG criterion"}, - ) - unitlm: bool = field( - default=False, - metadata={"help": "If set, use unit language model"}, - ) - lmpath: str = field( - default=MISSING, - metadata={"help": "Language model for KenLM decoder"}, - ) - lexicon: Optional[str] = field( - default=None, - metadata={"help": "Lexicon for Flashlight decoder"}, - ) - beam: int = field( - default=50, - metadata={"help": "Number of beams to use for decoding"}, - ) - beamthreshold: float = field( - default=15.0, - metadata={"help": "Threshold for beam search decoding"}, - ) - beamsizetoken: Optional[int] = field( - default=None, - metadata={"help": "Beam size to use"} - ) - wordscore: float = field( - default=1.5, - metadata={"help": "Word score for KenLM decoder"}, - ) - unkweight: float = field( - default=-math.inf, - metadata={"help": "Unknown weight for KenLM decoder"}, - ) - silweight: float = field( - default=-0.3, - metadata={"help": "Silence weight for KenLM decoder"}, - ) - lmweight: float = field( - default=1.5, - metadata={"help": "Weight for LM while interpolating score"}, - ) - unitlm: bool = field( - default=False, - metadata={"help": "If using a unit language model"}, - ) - +class KenLMDecoder(BaseDecoder): + def __init__(self, cfg: FlashlightDecoderConfig, tgt_dict: Dictionary) -> None: + super().__init__(tgt_dict) -class BaseDecoder: - def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: - self.tgt_dict = tgt_dict - self.vocab_size = len(tgt_dict) self.nbest = cfg.nbest self.unitlm = cfg.unitlm - if cfg.criterion == "ctc": - self.criterion_type = CriterionType.CTC - self.blank = ( - tgt_dict.index("<ctc_blank>") - if "<ctc_blank>" in tgt_dict.indices - else tgt_dict.bos() - ) - if "<sep>" in tgt_dict.indices: - self.silence = tgt_dict.index("<sep>") - elif "|" in tgt_dict.indices: - self.silence = tgt_dict.index("|") - else: - self.silence = tgt_dict.eos() - self.asgtransitions = None - elif cfg.criterion == "asg_loss": - self.criterion_type = CriterionType.ASG - self.blank = -1 - self.silence = -1 - self.asgtransitions = cfg.asgtransitions - self.maxreplabel = cfg.maxreplabel - assert len(self.asgtransitions) == self.vocab_size ** 2 - else: - raise RuntimeError(f"unknown criterion: {cfg.criterion}") - - def generate( - self, - models: List[FairseqModel], - sample: Dict[str, Any], - **unused - ) -> List[List[Dict[str, torch.LongTensor]]]: - encoder_input = { - k: v - for k, v in sample["net_input"].items() - if k != "prev_output_tokens" - } - emissions = self.get_emissions(models, encoder_input) - return self.decode(emissions) - - def get_emissions( - self, - models: List[FairseqModel], - encoder_input: Dict[str, Any], - ) -> torch.FloatTensor: - model = models[0] - encoder_out = model(**encoder_input) - if self.criterion_type == CriterionType.CTC: - if hasattr(model, "get_logits"): - emissions = model.get_logits(encoder_out) - else: - emissions = model.get_normalized_probs( - encoder_out, log_probs=True) - elif self.criterion_type == CriterionType.ASG: - emissions = encoder_out["encoder_out"] - else: - raise ValueError("Criterion not implemented: " - f"{self.criterion_type}") - return emissions.transpose(0, 1).float().cpu().contiguous() - - def get_tokens(self, idxs: torch.IntTensor) -> torch.LongTensor: - idxs = (g[0] for g in it.groupby(idxs)) - if self.criterion_type == CriterionType.CTC: - idxs = filter(lambda x: x != self.blank, idxs) - elif self.criterion_type == CriterionType.ASG: - idxs = filter(lambda x: x >= 0, idxs) - idxs = unpack_replabels( - list(idxs), self.tgt_dict, self.maxreplabel) - return torch.LongTensor(list(idxs)) - - def decode( - self, - emissions: torch.FloatTensor, - ) -> List[List[Dict[str, torch.LongTensor]]]: - raise NotImplementedError - - -class ViterbiDecoder(BaseDecoder): - def decode( - self, - emissions: torch.FloatTensor, - ) -> List[List[Dict[str, torch.LongTensor]]]: - B, T, N = emissions.size() - if self.asgtransitions is None: - transitions = torch.FloatTensor(N, N).zero_() - else: - transitions = torch.FloatTensor(self.asgtransitions).view(N, N) - viterbi_path = torch.IntTensor(B, T) - workspace = torch.ByteTensor( - CpuViterbiPath.get_workspace_size(B, T, N)) - CpuViterbiPath.compute( - B, - T, - N, - get_data_ptr_as_bytes(emissions), - get_data_ptr_as_bytes(transitions), - get_data_ptr_as_bytes(viterbi_path), - get_data_ptr_as_bytes(workspace), - ) - return [ - [{"tokens": self.get_tokens(viterbi_path[b].tolist()), "score": 0}] - for b in range(B) - ] - - -class KenLMDecoder(BaseDecoder): - def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: - super().__init__(cfg, tgt_dict) - if cfg.lexicon: self.lexicon = load_words(cfg.lexicon) self.word_dict = create_word_dict(self.lexicon) @@ -245,12 +70,10 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: word_idx = self.word_dict.get_index(word) _, score = self.lm.score(start_state, word_idx) for spelling in spellings: - spelling_idxs = [ - tgt_dict.index(token) - for token in spelling - ] - assert tgt_dict.unk() not in spelling_idxs, \ - f"{word} {spelling} {spelling_idxs}" + spelling_idxs = [tgt_dict.index(token) for token in spelling] + assert ( + tgt_dict.unk() not in spelling_idxs + ), f"{word} {spelling} {spelling_idxs}" self.trie.insert(spelling_idxs, word_idx, score) self.trie.smear(SmearingMode.MAX) @@ -263,12 +86,9 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: unk_score=cfg.unkweight, sil_score=cfg.silweight, log_add=False, - criterion_type=self.criterion_type, + criterion_type=CriterionType.CTC, ) - if self.asgtransitions is None: - self.asgtransitions = [] - self.decoder = LexiconDecoder( self.decoder_opts, self.trie, @@ -276,7 +96,7 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: self.silence, self.blank, self.unk_word, - self.asgtransitions, + [], self.unitlm, ) else: @@ -292,7 +112,7 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: lm_weight=cfg.lmweight, sil_score=cfg.silweight, log_add=False, - criterion_type=self.criterion_type, + criterion_type=CriterionType.CTC, ) self.decoder = LexiconFreeDecoder( self.decoder_opts, self.lm, self.silence, self.blank, [] @@ -309,16 +129,18 @@ def decode( results = self.decoder.decode(emissions_ptr, T, N) nbest_results = results[: self.nbest] - hypos.append([ - { - "tokens": self.get_tokens(result.tokens), - "score": result.score, - "words": [ - self.word_dict.get_entry(x) - for x in result.words if x >= 0 - ], - } for result in nbest_results - ]) + hypos.append( + [ + { + "tokens": self.get_tokens(result.tokens), + "score": result.score, + "words": [ + self.word_dict.get_entry(x) for x in result.words if x >= 0 + ], + } + for result in nbest_results + ] + ) return hypos @@ -328,7 +150,7 @@ def decode( "prefix", "incremental_state", "probs", - ] + ], ) @@ -343,7 +165,8 @@ def __init__(self, dictionary: Dictionary, model: FairseqModel) -> None: self.save_incremental = False # this currently does not work properly self.max_cache = 20_000 - model.cuda() + if torch.cuda.is_available(): + model.cuda() model.eval() model.make_generation_fast_() @@ -355,14 +178,11 @@ def start(self, start_with_nothing: bool) -> LMState: prefix = torch.LongTensor([[self.dictionary.eos()]]) incremental_state = {} if self.save_incremental else None with torch.no_grad(): - res = self.model( - prefix.cuda(), incremental_state=incremental_state) - probs = self.model.get_normalized_probs( - res, log_probs=True, sample=None) + res = self.model(prefix.cuda(), incremental_state=incremental_state) + probs = self.model.get_normalized_probs(res, log_probs=True, sample=None) if incremental_state is not None: - incremental_state = apply_to_sample( - lambda x: x.cpu(), incremental_state) + incremental_state = apply_to_sample(lambda x: x.cpu(), incremental_state) self.states[state] = FairseqLMState( prefix.numpy(), incremental_state, probs[0, -1].cpu().numpy() ) @@ -425,8 +245,7 @@ def trim_cache(targ_size: int) -> None: ) curr_state = FairseqLMState( - curr_state.prefix, new_incremental_state, probs[0, -1].cpu( - ).numpy() + curr_state.prefix, new_incremental_state, probs[0, -1].cpu().numpy() ) if not no_cache: @@ -467,8 +286,11 @@ def empty_cache(self) -> None: class FairseqLMDecoder(BaseDecoder): - def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: - super().__init__(cfg, tgt_dict) + def __init__(self, cfg: FlashlightDecoderConfig, tgt_dict: Dictionary) -> None: + super().__init__(tgt_dict) + + self.nbest = cfg.nbest + self.unitlm = cfg.unitlm self.lexicon = load_words(cfg.lexicon) if cfg.lexicon else None self.idx_to_wrd = {} @@ -480,6 +302,9 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: else: lm_args = convert_namespace_to_omegaconf(checkpoint["args"]) + if not OmegaConf.is_dict(lm_args): + lm_args = OmegaConf.create(lm_args) + with open_dict(lm_args.task): lm_args.task.data = osp.dirname(cfg.lmpath) @@ -502,16 +327,13 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: score = 0 else: word_idx = self.word_dict.index(word) - _, score = self.lm.score( - start_state, word_idx, no_cache=True) + _, score = self.lm.score(start_state, word_idx, no_cache=True) for spelling in spellings: - spelling_idxs = [ - tgt_dict.index(token) - for token in spelling - ] - assert tgt_dict.unk() not in spelling_idxs, \ - f"{spelling} {spelling_idxs}" + spelling_idxs = [tgt_dict.index(token) for token in spelling] + assert ( + tgt_dict.unk() not in spelling_idxs + ), f"{spelling} {spelling_idxs}" self.trie.insert(spelling_idxs, word_idx, score) self.trie.smear(SmearingMode.MAX) @@ -524,12 +346,9 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: unk_score=cfg.unkweight, sil_score=cfg.silweight, log_add=False, - criterion_type=self.criterion_type, + criterion_type=CriterionType.CTC, ) - if self.asgtransitions is None: - self.asgtransitions = [] - self.decoder = LexiconDecoder( self.decoder_opts, self.trie, @@ -537,7 +356,7 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: self.silence, self.blank, self.unk_word, - self.asgtransitions, + [], self.unitlm, ) else: @@ -553,7 +372,7 @@ def __init__(self, cfg: DecoderConfig, tgt_dict: Dictionary) -> None: lm_weight=cfg.lmweight, sil_score=cfg.silweight, log_add=False, - criterion_type=self.criterion_type, + criterion_type=CriterionType.CTC, ) self.decoder = LexiconFreeDecoder( self.decoder_opts, self.lm, self.silence, self.blank, [] @@ -574,7 +393,8 @@ def make_hypo(result: DecodeResult) -> Dict[str, Any]: if self.lexicon: hypo["words"] = [ self.idx_to_wrd[x] if self.unitlm else self.word_dict[x] - for x in result.words if x >= 0 + for x in result.words + if x >= 0 ] return hypo @@ -582,18 +402,8 @@ def make_hypo(result: DecodeResult) -> Dict[str, Any]: emissions_ptr = emissions.data_ptr() + 4 * b * emissions.stride(0) results = self.decoder.decode(emissions_ptr, T, N) - nbest_results = results[:self.nbest] + nbest_results = results[: self.nbest] hypos.append([make_hypo(result) for result in nbest_results]) self.lm.empty_cache() return hypos - - -def Decoder(cfg: DecoderConfig, tgt_dict: Dictionary) -> BaseDecoder: - if cfg.name == "viterbi": - return ViterbiDecoder(cfg, tgt_dict) - if cfg.name == "kenlm": - return KenLMDecoder(cfg, tgt_dict) - if cfg.name == "fairseqlm": - return FairseqLMDecoder(cfg, tgt_dict) - raise NotImplementedError(f"Invalid decoder name: {cfg.name}") diff --git a/examples/speech_recognition/new/decoders/viterbi_decoder.py b/examples/speech_recognition/new/decoders/viterbi_decoder.py new file mode 100644 index 0000000000..b1c47868fa --- /dev/null +++ b/examples/speech_recognition/new/decoders/viterbi_decoder.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + +from typing import List, Dict + +from .base_decoder import BaseDecoder + + +class ViterbiDecoder(BaseDecoder): + def decode( + self, + emissions: torch.FloatTensor, + ) -> List[List[Dict[str, torch.LongTensor]]]: + def get_pred(e): + toks = e.argmax(dim=-1).unique_consecutive() + return toks[toks != self.blank] + + return [[{"tokens": get_pred(x), "score": 0}] for x in emissions] diff --git a/examples/speech_recognition/hydra/infer.py b/examples/speech_recognition/new/infer.py similarity index 80% rename from examples/speech_recognition/hydra/infer.py rename to examples/speech_recognition/new/infer.py index 1b49823553..79afbc426d 100644 --- a/examples/speech_recognition/hydra/infer.py +++ b/examples/speech_recognition/new/infer.py @@ -10,25 +10,32 @@ import os import shutil import sys -from dataclasses import dataclass, field +from dataclasses import dataclass, field, is_dataclass from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple, Union import editdistance import torch import torch.distributed as dist -from examples.speech_recognition.hydra.decoder import Decoder, DecoderConfig -from fairseq import (checkpoint_utils, distributed_utils, progress_bar, tasks, - utils) +from examples.speech_recognition.new.decoders.decoder_config import ( + DecoderConfig, + FlashlightDecoderConfig, +) +from examples.speech_recognition.new.decoders.decoder import Decoder +from fairseq import checkpoint_utils, distributed_utils, progress_bar, tasks, utils from fairseq.data.data_utils import post_process -from fairseq.dataclass.configs import (CheckpointConfig, CommonConfig, - CommonEvalConfig, DatasetConfig, - DistributedTrainingConfig, - FairseqDataclass, GenerationConfig) +from fairseq.dataclass.configs import ( + CheckpointConfig, + CommonConfig, + CommonEvalConfig, + DatasetConfig, + DistributedTrainingConfig, + FairseqDataclass, +) from fairseq.logging.meters import StopwatchMeter, TimeMeter from fairseq.logging.progress_bar import BaseProgressBar from fairseq.models.fairseq_model import FairseqModel -from omegaconf import MISSING, OmegaConf +from omegaconf import OmegaConf import hydra from hydra.core.config_store import ConfigStore @@ -41,20 +48,17 @@ @dataclass -class DecodingConfig(FairseqDataclass): - exp_dir: str = field( - default=MISSING, - metadata={"help": "Path to the experiment directory"}, - ) +class DecodingConfig(DecoderConfig, FlashlightDecoderConfig): unique_wer_file: bool = field( default=False, metadata={"help": "If set, use a unique file for storing WER"}, ) - write_sentences: bool = field( - default=True, - metadata={"help": "If set, write hypothesis and reference sentences"}, + results_path: Optional[str] = field( + default=None, + metadata={ + "help": "If set, write hypothesis and reference sentences into this directory" + }, ) - decoder: DecoderConfig = DecoderConfig() @dataclass @@ -64,9 +68,14 @@ class InferConfig(FairseqDataclass): common: CommonConfig = CommonConfig() common_eval: CommonEvalConfig = CommonEvalConfig() checkpoint: CheckpointConfig = CheckpointConfig() - generation: GenerationConfig = GenerationConfig() distributed_training: DistributedTrainingConfig = DistributedTrainingConfig() dataset: DatasetConfig = DatasetConfig() + is_ax: bool = field( + default=False, + metadata={ + "help": "if true, assumes we are using ax for tuning and returns a tuple for ax to consume" + }, + ) def reset_logging(): @@ -85,6 +94,8 @@ def reset_logging(): class InferenceProcessor: + cfg: InferConfig + def __init__(self, cfg: InferConfig) -> None: self.cfg = cfg self.task = tasks.setup_task(cfg.task) @@ -98,7 +109,7 @@ def __init__(self, cfg: InferConfig) -> None: self.cfg.dataset.gen_subset, task_cfg=saved_cfg.task, ) - self.generator = Decoder(cfg.decoding.decoder, self.tgt_dict) + self.generator = Decoder(cfg.decoding, self.tgt_dict) self.gen_timer = StopwatchMeter() self.wps_meter = TimeMeter() self.num_sentences = 0 @@ -113,7 +124,7 @@ def __init__(self, cfg: InferConfig) -> None: self.progress_bar = self.build_progress_bar() def __enter__(self) -> "InferenceProcessor": - if self.cfg.decoding.write_sentences: + if self.cfg.decoding.results_path is not None: self.hypo_words_file = self.get_res_file("hypo.word") self.hypo_units_file = self.get_res_file("hypo.units") self.ref_words_file = self.get_res_file("ref.word") @@ -121,7 +132,7 @@ def __enter__(self) -> "InferenceProcessor": return self def __exit__(self, *exc) -> bool: - if self.cfg.decoding.write_sentences: + if self.cfg.decoding.results_path is not None: self.hypo_words_file.close() self.hypo_units_file.close() self.ref_words_file.close() @@ -145,6 +156,7 @@ def print(self, *args, **kwargs): self.progress_bar.print(*args, **kwargs) def get_res_file(self, fname: str) -> None: + fname = os.path.join(self.cfg.decoding.results_path, fname) if self.data_parallel_world_size > 1: fname = f"{fname}.{self.data_parallel_rank}" return open(fname, "w", buffering=1) @@ -156,7 +168,9 @@ def merge_shards(self) -> None: num_shards = self.data_parallel_world_size if self.data_parallel_world_size > 1: + def merge_shards_with_root(fname: str) -> None: + fname = os.path.join(self.cfg.decoding.results_path, fname) logger.info("Merging %s on shard %d", fname, shard_id) base_fpath = Path(f"{fname}.0") with open(base_fpath, "a") as out_file: @@ -180,11 +194,7 @@ def merge_shards_with_root(fname: str) -> None: dist.barrier() def optimize_model(self, model: FairseqModel) -> None: - gcfg = self.cfg.generation - model.make_generation_fast_( - beamable_mm_beam_size=None if gcfg.no_beamable_mm else gcfg.beam, - need_attn=gcfg.print_alignment, - ) + model.make_generation_fast_() if self.cfg.common.fp16: model.half() if not self.cfg.common.cpu: @@ -193,7 +203,7 @@ def optimize_model(self, model: FairseqModel) -> None: def load_model_ensemble(self) -> Tuple[List[FairseqModel], FairseqDataclass]: arg_overrides = ast.literal_eval(self.cfg.common_eval.model_overrides) models, saved_cfg = checkpoint_utils.load_model_ensemble( - utils.split_paths(self.cfg.common_eval.path), + utils.split_paths(self.cfg.common_eval.path, separator="\\"), arg_overrides=arg_overrides, task=self.task, suffix=self.cfg.checkpoint.checkpoint_suffix, @@ -268,21 +278,24 @@ def process_sentence( if "words" in hypo: hyp_words = " ".join(hypo["words"]) else: - hyp_words = post_process(hyp_pieces, - self.cfg.common_eval.post_process) + hyp_words = post_process(hyp_pieces, self.cfg.common_eval.post_process) # Processes target. target_tokens = utils.strip_pad(toks, self.tgt_dict.pad()) tgt_pieces = self.tgt_dict.string(target_tokens.int().cpu()) - tgt_words = post_process(tgt_pieces, - self.cfg.common_eval.post_process) + tgt_words = post_process(tgt_pieces, self.cfg.common_eval.post_process) - if self.cfg.decoding.write_sentences: + if self.cfg.decoding.results_path is not None: print(f"{hyp_pieces} ({speaker}-{sid})", file=self.hypo_units_file) print(f"{hyp_words} ({speaker}-{sid})", file=self.hypo_words_file) print(f"{tgt_pieces} ({speaker}-{sid})", file=self.ref_units_file) print(f"{tgt_words} ({speaker}-{sid})", file=self.ref_words_file) + if not self.cfg.common_eval.quiet: + logger.info(f"HYPO: {hyp_words}") + logger.info(f"REF: {tgt_words}") + logger.info("---------------------") + hyp_words, tgt_words = hyp_words.split(), tgt_words.split() return editdistance.eval(hyp_words, tgt_words), len(tgt_words) @@ -315,11 +328,15 @@ def process_sample(self, sample: Dict[str, Any]) -> None: self.num_sentences += sample["id"].numel() def log_generation_time(self) -> None: - logger.info("Processed %d sentences (%d tokens) in %.1fs %.2f " - "sentences per second, %.2f tokens per second)", - self.num_sentences, self.gen_timer.n, self.gen_timer.sum, - self.num_sentences / self.gen_timer.sum, - 1.0 / self.gen_timer.avg) + logger.info( + "Processed %d sentences (%d tokens) in %.1fs %.2f " + "sentences per second, %.2f tokens per second)", + self.num_sentences, + self.gen_timer.n, + self.gen_timer.sum, + self.num_sentences / self.gen_timer.sum, + 1.0 / self.gen_timer.avg, + ) def parse_wer(wer_file: Path) -> float: @@ -329,12 +346,16 @@ def parse_wer(wer_file: Path) -> float: def get_wer_file(cfg: InferConfig) -> Path: """Hashes the decoding parameters to a unique file ID.""" + base_path = "wer" + if cfg.decoding.results_path is not None: + base_path = os.path.join(cfg.decoding.results_path, base_path) + if cfg.decoding.unique_wer_file: yaml_str = OmegaConf.to_yaml(cfg.decoding) fid = int(hashlib.md5(yaml_str.encode("utf-8")).hexdigest(), 16) - return Path(f"wer.{fid % 1000000}") + return Path(f"{base_path}.{fid % 1000000}") else: - return Path("wer") + return Path(base_path) def main(cfg: InferConfig) -> float: @@ -356,8 +377,6 @@ def main(cfg: InferConfig) -> float: cfg.dataset.max_tokens = 4000000 if not cfg.common.cpu and not torch.cuda.is_available(): raise ValueError("CUDA not found; set `cpu=True` to run without CUDA") - if cfg.generation.nbest > 1: - raise ValueError("`nbest > 1` not implemented yet") with InferenceProcessor(cfg) as processor: for sample in processor: @@ -365,7 +384,7 @@ def main(cfg: InferConfig) -> float: processor.log_generation_time() - if cfg.decoding.write_sentences: + if cfg.decoding.results_path is not None: processor.merge_shards() errs_t, leng_t = processor.total_errors, processor.total_length @@ -381,17 +400,19 @@ def main(cfg: InferConfig) -> float: if distributed_utils.is_master(cfg.distributed_training): with open(wer_file, "w") as f: - f.write(( - f"WER: {wer}\n" - f"err / num_ref_words = {errs_t} / {leng_t}\n\n" - f"{yaml_str}" - )) + f.write( + ( + f"WER: {wer}\n" + f"err / num_ref_words = {errs_t} / {leng_t}\n\n" + f"{yaml_str}" + ) + ) return wer @hydra.main(config_path=config_path, config_name="infer") -def hydra_main(cfg: InferConfig) -> None: +def hydra_main(cfg: InferConfig) -> Union[float, Tuple[float, Optional[float]]]: container = OmegaConf.to_container(cfg, resolve=True, enum_to_str=True) cfg = OmegaConf.create(container) OmegaConf.set_struct(cfg, True) @@ -399,8 +420,7 @@ def hydra_main(cfg: InferConfig) -> None: if cfg.common.reset_logging: reset_logging() - logger.info("Config:\n%s", OmegaConf.to_yaml(cfg)) - logger.info("Working directory: %s", Path.cwd()) + # logger.info("Config:\n%s", OmegaConf.to_yaml(cfg)) wer = float("inf") try: @@ -419,13 +439,18 @@ def hydra_main(cfg: InferConfig) -> None: logger.error("Crashed! %s", str(e)) logger.info("Word error rate: %.4f", wer) + if cfg.is_ax: + return wer, None + return wer def cli_main() -> None: try: - from hydra._internal.utils import \ - get_args # pylint: disable=import-outside-toplevel + from hydra._internal.utils import ( + get_args, + ) # pylint: disable=import-outside-toplevel + cfg_name = get_args().config_name or "infer" except ImportError: logger.warning("Failed to get config name from hydra args") @@ -435,12 +460,9 @@ def cli_main() -> None: cs.store(name=cfg_name, node=InferConfig) for k in InferConfig.__dataclass_fields__: - v = InferConfig.__dataclass_fields__[k].default - try: + if is_dataclass(InferConfig.__dataclass_fields__[k].type): + v = InferConfig.__dataclass_fields__[k].default cs.store(name=k, node=v) - except BaseException: - logger.error(f"{k} - {v}") - raise hydra_main() # pylint: disable=no-value-for-parameter diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index 543e796da3..10e3618382 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -66,7 +66,11 @@ class CtcCriterionConfig(FairseqDataclass): class CtcCriterion(FairseqCriterion): def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): super().__init__(task) - self.blank_idx = task.target_dictionary.index(task.blank_symbol) if hasattr(task, 'blank_symbol') else 0 + self.blank_idx = ( + task.target_dictionary.index(task.blank_symbol) + if hasattr(task, "blank_symbol") + else 0 + ) self.pad_idx = task.target_dictionary.pad() self.eos_idx = task.target_dictionary.eos() self.post_process = cfg.post_process @@ -111,8 +115,13 @@ def forward(self, model, sample, reduce=True): if "src_lengths" in sample["net_input"]: input_lengths = sample["net_input"]["src_lengths"] else: - non_padding_mask = ~net_output["padding_mask"] - input_lengths = non_padding_mask.long().sum(-1) + if net_output["padding_mask"] is not None: + non_padding_mask = ~net_output["padding_mask"] + input_lengths = non_padding_mask.long().sum(-1) + else: + input_lengths = lprobs.new_full( + (lprobs.size(1),), lprobs.size(0), dtype=torch.long + ) pad_mask = (sample["target"] != self.pad_idx) & ( sample["target"] != self.eos_idx diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 27c9006fdb..89206125d1 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -9,7 +9,7 @@ import os import re from argparse import ArgumentError, ArgumentParser, Namespace -from dataclasses import _MISSING_TYPE, MISSING +from dataclasses import _MISSING_TYPE, MISSING, is_dataclass from enum import Enum from typing import Any, Dict, List, Optional, Tuple, Type @@ -457,7 +457,19 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): cfg[k] = overrides[k] -def merge_with_parent(dc: FairseqDataclass, cfg: FairseqDataclass): +def merge_with_parent(dc: FairseqDataclass, cfg: DictConfig, remove_missing=True): + if remove_missing: + + if is_dataclass(dc): + target_keys = set(dc.__dataclass_fields__.keys()) + else: + target_keys = set(dc.keys()) + + with open_dict(cfg): + for k in list(cfg.keys()): + if k not in target_keys: + del cfg[k] + merged_cfg = OmegaConf.merge(dc, cfg) merged_cfg.__dict__["_parent"] = cfg.__dict__["_parent"] OmegaConf.set_struct(merged_cfg, True) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index abae9d1ab3..405d1e613a 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -31,7 +31,6 @@ LayerNorm, PositionalEmbedding, TransformerDecoderLayer, - SamePad, ) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 71cefcfcaa..ce454e12b7 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -12,9 +12,8 @@ from argparse import Namespace from dataclasses import dataclass, field -import numpy as np from typing import Optional, Any -from omegaconf import MISSING, II +from omegaconf import MISSING, II, OmegaConf from fairseq.data import ( AddTargetDataset, @@ -44,6 +43,27 @@ def __call__(self, label): ) +@dataclass +class InferredW2vConfig: + # The following are needed to precompute mask and mask channel indices + # before model's forward. + mask_length: Optional[int] = II("model.mask_length") + mask_prob: Optional[float] = II("model.mask_prob") + mask_selection: Optional[str] = II("model.mask_selection") + mask_other: Optional[float] = II("model.mask_other") + no_mask_overlap: Optional[bool] = II("model.no_mask_overlap") + mask_min_space: Optional[int] = II("model.mask_min_space") + mask_channel_length: Optional[int] = II("model.mask_channel_length") + mask_channel_prob: Optional[float] = II("model.mask_channel_prob") + mask_channel_selection: Optional[str] = II("model.mask_channel_selection") + mask_channel_other: Optional[float] = II("model.mask_channel_other") + no_mask_channel_overlap: Optional[bool] = II("model.no_mask_channel_overlap") + mask_channel_min_space: Optional[int] = II("model.mask_channel_min_space") + + conv_feature_layers: Optional[str] = II("model.conv_feature_layers") + encoder_embed_dim: Optional[int] = II("model.encoder_embed_dim") + + @dataclass class AudioPretrainingConfig(FairseqDataclass): data: str = field(default=MISSING, metadata={"help": "path to data directory"}) @@ -114,23 +134,13 @@ class AudioPretrainingConfig(FairseqDataclass): "help": "flag to compute mask indices in data preparation.", }, ) - # The following are needed to precompute mask and mask channel indices - # before model's forward. - mask_length: Optional[int] = II("model.mask_length") - mask_prob: Optional[float] = II("model.mask_prob") - mask_selection: Optional[str] = II("model.mask_selection") - mask_other: Optional[float] = II("model.mask_other") - no_mask_overlap: Optional[bool] = II("model.no_mask_overlap") - mask_min_space: Optional[int] = II("model.mask_min_space") - mask_channel_length: Optional[int] = II("model.mask_channel_length") - mask_channel_prob: Optional[float] = II("model.mask_channel_prob") - mask_channel_selection: Optional[str] = II("model.mask_channel_selection") - mask_channel_other: Optional[float] = II("model.mask_channel_other") - no_mask_channel_overlap: Optional[bool] = II("model.no_mask_channel_overlap") - mask_channel_min_space: Optional[int] = II("model.mask_channel_min_space") - conv_feature_layers: Optional[str] = II("model.conv_feature_layers") - encoder_embed_dim: Optional[int] = II("model.encoder_embed_dim") + inferred_w2v_config: Optional[InferredW2vConfig] = field( + default=None, + metadata={ + "help": "wav2vec 2.0 masking arguments used to pre-compute masks (required for TPU)", + }, + ) tpu: bool = II("common.tpu") @@ -170,23 +180,12 @@ def load_target_dictionary(self): def _get_mask_precompute_kwargs(self, cfg): if self.cfg.precompute_mask_indices or self.cfg.tpu: - args = [ - "mask_length", - "mask_prob", - "mask_selection", - "mask_other", - "no_mask_overlap", - "mask_min_space", - "mask_channel_length", - "mask_channel_prob", - "mask_channel_selection", - "mask_channel_other", - "no_mask_channel_overlap", - "mask_channel_min_space", - "encoder_embed_dim", - "conv_feature_layers", - ] - return {arg: cfg[arg] for arg in args} + assert ( + cfg.inferred_w2v_config is not None + ), "inferred_w2v_config must be set" + return OmegaConf.to_container( + cfg.inferred_w2v_config, resolve=True, enum_to_str=True + ) else: return {} diff --git a/fairseq/utils.py b/fairseq/utils.py index d0ce16ae6b..bf5727edfd 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -57,9 +57,9 @@ def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, argument) -def split_paths(paths: str) -> List[str]: +def split_paths(paths: str, separator=os.pathsep) -> List[str]: return ( - paths.split(os.pathsep) + paths.split(separator) if "://" not in paths else paths.split(MANIFOLD_PATH_SEP) ) diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index f0d983ee6b..22b93e9a6a 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -14,6 +14,7 @@ from fairseq import checkpoint_utils, distributed_utils, options, utils from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import metrics, progress_bar +from fairseq.utils import reset_logging from omegaconf import DictConfig @@ -32,6 +33,8 @@ def main(cfg: DictConfig, override_args=None): utils.import_user_module(cfg.common) + reset_logging() + assert ( cfg.dataset.max_tokens is not None or cfg.dataset.batch_size is not None ), "Must specify batch size either with --max-tokens or --batch-size" From c8223e350cfc616bb47196151d1223683e483b6d Mon Sep 17 00:00:00 2001 From: Nicola De Cao <nicola.decao@uva.nl> Date: Wed, 26 May 2021 18:20:04 -0700 Subject: [PATCH 353/774] fixing prefix_allowed_tokens_fn (#3276) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes the use of `prefix_allowed_tokens_fn` in generation. It was working for `fairseq==0.9.0` (see https://github.com/facebookresearch/GENRE) but with the current version is broken. ## PR review Anyone in the community is free to review the PR once the tests have passed. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3276 Reviewed By: alexeib Differential Revision: D26725494 Pulled By: myleott fbshipit-source-id: ce3da725f36352687e5cb5d62a59b4c89ce0b0bc --- fairseq/hub_utils.py | 7 ++++++- fairseq/tasks/fairseq_task.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index 7de2e2b0d4..d74470d2ec 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -151,6 +151,7 @@ def generate( verbose: bool = False, skip_invalid_size_inputs=False, inference_step_args=None, + prefix_allowed_tokens_fn=None, **kwargs ) -> List[List[Dict[str, torch.Tensor]]]: if torch.is_tensor(tokenized_sentences) and tokenized_sentences.dim() == 1: @@ -164,7 +165,11 @@ def generate( gen_args.beam = beam for k, v in kwargs.items(): setattr(gen_args, k, v) - generator = self.task.build_generator(self.models, gen_args) + generator = self.task.build_generator( + self.models, + gen_args, + prefix_allowed_tokens_fn=prefix_allowed_tokens_fn, + ) inference_step_args = inference_step_args or {} results = [] diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index e30b2cd985..fbec9bb2a5 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -341,8 +341,32 @@ def build_criterion(self, cfg: DictConfig): return criterions.build_criterion(cfg, self) def build_generator( - self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None + self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None, prefix_allowed_tokens_fn=None, ): + """ + Build a :class:`~fairseq.SequenceGenerator` instance for this + task. + + Args: + models (List[~fairseq.models.FairseqModel]): ensemble of models + args (fairseq.dataclass.configs.GenerationConfig): + configuration object (dataclass) for generation + extra_gen_cls_kwargs (Dict[str, Any]): extra options to pass + through to SequenceGenerator + prefix_allowed_tokens_fn (Callable[[int, torch.Tensor], List[int]]): + If provided, this function constrains the beam search to + allowed tokens only at each step. The provided function + should take 2 arguments: the batch ID (`batch_id: int`) + and a unidimensional tensor of token ids (`inputs_ids: + torch.Tensor`). It has to return a `List[int]` with the + allowed tokens for the next generation step conditioned + on the previously generated tokens (`inputs_ids`) and + the batch ID (`batch_id`). This argument is useful for + constrained generation conditioned on the prefix, as + described in "Autoregressive Entity Retrieval" + (https://arxiv.org/abs/2010.00904) and + https://github.com/facebookresearch/GENRE. + """ if getattr(args, "score_reference", False): from fairseq.sequence_scorer import SequenceScorer @@ -369,7 +393,8 @@ def build_generator( match_source_len = getattr(args, "match_source_len", False) diversity_rate = getattr(args, "diversity_rate", -1) constrained = getattr(args, "constraints", False) - prefix_allowed_tokens_fn = getattr(args, "prefix_allowed_tokens_fn", None) + if prefix_allowed_tokens_fn is None: + prefix_allowed_tokens_fn = getattr(args, "prefix_allowed_tokens_fn", None) if ( sum( int(cond) From 9497ae3cfb04bb6ec4735758bbe8dc767276932c Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines <mandeep.baines@gmail.com> Date: Thu, 27 May 2021 12:14:40 -0700 Subject: [PATCH 354/774] disable raise_if_valid_subsets_unintentionally_ignored check for dummy tasks (#3552) Summary: Fixes the following crash: ```python Traceback (most recent call last): File "/private/home/msb/.conda/envs/fairseq-20210102-pt181/lib/python3.8/site-packages/torch/multiprocessing/spawn.py", line 59, in _wrap fn(i, *args) File "/private/home/msb/code/fairseq/fairseq/distributed/utils.py", line 328, in distributed_main main(cfg, **kwargs) File "/private/home/msb/code/fairseq/fairseq_cli/train.py", line 117, in main data_utils.raise_if_valid_subsets_unintentionally_ignored(cfg) File "/private/home/msb/code/fairseq/fairseq/data/data_utils.py", line 584, in raise_if_valid_subsets_unintentionally_ignored other_paths = _find_extra_valid_paths(train_cfg.task.data) AttributeError: 'Namespace' object has no attribute 'data' ``` Pull Request resolved: https://github.com/pytorch/fairseq/pull/3552 Reviewed By: sshleifer Differential Revision: D28667773 Pulled By: msbaines fbshipit-source-id: bc9a633184105dbae0cce58756bb1d379b03980a --- fairseq/data/data_utils.py | 1 + tests/test_valid_subset_checks.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 70a4086cd0..b3de57681e 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -583,6 +583,7 @@ def raise_if_valid_subsets_unintentionally_ignored(train_cfg) -> None: train_cfg.dataset.ignore_unused_valid_subsets or train_cfg.dataset.combine_valid_subsets or train_cfg.dataset.disable_validation + or not hasattr(train_cfg.task, "data") ): return other_paths = _find_extra_valid_paths(train_cfg.task.data) diff --git a/tests/test_valid_subset_checks.py b/tests/test_valid_subset_checks.py index ab778fb3fa..8da79cfb82 100644 --- a/tests/test_valid_subset_checks.py +++ b/tests/test_valid_subset_checks.py @@ -10,18 +10,20 @@ def make_lm_config( - data_dir, + data_dir=None, extra_flags=None, task="language_modeling", arch="transformer_lm_gpt2_tiny", ): + task_args = [task] + if data_dir is not None: + task_args += [data_dir] train_parser = options.get_training_parser() train_args = options.parse_args_and_arch( train_parser, [ "--task", - task, - data_dir, + *task_args, "--arch", arch, "--optimizer", @@ -97,6 +99,10 @@ def test_disable_validation(self): self._test_case([], ["--disable-validation"]) self._test_case(["valid", "valid1"], ["--disable-validation"]) + def test_dummy_task(self): + cfg = make_lm_config(task="dummy_lm") + raise_if_valid_subsets_unintentionally_ignored(cfg) + class TestCombineValidSubsets(unittest.TestCase): def _train(self, extra_flags): From 19793a78e5cd9aa0de427065f125c93100a942ea Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Thu, 27 May 2021 14:28:23 -0700 Subject: [PATCH 355/774] Remove duplicate registration of ManifoldPathHandler Summary: `ManifoldPathHandler` is automatically registered with `IOPathManager` upon importing the latter (see D27960781). Therefore it is no longer necessary to register `ManifoldPathManager` in fairseq, as introduced by D27809504 (https://github.com/pytorch/fairseq/commit/3a90a859d4dfdbf13f15399be12a1928aa2c54ff). Reviewed By: sujitoc Differential Revision: D28735316 fbshipit-source-id: 03e246dd17ba9f2a9a81dd4e741cce88f26feedd --- fairseq/file_io.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fairseq/file_io.py b/fairseq/file_io.py index 6266e6a1d8..dba663d4aa 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -29,14 +29,6 @@ "S3PathHandler couldn't be imported. Either missing fb-only files, or boto3 module." ) - try: - # [FB only] Add extra FB only PathHandlers for PathManager - import fairseq.fb_file_io as fb_file_io - - fb_file_io.update_path_manager(IOPathManager) - except ImportError: - pass - except ImportError: IOPathManager = None From 62ccebaf70cd8d392e178b67e0af661da0431a20 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Mon, 31 May 2021 01:13:41 -0700 Subject: [PATCH 356/774] =?UTF-8?q?fix=20'=5Fpickle.PicklingError:=20Can't?= =?UTF-8?q?=20pickle=20<enum=20'Choices'>:=20attribute=20=E2=80=A6=20(#191?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: for whatever reason, checkpoints are failing to save because choiceenum can't be pickled again (could be env specific). this should permanently resolve it by converting choice enum to string in the config before saving Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1915 Reviewed By: arbabu123 Differential Revision: D28784506 Pulled By: alexeib fbshipit-source-id: 17843cfa00e8e624eb06262df8e1b71b062a237b --- fairseq/trainer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index d1d08025f6..64c6fabed6 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -369,7 +369,7 @@ def state_dict(self): state_dict = { "args": None, # legacy "cfg": ( - OmegaConf.to_container(self.cfg) + OmegaConf.to_container(self.cfg, resolve=True, enum_to_str=True) if OmegaConf.is_config(self.cfg) else self.cfg ), From c47a9b2eef0f41b0564c8daf52cb82ea97fc6548 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Tue, 1 Jun 2021 16:42:48 -0700 Subject: [PATCH 357/774] fix #3574 (#1921) Summary: support pre-hydra w2v models Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1921 Reviewed By: arbabu123 Differential Revision: D28807630 Pulled By: alexeib fbshipit-source-id: 0fc8bcda12cf677e909d88678f235bfdeb50e726 --- fairseq/tasks/audio_pretraining.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index ce454e12b7..c642ff5226 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -303,7 +303,7 @@ def build_model(self, model_cfg: FairseqDataclass): else: self.tokenizer = None - actualized_cfg = getattr(model, "cfg") + actualized_cfg = getattr(model, "cfg", None) if actualized_cfg is not None: if "w2v_args" in actualized_cfg: model_cfg.w2v_args = actualized_cfg.w2v_args From 4950c56f461db1646872159b2c470fe57ae72c69 Mon Sep 17 00:00:00 2001 From: Henry Hu <henryhu6@fb.com> Date: Thu, 3 Jun 2021 16:19:27 -0700 Subject: [PATCH 358/774] Add export flag to transform, so LayerNorm can be TorchScripted. Summary: Previously on cuda, LayerNorm would always default to FusedLayerNorm, which could not be exported. Add export flag, so torch.nn.LayerNorm would be used. Reviewed By: myleott, mikekgfb, kpuatfb Differential Revision: D28858633 fbshipit-source-id: 58dd4945f596b2bcc94a6b74356bd9fd3c73ca1a --- fairseq/models/transformer.py | 12 ++++++------ fairseq/modules/transformer_layer.py | 10 ++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index b7b8783fa2..f4f6bea27b 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -378,9 +378,9 @@ def __init__(self, args, dictionary, embed_tokens): if not args.no_token_positional_embeddings else None ) - + export = getattr(args, "export", False) if getattr(args, "layernorm_embedding", False): - self.layernorm_embedding = LayerNorm(embed_dim) + self.layernorm_embedding = LayerNorm(embed_dim, export=export) else: self.layernorm_embedding = None @@ -403,7 +403,7 @@ def __init__(self, args, dictionary, embed_tokens): self.num_layers = len(self.layers) if args.encoder_normalize_before: - self.layer_norm = LayerNorm(embed_dim) + self.layer_norm = LayerNorm(embed_dim, export=export) else: self.layer_norm = None @@ -702,9 +702,9 @@ def __init__( if not args.no_token_positional_embeddings else None ) - + export = getattr(args, "export", False) if getattr(args, "layernorm_embedding", False): - self.layernorm_embedding = LayerNorm(embed_dim) + self.layernorm_embedding = LayerNorm(embed_dim, export=export) else: self.layernorm_embedding = None @@ -725,7 +725,7 @@ def __init__( if args.decoder_normalize_before and not getattr( args, "no_decoder_final_norm", False ): - self.layer_norm = LayerNorm(embed_dim) + self.layer_norm = LayerNorm(embed_dim, export=export) else: self.layer_norm = None diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index f9ada37bde..4f9ea22a9b 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -36,7 +36,8 @@ def __init__(self, args): self.quant_noise = getattr(args, 'quant_noise_pq', 0) self.quant_noise_block_size = getattr(args, 'quant_noise_pq_block_size', 8) or 8 self.self_attn = self.build_self_attention(self.embed_dim, args) - self.self_attn_layer_norm = LayerNorm(self.embed_dim) + export = getattr(args, "export", False) + self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) self.dropout_module = FairseqDropout( args.dropout, module_name=self.__class__.__name__ ) @@ -64,7 +65,7 @@ def __init__(self, args): self.quant_noise_block_size, ) - self.final_layer_norm = LayerNorm(self.embed_dim) + self.final_layer_norm = LayerNorm(self.embed_dim, export=export) def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): return quant_noise( @@ -207,10 +208,7 @@ def __init__( ) self.normalize_before = args.decoder_normalize_before - # use layerNorm rather than FusedLayerNorm for exporting. - # char_inputs can be used to determint this. - # TODO remove this once we update apex with the fix - export = getattr(args, "char_inputs", False) + export = getattr(args, "export", False) self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) if no_encoder_attn: From 50f3766a9d8413a5875a9b2b599b233b5690c7f2 Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Thu, 3 Jun 2021 17:48:17 -0700 Subject: [PATCH 359/774] TALNet: Use batch size as sample_size Summary: `Wav2VecCriterion` uses a sample_size for two purposes: 1. It weights the extra loss by multiplying it by sample_size; 2. It divides the total loss by sample_size before reporting them in the learning curves. By default, when using the binary cross-entropy loss (`infonce = False`), `Wav2VecCriterion` uses the number of 1's in the label matrix as sample_size. For TALNet, because each recording may have multiple labels, this sample_size is not a constant across batches. TALNet also uses a consistency loss between the predictions on two different copies of augmented data as an extra loss, and it is undesirable for the weight of the extra loss to vary from batch to batch. This diff adds a field "sample_size" to the batch in the `AcousticEventCollater`, and makes it equal to the batch size (number or recordings in a batch). Because the extra loss is multiplied by sample_size in `Wav2VecCriterion`, this diff also divides the consistency loss by the batch size in the `forward` method of `TALNetModel`. This diff also adds a unit test for the consistency loss. Reviewed By: alexeib Differential Revision: D28728699 fbshipit-source-id: dda1f2a1b02e49b894842c8990218b5fe92d0330 --- fairseq/criterions/wav2vec_criterion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index 521d0cf1ad..a5048fdb4a 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -82,7 +82,7 @@ def forward(self, model, sample, reduce=True): ) loss = (loss * mi).sum() if reduce else (loss * mi) - if 'sample_size' in sample and self.infonce: + if 'sample_size' in sample: sample_size = sample['sample_size'] elif 'mask_indices' in sample['net_input']: sample_size = sample['net_input']['mask_indices'].sum() From 3084b812beb72a880b6ddb5d9076ead60b7232d6 Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Thu, 3 Jun 2021 17:48:17 -0700 Subject: [PATCH 360/774] Teacher-student learning for TALNet Summary: This diff implements teacher-student learning for TALNet. Three classes take part in the teacher-student learning: * The task loads the teacher models; * The model generates predictions using the teacher models, and mixes them with the original targets; * The `Wav2VecCriterion` reads the mixed targets to compute the loss. However, it still uses the original targets to compute the MAP and MAUC metrics. There are two types of teachers: * Static teachers: a file that stores predictions on training data which have been produced by running a model offline; * Dynamic teachers: model files that are loaded at the beginning of training and executed on the fly to produce predictions. We actually no longer use static teachers. The code about static teachers are copied over from the `KnowledgeDistillationBinaryCrossEntropyCriterion` class. This class will be cleaned up in D28728718. The teacher models are stored in the task object, and will not be saved into checkpoints. Reviewed By: alexeib Differential Revision: D28728707 fbshipit-source-id: 0fcfc00db2e7194a6f7ee687cad9fa72e82a028b --- fairseq/checkpoint_utils.py | 9 +++++++++ fairseq/criterions/wav2vec_criterion.py | 8 +++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index ecc45f4351..402921744d 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -611,6 +611,15 @@ def _upgrade_state_dict(state): and len(state["args"].data) > 0 ): state["args"].data = state["args"].data[0] + # remove keys in state["args"] related to teacher-student learning + for key in [ + "static_teachers", + "static_teacher_weights", + "dynamic_teachers", + "dynamic_teacher_weights", + ]: + if key in state["args"]: + delattr(state["args"], key) state["cfg"] = convert_namespace_to_omegaconf(state["args"]) diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index a5048fdb4a..e04786cc3b 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -121,7 +121,13 @@ def forward(self, model, sample, reduce=True): logging_output["logits"] = logits.cpu().numpy() elif lk == "target": if not self.training: - logging_output["target"] = target.cpu().numpy() + # If the targets have been mixed with the predictions of + # teacher models, find the original targets + if hasattr(model, "get_original_targets"): + original_target = model.get_original_targets(sample, net_output) + else: + original_target = target + logging_output["target"] = original_target.cpu().numpy() elif lk in net_output: value = net_output[lk] if not is_xla_tensor(value): From 45d8fefaa6871afbb747e5e65ba58b8f9fda37fe Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines <mandeep.baines@gmail.com> Date: Fri, 4 Jun 2021 11:23:32 -0700 Subject: [PATCH 361/774] fix logging when running single-process (#3592) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: In file_io.py, there is a logging message that happens in the global scope. This logging message can be invoked before calling logging.basicConfig() in fairseq_cli/train.py resulting in that call becoming a no-op. This was causing the loglevel to remain at WARNING. Fix is to call logging.basicConfig() before import-ing any fairseq libraries that may do logging in global scope. Verified that I logging.info messages are now visible after applying this PR. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3592 Reviewed By: sujitoc Differential Revision: D28900871 Pulled By: msbaines fbshipit-source-id: ff5393aa7c5e4cbec168ff0b846da048de76cdbc --- fairseq_cli/train.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index a1b7cb58e2..8347587313 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -14,6 +14,15 @@ import sys from typing import Dict, Optional, Any, List, Tuple, Callable +# We need to setup root logger before importing any fairseq libraries. +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("fairseq_cli.train") + import numpy as np import torch from fairseq import ( @@ -35,13 +44,6 @@ from omegaconf import DictConfig, OmegaConf -logging.basicConfig( - format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - level=os.environ.get("LOGLEVEL", "INFO").upper(), - stream=sys.stdout, -) -logger = logging.getLogger("fairseq_cli.train") def main(cfg: FairseqConfig) -> None: From fc391ff6974969649ec94dc18eb7795de66bda4f Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Fri, 4 Jun 2021 16:19:04 -0700 Subject: [PATCH 362/774] Fix loading some TALNet models Summary: D28728718 cleaned up the "kd_binary_cross_entropy" criterion, but this caused loading old models trained with this criterion to fail. This diff replaces the "kd_binary_cross_entropy" criterion with the "wav2vec" criterion when loading models, and fixes this error. It also removes the "log_keys" argument if it's `None`. Some criteria (e.g. wav2vec) require this argument to be a list, and will supply a default value of `[]` when it's absent. The presence of the `None` value prevents the use of this default value and causes an error. Differential Revision: D28901263 fbshipit-source-id: 9b33aed35e76d2c734d1d4e2cbca1ff193a8c920 --- fairseq/checkpoint_utils.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 402921744d..80c797bcdd 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -16,7 +16,7 @@ from random import randint import torch -from fairseq.dataclass.configs import CheckpointConfig, FairseqConfig +from fairseq.dataclass.configs import CheckpointConfig from fairseq.dataclass.utils import ( convert_namespace_to_omegaconf, overwrite_args_by_name, @@ -24,7 +24,7 @@ from fairseq.distributed.fully_sharded_data_parallel import FSDP, has_FSDP from fairseq.file_io import PathManager from fairseq.models import FairseqDecoder, FairseqEncoder -from omegaconf import Container, DictConfig, open_dict, OmegaConf +from omegaconf import DictConfig, open_dict, OmegaConf logger = logging.getLogger(__name__) @@ -512,7 +512,6 @@ def _torch_persistent_save(obj, f): def _upgrade_state_dict(state): """Helper for upgrading old model checkpoints.""" - from fairseq import models, registry, tasks # add optimizer_history if "optimizer_history" not in state: @@ -586,12 +585,18 @@ def _upgrade_state_dict(state): if hasattr(state["args"], "min_lr"): state["args"].stop_min_lr = state["args"].min_lr del state["args"].min_lr - # binary_cross_entropy => wav2vec criterion + # binary_cross_entropy / kd_binary_cross_entropy => wav2vec criterion if ( hasattr(state["args"], "criterion") - and state["args"].criterion == "binary_cross_entropy" + and state["args"].criterion in [ + "binary_cross_entropy", + "kd_binary_cross_entropy", + ] ): state["args"].criterion = "wav2vec" + # remove log_keys if it's None (criteria will supply a default value of []) + if hasattr(state["args"], "log_keys") and state["args"].log_keys is None: + delattr(state["args"], "log_keys") # speech_pretraining => audio pretraining if ( hasattr(state["args"], "task") From 2fd9d8a972794ba919174baf0d1828a5a4c626f3 Mon Sep 17 00:00:00 2001 From: Naman Goyal <namangoyal@learnfair1299.h2.fair> Date: Mon, 7 Jun 2021 15:04:31 -0700 Subject: [PATCH 363/774] released xlmr xl and xxl model weights (#1944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1944 Reviewed By: jingfeidu Differential Revision: D28944206 fbshipit-source-id: 583837f7dd387341574d27dd9acc145455d640a8 --- README.md | 1 + examples/xlmr/README.md | 31 +++++++++++++++++++++++----- fairseq/models/roberta/model_xlmr.py | 2 ++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 839dd8e1de..82b6ba7cd8 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ We provide reference implementations of various sequence modeling papers: ### What's New: +* June 2021 [Released XLMR-XL and XLMR-XXL models](examples/xlmr/README.md) * March 2021 [Added full parameter and optimizer state sharding + CPU offloading](examples/fully_sharded_data_parallel/README.md) * February 2021 [Added LASER training code](examples/laser/README.md) * December 2020: [Added Adaptive Attention Span code](examples/adaptive_span/README.md) diff --git a/examples/xlmr/README.md b/examples/xlmr/README.md index 65d4be13de..b95bfe15d3 100644 --- a/examples/xlmr/README.md +++ b/examples/xlmr/README.md @@ -1,9 +1,16 @@ # Unsupervised Cross-lingual Representation Learning at Scale (XLM-RoBERTa) https://arxiv.org/pdf/1911.02116.pdf +# Larger-Scale Transformers for Multilingual Masked Language Modeling +https://arxiv.org/pdf/2105.00572.pdf + + +## What's New: +- June 2021: `XLMR-XL` AND `XLMR-XXL` models released. + ## Introduction -XLM-R (XLM-RoBERTa) is a generic cross lingual sentence encoder that obtains state-of-the-art results on many cross-lingual understanding (XLU) benchmarks. It is trained on 2.5T of filtered CommonCrawl data in 100 languages (list below). +`XLM-R` (`XLM-RoBERTa`) is a generic cross lingual sentence encoder that obtains state-of-the-art results on many cross-lingual understanding (XLU) benchmarks. It is trained on `2.5T` of filtered CommonCrawl data in 100 languages (list below). Language | Language|Language |Language | Language ---|---|---|---|--- @@ -34,8 +41,8 @@ Model | Description | #params | vocab size | Download ---|---|---|---|--- `xlmr.base` | XLM-R using the BERT-base architecture | 250M | 250k | [xlm.base.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr.base.tar.gz) `xlmr.large` | XLM-R using the BERT-large architecture | 560M | 250k | [xlm.large.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr.large.tar.gz) - -(Note: Above are final model checkpoints. If you were using previously released `v0` version, we recommend using above. They have same architecture and dictionary.) +`xlmr.xl` | XLM-R (`layers=36, model_dim=2560`) | 3.5B | 250k | [xlm.xl.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr/xlmr.xl.tar.gz) +`xlmr.xxl` | XLM-R (`layers=48, model_dim=4096`) | 10.7B | 250k | [xlm.xxl.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xlmr/xlmr.xxl.tar.gz) ## Results @@ -44,7 +51,9 @@ Model | Description | #params | vocab size | Download Model | average | en | fr | es | de | el | bg | ru | tr | ar | vi | th | zh | hi | sw | ur ---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|--- `roberta.large.mnli` _(TRANSLATE-TEST)_ | 77.8 | 91.3 | 82.9 | 84.3 | 81.2 | 81.7 | 83.1 | 78.3 | 76.8 | 76.6 | 74.2 | 74.1 | 77.5 | 70.9 | 66.7 | 66.8 -`xlmr.large` _(TRANSLATE-TRAIN-ALL)_ | **83.6** | 89.1 | 85.1 | 86.6 | 85.7 | 85.3 | 85.9 | 83.5 | 83.2 | 83.1 | 83.7 | 81.5 | 83.7 | 81.6 | 78.0 | 78.1 +`xlmr.large` _(TRANSLATE-TRAIN-ALL)_ | 83.6 | 89.1 | 85.1 | 86.6 | 85.7 | 85.3 | 85.9 | 83.5 | 83.2 | 83.1 | 83.7 | 81.5 | 83.7 | 81.6 | 78.0 | 78.1 +`xlmr.xl` _(TRANSLATE-TRAIN-ALL)_ | 85.4 | 91.1 | 87.2 | 88.1 | 87.0 | 87.4 | 87.8 | 85.3 | 85.2 | 85.3 | 86.2 | 83.8 | 85.3 | 83.1 | 79.8 | 78.2 | 85.4 +`xlmr.xxl` _(TRANSLATE-TRAIN-ALL)_ | 86.0 | 91.5 | 87.6 | 88.7 | 87.8 | 87.4 | 88.2 | 85.6 | 85.1 | 85.8 | 86.3 | 83.9 | 85.6 | 84.6 | 81.7 | 80.6 **[MLQA (Lewis et al., 2018)](https://arxiv.org/abs/1910.07475)** @@ -52,7 +61,9 @@ Model | average | en | es | de | ar | hi | vi | zh ---|---|---|---|---|---|---|---|--- `BERT-large` | - | 80.2/67.4 | - | - | - | - | - | - `mBERT` | 57.7 / 41.6 | 77.7 / 65.2 | 64.3 / 46.6 | 57.9 / 44.3 | 45.7 / 29.8| 43.8 / 29.7 | 57.1 / 38.6 | 57.5 / 37.3 -`xlmr.large` | **70.7 / 52.7** | 80.6 / 67.8 | 74.1 / 56.0 | 68.5 / 53.6 | 63.1 / 43.5 | 69.2 / 51.6 | 71.3 / 50.9 | 68.0 / 45.4 +`xlmr.large` | 70.7 / 52.7 | 80.6 / 67.8 | 74.1 / 56.0 | 68.5 / 53.6 | 63.1 / 43.5 | 69.2 / 51.6 | 71.3 / 50.9 | 68.0 / 45.4 +`xlmr.xl` | 73.4 / 55.3 | 85.1 / 72.6 | 66.7 / 46.2 | 70.5 / 55.5 | 74.3 / 56.9 | 72.2 / 54.7 | 74.4 / 52.9 | 70.9 / 48.5 +`xlmr.xxl` | 74.8 / 56.6 | 85.5 / 72.4 | 68.6 / 48.4 | 72.7 / 57.8 | 75.4 / 57.6 | 73.7 / 55.8 | 76.0 / 55.0 | 71.7 / 48.9 ## Example usage @@ -121,3 +132,13 @@ assert torch.all(all_layers[-1] == last_layer_features) year={2019} } ``` + + +```bibtex +@article{goyal2021larger, + title={Larger-Scale Transformers for Multilingual Masked Language Modeling}, + author={Goyal, Naman and Du, Jingfei and Ott, Myle and Anantharaman, Giri and Conneau, Alexis}, + journal={arXiv preprint arXiv:2105.00572}, + year={2021} +} +``` diff --git a/fairseq/models/roberta/model_xlmr.py b/fairseq/models/roberta/model_xlmr.py index 5886880f73..cf6e354d53 100644 --- a/fairseq/models/roberta/model_xlmr.py +++ b/fairseq/models/roberta/model_xlmr.py @@ -19,6 +19,8 @@ def hub_models(cls): return { "xlmr.base": "http://dl.fbaipublicfiles.com/fairseq/models/xlmr.base.tar.gz", "xlmr.large": "http://dl.fbaipublicfiles.com/fairseq/models/xlmr.large.tar.gz", + "xlmr.xl": "http://dl.fbaipublicfiles.com/fairseq/models/xlmr/xlmr.xl.tar.gz", + "xlmr.xxl": "http://dl.fbaipublicfiles.com/fairseq/models/xlmr/xlmr.xxl.tar.gz", } @classmethod From 50158da3a7b293f2d2fa06a23e90c160b92f54ce Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Thu, 10 Jun 2021 09:42:18 -0700 Subject: [PATCH 364/774] Migrate DummyMaskedLMTask to FairseqTask (#3593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3593 Reviewed By: msbaines Differential Revision: D28992614 Pulled By: dianaml0 fbshipit-source-id: b2dfcab472a65c41536e78600a0e6b3745dc3a08 --- fairseq/benchmark/__init__.py | 2 +- fairseq/benchmark/dummy_dataset.py | 36 ++++++++ fairseq/benchmark/dummy_lm.py | 39 +-------- fairseq/benchmark/dummy_masked_lm.py | 119 ++++++++++----------------- tests/test_valid_subset_checks.py | 4 + 5 files changed, 86 insertions(+), 114 deletions(-) create mode 100644 fairseq/benchmark/dummy_dataset.py diff --git a/fairseq/benchmark/__init__.py b/fairseq/benchmark/__init__.py index f6584661bd..0317d5c623 100644 --- a/fairseq/benchmark/__init__.py +++ b/fairseq/benchmark/__init__.py @@ -4,4 +4,4 @@ # LICENSE file in the root directory of this source tree. # import models/tasks to register them -from . import dummy_lm, dummy_masked_lm, dummy_model, dummy_mt # noqa +from . import dummy_dataset, dummy_lm, dummy_masked_lm, dummy_model, dummy_mt # noqa diff --git a/fairseq/benchmark/dummy_dataset.py b/fairseq/benchmark/dummy_dataset.py new file mode 100644 index 0000000000..2f051754af --- /dev/null +++ b/fairseq/benchmark/dummy_dataset.py @@ -0,0 +1,36 @@ +import numpy as np +from fairseq.data import FairseqDataset + + +class DummyDataset(FairseqDataset): + def __init__(self, batch, num_items, item_size): + super().__init__() + self.batch = batch + self.num_items = num_items + self.item_size = item_size + + def __getitem__(self, index): + return index + + def __len__(self): + return self.num_items + + def collater(self, samples): + return self.batch + + @property + def sizes(self): + return np.array([self.item_size] * self.num_items) + + def num_tokens(self, index): + return self.item_size + + def size(self, index): + return self.item_size + + def ordered_indices(self): + return np.arange(self.num_items) + + @property + def supports_prefetch(self): + return False diff --git a/fairseq/benchmark/dummy_lm.py b/fairseq/benchmark/dummy_lm.py index d917e28837..c6246a0c0e 100644 --- a/fairseq/benchmark/dummy_lm.py +++ b/fairseq/benchmark/dummy_lm.py @@ -7,9 +7,9 @@ from dataclasses import dataclass, field from typing import Optional -import numpy as np import torch -from fairseq.data import Dictionary, FairseqDataset +from .dummy_dataset import DummyDataset +from fairseq.data import Dictionary from fairseq.dataclass import FairseqDataclass from fairseq.tasks import FairseqTask, register_task from omegaconf import II @@ -33,7 +33,6 @@ class DummyLMConfig(FairseqDataclass): @register_task("dummy_lm", dataclass=DummyLMConfig) class DummyLMTask(FairseqTask): - def __init__(self, cfg: DummyLMConfig): super().__init__(cfg) @@ -82,37 +81,3 @@ def source_dictionary(self): @property def target_dictionary(self): return self.dictionary - - -class DummyDataset(FairseqDataset): - def __init__(self, batch, num_items, item_size): - super().__init__() - self.batch = batch - self.num_items = num_items - self.item_size = item_size - - def __getitem__(self, index): - return index - - def __len__(self): - return self.num_items - - def collater(self, samples): - return self.batch - - @property - def sizes(self): - return np.array([self.item_size] * self.num_items) - - def num_tokens(self, index): - return self.item_size - - def size(self, index): - return self.item_size - - def ordered_indices(self): - return np.arange(self.num_items) - - @property - def supports_prefetch(self): - return False diff --git a/fairseq/benchmark/dummy_masked_lm.py b/fairseq/benchmark/dummy_masked_lm.py index ab506fe1d5..12b9c5d0f5 100644 --- a/fairseq/benchmark/dummy_masked_lm.py +++ b/fairseq/benchmark/dummy_masked_lm.py @@ -4,43 +4,53 @@ # LICENSE file in the root directory of this source tree. import logging +from dataclasses import dataclass, field +from typing import Optional -import numpy as np import torch -from fairseq.data import Dictionary, FairseqDataset -from fairseq.tasks import LegacyFairseqTask, register_task +from omegaconf import II +from .dummy_dataset import DummyDataset +from fairseq.data import Dictionary +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task logger = logging.getLogger(__name__) -@register_task("dummy_masked_lm") -class DummyMaskedLMTask(LegacyFairseqTask): - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - parser.add_argument("--dict-size", default=49995, type=int) - parser.add_argument("--dataset-size", default=100000, type=int) - parser.add_argument( - "--tokens-per-sample", - default=512, - type=int, - help="max number of total tokens over all segments " - "per sample for BERT dataset", - ) - - def __init__(self, args, dictionary): - super().__init__(args) - self.dictionary = dictionary - +@dataclass +class DummyMaskedLMConfig(FairseqDataclass): + dict_size: int = 49996 + dataset_size: int = 100000 + tokens_per_sample: int = field( + default=512, + metadata={ + "help": "max number of total tokens over all" + " segments per sample for BERT dataset" + }, + ) + batch_size: Optional[int] = II("dataset.batch_size") + max_tokens: Optional[int] = II("dataset.max_tokens") + max_target_positions: int = II("task.tokens_per_sample") + + +@register_task("dummy_masked_lm", dataclass=DummyMaskedLMConfig) +class DummyMaskedLMTask(FairseqTask): + def __init__(self, cfg: DummyMaskedLMConfig): + super().__init__(cfg) + + self.dictionary = Dictionary() + for i in range(cfg.dict_size): + self.dictionary.add_symbol("word{}".format(i)) + logger.info("dictionary: {} types".format(len(self.dictionary))) # add mask token - self.mask_idx = dictionary.add_symbol("<mask>") - dictionary.pad_to_multiple_(8) # often faster if divisible by 8 + self.mask_idx = self.dictionary.add_symbol("<mask>") + self.dictionary.pad_to_multiple_(8) # often faster if divisible by 8 mask_idx = 0 pad_idx = 1 - seq = torch.arange(args.tokens_per_sample) + pad_idx + 1 - mask = torch.arange(2, args.tokens_per_sample, 7) # ~15% + seq = torch.arange(cfg.tokens_per_sample) + pad_idx + 1 + mask = torch.arange(2, cfg.tokens_per_sample, 7) # ~15% src = seq.clone() src[mask] = mask_idx tgt = torch.full_like(seq, pad_idx) @@ -49,39 +59,30 @@ def __init__(self, args, dictionary): self.dummy_src = src self.dummy_tgt = tgt - @classmethod - def setup_task(cls, args, **kwargs): - """Setup the task. """ - dictionary = Dictionary() - for i in range(args.dict_size): - dictionary.add_symbol("word{}".format(i)) - logger.info("dictionary: {} types".format(len(dictionary))) - return cls(args, dictionary) - def load_dataset(self, split, epoch=1, combine=False, **kwargs): """Load a given dataset split. Args: split (str): name of the split (e.g., train, valid, test) """ - if self.args.batch_size is not None: - bsz = self.args.batch_size + if self.cfg.batch_size is not None: + bsz = self.cfg.batch_size else: - bsz = max(1, self.args.max_tokens // self.args.tokens_per_sample) + bsz = max(1, self.cfg.max_tokens // self.cfg.tokens_per_sample) self.datasets[split] = DummyDataset( { "id": 1, "net_input": { "src_tokens": torch.stack([self.dummy_src for _ in range(bsz)]), "src_lengths": torch.full( - (bsz,), self.args.tokens_per_sample, dtype=torch.long + (bsz,), self.cfg.tokens_per_sample, dtype=torch.long ), }, "target": torch.stack([self.dummy_tgt for _ in range(bsz)]), "nsentences": bsz, - "ntokens": bsz * self.args.tokens_per_sample, + "ntokens": bsz * self.cfg.tokens_per_sample, }, - num_items=self.args.dataset_size, - item_size=self.args.tokens_per_sample, + num_items=self.cfg.dataset_size, + item_size=self.cfg.tokens_per_sample, ) @property @@ -91,37 +92,3 @@ def source_dictionary(self): @property def target_dictionary(self): return self.dictionary - - -class DummyDataset(FairseqDataset): - def __init__(self, batch, num_items, item_size): - super().__init__() - self.batch = batch - self.num_items = num_items - self.item_size = item_size - - def __getitem__(self, index): - return index - - def __len__(self): - return self.num_items - - def collater(self, samples): - return self.batch - - @property - def sizes(self): - return np.array([self.item_size] * self.num_items) - - def num_tokens(self, index): - return self.item_size - - def size(self, index): - return self.item_size - - def ordered_indices(self): - return np.arange(self.num_items) - - @property - def supports_prefetch(self): - return False diff --git a/tests/test_valid_subset_checks.py b/tests/test_valid_subset_checks.py index 8da79cfb82..3e9191bda6 100644 --- a/tests/test_valid_subset_checks.py +++ b/tests/test_valid_subset_checks.py @@ -103,6 +103,10 @@ def test_dummy_task(self): cfg = make_lm_config(task="dummy_lm") raise_if_valid_subsets_unintentionally_ignored(cfg) + def test_masked_dummy_task(self): + cfg = make_lm_config(task="dummy_masked_lm") + raise_if_valid_subsets_unintentionally_ignored(cfg) + class TestCombineValidSubsets(unittest.TestCase): def _train(self, extra_flags): From f8a7c93440cd925f70979a6082c18f830b39e44b Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 10 Jun 2021 21:57:48 -0700 Subject: [PATCH 365/774] W2v u update (#1954) Summary: updating the scripts and examples to be easier to follow Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1954 Reviewed By: wnhsu Differential Revision: D29041166 Pulled By: alexeib fbshipit-source-id: d9410c6e925337b810e92b393e226869ef9e1733 --- .../kaldi/config/kaldi_initializer.yaml | 8 +++ examples/speech_recognition/w2l_decoder.py | 51 +++++---------- examples/wav2vec/unsupervised/README.md | 60 +++++++++++------ .../wav2vec/unsupervised/config/gan/w2vu.yaml | 7 ++ .../unsupervised/config/generate/viterbi.yaml | 1 - .../wav2vec/unsupervised/models/wav2vec_u.py | 65 +++++++------------ .../wav2vec/unsupervised/scripts/apply_pca.py | 8 ++- .../unsupervised/scripts/g2p_wrd_to_phn.py | 20 +++--- .../wav2vec/unsupervised/scripts/mean_pool.py | 13 +++- .../unsupervised/scripts/merge_clusters.py | 14 ++-- .../scripts/normalize_and_filter_text.py | 29 +++++++-- .../unsupervised/scripts/prepare_audio.sh | 45 +++++++++---- .../unsupervised/scripts/prepare_text.sh | 60 ++++++++++++----- .../unsupervised/scripts/remove_silence.py | 1 - examples/wav2vec/unsupervised/scripts/vads.py | 25 +++++-- .../scripts/wav2vec_apply_cluster_faiss.py | 29 +++++++-- .../scripts/wav2vec_extract_features.py | 8 ++- .../unsupervised/tasks/unpaired_audio_text.py | 34 ++++++---- .../wav2vec/unsupervised/w2vu_generate.py | 3 + fairseq/models/__init__.py | 46 +++++++------ fairseq/models/wav2vec/wav2vec.py | 2 +- fairseq/tasks/__init__.py | 52 ++++++++------- fairseq/utils.py | 17 +++-- 23 files changed, 372 insertions(+), 226 deletions(-) create mode 100644 examples/speech_recognition/kaldi/config/kaldi_initializer.yaml diff --git a/examples/speech_recognition/kaldi/config/kaldi_initializer.yaml b/examples/speech_recognition/kaldi/config/kaldi_initializer.yaml new file mode 100644 index 0000000000..be9ba98f55 --- /dev/null +++ b/examples/speech_recognition/kaldi/config/kaldi_initializer.yaml @@ -0,0 +1,8 @@ +# @package _group_ + +data_dir: ??? +fst_dir: ??? +in_labels: ??? +kaldi_root: ??? +lm_arpa: ??? +blank_symbol: <s> diff --git a/examples/speech_recognition/w2l_decoder.py b/examples/speech_recognition/w2l_decoder.py index 8b158293a0..aef4481593 100644 --- a/examples/speech_recognition/w2l_decoder.py +++ b/examples/speech_recognition/w2l_decoder.py @@ -52,29 +52,19 @@ def __init__(self, args, tgt_dict): self.nbest = args.nbest # criterion-specific init - if args.criterion == "ctc": - self.criterion_type = CriterionType.CTC - self.blank = ( - tgt_dict.index("<ctc_blank>") - if "<ctc_blank>" in tgt_dict.indices - else tgt_dict.bos() - ) - if "<sep>" in tgt_dict.indices: - self.silence = tgt_dict.index("<sep>") - elif "|" in tgt_dict.indices: - self.silence = tgt_dict.index("|") - else: - self.silence = tgt_dict.eos() - self.asg_transitions = None - elif args.criterion == "asg_loss": - self.criterion_type = CriterionType.ASG - self.blank = -1 - self.silence = -1 - self.asg_transitions = args.asg_transitions - self.max_replabel = args.max_replabel - assert len(self.asg_transitions) == self.vocab_size ** 2 + self.criterion_type = CriterionType.CTC + self.blank = ( + tgt_dict.index("<ctc_blank>") + if "<ctc_blank>" in tgt_dict.indices + else tgt_dict.bos() + ) + if "<sep>" in tgt_dict.indices: + self.silence = tgt_dict.index("<sep>") + elif "|" in tgt_dict.indices: + self.silence = tgt_dict.index("|") else: - raise RuntimeError(f"unknown criterion: {args.criterion}") + self.silence = tgt_dict.eos() + self.asg_transitions = None def generate(self, models, sample, **unused): """Generate a batch of inferences.""" @@ -90,23 +80,16 @@ def get_emissions(self, models, encoder_input): """Run encoder and normalize emissions""" model = models[0] encoder_out = model(**encoder_input) - if self.criterion_type == CriterionType.CTC: - if hasattr(model, "get_logits"): - emissions = model.get_logits(encoder_out) # no need to normalize emissions - else: - emissions = model.get_normalized_probs(encoder_out, log_probs=True) - elif self.criterion_type == CriterionType.ASG: - emissions = encoder_out["encoder_out"] + if hasattr(model, "get_logits"): + emissions = model.get_logits(encoder_out) # no need to normalize emissions + else: + emissions = model.get_normalized_probs(encoder_out, log_probs=True) return emissions.transpose(0, 1).float().cpu().contiguous() def get_tokens(self, idxs): """Normalize tokens by handling CTC blank, ASG replabels, etc.""" idxs = (g[0] for g in it.groupby(idxs)) - if self.criterion_type == CriterionType.CTC: - idxs = filter(lambda x: x != self.blank, idxs) - elif self.criterion_type == CriterionType.ASG: - idxs = filter(lambda x: x >= 0, idxs) - idxs = unpack_replabels(list(idxs), self.tgt_dict, self.max_replabel) + idxs = filter(lambda x: x != self.blank, idxs) return torch.LongTensor(list(idxs)) diff --git a/examples/wav2vec/unsupervised/README.md b/examples/wav2vec/unsupervised/README.md index e9ec59f06d..c2a935d414 100644 --- a/examples/wav2vec/unsupervised/README.md +++ b/examples/wav2vec/unsupervised/README.md @@ -12,31 +12,41 @@ Similar to [wav2vec 2.0](https://github.com/pytorch/fairseq/blob/master/examples In **/path/to/data/with_silence** you need a *train.tsv* file as well as (optionally) *{valid,test}.{tsv,wrd,phn}*. It is nice to have *10h.{tsv,phn}* files there too for reproducing the ablation study on layer selection. In **/path/to/data/without_silence** you have the same files, except *.tsv* files contain audios with silences removed using rVAD. -Here is how you can create new audio files without silences from a list of input audio files: +Pre-requisites: +* set FAIRSEQ_ROOT environmental variable to your fairseq installation +* set RVAD_ROOT environmental variable to a checkout of [rVADfast](https://github.com/zhenghuatan/rVADfast) +* set KENLM_ROOT environmental variable to the location of [KenLM](https://github.com/kpu/kenlm) binaries +* install [PyKaldi](https://github.com/pykaldi/pykaldi) and set KALDI_ROOT environmental variable to the location of your kaldi installation. To use the version bundled with PyKaldi, you can use /path/to/pykaldi/tools/kaldi + +Create new audio files without silences: ```shell -python scripts/vads.py < /path/to/train.tsv > train.vads +# create a manifest file for the set original of audio files +python $FAIRSEQ_ROOT/examples/wav2vec/wav2vec_manifest.py /dir/to/save/audio/files --ext wav --dest /path/to/new/train.tsv --valid-percent 0 + +python scripts/vads.py -r $RVAD_ROOT < /path/to/train.tsv > train.vads python scripts/remove_silence.py --tsv /path/to/train.tsv --vads train.vads --out /dir/to/save/audio/files -python $FAIRSEQ_ROOT/examples/wav2vec/wav2vec_manifest.py /dir/to/save/audio/files --ext wav --dest /path/to/new/train.tsv --valid-percent 0 +python $FAIRSEQ_ROOT/examples/wav2vec/wav2vec_manifest.py /dir/to/save/audio/files --ext wav --dest /path/to/new/train.tsv --valid-percent 0.01 ``` -You will need to add the path to rVAD directory to vads.py. - Next, we need to preprocess the audio data to better match phonemized text data: ```shell -zsh scripts/prepare_audio.sh /dir/with/{train,test,valid}.tsv /output/dir /path/to/wav2vec2/model.pt +zsh scripts/prepare_audio.sh /dir/with/{train,test,valid}.tsv /output/dir /path/to/wav2vec2/model.pt 512 14 ``` -Note that if you have splits different than train/valid/test, you will need to modify this script. +Note that if you have splits different than train/valid/test, you will need to modify this script. The last two arguments are the PCA dimensionality and the 0-based index of the layer from which to extract representations. Now we need to prepare text data: ```shell -zsh scripts/prepare_text.sh language /path/to/text/file /output/dir +zsh scripts/prepare_text.sh language /path/to/text/file /output/dir 1000 espeak /path/to/fasttext/lid/model ``` -Note that if you want to use a different phonemizer, such as G2P, you will need to modify this script. +The fourth argument is minimum number observations of phones to keep. If your text corpus is small, you might want to reduce this number. +The fifth argument is which phonemizer to use. Supported values are [espeak](http://espeak.sourceforge.net/), [espeak-ng](https://github.com/espeak-ng/espeak-ng), and [G2P](https://github.com/Kyubyong/g2p) (english only). + +Pre-trained fasttext LID models can be downloaded [here](https://fasttext.cc/docs/en/language-identification.html). ## Generative adversarial training (GAN) @@ -46,26 +56,34 @@ Launching GAN training on top of preprocessed features, with default hyperparame ``` PREFIX=w2v_unsup_gan_xp -TASK_DATA=/path/to/features/unfiltered/precompute_unfiltered_pca512_cls128_mean_pooled -TEXT_DATA=/path/to/data # path to fairseq-preprocessed GAN data -KENLM_PATH=/path/to/data/kenlm.phn.o4.bin # KenLM 4-gram phoneme language model (LM data = GAN data here) - -PREFIX=$PREFIX fairseq-hydra-train \ - -m --config-dir configs/gan \ - --config-name w2vu \ - task.data=${TASK_DATA} \ - task.text_data=${TEXT_DATA} \ - task.kenlm_path=${KENLM_PATH} \ - 'common.seed=range(0,5)' & +TASK_DATA=/path/to/features/precompute_unfiltered_pca512_cls128_mean_pooled +TEXT_DATA=/path/to/data/phones # path to fairseq-preprocessed GAN data (phones dir) +KENLM_PATH=/path/to/data/phones/kenlm.phn.o4.bin # KenLM 4-gram phoneme language model (LM data = GAN data here) + +PYTHONPATH=$FAIRSEQ_ROOT PREFIX=$PREFIX fairseq-hydra-train \ + -m --config-dir config/gan \ + --config-name w2vu \ + task.data=${TASK_DATA} \ + task.text_data=${TEXT_DATA} \ + task.kenlm_path=${KENLM_PATH} \ + common.user_dir=${FAIRSEQ_ROOT}/examples/wav2vec/unsupervised \ + model.code_penalty=2,4 model.gradient_penalty=1.5,2.0 \ + model.smoothness_weight=0.5,0.75,1.0 'common.seed=range(0,5)' ``` + Once we find the best checkpoint (chosen using unsupervised metric that combined language model perplexity and vocabulary usage), we can use it to generate phone labels (or word labels with an appropriate kaldi WFST): ```shell python w2vu_generate.py --config-dir config/generate --config-name viterbi \ -fairseq.task.data=/path/to/dir/with/tsvs fairseq.common_eval.path=/path/to/gan/checkpoint \ +fairseq.common.user_dir=${FAIRSEQ_ROOT}/examples/wav2vec/unsupervised \ +fairseq.task.data=/path/to/dir/with/features \ +fairseq.common_eval.path=/path/to/gan/checkpoint \ fairseq.dataset.gen_subset=valid results_path=/where/to/save/transcriptions ``` + +The decoding without LM works best on the same adjacent-mean-pooled features that the gan was trained on, while decoding with LM works better on features before the adjacent timestep mean-pooling step (without the "_pooled" suffix). + ## Iterative self-training + Kaldi LM-decoding After the GAN training provides a first unsupervised model, we can then progressively refine the quality of transcriptions using several iterations of semi-supervised learning. We perform two iterations: first, pseudo-label the training data with the unsupervised GAN model and train an HMM on the pseudo-labels. Second, we relabel the training data with the HMM and then fine-tune the original wav2vec 2.0 model using the HMM pseudo-labels with a CTC loss. Note that HMM models use phonemes as output, while wav2vec 2.0 use letter. Both are decoded using WFST decoders into words. diff --git a/examples/wav2vec/unsupervised/config/gan/w2vu.yaml b/examples/wav2vec/unsupervised/config/gan/w2vu.yaml index d168a11e19..74f1829d14 100644 --- a/examples/wav2vec/unsupervised/config/gan/w2vu.yaml +++ b/examples/wav2vec/unsupervised/config/gan/w2vu.yaml @@ -10,10 +10,15 @@ common: suppress_crashes: false checkpoint: + save_interval: 1000 + save_interval_updates: 1000 no_epoch_checkpoints: true best_checkpoint_metric: weighted_lm_ppl save_dir: . +distributed_training: + distributed_world_size: 1 + task: _name: unpaired_audio_text data: ??? @@ -30,6 +35,8 @@ dataset: batch_size: 160 skip_invalid_size_inputs_valid_test: true valid_subset: valid + validate_interval: 1000 + validate_interval_updates: 1000 criterion: _name: model diff --git a/examples/wav2vec/unsupervised/config/generate/viterbi.yaml b/examples/wav2vec/unsupervised/config/generate/viterbi.yaml index 0f850bb3e7..9c88beebcb 100644 --- a/examples/wav2vec/unsupervised/config/generate/viterbi.yaml +++ b/examples/wav2vec/unsupervised/config/generate/viterbi.yaml @@ -18,5 +18,4 @@ fairseq: batch_size: 1 w2l_decoder: VITERBI -lm_model: ??? post_process: silence diff --git a/examples/wav2vec/unsupervised/models/wav2vec_u.py b/examples/wav2vec/unsupervised/models/wav2vec_u.py index d3f195b94e..27792ebda8 100644 --- a/examples/wav2vec/unsupervised/models/wav2vec_u.py +++ b/examples/wav2vec/unsupervised/models/wav2vec_u.py @@ -76,7 +76,6 @@ class Wav2vec_UConfig(FairseqDataclass): hard_gumbel: bool = True temp: Tuple[float, float, float] = (2, 0.1, 0.99995) input_dim: int = 128 - wgan_loss: bool = False segmentation: SegmentationConfig = SegmentationConfig() @@ -397,12 +396,7 @@ def set_num_updates(self, num_updates): ) def discrim_step(self, num_updates): - if num_updates < self.zero_pretrain_updates: - return False - if self.dynamic_step_thresh <= 0 or self.last_acc is None: - return num_updates % 2 == 1 - else: - return self.last_acc < self.dynamic_step_thresh + return num_updates % 2 == 1 def get_groups_for_update(self, num_updates): return "discriminator" if self.discrim_step(num_updates) else "generator" @@ -413,7 +407,6 @@ def __init__(self, cfg: Wav2vec_UConfig, target_dict): self.cfg = cfg self.zero_index = target_dict.index("<SIL>") if "<SIL>" in target_dict else 0 self.smoothness_weight = cfg.smoothness_weight - self.wgan_loss = cfg.wgan_loss output_size = len(target_dict) self.pad = target_dict.pad() @@ -432,7 +425,7 @@ def __init__(self, cfg: Wav2vec_UConfig, target_dict): self.blank_index = target_dict.index("<SIL>") if cfg.blank_is_sil else 0 assert self.blank_index != target_dict.unk() - self.discriminator = self.Discriminator(output_size, cfg) + self.discriminator = Discriminator(output_size, cfg) for p in self.discriminator.parameters(): p.param_group = "discriminator" @@ -441,9 +434,7 @@ def __init__(self, cfg: Wav2vec_UConfig, target_dict): self.segmenter = SEGMENT_FACTORY[cfg.segmentation.type](cfg.segmentation) - self.generator = self.Generator( - d, output_size, cfg, lambda x: self.normalize(x)[0] - ) + self.generator = Generator(d, output_size, cfg) for p in self.generator.parameters(): p.param_group = "generator" @@ -589,20 +580,16 @@ def forward( code_pen = None if d_step: - if self.wgan_loss: - loss_dense = dense_y.sum() - loss_token = -1 * token_y.sum() - else: - loss_dense = F.binary_cross_entropy_with_logits( - dense_y, - dense_y.new_ones(dense_y.shape) - fake_smooth, - reduction="sum", - ) - loss_token = F.binary_cross_entropy_with_logits( - token_y, - token_y.new_zeros(token_y.shape) + real_smooth, - reduction="sum", - ) + loss_dense = F.binary_cross_entropy_with_logits( + dense_y, + dense_y.new_ones(dense_y.shape) - fake_smooth, + reduction="sum", + ) + loss_token = F.binary_cross_entropy_with_logits( + token_y, + token_y.new_zeros(token_y.shape) + real_smooth, + reduction="sum", + ) if self.training and self.gradient_penalty > 0: grad_pen = self.calc_gradient_penalty(token_x, dense_x) grad_pen = grad_pen.sum() * self.gradient_penalty @@ -611,23 +598,15 @@ def forward( else: grad_pen = None loss_token = None - if self.update_num >= self.zero_pretrain_updates: - if self.wgan_loss: - loss_dense = -1 * dense_y.sum() - else: - loss_dense = F.binary_cross_entropy_with_logits( - dense_y, - dense_y.new_zeros(dense_y.shape) + fake_smooth, - reduction="sum", - ) - num_vars = dense_x.size(-1) - if prob_perplexity is not None: - code_pen = (num_vars - prob_perplexity) / num_vars - if self.exponential_code_pen: - code_pen = (1 - 1 / code_pen ** 2).exp() - code_pen = code_pen * sample_size * self.code_penalty - else: - loss_dense = None + loss_dense = F.binary_cross_entropy_with_logits( + dense_y, + dense_y.new_zeros(dense_y.shape) + fake_smooth, + reduction="sum", + ) + num_vars = dense_x.size(-1) + if prob_perplexity is not None: + code_pen = (num_vars - prob_perplexity) / num_vars + code_pen = code_pen * sample_size * self.code_penalty if self.smoothness_weight > 0: smoothness_loss = F.mse_loss( diff --git a/examples/wav2vec/unsupervised/scripts/apply_pca.py b/examples/wav2vec/unsupervised/scripts/apply_pca.py index 0cddd20001..10ad6ce47c 100644 --- a/examples/wav2vec/unsupervised/scripts/apply_pca.py +++ b/examples/wav2vec/unsupervised/scripts/apply_pca.py @@ -50,8 +50,12 @@ def main(): copyfile(source_path + ".tsv", save_path + ".tsv") copyfile(data_poth + ".lengths", save_path + ".lengths") - copyfile(source_path + ".phn", save_path + ".phn") - copyfile(source_path + ".wrd", save_path + ".wrd") + + if osp.exists(source_path + ".phn"): + copyfile(source_path + ".phn", save_path + ".phn") + + if osp.exists(source_path + ".wrd"): + copyfile(source_path + ".wrd", save_path + ".wrd") if osp.exists(save_path + ".npy"): os.remove(save_path + ".npy") diff --git a/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py b/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py index 8c3138e55b..2e31c307bd 100644 --- a/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py +++ b/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py @@ -12,28 +12,32 @@ def main(): parser = argparse.ArgumentParser() - parser.add_argument("root_dirs", nargs="*") - parser.add_argument("--insert-silence", "-s", action="store_true") + parser.add_argument( + "--compact", + action="store_true", + help="if set, compacts phones", + ) args = parser.parse_args() - sil = "<s>" + + compact = args.compact wrd_to_phn = {} g2p = G2p() for line in sys.stdin: words = line.strip().split() phones = [] - if args.insert_silence: - phones.append(sil) for w in words: if w not in wrd_to_phn: wrd_to_phn[w] = g2p(w) + if compact: + wrd_to_phn[w] = [ + p[:-1] if p[-1].isnumeric() else p for p in wrd_to_phn[w] + ] phones.extend(wrd_to_phn[w]) - if args.insert_silence: - phones.append(sil) try: print(" ".join(phones)) except: - print(wrd_to_phn, w, phones, file=sys.stderr) + print(wrd_to_phn, words, phones, file=sys.stderr) raise diff --git a/examples/wav2vec/unsupervised/scripts/mean_pool.py b/examples/wav2vec/unsupervised/scripts/mean_pool.py index 1145e774eb..4eea048ef3 100644 --- a/examples/wav2vec/unsupervised/scripts/mean_pool.py +++ b/examples/wav2vec/unsupervised/scripts/mean_pool.py @@ -47,8 +47,17 @@ def main(): save_path = osp.join(args.save_dir, args.split) copyfile(source_path + ".tsv", save_path + ".tsv") - copyfile(source_path + ".phn", save_path + ".phn") - copyfile(source_path + ".wrd", save_path + ".wrd") + + if os.path.exists(source_path + ".phn"): + copyfile(source_path + ".phn", save_path + ".phn") + if os.path.exists(source_path + ".wrd"): + copyfile(source_path + ".wrd", save_path + ".wrd") + + if os.path.exists(osp.join(args.source, "dict.phn.txt")): + copyfile( + osp.join(args.source, "dict.phn.txt"), + osp.join(args.save_dir, "dict.phn.txt"), + ) if osp.exists(save_path + ".npy"): os.remove(save_path + ".npy") diff --git a/examples/wav2vec/unsupervised/scripts/merge_clusters.py b/examples/wav2vec/unsupervised/scripts/merge_clusters.py index 6502ed5718..2780f9d971 100644 --- a/examples/wav2vec/unsupervised/scripts/merge_clusters.py +++ b/examples/wav2vec/unsupervised/scripts/merge_clusters.py @@ -62,14 +62,16 @@ def main(): save_path = osp.join(args.save_dir, args.split) copyfile(source_path + ".tsv", save_path + ".tsv") - copyfile(source_path + ".phn", save_path + ".phn") - if os.path.exists(source_path + ".phnsc"): - copyfile(source_path + ".phnsc", save_path + ".phnsc") + + if os.path.exists(source_path + ".phn"): + copyfile(source_path + ".phn", save_path + ".phn") + if os.path.exists(osp.join(args.source, "dict.phn.txt")): copyfile( - osp.join(args.source, "dict.phnsc.txt"), - osp.join(args.save_dir, "dict.phnsc.txt"), + osp.join(args.source, "dict.phn.txt"), + osp.join(args.save_dir, "dict.phn.txt"), ) - copyfile(source_path + ".wrd", save_path + ".wrd") + if os.path.exists(source_path + ".wrd"): + copyfile(source_path + ".wrd", save_path + ".wrd") if osp.exists(save_path + ".npy"): os.remove(save_path + ".npy") diff --git a/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py b/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py index 1284747795..c2bd16efb5 100644 --- a/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py +++ b/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py @@ -6,6 +6,7 @@ import argparse import fasttext as ft +import os import regex import sys @@ -39,17 +40,31 @@ def main(): lg_label = f"__label__{lg}" thresh = args.lid_threshold - model = ft.load_model(args.fasttext_model) + if os.path.exists(args.fasttext_model): + model = ft.load_model(args.fasttext_model) + else: + print( + f"fasttext language id model {args.fasttext_model} not found. Proceeding without language filtering. " + f"To enable language filtering, please download the latest language id model " + f"from https://fasttext.cc/docs/en/language-identification.html", + file=sys.stderr, + ) + model = None + for line in sys.stdin: line = line.strip() line = filter_r.sub(" ", line) line = " ".join(line.split()) - lid, prob = model.predict(line, k=100) - try: - target_idx = lid.index(lg_label) - except ValueError: - continue - if target_idx == 0 or prob[target_idx] >= thresh: + + if model is not None: + lid, prob = model.predict(line, k=100) + try: + target_idx = lid.index(lg_label) + except ValueError: + continue + if target_idx == 0 or prob[target_idx] >= thresh: + print(line) + else: print(line) diff --git a/examples/wav2vec/unsupervised/scripts/prepare_audio.sh b/examples/wav2vec/unsupervised/scripts/prepare_audio.sh index 893c9fda1a..013f7a9b05 100644 --- a/examples/wav2vec/unsupervised/scripts/prepare_audio.sh +++ b/examples/wav2vec/unsupervised/scripts/prepare_audio.sh @@ -17,10 +17,31 @@ fi echo "using $dim dim for PCA" +if [ -z "$5" ] + then + layer=14 + else + layer=$5 +fi + +echo "extracting from layer $layer" + train_split=train valid_split=valid test_split=test +all_splits=($train_split) + +if [[ -f "$source_dir/valid.tsv" ]]; then + all_splits+=('valid') +fi + +if [[ -f "$source_dir/test.tsv" ]]; then + all_splits+=('test') +fi + +echo "processing splits: $all_splits" + mkdir -p $tgt_dir cp $source_dir/*.tsv $tgt_dir @@ -31,27 +52,27 @@ cp $source_dir/dict* $tgt_dir setopt shwordsplit -for split in $train_split $valid_split $test_split; do - python wav2vec_extract_features.py $source_dir --split $split \ - --save-dir $tgt_dir --checkpoint $model +for split in $all_splits; do + python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py $source_dir --split $split \ + --save-dir $tgt_dir --checkpoint $model --layer $layer done -python wav2vec_cluster_faiss.py $tgt_dir/${train_split}.tsv \ +python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_cluster_faiss.py $tgt_dir/${train_split}.tsv \ --checkpoint $model --save-dir $tgt_dir -f "CLUS128" --sample-pct 1.0 -for split in $train_split $valid_split $test_split; do - python wav2vec_apply_cluster_faiss.py $tgt_dir \ +for split in $all_splits; do + python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py $tgt_dir \ --checkpoint $model --path $tgt_dir/CLUS128 --split $split done -python pca.py $tgt_dir/${train_split}.npy --output $tgt_dir/pca --dim $dim +python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/pca.py $tgt_dir/${train_split}.npy --output $tgt_dir/pca --dim $dim -for split in $train_split $valid_split $test_split; do - python apply_pca.py $tgt_dir --split $split --save-dir $tgt_dir/precompute_pca$dim --pca-path $tgt_dir/pca/${dim}_pca --batch-size 1048000 +for split in $all_splits; do + python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/apply_pca.py $tgt_dir --split $split --save-dir $tgt_dir/precompute_pca$dim --pca-path $tgt_dir/pca/${dim}_pca --batch-size 1048000 - python merge_clusters.py $tgt_dir/precompute_pca$dim --cluster-dir $tgt_dir/CLUS128 \ + python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/merge_clusters.py $tgt_dir/precompute_pca$dim --cluster-dir $tgt_dir/CLUS128 \ --split $split --save-dir $tgt_dir/precompute_pca${dim}_cls128_mean --pooling mean - python mean_pool.py $tgt_dir/precompute_pca${dim}_cls128_mean \ + python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/mean_pool.py $tgt_dir/precompute_pca${dim}_cls128_mean \ --save-dir $tgt_dir/precompute_pca${dim}_cls128_mean_pooled --split $split -done \ No newline at end of file +done diff --git a/examples/wav2vec/unsupervised/scripts/prepare_text.sh b/examples/wav2vec/unsupervised/scripts/prepare_text.sh index e9090a3d80..1caf13cb6a 100644 --- a/examples/wav2vec/unsupervised/scripts/prepare_text.sh +++ b/examples/wav2vec/unsupervised/scripts/prepare_text.sh @@ -7,6 +7,13 @@ lg=$1 text_path=$2 target_dir=$3 +min_phones=$4 +phonemizer=$5 +lid_path=$6 + +if [ -z "$lid_path" ]; then + lid_path="lid.187.bin" +fi ph_lg=${lg:l} if test "$lg" = 'fr'; then @@ -17,40 +24,59 @@ elif test "$lg" = 'pt'; then ph_lg='pt-br' fi +ESPEAK_PATH='' +if test "$phonemizer" = 'espeak'; then + ESPEAK_PATH=$(which espeak) +elif test "$phonemizer" = 'espeak-ng'; then + ESPEAK_PATH=$(which espeak-ng) +elif test "$phonemizer" = 'G2P'; then + ESPEAK_PATH='' +else + echo "Unknown phonemizer $phonemizer. Valid options are espeak, espean-ng and G2P" + exit 1 +fi + echo $lg echo $ph_lg echo $text_path echo $target_dir +echo "min phone seen threshold is $min_phones" mkdir -p $target_dir -python normalize_and_filter_text.py --lang $lg < $text_path | grep -v '\-\-\-' >! $target_dir/lm.upper.lid.txt +python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/normalize_and_filter_text.py --lang $lg --fasttext-model $lid_path < $text_path | grep -v '\-\-\-' >! $target_dir/lm.upper.lid.txt python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/lm.upper.lid.txt --only-source --destdir $target_dir --thresholdsrc 2 --padding-factor 1 --dict-only cut -f1 -d' ' $target_dir/dict.txt | grep -v -x '[[:punct:]]*' | grep -Pv '\d\d\d\d\d+' >! $target_dir/words.txt -one=$(echo "1" | PHONEMIZER_ESPEAK_PATH=$(which espeak) phonemize -p ' ' -w '' -l $ph_lg --language-switch remove-flags) -sed 's/$/ 1/' $target_dir/words.txt | PHONEMIZER_ESPEAK_PATH=$(which espeak) phonemize -o $target_dir/phones.txt -p ' ' -w '' -l $ph_lg -j 70 --language-switch remove-flags -echo "one is ${one}" +if [ -z "$ESPEAK_PATH" ]; then + python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/g2p_wrd_to_phn.py --compact < $target_dir/words.txt > $target_dir/phones.txt +else + # echoing 1 into corpus will prevent the mismatch lines between lexicon and phones in case the phonemizer fails + one=$(echo "1" | PHONEMIZER_ESPEAK_PATH=$ESPEAK_PATH phonemize -p ' ' -w '' -l $ph_lg --language-switch remove-flags) + sed 's/$/ 1/' $target_dir/words.txt | PHONEMIZER_ESPEAK_PATH=$ESPEAK_PATH phonemize -o $target_dir/phones.txt -p ' ' -w '' -l $ph_lg -j 70 --language-switch remove-flags + echo "one is ${one}" + sed -i "s/${one}$//" $target_dir/phones.txt +fi -sed -i "s/${one}$//" $target_dir/phones.txt paste $target_dir/words.txt $target_dir/phones.txt >! $target_dir/lexicon.lst -python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones.txt --only-source --destdir $target_dir/phones --thresholdsrc 1000 --padding-factor 1 --dict-only +python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones.txt --only-source --destdir $target_dir/phones --thresholdsrc $min_phones --padding-factor 1 --dict-only -python filter_lexicon.py -d $target_dir/phones/dict.txt < $target_dir/lexicon.lst >! $target_dir/lexicon_filtered.lst -python phonemize_with_sil.py -s 0.25 --surround --lexicon $target_dir/lexicon_filtered.lst < $target_dir/lm.upper.lid.txt >! $target_dir/phones/lm.phones.filtered.txt +python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/filter_lexicon.py -d $target_dir/phones/dict.txt < $target_dir/lexicon.lst >! $target_dir/lexicon_filtered.lst +python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py -s 0.25 --surround --lexicon $target_dir/lexicon_filtered.lst < $target_dir/lm.upper.lid.txt >! $target_dir/phones/lm.phones.filtered.txt cp $target_dir/phones/dict.txt $target_dir/phones/dict.phn.txt echo "<SIL> 0" >> $target_dir/phones/dict.phn.txt python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones/lm.phones.filtered.txt --workers 70 --only-source --destdir $target_dir/phones --srcdict $target_dir/phones/dict.phn.txt -lmplz -o 4 < $target_dir/lm.upper.lid.txt --discount_fallback --prune 0 0 0 3 >! $target_dir/kenlm.wrd.o40003.arpa -build_binary $target_dir/kenlm.wrd.o40003.arpa $target_dir/kenlm.wrd.o40003.bin -lg=$lg python examples/speech_recognition/kaldi/kaldi_initializer.py fst_dir=$target_dir/fst/phn_to_words_sil lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones "blank_symbol='<SIL>'" -lg=$lg python examples/speech_recognition/kaldi/kaldi_initializer.py fst_dir=$target_dir/fst/phn_to_words lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones +$KENLM_ROOT/lmplz -o 4 < $target_dir/lm.upper.lid.txt --discount_fallback --prune 0 0 0 3 >! $target_dir/kenlm.wrd.o40003.arpa +$KENLM_ROOT/build_binary $target_dir/kenlm.wrd.o40003.arpa $target_dir/kenlm.wrd.o40003.bin + +lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$target_dir/fst/phn_to_words_sil lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones in_labels=phn "blank_symbol='<SIL>'" +lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$target_dir/fst/phn_to_words lm_arpa=$target_dir/kenlm.wrd.o40003.arpa wav2letter_lexicon=$target_dir/lexicon_filtered.lst data_dir=$target_dir/phones in_labels=phn -lmplz -o 4 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.04.arpa -build_binary $target_dir/phones/lm.phones.filtered.04.arpa $target_dir/phones/lm.phones.filtered.04.bin -lmplz -o 6 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.06.arpa -build_binary $target_dir/phones/lm.phones.filtered.06.arpa $target_dir/phones/lm.phones.filtered.06.bin +$KENLM_ROOT/lmplz -o 4 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.04.arpa +$KENLM_ROOT/build_binary $target_dir/phones/lm.phones.filtered.04.arpa $target_dir/phones/lm.phones.filtered.04.bin +$KENLM_ROOT/lmplz -o 6 < $target_dir/phones/lm.phones.filtered.txt --discount_fallback >! $target_dir/phones/lm.phones.filtered.06.arpa +$KENLM_ROOT/build_binary $target_dir/phones/lm.phones.filtered.06.arpa $target_dir/phones/lm.phones.filtered.06.bin -lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py fst_dir=$target_dir/fst/phn_to_phn_sil lm_arpa=$target_dir/phones/lm.phones.filtered.06.arpa data_dir=$target_dir/phones "blank_symbol='<SIL>'" +lg=$lg python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$target_dir/fst/phn_to_phn_sil lm_arpa=$target_dir/phones/lm.phones.filtered.06.arpa data_dir=$target_dir/phones in_labels=phn "blank_symbol='<SIL>'" diff --git a/examples/wav2vec/unsupervised/scripts/remove_silence.py b/examples/wav2vec/unsupervised/scripts/remove_silence.py index 417b703de8..fac88b9897 100644 --- a/examples/wav2vec/unsupervised/scripts/remove_silence.py +++ b/examples/wav2vec/unsupervised/scripts/remove_silence.py @@ -58,7 +58,6 @@ if not os.path.isdir("/".join(outpath.split("/")[:-1])): os.makedirs("/".join(outpath.split("/")[:-1])) if not os.path.exists(outpath): - print(outpath) torchaudio.save(outpath, data_filtered, sample_rate=16000) else: print(outpath, "exists!") diff --git a/examples/wav2vec/unsupervised/scripts/vads.py b/examples/wav2vec/unsupervised/scripts/vads.py index 1acd95369c..2398da97d8 100644 --- a/examples/wav2vec/unsupervised/scripts/vads.py +++ b/examples/wav2vec/unsupervised/scripts/vads.py @@ -4,10 +4,9 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import argparse import sys -sys.path.append("/path/to/rVADfast_py_2.0") -import speechproc from copy import deepcopy from scipy.signal import lfilter @@ -17,7 +16,19 @@ import os.path as osp -def rvad(path): +def get_parser(): + parser = argparse.ArgumentParser(description="compute vad segments") + parser.add_argument( + "--rvad-home", + "-r", + help="path to rvad home (see https://github.com/zhenghuatan/rVADfast)", + required=True, + ) + + return parser + + +def rvad(speechproc, path): winlen, ovrlen, pre_coef, nfilter, nftt = 0.025, 0.01, 0.97, 20, 512 ftThres = 0.5 vadThres = 0.4 @@ -56,12 +67,18 @@ def rvad(path): def main(): + parser = get_parser() + args = parser.parse_args() + + sys.path.append(args.rvad_home) + import speechproc + stride = 160 lines = sys.stdin.readlines() root = lines[0].rstrip() for fpath in tqdm(lines[1:]): path = osp.join(root, fpath.split()[0]) - vads, wav = rvad(path) + vads, wav = rvad(speechproc, path) start = None vad_segs = [] diff --git a/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py b/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py index 25bc4e41ac..a5dd7ae6c1 100644 --- a/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py +++ b/examples/wav2vec/unsupervised/scripts/wav2vec_apply_cluster_faiss.py @@ -5,6 +5,7 @@ # LICENSE file in the root directory of this source tree. import argparse +import os import os.path as osp import numpy as np import tqdm @@ -33,13 +34,21 @@ def get_parser(): def get_iterator(args): - with open(osp.join(args.data, f"{args.split}.tsv"), "r") as fp, open( - osp.join(args.data, f"{args.split}.{args.labels}"), "r" - ) as lp: + label_path = osp.join(args.data, f"{args.split}.{args.labels}") + if osp.exists(label_path): + lp = open(label_path, "r") + else: + lp = None + + with open(osp.join(args.data, f"{args.split}.tsv"), "r") as fp: lines = fp.read().split("\n") root = lines.pop(0).strip() files = [line.rstrip() for line in lines if len(line) > 0] - lbls = [line.rstrip() for line in lp] + + if lp is not None: + lbls = [line.rstrip() for line in lp] + else: + lbls = [None] * len(files) num = len(files) reader = Wav2VecFeatureReader(args.checkpoint, args.layer) @@ -87,10 +96,13 @@ def main(): generator, num, root = get_iterator(args) iterator = generator() + had_labels = False + label_path = osp.join(args.path, f"{args.split}.{args.labels}") + with torch.no_grad(): with open(osp.join(args.path, f"{args.split}.src"), "w") as fp, open( osp.join(args.path, f"{args.split}.tsv"), "w" - ) as pp, open(osp.join(args.path, f"{args.split}.{args.labels}"), "w") as lp: + ) as pp, open(label_path, "w") as lp: print(root, file=pp) for f, fname, lbl in tqdm.tqdm(iterator, total=num): if faiss_spec.pca: @@ -104,7 +116,12 @@ def main(): print(" ".join(str(x.item()) for x in z), file=fp) print(fname, file=pp) - print(lbl, file=lp) + + if lbl is not None: + print(lbl, file=lp) + had_labels = True + if not had_labels: + os.remove(label_path) if __name__ == "__main__": diff --git a/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py b/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py index 023dd1aaa5..b07e274d20 100644 --- a/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py +++ b/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py @@ -27,13 +27,14 @@ def get_parser(): parser.add_argument('--split', help='which split to read', required=True) parser.add_argument('--save-dir', help='where to save the output', required=True) parser.add_argument('--checkpoint', type=str, help='checkpoint for wav2vec ctc model', required=True) + parser.add_argument('--layer', type=int, default=14, help='which layer to use') # fmt: on return parser class Wav2VecFeatureReader(object): - def __init__(self, cp_file): + def __init__(self, cp_file, layer): model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task( [cp_file] ) @@ -42,6 +43,7 @@ def __init__(self, cp_file): model.cuda() self.model = model self.task = task + self.layer = layer def read_audio(self, fname): """Load an audio file and return PCM along with the sample rate""" @@ -60,7 +62,7 @@ def get_feats(self, loc): source = F.layer_norm(source, source.shape) source = source.view(1, -1) - m_res = self.model(source=source, mask=False, features_only=True, layer=14) + m_res = self.model(source=source, mask=False, features_only=True, layer=self.layer) return m_res["x"].squeeze(0).cpu() @@ -71,7 +73,7 @@ def get_iterator(args): files = [osp.join(root, line.split("\t")[0]) for line in lines if len(line) > 0] num = len(files) - reader = Wav2VecFeatureReader(args.checkpoint) + reader = Wav2VecFeatureReader(args.checkpoint, args.layer) def iterate(): for fname in files: diff --git a/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py index 0b770a1509..5f292528f8 100644 --- a/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py +++ b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py @@ -83,7 +83,7 @@ class UnpairedAudioTextConfig(FairseqDataclass): decoding_config: DecodingConfig = DecodingConfig() -@register_task("gan_audio_pretraining_feats", dataclass=UnpairedAudioTextConfig) +@register_task("unpaired_audio_text", dataclass=UnpairedAudioTextConfig) class UnpairedAudioText(FairseqTask): """ """ @@ -194,12 +194,13 @@ def valid_step(self, sample, model, criterion): for i, (x, t, id) in enumerate( zip( z, - sample["target"], + sample["target"] if "target" in sample else [None] * len(z), sample["id"], ) ): - t = t[(t >= self.target_dictionary.nspecial)] + if t is not None: + t = t[(t >= self.target_dictionary.nspecial)] x = x[ (x >= self.target_dictionary.nspecial) & (x < (self.num_symbols + self.target_dictionary.nspecial)) @@ -215,28 +216,37 @@ def valid_step(self, sample, model, criterion): pred_units_arr = pred_units_arr[pred_units_arr != 0] if id == 0: - logger.info(f"REF: {self.target_dictionary.string(t)}") + if t is not None: + logger.info(f"REF: {self.target_dictionary.string(t)}") logger.info(f"HYP: {self.target_dictionary.string(pred_units_arr)}") if self.kenlm is not None: - ref_lm_s = self.compute_lm_score(self.target_dictionary.string(t)) + if t is not None: + ref_lm_s = self.compute_lm_score( + self.target_dictionary.string(t) + ) + logger.info( + f"LM [REF]: {ref_lm_s}, {math.pow(10, -ref_lm_s / (len(t) + 1))}" + ) + hyp_lm_s = self.compute_lm_score( self.target_dictionary.string(pred_units_arr) ) logger.info( - f"LM [REF]: {ref_lm_s}, {math.pow(10, ref_lm_s / (len(t) + 1))}" - ) - logger.info( - f"LM [HYP]: {hyp_lm_s}, {math.pow(10, hyp_lm_s / (len(pred_units_arr) + 1))}" + f"LM [HYP]: {hyp_lm_s}, {math.pow(10, -hyp_lm_s / (len(pred_units_arr) + 1))}" ) pred_units_arr = pred_units_arr.tolist() - t = t.tolist() - c_err += editdistance.eval(pred_units_arr, t) - c_len += len(t) pred_c_len += len(pred_units_arr) + if t is not None: + t = t.tolist() + c_err += editdistance.eval(pred_units_arr, t) + c_len += len(t) + else: + c_len = pred_c_len + if self.kenlm is not None: pred_str = self.target_dictionary.string(pred_units_arr) lm_score = self.compute_lm_score(pred_str) diff --git a/examples/wav2vec/unsupervised/w2vu_generate.py b/examples/wav2vec/unsupervised/w2vu_generate.py index a1bc0ec706..b1e126665f 100644 --- a/examples/wav2vec/unsupervised/w2vu_generate.py +++ b/examples/wav2vec/unsupervised/w2vu_generate.py @@ -681,6 +681,9 @@ def hydra_main(cfg): ) OmegaConf.set_struct(cfg, True) logger.info(cfg) + + utils.import_user_module(cfg.fairseq.common) + _, score = main(cfg) if cfg.is_ax: diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 135530d5c0..61425c8ef5 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -195,25 +195,31 @@ def register_model_arch_fn(fn): return register_model_arch_fn +def import_models(models_dir, namespace): + for file in os.listdir(models_dir): + path = os.path.join(models_dir, file) + if ( + not file.startswith("_") + and not file.startswith(".") + and (file.endswith(".py") or os.path.isdir(path)) + ): + model_name = file[: file.find(".py")] if file.endswith(".py") else file + importlib.import_module(namespace + "." + model_name) + + # extra `model_parser` for sphinx + if model_name in MODEL_REGISTRY: + parser = argparse.ArgumentParser(add_help=False) + group_archs = parser.add_argument_group("Named architectures") + group_archs.add_argument( + "--arch", choices=ARCH_MODEL_INV_REGISTRY[model_name] + ) + group_args = parser.add_argument_group( + "Additional command-line arguments" + ) + MODEL_REGISTRY[model_name].add_args(group_args) + globals()[model_name + "_parser"] = parser + + # automatically import any Python files in the models/ directory models_dir = os.path.dirname(__file__) -for file in os.listdir(models_dir): - path = os.path.join(models_dir, file) - if ( - not file.startswith("_") - and not file.startswith(".") - and (file.endswith(".py") or os.path.isdir(path)) - ): - model_name = file[: file.find(".py")] if file.endswith(".py") else file - module = importlib.import_module("fairseq.models." + model_name) - - # extra `model_parser` for sphinx - if model_name in MODEL_REGISTRY: - parser = argparse.ArgumentParser(add_help=False) - group_archs = parser.add_argument_group("Named architectures") - group_archs.add_argument( - "--arch", choices=ARCH_MODEL_INV_REGISTRY[model_name] - ) - group_args = parser.add_argument_group("Additional command-line arguments") - MODEL_REGISTRY[model_name].add_args(group_args) - globals()[model_name + "_parser"] = parser +import_models(models_dir, "fairseq.models") diff --git a/fairseq/models/wav2vec/wav2vec.py b/fairseq/models/wav2vec/wav2vec.py index 83b6461129..af6604da10 100644 --- a/fairseq/models/wav2vec/wav2vec.py +++ b/fairseq/models/wav2vec/wav2vec.py @@ -50,7 +50,7 @@ class Wav2VecConfig(FairseqDataclass): default=0, metadata={"help": "num of cross sampled negatives"} ) num_negatives: int = field( - default=10, metadata={"help": "num of cross sampled negatives"} + default=10, metadata={"help": "num of sampled negatives"} ) conv_feature_layers: str = field( default="[(512, 10, 5), (512, 8, 4), (512, 4, 2), (512, 4, 2), (512, 4, 2), (512, 1, 1), (512, 1, 1), (512, 1, 1)]", diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 95b4a9647f..79dde74057 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -39,7 +39,9 @@ def setup_task(cfg: FairseqDataclass, **kwargs): cfg = merge_with_parent(dc(), cfg) task = TASK_REGISTRY[task_name] - assert task is not None, f"Could not infer task type from {cfg}. Available tasks: {TASK_REGISTRY.keys()}" + assert ( + task is not None + ), f"Could not infer task type from {cfg}. Available tasks: {TASK_REGISTRY.keys()}" return task.setup_task(cfg, **kwargs) @@ -103,26 +105,32 @@ def get_task(name): return TASK_REGISTRY[name] +def import_tasks(tasks_dir, namespace): + for file in os.listdir(tasks_dir): + path = os.path.join(tasks_dir, file) + if ( + not file.startswith("_") + and not file.startswith(".") + and (file.endswith(".py") or os.path.isdir(path)) + ): + task_name = file[: file.find(".py")] if file.endswith(".py") else file + importlib.import_module(namespace + "." + task_name) + + # expose `task_parser` for sphinx + if task_name in TASK_REGISTRY: + parser = argparse.ArgumentParser(add_help=False) + group_task = parser.add_argument_group("Task name") + # fmt: off + group_task.add_argument('--task', metavar=task_name, + help='Enable this task with: ``--task=' + task_name + '``') + # fmt: on + group_args = parser.add_argument_group( + "Additional command-line arguments" + ) + TASK_REGISTRY[task_name].add_args(group_args) + globals()[task_name + "_parser"] = parser + + # automatically import any Python files in the tasks/ directory tasks_dir = os.path.dirname(__file__) -for file in os.listdir(tasks_dir): - path = os.path.join(tasks_dir, file) - if ( - not file.startswith("_") - and not file.startswith(".") - and (file.endswith(".py") or os.path.isdir(path)) - ): - task_name = file[: file.find(".py")] if file.endswith(".py") else file - module = importlib.import_module("fairseq.tasks." + task_name) - - # expose `task_parser` for sphinx - if task_name in TASK_REGISTRY: - parser = argparse.ArgumentParser(add_help=False) - group_task = parser.add_argument_group("Task name") - # fmt: off - group_task.add_argument('--task', metavar=task_name, - help='Enable this task with: ``--task=' + task_name + '``') - # fmt: on - group_args = parser.add_argument_group("Additional command-line arguments") - TASK_REGISTRY[task_name].add_args(group_args) - globals()[task_name + "_parser"] = parser +import_tasks(tasks_dir, "fairseq.tasks") diff --git a/fairseq/utils.py b/fairseq/utils.py index bf5727edfd..4fe95b9e8b 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -10,7 +10,6 @@ import logging import os import sys -import tempfile import warnings from itertools import accumulate from typing import Callable, Dict, List, Optional @@ -59,9 +58,7 @@ def __call__(self, parser, namespace, values, option_string=None): def split_paths(paths: str, separator=os.pathsep) -> List[str]: return ( - paths.split(separator) - if "://" not in paths - else paths.split(MANIFOLD_PATH_SEP) + paths.split(separator) if "://" not in paths else paths.split(MANIFOLD_PATH_SEP) ) @@ -483,6 +480,18 @@ def import_user_module(args): if module_name not in sys.modules: sys.path.insert(0, module_parent) importlib.import_module(module_name) + + tasks_path = os.path.join(module_path, "tasks") + if os.path.exists(tasks_path): + from fairseq.tasks import import_tasks + + import_tasks(tasks_path, f"{module_name}.tasks") + + models_path = os.path.join(module_path, "models") + if os.path.exists(models_path): + from fairseq.models import import_models + + import_models(models_path, f"{module_name}.models") else: raise ImportError( "Failed to import --user-dir={} because the corresponding module name " From c36294ea4fd35eac757f417de9668b32c57d4b3d Mon Sep 17 00:00:00 2001 From: Valentin Andrei <vandrei@fb.com> Date: Fri, 11 Jun 2021 17:59:24 -0700 Subject: [PATCH 366/774] Do FP16/BF16 conversions on the host to transfer less through PCIe Summary: If we do the FP16/BF32 conversion on the host, we do it at DRAM speed but transfer 2X smaller buffer to the GPU through PCIe. PCIe bandwidth is an order of magnitude lower so we actually gain about 50% of execution time compared to when performing the quantization on the GPU. Also, by transfering an already FP16 buffer, we save memory capacity. Reviewed By: zhengwy888 Differential Revision: D24146486 fbshipit-source-id: b897e7a32835aa1b571b0fae5f3d72a131ad16a1 --- fairseq/dataclass/configs.py | 7 ++++++ fairseq/trainer.py | 49 ++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 70d7476d31..f2dc5b4fd6 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -148,6 +148,13 @@ class CommonConfig(FairseqDataclass): "help": "pct of updates that can overflow before decreasing the loss scale" }, ) + on_cpu_convert_precision: bool = field( + default=False, + metadata={ + "help": "if set, the floating point conversion to fp16/bf16 runs on CPU. " + "This reduces bus transfer time and GPU memory usage." + } + ) min_loss_scale: float = field( default=1e-4, metadata={"help": "minimum FP16/AMP loss scale, after which training is stopped"}, diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 64c6fabed6..a55eb0ba3e 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -1124,6 +1124,25 @@ def _local_cumulative_training_time(self): """Aggregate training time in seconds.""" return time.time() - self._start_time + self._previous_training_time + def _fp_convert_sample(self, sample): + def apply_half(t): + if t.dtype is torch.float32: + return t.to(dtype=torch.half) + return t + + def apply_bfloat16(t): + if t.dtype is torch.float32: + return t.to(dtype=torch.bfloat16) + return t + + if self.cfg.common.fp16: + sample = utils.apply_to_sample(apply_half, sample) + + if self.cfg.common.bf16: + sample = utils.apply_to_sample(apply_bfloat16, sample) + + return sample + def _prepare_sample(self, sample, is_dummy=False): if sample == "DUMMY": raise Exception( @@ -1139,33 +1158,25 @@ def _prepare_sample(self, sample, is_dummy=False): sample, _ = self._prepare_sample(self._dummy_batch, is_dummy=True) return sample, True + # Given that PCIe/NVLink bandwidth is significantly smaller than DRAM bandwidth + # it makes sense to do the format conversion on the CPU and then transfer + # a smaller buffer to the device. This also saves GPU memory capacity. + + if self.cfg.common.on_cpu_convert_precision: + sample = self._fp_convert_sample(sample) + if self.cuda: if self.pipeline_model_parallel: - if "target" in sample: - sample["target"] = utils.move_to_cuda( - sample["target"], device=self.last_device - ) + if 'target' in sample: + sample['target'] = utils.move_to_cuda(sample['target'], device=self.last_device) else: sample = utils.move_to_cuda(sample) elif self.tpu and is_dummy: # the dummy batch may not be on the appropriate device sample = utils.move_to_cuda(sample, device=self.device) - def apply_half(t): - if t.dtype is torch.float32: - return t.half() - return t - - def apply_bfloat16(t): - if t.dtype is torch.float32: - return t.to(dtype=torch.bfloat16) - return t - - if self.cfg.common.fp16: - sample = utils.apply_to_sample(apply_half, sample) - - if self.cfg.common.bf16: - sample = utils.apply_to_sample(apply_bfloat16, sample) + if not self.cfg.common.on_cpu_convert_precision: + sample = self._fp_convert_sample(sample) if self._dummy_batch == "DUMMY": self._dummy_batch = sample From 176b2e4e766c94e64f945b9c1323e612d8887d83 Mon Sep 17 00:00:00 2001 From: Henry Hu <henryhu6@fb.com> Date: Mon, 14 Jun 2021 09:09:25 -0700 Subject: [PATCH 367/774] Fix warning for empty tensor without type Summary: Fairseq create an empty tensor without type. It will create warning for torchscript model. Warning: Creating a tensor from an empty intlist will create a tensor of default floating point type (currently Float) in python but a tensor of type int in torchscript. This diff adds definition of the type. Reviewed By: myleott Differential Revision: D29081170 fbshipit-source-id: 5c32aae65c9998b245eac43bfedc820bea509338 --- fairseq/ngram_repeat_block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/ngram_repeat_block.py b/fairseq/ngram_repeat_block.py index ed2d744635..8541251494 100644 --- a/fairseq/ngram_repeat_block.py +++ b/fairseq/ngram_repeat_block.py @@ -123,7 +123,7 @@ def _no_repeat_ngram(self, tokens, lprobs, bsz: int, beam_size: int, step: int): ] for bbsz_idx in range(bsz * beam_size): lprobs[bbsz_idx][ - torch.tensor(banned_tokens[bbsz_idx]).long() + torch.tensor(banned_tokens[bbsz_idx], dtype=torch.int64) ] = torch.tensor(-math.inf).to(lprobs) return lprobs From cd5775f30184baa414a354d9f06b747344a8ba74 Mon Sep 17 00:00:00 2001 From: msbaines <35972327+msbaines@users.noreply.github.com> Date: Mon, 14 Jun 2021 16:37:53 -0700 Subject: [PATCH 368/774] avoid freezing batches unnecessarily (#3610) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: In EpochBatchIterator, first_batch() freezes batches in order to generate the dummy_batch. We then freeze batches again in the call to next_epoch_itr(). We can avoid the second freeze and reduce time to first iteration by about 50% in cases where we have a callable batch_sampler. Before: ![Screen Shot 2021-06-10 at 5 08 22 PM](https://user-images.githubusercontent.com/35972327/121613200-d2366600-ca10-11eb-9d1d-bafc2403766a.png) After: ![Screen Shot 2021-06-10 at 5 07 54 PM](https://user-images.githubusercontent.com/35972327/121613224-dfebeb80-ca10-11eb-9d5a-07be9440db77.png) # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3610 Reviewed By: myleott Differential Revision: D29105845 Pulled By: msbaines fbshipit-source-id: 9795d46d70a99ad1218ce225092cc22ee3192bbc --- fairseq/data/iterators.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 8321a49b54..86f6d05533 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -356,6 +356,7 @@ def next_epoch_itr( """ if self.disable_shuffling: shuffle = False + prev_epoch = self.epoch self.epoch = self.next_epoch_idx if set_dataset_epoch and hasattr(self.dataset, "set_epoch"): self.dataset.set_epoch(self.epoch) @@ -363,7 +364,7 @@ def next_epoch_itr( self._cur_epoch_itr = self._next_epoch_itr self._next_epoch_itr = None else: - if callable(self.batch_sampler): + if callable(self.batch_sampler) and prev_epoch != self.epoch: # reset _frozen_batches to refresh the next epoch self._frozen_batches = None self._cur_epoch_itr = self._get_iterator_for_epoch( From 8320f6708ff27537f51a8d3a4c4a0bfbceea71d9 Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushall@fb.com> Date: Tue, 15 Jun 2021 10:49:33 -0700 Subject: [PATCH 369/774] Instructions for loading HuBERT model (#1966) Summary: ## What does this PR do? Fixes the HuBERT README to contain instructions to load pretrained checkpoints. ## PR review Tested in a fresh environment that doesn't have access to FAIR's dev env. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1966 Reviewed By: wnhsu Differential Revision: D29117906 Pulled By: hikushalhere fbshipit-source-id: 89b0407ecf8cdbeddcab80f55e6b2f1fed24c967 --- examples/hubert/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/hubert/README.md b/examples/hubert/README.md index c0b1125cb5..3254b754f0 100644 --- a/examples/hubert/README.md +++ b/examples/hubert/README.md @@ -9,6 +9,13 @@ HuBERT Extra Large (~1B params) | [Libri-Light](https://github.com/facebookresea HuBERT Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k_finetune_ls960.pt) HuBERT Extra Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k_finetune_ls960.pt) +## Load a pretrained model +``` +ckpt_path = "/path/to/the/checkpoint.pt" +models, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path], strict=False) +model = models[0] +``` +** We will follow-up with a patch such that you wouldn't need to pass `strict=False` for loading the checkpoint in future. ## Train a new model From 128b4fc3789338d782c1ae4a27c5f0d6fa6dfed0 Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushall@fb.com> Date: Tue, 15 Jun 2021 14:09:01 -0700 Subject: [PATCH 370/774] Check attributes in trainer and checkpoint loading before using them (#1970) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## What does this PR do? Fixes None exception when some attributes in don't exist in cfg. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1970 Reviewed By: alexeib Differential Revision: D29140036 Pulled By: hikushalhere fbshipit-source-id: 7d941bcae6bb000c281a43ca2cd0876a49912ab9 --- fairseq/checkpoint_utils.py | 2 ++ fairseq/dataclass/configs.py | 6 ++++++ fairseq/trainer.py | 5 ++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 80c797bcdd..627f14160d 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -647,6 +647,8 @@ def _upgrade_state_dict(state): and ( hasattr(cfg.model.w2v_args, "task") or "task" in cfg.model.w2v_args ) + and hasattr(cfg.model.w2v_args.task, "eval_wer_config") + and cfg.model.w2v_args.task.eval_wer_config is not None and isinstance( cfg.model.w2v_args.task.eval_wer_config.print_alignment, bool ) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index f2dc5b4fd6..b0146fa4c7 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -229,6 +229,12 @@ class DistributedTrainingConfig(FairseqDataclass): "help": "total number of GPUs across all nodes (default: all visible GPUs)" }, ) + distributed_num_procs: Optional[int] = field( + default=max(1, torch.cuda.device_count()), + metadata={ + "help": "total number of processes to fork (default: all visible GPUs)" + }, + ) distributed_rank: Optional[int] = field( default=0, metadata={"help": "rank of the current worker"} ) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index a55eb0ba3e..1deb14326f 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -73,7 +73,10 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): "option (it's already built in)" ) else: - if self.cfg.distributed_training.cpu_offload: + if ( + hasattr(self.cfg.distributed_training, "cpu_offload") + and self.cfg.distributed_training.cpu_offload + ): raise ValueError("--cpu-offload requires --ddp-backend=fully_sharded") # copy model and criterion to current device/dtype From afc77bdf4bb51453ce76f1572ef2ee6ddcda8eeb Mon Sep 17 00:00:00 2001 From: Neeyanth Kopparapu <neeyanth@fb.com> Date: Tue, 15 Jun 2021 22:01:55 -0700 Subject: [PATCH 371/774] Enabled storing of dictionaries (#3601) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## What does this PR do? For HubertPretrainingTask, added dictionaries to the task state to enable the serialization of the dictionaries (thus removing the need to load from the disk after training) ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3601 Test Plan: To verify the success, run the Hubert Pretraining pipeline, load a checkpoint model, and verify that the "dictionaries" key is present in the state within the model. Specifically, ``` PYTHONPATH=. python /path/to/fairseq/fairseq_cli/hydra_train.py -m \ --config-dir ${fairseq_dir}/examples/hubert/config/pretrain \ --config-name hubert_base_librispeech \ hydra/launcher=submitit_local \ hydra.launcher.gpus_per_node=2 \ hydra.launcher.cpus_per_task=8 \ hydra.launcher.mem_gb=384 \ task.data=${tsv_dir} \ task.label_dir=${km_dir} \ task.labels=["km"] \ +data=iter1 \ optimization.max_update=250 \ hydra.sweep.dir=${exp_dir} \ hydra.run.dir=${exp_dir} > ${exp_dir}/log.out 2> ${exp_dir}/log.err & ``` Then, at the location of the model, load the model using `pytorch.load`, and verifying that "dictionaries" is a key under the `task_state` key of the model. ## Did you have fun? Make sure you had fun coding � Reviewed By: wnhsu Differential Revision: D28995537 Pulled By: neeyanthkvk fbshipit-source-id: e10c5163c367285518961b3ce1e719a29da06aa6 --- examples/hubert/config/finetune/base_10h.yaml | 1 + fairseq/tasks/hubert_pretraining.py | 42 ++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/examples/hubert/config/finetune/base_10h.yaml b/examples/hubert/config/finetune/base_10h.yaml index 844484d7fb..a22c7c0347 100644 --- a/examples/hubert/config/finetune/base_10h.yaml +++ b/examples/hubert/config/finetune/base_10h.yaml @@ -23,6 +23,7 @@ distributed_training: task: _name: hubert_pretraining data: ??? + fine_tuning: true label_dir: ??? normalize: false # must be consistent with pre-training labels: ["ltr"] diff --git a/fairseq/tasks/hubert_pretraining.py b/fairseq/tasks/hubert_pretraining.py index aff4100bb8..a63f2f6ef8 100644 --- a/fairseq/tasks/hubert_pretraining.py +++ b/fairseq/tasks/hubert_pretraining.py @@ -37,6 +37,9 @@ class HubertPretrainingConfig(FairseqDataclass): data: str = field( default=MISSING, metadata={"help": "path to data directory"} ) + fine_tuning: bool = field( + default=False, metadata={"help": "set to true if fine-tuning Hubert"} + ) labels: List[str] = field( default_factory=lambda: ["ltr"], metadata={ @@ -56,7 +59,6 @@ class HubertPretrainingConfig(FairseqDataclass): default=-1, metadata={"help": "label frame rate. -1 for sequence label"}, ) - sample_rate: int = field( default=16_000, metadata={ @@ -107,19 +109,22 @@ class HubertPretrainingTask(FairseqTask): def __init__( self, cfg: HubertPretrainingConfig, - dictionaries: Dict[str, Dictionary], ) -> None: super().__init__(cfg) logger.info(f"current directory is {os.getcwd()}") logger.info(f"HubertPretrainingTask Config {cfg}") - self._dictionaries = dictionaries + + self.cfg = cfg + self.fine_tuning = cfg.fine_tuning + + if cfg.fine_tuning: + self.state.add_factory("target_dictionary", lambda: self.load_dictionaries) + else: + self.state.add_factory("dictionaries", lambda: self.load_dictionaries) self._source_dictionary = None - self._target_dictionary = None - if len(self.dictionaries) == 1: - self._target_dictionary = self.dictionaries[0] self.blank_symbol = "<s>" @property @@ -128,24 +133,22 @@ def source_dictionary(self) -> Optional[Dictionary]: @property def target_dictionary(self) -> Optional[Dictionary]: - return self._target_dictionary + return self.state.target_dictionary @property def dictionaries(self) -> List[Dictionary]: - return [self._dictionaries[l] for l in self.cfg.labels] + return self.state.dictionaries @classmethod def setup_task( cls, cfg: HubertPretrainingConfig, **kwargs ) -> "HubertPretrainingTask": - label_dir = cfg.data if cfg.label_dir is None else cfg.label_dir - dictionaries = { - label: Dictionary.load(f"{label_dir}/dict.{label}.txt") - if os.path.exists(f"{label_dir}/dict.{label}.txt") - else None - for label in cfg.labels - } - return cls(cfg, dictionaries) + return cls(cfg) + + def load_dictionaries(self): + label_dir = self.cfg.data if self.cfg.label_dir is None else self.cfg.label_dir + dictionaries = [Dictionary.load(f"{label_dir}/dict.{label}.txt") for label in self.cfg.labels] + return dictionaries[0] if self.cfg.fine_tuning else dictionaries def get_label_dir(self) -> str: if self.cfg.label_dir is None: @@ -154,9 +157,10 @@ def get_label_dir(self) -> str: def load_dataset(self, split: str, **kwargs) -> None: manifest = f"{self.cfg.data}/{split}.tsv" - pad_list = [self._dictionaries[l].pad() for l in self.cfg.labels] - eos_list = [self._dictionaries[l].eos() for l in self.cfg.labels] - procs = [LabelEncoder(self._dictionaries[l]) for l in self.cfg.labels] + dicts = [self.target_dictionary] if self.cfg.fine_tuning else self.dictionaries + pad_list = [dict.pad() for dict in dicts] + eos_list = [dict.eos() for dict in dicts] + procs = [LabelEncoder(dict) for dict in dicts] paths = [ f"{self.get_label_dir()}/{split}.{l}" for l in self.cfg.labels ] From 67138ceb08b02c3148034e445cf5e76a616fc859 Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Thu, 17 Jun 2021 13:19:15 -0700 Subject: [PATCH 372/774] Fix lr for reduce_lr_on_plateau when there is no warmup Summary: warmup_init_lr should not be used if there is no warmup i.e. warmup_updates = 0 Created from Diffusion's 'Open in Editor' feature. Reviewed By: myleott Differential Revision: D29174059 fbshipit-source-id: c2e4cf998aebcff090584e689f692a0abe082e65 --- fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py b/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py index 6e29ba79b6..5ee9c1be4a 100644 --- a/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py +++ b/fairseq/optim/lr_scheduler/reduce_lr_on_plateau.py @@ -101,7 +101,7 @@ def __init__(self, cfg: ReduceLROnPlateauLRScheduleConfig, optimizer): # initial learning rate # this self.lr is used only during init and/or warm up period - self.lr = cfg.warmup_init_lr + self.lr = warmup_end_lr if self.warmup_end else cfg.warmup_init_lr self.optimizer.set_lr(self.lr) def state_dict(self): From b3491ae9d4c3eaa24292512cee7c21def713c535 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Thu, 17 Jun 2021 13:58:56 -0700 Subject: [PATCH 373/774] Add latency metrics to simulate tuna inference script and some other minor updates Summary: - Add average lagging latency metrics for online model. Offline models by default return 0 - Pad smaller input chunks with 0. - Enable export option in layer norm in transformer.py to avoid errors in scripted model inference. - Warm up prediction for scripted online model - Add additional args like force_read_cnt, data_split Reviewed By: xutaima Differential Revision: D28881594 fbshipit-source-id: fd4cce017539b5d8f6e39f9af9651341e47d6db0 --- fairseq/models/transformer.py | 4 +++- fairseq/modules/transformer_layer.py | 15 ++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index f4f6bea27b..2562752af9 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -725,7 +725,9 @@ def __init__( if args.decoder_normalize_before and not getattr( args, "no_decoder_final_norm", False ): - self.layer_norm = LayerNorm(embed_dim, export=export) + self.layer_norm = LayerNorm( + embed_dim, export=getattr(args, "char_inputs", False) + ) else: self.layer_norm = None diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 4f9ea22a9b..79af17fe30 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -33,8 +33,8 @@ def __init__(self, args): super().__init__() self.args = args self.embed_dim = args.encoder_embed_dim - self.quant_noise = getattr(args, 'quant_noise_pq', 0) - self.quant_noise_block_size = getattr(args, 'quant_noise_pq_block_size', 8) or 8 + self.quant_noise = getattr(args, "quant_noise_pq", 0) + self.quant_noise_block_size = getattr(args, "quant_noise_pq_block_size", 8) or 8 self.self_attn = self.build_self_attention(self.embed_dim, args) export = getattr(args, "export", False) self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) @@ -42,7 +42,7 @@ def __init__(self, args): args.dropout, module_name=self.__class__.__name__ ) self.activation_fn = utils.get_activation_fn( - activation=getattr(args, 'activation_fn', 'relu') or "relu" + activation=getattr(args, "activation_fn", "relu") or "relu" ) activation_dropout_p = getattr(args, "activation_dropout", 0) or 0 if activation_dropout_p == 0: @@ -104,7 +104,12 @@ def upgrade_state_dict_named(self, state_dict, name): state_dict["{}.{}.{}".format(name, new, m)] = state_dict[k] del state_dict[k] - def forward(self, x, encoder_padding_mask: Optional[Tensor], attn_mask: Optional[Tensor] = None): + def forward( + self, + x, + encoder_padding_mask: Optional[Tensor], + attn_mask: Optional[Tensor] = None, + ): """ Args: x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)` @@ -208,7 +213,7 @@ def __init__( ) self.normalize_before = args.decoder_normalize_before - export = getattr(args, "export", False) + export = getattr(args, "char_inputs", False) self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) if no_encoder_attn: From fc77eeb550e8ae74a14b36e6b9babc129f896725 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Fri, 18 Jun 2021 13:47:20 -0700 Subject: [PATCH 374/774] Change char_inputs to export as recommended in Fairseq Summary: TSIA Reviewed By: jmp84, henryhu6 Differential Revision: D29232406 fbshipit-source-id: 557006705faf28d723dc9f0ed9e92b0abe68e895 --- fairseq/models/transformer.py | 4 +--- fairseq/modules/transformer_layer.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index 2562752af9..f4f6bea27b 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -725,9 +725,7 @@ def __init__( if args.decoder_normalize_before and not getattr( args, "no_decoder_final_norm", False ): - self.layer_norm = LayerNorm( - embed_dim, export=getattr(args, "char_inputs", False) - ) + self.layer_norm = LayerNorm(embed_dim, export=export) else: self.layer_norm = None diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 79af17fe30..aa06a42935 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -213,7 +213,7 @@ def __init__( ) self.normalize_before = args.decoder_normalize_before - export = getattr(args, "char_inputs", False) + export = getattr(args, "export", False) self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) if no_encoder_attn: From 822442e42a020bac1ddaaaf4a99124db8b0cfab0 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Mon, 21 Jun 2021 11:05:15 -0700 Subject: [PATCH 375/774] fix task name in w2v-u generate (#1989) Summary: see title Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1989 Reviewed By: arbabu123 Differential Revision: D29267899 Pulled By: alexeib fbshipit-source-id: b89b804c14dbf8779b5cb56657d33bb03530f303 --- examples/wav2vec/unsupervised/w2vu_generate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wav2vec/unsupervised/w2vu_generate.py b/examples/wav2vec/unsupervised/w2vu_generate.py index b1e126665f..2bad873616 100644 --- a/examples/wav2vec/unsupervised/w2vu_generate.py +++ b/examples/wav2vec/unsupervised/w2vu_generate.py @@ -577,7 +577,7 @@ def main(cfg: UnsupGenerateConfig, model=None): overrides = ast.literal_eval(cfg.fairseq.common_eval.model_overrides) - if cfg.fairseq.task._name == "gan_audio_pretraining_feats": + if cfg.fairseq.task._name == "unpaired_audio_text": overrides["model"] = { "blank_weight": cfg.blank_weight, "blank_mode": cfg.blank_mode, From e47a4c84da877382c4d37941be4e84449f99d186 Mon Sep 17 00:00:00 2001 From: Neeyanth Kopparapu <neeyanth@fb.com> Date: Mon, 21 Jun 2021 12:32:19 -0700 Subject: [PATCH 376/774] hotfix to change factory creation for dictionaries (#1987) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## What does this PR do? Fixes issue of creating factories causing errors because the lambda function is not proper. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1987 Test Plan: Completed a small pretraining+finetuning procedure: Pretraining: ``` PYTHONPATH=. python /private/home/neeyanth/project/fairseq/fairseq_cli/hydra_train.py -m \ --config-dir ${fairseq_dir}/examples/hubert/config/pretrain \ --config-name hubert_base_librispeech \ hydra/launcher=submitit_local \ hydra.launcher.gpus_per_node=1 \ hydra.launcher.cpus_per_task=8 \ hydra.launcher.mem_gb=384 \ task.data=${tsv_dir} \ task.label_dir=${km_dir} \ task.labels=["km"] \ +data=iter1 \ optimization.max_update=250 \ hydra.sweep.dir=${exp_dir} \ hydra.run.dir=${exp_dir} > ${exp_dir}/log.out 2> ${exp_dir}/log.err & ``` Finetuning: ``` PYTHONPATH=. python /private/home/neeyanth/project/fairseq/fairseq_cli/hydra_train.py -m \ --config-dir ${fairseq_dir}/examples/hubert/config/finetune \ --config-name base_10h \ hydra/launcher=submitit_local \ hydra.launcher.gpus_per_node=1 \ hydra.launcher.cpus_per_task=8 \ hydra.launcher.mem_gb=384 \ task.data=${tsv_dir} \ task.label_dir=${tsv_dir} \ model.w2v_path=${model_dir} \ +data=iter1 \ optimization.max_update=250 \ hydra.sweep.dir=${exp_dir} \ hydra.run.dir=${exp_dir} > ${exp_dir}/log.out 2> ${exp_dir}/log.err & ``` Reviewed By: hikushalhere Differential Revision: D29266136 Pulled By: neeyanthkvk fbshipit-source-id: d36c668ae38a7761b4c44f4dcb0c4cc8e15e42ce --- fairseq/tasks/hubert_pretraining.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/tasks/hubert_pretraining.py b/fairseq/tasks/hubert_pretraining.py index a63f2f6ef8..ee3fedce3f 100644 --- a/fairseq/tasks/hubert_pretraining.py +++ b/fairseq/tasks/hubert_pretraining.py @@ -119,9 +119,9 @@ def __init__( self.fine_tuning = cfg.fine_tuning if cfg.fine_tuning: - self.state.add_factory("target_dictionary", lambda: self.load_dictionaries) + self.state.add_factory("target_dictionary", self.load_dictionaries) else: - self.state.add_factory("dictionaries", lambda: self.load_dictionaries) + self.state.add_factory("dictionaries", self.load_dictionaries) self._source_dictionary = None From 900a607ea3226e0cfd966a894b8b1effe25faa5e Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Mon, 21 Jun 2021 19:40:02 -0700 Subject: [PATCH 377/774] add timit w2vu recipe (#1991) Summary: ## What does this PR do? Add TIMIT data preparation scripts for wav2vec-U Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1991 Reviewed By: alexeib Differential Revision: D29284481 Pulled By: wnhsu fbshipit-source-id: dccd75159a9de4f3cd95f9e4a90ce4bdf9264f2b --- examples/wav2vec/unsupervised/README.md | 10 + .../config/timit_matched/test.uid | 192 + .../config/timit_matched/train.uid | 3696 +++++++++++++++++ .../config/timit_matched/train_text.uid | 3696 +++++++++++++++++ .../config/timit_matched/valid.uid | 400 ++ .../config/timit_unmatched/test.uid | 1680 ++++++++ .../config/timit_unmatched/train.uid | 3000 +++++++++++++ .../config/timit_unmatched/train_text.uid | 1000 +++++ .../config/timit_unmatched/valid.uid | 620 +++ .../unsupervised/scripts/prepare_timit.sh | 79 + 10 files changed, 14373 insertions(+) create mode 100644 examples/wav2vec/unsupervised/config/timit_matched/test.uid create mode 100644 examples/wav2vec/unsupervised/config/timit_matched/train.uid create mode 100644 examples/wav2vec/unsupervised/config/timit_matched/train_text.uid create mode 100644 examples/wav2vec/unsupervised/config/timit_matched/valid.uid create mode 100644 examples/wav2vec/unsupervised/config/timit_unmatched/test.uid create mode 100644 examples/wav2vec/unsupervised/config/timit_unmatched/train.uid create mode 100644 examples/wav2vec/unsupervised/config/timit_unmatched/train_text.uid create mode 100644 examples/wav2vec/unsupervised/config/timit_unmatched/valid.uid create mode 100644 examples/wav2vec/unsupervised/scripts/prepare_timit.sh diff --git a/examples/wav2vec/unsupervised/README.md b/examples/wav2vec/unsupervised/README.md index c2a935d414..046202e01c 100644 --- a/examples/wav2vec/unsupervised/README.md +++ b/examples/wav2vec/unsupervised/README.md @@ -48,6 +48,16 @@ The fifth argument is which phonemizer to use. Supported values are [espeak](htt Pre-trained fasttext LID models can be downloaded [here](https://fasttext.cc/docs/en/language-identification.html). +### Prepare TIMIT data +TIMIT transcripts include silence. Therefore VAD is not used for audio preprocessing, and we do not wrap transcripts with silences or insert random silence in between words. + +To prepare TIMIT data for both the matched an unmatched setup: +```shell +bash scripts/prepare_timit.sh /dir/to/timit/raw/data /output/dir /path/to/wav2vec2/model.pt +``` + +Note that we assume the TIMIT distribution with capitalized directories and filenames are used (e.g., `TRAIN/DR1/FCJF0/SA1.PHN`). + ## Generative adversarial training (GAN) We then use a GAN model to build a first unsupervised ASR model. The data preparation above of both speech features and text data is a necessary procedure that enables the generator to match speech to text in an unsupervised way. diff --git a/examples/wav2vec/unsupervised/config/timit_matched/test.uid b/examples/wav2vec/unsupervised/config/timit_matched/test.uid new file mode 100644 index 0000000000..401008246a --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_matched/test.uid @@ -0,0 +1,192 @@ +FDHC0_SI1559 +FDHC0_SI2189 +FDHC0_SI929 +FDHC0_SX119 +FDHC0_SX209 +FDHC0_SX29 +FDHC0_SX299 +FDHC0_SX389 +FELC0_SI1386 +FELC0_SI2016 +FELC0_SI756 +FELC0_SX126 +FELC0_SX216 +FELC0_SX306 +FELC0_SX36 +FELC0_SX396 +FJLM0_SI1043 +FJLM0_SI1673 +FJLM0_SI2303 +FJLM0_SX143 +FJLM0_SX233 +FJLM0_SX323 +FJLM0_SX413 +FJLM0_SX53 +FMGD0_SI1564 +FMGD0_SI2194 +FMGD0_SI934 +FMGD0_SX124 +FMGD0_SX214 +FMGD0_SX304 +FMGD0_SX34 +FMGD0_SX394 +FMLD0_SI2185 +FMLD0_SI822 +FMLD0_SI925 +FMLD0_SX115 +FMLD0_SX205 +FMLD0_SX25 +FMLD0_SX295 +FMLD0_SX385 +FNLP0_SI1308 +FNLP0_SI1938 +FNLP0_SI678 +FNLP0_SX138 +FNLP0_SX228 +FNLP0_SX318 +FNLP0_SX408 +FNLP0_SX48 +FPAS0_SI1272 +FPAS0_SI2204 +FPAS0_SI944 +FPAS0_SX134 +FPAS0_SX224 +FPAS0_SX314 +FPAS0_SX404 +FPAS0_SX44 +FPKT0_SI1538 +FPKT0_SI2168 +FPKT0_SI908 +FPKT0_SX188 +FPKT0_SX278 +FPKT0_SX368 +FPKT0_SX8 +FPKT0_SX98 +MBPM0_SI1577 +MBPM0_SI1584 +MBPM0_SI947 +MBPM0_SX137 +MBPM0_SX227 +MBPM0_SX317 +MBPM0_SX407 +MBPM0_SX47 +MCMJ0_SI1094 +MCMJ0_SI464 +MCMJ0_SI602 +MCMJ0_SX104 +MCMJ0_SX14 +MCMJ0_SX194 +MCMJ0_SX284 +MCMJ0_SX374 +MDAB0_SI1039 +MDAB0_SI1669 +MDAB0_SI2299 +MDAB0_SX139 +MDAB0_SX229 +MDAB0_SX319 +MDAB0_SX409 +MDAB0_SX49 +MGRT0_SI1450 +MGRT0_SI2080 +MGRT0_SI820 +MGRT0_SX10 +MGRT0_SX100 +MGRT0_SX190 +MGRT0_SX280 +MGRT0_SX370 +MJDH0_SI1354 +MJDH0_SI1984 +MJDH0_SI724 +MJDH0_SX184 +MJDH0_SX274 +MJDH0_SX364 +MJDH0_SX4 +MJDH0_SX94 +MJLN0_SI1449 +MJLN0_SI2079 +MJLN0_SI819 +MJLN0_SX189 +MJLN0_SX279 +MJLN0_SX369 +MJLN0_SX9 +MJLN0_SX99 +MJMP0_SI1535 +MJMP0_SI1791 +MJMP0_SI905 +MJMP0_SX185 +MJMP0_SX275 +MJMP0_SX365 +MJMP0_SX5 +MJMP0_SX95 +MKLT0_SI1213 +MKLT0_SI1843 +MKLT0_SI583 +MKLT0_SX133 +MKLT0_SX223 +MKLT0_SX313 +MKLT0_SX403 +MKLT0_SX43 +MLLL0_SI1363 +MLLL0_SI1993 +MLLL0_SI733 +MLLL0_SX103 +MLLL0_SX13 +MLLL0_SX193 +MLLL0_SX283 +MLLL0_SX373 +MLNT0_SI1574 +MLNT0_SI1902 +MLNT0_SI642 +MLNT0_SX102 +MLNT0_SX12 +MLNT0_SX192 +MLNT0_SX282 +MLNT0_SX372 +MNJM0_SI1580 +MNJM0_SI2210 +MNJM0_SI950 +MNJM0_SX140 +MNJM0_SX230 +MNJM0_SX320 +MNJM0_SX410 +MNJM0_SX50 +MPAM0_SI1189 +MPAM0_SI1819 +MPAM0_SI1961 +MPAM0_SX109 +MPAM0_SX19 +MPAM0_SX199 +MPAM0_SX289 +MPAM0_SX379 +MTAS1_SI1473 +MTAS1_SI2098 +MTAS1_SI838 +MTAS1_SX118 +MTAS1_SX208 +MTAS1_SX28 +MTAS1_SX298 +MTAS1_SX388 +MTLS0_SI1370 +MTLS0_SI2000 +MTLS0_SI740 +MTLS0_SX110 +MTLS0_SX20 +MTLS0_SX200 +MTLS0_SX290 +MTLS0_SX380 +MWBT0_SI1553 +MWBT0_SI2183 +MWBT0_SI923 +MWBT0_SX113 +MWBT0_SX203 +MWBT0_SX23 +MWBT0_SX293 +MWBT0_SX383 +MWEW0_SI1361 +MWEW0_SI1991 +MWEW0_SI731 +MWEW0_SX101 +MWEW0_SX11 +MWEW0_SX191 +MWEW0_SX281 +MWEW0_SX371 diff --git a/examples/wav2vec/unsupervised/config/timit_matched/train.uid b/examples/wav2vec/unsupervised/config/timit_matched/train.uid new file mode 100644 index 0000000000..c39fd0b91d --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_matched/train.uid @@ -0,0 +1,3696 @@ +FAEM0_SI1392 +FAEM0_SI2022 +FAEM0_SI762 +FAEM0_SX132 +FAEM0_SX222 +FAEM0_SX312 +FAEM0_SX402 +FAEM0_SX42 +FAJW0_SI1263 +FAJW0_SI1893 +FAJW0_SI633 +FAJW0_SX183 +FAJW0_SX273 +FAJW0_SX3 +FAJW0_SX363 +FAJW0_SX93 +FALK0_SI1086 +FALK0_SI456 +FALK0_SI658 +FALK0_SX186 +FALK0_SX276 +FALK0_SX366 +FALK0_SX6 +FALK0_SX96 +FALR0_SI1325 +FALR0_SI1955 +FALR0_SI695 +FALR0_SX155 +FALR0_SX245 +FALR0_SX335 +FALR0_SX425 +FALR0_SX65 +FAPB0_SI1063 +FAPB0_SI1693 +FAPB0_SI2323 +FAPB0_SX163 +FAPB0_SX253 +FAPB0_SX343 +FAPB0_SX433 +FAPB0_SX73 +FBAS0_SI1387 +FBAS0_SI1472 +FBAS0_SI2066 +FBAS0_SX127 +FBAS0_SX217 +FBAS0_SX307 +FBAS0_SX37 +FBAS0_SX397 +FBCG1_SI1612 +FBCG1_SI2242 +FBCG1_SI982 +FBCG1_SX172 +FBCG1_SX262 +FBCG1_SX352 +FBCG1_SX442 +FBCG1_SX82 +FBCH0_SI1586 +FBCH0_SI956 +FBCH0_SI959 +FBCH0_SX146 +FBCH0_SX236 +FBCH0_SX326 +FBCH0_SX416 +FBCH0_SX56 +FBJL0_SI1552 +FBJL0_SI2182 +FBJL0_SI922 +FBJL0_SX112 +FBJL0_SX202 +FBJL0_SX22 +FBJL0_SX292 +FBJL0_SX382 +FBLV0_SI1058 +FBLV0_SI1688 +FBLV0_SI2318 +FBLV0_SX158 +FBLV0_SX248 +FBLV0_SX338 +FBLV0_SX428 +FBLV0_SX68 +FBMH0_SI1136 +FBMH0_SI1766 +FBMH0_SI970 +FBMH0_SX146 +FBMH0_SX236 +FBMH0_SX326 +FBMH0_SX416 +FBMH0_SX56 +FBMJ0_SI1776 +FBMJ0_SI516 +FBMJ0_SI815 +FBMJ0_SX156 +FBMJ0_SX246 +FBMJ0_SX336 +FBMJ0_SX426 +FBMJ0_SX66 +FCAG0_SI1503 +FCAG0_SI1641 +FCAG0_SI2133 +FCAG0_SX153 +FCAG0_SX243 +FCAG0_SX333 +FCAG0_SX423 +FCAG0_SX63 +FCAJ0_SI1479 +FCAJ0_SI1804 +FCAJ0_SI849 +FCAJ0_SX129 +FCAJ0_SX219 +FCAJ0_SX309 +FCAJ0_SX39 +FCAJ0_SX399 +FCDR1_SI1186 +FCDR1_SI1816 +FCDR1_SI556 +FCDR1_SX106 +FCDR1_SX16 +FCDR1_SX196 +FCDR1_SX286 +FCDR1_SX376 +FCEG0_SI1248 +FCEG0_SI1878 +FCEG0_SI618 +FCEG0_SX168 +FCEG0_SX258 +FCEG0_SX348 +FCEG0_SX438 +FCEG0_SX78 +FCJF0_SI1027 +FCJF0_SI1657 +FCJF0_SI648 +FCJF0_SX127 +FCJF0_SX217 +FCJF0_SX307 +FCJF0_SX37 +FCJF0_SX397 +FCJS0_SI1607 +FCJS0_SI2237 +FCJS0_SI977 +FCJS0_SX167 +FCJS0_SX257 +FCJS0_SX347 +FCJS0_SX437 +FCJS0_SX77 +FCKE0_SI1111 +FCKE0_SI1741 +FCKE0_SI481 +FCKE0_SX121 +FCKE0_SX211 +FCKE0_SX301 +FCKE0_SX31 +FCKE0_SX391 +FCLT0_SI1438 +FCLT0_SI2068 +FCLT0_SI808 +FCLT0_SX178 +FCLT0_SX268 +FCLT0_SX358 +FCLT0_SX448 +FCLT0_SX88 +FCMG0_SI1142 +FCMG0_SI1242 +FCMG0_SI1872 +FCMG0_SX162 +FCMG0_SX252 +FCMG0_SX342 +FCMG0_SX432 +FCMG0_SX72 +FCMM0_SI1083 +FCMM0_SI1957 +FCMM0_SI453 +FCMM0_SX183 +FCMM0_SX273 +FCMM0_SX363 +FCMM0_SX420 +FCMM0_SX93 +FCRZ0_SI1913 +FCRZ0_SI2053 +FCRZ0_SI793 +FCRZ0_SX163 +FCRZ0_SX253 +FCRZ0_SX343 +FCRZ0_SX433 +FCRZ0_SX73 +FCYL0_SI1297 +FCYL0_SI1927 +FCYL0_SI667 +FCYL0_SX127 +FCYL0_SX217 +FCYL0_SX349 +FCYL0_SX37 +FCYL0_SX397 +FDAS1_SI1461 +FDAS1_SI2091 +FDAS1_SI831 +FDAS1_SX111 +FDAS1_SX201 +FDAS1_SX21 +FDAS1_SX291 +FDAS1_SX381 +FDAW0_SI1271 +FDAW0_SI1406 +FDAW0_SI2036 +FDAW0_SX146 +FDAW0_SX236 +FDAW0_SX326 +FDAW0_SX416 +FDAW0_SX56 +FDFB0_SI1318 +FDFB0_SI1948 +FDFB0_SI2010 +FDFB0_SX148 +FDFB0_SX238 +FDFB0_SX328 +FDFB0_SX418 +FDFB0_SX58 +FDJH0_SI1565 +FDJH0_SI2195 +FDJH0_SI935 +FDJH0_SX125 +FDJH0_SX215 +FDJH0_SX305 +FDJH0_SX35 +FDJH0_SX395 +FDKN0_SI1081 +FDKN0_SI1202 +FDKN0_SI1711 +FDKN0_SX181 +FDKN0_SX271 +FDKN0_SX361 +FDKN0_SX451 +FDKN0_SX91 +FDML0_SI1149 +FDML0_SI1779 +FDML0_SI2075 +FDML0_SX159 +FDML0_SX249 +FDML0_SX339 +FDML0_SX429 +FDML0_SX69 +FDMY0_SI1197 +FDMY0_SI567 +FDMY0_SI714 +FDMY0_SX117 +FDMY0_SX207 +FDMY0_SX27 +FDMY0_SX297 +FDMY0_SX387 +FDNC0_SI1278 +FDNC0_SI1908 +FDNC0_SI2287 +FDNC0_SX108 +FDNC0_SX18 +FDNC0_SX198 +FDNC0_SX288 +FDNC0_SX378 +FDTD0_SI1561 +FDTD0_SI2191 +FDTD0_SI931 +FDTD0_SX121 +FDTD0_SX211 +FDTD0_SX301 +FDTD0_SX321 +FDTD0_SX391 +FDXW0_SI1511 +FDXW0_SI2141 +FDXW0_SI881 +FDXW0_SX161 +FDXW0_SX251 +FDXW0_SX341 +FDXW0_SX431 +FDXW0_SX71 +FEAC0_SI1245 +FEAC0_SI1875 +FEAC0_SI615 +FEAC0_SX165 +FEAC0_SX255 +FEAC0_SX345 +FEAC0_SX435 +FEAC0_SX75 +FEAR0_SI1252 +FEAR0_SI1882 +FEAR0_SI622 +FEAR0_SX172 +FEAR0_SX262 +FEAR0_SX352 +FEAR0_SX442 +FEAR0_SX82 +FECD0_SI1418 +FECD0_SI2048 +FECD0_SI788 +FECD0_SX158 +FECD0_SX248 +FECD0_SX338 +FECD0_SX428 +FECD0_SX68 +FEEH0_SI1112 +FEEH0_SI1742 +FEEH0_SI471 +FEEH0_SX122 +FEEH0_SX212 +FEEH0_SX302 +FEEH0_SX32 +FEEH0_SX392 +FEME0_SI1505 +FEME0_SI2135 +FEME0_SI875 +FEME0_SX155 +FEME0_SX245 +FEME0_SX335 +FEME0_SX425 +FEME0_SX65 +FETB0_SI1148 +FETB0_SI1778 +FETB0_SI518 +FETB0_SX158 +FETB0_SX248 +FETB0_SX338 +FETB0_SX428 +FETB0_SX68 +FEXM0_SI1101 +FEXM0_SI1731 +FEXM0_SI482 +FEXM0_SX111 +FEXM0_SX201 +FEXM0_SX291 +FEXM0_SX366 +FEXM0_SX381 +FGCS0_SI1486 +FGCS0_SI2116 +FGCS0_SI856 +FGCS0_SX136 +FGCS0_SX226 +FGCS0_SX316 +FGCS0_SX406 +FGCS0_SX46 +FGDP0_SI1618 +FGDP0_SI2248 +FGDP0_SI988 +FGDP0_SX178 +FGDP0_SX268 +FGDP0_SX358 +FGDP0_SX448 +FGDP0_SX88 +FGMB0_SI1145 +FGMB0_SI1775 +FGMB0_SI515 +FGMB0_SX155 +FGMB0_SX245 +FGMB0_SX335 +FGMB0_SX425 +FGMB0_SX65 +FGRW0_SI1152 +FGRW0_SI1782 +FGRW0_SI1990 +FGRW0_SX162 +FGRW0_SX252 +FGRW0_SX342 +FGRW0_SX432 +FGRW0_SX72 +FHLM0_SI1560 +FHLM0_SI2190 +FHLM0_SI930 +FHLM0_SX120 +FHLM0_SX210 +FHLM0_SX300 +FHLM0_SX349 +FHLM0_SX390 +FHXS0_SI1075 +FHXS0_SI2302 +FHXS0_SI2335 +FHXS0_SX175 +FHXS0_SX265 +FHXS0_SX355 +FHXS0_SX445 +FHXS0_SX85 +FJDM2_SI1582 +FJDM2_SI1964 +FJDM2_SI2212 +FJDM2_SX142 +FJDM2_SX232 +FJDM2_SX322 +FJDM2_SX412 +FJDM2_SX52 +FJEN0_SI1047 +FJEN0_SI1677 +FJEN0_SI2307 +FJEN0_SX147 +FJEN0_SX237 +FJEN0_SX327 +FJEN0_SX417 +FJEN0_SX57 +FJHK0_SI1022 +FJHK0_SI1652 +FJHK0_SI2282 +FJHK0_SX122 +FJHK0_SX212 +FJHK0_SX302 +FJHK0_SX32 +FJHK0_SX392 +FJKL0_SI1562 +FJKL0_SI2192 +FJKL0_SI932 +FJKL0_SX122 +FJKL0_SX212 +FJKL0_SX302 +FJKL0_SX32 +FJKL0_SX392 +FJLG0_SI1506 +FJLG0_SI1889 +FJLG0_SI2306 +FJLG0_SX179 +FJLG0_SX269 +FJLG0_SX359 +FJLG0_SX449 +FJLG0_SX89 +FJLR0_SI1231 +FJLR0_SI1861 +FJLR0_SI601 +FJLR0_SX151 +FJLR0_SX241 +FJLR0_SX331 +FJLR0_SX421 +FJLR0_SX61 +FJRB0_SI1302 +FJRB0_SI1932 +FJRB0_SI672 +FJRB0_SX132 +FJRB0_SX222 +FJRB0_SX312 +FJRB0_SX402 +FJRB0_SX42 +FJRP1_SI1432 +FJRP1_SI2062 +FJRP1_SI802 +FJRP1_SX172 +FJRP1_SX262 +FJRP1_SX352 +FJRP1_SX442 +FJRP1_SX82 +FJSK0_SI1052 +FJSK0_SI1682 +FJSK0_SI2312 +FJSK0_SX152 +FJSK0_SX242 +FJSK0_SX332 +FJSK0_SX422 +FJSK0_SX62 +FJSP0_SI1434 +FJSP0_SI1763 +FJSP0_SI804 +FJSP0_SX174 +FJSP0_SX264 +FJSP0_SX354 +FJSP0_SX444 +FJSP0_SX84 +FJWB1_SI2055 +FJWB1_SI748 +FJWB1_SI795 +FJWB1_SX165 +FJWB1_SX255 +FJWB1_SX345 +FJWB1_SX435 +FJWB1_SX75 +FJXM0_SI1211 +FJXM0_SI1971 +FJXM0_SI581 +FJXM0_SX131 +FJXM0_SX221 +FJXM0_SX311 +FJXM0_SX401 +FJXM0_SX41 +FJXP0_SI1122 +FJXP0_SI1752 +FJXP0_SI492 +FJXP0_SX132 +FJXP0_SX222 +FJXP0_SX312 +FJXP0_SX402 +FJXP0_SX42 +FKAA0_SI1208 +FKAA0_SI1838 +FKAA0_SI578 +FKAA0_SX128 +FKAA0_SX218 +FKAA0_SX308 +FKAA0_SX38 +FKAA0_SX398 +FKDE0_SI1141 +FKDE0_SI1771 +FKDE0_SI2221 +FKDE0_SX151 +FKDE0_SX241 +FKDE0_SX331 +FKDE0_SX421 +FKDE0_SX61 +FKDW0_SI1207 +FKDW0_SI1891 +FKDW0_SI577 +FKDW0_SX127 +FKDW0_SX217 +FKDW0_SX307 +FKDW0_SX37 +FKDW0_SX397 +FKFB0_SI1608 +FKFB0_SI2238 +FKFB0_SI978 +FKFB0_SX168 +FKFB0_SX258 +FKFB0_SX348 +FKFB0_SX438 +FKFB0_SX78 +FKKH0_SI1290 +FKKH0_SI1920 +FKKH0_SI660 +FKKH0_SX120 +FKKH0_SX210 +FKKH0_SX30 +FKKH0_SX300 +FKKH0_SX390 +FKLC0_SI1615 +FKLC0_SI2245 +FKLC0_SI985 +FKLC0_SX175 +FKLC0_SX265 +FKLC0_SX355 +FKLC0_SX445 +FKLC0_SX85 +FKLC1_SI1048 +FKLC1_SI1678 +FKLC1_SI2308 +FKLC1_SX148 +FKLC1_SX238 +FKLC1_SX328 +FKLC1_SX418 +FKLC1_SX58 +FKLH0_SI1257 +FKLH0_SI1887 +FKLH0_SI627 +FKLH0_SX177 +FKLH0_SX267 +FKLH0_SX357 +FKLH0_SX447 +FKLH0_SX87 +FKSR0_SI1117 +FKSR0_SI1747 +FKSR0_SI487 +FKSR0_SX161 +FKSR0_SX217 +FKSR0_SX366 +FKSR0_SX37 +FKSR0_SX397 +FLAC0_SI1339 +FLAC0_SI2161 +FLAC0_SI901 +FLAC0_SX181 +FLAC0_SX271 +FLAC0_SX361 +FLAC0_SX451 +FLAC0_SX91 +FLAG0_SI1464 +FLAG0_SI2094 +FLAG0_SI834 +FLAG0_SX114 +FLAG0_SX204 +FLAG0_SX24 +FLAG0_SX294 +FLAG0_SX384 +FLEH0_SI1051 +FLEH0_SI1681 +FLEH0_SI2311 +FLEH0_SX151 +FLEH0_SX241 +FLEH0_SX331 +FLEH0_SX421 +FLEH0_SX61 +FLET0_SI1137 +FLET0_SI1767 +FLET0_SI507 +FLET0_SX147 +FLET0_SX237 +FLET0_SX277 +FLET0_SX417 +FLET0_SX57 +FLHD0_SI1344 +FLHD0_SI1827 +FLHD0_SI1974 +FLHD0_SX174 +FLHD0_SX264 +FLHD0_SX354 +FLHD0_SX444 +FLHD0_SX84 +FLJA0_SI1078 +FLJA0_SI1708 +FLJA0_SI2338 +FLJA0_SX178 +FLJA0_SX268 +FLJA0_SX358 +FLJA0_SX448 +FLJA0_SX88 +FLJD0_SI1516 +FLJD0_SI2146 +FLJD0_SI886 +FLJD0_SX166 +FLJD0_SX256 +FLJD0_SX346 +FLJD0_SX436 +FLJD0_SX76 +FLJG0_SI1611 +FLJG0_SI2241 +FLJG0_SI981 +FLJG0_SX171 +FLJG0_SX261 +FLJG0_SX351 +FLJG0_SX441 +FLJG0_SX81 +FLKM0_SI1880 +FLKM0_SI620 +FLKM0_SI686 +FLKM0_SX116 +FLKM0_SX260 +FLKM0_SX350 +FLKM0_SX440 +FLKM0_SX80 +FLMA0_SI1243 +FLMA0_SI1873 +FLMA0_SI613 +FLMA0_SX163 +FLMA0_SX253 +FLMA0_SX343 +FLMA0_SX433 +FLMA0_SX73 +FLMC0_SI1372 +FLMC0_SI2002 +FLMC0_SI742 +FLMC0_SX112 +FLMC0_SX22 +FLMC0_SX292 +FLMC0_SX336 +FLMC0_SX382 +FLMK0_SI1035 +FLMK0_SI1229 +FLMK0_SI2295 +FLMK0_SX135 +FLMK0_SX225 +FLMK0_SX315 +FLMK0_SX405 +FLMK0_SX45 +FLOD0_SI1287 +FLOD0_SI1917 +FLOD0_SI657 +FLOD0_SX117 +FLOD0_SX171 +FLOD0_SX207 +FLOD0_SX297 +FLOD0_SX387 +FLTM0_SI1070 +FLTM0_SI1700 +FLTM0_SI2330 +FLTM0_SX170 +FLTM0_SX260 +FLTM0_SX350 +FLTM0_SX440 +FLTM0_SX80 +FMAH1_SI1509 +FMAH1_SI2139 +FMAH1_SI879 +FMAH1_SX159 +FMAH1_SX249 +FMAH1_SX339 +FMAH1_SX429 +FMAH1_SX69 +FMBG0_SI1160 +FMBG0_SI1790 +FMBG0_SI2264 +FMBG0_SX260 +FMBG0_SX3 +FMBG0_SX350 +FMBG0_SX440 +FMBG0_SX80 +FMEM0_SI1377 +FMEM0_SI2007 +FMEM0_SI747 +FMEM0_SX117 +FMEM0_SX207 +FMEM0_SX297 +FMEM0_SX333 +FMEM0_SX387 +FMJB0_SI1177 +FMJB0_SI1807 +FMJB0_SI547 +FMJB0_SX187 +FMJB0_SX277 +FMJB0_SX367 +FMJB0_SX7 +FMJB0_SX97 +FMJF0_SI1254 +FMJF0_SI1884 +FMJF0_SI624 +FMJF0_SX174 +FMJF0_SX264 +FMJF0_SX354 +FMJF0_SX444 +FMJF0_SX84 +FMJU0_SI1389 +FMJU0_SI2019 +FMJU0_SI759 +FMJU0_SX129 +FMJU0_SX219 +FMJU0_SX309 +FMJU0_SX39 +FMJU0_SX399 +FMKC0_SI1041 +FMKC0_SI1072 +FMKC0_SI1702 +FMKC0_SX172 +FMKC0_SX262 +FMKC0_SX352 +FMKC0_SX442 +FMKC0_SX82 +FMKF0_SI1018 +FMKF0_SI1536 +FMKF0_SI906 +FMKF0_SX186 +FMKF0_SX276 +FMKF0_SX366 +FMKF0_SX6 +FMKF0_SX96 +FMMH0_SI1537 +FMMH0_SI2167 +FMMH0_SI907 +FMMH0_SX187 +FMMH0_SX367 +FMMH0_SX420 +FMMH0_SX7 +FMMH0_SX97 +FMPG0_SI1602 +FMPG0_SI2232 +FMPG0_SI972 +FMPG0_SX162 +FMPG0_SX252 +FMPG0_SX342 +FMPG0_SX432 +FMPG0_SX72 +FNKL0_SI1522 +FNKL0_SI2152 +FNKL0_SI892 +FNKL0_SX172 +FNKL0_SX196 +FNKL0_SX262 +FNKL0_SX442 +FNKL0_SX82 +FNTB0_SI1203 +FNTB0_SI573 +FNTB0_SI679 +FNTB0_SX123 +FNTB0_SX213 +FNTB0_SX303 +FNTB0_SX33 +FNTB0_SX393 +FPAB1_SI1471 +FPAB1_SI2101 +FPAB1_SI841 +FPAB1_SX121 +FPAB1_SX211 +FPAB1_SX301 +FPAB1_SX31 +FPAB1_SX391 +FPAC0_SI1921 +FPAC0_SI2011 +FPAC0_SI661 +FPAC0_SX121 +FPAC0_SX211 +FPAC0_SX301 +FPAC0_SX31 +FPAC0_SX391 +FPAD0_SI1346 +FPAD0_SI1976 +FPAD0_SI716 +FPAD0_SX176 +FPAD0_SX266 +FPAD0_SX356 +FPAD0_SX446 +FPAD0_SX86 +FPAF0_SI1054 +FPAF0_SI1684 +FPAF0_SI2314 +FPAF0_SX154 +FPAF0_SX244 +FPAF0_SX334 +FPAF0_SX424 +FPAF0_SX64 +FPAZ0_SI1593 +FPAZ0_SI2223 +FPAZ0_SI963 +FPAZ0_SX153 +FPAZ0_SX243 +FPAZ0_SX27 +FPAZ0_SX423 +FPAZ0_SX63 +FPJF0_SI1046 +FPJF0_SI1259 +FPJF0_SI1676 +FPJF0_SX146 +FPJF0_SX236 +FPJF0_SX326 +FPJF0_SX352 +FPJF0_SX56 +FPLS0_SI1590 +FPLS0_SI2220 +FPLS0_SI960 +FPLS0_SX150 +FPLS0_SX240 +FPLS0_SX3 +FPLS0_SX330 +FPLS0_SX60 +FPMY0_SI1153 +FPMY0_SI1783 +FPMY0_SI523 +FPMY0_SX163 +FPMY0_SX196 +FPMY0_SX253 +FPMY0_SX343 +FPMY0_SX73 +FREH0_SI1315 +FREH0_SI1945 +FREH0_SI685 +FREH0_SX145 +FREH0_SX235 +FREH0_SX325 +FREH0_SX415 +FREH0_SX55 +FRJB0_SI1427 +FRJB0_SI1470 +FRJB0_SI1794 +FRJB0_SX167 +FRJB0_SX257 +FRJB0_SX347 +FRJB0_SX437 +FRJB0_SX77 +FRLL0_SI1514 +FRLL0_SI805 +FRLL0_SI884 +FRLL0_SX164 +FRLL0_SX254 +FRLL0_SX344 +FRLL0_SX434 +FRLL0_SX74 +FSAG0_SI1323 +FSAG0_SI1953 +FSAG0_SI693 +FSAG0_SX153 +FSAG0_SX243 +FSAG0_SX333 +FSAG0_SX423 +FSAG0_SX63 +FSAH0_SI1244 +FSAH0_SI1874 +FSAH0_SI614 +FSAH0_SX164 +FSAH0_SX327 +FSAH0_SX344 +FSAH0_SX434 +FSAH0_SX74 +FSAK0_SI1300 +FSAK0_SI1930 +FSAK0_SI670 +FSAK0_SX130 +FSAK0_SX220 +FSAK0_SX310 +FSAK0_SX40 +FSAK0_SX400 +FSBK0_SI1069 +FSBK0_SI1699 +FSBK0_SI2329 +FSBK0_SX169 +FSBK0_SX259 +FSBK0_SX349 +FSBK0_SX439 +FSBK0_SX79 +FSCN0_SI1886 +FSCN0_SI626 +FSCN0_SI705 +FSCN0_SX176 +FSCN0_SX266 +FSCN0_SX356 +FSCN0_SX446 +FSCN0_SX86 +FSDC0_SI1312 +FSDC0_SI1942 +FSDC0_SI2234 +FSDC0_SX142 +FSDC0_SX232 +FSDC0_SX322 +FSDC0_SX412 +FSDC0_SX52 +FSDJ0_SI1115 +FSDJ0_SI1745 +FSDJ0_SI485 +FSDJ0_SX125 +FSDJ0_SX215 +FSDJ0_SX305 +FSDJ0_SX35 +FSDJ0_SX395 +FSGF0_SI1557 +FSGF0_SI2187 +FSGF0_SI927 +FSGF0_SX117 +FSGF0_SX207 +FSGF0_SX27 +FSGF0_SX297 +FSGF0_SX387 +FSJG0_SI1570 +FSJG0_SI2200 +FSJG0_SI940 +FSJG0_SX130 +FSJG0_SX220 +FSJG0_SX310 +FSJG0_SX40 +FSJG0_SX400 +FSJK1_SI1025 +FSJK1_SI2285 +FSJK1_SI696 +FSJK1_SX125 +FSJK1_SX215 +FSJK1_SX305 +FSJK1_SX35 +FSJK1_SX395 +FSJS0_SI1171 +FSJS0_SI1801 +FSJS0_SI541 +FSJS0_SX181 +FSJS0_SX271 +FSJS0_SX361 +FSJS0_SX451 +FSJS0_SX91 +FSJW0_SI1333 +FSJW0_SI1963 +FSJW0_SI703 +FSJW0_SX163 +FSJW0_SX253 +FSJW0_SX343 +FSJW0_SX433 +FSJW0_SX73 +FSKC0_SI1416 +FSKC0_SI2046 +FSKC0_SI786 +FSKC0_SX156 +FSKC0_SX246 +FSKC0_SX336 +FSKC0_SX426 +FSKC0_SX66 +FSKL0_SI1529 +FSKL0_SI2159 +FSKL0_SI899 +FSKL0_SX179 +FSKL0_SX269 +FSKL0_SX359 +FSKL0_SX449 +FSKL0_SX89 +FSKP0_SI1098 +FSKP0_SI1728 +FSKP0_SI468 +FSKP0_SX108 +FSKP0_SX18 +FSKP0_SX198 +FSKP0_SX288 +FSKP0_SX378 +FSLS0_SI1056 +FSLS0_SI1686 +FSLS0_SI2316 +FSLS0_SX156 +FSLS0_SX202 +FSLS0_SX246 +FSLS0_SX426 +FSLS0_SX66 +FSMA0_SI1621 +FSMA0_SI2251 +FSMA0_SI991 +FSMA0_SX181 +FSMA0_SX271 +FSMA0_SX361 +FSMA0_SX451 +FSMA0_SX91 +FSMM0_SI1314 +FSMM0_SI1944 +FSMM0_SI684 +FSMM0_SX144 +FSMM0_SX234 +FSMM0_SX324 +FSMM0_SX414 +FSMM0_SX54 +FSMS1_SI1504 +FSMS1_SI2134 +FSMS1_SI874 +FSMS1_SX154 +FSMS1_SX244 +FSMS1_SX334 +FSMS1_SX347 +FSMS1_SX64 +FSPM0_SI1241 +FSPM0_SI1871 +FSPM0_SI611 +FSPM0_SX161 +FSPM0_SX251 +FSPM0_SX341 +FSPM0_SX431 +FSPM0_SX71 +FSRH0_SI1719 +FSRH0_SI1931 +FSRH0_SI671 +FSRH0_SX131 +FSRH0_SX221 +FSRH0_SX311 +FSRH0_SX401 +FSRH0_SX41 +FSSB0_SI1082 +FSSB0_SI1712 +FSSB0_SI2342 +FSSB0_SX182 +FSSB0_SX272 +FSSB0_SX362 +FSSB0_SX452 +FSSB0_SX92 +FTAJ0_SI1329 +FTAJ0_SI474 +FTAJ0_SI699 +FTAJ0_SX159 +FTAJ0_SX249 +FTAJ0_SX339 +FTAJ0_SX429 +FTAJ0_SX69 +FTBR0_SI1402 +FTBR0_SI2181 +FTBR0_SI921 +FTBR0_SX111 +FTBR0_SX201 +FTBR0_SX21 +FTBR0_SX291 +FTBR0_SX381 +FTBW0_SI1345 +FTBW0_SI1975 +FTBW0_SI715 +FTBW0_SX175 +FTBW0_SX265 +FTBW0_SX355 +FTBW0_SX445 +FTBW0_SX85 +FTLG0_SI1743 +FTLG0_SI483 +FTLG0_SI840 +FTLG0_SX123 +FTLG0_SX213 +FTLG0_SX303 +FTLG0_SX33 +FTLG0_SX393 +FTMG0_SI1532 +FTMG0_SI2162 +FTMG0_SI902 +FTMG0_SX182 +FTMG0_SX272 +FTMG0_SX362 +FTMG0_SX452 +FTMG0_SX92 +FVFB0_SI1032 +FVFB0_SI1510 +FVFB0_SI2292 +FVFB0_SX132 +FVFB0_SX222 +FVFB0_SX312 +FVFB0_SX402 +FVFB0_SX42 +FVKB0_SI1159 +FVKB0_SI1789 +FVKB0_SI529 +FVKB0_SX169 +FVKB0_SX259 +FVKB0_SX349 +FVKB0_SX439 +FVKB0_SX79 +FVMH0_SI1466 +FVMH0_SI2096 +FVMH0_SI836 +FVMH0_SX116 +FVMH0_SX206 +FVMH0_SX26 +FVMH0_SX296 +FVMH0_SX386 +MABC0_SI1620 +MABC0_SI2041 +MABC0_SI781 +MABC0_SX151 +MABC0_SX241 +MABC0_SX331 +MABC0_SX421 +MABC0_SX61 +MADC0_SI1367 +MADC0_SI1997 +MADC0_SI737 +MADC0_SX107 +MADC0_SX17 +MADC0_SX197 +MADC0_SX287 +MADC0_SX377 +MADD0_SI1295 +MADD0_SI1798 +MADD0_SI538 +MADD0_SX178 +MADD0_SX268 +MADD0_SX358 +MADD0_SX448 +MADD0_SX88 +MAEB0_SI1411 +MAEB0_SI2250 +MAEB0_SI990 +MAEB0_SX180 +MAEB0_SX270 +MAEB0_SX360 +MAEB0_SX450 +MAEB0_SX90 +MAEO0_SI1326 +MAEO0_SI1655 +MAEO0_SI1956 +MAEO0_SX156 +MAEO0_SX246 +MAEO0_SX336 +MAEO0_SX426 +MAEO0_SX66 +MAFM0_SI1569 +MAFM0_SI2199 +MAFM0_SI939 +MAFM0_SX129 +MAFM0_SX219 +MAFM0_SX309 +MAFM0_SX39 +MAFM0_SX399 +MAJP0_SI1074 +MAJP0_SI1704 +MAJP0_SI2334 +MAJP0_SX174 +MAJP0_SX264 +MAJP0_SX354 +MAJP0_SX444 +MAJP0_SX84 +MAKB0_SI1016 +MAKB0_SI1646 +MAKB0_SI2276 +MAKB0_SX116 +MAKB0_SX206 +MAKB0_SX26 +MAKB0_SX296 +MAKB0_SX386 +MAKR0_SI1352 +MAKR0_SI1982 +MAKR0_SI722 +MAKR0_SX182 +MAKR0_SX272 +MAKR0_SX362 +MAKR0_SX452 +MAKR0_SX92 +MAPV0_SI1293 +MAPV0_SI1923 +MAPV0_SI663 +MAPV0_SX123 +MAPV0_SX213 +MAPV0_SX303 +MAPV0_SX33 +MAPV0_SX393 +MARC0_SI1188 +MARC0_SI1818 +MARC0_SI558 +MARC0_SX108 +MARC0_SX18 +MARC0_SX198 +MARC0_SX288 +MARC0_SX378 +MARW0_SI1276 +MARW0_SI1906 +MARW0_SI646 +MARW0_SX106 +MARW0_SX16 +MARW0_SX286 +MARW0_SX349 +MARW0_SX376 +MBAR0_SI1319 +MBAR0_SI1949 +MBAR0_SI689 +MBAR0_SX149 +MBAR0_SX239 +MBAR0_SX329 +MBAR0_SX419 +MBAR0_SX59 +MBBR0_SI1055 +MBBR0_SI1685 +MBBR0_SI2315 +MBBR0_SX155 +MBBR0_SX245 +MBBR0_SX335 +MBBR0_SX425 +MBBR0_SX65 +MBCG0_SI2217 +MBCG0_SI486 +MBCG0_SI957 +MBCG0_SX147 +MBCG0_SX237 +MBCG0_SX327 +MBCG0_SX417 +MBCG0_SX57 +MBEF0_SI1281 +MBEF0_SI1911 +MBEF0_SI651 +MBEF0_SX111 +MBEF0_SX201 +MBEF0_SX21 +MBEF0_SX291 +MBEF0_SX381 +MBGT0_SI1341 +MBGT0_SI1841 +MBGT0_SI711 +MBGT0_SX171 +MBGT0_SX261 +MBGT0_SX351 +MBGT0_SX441 +MBGT0_SX81 +MBJV0_SI1247 +MBJV0_SI1877 +MBJV0_SI617 +MBJV0_SX167 +MBJV0_SX257 +MBJV0_SX347 +MBJV0_SX437 +MBJV0_SX77 +MBMA0_SI1222 +MBMA0_SI1852 +MBMA0_SI592 +MBMA0_SX142 +MBMA0_SX232 +MBMA0_SX322 +MBMA0_SX412 +MBMA0_SX52 +MBMA1_SI2207 +MBMA1_SI2214 +MBMA1_SI954 +MBMA1_SX144 +MBMA1_SX234 +MBMA1_SX324 +MBMA1_SX414 +MBMA1_SX54 +MBML0_SI1169 +MBML0_SI1799 +MBML0_SI539 +MBML0_SX179 +MBML0_SX269 +MBML0_SX359 +MBML0_SX449 +MBML0_SX89 +MBOM0_SI1014 +MBOM0_SI1644 +MBOM0_SI2274 +MBOM0_SX114 +MBOM0_SX204 +MBOM0_SX294 +MBOM0_SX311 +MBOM0_SX384 +MBSB0_SI1353 +MBSB0_SI1983 +MBSB0_SI723 +MBSB0_SX183 +MBSB0_SX273 +MBSB0_SX3 +MBSB0_SX363 +MBSB0_SX93 +MBTH0_SI2102 +MBTH0_SI505 +MBTH0_SI757 +MBTH0_SX122 +MBTH0_SX212 +MBTH0_SX302 +MBTH0_SX32 +MBTH0_SX392 +MBWP0_SI1531 +MBWP0_SI1969 +MBWP0_SI709 +MBWP0_SX169 +MBWP0_SX259 +MBWP0_SX349 +MBWP0_SX439 +MBWP0_SX79 +MCAE0_SI1447 +MCAE0_SI2077 +MCAE0_SI817 +MCAE0_SX187 +MCAE0_SX277 +MCAE0_SX367 +MCAE0_SX7 +MCAE0_SX97 +MCAL0_SI1138 +MCAL0_SI1768 +MCAL0_SI508 +MCAL0_SX148 +MCAL0_SX238 +MCAL0_SX328 +MCAL0_SX418 +MCAL0_SX58 +MCDC0_SI1292 +MCDC0_SI1922 +MCDC0_SI662 +MCDC0_SX122 +MCDC0_SX212 +MCDC0_SX302 +MCDC0_SX32 +MCDC0_SX392 +MCDD0_SI1513 +MCDD0_SI2143 +MCDD0_SI883 +MCDD0_SX163 +MCDD0_SX253 +MCDD0_SX343 +MCDD0_SX433 +MCDD0_SX73 +MCDR0_SI1154 +MCDR0_SI1784 +MCDR0_SI524 +MCDR0_SX164 +MCDR0_SX254 +MCDR0_SX344 +MCDR0_SX434 +MCDR0_SX74 +MCEF0_SI1135 +MCEF0_SI1765 +MCEF0_SI842 +MCEF0_SX145 +MCEF0_SX235 +MCEF0_SX325 +MCEF0_SX415 +MCEF0_SX55 +MCEW0_SI1442 +MCEW0_SI2072 +MCEW0_SI812 +MCEW0_SX182 +MCEW0_SX272 +MCEW0_SX362 +MCEW0_SX452 +MCEW0_SX92 +MCHL0_SI1347 +MCHL0_SI1404 +MCHL0_SI1977 +MCHL0_SX177 +MCHL0_SX267 +MCHL0_SX357 +MCHL0_SX447 +MCHL0_SX87 +MCLK0_SI1660 +MCLK0_SI2290 +MCLK0_SI650 +MCLK0_SX130 +MCLK0_SX220 +MCLK0_SX310 +MCLK0_SX40 +MCLK0_SX400 +MCLM0_SI1456 +MCLM0_SI2086 +MCLM0_SI826 +MCLM0_SX106 +MCLM0_SX16 +MCLM0_SX196 +MCLM0_SX286 +MCLM0_SX376 +MCPM0_SI1194 +MCPM0_SI1824 +MCPM0_SI564 +MCPM0_SX114 +MCPM0_SX204 +MCPM0_SX24 +MCPM0_SX294 +MCPM0_SX384 +MCRE0_SI1121 +MCRE0_SI1725 +MCRE0_SI1751 +MCRE0_SX131 +MCRE0_SX221 +MCRE0_SX24 +MCRE0_SX401 +MCRE0_SX41 +MCSS0_SI1380 +MCSS0_SI688 +MCSS0_SI750 +MCSS0_SX120 +MCSS0_SX210 +MCSS0_SX30 +MCSS0_SX300 +MCSS0_SX390 +MCTH0_SI1209 +MCTH0_SI1839 +MCTH0_SI579 +MCTH0_SX129 +MCTH0_SX219 +MCTH0_SX309 +MCTH0_SX39 +MCTH0_SX399 +MCTM0_SI1350 +MCTM0_SI1980 +MCTM0_SI720 +MCTM0_SX180 +MCTM0_SX270 +MCTM0_SX360 +MCTM0_SX450 +MCTM0_SX90 +MCXM0_SI1351 +MCXM0_SI1981 +MCXM0_SI721 +MCXM0_SX181 +MCXM0_SX271 +MCXM0_SX361 +MCXM0_SX451 +MCXM0_SX91 +MDAC0_SI1261 +MDAC0_SI1837 +MDAC0_SI631 +MDAC0_SX181 +MDAC0_SX271 +MDAC0_SX361 +MDAC0_SX451 +MDAC0_SX91 +MDAS0_SI1266 +MDAS0_SI1896 +MDAS0_SI636 +MDAS0_SX186 +MDAS0_SX21 +MDAS0_SX276 +MDAS0_SX6 +MDAS0_SX96 +MDBB1_SI1006 +MDBB1_SI1636 +MDBB1_SI2056 +MDBB1_SX106 +MDBB1_SX16 +MDBB1_SX196 +MDBB1_SX286 +MDBB1_SX376 +MDBP0_SI1158 +MDBP0_SI1788 +MDBP0_SI528 +MDBP0_SX168 +MDBP0_SX258 +MDBP0_SX348 +MDBP0_SX438 +MDBP0_SX78 +MDCD0_SI1415 +MDCD0_SI2045 +MDCD0_SI785 +MDCD0_SX155 +MDCD0_SX245 +MDCD0_SX335 +MDCD0_SX425 +MDCD0_SX65 +MDCM0_SI1480 +MDCM0_SI2110 +MDCM0_SI850 +MDCM0_SX130 +MDCM0_SX220 +MDCM0_SX310 +MDCM0_SX40 +MDCM0_SX400 +MDDC0_SI1419 +MDDC0_SI2049 +MDDC0_SI789 +MDDC0_SX159 +MDDC0_SX249 +MDDC0_SX339 +MDDC0_SX429 +MDDC0_SX69 +MDED0_SI1170 +MDED0_SI1800 +MDED0_SI540 +MDED0_SX180 +MDED0_SX270 +MDED0_SX360 +MDED0_SX450 +MDED0_SX90 +MDEF0_SI1123 +MDEF0_SI1563 +MDEF0_SI2193 +MDEF0_SX123 +MDEF0_SX213 +MDEF0_SX303 +MDEF0_SX33 +MDEF0_SX393 +MDEM0_SI1868 +MDEM0_SI608 +MDEM0_SI800 +MDEM0_SX158 +MDEM0_SX248 +MDEM0_SX338 +MDEM0_SX428 +MDEM0_SX68 +MDHL0_SI1439 +MDHL0_SI2069 +MDHL0_SI809 +MDHL0_SX179 +MDHL0_SX269 +MDHL0_SX359 +MDHL0_SX449 +MDHL0_SX89 +MDHS0_SI1530 +MDHS0_SI2160 +MDHS0_SI900 +MDHS0_SX180 +MDHS0_SX270 +MDHS0_SX360 +MDHS0_SX450 +MDHS0_SX90 +MDJM0_SI1455 +MDJM0_SI2085 +MDJM0_SI825 +MDJM0_SX105 +MDJM0_SX15 +MDJM0_SX195 +MDJM0_SX285 +MDJM0_SX375 +MDKS0_SI1066 +MDKS0_SI1696 +MDKS0_SI2326 +MDKS0_SX166 +MDKS0_SX256 +MDKS0_SX346 +MDKS0_SX436 +MDKS0_SX76 +MDLB0_SI1306 +MDLB0_SI1936 +MDLB0_SI676 +MDLB0_SX136 +MDLB0_SX226 +MDLB0_SX316 +MDLB0_SX406 +MDLB0_SX46 +MDLC0_SI1395 +MDLC0_SI2025 +MDLC0_SI765 +MDLC0_SX135 +MDLC0_SX225 +MDLC0_SX315 +MDLC0_SX405 +MDLC0_SX45 +MDLC1_SI1435 +MDLC1_SI2065 +MDLC1_SI2144 +MDLC1_SX175 +MDLC1_SX265 +MDLC1_SX355 +MDLC1_SX445 +MDLC1_SX85 +MDLC2_SI1614 +MDLC2_SI2244 +MDLC2_SI984 +MDLC2_SX174 +MDLC2_SX264 +MDLC2_SX354 +MDLC2_SX444 +MDLC2_SX84 +MDLH0_SI1960 +MDLH0_SI574 +MDLH0_SI700 +MDLH0_SX160 +MDLH0_SX250 +MDLH0_SX340 +MDLH0_SX430 +MDLH0_SX70 +MDLM0_SI1234 +MDLM0_SI1864 +MDLM0_SI604 +MDLM0_SX154 +MDLM0_SX244 +MDLM0_SX334 +MDLM0_SX424 +MDLM0_SX64 +MDLR0_SI1233 +MDLR0_SI1863 +MDLR0_SI603 +MDLR0_SX153 +MDLR0_SX243 +MDLR0_SX333 +MDLR0_SX423 +MDLR0_SX63 +MDLR1_SI1299 +MDLR1_SI1929 +MDLR1_SI669 +MDLR1_SX129 +MDLR1_SX219 +MDLR1_SX309 +MDLR1_SX39 +MDLR1_SX399 +MDMA0_SI1238 +MDMA0_SI1430 +MDMA0_SI2060 +MDMA0_SX170 +MDMA0_SX260 +MDMA0_SX350 +MDMA0_SX440 +MDMA0_SX80 +MDMT0_SI1832 +MDMT0_SI2341 +MDMT0_SI572 +MDMT0_SX122 +MDMT0_SX212 +MDMT0_SX302 +MDMT0_SX32 +MDMT0_SX392 +MDNS0_SI1011 +MDNS0_SI2271 +MDNS0_SI873 +MDNS0_SX111 +MDNS0_SX201 +MDNS0_SX21 +MDNS0_SX291 +MDNS0_SX381 +MDPB0_SI1760 +MDPB0_SI2126 +MDPB0_SI866 +MDPB0_SX146 +MDPB0_SX236 +MDPB0_SX326 +MDPB0_SX416 +MDPB0_SX56 +MDPK0_SI1053 +MDPK0_SI1683 +MDPK0_SI552 +MDPK0_SX153 +MDPK0_SX243 +MDPK0_SX333 +MDPK0_SX423 +MDPK0_SX63 +MDPS0_SI1651 +MDPS0_SI1979 +MDPS0_SI719 +MDPS0_SX179 +MDPS0_SX269 +MDPS0_SX359 +MDPS0_SX449 +MDPS0_SX89 +MDRD0_SI1382 +MDRD0_SI2012 +MDRD0_SI752 +MDRD0_SX122 +MDRD0_SX212 +MDRD0_SX302 +MDRD0_SX32 +MDRD0_SX392 +MDSJ0_SI1462 +MDSJ0_SI2092 +MDSJ0_SI832 +MDSJ0_SX112 +MDSJ0_SX22 +MDSJ0_SX292 +MDSJ0_SX382 +MDSJ0_SX438 +MDSS0_SI1881 +MDSS0_SI2087 +MDSS0_SI621 +MDSS0_SX171 +MDSS0_SX261 +MDSS0_SX351 +MDSS0_SX441 +MDSS0_SX81 +MDSS1_SI1327 +MDSS1_SI1713 +MDSS1_SI697 +MDSS1_SX157 +MDSS1_SX247 +MDSS1_SX337 +MDSS1_SX427 +MDSS1_SX67 +MDTB0_SI1200 +MDTB0_SI1830 +MDTB0_SI570 +MDTB0_SX120 +MDTB0_SX210 +MDTB0_SX300 +MDTB0_SX321 +MDTB0_SX390 +MDWD0_SI1260 +MDWD0_SI1890 +MDWD0_SI557 +MDWD0_SX180 +MDWD0_SX270 +MDWD0_SX360 +MDWD0_SX450 +MDWD0_SX90 +MDWH0_SI1168 +MDWH0_SI1925 +MDWH0_SI665 +MDWH0_SX125 +MDWH0_SX215 +MDWH0_SX305 +MDWH0_SX35 +MDWH0_SX395 +MDWM0_SI1546 +MDWM0_SI2176 +MDWM0_SI916 +MDWM0_SX106 +MDWM0_SX16 +MDWM0_SX286 +MDWM0_SX376 +MDWM0_SX433 +MEAL0_SI1547 +MEAL0_SI2177 +MEAL0_SI917 +MEAL0_SX107 +MEAL0_SX197 +MEAL0_SX287 +MEAL0_SX347 +MEAL0_SX377 +MEDR0_SI1374 +MEDR0_SI2004 +MEDR0_SI744 +MEDR0_SX114 +MEDR0_SX204 +MEDR0_SX24 +MEDR0_SX294 +MEDR0_SX384 +MEFG0_SI465 +MEFG0_SI491 +MEFG0_SI598 +MEFG0_SX105 +MEFG0_SX15 +MEFG0_SX195 +MEFG0_SX285 +MEFG0_SX375 +MEGJ0_SI1337 +MEGJ0_SI1967 +MEGJ0_SI707 +MEGJ0_SX167 +MEGJ0_SX257 +MEGJ0_SX3 +MEGJ0_SX437 +MEGJ0_SX77 +MEJL0_SI1592 +MEJL0_SI1654 +MEJL0_SI962 +MEJL0_SX152 +MEJL0_SX242 +MEJL0_SX332 +MEJL0_SX422 +MEJL0_SX62 +MEJS0_SI1240 +MEJS0_SI1870 +MEJS0_SI610 +MEJS0_SX160 +MEJS0_SX250 +MEJS0_SX340 +MEJS0_SX430 +MEJS0_SX70 +MESG0_SI1332 +MESG0_SI1962 +MESG0_SI702 +MESG0_SX162 +MESG0_SX252 +MESG0_SX342 +MESG0_SX432 +MESG0_SX72 +MESJ0_SI2039 +MESJ0_SI2257 +MESJ0_SI997 +MESJ0_SX187 +MESJ0_SX277 +MESJ0_SX367 +MESJ0_SX7 +MESJ0_SX97 +MEWM0_SI1348 +MEWM0_SI1978 +MEWM0_SI718 +MEWM0_SX178 +MEWM0_SX268 +MEWM0_SX358 +MEWM0_SX448 +MEWM0_SX88 +MFER0_SI1492 +MFER0_SI2122 +MFER0_SI862 +MFER0_SX142 +MFER0_SX232 +MFER0_SX322 +MFER0_SX412 +MFER0_SX52 +MFMC0_SI1132 +MFMC0_SI1762 +MFMC0_SI502 +MFMC0_SX142 +MFMC0_SX232 +MFMC0_SX322 +MFMC0_SX412 +MFMC0_SX52 +MFRM0_SI1155 +MFRM0_SI1717 +MFRM0_SI1785 +MFRM0_SX165 +MFRM0_SX255 +MFRM0_SX345 +MFRM0_SX435 +MFRM0_SX75 +MFWK0_SI1249 +MFWK0_SI1879 +MFWK0_SI619 +MFWK0_SX169 +MFWK0_SX259 +MFWK0_SX349 +MFWK0_SX439 +MFWK0_SX79 +MFXS0_SI1674 +MFXS0_SI2225 +MFXS0_SI2304 +MFXS0_SX144 +MFXS0_SX234 +MFXS0_SX324 +MFXS0_SX414 +MFXS0_SX54 +MFXV0_SI1005 +MFXV0_SI1342 +MFXV0_SI1635 +MFXV0_SX105 +MFXV0_SX15 +MFXV0_SX195 +MFXV0_SX285 +MFXV0_SX375 +MGAF0_SI1282 +MGAF0_SI1912 +MGAF0_SI652 +MGAF0_SX112 +MGAF0_SX202 +MGAF0_SX22 +MGAF0_SX292 +MGAF0_SX382 +MGAG0_SI1321 +MGAG0_SI645 +MGAG0_SI691 +MGAG0_SX151 +MGAG0_SX241 +MGAG0_SX331 +MGAG0_SX421 +MGAG0_SX61 +MGAK0_SI1036 +MGAK0_SI1666 +MGAK0_SI2296 +MGAK0_SX136 +MGAK0_SX226 +MGAK0_SX316 +MGAK0_SX406 +MGAK0_SX46 +MGAR0_SI1212 +MGAR0_SI1694 +MGAR0_SI1842 +MGAR0_SX132 +MGAR0_SX222 +MGAR0_SX312 +MGAR0_SX402 +MGAR0_SX42 +MGAW0_SI1165 +MGAW0_SI1802 +MGAW0_SI535 +MGAW0_SX175 +MGAW0_SX265 +MGAW0_SX355 +MGAW0_SX445 +MGAW0_SX85 +MGES0_SI1481 +MGES0_SI2111 +MGES0_SI851 +MGES0_SX131 +MGES0_SX221 +MGES0_SX311 +MGES0_SX401 +MGES0_SX41 +MGJC0_SI1256 +MGJC0_SI1335 +MGJC0_SI1965 +MGJC0_SX165 +MGJC0_SX255 +MGJC0_SX345 +MGJC0_SX435 +MGJC0_SX75 +MGRL0_SI1497 +MGRL0_SI2127 +MGRL0_SI867 +MGRL0_SX147 +MGRL0_SX237 +MGRL0_SX327 +MGRL0_SX417 +MGRL0_SX57 +MGRP0_SI1317 +MGRP0_SI1947 +MGRP0_SI687 +MGRP0_SX147 +MGRP0_SX237 +MGRP0_SX327 +MGRP0_SX417 +MGRP0_SX57 +MGSH0_SI1176 +MGSH0_SI1806 +MGSH0_SI546 +MGSH0_SX127 +MGSH0_SX186 +MGSH0_SX276 +MGSH0_SX6 +MGSH0_SX96 +MGSL0_SI1164 +MGSL0_SI534 +MGSL0_SI797 +MGSL0_SX174 +MGSL0_SX264 +MGSL0_SX354 +MGSL0_SX444 +MGSL0_SX84 +MGXP0_SI1087 +MGXP0_SI457 +MGXP0_SI525 +MGXP0_SX187 +MGXP0_SX277 +MGXP0_SX367 +MGXP0_SX7 +MGXP0_SX97 +MHBS0_SI1575 +MHBS0_SI2205 +MHBS0_SI945 +MHBS0_SX135 +MHBS0_SX225 +MHBS0_SX315 +MHBS0_SX405 +MHBS0_SX45 +MHIT0_SI1613 +MHIT0_SI2243 +MHIT0_SI983 +MHIT0_SX173 +MHIT0_SX263 +MHIT0_SX353 +MHIT0_SX443 +MHIT0_SX83 +MHJB0_SI1017 +MHJB0_SI1647 +MHJB0_SI2277 +MHJB0_SX117 +MHJB0_SX207 +MHJB0_SX27 +MHJB0_SX297 +MHJB0_SX387 +MHMG0_SI1365 +MHMG0_SI1995 +MHMG0_SI735 +MHMG0_SX105 +MHMG0_SX15 +MHMG0_SX195 +MHMG0_SX285 +MHMG0_SX375 +MHMR0_SI1119 +MHMR0_SI1692 +MHMR0_SI489 +MHMR0_SX129 +MHMR0_SX219 +MHMR0_SX309 +MHMR0_SX39 +MHMR0_SX399 +MHRM0_SI1475 +MHRM0_SI2218 +MHRM0_SI958 +MHRM0_SX148 +MHRM0_SX238 +MHRM0_SX328 +MHRM0_SX418 +MHRM0_SX58 +MHXL0_SI1772 +MHXL0_SI512 +MHXL0_SI612 +MHXL0_SX152 +MHXL0_SX242 +MHXL0_SX332 +MHXL0_SX422 +MHXL0_SX62 +MILB0_SI2163 +MILB0_SI807 +MILB0_SI903 +MILB0_SX183 +MILB0_SX273 +MILB0_SX3 +MILB0_SX363 +MILB0_SX93 +MJAC0_SI1331 +MJAC0_SI2148 +MJAC0_SI701 +MJAC0_SX251 +MJAC0_SX307 +MJAC0_SX341 +MJAC0_SX431 +MJAC0_SX71 +MJAE0_SI1524 +MJAE0_SI1999 +MJAE0_SI2154 +MJAE0_SX174 +MJAE0_SX264 +MJAE0_SX354 +MJAE0_SX444 +MJAE0_SX84 +MJAI0_SI1604 +MJAI0_SI682 +MJAI0_SI710 +MJAI0_SX164 +MJAI0_SX254 +MJAI0_SX344 +MJAI0_SX434 +MJAI0_SX74 +MJBG0_SI1232 +MJBG0_SI1724 +MJBG0_SI1862 +MJBG0_SX152 +MJBG0_SX242 +MJBG0_SX332 +MJBG0_SX422 +MJBG0_SX62 +MJDA0_SI1031 +MJDA0_SI1661 +MJDA0_SI2291 +MJDA0_SX131 +MJDA0_SX221 +MJDA0_SX311 +MJDA0_SX401 +MJDA0_SX41 +MJDC0_SI1161 +MJDC0_SI2165 +MJDC0_SI531 +MJDC0_SX171 +MJDC0_SX261 +MJDC0_SX351 +MJDC0_SX441 +MJDC0_SX81 +MJDE0_SI1120 +MJDE0_SI463 +MJDE0_SI490 +MJDE0_SX130 +MJDE0_SX220 +MJDE0_SX310 +MJDE0_SX40 +MJDE0_SX400 +MJDG0_SI1042 +MJDG0_SI1672 +MJDG0_SI1705 +MJDG0_SX142 +MJDG0_SX232 +MJDG0_SX322 +MJDG0_SX412 +MJDG0_SX52 +MJDM0_SI1340 +MJDM0_SI1937 +MJDM0_SI974 +MJDM0_SX170 +MJDM0_SX260 +MJDM0_SX350 +MJDM0_SX440 +MJDM0_SX80 +MJEB0_SI1286 +MJEB0_SI1916 +MJEB0_SI656 +MJEB0_SX170 +MJEB0_SX206 +MJEB0_SX26 +MJEB0_SX296 +MJEB0_SX386 +MJEB1_SI1467 +MJEB1_SI2097 +MJEB1_SI837 +MJEB1_SX117 +MJEB1_SX207 +MJEB1_SX27 +MJEB1_SX297 +MJEB1_SX387 +MJEE0_SI1237 +MJEE0_SI1867 +MJEE0_SI607 +MJEE0_SX157 +MJEE0_SX247 +MJEE0_SX337 +MJEE0_SX427 +MJEE0_SX67 +MJFH0_SI1107 +MJFH0_SI1737 +MJFH0_SI477 +MJFH0_SX117 +MJFH0_SX207 +MJFH0_SX27 +MJFH0_SX297 +MJFH0_SX387 +MJFR0_SI1605 +MJFR0_SI2235 +MJFR0_SI975 +MJFR0_SX165 +MJFR0_SX255 +MJFR0_SX345 +MJFR0_SX435 +MJFR0_SX75 +MJHI0_SI1328 +MJHI0_SI555 +MJHI0_SI698 +MJHI0_SX158 +MJHI0_SX248 +MJHI0_SX338 +MJHI0_SX428 +MJHI0_SX68 +MJJB0_SI1139 +MJJB0_SI1277 +MJJB0_SI1769 +MJJB0_SX149 +MJJB0_SX239 +MJJB0_SX329 +MJJB0_SX419 +MJJB0_SX59 +MJJJ0_SI1163 +MJJJ0_SI1793 +MJJJ0_SI533 +MJJJ0_SX173 +MJJJ0_SX263 +MJJJ0_SX353 +MJJJ0_SX443 +MJJJ0_SX83 +MJJM0_SI1251 +MJJM0_SI1457 +MJJM0_SI827 +MJJM0_SX107 +MJJM0_SX17 +MJJM0_SX197 +MJJM0_SX287 +MJJM0_SX377 +MJKR0_SI1201 +MJKR0_SI1831 +MJKR0_SI571 +MJKR0_SX121 +MJKR0_SX211 +MJKR0_SX301 +MJKR0_SX31 +MJKR0_SX391 +MJLB0_SI1616 +MJLB0_SI2246 +MJLB0_SI986 +MJLB0_SX176 +MJLB0_SX266 +MJLB0_SX356 +MJLB0_SX446 +MJLB0_SX86 +MJLG1_SI1012 +MJLG1_SI1642 +MJLG1_SI2272 +MJLG1_SX112 +MJLG1_SX202 +MJLG1_SX22 +MJLG1_SX292 +MJLG1_SX382 +MJLS0_SI1096 +MJLS0_SI1726 +MJLS0_SI466 +MJLS0_SX106 +MJLS0_SX16 +MJLS0_SX196 +MJLS0_SX286 +MJLS0_SX376 +MJMA0_SI1495 +MJMA0_SI2125 +MJMA0_SI865 +MJMA0_SX145 +MJMA0_SX235 +MJMA0_SX325 +MJMA0_SX415 +MJMA0_SX55 +MJMD0_SI1028 +MJMD0_SI1658 +MJMD0_SI2288 +MJMD0_SX128 +MJMD0_SX218 +MJMD0_SX308 +MJMD0_SX38 +MJMD0_SX398 +MJMM0_SI1255 +MJMM0_SI1885 +MJMM0_SI625 +MJMM0_SX175 +MJMM0_SX265 +MJMM0_SX355 +MJMM0_SX445 +MJMM0_SX85 +MJPG0_SI1191 +MJPG0_SI1821 +MJPG0_SI561 +MJPG0_SX111 +MJPG0_SX201 +MJPG0_SX21 +MJPG0_SX291 +MJPG0_SX381 +MJPM0_SI1368 +MJPM0_SI1998 +MJPM0_SI738 +MJPM0_SX108 +MJPM0_SX18 +MJPM0_SX198 +MJPM0_SX288 +MJPM0_SX378 +MJPM1_SI1897 +MJPM1_SI2280 +MJPM1_SI761 +MJPM1_SX131 +MJPM1_SX221 +MJPM1_SX311 +MJPM1_SX401 +MJPM1_SX41 +MJRA0_SI1236 +MJRA0_SI1866 +MJRA0_SI606 +MJRA0_SX156 +MJRA0_SX246 +MJRA0_SX336 +MJRA0_SX426 +MJRA0_SX66 +MJRG0_SI1366 +MJRG0_SI1996 +MJRG0_SI736 +MJRG0_SX106 +MJRG0_SX16 +MJRG0_SX286 +MJRG0_SX352 +MJRG0_SX376 +MJRH0_SI1125 +MJRH0_SI1755 +MJRH0_SI1840 +MJRH0_SX135 +MJRH0_SX225 +MJRH0_SX315 +MJRH0_SX405 +MJRH0_SX45 +MJRH1_SI1558 +MJRH1_SI1774 +MJRH1_SI514 +MJRH1_SX154 +MJRH1_SX244 +MJRH1_SX334 +MJRH1_SX424 +MJRH1_SX64 +MJRK0_SI1662 +MJRK0_SI2103 +MJRK0_SI880 +MJRK0_SX160 +MJRK0_SX250 +MJRK0_SX340 +MJRK0_SX430 +MJRK0_SX70 +MJRP0_SI1835 +MJRP0_SI1845 +MJRP0_SI585 +MJRP0_SX135 +MJRP0_SX225 +MJRP0_SX315 +MJRP0_SX405 +MJRP0_SX45 +MJSR0_SI1424 +MJSR0_SI2054 +MJSR0_SI794 +MJSR0_SX164 +MJSR0_SX254 +MJSR0_SX344 +MJSR0_SX434 +MJSR0_SX74 +MJWG0_SI2155 +MJWG0_SI813 +MJWG0_SI895 +MJWG0_SX175 +MJWG0_SX265 +MJWG0_SX355 +MJWG0_SX445 +MJWG0_SX85 +MJWS0_SI1143 +MJWS0_SI1773 +MJWS0_SI513 +MJWS0_SX153 +MJWS0_SX243 +MJWS0_SX333 +MJWS0_SX423 +MJWS0_SX63 +MJWT0_SI1291 +MJWT0_SI1381 +MJWT0_SI751 +MJWT0_SX121 +MJWT0_SX211 +MJWT0_SX301 +MJWT0_SX31 +MJWT0_SX391 +MJXA0_SI1507 +MJXA0_SI2137 +MJXA0_SI877 +MJXA0_SX157 +MJXA0_SX247 +MJXA0_SX337 +MJXA0_SX427 +MJXA0_SX67 +MJXL0_SI1172 +MJXL0_SI1795 +MJXL0_SI542 +MJXL0_SX182 +MJXL0_SX272 +MJXL0_SX362 +MJXL0_SX452 +MJXL0_SX92 +MKAG0_SI1609 +MKAG0_SI2239 +MKAG0_SI979 +MKAG0_SX169 +MKAG0_SX259 +MKAG0_SX30 +MKAG0_SX439 +MKAG0_SX79 +MKAH0_SI1528 +MKAH0_SI2158 +MKAH0_SI898 +MKAH0_SX178 +MKAH0_SX268 +MKAH0_SX358 +MKAH0_SX448 +MKAH0_SX88 +MKAJ0_SI1414 +MKAJ0_SI2044 +MKAJ0_SI784 +MKAJ0_SX154 +MKAJ0_SX244 +MKAJ0_SX334 +MKAJ0_SX424 +MKAJ0_SX64 +MKAM0_SI1250 +MKAM0_SI1316 +MKAM0_SI1465 +MKAM0_SX146 +MKAM0_SX236 +MKAM0_SX326 +MKAM0_SX416 +MKAM0_SX56 +MKDB0_SI2132 +MKDB0_SI588 +MKDB0_SI872 +MKDB0_SX152 +MKDB0_SX242 +MKDB0_SX332 +MKDB0_SX422 +MKDB0_SX62 +MKDD0_SI1567 +MKDD0_SI2197 +MKDD0_SI937 +MKDD0_SX127 +MKDD0_SX217 +MKDD0_SX307 +MKDD0_SX37 +MKDD0_SX397 +MKDT0_SI2153 +MKDT0_SI814 +MKDT0_SI893 +MKDT0_SX173 +MKDT0_SX263 +MKDT0_SX353 +MKDT0_SX443 +MKDT0_SX83 +MKES0_SI1253 +MKES0_SI1883 +MKES0_SI623 +MKES0_SX173 +MKES0_SX263 +MKES0_SX353 +MKES0_SX443 +MKES0_SX83 +MKJO0_SI1517 +MKJO0_SI2147 +MKJO0_SI887 +MKJO0_SX167 +MKJO0_SX257 +MKJO0_SX424 +MKJO0_SX437 +MKJO0_SX77 +MKLN0_SI1598 +MKLN0_SI2228 +MKLN0_SI968 +MKLN0_SX158 +MKLN0_SX248 +MKLN0_SX338 +MKLN0_SX428 +MKLN0_SX68 +MKLR0_SI1059 +MKLR0_SI1689 +MKLR0_SI2319 +MKLR0_SX159 +MKLR0_SX249 +MKLR0_SX339 +MKLR0_SX429 +MKLR0_SX69 +MKLS0_SI1437 +MKLS0_SI1533 +MKLS0_SI2067 +MKLS0_SX177 +MKLS0_SX267 +MKLS0_SX357 +MKLS0_SX447 +MKLS0_SX87 +MKLS1_SI1545 +MKLS1_SI2175 +MKLS1_SI915 +MKLS1_SX105 +MKLS1_SX15 +MKLS1_SX195 +MKLS1_SX285 +MKLS1_SX375 +MKLW0_SI1571 +MKLW0_SI1844 +MKLW0_SI2201 +MKLW0_SX131 +MKLW0_SX221 +MKLW0_SX311 +MKLW0_SX401 +MKLW0_SX41 +MKRG0_SI1491 +MKRG0_SI2121 +MKRG0_SI861 +MKRG0_SX141 +MKRG0_SX231 +MKRG0_SX31 +MKRG0_SX411 +MKRG0_SX51 +MKXL0_SI1185 +MKXL0_SI1815 +MKXL0_SI1958 +MKXL0_SX105 +MKXL0_SX15 +MKXL0_SX195 +MKXL0_SX285 +MKXL0_SX375 +MLBC0_SI1239 +MLBC0_SI1869 +MLBC0_SI609 +MLBC0_SX159 +MLBC0_SX249 +MLBC0_SX339 +MLBC0_SX429 +MLBC0_SX69 +MLEL0_SI1246 +MLEL0_SI1876 +MLEL0_SI616 +MLEL0_SX166 +MLEL0_SX256 +MLEL0_SX346 +MLEL0_SX436 +MLEL0_SX76 +MLJC0_SI1225 +MLJC0_SI1855 +MLJC0_SI595 +MLJC0_SX145 +MLJC0_SX235 +MLJC0_SX325 +MLJC0_SX415 +MLJC0_SX55 +MLJH0_SI1324 +MLJH0_SI1422 +MLJH0_SI694 +MLJH0_SX154 +MLJH0_SX244 +MLJH0_SX334 +MLJH0_SX424 +MLJH0_SX64 +MLNS0_SI1407 +MLNS0_SI2037 +MLNS0_SI777 +MLNS0_SX147 +MLNS0_SX237 +MLNS0_SX327 +MLNS0_SX417 +MLNS0_SX57 +MLSH0_SI1417 +MLSH0_SI2047 +MLSH0_SI787 +MLSH0_SX157 +MLSH0_SX247 +MLSH0_SX337 +MLSH0_SX427 +MLSH0_SX67 +MMAA0_SI1588 +MMAA0_SI2105 +MMAA0_SI845 +MMAA0_SX125 +MMAA0_SX215 +MMAA0_SX305 +MMAA0_SX35 +MMAA0_SX395 +MMAB1_SI1494 +MMAB1_SI2124 +MMAB1_SI864 +MMAB1_SX144 +MMAB1_SX234 +MMAB1_SX324 +MMAB1_SX414 +MMAB1_SX54 +MMAG0_SI1126 +MMAG0_SI1756 +MMAG0_SI496 +MMAG0_SX136 +MMAG0_SX226 +MMAG0_SX316 +MMAG0_SX406 +MMAG0_SX46 +MMAM0_SI1597 +MMAM0_SI1668 +MMAM0_SI2227 +MMAM0_SX157 +MMAM0_SX247 +MMAM0_SX337 +MMAM0_SX427 +MMAM0_SX67 +MMAR0_SI1336 +MMAR0_SI1966 +MMAR0_SI706 +MMAR0_SX166 +MMAR0_SX256 +MMAR0_SX346 +MMAR0_SX436 +MMAR0_SX76 +MMBS0_SI1151 +MMBS0_SI1781 +MMBS0_SI521 +MMBS0_SX161 +MMBS0_SX251 +MMBS0_SX341 +MMBS0_SX431 +MMBS0_SX71 +MMCC0_SI1338 +MMCC0_SI1968 +MMCC0_SI708 +MMCC0_SX168 +MMCC0_SX258 +MMCC0_SX348 +MMCC0_SX438 +MMCC0_SX78 +MMDB0_SI1358 +MMDB0_SI1617 +MMDB0_SI987 +MMDB0_SX177 +MMDB0_SX267 +MMDB0_SX357 +MMDB0_SX447 +MMDB0_SX87 +MMDG0_SI1780 +MMDG0_SI2035 +MMDG0_SI520 +MMDG0_SX160 +MMDG0_SX250 +MMDG0_SX340 +MMDG0_SX430 +MMDG0_SX70 +MMDM0_SI1311 +MMDM0_SI1941 +MMDM0_SI681 +MMDM0_SX141 +MMDM0_SX231 +MMDM0_SX321 +MMDM0_SX411 +MMDM0_SX51 +MMDM1_SI1650 +MMDM1_SI2043 +MMDM1_SI783 +MMDM1_SX153 +MMDM1_SX243 +MMDM1_SX333 +MMDM1_SX423 +MMDM1_SX63 +MMDS0_SI1343 +MMDS0_SI1973 +MMDS0_SI713 +MMDS0_SX173 +MMDS0_SX263 +MMDS0_SX353 +MMDS0_SX443 +MMDS0_SX83 +MMEA0_SI1388 +MMEA0_SI2018 +MMEA0_SI758 +MMEA0_SX128 +MMEA0_SX218 +MMEA0_SX308 +MMEA0_SX38 +MMEA0_SX398 +MMEB0_SI1357 +MMEB0_SI1987 +MMEB0_SI727 +MMEB0_SX187 +MMEB0_SX327 +MMEB0_SX367 +MMEB0_SX7 +MMEB0_SX97 +MMGC0_SI1305 +MMGC0_SI1935 +MMGC0_SI2184 +MMGC0_SX135 +MMGC0_SX225 +MMGC0_SX315 +MMGC0_SX405 +MMGC0_SX45 +MMGG0_SI1079 +MMGG0_SI1709 +MMGG0_SI2339 +MMGG0_SX179 +MMGG0_SX269 +MMGG0_SX359 +MMGG0_SX449 +MMGG0_SX89 +MMGK0_SI1322 +MMGK0_SI1952 +MMGK0_SI692 +MMGK0_SX152 +MMGK0_SX242 +MMGK0_SX332 +MMGK0_SX422 +MMGK0_SX62 +MMJB1_SI1408 +MMJB1_SI2038 +MMJB1_SI778 +MMJB1_SX148 +MMJB1_SX238 +MMJB1_SX328 +MMJB1_SX418 +MMJB1_SX58 +MMLM0_SI1527 +MMLM0_SI2150 +MMLM0_SI897 +MMLM0_SX177 +MMLM0_SX267 +MMLM0_SX357 +MMLM0_SX447 +MMLM0_SX87 +MMPM0_SI1061 +MMPM0_SI1691 +MMPM0_SI2321 +MMPM0_SX161 +MMPM0_SX251 +MMPM0_SX341 +MMPM0_SX431 +MMPM0_SX71 +MMRP0_SI2034 +MMRP0_SI717 +MMRP0_SI774 +MMRP0_SX144 +MMRP0_SX234 +MMRP0_SX324 +MMRP0_SX414 +MMRP0_SX54 +MMSM0_SI1106 +MMSM0_SI1736 +MMSM0_SI476 +MMSM0_SX116 +MMSM0_SX206 +MMSM0_SX26 +MMSM0_SX296 +MMSM0_SX386 +MMVP0_SI1284 +MMVP0_SI1914 +MMVP0_SI654 +MMVP0_SX114 +MMVP0_SX204 +MMVP0_SX294 +MMVP0_SX347 +MMVP0_SX384 +MMWB0_SI1619 +MMWB0_SI2249 +MMWB0_SI989 +MMWB0_SX179 +MMWB0_SX269 +MMWB0_SX359 +MMWB0_SX449 +MMWB0_SX89 +MMWS0_SI1518 +MMWS0_SI559 +MMWS0_SI888 +MMWS0_SX168 +MMWS0_SX258 +MMWS0_SX348 +MMWS0_SX438 +MMWS0_SX78 +MMWS1_SI1071 +MMWS1_SI1701 +MMWS1_SI2331 +MMWS1_SX261 +MMWS1_SX27 +MMWS1_SX351 +MMWS1_SX441 +MMWS1_SX81 +MMXS0_SI2136 +MMXS0_SI629 +MMXS0_SI876 +MMXS0_SX156 +MMXS0_SX246 +MMXS0_SX336 +MMXS0_SX426 +MMXS0_SX66 +MNET0_SI1446 +MNET0_SI2076 +MNET0_SI816 +MNET0_SX186 +MNET0_SX276 +MNET0_SX366 +MNET0_SX6 +MNET0_SX96 +MNTW0_SI1068 +MNTW0_SI1698 +MNTW0_SI2328 +MNTW0_SX168 +MNTW0_SX202 +MNTW0_SX258 +MNTW0_SX348 +MNTW0_SX78 +MPAR0_SI1576 +MPAR0_SI2206 +MPAR0_SI946 +MPAR0_SX136 +MPAR0_SX226 +MPAR0_SX316 +MPAR0_SX406 +MPAR0_SX46 +MPEB0_SI1034 +MPEB0_SI1860 +MPEB0_SI600 +MPEB0_SX150 +MPEB0_SX240 +MPEB0_SX330 +MPEB0_SX420 +MPEB0_SX60 +MPFU0_SI1258 +MPFU0_SI1888 +MPFU0_SI628 +MPFU0_SX178 +MPFU0_SX268 +MPFU0_SX358 +MPFU0_SX448 +MPFU0_SX88 +MPGH0_SI1554 +MPGH0_SI675 +MPGH0_SI924 +MPGH0_SX114 +MPGH0_SX204 +MPGH0_SX24 +MPGH0_SX294 +MPGH0_SX384 +MPGR0_SI1410 +MPGR0_SI2040 +MPGR0_SI780 +MPGR0_SX150 +MPGR0_SX240 +MPGR0_SX330 +MPGR0_SX420 +MPGR0_SX60 +MPGR1_SI1269 +MPGR1_SI1499 +MPGR1_SI2129 +MPGR1_SX149 +MPGR1_SX239 +MPGR1_SX329 +MPGR1_SX419 +MPGR1_SX59 +MPMB0_SI1501 +MPMB0_SI2131 +MPMB0_SI871 +MPMB0_SX151 +MPMB0_SX241 +MPMB0_SX331 +MPMB0_SX421 +MPMB0_SX61 +MPPC0_SI1412 +MPPC0_SI2042 +MPPC0_SI782 +MPPC0_SX152 +MPPC0_SX242 +MPPC0_SX332 +MPPC0_SX422 +MPPC0_SX62 +MPRB0_SI1205 +MPRB0_SI1215 +MPRB0_SI575 +MPRB0_SX125 +MPRB0_SX215 +MPRB0_SX305 +MPRB0_SX35 +MPRB0_SX395 +MPRD0_SI1431 +MPRD0_SI2061 +MPRD0_SI801 +MPRD0_SX171 +MPRD0_SX261 +MPRD0_SX351 +MPRD0_SX441 +MPRD0_SX81 +MPRK0_SI1097 +MPRK0_SI1727 +MPRK0_SI467 +MPRK0_SX107 +MPRK0_SX17 +MPRK0_SX197 +MPRK0_SX287 +MPRK0_SX377 +MPRT0_SI1210 +MPRT0_SI495 +MPRT0_SI580 +MPRT0_SX130 +MPRT0_SX220 +MPRT0_SX310 +MPRT0_SX40 +MPRT0_SX400 +MPSW0_SI1067 +MPSW0_SI1697 +MPSW0_SI2327 +MPSW0_SX167 +MPSW0_SX24 +MPSW0_SX257 +MPSW0_SX437 +MPSW0_SX77 +MRAB0_SI1224 +MRAB0_SI1854 +MRAB0_SI594 +MRAB0_SX144 +MRAB0_SX234 +MRAB0_SX324 +MRAB0_SX414 +MRAB0_SX54 +MRAB1_SI1478 +MRAB1_SI2108 +MRAB1_SI848 +MRAB1_SX128 +MRAB1_SX218 +MRAB1_SX308 +MRAB1_SX38 +MRAB1_SX398 +MRAI0_SI1954 +MRAI0_SI2052 +MRAI0_SI792 +MRAI0_SX162 +MRAI0_SX252 +MRAI0_SX342 +MRAI0_SX432 +MRAI0_SX72 +MRAM0_SI1275 +MRAM0_SI1905 +MRAM0_SI1951 +MRAM0_SX105 +MRAM0_SX15 +MRAM0_SX195 +MRAM0_SX285 +MRAM0_SX375 +MRAV0_SI1008 +MRAV0_SI1638 +MRAV0_SI2268 +MRAV0_SX108 +MRAV0_SX18 +MRAV0_SX198 +MRAV0_SX288 +MRAV0_SX378 +MRBC0_SI1665 +MRBC0_SI1859 +MRBC0_SI599 +MRBC0_SX149 +MRBC0_SX239 +MRBC0_SX329 +MRBC0_SX419 +MRBC0_SX59 +MRCG0_SI1428 +MRCG0_SI2058 +MRCG0_SI798 +MRCG0_SX168 +MRCG0_SX258 +MRCG0_SX348 +MRCG0_SX438 +MRCG0_SX78 +MRCW0_SI1371 +MRCW0_SI2001 +MRCW0_SI741 +MRCW0_SX111 +MRCW0_SX201 +MRCW0_SX21 +MRCW0_SX291 +MRCW0_SX381 +MRDD0_SI1050 +MRDD0_SI1680 +MRDD0_SI2310 +MRDD0_SX150 +MRDD0_SX240 +MRDD0_SX277 +MRDD0_SX330 +MRDD0_SX60 +MRDM0_SI1044 +MRDM0_SI1595 +MRDM0_SI965 +MRDM0_SX155 +MRDM0_SX245 +MRDM0_SX335 +MRDM0_SX425 +MRDM0_SX65 +MRDS0_SI1167 +MRDS0_SI1797 +MRDS0_SI537 +MRDS0_SX177 +MRDS0_SX267 +MRDS0_SX357 +MRDS0_SX447 +MRDS0_SX87 +MREE0_SI1104 +MREE0_SI1734 +MREE0_SI1959 +MREE0_SX114 +MREE0_SX204 +MREE0_SX24 +MREE0_SX294 +MREE0_SX384 +MREH1_SI1599 +MREH1_SI2229 +MREH1_SI969 +MREH1_SX159 +MREH1_SX249 +MREH1_SX339 +MREH1_SX429 +MREH1_SX69 +MREM0_SI1591 +MREM0_SI511 +MREM0_SI961 +MREM0_SX151 +MREM0_SX241 +MREM0_SX331 +MREM0_SX421 +MREM0_SX61 +MREW1_SI1500 +MREW1_SI2130 +MREW1_SI870 +MREW1_SX150 +MREW1_SX240 +MREW1_SX330 +MREW1_SX420 +MREW1_SX60 +MRFK0_SI1076 +MRFK0_SI1706 +MRFK0_SI2336 +MRFK0_SX176 +MRFK0_SX266 +MRFK0_SX356 +MRFK0_SX446 +MRFK0_SX86 +MRFL0_SI1156 +MRFL0_SI1786 +MRFL0_SI526 +MRFL0_SX166 +MRFL0_SX256 +MRFL0_SX346 +MRFL0_SX436 +MRFL0_SX76 +MRGM0_SI1162 +MRGM0_SI1792 +MRGM0_SI532 +MRGM0_SX172 +MRGM0_SX262 +MRGM0_SX416 +MRGM0_SX442 +MRGM0_SX82 +MRGS0_SI1356 +MRGS0_SI1986 +MRGS0_SI726 +MRGS0_SX186 +MRGS0_SX276 +MRGS0_SX366 +MRGS0_SX6 +MRGS0_SX96 +MRHL0_SI1515 +MRHL0_SI2145 +MRHL0_SI885 +MRHL0_SX165 +MRHL0_SX255 +MRHL0_SX345 +MRHL0_SX435 +MRHL0_SX75 +MRJB1_SI1020 +MRJB1_SI1413 +MRJB1_SI2021 +MRJB1_SX120 +MRJB1_SX210 +MRJB1_SX30 +MRJB1_SX300 +MRJB1_SX390 +MRJH0_SI1519 +MRJH0_SI889 +MRJH0_SI914 +MRJH0_SX169 +MRJH0_SX259 +MRJH0_SX307 +MRJH0_SX439 +MRJH0_SX79 +MRJM0_SI1095 +MRJM0_SI1228 +MRJM0_SI1858 +MRJM0_SX148 +MRJM0_SX238 +MRJM0_SX328 +MRJM0_SX418 +MRJM0_SX58 +MRJM1_SI1298 +MRJM1_SI1928 +MRJM1_SI668 +MRJM1_SX128 +MRJM1_SX218 +MRJM1_SX308 +MRJM1_SX38 +MRJM1_SX398 +MRJT0_SI1498 +MRJT0_SI1805 +MRJT0_SI868 +MRJT0_SX148 +MRJT0_SX238 +MRJT0_SX328 +MRJT0_SX418 +MRJT0_SX58 +MRKM0_SI1267 +MRKM0_SI1391 +MRKM0_SI637 +MRKM0_SX187 +MRKM0_SX277 +MRKM0_SX367 +MRKM0_SX7 +MRKM0_SX97 +MRLD0_SI1594 +MRLD0_SI2224 +MRLD0_SI964 +MRLD0_SX154 +MRLD0_SX244 +MRLD0_SX334 +MRLD0_SX424 +MRLD0_SX64 +MRLJ0_SI1420 +MRLJ0_SI2050 +MRLJ0_SI790 +MRLJ0_SX160 +MRLJ0_SX250 +MRLJ0_SX340 +MRLJ0_SX430 +MRLJ0_SX70 +MRLJ1_SI1671 +MRLJ1_SI2301 +MRLJ1_SI2332 +MRLJ1_SX141 +MRLJ1_SX231 +MRLJ1_SX321 +MRLJ1_SX411 +MRLJ1_SX51 +MRLK0_SI1468 +MRLK0_SI2140 +MRLK0_SI843 +MRLK0_SX123 +MRLK0_SX213 +MRLK0_SX303 +MRLK0_SX33 +MRLK0_SX393 +MRLR0_SI1196 +MRLR0_SI1826 +MRLR0_SI566 +MRLR0_SX116 +MRLR0_SX206 +MRLR0_SX26 +MRLR0_SX296 +MRLR0_SX386 +MRMB0_SI1581 +MRMB0_SI2211 +MRMB0_SI951 +MRMB0_SX141 +MRMB0_SX231 +MRMB0_SX321 +MRMB0_SX411 +MRMB0_SX51 +MRMG0_SI1080 +MRMG0_SI1710 +MRMG0_SI2340 +MRMG0_SX180 +MRMG0_SX270 +MRMG0_SX360 +MRMG0_SX450 +MRMG0_SX90 +MRMH0_SI1021 +MRMH0_SI1349 +MRMH0_SI2281 +MRMH0_SX121 +MRMH0_SX211 +MRMH0_SX301 +MRMH0_SX31 +MRMH0_SX391 +MRML0_SI1421 +MRML0_SI2051 +MRML0_SI791 +MRML0_SX161 +MRML0_SX251 +MRML0_SX341 +MRML0_SX431 +MRML0_SX71 +MRMS0_SI1113 +MRMS0_SI2057 +MRMS0_SI2100 +MRMS0_SX120 +MRMS0_SX210 +MRMS0_SX30 +MRMS0_SX300 +MRMS0_SX390 +MRPC1_SI1482 +MRPC1_SI2026 +MRPC1_SI2112 +MRPC1_SX132 +MRPC1_SX222 +MRPC1_SX312 +MRPC1_SX402 +MRPC1_SX42 +MRRE0_SI1334 +MRRE0_SI704 +MRRE0_SI952 +MRRE0_SX164 +MRRE0_SX254 +MRRE0_SX344 +MRRE0_SX434 +MRRE0_SX74 +MRSO0_SI1206 +MRSO0_SI1659 +MRSO0_SI2289 +MRSO0_SX129 +MRSO0_SX219 +MRSO0_SX309 +MRSO0_SX39 +MRSO0_SX399 +MRSP0_SI1429 +MRSP0_SI2059 +MRSP0_SI799 +MRSP0_SX169 +MRSP0_SX196 +MRSP0_SX259 +MRSP0_SX439 +MRSP0_SX79 +MRTC0_SI1458 +MRTC0_SI2088 +MRTC0_SI828 +MRTC0_SX108 +MRTC0_SX18 +MRTC0_SX198 +MRTC0_SX288 +MRTC0_SX378 +MRTJ0_SI1551 +MRTJ0_SI2032 +MRTJ0_SI772 +MRTJ0_SX142 +MRTJ0_SX232 +MRTJ0_SX322 +MRTJ0_SX412 +MRTJ0_SX52 +MRVG0_SI1140 +MRVG0_SI1770 +MRVG0_SI510 +MRVG0_SX150 +MRVG0_SX240 +MRVG0_SX330 +MRVG0_SX420 +MRVG0_SX60 +MRWA0_SI1603 +MRWA0_SI2233 +MRWA0_SI973 +MRWA0_SX163 +MRWA0_SX253 +MRWA0_SX343 +MRWA0_SX433 +MRWA0_SX73 +MRWS0_SI1102 +MRWS0_SI1732 +MRWS0_SI472 +MRWS0_SX112 +MRWS0_SX202 +MRWS0_SX22 +MRWS0_SX292 +MRWS0_SX382 +MRXB0_SI1585 +MRXB0_SI2215 +MRXB0_SI955 +MRXB0_SX145 +MRXB0_SX235 +MRXB0_SX325 +MRXB0_SX415 +MRXB0_SX55 +MSAH1_SI1049 +MSAH1_SI1679 +MSAH1_SI2309 +MSAH1_SX149 +MSAH1_SX239 +MSAH1_SX329 +MSAH1_SX419 +MSAH1_SX59 +MSAS0_SI1376 +MSAS0_SI2006 +MSAS0_SI746 +MSAS0_SX116 +MSAS0_SX206 +MSAS0_SX26 +MSAS0_SX296 +MSAS0_SX386 +MSAT0_SI1526 +MSAT0_SI2156 +MSAT0_SI896 +MSAT0_SX176 +MSAT0_SX266 +MSAT0_SX356 +MSAT0_SX446 +MSAT0_SX86 +MSAT1_SI1073 +MSAT1_SI1703 +MSAT1_SI2333 +MSAT1_SX173 +MSAT1_SX263 +MSAT1_SX353 +MSAT1_SX443 +MSAT1_SX83 +MSDB0_SI1007 +MSDB0_SI1637 +MSDB0_SI2267 +MSDB0_SX107 +MSDB0_SX17 +MSDB0_SX197 +MSDB0_SX287 +MSDB0_SX377 +MSDH0_SI2113 +MSDH0_SI2240 +MSDH0_SI980 +MSDH0_SX170 +MSDH0_SX260 +MSDH0_SX350 +MSDH0_SX440 +MSDH0_SX80 +MSDS0_SI1077 +MSDS0_SI1707 +MSDS0_SI2337 +MSDS0_SX177 +MSDS0_SX267 +MSDS0_SX357 +MSDS0_SX447 +MSDS0_SX87 +MSEM1_SI1440 +MSEM1_SI2070 +MSEM1_SI810 +MSEM1_SX180 +MSEM1_SX270 +MSEM1_SX360 +MSEM1_SX450 +MSEM1_SX90 +MSES0_SI1589 +MSES0_SI2216 +MSES0_SI2219 +MSES0_SX149 +MSES0_SX239 +MSES0_SX329 +MSES0_SX419 +MSES0_SX59 +MSFH0_SI1216 +MSFH0_SI1738 +MSFH0_SI586 +MSFH0_SX136 +MSFH0_SX226 +MSFH0_SX316 +MSFH0_SX406 +MSFH0_SX46 +MSFV0_SI1262 +MSFV0_SI1892 +MSFV0_SI632 +MSFV0_SX182 +MSFV0_SX272 +MSFV0_SX362 +MSFV0_SX452 +MSFV0_SX92 +MSJK0_SI1596 +MSJK0_SI2226 +MSJK0_SI966 +MSJK0_SX156 +MSJK0_SX246 +MSJK0_SX336 +MSJK0_SX426 +MSJK0_SX66 +MSMC0_SI1907 +MSMC0_SI509 +MSMC0_SI647 +MSMC0_SX107 +MSMC0_SX17 +MSMC0_SX197 +MSMC0_SX287 +MSMC0_SX377 +MSMR0_SI1150 +MSMR0_SI1405 +MSMR0_SI775 +MSMR0_SX145 +MSMR0_SX235 +MSMR0_SX325 +MSMR0_SX415 +MSMR0_SX55 +MSMS0_SI1433 +MSMS0_SI2063 +MSMS0_SI803 +MSMS0_SX173 +MSMS0_SX263 +MSMS0_SX353 +MSMS0_SX443 +MSMS0_SX83 +MSRG0_SI1221 +MSRG0_SI1851 +MSRG0_SI591 +MSRG0_SX141 +MSRG0_SX231 +MSRG0_SX321 +MSRG0_SX411 +MSRG0_SX51 +MSRR0_SI1131 +MSRR0_SI1761 +MSRR0_SI501 +MSRR0_SX141 +MSRR0_SX231 +MSRR0_SX30 +MSRR0_SX411 +MSRR0_SX51 +MSTF0_SI1396 +MSTF0_SI766 +MSTF0_SI852 +MSTF0_SX136 +MSTF0_SX226 +MSTF0_SX316 +MSTF0_SX406 +MSTF0_SX46 +MSVS0_SI1568 +MSVS0_SI2198 +MSVS0_SI938 +MSVS0_SX128 +MSVS0_SX218 +MSVS0_SX308 +MSVS0_SX38 +MSVS0_SX398 +MTAB0_SI1572 +MTAB0_SI2202 +MTAB0_SI942 +MTAB0_SX132 +MTAB0_SX222 +MTAB0_SX312 +MTAB0_SX402 +MTAB0_SX42 +MTAS0_SI1385 +MTAS0_SI2015 +MTAS0_SI755 +MTAS0_SX125 +MTAS0_SX215 +MTAS0_SX305 +MTAS0_SX35 +MTAS0_SX395 +MTAT0_SI1110 +MTAT0_SI1740 +MTAT0_SI811 +MTAT0_SX120 +MTAT0_SX210 +MTAT0_SX30 +MTAT0_SX300 +MTAT0_SX390 +MTAT1_SI1409 +MTAT1_SI1627 +MTAT1_SI779 +MTAT1_SX149 +MTAT1_SX239 +MTAT1_SX329 +MTAT1_SX419 +MTAT1_SX59 +MTBC0_SI1173 +MTBC0_SI1803 +MTBC0_SI543 +MTBC0_SX183 +MTBC0_SX273 +MTBC0_SX347 +MTBC0_SX363 +MTBC0_SX93 +MTCS0_SI1972 +MTCS0_SI2265 +MTCS0_SI712 +MTCS0_SX172 +MTCS0_SX262 +MTCS0_SX352 +MTCS0_SX442 +MTCS0_SX82 +MTDB0_SI1401 +MTDB0_SI2031 +MTDB0_SI771 +MTDB0_SX141 +MTDB0_SX231 +MTDB0_SX321 +MTDB0_SX411 +MTDB0_SX51 +MTDP0_SI1274 +MTDP0_SI1521 +MTDP0_SI2151 +MTDP0_SX171 +MTDP0_SX261 +MTDP0_SX351 +MTDP0_SX441 +MTDP0_SX81 +MTER0_SI1157 +MTER0_SI1787 +MTER0_SI527 +MTER0_SX167 +MTER0_SX17 +MTER0_SX257 +MTER0_SX437 +MTER0_SX77 +MTJG0_SI1520 +MTJG0_SI2157 +MTJG0_SI890 +MTJG0_SX170 +MTJG0_SX260 +MTJG0_SX350 +MTJG0_SX440 +MTJG0_SX80 +MTJM0_SI1226 +MTJM0_SI1856 +MTJM0_SI655 +MTJM0_SX146 +MTJM0_SX236 +MTJM0_SX326 +MTJM0_SX416 +MTJM0_SX56 +MTJS0_SI1192 +MTJS0_SI1822 +MTJS0_SI562 +MTJS0_SX112 +MTJS0_SX202 +MTJS0_SX22 +MTJS0_SX292 +MTJS0_SX382 +MTJU0_SI2020 +MTJU0_SI2269 +MTJU0_SI760 +MTJU0_SX130 +MTJU0_SX220 +MTJU0_SX310 +MTJU0_SX40 +MTJU0_SX400 +MTKD0_SI1187 +MTKD0_SI1817 +MTKD0_SI630 +MTKD0_SX107 +MTKD0_SX17 +MTKD0_SX197 +MTKD0_SX287 +MTKD0_SX377 +MTKP0_SI1023 +MTKP0_SI2283 +MTKP0_SI454 +MTKP0_SX123 +MTKP0_SX213 +MTKP0_SX303 +MTKP0_SX33 +MTKP0_SX393 +MTLB0_SI1134 +MTLB0_SI1764 +MTLB0_SI504 +MTLB0_SX144 +MTLB0_SX234 +MTLB0_SX324 +MTLB0_SX414 +MTLB0_SX54 +MTLC0_SI1313 +MTLC0_SI1477 +MTLC0_SI847 +MTLC0_SX127 +MTLC0_SX217 +MTLC0_SX307 +MTLC0_SX37 +MTLC0_SX397 +MTML0_SI1065 +MTML0_SI1695 +MTML0_SI2325 +MTML0_SX165 +MTML0_SX255 +MTML0_SX345 +MTML0_SX435 +MTML0_SX75 +MTMN0_SI1064 +MTMN0_SI2324 +MTMN0_SI582 +MTMN0_SX164 +MTMN0_SX254 +MTMN0_SX344 +MTMN0_SX434 +MTMN0_SX74 +MTMT0_SI1118 +MTMT0_SI1748 +MTMT0_SI488 +MTMT0_SX128 +MTMT0_SX218 +MTMT0_SX308 +MTMT0_SX38 +MTMT0_SX398 +MTPF0_SI1235 +MTPF0_SI1865 +MTPF0_SI605 +MTPF0_SX155 +MTPF0_SX245 +MTPF0_SX335 +MTPF0_SX425 +MTPF0_SX65 +MTPG0_SI1383 +MTPG0_SI2013 +MTPG0_SI753 +MTPG0_SX123 +MTPG0_SX213 +MTPG0_SX303 +MTPG0_SX33 +MTPG0_SX393 +MTPP0_SI1508 +MTPP0_SI2138 +MTPP0_SI878 +MTPP0_SX158 +MTPP0_SX248 +MTPP0_SX338 +MTPP0_SX428 +MTPP0_SX68 +MTPR0_SI1600 +MTPR0_SI2230 +MTPR0_SI506 +MTPR0_SX160 +MTPR0_SX250 +MTPR0_SX340 +MTPR0_SX430 +MTPR0_SX70 +MTQC0_SI1441 +MTQC0_SI2071 +MTQC0_SI480 +MTQC0_SX181 +MTQC0_SX271 +MTQC0_SX361 +MTQC0_SX451 +MTQC0_SX91 +MTRC0_SI1623 +MTRC0_SI589 +MTRC0_SI993 +MTRC0_SX170 +MTRC0_SX183 +MTRC0_SX273 +MTRC0_SX363 +MTRC0_SX93 +MTRR0_SI1548 +MTRR0_SI2178 +MTRR0_SI918 +MTRR0_SX108 +MTRR0_SX18 +MTRR0_SX198 +MTRR0_SX288 +MTRR0_SX378 +MTRT0_SI1227 +MTRT0_SI1857 +MTRT0_SI597 +MTRT0_SX147 +MTRT0_SX237 +MTRT0_SX254 +MTRT0_SX417 +MTRT0_SX57 +MTWH1_SI1512 +MTWH1_SI2142 +MTWH1_SI882 +MTWH1_SX162 +MTWH1_SX252 +MTWH1_SX342 +MTWH1_SX432 +MTWH1_SX72 +MTXS0_SI1060 +MTXS0_SI1690 +MTXS0_SI2320 +MTXS0_SX160 +MTXS0_SX250 +MTXS0_SX340 +MTXS0_SX430 +MTXS0_SX70 +MVJH0_SI1556 +MVJH0_SI2186 +MVJH0_SI926 +MVJH0_SX116 +MVJH0_SX206 +MVJH0_SX26 +MVJH0_SX296 +MVJH0_SX386 +MVLO0_SI1147 +MVLO0_SI1777 +MVLO0_SI517 +MVLO0_SX157 +MVLO0_SX247 +MVLO0_SX337 +MVLO0_SX427 +MVLO0_SX67 +MVRW0_SI1485 +MVRW0_SI2115 +MVRW0_SI855 +MVRW0_SX135 +MVRW0_SX225 +MVRW0_SX315 +MVRW0_SX405 +MVRW0_SX45 +MWAC0_SI1601 +MWAC0_SI2231 +MWAC0_SI971 +MWAC0_SX161 +MWAC0_SX251 +MWAC0_SX341 +MWAC0_SX431 +MWAC0_SX71 +MWAD0_SI1062 +MWAD0_SI1749 +MWAD0_SI2322 +MWAD0_SX162 +MWAD0_SX252 +MWAD0_SX342 +MWAD0_SX432 +MWAD0_SX72 +MWAR0_SI1045 +MWAR0_SI1675 +MWAR0_SI2305 +MWAR0_SX145 +MWAR0_SX235 +MWAR0_SX325 +MWAR0_SX415 +MWAR0_SX55 +MWCH0_SI1622 +MWCH0_SI1895 +MWCH0_SI2252 +MWCH0_SX182 +MWCH0_SX272 +MWCH0_SX362 +MWCH0_SX452 +MWCH0_SX92 +MWDK0_SI1436 +MWDK0_SI2017 +MWDK0_SI806 +MWDK0_SX176 +MWDK0_SX266 +MWDK0_SX356 +MWDK0_SX446 +MWDK0_SX86 +MWEM0_SI1320 +MWEM0_SI1393 +MWEM0_SI1950 +MWEM0_SX150 +MWEM0_SX240 +MWEM0_SX330 +MWEM0_SX420 +MWEM0_SX60 +MWGR0_SI1606 +MWGR0_SI2236 +MWGR0_SI976 +MWGR0_SX166 +MWGR0_SX256 +MWGR0_SX346 +MWGR0_SX436 +MWGR0_SX76 +MWRE0_SI1057 +MWRE0_SI1687 +MWRE0_SI2317 +MWRE0_SX157 +MWRE0_SX247 +MWRE0_SX337 +MWRE0_SX427 +MWRE0_SX67 +MWRP0_SI1443 +MWRP0_SI1525 +MWRP0_SI2073 +MWRP0_SX183 +MWRP0_SX273 +MWRP0_SX3 +MWRP0_SX363 +MWRP0_SX93 +MWSB0_SI1626 +MWSB0_SI2256 +MWSB0_SI996 +MWSB0_SX186 +MWSB0_SX276 +MWSB0_SX366 +MWSB0_SX6 +MWSB0_SX96 +MWSH0_SI1426 +MWSH0_SI2266 +MWSH0_SI796 +MWSH0_SX166 +MWSH0_SX256 +MWSH0_SX346 +MWSH0_SX436 +MWSH0_SX76 +MZMB0_SI1166 +MZMB0_SI1796 +MZMB0_SI536 +MZMB0_SX176 +MZMB0_SX266 +MZMB0_SX356 +MZMB0_SX446 +MZMB0_SX86 diff --git a/examples/wav2vec/unsupervised/config/timit_matched/train_text.uid b/examples/wav2vec/unsupervised/config/timit_matched/train_text.uid new file mode 100644 index 0000000000..c39fd0b91d --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_matched/train_text.uid @@ -0,0 +1,3696 @@ +FAEM0_SI1392 +FAEM0_SI2022 +FAEM0_SI762 +FAEM0_SX132 +FAEM0_SX222 +FAEM0_SX312 +FAEM0_SX402 +FAEM0_SX42 +FAJW0_SI1263 +FAJW0_SI1893 +FAJW0_SI633 +FAJW0_SX183 +FAJW0_SX273 +FAJW0_SX3 +FAJW0_SX363 +FAJW0_SX93 +FALK0_SI1086 +FALK0_SI456 +FALK0_SI658 +FALK0_SX186 +FALK0_SX276 +FALK0_SX366 +FALK0_SX6 +FALK0_SX96 +FALR0_SI1325 +FALR0_SI1955 +FALR0_SI695 +FALR0_SX155 +FALR0_SX245 +FALR0_SX335 +FALR0_SX425 +FALR0_SX65 +FAPB0_SI1063 +FAPB0_SI1693 +FAPB0_SI2323 +FAPB0_SX163 +FAPB0_SX253 +FAPB0_SX343 +FAPB0_SX433 +FAPB0_SX73 +FBAS0_SI1387 +FBAS0_SI1472 +FBAS0_SI2066 +FBAS0_SX127 +FBAS0_SX217 +FBAS0_SX307 +FBAS0_SX37 +FBAS0_SX397 +FBCG1_SI1612 +FBCG1_SI2242 +FBCG1_SI982 +FBCG1_SX172 +FBCG1_SX262 +FBCG1_SX352 +FBCG1_SX442 +FBCG1_SX82 +FBCH0_SI1586 +FBCH0_SI956 +FBCH0_SI959 +FBCH0_SX146 +FBCH0_SX236 +FBCH0_SX326 +FBCH0_SX416 +FBCH0_SX56 +FBJL0_SI1552 +FBJL0_SI2182 +FBJL0_SI922 +FBJL0_SX112 +FBJL0_SX202 +FBJL0_SX22 +FBJL0_SX292 +FBJL0_SX382 +FBLV0_SI1058 +FBLV0_SI1688 +FBLV0_SI2318 +FBLV0_SX158 +FBLV0_SX248 +FBLV0_SX338 +FBLV0_SX428 +FBLV0_SX68 +FBMH0_SI1136 +FBMH0_SI1766 +FBMH0_SI970 +FBMH0_SX146 +FBMH0_SX236 +FBMH0_SX326 +FBMH0_SX416 +FBMH0_SX56 +FBMJ0_SI1776 +FBMJ0_SI516 +FBMJ0_SI815 +FBMJ0_SX156 +FBMJ0_SX246 +FBMJ0_SX336 +FBMJ0_SX426 +FBMJ0_SX66 +FCAG0_SI1503 +FCAG0_SI1641 +FCAG0_SI2133 +FCAG0_SX153 +FCAG0_SX243 +FCAG0_SX333 +FCAG0_SX423 +FCAG0_SX63 +FCAJ0_SI1479 +FCAJ0_SI1804 +FCAJ0_SI849 +FCAJ0_SX129 +FCAJ0_SX219 +FCAJ0_SX309 +FCAJ0_SX39 +FCAJ0_SX399 +FCDR1_SI1186 +FCDR1_SI1816 +FCDR1_SI556 +FCDR1_SX106 +FCDR1_SX16 +FCDR1_SX196 +FCDR1_SX286 +FCDR1_SX376 +FCEG0_SI1248 +FCEG0_SI1878 +FCEG0_SI618 +FCEG0_SX168 +FCEG0_SX258 +FCEG0_SX348 +FCEG0_SX438 +FCEG0_SX78 +FCJF0_SI1027 +FCJF0_SI1657 +FCJF0_SI648 +FCJF0_SX127 +FCJF0_SX217 +FCJF0_SX307 +FCJF0_SX37 +FCJF0_SX397 +FCJS0_SI1607 +FCJS0_SI2237 +FCJS0_SI977 +FCJS0_SX167 +FCJS0_SX257 +FCJS0_SX347 +FCJS0_SX437 +FCJS0_SX77 +FCKE0_SI1111 +FCKE0_SI1741 +FCKE0_SI481 +FCKE0_SX121 +FCKE0_SX211 +FCKE0_SX301 +FCKE0_SX31 +FCKE0_SX391 +FCLT0_SI1438 +FCLT0_SI2068 +FCLT0_SI808 +FCLT0_SX178 +FCLT0_SX268 +FCLT0_SX358 +FCLT0_SX448 +FCLT0_SX88 +FCMG0_SI1142 +FCMG0_SI1242 +FCMG0_SI1872 +FCMG0_SX162 +FCMG0_SX252 +FCMG0_SX342 +FCMG0_SX432 +FCMG0_SX72 +FCMM0_SI1083 +FCMM0_SI1957 +FCMM0_SI453 +FCMM0_SX183 +FCMM0_SX273 +FCMM0_SX363 +FCMM0_SX420 +FCMM0_SX93 +FCRZ0_SI1913 +FCRZ0_SI2053 +FCRZ0_SI793 +FCRZ0_SX163 +FCRZ0_SX253 +FCRZ0_SX343 +FCRZ0_SX433 +FCRZ0_SX73 +FCYL0_SI1297 +FCYL0_SI1927 +FCYL0_SI667 +FCYL0_SX127 +FCYL0_SX217 +FCYL0_SX349 +FCYL0_SX37 +FCYL0_SX397 +FDAS1_SI1461 +FDAS1_SI2091 +FDAS1_SI831 +FDAS1_SX111 +FDAS1_SX201 +FDAS1_SX21 +FDAS1_SX291 +FDAS1_SX381 +FDAW0_SI1271 +FDAW0_SI1406 +FDAW0_SI2036 +FDAW0_SX146 +FDAW0_SX236 +FDAW0_SX326 +FDAW0_SX416 +FDAW0_SX56 +FDFB0_SI1318 +FDFB0_SI1948 +FDFB0_SI2010 +FDFB0_SX148 +FDFB0_SX238 +FDFB0_SX328 +FDFB0_SX418 +FDFB0_SX58 +FDJH0_SI1565 +FDJH0_SI2195 +FDJH0_SI935 +FDJH0_SX125 +FDJH0_SX215 +FDJH0_SX305 +FDJH0_SX35 +FDJH0_SX395 +FDKN0_SI1081 +FDKN0_SI1202 +FDKN0_SI1711 +FDKN0_SX181 +FDKN0_SX271 +FDKN0_SX361 +FDKN0_SX451 +FDKN0_SX91 +FDML0_SI1149 +FDML0_SI1779 +FDML0_SI2075 +FDML0_SX159 +FDML0_SX249 +FDML0_SX339 +FDML0_SX429 +FDML0_SX69 +FDMY0_SI1197 +FDMY0_SI567 +FDMY0_SI714 +FDMY0_SX117 +FDMY0_SX207 +FDMY0_SX27 +FDMY0_SX297 +FDMY0_SX387 +FDNC0_SI1278 +FDNC0_SI1908 +FDNC0_SI2287 +FDNC0_SX108 +FDNC0_SX18 +FDNC0_SX198 +FDNC0_SX288 +FDNC0_SX378 +FDTD0_SI1561 +FDTD0_SI2191 +FDTD0_SI931 +FDTD0_SX121 +FDTD0_SX211 +FDTD0_SX301 +FDTD0_SX321 +FDTD0_SX391 +FDXW0_SI1511 +FDXW0_SI2141 +FDXW0_SI881 +FDXW0_SX161 +FDXW0_SX251 +FDXW0_SX341 +FDXW0_SX431 +FDXW0_SX71 +FEAC0_SI1245 +FEAC0_SI1875 +FEAC0_SI615 +FEAC0_SX165 +FEAC0_SX255 +FEAC0_SX345 +FEAC0_SX435 +FEAC0_SX75 +FEAR0_SI1252 +FEAR0_SI1882 +FEAR0_SI622 +FEAR0_SX172 +FEAR0_SX262 +FEAR0_SX352 +FEAR0_SX442 +FEAR0_SX82 +FECD0_SI1418 +FECD0_SI2048 +FECD0_SI788 +FECD0_SX158 +FECD0_SX248 +FECD0_SX338 +FECD0_SX428 +FECD0_SX68 +FEEH0_SI1112 +FEEH0_SI1742 +FEEH0_SI471 +FEEH0_SX122 +FEEH0_SX212 +FEEH0_SX302 +FEEH0_SX32 +FEEH0_SX392 +FEME0_SI1505 +FEME0_SI2135 +FEME0_SI875 +FEME0_SX155 +FEME0_SX245 +FEME0_SX335 +FEME0_SX425 +FEME0_SX65 +FETB0_SI1148 +FETB0_SI1778 +FETB0_SI518 +FETB0_SX158 +FETB0_SX248 +FETB0_SX338 +FETB0_SX428 +FETB0_SX68 +FEXM0_SI1101 +FEXM0_SI1731 +FEXM0_SI482 +FEXM0_SX111 +FEXM0_SX201 +FEXM0_SX291 +FEXM0_SX366 +FEXM0_SX381 +FGCS0_SI1486 +FGCS0_SI2116 +FGCS0_SI856 +FGCS0_SX136 +FGCS0_SX226 +FGCS0_SX316 +FGCS0_SX406 +FGCS0_SX46 +FGDP0_SI1618 +FGDP0_SI2248 +FGDP0_SI988 +FGDP0_SX178 +FGDP0_SX268 +FGDP0_SX358 +FGDP0_SX448 +FGDP0_SX88 +FGMB0_SI1145 +FGMB0_SI1775 +FGMB0_SI515 +FGMB0_SX155 +FGMB0_SX245 +FGMB0_SX335 +FGMB0_SX425 +FGMB0_SX65 +FGRW0_SI1152 +FGRW0_SI1782 +FGRW0_SI1990 +FGRW0_SX162 +FGRW0_SX252 +FGRW0_SX342 +FGRW0_SX432 +FGRW0_SX72 +FHLM0_SI1560 +FHLM0_SI2190 +FHLM0_SI930 +FHLM0_SX120 +FHLM0_SX210 +FHLM0_SX300 +FHLM0_SX349 +FHLM0_SX390 +FHXS0_SI1075 +FHXS0_SI2302 +FHXS0_SI2335 +FHXS0_SX175 +FHXS0_SX265 +FHXS0_SX355 +FHXS0_SX445 +FHXS0_SX85 +FJDM2_SI1582 +FJDM2_SI1964 +FJDM2_SI2212 +FJDM2_SX142 +FJDM2_SX232 +FJDM2_SX322 +FJDM2_SX412 +FJDM2_SX52 +FJEN0_SI1047 +FJEN0_SI1677 +FJEN0_SI2307 +FJEN0_SX147 +FJEN0_SX237 +FJEN0_SX327 +FJEN0_SX417 +FJEN0_SX57 +FJHK0_SI1022 +FJHK0_SI1652 +FJHK0_SI2282 +FJHK0_SX122 +FJHK0_SX212 +FJHK0_SX302 +FJHK0_SX32 +FJHK0_SX392 +FJKL0_SI1562 +FJKL0_SI2192 +FJKL0_SI932 +FJKL0_SX122 +FJKL0_SX212 +FJKL0_SX302 +FJKL0_SX32 +FJKL0_SX392 +FJLG0_SI1506 +FJLG0_SI1889 +FJLG0_SI2306 +FJLG0_SX179 +FJLG0_SX269 +FJLG0_SX359 +FJLG0_SX449 +FJLG0_SX89 +FJLR0_SI1231 +FJLR0_SI1861 +FJLR0_SI601 +FJLR0_SX151 +FJLR0_SX241 +FJLR0_SX331 +FJLR0_SX421 +FJLR0_SX61 +FJRB0_SI1302 +FJRB0_SI1932 +FJRB0_SI672 +FJRB0_SX132 +FJRB0_SX222 +FJRB0_SX312 +FJRB0_SX402 +FJRB0_SX42 +FJRP1_SI1432 +FJRP1_SI2062 +FJRP1_SI802 +FJRP1_SX172 +FJRP1_SX262 +FJRP1_SX352 +FJRP1_SX442 +FJRP1_SX82 +FJSK0_SI1052 +FJSK0_SI1682 +FJSK0_SI2312 +FJSK0_SX152 +FJSK0_SX242 +FJSK0_SX332 +FJSK0_SX422 +FJSK0_SX62 +FJSP0_SI1434 +FJSP0_SI1763 +FJSP0_SI804 +FJSP0_SX174 +FJSP0_SX264 +FJSP0_SX354 +FJSP0_SX444 +FJSP0_SX84 +FJWB1_SI2055 +FJWB1_SI748 +FJWB1_SI795 +FJWB1_SX165 +FJWB1_SX255 +FJWB1_SX345 +FJWB1_SX435 +FJWB1_SX75 +FJXM0_SI1211 +FJXM0_SI1971 +FJXM0_SI581 +FJXM0_SX131 +FJXM0_SX221 +FJXM0_SX311 +FJXM0_SX401 +FJXM0_SX41 +FJXP0_SI1122 +FJXP0_SI1752 +FJXP0_SI492 +FJXP0_SX132 +FJXP0_SX222 +FJXP0_SX312 +FJXP0_SX402 +FJXP0_SX42 +FKAA0_SI1208 +FKAA0_SI1838 +FKAA0_SI578 +FKAA0_SX128 +FKAA0_SX218 +FKAA0_SX308 +FKAA0_SX38 +FKAA0_SX398 +FKDE0_SI1141 +FKDE0_SI1771 +FKDE0_SI2221 +FKDE0_SX151 +FKDE0_SX241 +FKDE0_SX331 +FKDE0_SX421 +FKDE0_SX61 +FKDW0_SI1207 +FKDW0_SI1891 +FKDW0_SI577 +FKDW0_SX127 +FKDW0_SX217 +FKDW0_SX307 +FKDW0_SX37 +FKDW0_SX397 +FKFB0_SI1608 +FKFB0_SI2238 +FKFB0_SI978 +FKFB0_SX168 +FKFB0_SX258 +FKFB0_SX348 +FKFB0_SX438 +FKFB0_SX78 +FKKH0_SI1290 +FKKH0_SI1920 +FKKH0_SI660 +FKKH0_SX120 +FKKH0_SX210 +FKKH0_SX30 +FKKH0_SX300 +FKKH0_SX390 +FKLC0_SI1615 +FKLC0_SI2245 +FKLC0_SI985 +FKLC0_SX175 +FKLC0_SX265 +FKLC0_SX355 +FKLC0_SX445 +FKLC0_SX85 +FKLC1_SI1048 +FKLC1_SI1678 +FKLC1_SI2308 +FKLC1_SX148 +FKLC1_SX238 +FKLC1_SX328 +FKLC1_SX418 +FKLC1_SX58 +FKLH0_SI1257 +FKLH0_SI1887 +FKLH0_SI627 +FKLH0_SX177 +FKLH0_SX267 +FKLH0_SX357 +FKLH0_SX447 +FKLH0_SX87 +FKSR0_SI1117 +FKSR0_SI1747 +FKSR0_SI487 +FKSR0_SX161 +FKSR0_SX217 +FKSR0_SX366 +FKSR0_SX37 +FKSR0_SX397 +FLAC0_SI1339 +FLAC0_SI2161 +FLAC0_SI901 +FLAC0_SX181 +FLAC0_SX271 +FLAC0_SX361 +FLAC0_SX451 +FLAC0_SX91 +FLAG0_SI1464 +FLAG0_SI2094 +FLAG0_SI834 +FLAG0_SX114 +FLAG0_SX204 +FLAG0_SX24 +FLAG0_SX294 +FLAG0_SX384 +FLEH0_SI1051 +FLEH0_SI1681 +FLEH0_SI2311 +FLEH0_SX151 +FLEH0_SX241 +FLEH0_SX331 +FLEH0_SX421 +FLEH0_SX61 +FLET0_SI1137 +FLET0_SI1767 +FLET0_SI507 +FLET0_SX147 +FLET0_SX237 +FLET0_SX277 +FLET0_SX417 +FLET0_SX57 +FLHD0_SI1344 +FLHD0_SI1827 +FLHD0_SI1974 +FLHD0_SX174 +FLHD0_SX264 +FLHD0_SX354 +FLHD0_SX444 +FLHD0_SX84 +FLJA0_SI1078 +FLJA0_SI1708 +FLJA0_SI2338 +FLJA0_SX178 +FLJA0_SX268 +FLJA0_SX358 +FLJA0_SX448 +FLJA0_SX88 +FLJD0_SI1516 +FLJD0_SI2146 +FLJD0_SI886 +FLJD0_SX166 +FLJD0_SX256 +FLJD0_SX346 +FLJD0_SX436 +FLJD0_SX76 +FLJG0_SI1611 +FLJG0_SI2241 +FLJG0_SI981 +FLJG0_SX171 +FLJG0_SX261 +FLJG0_SX351 +FLJG0_SX441 +FLJG0_SX81 +FLKM0_SI1880 +FLKM0_SI620 +FLKM0_SI686 +FLKM0_SX116 +FLKM0_SX260 +FLKM0_SX350 +FLKM0_SX440 +FLKM0_SX80 +FLMA0_SI1243 +FLMA0_SI1873 +FLMA0_SI613 +FLMA0_SX163 +FLMA0_SX253 +FLMA0_SX343 +FLMA0_SX433 +FLMA0_SX73 +FLMC0_SI1372 +FLMC0_SI2002 +FLMC0_SI742 +FLMC0_SX112 +FLMC0_SX22 +FLMC0_SX292 +FLMC0_SX336 +FLMC0_SX382 +FLMK0_SI1035 +FLMK0_SI1229 +FLMK0_SI2295 +FLMK0_SX135 +FLMK0_SX225 +FLMK0_SX315 +FLMK0_SX405 +FLMK0_SX45 +FLOD0_SI1287 +FLOD0_SI1917 +FLOD0_SI657 +FLOD0_SX117 +FLOD0_SX171 +FLOD0_SX207 +FLOD0_SX297 +FLOD0_SX387 +FLTM0_SI1070 +FLTM0_SI1700 +FLTM0_SI2330 +FLTM0_SX170 +FLTM0_SX260 +FLTM0_SX350 +FLTM0_SX440 +FLTM0_SX80 +FMAH1_SI1509 +FMAH1_SI2139 +FMAH1_SI879 +FMAH1_SX159 +FMAH1_SX249 +FMAH1_SX339 +FMAH1_SX429 +FMAH1_SX69 +FMBG0_SI1160 +FMBG0_SI1790 +FMBG0_SI2264 +FMBG0_SX260 +FMBG0_SX3 +FMBG0_SX350 +FMBG0_SX440 +FMBG0_SX80 +FMEM0_SI1377 +FMEM0_SI2007 +FMEM0_SI747 +FMEM0_SX117 +FMEM0_SX207 +FMEM0_SX297 +FMEM0_SX333 +FMEM0_SX387 +FMJB0_SI1177 +FMJB0_SI1807 +FMJB0_SI547 +FMJB0_SX187 +FMJB0_SX277 +FMJB0_SX367 +FMJB0_SX7 +FMJB0_SX97 +FMJF0_SI1254 +FMJF0_SI1884 +FMJF0_SI624 +FMJF0_SX174 +FMJF0_SX264 +FMJF0_SX354 +FMJF0_SX444 +FMJF0_SX84 +FMJU0_SI1389 +FMJU0_SI2019 +FMJU0_SI759 +FMJU0_SX129 +FMJU0_SX219 +FMJU0_SX309 +FMJU0_SX39 +FMJU0_SX399 +FMKC0_SI1041 +FMKC0_SI1072 +FMKC0_SI1702 +FMKC0_SX172 +FMKC0_SX262 +FMKC0_SX352 +FMKC0_SX442 +FMKC0_SX82 +FMKF0_SI1018 +FMKF0_SI1536 +FMKF0_SI906 +FMKF0_SX186 +FMKF0_SX276 +FMKF0_SX366 +FMKF0_SX6 +FMKF0_SX96 +FMMH0_SI1537 +FMMH0_SI2167 +FMMH0_SI907 +FMMH0_SX187 +FMMH0_SX367 +FMMH0_SX420 +FMMH0_SX7 +FMMH0_SX97 +FMPG0_SI1602 +FMPG0_SI2232 +FMPG0_SI972 +FMPG0_SX162 +FMPG0_SX252 +FMPG0_SX342 +FMPG0_SX432 +FMPG0_SX72 +FNKL0_SI1522 +FNKL0_SI2152 +FNKL0_SI892 +FNKL0_SX172 +FNKL0_SX196 +FNKL0_SX262 +FNKL0_SX442 +FNKL0_SX82 +FNTB0_SI1203 +FNTB0_SI573 +FNTB0_SI679 +FNTB0_SX123 +FNTB0_SX213 +FNTB0_SX303 +FNTB0_SX33 +FNTB0_SX393 +FPAB1_SI1471 +FPAB1_SI2101 +FPAB1_SI841 +FPAB1_SX121 +FPAB1_SX211 +FPAB1_SX301 +FPAB1_SX31 +FPAB1_SX391 +FPAC0_SI1921 +FPAC0_SI2011 +FPAC0_SI661 +FPAC0_SX121 +FPAC0_SX211 +FPAC0_SX301 +FPAC0_SX31 +FPAC0_SX391 +FPAD0_SI1346 +FPAD0_SI1976 +FPAD0_SI716 +FPAD0_SX176 +FPAD0_SX266 +FPAD0_SX356 +FPAD0_SX446 +FPAD0_SX86 +FPAF0_SI1054 +FPAF0_SI1684 +FPAF0_SI2314 +FPAF0_SX154 +FPAF0_SX244 +FPAF0_SX334 +FPAF0_SX424 +FPAF0_SX64 +FPAZ0_SI1593 +FPAZ0_SI2223 +FPAZ0_SI963 +FPAZ0_SX153 +FPAZ0_SX243 +FPAZ0_SX27 +FPAZ0_SX423 +FPAZ0_SX63 +FPJF0_SI1046 +FPJF0_SI1259 +FPJF0_SI1676 +FPJF0_SX146 +FPJF0_SX236 +FPJF0_SX326 +FPJF0_SX352 +FPJF0_SX56 +FPLS0_SI1590 +FPLS0_SI2220 +FPLS0_SI960 +FPLS0_SX150 +FPLS0_SX240 +FPLS0_SX3 +FPLS0_SX330 +FPLS0_SX60 +FPMY0_SI1153 +FPMY0_SI1783 +FPMY0_SI523 +FPMY0_SX163 +FPMY0_SX196 +FPMY0_SX253 +FPMY0_SX343 +FPMY0_SX73 +FREH0_SI1315 +FREH0_SI1945 +FREH0_SI685 +FREH0_SX145 +FREH0_SX235 +FREH0_SX325 +FREH0_SX415 +FREH0_SX55 +FRJB0_SI1427 +FRJB0_SI1470 +FRJB0_SI1794 +FRJB0_SX167 +FRJB0_SX257 +FRJB0_SX347 +FRJB0_SX437 +FRJB0_SX77 +FRLL0_SI1514 +FRLL0_SI805 +FRLL0_SI884 +FRLL0_SX164 +FRLL0_SX254 +FRLL0_SX344 +FRLL0_SX434 +FRLL0_SX74 +FSAG0_SI1323 +FSAG0_SI1953 +FSAG0_SI693 +FSAG0_SX153 +FSAG0_SX243 +FSAG0_SX333 +FSAG0_SX423 +FSAG0_SX63 +FSAH0_SI1244 +FSAH0_SI1874 +FSAH0_SI614 +FSAH0_SX164 +FSAH0_SX327 +FSAH0_SX344 +FSAH0_SX434 +FSAH0_SX74 +FSAK0_SI1300 +FSAK0_SI1930 +FSAK0_SI670 +FSAK0_SX130 +FSAK0_SX220 +FSAK0_SX310 +FSAK0_SX40 +FSAK0_SX400 +FSBK0_SI1069 +FSBK0_SI1699 +FSBK0_SI2329 +FSBK0_SX169 +FSBK0_SX259 +FSBK0_SX349 +FSBK0_SX439 +FSBK0_SX79 +FSCN0_SI1886 +FSCN0_SI626 +FSCN0_SI705 +FSCN0_SX176 +FSCN0_SX266 +FSCN0_SX356 +FSCN0_SX446 +FSCN0_SX86 +FSDC0_SI1312 +FSDC0_SI1942 +FSDC0_SI2234 +FSDC0_SX142 +FSDC0_SX232 +FSDC0_SX322 +FSDC0_SX412 +FSDC0_SX52 +FSDJ0_SI1115 +FSDJ0_SI1745 +FSDJ0_SI485 +FSDJ0_SX125 +FSDJ0_SX215 +FSDJ0_SX305 +FSDJ0_SX35 +FSDJ0_SX395 +FSGF0_SI1557 +FSGF0_SI2187 +FSGF0_SI927 +FSGF0_SX117 +FSGF0_SX207 +FSGF0_SX27 +FSGF0_SX297 +FSGF0_SX387 +FSJG0_SI1570 +FSJG0_SI2200 +FSJG0_SI940 +FSJG0_SX130 +FSJG0_SX220 +FSJG0_SX310 +FSJG0_SX40 +FSJG0_SX400 +FSJK1_SI1025 +FSJK1_SI2285 +FSJK1_SI696 +FSJK1_SX125 +FSJK1_SX215 +FSJK1_SX305 +FSJK1_SX35 +FSJK1_SX395 +FSJS0_SI1171 +FSJS0_SI1801 +FSJS0_SI541 +FSJS0_SX181 +FSJS0_SX271 +FSJS0_SX361 +FSJS0_SX451 +FSJS0_SX91 +FSJW0_SI1333 +FSJW0_SI1963 +FSJW0_SI703 +FSJW0_SX163 +FSJW0_SX253 +FSJW0_SX343 +FSJW0_SX433 +FSJW0_SX73 +FSKC0_SI1416 +FSKC0_SI2046 +FSKC0_SI786 +FSKC0_SX156 +FSKC0_SX246 +FSKC0_SX336 +FSKC0_SX426 +FSKC0_SX66 +FSKL0_SI1529 +FSKL0_SI2159 +FSKL0_SI899 +FSKL0_SX179 +FSKL0_SX269 +FSKL0_SX359 +FSKL0_SX449 +FSKL0_SX89 +FSKP0_SI1098 +FSKP0_SI1728 +FSKP0_SI468 +FSKP0_SX108 +FSKP0_SX18 +FSKP0_SX198 +FSKP0_SX288 +FSKP0_SX378 +FSLS0_SI1056 +FSLS0_SI1686 +FSLS0_SI2316 +FSLS0_SX156 +FSLS0_SX202 +FSLS0_SX246 +FSLS0_SX426 +FSLS0_SX66 +FSMA0_SI1621 +FSMA0_SI2251 +FSMA0_SI991 +FSMA0_SX181 +FSMA0_SX271 +FSMA0_SX361 +FSMA0_SX451 +FSMA0_SX91 +FSMM0_SI1314 +FSMM0_SI1944 +FSMM0_SI684 +FSMM0_SX144 +FSMM0_SX234 +FSMM0_SX324 +FSMM0_SX414 +FSMM0_SX54 +FSMS1_SI1504 +FSMS1_SI2134 +FSMS1_SI874 +FSMS1_SX154 +FSMS1_SX244 +FSMS1_SX334 +FSMS1_SX347 +FSMS1_SX64 +FSPM0_SI1241 +FSPM0_SI1871 +FSPM0_SI611 +FSPM0_SX161 +FSPM0_SX251 +FSPM0_SX341 +FSPM0_SX431 +FSPM0_SX71 +FSRH0_SI1719 +FSRH0_SI1931 +FSRH0_SI671 +FSRH0_SX131 +FSRH0_SX221 +FSRH0_SX311 +FSRH0_SX401 +FSRH0_SX41 +FSSB0_SI1082 +FSSB0_SI1712 +FSSB0_SI2342 +FSSB0_SX182 +FSSB0_SX272 +FSSB0_SX362 +FSSB0_SX452 +FSSB0_SX92 +FTAJ0_SI1329 +FTAJ0_SI474 +FTAJ0_SI699 +FTAJ0_SX159 +FTAJ0_SX249 +FTAJ0_SX339 +FTAJ0_SX429 +FTAJ0_SX69 +FTBR0_SI1402 +FTBR0_SI2181 +FTBR0_SI921 +FTBR0_SX111 +FTBR0_SX201 +FTBR0_SX21 +FTBR0_SX291 +FTBR0_SX381 +FTBW0_SI1345 +FTBW0_SI1975 +FTBW0_SI715 +FTBW0_SX175 +FTBW0_SX265 +FTBW0_SX355 +FTBW0_SX445 +FTBW0_SX85 +FTLG0_SI1743 +FTLG0_SI483 +FTLG0_SI840 +FTLG0_SX123 +FTLG0_SX213 +FTLG0_SX303 +FTLG0_SX33 +FTLG0_SX393 +FTMG0_SI1532 +FTMG0_SI2162 +FTMG0_SI902 +FTMG0_SX182 +FTMG0_SX272 +FTMG0_SX362 +FTMG0_SX452 +FTMG0_SX92 +FVFB0_SI1032 +FVFB0_SI1510 +FVFB0_SI2292 +FVFB0_SX132 +FVFB0_SX222 +FVFB0_SX312 +FVFB0_SX402 +FVFB0_SX42 +FVKB0_SI1159 +FVKB0_SI1789 +FVKB0_SI529 +FVKB0_SX169 +FVKB0_SX259 +FVKB0_SX349 +FVKB0_SX439 +FVKB0_SX79 +FVMH0_SI1466 +FVMH0_SI2096 +FVMH0_SI836 +FVMH0_SX116 +FVMH0_SX206 +FVMH0_SX26 +FVMH0_SX296 +FVMH0_SX386 +MABC0_SI1620 +MABC0_SI2041 +MABC0_SI781 +MABC0_SX151 +MABC0_SX241 +MABC0_SX331 +MABC0_SX421 +MABC0_SX61 +MADC0_SI1367 +MADC0_SI1997 +MADC0_SI737 +MADC0_SX107 +MADC0_SX17 +MADC0_SX197 +MADC0_SX287 +MADC0_SX377 +MADD0_SI1295 +MADD0_SI1798 +MADD0_SI538 +MADD0_SX178 +MADD0_SX268 +MADD0_SX358 +MADD0_SX448 +MADD0_SX88 +MAEB0_SI1411 +MAEB0_SI2250 +MAEB0_SI990 +MAEB0_SX180 +MAEB0_SX270 +MAEB0_SX360 +MAEB0_SX450 +MAEB0_SX90 +MAEO0_SI1326 +MAEO0_SI1655 +MAEO0_SI1956 +MAEO0_SX156 +MAEO0_SX246 +MAEO0_SX336 +MAEO0_SX426 +MAEO0_SX66 +MAFM0_SI1569 +MAFM0_SI2199 +MAFM0_SI939 +MAFM0_SX129 +MAFM0_SX219 +MAFM0_SX309 +MAFM0_SX39 +MAFM0_SX399 +MAJP0_SI1074 +MAJP0_SI1704 +MAJP0_SI2334 +MAJP0_SX174 +MAJP0_SX264 +MAJP0_SX354 +MAJP0_SX444 +MAJP0_SX84 +MAKB0_SI1016 +MAKB0_SI1646 +MAKB0_SI2276 +MAKB0_SX116 +MAKB0_SX206 +MAKB0_SX26 +MAKB0_SX296 +MAKB0_SX386 +MAKR0_SI1352 +MAKR0_SI1982 +MAKR0_SI722 +MAKR0_SX182 +MAKR0_SX272 +MAKR0_SX362 +MAKR0_SX452 +MAKR0_SX92 +MAPV0_SI1293 +MAPV0_SI1923 +MAPV0_SI663 +MAPV0_SX123 +MAPV0_SX213 +MAPV0_SX303 +MAPV0_SX33 +MAPV0_SX393 +MARC0_SI1188 +MARC0_SI1818 +MARC0_SI558 +MARC0_SX108 +MARC0_SX18 +MARC0_SX198 +MARC0_SX288 +MARC0_SX378 +MARW0_SI1276 +MARW0_SI1906 +MARW0_SI646 +MARW0_SX106 +MARW0_SX16 +MARW0_SX286 +MARW0_SX349 +MARW0_SX376 +MBAR0_SI1319 +MBAR0_SI1949 +MBAR0_SI689 +MBAR0_SX149 +MBAR0_SX239 +MBAR0_SX329 +MBAR0_SX419 +MBAR0_SX59 +MBBR0_SI1055 +MBBR0_SI1685 +MBBR0_SI2315 +MBBR0_SX155 +MBBR0_SX245 +MBBR0_SX335 +MBBR0_SX425 +MBBR0_SX65 +MBCG0_SI2217 +MBCG0_SI486 +MBCG0_SI957 +MBCG0_SX147 +MBCG0_SX237 +MBCG0_SX327 +MBCG0_SX417 +MBCG0_SX57 +MBEF0_SI1281 +MBEF0_SI1911 +MBEF0_SI651 +MBEF0_SX111 +MBEF0_SX201 +MBEF0_SX21 +MBEF0_SX291 +MBEF0_SX381 +MBGT0_SI1341 +MBGT0_SI1841 +MBGT0_SI711 +MBGT0_SX171 +MBGT0_SX261 +MBGT0_SX351 +MBGT0_SX441 +MBGT0_SX81 +MBJV0_SI1247 +MBJV0_SI1877 +MBJV0_SI617 +MBJV0_SX167 +MBJV0_SX257 +MBJV0_SX347 +MBJV0_SX437 +MBJV0_SX77 +MBMA0_SI1222 +MBMA0_SI1852 +MBMA0_SI592 +MBMA0_SX142 +MBMA0_SX232 +MBMA0_SX322 +MBMA0_SX412 +MBMA0_SX52 +MBMA1_SI2207 +MBMA1_SI2214 +MBMA1_SI954 +MBMA1_SX144 +MBMA1_SX234 +MBMA1_SX324 +MBMA1_SX414 +MBMA1_SX54 +MBML0_SI1169 +MBML0_SI1799 +MBML0_SI539 +MBML0_SX179 +MBML0_SX269 +MBML0_SX359 +MBML0_SX449 +MBML0_SX89 +MBOM0_SI1014 +MBOM0_SI1644 +MBOM0_SI2274 +MBOM0_SX114 +MBOM0_SX204 +MBOM0_SX294 +MBOM0_SX311 +MBOM0_SX384 +MBSB0_SI1353 +MBSB0_SI1983 +MBSB0_SI723 +MBSB0_SX183 +MBSB0_SX273 +MBSB0_SX3 +MBSB0_SX363 +MBSB0_SX93 +MBTH0_SI2102 +MBTH0_SI505 +MBTH0_SI757 +MBTH0_SX122 +MBTH0_SX212 +MBTH0_SX302 +MBTH0_SX32 +MBTH0_SX392 +MBWP0_SI1531 +MBWP0_SI1969 +MBWP0_SI709 +MBWP0_SX169 +MBWP0_SX259 +MBWP0_SX349 +MBWP0_SX439 +MBWP0_SX79 +MCAE0_SI1447 +MCAE0_SI2077 +MCAE0_SI817 +MCAE0_SX187 +MCAE0_SX277 +MCAE0_SX367 +MCAE0_SX7 +MCAE0_SX97 +MCAL0_SI1138 +MCAL0_SI1768 +MCAL0_SI508 +MCAL0_SX148 +MCAL0_SX238 +MCAL0_SX328 +MCAL0_SX418 +MCAL0_SX58 +MCDC0_SI1292 +MCDC0_SI1922 +MCDC0_SI662 +MCDC0_SX122 +MCDC0_SX212 +MCDC0_SX302 +MCDC0_SX32 +MCDC0_SX392 +MCDD0_SI1513 +MCDD0_SI2143 +MCDD0_SI883 +MCDD0_SX163 +MCDD0_SX253 +MCDD0_SX343 +MCDD0_SX433 +MCDD0_SX73 +MCDR0_SI1154 +MCDR0_SI1784 +MCDR0_SI524 +MCDR0_SX164 +MCDR0_SX254 +MCDR0_SX344 +MCDR0_SX434 +MCDR0_SX74 +MCEF0_SI1135 +MCEF0_SI1765 +MCEF0_SI842 +MCEF0_SX145 +MCEF0_SX235 +MCEF0_SX325 +MCEF0_SX415 +MCEF0_SX55 +MCEW0_SI1442 +MCEW0_SI2072 +MCEW0_SI812 +MCEW0_SX182 +MCEW0_SX272 +MCEW0_SX362 +MCEW0_SX452 +MCEW0_SX92 +MCHL0_SI1347 +MCHL0_SI1404 +MCHL0_SI1977 +MCHL0_SX177 +MCHL0_SX267 +MCHL0_SX357 +MCHL0_SX447 +MCHL0_SX87 +MCLK0_SI1660 +MCLK0_SI2290 +MCLK0_SI650 +MCLK0_SX130 +MCLK0_SX220 +MCLK0_SX310 +MCLK0_SX40 +MCLK0_SX400 +MCLM0_SI1456 +MCLM0_SI2086 +MCLM0_SI826 +MCLM0_SX106 +MCLM0_SX16 +MCLM0_SX196 +MCLM0_SX286 +MCLM0_SX376 +MCPM0_SI1194 +MCPM0_SI1824 +MCPM0_SI564 +MCPM0_SX114 +MCPM0_SX204 +MCPM0_SX24 +MCPM0_SX294 +MCPM0_SX384 +MCRE0_SI1121 +MCRE0_SI1725 +MCRE0_SI1751 +MCRE0_SX131 +MCRE0_SX221 +MCRE0_SX24 +MCRE0_SX401 +MCRE0_SX41 +MCSS0_SI1380 +MCSS0_SI688 +MCSS0_SI750 +MCSS0_SX120 +MCSS0_SX210 +MCSS0_SX30 +MCSS0_SX300 +MCSS0_SX390 +MCTH0_SI1209 +MCTH0_SI1839 +MCTH0_SI579 +MCTH0_SX129 +MCTH0_SX219 +MCTH0_SX309 +MCTH0_SX39 +MCTH0_SX399 +MCTM0_SI1350 +MCTM0_SI1980 +MCTM0_SI720 +MCTM0_SX180 +MCTM0_SX270 +MCTM0_SX360 +MCTM0_SX450 +MCTM0_SX90 +MCXM0_SI1351 +MCXM0_SI1981 +MCXM0_SI721 +MCXM0_SX181 +MCXM0_SX271 +MCXM0_SX361 +MCXM0_SX451 +MCXM0_SX91 +MDAC0_SI1261 +MDAC0_SI1837 +MDAC0_SI631 +MDAC0_SX181 +MDAC0_SX271 +MDAC0_SX361 +MDAC0_SX451 +MDAC0_SX91 +MDAS0_SI1266 +MDAS0_SI1896 +MDAS0_SI636 +MDAS0_SX186 +MDAS0_SX21 +MDAS0_SX276 +MDAS0_SX6 +MDAS0_SX96 +MDBB1_SI1006 +MDBB1_SI1636 +MDBB1_SI2056 +MDBB1_SX106 +MDBB1_SX16 +MDBB1_SX196 +MDBB1_SX286 +MDBB1_SX376 +MDBP0_SI1158 +MDBP0_SI1788 +MDBP0_SI528 +MDBP0_SX168 +MDBP0_SX258 +MDBP0_SX348 +MDBP0_SX438 +MDBP0_SX78 +MDCD0_SI1415 +MDCD0_SI2045 +MDCD0_SI785 +MDCD0_SX155 +MDCD0_SX245 +MDCD0_SX335 +MDCD0_SX425 +MDCD0_SX65 +MDCM0_SI1480 +MDCM0_SI2110 +MDCM0_SI850 +MDCM0_SX130 +MDCM0_SX220 +MDCM0_SX310 +MDCM0_SX40 +MDCM0_SX400 +MDDC0_SI1419 +MDDC0_SI2049 +MDDC0_SI789 +MDDC0_SX159 +MDDC0_SX249 +MDDC0_SX339 +MDDC0_SX429 +MDDC0_SX69 +MDED0_SI1170 +MDED0_SI1800 +MDED0_SI540 +MDED0_SX180 +MDED0_SX270 +MDED0_SX360 +MDED0_SX450 +MDED0_SX90 +MDEF0_SI1123 +MDEF0_SI1563 +MDEF0_SI2193 +MDEF0_SX123 +MDEF0_SX213 +MDEF0_SX303 +MDEF0_SX33 +MDEF0_SX393 +MDEM0_SI1868 +MDEM0_SI608 +MDEM0_SI800 +MDEM0_SX158 +MDEM0_SX248 +MDEM0_SX338 +MDEM0_SX428 +MDEM0_SX68 +MDHL0_SI1439 +MDHL0_SI2069 +MDHL0_SI809 +MDHL0_SX179 +MDHL0_SX269 +MDHL0_SX359 +MDHL0_SX449 +MDHL0_SX89 +MDHS0_SI1530 +MDHS0_SI2160 +MDHS0_SI900 +MDHS0_SX180 +MDHS0_SX270 +MDHS0_SX360 +MDHS0_SX450 +MDHS0_SX90 +MDJM0_SI1455 +MDJM0_SI2085 +MDJM0_SI825 +MDJM0_SX105 +MDJM0_SX15 +MDJM0_SX195 +MDJM0_SX285 +MDJM0_SX375 +MDKS0_SI1066 +MDKS0_SI1696 +MDKS0_SI2326 +MDKS0_SX166 +MDKS0_SX256 +MDKS0_SX346 +MDKS0_SX436 +MDKS0_SX76 +MDLB0_SI1306 +MDLB0_SI1936 +MDLB0_SI676 +MDLB0_SX136 +MDLB0_SX226 +MDLB0_SX316 +MDLB0_SX406 +MDLB0_SX46 +MDLC0_SI1395 +MDLC0_SI2025 +MDLC0_SI765 +MDLC0_SX135 +MDLC0_SX225 +MDLC0_SX315 +MDLC0_SX405 +MDLC0_SX45 +MDLC1_SI1435 +MDLC1_SI2065 +MDLC1_SI2144 +MDLC1_SX175 +MDLC1_SX265 +MDLC1_SX355 +MDLC1_SX445 +MDLC1_SX85 +MDLC2_SI1614 +MDLC2_SI2244 +MDLC2_SI984 +MDLC2_SX174 +MDLC2_SX264 +MDLC2_SX354 +MDLC2_SX444 +MDLC2_SX84 +MDLH0_SI1960 +MDLH0_SI574 +MDLH0_SI700 +MDLH0_SX160 +MDLH0_SX250 +MDLH0_SX340 +MDLH0_SX430 +MDLH0_SX70 +MDLM0_SI1234 +MDLM0_SI1864 +MDLM0_SI604 +MDLM0_SX154 +MDLM0_SX244 +MDLM0_SX334 +MDLM0_SX424 +MDLM0_SX64 +MDLR0_SI1233 +MDLR0_SI1863 +MDLR0_SI603 +MDLR0_SX153 +MDLR0_SX243 +MDLR0_SX333 +MDLR0_SX423 +MDLR0_SX63 +MDLR1_SI1299 +MDLR1_SI1929 +MDLR1_SI669 +MDLR1_SX129 +MDLR1_SX219 +MDLR1_SX309 +MDLR1_SX39 +MDLR1_SX399 +MDMA0_SI1238 +MDMA0_SI1430 +MDMA0_SI2060 +MDMA0_SX170 +MDMA0_SX260 +MDMA0_SX350 +MDMA0_SX440 +MDMA0_SX80 +MDMT0_SI1832 +MDMT0_SI2341 +MDMT0_SI572 +MDMT0_SX122 +MDMT0_SX212 +MDMT0_SX302 +MDMT0_SX32 +MDMT0_SX392 +MDNS0_SI1011 +MDNS0_SI2271 +MDNS0_SI873 +MDNS0_SX111 +MDNS0_SX201 +MDNS0_SX21 +MDNS0_SX291 +MDNS0_SX381 +MDPB0_SI1760 +MDPB0_SI2126 +MDPB0_SI866 +MDPB0_SX146 +MDPB0_SX236 +MDPB0_SX326 +MDPB0_SX416 +MDPB0_SX56 +MDPK0_SI1053 +MDPK0_SI1683 +MDPK0_SI552 +MDPK0_SX153 +MDPK0_SX243 +MDPK0_SX333 +MDPK0_SX423 +MDPK0_SX63 +MDPS0_SI1651 +MDPS0_SI1979 +MDPS0_SI719 +MDPS0_SX179 +MDPS0_SX269 +MDPS0_SX359 +MDPS0_SX449 +MDPS0_SX89 +MDRD0_SI1382 +MDRD0_SI2012 +MDRD0_SI752 +MDRD0_SX122 +MDRD0_SX212 +MDRD0_SX302 +MDRD0_SX32 +MDRD0_SX392 +MDSJ0_SI1462 +MDSJ0_SI2092 +MDSJ0_SI832 +MDSJ0_SX112 +MDSJ0_SX22 +MDSJ0_SX292 +MDSJ0_SX382 +MDSJ0_SX438 +MDSS0_SI1881 +MDSS0_SI2087 +MDSS0_SI621 +MDSS0_SX171 +MDSS0_SX261 +MDSS0_SX351 +MDSS0_SX441 +MDSS0_SX81 +MDSS1_SI1327 +MDSS1_SI1713 +MDSS1_SI697 +MDSS1_SX157 +MDSS1_SX247 +MDSS1_SX337 +MDSS1_SX427 +MDSS1_SX67 +MDTB0_SI1200 +MDTB0_SI1830 +MDTB0_SI570 +MDTB0_SX120 +MDTB0_SX210 +MDTB0_SX300 +MDTB0_SX321 +MDTB0_SX390 +MDWD0_SI1260 +MDWD0_SI1890 +MDWD0_SI557 +MDWD0_SX180 +MDWD0_SX270 +MDWD0_SX360 +MDWD0_SX450 +MDWD0_SX90 +MDWH0_SI1168 +MDWH0_SI1925 +MDWH0_SI665 +MDWH0_SX125 +MDWH0_SX215 +MDWH0_SX305 +MDWH0_SX35 +MDWH0_SX395 +MDWM0_SI1546 +MDWM0_SI2176 +MDWM0_SI916 +MDWM0_SX106 +MDWM0_SX16 +MDWM0_SX286 +MDWM0_SX376 +MDWM0_SX433 +MEAL0_SI1547 +MEAL0_SI2177 +MEAL0_SI917 +MEAL0_SX107 +MEAL0_SX197 +MEAL0_SX287 +MEAL0_SX347 +MEAL0_SX377 +MEDR0_SI1374 +MEDR0_SI2004 +MEDR0_SI744 +MEDR0_SX114 +MEDR0_SX204 +MEDR0_SX24 +MEDR0_SX294 +MEDR0_SX384 +MEFG0_SI465 +MEFG0_SI491 +MEFG0_SI598 +MEFG0_SX105 +MEFG0_SX15 +MEFG0_SX195 +MEFG0_SX285 +MEFG0_SX375 +MEGJ0_SI1337 +MEGJ0_SI1967 +MEGJ0_SI707 +MEGJ0_SX167 +MEGJ0_SX257 +MEGJ0_SX3 +MEGJ0_SX437 +MEGJ0_SX77 +MEJL0_SI1592 +MEJL0_SI1654 +MEJL0_SI962 +MEJL0_SX152 +MEJL0_SX242 +MEJL0_SX332 +MEJL0_SX422 +MEJL0_SX62 +MEJS0_SI1240 +MEJS0_SI1870 +MEJS0_SI610 +MEJS0_SX160 +MEJS0_SX250 +MEJS0_SX340 +MEJS0_SX430 +MEJS0_SX70 +MESG0_SI1332 +MESG0_SI1962 +MESG0_SI702 +MESG0_SX162 +MESG0_SX252 +MESG0_SX342 +MESG0_SX432 +MESG0_SX72 +MESJ0_SI2039 +MESJ0_SI2257 +MESJ0_SI997 +MESJ0_SX187 +MESJ0_SX277 +MESJ0_SX367 +MESJ0_SX7 +MESJ0_SX97 +MEWM0_SI1348 +MEWM0_SI1978 +MEWM0_SI718 +MEWM0_SX178 +MEWM0_SX268 +MEWM0_SX358 +MEWM0_SX448 +MEWM0_SX88 +MFER0_SI1492 +MFER0_SI2122 +MFER0_SI862 +MFER0_SX142 +MFER0_SX232 +MFER0_SX322 +MFER0_SX412 +MFER0_SX52 +MFMC0_SI1132 +MFMC0_SI1762 +MFMC0_SI502 +MFMC0_SX142 +MFMC0_SX232 +MFMC0_SX322 +MFMC0_SX412 +MFMC0_SX52 +MFRM0_SI1155 +MFRM0_SI1717 +MFRM0_SI1785 +MFRM0_SX165 +MFRM0_SX255 +MFRM0_SX345 +MFRM0_SX435 +MFRM0_SX75 +MFWK0_SI1249 +MFWK0_SI1879 +MFWK0_SI619 +MFWK0_SX169 +MFWK0_SX259 +MFWK0_SX349 +MFWK0_SX439 +MFWK0_SX79 +MFXS0_SI1674 +MFXS0_SI2225 +MFXS0_SI2304 +MFXS0_SX144 +MFXS0_SX234 +MFXS0_SX324 +MFXS0_SX414 +MFXS0_SX54 +MFXV0_SI1005 +MFXV0_SI1342 +MFXV0_SI1635 +MFXV0_SX105 +MFXV0_SX15 +MFXV0_SX195 +MFXV0_SX285 +MFXV0_SX375 +MGAF0_SI1282 +MGAF0_SI1912 +MGAF0_SI652 +MGAF0_SX112 +MGAF0_SX202 +MGAF0_SX22 +MGAF0_SX292 +MGAF0_SX382 +MGAG0_SI1321 +MGAG0_SI645 +MGAG0_SI691 +MGAG0_SX151 +MGAG0_SX241 +MGAG0_SX331 +MGAG0_SX421 +MGAG0_SX61 +MGAK0_SI1036 +MGAK0_SI1666 +MGAK0_SI2296 +MGAK0_SX136 +MGAK0_SX226 +MGAK0_SX316 +MGAK0_SX406 +MGAK0_SX46 +MGAR0_SI1212 +MGAR0_SI1694 +MGAR0_SI1842 +MGAR0_SX132 +MGAR0_SX222 +MGAR0_SX312 +MGAR0_SX402 +MGAR0_SX42 +MGAW0_SI1165 +MGAW0_SI1802 +MGAW0_SI535 +MGAW0_SX175 +MGAW0_SX265 +MGAW0_SX355 +MGAW0_SX445 +MGAW0_SX85 +MGES0_SI1481 +MGES0_SI2111 +MGES0_SI851 +MGES0_SX131 +MGES0_SX221 +MGES0_SX311 +MGES0_SX401 +MGES0_SX41 +MGJC0_SI1256 +MGJC0_SI1335 +MGJC0_SI1965 +MGJC0_SX165 +MGJC0_SX255 +MGJC0_SX345 +MGJC0_SX435 +MGJC0_SX75 +MGRL0_SI1497 +MGRL0_SI2127 +MGRL0_SI867 +MGRL0_SX147 +MGRL0_SX237 +MGRL0_SX327 +MGRL0_SX417 +MGRL0_SX57 +MGRP0_SI1317 +MGRP0_SI1947 +MGRP0_SI687 +MGRP0_SX147 +MGRP0_SX237 +MGRP0_SX327 +MGRP0_SX417 +MGRP0_SX57 +MGSH0_SI1176 +MGSH0_SI1806 +MGSH0_SI546 +MGSH0_SX127 +MGSH0_SX186 +MGSH0_SX276 +MGSH0_SX6 +MGSH0_SX96 +MGSL0_SI1164 +MGSL0_SI534 +MGSL0_SI797 +MGSL0_SX174 +MGSL0_SX264 +MGSL0_SX354 +MGSL0_SX444 +MGSL0_SX84 +MGXP0_SI1087 +MGXP0_SI457 +MGXP0_SI525 +MGXP0_SX187 +MGXP0_SX277 +MGXP0_SX367 +MGXP0_SX7 +MGXP0_SX97 +MHBS0_SI1575 +MHBS0_SI2205 +MHBS0_SI945 +MHBS0_SX135 +MHBS0_SX225 +MHBS0_SX315 +MHBS0_SX405 +MHBS0_SX45 +MHIT0_SI1613 +MHIT0_SI2243 +MHIT0_SI983 +MHIT0_SX173 +MHIT0_SX263 +MHIT0_SX353 +MHIT0_SX443 +MHIT0_SX83 +MHJB0_SI1017 +MHJB0_SI1647 +MHJB0_SI2277 +MHJB0_SX117 +MHJB0_SX207 +MHJB0_SX27 +MHJB0_SX297 +MHJB0_SX387 +MHMG0_SI1365 +MHMG0_SI1995 +MHMG0_SI735 +MHMG0_SX105 +MHMG0_SX15 +MHMG0_SX195 +MHMG0_SX285 +MHMG0_SX375 +MHMR0_SI1119 +MHMR0_SI1692 +MHMR0_SI489 +MHMR0_SX129 +MHMR0_SX219 +MHMR0_SX309 +MHMR0_SX39 +MHMR0_SX399 +MHRM0_SI1475 +MHRM0_SI2218 +MHRM0_SI958 +MHRM0_SX148 +MHRM0_SX238 +MHRM0_SX328 +MHRM0_SX418 +MHRM0_SX58 +MHXL0_SI1772 +MHXL0_SI512 +MHXL0_SI612 +MHXL0_SX152 +MHXL0_SX242 +MHXL0_SX332 +MHXL0_SX422 +MHXL0_SX62 +MILB0_SI2163 +MILB0_SI807 +MILB0_SI903 +MILB0_SX183 +MILB0_SX273 +MILB0_SX3 +MILB0_SX363 +MILB0_SX93 +MJAC0_SI1331 +MJAC0_SI2148 +MJAC0_SI701 +MJAC0_SX251 +MJAC0_SX307 +MJAC0_SX341 +MJAC0_SX431 +MJAC0_SX71 +MJAE0_SI1524 +MJAE0_SI1999 +MJAE0_SI2154 +MJAE0_SX174 +MJAE0_SX264 +MJAE0_SX354 +MJAE0_SX444 +MJAE0_SX84 +MJAI0_SI1604 +MJAI0_SI682 +MJAI0_SI710 +MJAI0_SX164 +MJAI0_SX254 +MJAI0_SX344 +MJAI0_SX434 +MJAI0_SX74 +MJBG0_SI1232 +MJBG0_SI1724 +MJBG0_SI1862 +MJBG0_SX152 +MJBG0_SX242 +MJBG0_SX332 +MJBG0_SX422 +MJBG0_SX62 +MJDA0_SI1031 +MJDA0_SI1661 +MJDA0_SI2291 +MJDA0_SX131 +MJDA0_SX221 +MJDA0_SX311 +MJDA0_SX401 +MJDA0_SX41 +MJDC0_SI1161 +MJDC0_SI2165 +MJDC0_SI531 +MJDC0_SX171 +MJDC0_SX261 +MJDC0_SX351 +MJDC0_SX441 +MJDC0_SX81 +MJDE0_SI1120 +MJDE0_SI463 +MJDE0_SI490 +MJDE0_SX130 +MJDE0_SX220 +MJDE0_SX310 +MJDE0_SX40 +MJDE0_SX400 +MJDG0_SI1042 +MJDG0_SI1672 +MJDG0_SI1705 +MJDG0_SX142 +MJDG0_SX232 +MJDG0_SX322 +MJDG0_SX412 +MJDG0_SX52 +MJDM0_SI1340 +MJDM0_SI1937 +MJDM0_SI974 +MJDM0_SX170 +MJDM0_SX260 +MJDM0_SX350 +MJDM0_SX440 +MJDM0_SX80 +MJEB0_SI1286 +MJEB0_SI1916 +MJEB0_SI656 +MJEB0_SX170 +MJEB0_SX206 +MJEB0_SX26 +MJEB0_SX296 +MJEB0_SX386 +MJEB1_SI1467 +MJEB1_SI2097 +MJEB1_SI837 +MJEB1_SX117 +MJEB1_SX207 +MJEB1_SX27 +MJEB1_SX297 +MJEB1_SX387 +MJEE0_SI1237 +MJEE0_SI1867 +MJEE0_SI607 +MJEE0_SX157 +MJEE0_SX247 +MJEE0_SX337 +MJEE0_SX427 +MJEE0_SX67 +MJFH0_SI1107 +MJFH0_SI1737 +MJFH0_SI477 +MJFH0_SX117 +MJFH0_SX207 +MJFH0_SX27 +MJFH0_SX297 +MJFH0_SX387 +MJFR0_SI1605 +MJFR0_SI2235 +MJFR0_SI975 +MJFR0_SX165 +MJFR0_SX255 +MJFR0_SX345 +MJFR0_SX435 +MJFR0_SX75 +MJHI0_SI1328 +MJHI0_SI555 +MJHI0_SI698 +MJHI0_SX158 +MJHI0_SX248 +MJHI0_SX338 +MJHI0_SX428 +MJHI0_SX68 +MJJB0_SI1139 +MJJB0_SI1277 +MJJB0_SI1769 +MJJB0_SX149 +MJJB0_SX239 +MJJB0_SX329 +MJJB0_SX419 +MJJB0_SX59 +MJJJ0_SI1163 +MJJJ0_SI1793 +MJJJ0_SI533 +MJJJ0_SX173 +MJJJ0_SX263 +MJJJ0_SX353 +MJJJ0_SX443 +MJJJ0_SX83 +MJJM0_SI1251 +MJJM0_SI1457 +MJJM0_SI827 +MJJM0_SX107 +MJJM0_SX17 +MJJM0_SX197 +MJJM0_SX287 +MJJM0_SX377 +MJKR0_SI1201 +MJKR0_SI1831 +MJKR0_SI571 +MJKR0_SX121 +MJKR0_SX211 +MJKR0_SX301 +MJKR0_SX31 +MJKR0_SX391 +MJLB0_SI1616 +MJLB0_SI2246 +MJLB0_SI986 +MJLB0_SX176 +MJLB0_SX266 +MJLB0_SX356 +MJLB0_SX446 +MJLB0_SX86 +MJLG1_SI1012 +MJLG1_SI1642 +MJLG1_SI2272 +MJLG1_SX112 +MJLG1_SX202 +MJLG1_SX22 +MJLG1_SX292 +MJLG1_SX382 +MJLS0_SI1096 +MJLS0_SI1726 +MJLS0_SI466 +MJLS0_SX106 +MJLS0_SX16 +MJLS0_SX196 +MJLS0_SX286 +MJLS0_SX376 +MJMA0_SI1495 +MJMA0_SI2125 +MJMA0_SI865 +MJMA0_SX145 +MJMA0_SX235 +MJMA0_SX325 +MJMA0_SX415 +MJMA0_SX55 +MJMD0_SI1028 +MJMD0_SI1658 +MJMD0_SI2288 +MJMD0_SX128 +MJMD0_SX218 +MJMD0_SX308 +MJMD0_SX38 +MJMD0_SX398 +MJMM0_SI1255 +MJMM0_SI1885 +MJMM0_SI625 +MJMM0_SX175 +MJMM0_SX265 +MJMM0_SX355 +MJMM0_SX445 +MJMM0_SX85 +MJPG0_SI1191 +MJPG0_SI1821 +MJPG0_SI561 +MJPG0_SX111 +MJPG0_SX201 +MJPG0_SX21 +MJPG0_SX291 +MJPG0_SX381 +MJPM0_SI1368 +MJPM0_SI1998 +MJPM0_SI738 +MJPM0_SX108 +MJPM0_SX18 +MJPM0_SX198 +MJPM0_SX288 +MJPM0_SX378 +MJPM1_SI1897 +MJPM1_SI2280 +MJPM1_SI761 +MJPM1_SX131 +MJPM1_SX221 +MJPM1_SX311 +MJPM1_SX401 +MJPM1_SX41 +MJRA0_SI1236 +MJRA0_SI1866 +MJRA0_SI606 +MJRA0_SX156 +MJRA0_SX246 +MJRA0_SX336 +MJRA0_SX426 +MJRA0_SX66 +MJRG0_SI1366 +MJRG0_SI1996 +MJRG0_SI736 +MJRG0_SX106 +MJRG0_SX16 +MJRG0_SX286 +MJRG0_SX352 +MJRG0_SX376 +MJRH0_SI1125 +MJRH0_SI1755 +MJRH0_SI1840 +MJRH0_SX135 +MJRH0_SX225 +MJRH0_SX315 +MJRH0_SX405 +MJRH0_SX45 +MJRH1_SI1558 +MJRH1_SI1774 +MJRH1_SI514 +MJRH1_SX154 +MJRH1_SX244 +MJRH1_SX334 +MJRH1_SX424 +MJRH1_SX64 +MJRK0_SI1662 +MJRK0_SI2103 +MJRK0_SI880 +MJRK0_SX160 +MJRK0_SX250 +MJRK0_SX340 +MJRK0_SX430 +MJRK0_SX70 +MJRP0_SI1835 +MJRP0_SI1845 +MJRP0_SI585 +MJRP0_SX135 +MJRP0_SX225 +MJRP0_SX315 +MJRP0_SX405 +MJRP0_SX45 +MJSR0_SI1424 +MJSR0_SI2054 +MJSR0_SI794 +MJSR0_SX164 +MJSR0_SX254 +MJSR0_SX344 +MJSR0_SX434 +MJSR0_SX74 +MJWG0_SI2155 +MJWG0_SI813 +MJWG0_SI895 +MJWG0_SX175 +MJWG0_SX265 +MJWG0_SX355 +MJWG0_SX445 +MJWG0_SX85 +MJWS0_SI1143 +MJWS0_SI1773 +MJWS0_SI513 +MJWS0_SX153 +MJWS0_SX243 +MJWS0_SX333 +MJWS0_SX423 +MJWS0_SX63 +MJWT0_SI1291 +MJWT0_SI1381 +MJWT0_SI751 +MJWT0_SX121 +MJWT0_SX211 +MJWT0_SX301 +MJWT0_SX31 +MJWT0_SX391 +MJXA0_SI1507 +MJXA0_SI2137 +MJXA0_SI877 +MJXA0_SX157 +MJXA0_SX247 +MJXA0_SX337 +MJXA0_SX427 +MJXA0_SX67 +MJXL0_SI1172 +MJXL0_SI1795 +MJXL0_SI542 +MJXL0_SX182 +MJXL0_SX272 +MJXL0_SX362 +MJXL0_SX452 +MJXL0_SX92 +MKAG0_SI1609 +MKAG0_SI2239 +MKAG0_SI979 +MKAG0_SX169 +MKAG0_SX259 +MKAG0_SX30 +MKAG0_SX439 +MKAG0_SX79 +MKAH0_SI1528 +MKAH0_SI2158 +MKAH0_SI898 +MKAH0_SX178 +MKAH0_SX268 +MKAH0_SX358 +MKAH0_SX448 +MKAH0_SX88 +MKAJ0_SI1414 +MKAJ0_SI2044 +MKAJ0_SI784 +MKAJ0_SX154 +MKAJ0_SX244 +MKAJ0_SX334 +MKAJ0_SX424 +MKAJ0_SX64 +MKAM0_SI1250 +MKAM0_SI1316 +MKAM0_SI1465 +MKAM0_SX146 +MKAM0_SX236 +MKAM0_SX326 +MKAM0_SX416 +MKAM0_SX56 +MKDB0_SI2132 +MKDB0_SI588 +MKDB0_SI872 +MKDB0_SX152 +MKDB0_SX242 +MKDB0_SX332 +MKDB0_SX422 +MKDB0_SX62 +MKDD0_SI1567 +MKDD0_SI2197 +MKDD0_SI937 +MKDD0_SX127 +MKDD0_SX217 +MKDD0_SX307 +MKDD0_SX37 +MKDD0_SX397 +MKDT0_SI2153 +MKDT0_SI814 +MKDT0_SI893 +MKDT0_SX173 +MKDT0_SX263 +MKDT0_SX353 +MKDT0_SX443 +MKDT0_SX83 +MKES0_SI1253 +MKES0_SI1883 +MKES0_SI623 +MKES0_SX173 +MKES0_SX263 +MKES0_SX353 +MKES0_SX443 +MKES0_SX83 +MKJO0_SI1517 +MKJO0_SI2147 +MKJO0_SI887 +MKJO0_SX167 +MKJO0_SX257 +MKJO0_SX424 +MKJO0_SX437 +MKJO0_SX77 +MKLN0_SI1598 +MKLN0_SI2228 +MKLN0_SI968 +MKLN0_SX158 +MKLN0_SX248 +MKLN0_SX338 +MKLN0_SX428 +MKLN0_SX68 +MKLR0_SI1059 +MKLR0_SI1689 +MKLR0_SI2319 +MKLR0_SX159 +MKLR0_SX249 +MKLR0_SX339 +MKLR0_SX429 +MKLR0_SX69 +MKLS0_SI1437 +MKLS0_SI1533 +MKLS0_SI2067 +MKLS0_SX177 +MKLS0_SX267 +MKLS0_SX357 +MKLS0_SX447 +MKLS0_SX87 +MKLS1_SI1545 +MKLS1_SI2175 +MKLS1_SI915 +MKLS1_SX105 +MKLS1_SX15 +MKLS1_SX195 +MKLS1_SX285 +MKLS1_SX375 +MKLW0_SI1571 +MKLW0_SI1844 +MKLW0_SI2201 +MKLW0_SX131 +MKLW0_SX221 +MKLW0_SX311 +MKLW0_SX401 +MKLW0_SX41 +MKRG0_SI1491 +MKRG0_SI2121 +MKRG0_SI861 +MKRG0_SX141 +MKRG0_SX231 +MKRG0_SX31 +MKRG0_SX411 +MKRG0_SX51 +MKXL0_SI1185 +MKXL0_SI1815 +MKXL0_SI1958 +MKXL0_SX105 +MKXL0_SX15 +MKXL0_SX195 +MKXL0_SX285 +MKXL0_SX375 +MLBC0_SI1239 +MLBC0_SI1869 +MLBC0_SI609 +MLBC0_SX159 +MLBC0_SX249 +MLBC0_SX339 +MLBC0_SX429 +MLBC0_SX69 +MLEL0_SI1246 +MLEL0_SI1876 +MLEL0_SI616 +MLEL0_SX166 +MLEL0_SX256 +MLEL0_SX346 +MLEL0_SX436 +MLEL0_SX76 +MLJC0_SI1225 +MLJC0_SI1855 +MLJC0_SI595 +MLJC0_SX145 +MLJC0_SX235 +MLJC0_SX325 +MLJC0_SX415 +MLJC0_SX55 +MLJH0_SI1324 +MLJH0_SI1422 +MLJH0_SI694 +MLJH0_SX154 +MLJH0_SX244 +MLJH0_SX334 +MLJH0_SX424 +MLJH0_SX64 +MLNS0_SI1407 +MLNS0_SI2037 +MLNS0_SI777 +MLNS0_SX147 +MLNS0_SX237 +MLNS0_SX327 +MLNS0_SX417 +MLNS0_SX57 +MLSH0_SI1417 +MLSH0_SI2047 +MLSH0_SI787 +MLSH0_SX157 +MLSH0_SX247 +MLSH0_SX337 +MLSH0_SX427 +MLSH0_SX67 +MMAA0_SI1588 +MMAA0_SI2105 +MMAA0_SI845 +MMAA0_SX125 +MMAA0_SX215 +MMAA0_SX305 +MMAA0_SX35 +MMAA0_SX395 +MMAB1_SI1494 +MMAB1_SI2124 +MMAB1_SI864 +MMAB1_SX144 +MMAB1_SX234 +MMAB1_SX324 +MMAB1_SX414 +MMAB1_SX54 +MMAG0_SI1126 +MMAG0_SI1756 +MMAG0_SI496 +MMAG0_SX136 +MMAG0_SX226 +MMAG0_SX316 +MMAG0_SX406 +MMAG0_SX46 +MMAM0_SI1597 +MMAM0_SI1668 +MMAM0_SI2227 +MMAM0_SX157 +MMAM0_SX247 +MMAM0_SX337 +MMAM0_SX427 +MMAM0_SX67 +MMAR0_SI1336 +MMAR0_SI1966 +MMAR0_SI706 +MMAR0_SX166 +MMAR0_SX256 +MMAR0_SX346 +MMAR0_SX436 +MMAR0_SX76 +MMBS0_SI1151 +MMBS0_SI1781 +MMBS0_SI521 +MMBS0_SX161 +MMBS0_SX251 +MMBS0_SX341 +MMBS0_SX431 +MMBS0_SX71 +MMCC0_SI1338 +MMCC0_SI1968 +MMCC0_SI708 +MMCC0_SX168 +MMCC0_SX258 +MMCC0_SX348 +MMCC0_SX438 +MMCC0_SX78 +MMDB0_SI1358 +MMDB0_SI1617 +MMDB0_SI987 +MMDB0_SX177 +MMDB0_SX267 +MMDB0_SX357 +MMDB0_SX447 +MMDB0_SX87 +MMDG0_SI1780 +MMDG0_SI2035 +MMDG0_SI520 +MMDG0_SX160 +MMDG0_SX250 +MMDG0_SX340 +MMDG0_SX430 +MMDG0_SX70 +MMDM0_SI1311 +MMDM0_SI1941 +MMDM0_SI681 +MMDM0_SX141 +MMDM0_SX231 +MMDM0_SX321 +MMDM0_SX411 +MMDM0_SX51 +MMDM1_SI1650 +MMDM1_SI2043 +MMDM1_SI783 +MMDM1_SX153 +MMDM1_SX243 +MMDM1_SX333 +MMDM1_SX423 +MMDM1_SX63 +MMDS0_SI1343 +MMDS0_SI1973 +MMDS0_SI713 +MMDS0_SX173 +MMDS0_SX263 +MMDS0_SX353 +MMDS0_SX443 +MMDS0_SX83 +MMEA0_SI1388 +MMEA0_SI2018 +MMEA0_SI758 +MMEA0_SX128 +MMEA0_SX218 +MMEA0_SX308 +MMEA0_SX38 +MMEA0_SX398 +MMEB0_SI1357 +MMEB0_SI1987 +MMEB0_SI727 +MMEB0_SX187 +MMEB0_SX327 +MMEB0_SX367 +MMEB0_SX7 +MMEB0_SX97 +MMGC0_SI1305 +MMGC0_SI1935 +MMGC0_SI2184 +MMGC0_SX135 +MMGC0_SX225 +MMGC0_SX315 +MMGC0_SX405 +MMGC0_SX45 +MMGG0_SI1079 +MMGG0_SI1709 +MMGG0_SI2339 +MMGG0_SX179 +MMGG0_SX269 +MMGG0_SX359 +MMGG0_SX449 +MMGG0_SX89 +MMGK0_SI1322 +MMGK0_SI1952 +MMGK0_SI692 +MMGK0_SX152 +MMGK0_SX242 +MMGK0_SX332 +MMGK0_SX422 +MMGK0_SX62 +MMJB1_SI1408 +MMJB1_SI2038 +MMJB1_SI778 +MMJB1_SX148 +MMJB1_SX238 +MMJB1_SX328 +MMJB1_SX418 +MMJB1_SX58 +MMLM0_SI1527 +MMLM0_SI2150 +MMLM0_SI897 +MMLM0_SX177 +MMLM0_SX267 +MMLM0_SX357 +MMLM0_SX447 +MMLM0_SX87 +MMPM0_SI1061 +MMPM0_SI1691 +MMPM0_SI2321 +MMPM0_SX161 +MMPM0_SX251 +MMPM0_SX341 +MMPM0_SX431 +MMPM0_SX71 +MMRP0_SI2034 +MMRP0_SI717 +MMRP0_SI774 +MMRP0_SX144 +MMRP0_SX234 +MMRP0_SX324 +MMRP0_SX414 +MMRP0_SX54 +MMSM0_SI1106 +MMSM0_SI1736 +MMSM0_SI476 +MMSM0_SX116 +MMSM0_SX206 +MMSM0_SX26 +MMSM0_SX296 +MMSM0_SX386 +MMVP0_SI1284 +MMVP0_SI1914 +MMVP0_SI654 +MMVP0_SX114 +MMVP0_SX204 +MMVP0_SX294 +MMVP0_SX347 +MMVP0_SX384 +MMWB0_SI1619 +MMWB0_SI2249 +MMWB0_SI989 +MMWB0_SX179 +MMWB0_SX269 +MMWB0_SX359 +MMWB0_SX449 +MMWB0_SX89 +MMWS0_SI1518 +MMWS0_SI559 +MMWS0_SI888 +MMWS0_SX168 +MMWS0_SX258 +MMWS0_SX348 +MMWS0_SX438 +MMWS0_SX78 +MMWS1_SI1071 +MMWS1_SI1701 +MMWS1_SI2331 +MMWS1_SX261 +MMWS1_SX27 +MMWS1_SX351 +MMWS1_SX441 +MMWS1_SX81 +MMXS0_SI2136 +MMXS0_SI629 +MMXS0_SI876 +MMXS0_SX156 +MMXS0_SX246 +MMXS0_SX336 +MMXS0_SX426 +MMXS0_SX66 +MNET0_SI1446 +MNET0_SI2076 +MNET0_SI816 +MNET0_SX186 +MNET0_SX276 +MNET0_SX366 +MNET0_SX6 +MNET0_SX96 +MNTW0_SI1068 +MNTW0_SI1698 +MNTW0_SI2328 +MNTW0_SX168 +MNTW0_SX202 +MNTW0_SX258 +MNTW0_SX348 +MNTW0_SX78 +MPAR0_SI1576 +MPAR0_SI2206 +MPAR0_SI946 +MPAR0_SX136 +MPAR0_SX226 +MPAR0_SX316 +MPAR0_SX406 +MPAR0_SX46 +MPEB0_SI1034 +MPEB0_SI1860 +MPEB0_SI600 +MPEB0_SX150 +MPEB0_SX240 +MPEB0_SX330 +MPEB0_SX420 +MPEB0_SX60 +MPFU0_SI1258 +MPFU0_SI1888 +MPFU0_SI628 +MPFU0_SX178 +MPFU0_SX268 +MPFU0_SX358 +MPFU0_SX448 +MPFU0_SX88 +MPGH0_SI1554 +MPGH0_SI675 +MPGH0_SI924 +MPGH0_SX114 +MPGH0_SX204 +MPGH0_SX24 +MPGH0_SX294 +MPGH0_SX384 +MPGR0_SI1410 +MPGR0_SI2040 +MPGR0_SI780 +MPGR0_SX150 +MPGR0_SX240 +MPGR0_SX330 +MPGR0_SX420 +MPGR0_SX60 +MPGR1_SI1269 +MPGR1_SI1499 +MPGR1_SI2129 +MPGR1_SX149 +MPGR1_SX239 +MPGR1_SX329 +MPGR1_SX419 +MPGR1_SX59 +MPMB0_SI1501 +MPMB0_SI2131 +MPMB0_SI871 +MPMB0_SX151 +MPMB0_SX241 +MPMB0_SX331 +MPMB0_SX421 +MPMB0_SX61 +MPPC0_SI1412 +MPPC0_SI2042 +MPPC0_SI782 +MPPC0_SX152 +MPPC0_SX242 +MPPC0_SX332 +MPPC0_SX422 +MPPC0_SX62 +MPRB0_SI1205 +MPRB0_SI1215 +MPRB0_SI575 +MPRB0_SX125 +MPRB0_SX215 +MPRB0_SX305 +MPRB0_SX35 +MPRB0_SX395 +MPRD0_SI1431 +MPRD0_SI2061 +MPRD0_SI801 +MPRD0_SX171 +MPRD0_SX261 +MPRD0_SX351 +MPRD0_SX441 +MPRD0_SX81 +MPRK0_SI1097 +MPRK0_SI1727 +MPRK0_SI467 +MPRK0_SX107 +MPRK0_SX17 +MPRK0_SX197 +MPRK0_SX287 +MPRK0_SX377 +MPRT0_SI1210 +MPRT0_SI495 +MPRT0_SI580 +MPRT0_SX130 +MPRT0_SX220 +MPRT0_SX310 +MPRT0_SX40 +MPRT0_SX400 +MPSW0_SI1067 +MPSW0_SI1697 +MPSW0_SI2327 +MPSW0_SX167 +MPSW0_SX24 +MPSW0_SX257 +MPSW0_SX437 +MPSW0_SX77 +MRAB0_SI1224 +MRAB0_SI1854 +MRAB0_SI594 +MRAB0_SX144 +MRAB0_SX234 +MRAB0_SX324 +MRAB0_SX414 +MRAB0_SX54 +MRAB1_SI1478 +MRAB1_SI2108 +MRAB1_SI848 +MRAB1_SX128 +MRAB1_SX218 +MRAB1_SX308 +MRAB1_SX38 +MRAB1_SX398 +MRAI0_SI1954 +MRAI0_SI2052 +MRAI0_SI792 +MRAI0_SX162 +MRAI0_SX252 +MRAI0_SX342 +MRAI0_SX432 +MRAI0_SX72 +MRAM0_SI1275 +MRAM0_SI1905 +MRAM0_SI1951 +MRAM0_SX105 +MRAM0_SX15 +MRAM0_SX195 +MRAM0_SX285 +MRAM0_SX375 +MRAV0_SI1008 +MRAV0_SI1638 +MRAV0_SI2268 +MRAV0_SX108 +MRAV0_SX18 +MRAV0_SX198 +MRAV0_SX288 +MRAV0_SX378 +MRBC0_SI1665 +MRBC0_SI1859 +MRBC0_SI599 +MRBC0_SX149 +MRBC0_SX239 +MRBC0_SX329 +MRBC0_SX419 +MRBC0_SX59 +MRCG0_SI1428 +MRCG0_SI2058 +MRCG0_SI798 +MRCG0_SX168 +MRCG0_SX258 +MRCG0_SX348 +MRCG0_SX438 +MRCG0_SX78 +MRCW0_SI1371 +MRCW0_SI2001 +MRCW0_SI741 +MRCW0_SX111 +MRCW0_SX201 +MRCW0_SX21 +MRCW0_SX291 +MRCW0_SX381 +MRDD0_SI1050 +MRDD0_SI1680 +MRDD0_SI2310 +MRDD0_SX150 +MRDD0_SX240 +MRDD0_SX277 +MRDD0_SX330 +MRDD0_SX60 +MRDM0_SI1044 +MRDM0_SI1595 +MRDM0_SI965 +MRDM0_SX155 +MRDM0_SX245 +MRDM0_SX335 +MRDM0_SX425 +MRDM0_SX65 +MRDS0_SI1167 +MRDS0_SI1797 +MRDS0_SI537 +MRDS0_SX177 +MRDS0_SX267 +MRDS0_SX357 +MRDS0_SX447 +MRDS0_SX87 +MREE0_SI1104 +MREE0_SI1734 +MREE0_SI1959 +MREE0_SX114 +MREE0_SX204 +MREE0_SX24 +MREE0_SX294 +MREE0_SX384 +MREH1_SI1599 +MREH1_SI2229 +MREH1_SI969 +MREH1_SX159 +MREH1_SX249 +MREH1_SX339 +MREH1_SX429 +MREH1_SX69 +MREM0_SI1591 +MREM0_SI511 +MREM0_SI961 +MREM0_SX151 +MREM0_SX241 +MREM0_SX331 +MREM0_SX421 +MREM0_SX61 +MREW1_SI1500 +MREW1_SI2130 +MREW1_SI870 +MREW1_SX150 +MREW1_SX240 +MREW1_SX330 +MREW1_SX420 +MREW1_SX60 +MRFK0_SI1076 +MRFK0_SI1706 +MRFK0_SI2336 +MRFK0_SX176 +MRFK0_SX266 +MRFK0_SX356 +MRFK0_SX446 +MRFK0_SX86 +MRFL0_SI1156 +MRFL0_SI1786 +MRFL0_SI526 +MRFL0_SX166 +MRFL0_SX256 +MRFL0_SX346 +MRFL0_SX436 +MRFL0_SX76 +MRGM0_SI1162 +MRGM0_SI1792 +MRGM0_SI532 +MRGM0_SX172 +MRGM0_SX262 +MRGM0_SX416 +MRGM0_SX442 +MRGM0_SX82 +MRGS0_SI1356 +MRGS0_SI1986 +MRGS0_SI726 +MRGS0_SX186 +MRGS0_SX276 +MRGS0_SX366 +MRGS0_SX6 +MRGS0_SX96 +MRHL0_SI1515 +MRHL0_SI2145 +MRHL0_SI885 +MRHL0_SX165 +MRHL0_SX255 +MRHL0_SX345 +MRHL0_SX435 +MRHL0_SX75 +MRJB1_SI1020 +MRJB1_SI1413 +MRJB1_SI2021 +MRJB1_SX120 +MRJB1_SX210 +MRJB1_SX30 +MRJB1_SX300 +MRJB1_SX390 +MRJH0_SI1519 +MRJH0_SI889 +MRJH0_SI914 +MRJH0_SX169 +MRJH0_SX259 +MRJH0_SX307 +MRJH0_SX439 +MRJH0_SX79 +MRJM0_SI1095 +MRJM0_SI1228 +MRJM0_SI1858 +MRJM0_SX148 +MRJM0_SX238 +MRJM0_SX328 +MRJM0_SX418 +MRJM0_SX58 +MRJM1_SI1298 +MRJM1_SI1928 +MRJM1_SI668 +MRJM1_SX128 +MRJM1_SX218 +MRJM1_SX308 +MRJM1_SX38 +MRJM1_SX398 +MRJT0_SI1498 +MRJT0_SI1805 +MRJT0_SI868 +MRJT0_SX148 +MRJT0_SX238 +MRJT0_SX328 +MRJT0_SX418 +MRJT0_SX58 +MRKM0_SI1267 +MRKM0_SI1391 +MRKM0_SI637 +MRKM0_SX187 +MRKM0_SX277 +MRKM0_SX367 +MRKM0_SX7 +MRKM0_SX97 +MRLD0_SI1594 +MRLD0_SI2224 +MRLD0_SI964 +MRLD0_SX154 +MRLD0_SX244 +MRLD0_SX334 +MRLD0_SX424 +MRLD0_SX64 +MRLJ0_SI1420 +MRLJ0_SI2050 +MRLJ0_SI790 +MRLJ0_SX160 +MRLJ0_SX250 +MRLJ0_SX340 +MRLJ0_SX430 +MRLJ0_SX70 +MRLJ1_SI1671 +MRLJ1_SI2301 +MRLJ1_SI2332 +MRLJ1_SX141 +MRLJ1_SX231 +MRLJ1_SX321 +MRLJ1_SX411 +MRLJ1_SX51 +MRLK0_SI1468 +MRLK0_SI2140 +MRLK0_SI843 +MRLK0_SX123 +MRLK0_SX213 +MRLK0_SX303 +MRLK0_SX33 +MRLK0_SX393 +MRLR0_SI1196 +MRLR0_SI1826 +MRLR0_SI566 +MRLR0_SX116 +MRLR0_SX206 +MRLR0_SX26 +MRLR0_SX296 +MRLR0_SX386 +MRMB0_SI1581 +MRMB0_SI2211 +MRMB0_SI951 +MRMB0_SX141 +MRMB0_SX231 +MRMB0_SX321 +MRMB0_SX411 +MRMB0_SX51 +MRMG0_SI1080 +MRMG0_SI1710 +MRMG0_SI2340 +MRMG0_SX180 +MRMG0_SX270 +MRMG0_SX360 +MRMG0_SX450 +MRMG0_SX90 +MRMH0_SI1021 +MRMH0_SI1349 +MRMH0_SI2281 +MRMH0_SX121 +MRMH0_SX211 +MRMH0_SX301 +MRMH0_SX31 +MRMH0_SX391 +MRML0_SI1421 +MRML0_SI2051 +MRML0_SI791 +MRML0_SX161 +MRML0_SX251 +MRML0_SX341 +MRML0_SX431 +MRML0_SX71 +MRMS0_SI1113 +MRMS0_SI2057 +MRMS0_SI2100 +MRMS0_SX120 +MRMS0_SX210 +MRMS0_SX30 +MRMS0_SX300 +MRMS0_SX390 +MRPC1_SI1482 +MRPC1_SI2026 +MRPC1_SI2112 +MRPC1_SX132 +MRPC1_SX222 +MRPC1_SX312 +MRPC1_SX402 +MRPC1_SX42 +MRRE0_SI1334 +MRRE0_SI704 +MRRE0_SI952 +MRRE0_SX164 +MRRE0_SX254 +MRRE0_SX344 +MRRE0_SX434 +MRRE0_SX74 +MRSO0_SI1206 +MRSO0_SI1659 +MRSO0_SI2289 +MRSO0_SX129 +MRSO0_SX219 +MRSO0_SX309 +MRSO0_SX39 +MRSO0_SX399 +MRSP0_SI1429 +MRSP0_SI2059 +MRSP0_SI799 +MRSP0_SX169 +MRSP0_SX196 +MRSP0_SX259 +MRSP0_SX439 +MRSP0_SX79 +MRTC0_SI1458 +MRTC0_SI2088 +MRTC0_SI828 +MRTC0_SX108 +MRTC0_SX18 +MRTC0_SX198 +MRTC0_SX288 +MRTC0_SX378 +MRTJ0_SI1551 +MRTJ0_SI2032 +MRTJ0_SI772 +MRTJ0_SX142 +MRTJ0_SX232 +MRTJ0_SX322 +MRTJ0_SX412 +MRTJ0_SX52 +MRVG0_SI1140 +MRVG0_SI1770 +MRVG0_SI510 +MRVG0_SX150 +MRVG0_SX240 +MRVG0_SX330 +MRVG0_SX420 +MRVG0_SX60 +MRWA0_SI1603 +MRWA0_SI2233 +MRWA0_SI973 +MRWA0_SX163 +MRWA0_SX253 +MRWA0_SX343 +MRWA0_SX433 +MRWA0_SX73 +MRWS0_SI1102 +MRWS0_SI1732 +MRWS0_SI472 +MRWS0_SX112 +MRWS0_SX202 +MRWS0_SX22 +MRWS0_SX292 +MRWS0_SX382 +MRXB0_SI1585 +MRXB0_SI2215 +MRXB0_SI955 +MRXB0_SX145 +MRXB0_SX235 +MRXB0_SX325 +MRXB0_SX415 +MRXB0_SX55 +MSAH1_SI1049 +MSAH1_SI1679 +MSAH1_SI2309 +MSAH1_SX149 +MSAH1_SX239 +MSAH1_SX329 +MSAH1_SX419 +MSAH1_SX59 +MSAS0_SI1376 +MSAS0_SI2006 +MSAS0_SI746 +MSAS0_SX116 +MSAS0_SX206 +MSAS0_SX26 +MSAS0_SX296 +MSAS0_SX386 +MSAT0_SI1526 +MSAT0_SI2156 +MSAT0_SI896 +MSAT0_SX176 +MSAT0_SX266 +MSAT0_SX356 +MSAT0_SX446 +MSAT0_SX86 +MSAT1_SI1073 +MSAT1_SI1703 +MSAT1_SI2333 +MSAT1_SX173 +MSAT1_SX263 +MSAT1_SX353 +MSAT1_SX443 +MSAT1_SX83 +MSDB0_SI1007 +MSDB0_SI1637 +MSDB0_SI2267 +MSDB0_SX107 +MSDB0_SX17 +MSDB0_SX197 +MSDB0_SX287 +MSDB0_SX377 +MSDH0_SI2113 +MSDH0_SI2240 +MSDH0_SI980 +MSDH0_SX170 +MSDH0_SX260 +MSDH0_SX350 +MSDH0_SX440 +MSDH0_SX80 +MSDS0_SI1077 +MSDS0_SI1707 +MSDS0_SI2337 +MSDS0_SX177 +MSDS0_SX267 +MSDS0_SX357 +MSDS0_SX447 +MSDS0_SX87 +MSEM1_SI1440 +MSEM1_SI2070 +MSEM1_SI810 +MSEM1_SX180 +MSEM1_SX270 +MSEM1_SX360 +MSEM1_SX450 +MSEM1_SX90 +MSES0_SI1589 +MSES0_SI2216 +MSES0_SI2219 +MSES0_SX149 +MSES0_SX239 +MSES0_SX329 +MSES0_SX419 +MSES0_SX59 +MSFH0_SI1216 +MSFH0_SI1738 +MSFH0_SI586 +MSFH0_SX136 +MSFH0_SX226 +MSFH0_SX316 +MSFH0_SX406 +MSFH0_SX46 +MSFV0_SI1262 +MSFV0_SI1892 +MSFV0_SI632 +MSFV0_SX182 +MSFV0_SX272 +MSFV0_SX362 +MSFV0_SX452 +MSFV0_SX92 +MSJK0_SI1596 +MSJK0_SI2226 +MSJK0_SI966 +MSJK0_SX156 +MSJK0_SX246 +MSJK0_SX336 +MSJK0_SX426 +MSJK0_SX66 +MSMC0_SI1907 +MSMC0_SI509 +MSMC0_SI647 +MSMC0_SX107 +MSMC0_SX17 +MSMC0_SX197 +MSMC0_SX287 +MSMC0_SX377 +MSMR0_SI1150 +MSMR0_SI1405 +MSMR0_SI775 +MSMR0_SX145 +MSMR0_SX235 +MSMR0_SX325 +MSMR0_SX415 +MSMR0_SX55 +MSMS0_SI1433 +MSMS0_SI2063 +MSMS0_SI803 +MSMS0_SX173 +MSMS0_SX263 +MSMS0_SX353 +MSMS0_SX443 +MSMS0_SX83 +MSRG0_SI1221 +MSRG0_SI1851 +MSRG0_SI591 +MSRG0_SX141 +MSRG0_SX231 +MSRG0_SX321 +MSRG0_SX411 +MSRG0_SX51 +MSRR0_SI1131 +MSRR0_SI1761 +MSRR0_SI501 +MSRR0_SX141 +MSRR0_SX231 +MSRR0_SX30 +MSRR0_SX411 +MSRR0_SX51 +MSTF0_SI1396 +MSTF0_SI766 +MSTF0_SI852 +MSTF0_SX136 +MSTF0_SX226 +MSTF0_SX316 +MSTF0_SX406 +MSTF0_SX46 +MSVS0_SI1568 +MSVS0_SI2198 +MSVS0_SI938 +MSVS0_SX128 +MSVS0_SX218 +MSVS0_SX308 +MSVS0_SX38 +MSVS0_SX398 +MTAB0_SI1572 +MTAB0_SI2202 +MTAB0_SI942 +MTAB0_SX132 +MTAB0_SX222 +MTAB0_SX312 +MTAB0_SX402 +MTAB0_SX42 +MTAS0_SI1385 +MTAS0_SI2015 +MTAS0_SI755 +MTAS0_SX125 +MTAS0_SX215 +MTAS0_SX305 +MTAS0_SX35 +MTAS0_SX395 +MTAT0_SI1110 +MTAT0_SI1740 +MTAT0_SI811 +MTAT0_SX120 +MTAT0_SX210 +MTAT0_SX30 +MTAT0_SX300 +MTAT0_SX390 +MTAT1_SI1409 +MTAT1_SI1627 +MTAT1_SI779 +MTAT1_SX149 +MTAT1_SX239 +MTAT1_SX329 +MTAT1_SX419 +MTAT1_SX59 +MTBC0_SI1173 +MTBC0_SI1803 +MTBC0_SI543 +MTBC0_SX183 +MTBC0_SX273 +MTBC0_SX347 +MTBC0_SX363 +MTBC0_SX93 +MTCS0_SI1972 +MTCS0_SI2265 +MTCS0_SI712 +MTCS0_SX172 +MTCS0_SX262 +MTCS0_SX352 +MTCS0_SX442 +MTCS0_SX82 +MTDB0_SI1401 +MTDB0_SI2031 +MTDB0_SI771 +MTDB0_SX141 +MTDB0_SX231 +MTDB0_SX321 +MTDB0_SX411 +MTDB0_SX51 +MTDP0_SI1274 +MTDP0_SI1521 +MTDP0_SI2151 +MTDP0_SX171 +MTDP0_SX261 +MTDP0_SX351 +MTDP0_SX441 +MTDP0_SX81 +MTER0_SI1157 +MTER0_SI1787 +MTER0_SI527 +MTER0_SX167 +MTER0_SX17 +MTER0_SX257 +MTER0_SX437 +MTER0_SX77 +MTJG0_SI1520 +MTJG0_SI2157 +MTJG0_SI890 +MTJG0_SX170 +MTJG0_SX260 +MTJG0_SX350 +MTJG0_SX440 +MTJG0_SX80 +MTJM0_SI1226 +MTJM0_SI1856 +MTJM0_SI655 +MTJM0_SX146 +MTJM0_SX236 +MTJM0_SX326 +MTJM0_SX416 +MTJM0_SX56 +MTJS0_SI1192 +MTJS0_SI1822 +MTJS0_SI562 +MTJS0_SX112 +MTJS0_SX202 +MTJS0_SX22 +MTJS0_SX292 +MTJS0_SX382 +MTJU0_SI2020 +MTJU0_SI2269 +MTJU0_SI760 +MTJU0_SX130 +MTJU0_SX220 +MTJU0_SX310 +MTJU0_SX40 +MTJU0_SX400 +MTKD0_SI1187 +MTKD0_SI1817 +MTKD0_SI630 +MTKD0_SX107 +MTKD0_SX17 +MTKD0_SX197 +MTKD0_SX287 +MTKD0_SX377 +MTKP0_SI1023 +MTKP0_SI2283 +MTKP0_SI454 +MTKP0_SX123 +MTKP0_SX213 +MTKP0_SX303 +MTKP0_SX33 +MTKP0_SX393 +MTLB0_SI1134 +MTLB0_SI1764 +MTLB0_SI504 +MTLB0_SX144 +MTLB0_SX234 +MTLB0_SX324 +MTLB0_SX414 +MTLB0_SX54 +MTLC0_SI1313 +MTLC0_SI1477 +MTLC0_SI847 +MTLC0_SX127 +MTLC0_SX217 +MTLC0_SX307 +MTLC0_SX37 +MTLC0_SX397 +MTML0_SI1065 +MTML0_SI1695 +MTML0_SI2325 +MTML0_SX165 +MTML0_SX255 +MTML0_SX345 +MTML0_SX435 +MTML0_SX75 +MTMN0_SI1064 +MTMN0_SI2324 +MTMN0_SI582 +MTMN0_SX164 +MTMN0_SX254 +MTMN0_SX344 +MTMN0_SX434 +MTMN0_SX74 +MTMT0_SI1118 +MTMT0_SI1748 +MTMT0_SI488 +MTMT0_SX128 +MTMT0_SX218 +MTMT0_SX308 +MTMT0_SX38 +MTMT0_SX398 +MTPF0_SI1235 +MTPF0_SI1865 +MTPF0_SI605 +MTPF0_SX155 +MTPF0_SX245 +MTPF0_SX335 +MTPF0_SX425 +MTPF0_SX65 +MTPG0_SI1383 +MTPG0_SI2013 +MTPG0_SI753 +MTPG0_SX123 +MTPG0_SX213 +MTPG0_SX303 +MTPG0_SX33 +MTPG0_SX393 +MTPP0_SI1508 +MTPP0_SI2138 +MTPP0_SI878 +MTPP0_SX158 +MTPP0_SX248 +MTPP0_SX338 +MTPP0_SX428 +MTPP0_SX68 +MTPR0_SI1600 +MTPR0_SI2230 +MTPR0_SI506 +MTPR0_SX160 +MTPR0_SX250 +MTPR0_SX340 +MTPR0_SX430 +MTPR0_SX70 +MTQC0_SI1441 +MTQC0_SI2071 +MTQC0_SI480 +MTQC0_SX181 +MTQC0_SX271 +MTQC0_SX361 +MTQC0_SX451 +MTQC0_SX91 +MTRC0_SI1623 +MTRC0_SI589 +MTRC0_SI993 +MTRC0_SX170 +MTRC0_SX183 +MTRC0_SX273 +MTRC0_SX363 +MTRC0_SX93 +MTRR0_SI1548 +MTRR0_SI2178 +MTRR0_SI918 +MTRR0_SX108 +MTRR0_SX18 +MTRR0_SX198 +MTRR0_SX288 +MTRR0_SX378 +MTRT0_SI1227 +MTRT0_SI1857 +MTRT0_SI597 +MTRT0_SX147 +MTRT0_SX237 +MTRT0_SX254 +MTRT0_SX417 +MTRT0_SX57 +MTWH1_SI1512 +MTWH1_SI2142 +MTWH1_SI882 +MTWH1_SX162 +MTWH1_SX252 +MTWH1_SX342 +MTWH1_SX432 +MTWH1_SX72 +MTXS0_SI1060 +MTXS0_SI1690 +MTXS0_SI2320 +MTXS0_SX160 +MTXS0_SX250 +MTXS0_SX340 +MTXS0_SX430 +MTXS0_SX70 +MVJH0_SI1556 +MVJH0_SI2186 +MVJH0_SI926 +MVJH0_SX116 +MVJH0_SX206 +MVJH0_SX26 +MVJH0_SX296 +MVJH0_SX386 +MVLO0_SI1147 +MVLO0_SI1777 +MVLO0_SI517 +MVLO0_SX157 +MVLO0_SX247 +MVLO0_SX337 +MVLO0_SX427 +MVLO0_SX67 +MVRW0_SI1485 +MVRW0_SI2115 +MVRW0_SI855 +MVRW0_SX135 +MVRW0_SX225 +MVRW0_SX315 +MVRW0_SX405 +MVRW0_SX45 +MWAC0_SI1601 +MWAC0_SI2231 +MWAC0_SI971 +MWAC0_SX161 +MWAC0_SX251 +MWAC0_SX341 +MWAC0_SX431 +MWAC0_SX71 +MWAD0_SI1062 +MWAD0_SI1749 +MWAD0_SI2322 +MWAD0_SX162 +MWAD0_SX252 +MWAD0_SX342 +MWAD0_SX432 +MWAD0_SX72 +MWAR0_SI1045 +MWAR0_SI1675 +MWAR0_SI2305 +MWAR0_SX145 +MWAR0_SX235 +MWAR0_SX325 +MWAR0_SX415 +MWAR0_SX55 +MWCH0_SI1622 +MWCH0_SI1895 +MWCH0_SI2252 +MWCH0_SX182 +MWCH0_SX272 +MWCH0_SX362 +MWCH0_SX452 +MWCH0_SX92 +MWDK0_SI1436 +MWDK0_SI2017 +MWDK0_SI806 +MWDK0_SX176 +MWDK0_SX266 +MWDK0_SX356 +MWDK0_SX446 +MWDK0_SX86 +MWEM0_SI1320 +MWEM0_SI1393 +MWEM0_SI1950 +MWEM0_SX150 +MWEM0_SX240 +MWEM0_SX330 +MWEM0_SX420 +MWEM0_SX60 +MWGR0_SI1606 +MWGR0_SI2236 +MWGR0_SI976 +MWGR0_SX166 +MWGR0_SX256 +MWGR0_SX346 +MWGR0_SX436 +MWGR0_SX76 +MWRE0_SI1057 +MWRE0_SI1687 +MWRE0_SI2317 +MWRE0_SX157 +MWRE0_SX247 +MWRE0_SX337 +MWRE0_SX427 +MWRE0_SX67 +MWRP0_SI1443 +MWRP0_SI1525 +MWRP0_SI2073 +MWRP0_SX183 +MWRP0_SX273 +MWRP0_SX3 +MWRP0_SX363 +MWRP0_SX93 +MWSB0_SI1626 +MWSB0_SI2256 +MWSB0_SI996 +MWSB0_SX186 +MWSB0_SX276 +MWSB0_SX366 +MWSB0_SX6 +MWSB0_SX96 +MWSH0_SI1426 +MWSH0_SI2266 +MWSH0_SI796 +MWSH0_SX166 +MWSH0_SX256 +MWSH0_SX346 +MWSH0_SX436 +MWSH0_SX76 +MZMB0_SI1166 +MZMB0_SI1796 +MZMB0_SI536 +MZMB0_SX176 +MZMB0_SX266 +MZMB0_SX356 +MZMB0_SX446 +MZMB0_SX86 diff --git a/examples/wav2vec/unsupervised/config/timit_matched/valid.uid b/examples/wav2vec/unsupervised/config/timit_matched/valid.uid new file mode 100644 index 0000000000..ab5ef381ab --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_matched/valid.uid @@ -0,0 +1,400 @@ +FADG0_SI1279 +FADG0_SI1909 +FADG0_SI649 +FADG0_SX109 +FADG0_SX19 +FADG0_SX199 +FADG0_SX289 +FADG0_SX379 +FAKS0_SI1573 +FAKS0_SI2203 +FAKS0_SI943 +FAKS0_SX133 +FAKS0_SX223 +FAKS0_SX313 +FAKS0_SX403 +FAKS0_SX43 +FCAL1_SI1403 +FCAL1_SI2033 +FCAL1_SI773 +FCAL1_SX143 +FCAL1_SX233 +FCAL1_SX323 +FCAL1_SX413 +FCAL1_SX53 +FCMH0_SI1454 +FCMH0_SI2084 +FCMH0_SI824 +FCMH0_SX104 +FCMH0_SX14 +FCMH0_SX194 +FCMH0_SX284 +FCMH0_SX374 +FDAC1_SI1474 +FDAC1_SI2104 +FDAC1_SI844 +FDAC1_SX124 +FDAC1_SX214 +FDAC1_SX304 +FDAC1_SX34 +FDAC1_SX394 +FDMS0_SI1218 +FDMS0_SI1502 +FDMS0_SI1848 +FDMS0_SX138 +FDMS0_SX228 +FDMS0_SX318 +FDMS0_SX408 +FDMS0_SX48 +FDRW0_SI1283 +FDRW0_SI1423 +FDRW0_SI653 +FDRW0_SX113 +FDRW0_SX203 +FDRW0_SX23 +FDRW0_SX293 +FDRW0_SX383 +FEDW0_SI1084 +FEDW0_SI1653 +FEDW0_SI1714 +FEDW0_SX184 +FEDW0_SX274 +FEDW0_SX364 +FEDW0_SX4 +FEDW0_SX94 +FGJD0_SI1179 +FGJD0_SI549 +FGJD0_SI818 +FGJD0_SX189 +FGJD0_SX279 +FGJD0_SX369 +FGJD0_SX9 +FGJD0_SX99 +FJEM0_SI1264 +FJEM0_SI1894 +FJEM0_SI634 +FJEM0_SX184 +FJEM0_SX274 +FJEM0_SX364 +FJEM0_SX4 +FJEM0_SX94 +FJMG0_SI1181 +FJMG0_SI1811 +FJMG0_SI551 +FJMG0_SX101 +FJMG0_SX11 +FJMG0_SX191 +FJMG0_SX281 +FJMG0_SX371 +FJSJ0_SI1484 +FJSJ0_SI2114 +FJSJ0_SI854 +FJSJ0_SX134 +FJSJ0_SX224 +FJSJ0_SX314 +FJSJ0_SX404 +FJSJ0_SX44 +FKMS0_SI1490 +FKMS0_SI2120 +FKMS0_SI860 +FKMS0_SX140 +FKMS0_SX230 +FKMS0_SX320 +FKMS0_SX410 +FKMS0_SX50 +FMAH0_SI1289 +FMAH0_SI1919 +FMAH0_SI659 +FMAH0_SX119 +FMAH0_SX209 +FMAH0_SX29 +FMAH0_SX299 +FMAH0_SX389 +FMML0_SI1040 +FMML0_SI1670 +FMML0_SI2300 +FMML0_SX140 +FMML0_SX230 +FMML0_SX320 +FMML0_SX410 +FMML0_SX50 +FNMR0_SI1399 +FNMR0_SI2029 +FNMR0_SI769 +FNMR0_SX139 +FNMR0_SX229 +FNMR0_SX319 +FNMR0_SX409 +FNMR0_SX49 +FREW0_SI1030 +FREW0_SI1280 +FREW0_SI1910 +FREW0_SX110 +FREW0_SX20 +FREW0_SX200 +FREW0_SX290 +FREW0_SX380 +FSEM0_SI1198 +FSEM0_SI1828 +FSEM0_SI568 +FSEM0_SX118 +FSEM0_SX208 +FSEM0_SX28 +FSEM0_SX298 +FSEM0_SX388 +MAJC0_SI1946 +MAJC0_SI2095 +MAJC0_SI835 +MAJC0_SX115 +MAJC0_SX205 +MAJC0_SX25 +MAJC0_SX295 +MAJC0_SX385 +MBDG0_SI1463 +MBDG0_SI2093 +MBDG0_SI833 +MBDG0_SX113 +MBDG0_SX203 +MBDG0_SX23 +MBDG0_SX293 +MBDG0_SX383 +MBNS0_SI1220 +MBNS0_SI1850 +MBNS0_SI590 +MBNS0_SX140 +MBNS0_SX230 +MBNS0_SX320 +MBNS0_SX410 +MBNS0_SX50 +MBWM0_SI1304 +MBWM0_SI1934 +MBWM0_SI674 +MBWM0_SX134 +MBWM0_SX224 +MBWM0_SX314 +MBWM0_SX404 +MBWM0_SX44 +MCSH0_SI1549 +MCSH0_SI2179 +MCSH0_SI919 +MCSH0_SX109 +MCSH0_SX19 +MCSH0_SX199 +MCSH0_SX289 +MCSH0_SX379 +MDLF0_SI1583 +MDLF0_SI2213 +MDLF0_SI953 +MDLF0_SX143 +MDLF0_SX233 +MDLF0_SX323 +MDLF0_SX413 +MDLF0_SX53 +MDLS0_SI1628 +MDLS0_SI2258 +MDLS0_SI998 +MDLS0_SX188 +MDLS0_SX278 +MDLS0_SX368 +MDLS0_SX8 +MDLS0_SX98 +MDVC0_SI2174 +MDVC0_SI2196 +MDVC0_SI936 +MDVC0_SX126 +MDVC0_SX216 +MDVC0_SX306 +MDVC0_SX36 +MDVC0_SX396 +MERS0_SI1019 +MERS0_SI1649 +MERS0_SI497 +MERS0_SX119 +MERS0_SX209 +MERS0_SX29 +MERS0_SX299 +MERS0_SX389 +MGJF0_SI1901 +MGJF0_SI641 +MGJF0_SI776 +MGJF0_SX101 +MGJF0_SX11 +MGJF0_SX191 +MGJF0_SX281 +MGJF0_SX371 +MGLB0_SI1534 +MGLB0_SI2164 +MGLB0_SI904 +MGLB0_SX184 +MGLB0_SX274 +MGLB0_SX364 +MGLB0_SX4 +MGLB0_SX94 +MGWT0_SI1539 +MGWT0_SI2169 +MGWT0_SI909 +MGWT0_SX189 +MGWT0_SX279 +MGWT0_SX369 +MGWT0_SX9 +MGWT0_SX99 +MJAR0_SI1988 +MJAR0_SI2247 +MJAR0_SI728 +MJAR0_SX188 +MJAR0_SX278 +MJAR0_SX368 +MJAR0_SX8 +MJAR0_SX98 +MJFC0_SI1033 +MJFC0_SI1663 +MJFC0_SI2293 +MJFC0_SX133 +MJFC0_SX223 +MJFC0_SX313 +MJFC0_SX403 +MJFC0_SX43 +MJSW0_SI1010 +MJSW0_SI1640 +MJSW0_SI2270 +MJSW0_SX110 +MJSW0_SX20 +MJSW0_SX200 +MJSW0_SX290 +MJSW0_SX380 +MMDB1_SI1625 +MMDB1_SI2255 +MMDB1_SI995 +MMDB1_SX185 +MMDB1_SX275 +MMDB1_SX365 +MMDB1_SX5 +MMDB1_SX95 +MMDM2_SI1452 +MMDM2_SI1555 +MMDM2_SI2082 +MMDM2_SX102 +MMDM2_SX12 +MMDM2_SX192 +MMDM2_SX282 +MMDM2_SX372 +MMJR0_SI1648 +MMJR0_SI2166 +MMJR0_SI2278 +MMJR0_SX118 +MMJR0_SX208 +MMJR0_SX28 +MMJR0_SX298 +MMJR0_SX388 +MMWH0_SI1089 +MMWH0_SI1301 +MMWH0_SI459 +MMWH0_SX189 +MMWH0_SX279 +MMWH0_SX369 +MMWH0_SX9 +MMWH0_SX99 +MPDF0_SI1542 +MPDF0_SI2172 +MPDF0_SI912 +MPDF0_SX102 +MPDF0_SX12 +MPDF0_SX192 +MPDF0_SX282 +MPDF0_SX372 +MRCS0_SI1223 +MRCS0_SI1853 +MRCS0_SI593 +MRCS0_SX143 +MRCS0_SX233 +MRCS0_SX323 +MRCS0_SX413 +MRCS0_SX53 +MREB0_SI1375 +MREB0_SI2005 +MREB0_SI745 +MREB0_SX115 +MREB0_SX205 +MREB0_SX25 +MREB0_SX295 +MREB0_SX385 +MRJM4_SI1489 +MRJM4_SI2119 +MRJM4_SI859 +MRJM4_SX139 +MRJM4_SX229 +MRJM4_SX319 +MRJM4_SX409 +MRJM4_SX49 +MRJR0_SI1182 +MRJR0_SI1812 +MRJR0_SI2313 +MRJR0_SX102 +MRJR0_SX12 +MRJR0_SX192 +MRJR0_SX282 +MRJR0_SX372 +MROA0_SI1307 +MROA0_SI1970 +MROA0_SI677 +MROA0_SX137 +MROA0_SX227 +MROA0_SX317 +MROA0_SX407 +MROA0_SX47 +MRTK0_SI1093 +MRTK0_SI1723 +MRTK0_SI1750 +MRTK0_SX103 +MRTK0_SX13 +MRTK0_SX193 +MRTK0_SX283 +MRTK0_SX373 +MRWS1_SI1130 +MRWS1_SI1496 +MRWS1_SI500 +MRWS1_SX140 +MRWS1_SX230 +MRWS1_SX320 +MRWS1_SX410 +MRWS1_SX50 +MTAA0_SI1285 +MTAA0_SI1915 +MTAA0_SI596 +MTAA0_SX115 +MTAA0_SX205 +MTAA0_SX25 +MTAA0_SX295 +MTAA0_SX385 +MTDT0_SI1994 +MTDT0_SI2254 +MTDT0_SI994 +MTDT0_SX184 +MTDT0_SX274 +MTDT0_SX364 +MTDT0_SX4 +MTDT0_SX94 +MTEB0_SI1133 +MTEB0_SI2064 +MTEB0_SI503 +MTEB0_SX143 +MTEB0_SX233 +MTEB0_SX323 +MTEB0_SX413 +MTEB0_SX53 +MTHC0_SI1015 +MTHC0_SI1645 +MTHC0_SI2275 +MTHC0_SX115 +MTHC0_SX205 +MTHC0_SX25 +MTHC0_SX295 +MTHC0_SX385 +MWJG0_SI1124 +MWJG0_SI1754 +MWJG0_SI494 +MWJG0_SX134 +MWJG0_SX224 +MWJG0_SX314 +MWJG0_SX404 +MWJG0_SX44 diff --git a/examples/wav2vec/unsupervised/config/timit_unmatched/test.uid b/examples/wav2vec/unsupervised/config/timit_unmatched/test.uid new file mode 100644 index 0000000000..e3967e4242 --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_unmatched/test.uid @@ -0,0 +1,1680 @@ +FADG0_SA1 +FADG0_SA2 +FADG0_SI1279 +FADG0_SI1909 +FADG0_SI649 +FADG0_SX109 +FADG0_SX19 +FADG0_SX199 +FADG0_SX289 +FADG0_SX379 +FAKS0_SA1 +FAKS0_SA2 +FAKS0_SI1573 +FAKS0_SI2203 +FAKS0_SI943 +FAKS0_SX133 +FAKS0_SX223 +FAKS0_SX313 +FAKS0_SX403 +FAKS0_SX43 +FASW0_SA1 +FASW0_SA2 +FASW0_SI1550 +FASW0_SI2180 +FASW0_SI920 +FASW0_SX110 +FASW0_SX20 +FASW0_SX200 +FASW0_SX290 +FASW0_SX380 +FAWF0_SA1 +FAWF0_SA2 +FAWF0_SI1000 +FAWF0_SI1630 +FAWF0_SI2260 +FAWF0_SX10 +FAWF0_SX100 +FAWF0_SX190 +FAWF0_SX280 +FAWF0_SX370 +FCAL1_SA1 +FCAL1_SA2 +FCAL1_SI1403 +FCAL1_SI2033 +FCAL1_SI773 +FCAL1_SX143 +FCAL1_SX233 +FCAL1_SX323 +FCAL1_SX413 +FCAL1_SX53 +FCAU0_SA1 +FCAU0_SA2 +FCAU0_SI1037 +FCAU0_SI1667 +FCAU0_SI2297 +FCAU0_SX137 +FCAU0_SX227 +FCAU0_SX317 +FCAU0_SX407 +FCAU0_SX47 +FCFT0_SA1 +FCFT0_SA2 +FCFT0_SI1178 +FCFT0_SI1808 +FCFT0_SI548 +FCFT0_SX188 +FCFT0_SX278 +FCFT0_SX368 +FCFT0_SX8 +FCFT0_SX98 +FCMH0_SA1 +FCMH0_SA2 +FCMH0_SI1454 +FCMH0_SI2084 +FCMH0_SI824 +FCMH0_SX104 +FCMH0_SX14 +FCMH0_SX194 +FCMH0_SX284 +FCMH0_SX374 +FCMH1_SA1 +FCMH1_SA2 +FCMH1_SI1493 +FCMH1_SI2123 +FCMH1_SI863 +FCMH1_SX143 +FCMH1_SX233 +FCMH1_SX323 +FCMH1_SX413 +FCMH1_SX53 +FCMR0_SA1 +FCMR0_SA2 +FCMR0_SI1105 +FCMR0_SI1735 +FCMR0_SI475 +FCMR0_SX115 +FCMR0_SX205 +FCMR0_SX25 +FCMR0_SX295 +FCMR0_SX385 +FCRH0_SA1 +FCRH0_SA2 +FCRH0_SI1088 +FCRH0_SI1718 +FCRH0_SI458 +FCRH0_SX188 +FCRH0_SX278 +FCRH0_SX368 +FCRH0_SX8 +FCRH0_SX98 +FDAC1_SA1 +FDAC1_SA2 +FDAC1_SI1474 +FDAC1_SI2104 +FDAC1_SI844 +FDAC1_SX124 +FDAC1_SX214 +FDAC1_SX304 +FDAC1_SX34 +FDAC1_SX394 +FDHC0_SA1 +FDHC0_SA2 +FDHC0_SI1559 +FDHC0_SI2189 +FDHC0_SI929 +FDHC0_SX119 +FDHC0_SX209 +FDHC0_SX29 +FDHC0_SX299 +FDHC0_SX389 +FDMS0_SA1 +FDMS0_SA2 +FDMS0_SI1218 +FDMS0_SI1502 +FDMS0_SI1848 +FDMS0_SX138 +FDMS0_SX228 +FDMS0_SX318 +FDMS0_SX408 +FDMS0_SX48 +FDRD1_SA1 +FDRD1_SA2 +FDRD1_SI1544 +FDRD1_SI1566 +FDRD1_SI2149 +FDRD1_SX104 +FDRD1_SX14 +FDRD1_SX194 +FDRD1_SX284 +FDRD1_SX374 +FDRW0_SA1 +FDRW0_SA2 +FDRW0_SI1283 +FDRW0_SI1423 +FDRW0_SI653 +FDRW0_SX113 +FDRW0_SX203 +FDRW0_SX23 +FDRW0_SX293 +FDRW0_SX383 +FEDW0_SA1 +FEDW0_SA2 +FEDW0_SI1084 +FEDW0_SI1653 +FEDW0_SI1714 +FEDW0_SX184 +FEDW0_SX274 +FEDW0_SX364 +FEDW0_SX4 +FEDW0_SX94 +FELC0_SA1 +FELC0_SA2 +FELC0_SI1386 +FELC0_SI2016 +FELC0_SI756 +FELC0_SX126 +FELC0_SX216 +FELC0_SX306 +FELC0_SX36 +FELC0_SX396 +FGJD0_SA1 +FGJD0_SA2 +FGJD0_SI1179 +FGJD0_SI549 +FGJD0_SI818 +FGJD0_SX189 +FGJD0_SX279 +FGJD0_SX369 +FGJD0_SX9 +FGJD0_SX99 +FGMD0_SA1 +FGMD0_SA2 +FGMD0_SI1943 +FGMD0_SI2107 +FGMD0_SI683 +FGMD0_SX143 +FGMD0_SX233 +FGMD0_SX323 +FGMD0_SX413 +FGMD0_SX53 +FGWR0_SA1 +FGWR0_SA2 +FGWR0_SI1578 +FGWR0_SI2208 +FGWR0_SI948 +FGWR0_SX138 +FGWR0_SX228 +FGWR0_SX318 +FGWR0_SX408 +FGWR0_SX48 +FHES0_SA1 +FHES0_SA2 +FHES0_SI1109 +FHES0_SI1739 +FHES0_SI479 +FHES0_SX119 +FHES0_SX209 +FHES0_SX29 +FHES0_SX299 +FHES0_SX389 +FHEW0_SA1 +FHEW0_SA2 +FHEW0_SI2023 +FHEW0_SI690 +FHEW0_SI763 +FHEW0_SX133 +FHEW0_SX223 +FHEW0_SX313 +FHEW0_SX403 +FHEW0_SX43 +FISB0_SA1 +FISB0_SA2 +FISB0_SI1579 +FISB0_SI2209 +FISB0_SI949 +FISB0_SX139 +FISB0_SX229 +FISB0_SX319 +FISB0_SX409 +FISB0_SX49 +FJAS0_SA1 +FJAS0_SA2 +FJAS0_SI1400 +FJAS0_SI2030 +FJAS0_SI770 +FJAS0_SX140 +FJAS0_SX230 +FJAS0_SX320 +FJAS0_SX410 +FJAS0_SX50 +FJCS0_SA1 +FJCS0_SA2 +FJCS0_SI1309 +FJCS0_SI1833 +FJCS0_SI1939 +FJCS0_SX139 +FJCS0_SX229 +FJCS0_SX319 +FJCS0_SX409 +FJCS0_SX49 +FJEM0_SA1 +FJEM0_SA2 +FJEM0_SI1264 +FJEM0_SI1894 +FJEM0_SI634 +FJEM0_SX184 +FJEM0_SX274 +FJEM0_SX364 +FJEM0_SX4 +FJEM0_SX94 +FJLM0_SA1 +FJLM0_SA2 +FJLM0_SI1043 +FJLM0_SI1673 +FJLM0_SI2303 +FJLM0_SX143 +FJLM0_SX233 +FJLM0_SX323 +FJLM0_SX413 +FJLM0_SX53 +FJMG0_SA1 +FJMG0_SA2 +FJMG0_SI1181 +FJMG0_SI1811 +FJMG0_SI551 +FJMG0_SX101 +FJMG0_SX11 +FJMG0_SX191 +FJMG0_SX281 +FJMG0_SX371 +FJRE0_SA1 +FJRE0_SA2 +FJRE0_SI1116 +FJRE0_SI1587 +FJRE0_SI1746 +FJRE0_SX126 +FJRE0_SX216 +FJRE0_SX306 +FJRE0_SX36 +FJRE0_SX396 +FJSA0_SA1 +FJSA0_SA2 +FJSA0_SI1379 +FJSA0_SI2009 +FJSA0_SI749 +FJSA0_SX119 +FJSA0_SX209 +FJSA0_SX29 +FJSA0_SX299 +FJSA0_SX389 +FJSJ0_SA1 +FJSJ0_SA2 +FJSJ0_SI1484 +FJSJ0_SI2114 +FJSJ0_SI854 +FJSJ0_SX134 +FJSJ0_SX224 +FJSJ0_SX314 +FJSJ0_SX404 +FJSJ0_SX44 +FJWB0_SA1 +FJWB0_SA2 +FJWB0_SI1265 +FJWB0_SI635 +FJWB0_SI992 +FJWB0_SX185 +FJWB0_SX275 +FJWB0_SX365 +FJWB0_SX5 +FJWB0_SX95 +FKMS0_SA1 +FKMS0_SA2 +FKMS0_SI1490 +FKMS0_SI2120 +FKMS0_SI860 +FKMS0_SX140 +FKMS0_SX230 +FKMS0_SX320 +FKMS0_SX410 +FKMS0_SX50 +FLAS0_SA1 +FLAS0_SA2 +FLAS0_SI1026 +FLAS0_SI1488 +FLAS0_SI858 +FLAS0_SX138 +FLAS0_SX228 +FLAS0_SX318 +FLAS0_SX408 +FLAS0_SX48 +FLBW0_SA1 +FLBW0_SA2 +FLBW0_SI1219 +FLBW0_SI1849 +FLBW0_SI2253 +FLBW0_SX139 +FLBW0_SX229 +FLBW0_SX319 +FLBW0_SX409 +FLBW0_SX49 +FLKD0_SA1 +FLKD0_SA2 +FLKD0_SI1369 +FLKD0_SI739 +FLKD0_SI894 +FLKD0_SX109 +FLKD0_SX19 +FLKD0_SX199 +FLKD0_SX289 +FLKD0_SX379 +FLNH0_SA1 +FLNH0_SA2 +FLNH0_SI1214 +FLNH0_SI584 +FLNH0_SI941 +FLNH0_SX134 +FLNH0_SX224 +FLNH0_SX314 +FLNH0_SX404 +FLNH0_SX44 +FMAF0_SA1 +FMAF0_SA2 +FMAF0_SI1459 +FMAF0_SI2089 +FMAF0_SI829 +FMAF0_SX109 +FMAF0_SX19 +FMAF0_SX199 +FMAF0_SX289 +FMAF0_SX379 +FMAH0_SA1 +FMAH0_SA2 +FMAH0_SI1289 +FMAH0_SI1919 +FMAH0_SI659 +FMAH0_SX119 +FMAH0_SX209 +FMAH0_SX29 +FMAH0_SX299 +FMAH0_SX389 +FMCM0_SA1 +FMCM0_SA2 +FMCM0_SI1180 +FMCM0_SI1810 +FMCM0_SI550 +FMCM0_SX10 +FMCM0_SX100 +FMCM0_SX190 +FMCM0_SX280 +FMCM0_SX370 +FMGD0_SA1 +FMGD0_SA2 +FMGD0_SI1564 +FMGD0_SI2194 +FMGD0_SI934 +FMGD0_SX124 +FMGD0_SX214 +FMGD0_SX304 +FMGD0_SX34 +FMGD0_SX394 +FMLD0_SA1 +FMLD0_SA2 +FMLD0_SI2185 +FMLD0_SI822 +FMLD0_SI925 +FMLD0_SX115 +FMLD0_SX205 +FMLD0_SX25 +FMLD0_SX295 +FMLD0_SX385 +FMML0_SA1 +FMML0_SA2 +FMML0_SI1040 +FMML0_SI1670 +FMML0_SI2300 +FMML0_SX140 +FMML0_SX230 +FMML0_SX320 +FMML0_SX410 +FMML0_SX50 +FNLP0_SA1 +FNLP0_SA2 +FNLP0_SI1308 +FNLP0_SI1938 +FNLP0_SI678 +FNLP0_SX138 +FNLP0_SX228 +FNLP0_SX318 +FNLP0_SX408 +FNLP0_SX48 +FNMR0_SA1 +FNMR0_SA2 +FNMR0_SI1399 +FNMR0_SI2029 +FNMR0_SI769 +FNMR0_SX139 +FNMR0_SX229 +FNMR0_SX319 +FNMR0_SX409 +FNMR0_SX49 +FPAS0_SA1 +FPAS0_SA2 +FPAS0_SI1272 +FPAS0_SI2204 +FPAS0_SI944 +FPAS0_SX134 +FPAS0_SX224 +FPAS0_SX314 +FPAS0_SX404 +FPAS0_SX44 +FPKT0_SA1 +FPKT0_SA2 +FPKT0_SI1538 +FPKT0_SI2168 +FPKT0_SI908 +FPKT0_SX188 +FPKT0_SX278 +FPKT0_SX368 +FPKT0_SX8 +FPKT0_SX98 +FRAM1_SA1 +FRAM1_SA2 +FRAM1_SI1360 +FRAM1_SI522 +FRAM1_SI730 +FRAM1_SX10 +FRAM1_SX100 +FRAM1_SX190 +FRAM1_SX280 +FRAM1_SX370 +FREW0_SA1 +FREW0_SA2 +FREW0_SI1030 +FREW0_SI1280 +FREW0_SI1910 +FREW0_SX110 +FREW0_SX20 +FREW0_SX200 +FREW0_SX290 +FREW0_SX380 +FRNG0_SA1 +FRNG0_SA2 +FRNG0_SI1355 +FRNG0_SI1985 +FRNG0_SI725 +FRNG0_SX185 +FRNG0_SX275 +FRNG0_SX365 +FRNG0_SX5 +FRNG0_SX95 +FSEM0_SA1 +FSEM0_SA2 +FSEM0_SI1198 +FSEM0_SI1828 +FSEM0_SI568 +FSEM0_SX118 +FSEM0_SX208 +FSEM0_SX28 +FSEM0_SX298 +FSEM0_SX388 +FSLB1_SA1 +FSLB1_SA2 +FSLB1_SI1904 +FSLB1_SI644 +FSLB1_SI891 +FSLB1_SX104 +FSLB1_SX14 +FSLB1_SX194 +FSLB1_SX284 +FSLB1_SX374 +FSXA0_SA1 +FSXA0_SA2 +FSXA0_SI1108 +FSXA0_SI1846 +FSXA0_SI478 +FSXA0_SX118 +FSXA0_SX208 +FSXA0_SX28 +FSXA0_SX298 +FSXA0_SX388 +FTLH0_SA1 +FTLH0_SA2 +FTLH0_SI1009 +FTLH0_SI1390 +FTLH0_SI1639 +FTLH0_SX109 +FTLH0_SX19 +FTLH0_SX199 +FTLH0_SX289 +FTLH0_SX379 +FUTB0_SA1 +FUTB0_SA2 +FUTB0_SI1204 +FUTB0_SI1330 +FUTB0_SI1834 +FUTB0_SX124 +FUTB0_SX214 +FUTB0_SX304 +FUTB0_SX34 +FUTB0_SX394 +MABW0_SA1 +MABW0_SA2 +MABW0_SI1230 +MABW0_SI1664 +MABW0_SI2294 +MABW0_SX134 +MABW0_SX224 +MABW0_SX314 +MABW0_SX404 +MABW0_SX44 +MAHH0_SA1 +MAHH0_SA2 +MAHH0_SI1294 +MAHH0_SI1924 +MAHH0_SI664 +MAHH0_SX124 +MAHH0_SX214 +MAHH0_SX304 +MAHH0_SX34 +MAHH0_SX394 +MAJC0_SA1 +MAJC0_SA2 +MAJC0_SI1946 +MAJC0_SI2095 +MAJC0_SI835 +MAJC0_SX115 +MAJC0_SX205 +MAJC0_SX25 +MAJC0_SX295 +MAJC0_SX385 +MBDG0_SA1 +MBDG0_SA2 +MBDG0_SI1463 +MBDG0_SI2093 +MBDG0_SI833 +MBDG0_SX113 +MBDG0_SX203 +MBDG0_SX23 +MBDG0_SX293 +MBDG0_SX383 +MBJK0_SA1 +MBJK0_SA2 +MBJK0_SI1175 +MBJK0_SI2128 +MBJK0_SI545 +MBJK0_SX185 +MBJK0_SX275 +MBJK0_SX365 +MBJK0_SX5 +MBJK0_SX95 +MBNS0_SA1 +MBNS0_SA2 +MBNS0_SI1220 +MBNS0_SI1850 +MBNS0_SI590 +MBNS0_SX140 +MBNS0_SX230 +MBNS0_SX320 +MBNS0_SX410 +MBNS0_SX50 +MBPM0_SA1 +MBPM0_SA2 +MBPM0_SI1577 +MBPM0_SI1584 +MBPM0_SI947 +MBPM0_SX137 +MBPM0_SX227 +MBPM0_SX317 +MBPM0_SX407 +MBPM0_SX47 +MBWM0_SA1 +MBWM0_SA2 +MBWM0_SI1304 +MBWM0_SI1934 +MBWM0_SI674 +MBWM0_SX134 +MBWM0_SX224 +MBWM0_SX314 +MBWM0_SX404 +MBWM0_SX44 +MCCS0_SA1 +MCCS0_SA2 +MCCS0_SI1469 +MCCS0_SI2099 +MCCS0_SI839 +MCCS0_SX119 +MCCS0_SX209 +MCCS0_SX29 +MCCS0_SX299 +MCCS0_SX389 +MCEM0_SA1 +MCEM0_SA2 +MCEM0_SI1398 +MCEM0_SI2028 +MCEM0_SI768 +MCEM0_SX138 +MCEM0_SX228 +MCEM0_SX318 +MCEM0_SX408 +MCEM0_SX48 +MCHH0_SA1 +MCHH0_SA2 +MCHH0_SI1004 +MCHH0_SI1634 +MCHH0_SI530 +MCHH0_SX104 +MCHH0_SX14 +MCHH0_SX194 +MCHH0_SX284 +MCHH0_SX374 +MCMB0_SA1 +MCMB0_SA2 +MCMB0_SI1268 +MCMB0_SI1898 +MCMB0_SI638 +MCMB0_SX188 +MCMB0_SX278 +MCMB0_SX368 +MCMB0_SX8 +MCMB0_SX98 +MCMJ0_SA1 +MCMJ0_SA2 +MCMJ0_SI1094 +MCMJ0_SI464 +MCMJ0_SI602 +MCMJ0_SX104 +MCMJ0_SX14 +MCMJ0_SX194 +MCMJ0_SX284 +MCMJ0_SX374 +MCRC0_SA1 +MCRC0_SA2 +MCRC0_SI1092 +MCRC0_SI1722 +MCRC0_SI462 +MCRC0_SX102 +MCRC0_SX12 +MCRC0_SX192 +MCRC0_SX282 +MCRC0_SX372 +MCSH0_SA1 +MCSH0_SA2 +MCSH0_SI1549 +MCSH0_SI2179 +MCSH0_SI919 +MCSH0_SX109 +MCSH0_SX19 +MCSH0_SX199 +MCSH0_SX289 +MCSH0_SX379 +MCTT0_SA1 +MCTT0_SA2 +MCTT0_SI1144 +MCTT0_SI2188 +MCTT0_SI928 +MCTT0_SX118 +MCTT0_SX208 +MCTT0_SX28 +MCTT0_SX298 +MCTT0_SX388 +MCTW0_SA1 +MCTW0_SA2 +MCTW0_SI1373 +MCTW0_SI2003 +MCTW0_SI743 +MCTW0_SX113 +MCTW0_SX203 +MCTW0_SX23 +MCTW0_SX293 +MCTW0_SX383 +MDAB0_SA1 +MDAB0_SA2 +MDAB0_SI1039 +MDAB0_SI1669 +MDAB0_SI2299 +MDAB0_SX139 +MDAB0_SX229 +MDAB0_SX319 +MDAB0_SX409 +MDAB0_SX49 +MDAC2_SA1 +MDAC2_SA2 +MDAC2_SI2259 +MDAC2_SI560 +MDAC2_SI999 +MDAC2_SX189 +MDAC2_SX279 +MDAC2_SX369 +MDAC2_SX9 +MDAC2_SX99 +MDAW1_SA1 +MDAW1_SA2 +MDAW1_SI1453 +MDAW1_SI2083 +MDAW1_SI823 +MDAW1_SX103 +MDAW1_SX13 +MDAW1_SX193 +MDAW1_SX283 +MDAW1_SX373 +MDBB0_SA1 +MDBB0_SA2 +MDBB0_SI1195 +MDBB0_SI1825 +MDBB0_SI565 +MDBB0_SX115 +MDBB0_SX205 +MDBB0_SX25 +MDBB0_SX295 +MDBB0_SX385 +MDLD0_SA1 +MDLD0_SA2 +MDLD0_SI1543 +MDLD0_SI2173 +MDLD0_SI913 +MDLD0_SX103 +MDLD0_SX13 +MDLD0_SX193 +MDLD0_SX283 +MDLD0_SX373 +MDLF0_SA1 +MDLF0_SA2 +MDLF0_SI1583 +MDLF0_SI2213 +MDLF0_SI953 +MDLF0_SX143 +MDLF0_SX233 +MDLF0_SX323 +MDLF0_SX413 +MDLF0_SX53 +MDLS0_SA1 +MDLS0_SA2 +MDLS0_SI1628 +MDLS0_SI2258 +MDLS0_SI998 +MDLS0_SX188 +MDLS0_SX278 +MDLS0_SX368 +MDLS0_SX8 +MDLS0_SX98 +MDRB0_SA1 +MDRB0_SA2 +MDRB0_SI1174 +MDRB0_SI2109 +MDRB0_SI544 +MDRB0_SX184 +MDRB0_SX274 +MDRB0_SX364 +MDRB0_SX4 +MDRB0_SX94 +MDRM0_SA1 +MDRM0_SA2 +MDRM0_SI1013 +MDRM0_SI1643 +MDRM0_SI2273 +MDRM0_SX113 +MDRM0_SX203 +MDRM0_SX23 +MDRM0_SX293 +MDRM0_SX383 +MDSC0_SA1 +MDSC0_SA2 +MDSC0_SI1038 +MDSC0_SI2298 +MDSC0_SI967 +MDSC0_SX138 +MDSC0_SX228 +MDSC0_SX318 +MDSC0_SX408 +MDSC0_SX48 +MDVC0_SA1 +MDVC0_SA2 +MDVC0_SI2174 +MDVC0_SI2196 +MDVC0_SI936 +MDVC0_SX126 +MDVC0_SX216 +MDVC0_SX306 +MDVC0_SX36 +MDVC0_SX396 +MDWA0_SA1 +MDWA0_SA2 +MDWA0_SI1146 +MDWA0_SI1445 +MDWA0_SI519 +MDWA0_SX185 +MDWA0_SX275 +MDWA0_SX365 +MDWA0_SX5 +MDWA0_SX95 +MDWK0_SA1 +MDWK0_SA2 +MDWK0_SI1540 +MDWK0_SI2170 +MDWK0_SI910 +MDWK0_SX10 +MDWK0_SX100 +MDWK0_SX190 +MDWK0_SX280 +MDWK0_SX370 +MERS0_SA1 +MERS0_SA2 +MERS0_SI1019 +MERS0_SI1649 +MERS0_SI497 +MERS0_SX119 +MERS0_SX209 +MERS0_SX29 +MERS0_SX299 +MERS0_SX389 +MESD0_SA1 +MESD0_SA2 +MESD0_SI1002 +MESD0_SI1632 +MESD0_SI2262 +MESD0_SX102 +MESD0_SX12 +MESD0_SX192 +MESD0_SX282 +MESD0_SX372 +MFGK0_SA1 +MFGK0_SA2 +MFGK0_SI1451 +MFGK0_SI1744 +MFGK0_SI484 +MFGK0_SX124 +MFGK0_SX214 +MFGK0_SX304 +MFGK0_SX34 +MFGK0_SX394 +MGJF0_SA1 +MGJF0_SA2 +MGJF0_SI1901 +MGJF0_SI641 +MGJF0_SI776 +MGJF0_SX101 +MGJF0_SX11 +MGJF0_SX191 +MGJF0_SX281 +MGJF0_SX371 +MGLB0_SA1 +MGLB0_SA2 +MGLB0_SI1534 +MGLB0_SI2164 +MGLB0_SI904 +MGLB0_SX184 +MGLB0_SX274 +MGLB0_SX364 +MGLB0_SX4 +MGLB0_SX94 +MGMM0_SA1 +MGMM0_SA2 +MGMM0_SI1129 +MGMM0_SI1759 +MGMM0_SI499 +MGMM0_SX139 +MGMM0_SX229 +MGMM0_SX319 +MGMM0_SX409 +MGMM0_SX49 +MGRT0_SA1 +MGRT0_SA2 +MGRT0_SI1450 +MGRT0_SI2080 +MGRT0_SI820 +MGRT0_SX10 +MGRT0_SX100 +MGRT0_SX190 +MGRT0_SX280 +MGRT0_SX370 +MGWT0_SA1 +MGWT0_SA2 +MGWT0_SI1539 +MGWT0_SI2169 +MGWT0_SI909 +MGWT0_SX189 +MGWT0_SX279 +MGWT0_SX369 +MGWT0_SX9 +MGWT0_SX99 +MHPG0_SA1 +MHPG0_SA2 +MHPG0_SI1090 +MHPG0_SI1720 +MHPG0_SI460 +MHPG0_SX10 +MHPG0_SX100 +MHPG0_SX190 +MHPG0_SX280 +MHPG0_SX370 +MJAR0_SA1 +MJAR0_SA2 +MJAR0_SI1988 +MJAR0_SI2247 +MJAR0_SI728 +MJAR0_SX188 +MJAR0_SX278 +MJAR0_SX368 +MJAR0_SX8 +MJAR0_SX98 +MJBR0_SA1 +MJBR0_SA2 +MJBR0_SI1001 +MJBR0_SI1631 +MJBR0_SI2261 +MJBR0_SX101 +MJBR0_SX11 +MJBR0_SX191 +MJBR0_SX281 +MJBR0_SX371 +MJDH0_SA1 +MJDH0_SA2 +MJDH0_SI1354 +MJDH0_SI1984 +MJDH0_SI724 +MJDH0_SX184 +MJDH0_SX274 +MJDH0_SX364 +MJDH0_SX4 +MJDH0_SX94 +MJDM1_SA1 +MJDM1_SA2 +MJDM1_SI1085 +MJDM1_SI1715 +MJDM1_SI455 +MJDM1_SX185 +MJDM1_SX275 +MJDM1_SX365 +MJDM1_SX5 +MJDM1_SX95 +MJES0_SA1 +MJES0_SA2 +MJES0_SI1384 +MJES0_SI2014 +MJES0_SI754 +MJES0_SX124 +MJES0_SX214 +MJES0_SX304 +MJES0_SX34 +MJES0_SX394 +MJFC0_SA1 +MJFC0_SA2 +MJFC0_SI1033 +MJFC0_SI1663 +MJFC0_SI2293 +MJFC0_SX133 +MJFC0_SX223 +MJFC0_SX313 +MJFC0_SX403 +MJFC0_SX43 +MJJG0_SA1 +MJJG0_SA2 +MJJG0_SI1003 +MJJG0_SI1633 +MJJG0_SI2263 +MJJG0_SX103 +MJJG0_SX13 +MJJG0_SX193 +MJJG0_SX283 +MJJG0_SX373 +MJLN0_SA1 +MJLN0_SA2 +MJLN0_SI1449 +MJLN0_SI2079 +MJLN0_SI819 +MJLN0_SX189 +MJLN0_SX279 +MJLN0_SX369 +MJLN0_SX9 +MJLN0_SX99 +MJMP0_SA1 +MJMP0_SA2 +MJMP0_SI1535 +MJMP0_SI1791 +MJMP0_SI905 +MJMP0_SX185 +MJMP0_SX275 +MJMP0_SX365 +MJMP0_SX5 +MJMP0_SX95 +MJRF0_SA1 +MJRF0_SA2 +MJRF0_SI1114 +MJRF0_SI2081 +MJRF0_SI821 +MJRF0_SX101 +MJRF0_SX11 +MJRF0_SX191 +MJRF0_SX281 +MJRF0_SX371 +MJSW0_SA1 +MJSW0_SA2 +MJSW0_SI1010 +MJSW0_SI1640 +MJSW0_SI2270 +MJSW0_SX110 +MJSW0_SX20 +MJSW0_SX200 +MJSW0_SX290 +MJSW0_SX380 +MJTC0_SA1 +MJTC0_SA2 +MJTC0_SI1460 +MJTC0_SI2090 +MJTC0_SI830 +MJTC0_SX110 +MJTC0_SX20 +MJTC0_SX200 +MJTC0_SX290 +MJTC0_SX380 +MJTH0_SA1 +MJTH0_SA2 +MJTH0_SI1296 +MJTH0_SI1926 +MJTH0_SI666 +MJTH0_SX126 +MJTH0_SX216 +MJTH0_SX306 +MJTH0_SX36 +MJTH0_SX396 +MJVW0_SA1 +MJVW0_SA2 +MJVW0_SI1733 +MJVW0_SI1758 +MJVW0_SI473 +MJVW0_SX113 +MJVW0_SX203 +MJVW0_SX23 +MJVW0_SX293 +MJVW0_SX383 +MKCH0_SA1 +MKCH0_SA2 +MKCH0_SI1378 +MKCH0_SI1425 +MKCH0_SI2008 +MKCH0_SX118 +MKCH0_SX208 +MKCH0_SX28 +MKCH0_SX298 +MKCH0_SX388 +MKCL0_SA1 +MKCL0_SA2 +MKCL0_SI1091 +MKCL0_SI1721 +MKCL0_SI461 +MKCL0_SX101 +MKCL0_SX11 +MKCL0_SX191 +MKCL0_SX281 +MKCL0_SX371 +MKDR0_SA1 +MKDR0_SA2 +MKDR0_SI1273 +MKDR0_SI1903 +MKDR0_SI643 +MKDR0_SX103 +MKDR0_SX13 +MKDR0_SX193 +MKDR0_SX283 +MKDR0_SX373 +MKJL0_SA1 +MKJL0_SA2 +MKJL0_SI1100 +MKJL0_SI1730 +MKJL0_SI470 +MKJL0_SX110 +MKJL0_SX20 +MKJL0_SX200 +MKJL0_SX290 +MKJL0_SX380 +MKLT0_SA1 +MKLT0_SA2 +MKLT0_SI1213 +MKLT0_SI1843 +MKLT0_SI583 +MKLT0_SX133 +MKLT0_SX223 +MKLT0_SX313 +MKLT0_SX403 +MKLT0_SX43 +MLIH0_SA1 +MLIH0_SA2 +MLIH0_SI1183 +MLIH0_SI1813 +MLIH0_SI553 +MLIH0_SX103 +MLIH0_SX13 +MLIH0_SX193 +MLIH0_SX283 +MLIH0_SX373 +MLJB0_SA1 +MLJB0_SA2 +MLJB0_SI1310 +MLJB0_SI1940 +MLJB0_SI680 +MLJB0_SX140 +MLJB0_SX230 +MLJB0_SX320 +MLJB0_SX410 +MLJB0_SX50 +MLLL0_SA1 +MLLL0_SA2 +MLLL0_SI1363 +MLLL0_SI1993 +MLLL0_SI733 +MLLL0_SX103 +MLLL0_SX13 +MLLL0_SX193 +MLLL0_SX283 +MLLL0_SX373 +MLNT0_SA1 +MLNT0_SA2 +MLNT0_SI1574 +MLNT0_SI1902 +MLNT0_SI642 +MLNT0_SX102 +MLNT0_SX12 +MLNT0_SX192 +MLNT0_SX282 +MLNT0_SX372 +MMAB0_SA1 +MMAB0_SA2 +MMAB0_SI1362 +MMAB0_SI1992 +MMAB0_SI732 +MMAB0_SX102 +MMAB0_SX12 +MMAB0_SX192 +MMAB0_SX282 +MMAB0_SX372 +MMDB1_SA1 +MMDB1_SA2 +MMDB1_SI1625 +MMDB1_SI2255 +MMDB1_SI995 +MMDB1_SX185 +MMDB1_SX275 +MMDB1_SX365 +MMDB1_SX5 +MMDB1_SX95 +MMDH0_SA1 +MMDH0_SA2 +MMDH0_SI1656 +MMDH0_SI2118 +MMDH0_SI2286 +MMDH0_SX126 +MMDH0_SX216 +MMDH0_SX306 +MMDH0_SX36 +MMDH0_SX396 +MMDM2_SA1 +MMDM2_SA2 +MMDM2_SI1452 +MMDM2_SI1555 +MMDM2_SI2082 +MMDM2_SX102 +MMDM2_SX12 +MMDM2_SX192 +MMDM2_SX282 +MMDM2_SX372 +MMJR0_SA1 +MMJR0_SA2 +MMJR0_SI1648 +MMJR0_SI2166 +MMJR0_SI2278 +MMJR0_SX118 +MMJR0_SX208 +MMJR0_SX28 +MMJR0_SX298 +MMJR0_SX388 +MMWH0_SA1 +MMWH0_SA2 +MMWH0_SI1089 +MMWH0_SI1301 +MMWH0_SI459 +MMWH0_SX189 +MMWH0_SX279 +MMWH0_SX369 +MMWH0_SX9 +MMWH0_SX99 +MNJM0_SA1 +MNJM0_SA2 +MNJM0_SI1580 +MNJM0_SI2210 +MNJM0_SI950 +MNJM0_SX140 +MNJM0_SX230 +MNJM0_SX320 +MNJM0_SX410 +MNJM0_SX50 +MNLS0_SA1 +MNLS0_SA2 +MNLS0_SI1483 +MNLS0_SI1610 +MNLS0_SI853 +MNLS0_SX133 +MNLS0_SX223 +MNLS0_SX313 +MNLS0_SX403 +MNLS0_SX43 +MPAB0_SA1 +MPAB0_SA2 +MPAB0_SI1103 +MPAB0_SI1128 +MPAB0_SI498 +MPAB0_SX138 +MPAB0_SX228 +MPAB0_SX318 +MPAB0_SX408 +MPAB0_SX48 +MPAM0_SA1 +MPAM0_SA2 +MPAM0_SI1189 +MPAM0_SI1819 +MPAM0_SI1961 +MPAM0_SX109 +MPAM0_SX19 +MPAM0_SX199 +MPAM0_SX289 +MPAM0_SX379 +MPAM1_SA1 +MPAM1_SA2 +MPAM1_SI1029 +MPAM1_SI1836 +MPAM1_SI576 +MPAM1_SX126 +MPAM1_SX216 +MPAM1_SX306 +MPAM1_SX36 +MPAM1_SX396 +MPCS0_SA1 +MPCS0_SA2 +MPCS0_SI1359 +MPCS0_SI1989 +MPCS0_SI729 +MPCS0_SX189 +MPCS0_SX279 +MPCS0_SX369 +MPCS0_SX9 +MPCS0_SX99 +MPDF0_SA1 +MPDF0_SA2 +MPDF0_SI1542 +MPDF0_SI2172 +MPDF0_SI912 +MPDF0_SX102 +MPDF0_SX12 +MPDF0_SX192 +MPDF0_SX282 +MPDF0_SX372 +MPGL0_SA1 +MPGL0_SA2 +MPGL0_SI1099 +MPGL0_SI1729 +MPGL0_SI469 +MPGL0_SX109 +MPGL0_SX19 +MPGL0_SX199 +MPGL0_SX289 +MPGL0_SX379 +MPLB0_SA1 +MPLB0_SA2 +MPLB0_SI1394 +MPLB0_SI2024 +MPLB0_SI764 +MPLB0_SX134 +MPLB0_SX224 +MPLB0_SX314 +MPLB0_SX404 +MPLB0_SX44 +MPWM0_SA1 +MPWM0_SA2 +MPWM0_SI1127 +MPWM0_SI1757 +MPWM0_SI2279 +MPWM0_SX137 +MPWM0_SX227 +MPWM0_SX317 +MPWM0_SX407 +MPWM0_SX47 +MRCS0_SA1 +MRCS0_SA2 +MRCS0_SI1223 +MRCS0_SI1853 +MRCS0_SI593 +MRCS0_SX143 +MRCS0_SX233 +MRCS0_SX323 +MRCS0_SX413 +MRCS0_SX53 +MRCZ0_SA1 +MRCZ0_SA2 +MRCZ0_SI1541 +MRCZ0_SI2171 +MRCZ0_SI911 +MRCZ0_SX101 +MRCZ0_SX11 +MRCZ0_SX191 +MRCZ0_SX281 +MRCZ0_SX371 +MREB0_SA1 +MREB0_SA2 +MREB0_SI1375 +MREB0_SI2005 +MREB0_SI745 +MREB0_SX115 +MREB0_SX205 +MREB0_SX25 +MREB0_SX295 +MREB0_SX385 +MRES0_SA1 +MRES0_SA2 +MRES0_SI1217 +MRES0_SI1847 +MRES0_SI587 +MRES0_SX137 +MRES0_SX227 +MRES0_SX317 +MRES0_SX407 +MRES0_SX47 +MRGG0_SA1 +MRGG0_SA2 +MRGG0_SI1199 +MRGG0_SI1829 +MRGG0_SI569 +MRGG0_SX119 +MRGG0_SX209 +MRGG0_SX29 +MRGG0_SX299 +MRGG0_SX389 +MRJM3_SA1 +MRJM3_SA2 +MRJM3_SI1448 +MRJM3_SI1809 +MRJM3_SI2078 +MRJM3_SX188 +MRJM3_SX278 +MRJM3_SX368 +MRJM3_SX8 +MRJM3_SX98 +MRJM4_SA1 +MRJM4_SA2 +MRJM4_SI1489 +MRJM4_SI2119 +MRJM4_SI859 +MRJM4_SX139 +MRJM4_SX229 +MRJM4_SX319 +MRJM4_SX409 +MRJM4_SX49 +MRJO0_SA1 +MRJO0_SA2 +MRJO0_SI1364 +MRJO0_SI1624 +MRJO0_SI734 +MRJO0_SX104 +MRJO0_SX14 +MRJO0_SX194 +MRJO0_SX284 +MRJO0_SX374 +MRJR0_SA1 +MRJR0_SA2 +MRJR0_SI1182 +MRJR0_SI1812 +MRJR0_SI2313 +MRJR0_SX102 +MRJR0_SX12 +MRJR0_SX192 +MRJR0_SX282 +MRJR0_SX372 +MRJS0_SA1 +MRJS0_SA2 +MRJS0_SI1444 +MRJS0_SI1523 +MRJS0_SI2074 +MRJS0_SX184 +MRJS0_SX274 +MRJS0_SX364 +MRJS0_SX4 +MRJS0_SX94 +MRKO0_SA1 +MRKO0_SA2 +MRKO0_SI1397 +MRKO0_SI2027 +MRKO0_SI767 +MRKO0_SX137 +MRKO0_SX227 +MRKO0_SX317 +MRKO0_SX407 +MRKO0_SX47 +MRMS1_SA1 +MRMS1_SA2 +MRMS1_SI1487 +MRMS1_SI2117 +MRMS1_SI857 +MRMS1_SX137 +MRMS1_SX227 +MRMS1_SX317 +MRMS1_SX407 +MRMS1_SX47 +MROA0_SA1 +MROA0_SA2 +MROA0_SI1307 +MROA0_SI1970 +MROA0_SI677 +MROA0_SX137 +MROA0_SX227 +MROA0_SX317 +MROA0_SX407 +MROA0_SX47 +MRPC0_SA1 +MRPC0_SA2 +MRPC0_SI1753 +MRPC0_SI493 +MRPC0_SI933 +MRPC0_SX133 +MRPC0_SX223 +MRPC0_SX313 +MRPC0_SX403 +MRPC0_SX43 +MRPP0_SA1 +MRPP0_SA2 +MRPP0_SI1184 +MRPP0_SI1814 +MRPP0_SI554 +MRPP0_SX104 +MRPP0_SX14 +MRPP0_SX194 +MRPP0_SX284 +MRPP0_SX374 +MRRK0_SA1 +MRRK0_SA2 +MRRK0_SI1288 +MRRK0_SI1716 +MRRK0_SI1918 +MRRK0_SX118 +MRRK0_SX208 +MRRK0_SX28 +MRRK0_SX298 +MRRK0_SX388 +MRTK0_SA1 +MRTK0_SA2 +MRTK0_SI1093 +MRTK0_SI1723 +MRTK0_SI1750 +MRTK0_SX103 +MRTK0_SX13 +MRTK0_SX193 +MRTK0_SX283 +MRTK0_SX373 +MRWS1_SA1 +MRWS1_SA2 +MRWS1_SI1130 +MRWS1_SI1496 +MRWS1_SI500 +MRWS1_SX140 +MRWS1_SX230 +MRWS1_SX320 +MRWS1_SX410 +MRWS1_SX50 +MSFH1_SA1 +MSFH1_SA2 +MSFH1_SI1270 +MSFH1_SI1900 +MSFH1_SI640 +MSFH1_SX10 +MSFH1_SX100 +MSFH1_SX190 +MSFH1_SX280 +MSFH1_SX370 +MSJS1_SA1 +MSJS1_SA2 +MSJS1_SI1899 +MSJS1_SI639 +MSJS1_SI869 +MSJS1_SX189 +MSJS1_SX279 +MSJS1_SX369 +MSJS1_SX9 +MSJS1_SX99 +MSLB0_SA1 +MSLB0_SA2 +MSLB0_SI1193 +MSLB0_SI1823 +MSLB0_SI563 +MSLB0_SX113 +MSLB0_SX203 +MSLB0_SX23 +MSLB0_SX293 +MSLB0_SX383 +MSTK0_SA1 +MSTK0_SA2 +MSTK0_SI1024 +MSTK0_SI2222 +MSTK0_SI2284 +MSTK0_SX124 +MSTK0_SX214 +MSTK0_SX304 +MSTK0_SX34 +MSTK0_SX394 +MTAA0_SA1 +MTAA0_SA2 +MTAA0_SI1285 +MTAA0_SI1915 +MTAA0_SI596 +MTAA0_SX115 +MTAA0_SX205 +MTAA0_SX25 +MTAA0_SX295 +MTAA0_SX385 +MTAS1_SA1 +MTAS1_SA2 +MTAS1_SI1473 +MTAS1_SI2098 +MTAS1_SI838 +MTAS1_SX118 +MTAS1_SX208 +MTAS1_SX28 +MTAS1_SX298 +MTAS1_SX388 +MTDT0_SA1 +MTDT0_SA2 +MTDT0_SI1994 +MTDT0_SI2254 +MTDT0_SI994 +MTDT0_SX184 +MTDT0_SX274 +MTDT0_SX364 +MTDT0_SX4 +MTDT0_SX94 +MTEB0_SA1 +MTEB0_SA2 +MTEB0_SI1133 +MTEB0_SI2064 +MTEB0_SI503 +MTEB0_SX143 +MTEB0_SX233 +MTEB0_SX323 +MTEB0_SX413 +MTEB0_SX53 +MTHC0_SA1 +MTHC0_SA2 +MTHC0_SI1015 +MTHC0_SI1645 +MTHC0_SI2275 +MTHC0_SX115 +MTHC0_SX205 +MTHC0_SX25 +MTHC0_SX295 +MTHC0_SX385 +MTLS0_SA1 +MTLS0_SA2 +MTLS0_SI1370 +MTLS0_SI2000 +MTLS0_SI740 +MTLS0_SX110 +MTLS0_SX20 +MTLS0_SX200 +MTLS0_SX290 +MTLS0_SX380 +MTMR0_SA1 +MTMR0_SA2 +MTMR0_SI1303 +MTMR0_SI1933 +MTMR0_SI673 +MTMR0_SX133 +MTMR0_SX223 +MTMR0_SX313 +MTMR0_SX403 +MTMR0_SX43 +MTWH0_SA1 +MTWH0_SA2 +MTWH0_SI1190 +MTWH0_SI1629 +MTWH0_SI1820 +MTWH0_SX110 +MTWH0_SX20 +MTWH0_SX200 +MTWH0_SX290 +MTWH0_SX380 +MWBT0_SA1 +MWBT0_SA2 +MWBT0_SI1553 +MWBT0_SI2183 +MWBT0_SI923 +MWBT0_SX113 +MWBT0_SX203 +MWBT0_SX23 +MWBT0_SX293 +MWBT0_SX383 +MWEW0_SA1 +MWEW0_SA2 +MWEW0_SI1361 +MWEW0_SI1991 +MWEW0_SI731 +MWEW0_SX101 +MWEW0_SX11 +MWEW0_SX191 +MWEW0_SX281 +MWEW0_SX371 +MWJG0_SA1 +MWJG0_SA2 +MWJG0_SI1124 +MWJG0_SI1754 +MWJG0_SI494 +MWJG0_SX134 +MWJG0_SX224 +MWJG0_SX314 +MWJG0_SX404 +MWJG0_SX44 +MWVW0_SA1 +MWVW0_SA2 +MWVW0_SI1476 +MWVW0_SI2106 +MWVW0_SI846 +MWVW0_SX126 +MWVW0_SX216 +MWVW0_SX306 +MWVW0_SX36 +MWVW0_SX396 diff --git a/examples/wav2vec/unsupervised/config/timit_unmatched/train.uid b/examples/wav2vec/unsupervised/config/timit_unmatched/train.uid new file mode 100644 index 0000000000..35b02e7f82 --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_unmatched/train.uid @@ -0,0 +1,3000 @@ +FAEM0_SA1 +FAEM0_SA2 +FAEM0_SI2022 +FAEM0_SX132 +FAEM0_SX222 +FAEM0_SX312 +FAEM0_SX402 +FAJW0_SA2 +FAJW0_SI1893 +FAJW0_SX183 +FAJW0_SX273 +FAJW0_SX363 +FALK0_SA1 +FALK0_SA2 +FALK0_SI1086 +FALK0_SI456 +FALK0_SX276 +FALK0_SX366 +FALK0_SX96 +FALR0_SA1 +FALR0_SA2 +FALR0_SI1955 +FALR0_SI695 +FALR0_SX155 +FALR0_SX245 +FALR0_SX425 +FALR0_SX65 +FAPB0_SA1 +FAPB0_SA2 +FAPB0_SI1693 +FAPB0_SX163 +FAPB0_SX253 +FAPB0_SX343 +FAPB0_SX73 +FBAS0_SA2 +FBAS0_SI1387 +FBAS0_SX127 +FBAS0_SX307 +FBAS0_SX37 +FBAS0_SX397 +FBCG1_SA2 +FBCG1_SI1612 +FBCG1_SI2242 +FBCG1_SI982 +FBCG1_SX262 +FBCG1_SX82 +FBCH0_SA1 +FBCH0_SA2 +FBCH0_SI1586 +FBCH0_SI956 +FBCH0_SX146 +FBCH0_SX326 +FBCH0_SX56 +FBJL0_SA1 +FBJL0_SA2 +FBJL0_SI1552 +FBJL0_SI2182 +FBJL0_SX112 +FBJL0_SX202 +FBJL0_SX22 +FBJL0_SX292 +FBJL0_SX382 +FBLV0_SA2 +FBLV0_SI2318 +FBLV0_SX158 +FBLV0_SX248 +FBLV0_SX428 +FBMH0_SA2 +FBMH0_SI1766 +FBMH0_SX146 +FBMH0_SX236 +FBMH0_SX326 +FBMH0_SX416 +FBMH0_SX56 +FBMJ0_SA2 +FBMJ0_SX156 +FBMJ0_SX246 +FBMJ0_SX426 +FBMJ0_SX66 +FCAG0_SA2 +FCAG0_SI1503 +FCAG0_SI1641 +FCAG0_SI2133 +FCAG0_SX333 +FCAG0_SX423 +FCAG0_SX63 +FCAJ0_SA1 +FCAJ0_SA2 +FCAJ0_SI1804 +FCAJ0_SI849 +FCAJ0_SX129 +FCAJ0_SX219 +FCAJ0_SX39 +FCAJ0_SX399 +FCDR1_SA1 +FCDR1_SA2 +FCDR1_SX16 +FCDR1_SX376 +FCEG0_SA1 +FCEG0_SI1248 +FCEG0_SI1878 +FCEG0_SI618 +FCEG0_SX168 +FCEG0_SX258 +FCEG0_SX348 +FCEG0_SX438 +FCEG0_SX78 +FCJF0_SA2 +FCJF0_SI1027 +FCJF0_SI1657 +FCJF0_SI648 +FCJF0_SX217 +FCJF0_SX307 +FCJF0_SX37 +FCJF0_SX397 +FCJS0_SA1 +FCJS0_SA2 +FCJS0_SI977 +FCJS0_SX167 +FCJS0_SX347 +FCJS0_SX437 +FCJS0_SX77 +FCKE0_SA1 +FCKE0_SI1111 +FCKE0_SX211 +FCKE0_SX301 +FCKE0_SX31 +FCKE0_SX391 +FCLT0_SA1 +FCLT0_SA2 +FCLT0_SI1438 +FCLT0_SX178 +FCLT0_SX268 +FCLT0_SX358 +FCMG0_SA1 +FCMG0_SI1242 +FCMG0_SX162 +FCMG0_SX252 +FCMG0_SX342 +FCMM0_SI1083 +FCMM0_SI453 +FCMM0_SX273 +FCMM0_SX363 +FCMM0_SX93 +FCRZ0_SA1 +FCRZ0_SA2 +FCRZ0_SI1913 +FCRZ0_SI793 +FCRZ0_SX163 +FCRZ0_SX253 +FCRZ0_SX343 +FCRZ0_SX73 +FCYL0_SA2 +FCYL0_SI1297 +FCYL0_SI1927 +FCYL0_SX127 +FCYL0_SX217 +FCYL0_SX397 +FDAS1_SA1 +FDAS1_SA2 +FDAS1_SX111 +FDAS1_SX21 +FDAS1_SX291 +FDAW0_SA1 +FDAW0_SA2 +FDAW0_SX146 +FDAW0_SX236 +FDAW0_SX326 +FDAW0_SX416 +FDAW0_SX56 +FDFB0_SI1318 +FDFB0_SI1948 +FDFB0_SX148 +FDFB0_SX238 +FDFB0_SX328 +FDFB0_SX418 +FDJH0_SA1 +FDJH0_SA2 +FDJH0_SI1565 +FDJH0_SI2195 +FDJH0_SX125 +FDJH0_SX215 +FDJH0_SX35 +FDJH0_SX395 +FDKN0_SA1 +FDKN0_SA2 +FDKN0_SI1081 +FDKN0_SI1711 +FDKN0_SX271 +FDKN0_SX361 +FDKN0_SX91 +FDML0_SA1 +FDML0_SI1149 +FDML0_SI1779 +FDML0_SI2075 +FDML0_SX339 +FDML0_SX69 +FDMY0_SI1197 +FDMY0_SX117 +FDMY0_SX207 +FDMY0_SX297 +FDNC0_SA1 +FDNC0_SA2 +FDNC0_SI2287 +FDNC0_SX108 +FDNC0_SX18 +FDNC0_SX378 +FDTD0_SA2 +FDTD0_SI1561 +FDTD0_SI2191 +FDTD0_SI931 +FDTD0_SX121 +FDTD0_SX301 +FDTD0_SX391 +FDXW0_SA2 +FDXW0_SI1511 +FDXW0_SI2141 +FDXW0_SI881 +FDXW0_SX161 +FDXW0_SX431 +FEAC0_SA1 +FEAC0_SA2 +FEAC0_SI1245 +FEAC0_SI1875 +FEAC0_SX255 +FEAC0_SX345 +FEAC0_SX435 +FEAR0_SA1 +FEAR0_SA2 +FEAR0_SI1252 +FEAR0_SI1882 +FEAR0_SX172 +FEAR0_SX262 +FEAR0_SX442 +FEAR0_SX82 +FECD0_SA2 +FECD0_SI2048 +FECD0_SX158 +FECD0_SX248 +FECD0_SX338 +FECD0_SX428 +FEEH0_SA2 +FEEH0_SI1112 +FEEH0_SX212 +FEEH0_SX302 +FEEH0_SX32 +FEEH0_SX392 +FEME0_SA2 +FEME0_SI1505 +FEME0_SI2135 +FEME0_SX245 +FEME0_SX425 +FETB0_SA2 +FETB0_SI1778 +FETB0_SI518 +FETB0_SX248 +FETB0_SX338 +FETB0_SX428 +FETB0_SX68 +FEXM0_SA2 +FEXM0_SI1731 +FEXM0_SX111 +FEXM0_SX201 +FEXM0_SX291 +FEXM0_SX381 +FGCS0_SA1 +FGCS0_SA2 +FGCS0_SI1486 +FGCS0_SI2116 +FGCS0_SI856 +FGCS0_SX46 +FGDP0_SA2 +FGDP0_SI1618 +FGDP0_SI2248 +FGDP0_SX178 +FGDP0_SX268 +FGDP0_SX358 +FGDP0_SX448 +FGMB0_SA1 +FGMB0_SA2 +FGMB0_SI515 +FGMB0_SX155 +FGMB0_SX425 +FGMB0_SX65 +FGRW0_SA2 +FGRW0_SI1782 +FGRW0_SI1990 +FGRW0_SX252 +FGRW0_SX342 +FGRW0_SX72 +FHLM0_SA1 +FHLM0_SA2 +FHLM0_SI1560 +FHLM0_SI2190 +FHLM0_SI930 +FHLM0_SX210 +FHLM0_SX300 +FHXS0_SI2335 +FHXS0_SX265 +FHXS0_SX355 +FHXS0_SX85 +FJDM2_SI1582 +FJDM2_SI1964 +FJDM2_SI2212 +FJDM2_SX322 +FJDM2_SX412 +FJEN0_SA2 +FJEN0_SI1047 +FJEN0_SI1677 +FJEN0_SI2307 +FJEN0_SX147 +FJEN0_SX237 +FJEN0_SX57 +FJHK0_SA1 +FJHK0_SA2 +FJHK0_SI1022 +FJHK0_SI1652 +FJHK0_SX122 +FJHK0_SX212 +FJHK0_SX32 +FJHK0_SX392 +FJKL0_SA1 +FJKL0_SA2 +FJKL0_SI1562 +FJKL0_SI2192 +FJKL0_SX122 +FJKL0_SX302 +FJKL0_SX32 +FJLG0_SA1 +FJLG0_SA2 +FJLG0_SI1506 +FJLG0_SX179 +FJLG0_SX269 +FJLG0_SX359 +FJLG0_SX449 +FJLG0_SX89 +FJLR0_SA2 +FJLR0_SI1861 +FJLR0_SI601 +FJLR0_SX151 +FJLR0_SX241 +FJLR0_SX331 +FJLR0_SX421 +FJLR0_SX61 +FJRB0_SA1 +FJRB0_SA2 +FJRB0_SI1302 +FJRB0_SI1932 +FJRB0_SI672 +FJRB0_SX132 +FJRB0_SX222 +FJRB0_SX312 +FJRB0_SX42 +FJRP1_SA2 +FJRP1_SI802 +FJRP1_SX172 +FJRP1_SX442 +FJSK0_SA2 +FJSK0_SI1682 +FJSK0_SI2312 +FJSK0_SX152 +FJSK0_SX242 +FJSK0_SX332 +FJSK0_SX422 +FJSK0_SX62 +FJSP0_SA1 +FJSP0_SA2 +FJSP0_SI1763 +FJSP0_SI804 +FJSP0_SX174 +FJSP0_SX84 +FJWB1_SA2 +FJWB1_SI2055 +FJWB1_SI795 +FJWB1_SX165 +FJWB1_SX255 +FJWB1_SX75 +FJXM0_SA2 +FJXM0_SI1211 +FJXM0_SI1971 +FJXM0_SX131 +FJXM0_SX221 +FJXP0_SA2 +FJXP0_SI492 +FJXP0_SX222 +FJXP0_SX312 +FJXP0_SX402 +FJXP0_SX42 +FKAA0_SA2 +FKAA0_SI1208 +FKAA0_SI1838 +FKAA0_SI578 +FKAA0_SX218 +FKAA0_SX308 +FKAA0_SX38 +FKDE0_SA2 +FKDE0_SI2221 +FKDE0_SX331 +FKDW0_SA1 +FKDW0_SA2 +FKDW0_SI577 +FKDW0_SX127 +FKDW0_SX217 +FKDW0_SX307 +FKDW0_SX37 +FKFB0_SA1 +FKFB0_SI2238 +FKFB0_SI978 +FKFB0_SX168 +FKFB0_SX258 +FKKH0_SI660 +FKKH0_SX210 +FKKH0_SX30 +FKKH0_SX300 +FKLC0_SA1 +FKLC0_SA2 +FKLC0_SI1615 +FKLC0_SI2245 +FKLC0_SX265 +FKLC0_SX445 +FKLC0_SX85 +FKLC1_SA1 +FKLC1_SA2 +FKLC1_SI1678 +FKLC1_SX148 +FKLC1_SX58 +FKLH0_SA1 +FKLH0_SI1887 +FKLH0_SI627 +FKLH0_SX267 +FKLH0_SX357 +FKLH0_SX447 +FKLH0_SX87 +FKSR0_SI1117 +FKSR0_SX161 +FKSR0_SX37 +FKSR0_SX397 +FLAC0_SA1 +FLAC0_SA2 +FLAC0_SI2161 +FLAC0_SI901 +FLAC0_SX181 +FLAC0_SX271 +FLAC0_SX361 +FLAC0_SX91 +FLAG0_SA1 +FLAG0_SI2094 +FLAG0_SX294 +FLEH0_SA1 +FLEH0_SA2 +FLEH0_SX151 +FLEH0_SX241 +FLEH0_SX421 +FLEH0_SX61 +FLET0_SA2 +FLET0_SI1137 +FLET0_SI1767 +FLET0_SX147 +FLET0_SX237 +FLET0_SX277 +FLET0_SX417 +FLET0_SX57 +FLHD0_SA1 +FLHD0_SA2 +FLHD0_SI1344 +FLHD0_SI1974 +FLHD0_SX174 +FLHD0_SX264 +FLHD0_SX444 +FLHD0_SX84 +FLJA0_SA2 +FLJA0_SI1708 +FLJA0_SX268 +FLJA0_SX358 +FLJA0_SX448 +FLJA0_SX88 +FLJD0_SA1 +FLJD0_SA2 +FLJD0_SI2146 +FLJD0_SX166 +FLJD0_SX256 +FLJD0_SX346 +FLJD0_SX436 +FLJG0_SA1 +FLJG0_SI1611 +FLJG0_SI2241 +FLJG0_SX261 +FLJG0_SX441 +FLJG0_SX81 +FLKM0_SI1880 +FLKM0_SX116 +FLMA0_SA2 +FLMA0_SI1243 +FLMA0_SI1873 +FLMA0_SX163 +FLMA0_SX253 +FLMA0_SX343 +FLMC0_SA1 +FLMC0_SA2 +FLMC0_SI2002 +FLMC0_SI742 +FLMC0_SX112 +FLMC0_SX292 +FLMC0_SX336 +FLMC0_SX382 +FLMK0_SA2 +FLMK0_SI2295 +FLMK0_SX135 +FLMK0_SX225 +FLMK0_SX45 +FLOD0_SA1 +FLOD0_SA2 +FLOD0_SI1287 +FLOD0_SI657 +FLOD0_SX207 +FLOD0_SX387 +FLTM0_SA2 +FLTM0_SI1700 +FLTM0_SX260 +FLTM0_SX80 +FMAH1_SA1 +FMAH1_SI1509 +FMAH1_SI2139 +FMAH1_SX249 +FMAH1_SX339 +FMAH1_SX429 +FMAH1_SX69 +FMBG0_SA1 +FMBG0_SI1790 +FMBG0_SX260 +FMBG0_SX3 +FMBG0_SX350 +FMBG0_SX440 +FMBG0_SX80 +FMEM0_SA2 +FMEM0_SI1377 +FMEM0_SI2007 +FMEM0_SX117 +FMEM0_SX207 +FMEM0_SX297 +FMJB0_SA1 +FMJB0_SA2 +FMJB0_SI1807 +FMJB0_SX187 +FMJB0_SX277 +FMJB0_SX367 +FMJB0_SX7 +FMJF0_SA1 +FMJF0_SI1254 +FMJF0_SI1884 +FMJF0_SX264 +FMJF0_SX354 +FMJF0_SX444 +FMJU0_SA1 +FMJU0_SA2 +FMJU0_SI2019 +FMJU0_SI759 +FMJU0_SX129 +FMJU0_SX219 +FMJU0_SX39 +FMKC0_SA1 +FMKC0_SA2 +FMKC0_SI1072 +FMKC0_SX172 +FMKC0_SX262 +FMKC0_SX352 +FMKF0_SA1 +FMKF0_SA2 +FMKF0_SI1536 +FMKF0_SI906 +FMKF0_SX276 +FMKF0_SX366 +FMKF0_SX6 +FMKF0_SX96 +FMMH0_SA1 +FMMH0_SA2 +FMMH0_SI1537 +FMMH0_SI2167 +FMMH0_SI907 +FMMH0_SX187 +FMMH0_SX367 +FMMH0_SX420 +FMMH0_SX7 +FMMH0_SX97 +FMPG0_SI1602 +FMPG0_SI2232 +FMPG0_SX252 +FMPG0_SX72 +FNKL0_SA1 +FNKL0_SA2 +FNKL0_SI2152 +FNKL0_SX172 +FNKL0_SX196 +FNKL0_SX262 +FNKL0_SX442 +FNKL0_SX82 +FNTB0_SA1 +FNTB0_SA2 +FNTB0_SX123 +FNTB0_SX213 +FNTB0_SX33 +FNTB0_SX393 +FPAB1_SA2 +FPAB1_SX121 +FPAB1_SX301 +FPAB1_SX31 +FPAB1_SX391 +FPAC0_SA1 +FPAC0_SI2011 +FPAC0_SX121 +FPAC0_SX211 +FPAC0_SX301 +FPAC0_SX31 +FPAC0_SX391 +FPAD0_SA1 +FPAD0_SI1346 +FPAD0_SI1976 +FPAD0_SX266 +FPAD0_SX446 +FPAF0_SI1684 +FPAF0_SI2314 +FPAF0_SX244 +FPAF0_SX334 +FPAF0_SX424 +FPAF0_SX64 +FPAZ0_SI1593 +FPAZ0_SX153 +FPAZ0_SX27 +FPAZ0_SX423 +FPAZ0_SX63 +FPJF0_SA2 +FPJF0_SI1046 +FPJF0_SI1676 +FPJF0_SX236 +FPJF0_SX326 +FPLS0_SA1 +FPLS0_SA2 +FPLS0_SI2220 +FPLS0_SX150 +FPLS0_SX240 +FPLS0_SX3 +FPLS0_SX60 +FPMY0_SA2 +FPMY0_SI1783 +FPMY0_SX163 +FPMY0_SX196 +FPMY0_SX253 +FPMY0_SX73 +FREH0_SI1315 +FREH0_SI685 +FREH0_SX145 +FREH0_SX235 +FREH0_SX325 +FREH0_SX55 +FRJB0_SA1 +FRJB0_SA2 +FRJB0_SI1427 +FRJB0_SI1470 +FRJB0_SI1794 +FRJB0_SX167 +FRJB0_SX257 +FRJB0_SX437 +FRJB0_SX77 +FRLL0_SA1 +FRLL0_SA2 +FRLL0_SI1514 +FRLL0_SI884 +FRLL0_SX164 +FRLL0_SX254 +FRLL0_SX344 +FRLL0_SX74 +FSAG0_SA2 +FSAG0_SI1953 +FSAG0_SI693 +FSAG0_SX63 +FSAH0_SI1244 +FSAH0_SI1874 +FSAH0_SX344 +FSAH0_SX74 +FSAK0_SA1 +FSAK0_SA2 +FSAK0_SI1930 +FSAK0_SI670 +FSAK0_SX130 +FSAK0_SX220 +FSAK0_SX310 +FSAK0_SX40 +FSAK0_SX400 +FSBK0_SA1 +FSBK0_SI1699 +FSBK0_SI2329 +FSBK0_SX259 +FSBK0_SX439 +FSBK0_SX79 +FSCN0_SI1886 +FSCN0_SX356 +FSDC0_SA1 +FSDC0_SI1942 +FSDC0_SI2234 +FSDC0_SX232 +FSDC0_SX412 +FSDJ0_SA1 +FSDJ0_SA2 +FSDJ0_SI1745 +FSDJ0_SX125 +FSDJ0_SX35 +FSGF0_SA1 +FSGF0_SA2 +FSGF0_SI1557 +FSGF0_SX207 +FSGF0_SX27 +FSGF0_SX297 +FSGF0_SX387 +FSJG0_SI1570 +FSJG0_SI2200 +FSJG0_SX310 +FSJK1_SA1 +FSJK1_SI1025 +FSJK1_SI2285 +FSJK1_SI696 +FSJK1_SX215 +FSJK1_SX305 +FSJK1_SX395 +FSJS0_SA2 +FSJS0_SI1171 +FSJS0_SI1801 +FSJS0_SI541 +FSJS0_SX271 +FSJS0_SX361 +FSJS0_SX91 +FSJW0_SA1 +FSJW0_SA2 +FSJW0_SI703 +FSJW0_SX163 +FSJW0_SX253 +FSJW0_SX343 +FSJW0_SX73 +FSKC0_SA1 +FSKC0_SA2 +FSKC0_SI2046 +FSKC0_SX156 +FSKC0_SX336 +FSKC0_SX426 +FSKC0_SX66 +FSKL0_SA1 +FSKL0_SA2 +FSKL0_SI2159 +FSKL0_SI899 +FSKL0_SX179 +FSKL0_SX269 +FSKL0_SX359 +FSKL0_SX89 +FSKP0_SA1 +FSKP0_SI1728 +FSKP0_SI468 +FSKP0_SX108 +FSKP0_SX18 +FSKP0_SX198 +FSKP0_SX288 +FSKP0_SX378 +FSLS0_SA1 +FSLS0_SA2 +FSLS0_SI1056 +FSLS0_SI1686 +FSLS0_SI2316 +FSLS0_SX202 +FSLS0_SX246 +FSLS0_SX66 +FSMA0_SA1 +FSMA0_SI1621 +FSMA0_SI2251 +FSMA0_SX271 +FSMA0_SX361 +FSMA0_SX91 +FSMM0_SA1 +FSMM0_SA2 +FSMM0_SI1314 +FSMM0_SI1944 +FSMM0_SI684 +FSMM0_SX414 +FSMM0_SX54 +FSMS1_SA1 +FSMS1_SA2 +FSMS1_SI1504 +FSMS1_SI2134 +FSMS1_SI874 +FSMS1_SX154 +FSMS1_SX334 +FSMS1_SX64 +FSPM0_SA1 +FSPM0_SI1871 +FSPM0_SI611 +FSPM0_SX341 +FSPM0_SX431 +FSRH0_SA1 +FSRH0_SA2 +FSRH0_SI1719 +FSRH0_SX131 +FSRH0_SX41 +FSSB0_SA1 +FSSB0_SA2 +FSSB0_SI1082 +FSSB0_SI2342 +FSSB0_SX182 +FSSB0_SX272 +FSSB0_SX452 +FSSB0_SX92 +FTAJ0_SA1 +FTAJ0_SA2 +FTAJ0_SI1329 +FTAJ0_SI474 +FTAJ0_SX339 +FTAJ0_SX69 +FTBR0_SA1 +FTBR0_SA2 +FTBR0_SI2181 +FTBR0_SX111 +FTBR0_SX201 +FTBR0_SX291 +FTBR0_SX381 +FTBW0_SA2 +FTBW0_SI1345 +FTBW0_SI1975 +FTBW0_SX265 +FTBW0_SX355 +FTBW0_SX445 +FTBW0_SX85 +FTLG0_SA1 +FTLG0_SA2 +FTLG0_SI840 +FTLG0_SX123 +FTLG0_SX213 +FTLG0_SX303 +FTLG0_SX33 +FTLG0_SX393 +FTMG0_SA1 +FTMG0_SA2 +FTMG0_SX182 +FTMG0_SX272 +FTMG0_SX362 +FTMG0_SX92 +FVFB0_SA1 +FVFB0_SI1032 +FVFB0_SI2292 +FVFB0_SX222 +FVFB0_SX312 +FVFB0_SX402 +FVKB0_SA2 +FVKB0_SI1159 +FVKB0_SI1789 +FVKB0_SI529 +FVKB0_SX169 +FVKB0_SX259 +FVKB0_SX439 +FVKB0_SX79 +FVMH0_SA1 +FVMH0_SI2096 +FVMH0_SX206 +FVMH0_SX296 +FVMH0_SX386 +MABC0_SA1 +MABC0_SA2 +MABC0_SX151 +MABC0_SX241 +MABC0_SX331 +MABC0_SX421 +MABC0_SX61 +MADC0_SA1 +MADC0_SA2 +MADC0_SI1997 +MADC0_SX17 +MADC0_SX197 +MADC0_SX287 +MADD0_SA1 +MADD0_SI1798 +MADD0_SI538 +MADD0_SX358 +MADD0_SX448 +MAEB0_SA1 +MAEB0_SA2 +MAEB0_SI2250 +MAEB0_SI990 +MAEB0_SX180 +MAEB0_SX270 +MAEB0_SX360 +MAEB0_SX90 +MAEO0_SA2 +MAEO0_SI1655 +MAEO0_SI1956 +MAEO0_SX156 +MAEO0_SX246 +MAEO0_SX336 +MAEO0_SX426 +MAEO0_SX66 +MAFM0_SA1 +MAFM0_SA2 +MAFM0_SI1569 +MAFM0_SI2199 +MAFM0_SX219 +MAFM0_SX39 +MAFM0_SX399 +MAJP0_SA1 +MAJP0_SI1074 +MAJP0_SI2334 +MAJP0_SX264 +MAJP0_SX354 +MAJP0_SX444 +MAJP0_SX84 +MAKB0_SA1 +MAKB0_SX206 +MAKB0_SX296 +MAKR0_SA1 +MAKR0_SA2 +MAKR0_SI1352 +MAKR0_SI1982 +MAKR0_SI722 +MAKR0_SX182 +MAKR0_SX272 +MAKR0_SX452 +MAPV0_SA1 +MAPV0_SA2 +MAPV0_SI1923 +MAPV0_SX123 +MAPV0_SX303 +MAPV0_SX33 +MAPV0_SX393 +MARC0_SA1 +MARC0_SI1188 +MARC0_SI1818 +MARC0_SI558 +MARC0_SX288 +MARC0_SX378 +MARW0_SA1 +MARW0_SA2 +MARW0_SI1276 +MARW0_SI646 +MARW0_SX106 +MARW0_SX16 +MARW0_SX376 +MBAR0_SA2 +MBAR0_SI1319 +MBAR0_SI1949 +MBAR0_SI689 +MBAR0_SX149 +MBAR0_SX239 +MBAR0_SX329 +MBBR0_SA1 +MBBR0_SA2 +MBBR0_SI1685 +MBBR0_SX155 +MBBR0_SX245 +MBBR0_SX425 +MBCG0_SA2 +MBCG0_SI2217 +MBCG0_SX147 +MBCG0_SX237 +MBCG0_SX417 +MBCG0_SX57 +MBEF0_SA1 +MBEF0_SA2 +MBEF0_SX111 +MBEF0_SX201 +MBEF0_SX291 +MBGT0_SA1 +MBGT0_SI1341 +MBGT0_SI711 +MBGT0_SX81 +MBJV0_SA2 +MBJV0_SI1247 +MBJV0_SI1877 +MBJV0_SX167 +MBJV0_SX257 +MBJV0_SX437 +MBJV0_SX77 +MBMA0_SA1 +MBMA0_SA2 +MBMA0_SI1852 +MBMA0_SX142 +MBMA0_SX322 +MBMA0_SX412 +MBMA1_SA1 +MBMA1_SA2 +MBMA1_SI2207 +MBMA1_SX144 +MBMA1_SX234 +MBMA1_SX414 +MBML0_SA1 +MBML0_SI1799 +MBML0_SI539 +MBML0_SX179 +MBML0_SX269 +MBML0_SX359 +MBML0_SX449 +MBOM0_SA1 +MBOM0_SI1014 +MBOM0_SI1644 +MBOM0_SX114 +MBOM0_SX204 +MBOM0_SX311 +MBOM0_SX384 +MBSB0_SA2 +MBSB0_SI1353 +MBSB0_SI1983 +MBSB0_SI723 +MBSB0_SX183 +MBSB0_SX273 +MBSB0_SX363 +MBSB0_SX93 +MBTH0_SA1 +MBTH0_SI505 +MBTH0_SI757 +MBTH0_SX212 +MBTH0_SX302 +MBTH0_SX392 +MBWP0_SA1 +MBWP0_SA2 +MBWP0_SI1531 +MBWP0_SI1969 +MBWP0_SI709 +MBWP0_SX169 +MBWP0_SX259 +MBWP0_SX439 +MBWP0_SX79 +MCAE0_SA1 +MCAE0_SA2 +MCAE0_SX187 +MCAE0_SX367 +MCAE0_SX7 +MCAE0_SX97 +MCAL0_SA1 +MCAL0_SI508 +MCAL0_SX148 +MCAL0_SX238 +MCAL0_SX328 +MCAL0_SX418 +MCAL0_SX58 +MCDC0_SA2 +MCDC0_SI1292 +MCDC0_SI1922 +MCDC0_SI662 +MCDC0_SX122 +MCDC0_SX302 +MCDC0_SX32 +MCDC0_SX392 +MCDD0_SA1 +MCDD0_SI1513 +MCDD0_SI2143 +MCDD0_SX163 +MCDD0_SX343 +MCDD0_SX73 +MCDR0_SA1 +MCDR0_SA2 +MCDR0_SX164 +MCDR0_SX254 +MCDR0_SX344 +MCDR0_SX434 +MCDR0_SX74 +MCEF0_SA1 +MCEF0_SA2 +MCEF0_SI1135 +MCEF0_SI1765 +MCEF0_SX145 +MCEF0_SX325 +MCEF0_SX55 +MCEW0_SI1442 +MCEW0_SX182 +MCEW0_SX272 +MCEW0_SX92 +MCHL0_SA1 +MCHL0_SA2 +MCHL0_SI1977 +MCHL0_SX177 +MCHL0_SX267 +MCHL0_SX357 +MCHL0_SX447 +MCLK0_SA1 +MCLK0_SA2 +MCLK0_SI1660 +MCLK0_SX130 +MCLK0_SX220 +MCLK0_SX40 +MCLK0_SX400 +MCLM0_SA2 +MCLM0_SI1456 +MCLM0_SX106 +MCLM0_SX16 +MCLM0_SX196 +MCLM0_SX286 +MCLM0_SX376 +MCPM0_SA2 +MCPM0_SI1194 +MCPM0_SI564 +MCPM0_SX204 +MCPM0_SX24 +MCRE0_SA1 +MCRE0_SA2 +MCRE0_SI1121 +MCRE0_SI1725 +MCRE0_SI1751 +MCRE0_SX131 +MCRE0_SX221 +MCRE0_SX24 +MCRE0_SX401 +MCRE0_SX41 +MCSS0_SA1 +MCSS0_SA2 +MCSS0_SX120 +MCSS0_SX210 +MCSS0_SX30 +MCSS0_SX300 +MCSS0_SX390 +MCTH0_SA2 +MCTH0_SI1209 +MCTH0_SI1839 +MCTH0_SI579 +MCTH0_SX129 +MCTH0_SX219 +MCTH0_SX309 +MCTH0_SX399 +MCTM0_SA1 +MCTM0_SA2 +MCTM0_SI720 +MCTM0_SX180 +MCTM0_SX270 +MCTM0_SX360 +MCTM0_SX450 +MCTM0_SX90 +MCXM0_SA1 +MCXM0_SA2 +MCXM0_SI1351 +MCXM0_SI1981 +MCXM0_SI721 +MCXM0_SX181 +MCXM0_SX271 +MCXM0_SX361 +MCXM0_SX451 +MDAC0_SA2 +MDAC0_SI1261 +MDAC0_SI1837 +MDAC0_SX271 +MDAC0_SX451 +MDAC0_SX91 +MDAS0_SA1 +MDAS0_SA2 +MDAS0_SI1266 +MDAS0_SX186 +MDAS0_SX21 +MDAS0_SX276 +MDAS0_SX96 +MDBB1_SA1 +MDBB1_SA2 +MDBB1_SI1006 +MDBB1_SI1636 +MDBB1_SI2056 +MDBB1_SX196 +MDBB1_SX286 +MDBP0_SA1 +MDBP0_SA2 +MDBP0_SI1158 +MDBP0_SI1788 +MDBP0_SX258 +MDBP0_SX348 +MDBP0_SX78 +MDCD0_SA1 +MDCD0_SA2 +MDCD0_SI2045 +MDCD0_SX155 +MDCD0_SX65 +MDCM0_SA1 +MDCM0_SA2 +MDCM0_SI2110 +MDCM0_SI850 +MDCM0_SX130 +MDCM0_SX220 +MDCM0_SX310 +MDDC0_SA1 +MDDC0_SA2 +MDDC0_SX249 +MDDC0_SX339 +MDDC0_SX429 +MDED0_SI1170 +MDED0_SI1800 +MDED0_SX180 +MDED0_SX270 +MDED0_SX360 +MDED0_SX450 +MDED0_SX90 +MDEF0_SA1 +MDEF0_SA2 +MDEF0_SI1563 +MDEF0_SI2193 +MDEF0_SX213 +MDEF0_SX33 +MDEF0_SX393 +MDEM0_SA2 +MDEM0_SI1868 +MDEM0_SX158 +MDEM0_SX248 +MDEM0_SX338 +MDEM0_SX68 +MDHL0_SA1 +MDHL0_SA2 +MDHL0_SI2069 +MDHL0_SI809 +MDHL0_SX179 +MDHL0_SX359 +MDHL0_SX89 +MDHS0_SX180 +MDHS0_SX270 +MDHS0_SX360 +MDHS0_SX450 +MDHS0_SX90 +MDJM0_SA1 +MDJM0_SA2 +MDJM0_SI2085 +MDJM0_SI825 +MDJM0_SX195 +MDJM0_SX285 +MDJM0_SX375 +MDKS0_SA1 +MDKS0_SA2 +MDKS0_SI1066 +MDKS0_SI1696 +MDKS0_SI2326 +MDKS0_SX256 +MDKS0_SX76 +MDLB0_SA1 +MDLB0_SI1936 +MDLB0_SI676 +MDLB0_SX226 +MDLB0_SX316 +MDLB0_SX46 +MDLC0_SA1 +MDLC0_SA2 +MDLC0_SI765 +MDLC0_SX135 +MDLC0_SX225 +MDLC0_SX315 +MDLC0_SX45 +MDLC1_SA1 +MDLC1_SX175 +MDLC1_SX265 +MDLC1_SX355 +MDLC1_SX85 +MDLC2_SA1 +MDLC2_SA2 +MDLC2_SI1614 +MDLC2_SI984 +MDLC2_SX174 +MDLC2_SX264 +MDLC2_SX444 +MDLC2_SX84 +MDLH0_SA1 +MDLH0_SI1960 +MDLH0_SI574 +MDLH0_SI700 +MDLH0_SX250 +MDLH0_SX340 +MDLH0_SX70 +MDLM0_SA1 +MDLM0_SA2 +MDLM0_SX244 +MDLM0_SX334 +MDLM0_SX64 +MDLR0_SI1233 +MDLR0_SX243 +MDLR0_SX423 +MDLR0_SX63 +MDLR1_SI1299 +MDLR1_SI1929 +MDLR1_SX129 +MDLR1_SX219 +MDLR1_SX309 +MDLR1_SX39 +MDLR1_SX399 +MDMA0_SA1 +MDMA0_SA2 +MDMA0_SI1238 +MDMA0_SI2060 +MDMT0_SI2341 +MDMT0_SI572 +MDMT0_SX212 +MDMT0_SX302 +MDMT0_SX392 +MDNS0_SA1 +MDNS0_SX111 +MDNS0_SX291 +MDNS0_SX381 +MDPB0_SA1 +MDPB0_SA2 +MDPB0_SI2126 +MDPB0_SX146 +MDPB0_SX236 +MDPB0_SX326 +MDPB0_SX56 +MDPK0_SA1 +MDPK0_SA2 +MDPK0_SI1683 +MDPK0_SI552 +MDPK0_SX153 +MDPK0_SX243 +MDPK0_SX63 +MDPS0_SA1 +MDPS0_SA2 +MDPS0_SI1651 +MDPS0_SI1979 +MDPS0_SX179 +MDPS0_SX269 +MDPS0_SX449 +MDPS0_SX89 +MDRD0_SA2 +MDRD0_SI1382 +MDRD0_SI2012 +MDRD0_SX122 +MDRD0_SX212 +MDRD0_SX302 +MDRD0_SX392 +MDSJ0_SA1 +MDSJ0_SA2 +MDSJ0_SI832 +MDSJ0_SX112 +MDSJ0_SX22 +MDSJ0_SX292 +MDSJ0_SX382 +MDSS0_SA1 +MDSS0_SI1881 +MDSS0_SI2087 +MDSS0_SI621 +MDSS0_SX171 +MDSS0_SX261 +MDSS0_SX351 +MDSS0_SX81 +MDSS1_SA2 +MDSS1_SI1713 +MDSS1_SX247 +MDSS1_SX337 +MDSS1_SX427 +MDTB0_SA1 +MDTB0_SA2 +MDTB0_SI570 +MDTB0_SX210 +MDTB0_SX300 +MDTB0_SX321 +MDTB0_SX390 +MDWD0_SA1 +MDWD0_SI1890 +MDWD0_SI557 +MDWD0_SX180 +MDWD0_SX360 +MDWD0_SX450 +MDWH0_SA2 +MDWH0_SI1925 +MDWH0_SX125 +MDWH0_SX35 +MDWH0_SX395 +MDWM0_SI1546 +MDWM0_SI2176 +MDWM0_SX106 +MDWM0_SX376 +MDWM0_SX433 +MEAL0_SA1 +MEAL0_SI1547 +MEAL0_SI917 +MEAL0_SX197 +MEAL0_SX287 +MEAL0_SX377 +MEDR0_SI744 +MEDR0_SX114 +MEDR0_SX204 +MEDR0_SX24 +MEDR0_SX294 +MEDR0_SX384 +MEFG0_SA2 +MEFG0_SI465 +MEFG0_SX105 +MEFG0_SX15 +MEFG0_SX195 +MEFG0_SX285 +MEFG0_SX375 +MEGJ0_SI1967 +MEGJ0_SX437 +MEGJ0_SX77 +MEJL0_SA2 +MEJL0_SI1592 +MEJL0_SI1654 +MEJL0_SI962 +MEJL0_SX332 +MEJL0_SX422 +MEJL0_SX62 +MEJS0_SA1 +MEJS0_SA2 +MEJS0_SI1870 +MEJS0_SX250 +MEJS0_SX430 +MEJS0_SX70 +MESG0_SA1 +MESG0_SA2 +MESG0_SI1332 +MESG0_SI1962 +MESG0_SX162 +MESG0_SX252 +MESG0_SX342 +MESG0_SX72 +MESJ0_SA1 +MESJ0_SA2 +MESJ0_SI2257 +MESJ0_SI997 +MESJ0_SX277 +MESJ0_SX367 +MESJ0_SX7 +MEWM0_SA1 +MEWM0_SA2 +MEWM0_SI1348 +MEWM0_SI1978 +MEWM0_SX268 +MEWM0_SX358 +MEWM0_SX448 +MFER0_SA1 +MFER0_SA2 +MFER0_SI1492 +MFER0_SI2122 +MFER0_SX232 +MFER0_SX322 +MFER0_SX412 +MFER0_SX52 +MFMC0_SA1 +MFMC0_SA2 +MFMC0_SI1132 +MFMC0_SI1762 +MFMC0_SI502 +MFMC0_SX142 +MFMC0_SX232 +MFMC0_SX322 +MFMC0_SX412 +MFMC0_SX52 +MFRM0_SA1 +MFRM0_SA2 +MFRM0_SI1155 +MFRM0_SI1717 +MFRM0_SI1785 +MFRM0_SX165 +MFRM0_SX255 +MFRM0_SX75 +MFWK0_SA1 +MFWK0_SA2 +MFWK0_SI1249 +MFWK0_SI619 +MFWK0_SX259 +MFWK0_SX439 +MFWK0_SX79 +MFXS0_SA1 +MFXS0_SA2 +MFXS0_SI1674 +MFXS0_SI2225 +MFXS0_SI2304 +MFXS0_SX144 +MFXS0_SX234 +MFXS0_SX414 +MFXV0_SA1 +MFXV0_SI1635 +MFXV0_SX15 +MFXV0_SX195 +MFXV0_SX285 +MFXV0_SX375 +MGAF0_SA2 +MGAF0_SI1912 +MGAF0_SI652 +MGAF0_SX112 +MGAF0_SX202 +MGAF0_SX292 +MGAG0_SA1 +MGAG0_SI1321 +MGAG0_SI645 +MGAG0_SX151 +MGAG0_SX241 +MGAG0_SX331 +MGAG0_SX421 +MGAG0_SX61 +MGAK0_SA1 +MGAK0_SA2 +MGAK0_SI1666 +MGAK0_SI2296 +MGAK0_SX316 +MGAK0_SX406 +MGAR0_SA1 +MGAR0_SA2 +MGAR0_SI1212 +MGAR0_SI1694 +MGAR0_SI1842 +MGAR0_SX222 +MGAR0_SX402 +MGAR0_SX42 +MGAW0_SA1 +MGAW0_SA2 +MGAW0_SI1802 +MGAW0_SX265 +MGAW0_SX355 +MGAW0_SX445 +MGAW0_SX85 +MGES0_SA2 +MGES0_SI1481 +MGES0_SX131 +MGES0_SX221 +MGES0_SX401 +MGES0_SX41 +MGJC0_SA1 +MGJC0_SI1256 +MGJC0_SI1335 +MGJC0_SI1965 +MGJC0_SX165 +MGJC0_SX255 +MGJC0_SX345 +MGRL0_SA1 +MGRL0_SA2 +MGRL0_SI1497 +MGRL0_SX237 +MGRL0_SX417 +MGRL0_SX57 +MGRP0_SA1 +MGRP0_SI1947 +MGRP0_SI687 +MGRP0_SX147 +MGRP0_SX237 +MGRP0_SX417 +MGRP0_SX57 +MGSH0_SA1 +MGSH0_SX186 +MGSH0_SX96 +MGSL0_SA2 +MGSL0_SI1164 +MGSL0_SX174 +MGSL0_SX354 +MGSL0_SX444 +MGSL0_SX84 +MGXP0_SA1 +MGXP0_SA2 +MGXP0_SI457 +MGXP0_SX277 +MGXP0_SX367 +MGXP0_SX97 +MHBS0_SA1 +MHBS0_SA2 +MHBS0_SI1575 +MHBS0_SI2205 +MHBS0_SX135 +MHBS0_SX225 +MHBS0_SX405 +MHIT0_SA2 +MHIT0_SI1613 +MHIT0_SI2243 +MHIT0_SX173 +MHIT0_SX263 +MHIT0_SX353 +MHIT0_SX443 +MHIT0_SX83 +MHJB0_SA2 +MHJB0_SI1647 +MHJB0_SI2277 +MHJB0_SX117 +MHJB0_SX207 +MHJB0_SX27 +MHJB0_SX297 +MHJB0_SX387 +MHMG0_SA1 +MHMG0_SA2 +MHMG0_SI1365 +MHMG0_SI1995 +MHMG0_SX105 +MHMG0_SX15 +MHMG0_SX285 +MHMG0_SX375 +MHMR0_SA2 +MHMR0_SI1119 +MHMR0_SX129 +MHMR0_SX219 +MHMR0_SX309 +MHMR0_SX39 +MHMR0_SX399 +MHRM0_SA2 +MHRM0_SI1475 +MHRM0_SI2218 +MHRM0_SX238 +MHRM0_SX328 +MHRM0_SX418 +MHXL0_SA1 +MHXL0_SA2 +MHXL0_SI512 +MHXL0_SI612 +MHXL0_SX152 +MHXL0_SX332 +MHXL0_SX422 +MHXL0_SX62 +MILB0_SA1 +MILB0_SI2163 +MILB0_SI807 +MILB0_SX183 +MILB0_SX273 +MILB0_SX3 +MILB0_SX363 +MILB0_SX93 +MJAC0_SA1 +MJAC0_SA2 +MJAC0_SI1331 +MJAC0_SI2148 +MJAC0_SX341 +MJAC0_SX431 +MJAE0_SA1 +MJAE0_SA2 +MJAE0_SI1524 +MJAE0_SI1999 +MJAE0_SI2154 +MJAE0_SX264 +MJAE0_SX354 +MJAE0_SX444 +MJAI0_SI1604 +MJAI0_SX164 +MJAI0_SX254 +MJAI0_SX344 +MJAI0_SX434 +MJAI0_SX74 +MJBG0_SA1 +MJBG0_SA2 +MJBG0_SI1232 +MJBG0_SI1724 +MJBG0_SI1862 +MJBG0_SX152 +MJBG0_SX242 +MJBG0_SX332 +MJBG0_SX422 +MJDA0_SA1 +MJDA0_SA2 +MJDA0_SI1661 +MJDA0_SI2291 +MJDA0_SX131 +MJDA0_SX221 +MJDA0_SX401 +MJDA0_SX41 +MJDC0_SA1 +MJDC0_SA2 +MJDC0_SI1161 +MJDC0_SI2165 +MJDC0_SX171 +MJDC0_SX261 +MJDC0_SX351 +MJDC0_SX441 +MJDC0_SX81 +MJDE0_SA2 +MJDE0_SX130 +MJDE0_SX310 +MJDE0_SX40 +MJDE0_SX400 +MJDG0_SA1 +MJDG0_SI1672 +MJDG0_SX142 +MJDG0_SX232 +MJDG0_SX322 +MJDG0_SX412 +MJDG0_SX52 +MJDM0_SA2 +MJDM0_SI1937 +MJDM0_SX260 +MJDM0_SX440 +MJDM0_SX80 +MJEB0_SA1 +MJEB0_SA2 +MJEB0_SI1286 +MJEB0_SI1916 +MJEB0_SX206 +MJEB0_SX26 +MJEB0_SX386 +MJEB1_SA1 +MJEB1_SI2097 +MJEB1_SX117 +MJEB1_SX27 +MJEB1_SX297 +MJEE0_SA2 +MJEE0_SI1237 +MJEE0_SI1867 +MJEE0_SI607 +MJEE0_SX157 +MJEE0_SX427 +MJEE0_SX67 +MJFH0_SA1 +MJFH0_SI1737 +MJFH0_SI477 +MJFH0_SX117 +MJFH0_SX207 +MJFH0_SX27 +MJFH0_SX297 +MJFH0_SX387 +MJFR0_SA2 +MJFR0_SI1605 +MJFR0_SI2235 +MJFR0_SI975 +MJFR0_SX165 +MJFR0_SX255 +MJFR0_SX345 +MJHI0_SA2 +MJHI0_SI555 +MJHI0_SI698 +MJHI0_SX248 +MJHI0_SX338 +MJHI0_SX428 +MJHI0_SX68 +MJJB0_SA2 +MJJB0_SI1139 +MJJB0_SI1277 +MJJB0_SI1769 +MJJB0_SX149 +MJJB0_SX329 +MJJB0_SX419 +MJJB0_SX59 +MJJJ0_SA1 +MJJJ0_SA2 +MJJJ0_SI1793 +MJJJ0_SI533 +MJJJ0_SX173 +MJJJ0_SX263 +MJJJ0_SX353 +MJJJ0_SX83 +MJJM0_SA1 +MJJM0_SI1457 +MJJM0_SX17 +MJJM0_SX197 +MJJM0_SX287 +MJJM0_SX377 +MJKR0_SA2 +MJKR0_SI1201 +MJKR0_SI1831 +MJKR0_SX121 +MJKR0_SX211 +MJKR0_SX301 +MJKR0_SX31 +MJKR0_SX391 +MJLB0_SA1 +MJLB0_SA2 +MJLB0_SI2246 +MJLB0_SI986 +MJLB0_SX266 +MJLB0_SX356 +MJLB0_SX446 +MJLB0_SX86 +MJLG1_SA1 +MJLG1_SA2 +MJLG1_SI1012 +MJLG1_SI1642 +MJLG1_SI2272 +MJLG1_SX112 +MJLG1_SX202 +MJLG1_SX22 +MJLG1_SX382 +MJLS0_SA1 +MJLS0_SA2 +MJLS0_SI1096 +MJLS0_SI466 +MJLS0_SX16 +MJLS0_SX196 +MJLS0_SX286 +MJLS0_SX376 +MJMA0_SI1495 +MJMA0_SI865 +MJMA0_SX145 +MJMA0_SX235 +MJMA0_SX325 +MJMA0_SX415 +MJMA0_SX55 +MJMD0_SA1 +MJMD0_SI1028 +MJMD0_SI1658 +MJMD0_SX128 +MJMD0_SX218 +MJMD0_SX398 +MJMM0_SA1 +MJMM0_SA2 +MJMM0_SI1885 +MJMM0_SI625 +MJMM0_SX265 +MJMM0_SX355 +MJMM0_SX445 +MJPG0_SA1 +MJPG0_SA2 +MJPG0_SI561 +MJPG0_SX291 +MJPG0_SX381 +MJPM0_SA1 +MJPM0_SI1998 +MJPM0_SI738 +MJPM0_SX108 +MJPM0_SX18 +MJPM0_SX198 +MJPM0_SX288 +MJPM1_SA1 +MJPM1_SA2 +MJPM1_SI1897 +MJPM1_SI761 +MJPM1_SX131 +MJPM1_SX221 +MJPM1_SX41 +MJRA0_SI606 +MJRA0_SX156 +MJRA0_SX246 +MJRA0_SX66 +MJRG0_SA1 +MJRG0_SA2 +MJRG0_SX106 +MJRG0_SX16 +MJRG0_SX286 +MJRH0_SA1 +MJRH0_SA2 +MJRH0_SI1125 +MJRH0_SI1755 +MJRH0_SX135 +MJRH0_SX315 +MJRH0_SX405 +MJRH0_SX45 +MJRH1_SA2 +MJRH1_SI1774 +MJRH1_SX334 +MJRH1_SX64 +MJRK0_SI2103 +MJRK0_SX340 +MJRK0_SX70 +MJRP0_SI1835 +MJRP0_SI585 +MJRP0_SX135 +MJRP0_SX315 +MJRP0_SX405 +MJRP0_SX45 +MJSR0_SA2 +MJSR0_SX164 +MJSR0_SX254 +MJSR0_SX434 +MJSR0_SX74 +MJWG0_SA2 +MJWG0_SI2155 +MJWG0_SX355 +MJWG0_SX445 +MJWG0_SX85 +MJWS0_SA1 +MJWS0_SA2 +MJWS0_SI1143 +MJWS0_SI1773 +MJWS0_SX243 +MJWS0_SX423 +MJWT0_SA2 +MJWT0_SI751 +MJXA0_SA1 +MJXA0_SA2 +MJXA0_SI1507 +MJXA0_SI2137 +MJXA0_SI877 +MJXA0_SX157 +MJXA0_SX247 +MJXA0_SX337 +MJXA0_SX67 +MJXL0_SA1 +MJXL0_SA2 +MJXL0_SI1795 +MJXL0_SX182 +MJXL0_SX272 +MJXL0_SX362 +MJXL0_SX452 +MJXL0_SX92 +MKAG0_SA2 +MKAG0_SI1609 +MKAG0_SI2239 +MKAG0_SX169 +MKAG0_SX30 +MKAG0_SX439 +MKAG0_SX79 +MKAH0_SA1 +MKAH0_SA2 +MKAH0_SI1528 +MKAH0_SI2158 +MKAH0_SI898 +MKAH0_SX268 +MKAH0_SX358 +MKAH0_SX448 +MKAH0_SX88 +MKAJ0_SA1 +MKAJ0_SI1414 +MKAJ0_SI2044 +MKAJ0_SI784 +MKAJ0_SX244 +MKAJ0_SX334 +MKAJ0_SX424 +MKAJ0_SX64 +MKAM0_SA2 +MKAM0_SI1316 +MKAM0_SX236 +MKAM0_SX416 +MKDB0_SI2132 +MKDB0_SI588 +MKDB0_SI872 +MKDB0_SX242 +MKDB0_SX332 +MKDB0_SX422 +MKDB0_SX62 +MKDD0_SA1 +MKDD0_SX127 +MKDD0_SX217 +MKDD0_SX307 +MKDD0_SX37 +MKDD0_SX397 +MKDT0_SA1 +MKDT0_SA2 +MKDT0_SI2153 +MKDT0_SI893 +MKDT0_SX173 +MKDT0_SX263 +MKDT0_SX353 +MKDT0_SX443 +MKDT0_SX83 +MKES0_SA2 +MKES0_SX263 +MKES0_SX353 +MKES0_SX443 +MKES0_SX83 +MKJO0_SA1 +MKJO0_SA2 +MKJO0_SI2147 +MKJO0_SX167 +MKJO0_SX257 +MKJO0_SX424 +MKJO0_SX77 +MKLN0_SA1 +MKLN0_SA2 +MKLN0_SI1598 +MKLN0_SI2228 +MKLN0_SX158 +MKLN0_SX338 +MKLN0_SX428 +MKLN0_SX68 +MKLR0_SA1 +MKLR0_SI1059 +MKLR0_SI2319 +MKLR0_SX159 +MKLR0_SX249 +MKLR0_SX339 +MKLR0_SX429 +MKLR0_SX69 +MKLS0_SA2 +MKLS0_SI1533 +MKLS0_SX177 +MKLS0_SX267 +MKLS0_SX447 +MKLS1_SI1545 +MKLS1_SI2175 +MKLS1_SX105 +MKLS1_SX15 +MKLS1_SX195 +MKLS1_SX285 +MKLW0_SA2 +MKLW0_SI1844 +MKLW0_SI2201 +MKLW0_SX131 +MKLW0_SX221 +MKLW0_SX401 +MKLW0_SX41 +MKRG0_SA1 +MKRG0_SA2 +MKRG0_SI1491 +MKRG0_SI2121 +MKRG0_SX141 +MKRG0_SX231 +MKRG0_SX31 +MKRG0_SX51 +MKXL0_SA1 +MKXL0_SI1185 +MKXL0_SX105 +MKXL0_SX195 +MKXL0_SX285 +MLBC0_SA2 +MLBC0_SI609 +MLBC0_SX159 +MLBC0_SX339 +MLBC0_SX429 +MLBC0_SX69 +MLEL0_SI1876 +MLEL0_SX346 +MLEL0_SX76 +MLJC0_SA1 +MLJC0_SA2 +MLJC0_SI1855 +MLJC0_SI595 +MLJC0_SX235 +MLJC0_SX325 +MLJC0_SX55 +MLJH0_SI1324 +MLJH0_SX154 +MLJH0_SX334 +MLJH0_SX424 +MLNS0_SA1 +MLNS0_SA2 +MLNS0_SI1407 +MLNS0_SI777 +MLNS0_SX147 +MLNS0_SX237 +MLNS0_SX327 +MLNS0_SX417 +MLNS0_SX57 +MLSH0_SA1 +MLSH0_SA2 +MLSH0_SI2047 +MLSH0_SI787 +MLSH0_SX157 +MLSH0_SX337 +MLSH0_SX427 +MLSH0_SX67 +MMAA0_SI2105 +MMAA0_SX125 +MMAA0_SX215 +MMAA0_SX305 +MMAA0_SX395 +MMAB1_SA1 +MMAB1_SA2 +MMAB1_SI2124 +MMAB1_SX144 +MMAB1_SX414 +MMAB1_SX54 +MMAG0_SI496 +MMAG0_SX226 +MMAG0_SX406 +MMAG0_SX46 +MMAM0_SA1 +MMAM0_SA2 +MMAM0_SI1597 +MMAM0_SI1668 +MMAM0_SX247 +MMAM0_SX337 +MMAM0_SX67 +MMAR0_SA1 +MMAR0_SA2 +MMAR0_SI1336 +MMAR0_SI706 +MMAR0_SX436 +MMAR0_SX76 +MMBS0_SA1 +MMBS0_SA2 +MMBS0_SI1151 +MMBS0_SX251 +MMBS0_SX341 +MMBS0_SX431 +MMBS0_SX71 +MMCC0_SA1 +MMCC0_SI1968 +MMCC0_SI708 +MMCC0_SX168 +MMCC0_SX258 +MMCC0_SX348 +MMCC0_SX438 +MMCC0_SX78 +MMDB0_SA1 +MMDB0_SA2 +MMDB0_SI1358 +MMDB0_SI1617 +MMDB0_SX267 +MMDB0_SX357 +MMDB0_SX447 +MMDB0_SX87 +MMDG0_SI2035 +MMDG0_SX340 +MMDG0_SX430 +MMDG0_SX70 +MMDM0_SA1 +MMDM0_SA2 +MMDM0_SX231 +MMDM0_SX321 +MMDM0_SX411 +MMDM0_SX51 +MMDM1_SA1 +MMDM1_SI1650 +MMDM1_SI783 +MMDM1_SX243 +MMDS0_SA2 +MMDS0_SI1343 +MMDS0_SI1973 +MMDS0_SI713 +MMDS0_SX173 +MMDS0_SX263 +MMDS0_SX353 +MMDS0_SX443 +MMDS0_SX83 +MMEA0_SA2 +MMEA0_SI1388 +MMEA0_SI2018 +MMEA0_SI758 +MMEA0_SX218 +MMEA0_SX308 +MMEA0_SX38 +MMEB0_SA1 +MMEB0_SI1357 +MMEB0_SI1987 +MMEB0_SI727 +MMEB0_SX7 +MMEB0_SX97 +MMGC0_SA1 +MMGC0_SI1935 +MMGC0_SI2184 +MMGC0_SX315 +MMGC0_SX405 +MMGC0_SX45 +MMGG0_SA1 +MMGG0_SA2 +MMGG0_SI1709 +MMGG0_SI2339 +MMGG0_SX179 +MMGG0_SX359 +MMGG0_SX89 +MMGK0_SA1 +MMGK0_SA2 +MMGK0_SI1322 +MMGK0_SI1952 +MMGK0_SI692 +MMGK0_SX152 +MMGK0_SX242 +MMGK0_SX422 +MMJB1_SA1 +MMJB1_SI1408 +MMJB1_SI2038 +MMJB1_SI778 +MMJB1_SX148 +MMJB1_SX238 +MMJB1_SX328 +MMJB1_SX418 +MMJB1_SX58 +MMLM0_SA1 +MMLM0_SA2 +MMLM0_SI1527 +MMLM0_SI897 +MMLM0_SX177 +MMLM0_SX267 +MMLM0_SX357 +MMLM0_SX447 +MMLM0_SX87 +MMPM0_SA1 +MMPM0_SA2 +MMPM0_SI1061 +MMPM0_SI1691 +MMPM0_SI2321 +MMPM0_SX251 +MMPM0_SX341 +MMPM0_SX431 +MMPM0_SX71 +MMRP0_SA1 +MMRP0_SI2034 +MMRP0_SI717 +MMRP0_SI774 +MMRP0_SX234 +MMRP0_SX414 +MMRP0_SX54 +MMSM0_SA1 +MMSM0_SA2 +MMSM0_SI1736 +MMSM0_SX26 +MMSM0_SX296 +MMSM0_SX386 +MMVP0_SI1284 +MMVP0_SI1914 +MMVP0_SX114 +MMVP0_SX204 +MMVP0_SX294 +MMVP0_SX384 +MMWB0_SA2 +MMWB0_SI1619 +MMWB0_SX179 +MMWB0_SX269 +MMWS0_SA1 +MMWS0_SI1518 +MMWS0_SI559 +MMWS0_SI888 +MMWS0_SX258 +MMWS0_SX78 +MMWS1_SA1 +MMWS1_SA2 +MMWS1_SI1071 +MMWS1_SI2331 +MMWS1_SX261 +MMWS1_SX27 +MMWS1_SX351 +MMWS1_SX441 +MMWS1_SX81 +MMXS0_SA1 +MMXS0_SA2 +MMXS0_SI629 +MMXS0_SI876 +MMXS0_SX156 +MMXS0_SX336 +MMXS0_SX66 +MNET0_SA1 +MNET0_SA2 +MNET0_SI1446 +MNET0_SI2076 +MNET0_SX186 +MNET0_SX276 +MNET0_SX366 +MNET0_SX96 +MNTW0_SA1 +MNTW0_SI2328 +MNTW0_SX202 +MNTW0_SX258 +MNTW0_SX348 +MPAR0_SA1 +MPAR0_SA2 +MPAR0_SI1576 +MPAR0_SX226 +MPAR0_SX406 +MPAR0_SX46 +MPEB0_SA1 +MPEB0_SA2 +MPEB0_SX150 +MPEB0_SX420 +MPEB0_SX60 +MPFU0_SA1 +MPFU0_SA2 +MPFU0_SI1888 +MPFU0_SX178 +MPFU0_SX268 +MPFU0_SX358 +MPFU0_SX88 +MPGH0_SA1 +MPGH0_SA2 +MPGH0_SI1554 +MPGH0_SI924 +MPGH0_SX204 +MPGH0_SX294 +MPGH0_SX384 +MPGR0_SA1 +MPGR0_SA2 +MPGR0_SI2040 +MPGR0_SI780 +MPGR0_SX150 +MPGR0_SX420 +MPGR0_SX60 +MPGR1_SA1 +MPGR1_SA2 +MPGR1_SI1269 +MPGR1_SI2129 +MPGR1_SX239 +MPGR1_SX329 +MPGR1_SX419 +MPGR1_SX59 +MPMB0_SX241 +MPPC0_SA2 +MPPC0_SI2042 +MPPC0_SI782 +MPPC0_SX152 +MPPC0_SX242 +MPPC0_SX332 +MPPC0_SX422 +MPPC0_SX62 +MPRB0_SA1 +MPRB0_SA2 +MPRB0_SI1205 +MPRB0_SX125 +MPRB0_SX215 +MPRB0_SX305 +MPRB0_SX35 +MPRB0_SX395 +MPRD0_SA2 +MPRD0_SI1431 +MPRD0_SI2061 +MPRK0_SA2 +MPRK0_SX17 +MPRK0_SX197 +MPRT0_SA2 +MPRT0_SI1210 +MPRT0_SI495 +MPRT0_SI580 +MPRT0_SX130 +MPRT0_SX220 +MPRT0_SX40 +MPRT0_SX400 +MPSW0_SA1 +MPSW0_SA2 +MPSW0_SI1697 +MPSW0_SI2327 +MPSW0_SX24 +MPSW0_SX257 +MPSW0_SX77 +MRAB0_SA1 +MRAB0_SA2 +MRAB0_SI1224 +MRAB0_SI594 +MRAB0_SX144 +MRAB0_SX234 +MRAB0_SX324 +MRAB0_SX414 +MRAB0_SX54 +MRAB1_SA1 +MRAB1_SA2 +MRAB1_SI1478 +MRAB1_SI2108 +MRAB1_SX218 +MRAB1_SX38 +MRAB1_SX398 +MRAI0_SI1954 +MRAI0_SX162 +MRAI0_SX252 +MRAI0_SX342 +MRAM0_SI1275 +MRAM0_SI1905 +MRAM0_SX105 +MRAM0_SX195 +MRAM0_SX285 +MRAM0_SX375 +MRAV0_SA1 +MRAV0_SA2 +MRAV0_SI1008 +MRAV0_SI1638 +MRAV0_SI2268 +MRAV0_SX108 +MRAV0_SX18 +MRAV0_SX198 +MRAV0_SX288 +MRAV0_SX378 +MRBC0_SA1 +MRBC0_SA2 +MRBC0_SI1665 +MRBC0_SI599 +MRBC0_SX149 +MRBC0_SX239 +MRBC0_SX59 +MRCG0_SA1 +MRCG0_SI2058 +MRCG0_SX258 +MRCG0_SX78 +MRCW0_SA2 +MRCW0_SI1371 +MRCW0_SI2001 +MRCW0_SX111 +MRCW0_SX201 +MRCW0_SX21 +MRCW0_SX381 +MRDD0_SA1 +MRDD0_SA2 +MRDD0_SI1050 +MRDD0_SI2310 +MRDD0_SX240 +MRDD0_SX330 +MRDM0_SA1 +MRDM0_SA2 +MRDM0_SI965 +MRDM0_SX155 +MRDM0_SX245 +MRDM0_SX425 +MRDS0_SA2 +MRDS0_SI1167 +MRDS0_SI1797 +MRDS0_SI537 +MRDS0_SX177 +MRDS0_SX267 +MRDS0_SX357 +MRDS0_SX447 +MRDS0_SX87 +MREE0_SA1 +MREE0_SA2 +MREE0_SI1734 +MREE0_SX114 +MREE0_SX204 +MREE0_SX294 +MREE0_SX384 +MREH1_SA2 +MREH1_SI2229 +MREH1_SX159 +MREH1_SX339 +MREH1_SX429 +MREM0_SA1 +MREM0_SI1591 +MREM0_SI961 +MREM0_SX151 +MREM0_SX241 +MREM0_SX331 +MREM0_SX421 +MREM0_SX61 +MREW1_SA1 +MREW1_SA2 +MREW1_SI1500 +MREW1_SI2130 +MREW1_SX150 +MREW1_SX240 +MREW1_SX330 +MREW1_SX420 +MREW1_SX60 +MRFK0_SA1 +MRFK0_SA2 +MRFK0_SI1706 +MRFK0_SI2336 +MRFK0_SX176 +MRFK0_SX266 +MRFK0_SX356 +MRFK0_SX86 +MRFL0_SA2 +MRFL0_SI1786 +MRFL0_SX346 +MRGM0_SA1 +MRGM0_SI1162 +MRGM0_SI1792 +MRGM0_SX416 +MRGM0_SX82 +MRGS0_SA1 +MRGS0_SI1986 +MRGS0_SX276 +MRGS0_SX366 +MRGS0_SX96 +MRHL0_SA1 +MRHL0_SA2 +MRHL0_SI1515 +MRHL0_SI2145 +MRHL0_SX165 +MRHL0_SX255 +MRHL0_SX75 +MRJB1_SI1020 +MRJB1_SX300 +MRJH0_SA1 +MRJH0_SI914 +MRJH0_SX259 +MRJH0_SX439 +MRJM0_SA1 +MRJM0_SA2 +MRJM0_SI1095 +MRJM0_SI1228 +MRJM0_SI1858 +MRJM0_SX238 +MRJM0_SX328 +MRJM0_SX418 +MRJM0_SX58 +MRJM1_SA1 +MRJM1_SI668 +MRJM1_SX218 +MRJM1_SX308 +MRJM1_SX38 +MRJM1_SX398 +MRJT0_SA1 +MRJT0_SI1805 +MRJT0_SX148 +MRJT0_SX238 +MRKM0_SA1 +MRKM0_SX187 +MRKM0_SX277 +MRKM0_SX7 +MRKM0_SX97 +MRLD0_SA1 +MRLD0_SI1594 +MRLD0_SI964 +MRLD0_SX244 +MRLD0_SX334 +MRLD0_SX64 +MRLJ0_SA2 +MRLJ0_SI1420 +MRLJ0_SI2050 +MRLJ0_SX160 +MRLJ0_SX430 +MRLJ0_SX70 +MRLJ1_SI1671 +MRLJ1_SI2332 +MRLJ1_SX141 +MRLJ1_SX231 +MRLJ1_SX411 +MRLJ1_SX51 +MRLK0_SA1 +MRLK0_SA2 +MRLK0_SI2140 +MRLK0_SX303 +MRLK0_SX33 +MRLK0_SX393 +MRLR0_SA1 +MRLR0_SA2 +MRLR0_SI1826 +MRLR0_SI566 +MRLR0_SX116 +MRLR0_SX206 +MRLR0_SX26 +MRLR0_SX296 +MRLR0_SX386 +MRMB0_SA1 +MRMB0_SI2211 +MRMB0_SI951 +MRMB0_SX141 +MRMB0_SX231 +MRMB0_SX321 +MRMB0_SX51 +MRMG0_SA2 +MRMG0_SI1710 +MRMG0_SI2340 +MRMG0_SX180 +MRMG0_SX270 +MRMG0_SX360 +MRMG0_SX90 +MRMH0_SA1 +MRMH0_SA2 +MRMH0_SI1021 +MRMH0_SX211 +MRMH0_SX301 +MRMH0_SX31 +MRMH0_SX391 +MRML0_SI2051 +MRML0_SI791 +MRML0_SX431 +MRML0_SX71 +MRMS0_SA1 +MRMS0_SA2 +MRMS0_SI1113 +MRMS0_SI2100 +MRMS0_SX120 +MRMS0_SX210 +MRMS0_SX30 +MRMS0_SX300 +MRMS0_SX390 +MRPC1_SA1 +MRPC1_SA2 +MRPC1_SI1482 +MRPC1_SI2026 +MRPC1_SX132 +MRPC1_SX222 +MRPC1_SX312 +MRPC1_SX402 +MRPC1_SX42 +MRRE0_SI704 +MRRE0_SX254 +MRRE0_SX434 +MRSO0_SA1 +MRSO0_SA2 +MRSO0_SI1659 +MRSO0_SI2289 +MRSO0_SX219 +MRSO0_SX309 +MRSO0_SX399 +MRSP0_SA1 +MRSP0_SA2 +MRSP0_SI2059 +MRSP0_SI799 +MRSP0_SX169 +MRSP0_SX196 +MRSP0_SX439 +MRSP0_SX79 +MRTC0_SA1 +MRTC0_SA2 +MRTC0_SI2088 +MRTC0_SI828 +MRTC0_SX108 +MRTC0_SX18 +MRTC0_SX198 +MRTC0_SX288 +MRTJ0_SA2 +MRTJ0_SI1551 +MRTJ0_SI2032 +MRTJ0_SX322 +MRTJ0_SX412 +MRVG0_SA1 +MRVG0_SA2 +MRVG0_SI1770 +MRVG0_SI510 +MRVG0_SX150 +MRVG0_SX330 +MRVG0_SX420 +MRVG0_SX60 +MRWA0_SA1 +MRWA0_SA2 +MRWA0_SI1603 +MRWA0_SI2233 +MRWA0_SX253 +MRWA0_SX343 +MRWA0_SX433 +MRWS0_SA1 +MRWS0_SA2 +MRWS0_SX112 +MRWS0_SX202 +MRWS0_SX292 +MRXB0_SA1 +MRXB0_SI1585 +MRXB0_SX145 +MRXB0_SX235 +MRXB0_SX325 +MRXB0_SX55 +MSAH1_SA1 +MSAH1_SA2 +MSAH1_SI1049 +MSAH1_SI2309 +MSAH1_SX149 +MSAH1_SX239 +MSAH1_SX329 +MSAH1_SX419 +MSAH1_SX59 +MSAS0_SA1 +MSAS0_SA2 +MSAS0_SI2006 +MSAS0_SX26 +MSAS0_SX296 +MSAT0_SA2 +MSAT0_SI1526 +MSAT0_SI2156 +MSAT0_SI896 +MSAT0_SX176 +MSAT0_SX266 +MSAT0_SX356 +MSAT0_SX446 +MSAT0_SX86 +MSAT1_SA1 +MSAT1_SA2 +MSAT1_SI1073 +MSAT1_SI1703 +MSAT1_SI2333 +MSAT1_SX173 +MSAT1_SX353 +MSDB0_SA1 +MSDB0_SA2 +MSDB0_SI1007 +MSDB0_SI1637 +MSDB0_SI2267 +MSDB0_SX107 +MSDB0_SX17 +MSDH0_SA1 +MSDH0_SA2 +MSDH0_SI2113 +MSDH0_SX260 +MSDH0_SX350 +MSDS0_SA2 +MSDS0_SI1707 +MSDS0_SI2337 +MSDS0_SX177 +MSDS0_SX447 +MSDS0_SX87 +MSEM1_SA1 +MSEM1_SA2 +MSEM1_SX360 +MSEM1_SX450 +MSEM1_SX90 +MSES0_SA1 +MSES0_SA2 +MSES0_SI2216 +MSES0_SI2219 +MSES0_SX149 +MSES0_SX329 +MSES0_SX59 +MSFH0_SA2 +MSFH0_SI1216 +MSFH0_SI586 +MSFH0_SX226 +MSFH0_SX46 +MSFV0_SA1 +MSFV0_SA2 +MSFV0_SI1262 +MSFV0_SX182 +MSFV0_SX272 +MSFV0_SX452 +MSJK0_SA1 +MSJK0_SA2 +MSJK0_SI2226 +MSJK0_SI966 +MSJK0_SX156 +MSJK0_SX246 +MSJK0_SX426 +MSJK0_SX66 +MSMC0_SA1 +MSMC0_SA2 +MSMC0_SI1907 +MSMC0_SI647 +MSMC0_SX107 +MSMC0_SX17 +MSMC0_SX197 +MSMC0_SX287 +MSMC0_SX377 +MSMR0_SA1 +MSMR0_SA2 +MSMR0_SI1405 +MSMR0_SI775 +MSMR0_SX145 +MSMR0_SX235 +MSMR0_SX325 +MSMR0_SX55 +MSMS0_SA2 +MSMS0_SI2063 +MSMS0_SI803 +MSMS0_SX263 +MSMS0_SX353 +MSMS0_SX443 +MSRG0_SA2 +MSRG0_SI1851 +MSRG0_SI591 +MSRG0_SX141 +MSRG0_SX231 +MSRG0_SX321 +MSRG0_SX411 +MSRG0_SX51 +MSRR0_SA1 +MSRR0_SA2 +MSRR0_SI1131 +MSRR0_SX141 +MSRR0_SX231 +MSRR0_SX30 +MSRR0_SX411 +MSRR0_SX51 +MSTF0_SA1 +MSTF0_SA2 +MSTF0_SI1396 +MSTF0_SX136 +MSTF0_SX226 +MSTF0_SX406 +MSVS0_SA1 +MSVS0_SI1568 +MSVS0_SX128 +MSVS0_SX218 +MSVS0_SX38 +MTAB0_SA1 +MTAB0_SA2 +MTAB0_SI2202 +MTAB0_SI942 +MTAB0_SX132 +MTAB0_SX222 +MTAB0_SX402 +MTAB0_SX42 +MTAS0_SA1 +MTAS0_SA2 +MTAS0_SI1385 +MTAS0_SI2015 +MTAS0_SI755 +MTAS0_SX125 +MTAS0_SX305 +MTAT0_SA2 +MTAT0_SI1740 +MTAT0_SX120 +MTAT0_SX210 +MTAT0_SX30 +MTAT0_SX300 +MTAT1_SA1 +MTAT1_SA2 +MTAT1_SI1409 +MTAT1_SI1627 +MTAT1_SX239 +MTAT1_SX419 +MTBC0_SA1 +MTBC0_SA2 +MTBC0_SI1173 +MTBC0_SX183 +MTBC0_SX273 +MTBC0_SX347 +MTBC0_SX363 +MTBC0_SX93 +MTCS0_SA1 +MTCS0_SI1972 +MTCS0_SX172 +MTCS0_SX262 +MTCS0_SX352 +MTCS0_SX442 +MTDB0_SA1 +MTDB0_SA2 +MTDB0_SI2031 +MTDB0_SX141 +MTDB0_SX231 +MTDB0_SX321 +MTDB0_SX411 +MTDB0_SX51 +MTDP0_SI1274 +MTDP0_SI2151 +MTDP0_SX261 +MTDP0_SX441 +MTDP0_SX81 +MTER0_SI527 +MTER0_SX167 +MTER0_SX17 +MTER0_SX257 +MTER0_SX77 +MTJG0_SA2 +MTJG0_SI1520 +MTJG0_SI890 +MTJG0_SX350 +MTJG0_SX440 +MTJG0_SX80 +MTJM0_SA1 +MTJM0_SA2 +MTJM0_SI1226 +MTJM0_SI655 +MTJM0_SX236 +MTJM0_SX326 +MTJM0_SX416 +MTJM0_SX56 +MTJS0_SA1 +MTJS0_SI1192 +MTJS0_SX112 +MTJS0_SX202 +MTJS0_SX22 +MTJS0_SX292 +MTJU0_SA1 +MTJU0_SA2 +MTJU0_SI2269 +MTJU0_SI760 +MTJU0_SX220 +MTJU0_SX310 +MTJU0_SX40 +MTKD0_SA1 +MTKD0_SA2 +MTKD0_SI1187 +MTKD0_SI1817 +MTKD0_SX17 +MTKD0_SX197 +MTKD0_SX377 +MTKP0_SA1 +MTKP0_SA2 +MTKP0_SX123 +MTKP0_SX213 +MTKP0_SX303 +MTKP0_SX33 +MTKP0_SX393 +MTLB0_SA2 +MTLB0_SI1764 +MTLB0_SI504 +MTLB0_SX144 +MTLB0_SX414 +MTLB0_SX54 +MTLC0_SA2 +MTLC0_SI847 +MTLC0_SX127 +MTLC0_SX217 +MTLC0_SX307 +MTLC0_SX37 +MTLC0_SX397 +MTML0_SA1 +MTML0_SA2 +MTML0_SI1065 +MTML0_SI1695 +MTML0_SX255 +MTML0_SX345 +MTML0_SX75 +MTMN0_SA1 +MTMN0_SX164 +MTMN0_SX254 +MTMN0_SX344 +MTMN0_SX74 +MTMT0_SA1 +MTMT0_SI1118 +MTMT0_SX128 +MTMT0_SX218 +MTMT0_SX308 +MTMT0_SX38 +MTMT0_SX398 +MTPF0_SA1 +MTPF0_SA2 +MTPF0_SI1235 +MTPF0_SI1865 +MTPF0_SI605 +MTPF0_SX155 +MTPF0_SX245 +MTPF0_SX335 +MTPF0_SX425 +MTPG0_SA1 +MTPG0_SA2 +MTPG0_SI2013 +MTPG0_SX123 +MTPG0_SX213 +MTPG0_SX33 +MTPG0_SX393 +MTPP0_SA1 +MTPP0_SA2 +MTPP0_SI2138 +MTPP0_SI878 +MTPP0_SX158 +MTPP0_SX248 +MTPP0_SX428 +MTPP0_SX68 +MTPR0_SA1 +MTPR0_SA2 +MTPR0_SI1600 +MTPR0_SI506 +MTPR0_SX250 +MTPR0_SX70 +MTQC0_SA2 +MTQC0_SI2071 +MTQC0_SX271 +MTQC0_SX361 +MTRC0_SA1 +MTRC0_SA2 +MTRC0_SI1623 +MTRC0_SI993 +MTRC0_SX170 +MTRC0_SX183 +MTRC0_SX273 +MTRC0_SX363 +MTRC0_SX93 +MTRR0_SA1 +MTRR0_SA2 +MTRR0_SI1548 +MTRR0_SI2178 +MTRR0_SX108 +MTRR0_SX18 +MTRR0_SX378 +MTRT0_SA1 +MTRT0_SI1857 +MTRT0_SI597 +MTRT0_SX147 +MTRT0_SX237 +MTRT0_SX417 +MTWH1_SA1 +MTWH1_SA2 +MTWH1_SI1512 +MTWH1_SI2142 +MTWH1_SI882 +MTWH1_SX162 +MTWH1_SX252 +MTWH1_SX342 +MTWH1_SX432 +MTXS0_SI1690 +MTXS0_SX250 +MTXS0_SX340 +MTXS0_SX70 +MVJH0_SA1 +MVJH0_SA2 +MVJH0_SI2186 +MVJH0_SX116 +MVJH0_SX26 +MVJH0_SX386 +MVLO0_SA2 +MVLO0_SI1147 +MVLO0_SI1777 +MVLO0_SX157 +MVLO0_SX247 +MVLO0_SX337 +MVLO0_SX427 +MVLO0_SX67 +MVRW0_SA1 +MVRW0_SI1485 +MVRW0_SI2115 +MVRW0_SI855 +MVRW0_SX315 +MVRW0_SX405 +MVRW0_SX45 +MWAC0_SA1 +MWAC0_SI2231 +MWAC0_SI971 +MWAC0_SX71 +MWAD0_SA1 +MWAD0_SA2 +MWAD0_SI1062 +MWAD0_SI1749 +MWAD0_SI2322 +MWAD0_SX162 +MWAD0_SX252 +MWAD0_SX342 +MWAR0_SA2 +MWAR0_SI2305 +MWAR0_SX145 +MWAR0_SX235 +MWAR0_SX325 +MWAR0_SX415 +MWAR0_SX55 +MWCH0_SA1 +MWCH0_SA2 +MWCH0_SI1622 +MWCH0_SX272 +MWCH0_SX362 +MWCH0_SX92 +MWDK0_SX266 +MWDK0_SX356 +MWDK0_SX446 +MWEM0_SA1 +MWEM0_SI1950 +MWEM0_SX240 +MWEM0_SX330 +MWEM0_SX60 +MWGR0_SA1 +MWGR0_SA2 +MWGR0_SI1606 +MWGR0_SI2236 +MWGR0_SI976 +MWGR0_SX166 +MWGR0_SX256 +MWGR0_SX436 +MWGR0_SX76 +MWRE0_SA1 +MWRE0_SI1687 +MWRE0_SI2317 +MWRE0_SX157 +MWRP0_SA2 +MWRP0_SI1525 +MWRP0_SI2073 +MWRP0_SX183 +MWRP0_SX3 +MWRP0_SX93 +MWSB0_SA1 +MWSB0_SA2 +MWSB0_SI1626 +MWSB0_SI2256 +MWSB0_SX186 +MWSB0_SX366 +MWSB0_SX6 +MWSB0_SX96 +MWSH0_SA1 +MWSH0_SA2 +MWSH0_SI2266 +MWSH0_SX346 +MWSH0_SX436 +MZMB0_SA2 +MZMB0_SI1166 +MZMB0_SI1796 +MZMB0_SI536 +MZMB0_SX176 +MZMB0_SX266 +MZMB0_SX356 +MZMB0_SX446 +MZMB0_SX86 diff --git a/examples/wav2vec/unsupervised/config/timit_unmatched/train_text.uid b/examples/wav2vec/unsupervised/config/timit_unmatched/train_text.uid new file mode 100644 index 0000000000..0e0c2517c9 --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_unmatched/train_text.uid @@ -0,0 +1,1000 @@ +FAEM0_SI762 +FAEM0_SX42 +FAJW0_SA1 +FAJW0_SX3 +FAJW0_SX93 +FALK0_SX186 +FALK0_SX6 +FALR0_SI1325 +FBAS0_SA1 +FBAS0_SX217 +FBCG1_SA1 +FBCG1_SX172 +FBCG1_SX442 +FBCH0_SX236 +FBCH0_SX416 +FBLV0_SA1 +FBLV0_SI1058 +FBLV0_SX338 +FBLV0_SX68 +FBMH0_SA1 +FBMJ0_SI815 +FCAG0_SA1 +FCAG0_SX153 +FCAG0_SX243 +FCAJ0_SI1479 +FCAJ0_SX309 +FCDR1_SX106 +FCDR1_SX196 +FCEG0_SA2 +FCJF0_SA1 +FCJF0_SX127 +FCJS0_SI1607 +FCJS0_SI2237 +FCJS0_SX257 +FCKE0_SA2 +FCKE0_SX121 +FCLT0_SI2068 +FCLT0_SX448 +FCLT0_SX88 +FCMG0_SA2 +FCMG0_SI1872 +FCMG0_SX72 +FCMM0_SA1 +FCMM0_SA2 +FCMM0_SX183 +FCRZ0_SI2053 +FCRZ0_SX433 +FCYL0_SA1 +FCYL0_SX37 +FDAS1_SI2091 +FDAS1_SX201 +FDAS1_SX381 +FDAW0_SI1406 +FDFB0_SA1 +FDFB0_SA2 +FDFB0_SI2010 +FDFB0_SX58 +FDJH0_SX305 +FDML0_SA2 +FDML0_SX159 +FDML0_SX249 +FDML0_SX429 +FDMY0_SA2 +FDMY0_SX27 +FDNC0_SX198 +FDNC0_SX288 +FDTD0_SX211 +FDXW0_SA1 +FDXW0_SX251 +FDXW0_SX341 +FDXW0_SX71 +FEAC0_SX165 +FEAC0_SX75 +FEAR0_SI622 +FECD0_SX68 +FEEH0_SA1 +FEEH0_SI1742 +FEEH0_SI471 +FEEH0_SX122 +FEME0_SA1 +FEME0_SX155 +FEME0_SX65 +FETB0_SA1 +FETB0_SI1148 +FETB0_SX158 +FEXM0_SI1101 +FGCS0_SX136 +FGCS0_SX226 +FGCS0_SX316 +FGCS0_SX406 +FGDP0_SA1 +FGMB0_SI1775 +FGMB0_SX245 +FHLM0_SX390 +FHXS0_SA2 +FHXS0_SX445 +FJDM2_SA1 +FJDM2_SX232 +FJDM2_SX52 +FJHK0_SX302 +FJKL0_SX212 +FJKL0_SX392 +FJLG0_SI2306 +FJLR0_SA1 +FJRP1_SI2062 +FJRP1_SX82 +FJSK0_SA1 +FJSP0_SX264 +FJSP0_SX354 +FJSP0_SX444 +FJWB1_SA1 +FJWB1_SX345 +FJWB1_SX435 +FJXM0_SA1 +FJXM0_SI581 +FJXM0_SX401 +FJXP0_SA1 +FJXP0_SI1122 +FJXP0_SX132 +FKAA0_SX128 +FKAA0_SX398 +FKDE0_SA1 +FKDE0_SX151 +FKDE0_SX241 +FKDE0_SX421 +FKDE0_SX61 +FKDW0_SX397 +FKFB0_SA2 +FKFB0_SX348 +FKFB0_SX78 +FKKH0_SA1 +FKKH0_SA2 +FKKH0_SX120 +FKKH0_SX390 +FKLC0_SX355 +FKLC1_SI2308 +FKLC1_SX238 +FKLC1_SX328 +FKLC1_SX418 +FKLH0_SA2 +FKLH0_SX177 +FKSR0_SA1 +FKSR0_SA2 +FKSR0_SI1747 +FKSR0_SI487 +FKSR0_SX217 +FLAC0_SX451 +FLAG0_SA2 +FLAG0_SX114 +FLAG0_SX204 +FLAG0_SX24 +FLAG0_SX384 +FLEH0_SI1681 +FLEH0_SI2311 +FLEH0_SX331 +FLET0_SA1 +FLHD0_SI1827 +FLHD0_SX354 +FLJA0_SA1 +FLJA0_SI2338 +FLJD0_SI886 +FLJD0_SX76 +FLJG0_SA2 +FLKM0_SA2 +FLKM0_SI686 +FLKM0_SX260 +FLKM0_SX80 +FLMA0_SA1 +FLMA0_SI613 +FLMA0_SX433 +FLMA0_SX73 +FLMC0_SX22 +FLMK0_SI1035 +FLMK0_SX315 +FLMK0_SX405 +FLOD0_SI1917 +FLOD0_SX117 +FLOD0_SX171 +FLOD0_SX297 +FLTM0_SA1 +FLTM0_SI1070 +FLTM0_SI2330 +FMAH1_SA2 +FMAH1_SX159 +FMBG0_SA2 +FMBG0_SI2264 +FMEM0_SI747 +FMEM0_SX387 +FMJB0_SI547 +FMJB0_SX97 +FMJF0_SA2 +FMJU0_SX309 +FMJU0_SX399 +FMKC0_SI1702 +FMKC0_SX442 +FMKC0_SX82 +FMKF0_SX186 +FMPG0_SA2 +FNKL0_SI1522 +FNTB0_SI1203 +FNTB0_SI573 +FNTB0_SX303 +FPAB1_SI1471 +FPAB1_SX211 +FPAC0_SA2 +FPAD0_SA2 +FPAD0_SX356 +FPAD0_SX86 +FPAF0_SA2 +FPAF0_SX154 +FPAZ0_SA1 +FPAZ0_SA2 +FPAZ0_SX243 +FPJF0_SA1 +FPJF0_SX146 +FPJF0_SX56 +FPLS0_SI1590 +FPLS0_SX330 +FPMY0_SA1 +FPMY0_SX343 +FREH0_SA1 +FREH0_SA2 +FREH0_SX415 +FRJB0_SX347 +FRLL0_SX434 +FSAG0_SA1 +FSAG0_SX243 +FSAH0_SA1 +FSAH0_SA2 +FSAH0_SX164 +FSAH0_SX434 +FSBK0_SA2 +FSBK0_SI1069 +FSBK0_SX169 +FSCN0_SA2 +FSCN0_SI626 +FSCN0_SX266 +FSCN0_SX446 +FSCN0_SX86 +FSDC0_SA2 +FSDC0_SX142 +FSDC0_SX322 +FSDC0_SX52 +FSDJ0_SI485 +FSDJ0_SX215 +FSDJ0_SX305 +FSDJ0_SX395 +FSGF0_SX117 +FSJG0_SX130 +FSJK1_SA2 +FSJK1_SX125 +FSJK1_SX35 +FSJS0_SX181 +FSJW0_SI1963 +FSJW0_SX433 +FSKC0_SI1416 +FSKC0_SI786 +FSKC0_SX246 +FSKL0_SI1529 +FSKL0_SX449 +FSKP0_SA2 +FSLS0_SX156 +FSLS0_SX426 +FSMA0_SA2 +FSMA0_SX181 +FSMM0_SX144 +FSMM0_SX234 +FSMS1_SX244 +FSMS1_SX347 +FSPM0_SA2 +FSPM0_SX161 +FSPM0_SX71 +FSRH0_SI1931 +FSRH0_SI671 +FSRH0_SX221 +FSRH0_SX401 +FTAJ0_SI699 +FTAJ0_SX159 +FTAJ0_SX249 +FTAJ0_SX429 +FTBR0_SX21 +FTBW0_SA1 +FTMG0_SI1532 +FTMG0_SI2162 +FTMG0_SX452 +FVFB0_SA2 +FVFB0_SX132 +FVFB0_SX42 +FVKB0_SA1 +FVMH0_SA2 +FVMH0_SX116 +FVMH0_SX26 +MABC0_SI1620 +MABC0_SI2041 +MABC0_SI781 +MADC0_SX107 +MADC0_SX377 +MADD0_SA2 +MADD0_SI1295 +MADD0_SX178 +MADD0_SX268 +MADD0_SX88 +MAEB0_SX450 +MAEO0_SA1 +MAFM0_SI939 +MAFM0_SX129 +MAFM0_SX309 +MAJP0_SA2 +MAKB0_SI1646 +MAKB0_SX26 +MAKB0_SX386 +MAKR0_SX362 +MAKR0_SX92 +MAPV0_SX213 +MARC0_SA2 +MARC0_SX108 +MARC0_SX18 +MARC0_SX198 +MARW0_SI1906 +MBAR0_SA1 +MBAR0_SX419 +MBAR0_SX59 +MBBR0_SI2315 +MBBR0_SX65 +MBCG0_SA1 +MBCG0_SI486 +MBEF0_SI1281 +MBEF0_SI1911 +MBEF0_SI651 +MBEF0_SX21 +MBEF0_SX381 +MBGT0_SA2 +MBGT0_SX261 +MBGT0_SX351 +MBGT0_SX441 +MBJV0_SA1 +MBJV0_SI617 +MBJV0_SX347 +MBMA0_SI592 +MBMA0_SX232 +MBMA0_SX52 +MBMA1_SI2214 +MBMA1_SX54 +MBML0_SA2 +MBML0_SI1169 +MBML0_SX89 +MBOM0_SA2 +MBOM0_SI2274 +MBOM0_SX294 +MBSB0_SA1 +MBSB0_SX3 +MBTH0_SA2 +MBTH0_SX122 +MBTH0_SX32 +MCAE0_SX277 +MCAL0_SA2 +MCAL0_SI1768 +MCDC0_SA1 +MCDC0_SX212 +MCDD0_SA2 +MCDD0_SI883 +MCDD0_SX253 +MCDD0_SX433 +MCDR0_SI1154 +MCEF0_SX235 +MCEF0_SX415 +MCEW0_SA2 +MCHL0_SX87 +MCLK0_SX310 +MCLM0_SA1 +MCLM0_SI2086 +MCLM0_SI826 +MCPM0_SA1 +MCPM0_SX114 +MCPM0_SX294 +MCPM0_SX384 +MCSS0_SI750 +MCTH0_SA1 +MCTH0_SX39 +MCXM0_SX91 +MDAC0_SA1 +MDAC0_SX181 +MDAC0_SX361 +MDAS0_SX6 +MDBB1_SX106 +MDBB1_SX16 +MDBB1_SX376 +MDBP0_SX168 +MDCD0_SI1415 +MDCD0_SX245 +MDCD0_SX425 +MDCM0_SX40 +MDCM0_SX400 +MDDC0_SI2049 +MDDC0_SI789 +MDDC0_SX159 +MDDC0_SX69 +MDED0_SA1 +MDED0_SA2 +MDEF0_SX123 +MDEF0_SX303 +MDHL0_SI1439 +MDHL0_SX269 +MDHL0_SX449 +MDHS0_SA1 +MDHS0_SA2 +MDHS0_SI1530 +MDHS0_SI2160 +MDJM0_SX105 +MDJM0_SX15 +MDKS0_SX436 +MDLB0_SA2 +MDLC0_SX405 +MDLC1_SA2 +MDLC1_SI2065 +MDLC1_SI2144 +MDLC1_SX445 +MDLC2_SI2244 +MDLC2_SX354 +MDLH0_SA2 +MDLM0_SI1234 +MDLM0_SI1864 +MDLM0_SX154 +MDLM0_SX424 +MDLR0_SA1 +MDLR0_SA2 +MDLR0_SI1863 +MDLR0_SI603 +MDLR0_SX153 +MDLR1_SA1 +MDLR1_SA2 +MDMA0_SI1430 +MDMA0_SX260 +MDMA0_SX80 +MDMT0_SA1 +MDMT0_SA2 +MDMT0_SI1832 +MDMT0_SX122 +MDMT0_SX32 +MDNS0_SA2 +MDNS0_SI2271 +MDNS0_SX201 +MDNS0_SX21 +MDPB0_SX416 +MDPK0_SI1053 +MDPK0_SX333 +MDPK0_SX423 +MDPS0_SI719 +MDPS0_SX359 +MDRD0_SA1 +MDRD0_SX32 +MDSJ0_SI2092 +MDSS0_SA2 +MDSS0_SX441 +MDSS1_SA1 +MDSS1_SI1327 +MDSS1_SI697 +MDSS1_SX157 +MDSS1_SX67 +MDTB0_SI1200 +MDTB0_SI1830 +MDTB0_SX120 +MDWD0_SA2 +MDWD0_SX270 +MDWD0_SX90 +MDWH0_SX215 +MDWH0_SX305 +MDWM0_SA1 +MDWM0_SA2 +MDWM0_SX16 +MDWM0_SX286 +MEAL0_SA2 +MEAL0_SI2177 +MEAL0_SX107 +MEAL0_SX347 +MEDR0_SA1 +MEDR0_SA2 +MEDR0_SI1374 +MEFG0_SA1 +MEGJ0_SA2 +MEGJ0_SX257 +MEGJ0_SX3 +MEJL0_SA1 +MEJL0_SX152 +MEJL0_SX242 +MEJS0_SI610 +MEJS0_SX160 +MEJS0_SX340 +MESG0_SX432 +MESJ0_SX187 +MESJ0_SX97 +MEWM0_SI718 +MEWM0_SX178 +MEWM0_SX88 +MFER0_SI862 +MFER0_SX142 +MFRM0_SX345 +MFRM0_SX435 +MFWK0_SI1879 +MFWK0_SX169 +MFXS0_SX54 +MFXV0_SA2 +MFXV0_SX105 +MGAF0_SA1 +MGAF0_SX22 +MGAF0_SX382 +MGAG0_SA2 +MGAK0_SX226 +MGAK0_SX46 +MGAR0_SX132 +MGAW0_SI535 +MGAW0_SX175 +MGES0_SA1 +MGES0_SI2111 +MGES0_SI851 +MGJC0_SA2 +MGJC0_SX75 +MGRL0_SI2127 +MGRL0_SI867 +MGRL0_SX147 +MGRP0_SA2 +MGSH0_SA2 +MGSH0_SI1806 +MGSH0_SX127 +MGSH0_SX276 +MGSH0_SX6 +MGSL0_SA1 +MGSL0_SI534 +MGSL0_SX264 +MGXP0_SX187 +MGXP0_SX7 +MHBS0_SX315 +MHBS0_SX45 +MHIT0_SA1 +MHJB0_SA1 +MHJB0_SI1017 +MHMG0_SX195 +MHMR0_SA1 +MHMR0_SI489 +MHRM0_SA1 +MHRM0_SI958 +MHRM0_SX148 +MHRM0_SX58 +MHXL0_SI1772 +MHXL0_SX242 +MILB0_SA2 +MJAC0_SX307 +MJAC0_SX71 +MJAE0_SX174 +MJAI0_SA1 +MJAI0_SA2 +MJBG0_SX62 +MJDA0_SI1031 +MJDA0_SX311 +MJDE0_SI463 +MJDG0_SA2 +MJDG0_SI1042 +MJDG0_SI1705 +MJDM0_SA1 +MJDM0_SI974 +MJEB0_SI656 +MJEB0_SX296 +MJEB1_SA2 +MJEB1_SX207 +MJEB1_SX387 +MJEE0_SA1 +MJEE0_SX247 +MJEE0_SX337 +MJFH0_SA2 +MJFH0_SI1107 +MJFR0_SX75 +MJHI0_SA1 +MJHI0_SX158 +MJJB0_SA1 +MJJB0_SX239 +MJJJ0_SX443 +MJJM0_SA2 +MJJM0_SI827 +MJJM0_SX107 +MJKR0_SA1 +MJKR0_SI571 +MJLB0_SX176 +MJLG1_SX292 +MJLS0_SX106 +MJMA0_SA1 +MJMA0_SA2 +MJMD0_SA2 +MJMD0_SX308 +MJMD0_SX38 +MJMM0_SX85 +MJPG0_SI1191 +MJPG0_SX111 +MJPG0_SX201 +MJPG0_SX21 +MJPM0_SA2 +MJPM0_SX378 +MJPM1_SI2280 +MJPM1_SX401 +MJRA0_SA1 +MJRA0_SA2 +MJRA0_SI1236 +MJRA0_SI1866 +MJRA0_SX426 +MJRG0_SI1366 +MJRG0_SI1996 +MJRG0_SX376 +MJRH0_SX225 +MJRH1_SA1 +MJRH1_SI514 +MJRH1_SX154 +MJRH1_SX244 +MJRH1_SX424 +MJRK0_SA1 +MJRK0_SA2 +MJRK0_SI1662 +MJRK0_SX160 +MJRK0_SX250 +MJRK0_SX430 +MJRP0_SA1 +MJRP0_SA2 +MJRP0_SX225 +MJSR0_SA1 +MJSR0_SI1424 +MJSR0_SX344 +MJWG0_SA1 +MJWG0_SX265 +MJWS0_SI513 +MJWS0_SX153 +MJWS0_SX63 +MJWT0_SA1 +MJWT0_SX121 +MJWT0_SX211 +MJWT0_SX301 +MJWT0_SX31 +MJWT0_SX391 +MJXA0_SX427 +MJXL0_SI542 +MKAG0_SA1 +MKAG0_SX259 +MKAJ0_SA2 +MKAJ0_SX154 +MKAM0_SA1 +MKAM0_SX146 +MKAM0_SX326 +MKAM0_SX56 +MKDB0_SA1 +MKDB0_SA2 +MKDB0_SX152 +MKDD0_SA2 +MKES0_SA1 +MKES0_SI1253 +MKES0_SI1883 +MKES0_SX173 +MKJO0_SI1517 +MKJO0_SI887 +MKJO0_SX437 +MKLN0_SI968 +MKLN0_SX248 +MKLR0_SA2 +MKLR0_SI1689 +MKLS0_SA1 +MKLS0_SX357 +MKLS0_SX87 +MKLS1_SA1 +MKLS1_SA2 +MKLS1_SX375 +MKLW0_SA1 +MKRG0_SX411 +MKXL0_SA2 +MKXL0_SX15 +MKXL0_SX375 +MLBC0_SA1 +MLBC0_SI1869 +MLBC0_SX249 +MLEL0_SA1 +MLEL0_SA2 +MLEL0_SI1246 +MLEL0_SX256 +MLEL0_SX436 +MLJC0_SX145 +MLJC0_SX415 +MLJH0_SX64 +MLNS0_SI2037 +MMAA0_SA1 +MMAA0_SA2 +MMAA0_SX35 +MMAB1_SI1494 +MMAB1_SX234 +MMAG0_SA2 +MMAG0_SI1126 +MMAG0_SX316 +MMAM0_SI2227 +MMAM0_SX157 +MMAM0_SX427 +MMAR0_SX256 +MMBS0_SI1781 +MMCC0_SA2 +MMDB0_SX177 +MMDG0_SA1 +MMDG0_SA2 +MMDG0_SI520 +MMDG0_SX160 +MMDG0_SX250 +MMDM0_SI1941 +MMDM0_SI681 +MMDM0_SX141 +MMDM1_SA2 +MMDM1_SI2043 +MMDM1_SX423 +MMDM1_SX63 +MMDS0_SA1 +MMEA0_SA1 +MMEA0_SX128 +MMEA0_SX398 +MMEB0_SA2 +MMEB0_SX187 +MMEB0_SX367 +MMGC0_SA2 +MMGC0_SX135 +MMGC0_SX225 +MMGG0_SX269 +MMGK0_SX332 +MMGK0_SX62 +MMJB1_SA2 +MMRP0_SA2 +MMRP0_SX144 +MMSM0_SX116 +MMSM0_SX206 +MMVP0_SA1 +MMVP0_SA2 +MMWB0_SI989 +MMWB0_SX89 +MMWS0_SA2 +MMWS0_SX168 +MMWS0_SX348 +MMWS0_SX438 +MMWS1_SI1701 +MMXS0_SI2136 +MMXS0_SX246 +MMXS0_SX426 +MNET0_SI816 +MNET0_SX6 +MNTW0_SA2 +MNTW0_SX168 +MNTW0_SX78 +MPAR0_SI2206 +MPAR0_SI946 +MPAR0_SX136 +MPAR0_SX316 +MPEB0_SI1034 +MPEB0_SI1860 +MPEB0_SX240 +MPEB0_SX330 +MPFU0_SI628 +MPFU0_SX448 +MPGH0_SX114 +MPGH0_SX24 +MPGR0_SX240 +MPGR0_SX330 +MPGR1_SX149 +MPPC0_SA1 +MPRD0_SA1 +MPRD0_SX261 +MPRD0_SX351 +MPRD0_SX441 +MPRD0_SX81 +MPRK0_SI1727 +MPRK0_SX107 +MPRK0_SX377 +MPRT0_SA1 +MPRT0_SX310 +MPSW0_SI1067 +MPSW0_SX167 +MPSW0_SX437 +MRAB1_SX128 +MRAB1_SX308 +MRAI0_SA1 +MRAI0_SA2 +MRAI0_SX72 +MRAM0_SA1 +MRAM0_SA2 +MRAM0_SX15 +MRBC0_SI1859 +MRBC0_SX329 +MRBC0_SX419 +MRCG0_SI798 +MRCG0_SX168 +MRCW0_SA1 +MRCW0_SX291 +MRDD0_SI1680 +MRDD0_SX150 +MRDD0_SX277 +MRDD0_SX60 +MRDM0_SI1595 +MRDM0_SX65 +MRDS0_SA1 +MREE0_SX24 +MREH1_SX249 +MREH1_SX69 +MREM0_SA2 +MREW1_SI870 +MRFK0_SX446 +MRFL0_SA1 +MRFL0_SX256 +MRFL0_SX436 +MRFL0_SX76 +MRGM0_SA2 +MRGM0_SX262 +MRGS0_SA2 +MRGS0_SX186 +MRHL0_SI885 +MRHL0_SX345 +MRHL0_SX435 +MRJB1_SA1 +MRJB1_SA2 +MRJB1_SX210 +MRJB1_SX30 +MRJB1_SX390 +MRJH0_SA2 +MRJH0_SX307 +MRJH0_SX79 +MRJM0_SX148 +MRJM1_SA2 +MRJM1_SI1298 +MRJM1_SI1928 +MRJM1_SX128 +MRJT0_SA2 +MRJT0_SI1498 +MRJT0_SX328 +MRJT0_SX418 +MRKM0_SA2 +MRKM0_SX367 +MRLD0_SA2 +MRLD0_SI2224 +MRLD0_SX154 +MRLD0_SX424 +MRLJ0_SA1 +MRLJ0_SX250 +MRLJ0_SX340 +MRLJ1_SA1 +MRLJ1_SA2 +MRLJ1_SX321 +MRLK0_SI843 +MRLK0_SX123 +MRLK0_SX213 +MRMB0_SA2 +MRMB0_SI1581 +MRMB0_SX411 +MRMG0_SA1 +MRMG0_SI1080 +MRMG0_SX450 +MRMH0_SI1349 +MRMH0_SI2281 +MRMH0_SX121 +MRML0_SA2 +MRML0_SX341 +MRPC1_SI2112 +MRRE0_SA2 +MRRE0_SX164 +MRRE0_SX344 +MRRE0_SX74 +MRSO0_SX129 +MRSO0_SX39 +MRSP0_SX259 +MRTC0_SX378 +MRVG0_SI1140 +MRVG0_SX240 +MRWA0_SI973 +MRWA0_SX163 +MRWA0_SX73 +MRWS0_SI1732 +MRWS0_SI472 +MRWS0_SX22 +MRWS0_SX382 +MRXB0_SA2 +MRXB0_SX415 +MSAH1_SI1679 +MSAS0_SX116 +MSAS0_SX206 +MSAS0_SX386 +MSAT0_SA1 +MSAT1_SX263 +MSAT1_SX443 +MSAT1_SX83 +MSDB0_SX197 +MSDB0_SX287 +MSDB0_SX377 +MSDH0_SI2240 +MSDH0_SX440 +MSDH0_SX80 +MSDS0_SA1 +MSEM1_SI1440 +MSEM1_SX180 +MSEM1_SX270 +MSES0_SI1589 +MSES0_SX239 +MSES0_SX419 +MSFH0_SX316 +MSFV0_SI1892 +MSFV0_SX362 +MSFV0_SX92 +MSMR0_SX415 +MSMS0_SA1 +MSMS0_SX173 +MSMS0_SX83 +MSRG0_SA1 +MSRG0_SI1221 +MSTF0_SI766 +MSTF0_SX316 +MSTF0_SX46 +MSVS0_SA2 +MSVS0_SX308 +MTAS0_SX215 +MTAS0_SX35 +MTAS0_SX395 +MTAT0_SX390 +MTAT1_SX59 +MTBC0_SI1803 +MTCS0_SA2 +MTCS0_SI2265 +MTCS0_SX82 +MTDP0_SA2 +MTER0_SA2 +MTER0_SI1787 +MTJG0_SA1 +MTJG0_SI2157 +MTJG0_SX260 +MTJM0_SI1856 +MTJM0_SX146 +MTJU0_SX130 +MTJU0_SX400 +MTKD0_SX107 +MTKD0_SX287 +MTKP0_SI1023 +MTLB0_SA1 +MTLB0_SX234 +MTLC0_SA1 +MTML0_SI2325 +MTML0_SX165 +MTMN0_SA2 +MTMN0_SI1064 +MTMN0_SI2324 +MTMN0_SX434 +MTMT0_SA2 +MTMT0_SI1748 +MTPF0_SX65 +MTPG0_SI1383 +MTPG0_SI753 +MTPG0_SX303 +MTPP0_SX338 +MTPR0_SX340 +MTQC0_SI480 +MTQC0_SX91 +MTRR0_SX198 +MTRR0_SX288 +MTRT0_SA2 +MTRT0_SX254 +MTRT0_SX57 +MTWH1_SX72 +MTXS0_SA1 +MTXS0_SA2 +MVJH0_SI926 +MVJH0_SX206 +MVJH0_SX296 +MVLO0_SA1 +MVRW0_SA2 +MVRW0_SX135 +MVRW0_SX225 +MWAC0_SA2 +MWAC0_SX341 +MWAC0_SX431 +MWAD0_SX432 +MWAD0_SX72 +MWAR0_SA1 +MWAR0_SI1675 +MWCH0_SI1895 +MWCH0_SI2252 +MWCH0_SX182 +MWCH0_SX452 +MWDK0_SA1 +MWDK0_SA2 +MWDK0_SI2017 +MWDK0_SI806 +MWDK0_SX176 +MWDK0_SX86 +MWEM0_SA2 +MWEM0_SI1320 +MWEM0_SI1393 +MWEM0_SX150 +MWGR0_SX346 +MWRE0_SX247 +MWRE0_SX337 +MWRE0_SX427 +MWRP0_SA1 +MWRP0_SX273 +MWRP0_SX363 +MWSB0_SX276 +MWSH0_SX256 +MWSH0_SX76 +MZMB0_SA1 diff --git a/examples/wav2vec/unsupervised/config/timit_unmatched/valid.uid b/examples/wav2vec/unsupervised/config/timit_unmatched/valid.uid new file mode 100644 index 0000000000..e99edfe937 --- /dev/null +++ b/examples/wav2vec/unsupervised/config/timit_unmatched/valid.uid @@ -0,0 +1,620 @@ +FAEM0_SI1392 +FAJW0_SI1263 +FAJW0_SI633 +FALK0_SI658 +FALR0_SX335 +FAPB0_SI1063 +FAPB0_SI2323 +FAPB0_SX433 +FBAS0_SI1472 +FBAS0_SI2066 +FBCG1_SX352 +FBCH0_SI959 +FBJL0_SI922 +FBLV0_SI1688 +FBMH0_SI1136 +FBMH0_SI970 +FBMJ0_SA1 +FBMJ0_SI1776 +FBMJ0_SI516 +FBMJ0_SX336 +FCDR1_SI1186 +FCDR1_SI1816 +FCDR1_SI556 +FCDR1_SX286 +FCKE0_SI1741 +FCKE0_SI481 +FCLT0_SI808 +FCMG0_SI1142 +FCMG0_SX432 +FCMM0_SI1957 +FCMM0_SX420 +FCYL0_SI667 +FCYL0_SX349 +FDAS1_SI1461 +FDAS1_SI831 +FDAW0_SI1271 +FDAW0_SI2036 +FDJH0_SI935 +FDKN0_SI1202 +FDKN0_SX181 +FDKN0_SX451 +FDMY0_SA1 +FDMY0_SI567 +FDMY0_SI714 +FDMY0_SX387 +FDNC0_SI1278 +FDNC0_SI1908 +FDTD0_SA1 +FDTD0_SX321 +FEAC0_SI615 +FEAR0_SX352 +FECD0_SA1 +FECD0_SI1418 +FECD0_SI788 +FEME0_SI875 +FEME0_SX335 +FEXM0_SA1 +FEXM0_SI482 +FEXM0_SX366 +FGDP0_SI988 +FGDP0_SX88 +FGMB0_SI1145 +FGMB0_SX335 +FGRW0_SA1 +FGRW0_SI1152 +FGRW0_SX162 +FGRW0_SX432 +FHLM0_SX120 +FHLM0_SX349 +FHXS0_SA1 +FHXS0_SI1075 +FHXS0_SI2302 +FHXS0_SX175 +FJDM2_SA2 +FJDM2_SX142 +FJEN0_SA1 +FJEN0_SX327 +FJEN0_SX417 +FJHK0_SI2282 +FJKL0_SI932 +FJLG0_SI1889 +FJLR0_SI1231 +FJRB0_SX402 +FJRP1_SA1 +FJRP1_SI1432 +FJRP1_SX262 +FJRP1_SX352 +FJSK0_SI1052 +FJSP0_SI1434 +FJWB1_SI748 +FJXM0_SX311 +FJXM0_SX41 +FJXP0_SI1752 +FKAA0_SA1 +FKDE0_SI1141 +FKDE0_SI1771 +FKDW0_SI1207 +FKDW0_SI1891 +FKFB0_SI1608 +FKFB0_SX438 +FKKH0_SI1290 +FKKH0_SI1920 +FKLC0_SI985 +FKLC0_SX175 +FKLC1_SI1048 +FKLH0_SI1257 +FKSR0_SX366 +FLAC0_SI1339 +FLAG0_SI1464 +FLAG0_SI834 +FLEH0_SI1051 +FLET0_SI507 +FLJA0_SI1078 +FLJA0_SX178 +FLJD0_SI1516 +FLJG0_SI981 +FLJG0_SX171 +FLJG0_SX351 +FLKM0_SA1 +FLKM0_SI620 +FLKM0_SX350 +FLKM0_SX440 +FLMC0_SI1372 +FLMK0_SA1 +FLMK0_SI1229 +FLTM0_SX170 +FLTM0_SX350 +FLTM0_SX440 +FMAH1_SI879 +FMBG0_SI1160 +FMEM0_SA1 +FMEM0_SX333 +FMJB0_SI1177 +FMJF0_SI624 +FMJF0_SX174 +FMJF0_SX84 +FMJU0_SI1389 +FMKC0_SI1041 +FMKF0_SI1018 +FMPG0_SA1 +FMPG0_SI972 +FMPG0_SX162 +FMPG0_SX342 +FMPG0_SX432 +FNKL0_SI892 +FNTB0_SI679 +FPAB1_SA1 +FPAB1_SI2101 +FPAB1_SI841 +FPAC0_SI1921 +FPAC0_SI661 +FPAD0_SI716 +FPAD0_SX176 +FPAF0_SA1 +FPAF0_SI1054 +FPAZ0_SI2223 +FPAZ0_SI963 +FPJF0_SI1259 +FPJF0_SX352 +FPLS0_SI960 +FPMY0_SI1153 +FPMY0_SI523 +FREH0_SI1945 +FRLL0_SI805 +FSAG0_SI1323 +FSAG0_SX153 +FSAG0_SX333 +FSAG0_SX423 +FSAH0_SI614 +FSAH0_SX327 +FSAK0_SI1300 +FSBK0_SX349 +FSCN0_SA1 +FSCN0_SI705 +FSCN0_SX176 +FSDC0_SI1312 +FSDJ0_SI1115 +FSGF0_SI2187 +FSGF0_SI927 +FSJG0_SA1 +FSJG0_SA2 +FSJG0_SI940 +FSJG0_SX220 +FSJG0_SX40 +FSJG0_SX400 +FSJS0_SA1 +FSJS0_SX451 +FSJW0_SI1333 +FSKP0_SI1098 +FSMA0_SI991 +FSMA0_SX451 +FSMM0_SX324 +FSPM0_SI1241 +FSPM0_SX251 +FSRH0_SX311 +FSSB0_SI1712 +FSSB0_SX362 +FTBR0_SI1402 +FTBR0_SI921 +FTBW0_SI715 +FTBW0_SX175 +FTLG0_SI1743 +FTLG0_SI483 +FTMG0_SI902 +FVFB0_SI1510 +FVKB0_SX349 +FVMH0_SI1466 +FVMH0_SI836 +MADC0_SI1367 +MADC0_SI737 +MAEB0_SI1411 +MAEO0_SI1326 +MAJP0_SI1704 +MAJP0_SX174 +MAKB0_SA2 +MAKB0_SI1016 +MAKB0_SI2276 +MAKB0_SX116 +MAPV0_SI1293 +MAPV0_SI663 +MARW0_SX286 +MARW0_SX349 +MBBR0_SI1055 +MBBR0_SX335 +MBCG0_SI957 +MBCG0_SX327 +MBGT0_SI1841 +MBGT0_SX171 +MBMA0_SI1222 +MBMA1_SI954 +MBMA1_SX324 +MBTH0_SI2102 +MBWP0_SX349 +MCAE0_SI1447 +MCAE0_SI2077 +MCAE0_SI817 +MCAL0_SI1138 +MCDR0_SI1784 +MCDR0_SI524 +MCEF0_SI842 +MCEW0_SA1 +MCEW0_SI2072 +MCEW0_SI812 +MCEW0_SX362 +MCEW0_SX452 +MCHL0_SI1347 +MCHL0_SI1404 +MCLK0_SI2290 +MCLK0_SI650 +MCPM0_SI1824 +MCSS0_SI1380 +MCSS0_SI688 +MCTM0_SI1350 +MCTM0_SI1980 +MDAC0_SI631 +MDAS0_SI1896 +MDAS0_SI636 +MDBP0_SI528 +MDBP0_SX438 +MDCD0_SI785 +MDCD0_SX335 +MDCM0_SI1480 +MDDC0_SI1419 +MDED0_SI540 +MDEF0_SI1123 +MDEM0_SA1 +MDEM0_SI608 +MDEM0_SI800 +MDEM0_SX428 +MDHS0_SI900 +MDJM0_SI1455 +MDKS0_SX166 +MDKS0_SX346 +MDLB0_SI1306 +MDLB0_SX136 +MDLB0_SX406 +MDLC0_SI1395 +MDLC0_SI2025 +MDLC1_SI1435 +MDLH0_SX160 +MDLH0_SX430 +MDLM0_SI604 +MDLR0_SX333 +MDLR1_SI669 +MDMA0_SX170 +MDMA0_SX350 +MDMA0_SX440 +MDNS0_SI1011 +MDNS0_SI873 +MDPB0_SI1760 +MDPB0_SI866 +MDRD0_SI752 +MDSJ0_SI1462 +MDSJ0_SX438 +MDWD0_SI1260 +MDWH0_SA1 +MDWH0_SI1168 +MDWH0_SI665 +MDWM0_SI916 +MEDR0_SI2004 +MEFG0_SI491 +MEFG0_SI598 +MEGJ0_SA1 +MEGJ0_SI1337 +MEGJ0_SI707 +MEGJ0_SX167 +MEJS0_SI1240 +MESG0_SI702 +MESJ0_SI2039 +MFWK0_SX349 +MFXS0_SX324 +MFXV0_SI1005 +MFXV0_SI1342 +MGAF0_SI1282 +MGAG0_SI691 +MGAK0_SI1036 +MGAK0_SX136 +MGAR0_SX312 +MGAW0_SI1165 +MGES0_SX311 +MGJC0_SX435 +MGRL0_SX327 +MGRP0_SI1317 +MGRP0_SX327 +MGSH0_SI1176 +MGSH0_SI546 +MGSL0_SI797 +MGXP0_SI1087 +MGXP0_SI525 +MHBS0_SI945 +MHIT0_SI983 +MHMG0_SI735 +MHMR0_SI1692 +MILB0_SI903 +MJAC0_SI701 +MJAC0_SX251 +MJAE0_SX84 +MJAI0_SI682 +MJAI0_SI710 +MJDC0_SI531 +MJDE0_SA1 +MJDE0_SI1120 +MJDE0_SI490 +MJDE0_SX220 +MJDM0_SI1340 +MJDM0_SX170 +MJDM0_SX350 +MJEB0_SX170 +MJEB1_SI1467 +MJEB1_SI837 +MJFR0_SA1 +MJFR0_SX435 +MJHI0_SI1328 +MJJJ0_SI1163 +MJJM0_SI1251 +MJLB0_SI1616 +MJLS0_SI1726 +MJMA0_SI2125 +MJMD0_SI2288 +MJMM0_SI1255 +MJMM0_SX175 +MJPG0_SI1821 +MJPM0_SI1368 +MJPM1_SX311 +MJRA0_SX336 +MJRG0_SI736 +MJRG0_SX352 +MJRH0_SI1840 +MJRH1_SI1558 +MJRK0_SI880 +MJRP0_SI1845 +MJSR0_SI2054 +MJSR0_SI794 +MJWG0_SI813 +MJWG0_SI895 +MJWG0_SX175 +MJWS0_SX333 +MJWT0_SI1291 +MJWT0_SI1381 +MJXL0_SI1172 +MKAG0_SI979 +MKAH0_SX178 +MKAM0_SI1250 +MKAM0_SI1465 +MKDD0_SI1567 +MKDD0_SI2197 +MKDD0_SI937 +MKDT0_SI814 +MKES0_SI623 +MKLS0_SI1437 +MKLS0_SI2067 +MKLS1_SI915 +MKLW0_SI1571 +MKLW0_SX311 +MKRG0_SI861 +MKXL0_SI1815 +MKXL0_SI1958 +MLBC0_SI1239 +MLEL0_SI616 +MLEL0_SX166 +MLJC0_SI1225 +MLJH0_SA1 +MLJH0_SA2 +MLJH0_SI1422 +MLJH0_SI694 +MLJH0_SX244 +MLSH0_SI1417 +MLSH0_SX247 +MMAA0_SI1588 +MMAA0_SI845 +MMAB1_SI864 +MMAB1_SX324 +MMAG0_SA1 +MMAG0_SI1756 +MMAG0_SX136 +MMAR0_SI1966 +MMAR0_SX166 +MMAR0_SX346 +MMBS0_SI521 +MMBS0_SX161 +MMCC0_SI1338 +MMDB0_SI987 +MMDG0_SI1780 +MMDM0_SI1311 +MMDM1_SX153 +MMDM1_SX333 +MMEB0_SX327 +MMGC0_SI1305 +MMGG0_SI1079 +MMGG0_SX449 +MMLM0_SI2150 +MMPM0_SX161 +MMRP0_SX324 +MMSM0_SI1106 +MMSM0_SI476 +MMVP0_SI654 +MMVP0_SX347 +MMWB0_SA1 +MMWB0_SI2249 +MMWB0_SX359 +MMWB0_SX449 +MNTW0_SI1068 +MNTW0_SI1698 +MPEB0_SI600 +MPFU0_SI1258 +MPGH0_SI675 +MPGR0_SI1410 +MPGR1_SI1499 +MPMB0_SA1 +MPMB0_SA2 +MPMB0_SI1501 +MPMB0_SI2131 +MPMB0_SI871 +MPMB0_SX151 +MPMB0_SX331 +MPMB0_SX421 +MPMB0_SX61 +MPPC0_SI1412 +MPRB0_SI1215 +MPRB0_SI575 +MPRD0_SI801 +MPRD0_SX171 +MPRK0_SA1 +MPRK0_SI1097 +MPRK0_SI467 +MPRK0_SX287 +MRAB0_SI1854 +MRAB1_SI848 +MRAI0_SI2052 +MRAI0_SI792 +MRAI0_SX432 +MRAM0_SI1951 +MRCG0_SA2 +MRCG0_SI1428 +MRCG0_SX348 +MRCG0_SX438 +MRCW0_SI741 +MRDM0_SI1044 +MRDM0_SX335 +MREE0_SI1104 +MREE0_SI1959 +MREH1_SA1 +MREH1_SI1599 +MREH1_SI969 +MREM0_SI511 +MRFK0_SI1076 +MRFL0_SI1156 +MRFL0_SI526 +MRFL0_SX166 +MRGM0_SI532 +MRGM0_SX172 +MRGM0_SX442 +MRGS0_SI1356 +MRGS0_SI726 +MRGS0_SX6 +MRJB1_SI1413 +MRJB1_SI2021 +MRJB1_SX120 +MRJH0_SI1519 +MRJH0_SI889 +MRJH0_SX169 +MRJT0_SI868 +MRJT0_SX58 +MRKM0_SI1267 +MRKM0_SI1391 +MRKM0_SI637 +MRLJ0_SI790 +MRLJ1_SI2301 +MRLK0_SI1468 +MRLR0_SI1196 +MRML0_SA1 +MRML0_SI1421 +MRML0_SX161 +MRML0_SX251 +MRMS0_SI2057 +MRRE0_SA1 +MRRE0_SI1334 +MRRE0_SI952 +MRSO0_SI1206 +MRSP0_SI1429 +MRTC0_SI1458 +MRTJ0_SA1 +MRTJ0_SI772 +MRTJ0_SX142 +MRTJ0_SX232 +MRTJ0_SX52 +MRWS0_SI1102 +MRXB0_SI2215 +MRXB0_SI955 +MSAS0_SI1376 +MSAS0_SI746 +MSDH0_SI980 +MSDH0_SX170 +MSDS0_SI1077 +MSDS0_SX267 +MSDS0_SX357 +MSEM1_SI2070 +MSEM1_SI810 +MSFH0_SA1 +MSFH0_SI1738 +MSFH0_SX136 +MSFH0_SX406 +MSFV0_SI632 +MSJK0_SI1596 +MSJK0_SX336 +MSMC0_SI509 +MSMR0_SI1150 +MSMS0_SI1433 +MSRR0_SI1761 +MSRR0_SI501 +MSTF0_SI852 +MSVS0_SI2198 +MSVS0_SI938 +MSVS0_SX398 +MTAB0_SI1572 +MTAB0_SX312 +MTAT0_SA1 +MTAT0_SI1110 +MTAT0_SI811 +MTAT1_SI779 +MTAT1_SX149 +MTAT1_SX329 +MTBC0_SI543 +MTCS0_SI712 +MTDB0_SI1401 +MTDB0_SI771 +MTDP0_SA1 +MTDP0_SI1521 +MTDP0_SX171 +MTDP0_SX351 +MTER0_SA1 +MTER0_SI1157 +MTER0_SX437 +MTJG0_SX170 +MTJS0_SA2 +MTJS0_SI1822 +MTJS0_SI562 +MTJS0_SX382 +MTJU0_SI2020 +MTKD0_SI630 +MTKP0_SI2283 +MTKP0_SI454 +MTLB0_SI1134 +MTLB0_SX324 +MTLC0_SI1313 +MTLC0_SI1477 +MTML0_SX435 +MTMN0_SI582 +MTMT0_SI488 +MTPP0_SI1508 +MTPR0_SI2230 +MTPR0_SX160 +MTPR0_SX430 +MTQC0_SA1 +MTQC0_SI1441 +MTQC0_SX181 +MTQC0_SX451 +MTRC0_SI589 +MTRR0_SI918 +MTRT0_SI1227 +MTXS0_SI1060 +MTXS0_SI2320 +MTXS0_SX160 +MTXS0_SX430 +MVJH0_SI1556 +MVLO0_SI517 +MWAC0_SI1601 +MWAC0_SX161 +MWAC0_SX251 +MWAR0_SI1045 +MWDK0_SI1436 +MWEM0_SX420 +MWRE0_SA2 +MWRE0_SI1057 +MWRE0_SX67 +MWRP0_SI1443 +MWSB0_SI996 +MWSH0_SI1426 +MWSH0_SI796 +MWSH0_SX166 diff --git a/examples/wav2vec/unsupervised/scripts/prepare_timit.sh b/examples/wav2vec/unsupervised/scripts/prepare_timit.sh new file mode 100644 index 0000000000..d8f5d596b4 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/prepare_timit.sh @@ -0,0 +1,79 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +timit_root=$1 # assume it is the upper-cased version +tgt_dir=$2 +model=$3 + +set -eu + +setups="matched unmatched" +splits="test valid train train_text" + +tgt_dir=$(realpath $tgt_dir) +sph2wav=$KALDI_ROOT/tools/sph2pipe_v2.5/sph2pipe +wav_dir=$tgt_dir/wav + + +mkdir -p $tgt_dir $wav_dir +find $timit_root/{TRAIN,TEST} -iname "*.WAV" > $tgt_dir/all_sph.flist +cat $tgt_dir/all_sph.flist | sed -e 's#//*#/#g' -e 's#.*/\([^/]*\)/\([^/]*\).WAV#\1_\2#g' > $tgt_dir/all.uid +paste -d' ' $tgt_dir/{all_sph.flist,all.uid} | \ + awk -v sph2wav=$sph2wav -v wav_dir=$wav_dir '{print sph2wav " -f wav " $1 " > " wav_dir "/" $2 ".wav"}' \ + > $tgt_dir/sph2wav.sh +bash $tgt_dir/sph2wav.sh +cat $tgt_dir/all.uid | awk -v wav_dir=$(pwd)/$wav_dir '{print $1" "wav_dir"/"$1".wav"}' | sort > $tgt_dir/all_wav.scp +cut -d' ' -f2 $tgt_dir/all_wav.scp | xargs -I{} soxi -s {} > $tgt_dir/all.dur +paste -d' ' $tgt_dir/{all_wav.scp,all.dur} > $tgt_dir/all_wav_dur.scp +rm $tgt_dir/{all.uid,all_sph.flist,sph2wav.sh} + +find $timit_root/{TRAIN,TEST} -iname "*.PHN" > $tgt_dir/all_phn60.flist +while read line; do + if [ ! -f $line ]; then + >&2 echo "Cannot find transcription file '$line'" && exit 1; + fi + cut -f3 -d' ' "$line" | tr '\n' ' ' | perl -ape 's: *$:\n:;' +done < $tgt_dir/all_phn60.flist > $tgt_dir/all.phn60 +cat $tgt_dir/all_phn60.flist | sed -e 's#//*#/#g' -e 's#.*/\([^/]*\)/\([^/]*\).PHN#\1_\2#g' | \ + paste -d' ' - $tgt_dir/all.phn60 | \ + $KALDI_ROOT/egs/timit/s5/local/timit_norm_trans.pl -i - -m $KALDI_ROOT/egs/timit/s5/conf/phones.60-48-39.map -to 39 | \ + sort > $tgt_dir/all.phn +echo "done preparing wav and 39-phone transcripts" + + +for s in $setups; do + mkdir -p $tgt_dir/$s + for x in $splits; do + uid_path=config/timit_${s}/${x}.uid + grep -w -f $uid_path $tgt_dir/all.phn | cut -d' ' -f2- > $tgt_dir/$s/$x.phn + ln -sf $(realpath $tgt_dir/$s/$x.phn) $tgt_dir/$s/$x.wrd + + echo "/" > $tgt_dir/$s/$x.tsv && grep -w -f $uid_path $tgt_dir/all_wav_dur.scp | cut -d' ' -f2- | sed 's# #\t#' >> $tgt_dir/$s/$x.tsv + done + + for x in $splits; do + cat $tgt_dir/$s/$x.phn + done | tr ' ' '\n' | sort -u | awk '{print $1" "1}' > $tgt_dir/$s/dict.phn.txt + ln -sf $(realpath $tgt_dir/$s/dict.phn.txt) $tgt_dir/$s/dict.wrd.txt +done +echo "done preparing unmatched and matched setups for TIMIT" + + +for s in $setups; do + zsh scripts/prepare_audio.sh $tgt_dir/$s $tgt_dir/$s/feat $model + + lm_dir=$tgt_dir/$s/phones + fst_dir=$tgt_dir/$s/fst/phn_to_phn + + python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $tgt_dir/$s/train_text.phn --workers 10 --only-source --destdir $lm_dir --srcdict $tgt_dir/$s/dict.phn.txt + $KENLM_ROOT/lmplz -o 3 < $tgt_dir/$s/train_text.phn --discount_fallback >$lm_dir/train_text_phn.03.arpa + $KENLM_ROOT/build_binary $lm_dir/train_text_phn.03.arpa $lm_dir/train_text_phn.03.bin + $KENLM_ROOT/lmplz -o 4 < $tgt_dir/$s/train_text.phn --discount_fallback >$lm_dir/train_text_phn.04.arpa + $KENLM_ROOT/build_binary $lm_dir/train_text_phn.04.arpa $lm_dir/train_text_phn.04.bin + + python $FAIRSEQ_ROOT/examples/speech_recognition/kaldi/kaldi_initializer.py kaldi_root=$KALDI_ROOT fst_dir=$fst_dir lm_arpa=$lm_dir/train_text_phn.03.arpa data_dir=$tgt_dir/$s in_labels=phn +done +echo "done preprocessing audio and text for wav2vec-U" From 3c4a8e41559fa50b6c907fbefa1dab55d57bda5c Mon Sep 17 00:00:00 2001 From: Nithin-Holla <nithin.holla7@gmail.com> Date: Mon, 21 Jun 2021 20:16:08 -0700 Subject: [PATCH 378/774] Enabling word-level timestamps for Wav2Vec 2.0 (#3627) Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3371. Currently, the output from Wav2Vec 2.0 decoding does not contain word-level start/end times, which can be useful for certain applications of ASR. Based on the discussion [here](https://github.com/flashlight/flashlight/issues/618), they could be computed based on the output from the Flashlight decoder. For the KenLM decoder, we could first obtain the frame number corresponding to each non-blank token. Next, the timestamp of each character could be computed as `segment_start + frame_no/total_frames * segment_duration`. Finally, the start and end time of each word could be calculated based on the timestamp of the word boundary characters. In order to enable this, the frame number of each non-blank character is returned as a result of KenLM decoding. This is similar to the `timesteps` output from the [ctcdecode](https://github.com/parlance/ctcdecode#outputs-from-the-decode-method) library. ## PR review alexeib Pull Request resolved: https://github.com/pytorch/fairseq/pull/3627 Reviewed By: michaelauli Differential Revision: D29282488 Pulled By: alexeib fbshipit-source-id: b5fe64bf50abd7ef8e9539f4e338937c866eb0ca --- .../new/decoders/flashlight_decoder.py | 22 +++++++++++++++++++ examples/speech_recognition/w2l_decoder.py | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/examples/speech_recognition/new/decoders/flashlight_decoder.py b/examples/speech_recognition/new/decoders/flashlight_decoder.py index 8a548bdf66..38c7ac492f 100644 --- a/examples/speech_recognition/new/decoders/flashlight_decoder.py +++ b/examples/speech_recognition/new/decoders/flashlight_decoder.py @@ -118,6 +118,27 @@ def __init__(self, cfg: FlashlightDecoderConfig, tgt_dict: Dictionary) -> None: self.decoder_opts, self.lm, self.silence, self.blank, [] ) + def get_timesteps(self, token_idxs: List[int]) -> List[int]: + """Returns frame numbers corresponding to every non-blank token. + + Parameters + ---------- + token_idxs : List[int] + IDs of decoded tokens. + + Returns + ------- + List[int] + Frame numbers corresponding to every non-blank token. + """ + timesteps = [] + for i, token_idx in enumerate(token_idxs): + if token_idx == self.blank: + continue + if i == 0 or token_idx != token_idxs[i-1]: + timesteps.append(i) + return timesteps + def decode( self, emissions: torch.FloatTensor, @@ -134,6 +155,7 @@ def decode( { "tokens": self.get_tokens(result.tokens), "score": result.score, + "timesteps": self.get_timesteps(result.tokens), "words": [ self.word_dict.get_entry(x) for x in result.words if x >= 0 ], diff --git a/examples/speech_recognition/w2l_decoder.py b/examples/speech_recognition/w2l_decoder.py index aef4481593..fbf2d3524e 100644 --- a/examples/speech_recognition/w2l_decoder.py +++ b/examples/speech_recognition/w2l_decoder.py @@ -12,6 +12,7 @@ import gc import itertools as it import os.path as osp +from typing import List import warnings from collections import deque, namedtuple @@ -194,6 +195,26 @@ def __init__(self, args, tgt_dict): self.decoder_opts, self.lm, self.silence, self.blank, [] ) + def get_timesteps(self, token_idxs: List[int]) -> List[int]: + """Returns frame numbers corresponding to every non-blank token. + + Parameters + ---------- + token_idxs : List[int] + IDs of decoded tokens. + + Returns + ------- + List[int] + Frame numbers corresponding to every non-blank token. + """ + timesteps = [] + for i, token_idx in enumerate(token_idxs): + if token_idx == self.blank: + continue + if i == 0 or token_idx != token_idxs[i-1]: + timesteps.append(i) + return timesteps def decode(self, emissions): B, T, N = emissions.size() @@ -208,6 +229,7 @@ def decode(self, emissions): { "tokens": self.get_tokens(result.tokens), "score": result.score, + "timesteps": self.get_timesteps(result.tokens), "words": [ self.word_dict.get_entry(x) for x in result.words if x >= 0 ], From 7ca8bc12c09d91187d95117094f6b31b3342cd17 Mon Sep 17 00:00:00 2001 From: Eduardo Romero <eduardoromero@fb.com> Date: Tue, 22 Jun 2021 09:11:13 -0700 Subject: [PATCH 379/774] KMeans Attention Summary: KMeans attention main file Reviewed By: yiq-liu Differential Revision: D28478149 fbshipit-source-id: 97ef1408cfa239bdf13ee5d54d5d31b61a7f2236 --- fairseq/modules/kmeans_attention.py | 609 ++++++++++++++++++++++++++++ 1 file changed, 609 insertions(+) create mode 100644 fairseq/modules/kmeans_attention.py diff --git a/fairseq/modules/kmeans_attention.py b/fairseq/modules/kmeans_attention.py new file mode 100644 index 0000000000..11a7debcf2 --- /dev/null +++ b/fairseq/modules/kmeans_attention.py @@ -0,0 +1,609 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math +from inspect import isfunction +from operator import mul +from functools import reduce, wraps + +from aml.multimodal_video.utils.einops.lib import rearrange, repeat +from aml.multimodal_video.utils.einops.lib.layers.torch import Rearrange + +from fairseq.modules.local_attention import LocalAttention + +# constants + +TOKEN_SELF_ATTN_VALUE = -5e4 +KMEAN_INIT_ITERS = 10 + +# helper functions + + +def exists(val): + return val is not None + + +def identity(x, *args, **kwargs): + return x + + +def default(x, d): + if not exists(x): + return d if not isfunction(d) else d() + return x + + +def cast_tuple(x): + return x if isinstance(x, tuple) else (x,) + + +def cache_fn(f): + cache = None + + @wraps(f) + def cached_fn(*args, **kwargs): + nonlocal cache + if exists(cache): + return cache + cache = f(*args, **kwargs) + return cache + return cached_fn + + +def to(t): + return {'device': t.device, 'dtype': t.dtype} + + +def find_modules(nn_module, type): + return [module for module in nn_module.modules() if isinstance(module, type)] + + +def is_empty(t): + return t.nelement() == 0 + + +def max_neg_value(tensor): + return -torch.finfo(tensor.dtype).max + + +def batched_index_select(values, indices): + last_dim = values.shape[-1] + return values.gather(2, expand_dim(indices, -1, last_dim)) + + +def merge_dims(ind_from, ind_to, tensor): + shape = list(tensor.shape) + arr_slice = slice(ind_from, ind_to + 1) + shape[arr_slice] = [reduce(mul, shape[arr_slice])] + return tensor.reshape(*shape) + + +def expand_dim(t, dim, k): + t = t.unsqueeze(dim) + expand_shape = [-1] * len(t.shape) + expand_shape[dim] = k + return t.expand(*expand_shape) + + +def scatter_mean(src, t, index, dim, eps=1e-5): + numer = src.scatter_add(dim, index, t) + denom = src.scatter_add(dim, index, torch.ones_like(t)) + return numer / (denom + eps) + + +def split_at_index(dim, index, t): + pre_slices = (slice(None),) * dim + l = (*pre_slices, slice(None, index)) + r = (*pre_slices, slice(index, None)) + return t[l], t[r] + + +def reshape_dim(t, dim, split_dims): + shape = list(t.shape) + num_dims = len(shape) + dim = (dim + num_dims) % num_dims + shape[dim:dim+1] = split_dims + return t.reshape(shape) + + +def ema(old, new, decay): + if not exists(old): + return new + return old * decay + new * (1 - decay) + + +def ema_inplace(moving_avg, new, decay): + if is_empty(moving_avg): + moving_avg.data.copy_(new) + return + moving_avg.data.mul_(decay).add_(new, alpha=(1 - decay)) + +# helper classes + + +def map_first_tuple_or_el(x, fn): + if isinstance(x, tuple): + return (fn(x[0]),) + x[1:] + return fn(x) + + +class Chunk(nn.Module): + def __init__(self, chunks, fn, along_dim=-1): + super().__init__() + self.dim = along_dim + self.chunks = chunks + self.fn = fn + + def forward(self, x, **kwargs): + if self.chunks <= 1: + return self.fn(x, **kwargs) + chunks = x.chunk(self.chunks, dim=self.dim) + return torch.cat([self.fn(c, **kwargs) for c in chunks], dim=self.dim) + + +class PreNorm(nn.ModuleList): + def __init__(self, norm_class, dim, fn): + super().__init__() + self.norm = norm_class(dim) + self.fn = fn + + def forward(self, x, **kwargs): + x = self.norm(x) + return self.fn(x, **kwargs) + + +class ReZero(nn.Module): + def __init__(self, fn): + super().__init__() + self.residual_weight = nn.Parameter(torch.zeros(1)) + self.fn = fn + + def forward(self, x, **kwargs): + x = self.fn(x, **kwargs) + return map_first_tuple_or_el(x, lambda t: t * self.residual_weight) + + +class ScaleNorm(nn.Module): + def __init__(self, dim, eps=1e-5): + super().__init__() + self.g = nn.Parameter(torch.ones(1)) + self.eps = eps + + def forward(self, x): + def norm(t): + n = torch.norm(t, dim=-1, keepdim=True).clamp(min=self.eps) + return t / n * self.g + return map_first_tuple_or_el(x, norm) + + +class ProjectInOut(nn.Module): + def __init__(self, fn, dim_in, dim_out, project_out=True): + super().__init__() + self.fn = fn + self.project_in = nn.Linear(dim_in, dim_out) + self.project_out = nn.Linear(dim_out, dim_in) if project_out else identity + + def forward(self, x, **kwargs): + x = self.project_in(x) + x, loss = self.fn(x, **kwargs) + x = self.project_out(x) + return x, loss + + +class MatrixMultiply(nn.Module): + def __init__(self, tensor, transpose=False): + super().__init__() + self.tensor = tensor + self.transpose = transpose + + def forward(self, x): + tensor = self.tensor + if self.transpose: + tensor = tensor.t() + return x @ tensor + +# positional embeddings + + +class DepthWiseConv1d(nn.Module): + def __init__(self, dim_in, dim_out, kernel_size, stride=1, bias=True, causal=False): + super().__init__() + self.padding = ((kernel_size - 1), 0) if causal else (kernel_size // 2, kernel_size // 2) + + self.net = nn.Sequential( + nn.Conv1d(dim_in, dim_in, kernel_size=kernel_size, groups=dim_in, stride=stride, bias=bias), + nn.Conv1d(dim_in, dim_out, 1, bias=bias) + ) + + def forward(self, x): + x = F.pad(x, self.padding, value=0.) + return self.net(x) + + +class FixedPositionalEmbedding(nn.Module): + def __init__(self, dim, max_seq_len): + super().__init__() + inv_freq = 1. / (10000 ** (torch.arange(0, dim, 2).float() / dim)) + position = torch.arange(0, max_seq_len, dtype=torch.float) + sinusoid_inp = torch.einsum("i,j->ij", position, inv_freq) + emb = torch.cat((sinusoid_inp.sin(), sinusoid_inp.cos()), dim=-1) + self.register_buffer('emb', emb) + + def forward(self, x): + return self.emb[None, :x.shape[1], :].to(x) + + +def rotate_every_two(x): + x = rearrange(x, '... (d j) -> ... d j', j=2) + x1, x2 = x.unbind(dim=-1) + x = torch.stack((-x2, x1), dim=-1) + return rearrange(x, '... d j -> ... (d j)') + + +def apply_rotary_pos_emb(q, k, sinu_pos): + sinu_pos = rearrange(sinu_pos, '() n (j d) -> n j d', j=2) + sin, cos = sinu_pos.unbind(dim=-2) + sin, cos = map(lambda t: repeat(t, 'b n -> b (n j)', j=2), (sin, cos)) + q, k = map(lambda t: (t * cos) + (rotate_every_two(t) * sin), (q, k)) + return q, k + +# kmeans related function and class + + +def update_kmeans_on_backwards(module): + module.kmean_modules = find_modules(module, Kmeans) + + def hook(_, grad_in, grad_out): + for m in module.kmean_modules: + m.update() + + return module.register_backward_hook(hook) + + +def similarity(x, means): + return torch.einsum('bhld,hcd->bhlc', x, means) + + +def dists_and_buckets(x, means): + dists = similarity(x, means) + _, buckets = torch.max(dists, dim=-1) + return dists, buckets + + +def batched_bincount(index, num_classes, dim=-1): + shape = list(index.shape) + shape[dim] = num_classes + out = index.new_zeros(shape) + out.scatter_add_(dim, index, torch.ones_like(index, dtype=index.dtype)) + return out + + +def kmeans_iter(x, means, buckets=None): + b, h, _, d, dtype, num_clusters = *x.shape, x.dtype, means.shape[1] + + if not exists(buckets): + _, buckets = dists_and_buckets(x, means) + + bins = batched_bincount(buckets, num_clusters).sum(0, keepdim=True) + zero_mask = bins.long() == 0 + + means_ = buckets.new_zeros(b, h, num_clusters, d, dtype=dtype) + means_.scatter_add_(-2, expand_dim(buckets, -1, d), x) + means_ = F.normalize(means_.sum(0, keepdim=True), dim=-1).type(dtype) + + means = torch.where(zero_mask.unsqueeze(-1), means, means_) + means = means.squeeze(0) + return means + + +def distribution(dists, window_size): + _, topk_indices = dists.topk(k=window_size, dim=-2) + indices = topk_indices.transpose(-2, -1) + return indices.reshape(*indices.size()[:2], -1) + + +class Kmeans(nn.Module): + def __init__(self, num_heads, head_dim, num_clusters, ema_decay=0.999, commitment=1e-4): + super().__init__() + self.commitment = commitment + self.ema_decay = ema_decay + + self.register_buffer('means', torch.randn(num_heads, num_clusters, head_dim)) + self.register_buffer('initted', torch.tensor(False)) + self.num_new_means = 0 + self.new_means = None + + @torch.no_grad() + def init(self, x): + if self.initted: + return + _, h, _, d, device, _ = *x.shape, x.device, x.dtype + + num_clusters = self.means.shape[1] + + means = x.transpose(0, 1).contiguous().view(h, -1, d) + num_samples = means.shape[1] + + if num_samples >= num_clusters: + indices = torch.randperm(num_samples, device=device)[:num_clusters] + else: + indices = torch.randint(0, num_samples, (num_clusters,), device=device) + + means = means[:, indices] + + for _ in range(KMEAN_INIT_ITERS): + means = kmeans_iter(x, means) + + self.num_new_means = 0 + self.means.data.copy_(means) + self.initted.data.copy_(torch.tensor(True)) + + @torch.no_grad() + def update(self, new_means=None): + new_means = default(new_means, self.new_means) + assert exists(new_means), 'new kmeans has not been supplied' + ema_inplace(self.means, new_means, self.ema_decay) + + del self.new_means + self.new_means = None + self.num_new_means = 0 + + def forward(self, x, update_means=False): + self.init(x) + + b, dtype = x.shape[0], x.dtype + means = self.means.type(dtype) + x = F.normalize(x, 2, dim=-1).type(dtype) + + with torch.no_grad(): + dists, buckets = dists_and_buckets(x, means) + + routed_means = batched_index_select(expand_dim(means, 0, b), buckets) + loss = F.mse_loss(x, routed_means) * self.commitment + + if update_means: + with torch.no_grad(): + means = kmeans_iter(x, means, buckets) + self.new_means = ema(self.new_means, means, self.num_new_means / (self.num_new_means + 1)) + self.num_new_means += 1 + + return dists, loss + +# kmeans attention class + + +class KmeansAttention(nn.Module): + def __init__(self, num_clusters, window_size, num_heads, head_dim, causal=False, dropout=0., ema_decay=0.999, commitment=1e-4, context_window_size=None, receives_context=False, num_mem_kv=0, shared_qk=False): + super().__init__() + self.num_heads = num_heads + self.num_clusters = num_clusters + self.head_dim = head_dim + + self.window_size = window_size + self.context_window_size = default(context_window_size, window_size) + self.causal = causal + + self.shared_qk = shared_qk + self.receives_context = receives_context + self.kmeans = Kmeans(num_heads, head_dim, num_clusters, ema_decay, commitment) + self.dropout = nn.Dropout(dropout) + + self.num_mem_kv = max(num_mem_kv, 1 if causal and not shared_qk else 0) + self.mem_key = nn.Parameter(torch.randn(num_heads, num_clusters, self.num_mem_kv, head_dim)) + self.mem_value = nn.Parameter(torch.randn(num_heads, num_clusters, self.num_mem_kv, head_dim)) + + def forward(self, q, k, v, query_mask=None, key_mask=None, **kwargs): + b, h, t, d, kv_t, wsz, c_wsz, nc, device, dtype = *q.shape, k.shape[2], self.window_size, self.context_window_size, self.num_clusters, q.device, q.dtype + is_reverse = kwargs.pop('_reverse', False) + + out = torch.zeros_like(q, dtype=dtype) + + update_kmeans = self.training and not is_reverse + + key_mask = default(key_mask, query_mask) if not self.receives_context else key_mask + kv_wsz = wsz if not self.receives_context else c_wsz + + wsz = min(wsz, t) + kv_wsz = min(kv_wsz, kv_t) + + if not self.shared_qk or self.receives_context: + dists, aux_loss = self.kmeans(torch.cat((q, k), dim=2), update_kmeans) + q_dists, k_dists = split_at_index(2, t, dists) + indices = distribution(q_dists, wsz) + kv_indices = distribution(k_dists, kv_wsz) + else: + dists, aux_loss = self.kmeans(q, update_kmeans) + k = F.normalize(k, dim=-1).to(q) + indices = distribution(dists, wsz) + kv_indices = indices + + q = batched_index_select(q, indices) + k = batched_index_select(k, kv_indices) + v = batched_index_select(v, kv_indices) + + reshape_with_window = lambda x: x.reshape(b, h, nc, -1, d) + q, k, v = map(reshape_with_window, (q, k, v)) + + m_k, m_v = map(lambda x: expand_dim(x, 0, b).to(q), (self.mem_key, self.mem_value)) + k, v = map(lambda x: torch.cat(x, dim=3), ((m_k, k), (m_v, v))) + + dots = torch.einsum('bhnid,bhnjd->bhnij', q, k) * (d ** -0.5) + + mask_value = max_neg_value(dots) + + if exists(query_mask) or exists(key_mask): + query_mask = default(query_mask, lambda: torch.ones((b, t), device=device).bool()) + key_mask = default(key_mask, lambda: torch.ones((b, kv_t), device=device).bool()) + + q_mask = expand_dim(query_mask, 1, h).gather(2, indices) + kv_mask = expand_dim(key_mask, 1, h).gather(2, kv_indices) + q_mask, kv_mask = map(lambda t: t.reshape(b, h, nc, -1), (q_mask, kv_mask)) + mask = q_mask[:, :, :, :, None] * kv_mask[:, :, :, None, :] + mask = F.pad(mask, (self.num_mem_kv, 0), value=1) + dots.masked_fill_(~mask, mask_value) + del mask + + if self.causal: + q_mask, kv_mask = map(lambda t: t.reshape(b, h, nc, -1), (indices, kv_indices)) + mask = q_mask[:, :, :, :, None] >= kv_mask[:, :, :, None, :] + mask = F.pad(mask, (self.num_mem_kv, 0), value=1) + dots.masked_fill_(~mask, mask_value) + del mask + + if self.shared_qk: + q_mask, kv_mask = map(lambda t: t.reshape(b, h, nc, -1), (indices, kv_indices)) + mask = q_mask[:, :, :, :, None] == kv_mask[:, :, :, None, :] + mask = F.pad(mask, (self.num_mem_kv, 0), value=0) + dots.masked_fill_(mask, TOKEN_SELF_ATTN_VALUE) + del mask + + dots = dots.softmax(dim=-1) + dots = self.dropout(dots) + + bo = torch.einsum('bhcij,bhcjd->bhcid', dots, v) + so = torch.reshape(bo, (b, h, -1, bo.shape[-1])).type(dtype) + out = scatter_mean(out, so, indices.unsqueeze(-1).expand_as(so), -2) + return out, aux_loss + +# feedforward + + +class GELU_(nn.Module): + def forward(self, x): + return 0.5 * x * (1 + torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3)))) + + +GELU = nn.GELU if hasattr(nn, 'GELU') else GELU_ + + +class FeedForward(nn.Module): + def __init__(self, dim, mult=4, dropout=0., activation=None, glu=False): + super().__init__() + activation = default(activation, GELU) + + self.glu = glu + self.w1 = nn.Linear(dim, dim * mult * (2 if glu else 1)) + self.act = activation() + self.dropout = nn.Dropout(dropout) + self.w2 = nn.Linear(dim * mult, dim) + + def forward(self, x, **kwargs): + if not self.glu: + x = self.w1(x) + x = self.act(x) + else: + x, v = self.w1(x).chunk(2, dim=-1) + x = self.act(x) * v + + x = self.dropout(x) + x = self.w2(x) + return x + +# self attention + + +class SelfAttention(nn.Module): + def __init__(self, dim, max_seq_len, heads, local_attn_heads, window_size, dim_head=None, local_attn_window_size=None, local_attn_radius_blocks=1, causal=False, attn_dropout=0., dropout=0., kmeans_ema_decay=0.999, commitment_factor=1e-4, receives_context=False, context_window_size=None, rel_pos_emb=True, num_mem_kv=0, shared_qk=False, conv_query_kernel=9): + super().__init__() + assert dim_head or (dim % heads) == 0, 'hidden dimension must be divisible by number of heads' + assert (max_seq_len % window_size) == 0, 'maximum sequence length must be divisible by the target window size' + assert local_attn_heads <= heads, 'number of local attention heads must be less than total heads' + assert not (receives_context and local_attn_heads > 0), 'local attention cannot be used for self attention with context' + assert not (receives_context and causal), 'contextual attention layer cannot be causal' + + local_attn_window_size = default(local_attn_window_size, window_size) + context_window_size = default(context_window_size, window_size) + + self.shared_qk = shared_qk + self.receives_context = receives_context + self.heads = heads + self.local_attn_heads = local_attn_heads + self.global_attn_heads = heads - local_attn_heads + + self.causal = causal + self.window_size = window_size + + dim_head = default(dim_head, dim // heads) + dim_heads = dim_head * heads + self.dim_head = dim_head + + num_clusters = max_seq_len // window_size + + # local + + local_dim_heads = dim_head * self.local_attn_heads + + if self.local_attn_heads > 0: + rel_pos_emb_config = (dim_head, local_attn_heads) if rel_pos_emb else None + self.local_attn = LocalAttention(dim=dim_head, window_size=local_attn_window_size, causal=causal, dropout=attn_dropout, rel_pos_emb_config=rel_pos_emb_config, look_backward=local_attn_radius_blocks, look_forward=0 if causal else local_attn_radius_blocks) + self.local_to_qkv = nn.Linear(dim, 3 * local_dim_heads) + + # global + + global_dim_heads = dim_head * self.global_attn_heads + + if self.global_attn_heads > 0: + self.global_attn = KmeansAttention(num_clusters, window_size, self.global_attn_heads, dim_head, causal=causal, dropout=attn_dropout, ema_decay=kmeans_ema_decay, commitment=commitment_factor, receives_context=receives_context, num_mem_kv=num_mem_kv, shared_qk=shared_qk) + + self.to_q = nn.Sequential( + Rearrange('b n c -> b c n'), + DepthWiseConv1d(dim, global_dim_heads, conv_query_kernel, causal=causal), + Rearrange('b c n -> b n c') + ) + + self.to_v = nn.Linear(dim, global_dim_heads, bias=False) + + if not self.shared_qk: + self.to_k = nn.Linear(dim, global_dim_heads, bias=False) + + # out + + self.to_out = nn.Linear(dim_heads, dim, bias=False) + self.dropout = nn.Dropout(dropout) + + def forward(self, query, key, value, context=None, key_padding_mask=None, context_mask=None, pos_emb=None, **kwargs): + assert not (self.receives_context and not exists(context)), 'context must be passed if self attention is set to receive context' + input_mask = key_padding_mask + x = query.transpose(0, 1) + b, t, _, h, dh = *x.shape, self.heads, self.dim_head + has_local, has_global = map(lambda x: x > 0, (self.local_attn_heads, self.global_attn_heads)) + + split_heads = lambda v: reshape_dim(v, -1, (-1, dh)).transpose(1, 2).contiguous() + + if has_local: + local_qkv = self.local_to_qkv(x).chunk(3, dim=-1) + lq, lk, lv = map(split_heads, local_qkv) + + if has_global: + kv_input = x if not self.receives_context else context + + q, v = self.to_q(x), self.to_v(kv_input) + + if not self.shared_qk: + k = self.to_k(kv_input) + else: + k = self.to_q(kv_input) if self.receives_context else q + + q, k, v = map(split_heads, (q, k, v)) + + out = [] + total_loss = torch.tensor(0., requires_grad=True, **to(x)) + + if has_local: + local_out = self.local_attn(lq, lk, lv, input_mask=input_mask) + out.append(local_out) + + if has_global: + if not self.receives_context and exists(pos_emb): + q, k = apply_rotary_pos_emb(q, k, pos_emb) + + global_out, loss = self.global_attn(q, k, v, query_mask=input_mask, key_mask=context_mask) + total_loss = total_loss + loss + + out.append(global_out) + + out = torch.cat(out, dim=1) + out = out.reshape(b, h, t, -1).transpose(1, 2).reshape(b, t, -1) + out = self.dropout(out.transpose(0, 1)) + # out = self.to_out(out) + return out, total_loss From 7818f6148da4ea04f0b4b3a2df780004c3580dad Mon Sep 17 00:00:00 2001 From: Ashwyn Sharma <ashwynsharma@fb.com> Date: Wed, 23 Jun 2021 11:13:05 -0700 Subject: [PATCH 380/774] Tuna integration and model packaging Reviewed By: sravyapopuri388 Differential Revision: D29118016 fbshipit-source-id: d183c821e5d8eb1b37dda48ded9e24e5efc65dc7 --- .../models/transformer_monotonic_attention.py | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/examples/simultaneous_translation/models/transformer_monotonic_attention.py b/examples/simultaneous_translation/models/transformer_monotonic_attention.py index 1062e9b955..77c0350d2d 100644 --- a/examples/simultaneous_translation/models/transformer_monotonic_attention.py +++ b/examples/simultaneous_translation/models/transformer_monotonic_attention.py @@ -34,6 +34,7 @@ "TransformerMonotonicDecoderOut", [ ("action", int), + ("p_choose", Optional[Tensor]), ("attn_list", Optional[List[Optional[Dict[str, Tensor]]]]), ("step_list", Optional[List[Optional[Tensor]]]), ("encoder_out", Optional[Dict[str, List[Tensor]]]), @@ -150,12 +151,16 @@ def pre_attention( x = x.transpose(0, 1) encoder_out = encoder_out_dict["encoder_out"][0] - encoder_padding_mask = ( - encoder_out_dict["encoder_padding_mask"][0] - if encoder_out_dict["encoder_padding_mask"] - and len(encoder_out_dict["encoder_padding_mask"]) > 0 - else None - ) + + if "encoder_padding_mask" in encoder_out_dict: + encoder_padding_mask = ( + encoder_out_dict["encoder_padding_mask"][0] + if encoder_out_dict["encoder_padding_mask"] + and len(encoder_out_dict["encoder_padding_mask"]) > 0 + else None + ) + else: + encoder_padding_mask = None return x, encoder_out, encoder_padding_mask @@ -215,6 +220,8 @@ def extract_features( attn_list: List[Optional[Dict[str, Tensor]]] = [] step_list: List[Optional[Tensor]] = [] + p_choose = torch.tensor([1.0]) + for i, layer in enumerate(self.layers): x, attn, _ = layer( @@ -255,6 +262,7 @@ def extract_features( return x, TransformerMonotonicDecoderOut( action=0, + p_choose=p_choose, attn_list=None, step_list=None, encoder_out=None, @@ -265,6 +273,7 @@ def extract_features( return x, TransformerMonotonicDecoderOut( action=1, + p_choose=p_choose, attn_list=attn_list, step_list=step_list, encoder_out=encoder_out, From 520d9d3ba68d06e56f0b9e1d331ed444f48755b2 Mon Sep 17 00:00:00 2001 From: Alex Liu <alexliu36@gmail.com> Date: Thu, 24 Jun 2021 13:59:58 -0700 Subject: [PATCH 381/774] remove debug code from w2vu gen (#1997) Summary: see title Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1997 Reviewed By: wnhsu, Alexander-H-Liu Differential Revision: D29371459 Pulled By: alexeib fbshipit-source-id: 874e36462f919aa4ba698a0dd49531c89f7e27cf --- examples/wav2vec/unsupervised/w2vu_generate.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/wav2vec/unsupervised/w2vu_generate.py b/examples/wav2vec/unsupervised/w2vu_generate.py index 2bad873616..6177239dc7 100644 --- a/examples/wav2vec/unsupervised/w2vu_generate.py +++ b/examples/wav2vec/unsupervised/w2vu_generate.py @@ -428,8 +428,6 @@ def build_generator(cfg: UnsupGenerateConfig): ) hypo_futures.append(hypos) samples.append(sample) - if cfg.debug: - break itr = list(zip(hypo_futures, samples)) start = 0 end = len(itr) From 81046fc13ef05c7b9bbfb7a4cd66e59033918dc3 Mon Sep 17 00:00:00 2001 From: Shiyan Deng <dsy842974287@fb.com> Date: Thu, 24 Jun 2021 14:01:26 -0700 Subject: [PATCH 382/774] Add decoder and decoding wrapper for nmt Summary: Add a decoder class `FairSeqNVFasterTransformerDecoder` that could replace `TransformerDecoder` in nmt. Add a decoding class `FairSeqNVFasterTransformerDecoding` that does `decoding + beam serach`. We can't use `FairSeqNVFasterTransformerDecoding` right now in nmt because nmt ensembles decoders and calculate avg probabilities across those decoders. Follow ups: 1. Currently `FairSeqNVFasterTransformerDecoder` doesn't produce "attn" https://fburl.com/code/pom5vhr5. 2. Move mem_cache and cache to incremental_state 2. Benchmark fairseq ft encoder decoder. 2. E2e tests stucks at somewhere. Differential Revision: D29166310 fbshipit-source-id: 36360cfff1d22ed4f12f89068ee30dec835d2141 --- fairseq/models/transformer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py index f4f6bea27b..c2726af34d 100644 --- a/fairseq/models/transformer.py +++ b/fairseq/models/transformer.py @@ -541,13 +541,14 @@ def forward_scriptable( # `forward` so we use a dictionary instead. # TorchScript does not support mixed values so the values are all lists. # The empty list is equivalent to None. + src_lengths = src_tokens.ne(self.padding_idx).sum(dim=1, dtype=torch.int32).reshape(-1, 1).contiguous() return { "encoder_out": [x], # T x B x C "encoder_padding_mask": [encoder_padding_mask], # B x T "encoder_embedding": [encoder_embedding], # B x T x C "encoder_states": encoder_states, # List[T x B x C] "src_tokens": [], - "src_lengths": [], + "src_lengths": [src_lengths], } @torch.jit.export From f8871521f7b2496bbfce58ff72ea611c4f6ec244 Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushall@fb.com> Date: Sat, 26 Jun 2021 08:59:02 -0700 Subject: [PATCH 383/774] Load dict from pretrained hubert model in HubertEncoder (#1999) Summary: ## What does this PR do? Load dict from pretrained hubert model in HubertEncoder so that the dictionary is not constructed for the labels. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1999 Test Plan: Tested with the cmdline below. ASR training progresses as expected without any exception. ``` PYTHONPATH=. HYDRA_FULL_ERROR=1 python fairseq_cli/hydra_train.py -m \ --config-dir examples/hubert/config/finetune \ --config-name base_10h \ dataset.num_workers=0 \ task.data=/checkpoint/kushall/data/librispeech/10h/raw \ task.label_dir=/checkpoint/kushall/data/librispeech/10h/raw \ model.w2v_path=/checkpoint/kushall/final_model_checkpoints/hubert/hubert_base_ls960_updated.pt \ hydra.sweep.dir=/checkpoint/kushall/experiments/hubert_test/base_asr_10h ``` Reviewed By: Abdel-rahmanMohamed Differential Revision: D29405491 Pulled By: hikushalhere fbshipit-source-id: be168a0ce27f8fcfea3dc980a192ba43fdf23871 --- examples/hubert/README.md | 5 ++--- fairseq/models/hubert/hubert_asr.py | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/hubert/README.md b/examples/hubert/README.md index 3254b754f0..b501a6eb2a 100644 --- a/examples/hubert/README.md +++ b/examples/hubert/README.md @@ -9,13 +9,12 @@ HuBERT Extra Large (~1B params) | [Libri-Light](https://github.com/facebookresea HuBERT Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k_finetune_ls960.pt) HuBERT Extra Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k_finetune_ls960.pt) -## Load a pretrained model +## Load a model ``` ckpt_path = "/path/to/the/checkpoint.pt" -models, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path], strict=False) +models, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path]) model = models[0] ``` -** We will follow-up with a patch such that you wouldn't need to pass `strict=False` for loading the checkpoint in future. ## Train a new model diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index 4cb3fb7153..dce899c9de 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -281,6 +281,9 @@ def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): w2v_args.task.data = cfg.data task = tasks.setup_task(w2v_args.task) + if state is not None and "task_state" in state: + # This will load the stored "dictionaries" object + task.load_state_dict(state["task_state"]) model = task.build_model(w2v_args.model) if state is not None and not cfg.no_pretrained_weights: From 53bf2b12934aa5d38ff2d700221457ca34b55cab Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Mon, 28 Jun 2021 01:45:15 -0700 Subject: [PATCH 384/774] Extract File Chunking to its own utils (#1955) Summary: ## What does this PR do? there are a few places where we do file chunking for multiprocessing a single file. However, the code is partly in Binarizer and partly just duplicated here and there. This PR extracts the file chunking/reading logic. The multiprocessing logic could probably be extracted too, but I haven't found a good abstraction yet. # Testing Added testing for this reading logic + maybe fixed a bug where the last part of a file might get dropped (even if it's unclear with the current stopping logic) Tested by running the preprocessing script as follow: ``` python -m fairseq_cli.preprocess --source-lang de --target-lang en --trainpref ...train.spm.clean.de_en --srcdict ...fairseq.dict --tgtdict .../fairseq.dict --destdir ... --workers 60 ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1955 Reviewed By: myleott Differential Revision: D29065473 Pulled By: Mortimerp9 fbshipit-source-id: c60843de8cfd45a63b3dbb8290f57ef3df3bf983 --- fairseq/binarizer.py | 56 +++++---------------- fairseq/data/dictionary.py | 55 +++++++++++---------- fairseq/file_chunker_utils.py | 84 ++++++++++++++++++++++++++++++++ fairseq_cli/preprocess.py | 38 +++++++++------ tests/test_dictionary.py | 29 +++++++++++ tests/test_file_chunker_utils.py | 63 ++++++++++++++++++++++++ 6 files changed, 239 insertions(+), 86 deletions(-) create mode 100644 fairseq/file_chunker_utils.py create mode 100644 tests/test_file_chunker_utils.py diff --git a/fairseq/binarizer.py b/fairseq/binarizer.py index 18ae67bf25..ae4d02a6db 100644 --- a/fairseq/binarizer.py +++ b/fairseq/binarizer.py @@ -3,23 +3,14 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import os from collections import Counter +from typing import Dict import torch + +from fairseq.file_chunker_utils import Chunker from fairseq.file_io import PathManager from fairseq.tokenizer import tokenize_line -from typing import List, Dict - - -def safe_readline(f): - pos = f.tell() - while True: - try: - return f.readline() - except UnicodeDecodeError: - pos -= 1 - f.seek(pos) # search where this character begins class Binarizer: @@ -42,19 +33,10 @@ def replaced_consumer(word, idx): if idx == dict.unk_index and word != dict.unk_word: replaced.update([word]) - with open(PathManager.get_local_path(filename), "r", encoding="utf-8") as f: - f.seek(offset) - # next(f) breaks f.tell(), hence readline() must be used - line = safe_readline(f) - while line: - # f.tell() does not always give the byte position in the file - # sometimes it skips to a very large number - # it is unlikely that through a normal read we go from - # end bytes to end + 2**32 bytes (4 GB) and this makes it unlikely - # that the procedure breaks by the undeterministic behavior of - # f.tell() - if end > 0 and f.tell() > end and f.tell() < end + 2 ** 32: - break + with Chunker( + PathManager.get_local_path(filename), offset, end + ) as line_iterator: + for line in line_iterator: if already_numberized: id_strings = line.strip().split() id_list = [int(id_string) for id_string in id_strings] @@ -75,7 +57,6 @@ def replaced_consumer(word, idx): nseq += 1 ntok += len(ids) consumer(ids) - line = f.readline() return { "nseq": nseq, "nunk": sum(replaced.values()), @@ -89,26 +70,11 @@ def binarize_alignments( ) -> Dict[str, int]: nseq = 0 - with open(PathManager.get_local_path(filename), "r") as f: - f.seek(offset) - line = safe_readline(f) - while line: - if end > 0 and f.tell() > end: - break + with Chunker( + PathManager.get_local_path(filename), offset, end + ) as line_iterator: + for line in line_iterator: ids = alignment_parser(line) nseq += 1 consumer(ids) - line = f.readline() return {"nseq": nseq} - - @staticmethod - def find_offsets(filename, num_chunks) -> List[int]: - with open(PathManager.get_local_path(filename), "r", encoding="utf-8") as f: - size = os.fstat(f.fileno()).st_size - chunk_size = size // num_chunks - offsets = [0 for _ in range(num_chunks + 1)] - for i in range(1, num_chunks): - f.seek(chunk_size * i) - safe_readline(f) - offsets[i] = f.tell() - return offsets diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index 0d8308a811..6876b461d7 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -9,8 +9,8 @@ import torch from fairseq import utils -from fairseq.binarizer import safe_readline from fairseq.data import data_utils +from fairseq.file_chunker_utils import Chunker, find_offsets from fairseq.file_io import PathManager from fairseq.tokenizer import tokenize_line @@ -48,6 +48,9 @@ def __getitem__(self, idx): return self.symbols[idx] return self.unk_word + def get_count(self, idx): + return self.count[idx] + def __len__(self): """Returns the number of symbols in the dictionary""" return len(self.symbols) @@ -78,7 +81,13 @@ def string( """ if torch.is_tensor(tensor) and tensor.dim() == 2: return "\n".join( - self.string(t, bpe_symbol, escape_unk, extra_symbols_to_ignore, include_eos=include_eos) + self.string( + t, + bpe_symbol, + escape_unk, + extra_symbols_to_ignore, + include_eos=include_eos, + ) for t in tensor ) @@ -320,31 +329,18 @@ def encode_line( @staticmethod def _add_file_to_dictionary_single_worker( - filename, tokenize, eos_word, worker_id=0, num_workers=1 + filename, + tokenize, + eos_word, + start_offset, + end_offset, ): counter = Counter() - with open(PathManager.get_local_path(filename), "r", encoding="utf-8") as f: - size = os.fstat(f.fileno()).st_size - chunk_size = size // num_workers - offset = worker_id * chunk_size - end = offset + chunk_size - f.seek(offset) - if offset > 0: - safe_readline(f) # drop first incomplete line - line = f.readline() - while line: + with Chunker(filename, start_offset, end_offset) as line_iterator: + for line in line_iterator: for word in tokenize(line): counter.update([word]) counter.update([eos_word]) - # f.tell() returns only an opaque number which can - # return to the position in the file via f.seek() - # and does not necessarily represent a byte position - # in the file. However, f.tell() is faithful to the - # byte position _most of the time_. Thus we can just - # check against the file size to prevent early exit. - if f.tell() > end and f.tell() < size: - break - line = f.readline() return counter @staticmethod @@ -353,14 +349,23 @@ def merge_result(counter): for w, c in sorted(counter.items()): dict.add_symbol(w, c) + local_file = PathManager.get_local_path(filename) + offsets = find_offsets(local_file, num_workers) if num_workers > 1: + chunks = zip(offsets, offsets[1:]) pool = Pool(processes=num_workers) results = [] - for worker_id in range(num_workers): + for (start_offset, end_offset) in chunks: results.append( pool.apply_async( Dictionary._add_file_to_dictionary_single_worker, - (filename, tokenize, dict.eos_word, worker_id, num_workers), + ( + local_file, + tokenize, + dict.eos_word, + start_offset, + end_offset, + ), ) ) pool.close() @@ -370,7 +375,7 @@ def merge_result(counter): else: merge_result( Dictionary._add_file_to_dictionary_single_worker( - filename, tokenize, dict.eos_word + local_file, tokenize, dict.eos_word, offsets[0], offsets[1] ) ) diff --git a/fairseq/file_chunker_utils.py b/fairseq/file_chunker_utils.py new file mode 100644 index 0000000000..443100c61a --- /dev/null +++ b/fairseq/file_chunker_utils.py @@ -0,0 +1,84 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import typing as tp + + +def _safe_readline(fd) -> str: + pos = fd.tell() + while True: + try: + return fd.readline() + except UnicodeDecodeError: + pos -= 1 + fd.seek(pos) # search where this character begins + + +def find_offsets(filename: str, num_chunks: int) -> tp.List[int]: + """ + given a file and a number of chuncks, find the offsets in the file + to be able to chunk around full lines. + """ + with open(filename, "r", encoding="utf-8") as f: + size = os.fstat(f.fileno()).st_size + chunk_size = size // num_chunks + offsets = [0 for _ in range(num_chunks + 1)] + for i in range(1, num_chunks): + f.seek(chunk_size * i) + _safe_readline(f) + offsets[i] = f.tell() + offsets[-1] = size + return offsets + + +class ChunkLineIterator: + """ + Iterator to properly iterate over lines of a file chunck. + """ + + def __init__(self, fd, start_offset: int, end_offset: int): + self._fd = fd + self._start_offset = start_offset + self._end_offset = end_offset + + def __iter__(self) -> tp.Iterable[str]: + self._fd.seek(self._start_offset) + # next(f) breaks f.tell(), hence readline() must be used + line = _safe_readline(self._fd) + while line: + pos = self._fd.tell() + # f.tell() does not always give the byte position in the file + # sometimes it skips to a very large number + # it is unlikely that through a normal read we go from + # end bytes to end + 2**32 bytes (4 GB) and this makes it unlikely + # that the procedure breaks by the undeterministic behavior of + # f.tell() + if ( + self._end_offset > 0 + and pos > self._end_offset + and pos < self._end_offset + 2 ** 32 + ): + break + yield line + line = self._fd.readline() + + +class Chunker: + """ + contextmanager to read a chunck of a file line by line. + """ + + def __init__(self, path: str, start_offset: int, end_offset: int): + self.path = path + self.start_offset = start_offset + self.end_offset = end_offset + + def __enter__(self) -> ChunkLineIterator: + self.fd = open(self.path, "r", encoding="utf-8") + return ChunkLineIterator(self.fd, self.start_offset, self.end_offset) + + def __exit__(self, exc_type, exc_val, exc_tb) -> None: + self.fd.close() diff --git a/fairseq_cli/preprocess.py b/fairseq_cli/preprocess.py index b788900d30..f7170eb00f 100644 --- a/fairseq_cli/preprocess.py +++ b/fairseq_cli/preprocess.py @@ -18,7 +18,7 @@ from fairseq import options, tasks, utils from fairseq.binarizer import Binarizer from fairseq.data import indexed_dataset - +from fairseq.file_chunker_utils import find_offsets logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -133,11 +133,14 @@ def merge_result(worker_result): input_file = "{}{}".format( input_prefix, ("." + lang) if lang is not None else "" ) - offsets = Binarizer.find_offsets(input_file, num_workers) + offsets = find_offsets(input_file, num_workers) + (first_chunk, *more_chunks) = zip(offsets, offsets[1:]) pool = None if num_workers > 1: pool = Pool(processes=num_workers - 1) - for worker_id in range(1, num_workers): + for worker_id, (start_offset, end_offset) in enumerate( + more_chunks, start=1 + ): prefix = "{}{}".format(output_prefix, worker_id) pool.apply_async( binarize, @@ -147,8 +150,8 @@ def merge_result(worker_result): vocab, prefix, lang, - offsets[worker_id], - offsets[worker_id + 1], + start_offset, + end_offset, ), callback=merge_result, ) @@ -161,7 +164,11 @@ def merge_result(worker_result): ) merge_result( Binarizer.binarize( - input_file, vocab, lambda t: ds.add_item(t), offset=0, end=offsets[1] + input_file, + vocab, + lambda t: ds.add_item(t), + offset=first_chunk[0], + end=first_chunk[1], ) ) if num_workers > 1: @@ -193,11 +200,14 @@ def merge_result(worker_result): nseq[0] += worker_result["nseq"] input_file = input_prefix - offsets = Binarizer.find_offsets(input_file, num_workers) + offsets = find_offsets(input_file, num_workers) + (first_chunk, *more_chunks) = zip(offsets, offsets[1:]) pool = None if num_workers > 1: pool = Pool(processes=num_workers - 1) - for worker_id in range(1, num_workers): + for worker_id, (start_offset, end_offset) in enumerate( + more_chunks, start=1 + ): prefix = "{}{}".format(output_prefix, worker_id) pool.apply_async( binarize_alignments, @@ -206,8 +216,8 @@ def merge_result(worker_result): input_file, utils.parse_alignment, prefix, - offsets[worker_id], - offsets[worker_id + 1], + start_offset, + end_offset, ), callback=merge_result, ) @@ -222,8 +232,8 @@ def merge_result(worker_result): input_file, utils.parse_alignment, lambda t: ds.add_item(t), - offset=0, - end=offsets[1], + offset=first_chunk[0], + end=first_chunk[1], ) ) if num_workers > 1: @@ -387,10 +397,6 @@ def dataset_dest_file(args, output_prefix, lang, extension): return "{}.{}".format(base, extension) -def get_offsets(input_file, num_workers): - return Binarizer.find_offsets(input_file, num_workers) - - def cli_main(): parser = options.get_preprocessing_parser() args = parser.parse_args() diff --git a/tests/test_dictionary.py b/tests/test_dictionary.py index 81ce102f4f..dc9d71b3c7 100644 --- a/tests/test_dictionary.py +++ b/tests/test_dictionary.py @@ -4,10 +4,13 @@ # LICENSE file in the root directory of this source tree. import io +import os +import string import tempfile import unittest import torch +from fairseq import tokenizer from fairseq.data import Dictionary @@ -111,6 +114,32 @@ def test_space(self): self.assertEqual(d.index("a"), 5) self.assertEqual(d.index("b"), 6) + def test_add_file_to_dict(self): + counts = {} + num_lines = 100 + per_line = 10 + with tempfile.TemporaryDirectory("test_sampling") as data_dir: + filename = os.path.join(data_dir, "dummy.txt") + with open(filename, "w", encoding="utf-8") as data: + for c in string.ascii_letters: + line = f"{c} " * per_line + for _ in range(num_lines): + data.write(f"{line}\n") + counts[c] = per_line * num_lines + per_line += 5 + + dict = Dictionary() + Dictionary.add_file_to_dictionary( + filename, dict, tokenizer.tokenize_line, 10 + ) + dict.finalize(threshold=0, nwords=-1, padding_factor=8) + + for c in string.ascii_letters: + count = dict.get_count(dict.index(c)) + self.assertEqual( + counts[c], count, f"{c} count is {count} but should be {counts[c]}" + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_file_chunker_utils.py b/tests/test_file_chunker_utils.py new file mode 100644 index 0000000000..5cded04572 --- /dev/null +++ b/tests/test_file_chunker_utils.py @@ -0,0 +1,63 @@ +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import shutil +import tempfile +import unittest +from typing import Optional + + +class TestFileChunker(unittest.TestCase): + _tmpdir: Optional[str] = None + _tmpfile: Optional[str] = None + _line_content = "Hello, World\n" + _num_bytes = None + _num_lines = 200 + _num_splits = 20 + + @classmethod + def setUpClass(cls) -> None: + cls._num_bytes = len(cls._line_content.encode("utf-8")) + cls._tmpdir = tempfile.mkdtemp() + with open(os.path.join(cls._tmpdir, "test.txt"), "w") as f: + cls._tmpfile = f.name + for _i in range(cls._num_lines): + f.write(cls._line_content) + f.flush() + + @classmethod + def tearDownClass(cls) -> None: + # Cleanup temp working dir. + if cls._tmpdir is not None: + shutil.rmtree(cls._tmpdir) # type: ignore + + def test_find_offsets(self): + from fairseq.file_chunker_utils import find_offsets + + offsets = find_offsets(self._tmpfile, self._num_splits) + self.assertEqual(len(offsets), self._num_splits + 1) + (zero, *real_offsets, last) = offsets + self.assertEqual(zero, 0) + for i, o in enumerate(real_offsets): + self.assertEqual( + o, + self._num_bytes + + ((i + 1) * self._num_bytes * self._num_lines / self._num_splits), + ) + self.assertEqual(last, self._num_bytes * self._num_lines) + + def test_readchunks(self): + from fairseq.file_chunker_utils import Chunker, find_offsets + + offsets = find_offsets(self._tmpfile, self._num_splits) + for start, end in zip(offsets, offsets[1:]): + with Chunker(self._tmpfile, start, end) as lines: + all_lines = list(lines) + num_lines = self._num_lines / self._num_splits + self.assertAlmostEqual( + len(all_lines), num_lines, delta=1 + ) # because we split on the bites, we might end up with one more/less line in a chunk + self.assertListEqual( + all_lines, [self._line_content for _ in range(len(all_lines))] + ) From 0972dde844e39540faf53b6d9afe76b38c7e2fd6 Mon Sep 17 00:00:00 2001 From: Liang Luo <liangluo@fb.com> Date: Tue, 29 Jun 2021 00:02:06 -0700 Subject: [PATCH 385/774] apply nonblocking H/D transfer optimizations Summary: merge D27701492 + D27701493 * make checkpoint activation cpu offloading nonblocking * make gradient cpu offloading nonblocking * synchronize cpu/gpu stream before applying optimizer update Reviewed By: myleott Differential Revision: D28047171 fbshipit-source-id: f862eca64049acc045026aa4f5e6dbe8d0f03244 --- fairseq/modules/checkpoint_activations.py | 4 ++-- fairseq/optim/cpu_adam.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index b44fc346ce..7489e09eb7 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -163,7 +163,7 @@ def forward(ctx, run_function, parent_ctx_dict, kwarg_keys, *args): if parent_ctx_dict["offload"]: ctx.fwd_device = tuple(x.device for x in tensor_inputs) ctx.grad_requirements = tuple(x.requires_grad for x in tensor_inputs) - tensor_inputs = tuple(x.cpu() for x in tensor_inputs) + tensor_inputs = tuple(x.to(torch.device("cpu"), non_blocking=True) for x in tensor_inputs) else: ctx.fwd_device, ctx.grad_requirements = None, None @@ -196,7 +196,7 @@ def backward(ctx, *args): tensor_inputs = checkpoint.detach_variable(tensor_inputs) if ctx.fwd_device is not None: tensor_inputs = [ - t.to(ctx.fwd_device[i]) for i, t in enumerate(tensor_inputs) + t.to(ctx.fwd_device[i], non_blocking=True) for i, t in enumerate(tensor_inputs) ] for i, need_grad in enumerate(ctx.grad_requirements): tensor_inputs[i].requires_grad = need_grad diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py index e36bccf123..211c376756 100644 --- a/fairseq/optim/cpu_adam.py +++ b/fairseq/optim/cpu_adam.py @@ -127,6 +127,8 @@ def step(self, closure=None): with torch.enable_grad(): loss = closure() + torch.cuda.synchronize() + for group_id, group in enumerate(self.param_groups): for param_id, p in enumerate(group["params"]): if p.grad is None: From 0794f9ae21bb50f940ff9b1bc3f28be08dfa7b76 Mon Sep 17 00:00:00 2001 From: Edan Tessel Sneh <edan@fb.com> Date: Tue, 29 Jun 2021 15:09:13 -0700 Subject: [PATCH 386/774] Back out "Adding FBSequenceGenerator" Summary: Original commit changeset: b7a83bbc719d Reverts commit D26228721 (https://github.com/pytorch/fairseq/commit/6381aa2bb24f125d271e241c726a2fea581bc3c4) Reviewed By: theweiho Differential Revision: D29369494 fbshipit-source-id: 9e745b11bc532ca8ced2816326aa94afbb46ba2d --- fairseq/tasks/fairseq_task.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index fbec9bb2a5..99bf2c3fe9 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -379,10 +379,6 @@ def build_generator( SequenceGenerator, SequenceGeneratorWithAlignment, ) - try: - from fairseq.fb_sequence_generator import FBSequenceGenerator - except ModuleNotFoundError: - pass # Choose search strategy. Defaults to Beam Search. sampling = getattr(args, "sampling", False) @@ -450,8 +446,6 @@ def build_generator( if getattr(args, "print_alignment", False): seq_gen_cls = SequenceGeneratorWithAlignment extra_gen_cls_kwargs["print_alignment"] = args.print_alignment - elif getattr(args, "fb_seq_gen", False): - seq_gen_cls = FBSequenceGenerator else: seq_gen_cls = SequenceGenerator From 9bee82e4a7b73249a88f2e2d286e991493ef13c2 Mon Sep 17 00:00:00 2001 From: Omry Yadan <omry@fb.com> Date: Thu, 1 Jul 2021 06:37:02 -0700 Subject: [PATCH 387/774] Hydra 1.1 compatibility: Use an explicit schema for the primary config (#3659) Summary: ## What does this PR do? Fixes compatibility with Hydra 1.1. The result is compatible with both Hydra 1.0 and Hydra 1.1, and will allow a smoother migration to Hydra 1.1. At this point I am not yet removing the restriction on the Hydra version from setup.py: 1. It depends on some Hydra 1.1 changes that are not yet released (It will be compatible with 1.1.1). 2. Upgrading will result in deprecation warnings, and fixing them will break compatibility with Hydra 1.0. There will be some followup to make the code fully compatible with 1.1 once Hydra 1.1 is the default version in fbcode. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3659 Reviewed By: omry Differential Revision: D29498036 Pulled By: lematt1991 fbshipit-source-id: 96999cde5daad6749ef4d3ddf6a36a1e984ff201 --- fairseq/checkpoint_utils.py | 2 +- fairseq/config/config.yaml | 1 + fairseq/dataclass/initialize.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 627f14160d..d22d987020 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -203,7 +203,7 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): cfg.restore_file == "checkpoint_last.pt" ): # default value of restore_file is 'checkpoint_last.pt' checkpoint_path = os.path.join( - cfg.save_dir, "checkpoint_last{}.pt".format(suffix) + cfg.get("save_dir"), "checkpoint_last{}.pt".format(suffix) ) first_launch = not PathManager.exists(checkpoint_path) if cfg.finetune_from_model is not None and first_launch: diff --git a/fairseq/config/config.yaml b/fairseq/config/config.yaml index e20d914b9b..087083e88a 100644 --- a/fairseq/config/config.yaml +++ b/fairseq/config/config.yaml @@ -5,6 +5,7 @@ hydra: dir: . defaults: + - config_schema - task: null - model: null - criterion: cross_entropy diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index 479aeb8b16..1d5c90eefd 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -16,7 +16,7 @@ def hydra_init(cfg_name="config") -> None: cs = ConfigStore.instance() - cs.store(name=cfg_name, node=FairseqConfig) + cs.store(name=f"{cfg_name}_schema", node=FairseqConfig) for k in FairseqConfig.__dataclass_fields__: v = FairseqConfig.__dataclass_fields__[k].default From 096f492a224e14ed6628d96700f1ae8b534d86a8 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 1 Jul 2021 08:36:02 -0700 Subject: [PATCH 388/774] fix xlsr checkpoint finetuning saving issues (#2013) Summary: fixes an issue with some old checkpoints that had deep nested namespaces containing choices enum - most prominently xlsr 53 checkpoint fixes #3634 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2013 Reviewed By: xuqiantong Differential Revision: D29511325 Pulled By: alexeib fbshipit-source-id: 79df978afa7482b4ce3aaf7396e193626181aa17 --- fairseq/dataclass/utils.py | 82 +++++++++++++++----------- fairseq/models/wav2vec/wav2vec2_asr.py | 2 + 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 89206125d1..1ed28b7ccc 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -17,7 +17,7 @@ from fairseq.dataclass.configs import FairseqConfig from hydra.core.global_hydra import GlobalHydra from hydra.experimental import compose, initialize -from omegaconf import DictConfig, OmegaConf, open_dict +from omegaconf import DictConfig, OmegaConf, open_dict, _utils logger = logging.getLogger(__name__) @@ -341,6 +341,17 @@ def override_module_args(args: Namespace) -> Tuple[List[str], List[str]]: return overrides, deletes +class omegaconf_no_object_check: + def __init__(self): + self.old_is_primitive = _utils.is_primitive_type + + def __enter__(self): + _utils.is_primitive_type = lambda _: True + + def __exit__(self, type, value, traceback): + _utils.is_primitive_type = self.old_is_primitive + + def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: """Convert a flat argparse.Namespace to a structured DictConfig.""" @@ -370,41 +381,40 @@ def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: # omegaconf version that supports object flags, or when we migrate all existing models from omegaconf import _utils - old_primitive = _utils.is_primitive_type - _utils.is_primitive_type = lambda _: True - - if cfg.task is None and getattr(args, "task", None): - cfg.task = Namespace(**vars(args)) - from fairseq.tasks import TASK_REGISTRY - - _set_legacy_defaults(cfg.task, TASK_REGISTRY[args.task]) - cfg.task._name = args.task - if cfg.model is None and getattr(args, "arch", None): - cfg.model = Namespace(**vars(args)) - from fairseq.models import ARCH_MODEL_REGISTRY - - _set_legacy_defaults(cfg.model, ARCH_MODEL_REGISTRY[args.arch]) - cfg.model._name = args.arch - if cfg.optimizer is None and getattr(args, "optimizer", None): - cfg.optimizer = Namespace(**vars(args)) - from fairseq.optim import OPTIMIZER_REGISTRY - - _set_legacy_defaults(cfg.optimizer, OPTIMIZER_REGISTRY[args.optimizer]) - cfg.optimizer._name = args.optimizer - if cfg.lr_scheduler is None and getattr(args, "lr_scheduler", None): - cfg.lr_scheduler = Namespace(**vars(args)) - from fairseq.optim.lr_scheduler import LR_SCHEDULER_REGISTRY - - _set_legacy_defaults(cfg.lr_scheduler, LR_SCHEDULER_REGISTRY[args.lr_scheduler]) - cfg.lr_scheduler._name = args.lr_scheduler - if cfg.criterion is None and getattr(args, "criterion", None): - cfg.criterion = Namespace(**vars(args)) - from fairseq.criterions import CRITERION_REGISTRY - - _set_legacy_defaults(cfg.criterion, CRITERION_REGISTRY[args.criterion]) - cfg.criterion._name = args.criterion - - _utils.is_primitive_type = old_primitive + with omegaconf_no_object_check(): + if cfg.task is None and getattr(args, "task", None): + cfg.task = Namespace(**vars(args)) + from fairseq.tasks import TASK_REGISTRY + + _set_legacy_defaults(cfg.task, TASK_REGISTRY[args.task]) + cfg.task._name = args.task + if cfg.model is None and getattr(args, "arch", None): + cfg.model = Namespace(**vars(args)) + from fairseq.models import ARCH_MODEL_REGISTRY + + _set_legacy_defaults(cfg.model, ARCH_MODEL_REGISTRY[args.arch]) + cfg.model._name = args.arch + if cfg.optimizer is None and getattr(args, "optimizer", None): + cfg.optimizer = Namespace(**vars(args)) + from fairseq.optim import OPTIMIZER_REGISTRY + + _set_legacy_defaults(cfg.optimizer, OPTIMIZER_REGISTRY[args.optimizer]) + cfg.optimizer._name = args.optimizer + if cfg.lr_scheduler is None and getattr(args, "lr_scheduler", None): + cfg.lr_scheduler = Namespace(**vars(args)) + from fairseq.optim.lr_scheduler import LR_SCHEDULER_REGISTRY + + _set_legacy_defaults( + cfg.lr_scheduler, LR_SCHEDULER_REGISTRY[args.lr_scheduler] + ) + cfg.lr_scheduler._name = args.lr_scheduler + if cfg.criterion is None and getattr(args, "criterion", None): + cfg.criterion = Namespace(**vars(args)) + from fairseq.criterions import CRITERION_REGISTRY + + _set_legacy_defaults(cfg.criterion, CRITERION_REGISTRY[args.criterion]) + cfg.criterion._name = args.criterion + OmegaConf.set_struct(cfg, True) return cfg diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 405d1e613a..04307e8771 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -337,6 +337,8 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): w2v_args = state.get("cfg", None) if w2v_args is None: w2v_args = convert_namespace_to_omegaconf(state["args"]) + w2v_args.criterion = None + w2v_args.lr_scheduler = None cfg.w2v_args = w2v_args else: state = None From cdc1a553eb2af4fac720880aff4ee2566a28ad21 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Thu, 1 Jul 2021 13:11:40 -0700 Subject: [PATCH 389/774] query tgt_dict after loading task_state (#2019) Summary: # Before submitting `self.task.target_dictionary` is queried before `task_state` is loaded (in `self.load_model_ensemble()`). ## What does this PR do? Fix the bug above Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2019 Reviewed By: alexeib Differential Revision: D29523921 Pulled By: wnhsu fbshipit-source-id: 763b504dc1b4899e623eaa5c19972cec9d0a8985 --- examples/speech_recognition/new/infer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_recognition/new/infer.py b/examples/speech_recognition/new/infer.py index 79afbc426d..3fb67151e0 100644 --- a/examples/speech_recognition/new/infer.py +++ b/examples/speech_recognition/new/infer.py @@ -99,11 +99,11 @@ class InferenceProcessor: def __init__(self, cfg: InferConfig) -> None: self.cfg = cfg self.task = tasks.setup_task(cfg.task) - self.tgt_dict = self.task.target_dictionary models, saved_cfg = self.load_model_ensemble() self.models = models self.saved_cfg = saved_cfg + self.tgt_dict = self.task.target_dictionary self.task.load_dataset( self.cfg.dataset.gen_subset, From dd106d9534b22e7db859a6b87ffd7780c38341f8 Mon Sep 17 00:00:00 2001 From: Omry Yadan <omry@fb.com> Date: Tue, 6 Jul 2021 15:06:07 -0700 Subject: [PATCH 390/774] fixes tests/test_train.py to mock checkpoint.save_dir config node (#3675) Summary: ## What does this PR do? Some downstream users reported that errors when passing Namespace to load_checkpoint(). A recent change made the assumption that the passed object is dict like (dict or DictConfig) that have a get function. This changes that and make sure the mocked config have checkpoint.save_dir to allow the test to run. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3675 Reviewed By: omry Differential Revision: D29564805 Pulled By: lematt1991 fbshipit-source-id: 89308811da382667f6c5d3152ee2d6480416ee62 --- fairseq/checkpoint_utils.py | 2 +- tests/test_train.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index d22d987020..627f14160d 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -203,7 +203,7 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): cfg.restore_file == "checkpoint_last.pt" ): # default value of restore_file is 'checkpoint_last.pt' checkpoint_path = os.path.join( - cfg.get("save_dir"), "checkpoint_last{}.pt".format(suffix) + cfg.save_dir, "checkpoint_last{}.pt".format(suffix) ) first_launch = not PathManager.exists(checkpoint_path) if cfg.finetune_from_model is not None and first_launch: diff --git a/tests/test_train.py b/tests/test_train.py index 65f4683bc6..02ef94cc5b 100644 --- a/tests/test_train.py +++ b/tests/test_train.py @@ -61,6 +61,7 @@ def get_mock_cfg(finetune_from_model): cfg_mock = OmegaConf.create( { "checkpoint": { + "save_dir": None, "optimizer_overrides": "{}", "reset_dataloader": False, "reset_meters": False, From 01576be513488601e936df67e65e2817d18f576e Mon Sep 17 00:00:00 2001 From: Henry Hu <henryhu6@fb.com> Date: Wed, 7 Jul 2021 15:41:37 -0700 Subject: [PATCH 391/774] Add tracing annotations Summary: Add profile record function at several locations in decoderlib and fariseq to annotate tracing. Most of the code changes are due to indentation and auto format. Reviewed By: mikekgfb Differential Revision: D29531358 fbshipit-source-id: 59934079c0ddc75b5b97922f585f4863680f1041 --- fairseq/sequence_generator.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 8a3858563e..ac04dc7db8 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -250,7 +250,8 @@ def _generate( self.min_len <= max_len ), "min_len cannot be larger than max_len, please adjust these!" # compute the encoder output for each beam - encoder_outs = self.model.forward_encoder(net_input) + with torch.autograd.profiler.record_function("EnsembleModel: forward_encoder"): + encoder_outs = self.model.forward_encoder(net_input) # placeholder of indices for bsz * beam_size to hold tokens and accumulative scores new_order = torch.arange(bsz).view(-1, 1).repeat(1, beam_size).view(-1) @@ -327,13 +328,13 @@ def _generate( encoder_outs = self.model.reorder_encoder_out( encoder_outs, reorder_state ) - - lprobs, avg_attn_scores = self.model.forward_decoder( - tokens[:, : step + 1], - encoder_outs, - incremental_states, - self.temperature, - ) + with torch.autograd.profiler.record_function("EnsembleModel: forward_decoder"): + lprobs, avg_attn_scores = self.model.forward_decoder( + tokens[:, : step + 1], + encoder_outs, + incremental_states, + self.temperature, + ) if self.lm_model is not None: lm_out = self.lm_model(tokens[:, : step + 1]) From 7b710acc9e0106e0359b809f285efc45be6fbfd1 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 8 Jul 2021 15:14:45 -0700 Subject: [PATCH 392/774] Fix static container (#2036) Summary: fixes StatefulContainer being static which is a problem when you load a checkpoint with task that already has the same keys in the container also print full path to checkpoints when saving (useful with hydra) and crash if repeatedly failing to save a checkpoint Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2036 Reviewed By: arbabu123 Differential Revision: D29608430 Pulled By: alexeib fbshipit-source-id: 1b65c8f839e02de9110af3ec53f1e7d48a4908f7 --- fairseq/checkpoint_utils.py | 12 ++++++++---- fairseq/tasks/fairseq_task.py | 11 ++++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 627f14160d..8ec967397f 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -92,8 +92,9 @@ def is_better(a, b): # add random digits to resolve ties rand_sfx = randint(0, cfg.keep_best_checkpoints) checkpoint_conds[ - "checkpoint.best_{}_{:.3f}{}.pt".format(cfg.best_checkpoint_metric, - val_loss, rand_sfx) + "checkpoint.best_{}_{:.3f}{}.pt".format( + cfg.best_checkpoint_metric, val_loss, rand_sfx + ) ] = worst_best is None or is_better(val_loss, worst_best) checkpoint_conds[ "checkpoint_last{}.pt".format(suffix) @@ -104,7 +105,7 @@ def is_better(a, b): extra_state.update({"best": save_checkpoint.best}) checkpoints = [ - os.path.join(cfg.save_dir, fn) for fn, cond in checkpoint_conds.items() if cond + os.path.abspath(os.path.join(cfg.save_dir, fn)) for fn, cond in checkpoint_conds.items() if cond ] if len(checkpoints) > 0: trainer.save_checkpoint(checkpoints[0], extra_state) @@ -452,7 +453,9 @@ def load_model_ensemble_and_task( state = None if shard_idx % 10 == 0 and shard_idx > 0: elapsed = time.time() - st - logger.info(f"Loaded {shard_idx} shards in {elapsed:.2f}s, {elapsed / (shard_idx+1):.2f}s/shard") + logger.info( + f"Loaded {shard_idx} shards in {elapsed:.2f}s, {elapsed / (shard_idx+1):.2f}s/shard" + ) # build model for ensemble ensemble.append(model) @@ -508,6 +511,7 @@ def _torch_persistent_save(obj, f): except Exception: if i == 2: logger.error(traceback.format_exc()) + raise def _upgrade_state_dict(state): diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 99bf2c3fe9..8148c77fe1 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -23,8 +23,9 @@ class StatefulContainer(object): - _state: Dict[str, Any] = dict() - _factories: Dict[str, Callable[[], Any]] = dict() + def __init__(self): + self._state = dict() + self._factories = dict() def add_factory(self, name, factory: Callable[[], Any]): self._factories[name] = factory @@ -78,11 +79,6 @@ def logging_outputs_can_be_summed(criterion) -> bool: """ return criterion.logging_outputs_can_be_summed() - cfg: FairseqDataclass - datasets: Dict[str, FairseqDataset] - dataset_to_epoch_iter: Dict[FairseqDataset, Any] - state: StatefulContainer = None - def __init__(self, cfg: FairseqDataclass, **kwargs): self.cfg = cfg self.datasets = dict() @@ -622,6 +618,7 @@ def get_interactive_tokens_and_lengths(self, lines, encode_fn): class LegacyFairseqTask(FairseqTask): def __init__(self, args: Namespace): + super().__init__(None) self.args = args self.datasets = {} self.dataset_to_epoch_iter = {} From 58201a15cceccd9b8f8c6463d7338e4252963b33 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 8 Jul 2021 16:56:58 -0700 Subject: [PATCH 393/774] migrate roberta glue finetuning to hydra (#2035) Summary: this allows roberta finetuning on different tasks using yaml config files + hydra entry point Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2035 Reviewed By: Mortimerp9 Differential Revision: D29601732 Pulled By: alexeib fbshipit-source-id: 774ef974b4b40ad0ced76874c62047d0c46520e7 --- examples/roberta/README.glue.md | 45 +---- examples/roberta/config/finetuning/cola.yaml | 56 ++++++ examples/roberta/config/finetuning/mnli.yaml | 56 ++++++ examples/roberta/config/finetuning/mrpc.yaml | 56 ++++++ examples/roberta/config/finetuning/qnli.yaml | 56 ++++++ examples/roberta/config/finetuning/qqp.yaml | 56 ++++++ examples/roberta/config/finetuning/rte.yaml | 56 ++++++ examples/roberta/config/finetuning/sst_2.yaml | 56 ++++++ examples/roberta/config/finetuning/sts_b.yaml | 56 ++++++ .../rxf/rxf_src/sentence_prediction_r3f.py | 1 + fairseq/criterions/sentence_prediction.py | 29 +-- fairseq/models/roberta/model.py | 91 +++++---- fairseq/tasks/__init__.py | 2 +- fairseq/tasks/sentence_prediction.py | 180 +++++++++--------- 14 files changed, 617 insertions(+), 179 deletions(-) create mode 100644 examples/roberta/config/finetuning/cola.yaml create mode 100644 examples/roberta/config/finetuning/mnli.yaml create mode 100644 examples/roberta/config/finetuning/mrpc.yaml create mode 100644 examples/roberta/config/finetuning/qnli.yaml create mode 100644 examples/roberta/config/finetuning/qqp.yaml create mode 100644 examples/roberta/config/finetuning/rte.yaml create mode 100644 examples/roberta/config/finetuning/sst_2.yaml create mode 100644 examples/roberta/config/finetuning/sts_b.yaml diff --git a/examples/roberta/README.glue.md b/examples/roberta/README.glue.md index 77015d2e2f..4f596d55af 100644 --- a/examples/roberta/README.glue.md +++ b/examples/roberta/README.glue.md @@ -17,54 +17,19 @@ Use `ALL` for preprocessing all the glue tasks. ### 3) Fine-tuning on GLUE task: Example fine-tuning cmd for `RTE` task ```bash -TOTAL_NUM_UPDATES=2036 # 10 epochs through RTE for bsz 16 -WARMUP_UPDATES=122 # 6 percent of the number of updates -LR=2e-05 # Peak LR for polynomial LR scheduler. -NUM_CLASSES=2 -MAX_SENTENCES=16 # Batch size. ROBERTA_PATH=/path/to/roberta/model.pt -CUDA_VISIBLE_DEVICES=0 fairseq-train RTE-bin/ \ - --restore-file $ROBERTA_PATH \ - --max-positions 512 \ - --batch-size $MAX_SENTENCES \ - --max-tokens 4400 \ - --task sentence_prediction \ - --reset-optimizer --reset-dataloader --reset-meters \ - --required-batch-size-multiple 1 \ - --init-token 0 --separator-token 2 \ - --arch roberta_large \ - --criterion sentence_prediction \ - --num-classes $NUM_CLASSES \ - --dropout 0.1 --attention-dropout 0.1 \ - --weight-decay 0.1 --optimizer adam --adam-betas "(0.9, 0.98)" --adam-eps 1e-06 \ - --clip-norm 0.0 \ - --lr-scheduler polynomial_decay --lr $LR --total-num-update $TOTAL_NUM_UPDATES --warmup-updates $WARMUP_UPDATES \ - --fp16 --fp16-init-scale 4 --threshold-loss-scale 1 --fp16-scale-window 128 \ - --max-epoch 10 \ - --find-unused-parameters \ - --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric; +CUDA_VISIBLE_DEVICES=0 fairseq-hydra-train -config-dir examples/roberta/config/finetuning --config-name rte \ +task.data=RTE-bin checkpoint.restore_file=$ROBERTA_PATH ``` -For each of the GLUE task, you will need to use following cmd-line arguments: - -Model | MNLI | QNLI | QQP | RTE | SST-2 | MRPC | CoLA | STS-B ----|---|---|---|---|---|---|---|--- -`--num-classes` | 3 | 2 | 2 | 2 | 2 | 2 | 2 | 1 -`--lr` | 1e-5 | 1e-5 | 1e-5 | 2e-5 | 1e-5 | 1e-5 | 1e-5 | 2e-5 -`--batch-size` | 32 | 32 | 32 | 16 | 32 | 16 | 16 | 16 -`--total-num-update` | 123873 | 33112 | 113272 | 2036 | 20935 | 2296 | 5336 | 3598 -`--warmup-updates` | 7432 | 1986 | 28318 | 122 | 1256 | 137 | 320 | 214 - -For `STS-B` additionally add `--regression-target --best-checkpoint-metric loss` and remove `--maximize-best-checkpoint-metric`. +There are additional config files for each of the GLUE tasks in the examples/roberta/config/finetuning directory. **Note:** -a) `--total-num-updates` is used by `--polynomial_decay` scheduler and is calculated for `--max-epoch=10` and `--batch-size=16/32` depending on the task. - -b) Above cmd-args and hyperparams are tested on one Nvidia `V100` GPU with `32gb` of memory for each task. Depending on the GPU memory resources available to you, you can use increase `--update-freq` and reduce `--batch-size`. +a) Above cmd-args and hyperparams are tested on one Nvidia `V100` GPU with `32gb` of memory for each task. Depending on the GPU memory resources available to you, you can use increase `--update-freq` and reduce `--batch-size`. -c) All the settings in above table are suggested settings based on our hyperparam search within a fixed search space (for careful comparison across models). You might be able to find better metrics with wider hyperparam search. +b) All the settings in above table are suggested settings based on our hyperparam search within a fixed search space (for careful comparison across models). You might be able to find better metrics with wider hyperparam search. ### Inference on GLUE task After training the model as mentioned in previous step, you can perform inference with checkpoints in `checkpoints/` directory using following python code snippet: diff --git a/examples/roberta/config/finetuning/cola.yaml b/examples/roberta/config/finetuning/cola.yaml new file mode 100644 index 0000000000..717069d407 --- /dev/null +++ b/examples/roberta/config/finetuning/cola.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 320 + +optimization: + clip_norm: 0.0 + lr: [1e-05] + max_update: 5336 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/mnli.yaml b/examples/roberta/config/finetuning/mnli.yaml new file mode 100644 index 0000000000..4bfc02bed9 --- /dev/null +++ b/examples/roberta/config/finetuning/mnli.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 3 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 7432 + +optimization: + clip_norm: 0.0 + lr: [1e-05] + max_update: 123873 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/mrpc.yaml b/examples/roberta/config/finetuning/mrpc.yaml new file mode 100644 index 0000000000..907b4639c1 --- /dev/null +++ b/examples/roberta/config/finetuning/mrpc.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 137 + +optimization: + clip_norm: 0.0 + lr: [1e-05] + max_update: 2296 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/qnli.yaml b/examples/roberta/config/finetuning/qnli.yaml new file mode 100644 index 0000000000..00aea91e56 --- /dev/null +++ b/examples/roberta/config/finetuning/qnli.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 1986 + +optimization: + clip_norm: 0.0 + lr: [1e-05] + max_update: 33112 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/qqp.yaml b/examples/roberta/config/finetuning/qqp.yaml new file mode 100644 index 0000000000..dc0296d26e --- /dev/null +++ b/examples/roberta/config/finetuning/qqp.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 28318 + +optimization: + clip_norm: 0.0 + lr: [1e-05] + max_update: 113272 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/rte.yaml b/examples/roberta/config/finetuning/rte.yaml new file mode 100644 index 0000000000..40dfd76169 --- /dev/null +++ b/examples/roberta/config/finetuning/rte.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 122 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 2036 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/sst_2.yaml b/examples/roberta/config/finetuning/sst_2.yaml new file mode 100644 index 0000000000..b808a850cb --- /dev/null +++ b/examples/roberta/config/finetuning/sst_2.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 1256 + +optimization: + clip_norm: 0.0 + lr: [1e-05] + max_update: 20935 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/sts_b.yaml b/examples/roberta/config/finetuning/sts_b.yaml new file mode 100644 index 0000000000..d354bb97dd --- /dev/null +++ b/examples/roberta/config/finetuning/sts_b.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 1 + max_positions: 512 + +checkpoint: + restore_file: ??? + reset_optimizer: true + reset_dataloader: true + reset_meters: true + best_checkpoint_metric: accuracy + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + +criterion: + _name: sentence_prediction + regression_target: true + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 214 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 3598 + max_epoch: 10 + +model: + _name: roberta_large + dropout: 0.1 + attention_dropout: 0.1 diff --git a/examples/rxf/rxf_src/sentence_prediction_r3f.py b/examples/rxf/rxf_src/sentence_prediction_r3f.py index 62dd63390c..6ecffd6b14 100644 --- a/examples/rxf/rxf_src/sentence_prediction_r3f.py +++ b/examples/rxf/rxf_src/sentence_prediction_r3f.py @@ -52,6 +52,7 @@ def add_args(parser): parser.add_argument('--classification-head-name', default='sentence_classification_head', help='name of the classification head to use') + parser.add_argument('--regression-target', action='store_true') # fmt: on def _get_symm_kl(self, noised_logits, input_logits): diff --git a/fairseq/criterions/sentence_prediction.py b/fairseq/criterions/sentence_prediction.py index 9519fdc56d..482b97985a 100644 --- a/fairseq/criterions/sentence_prediction.py +++ b/fairseq/criterions/sentence_prediction.py @@ -4,27 +4,32 @@ # LICENSE file in the root directory of this source tree. import math +from dataclasses import dataclass, field import torch import torch.nn.functional as F from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass -@register_criterion("sentence_prediction") +@dataclass +class SentencePredictionConfig(FairseqDataclass): + classification_head_name: str = field( + default="sentence_classification_head", + metadata={"help": "name of the classification head to use"}, + ) + regression_target: bool = field( + default=False, + ) + + +@register_criterion("sentence_prediction", dataclass=SentencePredictionConfig) class SentencePredictionCriterion(FairseqCriterion): - def __init__(self, task, classification_head_name, regression_target): + def __init__(self, cfg: SentencePredictionConfig, task): super().__init__(task) - self.classification_head_name = classification_head_name - self.regression_target = regression_target - - @staticmethod - def add_args(parser): - # fmt: off - parser.add_argument('--classification-head-name', - default='sentence_classification_head', - help='name of the classification head to use') - # fmt: on + self.classification_head_name = cfg.classification_head_name + self.regression_target = cfg.regression_target def forward(self, model, sample, reduce=True): """Compute the loss for the given sample. diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index d9d0f324cf..39a1cdd951 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -189,13 +189,24 @@ def add_args(parser): def build_model(cls, args, task): """Build a new model instance.""" + from omegaconf import OmegaConf + + if OmegaConf.is_config(args): + OmegaConf.set_struct(args, False) + # make sure all arguments are present base_architecture(args) if not hasattr(args, "max_positions"): + if not hasattr(args, "tokens_per_sample"): + args.tokens_per_sample = task.max_positions() args.max_positions = args.tokens_per_sample encoder = RobertaEncoder(args, task.source_dictionary) + + if OmegaConf.is_config(args): + OmegaConf.set_struct(args, True) + return cls(args, encoder) def forward( @@ -508,54 +519,62 @@ def max_positions(self): return self.args.max_positions +def safe_getattr(obj, k, default=None): + from omegaconf import OmegaConf + + if OmegaConf.is_config(obj): + return obj.k if k in obj and obj.k is not None else default + + return getattr(obj, k, default) + @register_model_architecture("roberta", "roberta") def base_architecture(args): - args.encoder_layers = getattr(args, "encoder_layers", 12) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 3072) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) - - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_dropout = getattr(args, "activation_dropout", 0.0) - args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) - - args.max_source_positions = getattr(args, "max_positions", 512) - args.no_token_positional_embeddings = getattr( + args.encoder_layers = safe_getattr(args, "encoder_layers", 12) + args.encoder_embed_dim = safe_getattr(args, "encoder_embed_dim", 768) + args.encoder_ffn_embed_dim = safe_getattr(args, "encoder_ffn_embed_dim", 3072) + args.encoder_attention_heads = safe_getattr(args, "encoder_attention_heads", 12) + + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.activation_dropout = safe_getattr(args, "activation_dropout", 0.0) + args.pooler_dropout = safe_getattr(args, "pooler_dropout", 0.0) + + args.max_source_positions = safe_getattr(args, "max_positions", 512) + args.no_token_positional_embeddings = safe_getattr( args, "no_token_positional_embeddings", False ) # BERT has a few structural differences compared to the original Transformer - args.encoder_learned_pos = getattr(args, "encoder_learned_pos", True) - args.layernorm_embedding = getattr(args, "layernorm_embedding", True) - args.no_scale_embedding = getattr(args, "no_scale_embedding", True) - args.activation_fn = getattr(args, "activation_fn", "gelu") - args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) - args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") - args.untie_weights_roberta = getattr(args, "untie_weights_roberta", False) + args.encoder_learned_pos = safe_getattr(args, "encoder_learned_pos", True) + args.layernorm_embedding = safe_getattr(args, "layernorm_embedding", True) + args.no_scale_embedding = safe_getattr(args, "no_scale_embedding", True) + args.activation_fn = safe_getattr(args, "activation_fn", "gelu") + args.encoder_normalize_before = safe_getattr(args, "encoder_normalize_before", False) + args.pooler_activation_fn = safe_getattr(args, "pooler_activation_fn", "tanh") + args.untie_weights_roberta = safe_getattr(args, "untie_weights_roberta", False) # Adaptive input config - args.adaptive_input = getattr(args, "adaptive_input", False) + args.adaptive_input = safe_getattr(args, "adaptive_input", False) # LayerDrop config - args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.0) - args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) + args.encoder_layerdrop = safe_getattr(args, "encoder_layerdrop", 0.0) + args.encoder_layers_to_keep = safe_getattr(args, "encoder_layers_to_keep", None) # Quantization noise config - args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) - args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8) - args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0) + args.quant_noise_pq = safe_getattr(args, "quant_noise_pq", 0) + args.quant_noise_pq_block_size = safe_getattr(args, "quant_noise_pq_block_size", 8) + args.quant_noise_scalar = safe_getattr(args, "quant_noise_scalar", 0) # R4F config - args.spectral_norm_classification_head = getattr( + args.spectral_norm_classification_head = safe_getattr( args, "spectral_norm_classification_head", False ) @register_model_architecture("roberta", "roberta_prenorm") def roberta_prenorm_architecture(args): - args.layernorm_embedding = getattr(args, "layernorm_embedding", False) - args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) + args.layernorm_embedding = safe_getattr(args, "layernorm_embedding", False) + args.encoder_normalize_before = safe_getattr(args, "encoder_normalize_before", True) base_architecture(args) @@ -566,17 +585,17 @@ def roberta_base_architecture(args): @register_model_architecture("roberta", "roberta_large") def roberta_large_architecture(args): - args.encoder_layers = getattr(args, "encoder_layers", 24) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.encoder_layers = safe_getattr(args, "encoder_layers", 24) + args.encoder_embed_dim = safe_getattr(args, "encoder_embed_dim", 1024) + args.encoder_ffn_embed_dim = safe_getattr(args, "encoder_ffn_embed_dim", 4096) + args.encoder_attention_heads = safe_getattr(args, "encoder_attention_heads", 16) base_architecture(args) @register_model_architecture("roberta", "xlm") def xlm_architecture(args): - args.encoder_layers = getattr(args, "encoder_layers", 16) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1280) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 1280 * 4) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.encoder_layers = safe_getattr(args, "encoder_layers", 16) + args.encoder_embed_dim = safe_getattr(args, "encoder_embed_dim", 1280) + args.encoder_ffn_embed_dim = safe_getattr(args, "encoder_ffn_embed_dim", 1280 * 4) + args.encoder_attention_heads = safe_getattr(args, "encoder_attention_heads", 16) base_architecture(args) diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 79dde74057..28305aa247 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -41,7 +41,7 @@ def setup_task(cfg: FairseqDataclass, **kwargs): assert ( task is not None - ), f"Could not infer task type from {cfg}. Available tasks: {TASK_REGISTRY.keys()}" + ), f"Could not infer task type from {cfg}. Available argparse tasks: {TASK_REGISTRY.keys()}. Available hydra tasks: {TASK_DATACLASS_REGISTRY.keys()}" return task.setup_task(cfg, **kwargs) diff --git a/fairseq/tasks/sentence_prediction.py b/fairseq/tasks/sentence_prediction.py index 6732728de9..d5f9302c10 100644 --- a/fairseq/tasks/sentence_prediction.py +++ b/fairseq/tasks/sentence_prediction.py @@ -6,8 +6,12 @@ import logging import os +import contextlib +from dataclasses import dataclass, field +from typing import Optional +from omegaconf import MISSING, II, open_dict, OmegaConf + import numpy as np -from fairseq import utils from fairseq.data import ( ConcatSentencesDataset, Dictionary, @@ -25,14 +29,63 @@ data_utils, ) from fairseq.data.shorten_dataset import maybe_shorten_dataset -from fairseq.tasks import LegacyFairseqTask, register_task +from fairseq.tasks import FairseqDataclass, FairseqTask, register_task +from fairseq.dataclass import ChoiceEnum logger = logging.getLogger(__name__) - - -@register_task("sentence_prediction") -class SentencePredictionTask(LegacyFairseqTask): +SHORTEN_METHOD_CHOICES = ChoiceEnum(["none", "truncate", "random_crop"]) + + +@dataclass +class SentencePredictionConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) + num_classes: int = field( + default=-1, + metadata={"help": "number of classes or regression targets"}, + ) + init_token: Optional[int] = field( + default=None, + metadata={"help": "add token at the beginning of each batch item"}, + ) + separator_token: Optional[int] = field( + default=None, + metadata={"help": "add separator token between inputs"}, + ) + no_shuffle: bool = field( + default=False, + ) + shorten_method: SHORTEN_METHOD_CHOICES = field( + default="none", + metadata={ + "help": "if not none, shorten sequences that exceed tokens_per_sample" + }, + ) + shorten_data_split_list: str = field( + default="", + metadata={ + "help": "comma-separated list of dataset splits to apply shortening to, " + 'e.g., "train,valid" (default: all dataset splits)' + }, + ) + add_prev_output_tokens: bool = field( + default=False, + metadata={ + "help": "add prev_output_tokens to sample, used for encoder-decoder arch" + }, + ) + max_positions: int = field( + default=512, + metadata={"help": "max tokens per example"}, + ) + + regression_target: bool = II("criterion.regression_target") + classification_head_name: str = II("criterion.classification_head_name") + seed: int = II("common.seed") + + +@register_task("sentence_prediction", dataclass=SentencePredictionConfig) +class SentencePredictionTask(FairseqTask): """ Sentence (or sentence pair) prediction (classification or regression) task. @@ -40,64 +93,13 @@ class SentencePredictionTask(LegacyFairseqTask): dictionary (Dictionary): the dictionary for the input of the task """ - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - parser.add_argument("data", metavar="FILE", help="file prefix for data") - parser.add_argument( - "--num-classes", - type=int, - default=-1, - help="number of classes or regression targets", - ) - parser.add_argument( - "--init-token", - type=int, - default=None, - help="add token at the beginning of each batch item", - ) - parser.add_argument( - "--separator-token", - type=int, - default=None, - help="add separator token between inputs", - ) - parser.add_argument("--regression-target", action="store_true", default=False) - parser.add_argument("--no-shuffle", action="store_true", default=False) - parser.add_argument( - "--shorten-method", - default="none", - choices=["none", "truncate", "random_crop"], - help="if not none, shorten sequences that exceed --tokens-per-sample", - ) - parser.add_argument( - "--shorten-data-split-list", - default="", - help="comma-separated list of dataset splits to apply shortening to, " - 'e.g., "train,valid" (default: all dataset splits)', - ) - parser.add_argument( - "--add-prev-output-tokens", - action="store_true", - default=False, - help="add prev_output_tokens to sample, used for encoder-decoder arch", - ) - - def __init__(self, args, data_dictionary, label_dictionary): - super().__init__(args) + def __init__(self, cfg, data_dictionary, label_dictionary): + super().__init__(cfg) self.dictionary = data_dictionary self._label_dictionary = label_dictionary - if not hasattr(args, "max_positions"): - self._max_positions = ( - args.max_source_positions, - args.max_target_positions, - ) - else: - self._max_positions = args.max_positions - args.tokens_per_sample = self._max_positions @classmethod - def load_dictionary(cls, args, filename, source=True): + def load_dictionary(cls, filename): """Load the dictionary from the filename Args: @@ -108,34 +110,30 @@ def load_dictionary(cls, args, filename, source=True): return dictionary @classmethod - def setup_task(cls, args, **kwargs): - assert args.num_classes > 0, "Must set --num-classes" + def setup_task(cls, cfg, **kwargs): + assert cfg.num_classes > 0, "Must set task.num_classes" # load data dictionary data_dict = cls.load_dictionary( - args, - os.path.join(args.data, "input0", "dict.txt"), - source=True, + os.path.join(cfg.data, "input0", "dict.txt"), ) logger.info("[input] dictionary: {} types".format(len(data_dict))) # load label dictionary - if not args.regression_target: + if not cfg.regression_target: label_dict = cls.load_dictionary( - args, - os.path.join(args.data, "label", "dict.txt"), - source=False, + os.path.join(cfg.data, "label", "dict.txt"), ) logger.info("[label] dictionary: {} types".format(len(label_dict))) else: label_dict = data_dict - return cls(args, data_dict, label_dict) + return cls(cfg, data_dict, label_dict) def load_dataset(self, split, combine=False, **kwargs): """Load a given dataset split (e.g., train, valid, test).""" def get_path(key, split): - return os.path.join(self.args.data, key, split) + return os.path.join(self.cfg.data, key, split) def make_dataset(key, dictionary): split_path = get_path(key, split) @@ -144,7 +142,6 @@ def make_dataset(key, dictionary): dataset = data_utils.load_indexed_dataset( split_path, dictionary, - self.args.dataset_impl, combine=combine, ) except Exception as e: @@ -161,27 +158,27 @@ def make_dataset(key, dictionary): ) input1 = make_dataset("input1", self.source_dictionary) - if self.args.init_token is not None: - input0 = PrependTokenDataset(input0, self.args.init_token) + if self.cfg.init_token is not None: + input0 = PrependTokenDataset(input0, self.cfg.init_token) if input1 is None: src_tokens = input0 else: - if self.args.separator_token is not None: - input1 = PrependTokenDataset(input1, self.args.separator_token) + if self.cfg.separator_token is not None: + input1 = PrependTokenDataset(input1, self.cfg.separator_token) src_tokens = ConcatSentencesDataset(input0, input1) - with data_utils.numpy_seed(self.args.seed): + with data_utils.numpy_seed(self.cfg.seed): shuffle = np.random.permutation(len(src_tokens)) src_tokens = maybe_shorten_dataset( src_tokens, split, - self.args.shorten_data_split_list, - self.args.shorten_method, + self.cfg.shorten_data_split_list, + self.cfg.shorten_method, self.max_positions(), - self.args.seed, + self.cfg.seed, ) dataset = { @@ -197,7 +194,7 @@ def make_dataset(key, dictionary): "ntokens": NumelDataset(src_tokens, reduce=True), } - if self.args.add_prev_output_tokens: + if self.cfg.add_prev_output_tokens: prev_tokens_dataset = RightPadDataset( RollDataset(src_tokens, 1), pad_idx=self.dictionary.pad(), @@ -206,7 +203,7 @@ def make_dataset(key, dictionary): prev_output_tokens=prev_tokens_dataset, ) - if not self.args.regression_target: + if not self.cfg.regression_target: label_dataset = make_dataset("label", self.label_dictionary) if label_dataset is not None: dataset.update( @@ -225,8 +222,8 @@ def make_dataset(key, dictionary): def parse_regression_target(i, line): values = line.split() assert ( - len(values) == self.args.num_classes - ), f'expected num_classes={self.args.num_classes} regression target values on line {i}, found: "{line}"' + len(values) == self.cfg.num_classes + ), f'expected num_classes={self.cfg.num_classes} regression target values on line {i}, found: "{line}"' return [float(x) for x in values] with open(label_path) as h: @@ -244,7 +241,7 @@ def parse_regression_target(i, line): sizes=[src_tokens.sizes], ) - if self.args.no_shuffle: + if self.cfg.no_shuffle: dataset = nested_dataset else: dataset = SortDataset( @@ -258,20 +255,23 @@ def parse_regression_target(i, line): self.datasets[split] = dataset return self.datasets[split] - def build_model(self, args): + def build_model(self, cfg): from fairseq import models - model = models.build_model(args, self) + with open_dict(cfg) if OmegaConf.is_config(cfg) else contextlib.ExitStack(): + cfg.max_positions = self.cfg.max_positions + + model = models.build_model(cfg, self) model.register_classification_head( - getattr(args, "classification_head_name", "sentence_classification_head"), - num_classes=self.args.num_classes, + self.cfg.classification_head_name, + num_classes=self.cfg.num_classes, ) return model def max_positions(self): - return self._max_positions + return self.cfg.max_positions @property def source_dictionary(self): From 605e1ceaa8be442726b0df9351dd28b979761d6e Mon Sep 17 00:00:00 2001 From: Pierce Chuang <pichuang@fb.com> Date: Thu, 8 Jul 2021 17:07:51 -0700 Subject: [PATCH 394/774] change denoising setup_task so that it can read from multiple shards Summary: Follow Roberta data handling to support | based data separation Reviewed By: myleott Differential Revision: D29619263 fbshipit-source-id: 6912df178965c1b0f859604c8f5ad8aff443198a --- fairseq/tasks/denoising.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fairseq/tasks/denoising.py b/fairseq/tasks/denoising.py index cbf01e14df..d1dff26c36 100644 --- a/fairseq/tasks/denoising.py +++ b/fairseq/tasks/denoising.py @@ -147,7 +147,9 @@ def __init__(self, args, dictionary): @classmethod def setup_task(cls, args, **kwargs): """Setup the task.""" - dictionary = Dictionary.load(os.path.join(args.data, "dict.txt")) + paths = utils.split_paths(args.data) + assert len(paths) > 0 + dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) logger.info("dictionary: {} types".format(len(dictionary))) if not hasattr(args, "shuffle_instance"): args.shuffle_instance = False @@ -196,6 +198,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): break_mode=self.args.sample_break_mode, document_sep_len=0, ) + logger.info("loaded {} blocks from: {}".format(len(dataset), split_path)) # prepend beginning-of-sentence token (<s>, equiv. to [CLS] in BERT) dataset = PrependTokenDataset(dataset, self.source_dictionary.bos()) From d18e44a28994a1558e9f8dc988a23bd6f77a55d5 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 8 Jul 2021 19:09:58 -0700 Subject: [PATCH 395/774] add robust w2v model (#2046) Summary: add robust wav2vec model Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2046 Reviewed By: wnhsu Differential Revision: D29628639 Pulled By: alexeib fbshipit-source-id: 296cd2da579a969a71a0f9ffe1062002b73a8d86 --- README.md | 3 +++ examples/wav2vec/README.md | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82b6ba7cd8..147714bae5 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ We provide reference implementations of various sequence modeling papers: + [Linformer: Self-Attention with Linear Complexity (Wang et al., 2020)](examples/linformer/README.md) + [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) + [Deep Transformers with Latent Depth (Li et al., 2020)](examples/latent_depth/README.md) + + [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979) + + [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027) * **Non-autoregressive Transformers** + Non-Autoregressive Neural Machine Translation (Gu et al., 2017) + Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement (Lee et al. 2018) @@ -61,6 +63,7 @@ We provide reference implementations of various sequence modeling papers: ### What's New: +* July 2021 [Released Robust wav2vec 2.0 model](examples/wav2vec/README.md) * June 2021 [Released XLMR-XL and XLMR-XXL models](examples/xlmr/README.md) * March 2021 [Added full parameter and optimizer state sharding + CPU offloading](examples/fully_sharded_data_parallel/README.md) * February 2021 [Added LASER training code](examples/laser/README.md) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 238639a9ba..c543b6b97b 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -6,6 +6,8 @@ We learned speech representations in multiple languages as well in [Unsupervised We also combined wav2vec 2.0 with self-training in [Self-training and Pre-training are Complementary for Speech Recognition (Xu et al., 2020)](https://arxiv.org/abs/2010.11430). +We combined speech data from multiple domains in [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027) + ## Pre-trained models Model | Finetuning split | Dataset | Model @@ -25,8 +27,10 @@ Wav2Vec 2.0 Large (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebo Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) +Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv.pt) -\* updated (Oct. 24, 2020) +\* updated (Oct. 24, 2020)\ +** updated (Jul. 8, 2021) We also release multilingual pre-trained wav2vec 2.0 (XLSR) models: From cffc057b58d9d4b36260d30861f86b2ab8817ac1 Mon Sep 17 00:00:00 2001 From: Wei Ho <weiho@fb.com> Date: Fri, 9 Jul 2021 16:13:51 -0700 Subject: [PATCH 396/774] Roll back os.path.abspath change Reviewed By: donhusa Differential Revision: D29641968 fbshipit-source-id: eca379158055f3e38e9c053b06db56842265e53a --- fairseq/checkpoint_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 8ec967397f..35cce7fda7 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -105,7 +105,7 @@ def is_better(a, b): extra_state.update({"best": save_checkpoint.best}) checkpoints = [ - os.path.abspath(os.path.join(cfg.save_dir, fn)) for fn, cond in checkpoint_conds.items() if cond + os.path.join(cfg.save_dir, fn) for fn, cond in checkpoint_conds.items() if cond ] if len(checkpoints) > 0: trainer.save_checkpoint(checkpoints[0], extra_state) From 7f2fb5caa872ce06f7cc5d95956f4eca2a6211fe Mon Sep 17 00:00:00 2001 From: Ann Lee <an918tw@users.noreply.github.com> Date: Fri, 9 Jul 2021 16:45:40 -0700 Subject: [PATCH 397/774] Release code for the paper "Discriminative Reranking for Neural Machine Translation" (#2044) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Release the code for the paper "Discriminative Reranking for Neural Machine Translation" ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2044 Reviewed By: michaelauli Differential Revision: D29628590 Pulled By: an918tw fbshipit-source-id: 7a52602d495b736573187cc721829aa545d24770 --- README.md | 1 + .../discriminative_reranking_nmt/README.md | 200 ++++++++ .../discriminative_reranking_nmt/__init__.py | 1 + .../config/deen.yaml | 56 +++ .../criterions/__init__.py | 6 + .../discriminative_reranking_criterion.py | 138 +++++ .../drnmt_rerank.py | 364 ++++++++++++++ .../models/__init__.py | 6 + .../models/discriminative_reranking_model.py | 365 ++++++++++++++ .../scripts/prep_data.py | 136 +++++ .../tasks/__init__.py | 6 + .../tasks/discriminative_reranking_task.py | 475 ++++++++++++++++++ 12 files changed, 1754 insertions(+) create mode 100644 examples/discriminative_reranking_nmt/README.md create mode 100644 examples/discriminative_reranking_nmt/__init__.py create mode 100644 examples/discriminative_reranking_nmt/config/deen.yaml create mode 100644 examples/discriminative_reranking_nmt/criterions/__init__.py create mode 100644 examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py create mode 100644 examples/discriminative_reranking_nmt/drnmt_rerank.py create mode 100644 examples/discriminative_reranking_nmt/models/__init__.py create mode 100644 examples/discriminative_reranking_nmt/models/discriminative_reranking_model.py create mode 100755 examples/discriminative_reranking_nmt/scripts/prep_data.py create mode 100644 examples/discriminative_reranking_nmt/tasks/__init__.py create mode 100644 examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py diff --git a/README.md b/README.md index 147714bae5..460f3439fb 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ We provide reference implementations of various sequence modeling papers: ### What's New: +* July 2021 [Released DrNMT code](examples/discriminative_reranking_nmt/README.md) * July 2021 [Released Robust wav2vec 2.0 model](examples/wav2vec/README.md) * June 2021 [Released XLMR-XL and XLMR-XXL models](examples/xlmr/README.md) * March 2021 [Added full parameter and optimizer state sharding + CPU offloading](examples/fully_sharded_data_parallel/README.md) diff --git a/examples/discriminative_reranking_nmt/README.md b/examples/discriminative_reranking_nmt/README.md new file mode 100644 index 0000000000..aba0090370 --- /dev/null +++ b/examples/discriminative_reranking_nmt/README.md @@ -0,0 +1,200 @@ +# Discriminative Reranking for Neural Machine Translation +This folder contains source code for training DrNMT, a discriminatively trained reranker for neural machine translation. + +## Data preparation +1. Follow the instructions under `examples/translation` to build a base MT model. Prepare three files, one with source sentences, one with ground truth target sentences, and one with hypotheses generated from the base MT model. Each line in the file contains one sentence in raw text (i.e. no sentencepiece, etc.). Below is an example of the files with _N_ hypotheses for each source sentence. + +``` +# Example of the source sentence file: (The file should contain L lines.) + +source_sentence_1 +source_sentence_2 +source_sentence_3 +... +source_sentence_L + +# Example of the target sentence file: (The file should contain L lines.) + +target_sentence_1 +target_sentence_2 +target_sentence_3 +... +target_sentence_L + +# Example of the hypotheses file: (The file should contain L*N lines.) + +source_sentence_1_hypo_1 +source_sentence_1_hypo_2 +... +source_sentence_1_hypo_N +source_sentence_2_hypo_1 +... +source_sentence_2_hypo_N +... +source_sentence_L_hypo_1 +... +source_sentence_L_hypo_N +``` + +2. Download the [XLMR model](https://github.com/fairinternal/fairseq-py/tree/master/examples/xlmr#pre-trained-models). +``` +wget https://dl.fbaipublicfiles.com/fairseq/models/xlmr.base.tar.gz +tar zxvf xlmr.base.tar.gz + +# The folder should contain dict.txt, model.pt and sentencepiece.bpe.model. +``` + +3. Prepare scores and BPE data. +* `N`: Number of hypotheses per each source sentence. We use 50 in the paper. +* `SPLIT`: Name of the data split, i.e. train, valid, test. Use split_name, split_name1, split_name2, ..., if there are multiple datasets for a split, e.g. train, train1, valid, valid1. +* `NUM_SHARDS`: Number of shards. Set this to 1 for non-train splits. +* `METRIC`: The metric for DrNMT to optimize for. We support either `bleu` or `ter`. +``` +# For each data split, e.g. train, valid, test, etc., run the following: + +SOURCE_FILE=/path/to/source_sentence_file +TARGET_FILE=/path/to/target_sentence_file +HYPO_FILE=/path/to/hypo_file +XLMR_DIR=/path/to/xlmr +OUTPUT_DIR=/path/to/output + +python scripts/prep_data.py \ + --input-source ${SOURCE_FILE} \ + --input-target ${TARGET_FILE} \ + --input-hypo ${HYPO_FILE} \ + --output-dir ${OUTPUT_DIR} \ + --split $SPLIT + --beam $N \ + --sentencepiece-model ${XLMR_DIR}/sentencepiece.bpe.model \ + --metric $METRIC \ + --num-shards ${NUM_SHARDS} + +# The script will create ${OUTPUT_DIR}/$METRIC with ${NUM_SHARDS} splits. +# Under split*/input_src, split*/input_tgt and split*/$METRIC, there will be $SPLIT.bpe and $SPLIT.$METRIC files, respectively. + +``` + +4. Pre-process the data into fairseq format. +``` +# use comma to separate if there are more than one train or valid set +for suffix in src tgt ; do + fairseq-preprocess --only-source \ + --trainpref ${OUTPUT_DIR}/$METRIC/split1/input_${suffix}/train.bpe \ + --validpref ${OUTPUT_DIR}/$METRIC/split1/input_${suffix}/valid.bpe \ + --destdir ${OUTPUT_DIR}/$METRIC/split1/input_${suffix} \ + --workers 60 \ + --srcdict ${XLMR_DIR}/dict.txt +done + +for i in `seq 2 ${NUM_SHARDS}`; do + for suffix in src tgt ; do + fairseq-preprocess --only-source \ + --trainpref ${OUTPUT_DIR}/$METRIC/split${i}/input_${suffix}/train.bpe \ + --destdir ${OUTPUT_DIR}/$METRIC/split${i}/input_${suffix} \ + --workers 60 \ + --srcdict ${XLMR_DIR}/dict.txt + + ln -s ${OUTPUT_DIR}/$METRIC/split1/input_${suffix}/valid* ${OUTPUT_DIR}/$METRIC/split${i}/input_${suffix}/. + done + + ln -s ${OUTPUT_DIR}/$METRIC/split1/$METRIC/valid* ${OUTPUT_DIR}/$METRIC/split${i}/$METRIC/. +done +``` + +## Training + +``` +EXP_DIR=/path/to/exp + +# An example of training the model with the config for De-En experiment in the paper. +# The config uses 16 GPUs and 50 hypotheses. +# For training with fewer number of GPUs, set +# distributed_training.distributed_world_size=k +optimization.update_freq='[x]' where x = 16/k +# For training with fewer number of hypotheses, set +# task.mt_beam=N dataset.batch_size=N dataset.required_batch_size_multiple=N + +fairseq-hydra-train -m \ + --config-dir config/ --config-name deen \ + task.data=${OUTPUT_DIR}/$METRIC/split1/ \ + task.num_data_splits=${NUM_SHARDS} \ + model.pretrained_model=${XLMR_DIR}/model.pt \ + common.user_dir=${FAIRSEQ_ROOT}/examples/discriminative_reranking_nmt \ + checkpoint.save_dir=${EXP_DIR} + +``` + +## Inference & scoring +Perform DrNMT reranking (fw + reranker score) +1. Tune weights on valid sets. +``` +# genrate N hypotheses with the base MT model (fw score) +VALID_SOURCE_FILE=/path/to/source_sentences # one sentence per line, converted to the sentencepiece used by the base MT model +VALID_TARGET_FILE=/path/to/target_sentences # one sentence per line in raw text, i.e. no sentencepiece and tokenization +MT_MODEL=/path/to/mt_model +MT_DATA_PATH=/path/to/mt_data + +cat ${VALID_SOURCE_FILE} | \ + fairseq-interactive ${MT_DATA_PATH} \ + --max-tokens 4000 --buffer-size 16 \ + --num-workers 32 --path ${MT_MODEL} \ + --beam $N --nbest $N \ + --post-process sentencepiece &> valid-hypo.out + +# replace "bleu" with "ter" to optimize for TER +python drnmt_rerank.py \ + ${OUTPUT_DIR}/$METRIC/split1/ \ + --path ${EXP_DIR}/checkpoint_best.pt \ + --in-text valid-hypo.out \ + --results-path ${EXP_DIR} \ + --gen-subset valid \ + --target-text ${VALID_TARGET_FILE} \ + --user-dir ${FAIRSEQ_ROOT}/examples/discriminative_reranking_nmt \ + --bpe sentencepiece \ + --sentencepiece-model ${XLMR_DIR}/sentencepiece.bpe.model \ + --beam $N \ + --batch-size $N \ + --metric bleu \ + --tune + +``` + +2. Apply best weights on test sets +``` +# genrate N hypotheses with the base MT model (fw score) +TEST_SOURCE_FILE=/path/to/source_sentences # one sentence per line, converted to the sentencepiece used by the base MT model + +cat ${TEST_SOURCE_FILE} | \ + fairseq-interactive ${MT_DATA_PATH} \ + --max-tokens 4000 --buffer-size 16 \ + --num-workers 32 --path ${MT_MODEL} \ + --beam $N --nbest $N \ + --post-process sentencepiece &> test-hypo.out + +# replace "bleu" with "ter" to evaluate TER +# Add --target-text for evaluating BLEU/TER, +# otherwise the script will only generate the hypotheses with the highest scores only. +python drnmt_rerank.py \ + ${OUTPUT_DIR}/$METRIC/split1/ \ + --path ${EXP_DIR}/checkpoint_best.pt \ + --in-text test-hypo.out \ + --results-path ${EXP_DIR} \ + --gen-subset test \ + --user-dir ${FAIRSEQ_ROOT}/examples/discriminative_reranking_nmt \ + --bpe sentencepiece \ + --sentencepiece-model ${XLMR_DIR}/sentencepiece.bpe.model \ + --beam $N \ + --batch-size $N \ + --metric bleu \ + --fw-weight ${BEST_FW_WEIGHT} \ + --lenpen ${BEST_LENPEN} +``` + +## Citation +```bibtex +@inproceedings{lee2021discriminative, + title={Discriminative Reranking for Neural Machine Translation}, + author={Lee, Ann and Auli, Michael and Ranzato, Marc'Aurelio}, + booktitle={ACL}, + year={2021} +} +``` diff --git a/examples/discriminative_reranking_nmt/__init__.py b/examples/discriminative_reranking_nmt/__init__.py new file mode 100644 index 0000000000..0278f6a273 --- /dev/null +++ b/examples/discriminative_reranking_nmt/__init__.py @@ -0,0 +1 @@ +from . import criterions, models, tasks # noqa diff --git a/examples/discriminative_reranking_nmt/config/deen.yaml b/examples/discriminative_reranking_nmt/config/deen.yaml new file mode 100644 index 0000000000..3fc2d5fcf5 --- /dev/null +++ b/examples/discriminative_reranking_nmt/config/deen.yaml @@ -0,0 +1,56 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 50 + seed: 2 + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: bleu + maximize_best_checkpoint_metric: true + +task: + _name: discriminative_reranking_nmt + data: ??? + num_data_splits: ??? + include_src: true + mt_beam: 50 + eval_target_metric: true + target_metric: bleu + +dataset: + batch_size: 50 + num_workers: 6 + required_batch_size_multiple: 50 + valid_subset: ??? + +criterion: + _name: kl_divergence_rereanking + target_dist_norm: minmax + temperature: 0.5 + +optimization: + max_epoch: 200 + lr: [0.00005] + update_freq: [32] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 8000 + total_num_update: 320000 + +model: + _name: discriminative_nmt_reranker + pretrained_model: ??? + classifier_dropout: 0.2 + +distributed_training: + ddp_backend: no_c10d + distributed_world_size: 16 diff --git a/examples/discriminative_reranking_nmt/criterions/__init__.py b/examples/discriminative_reranking_nmt/criterions/__init__.py new file mode 100644 index 0000000000..7c257c2700 --- /dev/null +++ b/examples/discriminative_reranking_nmt/criterions/__init__.py @@ -0,0 +1,6 @@ +from .discriminative_reranking_criterion import KLDivergenceRerankingCriterion + + +__all__ = [ + "KLDivergenceRerankingCriterion", +] diff --git a/examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py b/examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py new file mode 100644 index 0000000000..0b02ce1877 --- /dev/null +++ b/examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py @@ -0,0 +1,138 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from dataclasses import dataclass, field + +import torch +import torch.nn.functional as F + +from fairseq import metrics, utils +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import ChoiceEnum, FairseqDataclass + + +_EPSILON = torch.finfo(torch.float32).eps +TARGET_DIST_NORM_CHOICES = ChoiceEnum(["none", "minmax"]) + + +@dataclass +class KLDivergenceRerankingCriterionConfig(FairseqDataclass): + target_dist_norm: TARGET_DIST_NORM_CHOICES = field( + default="none", + metadata={"help": "method to normalize the range of target scores"}, + ) + temperature: float = field( + default=1.0, + metadata={"help": "temperature in softmax for target distributions"}, + ) + forward_batch_size: int = field( + default=32, + metadata={ + "help": "number of hypotheses per batch for model forward (set a value smaller than --mt-beam to avoid OOM when training with a large beam size)" + }, + ) + + +@register_criterion( + "kl_divergence_rereanking", dataclass=KLDivergenceRerankingCriterionConfig +) +class KLDivergenceRerankingCriterion(FairseqCriterion): + def __init__( + self, task, target_dist_norm, temperature, forward_batch_size, + ): + super().__init__(task) + self.target_dist_norm = target_dist_norm + self.temperature = temperature + self.forward_batch_size = forward_batch_size + + def forward(self, model, sample, reduce=True): + """Compute the loss for the given sample. + + Returns a tuple with three elements: + 1) the loss + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + + sample_size = sample["id"].numel() + assert sample_size % self.task.cfg.mt_beam == 0, ( + f"sample_size ({sample_size}) cannot be divided by beam size ({self.task.cfg.mt_beam})." + f"Please set --required-batch-size-multiple={self.task.cfg.mt_beam}." + ) + + # split into smaller batches for model forward + batch_out = [] + for i in range(0, sample_size, self.forward_batch_size): + j = min(i + self.forward_batch_size, sample_size) + + out = model( + src_tokens=sample["net_input"]["src_tokens"][i:j, :], + src_lengths=sample["net_input"]["src_lengths"][i:j], + ) + + batch_out.append( + model.sentence_forward(out, sample["net_input"]["src_tokens"][i:j, :]) + ) + + batch_out = torch.cat(batch_out, dim=0).view( + self.task.cfg.mt_beam, sample_size // self.task.cfg.mt_beam, -1 + ) # T x B x C + if model.joint_classification == "sent": + batch_out = model.joint_forward(batch_out) + scores = model.classification_forward(batch_out.view(sample_size, 1, -1)).view( + -1, self.task.cfg.mt_beam + ) # input: B x T x C + + loss = self.compute_kl_loss( + scores, sample["target"][:, 0].view(-1, self.task.cfg.mt_beam) + ) + + sample_size = sample_size // self.task.cfg.mt_beam + + logging_output = { + "loss": loss.detach(), + "ntokens": sample["ntokens"], + "nsentences": sample_size * self.task.cfg.mt_beam, + "sample_size": sample_size, + "scores": scores.detach(), + } + + return loss, sample_size, logging_output + + def compute_kl_loss(self, logits, target): + norm_target = target + if self.target_dist_norm == "minmax": + min_v = torch.min(target, 1, keepdim=True).values + max_v = torch.max(target, 1, keepdim=True).values + norm_target = (target - min_v) / (max_v - min_v + _EPSILON) + + target_dist = F.softmax( + norm_target / self.temperature, dim=-1, dtype=torch.float32 + ) + model_dist = F.log_softmax(logits, dim=-1, dtype=torch.float32) + loss = -(target_dist * model_dist - target_dist * target_dist.log()).sum() + return loss + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + loss_sum = utils.item(sum(log.get("loss", 0) for log in logging_outputs)) + + sample_size = utils.item( + sum(log.get("sample_size", 0) for log in logging_outputs) + ) + + loss = loss_sum / sample_size / math.log(2) + metrics.log_scalar("loss", loss, sample_size, round=3) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return True diff --git a/examples/discriminative_reranking_nmt/drnmt_rerank.py b/examples/discriminative_reranking_nmt/drnmt_rerank.py new file mode 100644 index 0000000000..2e0fc2bd29 --- /dev/null +++ b/examples/discriminative_reranking_nmt/drnmt_rerank.py @@ -0,0 +1,364 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +""" +Score raw text with a trained model. +""" + +from collections import namedtuple +import logging +from multiprocessing import Pool +import sys +import os +import random + +import numpy as np +import sacrebleu +import torch + +from fairseq import checkpoint_utils, options, utils + + +logger = logging.getLogger("fairseq_cli.drnmt_rerank") +logger.setLevel(logging.INFO) + +Batch = namedtuple("Batch", "ids src_tokens src_lengths") + + +pool_init_variables = {} + + +def init_loaded_scores(mt_scores, model_scores, hyp, ref): + global pool_init_variables + pool_init_variables["mt_scores"] = mt_scores + pool_init_variables["model_scores"] = model_scores + pool_init_variables["hyp"] = hyp + pool_init_variables["ref"] = ref + + +def parse_fairseq_gen(filename, task): + source = {} + hypos = {} + scores = {} + with open(filename, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if line.startswith("S-"): # source + uid, text = line.split("\t", 1) + uid = int(uid[2:]) + source[uid] = text + elif line.startswith("D-"): # hypo + uid, score, text = line.split("\t", 2) + uid = int(uid[2:]) + if uid not in hypos: + hypos[uid] = [] + scores[uid] = [] + hypos[uid].append(text) + scores[uid].append(float(score)) + else: + continue + + source_out = [source[i] for i in range(len(hypos))] + hypos_out = [h for i in range(len(hypos)) for h in hypos[i]] + scores_out = [s for i in range(len(scores)) for s in scores[i]] + + return source_out, hypos_out, scores_out + + +def read_target(filename): + with open(filename, "r", encoding="utf-8") as f: + output = [line.strip() for line in f] + return output + + +def make_batches(args, src, hyp, task, max_positions, encode_fn): + assert len(src) * args.beam == len( + hyp + ), f"Expect {len(src) * args.beam} hypotheses for {len(src)} source sentences with beam size {args.beam}. Got {len(hyp)} hypotheses intead." + hyp_encode = [ + task.source_dictionary.encode_line(encode_fn(h), add_if_not_exist=False).long() + for h in hyp + ] + if task.cfg.include_src: + src_encode = [ + task.source_dictionary.encode_line( + encode_fn(s), add_if_not_exist=False + ).long() + for s in src + ] + tokens = [(src_encode[i // args.beam], h) for i, h in enumerate(hyp_encode)] + lengths = [(t1.numel(), t2.numel()) for t1, t2 in tokens] + else: + tokens = [(h,) for h in hyp_encode] + lengths = [(h.numel(),) for h in hyp_encode] + + itr = task.get_batch_iterator( + dataset=task.build_dataset_for_inference(tokens, lengths), + max_tokens=args.max_tokens, + max_sentences=args.batch_size, + max_positions=max_positions, + ignore_invalid_inputs=args.skip_invalid_size_inputs_valid_test, + ).next_epoch_itr(shuffle=False) + + for batch in itr: + yield Batch( + ids=batch["id"], + src_tokens=batch["net_input"]["src_tokens"], + src_lengths=batch["net_input"]["src_lengths"], + ) + + +def decode_rerank_scores(args): + if args.max_tokens is None and args.batch_size is None: + args.batch_size = 1 + + logger.info(args) + + use_cuda = torch.cuda.is_available() and not args.cpu + + # Load ensemble + logger.info("loading model(s) from {}".format(args.path)) + models, _model_args, task = checkpoint_utils.load_model_ensemble_and_task( + [args.path], arg_overrides=eval(args.model_overrides), + ) + + for model in models: + if args.fp16: + model.half() + if use_cuda: + model.cuda() + + # Initialize generator + generator = task.build_generator(args) + + # Handle tokenization and BPE + tokenizer = task.build_tokenizer(args) + bpe = task.build_bpe(args) + + def encode_fn(x): + if tokenizer is not None: + x = tokenizer.encode(x) + if bpe is not None: + x = bpe.encode(x) + return x + + max_positions = utils.resolve_max_positions( + task.max_positions(), *[model.max_positions() for model in models] + ) + + src, hyp, mt_scores = parse_fairseq_gen(args.in_text, task) + model_scores = {} + logger.info("decode reranker score") + for batch in make_batches(args, src, hyp, task, max_positions, encode_fn): + src_tokens = batch.src_tokens + src_lengths = batch.src_lengths + if use_cuda: + src_tokens = src_tokens.cuda() + src_lengths = src_lengths.cuda() + + sample = { + "net_input": {"src_tokens": src_tokens, "src_lengths": src_lengths}, + } + scores = task.inference_step(generator, models, sample) + + for id, sc in zip(batch.ids.tolist(), scores.tolist()): + model_scores[id] = sc[0] + + model_scores = [model_scores[i] for i in range(len(model_scores))] + + return src, hyp, mt_scores, model_scores + + +def get_score(mt_s, md_s, w1, lp, tgt_len): + return mt_s / (tgt_len ** lp) * w1 + md_s + + +def get_best_hyps(mt_scores, md_scores, hypos, fw_weight, lenpen, beam): + assert len(mt_scores) == len(md_scores) and len(mt_scores) == len(hypos) + hypo_scores = [] + best_hypos = [] + best_scores = [] + offset = 0 + for i in range(len(hypos)): + tgt_len = len(hypos[i].split()) + hypo_scores.append( + get_score(mt_scores[i], md_scores[i], fw_weight, lenpen, tgt_len) + ) + + if (i + 1) % beam == 0: + max_i = np.argmax(hypo_scores) + best_hypos.append(hypos[offset + max_i]) + best_scores.append(hypo_scores[max_i]) + hypo_scores = [] + offset += beam + return best_hypos, best_scores + + +def eval_metric(args, hypos, ref): + if args.metric == "bleu": + score = sacrebleu.corpus_bleu(hypos, [ref]).score + else: + score = sacrebleu.corpus_ter(hypos, [ref]).score + + return score + + +def score_target_hypo(args, fw_weight, lp): + mt_scores = pool_init_variables["mt_scores"] + model_scores = pool_init_variables["model_scores"] + hyp = pool_init_variables["hyp"] + ref = pool_init_variables["ref"] + best_hypos, _ = get_best_hyps( + mt_scores, model_scores, hyp, fw_weight, lp, args.beam + ) + rerank_eval = None + if ref: + rerank_eval = eval_metric(args, best_hypos, ref) + print(f"fw_weight {fw_weight}, lenpen {lp}, eval {rerank_eval}") + + return rerank_eval + + +def print_result(best_scores, best_hypos, output_file): + for i, (s, h) in enumerate(zip(best_scores, best_hypos)): + print(f"{i}\t{s}\t{h}", file=output_file) + + +def main(args): + utils.import_user_module(args) + + src, hyp, mt_scores, model_scores = decode_rerank_scores(args) + + assert ( + not args.tune or args.target_text is not None + ), "--target-text has to be set when tuning weights" + if args.target_text: + ref = read_target(args.target_text) + assert len(src) == len( + ref + ), f"different numbers of source and target sentences ({len(src)} vs. {len(ref)})" + + orig_best_hypos = [hyp[i] for i in range(0, len(hyp), args.beam)] + orig_eval = eval_metric(args, orig_best_hypos, ref) + + if args.tune: + logger.info("tune weights for reranking") + + random_params = np.array( + [ + [ + random.uniform( + args.lower_bound_fw_weight, args.upper_bound_fw_weight + ), + random.uniform(args.lower_bound_lenpen, args.upper_bound_lenpen), + ] + for k in range(args.num_trials) + ] + ) + + logger.info("launching pool") + with Pool( + 32, + initializer=init_loaded_scores, + initargs=(mt_scores, model_scores, hyp, ref), + ) as p: + rerank_scores = p.starmap( + score_target_hypo, + [ + (args, random_params[i][0], random_params[i][1],) + for i in range(args.num_trials) + ], + ) + if args.metric == "bleu": + best_index = np.argmax(rerank_scores) + else: + best_index = np.argmin(rerank_scores) + best_fw_weight = random_params[best_index][0] + best_lenpen = random_params[best_index][1] + else: + assert ( + args.lenpen is not None and args.fw_weight is not None + ), "--lenpen and --fw-weight should be set" + best_fw_weight, best_lenpen = args.fw_weight, args.lenpen + + best_hypos, best_scores = get_best_hyps( + mt_scores, model_scores, hyp, best_fw_weight, best_lenpen, args.beam + ) + + if args.results_path is not None: + os.makedirs(args.results_path, exist_ok=True) + output_path = os.path.join( + args.results_path, "generate-{}.txt".format(args.gen_subset), + ) + with open(output_path, "w", buffering=1, encoding="utf-8") as o: + print_result(best_scores, best_hypos, o) + else: + print_result(best_scores, best_hypos, sys.stdout) + + if args.target_text: + rerank_eval = eval_metric(args, best_hypos, ref) + print(f"before reranking, {args.metric.upper()}:", orig_eval) + print( + f"after reranking with fw_weight={best_fw_weight}, lenpen={best_lenpen}, {args.metric.upper()}:", + rerank_eval, + ) + + +def cli_main(): + parser = options.get_generation_parser(interactive=True) + + parser.add_argument( + "--in-text", + default=None, + required=True, + help="text from fairseq-interactive output, containing source sentences and hypotheses", + ) + parser.add_argument("--target-text", default=None, help="reference text") + parser.add_argument("--metric", type=str, choices=["bleu", "ter"], default="bleu") + parser.add_argument( + "--tune", + action="store_true", + help="if set, tune weights on fw scores and lenpen instead of applying fixed weights for reranking", + ) + parser.add_argument( + "--lower-bound-fw-weight", + default=0.0, + type=float, + help="lower bound of search space", + ) + parser.add_argument( + "--upper-bound-fw-weight", + default=3, + type=float, + help="upper bound of search space", + ) + parser.add_argument( + "--lower-bound-lenpen", + default=0.0, + type=float, + help="lower bound of search space", + ) + parser.add_argument( + "--upper-bound-lenpen", + default=3, + type=float, + help="upper bound of search space", + ) + parser.add_argument( + "--fw-weight", type=float, default=None, help="weight on the fw model score" + ) + parser.add_argument( + "--num-trials", + default=1000, + type=int, + help="number of trials to do for random search", + ) + + args = options.parse_args_and_arch(parser) + main(args) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/discriminative_reranking_nmt/models/__init__.py b/examples/discriminative_reranking_nmt/models/__init__.py new file mode 100644 index 0000000000..c593ea5f18 --- /dev/null +++ b/examples/discriminative_reranking_nmt/models/__init__.py @@ -0,0 +1,6 @@ +from .discriminative_reranking_model import DiscriminativeNMTReranker + + +__all__ = [ + "DiscriminativeNMTReranker", +] diff --git a/examples/discriminative_reranking_nmt/models/discriminative_reranking_model.py b/examples/discriminative_reranking_nmt/models/discriminative_reranking_model.py new file mode 100644 index 0000000000..e4b5887f82 --- /dev/null +++ b/examples/discriminative_reranking_nmt/models/discriminative_reranking_model.py @@ -0,0 +1,365 @@ +from dataclasses import dataclass, field +import os + +import torch +import torch.nn as nn + +from fairseq import utils +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.models import ( + BaseFairseqModel, + register_model, +) + +from fairseq.models.roberta.model import RobertaClassificationHead + +from fairseq.modules import ( + LayerNorm, + TransformerSentenceEncoder, + TransformerSentenceEncoderLayer, +) + + +ACTIVATION_FN_CHOICES = ChoiceEnum(utils.get_available_activation_fns()) +JOINT_CLASSIFICATION_CHOICES = ChoiceEnum(["none", "sent"]) +SENTENCE_REP_CHOICES = ChoiceEnum(["head", "meanpool", "maxpool"]) + + +def update_init_roberta_model_state(state): + """ + update the state_dict of a Roberta model for initializing + weights of the BertRanker + """ + for k in list(state.keys()): + if ".lm_head." in k or "version" in k: + del state[k] + continue + # remove 'encoder/decoder.sentence_encoder.' from the key + assert k.startswith("encoder.sentence_encoder.") or k.startswith( + "decoder.sentence_encoder." + ), f"Cannot recognize parameter name {k}" + if "layernorm_embedding" in k: + new_k = k.replace(".layernorm_embedding.", ".emb_layer_norm.") + state[new_k[25:]] = state[k] + else: + state[k[25:]] = state[k] + del state[k] + + +class BaseRanker(nn.Module): + def __init__(self, args, task): + super().__init__() + + self.separator_token = task.dictionary.eos() + self.padding_idx = task.dictionary.pad() + + def forward(self, src_tokens): + raise NotImplementedError + + def get_segment_labels(self, src_tokens): + segment_boundary = (src_tokens == self.separator_token).long() + segment_labels = ( + segment_boundary.cumsum(dim=1) + - segment_boundary + - (src_tokens == self.padding_idx).long() + ) + + return segment_labels + + def get_positions(self, src_tokens, segment_labels): + segment_positions = ( + torch.arange(src_tokens.shape[1]) + .to(src_tokens.device) + .repeat(src_tokens.shape[0], 1) + ) + segment_boundary = (src_tokens == self.separator_token).long() + _, col_idx = (segment_positions * segment_boundary).nonzero(as_tuple=True) + col_idx = torch.cat([torch.zeros(1).type_as(col_idx), col_idx]) + offset = torch.cat( + [ + torch.zeros(1).type_as(segment_boundary), + segment_boundary.sum(dim=1).cumsum(dim=0)[:-1], + ] + ) + segment_positions -= col_idx[segment_labels + offset.unsqueeze(1)] * ( + segment_labels != 0 + ) + + padding_mask = src_tokens.ne(self.padding_idx) + segment_positions = (segment_positions + 1) * padding_mask.type_as( + segment_positions + ) + self.padding_idx + + return segment_positions + + +class BertRanker(BaseRanker): + def __init__(self, args, task): + super(BertRanker, self).__init__(args, task) + + init_model = getattr(args, "pretrained_model", "") + self.joint_layers = nn.ModuleList() + if os.path.isfile(init_model): + print(f"initialize weight from {init_model}") + + from fairseq import hub_utils + + x = hub_utils.from_pretrained( + os.path.dirname(init_model), + checkpoint_file=os.path.basename(init_model), + ) + + in_state_dict = x["models"][0].state_dict() + init_args = x["args"].model + + num_positional_emb = init_args.max_positions + task.dictionary.pad() + 1 + + # follow the setup in roberta + self.model = TransformerSentenceEncoder( + padding_idx=task.dictionary.pad(), + vocab_size=len(task.dictionary), + num_encoder_layers=getattr( + args, "encoder_layers", init_args.encoder_layers + ), + embedding_dim=init_args.encoder_embed_dim, + ffn_embedding_dim=init_args.encoder_ffn_embed_dim, + num_attention_heads=init_args.encoder_attention_heads, + dropout=init_args.dropout, + attention_dropout=init_args.attention_dropout, + activation_dropout=init_args.activation_dropout, + num_segments=2, # add language embeddings + max_seq_len=num_positional_emb, + offset_positions_by_padding=False, + encoder_normalize_before=True, + apply_bert_init=True, + activation_fn=init_args.activation_fn, + freeze_embeddings=args.freeze_embeddings, + n_trans_layers_to_freeze=args.n_trans_layers_to_freeze, + ) + + # still need to learn segment embeddings as we added a second language embedding + if args.freeze_embeddings: + for p in self.model.segment_embeddings.parameters(): + p.requires_grad = False + + update_init_roberta_model_state(in_state_dict) + print("loading weights from the pretrained model") + self.model.load_state_dict( + in_state_dict, strict=False + ) # ignore mismatch in language embeddings + + ffn_embedding_dim = init_args.encoder_ffn_embed_dim + num_attention_heads = init_args.encoder_attention_heads + dropout = init_args.dropout + attention_dropout = init_args.attention_dropout + activation_dropout = init_args.activation_dropout + activation_fn = init_args.activation_fn + + classifier_embed_dim = getattr( + args, "embed_dim", init_args.encoder_embed_dim + ) + if classifier_embed_dim != init_args.encoder_embed_dim: + self.transform_layer = nn.Linear( + init_args.encoder_embed_dim, classifier_embed_dim + ) + else: + self.model = TransformerSentenceEncoder( + padding_idx=task.dictionary.pad(), + vocab_size=len(task.dictionary), + num_encoder_layers=args.encoder_layers, + embedding_dim=args.embed_dim, + ffn_embedding_dim=args.ffn_embed_dim, + num_attention_heads=args.attention_heads, + dropout=args.dropout, + attention_dropout=args.attention_dropout, + activation_dropout=args.activation_dropout, + max_seq_len=task.max_positions() + if task.max_positions() + else args.tokens_per_sample, + num_segments=2, + offset_positions_by_padding=False, + encoder_normalize_before=args.encoder_normalize_before, + apply_bert_init=args.apply_bert_init, + activation_fn=args.activation_fn, + ) + + classifier_embed_dim = args.embed_dim + ffn_embedding_dim = args.ffn_embed_dim + num_attention_heads = args.attention_heads + dropout = args.dropout + attention_dropout = args.attention_dropout + activation_dropout = args.activation_dropout + activation_fn = args.activation_fn + + self.joint_classification = args.joint_classification + if args.joint_classification == "sent": + if args.joint_normalize_before: + self.joint_layer_norm = LayerNorm(classifier_embed_dim) + else: + self.joint_layer_norm = None + + self.joint_layers = nn.ModuleList( + [ + TransformerSentenceEncoderLayer( + embedding_dim=classifier_embed_dim, + ffn_embedding_dim=ffn_embedding_dim, + num_attention_heads=num_attention_heads, + dropout=dropout, + attention_dropout=attention_dropout, + activation_dropout=activation_dropout, + activation_fn=activation_fn, + ) + for _ in range(args.num_joint_layers) + ] + ) + + self.classifier = RobertaClassificationHead( + classifier_embed_dim, + classifier_embed_dim, + 1, # num_classes + "tanh", + args.classifier_dropout, + ) + + def forward(self, src_tokens, src_lengths): + segment_labels = self.get_segment_labels(src_tokens) + positions = self.get_positions(src_tokens, segment_labels) + + inner_states, _ = self.model( + tokens=src_tokens, + segment_labels=segment_labels, + last_state_only=True, + positions=positions, + ) + + return inner_states[-1].transpose(0, 1) # T x B x C -> B x T x C + + def sentence_forward(self, encoder_out, src_tokens=None, sentence_rep="head"): + # encoder_out: B x T x C + if sentence_rep == "head": + x = encoder_out[:, :1, :] + else: # 'meanpool', 'maxpool' + assert src_tokens is not None, "meanpool requires src_tokens input" + segment_labels = self.get_segment_labels(src_tokens) + padding_mask = src_tokens.ne(self.padding_idx) + encoder_mask = segment_labels * padding_mask.type_as(segment_labels) + + if sentence_rep == "meanpool": + ntokens = torch.sum(encoder_mask, dim=1, keepdim=True) + x = torch.sum( + encoder_out * encoder_mask.unsqueeze(2), dim=1, keepdim=True + ) / ntokens.unsqueeze(2).type_as(encoder_out) + else: # 'maxpool' + encoder_out[ + (encoder_mask == 0).unsqueeze(2).repeat(1, 1, encoder_out.shape[-1]) + ] = -float("inf") + x, _ = torch.max(encoder_out, dim=1, keepdim=True) + + if hasattr(self, "transform_layer"): + x = self.transform_layer(x) + + return x # B x 1 x C + + def joint_forward(self, x): + # x: T x B x C + if self.joint_layer_norm: + x = self.joint_layer_norm(x.transpose(0, 1)) + x = x.transpose(0, 1) + + for layer in self.joint_layers: + x, _ = layer(x, self_attn_padding_mask=None) + return x + + def classification_forward(self, x): + # x: B x T x C + return self.classifier(x) + + +@dataclass +class DiscriminativeNMTRerankerConfig(FairseqDataclass): + pretrained_model: str = field( + default="", metadata={"help": "pretrained model to load"} + ) + sentence_rep: SENTENCE_REP_CHOICES = field( + default="head", + metadata={ + "help": "method to transform the output of the transformer stack to a sentence-level representation" + }, + ) + + dropout: float = field(default=0.1, metadata={"help": "dropout probability"}) + attention_dropout: float = field( + default=0.0, metadata={"help": "dropout probability for attention weights"} + ) + activation_dropout: float = field( + default=0.0, metadata={"help": "dropout probability after activation in FFN"} + ) + classifier_dropout: float = field( + default=0.0, metadata={"help": "classifier dropout probability"} + ) + embed_dim: int = field(default=768, metadata={"help": "embedding dimension"}) + ffn_embed_dim: int = field( + default=2048, metadata={"help": "embedding dimension for FFN"} + ) + encoder_layers: int = field(default=12, metadata={"help": "num encoder layers"}) + attention_heads: int = field(default=8, metadata={"help": "num attention heads"}) + encoder_normalize_before: bool = field( + default=False, metadata={"help": "apply layernorm before each encoder block"} + ) + apply_bert_init: bool = field( + default=False, metadata={"help": "use custom param initialization for BERT"} + ) + activation_fn: ACTIVATION_FN_CHOICES = field( + default="relu", metadata={"help": "activation function to use"} + ) + freeze_embeddings: bool = field( + default=False, metadata={"help": "freeze embeddings in the pretrained model"} + ) + n_trans_layers_to_freeze: int = field( + default=0, + metadata={ + "help": "number of layers to freeze in the pretrained transformer model" + }, + ) + + # joint classfication + joint_classification: JOINT_CLASSIFICATION_CHOICES = field( + default="none", + metadata={"help": "method to compute joint features for classification"}, + ) + num_joint_layers: int = field( + default=1, metadata={"help": "number of joint layers"} + ) + joint_normalize_before: bool = field( + default=False, + metadata={"help": "apply layer norm on the input to the joint layer"}, + ) + + +@register_model( + "discriminative_nmt_reranker", dataclass=DiscriminativeNMTRerankerConfig +) +class DiscriminativeNMTReranker(BaseFairseqModel): + @classmethod + def build_model(cls, args, task): + model = BertRanker(args, task) + return DiscriminativeNMTReranker(args, model) + + def __init__(self, args, model): + super().__init__() + + self.model = model + self.sentence_rep = args.sentence_rep + self.joint_classification = args.joint_classification + + def forward(self, src_tokens, src_lengths, **kwargs): + return self.model(src_tokens, src_lengths) + + def sentence_forward(self, encoder_out, src_tokens): + return self.model.sentence_forward(encoder_out, src_tokens, self.sentence_rep) + + def joint_forward(self, x): + return self.model.joint_forward(x) + + def classification_forward(self, x): + return self.model.classification_forward(x) diff --git a/examples/discriminative_reranking_nmt/scripts/prep_data.py b/examples/discriminative_reranking_nmt/scripts/prep_data.py new file mode 100755 index 0000000000..7aa7d37edc --- /dev/null +++ b/examples/discriminative_reranking_nmt/scripts/prep_data.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python + +import argparse +from multiprocessing import Pool +from pathlib import Path + +import sacrebleu +import sentencepiece as spm + + +def read_text_file(filename): + with open(filename, "r") as f: + output = [line.strip() for line in f] + + return output + + +def get_bleu(in_sent, target_sent): + bleu = sacrebleu.corpus_bleu([in_sent], [[target_sent]]) + out = " ".join( + map(str, [bleu.score, bleu.sys_len, bleu.ref_len] + bleu.counts + bleu.totals) + ) + return out + + +def get_ter(in_sent, target_sent): + ter = sacrebleu.corpus_ter([in_sent], [[target_sent]]) + out = " ".join(map(str, [ter.score, ter.num_edits, ter.ref_length])) + return out + + +def init(sp_model): + global sp + sp = spm.SentencePieceProcessor() + sp.Load(sp_model) + + +def process(source_sent, target_sent, hypo_sent, metric): + source_bpe = " ".join(sp.EncodeAsPieces(source_sent)) + hypo_bpe = [" ".join(sp.EncodeAsPieces(h)) for h in hypo_sent] + + if metric == "bleu": + score_str = [get_bleu(h, target_sent) for h in hypo_sent] + else: # ter + score_str = [get_ter(h, target_sent) for h in hypo_sent] + + return source_bpe, hypo_bpe, score_str + + +def main(args): + assert ( + args.split.startswith("train") or args.num_shards == 1 + ), "--num-shards should be set to 1 for valid and test sets" + assert ( + args.split.startswith("train") + or args.split.startswith("valid") + or args.split.startswith("test") + ), "--split should be set to train[n]/valid[n]/test[n]" + + source_sents = read_text_file(args.input_source) + target_sents = read_text_file(args.input_target) + + num_sents = len(source_sents) + assert num_sents == len( + target_sents + ), f"{args.input_source} and {args.input_target} should have the same number of sentences." + + hypo_sents = read_text_file(args.input_hypo) + assert ( + len(hypo_sents) % args.beam == 0 + ), f"Number of hypotheses ({len(hypo_sents)}) cannot be divided by beam size ({args.beam})." + + hypo_sents = [ + hypo_sents[i : i + args.beam] for i in range(0, len(hypo_sents), args.beam) + ] + assert num_sents == len( + hypo_sents + ), f"{args.input_hypo} should contain {num_sents * args.beam} hypotheses but only has {len(hypo_sents) * args.beam}. (--beam={args.beam})" + + output_dir = args.output_dir / args.metric + for ns in range(args.num_shards): + print(f"processing shard {ns+1}/{args.num_shards}") + shard_output_dir = output_dir / f"split{ns+1}" + source_output_dir = shard_output_dir / "input_src" + hypo_output_dir = shard_output_dir / "input_tgt" + metric_output_dir = shard_output_dir / args.metric + + source_output_dir.mkdir(parents=True, exist_ok=True) + hypo_output_dir.mkdir(parents=True, exist_ok=True) + metric_output_dir.mkdir(parents=True, exist_ok=True) + + if args.n_proc > 1: + with Pool( + args.n_proc, initializer=init, initargs=(args.sentencepiece_model,) + ) as p: + output = p.starmap( + process, + [ + (source_sents[i], target_sents[i], hypo_sents[i], args.metric) + for i in range(ns, num_sents, args.num_shards) + ], + ) + else: + init(args.sentencepiece_model) + output = [ + process(source_sents[i], target_sents[i], hypo_sents[i], args.metric) + for i in range(ns, num_sents, args.num_shards) + ] + + with open(source_output_dir / f"{args.split}.bpe", "w") as s_o, open( + hypo_output_dir / f"{args.split}.bpe", "w" + ) as h_o, open(metric_output_dir / f"{args.split}.{args.metric}", "w") as m_o: + for source_bpe, hypo_bpe, score_str in output: + assert len(hypo_bpe) == len(score_str) + for h, m in zip(hypo_bpe, score_str): + s_o.write(f"{source_bpe}\n") + h_o.write(f"{h}\n") + m_o.write(f"{m}\n") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--input-source", type=Path, required=True) + parser.add_argument("--input-target", type=Path, required=True) + parser.add_argument("--input-hypo", type=Path, required=True) + parser.add_argument("--output-dir", type=Path, required=True) + parser.add_argument("--split", type=str, required=True) + parser.add_argument("--beam", type=int, required=True) + parser.add_argument("--sentencepiece-model", type=str, required=True) + parser.add_argument("--metric", type=str, choices=["bleu", "ter"], default="bleu") + parser.add_argument("--num-shards", type=int, default=1) + parser.add_argument("--n-proc", type=int, default=8) + + args = parser.parse_args() + + main(args) diff --git a/examples/discriminative_reranking_nmt/tasks/__init__.py b/examples/discriminative_reranking_nmt/tasks/__init__.py new file mode 100644 index 0000000000..2d78ca9870 --- /dev/null +++ b/examples/discriminative_reranking_nmt/tasks/__init__.py @@ -0,0 +1,6 @@ +from .discriminative_reranking_task import DiscriminativeRerankingNMTTask + + +__all__ = [ + "DiscriminativeRerankingNMTTask", +] diff --git a/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py b/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py new file mode 100644 index 0000000000..0e7fbba888 --- /dev/null +++ b/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py @@ -0,0 +1,475 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass, field + +import itertools +import logging +import os + +import numpy as np +import torch + +from fairseq import metrics +from fairseq.data import ( + ConcatDataset, + ConcatSentencesDataset, + data_utils, + Dictionary, + IdDataset, + indexed_dataset, + NestedDictionaryDataset, + NumSamplesDataset, + NumelDataset, + PrependTokenDataset, + RawLabelDataset, + RightPadDataset, + SortDataset, + TruncateDataset, + TokenBlockDataset, +) +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.tasks import FairseqTask, register_task +from omegaconf import II, MISSING + + +EVAL_BLEU_ORDER = 4 +TARGET_METRIC_CHOICES = ChoiceEnum(["bleu", "ter"]) + +logger = logging.getLogger(__name__) + + +@dataclass +class DiscriminativeRerankingNMTConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) + num_data_splits: int = field( + default=1, metadata={"help": "total number of data splits"} + ) + no_shuffle: bool = field( + default=False, metadata={"help": "do not shuffle training data"} + ) + max_positions: int = field( + default=512, metadata={"help": "number of positional embeddings to learn"} + ) + include_src: bool = field( + default=False, metadata={"help": "include source sentence"} + ) + mt_beam: int = field(default=50, metadata={"help": "beam size of input hypotheses"}) + eval_target_metric: bool = field( + default=False, + metadata={"help": "evaluation with the target metric during validation"}, + ) + target_metric: TARGET_METRIC_CHOICES = field( + default="bleu", metadata={"help": "name of the target metric to optimize for"} + ) + train_subset: str = field( + default=II("dataset.train_subset"), + metadata={"help": "data subset to use for training (e.g. train, valid, test)"}, + ) + seed: int = field( + default=II("common.seed"), + metadata={"help": "pseudo random number generator seed"}, + ) + + +class RerankerScorer(object): + """Scores the target for a given (source (optional), target) input.""" + + def __init__(self, args, mt_beam): + self.mt_beam = mt_beam + + @torch.no_grad() + def generate(self, models, sample, **kwargs): + """Score a batch of translations.""" + net_input = sample["net_input"] + + assert len(models) == 1, "does not support model ensemble" + model = models[0] + + bs = net_input["src_tokens"].shape[0] + assert ( + model.joint_classification == "none" or bs % self.mt_beam == 0 + ), f"invalid batch size ({bs}) for joint classification with beam size ({self.mt_beam})" + + model.eval() + logits = model(**net_input) + + batch_out = model.sentence_forward(logits, net_input["src_tokens"]) + if model.joint_classification == "sent": + batch_out = model.joint_forward( + batch_out.view(self.mt_beam, bs // self.mt_beam, -1) + ) + scores = model.classification_forward( + batch_out.view(bs, 1, -1) + ) # input: B x T x C + + return scores + + +@register_task( + "discriminative_reranking_nmt", dataclass=DiscriminativeRerankingNMTConfig +) +class DiscriminativeRerankingNMTTask(FairseqTask): + """ + Translation rerank task. + The input can be either (src, tgt) sentence pairs or tgt sentence only. + """ + + cfg: DiscriminativeRerankingNMTConfig + + def __init__(self, cfg: DiscriminativeRerankingNMTConfig, data_dictionary=None): + super().__init__(cfg) + self.dictionary = data_dictionary + self._max_positions = cfg.max_positions + # args.tokens_per_sample = self._max_positions + # self.num_classes = 1 # for model + + @classmethod + def load_dictionary(cls, cfg, filename): + """Load the dictionary from the filename""" + dictionary = Dictionary.load(filename) + dictionary.add_symbol("<mask>") # for loading pretrained XLMR model + + return dictionary + + @classmethod + def setup_task(cls, cfg: DiscriminativeRerankingNMTConfig, **kwargs): + # load data dictionary (assume joint dictionary) + data_path = cfg.data + data_dict = cls.load_dictionary( + cfg, os.path.join(data_path, "input_src/dict.txt") + ) + + logger.info("[input] src dictionary: {} types".format(len(data_dict))) + + return DiscriminativeRerankingNMTTask(cfg, data_dict) + + def load_dataset(self, split, epoch=0, combine=False, **kwargs): + """Load a given dataset split (e.g., train, valid, test).""" + if self.cfg.data.endswith("1"): + data_shard = (epoch - 1) % self.cfg.num_data_splits + 1 + data_path = self.cfg.data[:-1] + str(data_shard) + else: + data_path = self.cfg.data + + def get_path(type, data_split): + return os.path.join(data_path, str(type), data_split) + + def make_dataset(type, dictionary, data_split, combine): + split_path = get_path(type, data_split) + + dataset = data_utils.load_indexed_dataset( + split_path, dictionary, combine=combine, + ) + return dataset + + def load_split(data_split, metric): + input_src = None + if self.cfg.include_src: + input_src = make_dataset( + "input_src", self.dictionary, data_split, combine=False + ) + assert input_src is not None, "could not find dataset: {}".format( + get_path("input_src", data_split) + ) + + input_tgt = make_dataset( + "input_tgt", self.dictionary, data_split, combine=False + ) + assert input_tgt is not None, "could not find dataset: {}".format( + get_path("input_tgt", data_split) + ) + + label_path = f"{get_path(metric, data_split)}.{metric}" + assert os.path.exists(label_path), f"could not find dataset: {label_path}" + + np_labels = np.loadtxt(label_path) + if self.cfg.target_metric == "ter": + np_labels = -np_labels + label = RawLabelDataset(np_labels) + + return input_src, input_tgt, label + + src_datasets = [] + tgt_datasets = [] + label_datasets = [] + + if split == self.cfg.train_subset: + for k in itertools.count(): + split_k = "train" + (str(k) if k > 0 else "") + prefix = os.path.join(data_path, "input_tgt", split_k) + if not indexed_dataset.dataset_exists(prefix, impl=None): + if k > 0: + break + else: + raise FileNotFoundError(f"Dataset not found: {prefix}") + input_src, input_tgt, label = load_split( + split_k, self.cfg.target_metric + ) + src_datasets.append(input_src) + tgt_datasets.append(input_tgt) + label_datasets.append(label) + else: + input_src, input_tgt, label = load_split(split, self.cfg.target_metric) + src_datasets.append(input_src) + tgt_datasets.append(input_tgt) + label_datasets.append(label) + + if len(tgt_datasets) == 1: + input_tgt, label = tgt_datasets[0], label_datasets[0] + if self.cfg.include_src: + input_src = src_datasets[0] + else: + input_tgt = ConcatDataset(tgt_datasets) + label = ConcatDataset(label_datasets) + if self.cfg.include_src: + input_src = ConcatDataset(src_datasets) + + input_tgt = TruncateDataset(input_tgt, self.cfg.max_positions) + if self.cfg.include_src: + input_src = PrependTokenDataset(input_src, self.dictionary.bos()) + input_src = TruncateDataset(input_src, self.cfg.max_positions) + src_lengths = NumelDataset(input_src, reduce=False) + src_tokens = ConcatSentencesDataset(input_src, input_tgt) + else: + src_tokens = PrependTokenDataset(input_tgt, self.dictionary.bos()) + src_lengths = NumelDataset(src_tokens, reduce=False) + + dataset = { + "id": IdDataset(), + "net_input": { + "src_tokens": RightPadDataset( + src_tokens, pad_idx=self.source_dictionary.pad(), + ), + "src_lengths": src_lengths, + }, + "nsentences": NumSamplesDataset(), + "ntokens": NumelDataset(src_tokens, reduce=True), + "target": label, + } + + dataset = NestedDictionaryDataset(dataset, sizes=[src_tokens.sizes],) + + assert len(dataset) % self.cfg.mt_beam == 0, ( + "dataset size (%d) is not a multiple of beam size (%d)" + % (len(dataset), self.cfg.mt_beam) + ) + + # no need to shuffle valid/test sets + if not self.cfg.no_shuffle and split == self.cfg.train_subset: + + # need to keep all hypothese together + start_idx = np.arange(0, len(dataset), self.cfg.mt_beam) + with data_utils.numpy_seed(self.cfg.seed + epoch): + np.random.shuffle(start_idx) + + idx = np.arange(0, self.cfg.mt_beam) + shuffle = np.tile(idx, (len(start_idx), 1)).reshape(-1) + np.tile( + start_idx, (self.cfg.mt_beam, 1) + ).transpose().reshape(-1) + + dataset = SortDataset(dataset, sort_order=[shuffle],) + + logger.info(f"Loaded {split} with #samples: {len(dataset)}") + + self.datasets[split] = dataset + return self.datasets[split] + + def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): + assert not self.cfg.include_src or len(src_tokens[0]) == 2 + input_src = None + if self.cfg.include_src: + input_src = TokenBlockDataset( + [t[0] for t in src_tokens], + [l[0] for l in src_lengths], + block_size=None, # ignored for "eos" break mode + pad=self.source_dictionary.pad(), + eos=self.source_dictionary.eos(), + break_mode="eos", + ) + input_src = PrependTokenDataset(input_src, self.dictionary.bos()) + input_src = TruncateDataset(input_src, self.cfg.max_positions) + + input_tgt = TokenBlockDataset( + [t[-1] for t in src_tokens], + [l[-1] for l in src_lengths], + block_size=None, # ignored for "eos" break mode + pad=self.source_dictionary.pad(), + eos=self.source_dictionary.eos(), + break_mode="eos", + ) + input_tgt = TruncateDataset(input_tgt, self.cfg.max_positions) + if self.cfg.include_src: + src_tokens = ConcatSentencesDataset(input_src, input_tgt) + src_lengths = NumelDataset(input_src, reduce=False) + else: + input_tgt = PrependTokenDataset(input_tgt, self.dictionary.bos()) + src_tokens = input_tgt + src_lengths = NumelDataset(src_tokens, reduce=False) + + dataset = { + "id": IdDataset(), + "net_input": { + "src_tokens": RightPadDataset( + src_tokens, pad_idx=self.source_dictionary.pad(), + ), + "src_lengths": src_lengths, + }, + "nsentences": NumSamplesDataset(), + "ntokens": NumelDataset(src_tokens, reduce=True), + } + + return NestedDictionaryDataset(dataset, sizes=[src_tokens.sizes],) + + def build_model(self, cfg: FairseqDataclass): + return super().build_model(cfg) + + def build_generator(self, args): + return RerankerScorer(args, mt_beam=self.cfg.mt_beam) + + def max_positions(self): + return self._max_positions + + @property + def source_dictionary(self): + return self.dictionary + + @property + def target_dictionary(self): + return self.dictionary + + def create_dummy_batch(self, device): + dummy_target = ( + torch.zeros(self.cfg.mt_beam, EVAL_BLEU_ORDER * 2 + 3).long().to(device) + if not self.cfg.eval_ter + else torch.zeros(self.cfg.mt_beam, 3).long().to(device) + ) + + return { + "id": torch.zeros(self.cfg.mt_beam, 1).long().to(device), + "net_input": { + "src_tokens": torch.zeros(self.cfg.mt_beam, 4).long().to(device), + "src_lengths": torch.ones(self.cfg.mt_beam, 1).long().to(device), + }, + "nsentences": 0, + "ntokens": 0, + "target": dummy_target, + } + + def train_step( + self, sample, model, criterion, optimizer, update_num, ignore_grad=False + ): + if ignore_grad and sample is None: + sample = self.create_dummy_batch(model.device) + + return super().train_step( + sample, model, criterion, optimizer, update_num, ignore_grad + ) + + def valid_step(self, sample, model, criterion): + if sample is None: + sample = self.create_dummy_batch(model.device) + + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + + if not self.cfg.eval_target_metric: + return loss, sample_size, logging_output + + scores = logging_output["scores"] + + if self.cfg.target_metric == "bleu": + assert sample["target"].shape[1] == EVAL_BLEU_ORDER * 2 + 3, ( + "target does not contain enough information (" + + str(sample["target"].shape[1]) + + "for evaluating BLEU" + ) + + max_id = torch.argmax(scores, dim=1) + select_id = max_id + torch.arange( + 0, sample_size * self.cfg.mt_beam, self.cfg.mt_beam + ).to(max_id.device) + bleu_data = sample["target"][select_id, 1:].sum(0).data + + logging_output["_bleu_sys_len"] = bleu_data[0] + logging_output["_bleu_ref_len"] = bleu_data[1] + + for i in range(EVAL_BLEU_ORDER): + logging_output["_bleu_counts_" + str(i)] = bleu_data[2 + i] + logging_output["_bleu_totals_" + str(i)] = bleu_data[ + 2 + EVAL_BLEU_ORDER + i + ] + + elif self.cfg.target_metric == "ter": + assert sample["target"].shape[1] == 3, ( + "target does not contain enough information (" + + str(sample["target"].shape[1]) + + "for evaluating TER" + ) + + max_id = torch.argmax(scores, dim=1) + select_id = max_id + torch.arange( + 0, sample_size * self.cfg.mt_beam, self.cfg.mt_beam + ).to(max_id.device) + ter_data = sample["target"][select_id, 1:].sum(0).data + + logging_output["_ter_num_edits"] = -ter_data[0] + logging_output["_ter_ref_len"] = -ter_data[1] + + return loss, sample_size, logging_output + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + if not self.cfg.eval_target_metric: + return + + def sum_logs(key): + return sum(log.get(key, 0) for log in logging_outputs) + + if self.cfg.target_metric == "bleu": + counts, totals = [], [] + for i in range(EVAL_BLEU_ORDER): + counts.append(sum_logs("_bleu_counts_" + str(i))) + totals.append(sum_logs("_bleu_totals_" + str(i))) + + if max(totals) > 0: + # log counts as numpy arrays -- log_scalar will sum them correctly + metrics.log_scalar("_bleu_counts", np.array(counts)) + metrics.log_scalar("_bleu_totals", np.array(totals)) + metrics.log_scalar("_bleu_sys_len", sum_logs("_bleu_sys_len")) + metrics.log_scalar("_bleu_ref_len", sum_logs("_bleu_ref_len")) + + def compute_bleu(meters): + import inspect + import sacrebleu + + fn_sig = inspect.getfullargspec(sacrebleu.compute_bleu)[0] + if "smooth_method" in fn_sig: + smooth = {"smooth_method": "exp"} + else: + smooth = {"smooth": "exp"} + bleu = sacrebleu.compute_bleu( + correct=meters["_bleu_counts"].sum, + total=meters["_bleu_totals"].sum, + sys_len=meters["_bleu_sys_len"].sum, + ref_len=meters["_bleu_ref_len"].sum, + **smooth, + ) + return round(bleu.score, 2) + + metrics.log_derived("bleu", compute_bleu) + elif self.cfg.target_metric == "ter": + num_edits = sum_logs("_ter_num_edits") + ref_len = sum_logs("_ter_ref_len") + + if ref_len > 0: + metrics.log_scalar("_ter_num_edits", num_edits) + metrics.log_scalar("_ter_ref_len", ref_len) + + def compute_ter(meters): + score = meters["_ter_num_edits"].sum / meters["_ter_ref_len"].sum + return round(score.item(), 2) + + metrics.log_derived("ter", compute_ter) From 4497897fa506187db96cd9f00614f6dd7080b550 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Sun, 11 Jul 2021 15:21:06 -0700 Subject: [PATCH 398/774] respect roberta model name to init arch (#2049) Summary: previous PR was always applying base architecture when finetuning roberta Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2049 Reviewed By: arbabu123 Differential Revision: D29642089 Pulled By: alexeib fbshipit-source-id: e8c6ec6e1fa68bef233f7221e0e02787d7ad2c06 --- examples/roberta/config/finetuning/cola.yaml | 5 ++++- examples/roberta/config/finetuning/mnli.yaml | 5 ++++- examples/roberta/config/finetuning/mrpc.yaml | 5 ++++- examples/roberta/config/finetuning/qnli.yaml | 5 ++++- examples/roberta/config/finetuning/qqp.yaml | 5 ++++- examples/roberta/config/finetuning/rte.yaml | 5 ++++- examples/roberta/config/finetuning/sst_2.yaml | 5 ++++- examples/roberta/config/finetuning/sts_b.yaml | 6 ++++-- fairseq/models/__init__.py | 11 +++++++++++ fairseq/models/roberta/model.py | 2 +- 10 files changed, 44 insertions(+), 10 deletions(-) diff --git a/examples/roberta/config/finetuning/cola.yaml b/examples/roberta/config/finetuning/cola.yaml index 717069d407..ac76611201 100644 --- a/examples/roberta/config/finetuning/cola.yaml +++ b/examples/roberta/config/finetuning/cola.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -21,6 +23,7 @@ checkpoint: reset_meters: true best_checkpoint_metric: accuracy maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +54,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/mnli.yaml b/examples/roberta/config/finetuning/mnli.yaml index 4bfc02bed9..5be10c362f 100644 --- a/examples/roberta/config/finetuning/mnli.yaml +++ b/examples/roberta/config/finetuning/mnli.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -21,6 +23,7 @@ checkpoint: reset_meters: true best_checkpoint_metric: accuracy maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +54,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/mrpc.yaml b/examples/roberta/config/finetuning/mrpc.yaml index 907b4639c1..aa8b7db393 100644 --- a/examples/roberta/config/finetuning/mrpc.yaml +++ b/examples/roberta/config/finetuning/mrpc.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -21,6 +23,7 @@ checkpoint: reset_meters: true best_checkpoint_metric: accuracy maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +54,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/qnli.yaml b/examples/roberta/config/finetuning/qnli.yaml index 00aea91e56..b4595b090e 100644 --- a/examples/roberta/config/finetuning/qnli.yaml +++ b/examples/roberta/config/finetuning/qnli.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -21,6 +23,7 @@ checkpoint: reset_meters: true best_checkpoint_metric: accuracy maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +54,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/qqp.yaml b/examples/roberta/config/finetuning/qqp.yaml index dc0296d26e..5a2b2ed743 100644 --- a/examples/roberta/config/finetuning/qqp.yaml +++ b/examples/roberta/config/finetuning/qqp.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -21,6 +23,7 @@ checkpoint: reset_meters: true best_checkpoint_metric: accuracy maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +54,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/rte.yaml b/examples/roberta/config/finetuning/rte.yaml index 40dfd76169..7318465011 100644 --- a/examples/roberta/config/finetuning/rte.yaml +++ b/examples/roberta/config/finetuning/rte.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -21,6 +23,7 @@ checkpoint: reset_meters: true best_checkpoint_metric: accuracy maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +54,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/sst_2.yaml b/examples/roberta/config/finetuning/sst_2.yaml index b808a850cb..a93ad2f22c 100644 --- a/examples/roberta/config/finetuning/sst_2.yaml +++ b/examples/roberta/config/finetuning/sst_2.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -21,6 +23,7 @@ checkpoint: reset_meters: true best_checkpoint_metric: accuracy maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +54,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/examples/roberta/config/finetuning/sts_b.yaml b/examples/roberta/config/finetuning/sts_b.yaml index d354bb97dd..2d495221ad 100644 --- a/examples/roberta/config/finetuning/sts_b.yaml +++ b/examples/roberta/config/finetuning/sts_b.yaml @@ -5,6 +5,8 @@ common: fp16_init_scale: 4 threshold_loss_scale: 1 fp16_scale_window: 128 + log_format: json + log_interval: 200 task: _name: sentence_prediction @@ -19,7 +21,7 @@ checkpoint: reset_optimizer: true reset_dataloader: true reset_meters: true - best_checkpoint_metric: accuracy + no_epoch_checkpoints: true distributed_training: find_unused_parameters: true @@ -51,6 +53,6 @@ optimization: max_epoch: 10 model: - _name: roberta_large + _name: roberta dropout: 0.1 attention_dropout: 0.1 diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 61425c8ef5..05d2a9d087 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -7,10 +7,12 @@ import argparse import importlib import os +from contextlib import ExitStack from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import merge_with_parent, populate_dataclass from hydra.core.config_store import ConfigStore +from omegaconf import open_dict, OmegaConf from .composite_encoder import CompositeEncoder from .distributed_fairseq_model import DistributedFairseqModel @@ -80,10 +82,19 @@ def build_model(cfg: FairseqDataclass, task): if model_type in MODEL_DATACLASS_REGISTRY: # set defaults from dataclass. note that arch name and model name can be the same dc = MODEL_DATACLASS_REGISTRY[model_type] + if isinstance(cfg, argparse.Namespace): cfg = populate_dataclass(dc(), cfg) else: cfg = merge_with_parent(dc(), cfg) + else: + if model_type in ARCH_CONFIG_REGISTRY: + with open_dict(cfg) if OmegaConf.is_config(cfg) else ExitStack(): + # this calls the different "arch" functions (like base_architecture()) that you indicate + # if you specify --arch on the command line. this is only applicable to the old argparse based models + # hydra models should expose different architectures via different config files + # it will modify the cfg object and default parameters according to the arch + ARCH_CONFIG_REGISTRY[model_type](cfg) assert model is not None, ( f"Could not infer model type from {cfg}. " diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 39a1cdd951..3337616be6 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -523,7 +523,7 @@ def safe_getattr(obj, k, default=None): from omegaconf import OmegaConf if OmegaConf.is_config(obj): - return obj.k if k in obj and obj.k is not None else default + return obj[k] if k in obj and obj[k] is not None else default return getattr(obj, k, default) From 1a1380e5a8b0cce49090676d95044626f208c48c Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Sun, 11 Jul 2021 21:25:45 -0700 Subject: [PATCH 399/774] fix hydra upgrade (#2051) Summary: commit 72c0e4f36d150b8244260fba6228b94ff95914bf added "config_schema" to config and initialize.py which did not exist, and caused crashes for any interpreted keys (e.g. "common.tpu" in task) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2051 Reviewed By: arbabu123 Differential Revision: D29654730 Pulled By: alexeib fbshipit-source-id: bac18e3d2011de7c822ffcd7e6d4d4364a8edc52 --- fairseq/config/config.yaml | 1 - fairseq/dataclass/initialize.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq/config/config.yaml b/fairseq/config/config.yaml index 087083e88a..e20d914b9b 100644 --- a/fairseq/config/config.yaml +++ b/fairseq/config/config.yaml @@ -5,7 +5,6 @@ hydra: dir: . defaults: - - config_schema - task: null - model: null - criterion: cross_entropy diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index 1d5c90eefd..e43b31790e 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -16,7 +16,7 @@ def hydra_init(cfg_name="config") -> None: cs = ConfigStore.instance() - cs.store(name=f"{cfg_name}_schema", node=FairseqConfig) + cs.store(name=f"{cfg_name}", node=FairseqConfig) for k in FairseqConfig.__dataclass_fields__: v = FairseqConfig.__dataclass_fields__[k].default From d26dcedaf97e556da8dcab10b5de08cea72c3459 Mon Sep 17 00:00:00 2001 From: Jialu Joann Li <jialuli3@fb.com> Date: Mon, 12 Jul 2021 13:55:29 -0700 Subject: [PATCH 400/774] pyspeech embedding extractor Summary: Transformer to extract embeddings from pyspeech encoder models Reviewed By: vimalmanohar Differential Revision: D29492082 fbshipit-source-id: abf2432f43c75b93dcccb1a389039e5628f95e92 --- fairseq/models/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 05d2a9d087..c5a4bbc831 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -98,10 +98,10 @@ def build_model(cfg: FairseqDataclass, task): assert model is not None, ( f"Could not infer model type from {cfg}. " - f"Available models: " - + str(MODEL_DATACLASS_REGISTRY.keys()) - + " Requested model type: " - + model_type + "Available models: {}".format( + MODEL_DATACLASS_REGISTRY.keys() + ) + + f" Requested model type: {model_type}" ) return model.build_model(cfg, task) From 313ff0581561c7725ea9430321d6af2901573dfb Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Mon, 12 Jul 2021 17:58:00 -0700 Subject: [PATCH 401/774] migrate masked lm task and criterion (#2050) Summary: migrates masked lm task and criterion. old command line flags still continue to work as before Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2050 Reviewed By: arbabu123 Differential Revision: D29648056 Pulled By: alexeib fbshipit-source-id: 33079a461826ab6d1736d6016ee5e3522bcc5427 --- examples/roberta/README.pretraining.md | 28 +-- examples/roberta/config/pretraining/base.yaml | 42 ++++ fairseq/criterions/masked_lm.py | 15 +- fairseq/tasks/masked_lm.py | 201 +++++++++--------- 4 files changed, 159 insertions(+), 127 deletions(-) create mode 100644 examples/roberta/config/pretraining/base.yaml diff --git a/examples/roberta/README.pretraining.md b/examples/roberta/README.pretraining.md index 8b6e10c08c..a4e7453529 100644 --- a/examples/roberta/README.pretraining.md +++ b/examples/roberta/README.pretraining.md @@ -48,35 +48,21 @@ fairseq-preprocess \ ### 2) Train RoBERTa base ```bash -TOTAL_UPDATES=125000 # Total number of training steps -WARMUP_UPDATES=10000 # Warmup the learning rate over this many updates -PEAK_LR=0.0005 # Peak learning rate, adjust as needed -TOKENS_PER_SAMPLE=512 # Max sequence length -MAX_POSITIONS=512 # Num. positional embeddings (usually same as above) -MAX_SENTENCES=16 # Number of sequences per batch (batch size) -UPDATE_FREQ=16 # Increase the batch size 16x - DATA_DIR=data-bin/wikitext-103 -fairseq-train --fp16 $DATA_DIR \ - --task masked_lm --criterion masked_lm \ - --arch roberta_base --sample-break-mode complete --tokens-per-sample $TOKENS_PER_SAMPLE \ - --optimizer adam --adam-betas '(0.9,0.98)' --adam-eps 1e-6 --clip-norm 0.0 \ - --lr-scheduler polynomial_decay --lr $PEAK_LR --warmup-updates $WARMUP_UPDATES --total-num-update $TOTAL_UPDATES \ - --dropout 0.1 --attention-dropout 0.1 --weight-decay 0.01 \ - --batch-size $MAX_SENTENCES --update-freq $UPDATE_FREQ \ - --max-update $TOTAL_UPDATES --log-format simple --log-interval 1 +fairseq-hydra-train -m --config-dir examples/roberta/config/pretraining \ +--config-name base task.data=$DATA_DIR ``` **Note:** You can optionally resume training the released RoBERTa base model by -adding `--restore-file /path/to/roberta.base/model.pt`. +adding `checkpoint.restore_file=/path/to/roberta.base/model.pt`. **Note:** The above command assumes training on 8x32GB V100 GPUs. Each GPU uses -a batch size of 16 sequences (`$MAX_SENTENCES`) and accumulates gradients to -further increase the batch size by 16x (`$UPDATE_FREQ`), for a total batch size +a batch size of 16 sequences (`dataset.batch_size`) and accumulates gradients to +further increase the batch size by 16x (`optimization.update_freq`), for a total batch size of 2048 sequences. If you have fewer GPUs or GPUs with less memory you may need -to reduce `$MAX_SENTENCES` and increase `$UPDATE_FREQ` to compensate. -Alternatively if you have more GPUs you can decrease `$UPDATE_FREQ` accordingly +to reduce `dataset.batch_size` and increase dataset.update_freq to compensate. +Alternatively if you have more GPUs you can decrease `dataset.update_freq` accordingly to increase training speed. **Note:** The learning rate and batch size are tightly connected and need to be diff --git a/examples/roberta/config/pretraining/base.yaml b/examples/roberta/config/pretraining/base.yaml new file mode 100644 index 0000000000..97829908f7 --- /dev/null +++ b/examples/roberta/config/pretraining/base.yaml @@ -0,0 +1,42 @@ +# @package _group_ +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + no_epoch_checkpoints: true + +task: + _name: masked_lm + data: ??? + sample_break_mode: complete + tokens_per_sample: 512 + +criterion: masked_lm + +dataset: + batch_size: 16 + ignore_unused_valid_subsets: true + +optimizer: + _name: adam + weight_decay: 0.01 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 10000 + +optimization: + clip_norm: 0 + lr: [0.0005] + max_update: 125000 + update_freq: [16] + +model: + _name: roberta + max_positions: 512 + dropout: 0.1 + attention_dropout: 0.1 diff --git a/fairseq/criterions/masked_lm.py b/fairseq/criterions/masked_lm.py index b04cfbff6d..279458f317 100644 --- a/fairseq/criterions/masked_lm.py +++ b/fairseq/criterions/masked_lm.py @@ -3,23 +3,30 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass import math +from omegaconf import II import torch -import torch.nn.functional as F from fairseq import metrics, modules, utils from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass -@register_criterion("masked_lm") +@dataclass +class MaskedLmConfig(FairseqDataclass): + tpu: bool = II("common.tpu") + + +@register_criterion("masked_lm", dataclass=MaskedLmConfig) class MaskedLmLoss(FairseqCriterion): """ Implementation for the loss used in masked language model (MLM) training. """ - def __init__(self, task, tpu=False): + def __init__(self, cfg: MaskedLmConfig, task): super().__init__(task) - self.tpu = tpu + self.tpu = cfg.tpu def forward(self, model, sample, reduce=True): """Compute the loss for the given sample. diff --git a/fairseq/tasks/masked_lm.py b/fairseq/tasks/masked_lm.py index fd2ea6ade1..0c08132fb7 100644 --- a/fairseq/tasks/masked_lm.py +++ b/fairseq/tasks/masked_lm.py @@ -3,9 +3,12 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass, field import logging import os +from omegaconf import MISSING, II, OmegaConf + import numpy as np from fairseq import utils from fairseq.data import ( @@ -23,108 +26,103 @@ ) from fairseq.data.encoders.utils import get_whole_word_mask from fairseq.data.shorten_dataset import maybe_shorten_dataset -from fairseq.tasks import LegacyFairseqTask, register_task +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task + +from .language_modeling import SAMPLE_BREAK_MODE_CHOICES, SHORTEN_METHOD_CHOICES logger = logging.getLogger(__name__) -@register_task("masked_lm") -class MaskedLMTask(LegacyFairseqTask): - """Task for training masked language models (e.g., BERT, RoBERTa).""" - - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - parser.add_argument( - "data", - help="colon separated path to data directories list, \ - will be iterated upon during epochs in round-robin manner", - ) - parser.add_argument( - "--sample-break-mode", - default="complete", - choices=["none", "complete", "complete_doc", "eos"], - help='If omitted or "none", fills each sample with tokens-per-sample ' +@dataclass +class MaskedLMConfig(FairseqDataclass): + data: str = field( + default=MISSING, + metadata={ + "help": "colon separated path to data directories list, \ + will be iterated upon during epochs in round-robin manner" + }, + ) + sample_break_mode: SAMPLE_BREAK_MODE_CHOICES = field( + default="none", + metadata={ + "help": 'If omitted or "none", fills each sample with tokens-per-sample ' 'tokens. If set to "complete", splits samples only at the end ' "of sentence, but may include multiple sentences per sample. " '"complete_doc" is similar but respects doc boundaries. ' - 'If set to "eos", includes only one sentence per sample.', - ) - parser.add_argument( - "--tokens-per-sample", - default=512, - type=int, - help="max number of total tokens over all segments " - "per sample for BERT dataset", - ) - parser.add_argument( - "--mask-prob", - default=0.15, - type=float, - help="probability of replacing a token with mask", - ) - parser.add_argument( - "--leave-unmasked-prob", - default=0.1, - type=float, - help="probability that a masked token is unmasked", - ) - parser.add_argument( - "--random-token-prob", - default=0.1, - type=float, - help="probability of replacing a token with a random token", - ) - parser.add_argument( - "--freq-weighted-replacement", - default=False, - action="store_true", - help="sample random replacement words based on word frequencies", - ) - parser.add_argument( - "--mask-whole-words", - default=False, - action="store_true", - help="mask whole words; you may also want to set --bpe", - ) - parser.add_argument( - "--mask-multiple-length", - default=1, - type=int, - help="repeat the mask indices multiple times", - ) - parser.add_argument( - "--mask-stdev", default=0.0, type=float, help="stdev of the mask length" - ) - parser.add_argument( - "--shorten-method", - default="none", - choices=["none", "truncate", "random_crop"], - help="if not none, shorten sequences that exceed --tokens-per-sample", - ) - parser.add_argument( - "--shorten-data-split-list", - default="", - help="comma-separated list of dataset splits to apply shortening to, " - 'e.g., "train,valid" (default: all dataset splits)', - ) + 'If set to "eos", includes only one sentence per sample.' + }, + ) + tokens_per_sample: int = field( + default=1024, + metadata={"help": "max number of tokens per sample for LM dataset"}, + ) + mask_prob: float = field( + default=0.15, + metadata={"help": "probability of replacing a token with mask"}, + ) + leave_unmasked_prob: float = field( + default=0.1, + metadata={"help": "probability that a masked token is unmasked"}, + ) + random_token_prob: float = field( + default=0.1, + metadata={"help": "probability of replacing a token with a random token"}, + ) + freq_weighted_replacement: bool = field( + default=False, + metadata={"help": "sample random replacement words based on word frequencies"}, + ) + mask_whole_words: bool = field( + default=False, + metadata={"help": "mask whole words; you may also want to set --bpe"}, + ) + mask_multiple_length: int = field( + default=1, + metadata={"help": "repeat the mask indices multiple times"}, + ) + mask_stdev: float = field( + default=0.0, + metadata={"help": "stdev of the mask length"}, + ) + shorten_method: SHORTEN_METHOD_CHOICES = field( + default="none", + metadata={ + "help": "if not none, shorten sequences that exceed --tokens-per-sample" + }, + ) + shorten_data_split_list: str = field( + default="", + metadata={ + "help": "comma-separated list of dataset splits to apply shortening to, " + 'e.g., "train,valid" (default: all dataset splits)' + }, + ) + seed: int = II("common.seed") + + +@register_task("masked_lm", dataclass=MaskedLMConfig) +class MaskedLMTask(FairseqTask): + + cfg: MaskedLMConfig + + """Task for training masked language models (e.g., BERT, RoBERTa).""" - def __init__(self, args, dictionary): - super().__init__(args) + def __init__(self, cfg: MaskedLMConfig, dictionary): + super().__init__(cfg) self.dictionary = dictionary - self.seed = args.seed # add mask token self.mask_idx = dictionary.add_symbol("<mask>") @classmethod - def setup_task(cls, args, **kwargs): - paths = utils.split_paths(args.data) + def setup_task(cls, cfg: MaskedLMConfig, **kwargs): + paths = utils.split_paths(cfg.data) assert len(paths) > 0 dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) logger.info("dictionary: {} types".format(len(dictionary))) - return cls(args, dictionary) + return cls(cfg, dictionary) def load_dataset(self, split, epoch=1, combine=False, **kwargs): """Load a given dataset split. @@ -132,7 +130,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): Args: split (str): name of the split (e.g., train, valid, test) """ - paths = utils.split_paths(self.args.data) + paths = utils.split_paths(self.cfg.data) assert len(paths) > 0 data_path = paths[(epoch - 1) % len(paths)] split_path = os.path.join(data_path, split) @@ -140,7 +138,6 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): dataset = data_utils.load_indexed_dataset( split_path, self.source_dictionary, - self.args.dataset_impl, combine=combine, ) if dataset is None: @@ -151,20 +148,20 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): dataset = maybe_shorten_dataset( dataset, split, - self.args.shorten_data_split_list, - self.args.shorten_method, - self.args.tokens_per_sample, - self.args.seed, + self.cfg.shorten_data_split_list, + self.cfg.shorten_method, + self.cfg.tokens_per_sample, + self.cfg.seed, ) # create continuous blocks of tokens dataset = TokenBlockDataset( dataset, dataset.sizes, - self.args.tokens_per_sample - 1, # one less for <s> + self.cfg.tokens_per_sample - 1, # one less for <s> pad=self.source_dictionary.pad(), eos=self.source_dictionary.eos(), - break_mode=self.args.sample_break_mode, + break_mode=self.cfg.sample_break_mode, ) logger.info("loaded {} blocks from: {}".format(len(dataset), split_path)) @@ -174,7 +171,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): # create masked input and targets mask_whole_words = ( get_whole_word_mask(self.args, self.source_dictionary) - if self.args.mask_whole_words + if self.cfg.mask_whole_words else None ) @@ -183,17 +180,17 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): self.source_dictionary, pad_idx=self.source_dictionary.pad(), mask_idx=self.mask_idx, - seed=self.args.seed, - mask_prob=self.args.mask_prob, - leave_unmasked_prob=self.args.leave_unmasked_prob, - random_token_prob=self.args.random_token_prob, - freq_weighted_replacement=self.args.freq_weighted_replacement, + seed=self.cfg.seed, + mask_prob=self.cfg.mask_prob, + leave_unmasked_prob=self.cfg.leave_unmasked_prob, + random_token_prob=self.cfg.random_token_prob, + freq_weighted_replacement=self.cfg.freq_weighted_replacement, mask_whole_words=mask_whole_words, - mask_multiple_length=self.args.mask_multiple_length, - mask_stdev=self.args.mask_stdev, + mask_multiple_length=self.cfg.mask_multiple_length, + mask_stdev=self.cfg.mask_stdev, ) - with data_utils.numpy_seed(self.args.seed): + with data_utils.numpy_seed(self.cfg.seed): shuffle = np.random.permutation(len(src_dataset)) self.datasets[split] = SortDataset( @@ -227,7 +224,7 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, sort=True): TokenBlockDataset( src_tokens, src_lengths, - self.args.tokens_per_sample - 1, # one less for <s> + self.cfg.tokens_per_sample - 1, # one less for <s> pad=self.source_dictionary.pad(), eos=self.source_dictionary.eos(), break_mode="eos", From f2146bdc7abf293186de9449bfa2272775e39e1d Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Mon, 12 Jul 2021 20:28:51 -0700 Subject: [PATCH 402/774] refactor clustering in hubert example (#2018) Summary: ## What does this PR do? - Fix edge cases of sharded feature extraction in example/hubert/simple_kmeans, where some shard has 0 samples. - Refactor `example/hubert/simple_kmeans/dump_*_features.py` ## Test Tested on 2 iterations of clustering from MFCC and HUBERT features Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2018 Reviewed By: hikushalhere Differential Revision: D29523927 Pulled By: wnhsu fbshipit-source-id: b089f3d38bd464a940954d358cd5ef091e4892a2 --- .../simple_kmeans/dump_hubert_feature.py | 54 ++--------- .../simple_kmeans/dump_hubert_feature_s2t.py | 54 ++--------- .../hubert/simple_kmeans/dump_mfcc_feature.py | 48 +--------- .../hubert/simple_kmeans/dump_w2v2_feature.py | 95 +++++++++++++++++++ .../hubert/simple_kmeans/feature_utils.py | 66 +++++++++++++ 5 files changed, 183 insertions(+), 134 deletions(-) create mode 100644 examples/hubert/simple_kmeans/dump_w2v2_feature.py create mode 100644 examples/hubert/simple_kmeans/feature_utils.py diff --git a/examples/hubert/simple_kmeans/dump_hubert_feature.py b/examples/hubert/simple_kmeans/dump_hubert_feature.py index cd242890e5..5c7b67f8b1 100644 --- a/examples/hubert/simple_kmeans/dump_hubert_feature.py +++ b/examples/hubert/simple_kmeans/dump_hubert_feature.py @@ -4,7 +4,6 @@ # LICENSE file in the root directory of this source tree. import logging -import math import os import sys @@ -12,8 +11,9 @@ import soundfile as sf import torch import torch.nn.functional as F -import tqdm -from npy_append_array import NpyAppendArray + +from feature_utils import get_path_iterator, dump_feature + logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -66,53 +66,13 @@ def get_feats(self, path, ref_len=None): output_layer=self.layer, ) feat.append(feat_chunk) - return torch.cat(feat, 1).squeeze(0) - - -def get_path_iterator(tsv, nshard, rank): - with open(tsv, "r") as f: - root = f.readline().rstrip() - lines = [line.rstrip() for line in f] - tot = len(lines) - shard_size = math.ceil(tot / nshard) - start, end = rank * shard_size, min((rank + 1) * shard_size, tot) - assert start < end, "start={start}, end={end}" - logger.info( - f"rank {rank} of {nshard}, process {end-start} " - f"({start}-{end}) out of {tot}" - ) - - lines = lines[start:end] + return torch.cat(feat, 1).squeeze(0) - def iterate(): - for line in lines: - subpath, nsample = line.split("\t") - yield f"{root}/{subpath}", int(nsample) - return iterate, len(lines) - - -def dump_feature( - tsv_dir, split, ckpt_path, layer, nshard, rank, feat_dir, max_chunk -): +def main(tsv_dir, split, ckpt_path, layer, nshard, rank, feat_dir, max_chunk): reader = HubertFeatureReader(ckpt_path, layer, max_chunk) generator, num = get_path_iterator(f"{tsv_dir}/{split}.tsv", nshard, rank) - iterator = generator() - - feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy" - leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len" - - os.makedirs(feat_dir, exist_ok=True) - if os.path.exists(feat_path): - os.remove(feat_path) - - feat_f = NpyAppendArray(feat_path) - with open(leng_path, "w") as leng_f: - for path, nsample in tqdm.tqdm(iterator, total=num): - feat = reader.get_feats(path, nsample) - feat_f.append(feat.cpu().numpy()) - leng_f.write(f"{len(feat)}\n") - logger.info("finished successfully") + dump_feature(reader, generator, num, split, nshard, rank, feat_dir) if __name__ == "__main__": @@ -130,4 +90,4 @@ def dump_feature( args = parser.parse_args() logger.info(args) - dump_feature(**vars(args)) + main(**vars(args)) diff --git a/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py b/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py index 7ec8a7311b..6fff4faf44 100644 --- a/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py +++ b/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py @@ -6,18 +6,17 @@ import csv import io import logging -import math import os import os.path as op import sys -import tqdm from dump_hubert_feature import HubertFeatureReader +from feature_utils import get_shard_range, dump_feature from fairseq.data.audio.audio_utils import get_waveform from fairseq.data.audio.speech_to_text_dataset import ( read_from_uncompressed_zip, ) -from npy_append_array import NpyAppendArray + logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -57,54 +56,21 @@ def get_path_iterator(root, tsv, nshard, rank): quoting=csv.QUOTE_NONE, ) subpaths = [op.join(root, e["audio"]) for e in reader] - - tot = len(subpaths) - shard_size = math.ceil(tot / nshard) - start, end = rank * shard_size, min((rank + 1) * shard_size, tot) - assert start < end, "start={start}, end={end}" - logger.info( - f"rank {rank} of {nshard}, process {end-start} " - f"({start}-{end}) out of {tot}" - ) - + start, end = get_shard_range(len(subpaths), nshard, rank) subpaths = subpaths[start:end] - def iterate(): for subpath in subpaths: - yield op.join(root, subpath) - - return iterate, len(subpaths) + yield op.join(root, subpath), None + return iterate, len(subpaths) -def dump_feature( - root, - tsv_path, - ckpt_path, - layer, - nshard, - rank, - feat_dir, - feat_name, - max_chunk, +def main( + root, tsv_path, ckpt_path, layer, nshard, rank, feat_dir, split, max_chunk ): reader = HubertFeatureReaderS2T(ckpt_path, layer, max_chunk) generator, num = get_path_iterator(root, tsv_path, nshard, rank) - iterator = generator() - - feat_path = f"{feat_dir}/{feat_name}_{rank}_{nshard}.npy" - leng_path = f"{feat_dir}/{feat_name}_{rank}_{nshard}.len" - - os.makedirs(feat_dir, exist_ok=True) - if op.exists(feat_path): - os.remove(feat_path) + dump_feature(reader, generator, num, split, nshard, rank, feat_dir) - feat_f = NpyAppendArray(feat_path) - with open(leng_path, "w") as leng_f: - for path in tqdm.tqdm(iterator, total=num): - feat = reader.get_feats(path) - feat_f.append(feat.cpu().numpy()) - leng_f.write(f"{len(feat)}\n") - logger.info("finished successfully") if __name__ == "__main__": @@ -118,9 +84,9 @@ def dump_feature( parser.add_argument("nshard", type=int) parser.add_argument("rank", type=int) parser.add_argument("feat_dir") - parser.add_argument("feat_name") + parser.add_argument("split") parser.add_argument("--max_chunk", type=int, default=1600000) args = parser.parse_args() logger.info(args) - dump_feature(**vars(args)) + main(**vars(args)) diff --git a/examples/hubert/simple_kmeans/dump_mfcc_feature.py b/examples/hubert/simple_kmeans/dump_mfcc_feature.py index a36fa643bd..70d0016663 100644 --- a/examples/hubert/simple_kmeans/dump_mfcc_feature.py +++ b/examples/hubert/simple_kmeans/dump_mfcc_feature.py @@ -4,15 +4,14 @@ # LICENSE file in the root directory of this source tree. import logging -import math import os import sys import soundfile as sf import torch import torchaudio -import tqdm -from npy_append_array import NpyAppendArray + +from feature_utils import get_path_iterator, dump_feature logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -56,48 +55,11 @@ def get_feats(self, path, ref_len=None): return concat -def get_path_iterator(tsv, nshard, rank): - with open(tsv, "r") as f: - root = f.readline().rstrip() - lines = [line.rstrip() for line in f] - tot = len(lines) - shard_size = math.ceil(tot / nshard) - start, end = rank * shard_size, min((rank + 1) * shard_size, tot) - assert start < end, "start={start}, end={end}" - logger.info( - f"rank {rank} of {nshard}, process {end-start} " - f"({start}-{end}) out of {tot}" - ) - - lines = lines[start:end] - - def iterate(): - for line in lines: - subpath, nsample = line.split("\t") - yield f"{root}/{subpath}", int(nsample) - - return iterate, len(lines) - - -def dump_feature(tsv_dir, split, sample_rate, nshard, rank, feat_dir): +def main(tsv_dir, split, nshard, rank, feat_dir, sample_rate): reader = MfccFeatureReader(sample_rate) generator, num = get_path_iterator(f"{tsv_dir}/{split}.tsv", nshard, rank) - iterator = generator() - - feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy" - leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len" - - os.makedirs(feat_dir, exist_ok=True) - if os.path.exists(feat_path): - os.remove(feat_path) + dump_feature(reader, generator, num, split, nshard, rank, feat_dir) - feat_f = NpyAppendArray(feat_path) - with open(leng_path, "w") as leng_f: - for path, nsample in tqdm.tqdm(iterator, total=num): - feat = reader.get_feats(path, nsample) - feat_f.append(feat.cpu().numpy()) - leng_f.write(f"{len(feat)}\n") - logger.info("finished successfully") if __name__ == "__main__": @@ -113,4 +75,4 @@ def dump_feature(tsv_dir, split, sample_rate, nshard, rank, feat_dir): args = parser.parse_args() logger.info(args) - dump_feature(**vars(args)) + main(**vars(args)) diff --git a/examples/hubert/simple_kmeans/dump_w2v2_feature.py b/examples/hubert/simple_kmeans/dump_w2v2_feature.py new file mode 100644 index 0000000000..a1f0d902ac --- /dev/null +++ b/examples/hubert/simple_kmeans/dump_w2v2_feature.py @@ -0,0 +1,95 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import sys + +import fairseq +import soundfile as sf +import torch +import torch.nn.functional as F + +from feature_utils import get_path_iterator, dump_feature + + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("dump_w2v2_feature") + + +class Wav2Vec2FeatureReader(object): + def __init__(self, ckpt_path, layer, max_chunk=1600000): + ( + model, + cfg, + task, + ) = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path]) + self.model = model[0].eval().cuda() + self.task = task + self.layer = layer # assume this is 1-based like HuBERT + self.max_chunk = max_chunk + logger.info(f"TASK CONFIG:\n{self.task.cfg}") + logger.info(f" max_chunk = {self.max_chunk}") + logger.info(f" model:\n{self.model}") + + def read_audio(self, path, ref_len=None): + wav, sr = sf.read(path) + assert sr == self.task.cfg.sample_rate, sr + if wav.ndim == 2: + wav = wav.mean(-1) + assert wav.ndim == 1, wav.ndim + if ref_len is not None and abs(ref_len - len(wav)) > 160: + logging.warning(f"ref {ref_len} != read {len(wav)} ({path})") + return wav + + def get_feats(self, path, ref_len=None): + x = self.read_audio(path, ref_len) + with torch.no_grad(): + x = torch.from_numpy(x).float().cuda() + if self.task.cfg.normalize: + x = F.layer_norm(x, x.shape) + x = x.view(1, -1) + + feat = [] + for start in range(0, x.size(1), self.max_chunk): + x_chunk = x[:, start: start + self.max_chunk] + res = self.model.extract_features( + source=x_chunk, + padding_mask=None, + mask=False, + layer=self.layer - 1, + ) + feat_chunk = res["x"] + feat.append(feat_chunk) + return torch.cat(feat, 1).squeeze(0) + + +def main(tsv_dir, split, ckpt_path, layer, nshard, rank, feat_dir, max_chunk): + reader = Wav2Vec2FeatureReader(ckpt_path, layer, max_chunk) + generator, num = get_path_iterator(f"{tsv_dir}/{split}.tsv", nshard, rank) + dump_feature(reader, generator, num, split, nshard, rank, feat_dir) + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("tsv_dir") + parser.add_argument("split") + parser.add_argument("ckpt_path") + parser.add_argument("layer", type=int) + parser.add_argument("nshard", type=int) + parser.add_argument("rank", type=int) + parser.add_argument("feat_dir") + parser.add_argument("--max_chunk", type=int, default=1600000) + args = parser.parse_args() + logger.info(args) + + main(**vars(args)) diff --git a/examples/hubert/simple_kmeans/feature_utils.py b/examples/hubert/simple_kmeans/feature_utils.py new file mode 100644 index 0000000000..f80bc45697 --- /dev/null +++ b/examples/hubert/simple_kmeans/feature_utils.py @@ -0,0 +1,66 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import sys + +import tqdm +from npy_append_array import NpyAppendArray + + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("feature_utils") + + +def get_shard_range(tot, nshard, rank): + assert rank < nshard and rank >= 0, f"invaid rank/nshard {rank}/{nshard}" + start = round(tot / nshard * rank) + end = round(tot / nshard * (rank + 1)) + assert start < end, f"start={start}, end={end}" + logger.info( + f"rank {rank} of {nshard}, process {end-start} " + f"({start}-{end}) out of {tot}" + ) + return start, end + + +def get_path_iterator(tsv, nshard, rank): + with open(tsv, "r") as f: + root = f.readline().rstrip() + lines = [line.rstrip() for line in f] + start, end = get_shard_range(len(lines), nshard, rank) + lines = lines[start:end] + def iterate(): + for line in lines: + subpath, nsample = line.split("\t") + yield f"{root}/{subpath}", int(nsample) + return iterate, len(lines) + + +def dump_feature(reader, generator, num, split, nshard, rank, feat_dir): + iterator = generator() + + feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy" + leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len" + + os.makedirs(feat_dir, exist_ok=True) + if os.path.exists(feat_path): + os.remove(feat_path) + + feat_f = NpyAppendArray(feat_path) + with open(leng_path, "w") as leng_f: + for path, nsample in tqdm.tqdm(iterator, total=num): + feat = reader.get_feats(path, nsample) + feat_f.append(feat.cpu().numpy()) + leng_f.write(f"{len(feat)}\n") + logger.info("finished successfully") + + From 597a8fc5e36110450c6a7251506d17b42b635643 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Fri, 16 Jul 2021 04:54:46 -0700 Subject: [PATCH 403/774] Only import MultiheadAttention when doing typechecking Summary: This might create dependency loops in some cases and we don't use it otherwise. Reviewed By: myleott, dianaml0 Differential Revision: D29521387 fbshipit-source-id: b4c27426a5965cd864a0c7b353082756099fead5 --- fairseq/utils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fairseq/utils.py b/fairseq/utils.py index 4fe95b9e8b..d1ec9a274c 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -12,13 +12,14 @@ import sys import warnings from itertools import accumulate -from typing import Callable, Dict, List, Optional +from typing import Callable, Dict, List, Optional, TYPE_CHECKING import torch import torch.nn.functional as F -from fairseq.modules.multihead_attention import MultiheadAttention from torch import Tensor +if TYPE_CHECKING: + from fairseq.modules.multihead_attention import MultiheadAttention try: from amp_C import multi_tensor_l2norm @@ -130,7 +131,7 @@ def _move_to_tpu(tensor): def get_incremental_state( - module: MultiheadAttention, + module: "MultiheadAttention", incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], key: str, ) -> Optional[Dict[str, Optional[Tensor]]]: @@ -139,7 +140,7 @@ def get_incremental_state( def set_incremental_state( - module: MultiheadAttention, + module: "MultiheadAttention", incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], key: str, value: Dict[str, Optional[Tensor]], From aa15dc9a1b4cd586dc832a971a5e31ad668f9e22 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Fri, 16 Jul 2021 04:54:46 -0700 Subject: [PATCH 404/774] Transformer File Split Summary: transformer.py in fairseq is enormous. This doesn't change anything but just splits that file in the model file, the encoder file and the decoder file. We then adjust a few imports that were importing from the wrong modules or creating dependency loops. Reviewed By: myleott Differential Revision: D29533995 fbshipit-source-id: 776f6bbdadb08d729b0b521fd767b7ac6116a723 --- fairseq/models/nat/levenshtein_transformer.py | 3 +- fairseq/models/transformer.py | 1188 ----------------- fairseq/models/transformer/__init__.py | 44 + .../models/transformer/transformer_decoder.py | 452 +++++++ .../models/transformer/transformer_encoder.py | 322 +++++ .../models/transformer/transformer_model.py | 452 +++++++ 6 files changed, 1272 insertions(+), 1189 deletions(-) delete mode 100644 fairseq/models/transformer.py create mode 100644 fairseq/models/transformer/__init__.py create mode 100644 fairseq/models/transformer/transformer_decoder.py create mode 100644 fairseq/models/transformer/transformer_encoder.py create mode 100644 fairseq/models/transformer/transformer_model.py diff --git a/fairseq/models/nat/levenshtein_transformer.py b/fairseq/models/nat/levenshtein_transformer.py index 9377c3c7f5..d60d3c52d5 100644 --- a/fairseq/models/nat/levenshtein_transformer.py +++ b/fairseq/models/nat/levenshtein_transformer.py @@ -9,7 +9,8 @@ from fairseq.iterative_refinement_generator import DecoderOut from fairseq.models import register_model, register_model_architecture from fairseq.models.nat import FairseqNATDecoder, FairseqNATModel, ensemble_decoder -from fairseq.models.transformer import Embedding, TransformerDecoderLayer +from fairseq.models.transformer import Embedding +from fairseq.modules import TransformerDecoderLayer from fairseq.modules.transformer_sentence_encoder import init_bert_params from .levenshtein_utils import ( diff --git a/fairseq/models/transformer.py b/fairseq/models/transformer.py deleted file mode 100644 index c2726af34d..0000000000 --- a/fairseq/models/transformer.py +++ /dev/null @@ -1,1188 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import math -from typing import Any, Dict, List, Optional, Tuple - -import torch -import torch.nn as nn -from fairseq import utils -from fairseq.distributed import fsdp_wrap -from fairseq.models import ( - FairseqEncoder, - FairseqEncoderDecoderModel, - FairseqIncrementalDecoder, - register_model, - register_model_architecture, -) -from fairseq.modules import ( - AdaptiveSoftmax, - BaseLayer, - FairseqDropout, - LayerDropModuleList, - LayerNorm, - PositionalEmbedding, - SinusoidalPositionalEmbedding, - TransformerDecoderLayer, - TransformerEncoderLayer, -) -from fairseq.modules.checkpoint_activations import checkpoint_wrapper -from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ -from torch import Tensor - - -DEFAULT_MAX_SOURCE_POSITIONS = 1024 -DEFAULT_MAX_TARGET_POSITIONS = 1024 - - -DEFAULT_MIN_PARAMS_TO_WRAP = int(1e8) - - -@register_model("transformer") -class TransformerModel(FairseqEncoderDecoderModel): - """ - Transformer model from `"Attention Is All You Need" (Vaswani, et al, 2017) - <https://arxiv.org/abs/1706.03762>`_. - - Args: - encoder (TransformerEncoder): the encoder - decoder (TransformerDecoder): the decoder - - The Transformer model provides the following named architectures and - command-line arguments: - - .. argparse:: - :ref: fairseq.models.transformer_parser - :prog: - """ - - @classmethod - def hub_models(cls): - # fmt: off - - def moses_subword(path): - return { - 'path': path, - 'tokenizer': 'moses', - 'bpe': 'subword_nmt', - } - - def moses_fastbpe(path): - return { - 'path': path, - 'tokenizer': 'moses', - 'bpe': 'fastbpe', - } - - def spm(path): - return { - 'path': path, - 'bpe': 'sentencepiece', - 'tokenizer': 'space', - } - - return { - 'transformer.wmt14.en-fr': moses_subword('https://dl.fbaipublicfiles.com/fairseq/models/wmt14.en-fr.joined-dict.transformer.tar.bz2'), - 'transformer.wmt16.en-de': 'https://dl.fbaipublicfiles.com/fairseq/models/wmt16.en-de.joined-dict.transformer.tar.bz2', - 'transformer.wmt18.en-de': moses_subword('https://dl.fbaipublicfiles.com/fairseq/models/wmt18.en-de.ensemble.tar.gz'), - 'transformer.wmt19.en-de': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-de.joined-dict.ensemble.tar.gz'), - 'transformer.wmt19.en-ru': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-ru.ensemble.tar.gz'), - 'transformer.wmt19.de-en': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.de-en.joined-dict.ensemble.tar.gz'), - 'transformer.wmt19.ru-en': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.ru-en.ensemble.tar.gz'), - 'transformer.wmt19.en-de.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-de.joined-dict.single_model.tar.gz'), - 'transformer.wmt19.en-ru.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-ru.single_model.tar.gz'), - 'transformer.wmt19.de-en.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.de-en.joined-dict.single_model.tar.gz'), - 'transformer.wmt19.ru-en.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.ru-en.single_model.tar.gz'), - 'transformer.wmt20.en-ta': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-ta.single.tar.gz'), - 'transformer.wmt20.en-iu.news': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.news.single.tar.gz'), - 'transformer.wmt20.en-iu.nh': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.nh.single.tar.gz'), - 'transformer.wmt20.ta-en': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta-en.single.tar.gz'), - 'transformer.wmt20.iu-en.news': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.news.single.tar.gz'), - 'transformer.wmt20.iu-en.nh': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.nh.single.tar.gz'), - 'transformer.flores101.mm100.615M': spm('https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_615M.tar.gz'), - 'transformer.flores101.mm100.175M': spm('https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_175M.tar.gz'), - } - # fmt: on - - def __init__(self, args, encoder, decoder): - super().__init__(encoder, decoder) - self.args = args - self.supports_align_args = True - - @staticmethod - def add_args(parser): - """Add model-specific arguments to the parser.""" - # fmt: off - parser.add_argument('--activation-fn', - choices=utils.get_available_activation_fns(), - help='activation function to use') - parser.add_argument('--dropout', type=float, metavar='D', - help='dropout probability') - parser.add_argument('--attention-dropout', type=float, metavar='D', - help='dropout probability for attention weights') - parser.add_argument('--activation-dropout', '--relu-dropout', type=float, metavar='D', - help='dropout probability after activation in FFN.') - parser.add_argument('--encoder-embed-path', type=str, metavar='STR', - help='path to pre-trained encoder embedding') - parser.add_argument('--encoder-embed-dim', type=int, metavar='N', - help='encoder embedding dimension') - parser.add_argument('--encoder-ffn-embed-dim', type=int, metavar='N', - help='encoder embedding dimension for FFN') - parser.add_argument('--encoder-layers', type=int, metavar='N', - help='num encoder layers') - parser.add_argument('--encoder-attention-heads', type=int, metavar='N', - help='num encoder attention heads') - parser.add_argument('--encoder-normalize-before', action='store_true', - help='apply layernorm before each encoder block') - parser.add_argument('--encoder-learned-pos', action='store_true', - help='use learned positional embeddings in the encoder') - parser.add_argument('--decoder-embed-path', type=str, metavar='STR', - help='path to pre-trained decoder embedding') - parser.add_argument('--decoder-embed-dim', type=int, metavar='N', - help='decoder embedding dimension') - parser.add_argument('--decoder-ffn-embed-dim', type=int, metavar='N', - help='decoder embedding dimension for FFN') - parser.add_argument('--decoder-layers', type=int, metavar='N', - help='num decoder layers') - parser.add_argument('--decoder-attention-heads', type=int, metavar='N', - help='num decoder attention heads') - parser.add_argument('--decoder-learned-pos', action='store_true', - help='use learned positional embeddings in the decoder') - parser.add_argument('--decoder-normalize-before', action='store_true', - help='apply layernorm before each decoder block') - parser.add_argument('--decoder-output-dim', type=int, metavar='N', - help='decoder output dimension (extra linear layer ' - 'if different from decoder embed dim') - parser.add_argument('--share-decoder-input-output-embed', action='store_true', - help='share decoder input and output embeddings') - parser.add_argument('--share-all-embeddings', action='store_true', - help='share encoder, decoder and output embeddings' - ' (requires shared dictionary and embed dim)') - parser.add_argument('--no-token-positional-embeddings', default=False, action='store_true', - help='if set, disables positional embeddings (outside self attention)') - parser.add_argument('--adaptive-softmax-cutoff', metavar='EXPR', - help='comma separated list of adaptive softmax cutoff points. ' - 'Must be used with adaptive_loss criterion'), - parser.add_argument('--adaptive-softmax-dropout', type=float, metavar='D', - help='sets adaptive softmax dropout for the tail projections') - parser.add_argument('--layernorm-embedding', action='store_true', - help='add layernorm to embedding') - parser.add_argument('--no-scale-embedding', action='store_true', - help='if True, dont scale embeddings') - parser.add_argument('--checkpoint-activations', action='store_true', - help='checkpoint activations at each layer, which saves GPU ' - 'memory usage at the cost of some additional compute') - parser.add_argument('--offload-activations', action='store_true', - help='checkpoint activations at each layer, then save to gpu. Sets --checkpoint-activations.') - # args for "Cross+Self-Attention for Transformer Models" (Peitz et al., 2019) - parser.add_argument('--no-cross-attention', default=False, action='store_true', - help='do not perform cross-attention') - parser.add_argument('--cross-self-attention', default=False, action='store_true', - help='perform cross+self-attention') - # args for "Reducing Transformer Depth on Demand with Structured Dropout" (Fan et al., 2019) - parser.add_argument('--encoder-layerdrop', type=float, metavar='D', default=0, - help='LayerDrop probability for encoder') - parser.add_argument('--decoder-layerdrop', type=float, metavar='D', default=0, - help='LayerDrop probability for decoder') - parser.add_argument('--encoder-layers-to-keep', default=None, - help='which layers to *keep* when pruning as a comma-separated list') - parser.add_argument('--decoder-layers-to-keep', default=None, - help='which layers to *keep* when pruning as a comma-separated list') - # args for Training with Quantization Noise for Extreme Model Compression ({Fan*, Stock*} et al., 2020) - parser.add_argument('--quant-noise-pq', type=float, metavar='D', default=0, - help='iterative PQ quantization noise at training time') - parser.add_argument('--quant-noise-pq-block-size', type=int, metavar='D', default=8, - help='block size of quantization noise at training time') - parser.add_argument('--quant-noise-scalar', type=float, metavar='D', default=0, - help='scalar quantization noise and scalar quantization at training time') - # args for Fully Sharded Data Parallel (FSDP) training - parser.add_argument( - '--min-params-to-wrap', type=int, metavar='D', default=DEFAULT_MIN_PARAMS_TO_WRAP, - help=( - 'minimum number of params for a layer to be wrapped with FSDP() when ' - 'training with --ddp-backend=fully_sharded. Smaller values will ' - 'improve memory efficiency, but may make torch.distributed ' - 'communication less efficient due to smaller input sizes. This option ' - 'is set to 0 (i.e., always wrap) when --checkpoint-activations or ' - '--offload-activations are passed.' - ) - ) - # fmt: on - - @classmethod - def build_model(cls, args, task): - """Build a new model instance.""" - - # make sure all arguments are present in older models - base_architecture(args) - - if args.encoder_layers_to_keep: - args.encoder_layers = len(args.encoder_layers_to_keep.split(",")) - if args.decoder_layers_to_keep: - args.decoder_layers = len(args.decoder_layers_to_keep.split(",")) - - if getattr(args, "max_source_positions", None) is None: - args.max_source_positions = DEFAULT_MAX_SOURCE_POSITIONS - if getattr(args, "max_target_positions", None) is None: - args.max_target_positions = DEFAULT_MAX_TARGET_POSITIONS - - src_dict, tgt_dict = task.source_dictionary, task.target_dictionary - - if args.share_all_embeddings: - if src_dict != tgt_dict: - raise ValueError("--share-all-embeddings requires a joined dictionary") - if args.encoder_embed_dim != args.decoder_embed_dim: - raise ValueError( - "--share-all-embeddings requires --encoder-embed-dim to match --decoder-embed-dim" - ) - if args.decoder_embed_path and ( - args.decoder_embed_path != args.encoder_embed_path - ): - raise ValueError( - "--share-all-embeddings not compatible with --decoder-embed-path" - ) - encoder_embed_tokens = cls.build_embedding( - args, src_dict, args.encoder_embed_dim, args.encoder_embed_path - ) - decoder_embed_tokens = encoder_embed_tokens - args.share_decoder_input_output_embed = True - else: - encoder_embed_tokens = cls.build_embedding( - args, src_dict, args.encoder_embed_dim, args.encoder_embed_path - ) - decoder_embed_tokens = cls.build_embedding( - args, tgt_dict, args.decoder_embed_dim, args.decoder_embed_path - ) - if getattr(args, "offload_activations", False): - args.checkpoint_activations = True # offloading implies checkpointing - encoder = cls.build_encoder(args, src_dict, encoder_embed_tokens) - decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens) - if not args.share_all_embeddings: - min_params_to_wrap = getattr( - args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP - ) - # fsdp_wrap is a no-op when --ddp-backend != fully_sharded - encoder = fsdp_wrap(encoder, min_num_params=min_params_to_wrap) - decoder = fsdp_wrap(decoder, min_num_params=min_params_to_wrap) - return cls(args, encoder, decoder) - - @classmethod - def build_embedding(cls, args, dictionary, embed_dim, path=None): - num_embeddings = len(dictionary) - padding_idx = dictionary.pad() - - emb = Embedding(num_embeddings, embed_dim, padding_idx) - # if provided, load from preloaded dictionaries - if path: - embed_dict = utils.parse_embedding(path) - utils.load_embedding(embed_dict, dictionary, emb) - return emb - - @classmethod - def build_encoder(cls, args, src_dict, embed_tokens): - return TransformerEncoder(args, src_dict, embed_tokens) - - @classmethod - def build_decoder(cls, args, tgt_dict, embed_tokens): - return TransformerDecoder( - args, - tgt_dict, - embed_tokens, - no_encoder_attn=getattr(args, "no_cross_attention", False), - ) - - # TorchScript doesn't support optional arguments with variable length (**kwargs). - # Current workaround is to add union of all arguments in child classes. - def forward( - self, - src_tokens, - src_lengths, - prev_output_tokens, - return_all_hiddens: bool = True, - features_only: bool = False, - alignment_layer: Optional[int] = None, - alignment_heads: Optional[int] = None, - ): - """ - Run the forward pass for an encoder-decoder model. - - Copied from the base class, but without ``**kwargs``, - which are not supported by TorchScript. - """ - encoder_out = self.encoder( - src_tokens, src_lengths=src_lengths, return_all_hiddens=return_all_hiddens - ) - decoder_out = self.decoder( - prev_output_tokens, - encoder_out=encoder_out, - features_only=features_only, - alignment_layer=alignment_layer, - alignment_heads=alignment_heads, - src_lengths=src_lengths, - return_all_hiddens=return_all_hiddens, - ) - return decoder_out - - # Since get_normalized_probs is in the Fairseq Model which is not scriptable, - # I rewrite the get_normalized_probs from Base Class to call the - # helper function in the Base Class. - @torch.jit.export - def get_normalized_probs( - self, - net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], - log_probs: bool, - sample: Optional[Dict[str, Tensor]] = None, - ): - """Get normalized probabilities (or log probs) from a net's output.""" - return self.get_normalized_probs_scriptable(net_output, log_probs, sample) - - -class TransformerEncoder(FairseqEncoder): - """ - Transformer encoder consisting of *args.encoder_layers* layers. Each layer - is a :class:`TransformerEncoderLayer`. - - Args: - args (argparse.Namespace): parsed command-line arguments - dictionary (~fairseq.data.Dictionary): encoding dictionary - embed_tokens (torch.nn.Embedding): input embedding - """ - - def __init__(self, args, dictionary, embed_tokens): - self.args = args - super().__init__(dictionary) - self.register_buffer("version", torch.Tensor([3])) - - self.dropout_module = FairseqDropout( - args.dropout, module_name=self.__class__.__name__ - ) - self.encoder_layerdrop = args.encoder_layerdrop - - embed_dim = embed_tokens.embedding_dim - self.padding_idx = embed_tokens.padding_idx - self.max_source_positions = args.max_source_positions - - self.embed_tokens = embed_tokens - - self.embed_scale = 1.0 if args.no_scale_embedding else math.sqrt(embed_dim) - - self.embed_positions = ( - PositionalEmbedding( - args.max_source_positions, - embed_dim, - self.padding_idx, - learned=args.encoder_learned_pos, - ) - if not args.no_token_positional_embeddings - else None - ) - export = getattr(args, "export", False) - if getattr(args, "layernorm_embedding", False): - self.layernorm_embedding = LayerNorm(embed_dim, export=export) - else: - self.layernorm_embedding = None - - if not args.adaptive_input and args.quant_noise_pq > 0: - self.quant_noise = apply_quant_noise_( - nn.Linear(embed_dim, embed_dim, bias=False), - args.quant_noise_pq, - args.quant_noise_pq_block_size, - ) - else: - self.quant_noise = None - - if self.encoder_layerdrop > 0.0: - self.layers = LayerDropModuleList(p=self.encoder_layerdrop) - else: - self.layers = nn.ModuleList([]) - self.layers.extend( - [self.build_encoder_layer(args) for i in range(args.encoder_layers)] - ) - self.num_layers = len(self.layers) - - if args.encoder_normalize_before: - self.layer_norm = LayerNorm(embed_dim, export=export) - else: - self.layer_norm = None - - def build_encoder_layer(self, args): - layer = TransformerEncoderLayer(args) - checkpoint = getattr(args, "checkpoint_activations", False) - if checkpoint: - offload_to_cpu = getattr(args, "offload_activations", False) - layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) - # if we are checkpointing, enforce that FSDP always wraps the - # checkpointed layer, regardless of layer size - min_params_to_wrap = ( - getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) - if not checkpoint - else 0 - ) - layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) - return layer - - def forward_embedding( - self, src_tokens, token_embedding: Optional[torch.Tensor] = None - ): - # embed tokens and positions - if token_embedding is None: - token_embedding = self.embed_tokens(src_tokens) - x = embed = self.embed_scale * token_embedding - if self.embed_positions is not None: - x = embed + self.embed_positions(src_tokens) - if self.layernorm_embedding is not None: - x = self.layernorm_embedding(x) - x = self.dropout_module(x) - if self.quant_noise is not None: - x = self.quant_noise(x) - return x, embed - - def forward( - self, - src_tokens, - src_lengths: Optional[torch.Tensor] = None, - return_all_hiddens: bool = False, - token_embeddings: Optional[torch.Tensor] = None, - ): - """ - Args: - src_tokens (LongTensor): tokens in the source language of shape - `(batch, src_len)` - src_lengths (torch.LongTensor): lengths of each source sentence of - shape `(batch)` - return_all_hiddens (bool, optional): also return all of the - intermediate hidden states (default: False). - token_embeddings (torch.Tensor, optional): precomputed embeddings - default `None` will recompute embeddings - - Returns: - dict: - - **encoder_out** (Tensor): the last encoder layer's output of - shape `(src_len, batch, embed_dim)` - - **encoder_padding_mask** (ByteTensor): the positions of - padding elements of shape `(batch, src_len)` - - **encoder_embedding** (Tensor): the (scaled) embedding lookup - of shape `(batch, src_len, embed_dim)` - - **encoder_states** (List[Tensor]): all intermediate - hidden states of shape `(src_len, batch, embed_dim)`. - Only populated if *return_all_hiddens* is True. - """ - return self.forward_scriptable( - src_tokens, src_lengths, return_all_hiddens, token_embeddings - ) - - # TorchScript doesn't support super() method so that the scriptable Subclass - # can't access the base class model in Torchscript. - # Current workaround is to add a helper function with different name and - # call the helper function from scriptable Subclass. - def forward_scriptable( - self, - src_tokens, - src_lengths: Optional[torch.Tensor] = None, - return_all_hiddens: bool = False, - token_embeddings: Optional[torch.Tensor] = None, - ): - """ - Args: - src_tokens (LongTensor): tokens in the source language of shape - `(batch, src_len)` - src_lengths (torch.LongTensor): lengths of each source sentence of - shape `(batch)` - return_all_hiddens (bool, optional): also return all of the - intermediate hidden states (default: False). - token_embeddings (torch.Tensor, optional): precomputed embeddings - default `None` will recompute embeddings - - Returns: - dict: - - **encoder_out** (Tensor): the last encoder layer's output of - shape `(src_len, batch, embed_dim)` - - **encoder_padding_mask** (ByteTensor): the positions of - padding elements of shape `(batch, src_len)` - - **encoder_embedding** (Tensor): the (scaled) embedding lookup - of shape `(batch, src_len, embed_dim)` - - **encoder_states** (List[Tensor]): all intermediate - hidden states of shape `(src_len, batch, embed_dim)`. - Only populated if *return_all_hiddens* is True. - """ - # compute padding mask - encoder_padding_mask = src_tokens.eq(self.padding_idx) - has_pads = src_tokens.device.type == "xla" or encoder_padding_mask.any() - - x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) - - # account for padding while computing the representation - if has_pads: - x = x * (1 - encoder_padding_mask.unsqueeze(-1).type_as(x)) - - # B x T x C -> T x B x C - x = x.transpose(0, 1) - - encoder_states = [] - - if return_all_hiddens: - encoder_states.append(x) - - # encoder layers - for layer in self.layers: - x = layer( - x, encoder_padding_mask=encoder_padding_mask if has_pads else None - ) - if return_all_hiddens: - assert encoder_states is not None - encoder_states.append(x) - - if self.layer_norm is not None: - x = self.layer_norm(x) - - # The Pytorch Mobile lite interpreter does not supports returning NamedTuple in - # `forward` so we use a dictionary instead. - # TorchScript does not support mixed values so the values are all lists. - # The empty list is equivalent to None. - src_lengths = src_tokens.ne(self.padding_idx).sum(dim=1, dtype=torch.int32).reshape(-1, 1).contiguous() - return { - "encoder_out": [x], # T x B x C - "encoder_padding_mask": [encoder_padding_mask], # B x T - "encoder_embedding": [encoder_embedding], # B x T x C - "encoder_states": encoder_states, # List[T x B x C] - "src_tokens": [], - "src_lengths": [src_lengths], - } - - @torch.jit.export - def reorder_encoder_out(self, encoder_out: Dict[str, List[Tensor]], new_order): - """ - Reorder encoder output according to *new_order*. - - Args: - encoder_out: output from the ``forward()`` method - new_order (LongTensor): desired order - - Returns: - *encoder_out* rearranged according to *new_order* - """ - if len(encoder_out["encoder_out"]) == 0: - new_encoder_out = [] - else: - new_encoder_out = [encoder_out["encoder_out"][0].index_select(1, new_order)] - if len(encoder_out["encoder_padding_mask"]) == 0: - new_encoder_padding_mask = [] - else: - new_encoder_padding_mask = [ - encoder_out["encoder_padding_mask"][0].index_select(0, new_order) - ] - if len(encoder_out["encoder_embedding"]) == 0: - new_encoder_embedding = [] - else: - new_encoder_embedding = [ - encoder_out["encoder_embedding"][0].index_select(0, new_order) - ] - - if len(encoder_out["src_tokens"]) == 0: - src_tokens = [] - else: - src_tokens = [(encoder_out["src_tokens"][0]).index_select(0, new_order)] - - if len(encoder_out["src_lengths"]) == 0: - src_lengths = [] - else: - src_lengths = [(encoder_out["src_lengths"][0]).index_select(0, new_order)] - - encoder_states = encoder_out["encoder_states"] - if len(encoder_states) > 0: - for idx, state in enumerate(encoder_states): - encoder_states[idx] = state.index_select(1, new_order) - - return { - "encoder_out": new_encoder_out, # T x B x C - "encoder_padding_mask": new_encoder_padding_mask, # B x T - "encoder_embedding": new_encoder_embedding, # B x T x C - "encoder_states": encoder_states, # List[T x B x C] - "src_tokens": src_tokens, # B x T - "src_lengths": src_lengths, # B x 1 - } - - def max_positions(self): - """Maximum input length supported by the encoder.""" - if self.embed_positions is None: - return self.max_source_positions - return min(self.max_source_positions, self.embed_positions.max_positions) - - def upgrade_state_dict_named(self, state_dict, name): - """Upgrade a (possibly old) state dict for new versions of fairseq.""" - if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): - weights_key = "{}.embed_positions.weights".format(name) - if weights_key in state_dict: - print("deleting {0}".format(weights_key)) - del state_dict[weights_key] - state_dict[ - "{}.embed_positions._float_tensor".format(name) - ] = torch.FloatTensor(1) - for i in range(self.num_layers): - # update layer norms - self.layers[i].upgrade_state_dict_named( - state_dict, "{}.layers.{}".format(name, i) - ) - - version_key = "{}.version".format(name) - if utils.item(state_dict.get(version_key, torch.Tensor([1]))[0]) < 2: - # earlier checkpoints did not normalize after the stack of layers - self.layer_norm = None - self.normalize = False - state_dict[version_key] = torch.Tensor([1]) - return state_dict - - -class TransformerDecoder(FairseqIncrementalDecoder): - """ - Transformer decoder consisting of *args.decoder_layers* layers. Each layer - is a :class:`TransformerDecoderLayer`. - - Args: - args (argparse.Namespace): parsed command-line arguments - dictionary (~fairseq.data.Dictionary): decoding dictionary - embed_tokens (torch.nn.Embedding): output embedding - no_encoder_attn (bool, optional): whether to attend to encoder outputs - (default: False). - """ - - def __init__( - self, - args, - dictionary, - embed_tokens, - no_encoder_attn=False, - output_projection=None, - ): - self.args = args - super().__init__(dictionary) - self.register_buffer("version", torch.Tensor([3])) - self._future_mask = torch.empty(0) - - self.dropout_module = FairseqDropout( - args.dropout, module_name=self.__class__.__name__ - ) - self.decoder_layerdrop = args.decoder_layerdrop - self.share_input_output_embed = args.share_decoder_input_output_embed - - input_embed_dim = embed_tokens.embedding_dim - embed_dim = args.decoder_embed_dim - self.embed_dim = embed_dim - self.output_embed_dim = args.decoder_output_dim - - self.padding_idx = embed_tokens.padding_idx - self.max_target_positions = args.max_target_positions - - self.embed_tokens = embed_tokens - - self.embed_scale = 1.0 if args.no_scale_embedding else math.sqrt(embed_dim) - - if not args.adaptive_input and args.quant_noise_pq > 0: - self.quant_noise = apply_quant_noise_( - nn.Linear(embed_dim, embed_dim, bias=False), - args.quant_noise_pq, - args.quant_noise_pq_block_size, - ) - else: - self.quant_noise = None - - self.project_in_dim = ( - Linear(input_embed_dim, embed_dim, bias=False) - if embed_dim != input_embed_dim - else None - ) - self.embed_positions = ( - PositionalEmbedding( - self.max_target_positions, - embed_dim, - self.padding_idx, - learned=args.decoder_learned_pos, - ) - if not args.no_token_positional_embeddings - else None - ) - export = getattr(args, "export", False) - if getattr(args, "layernorm_embedding", False): - self.layernorm_embedding = LayerNorm(embed_dim, export=export) - else: - self.layernorm_embedding = None - - self.cross_self_attention = getattr(args, "cross_self_attention", False) - - if self.decoder_layerdrop > 0.0: - self.layers = LayerDropModuleList(p=self.decoder_layerdrop) - else: - self.layers = nn.ModuleList([]) - self.layers.extend( - [ - self.build_decoder_layer(args, no_encoder_attn) - for _ in range(args.decoder_layers) - ] - ) - self.num_layers = len(self.layers) - - if args.decoder_normalize_before and not getattr( - args, "no_decoder_final_norm", False - ): - self.layer_norm = LayerNorm(embed_dim, export=export) - else: - self.layer_norm = None - - self.project_out_dim = ( - Linear(embed_dim, self.output_embed_dim, bias=False) - if embed_dim != self.output_embed_dim and not args.tie_adaptive_weights - else None - ) - - self.adaptive_softmax = None - self.output_projection = output_projection - if self.output_projection is None: - self.build_output_projection(args, dictionary, embed_tokens) - - def build_output_projection(self, args, dictionary, embed_tokens): - if args.adaptive_softmax_cutoff is not None: - self.adaptive_softmax = AdaptiveSoftmax( - len(dictionary), - self.output_embed_dim, - utils.eval_str_list(args.adaptive_softmax_cutoff, type=int), - dropout=args.adaptive_softmax_dropout, - adaptive_inputs=embed_tokens if args.tie_adaptive_weights else None, - factor=args.adaptive_softmax_factor, - tie_proj=args.tie_adaptive_proj, - ) - elif self.share_input_output_embed: - self.output_projection = nn.Linear( - self.embed_tokens.weight.shape[1], - self.embed_tokens.weight.shape[0], - bias=False, - ) - self.output_projection.weight = self.embed_tokens.weight - else: - self.output_projection = nn.Linear( - self.output_embed_dim, len(dictionary), bias=False - ) - nn.init.normal_( - self.output_projection.weight, mean=0, std=self.output_embed_dim ** -0.5 - ) - num_base_layers = getattr(args, "base_layers", 0) - for i in range(num_base_layers): - self.layers.insert( - ((i + 1) * args.decoder_layers) // (num_base_layers + 1), - BaseLayer(args), - ) - - def build_decoder_layer(self, args, no_encoder_attn=False): - layer = TransformerDecoderLayer(args, no_encoder_attn) - checkpoint = getattr(args, "checkpoint_activations", False) - if checkpoint: - offload_to_cpu = getattr(args, "offload_activations", False) - layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) - # if we are checkpointing, enforce that FSDP always wraps the - # checkpointed layer, regardless of layer size - min_params_to_wrap = ( - getattr(args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP) - if not checkpoint - else 0 - ) - layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) - return layer - - def forward( - self, - prev_output_tokens, - encoder_out: Optional[Dict[str, List[Tensor]]] = None, - incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, - features_only: bool = False, - full_context_alignment: bool = False, - alignment_layer: Optional[int] = None, - alignment_heads: Optional[int] = None, - src_lengths: Optional[Any] = None, - return_all_hiddens: bool = False, - ): - """ - Args: - prev_output_tokens (LongTensor): previous decoder outputs of shape - `(batch, tgt_len)`, for teacher forcing - encoder_out (optional): output from the encoder, used for - encoder-side attention, should be of size T x B x C - incremental_state (dict): dictionary used for storing state during - :ref:`Incremental decoding` - features_only (bool, optional): only return features without - applying output layer (default: False). - full_context_alignment (bool, optional): don't apply - auto-regressive mask to self-attention (default: False). - - Returns: - tuple: - - the decoder's output of shape `(batch, tgt_len, vocab)` - - a dictionary with any model-specific outputs - """ - - x, extra = self.extract_features( - prev_output_tokens, - encoder_out=encoder_out, - incremental_state=incremental_state, - full_context_alignment=full_context_alignment, - alignment_layer=alignment_layer, - alignment_heads=alignment_heads, - ) - - if not features_only: - x = self.output_layer(x) - return x, extra - - def extract_features( - self, - prev_output_tokens, - encoder_out: Optional[Dict[str, List[Tensor]]], - incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, - full_context_alignment: bool = False, - alignment_layer: Optional[int] = None, - alignment_heads: Optional[int] = None, - ): - return self.extract_features_scriptable( - prev_output_tokens, - encoder_out, - incremental_state, - full_context_alignment, - alignment_layer, - alignment_heads, - ) - - """ - A scriptable subclass of this class has an extract_features method and calls - super().extract_features, but super() is not supported in torchscript. A copy of - this function is made to be used in the subclass instead. - """ - - def extract_features_scriptable( - self, - prev_output_tokens, - encoder_out: Optional[Dict[str, List[Tensor]]], - incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, - full_context_alignment: bool = False, - alignment_layer: Optional[int] = None, - alignment_heads: Optional[int] = None, - ): - """ - Similar to *forward* but only return features. - - Includes several features from "Jointly Learning to Align and - Translate with Transformer Models" (Garg et al., EMNLP 2019). - - Args: - full_context_alignment (bool, optional): don't apply - auto-regressive mask to self-attention (default: False). - alignment_layer (int, optional): return mean alignment over - heads at this layer (default: last layer). - alignment_heads (int, optional): only average alignment over - this many heads (default: all heads). - - Returns: - tuple: - - the decoder's features of shape `(batch, tgt_len, embed_dim)` - - a dictionary with any model-specific outputs - """ - bs, slen = prev_output_tokens.size() - if alignment_layer is None: - alignment_layer = self.num_layers - 1 - - enc: Optional[Tensor] = None - padding_mask: Optional[Tensor] = None - if encoder_out is not None and len(encoder_out["encoder_out"]) > 0: - enc = encoder_out["encoder_out"][0] - assert ( - enc.size()[1] == bs - ), f"Expected enc.shape == (t, {bs}, c) got {enc.shape}" - if encoder_out is not None and len(encoder_out["encoder_padding_mask"]) > 0: - padding_mask = encoder_out["encoder_padding_mask"][0] - - # embed positions - positions = None - if self.embed_positions is not None: - positions = self.embed_positions( - prev_output_tokens, incremental_state=incremental_state - ) - - if incremental_state is not None: - prev_output_tokens = prev_output_tokens[:, -1:] - if positions is not None: - positions = positions[:, -1:] - - # embed tokens and positions - x = self.embed_scale * self.embed_tokens(prev_output_tokens) - - if self.quant_noise is not None: - x = self.quant_noise(x) - - if self.project_in_dim is not None: - x = self.project_in_dim(x) - - if positions is not None: - x += positions - - if self.layernorm_embedding is not None: - x = self.layernorm_embedding(x) - - x = self.dropout_module(x) - - # B x T x C -> T x B x C - x = x.transpose(0, 1) - - self_attn_padding_mask: Optional[Tensor] = None - if self.cross_self_attention or prev_output_tokens.eq(self.padding_idx).any(): - self_attn_padding_mask = prev_output_tokens.eq(self.padding_idx) - - # decoder layers - attn: Optional[Tensor] = None - inner_states: List[Optional[Tensor]] = [x] - for idx, layer in enumerate(self.layers): - if incremental_state is None and not full_context_alignment: - self_attn_mask = self.buffered_future_mask(x) - else: - self_attn_mask = None - - x, layer_attn, _ = layer( - x, - enc, - padding_mask, - incremental_state, - self_attn_mask=self_attn_mask, - self_attn_padding_mask=self_attn_padding_mask, - need_attn=bool((idx == alignment_layer)), - need_head_weights=bool((idx == alignment_layer)), - ) - inner_states.append(x) - if layer_attn is not None and idx == alignment_layer: - attn = layer_attn.float().to(x) - - if attn is not None: - if alignment_heads is not None: - attn = attn[:alignment_heads] - - # average probabilities over heads - attn = attn.mean(dim=0) - - if self.layer_norm is not None: - x = self.layer_norm(x) - - # T x B x C -> B x T x C - x = x.transpose(0, 1) - - if self.project_out_dim is not None: - x = self.project_out_dim(x) - - return x, {"attn": [attn], "inner_states": inner_states} - - def output_layer(self, features): - """Project features to the vocabulary size.""" - if self.adaptive_softmax is None: - # project back to size of vocabulary - return self.output_projection(features) - else: - return features - - def max_positions(self): - """Maximum output length supported by the decoder.""" - if self.embed_positions is None: - return self.max_target_positions - return min(self.max_target_positions, self.embed_positions.max_positions) - - def buffered_future_mask(self, tensor): - dim = tensor.size(0) - # self._future_mask.device != tensor.device is not working in TorchScript. This is a workaround. - if ( - self._future_mask.size(0) == 0 - or (not self._future_mask.device == tensor.device) - or self._future_mask.size(0) < dim - ): - self._future_mask = torch.triu( - utils.fill_with_neg_inf(torch.zeros([dim, dim])), 1 - ) - self._future_mask = self._future_mask.to(tensor) - return self._future_mask[:dim, :dim] - - def upgrade_state_dict_named(self, state_dict, name): - """Upgrade a (possibly old) state dict for new versions of fairseq.""" - if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): - weights_key = "{}.embed_positions.weights".format(name) - if weights_key in state_dict: - del state_dict[weights_key] - state_dict[ - "{}.embed_positions._float_tensor".format(name) - ] = torch.FloatTensor(1) - - if f"{name}.output_projection.weight" not in state_dict: - if self.share_input_output_embed: - embed_out_key = f"{name}.embed_tokens.weight" - else: - embed_out_key = f"{name}.embed_out" - if embed_out_key in state_dict: - state_dict[f"{name}.output_projection.weight"] = state_dict[ - embed_out_key - ] - if not self.share_input_output_embed: - del state_dict[embed_out_key] - - for i in range(self.num_layers): - # update layer norms - layer_norm_map = { - "0": "self_attn_layer_norm", - "1": "encoder_attn_layer_norm", - "2": "final_layer_norm", - } - for old, new in layer_norm_map.items(): - for m in ("weight", "bias"): - k = "{}.layers.{}.layer_norms.{}.{}".format(name, i, old, m) - if k in state_dict: - state_dict[ - "{}.layers.{}.{}.{}".format(name, i, new, m) - ] = state_dict[k] - del state_dict[k] - - version_key = "{}.version".format(name) - if utils.item(state_dict.get(version_key, torch.Tensor([1]))[0]) <= 2: - # earlier checkpoints did not normalize after the stack of layers - self.layer_norm = None - self.normalize = False - state_dict[version_key] = torch.Tensor([1]) - - return state_dict - - -def Embedding(num_embeddings, embedding_dim, padding_idx): - m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) - nn.init.constant_(m.weight[padding_idx], 0) - return m - - -def Linear(in_features, out_features, bias=True): - m = nn.Linear(in_features, out_features, bias) - nn.init.xavier_uniform_(m.weight) - if bias: - nn.init.constant_(m.bias, 0.0) - return m - - -@register_model_architecture("transformer", "transformer_tiny") -def tiny_architecture(args): - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 64) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 64) - args.encoder_layers = getattr(args, "encoder_layers", 2) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 2) - args.decoder_layers = getattr(args, "decoder_layers", 2) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 2) - return base_architecture(args) - - -@register_model_architecture("transformer", "transformer") -def base_architecture(args): - args.encoder_embed_path = getattr(args, "encoder_embed_path", None) - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) - args.encoder_layers = getattr(args, "encoder_layers", 6) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 8) - args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) - args.encoder_learned_pos = getattr(args, "encoder_learned_pos", False) - args.decoder_embed_path = getattr(args, "decoder_embed_path", None) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) - args.decoder_ffn_embed_dim = getattr( - args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim - ) - args.decoder_layers = getattr(args, "decoder_layers", 6) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) - args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) - args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) - args.attention_dropout = getattr(args, "attention_dropout", 0.0) - args.activation_dropout = getattr(args, "activation_dropout", 0.0) - args.activation_fn = getattr(args, "activation_fn", "relu") - args.dropout = getattr(args, "dropout", 0.1) - args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) - args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) - args.share_decoder_input_output_embed = getattr( - args, "share_decoder_input_output_embed", False - ) - args.share_all_embeddings = getattr(args, "share_all_embeddings", False) - args.no_token_positional_embeddings = getattr( - args, "no_token_positional_embeddings", False - ) - args.adaptive_input = getattr(args, "adaptive_input", False) - args.no_cross_attention = getattr(args, "no_cross_attention", False) - args.cross_self_attention = getattr(args, "cross_self_attention", False) - - args.decoder_output_dim = getattr( - args, "decoder_output_dim", args.decoder_embed_dim - ) - args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) - - args.no_scale_embedding = getattr(args, "no_scale_embedding", False) - args.layernorm_embedding = getattr(args, "layernorm_embedding", False) - args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) - args.checkpoint_activations = getattr(args, "checkpoint_activations", False) - args.offload_activations = getattr(args, "offload_activations", False) - if args.offload_activations: - args.checkpoint_activations = True - args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) - args.decoder_layers_to_keep = getattr(args, "decoder_layers_to_keep", None) - args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0) - args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0) - args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) - args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8) - args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0) - - -@register_model_architecture("transformer", "transformer_iwslt_de_en") -def transformer_iwslt_de_en(args): - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 1024) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) - args.encoder_layers = getattr(args, "encoder_layers", 6) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 1024) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) - args.decoder_layers = getattr(args, "decoder_layers", 6) - base_architecture(args) - - -@register_model_architecture("transformer", "transformer_wmt_en_de") -def transformer_wmt_en_de(args): - base_architecture(args) - - -# parameters used in the "Attention Is All You Need" paper (Vaswani et al., 2017) -@register_model_architecture("transformer", "transformer_vaswani_wmt_en_de_big") -def transformer_vaswani_wmt_en_de_big(args): - args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096) - args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) - args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4096) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) - args.dropout = getattr(args, "dropout", 0.3) - base_architecture(args) - - -@register_model_architecture("transformer", "transformer_vaswani_wmt_en_fr_big") -def transformer_vaswani_wmt_en_fr_big(args): - args.dropout = getattr(args, "dropout", 0.1) - transformer_vaswani_wmt_en_de_big(args) - - -@register_model_architecture("transformer", "transformer_wmt_en_de_big") -def transformer_wmt_en_de_big(args): - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - transformer_vaswani_wmt_en_de_big(args) - - -# default parameters used in tensor2tensor implementation -@register_model_architecture("transformer", "transformer_wmt_en_de_big_t2t") -def transformer_wmt_en_de_big_t2t(args): - args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) - args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_dropout = getattr(args, "activation_dropout", 0.1) - transformer_vaswani_wmt_en_de_big(args) diff --git a/fairseq/models/transformer/__init__.py b/fairseq/models/transformer/__init__.py new file mode 100644 index 0000000000..6809adeab7 --- /dev/null +++ b/fairseq/models/transformer/__init__.py @@ -0,0 +1,44 @@ +# Copyright (c) Facebook Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +"""isort:skip_file""" + +from .transformer_decoder import TransformerDecoder, Linear +from .transformer_encoder import TransformerEncoder +from .transformer_model import ( + DEFAULT_MAX_SOURCE_POSITIONS, + DEFAULT_MAX_TARGET_POSITIONS, + DEFAULT_MIN_PARAMS_TO_WRAP, + TransformerModel, + base_architecture, + tiny_architecture, + transformer_iwslt_de_en, + transformer_wmt_en_de, + transformer_vaswani_wmt_en_de_big, + transformer_vaswani_wmt_en_fr_big, + transformer_wmt_en_de_big, + transformer_wmt_en_de_big_t2t, + Embedding, +) + + +__all__ = [ + "TransformerConfig", + "TransformerDecoder", + "TransformerEncoder", + "TransformerModel", + "Embedding", + "Linear", + "base_architecture", + "tiny_architecture", + "transformer_iwslt_de_en", + "transformer_wmt_en_de", + "transformer_vaswani_wmt_en_de_big", + "transformer_vaswani_wmt_en_fr_big", + "transformer_wmt_en_de_big", + "transformer_wmt_en_de_big_t2t", + "DEFAULT_MAX_SOURCE_POSITIONS", + "DEFAULT_MAX_TARGET_POSITIONS", + "DEFAULT_MIN_PARAMS_TO_WRAP", +] diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py new file mode 100644 index 0000000000..ca9e737e60 --- /dev/null +++ b/fairseq/models/transformer/transformer_decoder.py @@ -0,0 +1,452 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Any, Dict, List, Optional + +import torch +import torch.nn as nn +from fairseq import utils +from fairseq.distributed import fsdp_wrap +from fairseq.models import FairseqIncrementalDecoder +from fairseq.models.transformer import transformer_model +from fairseq.modules import ( + AdaptiveSoftmax, + BaseLayer, + FairseqDropout, + LayerDropModuleList, + LayerNorm, + PositionalEmbedding, + SinusoidalPositionalEmbedding, +) +from fairseq.modules import transformer_layer +from fairseq.modules.checkpoint_activations import checkpoint_wrapper +from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ +from torch import Tensor + + +class TransformerDecoder(FairseqIncrementalDecoder): + """ + Transformer decoder consisting of *args.decoder_layers* layers. Each layer + is a :class:`TransformerDecoderLayer`. + + Args: + args (argparse.Namespace): parsed command-line arguments + dictionary (~fairseq.data.Dictionary): decoding dictionary + embed_tokens (torch.nn.Embedding): output embedding + no_encoder_attn (bool, optional): whether to attend to encoder outputs + (default: False). + """ + + def __init__( + self, + args, + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=None, + ): + self.args = args + super().__init__(dictionary) + self.register_buffer("version", torch.Tensor([3])) + self._future_mask = torch.empty(0) + + self.dropout_module = FairseqDropout( + args.dropout, module_name=self.__class__.__name__ + ) + self.decoder_layerdrop = args.decoder_layerdrop + self.share_input_output_embed = args.share_decoder_input_output_embed + + input_embed_dim = embed_tokens.embedding_dim + embed_dim = args.decoder_embed_dim + self.embed_dim = embed_dim + self.output_embed_dim = args.decoder_output_dim + + self.padding_idx = embed_tokens.padding_idx + self.max_target_positions = args.max_target_positions + + self.embed_tokens = embed_tokens + + self.embed_scale = 1.0 if args.no_scale_embedding else math.sqrt(embed_dim) + + if not args.adaptive_input and args.quant_noise_pq > 0: + self.quant_noise = apply_quant_noise_( + nn.Linear(embed_dim, embed_dim, bias=False), + args.quant_noise_pq, + args.quant_noise_pq_block_size, + ) + else: + self.quant_noise = None + + self.project_in_dim = ( + Linear(input_embed_dim, embed_dim, bias=False) + if embed_dim != input_embed_dim + else None + ) + self.embed_positions = ( + PositionalEmbedding( + self.max_target_positions, + embed_dim, + self.padding_idx, + learned=args.decoder_learned_pos, + ) + if not args.no_token_positional_embeddings + else None + ) + export = getattr(args, "export", False) + if getattr(args, "layernorm_embedding", False): + self.layernorm_embedding = LayerNorm(embed_dim, export=export) + else: + self.layernorm_embedding = None + + self.cross_self_attention = getattr(args, "cross_self_attention", False) + + if self.decoder_layerdrop > 0.0: + self.layers = LayerDropModuleList(p=self.decoder_layerdrop) + else: + self.layers = nn.ModuleList([]) + self.layers.extend( + [ + self.build_decoder_layer(args, no_encoder_attn) + for _ in range(args.decoder_layers) + ] + ) + self.num_layers = len(self.layers) + + if args.decoder_normalize_before and not getattr( + args, "no_decoder_final_norm", False + ): + self.layer_norm = LayerNorm(embed_dim, export=export) + else: + self.layer_norm = None + + self.project_out_dim = ( + Linear(embed_dim, self.output_embed_dim, bias=False) + if embed_dim != self.output_embed_dim and not args.tie_adaptive_weights + else None + ) + + self.adaptive_softmax = None + self.output_projection = output_projection + if self.output_projection is None: + self.build_output_projection(args, dictionary, embed_tokens) + + def build_output_projection(self, args, dictionary, embed_tokens): + if args.adaptive_softmax_cutoff is not None: + self.adaptive_softmax = AdaptiveSoftmax( + len(dictionary), + self.output_embed_dim, + utils.eval_str_list(args.adaptive_softmax_cutoff, type=int), + dropout=args.adaptive_softmax_dropout, + adaptive_inputs=embed_tokens if args.tie_adaptive_weights else None, + factor=args.adaptive_softmax_factor, + tie_proj=args.tie_adaptive_proj, + ) + elif self.share_input_output_embed: + self.output_projection = nn.Linear( + self.embed_tokens.weight.shape[1], + self.embed_tokens.weight.shape[0], + bias=False, + ) + self.output_projection.weight = self.embed_tokens.weight + else: + self.output_projection = nn.Linear( + self.output_embed_dim, len(dictionary), bias=False + ) + nn.init.normal_( + self.output_projection.weight, mean=0, std=self.output_embed_dim ** -0.5 + ) + num_base_layers = getattr(args, "base_layers", 0) + for i in range(num_base_layers): + self.layers.insert( + ((i + 1) * args.decoder_layers) // (num_base_layers + 1), + BaseLayer(args), + ) + + def build_decoder_layer(self, args, no_encoder_attn=False): + layer = transformer_layer.TransformerDecoderLayer(args, no_encoder_attn) + checkpoint = getattr(args, "checkpoint_activations", False) + if checkpoint: + offload_to_cpu = getattr(args, "offload_activations", False) + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + # if we are checkpointing, enforce that FSDP always wraps the + # checkpointed layer, regardless of layer size + min_params_to_wrap = ( + getattr(args, "min_params_to_wrap", transformer_model.DEFAULT_MIN_PARAMS_TO_WRAP) + if not checkpoint + else 0 + ) + layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) + return layer + + def forward( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + features_only: bool = False, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + src_lengths: Optional[Any] = None, + return_all_hiddens: bool = False, + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + encoder_out (optional): output from the encoder, used for + encoder-side attention, should be of size T x B x C + incremental_state (dict): dictionary used for storing state during + :ref:`Incremental decoding` + features_only (bool, optional): only return features without + applying output layer (default: False). + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + + x, extra = self.extract_features( + prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + full_context_alignment=full_context_alignment, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + ) + + if not features_only: + x = self.output_layer(x) + return x, extra + + def extract_features( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + return self.extract_features_scriptable( + prev_output_tokens, + encoder_out, + incremental_state, + full_context_alignment, + alignment_layer, + alignment_heads, + ) + + """ + A scriptable subclass of this class has an extract_features method and calls + super().extract_features, but super() is not supported in torchscript. A copy of + this function is made to be used in the subclass instead. + """ + + def extract_features_scriptable( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + """ + Similar to *forward* but only return features. + + Includes several features from "Jointly Learning to Align and + Translate with Transformer Models" (Garg et al., EMNLP 2019). + + Args: + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + alignment_layer (int, optional): return mean alignment over + heads at this layer (default: last layer). + alignment_heads (int, optional): only average alignment over + this many heads (default: all heads). + + Returns: + tuple: + - the decoder's features of shape `(batch, tgt_len, embed_dim)` + - a dictionary with any model-specific outputs + """ + bs, slen = prev_output_tokens.size() + if alignment_layer is None: + alignment_layer = self.num_layers - 1 + + enc: Optional[Tensor] = None + padding_mask: Optional[Tensor] = None + if encoder_out is not None and len(encoder_out["encoder_out"]) > 0: + enc = encoder_out["encoder_out"][0] + assert ( + enc.size()[1] == bs + ), f"Expected enc.shape == (t, {bs}, c) got {enc.shape}" + if encoder_out is not None and len(encoder_out["encoder_padding_mask"]) > 0: + padding_mask = encoder_out["encoder_padding_mask"][0] + + # embed positions + positions = None + if self.embed_positions is not None: + positions = self.embed_positions( + prev_output_tokens, incremental_state=incremental_state + ) + + if incremental_state is not None: + prev_output_tokens = prev_output_tokens[:, -1:] + if positions is not None: + positions = positions[:, -1:] + + # embed tokens and positions + x = self.embed_scale * self.embed_tokens(prev_output_tokens) + + if self.quant_noise is not None: + x = self.quant_noise(x) + + if self.project_in_dim is not None: + x = self.project_in_dim(x) + + if positions is not None: + x += positions + + if self.layernorm_embedding is not None: + x = self.layernorm_embedding(x) + + x = self.dropout_module(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + self_attn_padding_mask: Optional[Tensor] = None + if self.cross_self_attention or prev_output_tokens.eq(self.padding_idx).any(): + self_attn_padding_mask = prev_output_tokens.eq(self.padding_idx) + + # decoder layers + attn: Optional[Tensor] = None + inner_states: List[Optional[Tensor]] = [x] + for idx, layer in enumerate(self.layers): + if incremental_state is None and not full_context_alignment: + self_attn_mask = self.buffered_future_mask(x) + else: + self_attn_mask = None + + x, layer_attn, _ = layer( + x, + enc, + padding_mask, + incremental_state, + self_attn_mask=self_attn_mask, + self_attn_padding_mask=self_attn_padding_mask, + need_attn=bool((idx == alignment_layer)), + need_head_weights=bool((idx == alignment_layer)), + ) + inner_states.append(x) + if layer_attn is not None and idx == alignment_layer: + attn = layer_attn.float().to(x) + + if attn is not None: + if alignment_heads is not None: + attn = attn[:alignment_heads] + + # average probabilities over heads + attn = attn.mean(dim=0) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + if self.project_out_dim is not None: + x = self.project_out_dim(x) + + return x, {"attn": [attn], "inner_states": inner_states} + + def output_layer(self, features): + """Project features to the vocabulary size.""" + if self.adaptive_softmax is None: + # project back to size of vocabulary + return self.output_projection(features) + else: + return features + + def max_positions(self): + """Maximum output length supported by the decoder.""" + if self.embed_positions is None: + return self.max_target_positions + return min(self.max_target_positions, self.embed_positions.max_positions) + + def buffered_future_mask(self, tensor): + dim = tensor.size(0) + # self._future_mask.device != tensor.device is not working in TorchScript. This is a workaround. + if ( + self._future_mask.size(0) == 0 + or (not self._future_mask.device == tensor.device) + or self._future_mask.size(0) < dim + ): + self._future_mask = torch.triu( + utils.fill_with_neg_inf(torch.zeros([dim, dim])), 1 + ) + self._future_mask = self._future_mask.to(tensor) + return self._future_mask[:dim, :dim] + + def upgrade_state_dict_named(self, state_dict, name): + """Upgrade a (possibly old) state dict for new versions of fairseq.""" + if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): + weights_key = "{}.embed_positions.weights".format(name) + if weights_key in state_dict: + del state_dict[weights_key] + state_dict[ + "{}.embed_positions._float_tensor".format(name) + ] = torch.FloatTensor(1) + + if f"{name}.output_projection.weight" not in state_dict: + if self.share_input_output_embed: + embed_out_key = f"{name}.embed_tokens.weight" + else: + embed_out_key = f"{name}.embed_out" + if embed_out_key in state_dict: + state_dict[f"{name}.output_projection.weight"] = state_dict[ + embed_out_key + ] + if not self.share_input_output_embed: + del state_dict[embed_out_key] + + for i in range(self.num_layers): + # update layer norms + layer_norm_map = { + "0": "self_attn_layer_norm", + "1": "encoder_attn_layer_norm", + "2": "final_layer_norm", + } + for old, new in layer_norm_map.items(): + for m in ("weight", "bias"): + k = "{}.layers.{}.layer_norms.{}.{}".format(name, i, old, m) + if k in state_dict: + state_dict[ + "{}.layers.{}.{}.{}".format(name, i, new, m) + ] = state_dict[k] + del state_dict[k] + + version_key = "{}.version".format(name) + if utils.item(state_dict.get(version_key, torch.Tensor([1]))[0]) <= 2: + # earlier checkpoints did not normalize after the stack of layers + self.layer_norm = None + self.normalize = False + state_dict[version_key] = torch.Tensor([1]) + + return state_dict + + +def Linear(in_features, out_features, bias=True): + m = nn.Linear(in_features, out_features, bias) + nn.init.xavier_uniform_(m.weight) + if bias: + nn.init.constant_(m.bias, 0.0) + return m diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py new file mode 100644 index 0000000000..6e57af5433 --- /dev/null +++ b/fairseq/models/transformer/transformer_encoder.py @@ -0,0 +1,322 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import math +from typing import Dict, List, Optional + +import torch +import torch.nn as nn +from fairseq import utils +from fairseq.distributed import fsdp_wrap +from fairseq.models import FairseqEncoder +from fairseq.modules import ( + FairseqDropout, + LayerDropModuleList, + LayerNorm, + PositionalEmbedding, + SinusoidalPositionalEmbedding, +) +from fairseq.modules.transformer_layer import TransformerEncoderLayer +from fairseq.modules.checkpoint_activations import checkpoint_wrapper +from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ +from torch import Tensor +from fairseq.models.transformer import transformer_model + + +class TransformerEncoder(FairseqEncoder): + """ + Transformer encoder consisting of *args.encoder_layers* layers. Each layer + is a :class:`TransformerEncoderLayer`. + + Args: + args (argparse.Namespace): parsed command-line arguments + dictionary (~fairseq.data.Dictionary): encoding dictionary + embed_tokens (torch.nn.Embedding): input embedding + """ + + def __init__(self, args, dictionary, embed_tokens): + self.args = args + super().__init__(dictionary) + self.register_buffer("version", torch.Tensor([3])) + + self.dropout_module = FairseqDropout( + args.dropout, module_name=self.__class__.__name__ + ) + self.encoder_layerdrop = args.encoder_layerdrop + + embed_dim = embed_tokens.embedding_dim + self.padding_idx = embed_tokens.padding_idx + self.max_source_positions = args.max_source_positions + + self.embed_tokens = embed_tokens + + self.embed_scale = 1.0 if args.no_scale_embedding else math.sqrt(embed_dim) + + self.embed_positions = ( + PositionalEmbedding( + args.max_source_positions, + embed_dim, + self.padding_idx, + learned=args.encoder_learned_pos, + ) + if not args.no_token_positional_embeddings + else None + ) + export = getattr(args, "export", False) + if getattr(args, "layernorm_embedding", False): + self.layernorm_embedding = LayerNorm(embed_dim, export=export) + else: + self.layernorm_embedding = None + + if not args.adaptive_input and args.quant_noise_pq > 0: + self.quant_noise = apply_quant_noise_( + nn.Linear(embed_dim, embed_dim, bias=False), + args.quant_noise_pq, + args.quant_noise_pq_block_size, + ) + else: + self.quant_noise = None + + if self.encoder_layerdrop > 0.0: + self.layers = LayerDropModuleList(p=self.encoder_layerdrop) + else: + self.layers = nn.ModuleList([]) + self.layers.extend( + [self.build_encoder_layer(args) for i in range(args.encoder_layers)] + ) + self.num_layers = len(self.layers) + + if args.encoder_normalize_before: + self.layer_norm = LayerNorm(embed_dim, export=export) + else: + self.layer_norm = None + + def build_encoder_layer(self, args): + layer = TransformerEncoderLayer(args) + checkpoint = getattr(args, "checkpoint_activations", False) + if checkpoint: + offload_to_cpu = getattr(args, "offload_activations", False) + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + # if we are checkpointing, enforce that FSDP always wraps the + # checkpointed layer, regardless of layer size + min_params_to_wrap = ( + getattr(args, "min_params_to_wrap", transformer_model.DEFAULT_MIN_PARAMS_TO_WRAP) + if not checkpoint + else 0 + ) + layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) + return layer + + def forward_embedding( + self, src_tokens, token_embedding: Optional[torch.Tensor] = None + ): + # embed tokens and positions + if token_embedding is None: + token_embedding = self.embed_tokens(src_tokens) + x = embed = self.embed_scale * token_embedding + if self.embed_positions is not None: + x = embed + self.embed_positions(src_tokens) + if self.layernorm_embedding is not None: + x = self.layernorm_embedding(x) + x = self.dropout_module(x) + if self.quant_noise is not None: + x = self.quant_noise(x) + return x, embed + + def forward( + self, + src_tokens, + src_lengths: Optional[torch.Tensor] = None, + return_all_hiddens: bool = False, + token_embeddings: Optional[torch.Tensor] = None, + ): + """ + Args: + src_tokens (LongTensor): tokens in the source language of shape + `(batch, src_len)` + src_lengths (torch.LongTensor): lengths of each source sentence of + shape `(batch)` + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + token_embeddings (torch.Tensor, optional): precomputed embeddings + default `None` will recompute embeddings + + Returns: + dict: + - **encoder_out** (Tensor): the last encoder layer's output of + shape `(src_len, batch, embed_dim)` + - **encoder_padding_mask** (ByteTensor): the positions of + padding elements of shape `(batch, src_len)` + - **encoder_embedding** (Tensor): the (scaled) embedding lookup + of shape `(batch, src_len, embed_dim)` + - **encoder_states** (List[Tensor]): all intermediate + hidden states of shape `(src_len, batch, embed_dim)`. + Only populated if *return_all_hiddens* is True. + """ + return self.forward_scriptable( + src_tokens, src_lengths, return_all_hiddens, token_embeddings + ) + + # TorchScript doesn't support super() method so that the scriptable Subclass + # can't access the base class model in Torchscript. + # Current workaround is to add a helper function with different name and + # call the helper function from scriptable Subclass. + def forward_scriptable( + self, + src_tokens, + src_lengths: Optional[torch.Tensor] = None, + return_all_hiddens: bool = False, + token_embeddings: Optional[torch.Tensor] = None, + ): + """ + Args: + src_tokens (LongTensor): tokens in the source language of shape + `(batch, src_len)` + src_lengths (torch.LongTensor): lengths of each source sentence of + shape `(batch)` + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + token_embeddings (torch.Tensor, optional): precomputed embeddings + default `None` will recompute embeddings + + Returns: + dict: + - **encoder_out** (Tensor): the last encoder layer's output of + shape `(src_len, batch, embed_dim)` + - **encoder_padding_mask** (ByteTensor): the positions of + padding elements of shape `(batch, src_len)` + - **encoder_embedding** (Tensor): the (scaled) embedding lookup + of shape `(batch, src_len, embed_dim)` + - **encoder_states** (List[Tensor]): all intermediate + hidden states of shape `(src_len, batch, embed_dim)`. + Only populated if *return_all_hiddens* is True. + """ + # compute padding mask + encoder_padding_mask = src_tokens.eq(self.padding_idx) + has_pads = src_tokens.device.type == "xla" or encoder_padding_mask.any() + + x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) + + # account for padding while computing the representation + if has_pads: + x = x * (1 - encoder_padding_mask.unsqueeze(-1).type_as(x)) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + encoder_states = [] + + if return_all_hiddens: + encoder_states.append(x) + + # encoder layers + for layer in self.layers: + x = layer( + x, encoder_padding_mask=encoder_padding_mask if has_pads else None + ) + if return_all_hiddens: + assert encoder_states is not None + encoder_states.append(x) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + # The Pytorch Mobile lite interpreter does not supports returning NamedTuple in + # `forward` so we use a dictionary instead. + # TorchScript does not support mixed values so the values are all lists. + # The empty list is equivalent to None. + src_lengths = src_tokens.ne(self.padding_idx).sum(dim=1, dtype=torch.int32).reshape(-1, 1).contiguous() + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [encoder_padding_mask], # B x T + "encoder_embedding": [encoder_embedding], # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [src_lengths], + } + + @torch.jit.export + def reorder_encoder_out(self, encoder_out: Dict[str, List[Tensor]], new_order): + """ + Reorder encoder output according to *new_order*. + + Args: + encoder_out: output from the ``forward()`` method + new_order (LongTensor): desired order + + Returns: + *encoder_out* rearranged according to *new_order* + """ + if len(encoder_out["encoder_out"]) == 0: + new_encoder_out = [] + else: + new_encoder_out = [encoder_out["encoder_out"][0].index_select(1, new_order)] + if len(encoder_out["encoder_padding_mask"]) == 0: + new_encoder_padding_mask = [] + else: + new_encoder_padding_mask = [ + encoder_out["encoder_padding_mask"][0].index_select(0, new_order) + ] + if len(encoder_out["encoder_embedding"]) == 0: + new_encoder_embedding = [] + else: + new_encoder_embedding = [ + encoder_out["encoder_embedding"][0].index_select(0, new_order) + ] + + if len(encoder_out["src_tokens"]) == 0: + src_tokens = [] + else: + src_tokens = [(encoder_out["src_tokens"][0]).index_select(0, new_order)] + + if len(encoder_out["src_lengths"]) == 0: + src_lengths = [] + else: + src_lengths = [(encoder_out["src_lengths"][0]).index_select(0, new_order)] + + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: + for idx, state in enumerate(encoder_states): + encoder_states[idx] = state.index_select(1, new_order) + + return { + "encoder_out": new_encoder_out, # T x B x C + "encoder_padding_mask": new_encoder_padding_mask, # B x T + "encoder_embedding": new_encoder_embedding, # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": src_tokens, # B x T + "src_lengths": src_lengths, # B x 1 + } + + def max_positions(self): + """Maximum input length supported by the encoder.""" + if self.embed_positions is None: + return self.max_source_positions + return min(self.max_source_positions, self.embed_positions.max_positions) + + def upgrade_state_dict_named(self, state_dict, name): + """Upgrade a (possibly old) state dict for new versions of fairseq.""" + if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): + weights_key = "{}.embed_positions.weights".format(name) + if weights_key in state_dict: + print("deleting {0}".format(weights_key)) + del state_dict[weights_key] + state_dict[ + "{}.embed_positions._float_tensor".format(name) + ] = torch.FloatTensor(1) + for i in range(self.num_layers): + # update layer norms + self.layers[i].upgrade_state_dict_named( + state_dict, "{}.layers.{}".format(name, i) + ) + + version_key = "{}.version".format(name) + if utils.item(state_dict.get(version_key, torch.Tensor([1]))[0]) < 2: + # earlier checkpoints did not normalize after the stack of layers + self.layer_norm = None + self.normalize = False + state_dict[version_key] = torch.Tensor([1]) + return state_dict diff --git a/fairseq/models/transformer/transformer_model.py b/fairseq/models/transformer/transformer_model.py new file mode 100644 index 0000000000..7cc5b64ad1 --- /dev/null +++ b/fairseq/models/transformer/transformer_model.py @@ -0,0 +1,452 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Optional, Tuple + +import torch.nn as nn +import torch +from fairseq import utils +from fairseq.distributed import fsdp_wrap +from fairseq.models import ( + FairseqEncoderDecoderModel, + register_model, + register_model_architecture, +) +from torch import Tensor +from fairseq.models import transformer + + +DEFAULT_MAX_SOURCE_POSITIONS = 1024 +DEFAULT_MAX_TARGET_POSITIONS = 1024 + + +DEFAULT_MIN_PARAMS_TO_WRAP = int(1e8) + + +@register_model("transformer") +class TransformerModel(FairseqEncoderDecoderModel): + """ + Transformer model from `"Attention Is All You Need" (Vaswani, et al, 2017) + <https://arxiv.org/abs/1706.03762>`_. + + Args: + encoder (TransformerEncoder): the encoder + decoder (TransformerDecoder): the decoder + + The Transformer model provides the following named architectures and + command-line arguments: + + .. argparse:: + :ref: fairseq.models.transformer_parser + :prog: + """ + + @classmethod + def hub_models(cls): + # fmt: off + + def moses_subword(path): + return { + 'path': path, + 'tokenizer': 'moses', + 'bpe': 'subword_nmt', + } + + def moses_fastbpe(path): + return { + 'path': path, + 'tokenizer': 'moses', + 'bpe': 'fastbpe', + } + + def spm(path): + return { + 'path': path, + 'bpe': 'sentencepiece', + 'tokenizer': 'space', + } + + return { + 'transformer.wmt14.en-fr': moses_subword('https://dl.fbaipublicfiles.com/fairseq/models/wmt14.en-fr.joined-dict.transformer.tar.bz2'), + 'transformer.wmt16.en-de': 'https://dl.fbaipublicfiles.com/fairseq/models/wmt16.en-de.joined-dict.transformer.tar.bz2', + 'transformer.wmt18.en-de': moses_subword('https://dl.fbaipublicfiles.com/fairseq/models/wmt18.en-de.ensemble.tar.gz'), + 'transformer.wmt19.en-de': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-de.joined-dict.ensemble.tar.gz'), + 'transformer.wmt19.en-ru': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-ru.ensemble.tar.gz'), + 'transformer.wmt19.de-en': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.de-en.joined-dict.ensemble.tar.gz'), + 'transformer.wmt19.ru-en': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.ru-en.ensemble.tar.gz'), + 'transformer.wmt19.en-de.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-de.joined-dict.single_model.tar.gz'), + 'transformer.wmt19.en-ru.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.en-ru.single_model.tar.gz'), + 'transformer.wmt19.de-en.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.de-en.joined-dict.single_model.tar.gz'), + 'transformer.wmt19.ru-en.single_model': moses_fastbpe('https://dl.fbaipublicfiles.com/fairseq/models/wmt19.ru-en.single_model.tar.gz'), + 'transformer.wmt20.en-ta': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-ta.single.tar.gz'), + 'transformer.wmt20.en-iu.news': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.news.single.tar.gz'), + 'transformer.wmt20.en-iu.nh': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.en-iu.nh.single.tar.gz'), + 'transformer.wmt20.ta-en': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.ta-en.single.tar.gz'), + 'transformer.wmt20.iu-en.news': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.news.single.tar.gz'), + 'transformer.wmt20.iu-en.nh': spm('https://dl.fbaipublicfiles.com/fairseq/models/wmt20.iu-en.nh.single.tar.gz'), + 'transformer.flores101.mm100.615M': spm('https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_615M.tar.gz'), + 'transformer.flores101.mm100.175M': spm('https://dl.fbaipublicfiles.com/flores101/pretrained_models/flores101_mm100_175M.tar.gz'), + } + # fmt: on + + def __init__(self, args, encoder, decoder): + super().__init__(encoder, decoder) + self.args = args + self.supports_align_args = True + + @staticmethod + def add_args(parser): + """Add model-specific arguments to the parser.""" + # fmt: off + parser.add_argument('--activation-fn', + choices=utils.get_available_activation_fns(), + help='activation function to use') + parser.add_argument('--dropout', type=float, metavar='D', + help='dropout probability') + parser.add_argument('--attention-dropout', type=float, metavar='D', + help='dropout probability for attention weights') + parser.add_argument('--activation-dropout', '--relu-dropout', type=float, metavar='D', + help='dropout probability after activation in FFN.') + parser.add_argument('--encoder-embed-path', type=str, metavar='STR', + help='path to pre-trained encoder embedding') + parser.add_argument('--encoder-embed-dim', type=int, metavar='N', + help='encoder embedding dimension') + parser.add_argument('--encoder-ffn-embed-dim', type=int, metavar='N', + help='encoder embedding dimension for FFN') + parser.add_argument('--encoder-layers', type=int, metavar='N', + help='num encoder layers') + parser.add_argument('--encoder-attention-heads', type=int, metavar='N', + help='num encoder attention heads') + parser.add_argument('--encoder-normalize-before', action='store_true', + help='apply layernorm before each encoder block') + parser.add_argument('--encoder-learned-pos', action='store_true', + help='use learned positional embeddings in the encoder') + parser.add_argument('--decoder-embed-path', type=str, metavar='STR', + help='path to pre-trained decoder embedding') + parser.add_argument('--decoder-embed-dim', type=int, metavar='N', + help='decoder embedding dimension') + parser.add_argument('--decoder-ffn-embed-dim', type=int, metavar='N', + help='decoder embedding dimension for FFN') + parser.add_argument('--decoder-layers', type=int, metavar='N', + help='num decoder layers') + parser.add_argument('--decoder-attention-heads', type=int, metavar='N', + help='num decoder attention heads') + parser.add_argument('--decoder-learned-pos', action='store_true', + help='use learned positional embeddings in the decoder') + parser.add_argument('--decoder-normalize-before', action='store_true', + help='apply layernorm before each decoder block') + parser.add_argument('--decoder-output-dim', type=int, metavar='N', + help='decoder output dimension (extra linear layer ' + 'if different from decoder embed dim') + parser.add_argument('--share-decoder-input-output-embed', action='store_true', + help='share decoder input and output embeddings') + parser.add_argument('--share-all-embeddings', action='store_true', + help='share encoder, decoder and output embeddings' + ' (requires shared dictionary and embed dim)') + parser.add_argument('--no-token-positional-embeddings', default=False, action='store_true', + help='if set, disables positional embeddings (outside self attention)') + parser.add_argument('--adaptive-softmax-cutoff', metavar='EXPR', + help='comma separated list of adaptive softmax cutoff points. ' + 'Must be used with adaptive_loss criterion'), + parser.add_argument('--adaptive-softmax-dropout', type=float, metavar='D', + help='sets adaptive softmax dropout for the tail projections') + parser.add_argument('--layernorm-embedding', action='store_true', + help='add layernorm to embedding') + parser.add_argument('--no-scale-embedding', action='store_true', + help='if True, dont scale embeddings') + parser.add_argument('--checkpoint-activations', action='store_true', + help='checkpoint activations at each layer, which saves GPU ' + 'memory usage at the cost of some additional compute') + parser.add_argument('--offload-activations', action='store_true', + help='checkpoint activations at each layer, then save to gpu. Sets --checkpoint-activations.') + # args for "Cross+Self-Attention for Transformer Models" (Peitz et al., 2019) + parser.add_argument('--no-cross-attention', default=False, action='store_true', + help='do not perform cross-attention') + parser.add_argument('--cross-self-attention', default=False, action='store_true', + help='perform cross+self-attention') + # args for "Reducing Transformer Depth on Demand with Structured Dropout" (Fan et al., 2019) + parser.add_argument('--encoder-layerdrop', type=float, metavar='D', default=0, + help='LayerDrop probability for encoder') + parser.add_argument('--decoder-layerdrop', type=float, metavar='D', default=0, + help='LayerDrop probability for decoder') + parser.add_argument('--encoder-layers-to-keep', default=None, + help='which layers to *keep* when pruning as a comma-separated list') + parser.add_argument('--decoder-layers-to-keep', default=None, + help='which layers to *keep* when pruning as a comma-separated list') + # args for Training with Quantization Noise for Extreme Model Compression ({Fan*, Stock*} et al., 2020) + parser.add_argument('--quant-noise-pq', type=float, metavar='D', default=0, + help='iterative PQ quantization noise at training time') + parser.add_argument('--quant-noise-pq-block-size', type=int, metavar='D', default=8, + help='block size of quantization noise at training time') + parser.add_argument('--quant-noise-scalar', type=float, metavar='D', default=0, + help='scalar quantization noise and scalar quantization at training time') + # args for Fully Sharded Data Parallel (FSDP) training + parser.add_argument( + '--min-params-to-wrap', type=int, metavar='D', default=DEFAULT_MIN_PARAMS_TO_WRAP, + help=( + 'minimum number of params for a layer to be wrapped with FSDP() when ' + 'training with --ddp-backend=fully_sharded. Smaller values will ' + 'improve memory efficiency, but may make torch.distributed ' + 'communication less efficient due to smaller input sizes. This option ' + 'is set to 0 (i.e., always wrap) when --checkpoint-activations or ' + '--offload-activations are passed.' + ) + ) + # fmt: on + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + + # make sure all arguments are present in older models + base_architecture(args) + + if args.encoder_layers_to_keep: + args.encoder_layers = len(args.encoder_layers_to_keep.split(",")) + if args.decoder_layers_to_keep: + args.decoder_layers = len(args.decoder_layers_to_keep.split(",")) + + if getattr(args, "max_source_positions", None) is None: + args.max_source_positions = DEFAULT_MAX_SOURCE_POSITIONS + if getattr(args, "max_target_positions", None) is None: + args.max_target_positions = DEFAULT_MAX_TARGET_POSITIONS + + src_dict, tgt_dict = task.source_dictionary, task.target_dictionary + + if args.share_all_embeddings: + if src_dict != tgt_dict: + raise ValueError("--share-all-embeddings requires a joined dictionary") + if args.encoder_embed_dim != args.decoder_embed_dim: + raise ValueError( + "--share-all-embeddings requires --encoder-embed-dim to match --decoder-embed-dim" + ) + if args.decoder_embed_path and ( + args.decoder_embed_path != args.encoder_embed_path + ): + raise ValueError( + "--share-all-embeddings not compatible with --decoder-embed-path" + ) + encoder_embed_tokens = cls.build_embedding( + args, src_dict, args.encoder_embed_dim, args.encoder_embed_path + ) + decoder_embed_tokens = encoder_embed_tokens + args.share_decoder_input_output_embed = True + else: + encoder_embed_tokens = cls.build_embedding( + args, src_dict, args.encoder_embed_dim, args.encoder_embed_path + ) + decoder_embed_tokens = cls.build_embedding( + args, tgt_dict, args.decoder_embed_dim, args.decoder_embed_path + ) + if getattr(args, "offload_activations", False): + args.checkpoint_activations = True # offloading implies checkpointing + encoder = cls.build_encoder(args, src_dict, encoder_embed_tokens) + decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens) + if not args.share_all_embeddings: + min_params_to_wrap = getattr( + args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP + ) + # fsdp_wrap is a no-op when --ddp-backend != fully_sharded + encoder = fsdp_wrap(encoder, min_num_params=min_params_to_wrap) + decoder = fsdp_wrap(decoder, min_num_params=min_params_to_wrap) + return cls(args, encoder, decoder) + + @classmethod + def build_embedding(cls, args, dictionary, embed_dim, path=None): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + + emb = Embedding(num_embeddings, embed_dim, padding_idx) + # if provided, load from preloaded dictionaries + if path: + embed_dict = utils.parse_embedding(path) + utils.load_embedding(embed_dict, dictionary, emb) + return emb + + @classmethod + def build_encoder(cls, args, src_dict, embed_tokens): + return transformer.TransformerEncoder(args, src_dict, embed_tokens) + + @classmethod + def build_decoder(cls, args, tgt_dict, embed_tokens): + return transformer.TransformerDecoder( + args, + tgt_dict, + embed_tokens, + no_encoder_attn=getattr(args, "no_cross_attention", False), + ) + + # TorchScript doesn't support optional arguments with variable length (**kwargs). + # Current workaround is to add union of all arguments in child classes. + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + return_all_hiddens: bool = True, + features_only: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + """ + Run the forward pass for an encoder-decoder model. + + Copied from the base class, but without ``**kwargs``, + which are not supported by TorchScript. + """ + encoder_out = self.encoder( + src_tokens, src_lengths=src_lengths, return_all_hiddens=return_all_hiddens + ) + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=encoder_out, + features_only=features_only, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + src_lengths=src_lengths, + return_all_hiddens=return_all_hiddens, + ) + return decoder_out + + # Since get_normalized_probs is in the Fairseq Model which is not scriptable, + # I rewrite the get_normalized_probs from Base Class to call the + # helper function in the Base Class. + @torch.jit.export + def get_normalized_probs( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): + """Get normalized probabilities (or log probs) from a net's output.""" + return self.get_normalized_probs_scriptable(net_output, log_probs, sample) + + +@register_model_architecture("transformer", "transformer_tiny") +def tiny_architecture(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 64) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 64) + args.encoder_layers = getattr(args, "encoder_layers", 2) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 2) + args.decoder_layers = getattr(args, "decoder_layers", 2) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 2) + return base_architecture(args) + + +@register_model_architecture("transformer", "transformer") +def base_architecture(args): + args.encoder_embed_path = getattr(args, "encoder_embed_path", None) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_layers = getattr(args, "encoder_layers", 6) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 8) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) + args.encoder_learned_pos = getattr(args, "encoder_learned_pos", False) + args.decoder_embed_path = getattr(args, "decoder_embed_path", None) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim + ) + args.decoder_layers = getattr(args, "decoder_layers", 6) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.attention_dropout = getattr(args, "attention_dropout", 0.0) + args.activation_dropout = getattr(args, "activation_dropout", 0.0) + args.activation_fn = getattr(args, "activation_fn", "relu") + args.dropout = getattr(args, "dropout", 0.1) + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + args.share_all_embeddings = getattr(args, "share_all_embeddings", False) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + args.adaptive_input = getattr(args, "adaptive_input", False) + args.no_cross_attention = getattr(args, "no_cross_attention", False) + args.cross_self_attention = getattr(args, "cross_self_attention", False) + + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) + + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + args.layernorm_embedding = getattr(args, "layernorm_embedding", False) + args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) + args.checkpoint_activations = getattr(args, "checkpoint_activations", False) + args.offload_activations = getattr(args, "offload_activations", False) + if args.offload_activations: + args.checkpoint_activations = True + args.encoder_layers_to_keep = getattr(args, "encoder_layers_to_keep", None) + args.decoder_layers_to_keep = getattr(args, "decoder_layers_to_keep", None) + args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8) + args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0) + + +@register_model_architecture("transformer", "transformer_iwslt_de_en") +def transformer_iwslt_de_en(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 1024) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.encoder_layers = getattr(args, "encoder_layers", 6) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 1024) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) + args.decoder_layers = getattr(args, "decoder_layers", 6) + base_architecture(args) + + +@register_model_architecture("transformer", "transformer_wmt_en_de") +def transformer_wmt_en_de(args): + base_architecture(args) + + +# parameters used in the "Attention Is All You Need" paper (Vaswani et al., 2017) +@register_model_architecture("transformer", "transformer_vaswani_wmt_en_de_big") +def transformer_vaswani_wmt_en_de_big(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4096) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + args.dropout = getattr(args, "dropout", 0.3) + base_architecture(args) + + +@register_model_architecture("transformer", "transformer_vaswani_wmt_en_fr_big") +def transformer_vaswani_wmt_en_fr_big(args): + args.dropout = getattr(args, "dropout", 0.1) + transformer_vaswani_wmt_en_de_big(args) + + +@register_model_architecture("transformer", "transformer_wmt_en_de_big") +def transformer_wmt_en_de_big(args): + args.attention_dropout = getattr(args, "attention_dropout", 0.1) + transformer_vaswani_wmt_en_de_big(args) + + +# default parameters used in tensor2tensor implementation +@register_model_architecture("transformer", "transformer_wmt_en_de_big_t2t") +def transformer_wmt_en_de_big_t2t(args): + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) + args.attention_dropout = getattr(args, "attention_dropout", 0.1) + args.activation_dropout = getattr(args, "activation_dropout", 0.1) + transformer_vaswani_wmt_en_de_big(args) + + +def Embedding(num_embeddings, embedding_dim, padding_idx): + m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) + nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.constant_(m.weight[padding_idx], 0) + return m From 7ebdc24909eaa1478e3423a942f5e41c35b9614c Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Fri, 16 Jul 2021 04:54:46 -0700 Subject: [PATCH 405/774] delegate namespace conversion to DC Summary: `populate_dataclass` is very basic in how it populates the dataclass. We might want more specific behaviour for some config dataclasses (like the hierarchical behaviour in TransformerConfig, see rest of stack). This diff move the populate logic to a `from_namespace` method in `FairseqDataclass` so that the a specific Dataclass can reimplement it. Reviewed By: myleott Differential Revision: D29521388 fbshipit-source-id: f3a6dc80e4ddfc9563c6e85c37c563173f193f4d --- fairseq/dataclass/configs.py | 16 ++++++++++++++++ fairseq/dataclass/utils.py | 14 -------------- fairseq/models/__init__.py | 4 ++-- fairseq/registry.py | 4 ++-- fairseq/tasks/__init__.py | 4 ++-- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index b0146fa4c7..6a86ea0192 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -79,6 +79,22 @@ def _get_argparse_alias(self, attribute_name: str) -> Any: def _get_choices(self, attribute_name: str) -> Any: return self._get_meta(attribute_name, "choices") + @classmethod + def from_namespace(cls, args): + if isinstance(args, cls): + return args + else: + config = cls() + for k in config.__dataclass_fields__.keys(): + if k.startswith("_"): + # private member, skip + continue + if hasattr(args, k): + setattr(config, k, getattr(args, k)) + + return config + + @dataclass class CommonConfig(FairseqDataclass): diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 1ed28b7ccc..5c25a2b3d4 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -419,20 +419,6 @@ def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: return cfg -def populate_dataclass( - dataclass: FairseqDataclass, - args: Namespace, -) -> FairseqDataclass: - for k in dataclass.__dataclass_fields__.keys(): - if k.startswith("_"): - # private member, skip - continue - if hasattr(args, k): - setattr(dataclass, k, getattr(args, k)) - - return dataclass - - def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): # this will be deprecated when we get rid of argparse and model_overrides logic diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index c5a4bbc831..337c77ac7b 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -10,7 +10,7 @@ from contextlib import ExitStack from fairseq.dataclass import FairseqDataclass -from fairseq.dataclass.utils import merge_with_parent, populate_dataclass +from fairseq.dataclass.utils import merge_with_parent from hydra.core.config_store import ConfigStore from omegaconf import open_dict, OmegaConf @@ -84,7 +84,7 @@ def build_model(cfg: FairseqDataclass, task): dc = MODEL_DATACLASS_REGISTRY[model_type] if isinstance(cfg, argparse.Namespace): - cfg = populate_dataclass(dc(), cfg) + cfg = dc.from_namespace(cfg) else: cfg = merge_with_parent(dc(), cfg) else: diff --git a/fairseq/registry.py b/fairseq/registry.py index 3fbaeac301..f3b9406043 100644 --- a/fairseq/registry.py +++ b/fairseq/registry.py @@ -7,7 +7,7 @@ from typing import Union from fairseq.dataclass import FairseqDataclass -from fairseq.dataclass.utils import populate_dataclass, merge_with_parent +from fairseq.dataclass.utils import merge_with_parent from hydra.core.config_store import ConfigStore from omegaconf import DictConfig @@ -45,7 +45,7 @@ def build_x(cfg: Union[DictConfig, str, Namespace], *extra_args, **extra_kwargs) else: choice = getattr(cfg, registry_name, None) if choice in DATACLASS_REGISTRY: - cfg = populate_dataclass(DATACLASS_REGISTRY[choice](), cfg) + cfg = DATACLASS_REGISTRY[choice].from_namespace(cfg) if choice is None: if required: diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 28305aa247..9a46b012c5 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -9,7 +9,7 @@ import os from fairseq.dataclass import FairseqDataclass -from fairseq.dataclass.utils import merge_with_parent, populate_dataclass +from fairseq.dataclass.utils import merge_with_parent from hydra.core.config_store import ConfigStore from .fairseq_task import FairseqTask, LegacyFairseqTask # noqa @@ -30,7 +30,7 @@ def setup_task(cfg: FairseqDataclass, **kwargs): task = TASK_REGISTRY[task_name] if task_name in TASK_DATACLASS_REGISTRY: dc = TASK_DATACLASS_REGISTRY[task_name] - cfg = populate_dataclass(dc(), cfg) + cfg = dc.from_namespace(cfg) else: task_name = getattr(cfg, "_name", None) From bc1504d4d709fd2157b6ba15f754c0307eb734f3 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Fri, 16 Jul 2021 04:54:46 -0700 Subject: [PATCH 406/774] Hierarchical Configs Summary: This is a precursor to D29232595 The current behaviour to convert a dataclass to a namespace is that all the fields from all DCs in the field hierarchy are flattened at the top. This is also the legacy behaviour with `add_args`. This is kind of cumbersome to build reusable Dataclasses as we need to make sure that each field has a unique name. In the case of Transformer for instance, we have a Decoder and Encoder config that share a large part of their fields (embed_dim, layers, etc.). We can build a single dataclass for this that can be reused and extended in other implementations. To be then able to have a flat namespace, instead of adding all subfields as is to the root namespace, we introduce the name of the field as prefix to the arg in the namespace. So: `model.decoder.embed_dim` becomes `decoder_embed_dim` and `model.encoder.embed_dim` becomes `encoder_embed_dim`. Reviewed By: myleott, dianaml0 Differential Revision: D29521386 fbshipit-source-id: f4bef036f0eeb620c6d8709ce97f96ae288848ef --- fairseq/dataclass/utils.py | 31 +++++++++++-- tests/test_dataclass_utils.py | 87 +++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 tests/test_dataclass_utils.py diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 5c25a2b3d4..1320ec4737 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -54,17 +54,27 @@ def gen_parser_from_dataclass( parser: ArgumentParser, dataclass_instance: FairseqDataclass, delete_default: bool = False, + with_prefix: Optional[str] = None, ) -> None: - """convert a dataclass instance to tailing parser arguments""" + """ + convert a dataclass instance to tailing parser arguments. + + If `with_prefix` is provided, prefix all the keys in the resulting parser with it. It means that we are + building a flat namespace from a structured dataclass (see transformer_config.py for example). + """ def argparse_name(name: str): - if name == "data": - # normally data is positional args + if name == "data" and (with_prefix is None or with_prefix == ''): + # normally data is positional args, so we don't add the -- nor the prefix return name if name == "_name": # private member, skip return None - return "--" + name.replace("_", "-") + full_name = "--" + name.replace("_", "-") + if with_prefix is not None and with_prefix != '': + # if a prefix is specified, construct the prefixed arg name + full_name = with_prefix + "-" + full_name[2:] # strip -- when composing + return full_name def get_kwargs_from_dc( dataclass_instance: FairseqDataclass, k: str @@ -132,6 +142,10 @@ def get_kwargs_from_dc( if field_default is not MISSING: kwargs["default"] = field_default + # build the help with the hierarchical prefix + if with_prefix is not None and with_prefix != '' and field_help is not None: + field_help = with_prefix[2:] + ': ' + field_help + kwargs["help"] = field_help if field_const is not None: kwargs["const"] = field_const @@ -145,7 +159,14 @@ def get_kwargs_from_dc( if field_name is None: continue elif inspect.isclass(field_type) and issubclass(field_type, FairseqDataclass): - gen_parser_from_dataclass(parser, field_type(), delete_default) + # for fields that are of type FairseqDataclass, we can recursively + # add their fields to the namespace (so we add the args from model, task, etc. to the root namespace) + prefix = None + if with_prefix is not None: + # if a prefix is specified, then we don't want to copy the subfields directly to the root namespace + # but we prefix them with the name of the current field. + prefix = field_name + gen_parser_from_dataclass(parser, field_type(), delete_default, prefix) continue kwargs = get_kwargs_from_dc(dataclass_instance, k) diff --git a/tests/test_dataclass_utils.py b/tests/test_dataclass_utils.py new file mode 100644 index 0000000000..45fc391a97 --- /dev/null +++ b/tests/test_dataclass_utils.py @@ -0,0 +1,87 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from argparse import ArgumentParser +from dataclasses import dataclass, field + +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.utils import gen_parser_from_dataclass + + +@dataclass +class A(FairseqDataclass): + data: str = field(default="test", metadata={"help": "the data input"}) + num_layers: int = field(default=200, metadata={"help": "more layers is better?"}) + + +@dataclass +class B(FairseqDataclass): + bar: A = field(default=A()) + foo: int = field(default=0, metadata={"help": "not a bar"}) + + +@dataclass +class D(FairseqDataclass): + arch: A = field(default=A()) + foo: int = field(default=0, metadata={"help": "not a bar"}) + + +@dataclass +class C(FairseqDataclass): + data: str = field(default="test", metadata={"help": "root level data input"}) + encoder: D = field(default=D()) + decoder: A = field(default=A()) + lr: int = field(default=0, metadata={"help": "learning rate"}) + + +class TestDataclassUtils(unittest.TestCase): + def test_argparse_convert_basic(self): + parser = ArgumentParser() + gen_parser_from_dataclass(parser, A(), True) + args = parser.parse_args(["--num-layers", '10', "the/data/path"]) + self.assertEqual(args.num_layers, 10) + self.assertEqual(args.data, "the/data/path") + + def test_argparse_recursive(self): + parser = ArgumentParser() + gen_parser_from_dataclass(parser, B(), True) + args = parser.parse_args(["--num-layers", "10", "--foo", "10", "the/data/path"]) + self.assertEqual(args.num_layers, 10) + self.assertEqual(args.foo, 10) + self.assertEqual(args.data, "the/data/path") + + def test_argparse_recursive_prefixing(self): + self.maxDiff = None + parser = ArgumentParser() + gen_parser_from_dataclass(parser, C(), True, "") + args = parser.parse_args( + [ + "--encoder-arch-data", + "ENCODER_ARCH_DATA", + "--encoder-arch-num-layers", + "10", + "--encoder-foo", + "10", + "--decoder-data", + "DECODER_DATA", + "--decoder-num-layers", + "10", + "--lr", + "10", + "the/data/path", + ] + ) + self.assertEqual(args.encoder_arch_data, "ENCODER_ARCH_DATA") + self.assertEqual(args.encoder_arch_num_layers, 10) + self.assertEqual(args.encoder_foo, 10) + self.assertEqual(args.decoder_data, "DECODER_DATA") + self.assertEqual(args.decoder_num_layers, 10) + self.assertEqual(args.lr, 10) + self.assertEqual(args.data, "the/data/path") + + +if __name__ == "__main__": + unittest.main() From 059187f5abbbe8a8118f01daaa4a1feb3a827249 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Fri, 16 Jul 2021 04:54:46 -0700 Subject: [PATCH 407/774] ArgumentError when double declaration Summary: A few subclasses of TransformerModel try to add the same params that have already been added. A workaround is to catch the argparse exception and just ignore it as we know the field was already added if it's thrown. Reviewed By: myleott, dianaml0 Differential Revision: D29521389 fbshipit-source-id: 7912a260c4f55fbfe486794c9726d6289370400e --- examples/laser/laser_src/laser_task.py | 33 +++++++++++-------- .../multilingual/multilingual_data_manager.py | 33 +++++++++++-------- fairseq/tasks/multilingual_translation.py | 13 +++++--- fairseq/tasks/online_backtranslation.py | 13 +++++--- 4 files changed, 56 insertions(+), 36 deletions(-) diff --git a/examples/laser/laser_src/laser_task.py b/examples/laser/laser_src/laser_task.py index c8ac805f54..e4152fde68 100644 --- a/examples/laser/laser_src/laser_task.py +++ b/examples/laser/laser_src/laser_task.py @@ -8,6 +8,7 @@ import json import os import logging +from argparse import ArgumentError from fairseq import options, models from fairseq.data import ( @@ -59,20 +60,24 @@ def add_args(parser): metavar="BOOL", help="pad the target on the left (default: False)", ) - parser.add_argument( - "--max-source-positions", - default=1024, - type=int, - metavar="N", - help="max number of tokens in the source sequence", - ) - parser.add_argument( - "--max-target-positions", - default=1024, - type=int, - metavar="N", - help="max number of tokens in the target sequence", - ) + try: + parser.add_argument( + "--max-source-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the source sequence", + ) + parser.add_argument( + "--max-target-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the target sequence", + ) + except ArgumentError: + # this might have already been defined. Once we transition this to hydra it should be fine to add it here. + pass def __init__(self, args, config, src_dictionary, tgt_dictionary, num_tasks): super().__init__(args) diff --git a/fairseq/data/multilingual/multilingual_data_manager.py b/fairseq/data/multilingual/multilingual_data_manager.py index a2fae5bf52..137481b449 100644 --- a/fairseq/data/multilingual/multilingual_data_manager.py +++ b/fairseq/data/multilingual/multilingual_data_manager.py @@ -9,6 +9,7 @@ import math import os from collections import OrderedDict, defaultdict +from argparse import ArgumentError from fairseq import utils from fairseq.data import ( @@ -141,20 +142,24 @@ def add_args(parser): metavar="BOOL", help="pad the target on the left", ) - parser.add_argument( - "--max-source-positions", - default=1024, - type=int, - metavar="N", - help="max number of tokens in the source sequence", - ) - parser.add_argument( - "--max-target-positions", - default=1024, - type=int, - metavar="N", - help="max number of tokens in the target sequence", - ) + try: + parser.add_argument( + "--max-source-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the source sequence", + ) + parser.add_argument( + "--max-target-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the target sequence", + ) + except ArgumentError: + # this might have already been defined. Once we transition this to hydra it should be fine to add it here. + pass parser.add_argument( "--upsample-primary", default=1, diff --git a/fairseq/tasks/multilingual_translation.py b/fairseq/tasks/multilingual_translation.py index 26e0b529d5..4f85ab4832 100644 --- a/fairseq/tasks/multilingual_translation.py +++ b/fairseq/tasks/multilingual_translation.py @@ -7,6 +7,7 @@ import logging import os from collections import OrderedDict +from argparse import ArgumentError import torch from fairseq import metrics, options, utils @@ -77,10 +78,14 @@ def add_args(parser): help='pad the source on the left (default: True)') parser.add_argument('--left-pad-target', default='False', type=str, metavar='BOOL', help='pad the target on the left (default: False)') - parser.add_argument('--max-source-positions', default=1024, type=int, metavar='N', - help='max number of tokens in the source sequence') - parser.add_argument('--max-target-positions', default=1024, type=int, metavar='N', - help='max number of tokens in the target sequence') + try: + parser.add_argument('--max-source-positions', default=1024, type=int, metavar='N', + help='max number of tokens in the source sequence') + parser.add_argument('--max-target-positions', default=1024, type=int, metavar='N', + help='max number of tokens in the target sequence') + except ArgumentError: + # this might have already been defined. Once we transition this to hydra it should be fine to add it here. + pass parser.add_argument('--upsample-primary', default=1, type=int, help='amount to upsample primary dataset') parser.add_argument('--encoder-langtok', default=None, type=str, choices=['src', 'tgt'], diff --git a/fairseq/tasks/online_backtranslation.py b/fairseq/tasks/online_backtranslation.py index 2545624cd4..2e27ca237c 100644 --- a/fairseq/tasks/online_backtranslation.py +++ b/fairseq/tasks/online_backtranslation.py @@ -12,6 +12,7 @@ from collections import OrderedDict, defaultdict from pathlib import Path from typing import Dict, Sequence, Tuple +from argparse import ArgumentError import numpy as np import torch @@ -110,10 +111,14 @@ def add_args(parser): help='pad the target on the left') parser.add_argument('--upsample-primary', default=1, type=int, help='amount to upsample primary dataset') - parser.add_argument('--max-source-positions', default=1024, type=int, metavar='N', - help='max number of tokens in the source sequence') - parser.add_argument('--max-target-positions', default=1024, type=int, metavar='N', - help='max number of tokens in the target sequence') + try: + parser.add_argument('--max-source-positions', default=1024, type=int, metavar='N', + help='max number of tokens in the source sequence') + parser.add_argument('--max-target-positions', default=1024, type=int, metavar='N', + help='max number of tokens in the target sequence') + except ArgumentError: + # this might have already been defined. Once we transition this to hydra it should be fine to add it here. + pass parser.add_argument('--truncate-source', action='store_true', default=False, help='truncate source to max-source-positions') parser.add_argument('--num-batch-buckets', default=0, type=int, metavar='N', From 129d8594ccdc6644be84dc249e16489e049f4bfd Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Fri, 16 Jul 2021 04:54:46 -0700 Subject: [PATCH 408/774] Transformer Hydration pt1. (#1984) Summary: ## What does this PR do? In https://github.com/fairinternal/fairseq-py/tree/hydra-transformer I tried to convert TransformerModel to hydra directly, but then had to deal with upgrading a lot of downstream classes and this got out of hand. I am trying a different approach here, this is my strategy in this PR: 0- make the argparse backward converter support hierarchical configs. This way, I can clean up the config and split it in "sub-configs" for Encoder/Decoder. This simplifies the config object and allows for code reusability. In the future, should simplify creating more specific configs for Enc/Dec. 1- Have a base classe that is hydrated (but not registered as model). This also mean hydrating the Encoder/Decoder/Layer classes. 2- first hide this behind a legacy model that is still called TransformerModel (to not break imports, etc. etc.). This legacy model transforms the argparse namespace in the dataclass config when it needs to. 3- make the dataclass look like the argparse namespace so that it can be used without subclassing/hydrating all the downstream classes under TransformerModel (see other branch to see what this involves) test_binaries seems to run fine but for one state loading issue. I am still digging into that but wanted to make sure this was a good approach. (I also decided to split the `transformer.py` file as it was getting a bit too large and I like making merges with master miserable) ## Next Steps - Separate PR to create a registered Hydra model, ideally renaming TransformerModel to TransformerModelLegacy and codemoding everything to inherit from TransformerModelLegacy. - add equivalent test_binaries test that run with hydra main (already done in other branch) - start converting some downstream models to hydra where needed. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1984 Reviewed By: dianaml0 Differential Revision: D29232595 Pulled By: Mortimerp9 fbshipit-source-id: f12eadfa9ccff29f28c67b527f9996311f791359 --- fairseq/models/transformer/__init__.py | 14 +- .../models/transformer/transformer_base.py | 169 ++++++++++ .../models/transformer/transformer_config.py | 318 ++++++++++++++++++ .../models/transformer/transformer_decoder.py | 126 ++++--- .../models/transformer/transformer_encoder.py | 83 +++-- ...sformer_model.py => transformer_legacy.py} | 245 ++------------ fairseq/modules/multihead_attention.py | 2 +- fairseq/modules/transformer_layer.py | 153 +++++---- 8 files changed, 751 insertions(+), 359 deletions(-) create mode 100644 fairseq/models/transformer/transformer_base.py create mode 100644 fairseq/models/transformer/transformer_config.py rename fairseq/models/transformer/{transformer_model.py => transformer_legacy.py} (50%) diff --git a/fairseq/models/transformer/__init__.py b/fairseq/models/transformer/__init__.py index 6809adeab7..681fca3d45 100644 --- a/fairseq/models/transformer/__init__.py +++ b/fairseq/models/transformer/__init__.py @@ -4,12 +4,15 @@ # LICENSE file in the root directory of this source tree. """isort:skip_file""" -from .transformer_decoder import TransformerDecoder, Linear -from .transformer_encoder import TransformerEncoder -from .transformer_model import ( +from .transformer_config import ( + TransformerConfig, DEFAULT_MAX_SOURCE_POSITIONS, DEFAULT_MAX_TARGET_POSITIONS, DEFAULT_MIN_PARAMS_TO_WRAP, +) +from .transformer_decoder import TransformerDecoder, TransformerDecoderBase, Linear +from .transformer_encoder import TransformerEncoder, TransformerEncoderBase +from .transformer_legacy import ( TransformerModel, base_architecture, tiny_architecture, @@ -19,14 +22,17 @@ transformer_vaswani_wmt_en_fr_big, transformer_wmt_en_de_big, transformer_wmt_en_de_big_t2t, - Embedding, ) +from .transformer_base import TransformerModelBase, Embedding __all__ = [ + "TransformerModelBase", "TransformerConfig", "TransformerDecoder", + "TransformerDecoderBase", "TransformerEncoder", + "TransformerEncoderBase", "TransformerModel", "Embedding", "Linear", diff --git a/fairseq/models/transformer/transformer_base.py b/fairseq/models/transformer/transformer_base.py new file mode 100644 index 0000000000..e3ceb3c317 --- /dev/null +++ b/fairseq/models/transformer/transformer_base.py @@ -0,0 +1,169 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Optional, Tuple + +import torch +import torch.nn as nn +from fairseq import utils +from fairseq.dataclass.utils import gen_parser_from_dataclass +from fairseq.distributed import fsdp_wrap +from fairseq.models import FairseqEncoderDecoderModel +from torch import Tensor +from fairseq.models.transformer import (TransformerEncoderBase, TransformerDecoderBase, TransformerConfig) + + +class TransformerModelBase(FairseqEncoderDecoderModel): + """ + Transformer model from `"Attention Is All You Need" (Vaswani, et al, 2017) + <https://arxiv.org/abs/1706.03762>`_. + + Args: + encoder (TransformerEncoder): the encoder + decoder (TransformerDecoder): the decoder + + The Transformer model provides the following named architectures and + command-line arguments: + + .. argparse:: + :ref: fairseq.models.transformer_parser + :prog: + """ + + def __init__(self, cfg, encoder, decoder): + super().__init__(encoder, decoder) + self.cfg = cfg + self.supports_align_args = True + + @staticmethod + def add_args(parser): + """Add model-specific arguments to the parser.""" + # we want to build the args recursively in this case. + gen_parser_from_dataclass( + parser, TransformerConfig(), delete_default=False, with_prefix="" + ) + + @classmethod + def build_model(cls, cfg, task): + """Build a new model instance.""" + + if cfg.encoder.layers_to_keep: + cfg.encoder.layers = len(cfg.encoder.layers_to_keep.split(',')) + if cfg.decoder.layers_to_keep: + cfg.decoder.layers = len(cfg.decoder.layers_to_keep.split(',')) + + src_dict, tgt_dict = task.source_dictionary, task.target_dictionary + + if cfg.share_all_embeddings: + if src_dict != tgt_dict: + raise ValueError("--share-all-embeddings requires a joined dictionary") + if cfg.encoder.embed_dim != cfg.decoder.embed_dim: + raise ValueError( + "--share-all-embeddings requires --encoder-embed-dim to match --decoder-embed-dim" + ) + if cfg.decoder.embed_path and ( + cfg.decoder.embed_path != cfg.encoder.embed_path + ): + raise ValueError( + "--share-all-embeddings not compatible with --decoder-embed-path" + ) + encoder_embed_tokens = cls.build_embedding( + cfg, src_dict, cfg.encoder.embed_dim, cfg.encoder.embed_path + ) + decoder_embed_tokens = encoder_embed_tokens + cfg.share_decoder_input_output_embed = True + else: + encoder_embed_tokens = cls.build_embedding( + cfg, src_dict, cfg.encoder.embed_dim, cfg.encoder.embed_path + ) + decoder_embed_tokens = cls.build_embedding( + cfg, tgt_dict, cfg.decoder.embed_dim, cfg.decoder.embed_path + ) + if cfg.offload_activations: + cfg.checkpoint_activations = True # offloading implies checkpointing + encoder = cls.build_encoder(cfg, src_dict, encoder_embed_tokens) + decoder = cls.build_decoder(cfg, tgt_dict, decoder_embed_tokens) + if not cfg.share_all_embeddings: + # fsdp_wrap is a no-op when --ddp-backend != fully_sharded + encoder = fsdp_wrap(encoder, min_num_params=cfg.min_params_to_wrap) + decoder = fsdp_wrap(decoder, min_num_params=cfg.min_params_to_wrap) + return cls(cfg, encoder, decoder) + + @classmethod + def build_embedding(cls, cfg, dictionary, embed_dim, path=None): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + + emb = Embedding(num_embeddings, embed_dim, padding_idx) + # if provided, load from preloaded dictionaries + if path: + embed_dict = utils.parse_embedding(path) + utils.load_embedding(embed_dict, dictionary, emb) + return emb + + @classmethod + def build_encoder(cls, cfg, src_dict, embed_tokens): + return TransformerEncoderBase(cfg, src_dict, embed_tokens) + + @classmethod + def build_decoder(cls, cfg, tgt_dict, embed_tokens): + return TransformerDecoderBase( + cfg, + tgt_dict, + embed_tokens, + no_encoder_attn=cfg.no_cross_attention, + ) + + # TorchScript doesn't support optional arguments with variable length (**kwargs). + # Current workaround is to add union of all arguments in child classes. + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + return_all_hiddens: bool = True, + features_only: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + """ + Run the forward pass for an encoder-decoder model. + + Copied from the base class, but without ``**kwargs``, + which are not supported by TorchScript. + """ + encoder_out = self.encoder( + src_tokens, src_lengths=src_lengths, return_all_hiddens=return_all_hiddens + ) + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=encoder_out, + features_only=features_only, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + src_lengths=src_lengths, + return_all_hiddens=return_all_hiddens, + ) + return decoder_out + + # Since get_normalized_probs is in the Fairseq Model which is not scriptable, + # I rewrite the get_normalized_probs from Base Class to call the + # helper function in the Base Class. + @torch.jit.export + def get_normalized_probs( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): + """Get normalized probabilities (or log probs) from a net's output.""" + return self.get_normalized_probs_scriptable(net_output, log_probs, sample) + + +def Embedding(num_embeddings, embedding_dim, padding_idx): + m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) + nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.constant_(m.weight[padding_idx], 0) + return m diff --git a/fairseq/models/transformer/transformer_config.py b/fairseq/models/transformer/transformer_config.py new file mode 100644 index 0000000000..2580d20aac --- /dev/null +++ b/fairseq/models/transformer/transformer_config.py @@ -0,0 +1,318 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import re +from dataclasses import dataclass, field, fields +from typing import List, Optional + +from fairseq import utils +from fairseq.dataclass import FairseqDataclass, ChoiceEnum +from omegaconf import II + +DEFAULT_MAX_SOURCE_POSITIONS = 1024 +DEFAULT_MAX_TARGET_POSITIONS = 1024 + +DEFAULT_MIN_PARAMS_TO_WRAP = int(1e8) + +_NAME_PARSER = r"(decoder|encoder|quant_noise)_(.*)" + + +@dataclass +class EncDecBaseConfig(FairseqDataclass): + embed_path: Optional[str] = field( + default=None, metadata={"help": "path to pre-trained embedding"} + ) + embed_dim: Optional[int] = field( + default=512, metadata={"help": "embedding dimension"} + ) + ffn_embed_dim: int = field( + default=2048, metadata={"help": "embedding dimension for FFN"} + ) + layers: int = field(default=6, metadata={"help": "number of layers"}) + attention_heads: int = field( + default=8, metadata={"help": "number of attention heads"} + ) + normalize_before: bool = field( + default=False, metadata={"help": "apply layernorm before each block"} + ) + learned_pos: bool = field( + default=False, metadata={"help": "use learned positional embeddings"} + ) + # args for "Reducing Transformer Depth on Demand with Structured Dropout" (Fan et al., 2019) + layerdrop: float = field(default=0, metadata={"help": "LayerDrop probability"}) + layers_to_keep: Optional[List[int]] = field( + default=None, metadata={"help": "which layers to *keep* when pruning"} + ) + + +@dataclass +class DecoderConfig(EncDecBaseConfig): + input_dim: int = II("model.decoder.embed_dim") + output_dim: int = field( + default=II("model.decoder.embed_dim"), + metadata={ + "help": "decoder output dimension (extra linear layer if different from decoder embed dim)" + }, + ) + + def __post_init__(self): + # II doesn't work if we are just creating the object outside of hydra so fix that + if self.input_dim == II("model.decoder.embed_dim"): + self.input_dim = self.embed_dim + if self.output_dim == II("model.decoder.embed_dim"): + self.output_dim = self.embed_dim + + +@dataclass +class QuantNoiseConfig(FairseqDataclass): + pq: float = field( + default=0.0, + metadata={"help": "iterative PQ quantization noise at training time"}, + ) + pq_block_size: int = field( + default=8, + metadata={"help": "block size of quantization noise at training time"}, + ) + scalar: float = field( + default=0.0, + metadata={ + "help": "scalar quantization noise and scalar quantization at training time" + }, + ) + + +@dataclass +class TransformerConfig(FairseqDataclass): + activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( + default="relu", + metadata={"help": "activation function to use"}, + ) + dropout: float = field(default=0.1, metadata={"help": "dropout probability"}) + attention_dropout: float = field( + default=0.0, metadata={"help": "dropout probability for attention weights"} + ) + activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN.", + "alias": "--relu-dropout", + }, + ) + adaptive_input: bool = False + encoder: EncDecBaseConfig = EncDecBaseConfig() + # TODO should really be in the encoder config + max_source_positions: int = field( + default=DEFAULT_MAX_SOURCE_POSITIONS, + metadata={"help": "Maximum input length supported by the encoder"}, + ) + decoder: DecoderConfig = DecoderConfig() + # TODO should really be in the decoder config + max_target_positions: int = field( + default=DEFAULT_MAX_TARGET_POSITIONS, + metadata={"help": "Maximum output length supported by the decoder"}, + ) + share_decoder_input_output_embed: bool = field( + default=False, metadata={"help": "share decoder input and output embeddings"} + ) + share_all_embeddings: bool = field( + default=False, + metadata={ + "help": "share encoder, decoder and output embeddings (requires shared dictionary and embed dim)" + }, + ) + no_token_positional_embeddings: bool = field( + default=False, + metadata={ + "help": "if True, disables positional embeddings (outside self attention)" + }, + ) + adaptive_softmax_cutoff: Optional[List[int]] = field( + default=None, + metadata={ + "help": "list of adaptive softmax cutoff points. Must be used with adaptive_loss criterion" + }, + ) + adaptive_softmax_dropout: float = field( + default=0.0, + metadata={"help": "sets adaptive softmax dropout for the tail projections"}, + ) + adaptive_softmax_factor: float = field( + default=4, metadata={"help": "adaptive input factor"} + ) + layernorm_embedding: bool = field( + default=False, metadata={"help": "add layernorm to embedding"} + ) + tie_adaptive_weights: bool = field( + default=False, + metadata={ + "help": "if set, ties the weights of adaptive softmax and adaptive input" + }, + ) + tie_adaptive_proj: bool = field( + default=False, + metadata={ + "help": "if set, ties the projection weights of adaptive softmax and adaptive input" + }, + ) + no_scale_embedding: bool = field( + default=False, metadata={"help": "if True, dont scale embeddings"} + ) + checkpoint_activations: bool = field( + default=False, + metadata={ + "help": "checkpoint activations at each layer, which saves GPU memory usage at the cost of some additional compute" + }, + ) + offload_activations: bool = field( + default=False, + metadata={ + "help": "checkpoint activations at each layer, then save to gpu. Sets --checkpoint-activations." + }, + ) + # args for "Cross+Self-Attention for Transformer Models" (Peitz et al., 2019) + no_cross_attention: bool = field( + default=False, metadata={"help": "do not perform cross-attention"} + ) + cross_self_attention: bool = field( + default=False, metadata={"help": "perform cross+self-attention"} + ) + # args for Training with Quantization Noise for Extreme Model Compression ({Fan*, Stock*} et al., 2020) + quant_noise: QuantNoiseConfig = field(default=QuantNoiseConfig()) + min_params_to_wrap: int = field( + default=DEFAULT_MIN_PARAMS_TO_WRAP, + metadata={ + "help": "minimum number of params for a layer to be wrapped with FSDP() when " + "training with --ddp-backend=fully_sharded. Smaller values will " + "improve memory efficiency, but may make torch.distributed " + "communication less efficient due to smaller input sizes. This option " + "is set to 0 (i.e., always wrap) when --checkpoint-activations or " + "--offload-activations are passed." + }, + ) + # DEPRECATED field, but some old checkpoints might have it + char_inputs: bool = field( + default=False, metadata={"help": "if set, model takes character ids as input"} + ) + relu_dropout: float = 0.0 + # config for "BASE Layers: Simplifying Training of Large, Sparse Models" + base_layers: Optional[int] = field( + default=0, metadata={"help": "number of BASE layers in total"} + ) + base_sublayers: Optional[int] = field( + default=1, metadata={"help": "number of sublayers in each BASE layer"} + ) + base_shuffle: Optional[int] = field( + default=1, + metadata={"help": "shuffle tokens between workers before computing assignment"}, + ) + + export: bool = field( + default=False, + metadata={"help": "make the layernorm exportable with torchscript."}, + ) + + # copied from transformer_lm but expected in transformer_decoder: + no_decoder_final_norm: bool = field( + default=False, + metadata={"help": "don't add an extra layernorm after the last decoder block"}, + ) + + # We need to make this hierarchical dataclass like the flat namespace + # __getattr__ and __setattr__ here allow backward compatibility + # for subclasses of Transformer(Legacy) that depend on read/write on + # the flat namespace. + + def __getattr__(self, name): + match = re.match(_NAME_PARSER, name) + if match: + sub = getattr(self, match[1]) + return getattr(sub, match[2]) + raise AttributeError(f"invalid argument {name}.") + + def __setattr__(self, name, value): + match = re.match(_NAME_PARSER, name) + if match: + sub = getattr(self, match[1]) + setattr(sub, match[2], value) + else: + super().__setattr__(name, value) + + @staticmethod + def _copy_keys(args, cls, prefix, seen): + """ + copy the prefixed keys (decoder_embed_dim) to the DC fields: decoder.embed_dim + """ + cfg = cls() + for fld in fields(cls): + # for all the fields in the DC, find the fields (e.g. embed_dim) + # in the namespace with the prefix (e.g. decoder) + # and set it on the dc. + args_key = f"{prefix}_{fld.name}" + if hasattr(args, args_key): + seen.add(args_key) + setattr(cfg, fld.name, getattr(args, args_key)) + if hasattr(args, fld.name): + seen.add(fld.name) + setattr(cfg, fld.name, getattr(args, fld.name)) + return cfg + + @classmethod + def from_namespace(cls, args): + if args is None: + return None + if not isinstance(args, cls): + seen = set() + config = cls() + # currently, we can go generically from DC fields to args hierarchically + # but we can't easily deconstruct a flat namespace to a hierarchical + # DC. Mostly because we could have a sub-dc called `decoder-foo` that should not + # go to the sub struct called `decoder`. There are ways to go around this, but let's keep it simple + # for now. + for fld in fields(cls): + # concretelly, the transformer_config know what sub-dc it has, so we go through all the dc fields + # and if it's one that has a sub-dc, we build that sub-dc with `copy_keys()` + if fld.name == "decoder": + if hasattr(args, "decoder"): + # in some cases, the args we receive is already structured (as DictConfigs), so let's just build the correct DC + seen.add("decoder") + config.decoder = DecoderConfig(**args.decoder) + else: + config.decoder = cls._copy_keys( + args, DecoderConfig, "decoder", seen + ) + elif fld.name == "encoder": + # same but for encoder + if hasattr(args, "encoder"): + seen.add("encoder") + config.encoder = EncDecBaseConfig(**args.encoder) + else: + config.encoder = cls._copy_keys( + args, EncDecBaseConfig, "encoder", seen + ) + elif fld.name == "quant_noise": + # same but for quant_noise + if hasattr(args, "quant_noise"): + seen.add("quant_noise") + config.quant_noise = QuantNoiseConfig(**args.quant_noise) + else: + config.quant_noise = cls._copy_keys( + args, QuantNoiseConfig, "quant_noise", seen + ) + elif hasattr(args, fld.name): + # if it's not a structure field, it's just a normal field, copy it over + seen.add(fld.name) + setattr(config, fld.name, getattr(args, fld.name)) + # we got all the fields defined in the dataclass, but + # the argparse namespace might have extra args for two reasons: + # - we are in a legacy class so all the args are not declared in the dataclass. Ideally once everyone has defined a dataclass for their model, we won't need this + # - some places expect args to be there but never define them + args_dict = args._asdict() if hasattr(args, '_asdict') else vars(args) if hasattr(args, '__dict__') else {} # namedtupled doesn't have __dict__ :-/ + for key, value in args_dict.items(): + if key not in seen: + setattr(config, key, value) + return config + else: + return args diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py index ca9e737e60..49e37917cc 100644 --- a/fairseq/models/transformer/transformer_decoder.py +++ b/fairseq/models/transformer/transformer_decoder.py @@ -11,7 +11,7 @@ from fairseq import utils from fairseq.distributed import fsdp_wrap from fairseq.models import FairseqIncrementalDecoder -from fairseq.models.transformer import transformer_model +from fairseq.models.transformer import TransformerConfig from fairseq.modules import ( AdaptiveSoftmax, BaseLayer, @@ -27,9 +27,17 @@ from torch import Tensor -class TransformerDecoder(FairseqIncrementalDecoder): +# rewrite name for backward compatibility in `make_generation_fast_` +def module_name_fordropout(module_name: str) -> str: + if module_name == 'TransformerDecoderBase': + return 'TransformerDecoder' + else: + return module_name + + +class TransformerDecoderBase(FairseqIncrementalDecoder): """ - Transformer decoder consisting of *args.decoder_layers* layers. Each layer + Transformer decoder consisting of *cfg.decoder.layers* layers. Each layer is a :class:`TransformerDecoderLayer`. Args: @@ -42,40 +50,40 @@ class TransformerDecoder(FairseqIncrementalDecoder): def __init__( self, - args, + cfg, dictionary, embed_tokens, no_encoder_attn=False, output_projection=None, ): - self.args = args + self.cfg = cfg super().__init__(dictionary) self.register_buffer("version", torch.Tensor([3])) self._future_mask = torch.empty(0) self.dropout_module = FairseqDropout( - args.dropout, module_name=self.__class__.__name__ + cfg.dropout, module_name=module_name_fordropout(self.__class__.__name__) ) - self.decoder_layerdrop = args.decoder_layerdrop - self.share_input_output_embed = args.share_decoder_input_output_embed + self.decoder_layerdrop = cfg.decoder.layerdrop + self.share_input_output_embed = cfg.share_decoder_input_output_embed input_embed_dim = embed_tokens.embedding_dim - embed_dim = args.decoder_embed_dim + embed_dim = cfg.decoder.embed_dim self.embed_dim = embed_dim - self.output_embed_dim = args.decoder_output_dim + self.output_embed_dim = cfg.decoder.output_dim self.padding_idx = embed_tokens.padding_idx - self.max_target_positions = args.max_target_positions + self.max_target_positions = cfg.max_target_positions self.embed_tokens = embed_tokens - self.embed_scale = 1.0 if args.no_scale_embedding else math.sqrt(embed_dim) + self.embed_scale = 1.0 if cfg.no_scale_embedding else math.sqrt(embed_dim) - if not args.adaptive_input and args.quant_noise_pq > 0: + if not cfg.adaptive_input and cfg.quant_noise.pq > 0: self.quant_noise = apply_quant_noise_( nn.Linear(embed_dim, embed_dim, bias=False), - args.quant_noise_pq, - args.quant_noise_pq_block_size, + cfg.quant_noise.pq, + cfg.quant_noise.pq_block_size, ) else: self.quant_noise = None @@ -90,18 +98,17 @@ def __init__( self.max_target_positions, embed_dim, self.padding_idx, - learned=args.decoder_learned_pos, + learned=cfg.decoder.learned_pos, ) - if not args.no_token_positional_embeddings + if not cfg.no_token_positional_embeddings else None ) - export = getattr(args, "export", False) - if getattr(args, "layernorm_embedding", False): - self.layernorm_embedding = LayerNorm(embed_dim, export=export) + if cfg.layernorm_embedding: + self.layernorm_embedding = LayerNorm(embed_dim, export=cfg.export) else: self.layernorm_embedding = None - self.cross_self_attention = getattr(args, "cross_self_attention", False) + self.cross_self_attention = cfg.cross_self_attention if self.decoder_layerdrop > 0.0: self.layers = LayerDropModuleList(p=self.decoder_layerdrop) @@ -109,40 +116,38 @@ def __init__( self.layers = nn.ModuleList([]) self.layers.extend( [ - self.build_decoder_layer(args, no_encoder_attn) - for _ in range(args.decoder_layers) + self.build_decoder_layer(cfg, no_encoder_attn) + for _ in range(cfg.decoder.layers) ] ) self.num_layers = len(self.layers) - if args.decoder_normalize_before and not getattr( - args, "no_decoder_final_norm", False - ): - self.layer_norm = LayerNorm(embed_dim, export=export) + if cfg.decoder.normalize_before and not cfg.no_decoder_final_norm: + self.layer_norm = LayerNorm(embed_dim, export=cfg.export) else: self.layer_norm = None self.project_out_dim = ( Linear(embed_dim, self.output_embed_dim, bias=False) - if embed_dim != self.output_embed_dim and not args.tie_adaptive_weights + if embed_dim != self.output_embed_dim and not cfg.tie_adaptive_weights else None ) self.adaptive_softmax = None self.output_projection = output_projection if self.output_projection is None: - self.build_output_projection(args, dictionary, embed_tokens) + self.build_output_projection(cfg, dictionary, embed_tokens) - def build_output_projection(self, args, dictionary, embed_tokens): - if args.adaptive_softmax_cutoff is not None: + def build_output_projection(self, cfg, dictionary, embed_tokens): + if cfg.adaptive_softmax_cutoff is not None: self.adaptive_softmax = AdaptiveSoftmax( len(dictionary), self.output_embed_dim, - utils.eval_str_list(args.adaptive_softmax_cutoff, type=int), - dropout=args.adaptive_softmax_dropout, - adaptive_inputs=embed_tokens if args.tie_adaptive_weights else None, - factor=args.adaptive_softmax_factor, - tie_proj=args.tie_adaptive_proj, + utils.eval_str_list(cfg.adaptive_softmax_cutoff, type=int), + dropout=cfg.adaptive_softmax_dropout, + adaptive_inputs=embed_tokens if cfg.tie_adaptive_weights else None, + factor=cfg.adaptive_softmax_factor, + tie_proj=cfg.tie_adaptive_proj, ) elif self.share_input_output_embed: self.output_projection = nn.Linear( @@ -158,26 +163,22 @@ def build_output_projection(self, args, dictionary, embed_tokens): nn.init.normal_( self.output_projection.weight, mean=0, std=self.output_embed_dim ** -0.5 ) - num_base_layers = getattr(args, "base_layers", 0) + num_base_layers = cfg.base_layers for i in range(num_base_layers): self.layers.insert( - ((i + 1) * args.decoder_layers) // (num_base_layers + 1), - BaseLayer(args), + ((i + 1) * cfg.decoder.layers) // (num_base_layers + 1), + BaseLayer(cfg), ) - def build_decoder_layer(self, args, no_encoder_attn=False): - layer = transformer_layer.TransformerDecoderLayer(args, no_encoder_attn) - checkpoint = getattr(args, "checkpoint_activations", False) + def build_decoder_layer(self, cfg, no_encoder_attn=False): + layer = transformer_layer.TransformerDecoderLayerBase(cfg, no_encoder_attn) + checkpoint = cfg.checkpoint_activations if checkpoint: - offload_to_cpu = getattr(args, "offload_activations", False) + offload_to_cpu = cfg.offload_activations layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) # if we are checkpointing, enforce that FSDP always wraps the # checkpointed layer, regardless of layer size - min_params_to_wrap = ( - getattr(args, "min_params_to_wrap", transformer_model.DEFAULT_MIN_PARAMS_TO_WRAP) - if not checkpoint - else 0 - ) + min_params_to_wrap = cfg.min_params_to_wrap if not checkpoint else 0 layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) return layer @@ -450,3 +451,32 @@ def Linear(in_features, out_features, bias=True): if bias: nn.init.constant_(m.bias, 0.0) return m + + +class TransformerDecoder(TransformerDecoderBase): + def __init__( + self, + args, + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=None, + ): + self.args = args + super().__init__( + TransformerConfig.from_namespace(args), + dictionary, + embed_tokens, + no_encoder_attn=no_encoder_attn, + output_projection=output_projection, + ) + + def build_output_projection(self, args, dictionary, embed_tokens): + super().build_output_projection( + TransformerConfig.from_namespace(args), dictionary, embed_tokens + ) + + def build_decoder_layer(self, args, no_encoder_attn=False): + return super().build_decoder_layer( + TransformerConfig.from_namespace(args), no_encoder_attn=no_encoder_attn + ) diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index 6e57af5433..f007776a6f 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -3,7 +3,6 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - import math from typing import Dict, List, Optional @@ -19,16 +18,26 @@ PositionalEmbedding, SinusoidalPositionalEmbedding, ) -from fairseq.modules.transformer_layer import TransformerEncoderLayer +from fairseq.modules import transformer_layer from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ from torch import Tensor -from fairseq.models.transformer import transformer_model +from fairseq.models.transformer import ( + TransformerConfig, +) + + +# rewrite name for backward compatibility in `make_generation_fast_` +def module_name_fordropout(module_name: str) -> str: + if module_name == 'TransformerEncoderBase': + return 'TransformerEncoder' + else: + return module_name -class TransformerEncoder(FairseqEncoder): +class TransformerEncoderBase(FairseqEncoder): """ - Transformer encoder consisting of *args.encoder_layers* layers. Each layer + Transformer encoder consisting of *cfg.encoder.layers* layers. Each layer is a :class:`TransformerEncoderLayer`. Args: @@ -37,45 +46,44 @@ class TransformerEncoder(FairseqEncoder): embed_tokens (torch.nn.Embedding): input embedding """ - def __init__(self, args, dictionary, embed_tokens): - self.args = args + def __init__(self, cfg, dictionary, embed_tokens): + self.cfg = cfg super().__init__(dictionary) self.register_buffer("version", torch.Tensor([3])) self.dropout_module = FairseqDropout( - args.dropout, module_name=self.__class__.__name__ + cfg.dropout, module_name=module_name_fordropout(self.__class__.__name__) ) - self.encoder_layerdrop = args.encoder_layerdrop + self.encoder_layerdrop = cfg.encoder.layerdrop embed_dim = embed_tokens.embedding_dim self.padding_idx = embed_tokens.padding_idx - self.max_source_positions = args.max_source_positions + self.max_source_positions = cfg.max_source_positions self.embed_tokens = embed_tokens - self.embed_scale = 1.0 if args.no_scale_embedding else math.sqrt(embed_dim) + self.embed_scale = 1.0 if cfg.no_scale_embedding else math.sqrt(embed_dim) self.embed_positions = ( PositionalEmbedding( - args.max_source_positions, + cfg.max_source_positions, embed_dim, self.padding_idx, - learned=args.encoder_learned_pos, + learned=cfg.encoder.learned_pos, ) - if not args.no_token_positional_embeddings + if not cfg.no_token_positional_embeddings else None ) - export = getattr(args, "export", False) - if getattr(args, "layernorm_embedding", False): - self.layernorm_embedding = LayerNorm(embed_dim, export=export) + if cfg.layernorm_embedding: + self.layernorm_embedding = LayerNorm(embed_dim, export=cfg.export) else: self.layernorm_embedding = None - if not args.adaptive_input and args.quant_noise_pq > 0: + if not cfg.adaptive_input and cfg.quant_noise.pq > 0: self.quant_noise = apply_quant_noise_( nn.Linear(embed_dim, embed_dim, bias=False), - args.quant_noise_pq, - args.quant_noise_pq_block_size, + cfg.quant_noise.pq, + cfg.quant_noise.pq_block_size, ) else: self.quant_noise = None @@ -85,28 +93,24 @@ def __init__(self, args, dictionary, embed_tokens): else: self.layers = nn.ModuleList([]) self.layers.extend( - [self.build_encoder_layer(args) for i in range(args.encoder_layers)] + [self.build_encoder_layer(cfg) for i in range(cfg.encoder.layers)] ) self.num_layers = len(self.layers) - if args.encoder_normalize_before: - self.layer_norm = LayerNorm(embed_dim, export=export) + if cfg.encoder.normalize_before: + self.layer_norm = LayerNorm(embed_dim, export=cfg.export) else: self.layer_norm = None - def build_encoder_layer(self, args): - layer = TransformerEncoderLayer(args) - checkpoint = getattr(args, "checkpoint_activations", False) + def build_encoder_layer(self, cfg): + layer = transformer_layer.TransformerEncoderLayerBase(cfg) + checkpoint = cfg.checkpoint_activations if checkpoint: - offload_to_cpu = getattr(args, "offload_activations", False) + offload_to_cpu = cfg.offload_activations layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) # if we are checkpointing, enforce that FSDP always wraps the # checkpointed layer, regardless of layer size - min_params_to_wrap = ( - getattr(args, "min_params_to_wrap", transformer_model.DEFAULT_MIN_PARAMS_TO_WRAP) - if not checkpoint - else 0 - ) + min_params_to_wrap = cfg.min_params_to_wrap if not checkpoint else 0 layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) return layer @@ -320,3 +324,18 @@ def upgrade_state_dict_named(self, state_dict, name): self.normalize = False state_dict[version_key] = torch.Tensor([1]) return state_dict + + +class TransformerEncoder(TransformerEncoderBase): + def __init__(self, args, dictionary, embed_tokens): + self.args = args + super().__init__( + TransformerConfig.from_namespace(args), + dictionary, + embed_tokens, + ) + + def build_encoder_layer(self, args): + return super().build_encoder_layer( + TransformerConfig.from_namespace(args), + ) diff --git a/fairseq/models/transformer/transformer_model.py b/fairseq/models/transformer/transformer_legacy.py similarity index 50% rename from fairseq/models/transformer/transformer_model.py rename to fairseq/models/transformer/transformer_legacy.py index 7cc5b64ad1..9534e400b5 100644 --- a/fairseq/models/transformer/transformer_model.py +++ b/fairseq/models/transformer/transformer_legacy.py @@ -3,44 +3,26 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from typing import Dict, List, Optional, Tuple - -import torch.nn as nn -import torch -from fairseq import utils -from fairseq.distributed import fsdp_wrap from fairseq.models import ( - FairseqEncoderDecoderModel, register_model, register_model_architecture, ) -from torch import Tensor -from fairseq.models import transformer - - -DEFAULT_MAX_SOURCE_POSITIONS = 1024 -DEFAULT_MAX_TARGET_POSITIONS = 1024 - - -DEFAULT_MIN_PARAMS_TO_WRAP = int(1e8) +from fairseq.models.transformer.transformer_config import ( + TransformerConfig, + DEFAULT_MAX_SOURCE_POSITIONS, + DEFAULT_MAX_TARGET_POSITIONS, + DEFAULT_MIN_PARAMS_TO_WRAP, +) +from fairseq.models.transformer.transformer_base import ( + TransformerModelBase, +) @register_model("transformer") -class TransformerModel(FairseqEncoderDecoderModel): +class TransformerModel(TransformerModelBase): """ - Transformer model from `"Attention Is All You Need" (Vaswani, et al, 2017) - <https://arxiv.org/abs/1706.03762>`_. - - Args: - encoder (TransformerEncoder): the encoder - decoder (TransformerDecoder): the decoder - - The Transformer model provides the following named architectures and - command-line arguments: - - .. argparse:: - :ref: fairseq.models.transformer_parser - :prog: + This is the legacy implementation of the transformer model that + uses argparse for configuration. """ @classmethod @@ -92,109 +74,9 @@ def spm(path): # fmt: on def __init__(self, args, encoder, decoder): - super().__init__(encoder, decoder) + cfg = TransformerConfig.from_namespace(args) + super().__init__(cfg, encoder, decoder) self.args = args - self.supports_align_args = True - - @staticmethod - def add_args(parser): - """Add model-specific arguments to the parser.""" - # fmt: off - parser.add_argument('--activation-fn', - choices=utils.get_available_activation_fns(), - help='activation function to use') - parser.add_argument('--dropout', type=float, metavar='D', - help='dropout probability') - parser.add_argument('--attention-dropout', type=float, metavar='D', - help='dropout probability for attention weights') - parser.add_argument('--activation-dropout', '--relu-dropout', type=float, metavar='D', - help='dropout probability after activation in FFN.') - parser.add_argument('--encoder-embed-path', type=str, metavar='STR', - help='path to pre-trained encoder embedding') - parser.add_argument('--encoder-embed-dim', type=int, metavar='N', - help='encoder embedding dimension') - parser.add_argument('--encoder-ffn-embed-dim', type=int, metavar='N', - help='encoder embedding dimension for FFN') - parser.add_argument('--encoder-layers', type=int, metavar='N', - help='num encoder layers') - parser.add_argument('--encoder-attention-heads', type=int, metavar='N', - help='num encoder attention heads') - parser.add_argument('--encoder-normalize-before', action='store_true', - help='apply layernorm before each encoder block') - parser.add_argument('--encoder-learned-pos', action='store_true', - help='use learned positional embeddings in the encoder') - parser.add_argument('--decoder-embed-path', type=str, metavar='STR', - help='path to pre-trained decoder embedding') - parser.add_argument('--decoder-embed-dim', type=int, metavar='N', - help='decoder embedding dimension') - parser.add_argument('--decoder-ffn-embed-dim', type=int, metavar='N', - help='decoder embedding dimension for FFN') - parser.add_argument('--decoder-layers', type=int, metavar='N', - help='num decoder layers') - parser.add_argument('--decoder-attention-heads', type=int, metavar='N', - help='num decoder attention heads') - parser.add_argument('--decoder-learned-pos', action='store_true', - help='use learned positional embeddings in the decoder') - parser.add_argument('--decoder-normalize-before', action='store_true', - help='apply layernorm before each decoder block') - parser.add_argument('--decoder-output-dim', type=int, metavar='N', - help='decoder output dimension (extra linear layer ' - 'if different from decoder embed dim') - parser.add_argument('--share-decoder-input-output-embed', action='store_true', - help='share decoder input and output embeddings') - parser.add_argument('--share-all-embeddings', action='store_true', - help='share encoder, decoder and output embeddings' - ' (requires shared dictionary and embed dim)') - parser.add_argument('--no-token-positional-embeddings', default=False, action='store_true', - help='if set, disables positional embeddings (outside self attention)') - parser.add_argument('--adaptive-softmax-cutoff', metavar='EXPR', - help='comma separated list of adaptive softmax cutoff points. ' - 'Must be used with adaptive_loss criterion'), - parser.add_argument('--adaptive-softmax-dropout', type=float, metavar='D', - help='sets adaptive softmax dropout for the tail projections') - parser.add_argument('--layernorm-embedding', action='store_true', - help='add layernorm to embedding') - parser.add_argument('--no-scale-embedding', action='store_true', - help='if True, dont scale embeddings') - parser.add_argument('--checkpoint-activations', action='store_true', - help='checkpoint activations at each layer, which saves GPU ' - 'memory usage at the cost of some additional compute') - parser.add_argument('--offload-activations', action='store_true', - help='checkpoint activations at each layer, then save to gpu. Sets --checkpoint-activations.') - # args for "Cross+Self-Attention for Transformer Models" (Peitz et al., 2019) - parser.add_argument('--no-cross-attention', default=False, action='store_true', - help='do not perform cross-attention') - parser.add_argument('--cross-self-attention', default=False, action='store_true', - help='perform cross+self-attention') - # args for "Reducing Transformer Depth on Demand with Structured Dropout" (Fan et al., 2019) - parser.add_argument('--encoder-layerdrop', type=float, metavar='D', default=0, - help='LayerDrop probability for encoder') - parser.add_argument('--decoder-layerdrop', type=float, metavar='D', default=0, - help='LayerDrop probability for decoder') - parser.add_argument('--encoder-layers-to-keep', default=None, - help='which layers to *keep* when pruning as a comma-separated list') - parser.add_argument('--decoder-layers-to-keep', default=None, - help='which layers to *keep* when pruning as a comma-separated list') - # args for Training with Quantization Noise for Extreme Model Compression ({Fan*, Stock*} et al., 2020) - parser.add_argument('--quant-noise-pq', type=float, metavar='D', default=0, - help='iterative PQ quantization noise at training time') - parser.add_argument('--quant-noise-pq-block-size', type=int, metavar='D', default=8, - help='block size of quantization noise at training time') - parser.add_argument('--quant-noise-scalar', type=float, metavar='D', default=0, - help='scalar quantization noise and scalar quantization at training time') - # args for Fully Sharded Data Parallel (FSDP) training - parser.add_argument( - '--min-params-to-wrap', type=int, metavar='D', default=DEFAULT_MIN_PARAMS_TO_WRAP, - help=( - 'minimum number of params for a layer to be wrapped with FSDP() when ' - 'training with --ddp-backend=fully_sharded. Smaller values will ' - 'improve memory efficiency, but may make torch.distributed ' - 'communication less efficient due to smaller input sizes. This option ' - 'is set to 0 (i.e., always wrap) when --checkpoint-activations or ' - '--offload-activations are passed.' - ) - ) - # fmt: on @classmethod def build_model(cls, args, task): @@ -228,100 +110,38 @@ def build_model(cls, args, task): raise ValueError( "--share-all-embeddings not compatible with --decoder-embed-path" ) - encoder_embed_tokens = cls.build_embedding( - args, src_dict, args.encoder_embed_dim, args.encoder_embed_path - ) - decoder_embed_tokens = encoder_embed_tokens args.share_decoder_input_output_embed = True - else: - encoder_embed_tokens = cls.build_embedding( - args, src_dict, args.encoder_embed_dim, args.encoder_embed_path - ) - decoder_embed_tokens = cls.build_embedding( - args, tgt_dict, args.decoder_embed_dim, args.decoder_embed_path - ) + if getattr(args, "offload_activations", False): args.checkpoint_activations = True # offloading implies checkpointing - encoder = cls.build_encoder(args, src_dict, encoder_embed_tokens) - decoder = cls.build_decoder(args, tgt_dict, decoder_embed_tokens) + if not args.share_all_embeddings: - min_params_to_wrap = getattr( + args.min_params_to_wrap = getattr( args, "min_params_to_wrap", DEFAULT_MIN_PARAMS_TO_WRAP ) - # fsdp_wrap is a no-op when --ddp-backend != fully_sharded - encoder = fsdp_wrap(encoder, min_num_params=min_params_to_wrap) - decoder = fsdp_wrap(decoder, min_num_params=min_params_to_wrap) - return cls(args, encoder, decoder) + cfg = TransformerConfig.from_namespace(args) + return super().build_model(cfg, task) @classmethod def build_embedding(cls, args, dictionary, embed_dim, path=None): - num_embeddings = len(dictionary) - padding_idx = dictionary.pad() - - emb = Embedding(num_embeddings, embed_dim, padding_idx) - # if provided, load from preloaded dictionaries - if path: - embed_dict = utils.parse_embedding(path) - utils.load_embedding(embed_dict, dictionary, emb) - return emb + return super().build_embedding( + TransformerConfig.from_namespace(args), dictionary, embed_dim, path + ) @classmethod def build_encoder(cls, args, src_dict, embed_tokens): - return transformer.TransformerEncoder(args, src_dict, embed_tokens) + return super().build_encoder( + TransformerConfig.from_namespace(args), src_dict, embed_tokens + ) @classmethod def build_decoder(cls, args, tgt_dict, embed_tokens): - return transformer.TransformerDecoder( - args, - tgt_dict, - embed_tokens, - no_encoder_attn=getattr(args, "no_cross_attention", False), + return super().build_decoder( + TransformerConfig.from_namespace(args), tgt_dict, embed_tokens ) - # TorchScript doesn't support optional arguments with variable length (**kwargs). - # Current workaround is to add union of all arguments in child classes. - def forward( - self, - src_tokens, - src_lengths, - prev_output_tokens, - return_all_hiddens: bool = True, - features_only: bool = False, - alignment_layer: Optional[int] = None, - alignment_heads: Optional[int] = None, - ): - """ - Run the forward pass for an encoder-decoder model. - - Copied from the base class, but without ``**kwargs``, - which are not supported by TorchScript. - """ - encoder_out = self.encoder( - src_tokens, src_lengths=src_lengths, return_all_hiddens=return_all_hiddens - ) - decoder_out = self.decoder( - prev_output_tokens, - encoder_out=encoder_out, - features_only=features_only, - alignment_layer=alignment_layer, - alignment_heads=alignment_heads, - src_lengths=src_lengths, - return_all_hiddens=return_all_hiddens, - ) - return decoder_out - - # Since get_normalized_probs is in the Fairseq Model which is not scriptable, - # I rewrite the get_normalized_probs from Base Class to call the - # helper function in the Base Class. - @torch.jit.export - def get_normalized_probs( - self, - net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], - log_probs: bool, - sample: Optional[Dict[str, Tensor]] = None, - ): - """Get normalized probabilities (or log probs) from a net's output.""" - return self.get_normalized_probs_scriptable(net_output, log_probs, sample) + +# architectures @register_model_architecture("transformer", "transformer_tiny") @@ -443,10 +263,3 @@ def transformer_wmt_en_de_big_t2t(args): args.attention_dropout = getattr(args, "attention_dropout", 0.1) args.activation_dropout = getattr(args, "activation_dropout", 0.1) transformer_vaswani_wmt_en_de_big(args) - - -def Embedding(num_embeddings, embedding_dim, padding_idx): - m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) - nn.init.constant_(m.weight[padding_idx], 0) - return m diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 9bdca0f6af..a251635611 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -148,7 +148,7 @@ def forward( tgt_len, bsz, embed_dim = query.size() src_len = tgt_len - assert embed_dim == self.embed_dim + assert embed_dim == self.embed_dim, f"query dim {embed_dim} != {self.embed_dim}" assert list(query.size()) == [tgt_len, bsz, embed_dim] if key is not None: src_len, key_bsz, _ = key.size() diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index aa06a42935..de25de6564 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -12,9 +12,12 @@ from fairseq.modules.fairseq_dropout import FairseqDropout from fairseq.modules.quant_noise import quant_noise from torch import Tensor +from fairseq.models.transformer import ( + TransformerConfig, +) -class TransformerEncoderLayer(nn.Module): +class TransformerEncoderLayerBase(nn.Module): """Encoder layer block. In the original paper each operation (multi-head attention or FFN) is @@ -23,49 +26,46 @@ class TransformerEncoderLayer(nn.Module): preprocessing each layer with layernorm and postprocessing with: `dropout -> add residual`. We default to the approach in the paper, but the tensor2tensor approach can be enabled by setting - *args.encoder_normalize_before* to ``True``. + *cfg.encoder.normalize_before* to ``True``. Args: args (argparse.Namespace): parsed command-line arguments """ - def __init__(self, args): + def __init__(self, cfg): super().__init__() - self.args = args - self.embed_dim = args.encoder_embed_dim - self.quant_noise = getattr(args, "quant_noise_pq", 0) - self.quant_noise_block_size = getattr(args, "quant_noise_pq_block_size", 8) or 8 - self.self_attn = self.build_self_attention(self.embed_dim, args) - export = getattr(args, "export", False) - self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + self.cfg = cfg + self.embed_dim = cfg.encoder.embed_dim + self.quant_noise = cfg.quant_noise.pq + self.quant_noise_block_size = cfg.quant_noise.pq_block_size + self.self_attn = self.build_self_attention(self.embed_dim, cfg) + self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) self.dropout_module = FairseqDropout( - args.dropout, module_name=self.__class__.__name__ - ) - self.activation_fn = utils.get_activation_fn( - activation=getattr(args, "activation_fn", "relu") or "relu" + cfg.dropout, module_name=self.__class__.__name__ ) - activation_dropout_p = getattr(args, "activation_dropout", 0) or 0 + self.activation_fn = utils.get_activation_fn(activation=cfg.activation_fn) + activation_dropout_p = cfg.activation_dropout if activation_dropout_p == 0: - # for backwards compatibility with models that use args.relu_dropout - activation_dropout_p = getattr(args, "relu_dropout", 0) or 0 + # for backwards compatibility with models that use cfg.relu_dropout + activation_dropout_p = cfg.relu_dropout or 0 self.activation_dropout_module = FairseqDropout( float(activation_dropout_p), module_name=self.__class__.__name__ ) - self.normalize_before = args.encoder_normalize_before + self.normalize_before = cfg.encoder.normalize_before self.fc1 = self.build_fc1( self.embed_dim, - args.encoder_ffn_embed_dim, + cfg.encoder.ffn_embed_dim, self.quant_noise, self.quant_noise_block_size, ) self.fc2 = self.build_fc2( - args.encoder_ffn_embed_dim, + cfg.encoder.ffn_embed_dim, self.embed_dim, self.quant_noise, self.quant_noise_block_size, ) - self.final_layer_norm = LayerNorm(self.embed_dim, export=export) + self.final_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): return quant_noise( @@ -77,11 +77,11 @@ def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size): nn.Linear(input_dim, output_dim), p=q_noise, block_size=qn_block_size ) - def build_self_attention(self, embed_dim, args): + def build_self_attention(self, embed_dim, cfg): return MultiheadAttention( embed_dim, - args.encoder_attention_heads, - dropout=args.attention_dropout, + cfg.encoder.attention_heads, + dropout=cfg.attention_dropout, self_attention=True, q_noise=self.quant_noise, qn_block_size=self.quant_noise_block_size, @@ -162,7 +162,19 @@ def forward( return x -class TransformerDecoderLayer(nn.Module): +# backward compatible with the legacy argparse format +class TransformerEncoderLayer(TransformerEncoderLayerBase): + def __init__(self, args): + super().__init__(TransformerConfig.from_namespace(args)) + self.args = args + + def build_self_attention(self, embed_dim, args): + return super().build_self_attention( + embed_dim, TransformerConfig.from_namespace(args) + ) + + +class TransformerDecoderLayerBase(nn.Module): """Decoder layer block. In the original paper each operation (multi-head attention, encoder @@ -171,7 +183,7 @@ class TransformerDecoderLayer(nn.Module): robust when preprocessing each layer with layernorm and postprocessing with: `dropout -> add residual`. We default to the approach in the paper, but the tensor2tensor approach can be enabled by setting - *args.decoder_normalize_before* to ``True``. + *cfg.decoder.normalize_before* to ``True``. Args: args (argparse.Namespace): parsed command-line arguments @@ -180,63 +192,58 @@ class TransformerDecoderLayer(nn.Module): """ def __init__( - self, args, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False + self, cfg, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False ): super().__init__() - self.embed_dim = args.decoder_embed_dim + self.embed_dim = cfg.decoder.embed_dim self.dropout_module = FairseqDropout( - args.dropout, module_name=self.__class__.__name__ + cfg.dropout, module_name=self.__class__.__name__ ) - self.quant_noise = getattr(args, "quant_noise_pq", 0) - self.quant_noise_block_size = getattr(args, "quant_noise_pq_block_size", 8) + self.quant_noise = cfg.quant_noise.pq + self.quant_noise_block_size = cfg.quant_noise.pq_block_size - self.cross_self_attention = getattr(args, "cross_self_attention", False) + self.cross_self_attention = cfg.cross_self_attention self.self_attn = self.build_self_attention( self.embed_dim, - args, + cfg, add_bias_kv=add_bias_kv, add_zero_attn=add_zero_attn, ) - self.activation_fn = utils.get_activation_fn( - activation=str(args.activation_fn) - if getattr(args, "activation_fn", None) is not None - else "relu" - ) - activation_dropout_p = getattr(args, "activation_dropout", 0) or 0 + self.activation_fn = utils.get_activation_fn(activation=cfg.activation_fn) + activation_dropout_p = cfg.activation_dropout if activation_dropout_p == 0: - # for backwards compatibility with models that use args.relu_dropout - activation_dropout_p = getattr(args, "relu_dropout", 0) or 0 + # for backwards compatibility with models that use cfg.relu_dropout + activation_dropout_p = cfg.relu_dropout or 0 self.activation_dropout_module = FairseqDropout( float(activation_dropout_p), module_name=self.__class__.__name__ ) - self.normalize_before = args.decoder_normalize_before + self.normalize_before = cfg.decoder.normalize_before - export = getattr(args, "export", False) - self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) if no_encoder_attn: self.encoder_attn = None self.encoder_attn_layer_norm = None else: - self.encoder_attn = self.build_encoder_attention(self.embed_dim, args) - self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + self.encoder_attn = self.build_encoder_attention(self.embed_dim, cfg) + self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) self.fc1 = self.build_fc1( self.embed_dim, - args.decoder_ffn_embed_dim, + cfg.decoder.ffn_embed_dim, self.quant_noise, self.quant_noise_block_size, ) self.fc2 = self.build_fc2( - args.decoder_ffn_embed_dim, + cfg.decoder.ffn_embed_dim, self.embed_dim, self.quant_noise, self.quant_noise_block_size, ) - self.final_layer_norm = LayerNorm(self.embed_dim, export=export) + self.final_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) self.need_attn = True self.onnx_trace = False @@ -248,26 +255,26 @@ def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size): return quant_noise(nn.Linear(input_dim, output_dim), q_noise, qn_block_size) def build_self_attention( - self, embed_dim, args, add_bias_kv=False, add_zero_attn=False + self, embed_dim, cfg, add_bias_kv=False, add_zero_attn=False ): return MultiheadAttention( embed_dim, - args.decoder_attention_heads, - dropout=args.attention_dropout, + cfg.decoder.attention_heads, + dropout=cfg.attention_dropout, add_bias_kv=add_bias_kv, add_zero_attn=add_zero_attn, - self_attention=not getattr(args, "cross_self_attention", False), + self_attention=not cfg.cross_self_attention, q_noise=self.quant_noise, qn_block_size=self.quant_noise_block_size, ) - def build_encoder_attention(self, embed_dim, args): + def build_encoder_attention(self, embed_dim, cfg): return MultiheadAttention( embed_dim, - args.decoder_attention_heads, - kdim=getattr(args, "encoder_embed_dim", None), - vdim=getattr(args, "encoder_embed_dim", None), - dropout=args.attention_dropout, + cfg.decoder.attention_heads, + kdim=cfg.encoder.embed_dim, + vdim=cfg.encoder.embed_dim, + dropout=cfg.attention_dropout, encoder_decoder_attention=True, q_noise=self.quant_noise, qn_block_size=self.quant_noise_block_size, @@ -417,3 +424,33 @@ def forward( def make_generation_fast_(self, need_attn: bool = False, **kwargs): self.need_attn = need_attn + + +# backward compatible with the legacy argparse format +class TransformerDecoderLayer(TransformerDecoderLayerBase): + def __init__( + self, args, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False + ): + super().__init__( + TransformerConfig.from_namespace(args), + no_encoder_attn=no_encoder_attn, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + self.args = args + + def build_self_attention( + self, embed_dim, args, add_bias_kv=False, add_zero_attn=False + ): + return super().build_self_attention( + embed_dim, + TransformerConfig.from_namespace(args), + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + + def build_encoder_attention(self, embed_dim, args): + return super().build_encoder_attention( + embed_dim, + TransformerConfig.from_namespace(args), + ) From c1624b273b206cc7c0a1529be4d2f35b38607ec5 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Fri, 16 Jul 2021 05:45:38 -0700 Subject: [PATCH 409/774] Criterions to Hydra Summary: convert a couple of criterions to hydra Reviewed By: dianaml0 Differential Revision: D29585608 fbshipit-source-id: 7790b767ed55f58bbcc0c237cfa689684b9bf5e2 --- ...l_smoothed_cross_entropy_with_alignment.py | 33 +++++++++++-------- fairseq/criterions/nat_loss.py | 24 +++++++------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py b/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py index 73cfa05310..2ea37c16b4 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py @@ -8,10 +8,27 @@ from fairseq import metrics, utils from fairseq.criterions import register_criterion -from .label_smoothed_cross_entropy import LabelSmoothedCrossEntropyCriterion +from .label_smoothed_cross_entropy import ( + LabelSmoothedCrossEntropyCriterion, + LabelSmoothedCrossEntropyCriterionConfig, +) +from dataclasses import dataclass, field -@register_criterion("label_smoothed_cross_entropy_with_alignment") + +@dataclass +class LabelSmoothedCrossEntropyCriterionWithAlignmentConfig( + LabelSmoothedCrossEntropyCriterionConfig +): + alignment_lambda: float = field( + default=0.05, metadata={"help": "weight for the alignment loss"} + ) + + +@register_criterion( + "label_smoothed_cross_entropy_with_alignment", + dataclass=LabelSmoothedCrossEntropyCriterionWithAlignmentConfig, +) class LabelSmoothedCrossEntropyCriterionWithAlignment( LabelSmoothedCrossEntropyCriterion ): @@ -19,18 +36,6 @@ def __init__(self, task, sentence_avg, label_smoothing, alignment_lambda): super().__init__(task, sentence_avg, label_smoothing) self.alignment_lambda = alignment_lambda - @staticmethod - def add_args(parser): - """Add criterion-specific arguments to the parser.""" - LabelSmoothedCrossEntropyCriterion.add_args(parser) - parser.add_argument( - "--alignment-lambda", - default=0.05, - type=float, - metavar="D", - help="weight for the alignment loss", - ) - def forward(self, model, sample, reduce=True): """Compute the loss for the given sample. diff --git a/fairseq/criterions/nat_loss.py b/fairseq/criterions/nat_loss.py index cdc7da861d..7dac32fbaf 100644 --- a/fairseq/criterions/nat_loss.py +++ b/fairseq/criterions/nat_loss.py @@ -9,26 +9,26 @@ import torch.nn.functional as F from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass from torch import Tensor +from dataclasses import dataclass, field -@register_criterion("nat_loss") + +@dataclass +class LabelSmoothedDualImitationCriterionConfig(FairseqDataclass): + label_smoothing: float = field( + default=0.0, + metadata={"help": "epsilon for label smoothing, 0 means no label smoothing"}, + ) + + +@register_criterion("nat_loss", dataclass=LabelSmoothedDualImitationCriterionConfig) class LabelSmoothedDualImitationCriterion(FairseqCriterion): def __init__(self, task, label_smoothing): super().__init__(task) self.label_smoothing = label_smoothing - @staticmethod - def add_args(parser): - """Add criterion-specific arguments to the parser.""" - parser.add_argument( - "--label-smoothing", - default=0.0, - type=float, - metavar="D", - help="epsilon for label smoothing, 0 means no label smoothing", - ) - def _compute_loss( self, outputs, targets, masks=None, label_smoothing=0.0, name="loss", factor=1.0 ): From 72323586aeae75e2b704c1c936784471bfa75019 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Tue, 20 Jul 2021 11:30:28 -0700 Subject: [PATCH 410/774] Add warning when combining --ddp-backend=fully_sharded and --update-freq (#2076) Summary: Add warning when combining `--ddp-backend=fully_sharded` and `--update-freq`, since that will result in increased memory usage. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2076 Reviewed By: xianxl Differential Revision: D29791364 Pulled By: myleott fbshipit-source-id: 5748f20484840f61a16448f1287b0f2e3b3ce9d8 --- fairseq/trainer.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 1deb14326f..1602688671 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -72,6 +72,12 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): "FullyShardedDataParallel is not compatible with --zero-sharding " "option (it's already built in)" ) + if self.cfg.optimization.update_freq[0] > 1: + logger.warning( + "Combining --update-freq with FullyShardedDataParallel will " + "result in increased memory usage, since full-sized gradients " + "will be accumulated on each GPU!" + ) else: if ( hasattr(self.cfg.distributed_training, "cpu_offload") From 804b49397606328221dd7296026c9bcc04a967d1 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Wed, 21 Jul 2021 13:16:15 -0700 Subject: [PATCH 411/774] Several updates on simultaneous translation (#1831) Summary: This pull request includes several updates and refactoring related to simultaneous translation 1. Add mixed precision training for simultaneous translation decoder (avoiding nan errors) 2. Add unit test for simultaneous decoders `cd examples/simultaneous_translation; python -m unittest test_text_models.py` 3. Simplify the inference code (simuleval only) 4. Reorganize code structure 5. Remove duplicated / deprecated code 6. Fixed a bug for waitk p_choose generation 7. Fixed a issue when using fixed_pre_decision + mma The update won't affect the current training. The old checkpoint can still be loaded and infered. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1831 Test Plan: Imported from GitHub, without a `Test Plan:` line. f286829279 f286829286 Reviewed By: sravyapopuri388 Differential Revision: D28082398 Pulled By: xutaima fbshipit-source-id: 882d077e7f1b94870f8328dba89660a4f3bd5d9c --- .../models/transformer_monotonic_attention.py | 98 +- .../modules/__init__.py | 5 +- .../modules/fixed_pre_decision.py | 90 +- .../modules/monotonic_multihead_attention.py | 1011 +++++------------ .../modules/monotonic_transformer_layer.py | 46 +- .../tests/test_text_models.py | 407 +++++++ .../utils/functions.py | 81 +- .../utils/monotonic_attention.py | 196 ++++ .../utils/p_choose_strategy.py | 82 +- 9 files changed, 1049 insertions(+), 967 deletions(-) create mode 100644 examples/simultaneous_translation/tests/test_text_models.py create mode 100644 examples/simultaneous_translation/utils/monotonic_attention.py diff --git a/examples/simultaneous_translation/models/transformer_monotonic_attention.py b/examples/simultaneous_translation/models/transformer_monotonic_attention.py index 77c0350d2d..b0cdc43483 100644 --- a/examples/simultaneous_translation/models/transformer_monotonic_attention.py +++ b/examples/simultaneous_translation/models/transformer_monotonic_attention.py @@ -7,7 +7,6 @@ import torch import torch.nn as nn -import torch.nn.functional as F from examples.simultaneous_translation.modules.monotonic_transformer_layer import ( TransformerMonotonicDecoderLayer, TransformerMonotonicEncoderLayer, @@ -23,12 +22,14 @@ base_architecture, transformer_iwslt_de_en, transformer_vaswani_wmt_en_de_big, - transformer_vaswani_wmt_en_fr_big, + tiny_architecture ) from torch import Tensor DEFAULT_MAX_SOURCE_POSITIONS = 1024 DEFAULT_MAX_TARGET_POSITIONS = 1024 +READ_ACTION = 0 +WRITE_ACTION = 1 TransformerMonotonicDecoderOut = NamedTuple( "TransformerMonotonicDecoderOut", @@ -36,7 +37,6 @@ ("action", int), ("p_choose", Optional[Tensor]), ("attn_list", Optional[List[Optional[Dict[str, Tensor]]]]), - ("step_list", Optional[List[Optional[Tensor]]]), ("encoder_out", Optional[Dict[str, List[Tensor]]]), ("encoder_padding_mask", Optional[Tensor]), ], @@ -60,26 +60,6 @@ def build_encoder(cls, args, src_dict, embed_tokens): def build_decoder(cls, args, tgt_dict, embed_tokens): return TransformerMonotonicDecoder(args, tgt_dict, embed_tokens) - def _indices_from_states(self, states): - if type(states["indices"]["src"]) == list: - if next(self.parameters()).is_cuda: - tensor = torch.cuda.LongTensor - else: - tensor = torch.LongTensor - - src_indices = tensor( - [states["indices"]["src"][: 1 + states["steps"]["src"]]] - ) - - tgt_indices = tensor( - [[self.decoder.dictionary.eos()] + states["indices"]["tgt"]] - ) - else: - src_indices = states["indices"]["src"][: 1 + states["steps"]["src"]] - tgt_indices = states["indices"]["tgt"] - - return src_indices, None, tgt_indices - class TransformerMonotonicEncoder(TransformerEncoder): def __init__(self, args, dictionary, embed_tokens): @@ -88,7 +68,10 @@ def __init__(self, args, dictionary, embed_tokens): self.dictionary = dictionary self.layers = nn.ModuleList([]) self.layers.extend( - [TransformerMonotonicEncoderLayer(args) for i in range(args.encoder_layers)] + [ + TransformerMonotonicEncoderLayer(args) + for i in range(args.encoder_layers) + ] ) @@ -112,10 +95,11 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): self.layers = nn.ModuleList([]) self.layers.extend( [ - TransformerMonotonicDecoderLayer(args, no_encoder_attn) + TransformerMonotonicDecoderLayer(args) for _ in range(args.decoder_layers) ] ) + self.policy_criterion = getattr(args, "policy_criterion", "any") def pre_attention( self, @@ -176,14 +160,15 @@ def post_attention(self, x): return x - def clear_cache( + def clean_cache( self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], end_id: Optional[int] = None, ): """ - Clear cache in the monotonic layers. - The cache is generated because of a forward pass of decode but no prediction. + Clean cache in the monotonic layers. + The cache is generated because of a forward pass of decoder has run but no prediction, + so that the self attention key value in decoder is written in the incremental state. end_id is the last idx of the layers """ if end_id is None: @@ -218,7 +203,6 @@ def extract_features( attn = None inner_states = [x] attn_list: List[Optional[Dict[str, Tensor]]] = [] - step_list: List[Optional[Tensor]] = [] p_choose = torch.tensor([1.0]) @@ -238,36 +222,28 @@ def extract_features( attn_list.append(attn) if incremental_state is not None: - curr_steps = layer.get_head_steps(incremental_state) - step_list.append(curr_steps) if_online = incremental_state["online"]["only"] assert if_online is not None if if_online.to(torch.bool): # Online indicates that the encoder states are still changing assert attn is not None - assert curr_steps is not None - p_choose = ( - attn["p_choose"].squeeze(0).squeeze(1).gather(1, curr_steps.t()) - ) - - new_steps = curr_steps + (p_choose < 0.5).t().type_as(curr_steps) - src = incremental_state["steps"]["src"] - assert src is not None - - if (new_steps >= src).any(): - # We need to prune the last self_attn saved_state - # if model decide not to read - # otherwise there will be duplicated saved_state - self.clear_cache(incremental_state, i + 1) - - return x, TransformerMonotonicDecoderOut( - action=0, - p_choose=p_choose, - attn_list=None, - step_list=None, - encoder_out=None, - encoder_padding_mask=None, - ) + if self.policy_criterion == "any": + # Any head decide to read than read + head_read = layer.encoder_attn._get_monotonic_buffer(incremental_state)["head_read"] + assert head_read is not None + if head_read.any(): + # We need to prune the last self_attn saved_state + # if model decide not to read + # otherwise there will be duplicated saved_state + self.clean_cache(incremental_state, i + 1) + + return x, TransformerMonotonicDecoderOut( + action=0, + p_choose=p_choose, + attn_list=None, + encoder_out=None, + encoder_padding_mask=None, + ) x = self.post_attention(x) @@ -275,18 +251,10 @@ def extract_features( action=1, p_choose=p_choose, attn_list=attn_list, - step_list=step_list, encoder_out=encoder_out, encoder_padding_mask=encoder_padding_mask, ) - def reorder_incremental_state(self, incremental_state, new_order): - super().reorder_incremental_state(incremental_state, new_order) - if "fastest_step" in incremental_state: - incremental_state["fastest_step"] = incremental_state[ - "fastest_step" - ].index_select(0, new_order) - @register_model_architecture("transformer_monotonic", "transformer_monotonic") def base_monotonic_architecture(args): @@ -322,3 +290,9 @@ def transformer_monotonic_vaswani_wmt_en_fr_big(args): ) def transformer_unidirectional_iwslt_de_en(args): transformer_iwslt_de_en(args) + + +@register_model_architecture("transformer_monotonic", "transformer_monotonic_tiny") +def monotonic_tiny_architecture(args): + tiny_architecture(args) + base_monotonic_architecture(args) diff --git a/examples/simultaneous_translation/modules/__init__.py b/examples/simultaneous_translation/modules/__init__.py index c695850c04..f5ea180f9b 100644 --- a/examples/simultaneous_translation/modules/__init__.py +++ b/examples/simultaneous_translation/modules/__init__.py @@ -3,12 +3,11 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import importlib -import os +import os +import importlib from fairseq import registry - ( build_monotonic_attention, register_monotonic_attention, diff --git a/examples/simultaneous_translation/modules/fixed_pre_decision.py b/examples/simultaneous_translation/modules/fixed_pre_decision.py index dd29c031b3..3991414aed 100644 --- a/examples/simultaneous_translation/modules/fixed_pre_decision.py +++ b/examples/simultaneous_translation/modules/fixed_pre_decision.py @@ -7,12 +7,12 @@ from . import register_monotonic_attention from .monotonic_multihead_attention import ( - MonotonicMultiheadAttentionWaitK, - MonotonicMultiheadAttentionHardAligned, - MonotonicMultiheadAttentionInfiniteLookback, + MonotonicAttention, + MonotonicInfiniteLookbackAttention, + WaitKAttention ) from typing import Dict, Optional -from examples.simultaneous_translation.utils import p_choose_strategy + def fixed_pooling_monotonic_attention(monotonic_attention): def create_model(monotonic_attention, klass): @@ -26,10 +26,7 @@ def __init__(self, args): self.pre_decision_type = args.fixed_pre_decision_type self.pre_decision_ratio = args.fixed_pre_decision_ratio self.pre_decision_pad_threshold = args.fixed_pre_decision_pad_threshold - if self.pre_decision_ratio == 1: - return - - self.strategy = args.simul_type + assert self.pre_decision_ratio > 1 if args.fixed_pre_decision_type == "average": self.pooling_layer = torch.nn.AvgPool1d( @@ -46,7 +43,7 @@ def last(key): k = key[ :, :, - self.pre_decision_ratio - 1 :: self.pre_decision_ratio, + self.pre_decision_ratio - 1:: self.pre_decision_ratio, ].contiguous() if key.size(-1) % self.pre_decision_ratio != 0: k = torch.cat([k, key[:, :, -1:]], dim=-1).contiguous() @@ -97,45 +94,6 @@ def insert_zeros(self, x): ) return x_upsample.squeeze(1).view(bsz_num_heads, tgt_len, -1) - def p_choose_waitk( - self, query, key, key_padding_mask: Optional[Tensor] = None, - incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None - ): - """ - query: bsz, tgt_len - key: bsz, src_len - key_padding_mask: bsz, src_len - """ - if incremental_state is not None: - # Retrieve target length from incremental states - # For inference the length of query is always 1 - tgt = incremental_state["steps"]["tgt"] - assert tgt is not None - tgt_len = int(tgt) - else: - tgt_len, bsz, _ = query.size() - - src_len, bsz, _ = key.size() - - p_choose = torch.ones(bsz, tgt_len, src_len).to(query) - p_choose = torch.tril(p_choose, diagonal=self.waitk_lagging - 1) - p_choose = torch.triu(p_choose, diagonal=self.waitk_lagging - 1) - - if incremental_state is not None: - p_choose = p_choose[:, -1:] - tgt_len = 1 - - # Extend to each head - p_choose = ( - p_choose.contiguous() - .unsqueeze(1) - .expand(-1, self.num_heads, -1, -1) - .contiguous() - .view(-1, tgt_len, src_len) - ) - - return p_choose - def p_choose( self, query: Optional[Tensor], @@ -149,28 +107,6 @@ def p_choose( tgt_len = query.size(0) batch_size = query.size(1) - if self.pre_decision_ratio == 1: - if self.strategy == "waitk": - return p_choose_strategy.waitk( - query, - key, - self.waitk_lagging, - self.num_heads, - key_padding_mask, - incremental_state=incremental_state, - ) - else: # hard_aligned or infinite_lookback - q_proj, k_proj, _ = self.input_projections(query, key, None, "monotonic") - attn_energy = self.attn_energy(q_proj, k_proj, key_padding_mask) - return p_choose_strategy.hard_aligned( - q_proj, - k_proj, - attn_energy, - self.noise_mean, - self.noise_var, - self.training - ) - key_pool = self.pooling_layer(key.transpose(0, 2)).transpose(0, 2) if key_padding_mask is not None: @@ -194,7 +130,7 @@ def p_choose( if key_padding_mask_pool is not None: key_padding_mask_pool = key_padding_mask_pool[:-1] - p_choose_pooled = self.p_choose_waitk( + p_choose_pooled = self.p_choose_from_qk( query, key_pool, key_padding_mask_pool, @@ -237,18 +173,18 @@ def p_choose( @register_monotonic_attention("waitk_fixed_pre_decision") -@fixed_pooling_monotonic_attention(MonotonicMultiheadAttentionWaitK) -class MonotonicMultiheadAttentionWaitkFixedStride: +@fixed_pooling_monotonic_attention(WaitKAttention) +class WaitKAttentionFixedStride: pass @register_monotonic_attention("hard_aligned_fixed_pre_decision") -@fixed_pooling_monotonic_attention(MonotonicMultiheadAttentionHardAligned) -class MonotonicMultiheadAttentionHardFixedStride: +@fixed_pooling_monotonic_attention(MonotonicAttention) +class MonotonicAttentionFixedStride: pass @register_monotonic_attention("infinite_lookback_fixed_pre_decision") -@fixed_pooling_monotonic_attention(MonotonicMultiheadAttentionInfiniteLookback) -class MonotonicMultiheadAttentionInfiniteLookbackFixedStride: +@fixed_pooling_monotonic_attention(MonotonicInfiniteLookbackAttention) +class MonotonicInfiniteLookbackAttentionFixedStride: pass diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index f49b1daa2f..2b8a48b1de 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -9,27 +9,44 @@ from torch import Tensor import torch.nn as nn -from examples.simultaneous_translation.utils.functions import ( - exclusive_cumprod, - lengths_to_mask, +from examples.simultaneous_translation.utils.p_choose_strategy import ( + learnable_p_choose, + waitk_p_choose +) + +from examples.simultaneous_translation.utils.monotonic_attention import ( + expected_alignment_from_p_choose, + expected_soft_attention, + mass_preservation, ) -from fairseq.incremental_decoding_utils import with_incremental_state from fairseq.modules import MultiheadAttention from . import register_monotonic_attention from typing import Dict, Optional -from examples.simultaneous_translation.utils import p_choose_strategy -@with_incremental_state -class MonotonicAttention(nn.Module): +@register_monotonic_attention("hard_aligned") +class MonotonicAttention(MultiheadAttention): """ Abstract class of monotonic attentions """ + k_in_proj: Dict[str, nn.Linear] + q_in_proj: Dict[str, nn.Linear] def __init__(self, args): - self.eps = args.attention_eps - self.mass_preservation = args.mass_preservation + super().__init__( + embed_dim=args.decoder_embed_dim, + num_heads=args.decoder_attention_heads, + kdim=getattr(args, "encoder_embed_dim", None), + vdim=getattr(args, "encoder_embed_dim", None), + dropout=args.attention_dropout, + encoder_decoder_attention=True, + ) + + self.soft_attention = False + + self.eps = getattr(args, "attention_eps", True) + self.mass_preservation = getattr(args, "mass_preservation", True) self.noise_type = args.noise_type self.noise_mean = args.noise_mean @@ -42,6 +59,10 @@ def __init__(self, args): else 0 ) + self.k_in_proj = {"monotonic": self.k_proj} + self.q_in_proj = {"monotonic": self.q_proj} + self.chunk_size = None + @staticmethod def add_args(parser): # fmt: off @@ -66,567 +87,316 @@ def add_args(parser): parser.add_argument('--attention-eps', type=float, default=1e-6, help='Epsilon when calculating expected attention') - def p_choose(self, *args): - raise NotImplementedError - - def input_projections(self, *args): - raise NotImplementedError - - def attn_energy( - self, q_proj, k_proj, key_padding_mask=None, attn_mask=None + def energy_from_qk( + self, + query: Tensor, + key: Tensor, + energy_type: str, + key_padding_mask: Optional[Tensor] = None, + bias: int = 0 ): """ - Calculating monotonic energies - - ============================================================ - Expected input size - q_proj: bsz * num_heads, tgt_len, self.head_dim - k_proj: bsz * num_heads, src_len, self.head_dim - key_padding_mask: bsz, src_len - attn_mask: tgt_len, src_len + Compute energy from query and key + q_func_value is a tuple looks like + (q_proj_func, q_tensor) + q_tensor size: bsz, tgt_len, emb_dim + k_tensor size: bsz, src_len, emb_dim + key_padding_mask size: bsz, src_len + attn_mask: bsz, src_len """ - bsz, tgt_len, embed_dim = q_proj.size() - bsz = bsz // self.num_heads - src_len = k_proj.size(1) - attn_energy = ( - torch.bmm(q_proj, k_proj.transpose(1, 2)) + self.energy_bias + length, bsz, _ = query.size() + q = self.q_in_proj[energy_type].forward(query) + q = ( + q.contiguous() + .view(length, bsz * self.num_heads, self.head_dim) + .transpose(0, 1) + ) + q = q * self.scaling + length, bsz, _ = key.size() + k = self.k_in_proj[energy_type].forward(key) + k = ( + k.contiguous() + .view(length, bsz * self.num_heads, self.head_dim) + .transpose(0, 1) ) - if attn_mask is not None: - attn_mask = attn_mask.unsqueeze(0) - attn_energy += attn_mask - - attn_energy = attn_energy.view(bsz, self.num_heads, tgt_len, src_len) + energy = torch.bmm(q, k.transpose(1, 2)) + bias if key_padding_mask is not None: - attn_energy = attn_energy.masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), - float("-inf"), + energy = energy.masked_fill( + key_padding_mask.unsqueeze(1).to(torch.bool), + - float("inf") ) - return attn_energy - - def expected_alignment_train(self, p_choose, key_padding_mask: Optional[Tensor]): - """ - Calculating expected alignment for MMA - Mask is not need because p_choose will be 0 if masked - - q_ij = (1 − p_{ij−1})q_{ij−1} + a+{i−1j} - a_ij = p_ij q_ij - - Parallel solution: - ai = p_i * cumprod(1 − pi) * cumsum(a_i / cumprod(1 − pi)) - - ============================================================ - Expected input size - p_choose: bsz * num_heads, tgt_len, src_len - """ - - # p_choose: bsz * num_heads, tgt_len, src_len - bsz_num_heads, tgt_len, src_len = p_choose.size() - - # cumprod_1mp : bsz * num_heads, tgt_len, src_len - cumprod_1mp = exclusive_cumprod(1 - p_choose, dim=2, eps=self.eps) - cumprod_1mp_clamp = torch.clamp(cumprod_1mp, self.eps, 1.0) - - init_attention = p_choose.new_zeros([bsz_num_heads, 1, src_len]) - init_attention[:, :, 0] = 1.0 + return energy - previous_attn = [init_attention] + def p_choose_from_qk(self, query, key, key_padding_mask): + monotonic_energy = self.energy_from_qk( + query, + key, + "monotonic", + key_padding_mask=key_padding_mask, + bias=self.energy_bias, + ) - for i in range(tgt_len): - # p_choose: bsz * num_heads, tgt_len, src_len - # cumprod_1mp_clamp : bsz * num_heads, tgt_len, src_len - # previous_attn[i]: bsz * num_heads, 1, src_len - # alpha_i: bsz * num_heads, src_len - alpha_i = ( - p_choose[:, i] - * cumprod_1mp[:, i] - * torch.cumsum(previous_attn[i][:, 0] / cumprod_1mp_clamp[:, i], dim=1) - ).clamp(0, 1.0) - previous_attn.append(alpha_i.unsqueeze(1)) + p_choose = learnable_p_choose( + monotonic_energy, + self.noise_mean, + self.noise_var, + self.training + ) + return p_choose - # alpha: bsz * num_heads, tgt_len, src_len - alpha = torch.cat(previous_attn[1:], dim=1) + def p_choose(self, query, key, key_padding_mask): + return self.p_choose_from_qk(self, query, key, key_padding_mask) - if self.mass_preservation: - # Last token has the residual probabilities - if key_padding_mask is not None and key_padding_mask[:, -1].any(): - # right padding - batch_size = key_padding_mask.size(0) - residuals = 1 - alpha.sum(dim=-1, keepdim=True).clamp(0.0, 1.0) - src_lens = src_len - key_padding_mask.sum(dim=1, keepdim=True) - src_lens = src_lens.expand( - batch_size, self.num_heads - ).contiguous().view(-1, 1) - src_lens = src_lens.expand(-1, tgt_len).contiguous() - # add back the last value - residuals += alpha.gather(2, src_lens.unsqueeze(-1) - 1) - alpha = alpha.scatter(2, src_lens.unsqueeze(-1) - 1, residuals) - else: - residuals = 1 - alpha[:, :, :-1].sum(dim=-1).clamp(0.0, 1.0) - alpha[:, :, -1] = residuals - - if torch.isnan(alpha).any(): - # Something is wrong - raise RuntimeError("NaN in alpha.") - - return alpha - - def expected_alignment_infer( - self, p_choose, encoder_padding_mask: Optional[Tensor], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] + def monotonic_attention_process_infer( + self, + query: Optional[Tensor], + key: Optional[Tensor], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], ): - # TODO modify this function """ - Calculating mo alignment for MMA during inference time - - ============================================================ - Expected input size - p_choose: bsz * num_heads, tgt_len, src_len - incremental_state: dict - encodencoder_padding_mask: bsz * src_len + Monotonic attention at inference time + Notice that this function is designed for simuleval not sequence_generator """ - # p_choose: bsz * self.num_heads, src_len - bsz_num_heads, tgt_len, src_len = p_choose.size() - # One token at a time - assert tgt_len == 1 - p_choose = p_choose[:, 0, :] + assert query is not None + assert key is not None - monotonic_cache = self._get_monotonic_buffer(incremental_state) + if query.size(1) != 1: + raise RuntimeError( + "Simultaneous translation models don't support batch decoding." + ) + # 1. compute stepwise probability + p_choose = self.p_choose( + query, key, None, incremental_state + ).squeeze(1) - # prev_monotonic_step: bsz, num_heads - bsz = bsz_num_heads // self.num_heads - prev_monotonic_step = monotonic_cache.get( - "head_step", - p_choose.new_zeros([bsz, self.num_heads]).long() + # 2. Compute the alpha + src_len = key.size(0) + # Maximum steps allows in this iteration + max_steps = src_len - 1 if self.mass_preservation else src_len + monotonic_cache = self._get_monotonic_buffer(incremental_state) + # Step for each head + monotonic_step = monotonic_cache.get( + 'head_step', + p_choose.new_zeros(1, self.num_heads).long() ) - assert prev_monotonic_step is not None - bsz, num_heads = prev_monotonic_step.size() - assert num_heads == self.num_heads - assert bsz * num_heads == bsz_num_heads - - # p_choose: bsz, num_heads, src_len - p_choose = p_choose.view(bsz, num_heads, src_len) + assert monotonic_step is not None + finish_read = monotonic_step.eq(max_steps) + p_choose_i = torch.tensor(1) - if encoder_padding_mask is not None: - src_lengths = src_len - \ - encoder_padding_mask.sum(dim=1, keepdim=True).long() - else: - src_lengths = prev_monotonic_step.new_ones(bsz, 1) * src_len - - # src_lengths: bsz, num_heads - src_lengths = src_lengths.expand_as(prev_monotonic_step) - # new_monotonic_step: bsz, num_heads - new_monotonic_step = prev_monotonic_step - - step_offset = 0 - if encoder_padding_mask is not None: - if encoder_padding_mask[:, 0].any(): - # left_pad_source = True: - step_offset = encoder_padding_mask.sum(dim=-1, keepdim=True) - - max_steps = src_lengths - 1 if self.mass_preservation else src_lengths - - # finish_read: bsz, num_heads - finish_read = new_monotonic_step.eq(max_steps) - p_choose_i = 1 - while finish_read.sum().item() < bsz * self.num_heads: - # p_choose: bsz * self.num_heads, src_len + while finish_read.sum().item() < self.num_heads: + # p_choose: self.num_heads, src_len # only choose the p at monotonic steps - # p_choose_i: bsz , self.num_heads + # p_choose_i: 1, self.num_heads p_choose_i = ( p_choose.gather( - 2, - (step_offset + new_monotonic_step) - .unsqueeze(2) + 1, + monotonic_step .clamp(0, src_len - 1), ) - ).squeeze(2) + ) - action = ( + read_one_step = ( (p_choose_i < 0.5) - .type_as(prev_monotonic_step) + .type_as(monotonic_step) .masked_fill(finish_read, 0) ) # 1 x bsz # sample actions on unfinished seq - # 1 means stay, finish reading - # 0 means leave, continue reading - # dist = torch.distributions.bernoulli.Bernoulli(p_choose) - # action = dist.sample().type_as(finish_read) * (1 - finish_read) + # 0 means stay, finish reading + # 1 means leave, continue reading + + monotonic_step += read_one_step - new_monotonic_step += action + finish_read = monotonic_step.eq(max_steps) | (read_one_step == 0) - finish_read = new_monotonic_step.eq(max_steps) | (action == 0) + # p_choose at last steps + p_choose_i = ( + p_choose.gather( + 1, + monotonic_step + .clamp(0, src_len - 1), + ) + ) - monotonic_cache["head_step"] = new_monotonic_step + monotonic_cache["head_step"] = monotonic_step # Whether a head is looking for new input monotonic_cache["head_read"] = ( - new_monotonic_step.eq(max_steps) & (p_choose_i < 0.5) + monotonic_step.eq(max_steps) & (p_choose_i < 0.5) ) + self._set_monotonic_buffer(incremental_state, monotonic_cache) - # alpha: bsz * num_heads, 1, src_len - # new_monotonic_step: bsz, num_heads + # 2. Update alpha alpha = ( p_choose - .new_zeros([bsz * self.num_heads, src_len]) + .new_zeros([self.num_heads, src_len]) .scatter( 1, - (step_offset + new_monotonic_step) - .view(bsz * self.num_heads, 1).clamp(0, src_len - 1), + (monotonic_step) + .view(self.num_heads, 1).clamp(0, src_len - 1), 1 ) ) if not self.mass_preservation: alpha = alpha.masked_fill( - (new_monotonic_step == max_steps) - .view(bsz * self.num_heads, 1), + (monotonic_step == max_steps) + .view(self.num_heads, 1), 0 ) - alpha = alpha.unsqueeze(1) - - self._set_monotonic_buffer(incremental_state, monotonic_cache) - - return alpha - - def _get_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): - return self.get_incremental_state( - incremental_state, - 'monotonic', - ) or {} - - def _set_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], buffer: Dict[str, Optional[Tensor]]): - self.set_incremental_state( - incremental_state, - 'monotonic', - buffer, - ) - - def v_proj_output(self, value): - raise NotImplementedError - - def forward( - self, query, key, value, - key_padding_mask=None, attn_mask=None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, - need_weights=True, static_kv=False - ): - - tgt_len, bsz, embed_dim = query.size() - src_len = value.size(0) - - # stepwise prob - # p_choose: bsz * self.num_heads, tgt_len, src_len - p_choose = self.p_choose( - query, key, key_padding_mask, incremental_state, - ) - - # expected alignment alpha - # bsz * self.num_heads, tgt_len, src_len - if incremental_state is not None: - alpha = self.expected_alignment_infer( - p_choose, key_padding_mask, incremental_state) + # 4. Compute Beta + if self.soft_attention: + monotonic_step = monotonic_step.t() + beta_mask = torch.arange(src_len).expand_as(alpha).gt(monotonic_step).unsqueeze(1) + # If it's soft attention just do softmax on current context + soft_energy = self.energy_from_qk( + query, + key, + "soft" + ) + beta = torch.nn.functional.softmax( + soft_energy.masked_fill(beta_mask, -float("inf")), dim=-1 + ) + # It could happen that a head doesn't move at all + beta = beta.masked_fill(monotonic_step.eq(0).unsqueeze(1), 0) else: - alpha = self.expected_alignment_train( - p_choose, key_padding_mask) - - # expected attention beta - # bsz * self.num_heads, tgt_len, src_len - beta = self.expected_attention( - alpha, query, key, value, - key_padding_mask, attn_mask, - incremental_state - ) + # If it's hard attention just select the last state + beta = alpha - attn_weights = beta + return p_choose, alpha, beta - v_proj = self.v_proj_output(value) - - attn = torch.bmm(attn_weights.type_as(v_proj), v_proj) - - attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) - - attn = self.out_proj(attn) - - beta = beta.view(bsz, self.num_heads, tgt_len, src_len) - alpha = alpha.view(bsz, self.num_heads, tgt_len, src_len) - p_choose = p_choose.view(bsz, self.num_heads, tgt_len, src_len) - - return attn, { - "alpha": alpha, - "beta": beta, - "p_choose": p_choose, - } - - -@register_monotonic_attention("hard_aligned") -class MonotonicMultiheadAttentionHardAligned( - MonotonicAttention, MultiheadAttention -): - def __init__(self, args): - MultiheadAttention.__init__( - self, - embed_dim=args.decoder_embed_dim, - num_heads=args.decoder_attention_heads, - kdim=getattr(args, "encoder_embed_dim", None), - vdim=getattr(args, "encoder_embed_dim", None), - dropout=args.attention_dropout, - encoder_decoder_attention=True, - ) - - MonotonicAttention.__init__(self, args) - - self.k_in_proj = {"monotonic": self.k_proj} - self.q_in_proj = {"monotonic": self.q_proj} - self.v_in_proj = {"output": self.v_proj} - - @staticmethod - def add_args(parser): - # fmt: off - parser.add_argument('--no-mass-preservation', action="store_false", - dest="mass_preservation", - help='Do not stay on the last token when decoding') - parser.add_argument('--mass-preservation', action="store_true", - dest="mass_preservation", - help='Stay on the last token when decoding') - parser.set_defaults(mass_preservation=True) - parser.add_argument('--noise-var', type=float, default=1.0, - help='Variance of discretness noise') - parser.add_argument('--noise-mean', type=float, default=0.0, - help='Mean of discretness noise') - parser.add_argument('--noise-type', type=str, default="flat", - help='Type of discretness noise') - parser.add_argument('--energy-bias', action="store_true", - default=False, - help='Bias for energy') - parser.add_argument('--energy-bias-init', type=float, default=-2.0, - help='Initial value of the bias for energy') - parser.add_argument('--attention-eps', type=float, default=1e-6, - help='Epsilon when calculating expected attention') - - def attn_energy( - self, q_proj: Optional[Tensor], k_proj: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, attn_mask: Optional[Tensor] = None + def monotonic_attention_process_train( + self, + query: Optional[Tensor], + key: Optional[Tensor], + key_padding_mask: Optional[Tensor] = None, ): """ - Calculating monotonic energies - - ============================================================ - Expected input size - q_proj: bsz * num_heads, tgt_len, self.head_dim - k_proj: bsz * num_heads, src_len, self.head_dim - key_padding_mask: bsz, src_len - attn_mask: tgt_len, src_len + Calculating monotonic attention process for training + Including: + stepwise probability: p_choose + expected hard alignment: alpha + expected soft attention: beta """ - assert q_proj is not None # Optional[Tensor] annotations in the signature above are to make the JIT compiler happy - assert k_proj is not None - bsz, tgt_len, embed_dim = q_proj.size() - bsz = bsz // self.num_heads - src_len = k_proj.size(1) - - attn_energy = ( - torch.bmm(q_proj, k_proj.transpose(1, 2)) + self.energy_bias - ) + assert query is not None + assert key is not None - if attn_mask is not None: - attn_mask = attn_mask.unsqueeze(0) - attn_energy += attn_mask + # 1. compute stepwise probability + p_choose = self.p_choose_from_qk(query, key, key_padding_mask) - attn_energy = attn_energy.view(bsz, self.num_heads, tgt_len, src_len) + # 2. compute expected_alignment + alpha = expected_alignment_from_p_choose( + p_choose, + key_padding_mask, + eps=self.eps, + ) - if key_padding_mask is not None: - attn_energy = attn_energy.masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), - float("-inf"), + if self.mass_preservation: + alpha = mass_preservation( + alpha, key_padding_mask ) - return attn_energy - - def expected_alignment_train(self, p_choose, key_padding_mask: Optional[Tensor]): - """ - Calculating expected alignment for MMA - Mask is not need because p_choose will be 0 if masked - - q_ij = (1 − p_{ij−1})q_{ij−1} + a+{i−1j} - a_ij = p_ij q_ij - - Parallel solution: - ai = p_i * cumprod(1 − pi) * cumsum(a_i / cumprod(1 − pi)) - - ============================================================ - Expected input size - p_choose: bsz * num_heads, tgt_len, src_len - """ - - # p_choose: bsz * num_heads, tgt_len, src_len - bsz_num_heads, tgt_len, src_len = p_choose.size() - - # cumprod_1mp : bsz * num_heads, tgt_len, src_len - cumprod_1mp = exclusive_cumprod(1 - p_choose, dim=2, eps=self.eps) - cumprod_1mp_clamp = torch.clamp(cumprod_1mp, self.eps, 1.0) - - init_attention = p_choose.new_zeros([bsz_num_heads, 1, src_len]) - init_attention[:, :, 0] = 1.0 - - previous_attn = [init_attention] + # 3. compute expected soft attention (soft aligned model only) + if self.soft_attention: + soft_energy = self.energy_from_qk( + query, + key, + "soft", + key_padding_mask=None, + ) - for i in range(tgt_len): - # p_choose: bsz * num_heads, tgt_len, src_len - # cumprod_1mp_clamp : bsz * num_heads, tgt_len, src_len - # previous_attn[i]: bsz * num_heads, 1, src_len - # alpha_i: bsz * num_heads, src_len - alpha_i = ( - p_choose[:, i] - * cumprod_1mp[:, i] - * torch.cumsum(previous_attn[i][:, 0] / cumprod_1mp_clamp[:, i], dim=1) - ).clamp(0, 1.0) - previous_attn.append(alpha_i.unsqueeze(1)) + beta = expected_soft_attention( + alpha, + soft_energy, + padding_mask=key_padding_mask, + chunk_size=self.chunk_size, + eps=self.eps, + ) + else: + beta = alpha + soft_energy = alpha - # alpha: bsz * num_heads, tgt_len, src_len - alpha = torch.cat(previous_attn[1:], dim=1) + return p_choose, alpha, beta, soft_energy - if self.mass_preservation: - # Last token has the residual probabilities - if key_padding_mask is not None and key_padding_mask[:, -1].any(): - # right padding - batch_size = key_padding_mask.size(0) - residuals = 1 - alpha.sum(dim=-1, keepdim=True).clamp(0.0, 1.0) - src_lens = src_len - key_padding_mask.sum(dim=1, keepdim=True) - src_lens = src_lens.expand( - batch_size, self.num_heads - ).contiguous().view(-1, 1) - src_lens = src_lens.expand(-1, tgt_len).contiguous() - # add back the last value - residuals += alpha.gather(2, src_lens.unsqueeze(-1) - 1) - alpha = alpha.scatter(2, src_lens.unsqueeze(-1) - 1, residuals) - else: - residuals = 1 - alpha[:, :, :-1].sum(dim=-1).clamp(0.0, 1.0) - alpha[:, :, -1] = residuals - - if torch.isnan(alpha).any(): - # Something is wrong - raise RuntimeError("NaN in alpha.") - - return alpha - - def expected_alignment_infer( - self, p_choose, encoder_padding_mask: Optional[Tensor], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] + def forward( + self, + query: Optional[Tensor], + key: Optional[Tensor], + value: Optional[Tensor], + key_padding_mask: Optional[Tensor] = None, + attn_mask: Optional[Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + need_weights: bool = True, static_kv: bool = False, need_head_weights: bool = False, ): - # TODO modify this function """ - Calculating mo alignment for MMA during inference time - - ============================================================ - Expected input size - p_choose: bsz * num_heads, tgt_len, src_len - incremental_state: dict - encodencoder_padding_mask: bsz * src_len + query: tgt_len, bsz, embed_dim + key: src_len, bsz, embed_dim + value: src_len, bsz, embed_dim """ - # p_choose: bsz * self.num_heads, src_len - bsz_num_heads, tgt_len, src_len = p_choose.size() - # One token at a time - assert tgt_len == 1 - p_choose = p_choose[:, 0, :] - monotonic_cache = self._get_monotonic_buffer(incremental_state) + assert attn_mask is None + assert query is not None + assert key is not None + assert value is not None - # prev_monotonic_step: bsz, num_heads - bsz = bsz_num_heads // self.num_heads - prev_monotonic_step = monotonic_cache.get( - "head_step", - p_choose.new_zeros([bsz, self.num_heads]).long() - ) - assert prev_monotonic_step is not None - bsz, num_heads = prev_monotonic_step.size() - assert num_heads == self.num_heads - assert bsz * num_heads == bsz_num_heads + tgt_len, bsz, embed_dim = query.size() + src_len = value.size(0) - # p_choose: bsz, num_heads, src_len - p_choose = p_choose.view(bsz, num_heads, src_len) + if key_padding_mask is not None: + assert not key_padding_mask[:, 0].any(), ( + "Only right padding is supported." + ) + key_padding_mask = ( + key_padding_mask + .unsqueeze(1) + .expand([bsz, self.num_heads, src_len]) + .contiguous() + .view(-1, src_len) + ) - if encoder_padding_mask is not None: - src_lengths = src_len - \ - encoder_padding_mask.sum(dim=1, keepdim=True).long() + if incremental_state is not None: + # Inference + ( + p_choose, alpha, beta + ) = self.monotonic_attention_process_infer( + query, key, incremental_state + ) + soft_energy = beta else: - src_lengths = torch.ones(bsz, 1).to(prev_monotonic_step) * src_len - - # src_lengths: bsz, num_heads - src_lengths = src_lengths.expand_as(prev_monotonic_step) - # new_monotonic_step: bsz, num_heads - new_monotonic_step = prev_monotonic_step - - step_offset = torch.tensor(0) - if encoder_padding_mask is not None: - if encoder_padding_mask[:, 0].any(): - # left_pad_source = True: - step_offset = encoder_padding_mask.sum(dim=-1, keepdim=True) - - max_steps = src_lengths - 1 if self.mass_preservation else src_lengths - - # finish_read: bsz, num_heads - finish_read = new_monotonic_step.eq(max_steps) - p_choose_i = torch.tensor(1) - while finish_read.sum().item() < bsz * self.num_heads: - # p_choose: bsz * self.num_heads, src_len - # only choose the p at monotonic steps - # p_choose_i: bsz , self.num_heads - p_choose_i = ( - p_choose.gather( - 2, - (step_offset + new_monotonic_step) - .unsqueeze(2) - .clamp(0, src_len - 1), - ) - ).squeeze(2) - - action = ( - (p_choose_i < 0.5) - .type_as(prev_monotonic_step) - .masked_fill(finish_read, 0) + # Train + ( + p_choose, alpha, beta, soft_energy + ) = self.monotonic_attention_process_train( + query, key, key_padding_mask ) - # 1 x bsz - # sample actions on unfinished seq - # 1 means stay, finish reading - # 0 means leave, continue reading - # dist = torch.distributions.bernoulli.Bernoulli(p_choose) - # action = dist.sample().type_as(finish_read) * (1 - finish_read) - - new_monotonic_step += action - - finish_read = new_monotonic_step.eq(max_steps) | (action == 0) - monotonic_cache["head_step"] = new_monotonic_step - # Whether a head is looking for new input - monotonic_cache["head_read"] = ( - new_monotonic_step.eq(max_steps) & (p_choose_i < 0.5) + v = self.v_proj(value) + length, bsz, _ = v.size() + v = ( + v.contiguous() + .view(length, bsz * self.num_heads, self.head_dim) + .transpose(0, 1) ) - # alpha: bsz * num_heads, 1, src_len - # new_monotonic_step: bsz, num_heads - alpha = ( - p_choose - .new_zeros([bsz * self.num_heads, src_len]) - .scatter( - 1, - (step_offset + new_monotonic_step) - .view(bsz * self.num_heads, 1).clamp(0, src_len - 1), - 1 - ) - ) + attn = torch.bmm(beta.type_as(v), v) - if not self.mass_preservation: - alpha = alpha.masked_fill( - (new_monotonic_step == max_steps) - .view(bsz * self.num_heads, 1), - 0 - ) + attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) - alpha = alpha.unsqueeze(1) + attn = self.out_proj(attn) - self._set_monotonic_buffer(incremental_state, monotonic_cache) + p_choose = p_choose.view(bsz, self.num_heads, tgt_len, src_len) + alpha = alpha.view(bsz, self.num_heads, tgt_len, src_len) + beta = beta.view(bsz, self.num_heads, tgt_len, src_len) - return alpha + return attn, { + "p_choose": p_choose, + "alpha": alpha, + "beta": beta, + } def _get_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): maybe_incremental_state = self.get_incremental_state( @@ -646,147 +416,14 @@ def _set_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, buffer, ) - def forward( - self, query: Optional[Tensor], key: Optional[Tensor], value: Optional[Tensor], - key_padding_mask: Optional[Tensor] = None, attn_mask: Optional[Tensor] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, - need_weights: bool = True, static_kv: bool = False, need_head_weights: bool = False, - ): - assert query is not None - assert value is not None - tgt_len, bsz, embed_dim = query.size() - src_len = value.size(0) - - # stepwise prob - # p_choose: bsz * self.num_heads, tgt_len, src_len - p_choose = self.p_choose( - query, key, key_padding_mask, incremental_state, - ) - - # expected alignment alpha - # bsz * self.num_heads, tgt_len, src_len - if incremental_state is not None: - alpha = self.expected_alignment_infer( - p_choose, key_padding_mask, incremental_state) - else: - alpha = self.expected_alignment_train( - p_choose, key_padding_mask) - - # expected attention beta - # bsz * self.num_heads, tgt_len, src_len - beta = self.expected_attention( - alpha, query, key, value, - key_padding_mask, attn_mask, - incremental_state - ) - - attn_weights = beta - - v_proj = self.v_proj_output(value) - assert v_proj is not None - - attn = torch.bmm(attn_weights.type_as(v_proj), v_proj) - - attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) - - attn = self.out_proj(attn) - - beta = beta.view(bsz, self.num_heads, tgt_len, src_len) - alpha = alpha.view(bsz, self.num_heads, tgt_len, src_len) - p_choose = p_choose.view(bsz, self.num_heads, tgt_len, src_len) - - return attn, { - "alpha": alpha, - "beta": beta, - "p_choose": p_choose, - } - - def input_projections(self, query: Optional[Tensor], key: Optional[Tensor], value: Optional[Tensor], name: str): - """ - Prepare inputs for multihead attention - - ============================================================ - Expected input size - query: tgt_len, bsz, embed_dim - key: src_len, bsz, embed_dim - value: src_len, bsz, embed_dim - name: monotonic or soft - """ - - if query is not None: - bsz = query.size(1) - q = self.q_proj(query) - q *= self.scaling - q = q.contiguous().view( - -1, bsz * self.num_heads, self.head_dim - ).transpose(0, 1) - else: - q = None - - if key is not None: - bsz = key.size(1) - k = self.k_proj(key) - k = k.contiguous().view( - -1, bsz * self.num_heads, self.head_dim - ).transpose(0, 1) - else: - k = None - - if value is not None: - bsz = value.size(1) - v = self.v_proj(value) - v = v.contiguous().view( - -1, bsz * self.num_heads, self.head_dim - ).transpose(0, 1) - else: - v = None - - return q, k, v - - def p_choose( - self, query: Optional[Tensor], key: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, - incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None - ): - """ - Calculating step wise prob for reading and writing - 1 to read, 0 to write - - ============================================================ - Expected input size - query: bsz, tgt_len, embed_dim - key: bsz, src_len, embed_dim - value: bsz, src_len, embed_dim - key_padding_mask: bsz, src_len - attn_mask: bsz, src_len - query: bsz, tgt_len, embed_dim - """ - - # prepare inputs - q_proj, k_proj, _ = self.input_projections( - query, key, None, "monotonic" - ) - - # attention energy - attn_energy = self.attn_energy(q_proj, k_proj, key_padding_mask) - - return p_choose_strategy.hard_aligned(q_proj, k_proj, attn_energy, self.noise_mean, self.noise_var, self.training) - - def expected_attention(self, alpha, *args): - """ - For MMA-H, beta = alpha - """ - return alpha - - def v_proj_output(self, value): - _, _, v_proj = self.input_projections(None, None, value, "output") - return v_proj - @register_monotonic_attention("infinite_lookback") -class MonotonicMultiheadAttentionInfiniteLookback( - MonotonicMultiheadAttentionHardAligned +class MonotonicInfiniteLookbackAttention( + MonotonicAttention ): def __init__(self, args): super().__init__(args) + self.soft_attention = True self.init_soft_attention() def init_soft_attention(self): @@ -808,80 +445,21 @@ def init_soft_attention(self): nn.init.xavier_uniform_(self.k_in_proj["soft"].weight) nn.init.xavier_uniform_(self.q_in_proj["soft"].weight) - def expected_attention( - self, alpha, query: Optional[Tensor], key: Optional[Tensor], value: Optional[Tensor], - key_padding_mask: Optional[Tensor], attn_mask: Optional[Tensor], incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] - ): - # monotonic attention, we will calculate milk here - bsz_x_num_heads, tgt_len, src_len = alpha.size() - bsz = int(bsz_x_num_heads / self.num_heads) - - q, k, _ = self.input_projections(query, key, None, "soft") - soft_energy = self.attn_energy(q, k, key_padding_mask, attn_mask) - - assert list(soft_energy.size()) == \ - [bsz, self.num_heads, tgt_len, src_len] - - soft_energy = soft_energy.view(bsz * self.num_heads, tgt_len, src_len) - - if incremental_state is not None: - monotonic_cache = self._get_monotonic_buffer(incremental_state) - head_step = monotonic_cache["head_step"] - assert head_step is not None - monotonic_length = head_step + 1 - step_offset = 0 - if key_padding_mask is not None: - if key_padding_mask[:, 0].any(): - # left_pad_source = True: - step_offset = key_padding_mask.sum(dim=-1, keepdim=True) - monotonic_length += step_offset - mask = lengths_to_mask( - monotonic_length.view(-1), - soft_energy.size(2), 1 - ).unsqueeze(1) - - soft_energy = soft_energy.masked_fill(~mask.to(torch.bool), float("-inf")) - soft_energy = soft_energy - soft_energy.max(dim=2, keepdim=True)[0] - exp_soft_energy = torch.exp(soft_energy) - exp_soft_energy_sum = exp_soft_energy.sum(dim=2) - beta = exp_soft_energy / exp_soft_energy_sum.unsqueeze(2) - - else: - soft_energy = soft_energy - soft_energy.max(dim=2, keepdim=True)[0] - exp_soft_energy = torch.exp(soft_energy) + self.eps - inner_items = alpha / (torch.cumsum(exp_soft_energy, dim=2)) - - beta = ( - exp_soft_energy - * torch.cumsum(inner_items.flip(dims=[2]), dim=2) - .flip(dims=[2]) - ) - - beta = beta.view(bsz, self.num_heads, tgt_len, src_len) - - if key_padding_mask is not None: - beta = beta.masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), 0) - - beta = beta / beta.sum(dim=3, keepdim=True) - beta = beta.view(bsz * self.num_heads, tgt_len, src_len) - beta = self.dropout_module(beta) - - if torch.isnan(beta).any(): - # Something is wrong - raise RuntimeError("NaN in beta.") - - return beta - @register_monotonic_attention("waitk") -class MonotonicMultiheadAttentionWaitK( - MonotonicMultiheadAttentionInfiniteLookback +class WaitKAttention( + MonotonicInfiniteLookbackAttention ): + """ + STACL: Simultaneous Translation with Implicit Anticipation and + Controllable Latency using Prefix-to-Prefix Framework + https://www.aclweb.org/anthology/P19-1289/ + """ def __init__(self, args): super().__init__(args) self.q_in_proj["soft"] = self.q_in_proj["monotonic"] self.k_in_proj["soft"] = self.k_in_proj["monotonic"] + self.waitk_lagging = args.waitk_lagging assert self.waitk_lagging > 0, ( f"Lagging has to been larger than 0, get {self.waitk_lagging}." @@ -890,21 +468,52 @@ def __init__(self, args): @staticmethod def add_args(parser): super( - MonotonicMultiheadAttentionWaitK, - MonotonicMultiheadAttentionWaitK, + MonotonicInfiniteLookbackAttention, + MonotonicInfiniteLookbackAttention ).add_args(parser) parser.add_argument( "--waitk-lagging", type=int, required=True, help="Wait K lagging" ) - def p_choose( - self, query: Optional[Tensor], key: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, + def p_choose_from_qk( + self, + query: Optional[Tensor], + key: Optional[Tensor], + key_padding_mask: Optional[Tensor] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, ): - """ - query: bsz, tgt_len - key: bsz, src_len - key_padding_mask: bsz, src_len - """ - return p_choose_strategy.waitk(query, key, self.waitk_lagging, self.num_heads, key_padding_mask, incremental_state) + assert query is not None + assert key is not None + + p_choose = waitk_p_choose( + tgt_len=query.size(0), + src_len=key.size(0), + bsz=query.size(1) * self.num_heads, + waitk_lagging=self.waitk_lagging, + key_padding_mask=key_padding_mask, + incremental_state=incremental_state, + ) + + return p_choose.to(query) + + +@register_monotonic_attention("chunkwise") +class ChunkwiseAttention( + MonotonicInfiniteLookbackAttention +): + def __init__(self, args): + super().__init__(args) + self.chunk_size = args.mocha_chunk_size + assert self.chunk_size > 1 + + @staticmethod + def add_args(parser): + super( + MonotonicInfiniteLookbackAttention + ).add_args(parser) + + parser.add_argument( + "--mocha-chunk-size", type=int, + required=True, help="Mocha chunk size" + ) diff --git a/examples/simultaneous_translation/modules/monotonic_transformer_layer.py b/examples/simultaneous_translation/modules/monotonic_transformer_layer.py index bcd45aa8a6..94bd71fb9c 100644 --- a/examples/simultaneous_translation/modules/monotonic_transformer_layer.py +++ b/examples/simultaneous_translation/modules/monotonic_transformer_layer.py @@ -3,14 +3,14 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from fairseq.modules import LayerNorm, TransformerDecoderLayer, TransformerEncoderLayer +from fairseq.modules import TransformerDecoderLayer, TransformerEncoderLayer from . import build_monotonic_attention -from typing import Dict, List, Optional +from typing import Dict, Optional, List -import torch from torch import Tensor +import torch class TransformerMonotonicEncoderLayer(TransformerEncoderLayer): @@ -22,29 +22,16 @@ def forward(self, x, encoder_padding_mask): class TransformerMonotonicDecoderLayer(TransformerDecoderLayer): - def __init__( - self, args, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False - ): - super().__init__( - args, - no_encoder_attn=True, - add_bias_kv=add_bias_kv, - add_zero_attn=add_zero_attn, - ) + def __init__(self, args): + super().__init__(args) assert args.simul_type is not None, "A --simul-type is needed." - self.encoder_attn = build_monotonic_attention(args) - self.encoder_attn_layer_norm = LayerNorm( - self.embed_dim, export=getattr(args, "char_inputs", False) - ) - def get_head_steps(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): - return self.encoder_attn._get_monotonic_buffer(incremental_state).get( - "head_step" - ) - - def prune_incremental_state(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): + def prune_incremental_state( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] + ): input_buffer = self.self_attn._get_input_buffer(incremental_state) for key in ["prev_key", "prev_value"]: input_buffer_key = input_buffer[key] @@ -58,19 +45,16 @@ def prune_incremental_state(self, incremental_state: Optional[Dict[str, Dict[str assert incremental_state is not None self.self_attn._set_input_buffer(incremental_state, input_buffer) - def get_steps(self, incremental_state): - return self.encoder_attn._get_monotonic_buffer(incremental_state).get("step", 0) - def forward( self, x, - encoder_out: Optional[torch.Tensor] = None, - encoder_padding_mask: Optional[torch.Tensor] = None, + encoder_out: Optional[Tensor] = None, + encoder_padding_mask: Optional[Tensor] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, - prev_self_attn_state: Optional[List[torch.Tensor]] = None, - prev_attn_state: Optional[List[torch.Tensor]] = None, - self_attn_mask: Optional[torch.Tensor] = None, - self_attn_padding_mask: Optional[torch.Tensor] = None, + prev_self_attn_state: Optional[List[Tensor]] = None, + prev_attn_state: Optional[List[Tensor]] = None, + self_attn_mask: Optional[Tensor] = None, + self_attn_padding_mask: Optional[Tensor] = None, need_attn: bool = False, need_head_weights: bool = False, ): diff --git a/examples/simultaneous_translation/tests/test_text_models.py b/examples/simultaneous_translation/tests/test_text_models.py new file mode 100644 index 0000000000..127adfa633 --- /dev/null +++ b/examples/simultaneous_translation/tests/test_text_models.py @@ -0,0 +1,407 @@ +import argparse +import unittest +from typing import Any, Dict + +import torch +from examples.simultaneous_translation.models import ( + transformer_monotonic_attention +) + + +from tests.test_roberta import FakeTask + + +DEFAULT_CONFIG = { + "attention_eps": 1e-6, + "mass_preservation": True, + "noise_type": "flat", + "noise_mean": 0.0, + "noise_var": 1.0, + "energy_bias_init": -2, + "energy_bias": True +} + + +PAD_INDEX = 1 + + +def generate_config(overrides_kv): + new_dict = {key: value for key, value in DEFAULT_CONFIG.items()} + for key, value in overrides_kv.items(): + new_dict[key] = value + return new_dict + + +def make_sample_with_padding(longer_src=False) -> Dict[str, Any]: + tokens_1 = torch.LongTensor( + [ + [2, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15, 2], + [ + 2, 11, 12, 14, 15, 10, 11, 12, 13, 14, 15, 2, + PAD_INDEX, PAD_INDEX + ], + ] + ) + tokens_2 = torch.LongTensor( + [ + [2, 11, 12, 13, 14, 2, PAD_INDEX, PAD_INDEX], + [2, 11, 22, 33, 2, PAD_INDEX, PAD_INDEX, PAD_INDEX] + ] + ) + if longer_src: + src_tokens = tokens_1[:, 1:] + prev_output_tokens = tokens_2 + else: + src_tokens = tokens_2[:, 1:8] + prev_output_tokens = tokens_1 + + src_lengths = src_tokens.ne(PAD_INDEX).sum(dim=1).long() + + sample = { + "net_input": { + "src_tokens": src_tokens, + "prev_output_tokens": prev_output_tokens, + "src_lengths": src_lengths, + }, + "target": prev_output_tokens[:, 1:], + } + return sample + + +def build_transformer_monotonic_attention(**extra_args: Any): + overrides = { + # Use characteristics dimensions + "encoder_embed_dim": 12, + "encoder_ffn_embed_dim": 14, + "decoder_embed_dim": 12, + "decoder_ffn_embed_dim": 14, + # Disable dropout so we have comparable tests. + "dropout": 0, + "attention_dropout": 0, + "activation_dropout": 0, + "encoder_layerdrop": 0, + } + overrides.update(extra_args) + # Overrides the defaults from the parser + args = argparse.Namespace(**overrides) + transformer_monotonic_attention.monotonic_tiny_architecture(args) + + torch.manual_seed(0) + task = FakeTask(args) + return ( + transformer_monotonic_attention + .TransformerModelSimulTrans + .build_model(args, task) + ) + + +def expected_alignment_formula( + p_choose, + mass_perservation=True, + padding_mask=None +): + # Online and Linear-Time Attention by Enforcing Monotonic Alignments + # https://arxiv.org/pdf/1704.00784.pdf + # Eq 18, 19 + bsz, tgt_len, src_len = p_choose.size() + alpha = torch.zeros_like(p_choose) + + if padding_mask is not None: + bsz_pad = padding_mask.size(0) + num_heads = int(bsz / bsz_pad) + padding_mask = ( + padding_mask + .unsqueeze(1) + .expand([bsz_pad, num_heads, src_len]) + .contiguous() + .view(-1, src_len) + ) + + p_choose = p_choose.masked_fill(padding_mask.unsqueeze(1), 0) + + for bsz_i in range(bsz): + for i in range(tgt_len): + for j in range(src_len): + if i == 0: + if j == 0: + # First source token + alpha[bsz_i, i, j] = p_choose[bsz_i, i, j] + else: + # First target token + alpha[bsz_i, i, j] = ( + p_choose[bsz_i, i, j] + * torch.prod( + 1 - p_choose[bsz_i, i, :j] + ) + ) + else: + alpha[bsz_i, i, j] = alpha[bsz_i, i - 1, j] + for k in range(j): + alpha[bsz_i, i, j] += ( + alpha[bsz_i, i - 1, k] + * torch.prod( + 1 - p_choose[bsz_i, i, k:j] + ) + ) + alpha[bsz_i, i, j] *= p_choose[bsz_i, i, j] + + alpha = alpha.masked_fill(padding_mask.unsqueeze(1), 0) + + if mass_perservation: + alpha = mass_perservation_formula(alpha, False, padding_mask) + + return alpha + + +def mass_perservation_formula(alpha, left_padding=False, padding_mask=None): + if padding_mask is None or alpha.size(-1) == 1: + if alpha.size(-1) > 1: + alpha[:, :, -1] = 1 - alpha[:, :, :-1].sum(dim=-1) + return alpha + + src_lens = (padding_mask.logical_not()).sum(dim=1).long() + + bsz, tgt_len, src_len = alpha.size() + + assert ( + not left_padding + or (left_padding and (not padding_mask[:, 0].any())) + ) + + alpha = alpha.masked_fill(padding_mask.unsqueeze(1), 0) + + for bsz_i in range(bsz): + if left_padding: + alpha[bsz_i, :, -1] = ( + 1 - alpha[bsz_i, :, :-1].sum(dim=-1) + ) + else: + alpha[bsz_i, :, src_lens[bsz_i] - 1] = ( + 1 - alpha[bsz_i, :, :src_lens[bsz_i] - 1].sum(dim=-1) + ) + + return alpha + + +def expected_soft_attention_formula( + alpha, + soft_energy, + padding_mask=None, + chunksize=1e10, +): + # Monotonic Infinite Lookback Attention for Simultaneous Machine Translation + # https://arxiv.org/pdf/1906.05218.pdf + # Eq 14 + + # Monotonic Chunkwise Attention + # https://arxiv.org/abs/1712.05382 + # Eq 17 + bsz, tgt_len, src_len = alpha.size() + beta = torch.zeros_like(alpha) + + if padding_mask is not None: + bsz_pad = padding_mask.size(0) + num_heads = int(bsz / bsz_pad) + # Expanding for potential head dimension + padding_mask = ( + padding_mask + .unsqueeze(1) + .expand([bsz_pad, num_heads, src_len]) + .contiguous() + .view(-1, src_len) + ) + soft_energy = soft_energy.masked_fill(padding_mask.unsqueeze(1), float('-inf')) + + for bsz_i in range(bsz): + for i in range(tgt_len): + for j in range(src_len): + for k in range(j, min([src_len, j + chunksize])): + if not padding_mask[bsz_i, j]: + beta[bsz_i, i, j] += ( + alpha[bsz_i, i, k] * torch.exp(soft_energy[bsz_i, i, j]) + / torch.sum(torch.exp(soft_energy[bsz_i, i, max([0, k - chunksize + 1]):k + 1])) + ) + return beta + + +class MonotonicAttentionTestAbstractClass(object): + def test_forward(self): + sample = make_sample_with_padding() + out, _ = self.model.forward(**sample["net_input"]) + loss = out.sum() + loss.backward() + + def test_p_choose(self): + sample = make_sample_with_padding() + _, extra_out = self.model.forward(**sample["net_input"]) + for item in extra_out.attn_list: + p_choose = item["p_choose"] + self.assertTrue(p_choose.le(1.0).all()) + self.assertTrue(p_choose.ge(0.0).all()) + + def test_expected_alignment(self): + for longer_src in [True, False]: + sample = make_sample_with_padding(longer_src) + _, extra_out = self.model.forward(**sample["net_input"]) + for item in extra_out.attn_list: + p_choose = item["p_choose"] + alpha_system = item["alpha"] + self.assertTrue(p_choose.size() == alpha_system.size()) + bsz, num_head, tgt_len, src_len = alpha_system.size() + alpha_system = alpha_system.view(-1, tgt_len, src_len) + p_choose = p_choose.view(-1, tgt_len, src_len) + + alpha_real = expected_alignment_formula( + p_choose, + self.model.decoder.layers[0].encoder_attn.mass_preservation, + sample["net_input"]["src_tokens"].eq(PAD_INDEX) + ) + + self.assertTrue( + torch.abs(alpha_system - alpha_real).le(5e-5).all(), + ) + + +class HardMonotonicAttentionTestCase( + unittest.TestCase, + MonotonicAttentionTestAbstractClass +): + def setUp(self): + self.model = build_transformer_monotonic_attention( + **generate_config({"simul_type": "hard_aligned"}) + ) + + +class InfiniteLookbackTestCase( + unittest.TestCase, + MonotonicAttentionTestAbstractClass +): + def setUp(self): + self.model = build_transformer_monotonic_attention( + **generate_config( + { + "simul_type": "infinite_lookback" + } + ) + ) + self.model.train() + + def test_fp16_for_long_input(self): + sample = { + "net_input": { + "src_tokens": torch.LongTensor([7] * 1000 + [2]).cuda().unsqueeze(0), + "prev_output_tokens": torch.LongTensor([7] * 1000 + [2]).cuda().unsqueeze(0), + "src_lengths": torch.LongTensor([1000]).cuda(), + }, + "target": torch.LongTensor([2] + [7] * 1000).unsqueeze(0).cuda() + } + self.model.cuda().half() + _, extra_out = self.model.forward(**sample["net_input"]) + for item in extra_out.attn_list: + for key in ["p_choose", "alpha", "beta", "soft_energy"]: + self.assertFalse(torch.isnan(item[key]).any()) + + def test_expected_attention(self): + for longer_src in [True, False]: + sample = make_sample_with_padding(longer_src) + _, extra_out = self.model.forward(**sample["net_input"]) + for item in extra_out.attn_list: + p_choose = item["p_choose"] + alpha_system = item["alpha"] + beta_system = item["beta"] + soft_energy_system = item["soft_energy"] + self.assertTrue(beta_system.size() == alpha_system.size()) + self.assertTrue(p_choose.size() == alpha_system.size()) + + bsz, num_head, tgt_len, src_len = alpha_system.size() + + alpha_system = alpha_system.view(-1, tgt_len, src_len) + beta_system = beta_system.view(-1, tgt_len, src_len) + p_choose = p_choose.view(-1, tgt_len, src_len) + soft_energy_system = soft_energy_system.view(-1, tgt_len, src_len) + + alpha_real = expected_alignment_formula( + p_choose, + self.model.decoder.layers[0].encoder_attn.mass_preservation, + sample["net_input"]["src_tokens"].eq(PAD_INDEX) + ) + + beta_real = expected_soft_attention_formula( + alpha_real, + soft_energy_system, + sample["net_input"]["src_tokens"].eq(PAD_INDEX), + chunksize=getattr( + self.model.decoder.layers[0].encoder_attn, + "chunk_size", + int(1e10) + ) + ) + + self.assertTrue( + torch.abs(beta_system - beta_real).le(1e-5).all(), + ) + + +class ChunkwiswTestCase( + InfiniteLookbackTestCase +): + def setUp(self): + self.model = build_transformer_monotonic_attention( + **generate_config( + { + "simul_type": "chunkwise", + "mocha_chunk_size": 3 + } + ) + ) + + +class WaitkTestCase(InfiniteLookbackTestCase): + def setUp(self): + self.model = build_transformer_monotonic_attention( + **generate_config( + { + "simul_type": "waitk", + "waitk_lagging": 3, + } + ) + ) + + def check_waitk(self, p_choose, lagging, padding_mask): + bsz, tgt_len, src_len = p_choose.size() + for bsz_i in range(bsz): + for i in range(tgt_len): + for j in range(src_len): + if not padding_mask[bsz_i, j]: + if j - i == lagging - 1: + self.assertTrue(p_choose[bsz_i, i, j] == 1) + else: + self.assertTrue(p_choose[bsz_i, i, j] == 0) + + def test_waitk_p_choose(self): + for longer_src in [True, False]: + for k in [1, 3, 10, 20, 100]: + sample = make_sample_with_padding(longer_src) + model = build_transformer_monotonic_attention( + **generate_config( + { + "simul_type": "waitk", + "waitk_lagging": k, + } + ) + ) + model.train() + _, extra_out = model.forward(**sample["net_input"]) + for item in extra_out.attn_list: + p_choose = item["p_choose"] + bsz, num_heads, tgt_len, src_len = p_choose.size() + padding_mask = sample["net_input"]["src_tokens"].eq(PAD_INDEX) + padding_mask = ( + padding_mask + .unsqueeze(1) + .expand([bsz, num_heads, src_len]) + .contiguous() + .view(-1, src_len) + ) + p_choose = p_choose.view(bsz * num_heads, tgt_len, src_len) + self.check_waitk(p_choose, k, padding_mask) diff --git a/examples/simultaneous_translation/utils/functions.py b/examples/simultaneous_translation/utils/functions.py index f795b5f31c..0ced35a9d5 100644 --- a/examples/simultaneous_translation/utils/functions.py +++ b/examples/simultaneous_translation/utils/functions.py @@ -6,12 +6,23 @@ import torch +def prob_check(tensor): + assert not torch.isnan(tensor).any(), ( + "Nan in a probability tensor." + ) + assert tensor.le(1.0).all() and tensor.ge(0.0).all(), ( + "Incorrect values in a probability tensor" + ", 0.0 <= tensor <= 1.0" + ) + + def exclusive_cumprod(tensor, dim: int, eps: float = 1e-10): """ Implementing exclusive cumprod. There is cumprod in pytorch, however there is no exclusive mode. cumprod(x) = [x1, x1x2, x2x3x4, ..., prod_{i=1}^n x_i] - exclusive means cumprod(x) = [1, x1, x1x2, x1x2x3, ..., prod_{i=1}^{n-1} x_i] + exclusive means + cumprod(x) = [1, x1, x1x2, x1x2x3, ..., prod_{i=1}^{n-1} x_i] """ tensor_size = list(tensor.size()) tensor_size[dim] = 1 @@ -28,7 +39,9 @@ def exclusive_cumprod(tensor, dim: int, eps: float = 1e-10): elif dim == 2: return return_tensor[:, :, :-1] else: - raise RuntimeError("Cumprod on dimension 3 and more is not implemented") + raise RuntimeError( + "Cumprod on dimension 3 and more is not implemented" + ) def safe_cumprod(tensor, dim: int, eps: float = 1e-10): @@ -52,42 +65,6 @@ def safe_cumprod(tensor, dim: int, eps: float = 1e-10): return exp_cumsum_log_tensor -def lengths_to_mask(lengths, max_len: int, dim: int = 0, negative_mask: bool = False): - """ - Convert a tensor of lengths to mask - For example, lengths = [[2, 3, 4]], max_len = 5 - mask = - [[1, 1, 1], - [1, 1, 1], - [0, 1, 1], - [0, 0, 1], - [0, 0, 0]] - """ - assert len(lengths.size()) <= 2 - if len(lengths) == 2: - if dim == 1: - lengths = lengths.t() - lengths = lengths - else: - lengths = lengths.unsqueeze(1) - - # lengths : batch_size, 1 - lengths = lengths.view(-1, 1) - - batch_size = lengths.size(0) - # batch_size, max_len - mask = torch.arange(max_len).expand(batch_size, max_len).type_as(lengths) < lengths - - if negative_mask: - mask = ~mask - - if dim == 0: - # max_len, batch_size - mask = mask.t() - - return mask - - def moving_sum(x, start_idx: int, end_idx: int): """ From MONOTONIC CHUNKWISE ATTENTION @@ -126,24 +103,22 @@ def moving_sum(x, start_idx: int, end_idx: int): [ 7, 17, 27], [ 4, 9, 14]] """ + # TODO: Make dimension configurable assert start_idx > 0 and end_idx > 0 - assert len(x.size()) == 2 - src_len, batch_size = x.size() + batch_size, tgt_len, src_len = x.size() + x = x.view(-1, src_len).unsqueeze(1) # batch_size, 1, src_len - x = x.t().unsqueeze(1) - # batch_size, 1, src_len - moving_sum_weight = x.new_ones([1, 1, end_idx + start_idx - 1]) + moving_sum_weight = torch.ones([1, 1, end_idx + start_idx - 1]).type_as(x) - moving_sum = ( - torch.nn.functional.conv1d( - x, moving_sum_weight, padding=start_idx + end_idx - 1 - ) - .squeeze(1) - .t() - ) - moving_sum = moving_sum[end_idx:-start_idx] + moving_sum = torch.nn.functional.conv1d( + x, moving_sum_weight, padding=start_idx + end_idx - 1 + ).squeeze(1) + + moving_sum = moving_sum[:, end_idx:-start_idx] + + assert src_len == moving_sum.size(1) + assert batch_size * tgt_len == moving_sum.size(0) - assert src_len == moving_sum.size(0) - assert batch_size == moving_sum.size(1) + moving_sum = moving_sum.view(batch_size, tgt_len, src_len) return moving_sum diff --git a/examples/simultaneous_translation/utils/monotonic_attention.py b/examples/simultaneous_translation/utils/monotonic_attention.py new file mode 100644 index 0000000000..fd45137735 --- /dev/null +++ b/examples/simultaneous_translation/utils/monotonic_attention.py @@ -0,0 +1,196 @@ +from typing import Optional +import torch +from torch import Tensor + +from examples.simultaneous_translation.utils.functions import ( + exclusive_cumprod, + prob_check, + moving_sum, +) + + +def expected_alignment_from_p_choose( + p_choose: Tensor, + padding_mask: Optional[Tensor] = None, + eps: float = 1e-6 +): + """ + Calculating expected alignment for from stepwise probability + + Reference: + Online and Linear-Time Attention by Enforcing Monotonic Alignments + https://arxiv.org/pdf/1704.00784.pdf + + q_ij = (1 − p_{ij−1})q_{ij−1} + a+{i−1j} + a_ij = p_ij q_ij + + Parallel solution: + ai = p_i * cumprod(1 − pi) * cumsum(a_i / cumprod(1 − pi)) + + ============================================================ + Expected input size + p_choose: bsz, tgt_len, src_len + """ + prob_check(p_choose) + + # p_choose: bsz, tgt_len, src_len + bsz, tgt_len, src_len = p_choose.size() + dtype = p_choose.dtype + + p_choose = p_choose.float() + + if padding_mask is not None: + p_choose = p_choose.masked_fill(padding_mask.unsqueeze(1), 0.0) + + # cumprod_1mp : bsz, tgt_len, src_len + cumprod_1mp = exclusive_cumprod(1 - p_choose, dim=2, eps=eps) + cumprod_1mp_clamp = torch.clamp(cumprod_1mp, eps, 1.0) + + alpha_0 = p_choose.new_zeros([bsz, 1, src_len]) + alpha_0[:, :, 0] = 1.0 + + previous_alpha = [alpha_0] + + for i in range(tgt_len): + # p_choose: bsz , tgt_len, src_len + # cumprod_1mp_clamp : bsz, tgt_len, src_len + # previous_alpha[i]: bsz, 1, src_len + # alpha_i: bsz, src_len + alpha_i = ( + p_choose[:, i] + * cumprod_1mp[:, i] + * torch.cumsum( + previous_alpha[i][:, 0] / cumprod_1mp_clamp[:, i], dim=1 + ) + ).clamp(0, 1.0) + + previous_alpha.append(alpha_i.unsqueeze(1)) + + # alpha: bsz * num_heads, tgt_len, src_len + alpha = torch.cat(previous_alpha[1:], dim=1) + + # Mix precision to prevent overflow for fp16 + alpha = alpha.type(dtype) + + prob_check(alpha) + + return alpha + + +def expected_soft_attention( + alpha: Tensor, + soft_energy: Tensor, + padding_mask: Optional[Tensor] = None, + chunk_size: Optional[int] = None, + eps: float = 1e-10 +): + """ + Function to compute expected soft attention for + monotonic infinite lookback attention from + expected alignment and soft energy. + + Reference: + Monotonic Chunkwise Attention + https://arxiv.org/abs/1712.05382 + + Monotonic Infinite Lookback Attention for Simultaneous Machine Translation + https://arxiv.org/abs/1906.05218 + + alpha: bsz, tgt_len, src_len + soft_energy: bsz, tgt_len, src_len + padding_mask: bsz, src_len + left_padding: bool + """ + if padding_mask is not None: + alpha = alpha.masked_fill(padding_mask.unsqueeze(1), 0.0) + soft_energy = soft_energy.masked_fill( + padding_mask.unsqueeze(1), -float("inf") + ) + + prob_check(alpha) + + dtype = alpha.dtype + + alpha = alpha.float() + soft_energy = soft_energy.float() + + soft_energy = soft_energy - soft_energy.max(dim=2, keepdim=True)[0] + exp_soft_energy = torch.exp(soft_energy) + eps + + if chunk_size is not None: + # Chunkwise + beta = ( + exp_soft_energy + * moving_sum( + alpha / (eps + moving_sum(exp_soft_energy, chunk_size, 1)), + 1, chunk_size + ) + ) + else: + # Infinite lookback + # Notice that infinite lookback is a special case of chunkwise + # where chunksize = inf + inner_items = alpha / (eps + torch.cumsum(exp_soft_energy, dim=2)) + + beta = ( + exp_soft_energy + * torch.cumsum(inner_items.flip(dims=[2]), dim=2) + .flip(dims=[2]) + ) + + if padding_mask is not None: + beta = beta.masked_fill( + padding_mask.unsqueeze(1).to(torch.bool), 0.0) + + # Mix precision to prevent overflow for fp16 + beta = beta.type(dtype) + + prob_check(beta) + + return beta + + +def mass_preservation( + alpha: Tensor, + padding_mask: Optional[Tensor] = None, + left_padding: bool = False +): + """ + Function to compute the mass perservation for alpha. + This means that the residual weights of alpha will be assigned + to the last token. + + Reference: + Monotonic Infinite Lookback Attention for Simultaneous Machine Translation + https://arxiv.org/abs/1906.05218 + + alpha: bsz, tgt_len, src_len + padding_mask: bsz, src_len + left_padding: bool + """ + + prob_check(alpha) + + if padding_mask is not None: + if not left_padding: + assert not padding_mask[:, 0].any(), ( + "Find padding on the beginning of the sequence." + ) + alpha = alpha.masked_fill(padding_mask.unsqueeze(1), 0.0) + + if left_padding or padding_mask is None: + residuals = 1 - alpha[:, :, :-1].sum(dim=-1).clamp(0, 1) + alpha[:, :, -1] = residuals + else: + # right padding + _, tgt_len, src_len = alpha.size() + residuals = 1 - alpha.sum(dim=-1, keepdim=True).clamp(0, 1) + src_lens = src_len - padding_mask.sum(dim=1, keepdim=True) + src_lens = src_lens.expand(-1, tgt_len).contiguous() + # add back the last value + residuals += alpha.gather(2, src_lens.unsqueeze(2) - 1) + alpha = alpha.scatter(2, src_lens.unsqueeze(2) - 1, residuals) + + prob_check(alpha) + + return alpha diff --git a/examples/simultaneous_translation/utils/p_choose_strategy.py b/examples/simultaneous_translation/utils/p_choose_strategy.py index 308227ed96..724c6912a6 100644 --- a/examples/simultaneous_translation/utils/p_choose_strategy.py +++ b/examples/simultaneous_translation/utils/p_choose_strategy.py @@ -3,30 +3,34 @@ import torch -def waitk( - query, key, waitk_lagging: int, num_heads: int, key_padding_mask: Optional[Tensor] = None, +def waitk_p_choose( + tgt_len: int, + src_len: int, + bsz: int, + waitk_lagging: int, + key_padding_mask: Optional[Tensor] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None ): + + max_src_len = src_len if incremental_state is not None: # Retrieve target length from incremental states # For inference the length of query is always 1 - tgt_len = incremental_state["steps"]["tgt"] - assert tgt_len is not None - tgt_len = int(tgt_len) + max_tgt_len = incremental_state["steps"]["tgt"] + assert max_tgt_len is not None + max_tgt_len = int(max_tgt_len) else: - tgt_len, bsz, _ = query.size() - - max_src_len, bsz, _ = key.size() + max_tgt_len = tgt_len if max_src_len < waitk_lagging: if incremental_state is not None: - tgt_len = 1 - return query.new_zeros( - bsz * num_heads, tgt_len, max_src_len + max_tgt_len = 1 + return torch.zeros( + bsz, max_tgt_len, max_src_len ) # Assuming the p_choose looks like this for wait k=3 - # src_len = 6, tgt_len = 5 + # src_len = 6, max_tgt_len = 5 # [0, 0, 1, 0, 0, 0, 0] # [0, 0, 0, 1, 0, 0, 0] # [0, 0, 0, 0, 1, 0, 0] @@ -39,21 +43,20 @@ def waitk( # 3 + 6 * 1 # ... # n + src_len * n + k - 1 = n * (src_len + 1) + k - 1 - # n from 0 to tgt_len - 1 + # n from 0 to max_tgt_len - 1 # - # First, generate the indices (activate_indices_offset: bsz, tgt_len) - # Second, scatter a zeros tensor (bsz, tgt_len * src_len) + # First, generate the indices (activate_indices_offset: bsz, max_tgt_len) + # Second, scatter a zeros tensor (bsz, max_tgt_len * src_len) # with activate_indices_offset - # Third, resize the tensor to (bsz, tgt_len, src_len) + # Third, resize the tensor to (bsz, max_tgt_len, src_len) activate_indices_offset = ( ( - torch.arange(tgt_len) * (max_src_len + 1) + torch.arange(max_tgt_len) * (max_src_len + 1) + waitk_lagging - 1 ) .unsqueeze(0) - .expand(bsz, tgt_len) - .to(query) + .expand(bsz, max_tgt_len) .long() ) @@ -71,54 +74,53 @@ def waitk( 0, min( [ - tgt_len, + max_tgt_len, max_src_len - waitk_lagging + 1 ] ) * max_src_len - 1 ) ) - p_choose = torch.zeros(bsz, tgt_len * max_src_len).to(query) + p_choose = torch.zeros(bsz, max_tgt_len * max_src_len) p_choose = p_choose.scatter( 1, activate_indices_offset, 1.0 - ).view(bsz, tgt_len, max_src_len) + ).view(bsz, max_tgt_len, max_src_len) + + if key_padding_mask is not None: + p_choose = p_choose.to(key_padding_mask) + p_choose = p_choose.masked_fill(key_padding_mask.unsqueeze(1), 0) if incremental_state is not None: p_choose = p_choose[:, -1:] - tgt_len = 1 - - # Extend to each head - p_choose = ( - p_choose.contiguous() - .unsqueeze(1) - .expand(-1, num_heads, -1, -1) - .contiguous() - .view(-1, tgt_len, max_src_len) - ) - return p_choose + return p_choose.float() -def hard_aligned(q_proj: Optional[Tensor], k_proj: Optional[Tensor], attn_energy, noise_mean: float = 0.0, noise_var: float = 0.0, training: bool = True): +def learnable_p_choose( + energy, + noise_mean: float = 0.0, + noise_var: float = 0.0, + training: bool = True +): """ Calculating step wise prob for reading and writing 1 to read, 0 to write + energy: bsz, tgt_len, src_len """ noise = 0 if training: # add noise here to encourage discretness noise = ( - torch.normal(noise_mean, noise_var, attn_energy.size()) - .type_as(attn_energy) - .to(attn_energy.device) + torch.normal(noise_mean, noise_var, energy.size()) + .type_as(energy) + .to(energy.device) ) - p_choose = torch.sigmoid(attn_energy + noise) - _, _, tgt_len, src_len = p_choose.size() + p_choose = torch.sigmoid(energy + noise) # p_choose: bsz * self.num_heads, tgt_len, src_len - return p_choose.view(-1, tgt_len, src_len) + return p_choose From 95a9cb798dc8d6375428c6a9502234de8b4c3ec8 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Wed, 21 Jul 2021 13:29:09 -0700 Subject: [PATCH 412/774] add text compression to FileAudioDataset + speed up AddTargetDataset Summary: # Add text compression to FileAudioDataset The FileAudioDatasetstores the full manifest (mainly raw texts --- audio filenames + target texts for finetuning) in memory. This leads to large memory usage as data is duplicated in multiple workers. And it limits the scale of training data that we can use before having to switch to `BinarizedAudioDataset`. This diff aims at alleviating this limitation by in-memory text compression. This technique can be applied to any other dataset classes that store raw texts (e.g. `speech_to_text_dataset`). ### Implementation - `zlib` for low-level compression: built-in, relatively fast (as shown in the benchmarking below) - `unishox2` for high-level compression: optimized for short texts but relatively slower ### Benchmarking Tested with single process/thread. **On 3.6G TSV manifest (ASCII filenames) data** | Compression Level | CPU Mem Usage | Loading + Encoding | Decoding | |---|---|---|---| | No | 6782.18MB | 00:32 | - | | Low | 6450.04MB (95.10%) | 04:39 | 01:03 | | High | 4742.91MB (69.93%) | 08:49 | 01:31| **On 7.8G label (Arabic text) data** | Compression Level | CPU Mem Usage | Loading + Encoding | Decoding | |---|---|---|---| | No | 14623.57MB | 00:58 | - | | Low | 10773.65MB (73.67%) | 05:38 | 01:45 | | High | 7352.67MB (50.28%) | 25:03 | 04:31 | The difference on CPU memory usage will be enlarged when data is duplicated in multiple dataloading workers. # Speed up AddTargetDataset AddTargetDataset gets label length from tensorized data which is very slow --- leading to 6+hrs for batching ~8G text. Replaced it with a helper function that gets length from untokenized string data and reduced the time from 6+hrs to 10min. Reviewed By: cndn Differential Revision: D29093876 fbshipit-source-id: b6b9a8da61944771bb7c8cb57b207ed4d79d0764 --- fairseq/data/add_target_dataset.py | 21 ++++++---- fairseq/data/audio/raw_audio_dataset.py | 12 ++++-- fairseq/data/text_compressor.py | 56 +++++++++++++++++++++++++ fairseq/tasks/audio_pretraining.py | 26 +++++++++++- 4 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 fairseq/data/text_compressor.py diff --git a/fairseq/data/add_target_dataset.py b/fairseq/data/add_target_dataset.py index 9ef467058b..673963d0ed 100644 --- a/fairseq/data/add_target_dataset.py +++ b/fairseq/data/add_target_dataset.py @@ -6,6 +6,7 @@ import torch from . import BaseWrapperDataset, data_utils +from fairseq.data.text_compressor import TextCompressor, TextCompressionLevel class AddTargetDataset(BaseWrapperDataset): @@ -17,7 +18,9 @@ def __init__( eos, batch_targets, process_label=None, + label_len_fn=None, add_to_input=False, + text_compression_level=TextCompressionLevel.none ): super().__init__(dataset) self.labels = labels @@ -25,24 +28,24 @@ def __init__( self.pad = pad self.eos = eos self.process_label = process_label + self.label_len_fn = label_len_fn self.add_to_input = add_to_input + self.text_compressor = TextCompressor(level=text_compression_level) - def get_label(self, index): - return ( - self.labels[index] - if self.process_label is None - else self.process_label(self.labels[index]) - ) + def get_label(self, index, process_fn=None): + lbl = self.labels[index] + lbl = self.text_compressor.decompress(lbl) + return lbl if process_fn is None else process_fn(lbl) def __getitem__(self, index): item = self.dataset[index] - item["label"] = self.get_label(index) + item["label"] = self.get_label(index, process_fn=self.process_label) return item def size(self, index): sz = self.dataset.size(index) - own_sz = len(self.get_label(index)) - return (sz, own_sz) + own_sz = self.label_len_fn(self.get_label(index)) + return sz, own_sz def collater(self, samples): collated = self.dataset.collater(samples) diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 9ce3f7e39d..f4e965493c 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -20,6 +20,7 @@ read_from_stored_zip, is_sf_audio_data, ) +from fairseq.data.text_compressor import TextCompressor, TextCompressionLevel logger = logging.getLogger(__name__) @@ -256,6 +257,7 @@ def __init__( normalize=False, num_buckets=0, compute_mask_indices=False, + text_compression_level=TextCompressionLevel.none, **mask_compute_kwargs, ): super().__init__( @@ -269,6 +271,8 @@ def __init__( **mask_compute_kwargs, ) + self.text_compressor = TextCompressor(level=text_compression_level) + skipped = 0 self.fnames = [] sizes = [] @@ -284,7 +288,7 @@ def __init__( skipped += 1 self.skipped_indices.add(i) continue - self.fnames.append(items[0]) + self.fnames.append(self.text_compressor.compress(items[0])) sizes.append(sz) logger.info(f"loaded {len(self.fnames)}, skipped {skipped} samples") @@ -304,8 +308,10 @@ def __init__( def __getitem__(self, index): import soundfile as sf - - path_or_fp = os.path.join(self.root_dir, str(self.fnames[index])) + fn = self.fnames[index] + fn = fn if isinstance(self.fnames, list) else fn.as_py() + fn = self.text_compressor.decompress(fn) + path_or_fp = os.path.join(self.root_dir, fn) _path, slice_ptr = parse_path(path_or_fp) if len(slice_ptr) == 2: byte_data = read_from_stored_zip(_path, slice_ptr[0], slice_ptr[1]) diff --git a/fairseq/data/text_compressor.py b/fairseq/data/text_compressor.py new file mode 100644 index 0000000000..561e9ac89a --- /dev/null +++ b/fairseq/data/text_compressor.py @@ -0,0 +1,56 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from enum import Enum + + +class TextCompressionLevel(Enum): + none = 0 + low = 1 + high = 2 + + +class TextCompressor(object): + def __init__( + self, level: TextCompressionLevel, + max_input_byte_length: int = 2 ** 16 + ): + self.level = level + self.max_input_length = max_input_byte_length + + def compress(self, text: str) -> bytes: + if self.level == TextCompressionLevel.low: + import zlib + # zlib: built-in, fast + return zlib.compress(text.encode(), level=0) + elif self.level == TextCompressionLevel.high: + try: + import unishox2 + # unishox2: optimized for short text but slower + except ImportError: + raise ImportError( + "Please install unishox2 for the text compression feature: " + "pip install unishox2-py3" + ) + assert len(text.encode()) <= self.max_input_length + return unishox2.compress(text)[0] + else: + return text.encode() + + def decompress(self, compressed: bytes) -> str: + if self.level == TextCompressionLevel.low: + import zlib + return zlib.decompress(compressed).decode() + elif self.level == TextCompressionLevel.high: + try: + import unishox2 + except ImportError: + raise ImportError( + "Please install unishox2 for the text compression feature: " + "pip install unishox2-py3" + ) + return unishox2.decompress(compressed, self.max_input_length) + else: + return compressed.decode() diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index c642ff5226..059e2d70c8 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -22,8 +22,9 @@ FileAudioDataset, encoders, ) -from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass import FairseqDataclass, ChoiceEnum from fairseq.dataclass.configs import GenerationConfig +from fairseq.data.text_compressor import TextCompressor, TextCompressionLevel from . import FairseqTask, register_task from .. import utils @@ -43,6 +44,10 @@ def __call__(self, label): ) +def label_len_fn(label): + return len(label.split(" ")) + + @dataclass class InferredW2vConfig: # The following are needed to precompute mask and mask channel indices @@ -143,6 +148,13 @@ class AudioPretrainingConfig(FairseqDataclass): ) tpu: bool = II("common.tpu") + text_compression_level: ChoiceEnum([x.name for x in TextCompressionLevel]) = field( + default="none", + metadata={ + "help": "compression level for texts (e.g. audio filenames, " + "target texts): none/low/high (default: none). " + } + ) @register_task("audio_pretraining", dataclass=AudioPretrainingConfig) @@ -198,6 +210,9 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): if not hasattr(task_cfg, "autoregressive"): task_cfg.autoregressive = not task_cfg.criterion == "ctc" + text_compression_level = getattr( + TextCompressionLevel, str(self.cfg.text_compression_level) + ) if getattr(task_cfg, "binarized_dataset", False): self.datasets[split] = BinarizedAudioDataset( data_path, @@ -223,6 +238,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): normalize=task_cfg.normalize, num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), compute_mask_indices=(self.cfg.precompute_mask_indices or self.cfg.tpu), + text_compression_level=text_compression_level, **self._get_mask_precompute_kwargs(task_cfg), ) @@ -236,8 +252,12 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): if task_cfg.labels: label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) + text_compressor = TextCompressor(level=text_compression_level) with open(label_path, "r") as f: - labels = [line for i, line in enumerate(f) if i not in skipped_indices] + labels = [ + text_compressor.compress(l) + for i, l in enumerate(f) if i not in skipped_indices + ] assert len(labels) == len(self.datasets[split]), ( f"labels length ({len(labels)}) and dataset length " @@ -253,7 +273,9 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): eos=self.target_dictionary.eos(), batch_targets=True, process_label=process_label, + label_len_fn=label_len_fn, add_to_input=task_cfg.get("autoregressive", False), + text_compression_level=text_compression_level ) @property From 698961dc0d2eb17d15e9665f6f31fd4c1c4b58c7 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Wed, 21 Jul 2021 15:05:35 -0700 Subject: [PATCH 413/774] Make FSDP and --update-freq play nice (#3727) Summary: Previously combining FSDP with `--update-freq` would result in significant memory usage because full-size gradients would be accumulated on each GPU. We can instead skip the `no_sync` context manager in this case. The tradeoff is more communication (we do reduce-scatter on each backward), but the memory savings are likely to be worth it in most cases. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3727 Reviewed By: sshleifer Differential Revision: D29824021 Pulled By: myleott fbshipit-source-id: 2d942586cc1a9ac33fd34b8709df91dda870dd49 --- fairseq/trainer.py | 62 ++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 1602688671..d53e650b0a 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -61,7 +61,7 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): else: self.device = torch.device("cpu") - if self.cfg.distributed_training.ddp_backend == "fully_sharded": + if self.is_fsdp: if self.cfg.common.bf16: raise ValueError( "FullyShardedDataParallel is not compatible with --bf16 or " @@ -72,12 +72,6 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): "FullyShardedDataParallel is not compatible with --zero-sharding " "option (it's already built in)" ) - if self.cfg.optimization.update_freq[0] > 1: - logger.warning( - "Combining --update-freq with FullyShardedDataParallel will " - "result in increased memory usage, since full-sized gradients " - "will be accumulated on each GPU!" - ) else: if ( hasattr(self.cfg.distributed_training, "cpu_offload") @@ -88,7 +82,7 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): # copy model and criterion to current device/dtype self._criterion = criterion self._model = model - if cfg.distributed_training.ddp_backend != "fully_sharded": + if not self.is_fsdp: if cfg.common.fp16: assert not cfg.common.amp, "Cannot use fp16 and AMP together" self._criterion = self._criterion.half() @@ -197,16 +191,14 @@ def use_distributed_wrapper(self) -> bool: return ( self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf ) or ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and self.cfg.distributed_training.cpu_offload + self.is_fsdp and self.cfg.distributed_training.cpu_offload ) @property def should_save_checkpoint_on_current_rank(self) -> bool: """Indicates whether to save checkpoints on the current DDP rank.""" if ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and self.cfg.distributed_training.use_sharded_state + self.is_fsdp and self.cfg.distributed_training.use_sharded_state ) or getattr(self.cfg.model, "base_layers", 0) > 0: return True else: @@ -214,10 +206,7 @@ def should_save_checkpoint_on_current_rank(self) -> bool: @property def always_call_state_dict_during_save_checkpoint(self) -> bool: - if ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and not self.cfg.distributed_training.use_sharded_state - ): + if self.is_fsdp and not self.cfg.distributed_training.use_sharded_state: # FSDP calls communication collective when consolidating checkpoints return True else: @@ -226,10 +215,7 @@ def always_call_state_dict_during_save_checkpoint(self) -> bool: @property def checkpoint_suffix(self) -> str: """Suffix to add to the checkpoint file name.""" - if ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and self.cfg.distributed_training.use_sharded_state - ): + if self.is_fsdp and self.cfg.distributed_training.use_sharded_state: return self.cfg.checkpoint.checkpoint_suffix + "-shard{0}".format( self.data_parallel_rank ) @@ -284,10 +270,7 @@ def _build_optimizer(self): ) ) - if ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and self.cfg.common.fp16 - ): + if self.is_fsdp and self.cfg.common.fp16: # FullyShardedDataParallel always uses MemoryEfficientFP16 wrapper, # mostly for the grad scaling. But if we don't have the # --memory-efficient-fp16 flag set, then we're effectively doing @@ -319,7 +302,7 @@ def _build_optimizer(self): logger.info("NOTE: your device may support faster training with --fp16 or --amp") self._optimizer = optim.build_optimizer(self.cfg.optimizer, params) - if self.cfg.distributed_training.ddp_backend == "fully_sharded": + if self.is_fsdp: assert ( not self.cfg.optimization.use_bmuf ), "--ddp-backend=fully_sharded is not compatible with BMUF" @@ -357,6 +340,10 @@ def _build_optimizer(self): ) self._lr_scheduler.step_update(0) + @property + def is_fsdp(self): + return self.cfg.distributed_training.ddp_backend == "fully_sharded" + def consolidate_optimizer(self): """For OSS, we need to consolidate the state dict.""" if self.cfg.checkpoint.no_save_optimizer_state: @@ -364,11 +351,7 @@ def consolidate_optimizer(self): self._gathered_optim_state = None if hasattr(self.optimizer.optimizer, "consolidate_state_dict"): self.optimizer.optimizer.consolidate_state_dict() - - elif ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and not self.model.use_sharded_state - ): + elif self.is_fsdp and not self.model.use_sharded_state: st = self.model.gather_full_optim_state_dict( self.optimizer ) # only returns on rank 0 @@ -409,7 +392,7 @@ def state_dict(self): self._gathered_optim_state = None else: state_dict["last_optimizer_state"] = self.optimizer.state_dict() - if self.cfg.distributed_training.ddp_backend == "fully_sharded": + if self.is_fsdp: # save meta data for recombining checkpoint upon loading state_dict["fsdp_metadata"] = self.model.local_metadata_dict() return state_dict @@ -453,10 +436,7 @@ def load_checkpoint( # on every worker for now or self.tpu # FSDP requires loading checkpoint shards on all ranks - or ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and self.cfg.distributed_training.use_sharded_state - ) + or (self.is_fsdp and self.cfg.distributed_training.use_sharded_state) or getattr(self.cfg.model, "base_layers", 0) > 0 ) @@ -527,10 +507,7 @@ def load_checkpoint( if not reset_lr_scheduler: self.lr_scheduler.load_state_dict(last_optim["lr_scheduler_state"]) - if ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" - and not self.model.use_sharded_state - ): + if self.is_fsdp and not self.model.use_sharded_state: # if use_sharded_state, the last_optim_state is already sharded, skip this last_optim_state = self.model.get_shard_from_optim_state_dict( last_optim_state @@ -702,6 +679,11 @@ def maybe_no_sync(): self.data_parallel_world_size > 1 and hasattr(self.model, "no_sync") and i < len(samples) - 1 + # The no_sync context manager results in increased memory + # usage with FSDP, since full-size gradients will be + # accumulated on each GPU. It's typically a better tradeoff + # to do the extra communication with FSDP. + and not self.is_fsdp ): return self.model.no_sync() else: @@ -1112,7 +1094,7 @@ def agg_norm_fn(total_norm): return total_norm ** 0.5 should_agg_norm = ( - self.cfg.distributed_training.ddp_backend == "fully_sharded" + self.is_fsdp and ( self.data_parallel_process_group is not None or torch.distributed.is_initialized() From 5826a6855f05cab919f567a68b66d6d8c1817551 Mon Sep 17 00:00:00 2001 From: Ishani Karmarkar <ikarmarkar@fb.com> Date: Wed, 21 Jul 2021 23:11:59 -0700 Subject: [PATCH 414/774] Allow Moving Observer to Cuda Summary: Allow for moving observer to cuda in emulate_int8_{method} functions in order to make it compatible with pytext trainers. Reviewed By: huihuifan Differential Revision: D29686263 fbshipit-source-id: 7eddaadb17163bd4be33de1ae729621d043520d2 --- fairseq/modules/quantization/scalar/ops.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fairseq/modules/quantization/scalar/ops.py b/fairseq/modules/quantization/scalar/ops.py index 2a855159be..cb0120fa81 100644 --- a/fairseq/modules/quantization/scalar/ops.py +++ b/fairseq/modules/quantization/scalar/ops.py @@ -20,6 +20,7 @@ def quantize(w, scale, zero_point): def emulate_int8_histogram(w, scale=None, zero_point=None): if scale is None: obs = torch.quantization.observer.HistogramObserver() + obs.to(device=w.device) _ = obs(w.float()) scale, zero_point = obs.calculate_qparams() scale = scale.cuda().type_as(w) @@ -32,6 +33,7 @@ def emulate_int8_channel(w, scale=None, zero_point=None): obs = torch.quantization.observer.PerChannelMinMaxObserver( ch_axis=-1, qscheme=torch.per_channel_symmetric ) + obs.to(device=w.device) _ = obs(w) scale, zero_point, ch_axis = obs.get_qparams() scale = scale.cuda().type_as(w) @@ -42,6 +44,7 @@ def emulate_int8_channel(w, scale=None, zero_point=None): def emulate_int8_tensor(w, scale=None, zero_point=None): if scale is None: obs = torch.quantization.observer.MinMaxObserver() + obs.to(device=w.device) _ = obs(w) scale, zero_point = obs.calculate_qparams() scale = scale.cuda().type_as(w) From 7feb8747b2f88752a5a5c5a5c85b0b3e428ca549 Mon Sep 17 00:00:00 2001 From: Ishani Karmarkar <ikarmarkar@fb.com> Date: Thu, 22 Jul 2021 05:00:38 -0700 Subject: [PATCH 415/774] Support Quantization to variable number of bits Summary: allow quantization using quant noise with variable number of bits Reviewed By: huihuifan Differential Revision: D29686262 fbshipit-source-id: 661e7d684f006af891191b32639651214df79bc4 --- fairseq/modules/quantization/scalar/ops.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/fairseq/modules/quantization/scalar/ops.py b/fairseq/modules/quantization/scalar/ops.py index cb0120fa81..c74f530380 100644 --- a/fairseq/modules/quantization/scalar/ops.py +++ b/fairseq/modules/quantization/scalar/ops.py @@ -7,17 +7,19 @@ def emulate_int(w, bits, method, scale=None, zero_point=None): - q = globals()[f"emulate_int{bits}_{method}"] - return q(w, scale=scale, zero_point=zero_point) + q = globals()[f"emulate_int8_{method}"] + return q(w, scale=scale, zero_point=zero_point, bits=bits) -def quantize(w, scale, zero_point): +def quantize(w, scale, zero_point, bits=8): + # In the default behavior, max_val = 255. + max_val = 2 ** bits - 1 return ( - torch.clamp(torch.round(w / scale + zero_point), 0, 255) - zero_point + torch.clamp(torch.round(w / scale + zero_point), 0, max_val) - zero_point ) * scale -def emulate_int8_histogram(w, scale=None, zero_point=None): +def emulate_int8_histogram(w, scale=None, zero_point=None, bits=8): if scale is None: obs = torch.quantization.observer.HistogramObserver() obs.to(device=w.device) @@ -25,10 +27,10 @@ def emulate_int8_histogram(w, scale=None, zero_point=None): scale, zero_point = obs.calculate_qparams() scale = scale.cuda().type_as(w) zero_point = zero_point.cuda().type_as(w) - return quantize(w, scale, zero_point), scale, zero_point + return quantize(w, scale, zero_point, bits=bits), scale, zero_point -def emulate_int8_channel(w, scale=None, zero_point=None): +def emulate_int8_channel(w, scale=None, zero_point=None, bits=8): if scale is None: obs = torch.quantization.observer.PerChannelMinMaxObserver( ch_axis=-1, qscheme=torch.per_channel_symmetric @@ -38,10 +40,10 @@ def emulate_int8_channel(w, scale=None, zero_point=None): scale, zero_point, ch_axis = obs.get_qparams() scale = scale.cuda().type_as(w) zero_point = zero_point.cuda().type_as(w) - return quantize(w, scale, zero_point), scale, zero_point + return quantize(w, scale, zero_point, bits=bits), scale, zero_point -def emulate_int8_tensor(w, scale=None, zero_point=None): +def emulate_int8_tensor(w, scale=None, zero_point=None, bits=8): if scale is None: obs = torch.quantization.observer.MinMaxObserver() obs.to(device=w.device) @@ -49,4 +51,4 @@ def emulate_int8_tensor(w, scale=None, zero_point=None): scale, zero_point = obs.calculate_qparams() scale = scale.cuda().type_as(w) zero_point = zero_point.cuda().type_as(w) - return quantize(w, scale, zero_point), scale, zero_point + return quantize(w, scale, zero_point, bits=bits), scale, zero_point From eff39d5d453497a5a6e5e998e2a920fb5f0618e1 Mon Sep 17 00:00:00 2001 From: Ishani Karmarkar <ikarmarkar@fb.com> Date: Thu, 22 Jul 2021 05:16:11 -0700 Subject: [PATCH 416/774] quantize_layers_ using variable methods Summary: allow for moving average per channel and per channel observer to be customized when calling quantize_model_ Reviewed By: huihuifan Differential Revision: D29686457 fbshipit-source-id: 37b833d27d643e6963c9ab7e0af9b8f889e1a2fc --- fairseq/modules/quantization/pq/utils.py | 6 +++++- fairseq/modules/quantization/scalar/utils.py | 10 ++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/fairseq/modules/quantization/pq/utils.py b/fairseq/modules/quantization/pq/utils.py index 03b15e4b1b..3c5ea4155d 100644 --- a/fairseq/modules/quantization/pq/utils.py +++ b/fairseq/modules/quantization/pq/utils.py @@ -152,7 +152,7 @@ def quantize_model_( return quantized_layers -def get_layers(model, filter_regexp): +def get_layers(model, filter_regexp, remove_weights=False): """ Filters out the layers according to a regexp. Note that we omit biases. @@ -181,6 +181,10 @@ def get_layers(model, filter_regexp): # remove .weight in all other names (or .weight_orig is spectral norm) all_layers = map(lambda x: x.replace(".weight_orig", ""), all_layers) + # remove weights indicates whether the weights extension should be removed, in addition to + # weight_orig and weight extension on names + if remove_weights: + all_layers = map(lambda x: x.replace(".weights", ""), all_layers) all_layers = map(lambda x: x.replace(".weight", ""), all_layers) # return filtered layers diff --git a/fairseq/modules/quantization/scalar/utils.py b/fairseq/modules/quantization/scalar/utils.py index 32cf616568..76db40fec0 100644 --- a/fairseq/modules/quantization/scalar/utils.py +++ b/fairseq/modules/quantization/scalar/utils.py @@ -16,7 +16,7 @@ MAPPING = {nn.Linear: IntLinear, nn.Embedding: IntEmbedding, nn.Conv2d: IntConv2d} -def quantize_model_(model, p=0.2, bits=8, update_step=3000): +def quantize_model_(model, p=0.2, bits=8, update_step=3000, method="histogram", remove_weights=False): """ Replaces all modules with their scalar quantized counterpart and registers hooks to quantize the post-ativations of those modules. @@ -29,7 +29,9 @@ def quantize_model_(model, p=0.2, bits=8, update_step=3000): """ # quantize all layers - quantized_layers = get_layers(model, "(.*?)") + # remove weights indicates whether the weights extension should be removed, in addition to + # weight_orig and weight extension on names + quantized_layers = get_layers(model, "(.*?)", remove_weights=remove_weights) for layer in quantized_layers: @@ -50,7 +52,7 @@ def quantize_model_(model, p=0.2, bits=8, update_step=3000): "p": p, "update_step": update_step, "bits": bits, - "method": "histogram", + "method": method, "counter": 0, } @@ -68,7 +70,7 @@ def quantize_model_(model, p=0.2, bits=8, update_step=3000): continue # activation quantization - a_q = ActivationQuantizer(quantized_module, p=0, bits=bits, method="histogram") + a_q = ActivationQuantizer(quantized_module, p=0, bits=bits, method=method) # replace layer by its quantized counterpart attrsetter(layer)(model, quantized_module) From bc3bd55ec98c39af45ff7323ae49bcbdf93acc36 Mon Sep 17 00:00:00 2001 From: Kenneth Heafield <kheafield@fb.com> Date: Thu, 22 Jul 2021 10:38:47 -0700 Subject: [PATCH 417/774] Fix anchor link for inference & evaluation Summary: The link in the documentation was wrong due to & in the anchor. Reviewed By: xutaima Differential Revision: D29850940 fbshipit-source-id: 5024802e868f4a2f5440a35f1792bf5337fd3abf --- examples/speech_to_text/docs/simulst_mustc_example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_to_text/docs/simulst_mustc_example.md b/examples/speech_to_text/docs/simulst_mustc_example.md index 52ca9ac062..f3b5a413a2 100644 --- a/examples/speech_to_text/docs/simulst_mustc_example.md +++ b/examples/speech_to_text/docs/simulst_mustc_example.md @@ -6,7 +6,7 @@ This is a tutorial of training and evaluating a transformer *wait-k* simultaneou ## Data Preparation This section introduces the data preparation for training and evaluation. -If you only want to evaluate the model, please jump to [Inference & Evaluation](#inference-&-evaluation) +If you only want to evaluate the model, please jump to [Inference & Evaluation](#inference--evaluation) [Download](https://ict.fbk.eu/must-c) and unpack MuST-C data to a path `${MUSTC_ROOT}/en-${TARGET_LANG_ID}`, then preprocess it with From e1adc9d388c1af907366c5f328bb7672f618a73c Mon Sep 17 00:00:00 2001 From: Edan Tessel Sneh <edan@fb.com> Date: Fri, 23 Jul 2021 10:43:24 -0700 Subject: [PATCH 418/774] hacky fix for gen_parser bug Summary: hacky fix for gen_parser bug to unblock fbtranslate Reviewed By: theweiho Differential Revision: D29865385 fbshipit-source-id: 0d92c8c67c465cec6eb309185087aec469ade713 --- fairseq/models/transformer/transformer_base.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fairseq/models/transformer/transformer_base.py b/fairseq/models/transformer/transformer_base.py index e3ceb3c317..49fd30e502 100644 --- a/fairseq/models/transformer/transformer_base.py +++ b/fairseq/models/transformer/transformer_base.py @@ -49,6 +49,10 @@ def add_args(parser): def build_model(cls, cfg, task): """Build a new model instance.""" + # hacky fixes for issue with II + cfg.decoder.input_dim = int(cfg.decoder.input_dim) + cfg.decoder.output_dim = int(cfg.decoder.output_dim) + if cfg.encoder.layers_to_keep: cfg.encoder.layers = len(cfg.encoder.layers_to_keep.split(',')) if cfg.decoder.layers_to_keep: From 67ff6baa42c1208d0da85f5af2f01689034d1dfd Mon Sep 17 00:00:00 2001 From: Shashank Chaudhry <gandalf@fb.com> Date: Fri, 23 Jul 2021 11:07:47 -0700 Subject: [PATCH 419/774] Apply the CLANGFORMAT linter to fbcode/deeplearning/projects/fairseq-py/** Summary: Try to lint the folders in deeplearning/projects/**. Context: FBCode doesn't enable CLANGFORMAT linter over the entire repo because too many files currently don't conform to it. This is an attempt to migrate folder paths to use CLANGFORMAT conventions. Doc: https://fburl.com/clangformat-for-fbcode Actions: Please check the formatting recommendations and accept if they seem ok, or reply if there is a reason for concern. Command run: arc lint --take CLANGFORMAT -a --paths-cmd 'hg files deeplearning/projects/fairseq-py/**' Reviewed By: dianaml0 Differential Revision: D29838082 fbshipit-source-id: 3afbff42e239a6376543c4a849da4221dbf7eb32 --- .../kaldi/add-self-loop-simple.cc | 12 +- fairseq/clib/cuda/ngram_repeat_block_cuda.cpp | 32 +- .../cuda/ngram_repeat_block_cuda_kernel.cu | 32 +- fairseq/clib/libbase/balanced_assignment.cpp | 138 +++-- fairseq/clib/libbleu/libbleu.cpp | 86 +-- fairseq/clib/libbleu/module.cpp | 22 +- fairseq/clib/libnat/edit_dist.cpp | 4 +- fairseq/clib/libnat_cuda/binding.cpp | 69 ++- fairseq/clib/libnat_cuda/edit_dist.cu | 566 +++++++++--------- fairseq/clib/libnat_cuda/edit_dist.h | 16 +- fairseq/modules/cuda_utils.cu | 79 ++- .../dynamicconv_layer/dynamicconv_cuda.cpp | 45 +- .../dynamicconv_layer/dynamicconv_cuda.cuh | 29 +- .../dynamicconv_cuda_kernel.cu | 104 ++-- .../dynamicconv_layer/dynamiconv_cpu.cpp | 22 +- .../lightconv_layer/lightconv_cuda.cpp | 43 +- .../lightconv_layer/lightconv_cuda.cuh | 52 +- .../lightconv_layer/lightconv_cuda_kernel.cu | 173 +++--- 18 files changed, 798 insertions(+), 726 deletions(-) diff --git a/examples/speech_recognition/kaldi/add-self-loop-simple.cc b/examples/speech_recognition/kaldi/add-self-loop-simple.cc index 89754b925e..e18fb62df5 100644 --- a/examples/speech_recognition/kaldi/add-self-loop-simple.cc +++ b/examples/speech_recognition/kaldi/add-self-loop-simple.cc @@ -1,9 +1,9 @@ /* -* Copyright (c) Facebook, Inc. and its affiliates. -* -* This source code is licensed under the MIT license found in the -* LICENSE file in the root directory of this source tree. -*/ + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ #include <iostream> #include "fstext/fstext-lib.h" // @manual @@ -91,4 +91,4 @@ int main(int argc, char** argv) { KALDI_LOG << "Writing FST to " << output << std::endl; delete fst; -} \ No newline at end of file +} diff --git a/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp b/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp index 4199cd6ea8..707219105a 100644 --- a/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp +++ b/fairseq/clib/cuda/ngram_repeat_block_cuda.cpp @@ -11,10 +11,13 @@ CPP Binding for CUDA OP */ // CUDA forward declarations -torch::Tensor ngram_repeat_block_cuda_forward(torch::Tensor tokens, - torch::Tensor lprobs, int bsz, - int step, int beam_size, - int no_repeat_ngram_size); +torch::Tensor ngram_repeat_block_cuda_forward( + torch::Tensor tokens, + torch::Tensor lprobs, + int bsz, + int step, + int beam_size, + int no_repeat_ngram_size); #define CHECK_CUDA(x) \ TORCH_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") @@ -26,10 +29,13 @@ torch::Tensor ngram_repeat_block_cuda_forward(torch::Tensor tokens, // Input check and call to CUDA OP // Backward method not required -torch::Tensor ngram_repeat_block_forward(torch::Tensor tokens, - torch::Tensor lprobs, int bsz, - int step, int beam_size, - int no_repeat_ngram_size) { +torch::Tensor ngram_repeat_block_forward( + torch::Tensor tokens, + torch::Tensor lprobs, + int bsz, + int step, + int beam_size, + int no_repeat_ngram_size) { CHECK_INPUT(tokens); CHECK_INPUT(lprobs); assert(bsz > 0); @@ -37,11 +43,13 @@ torch::Tensor ngram_repeat_block_forward(torch::Tensor tokens, assert(beam_size > 0); assert(no_repeat_ngram_size > 0); - return ngram_repeat_block_cuda_forward(tokens, lprobs, bsz, step, beam_size, - no_repeat_ngram_size); + return ngram_repeat_block_cuda_forward( + tokens, lprobs, bsz, step, beam_size, no_repeat_ngram_size); } PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("forward", &ngram_repeat_block_forward, - "No Repeat Ngram Block forward (CUDA)"); + m.def( + "forward", + &ngram_repeat_block_forward, + "No Repeat Ngram Block forward (CUDA)"); } diff --git a/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu b/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu index b458b0916a..bd6106cba0 100644 --- a/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu +++ b/fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu @@ -14,10 +14,12 @@ Kernel implementation for blocking repeated n-grams. #include <vector> // Ban repeated ngrams of length = 'no_repeat_ngram_size' -__global__ void banRepeatedTokens(long* __restrict__ tokens, - float* __restrict__ lprobs, - int max_predict_len, int vocab_size, - int no_repeat_ngram_size) { +__global__ void banRepeatedTokens( + long* __restrict__ tokens, + float* __restrict__ lprobs, + int max_predict_len, + int vocab_size, + int no_repeat_ngram_size) { auto row = blockIdx.x; auto col = threadIdx.x; auto start = row * (max_predict_len) + col; @@ -30,10 +32,10 @@ __global__ void banRepeatedTokens(long* __restrict__ tokens, extern __shared__ long tokens_shm[]; tokens_shm[col] = tokens[start]; if (col == blockDim.x - 1) { - for (int i=1; i<no_repeat_ngram_size; i++){ - if (col+i < max_predict_len){ - tokens_shm[col + i] = tokens[start + i]; - } + for (int i = 1; i < no_repeat_ngram_size; i++) { + if (col + i < max_predict_len) { + tokens_shm[col + i] = tokens[start + i]; + } } } __syncthreads(); @@ -52,12 +54,16 @@ __global__ void banRepeatedTokens(long* __restrict__ tokens, // Allocate blocks and threads based on // batch size and sequence length and launch // kernel -torch::Tensor ngram_repeat_block_cuda_forward(const torch::Tensor tokens, - torch::Tensor lprobs, int bsz, - int step, int beam_size, - int no_repeat_ngram_size) { +torch::Tensor ngram_repeat_block_cuda_forward( + const torch::Tensor tokens, + torch::Tensor lprobs, + int bsz, + int step, + int beam_size, + int no_repeat_ngram_size) { int threads = step - no_repeat_ngram_size + 2; - if (threads <= 0) return lprobs; + if (threads <= 0) + return lprobs; int max_predict_len = tokens.size(1); int vocab_size = lprobs.size(1); auto token_ptr = tokens.data_ptr<long>(); diff --git a/fairseq/clib/libbase/balanced_assignment.cpp b/fairseq/clib/libbase/balanced_assignment.cpp index 296f03b6ae..1a5a1061f3 100644 --- a/fairseq/clib/libbase/balanced_assignment.cpp +++ b/fairseq/clib/libbase/balanced_assignment.cpp @@ -8,86 +8,100 @@ /* C++ code for solving the linear assignment problem. -Based on the Auction Algorithm from https://dspace.mit.edu/bitstream/handle/1721.1/3265/P-2108-26912652.pdf and the implementation from: -https://github.com/bkj/auction-lap -Adapted to be more efficient when each worker is looking for k jobs instead of 1. +Based on the Auction Algorithm from +https://dspace.mit.edu/bitstream/handle/1721.1/3265/P-2108-26912652.pdf and the +implementation from: https://github.com/bkj/auction-lap Adapted to be more +efficient when each worker is looking for k jobs instead of 1. */ #include <torch/extension.h> #include <iostream> using namespace torch::indexing; torch::Tensor balanced_assignment(torch::Tensor job_and_worker_to_score) { - int max_iterations = 100; - torch::Tensor epsilon = (job_and_worker_to_score.max() - job_and_worker_to_score.min()) / 50; - epsilon.clamp_min_(1e-04); - torch::Tensor worker_and_job_to_score = job_and_worker_to_score.detach().transpose(0,1).contiguous(); - int num_workers = worker_and_job_to_score.size(0); - int num_jobs = worker_and_job_to_score.size(1); - auto device = worker_and_job_to_score.device(); - int jobs_per_worker = num_jobs / num_workers; - torch::Tensor value = worker_and_job_to_score.clone(); - int counter = 0; - torch::Tensor max_value = worker_and_job_to_score.max(); + int max_iterations = 100; + torch::Tensor epsilon = + (job_and_worker_to_score.max() - job_and_worker_to_score.min()) / 50; + epsilon.clamp_min_(1e-04); + torch::Tensor worker_and_job_to_score = + job_and_worker_to_score.detach().transpose(0, 1).contiguous(); + int num_workers = worker_and_job_to_score.size(0); + int num_jobs = worker_and_job_to_score.size(1); + auto device = worker_and_job_to_score.device(); + int jobs_per_worker = num_jobs / num_workers; + torch::Tensor value = worker_and_job_to_score.clone(); + int counter = 0; + torch::Tensor max_value = worker_and_job_to_score.max(); - torch::Tensor bid_indices; - torch::Tensor cost = worker_and_job_to_score.new_zeros({1, num_jobs}); - torch::Tensor bids = worker_and_job_to_score.new_empty({num_workers, num_jobs}); - torch::Tensor bid_increments = worker_and_job_to_score.new_empty({num_workers, jobs_per_worker}); - torch::Tensor top_values = worker_and_job_to_score.new_empty({num_workers, jobs_per_worker + 1}); - torch::Tensor high_bids = worker_and_job_to_score.new_empty({num_jobs}); + torch::Tensor bid_indices; + torch::Tensor cost = worker_and_job_to_score.new_zeros({1, num_jobs}); + torch::Tensor bids = + worker_and_job_to_score.new_empty({num_workers, num_jobs}); + torch::Tensor bid_increments = + worker_and_job_to_score.new_empty({num_workers, jobs_per_worker}); + torch::Tensor top_values = + worker_and_job_to_score.new_empty({num_workers, jobs_per_worker + 1}); + torch::Tensor high_bids = worker_and_job_to_score.new_empty({num_jobs}); - torch::Tensor top_index = top_values.to(torch::kLong); - torch::Tensor high_bidders = top_index.new_empty({num_jobs}); - torch::Tensor have_bids = high_bidders.to(torch::kBool); - torch::Tensor jobs_indices = torch::arange({num_jobs}, torch::dtype(torch::kLong).device(device)); - torch::Tensor true_tensor = torch::ones({1}, torch::dtype(torch::kBool).device(device)); + torch::Tensor top_index = top_values.to(torch::kLong); + torch::Tensor high_bidders = top_index.new_empty({num_jobs}); + torch::Tensor have_bids = high_bidders.to(torch::kBool); + torch::Tensor jobs_indices = + torch::arange({num_jobs}, torch::dtype(torch::kLong).device(device)); + torch::Tensor true_tensor = + torch::ones({1}, torch::dtype(torch::kBool).device(device)); - while (true) { - bids.zero_(); - torch::topk_out(top_values, top_index, value, jobs_per_worker + 1, 1); + while (true) { + bids.zero_(); + torch::topk_out(top_values, top_index, value, jobs_per_worker + 1, 1); - // Each worker bids the difference in value between that job and the k+1th job - torch::sub_out(bid_increments, - top_values.index({Slice(None, None), Slice(0, jobs_per_worker)}), - top_values.index({Slice(None, None), jobs_per_worker}).unsqueeze(1)); + // Each worker bids the difference in value between that job and the k+1th + // job + torch::sub_out( + bid_increments, + top_values.index({Slice(None, None), Slice(0, jobs_per_worker)}), + top_values.index({Slice(None, None), jobs_per_worker}).unsqueeze(1)); - bid_increments.add_(epsilon); - bids.scatter_(1, - top_index.index({Slice(None, None),Slice(0, jobs_per_worker)}), - bid_increments); + bid_increments.add_(epsilon); + bids.scatter_( + 1, + top_index.index({Slice(None, None), Slice(0, jobs_per_worker)}), + bid_increments); - if (counter < max_iterations && counter > 0) { - // Put in a minimal bid to retain items from the last round if no-one else bids for them this round - bids.view(-1).index_put_({bid_indices}, epsilon); - } - - // Find the highest bidding worker per job - torch::max_out(high_bids, high_bidders, bids, 0); - torch::gt_out(have_bids, high_bids, 0); + if (counter < max_iterations && counter > 0) { + // Put in a minimal bid to retain items from the last round if no-one else + // bids for them this round + bids.view(-1).index_put_({bid_indices}, epsilon); + } - if (have_bids.all().item<bool>()) { - // All jobs were bid for - break; - } + // Find the highest bidding worker per job + torch::max_out(high_bids, high_bidders, bids, 0); + torch::gt_out(have_bids, high_bids, 0); - // Make popular items more expensive - cost.add_(high_bids); - torch::sub_out(value, worker_and_job_to_score, cost); + if (have_bids.all().item<bool>()) { + // All jobs were bid for + break; + } - bid_indices = ((high_bidders * num_jobs) + jobs_indices).index({have_bids}); + // Make popular items more expensive + cost.add_(high_bids); + torch::sub_out(value, worker_and_job_to_score, cost); - if (counter < max_iterations) { - // Make sure that this item will be in the winning worker's top-k next time. - value.view(-1).index_put_({bid_indices}, max_value); - } - else { - // Suboptimal approximation that converges quickly from current solution - value.view(-1).index_put_({bid_indices}, worker_and_job_to_score.view(-1).index({bid_indices})); - } + bid_indices = ((high_bidders * num_jobs) + jobs_indices).index({have_bids}); - counter += 1; + if (counter < max_iterations) { + // Make sure that this item will be in the winning worker's top-k next + // time. + value.view(-1).index_put_({bid_indices}, max_value); + } else { + // Suboptimal approximation that converges quickly from current solution + value.view(-1).index_put_( + {bid_indices}, worker_and_job_to_score.view(-1).index({bid_indices})); } - return top_index.index({Slice(None, None), Slice(0, jobs_per_worker)}).reshape(-1); + counter += 1; + } + + return top_index.index({Slice(None, None), Slice(0, jobs_per_worker)}) + .reshape(-1); } PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { diff --git a/fairseq/clib/libbleu/libbleu.cpp b/fairseq/clib/libbleu/libbleu.cpp index 3cf2d65b6d..939d9e1174 100644 --- a/fairseq/clib/libbleu/libbleu.cpp +++ b/fairseq/clib/libbleu/libbleu.cpp @@ -6,30 +6,32 @@ * LICENSE file in the root directory of this source tree. */ -#include <map> #include <array> -#include <cstring> #include <cstdio> +#include <cstring> +#include <map> -typedef struct -{ - size_t reflen; - size_t predlen; - size_t match1; - size_t count1; - size_t match2; - size_t count2; - size_t match3; - size_t count3; - size_t match4; - size_t count4; +// NOLINTNEXTLINE +typedef struct { + size_t reflen; + size_t predlen; + size_t match1; + size_t count1; + size_t match2; + size_t count2; + size_t match3; + size_t count3; + size_t match4; + size_t count4; } bleu_stat; // left trim (remove pad) void bleu_ltrim(size_t* len, int** sent, int pad) { size_t start = 0; - while(start < *len) { - if (*(*sent + start) != pad) { break; } + while (start < *len) { + if (*(*sent + start) != pad) { + break; + } start++; } *sent += start; @@ -40,7 +42,9 @@ void bleu_ltrim(size_t* len, int** sent, int pad) { void bleu_rtrim(size_t* len, int** sent, int pad, int eos) { size_t end = *len - 1; while (end > 0) { - if (*(*sent + end) != eos && *(*sent + end) != pad) { break; } + if (*(*sent + end) != eos && *(*sent + end) != pad) { + break; + } end--; } *len = end + 1; @@ -53,10 +57,10 @@ void bleu_trim(size_t* len, int** sent, int pad, int eos) { } size_t bleu_hash(int len, int* data) { - size_t h = 14695981039346656037ul; + size_t h = 14695981039346656037ul; size_t prime = 0x100000001b3; - char* b = (char*) data; - size_t blen = sizeof(int) * len; + char* b = (char*)data; + size_t blen = sizeof(int) * len; while (blen-- > 0) { h ^= *b++; @@ -67,15 +71,23 @@ size_t bleu_hash(int len, int* data) { } void bleu_addngram( - size_t *ntotal, size_t *nmatch, size_t n, - size_t reflen, int* ref, size_t predlen, int* pred) { - - if (predlen < n) { return; } + size_t* ntotal, + size_t* nmatch, + size_t n, + size_t reflen, + int* ref, + size_t predlen, + int* pred) { + if (predlen < n) { + return; + } predlen = predlen - n + 1; (*ntotal) += predlen; - if (reflen < n) { return; } + if (reflen < n) { + return; + } reflen = reflen - n + 1; @@ -90,7 +102,7 @@ void bleu_addngram( size_t w = bleu_hash(n, ref++); if (count[w] > 0) { (*nmatch)++; - count[w] -=1; + count[w] -= 1; } reflen--; } @@ -99,16 +111,16 @@ void bleu_addngram( extern "C" { #ifdef _WIN64 -__declspec(dllexport) +__declspec(dllexport) #endif -void bleu_zero_init(bleu_stat* stat) { + void bleu_zero_init(bleu_stat* stat) { std::memset(stat, 0, sizeof(bleu_stat)); } #ifdef _WIN64 -__declspec(dllexport) +__declspec(dllexport) #endif -void bleu_one_init(bleu_stat* stat) { + void bleu_one_init(bleu_stat* stat) { bleu_zero_init(stat); stat->count1 = 0; stat->count2 = 1; @@ -121,11 +133,16 @@ void bleu_one_init(bleu_stat* stat) { } #ifdef _WIN64 -__declspec(dllexport) +__declspec(dllexport) #endif -void bleu_add( - bleu_stat* stat, - size_t reflen, int* ref, size_t predlen, int* pred, int pad, int eos) { + void bleu_add( + bleu_stat* stat, + size_t reflen, + int* ref, + size_t predlen, + int* pred, + int pad, + int eos) { bleu_trim(&reflen, &ref, pad, eos); bleu_trim(&predlen, &pred, pad, eos); @@ -137,5 +154,4 @@ void bleu_add( bleu_addngram(&stat->count3, &stat->match3, 3, reflen, ref, predlen, pred); bleu_addngram(&stat->count4, &stat->match4, 4, reflen, ref, predlen, pred); } - } diff --git a/fairseq/clib/libbleu/module.cpp b/fairseq/clib/libbleu/module.cpp index 8ed9a84b1c..35288b3177 100644 --- a/fairseq/clib/libbleu/module.cpp +++ b/fairseq/clib/libbleu/module.cpp @@ -8,20 +8,16 @@ #include <Python.h> - -static PyMethodDef method_def[] = { - {NULL, NULL, 0, NULL} -}; +static PyMethodDef method_def[] = {{NULL, NULL, 0, NULL}}; // NOLINT static struct PyModuleDef module_def = { - PyModuleDef_HEAD_INIT, - "libbleu", /* name of module */ - NULL, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module, - or -1 if the module keeps state in global variables. */ - method_def -}; - + PyModuleDef_HEAD_INIT, + "libbleu", /* name of module */ + // NOLINTNEXTLINE + NULL, /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + method_def}; // NOLINT #if PY_MAJOR_VERSION == 2 PyMODINIT_FUNC init_libbleu() @@ -29,7 +25,7 @@ PyMODINIT_FUNC init_libbleu() PyMODINIT_FUNC PyInit_libbleu() #endif { - PyObject *m = PyModule_Create(&module_def); + PyObject* m = PyModule_Create(&module_def); if (!m) { return NULL; } diff --git a/fairseq/clib/libnat/edit_dist.cpp b/fairseq/clib/libnat/edit_dist.cpp index 6bc6a937d6..9ffb60569d 100644 --- a/fairseq/clib/libnat/edit_dist.cpp +++ b/fairseq/clib/libnat/edit_dist.cpp @@ -6,10 +6,9 @@ * LICENSE file in the root directory of this source tree. */ -#include <torch/torch.h> // @manual=//caffe2:torch_extension #include <pybind11/detail/common.h> #include <pybind11/pybind11.h> -#include <vector> +#include <torch/torch.h> // @manual=//caffe2:torch_extension #include <algorithm> #include <cstdint> #include <iosfwd> @@ -17,6 +16,7 @@ #include <new> #include <string> #include <utility> +#include <vector> using namespace ::std; diff --git a/fairseq/clib/libnat_cuda/binding.cpp b/fairseq/clib/libnat_cuda/binding.cpp index aaa6244d5c..ced91c0d0a 100644 --- a/fairseq/clib/libnat_cuda/binding.cpp +++ b/fairseq/clib/libnat_cuda/binding.cpp @@ -7,54 +7,61 @@ */ /* - This code is partially adpoted from https://github.com/1ytic/pytorch-edit-distance + This code is partially adpoted from + https://github.com/1ytic/pytorch-edit-distance */ -#include "edit_dist.h" #include <torch/types.h> +#include "edit_dist.h" #ifndef TORCH_CHECK #define TORCH_CHECK AT_CHECK #endif -#define CHECK_CUDA(x) TORCH_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") -#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") -#define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) - +#define CHECK_CUDA(x) \ + TORCH_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") +#define CHECK_CONTIGUOUS(x) \ + TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") +#define CHECK_INPUT(x) \ + CHECK_CUDA(x); \ + CHECK_CONTIGUOUS(x) torch::Tensor LevenshteinDistance( - torch::Tensor source, - torch::Tensor target, - torch::Tensor source_length, - torch::Tensor target_length) { - - CHECK_INPUT(source); - CHECK_INPUT(target); - CHECK_INPUT(source_length); - CHECK_INPUT(target_length); - return LevenshteinDistanceCuda(source, target, source_length, target_length); + torch::Tensor source, + torch::Tensor target, + torch::Tensor source_length, + torch::Tensor target_length) { + CHECK_INPUT(source); + CHECK_INPUT(target); + CHECK_INPUT(source_length); + CHECK_INPUT(target_length); + return LevenshteinDistanceCuda(source, target, source_length, target_length); } torch::Tensor GenerateDeletionLabel( - torch::Tensor source, - torch::Tensor operations) { - - CHECK_INPUT(source); - CHECK_INPUT(operations); - return GenerateDeletionLabelCuda(source, operations); + torch::Tensor source, + torch::Tensor operations) { + CHECK_INPUT(source); + CHECK_INPUT(operations); + return GenerateDeletionLabelCuda(source, operations); } std::pair<torch::Tensor, torch::Tensor> GenerateInsertionLabel( - torch::Tensor target, - torch::Tensor operations) { - - CHECK_INPUT(target); - CHECK_INPUT(operations); - return GenerateInsertionLabelCuda(target, operations); + torch::Tensor target, + torch::Tensor operations) { + CHECK_INPUT(target); + CHECK_INPUT(operations); + return GenerateInsertionLabelCuda(target, operations); } PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("levenshtein_distance", &LevenshteinDistance, "Levenshtein distance"); - m.def("generate_deletion_labels", &GenerateDeletionLabel, "Generate Deletion Label"); - m.def("generate_insertion_labels", &GenerateInsertionLabel, "Generate Insertion Label"); + m.def("levenshtein_distance", &LevenshteinDistance, "Levenshtein distance"); + m.def( + "generate_deletion_labels", + &GenerateDeletionLabel, + "Generate Deletion Label"); + m.def( + "generate_insertion_labels", + &GenerateInsertionLabel, + "Generate Insertion Label"); } diff --git a/fairseq/clib/libnat_cuda/edit_dist.cu b/fairseq/clib/libnat_cuda/edit_dist.cu index 22de16b270..96569d46c8 100644 --- a/fairseq/clib/libnat_cuda/edit_dist.cu +++ b/fairseq/clib/libnat_cuda/edit_dist.cu @@ -1,332 +1,344 @@ /** -* Copyright 2017-present, Facebook, Inc. -* All rights reserved. -* -* This source code is licensed under the license found in the -* LICENSE file in the root directory of this source tree. -*/ + * Copyright 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE file in the root directory of this source tree. + */ #include "edit_dist.h" + #include <THC/THC.h> #include <cuda.h> #include <cuda_runtime.h> #include <device_launch_parameters.h> -#include <utility> // std::pair +#include <utility> // std::pair template <typename scalar_t> __global__ void generate_deletion_label_kernel( - const scalar_t* __restrict__ source, - const size_t source_size, - const size_t operation_size, - int* __restrict__ operations, - int* __restrict__ labels) { - - const int index = blockIdx.x; - const int offset = index * operation_size; - const int offset_label = index * source_size; - - for (int i = 0; i < source_size; i++) { - labels[offset_label + i] = 0; - } - - int k = 0; - for (int i = 0; i < operation_size; i++){ - if (operations[offset + i] == 0){ - break; - } else if (operations[offset + i] == 1){ - continue; - } else { - labels[offset_label + k] = 3 - operations[offset + i]; - k++; - } + const scalar_t* __restrict__ source, + const size_t source_size, + const size_t operation_size, + int* __restrict__ operations, + int* __restrict__ labels) { + const int index = blockIdx.x; + const int offset = index * operation_size; + const int offset_label = index * source_size; + + for (int i = 0; i < source_size; i++) { + labels[offset_label + i] = 0; + } + + int k = 0; + for (int i = 0; i < operation_size; i++) { + if (operations[offset + i] == 0) { + break; + } else if (operations[offset + i] == 1) { + continue; + } else { + labels[offset_label + k] = 3 - operations[offset + i]; + k++; } + } } template <typename scalar_t> __global__ void generate_insertion_label_kernel( - const scalar_t* __restrict__ target, - const size_t target_size, - const size_t operation_size, - int* __restrict__ operations, - int* __restrict__ labels, - int* __restrict__ masks) { - - const int index = blockIdx.x; - const int offset = index * operation_size; - const int offset_label = index * target_size; - - int k = 0; - int u = 0; - int m = 0; - - for (int i = 0; i < target_size; i++) { - labels[offset_label + i] = 0; - masks[offset_label + i] = 0; - } - - for (int i = 0; i < operation_size-1; i++){ - if (operations[offset + i] == 0){ - break; - } else if (operations[offset + i] == 2){ - continue; - } else if (operations[offset + i] == 1){ - masks[offset_label + m] = 1; - u++; m++; - } else { - labels[offset_label + k] = u; - masks[offset_label + m] = 0; - k++; m++; - u = 0; - } + const scalar_t* __restrict__ target, + const size_t target_size, + const size_t operation_size, + int* __restrict__ operations, + int* __restrict__ labels, + int* __restrict__ masks) { + const int index = blockIdx.x; + const int offset = index * operation_size; + const int offset_label = index * target_size; + + int k = 0; + int u = 0; + int m = 0; + + for (int i = 0; i < target_size; i++) { + labels[offset_label + i] = 0; + masks[offset_label + i] = 0; + } + + for (int i = 0; i < operation_size - 1; i++) { + if (operations[offset + i] == 0) { + break; + } else if (operations[offset + i] == 2) { + continue; + } else if (operations[offset + i] == 1) { + masks[offset_label + m] = 1; + u++; + m++; + } else { + labels[offset_label + k] = u; + masks[offset_label + m] = 0; + k++; + m++; + u = 0; } + } } template <typename scalar_t> __global__ void levenshtein_distance_kernel( - const scalar_t* __restrict__ source, - const scalar_t* __restrict__ target, - const int* __restrict__ source_length, - const int* __restrict__ target_length, - const size_t source_size, - const size_t target_size, - int* __restrict__ operations, - int* __restrict__ errors_curr) { - - const int index = blockIdx.x; - const int offset = index * (source_size + target_size); - const int d = index * (source_size + 1) * (target_size + 1); - const int t = target_size + 1; - - auto err_idx = [d, t](int i, int j) { return d + i * t + j; }; - auto opt_idx = [offset](int k) { return offset + k; }; - - const int hyp_len = source_length[index]; - const int ref_len = target_length[index]; - const scalar_t* hyp_begin = source + index * source_size; - const scalar_t* ref_begin = target + index * target_size; - - // dynamic programming - for (int i = 0; i <= hyp_len; i++){ - errors_curr[err_idx(i, 0)] = i; - } - for (int j = 0; j <= ref_len; j++){ - errors_curr[err_idx(0, j)] = j; - } - for (int i = 1; i <= hyp_len; i++){ - for (int j = 1; j <= ref_len; j++){ - errors_curr[err_idx(i, j)] = min( - min( - errors_curr[err_idx(i-1, j)], - errors_curr[err_idx(i, j-1)] - ) + 1, - errors_curr[err_idx(i-1, j-1)] + 2 * ( - *(hyp_begin+i-1) == *(ref_begin+j-1) ? 0 : 1 - ) - ); - } + const scalar_t* __restrict__ source, + const scalar_t* __restrict__ target, + const int* __restrict__ source_length, + const int* __restrict__ target_length, + const size_t source_size, + const size_t target_size, + int* __restrict__ operations, + int* __restrict__ errors_curr) { + const int index = blockIdx.x; + const int offset = index * (source_size + target_size); + const int d = index * (source_size + 1) * (target_size + 1); + const int t = target_size + 1; + + auto err_idx = [d, t](int i, int j) { return d + i * t + j; }; + auto opt_idx = [offset](int k) { return offset + k; }; + + const int hyp_len = source_length[index]; + const int ref_len = target_length[index]; + const scalar_t* hyp_begin = source + index * source_size; + const scalar_t* ref_begin = target + index * target_size; + + // dynamic programming + for (int i = 0; i <= hyp_len; i++) { + errors_curr[err_idx(i, 0)] = i; + } + for (int j = 0; j <= ref_len; j++) { + errors_curr[err_idx(0, j)] = j; + } + for (int i = 1; i <= hyp_len; i++) { + for (int j = 1; j <= ref_len; j++) { + errors_curr[err_idx(i, j)] = min( + min(errors_curr[err_idx(i - 1, j)], errors_curr[err_idx(i, j - 1)]) + + 1, + errors_curr[err_idx(i - 1, j - 1)] + + 2 * (*(hyp_begin + i - 1) == *(ref_begin + j - 1) ? 0 : 1)); } + } - // back-tracing - int i = hyp_len; - int j = ref_len; - int o = hyp_len + ref_len; + // back-tracing + int i = hyp_len; + int j = ref_len; + int o = hyp_len + ref_len; - for (int k = 0; k < source_size + target_size; k++) { - operations[opt_idx(k)] = 0; - } + for (int k = 0; k < source_size + target_size; k++) { + operations[opt_idx(k)] = 0; + } - while ((i >= 0) && (j >= 0)) { - if ((i == 0) && (j == 0)) { - break; - } - - if ((j > 0) && (errors_curr[err_idx(i, j-1)] < errors_curr[err_idx(i, j)])) { - o--; operations[opt_idx(o)] = 1; j--; // insertion - } else if ((i > 0) && (errors_curr[err_idx(i-1, j)] < errors_curr[err_idx(i, j)])) { - o--; operations[opt_idx(o)] = 2; i--; // deletion - } else { - o--; operations[opt_idx(o)] = 3; i--; j--; // do nothing - } + while ((i >= 0) && (j >= 0)) { + if ((i == 0) && (j == 0)) { + break; } - // moving to the left - for (int k = 0; k < hyp_len + ref_len; k++) { - if (k + o < hyp_len + ref_len){ - operations[opt_idx(k)] = operations[opt_idx(k+o)]; - } else{ - operations[opt_idx(k)] = 0; // padding - } + if ((j > 0) && + (errors_curr[err_idx(i, j - 1)] < errors_curr[err_idx(i, j)])) { + o--; + operations[opt_idx(o)] = 1; + j--; // insertion + } else if ( + (i > 0) && + (errors_curr[err_idx(i - 1, j)] < errors_curr[err_idx(i, j)])) { + o--; + operations[opt_idx(o)] = 2; + i--; // deletion + } else { + o--; + operations[opt_idx(o)] = 3; + i--; + j--; // do nothing } + } + // moving to the left + for (int k = 0; k < hyp_len + ref_len; k++) { + if (k + o < hyp_len + ref_len) { + operations[opt_idx(k)] = operations[opt_idx(k + o)]; + } else { + operations[opt_idx(k)] = 0; // padding + } + } } template <typename scalar_t> __global__ void faster_levenshtein_distance_kernel( - const scalar_t* __restrict__ source, - const scalar_t* __restrict__ target, - const int* __restrict__ source_length, - const int* __restrict__ target_length, - const size_t source_size, - const size_t target_size, - int* __restrict__ operations) { - - extern __shared__ short errors[]; - auto errors_curr = errors; - - const int index = blockIdx.x; - const int offset = index * (source_size + target_size); - const int t = target_size + 1; - - auto err_idx = [t](int i, int j) { return i * t + j; }; - auto opt_idx = [offset](int k) { return offset + k; }; - - const int hyp_len = source_length[index]; - const int ref_len = target_length[index]; - const scalar_t* hyp_begin = source + index * source_size; - const scalar_t* ref_begin = target + index * target_size; - - // dynamic programming - for (int i = 0; i <= hyp_len; i++){ - errors_curr[err_idx(i, 0)] = i; - } - for (int j = 0; j <= ref_len; j++){ - errors_curr[err_idx(0, j)] = j; - } - for (int i = 1; i <= hyp_len; i++){ - for (int j = 1; j <= ref_len; j++){ - errors_curr[err_idx(i, j)] = min( - min( - errors_curr[err_idx(i-1, j)], - errors_curr[err_idx(i, j-1)] - ) + 1, - errors_curr[err_idx(i-1, j-1)] + 2 * ( - *(hyp_begin+i-1) == *(ref_begin+j-1) ? 0 : 1 - ) - ); - } + const scalar_t* __restrict__ source, + const scalar_t* __restrict__ target, + const int* __restrict__ source_length, + const int* __restrict__ target_length, + const size_t source_size, + const size_t target_size, + int* __restrict__ operations) { + extern __shared__ short errors[]; + auto errors_curr = errors; + + const int index = blockIdx.x; + const int offset = index * (source_size + target_size); + const int t = target_size + 1; + + auto err_idx = [t](int i, int j) { return i * t + j; }; + auto opt_idx = [offset](int k) { return offset + k; }; + + const int hyp_len = source_length[index]; + const int ref_len = target_length[index]; + const scalar_t* hyp_begin = source + index * source_size; + const scalar_t* ref_begin = target + index * target_size; + + // dynamic programming + for (int i = 0; i <= hyp_len; i++) { + errors_curr[err_idx(i, 0)] = i; + } + for (int j = 0; j <= ref_len; j++) { + errors_curr[err_idx(0, j)] = j; + } + for (int i = 1; i <= hyp_len; i++) { + for (int j = 1; j <= ref_len; j++) { + errors_curr[err_idx(i, j)] = min( + min(errors_curr[err_idx(i - 1, j)], errors_curr[err_idx(i, j - 1)]) + + 1, + errors_curr[err_idx(i - 1, j - 1)] + + 2 * (*(hyp_begin + i - 1) == *(ref_begin + j - 1) ? 0 : 1)); } + } - // back-tracing - int i = hyp_len; - int j = ref_len; - int o = hyp_len + ref_len; + // back-tracing + int i = hyp_len; + int j = ref_len; + int o = hyp_len + ref_len; - for (int k = 0; k < source_size + target_size; k++) { - operations[opt_idx(k)] = 0; - } + for (int k = 0; k < source_size + target_size; k++) { + operations[opt_idx(k)] = 0; + } - while ((i >= 0) && (j >= 0)) { - if ((i == 0) && (j == 0)) { - break; - } - - if ((j > 0) && (errors_curr[err_idx(i, j-1)] < errors_curr[err_idx(i, j)])) { - o--; operations[opt_idx(o)] = 1; j--; // insertion - } else if ((i > 0) && (errors_curr[err_idx(i-1, j)] < errors_curr[err_idx(i, j)])) { - o--; operations[opt_idx(o)] = 2; i--; // deletion - } else { - o--; operations[opt_idx(o)] = 3; i--; j--; // do nothing - } + while ((i >= 0) && (j >= 0)) { + if ((i == 0) && (j == 0)) { + break; } - // moving to the left - for (int k = 0; k < hyp_len + ref_len; k++) { - if (k + o < hyp_len + ref_len){ - operations[opt_idx(k)] = operations[opt_idx(k+o)]; - } else{ - operations[opt_idx(k)] = 0; // padding - } + if ((j > 0) && + (errors_curr[err_idx(i, j - 1)] < errors_curr[err_idx(i, j)])) { + o--; + operations[opt_idx(o)] = 1; + j--; // insertion + } else if ( + (i > 0) && + (errors_curr[err_idx(i - 1, j)] < errors_curr[err_idx(i, j)])) { + o--; + operations[opt_idx(o)] = 2; + i--; // deletion + } else { + o--; + operations[opt_idx(o)] = 3; + i--; + j--; // do nothing } + } + // moving to the left + for (int k = 0; k < hyp_len + ref_len; k++) { + if (k + o < hyp_len + ref_len) { + operations[opt_idx(k)] = operations[opt_idx(k + o)]; + } else { + operations[opt_idx(k)] = 0; // padding + } + } } - torch::Tensor GenerateDeletionLabelCuda( - torch::Tensor source, - torch::Tensor operations) { - - const auto batch_size = source.size(0); - at::TensorOptions options(source.device()); - options = options.dtype(at::ScalarType::Int); - auto labels = torch::empty({batch_size, source.size(1)}, options); - auto stream = at::cuda::getCurrentCUDAStream(source.device().index()); - - AT_DISPATCH_ALL_TYPES(source.scalar_type(), "generate_deletion_labels", ([&] { - generate_deletion_label_kernel<scalar_t><<<batch_size, 1, 0, stream>>>( - source.data_ptr<scalar_t>(), - source.size(1), - operations.size(1), - operations.data_ptr<int>(), - labels.data_ptr<int>()); - })); - - return labels; + torch::Tensor source, + torch::Tensor operations) { + const auto batch_size = source.size(0); + at::TensorOptions options(source.device()); + options = options.dtype(at::ScalarType::Int); + auto labels = torch::empty({batch_size, source.size(1)}, options); + auto stream = at::cuda::getCurrentCUDAStream(source.device().index()); + + AT_DISPATCH_ALL_TYPES(source.scalar_type(), "generate_deletion_labels", ([&] { + generate_deletion_label_kernel<scalar_t> + <<<batch_size, 1, 0, stream>>>( + source.data_ptr<scalar_t>(), + source.size(1), + operations.size(1), + operations.data_ptr<int>(), + labels.data_ptr<int>()); + })); + + return labels; } std::pair<torch::Tensor, torch::Tensor> GenerateInsertionLabelCuda( torch::Tensor target, torch::Tensor operations) { + const auto batch_size = target.size(0); + at::TensorOptions options(target.device()); + options = options.dtype(at::ScalarType::Int); + auto labels = torch::empty({batch_size, target.size(1)}, options); + auto masks = torch::empty({batch_size, target.size(1)}, options); + auto stream = at::cuda::getCurrentCUDAStream(target.device().index()); + + AT_DISPATCH_ALL_TYPES( + target.scalar_type(), "generate_insertion_labels", ([&] { + generate_insertion_label_kernel<scalar_t><<<batch_size, 1, 0, stream>>>( + target.data_ptr<scalar_t>(), + target.size(1), + operations.size(1), + operations.data_ptr<int>(), + labels.data_ptr<int>(), + masks.data_ptr<int>()); + })); -const auto batch_size = target.size(0); -at::TensorOptions options(target.device()); -options = options.dtype(at::ScalarType::Int); -auto labels = torch::empty({batch_size, target.size(1)}, options); -auto masks = torch::empty({batch_size, target.size(1)}, options); -auto stream = at::cuda::getCurrentCUDAStream(target.device().index()); - -AT_DISPATCH_ALL_TYPES(target.scalar_type(), "generate_insertion_labels", ([&] { - generate_insertion_label_kernel<scalar_t><<<batch_size, 1, 0, stream>>>( - target.data_ptr<scalar_t>(), - target.size(1), - operations.size(1), - operations.data_ptr<int>(), - labels.data_ptr<int>(), - masks.data_ptr<int>()); -})); - -return std::make_pair(labels, masks); + return std::make_pair(labels, masks); } - torch::Tensor LevenshteinDistanceCuda( - torch::Tensor source, - torch::Tensor target, - torch::Tensor source_length, - torch::Tensor target_length) { - - const auto batch_size = source.size(0); - const auto shared_size = (source.size(1) + 1) * (target.size(1) + 1) * sizeof(short); - - at::TensorOptions options(source.device()); - options = options.dtype(at::ScalarType::Int); - auto operations = torch::empty({batch_size, source.size(1) + target.size(1)}, options); - auto stream = at::cuda::getCurrentCUDAStream(source.device().index()); - - if (shared_size > 40000) { - auto distances = torch::empty({batch_size, (source.size(1) + 1) * (target.size(1) + 1)}, options); - AT_DISPATCH_ALL_TYPES(source.scalar_type(), "levenshtein_distance", ([&] { - levenshtein_distance_kernel<scalar_t><<<batch_size, 1, 0, stream>>>( - source.data_ptr<scalar_t>(), - target.data_ptr<scalar_t>(), - source_length.data_ptr<int>(), - target_length.data_ptr<int>(), - source.size(1), - target.size(1), - operations.data_ptr<int>(), - distances.data_ptr<int>()); - })); - } else { - AT_DISPATCH_ALL_TYPES(source.scalar_type(), "faster_levenshtein_distance", ([&] { - faster_levenshtein_distance_kernel<scalar_t><<<batch_size, 1, shared_size, stream>>>( - source.data_ptr<scalar_t>(), - target.data_ptr<scalar_t>(), - source_length.data_ptr<int>(), - target_length.data_ptr<int>(), - source.size(1), - target.size(1), - operations.data_ptr<int>()); + torch::Tensor source, + torch::Tensor target, + torch::Tensor source_length, + torch::Tensor target_length) { + const auto batch_size = source.size(0); + const auto shared_size = + (source.size(1) + 1) * (target.size(1) + 1) * sizeof(short); + + at::TensorOptions options(source.device()); + options = options.dtype(at::ScalarType::Int); + auto operations = + torch::empty({batch_size, source.size(1) + target.size(1)}, options); + auto stream = at::cuda::getCurrentCUDAStream(source.device().index()); + + if (shared_size > 40000) { + auto distances = torch::empty( + {batch_size, (source.size(1) + 1) * (target.size(1) + 1)}, options); + AT_DISPATCH_ALL_TYPES(source.scalar_type(), "levenshtein_distance", ([&] { + levenshtein_distance_kernel<scalar_t> + <<<batch_size, 1, 0, stream>>>( + source.data_ptr<scalar_t>(), + target.data_ptr<scalar_t>(), + source_length.data_ptr<int>(), + target_length.data_ptr<int>(), + source.size(1), + target.size(1), + operations.data_ptr<int>(), + distances.data_ptr<int>()); + })); + } else { + AT_DISPATCH_ALL_TYPES( + source.scalar_type(), "faster_levenshtein_distance", ([&] { + faster_levenshtein_distance_kernel<scalar_t> + <<<batch_size, 1, shared_size, stream>>>( + source.data_ptr<scalar_t>(), + target.data_ptr<scalar_t>(), + source_length.data_ptr<int>(), + target_length.data_ptr<int>(), + source.size(1), + target.size(1), + operations.data_ptr<int>()); })); - } + } - return operations; + return operations; } diff --git a/fairseq/clib/libnat_cuda/edit_dist.h b/fairseq/clib/libnat_cuda/edit_dist.h index e3506cd34d..5220c52fd8 100644 --- a/fairseq/clib/libnat_cuda/edit_dist.h +++ b/fairseq/clib/libnat_cuda/edit_dist.h @@ -11,15 +11,15 @@ #include <torch/extension.h> torch::Tensor LevenshteinDistanceCuda( - torch::Tensor source, - torch::Tensor target, - torch::Tensor source_length, - torch::Tensor target_length); + torch::Tensor source, + torch::Tensor target, + torch::Tensor source_length, + torch::Tensor target_length); torch::Tensor GenerateDeletionLabelCuda( - torch::Tensor source, - torch::Tensor operations); + torch::Tensor source, + torch::Tensor operations); std::pair<torch::Tensor, torch::Tensor> GenerateInsertionLabelCuda( - torch::Tensor source, - torch::Tensor operations); + torch::Tensor source, + torch::Tensor operations); diff --git a/fairseq/modules/cuda_utils.cu b/fairseq/modules/cuda_utils.cu index 516f1d9244..924f852758 100644 --- a/fairseq/modules/cuda_utils.cu +++ b/fairseq/modules/cuda_utils.cu @@ -1,20 +1,17 @@ /** * Copyright (c) Facebook, Inc. and its affiliates. - * + * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ - -template <typename U, typename V> -constexpr __host__ __device__ auto divUp(U a, V b) -> decltype(a + b) { - return (a + b - 1) / b; +template <typename U, typename V> +constexpr __host__ __device__ auto divUp(U a, V b) -> decltype(a + b) { + return (a + b - 1) / b; } - -template<int FS, int SB, int padding_l, typename scalar_t> -__inline__ __device__ -void zeroSharedMem(scalar_t* data) { +template <int FS, int SB, int padding_l, typename scalar_t> +__inline__ __device__ void zeroSharedMem(scalar_t* data) { /* Given an array of length FS + SB, zero out the first padding_l and last (FS - padding_l) values in the array @@ -23,13 +20,11 @@ void zeroSharedMem(scalar_t* data) { int tid = threadIdx.x; if (FS < SB) { - // zero all if we have enough threads in a block to do all of them if (tid < padding_l || tid > SB - FS + padding_l - 1) { data[tid] = scalar_t(0.0); } } else { - // otherwise zero out one block at a time const int numIterations = divUp<int, int>(FS, SB); for (int i = 0; i < numIterations; i++) { @@ -43,9 +38,8 @@ void zeroSharedMem(scalar_t* data) { } } -template<typename scalar_t> -__inline__ __device__ -scalar_t warpReduce(scalar_t data) { +template <typename scalar_t> +__inline__ __device__ scalar_t warpReduce(scalar_t data) { /* Reduce an array within each warp. After processing all values in warp will caontain the sum of all original values in that warp. @@ -60,9 +54,8 @@ scalar_t warpReduce(scalar_t data) { return data; } -template<typename scalar_t> -__inline__ __device__ -scalar_t blockReduce(scalar_t data) { +template <typename scalar_t> +__inline__ __device__ scalar_t blockReduce(scalar_t data) { /* Reduce an entire array on the block level. After processing, the first value in the array will contain the reduced sum. @@ -82,7 +75,7 @@ scalar_t blockReduce(scalar_t data) { if (lane == 0) { warpSum[wid] = sum; } - + __syncthreads(); scalar_t v; @@ -102,21 +95,23 @@ scalar_t blockReduce(scalar_t data) { } void checkCudaStatus(cudaError_t status, int lineNumber = -1) { - if (status != cudaSuccess) { - std::cout << cudaGetErrorString(status) - << " at line " << lineNumber << std::endl; + std::cout << cudaGetErrorString(status) << " at line " << lineNumber + << std::endl; std::cout << "Exiting" << std::endl; exit(1); } } -template<int FS, int SB, int padding_l, typename scalar_t> -__device__ -void load_input_to_shared(const scalar_t* input, // global memory - int inputOffset, int sequenceLength, - int iteration, int numIterations, - bool no_prev, scalar_t* output /* shared memory */) { +template <int FS, int SB, int padding_l, typename scalar_t> +__device__ void load_input_to_shared( + const scalar_t* input, // global memory + int inputOffset, + int sequenceLength, + int iteration, + int numIterations, + bool no_prev, + scalar_t* output /* shared memory */) { /* Load a block size of input into shared memory with right and left overhang of total size FS. If previously @@ -138,19 +133,20 @@ void load_input_to_shared(const scalar_t* input, // global memory // Load the left "overhang" of input if (iteration > 0) { if (padding_l < SB) { - // load all at once if (tid < padding_l) { - output[tid] = (no_prev) ? input[inputOffset - padding_l + tid] : output[tid + SB]; + output[tid] = + (no_prev) ? input[inputOffset - padding_l + tid] : output[tid + SB]; } } else { - // load in chunks of size SB int numIterations = divUp<int, int>(padding_l, SB); for (int i = 0; i < numIterations; i++) { int offset = i * SB; if ((tid + offset) < padding_l) { - output[tid + offset] = (no_prev) ? input[inputOffset - padding_l + tid + offset] : output[tid + offset + SB]; + output[tid + offset] = (no_prev) + ? input[inputOffset - padding_l + tid + offset] + : output[tid + offset + SB]; } } } @@ -158,22 +154,25 @@ void load_input_to_shared(const scalar_t* input, // global memory // Load the right "overhang" of input if (iteration < (numIterations - 1)) { - const int elementsLeft = sequenceLength - (iteration+1) * SB; + const int elementsLeft = sequenceLength - (iteration + 1) * SB; if ((FS - padding_l) < SB) { - // load all at once if (tid < (FS - padding_l)) { - output[padding_l + SB + tid] = (tid < elementsLeft) ? input[inputOffset + SB + tid] : scalar_t(0.0); + output[padding_l + SB + tid] = (tid < elementsLeft) + ? input[inputOffset + SB + tid] + : scalar_t(0.0); } } else { - // load in chunks of size SB int numIterations = divUp<int, int>(FS - padding_l, SB); for (int i = 0; i < numIterations; i++) { int offset = i * SB; if ((tid + offset) < (FS - padding_l)) { - output[padding_l + SB + tid + offset] = ((tid + offset) < elementsLeft) ? input[inputOffset + SB + tid + offset] : scalar_t(0.0); + output[padding_l + SB + tid + offset] = + ((tid + offset) < elementsLeft) + ? input[inputOffset + SB + tid + offset] + : scalar_t(0.0); } } } @@ -182,13 +181,11 @@ void load_input_to_shared(const scalar_t* input, // global memory // We should also clear out the right "overhang" if (iteration == (numIterations - 1)) { if ((FS - padding_l) < SB) { - // clear out all at once if (tid < (FS - padding_l)) { - output[padding_l + SB + tid] = scalar_t(0.0); + output[padding_l + SB + tid] = scalar_t(0.0); } } else { - // clear in chunks of size SB int numIterations = divUp<int, int>(FS - padding_l, SB); for (int i = 0; i < numIterations; i++) { @@ -199,5 +196,7 @@ void load_input_to_shared(const scalar_t* input, // global memory } } } - output[tid + padding_l] = ((inputOffset + tid) < sequenceLength) ? input[inputOffset + tid] : scalar_t(0.0); + output[tid + padding_l] = ((inputOffset + tid) < sequenceLength) + ? input[inputOffset + tid] + : scalar_t(0.0); } diff --git a/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cpp b/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cpp index ebd4df0e96..744c363e55 100644 --- a/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cpp +++ b/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cpp @@ -8,10 +8,8 @@ #include <torch/extension.h> #include <vector> -std::vector<at::Tensor> dynamicconv_cuda_forward( - at::Tensor input, - at::Tensor filters, - int padding_l); +std::vector<at::Tensor> +dynamicconv_cuda_forward(at::Tensor input, at::Tensor filters, int padding_l); std::vector<at::Tensor> dynamicconv_cuda_backward( at::Tensor gradOutput, @@ -19,21 +17,20 @@ std::vector<at::Tensor> dynamicconv_cuda_backward( at::Tensor input, at::Tensor filters); +#define CHECK_CUDA(x) \ + AT_ASSERTM(x.type().is_cuda(), #x " must be a CUDA tensor") +#define CHECK_CONTIGUOUS(x) \ + AT_ASSERTM(x.is_contiguous(), #x " must be contiguous") +#define CHECK_INPUT(x) \ + CHECK_CUDA(x); \ + CHECK_CONTIGUOUS(x) -#define CHECK_CUDA(x) AT_ASSERTM(x.type().is_cuda(), #x " must be a CUDA tensor") -#define CHECK_CONTIGUOUS(x) AT_ASSERTM(x.is_contiguous(), #x " must be contiguous") -#define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) - -std::vector<at::Tensor> dynamicconv_forward( - at::Tensor input, - at::Tensor filters, - int padding_l) { +std::vector<at::Tensor> +dynamicconv_forward(at::Tensor input, at::Tensor filters, int padding_l) { + CHECK_INPUT(input); + CHECK_INPUT(filters); - CHECK_INPUT(input); - CHECK_INPUT(filters); - - return dynamicconv_cuda_forward(input, filters, - padding_l); + return dynamicconv_cuda_forward(input, filters, padding_l); } std::vector<at::Tensor> dynamicconv_backward( @@ -41,16 +38,14 @@ std::vector<at::Tensor> dynamicconv_backward( int padding_l, at::Tensor input, at::Tensor filters) { + CHECK_INPUT(gradOutput); + CHECK_INPUT(input); + CHECK_INPUT(filters); - CHECK_INPUT(gradOutput); - CHECK_INPUT(input); - CHECK_INPUT(filters); - - return dynamicconv_cuda_backward(gradOutput, padding_l, - input, filters); + return dynamicconv_cuda_backward(gradOutput, padding_l, input, filters); } PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("forward", &dynamicconv_forward, "dynamicconv forward (CUDA)"); - m.def("backward", &dynamicconv_backward, "dynamicconv backward (CUDA)"); + m.def("forward", &dynamicconv_forward, "dynamicconv forward (CUDA)"); + m.def("backward", &dynamicconv_backward, "dynamicconv backward (CUDA)"); } diff --git a/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cuh b/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cuh index 2196259433..44baf21bdd 100644 --- a/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cuh +++ b/fairseq/modules/dynamicconv_layer/dynamicconv_cuda.cuh @@ -1,6 +1,6 @@ /** * Copyright (c) Facebook, Inc. and its affiliates. - * + * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ @@ -19,26 +19,25 @@ #include <utility> #include <vector> -#include <stdlib.h> #include <assert.h> #include <math.h> +#include <stdlib.h> #define SHFL_MASK 0xffffffff -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void dynamicconv_forward_kernel(const scalar_t* input, - const scalar_t* weight, - int minibatch, - int sequenceLength, - int numFeatures, - int numFiltersInBlock, - int numHeads, - scalar_t* output); +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void dynamicconv_forward_kernel( + const scalar_t* input, + const scalar_t* weight, + int minibatch, + int sequenceLength, + int numFeatures, + int numFiltersInBlock, + int numHeads, + scalar_t* output); -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void dynamicconv_backward_kernel( +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void dynamicconv_backward_kernel( const scalar_t* gradOutput, // B * C * T const scalar_t* input, // B * C * T const scalar_t* weight, diff --git a/fairseq/modules/dynamicconv_layer/dynamicconv_cuda_kernel.cu b/fairseq/modules/dynamicconv_layer/dynamicconv_cuda_kernel.cu index 300d35b647..4630f1e982 100644 --- a/fairseq/modules/dynamicconv_layer/dynamicconv_cuda_kernel.cu +++ b/fairseq/modules/dynamicconv_layer/dynamicconv_cuda_kernel.cu @@ -1,26 +1,26 @@ /** * Copyright (c) Facebook, Inc. and its affiliates. - * + * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ +#include "../cuda_utils.cu" #include "dynamicconv_cuda.cuh" -#include "dynamicconv_cuda_forward.cu" #include "dynamicconv_cuda_backward.cu" -#include "../cuda_utils.cu" +#include "dynamicconv_cuda_forward.cu" // FS is filter size and kernels are specialized for filter sizes -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void dynamicconv_forward_kernel(const scalar_t* input, - const scalar_t* weight, - int minibatch, - int sequenceLength, - int numFeatures, - int numFiltersInBlock, - int numHeads, - scalar_t* output) { +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void dynamicconv_forward_kernel( + const scalar_t* input, + const scalar_t* weight, + int minibatch, + int sequenceLength, + int numFeatures, + int numFiltersInBlock, + int numHeads, + scalar_t* output) { assert(blockDim.x == SB); const int tid = threadIdx.x; @@ -28,8 +28,8 @@ void dynamicconv_forward_kernel(const scalar_t* input, const int featureIdx = blockIdx.y; const int head = featureIdx / numFiltersInBlock; - const int IOOffset = batchIdx * numFeatures * sequenceLength - + featureIdx * sequenceLength; + const int IOOffset = + batchIdx * numFeatures * sequenceLength + featureIdx * sequenceLength; const scalar_t* inputFeature = &input[IOOffset]; scalar_t* outputFeature = &output[IOOffset]; @@ -43,36 +43,36 @@ void dynamicconv_forward_kernel(const scalar_t* input, for (int i = 0; i < numIterations; ++i) { __syncthreads(); const int inputOffset = i * SB; - load_input_to_shared<FS, SB, padding_l>(inputFeature, inputOffset, - sequenceLength, i, - numIterations, false, tempInput); + load_input_to_shared<FS, SB, padding_l>( + inputFeature, + inputOffset, + sequenceLength, + i, + numIterations, + false, + tempInput); __syncthreads(); if (inputOffset + tid < sequenceLength) { - - #pragma unroll +#pragma unroll for (int k = 0; k < FS; ++k) { - const int filterOffset = batchIdx * numHeads * FS * sequenceLength - + head * FS * sequenceLength - + k * sequenceLength - + i * SB + tid; + const int filterOffset = batchIdx * numHeads * FS * sequenceLength + + head * FS * sequenceLength + k * sequenceLength + i * SB + tid; filter[k] = weight[filterOffset]; } scalar_t out = scalar_t(0.0); - #pragma unroll +#pragma unroll for (int k = 0; k < FS; ++k) { out += filter[k] * tempInput[tid + k]; } outputFeature[inputOffset + tid] = out; - } } } -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void dynamicconv_backward_kernel( +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void dynamicconv_backward_kernel( const scalar_t* gradOutput, // B * C * T const scalar_t* input, // B * C * T const scalar_t* weight, @@ -111,52 +111,60 @@ void dynamicconv_backward_kernel( int idxOffset = inputOffset + tid + k - padding; if (idxOffset >= 0 && idxOffset < sequenceLength) { - int bfilterOffset = batchIdx * numHeads * FS * sequenceLength - + headIdx * FS * sequenceLength - + (FS - k - 1) * sequenceLength - + idxOffset; + int bfilterOffset = batchIdx * numHeads * FS * sequenceLength + + headIdx * FS * sequenceLength + (FS - k - 1) * sequenceLength + + idxOffset; bfilter[k] = weight[bfilterOffset]; } else { bfilter[k] = scalar_t(0.0); } } - // iterate over filter block for (int featureIdx = 0; featureIdx < numFiltersInBlock; ++featureIdx) { __syncthreads(); // load input and output gradient for this channel and chunk - const int IOOffset = batchIdx * numFeatures * sequenceLength - + (headIdx * numFiltersInBlock + featureIdx) * sequenceLength; + const int IOOffset = batchIdx * numFeatures * sequenceLength + + (headIdx * numFiltersInBlock + featureIdx) * sequenceLength; const scalar_t* inputFeature = &input[IOOffset]; const scalar_t* gradOutputFeature = &gradOutput[IOOffset]; scalar_t* gradInputFeature = &gradInput[IOOffset]; - load_input_to_shared<FS, SB, padding>(gradOutputFeature, inputOffset, - sequenceLength, chunkIdx, - numChunks, true, tempGradOutput); - load_input_to_shared<FS, SB, padding_l>(inputFeature, inputOffset, - sequenceLength, chunkIdx, - numChunks, true, tempInput); + load_input_to_shared<FS, SB, padding>( + gradOutputFeature, + inputOffset, + sequenceLength, + chunkIdx, + numChunks, + true, + tempGradOutput); + load_input_to_shared<FS, SB, padding_l>( + inputFeature, + inputOffset, + sequenceLength, + chunkIdx, + numChunks, + true, + tempInput); __syncthreads(); - + // sum input and weight gradients scalar_t out = scalar_t(0.0); - #pragma unroll +#pragma unroll for (int k = 0; k < FS; ++k) { tempGradSum[k] += tempInput[tid + k] * tempGradOutput[tid + padding]; out += bfilter[k] * tempGradOutput[tid + k]; } - + if (inputOffset + tid < sequenceLength) { gradInputFeature[inputOffset + tid] = out; } } - const int gradOffset = batchIdx * numHeads * FS * sequenceLength - + headIdx * FS * sequenceLength; - scalar_t *gradWeightFeature = &gradWeight[gradOffset]; + const int gradOffset = + batchIdx * numHeads * FS * sequenceLength + headIdx * FS * sequenceLength; + scalar_t* gradWeightFeature = &gradWeight[gradOffset]; // write weight gradient if (inputOffset + tid < sequenceLength) { diff --git a/fairseq/modules/dynamicconv_layer/dynamiconv_cpu.cpp b/fairseq/modules/dynamicconv_layer/dynamiconv_cpu.cpp index 8a6af4285d..d7e57c8590 100644 --- a/fairseq/modules/dynamicconv_layer/dynamiconv_cpu.cpp +++ b/fairseq/modules/dynamicconv_layer/dynamiconv_cpu.cpp @@ -1,10 +1,8 @@ #include <torch/torch.h> #include <vector> -std::vector<float*> dynamicconv_cpu_forward( - float* input, - float* filters, - int padding_l); +std::vector<float*> +dynamicconv_cpu_forward(float* input, float* filters, int padding_l); std::vector<float*> dynamicconv_cpu_backward( float* gradOutput, @@ -12,12 +10,9 @@ std::vector<float*> dynamicconv_cpu_backward( float* input, float* filters); -std::vector<float*> dynamicconv_forward( - float* input, - float* filters, - int padding_l) { - - return dynamicconv_cpu_forward(input, filters, padding_l); +std::vector<float*> +dynamicconv_forward(float* input, float* filters, int padding_l) { + return dynamicconv_cpu_forward(input, filters, padding_l); } std::vector<float*> dynamicconv_backward( @@ -25,11 +20,10 @@ std::vector<float*> dynamicconv_backward( int padding_l, float* input, float* filters) { - - return dynamicconv_cpu_backward(gradOutput, padding_l, input, filters); + return dynamicconv_cpu_backward(gradOutput, padding_l, input, filters); } PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("forward", &dynamicconv_forward, "dynamicconv forward (CPU)"); - m.def("backward", &dynamicconv_backward, "dynamicconv backward (CPU)"); + m.def("forward", &dynamicconv_forward, "dynamicconv forward (CPU)"); + m.def("backward", &dynamicconv_backward, "dynamicconv backward (CPU)"); } diff --git a/fairseq/modules/lightconv_layer/lightconv_cuda.cpp b/fairseq/modules/lightconv_layer/lightconv_cuda.cpp index 4bf6b5ad36..ece47a8d90 100644 --- a/fairseq/modules/lightconv_layer/lightconv_cuda.cpp +++ b/fairseq/modules/lightconv_layer/lightconv_cuda.cpp @@ -8,10 +8,8 @@ #include <torch/extension.h> #include <vector> -std::vector<at::Tensor> lightconv_cuda_forward( - at::Tensor input, - at::Tensor filters, - int padding_l); +std::vector<at::Tensor> +lightconv_cuda_forward(at::Tensor input, at::Tensor filters, int padding_l); std::vector<at::Tensor> lightconv_cuda_backward( at::Tensor gradOutput, @@ -19,20 +17,20 @@ std::vector<at::Tensor> lightconv_cuda_backward( at::Tensor input, at::Tensor filters); +#define CHECK_CUDA(x) \ + AT_ASSERTM(x.type().is_cuda(), #x " must be a CUDA tensor") +#define CHECK_CONTIGUOUS(x) \ + AT_ASSERTM(x.is_contiguous(), #x " must be contiguous") +#define CHECK_INPUT(x) \ + CHECK_CUDA(x); \ + CHECK_CONTIGUOUS(x) -#define CHECK_CUDA(x) AT_ASSERTM(x.type().is_cuda(), #x " must be a CUDA tensor") -#define CHECK_CONTIGUOUS(x) AT_ASSERTM(x.is_contiguous(), #x " must be contiguous") -#define CHECK_INPUT(x) CHECK_CUDA(x); CHECK_CONTIGUOUS(x) - -std::vector<at::Tensor> lightconv_forward( - at::Tensor input, - at::Tensor filters, - int padding_l) { +std::vector<at::Tensor> +lightconv_forward(at::Tensor input, at::Tensor filters, int padding_l) { + CHECK_INPUT(input); + CHECK_INPUT(filters); - CHECK_INPUT(input); - CHECK_INPUT(filters); - - return lightconv_cuda_forward(input, filters, padding_l); + return lightconv_cuda_forward(input, filters, padding_l); } std::vector<at::Tensor> lightconv_backward( @@ -40,15 +38,14 @@ std::vector<at::Tensor> lightconv_backward( int padding_l, at::Tensor input, at::Tensor filters) { + CHECK_INPUT(gradOutput); + CHECK_INPUT(input); + CHECK_INPUT(filters); - CHECK_INPUT(gradOutput); - CHECK_INPUT(input); - CHECK_INPUT(filters); - - return lightconv_cuda_backward(gradOutput, padding_l, input, filters); + return lightconv_cuda_backward(gradOutput, padding_l, input, filters); } PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { - m.def("forward", &lightconv_forward, "lighconv forward (CUDA)"); - m.def("backward", &lightconv_backward, "lighconv backward (CUDA)"); + m.def("forward", &lightconv_forward, "lighconv forward (CUDA)"); + m.def("backward", &lightconv_backward, "lighconv backward (CUDA)"); } diff --git a/fairseq/modules/lightconv_layer/lightconv_cuda.cuh b/fairseq/modules/lightconv_layer/lightconv_cuda.cuh index 3cae57b68f..610ab399e9 100644 --- a/fairseq/modules/lightconv_layer/lightconv_cuda.cuh +++ b/fairseq/modules/lightconv_layer/lightconv_cuda.cuh @@ -1,6 +1,6 @@ /** * Copyright (c) Facebook, Inc. and its affiliates. - * + * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ @@ -18,23 +18,24 @@ #include <utility> #include <vector> -#include <stdlib.h> #include <assert.h> +#include <stdlib.h> #define SHFL_MASK 0xffffffff -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_forward_kernel(const scalar_t* input, - const scalar_t* filters, - int minibatch, int sequenceLength, - int numFeatures, int numFiltersInBlock, - scalar_t* output); +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_forward_kernel( + const scalar_t* input, + const scalar_t* filters, + int minibatch, + int sequenceLength, + int numFeatures, + int numFiltersInBlock, + scalar_t* output); -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_grad_wrt_input_kernel( - const scalar_t* input, +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_grad_wrt_input_kernel( + const scalar_t* input, const scalar_t* filters, int minibatch, int sequenceLength, @@ -42,9 +43,8 @@ void lightconv_grad_wrt_input_kernel( int numFiltersInBlock, scalar_t* output); -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_firstpass_short_kernel( +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_firstpass_short_kernel( const scalar_t* input, const scalar_t* gradInput, int minibatch, @@ -54,17 +54,15 @@ void lightconv_grad_wrt_weights_firstpass_short_kernel( int numHeads, float* output); -template<int FS, int SB, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_secondpass_short_kernel( +template <int FS, int SB, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_secondpass_short_kernel( const float* input, - const int minibatch, + const int minibatch, const int numFiltersInBlock, scalar_t* output); -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_firstpass_kernel( +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_firstpass_kernel( const scalar_t* input, const scalar_t* gradInput, int minibatch, @@ -73,11 +71,9 @@ void lightconv_grad_wrt_weights_firstpass_kernel( int numFiltersInBlock, float* output); -template<int FS, int SB, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_secondpass_kernel( +template <int FS, int SB, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_secondpass_kernel( const float* input, - const int minibatch, + const int minibatch, const int numFiltersInBlock, scalar_t* output); - diff --git a/fairseq/modules/lightconv_layer/lightconv_cuda_kernel.cu b/fairseq/modules/lightconv_layer/lightconv_cuda_kernel.cu index 8ee83a56c8..cdf31d5d2d 100644 --- a/fairseq/modules/lightconv_layer/lightconv_cuda_kernel.cu +++ b/fairseq/modules/lightconv_layer/lightconv_cuda_kernel.cu @@ -1,29 +1,31 @@ /** * Copyright (c) Facebook, Inc. and its affiliates. - * + * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ +#include "../cuda_utils.cu" #include "lightconv_cuda.cuh" -#include "lightconv_cuda_forward.cu" #include "lightconv_cuda_backward.cu" -#include "../cuda_utils.cu" - -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_forward_kernel(const scalar_t* input, - const scalar_t* filters, - int minibatch, int sequenceLength, - int numFeatures, int numFiltersInBlock, - scalar_t* output) { +#include "lightconv_cuda_forward.cu" +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_forward_kernel( + const scalar_t* input, + const scalar_t* filters, + int minibatch, + int sequenceLength, + int numFeatures, + int numFiltersInBlock, + scalar_t* output) { const int tid = threadIdx.x; const int batchIdx = blockIdx.x; const int featureIdx = blockIdx.y; const int filterIdx = featureIdx / numFiltersInBlock; - const int IOOffset = numFeatures * sequenceLength * batchIdx + featureIdx * sequenceLength; + const int IOOffset = + numFeatures * sequenceLength * batchIdx + featureIdx * sequenceLength; const scalar_t* inputFeature = &input[IOOffset]; scalar_t* outputFeature = &output[IOOffset]; const scalar_t* inputFilter = &filters[filterIdx * FS]; @@ -31,7 +33,7 @@ void lightconv_forward_kernel(const scalar_t* input, assert(blockDim.x == SB); scalar_t filter[FS]; - #pragma unroll +#pragma unroll for (int i = 0; i < FS; ++i) { filter[i] = inputFilter[i]; } @@ -45,13 +47,19 @@ void lightconv_forward_kernel(const scalar_t* input, // Read input into shared memory const int inputOffset = i * SB; - load_input_to_shared<FS, SB, padding_l>(inputFeature, inputOffset, sequenceLength, - i, numIterations, (numIterations == 1), temp); + load_input_to_shared<FS, SB, padding_l>( + inputFeature, + inputOffset, + sequenceLength, + i, + numIterations, + (numIterations == 1), + temp); __syncthreads(); scalar_t out = 0; - #pragma unroll +#pragma unroll for (int j = 0; j < FS; ++j) { out += filter[j] * temp[tid + j]; } @@ -66,9 +74,8 @@ void lightconv_forward_kernel(const scalar_t* input, } } -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_grad_wrt_input_kernel( +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_grad_wrt_input_kernel( const scalar_t* input, const scalar_t* filters, int minibatch, @@ -76,14 +83,14 @@ void lightconv_grad_wrt_input_kernel( int numFeatures, int numFiltersInBlock, scalar_t* output) { - // input grad kernel is similar to forward kernel const int tid = threadIdx.x; const int batchIdx = blockIdx.x; const int featureIdx = blockIdx.y; const int filterIdx = featureIdx / numFiltersInBlock; - const int IOOffset = numFeatures * sequenceLength * batchIdx + featureIdx * sequenceLength; + const int IOOffset = + numFeatures * sequenceLength * batchIdx + featureIdx * sequenceLength; const scalar_t* inputFeature = &input[IOOffset]; scalar_t* outputFeature = &output[IOOffset]; const scalar_t* inputFilter = &filters[filterIdx * FS]; @@ -92,8 +99,8 @@ void lightconv_grad_wrt_input_kernel( scalar_t filter[FS]; - // The only change is loading the filter in reverse - #pragma unroll +// The only change is loading the filter in reverse +#pragma unroll for (int i = 0; i < FS; ++i) { filter[i] = inputFilter[FS - i - 1]; } @@ -110,13 +117,19 @@ void lightconv_grad_wrt_input_kernel( // Read input into shared memory const int inputOffset = i * SB; - load_input_to_shared<FS, SB, padding>(inputFeature, inputOffset, sequenceLength, - i, numIterations, false, temp); + load_input_to_shared<FS, SB, padding>( + inputFeature, + inputOffset, + sequenceLength, + i, + numIterations, + false, + temp); __syncthreads(); scalar_t out = 0; - #pragma unroll +#pragma unroll for (int j = 0; j < FS; ++j) { out += filter[j] * temp[tid + j]; } @@ -133,9 +146,8 @@ void lightconv_grad_wrt_input_kernel( // This is by far the most expensive kernel in terms of time taken. // Can be 16x slower than the forward or grad_wrt_input when filter size is 31 -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_firstpass_short_kernel( +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_firstpass_short_kernel( const scalar_t* input, const scalar_t* gradInput, int minibatch, @@ -144,7 +156,6 @@ void lightconv_grad_wrt_weights_firstpass_short_kernel( int numFiltersInBlock, int numHeads, float* output) { - const int tid = threadIdx.x; const int batchIdx = blockIdx.x; const int filterIdx = blockIdx.y; @@ -166,52 +177,60 @@ void lightconv_grad_wrt_weights_firstpass_short_kernel( accumWeights[i] = float(0.0); } - // loop over each sequence within filterblock - for (int idxInFilterBlock = 0; idxInFilterBlock < numFiltersInBlock; ++idxInFilterBlock) { - - const int featureOffset = batchIdx * numFeatures * sequenceLength + (filterIdx * numFiltersInBlock + idxInFilterBlock) * sequenceLength; + for (int idxInFilterBlock = 0; idxInFilterBlock < numFiltersInBlock; + ++idxInFilterBlock) { + const int featureOffset = batchIdx * numFeatures * sequenceLength + + (filterIdx * numFiltersInBlock + idxInFilterBlock) * sequenceLength; const scalar_t* inputFeature = &input[featureOffset]; const scalar_t* gradInputFeature = &gradInput[featureOffset]; zeroSharedMem<FS, SB, padding_l>(tempInput); - zeroSharedMem<FS, SB, (FS/2)>(tempGradInput); + zeroSharedMem<FS, SB, (FS / 2)>(tempGradInput); __syncthreads(); for (int i = 0; i < numIterations; ++i) { - const int inputOffset = i * SB; - load_input_to_shared<FS, SB, padding_l>(inputFeature, inputOffset, sequenceLength, - i, numIterations, false, tempInput); - load_input_to_shared<FS, SB, (FS/2)>(gradInputFeature, inputOffset, sequenceLength, - i, numIterations, false, tempGradInput); + load_input_to_shared<FS, SB, padding_l>( + inputFeature, + inputOffset, + sequenceLength, + i, + numIterations, + false, + tempInput); + load_input_to_shared<FS, SB, (FS / 2)>( + gradInputFeature, + inputOffset, + sequenceLength, + i, + numIterations, + false, + tempGradInput); __syncthreads(); - const int gradIndex = (FS/2) + tid; + const int gradIndex = (FS / 2) + tid; scalar_t tempGrad = tempGradInput[gradIndex]; - #pragma unroll +#pragma unroll for (int j = 0; j < FS; j++) { const int inputIndex = tid + j; accumWeights[j] += tempInput[inputIndex] * tempGrad; } __syncthreads(); - } - } // Row-major sum for (int filterWeightIdx = 0; filterWeightIdx < FS; ++filterWeightIdx) { - float temp; if (tid < sequenceLength) { - temp = accumWeights[filterWeightIdx]; + temp = accumWeights[filterWeightIdx]; } else { - temp = float(0.0); + temp = float(0.0); } const int outputOffset = filterWeightIdx * minibatch + batchIdx; @@ -224,14 +243,12 @@ void lightconv_grad_wrt_weights_firstpass_short_kernel( } } -template<int FS, int SB, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_secondpass_short_kernel( +template <int FS, int SB, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_secondpass_short_kernel( const float* input, const int minibatch, const int numFiltersInBlock, scalar_t* output) { - assert(blockDim.x == SB); const int tid = threadIdx.x; @@ -239,8 +256,8 @@ void lightconv_grad_wrt_weights_secondpass_short_kernel( const int filterIdx = blockIdx.x; const int filterWeightIdx = blockIdx.y; - const int inputOffset = filterIdx * FS * minibatch + - filterWeightIdx * minibatch; + const int inputOffset = + filterIdx * FS * minibatch + filterWeightIdx * minibatch; const float* tempInput = &input[inputOffset]; // read into shared memory for reduction @@ -261,9 +278,8 @@ void lightconv_grad_wrt_weights_secondpass_short_kernel( // This is by far the most expensive kernel in terms of time taken. // Can be 16x slower than the forward or grad_wrt_input when filter size is 31 -template<int FS, int SB, int padding_l, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_firstpass_kernel( +template <int FS, int SB, int padding_l, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_firstpass_kernel( const scalar_t* input, const scalar_t* gradInput, int minibatch, @@ -271,7 +287,6 @@ void lightconv_grad_wrt_weights_firstpass_kernel( int numFeatures, int numFiltersInBlock, float* output) { - assert(blockDim.x == SB); const int tid = threadIdx.x; @@ -287,7 +302,7 @@ void lightconv_grad_wrt_weights_firstpass_kernel( __shared__ scalar_t tempInput[SB + FS]; __shared__ scalar_t tempGradInput[SB + FS]; zeroSharedMem<FS, SB, padding_l>(tempInput); - zeroSharedMem<FS, SB, (FS/2)>(tempGradInput); + zeroSharedMem<FS, SB, (FS / 2)>(tempGradInput); __syncthreads(); float accumWeights[FS]; @@ -296,23 +311,37 @@ void lightconv_grad_wrt_weights_firstpass_kernel( accumWeights[i] = float(0.0); } - const int IOOffset = batchIdx * numFeatures * sequenceLength + featureIdx * sequenceLength; + const int IOOffset = + batchIdx * numFeatures * sequenceLength + featureIdx * sequenceLength; const scalar_t* inputFeature = &input[IOOffset]; const scalar_t* gradInputFeature = &gradInput[IOOffset]; - float* tempOutputGradWeight = &output[filterIdx * FS * minibatch * numFiltersInBlock]; + float* tempOutputGradWeight = + &output[filterIdx * FS * minibatch * numFiltersInBlock]; for (int i = 0; i < numIterations; ++i) { const int inputOffset = i * SB; - load_input_to_shared<FS, SB, padding_l>(inputFeature, inputOffset, sequenceLength, - i, numIterations, false, tempInput); - load_input_to_shared<FS, SB, (FS/2)>(gradInputFeature, inputOffset, sequenceLength, - i, numIterations, false, tempGradInput); + load_input_to_shared<FS, SB, padding_l>( + inputFeature, + inputOffset, + sequenceLength, + i, + numIterations, + false, + tempInput); + load_input_to_shared<FS, SB, (FS / 2)>( + gradInputFeature, + inputOffset, + sequenceLength, + i, + numIterations, + false, + tempGradInput); __syncthreads(); - #pragma unroll +#pragma unroll for (int j = 0; j < FS; ++j) { - accumWeights[j] += tempInput[tid + j] * tempGradInput[tid + (FS/2)]; + accumWeights[j] += tempInput[tid + j] * tempGradInput[tid + (FS / 2)]; } __syncthreads(); @@ -320,7 +349,6 @@ void lightconv_grad_wrt_weights_firstpass_kernel( // Row-major sum for (int filterWeightIdx = 0; filterWeightIdx < FS; ++filterWeightIdx) { - // Write to shared memory before reduction if (tid < sequenceLength) { temp = accumWeights[filterWeightIdx]; @@ -331,8 +359,7 @@ void lightconv_grad_wrt_weights_firstpass_kernel( temp = blockReduce(temp); const int outputOffset = filterWeightIdx * minibatch * numFiltersInBlock + - batchIdx * numFiltersInBlock + - idxInFilterBlock; + batchIdx * numFiltersInBlock + idxInFilterBlock; if (tid == 0) { tempOutputGradWeight[outputOffset] = temp; @@ -340,14 +367,12 @@ void lightconv_grad_wrt_weights_firstpass_kernel( } } -template<int FS, int SB, typename scalar_t> -__global__ -void lightconv_grad_wrt_weights_secondpass_kernel( +template <int FS, int SB, typename scalar_t> +__global__ void lightconv_grad_wrt_weights_secondpass_kernel( const float* input, const int minibatch, const int numFiltersInBlock, scalar_t* output) { - assert(blockDim.x == SB); const int tid = threadIdx.x; @@ -356,7 +381,7 @@ void lightconv_grad_wrt_weights_secondpass_kernel( const int filterWeightIdx = blockIdx.y; const int inputOffset = filterIdx * FS * minibatch * numFiltersInBlock + - filterWeightIdx * minibatch * numFiltersInBlock; + filterWeightIdx * minibatch * numFiltersInBlock; const float* tempInput = &input[inputOffset]; int readIndex = tid; From 53802e781291b63e656c89818c38bfc49ff0f108 Mon Sep 17 00:00:00 2001 From: Omry Yadan <omry@fb.com> Date: Mon, 26 Jul 2021 16:35:40 -0700 Subject: [PATCH 420/774] Compatibility fix with Hydra 1.1 (#3722) Summary: One of the changes in Hydra 1.1 is that the default composition order is changing. This is documented [here](https://hydra.cc/docs/upgrades/1.0_to_1.1/default_composition_order). In Hydra 1.1, a config is overriding values introduced by the defaults list while in Hydra 1.0 - the defaults list was overriding the values in the config. fairseq is currently depending on the previous behavior: The class `FairseqConfig` defines config values, and it's expecting them to be overridden by the defaults list. This result in a different config being created when running `fairseq_cli/hydra_train.py` with Hydra 1.0 and with 1.1. Hydra 1.1 introduced the `_self_` keyword in the defaults list to control the composition order. In order to achieve the behavior of Hydra 1.0, `_self_` should be added as the first item in the defaults list. To allow for a smoother migration, Hydra 1.0 is ignoring `_self_` starting from 1.0.7 (previous versions will issue an error). This diff adds `_self_` as the first item in the defaults list the fairseq config, and introduce a dependency a Hydra 1.0 version that is equal or newer to 1.0.7. ### Testing: I ensured that the following yield the same composed config: Default config with Hydra 1.0.6, 1.0.7 and 1.1.0 `examples/wav2vec/config/finetuning/base_10h.yaml` with Hydra 1.0.6, 1.0.7 and 1.1.0. This can be achieved by outputing the generated config using `--cfg job` and compating the outputs. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3722 Reviewed By: dianaml0 Differential Revision: D29917677 Pulled By: jieru-hu fbshipit-source-id: 7e645b83cccb03fc80a6702e302c4643d2b14a78 --- fairseq/config/config.yaml | 1 + fairseq/optim/fp16_optimizer.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fairseq/config/config.yaml b/fairseq/config/config.yaml index e20d914b9b..2ed7168cb7 100644 --- a/fairseq/config/config.yaml +++ b/fairseq/config/config.yaml @@ -5,6 +5,7 @@ hydra: dir: . defaults: + - _self_ - task: null - model: null - criterion: cross_entropy diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index 370a910102..b84236e685 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -479,7 +479,7 @@ def __init__( "Unsupported optimizer: {}".format(optimizer.__class__.__name__) ) - super().__init__(cfg.optimizer) + super().__init__(getattr(cfg, "optimizer", None)) self.wrapped_optimizer = optimizer if getattr(cfg.common, "fp16_scale_window", None) is None: diff --git a/setup.py b/setup.py index 51e555229c..7a19b73c9e 100644 --- a/setup.py +++ b/setup.py @@ -201,7 +201,7 @@ def do_setup(package_data): "cffi", "cython", 'dataclasses; python_version<"3.7"', - "hydra-core<1.1", + "hydra-core>=1.0.7,<1.1", "omegaconf<2.1", 'numpy<1.20.0; python_version<"3.7"', 'numpy; python_version>="3.7"', From 0769cfe2e9ecd8c2dd15cb2491474ef0b4b3d0e2 Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <sivaibhav@google.com> Date: Tue, 27 Jul 2021 12:59:08 -0700 Subject: [PATCH 421/774] Fixed the reference to mask_channel_prob in task cfg (#3742) Summary: Updated example config file for tpu to include mask parameters. Noted currently cli bug in README ## What does this PR do? Fixes # (3741) B. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3742 Reviewed By: arbabu123 Differential Revision: D29938257 Pulled By: alexeib fbshipit-source-id: 6ab5cd2974949806621fb37cb13d918bea733a73 --- examples/wav2vec/README.md | 5 +++-- .../config/pretraining/wav2vec2_large_librivox_tpu.yaml | 5 +++++ fairseq/tasks/audio_pretraining.py | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index c543b6b97b..badfda8979 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -196,7 +196,7 @@ target_transcription = "A MAN SAID TO THE UNIVERSE I EXIST" # encode labels with processor.as_target_processor(): - labels = processor(target_transcription, return_tensors="pt").input_ids + labels = processor(target_transcription, return_tensors="pt").input_ids # compute loss by passing labels loss = model(input_values, labels=labels).loss @@ -263,6 +263,7 @@ $ OMP_NUM_THREADS=1 fairseq-hydra-train \ ``` #### Using command line arguments on a v3-8: +Note: Commandline arguments way of execution has a [known-problem](https://github.com/pytorch/fairseq/issues/3741) currently. ``` $ OMP_NUM_THREADS=1 python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ @@ -285,7 +286,7 @@ $ OMP_NUM_THREADS=1 fairseq-hydra-train \ ``` #### Using command line arguments on a pod slice (v3-N with N > 8): - +Note: Commandline arguments way of execution has a [known-problem](https://github.com/pytorch/fairseq/issues/3741) currently. ``` $ python -m torch_xla.distributed.xla_dist \ diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml index 2036e23c6b..ee55bdab72 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox_tpu.yaml @@ -20,6 +20,11 @@ task: num_batch_buckets: 3 precompute_mask_indices: true enable_padding: true + inferred_w2v_config: + mask_prob: 0.65 + mask_selection: 'static' + mask_other: 0 + mask_channel_prob: 0.1 dataset: num_workers: 6 diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index 059e2d70c8..b7d0f3da57 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -242,7 +242,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): **self._get_mask_precompute_kwargs(task_cfg), ) - if self.cfg.tpu and task_cfg["mask_channel_prob"] == 0.0: + if self.cfg.tpu and task_cfg.inferred_w2v_config.mask_channel_prob == 0.0: logger.info( "Pretraining on TPUs may suffer convergence " "issues when training with `mask_channel_prob` value of " From 7ca95a66d64411deea49cb8710195ed2e0699f0a Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Tue, 27 Jul 2021 13:23:07 -0700 Subject: [PATCH 422/774] Add speech/text joint training for speech to text task (step 1) Summary: 1. adding feature to generate raw audio with target sampling rate 2. fix bugs a) empty sample in transform_eos_lang_pair_dataset.py b) S2T decoding with language model Reviewed By: kahne Differential Revision: D29699692 fbshipit-source-id: cc4b76618ef3b43dbba53a422f24597b9866d17f --- fairseq/data/audio/audio_utils.py | 82 +++-- fairseq/data/audio/speech_to_text_dataset.py | 346 +++++++++++------- .../data/transform_eos_lang_pair_dataset.py | 2 + .../models/speech_to_text/s2t_transformer.py | 16 +- fairseq/tasks/speech_to_text.py | 23 +- 5 files changed, 290 insertions(+), 179 deletions(-) diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index f51cb0cddc..7c2638dc0c 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -9,31 +9,46 @@ FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS = {".npy", ".wav", ".flac", ".ogg"} -def _convert_to_mono( - waveform: torch.FloatTensor, sample_rate: int -) -> torch.FloatTensor: - if waveform.shape[0] > 1: - try: - import torchaudio.sox_effects as ta_sox - except ImportError: - raise ImportError( - "Please install torchaudio to convert multi-channel audios" - ) - effects = [['channels', '1']] - return ta_sox.apply_effects_tensor(waveform, sample_rate, effects)[0] +def update_sample_rate( + waveform: np.ndarray, + sample_rate: int, + tgt_sample_rate: int, +) -> np.ndarray: + if tgt_sample_rate > 0 and tgt_sample_rate != sample_rate: + _waveform = torch.from_numpy(waveform) + effects = [["rate", f"{tgt_sample_rate}"]] + return _sox_convert(_waveform, sample_rate, effects).numpy() return waveform +def _sox_convert( + waveform: torch.FloatTensor, + sample_rate: int, + effects: List[List[str]], +) -> torch.FloatTensor: + try: + import torchaudio.sox_effects as ta_sox + except ImportError: + raise ImportError("Please install torchaudio to convert audios") + return ta_sox.apply_effects_tensor(waveform, sample_rate, effects)[0] + + def convert_to_mono(waveform: np.ndarray, sample_rate: int) -> np.ndarray: if waveform.shape[0] > 1: _waveform = torch.from_numpy(waveform) - return _convert_to_mono(_waveform, sample_rate).numpy() + effects = [["channels", "1"]] + return _sox_convert(_waveform, sample_rate, effects).numpy() return waveform def get_waveform( - path_or_fp: Union[str, BinaryIO], normalization=True, mono=True, - frames=-1, start=0, always_2d=True + path_or_fp: Union[str, BinaryIO], + normalization=True, + mono=True, + frames=-1, + start=0, + always_2d=True, + output_sample_rate=-1, ) -> Tuple[np.ndarray, int]: """Get the waveform and sample rate of a 16-bit WAV/FLAC/OGG Vorbis audio. @@ -44,6 +59,7 @@ def get_waveform( frames (int): the number of frames to read. (-1 for reading all) start (int): Where to start reading. A negative value counts from the end. always_2d (bool): always return 2D array even for mono-channel audios + output_sample_rate (int): output sample rate, -1 using default Returns: waveform (numpy.ndarray): 1D or 2D waveform (channels x length) sample_rate (float): sample rate @@ -56,9 +72,7 @@ def get_waveform( try: import soundfile as sf except ImportError: - raise ImportError( - "Please install soundfile to load WAV/FLAC/OGG Vorbis audios" - ) + raise ImportError("Please install soundfile to load WAV/FLAC/OGG Vorbis audios") waveform, sample_rate = sf.read( path_or_fp, dtype="float32", always_2d=True, frames=frames, start=start @@ -66,6 +80,9 @@ def get_waveform( waveform = waveform.T # T x C -> C x T if mono and waveform.shape[0] > 1: waveform = convert_to_mono(waveform, sample_rate) + if output_sample_rate > 0: + waveform = update_sample_rate(waveform, sample_rate, output_sample_rate) + sample_rate = output_sample_rate if not normalization: waveform *= 2 ** 15 # denormalized to 16-bit signed integers if not always_2d: @@ -74,12 +91,12 @@ def get_waveform( def _get_kaldi_fbank( - waveform: np.ndarray, sample_rate: int, n_bins=80 + waveform: np.ndarray, sample_rate: int, n_bins=80 ) -> Optional[np.ndarray]: """Get mel-filter bank features via PyKaldi.""" try: - from kaldi.feat.mel import MelBanksOptions from kaldi.feat.fbank import FbankOptions, Fbank + from kaldi.feat.mel import MelBanksOptions from kaldi.feat.window import FrameExtractionOptions from kaldi.matrix import Vector @@ -98,11 +115,12 @@ def _get_kaldi_fbank( def _get_torchaudio_fbank( - waveform: np.ndarray, sample_rate, n_bins=80 + waveform: np.ndarray, sample_rate, n_bins=80 ) -> Optional[np.ndarray]: """Get mel-filter bank features via TorchAudio.""" try: import torchaudio.compliance.kaldi as ta_kaldi + waveform = torch.from_numpy(waveform) features = ta_kaldi.fbank( waveform, num_mel_bins=n_bins, sample_frequency=sample_rate @@ -136,9 +154,9 @@ def is_npy_data(data: bytes) -> bool: def is_sf_audio_data(data: bytes) -> bool: - is_wav = (data[0] == 82 and data[1] == 73 and data[2] == 70) - is_flac = (data[0] == 102 and data[1] == 76 and data[2] == 97) - is_ogg = (data[0] == 79 and data[1] == 103 and data[2] == 103) + is_wav = data[0] == 82 and data[1] == 73 and data[2] == 70 + is_flac = data[0] == 102 and data[1] == 76 and data[2] == 97 + is_ogg = data[0] == 79 and data[1] == 103 and data[2] == 103 return is_wav or is_flac or is_ogg @@ -151,16 +169,16 @@ def read_from_stored_zip(zip_path: str, offset: int, file_size: int) -> bytes: def parse_path(path: str) -> Tuple[str, List[int]]: """Parse data path which is either a path to - 1. a .npy/.wav/.flac/.ogg file - 2. a stored ZIP file with slicing info: "[zip_path]:[offset]:[length]" + 1. a .npy/.wav/.flac/.ogg file + 2. a stored ZIP file with slicing info: "[zip_path]:[offset]:[length]" - Args: - path (str): the data path to parse + Args: + path (str): the data path to parse - Returns: - file_path (str): the file path - slice_ptr (list of int): empty in case 1; - byte offset and length for the slice in case 2 + Returns: + file_path (str): the file path + slice_ptr (list of int): empty in case 1; + byte offset and length for the slice in case 2 """ if Path(path).suffix in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index d4b5668d8f..ba6c28632e 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -6,9 +6,10 @@ import csv import io import logging -import os.path as op import re -from typing import Dict, List, Optional, Tuple +from collections import defaultdict +from pathlib import Path +from typing import Dict, List, Optional, NamedTuple import numpy as np import torch @@ -20,8 +21,13 @@ data_utils as fairseq_data_utils, ) from fairseq.data.audio.audio_utils import ( - get_fbank, get_waveform, read_from_stored_zip, is_npy_data, - is_sf_audio_data, parse_path, FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS + get_fbank, + get_waveform, + read_from_stored_zip, + is_npy_data, + is_sf_audio_data, + parse_path, + FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS, ) from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform @@ -32,20 +38,22 @@ class S2TDataConfig(object): """Wrapper class for data config YAML""" - def __init__(self, yaml_path): + def __init__(self, yaml_path: Path): try: import yaml except ImportError: - print("Please install PyYAML to load YAML files for " "S2T data config") + print("Please install PyYAML to load YAML files for S2T data config") self.config = {} - if op.isfile(yaml_path): + if yaml_path.is_file(): try: with open(yaml_path) as f: self.config = yaml.load(f, Loader=yaml.FullLoader) except Exception as e: - raise Exception(f"Failed to load config from {yaml_path}: {e}") + raise Exception( + f"Failed to load config from {yaml_path.as_posix()}: {e}" + ) else: - raise FileNotFoundError(f"{yaml_path} not found") + raise FileNotFoundError(f"{yaml_path.as_posix()} not found") @property def vocab_filename(self): @@ -102,6 +110,12 @@ def use_audio_input(self): raw audio as inputs.""" return self.config.get("use_audio_input", False) + @property + def use_sample_rate(self): + """Needed by the dataset loader to see if the model requires + raw audio with specific sample rate as inputs.""" + return self.config.get("use_sample_rate", 16000) + @property def audio_root(self): """Audio paths in the manifest TSV can be relative and this provides @@ -124,14 +138,18 @@ def get_feature_transforms(self, split, is_train): def get_features_from_npy_or_audio(path): - ext = op.splitext(op.basename(path))[1] + ext = Path(path).suffix if ext not in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: raise ValueError(f'Unsupported file format for "{path}"') return np.load(path) if ext == ".npy" else get_fbank(path) def get_features_or_waveform_from_stored_zip( - path, byte_offset, byte_size, need_waveform=False + path, + byte_offset, + byte_size, + need_waveform=False, + use_sample_rate=-1, ): assert path.endswith(".zip") data = read_from_stored_zip(path, byte_offset, byte_size) @@ -139,14 +157,17 @@ def get_features_or_waveform_from_stored_zip( if is_npy_data(data): features_or_waveform = np.load(f) elif is_sf_audio_data(data): - features_or_waveform = \ - get_waveform(f, always_2d=False)[0] if need_waveform else get_fbank(f) + features_or_waveform = ( + get_waveform(f, always_2d=False, output_sample_rate=use_sample_rate)[0] + if need_waveform + else get_fbank(f) + ) else: raise ValueError(f'Unknown file format for "{path}"') return features_or_waveform -def get_features_or_waveform(path: str, need_waveform=False): +def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=-1): """Get speech features from .npy file or waveform from .wav/.flac file. The file may be inside an uncompressed ZIP file and is accessed via byte offset and length. @@ -155,6 +176,7 @@ def get_features_or_waveform(path: str, need_waveform=False): path (str): File path in the format of "<.npy/.wav/.flac path>" or "<zip path>:<byte offset>:<byte length>". need_waveform (bool): return waveform instead of features. + use_sample_rate (int): change sample rate for the input wave file Returns: features_or_waveform (numpy.ndarray): speech features or waveform. @@ -162,11 +184,17 @@ def get_features_or_waveform(path: str, need_waveform=False): _path, slice_ptr = parse_path(path) if len(slice_ptr) == 0: if need_waveform: - return get_waveform(_path, always_2d=False) + return get_waveform( + _path, always_2d=False, output_sample_rate=use_sample_rate + )[0] return get_features_from_npy_or_audio(_path) elif len(slice_ptr) == 2: features_or_waveform = get_features_or_waveform_from_stored_zip( - _path, slice_ptr[0], slice_ptr[1], need_waveform=need_waveform + _path, + slice_ptr[0], + slice_ptr[1], + need_waveform=need_waveform, + use_sample_rate=use_sample_rate, ) else: raise ValueError(f"Invalid path: {path}") @@ -195,6 +223,12 @@ def _collate_frames( return out +class SpeechToTextDatasetItem(NamedTuple): + index: int + source: torch.Tensor + target: Optional[torch.Tensor] = None + + class SpeechToTextDataset(FairseqDataset): LANG_TAG_TEMPLATE = "<lang:{}>" @@ -202,7 +236,7 @@ def __init__( self, split: str, is_train_split: bool, - data_cfg: S2TDataConfig, + cfg: S2TDataConfig, audio_paths: List[str], n_frames: List[int], src_texts: Optional[List[str]] = None, @@ -216,7 +250,7 @@ def __init__( bpe_tokenizer=None, ): self.split, self.is_train_split = split, is_train_split - self.data_cfg = data_cfg + self.cfg = cfg self.audio_paths, self.n_frames = audio_paths, n_frames self.n_samples = len(audio_paths) assert len(n_frames) == self.n_samples > 0 @@ -234,22 +268,42 @@ def __init__( self.tgt_dict = tgt_dict self.check_tgt_lang_tag() self.ids = ids - self.shuffle = data_cfg.shuffle if is_train_split else False + self.shuffle = cfg.shuffle if is_train_split else False self.feature_transforms = CompositeAudioFeatureTransform.from_config_dict( - self.data_cfg.get_feature_transforms(split, is_train_split) + self.cfg.get_feature_transforms(split, is_train_split) ) self.pre_tokenizer = pre_tokenizer self.bpe_tokenizer = bpe_tokenizer + self.tgt_lens = self.get_tgt_lens_and_check_oov() + logger.info(self.__repr__()) + def get_tgt_lens_and_check_oov(self): + if self.tgt_texts is None: + return [0 for _ in range(self.n_samples)] + tgt_lens = [] + n_tokens, n_oov_tokens = 0, 0 + for i in range(self.n_samples): + tokenized = self.get_tokenized_tgt_text(i).split(" ") + oov_tokens = [ + t + for t in tokenized + if self.tgt_dict.index(t) == self.tgt_dict.unk_index + ] + n_tokens += len(tokenized) + n_oov_tokens += len(oov_tokens) + tgt_lens.append(len(tokenized)) + logger.info(f"'{self.split}' has {n_oov_tokens / n_tokens * 100:.2f}% OOV") + return tgt_lens + def __repr__(self): return ( self.__class__.__name__ + f'(split="{self.split}", n_samples={self.n_samples}, ' - f"prepend_tgt_lang_tag={self.data_cfg.prepend_tgt_lang_tag}, " + f"prepend_tgt_lang_tag={self.cfg.prepend_tgt_lang_tag}, " f"shuffle={self.shuffle}, transforms={self.feature_transforms})" ) @@ -259,55 +313,65 @@ def is_lang_tag(cls, token): return re.match(pattern, token) def check_tgt_lang_tag(self): - if self.data_cfg.prepend_tgt_lang_tag: + if self.cfg.prepend_tgt_lang_tag: assert self.tgt_langs is not None and self.tgt_dict is not None tgt_lang_tags = [ self.LANG_TAG_TEMPLATE.format(t) for t in set(self.tgt_langs) ] assert all(t in self.tgt_dict for t in tgt_lang_tags) - def tokenize_text(self, text: str): - if self.pre_tokenizer is not None: - text = self.pre_tokenizer.encode(text) - if self.bpe_tokenizer is not None: - text = self.bpe_tokenizer.encode(text) + @classmethod + def tokenize(cls, tokenizer, text: str): + return text if tokenizer is None else tokenizer.encode(text) + + def get_tokenized_tgt_text(self, index: int): + text = self.tokenize(self.pre_tokenizer, self.tgt_texts[index]) + text = self.tokenize(self.bpe_tokenizer, text) return text - def __getitem__( - self, index: int - ) -> Tuple[int, torch.Tensor, Optional[torch.Tensor]]: + @classmethod + def get_lang_tag_idx(cls, lang: str, dictionary: Dictionary): + lang_tag_idx = dictionary.index(cls.LANG_TAG_TEMPLATE.format(lang)) + assert lang_tag_idx != dictionary.unk() + return lang_tag_idx + + def __getitem__(self, index: int) -> SpeechToTextDatasetItem: source = get_features_or_waveform( - self.audio_paths[index], need_waveform=self.data_cfg.use_audio_input + self.audio_paths[index], + need_waveform=self.cfg.use_audio_input, + use_sample_rate=self.cfg.use_sample_rate, ) if self.feature_transforms is not None: - assert not self.data_cfg.use_audio_input + assert not self.cfg.use_audio_input source = self.feature_transforms(source) source = torch.from_numpy(source).float() target = None if self.tgt_texts is not None: - tokenized = self.tokenize_text(self.tgt_texts[index]) + tokenized = self.get_tokenized_tgt_text(index) target = self.tgt_dict.encode_line( tokenized, add_if_not_exist=False, append_eos=True ).long() - if self.data_cfg.prepend_tgt_lang_tag: - lang_tag = self.LANG_TAG_TEMPLATE.format(self.tgt_langs[index]) - lang_tag_idx = self.tgt_dict.index(lang_tag) + if self.cfg.prepend_tgt_lang_tag: + lang_tag_idx = self.get_lang_tag_idx( + self.tgt_langs[index], self.tgt_dict + ) target = torch.cat((torch.LongTensor([lang_tag_idx]), target), 0) - return index, source, target + + return SpeechToTextDatasetItem(index=index, source=source, target=target) def __len__(self): return self.n_samples - def collater(self, samples: List[Tuple[int, torch.Tensor, torch.Tensor]]) -> Dict: + def collater( + self, samples: List[SpeechToTextDatasetItem], return_order: bool = False + ) -> Dict: if len(samples) == 0: return {} - indices = torch.tensor([i for i, _, _ in samples], dtype=torch.long) - frames = _collate_frames( - [s for _, s, _ in samples], self.data_cfg.use_audio_input - ) + indices = torch.tensor([x.index for x in samples], dtype=torch.long) + frames = _collate_frames([x.source for x in samples], self.cfg.use_audio_input) # sort samples by descending number of frames - n_frames = torch.tensor([s.size(0) for _, s, _ in samples], dtype=torch.long) + n_frames = torch.tensor([x.source.size()[0] for x in samples], dtype=torch.long) n_frames, order = n_frames.sort(descending=True) indices = indices.index_select(0, order) frames = frames.index_select(0, order) @@ -317,7 +381,7 @@ def collater(self, samples: List[Tuple[int, torch.Tensor, torch.Tensor]]) -> Dic ntokens = None if self.tgt_texts is not None: target = fairseq_data_utils.collate_tokens( - [t for _, _, t in samples], + [x.target for x in samples], self.tgt_dict.pad(), self.tgt_dict.eos(), left_pad=False, @@ -325,41 +389,40 @@ def collater(self, samples: List[Tuple[int, torch.Tensor, torch.Tensor]]) -> Dic ) target = target.index_select(0, order) target_lengths = torch.tensor( - [t.size(0) for _, _, t in samples], dtype=torch.long + [x.target.size()[0] for x in samples], dtype=torch.long ).index_select(0, order) prev_output_tokens = fairseq_data_utils.collate_tokens( - [t for _, _, t in samples], + [x.target for x in samples], self.tgt_dict.pad(), self.tgt_dict.eos(), left_pad=False, move_eos_to_beginning=True, ) prev_output_tokens = prev_output_tokens.index_select(0, order) - ntokens = sum(t.size(0) for _, _, t in samples) + ntokens = sum(x.target.size()[0] for x in samples) + net_input = { + "src_tokens": frames, + "src_lengths": n_frames, + "prev_output_tokens": prev_output_tokens, + } out = { "id": indices, - "net_input": { - "src_tokens": frames, - "src_lengths": n_frames, - "prev_output_tokens": prev_output_tokens, - }, + "net_input": net_input, "target": target, "target_lengths": target_lengths, "ntokens": ntokens, "nsentences": len(samples), } + if return_order: + out["order"] = order return out def num_tokens(self, index): return self.n_frames[index] def size(self, index): - t_len = 0 - if self.tgt_texts is not None: - tokenized = self.tokenize_text(self.tgt_texts[index]) - t_len = len(tokenized.split(" ")) - return self.n_frames[index], t_len + return self.n_frames[index], self.tgt_lens[index] @property def sizes(self): @@ -397,67 +460,111 @@ def _from_list( cls, split_name: str, is_train_split, - samples: List[List[Dict]], - data_cfg: S2TDataConfig, + samples: List[Dict], + cfg: S2TDataConfig, tgt_dict, pre_tokenizer, bpe_tokenizer, ) -> SpeechToTextDataset: - audio_paths, n_frames, src_texts, tgt_texts, ids = [], [], [], [], [] - speakers, src_langs, tgt_langs = [], [], [] - for s in samples: - ids.extend([ss[cls.KEY_ID] for ss in s]) - audio_paths.extend( - [op.join(data_cfg.audio_root, ss[cls.KEY_AUDIO]) for ss in s] - ) - n_frames.extend([int(ss[cls.KEY_N_FRAMES]) for ss in s]) - tgt_texts.extend([ss[cls.KEY_TGT_TEXT] for ss in s]) - src_texts.extend( - [ss.get(cls.KEY_SRC_TEXT, cls.DEFAULT_SRC_TEXT) for ss in s] - ) - speakers.extend([ss.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for ss in s]) - src_langs.extend([ss.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for ss in s]) - tgt_langs.extend([ss.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for ss in s]) + audio_root = Path(cfg.audio_root) + ids = [s[cls.KEY_ID] for s in samples] + audio_paths = [(audio_root / s[cls.KEY_AUDIO]).as_posix() for s in samples] + n_frames = [int(s[cls.KEY_N_FRAMES]) for s in samples] + tgt_texts = [s[cls.KEY_TGT_TEXT] for s in samples] + src_texts = [s.get(cls.KEY_SRC_TEXT, cls.DEFAULT_SRC_TEXT) for s in samples] + speakers = [s.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for s in samples] + src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] + tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] return SpeechToTextDataset( split_name, is_train_split, - data_cfg, + cfg, audio_paths, n_frames, - src_texts, - tgt_texts, - speakers, - src_langs, - tgt_langs, - ids, - tgt_dict, - pre_tokenizer, - bpe_tokenizer, + src_texts=src_texts, + tgt_texts=tgt_texts, + speakers=speakers, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + tgt_dict=tgt_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, ) @classmethod - def _get_size_ratios(cls, ids: List[str], sizes: List[int], alpha: float = 1.0): + def get_size_ratios( + cls, datasets: List[SpeechToTextDataset], alpha: float = 1.0 + ) -> List[float]: """Size ratios for temperature-based sampling (https://arxiv.org/abs/1907.05019)""" - _sizes = np.array(sizes) - prob = _sizes / _sizes.sum() - smoothed_prob = prob ** alpha - smoothed_prob = smoothed_prob / smoothed_prob.sum() - size_ratio = (smoothed_prob * _sizes.sum()) / _sizes - - o_str = str({_i: f"{prob[i]:.3f}" for i, _i in enumerate(ids)}) - logger.info(f"original sampling probability: {o_str}") - p_str = str({_i: f"{smoothed_prob[i]:.3f}" for i, _i in enumerate(ids)}) - logger.info(f"balanced sampling probability: {p_str}") - sr_str = str({_id: f"{size_ratio[i]:.3f}" for i, _id in enumerate(ids)}) - logger.info(f"balanced sampling size ratio: {sr_str}") - return size_ratio.tolist() + + id_to_lp, lp_to_sz = {}, defaultdict(int) + for ds in datasets: + lang_pairs = {f"{s}->{t}" for s, t in zip(ds.src_langs, ds.tgt_langs)} + assert len(lang_pairs) == 1 + lang_pair = list(lang_pairs)[0] + id_to_lp[ds.split] = lang_pair + lp_to_sz[lang_pair] += sum(ds.n_frames) + + sz_sum = sum(v for v in lp_to_sz.values()) + lp_to_prob = {k: v / sz_sum for k, v in lp_to_sz.items()} + lp_to_tgt_prob = {k: v ** alpha for k, v in lp_to_prob.items()} + prob_sum = sum(v for v in lp_to_tgt_prob.values()) + lp_to_tgt_prob = {k: v / prob_sum for k, v in lp_to_tgt_prob.items()} + lp_to_sz_ratio = { + k: (lp_to_tgt_prob[k] * sz_sum) / v for k, v in lp_to_sz.items() + } + size_ratio = [lp_to_sz_ratio[id_to_lp[ds.split]] for ds in datasets] + + p_formatted = { + k: f"{lp_to_prob[k]:.3f}->{lp_to_tgt_prob[k]:.3f}" for k in lp_to_sz + } + logger.info(f"sampling probability balancing: {p_formatted}") + sr_formatted = {ds.split: f"{r:.3f}" for ds, r in zip(datasets, size_ratio)} + logger.info(f"balanced sampling size ratio: {sr_formatted}") + return size_ratio + + @classmethod + def _load_samples_from_tsv(cls, root: str, split: str): + tsv_path = Path(root) / f"{split}.tsv" + if not tsv_path.is_file(): + raise FileNotFoundError(f"Dataset not found: {tsv_path}") + with open(tsv_path) as f: + reader = csv.DictReader( + f, + delimiter="\t", + quotechar=None, + doublequote=False, + lineterminator="\n", + quoting=csv.QUOTE_NONE, + ) + samples = [dict(e) for e in reader] + if len(samples) == 0: + raise ValueError(f"Empty manifest: {tsv_path}") + return samples + + @classmethod + def _from_tsv( + cls, + root: str, + cfg: S2TDataConfig, + split: str, + tgt_dict, + is_train_split: bool, + pre_tokenizer, + bpe_tokenizer, + ) -> SpeechToTextDataset: + samples = cls._load_samples_from_tsv(root, split) + return cls._from_list( + split, is_train_split, samples, cfg, tgt_dict, pre_tokenizer, bpe_tokenizer + ) @classmethod def from_tsv( cls, root: str, - data_cfg: S2TDataConfig, + cfg: S2TDataConfig, splits: str, tgt_dict, pre_tokenizer, @@ -466,46 +573,21 @@ def from_tsv( epoch: int, seed: int, ) -> SpeechToTextDataset: - samples = [] - _splits = splits.split(",") - for split in _splits: - tsv_path = op.join(root, f"{split}.tsv") - if not op.isfile(tsv_path): - raise FileNotFoundError(f"Dataset not found: {tsv_path}") - with open(tsv_path) as f: - reader = csv.DictReader( - f, - delimiter="\t", - quotechar=None, - doublequote=False, - lineterminator="\n", - quoting=csv.QUOTE_NONE, - ) - samples.append([dict(e) for e in reader]) - assert len(samples) > 0 - datasets = [ - cls._from_list( - name, - is_train_split, - [s], - data_cfg, - tgt_dict, - pre_tokenizer, - bpe_tokenizer, + cls._from_tsv( + root, cfg, split, tgt_dict, is_train_split, pre_tokenizer, bpe_tokenizer ) - for name, s in zip(_splits, samples) + for split in splits.split(",") ] - if is_train_split and len(_splits) > 1 and data_cfg.sampling_alpha != 1.0: + if is_train_split and len(datasets) > 1 and cfg.sampling_alpha != 1.0: # temperature-based sampling - size_ratios = cls._get_size_ratios( - _splits, [len(s) for s in samples], alpha=data_cfg.sampling_alpha - ) + size_ratios = cls.get_size_ratios(datasets, alpha=cfg.sampling_alpha) datasets = [ ResamplingDataset( d, size_ratio=r, seed=seed, epoch=epoch, replace=(r >= 1.0) ) - for d, r in zip(datasets, size_ratios) + for r, d in zip(size_ratios, datasets) ] - return ConcatDataset(datasets) + + return ConcatDataset(datasets) if len(datasets) > 1 else datasets[0] diff --git a/fairseq/data/transform_eos_lang_pair_dataset.py b/fairseq/data/transform_eos_lang_pair_dataset.py index 07ebdd5f38..e21144a88e 100644 --- a/fairseq/data/transform_eos_lang_pair_dataset.py +++ b/fairseq/data/transform_eos_lang_pair_dataset.py @@ -49,6 +49,8 @@ def __len__(self): def collater(self, samples, **extra_args): samples = self.dataset.collater(samples, **extra_args) + if len(samples) == 0: + return samples if 'net_input' not in samples: return samples diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 5c935efaf5..aff9d0ffc7 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -308,7 +308,7 @@ def __init__(self, args): else: self.layer_norm = None - def _forward(self, src_tokens, src_lengths): + def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): x, input_lengths = self.subsample(src_tokens, src_lengths) x = self.embed_scale * x @@ -317,8 +317,12 @@ def _forward(self, src_tokens, src_lengths): x += positions x = self.dropout_module(x) + encoder_states = [] + for layer in self.transformer_layers: x = layer(x, encoder_padding_mask) + if return_all_hiddens: + encoder_states.append(x) if self.layer_norm is not None: x = self.layer_norm(x) @@ -327,17 +331,19 @@ def _forward(self, src_tokens, src_lengths): "encoder_out": [x], # T x B x C "encoder_padding_mask": [encoder_padding_mask] if encoder_padding_mask.any() else [], # B x T "encoder_embedding": [], # B x T x C - "encoder_states": [], # List[T x B x C] + "encoder_states": encoder_states, # List[T x B x C] "src_tokens": [], "src_lengths": [], } - def forward(self, src_tokens, src_lengths): + def forward(self, src_tokens, src_lengths, return_all_hiddens=False): if self.num_updates < self.encoder_freezing_updates: with torch.no_grad(): - x = self._forward(src_tokens, src_lengths) + x = self._forward(src_tokens, src_lengths, + return_all_hiddens=return_all_hiddens) else: - x = self._forward(src_tokens, src_lengths) + x = self._forward(src_tokens, src_lengths, + return_all_hiddens=return_all_hiddens) return x def reorder_encoder_out(self, encoder_out, new_order): diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 8bdf215643..5795c04bf7 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -4,7 +4,7 @@ # LICENSE file in the root directory of this source tree. import logging -import os.path as op +from pathlib import Path from argparse import Namespace from fairseq.data import Dictionary, encoders @@ -22,8 +22,8 @@ @register_task("speech_to_text") class SpeechToTextTask(LegacyFairseqTask): - @staticmethod - def add_args(parser): + @classmethod + def add_args(cls, parser): parser.add_argument("data", help="manifest root path") parser.add_argument( "--config-yaml", @@ -49,15 +49,15 @@ def add_args(parser): def __init__(self, args, tgt_dict): super().__init__(args) self.tgt_dict = tgt_dict - self.data_cfg = S2TDataConfig(op.join(args.data, args.config_yaml)) + self.data_cfg = S2TDataConfig(Path(args.data) / args.config_yaml) @classmethod def setup_task(cls, args, **kwargs): - data_cfg = S2TDataConfig(op.join(args.data, args.config_yaml)) - dict_path = op.join(args.data, data_cfg.vocab_filename) - if not op.isfile(dict_path): - raise FileNotFoundError(f"Dict not found: {dict_path}") - tgt_dict = Dictionary.load(dict_path) + data_cfg = S2TDataConfig(Path(args.data) / args.config_yaml) + dict_path = Path(args.data) / data_cfg.vocab_filename + if not dict_path.is_file(): + raise FileNotFoundError(f"Dict not found: {dict_path.as_posix()}") + tgt_dict = Dictionary.load(dict_path.as_posix()) logger.info( f"dictionary size ({data_cfg.vocab_filename}): " f"{len(tgt_dict):,}" ) @@ -126,7 +126,10 @@ def build_generator( for s, i in self.tgt_dict.indices.items() if SpeechToTextDataset.is_lang_tag(s) } - extra_gen_cls_kwargs = {"symbols_to_strip_from_output": lang_token_ids} + if extra_gen_cls_kwargs is None: + extra_gen_cls_kwargs = {"symbols_to_strip_from_output": lang_token_ids} + else: + extra_gen_cls_kwargs["symbols_to_strip_from_output"] = lang_token_ids return super().build_generator( models, args, seq_gen_cls=None, extra_gen_cls_kwargs=extra_gen_cls_kwargs ) From 75051ecf26239be1b082101b9d1fe8886e734b45 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Tue, 27 Jul 2021 13:24:45 -0700 Subject: [PATCH 423/774] wav2vec2 speech translation OSS Summary: wav2vec2 speech translation OSS - Based on https://github.com/fairinternal/fairseq-py/pull/1829 - Updated `Wav2VecEncoder` API to make it consistent for `Wav2VecCTC` (for ASR) and `Wav2Vec2Seq2Seq` (for ST) - Small fixes in `Wav2Vec2Seq2Seq` - Refactored `audio_pretraining` into `audio_pretraining` and `audio_finetuning` Reviewed By: sravyapopuri388, cndn Differential Revision: D29285182 fbshipit-source-id: 89f93b42caa88079940a4b2cac0f8952547d3ff0 --- examples/wav2vec/README.md | 2 +- .../wav2vec/config/finetuning/base_100h.yaml | 3 +- .../wav2vec/config/finetuning/base_10h.yaml | 3 +- .../wav2vec/config/finetuning/base_10m.yaml | 3 +- .../wav2vec/config/finetuning/base_1h.yaml | 3 +- .../wav2vec/config/finetuning/base_960h.yaml | 3 +- .../wav2vec/config/finetuning/vox_100h.yaml | 3 +- .../wav2vec/config/finetuning/vox_10h.yaml | 3 +- .../wav2vec/config/finetuning/vox_10m.yaml | 3 +- .../wav2vec/config/finetuning/vox_1h.yaml | 3 +- .../wav2vec/config/finetuning/vox_960h.yaml | 3 +- .../config/finetuning/w2v_finetune.yaml | 2 +- fairseq/data/add_target_dataset.py | 6 + fairseq/models/wav2vec/wav2vec2_asr.py | 77 ++-- fairseq/tasks/audio_finetuning.py | 346 ++++++++++++++++++ fairseq/tasks/audio_pretraining.py | 212 +---------- fairseq_cli/generate.py | 6 + 17 files changed, 419 insertions(+), 262 deletions(-) create mode 100644 fairseq/tasks/audio_finetuning.py diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index badfda8979..2d6717dc04 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -143,7 +143,7 @@ Next, run the evaluation command: ```shell script $subset=dev_other -python examples/speech_recognition/infer.py /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw --task audio_pretraining \ +python examples/speech_recognition/infer.py /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw --task audio_finetuning \ --nbest 1 --path /path/to/model --gen-subset $subset --results-path /path/to/save/results/for/sclite --w2l-decoder kenlm \ --lm-model /path/to/kenlm.bin --lm-weight 2 --word-score -1 --sil-weight 0 --criterion ctc --labels ltr --max-tokens 4000000 \ --post-process letter diff --git a/examples/wav2vec/config/finetuning/base_100h.yaml b/examples/wav2vec/config/finetuning/base_100h.yaml index 539dabb047..153b5df170 100644 --- a/examples/wav2vec/config/finetuning/base_100h.yaml +++ b/examples/wav2vec/config/finetuning/base_100h.yaml @@ -10,7 +10,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: false labels: ltr @@ -56,4 +56,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 0 - diff --git a/examples/wav2vec/config/finetuning/base_10h.yaml b/examples/wav2vec/config/finetuning/base_10h.yaml index 16a3c4d96c..5044518025 100644 --- a/examples/wav2vec/config/finetuning/base_10h.yaml +++ b/examples/wav2vec/config/finetuning/base_10h.yaml @@ -13,7 +13,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: false labels: ltr @@ -61,4 +61,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/config/finetuning/base_10m.yaml b/examples/wav2vec/config/finetuning/base_10m.yaml index 3ceb77a252..14abc013bd 100644 --- a/examples/wav2vec/config/finetuning/base_10m.yaml +++ b/examples/wav2vec/config/finetuning/base_10m.yaml @@ -13,7 +13,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: false labels: ltr @@ -61,4 +61,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/config/finetuning/base_1h.yaml b/examples/wav2vec/config/finetuning/base_1h.yaml index 3ceb77a252..14abc013bd 100644 --- a/examples/wav2vec/config/finetuning/base_1h.yaml +++ b/examples/wav2vec/config/finetuning/base_1h.yaml @@ -13,7 +13,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: false labels: ltr @@ -61,4 +61,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/config/finetuning/base_960h.yaml b/examples/wav2vec/config/finetuning/base_960h.yaml index 2d38211e91..3eadc36b37 100644 --- a/examples/wav2vec/config/finetuning/base_960h.yaml +++ b/examples/wav2vec/config/finetuning/base_960h.yaml @@ -10,7 +10,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: false labels: ltr @@ -55,4 +55,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 0 - diff --git a/examples/wav2vec/config/finetuning/vox_100h.yaml b/examples/wav2vec/config/finetuning/vox_100h.yaml index 2fdb0c568c..b8f81e5e18 100644 --- a/examples/wav2vec/config/finetuning/vox_100h.yaml +++ b/examples/wav2vec/config/finetuning/vox_100h.yaml @@ -10,7 +10,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: true labels: ltr @@ -56,4 +56,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/config/finetuning/vox_10h.yaml b/examples/wav2vec/config/finetuning/vox_10h.yaml index f1a979e05d..8f1ca71ee2 100644 --- a/examples/wav2vec/config/finetuning/vox_10h.yaml +++ b/examples/wav2vec/config/finetuning/vox_10h.yaml @@ -13,7 +13,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: true labels: ltr @@ -61,4 +61,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/config/finetuning/vox_10m.yaml b/examples/wav2vec/config/finetuning/vox_10m.yaml index d12439bb28..07e327fe74 100644 --- a/examples/wav2vec/config/finetuning/vox_10m.yaml +++ b/examples/wav2vec/config/finetuning/vox_10m.yaml @@ -13,7 +13,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: true labels: ltr @@ -61,4 +61,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/config/finetuning/vox_1h.yaml b/examples/wav2vec/config/finetuning/vox_1h.yaml index 7f3b04c034..fac1bbb32f 100644 --- a/examples/wav2vec/config/finetuning/vox_1h.yaml +++ b/examples/wav2vec/config/finetuning/vox_1h.yaml @@ -13,7 +13,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: true labels: ltr @@ -61,4 +61,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/config/finetuning/vox_960h.yaml b/examples/wav2vec/config/finetuning/vox_960h.yaml index 0633915bb2..9d72404fa3 100644 --- a/examples/wav2vec/config/finetuning/vox_960h.yaml +++ b/examples/wav2vec/config/finetuning/vox_960h.yaml @@ -10,7 +10,7 @@ checkpoint: best_checkpoint_metric: wer task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: true labels: ltr @@ -55,4 +55,3 @@ model: activation_dropout: 0.1 feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - diff --git a/examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml b/examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml index e94da2ba4e..19a3ef3484 100644 --- a/examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml +++ b/examples/wav2vec/unsupervised/config/finetuning/w2v_finetune.yaml @@ -11,7 +11,7 @@ checkpoint: save_interval_updates: 20000 task: - _name: audio_pretraining + _name: audio_finetuning data: ??? normalize: true labels: ltr diff --git a/fairseq/data/add_target_dataset.py b/fairseq/data/add_target_dataset.py index 673963d0ed..d8a08e746d 100644 --- a/fairseq/data/add_target_dataset.py +++ b/fairseq/data/add_target_dataset.py @@ -71,3 +71,9 @@ def collater(self, samples): ).long() collated["ntokens"] += target.size(0) return collated + + def filter_indices_by_size(self, indices, max_sizes): + indices, ignored = data_utils._filter_by_size_dynamic( + indices, self.size, max_sizes + ) + return indices, ignored diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 04307e8771..eb5d819da5 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -65,6 +65,19 @@ class Wav2Vec2AsrConfig(FairseqDataclass): "help": "dropout probability after activation in FFN inside wav2vec 2.0 model" }, ) + conv_feature_layers: Optional[str] = field( + default="[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]", + metadata={ + "help": ( + "string describing convolutional feature extraction " + "layers in form of a python list that contains " + "[(dim, kernel_size, stride), ...]" + ), + }, + ) + encoder_embed_dim: Optional[int] = field( + default=768, metadata={"help": "encoder embedding dimension"} + ) # masking apply_mask: bool = field( @@ -92,6 +105,10 @@ class Wav2Vec2AsrConfig(FairseqDataclass): no_mask_overlap: bool = field( default=False, metadata={"help": "whether to allow masks to overlap"} ) + mask_min_space: Optional[int] = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) # channel masking mask_channel_length: int = field( @@ -123,6 +140,10 @@ class Wav2Vec2AsrConfig(FairseqDataclass): layerdrop: float = field( default=0.0, metadata={"help": "probability of dropping a layer in wav2vec 2.0"} ) + mask_channel_min_space: Optional[int] = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) mask_channel_before: bool = False normalize: bool = II("task.normalize") data: str = II("task.data") @@ -134,27 +155,6 @@ class Wav2Vec2AsrConfig(FairseqDataclass): class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): blank_weight: float = 0 blank_mode: str = "add" - mask_min_space: Optional[int] = field( - default=1, - metadata={"help": "min space between spans (if no overlap is enabled)"}, - ) - mask_channel_min_space: Optional[int] = field( - default=1, - metadata={"help": "min space between spans (if no overlap is enabled)"}, - ) - conv_feature_layers: Optional[str] = field( - default="[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]", - metadata={ - "help": ( - "string describing convolutional feature extraction " - "layers in form of a python list that contains " - "[(dim, kernel_size, stride), ...]" - ), - }, - ) - encoder_embed_dim: Optional[int] = field( - default=768, metadata={"help": "encoder embedding dimension"} - ) @register_model("wav2vec_ctc", dataclass=Wav2Vec2CtcConfig) @@ -299,7 +299,7 @@ def build_decoder(cls, cfg: Wav2Vec2Seq2SeqConfig, tgt_dict, embed_tokens): return TransformerDecoder(cfg, tgt_dict, embed_tokens) def forward(self, **kwargs): - encoder_out = self.encoder(tbc=False, **kwargs) + encoder_out = self.encoder(**kwargs) decoder_out = self.decoder(encoder_out=encoder_out, **kwargs) return decoder_out @@ -386,7 +386,8 @@ def set_num_updates(self, num_updates): super().set_num_updates(num_updates) self.num_updates = num_updates - def forward(self, source, padding_mask, tbc=True, **kwargs): + def forward(self, source, padding_mask, **kwargs): + w2v_args = { "source": source, "padding_mask": padding_mask, @@ -401,9 +402,8 @@ def forward(self, source, padding_mask, tbc=True, **kwargs): x = res["x"] padding_mask = res["padding_mask"] - if tbc: - # BTC -> TBC - x = x.transpose(0, 1) + # B x T x C -> T x B x C + x = x.transpose(0, 1) x = self.final_dropout(x) @@ -412,21 +412,24 @@ def forward(self, source, padding_mask, tbc=True, **kwargs): return { "encoder_out": x, # T x B x C - "encoder_padding_mask": padding_mask.transpose(0, 1) - if padding_mask is not None - else None, # T x B - "padding_mask": padding_mask, + "padding_mask": padding_mask, # B x T, "layer_results": res["layer_results"], } + def forward_torchscript(self, net_input): + if torch.jit.is_scripting(): + return self.forward(net_input["source"], net_input["padding_mask"]) + else: + return self.forward_non_torchscript(net_input) + def reorder_encoder_out(self, encoder_out, new_order): if encoder_out["encoder_out"] is not None: encoder_out["encoder_out"] = encoder_out["encoder_out"].index_select( 1, new_order ) - if encoder_out["encoder_padding_mask"] is not None: - encoder_out["encoder_padding_mask"] = encoder_out[ - "encoder_padding_mask" + if encoder_out["padding_mask"] is not None: + encoder_out["padding_mask"] = encoder_out[ + "padding_mask" ].index_select(0, new_order) return encoder_out @@ -469,7 +472,7 @@ def __init__( self.layerdrop = cfg.decoder_layerdrop - padding_idx = embed_tokens.padding_idx + self.padding_idx = embed_tokens.padding_idx self.max_target_positions = cfg.max_target_positions self.embed_tokens = embed_tokens @@ -485,7 +488,7 @@ def __init__( PositionalEmbedding( cfg.max_target_positions, embed_dim, - padding_idx, + self.padding_idx, learned=cfg.decoder_learned_pos, ) if not cfg.no_token_positional_embeddings @@ -589,6 +592,9 @@ def extract_features( inner_states = [x] # decoder layers + self_attn_padding_mask = None + if prev_output_tokens.eq(self.padding_idx).any(): + self_attn_padding_mask = prev_output_tokens.eq(self.padding_idx) for layer in self.layers: dropout_probability = np.random.random() if not self.training or (dropout_probability > self.layerdrop): @@ -600,6 +606,7 @@ def extract_features( self_attn_mask=self.buffered_future_mask(x) if incremental_state is None else None, + self_attn_padding_mask=self_attn_padding_mask ) inner_states.append(x) diff --git a/fairseq/tasks/audio_finetuning.py b/fairseq/tasks/audio_finetuning.py new file mode 100644 index 0000000000..4ef87c604f --- /dev/null +++ b/fairseq/tasks/audio_finetuning.py @@ -0,0 +1,346 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import os +import torch +import json + +from argparse import Namespace +from dataclasses import dataclass, field +from typing import Optional, Any + +from fairseq.data import AddTargetDataset, Dictionary, encoders +from fairseq.tasks.audio_pretraining import AudioPretrainingTask, AudioPretrainingConfig +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.configs import GenerationConfig +from fairseq.data.text_compressor import TextCompressor, TextCompressionLevel + +from . import register_task +from .. import utils +from ..logging import metrics + + +logger = logging.getLogger(__name__) + + +class LabelEncoder(object): + def __init__(self, dictionary): + self.dictionary = dictionary + + def __call__(self, label): + return self.dictionary.encode_line( + label, append_eos=False, add_if_not_exist=False + ) + + +def label_len_fn(label): + return len(label.split(" ")) + + +@dataclass +class AudioFinetuningConfig(AudioPretrainingConfig): + # Options for reporting WER metrics during validation. Only applicable to + # Seq2Seq models during fine-tuning + eval_wer: bool = field( + default=False, metadata={"help": "compute WER for Seq2Seq models"} + ) + eval_wer_config: GenerationConfig = field( + default_factory=lambda: GenerationConfig(), + metadata={"help": "beam search config for evaluating wer during training"}, + ) + eval_wer_tokenizer: Any = field( + default=None, + metadata={"help": "tokenizer config for evaluating wer during training"}, + ) + eval_wer_post_process: str = field( + default="letter", + metadata={ + "help": "remove BPE tokens before scoring (can be sentencepiece, letter, and more)" + }, + ) + eval_bleu: bool = field( + default=False, metadata={"help": "evaluation with BLEU scores"} + ) + eval_bleu_detok: Optional[str] = field( + default=None, metadata={ + "help": "detokenize before computing BLEU (e.g., 'moses'); " + "required if using --eval-bleu; use 'space' to disable " + "detokenization; see fairseq.data.encoders for other options" + } + ) + eval_bleu_detok_args: str = field( + default="{}", + metadata={"help": "args for building the tokenizer, if needed"} + ) + eval_tokenized_bleu: bool = field( + default=False, + metadata={"help": "compute tokenized BLEU instead of sacrebleu"} + ) + eval_bleu_remove_bpe: Optional[str] = field( + default=None, metadata={"help": "remove BPE before computing BLEU"} + ) + eval_bleu_args: str = field( + default="{}", + metadata={"help": "generation args for BLUE scoring, e.g., " + "'{\"beam\": 4, \"lenpen\": 0.6}'"} + ) + eval_bleu_print_samples: bool = field( + default=False, + metadata={"help": "print sample generations during validation"} + ) + autoregressive: bool = field( + default=False, + metadata={ + "help": "required for autoregressive decoders (like seq2seq models); " + "adds 'prev_output_tokens' to input and appends eos to target" + }, + ) + + +@register_task("audio_finetuning", dataclass=AudioFinetuningConfig) +class AudioFinetuningTask(AudioPretrainingTask): + """ """ + + cfg: AudioFinetuningConfig + + def __init__( + self, + cfg: AudioFinetuningConfig, + ): + super().__init__(cfg) + self.blank_symbol = "<s>" + + self.state.add_factory("target_dictionary", self.load_target_dictionary) + + def load_target_dictionary(self): + if self.cfg.labels: + dict_path = os.path.join(self.cfg.data, f"dict.{self.cfg.labels}.txt") + return Dictionary.load(dict_path) + return None + + def load_dataset(self, split: str, task_cfg: AudioFinetuningConfig = None, **kwargs): + super().load_dataset(split, task_cfg, **kwargs) + + task_cfg = task_cfg or self.cfg + assert task_cfg.labels is not None + text_compression_level = getattr( + TextCompressionLevel, str(self.cfg.text_compression_level) + ) + data_path = self.cfg.data + label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") + skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) + text_compressor = TextCompressor(level=text_compression_level) + with open(label_path, "r") as f: + labels = [ + text_compressor.compress(l) + for i, l in enumerate(f) if i not in skipped_indices + ] + + assert len(labels) == len(self.datasets[split]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.datasets[split])}) do not match" + ) + + process_label = LabelEncoder(self.target_dictionary) + + self.datasets[split] = AddTargetDataset( + self.datasets[split], + labels, + pad=self.target_dictionary.pad(), + eos=self.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + label_len_fn=label_len_fn, + add_to_input=task_cfg.get("autoregressive", False), + text_compression_level=text_compression_level + ) + + @property + def target_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.state.target_dictionary + + def valid_step(self, sample, model, criterion): + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + if self.cfg.eval_wer and self.cfg.autoregressive: + metrics = self._inference_with_wer(self.sequence_generator, sample, model) + logging_output["_num_char_errors"] = metrics["num_char_errors"] + logging_output["_num_chars"] = metrics["num_chars"] + logging_output["_num_word_errors"] = metrics["num_word_errors"] + logging_output["_num_words"] = metrics["num_words"] + if self.cfg.eval_bleu and self.cfg.autoregressive: + metrics = self._inference_with_bleu(self.sequence_generator, sample, model) + logging_output['_bleu_sys_len'] = metrics.sys_len + logging_output['_bleu_ref_len'] = metrics.ref_len + # we split counts into separate entries so that they can be + # summed efficiently across workers using fast-stat-sync + assert len(metrics.counts) == 4 + for i in range(4): + logging_output[f"_bleu_counts_{i}"] = metrics.counts[i] + logging_output[f"_bleu_totals_{i}"] = metrics.totals[i] + return loss, sample_size, logging_output + + def build_model(self, model_cfg: FairseqDataclass): + model = super().build_model(model_cfg) + + if self.cfg.eval_wer and self.cfg.autoregressive: + self.sequence_generator = self.build_generator( + [model], + self.cfg.eval_wer_config, + ) + if self.cfg.eval_wer_tokenizer: + self.tokenizer = encoders.build_tokenizer(self.cfg.eval_wer_tokenizer) + else: + self.tokenizer = None + if self.cfg.eval_bleu and self.cfg.autoregressive: + assert self.cfg.eval_bleu_detok is not None, ( + '--eval-bleu-detok is required if using --eval-bleu; ' + 'try --eval-bleu-detok=moses (or --eval-bleu-detok=space ' + 'to disable detokenization, e.g., when using sentencepiece)' + ) + detok_args = json.loads(self.cfg.eval_bleu_detok_args) + self.tokenizer = encoders.build_tokenizer( + Namespace(tokenizer=self.cfg.eval_bleu_detok, **detok_args) + ) + gen_args = json.loads(self.cfg.eval_bleu_args) + gen_args = Namespace(**gen_args) + self.sequence_generator = self.build_generator([model], gen_args) + + return model + + def _inference_with_wer(self, generator, sample, model): + import editdistance + + def decode(toks): + s = self.target_dictionary.string( + toks.int().cpu(), + self.cfg.eval_wer_post_process, + escape_unk=True, + ) + if self.tokenizer: + s = self.tokenizer.decode(s) + return s + + num_word_errors, num_char_errors = 0, 0 + num_chars, num_words = 0, 0 + gen_out = self.inference_step(generator, [model], sample, None) + for i in range(len(gen_out)): + hyp = decode(gen_out[i][0]["tokens"]) + ref = decode( + utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), + ) + num_char_errors += editdistance.eval(hyp, ref) + num_chars += len(ref) + hyp_words = hyp.split() + ref_words = ref.split() + num_word_errors += editdistance.eval(hyp_words, ref_words) + num_words += len(ref_words) + + return { + "num_char_errors": num_char_errors, + "num_chars": num_chars, + "num_word_errors": num_word_errors, + "num_words": num_words, + } + + def _inference_with_bleu(self, generator, sample, model): + import sacrebleu + + def decode(toks, is_ref): + s = self.target_dictionary.string( + toks.int().cpu(), + self.cfg.eval_bleu_remove_bpe, + # The default unknown string in fairseq is `<unk>`, but + # this is tokenized by sacrebleu as `< unk >`, inflating + # BLEU scores. Instead, we use a somewhat more verbose + # alternative that is unlikely to appear in the real + # reference, but doesn't get split into multiple tokens. + unk_string=( + "UNKNOWNTOKENINREF" if is_ref else "UNKNOWNTOKENINHYP" + ), + ) + if self.tokenizer: + s = self.tokenizer.decode(s) + return s + + gen_out = self.inference_step(generator, [model], sample) + hyps, refs = [], [] + for i in range(len(gen_out)): + hyps.append(decode(gen_out[i][0]['tokens'], is_ref=False)) + refs.append( + decode( + utils.strip_pad( + sample['target'][i], + self.target_dictionary.pad() + ), + is_ref=True, # don't count <unk> as matches to the hypo + ) + ) + if self.cfg.eval_bleu_print_samples: + logger.info('H-{} {}'.format(sample["id"][0], hyps[0])) + logger.info('T-{} {}'.format(sample["id"][0], refs[0])) + + eval_tokenization = 'none' if self.cfg.eval_tokenized_bleu else '13a' + return sacrebleu.corpus_bleu(hyps, [refs], tokenize=eval_tokenization) + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + if self.cfg.eval_wer: + zero = torch.scalar_tensor(0.0) + num_char_errors = sum( + log.get("_num_char_errors", zero) for log in logging_outputs + ) + num_chars = sum(log.get("_num_chars", zero) for log in logging_outputs) + num_word_errors = sum( + log.get("_num_word_errors", zero) for log in logging_outputs + ) + num_words = sum(log.get("_num_words", zero) for log in logging_outputs) + metrics.log_scalar("_num_char_errors", num_char_errors) + metrics.log_scalar("_num_chars", num_chars) + metrics.log_scalar("_num_word_errors", num_word_errors) + metrics.log_scalar("_num_words", num_words) + if num_chars > 0: + metrics.log_derived( + "uer", + lambda meters: meters["_num_char_errors"].sum + * 100.0 + / meters["_num_chars"].sum + if meters["_num_chars"].sum > 0 + else float("nan"), + ) + if num_words > 0: + metrics.log_derived( + "wer", + lambda meters: meters["_num_word_errors"].sum + * 100.0 + / meters["_num_words"].sum + if meters["_num_words"].sum > 0 + else float("nan"), + ) + if self.cfg.eval_bleu: + len_keys = ["_bleu_sys_len", "_bleu_ref_len"] + count_keys = [f"_bleu_counts_{i}" for i in range(4)] + total_keys = [f"_bleu_totals_{i}" for i in range(4)] + for k in len_keys + count_keys + total_keys: + metrics.log_scalar( + k, sum(log.get(k, 0) for log in logging_outputs) + ) + + import sacrebleu + metrics.log_derived( + 'bleu', + lambda meters: sacrebleu.compute_bleu( + correct=[meters[k].sum for k in count_keys], + total=[meters[k].sum for k in total_keys], + sys_len=meters['_bleu_sys_len'].sum, + ref_len=meters['_bleu_ref_len'].sum, + smooth_method="exp" + ).score + ) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index b7d0f3da57..c99c6bf7d1 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -8,46 +8,22 @@ import logging import os import sys -import torch from argparse import Namespace from dataclasses import dataclass, field -from typing import Optional, Any +from typing import Optional from omegaconf import MISSING, II, OmegaConf -from fairseq.data import ( - AddTargetDataset, - BinarizedAudioDataset, - Dictionary, - FileAudioDataset, - encoders, -) +from fairseq.data import BinarizedAudioDataset, FileAudioDataset from fairseq.dataclass import FairseqDataclass, ChoiceEnum -from fairseq.dataclass.configs import GenerationConfig -from fairseq.data.text_compressor import TextCompressor, TextCompressionLevel +from fairseq.data.text_compressor import TextCompressionLevel from . import FairseqTask, register_task -from .. import utils -from ..logging import metrics logger = logging.getLogger(__name__) -class LabelEncoder(object): - def __init__(self, dictionary): - self.dictionary = dictionary - - def __call__(self, label): - return self.dictionary.encode_line( - label, append_eos=False, add_if_not_exist=False - ) - - -def label_len_fn(label): - return len(label.split(" ")) - - @dataclass class InferredW2vConfig: # The following are needed to precompute mask and mask channel indices @@ -74,7 +50,8 @@ class AudioPretrainingConfig(FairseqDataclass): data: str = field(default=MISSING, metadata={"help": "path to data directory"}) labels: Optional[str] = field( default=None, - metadata={"help": "extension of the label file to load, used for fine-tuning"}, + metadata={ + "help": "extension of the label file to load, used for fine-tuning"}, ) binarized_dataset: bool = field( default=False, @@ -102,33 +79,6 @@ class AudioPretrainingConfig(FairseqDataclass): min_sample_size: Optional[int] = field( default=None, metadata={"help": "min sample size to skip small examples"} ) - - # Options for reporting WER metrics during validation. Only applicable to - # Seq2Seq models during fine-tuning - eval_wer: bool = field( - default=False, metadata={"help": "compute WER for Seq2Seq models"} - ) - eval_wer_config: GenerationConfig = field( - default_factory=lambda: GenerationConfig(), - metadata={"help": "beam search config for evaluating wer during training"}, - ) - eval_wer_tokenizer: Any = field( - default=None, - metadata={"help": "tokenizer config for evaluating wer during training"}, - ) - eval_wer_post_process: str = field( - default="letter", - metadata={ - "help": "remove BPE tokens before scoring (can be sentencepiece, letter, and more)" - }, - ) - autoregressive: bool = field( - default=False, - metadata={ - "help": "required for autoregressive decoders (like seq2seq models); " - "adds 'prev_output_tokens' to input and appends eos to target" - }, - ) num_batch_buckets: int = field( default=0, metadata={"help": "number of buckets"}, @@ -163,17 +113,6 @@ class AudioPretrainingTask(FairseqTask): cfg: AudioPretrainingConfig - def __init__( - self, - cfg: AudioPretrainingConfig, - ): - super().__init__(cfg) - if cfg.eval_wer: - assert cfg.labels is not None, "eval_wer can only be set during fine-tuning" - self.blank_symbol = "<s>" - - self.state.add_factory("target_dictionary", self.load_target_dictionary) - @classmethod def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): """Setup the task (e.g., load dictionaries). @@ -184,12 +123,6 @@ def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): return cls(cfg) - def load_target_dictionary(self): - if self.cfg.labels: - dict_path = os.path.join(self.cfg.data, f"dict.{self.cfg.labels}.txt") - return Dictionary.load(dict_path) - return None - def _get_mask_precompute_kwargs(self, cfg): if self.cfg.precompute_mask_indices or self.cfg.tpu: assert ( @@ -249,155 +182,24 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): "0. You may want to set this to a low value close to 0." ) - if task_cfg.labels: - label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") - skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) - text_compressor = TextCompressor(level=text_compression_level) - with open(label_path, "r") as f: - labels = [ - text_compressor.compress(l) - for i, l in enumerate(f) if i not in skipped_indices - ] - - assert len(labels) == len(self.datasets[split]), ( - f"labels length ({len(labels)}) and dataset length " - f"({len(self.datasets[split])}) do not match" - ) - - process_label = LabelEncoder(self.target_dictionary) - - self.datasets[split] = AddTargetDataset( - self.datasets[split], - labels, - pad=self.target_dictionary.pad(), - eos=self.target_dictionary.eos(), - batch_targets=True, - process_label=process_label, - label_len_fn=label_len_fn, - add_to_input=task_cfg.get("autoregressive", False), - text_compression_level=text_compression_level - ) - @property def source_dictionary(self): return None @property def target_dictionary(self): - """Return the :class:`~fairseq.data.Dictionary` for the language - model.""" - return self.state.target_dictionary + return None def max_positions(self): """Maximum input length supported by the encoder.""" - return (sys.maxsize, sys.maxsize) - - def filter_indices_by_size( - self, - indices, - dataset, - max_positions=None, - ignore_invalid_inputs=False, - ): - # we do not need to filter by size in this task as dataloaders take care of this - return indices - - def valid_step(self, sample, model, criterion): - loss, sample_size, logging_output = super().valid_step(sample, model, criterion) - if self.cfg.eval_wer and self.cfg.autoregressive: - metrics = self._inference_with_wer(self.sequence_generator, sample, model) - logging_output["_num_char_errors"] = metrics["num_char_errors"] - logging_output["_num_chars"] = metrics["num_chars"] - logging_output["_num_word_errors"] = metrics["num_word_errors"] - logging_output["_num_words"] = metrics["num_words"] - return loss, sample_size, logging_output + return sys.maxsize, sys.maxsize def build_model(self, model_cfg: FairseqDataclass): model = super().build_model(model_cfg) - if self.cfg.eval_wer and self.cfg.autoregressive: - self.sequence_generator = self.build_generator( - [model], - self.cfg.eval_wer_config, - ) - if self.cfg.eval_wer_tokenizer: - self.tokenizer = encoders.build_tokenizer(self.cfg.eval_wer_tokenizer) - else: - self.tokenizer = None - actualized_cfg = getattr(model, "cfg", None) if actualized_cfg is not None: if "w2v_args" in actualized_cfg: model_cfg.w2v_args = actualized_cfg.w2v_args return model - - def _inference_with_wer(self, generator, sample, model): - import editdistance - - def decode(toks): - s = self.target_dictionary.string( - toks.int().cpu(), - self.cfg.eval_wer_post_process, - escape_unk=True, - ) - if self.tokenizer: - s = self.tokenizer.decode(s) - return s - - num_word_errors, num_char_errors = 0, 0 - num_chars, num_words = 0, 0 - gen_out = self.inference_step(generator, [model], sample, None) - for i in range(len(gen_out)): - hyp = decode(gen_out[i][0]["tokens"]) - ref = decode( - utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), - ) - num_char_errors += editdistance.eval(hyp, ref) - num_chars += len(ref) - hyp_words = hyp.split() - ref_words = ref.split() - num_word_errors += editdistance.eval(hyp_words, ref_words) - num_words += len(ref_words) - - return { - "num_char_errors": num_char_errors, - "num_chars": num_chars, - "num_word_errors": num_word_errors, - "num_words": num_words, - } - - def reduce_metrics(self, logging_outputs, criterion): - super().reduce_metrics(logging_outputs, criterion) - - zero = torch.scalar_tensor(0.0) - num_char_errors = sum( - log.get("_num_char_errors", zero) for log in logging_outputs - ) - num_chars = sum(log.get("_num_chars", zero) for log in logging_outputs) - num_word_errors = sum( - log.get("_num_word_errors", zero) for log in logging_outputs - ) - num_words = sum(log.get("_num_words", zero) for log in logging_outputs) - metrics.log_scalar("_num_char_errors", num_char_errors) - metrics.log_scalar("_num_chars", num_chars) - metrics.log_scalar("_num_word_errors", num_word_errors) - metrics.log_scalar("_num_words", num_words) - if num_chars > 0: - metrics.log_derived( - "uer", - lambda meters: meters["_num_char_errors"].sum - * 100.0 - / meters["_num_chars"].sum - if meters["_num_chars"].sum > 0 - else float("nan"), - ) - if num_words > 0: - metrics.log_derived( - "wer", - lambda meters: meters["_num_word_errors"].sum - * 100.0 - / meters["_num_words"].sum - if meters["_num_words"].sum > 0 - else float("nan"), - ) diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 7bd582b256..c9ea52493d 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -400,6 +400,12 @@ def decode_fn(x): def cli_main(): parser = options.get_generation_parser() + # TODO: replace this workaround with refactoring of `AudioPretraining` + parser.add_argument( + '--arch', '-a', metavar='ARCH', default="transformer", + help='Model architecture. For constructing tasks that rely on ' + 'model args (e.g. `AudioPretraining`)' + ) args = options.parse_args_and_arch(parser) main(args) From 440def26c167af762ae8e8fc64716e1b88f3968b Mon Sep 17 00:00:00 2001 From: Edan Tessel Sneh <edan@fb.com> Date: Wed, 28 Jul 2021 14:58:47 -0700 Subject: [PATCH 424/774] added more descriptive comment to urgent change Summary: Added description of problem and task associated with it in code Reviewed By: dianaml0 Differential Revision: D29942196 fbshipit-source-id: 037d92af720f52bdd51f4efc5b9d49a6465cdd31 --- fairseq/models/transformer/transformer_base.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fairseq/models/transformer/transformer_base.py b/fairseq/models/transformer/transformer_base.py index 49fd30e502..810c9b98db 100644 --- a/fairseq/models/transformer/transformer_base.py +++ b/fairseq/models/transformer/transformer_base.py @@ -11,8 +11,12 @@ from fairseq.dataclass.utils import gen_parser_from_dataclass from fairseq.distributed import fsdp_wrap from fairseq.models import FairseqEncoderDecoderModel +from fairseq.models.transformer import ( + TransformerEncoderBase, + TransformerDecoderBase, + TransformerConfig, +) from torch import Tensor -from fairseq.models.transformer import (TransformerEncoderBase, TransformerDecoderBase, TransformerConfig) class TransformerModelBase(FairseqEncoderDecoderModel): @@ -49,14 +53,16 @@ def add_args(parser): def build_model(cls, cfg, task): """Build a new model instance.""" - # hacky fixes for issue with II + # -- TODO T96535332 + # bug caused by interaction between OmegaConf II and argparsing cfg.decoder.input_dim = int(cfg.decoder.input_dim) cfg.decoder.output_dim = int(cfg.decoder.output_dim) + # -- if cfg.encoder.layers_to_keep: - cfg.encoder.layers = len(cfg.encoder.layers_to_keep.split(',')) + cfg.encoder.layers = len(cfg.encoder.layers_to_keep.split(",")) if cfg.decoder.layers_to_keep: - cfg.decoder.layers = len(cfg.decoder.layers_to_keep.split(',')) + cfg.decoder.layers = len(cfg.decoder.layers_to_keep.split(",")) src_dict, tgt_dict = task.source_dictionary, task.target_dictionary From 1df3e50a2f3d93cd815d2a8730d6a3c8271af891 Mon Sep 17 00:00:00 2001 From: Henry Hu <henryhu6@fb.com> Date: Thu, 29 Jul 2021 12:03:01 -0700 Subject: [PATCH 425/774] Minor performance optimization for sequence generator Summary: Minor performance optimization for sequence generator finalize_hypos function. Reviewed By: myleott Differential Revision: D29784509 fbshipit-source-id: ac42dda75995cea3750c8d4ef07d8950a891c5f8 --- fairseq/sequence_generator.py | 53 +++++++++++++++-------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index ac04dc7db8..d9c906ceea 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -654,44 +654,38 @@ def finalize_hypos( prev += 1 else: cum_unfin.append(prev) + cum_fin_tensor = torch.tensor(cum_unfin, dtype=torch.int).to(bbsz_idx) - # The keys here are of the form "{sent}_{unfin_idx}", where + unfin_idx = bbsz_idx // beam_size + sent = unfin_idx + torch.index_select(cum_fin_tensor, 0, unfin_idx) + + # Create a set of "{sent}{unfin_idx}", where # "unfin_idx" is the index in the current (possibly reduced) # list of sentences, and "sent" is the index in the original, # unreduced batch - # set() is not supported in script export - sents_seen: Dict[str, Optional[Tensor]] = {} - # For every finished beam item - for i in range(bbsz_idx.size()[0]): - idx = bbsz_idx[i] - score = eos_scores[i] - # sentence index in the current (possibly reduced) batch - unfin_idx = idx // beam_size - # sentence index in the original (unreduced) batch - sent = unfin_idx + cum_unfin[unfin_idx] - # Cannot create dict for key type '(int, int)' in torchscript. - # The workaround is to cast int to string - seen = str(sent.item()) + "_" + str(unfin_idx.item()) - if seen not in sents_seen: - sents_seen[seen] = None - - if self.match_source_len and step > src_lengths[unfin_idx]: - score = torch.tensor(-math.inf).to(score) + # sentence index in the current (possibly reduced) batch + seen = (sent << 32) + unfin_idx + unique_seen: List[int] = torch.unique(seen).tolist() + if self.match_source_len: + condition = step > torch.index_select(src_lengths, 0, unfin_idx) + eos_scores = torch.where(condition, torch.tensor(-math.inf), eos_scores) + sent_list: List[int] = sent.tolist() + for i in range(bbsz_idx.size()[0]): # An input sentence (among those in a batch) is finished when # beam_size hypotheses have been collected for it - if len(finalized[sent]) < beam_size: + if len(finalized[sent_list[i]]) < beam_size: if attn_clone is not None: # remove padding tokens from attn scores hypo_attn = attn_clone[i] else: hypo_attn = torch.empty(0) - finalized[sent].append( + finalized[sent_list[i]].append( { "tokens": tokens_clone[i], - "score": score, + "score": eos_scores[i], "attention": hypo_attn, # src_len x tgt_len "alignment": torch.empty(0), "positional_scores": pos_scores[i], @@ -699,17 +693,16 @@ def finalize_hypos( ) newly_finished: List[int] = [] - - for seen in sents_seen.keys(): + for unique_s in unique_seen: # check termination conditions for this sentence - sent: int = int(float(seen.split("_")[0])) - unfin_idx: int = int(float(seen.split("_")[1])) + unique_sent: int = unique_s >> 32 + unique_unfin_idx: int = unique_s - (unique_sent << 32) - if not finished[sent] and self.is_finished( - step, unfin_idx, max_len, len(finalized[sent]), beam_size + if not finished[unique_sent] and self.is_finished( + step, unique_unfin_idx, max_len, len(finalized[unique_sent]), beam_size ): - finished[sent] = True - newly_finished.append(unfin_idx) + finished[unique_sent] = True + newly_finished.append(unique_unfin_idx) return newly_finished From f1b447075844e7cb912879786c787e30d413ebda Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Thu, 29 Jul 2021 15:59:22 -0700 Subject: [PATCH 426/774] use suffix when saving best checkpoints with metric Summary: This is needed when training with FSDP + sharded state, as the checkpoints should have `-shard0.pt` Reviewed By: sshleifer Differential Revision: D29947728 fbshipit-source-id: d2cb7c23e1e6d027d115cb734e2f2f1c34239eba --- fairseq/checkpoint_utils.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 35cce7fda7..aba1e9f725 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -82,18 +82,21 @@ def is_better(a, b): worst_best = getattr(save_checkpoint, "best", None) chkpts = checkpoint_paths( cfg.save_dir, - pattern=r"checkpoint\.best_{}_(\d+\.?\d*)\.pt".format( - cfg.best_checkpoint_metric + pattern=r"checkpoint\.best_{}_(\d+\.?\d*){}\.pt".format( + cfg.best_checkpoint_metric, suffix ), ) if len(chkpts) > 0: p = chkpts[-1] if cfg.maximize_best_checkpoint_metric else chkpts[0] - worst_best = float(p.rsplit("_")[-1].replace(".pt", "")) + worst_best = float(p.rsplit("_")[-1].replace("{}.pt".format(suffix), "")) # add random digits to resolve ties rand_sfx = randint(0, cfg.keep_best_checkpoints) checkpoint_conds[ - "checkpoint.best_{}_{:.3f}{}.pt".format( - cfg.best_checkpoint_metric, val_loss, rand_sfx + "checkpoint.best_{}_{:.3f}{}{}.pt".format( + cfg.best_checkpoint_metric, + val_loss, + rand_sfx, + suffix ) ] = worst_best is None or is_better(val_loss, worst_best) checkpoint_conds[ From 3cf9053ea260c0de31beaa8948ee4acae2221ba1 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Thu, 29 Jul 2021 15:59:22 -0700 Subject: [PATCH 427/774] use pathmanager to delete old checkpoints Summary: --keep-best-checkpoints doesn't work for Manifold paths because the current code assumes normal paths. Lets use PathManager to properly remove them. Reviewed By: myleott, sshleifer Differential Revision: D29947965 fbshipit-source-id: 237a7b5aaa8293bb203ad05937decdf3b3ae2fc0 --- fairseq/checkpoint_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index aba1e9f725..de2b3eaecd 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -164,6 +164,8 @@ def is_better(a, b): for old_chk in checkpoints[cfg.keep_last_epochs :]: if os.path.lexists(old_chk): os.remove(old_chk) + elif PathManager.exists(old_chk): + PathManager.rm(old_chk) if cfg.keep_best_checkpoints > 0: # only keep the best N checkpoints according to validation metric @@ -178,6 +180,8 @@ def is_better(a, b): for old_chk in checkpoints[cfg.keep_best_checkpoints :]: if os.path.lexists(old_chk): os.remove(old_chk) + elif PathManager.exists(old_chk): + PathManager.rm(old_chk) def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): From 777bba3a41bb92aecc611037e49b1e42fee24836 Mon Sep 17 00:00:00 2001 From: Alex Xiao <axiao@fb.com> Date: Thu, 29 Jul 2021 15:59:22 -0700 Subject: [PATCH 428/774] seed random suffix in checkpoint to be consistent across shards Summary: Currently the random suffix for saving sharded checkpoints can be different for each shard when training with FSDP and use_sharded_state=True. This makes it difficult for downstream applications to load the checkpoints properly, since each shard may have different suffixes. This diff seeds the random suffix to be consistent across shards Reviewed By: zhengwy888 Differential Revision: D29951167 fbshipit-source-id: 65749357e62a28978f3b46b71767204a508e1f61 --- fairseq/checkpoint_utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index de2b3eaecd..daabba4574 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -7,15 +7,16 @@ import collections import contextlib import logging +import numpy as np import os import re import time import traceback from collections import OrderedDict from typing import Any, Dict, Optional, Union -from random import randint import torch +from fairseq.data import data_utils from fairseq.dataclass.configs import CheckpointConfig from fairseq.dataclass.utils import ( convert_namespace_to_omegaconf, @@ -90,7 +91,9 @@ def is_better(a, b): p = chkpts[-1] if cfg.maximize_best_checkpoint_metric else chkpts[0] worst_best = float(p.rsplit("_")[-1].replace("{}.pt".format(suffix), "")) # add random digits to resolve ties - rand_sfx = randint(0, cfg.keep_best_checkpoints) + with data_utils.numpy_seed(epoch, updates, val_loss): + rand_sfx = np.random.randint(0, cfg.keep_best_checkpoints) + checkpoint_conds[ "checkpoint.best_{}_{:.3f}{}{}.pt".format( cfg.best_checkpoint_metric, From 7a6706f5a3cd9995c9370ec7adcd2da454aecd97 Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Thu, 29 Jul 2021 17:43:20 -0700 Subject: [PATCH 429/774] Add speech/text joint training for speech to text task (step 2) Summary: Add scripts for speech/text joint training for the speech to text task. It includes scripts/recipes from the following papers "A General Multi-Task Learning Framework to Leverage Text Data for Speech to Text Tasks", ICASSP 2021 "Improving Speech Translation by Understanding and Learning from the Auxiliary Text Translation Task", ACL 2021 "FST: the FAIR Speech Translation System for the IWSLT21 Multilingual Shared Task", IWSLT 2021 Reviewed By: kahne Differential Revision: D29820444 fbshipit-source-id: 925eaedb69233e0a6f4c110045db63a6007a2b60 --- examples/speech_text_joint_to_text/README.md | 46 + .../speech_text_joint_to_text/__init__.py | 6 + .../configs/mustc_noise.list | 49 + .../criterions/__init__.py | 15 + .../text_guide_cross_entropy_acc.py | 223 ++++ .../docs/ende-mustc.md | 112 ++ .../docs/iwslt2021.md | 76 ++ .../models/__init__.py | 14 + .../models/s2t_dualinputtransformer.py | 1090 +++++++++++++++++ .../models/s2t_dualinputxmtransformer.py | 584 +++++++++ .../scripts/g2p_encode.py | 191 +++ .../tasks/__init__.py | 12 + .../tasks/speech_text_joint.py | 372 ++++++ fairseq/data/audio/multi_modality_dataset.py | 263 ++++ .../audio/speech_to_text_joint_dataset.py | 288 +++++ fairseq/data/iterators.py | 125 ++ fairseq/models/speech_to_text/__init__.py | 3 +- .../models/speech_to_text/xm_transformer.py | 504 ++++++++ 18 files changed, 3972 insertions(+), 1 deletion(-) create mode 100644 examples/speech_text_joint_to_text/README.md create mode 100644 examples/speech_text_joint_to_text/__init__.py create mode 100644 examples/speech_text_joint_to_text/configs/mustc_noise.list create mode 100644 examples/speech_text_joint_to_text/criterions/__init__.py create mode 100644 examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py create mode 100644 examples/speech_text_joint_to_text/docs/ende-mustc.md create mode 100644 examples/speech_text_joint_to_text/docs/iwslt2021.md create mode 100644 examples/speech_text_joint_to_text/models/__init__.py create mode 100644 examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py create mode 100644 examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py create mode 100644 examples/speech_text_joint_to_text/scripts/g2p_encode.py create mode 100644 examples/speech_text_joint_to_text/tasks/__init__.py create mode 100644 examples/speech_text_joint_to_text/tasks/speech_text_joint.py create mode 100644 fairseq/data/audio/multi_modality_dataset.py create mode 100644 fairseq/data/audio/speech_to_text_joint_dataset.py create mode 100644 fairseq/models/speech_to_text/xm_transformer.py diff --git a/examples/speech_text_joint_to_text/README.md b/examples/speech_text_joint_to_text/README.md new file mode 100644 index 0000000000..e071d241e0 --- /dev/null +++ b/examples/speech_text_joint_to_text/README.md @@ -0,0 +1,46 @@ +# Joint Speech Text training in Fairseq +An extension of Fairseq s2t project with the speech to text task enhanced by the co-trained text to text mapping task. More details about Fairseq s2t can be found [here](../speech_to_text/README.md) + +## Examples +Examples of speech text joint training in fairseq +- [English-to-German MuST-C model](docs/ende-mustc.md) +- [IWSLT 2021 Multilingual Speech Translation](docs/iwslt2021.md) + +## Citation +Please cite as: +``` +@inproceedings{Tang2021AGM, + title={A General Multi-Task Learning Framework to Leverage Text Data for Speech to Text Tasks}, + author={Yun Tang and J. Pino and Changhan Wang and Xutai Ma and Dmitriy Genzel}, + booktitle={ICASSP}, + year={2021} +} + +@inproceedings{Tang2021IST, + title = {Improving Speech Translation by Understanding and Learning from the Auxiliary Text Translation Task}, + author = {Yun Tang and Juan Pino and Xian Li and Changhan Wang and Dmitriy Genzel}, + booktitle = {ACL}, + year = {2021}, +} + +@inproceedings{Tang2021FST, + title = {FST: the FAIR Speech Translation System for the IWSLT21 Multilingual Shared Task}, + author = {Yun Tang and Hongyu Gong and Xian Li and Changhan Wang and Juan Pino and Holger Schwenk and Naman Goyal}, + booktitle = {IWSLT}, + year = {2021}, +} + +@inproceedings{wang2020fairseqs2t, + title = {fairseq S2T: Fast Speech-to-Text Modeling with fairseq}, + author = {Changhan Wang and Yun Tang and Xutai Ma and Anne Wu and Dmytro Okhonko and Juan Pino}, + booktitle = {Proceedings of the 2020 Conference of the Asian Chapter of the Association for Computational Linguistics (AACL): System Demonstrations}, + year = {2020}, +} + +@inproceedings{ott2019fairseq, + title = {fairseq: A Fast, Extensible Toolkit for Sequence Modeling}, + author = {Myle Ott and Sergey Edunov and Alexei Baevski and Angela Fan and Sam Gross and Nathan Ng and David Grangier and Michael Auli}, + booktitle = {Proceedings of NAACL-HLT 2019: Demonstrations}, + year = {2019}, +} +``` diff --git a/examples/speech_text_joint_to_text/__init__.py b/examples/speech_text_joint_to_text/__init__.py new file mode 100644 index 0000000000..239d2e69f9 --- /dev/null +++ b/examples/speech_text_joint_to_text/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from . import tasks, criterions, models # noqa diff --git a/examples/speech_text_joint_to_text/configs/mustc_noise.list b/examples/speech_text_joint_to_text/configs/mustc_noise.list new file mode 100644 index 0000000000..02eeac4e00 --- /dev/null +++ b/examples/speech_text_joint_to_text/configs/mustc_noise.list @@ -0,0 +1,49 @@ +"(Applause) NOISE +"(Laughter) VOICE +"(Laughter)" VOICE +(Applause) NOISE +(Applause). NOISE +(Audience) VOICE +(Audio) NOISE +(Beat) NOISE +(Beatboxing) VOICE +(Beep) NOISE +(Beeps) NOISE +(Cheering) VOICE +(Cheers) VOICE +(Claps) NOISE +(Clicking) NOISE +(Clunk) NOISE +(Coughs) NOISE +(Drums) NOISE +(Explosion) NOISE +(Gasps) VOICE +(Guitar) NOISE +(Honk) NOISE +(Laugher) VOICE +(Laughing) VOICE +(Laughs) VOICE +(Laughter) VOICE +(Laughter). VOICE +(Laughter)... VOICE +(Mumbling) VOICE +(Music) NOISE +(Noise) NOISE +(Recording) VOICE +(Ringing) NOISE +(Shouts) VOICE +(Sigh) VOICE +(Sighs) VOICE +(Silence) NOISE +(Singing) VOICE +(Sings) VOICE +(Spanish) VOICE +(Static) NOISE +(Tones) NOISE +(Trumpet) NOISE +(Video) NOISE +(Video): NOISE +(Voice-over) NOISE +(Whistle) NOISE +(Whistling) NOISE +(video): NOISE diff --git a/examples/speech_text_joint_to_text/criterions/__init__.py b/examples/speech_text_joint_to_text/criterions/__init__.py new file mode 100644 index 0000000000..7faae73119 --- /dev/null +++ b/examples/speech_text_joint_to_text/criterions/__init__.py @@ -0,0 +1,15 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import importlib +import os + + +for file in os.listdir(os.path.dirname(__file__)): + if file.endswith(".py") and not file.startswith("_"): + criterion_name = file[: file.find(".py")] + importlib.import_module( + "examples.speech_text_joint_to_text.criterions." + criterion_name + ) diff --git a/examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py b/examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py new file mode 100644 index 0000000000..0d356e5a10 --- /dev/null +++ b/examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py @@ -0,0 +1,223 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import math + +import torch +import torch.nn.functional as F +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.criterions.label_smoothed_cross_entropy import label_smoothed_nll_loss +from fairseq import metrics, utils + + +@register_criterion("guided_label_smoothed_cross_entropy_with_accuracy") +class GuidedCrossEntAccCriterion(FairseqCriterion): + def __init__( + self, + task, + sentence_avg, + guide_alpha, + text_input_cost_ratio, + label_smoothing, + disable_text_guide_update_num=0, + attentive_cost_regularization=0, + ): + """ + guide_alpha: alpha to inteplate nll and kd loss + text_input_cost_ratio: loss ratio for text only input data + label_smoothing: label smoothing ratio + disable_text_guide_update_num: only use nll loss for the first N updates + attentive_cost_regularization: ratio fo attentive cost + """ + super().__init__(task) + self.alpha = guide_alpha + self.attn_beta = attentive_cost_regularization + self.sentence_avg = sentence_avg + self.eps = label_smoothing + self.text_input_cost_ratio = text_input_cost_ratio + self.disable_update_num = disable_text_guide_update_num + assert self.alpha >= 0 and self.alpha <= 1.0 + + @staticmethod + def add_args(parser): + """Add criterion-specific arguments to the parser.""" + # fmt: off + parser.add_argument('--label-smoothing', default=0., type=float, metavar='D', + help='epsilon for label smoothing, 0 means no label smoothing') + # fmt: off + parser.add_argument('--guide-alpha', default=0., type=float, metavar='D', + help='alpha to merge kd cost from text to speech input with ce loss') + # fmt: off + parser.add_argument('--disable-text-guide-update-num', default=0, type=int, metavar='D', + help='disable guided target from text for the first N updates.') + parser.add_argument("--attentive-cost-regularization", default=0.0, type=float, metavar='D', + help="use encoder attentive loss regularization with cost ratio D") + parser.add_argument("--attentive-cost-without-normalize", action='store_true', + help="Don't do normalization during attentive cost computation") + + def forward(self, model, sample, reduce=True): + reduction = 'sum' if reduce else 'none' + net_input = sample["net_input"] + net_output = model(**net_input) + attn_cost = None + lprobs = model.get_normalized_probs(net_output, log_probs=True) + is_dual_input = True if net_input['src_tokens'] is not None and net_input.get('src_txt_tokens') is not None else False + target = model.get_targets(sample, net_output) + src_token_num = 0 + if is_dual_input: + # lprobs_spch from speech encoder and lprobs_text from text encoder + lprobs_spch, lprobs_text = torch.chunk(lprobs, 2) + lprobs_spch.batch_first = lprobs.batch_first + lprobs_text.batch_first = lprobs.batch_first + + speech_loss, speech_nll_loss, speech_correct, speech_total = \ + self.guide_loss_and_acc(model, lprobs_spch, lprobs_text, target, reduce=(reduction == 'sum')) + text_loss, text_nll_loss, text_correct, text_total = self.compute_loss_and_acc(model, lprobs_text, target, reduction=reduction) + loss = (speech_loss + text_loss) + nll_loss = (speech_nll_loss + text_nll_loss) + correct = speech_correct + text_correct + total = speech_total + text_total + + attn_cost = net_output[1].get('attn_cost') + if attn_cost is not None: + # attn_cost is batch_first and padding tokens have been masked already + src_token_num = attn_cost.ne(0).sum() + attn_cost = attn_cost.sum() + loss = loss + attn_cost * self.attn_beta + else: + attn_cost = 0 + else: + loss, nll_loss, correct, total = self.compute_loss_and_acc(model, lprobs, target, reduction=reduction) + if sample["net_input"]['src_tokens'] is None: # text input only + loss = loss * self.text_input_cost_ratio + speech_loss = None + speech_nll_loss = None + + sample_size, logging_output = self.get_logging_output( + sample, loss, nll_loss, correct, total, src_token_num, speech_loss, speech_nll_loss, attn_cost, is_dual_input + ) + return loss, sample_size, logging_output + + def compute_loss_and_acc(self, model, lprobs, target, reduction='sum'): + if not lprobs.batch_first: + lprobs = lprobs.transpose(0, 1) + lprobs = lprobs.view(-1, lprobs.size(-1)) # -> (B x T) x C + target = target.view(-1) + loss, nll_loss = label_smoothed_nll_loss( + lprobs, target, self.eps, ignore_index=self.padding_idx, reduce=(reduction == 'sum'), + ) + + mask = target.ne(self.padding_idx) + correct = torch.sum(lprobs.argmax(1).masked_select(mask).eq(target.masked_select(mask))) + total = torch.sum(mask) + return loss, nll_loss, correct, total + + def guide_loss_and_acc(self, model, lprobs, lprobs_teacher, target, reduce=True): + """ lprobs_teacher is used as guide for lprobs """ + if self.alpha == 0.0 or model.num_updates < self.disable_update_num: + return self.compute_loss_and_acc(model, lprobs, target, reduction=('sum' if reduce else 'none')) + if not lprobs.batch_first: + lprobs = lprobs.transpose(0, 1) + lprobs_teacher = lprobs_teacher.transpose(0, 1) + + lprobs = lprobs.view(-1, lprobs.size(-1)).float() # -> (B x T) x C + lprobs_teacher = lprobs_teacher.view(-1, lprobs_teacher.size(-1)).float() # -> (B x T) x C + target = target.view(-1) + loss = F.nll_loss(lprobs, target, ignore_index=self.padding_idx, reduction='sum' if reduce else 'none') + nll_loss = loss + probs_teacher = lprobs_teacher.exp().masked_fill_(target.unsqueeze(-1).eq(self.padding_idx), 0) + probs_teacher = probs_teacher.detach() + guide_loss = -(probs_teacher*lprobs).sum() if reduce else -(probs_teacher*lprobs).sum(-1, keepdim=True) + loss = self.alpha*guide_loss + (1.0 - self.alpha)*loss + + mask = target.ne(self.padding_idx) + correct = torch.sum(lprobs.argmax(1).masked_select(mask).eq(target.masked_select(mask))) + total = torch.sum(mask) + return loss, nll_loss, correct, total + + def get_logging_output( + self, + sample, + loss, + nll_loss, + correct, + total, + src_token_num=0, + speech_loss=None, + speech_nll_loss=None, + attn_cost=None, + is_dual_input=False, + ): + + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + mul_size = 2 if is_dual_input else 1 + + logging_output = { + "loss": utils.item(loss.data), # * sample['ntokens'], + "nll_loss": utils.item(nll_loss.data), # * sample['ntokens'], + "ntokens": sample["ntokens"]*mul_size, + "nsentences": sample["target"].size(0)*mul_size, + "sample_size": sample_size*mul_size, + "correct": utils.item(correct.data), + "total": utils.item(total.data), + "src_token_num": utils.item(src_token_num.data) if src_token_num > 0 else 0, + "nframes": torch.sum(sample["net_input"]["src_lengths"]).item(), + } + + if speech_loss is not None: + logging_output["speech_loss"] = utils.item(speech_loss.data) + logging_output["speech_nll_loss"] = utils.item(speech_nll_loss.data) + logging_output["sample_size_speech_cost"] = sample_size + logging_output["speech_attn_loss"] = attn_cost + + return sample_size*mul_size, logging_output + + @staticmethod + def aggregate_logging_outputs(logging_outputs): + """Aggregate logging outputs from data parallel training.""" + correct_sum = sum(log.get("correct", 0) for log in logging_outputs) + total_sum = sum(log.get("total", 0) for log in logging_outputs) + src_token_sum = sum(log.get("src_token_num", 0) for log in logging_outputs) + loss_sum = sum(log.get("loss", 0) for log in logging_outputs) + nll_loss_sum = sum(log.get("nll_loss", 0) for log in logging_outputs) + ntokens = sum(log.get("ntokens", 0) for log in logging_outputs) + nsentences = sum(log.get("nsentences", 0) for log in logging_outputs) + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + nframes = sum(log.get("nframes", 0) for log in logging_outputs) + speech_loss_sum = sum(log.get("speech_loss", 0) for log in logging_outputs) + speech_nll_loss_sum = sum(log.get("speech_nll_loss", 0) for log in logging_outputs) + speech_attn_loss_sum = sum(log.get("speech_attn_loss", 0) for log in logging_outputs) + sample_size_speech = sum(log.get("sample_size_speech_cost", 0) for log in logging_outputs) + + agg_output = { + "loss": loss_sum / sample_size / math.log(2) if sample_size > 0 else 0.0, + "nll_loss": nll_loss_sum / sample_size / math.log(2) if sample_size > 0 else 0.0, + # if args.sentence_avg, then sample_size is nsentences, and loss + # is per-sentence loss; else sample_size is ntokens, and the loss + # becomes per-output token loss + "speech_loss": speech_loss_sum / sample_size_speech / math.log(2) if sample_size_speech > 0 else 0.0, + "speech_nll_loss": speech_nll_loss_sum / sample_size_speech / math.log(2) if sample_size_speech > 0 else 0.0, + "speech_attn_loss": speech_attn_loss_sum / src_token_sum / math.log(2) if src_token_sum > 0 else 0.0, + "ntokens": ntokens, + "nsentences": nsentences, + "nframes": nframes, + "sample_size": sample_size, + "acc": correct_sum * 100.0 / total_sum if total_sum > 0 else 0.0, + "correct": correct_sum, + "total": total_sum, + "src_token_num": src_token_sum, + # total is the number of validate tokens + } + return agg_output + + @classmethod + def reduce_metrics(cls, logging_outputs): + """Aggregate logging outputs from data parallel training.""" + agg_logging_outputs = cls.aggregate_logging_outputs(logging_outputs) + for k, v in agg_logging_outputs.items(): + if k in {'nsentences', 'ntokens', 'sample_size'}: + continue + metrics.log_scalar(k, v, round=3) diff --git a/examples/speech_text_joint_to_text/docs/ende-mustc.md b/examples/speech_text_joint_to_text/docs/ende-mustc.md new file mode 100644 index 0000000000..3487af6671 --- /dev/null +++ b/examples/speech_text_joint_to_text/docs/ende-mustc.md @@ -0,0 +1,112 @@ +[[Back]](..) + +# Joint Speech Text Training for the MuST-C English to German Speech Translation task + +Joint Training Baseline: it is based on paper ["A general multi-task learning framework to leverage text data for speech to text tasks"](https://arxiv.org/pdf/2010.11338.pdf) + +Enhanced Joint Training: the joint training is enhanced with pre-trained models, cross attentive regularization and online knowledge distillation based on paper ["Improving Speech Translation by Understanding and Learning from the Auxiliary Text Translation Task"](https://research.fb.com/publications/improving-speech-translation-by-understanding-and-learning-from-the-auxiliary-text-translation-task) + +## Prepare Data +#### Download files +- Sentence piece model [spm.model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/spm.model) +- Dictionary [dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/dict.txt) +- config [config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/config.yaml) +#### Prepare MuST-C data set +- [Please follow the data preparation in the S2T example](https://github.com/pytorch/fairseq/blob/master/examples/speech_to_text/docs/mustc_example.md) +- Append src_text in the tsv file with phoneme representation. +```bash + python examples/speech_text_joint_to_text/scripts/g2p_encode.py \ + --lower-case --do-filter --use-word-start --no-punc \ + --reserve-word examples/speech_text_joint_to_text/configs/mustc_noise.list \ + --data-path ${must_c_en_de_src_text} \ + --out-path ${must_c_en_de_src_text_pho} +``` +- Update tsv data with src_text generated above and save to $MANIFEST_ROOT +- Prepare phoneme dictionary and save to $MANIFEST_ROOT as [src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/src_dict.txt) +#### Prepare WMT text data +- [Download wmt data](https://github.com/pytorch/fairseq/blob/master/examples/translation/prepare-wmt14en2de.sh) +- Convert source text (English) into phoneme representation as above +- Generate binary parallel file for training (as translation example) and save data in $parallel_text_data + +## Training +The model is trained with 8 v100 GPUs. + +#### Download pretrained models +- [pretrain_encoder](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_multilingual_asr_transformer_m.pt) +- [pretrain_nmt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/checkpoint_mt.pt) + +#### Training scripts +- Jointly trained model from scratch +```bash +python train.py ${MANIFEST_ROOT} \ + --save-dir ${save_dir} \ + --num-workers 8 \ + --task speech_text_joint_to_text \ + --arch dualinputs2ttransformer_s \ + --user-dir examples/speech_text_joint_to_text \ + --max-epoch 100 --update-mix-data \ + --optimizer adam --lr-scheduler inverse_sqrt \ + --lr 0.001 --update-freq 4 --clip-norm 10.0 \ + --criterion guided_label_smoothed_cross_entropy_with_accuracy \ + --label-smoothing 0.1 --max-tokens 10000 --max-tokens-text 10000 \ + --max-positions-text 400 --seed 2 --speech-encoder-layers 12 \ + --text-encoder-layers 6 --encoder-shared-layers 6 --decoder-layers 6 \ + --dropout 0.1 --warmup-updates 20000 \ + --text-sample-ratio 0.25 --parallel-text-data ${parallel_text_data} \ + --text-input-cost-ratio 0.5 --enc-grad-mult 2.0 --add-speech-eos \ + --log-format json --langpairs en-de --noise-token '"'"'▁NOISE'"'"' \ + --mask-text-ratio 0.0 --max-tokens-valid 20000 --ddp-backend no_c10d \ + --log-interval 100 --data-buffer-size 50 --config-yaml config.yaml \ + --keep-last-epochs 10 +``` +- Jointly trained model with good initialization, cross attentive loss and online knowledge distillation +```bash +python train.py ${MANIFEST_ROOT} \ + --save-dir ${save_dir} \ + --num-workers 8 \ + --task speech_text_joint_to_text \ + --arch dualinputs2ttransformer_m \ + --user-dir examples/speech_text_joint_to_text \ + --max-epoch 100 --update-mix-data \ + --optimizer adam --lr-scheduler inverse_sqrt \ + --lr 0.002 --update-freq 4 --clip-norm 10.0 \ + --criterion guided_label_smoothed_cross_entropy_with_accuracy \ + --guide-alpha 0.8 --disable-text-guide-update-num 5000 \ + --label-smoothing 0.1 --max-tokens 10000 --max-tokens-text 10000 \ + --max-positions-text 400 --seed 2 --speech-encoder-layers 12 \ + --text-encoder-layers 6 --encoder-shared-layers 6 --decoder-layers 6 \ + --dropout 0.1 --warmup-updates 20000 --attentive-cost-regularization 0.02 \ + --text-sample-ratio 0.25 --parallel-text-data ${parallel_text_data} \ + --text-input-cost-ratio 0.5 --enc-grad-mult 2.0 --add-speech-eos \ + --log-format json --langpairs en-de --noise-token '"'"'▁NOISE'"'"' \ + --mask-text-ratio 0.0 --max-tokens-valid 20000 --ddp-backend no_c10d \ + --log-interval 100 --data-buffer-size 50 --config-yaml config.yaml \ + --load-pretrain-speech-encoder ${pretrain_encoder} \ + --load-pretrain-decoder ${pretrain_nmt} \ + --load-pretrain-text-encoder-last ${pretrain_nmt} \ + --keep-last-epochs 10 +``` + +## Evaluation +```bash +python ./fairseq_cli/generate.py \ + ${MANIFEST_ROOT} \ + --task speech_text_joint_to_text \ + --max-tokens 25000 \ + --nbest 1 \ + --results-path ${infer_results} \ + --batch-size 512 \ + --path ${model} \ + --gen-subset tst-COMMON \ + --config-yaml config_spm.yaml \ + --scoring sacrebleu \ + --beam 5 --lenpen 1.0 \ + --user-dir examples/speech_text_joint_to_text \ + --load-speech-only +``` + +## Results (Joint training with initialization + CAR + online KD) +|Direction|En-De | En-Es | En-Fr | +|---|---|---|---| +|BLEU|27.4| 31.2 | 37.6 | +|checkpoint | [link](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/checkpoint_ave_10.pt) |[link](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_es/checkpoint_ave_10.pt)|[link](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_fr/checkpoint_ave_10.pt)| diff --git a/examples/speech_text_joint_to_text/docs/iwslt2021.md b/examples/speech_text_joint_to_text/docs/iwslt2021.md new file mode 100644 index 0000000000..37a07c4a05 --- /dev/null +++ b/examples/speech_text_joint_to_text/docs/iwslt2021.md @@ -0,0 +1,76 @@ +[[Back]](..) + +# Joint Speech Text Training for the 2021 IWSLT multilingual speech translation + +This directory contains the code from paper ["FST: the FAIR Speech Translation System for the IWSLT21 Multilingual Shared Task"](https://arxiv.org/pdf/2107.06959.pdf). + +## Prepare Data +#### Download files +- Sentence piece model [spm.model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/spm.model) +- Dictionary [tgt_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/dict.txt) +- Config [config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/config.yaml) + +#### Prepare +- [Please follow the data preparation in speech-to-text](https://github.com/pytorch/fairseq/blob/master/examples/speech_to_text/docs/mtedx_example.md) + + + +## Training + +#### Download pretrained models +- [Pretrained mbart model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/mbart.pt) +- [Pretrained w2v model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/xlsr_53_56k.pt) + + +#### Training scripts + +```bash +python train.py ${MANIFEST_ROOT} \ + --save-dir ${save_dir} \ + --user-dir examples/speech_text_joint_to_text \ + --train-subset train_es_en_tedx,train_es_es_tedx,train_fr_en_tedx,train_fr_es_tedx,train_fr_fr_tedx,train_it_it_tedx,train_pt_en_tedx,train_pt_pt_tedx \ + --valid-subset valid_es_en_tedx,valid_es_es_tedx,valid_es_fr_tedx,valid_es_it_tedx,valid_es_pt_tedx,valid_fr_en_tedx,valid_fr_es_tedx,valid_fr_fr_tedx,valid_fr_pt_tedx,valid_it_en_tedx,valid_it_es_tedx,valid_it_it_tedx,valid_pt_en_tedx,valid_pt_es_tedx,valid_pt_pt_tedx \ + --config-yaml config.yaml --ddp-backend no_c10d \ + --num-workers 2 --task speech_text_joint_to_text \ + --criterion guided_label_smoothed_cross_entropy_with_accuracy \ + --label-smoothing 0.3 --guide-alpha 0.8 \ + --disable-text-guide-update-num 5000 --arch dualinputxmtransformer_base \ + --max-tokens 500000 --max-sentences 3 --max-tokens-valid 800000 \ + --max-source-positions 800000 --enc-grad-mult 2.0 \ + --attentive-cost-regularization 0.02 --optimizer adam \ + --clip-norm 1.0 --log-format simple --log-interval 200 \ + --keep-last-epochs 5 --seed 1 \ + --w2v-path ${w2v_path} \ + --load-pretrained-mbart-from ${mbart_path} \ + --max-update 1000000 --update-freq 4 \ + --skip-invalid-size-inputs-valid-test \ + --skip-encoder-projection --save-interval 1 \ + --attention-dropout 0.3 --mbart-dropout 0.3 \ + --finetune-w2v-params all --finetune-mbart-decoder-params all \ + --finetune-mbart-encoder-params all --stack-w2v-mbart-encoder \ + --drop-w2v-layers 12 --normalize \ + --lr 5e-05 --lr-scheduler inverse_sqrt --warmup-updates 5000 +``` + +## Evaluation +```bash +python ./fairseq_cli/generate.py + ${MANIFEST_ROOT} \ + --task speech_text_joint_to_text \ + --user-dir ./examples/speech_text_joint_to_text \ + --load-speech-only --gen-subset test_es_en_tedx \ + --path ${model} \ + --max-source-positions 800000 \ + --skip-invalid-size-inputs-valid-test \ + --config-yaml config.yaml \ + --infer-target-lang en \ + --max-tokens 800000 \ + --beam 5 \ + --results-path ${RESULTS_DIR} \ + --scoring sacrebleu +``` +The trained model can be downloaded [here](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/checkpoint17.pt) + +|direction|es_en|fr_en|pt_en|it_en|fr_es|pt_es|it_es|es_es|fr_fr|pt_pt|it_it| +|---|---|---|---|---|---|---|---|---|---|---|---| +|BLEU|31.62|36.93|35.07|27.12|38.87|35.57|34.13|74.59|74.64|70.84|69.76| diff --git a/examples/speech_text_joint_to_text/models/__init__.py b/examples/speech_text_joint_to_text/models/__init__.py new file mode 100644 index 0000000000..7a394c7e4f --- /dev/null +++ b/examples/speech_text_joint_to_text/models/__init__.py @@ -0,0 +1,14 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import importlib +import os + +for file in os.listdir(os.path.dirname(__file__)): + if file.endswith(".py") and not file.startswith("_"): + model_name = file[: file.find(".py")] + importlib.import_module( + "examples.speech_text_joint_to_text.models." + model_name + ) diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py new file mode 100644 index 0000000000..7970a3c714 --- /dev/null +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py @@ -0,0 +1,1090 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from collections import namedtuple + +import torch +import torch.nn as nn +from fairseq import checkpoint_utils +from fairseq import utils +from fairseq.models import ( + FairseqEncoder, + FairseqDecoder, + FairseqEncoderDecoderModel, + register_model, + register_model_architecture, +) +from fairseq.models.fairseq_encoder import EncoderOut +from fairseq.models.speech_to_text import ( + TransformerDecoder, + S2TTransformerEncoder, +) +from fairseq.models.transformer import TransformerEncoder +from fairseq.modules import ( + TransformerEncoderLayer, + GradMultiply, + LayerNorm, +) + +logger = logging.getLogger(__name__) + + +class SpeechEoSEncoder(FairseqEncoder): + def __init__(self, encoder, eos_num, feat_dim, adapter_type="None", adapter_dim=0): + super().__init__(None) + self.encoder = encoder + self.eos_num = eos_num # downsampling rate for speech input feature + self.eos_emb = ( + nn.Parameter(torch.zeros(1, feat_dim), requires_grad=True) + if eos_num > 0 + else None + ) + self.adapter = self.add_adapter(adapter_type, adapter_dim) + + def add_adapter(self, adapter_type, adapter_dim): + def _make_identity(linear, eps=1e-5): + assert isinstance(linear, nn.Linear) + linear.weight.data.mul_(eps) + linear.weight.data.fill_diagonal_(1.0) + if linear.bias is not None: + linear.bias.data.mul_(eps) + + adapter = None + if adapter_type == "Linear": + assert adapter_dim > 0 + adapter = nn.Sequential( + nn.Linear(adapter_dim, adapter_dim), LayerNorm(adapter_dim) + ) + # initialize the adapter as identity matrix first + _make_identity(adapter[0]) + + elif adapter_type == "MLP": + assert adapter_dim > 0 + # assume the model is pre-norm model + adapter = nn.Sequential( + nn.Linear(adapter_dim, 2 * adapter_dim), + nn.ReLU(), + nn.Linear(2 * adapter_dim, adapter_dim), + LayerNorm(adapter_dim), + ) + _make_identity(adapter[0]) + _make_identity(adapter[2]) + return adapter + + def add_eos(self, src_tokens, src_lengths): + bsz, max_seq_len, fdim = src_tokens.size() + if self.eos_num > 0: + src_token_eos = torch.zeros( + [bsz, max_seq_len + self.eos_num, fdim], + dtype=src_tokens.dtype, + device=src_tokens.device, + ) + src_token_eos[:, :max_seq_len] = src_tokens + for bi in range(bsz): + src_token_eos[bi][ + src_lengths[bi] : src_lengths[bi] + self.eos_num + ] = self.eos_emb.expand(self.eos_num, fdim) + src_lengths = src_lengths + self.eos_num + src_tokens = src_token_eos + return src_tokens, src_lengths + + def apply_adapter(self, enc_out): + if self.adapter is None: + return enc_out + rst = self.adapter(enc_out.encoder_out) + if enc_out.encoder_padding_mask is not None: + rst.masked_fill_( + enc_out.encoder_padding_mask.transpose(0, 1).unsqueeze(-1), 0 + ) + return EncoderOut( + encoder_out=rst, + encoder_padding_mask=enc_out.encoder_padding_mask, + encoder_embedding=enc_out.encoder_embedding, + encoder_states=enc_out.encoder_states, + src_tokens=enc_out.src_tokens, + src_lengths=enc_out.src_lengths, + ) + + def forward(self, src_tokens, src_lengths=None, return_all_hiddens=False, **kwargs): + """ + src_tokens: padded tensor (B, T, C * feat) + src_lengths: tensor of original lengths of input utterances (B,) + """ + src_tokens, src_lengths = self.add_eos(src_tokens, src_lengths) + enc_out = self.encoder(src_tokens, src_lengths, return_all_hiddens) + enc_out = self.apply_adapter(enc_out) + return enc_out + + def reorder_encoder_out(self, encoder_out, new_order): + return self.encoder.reorder_encoder_out(encoder_out, new_order) + + +class DualInputEncoder(FairseqEncoder): + def __init__( + self, + args, + spch_encoder, + text_encoder, + dictionary, + cross_attentive_loss_before_last_layer=-1, + ): + super().__init__(dictionary) + + self.spch_encoder = spch_encoder + self.text_encoder = text_encoder + self.enc_grad_mult = args.enc_grad_mult + self.cross_attentive_loss_before_last_layer = ( + cross_attentive_loss_before_last_layer + ) + self.use_cross_attentive_loss = ( + False if cross_attentive_loss_before_last_layer <= -1 else True + ) + self.enc2_along_grad_mult = args.enc2_along_grad_mult + + @classmethod + def set_shared_layer(cls, share_level, src_layer, tgt_layer): + """ + share parameters from tgt_layer to src_layer + share_level: + 0: share everything + 1: share everything but different model + 2: share weight but not bias, layernorm + """ + if share_level == 0: + return tgt_layer + if isinstance(src_layer, nn.Linear): + return tgt_layer + if isinstance(src_layer, TransformerEncoderLayer): + assert src_layer.embed_dim == tgt_layer.embed_dim + assert src_layer.normalize_before == tgt_layer.normalize_before + if share_level == 1: + src_layer.fc1 = tgt_layer.fc1 + src_layer.fc2 = tgt_layer.fc2 + src_layer.self_attn = tgt_layer.self_attn + src_layer.final_layer_norm = tgt_layer.final_layer_norm + src_layer.self_attn_layer_norm = tgt_layer.self_attn_layer_norm + src_layer.layernorm_embedding = tgt_layer.layernorm_embedding + else: + src_layer.fc1.weight = tgt_layer.fc1.weight + src_layer.fc2.weight = tgt_layer.fc2.weight + src_layer.self_attn.k_proj.weight = tgt_layer.self_attn.k_proj.weight + src_layer.self_attn.v_proj.weight = tgt_layer.self_attn.v_proj.weight + src_layer.self_attn.q_proj.weight = tgt_layer.self_attn.q_proj.weight + src_layer.self_attn.out_proj.weight = ( + tgt_layer.self_attn.out_proj.weight + ) + else: + if share_level == 1: + return tgt_layer + return src_layer + + @classmethod + def build_spch_encoder(cls, args): + cfg = { + "input_feat_per_channel": args.input_feat_per_channel, + "input_channels": args.input_channels, + "conv_kernel_sizes": args.conv_kernel_sizes, + "conv_channels": args.conv_channels, + "encoder_embed_dim": args.encoder_embed_dim, + "encoder_ffn_embed_dim": args.encoder_ffn_embed_dim, + "encoder_layers": args.speech_encoder_layers, + "encoder_layerdrop": args.encoder_layerdrop, + "encoder_attention_heads": args.encoder_attention_heads, + "max_source_positions": args.max_source_positions, + "dropout": args.dropout, + "encoder_normalize_before": args.encoder_normalize_before, + "activation_dropout": args.activation_dropout, + "attention_dropout": args.attention_dropout, + "activation_fn": args.activation_fn, + "layernorm_embedding": args.layernorm_embedding, + "no_token_positional_embeddings": args.no_token_positional_embeddings, + "no_scale_embedding": args.no_scale_embedding, + "quant_noise_pq": args.quant_noise_pq, + "encoder_freezing_updates": 0, + } + model_args = namedtuple("args", cfg.keys())(*cfg.values()) + spch_encoder = S2TTransformerEncoder(model_args) + if args.add_speech_eos: + spch_encoder = SpeechEoSEncoder( + spch_encoder, + 2 * len(args.conv_kernel_sizes.split(",")), + args.input_feat_per_channel, + adapter_type=getattr(args, "speech_encoder_adapter_type", "None"), + adapter_dim=args.encoder_embed_dim, + ) + return spch_encoder + + @classmethod + def build_text_encoder(cls, args, src_dictionary, spch_encoder): + if args.encoder_shared_layers > 0: + mx_shared_layers = ( + args.speech_encoder_layers + if args.speech_encoder_layers < args.text_encoder_layers + else args.text_encoder_layers + ) + args.encoder_shared_layers = ( + args.encoder_shared_layers + if args.encoder_shared_layers <= mx_shared_layers + else mx_shared_layers + ) + cfg = { + "encoder_embed_dim": args.encoder_text_embed_dim, + "encoder_ffn_embed_dim": args.encoder_ffn_embed_dim, + "encoder_layers": args.text_encoder_layers, + "encoder_layerdrop": args.encoder_layerdrop, + "encoder_attention_heads": args.encoder_attention_heads, + "encoder_learned_pos": args.encoder_learned_pos, + "max_source_positions": args.max_source_positions, + "dropout": args.dropout, + "encoder_normalize_before": args.encoder_normalize_before, + "activation_dropout": args.activation_dropout, + "attention_dropout": args.attention_dropout, + "activation_fn": args.activation_fn, + "adaptive_input": args.adaptive_input, + "no_token_positional_embeddings": args.no_token_positional_embeddings, + "no_scale_embedding": args.no_scale_embedding, + "quant_noise_pq": args.quant_noise_pq, + } + model_args = namedtuple("args", cfg.keys())(*cfg.values()) + enc_emb = nn.Embedding( + len(src_dictionary), model_args.encoder_embed_dim, src_dictionary.pad() + ) + text_encoder = TransformerEncoder(model_args, src_dictionary, enc_emb) + if args.add_speech_eos: + spch_encoder = spch_encoder.encoder + if args.encoder_shared_layers > 0: + text_encoder.layer_norm = cls.set_shared_layer( + args.encoder_shared_layer_level, + text_encoder.layer_norm, + spch_encoder.layer_norm, + ) + for i, ly in enumerate( + spch_encoder.transformer_layers[-args.encoder_shared_layers :] + ): + ly_id = i + args.text_encoder_layers - args.encoder_shared_layers + assert isinstance(text_encoder.layers[ly_id], type(ly)) + text_encoder.layers[ly_id] = cls.set_shared_layer( + args.encoder_shared_layer_level, + text_encoder.layers[ly_id], + ly, + ) + return text_encoder + + def mult_rst_grad(self, rst, ratio): + assert isinstance(rst, dict) # instead of EncoderOut + assert len(rst["encoder_out"]) == 1 + rst["encoder_out"][0] = GradMultiply.apply(rst["encoder_out"][0], ratio) + return rst + + def process_attentive_loss_states(self, rst, interstates): + assert isinstance(rst, dict) # instead of EncoderOut + rst["encoder_states"] = interstates + return rst + + def forward( + self, + src_tokens, + src_lengths=None, + src_txt_tokens=None, + src_txt_lengths=None, + **kwargs + ): + """ + Args: + src_tokens: padded tensor (B, T, C * feat) + src_lengths: tensor of original lengths of input utterances (speech) (B,) + src_txt_tokens: padded tensor (B, T) + src_txt_lengths: tensor of original lengths of input utterances (text) (B,) + """ + # src_tokens only: inference + # src_tokens, src_lengths: speech only training + # src_txt_tokens, src_txt_lengths: text only training + # all valid: speech + text training + + if src_tokens is None and src_txt_tokens is None: + raise ValueError( + "src_tokens and src_txt_tokens cannot be None at the same time" + ) + ret1 = None + ret2 = None + return_all_hiddens = False + if src_tokens is not None: + if ( + self.use_cross_attentive_loss and src_txt_tokens is not None + ): # remove self.training so we can get attn score during validation step + return_all_hiddens = True + ret1 = self.spch_encoder( + src_tokens, src_lengths, return_all_hiddens=return_all_hiddens + ) + + if self.use_cross_attentive_loss and src_txt_tokens is not None: + assert self.cross_attentive_loss_before_last_layer < len( + ret1["encoder_states"] + ) + ret1 = self.process_attentive_loss_states( + ret1, + ret1["encoder_states"][ + -self.cross_attentive_loss_before_last_layer - 1 + ], + ) + + if src_txt_tokens is not None: + ret2 = self.text_encoder( + src_txt_tokens, src_txt_lengths, return_all_hiddens=return_all_hiddens + ) + if return_all_hiddens: + if self.cross_attentive_loss_before_last_layer == len( + self.text_encoder.layers + ): + text_embedding, _ = self.text_encoder.forward_embedding( + src_txt_tokens + ) + text_embedding = text_embedding.transpose(0, 1) + ret2 = self.process_attentive_loss_states(ret2, text_embedding) + else: + assert self.cross_attentive_loss_before_last_layer < len( + self.text_encoder.layers + ) + ret2 = self.process_attentive_loss_states( + ret2, + ret2["encoder_states"][ + -self.cross_attentive_loss_before_last_layer - 1 + ], + ) + + def merge_output(rst1, rst2): + if rst1 is None: + if not (self.enc2_along_grad_mult == 1.0 or self.training): + rst2 = self.mult_rst_grad(rst2, self.enc2_along_grad_mult) + return rst2 + if rst2 is None: + return rst1 + if self.enc_grad_mult != 1.0 and self.training: + rst1 = self.mult_rst_grad(rst1, self.enc_grad_mult) + rst2 = self.mult_rst_grad(rst2, self.enc_grad_mult) + rst = (rst1, rst2) + return rst + + return merge_output(ret1, ret2) + + def reorder_encoder_out(self, encoder_out, new_order): + assert self.training is False # used for inference only + return self.spch_encoder.reorder_encoder_out(encoder_out, new_order) + + +# TransformerMultiInputDecoder: take one or two encoder inputs +class TransformerMultiInputDecoder(FairseqDecoder): + def __init__( + self, + dictionary, + spch_decoder, + text_decoder, + compute_cross_attentive_loss=False, + cross_attentive_loss_with_norm=True, + cross_attentive_loss_reverse=False, + ): + + super().__init__(dictionary) + self.spch_decoder = spch_decoder + self.text_decoder = text_decoder + self.compute_cross_attentive_loss = compute_cross_attentive_loss + self.cross_attentive_loss_with_norm = cross_attentive_loss_with_norm + self.cross_attentive_loss_reverse = cross_attentive_loss_reverse + + @classmethod + def share_spchdecoder(cls, task_args, text_decoder, spch_decoder): + if task_args.decoder_shared_layer_level == 0: + return text_decoder + assert text_decoder.embed_tokens == spch_decoder.embed_tokens + spch_decoder.project_in_dim = text_decoder.project_in_dim + spch_decoder.embed_positions = text_decoder.embed_positions + spch_decoder.layernorm_embedding = text_decoder.layernorm_embedding + spch_decoder.project_out_dim = text_decoder.project_out_dim + spch_decoder.adaptive_softmax = text_decoder.adaptive_softmax + if task_args.decoder_shared_layer_level == 1: + spch_decoder.output_projection = text_decoder.output_projection + spch_decoder.layer_norm = text_decoder.layer_norm + else: # 2 + spch_decoder.output_projection.weight = ( + text_decoder.output_projection.weight + ) + for i, ly in enumerate(text_decoder.layers): + sly = spch_decoder.layers[i] + sly.self_attn = ly.self_attn + sly.self_attn_layer_norm = ly.self_attn_layer_norm + # sly.encoder_attn = ly.encoder_attn + if ( + task_args.decoder_shared_layer_level == 1 + ): # share everything, but under different models + sly.encoder_attn = ly.encoder_attn + sly.encoder_attn_layer_norm = ly.encoder_attn_layer_norm + sly.fc1 = ly.fc1 + sly.fc2 = ly.fc2 + sly.final_layer_norm = ly.final_layer_norm + else: # task_args.decoder_shared_layer_level == 2: #separated encoder_attn_layer_norm and bias + sly.encoder_attn.k_proj.weight = ly.encoder_attn.k_proj.weight + sly.encoder_attn.v_proj.weight = ly.encoder_attn.v_proj.weight + sly.encoder_attn.q_proj.weight = ly.encoder_attn.q_proj.weight + sly.encoder_attn.out_proj.weight = ly.encoder_attn.out_proj.weight + sly.fc1.weight = ly.fc1.weight + sly.fc2.weight = ly.fc2.weight + + return spch_decoder + + def cross_attentive_loss( + self, teacher_states, student_states, teacher_masking, student_masking, eps=1e-6 + ): + x = teacher_states.transpose(0, 1) # from T X B X D to B X T X D + y = student_states.transpose(0, 1) + if self.cross_attentive_loss_with_norm: + x = x / (x.norm(dim=2, keepdim=True) + eps) + y = y / (y.norm(dim=2, keepdim=True) + eps) + dim = x.size(-1) + # lengths: batch X seqLen + sim_scores_xy = torch.bmm(x, y.transpose(1, 2)) # batch X lenx X leny ] + if y.dtype == torch.float16: + sim_scores_xy = sim_scores_xy.float() + y = y.float() + x = x.float() + if teacher_masking != []: + assert len(teacher_masking) == 1 + sim_scores_xy = sim_scores_xy.masked_fill( + teacher_masking[0].unsqueeze(-1), float("-inf") + ) + if student_masking != []: + sim_scores_xy = sim_scores_xy.masked_fill( + student_masking[0].unsqueeze(1), float("-inf") + ) + # do masking + y_weights = utils.softmax(sim_scores_xy, dim=-1) + if teacher_masking != []: + y_weights = y_weights.masked_fill(teacher_masking[0].unsqueeze(-1), 0) + x_reconstruct_from_y = torch.bmm(y_weights, y) + + sim_scores_xx = torch.bmm(x, x.transpose(1, 2)) # batch X lenx X lenx ] + x_weights = utils.softmax(sim_scores_xx, dim=-1) + if teacher_masking != []: + x_weights = x_weights.masked_fill(teacher_masking[0].unsqueeze(-1), 0) + + # no gradient for teacher state + x_reconstruct_from_x = torch.bmm(x_weights, x).detach() + cost = (x_reconstruct_from_x - x_reconstruct_from_y).norm(dim=2) + if teacher_masking != []: + cost = cost.masked_fill(teacher_masking[0], 0) + + if not self.cross_attentive_loss_with_norm: + cost = cost / dim + return cost + + def forward( + self, + prev_output_tokens, + encoder_out, + incremental_state=None, + has_txt_input=False, + **kwargs + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for input feeding/teacher forcing. If there are + two or more input during training, they will share the same prev_output_tokens + encoder_out (tuple[Tensor]): output from the encoder, used for + encoder-side attention. It will be tuple if there are more inputs, but a tensor + if only one input + incremental_state ([dict]): dictionary used for storing state during + :ref:`Incremental decoding`. It is only valid for inference, only from single + input + Returns: + tuple: + - the last decoder layer's output of shape `(batch, tgt_len, + vocab)`. If there are N inputs, batch will be N bigger than a single input + - the last decoder layer's attention weights of shape `(batch, + tgt_len, src_len)` + """ + assert not isinstance(encoder_out, EncoderOut) + if isinstance(encoder_out, tuple): # training with mulitple input + rst = [] + assert len(encoder_out) == 2 + for i, eo in enumerate(encoder_out): + assert incremental_state is None + if i == 0: + rst.append( + self.spch_decoder(prev_output_tokens, eo, incremental_state) + ) + else: + rst.append( + self.text_decoder(prev_output_tokens, eo, incremental_state) + ) + dec_out = torch.cat([r[0] for r in rst], dim=0) + attn_cost = None + if self.compute_cross_attentive_loss: + assert isinstance(encoder_out[0], dict) + if self.cross_attentive_loss_reverse: + attn_cost = self.cross_attentive_loss( + teacher_states=encoder_out[1]["encoder_states"], # text_states + student_states=encoder_out[0]["encoder_states"], # spch_states + teacher_masking=encoder_out[1]["encoder_padding_mask"], + student_masking=encoder_out[0]["encoder_padding_mask"], + ) + else: + attn_cost = self.cross_attentive_loss( + teacher_states=encoder_out[0]["encoder_states"], # spch_states + student_states=encoder_out[1]["encoder_states"], # text_states + teacher_masking=encoder_out[0]["encoder_padding_mask"], + student_masking=encoder_out[1]["encoder_padding_mask"], + ) + + return (dec_out, {"attn_cost": attn_cost}) + else: # inference or training with one input + if has_txt_input: + return self.text_decoder( + prev_output_tokens, encoder_out, incremental_state + ) + return self.spch_decoder(prev_output_tokens, encoder_out, incremental_state) + + +# Note: +# dual input transformer: +# encoder: S2TTransformerEncoder for speech + TransformerEncoder for text +# decoder: TransformerDecoder for text +@register_model("dual_input_s2t_transformer") +class DualInputS2TTransformerModel(FairseqEncoderDecoderModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + self.num_updates = 0 + + def max_positions(self): + return None # it is provided in task + + @staticmethod + def add_args(parser): + """Add model-specific arguments to the parser.""" + # encoder 1: S2TTransformerEncoder for speech + parser.add_argument( + "--conv-kernel-sizes", + type=str, + metavar="N", + help="kernel sizes of Conv1d subsampling layers", + ) + parser.add_argument( + "--conv-channels", + type=int, + metavar="N", + help="# of channels in Conv1d subsampling layers", + ) + parser.add_argument( + "--enc-output-dim", + type=int, + metavar="N", + help=""" + encoder output dimension, can be None. If specified, projecting the + transformer output to the specified dimension""", + ) + # standard Transformer + parser.add_argument( + "--activation-fn", + type=str, + default="relu", + choices=utils.get_available_activation_fns(), + help="activation function to use", + ) + parser.add_argument( + "--dropout", type=float, metavar="D", help="dropout probability" + ) + parser.add_argument( + "--attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights", + ) + parser.add_argument( + "--activation-dropout", + "--relu-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN.", + ) + parser.add_argument( + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension", + ) + parser.add_argument( + "--encoder-text-embed-dim", + type=int, + metavar="N", + help="encoder text embedding dimension", + ) + parser.add_argument( + "--encoder-ffn-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension for FFN", + ) + parser.add_argument( + "--encoder-attention-heads", + type=int, + metavar="N", + help="num encoder attention heads", + ) + parser.add_argument( + "--decoder-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension", + ) + parser.add_argument( + "--decoder-ffn-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension for FFN", + ) + parser.add_argument( + "--decoder-layers", type=int, metavar="N", help="num decoder layers" + ) + parser.add_argument( + "--decoder-attention-heads", + type=int, + metavar="N", + help="num decoder attention heads", + ) + parser.add_argument( + "--layernorm-embedding", + action="store_true", + help="add layernorm to embedding", + ) + parser.add_argument( + "--no-scale-embedding", + action="store_true", + help="if True, dont scale embeddings", + ) + # non-standard transformer parameters + parser.add_argument( + "--speech-encoder-layers", + type=int, + metavar="N", + help="num speech encoder layers", + ) + parser.add_argument( + "--text-encoder-layers", + type=int, + metavar="N", + help="num text encoder layers", + ) + parser.add_argument( + "--encoder-shared-layers", + type=int, + metavar="N", + help="num shared encoder layers", + ) + parser.add_argument( + "--encoder-shared-layer-level", + type=int, + metavar="N", + default=0, + choices=[0, 1, 2], + help="share layer level 0: all share 1: all share with separate model 2: share weight but not bias and layernorm", + ) + + parser.add_argument( + "--decoder-shared-layer-level", + default=0, + choices=[0, 1, 2], + type=int, + metavar="N", + help="0: share everything; 1: share everything with different model 2: no share layer_norm and bias", + ) + ### + parser.add_argument( + "--text-input-cost-ratio", + type=float, + default=1.0, + metavar="V", + help="text input cost ratio relative to speech input cost", + ) + parser.add_argument( + "--init-scale", + type=float, + default=1.0, + metavar="V", + help="scale the initial weight by given factor", + ) + parser.add_argument( + "--enc-grad-mult", + type=float, + metavar="V", + default=1.0, + help="multiply enc1 and enc2 gradient by V", + ) + parser.add_argument( + "--enc2-along-grad-mult", + type=float, + metavar="V", + default=1.0, + help="multiply enc2 gradient by V if only enc2 is used", + ) + parser.add_argument( + "--load-pretrain-encoder", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained encoder """, + ) + parser.add_argument( + "--load-pretrain-speech-encoder", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained speech encoder """, + ) + parser.add_argument( + "--load-pretrain-text-encoder", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained text encoder """, + ) + parser.add_argument( + "--load-pretrain-text-encoder-last", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained text encoder """, + ) + parser.add_argument( + "--load-pretrain-decoder", + type=str, + metavar="EXPR", + default="", + help=""" path to the pretrained encoder """, + ) + parser.add_argument( + "--add-speech-eos", + action="store_true", + help="add eos token at the end of input feature", + ) + parser.add_argument( + "--speech-encoder-adapter-type", + type=str, + metavar="EXPR", + default="None", + choices=["None", "Linear", "MLP"], + help="add speech encoder adapter", + ) + + @classmethod + def build_encoder(cls, args, task): + spch_encoder = DualInputEncoder.build_spch_encoder(args) + text_encoder = DualInputEncoder.build_text_encoder( + args, task.src_dict, spch_encoder + ) + cross_attentive_loss_before_last_layer = ( + 0 if getattr(args, "attentive_cost_regularization", 0.0) > 0.0 else -1 + ) + encoder = DualInputEncoder( + args, + spch_encoder, + text_encoder, + task.src_dict, + cross_attentive_loss_before_last_layer, + ) + if args.init_scale != 1.0: + with torch.no_grad(): + for param in encoder.parameters(): + param.data.mul_(args.init_scale) + if args.load_pretrain_text_encoder != "": + checkpoint_utils.load_pretrained_component_from_model( + text_encoder, args.load_pretrain_text_encoder + ) + if args.load_pretrain_speech_encoder != "": + if hasattr(spch_encoder, "encoder"): + checkpoint_utils.load_pretrained_component_from_model( + spch_encoder.encoder, args.load_pretrain_speech_encoder + ) + else: + checkpoint_utils.load_pretrained_component_from_model( + spch_encoder, args.load_pretrain_speech_encoder + ) + if ( + args.load_pretrain_text_encoder_last != "" + ): # if share encoder, speech encoder parameters will be used. + # It provides a chance to use pre-trained mt encoder instead + checkpoint_utils.load_pretrained_component_from_model( + text_encoder, args.load_pretrain_text_encoder_last + ) + + if args.load_pretrain_encoder != "": + checkpoint_utils.load_pretrained_component_from_model( + encoder, args.load_pretrain_encoder + ) + return encoder + + @classmethod + def build_decoder(cls, args, task): + dec_cfg = { + "decoder_layerdrop": args.decoder_layerdrop, + "share_decoder_input_output_embed": args.share_decoder_input_output_embed, + "decoder_embed_dim": args.decoder_embed_dim, + "max_target_positions": args.max_target_positions, + "dropout": args.dropout, + "encoder_learned_pos": args.encoder_learned_pos, + "decoder_learned_pos": args.decoder_learned_pos, + "layernorm_embedding": args.layernorm_embedding, + "decoder_normalize_before": args.decoder_normalize_before, + "activation_dropout": args.activation_dropout, + "attention_dropout": args.attention_dropout, + "decoder_ffn_embed_dim": args.decoder_ffn_embed_dim, + "decoder_layers": args.decoder_layers, + "decoder_attention_heads": args.decoder_attention_heads, + "decoder_output_dim": args.decoder_embed_dim, + "no_scale_embedding": args.no_scale_embedding, + "adaptive_input": args.adaptive_input, + "quant_noise_pq": args.quant_noise_pq, + "adaptive_softmax_cutoff": args.adaptive_softmax_cutoff, + "tie_adaptive_weights": args.tie_adaptive_weights, + "no_token_positional_embeddings": args.no_token_positional_embeddings, + } + dec_cfg = namedtuple("args", dec_cfg.keys())(*dec_cfg.values()) + dec_emb = nn.Embedding( + len(task.target_dictionary), + args.decoder_embed_dim, + task.target_dictionary.pad(), + ) + compute_cross_attentive_loss = ( + True if getattr(args, "attentive_cost_regularization", 0.0) > 0.0 else False + ) + cross_attentive_loss_without_norm = getattr( + args, "attentive_cost_without_normalize", False + ) + cross_attentive_loss_reverse = ( + False # getattr(args, "attentive_cost_reverse", False) + ) + + text_decoder = TransformerDecoder(dec_cfg, task.target_dictionary, dec_emb) + spch_decoder = TransformerDecoder(dec_cfg, task.target_dictionary, dec_emb) + spch_decoder = TransformerMultiInputDecoder.share_spchdecoder( + args, text_decoder, spch_decoder + ) + decoder = TransformerMultiInputDecoder( + dictionary=task.target_dictionary, + spch_decoder=spch_decoder, + text_decoder=text_decoder, + compute_cross_attentive_loss=compute_cross_attentive_loss, + cross_attentive_loss_with_norm=True + if not cross_attentive_loss_without_norm + else False, + cross_attentive_loss_reverse=cross_attentive_loss_reverse, + ) + if args.init_scale != 1.0: + with torch.no_grad(): + for param in decoder.parameters(): + param.data.mul_(args.init_scale) + if args.load_pretrain_decoder != "": + try: + checkpoint_utils.load_pretrained_component_from_model( + decoder, args.load_pretrain_decoder + ) + except RuntimeError: + checkpoint_utils.load_pretrained_component_from_model( + decoder.text_decoder, args.load_pretrain_decoder + ) + if args.decoder_shared_layer_level > 0: + checkpoint_utils.load_pretrained_component_from_model( + decoder.spch_decoder, args.load_pretrain_decoder + ) + + return decoder + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + # make sure that all args are properly defaulted + # (in case there are any new ones) + dualinputs2ttransformer_base(args) + + encoder = cls.build_encoder(args, task) + decoder = cls.build_decoder(args, task) + return cls(encoder, decoder) + + def get_normalized_probs(self, net_output, log_probs, sample=None): + # net_output['encoder_out'] is a (B, T, D) tensor + lprobs = super().get_normalized_probs(net_output, log_probs, sample) + lprobs.batch_first = True + return lprobs + + def set_num_updates(self, num_updates): + """Set the number of parameters updates.""" + super().set_num_updates(num_updates) + self.num_updates = num_updates + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + use_encoder_outputs=False, + src_txt_tokens=None, + src_txt_lengths=None, + mode="sup_speech", + **kwargs + ): + """ + Run the forward pass for an encoder-decoder model. + + First feed a batch of source tokens through the encoder. Then, feed the + encoder output and previous decoder outputs (i.e., teacher forcing) to + the decoder to produce the next outputs:: + + encoder_out = self.encoder(src_tokens, src_lengths) + return self.decoder(prev_output_tokens, encoder_out) + + Args: + src_tokens (LongTensor): tokens in the source language of shape + `(batch, src_len)` + src_lengths (LongTensor): source sentence lengths of shape `(batch)` + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + mode = 'sup_speech' or 'text' + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + if mode == "text": + assert src_txt_tokens is None + src_txt_tokens = src_tokens + src_txt_lengths = src_lengths + src_tokens = None + src_lengths = None + encoder_out = self.encoder( + src_tokens, + src_lengths=src_lengths, + src_txt_tokens=src_txt_tokens, + src_txt_lengths=src_txt_lengths, + **kwargs + ) + has_txt_input = True if src_txt_tokens is not None else False + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=encoder_out, + has_txt_input=has_txt_input, + **kwargs + ) + if use_encoder_outputs: + return decoder_out, encoder_out + return decoder_out + + +@register_model_architecture( + "dual_input_s2t_transformer", "dualinputs2ttransformer_base" +) +def dualinputs2ttransformer_base(args): + args.encoder_freezing_updates = getattr(args, "encoder_freezing_updates", 0) + # Convolutional subsampler + args.input_feat_per_channel = getattr(args, "input_feat_per_channel", 80) + args.conv_kernel_sizes = getattr(args, "conv_kernel_sizes", "5,5") + args.conv_channels = getattr(args, "conv_channels", 1024) + # Transformer + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_text_embed_dim = getattr( + args, "encoder_text_embed_dim", args.encoder_embed_dim + ) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 8) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) + args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0) + args.encoder_learned_pos = getattr(args, "encoder_learned_pos", False) + + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim + ) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", args.dropout) + args.activation_dropout = getattr(args, "activation_dropout", args.dropout) + args.activation_fn = getattr(args, "activation_fn", "relu") + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + args.adaptive_input = getattr(args, "adaptive_input", False) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.layernorm_embedding = getattr(args, "layernorm_embedding", False) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 10) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.encoder_shared_layers = getattr(args, "encoder_shared_layers", 0) + args.decoder_layers = getattr(args, "decoder_layers", 6) + + args.add_speech_eos = getattr(args, "add_speech_eos", False) + + +@register_model_architecture("dual_input_s2t_transformer", "dualinputs2ttransformer_s") +def dualinputs2ttransformer_s(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 256 * 4) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 7) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 7) + args.decoder_layers = getattr(args, "decoder_layers", 7) + dualinputs2ttransformer_base(args) + + +@register_model_architecture("dual_input_s2t_transformer", "dualinputs2ttransformer_m") +def dualinputs2ttransformer_m(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 512 * 4) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 8) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) + args.dropout = getattr(args, "dropout", 0.15) + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 10) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.decoder_layers = getattr(args, "decoder_layers", 6) + dualinputs2ttransformer_base(args) + + +@register_model_architecture("dual_input_s2t_transformer", "dualinputs2ttransformer_b") +def dualinputs2ttransformer_b(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 768 * 4) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 12) + args.dropout = getattr(args, "dropout", 0.15) + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 12) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.decoder_layers = getattr(args, "decoder_layers", 6) + dualinputs2ttransformer_base(args) + + +@register_model_architecture("dual_input_s2t_transformer", "dualinputs2ttransformer_l") +def dualinputs2ttransformer_l(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 1024 * 4) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + args.dropout = getattr(args, "dropout", 0.2) + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 12) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.decoder_layers = getattr(args, "decoder_layers", 6) + dualinputs2ttransformer_base(args) diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py new file mode 100644 index 0000000000..6c853b96ed --- /dev/null +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py @@ -0,0 +1,584 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import copy + +import torch.nn as nn +from fairseq import checkpoint_utils +from fairseq import utils +from fairseq.data.data_utils import lengths_to_padding_mask +from fairseq.models import ( + register_model, + register_model_architecture, + FairseqEncoder, +) +from fairseq.models.speech_to_text import XMTransformerModel, Wav2VecEncoderWithAdaptor +from fairseq.models.speech_to_text.xm_transformer import ( + set_default_adaptor_args, + set_default_w2v_encoder_args, +) +from fairseq.models.transformer import TransformerEncoder, TransformerDecoder +from fairseq.models.wav2vec import TransformerSentenceEncoderLayer + +from .s2t_dualinputtransformer import ( + DualInputS2TTransformerModel, + TransformerMultiInputDecoder, + DualInputEncoder, +) + + +class TransformerSentenceEncoderLayerStd(TransformerSentenceEncoderLayer): + def __init__(self, sent_enc_layer): + super(TransformerSentenceEncoderLayer, self).__init__() + self.embedding_dim = sent_enc_layer.embedding_dim + self.dropout = sent_enc_layer.dropout + self.activation_dropout = sent_enc_layer.activation_dropout + + # Initialize blocks + self.activation_fn = sent_enc_layer.activation_fn + self.self_attn = sent_enc_layer.self_attn + + self.dropout1 = sent_enc_layer.dropout1 + self.dropout2 = sent_enc_layer.dropout2 + self.dropout3 = sent_enc_layer.dropout3 + + self.layer_norm_first = sent_enc_layer.layer_norm_first + + # layer norm associated with the self attention layer + self.self_attn_layer_norm = sent_enc_layer.self_attn_layer_norm + self.fc1 = sent_enc_layer.fc1 + self.fc2 = sent_enc_layer.fc2 + + # layer norm associated with the position wise feed-forward NN + self.final_layer_norm = sent_enc_layer.final_layer_norm + + def forward( + self, + x, + self_attn_mask=None, + self_attn_padding_mask=None, + need_weights=None, + att_args=None, + ): + x, attn = super().forward( + x, self_attn_mask, self_attn_padding_mask, need_weights, att_args + ) + return x + + +# TODO retire SharedEncoder +class SharedEncoder(FairseqEncoder): + def __init__(self, wav2vec_enc, mbart_enc, adaptor, shared_layers): + super().__init__(None) + self.w2v_encoder = wav2vec_enc + self.shared_layers = self.w2v_encoder.w2v_model.encoder.layers[-shared_layers:] + self.w2v_encoder.w2v_model.encoder.layers = ( + self.w2v_encoder.w2v_model.encoder.layers[:-shared_layers] + ) + self.adaptor = adaptor + if self.shared_layers[-1].layer_norm_first: + self.final_layer_norm = mbart_enc.layer_norm + else: + mbart_enc.layer_norm = None + self.final_layer_norm = None + shared_layer_from = len(mbart_enc.layers) - shared_layers + if shared_layer_from < 0: + shared_layer_from = 0 + for layer_id, layer in enumerate(self.shared_layers): + mbart_enc.layers[ + shared_layer_from + layer_id + ] = TransformerSentenceEncoderLayerStd(layer) + + def forward(self, src_tokens, src_lengths=None, **kwargs): + padding_mask = lengths_to_padding_mask(src_lengths) + if not padding_mask.any(): + padding_mask = None + + out = self.w2v_encoder.forward(src_tokens, padding_mask, tbc=True) + x = out["encoder_out"] + enc_padding_mask = None + if out["encoder_padding_mask"] is not None: + enc_padding_mask = out["encoder_padding_mask"].transpose( + 0, 1 + ) # T X B --> B X T + + x, enc_padding_mask = self.adaptor(x, enc_padding_mask) + for layer in self.shared_layers: + x, _ = layer(x, enc_padding_mask) + if self.final_layer_norm is not None: + x = self.final_layer_norm(x) + + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [enc_padding_mask] + if enc_padding_mask is not None + else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": [], # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + + +class StackedWav2VecEncoderWithAdaptor(FairseqEncoder): + def __init__( + self, + wav2vec_enc, + mbart_enc_layers, + mbart_layer_norm, + adaptor, + drop_w2v_layers=0, + ): + super().__init__(None) + self.w2v_encoder = wav2vec_enc + self.adaptor = adaptor + self.mbart_encoder_layers = mbart_enc_layers + self.final_layer_norm = mbart_layer_norm + if drop_w2v_layers > 0: + self.w2v_encoder.w2v_model.encoder.layers = ( + self.w2v_encoder.w2v_model.encoder.layers[:-drop_w2v_layers] + ) + + def forward(self, src_tokens, src_lengths=None, return_all_hiddens=False, **kwargs): + padding_mask = lengths_to_padding_mask(src_lengths) + if not padding_mask.any(): + padding_mask = None + + out = self.w2v_encoder.forward(src_tokens, padding_mask, tbc=True) + x = out["encoder_out"] + enc_padding_mask = None + if out["encoder_padding_mask"] is not None: + enc_padding_mask = out["encoder_padding_mask"].transpose( + 0, 1 + ) # T X B --> B X T + + x, enc_padding_mask = self.adaptor(x, enc_padding_mask) + encoder_states = [] + for layer in self.mbart_encoder_layers: + x = layer(x, enc_padding_mask) + if return_all_hiddens: + encoder_states.append(x) + if self.final_layer_norm is not None: + x = self.final_layer_norm(x) + + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [enc_padding_mask] + if enc_padding_mask is not None + else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + + def reorder_encoder_out(self, encoder_out, new_order): + new_encoder_out = ( + [] + if len(encoder_out["encoder_out"]) == 0 + else [x.index_select(1, new_order) for x in encoder_out["encoder_out"]] + ) + + new_encoder_padding_mask = ( + [] + if len(encoder_out["encoder_padding_mask"]) == 0 + else [ + x.index_select(0, new_order) + for x in encoder_out["encoder_padding_mask"] + ] + ) + + new_encoder_embedding = ( + [] + if len(encoder_out["encoder_embedding"]) == 0 + else [ + x.index_select(0, new_order) for x in encoder_out["encoder_embedding"] + ] + ) + + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: + for idx, state in enumerate(encoder_states): + encoder_states[idx] = state.index_select(1, new_order) + + return { + "encoder_out": new_encoder_out, # T x B x C + "encoder_padding_mask": new_encoder_padding_mask, # B x T + "encoder_embedding": new_encoder_embedding, # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], # B x T + "src_lengths": [], # B x 1 + } + + +# Note: +# dual input transformer: +# encoder: wav2vec for speech + mbart encoder for text +# decoder: mbart decoder for text +@register_model("dual_input_xm_transformer") +class DualInputXMTransformerModel(DualInputS2TTransformerModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @staticmethod + def add_args(parser): + """Add model-specific arguments to the parser.""" + # wav2vec encoder + Wav2VecEncoderWithAdaptor.add_args(parser) + # add_decoder_args(parser) + # mbart Transformer + parser.add_argument( + "--activation-fn", + type=str, + default="relu", + choices=utils.get_available_activation_fns(), + help="activation function to use", + ) + + parser.add_argument( + "--mbart-dropout", type=float, metavar="D", help="dropout probability" + ) + parser.add_argument( + "--mbart-attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights", + ) + parser.add_argument( + "--mbart-activation-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN.", + ) + + parser.add_argument( + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension", + ) + parser.add_argument( + "--encoder-ffn-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension for FFN", + ) + parser.add_argument( + "--encoder-layers", type=int, metavar="N", help="num encoder layers" + ) + parser.add_argument( + "--encoder-attention-heads", + type=int, + metavar="N", + help="num encoder attention heads", + ) + parser.add_argument( + "--encoder-normalize-before", + action="store_true", + help="apply layernorm before each encoder block", + ) + + parser.add_argument( + "--decoder-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension", + ) + parser.add_argument( + "--decoder-ffn-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension for FFN", + ) + parser.add_argument( + "--decoder-layers", type=int, metavar="N", help="num decoder layers" + ) + parser.add_argument( + "--decoder-attention-heads", + type=int, + metavar="N", + help="num decoder attention heads", + ) + parser.add_argument( + "--decoder-normalize-before", + action="store_true", + help="apply layernorm before each decoder block", + ) + parser.add_argument( + "--layernorm-embedding", + action="store_true", + help="add layernorm to embedding", + ) + parser.add_argument( + "--no-scale-embedding", + action="store_true", + help="if True, dont scale embeddings", + ) + parser.add_argument( + "--load-pretrained-mbart-from", + type=str, + metavar="STR", + help="model to take text encoder decoder weights from (for initialization)", + ) + # parser.add_argument("--finetune-w2v-params", type=str, metavar="STR", + # help="comma-separated param strings to finetune.") + parser.add_argument( + "--finetune-mbart-decoder-params", + type=str, + metavar="STR", + help="comma-separated param strings to finetune.", + ) + parser.add_argument( + "--finetune-mbart-encoder-params", + type=str, + metavar="STR", + help="comma-separated param strings to finetune.", + ) + parser.add_argument( + "--skip-encoder-projection", + action="store_true", + help="skip the projection layer in encoder", + ) + + parser.add_argument( + "--enc-grad-mult", + type=float, + metavar="V", + default=1.0, + help="multiply enc1 and enc2 gradient by V", + ) + parser.add_argument( + "--enc2-along-grad-mult", + type=float, + metavar="V", + default=1.0, + help="multiply enc2 gradient by V if only enc2 is used", + ) + parser.add_argument( + "--text-input-cost-ratio", + type=float, + default=1.0, + metavar="V", + help="text input cost ratio relative to speech input cost", + ) + parser.add_argument( + "--stack-w2v-mbart-encoder", + action="store_true", + help="stack w2v and mbart encoder", + ) + parser.add_argument( + "--stack-w2v-mbart-nonorm-encoder", + action="store_true", + help="stack w2v and mbart encoder", + ) + parser.add_argument( + "--no-final-norm-decoder", action="store_true", help="no layer norm" + ) + parser.add_argument( + "--drop-w2v-layers", + type=int, + default=0, + metavar="N", + help="drop w2v encoder layers", + ) + + parser.add_argument( + "--share-w2v-text-encoder", + action="store_true", + help="share w2v encoder layers with text encoder", + ) + parser.add_argument( + "--shared-w2v-layers", + type=int, + default=0, + metavar="N", + help="shared encoder layers from w2v encoder", + ) + + @classmethod + def build_encoder(cls, args, task): + _args = copy.deepcopy(args) + _args.dropout = args.mbart_dropout + _args.attention_dropout = args.mbart_attention_dropout + _args.activation_dropout = args.mbart_activation_dropout + _args.max_source_positions = 1024 + enc_emb = nn.Embedding( + len(task.src_dict), _args.encoder_embed_dim, task.src_dict.pad() + ) + text_encoder = TransformerEncoder(_args, task.src_dict, enc_emb) + spch_encoder = Wav2VecEncoderWithAdaptor(args) + if getattr(args, "load_pretrained_mbart_from", None): + text_encoder = checkpoint_utils.load_pretrained_component_from_model( + component=text_encoder, checkpoint=args.load_pretrained_mbart_from + ) + if getattr(args, "stack_w2v_mbart_encoder", False): + assert getattr(args, "share_w2v_text_encoder", False) is False + spch_encoder = StackedWav2VecEncoderWithAdaptor( + spch_encoder.w2v_encoder, + text_encoder.layers, + text_encoder.layer_norm, + spch_encoder.adaptor, + args.drop_w2v_layers, + ) + elif getattr(args, "stack_w2v_mbart_nonorm_encoder", False): + text_encoder.layer_norm = None + spch_encoder = StackedWav2VecEncoderWithAdaptor( + spch_encoder.w2v_encoder, + text_encoder.layers, + text_encoder.layer_norm, + spch_encoder.adaptor, + args.drop_w2v_layers, + ) + elif getattr(args, "share_w2v_text_encoder", False): + spch_encoder = SharedEncoder( + spch_encoder.w2v_encoder, + text_encoder, + spch_encoder.adaptor, + args.shared_w2v_layers, + ) + + for k, p in spch_encoder.named_parameters(): + # Freeze pretrained models by default + if hasattr( + args, "finetune_w2v_params" + ) and XMTransformerModel.finetune_params(args.finetune_w2v_params, k): + p.requires_grad = True + else: + p.requires_grad = False + for k, p in text_encoder.named_parameters(): + # Freeze pretrained models by default + if hasattr( + args, "finetune_mbart_encoder_params" + ) and XMTransformerModel.finetune_params( + args.finetune_mbart_encoder_params, k + ): + p.requires_grad = True + else: + p.requires_grad = False + cross_attentive_loss_before_last_layer = ( + 0 if getattr(args, "attentive_cost_regularization", 0.0) > 0.0 else -1 + ) + encoder = DualInputEncoder( + args, + spch_encoder, + text_encoder, + task.src_dict, + cross_attentive_loss_before_last_layer, + ) + return encoder + + @classmethod + def build_decoder(cls, args, task): + _args = copy.deepcopy(args) + _args.dropout = args.mbart_dropout + _args.attention_dropout = args.mbart_attention_dropout + _args.activation_dropout = args.mbart_activation_dropout + _args.max_target_positions = 1024 + dec_emb = nn.Embedding( + len(task.tgt_dict), _args.encoder_embed_dim, task.tgt_dict.pad() + ) + decoder = TransformerDecoder(_args, task.tgt_dict, dec_emb) + if getattr(args, "load_pretrained_mbart_from", None): + decoder = checkpoint_utils.load_pretrained_component_from_model( + component=decoder, checkpoint=args.load_pretrained_mbart_from + ) + if getattr(args, "no_final_norm_decoder", False): + decoder.layer_norm = None + for k, p in decoder.named_parameters(): + # Freeze pretrained models by default + if hasattr( + args, "finetune_mbart_decoder_params" + ) and XMTransformerModel.finetune_params( + args.finetune_mbart_decoder_params, k + ): + p.requires_grad = True + else: + p.requires_grad = False + + compute_cross_attentive_loss = ( + True if getattr(args, "attentive_cost_regularization", 0.0) > 0.0 else False + ) + cross_attentive_loss_without_norm = getattr( + args, "attentive_cost_without_normalize", False + ) + cross_attentive_loss_reverse = ( + False # getattr(args, "attentive_cost_reverse", False) + ) + decoder = TransformerMultiInputDecoder( + dictionary=task.target_dictionary, + spch_decoder=decoder, + text_decoder=decoder, + compute_cross_attentive_loss=compute_cross_attentive_loss, + cross_attentive_loss_with_norm=True + if not cross_attentive_loss_without_norm + else False, + cross_attentive_loss_reverse=cross_attentive_loss_reverse, + ) + return decoder + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + # make sure that all args are properly defaulted + # (in case there are any new ones) + dualinputxmtransformer_base(args) + + encoder = cls.build_encoder(args, task) + decoder = cls.build_decoder(args, task) + return cls(encoder, decoder) + + +@register_model_architecture("dual_input_xm_transformer", "dualinputxmtransformer_base") +def dualinputxmtransformer_base(args): + # wav2vec encoder + set_default_w2v_encoder_args(args) + set_default_adaptor_args(args) + + # mbart model + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) + args.encoder_ffn_embed_dim = getattr( + args, "encoder_ffn_embed_dim", 4 * args.encoder_embed_dim + ) + args.encoder_layers = getattr(args, "encoder_layers", 12) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) + args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0) + args.encoder_learned_pos = getattr(args, "encoder_learned_pos", True) + + args.decoder_embed_path = getattr(args, "decoder_embed_path", None) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4 * 1024) + args.decoder_layers = getattr(args, "decoder_layers", 12) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + + args.adaptive_input = getattr(args, "adaptive_input", False) + + args.mbart_attention_dropout = getattr(args, "mbart_attention_dropout", 0.0) + args.mbart_activation_dropout = getattr(args, "mbart_activation_dropout", 0.0) + args.mbart_dropout = getattr(args, "mbart_dropout", 0.1) + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", True + ) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) + + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + args.layernorm_embedding = getattr(args, "layernorm_embedding", True) + + args.activation_fn = getattr(args, "activation_fn", "gelu") + args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") + args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) diff --git a/examples/speech_text_joint_to_text/scripts/g2p_encode.py b/examples/speech_text_joint_to_text/scripts/g2p_encode.py new file mode 100644 index 0000000000..9db779396f --- /dev/null +++ b/examples/speech_text_joint_to_text/scripts/g2p_encode.py @@ -0,0 +1,191 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import itertools +import logging +import re +import time + +from g2p_en import G2p + +logger = logging.getLogger(__name__) + +FAIL_SENT = "FAILED_SENTENCE" + + +def parse(): + parser = argparse.ArgumentParser() + parser.add_argument("--data-path", type=str, required=True) + parser.add_argument("--out-path", type=str, required=True) + parser.add_argument("--lower-case", action="store_true") + parser.add_argument("--do-filter", action="store_true") + parser.add_argument("--use-word-start", action="store_true") + parser.add_argument("--dup-vowel", default=1, type=int) + parser.add_argument("--dup-consonant", default=1, type=int) + parser.add_argument("--no-punc", action="store_true") + parser.add_argument("--reserve-word", type=str, default="") + parser.add_argument( + "--reserve-first-column", + action="store_true", + help="first column is sentence id", + ) + ### + parser.add_argument("--parallel-process-num", default=1, type=int) + parser.add_argument("--logdir", default="") + args = parser.parse_args() + return args + + +def process_sent(sent, g2p, res_wrds, args): + sents = pre_process_sent(sent, args.do_filter, args.lower_case, res_wrds) + pho_seqs = [do_g2p(g2p, s, res_wrds, i == 0) for i, s in enumerate(sents)] + pho_seq = ( + [FAIL_SENT] + if [FAIL_SENT] in pho_seqs + else list(itertools.chain.from_iterable(pho_seqs)) + ) + if args.no_punc: + pho_seq = remove_punc(pho_seq) + if args.dup_vowel > 1 or args.dup_consonant > 1: + pho_seq = dup_pho(pho_seq, args.dup_vowel, args.dup_consonant) + if args.use_word_start: + pho_seq = add_word_start(pho_seq) + return " ".join(pho_seq) + + +def remove_punc(sent): + ns = [] + regex = re.compile("[^a-zA-Z0-9 ]") + for p in sent: + if (not regex.search(p)) or p == FAIL_SENT: + if p == " " and (len(ns) == 0 or ns[-1] == " "): + continue + ns.append(p) + return ns + + +def do_g2p(g2p, sent, res_wrds, is_first_sent): + if sent in res_wrds: + pho_seq = [res_wrds[sent]] + else: + pho_seq = g2p(sent) + if not is_first_sent: + pho_seq = [" "] + pho_seq # add space to separate + return pho_seq + + +def pre_process_sent(sent, do_filter, lower_case, res_wrds): + if do_filter: + sent = re.sub("-", " ", sent) + sent = re.sub("—", " ", sent) + if len(res_wrds) > 0: + wrds = sent.split() + wrds = ["SPLIT_ME " + w + " SPLIT_ME" if w in res_wrds else w for w in wrds] + sents = [x.strip() for x in " ".join(wrds).split("SPLIT_ME") if x.strip() != ""] + else: + sents = [sent] + if lower_case: + sents = [s.lower() if s not in res_wrds else s for s in sents] + return sents + + +def dup_pho(sent, dup_v_num, dup_c_num): + """ + duplicate phoneme defined as cmudict + http://www.speech.cs.cmu.edu/cgi-bin/cmudict + """ + if dup_v_num == 1 and dup_c_num == 1: + return sent + ns = [] + for p in sent: + ns.append(p) + if re.search(r"\d$", p): + for i in range(1, dup_v_num): + ns.append(f"{p}-{i}P") + elif re.search(r"\w", p): + for i in range(1, dup_c_num): + ns.append(f"{p}-{i}P") + return ns + + +def add_word_start(sent): + ns = [] + do_add = True + ws = "▁" + for p in sent: + if do_add: + p = ws + p + do_add = False + if p == " ": + do_add = True + else: + ns.append(p) + return ns + + +def load_reserve_word(reserve_word): + if reserve_word == "": + return [] + with open(reserve_word, "r") as fp: + res_wrds = [x.strip().split() for x in fp.readlines() if x.strip() != ""] + assert sum([0 if len(x) == 2 else 1 for x in res_wrds]) == 0 + res_wrds = dict(res_wrds) + return res_wrds + + +def process_sents(sents, args): + g2p = G2p() + out_sents = [] + res_wrds = load_reserve_word(args.reserve_word) + for sent in sents: + col1 = "" + if args.reserve_first_column: + col1, sent = sent.split(None, 1) + sent = process_sent(sent, g2p, res_wrds, args) + if args.reserve_first_column and col1 != "": + sent = f"{col1} {sent}" + out_sents.append(sent) + return out_sents + + +def main(): + args = parse() + out_sents = [] + with open(args.data_path, "r") as fp: + sent_list = [x.strip() for x in fp.readlines()] + if args.parallel_process_num > 1: + try: + import submitit + except ImportError: + logger.warn( + "submitit is not found and only one job is used to process the data" + ) + submitit = None + + if args.parallel_process_num == 1 or submitit is None: + out_sents = process_sents(sent_list, args) + else: + # process sentences with parallel computation + lsize = len(sent_list) // args.parallel_process_num + 1 + executor = submitit.AutoExecutor(folder=args.logdir) + executor.update_parameters(timeout_min=1000, cpus_per_task=4) + jobs = [] + for i in range(args.parallel_process_num): + job = executor.submit( + process_sents, sent_list[lsize * i : lsize * (i + 1)], args + ) + jobs.append(job) + is_running = True + while is_running: + time.sleep(5) + is_running = sum([job.done() for job in jobs]) < len(jobs) + out_sents = list(itertools.chain.from_iterable([job.result() for job in jobs])) + with open(args.out_path, "w") as fp: + fp.write("\n".join(out_sents) + "\n") + + +if __name__ == "__main__": + main() diff --git a/examples/speech_text_joint_to_text/tasks/__init__.py b/examples/speech_text_joint_to_text/tasks/__init__.py new file mode 100644 index 0000000000..d878278475 --- /dev/null +++ b/examples/speech_text_joint_to_text/tasks/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import importlib +import os + +for file in os.listdir(os.path.dirname(__file__)): + if file.endswith(".py") and not file.startswith("_"): + task_name = file[: file.find(".py")] + importlib.import_module("examples.speech_text_joint_to_text.tasks." + task_name) diff --git a/examples/speech_text_joint_to_text/tasks/speech_text_joint.py b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py new file mode 100644 index 0000000000..f2b3966d2d --- /dev/null +++ b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py @@ -0,0 +1,372 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import logging +import os +from argparse import Namespace +from pathlib import Path + +import torch +from fairseq.data import ( + encoders, + Dictionary, + ResamplingDataset, + TransformEosLangPairDataset, + ConcatDataset, +) +from fairseq.data.iterators import GroupedEpochBatchIterator +from fairseq.data.audio.multi_modality_dataset import ( + MultiModalityDataset, + LangPairMaskDataset, + ModalityDatasetItem, +) +from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset, SpeechToTextDatasetCreator +from fairseq.data.audio.speech_to_text_joint_dataset import ( + S2TJointDataConfig, + SpeechToTextJointDatasetCreator, +) +from fairseq.tasks import register_task +from fairseq.tasks.speech_to_text import SpeechToTextTask +from fairseq.tasks.translation import load_langpair_dataset + +logger = logging.getLogger(__name__) +LANG_TAG_TEMPLATE = "<lang:{}>" + + +@register_task("speech_text_joint_to_text") +class SpeechTextJointToTextTask(SpeechToTextTask): + """ + Task for joint training speech and text to text. + """ + + @classmethod + def add_args(cls, parser): + """Add task-specific arguments to the parser.""" + super(SpeechTextJointToTextTask, cls).add_args(parser) + ### + parser.add_argument( + "--parallel-text-data", + default="", + help="path to parallel text data directory", + ) + parser.add_argument( + "--max-tokens-text", + type=int, + metavar="N", + help="maximum tokens for encoder text input ", + ) + parser.add_argument( + "--max-positions-text", + type=int, + metavar="N", + default=400, + help="maximum tokens for per encoder text input ", + ) + parser.add_argument( + "--langpairs", + default=None, + metavar="S", + help='language pairs for text training, separated with ","', + ) + parser.add_argument( + "--speech-sample-ratio", + default=1, + type=float, + metavar="N", + help="Multiple Ratio for speech dataset with transcripts ", + ) + parser.add_argument( + "--text-sample-ratio", + default=1, + type=float, + metavar="N", + help="Multiple Ratio for text set ", + ) + parser.add_argument( + "--update-mix-data", + action="store_true", + help="use mixed data in one update when update-freq > 1", + ) + parser.add_argument( + "--load-speech-only", + action="store_true", + help="load speech data only", + ) + parser.add_argument( + "--mask-text-ratio", + type=float, + metavar="V", + default=0.0, + help="mask V source tokens for text only mode", + ) + parser.add_argument( + "--mask-text-type", + default="random", + choices=["random", "tail"], + help="mask text typed", + ) + parser.add_argument( + "--noise-token", + default="", + help="noise token for masking src text tokens if mask-text-ratio > 0", + ) + parser.add_argument( + "--infer-target-lang", + default="", + metavar="S", + help="target language for inference", + ) + + def __init__(self, args, src_dict, tgt_dict, infer_tgt_lang_id=None): + super().__init__(args, tgt_dict) + self.src_dict = src_dict + self.data_cfg = S2TJointDataConfig(Path(args.data) / args.config_yaml) + assert self.tgt_dict.pad() == self.src_dict.pad() + assert self.tgt_dict.eos() == self.src_dict.eos() + self.speech_only = args.load_speech_only + self._infer_tgt_lang_id = infer_tgt_lang_id + + @classmethod + def setup_task(cls, args, **kwargs): + """Setup the task (e.g., load dictionaries).""" + data_cfg = S2TJointDataConfig(Path(args.data) / args.config_yaml) + tgt_dict_path = Path(args.data) / data_cfg.vocab_filename + src_dict_path = Path(args.data) / data_cfg.src_vocab_filename + if (not os.path.isfile(src_dict_path)) or (not os.path.isfile(tgt_dict_path)): + raise FileNotFoundError("Dict not found: {}".format(args.data)) + src_dict = Dictionary.load(src_dict_path.as_posix()) + tgt_dict = Dictionary.load(tgt_dict_path.as_posix()) + + print("| src dictionary: {} types".format(len(src_dict))) + print("| tgt dictionary: {} types".format(len(tgt_dict))) + + if args.parallel_text_data != "": + if not os.path.isabs(args.parallel_text_data): + args.parallel_text_data = os.path.join( + args.data, args.parallel_text_data + ) + + if args.langpairs is None: + raise Exception( + "Could not infer language pair, please provide it explicitly" + ) + infer_tgt_lang_id = None + if args.infer_target_lang != "" and data_cfg.prepend_tgt_lang_tag_no_change: + tgt_lang_tag = SpeechToTextDataset.LANG_TAG_TEMPLATE.format( + args.infer_target_lang + ) + infer_tgt_lang_id = tgt_dict.index(tgt_lang_tag) + assert infer_tgt_lang_id != tgt_dict.unk() + return cls(args, src_dict, tgt_dict, infer_tgt_lang_id=infer_tgt_lang_id) + + def load_langpair_dataset(self, prepend_tgt_lang_tag=False, sampling_alpha=1.0, epoch=0): + lang_pairs = [] + text_dataset = None + split = "train" + for lp in self.args.langpairs.split(","): + src, tgt = lp.split("-") + text_dataset = load_langpair_dataset( + self.args.parallel_text_data, + split, + src, + self.src_dict, + tgt, + self.tgt_dict, + combine=True, + dataset_impl=None, + upsample_primary=1, + left_pad_source=False, + left_pad_target=False, + max_source_positions=self.args.max_positions_text, + max_target_positions=self.args.max_target_positions, + load_alignments=False, + truncate_source=False, + ) + if prepend_tgt_lang_tag: + # TODO + text_dataset = TransformEosLangPairDataset( + text_dataset, + src_eos=self.src_dict.eos(), + tgt_bos=self.tgt_dict.eos(), # 'prev_output_tokens' starts with eos + new_tgt_bos=self.tgt_dict.index(LANG_TAG_TEMPLATE.format(tgt)), + ) + lang_pairs.append(text_dataset) + if len(lang_pairs) > 1: + if sampling_alpha != 1.0: + size_ratios = SpeechToTextDatasetCreator.get_size_ratios( + self.args.langpairs.split(","), + [len(s) for s in lang_pairs], + alpha=sampling_alpha, + ) + lang_pairs = [ + ResamplingDataset( + d, size_ratio=r, epoch=epoch, replace=(r >= 1.0) + ) + for d, r in zip(lang_pairs, size_ratios) + ] + return ConcatDataset(lang_pairs) + return text_dataset + + def inference_step( + self, generator, models, sample, prefix_tokens=None, constraints=None + ): + with torch.no_grad(): + return generator.generate( + models, + sample, + prefix_tokens=prefix_tokens, + constraints=constraints, + bos_token=self._infer_tgt_lang_id, + ) + + def build_src_tokenizer(self, args): + logger.info(f"src-pre-tokenizer: {self.data_cfg.src_pre_tokenizer}") + return encoders.build_tokenizer(Namespace(**self.data_cfg.src_pre_tokenizer)) + + def build_src_bpe(self, args): + logger.info(f"tokenizer: {self.data_cfg.src_bpe_tokenizer}") + return encoders.build_bpe(Namespace(**self.data_cfg.src_bpe_tokenizer)) + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + """Load a given dataset split. + + Args: + split (str): name of the split (e.g., train, valid, test) + """ + is_train_split = split.startswith("train") + pre_tokenizer = self.build_tokenizer(self.args) + bpe_tokenizer = self.build_bpe(self.args) + src_pre_tokenizer = self.build_src_tokenizer(self.args) + src_bpe_tokenizer = self.build_src_bpe(self.args) + ast_dataset = SpeechToTextJointDatasetCreator.from_tsv( + self.args.data, + self.data_cfg, + split, + self.tgt_dict, + src_dict=None if self.speech_only else self.src_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + src_pre_tokenizer=src_pre_tokenizer, + src_bpe_tokenizer=src_bpe_tokenizer, + is_train_split=is_train_split, + epoch=epoch, + seed=self.args.seed, + ) + noise_token_id = -1 + text_dataset = None + if self.args.parallel_text_data != "" and is_train_split: + text_dataset = self.load_langpair_dataset( + self.data_cfg.prepend_tgt_lang_tag_no_change, + 1.0, + epoch=epoch, + ) + if self.args.mask_text_ratio > 0: + # add mask + noise_token_id = ( + self.src_dict.unk() + if self.args.noise_token == "" + else self.src_dict.index(self.args.noise_token) + ) + text_dataset = LangPairMaskDataset( + text_dataset, + src_bos=self.src_dict.bos(), + src_eos=self.src_dict.eos(), + noise_id=noise_token_id, + mask_ratio=self.args.mask_text_ratio, + mask_type=self.args.mask_text_type, + ) + + if text_dataset is not None: + mdsets = [ + ModalityDatasetItem( + "sup_speech", + ast_dataset, + (self.args.max_source_positions, self.args.max_target_positions), + self.args.max_tokens, + self.args.batch_size, + ), + ModalityDatasetItem( + "text", + text_dataset, + (self.args.max_positions_text, self.args.max_target_positions), + self.args.max_tokens_text + if self.args.max_tokens_text is not None + else self.args.max_tokens, + self.args.batch_size, + ), + ] + ast_dataset = MultiModalityDataset(mdsets) + self.datasets[split] = ast_dataset + + @property + def target_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.tgt_dict + + @property + def source_dictionary(self): + """Return the source :class:`~fairseq.data.Dictionary` (if applicable + for this task).""" + return None if self.speech_only else self.src_dict + + def get_batch_iterator( + self, + dataset, + max_tokens=None, + max_sentences=None, + max_positions=None, + ignore_invalid_inputs=False, + required_batch_size_multiple=1, + seed=1, + num_shards=1, + shard_id=0, + num_workers=0, + epoch=0, + data_buffer_size=0, + disable_iterator_cache=False, + ): + + if not isinstance(dataset, MultiModalityDataset): + return super(SpeechTextJointToTextTask, self).get_batch_iterator( + dataset, + max_tokens, + max_sentences, + max_positions, + ignore_invalid_inputs, + required_batch_size_multiple, + seed, + num_shards, + shard_id, + num_workers, + epoch, + data_buffer_size, + disable_iterator_cache, + ) + + mult_ratio = [self.args.speech_sample_ratio, self.args.text_sample_ratio] + assert len(dataset.datasets) == 2 + + # initialize the dataset with the correct starting epoch + dataset.set_epoch(epoch) + + batch_samplers = dataset.get_batch_samplers( + mult_ratio, required_batch_size_multiple, seed + ) + + # return a reusable, sharded iterator + epoch_iter = GroupedEpochBatchIterator( + dataset=dataset, + collate_fn=dataset.collater, + batch_samplers=batch_samplers, + seed=seed, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + epoch=epoch, + mult_rate=1 if self.args.update_mix_data else max(self.args.update_freq), + buffer_size=data_buffer_size, + ) + self.dataset_to_epoch_iter[dataset] = {} # refresh it every epoch + return epoch_iter diff --git a/fairseq/data/audio/multi_modality_dataset.py b/fairseq/data/audio/multi_modality_dataset.py new file mode 100644 index 0000000000..69d23d31c1 --- /dev/null +++ b/fairseq/data/audio/multi_modality_dataset.py @@ -0,0 +1,263 @@ +# Copyright (c) 2021-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import math +from typing import List, Optional, NamedTuple + +import numpy as np +import torch +from fairseq.data import ( + ConcatDataset, + LanguagePairDataset, + FileAudioDataset, + data_utils, +) +from fairseq.data import FairseqDataset + +logger = logging.getLogger(__name__) + + +class ModalityDatasetItem(NamedTuple): + datasetname: str + dataset: any + max_positions: List[int] + max_tokens: Optional[int] = None + max_sentences: Optional[int] = None + +# MultiModalityDataset: it concate multiple datasets with different modalities. +# Compared with ConcatDataset it can 1) sample data given the ratios for different datasets +# 2) it adds mode to indicate what type of the data samples come from. +# It will be used with GroupedEpochBatchIterator together to generate mini-batch with samples +# from the same type of dataset +# If only one dataset is used, it will perform like the original dataset with mode added +class MultiModalityDataset(ConcatDataset): + def __init__(self, datasets: List[ModalityDatasetItem]): + id_to_mode = [] + dsets = [] + max_tokens = [] + max_sentences = [] + max_positions = [] + for dset in datasets: + id_to_mode.append(dset.datasetname) + dsets.append(dset.dataset) + max_tokens.append(dset.max_tokens) + max_positions.append(dset.max_positions) + max_sentences.append(dset.max_sentences) + weights = [1.0 for s in dsets] + super().__init__(dsets, weights) + self.max_tokens = max_tokens + self.max_positions = max_positions + self.max_sentences = max_sentences + self.id_to_mode = id_to_mode + self.raw_sub_batch_samplers = [] + self._cur_epoch = 0 + + def set_epoch(self, epoch): + super().set_epoch(epoch) + self._cur_epoch = epoch + + def __getitem__(self, idx): + dataset_idx, sample_idx = self._get_dataset_and_sample_index(idx) + sample = self.datasets[dataset_idx][sample_idx] + return (dataset_idx, sample) + + def collater(self, samples): + if len(samples) == 0: + return {} + dataset_idx = samples[0][0] + # make sure all samples in samples are from same dataset + assert sum([0 if dataset_idx == s[0] else 1 for s in samples]) == 0 + samples = self.datasets[dataset_idx].collater([x[1] for x in samples]) + # add mode + samples["net_input"]["mode"] = self.id_to_mode[dataset_idx] + + return samples + + def size(self, index: int): + if len(self.datasets) == 1: + return self.datasets[0].size(index) + return super().size(index) + + @property + def sizes(self): + if len(self.datasets) == 1: + return self.datasets[0].sizes + super().sizes + + def ordered_indices(self): + """ + Returns indices sorted by length. So less padding is needed. + """ + if len(self.datasets) == 1: + return self.datasets[0].ordered_indices() + indices_group = [] + for d_idx, ds in enumerate(self.datasets): + sample_num = self.cumulative_sizes[d_idx] + if d_idx > 0: + sample_num = sample_num - self.cumulative_sizes[d_idx - 1] + assert sample_num == len(ds) + indices_group.append(ds.ordered_indices()) + return indices_group + + def get_raw_batch_samplers(self, required_batch_size_multiple, seed): + if len(self.raw_sub_batch_samplers) > 0: + logger.info(" raw_sub_batch_samplers exists. No action is taken") + return + with data_utils.numpy_seed(seed): + indices = self.ordered_indices() + for i, ds in enumerate(self.datasets): + indices[i] = ds.filter_indices_by_size( + indices[i], + self.max_positions[i], + )[0] + sub_batch_sampler = ds.batch_by_size( + indices[i], + max_tokens=self.max_tokens[i], + max_sentences=self.max_sentences[i], + required_batch_size_multiple=required_batch_size_multiple, + ) + self.raw_sub_batch_samplers.append(sub_batch_sampler) + + def get_batch_samplers(self, mult_ratios, required_batch_size_multiple, seed): + self.get_raw_batch_samplers(required_batch_size_multiple, seed) + batch_samplers = [] + for i, _ in enumerate(self.datasets): + if i > 0: + sub_batch_sampler = [ + [y + self.cumulative_sizes[i - 1] for y in x] + for x in self.raw_sub_batch_samplers[i] + ] + else: + sub_batch_sampler = list(self.raw_sub_batch_samplers[i]) + smp_r = mult_ratios[i] + if smp_r != 1: + is_increase = "increased" if smp_r > 1 else "decreased" + logger.info( + "number of batch for the dataset {} is {} from {} to {}".format( + self.id_to_mode[i], + is_increase, + len(sub_batch_sampler), + int(len(sub_batch_sampler) * smp_r), + ) + ) + mul_samplers = [] + for _ in range(math.floor(smp_r)): + mul_samplers = mul_samplers + sub_batch_sampler + if math.floor(smp_r) != smp_r: + with data_utils.numpy_seed(seed + self._cur_epoch): + np.random.shuffle(sub_batch_sampler) + smp_num = int( + (smp_r - math.floor(smp_r)) * len(sub_batch_sampler) + ) + mul_samplers = mul_samplers + sub_batch_sampler[:smp_num] + sub_batch_sampler = mul_samplers + else: + logger.info( + "dataset {} batch number is {} ".format( + self.id_to_mode[i], len(sub_batch_sampler) + ) + ) + batch_samplers.append(sub_batch_sampler) + + return batch_samplers + + +class LangPairMaskDataset(FairseqDataset): + def __init__( + self, + dataset: LanguagePairDataset, + src_eos: int, + src_bos: Optional[int] = None, + noise_id: Optional[int] = -1, + mask_ratio: Optional[float] = 0, + mask_type: Optional[str] = "random", + ): + self.dataset = dataset + self.src_eos = src_eos + self.src_bos = src_bos + self.noise_id = noise_id + self.mask_ratio = mask_ratio + self.mask_type = mask_type + assert mask_type in ("random", "tail") + + @property + def src_sizes(self): + return self.dataset.src_sizes + + @property + def tgt_sizes(self): + return self.dataset.tgt_sizes + + @property + def sizes(self): + # dataset.sizes can be a dynamically computed sizes: + return self.dataset.sizes + + def get_batch_shapes(self): + return self.dataset.buckets + + def num_tokens_vec(self, indices): + return self.dataset.num_tokens_vec(indices) + + def __len__(self): + return len(self.dataset) + + def num_tokens(self, index): + return self.dataset.num_tokens(index) + + def size(self, index): + return self.dataset.size(index) + + def ordered_indices(self): + return self.dataset.ordered_indices() + + @property + def supports_prefetch(self): + return getattr(self.dataset, "supports_prefetch", False) + + def prefetch(self, indices): + return self.dataset.prefetch(indices) + + def mask_src_tokens(self, sample): + src_item = sample["source"] + mask = None + if self.mask_type == "random": + mask = torch.rand(len(src_item)).le(self.mask_ratio) + else: + mask = torch.ones(len(src_item)) + mask[: int(len(src_item) * (1 - self.mask_ratio))] = 0 + mask = mask.eq(1) + if src_item[0] == self.src_bos: + mask[0] = False + if src_item[-1] == self.src_eos: + mask[-1] = False + mask_src_item = src_item.masked_fill(mask, self.noise_id) + smp = {"id": sample["id"], "source": mask_src_item, "target": sample["target"]} + return smp + + def __getitem__(self, index): + sample = self.dataset[index] + if self.mask_ratio > 0: + sample = self.mask_src_tokens(sample) + return sample + + def collater(self, samples, pad_to_length=None): + return self.dataset.collater(samples, pad_to_length) + + +class FileAudioDatasetWrapper(FileAudioDataset): + def collater(self, samples): + samples = super().collater(samples) + if len(samples) == 0: + return {} + samples["net_input"]["src_tokens"] = samples["net_input"]["source"] + samples["net_input"]["prev_output_tokens"] = None + del samples["net_input"]["source"] + samples["net_input"]["src_lengths"] = None + samples["net_input"]["alignment"] = None + return samples diff --git a/fairseq/data/audio/speech_to_text_joint_dataset.py b/fairseq/data/audio/speech_to_text_joint_dataset.py new file mode 100644 index 0000000000..885ee7e0a3 --- /dev/null +++ b/fairseq/data/audio/speech_to_text_joint_dataset.py @@ -0,0 +1,288 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from pathlib import Path +from typing import Dict, List, Optional, NamedTuple + +import torch +from fairseq.data import ( + ConcatDataset, + Dictionary, + ResamplingDataset, + data_utils as fairseq_data_utils, +) +from fairseq.data.audio.speech_to_text_dataset import ( + SpeechToTextDataset, + S2TDataConfig, + SpeechToTextDatasetCreator, +) + + +logger = logging.getLogger(__name__) + + +class S2TJointDataConfig(S2TDataConfig): + """Wrapper class for data config YAML""" + + @property + def src_vocab_filename(self): + """fairseq vocabulary file under data root""" + return self.config.get("src_vocab_filename", "src_dict.txt") + + @property + def src_pre_tokenizer(self) -> Dict: + """Pre-tokenizer to apply before subword tokenization. Returning + a dictionary with `tokenizer` providing the tokenizer name and + the other items providing the tokenizer-specific arguments. + Tokenizers are defined in `fairseq.data.encoders.*`""" + return self.config.get("src_pre_tokenizer", {"tokenizer": None}) + + @property + def src_bpe_tokenizer(self) -> Dict: + """Subword tokenizer to apply on source text after pre-tokenization. + Returning a dictionary with `bpe` providing the tokenizer name and + the other items providing the tokenizer-specific arguments. + Tokenizers are defined in `fairseq.data.encoders.*`""" + return self.config.get("src_bpe_tokenizer", {"bpe": None}) + + @property + def prepend_tgt_lang_tag_no_change(self) -> bool: + """Prepend target lang ID token as the prev_output_tokens BOS (e.g. for + to-many multilingual setting). No change needed during inference. + """ + return self.config.get("prepend_tgt_lang_tag_no_change", False) + + +class SpeechToTextJointDatasetItem(NamedTuple): + index: int + source: torch.Tensor + target: Optional[torch.Tensor] = None + src_txt_tokens: Optional[torch.Tensor] = None + tgt_lang_tag: Optional[int] = None + + +class SpeechToTextJointDataset(SpeechToTextDataset): + def __init__( + self, + split: str, + is_train_split: bool, + cfg: S2TJointDataConfig, + audio_paths: List[str], + n_frames: List[int], + src_texts: Optional[List[str]] = None, + tgt_texts: Optional[List[str]] = None, + speakers: Optional[List[str]] = None, + src_langs: Optional[List[str]] = None, + tgt_langs: Optional[List[str]] = None, + ids: Optional[List[str]] = None, + tgt_dict: Optional[Dictionary] = None, + src_dict: Optional[Dictionary] = None, + pre_tokenizer=None, + bpe_tokenizer=None, + src_pre_tokenizer=None, + src_bpe_tokenizer=None, + ): + super().__init__( + split, + is_train_split, + cfg, + audio_paths, + n_frames, + src_texts=src_texts, + tgt_texts=tgt_texts, + speakers=speakers, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + tgt_dict=tgt_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + ) + + self.src_dict = src_dict + self.src_pre_tokenizer = src_pre_tokenizer + self.src_bpe_tokenizer = src_bpe_tokenizer + + def get_tokenized_src_text(self, index: int): + text = self.tokenize(self.src_pre_tokenizer, self.src_texts[index]) + text = self.tokenize(self.src_bpe_tokenizer, text) + return text + + def __getitem__(self, index: int) -> SpeechToTextJointDatasetItem: + s2t_dataset_item = super().__getitem__(index) + src_tokens = None + if self.src_texts is not None and self.src_dict is not None: + src_tokens = self.get_tokenized_src_text(index) + src_tokens = self.src_dict.encode_line( + src_tokens, add_if_not_exist=False, append_eos=True + ).long() + tgt_lang_tag = None + if self.cfg.prepend_tgt_lang_tag_no_change: + # prepend_tgt_lang_tag_no_change: modify prev_output_tokens instead + tgt_lang_tag = self.get_lang_tag_idx(self.tgt_langs[index], self.tgt_dict) + + return SpeechToTextJointDatasetItem( + index=index, + source=s2t_dataset_item.source, + target=s2t_dataset_item.target, + src_txt_tokens=src_tokens, + tgt_lang_tag=tgt_lang_tag, + ) + + def __len__(self): + return self.n_samples + + def collater(self, samples: List[SpeechToTextJointDatasetItem]) -> Dict: + s2t_out = super().collater(samples, return_order=True) + if s2t_out == {}: + return s2t_out + net_input, order = s2t_out["net_input"], s2t_out["order"] + + if self.src_texts is not None and self.src_dict is not None: + src_txt_tokens = fairseq_data_utils.collate_tokens( + [x.src_txt_tokens for x in samples], + self.src_dict.pad(), + self.src_dict.eos(), + left_pad=False, + move_eos_to_beginning=False, + ) + src_txt_tokens = src_txt_tokens.index_select(0, order) + src_txt_lengths = torch.tensor( + [x.src_txt_tokens.size()[0] for x in samples], dtype=torch.long + ).index_select(0, order) + net_input["src_txt_tokens"] = src_txt_tokens + net_input["src_txt_lengths"] = src_txt_lengths + + if self.tgt_texts is not None and samples[0].tgt_lang_tag is not None: + for i in range(len(samples)): + net_input["prev_output_tokens"][i][0] = samples[order[i]].tgt_lang_tag + + out = { + "id": s2t_out["id"], + "net_input": net_input, + "target": s2t_out["target"], + "target_lengths": s2t_out["target_lengths"], + "ntokens": s2t_out["ntokens"], + "nsentences": len(samples), + } + return out + + +class SpeechToTextJointDatasetCreator(SpeechToTextDatasetCreator): + @classmethod + def _from_list( + cls, + split_name: str, + is_train_split, + samples: List[Dict], + cfg: S2TJointDataConfig, + tgt_dict, + src_dict, + pre_tokenizer, + bpe_tokenizer, + src_pre_tokenizer, + src_bpe_tokenizer, + ) -> SpeechToTextJointDataset: + audio_root = Path(cfg.audio_root) + ids = [s[cls.KEY_ID] for s in samples] + audio_paths = [(audio_root / s[cls.KEY_AUDIO]).as_posix() for s in samples] + n_frames = [int(s[cls.KEY_N_FRAMES]) for s in samples] + tgt_texts = [s[cls.KEY_TGT_TEXT] for s in samples] + src_texts = [s.get(cls.KEY_SRC_TEXT, cls.DEFAULT_SRC_TEXT) for s in samples] + speakers = [s.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for s in samples] + src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] + tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] + return SpeechToTextJointDataset( + split_name, + is_train_split, + cfg, + audio_paths, + n_frames, + src_texts=src_texts, + tgt_texts=tgt_texts, + speakers=speakers, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + tgt_dict=tgt_dict, + src_dict=src_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + src_pre_tokenizer=src_pre_tokenizer, + src_bpe_tokenizer=src_bpe_tokenizer, + ) + + @classmethod + def _from_tsv( + cls, + root: str, + cfg: S2TJointDataConfig, + split: str, + tgt_dict, + src_dict, + is_train_split: bool, + pre_tokenizer, + bpe_tokenizer, + src_pre_tokenizer, + src_bpe_tokenizer, + ) -> SpeechToTextJointDataset: + samples = cls._load_samples_from_tsv(root, split) + return cls._from_list( + split, + is_train_split, + samples, + cfg, + tgt_dict, + src_dict, + pre_tokenizer, + bpe_tokenizer, + src_pre_tokenizer, + src_bpe_tokenizer, + ) + + @classmethod + def from_tsv( + cls, + root: str, + cfg: S2TJointDataConfig, + splits: str, + tgt_dict, + src_dict, + pre_tokenizer, + bpe_tokenizer, + src_pre_tokenizer, + src_bpe_tokenizer, + is_train_split: bool, + epoch: int, + seed: int, + ) -> SpeechToTextJointDataset: + datasets = [ + cls._from_tsv( + root, + cfg, + split, + tgt_dict, + src_dict, + is_train_split, + pre_tokenizer, + bpe_tokenizer, + src_pre_tokenizer, + src_bpe_tokenizer, + ) + for split in splits.split(",") + ] + + if is_train_split and len(datasets) > 1 and cfg.sampling_alpha != 1.0: + # temperature-based sampling + size_ratios = cls.get_size_ratios(datasets, alpha=cfg.sampling_alpha) + datasets = [ + ResamplingDataset( + d, size_ratio=r, seed=seed, epoch=epoch, replace=(r >= 1.0) + ) + for r, d in zip(size_ratios, datasets) + ] + + return ConcatDataset(datasets) if len(datasets) > 1 else datasets[0] diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 86f6d05533..1ce26e57e5 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -638,3 +638,128 @@ def __next__(self): if item is _sentinel: raise StopIteration() return item + +class GroupedEpochBatchIterator(EpochBatchIterator): + """Grouped version of EpochBatchIterator + It takes several samplers from different datasets. + Each epoch shuffle the dataset wise sampler individually with different + random seed. The those sub samplers are combined with into + one big samplers with deterministic permutation to mix batches from + different datasets. It will act like EpochBatchIterator but make sure + 1) data from one data set each time + 2) for different workers, they use the same order to fetch the data + so they will use data from the same dataset everytime + mult_rate is used for update_freq > 1 case where we want to make sure update_freq + mini-batches come from same source + """ + + def __init__( + self, + dataset, + collate_fn, + batch_samplers, + seed=1, + num_shards=1, + shard_id=0, + num_workers=0, + epoch=0, + mult_rate=1, + buffer_size=0, + ): + super().__init__( + dataset, + collate_fn, + batch_samplers, + seed, + num_shards, + shard_id, + num_workers, + epoch, + buffer_size, + ) + # level 0: sub-samplers 1: batch_idx 2: batches + self._frozen_batches = tuple([tuple(sub_batch) for sub_batch in batch_samplers]) + self.step_size = mult_rate * num_shards + + self.lengths = [ + (len(x) // self.step_size) * self.step_size for x in self.frozen_batches + ] + + def __len__(self): + return sum(self.lengths) + + @property + def first_batch(self): + if len(self.frozen_batches) == 0: + raise Exception( + "The dataset is empty. This could indicate " + "that all elements in the dataset have been skipped. " + "Try increasing the max number of allowed tokens or using " + "a larger dataset." + ) + + if self.dataset.supports_fetch_outside_dataloader: + return self.collate_fn([self.dataset[i] for i in self.frozen_batches[0][0]]) + else: + return "DUMMY" + + def _get_iterator_for_epoch( + self, epoch, shuffle, fix_batches_to_gpus=False, offset=0 + ): + def shuffle_batches(batches, seed): + with data_utils.numpy_seed(seed): + np.random.shuffle(batches) + return batches + + def return_full_batches(batch_sets, seed, shuffle): + if shuffle: + batch_sets = [shuffle_batches(list(x), seed) for x in batch_sets] + + batch_sets = [ + batch_sets[i][: self.lengths[i]] for i in range(len(batch_sets)) + ] + batches = list(itertools.chain.from_iterable(batch_sets)) + + if shuffle: + with data_utils.numpy_seed(seed): + idx = np.random.permutation(len(batches) // self.step_size) + if len(idx) * self.step_size != len(batches): + raise ValueError( + "ERROR: %d %d %d %d" + % (len(idx), self.step_size, len(batches), self.shard_id), + ":".join(["%d" % x for x in self.lengths]), + ) + mini_shards = [ + batches[i * self.step_size : (i + 1) * self.step_size] + for i in idx + ] + batches = list(itertools.chain.from_iterable(mini_shards)) + + return batches + + if self._supports_prefetch: + raise NotImplementedError("To be implemented") + else: + batches = return_full_batches( + self.frozen_batches, self.seed + epoch, shuffle + ) + batches = list( + ShardedIterator(batches, self.num_shards, self.shard_id, fill_value=[]) + ) + + if offset > 0 and offset >= len(batches): + return None + + if self.num_workers > 0: + os.environ["PYTHONWARNINGS"] = "ignore:semaphore_tracker:UserWarning" + + itr = torch.utils.data.DataLoader( + self.dataset, + collate_fn=self.collate_fn, + batch_sampler=batches[offset:], + num_workers=self.num_workers, + ) + if self.buffer_size > 0: + itr = BufferedIterator(self.buffer_size, itr) + + return CountingIterator(itr, start=offset) diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index c6ae9b17ba..cac365cbb8 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -5,4 +5,5 @@ from .berard import * # noqa from .convtransformer import * # noqa -from .s2t_transformer import * # noqa +from .s2t_transformer import * # noqa +from .xm_transformer import * # noqa diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py new file mode 100644 index 0000000000..03c434b5ea --- /dev/null +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -0,0 +1,504 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import copy +from typing import Dict, List, Optional, Tuple + +from fairseq import utils, checkpoint_utils +from fairseq.models import (FairseqEncoderDecoderModel, FairseqEncoder, + register_model, register_model_architecture) +from fairseq.models.transformer import Embedding, TransformerDecoder +from fairseq.models.wav2vec import Wav2VecEncoder +from fairseq.modules.layer_norm import LayerNorm +from fairseq.data.data_utils import lengths_to_padding_mask +from torch import Tensor +import torch.nn as nn + + +logger = logging.getLogger(__name__) + + +class Conv1dAdaptor(nn.Module): + def __init__(self, in_dim, out_dim, n_layers=3, kernel_size=3, stride=2, + add_layernorm=False): + super().__init__() + self.layers = nn.ModuleList( + nn.Conv1d(in_dim if i == 0 else out_dim, out_dim * 2, kernel_size, + stride=stride, padding=kernel_size // 2) + for i in range(n_layers) + ) + self.layernorms = None + if add_layernorm: + self.layernorms = nn.ModuleList(LayerNorm(out_dim) + for _ in range(n_layers)) + self.stride = stride + + @classmethod + def add_args(cls, parser): + parser.add_argument("--adaptor-n-layers", type=int) + parser.add_argument("--adaptor-kernel-size", type=int) + parser.add_argument("--adaptor-stride", type=int) + parser.add_argument("--adaptor-layernorm", action='store_true') + + def get_out_seq_lens_tensor(self, in_seq_lens_tensor): + out = in_seq_lens_tensor.clone() + for _ in self.layers: + out = ((out.float() - 1) / self.stride + 1).floor().long() + return out + + def forward(self, x, padding_mask): + # T x B x C -> B x C x T + x = x.transpose(0, 1).transpose(1, 2) + for i, layer in enumerate(self.layers): + x = nn.functional.glu(layer(x), dim=1) + if self.layernorms is not None: + x = self.layernorms[i](x.transpose(1, 2)).transpose(1, 2) + # B x C x T -> T x B x C + x = x.transpose(1, 2).transpose(0, 1) + + if padding_mask is None: + out_padding_mask = None + else: + out_lengths = self.get_out_seq_lens_tensor((~padding_mask).sum(1)) + out_padding_mask = lengths_to_padding_mask(out_lengths) + return x, out_padding_mask + + +def add_wav2vec_asr_args(parser): + parser.add_argument("--w2v-path", help="path to wav2vec 2.0 model") + parser.add_argument( + "--no-pretrained-weights", + action="store_true", + help="if true, does not load pretrained weights", + ) + parser.add_argument( + "--dropout-input", + type=float, + metavar="D", + help="dropout to apply to the input (after feat extr)", + ) + parser.add_argument( + "--final-dropout", + type=float, + metavar="D", + help="dropout after transformer and before final projection", + ) + parser.add_argument( + "--apply-mask", action="store_true", help="apply masking during fine-tuning" + ) + parser.add_argument( + "--dropout", + type=float, + metavar="D", + help="dropout probability inside wav2vec 2.0 model", + ) + parser.add_argument( + "--attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights inside wav2vec 2.0 model", + ) + parser.add_argument( + "--activation-dropout", + "--relu-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN inside wav2vec 2.0 model", + ) + + parser.add_argument( + "--mask-length", type=int, help="repeat the mask indices multiple times" + ) + + parser.add_argument( + "--mask-prob", type=float, help="probability of replacing a token with mask" + ) + + parser.add_argument( + "--mask-selection", + type=str, + choices=["static", "uniform", "normal", "poisson"], + help="how to choose masks", + ) + + parser.add_argument( + "--mask-other", + type=float, + help="stdev of the mask length in case of 'normal' selection strategy", + ) + + parser.add_argument( + "--no-mask-overlap", + action="store_true", + help="whether to allow masks to overlap", + ) + + parser.add_argument( + "--mask-channel-length", type=int, help="repeat the mask indices multiple times" + ) + + parser.add_argument( + "--mask-channel-prob", + type=float, + help="probability of replacing a token with mask", + ) + + parser.add_argument( + "--mask-channel-selection", + type=str, + choices=["static", "uniform", "normal", "poisson"], + help="how to choose masks", + ) + + parser.add_argument( + "--mask-channel-other", + type=float, + help="stdev of the mask length in case of 'normal' selection strategy", + ) + + parser.add_argument( + "--no-mask-channel-overlap", + action="store_true", + help="whether to allow masks to overlap", + ) + + parser.add_argument( + "--freeze-finetune-updates", + default=0, + type=int, + help="dont finetune wav2vec for this many updates", + ) + + parser.add_argument( + "--feature-grad-mult", + default=None, + type=float, + help="reset feature grad mult in wav2vec 2.0 to this", + ) + + parser.add_argument( + "--layerdrop", + default=0.0, + type=float, + help="probability of dropping a layer in wav2vec 2.0", + ) + parser.add_argument("--w2v-args", default=None) + + +class Wav2VecEncoderWithAdaptor(FairseqEncoder): + def __init__(self, args): + super().__init__(None) + self.w2v_encoder = Wav2VecEncoder(args) + encoder_out_dim = self.w2v_encoder.w2v_model.encoder.embedding_dim + # Projection + 8x shrinking + self.adaptor = Conv1dAdaptor( + encoder_out_dim, args.decoder_embed_dim, + n_layers=args.adaptor_n_layers, + kernel_size=args.adaptor_kernel_size, stride=args.adaptor_stride, + add_layernorm=args.adaptor_layernorm + ) + for k, p in self.w2v_encoder.w2v_model.named_parameters(): + # Freeze pretrained models by default + if hasattr(args, 'finetune_w2v_params') and XMTransformerModel.finetune_params( + args.finetune_w2v_params, k): + p.requires_grad = True + else: + p.requires_grad = False + + @classmethod + def add_args(cls, parser): + add_wav2vec_asr_args(parser) + parser.add_argument( + "--normalize", action="store_true", + help="if set, normalizes input to have 0 mean and unit variance", + ) + parser.add_argument("--finetune-w2v-params", type=str, metavar="STR", + help="comma-separated param strings to finetune.") + Conv1dAdaptor.add_args(parser) + + def forward(self, src_tokens, src_lengths=None, **kwargs): + padding_mask = lengths_to_padding_mask(src_lengths) + out = self.w2v_encoder.forward(src_tokens, padding_mask, tbc=True) + x = out["encoder_out"] + enc_padding_mask = None + if out["encoder_padding_mask"] is not None: + enc_padding_mask = out["encoder_padding_mask"].transpose(0, 1) # T X B --> B X T + + x, enc_padding_mask = self.adaptor(x, enc_padding_mask) + + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [enc_padding_mask] if enc_padding_mask.any() else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": [], # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + + def reorder_encoder_out(self, encoder_out, new_order): + new_encoder_out = ( + [] if len(encoder_out["encoder_out"]) == 0 + else [x.index_select(1, new_order) for x in encoder_out["encoder_out"]] + ) + + new_encoder_padding_mask = ( + [] if len(encoder_out["encoder_padding_mask"]) == 0 + else [x.index_select(0, new_order) for x in + encoder_out["encoder_padding_mask"]] + ) + + new_encoder_embedding = ( + [] if len(encoder_out["encoder_embedding"]) == 0 + else [x.index_select(0, new_order) for x in + encoder_out["encoder_embedding"]] + ) + + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: + for idx, state in enumerate(encoder_states): + encoder_states[idx] = state.index_select(1, new_order) + + return { + "encoder_out": new_encoder_out, # T x B x C + "encoder_padding_mask": new_encoder_padding_mask, # B x T + "encoder_embedding": new_encoder_embedding, # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], # B x T + "src_lengths": [], # B x 1 + } + + +def add_decoder_args(parser): + parser.add_argument("--activation-fn", type=str, default='relu', + choices=utils.get_available_activation_fns(), + help="activation function to use") + parser.add_argument("--decoder-dropout", type=float, metavar="D", + help="dropout probability") + parser.add_argument("--decoder-attention-dropout", type=float, + metavar="D", + help="dropout probability for attention weights") + parser.add_argument("--decoder-activation-dropout", type=float, + metavar="D", + help="dropout probability after activation in FFN.") + parser.add_argument("--decoder-embed-dim", type=int, metavar="N", + help="decoder embedding dimension") + parser.add_argument("--decoder-ffn-embed-dim", type=int, metavar="N", + help="decoder embedding dimension for FFN") + parser.add_argument("--decoder-layers", type=int, metavar="N", + help="num decoder layers") + parser.add_argument("--decoder-attention-heads", type=int, metavar="N", + help="num decoder attention heads") + parser.add_argument("--decoder-normalize-before", action="store_true", + help="apply layernorm before each decoder block") + parser.add_argument("--layernorm-embedding", action="store_true", + help="add layernorm to embedding") + parser.add_argument("--no-scale-embedding", action="store_true", + help="if True, dont scale embeddings") + parser.add_argument( + "--load-pretrained-decoder-from", type=str, metavar="STR", + help="model to take decoder weights from (for initialization)" + ) + parser.add_argument("--finetune-decoder-params", type=str, + metavar="STR", + help="comma-separated param strings to finetune.") + parser.add_argument("--checkpoint-activations", action="store_true") + + +@register_model("xm_transformer") +class XMTransformerModel(FairseqEncoderDecoderModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @classmethod + def add_args(cls, parser): + """Add model-specific arguments to the parser.""" + Wav2VecEncoderWithAdaptor.add_args(parser) + add_decoder_args(parser) + + @classmethod + def build_encoder(cls, args): + _args = copy.deepcopy(args) + state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) + if state.get("cfg") is not None: + encoder_embed_dim = state["cfg"]._content["model"]["encoder_embed_dim"] + elif state.get("args") is not None: + encoder_embed_dim = state["args"].encoder_embed_dim + else: + raise ValueError(f"Invalid config in {args.w2v_path}") + _args.decoder_embed_dim = encoder_embed_dim + encoder = Wav2VecEncoderWithAdaptor(_args) + return encoder + + @classmethod + def build_decoder(cls, args, task, embed_tokens): + _args = copy.deepcopy(args) + _args.dropout = args.decoder_dropout + _args.attention_dropout = args.decoder_attention_dropout + _args.activation_dropout = args.decoder_activation_dropout + _args.max_target_positions = 1024 + + decoder = TransformerDecoder(_args, task.target_dictionary, + embed_tokens) + if getattr(args, "load_pretrained_decoder_from", None): + decoder = checkpoint_utils.load_pretrained_component_from_model( + component=decoder, checkpoint=args.load_pretrained_decoder_from + ) + for k, p in decoder.named_parameters(): + # Freeze pretrained models by default + if hasattr(args, 'finetune_decoder_params') and XMTransformerModel.finetune_params( + args.finetune_decoder_params, k): + p.requires_grad = True + else: + p.requires_grad = False + return decoder + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + + # make sure all arguments are present in older models + base_architecture(args) + + def build_embedding(dictionary, embed_dim): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + return Embedding(num_embeddings, embed_dim, padding_idx) + + decoder_embed_tokens = build_embedding(task.target_dictionary, + args.decoder_embed_dim) + encoder = cls.build_encoder(args) + decoder = cls.build_decoder(args, task, decoder_embed_tokens) + return cls(encoder, decoder) + + def get_normalized_probs( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): + # net_output['encoder_out'] is a (B, T, D) tensor + lprobs = self.get_normalized_probs_scriptable(net_output, log_probs, + sample) + lprobs.batch_first = True + return lprobs + + def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): + """ + The forward method inherited from the base class has a **kwargs + argument in its input, which is not supported in torchscript. This + method overrites the forward method definition without **kwargs. + """ + encoder_out = self.encoder(src_tokens=src_tokens, + src_lengths=src_lengths, **kwargs) + decoder_out = self.decoder(prev_output_tokens=prev_output_tokens, + encoder_out=encoder_out) + return decoder_out + + def upgrade_state_dict(self, state_dict): + for k, _ in state_dict.items(): + if 'adaptor.layers' in state_dict: + print(k) + new = k.replace('adaptor.layers', 'adaptor_layers') + state_dict[new] = state_dict[k] + del state_dict[k] + + @staticmethod + def finetune_params(finetune_params, param_name): + if finetune_params == "all": + return True + finetune_params_list = finetune_params.split(",") + for finetune_param in finetune_params_list: + if finetune_param in param_name: + return True + return False + + +def set_default_w2v_encoder_args(args): + args.no_pretrained_weights = getattr(args, "no_pretrained_weights", False) + args.dropout_input = getattr(args, "dropout_input", 0) + args.final_dropout = getattr(args, "final_dropout", 0) + args.apply_mask = getattr(args, "apply_mask", False) + args.dropout = getattr(args, "dropout", 0) + args.attention_dropout = getattr(args, "attention_dropout", 0) + args.activation_dropout = getattr(args, "activation_dropout", 0) + + args.mask_length = getattr(args, "mask_length", 10) + args.mask_prob = getattr(args, "mask_prob", 0.5) + args.mask_selection = getattr(args, "mask_selection", "static") + args.mask_other = getattr(args, "mask_other", 0) + args.no_mask_overlap = getattr(args, "no_mask_overlap", False) + args.mask_channel_length = getattr(args, "mask_channel_length", 10) + args.mask_channel_prob = getattr(args, "mask_channel_prob", 0.5) + args.mask_channel_before = getattr(args, "mask_channel_before", False) + args.mask_channel_selection = getattr(args, "mask_channel_selection", + "static") + args.mask_channel_other = getattr(args, "mask_channel_other", 0) + args.no_mask_channel_overlap = getattr(args, "no_mask_channel_overlap", + False) + + args.freeze_finetune_updates = getattr(args, "freeze_finetune_updates", 0) + args.feature_grad_mult = 0.1 + args.layerdrop = getattr(args, "layerdrop", 0.0) + + args.normalize = getattr(args, "normalize", False) + + +def set_default_adaptor_args(args): + args.adaptor_n_layers = getattr(args, "adaptor_n_layers", 3) + args.adaptor_kernel_size = getattr(args, "adaptor_kernel_size", 3) + args.adaptor_stride = getattr(args, "adaptor_stride", 2) + args.adaptor_layernorm = getattr(args, "adaptor_layernorm", False) + + +def set_default_mbart_decoder_args(args): + args.decoder_embed_path = getattr(args, 'decoder_embed_path', None) + args.decoder_embed_dim = getattr(args, 'decoder_embed_dim', 1024) + args.decoder_ffn_embed_dim = getattr(args, 'decoder_ffn_embed_dim', + 4 * 1024) + args.decoder_layers = getattr(args, 'decoder_layers', 12) + args.decoder_attention_heads = getattr(args, 'decoder_attention_heads', 16) + args.decoder_normalize_before = getattr(args, 'decoder_normalize_before', + True) + args.decoder_learned_pos = getattr(args, 'decoder_learned_pos', True) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + args.adaptive_input = getattr(args, "adaptive_input", False) + args.decoder_attention_dropout = getattr(args, 'decoder_attention_dropout', + 0.) + args.decoder_activation_dropout = getattr(args, + 'decoder_activation_dropout', 0.) + args.decoder_dropout = getattr(args, 'decoder_dropout', 0.1) + args.adaptive_softmax_cutoff = getattr(args, 'adaptive_softmax_cutoff', + None) + args.adaptive_softmax_dropout = getattr(args, 'adaptive_softmax_dropout', 0) + args.share_decoder_input_output_embed = getattr( + args, 'share_decoder_input_output_embed', True + ) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + + args.decoder_output_dim = getattr(args, 'decoder_output_dim', + args.decoder_embed_dim) + args.decoder_input_dim = getattr(args, 'decoder_input_dim', + args.decoder_embed_dim) + + args.no_scale_embedding = getattr(args, 'no_scale_embedding', False) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + args.layernorm_embedding = getattr(args, 'layernorm_embedding', True) + + args.activation_fn = getattr(args, 'activation_fn', 'gelu') + args.pooler_activation_fn = getattr(args, 'pooler_activation_fn', 'tanh') + args.pooler_dropout = getattr(args, 'pooler_dropout', 0.0) + args.checkpoint_activations = getattr(args, "checkpoint_activations", False) + + +@register_model_architecture(model_name="xm_transformer", + arch_name="xm_transformer") +def base_architecture(args): + set_default_w2v_encoder_args(args) + set_default_adaptor_args(args) + set_default_mbart_decoder_args(args) From 20fbc348215e558d23da9461a5daaec85b97d114 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <31931787+wnhsu@users.noreply.github.com> Date: Fri, 30 Jul 2021 10:15:09 -0700 Subject: [PATCH 430/774] update hubert decode config (#2106) Summary: Update HuBERT decode config yaml to make compatible with the new decoder config Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2106 Reviewed By: alexeib Differential Revision: D29967631 Pulled By: wnhsu fbshipit-source-id: fe39c5126f50c3024022f8333e2f3aa97065cbfc --- examples/hubert/config/decode/infer_fsqlm.yaml | 8 ++++---- examples/hubert/config/decode/infer_kenlm.yaml | 6 +++--- examples/hubert/config/decode/infer_viterbi.yaml | 8 +++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/examples/hubert/config/decode/infer_fsqlm.yaml b/examples/hubert/config/decode/infer_fsqlm.yaml index bc77cab32e..026ad8db89 100644 --- a/examples/hubert/config/decode/infer_fsqlm.yaml +++ b/examples/hubert/config/decode/infer_fsqlm.yaml @@ -5,14 +5,15 @@ defaults: hydra: run: - dir: ${common_eval.results_path}/beam${decoding.decoder.beam}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + dir: ${common_eval.results_path}/beam${decoding.beam}_th${decoding.beamthreshold}_lmw${decoding.lmweight}_wrd${decoding.wordscore}_sil${decoding.silweight} sweep: dir: ${common_eval.results_path} - subdir: beam${decoding.decoder.beam}_th${decoding.decoder.beamthreshold}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + subdir: beam${decoding.beam}_th${decoding.beamthreshold}_lmw${decoding.lmweight}_wrd${decoding.wordscore}_sil${decoding.silweight} task: _name: hubert_pretraining single_target: true + fine_tuning: true data: ??? normalize: ??? @@ -20,13 +21,12 @@ decoding: type: fairseqlm lexicon: ??? lmpath: ??? - beamthreshold: 25 # 100 + beamthreshold: 25 beam: 500 lmweight: 2 wordscore: -1 silweight: 0 unique_wer_file: true - beam: 500 common_eval: results_path: ??? path: ??? diff --git a/examples/hubert/config/decode/infer_kenlm.yaml b/examples/hubert/config/decode/infer_kenlm.yaml index 26f5c48928..04642aeb65 100644 --- a/examples/hubert/config/decode/infer_kenlm.yaml +++ b/examples/hubert/config/decode/infer_kenlm.yaml @@ -5,14 +5,15 @@ defaults: hydra: run: - dir: ${common_eval.results_path}/beam${decoding.decoder.beam}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + dir: ${common_eval.results_path}/beam${decoding.beam}_th${decoding.beamthreshold}_lmw${decoding.lmweight}_wrd${decoding.wordscore}_sil${decoding.silweight} sweep: dir: ${common_eval.results_path} - subdir: beam${decoding.decoder.beam}_th${decoding.decoder.beamthreshold}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + subdir: beam${decoding.beam}_th${decoding.beamthreshold}_lmw${decoding.lmweight}_wrd${decoding.wordscore}_sil${decoding.silweight} task: _name: hubert_pretraining single_target: true + fine_tuning: true data: ??? normalize: ??? @@ -26,7 +27,6 @@ decoding: wordscore: -1 silweight: 0 unique_wer_file: true - beam: 500 common_eval: results_path: ??? path: ??? diff --git a/examples/hubert/config/decode/infer_viterbi.yaml b/examples/hubert/config/decode/infer_viterbi.yaml index 935d7d1d01..4afc74c18c 100644 --- a/examples/hubert/config/decode/infer_viterbi.yaml +++ b/examples/hubert/config/decode/infer_viterbi.yaml @@ -5,14 +5,15 @@ defaults: hydra: run: - dir: ${common_eval.results_path}/beam${decoding.decoder.beam}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + dir: ${common_eval.results_path}/viterbi sweep: dir: ${common_eval.results_path} - subdir: beam${decoding.decoder.beam}_th${decoding.decoder.beamthreshold}_lmw${decoding.decoder.lmweight}_wrd${decoding.decoder.wordscore}_sil${decoding.decoder.silweight} + subdir: viterbi task: _name: hubert_pretraining single_target: true + fine_tuning: true data: ??? normalize: ??? @@ -23,9 +24,6 @@ common_eval: results_path: ??? path: ??? post_process: letter -generation: - nbest: 1 - beam: 500 dataset: max_tokens: 1100000 gen_subset: ??? From 972401937b9aa44e45ee3380fa497c8eb30005c4 Mon Sep 17 00:00:00 2001 From: Ann Lee <annl@fb.com> Date: Fri, 30 Jul 2021 14:33:53 -0700 Subject: [PATCH 431/774] add paper link (#2116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2116 Reviewed By: michaelauli Differential Revision: D30019908 Pulled By: an918tw fbshipit-source-id: ca8d7a6e97ed81e7df9a15e778c68fad8fb0a308 --- examples/discriminative_reranking_nmt/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/discriminative_reranking_nmt/README.md b/examples/discriminative_reranking_nmt/README.md index aba0090370..e6f42b1278 100644 --- a/examples/discriminative_reranking_nmt/README.md +++ b/examples/discriminative_reranking_nmt/README.md @@ -1,4 +1,6 @@ # Discriminative Reranking for Neural Machine Translation +https://aclanthology.org/2021.acl-long.563/ + This folder contains source code for training DrNMT, a discriminatively trained reranker for neural machine translation. ## Data preparation From 9d70f9ca6eb0dc49065a2691f302df2e68c1cac4 Mon Sep 17 00:00:00 2001 From: Ishani Karmarkar <ikarmarkar@fb.com> Date: Fri, 30 Jul 2021 17:41:47 -0700 Subject: [PATCH 432/774] iPQ Summary: Implemented iterative product quantization (iPQ trainer) and unit tests Reviewed By: AkshatSh, AdithyaSagar007 Differential Revision: D29662949 fbshipit-source-id: fdc1f124decc722b54225a7fe0031695823e1c69 --- fairseq/modules/quantization/pq/__init__.py | 2 +- fairseq/modules/quantization/pq/utils.py | 37 +++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/fairseq/modules/quantization/pq/__init__.py b/fairseq/modules/quantization/pq/__init__.py index 5b10b51b1b..c142a802e0 100644 --- a/fairseq/modules/quantization/pq/__init__.py +++ b/fairseq/modules/quantization/pq/__init__.py @@ -3,4 +3,4 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from .utils import SizeTracker, quantize_model_ # NOQA +from .utils import SizeTracker, get_param, attrsetter, quantize_model_ # NOQA diff --git a/fairseq/modules/quantization/pq/utils.py b/fairseq/modules/quantization/pq/utils.py index 3c5ea4155d..14c015b7c1 100644 --- a/fairseq/modules/quantization/pq/utils.py +++ b/fairseq/modules/quantization/pq/utils.py @@ -6,7 +6,7 @@ import logging import re from operator import attrgetter, itemgetter - +import torch import numpy as np import torch.distributed as dist import torch.nn as nn @@ -25,7 +25,9 @@ def quantize_model_( n_iter=15, eps=1e-6, max_tentatives=100, + remove_weights=False, verbose=True, + state_dict=None, ): """ Quantize a model in-place by stages. All the targeted @@ -58,7 +60,7 @@ def quantize_model_( to layers_to_quantize[step] """ - quantized_layers = get_layers(model, layers_to_quantize[step]) + quantized_layers = get_layers(model, layers_to_quantize[step], remove_weights=remove_weights) for layer in quantized_layers: @@ -96,6 +98,37 @@ def quantize_model_( centroids = quantizer.centroids.contiguous() assignments = quantizer.assignments.contiguous() + # If n_iter = 0 and state_dict is provided, then + # we initialize random assignments and centroids to + # random values of the appropriate dimensions + # because the quantized model parameters will + # overwritten by the state_dict later on. + if n_iter == 0 and state_dict: + # Initialize random centroids of the correct size + centroids = torch.rand(centroids.size()) + centroids.cuda() + # Get counts and assignment keys from layer in loaded checkpoint. + counts_key = layer+"."+"counts" + assignment_key = layer+"."+"assignments" + # Get number of different bins to include. + counts = list(state_dict[counts_key].shape)[0] + print(layer) + print(state_dict[counts_key]) + print(counts) + # Initialize random assignments of the correct size + # with an appropriate number of bins. + num_assignments = list(state_dict[assignment_key].shape)[0] + num_extra = num_assignments - counts + print(num_assignments) + print(num_extra) + assignments_bins = torch.arange(counts) + assignments_rand = torch.randint(0, counts-1, (num_extra, )) + assignments = torch.cat((assignments_bins, assignments_rand), 0) + # assignments = assignments.type(torch.IntTensor) + assignments.cuda() + print("assignments") + print(assignments) + # broadcast results to make sure weights are up-to-date if dist.is_initialized(): dist.broadcast(centroids, 0) From 82e8a24bddc1cb5aecb267bb529f76f5b3901432 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Mon, 2 Aug 2021 12:39:30 -0700 Subject: [PATCH 433/774] add max_keep_size (#2124) Summary: Set max_keep_size to filter long utterances. Needed when trained on labeled datasets with long utterances. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2124 Reviewed By: Abdel-rahmanMohamed Differential Revision: D30046509 Pulled By: wnhsu fbshipit-source-id: ec52ae0997284a05295dff35626927a71c78cf52 --- fairseq/tasks/hubert_pretraining.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/fairseq/tasks/hubert_pretraining.py b/fairseq/tasks/hubert_pretraining.py index ee3fedce3f..f756080dd1 100644 --- a/fairseq/tasks/hubert_pretraining.py +++ b/fairseq/tasks/hubert_pretraining.py @@ -76,6 +76,10 @@ class HubertPretrainingConfig(FairseqDataclass): default=False, metadata={"help": "pad shorter samples instead of cropping"}, ) + max_keep_size: Optional[int] = field( + default=None, + metadata={"help": "exclude sample longer than this"}, + ) max_sample_size: Optional[int] = field( default=None, metadata={"help": "max sample size to crop to for batching"}, @@ -123,13 +127,11 @@ def __init__( else: self.state.add_factory("dictionaries", self.load_dictionaries) - self._source_dictionary = None - self.blank_symbol = "<s>" @property def source_dictionary(self) -> Optional[Dictionary]: - return self._source_dictionary + return None @property def target_dictionary(self) -> Optional[Dictionary]: @@ -174,7 +176,7 @@ def load_dataset(self, split: str, **kwargs) -> None: pad_list=pad_list, eos_list=eos_list, label_processors=procs, - max_keep_sample_size=None, + max_keep_sample_size=self.cfg.max_keep_size, min_keep_sample_size=self.cfg.min_sample_size, max_sample_size=self.cfg.max_sample_size, pad_audio=self.cfg.pad_audio, From db4f96b09295ffae2e534adbc6eefcd9f2d2089f Mon Sep 17 00:00:00 2001 From: Jingfei Du <jingfeidu@fb.com> Date: Mon, 2 Aug 2021 14:35:22 -0700 Subject: [PATCH 434/774] fixing checkpoint config upgrade for generation print_alignment (#2125) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes config upgrade conditions for upgrading generation. print_alignment ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2125 Reviewed By: myleott Differential Revision: D30049140 Pulled By: jingfeidu fbshipit-source-id: e613821e94d0cdb876c35bc6e3fede7affbf4628 --- fairseq/checkpoint_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index daabba4574..b8c46f8253 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -653,7 +653,7 @@ def _upgrade_state_dict(state): ): cfg.task.eval_wer_config.print_alignment = "hard" if "generation" in cfg and isinstance(cfg.generation.print_alignment, bool): - cfg.generation.print_alignment = "hard" + cfg.generation.print_alignment = "hard" if cfg.generation.print_alignment else None if ( "model" in cfg and "w2v_args" in cfg.model From fe15926d48167c5028d2d7e2ed7d0a66642d0700 Mon Sep 17 00:00:00 2001 From: Edan Tessel Sneh <edan@fb.com> Date: Mon, 2 Aug 2021 18:39:08 -0700 Subject: [PATCH 435/774] Adding Hydra based trainer target to fairseq in fbcode Summary: Adding fairseq entrypoint section of e2e pipeline so FairseqConfig to hydra_main, runs smoothly Reviewed By: jieru-hu Differential Revision: D29714729 fbshipit-source-id: e3694e0037bb4c4f69208c1d6ec7df91d42fb588 --- fairseq/dataclass/initialize.py | 2 +- fairseq_cli/hydra_train.py | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index e43b31790e..8f6cbafb80 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -47,7 +47,7 @@ def add_defaults(cfg: DictConfig) -> None: field_cfg = DictConfig({"_name": field_cfg}) field_cfg.__dict__["_parent"] = field_cfg.__dict__["_parent"] - name = field_cfg.get("_name") + name = getattr(field_cfg, "_name", None) if k == "task": dc = TASK_DATACLASS_REGISTRY.get(name) diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index 9de01084ba..6555ab415e 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -11,6 +11,7 @@ from fairseq_cli.train import main as pre_main from fairseq import distributed_utils, metrics from fairseq.dataclass.configs import FairseqConfig +from fairseq.dataclass.utils import omegaconf_no_object_check from fairseq.utils import reset_logging import hydra @@ -24,25 +25,32 @@ @hydra.main(config_path=os.path.join("..", "fairseq", "config"), config_name="config") def hydra_main(cfg: FairseqConfig) -> float: + _hydra_main(cfg) + + +def _hydra_main(cfg: FairseqConfig, **kwargs) -> float: add_defaults(cfg) if cfg.common.reset_logging: reset_logging() # Hydra hijacks logging, fix that else: - with open_dict(cfg): - # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) - cfg.job_logging_cfg = OmegaConf.to_container(HydraConfig.get().job_logging, resolve=True) - - cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) + # check if directly called or called through hydra_main + if HydraConfig.initialized(): + with open_dict(cfg): + # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) + cfg.job_logging_cfg = OmegaConf.to_container(HydraConfig.get().job_logging, resolve=True) + + with omegaconf_no_object_check(): + cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) OmegaConf.set_struct(cfg, True) try: if cfg.common.profile: with torch.cuda.profiler.profile(): with torch.autograd.profiler.emit_nvtx(): - distributed_utils.call_main(cfg, pre_main) + distributed_utils.call_main(cfg, pre_main, **kwargs) else: - distributed_utils.call_main(cfg, pre_main) + distributed_utils.call_main(cfg, pre_main, **kwargs) except BaseException as e: if not cfg.common.suppress_crashes: raise From 3d90df4a1fd3e7734622f7bd6cfda5dd6b4d3aef Mon Sep 17 00:00:00 2001 From: Ishani Karmarkar <ikarmarkar@fb.com> Date: Mon, 2 Aug 2021 21:57:40 -0700 Subject: [PATCH 436/774] Quant Noise Summary: Implemented fix bit scalar quantization with quant noise for pytext models Reviewed By: AkshatSh Differential Revision: D29662977 fbshipit-source-id: ebab68a4a5ff1583a0c6dfadcf2671663e232c18 --- fairseq/modules/quantization/scalar/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fairseq/modules/quantization/scalar/utils.py b/fairseq/modules/quantization/scalar/utils.py index 76db40fec0..2ec6af3fcb 100644 --- a/fairseq/modules/quantization/scalar/utils.py +++ b/fairseq/modules/quantization/scalar/utils.py @@ -27,7 +27,6 @@ def quantize_model_(model, p=0.2, bits=8, update_step=3000, method="histogram", - bits: number of bits - update_step: update quantization parameters every update_step steps """ - # quantize all layers # remove weights indicates whether the weights extension should be removed, in addition to # weight_orig and weight extension on names From 9825786fbe8a32053f21bec988d953d175f7262a Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 4 Aug 2021 16:30:23 -0700 Subject: [PATCH 437/774] --fp16-adam-stats (#2139) Summary: - stores exp_avg and exp_sq_avg in fp16, with `scale` variables to avoid overflow. - myleott added this to gshard, following github.com/openai/jukebox/blob/master/jukebox/utils/fp16.py Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2139 Reviewed By: myleott Differential Revision: D30113175 Pulled By: sshleifer fbshipit-source-id: 03995c8eb096629675eadec4e7b8e7f18fc2730e --- fairseq/optim/adam.py | 13 ++++++++- fairseq/optim/cpu_adam.py | 4 +++ fairseq/optim/fp16_optimizer.py | 2 ++ fairseq/optim/fused_adam.py | 52 ++++++++++++++++++++++++++++----- 4 files changed, 62 insertions(+), 9 deletions(-) diff --git a/fairseq/optim/adam.py b/fairseq/optim/adam.py index 6a31e53a62..d3ae9e64a7 100644 --- a/fairseq/optim/adam.py +++ b/fairseq/optim/adam.py @@ -33,6 +33,9 @@ class FairseqAdamConfig(FairseqDataclass): use_old_adam: bool = field( default=False, metadata={"help": "Use fairseq.optim.adam.Adam"} ) + fp16_adam_stats: bool = field( + default=False, metadata={"help": "use FP16 stats (with automatic scaling)"} + ) # TODO common vars below in parent tpu: bool = II("common.tpu") lr: List[float] = II("optimization.lr") @@ -56,13 +59,21 @@ def __init__(self, cfg: FairseqAdamConfig, params): and torch.cuda.is_available() ) if getattr(cfg, "tpu", False): + if self.cfg.fp16_adam_stats: + raise NotImplementedError("--fp16-adam-stats is only supported on GPU") # on TPUs we use the Adam defined here, since it # automatically casts gradients to FP32 self._optimizer = Adam(params, **self.optimizer_config) elif use_fused_adam: logger.info("using FusedAdam") - self._optimizer = fused_adam_cls(params, **self.optimizer_config) + self._optimizer = fused_adam_cls( + params, + use_fp16_stats=self.cfg.fp16_adam_stats, + **self.optimizer_config + ) else: + if self.cfg.fp16_adam_stats: + raise NotImplementedError("--fp16-adam-stats is only supported with FusedAdamV1") self._optimizer = Adam(params, **self.optimizer_config) @property diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py index 211c376756..b2f893aeda 100644 --- a/fairseq/optim/cpu_adam.py +++ b/fairseq/optim/cpu_adam.py @@ -116,6 +116,10 @@ def __init__( self.opt_id, lr, betas[0], betas[1], eps, weight_decay, adamw_mode ) + @property + def supports_memory_efficient_fp16(self): + return True + @property def supports_flat_params(self): return True diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index b84236e685..c59b21cf6b 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -66,6 +66,8 @@ def build_fp32_params(cls, args, params, flatten=True): p32 = torch.nn.Parameter(p.data.float()) if hasattr(p, 'expert'): p32.expert = True + elif hasattr(p, 'base_expert'): + p32.base_expert = True p32.grad = torch.zeros_like(p32.data) if hasattr(p, "param_group"): p32.param_group = p.param_group diff --git a/fairseq/optim/fused_adam.py b/fairseq/optim/fused_adam.py index e2b8e1bcd1..7a6d1f73d5 100644 --- a/fairseq/optim/fused_adam.py +++ b/fairseq/optim/fused_adam.py @@ -80,6 +80,7 @@ def __init__( weight_decay=0.0, max_grad_norm=0.0, amsgrad=False, + use_fp16_stats=False, ): global fused_adam_cuda import importlib @@ -99,6 +100,9 @@ def __init__( super().__init__(params, defaults) self.eps_mode = 0 if eps_inside_sqrt else 1 + self.use_fp16_stats = use_fp16_stats + self.FLOAT16_MAX = 65504.0 + @property def supports_memory_efficient_fp16(self): return True @@ -173,29 +177,42 @@ def step(self, closure=None, grads=None, scale=1.0, grad_norms=None): "please consider SparseAdam instead" ) - p_data_fp32 = p.data.float() + if p.device.type == "cpu": + p_data_fp32 = p.data.cuda(non_blocking=True).float() + out_p = torch.tensor([], dtype = torch.float) + else: + p_data_fp32 = p.data.float() + out_p = p.data state = self.state[p] # State initialization + dtype = torch.float16 if self.use_fp16_stats else p_data_fp32.dtype if len(state) == 0: state["step"] = 0 # Exponential moving average of gradient values - state["exp_avg"] = torch.zeros_like(p_data_fp32) + state["exp_avg"] = torch.zeros_like(p_data_fp32, dtype=dtype) # Exponential moving average of squared gradient values - state["exp_avg_sq"] = torch.zeros_like(p_data_fp32) + state["exp_avg_sq"] = torch.zeros_like(p_data_fp32, dtype=dtype) + if self.use_fp16_stats: + state["exp_avg_scale"] = 1.0 + state["exp_avg_sq_scale"] = 1.0 else: - state["exp_avg"] = state["exp_avg"].to(p_data_fp32) - state["exp_avg_sq"] = state["exp_avg_sq"].to(p_data_fp32) + device = p_data_fp32.device + state["exp_avg"] = state["exp_avg"].to(device, dtype) + state["exp_avg_sq"] = state["exp_avg_sq"].to(device, dtype) exp_avg = state["exp_avg"] exp_avg_sq = state["exp_avg_sq"] + if self.use_fp16_stats: + assert exp_avg.dtype == torch.float16 + exp_avg = exp_avg.float() * state["exp_avg_scale"] + exp_avg_sq = exp_avg_sq.float() * state["exp_avg_sq_scale"] beta1, beta2 = group["betas"] state["step"] += 1 - out_p = p.data - with torch.cuda.device(p.device): + with torch.cuda.device(p_data_fp32.device): fused_adam_cuda.adam( p_data_fp32, out_p, @@ -213,6 +230,23 @@ def step(self, closure=None, grads=None, scale=1.0, grad_norms=None): group["weight_decay"], ) + if p.device.type == "cpu": + p.data.copy_(p_data_fp32, non_blocking=True) + + if self.use_fp16_stats: + def inf_norm(t): + return torch.norm(t, float("inf")) + + # from github.com/openai/jukebox/blob/master/jukebox/utils/fp16.py + state["exp_avg_scale"], state["exp_avg_sq_scale"] = ( + 1e-8 + inf_norm(exp_avg) / self.FLOAT16_MAX, + 1e-8 + inf_norm(exp_avg_sq) / self.FLOAT16_MAX, + ) + state["exp_avg"], state["exp_avg_sq"] = ( + (exp_avg / state["exp_avg_scale"]).half(), + (exp_avg_sq / state["exp_avg_sq_scale"]).half(), + ) + return loss @@ -226,7 +260,9 @@ class FusedAdamV2(FusedAdam): and params to FP32 internally to support ``--memory-efficient-fp16``. """ - def __init__(self, *args, **kwargs): + def __init__(self, *args, use_fp16_stats=False, **kwargs): + if use_fp16_stats: + raise NotImplementedError("--fp16-adam-stats is only supported with FusedAdamV1") super().__init__(*args, **kwargs) if not hasattr(self, "multi_tensor_adam"): raise Exception( From 741fd138c69eebc1fac09b590047da85cdeafe2d Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushall@fb.com> Date: Wed, 11 Aug 2021 16:07:06 -0700 Subject: [PATCH 438/774] Commit README for GSLM (#2151) Summary: ## What does this PR do? Adds GSLM directory with README. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2151 Reviewed By: wnhsu Differential Revision: D30147672 Pulled By: hikushalhere fbshipit-source-id: bcc7cbbde3626ea3d91917707a91aff85d715baa --- examples/textless_nlp/gslm/README.md | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 examples/textless_nlp/gslm/README.md diff --git a/examples/textless_nlp/gslm/README.md b/examples/textless_nlp/gslm/README.md new file mode 100644 index 0000000000..7fdb337335 --- /dev/null +++ b/examples/textless_nlp/gslm/README.md @@ -0,0 +1,49 @@ +# Generative Spoken Language Modeling + +## Speech to Unit Model (S2U) +### Acoustic Model +For quantizing speech we learn a K-means clustering over acoustic representations for which we either use Log-Mel Filterbank or pretrained acoustic representation models. For using pretrained models, please download from their respective locations linked below. +* [HuBERT-Base](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) +* [Wav2Vec 2.0-Base](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small.pt) +* [CPC](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc_big_ll6kh_top_ctc.pt) + +### Quantization +For quantizing speech with a given acoustic representation, please follow the steps below. +1. Learn K-means clustering model +``` +N_CLUSTERS=<num_cluster> +TYPE=<logmel/hubert/w2v2/cpc> +CKPT_PATH=<path_of_pretrained_acoustic_model> +LAYER=<layer_of_acoustic_model_to_extract_features_from> +MANIFEST=<path_manifest_of_input_audio_files_to_train_with> +KM_MODEL_PATH=<path_of_trained_kmeans_model> + +PYTHONPATH=. python examples/textless_nlp/gslm/u2s/clustering/cluster_kmeans.py \ + --num_clusters $N_CLUSTERS \ + --feature_type $TYPE \ + --checkpoint_path $CKPT_PATH \ + --layer $LAYER \ + --manifest_path $MANIFEST \ + --out_kmeans_model_path $KM_MODEL_PATH +``` +2. Quantize using the learned clusters +``` +MANIFEST=<path_manifest_of_input_audio_files_to_quantize> +OUT_QUANT_FILE=<path_quzntized_audio_file> + +python examples/textless_nlp/gslm/u2s/clustering/del/quantize_with_kmeans.py \ + --feature_type $TYPE \ + --kmeans_model_path $KM_MODEL_PATH \ + --checkpoint_path $CKPT_PATH \ + --layer $LAYER \ + --manifest_path $MANIFEST \ + --out_quantized_file_path $OUT_QUANT_FILE \ + --extension .flac +``` + +## Unit Language Model (ULM) +Unit Language Model is a generative LM trained on quantized speech. We use it to generate novel quantized spoken language with and without prompt. + +## Unit to Speech Model (U2S) +Unit to speech model is modified Tacotron2 model that learns to syntehsize speech from discrete speech units. We use to synthesize quantized spoken language. + From 2513524a1604dbafcc4ea9cc5a99ae0aa4f19694 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Tue, 17 Aug 2021 06:55:26 -0700 Subject: [PATCH 439/774] add finetuned robust w2v models and update readme (#2196) Summary: adds finetuned robust w2v models and updates readme fixes #3721 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2196 Reviewed By: wnhsu Differential Revision: D30367999 Pulled By: alexeib fbshipit-source-id: 616b373bf31265c89f694fba7dccce2961d394f3 --- README.md | 2 ++ examples/wav2vec/README.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 460f3439fb..cd9654cf31 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ We provide reference implementations of various sequence modeling papers: + [Deep Transformers with Latent Depth (Li et al., 2020)](examples/latent_depth/README.md) + [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979) + [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027) + + [Unsupervised Speech Recognition (Baevski, et al., 2021)](https://arxiv.org/abs/2105.11084) * **Non-autoregressive Transformers** + Non-Autoregressive Neural Machine Translation (Gu et al., 2017) + Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement (Lee et al. 2018) @@ -66,6 +67,7 @@ We provide reference implementations of various sequence modeling papers: * July 2021 [Released DrNMT code](examples/discriminative_reranking_nmt/README.md) * July 2021 [Released Robust wav2vec 2.0 model](examples/wav2vec/README.md) * June 2021 [Released XLMR-XL and XLMR-XXL models](examples/xlmr/README.md) +* May 2021 [Released Unsupervised Speech Recognition code](examples/wav2vec/unsupervised/README.md) * March 2021 [Added full parameter and optimizer state sharding + CPU offloading](examples/fully_sharded_data_parallel/README.md) * February 2021 [Added LASER training code](examples/laser/README.md) * December 2020: [Added Adaptive Attention Span code](examples/adaptive_span/README.md) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 2d6717dc04..253c8af251 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -28,6 +28,8 @@ Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https:/ Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv.pt) +Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | 960 hours Librispeech | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv_ftls960.pt) +Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | 300 hours Switchboard | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv_ftsb300.pt) \* updated (Oct. 24, 2020)\ ** updated (Jul. 8, 2021) From cb747010c47a017e71285556afa9acce0ec62786 Mon Sep 17 00:00:00 2001 From: Vaibhav Singh <sivaibhav@google.com> Date: Tue, 17 Aug 2021 07:02:41 -0700 Subject: [PATCH 440/774] Set batch size to 4 to prevent OOM due dynamic batch sizing (#3781) Summary: ## What does this PR do? Fixes OOM which happens from TPUs due to dynamic batching exceed the max a single core can work with. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3781 Reviewed By: wnhsu Differential Revision: D30327091 Pulled By: alexeib fbshipit-source-id: 0ebe6b18329fa05d359083fa8ac54aba7b48bc53 --- examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml index bee41157a9..3192ce4cba 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_large_librivox.yaml @@ -18,6 +18,7 @@ task: normalize: true dataset: + batch_size: 4 num_workers: 6 max_tokens: 1200000 skip_invalid_size_inputs_valid_test: true From 1f7ef9ed1e1061f8c7f88f8b94c7186834398690 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Thu, 19 Aug 2021 12:49:06 -0700 Subject: [PATCH 441/774] (fix #2177) Erase the encoder_embed_dim default (#2213) Summary: Fix https://github.com/fairinternal/fairseq-py/issues/2177 for the transformer conversion to Hydra. The way the defaults are dealt with now is different so when you use the legacy Namespace configuration, you end up with a default encoder_embed_dim, which in the VGG case sets up a encoder attention in the TransformerDecoderLayer with the wrong dimentions. The easiest solution is to erase the default value for encoder_embed_dim (by forcing it to None) when converting the VGG config to the raw Namespace for the decoder layer. Tested with: `pytest tests/speech_recognition/test_vggtransformer.py -k Transformer` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2213 Test Plan: pytest tests/speech_recognition/test_vggtransformer.py -k Transformer Reviewed By: sshleifer Differential Revision: D30425143 Pulled By: Mortimerp9 fbshipit-source-id: 92f6dea2ffbb68e441700bcc55274b3167a587b3 --- examples/speech_recognition/models/vggtransformer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/speech_recognition/models/vggtransformer.py b/examples/speech_recognition/models/vggtransformer.py index 97974360a4..bca0ae59a8 100644 --- a/examples/speech_recognition/models/vggtransformer.py +++ b/examples/speech_recognition/models/vggtransformer.py @@ -203,6 +203,7 @@ def prepare_transformer_decoder_params( relu_dropout, ): args = argparse.Namespace() + args.encoder_embed_dim = None args.decoder_embed_dim = input_dim args.decoder_attention_heads = num_heads args.attention_dropout = attention_dropout From 6f847c8654d56b4d1b1fbacec027f47419426ddb Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushall@fb.com> Date: Thu, 26 Aug 2021 05:46:38 -0700 Subject: [PATCH 442/774] Release GSLM (#2201) Summary: ## What does this PR do? Open sourcing code for Generative Spoken Language Modeling Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2201 Reviewed By: wnhsu, eugene-kharitonov Differential Revision: D30563114 Pulled By: hikushalhere fbshipit-source-id: 6c1ee3b29038fd2c9fb5939bddcc70af0794dab4 --- examples/textless_nlp/gslm/README.md | 54 +- examples/textless_nlp/gslm/metrics/README.md | 10 + .../gslm/metrics/abx_metrics/README.md | 77 ++ .../metrics/abx_metrics/dump_abx_feats.py | 107 +++ .../gslm/metrics/asr_metrics/README.md | 87 +++ .../metrics/asr_metrics/continuation_eval.py | 99 +++ .../metrics/asr_metrics/misc/bleu_utils.py | 166 +++++ .../gslm/metrics/asr_metrics/misc/cut_as.py | 69 ++ .../metrics/asr_metrics/misc/dict.ltr.txt | 28 + .../gslm/metrics/asr_metrics/ppx.py | 122 ++++ .../metrics/asr_metrics/self_auto_bleu.py | 201 ++++++ .../textless_nlp/gslm/speech2unit/README.md | 71 ++ .../textless_nlp/gslm/speech2unit/__init__.py | 0 .../gslm/speech2unit/clustering/__init__.py | 0 .../speech2unit/clustering/cluster_kmeans.py | 212 ++++++ .../gslm/speech2unit/clustering/dump_feats.py | 91 +++ .../clustering/quantize_with_kmeans.py | 125 ++++ .../gslm/speech2unit/clustering/utils.py | 20 + .../pretrained/cpc_feature_reader.py | 192 +++++ .../pretrained/hubert_feature_reader.py | 59 ++ .../pretrained/logmel_feature_reader.py | 30 + .../gslm/speech2unit/pretrained/utils.py | 126 ++++ .../pretrained/w2v2_feature_reader.py | 46 ++ examples/textless_nlp/gslm/tools/README.md | 22 + .../gslm/tools/resynthesize_speech.py | 138 ++++ examples/textless_nlp/gslm/ulm/README.md | 72 ++ examples/textless_nlp/gslm/ulm/sample.py | 174 +++++ .../textless_nlp/gslm/unit2speech/README.md | 42 ++ .../gslm/unit2speech/convert_to_16k.py | 56 ++ .../textless_nlp/gslm/unit2speech/glow.py | 311 ++++++++ .../gslm/unit2speech/multiproc.py | 27 + .../synthesize_audio_from_units.py | 97 +++ .../gslm/unit2speech/tacotron2/__init__.py | 0 .../unit2speech/tacotron2/audio_processing.py | 93 +++ .../gslm/unit2speech/tacotron2/cleaners.py | 90 +++ .../gslm/unit2speech/tacotron2/cmudict.py | 65 ++ .../gslm/unit2speech/tacotron2/layers.py | 103 +++ .../gslm/unit2speech/tacotron2/model.py | 669 ++++++++++++++++++ .../gslm/unit2speech/tacotron2/numbers.py | 71 ++ .../gslm/unit2speech/tacotron2/stft.py | 141 ++++ .../gslm/unit2speech/tacotron2/symbols.py | 18 + .../gslm/unit2speech/tacotron2/text.py | 107 +++ .../gslm/unit2speech/tacotron2/utils.py | 167 +++++ .../tacotron2/waveglow_denoiser.py | 40 ++ .../textless_nlp/gslm/unit2speech/tts_data.py | 52 ++ .../textless_nlp/gslm/unit2speech/utils.py | 55 ++ fairseq/tasks/audio_pretraining.py | 3 +- 47 files changed, 4563 insertions(+), 42 deletions(-) create mode 100644 examples/textless_nlp/gslm/metrics/README.md create mode 100644 examples/textless_nlp/gslm/metrics/abx_metrics/README.md create mode 100644 examples/textless_nlp/gslm/metrics/abx_metrics/dump_abx_feats.py create mode 100644 examples/textless_nlp/gslm/metrics/asr_metrics/README.md create mode 100644 examples/textless_nlp/gslm/metrics/asr_metrics/continuation_eval.py create mode 100644 examples/textless_nlp/gslm/metrics/asr_metrics/misc/bleu_utils.py create mode 100644 examples/textless_nlp/gslm/metrics/asr_metrics/misc/cut_as.py create mode 100644 examples/textless_nlp/gslm/metrics/asr_metrics/misc/dict.ltr.txt create mode 100644 examples/textless_nlp/gslm/metrics/asr_metrics/ppx.py create mode 100644 examples/textless_nlp/gslm/metrics/asr_metrics/self_auto_bleu.py create mode 100644 examples/textless_nlp/gslm/speech2unit/README.md create mode 100644 examples/textless_nlp/gslm/speech2unit/__init__.py create mode 100644 examples/textless_nlp/gslm/speech2unit/clustering/__init__.py create mode 100644 examples/textless_nlp/gslm/speech2unit/clustering/cluster_kmeans.py create mode 100644 examples/textless_nlp/gslm/speech2unit/clustering/dump_feats.py create mode 100644 examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py create mode 100644 examples/textless_nlp/gslm/speech2unit/clustering/utils.py create mode 100644 examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py create mode 100644 examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py create mode 100644 examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py create mode 100644 examples/textless_nlp/gslm/speech2unit/pretrained/utils.py create mode 100644 examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py create mode 100644 examples/textless_nlp/gslm/tools/README.md create mode 100644 examples/textless_nlp/gslm/tools/resynthesize_speech.py create mode 100644 examples/textless_nlp/gslm/ulm/README.md create mode 100644 examples/textless_nlp/gslm/ulm/sample.py create mode 100644 examples/textless_nlp/gslm/unit2speech/README.md create mode 100644 examples/textless_nlp/gslm/unit2speech/convert_to_16k.py create mode 100644 examples/textless_nlp/gslm/unit2speech/glow.py create mode 100644 examples/textless_nlp/gslm/unit2speech/multiproc.py create mode 100644 examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/__init__.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/audio_processing.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/cleaners.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/cmudict.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/layers.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/model.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/numbers.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/stft.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/symbols.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/text.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tacotron2/waveglow_denoiser.py create mode 100644 examples/textless_nlp/gslm/unit2speech/tts_data.py create mode 100644 examples/textless_nlp/gslm/unit2speech/utils.py diff --git a/examples/textless_nlp/gslm/README.md b/examples/textless_nlp/gslm/README.md index 7fdb337335..79de55d96e 100644 --- a/examples/textless_nlp/gslm/README.md +++ b/examples/textless_nlp/gslm/README.md @@ -1,49 +1,21 @@ # Generative Spoken Language Modeling -## Speech to Unit Model (S2U) -### Acoustic Model -For quantizing speech we learn a K-means clustering over acoustic representations for which we either use Log-Mel Filterbank or pretrained acoustic representation models. For using pretrained models, please download from their respective locations linked below. -* [HuBERT-Base](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) -* [Wav2Vec 2.0-Base](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_small.pt) -* [CPC](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc_big_ll6kh_top_ctc.pt) +* [Paper](https://arxiv.org/abs/2102.01192) +* [Demo](https://speechbot.github.io/gslm/index.html) -### Quantization -For quantizing speech with a given acoustic representation, please follow the steps below. -1. Learn K-means clustering model -``` -N_CLUSTERS=<num_cluster> -TYPE=<logmel/hubert/w2v2/cpc> -CKPT_PATH=<path_of_pretrained_acoustic_model> -LAYER=<layer_of_acoustic_model_to_extract_features_from> -MANIFEST=<path_manifest_of_input_audio_files_to_train_with> -KM_MODEL_PATH=<path_of_trained_kmeans_model> +We build and evaluate generative speech2speech systems using [Log Mel Filtebank](https://pytorch.org/audio/stable/compliance.kaldi.html#fbank), [Modified CPC](https://github.com/facebookresearch/CPC_audio), [HuBERT Base](https://github.com/pytorch/fairseq/tree/master/examples/hubert) and [Wav2Vec 2.0 Large](https://github.com/pytorch/fairseq/tree/master/examples/wav2vec). Our system is composed of three components, namely, *speech2unit*, *ulm* and *unit2speech*. We explain about models and usage of these components in their respective sub-directories. See the links below. -PYTHONPATH=. python examples/textless_nlp/gslm/u2s/clustering/cluster_kmeans.py \ - --num_clusters $N_CLUSTERS \ - --feature_type $TYPE \ - --checkpoint_path $CKPT_PATH \ - --layer $LAYER \ - --manifest_path $MANIFEST \ - --out_kmeans_model_path $KM_MODEL_PATH -``` -2. Quantize using the learned clusters -``` -MANIFEST=<path_manifest_of_input_audio_files_to_quantize> -OUT_QUANT_FILE=<path_quzntized_audio_file> +## Speech to Unit Model (speech2unit) +Speech to unit model is used for quantizing raw speech into learned discrete speech units. [More details](speech2unit) -python examples/textless_nlp/gslm/u2s/clustering/del/quantize_with_kmeans.py \ - --feature_type $TYPE \ - --kmeans_model_path $KM_MODEL_PATH \ - --checkpoint_path $CKPT_PATH \ - --layer $LAYER \ - --manifest_path $MANIFEST \ - --out_quantized_file_path $OUT_QUANT_FILE \ - --extension .flac -``` +## Unit Language Model (ulm) +Unit Language Model is a generative language model trained on discrete speech units. [More details](ulm) -## Unit Language Model (ULM) -Unit Language Model is a generative LM trained on quantized speech. We use it to generate novel quantized spoken language with and without prompt. +## Unit to Speech Model (unit2speech) +Unit to speech model is used for synthesizing speech from discrete speech units. [More details](unit2speech) -## Unit to Speech Model (U2S) -Unit to speech model is modified Tacotron2 model that learns to syntehsize speech from discrete speech units. We use to synthesize quantized spoken language. +## Metrics +We show how to compute ASR based metrics as well as zero-shot metrics proposed in our paper [here](metrics). +## Tools +We share two tools to resynthesize a given spoken utterance, and generate novel spoken language given a spoken prompt. [More detail](tools) \ No newline at end of file diff --git a/examples/textless_nlp/gslm/metrics/README.md b/examples/textless_nlp/gslm/metrics/README.md new file mode 100644 index 0000000000..0a63e2f0d8 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/README.md @@ -0,0 +1,10 @@ +# GSLM Metrics + +## ASR Metrics +The suite of metrics here uses an ASR model to transcribe the synthesized speech into text, and then uses text-based metrics. We also use word error rate from ASR transcription itself as one of the metrics. [More details](asr_metrics) + +## ABX Metrics +We use [ABX](https://www.semanticscholar.org/paper/ABX-Discriminability-Measures-and-Applications-Schatz/13d3537228f728c1063cc83743cb118bba3367a0) to evaluate how well-separated phonetic categories are with quantized representations. [More details](abx_metrics) + +## sWUGGY and sBLIMP +We refer to [ZeroSpeech challenge](https://www.zerospeech.com/2021/track_s.html#scoring-based-metrics) for details on the sWUGGY and sBLIMP metrics. diff --git a/examples/textless_nlp/gslm/metrics/abx_metrics/README.md b/examples/textless_nlp/gslm/metrics/abx_metrics/README.md new file mode 100644 index 0000000000..aa2560f045 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/abx_metrics/README.md @@ -0,0 +1,77 @@ +# ABX-based evaluation + +ABX is used to evaluate the quality of the obtained discrete units. + +The life cycle of the ABX-based evaluation for the Speech-to-Unit contains the following steps: +1. Training an acoustic model (or use an existing acoustic model) ([description](./../..)) +2. Perform quantization of speech by learning a K-means clustering model ([description](./../..)) +3. Compute discrete features for ABX computation using the learned clusters +4. Compute the ABX score over the discrete features taking advantage of [libri-light's ABX evaluation script][ll-abx] + +Here we assume that you already went throught the first two steps and focus solely on extracting features and computing ABX scores. + +## Libri-light setup + +Follow [libri-light's instructions][ll-instructions] for installation and [ABX evaluation setup][ll-abx] (including the download of the data items required for ABX computation). + +## Computing ABX + +### Dumping quantized features + +The first step for the ABX computation is to dump the quantized representations corresponding to the test files. + +```shell +TYPE="hubert" +LAYER=6 +CKPT_PATH="<PATH_TO_HUBERT_MODEL_CHECKPOINT_FILE>" +KM_MODEL_PATH="<PATH_TO_PRETRAINED_KM_MODEL_FILE>" + +SUBSET="dev-clean" +MANIFEST="<PATH_TO_MANIFEST_FOR_LS_DEV-CLEAN>" +DATA_DIR="<PATH_TO_DIR_TO_STORE_FEATURES>/$SUBSET" + +PYTHONPATH=. python examples/textless_nlp/gslm/metrics/abx_metrics/dump_abx_feats.py \ + --feature_type $TYPE \ + --kmeans_model_path $KM_MODEL_PATH \ + --checkpoint_path $CKPT_PATH \ + --layer $LAYER \ + --manifest_path $MANIFEST \ + --out_dir_path $DATA_DIR \ + --extension ".flac" +``` + +Again the manifest file follows the same structure than elsewhere in the codebase. + +### Compute ABX with Libri-light + +Use libri-light's `eval_ABX.py` script (within the appropriate environment set up) as followed: + +```shell +LIBRILIGHT_ROOT="<PATH_TO_LIBRILIGHT>" + +SUBSET="dev-clean" +DATA_DIR="<PATH_TO_DIR_TO_STORE_FEATURES>/$SUBSET" +ITEM_FILE_PATH="$LIBRILIGHT_ROOT/eval/ABX_data/$SUBSET.item" +OUT_DIR="<PATH_TO_DIR_TO_STORE_ABX_SCORES>/$SUBSET" + +FILE_EXTENSION=".npy" +FEATURE_SIZE=0.02 # depends on the model used + +PYTHONPATH=$LIBRILIGHT_ROOT \ + python $LIBRILIGHT_ROOT/eval/eval_ABX.py \ + $DATA_DIR \ + $ITEM_FILE_PATH \ + --file_extension $FILE_EXTENSION \ + --feature_size $FEATURE_SIZE \ + --out $OUT_DIR \ + --mode "all" +``` + +Note that `FEATURE_SIZE` will depend on the model type you are using to extract the acoustic features: +* For HuBERT and Wav2Vec2.0, use `FEATURE_SIZE=0.02` +* For CPC and Log Mel, use `FEATURE_SIZE=0.01` + +If you have a gpu available, make sure you add the `--cuda` flag for faster computation. + +[ll-instructions]: https://github.com/facebookresearch/libri-light +[ll-abx]: https://github.com/facebookresearch/libri-light/tree/master/eval#abx diff --git a/examples/textless_nlp/gslm/metrics/abx_metrics/dump_abx_feats.py b/examples/textless_nlp/gslm/metrics/abx_metrics/dump_abx_feats.py new file mode 100644 index 0000000000..41cf558970 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/abx_metrics/dump_abx_feats.py @@ -0,0 +1,107 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import os + +import joblib +import numpy as np + +from examples.textless_nlp.gslm.speech2unit.clustering.utils import get_audio_files +from examples.textless_nlp.gslm.speech2unit.pretrained.utils import get_features + +def get_logger(): + log_format = "[%(asctime)s] [%(levelname)s]: %(message)s" + logging.basicConfig(format=log_format, level=logging.INFO) + logger = logging.getLogger(__name__) + return logger + +def get_parser(): + parser = argparse.ArgumentParser( + description="Quantize using K-means clustering over acoustic features." + ) + parser.add_argument( + "--feature_type", + type=str, + choices=["logmel", "hubert", "w2v2", "cpc"], + default=None, + required=True, + help="Acoustic feature type", + ) + parser.add_argument( + "--kmeans_model_path", + type=str, + required=True, + help="K-means model file path to use for inference", + ) + parser.add_argument( + "--manifest_path", + type=str, + default=None, + help="Manifest file containing the root dir and file names", + ) + parser.add_argument( + "--checkpoint_path", + type=str, + help="Pretrained model checkpoint", + ) + parser.add_argument( + "--layer", + type=int, + help="The layer of the pretrained model to extract features from", + default=-1, + ) + parser.add_argument( + "--out_dir_path", + required=True, + type=str, + help="File path of quantized output.", + ) + parser.add_argument( + "--extension", type=str, default=".flac", help="Features file path" + ) + return parser + + +def one_hot(feat, n_clusters): + return np.eye(n_clusters)[feat] + +def main(args, logger): + # Feature extraction + logger.info(f"Extracting {args.feature_type} acoustic features...") + features_batch = get_features( + feature_type=args.feature_type, + checkpoint_path=args.checkpoint_path, + layer=args.layer, + manifest_path=args.manifest_path, + sample_pct=1.0, + flatten=False, + ) + logger.info(f"Features extracted for {len(features_batch)} utterances.\n") + logger.info(f"Dimensionality of representation = {features_batch[0].shape[1]}") + + logger.info(f"Loading K-means model from {args.kmeans_model_path} ...") + kmeans_model = joblib.load(open(args.kmeans_model_path, "rb")) + kmeans_model.verbose = False + + _, fnames, _ = get_audio_files(args.manifest_path) + + os.makedirs(args.out_dir_path, exist_ok=True) + logger.info(f"Writing quantized features to {args.out_dir_path}") + for i, feats in enumerate(features_batch): + pred = kmeans_model.predict(feats) + emb = one_hot(pred, kmeans_model.n_clusters) + base_fname = os.path.basename(fnames[i]).rstrip(args.extension) + output_path = os.path.join(args.out_dir_path, f"{base_fname}.npy") + with open(output_path, "wb") as f: + np.save(f, emb) + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + logger = get_logger() + logger.info(args) + main(args, logger) diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/README.md b/examples/textless_nlp/gslm/metrics/asr_metrics/README.md new file mode 100644 index 0000000000..d05bc73d0d --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/README.md @@ -0,0 +1,87 @@ +# ASR-based evaluation + +Overall, the life cycle of the ASR-based evaluation for an ULM contains the following steps: + 1. Training an ULM and sampling from it [[description]](./../../ulm) + 2. Running UTS on the sampled unit sequences [[description]](./../../unit2speech) + 3. Pre-processing for the ASR (down-sampling to 16 KHz, aligning length of the generated audio with ground-truth utterances) + 4. Running ASR + 5. Calculation of the post-ASR evaluation metrics + +Here we assume that you have already went throught the first two steps and focus on the rest. + +## Preprocessing +### Down-sampling to 16KHz +The bulk conversion can be done by running +```bash + python $FAIRSEQ_ROOT/examples/textless_nlp/gslm/unit2speech/convert_to_16k.py $UTS_OUTPUT $UTS_OUTPUT_DOWNSAMPLE + ``` + where `$UTS_OUTPUT` specifies the directory with the generated audio and `$UTS_OUTPUT_DOWNSAMPLE` is the directory where downsampled audio would be saved. + + ### Matching by length +This step is somewhat optional. However, if you want to compare the fluency and diversity of a generated speech utterance to that of the ground-truth speech with the same prefix, it is a good idea to force them to be of the same length. +```bash +python $FAIRSEQ_ROOT/examples/textless_nlp/asr_metrics/cut_as.py \ + --samples_dir=$UTS_OUTPUT_DOWNSAMPLE --out_dir=$UTS_OUTPUT_DOWNSAMPLE_CUT \ + --prompts_description=data/ground_truth_continuation_dev.json +``` + +Here `ground_truth_continuation_dev.json` is a json file with ground-truth text from LibriSpeech dev-clean, associated with some meta-data (assuming the evaluation is done on dev-clean). This file can be downloaded [[here]](https://dl.fbaipublicfiles.com/textless_nlp/gslm/eval_data/ground_truth_continuation_dev.json). A similar file for the test-clean is [[here]](https://dl.fbaipublicfiles.com/textless_nlp/gslm/eval_data/ground_truth_continuation_test.json). These files are used for the evaluation and contain texts for audio sequences that are at least 6s long. + +## Running ASR +We use a pre-trained wav2vec model to run the ASR step. We firstly need to prepare manifest files which, roughly, tell the ASR system which files we want to transcribe. You can find more details and download the `960h_scratch.pt` checkpoint +[[here]](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec/README.md)). To run ASR, you would also need to +install KenLM, Flashlight decoder, and download the KenLM 4-gram English language model. + +```bash + python $FAIRSEQ_ROOT/examples/wav2vec/wav2vec_manifest.py \ + $UTS_OUTPUT_DOWNSAMPLE_CUT --valid-percent 0.0 --dest $MANIFEST_DIR --ext wav +``` +where `$UTS_OUTPUT_DOWNSAMPLE_CUT` speficies the directory with the preprocessed UTS outputs and `$MANIFEST_DIR` is the output directory. + +We will be running an out-of-the-box evaluation script which requires ground-truth transcripts to measure quality metrics. We are only +interested in the transcripts (and we don't have ground-truth outputs for when our ULM generated!), hence we will just generate +some dummy transcripts instead: +```bash +cp $FAIRSEQ_ROOT/examples/textless_nlp/gslm/asr_metrics/misc/dict.ltr.txt $MANIFEST_DIR +python $FAIRSEQ_ROOT/examples/textless_nlp/gslm/asr_metrics/misc/dummy_asr_data.py --tsv=$MANIFEST_DIR/train.tsv \ + --output-dir=$MANIFEST_DIR +``` + +Now we are ready for running ASR: +``` +mkdir -p asr +python $FAIRSEQ_ROOT/examples/speech_recognition/infer.py \ + $MANIFEST_DIR \ + --task audio_pretraining --nbest 1 --path 960h_scratch.pt \ + --gen-subset=train --results-path $PATH_TO_ASR_OUTPUT \ + --w2l-decoder kenlm --lm-model 4-gram.bin \ + --lexicon librispeech/lexicon_ltr.lst --word-score -1 \ + --sil-weight 0 --lm-weight 2 --criterion ctc --labels ltr --max-tokens 300000 --remove-bpe letter +``` +where `lexicon_ltr.lst` is the LibriSpeech lexicon and `$PATH_TO_ASR_OUTPUT` is the output directory (can be downloaded [[here]](https://dl.fbaipublicfiles.com/textless_nlp/gslm/eval_data/lexicon_ltr.lst)). + +## Evaluation metrics +We run evaluation on the 1_000 shortest sequences that are at least 6s long. To filter those from the ASR transcript, we additionally provide each metric script with the paths to the manifest and `ground_truth_continuation_*` files. + +### Perplexity (PPX) +To get a PPX metric estimate on an ASR transcript, you need to run the following command: +```bash +python ppx.py $PATH_TO_ASR_OUTPUT/hypo.word-960h_scratch.pt-train.txt --cut-tail\ + --manifest=$MANIFEST_DIR/train.tsv --prompts-description=data/ground_truth_continuation_dev.json +``` +where `--cut-tail` tells the script to ignore the last token on each line (ASR puts the sequence ID there). + +### Self- and Auto-BLEU +```bash +python self_bleu.py $PATH_TO_ASR_OUTPUT/hypo.word-960h_scratch.pt-train.txt --cut-tail \ + --manifest=$MANIFEST_DIR/train.tsv --prompts-description=data/ground_truth_continuation_dev.json +``` + +### Continuation-BLEU +```bash +python continuation_eval.py --asr-transcript $PATH_TO_ASR_OUTPUT/hypo.word-960h_scratch.pt-train.txt \ + --manifest=$MANIFEST_DIR/train.tsv --prompts-description=data/ground_truth_continuation_dev.json +``` + +### AUC +Based on the metrics calculated above, we can estimate the AUC of the perplexity/diversity trade-off. We provide an illustration in a [Colab notebook](https://colab.research.google.com/drive/1pVPfOVax_PU3MkYdHRSsa-SI8GBUldNt?usp=sharing). diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/continuation_eval.py b/examples/textless_nlp/gslm/metrics/asr_metrics/continuation_eval.py new file mode 100644 index 0000000000..72b92a341d --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/continuation_eval.py @@ -0,0 +1,99 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +from collections import defaultdict +import numpy as np +from misc.bleu_utils import sentence_bleu +import json +import warnings + + +def get_args(): + import argparse + + parser = argparse.ArgumentParser("Tool to calculate Continuation-BLEU2") + parser.add_argument('--asr-transcript', type=str, + help='Path to the transcript file.') + parser.add_argument('--prompts-description', type=str, + help='Path to the ground-truth continuation') + parser.add_argument('--manifest', type=str, required=True) + parser.add_argument('--take-shortest', type=int, default=1000) + + args = parser.parse_args() + + return args + + +def main(): + # NLTK produces warnings + warnings.filterwarnings("ignore") + + args = get_args() + + with open(args.prompts_description, 'r') as fin: + original_continuations = json.loads(fin.read()) + + sequence2length = [(k, v[0]) for k, v in original_continuations.items()] + assert all(float(v) >= 6.0 for (_, v) in sequence2length) # 6 seconds + + sequence2length.sort(key=lambda x: x[1]) + to_take = set(v[0] for v in sequence2length[:args.take_shortest]) + + with open(args.manifest, 'r') as fin: + fin.readline() + + linenum2file = dict([ + (i, l.split("__")[0]) for (i, l) in enumerate(fin) + ]) + + max_files = max(linenum2file.keys()) + continuations = defaultdict(list) + + mean_length_after = 0 + n_examples = 0 + + with open(args.asr_transcript, 'r') as fin: + for line in fin: + n_examples += 1 + line = line.split() + sequence_id = int(line[-1].split('-')[1][:-1]) + + assert sequence_id <= max_files + + sequence_name = linenum2file[sequence_id] + + continuations[sequence_name].append(line[:-1]) + mean_length_after += len(line) + + mean_length_after /= n_examples + print(f'Mean length of continuations, in words: {mean_length_after}') + metric_values = [] + + mean_ground_truth_words = 0 + n_examples = 0 + n_candidates = 0 + + for k, candidates in continuations.items(): + if k not in to_take: + continue + + n_examples += 1 + + ground_truth = original_continuations[k][1].split() + n_candidates += len(candidates) + bleu = sentence_bleu(candidates, ground_truth, weights=( + 0.5, 0.5), no_length_penalty=True, averaging_mode="geometric") + mean_ground_truth_words += len(ground_truth) + + metric_values.append(bleu) + + n = len(metric_values) + print( + f'Median BLEU over {n} examples: {np.median(metric_values)} +- {np.std(metric_values) / np.sqrt(n)}') + + +if __name__ == '__main__': + main() diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/misc/bleu_utils.py b/examples/textless_nlp/gslm/metrics/asr_metrics/misc/bleu_utils.py new file mode 100644 index 0000000000..75cc5272d3 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/misc/bleu_utils.py @@ -0,0 +1,166 @@ +""" + +TODO: the code is take from Apache-2 Licensed NLTK: make sure we do this properly! + + +Copied over from nltk.tranlate.bleu_score. This code has two major changes: + - allows to turn off length/brevity penalty --- it has no sense for self-bleu, + - allows to use arithmetic instead of geometric mean +""" + +import math +import sys +from fractions import Fraction +import warnings +from collections import Counter +from nltk.translate.bleu_score import modified_precision, closest_ref_length, brevity_penalty, SmoothingFunction + + +def corpus_bleu( + list_of_references, + hypotheses, + weights=(0.25, 0.25, 0.25, 0.25), + smoothing_function=None, + auto_reweigh=False, + averaging_mode="geometric", + no_length_penalty=False +): + """ + Calculate a single corpus-level BLEU score (aka. system-level BLEU) for all + the hypotheses and their respective references. + + Instead of averaging the sentence level BLEU scores (i.e. marco-average + precision), the original BLEU metric (Papineni et al. 2002) accounts for + the micro-average precision (i.e. summing the numerators and denominators + for each hypothesis-reference(s) pairs before the division). + + >>> hyp1 = ['It', 'is', 'a', 'guide', 'to', 'action', 'which', + ... 'ensures', 'that', 'the', 'military', 'always', + ... 'obeys', 'the', 'commands', 'of', 'the', 'party'] + >>> ref1a = ['It', 'is', 'a', 'guide', 'to', 'action', 'that', + ... 'ensures', 'that', 'the', 'military', 'will', 'forever', + ... 'heed', 'Party', 'commands'] + >>> ref1b = ['It', 'is', 'the', 'guiding', 'principle', 'which', + ... 'guarantees', 'the', 'military', 'forces', 'always', + ... 'being', 'under', 'the', 'command', 'of', 'the', 'Party'] + >>> ref1c = ['It', 'is', 'the', 'practical', 'guide', 'for', 'the', + ... 'army', 'always', 'to', 'heed', 'the', 'directions', + ... 'of', 'the', 'party'] + + >>> hyp2 = ['he', 'read', 'the', 'book', 'because', 'he', 'was', + ... 'interested', 'in', 'world', 'history'] + >>> ref2a = ['he', 'was', 'interested', 'in', 'world', 'history', + ... 'because', 'he', 'read', 'the', 'book'] + + >>> list_of_references = [[ref1a, ref1b, ref1c], [ref2a]] + >>> hypotheses = [hyp1, hyp2] + >>> corpus_bleu(list_of_references, hypotheses) # doctest: +ELLIPSIS + 0.5920... + + The example below show that corpus_bleu() is different from averaging + sentence_bleu() for hypotheses + + >>> score1 = sentence_bleu([ref1a, ref1b, ref1c], hyp1) + >>> score2 = sentence_bleu([ref2a], hyp2) + >>> (score1 + score2) / 2 # doctest: +ELLIPSIS + 0.6223... + + :param list_of_references: a corpus of lists of reference sentences, w.r.t. hypotheses + :type list_of_references: list(list(list(str))) + :param hypotheses: a list of hypothesis sentences + :type hypotheses: list(list(str)) + :param weights: weights for unigrams, bigrams, trigrams and so on + :type weights: list(float) + :param smoothing_function: + :type smoothing_function: SmoothingFunction + :param auto_reweigh: Option to re-normalize the weights uniformly. + :type auto_reweigh: bool + :return: The corpus-level BLEU score. + :rtype: float + """ + # Before proceeding to compute BLEU, perform sanity checks. + + p_numerators = Counter() # Key = ngram order, and value = no. of ngram matches. + p_denominators = Counter() # Key = ngram order, and value = no. of ngram in ref. + hyp_lengths, ref_lengths = 0, 0 + + assert len(list_of_references) == len(hypotheses), ( + "The number of hypotheses and their reference(s) should be the " "same " + ) + + # Iterate through each hypothesis and their corresponding references. + for references, hypothesis in zip(list_of_references, hypotheses): + # For each order of ngram, calculate the numerator and + # denominator for the corpus-level modified precision. + for i, _ in enumerate(weights, start=1): + p_i = modified_precision(references, hypothesis, i) + p_numerators[i] += p_i.numerator + p_denominators[i] += p_i.denominator + + # Calculate the hypothesis length and the closest reference length. + # Adds them to the corpus-level hypothesis and reference counts. + hyp_len = len(hypothesis) + hyp_lengths += hyp_len + ref_lengths += closest_ref_length(references, hyp_len) + + # Calculate corpus-level brevity penalty. + if no_length_penalty and averaging_mode == 'geometric': + bp = 1.0 + elif no_length_penalty and averaging_mode == 'arithmetic': + bp = 0.0 + else: + assert not no_length_penalty + assert averaging_mode != 'arithmetic', 'Not sure how to apply length penalty when aurithmetic mode' + bp = brevity_penalty(ref_lengths, hyp_lengths) + + # Uniformly re-weighting based on maximum hypothesis lengths if largest + # order of n-grams < 4 and weights is set at default. + if auto_reweigh: + if hyp_lengths < 4 and weights == (0.25, 0.25, 0.25, 0.25): + weights = (1 / hyp_lengths,) * hyp_lengths + + # Collects the various precision values for the different ngram orders. + p_n = [ + Fraction(p_numerators[i], p_denominators[i], _normalize=False) + for i, _ in enumerate(weights, start=1) + ] + + # Returns 0 if there's no matching n-grams + # We only need to check for p_numerators[1] == 0, since if there's + # no unigrams, there won't be any higher order ngrams. + if p_numerators[1] == 0: + return 0 + + # If there's no smoothing, set use method0 from SmoothinFunction class. + if not smoothing_function: + smoothing_function = SmoothingFunction().method0 + # Smoothen the modified precision. + # Note: smoothing_function() may convert values into floats; + # it tries to retain the Fraction object as much as the + # smoothing method allows. + p_n = smoothing_function( + p_n, references=references, hypothesis=hypothesis, hyp_len=hyp_lengths + ) + + if averaging_mode == "geometric": + s = (w_i * math.log(p_i) for w_i, p_i in zip(weights, p_n)) + s = bp * math.exp(math.fsum(s)) + elif averaging_mode == "arithmetic": + s = (w_i * p_i for w_i, p_i in zip(weights, p_n)) + s = math.fsum(s) + + return s + + +def sentence_bleu( + references, + hypothesis, + weights=(0.25, 0.25, 0.25, 0.25), + smoothing_function=None, + auto_reweigh=False, + averaging_mode="geometric", + no_length_penalty=False +): + return corpus_bleu( + [references], [hypothesis], weights, smoothing_function, auto_reweigh, averaging_mode, no_length_penalty + ) \ No newline at end of file diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/misc/cut_as.py b/examples/textless_nlp/gslm/metrics/asr_metrics/misc/cut_as.py new file mode 100644 index 0000000000..5b7e1e9685 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/misc/cut_as.py @@ -0,0 +1,69 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import torchaudio +import argparse +import json +import pathlib + + +def get_args(): + parser = argparse.ArgumentParser( + "Assuring generated audio have the same length as ground-truth audio") + parser.add_argument('--samples_dir', required=True, type=str) + parser.add_argument('--out_dir', required=True, type=str) + parser.add_argument('--prompts_description', required=True, type=str) + return parser.parse_args() + + +def cut(src, tgt, l): + x, sr = torchaudio.load(str(src)) + assert sr == 16_000 + + x = x.squeeze() + target_frames = int(l * sr) + + flag = 0 + if target_frames <= x.size(0): + x = x[:target_frames] + flag = 1 + else: + flag = 0 + torchaudio.save(str(tgt), x.unsqueeze(0), sr) + return flag + + +def main(): + args = get_args() + tgt_dir = pathlib.Path(args.out_dir) + tgt_dir.mkdir(exist_ok=True, parents=True) + + total_files, sufficiently_long = 0, 0 + + with open(args.prompts_description, 'r') as f: + description = json.loads(f.read()) + + for src_f in pathlib.Path(args.samples_dir).glob('*.wav'): + name_prompt = src_f.with_suffix('').name.split('__')[0] + + assert name_prompt in description, f'Cannot find {name_prompt}!' + + target_length = description[name_prompt][0] + tgt_f = tgt_dir / (src_f.name) + + is_long_enough = cut(src_f, tgt_f, target_length) + sufficiently_long += is_long_enough + if not is_long_enough: + print(f'{src_f} is not long enough') + + total_files += 1 + + print( + f'Total files: {total_files}; sufficiently long: {sufficiently_long}') + + +if __name__ == '__main__': + main() diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/misc/dict.ltr.txt b/examples/textless_nlp/gslm/metrics/asr_metrics/misc/dict.ltr.txt new file mode 100644 index 0000000000..69929e1666 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/misc/dict.ltr.txt @@ -0,0 +1,28 @@ +| 94802 +E 51860 +T 38431 +A 33152 +O 31495 +N 28855 +I 28794 +H 27187 +S 26071 +R 23546 +D 18289 +L 16308 +U 12400 +M 10685 +W 10317 +C 9844 +F 9062 +G 8924 +Y 8226 +P 6890 +B 6339 +V 3936 +K 3456 +' 1023 +X 636 +J 598 +Q 437 +Z 213 diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/ppx.py b/examples/textless_nlp/gslm/metrics/asr_metrics/ppx.py new file mode 100644 index 0000000000..d6a40e4d35 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/ppx.py @@ -0,0 +1,122 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +import numpy as np +import warnings + + +def get_target_sequences(manifest, ground_truth, to_take=1000): + import json + import pathlib + + with open(ground_truth, 'r') as fin: + original_continuations = json.loads(fin.read()) + + sequence2length = [(k, v[0]) for k, v in original_continuations.items()] + assert all(float(v) >= 6.0 for (_, v) in sequence2length) # 6 seconds + + sequence2length.sort(key=lambda x: x[1]) + to_take_sequences = set(v[0] for v in sequence2length[:to_take]) + to_take_ids = [] + + with open(manifest, 'r') as f: + f.readline() + + for i, line in enumerate(f.readlines()): + seq_id = line.split()[0] + seq_id = pathlib.Path(seq_id).name.split('__')[0] + + if seq_id in to_take_sequences: + to_take_ids.append(i) + + print(f'Took {len(to_take_ids)} ids') + return set(to_take_ids) + + +def get_args(): + import argparse + + parser = argparse.ArgumentParser("Evaluate PPX metric of a transcript.") + parser.add_argument('--asr-transcript', type=str, + help='Path to the transcript file.') + parser.add_argument('--cut-id', action='store_true', + help='Whether cut the first token (typically a seq id)') + parser.add_argument('--cut-tail', action='store_true', + help='Whether cut the last token (typically a speaker id)') + + parser.add_argument('--manifest', type=str, default=None) + parser.add_argument('--prompts-description', type=str, default=None) + + args = parser.parse_args() + + return args + + +def main(): + args = get_args() + + lm = torch.hub.load( + 'pytorch/fairseq', 'transformer_lm.wmt19.en', tokenizer='moses', bpe='fastbpe') + + lm.eval().cuda() # disable dropout + + if args.manifest is None and args.prompts_description is None: + target_ids = None + else: + target_ids = get_target_sequences( + args.manifest, args.prompts_description) + + with open(args.asr_transcript, 'r') as fin: + lines = fin.readlines() + + if target_ids is not None: + filtered = [] + for line in lines: + line_id = line.split()[-1] + line_id = int(line_id.split('-')[1][:-1]) + if line_id in target_ids: + filtered.append(line) + lines = filtered + else: + pass + + if args.cut_id: + lines = [' '.join(x.split()[1:]) for x in lines] + if args.cut_tail: + lines = [' '.join(x.split()[:-1]) for x in lines] + lines = [x.strip().lower() for x in lines] + + def get_logprob(sent): return \ + lm.score(sent)['positional_scores'].mean().neg().item() + + logprobs = [get_logprob(l) for l in lines] + + filtered = [x for x in logprobs if not np.isnan(x)] + if len(filtered) != len(logprobs): + warnings.warn("NaNs detected!") + logprobs = filtered + + perplexities = [np.exp(l) for l in logprobs] + + for name, stats in [('logprob', logprobs), ('perplexity', perplexities)]: + mean = np.mean(stats) + sem = np.std(stats) / np.sqrt(len(stats)) + + median = np.median(stats) + interval = list(np.percentile(stats, [10, 90])) + + mean, sem, median, percentile10, percentile90 = [ + round(x, 2) for x in [mean, sem, median] + interval] + + print(name) + print(f"\tMean {mean} +- {sem}") + print( + f"\tMedian {median}, 90% confidence interval {percentile10}...{percentile90}") + + +if __name__ == '__main__': + main() diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/self_auto_bleu.py b/examples/textless_nlp/gslm/metrics/asr_metrics/self_auto_bleu.py new file mode 100644 index 0000000000..062bb82f66 --- /dev/null +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/self_auto_bleu.py @@ -0,0 +1,201 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +import nltk +from misc.bleu_utils import sentence_bleu +import warnings + + +def get_target_sequences(manifest, ground_truth, to_take=1000): + import json + import pathlib + + with open(ground_truth, 'r') as fin: + original_continuations = json.loads(fin.read()) + + sequence2length = [(k, v[0]) for k, v in original_continuations.items()] + assert all(float(v) >= 6.0 for (_, v) in sequence2length) # 6 seconds + + sequence2length.sort(key=lambda x: x[1]) + to_take_sequences = set(v[0] for v in sequence2length[:to_take]) + to_take_ids = [] + + with open(manifest, 'r') as f: + f.readline() + + for i, line in enumerate(f.readlines()): + seq_id = line.split()[0] + seq_id = pathlib.Path(seq_id).name.split('__')[0] + + if seq_id in to_take_sequences: + to_take_ids.append(i) + + print(f'Took {len(to_take_ids)} ids') + return set(to_take_ids) + + +def get_args(): + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('--asr-transcript', type=str, + help='Path to the transcript file.') + + parser.add_argument('--manifest', required=True) + parser.add_argument('--prompts-description', required=True) + + parser.add_argument('--cut-id', action='store_true', + help='Whether cut the first token (typically a seq id)') + parser.add_argument('--cut-tail', action='store_true', + help='Whether cut the last token (typically a speaker id)') + parser.add_argument('--debug', action='store_true') + + args = parser.parse_args() + + return args + + +def get_self_bleu(utterances, averaging_mode, weights): + self_bleu = [] + + for i in range(len(utterances)): + hypo = utterances[i] + rest = utterances[:i] + utterances[i+1:] + + self_bleu.append(sentence_bleu(rest, hypo, weights, + no_length_penalty=True, averaging_mode=averaging_mode)) + + return self_bleu + + +def get_self_bleu2_arithmetic(utterances): + weights = (0.5, 0.5) # equal weight for unigrams and bigrams + return get_self_bleu(utterances, averaging_mode='arithmetic', weights=weights) + + +def get_self_bleu2_geometric(utterances): + weights = (0.5, 0.5) + return get_self_bleu(utterances, averaging_mode='geometric', weights=weights) + + +def get_auto_bleu2_arithmetic(utterances): + weights = (0.5, 0.5) + return [auto_bleu(u, mean_mode='arithmetic', weights=weights) for u in utterances] + + +def get_auto_bleu2_geometric(utterances): + weights = (0.5, 0.5) + return [auto_bleu(u, mean_mode='geometric', weights=weights) for u in utterances] + + +def get_auto_bleu3_geometric(utterances): + weights = (1./3, 1./3, 1./3) + return [auto_bleu(u, mean_mode='geometric', weights=weights) for u in utterances] + + +def get_auto_bleu3_arithmetic(utterances): + weights = (1./3, 1./3, 1./3) + return [auto_bleu(u, mean_mode='arithmetic', weights=weights) for u in utterances] + + +def get_self_bleu3_arithmetic(utterances): + weights = (1./3, 1./3, 1./3) + return get_self_bleu(utterances, averaging_mode='arithmetic', weights=weights) + + +def get_self_bleu3_geometric(utterances): + weights = (1./3, 1./3, 1./3) + return get_self_bleu(utterances, averaging_mode='geometric', weights=weights) + + +def auto_bleu(sentence, weights, mean_mode='arithmetic'): + if len(sentence) <= 1: + return 0 + + N = len(weights) + + bleu_n = np.zeros([N]) + for n in range(N): + targ_ngrams = list(nltk.ngrams(sentence, n+1)) + for p in range(len(targ_ngrams)): + left = sentence[:p] + right = sentence[(p+n+1):] + rest_ngrams = list(nltk.ngrams(left, n+1)) + \ + list(nltk.ngrams(right, n+1)) + # compute the nb of matching ngrams + bleu_n[n] += targ_ngrams[p] in rest_ngrams + bleu_n[n] /= len(targ_ngrams) # average them to get a proportion + + weights = np.array(weights) + if mean_mode == 'arithmetic': + return (bleu_n * weights).sum() + elif mean_mode == 'geometric': + return (bleu_n ** weights).prod() + else: + raise ValueError(f'Unknown agggregation mode {mean_mode}') + + +def main(): + from multiprocessing import Pool + + args = get_args() + target_ids = get_target_sequences(args.manifest, args.prompts_description) + + with open(args.asr_transcript, 'r') as fin: + lines = fin.readlines() + + terms = [x.strip().split() for x in lines] + filtered = [] + for term in terms: + line_id = int(term[-1].split('-')[1][:-1]) + if line_id in target_ids: + filtered.append(term) + terms = filtered + + if args.cut_id: + terms = [x[1:] for x in terms] + if args.cut_tail: + terms = [x[:-1] for x in terms] + + if args.debug: + terms = terms[:10] + + tasks = [ + ('Self-BLEU2-arithmetic', get_self_bleu2_arithmetic), + ('Self-BLEU2-geometric', get_self_bleu2_geometric), + ('Auto-BLEU2-arithmetic', get_auto_bleu2_arithmetic), + ('Auto-BLEU2-geometric', get_auto_bleu2_geometric), + + ('Self-BLEU3-arithmetic', get_self_bleu3_arithmetic), + ('Self-BLEU3-geometric', get_self_bleu3_geometric), + ('Auto-BLEU3-arithmetic', get_auto_bleu3_arithmetic), + ('Auto-BLEU3-geometric', get_auto_bleu3_geometric), + ] + + n_processes = min(16, len(tasks)) + with Pool(n_processes) as pool: + metrics = pool.map(run_f, [(t[1], terms) for t in tasks]) + + for (metric_name, _), metric in zip(tasks, metrics): + metric, sem = np.mean(metric), np.std(metric) / np.sqrt(len(metric)) + + metric, sem = [ + round(100 * x, 2) for x in [metric, sem] + ] + + print(f'{metric_name} {metric} +- {sem}') + + +def run_f(task_params): + f, terms = task_params + return f(terms) + + +if __name__ == '__main__': + # NLTK produces warnings + warnings.filterwarnings("ignore") + + main() diff --git a/examples/textless_nlp/gslm/speech2unit/README.md b/examples/textless_nlp/gslm/speech2unit/README.md new file mode 100644 index 0000000000..1a3d131ec1 --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/README.md @@ -0,0 +1,71 @@ +# Speech to Unit Model (speech2unit) + +## Acoustic Model +For quantizing speech we learn a K-means clustering over acoustic representations for which we either use Log-Mel Filterbank or pretrained acoustic representation models. For using pretrained models, please download from their respective locations linked below. +* [Modified CPC](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/cpc_big_ll6kh_top_ctc.pt) +* [HuBERT-Base](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) +* [Wav2Vec 2.0-Base](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_new.pt) + +## Quantization Model +You can download pretrained quantized model from the list below. + +K-Means Model | Download Link +|-|- +Log Mel Filterbank + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km50/km.bin) +Log Mel Filterbank + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km100/km.bin) +Log Mel Filterbank + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km200/km.bin) +Log Mel Filterbank + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km500/km.bin) +Modified CPC + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km50/km.bin) +Modified CPC + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km100/km.bin) +Modified CPC + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km200/km.bin) +Modified CPC + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km500/km.bin) +HuBERT Base + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km50/km.bin) +HuBERT Base + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km100/km.bin) +HuBERT Base + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km200/km.bin) +HuBERT Base + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km500/km.bin) +wav2vec 2.0 Large + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km50/km.bin) +wav2vec 2.0 Large + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km100/km.bin) +wav2vec 2.0 Large + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km200/km.bin) +wav2vec 2.0 Large + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km500/km.bin) + +### Quantization +For quantizing speech with a given acoustic representation, please follow the steps below. +1. Learn K-means clustering model +``` +N_CLUSTERS=<number_of_clusters_used_for_kmeans> +TYPE=<one_of_logmel/cpc/hubert/w2v2> +CKPT_PATH=<path_of_pretrained_acoustic_model> +LAYER=<layer_of_acoustic_model_to_extract_features_from> +MANIFEST=<tab_separated_manifest_of_audio_files_for_training_kmeans> +KM_MODEL_PATH=<output_path_of_the_kmeans_model> + +PYTHONPATH=. python examples/textless_nlp/gslm/speech2unit/clustering/cluster_kmeans.py \ + --num_clusters $N_CLUSTERS \ + --feature_type $TYPE \ + --checkpoint_path $CKPT_PATH \ + --layer $LAYER \ + --manifest_path $MANIFEST \ + --out_kmeans_model_path $KM_MODEL_PATH +``` +2. Quantize using the learned clusters +``` +MANIFEST=<tab_separated_manifest_of_audio_files_to_quantize> +OUT_QUANTIZED_FILE=<output_quantized_audio_file_path> + +python examples/textless_nlp/gslm/speech2unit/clustering/del/quantize_with_kmeans.py \ + --feature_type $TYPE \ + --kmeans_model_path $KM_MODEL_PATH \ + --checkpoint_path $CKPT_PATH \ + --layer $LAYER \ + --manifest_path $MANIFEST \ + --out_quantized_file_path $OUT_QUANTIZED_FILE \ + --extension ".flac" +``` + +Note about the manifest file is a file with paths and length of input audio files. The format of the file is as follows: +``` +<path_of_root_directory_containing_audio_files> +<relative_path_of_audio_file_1>\t<number_of_frames_1> +<relative_path_of_audio_file_2>\t<number_of_frames_1> +... +``` \ No newline at end of file diff --git a/examples/textless_nlp/gslm/speech2unit/__init__.py b/examples/textless_nlp/gslm/speech2unit/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/textless_nlp/gslm/speech2unit/clustering/__init__.py b/examples/textless_nlp/gslm/speech2unit/clustering/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/textless_nlp/gslm/speech2unit/clustering/cluster_kmeans.py b/examples/textless_nlp/gslm/speech2unit/clustering/cluster_kmeans.py new file mode 100644 index 0000000000..7cf844a95a --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/clustering/cluster_kmeans.py @@ -0,0 +1,212 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import os +import time + +import numpy as np +from sklearn.cluster import MiniBatchKMeans + +import joblib +from examples.textless_nlp.gslm.speech2unit.pretrained.utils import ( + get_and_dump_features, + get_features, +) + + +def get_logger(): + log_format = "[%(asctime)s] [%(levelname)s]: %(message)s" + logging.basicConfig(format=log_format, level=logging.INFO) + logger = logging.getLogger(__name__) + return logger + + +def get_parser(): + parser = argparse.ArgumentParser( + description="Learn K-means clustering over acoustic features." + ) + + # Features arguments + parser.add_argument( + "--in_features_path", type=str, default=None, help="Features file path" + ) + parser.add_argument( + "--feature_type", + type=str, + choices=["logmel", "hubert", "w2v2", "cpc"], + default=None, + help="Acoustic feature type", + ) + parser.add_argument( + "--manifest_path", + type=str, + default=None, + help="Manifest file containing the root dir and file names", + ) + parser.add_argument( + "--out_features_path", + type=str, + default=None, + help="Features file path to write to", + ) + parser.add_argument( + "--checkpoint_path", + type=str, + help="Pretrained acoustic model checkpoint", + ) + parser.add_argument( + "--layer", + type=int, + help="The layer of the pretrained model to extract features from", + default=-1, + ) + parser.add_argument( + "--sample_pct", + type=float, + help="Percent data to use for K-means training", + default=0.1, + ) + + # K-means arguments + parser.add_argument( + "--num_clusters", type=int, help="Nubmer of clusters", default=50 + ) + parser.add_argument("--init", default="k-means++") + parser.add_argument( + "--max_iter", + type=int, + help="Maximum number of iterations for K-means training", + default=150, + ) + parser.add_argument( + "--batch_size", + type=int, + help="Batch size for K-means training", + default=10000, + ) + parser.add_argument("--tol", default=0.0, type=float) + parser.add_argument("--max_no_improvement", default=100, type=int) + parser.add_argument("--n_init", default=20, type=int) + parser.add_argument("--reassignment_ratio", default=0.5, type=float) + parser.add_argument( + "--out_kmeans_model_path", + type=str, + required=True, + help="Path to save K-means model", + ) + + # Leftovers + parser.add_argument( + "--seed", + type=int, + help="Random seed to use for K-means training", + default=1369, + ) + + return parser + + +def get_kmeans_model( + n_clusters, + init, + max_iter, + batch_size, + tol, + max_no_improvement, + n_init, + reassignment_ratio, + random_state, +): + return MiniBatchKMeans( + n_clusters=n_clusters, + init=init, + max_iter=max_iter, + batch_size=batch_size, + tol=tol, + max_no_improvement=max_no_improvement, + n_init=n_init, + reassignment_ratio=reassignment_ratio, + random_state=random_state, + verbose=1, + compute_labels=True, + init_size=None, + ) + + +def train_kmeans(kmeans_model, features_batch): + start_time = time.time() + kmeans_model.fit(features_batch) + time_taken = round((time.time() - start_time) // 60, 2) + return kmeans_model, time_taken + + +def main(args, logger): + # Features loading/extraction for K-means + if args.in_features_path: + # Feature loading + logger.info(f"Loading features from {args.in_features_path}...") + features_batch = np.load(args.in_features_path, allow_pickle=True) + else: + # Feature extraction + logger.info(f"Extracting {args.feature_type} acoustic features...") + features_batch = ( + get_features( + feature_type=args.feature_type, + checkpoint_path=args.checkpoint_path, + layer=args.layer, + manifest_path=args.manifest_path, + sample_pct=args.sample_pct, + flatten=True, + ) + if not args.out_features_path + else get_and_dump_features( + feature_type=args.feature_type, + checkpoint_path=args.checkpoint_path, + layer=args.layer, + manifest_path=args.manifest_path, + sample_pct=args.sample_pct, + flatten=True, + out_features_path=args.out_features_path, + ) + ) + if args.out_features_path: + logger.info( + f"Saved extracted features at {args.out_features_path}" + ) + logger.info(f"Features shape = {features_batch.shape}\n") + + # Learn and save K-means model + kmeans_model = get_kmeans_model( + n_clusters=args.num_clusters, + init=args.init, + max_iter=args.max_iter, + batch_size=args.batch_size, + tol=args.tol, + max_no_improvement=args.max_no_improvement, + n_init=args.n_init, + reassignment_ratio=args.reassignment_ratio, + random_state=args.seed, + ) + logger.info("Starting k-means training...") + kmeans_model, time_taken = train_kmeans( + kmeans_model=kmeans_model, features_batch=features_batch + ) + logger.info(f"...done k-means training in {time_taken} minutes") + inertia = -kmeans_model.score(features_batch) / len(features_batch) + logger.info(f"Total intertia: {round(inertia, 2)}\n") + + logger.info(f"Saving k-means model to {args.out_kmeans_model_path}") + os.makedirs(os.path.dirname(args.out_kmeans_model_path), exist_ok=True) + joblib.dump(kmeans_model, open(args.out_kmeans_model_path, "wb")) + + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + logger = get_logger() + logger.info(args) + main(args, logger) diff --git a/examples/textless_nlp/gslm/speech2unit/clustering/dump_feats.py b/examples/textless_nlp/gslm/speech2unit/clustering/dump_feats.py new file mode 100644 index 0000000000..031567c6d8 --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/clustering/dump_feats.py @@ -0,0 +1,91 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging + +from examples.textless_nlp.gslm.speech2unit.pretrained.utils import ( + get_and_dump_features, +) + + +def get_parser(): + parser = argparse.ArgumentParser( + description="Compute and dump log mel fbank features." + ) + parser.add_argument( + "--feature_type", + type=str, + choices=["logmel", "hubert", "w2v2", "cpc"], + default=None, + help="Acoustic feature type", + ) + parser.add_argument( + "--manifest_path", + type=str, + default=None, + help="Manifest file containing the root dir and file names", + ) + parser.add_argument( + "--out_features_path", + type=str, + default=None, + help="Features file path to write to", + ) + parser.add_argument( + "--checkpoint_path", + type=str, + help="Pretrained acoustic model checkpoint", + ) + parser.add_argument( + "--layer", + type=int, + help="The layer of the pretrained model to extract features from", + default=-1, + ) + parser.add_argument( + "--sample_pct", + type=float, + help="Percent data to use for K-means training", + default=0.1, + ) + parser.add_argument( + "--out_features_path", + type=str, + help="Path to save log mel fbank features", + ) + return parser + + +def get_logger(): + log_format = "[%(asctime)s] [%(levelname)s]: %(message)s" + logging.basicConfig(format=log_format, level=logging.INFO) + logger = logging.getLogger(__name__) + return logger + + +if __name__ == "__main__": + """ + Example command: + python ~/speechbot/clustering/dump_logmelfank_feats.py \ + --manifest_path /checkpoint/kushall/data/LJSpeech-1.1/asr_input_wavs_16k/train.tsv + --out_features_path /checkpoint/kushall/experiments/speechbot/logmelfbank/features/ljspeech/train.npy + """ + parser = get_parser() + args = parser.parse_args() + logger = get_logger() + logger.info(args) + + logger.info(f"Extracting {args.feature_type} acoustic features...") + get_and_dump_features( + feature_type=args.feature_type, + checkpoint_path=args.checkpoint_path, + layer=args.layer, + manifest_path=args.manifest_path, + sample_pct=args.sample_pct, + flatten=True, + out_features_path=args.out_features_path, + ) + logger.info(f"Saved extracted features at {args.out_features_path}") diff --git a/examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py b/examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py new file mode 100644 index 0000000000..2c87445d81 --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py @@ -0,0 +1,125 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import os + +import numpy as np + +import joblib +from examples.textless_nlp.gslm.speech2unit.clustering.utils import ( + get_audio_files, +) +from examples.textless_nlp.gslm.speech2unit.pretrained.utils import ( + get_features, +) + + +def get_logger(): + log_format = "[%(asctime)s] [%(levelname)s]: %(message)s" + logging.basicConfig(format=log_format, level=logging.INFO) + logger = logging.getLogger(__name__) + return logger + + +def get_parser(): + parser = argparse.ArgumentParser( + description="Quantize using K-means clustering over acoustic features." + ) + parser.add_argument( + "--feature_type", + type=str, + choices=["logmel", "hubert", "w2v2", "cpc"], + default=None, + required=True, + help="Acoustic feature type", + ) + parser.add_argument( + "--acoustic_model_path", + type=str, + help="Pretrained acoustic model checkpoint" + ) + parser.add_argument( + "--layer", + type=int, + help="The layer of the pretrained model to extract features from", + default=-1, + ) + parser.add_argument( + "--kmeans_model_path", + type=str, + required=True, + help="K-means model file path to use for inference", + ) + parser.add_argument( + "--features_path", + type=str, + default=None, + help="Features file path. You don't need to enter acoustic model details if you have dumped features", + ) + parser.add_argument( + "--manifest_path", + type=str, + default=None, + help="Manifest file containing the root dir and file names", + ) + parser.add_argument( + "--out_quantized_file_path", + required=True, + type=str, + help="File path of quantized output.", + ) + parser.add_argument( + "--extension", type=str, default=".flac", help="Features file path" + ) + return parser + + +def main(args, logger): + # Feature extraction + if args.features_path is not None: + logger.info(f"Loading acoustic features from {args.features_path}...") + features_batch = np.load(args.features_path) + else: + logger.info(f"Extracting {args.feature_type} acoustic features...") + features_batch = get_features( + feature_type=args.feature_type, + checkpoint_path=args.acoustic_model_path, + layer=args.layer, + manifest_path=args.manifest_path, + sample_pct=1.0, + flatten=False, + ) + logger.info( + f"Features extracted for {len(features_batch)} utterances.\n" + ) + logger.info( + f"Dimensionality of representation = {features_batch[0].shape[1]}" + ) + + # K-means model + logger.info(f"Loading K-means model from {args.kmeans_model_path} ...") + kmeans_model = joblib.load(open(args.kmeans_model_path, "rb")) + kmeans_model.verbose = False + + _, fnames, _ = get_audio_files(args.manifest_path) + + os.makedirs(os.path.dirname(args.out_quantized_file_path), exist_ok=True) + print(f"Writing quantized predictions to {args.out_quantized_file_path}") + with open(args.out_quantized_file_path, "w") as fout: + for i, feats in enumerate(features_batch): + pred = kmeans_model.predict(feats) + pred_str = " ".join(str(p) for p in pred) + base_fname = os.path.basename(fnames[i]).rstrip(args.extension) + fout.write(f"{base_fname}|{pred_str}\n") + + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + logger = get_logger() + logger.info(args) + main(args, logger) diff --git a/examples/textless_nlp/gslm/speech2unit/clustering/utils.py b/examples/textless_nlp/gslm/speech2unit/clustering/utils.py new file mode 100644 index 0000000000..cf08d1fe4b --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/clustering/utils.py @@ -0,0 +1,20 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import List, Tuple + + +def get_audio_files(manifest_path: str) -> Tuple[str, List[str], List[int]]: + fnames, sizes = [], [] + with open(manifest_path, "r") as f: + root_dir = f.readline().strip() + for line in f: + items = line.strip().split("\t") + assert ( + len(items) == 2 + ), f"File must have two columns separated by tab. Got {line}" + fnames.append(items[0]) + sizes.append(int(items[1])) + return root_dir, fnames, sizes diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py new file mode 100644 index 0000000000..c613f52d3c --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py @@ -0,0 +1,192 @@ +import soundfile as sf +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class CpcFeatureReader: + """ + Wrapper class to run inference on CPC model. + Helps extract features for a given audio file. + """ + + def __init__( + self, + checkpoint_path, + layer, + use_encoder_layer=False, + norm_features=False, + sample_rate=16000, + max_chunk=64000, + ): + self.model = load_cpc_model(checkpoint_path, layer).eval().cuda() + self.sample_rate = sample_rate + self.max_chunk = max_chunk + self.norm_features = norm_features + self.use_encoder_layer = use_encoder_layer + + def read_audio(self, path, ref_len=None): + wav, sr = sf.read(path) + if wav.ndim == 2: + wav = wav.mean(-1) + assert wav.ndim == 1, wav.ndim + assert sr == self.sample_rate, sr + if ref_len is not None and abs(ref_len - len(wav)) > 160: + print(f"ref {ref_len} != read {len(wav)} ({path})") + return wav + + def get_feats(self, file_path, ref_len=None): + x = self.read_audio(file_path, ref_len) + # Inspired from CPC_audio feature_loader.py + with torch.no_grad(): + x = torch.from_numpy(x).float().cuda() + x = x.view(1, 1, -1) + size = x.size(2) + feat = [] + start = 0 + while start < size: + if start + self.max_chunk > size: + break + x_chunk = x[..., start : start + self.max_chunk] + feat_chunk = self.model.extract_features( + source=x_chunk, + get_encoded=self.use_encoder_layer, + norm_output=self.norm_features, + ) + feat.append(feat_chunk) + start += self.max_chunk + + if start < size: + x_chunk = x[:, -self.max_chunk :] + feat_chunk = self.model.extract_features( + source=x_chunk, + get_encoded=self.use_encoder_layer, + norm_output=self.norm_features, + ) + df = x_chunk.size(2) // feat_chunk.size(1) + delta = (size - start) // df + feat.append(feat_chunk[:, -delta:]) + return torch.cat(feat, 1).squeeze(0) + + +def load_cpc_model(checkpoint_path, layer=None): + state_dict = torch.load(checkpoint_path) + weights = state_dict["weights"] + config = state_dict["config"] + if layer is not None: + config["nLevelsGRU"] = layer + + encoder = CPCEncoder(config["hiddenEncoder"]) + ar_net = CPCAR( + config["hiddenEncoder"], config["hiddenGar"], False, config["nLevelsGRU"] + ) + + model = CPCModel(encoder, ar_net) + model.load_state_dict(weights, strict=False) + model.config = config + + return model + + +class ChannelNorm(nn.Module): + def __init__(self, num_features, epsilon=1e-05, affine=True): + super(ChannelNorm, self).__init__() + if affine: + self.weight = nn.parameter.Parameter(torch.Tensor(1, num_features, 1)) + self.bias = nn.parameter.Parameter(torch.Tensor(1, num_features, 1)) + else: + self.weight = None + self.bias = None + self.epsilon = epsilon + self.p = 0 + self.affine = affine + self.reset_parameters() + + def reset_parameters(self): + if self.affine: + torch.nn.init.ones_(self.weight) + torch.nn.init.zeros_(self.bias) + + def forward(self, x): + cum_mean = x.mean(dim=1, keepdim=True) + cum_var = x.var(dim=1, keepdim=True) + x = (x - cum_mean) * torch.rsqrt(cum_var + self.epsilon) + if self.weight is not None: + x = x * self.weight + self.bias + return x + + +class CPCEncoder(nn.Module): + def __init__(self, hidden_dim=512): + super(CPCEncoder, self).__init__() + self.conv0 = nn.Conv1d(1, hidden_dim, 10, stride=5, padding=3) + self.batchNorm0 = ChannelNorm(hidden_dim) + self.conv1 = nn.Conv1d(hidden_dim, hidden_dim, 8, stride=4, padding=2) + self.batchNorm1 = ChannelNorm(hidden_dim) + self.conv2 = nn.Conv1d(hidden_dim, hidden_dim, 4, stride=2, padding=1) + self.batchNorm2 = ChannelNorm(hidden_dim) + self.conv3 = nn.Conv1d(hidden_dim, hidden_dim, 4, stride=2, padding=1) + self.batchNorm3 = ChannelNorm(hidden_dim) + self.conv4 = nn.Conv1d(hidden_dim, hidden_dim, 4, stride=2, padding=1) + self.batchNorm4 = ChannelNorm(hidden_dim) + self.DOWNSAMPLING = 160 + + def get_output_dim(self): + return self.conv4.out_channels + + def forward(self, x): + x = F.relu(self.batchNorm0(self.conv0(x))) + x = F.relu(self.batchNorm1(self.conv1(x))) + x = F.relu(self.batchNorm2(self.conv2(x))) + x = F.relu(self.batchNorm3(self.conv3(x))) + x = F.relu(self.batchNorm4(self.conv4(x))) + return x + + +class CPCAR(nn.Module): + def __init__(self, dim_encoded, dim_output, keep_hidden, num_layers): + super(CPCAR, self).__init__() + self.baseNet = nn.LSTM( + dim_encoded, dim_output, num_layers=num_layers, batch_first=True + ) + self.hidden = None + self.keep_hidden = keep_hidden + + def get_output_dim(self): + return self.baseNet.hidden_size + + def forward(self, x): + try: + self.baseNet.flatten_parameters() + except RuntimeError: + pass + x, h = self.baseNet(x, self.hidden) + if self.keep_hidden: + if isinstance(h, tuple): + self.hidden = tuple(x.detach() for x in h) + else: + self.hidden = h.detach() + return x + + +class CPCModel(nn.Module): + def __init__(self, encoder, ar_net): + super(CPCModel, self).__init__() + self.gEncoder = encoder + self.gAR = ar_net + self.config = None + + def forward(self, x, label): + encoded = self.gEncoder(x).permute(0, 2, 1) + cpc_feature = self.gAR(encoded) + return cpc_feature, encoded, label + + def extract_features(self, source, get_encoded=False, norm_output=False): + cpc_feature, encoded, _ = self.forward(source, None) + if get_encoded: + cpc_feature = encoded + if norm_output: + mean = cpc_feature.mean(dim=1, keepdim=True) + var = cpc_feature.var(dim=1, keepdim=True) + cpc_feature = (cpc_feature - mean) / torch.sqrt(var + 1e-08) + return cpc_feature diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py new file mode 100644 index 0000000000..09442206e1 --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py @@ -0,0 +1,59 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import fairseq +import soundfile as sf +import torch.nn.functional as F + + +class HubertFeatureReader: + """ + Wrapper class to run inference on HuBERT model. + Helps extract features for a given audio file. + """ + + def __init__(self, checkpoint_path, layer, max_chunk=1600000): + ( + model, + cfg, + task, + ) = fairseq.checkpoint_utils.load_model_ensemble_and_task( + [checkpoint_path] + ) + self.model = model[0].eval().cuda() + self.task = task + self.layer = layer + self.max_chunk = max_chunk + + def read_audio(self, path, ref_len=None): + wav, sr = sf.read(path) + if wav.ndim == 2: + wav = wav.mean(-1) + assert wav.ndim == 1, wav.ndim + assert sr == self.task.cfg.sample_rate, sr + if ref_len is not None and abs(ref_len - len(wav)) > 160: + print(f"ref {ref_len} != read {len(wav)} ({path})") + return wav + + def get_feats(self, file_path, ref_len=None): + x = self.read_audio(file_path, ref_len) + with torch.no_grad(): + x = torch.from_numpy(x).float().cuda() + if self.task.cfg.normalize: + x = F.layer_norm(x, x.shape) + x = x.view(1, -1) + + feat = [] + for start in range(0, x.size(1), self.max_chunk): + x_chunk = x[:, start: start + self.max_chunk] + feat_chunk, _ = self.model.extract_features( + source=x_chunk, + padding_mask=None, + mask=False, + output_layer=self.layer, + ) + feat.append(feat_chunk) + return torch.cat(feat, 1).squeeze(0) diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py new file mode 100644 index 0000000000..106f502476 --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py @@ -0,0 +1,30 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import soundfile as sf +import torch +import torchaudio.compliance.kaldi as kaldi + + +class LogMelFeatureReader: + """ + Wrapper class to run inference on HuBERT model. + Helps extract features for a given audio file. + """ + + def __init__(self, *args, **kwargs): + self.num_mel_bins = kwargs.get("num_mel_bins", 80) + self.frame_length = kwargs.get("frame_length", 25.0) + + def get_feats(self, file_path): + wav, sr = sf.read(file_path) + feats = torch.from_numpy(wav).float() + feats = kaldi.fbank( + feats.unsqueeze(0), + num_mel_bins=self.num_mel_bins, + frame_length=self.frame_length, + sample_frequency=sr, + ) + return feats diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/utils.py b/examples/textless_nlp/gslm/speech2unit/pretrained/utils.py new file mode 100644 index 0000000000..5aaddf6421 --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/utils.py @@ -0,0 +1,126 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import gc +import os +import random +import shutil +import numpy as np + +import torch +import tqdm +from examples.textless_nlp.gslm.speech2unit.pretrained.cpc_feature_reader import ( + CpcFeatureReader, +) +from examples.textless_nlp.gslm.speech2unit.pretrained.hubert_feature_reader import ( + HubertFeatureReader, +) +from examples.textless_nlp.gslm.speech2unit.pretrained.logmel_feature_reader import ( + LogMelFeatureReader, +) +from examples.textless_nlp.gslm.speech2unit.pretrained.w2v2_feature_reader import ( + Wav2VecFeatureReader, +) + + +def get_feature_reader(feature_type): + if feature_type == "logmel": + return LogMelFeatureReader + elif feature_type == "hubert": + return HubertFeatureReader + elif feature_type == "w2v2": + return Wav2VecFeatureReader + elif feature_type == "cpc": + return CpcFeatureReader + else: + raise NotImplementedError(f"{feature_type} is not supported.") + + +def get_feature_iterator( + feature_type, checkpoint_path, layer, manifest_path, sample_pct +): + feature_reader_cls = get_feature_reader(feature_type) + with open(manifest_path, "r") as fp: + lines = fp.read().split("\n") + root = lines.pop(0).strip() + file_path_list = [ + os.path.join(root, line.split("\t")[0]) + for line in lines + if len(line) > 0 + ] + if sample_pct < 1.0: + file_path_list = random.sample( + file_path_list, int(sample_pct * len(file_path_list)) + ) + num_files = len(file_path_list) + reader = feature_reader_cls( + checkpoint_path=checkpoint_path, layer=layer + ) + + def iterate(): + for file_path in file_path_list: + feats = reader.get_feats(file_path) + yield feats.cpu().numpy() + + return iterate, num_files + + +def get_features( + feature_type, checkpoint_path, layer, manifest_path, sample_pct, flatten +): + generator, num_files = get_feature_iterator( + feature_type=feature_type, + checkpoint_path=checkpoint_path, + layer=layer, + manifest_path=manifest_path, + sample_pct=sample_pct, + ) + iterator = generator() + + features_list = [] + for features in tqdm.tqdm(iterator, total=num_files): + features_list.append(features) + + # Explicit clean up + del iterator + del generator + gc.collect() + torch.cuda.empty_cache() + + if flatten: + return np.concatenate(features_list) + + return features_list + + +def get_and_dump_features( + feature_type, + checkpoint_path, + layer, + manifest_path, + sample_pct, + flatten, + out_features_path, +): + # Feature extraction + features_batch = get_features( + feature_type=feature_type, + checkpoint_path=checkpoint_path, + layer=layer, + manifest_path=manifest_path, + sample_pct=sample_pct, + flatten=flatten, + ) + + # Save features + out_dir_path = os.path.dirname(out_features_path) + os.makedirs(out_dir_path, exist_ok=True) + shutil.copyfile( + manifest_path, + os.path.join(out_dir_path, os.path.basename(manifest_path)), + ) + np.save(out_features_path, features_batch) + + return features_batch diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py new file mode 100644 index 0000000000..b878321e44 --- /dev/null +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py @@ -0,0 +1,46 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import fairseq +import soundfile as sf + + +class Wav2VecFeatureReader: + """ + Wrapper class to run inference on Wav2Vec 2.0 model. + Helps extract features for a given audio file. + """ + + def __init__(self, checkpoint_path, layer): + state = fairseq.checkpoint_utils.load_checkpoint_to_cpu( + checkpoint_path + ) + + w2v_args = state["args"] + self.task = fairseq.tasks.setup_task(w2v_args) + model = self.task.build_model(w2v_args) + model.load_state_dict(state["model"], strict=True) + model.eval() + model.cuda() + self.model = model + self.layer = layer + + def read_audio(self, fname): + wav, sr = sf.read(fname) + if wav.ndim == 2: + wav = wav.mean(-1) + assert wav.ndim == 1, wav.ndim + assert sr == self.task.cfg.sample_rate, sr + return wav + + def get_feats(self, file_path): + x = self.read_audio(file_path) + with torch.no_grad(): + source = torch.from_numpy(x).view(1, -1).float().cuda() + res = self.model( + source=source, mask=False, features_only=True, layer=self.layer + ) + return res["layer_results"][self.layer][0].squeeze(1) diff --git a/examples/textless_nlp/gslm/tools/README.md b/examples/textless_nlp/gslm/tools/README.md new file mode 100644 index 0000000000..61fcbbded8 --- /dev/null +++ b/examples/textless_nlp/gslm/tools/README.md @@ -0,0 +1,22 @@ +# GSLM Tools + +## Resynthesis +You can use the command line tool below to input an audio file and get the resynthesized audio. This tool implements the unsupervised method for resynthesis described in the paper. The way to invoke the command line tool is shown below. +``` +FAIRSEQ_ROOT=<path_to_your_fairseq_repo_root> +TYPE=<one_of_logmel/cpc/hubert/w2v2> +ACOUSTIC_MODEL_PATH=<path_of_pretrained_acoustic_model> +LAYER=<layer_of_acoustic_model_to_extract_features_from> +KM_MODEL_PATH=<output_path_of_the_kmeans_model> +TTS_MODEL_PATH=<unit2speech_model_file_path> +WAVEGLOW_PATH=<path_where_you_have_downloaded_waveglow_checkpoint> + +PYTHONPATH=${FAIRSEQ_ROOT}:${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/unit2speech python ${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/tools/gen_speech.py \ + --feature_type $TYPE \ + --acoustic_model_path $ACOUSTIC_MODEL_PATH \ + --layer $LAYER \ + --kmeans_model_path $KM_MODEL_PATH \ + --tts_model_path $TTS_MODEL_PATH \ + --waveglow_path $WAVEGLOW_PATH \ + --max_decoder_steps 2000 +``` \ No newline at end of file diff --git a/examples/textless_nlp/gslm/tools/resynthesize_speech.py b/examples/textless_nlp/gslm/tools/resynthesize_speech.py new file mode 100644 index 0000000000..2b6215d372 --- /dev/null +++ b/examples/textless_nlp/gslm/tools/resynthesize_speech.py @@ -0,0 +1,138 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import gc +import logging + +import joblib +import soundfile as sf +import torch +from examples.textless_nlp.gslm.speech2unit.pretrained.utils import ( + get_feature_reader, +) +from examples.textless_nlp.gslm.unit2speech.tts_data import ( + TacotronInputDataset, +) +from examples.textless_nlp.gslm.unit2speech.utils import ( + load_tacotron, + load_waveglow, + synthesize_audio, +) + + +def get_logger(): + log_format = "[%(asctime)s] [%(levelname)s]: %(message)s" + logging.basicConfig(format=log_format, level=logging.INFO) + logger = logging.getLogger(__name__) + return logger + + +def get_parser(): + parser = argparse.ArgumentParser( + description="GSLM speech resynthesis tool." + ) + parser.add_argument( + "--feature_type", + type=str, + choices=["logmel", "hubert", "w2v2", "cpc"], + default=None, + required=True, + help="Acoustic feature type", + ) + parser.add_argument( + "--acoustic_model_path", + type=str, + help="Pretrained acoustic model checkpoint", + ) + parser.add_argument( + "--layer", type=int, help="Layer of acoustic model" + ) + parser.add_argument( + "--kmeans_model_path", + type=str, + required=True, + help="K-means model file path to use for inference", + ) + parser.add_argument( + "--tts_model_path", + type=str, + help="TTS model file path to use for inference", + ) + parser.add_argument( + "--waveglow_path", + type=str, + help="Waveglow (vocoder) model file path to use for inference", + ) + parser.add_argument("--max_decoder_steps", type=int, default=2000) + parser.add_argument("--denoiser_strength", type=float, default=0.1) + return parser + + +################################################ +def main(args, logger): + # Acoustic Model + logger.info(f"Loading acoustic model from {args.tts_model_path}...") + feature_reader_cls = get_feature_reader(args.feature_type) + reader = feature_reader_cls( + checkpoint_path=args.acoustic_model_path, layer=args.layer + ) + + # K-means Model + logger.info(f"Loading K-means model from {args.kmeans_model_path} ...") + kmeans_model = joblib.load(open(args.kmeans_model_path, "rb")) + kmeans_model.verbose = False + + # TTS Model + logger.info(f"Loading TTS model from {args.tts_model_path}...") + tacotron_model, sample_rate, hparams = load_tacotron( + tacotron_model_path=args.tts_model_path, + max_decoder_steps=args.max_decoder_steps, + ) + + # Waveglow Model + logger.info(f"Loading Waveglow model from {args.waveglow_path}...") + waveglow, denoiser = load_waveglow(waveglow_path=args.waveglow_path) + + # Dataset + tts_dataset = TacotronInputDataset(hparams) + + iters = 0 + while True: + in_file_path = input( + "Input: Enter the full file path of audio file...\n" + ) + out_file_path = input( + "Output: Enter the full file path of audio file...\n" + ) + feats = reader.get_feats(in_file_path).cpu().numpy() + iters += 1 + if iters == 1000: + gc.collect() + torch.cuda.empty_cache() + + quantized_units = kmeans_model.predict(feats) + quantized_units_str = " ".join(map(str, quantized_units)) + + tts_input = tts_dataset.get_tensor(quantized_units_str) + mel, aud, aud_dn, has_eos = synthesize_audio( + tacotron_model, + waveglow, + denoiser, + tts_input.unsqueeze(0), + strength=args.denoiser_strength, + ) + sf.write( + f"{out_file_path}", aud_dn[0].cpu().float().numpy(), sample_rate + ) + logger.info("Resynthesis done!\n") + + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + logger = get_logger() + logger.info(args) + main(args, logger) diff --git a/examples/textless_nlp/gslm/ulm/README.md b/examples/textless_nlp/gslm/ulm/README.md new file mode 100644 index 0000000000..01459121ce --- /dev/null +++ b/examples/textless_nlp/gslm/ulm/README.md @@ -0,0 +1,72 @@ +# Unit Language Model (ULM) + +Here you can find links to the pre-trained ULMs and instructions on training new models using fairseq. At the end of the page, we also share how to run sampling for those models and provide pointers to the transcribed prompts we used. + +## Pre-trained models + +Using the links below, you can download pre-trained models for various unit types and vocabulary sizes: + +| | 50 | 100 | 200 +|-|-|-|- +| LogMel Filterbank | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/lm_km50/logmel50_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/lm_km100/logmel100_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/lm_km200/logmel200_lm.tgz) +| Modified CPC | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/lm_km50/cpc50_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/lm_km100/cpc100_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/lm_km200/cpc200_lm.tgz) +| HuBERT | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/lm_km50/hubert50_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/lm_km100/hubert100_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/lm_km200/hubert200_lm.tgz) +| Wav2Vec 2.0 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/lm_km50/w2v2_50_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/lm_km100/w2v2_100_lm.tgz) | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/lm_km200/w2v2_200_lm.tgz) + + +## Preprocessing data +Assuming that unit-transcribed train, valid, and test sets are located in `data/train.txt`, `data/valid.txt`, and `data/test.txt`, respectively, +we run the following command to get a preprocessed version of the datast in `data-bin`: + +```bash +fairseq-preprocess --only-source \ + --trainpref data/train.txt --validpref data/valid.txt --testpref data/test.txt \ + --destdir data-bin/ --workers 40 +``` +As a result, the `data-bin` directory should appear. + +## Fitting a Unit Language Model (ULM) +As an ULM, we train a standard fairseq Transformer LM. Assuming 8 GPUs used for training, a good starting point for an ULM training would be: +```bash + fairseq-train data-bin/ \ + --task=language_modeling \ + --arch=transformer_lm_big \ + --share-decoder-input-output-embed \ + --dropout=0.1 \ + --attention-dropout=0.1 \ + --optimizer=adam \ + --adam-betas='(0.9, 0.98)' \ + --clip-norm=1.0 \ + --lr=0.0005 \ + --lr-scheduler=inverse_sqrt \ + --warmup-updates=4000 \ + --warmup-init-lr=1e-07 \ + --tokens-per-sample=3072 \ + --update-freq=16 \ + --max-tokens=4096 \ + --num-workers=4 \ + --skip-invalid-size-inputs-valid-test \ + --max-update=500000 \ + --log-interval=10 \ + --seed=100501 \ + --fp16 \ + --sample-break-mode=eos +``` +This command will train a Transformer-large model (12 layers). You can train other standard LM models provided by fairseq, e.g. specify `--arch=transformer_lm` to train a smaller (6-layer) Transformer model. When training with a different number of GPUs, it might be a good idea to adjust the `update-freq` parameter. To save the GPU memory at an expense of additional computation, it can be useful to enable activation checkpointing with `--checkpoint-activations`. + +## Sampling from an ULM +Once an ULM was trained, we can use it for generating new utterances. Suppose, that the prompts are given in a file named `prompts.txt`. Then we can sample continuations by running the following command: + +```bash + python sample.py data-bin/ \ + --path=checkpoints/checkpoint_best.pt --task=language_modeling --sampling --temperature=0.7 \ + --seed=1 --prompts=prompts.txt --output=samples.txt --max-len-a=0 --max-len-b=500 \ + --prefix-size=-1 --batch-size=16 --fp16 --samples-per-prompt=10 +``` +Here, `--prefix-size` controls the number of tokens that are used to prime the ULM. When set to a positive value, the sampling script will take first `prefix-size` tokens to prompt the ULM; with `0` it runs unconditional sampling and with `-1` the entire prompt is used. +`--samples-per-prompt` specifies how many utterances are generated with every prompt which can be useful when generating multiple prompt continuations. In this command, `--max-len-a` and `--max-len-b` control the number of generated tokens. + +When using a pretrained model from above, `data-bin` should point to the unpacked directory (with `dict.txt` file). + +Evaluation-time, to generate prompts, we used utterances from LibriSpeech dev-clean and test-clean that are longer than 6s. We took first 3s from an utterance as a prompt. Unit transcripts of those prompts can be downloaded here: [[dev]](https://dl.fbaipublicfiles.com/textless_nlp/gslm/eval_data/dev_prompts.tgz) [[test]](https://dl.fbaipublicfiles.com/textless_nlp/gslm/eval_data/test_prompts.tgz) + diff --git a/examples/textless_nlp/gslm/ulm/sample.py b/examples/textless_nlp/gslm/ulm/sample.py new file mode 100644 index 0000000000..77302a6894 --- /dev/null +++ b/examples/textless_nlp/gslm/ulm/sample.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +""" +Sample from a trained LM; hacked fairseq-interactive +""" +from collections import namedtuple +import os +import ast +import numpy as np + +from fairseq import checkpoint_utils, options, tasks, utils + +import tqdm + +Batch = namedtuple('Batch', 'ids src_tokens src_lengths') +Translation = namedtuple('Translation', 'src_str hypos pos_scores alignments') + + +def make_batches(lines, args, task, max_positions): + tokens = [ + task.source_dictionary.encode_line( + src_str, add_if_not_exist=False + ).long() + for src_str in lines + ] + lengths = [t.numel() for t in tokens] + itr = task.get_batch_iterator( + dataset=task.build_dataset_for_inference(tokens, lengths), + max_tokens=args.dataset.max_tokens, + max_sentences=args.dataset.batch_size, + max_positions=max_positions, + ignore_invalid_inputs=args.dataset.skip_invalid_size_inputs_valid_test + ).next_epoch_itr(shuffle=False) + for batch in itr: + yield Batch( + ids=batch['id'], + src_tokens=batch['net_input']['src_tokens'], src_lengths=batch['net_input']['src_lengths'], + ) + + +def main(args): + arg_prompts = args.prompts + arg_output = args.output + arg_debug = args.debug + arg_sample_size = args.samples_per_prompt + + try: + from fairseq.dataclass.utils import convert_namespace_to_omegaconf + args = convert_namespace_to_omegaconf(args) + except: + pass + + # if args.max_tokens is None and args.max_sentences is None: + if args.common.seed is not None: + np.random.seed(args.common.seed) + utils.set_torch_seed(args.common.seed) + + if args.generation.sampling: + args.generation.nbest = args.generation.beam = arg_sample_size + + task = tasks.setup_task(args.task) + + overrides = ast.literal_eval(args.common_eval.model_overrides) + + models, _model_args = checkpoint_utils.load_model_ensemble( + args.common_eval.path.split(os.pathsep), + arg_overrides=overrides, + task=task, + suffix=getattr(args, "checkpoint_suffix", ""), + ) + + # Set dictionaries + src_dict = task.source_dictionary + tgt_dict = task.target_dictionary + + # Optimize ensemble for generation + for model in models: + model.prepare_for_inference_(args) + model.cuda() + + # Load alignment dictionary for unknown word replacement + # (None if no unknown word replacement, empty if no path to align dictionary) + align_dict = utils.load_align_dict(args.generation.replace_unk) + + max_positions = utils.resolve_max_positions( + task.max_positions(), + *[model.max_positions() for model in models] + ) + + output_file = open(arg_output, 'w') + + with open(arg_prompts, 'r') as fin: + lines = fin.readlines() + + split = [x.split('|', 1) for x in lines] + seq_id = [x[0] for x in split] + prompts = [x[1] for x in split] + + if args.generation.prefix_size >= 0: + prompts = [' '.join(l.split()[:args.generation.prefix_size]) + for l in prompts] + + if arg_debug: + prompts = prompts[:10] + + generator = task.build_generator(models, args.generation) + + start_id = 0 + pbar = tqdm.tqdm(total=len(prompts)) + for batch in make_batches(prompts, args, task, max_positions): + src_tokens = batch.src_tokens + src_lengths = batch.src_lengths + src_tokens = src_tokens.cuda() + src_lengths = src_lengths.cuda() + + sample = { + 'net_input': { + 'src_tokens': src_tokens, + 'src_lengths': src_lengths, + }, + } + + results = [] + translations = task.inference_step(generator, models, sample) + for i, (id, hypos) in enumerate(zip(batch.ids.tolist(), translations)): + src_tokens_i = utils.strip_pad(src_tokens[i], tgt_dict.pad()) + results.append((i + start_id, src_tokens_i, hypos)) + + # sort output to match input order + for id, src_tokens, hypos in sorted(results, key=lambda x: x[0]): + if src_dict is not None: + src_str = src_dict.string( + src_tokens, args.common_eval.post_process) + + # Process top predictions + for hypo_id, hypo in enumerate(hypos): + _hypo_tokens, hypo_str, _alignment = utils.post_process_prediction( + hypo_tokens=hypo['tokens'].int().cpu(), + src_str=src_str, + alignment=hypo['alignment'], + align_dict=align_dict, + tgt_dict=tgt_dict, + remove_bpe=args.common_eval.post_process, + ) + + detok_hypo_str = hypo_str + utterance = detok_hypo_str + print(f'{seq_id[id]}__{hypo_id}|{utterance}', file=output_file) + pbar.update(1) + start_id += len(results) + + # output_file.close() + + +def cli_main(): + parser = options.get_interactive_generation_parser() + parser.add_argument('--prompts', type=str, default=None, required=True) + parser.add_argument('--output', type=str, default=None, required=True) + parser.add_argument('--debug', action='store_true') + parser.add_argument('--samples-per-prompt', type=int, default=1) + + args = options.parse_args_and_arch(parser) + + np.random.seed(args.seed) + utils.set_torch_seed(args.seed) + + main(args) + + +if __name__ == '__main__': + cli_main() diff --git a/examples/textless_nlp/gslm/unit2speech/README.md b/examples/textless_nlp/gslm/unit2speech/README.md new file mode 100644 index 0000000000..5710423065 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/README.md @@ -0,0 +1,42 @@ +# Unit to Speech Model (unit2speech) + +Unit to speech model is modified Tacotron2 model that learns to synthesize speech from discrete speech units. All models are trained on quantized [LJSpeech](https://keithito.com/LJ-Speech-Dataset/). + +Upstream Units | Download Link +|-|- +Log Mel Filterbank + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km50/tts_checkpoint_best.pt) +Log Mel Filterbank + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km100/tts_checkpoint_best.pt) +Log Mel Filterbank + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km200/tts_checkpoint_best.pt) +Log Mel Filterbank + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km500/tts_checkpoint_best.pt) +Modified CPC + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km50/tts_checkpoint_best.pt) +Modified CPC + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km100/tts_checkpoint_best.pt) +Modified CPC + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km200/tts_checkpoint_best.pt) +Modified CPC + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km500/tts_checkpoint_best.pt) +HuBERT Base + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km50/tts_checkpoint_best.pt) +HuBERT Base + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km100/tts_checkpoint_best.pt) +HuBERT Base + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km200/tts_checkpoint_best.pt) +HuBERT Base + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km500/tts_checkpoint_best.pt) +wav2vec 2.0 Large + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km50/tts_checkpoint_best.pt) +wav2vec 2.0 Large + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km100/tts_checkpoint_best.pt) +wav2vec 2.0 Large + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km200/tts_checkpoint_best.pt) +wav2vec 2.0 Large + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km500/tts_checkpoint_best.pt) + +## Run inference using a unit2speech model +* Install librosa, unidecode and inflect using `pip install librosa, unidecode, inflect` +* Download [Waveglow checkpoint](https://dl.fbaipublicfiles.com/textless_nlp/gslm/waveglow_256channels_new.pt). This is the vocoder. + +Sample commnd to run inference using trained unit2speech models. Please note that the quantized audio to synthesized should be using the same units as the unit2speech model was trained with. +``` +FAIRSEQ_ROOT=<path_to_your_fairseq_repo_root> +TTS_MODEL_PATH=<unit2speech_model_file_path> +QUANTIZED_UNIT_PATH=<quantized_audio_file_path> +OUT_DIR=<dir_to_dump_synthesized_audio_files> +WAVEGLOW_PATH=<path_where_you_have_downloaded_waveglow_checkpoint> + +PYTHONPATH=${FAIRSEQ_ROOT}:${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/unit2speech python ${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py \ + --tts_model_path $TTS_MODEL_PATH \ + --quantized_unit_path $QUANTIZED_UNIT_PATH \ + --out_audio_dir $OUT_DIR \ + --waveglow_path $WAVEGLOW_PATH \ + --max_decoder_steps 2000 +``` \ No newline at end of file diff --git a/examples/textless_nlp/gslm/unit2speech/convert_to_16k.py b/examples/textless_nlp/gslm/unit2speech/convert_to_16k.py new file mode 100644 index 0000000000..2be848fcea --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/convert_to_16k.py @@ -0,0 +1,56 @@ +import os +import shlex +import subprocess +import progressbar +from time import time +from pathlib import Path + +def find_all_files(path_dir, extension): + out = [] + for root, dirs, filenames in os.walk(path_dir): + for f in filenames: + if f.endswith(extension): + out.append(((str(Path(f).stem)), os.path.join(root, f))) + return out + +def convert16k(inputfile, outputfile16k): + command = ('sox -c 1 -b 16 {} -t wav {} rate 16k'.format(inputfile, outputfile16k)) + subprocess.call(shlex.split(command)) + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description='Convert to wav 16k audio using sox.') + parser.add_argument('input_dir', type=str, + help='Path to the input dir.') + parser.add_argument('output_dir', type=str, + help='Path to the output dir.') + parser.add_argument('--extension', type=str, default='wav', + help='Audio file extension in the input. Default: mp3') + args = parser.parse_args() + + # Find all sequences + print(f"Finding all audio files with extension '{args.extension}' from {args.input_dir}...") + audio_files = find_all_files(args.input_dir, args.extension) + print(f"Done! Found {len(audio_files)} files.") + + # Convert to relative path + audio_files = [os.path.relpath(file[-1], start=args.input_dir) for file in audio_files] + + # Create all the directories needed + rel_dirs_set = set([os.path.dirname(file) for file in audio_files]) + for rel_dir in rel_dirs_set: + Path(os.path.join(args.output_dir, rel_dir)).mkdir(parents=True, exist_ok=True) + + # Converting wavs files + print("Converting the audio to wav files...") + bar = progressbar.ProgressBar(maxval=len(audio_files)) + bar.start() + start_time = time() + for index, file in enumerate(audio_files): + bar.update(index) + input_file = os.path.join(args.input_dir, file) + output_file = os.path.join(args.output_dir, os.path.splitext(file)[0]+".wav") + convert16k(input_file, output_file) + bar.finish() + print(f"...done {len(audio_files)} files in {time()-start_time} seconds.") \ No newline at end of file diff --git a/examples/textless_nlp/gslm/unit2speech/glow.py b/examples/textless_nlp/gslm/unit2speech/glow.py new file mode 100644 index 0000000000..7a7696403d --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/glow.py @@ -0,0 +1,311 @@ +# ***************************************************************************** +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the NVIDIA CORPORATION nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# ***************************************************************************** +import copy +import torch +from torch.autograd import Variable +import torch.nn.functional as F + + +@torch.jit.script +def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels): + n_channels_int = n_channels[0] + in_act = input_a+input_b + t_act = torch.tanh(in_act[:, :n_channels_int, :]) + s_act = torch.sigmoid(in_act[:, n_channels_int:, :]) + acts = t_act * s_act + return acts + + +class WaveGlowLoss(torch.nn.Module): + def __init__(self, sigma=1.0): + super(WaveGlowLoss, self).__init__() + self.sigma = sigma + + def forward(self, model_output): + z, log_s_list, log_det_W_list = model_output + for i, log_s in enumerate(log_s_list): + if i == 0: + log_s_total = torch.sum(log_s) + log_det_W_total = log_det_W_list[i] + else: + log_s_total = log_s_total + torch.sum(log_s) + log_det_W_total += log_det_W_list[i] + + loss = torch.sum(z*z)/(2*self.sigma*self.sigma) - log_s_total - log_det_W_total + return loss/(z.size(0)*z.size(1)*z.size(2)) + + +class Invertible1x1Conv(torch.nn.Module): + """ + The layer outputs both the convolution, and the log determinant + of its weight matrix. If reverse=True it does convolution with + inverse + """ + def __init__(self, c): + super(Invertible1x1Conv, self).__init__() + self.conv = torch.nn.Conv1d(c, c, kernel_size=1, stride=1, padding=0, + bias=False) + + # Sample a random orthonormal matrix to initialize weights + W = torch.qr(torch.FloatTensor(c, c).normal_())[0] + + # Ensure determinant is 1.0 not -1.0 + if torch.det(W) < 0: + W[:,0] = -1*W[:,0] + W = W.view(c, c, 1) + self.conv.weight.data = W + + def forward(self, z, reverse=False): + # shape + batch_size, group_size, n_of_groups = z.size() + + W = self.conv.weight.squeeze() + + if reverse: + if not hasattr(self, 'W_inverse'): + # Reverse computation + W_inverse = W.float().inverse() + W_inverse = Variable(W_inverse[..., None]) + if z.type() == 'torch.cuda.HalfTensor': + W_inverse = W_inverse.half() + self.W_inverse = W_inverse + z = F.conv1d(z, self.W_inverse, bias=None, stride=1, padding=0) + return z + else: + # Forward computation + log_det_W = batch_size * n_of_groups * torch.logdet(W) + z = self.conv(z) + return z, log_det_W + + +class WN(torch.nn.Module): + """ + This is the WaveNet like layer for the affine coupling. The primary difference + from WaveNet is the convolutions need not be causal. There is also no dilation + size reset. The dilation only doubles on each layer + """ + def __init__(self, n_in_channels, n_mel_channels, n_layers, n_channels, + kernel_size): + super(WN, self).__init__() + assert(kernel_size % 2 == 1) + assert(n_channels % 2 == 0) + self.n_layers = n_layers + self.n_channels = n_channels + self.in_layers = torch.nn.ModuleList() + self.res_skip_layers = torch.nn.ModuleList() + + start = torch.nn.Conv1d(n_in_channels, n_channels, 1) + start = torch.nn.utils.weight_norm(start, name='weight') + self.start = start + + # Initializing last layer to 0 makes the affine coupling layers + # do nothing at first. This helps with training stability + end = torch.nn.Conv1d(n_channels, 2*n_in_channels, 1) + end.weight.data.zero_() + end.bias.data.zero_() + self.end = end + + cond_layer = torch.nn.Conv1d(n_mel_channels, 2*n_channels*n_layers, 1) + self.cond_layer = torch.nn.utils.weight_norm(cond_layer, name='weight') + + for i in range(n_layers): + dilation = 2 ** i + padding = int((kernel_size*dilation - dilation)/2) + in_layer = torch.nn.Conv1d(n_channels, 2*n_channels, kernel_size, + dilation=dilation, padding=padding) + in_layer = torch.nn.utils.weight_norm(in_layer, name='weight') + self.in_layers.append(in_layer) + + + # last one is not necessary + if i < n_layers - 1: + res_skip_channels = 2*n_channels + else: + res_skip_channels = n_channels + res_skip_layer = torch.nn.Conv1d(n_channels, res_skip_channels, 1) + res_skip_layer = torch.nn.utils.weight_norm(res_skip_layer, name='weight') + self.res_skip_layers.append(res_skip_layer) + + def forward(self, forward_input): + audio, spect = forward_input + audio = self.start(audio) + output = torch.zeros_like(audio) + n_channels_tensor = torch.IntTensor([self.n_channels]) + + spect = self.cond_layer(spect) + + for i in range(self.n_layers): + spect_offset = i*2*self.n_channels + acts = fused_add_tanh_sigmoid_multiply( + self.in_layers[i](audio), + spect[:,spect_offset:spect_offset+2*self.n_channels,:], + n_channels_tensor) + + res_skip_acts = self.res_skip_layers[i](acts) + if i < self.n_layers - 1: + audio = audio + res_skip_acts[:,:self.n_channels,:] + output = output + res_skip_acts[:,self.n_channels:,:] + else: + output = output + res_skip_acts + + return self.end(output) + + +class WaveGlow(torch.nn.Module): + def __init__(self, n_mel_channels, n_flows, n_group, n_early_every, + n_early_size, WN_config): + super(WaveGlow, self).__init__() + + self.upsample = torch.nn.ConvTranspose1d(n_mel_channels, + n_mel_channels, + 1024, stride=256) + assert(n_group % 2 == 0) + self.n_flows = n_flows + self.n_group = n_group + self.n_early_every = n_early_every + self.n_early_size = n_early_size + self.WN = torch.nn.ModuleList() + self.convinv = torch.nn.ModuleList() + + n_half = int(n_group/2) + + # Set up layers with the right sizes based on how many dimensions + # have been output already + n_remaining_channels = n_group + for k in range(n_flows): + if k % self.n_early_every == 0 and k > 0: + n_half = n_half - int(self.n_early_size/2) + n_remaining_channels = n_remaining_channels - self.n_early_size + self.convinv.append(Invertible1x1Conv(n_remaining_channels)) + self.WN.append(WN(n_half, n_mel_channels*n_group, **WN_config)) + self.n_remaining_channels = n_remaining_channels # Useful during inference + + def forward(self, forward_input): + """ + forward_input[0] = mel_spectrogram: batch x n_mel_channels x frames + forward_input[1] = audio: batch x time + """ + spect, audio = forward_input + + # Upsample spectrogram to size of audio + spect = self.upsample(spect) + assert(spect.size(2) >= audio.size(1)) + if spect.size(2) > audio.size(1): + spect = spect[:, :, :audio.size(1)] + + spect = spect.unfold(2, self.n_group, self.n_group).permute(0, 2, 1, 3) + spect = spect.contiguous().view(spect.size(0), spect.size(1), -1).permute(0, 2, 1) + + audio = audio.unfold(1, self.n_group, self.n_group).permute(0, 2, 1) + output_audio = [] + log_s_list = [] + log_det_W_list = [] + + for k in range(self.n_flows): + if k % self.n_early_every == 0 and k > 0: + output_audio.append(audio[:,:self.n_early_size,:]) + audio = audio[:,self.n_early_size:,:] + + audio, log_det_W = self.convinv[k](audio) + log_det_W_list.append(log_det_W) + + n_half = int(audio.size(1)/2) + audio_0 = audio[:,:n_half,:] + audio_1 = audio[:,n_half:,:] + + output = self.WN[k]((audio_0, spect)) + log_s = output[:, n_half:, :] + b = output[:, :n_half, :] + audio_1 = torch.exp(log_s)*audio_1 + b + log_s_list.append(log_s) + + audio = torch.cat([audio_0, audio_1],1) + + output_audio.append(audio) + return torch.cat(output_audio,1), log_s_list, log_det_W_list + + def infer(self, spect, sigma=1.0): + spect = self.upsample(spect) + # trim conv artifacts. maybe pad spec to kernel multiple + time_cutoff = self.upsample.kernel_size[0] - self.upsample.stride[0] + spect = spect[:, :, :-time_cutoff] + + spect = spect.unfold(2, self.n_group, self.n_group).permute(0, 2, 1, 3) + spect = spect.contiguous().view(spect.size(0), spect.size(1), -1).permute(0, 2, 1) + + if spect.type() == 'torch.cuda.HalfTensor': + audio = torch.cuda.HalfTensor(spect.size(0), + self.n_remaining_channels, + spect.size(2)).normal_() + else: + audio = torch.cuda.FloatTensor(spect.size(0), + self.n_remaining_channels, + spect.size(2)).normal_() + + audio = torch.autograd.Variable(sigma*audio) + + for k in reversed(range(self.n_flows)): + n_half = int(audio.size(1)/2) + audio_0 = audio[:,:n_half,:] + audio_1 = audio[:,n_half:,:] + + output = self.WN[k]((audio_0, spect)) + + s = output[:, n_half:, :] + b = output[:, :n_half, :] + audio_1 = (audio_1 - b)/torch.exp(s) + audio = torch.cat([audio_0, audio_1],1) + + audio = self.convinv[k](audio, reverse=True) + + if k % self.n_early_every == 0 and k > 0: + if spect.type() == 'torch.cuda.HalfTensor': + z = torch.cuda.HalfTensor(spect.size(0), self.n_early_size, spect.size(2)).normal_() + else: + z = torch.cuda.FloatTensor(spect.size(0), self.n_early_size, spect.size(2)).normal_() + audio = torch.cat((sigma*z, audio),1) + + audio = audio.permute(0,2,1).contiguous().view(audio.size(0), -1).data + return audio + + @staticmethod + def remove_weightnorm(model): + waveglow = model + for WN in waveglow.WN: + WN.start = torch.nn.utils.remove_weight_norm(WN.start) + WN.in_layers = remove(WN.in_layers) + WN.cond_layer = torch.nn.utils.remove_weight_norm(WN.cond_layer) + WN.res_skip_layers = remove(WN.res_skip_layers) + return waveglow + + +def remove(conv_list): + new_conv_list = torch.nn.ModuleList() + for old_conv in conv_list: + old_conv = torch.nn.utils.remove_weight_norm(old_conv) + new_conv_list.append(old_conv) + return new_conv_list diff --git a/examples/textless_nlp/gslm/unit2speech/multiproc.py b/examples/textless_nlp/gslm/unit2speech/multiproc.py new file mode 100644 index 0000000000..2a287a4e97 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/multiproc.py @@ -0,0 +1,27 @@ +import os +import time +import torch +import sys +import subprocess + +argslist = list(sys.argv)[1:] +log_dir = argslist[-1] +num_gpus = torch.cuda.device_count() +argslist.append('--n_gpus={}'.format(num_gpus)) +workers = [] +job_id = time.strftime("%Y_%m_%d-%H%M%S") +argslist.append("--group_name=group_{}".format(job_id)) + +print("GPU log directory is {}".format(log_dir)) +os.makedirs(log_dir, exist_ok=True) +for i in range(num_gpus): + argslist.append('--rank={}'.format(i)) + stdout = None if i == 0 else open("{}/{}_GPU_{}.log".format(log_dir, job_id, i), + "w") + print(argslist) + p = subprocess.Popen([str(sys.executable)]+argslist, stdout=stdout) + workers.append(p) + argslist = argslist[:-1] + +for p in workers: + p.wait() diff --git a/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py b/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py new file mode 100644 index 0000000000..f226d5f505 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py @@ -0,0 +1,97 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import os + +import soundfile as sf +from examples.textless_nlp.gslm.unit2speech.tts_data import ( + TacotronInputDataset, +) +from examples.textless_nlp.gslm.unit2speech.utils import ( + load_quantized_audio_from_file, + load_tacotron, + load_waveglow, + synthesize_audio, +) + + +def get_logger(): + log_format = "[%(asctime)s] [%(levelname)s]: %(message)s" + logging.basicConfig(format=log_format, level=logging.INFO) + logger = logging.getLogger(__name__) + return logger + + +def get_parser(): + parser = argparse.ArgumentParser( + description="Wav2Vec 2.0 speech generator." + ) + parser.add_argument( + "--quantized_unit_path", + type=str, + help="K-means model file path to use for inference", + ) + parser.add_argument( + "--tts_model_path", + type=str, + help="TTS model file path to use for inference", + ) + parser.add_argument( + "--waveglow_path", + type=str, + help="Path to the waveglow checkpoint (vocoder).", + ) + parser.add_argument("--max_decoder_steps", type=int, default=2000) + parser.add_argument("--denoiser_strength", type=float, default=0.1) + parser.add_argument( + "--out_audio_dir", + type=str, + help="Output directory to dump audio files", + ) + + return parser + + +def main(args, logger): + # Load quantized audio + logger.info(f"Loading quantized audio from {args.quantized_unit_path}...") + names_batch, quantized_units_batch = load_quantized_audio_from_file( + file_path=args.quantized_unit_path + ) + + logger.info(f"Loading TTS model from {args.tts_model_path}...") + tacotron_model, sample_rate, hparams = load_tacotron( + tacotron_model_path=args.tts_model_path, + max_decoder_steps=args.max_decoder_steps, + ) + + logger.info(f"Loading Waveglow model from {args.waveglow_path}...") + waveglow, denoiser = load_waveglow(waveglow_path=args.waveglow_path) + + tts_dataset = TacotronInputDataset(hparams) + for name, quantized_units in zip(names_batch, quantized_units_batch): + quantized_units_str = " ".join(map(str, quantized_units)) + tts_input = tts_dataset.get_tensor(quantized_units_str) + mel, aud, aud_dn, has_eos = synthesize_audio( + tacotron_model, + waveglow, + denoiser, + tts_input.unsqueeze(0), + strength=args.denoiser_strength, + ) + out_file_path = os.path.join(args.out_audio_dir, f"{name}.wav") + sf.write( + f"{out_file_path}", aud_dn[0].cpu().float().numpy(), sample_rate + ) + + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + logger = get_logger() + logger.info(args) + main(args, logger) diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/__init__.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/audio_processing.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/audio_processing.py new file mode 100644 index 0000000000..b5af7f723e --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/audio_processing.py @@ -0,0 +1,93 @@ +import torch +import numpy as np +from scipy.signal import get_window +import librosa.util as librosa_util + + +def window_sumsquare(window, n_frames, hop_length=200, win_length=800, + n_fft=800, dtype=np.float32, norm=None): + """ + # from librosa 0.6 + Compute the sum-square envelope of a window function at a given hop length. + + This is used to estimate modulation effects induced by windowing + observations in short-time fourier transforms. + + Parameters + ---------- + window : string, tuple, number, callable, or list-like + Window specification, as in `get_window` + + n_frames : int > 0 + The number of analysis frames + + hop_length : int > 0 + The number of samples to advance between frames + + win_length : [optional] + The length of the window function. By default, this matches `n_fft`. + + n_fft : int > 0 + The length of each analysis frame. + + dtype : np.dtype + The data type of the output + + Returns + ------- + wss : np.ndarray, shape=`(n_fft + hop_length * (n_frames - 1))` + The sum-squared envelope of the window function + """ + if win_length is None: + win_length = n_fft + + n = n_fft + hop_length * (n_frames - 1) + x = np.zeros(n, dtype=dtype) + + # Compute the squared window at the desired length + win_sq = get_window(window, win_length, fftbins=True) + win_sq = librosa_util.normalize(win_sq, norm=norm)**2 + win_sq = librosa_util.pad_center(win_sq, n_fft) + + # Fill the envelope + for i in range(n_frames): + sample = i * hop_length + x[sample:min(n, sample + n_fft)] += win_sq[:max(0, min(n_fft, n - sample))] + return x + + +def griffin_lim(magnitudes, stft_fn, n_iters=30): + """ + PARAMS + ------ + magnitudes: spectrogram magnitudes + stft_fn: STFT class with transform (STFT) and inverse (ISTFT) methods + """ + + angles = np.angle(np.exp(2j * np.pi * np.random.rand(*magnitudes.size()))) + angles = angles.astype(np.float32) + angles = torch.autograd.Variable(torch.from_numpy(angles)) + signal = stft_fn.inverse(magnitudes, angles).squeeze(1) + + for i in range(n_iters): + _, angles = stft_fn.transform(signal) + signal = stft_fn.inverse(magnitudes, angles).squeeze(1) + return signal + + +def dynamic_range_compression(x, C=1, clip_val=1e-5): + """ + PARAMS + ------ + C: compression factor + """ + return torch.log(torch.clamp(x, min=clip_val) * C) + + +def dynamic_range_decompression(x, C=1): + """ + PARAMS + ------ + C: compression factor used to compress + """ + return torch.exp(x) / C diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/cleaners.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/cleaners.py new file mode 100644 index 0000000000..e2e35c1a8c --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/cleaners.py @@ -0,0 +1,90 @@ +""" from https://github.com/keithito/tacotron """ + +''' +Cleaners are transformations that run over the input text at both training and eval time. + +Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners" +hyperparameter. Some cleaners are English-specific. You'll typically want to use: + 1. "english_cleaners" for English text + 2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using + the Unidecode library (https://pypi.python.org/pypi/Unidecode) + 3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update + the symbols in symbols.py to match your data). +''' + +import re +from unidecode import unidecode +from .numbers import normalize_numbers + + +# Regular expression matching whitespace: +_whitespace_re = re.compile(r'\s+') + +# List of (regular expression, replacement) pairs for abbreviations: +_abbreviations = [(re.compile('\\b%s\\.' % x[0], re.IGNORECASE), x[1]) for x in [ + ('mrs', 'misess'), + ('mr', 'mister'), + ('dr', 'doctor'), + ('st', 'saint'), + ('co', 'company'), + ('jr', 'junior'), + ('maj', 'major'), + ('gen', 'general'), + ('drs', 'doctors'), + ('rev', 'reverend'), + ('lt', 'lieutenant'), + ('hon', 'honorable'), + ('sgt', 'sergeant'), + ('capt', 'captain'), + ('esq', 'esquire'), + ('ltd', 'limited'), + ('col', 'colonel'), + ('ft', 'fort'), +]] + + +def expand_abbreviations(text): + for regex, replacement in _abbreviations: + text = re.sub(regex, replacement, text) + return text + + +def expand_numbers(text): + return normalize_numbers(text) + + +def lowercase(text): + return text.lower() + + +def collapse_whitespace(text): + return re.sub(_whitespace_re, ' ', text) + + +def convert_to_ascii(text): + return unidecode(text) + + +def basic_cleaners(text): + '''Basic pipeline that lowercases and collapses whitespace without transliteration.''' + text = lowercase(text) + text = collapse_whitespace(text) + return text + + +def transliteration_cleaners(text): + '''Pipeline for non-English text that transliterates to ASCII.''' + text = convert_to_ascii(text) + text = lowercase(text) + text = collapse_whitespace(text) + return text + + +def english_cleaners(text): + '''Pipeline for English text, including number and abbreviation expansion.''' + text = convert_to_ascii(text) + text = lowercase(text) + text = expand_numbers(text) + text = expand_abbreviations(text) + text = collapse_whitespace(text) + return text diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/cmudict.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/cmudict.py new file mode 100644 index 0000000000..62bfef745c --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/cmudict.py @@ -0,0 +1,65 @@ +""" from https://github.com/keithito/tacotron """ + +import re + + +valid_symbols = [ + 'AA', 'AA0', 'AA1', 'AA2', 'AE', 'AE0', 'AE1', 'AE2', 'AH', 'AH0', 'AH1', 'AH2', + 'AO', 'AO0', 'AO1', 'AO2', 'AW', 'AW0', 'AW1', 'AW2', 'AY', 'AY0', 'AY1', 'AY2', + 'B', 'CH', 'D', 'DH', 'EH', 'EH0', 'EH1', 'EH2', 'ER', 'ER0', 'ER1', 'ER2', 'EY', + 'EY0', 'EY1', 'EY2', 'F', 'G', 'HH', 'IH', 'IH0', 'IH1', 'IH2', 'IY', 'IY0', 'IY1', + 'IY2', 'JH', 'K', 'L', 'M', 'N', 'NG', 'OW', 'OW0', 'OW1', 'OW2', 'OY', 'OY0', + 'OY1', 'OY2', 'P', 'R', 'S', 'SH', 'T', 'TH', 'UH', 'UH0', 'UH1', 'UH2', 'UW', + 'UW0', 'UW1', 'UW2', 'V', 'W', 'Y', 'Z', 'ZH' +] + +_valid_symbol_set = set(valid_symbols) + + +class CMUDict: + '''Thin wrapper around CMUDict data. http://www.speech.cs.cmu.edu/cgi-bin/cmudict''' + def __init__(self, file_or_path, keep_ambiguous=True): + if isinstance(file_or_path, str): + with open(file_or_path, encoding='latin-1') as f: + entries = _parse_cmudict(f) + else: + entries = _parse_cmudict(file_or_path) + if not keep_ambiguous: + entries = {word: pron for word, pron in entries.items() if len(pron) == 1} + self._entries = entries + + + def __len__(self): + return len(self._entries) + + + def lookup(self, word): + '''Returns list of ARPAbet pronunciations of the given word.''' + return self._entries.get(word.upper()) + + + +_alt_re = re.compile(r'\([0-9]+\)') + + +def _parse_cmudict(file): + cmudict = {} + for line in file: + if len(line) and (line[0] >= 'A' and line[0] <= 'Z' or line[0] == "'"): + parts = line.split(' ') + word = re.sub(_alt_re, '', parts[0]) + pronunciation = _get_pronunciation(parts[1]) + if pronunciation: + if word in cmudict: + cmudict[word].append(pronunciation) + else: + cmudict[word] = [pronunciation] + return cmudict + + +def _get_pronunciation(s): + parts = s.strip().split(' ') + for part in parts: + if part not in _valid_symbol_set: + return None + return ' '.join(parts) diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/layers.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/layers.py new file mode 100644 index 0000000000..f10d557ff5 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/layers.py @@ -0,0 +1,103 @@ +import torch +from librosa.filters import mel as librosa_mel_fn +from .audio_processing import dynamic_range_compression +from .audio_processing import dynamic_range_decompression +from .stft import STFT +from .utils import get_mask_from_lengths + + +class LinearNorm(torch.nn.Module): + def __init__(self, in_dim, out_dim, bias=True, w_init_gain='linear'): + super(LinearNorm, self).__init__() + self.linear_layer = torch.nn.Linear(in_dim, out_dim, bias=bias) + + torch.nn.init.xavier_uniform_( + self.linear_layer.weight, + gain=torch.nn.init.calculate_gain(w_init_gain)) + + def forward(self, x): + return self.linear_layer(x) + + +class ConvNorm(torch.nn.Module): + def __init__(self, in_channels, out_channels, kernel_size=1, stride=1, + padding=None, dilation=1, bias=True, w_init_gain='linear'): + super(ConvNorm, self).__init__() + if padding is None: + assert(kernel_size % 2 == 1) + padding = int(dilation * (kernel_size - 1) / 2) + + self.conv = torch.nn.Conv1d(in_channels, out_channels, + kernel_size=kernel_size, stride=stride, + padding=padding, dilation=dilation, + bias=bias) + + torch.nn.init.xavier_uniform_( + self.conv.weight, gain=torch.nn.init.calculate_gain(w_init_gain)) + + def forward(self, signal): + conv_signal = self.conv(signal) + return conv_signal + + +class GlobalAvgPool(torch.nn.Module): + def __init__(self): + super(GlobalAvgPool, self).__init__() + + def forward(self, x, lengths=None): + """Average pooling across time steps (dim=1) with optionally lengths. + Args: + x: torch.Tensor of shape (N, T, ...) + lengths: None or torch.Tensor of shape (N,) + dim: dimension to pool + """ + if lengths is None: + return x.mean(dim=1, keepdim=False) + else: + mask = get_mask_from_lengths(lengths).type(x.type()).to(x.device) + mask_shape = list(mask.size()) + [1 for _ in range(x.ndimension()-2)] + mask = mask.reshape(*mask_shape) + numer = (x * mask).sum(dim=1, keepdim=False) + denom = mask.sum(dim=1, keepdim=False) + return numer / denom + + +class TacotronSTFT(torch.nn.Module): + def __init__(self, filter_length=1024, hop_length=256, win_length=1024, + n_mel_channels=80, sampling_rate=22050, mel_fmin=0.0, + mel_fmax=8000.0): + super(TacotronSTFT, self).__init__() + self.n_mel_channels = n_mel_channels + self.sampling_rate = sampling_rate + self.stft_fn = STFT(filter_length, hop_length, win_length) + mel_basis = librosa_mel_fn( + sampling_rate, filter_length, n_mel_channels, mel_fmin, mel_fmax) + mel_basis = torch.from_numpy(mel_basis).float() + self.register_buffer('mel_basis', mel_basis) + + def spectral_normalize(self, magnitudes): + output = dynamic_range_compression(magnitudes) + return output + + def spectral_de_normalize(self, magnitudes): + output = dynamic_range_decompression(magnitudes) + return output + + def mel_spectrogram(self, y): + """Computes mel-spectrograms from a batch of waves + PARAMS + ------ + y: Variable(torch.FloatTensor) with shape (B, T) in range [-1, 1] + + RETURNS + ------- + mel_output: torch.FloatTensor of shape (B, n_mel_channels, T) + """ + assert(torch.min(y.data) >= -1) + assert(torch.max(y.data) <= 1) + + magnitudes, phases = self.stft_fn.transform(y) + magnitudes = magnitudes.data + mel_output = torch.matmul(self.mel_basis, magnitudes) + mel_output = self.spectral_normalize(mel_output) + return mel_output diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/model.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/model.py new file mode 100644 index 0000000000..ccf132b150 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/model.py @@ -0,0 +1,669 @@ +from math import sqrt +import torch +import torch.distributions as distr +from torch.autograd import Variable +from torch import nn +from torch.nn import functional as F +from .layers import ConvNorm, LinearNorm, GlobalAvgPool +from .utils import to_gpu, get_mask_from_lengths + + +class LocationLayer(nn.Module): + def __init__(self, attention_n_filters, attention_kernel_size, + attention_dim): + super(LocationLayer, self).__init__() + padding = int((attention_kernel_size - 1) / 2) + self.location_conv = ConvNorm(2, attention_n_filters, + kernel_size=attention_kernel_size, + padding=padding, bias=False, stride=1, + dilation=1) + self.location_dense = LinearNorm(attention_n_filters, attention_dim, + bias=False, w_init_gain='tanh') + + def forward(self, attention_weights_cat): + processed_attention = self.location_conv(attention_weights_cat) + processed_attention = processed_attention.transpose(1, 2) + processed_attention = self.location_dense(processed_attention) + return processed_attention + + +class Attention(nn.Module): + def __init__(self, attention_rnn_dim, embedding_dim, attention_dim, + attention_location_n_filters, attention_location_kernel_size): + super(Attention, self).__init__() + self.query_layer = LinearNorm(attention_rnn_dim, attention_dim, + bias=False, w_init_gain='tanh') + self.memory_layer = LinearNorm(embedding_dim, attention_dim, bias=False, + w_init_gain='tanh') + self.v = LinearNorm(attention_dim, 1, bias=False) + self.location_layer = LocationLayer(attention_location_n_filters, + attention_location_kernel_size, + attention_dim) + self.score_mask_value = -float("inf") + + def get_alignment_energies(self, query, processed_memory, + attention_weights_cat): + """ + PARAMS + ------ + query: decoder output (batch, n_mel_channels * n_frames_per_step) + processed_memory: processed encoder outputs (B, T_in, attention_dim) + attention_weights_cat: cumulative and prev. att weights (B, 2, max_time) + + RETURNS + ------- + alignment (batch, max_time) + """ + + processed_query = self.query_layer(query.unsqueeze(1)) + processed_attention_weights = self.location_layer(attention_weights_cat) + energies = self.v(torch.tanh( + processed_query + processed_attention_weights + processed_memory)) + + energies = energies.squeeze(-1) + return energies + + def forward(self, attention_hidden_state, memory, processed_memory, + attention_weights_cat, mask): + """ + PARAMS + ------ + attention_hidden_state: attention rnn last output + memory: encoder outputs + processed_memory: processed encoder outputs + attention_weights_cat: previous and cummulative attention weights + mask: binary mask for padded data + """ + alignment = self.get_alignment_energies( + attention_hidden_state, processed_memory, attention_weights_cat) + + if mask is not None: + alignment.data.masked_fill_(mask, self.score_mask_value) + + attention_weights = F.softmax(alignment, dim=1) + attention_context = torch.bmm(attention_weights.unsqueeze(1), memory) + attention_context = attention_context.squeeze(1) + + return attention_context, attention_weights + + +class Prenet(nn.Module): + def __init__(self, in_dim, sizes): + super(Prenet, self).__init__() + in_sizes = [in_dim] + sizes[:-1] + self.layers = nn.ModuleList( + [LinearNorm(in_size, out_size, bias=False) + for (in_size, out_size) in zip(in_sizes, sizes)]) + + def forward(self, x): + for linear in self.layers: + x = F.dropout(F.relu(linear(x)), p=0.5, training=True) + return x + + +class Postnet(nn.Module): + """Postnet + - Five 1-d convolution with 512 channels and kernel size 5 + """ + + def __init__(self, hparams): + super(Postnet, self).__init__() + self.convolutions = nn.ModuleList() + + self.convolutions.append( + nn.Sequential( + ConvNorm(hparams.n_mel_channels, hparams.postnet_embedding_dim, + kernel_size=hparams.postnet_kernel_size, stride=1, + padding=int((hparams.postnet_kernel_size - 1) / 2), + dilation=1, w_init_gain='tanh'), + nn.BatchNorm1d(hparams.postnet_embedding_dim)) + ) + + for i in range(1, hparams.postnet_n_convolutions - 1): + self.convolutions.append( + nn.Sequential( + ConvNorm(hparams.postnet_embedding_dim, + hparams.postnet_embedding_dim, + kernel_size=hparams.postnet_kernel_size, stride=1, + padding=int((hparams.postnet_kernel_size - 1) / 2), + dilation=1, w_init_gain='tanh'), + nn.BatchNorm1d(hparams.postnet_embedding_dim)) + ) + + self.convolutions.append( + nn.Sequential( + ConvNorm(hparams.postnet_embedding_dim, hparams.n_mel_channels, + kernel_size=hparams.postnet_kernel_size, stride=1, + padding=int((hparams.postnet_kernel_size - 1) / 2), + dilation=1, w_init_gain='linear'), + nn.BatchNorm1d(hparams.n_mel_channels)) + ) + + def forward(self, x): + for i in range(len(self.convolutions) - 1): + x = F.dropout(torch.tanh(self.convolutions[i](x)), 0.5, self.training) + x = F.dropout(self.convolutions[-1](x), 0.5, self.training) + + return x + + +class Encoder(nn.Module): + """Encoder module: + - Three 1-d convolution banks + - Bidirectional LSTM + """ + def __init__(self, hparams): + super(Encoder, self).__init__() + + convolutions = [] + for _ in range(hparams.encoder_n_convolutions): + conv_layer = nn.Sequential( + ConvNorm(hparams.encoder_embedding_dim, + hparams.encoder_embedding_dim, + kernel_size=hparams.encoder_kernel_size, stride=1, + padding=int((hparams.encoder_kernel_size - 1) / 2), + dilation=1, w_init_gain='relu'), + nn.BatchNorm1d(hparams.encoder_embedding_dim)) + convolutions.append(conv_layer) + self.convolutions = nn.ModuleList(convolutions) + + self.lstm = nn.LSTM(hparams.encoder_embedding_dim, + int(hparams.encoder_embedding_dim / 2), 1, + batch_first=True, bidirectional=True) + + def forward(self, x, input_lengths): + for conv in self.convolutions: + x = F.dropout(F.relu(conv(x)), 0.5, self.training) + + x = x.transpose(1, 2) + + # pytorch tensor are not reversible, hence the conversion + input_lengths = input_lengths.cpu().numpy() + x = nn.utils.rnn.pack_padded_sequence( + x, input_lengths, batch_first=True) + + self.lstm.flatten_parameters() + outputs, _ = self.lstm(x) + + outputs, _ = nn.utils.rnn.pad_packed_sequence( + outputs, batch_first=True) + + return outputs + + def inference(self, x): + for conv in self.convolutions: + x = F.dropout(F.relu(conv(x)), 0.5, self.training) + + x = x.transpose(1, 2) + + self.lstm.flatten_parameters() + outputs, _ = self.lstm(x) + + return outputs + + +class AudioEncoder(nn.Module): + def __init__(self, hparams): + super(AudioEncoder, self).__init__() + + assert hparams.lat_dim > 0 + + convolutions = [] + inp_dim = hparams.n_mel_channels + for _ in range(hparams.lat_n_convolutions): + conv_layer = nn.Sequential( + ConvNorm(inp_dim, hparams.lat_n_filters, + kernel_size=hparams.lat_kernel_size, stride=1, + padding=int((hparams.lat_kernel_size - 1) / 2), + dilation=1, w_init_gain='tanh'), + nn.BatchNorm1d(hparams.lat_n_filters)) + inp_dim = hparams.lat_n_filters + convolutions.append(conv_layer) + self.convolutions = nn.ModuleList(convolutions) + + self.lstm = nn.LSTM(hparams.lat_n_filters, + int(hparams.lat_n_filters / 2), + hparams.lat_n_blstms, batch_first=True, + bidirectional=True) + self.pool = GlobalAvgPool() + + self.mu_proj = LinearNorm(hparams.lat_n_filters, hparams.lat_dim) + self.logvar_proj = LinearNorm(hparams.lat_n_filters, hparams.lat_dim) + self.lat_dim = hparams.lat_dim + + def forward(self, x, lengths): + """ + Args: + x (torch.Tensor): (B, F, T) + """ + + for conv in self.convolutions: + x = F.dropout(F.tanh(conv(x)), 0.5, self.training) + + x = x.transpose(1, 2) # (B, T, D) + + # x may not be sorted by length. Sort->process->unsort + max_len = x.size(1) + assert max_len == torch.max(lengths).item() + + lengths, perm_idx = lengths.sort(0, descending=True) + x = x[perm_idx] + x = nn.utils.rnn.pack_padded_sequence(x, lengths, batch_first=True) + + self.lstm.flatten_parameters() + outputs, _ = self.lstm(x) + outputs, _ = nn.utils.rnn.pad_packed_sequence(outputs, batch_first=True) + + _, unperm_idx = perm_idx.sort(0) + outputs = outputs[unperm_idx] # (B, T, D) + lengths = lengths[unperm_idx] # (B, T, D) + + outputs = self.pool(outputs, lengths) # (B, D) + + mu = self.mu_proj(outputs) + logvar = self.logvar_proj(outputs) + z = distr.Normal(mu, logvar).rsample() + return z, mu, logvar + + +class Decoder(nn.Module): + def __init__(self, hparams): + super(Decoder, self).__init__() + self.n_mel_channels = hparams.n_mel_channels + self.n_frames_per_step = hparams.n_frames_per_step + self.encoder_embedding_dim = hparams.encoder_embedding_dim + self.obs_dim = hparams.obs_dim + self.lat_dim = hparams.lat_dim + self.attention_rnn_dim = hparams.attention_rnn_dim + self.decoder_rnn_dim = hparams.decoder_rnn_dim + self.prenet_dim = hparams.prenet_dim + self.max_decoder_steps = hparams.max_decoder_steps + self.gate_threshold = hparams.gate_threshold + self.p_attention_dropout = hparams.p_attention_dropout + self.p_decoder_dropout = hparams.p_decoder_dropout + + self.prenet = Prenet( + hparams.n_mel_channels * hparams.n_frames_per_step, + [hparams.prenet_dim, hparams.prenet_dim]) + + self.attention_rnn = nn.LSTMCell( + hparams.prenet_dim + hparams.encoder_embedding_dim, + hparams.attention_rnn_dim) + + self.attention_layer = Attention( + hparams.attention_rnn_dim, hparams.encoder_embedding_dim, + hparams.attention_dim, hparams.attention_location_n_filters, + hparams.attention_location_kernel_size) + + encoder_tot_dim = (hparams.encoder_embedding_dim + \ + hparams.lat_dim + hparams.obs_dim) + self.decoder_rnn = nn.LSTMCell( + hparams.attention_rnn_dim + encoder_tot_dim, + hparams.decoder_rnn_dim, 1) + + self.linear_projection = LinearNorm( + hparams.decoder_rnn_dim + encoder_tot_dim, + hparams.n_mel_channels * hparams.n_frames_per_step) + + self.gate_layer = LinearNorm( + hparams.decoder_rnn_dim + encoder_tot_dim, 1, + bias=True, w_init_gain='sigmoid') + + def get_go_frame(self, memory): + """ Gets all zeros frames to use as first decoder input + PARAMS + ------ + memory: decoder outputs + + RETURNS + ------- + decoder_input: all zeros frames + """ + B = memory.size(0) + decoder_input = Variable(memory.data.new( + B, self.n_mel_channels * self.n_frames_per_step).zero_()) + return decoder_input + + def initialize_decoder_states(self, memory, obs_and_lat, mask): + """ Initializes attention rnn states, decoder rnn states, attention + weights, attention cumulative weights, attention context, stores memory + and stores processed memory + PARAMS + ------ + memory: Encoder outputs + obs_and_lat: Observed and latent attribute embeddings + mask: Mask for padded data if training, expects None for inference + """ + B = memory.size(0) + MAX_TIME = memory.size(1) + + self.attention_hidden = Variable(memory.data.new( + B, self.attention_rnn_dim).zero_()) + self.attention_cell = Variable(memory.data.new( + B, self.attention_rnn_dim).zero_()) + + self.decoder_hidden = Variable(memory.data.new( + B, self.decoder_rnn_dim).zero_()) + self.decoder_cell = Variable(memory.data.new( + B, self.decoder_rnn_dim).zero_()) + + self.attention_weights = Variable(memory.data.new( + B, MAX_TIME).zero_()) + self.attention_weights_cum = Variable(memory.data.new( + B, MAX_TIME).zero_()) + self.attention_context = Variable(memory.data.new( + B, self.encoder_embedding_dim).zero_()) + + self.memory = memory + self.processed_memory = self.attention_layer.memory_layer(memory) + self.obs_and_lat = obs_and_lat + self.mask = mask + + def parse_decoder_inputs(self, decoder_inputs): + """ Prepares decoder inputs, i.e. mel outputs + PARAMS + ------ + decoder_inputs: inputs used for teacher-forced training, i.e. mel-specs + + RETURNS + ------- + inputs: processed decoder inputs + + """ + # (B, n_mel_channels, T_out) -> (B, T_out, n_mel_channels) + decoder_inputs = decoder_inputs.transpose(1, 2) + decoder_inputs = decoder_inputs.view( + decoder_inputs.size(0), + int(decoder_inputs.size(1)/self.n_frames_per_step), -1) + # (B, T_out, n_mel_channels) -> (T_out, B, n_mel_channels) + decoder_inputs = decoder_inputs.transpose(0, 1) + return decoder_inputs + + def parse_decoder_outputs(self, mel_outputs, gate_outputs, alignments): + """ Prepares decoder outputs for output + PARAMS + ------ + mel_outputs: + gate_outputs: gate output energies + alignments: + + RETURNS + ------- + mel_outputs: + gate_outpust: gate output energies + alignments: + """ + # (T_out, B) -> (B, T_out) + alignments = torch.stack(alignments).transpose(0, 1) + # (T_out, B) -> (B, T_out) + gate_outputs = torch.stack(gate_outputs).transpose(0, 1) + gate_outputs = gate_outputs.contiguous() + # (T_out, B, n_mel_channels) -> (B, T_out, n_mel_channels) + mel_outputs = torch.stack(mel_outputs).transpose(0, 1).contiguous() + # decouple frames per step + mel_outputs = mel_outputs.view( + mel_outputs.size(0), -1, self.n_mel_channels) + # (B, T_out, n_mel_channels) -> (B, n_mel_channels, T_out) + mel_outputs = mel_outputs.transpose(1, 2) + + return mel_outputs, gate_outputs, alignments + + def decode(self, decoder_input): + """ Decoder step using stored states, attention and memory + PARAMS + ------ + decoder_input: previous mel output + + RETURNS + ------- + mel_output: + gate_output: gate output energies + attention_weights: + """ + cell_input = torch.cat((decoder_input, self.attention_context), -1) + self.attention_hidden, self.attention_cell = self.attention_rnn( + cell_input, (self.attention_hidden, self.attention_cell)) + self.attention_hidden = F.dropout( + self.attention_hidden, self.p_attention_dropout, self.training) + + attention_weights_cat = torch.cat( + (self.attention_weights.unsqueeze(1), + self.attention_weights_cum.unsqueeze(1)), dim=1) + self.attention_context, self.attention_weights = self.attention_layer( + self.attention_hidden, self.memory, self.processed_memory, + attention_weights_cat, self.mask) + + self.attention_weights_cum += self.attention_weights + decoder_input = torch.cat( + (self.attention_hidden, self.attention_context), -1) + if self.obs_and_lat is not None: + decoder_input = torch.cat((decoder_input, self.obs_and_lat), -1) + self.decoder_hidden, self.decoder_cell = self.decoder_rnn( + decoder_input, (self.decoder_hidden, self.decoder_cell)) + self.decoder_hidden = F.dropout( + self.decoder_hidden, self.p_decoder_dropout, self.training) + + decoder_hidden_attention_context = torch.cat( + (self.decoder_hidden, self.attention_context), dim=1) + if self.obs_and_lat is not None: + decoder_hidden_attention_context = torch.cat( + (decoder_hidden_attention_context, self.obs_and_lat), dim=1) + decoder_output = self.linear_projection( + decoder_hidden_attention_context) + + gate_prediction = self.gate_layer(decoder_hidden_attention_context) + return decoder_output, gate_prediction, self.attention_weights + + def forward(self, memory, obs_and_lat, decoder_inputs, memory_lengths): + """ Decoder forward pass for training + PARAMS + ------ + memory: Encoder outputs + obs_and_lat: Observed and latent attribute embeddings + decoder_inputs: Decoder inputs for teacher forcing. i.e. mel-specs + memory_lengths: Encoder output lengths for attention masking. + + RETURNS + ------- + mel_outputs: mel outputs from the decoder + gate_outputs: gate outputs from the decoder + alignments: sequence of attention weights from the decoder + """ + + decoder_input = self.get_go_frame(memory).unsqueeze(0) + decoder_inputs = self.parse_decoder_inputs(decoder_inputs) + decoder_inputs = torch.cat((decoder_input, decoder_inputs), dim=0) + decoder_inputs = self.prenet(decoder_inputs) + + self.initialize_decoder_states( + memory, obs_and_lat, mask=~get_mask_from_lengths(memory_lengths)) + + mel_outputs, gate_outputs, alignments = [], [], [] + while len(mel_outputs) < decoder_inputs.size(0) - 1: + decoder_input = decoder_inputs[len(mel_outputs)] + mel_output, gate_output, attention_weights = self.decode( + decoder_input) + mel_outputs += [mel_output.squeeze(1)] + gate_outputs += [gate_output.squeeze()] + alignments += [attention_weights] + + mel_outputs, gate_outputs, alignments = self.parse_decoder_outputs( + mel_outputs, gate_outputs, alignments) + + return mel_outputs, gate_outputs, alignments + + def inference(self, memory, obs_and_lat, ret_has_eos=False): + """ Decoder inference + PARAMS + ------ + memory: Encoder outputs + obs_and_lat: Observed and latent attribute embeddings + + RETURNS + ------- + mel_outputs: mel outputs from the decoder + gate_outputs: gate outputs from the decoder + alignments: sequence of attention weights from the decoder + """ + decoder_input = self.get_go_frame(memory) + + self.initialize_decoder_states(memory, obs_and_lat, mask=None) + + mel_outputs, gate_outputs, alignments = [], [], [] + has_eos = False + while True: + decoder_input = self.prenet(decoder_input) + mel_output, gate_output, alignment = self.decode(decoder_input) + + mel_outputs += [mel_output.squeeze(1)] + gate_outputs += [gate_output] + alignments += [alignment] + + if torch.sigmoid(gate_output.data) > self.gate_threshold: + has_eos = True + break + elif len(mel_outputs) == self.max_decoder_steps: + # print("Warning! Reached max decoder steps") + break + + decoder_input = mel_output + + mel_outputs, gate_outputs, alignments = self.parse_decoder_outputs( + mel_outputs, gate_outputs, alignments) + + if ret_has_eos: + return mel_outputs, gate_outputs, alignments, has_eos + else: + return mel_outputs, gate_outputs, alignments + + +class Tacotron2(nn.Module): + def __init__(self, hparams): + super(Tacotron2, self).__init__() + self.mask_padding = hparams.mask_padding + self.fp16_run = hparams.fp16_run + self.n_mel_channels = hparams.n_mel_channels + self.n_frames_per_step = hparams.n_frames_per_step + + # initialize text encoder embedding + self.embedding = nn.Embedding( + hparams.n_symbols, hparams.symbols_embedding_dim) + std = sqrt(2.0 / (hparams.n_symbols + hparams.symbols_embedding_dim)) + val = sqrt(3.0) * std # uniform bounds for std + self.embedding.weight.data.uniform_(-val, val) + + # initialize observed attribute embedding + self.obs_embedding = None + if hparams.obs_dim > 0: + self.obs_embedding = nn.Embedding( + hparams.obs_n_class, hparams.obs_dim) + std = sqrt(2.0 / (hparams.obs_n_class + hparams.obs_dim)) + val = sqrt(3.0) * std # uniform bounds for std + self.obs_embedding.weight.data.uniform_(-val, val) + + self.encoder = Encoder(hparams) + self.decoder = Decoder(hparams) + self.postnet = Postnet(hparams) + + self.lat_encoder = None + if hparams.lat_dim > 0: + self.lat_encoder = AudioEncoder(hparams) + + def parse_batch(self, batch): + (text_padded, input_lengths, obs_labels, + mel_padded, gate_padded, output_lengths) = batch + text_padded = to_gpu(text_padded).long() + input_lengths = to_gpu(input_lengths).long() + obs_labels = to_gpu(obs_labels).long() + max_len = torch.max(input_lengths.data).item() + mel_padded = to_gpu(mel_padded).float() + gate_padded = to_gpu(gate_padded).float() + output_lengths = to_gpu(output_lengths).long() + + return ( + (text_padded, input_lengths, obs_labels, + mel_padded, max_len, output_lengths), + (mel_padded, gate_padded)) + + def parse_output(self, outputs, output_lengths=None): + if self.mask_padding and output_lengths is not None: + mask = ~get_mask_from_lengths(output_lengths) + mask = mask.expand(self.n_mel_channels, mask.size(0), mask.size(1)) + mask = mask.permute(1, 0, 2) + + outputs[0].data.masked_fill_(mask, 0.0) + outputs[1].data.masked_fill_(mask, 0.0) + outputs[2].data.masked_fill_(mask[:, 0, :], 1e3) # gate energies + + return outputs + + def forward(self, inputs): + (text_inputs, text_lengths, obs_labels, + mels, max_len, output_lengths) = inputs + text_lengths, output_lengths = text_lengths.data, output_lengths.data + + embedded_inputs = self.embedding(text_inputs).transpose(1, 2) + + encoder_outputs = self.encoder(embedded_inputs, text_lengths) + + obs = None + if self.obs_embedding is not None: + obs = self.obs_embedding(obs_labels) + + lat, lat_mu, lat_logvar = None, None, None + if self.lat_encoder is not None: + (lat, lat_mu, lat_logvar) = self.lat_encoder(mels, output_lengths) + + obs_and_lat = [x for x in [obs, lat] if x is not None] + if bool(obs_and_lat): + obs_and_lat = torch.cat(obs_and_lat, dim=-1) + else: + obs_and_lat = None + + mel_outputs, gate_outputs, alignments = self.decoder( + encoder_outputs, obs_and_lat, mels, memory_lengths=text_lengths) + + mel_outputs_postnet = self.postnet(mel_outputs) + mel_outputs_postnet = mel_outputs + mel_outputs_postnet + + return self.parse_output( + [mel_outputs, mel_outputs_postnet, gate_outputs, alignments, + lat_mu, lat_logvar], + output_lengths) + + def inference(self, inputs, obs_labels=None, lat=None, ret_has_eos=False): + embedded_inputs = self.embedding(inputs).transpose(1, 2) + encoder_outputs = self.encoder.inference(embedded_inputs) + + if obs_labels is None: + obs_labels = torch.LongTensor(len(inputs)) + obs_labels = obs_labels.to(inputs.device).zero_() + + obs = None + if self.obs_embedding is not None: + obs = self.obs_embedding(obs_labels) + + if self.lat_encoder is not None: + if lat is None: + lat = torch.FloatTensor(len(inputs), self.lat_encoder.lat_dim) + lat = lat.to(inputs.device).zero_().type(encoder_outputs.type()) + + obs_and_lat = [x for x in [obs, lat] if x is not None] + if bool(obs_and_lat): + obs_and_lat = torch.cat(obs_and_lat, dim=-1) + else: + obs_and_lat = None + + mel_outputs, gate_outputs, alignments, has_eos = self.decoder.inference( + encoder_outputs, obs_and_lat, ret_has_eos=True) + + mel_outputs_postnet = self.postnet(mel_outputs) + mel_outputs_postnet = mel_outputs + mel_outputs_postnet + + outputs = self.parse_output( + [mel_outputs, mel_outputs_postnet, gate_outputs, alignments]) + + if ret_has_eos: + return outputs + [has_eos] + else: + return outputs diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/numbers.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/numbers.py new file mode 100644 index 0000000000..0d5f7fa818 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/numbers.py @@ -0,0 +1,71 @@ +""" from https://github.com/keithito/tacotron """ + +import inflect +import re + + +_inflect = inflect.engine() +_comma_number_re = re.compile(r'([0-9][0-9\,]+[0-9])') +_decimal_number_re = re.compile(r'([0-9]+\.[0-9]+)') +_pounds_re = re.compile(r'£([0-9\,]*[0-9]+)') +_dollars_re = re.compile(r'\$([0-9\.\,]*[0-9]+)') +_ordinal_re = re.compile(r'[0-9]+(st|nd|rd|th)') +_number_re = re.compile(r'[0-9]+') + + +def _remove_commas(m): + return m.group(1).replace(',', '') + + +def _expand_decimal_point(m): + return m.group(1).replace('.', ' point ') + + +def _expand_dollars(m): + match = m.group(1) + parts = match.split('.') + if len(parts) > 2: + return match + ' dollars' # Unexpected format + dollars = int(parts[0]) if parts[0] else 0 + cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0 + if dollars and cents: + dollar_unit = 'dollar' if dollars == 1 else 'dollars' + cent_unit = 'cent' if cents == 1 else 'cents' + return '%s %s, %s %s' % (dollars, dollar_unit, cents, cent_unit) + elif dollars: + dollar_unit = 'dollar' if dollars == 1 else 'dollars' + return '%s %s' % (dollars, dollar_unit) + elif cents: + cent_unit = 'cent' if cents == 1 else 'cents' + return '%s %s' % (cents, cent_unit) + else: + return 'zero dollars' + + +def _expand_ordinal(m): + return _inflect.number_to_words(m.group(0)) + + +def _expand_number(m): + num = int(m.group(0)) + if num > 1000 and num < 3000: + if num == 2000: + return 'two thousand' + elif num > 2000 and num < 2010: + return 'two thousand ' + _inflect.number_to_words(num % 100) + elif num % 100 == 0: + return _inflect.number_to_words(num // 100) + ' hundred' + else: + return _inflect.number_to_words(num, andword='', zero='oh', group=2).replace(', ', ' ') + else: + return _inflect.number_to_words(num, andword='') + + +def normalize_numbers(text): + text = re.sub(_comma_number_re, _remove_commas, text) + text = re.sub(_pounds_re, r'\1 pounds', text) + text = re.sub(_dollars_re, _expand_dollars, text) + text = re.sub(_decimal_number_re, _expand_decimal_point, text) + text = re.sub(_ordinal_re, _expand_ordinal, text) + text = re.sub(_number_re, _expand_number, text) + return text diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/stft.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/stft.py new file mode 100644 index 0000000000..63fcd431e2 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/stft.py @@ -0,0 +1,141 @@ +""" +BSD 3-Clause License + +Copyright (c) 2017, Prem Seetharaman +All rights reserved. + +* Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +import torch +import numpy as np +import torch.nn.functional as F +from torch.autograd import Variable +from scipy.signal import get_window +from librosa.util import pad_center, tiny +from .audio_processing import window_sumsquare + + +class STFT(torch.nn.Module): + """adapted from Prem Seetharaman's https://github.com/pseeth/pytorch-stft""" + def __init__(self, filter_length=800, hop_length=200, win_length=800, + window='hann'): + super(STFT, self).__init__() + self.filter_length = filter_length + self.hop_length = hop_length + self.win_length = win_length + self.window = window + self.forward_transform = None + scale = self.filter_length / self.hop_length + fourier_basis = np.fft.fft(np.eye(self.filter_length)) + + cutoff = int((self.filter_length / 2 + 1)) + fourier_basis = np.vstack([np.real(fourier_basis[:cutoff, :]), + np.imag(fourier_basis[:cutoff, :])]) + + forward_basis = torch.FloatTensor(fourier_basis[:, None, :]) + inverse_basis = torch.FloatTensor( + np.linalg.pinv(scale * fourier_basis).T[:, None, :]) + + if window is not None: + assert(filter_length >= win_length) + # get window and zero center pad it to filter_length + fft_window = get_window(window, win_length, fftbins=True) + fft_window = pad_center(fft_window, filter_length) + fft_window = torch.from_numpy(fft_window).float() + + # window the bases + forward_basis *= fft_window + inverse_basis *= fft_window + + self.register_buffer('forward_basis', forward_basis.float()) + self.register_buffer('inverse_basis', inverse_basis.float()) + + def transform(self, input_data): + num_batches = input_data.size(0) + num_samples = input_data.size(1) + + self.num_samples = num_samples + + # similar to librosa, reflect-pad the input + input_data = input_data.view(num_batches, 1, num_samples) + input_data = F.pad( + input_data.unsqueeze(1), + (int(self.filter_length / 2), int(self.filter_length / 2), 0, 0), + mode='reflect') + input_data = input_data.squeeze(1) + + forward_transform = F.conv1d( + input_data, + Variable(self.forward_basis, requires_grad=False), + stride=self.hop_length, + padding=0) + + cutoff = int((self.filter_length / 2) + 1) + real_part = forward_transform[:, :cutoff, :] + imag_part = forward_transform[:, cutoff:, :] + + magnitude = torch.sqrt(real_part**2 + imag_part**2) + phase = torch.autograd.Variable( + torch.atan2(imag_part.data, real_part.data)) + + return magnitude, phase + + def inverse(self, magnitude, phase): + recombine_magnitude_phase = torch.cat( + [magnitude*torch.cos(phase), magnitude*torch.sin(phase)], dim=1) + + inverse_transform = F.conv_transpose1d( + recombine_magnitude_phase, + Variable(self.inverse_basis, requires_grad=False), + stride=self.hop_length, + padding=0) + + if self.window is not None: + window_sum = window_sumsquare( + self.window, magnitude.size(-1), hop_length=self.hop_length, + win_length=self.win_length, n_fft=self.filter_length, + dtype=np.float32) + # remove modulation effects + approx_nonzero_indices = torch.from_numpy( + np.where(window_sum > tiny(window_sum))[0]) + window_sum = torch.autograd.Variable( + torch.from_numpy(window_sum), requires_grad=False) + window_sum = window_sum.cuda() if magnitude.is_cuda else window_sum + inverse_transform[:, :, approx_nonzero_indices] /= window_sum[approx_nonzero_indices] + + # scale by hop ratio + inverse_transform *= float(self.filter_length) / self.hop_length + + inverse_transform = inverse_transform[:, :, int(self.filter_length/2):] + inverse_transform = inverse_transform[:, :, :-int(self.filter_length/2):] + + return inverse_transform + + def forward(self, input_data): + self.magnitude, self.phase = self.transform(input_data) + reconstruction = self.inverse(self.magnitude, self.phase) + return reconstruction diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/symbols.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/symbols.py new file mode 100644 index 0000000000..5f0d70fdad --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/symbols.py @@ -0,0 +1,18 @@ +""" from https://github.com/keithito/tacotron """ + +''' +Defines the set of symbols used in text input to the model. + +The default is a set of ASCII characters that works well for English or text that has been run through Unidecode. For other data, you can modify _characters. See TRAINING_DATA.md for details. ''' +from . import cmudict + +_pad = '_' +_punctuation = '!\'(),.:;? ' +_special = '-' +_letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + +# Prepend "@" to ARPAbet symbols to ensure uniqueness (some are the same as uppercase letters): +_arpabet = ['@' + s for s in cmudict.valid_symbols] + +# Export all symbols: +symbols = [_pad] + list(_special) + list(_punctuation) + list(_letters) + _arpabet diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/text.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/text.py new file mode 100644 index 0000000000..49e2ca498b --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/text.py @@ -0,0 +1,107 @@ +""" from https://github.com/keithito/tacotron """ +import numpy as np +import re +from . import cleaners +from .symbols import symbols + + +# Mappings from symbol to numeric ID and vice versa: +_symbol_to_id = {s: i for i, s in enumerate(symbols)} +_id_to_symbol = {i: s for i, s in enumerate(symbols)} + +# Regular expression matching text enclosed in curly braces: +_curly_re = re.compile(r'(.*?)\{(.+?)\}(.*)') + +# Special symbols +SOS_TOK = '<s>' +EOS_TOK = '</s>' + +def text_to_sequence(text, cleaner_names): + '''Converts a string of text to a sequence of IDs corresponding to the symbols in the text. + + The text can optionally have ARPAbet sequences enclosed in curly braces embedded + in it. For example, "Turn left on {HH AW1 S S T AH0 N} Street." + + Args: + text: string to convert to a sequence + cleaner_names: names of the cleaner functions to run the text through + + Returns: + List of integers corresponding to the symbols in the text + ''' + sequence = [] + + # Check for curly braces and treat their contents as ARPAbet: + while len(text): + m = _curly_re.match(text) + if not m: + sequence += _symbols_to_sequence(_clean_text(text, cleaner_names)) + break + sequence += _symbols_to_sequence(_clean_text(m.group(1), cleaner_names)) + sequence += _arpabet_to_sequence(m.group(2)) + text = m.group(3) + + return sequence + + +def sample_code_chunk(code, size): + assert(size > 0 and size <= len(code)) + start = np.random.randint(len(code) - size + 1) + end = start + size + return code[start:end], start, end + + +def code_to_sequence(code, code_dict, collapse_code): + if collapse_code: + prev_c = None + sequence = [] + for c in code: + if c in code_dict and c != prev_c: + sequence.append(code_dict[c]) + prev_c = c + else: + sequence = [code_dict[c] for c in code if c in code_dict] + if len(sequence) < 0.95 * len(code): + print('WARNING : over 5%% codes are OOV') + + return sequence + + +def sequence_to_text(sequence): + '''Converts a sequence of IDs back to a string''' + result = '' + for symbol_id in sequence: + if symbol_id in _id_to_symbol: + s = _id_to_symbol[symbol_id] + # Enclose ARPAbet back in curly braces: + if len(s) > 1 and s[0] == '@': + s = '{%s}' % s[1:] + result += s + return result.replace('}{', ' ') + + +def sequence_to_code(sequence, code_dict): + '''Analogous to sequence_to_text''' + id_to_code = {i: c for c, i in code_dict.items()} + return ' '.join([id_to_code[i] for i in sequence]) + + +def _clean_text(text, cleaner_names): + for name in cleaner_names: + cleaner = getattr(cleaners, name) + if not cleaner: + raise Exception('Unknown cleaner: %s' % name) + text = cleaner(text) + return text + + +def _symbols_to_sequence(symbols): + return [_symbol_to_id[s] for s in symbols if _should_keep_symbol(s)] + + +def _arpabet_to_sequence(text): + return _symbols_to_sequence(['@' + s for s in text.split()]) + + +def _should_keep_symbol(s): + return s in _symbol_to_id and s != '_' and s != '~' diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py new file mode 100644 index 0000000000..66a426d222 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py @@ -0,0 +1,167 @@ +import collections +import io +import json +import librosa +import numpy as np +import soundfile as sf +import time +import torch +from scipy.io.wavfile import read +from .text import SOS_TOK, EOS_TOK + + +def get_mask_from_lengths(lengths): + max_len = torch.max(lengths).item() + ids = torch.arange(0, max_len, out=torch.cuda.LongTensor(max_len)) + mask = (ids < lengths.unsqueeze(1)) + return mask + + +def load_wav_to_torch(full_path, sr=None): + data, sr = librosa.load(full_path, sr=sr) + data = np.clip(data, -1, 1) # potentially out of [-1, 1] due to resampling + data = data * 32768.0 # match values loaded by scipy + return torch.FloatTensor(data.astype(np.float32)), sr + + +def read_binary_audio(bin_data, tar_sr=None): + """ + read binary audio (`bytes` or `uint8` `numpy.ndarray`) to `float32` + `numpy.ndarray` + + RETURNS: + data (np.ndarray) : audio of shape (n,) or (2, n) + tar_sr (int) : sample rate + """ + data, ori_sr = sf.read(io.BytesIO(bin_data), dtype='float32') + data = data.T + if (tar_sr is not None) and (ori_sr != tar_sr): + data = librosa.resample(data, ori_sr, tar_sr) + else: + tar_sr = ori_sr + data = np.clip(data, -1, 1) + data = data * 32768.0 + return torch.FloatTensor(data.astype(np.float32)), tar_sr + + +def load_filepaths_and_text(filename): + with open(filename, encoding='utf-8') as f: + data = [json.loads(line.rstrip()) for line in f] + return data + + +def to_gpu(x): + x = x.contiguous() + + if torch.cuda.is_available(): + x = x.cuda(non_blocking=True) + return torch.autograd.Variable(x) + + +def load_code_dict(path, add_sos=False, add_eos=False): + if not path: + return {} + + with open(path, 'r') as f: + codes = ['_'] + [line.rstrip() for line in f] # '_' for pad + code_dict = {c: i for i, c in enumerate(codes)} + + if add_sos: + code_dict[SOS_TOK] = len(code_dict) + if add_eos: + code_dict[EOS_TOK] = len(code_dict) + assert(set(code_dict.values()) == set(range(len(code_dict)))) + + return code_dict + + +def load_obs_label_dict(path): + if not path: + return {} + with open(path, 'r') as f: + obs_labels = [line.rstrip() for line in f] + return {c: i for i, c in enumerate(obs_labels)} + + +# A simple timer class inspired from `tnt.TimeMeter` +class CudaTimer: + def __init__(self, keys): + self.keys = keys + self.reset() + + def start(self, key): + s = torch.cuda.Event(enable_timing=True) + s.record() + self.start_events[key].append(s) + return self + + def stop(self, key): + e = torch.cuda.Event(enable_timing=True) + e.record() + self.end_events[key].append(e) + return self + + def reset(self): + self.start_events = collections.defaultdict(list) + self.end_events = collections.defaultdict(list) + self.running_times = collections.defaultdict(float) + self.n = collections.defaultdict(int) + return self + + def value(self): + self._synchronize() + return {k: self.running_times[k] / self.n[k] for k in self.keys} + + def _synchronize(self): + torch.cuda.synchronize() + for k in self.keys: + starts = self.start_events[k] + ends = self.end_events[k] + if len(starts) == 0: + raise ValueError("Trying to divide by zero in TimeMeter") + if len(ends) != len(starts): + raise ValueError("Call stop before checking value!") + time = 0 + for start, end in zip(starts, ends): + time += start.elapsed_time(end) + self.running_times[k] += time * 1e-3 + self.n[k] += len(starts) + self.start_events = collections.defaultdict(list) + self.end_events = collections.defaultdict(list) + + +# Used to measure the time taken for multiple events +class Timer: + def __init__(self, keys): + self.keys = keys + self.n = {} + self.running_time = {} + self.total_time = {} + self.reset() + + def start(self, key): + self.running_time[key] = time.time() + return self + + def stop(self, key): + self.total_time[key] = time.time() - self.running_time[key] + self.n[key] += 1 + self.running_time[key] = None + return self + + def reset(self): + for k in self.keys: + self.total_time[k] = 0 + self.running_time[k] = None + self.n[k] = 0 + return self + + def value(self): + vals = {} + for k in self.keys: + if self.n[k] == 0: + raise ValueError("Trying to divide by zero in TimeMeter") + else: + vals[k] = self.total_time[k] / self.n[k] + return vals + diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/waveglow_denoiser.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/waveglow_denoiser.py new file mode 100644 index 0000000000..6a6585e8b6 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/waveglow_denoiser.py @@ -0,0 +1,40 @@ +# import sys +# sys.path.append('tacotron2') +import torch +from .layers import STFT + + +class Denoiser(torch.nn.Module): + """ Removes model bias from audio produced with waveglow """ + + def __init__(self, waveglow, filter_length=1024, n_overlap=4, + win_length=1024, mode='zeros'): + super(Denoiser, self).__init__() + self.stft = STFT(filter_length=filter_length, + hop_length=int(filter_length/n_overlap), + win_length=win_length).cuda() + if mode == 'zeros': + mel_input = torch.zeros( + (1, 80, 88), + dtype=waveglow.upsample.weight.dtype, + device=waveglow.upsample.weight.device) + elif mode == 'normal': + mel_input = torch.randn( + (1, 80, 88), + dtype=waveglow.upsample.weight.dtype, + device=waveglow.upsample.weight.device) + else: + raise Exception("Mode {} if not supported".format(mode)) + + with torch.no_grad(): + bias_audio = waveglow.infer(mel_input, sigma=0.0).float() + bias_spec, _ = self.stft.transform(bias_audio) + + self.register_buffer('bias_spec', bias_spec[:, :, 0][:, :, None]) + + def forward(self, audio, strength=0.1): + audio_spec, audio_angles = self.stft.transform(audio.cuda().float()) + audio_spec_denoised = audio_spec - self.bias_spec * strength + audio_spec_denoised = torch.clamp(audio_spec_denoised, 0.0) + audio_denoised = self.stft.inverse(audio_spec_denoised, audio_angles) + return audio_denoised diff --git a/examples/textless_nlp/gslm/unit2speech/tts_data.py b/examples/textless_nlp/gslm/unit2speech/tts_data.py new file mode 100644 index 0000000000..eb0f7c360d --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/tts_data.py @@ -0,0 +1,52 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +import numpy as np +from examples.textless_nlp.gslm.unit2speech.tacotron2.text import ( + EOS_TOK, + SOS_TOK, + code_to_sequence, + text_to_sequence, +) +from examples.textless_nlp.gslm.unit2speech.tacotron2.utils import ( + load_code_dict, +) + + +class TacotronInputDataset: + def __init__(self, hparams, append_str=""): + self.is_text = getattr(hparams, "text_or_code", "text") == "text" + if not self.is_text: + self.code_dict = load_code_dict(hparams.code_dict) + self.code_key = hparams.code_key + self.add_sos = hparams.add_sos + self.add_eos = hparams.add_eos + self.collapse_code = hparams.collapse_code + self.append_str = append_str + + def process_code(self, inp_str): + inp_toks = inp_str.split() + if self.add_sos: + inp_toks = [SOS_TOK] + inp_toks + if self.add_eos: + inp_toks = inp_toks + [EOS_TOK] + return code_to_sequence(inp_toks, self.code_dict, self.collapse_code) + + def process_text(self, inp_str): + return text_to_sequence(inp_str, ["english_cleaners"]) + + def get_tensor(self, inp_str): + # uid, txt, inp_str = self._get_data(idx) + inp_str = inp_str + self.append_str + if self.is_text: + inp_toks = self.process_text(inp_str) + else: + inp_toks = self.process_code(inp_str) + return torch.from_numpy(np.array(inp_toks)).long() + + def __len__(self): + return len(self.data) diff --git a/examples/textless_nlp/gslm/unit2speech/utils.py b/examples/textless_nlp/gslm/unit2speech/utils.py new file mode 100644 index 0000000000..7aced08d38 --- /dev/null +++ b/examples/textless_nlp/gslm/unit2speech/utils.py @@ -0,0 +1,55 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from examples.textless_nlp.gslm.unit2speech.tacotron2.model import Tacotron2 +from examples.textless_nlp.gslm.unit2speech.tacotron2.waveglow_denoiser import ( + Denoiser, +) + + +def load_quantized_audio_from_file(file_path): + base_fname_batch, quantized_units_batch = [], [] + with open(file_path) as f: + for line in f: + base_fname, quantized_units_str = line.rstrip().split("|") + quantized_units = [int(q) for q in quantized_units_str.split(" ")] + base_fname_batch.append(base_fname) + quantized_units_batch.append(quantized_units) + return base_fname_batch, quantized_units_batch + + +def synthesize_audio(model, waveglow, denoiser, inp, lab=None, strength=0.0): + assert inp.size(0) == 1 + inp = inp.cuda() + if lab is not None: + lab = torch.LongTensor(1).cuda().fill_(lab) + + with torch.no_grad(): + _, mel, _, ali, has_eos = model.inference(inp, lab, ret_has_eos=True) + aud = waveglow.infer(mel, sigma=0.666) + aud_dn = denoiser(aud, strength=strength).squeeze(1) + return mel, aud, aud_dn, has_eos + + +def load_tacotron(tacotron_model_path, max_decoder_steps): + ckpt_dict = torch.load(tacotron_model_path) + hparams = ckpt_dict["hparams"] + hparams.max_decoder_steps = max_decoder_steps + sr = hparams.sampling_rate + model = Tacotron2(hparams) + model.load_state_dict(ckpt_dict["model_dict"]) + model = model.cuda().eval().half() + return model, sr, hparams + + +def load_waveglow(waveglow_path): + waveglow = torch.load(waveglow_path)["model"] + waveglow = waveglow.cuda().eval().half() + for k in waveglow.convinv: + k.float() + denoiser = Denoiser(waveglow) + return waveglow, denoiser diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index c99c6bf7d1..cc310088db 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -199,7 +199,8 @@ def build_model(self, model_cfg: FairseqDataclass): actualized_cfg = getattr(model, "cfg", None) if actualized_cfg is not None: - if "w2v_args" in actualized_cfg: + # if "w2v_args" in actualized_cfg: + if hasattr(actualized_cfg, "w2v_args"): model_cfg.w2v_args = actualized_cfg.w2v_args return model From db0175a882e8ae0f30d89b5a610373dbe032d528 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Fri, 27 Aug 2021 05:54:21 -0700 Subject: [PATCH 443/774] Require fairscale >= 0.4.0 to combine FSDP and --update-freq (#2239) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2239 Reviewed By: sshleifer, ngoyal2707 Differential Revision: D30574791 Pulled By: myleott fbshipit-source-id: 0f83e6ffe53d608292545884df269a604a57448d --- fairseq/trainer.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index d53e650b0a..c86b1a51ec 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -62,6 +62,7 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): self.device = torch.device("cpu") if self.is_fsdp: + import fairscale if self.cfg.common.bf16: raise ValueError( "FullyShardedDataParallel is not compatible with --bf16 or " @@ -72,6 +73,11 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): "FullyShardedDataParallel is not compatible with --zero-sharding " "option (it's already built in)" ) + if max(self.cfg.optimization.update_freq) > 1 and fairscale.__version__ < "0.4.0": + raise RuntimeError( + "Please update to fairscale 0.4.0 or newer when combining " + "--update-freq with FullyShardedDataParallel" + ) else: if ( hasattr(self.cfg.distributed_training, "cpu_offload") From 932a3d4aad6cae3ef05aad59e257eba1c765a36c Mon Sep 17 00:00:00 2001 From: Jingfei Du <jingfeidu@fb.com> Date: Mon, 30 Aug 2021 18:05:50 -0700 Subject: [PATCH 444/774] fix beam search with prefix tokens (#2227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: 1. added test for genereting pad tokens during beam search with prefix tokens 2. modified lprobs for pad token and prefix tokens to avoid generating pad # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2227 Reviewed By: xianxl Differential Revision: D30649356 Pulled By: jingfeidu fbshipit-source-id: d94903a912e767391c8fca61f98f65b5cea3b56e --- fairseq/sequence_generator.py | 22 ++++++------- tests/test_sequence_generator.py | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index d9c906ceea..740c32d648 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -344,16 +344,6 @@ def _generate( probs = probs[:, -1, :] * self.lm_weight lprobs += probs - lprobs[lprobs != lprobs] = torch.tensor(-math.inf).to(lprobs) - - lprobs[:, self.pad] = -math.inf # never select pad - lprobs[:, self.unk] -= self.unk_penalty # apply unk penalty - - # handle max length constraint - if step >= max_len: - lprobs[:, : self.eos] = -math.inf - lprobs[:, self.eos + 1 :] = -math.inf - # handle prefix tokens (possibly with different lengths) if ( prefix_tokens is not None @@ -367,6 +357,16 @@ def _generate( # minimum length constraint (does not apply if using prefix_tokens) lprobs[:, self.eos] = -math.inf + lprobs[lprobs != lprobs] = torch.tensor(-math.inf).to(lprobs) + + lprobs[:, self.pad] = -math.inf # never select pad + lprobs[:, self.unk] -= self.unk_penalty # apply unk penalty + + # handle max length constraint + if step >= max_len: + lprobs[:, : self.eos] = -math.inf + lprobs[:, self.eos + 1 :] = -math.inf + # Record attention scores, only support avg_attn_scores is a Tensor if avg_attn_scores is not None: if attn is None: @@ -568,7 +568,7 @@ def _prefix_tokens( prefix_toks = prefix_tokens[:, step].unsqueeze(-1).repeat(1, beam_size).view(-1) prefix_lprobs = lprobs.gather(-1, prefix_toks.unsqueeze(-1)) prefix_mask = prefix_toks.ne(self.pad) - lprobs[prefix_mask] = torch.tensor(-math.inf).to(lprobs) + lprobs[prefix_mask] = torch.min(prefix_lprobs) lprobs[prefix_mask] = lprobs[prefix_mask].scatter( -1, prefix_toks[prefix_mask].unsqueeze(-1), prefix_lprobs[prefix_mask] ) diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index afbdfb6c2c..9273191962 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -563,6 +563,60 @@ def test_diverse_beam_search(self): self.assertHypoScore(hypos[1][1], [0.7, 0.35, 0.9], [0, 2, 1], 0.5) +class TestPrefixBeamSearch(TestSequenceGeneratorBase): + def setUp(self): + # construct dummy dictionary + vocab_size = 10 + d = test_utils.dummy_dictionary(vocab_size=vocab_size) + self.assertEqual(d.pad(), 1) + self.assertEqual(d.eos(), 2) + self.assertEqual(d.unk(), 3) + self.eos = d.eos() + self.w1 = 4 + self.w2 = 5 + self.beam_size = 3 + + # construct prefix data + self.tokens = torch.LongTensor( + [ + [self.w1, self.w2, self.eos], + ] + ) + self.token_lengths = torch.LongTensor([2]) + + args = argparse.Namespace() + unk = 0.0 + args.beam_probs = [ + # prefix step 0: + torch.FloatTensor( + [ + # eos + [0.0, unk] + [1.0 / vocab_size] * vocab_size # beam 1 + ] * self.beam_size + ), + ] * vocab_size + + task = test_utils.TestTranslationTask.setup_task(args, d, d) + self.model = task.build_model(args) + self.tgt_dict = task.target_dictionary + + def test_prefix_beam_search(self): + search_strategy = search.BeamSearch(self.tgt_dict) + generator = SequenceGenerator( + [self.model], + self.tgt_dict, + beam_size=self.beam_size, + search_strategy=search_strategy, + ) + sample = { + "net_input": { + "src_tokens": self.tokens, + "src_lengths": self.token_lengths, + } + } + # make sure test sample doesn't break any assertion + generator.forward(sample, prefix_tokens=self.tokens[:, :-1]) + class TestTopPSamplingSearch(TestSequenceGeneratorBase): def setUp(self): # construct dummy dictionary From 5277ec47bdb51165592596e2a2c4c7ee650d9958 Mon Sep 17 00:00:00 2001 From: Rengan Xu <renganxu@fb.com> Date: Mon, 30 Aug 2021 21:47:52 -0700 Subject: [PATCH 445/774] Fix test_eval_bleu unittest (#2236) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2236 The test_eval_bleu unittest in TestTranslation in tests/test_binaries.py failed after the scarebleu version is updated to 2.0.0 in OSS testing tool. Added the fix so that the test can pass when scarebleu version is both 1.x and 2.0.0. Reviewed By: myleott, sravyapopuri388 Differential Revision: D30525920 fbshipit-source-id: 8ef27509cec45422a8d22003c87c2a7acb55225d --- fairseq/tasks/translation.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index ea80fa2e73..8647360867 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -418,14 +418,20 @@ def sum_logs(key): def compute_bleu(meters): import inspect - import sacrebleu - - fn_sig = inspect.getfullargspec(sacrebleu.compute_bleu)[0] + try: + from sacrebleu.metrics import BLEU + comp_bleu = BLEU.compute_bleu + except ImportError: + # compatibility API for sacrebleu 1.x + import sacrebleu + comp_bleu = sacrebleu.compute_bleu + + fn_sig = inspect.getfullargspec(comp_bleu)[0] if "smooth_method" in fn_sig: smooth = {"smooth_method": "exp"} else: smooth = {"smooth": "exp"} - bleu = sacrebleu.compute_bleu( + bleu = comp_bleu( correct=meters["_bleu_counts"].sum, total=meters["_bleu_totals"].sum, sys_len=meters["_bleu_sys_len"].sum, From 68a81202a371574b3acb5f8a8c36bfac7ab255ed Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Tue, 31 Aug 2021 01:11:34 -0700 Subject: [PATCH 446/774] Indexed Huffman Coded dataset (#2029) Summary: ## What does this PR do? Currently, binarized dataset are stored as a bin representation of int tensors. At best, each int is coded as uint16 on disk. When coding a fixed size vocabulary dataset where we know the frequency of each symbol and where some symbols are more common than other, we can do better. This happens in particular when binarizing a dataset split in subword units as the most common "tokenizers" like bpe and spm will choose subwords with high frequencies over subwords with low frequencies. In practice, if we know the frequency of all symbols (or a good estimate), we can use entropy encoding methods to compress the data. The idea is to assign a compressed representation where frequent symbols will have shorter representations than unfrequent symbols. In this PR, we build a Huffman code from a frequency table and use this code to encode a dataset. The PR provides the huffman coder implementation (using the single queue approach as we usually start with a sorted set of symbols) as well as a memory map implementation of a dataset that stores the data compressed with a huffman code and can return indexed tensors from it. Over a whole dataset, depending on how many symbols we sample to evaluate the frequency, we can save between 25% and 30% of storage space. ## Follow Ups currently the binarizer/preprocess script make too many assumptions about the dataset writers so the huffman dataset writer cannot be used straight out of the box with it. I will make follow ups PRs to provide easy to use scripts to build such datasets. But it's as simple as doing: ``` code_builder = HuffmanCodeBuilder() with open(sample_file, 'r', encoding="utf-8") as input: for line in input: code_builder.add(*line.strip().split(" ")) coder = code_builder.build_code() with HuffmanMMapIndexedDatasetBuilder('/tmp/testing_huffman', coder) as builder: with open(dataset_file, 'r', encoding="utf-8") as input: for line in input: builder.add_item(line.strip().split(' ')) ``` a lot of the `HuffmanMMapIndexedDataset` code comes from the normal `MMapIndexedDataset` and we could probably extract commonalities in a base class the `HuffmanCoder` is also really a special kind of `Dictionary` and again, a common base class could be abstracted out of them. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2029 Reviewed By: dianaml0 Differential Revision: D29557468 Pulled By: Mortimerp9 fbshipit-source-id: a01b6d98f38f937934cadebb3786133e257adefe --- fairseq/data/dictionary.py | 2 +- fairseq/data/huffman/__init__.py | 21 ++ fairseq/data/huffman/huffman_coder.py | 265 ++++++++++++++++ .../huffman/huffman_mmap_indexed_dataset.py | 287 ++++++++++++++++++ fairseq/data/indexed_dataset.py | 9 + fairseq/dataclass/constants.py | 2 +- fairseq_cli/preprocess.py | 2 + setup.py | 1 + tests/test_huffman.py | 201 ++++++++++++ 9 files changed, 788 insertions(+), 2 deletions(-) create mode 100644 fairseq/data/huffman/__init__.py create mode 100644 fairseq/data/huffman/huffman_coder.py create mode 100644 fairseq/data/huffman/huffman_mmap_indexed_dataset.py create mode 100644 tests/test_huffman.py diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index 6876b461d7..d3ef0f9896 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -267,7 +267,7 @@ def add_from_file(self, f): self.add_symbol(word, n=count, overwrite=overwrite) except ValueError: raise ValueError( - "Incorrect dictionary format, expected '<token> <cnt> [flags]'" + f"Incorrect dictionary format, expected '<token> <cnt> [flags]': \"{line}\"" ) def _save(self, f, kv_iterator): diff --git a/fairseq/data/huffman/__init__.py b/fairseq/data/huffman/__init__.py new file mode 100644 index 0000000000..9b61fafadb --- /dev/null +++ b/fairseq/data/huffman/__init__.py @@ -0,0 +1,21 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .huffman_coder import HuffmanCodeBuilder, HuffmanCoder +from .huffman_mmap_indexed_dataset import ( + HuffmanMMapIndex, + HuffmanMMapIndexedDataset, + HuffmanMMapIndexedDatasetBuilder, + vocab_file_path, +) + +__all__ = [ + "HuffmanCoder", + "HuffmanCodeBuilder", + "HuffmanMMapIndexedDatasetBuilder", + "HuffmanMMapIndexedDataset", + "HuffmanMMapIndex", + "vocab_file_path", +] diff --git a/fairseq/data/huffman/huffman_coder.py b/fairseq/data/huffman/huffman_coder.py new file mode 100644 index 0000000000..6531f1547c --- /dev/null +++ b/fairseq/data/huffman/huffman_coder.py @@ -0,0 +1,265 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import re +import typing as tp +from collections import Counter, deque +from dataclasses import dataclass + +from bitarray import bitarray, util +from fairseq.data import Dictionary + +# basically we have to write to addressable bytes for the memory mapped +# dataset loader. Sentences that get encoded to a length that is not a +# multiple of BLOCKSIZE (a byte) will be padded to fit. (see _pad in the coder) +BLOCKSIZE = 8 + + +class HuffmanCoder: + def __init__( + self, root: "HuffmanNode", bos="<s>", pad="<pad>", eos="</s>", unk="<unk>" + ): + self.root = root + self.table = root.code_table() + self.bos_word, self.unk_word, self.pad_word, self.eos_word = bos, unk, pad, eos + + def _pad(self, a: bitarray) -> bitarray: + """ + bitpadding, 1 then 0. + + If the array is already a multiple of blocksize, we add a full block. + """ + pad_len = BLOCKSIZE - (len(a) % BLOCKSIZE) - 1 + padding = bitarray("1" + "0" * pad_len) + return a + padding + + def _unpad(self, a: bitarray) -> bitarray: + """ + remove the bitpadding. + + There will be a set of 0s preceded by a 1 at the end of the bitarray, we remove that + """ + # count the 0 padding at the end until we find the first 1 + # we want to remove the one too + remove_cnt = util.rindex(a, 1) + return a[:remove_cnt] + + def encode(self, iter: tp.List[str]) -> bytes: + """ + encode a list of tokens a return bytes. We use bitpadding to make sure the encoded bits fit in bytes. + """ + a = bitarray() + for token in iter: + code = self.get_code(token) + if code is None: + if self.unk_word is None: + raise Exception(f"unknown token {token} cannot be encoded.") + else: + token = self.unk_word + a = a + self.get_code(token) + return self._pad(a).tobytes() + + def decode(self, bits: bytes) -> tp.Iterator["HuffmanNode"]: + """ + take bitpadded bytes and decode it to a set of leaves. You can then use each node to find the symbol/id + """ + a = bitarray() + a.frombytes(bits) + return self.root.decode(self._unpad(a)) + + def get_code(self, symbol: str) -> tp.Optional[bitarray]: + node = self.get_node(symbol) + return None if node is None else node.code + + def get_node(self, symbol: str) -> "HuffmanNode": + return self.table.get(symbol) + + @classmethod + def from_file( + cls, + filename: str, + bos="<s>", + pad="<pad>", + eos="</s>", + unk="<unk>", + ) -> "HuffmanCoder": + builder = HuffmanCodeBuilder.from_file(filename) + return builder.build_code(bos=bos, pad=pad, eos=eos, unk=unk) + + def to_file(self, filename, sep="\t"): + nodes = list(self.table.values()) + nodes.sort(key=lambda n: n.id) + with open(filename, "w", encoding="utf-8") as output: + for n in nodes: + output.write(f"{n.symbol}{sep}{n.count}\n") + + def __iter__(self): + for n in self.table.values(): + yield n + + def merge(self, other_coder: "HuffmanCoder") -> "HuffmanCoder": + builder = HuffmanCodeBuilder() + for n in self: + builder.increment(n.symbol, n.count) + for n in other_coder: + builder.increment(n.symbol, n.count) + return builder.build_code() + + def __eq__(self, other: "HuffmanCoder") -> bool: + return self.table == other.table + + def __len__(self) -> int: + return len(self.table) + + def __contains__(self, sym: str) -> bool: + return sym in self.table + + def to_dictionary(self) -> Dictionary: + dictionary = Dictionary(bos=self.bos, unk=self.unk, pad=self.pad, eos=self.eos) + for n in self: + dictionary.add_symbol(n.symbol, n=n.count) + dictionary.finalize() + return dictionary + + +@dataclass +class HuffmanNode: + """ + a node in a Huffman tree + """ + + id: int + count: int + symbol: tp.Optional[str] = None + left: tp.Optional["HuffmanNode"] = None + right: tp.Optional["HuffmanNode"] = None + code: tp.Optional[bitarray] = None + + def is_leaf(self) -> bool: + return self.left is None and self.right is None + + def code_table(self, prefix: tp.Optional[bitarray] = None) -> tp.Dict[str, "HuffmanNode"]: + defaulted_prefix = prefix if prefix is not None else bitarray() + if self.is_leaf(): + self.code = ( + defaulted_prefix if len(defaulted_prefix) > 0 else bitarray("0") + ) # leaf could be the root if there is only one symbol + return {self.symbol: self} + + codes_right = self.right.code_table(defaulted_prefix + bitarray([0])) + codes_left = self.left.code_table(defaulted_prefix + bitarray([1])) + return {**codes_left, **codes_right} + + def decode(self, bits: bitarray) -> tp.Iterator["HuffmanNode"]: + current_node = self + for bit in bits: + if bit == 0: # go right + current_node = current_node.right + else: # go left + current_node = current_node.left + if current_node is None: + # we shouldn't be on a leaf here + raise Exception("fell off a leaf") + if current_node.is_leaf(): + yield current_node + current_node = self + if current_node != self: + raise Exception("couldn't decode all the bits") + + +class HuffmanCodeBuilder: + """ + build a dictionary with occurence count and then build the Huffman code for it. + """ + + def __init__(self): + self.symbols = Counter() + + def add_symbols(self, *syms) -> None: + self.symbols.update(syms) + + def increment(self, symbol: str, cnt: int) -> None: + self.symbols[symbol] += cnt + + @classmethod + def from_file(cls, filename): + c = cls() + with open(filename, "r", encoding="utf-8") as input: + for line in input: + split = re.split(r"[\s]+", line) + c.increment(split[0], int(split[1])) + return c + + def to_file(self, filename, sep="\t"): + with open(filename, "w", encoding="utf-8") as output: + for (tok, cnt) in self.symbols.most_common(): + output.write(f"{tok}{sep}{cnt}\n") + + def _smallest(self, q1: deque, q2: deque) -> HuffmanNode: + if len(q1) == 0: + return q2.pop() + + if len(q2) == 0: + return q1.pop() + + if q1[-1].count < q2[-1].count: + return q1.pop() + + return q2.pop() + + def __add__(self, c: "HuffmanCodeBuilder") -> "HuffmanCodeBuilder": + new_c = self.symbols + c.symbols + new_b = HuffmanCodeBuilder() + new_b.symbols = new_c + return new_b + + def build_code( + self, + bos="<s>", + pad="<pad>", + eos="</s>", + unk="<unk>", + ) -> HuffmanCoder: + assert len(self.symbols) > 0, "cannot build code from empty list of symbols" + + if self.symbols[bos] == 0: + self.add_symbols(bos) + if self.symbols[pad] == 0: + self.add_symbols(pad) + if self.symbols[eos] == 0: + self.add_symbols(eos) + if self.symbols[unk] == 0: + self.add_symbols(unk) + + node_id = 0 + leaves_queue = deque( + [ + HuffmanNode(symbol=symbol, count=count, id=idx) + for idx, (symbol, count) in enumerate(self.symbols.most_common()) + ] + ) # left are the most common, right are the least common + + if len(leaves_queue) == 1: + root = leaves_queue.pop() + root.id = 0 + return HuffmanCoder(root) + + nodes_queue = deque() + + while len(leaves_queue) > 0 or len(nodes_queue) != 1: + # get the lowest two nodes at the head of each queue + node1 = self._smallest(leaves_queue, nodes_queue) + node2 = self._smallest(leaves_queue, nodes_queue) + + # add new node + nodes_queue.appendleft( + HuffmanNode( + count=node1.count + node2.count, left=node1, right=node2, id=node_id + ) + ) + node_id += 1 + + # we are left with the root + return HuffmanCoder(nodes_queue.pop(), bos=bos, pad=pad, eos=eos, unk=unk) diff --git a/fairseq/data/huffman/huffman_mmap_indexed_dataset.py b/fairseq/data/huffman/huffman_mmap_indexed_dataset.py new file mode 100644 index 0000000000..3279dae89a --- /dev/null +++ b/fairseq/data/huffman/huffman_mmap_indexed_dataset.py @@ -0,0 +1,287 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import mmap +import os +import shutil +import struct +import typing as tp +from functools import lru_cache + +import numpy as np +import torch +from fairseq.data import indexed_dataset +from fairseq.data.huffman import HuffmanCoder +from fairseq.file_io import PathManager + + +class HuffmanMMapIndex: + """ + keep an index of the offsets in the huffman binary file. + First a header, then the list of sizes (num tokens) for each instance and finally + the addresses of each instance. + """ + + _HDR_MAGIC = b"HUFFIDX\x00\x00" + _VERSION = 1 + + @classmethod + def writer(cls, path: str, data_len: int): + class _Writer: + def __enter__(self): + self._file = open(path, "wb") + + # write header (magic + version) + self._file.write(cls._HDR_MAGIC) + self._file.write(struct.pack("<Q", cls._VERSION)) + self._file.write(struct.pack("<Q", data_len)) + + return self + + def write(self, sizes, pointers): + # add number of items in the index to the header + self._file.write(struct.pack("<Q", len(sizes))) + + # write sizes + sizes = np.array(sizes, dtype=np.int32) + self._file.write(sizes.tobytes(order="C")) + del sizes + + # write address pointers + pointers = np.array(pointers, dtype=np.int64) + self._file.write(pointers.tobytes(order="C")) + del pointers + + def __exit__(self, exc_type, exc_val, exc_tb): + self._file.close() + + return _Writer() + + def __init__(self, path): + with open(path, "rb") as stream: + # read headers + magic_test = stream.read(9) + assert self._HDR_MAGIC == magic_test, ( + "Index file doesn't match expected format. " + "Make sure that --dataset-impl is configured properly." + ) + (version,) = struct.unpack("<Q", stream.read(8)) + assert ( + self._VERSION == version + ), "Unexpected file version f{version} != code version f{self._VERSION}" + + # read length of data file + (self._data_len,) = struct.unpack("<Q", stream.read(8)) + # read number of items in data file/index + (self._len,) = struct.unpack("<Q", stream.read(8)) + offset = stream.tell() + + indexed_dataset._warmup_mmap_file(path) + + self._bin_buffer_mmap = np.memmap(path, mode="r", order="C") + self._bin_buffer = memoryview(self._bin_buffer_mmap) + self._sizes = np.frombuffer( + self._bin_buffer, dtype=np.int32, count=self._len, offset=offset + ) + self._pointers = np.frombuffer( + self._bin_buffer, + dtype=np.int64, + count=self._len, + offset=offset + self._sizes.nbytes, + ) + + def __del__(self): + self._bin_buffer_mmap._mmap.close() + del self._bin_buffer_mmap + + def __iter__(self): + for i in range(self._len): + yield self[i] + + @property + def data_len(self): + return self._data_len + + @property + def sizes(self): + return self._sizes + + @lru_cache(maxsize=8) + def __getitem__(self, i): + return self._pointers[i], self._sizes[i] + + def __len__(self): + return self._len + + +def vocab_file_path(prefix_path): + return prefix_path + ".vocab" + + +class HuffmanMMapIndexedDataset(torch.utils.data.Dataset): + """ + an indexed dataset that use mmap and memoryview to access data from disk + that was compressed with a HuffmanCoder. + """ + + def __init__(self, prefix_path): + super().__init__() + + self._prefix_path = None + self._index = None + self._bin_buffer = None + self._coder = None + self._file = None + + self._bin_buffer_mmap = None + + self._do_init(prefix_path) + + def __getstate__(self): + return self._prefix_path + + def __setstate__(self, state): + self._do_init(state) + + def _do_init(self, prefix_path): + self._prefix_path = prefix_path + self._index = HuffmanMMapIndex( + indexed_dataset.index_file_path(self._prefix_path) + ) + self._coder = HuffmanCoder.from_file(vocab_file_path(self._prefix_path)) + + indexed_dataset._warmup_mmap_file( + indexed_dataset.data_file_path(self._prefix_path) + ) + self._file = os.open( + indexed_dataset.data_file_path(self._prefix_path), os.O_RDONLY + ) + self._bin_buffer_mmap = mmap.mmap( + self._file, + self._index.data_len, + access=mmap.ACCESS_READ, + ) + self._bin_buffer = memoryview(self._bin_buffer_mmap) + + def __del__(self): + del self._bin_buffer + if self._file: + os.close(self._file) + del self._index + + def __len__(self): + return len(self._index) + + def _decode(self, i): + ptr, _ = self._index[i] + if i == 0: + raw_bytes = self._bin_buffer[:ptr] + else: + (prev_ptr, _) = self._index[i - 1] + raw_bytes = self._bin_buffer[prev_ptr:ptr] + + return self._coder.decode(raw_bytes.tobytes()) + + @lru_cache(maxsize=8) + def __getitem__(self, i): + nodes = self._decode(i) + return torch.tensor([n.id for n in nodes], dtype=torch.int64) + + def __iter__(self): + for idx in range(len(self)): + yield self[idx] + + def get_symbols(self, i): + nodes = self._decode(i) + for n in nodes: + yield n.symbol + + @property + def sizes(self): + return self._index.sizes + + @property + def supports_prefetch(self): + return False + + @property + def coder(self): + return self._coder + + @staticmethod + def exists(prefix_path): + return ( + PathManager.exists(indexed_dataset.index_file_path(prefix_path)) + and PathManager.exists(indexed_dataset.data_file_path(prefix_path)) + and PathManager.exists(vocab_file_path(prefix_path)) + ) + + +class HuffmanMMapIndexedDatasetBuilder: + """ + Helper to build a memory mapped datasets with a huffman encoder. + You can either open/close this manually or use it as a ContextManager. + Provide your own coder, it will then be stored alongside the dataset. + The builder will first write the vocab file, then open the binary file so you can stream + into it, finally the index will be written when the builder is closed (your index should fit in memory). + """ + + def __init__(self, path_prefix: str, coder: HuffmanCoder) -> None: + self._path_prefix = path_prefix + self._coder = coder + self._sizes = [] + self._ptrs = [] + self._data_len = 0 + + def open(self): + self._coder.to_file(vocab_file_path(self._path_prefix)) + self._data_file = open(indexed_dataset.data_file_path(self._path_prefix), "wb") + + def __enter__(self) -> "HuffmanMMapIndexedDatasetBuilder": + self.open() + return self + + def add_item(self, tokens: tp.List[str]) -> None: + """ + add a list of tokens to the dataset, they will compressed with the + provided coder before being written to file. + """ + encoded = self._coder.encode(tokens) + code_len = len(encoded) + last_ptr = 0 + if len(self._ptrs) > 0: + last_ptr = self._ptrs[-1] + self._sizes.append(len(tokens)) + self._ptrs.append(last_ptr + code_len) + self._data_len += code_len + self._data_file.write(encoded) + + def append(self, other_dataset_path_prefix: str) -> None: + """ + append an existing dataset. + Beware, if it wasn't built with the same coder, you are in trouble. + """ + other_index = HuffmanMMapIndex( + indexed_dataset.index_file_path(other_dataset_path_prefix) + ) + for (ptr, size) in other_index: + self._ptrs.append(ptr + self._data_len) + self._sizes.append(size) + + # Concatenate data + with open(indexed_dataset.data_file_path(other_dataset_path_prefix), "rb") as f: + shutil.copyfileobj(f, self._data_file) + + self._data_len += other_index.data_len + + def close(self): + self._data_file.close() + with HuffmanMMapIndex.writer( + indexed_dataset.index_file_path(self._path_prefix), self._data_len + ) as index: + index.write(self._sizes, self._ptrs) + + def __exit__(self, exc_type, exc_val, exc_tb) -> None: + self.close() diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index 802e37a7ff..23afb43356 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -12,6 +12,7 @@ from fairseq.dataclass.constants import DATASET_IMPL_CHOICES from fairseq.data.fasta_dataset import FastaDataset from fairseq.file_io import PathManager +from fairseq.data.huffman import HuffmanMMapIndexedDataset, HuffmanMMapIndex from . import FairseqDataset @@ -48,6 +49,8 @@ def infer_dataset_impl(path): return "cached" elif magic == MMapIndexedDataset.Index._HDR_MAGIC[:8]: return "mmap" + elif magic == HuffmanMMapIndex._HDR_MAGIC[:8]: + return "huffman" else: return None elif FastaDataset.exists(path): @@ -63,6 +66,8 @@ def make_builder(out_file, impl, vocab_size=None): ) elif impl == "fasta": raise NotImplementedError + elif impl == "huffman": + raise ValueError("Use HuffmanCodeBuilder directly as it has a different interface.") else: return IndexedDatasetBuilder(out_file) @@ -81,6 +86,8 @@ def make_dataset(path, impl, fix_lua_indexing=False, dictionary=None): from fairseq.data.fasta_dataset import EncodedFastaDataset return EncodedFastaDataset(path, dictionary) + elif impl == "huffman" and HuffmanMMapIndexedDataset.exists(path): + return HuffmanMMapIndexedDataset(path) return None @@ -89,6 +96,8 @@ def dataset_exists(path, impl): return IndexedRawTextDataset.exists(path) elif impl == "mmap": return MMapIndexedDataset.exists(path) + elif impl == "huffman": + return HuffmanMMapIndexedDataset.exists(path) else: return IndexedDataset.exists(path) diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 442c25982b..4f159cfe9a 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -44,7 +44,7 @@ def ChoiceEnum(choices: List[str]): "slow_mo", ]) DDP_COMM_HOOK_CHOICES = ChoiceEnum(["none", "fp16"]) -DATASET_IMPL_CHOICES = ChoiceEnum(["raw", "lazy", "cached", "mmap", "fasta"]) +DATASET_IMPL_CHOICES = ChoiceEnum(["raw", "lazy", "cached", "mmap", "fasta", "huffman"]) GENERATION_CONSTRAINTS_CHOICES = ChoiceEnum(["ordered", "unordered"]) GENERATION_DECODING_FORMAT_CHOICES = ChoiceEnum( ["unigram", "ensemble", "vote", "dp", "bs"] diff --git a/fairseq_cli/preprocess.py b/fairseq_cli/preprocess.py index f7170eb00f..4ee9a1e3ba 100644 --- a/fairseq_cli/preprocess.py +++ b/fairseq_cli/preprocess.py @@ -41,6 +41,8 @@ def main(args): ) logger.info(args) + assert args.dataset_impl != "huffman", "preprocessing.py doesn't support Huffman yet, use HuffmanCodeBuilder directly." + task = tasks.get_task(args.task) def train_path(lang): diff --git a/setup.py b/setup.py index 7a19b73c9e..c699936a99 100644 --- a/setup.py +++ b/setup.py @@ -209,6 +209,7 @@ def do_setup(package_data): "sacrebleu>=1.4.12", "torch", "tqdm", + "bitarray", ], dependency_links=dependency_links, packages=find_packages( diff --git a/tests/test_huffman.py b/tests/test_huffman.py new file mode 100644 index 0000000000..a8cd5222b4 --- /dev/null +++ b/tests/test_huffman.py @@ -0,0 +1,201 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import random +import string +import typing as tp +import unittest +from collections import Counter +from tempfile import NamedTemporaryFile, TemporaryDirectory + +from fairseq.data import Dictionary, indexed_dataset +from fairseq.data.huffman import ( + HuffmanCodeBuilder, + HuffmanCoder, + HuffmanMMapIndexedDataset, + HuffmanMMapIndexedDatasetBuilder, +) + +POPULATION = string.ascii_letters + string.digits + + +def make_sentence() -> tp.List[str]: + length = random.randint(10, 50) + return random.choices( + population=POPULATION, k=length, weights=range(1, len(POPULATION) + 1) + ) + + +def make_data(length=1000) -> tp.List[tp.List[str]]: + return ( + [make_sentence() for _ in range(0, length)] + # add all the symbols at least once + + [list(string.ascii_letters), list(string.digits)] + ) + + +def make_counts(data: tp.List[tp.List[str]]) -> Counter: + return Counter([symbol for sentence in data for symbol in sentence]) + + +def make_code_builder(data: tp.List[tp.List[str]]) -> HuffmanCodeBuilder: + builder = HuffmanCodeBuilder() + for sentence in data: + builder.add_symbols(*sentence) + return builder + + +class TestCodeBuilder(unittest.TestCase): + def test_code_builder_can_count(self): + data = make_data() + counts = make_counts(data) + builder = make_code_builder(data) + + self.assertEqual(builder.symbols, counts) + + def test_code_builder_can_add(self): + data = make_data() + counts = make_counts(data) + builder = make_code_builder(data) + + new_builder = builder + builder + + self.assertEqual(new_builder.symbols, counts + counts) + + def test_code_builder_can_io(self): + data = make_data() + builder = make_code_builder(data) + + with NamedTemporaryFile() as tmp_fp: + builder.to_file(tmp_fp.name) + other_builder = HuffmanCodeBuilder.from_file(tmp_fp.name) + + self.assertEqual(builder.symbols, other_builder.symbols) + + +class TestCoder(unittest.TestCase): + def test_coder_can_io(self): + data = make_data() + builder = make_code_builder(data) + coder = builder.build_code() + + with NamedTemporaryFile() as tmp_fp: + coder.to_file(tmp_fp.name) + other_coder = HuffmanCoder.from_file(tmp_fp.name) + + self.assertEqual(coder, other_coder) + + def test_coder_can_encode_decode(self): + data = make_data() + builder = make_code_builder(data) + coder = builder.build_code() + + encoded = [coder.encode(sentence) for sentence in data] + decoded = [[n.symbol for n in coder.decode(enc)] for enc in encoded] + + self.assertEqual(decoded, data) + + unseen_data = make_data() + unseen_encoded = [coder.encode(sentence) for sentence in unseen_data] + unseen_decoded = [ + [n.symbol for n in coder.decode(enc)] for enc in unseen_encoded + ] + self.assertEqual(unseen_decoded, unseen_data) + + +def build_dataset(prefix, data, coder): + with HuffmanMMapIndexedDatasetBuilder(prefix, coder) as builder: + for sentence in data: + builder.add_item(sentence) + + +def sizes(data): + return [len(sentence) for sentence in data] + + +class TestHuffmanDataset(unittest.TestCase): + def test_huffman_can_encode_decode(self): + data = make_data() + builder = make_code_builder(data) + coder = builder.build_code() + + with TemporaryDirectory() as dirname: + prefix = os.path.join(dirname, "test1") + build_dataset(prefix, data, coder) + dataset = HuffmanMMapIndexedDataset(prefix) + + self.assertEqual(len(dataset), len(data)) + decoded = [list(dataset.get_symbols(i)) for i in range(0, len(dataset))] + + self.assertEqual(decoded, data) + data_sizes = [i.item() for i in dataset.sizes] + self.assertEqual(data_sizes, sizes(data)) + + def test_huffman_compresses(self): + data = make_data() + builder = make_code_builder(data) + coder = builder.build_code() + + with TemporaryDirectory() as dirname: + prefix = os.path.join(dirname, "huffman") + build_dataset(prefix, data, coder) + + prefix_mmap = os.path.join(dirname, "mmap") + mmap_builder = indexed_dataset.make_builder( + indexed_dataset.data_file_path(prefix_mmap), + "mmap", + vocab_size=len(POPULATION), + ) + dictionary = Dictionary() + for c in POPULATION: + dictionary.add_symbol(c) + dictionary.finalize() + for sentence in data: + mmap_builder.add_item(dictionary.encode_line(" ".join(sentence))) + mmap_builder.finalize(indexed_dataset.index_file_path(prefix_mmap)) + + huff_size = os.stat(indexed_dataset.data_file_path(prefix)).st_size + mmap_size = os.stat(indexed_dataset.data_file_path(prefix_mmap)).st_size + self.assertLess(huff_size, mmap_size) + + def test_huffman_can_append(self): + data1 = make_data() + builder = make_code_builder(data1) + coder = builder.build_code() + + with TemporaryDirectory() as dirname: + prefix1 = os.path.join(dirname, "test1") + build_dataset(prefix1, data1, coder) + + data2 = make_data() + prefix2 = os.path.join(dirname, "test2") + build_dataset(prefix2, data2, coder) + + prefix3 = os.path.join(dirname, "test3") + + with HuffmanMMapIndexedDatasetBuilder(prefix3, coder) as builder: + builder.append(prefix1) + builder.append(prefix2) + + dataset = HuffmanMMapIndexedDataset(prefix3) + + self.assertEqual(len(dataset), len(data1) + len(data2)) + + decoded1 = [list(dataset.get_symbols(i)) for i in range(0, len(data1))] + self.assertEqual(decoded1, data1) + + decoded2 = [ + list(dataset.get_symbols(i)) for i in range(len(data1), len(dataset)) + ] + self.assertEqual(decoded2, data2) + + data_sizes = [i.item() for i in dataset.sizes] + self.assertEqual(data_sizes[: len(data1)], sizes(data1)) + self.assertEqual(data_sizes[len(data1) : len(dataset)], sizes(data2)) + + +if __name__ == "__main__": + unittest.main() From 8feccf94412424a4683b01090de36fa77cb4951d Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Wed, 1 Sep 2021 11:43:25 -0700 Subject: [PATCH 447/774] EMA Summary: Adds Exponential moving average (EMA) model for Kaizen semi-supervised training https://arxiv.org/abs/2106.07759 1. Add `ema.store_ema` to enable storing EMA. EMA will be written to extra_state in the state dict while saving checkpoint. 2. `ema.ema_start_update` to control when the EMA starts accumulating 3. Tasks can use `uses_ema` property to decide if the EMA should be passed to the task. (Default is False) 4. `load_ema_from_checkpoint` can be used to load EMA model in place of the model to be used for evalutation. Pyspeech has eval-ema option for this. ``` This module has the EMA class used to store a copy of the exponentially decayed model params. Typical usage of EMA class involves initializing an object using an existing model (random or from a seed model) and setting the config like ema_decay, ema_start_update which determine how the EMA model is updated. After every update of the model i.e. at the end of the train_step, the EMA should be updated by passing the new model to the EMA.step function. The EMA model state dict can be stored in the extra state under the key of "ema" and dumped into a checkpoint and loaded. The EMA object can be passed to tasks by setting task.uses_ema property. EMA is a smoothed/ensemble model which might have better performance when used for inference or further fine-tuning. EMA class has a reverse function to load the EMA params into a model and use it like a regular model. ``` Reviewed By: cruvadom Differential Revision: D24238379 fbshipit-source-id: 879d3ba5070a614b7d365f9503af357001e875b2 --- fairseq/checkpoint_utils.py | 46 ++++++++ fairseq/dataclass/configs.py | 31 +++++ fairseq/models/ema/__init__.py | 20 ++++ fairseq/models/ema/ema.py | 189 +++++++++++++++++++++++++++++++ fairseq/options.py | 7 ++ fairseq/trainer.py | 78 ++++++++++++- tests/gpu/test_ema_gpu.py | 200 +++++++++++++++++++++++++++++++++ tests/test_ema.py | 199 ++++++++++++++++++++++++++++++++ 8 files changed, 769 insertions(+), 1 deletion(-) create mode 100644 fairseq/models/ema/__init__.py create mode 100644 fairseq/models/ema/ema.py create mode 100644 tests/gpu/test_ema_gpu.py create mode 100644 tests/test_ema.py diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index b8c46f8253..ef5d4c9022 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -810,3 +810,49 @@ def verify_checkpoint_directory(save_dir: str) -> None: raise e else: os.remove(temp_file_path) + + +def load_ema_from_checkpoint(fpath): + """Loads exponential moving averaged (EMA) checkpoint from input and + returns a model with ema weights. + + Args: + fpath: A string path of checkpoint to load from. + + Returns: + A dict of string keys mapping to various values. The 'model' key + from the returned dict should correspond to an OrderedDict mapping + string parameter names to torch Tensors. + """ + params_dict = collections.OrderedDict() + new_state = None + + with PathManager.open(fpath, 'rb') as f: + new_state = torch.load( + f, + map_location=( + lambda s, _: torch.serialization.default_restore_location(s, 'cpu') + ), + ) + + # EMA model is stored in a separate "extra state" + model_params = new_state['extra_state']['ema'] + + for key in list(model_params.keys()): + p = model_params[key] + if isinstance(p, torch.HalfTensor): + p = p.float() + if key not in params_dict: + params_dict[key] = p.clone() + # NOTE: clone() is needed in case of p is a shared parameter + else: + raise ValueError("Key {} is repeated in EMA model params.".format(key)) + + if len(params_dict) == 0: + raise ValueError( + f"Input checkpoint path '{fpath}' does not contain " + "ema model weights, is this model trained with EMA?" + ) + + new_state['model'] = params_dict + return new_state diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 6a86ea0192..952f1ec4d1 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -984,6 +984,36 @@ class InteractiveConfig(FairseqDataclass): ) +@dataclass +class EMAConfig(FairseqDataclass): + store_ema: bool = field( + default=False, metadata={ + help: "store exponential moving average shadow model" + } + ) + ema_decay: float = field( + default=0.9999, metadata={ + "help": 'decay for exponential moving average model' + } + ) + ema_start_update : int = field( + default=0, metadata={"help": "start EMA update after this many model updates"} + ) + ema_seed_model : Optional[str] = field( + default=None, metadata={ + "help": "Seed to load EMA model from. " + "Used to load EMA model separately from the actual model." + } + ) + ema_update_freq : int = field( + default=1, metadata={"help": "Do EMA update every this many model updates"} + ) + ema_fp32: bool = field( + default=False, + metadata={"help": "If true, store EMA model in fp32 even if model is in fp16"}, + ) + + @dataclass class FairseqConfig(FairseqDataclass): common: CommonConfig = CommonConfig() @@ -1004,3 +1034,4 @@ class FairseqConfig(FairseqDataclass): scoring: Any = None bpe: Any = None tokenizer: Any = None + ema: EMAConfig = EMAConfig() diff --git a/fairseq/models/ema/__init__.py b/fairseq/models/ema/__init__.py new file mode 100644 index 0000000000..503ceaa609 --- /dev/null +++ b/fairseq/models/ema/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import importlib +import os + +from .ema import EMA + + +def build_ema(model, cfg, device): + return EMA(model, cfg, device) + + +# automatically import any Python files in the models/ema/ directory +for file in sorted(os.listdir(os.path.dirname(__file__))): + if file.endswith(".py") and not file.startswith("_"): + file_name = file[: file.find(".py")] + importlib.import_module("fairseq.models.ema." + file_name) diff --git a/fairseq/models/ema/ema.py b/fairseq/models/ema/ema.py new file mode 100644 index 0000000000..6c0af69325 --- /dev/null +++ b/fairseq/models/ema/ema.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 + +""" +This module has the EMA class used to store a copy of the exponentially decayed +model params. + +Typical usage of EMA class involves initializing an object using an existing +model (random or from a seed model) and setting the config like ema_decay, +ema_start_update which determine how the EMA model is updated. After every +update of the model i.e. at the end of the train_step, the EMA should be updated +by passing the new model to the EMA.step function. The EMA model state dict +can be stored in the extra state under the key of "ema" and dumped +into a checkpoint and loaded. The EMA object can be passed to tasks +by setting task.uses_ema property. +EMA is a smoothed/ensemble model which might have better performance +when used for inference or further fine-tuning. EMA class has a +reverse function to load the EMA params into a model and use it +like a regular model. +""" + +import copy +import logging + +import torch +from fairseq import checkpoint_utils + + +class EMA(object): + """Exponential Moving Average of Fairseq Models + EMA keeps a copy of the exponentially decayed model params. + The set of params should include both gradient-descent and + non-gradient descent params, such as batch mean/var and buffers. + This is a modified implementation of + the open source code in https://github.com/zhawe01/fairseq-gec.git, + and internal source code in + fbcode/mobile-vision/projects/classification_pytorch/lib/utils/model_ema.py. + + Similar to TF EMA. + https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage. + EMA provides a averaged and smoothed set of model weights, and has been shown to + improve vision models. EMA class does all necessary functions to update, reload, + or init EMA methods. + + EMA object is initialized from an arbitrary model. By default, it is stored in + the same device (unless device specified at initialization) and with the + same precision as the model (unless ema_fp32 is True). ema_fp32 is recommended. + This stores the EMA parameters in fp32 only for the EMA update step, and + is used at the default precision otherwise. + EMA is usually enabled using EMAConfig with store_ema=True. Some important + parameters to configure EMA are + 1) ema_decay - The decay of EMA + 2) ema_update_freq - EMA is updated every this many model updates. + 3) ema_start_update - Start EMA update after this many model updates [default 0] + + Key methods: + 1) step - One update of EMA using new model + 2) restore - Update EMA from a state dict + 3) reverse - Load EMA into a model + 4) get_decay, _set_decay - Used to get or set the decay. Note _set_decay is + called from step. + 5) build_fp32_params - Used to initialize or update the fp32 copy of EMA params. + Note this is enabled only when ema_fp32=True + """ + + def __init__(self, model, config, device=None): + """ + @param model model to initialize the EMA with + @param config EMAConfig object with configuration like + ema_decay, ema_update_freq, ema_fp32 + @param device If provided, copy EMA to this device (e.g. gpu). + Otherwise EMA is in the same device as the model. + """ + + self.decay = config.ema_decay + self.model = copy.deepcopy(model) + self.model.requires_grad_(False) + self.config = config + self.fp32_params = {} + + if self.config.ema_seed_model is not None: + state = checkpoint_utils.load_ema_from_checkpoint(self.config.ema_seed_model) + self.model.load_state_dict(state["model"], strict=True) + + if device is not None: + logging.info(f"Copying EMA model to device {device}") + self.model = self.model.to(device=device) + + if self.config.ema_fp32: + self.build_fp32_params() + + self.update_freq_counter = 0 + + def get_model(self): + return self.model + + def build_fp32_params(self, state_dict=None): + """ + Store a copy of the EMA params in fp32. + If state dict is passed, the EMA params is copied from + the provided state dict. Otherwise, it is copied from the + current EMA model parameters. + """ + if not self.config.ema_fp32: + raise RuntimeError( + "build_fp32_params should not be called if ema_fp32=False. " + "Use ema_fp32=True if this is really intended." + ) + + if state_dict is None: + state_dict = self.model.state_dict() + + def _to_float(t): + return t.float() if torch.is_floating_point(t) else t + + for param_key in state_dict: + if param_key in self.fp32_params: + self.fp32_params[param_key].copy_(state_dict[param_key]) + else: + self.fp32_params[param_key] = _to_float(state_dict[param_key]) + + def restore(self, state_dict, build_fp32_params=False): + """ Load data from a model spec into EMA model """ + self.model.load_state_dict(state_dict, strict=False) + if build_fp32_params: + self.build_fp32_params(state_dict) + + def _set_decay(self, decay): + self.decay = decay + + def get_decay(self): + return self.decay + + def _step_internal(self, new_model, updates=None): + """ One update of the EMA model based on new model weights """ + decay = self.decay + + ema_state_dict = {} + ema_params = self.fp32_params if self.config.ema_fp32 else self.model.state_dict() + for key, param in new_model.state_dict().items(): + try: + ema_param = ema_params[key] + except KeyError: + ema_param = param.float().clone() if param.ndim == 1 else copy.deepcopy(param) + + if param.shape != ema_param.shape: + raise ValueError( + "incompatible tensor shapes between model param and ema param" + + "{} vs. {}".format(param.shape, ema_param.shape) + ) + if "version" in key: + # Do not decay a model.version pytorch param + continue + ema_param.mul_(decay) + ema_param.add_(param.to(dtype=ema_param.dtype), alpha=1-decay) + ema_state_dict[key] = ema_param + self.restore(ema_state_dict, build_fp32_params=False) + + def step(self, new_model, updates=None): + """ + One update of EMA which is done every self.config.ema_update_freq + updates of the model. + + @param updates The current number of model updates done. + Decay is set of 0 if model updates < ema_start_update, which means + the model will be simply copied over to the EMA. + When model updates >= ema_start_updates, then EMA is updated with + a decay of self.config.ema_decay. + """ + self._set_decay( + 0 + if updates is not None + and updates < self.config.ema_start_update + else self.config.ema_decay + ) + if updates is not None and self.config.ema_update_freq > 1: + self.update_freq_counter += 1 + if self.update_freq_counter >= self.config.ema_update_freq: + self._step_internal(new_model, updates) + self.update_freq_counter = 0 + else: + self._step_internal(new_model, updates) + + def reverse(self, model): + """ + Load the model parameters from EMA model. + Useful for inference or fine-tuning from the EMA model. + """ + model.load_state_dict(self.model.state_dict(), strict=False) + return model diff --git a/fairseq/options.py b/fairseq/options.py index 2d9f8381a7..03883fc561 100644 --- a/fairseq/options.py +++ b/fairseq/options.py @@ -20,6 +20,7 @@ GenerationConfig, InteractiveConfig, OptimizationConfig, + EMAConfig, ) from fairseq.dataclass.utils import gen_parser_from_dataclass @@ -40,6 +41,7 @@ def get_training_parser(default_task="translation"): add_model_args(parser) add_optimization_args(parser) add_checkpoint_args(parser) + add_ema_args(parser) return parser @@ -379,3 +381,8 @@ def get_args( setattr(args, k, v) return args + + +def add_ema_args(parser): + group = parser.add_argument_group("EMA configuration") + gen_parser_from_dataclass(group, EMAConfig()) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index c86b1a51ec..e46ccfe0b8 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -22,6 +22,7 @@ from fairseq.distributed import utils as distributed_utils from fairseq.file_io import PathManager from fairseq.logging import meters, metrics +from fairseq.models.ema import build_ema from fairseq.nan_detector import NanDetector from fairseq.optim import lr_scheduler from omegaconf import OmegaConf @@ -131,6 +132,7 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): self._warn_once = set() self._wrapped_criterion = None self._wrapped_model = None + self._ema = None # TODO(myleott): support tpu if self.cuda and self.data_parallel_world_size > 1: @@ -256,6 +258,19 @@ def model(self): self._wrapped_model = self._model return self._wrapped_model + @property + def ema(self): + if self._ema is None: + self._build_ema() + return self._ema + + def _build_ema(self): + if self.cfg.ema.store_ema: + self._ema = build_ema(self._model, self.cfg.ema, self.device) + logger.info( + "Exponential Moving Average Shadow Model is initialized." + ) + @property def optimizer(self): if self._optimizer is None: @@ -392,6 +407,12 @@ def state_dict(self): "previous_training_time": self.cumulative_training_time(), }, } + if self.cfg.ema.store_ema: + # Save EMA model state as extra state + state_dict["extra_state"]["ema"] = self.ema.get_model().state_dict() + if self.cfg.ema.ema_fp32: + # Save EMA params in fp32 + state_dict["extra_state"]["ema_fp32_params"] = self.ema.fp32_params if not self.cfg.checkpoint.no_save_optimizer_state: if self._gathered_optim_state is not None: state_dict["last_optimizer_state"] = self._gathered_optim_state @@ -552,6 +573,31 @@ def load_checkpoint( if isinstance(meter, meters.TimeMeter): meter.reset() + if self.cfg.ema.store_ema: + if "ema" not in extra_state: + logger.warn( + "EMA not found in checkpoint. But store_ema is True. " + "EMA is re-initialized from checkpoint." + ) + self.ema.restore(state["model"], build_fp32_params=self.cfg.ema.ema_fp32) + else: + logger.info( + "Loading EMA from checkpoint" + ) + self.ema.restore(extra_state["ema"], build_fp32_params=False) + + if self.cfg.ema.ema_fp32: + if "ema_fp32_params" in extra_state: + logger.info( + "Loading EMA fp32 params from checkpoint" + ) + self.ema.build_fp32_params(extra_state["ema_fp32_params"]) + else: + logger.info( + "Building EMA fp32 params from EMA model in checkpoint" + ) + self.ema.build_fp32_params() + logger.info( "Loaded checkpoint {} (epoch {} @ {} updates)".format( filename, epoch, self.get_num_updates() @@ -670,6 +716,13 @@ def train_step(self, samples, raise_oom=False): metrics.log_start_time("train_wall", priority=800, round=0) + # If EMA is enabled through store_ema=True + # and task.uses_ema is True, pass the EMA model as a keyword + # argument to the task. + extra_kwargs = {} + if self.cfg.ema.store_ema and getattr(self.task, "uses_ema", False): + extra_kwargs["ema_model"] = self.ema.get_model() + # forward and backward pass logging_outputs, sample_size, ooms = [], 0, 0 for i, sample in enumerate(samples): # delayed update loop @@ -705,6 +758,7 @@ def maybe_no_sync(): optimizer=self.optimizer, update_num=self.get_num_updates(), ignore_grad=is_dummy_batch, + **extra_kwargs, ) del loss @@ -840,6 +894,7 @@ def maybe_no_sync(): self.optimizer, self.get_num_updates(), ignore_grad=False, + **extra_kwargs, ) raise except OverflowError as e: @@ -871,6 +926,20 @@ def maybe_no_sync(): if not overflow or self.cfg.distributed_training.ddp_backend == "slow_mo": self.set_num_updates(self.get_num_updates() + 1) + if self.cfg.ema.store_ema: + # Step EMA forward with new model. + self.ema.step( + self.get_model(), + self.get_num_updates(), + ) + metrics.log_scalar( + "ema_decay", + self.ema.get_decay(), + priority=10000, + round=5, + weight=0, + ) + if self.tpu: import torch_xla.core.xla_model as xm @@ -953,6 +1022,13 @@ def valid_step(self, sample, raise_oom=False): xm.rendezvous("valid_step") # wait for all workers + # If EMA is enabled through store_ema=True + # and task.uses_ema is True, pass the EMA model as a keyword + # argument to the task. + extra_kwargs = {} + if self.cfg.ema.store_ema and getattr(self.task, "uses_ema", False): + extra_kwargs["ema_model"] = self.ema.get_model() + with torch.no_grad(): self.model.eval() self.criterion.eval() @@ -961,7 +1037,7 @@ def valid_step(self, sample, raise_oom=False): try: _loss, sample_size, logging_output = self.task.valid_step( - sample, self.model, self.criterion + sample, self.model, self.criterion, **extra_kwargs ) except RuntimeError as e: if "out of memory" in str(e): diff --git a/tests/gpu/test_ema_gpu.py b/tests/gpu/test_ema_gpu.py new file mode 100644 index 0000000000..337107d69a --- /dev/null +++ b/tests/gpu/test_ema_gpu.py @@ -0,0 +1,200 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from copy import deepcopy +from dataclasses import dataclass +from typing import Optional + +import torch +from fairseq.models.ema import EMA + + +class DummyModule(torch.nn.Module): + def __init__(self) -> None: + """LightningModule for testing purposes + + Args: + epoch_min_loss_override (int, optional): Pass in an epoch that will be set to the minimum + validation loss for testing purposes (zero based). If None this is ignored. Defaults to None. + """ + super().__init__() + self.layer = torch.nn.Linear(in_features=32, out_features=2) + self.another_layer = torch.nn.Linear(in_features=2, out_features=2) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.layer(x) + return self.another_layer(x) + + +@dataclass +class EMAConfig(object): + ema_decay: float = 0.99 + ema_start_update: int = 0 + ema_fp32: bool = False + ema_seed_model: Optional[str] = None + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestEMAGPU(unittest.TestCase): + def assertTorchAllClose(self, x, y, atol=1e-8, rtol=1e-5, msg=None): + diff = x.float() - y.float() + diff_norm = torch.norm(diff) + other_norm = torch.norm(y.float()) + + if msg is None: + msg = "|input - other| > {} + {} * |other|".format( + atol, rtol + ) + + self.assertLessEqual( + diff_norm, + atol + rtol * other_norm, + msg=msg, + ) + + def test_ema(self): + model = DummyModule().cuda() + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + state = deepcopy(model.state_dict()) + config = EMAConfig() + ema = EMA(model, config) + + # set decay + ema._set_decay(config.ema_decay) + self.assertEqual(ema.get_decay(), config.ema_decay) + + # get model + self.assertEqual(ema.get_model(), ema.model) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + # EMA step + x = torch.randn(32).cuda() + y = model(x) + loss = y.sum() + loss.backward() + optimizer.step() + + ema.step(model) + + ema_state_dict = ema.get_model().state_dict() + + for key, param in model.state_dict().items(): + prev_param = state[key] + ema_param = ema_state_dict[key] + + if "version" in key: + # Do not decay a model.version pytorch param + continue + self.assertTorchAllClose( + ema_param, + config.ema_decay * prev_param + (1 - config.ema_decay) * param, + ) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + # Load EMA into model + model2 = DummyModule().cuda() + ema.reverse(model2) + + for key, param in model2.state_dict().items(): + ema_param = ema_state_dict[key] + self.assertTrue( + torch.allclose(ema_param, param) + ) + + def test_ema_fp32(self): + model = DummyModule().cuda().half() + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + state = deepcopy(model.state_dict()) + config = EMAConfig(ema_fp32=True) + ema = EMA(model, config) + + x = torch.randn(32).cuda() + y = model(x.half()) + loss = y.sum() + loss.backward() + optimizer.step() + + ema.step(model) + + for key, param in model.state_dict().items(): + prev_param = state[key] + ema_param = ema.get_model().state_dict()[key] + + if "version" in key: + # Do not decay a model.version pytorch param + continue + self.assertIn(key, ema.fp32_params) + + # EMA update is done in fp32, and hence the EMA param must be + # closer to the EMA update done in fp32 than in fp16. + self.assertLessEqual( + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ), + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ), + ) + self.assertTorchAllClose( + ema_param, + (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half(), + ) + + def test_ema_fp16(self): + model = DummyModule().cuda().half() + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + state = deepcopy(model.state_dict()) + config = EMAConfig(ema_fp32=False) + ema = EMA(model, config) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + x = torch.randn(32).cuda() + y = model(x.half()) + loss = y.sum() + loss.backward() + optimizer.step() + + ema.step(model) + + for key, param in model.state_dict().items(): + prev_param = state[key] + ema_param = ema.get_model().state_dict()[key] + + if "version" in key: + # Do not decay a model.version pytorch param + continue + + # EMA update is done in fp16, and hence the EMA param must be + # closer to the EMA update done in fp16 than in fp32. + self.assertLessEqual( + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ), + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ), + ) + self.assertTorchAllClose( + ema_param, + config.ema_decay * prev_param + (1 - config.ema_decay) * param, + ) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_ema.py b/tests/test_ema.py new file mode 100644 index 0000000000..88ea65a434 --- /dev/null +++ b/tests/test_ema.py @@ -0,0 +1,199 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from copy import deepcopy +from dataclasses import dataclass +from typing import Optional + +import torch +from fairseq.models.ema import EMA + + +class DummyModule(torch.nn.Module): + def __init__(self) -> None: + """LightningModule for testing purposes + + Args: + epoch_min_loss_override (int, optional): Pass in an epoch that will be set to the minimum + validation loss for testing purposes (zero based). If None this is ignored. Defaults to None. + """ + super().__init__() + self.layer = torch.nn.Linear(in_features=32, out_features=2) + self.another_layer = torch.nn.Linear(in_features=2, out_features=2) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + x = self.layer(x) + return self.another_layer(x) + + +@dataclass +class EMAConfig(object): + ema_decay: float = 0.99 + ema_start_update: int = 0 + ema_fp32: bool = False + ema_seed_model: Optional[str] = None + + +class TestEMAGPU(unittest.TestCase): + def assertTorchAllClose(self, x, y, atol=1e-8, rtol=1e-5, msg=None): + diff = x.float() - y.float() + diff_norm = torch.norm(diff) + other_norm = torch.norm(y.float()) + + if msg is None: + msg = "|input - other| > {} + {} * |other|".format( + atol, rtol + ) + + self.assertLessEqual( + diff_norm, + atol + rtol * other_norm, + msg=msg, + ) + + def test_ema(self): + model = DummyModule() + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + state = deepcopy(model.state_dict()) + config = EMAConfig() + ema = EMA(model, config) + + # set decay + ema._set_decay(config.ema_decay) + self.assertEqual(ema.get_decay(), config.ema_decay) + + # get model + self.assertEqual(ema.get_model(), ema.model) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + # EMA step + x = torch.randn(32) + y = model(x) + loss = y.sum() + loss.backward() + optimizer.step() + + ema.step(model) + + ema_state_dict = ema.get_model().state_dict() + + for key, param in model.state_dict().items(): + prev_param = state[key] + ema_param = ema_state_dict[key] + + if "version" in key: + # Do not decay a model.version pytorch param + continue + self.assertTorchAllClose( + ema_param, + config.ema_decay * prev_param + (1 - config.ema_decay) * param, + ) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + # Load EMA into model + model2 = DummyModule() + ema.reverse(model2) + + for key, param in model2.state_dict().items(): + ema_param = ema_state_dict[key] + self.assertTrue( + torch.allclose(ema_param, param) + ) + + def test_ema_fp32(self): + model = DummyModule().half() + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + state = deepcopy(model.state_dict()) + config = EMAConfig(ema_fp32=True) + ema = EMA(model, config) + + x = torch.randn(32) + y = model(x.half()) + loss = y.sum() + loss.backward() + optimizer.step() + + ema.step(model) + + for key, param in model.state_dict().items(): + prev_param = state[key] + ema_param = ema.get_model().state_dict()[key] + + if "version" in key: + # Do not decay a model.version pytorch param + continue + self.assertIn(key, ema.fp32_params) + + # EMA update is done in fp32, and hence the EMA param must be + # closer to the EMA update done in fp32 than in fp16. + self.assertLessEqual( + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ), + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ), + ) + self.assertTorchAllClose( + ema_param, + (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half(), + ) + + def test_ema_fp16(self): + model = DummyModule().half() + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + state = deepcopy(model.state_dict()) + config = EMAConfig(ema_fp32=False) + ema = EMA(model, config) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + x = torch.randn(32) + y = model(x.half()) + loss = y.sum() + loss.backward() + optimizer.step() + + ema.step(model) + + for key, param in model.state_dict().items(): + prev_param = state[key] + ema_param = ema.get_model().state_dict()[key] + + if "version" in key: + # Do not decay a model.version pytorch param + continue + + # EMA update is done in fp16, and hence the EMA param must be + # closer to the EMA update done in fp16 than in fp32. + self.assertLessEqual( + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ), + torch.norm( + ema_param.float() - + (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ), + ) + self.assertTorchAllClose( + ema_param, + config.ema_decay * prev_param + (1 - config.ema_decay) * param, + ) + + # Since fp32 params is not used, it should be of size 0 + self.assertEqual(len(ema.fp32_params), 0) + + +if __name__ == "__main__": + unittest.main() From 14c5bd027f04aae9dbb32f1bd7b34591b61af97f Mon Sep 17 00:00:00 2001 From: Koustuv Sinha <koustuvsinha@hotmail.com> Date: Wed, 1 Sep 2021 13:13:08 -0700 Subject: [PATCH 448/774] Releasing models for our paper "Masked Language Modeling and the Distributional Hypothesis" (#1930) Summary: Paper submitted to EMNLP: https://arxiv.org/abs/2104.06644 Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/1930 Reviewed By: lematt1991 Differential Revision: D28885634 Pulled By: shruti-bh fbshipit-source-id: d433c87cff3603b3e676a129029a827c510a72c7 --- .../shuffled_word_order/README.finetuning.md | 135 ++++++++++++++++++ examples/shuffled_word_order/README.md | 84 +++++++++++ 2 files changed, 219 insertions(+) create mode 100644 examples/shuffled_word_order/README.finetuning.md create mode 100644 examples/shuffled_word_order/README.md diff --git a/examples/shuffled_word_order/README.finetuning.md b/examples/shuffled_word_order/README.finetuning.md new file mode 100644 index 0000000000..ecbcb65884 --- /dev/null +++ b/examples/shuffled_word_order/README.finetuning.md @@ -0,0 +1,135 @@ +# Fine-tuning details + +For each task (GLUE and PAWS), we perform hyperparam search for each model, and report the mean and standard deviation across 5 seeds of the best model. First, get the datasets following the instructions in [RoBERTa fine-tuning README](../roberta/README.glue.md). Alternatively, you can use [huggingface datasets](https://huggingface.co/docs/datasets/) to get the task data: + +```python +from datasets import load_dataset +import pandas as pd +from pathlib import Path + +key2file = { +"paws": { + "loc": "paws_data", + "columns": ["id", "sentence1", "sentence2", "label"], + "train": "train.tsv", + "validation": "dev.tsv", + "test": "test.tsv" + } +} + +task_data = load_dataset("paws", "labeled_final") +task_config = key2file["paws"] +save_path = Path(task_config["loc"]) +save_path.mkdir(exist_ok=True, parents=True) +for key, fl in task_config.items(): + if key in ["loc", "columns"]: + continue + print(f"Reading {key}") + columns = task_config["columns"] + df = pd.DataFrame(task_data[key]) + print(df.columns) + df = df[columns] + print(f"Got {len(df)} records") + save_loc = save_path / fl + print(f"Saving to : {save_loc}") + df.to_csv(save_loc, sep="\t", header=None, index=None) + +``` + +- Preprocess using RoBERTa GLUE preprocessing script, while keeping in mind the column numbers for `sentence1`, `sentence2` and `label` (which is 0,1,2 if you save the data according to the above example.) +- Then, fine-tuning is performed similarly to RoBERTa (for example, in case of RTE): + +```bash +TOTAL_NUM_UPDATES=30875 # 10 epochs through RTE for bsz 16 +WARMUP_UPDATES=1852 # 6 percent of the number of updates +LR=2e-05 # Peak LR for polynomial LR scheduler. +NUM_CLASSES=2 +MAX_SENTENCES=16 # Batch size. +SHUFFLED_ROBERTA_PATH=/path/to/shuffled_roberta/model.pt + +CUDA_VISIBLE_DEVICES=0 fairseq-train RTE-bin/ \ + --restore-file $SHUFFLED_ROBERTA_PATH \ + --max-positions 512 \ + --batch-size $MAX_SENTENCES \ + --max-tokens 4400 \ + --task sentence_prediction \ + --reset-optimizer --reset-dataloader --reset-meters \ + --required-batch-size-multiple 1 \ + --init-token 0 --separator-token 2 \ + --arch roberta_large \ + --criterion sentence_prediction \ + --num-classes $NUM_CLASSES \ + --dropout 0.1 --attention-dropout 0.1 \ + --weight-decay 0.1 --optimizer adam --adam-betas "(0.9, 0.98)" --adam-eps 1e-06 \ + --clip-norm 0.0 \ + --lr-scheduler polynomial_decay --lr $LR --total-num-update $TOTAL_NUM_UPDATES --warmup-updates $WARMUP_UPDATES \ + --fp16 --fp16-init-scale 4 --threshold-loss-scale 1 --fp16-scale-window 128 \ + --max-epoch 10 \ + --find-unused-parameters \ + --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric; +``` + +- `TOTAL_NUM_UPDATES` is computed based on the `--batch_size` value and the dataset size. +- `WARMUP_UPDATES` is computed as 6% of `TOTAL_NUM_UPDATES` +- Best hyperparam of `--lr` and `--batch_size` is reported below: + +## `--lr` + +| | name | RTE | MRPC | SST-2 | CoLA | QQP | QNLI | MNLI | PAWS | +| --: | :----------- | ----: | ----: | ----: | ----: | ----: | ----: | ----: | ----: | +| 0 | original | 2e-05 | 2e-05 | 1e-05 | 2e-05 | 1e-05 | 1e-05 | 1e-05 | 2e-05 | +| 1 | n_1 | 2e-05 | 1e-05 | 1e-05 | 1e-05 | 3e-05 | 1e-05 | 2e-05 | 2e-05 | +| 2 | n_2 | 2e-05 | 2e-05 | 1e-05 | 1e-05 | 2e-05 | 1e-05 | 1e-05 | 3e-05 | +| 3 | n_3 | 3e-05 | 1e-05 | 2e-05 | 2e-05 | 3e-05 | 1e-05 | 1e-05 | 2e-05 | +| 4 | n_4 | 3e-05 | 1e-05 | 2e-05 | 2e-05 | 2e-05 | 1e-05 | 1e-05 | 2e-05 | +| 5 | r512 | 1e-05 | 3e-05 | 2e-05 | 2e-05 | 3e-05 | 2e-05 | 3e-05 | 2e-05 | +| 6 | rand_corpus | 2e-05 | 1e-05 | 3e-05 | 1e-05 | 3e-05 | 3e-05 | 3e-05 | 2e-05 | +| 7 | rand_uniform | 2e-05 | 1e-05 | 3e-05 | 2e-05 | 3e-05 | 3e-05 | 3e-05 | 1e-05 | +| 8 | rand_init | 1e-05 | 1e-05 | 3e-05 | 1e-05 | 1e-05 | 1e-05 | 2e-05 | 1e-05 | +| 9 | no_pos | 1e-05 | 3e-05 | 2e-05 | 1e-05 | 1e-05 | 1e-05 | 1e-05 | 1e-05 | + +## `--batch_size` + +| | name | RTE | MRPC | SST-2 | CoLA | QQP | QNLI | MNLI | PAWS | +| --: | :----------- | --: | ---: | ----: | ---: | --: | ---: | ---: | ---: | +| 0 | orig | 16 | 16 | 32 | 16 | 16 | 32 | 32 | 16 | +| 1 | n_1 | 32 | 32 | 16 | 32 | 32 | 16 | 32 | 16 | +| 2 | n_2 | 32 | 16 | 32 | 16 | 32 | 32 | 16 | 32 | +| 3 | n_3 | 32 | 32 | 16 | 32 | 32 | 16 | 32 | 32 | +| 4 | n_4 | 32 | 16 | 32 | 16 | 32 | 32 | 32 | 32 | +| 5 | r512 | 32 | 16 | 16 | 32 | 32 | 16 | 16 | 16 | +| 6 | rand_corpus | 16 | 16 | 16 | 16 | 32 | 16 | 16 | 32 | +| 7 | rand_uniform | 16 | 32 | 16 | 16 | 32 | 16 | 16 | 16 | +| 8 | rand_init | 16 | 16 | 32 | 16 | 16 | 16 | 32 | 16 | +| 9 | no_pos | 16 | 32 | 16 | 16 | 32 | 16 | 16 | 16 | + +- Perform inference similar to RoBERTa as well: + +```python +from fairseq.models.roberta import RobertaModel + +roberta = RobertaModel.from_pretrained( + 'checkpoints/', + checkpoint_file='checkpoint_best.pt', + data_name_or_path='PAWS-bin' +) + +label_fn = lambda label: roberta.task.label_dictionary.string( + [label + roberta.task.label_dictionary.nspecial] +) +ncorrect, nsamples = 0, 0 +roberta.cuda() +roberta.eval() +with open('paws_data/dev.tsv') as fin: + fin.readline() + for index, line in enumerate(fin): + tokens = line.strip().split('\t') + sent1, sent2, target = tokens[0], tokens[1], tokens[2] + tokens = roberta.encode(sent1, sent2) + prediction = roberta.predict('sentence_classification_head', tokens).argmax().item() + prediction_label = label_fn(prediction) + ncorrect += int(prediction_label == target) + nsamples += 1 +print('| Accuracy: ', float(ncorrect)/float(nsamples)) + +``` diff --git a/examples/shuffled_word_order/README.md b/examples/shuffled_word_order/README.md new file mode 100644 index 0000000000..14c240cb56 --- /dev/null +++ b/examples/shuffled_word_order/README.md @@ -0,0 +1,84 @@ +# Masked Language Modeling and the Distributional Hypothesis: Order Word Matters Pre-training for Little + +[https://arxiv.org/abs/2104.06644](https://arxiv.org/abs/2104.06644) + +## Introduction + +In this work, we pre-train [RoBERTa](../roberta) base on various word shuffled variants of BookWiki corpus (16GB). We observe that a word shuffled pre-trained model achieves surprisingly good scores on GLUE, PAWS and several parametric probing tasks. Please read our paper for more details on the experiments. + +## Pre-trained models + +| Model | Description | Download | +| ------------------------------------- | -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | +| `roberta.base.orig` | RoBERTa (base) trained on natural corpus | [roberta.base.orig.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.orig.tar.gz) | +| `roberta.base.shuffle.n1` | RoBERTa (base) trained on n=1 gram sentence word shuffled data | [roberta.base.shuffle.n1.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n1.tar.gz) | +| `roberta.base.shuffle.n2` | RoBERTa (base) trained on n=2 gram sentence word shuffled data | [roberta.base.shuffle.n2.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n2.tar.gz) | +| `roberta.base.shuffle.n3` | RoBERTa (base) trained on n=3 gram sentence word shuffled data | [roberta.base.shuffle.n3.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n3.tar.gz) | +| `roberta.base.shuffle.n4` | RoBERTa (base) trained on n=4 gram sentence word shuffled data | [roberta.base.shuffle.n4.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n4.tar.gz) | +| `roberta.base.shuffle.512` | RoBERTa (base) trained on unigram 512 word block shuffled data | [roberta.base.shuffle.512.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.512.tar.gz) | +| `roberta.base.shuffle.corpus` | RoBERTa (base) trained on unigram corpus word shuffled data | [roberta.base.shuffle.corpus.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.corpus.tar.gz) | +| `roberta.base.shuffle.corpus_uniform` | RoBERTa (base) trained on unigram corpus word shuffled data, where all words are uniformly sampled | [roberta.base.shuffle.corpus_uniform.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.corpus_uniform.tar.gz) | +| `roberta.base.nopos` | RoBERTa (base) without positional embeddings, trained on natural corpus | [roberta.base.nopos.tar.gz](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.nopos.tar.gz) | + +## Results + +[GLUE (Wang et al, 2019)](https://gluebenchmark.com/) & [PAWS (Zhang et al, 2019)](https://github.com/google-research-datasets/paws) _(dev set, single model, single-task fine-tuning, median of 5 seeds)_ + +| name | CoLA | MNLI | MRPC | PAWS | QNLI | QQP | RTE | SST-2 | +| :----------------------------------- | ----: | ----: | ----: | ----: | ----: | ----: | ----: | ----: | +| `roberta.base.orig` | 61.4 | 86.11 | 89.19 | 94.46 | 92.53 | 91.26 | 74.64 | 93.92 | +| `roberta.base.shuffle.n1` | 35.15 | 82.64 | 86 | 89.97 | 89.02 | 91.01 | 69.02 | 90.47 | +| `roberta.base.shuffle.n2` | 54.37 | 83.43 | 86.24 | 93.46 | 90.44 | 91.36 | 70.83 | 91.79 | +| `roberta.base.shuffle.n3` | 48.72 | 83.85 | 86.36 | 94.05 | 91.69 | 91.24 | 70.65 | 92.02 | +| `roberta.base.shuffle.n4` | 58.64 | 83.77 | 86.98 | 94.32 | 91.69 | 91.4 | 70.83 | 92.48 | +| `roberta.base.shuffle.512` | 12.76 | 77.52 | 79.61 | 84.77 | 85.19 | 90.2 | 56.52 | 86.34 | +| `roberta.base.shuffle.corpus` | 0 | 71.9 | 70.52 | 58.52 | 71.11 | 85.52 | 53.99 | 83.35 | +| `roberta.base.shuffle.corpus_random` | 9.19 | 72.33 | 70.76 | 58.42 | 77.76 | 85.93 | 53.99 | 84.04 | +| `roberta.base.nopos` | 0 | 63.5 | 72.73 | 57.08 | 77.72 | 87.87 | 54.35 | 83.24 | + +For more results on probing tasks, please refer to [our paper](https://arxiv.org/abs/2104.06644). + +## Example Usage + +Follow the same usage as in [RoBERTa](https://github.com/pytorch/fairseq/tree/master/examples/roberta) to load and test your models: + +```python +# Download roberta.base.shuffle.n1 model +wget https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n1.tar.gz +tar -xzvf roberta.base.shuffle.n1.tar.gz + +# Load the model in fairseq +from fairseq.models.roberta import RoBERTaModel +roberta = RoBERTaModel.from_pretrained('/path/to/roberta.base.shuffle.n1', checkpoint_file='model.pt') +roberta.eval() # disable dropout (or leave in train mode to finetune) +``` + +**Note**: The model trained without positional embeddings (`roberta.base.nopos`) is a modified `RoBERTa` model, where the positional embeddings are not used. Thus, the typical `from_pretrained` method on fairseq version of RoBERTa will not be able to load the above model weights. To do so, construct a new `RoBERTaModel` object by setting the flag `use_positional_embeddings` to `False` (or [in the latest code](https://github.com/pytorch/fairseq/blob/master/fairseq/models/roberta/model.py#L543), set `no_token_positional_embeddings` to `True`), and then load the individual weights. + +## Fine-tuning Evaluation + +We provide the trained fine-tuned models on MNLI here for each model above for quick evaluation (1 seed for each model). Please refer to [finetuning details](README.finetuning.md) for the parameters of these models. Follow [RoBERTa](https://github.com/pytorch/fairseq/tree/master/examples/roberta) instructions to evaluate these models. + +| Model | MNLI M Dev Accuracy | Link | +| :----------------------------------------- | :------------------ | :--------------------------------------------------------------------------------------------------------------- | +| `roberta.base.orig.mnli` | 86.14 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.orig.mnli.tar.gz) | +| `roberta.base.shuffle.n1.mnli` | 82.55 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n1.mnli.tar.gz) | +| `roberta.base.shuffle.n2.mnli` | 83.21 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n2.mnli.tar.gz) | +| `roberta.base.shuffle.n3.mnli` | 83.89 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n3.mnli.tar.gz) | +| `roberta.base.shuffle.n4.mnli` | 84.00 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n4.mnli.tar.gz) | +| `roberta.base.shuffle.512.mnli` | 77.22 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.512.mnli.tar.gz) | +| `roberta.base.shuffle.corpus.mnli` | 71.88 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.corpus.mnli.tar.gz) | +| `roberta.base.shuffle.corpus_uniform.mnli` | 72.46 | [Download](https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.corpus_uniform.mnli.tar.gz) | + +## Citation + +```bibtex +@misc{sinha2021masked, + title={Masked Language Modeling and the Distributional Hypothesis: Order Word Matters Pre-training for Little}, + author={Koustuv Sinha and Robin Jia and Dieuwke Hupkes and Joelle Pineau and Adina Williams and Douwe Kiela}, + year={2021}, + eprint={2104.06644}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} +``` From 5cfd373876ad374139b2de15735a870d4797c606 Mon Sep 17 00:00:00 2001 From: Jingfei Du <jingfeidu@fb.com> Date: Tue, 7 Sep 2021 13:18:00 -0700 Subject: [PATCH 449/774] fix default lprob score of beam search with prefix tokens (#2267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting the default score was set as min score of all lprobs, which would let us select tokens other than prefix tokens during beam search. having a pretty hacky way to make it smaller than any lprobs. - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2267 Reviewed By: myleott Differential Revision: D30730475 Pulled By: jingfeidu fbshipit-source-id: 7dab4e9ed2fc094910467bad776155230987e21a --- fairseq/sequence_generator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 740c32d648..2e61140dd8 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -343,7 +343,6 @@ def _generate( ) probs = probs[:, -1, :] * self.lm_weight lprobs += probs - # handle prefix tokens (possibly with different lengths) if ( prefix_tokens is not None @@ -568,7 +567,7 @@ def _prefix_tokens( prefix_toks = prefix_tokens[:, step].unsqueeze(-1).repeat(1, beam_size).view(-1) prefix_lprobs = lprobs.gather(-1, prefix_toks.unsqueeze(-1)) prefix_mask = prefix_toks.ne(self.pad) - lprobs[prefix_mask] = torch.min(prefix_lprobs) + lprobs[prefix_mask] = torch.min(prefix_lprobs) - 1 lprobs[prefix_mask] = lprobs[prefix_mask].scatter( -1, prefix_toks[prefix_mask].unsqueeze(-1), prefix_lprobs[prefix_mask] ) From 9549e7f76994095c92441b81c615a169dc21f478 Mon Sep 17 00:00:00 2001 From: Yunhong Xu <yunhong@fb.com> Date: Tue, 7 Sep 2021 15:08:44 -0700 Subject: [PATCH 450/774] try using gradient_as_bucket_view in DDP Summary: As title Reviewed By: zhengwy888, xiaoxiao26 Differential Revision: D30621478 fbshipit-source-id: d79aba3f98d39a5c46a53bf206522c5f7d05e02a --- fairseq/dataclass/configs.py | 7 +++++++ fairseq/models/distributed_fairseq_model.py | 1 + 2 files changed, 8 insertions(+) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 952f1ec4d1..80caa0f2da 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -306,6 +306,13 @@ class DistributedTrainingConfig(FairseqDataclass): "--ddp-backend=legacy_ddp)" }, ) + gradient_as_bucket_view: bool = field( + default=False, + metadata={ + "help": "when set to True, gradients will be views pointing to different offsets of allreduce communication buckets. This can reduce peak memory usage, where the saved memory size will be equal to the total gradients size. " + "--gradient-as-bucket-view=gradient_as_bucket_view)" + }, + ) fast_stat_sync: bool = field( default=False, metadata={"help": "[deprecated] this is now defined per Criterion"}, diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index 06905455fd..5eda227640 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -63,6 +63,7 @@ def DistributedFairseqModel(args, model, process_group, device): bucket_cap_mb=args.bucket_cap_mb, process_group=process_group, find_unused_parameters=args.find_unused_parameters, + gradient_as_bucket_view=args.gradient_as_bucket_view, ) if args.ddp_comm_hook == "fp16": logger.info("enable fp16 communication hook in DDP") From 50b65368639ac25663764e1d4b3cf46b821975ec Mon Sep 17 00:00:00 2001 From: "Yuan Shangguan (June)" <yuansg@fb.com> Date: Wed, 8 Sep 2021 18:16:54 -0700 Subject: [PATCH 451/774] Fairseq needs to store and load metadata from model state_dict Summary: ## TL;DR Fairseq checkpoint saving and loading should mirror torch's checkpoint by saving and loading "state_dict()._metadata". ## Long Story: #### What happened: During model loading and saving, Quantization-aware-training models in Pytorch encounters a weird bug that says state_dict "fake_weight_quant.weight.min_val" is mismatched to "min_vals". #### What was the reason: - We found the issue in that torch uses state_dict()._metadata to store module._version, but the metadata was never store in checkpoint, nor are they loaded during checkpoint loading in fairseq. Reviewed By: frankseide Differential Revision: D30649933 fbshipit-source-id: ce262486b9b95fbcece463fa05c4e1903d4232d7 --- fairseq/checkpoint_utils.py | 37 ++++++++++++++++++++++++++++++--- fairseq/models/fairseq_model.py | 32 ++++++++++++++++++++++++++++ fairseq/trainer.py | 9 +++++++- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index ef5d4c9022..7a494356ac 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) -def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): +def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss, save_metadata=False): from fairseq import meters # only one worker should attempt to create the required dir @@ -114,7 +114,7 @@ def is_better(a, b): os.path.join(cfg.save_dir, fn) for fn, cond in checkpoint_conds.items() if cond ] if len(checkpoints) > 0: - trainer.save_checkpoint(checkpoints[0], extra_state) + trainer.save_checkpoint(checkpoints[0], extra_state, save_metadata) for cp in checkpoints[1:]: if cfg.write_checkpoints_asynchronously: # TODO[ioPath]: Need to implement a delayed asynchronous @@ -455,8 +455,35 @@ def load_model_ensemble_and_task( else: # model parallel checkpoint or unsharded checkpoint model = task.build_model(cfg.model) + new_state_model = state["model"] + + '''=====The following if-else statement is a work-around ===== + # the current metadata loading/saving of pytorch. + # In Pytorch, if state["model"]["_metadata"] exists as dictionary, then model.load_state_dict(strict=True) + # will throw an error for unexpected "_metadata" key. To avoid this error, we need the state_dict to be + # in orderedDict format, which has new_state_model._metadata attribute but not as key. + # TODO yuansg@ This issue should be fixed in pytorch ideally. + ''' + if new_state_model.get("_metadata", None) is not None: + new_metadata = new_state_model.get("_metadata", None) + del state["model"]["_metadata"] + else: + new_metadata = None + # Construct state dict content. + contents = OrderedDict(new_state_model) + # We explicitly set _metadata for the state models. The _metadata is implicitly stored for pytorch models. + # calling state["model"] in fairseq will not invoke metadata storage. + if new_metadata is None: + logger.warning("===Jit: state[\"model\"] does not contain key \"_metadata\"=====") + logger.warning("===Jit: we will be filling in with current model's meta-data instead.") + # For models trained before this diff, we do the following to be backward compatible. + contents.__setattr__("_metadata", model.state_dict()._metadata) + else: + contents.__setattr__("_metadata", new_metadata) + '''====End of work-around logic=====''' + model.load_state_dict( - state["model"], strict=strict, model_cfg=cfg.model + contents, strict=strict, model_cfg=cfg.model ) # reset state so it gets loaded for the next model in ensemble @@ -683,6 +710,7 @@ def prune_state_dict(state_dict, model_cfg: Optional[DictConfig]): It's called by functions that load models from checkpoints and does not need to be called directly. """ + state_meta_data = state_dict.get("_metadata", None) arch = None if model_cfg is not None: arch = ( @@ -762,6 +790,9 @@ def create_pruning_pass(layers_to_keep, layer_name): if hasattr(model_cfg, "decoder_layers_to_keep"): model_cfg.decoder_layers_to_keep = None + # Ensure metadata is stored. + if state_meta_data is not None: + new_state_dict["_metadata"] = state_meta_data return new_state_dict diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index e55c7ba1ad..0645208efe 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -22,6 +22,7 @@ from fairseq.models import FairseqDecoder, FairseqEncoder from omegaconf import DictConfig from torch import Tensor +from collections import OrderedDict logger = logging.getLogger(__name__) @@ -122,6 +123,15 @@ def load_state_dict( from fairseq.checkpoint_utils import prune_state_dict new_state_dict = prune_state_dict(state_dict, model_cfg) + # The pytorch assumption of module is that it is an OrderedDict. + # Pytorch also assumes module._metadata exists in the state_dict, + # not as dictionary keys, rather as an attribute of the state dict. + new_state_dict = OrderedDict(new_state_dict) + metadata = new_state_dict.get("_metadata", None) + + if metadata: + del new_state_dict["_metadata"] + new_state_dict.__setattr__("_metadata", metadata) return super().load_state_dict(new_state_dict, strict) def upgrade_state_dict(self, state_dict): @@ -151,6 +161,28 @@ def do_upgrade(m, prefix): do_upgrade(self, name) + def update_metadata(self, model_meta): + """ The model.state_dict()._metadata is stored in a collective location in + state_dict["model"]["_metadata"]. + A pytorch module's _metadata contains the torch modules' versions, which is important + for versionsetting functions. + + During model loading time, we load the model state_dict, but we don't load the state_dict metadata. + This function helps to update the model according to the state_dict["model"]["_metadata"] dump. + InputArgs: + update_metadata: Dict; key is module names, value is {"version", 1} or other metadata. + """ + # Do nothing if the model level metadata is empty. + if model_meta is None: + return + assert isinstance(model_meta, Dict), \ + "Input model_meta from state_dict should be a dictionary. Check state dict." + for key, val in model_meta.items(): + if key is None: # First level set up + self._metadata = val + else: # Subsequent levels of the model + self.get_submodule(key)._metadata = val + def set_num_updates(self, num_updates): """State from trainer to pass along to model at every update.""" for m in self.modules(): diff --git a/fairseq/trainer.py b/fairseq/trainer.py index e46ccfe0b8..a10ec97aa7 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -424,12 +424,18 @@ def state_dict(self): state_dict["fsdp_metadata"] = self.model.local_metadata_dict() return state_dict - def save_checkpoint(self, filename, extra_state): + def save_checkpoint(self, filename, extra_state, save_metadata=False): """Save all training state in a checkpoint file.""" logger.info(f"Saving checkpoint to {filename}") # call state_dict on all ranks in case it needs internal communication state_dict = utils.move_to_cpu(self.state_dict()) state_dict["extra_state"].update(extra_state) + # This should be added because model versions are stored as metadata. + if save_metadata and getattr(self.model.state_dict(), "_metadata", None) is not None: + logger.warning("Trainer: _metadata is inside model.state_dict(). ") + state_dict["model"]["_metadata"] = self.model.state_dict()._metadata + else: + logger.warning("Trainer: _metadata is not saved inside model.state_dict(). ") if self.should_save_checkpoint_on_current_rank: checkpoint_utils.torch_persistent_save( state_dict, @@ -502,6 +508,7 @@ def load_checkpoint( self.model.load_state_dict( state["model"], strict=True, model_cfg=self.cfg.model ) + self.model.update_metadata(getattr(state["model"], "_metadata", None)) # save memory for later steps del state["model"] if utils.has_parameters(self.get_criterion()): From e3fafbdfc9a39ba8339ebde98aa01c5349ab060d Mon Sep 17 00:00:00 2001 From: Xianfeng Rui <xfrui@fb.com> Date: Thu, 9 Sep 2021 10:09:34 -0700 Subject: [PATCH 452/774] annotation added for jitable Summary: 1) add annotation for encoder_out 2) force dropout to be float for jitable purpose. Reviewed By: cndn Differential Revision: D30826657 fbshipit-source-id: aca79845d7ae48d450b602a7be8f56404f4c7bab --- fairseq/models/lstm.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fairseq/models/lstm.py b/fairseq/models/lstm.py index 12e3aff85d..e1e66a7d50 100644 --- a/fairseq/models/lstm.py +++ b/fairseq/models/lstm.py @@ -225,10 +225,10 @@ def __init__( super().__init__(dictionary) self.num_layers = num_layers self.dropout_in_module = FairseqDropout( - dropout_in, module_name=self.__class__.__name__ + dropout_in*1.0, module_name=self.__class__.__name__ ) self.dropout_out_module = FairseqDropout( - dropout_out, module_name=self.__class__.__name__ + dropout_out*1.0, module_name=self.__class__.__name__ ) self.bidirectional = bidirectional self.hidden_size = hidden_size @@ -329,7 +329,7 @@ def combine_bidir(self, outs, bsz: int): out = outs.view(self.num_layers, 2, bsz, -1).transpose(1, 2).contiguous() return out.view(self.num_layers, bsz, -1) - def reorder_encoder_out(self, encoder_out, new_order): + def reorder_encoder_out(self, encoder_out: Tuple[Tensor, Tensor, Tensor, Tensor], new_order): return tuple( ( encoder_out[0].index_select(1, new_order), @@ -402,10 +402,10 @@ def __init__( ): super().__init__(dictionary) self.dropout_in_module = FairseqDropout( - dropout_in, module_name=self.__class__.__name__ + dropout_in*1.0, module_name=self.__class__.__name__ ) self.dropout_out_module = FairseqDropout( - dropout_out, module_name=self.__class__.__name__ + dropout_out*1.0, module_name=self.__class__.__name__ ) self.hidden_size = hidden_size self.share_input_output_embed = share_input_output_embed From dbe1f82fc8c76d7578081b453398f594e2ae671a Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Sun, 12 Sep 2021 20:19:11 -0700 Subject: [PATCH 453/774] add speech synthesis preprocessing and evaluation scripts Summary: [fairseq-py] add speech synthesis preprocessing and evaluation scripts Reviewed By: wnhsu Differential Revision: D30720282 fbshipit-source-id: 6e4b098b6f56fff41b82af4347518d7f7905c801 --- examples/speech_synthesis/README.md | 16 + examples/speech_synthesis/__init__.py | 4 + .../docs/common_voice_example.md | 56 +++ .../speech_synthesis/docs/ljspeech_example.md | 138 +++++ .../speech_synthesis/docs/vctk_example.md | 51 ++ .../speech_synthesis/evaluation/__init__.py | 4 + .../speech_synthesis/evaluation/eval_asr.py | 128 +++++ .../speech_synthesis/evaluation/eval_f0.py | 266 ++++++++++ .../speech_synthesis/evaluation/eval_sp.py | 131 +++++ .../evaluation/get_eval_manifest.py | 58 +++ .../preprocessing/__init__.py | 4 + .../preprocessing/denoise_and_vad_audio.py | 204 ++++++++ .../preprocessing/denoiser/__init__.py | 4 + .../preprocessing/denoiser/demucs.py | 473 ++++++++++++++++++ .../preprocessing/denoiser/pretrained.py | 81 +++ .../preprocessing/denoiser/resample.py | 79 +++ .../preprocessing/denoiser/utils.py | 176 +++++++ .../get_common_voice_audio_manifest.py | 140 ++++++ .../preprocessing/get_feature_manifest.py | 233 +++++++++ .../get_ljspeech_audio_manifest.py | 70 +++ .../preprocessing/get_speaker_embedding.py | 89 ++++ .../preprocessing/get_vctk_audio_manifest.py | 79 +++ .../speaker_embedder/__init__.py | 135 +++++ .../preprocessing/vad/__init__.py | 192 +++++++ 24 files changed, 2811 insertions(+) create mode 100644 examples/speech_synthesis/README.md create mode 100644 examples/speech_synthesis/__init__.py create mode 100644 examples/speech_synthesis/docs/common_voice_example.md create mode 100644 examples/speech_synthesis/docs/ljspeech_example.md create mode 100644 examples/speech_synthesis/docs/vctk_example.md create mode 100644 examples/speech_synthesis/evaluation/__init__.py create mode 100644 examples/speech_synthesis/evaluation/eval_asr.py create mode 100644 examples/speech_synthesis/evaluation/eval_f0.py create mode 100644 examples/speech_synthesis/evaluation/eval_sp.py create mode 100644 examples/speech_synthesis/evaluation/get_eval_manifest.py create mode 100644 examples/speech_synthesis/preprocessing/__init__.py create mode 100644 examples/speech_synthesis/preprocessing/denoise_and_vad_audio.py create mode 100644 examples/speech_synthesis/preprocessing/denoiser/__init__.py create mode 100644 examples/speech_synthesis/preprocessing/denoiser/demucs.py create mode 100644 examples/speech_synthesis/preprocessing/denoiser/pretrained.py create mode 100644 examples/speech_synthesis/preprocessing/denoiser/resample.py create mode 100644 examples/speech_synthesis/preprocessing/denoiser/utils.py create mode 100644 examples/speech_synthesis/preprocessing/get_common_voice_audio_manifest.py create mode 100644 examples/speech_synthesis/preprocessing/get_feature_manifest.py create mode 100644 examples/speech_synthesis/preprocessing/get_ljspeech_audio_manifest.py create mode 100644 examples/speech_synthesis/preprocessing/get_speaker_embedding.py create mode 100644 examples/speech_synthesis/preprocessing/get_vctk_audio_manifest.py create mode 100644 examples/speech_synthesis/preprocessing/speaker_embedder/__init__.py create mode 100644 examples/speech_synthesis/preprocessing/vad/__init__.py diff --git a/examples/speech_synthesis/README.md b/examples/speech_synthesis/README.md new file mode 100644 index 0000000000..4a3ae54b85 --- /dev/null +++ b/examples/speech_synthesis/README.md @@ -0,0 +1,16 @@ +Speech Synthesis (S^2) +=== + +Speech synthesis with fairseq. + +- Autoregressive and non-autoregressive models +- Multi-speaker synthesis +- Audio preprocessing +- Automatic metrics +- Similar data configuration as [S2T](../speech_to_text/README.md) + + +## Examples +- [Single-speaker synthesis on LJSpeech](docs/ljspeech_example.md) +- [Multi-speaker synthesis on VCTK](docs/vctk_example.md) +- [Multi-speaker synthesis on Common Voice](docs/common_voice_example.md) diff --git a/examples/speech_synthesis/__init__.py b/examples/speech_synthesis/__init__.py new file mode 100644 index 0000000000..6264236915 --- /dev/null +++ b/examples/speech_synthesis/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/speech_synthesis/docs/common_voice_example.md b/examples/speech_synthesis/docs/common_voice_example.md new file mode 100644 index 0000000000..40e841b284 --- /dev/null +++ b/examples/speech_synthesis/docs/common_voice_example.md @@ -0,0 +1,56 @@ +[[Back]](..) + +# Common Voice + +[Common Voice](https://commonvoice.mozilla.org/en/datasets) is a public domain speech corpus with 11.2K hours of read +speech in 76 languages (the latest version 7.0). We provide examples for building +[Transformer](https://arxiv.org/abs/1809.08895) models on this dataset. + + +## Data preparation +[Download](https://commonvoice.mozilla.org/en/datasets) and unpack Common Voice v4 to a path `${DATA_ROOT}/${LANG_ID}`. +Create splits and generate audio manifests with +```bash +python -m examples.speech_synthesis.preprocessing.get_common_voice_audio_manifest \ + --data-root ${DATA_ROOT} \ + --lang ${LANG_ID} \ + --output-manifest-root ${AUDIO_MANIFEST_ROOT} --convert-to-wav +``` + +Then, extract log-Mel spectrograms, generate feature manifest and create data configuration YAML with +```bash +python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ + --audio-manifest-root ${AUDIO_MANIFEST_ROOT} \ + --output-root ${FEATURE_MANIFEST_ROOT} \ + --ipa-vocab --lang ${LANG_ID} +``` +where we use phoneme inputs (`--ipa-vocab`) as example. + +To denoise audio and trim leading/trailing silence using signal processing based VAD, run +```bash +for SPLIT in dev test train; do + python -m examples.speech_synthesis.preprocessing.denoise_and_vad_audio \ + --audio-manifest ${AUDIO_MANIFEST_ROOT}/${SPLIT}.audio.tsv \ + --output-dir ${PROCESSED_DATA_ROOT} \ + --denoise --vad --vad-agg-level 2 +done +``` + + +## Training +(Please refer to [the LJSpeech example](../docs/ljspeech_example.md#transformer).) + + +## Inference +(Please refer to [the LJSpeech example](../docs/ljspeech_example.md#inference).) + +## Automatic Evaluation +(Please refer to [the LJSpeech example](../docs/ljspeech_example.md#automatic-evaluation).) + +## Results + +| Language | Speakers | --arch | Params | Test MCD | Model | +|---|---|---|---|---|---| +| English | 200 | tts_transformer | 54M | 3.8 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2/cv4_en200_transformer_phn.tar) | + +[[Back]](..) diff --git a/examples/speech_synthesis/docs/ljspeech_example.md b/examples/speech_synthesis/docs/ljspeech_example.md new file mode 100644 index 0000000000..2b8d21abf9 --- /dev/null +++ b/examples/speech_synthesis/docs/ljspeech_example.md @@ -0,0 +1,138 @@ +[[Back]](..) + +# LJSpeech + +[LJSpeech](https://keithito.com/LJ-Speech-Dataset) is a public domain TTS +corpus with around 24 hours of English speech sampled at 22.05kHz. We provide examples for building +[Transformer](https://arxiv.org/abs/1809.08895) and [FastSpeech 2](https://arxiv.org/abs/2006.04558) +models on this dataset. + + +## Data preparation + +Download data, create splits and generate audio manifests with +```bash +python -m examples.speech_synthesis.preprocessing.get_ljspeech_audio_manifest \ + --output-data-root ${AUDIO_DATA_ROOT} \ + --output-manifest-root ${AUDIO_MANIFEST_ROOT} +``` + +Then, extract log-Mel spectrograms, generate feature manifest and create data configuration YAML with +```bash +python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ + --audio-manifest-root ${AUDIO_MANIFEST_ROOT} \ + --output-root ${FEATURE_MANIFEST_ROOT} \ + --ipa-vocab --use-g2p +``` +where we use phoneme inputs (`--ipa-vocab --use-g2p`) as example. + +FastSpeech 2 additionally requires frame durations, pitch and energy as auxiliary training targets. +Add `--add-fastspeech-targets` to include these fields in the feature manifests. We get frame durations either from +phoneme-level force-alignment or frame-level pseudo-text unit sequence. They should be pre-computed and specified via: +- `--textgrid-zip ${TEXT_GRID_ZIP_PATH}` for a ZIP file, inside which there is one + [TextGrid](https://www.fon.hum.uva.nl/praat/manual/TextGrid.html) file per sample to provide force-alignment info. +- `--id-to-units-tsv ${ID_TO_UNIT_TSV}` for a TSV file, where there are 2 columns for sample ID and + space-delimited pseudo-text unit sequence, respectively. + +For your convenience, we provide pre-computed +[force-alignment](https://dl.fbaipublicfiles.com/fairseq/s2/ljspeech_mfa.zip) from +[Montreal Forced Aligner](https://github.com/MontrealCorpusTools/Montreal-Forced-Aligner) and +[pseudo-text units](s3://dl.fbaipublicfiles.com/fairseq/s2/ljspeech_hubert.tsv) from +[HuBERT](https://github.com/pytorch/fairseq/tree/master/examples/hubert). You can also generate them by yourself using +a different software or model. + + +## Training +#### Transformer +```bash +fairseq-train ${FEATURE_MANIFEST_ROOT} --save-dir ${SAVE_DIR} \ + --config-yaml config.yaml --train-subset train --valid-subset dev \ + --num-workers 4 --max-tokens 30000 --max-update 200000 \ + --task text_to_speech --criterion tacotron2 --arch tts_transformer \ + --clip-norm 5.0 --n-frames-per-step 4 --bce-pos-weight 5.0 \ + --dropout 0.1 --attention-dropout 0.1 --activation-dropout 0.1 \ + --encoder-normalize-before --decoder-normalize-before \ + --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt --warmup-updates 4000 \ + --seed 1 --update-freq 8 --eval-inference --best-checkpoint-metric mcd_loss +``` +where `SAVE_DIR` is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to +update it accordingly when using more than 1 GPU. + +#### FastSpeech2 +```bash +fairseq-train ${FEATURE_MANIFEST_ROOT} --save-dir ${SAVE_DIR} \ + --config-yaml config.yaml --train-subset train --valid-subset dev \ + --num-workers 4 --max-sentences 6 --max-update 200000 \ + --task text_to_speech --criterion fastspeech2 --arch fastspeech2 \ + --clip-norm 5.0 --n-frames-per-step 1 \ + --dropout 0.1 --attention-dropout 0.1 --activation-dropout 0.1 \ + --encoder-normalize-before --decoder-normalize-before \ + --optimizer adam --lr 5e-4 --lr-scheduler inverse_sqrt --warmup-updates 4000 \ + --seed 1 --update-freq 8 --eval-inference --best-checkpoint-metric mcd_loss +``` + + +## Inference +Average the last 5 checkpoints, generate the test split spectrogram and waveform using the default Griffin-Lim vocoder: +```bash +SPLIT=test +CHECKPOINT_NAME=avg_last_5 +CHECKPOINT_PATH=${SAVE_DIR}/checkpoint_${CHECKPOINT_NAME}.pt +python scripts/average_checkpoints.py --inputs ${SAVE_DIR} \ + --num-epoch-checkpoints 5 \ + --output ${CHECKPOINT_PATH} + +python -m examples.speech_synthesis.generate_waveform ${FEATURE_MANIFEST_ROOT} \ + --config-yaml config.yaml --gen-subset ${SPLIT} --task text_to_speech \ + --path ${CHECKPOINT_PATH} --max-tokens 50000 --spec-bwd-max-iter 32 \ + --dump-waveforms +``` +which dumps files (waveform, feature, attention plot, etc.) to `${SAVE_DIR}/generate-${CHECKPOINT_NAME}-${SPLIT}`. To +re-synthesize target waveforms for automatic evaluation, add `--dump-target`. + +## Automatic Evaluation +To start with, generate the manifest for synthetic speech, which will be taken as inputs by evaluation scripts. +```bash +python -m examples.speech_synthesis.evaluation.get_eval_manifest \ + --generation-root ${SAVE_DIR}/generate-${CHECKPOINT_NAME}-${SPLIT} \ + --audio-manifest ${AUDIO_MANIFEST_ROOT}/${SPLIT}.audio.tsv \ + --output-path ${EVAL_OUTPUT_ROOT}/eval.tsv \ + --vocoder griffin_lim --sample-rate 22050 --audio-format flac \ + --use-resynthesized-target +``` +Speech recognition (ASR) models usually operate at lower sample rates (e.g. 16kHz). For the WER/CER metric, +you may need to resample the audios accordingly --- add `--output-sample-rate 16000` for `generate_waveform.py` and +use `--sample-rate 16000` for `get_eval_manifest.py`. + + +#### WER/CER metric +We use wav2vec 2.0 ASR model as example. [Download](https://github.com/pytorch/fairseq/tree/master/examples/wav2vec) +the model checkpoint and dictionary, then compute WER/CER with +```bash +python -m examples.speech_synthesis.evaluation.eval_asr \ + --audio-header syn --text-header text --err-unit char --split ${SPLIT} \ + --w2v-ckpt ${WAV2VEC2_CHECKPOINT_PATH} --w2v-dict-dir ${WAV2VEC2_DICT_DIR} \ + --raw-manifest ${EVAL_OUTPUT_ROOT}/eval_16khz.tsv --asr-dir ${EVAL_OUTPUT_ROOT}/asr +``` + +#### MCD/MSD metric +```bash +python -m examples.speech_synthesis.evaluation.eval_sp \ + ${EVAL_OUTPUT_ROOT}/eval.tsv --mcd --msd +``` + +#### F0 metrics +```bash +python -m examples.speech_synthesis.evaluation.eval_f0 \ + ${EVAL_OUTPUT_ROOT}/eval.tsv --gpe --vde --ffe +``` + + +## Results + +| --arch | Params | Test MCD | Model | +|---|---|---|---| +| tts_transformer | 54M | 3.8 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2/ljspeech_transformer_phn.tar) | +| fastspeech2 | 41M | 3.8 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2/ljspeech_fastspeech2_phn.tar) | + +[[Back]](..) diff --git a/examples/speech_synthesis/docs/vctk_example.md b/examples/speech_synthesis/docs/vctk_example.md new file mode 100644 index 0000000000..2ba78f3f73 --- /dev/null +++ b/examples/speech_synthesis/docs/vctk_example.md @@ -0,0 +1,51 @@ +[[Back]](..) + +# VCTK + +[VCTK](https://datashare.ed.ac.uk/handle/10283/3443) is an open English speech corpus. We provide examples +for building [Transformer](https://arxiv.org/abs/1809.08895) models on this dataset. + + +## Data preparation +Download data, create splits and generate audio manifests with +```bash +python -m examples.speech_synthesis.preprocessing.get_vctk_audio_manifest \ + --output-data-root ${AUDIO_DATA_ROOT} \ + --output-manifest-root ${AUDIO_MANIFEST_ROOT} +``` + +Then, extract log-Mel spectrograms, generate feature manifest and create data configuration YAML with +```bash +python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ + --audio-manifest-root ${AUDIO_MANIFEST_ROOT} \ + --output-root ${FEATURE_MANIFEST_ROOT} \ + --ipa-vocab --use-g2p +``` +where we use phoneme inputs (`--ipa-vocab --use-g2p`) as example. + +To denoise audio and trim leading/trailing silence using signal processing based VAD, run +```bash +for SPLIT in dev test train; do + python -m examples.speech_synthesis.preprocessing.denoise_and_vad_audio \ + --audio-manifest ${AUDIO_MANIFEST_ROOT}/${SPLIT}.audio.tsv \ + --output-dir ${PROCESSED_DATA_ROOT} \ + --denoise --vad --vad-agg-level 3 +done +``` + +## Training +(Please refer to [the LJSpeech example](../docs/ljspeech_example.md#transformer).) + +## Inference +(Please refer to [the LJSpeech example](../docs/ljspeech_example.md#inference).) + +## Automatic Evaluation +(Please refer to [the LJSpeech example](../docs/ljspeech_example.md#automatic-evaluation).) + +## Results + +| --arch | Params | Test MCD | Model | +|---|---|---|---| +| tts_transformer | 54M | 3.4 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2/vctk_transformer_phn.tar) | + +[[Back]](..) diff --git a/examples/speech_synthesis/evaluation/__init__.py b/examples/speech_synthesis/evaluation/__init__.py new file mode 100644 index 0000000000..6264236915 --- /dev/null +++ b/examples/speech_synthesis/evaluation/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/speech_synthesis/evaluation/eval_asr.py b/examples/speech_synthesis/evaluation/eval_asr.py new file mode 100644 index 0000000000..005a11bfb3 --- /dev/null +++ b/examples/speech_synthesis/evaluation/eval_asr.py @@ -0,0 +1,128 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import editdistance +import re +import shutil +import soundfile as sf +import subprocess +from pathlib import Path + +from examples.speech_to_text.data_utils import load_tsv_to_dicts + + +def preprocess_text(text): + text = "|".join(re.sub(r"[^A-Z' ]", " ", text.upper()).split()) + text = " ".join(text) + return text + + +def prepare_w2v_data( + dict_dir, sample_rate, label, audio_paths, texts, split, data_dir +): + data_dir.mkdir(parents=True, exist_ok=True) + shutil.copyfile( + dict_dir / f"dict.{label}.txt", + data_dir / f"dict.{label}.txt" + ) + with open(data_dir / f"{split}.tsv", "w") as f: + f.write("/\n") + for audio_path in audio_paths: + wav, sr = sf.read(audio_path) + assert sr == sample_rate, f"{sr} != sample_rate" + nsample = len(wav) + f.write(f"{audio_path}\t{nsample}\n") + with open(data_dir / f"{split}.{label}", "w") as f: + for text in texts: + text = preprocess_text(text) + f.write(f"{text}\n") + + +def run_asr(asr_dir, split, w2v_ckpt, w2v_label, res_dir): + """ + results will be saved at + {res_dir}/{ref,hypo}.word-{w2v_ckpt.filename}-{split}.txt + """ + cmd = ["python", "-m", "examples.speech_recognition.infer"] + cmd += [str(asr_dir.resolve())] + cmd += ["--task", "audio_finetuning", "--nbest", "1", "--quiet"] + cmd += ["--w2l-decoder", "viterbi", "--criterion", "ctc"] + cmd += ["--post-process", "letter", "--max-tokens", "4000000"] + cmd += ["--path", str(w2v_ckpt.resolve()), "--labels", w2v_label] + cmd += ["--gen-subset", split, "--results-path", str(res_dir.resolve())] + + print(f"running cmd:\n{' '.join(cmd)}") + subprocess.run(cmd, check=True) + + +def compute_error_rate(hyp_wrd_path, ref_wrd_path, unit="word"): + """each line is "<text> (None-<index>)" """ + tokenize_line = { + "word": lambda x: re.sub(r" \(.*\)$", "", x.rstrip()).split(), + "char": lambda x: list(re.sub(r" \(.*\)$", "", x.rstrip())) + }.get(unit) + if tokenize_line is None: + raise ValueError(f"{unit} not supported") + + inds = [int(re.sub(r"\D*(\d*)\D*", r"\1", line)) + for line in open(hyp_wrd_path)] + hyps = [tokenize_line(line) for line in open(hyp_wrd_path)] + refs = [tokenize_line(line) for line in open(ref_wrd_path)] + assert(len(hyps) == len(refs)) + err_rates = [ + editdistance.eval(hyp, ref) / len(ref) for hyp, ref in zip(hyps, refs) + ] + ind_to_err_rates = {i: e for i, e in zip(inds, err_rates)} + return ind_to_err_rates + + +def main(args): + samples = load_tsv_to_dicts(args.raw_manifest) + ids = [ + sample[args.id_header] if args.id_header else "" for sample in samples + ] + audio_paths = [sample[args.audio_header] for sample in samples] + texts = [sample[args.text_header] for sample in samples] + + prepare_w2v_data( + args.w2v_dict_dir, + args.w2v_sample_rate, + args.w2v_label, + audio_paths, + texts, + args.split, + args.asr_dir + ) + run_asr(args.asr_dir, args.split, args.w2v_ckpt, args.w2v_label, args.asr_dir) + ind_to_err_rates = compute_error_rate( + args.asr_dir / f"hypo.word-{args.w2v_ckpt.name}-{args.split}.txt", + args.asr_dir / f"ref.word-{args.w2v_ckpt.name}-{args.split}.txt", + args.err_unit, + ) + + uer_path = args.asr_dir / f"uer_{args.err_unit}.{args.split}.tsv" + with open(uer_path, "w") as f: + f.write("id\taudio\tuer\n") + for ind, (id_, audio_path) in enumerate(zip(ids, audio_paths)): + f.write(f"{id_}\t{audio_path}\t{ind_to_err_rates[ind]:.4f}\n") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("--raw-manifest", required=True, type=Path) + parser.add_argument("--asr-dir", required=True, type=Path) + parser.add_argument("--id-header", default="id", type=str) + parser.add_argument("--audio-header", default="audio", type=str) + parser.add_argument("--text-header", default="src_text", type=str) + parser.add_argument("--split", default="raw", type=str) + parser.add_argument("--w2v-ckpt", required=True, type=Path) + parser.add_argument("--w2v-dict-dir", required=True, type=Path) + parser.add_argument("--w2v-sample-rate", default=16000, type=int) + parser.add_argument("--w2v-label", default="ltr", type=str) + parser.add_argument("--err-unit", default="word", type=str) + args = parser.parse_args() + + main(args) diff --git a/examples/speech_synthesis/evaluation/eval_f0.py b/examples/speech_synthesis/evaluation/eval_f0.py new file mode 100644 index 0000000000..df721d6831 --- /dev/null +++ b/examples/speech_synthesis/evaluation/eval_f0.py @@ -0,0 +1,266 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +Signal processing-based evaluation using waveforms +""" +import numpy as np +import os.path as op + +import torchaudio +import tqdm +from tabulate import tabulate + +from examples.speech_synthesis.utils import ( + gross_pitch_error, voicing_decision_error, f0_frame_error +) +from examples.speech_synthesis.evaluation.eval_sp import load_eval_spec + + +def difference_function(x, n, tau_max): + """ + Compute difference function of data x. This solution is implemented directly + with Numpy fft. + + + :param x: audio data + :param n: length of data + :param tau_max: integration window size + :return: difference function + :rtype: list + """ + + x = np.array(x, np.float64) + w = x.size + tau_max = min(tau_max, w) + x_cumsum = np.concatenate((np.array([0.]), (x * x).cumsum())) + size = w + tau_max + p2 = (size // 32).bit_length() + nice_numbers = (16, 18, 20, 24, 25, 27, 30, 32) + size_pad = min(x * 2 ** p2 for x in nice_numbers if x * 2 ** p2 >= size) + fc = np.fft.rfft(x, size_pad) + conv = np.fft.irfft(fc * fc.conjugate())[:tau_max] + return x_cumsum[w:w - tau_max:-1] + x_cumsum[w] - x_cumsum[:tau_max] - \ + 2 * conv + + +def cumulative_mean_normalized_difference_function(df, n): + """ + Compute cumulative mean normalized difference function (CMND). + + :param df: Difference function + :param n: length of data + :return: cumulative mean normalized difference function + :rtype: list + """ + + # scipy method + cmn_df = df[1:] * range(1, n) / np.cumsum(df[1:]).astype(float) + return np.insert(cmn_df, 0, 1) + + +def get_pitch(cmdf, tau_min, tau_max, harmo_th=0.1): + """ + Return fundamental period of a frame based on CMND function. + + :param cmdf: Cumulative Mean Normalized Difference function + :param tau_min: minimum period for speech + :param tau_max: maximum period for speech + :param harmo_th: harmonicity threshold to determine if it is necessary to + compute pitch frequency + :return: fundamental period if there is values under threshold, 0 otherwise + :rtype: float + """ + tau = tau_min + while tau < tau_max: + if cmdf[tau] < harmo_th: + while tau + 1 < tau_max and cmdf[tau + 1] < cmdf[tau]: + tau += 1 + return tau + tau += 1 + + return 0 # if unvoiced + + +def compute_yin(sig, sr, w_len=512, w_step=256, f0_min=100, f0_max=500, + harmo_thresh=0.1): + """ + + Compute the Yin Algorithm. Return fundamental frequency and harmonic rate. + + https://github.com/NVIDIA/mellotron adaption of + https://github.com/patriceguyot/Yin + + :param sig: Audio signal (list of float) + :param sr: sampling rate (int) + :param w_len: size of the analysis window (samples) + :param w_step: size of the lag between two consecutives windows (samples) + :param f0_min: Minimum fundamental frequency that can be detected (hertz) + :param f0_max: Maximum fundamental frequency that can be detected (hertz) + :param harmo_thresh: Threshold of detection. The yalgorithmù return the + first minimum of the CMND function below this threshold. + + :returns: + + * pitches: list of fundamental frequencies, + * harmonic_rates: list of harmonic rate values for each fundamental + frequency value (= confidence value) + * argmins: minimums of the Cumulative Mean Normalized DifferenceFunction + * times: list of time of each estimation + :rtype: tuple + """ + + tau_min = int(sr / f0_max) + tau_max = int(sr / f0_min) + + # time values for each analysis window + time_scale = range(0, len(sig) - w_len, w_step) + times = [t/float(sr) for t in time_scale] + frames = [sig[t:t + w_len] for t in time_scale] + + pitches = [0.0] * len(time_scale) + harmonic_rates = [0.0] * len(time_scale) + argmins = [0.0] * len(time_scale) + + for i, frame in enumerate(frames): + # Compute YIN + df = difference_function(frame, w_len, tau_max) + cm_df = cumulative_mean_normalized_difference_function(df, tau_max) + p = get_pitch(cm_df, tau_min, tau_max, harmo_thresh) + + # Get results + if np.argmin(cm_df) > tau_min: + argmins[i] = float(sr / np.argmin(cm_df)) + if p != 0: # A pitch was found + pitches[i] = float(sr / p) + harmonic_rates[i] = cm_df[p] + else: # No pitch, but we compute a value of the harmonic rate + harmonic_rates[i] = min(cm_df) + + return pitches, harmonic_rates, argmins, times + + +def extract_f0(samples): + f0_samples = [] + for sample in tqdm.tqdm(samples): + if not op.isfile(sample["ref"]) or not op.isfile(sample["syn"]): + f0_samples.append(None) + continue + + # assume single channel + yref, sr = torchaudio.load(sample["ref"]) + ysyn, _sr = torchaudio.load(sample["syn"]) + yref, ysyn = yref[0], ysyn[0] + assert sr == _sr, f"{sr} != {_sr}" + + yref_f0 = compute_yin(yref, sr) + ysyn_f0 = compute_yin(ysyn, sr) + + f0_samples += [ + { + "ref": yref_f0, + "syn": ysyn_f0 + } + ] + + return f0_samples + + +def eval_f0_error(samples, distortion_fn): + results = [] + for sample in tqdm.tqdm(samples): + if sample is None: + results.append(None) + continue + # assume single channel + yref_f, _, _, yref_t = sample["ref"] + ysyn_f, _, _, ysyn_t = sample["syn"] + + yref_f = np.array(yref_f) + yref_t = np.array(yref_t) + ysyn_f = np.array(ysyn_f) + ysyn_t = np.array(ysyn_t) + + distortion = distortion_fn(yref_t, yref_f, ysyn_t, ysyn_f) + results.append((distortion.item(), + len(yref_f), + len(ysyn_f) + )) + return results + + +def eval_gross_pitch_error(samples): + return eval_f0_error(samples, gross_pitch_error) + + +def eval_voicing_decision_error(samples): + return eval_f0_error(samples, voicing_decision_error) + + +def eval_f0_frame_error(samples): + return eval_f0_error(samples, f0_frame_error) + + +def print_results(results, show_bin): + results = np.array(list(filter(lambda x: x is not None, results))) + + np.set_printoptions(precision=3) + + def _print_result(results): + res = { + "nutt": len(results), + "error": results[:, 0].mean(), + "std": results[:, 0].std(), + "dur_ref": int(results[:, 1].sum()), + "dur_syn": int(results[:, 2].sum()), + } + print(tabulate([res.values()], res.keys(), floatfmt=".4f")) + + print(">>>> ALL") + _print_result(results) + + if show_bin: + edges = [0, 200, 400, 600, 800, 1000, 2000, 4000] + for i in range(1, len(edges)): + mask = np.logical_and(results[:, 1] >= edges[i-1], + results[:, 1] < edges[i]) + if not mask.any(): + continue + bin_results = results[mask] + print(f">>>> ({edges[i-1]}, {edges[i]})") + _print_result(bin_results) + + +def main(eval_f0, gpe, vde, ffe, show_bin): + samples = load_eval_spec(eval_f0) + if gpe or vde or ffe: + f0_samples = extract_f0(samples) + + if gpe: + print("===== Evaluate Gross Pitch Error =====") + results = eval_gross_pitch_error(f0_samples) + print_results(results, show_bin) + if vde: + print("===== Evaluate Voicing Decision Error =====") + results = eval_voicing_decision_error(f0_samples) + print_results(results, show_bin) + if ffe: + print("===== Evaluate F0 Frame Error =====") + results = eval_f0_frame_error(f0_samples) + print_results(results, show_bin) + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("eval_f0") + parser.add_argument("--gpe", action="store_true") + parser.add_argument("--vde", action="store_true") + parser.add_argument("--ffe", action="store_true") + parser.add_argument("--show-bin", action="store_true") + args = parser.parse_args() + + main(args.eval_f0, args.gpe, args.vde, args.ffe, args.show_bin) diff --git a/examples/speech_synthesis/evaluation/eval_sp.py b/examples/speech_synthesis/evaluation/eval_sp.py new file mode 100644 index 0000000000..702c498038 --- /dev/null +++ b/examples/speech_synthesis/evaluation/eval_sp.py @@ -0,0 +1,131 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +""" +Signal processing-based evaluation using waveforms +""" + +import csv +import numpy as np +import os.path as op + +import torch +import tqdm +from tabulate import tabulate +import torchaudio + +from examples.speech_synthesis.utils import batch_mel_spectral_distortion +from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion + + +def load_eval_spec(path): + with open(path) as f: + reader = csv.DictReader(f, delimiter='\t') + samples = list(reader) + return samples + + +def eval_distortion(samples, distortion_fn, device="cuda"): + nmiss = 0 + results = [] + for sample in tqdm.tqdm(samples): + if not op.isfile(sample["ref"]) or not op.isfile(sample["syn"]): + nmiss += 1 + results.append(None) + continue + # assume single channel + yref, sr = torchaudio.load(sample["ref"]) + ysyn, _sr = torchaudio.load(sample["syn"]) + yref, ysyn = yref[0].to(device), ysyn[0].to(device) + assert sr == _sr, f"{sr} != {_sr}" + + distortion, extra = distortion_fn([yref], [ysyn], sr, None)[0] + _, _, _, _, _, pathmap = extra + nins = torch.sum(pathmap.sum(dim=1) - 1) # extra frames in syn + ndel = torch.sum(pathmap.sum(dim=0) - 1) # missing frames from syn + results.append( + (distortion.item(), # path distortion + pathmap.size(0), # yref num frames + pathmap.size(1), # ysyn num frames + pathmap.sum().item(), # path length + nins.item(), # insertion + ndel.item(), # deletion + ) + ) + return results + + +def eval_mel_cepstral_distortion(samples, device="cuda"): + return eval_distortion(samples, batch_mel_cepstral_distortion, device) + + +def eval_mel_spectral_distortion(samples, device="cuda"): + return eval_distortion(samples, batch_mel_spectral_distortion, device) + + +def print_results(results, show_bin): + results = np.array(list(filter(lambda x: x is not None, results))) + + np.set_printoptions(precision=3) + + def _print_result(results): + dist, dur_ref, dur_syn, dur_ali, nins, ndel = results.sum(axis=0) + res = { + "nutt": len(results), + "dist": dist, + "dur_ref": int(dur_ref), + "dur_syn": int(dur_syn), + "dur_ali": int(dur_ali), + "dist_per_ref_frm": dist/dur_ref, + "dist_per_syn_frm": dist/dur_syn, + "dist_per_ali_frm": dist/dur_ali, + "ins": nins/dur_ref, + "del": ndel/dur_ref, + } + print(tabulate( + [res.values()], + res.keys(), + floatfmt=".4f" + )) + + print(">>>> ALL") + _print_result(results) + + if show_bin: + edges = [0, 200, 400, 600, 800, 1000, 2000, 4000] + for i in range(1, len(edges)): + mask = np.logical_and(results[:, 1] >= edges[i-1], + results[:, 1] < edges[i]) + if not mask.any(): + continue + bin_results = results[mask] + print(f">>>> ({edges[i-1]}, {edges[i]})") + _print_result(bin_results) + + +def main(eval_spec, mcd, msd, show_bin): + samples = load_eval_spec(eval_spec) + device = "cpu" + if mcd: + print("===== Evaluate Mean Cepstral Distortion =====") + results = eval_mel_cepstral_distortion(samples, device) + print_results(results, show_bin) + if msd: + print("===== Evaluate Mean Spectral Distortion =====") + results = eval_mel_spectral_distortion(samples, device) + print_results(results, show_bin) + + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("eval_spec") + parser.add_argument("--mcd", action="store_true") + parser.add_argument("--msd", action="store_true") + parser.add_argument("--show-bin", action="store_true") + args = parser.parse_args() + + main(args.eval_spec, args.mcd, args.msd, args.show_bin) diff --git a/examples/speech_synthesis/evaluation/get_eval_manifest.py b/examples/speech_synthesis/evaluation/get_eval_manifest.py new file mode 100644 index 0000000000..a28cd607a0 --- /dev/null +++ b/examples/speech_synthesis/evaluation/get_eval_manifest.py @@ -0,0 +1,58 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import csv +from pathlib import Path + + +def main(args): + """ + `uid syn ref text` + """ + in_root = Path(args.generation_root).resolve() + ext = args.audio_format + with open(args.audio_manifest) as f, open(args.output_path, "w") as f_out: + reader = csv.DictReader( + f, delimiter="\t", quotechar=None, doublequote=False, + lineterminator="\n", quoting=csv.QUOTE_NONE + ) + header = ["id", "syn", "ref", "text", "speaker"] + f_out.write("\t".join(header) + "\n") + for row in reader: + dir_name = f"{ext}_{args.sample_rate}hz_{args.vocoder}" + id_ = row["id"] + syn = (in_root / dir_name / f"{id_}.{ext}").as_posix() + ref = row["audio"] + if args.use_resynthesized_target: + ref = (in_root / f"{dir_name}_tgt" / f"{id_}.{ext}").as_posix() + sample = [id_, syn, ref, row["tgt_text"], row["speaker"]] + f_out.write("\t".join(sample) + "\n") + print(f"wrote evaluation file to {args.output_path}") + + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser() + parser.add_argument( + "--generation-root", help="output directory for generate_waveform.py" + ) + parser.add_argument( + "--audio-manifest", + help="used to determine the original utterance ID and text" + ) + parser.add_argument( + "--output-path", help="path to output evaluation spec file" + ) + parser.add_argument( + "--use-resynthesized-target", action="store_true", + help="use resynthesized reference instead of the original audio" + ) + parser.add_argument("--vocoder", type=str, default="griffin_lim") + parser.add_argument("--sample-rate", type=int, default=22_050) + parser.add_argument("--audio-format", type=str, default="wav") + args = parser.parse_args() + + main(args) diff --git a/examples/speech_synthesis/preprocessing/__init__.py b/examples/speech_synthesis/preprocessing/__init__.py new file mode 100644 index 0000000000..6264236915 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/speech_synthesis/preprocessing/denoise_and_vad_audio.py b/examples/speech_synthesis/preprocessing/denoise_and_vad_audio.py new file mode 100644 index 0000000000..4e13b38a5d --- /dev/null +++ b/examples/speech_synthesis/preprocessing/denoise_and_vad_audio.py @@ -0,0 +1,204 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import os +import csv +import tempfile +from collections import defaultdict +from pathlib import Path + +import torchaudio +try: + import webrtcvad +except ImportError: + raise ImportError("Please install py-webrtcvad: pip install webrtcvad") +import pandas as pd +from tqdm import tqdm + +from examples.speech_synthesis.preprocessing.denoiser.pretrained import master64 +import examples.speech_synthesis.preprocessing.denoiser.utils as utils +from examples.speech_synthesis.preprocessing.vad import ( + frame_generator, vad_collector, read_wave, write_wave, FS_MS, THRESHOLD, + SCALE +) +from examples.speech_to_text.data_utils import save_df_to_tsv + + +log = logging.getLogger(__name__) + +PATHS = ["after_denoise", "after_vad"] +MIN_T = 0.05 + + +def generate_tmp_filename(extension="txt"): + return tempfile._get_default_tempdir() + "/" + \ + next(tempfile._get_candidate_names()) + "." + extension + + +def convert_sr(inpath, sr, output_path=None): + if not output_path: + output_path = generate_tmp_filename("wav") + cmd = f"sox {inpath} -r {sr} {output_path}" + os.system(cmd) + return output_path + + +def apply_vad(vad, inpath): + audio, sample_rate = read_wave(inpath) + frames = frame_generator(FS_MS, audio, sample_rate) + frames = list(frames) + segments = vad_collector(sample_rate, FS_MS, 300, vad, frames) + merge_segments = list() + timestamp_start = 0.0 + timestamp_end = 0.0 + # removing start, end, and long sequences of sils + for i, segment in enumerate(segments): + merge_segments.append(segment[0]) + if i and timestamp_start: + sil_duration = segment[1] - timestamp_end + if sil_duration > THRESHOLD: + merge_segments.append(int(THRESHOLD / SCALE) * (b'\x00')) + else: + merge_segments.append(int((sil_duration / SCALE)) * (b'\x00')) + timestamp_start = segment[1] + timestamp_end = segment[2] + segment = b''.join(merge_segments) + return segment, sample_rate + + +def write(wav, filename, sr=16_000): + # Normalize audio if it prevents clipping + wav = wav / max(wav.abs().max().item(), 1) + torchaudio.save(filename, wav.cpu(), sr, encoding="PCM_S", + bits_per_sample=16) + + +def process(args): + # making sure we are requested either denoise or vad + if not args.denoise and not args.vad: + log.error("No denoise or vad is requested.") + return + + log.info("Creating out directories...") + if args.denoise: + out_denoise = Path(args.output_dir).absolute().joinpath(PATHS[0]) + out_denoise.mkdir(parents=True, exist_ok=True) + if args.vad: + out_vad = Path(args.output_dir).absolute().joinpath(PATHS[1]) + out_vad.mkdir(parents=True, exist_ok=True) + + log.info("Loading pre-trained speech enhancement model...") + model = master64().to(args.device) + + log.info("Building the VAD model...") + vad = webrtcvad.Vad(int(args.vad_agg_level)) + + # preparing the output dict + output_dict = defaultdict(list) + + log.info(f"Parsing input manifest: {args.audio_manifest}") + with open(args.audio_manifest, "r") as f: + manifest_dict = csv.DictReader(f, delimiter="\t") + for row in tqdm(manifest_dict): + filename = str(row["audio"]) + + final_output = filename + keep_sample = True + n_frames = row["n_frames"] + snr = -1 + if args.denoise: + output_path_denoise = out_denoise.joinpath(Path(filename).name) + # convert to 16khz in case we use a differet sr + tmp_path = convert_sr(final_output, 16000) + + # loading audio file and generating the enhanced version + out, sr = torchaudio.load(tmp_path) + out = out.to(args.device) + estimate = model(out) + estimate = (1 - args.dry_wet) * estimate + args.dry_wet * out + write(estimate[0], str(output_path_denoise), sr) + + snr = utils.cal_snr(out, estimate) + snr = snr.cpu().detach().numpy()[0][0] + final_output = str(output_path_denoise) + + if args.vad: + output_path_vad = out_vad.joinpath(Path(filename).name) + sr = torchaudio.info(final_output).sample_rate + if sr in [16000, 32000, 48000]: + tmp_path = final_output + elif sr < 16000: + tmp_path = convert_sr(final_output, 16000) + elif sr < 32000: + tmp_path = convert_sr(final_output, 32000) + else: + tmp_path = convert_sr(final_output, 48000) + # apply VAD + segment, sample_rate = apply_vad(vad, tmp_path) + if len(segment) < sample_rate * MIN_T: + keep_sample = False + print(( + f"WARNING: skip {filename} because it is too short " + f"after VAD ({len(segment) / sample_rate} < {MIN_T})" + )) + else: + if sample_rate != sr: + tmp_path = generate_tmp_filename("wav") + write_wave(tmp_path, segment, sample_rate) + convert_sr(tmp_path, sr, + output_path=str(output_path_vad)) + else: + write_wave(str(output_path_vad), segment, sample_rate) + final_output = str(output_path_vad) + segment, _ = torchaudio.load(final_output) + n_frames = segment.size(1) + + if keep_sample: + output_dict["id"].append(row["id"]) + output_dict["audio"].append(final_output) + output_dict["n_frames"].append(n_frames) + output_dict["tgt_text"].append(row["tgt_text"]) + output_dict["speaker"].append(row["speaker"]) + output_dict["src_text"].append(row["src_text"]) + output_dict["snr"].append(snr) + + out_tsv_path = Path(args.output_dir) / Path(args.audio_manifest).name + log.info(f"Saving manifest to {out_tsv_path.as_posix()}") + save_df_to_tsv(pd.DataFrame.from_dict(output_dict), out_tsv_path) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--audio-manifest", "-i", required=True, + type=str, help="path to the input manifest.") + parser.add_argument( + "--output-dir", "-o", required=True, type=str, + help="path to the output dir. it will contain files after denoising and" + " vad" + ) + parser.add_argument("--vad-agg-level", "-a", type=int, default=2, + help="the aggresive level of the vad [0-3].") + parser.add_argument( + "--dry-wet", "-dw", type=float, default=0.01, + help="the level of linear interpolation between noisy and enhanced " + "files." + ) + parser.add_argument( + "--device", "-d", type=str, default="cpu", + help="the device to be used for the speech enhancement model: " + "cpu | cuda." + ) + parser.add_argument("--denoise", action="store_true", + help="apply a denoising") + parser.add_argument("--vad", action="store_true", help="apply a VAD") + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_synthesis/preprocessing/denoiser/__init__.py b/examples/speech_synthesis/preprocessing/denoiser/__init__.py new file mode 100644 index 0000000000..6264236915 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/denoiser/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/speech_synthesis/preprocessing/denoiser/demucs.py b/examples/speech_synthesis/preprocessing/denoiser/demucs.py new file mode 100644 index 0000000000..3f70e73d6a --- /dev/null +++ b/examples/speech_synthesis/preprocessing/denoiser/demucs.py @@ -0,0 +1,473 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +# author: adefossez + +import math +import time + +import torch as th +from torch import nn +from torch.nn import functional as F + +from .resample import downsample2, upsample2 +from .utils import capture_init + + +class BLSTM(nn.Module): + def __init__(self, dim, layers=2, bi=True): + super().__init__() + klass = nn.LSTM + self.lstm = klass( + bidirectional=bi, num_layers=layers, hidden_size=dim, input_size=dim + ) + self.linear = None + if bi: + self.linear = nn.Linear(2 * dim, dim) + + def forward(self, x, hidden=None): + x, hidden = self.lstm(x, hidden) + if self.linear: + x = self.linear(x) + return x, hidden + + +def rescale_conv(conv, reference): + std = conv.weight.std().detach() + scale = (std / reference)**0.5 + conv.weight.data /= scale + if conv.bias is not None: + conv.bias.data /= scale + + +def rescale_module(module, reference): + for sub in module.modules(): + if isinstance(sub, (nn.Conv1d, nn.ConvTranspose1d)): + rescale_conv(sub, reference) + + +class Demucs(nn.Module): + """ + Demucs speech enhancement model. + Args: + - chin (int): number of input channels. + - chout (int): number of output channels. + - hidden (int): number of initial hidden channels. + - depth (int): number of layers. + - kernel_size (int): kernel size for each layer. + - stride (int): stride for each layer. + - causal (bool): if false, uses BiLSTM instead of LSTM. + - resample (int): amount of resampling to apply to the input/output. + Can be one of 1, 2 or 4. + - growth (float): number of channels is multiplied by this for every layer. + - max_hidden (int): maximum number of channels. Can be useful to + control the size/speed of the model. + - normalize (bool): if true, normalize the input. + - glu (bool): if true uses GLU instead of ReLU in 1x1 convolutions. + - rescale (float): controls custom weight initialization. + See https://arxiv.org/abs/1911.13254. + - floor (float): stability flooring when normalizing. + + """ + @capture_init + def __init__(self, + chin=1, + chout=1, + hidden=48, + depth=5, + kernel_size=8, + stride=4, + causal=True, + resample=4, + growth=2, + max_hidden=10_000, + normalize=True, + glu=True, + rescale=0.1, + floor=1e-3): + + super().__init__() + if resample not in [1, 2, 4]: + raise ValueError("Resample should be 1, 2 or 4.") + + self.chin = chin + self.chout = chout + self.hidden = hidden + self.depth = depth + self.kernel_size = kernel_size + self.stride = stride + self.causal = causal + self.floor = floor + self.resample = resample + self.normalize = normalize + + self.encoder = nn.ModuleList() + self.decoder = nn.ModuleList() + activation = nn.GLU(1) if glu else nn.ReLU() + ch_scale = 2 if glu else 1 + + for index in range(depth): + encode = [] + encode += [ + nn.Conv1d(chin, hidden, kernel_size, stride), + nn.ReLU(), + nn.Conv1d(hidden, hidden * ch_scale, 1), activation, + ] + self.encoder.append(nn.Sequential(*encode)) + + decode = [] + decode += [ + nn.Conv1d(hidden, ch_scale * hidden, 1), activation, + nn.ConvTranspose1d(hidden, chout, kernel_size, stride), + ] + if index > 0: + decode.append(nn.ReLU()) + self.decoder.insert(0, nn.Sequential(*decode)) + chout = hidden + chin = hidden + hidden = min(int(growth * hidden), max_hidden) + + self.lstm = BLSTM(chin, bi=not causal) + if rescale: + rescale_module(self, reference=rescale) + + def valid_length(self, length): + """ + Return the nearest valid length to use with the model so that + there is no time steps left over in a convolutions, e.g. for all + layers, size of the input - kernel_size % stride = 0. + + If the mixture has a valid length, the estimated sources + will have exactly the same length. + """ + length = math.ceil(length * self.resample) + for _ in range(self.depth): + length = math.ceil((length - self.kernel_size) / self.stride) + 1 + length = max(length, 1) + for _ in range(self.depth): + length = (length - 1) * self.stride + self.kernel_size + length = int(math.ceil(length / self.resample)) + return int(length) + + @property + def total_stride(self): + return self.stride ** self.depth // self.resample + + def forward(self, mix): + if mix.dim() == 2: + mix = mix.unsqueeze(1) + + if self.normalize: + mono = mix.mean(dim=1, keepdim=True) + std = mono.std(dim=-1, keepdim=True) + mix = mix / (self.floor + std) + else: + std = 1 + length = mix.shape[-1] + x = mix + x = F.pad(x, (0, self.valid_length(length) - length)) + if self.resample == 2: + x = upsample2(x) + elif self.resample == 4: + x = upsample2(x) + x = upsample2(x) + skips = [] + for encode in self.encoder: + x = encode(x) + skips.append(x) + x = x.permute(2, 0, 1) + x, _ = self.lstm(x) + x = x.permute(1, 2, 0) + for decode in self.decoder: + skip = skips.pop(-1) + x = x + skip[..., :x.shape[-1]] + x = decode(x) + if self.resample == 2: + x = downsample2(x) + elif self.resample == 4: + x = downsample2(x) + x = downsample2(x) + + x = x[..., :length] + return std * x + + +def fast_conv(conv, x): + """ + Faster convolution evaluation if either kernel size is 1 + or length of sequence is 1. + """ + batch, chin, length = x.shape + chout, chin, kernel = conv.weight.shape + assert batch == 1 + if kernel == 1: + x = x.view(chin, length) + out = th.addmm(conv.bias.view(-1, 1), + conv.weight.view(chout, chin), x) + elif length == kernel: + x = x.view(chin * kernel, 1) + out = th.addmm(conv.bias.view(-1, 1), + conv.weight.view(chout, chin * kernel), x) + else: + out = conv(x) + return out.view(batch, chout, -1) + + +class DemucsStreamer: + """ + Streaming implementation for Demucs. It supports being fed with any amount + of audio at a time. You will get back as much audio as possible at that + point. + + Args: + - demucs (Demucs): Demucs model. + - dry (float): amount of dry (e.g. input) signal to keep. 0 is maximum + noise removal, 1 just returns the input signal. Small values > 0 + allows to limit distortions. + - num_frames (int): number of frames to process at once. Higher values + will increase overall latency but improve the real time factor. + - resample_lookahead (int): extra lookahead used for the resampling. + - resample_buffer (int): size of the buffer of previous inputs/outputs + kept for resampling. + """ + def __init__(self, demucs, + dry=0, + num_frames=1, + resample_lookahead=64, + resample_buffer=256): + device = next(iter(demucs.parameters())).device + self.demucs = demucs + self.lstm_state = None + self.conv_state = None + self.dry = dry + self.resample_lookahead = resample_lookahead + resample_buffer = min(demucs.total_stride, resample_buffer) + self.resample_buffer = resample_buffer + self.frame_length = demucs.valid_length(1) + \ + demucs.total_stride * (num_frames - 1) + self.total_length = self.frame_length + self.resample_lookahead + self.stride = demucs.total_stride * num_frames + self.resample_in = th.zeros(demucs.chin, resample_buffer, device=device) + self.resample_out = th.zeros( + demucs.chin, resample_buffer, device=device + ) + + self.frames = 0 + self.total_time = 0 + self.variance = 0 + self.pending = th.zeros(demucs.chin, 0, device=device) + + bias = demucs.decoder[0][2].bias + weight = demucs.decoder[0][2].weight + chin, chout, kernel = weight.shape + self._bias = bias.view(-1, 1).repeat(1, kernel).view(-1, 1) + self._weight = weight.permute(1, 2, 0).contiguous() + + def reset_time_per_frame(self): + self.total_time = 0 + self.frames = 0 + + @property + def time_per_frame(self): + return self.total_time / self.frames + + def flush(self): + """ + Flush remaining audio by padding it with zero. Call this + when you have no more input and want to get back the last chunk of audio. + """ + pending_length = self.pending.shape[1] + padding = th.zeros( + self.demucs.chin, self.total_length, device=self.pending.device + ) + out = self.feed(padding) + return out[:, :pending_length] + + def feed(self, wav): + """ + Apply the model to mix using true real time evaluation. + Normalization is done online as is the resampling. + """ + begin = time.time() + demucs = self.demucs + resample_buffer = self.resample_buffer + stride = self.stride + resample = demucs.resample + + if wav.dim() != 2: + raise ValueError("input wav should be two dimensional.") + chin, _ = wav.shape + if chin != demucs.chin: + raise ValueError(f"Expected {demucs.chin} channels, got {chin}") + + self.pending = th.cat([self.pending, wav], dim=1) + outs = [] + while self.pending.shape[1] >= self.total_length: + self.frames += 1 + frame = self.pending[:, :self.total_length] + dry_signal = frame[:, :stride] + if demucs.normalize: + mono = frame.mean(0) + variance = (mono**2).mean() + self.variance = variance / self.frames + \ + (1 - 1 / self.frames) * self.variance + frame = frame / (demucs.floor + math.sqrt(self.variance)) + frame = th.cat([self.resample_in, frame], dim=-1) + self.resample_in[:] = frame[:, stride - resample_buffer:stride] + + if resample == 4: + frame = upsample2(upsample2(frame)) + elif resample == 2: + frame = upsample2(frame) + # remove pre sampling buffer + frame = frame[:, resample * resample_buffer:] + # remove extra samples after window + frame = frame[:, :resample * self.frame_length] + + out, extra = self._separate_frame(frame) + padded_out = th.cat([self.resample_out, out, extra], 1) + self.resample_out[:] = out[:, -resample_buffer:] + if resample == 4: + out = downsample2(downsample2(padded_out)) + elif resample == 2: + out = downsample2(padded_out) + else: + out = padded_out + + out = out[:, resample_buffer // resample:] + out = out[:, :stride] + + if demucs.normalize: + out *= math.sqrt(self.variance) + out = self.dry * dry_signal + (1 - self.dry) * out + outs.append(out) + self.pending = self.pending[:, stride:] + + self.total_time += time.time() - begin + if outs: + out = th.cat(outs, 1) + else: + out = th.zeros(chin, 0, device=wav.device) + return out + + def _separate_frame(self, frame): + demucs = self.demucs + skips = [] + next_state = [] + first = self.conv_state is None + stride = self.stride * demucs.resample + x = frame[None] + for idx, encode in enumerate(demucs.encoder): + stride //= demucs.stride + length = x.shape[2] + if idx == demucs.depth - 1: + # This is sligthly faster for the last conv + x = fast_conv(encode[0], x) + x = encode[1](x) + x = fast_conv(encode[2], x) + x = encode[3](x) + else: + if not first: + prev = self.conv_state.pop(0) + prev = prev[..., stride:] + tgt = (length - demucs.kernel_size) // demucs.stride + 1 + missing = tgt - prev.shape[-1] + offset = length - demucs.kernel_size - \ + demucs.stride * (missing - 1) + x = x[..., offset:] + x = encode[1](encode[0](x)) + x = fast_conv(encode[2], x) + x = encode[3](x) + if not first: + x = th.cat([prev, x], -1) + next_state.append(x) + skips.append(x) + + x = x.permute(2, 0, 1) + x, self.lstm_state = demucs.lstm(x, self.lstm_state) + x = x.permute(1, 2, 0) + # In the following, x contains only correct samples, i.e. the one + # for which each time position is covered by two window of the upper + # layer. extra contains extra samples to the right, and is used only as + # a better padding for the online resampling. + extra = None + for idx, decode in enumerate(demucs.decoder): + skip = skips.pop(-1) + x += skip[..., :x.shape[-1]] + x = fast_conv(decode[0], x) + x = decode[1](x) + + if extra is not None: + skip = skip[..., x.shape[-1]:] + extra += skip[..., :extra.shape[-1]] + extra = decode[2](decode[1](decode[0](extra))) + x = decode[2](x) + next_state.append( + x[..., -demucs.stride:] - decode[2].bias.view(-1, 1) + ) + if extra is None: + extra = x[..., -demucs.stride:] + else: + extra[..., :demucs.stride] += next_state[-1] + x = x[..., :-demucs.stride] + + if not first: + prev = self.conv_state.pop(0) + x[..., :demucs.stride] += prev + if idx != demucs.depth - 1: + x = decode[3](x) + extra = decode[3](extra) + self.conv_state = next_state + return x[0], extra[0] + + +def test(): + import argparse + parser = argparse.ArgumentParser( + "denoiser.demucs", + description="Benchmark the streaming Demucs implementation, as well as " + "checking the delta with the offline implementation.") + parser.add_argument("--depth", default=5, type=int) + parser.add_argument("--resample", default=4, type=int) + parser.add_argument("--hidden", default=48, type=int) + parser.add_argument("--sample_rate", default=16000, type=float) + parser.add_argument("--device", default="cpu") + parser.add_argument("-t", "--num_threads", type=int) + parser.add_argument("-f", "--num_frames", type=int, default=1) + args = parser.parse_args() + if args.num_threads: + th.set_num_threads(args.num_threads) + sr = args.sample_rate + sr_ms = sr / 1000 + demucs = Demucs( + depth=args.depth, hidden=args.hidden, resample=args.resample + ).to(args.device) + x = th.randn(1, int(sr * 4)).to(args.device) + out = demucs(x[None])[0] + streamer = DemucsStreamer(demucs, num_frames=args.num_frames) + out_rt = [] + frame_size = streamer.total_length + with th.no_grad(): + while x.shape[1] > 0: + out_rt.append(streamer.feed(x[:, :frame_size])) + x = x[:, frame_size:] + frame_size = streamer.demucs.total_stride + out_rt.append(streamer.flush()) + out_rt = th.cat(out_rt, 1) + model_size = sum(p.numel() for p in demucs.parameters()) * 4 / 2**20 + initial_lag = streamer.total_length / sr_ms + tpf = 1000 * streamer.time_per_frame + print(f"model size: {model_size:.1f}MB, ", end='') + print(f"delta batch/streaming: {th.norm(out - out_rt) / th.norm(out):.2%}") + print(f"initial lag: {initial_lag:.1f}ms, ", end='') + print(f"stride: {streamer.stride * args.num_frames / sr_ms:.1f}ms") + print(f"time per frame: {tpf:.1f}ms, ", end='') + rtf = (1000 * streamer.time_per_frame) / (streamer.stride / sr_ms) + print(f"RTF: {rtf:.2f}") + print(f"Total lag with computation: {initial_lag + tpf:.1f}ms") + + +if __name__ == "__main__": + test() diff --git a/examples/speech_synthesis/preprocessing/denoiser/pretrained.py b/examples/speech_synthesis/preprocessing/denoiser/pretrained.py new file mode 100644 index 0000000000..2fa846075b --- /dev/null +++ b/examples/speech_synthesis/preprocessing/denoiser/pretrained.py @@ -0,0 +1,81 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +# author: adefossez + +import logging + +import torch.hub + +from .demucs import Demucs +from .utils import deserialize_model + +logger = logging.getLogger(__name__) +ROOT = "https://dl.fbaipublicfiles.com/adiyoss/denoiser/" +DNS_48_URL = ROOT + "dns48-11decc9d8e3f0998.th" +DNS_64_URL = ROOT + "dns64-a7761ff99a7d5bb6.th" +MASTER_64_URL = ROOT + "master64-8a5dfb4bb92753dd.th" + + +def _demucs(pretrained, url, **kwargs): + model = Demucs(**kwargs) + if pretrained: + state_dict = torch.hub.load_state_dict_from_url(url, map_location='cpu') + model.load_state_dict(state_dict) + return model + + +def dns48(pretrained=True): + return _demucs(pretrained, DNS_48_URL, hidden=48) + + +def dns64(pretrained=True): + return _demucs(pretrained, DNS_64_URL, hidden=64) + + +def master64(pretrained=True): + return _demucs(pretrained, MASTER_64_URL, hidden=64) + + +def add_model_flags(parser): + group = parser.add_mutually_exclusive_group(required=False) + group.add_argument( + "-m", "--model_path", help="Path to local trained model." + ) + group.add_argument( + "--dns48", action="store_true", + help="Use pre-trained real time H=48 model trained on DNS." + ) + group.add_argument( + "--dns64", action="store_true", + help="Use pre-trained real time H=64 model trained on DNS." + ) + group.add_argument( + "--master64", action="store_true", + help="Use pre-trained real time H=64 model trained on DNS and Valentini." + ) + + +def get_model(args): + """ + Load local model package or torchhub pre-trained model. + """ + if args.model_path: + logger.info("Loading model from %s", args.model_path) + pkg = torch.load(args.model_path) + model = deserialize_model(pkg) + elif args.dns64: + logger.info("Loading pre-trained real time H=64 model trained on DNS.") + model = dns64() + elif args.master64: + logger.info( + "Loading pre-trained real time H=64 model trained on DNS and Valentini." + ) + model = master64() + else: + logger.info("Loading pre-trained real time H=48 model trained on DNS.") + model = dns48() + logger.debug(model) + return model diff --git a/examples/speech_synthesis/preprocessing/denoiser/resample.py b/examples/speech_synthesis/preprocessing/denoiser/resample.py new file mode 100644 index 0000000000..1222addc42 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/denoiser/resample.py @@ -0,0 +1,79 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +# author: adefossez + +import math + +import torch as th +from torch.nn import functional as F + + +def sinc(t): + """sinc. + + :param t: the input tensor + """ + return th.where(t == 0, th.tensor(1., device=t.device, dtype=t.dtype), + th.sin(t) / t) + + +def kernel_upsample2(zeros=56): + """kernel_upsample2. + + """ + win = th.hann_window(4 * zeros + 1, periodic=False) + winodd = win[1::2] + t = th.linspace(-zeros + 0.5, zeros - 0.5, 2 * zeros) + t *= math.pi + kernel = (sinc(t) * winodd).view(1, 1, -1) + return kernel + + +def upsample2(x, zeros=56): + """ + Upsampling the input by 2 using sinc interpolation. + Smith, Julius, and Phil Gossett. "A flexible sampling-rate conversion method." + ICASSP'84. IEEE International Conference on Acoustics, Speech, and Signal Processing. + Vol. 9. IEEE, 1984. + """ + *other, time = x.shape + kernel = kernel_upsample2(zeros).to(x) + out = F.conv1d(x.view(-1, 1, time), kernel, padding=zeros)[..., 1:].view( + *other, time + ) + y = th.stack([x, out], dim=-1) + return y.view(*other, -1) + + +def kernel_downsample2(zeros=56): + """kernel_downsample2. + + """ + win = th.hann_window(4 * zeros + 1, periodic=False) + winodd = win[1::2] + t = th.linspace(-zeros + 0.5, zeros - 0.5, 2 * zeros) + t.mul_(math.pi) + kernel = (sinc(t) * winodd).view(1, 1, -1) + return kernel + + +def downsample2(x, zeros=56): + """ + Downsampling the input by 2 using sinc interpolation. + Smith, Julius, and Phil Gossett. "A flexible sampling-rate conversion method." + ICASSP'84. IEEE International Conference on Acoustics, Speech, and Signal Processing. + Vol. 9. IEEE, 1984. + """ + if x.shape[-1] % 2 != 0: + x = F.pad(x, (0, 1)) + xeven = x[..., ::2] + xodd = x[..., 1::2] + *other, time = xodd.shape + kernel = kernel_downsample2(zeros).to(x) + out = xeven + F.conv1d( + xodd.view(-1, 1, time), kernel, padding=zeros + )[..., :-1].view(*other, time) + return out.view(*other, -1).mul(0.5) diff --git a/examples/speech_synthesis/preprocessing/denoiser/utils.py b/examples/speech_synthesis/preprocessing/denoiser/utils.py new file mode 100644 index 0000000000..734d047f1b --- /dev/null +++ b/examples/speech_synthesis/preprocessing/denoiser/utils.py @@ -0,0 +1,176 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +# author: adefossez + +import functools +import logging +from contextlib import contextmanager +import inspect +import time + +logger = logging.getLogger(__name__) + +EPS = 1e-8 + + +def capture_init(init): + """capture_init. + + Decorate `__init__` with this, and you can then + recover the *args and **kwargs passed to it in `self._init_args_kwargs` + """ + @functools.wraps(init) + def __init__(self, *args, **kwargs): + self._init_args_kwargs = (args, kwargs) + init(self, *args, **kwargs) + + return __init__ + + +def deserialize_model(package, strict=False): + """deserialize_model. + + """ + klass = package['class'] + if strict: + model = klass(*package['args'], **package['kwargs']) + else: + sig = inspect.signature(klass) + kw = package['kwargs'] + for key in list(kw): + if key not in sig.parameters: + logger.warning("Dropping inexistant parameter %s", key) + del kw[key] + model = klass(*package['args'], **kw) + model.load_state_dict(package['state']) + return model + + +def copy_state(state): + return {k: v.cpu().clone() for k, v in state.items()} + + +def serialize_model(model): + args, kwargs = model._init_args_kwargs + state = copy_state(model.state_dict()) + return {"class": model.__class__, "args": args, "kwargs": kwargs, "state": state} + + +@contextmanager +def swap_state(model, state): + """ + Context manager that swaps the state of a model, e.g: + + # model is in old state + with swap_state(model, new_state): + # model in new state + # model back to old state + """ + old_state = copy_state(model.state_dict()) + model.load_state_dict(state) + try: + yield + finally: + model.load_state_dict(old_state) + + +def pull_metric(history, name): + out = [] + for metrics in history: + if name in metrics: + out.append(metrics[name]) + return out + + +class LogProgress: + """ + Sort of like tqdm but using log lines and not as real time. + Args: + - logger: logger obtained from `logging.getLogger`, + - iterable: iterable object to wrap + - updates (int): number of lines that will be printed, e.g. + if `updates=5`, log every 1/5th of the total length. + - total (int): length of the iterable, in case it does not support + `len`. + - name (str): prefix to use in the log. + - level: logging level (like `logging.INFO`). + """ + def __init__(self, + logger, + iterable, + updates=5, + total=None, + name="LogProgress", + level=logging.INFO): + self.iterable = iterable + self.total = total or len(iterable) + self.updates = updates + self.name = name + self.logger = logger + self.level = level + + def update(self, **infos): + self._infos = infos + + def __iter__(self): + self._iterator = iter(self.iterable) + self._index = -1 + self._infos = {} + self._begin = time.time() + return self + + def __next__(self): + self._index += 1 + try: + value = next(self._iterator) + except StopIteration: + raise + else: + return value + finally: + log_every = max(1, self.total // self.updates) + # logging is delayed by 1 it, in order to have the metrics from update + if self._index >= 1 and self._index % log_every == 0: + self._log() + + def _log(self): + self._speed = (1 + self._index) / (time.time() - self._begin) + infos = " | ".join(f"{k.capitalize()} {v}" for k, v in self._infos.items()) + if self._speed < 1e-4: + speed = "oo sec/it" + elif self._speed < 0.1: + speed = f"{1/self._speed:.1f} sec/it" + else: + speed = f"{self._speed:.1f} it/sec" + out = f"{self.name} | {self._index}/{self.total} | {speed}" + if infos: + out += " | " + infos + self.logger.log(self.level, out) + + +def colorize(text, color): + """ + Display text with some ANSI color in the terminal. + """ + code = f"\033[{color}m" + restore = "\033[0m" + return "".join([code, text, restore]) + + +def bold(text): + """ + Display text in bold in the terminal. + """ + return colorize(text, "1") + + +def cal_snr(lbl, est): + import torch + y = 10.0 * torch.log10( + torch.sum(lbl**2, dim=-1) / (torch.sum((est-lbl)**2, dim=-1) + EPS) + + EPS + ) + return y diff --git a/examples/speech_synthesis/preprocessing/get_common_voice_audio_manifest.py b/examples/speech_synthesis/preprocessing/get_common_voice_audio_manifest.py new file mode 100644 index 0000000000..a302546043 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/get_common_voice_audio_manifest.py @@ -0,0 +1,140 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +from pathlib import Path +from collections import defaultdict +from typing import List, Dict, Tuple + +import pandas as pd +import numpy as np +import torchaudio +from tqdm import tqdm + +from examples.speech_to_text.data_utils import load_df_from_tsv, save_df_to_tsv + + +log = logging.getLogger(__name__) + +SPLITS = ["train", "dev", "test"] + + +def get_top_n( + root: Path, n_speakers: int = 10, min_n_tokens: int = 5 +) -> pd.DataFrame: + df = load_df_from_tsv(root / "validated.tsv") + df["n_tokens"] = [len(s.split()) for s in df["sentence"]] + df = df[df["n_tokens"] >= min_n_tokens] + df["n_frames"] = [ + torchaudio.info((root / "clips" / p).as_posix()).num_frames + for p in tqdm(df["path"]) + ] + df["id"] = [Path(p).stem for p in df["path"]] + total_duration_ms = df.groupby("client_id")["n_frames"].agg(["sum"]) + total_duration_ms = total_duration_ms.sort_values("sum", ascending=False) + + top_n_total_duration_ms = total_duration_ms.head(n_speakers) + top_n_client_ids = set(top_n_total_duration_ms.index.tolist()) + df_top_n = df[df["client_id"].isin(top_n_client_ids)] + return df_top_n + + +def get_splits( + df, train_split_ratio=0.99, speaker_in_all_splits=False, rand_seed=0 +) -> Tuple[Dict[str, str], List[str]]: + np.random.seed(rand_seed) + dev_split_ratio = (1. - train_split_ratio) / 3 + grouped = list(df.groupby("client_id")) + id_to_split = {} + for _, cur_df in tqdm(grouped): + cur_n_examples = len(cur_df) + if speaker_in_all_splits and cur_n_examples < 3: + continue + cur_n_train = int(cur_n_examples * train_split_ratio) + cur_n_dev = int(cur_n_examples * dev_split_ratio) + cur_n_test = cur_n_examples - cur_n_dev - cur_n_train + if speaker_in_all_splits and cur_n_dev * cur_n_test == 0: + cur_n_dev, cur_n_test = 1, 1 + cur_n_train = cur_n_examples - cur_n_dev - cur_n_test + cur_indices = cur_df.index.tolist() + cur_shuffled_indices = np.random.permutation(cur_n_examples) + cur_shuffled_indices = [cur_indices[i] for i in cur_shuffled_indices] + cur_indices_by_split = { + "train": cur_shuffled_indices[:cur_n_train], + "dev": cur_shuffled_indices[cur_n_train: cur_n_train + cur_n_dev], + "test": cur_shuffled_indices[cur_n_train + cur_n_dev:] + } + for split in SPLITS: + for i in cur_indices_by_split[split]: + id_ = df["id"].loc[i] + id_to_split[id_] = split + return id_to_split, sorted(df["client_id"].unique()) + + +def convert_to_wav(root: Path, filenames: List[str], target_sr=16_000): + out_root = root / "wav" + out_root.mkdir(exist_ok=True, parents=True) + print("Converting to WAV...") + for n in tqdm(filenames): + in_path = (root / "clips" / n).as_posix() + waveform, sr = torchaudio.load(in_path) + converted, converted_sr = torchaudio.sox_effects.apply_effects_tensor( + waveform, sr, [["rate", str(target_sr)], ["channels", "1"]] + ) + out_path = (out_root / Path(n).with_suffix(".wav").name).as_posix() + torchaudio.save(out_path, converted, converted_sr, encoding="PCM_S", + bits_per_sample=16) + + +def process(args): + data_root = Path(args.data_root).absolute() / args.lang + + # Generate TSV manifest + print("Generating manifest...") + + df_top_n = get_top_n(data_root) + id_to_split, speakers = get_splits(df_top_n) + + if args.convert_to_wav: + convert_to_wav(data_root, df_top_n["path"].tolist()) + + manifest_by_split = {split: defaultdict(list) for split in SPLITS} + for sample in tqdm(df_top_n.to_dict(orient="index").values()): + sample_id = sample["id"] + split = id_to_split[sample_id] + manifest_by_split[split]["id"].append(sample_id) + if args.convert_to_wav: + audio_path = data_root / "wav" / f"{sample_id}.wav" + else: + audio_path = data_root / "clips" / f"{sample_id}.mp3" + manifest_by_split[split]["audio"].append(audio_path.as_posix()) + manifest_by_split[split]["n_frames"].append(sample["n_frames"]) + manifest_by_split[split]["tgt_text"].append(sample["sentence"]) + manifest_by_split[split]["speaker"].append(sample["client_id"]) + manifest_by_split[split]["src_text"].append(sample["sentence"]) + + output_root = Path(args.output_manifest_root).absolute() + output_root.mkdir(parents=True, exist_ok=True) + for split in SPLITS: + save_df_to_tsv( + pd.DataFrame.from_dict(manifest_by_split[split]), + output_root / f"{split}.audio.tsv" + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--data-root", "-d", required=True, type=str) + parser.add_argument("--output-manifest-root", "-m", required=True, type=str) + parser.add_argument("--lang", "-l", required=True, type=str) + parser.add_argument("--convert-to-wav", action="store_true") + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_synthesis/preprocessing/get_feature_manifest.py b/examples/speech_synthesis/preprocessing/get_feature_manifest.py new file mode 100644 index 0000000000..516f2cc469 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/get_feature_manifest.py @@ -0,0 +1,233 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +from pathlib import Path +import shutil +from tempfile import NamedTemporaryFile +from collections import Counter, defaultdict + +import pandas as pd +import torchaudio +from tqdm import tqdm + +from fairseq.data.audio.audio_utils import convert_waveform +from examples.speech_to_text.data_utils import ( + create_zip, + gen_config_yaml, + gen_vocab, + get_zip_manifest, + load_tsv_to_dicts, + save_df_to_tsv +) +from examples.speech_synthesis.data_utils import ( + extract_logmel_spectrogram, extract_pitch, extract_energy, get_global_cmvn, + ipa_phonemize, get_mfa_alignment, get_unit_alignment +) + + +log = logging.getLogger(__name__) + + +def process(args): + assert "train" in args.splits + out_root = Path(args.output_root).absolute() + out_root.mkdir(exist_ok=True) + + print("Fetching data...") + audio_manifest_root = Path(args.audio_manifest_root).absolute() + samples = [] + for s in args.splits: + for e in load_tsv_to_dicts(audio_manifest_root / f"{s}.audio.tsv"): + e["split"] = s + samples.append(e) + sample_ids = [s["id"] for s in samples] + + # Get alignment info + id_to_alignment = None + if args.textgrid_zip is not None: + assert args.id_to_units_tsv is None + id_to_alignment = get_mfa_alignment( + args.textgrid_zip, sample_ids, args.sample_rate, args.hop_length + ) + elif args.id_to_units_tsv is not None: + # assume identical hop length on the unit sequence + id_to_alignment = get_unit_alignment(args.id_to_units_tsv, sample_ids) + + # Extract features and pack features into ZIP + feature_name = "logmelspec80" + zip_path = out_root / f"{feature_name}.zip" + pitch_zip_path = out_root / "pitch.zip" + energy_zip_path = out_root / "energy.zip" + gcmvn_npz_path = out_root / "gcmvn_stats.npz" + if zip_path.exists() and gcmvn_npz_path.exists(): + print(f"{zip_path} and {gcmvn_npz_path} exist.") + else: + feature_root = out_root / feature_name + feature_root.mkdir(exist_ok=True) + pitch_root = out_root / "pitch" + energy_root = out_root / "energy" + if args.add_fastspeech_targets: + pitch_root.mkdir(exist_ok=True) + energy_root.mkdir(exist_ok=True) + print("Extracting Mel spectrogram features...") + for sample in tqdm(samples): + waveform, sample_rate = torchaudio.load(sample["audio"]) + waveform, sample_rate = convert_waveform( + waveform, sample_rate, normalize_volume=args.normalize_volume, + to_sample_rate=args.sample_rate + ) + sample_id = sample["id"] + target_length = None + if id_to_alignment is not None: + a = id_to_alignment[sample_id] + target_length = sum(a.frame_durations) + if a.start_sec is not None and a.end_sec is not None: + start_frame = int(a.start_sec * sample_rate) + end_frame = int(a.end_sec * sample_rate) + waveform = waveform[:, start_frame: end_frame] + extract_logmel_spectrogram( + waveform, sample_rate, feature_root / f"{sample_id}.npy", + win_length=args.win_length, hop_length=args.hop_length, + n_fft=args.n_fft, n_mels=args.n_mels, f_min=args.f_min, + f_max=args.f_max, target_length=target_length + ) + if args.add_fastspeech_targets: + assert id_to_alignment is not None + extract_pitch( + waveform, sample_rate, pitch_root / f"{sample_id}.npy", + hop_length=args.hop_length, log_scale=True, + phoneme_durations=id_to_alignment[sample_id].frame_durations + ) + extract_energy( + waveform, energy_root / f"{sample_id}.npy", + hop_length=args.hop_length, n_fft=args.n_fft, + log_scale=True, + phoneme_durations=id_to_alignment[sample_id].frame_durations + ) + print("ZIPing features...") + create_zip(feature_root, zip_path) + get_global_cmvn(feature_root, gcmvn_npz_path) + shutil.rmtree(feature_root) + if args.add_fastspeech_targets: + create_zip(pitch_root, pitch_zip_path) + shutil.rmtree(pitch_root) + create_zip(energy_root, energy_zip_path) + shutil.rmtree(energy_root) + + print("Fetching ZIP manifest...") + audio_paths, audio_lengths = get_zip_manifest(zip_path) + pitch_paths, pitch_lengths, energy_paths, energy_lengths = [None] * 4 + if args.add_fastspeech_targets: + pitch_paths, pitch_lengths = get_zip_manifest(pitch_zip_path) + energy_paths, energy_lengths = get_zip_manifest(energy_zip_path) + # Generate TSV manifest + print("Generating manifest...") + manifest_by_split = {split: defaultdict(list) for split in args.splits} + for sample in tqdm(samples): + sample_id, split = sample["id"], sample["split"] + normalized_utt = sample["tgt_text"] + if id_to_alignment is not None: + normalized_utt = " ".join(id_to_alignment[sample_id].tokens) + elif args.ipa_vocab: + normalized_utt = ipa_phonemize( + normalized_utt, lang=args.lang, use_g2p=args.use_g2p + ) + manifest_by_split[split]["id"].append(sample_id) + manifest_by_split[split]["audio"].append(audio_paths[sample_id]) + manifest_by_split[split]["n_frames"].append(audio_lengths[sample_id]) + manifest_by_split[split]["tgt_text"].append(normalized_utt) + manifest_by_split[split]["speaker"].append(sample["speaker"]) + manifest_by_split[split]["src_text"].append(sample["src_text"]) + if args.add_fastspeech_targets: + assert id_to_alignment is not None + duration = " ".join( + str(d) for d in id_to_alignment[sample_id].frame_durations + ) + manifest_by_split[split]["duration"].append(duration) + manifest_by_split[split]["pitch"].append(pitch_paths[sample_id]) + manifest_by_split[split]["energy"].append(energy_paths[sample_id]) + for split in args.splits: + save_df_to_tsv( + pd.DataFrame.from_dict(manifest_by_split[split]), + out_root / f"{split}.tsv" + ) + # Generate vocab + vocab_name, spm_filename = None, None + if id_to_alignment is not None or args.ipa_vocab: + vocab = Counter() + for t in manifest_by_split["train"]["tgt_text"]: + vocab.update(t.split(" ")) + vocab_name = "vocab.txt" + with open(out_root / vocab_name, "w") as f: + for s, c in vocab.most_common(): + f.write(f"{s} {c}\n") + else: + spm_filename_prefix = "spm_char" + spm_filename = f"{spm_filename_prefix}.model" + with NamedTemporaryFile(mode="w") as f: + for t in manifest_by_split["train"]["tgt_text"]: + f.write(t + "\n") + f.flush() # needed to ensure gen_vocab sees dumped text + gen_vocab(Path(f.name), out_root / spm_filename_prefix, "char") + # Generate speaker list + speakers = sorted({sample["speaker"] for sample in samples}) + speakers_path = out_root / "speakers.txt" + with open(speakers_path, "w") as f: + for speaker in speakers: + f.write(f"{speaker}\n") + # Generate config YAML + win_len_t = args.win_length / args.sample_rate + hop_len_t = args.hop_length / args.sample_rate + extra = { + "sample_rate": args.sample_rate, + "features": { + "type": "spectrogram+melscale+log", + "eps": 1e-2, "n_mels": args.n_mels, "n_fft": args.n_fft, + "window_fn": "hann", "win_length": args.win_length, + "hop_length": args.hop_length, "sample_rate": args.sample_rate, + "win_len_t": win_len_t, "hop_len_t": hop_len_t, + "f_min": args.f_min, "f_max": args.f_max, + "n_stft": args.n_fft // 2 + 1 + } + } + if len(speakers) > 1: + extra["speaker_set_filename"] = "speakers.txt" + gen_config_yaml( + out_root, spm_filename=spm_filename, vocab_name=vocab_name, + audio_root=out_root.as_posix(), input_channels=None, + input_feat_per_channel=None, specaugment_policy=None, + cmvn_type="global", gcmvn_path=gcmvn_npz_path, extra=extra + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--audio-manifest-root", "-m", required=True, type=str) + parser.add_argument("--output-root", "-o", required=True, type=str) + parser.add_argument("--splits", "-s", type=str, nargs="+", + default=["train", "dev", "test"]) + parser.add_argument("--ipa-vocab", action="store_true") + parser.add_argument("--use-g2p", action="store_true") + parser.add_argument("--lang", type=str, default="en-us") + parser.add_argument("--win-length", type=int, default=1024) + parser.add_argument("--hop-length", type=int, default=256) + parser.add_argument("--n-fft", type=int, default=1024) + parser.add_argument("--n-mels", type=int, default=80) + parser.add_argument("--f-min", type=int, default=20) + parser.add_argument("--f-max", type=int, default=8000) + parser.add_argument("--sample-rate", type=int, default=22050) + parser.add_argument("--normalize-volume", "-n", action="store_true") + parser.add_argument("--textgrid-zip", type=str, default=None) + parser.add_argument("--id-to-units-tsv", type=str, default=None) + parser.add_argument("--add-fastspeech-targets", action="store_true") + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_synthesis/preprocessing/get_ljspeech_audio_manifest.py b/examples/speech_synthesis/preprocessing/get_ljspeech_audio_manifest.py new file mode 100644 index 0000000000..7ec1fb7521 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/get_ljspeech_audio_manifest.py @@ -0,0 +1,70 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +from pathlib import Path +from collections import defaultdict + +import pandas as pd +from torchaudio.datasets import LJSPEECH +from tqdm import tqdm + +from examples.speech_to_text.data_utils import save_df_to_tsv + + +log = logging.getLogger(__name__) + +SPLITS = ["train", "dev", "test"] + + +def process(args): + out_root = Path(args.output_data_root).absolute() + out_root.mkdir(parents=True, exist_ok=True) + + # Generate TSV manifest + print("Generating manifest...") + # following FastSpeech's splits + dataset = LJSPEECH(out_root.as_posix(), download=True) + id_to_split = {} + for x in dataset._flist: + id_ = x[0] + speaker = id_.split("-")[0] + id_to_split[id_] = { + "LJ001": "test", "LJ002": "test", "LJ003": "dev" + }.get(speaker, "train") + manifest_by_split = {split: defaultdict(list) for split in SPLITS} + progress = tqdm(enumerate(dataset), total=len(dataset)) + for i, (waveform, _, utt, normalized_utt) in progress: + sample_id = dataset._flist[i][0] + split = id_to_split[sample_id] + manifest_by_split[split]["id"].append(sample_id) + audio_path = f"{dataset._path}/{sample_id}.wav" + manifest_by_split[split]["audio"].append(audio_path) + manifest_by_split[split]["n_frames"].append(len(waveform[0])) + manifest_by_split[split]["tgt_text"].append(normalized_utt) + manifest_by_split[split]["speaker"].append("ljspeech") + manifest_by_split[split]["src_text"].append(utt) + + manifest_root = Path(args.output_manifest_root).absolute() + manifest_root.mkdir(parents=True, exist_ok=True) + for split in SPLITS: + save_df_to_tsv( + pd.DataFrame.from_dict(manifest_by_split[split]), + manifest_root / f"{split}.audio.tsv" + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--output-data-root", "-d", required=True, type=str) + parser.add_argument("--output-manifest-root", "-m", required=True, type=str) + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_synthesis/preprocessing/get_speaker_embedding.py b/examples/speech_synthesis/preprocessing/get_speaker_embedding.py new file mode 100644 index 0000000000..0e3e4c5cd7 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/get_speaker_embedding.py @@ -0,0 +1,89 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import argparse +from collections import defaultdict +from itertools import chain +from pathlib import Path + +import numpy as np +import torchaudio +import torchaudio.sox_effects as ta_sox +import yaml +from tqdm import tqdm + +from examples.speech_to_text.data_utils import load_tsv_to_dicts +from examples.speech_synthesis.preprocessing.speaker_embedder import SpkrEmbedder + + +def extract_embedding(audio_path, embedder): + wav, sr = torchaudio.load(audio_path) # 2D + if sr != embedder.RATE: + wav, sr = ta_sox.apply_effects_tensor( + wav, sr, [["rate", str(embedder.RATE)]] + ) + try: + emb = embedder([wav[0].cuda().float()]).cpu().numpy() + except RuntimeError: + emb = None + return emb + + +def process(args): + print("Fetching data...") + raw_manifest_root = Path(args.raw_manifest_root).absolute() + samples = [load_tsv_to_dicts(raw_manifest_root / (s + ".tsv")) + for s in args.splits] + samples = list(chain(*samples)) + with open(args.config, "r") as f: + config = yaml.load(f, Loader=yaml.FullLoader) + with open(f"{config['audio_root']}/{config['speaker_set_filename']}") as f: + speaker_to_id = {r.strip(): i for i, r in enumerate(f)} + + embedder = SpkrEmbedder(args.ckpt).cuda() + speaker_to_cnt = defaultdict(float) + speaker_to_emb = defaultdict(float) + for sample in tqdm(samples, desc="extract emb"): + emb = extract_embedding(sample["audio"], embedder) + if emb is not None: + speaker_to_cnt[sample["speaker"]] += 1 + speaker_to_emb[sample["speaker"]] += emb + if len(speaker_to_emb) != len(speaker_to_id): + missed = set(speaker_to_id) - set(speaker_to_emb.keys()) + print( + f"WARNING: missing embeddings for {len(missed)} speaker:\n{missed}" + ) + speaker_emb_mat = np.zeros((len(speaker_to_id), len(emb)), float) + for speaker in speaker_to_emb: + idx = speaker_to_id[speaker] + emb = speaker_to_emb[speaker] + cnt = speaker_to_cnt[speaker] + speaker_emb_mat[idx, :] = emb / cnt + speaker_emb_name = "speaker_emb.npy" + speaker_emb_path = f"{config['audio_root']}/{speaker_emb_name}" + np.save(speaker_emb_path, speaker_emb_mat) + config["speaker_emb_filename"] = speaker_emb_name + + with open(args.new_config, "w") as f: + yaml.dump(config, f) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--raw-manifest-root", "-m", required=True, type=str) + parser.add_argument("--splits", "-s", type=str, nargs="+", + default=["train"]) + parser.add_argument("--config", "-c", required=True, type=str) + parser.add_argument("--new-config", "-n", required=True, type=str) + parser.add_argument("--ckpt", required=True, type=str, + help="speaker embedder checkpoint") + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_synthesis/preprocessing/get_vctk_audio_manifest.py b/examples/speech_synthesis/preprocessing/get_vctk_audio_manifest.py new file mode 100644 index 0000000000..7afa40fcd1 --- /dev/null +++ b/examples/speech_synthesis/preprocessing/get_vctk_audio_manifest.py @@ -0,0 +1,79 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import numpy as np +import re +from pathlib import Path +from collections import defaultdict + +import pandas as pd +from torchaudio.datasets import VCTK +from tqdm import tqdm + +from examples.speech_to_text.data_utils import save_df_to_tsv + + +log = logging.getLogger(__name__) + +SPLITS = ["train", "dev", "test"] + + +def normalize_text(text): + return re.sub(r"[^a-zA-Z.?!,'\- ]", '', text) + + +def process(args): + out_root = Path(args.output_data_root).absolute() + out_root.mkdir(parents=True, exist_ok=True) + + # Generate TSV manifest + print("Generating manifest...") + dataset = VCTK(out_root.as_posix(), download=False) + ids = list(dataset._walker) + np.random.seed(args.seed) + np.random.shuffle(ids) + n_train = len(ids) - args.n_dev - args.n_test + _split = ["train"] * n_train + ["dev"] * args.n_dev + ["test"] * args.n_test + id_to_split = dict(zip(ids, _split)) + manifest_by_split = {split: defaultdict(list) for split in SPLITS} + progress = tqdm(enumerate(dataset), total=len(dataset)) + for i, (waveform, _, text, speaker_id, _) in progress: + sample_id = dataset._walker[i] + _split = id_to_split[sample_id] + audio_dir = Path(dataset._path) / dataset._folder_audio / speaker_id + audio_path = audio_dir / f"{sample_id}.wav" + text = normalize_text(text) + manifest_by_split[_split]["id"].append(sample_id) + manifest_by_split[_split]["audio"].append(audio_path.as_posix()) + manifest_by_split[_split]["n_frames"].append(len(waveform[0])) + manifest_by_split[_split]["tgt_text"].append(text) + manifest_by_split[_split]["speaker"].append(speaker_id) + manifest_by_split[_split]["src_text"].append(text) + + manifest_root = Path(args.output_manifest_root).absolute() + manifest_root.mkdir(parents=True, exist_ok=True) + for _split in SPLITS: + save_df_to_tsv( + pd.DataFrame.from_dict(manifest_by_split[_split]), + manifest_root / f"{_split}.audio.tsv" + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--output-data-root", "-d", required=True, type=str) + parser.add_argument("--output-manifest-root", "-m", required=True, type=str) + parser.add_argument("--n-dev", default=50, type=int) + parser.add_argument("--n-test", default=100, type=int) + parser.add_argument("--seed", "-s", default=1234, type=int) + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_synthesis/preprocessing/speaker_embedder/__init__.py b/examples/speech_synthesis/preprocessing/speaker_embedder/__init__.py new file mode 100644 index 0000000000..3b178676ba --- /dev/null +++ b/examples/speech_synthesis/preprocessing/speaker_embedder/__init__.py @@ -0,0 +1,135 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import librosa +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.utils.data +import torchaudio + + +EMBEDDER_PARAMS = { + 'num_mels': 40, + 'n_fft': 512, + 'emb_dim': 256, + 'lstm_hidden': 768, + 'lstm_layers': 3, + 'window': 80, + 'stride': 40, +} + + +def set_requires_grad(nets, requires_grad=False): + """Set requies_grad=Fasle for all the networks to avoid unnecessary + computations + Parameters: + nets (network list) -- a list of networks + requires_grad (bool) -- whether the networks require gradients or not + """ + if not isinstance(nets, list): + nets = [nets] + for net in nets: + if net is not None: + for param in net.parameters(): + param.requires_grad = requires_grad + + +class LinearNorm(nn.Module): + def __init__(self, hp): + super(LinearNorm, self).__init__() + self.linear_layer = nn.Linear(hp["lstm_hidden"], hp["emb_dim"]) + + def forward(self, x): + return self.linear_layer(x) + + +class SpeechEmbedder(nn.Module): + def __init__(self, hp): + super(SpeechEmbedder, self).__init__() + self.lstm = nn.LSTM(hp["num_mels"], + hp["lstm_hidden"], + num_layers=hp["lstm_layers"], + batch_first=True) + self.proj = LinearNorm(hp) + self.hp = hp + + def forward(self, mel): + # (num_mels, T) -> (num_mels, T', window) + mels = mel.unfold(1, self.hp["window"], self.hp["stride"]) + mels = mels.permute(1, 2, 0) # (T', window, num_mels) + x, _ = self.lstm(mels) # (T', window, lstm_hidden) + x = x[:, -1, :] # (T', lstm_hidden), use last frame only + x = self.proj(x) # (T', emb_dim) + x = x / torch.norm(x, p=2, dim=1, keepdim=True) # (T', emb_dim) + + x = x.mean(dim=0) + if x.norm(p=2) != 0: + x = x / x.norm(p=2) + return x + + +class SpkrEmbedder(nn.Module): + RATE = 16000 + + def __init__( + self, + embedder_path, + embedder_params=EMBEDDER_PARAMS, + rate=16000, + hop_length=160, + win_length=400, + pad=False, + ): + super(SpkrEmbedder, self).__init__() + embedder_pt = torch.load(embedder_path, map_location="cpu") + self.embedder = SpeechEmbedder(embedder_params) + self.embedder.load_state_dict(embedder_pt) + self.embedder.eval() + set_requires_grad(self.embedder, requires_grad=False) + self.embedder_params = embedder_params + + self.register_buffer('mel_basis', torch.from_numpy( + librosa.filters.mel( + sr=self.RATE, + n_fft=self.embedder_params["n_fft"], + n_mels=self.embedder_params["num_mels"]) + ) + ) + + self.resample = None + if rate != self.RATE: + self.resample = torchaudio.transforms.Resample(rate, self.RATE) + self.hop_length = hop_length + self.win_length = win_length + self.pad = pad + + def get_mel(self, y): + if self.pad and y.shape[-1] < 14000: + y = F.pad(y, (0, 14000 - y.shape[-1])) + + window = torch.hann_window(self.win_length).to(y) + y = torch.stft(y, n_fft=self.embedder_params["n_fft"], + hop_length=self.hop_length, + win_length=self.win_length, + window=window) + magnitudes = torch.norm(y, dim=-1, p=2) ** 2 + mel = torch.log10(self.mel_basis @ magnitudes + 1e-6) + return mel + + def forward(self, inputs): + dvecs = [] + for wav in inputs: + mel = self.get_mel(wav) + if mel.dim() == 3: + mel = mel.squeeze(0) + dvecs += [self.embedder(mel)] + dvecs = torch.stack(dvecs) + + dvec = torch.mean(dvecs, dim=0) + dvec = dvec / torch.norm(dvec) + + return dvec diff --git a/examples/speech_synthesis/preprocessing/vad/__init__.py b/examples/speech_synthesis/preprocessing/vad/__init__.py new file mode 100644 index 0000000000..9cf121081f --- /dev/null +++ b/examples/speech_synthesis/preprocessing/vad/__init__.py @@ -0,0 +1,192 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import collections +import contextlib +import wave + +try: + import webrtcvad +except ImportError: + raise ImportError("Please install py-webrtcvad: pip install webrtcvad") +import argparse +import os +import logging +from tqdm import tqdm + +AUDIO_SUFFIX = '.wav' +FS_MS = 30 +SCALE = 6e-5 +THRESHOLD = 0.3 + + +def read_wave(path): + """Reads a .wav file. + Takes the path, and returns (PCM audio data, sample rate). + """ + with contextlib.closing(wave.open(path, 'rb')) as wf: + num_channels = wf.getnchannels() + assert num_channels == 1 + sample_width = wf.getsampwidth() + assert sample_width == 2 + sample_rate = wf.getframerate() + assert sample_rate in (8000, 16000, 32000, 48000) + pcm_data = wf.readframes(wf.getnframes()) + return pcm_data, sample_rate + + +def write_wave(path, audio, sample_rate): + """Writes a .wav file. + Takes path, PCM audio data, and sample rate. + """ + with contextlib.closing(wave.open(path, 'wb')) as wf: + wf.setnchannels(1) + wf.setsampwidth(2) + wf.setframerate(sample_rate) + wf.writeframes(audio) + + +class Frame(object): + """Represents a "frame" of audio data.""" + def __init__(self, bytes, timestamp, duration): + self.bytes = bytes + self.timestamp = timestamp + self.duration = duration + + +def frame_generator(frame_duration_ms, audio, sample_rate): + """Generates audio frames from PCM audio data. + Takes the desired frame duration in milliseconds, the PCM data, and + the sample rate. + Yields Frames of the requested duration. + """ + n = int(sample_rate * (frame_duration_ms / 1000.0) * 2) + offset = 0 + timestamp = 0.0 + duration = (float(n) / sample_rate) / 2.0 + while offset + n < len(audio): + yield Frame(audio[offset:offset + n], timestamp, duration) + timestamp += duration + offset += n + + +def vad_collector(sample_rate, frame_duration_ms, + padding_duration_ms, vad, frames): + """Filters out non-voiced audio frames. + Given a webrtcvad.Vad and a source of audio frames, yields only + the voiced audio. + Uses a padded, sliding window algorithm over the audio frames. + When more than 90% of the frames in the window are voiced (as + reported by the VAD), the collector triggers and begins yielding + audio frames. Then the collector waits until 90% of the frames in + the window are unvoiced to detrigger. + The window is padded at the front and back to provide a small + amount of silence or the beginnings/endings of speech around the + voiced frames. + Arguments: + sample_rate - The audio sample rate, in Hz. + frame_duration_ms - The frame duration in milliseconds. + padding_duration_ms - The amount to pad the window, in milliseconds. + vad - An instance of webrtcvad.Vad. + frames - a source of audio frames (sequence or generator). + Returns: A generator that yields PCM audio data. + """ + num_padding_frames = int(padding_duration_ms / frame_duration_ms) + # We use a deque for our sliding window/ring buffer. + ring_buffer = collections.deque(maxlen=num_padding_frames) + # We have two states: TRIGGERED and NOTTRIGGERED. We start in the + # NOTTRIGGERED state. + triggered = False + + voiced_frames = [] + for frame in frames: + is_speech = vad.is_speech(frame.bytes, sample_rate) + + # sys.stdout.write('1' if is_speech else '0') + if not triggered: + ring_buffer.append((frame, is_speech)) + num_voiced = len([f for f, speech in ring_buffer if speech]) + # If we're NOTTRIGGERED and more than 90% of the frames in + # the ring buffer are voiced frames, then enter the + # TRIGGERED state. + if num_voiced > 0.9 * ring_buffer.maxlen: + triggered = True + # We want to yield all the audio we see from now until + # we are NOTTRIGGERED, but we have to start with the + # audio that's already in the ring buffer. + for f, _ in ring_buffer: + voiced_frames.append(f) + ring_buffer.clear() + else: + # We're in the TRIGGERED state, so collect the audio data + # and add it to the ring buffer. + voiced_frames.append(frame) + ring_buffer.append((frame, is_speech)) + num_unvoiced = len([f for f, speech in ring_buffer if not speech]) + # If more than 90% of the frames in the ring buffer are + # unvoiced, then enter NOTTRIGGERED and yield whatever + # audio we've collected. + if num_unvoiced > 0.9 * ring_buffer.maxlen: + triggered = False + yield [b''.join([f.bytes for f in voiced_frames]), + voiced_frames[0].timestamp, voiced_frames[-1].timestamp] + ring_buffer.clear() + voiced_frames = [] + # If we have any leftover voiced audio when we run out of input, + # yield it. + if voiced_frames: + yield [b''.join([f.bytes for f in voiced_frames]), + voiced_frames[0].timestamp, voiced_frames[-1].timestamp] + + +def main(args): + # create output folder + try: + cmd = f"mkdir -p {args.out_path}" + os.system(cmd) + except Exception: + logging.error("Can not create output folder") + exit(-1) + + # build vad object + vad = webrtcvad.Vad(int(args.agg)) + # iterating over wavs in dir + for file in tqdm(os.listdir(args.in_path)): + if file.endswith(AUDIO_SUFFIX): + audio_inpath = os.path.join(args.in_path, file) + audio_outpath = os.path.join(args.out_path, file) + audio, sample_rate = read_wave(audio_inpath) + frames = frame_generator(FS_MS, audio, sample_rate) + frames = list(frames) + segments = vad_collector(sample_rate, FS_MS, 300, vad, frames) + merge_segments = list() + timestamp_start = 0.0 + timestamp_end = 0.0 + # removing start, end, and long sequences of sils + for i, segment in enumerate(segments): + merge_segments.append(segment[0]) + if i and timestamp_start: + sil_duration = segment[1] - timestamp_end + if sil_duration > THRESHOLD: + merge_segments.append(int(THRESHOLD / SCALE)*(b'\x00')) + else: + merge_segments.append(int((sil_duration / SCALE))*(b'\x00')) + timestamp_start = segment[1] + timestamp_end = segment[2] + segment = b''.join(merge_segments) + write_wave(audio_outpath, segment, sample_rate) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Apply vad to a file of fils.') + parser.add_argument('in_path', type=str, help='Path to the input files') + parser.add_argument('out_path', type=str, + help='Path to save the processed files') + parser.add_argument('--agg', type=int, default=3, + help='The level of aggressiveness of the VAD: [0-3]') + args = parser.parse_args() + + main(args) From d974c709bf57cf494738a824a1597e1886bebb7a Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Sun, 12 Sep 2021 22:21:09 -0700 Subject: [PATCH 454/774] update S2T Summary: [fairseq-py] update S2T Reviewed By: wnhsu Differential Revision: D30720434 fbshipit-source-id: dc4e46b0cc3dec24943baeabe59424dabd5be38f --- examples/speech_to_text/data_utils.py | 115 +++++++---- examples/speech_to_text/prep_covost_data.py | 11 +- .../speech_to_text/prep_librispeech_data.py | 13 +- examples/speech_to_text/prep_mtedx_data.py | 103 ++++++---- examples/speech_to_text/prep_mustc_data.py | 137 ++++++++----- fairseq/data/audio/audio_utils.py | 172 ++++++++++++---- fairseq/data/audio/data_cfg.py | 139 +++++++++++++ fairseq/data/audio/speech_to_text_dataset.py | 188 ++++++------------ fairseq_cli/generate.py | 2 +- 9 files changed, 571 insertions(+), 309 deletions(-) create mode 100644 fairseq/data/audio/data_cfg.py diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index 2bcff046f7..41afac0bf8 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # Copyright (c) Facebook, Inc. and its affiliates. # # This source code is licensed under the MIT license found in the @@ -10,14 +9,17 @@ from functools import reduce from multiprocessing import cpu_count from typing import Any, Dict, List, Optional, Union +import io import numpy as np import pandas as pd import sentencepiece as sp from fairseq.data.audio.audio_utils import ( - _convert_to_mono, _get_kaldi_fbank, _get_torchaudio_fbank + convert_waveform, _get_kaldi_fbank, _get_torchaudio_fbank, is_npy_data, + is_sf_audio_data ) import torch +import soundfile as sf from tqdm import tqdm @@ -78,8 +80,9 @@ def extract_fbank_features( if output_path is not None and output_path.is_file() and not overwrite: return - _waveform = _convert_to_mono(waveform, sample_rate) - _waveform = _waveform * (2 ** 15) # Kaldi compliance: 16-bit signed integers + _waveform = convert_waveform(waveform, sample_rate, to_mono=True) + # Kaldi compliance: 16-bit signed integers + _waveform = _waveform * (2 ** 15) _waveform = _waveform.numpy() features = _get_kaldi_fbank(_waveform, sample_rate, n_mel_bins) @@ -92,8 +95,7 @@ def extract_fbank_features( if output_path is not None: np.save(output_path.as_posix(), features) - else: - return features + return features def create_zip(data_root: Path, zip_path: Path): @@ -103,42 +105,58 @@ def create_zip(data_root: Path, zip_path: Path): f.write(path, arcname=path.name) -def is_npy_data(data: bytes) -> bool: - return data[0] == 147 and data[1] == 78 - - -def get_zip_manifest(zip_path: Path, zip_root: Optional[Path] = None): - _zip_path = zip_path if zip_root is None else Path.joinpath(zip_root, zip_path) +def get_zip_manifest( + zip_path: Path, zip_root: Optional[Path] = None, is_audio=False +): + _zip_path = Path.joinpath(zip_root or Path(""), zip_path) with zipfile.ZipFile(_zip_path, mode="r") as f: info = f.infolist() - manifest = {} + paths, lengths = {}, {} for i in tqdm(info): utt_id = Path(i.filename).stem offset, file_size = i.header_offset + 30 + len(i.filename), i.file_size - manifest[utt_id] = f"{zip_path.as_posix()}:{offset}:{file_size}" + paths[utt_id] = f"{zip_path.as_posix()}:{offset}:{file_size}" with open(_zip_path, "rb") as f: f.seek(offset) - data = f.read(file_size) - assert len(data) > 1 and is_npy_data(data) - return manifest + byte_data = f.read(file_size) + assert len(byte_data) > 1 + if is_audio: + assert is_sf_audio_data(byte_data), i + else: + assert is_npy_data(byte_data), i + byte_data_fp = io.BytesIO(byte_data) + if is_audio: + lengths[utt_id] = sf.info(byte_data_fp).frames + else: + lengths[utt_id] = np.load(byte_data_fp).shape[0] + return paths, lengths def gen_config_yaml( manifest_root: Path, - spm_filename: str, + spm_filename: Optional[str] = None, + vocab_name: Optional[str] = None, yaml_filename: str = "config.yaml", - specaugment_policy: str = "lb", + specaugment_policy: Optional[str] = "lb", prepend_tgt_lang_tag: bool = False, - sampling_alpha: float = 1.0, + sampling_alpha: Optional[float] = None, + input_channels: Optional[int] = 1, + input_feat_per_channel: Optional[int] = 80, audio_root: str = "", cmvn_type: str = "utterance", gcmvn_path: Optional[Path] = None, + extra=None ): manifest_root = manifest_root.absolute() writer = S2TDataConfigWriter(manifest_root / yaml_filename) - writer.set_vocab_filename(spm_filename.replace(".model", ".txt")) - writer.set_input_channels(1) - writer.set_input_feat_per_channel(80) + assert spm_filename is not None or vocab_name is not None + vocab_name = spm_filename.replace(".model", ".txt") if vocab_name is None \ + else vocab_name + writer.set_vocab_filename(vocab_name) + if input_channels is not None: + writer.set_input_channels(input_channels) + if input_feat_per_channel is not None: + writer.set_input_feat_per_channel(input_feat_per_channel) specaugment_setters = { "lb": writer.set_specaugment_lb_policy, "ld": writer.set_specaugment_ld_policy, @@ -148,34 +166,42 @@ def gen_config_yaml( specaugment_setter = specaugment_setters.get(specaugment_policy, None) if specaugment_setter is not None: specaugment_setter() - writer.set_bpe_tokenizer( - { - "bpe": "sentencepiece", - "sentencepiece_model": (manifest_root / spm_filename).as_posix(), - } - ) + if spm_filename is not None: + writer.set_bpe_tokenizer( + { + "bpe": "sentencepiece", + "sentencepiece_model": (manifest_root / spm_filename).as_posix(), + } + ) if prepend_tgt_lang_tag: writer.set_prepend_tgt_lang_tag(True) - writer.set_sampling_alpha(sampling_alpha) + if sampling_alpha is not None: + writer.set_sampling_alpha(sampling_alpha) if cmvn_type not in ["global", "utterance"]: raise NotImplementedError - writer.set_feature_transforms("_train", [f"{cmvn_type}_cmvn", "specaugment"]) + if specaugment_policy is not None: + writer.set_feature_transforms( + "_train", [f"{cmvn_type}_cmvn", "specaugment"] + ) writer.set_feature_transforms("*", [f"{cmvn_type}_cmvn"]) if cmvn_type == "global": - assert gcmvn_path is not None, ( - 'Please provide path of global cmvn file.' - ) - writer.set_global_cmvn(str(gcmvn_path)) + if gcmvn_path is None: + raise ValueError("Please provide path of global cmvn file.") + else: + writer.set_global_cmvn(gcmvn_path.as_posix()) if len(audio_root) > 0: writer.set_audio_root(audio_root) + + if extra is not None: + writer.set_extra(extra) writer.flush() -def load_df_from_tsv(path: Union[str, Path]): +def load_df_from_tsv(path: Union[str, Path]) -> pd.DataFrame: _path = path if isinstance(path, str) else path.as_posix() return pd.read_csv( _path, @@ -201,6 +227,20 @@ def save_df_to_tsv(dataframe, path: Union[str, Path]): ) +def load_tsv_to_dicts(path: Union[str, Path]) -> List[dict]: + with open(path, "r") as f: + reader = csv.DictReader( + f, + delimiter="\t", + quotechar=None, + doublequote=False, + lineterminator="\n", + quoting=csv.QUOTE_NONE, + ) + rows = [dict(e) for e in reader] + return rows + + def filter_manifest_df( df, is_train_split=False, extra_filters=None, min_n_frames=5, max_n_frames=3000 ): @@ -337,3 +377,6 @@ def set_prepend_tgt_lang_tag(self, flag: bool = True): def set_sampling_alpha(self, sampling_alpha: float = 1.0): self.config["sampling_alpha"] = sampling_alpha + + def set_extra(self, data): + self.config.update(data) diff --git a/examples/speech_to_text/prep_covost_data.py b/examples/speech_to_text/prep_covost_data.py index af1d3fc6b8..411e9b5515 100644 --- a/examples/speech_to_text/prep_covost_data.py +++ b/examples/speech_to_text/prep_covost_data.py @@ -209,7 +209,7 @@ def process(args): print("ZIPing features...") create_zip(feature_root, zip_path) print("Fetching ZIP manifest...") - zip_manifest = get_zip_manifest(zip_path) + audio_paths, audio_lengths = get_zip_manifest(zip_path) # Generate TSV manifest print("Generating manifest...") train_text = [] @@ -219,11 +219,10 @@ def process(args): for split in CoVoST.SPLITS: manifest = {c: [] for c in MANIFEST_COLUMNS} dataset = CoVoST(root, split, args.src_lang, args.tgt_lang) - for wav, sr, src_utt, tgt_utt, speaker_id, utt_id in tqdm(dataset): + for _, _, src_utt, tgt_utt, speaker_id, utt_id in tqdm(dataset): manifest["id"].append(utt_id) - manifest["audio"].append(zip_manifest[utt_id]) - duration_ms = int(wav.size(1) / sr * 1000) - manifest["n_frames"].append(int(1 + (duration_ms - 25) / 10)) + manifest["audio"].append(audio_paths[utt_id]) + manifest["n_frames"].append(audio_lengths[utt_id]) manifest["tgt_text"].append(src_utt if args.tgt_lang is None else tgt_utt) manifest["speaker"].append(speaker_id) is_train_split = split.startswith("train") @@ -247,7 +246,7 @@ def process(args): # Generate config YAML gen_config_yaml( root, - spm_filename_prefix + ".model", + spm_filename=spm_filename_prefix + ".model", yaml_filename=f"config_{task}.yaml", specaugment_policy="lb", ) diff --git a/examples/speech_to_text/prep_librispeech_data.py b/examples/speech_to_text/prep_librispeech_data.py index 7b08447190..f379fa7bf1 100644 --- a/examples/speech_to_text/prep_librispeech_data.py +++ b/examples/speech_to_text/prep_librispeech_data.py @@ -58,19 +58,18 @@ def process(args): print("ZIPing features...") create_zip(feature_root, zip_path) print("Fetching ZIP manifest...") - zip_manifest = get_zip_manifest(zip_path) + audio_paths, audio_lengths = get_zip_manifest(zip_path) # Generate TSV manifest print("Generating manifest...") train_text = [] for split in SPLITS: manifest = {c: [] for c in MANIFEST_COLUMNS} dataset = LIBRISPEECH(out_root.as_posix(), url=split) - for wav, sample_rate, utt, spk_id, chapter_no, utt_no in tqdm(dataset): + for _, _, utt, spk_id, chapter_no, utt_no in tqdm(dataset): sample_id = f"{spk_id}-{chapter_no}-{utt_no}" manifest["id"].append(sample_id) - manifest["audio"].append(zip_manifest[sample_id]) - duration_ms = int(wav.size(1) / sample_rate * 1000) - manifest["n_frames"].append(int(1 + (duration_ms - 25) / 10)) + manifest["audio"].append(audio_paths[sample_id]) + manifest["n_frames"].append(audio_lengths[sample_id]) manifest["tgt_text"].append(utt.lower()) manifest["speaker"].append(spk_id) save_df_to_tsv( @@ -92,7 +91,9 @@ def process(args): ) # Generate config YAML gen_config_yaml( - out_root, spm_filename_prefix + ".model", specaugment_policy="ld" + out_root, + spm_filename=spm_filename_prefix + ".model", + specaugment_policy="ld" ) # Clean up shutil.rmtree(feature_root) diff --git a/examples/speech_to_text/prep_mtedx_data.py b/examples/speech_to_text/prep_mtedx_data.py index 34b1c398c8..2dfd631763 100644 --- a/examples/speech_to_text/prep_mtedx_data.py +++ b/examples/speech_to_text/prep_mtedx_data.py @@ -29,13 +29,15 @@ from torch.utils.data import Dataset from tqdm import tqdm -from fairseq.data.audio.audio_utils import get_waveform +from fairseq.data.audio.audio_utils import get_waveform, convert_waveform log = logging.getLogger(__name__) -MANIFEST_COLUMNS = ["id", "audio", "n_frames", "tgt_text", "speaker", "tgt_lang"] +MANIFEST_COLUMNS = [ + "id", "audio", "n_frames", "tgt_text", "speaker", "tgt_lang" +] class mTEDx(Dataset): @@ -46,9 +48,9 @@ class mTEDx(Dataset): """ SPLITS = ["train", "valid", "test"] - LANGPAIRS = ["es-es", "fr-fr", "pt-pt", "it-it", "ru-ru", "el-el", "ar-ar", "de-de", - "es-en", "es-fr", "es-pt", "es-it", "fr-en", "fr-es", "fr-pt", - "pt-en", "pt-es", "it-en", "it-es", "ru-en", "el-en"] + LANGPAIRS = ["es-es", "fr-fr", "pt-pt", "it-it", "ru-ru", "el-el", "ar-ar", + "de-de", "es-en", "es-fr", "es-pt", "es-it", "fr-en", "fr-es", + "fr-pt", "pt-en", "pt-es", "it-en", "it-es", "ru-en", "el-en"] def __init__(self, root: str, lang: str, split: str) -> None: assert split in self.SPLITS and lang in self.LANGPAIRS @@ -59,7 +61,9 @@ def __init__(self, root: str, lang: str, split: str) -> None: try: import yaml except ImportError: - print("Please install PyYAML to load the Multilingual TEDx YAML files") + print( + "Please install PyYAML to load the Multilingual TEDx YAML files" + ) with open(txt_root / f"{split}.yaml") as f: segments = yaml.load(f, Loader=yaml.BaseLoader) # Load source and target utterances @@ -95,8 +99,11 @@ def __init__(self, root: str, lang: str, split: str) -> None: ) ) - def __getitem__(self, n: int) -> Tuple[torch.Tensor, int, str, str, str, str, str]: - wav_path, offset, n_frames, sr, src_utt, tgt_utt, spk_id, tgt_lang, utt_id = self.data[n] + def __getitem__( + self, n: int + ) -> Tuple[torch.Tensor, int, str, str, str, str, str]: + wav_path, offset, n_frames, sr, src_utt, tgt_utt, spk_id, tgt_lang, \ + utt_id = self.data[n] waveform, _ = get_waveform(wav_path, frames=n_frames, start=offset) waveform = torch.from_numpy(waveform) return waveform, sr, src_utt, tgt_utt, spk_id, tgt_lang, utt_id @@ -113,36 +120,50 @@ def process(args): print(f"{cur_root.as_posix()} does not exist. Skipped.") continue # Extract features - feature_root = cur_root / "fbank80" - feature_root.mkdir(exist_ok=True) + audio_root = cur_root / ("flac" if args.use_audio_input else "fbank80") + audio_root.mkdir(exist_ok=True) for split in mTEDx.SPLITS: print(f"Fetching split {split}...") dataset = mTEDx(root.as_posix(), lang, split) - print("Extracting log mel filter bank features...") - for waveform, sample_rate, _, _, _, _, utt_id in tqdm(dataset): - extract_fbank_features( - waveform, sample_rate, feature_root / f"{utt_id}.npy" - ) + if args.use_audio_input: + print("Converting audios...") + for waveform, sample_rate, _, _, _, utt_id in tqdm(dataset): + tgt_sample_rate = 16_000 + _wavform, _ = convert_waveform( + waveform, sample_rate, to_mono=True, + to_sample_rate=tgt_sample_rate + ) + sf.write( + (audio_root / f"{utt_id}.flac").as_posix(), + _wavform.numpy(), tgt_sample_rate + ) + else: + print("Extracting log mel filter bank features...") + for waveform, sample_rate, _, _, _, _, utt_id in tqdm(dataset): + extract_fbank_features( + waveform, sample_rate, audio_root / f"{utt_id}.npy" + ) # Pack features into ZIP - zip_path = cur_root / "fbank80.zip" - print("ZIPing features...") - create_zip(feature_root, zip_path) + zip_path = cur_root / f"{audio_root.name}.zip" + print("ZIPing audios/features...") + create_zip(audio_root, zip_path) print("Fetching ZIP manifest...") - zip_manifest = get_zip_manifest(zip_path) + audio_paths, audio_lengths = get_zip_manifest(zip_path) # Generate TSV manifest print("Generating manifest...") train_text = [] for split in mTEDx.SPLITS: is_train_split = split.startswith("train") manifest = {c: [] for c in MANIFEST_COLUMNS} - dataset = mTEDx(args.data_root, lang, split) - for wav, sr, src_utt, tgt_utt, speaker_id, tgt_lang, utt_id in tqdm(dataset): + ds = mTEDx(args.data_root, lang, split) + for _, _, src_utt, tgt_utt, spk_id, tgt_lang, utt_id in tqdm(ds): manifest["id"].append(utt_id) - manifest["audio"].append(zip_manifest[utt_id]) - duration_ms = int(wav.size(1) / sr * 1000) - manifest["n_frames"].append(int(1 + (duration_ms - 25) / 10)) - manifest["tgt_text"].append(src_utt if args.task == "asr" else tgt_utt) - manifest["speaker"].append(speaker_id) + manifest["audio"].append(audio_paths[utt_id]) + manifest["n_frames"].append(audio_lengths[utt_id]) + manifest["tgt_text"].append( + src_utt if args.task == "asr" else tgt_utt + ) + manifest["speaker"].append(spk_id) manifest["tgt_lang"].append(tgt_lang) if is_train_split: train_text.extend(manifest["tgt_text"]) @@ -162,14 +183,23 @@ def process(args): args.vocab_size, ) # Generate config YAML - gen_config_yaml( - cur_root, - spm_filename_prefix + ".model", - yaml_filename=f"config_{args.task}.yaml", - specaugment_policy="lb", - ) + if args.use_audio_input: + gen_config_yaml( + cur_root, + spm_filename=spm_filename_prefix + ".model", + yaml_filename=f"config_{args.task}.yaml", + specaugment_policy=None, + extra={"use_audio_input": True} + ) + else: + gen_config_yaml( + cur_root, + spm_filename=spm_filename_prefix + ".model", + yaml_filename=f"config_{args.task}.yaml", + specaugment_policy="lb", + ) # Clean up - shutil.rmtree(feature_root) + shutil.rmtree(audio_root) def process_joint(args): @@ -188,7 +218,9 @@ def process_joint(args): special_symbols = None if args.joint: # Add tgt_lang tags to dict - special_symbols = list({f'<lang:{lang.split("-")[1]}>' for lang in mTEDx.LANGPAIRS}) + special_symbols = list( + {f'<lang:{lang.split("-")[1]}>' for lang in mTEDx.LANGPAIRS} + ) gen_vocab( Path(f.name), cur_root / spm_filename_prefix, @@ -199,7 +231,7 @@ def process_joint(args): # Generate config YAML gen_config_yaml( cur_root, - spm_filename_prefix + ".model", + spm_filename=spm_filename_prefix + ".model", yaml_filename=f"config_{args.task}.yaml", specaugment_policy="ld", prepend_tgt_lang_tag=(args.joint), @@ -226,6 +258,7 @@ def main(): parser.add_argument("--vocab-size", default=8000, type=int) parser.add_argument("--task", type=str, choices=["asr", "st"]) parser.add_argument("--joint", action="store_true", help="") + parser.add_argument("--use-audio-input", action="store_true") args = parser.parse_args() if args.joint: diff --git a/examples/speech_to_text/prep_mustc_data.py b/examples/speech_to_text/prep_mustc_data.py index 0ee204e651..3f0d3fcbd9 100644 --- a/examples/speech_to_text/prep_mustc_data.py +++ b/examples/speech_to_text/prep_mustc_data.py @@ -31,7 +31,7 @@ from torch.utils.data import Dataset from tqdm import tqdm -from fairseq.data.audio.audio_utils import get_waveform +from fairseq.data.audio.audio_utils import get_waveform, convert_waveform log = logging.getLogger(__name__) @@ -92,8 +92,11 @@ def __init__(self, root: str, lang: str, split: str) -> None: ) ) - def __getitem__(self, n: int) -> Tuple[torch.Tensor, int, str, str, str, str]: - wav_path, offset, n_frames, sr, src_utt, tgt_utt, spk_id, utt_id = self.data[n] + def __getitem__( + self, n: int + ) -> Tuple[torch.Tensor, int, str, str, str, str]: + wav_path, offset, n_frames, sr, src_utt, tgt_utt, spk_id, \ + utt_id = self.data[n] waveform, _ = get_waveform(wav_path, frames=n_frames, start=offset) waveform = torch.from_numpy(waveform) return waveform, sr, src_utt, tgt_utt, spk_id, utt_id @@ -110,40 +113,50 @@ def process(args): print(f"{cur_root.as_posix()} does not exist. Skipped.") continue # Extract features - feature_root = cur_root / "fbank80" - feature_root.mkdir(exist_ok=True) + audio_root = cur_root / ("flac" if args.use_audio_input else "fbank80") + audio_root.mkdir(exist_ok=True) + for split in MUSTC.SPLITS: print(f"Fetching split {split}...") dataset = MUSTC(root.as_posix(), lang, split) - print("Extracting log mel filter bank features...") - if split == 'train' and args.cmvn_type == "global": - print("And estimating cepstral mean and variance stats...") + if args.use_audio_input: + print("Converting audios...") + for waveform, sample_rate, _, _, _, utt_id in tqdm(dataset): + tgt_sample_rate = 16_000 + _wavform, _ = convert_waveform( + waveform, sample_rate, to_mono=True, + to_sample_rate=tgt_sample_rate + ) + sf.write( + (audio_root / f"{utt_id}.flac").as_posix(), + _wavform.numpy(), tgt_sample_rate + ) + else: + print("Extracting log mel filter bank features...") gcmvn_feature_list = [] + if split == 'train' and args.cmvn_type == "global": + print("And estimating cepstral mean and variance stats...") - for waveform, sample_rate, _, _, _, utt_id in tqdm(dataset): - features = extract_fbank_features(waveform, sample_rate) - - np.save( - (feature_root / f"{utt_id}.npy").as_posix(), - features - ) + for waveform, sample_rate, _, _, _, utt_id in tqdm(dataset): + features = extract_fbank_features( + waveform, sample_rate, audio_root / f"{utt_id}.npy" + ) + if split == 'train' and args.cmvn_type == "global": + if len(gcmvn_feature_list) < args.gcmvn_max_num: + gcmvn_feature_list.append(features) if split == 'train' and args.cmvn_type == "global": - if len(gcmvn_feature_list) < args.gcmvn_max_num: - gcmvn_feature_list.append(features) - - if split == 'train' and args.cmvn_type == "global": - # Estimate and save cmv - stats = cal_gcmvn_stats(gcmvn_feature_list) - with open(cur_root / "gcmvn.npz", "wb") as f: - np.savez(f, mean=stats["mean"], std=stats["std"]) + # Estimate and save cmv + stats = cal_gcmvn_stats(gcmvn_feature_list) + with open(cur_root / "gcmvn.npz", "wb") as f: + np.savez(f, mean=stats["mean"], std=stats["std"]) # Pack features into ZIP - zip_path = cur_root / "fbank80.zip" - print("ZIPing features...") - create_zip(feature_root, zip_path) + zip_path = cur_root / f"{audio_root.name}.zip" + print("ZIPing audios/features...") + create_zip(audio_root, zip_path) print("Fetching ZIP manifest...") - zip_manifest = get_zip_manifest(zip_path) + audio_paths, audio_lengths = get_zip_manifest(zip_path) # Generate TSV manifest print("Generating manifest...") train_text = [] @@ -151,12 +164,13 @@ def process(args): is_train_split = split.startswith("train") manifest = {c: [] for c in MANIFEST_COLUMNS} dataset = MUSTC(args.data_root, lang, split) - for wav, sr, src_utt, tgt_utt, speaker_id, utt_id in tqdm(dataset): + for _, _, src_utt, tgt_utt, speaker_id, utt_id in tqdm(dataset): manifest["id"].append(utt_id) - manifest["audio"].append(zip_manifest[utt_id]) - duration_ms = int(wav.size(1) / sr * 1000) - manifest["n_frames"].append(int(1 + (duration_ms - 25) / 10)) - manifest["tgt_text"].append(src_utt if args.task == "asr" else tgt_utt) + manifest["audio"].append(audio_paths[utt_id]) + manifest["n_frames"].append(audio_lengths[utt_id]) + manifest["tgt_text"].append( + src_utt if args.task == "asr" else tgt_utt + ) manifest["speaker"].append(speaker_id) if is_train_split: train_text.extend(manifest["tgt_text"]) @@ -176,25 +190,35 @@ def process(args): args.vocab_size, ) # Generate config YAML - gen_config_yaml( - cur_root, - spm_filename_prefix + ".model", - yaml_filename=f"config_{args.task}.yaml", - specaugment_policy="lb", - cmvn_type=args.cmvn_type, - gcmvn_path=( - cur_root / "gcmvn.npz" if args.cmvn_type == "global" - else None - ), - ) + if args.use_audio_input: + gen_config_yaml( + cur_root, + spm_filename=spm_filename_prefix + ".model", + yaml_filename=f"config_{args.task}.yaml", + specaugment_policy=None, + extra={"use_audio_input": True} + ) + else: + gen_config_yaml( + cur_root, + spm_filename=spm_filename_prefix + ".model", + yaml_filename=f"config_{args.task}.yaml", + specaugment_policy="lb", + cmvn_type=args.cmvn_type, + gcmvn_path=( + cur_root / "gcmvn.npz" if args.cmvn_type == "global" + else None + ), + ) # Clean up - shutil.rmtree(feature_root) + shutil.rmtree(audio_root) def process_joint(args): cur_root = Path(args.data_root) - assert all((cur_root / f"en-{lang}").is_dir() for lang in MUSTC.LANGUAGES), \ - "do not have downloaded data available for all 8 languages" + assert all( + (cur_root / f"en-{lang}").is_dir() for lang in MUSTC.LANGUAGES + ), "do not have downloaded data available for all 8 languages" # Generate vocab vocab_size_str = "" if args.vocab_type == "char" else str(args.vocab_size) spm_filename_prefix = f"spm_{args.vocab_type}{vocab_size_str}_{args.task}" @@ -217,7 +241,7 @@ def process_joint(args): # Generate config YAML gen_config_yaml( cur_root, - spm_filename_prefix + ".model", + spm_filename=spm_filename_prefix + ".model", yaml_filename=f"config_{args.task}.yaml", specaugment_policy="ld", prepend_tgt_lang_tag=(args.task == "st"), @@ -244,14 +268,17 @@ def main(): parser.add_argument("--vocab-size", default=8000, type=int) parser.add_argument("--task", type=str, choices=["asr", "st"]) parser.add_argument("--joint", action="store_true", help="") - parser.add_argument("--cmvn-type", default="utterance", - choices=["global", "utterance"], - help="The type of cepstral mean and variance normalization") - parser.add_argument("--gcmvn-max-num", default=150000, type=int, - help=( - "Maximum number of sentences to use to estimate" - "global mean and variance" - )) + parser.add_argument( + "--cmvn-type", default="utterance", + choices=["global", "utterance"], + help="The type of cepstral mean and variance normalization" + ) + parser.add_argument( + "--gcmvn-max-num", default=150000, type=int, + help="Maximum number of sentences to use to estimate global mean and " + "variance" + ) + parser.add_argument("--use-audio-input", action="store_true") args = parser.parse_args() if args.joint: diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index 7c2638dc0c..b9444cb8d0 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -1,65 +1,83 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + from pathlib import Path from typing import BinaryIO, Optional, Tuple, Union, List import numpy as np import torch +import torch.nn.functional as F SF_AUDIO_FILE_EXTENSIONS = {".wav", ".flac", ".ogg"} FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS = {".npy", ".wav", ".flac", ".ogg"} -def update_sample_rate( - waveform: np.ndarray, - sample_rate: int, - tgt_sample_rate: int, -) -> np.ndarray: - if tgt_sample_rate > 0 and tgt_sample_rate != sample_rate: - _waveform = torch.from_numpy(waveform) - effects = [["rate", f"{tgt_sample_rate}"]] - return _sox_convert(_waveform, sample_rate, effects).numpy() - return waveform - - -def _sox_convert( - waveform: torch.FloatTensor, - sample_rate: int, - effects: List[List[str]], -) -> torch.FloatTensor: +def convert_waveform( + waveform: Union[np.ndarray, torch.Tensor], sample_rate: int, + normalize_volume: bool = False, to_mono: bool = False, + to_sample_rate: Optional[int] = None +) -> Tuple[Union[np.ndarray, torch.Tensor], int]: + """convert a waveform: + - to a target sample rate + - from multi-channel to mono channel + - volume normalization + + Args: + waveform (numpy.ndarray or torch.Tensor): 2D original waveform + (channels x length) + sample_rate (int): original sample rate + normalize_volume (bool): perform volume normalization + to_mono (bool): convert to mono channel if having multiple channels + to_sample_rate (Optional[int]): target sample rate + Returns: + waveform (numpy.ndarray): converted 2D waveform (channels x length) + sample_rate (float): target sample rate + """ try: import torchaudio.sox_effects as ta_sox except ImportError: - raise ImportError("Please install torchaudio to convert audios") - return ta_sox.apply_effects_tensor(waveform, sample_rate, effects)[0] - - -def convert_to_mono(waveform: np.ndarray, sample_rate: int) -> np.ndarray: - if waveform.shape[0] > 1: - _waveform = torch.from_numpy(waveform) - effects = [["channels", "1"]] - return _sox_convert(_waveform, sample_rate, effects).numpy() - return waveform + raise ImportError("Please install torchaudio: pip install torchaudio") + + effects = [] + if normalize_volume: + effects.append(["gain", "-n"]) + if to_sample_rate is not None and to_sample_rate != sample_rate: + effects.append(["rate", f"{to_sample_rate}"]) + if to_mono and waveform.shape[0] > 1: + effects.append(["channels", "1"]) + if len(effects) > 0: + is_np_input = isinstance(waveform, np.ndarray) + _waveform = torch.from_numpy(waveform) if is_np_input else waveform + converted, converted_sample_rate = ta_sox.apply_effects_tensor( + _waveform, sample_rate, effects + ) + if is_np_input: + converted = converted.numpy() + return converted, converted_sample_rate + return waveform, sample_rate def get_waveform( - path_or_fp: Union[str, BinaryIO], - normalization=True, - mono=True, - frames=-1, - start=0, - always_2d=True, - output_sample_rate=-1, + path_or_fp: Union[str, BinaryIO], normalization: bool = True, + mono: bool = True, frames: int = -1, start: int = 0, + always_2d: bool = True, output_sample_rate: Optional[int] = None, + normalize_volume: bool = False ) -> Tuple[np.ndarray, int]: """Get the waveform and sample rate of a 16-bit WAV/FLAC/OGG Vorbis audio. Args: path_or_fp (str or BinaryIO): the path or file-like object - normalization (bool): Normalize values to [-1, 1] (Default: True) + normalization (bool): normalize values to [-1, 1] (Default: True) mono (bool): convert multi-channel audio to mono-channel one frames (int): the number of frames to read. (-1 for reading all) start (int): Where to start reading. A negative value counts from the end. always_2d (bool): always return 2D array even for mono-channel audios - output_sample_rate (int): output sample rate, -1 using default + output_sample_rate (Optional[int]): output sample rate + normalize_volume (bool): normalize volume Returns: waveform (numpy.ndarray): 1D or 2D waveform (channels x length) sample_rate (float): sample rate @@ -72,17 +90,17 @@ def get_waveform( try: import soundfile as sf except ImportError: - raise ImportError("Please install soundfile to load WAV/FLAC/OGG Vorbis audios") + raise ImportError("Please install soundfile: pip install soundfile") waveform, sample_rate = sf.read( path_or_fp, dtype="float32", always_2d=True, frames=frames, start=start ) waveform = waveform.T # T x C -> C x T - if mono and waveform.shape[0] > 1: - waveform = convert_to_mono(waveform, sample_rate) - if output_sample_rate > 0: - waveform = update_sample_rate(waveform, sample_rate, output_sample_rate) - sample_rate = output_sample_rate + waveform, sample_rate = convert_waveform( + waveform, sample_rate, normalize_volume=normalize_volume, to_mono=mono, + to_sample_rate=output_sample_rate + ) + if not normalization: waveform *= 2 ** 15 # denormalized to 16-bit signed integers if not always_2d: @@ -190,3 +208,73 @@ def parse_path(path: str) -> Tuple[str, List[int]]: assert len(slice_ptr) in {0, 2}, f"Invalid path: {path}" slice_ptr = [int(i) for i in slice_ptr] return _path, slice_ptr + + +def get_window( + window_fn: callable, n_fft: int, win_length: int +) -> torch.Tensor: + padding = n_fft - win_length + assert padding >= 0 + return F.pad(window_fn(win_length), (padding // 2, padding - padding // 2)) + + +def get_fourier_basis(n_fft: int) -> torch.Tensor: + basis = np.fft.fft(np.eye(n_fft)) + basis = np.vstack( + [np.real(basis[:n_fft // 2 + 1, :]), np.imag(basis[:n_fft // 2 + 1, :])] + ) + return torch.from_numpy(basis).float() + + +def get_mel_filters( + sample_rate: int, n_fft: int, n_mels: int, f_min: float, f_max: float +) -> torch.Tensor: + try: + import librosa + except ImportError: + raise ImportError("Please install librosa: pip install librosa") + basis = librosa.filters.mel(sample_rate, n_fft, n_mels, f_min, f_max) + return torch.from_numpy(basis).float() + + +class TTSSpectrogram(torch.nn.Module): + def __init__( + self, n_fft: int, win_length: int, hop_length: int, + window_fn: callable = torch.hann_window, return_phase: bool = False + ) -> None: + super(TTSSpectrogram, self).__init__() + self.n_fft = n_fft + self.hop_length = hop_length + self.return_phase = return_phase + + basis = get_fourier_basis(n_fft).unsqueeze(1) + basis *= get_window(window_fn, n_fft, win_length) + self.register_buffer('basis', basis) + + def forward( + self, waveform: torch.Tensor + ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]: + padding = (self.n_fft // 2, self.n_fft // 2) + x = F.pad(waveform.unsqueeze(1), padding, mode='reflect') + x = F.conv1d(x, self.basis, stride=self.hop_length) + real_part = x[:, :self.n_fft // 2 + 1, :] + imag_part = x[:, self.n_fft // 2 + 1:, :] + magnitude = torch.sqrt(real_part ** 2 + imag_part ** 2) + if self.return_phase: + phase = torch.atan2(imag_part, real_part) + return magnitude, phase + return magnitude + + +class TTSMelScale(torch.nn.Module): + def __init__( + self, n_mels: int, sample_rate: int, f_min: float, f_max: float, + n_stft: int + ) -> None: + super(TTSMelScale, self).__init__() + basis = get_mel_filters(sample_rate, (n_stft - 1) * 2, n_mels, f_min, + f_max) + self.register_buffer('basis', basis) + + def forward(self, specgram: torch.Tensor) -> torch.Tensor: + return torch.matmul(self.basis, specgram) diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py new file mode 100644 index 0000000000..95b403ad9c --- /dev/null +++ b/fairseq/data/audio/data_cfg.py @@ -0,0 +1,139 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from pathlib import Path +from typing import Dict, Optional + + +class S2TDataConfig(object): + """Wrapper class for data config YAML""" + + def __init__(self, yaml_path: Path): + try: + import yaml + except ImportError: + print("Please install PyYAML: pip install PyYAML") + self.config = {} + if yaml_path.is_file(): + try: + with open(yaml_path) as f: + self.config = yaml.load(f, Loader=yaml.FullLoader) + except Exception as e: + raise Exception( + f"Failed to load config from {yaml_path.as_posix()}: {e}" + ) + else: + raise FileNotFoundError(f"{yaml_path.as_posix()} not found") + self.root = yaml_path.parent + + def _auto_convert_to_abs_path(self, x): + if isinstance(x, str): + if not Path(x).exists() and (self.root / x).exists(): + return (self.root / x).as_posix() + elif isinstance(x, dict): + return {k: self._auto_convert_to_abs_path(v) for k, v in x.items()} + return x + + @property + def vocab_filename(self): + """fairseq vocabulary file under data root""" + return self.config.get("vocab_filename", "dict.txt") + + @property + def speaker_set_filename(self): + """fairseq vocabulary file under data root""" + return self.config.get("speaker_set_filename", None) + + @property + def shuffle(self) -> bool: + """Shuffle dataset samples before batching""" + return self.config.get("shuffle", False) + + @property + def pre_tokenizer(self) -> Dict: + """Pre-tokenizer to apply before subword tokenization. Returning + a dictionary with `tokenizer` providing the tokenizer name and + the other items providing the tokenizer-specific arguments. + Tokenizers are defined in `fairseq.data.encoders.*`""" + tokenizer = self.config.get("pre_tokenizer", {"tokenizer": None}) + return self._auto_convert_to_abs_path(tokenizer) + + @property + def bpe_tokenizer(self) -> Dict: + """Subword tokenizer to apply after pre-tokenization. Returning + a dictionary with `bpe` providing the tokenizer name and + the other items providing the tokenizer-specific arguments. + Tokenizers are defined in `fairseq.data.encoders.*`""" + tokenizer = self.config.get("bpe_tokenizer", {"bpe": None}) + return self._auto_convert_to_abs_path(tokenizer) + + @property + def prepend_tgt_lang_tag(self) -> bool: + """Prepend target lang ID token as the target BOS (e.g. for to-many + multilingual setting). During inference, this requires `--prefix-size 1` + to force BOS to be lang ID token.""" + return self.config.get("prepend_tgt_lang_tag", False) + + @property + def input_feat_per_channel(self): + """The dimension of input features (per audio channel)""" + return self.config.get("input_feat_per_channel", 80) + + @property + def input_channels(self): + """The number of channels in the input audio""" + return self.config.get("input_channels", 1) + + @property + def sample_rate(self): + return self.config.get("sample_rate", 16_000) + + @property + def sampling_alpha(self): + """Hyper-parameter alpha = 1/T for temperature-based resampling. + (alpha = 1 for no resampling)""" + return self.config.get("sampling_alpha", 1.0) + + @property + def use_audio_input(self): + """Needed by the dataset loader to see if the model requires + raw audio as inputs.""" + return self.config.get("use_audio_input", False) + + @property + def use_sample_rate(self): + """Needed by the dataset loader to see if the model requires + raw audio with specific sample rate as inputs.""" + return self.config.get("use_sample_rate", 16000) + + @property + def audio_root(self): + """Audio paths in the manifest TSV can be relative and this provides + the root path. Set this to empty string when using absolute paths.""" + return self.config.get("audio_root", "") + + def get_feature_transforms(self, split, is_train): + """Split-specific feature transforms. Allowing train set + wildcard `_train`, evaluation set wildcard `_eval` and general + wildcard `*` for matching.""" + from copy import deepcopy + + cfg = deepcopy(self.config) + _cur = cfg.get("transforms", {}) + cur = _cur.get(split) + cur = _cur.get("_train") if cur is None and is_train else cur + cur = _cur.get("_eval") if cur is None and not is_train else cur + cur = _cur.get("*") if cur is None else cur + cfg["transforms"] = cur + return cfg + + @property + def global_cmvn_stats_npz(self) -> Optional[str]: + path = self.config.get("global_cmvn", {}).get("stats_npz_path", None) + return self._auto_convert_to_abs_path(path) + + @property + def vocoder(self) -> Optional[Dict[str, str]]: + return self.config.get("vocoder", None) diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index ba6c28632e..164bf413e4 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -9,7 +9,8 @@ import re from collections import defaultdict from pathlib import Path -from typing import Dict, List, Optional, NamedTuple +from typing import Dict, List, Optional +from dataclasses import dataclass import numpy as np import torch @@ -30,113 +31,12 @@ FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS, ) from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform +from fairseq.data.audio.data_cfg import S2TDataConfig logger = logging.getLogger(__name__) -class S2TDataConfig(object): - """Wrapper class for data config YAML""" - - def __init__(self, yaml_path: Path): - try: - import yaml - except ImportError: - print("Please install PyYAML to load YAML files for S2T data config") - self.config = {} - if yaml_path.is_file(): - try: - with open(yaml_path) as f: - self.config = yaml.load(f, Loader=yaml.FullLoader) - except Exception as e: - raise Exception( - f"Failed to load config from {yaml_path.as_posix()}: {e}" - ) - else: - raise FileNotFoundError(f"{yaml_path.as_posix()} not found") - - @property - def vocab_filename(self): - """fairseq vocabulary file under data root""" - return self.config.get("vocab_filename", "dict.txt") - - @property - def shuffle(self) -> bool: - """Shuffle dataset samples before batching""" - return self.config.get("shuffle", False) - - @property - def pre_tokenizer(self) -> Dict: - """Pre-tokenizer to apply before subword tokenization. Returning - a dictionary with `tokenizer` providing the tokenizer name and - the other items providing the tokenizer-specific arguments. - Tokenizers are defined in `fairseq.data.encoders.*`""" - return self.config.get("pre_tokenizer", {"tokenizer": None}) - - @property - def bpe_tokenizer(self) -> Dict: - """Subword tokenizer to apply after pre-tokenization. Returning - a dictionary with `bpe` providing the tokenizer name and - the other items providing the tokenizer-specific arguments. - Tokenizers are defined in `fairseq.data.encoders.*`""" - return self.config.get("bpe_tokenizer", {"bpe": None}) - - @property - def prepend_tgt_lang_tag(self) -> bool: - """Prepend target lang ID token as the target BOS (e.g. for to-many - multilingual setting). During inference, this requires `--prefix-size 1` - to force BOS to be lang ID token.""" - return self.config.get("prepend_tgt_lang_tag", False) - - @property - def input_feat_per_channel(self): - """The dimension of input features (per audio channel)""" - return self.config.get("input_feat_per_channel", 80) - - @property - def input_channels(self): - """The number of channels in the input audio""" - return self.config.get("input_channels", 1) - - @property - def sampling_alpha(self): - """Hyper-parameter alpha = 1/T for temperature-based resampling. - (alpha = 1 for no resampling)""" - return self.config.get("sampling_alpha", 1.0) - - @property - def use_audio_input(self): - """Needed by the dataset loader to see if the model requires - raw audio as inputs.""" - return self.config.get("use_audio_input", False) - - @property - def use_sample_rate(self): - """Needed by the dataset loader to see if the model requires - raw audio with specific sample rate as inputs.""" - return self.config.get("use_sample_rate", 16000) - - @property - def audio_root(self): - """Audio paths in the manifest TSV can be relative and this provides - the root path. Set this to empty string when using absolute paths.""" - return self.config.get("audio_root", "") - - def get_feature_transforms(self, split, is_train): - """Split-specific feature transforms. Allowing train set wildcard `_train`, - evaluation set wildcard `_eval` and general wildcard `*` for matching.""" - from copy import deepcopy - - cfg = deepcopy(self.config) - _cur = cfg.get("transforms", {}) - cur = _cur.get(split) - cur = _cur.get("_train") if cur is None and is_train else cur - cur = _cur.get("_eval") if cur is None and not is_train else cur - cur = _cur.get("*") if cur is None else cur - cfg["transforms"] = cur - return cfg - - def get_features_from_npy_or_audio(path): ext = Path(path).suffix if ext not in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: @@ -145,11 +45,7 @@ def get_features_from_npy_or_audio(path): def get_features_or_waveform_from_stored_zip( - path, - byte_offset, - byte_size, - need_waveform=False, - use_sample_rate=-1, + path, byte_offset, byte_size, need_waveform=False, use_sample_rate=None, ): assert path.endswith(".zip") data = read_from_stored_zip(path, byte_offset, byte_size) @@ -157,17 +53,18 @@ def get_features_or_waveform_from_stored_zip( if is_npy_data(data): features_or_waveform = np.load(f) elif is_sf_audio_data(data): - features_or_waveform = ( - get_waveform(f, always_2d=False, output_sample_rate=use_sample_rate)[0] - if need_waveform - else get_fbank(f) - ) + features_or_waveform = \ + get_waveform( + f, always_2d=False, output_sample_rate=use_sample_rate + )[0] if need_waveform else get_fbank(f) else: raise ValueError(f'Unknown file format for "{path}"') return features_or_waveform -def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=-1): +def get_features_or_waveform( + path: str, need_waveform=False, use_sample_rate=None +): """Get speech features from .npy file or waveform from .wav/.flac file. The file may be inside an uncompressed ZIP file and is accessed via byte offset and length. @@ -190,11 +87,8 @@ def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=-1) return get_features_from_npy_or_audio(_path) elif len(slice_ptr) == 2: features_or_waveform = get_features_or_waveform_from_stored_zip( - _path, - slice_ptr[0], - slice_ptr[1], - need_waveform=need_waveform, - use_sample_rate=use_sample_rate, + _path, slice_ptr[0], slice_ptr[1], need_waveform=need_waveform, + use_sample_rate=use_sample_rate ) else: raise ValueError(f"Invalid path: {path}") @@ -223,10 +117,12 @@ def _collate_frames( return out -class SpeechToTextDatasetItem(NamedTuple): +@dataclass +class SpeechToTextDatasetItem(object): index: int source: torch.Tensor target: Optional[torch.Tensor] = None + speaker_id: Optional[int] = None class SpeechToTextDataset(FairseqDataset): @@ -248,6 +144,8 @@ def __init__( tgt_dict: Optional[Dictionary] = None, pre_tokenizer=None, bpe_tokenizer=None, + n_frames_per_step=1, + speaker_to_id=None ): self.split, self.is_train_split = split, is_train_split self.cfg = cfg @@ -265,6 +163,7 @@ def __init__( ) self.src_texts, self.tgt_texts = src_texts, tgt_texts self.src_langs, self.tgt_langs = src_langs, tgt_langs + self.speakers = speakers self.tgt_dict = tgt_dict self.check_tgt_lang_tag() self.ids = ids @@ -276,6 +175,8 @@ def __init__( self.pre_tokenizer = pre_tokenizer self.bpe_tokenizer = bpe_tokenizer + self.n_frames_per_step = n_frames_per_step + self.speaker_to_id = speaker_to_id self.tgt_lens = self.get_tgt_lens_and_check_oov() @@ -302,9 +203,10 @@ def get_tgt_lens_and_check_oov(self): def __repr__(self): return ( self.__class__.__name__ - + f'(split="{self.split}", n_samples={self.n_samples}, ' + + f'(split="{self.split}", n_samples={self.n_samples:_}, ' f"prepend_tgt_lang_tag={self.cfg.prepend_tgt_lang_tag}, " - f"shuffle={self.shuffle}, transforms={self.feature_transforms})" + f"shuffle={self.shuffle}, transforms={self.feature_transforms}, " + f"n_frames_per_step={self.n_frames_per_step}" ) @classmethod @@ -329,6 +231,13 @@ def get_tokenized_tgt_text(self, index: int): text = self.tokenize(self.bpe_tokenizer, text) return text + def pack_frames(self, feature: torch.Tensor): + if self.n_frames_per_step == 1: + return feature + n_packed_frames = feature.shape[0] // self.n_frames_per_step + feature = feature[:self.n_frames_per_step * n_packed_frames] + return feature.reshape(n_packed_frames, -1) + @classmethod def get_lang_tag_idx(cls, lang: str, dictionary: Dictionary): lang_tag_idx = dictionary.index(cls.LANG_TAG_TEMPLATE.format(lang)) @@ -345,6 +254,7 @@ def __getitem__(self, index: int) -> SpeechToTextDatasetItem: assert not self.cfg.use_audio_input source = self.feature_transforms(source) source = torch.from_numpy(source).float() + source = self.pack_frames(source) target = None if self.tgt_texts is not None: @@ -358,7 +268,12 @@ def __getitem__(self, index: int) -> SpeechToTextDatasetItem: ) target = torch.cat((torch.LongTensor([lang_tag_idx]), target), 0) - return SpeechToTextDatasetItem(index=index, source=source, target=target) + speaker_id = None + if self.speaker_to_id is not None: + speaker_id = self.speaker_to_id[self.speakers[index]] + return SpeechToTextDatasetItem( + index=index, source=source, target=target, speaker_id=speaker_id + ) def __len__(self): return self.n_samples @@ -371,7 +286,7 @@ def collater( indices = torch.tensor([x.index for x in samples], dtype=torch.long) frames = _collate_frames([x.source for x in samples], self.cfg.use_audio_input) # sort samples by descending number of frames - n_frames = torch.tensor([x.source.size()[0] for x in samples], dtype=torch.long) + n_frames = torch.tensor([x.source.size(0) for x in samples], dtype=torch.long) n_frames, order = n_frames.sort(descending=True) indices = indices.index_select(0, order) frames = frames.index_select(0, order) @@ -389,7 +304,7 @@ def collater( ) target = target.index_select(0, order) target_lengths = torch.tensor( - [x.target.size()[0] for x in samples], dtype=torch.long + [x.target.size(0) for x in samples], dtype=torch.long ).index_select(0, order) prev_output_tokens = fairseq_data_utils.collate_tokens( [x.target for x in samples], @@ -399,7 +314,13 @@ def collater( move_eos_to_beginning=True, ) prev_output_tokens = prev_output_tokens.index_select(0, order) - ntokens = sum(x.target.size()[0] for x in samples) + ntokens = sum(x.target.size(0) for x in samples) + + speaker = None + if self.speaker_to_id is not None: + speaker = torch.tensor( + [s.speaker_id for s in samples], dtype=torch.long + ).index_select(0, order).view(-1, 1) net_input = { "src_tokens": frames, @@ -409,6 +330,7 @@ def collater( out = { "id": indices, "net_input": net_input, + "speaker": speaker, "target": target, "target_lengths": target_lengths, "ntokens": ntokens, @@ -465,6 +387,8 @@ def _from_list( tgt_dict, pre_tokenizer, bpe_tokenizer, + n_frames_per_step, + speaker_to_id ) -> SpeechToTextDataset: audio_root = Path(cfg.audio_root) ids = [s[cls.KEY_ID] for s in samples] @@ -490,6 +414,8 @@ def _from_list( tgt_dict=tgt_dict, pre_tokenizer=pre_tokenizer, bpe_tokenizer=bpe_tokenizer, + n_frames_per_step=n_frames_per_step, + speaker_to_id=speaker_to_id ) @classmethod @@ -554,10 +480,13 @@ def _from_tsv( is_train_split: bool, pre_tokenizer, bpe_tokenizer, + n_frames_per_step, + speaker_to_id ) -> SpeechToTextDataset: samples = cls._load_samples_from_tsv(root, split) return cls._from_list( - split, is_train_split, samples, cfg, tgt_dict, pre_tokenizer, bpe_tokenizer + split, is_train_split, samples, cfg, tgt_dict, pre_tokenizer, + bpe_tokenizer, n_frames_per_step, speaker_to_id ) @classmethod @@ -572,10 +501,13 @@ def from_tsv( is_train_split: bool, epoch: int, seed: int, + n_frames_per_step: int = 1, + speaker_to_id=None ) -> SpeechToTextDataset: datasets = [ cls._from_tsv( - root, cfg, split, tgt_dict, is_train_split, pre_tokenizer, bpe_tokenizer + root, cfg, split, tgt_dict, is_train_split, pre_tokenizer, + bpe_tokenizer, n_frames_per_step, speaker_to_id ) for split in splits.split(",") ] diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index c9ea52493d..7e887e8864 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -402,7 +402,7 @@ def cli_main(): parser = options.get_generation_parser() # TODO: replace this workaround with refactoring of `AudioPretraining` parser.add_argument( - '--arch', '-a', metavar='ARCH', default="transformer", + '--arch', '-a', metavar='ARCH', default="wav2vec2", help='Model architecture. For constructing tasks that rely on ' 'model args (e.g. `AudioPretraining`)' ) From e679327497702f52e4c6e5c2ab29b4d576c44ec4 Mon Sep 17 00:00:00 2001 From: "Yuan Shangguan (June)" <yuansg@fb.com> Date: Mon, 13 Sep 2021 13:19:35 -0700 Subject: [PATCH 455/774] Back out "Fairseq needs to store and load metadata from model state_dict" (#3861) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3861 backout fairseq changes. fix with a suggested, more optimal changes in checkopint utils. Reviewed By: zhengwy888 Differential Revision: D30886481 fbshipit-source-id: 12b6dd4d5107ab4371b73a58d9a044a17c733260 --- fairseq/checkpoint_utils.py | 37 +++------------------------------ fairseq/models/fairseq_model.py | 32 ---------------------------- fairseq/trainer.py | 9 +------- 3 files changed, 4 insertions(+), 74 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 7a494356ac..ef5d4c9022 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -31,7 +31,7 @@ logger = logging.getLogger(__name__) -def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss, save_metadata=False): +def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): from fairseq import meters # only one worker should attempt to create the required dir @@ -114,7 +114,7 @@ def is_better(a, b): os.path.join(cfg.save_dir, fn) for fn, cond in checkpoint_conds.items() if cond ] if len(checkpoints) > 0: - trainer.save_checkpoint(checkpoints[0], extra_state, save_metadata) + trainer.save_checkpoint(checkpoints[0], extra_state) for cp in checkpoints[1:]: if cfg.write_checkpoints_asynchronously: # TODO[ioPath]: Need to implement a delayed asynchronous @@ -455,35 +455,8 @@ def load_model_ensemble_and_task( else: # model parallel checkpoint or unsharded checkpoint model = task.build_model(cfg.model) - new_state_model = state["model"] - - '''=====The following if-else statement is a work-around ===== - # the current metadata loading/saving of pytorch. - # In Pytorch, if state["model"]["_metadata"] exists as dictionary, then model.load_state_dict(strict=True) - # will throw an error for unexpected "_metadata" key. To avoid this error, we need the state_dict to be - # in orderedDict format, which has new_state_model._metadata attribute but not as key. - # TODO yuansg@ This issue should be fixed in pytorch ideally. - ''' - if new_state_model.get("_metadata", None) is not None: - new_metadata = new_state_model.get("_metadata", None) - del state["model"]["_metadata"] - else: - new_metadata = None - # Construct state dict content. - contents = OrderedDict(new_state_model) - # We explicitly set _metadata for the state models. The _metadata is implicitly stored for pytorch models. - # calling state["model"] in fairseq will not invoke metadata storage. - if new_metadata is None: - logger.warning("===Jit: state[\"model\"] does not contain key \"_metadata\"=====") - logger.warning("===Jit: we will be filling in with current model's meta-data instead.") - # For models trained before this diff, we do the following to be backward compatible. - contents.__setattr__("_metadata", model.state_dict()._metadata) - else: - contents.__setattr__("_metadata", new_metadata) - '''====End of work-around logic=====''' - model.load_state_dict( - contents, strict=strict, model_cfg=cfg.model + state["model"], strict=strict, model_cfg=cfg.model ) # reset state so it gets loaded for the next model in ensemble @@ -710,7 +683,6 @@ def prune_state_dict(state_dict, model_cfg: Optional[DictConfig]): It's called by functions that load models from checkpoints and does not need to be called directly. """ - state_meta_data = state_dict.get("_metadata", None) arch = None if model_cfg is not None: arch = ( @@ -790,9 +762,6 @@ def create_pruning_pass(layers_to_keep, layer_name): if hasattr(model_cfg, "decoder_layers_to_keep"): model_cfg.decoder_layers_to_keep = None - # Ensure metadata is stored. - if state_meta_data is not None: - new_state_dict["_metadata"] = state_meta_data return new_state_dict diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 0645208efe..e55c7ba1ad 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -22,7 +22,6 @@ from fairseq.models import FairseqDecoder, FairseqEncoder from omegaconf import DictConfig from torch import Tensor -from collections import OrderedDict logger = logging.getLogger(__name__) @@ -123,15 +122,6 @@ def load_state_dict( from fairseq.checkpoint_utils import prune_state_dict new_state_dict = prune_state_dict(state_dict, model_cfg) - # The pytorch assumption of module is that it is an OrderedDict. - # Pytorch also assumes module._metadata exists in the state_dict, - # not as dictionary keys, rather as an attribute of the state dict. - new_state_dict = OrderedDict(new_state_dict) - metadata = new_state_dict.get("_metadata", None) - - if metadata: - del new_state_dict["_metadata"] - new_state_dict.__setattr__("_metadata", metadata) return super().load_state_dict(new_state_dict, strict) def upgrade_state_dict(self, state_dict): @@ -161,28 +151,6 @@ def do_upgrade(m, prefix): do_upgrade(self, name) - def update_metadata(self, model_meta): - """ The model.state_dict()._metadata is stored in a collective location in - state_dict["model"]["_metadata"]. - A pytorch module's _metadata contains the torch modules' versions, which is important - for versionsetting functions. - - During model loading time, we load the model state_dict, but we don't load the state_dict metadata. - This function helps to update the model according to the state_dict["model"]["_metadata"] dump. - InputArgs: - update_metadata: Dict; key is module names, value is {"version", 1} or other metadata. - """ - # Do nothing if the model level metadata is empty. - if model_meta is None: - return - assert isinstance(model_meta, Dict), \ - "Input model_meta from state_dict should be a dictionary. Check state dict." - for key, val in model_meta.items(): - if key is None: # First level set up - self._metadata = val - else: # Subsequent levels of the model - self.get_submodule(key)._metadata = val - def set_num_updates(self, num_updates): """State from trainer to pass along to model at every update.""" for m in self.modules(): diff --git a/fairseq/trainer.py b/fairseq/trainer.py index a10ec97aa7..e46ccfe0b8 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -424,18 +424,12 @@ def state_dict(self): state_dict["fsdp_metadata"] = self.model.local_metadata_dict() return state_dict - def save_checkpoint(self, filename, extra_state, save_metadata=False): + def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" logger.info(f"Saving checkpoint to {filename}") # call state_dict on all ranks in case it needs internal communication state_dict = utils.move_to_cpu(self.state_dict()) state_dict["extra_state"].update(extra_state) - # This should be added because model versions are stored as metadata. - if save_metadata and getattr(self.model.state_dict(), "_metadata", None) is not None: - logger.warning("Trainer: _metadata is inside model.state_dict(). ") - state_dict["model"]["_metadata"] = self.model.state_dict()._metadata - else: - logger.warning("Trainer: _metadata is not saved inside model.state_dict(). ") if self.should_save_checkpoint_on_current_rank: checkpoint_utils.torch_persistent_save( state_dict, @@ -508,7 +502,6 @@ def load_checkpoint( self.model.load_state_dict( state["model"], strict=True, model_cfg=self.cfg.model ) - self.model.update_metadata(getattr(state["model"], "_metadata", None)) # save memory for later steps del state["model"] if utils.has_parameters(self.get_criterion()): From 32b31173aa30e9b1555c4048917e8aa9f6227e18 Mon Sep 17 00:00:00 2001 From: "Yuan Shangguan (June)" <yuansg@fb.com> Date: Mon, 13 Sep 2021 13:19:35 -0700 Subject: [PATCH 456/774] Allow attributes of OrderedDict to be saved (#3862) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3862 We resolved a bug for missing "_metadata" attribute for pytorch models during checkpoing saving and loading using forced state["model"]["_metadata"], but it's not an efficient solution due to expensive model.state_dict() invocation. This diff offers an alternative solution. Reviewed By: zhengwy888 Differential Revision: D30857147 fbshipit-source-id: 5daa978e2a558ad4159e2da55470253950151bde --- fairseq/utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fairseq/utils.py b/fairseq/utils.py index d1ec9a274c..623ff87a8c 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -17,6 +17,7 @@ import torch import torch.nn.functional as F from torch import Tensor +import collections if TYPE_CHECKING: from fairseq.modules.multihead_attention import MultiheadAttention @@ -82,6 +83,11 @@ def apply_to_sample(f, sample): def _apply(x): if torch.is_tensor(x): return f(x) + elif isinstance(x, collections.OrderedDict): + # OrderedDict has attributes that needs to be preserved + od = collections.OrderedDict((key, _apply(value)) for key, value in x.items()) + od.__dict__ = x.__dict__ + return od elif isinstance(x, dict): return {key: _apply(value) for key, value in x.items()} elif isinstance(x, list): From 0ac3f3270c90e6d62284272b28ce076f61fb14eb Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Mon, 13 Sep 2021 18:12:38 -0700 Subject: [PATCH 457/774] add TTS Summary: [fairseq-py] add TTS Reviewed By: wnhsu Differential Revision: D30720666 fbshipit-source-id: b5288acec72bea1d3a9f3884a4ed51b616c7a403 --- examples/speech_synthesis/data_utils.py | 320 ++++++++++++ .../speech_synthesis/generate_waveform.py | 191 +++++++ examples/speech_synthesis/utils.py | 101 ++++ fairseq/criterions/fastspeech2_loss.py | 125 +++++ fairseq/criterions/tacotron2_loss.py | 210 ++++++++ .../data/audio/frm_text_to_speech_dataset.py | 207 ++++++++ fairseq/data/audio/text_to_speech_dataset.py | 215 ++++++++ fairseq/data/dictionary.py | 3 +- fairseq/models/speech_to_text/__init__.py | 4 +- fairseq/models/speech_to_text/utils.py | 1 - fairseq/models/text_to_speech/__init__.py | 8 + fairseq/models/text_to_speech/fastspeech2.py | 352 +++++++++++++ fairseq/models/text_to_speech/hifigan.py | 173 +++++++ fairseq/models/text_to_speech/tacotron2.py | 350 +++++++++++++ .../models/text_to_speech/tts_transformer.py | 371 ++++++++++++++ fairseq/models/text_to_speech/vocoder.py | 197 ++++++++ fairseq/modules/__init__.py | 4 + fairseq/modules/location_attention.py | 72 +++ fairseq/modules/lstm_cell_with_zoneout.py | 37 ++ .../optim/lr_scheduler/step_lr_scheduler.py | 86 ++++ fairseq/options.py | 18 + fairseq/speech_generator.py | 219 ++++++++ fairseq/tasks/frm_text_to_speech.py | 56 +++ fairseq/tasks/speech_to_text.py | 21 +- fairseq/tasks/text_to_speech.py | 467 ++++++++++++++++++ setup.py | 1 + 26 files changed, 3801 insertions(+), 8 deletions(-) create mode 100644 examples/speech_synthesis/data_utils.py create mode 100644 examples/speech_synthesis/generate_waveform.py create mode 100644 examples/speech_synthesis/utils.py create mode 100644 fairseq/criterions/fastspeech2_loss.py create mode 100644 fairseq/criterions/tacotron2_loss.py create mode 100644 fairseq/data/audio/frm_text_to_speech_dataset.py create mode 100644 fairseq/data/audio/text_to_speech_dataset.py create mode 100644 fairseq/models/text_to_speech/__init__.py create mode 100644 fairseq/models/text_to_speech/fastspeech2.py create mode 100644 fairseq/models/text_to_speech/hifigan.py create mode 100644 fairseq/models/text_to_speech/tacotron2.py create mode 100644 fairseq/models/text_to_speech/tts_transformer.py create mode 100644 fairseq/models/text_to_speech/vocoder.py create mode 100644 fairseq/modules/location_attention.py create mode 100644 fairseq/modules/lstm_cell_with_zoneout.py create mode 100644 fairseq/optim/lr_scheduler/step_lr_scheduler.py create mode 100644 fairseq/speech_generator.py create mode 100644 fairseq/tasks/frm_text_to_speech.py create mode 100644 fairseq/tasks/text_to_speech.py diff --git a/examples/speech_synthesis/data_utils.py b/examples/speech_synthesis/data_utils.py new file mode 100644 index 0000000000..f43a4a9004 --- /dev/null +++ b/examples/speech_synthesis/data_utils.py @@ -0,0 +1,320 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +from pathlib import Path +from typing import Optional, List, Dict +import zipfile +import tempfile +from dataclasses import dataclass +from itertools import groupby + +import torch +import torch.nn.functional as F +import numpy as np +from tqdm import tqdm + +from examples.speech_to_text.data_utils import load_tsv_to_dicts +from fairseq.data.audio.audio_utils import TTSSpectrogram, TTSMelScale + + +def trim_or_pad_to_target_length( + data_1d_or_2d: np.ndarray, target_length: int +) -> np.ndarray: + assert len(data_1d_or_2d.shape) in {1, 2} + delta = data_1d_or_2d.shape[0] - target_length + if delta >= 0: # trim if being longer + data_1d_or_2d = data_1d_or_2d[: target_length] + else: # pad if being shorter + if len(data_1d_or_2d.shape) == 1: + data_1d_or_2d = np.concatenate( + [data_1d_or_2d, np.zeros(-delta)], axis=0 + ) + else: + data_1d_or_2d = np.concatenate( + [data_1d_or_2d, np.zeros((-delta, data_1d_or_2d.shape[1]))], + axis=0 + ) + return data_1d_or_2d + + +def extract_logmel_spectrogram( + waveform: torch.Tensor, sample_rate: int, + output_path: Optional[Path] = None, win_length: int = 1024, + hop_length: int = 256, n_fft: int = 1024, + win_fn: callable = torch.hann_window, n_mels: int = 80, + f_min: float = 0., f_max: float = 8000, eps: float = 1e-5, + overwrite: bool = False, target_length: Optional[int] = None +): + if output_path is not None and output_path.is_file() and not overwrite: + return + + spectrogram_transform = TTSSpectrogram( + n_fft=n_fft, win_length=win_length, hop_length=hop_length, + window_fn=win_fn + ) + mel_scale_transform = TTSMelScale( + n_mels=n_mels, sample_rate=sample_rate, f_min=f_min, f_max=f_max, + n_stft=n_fft // 2 + 1 + ) + spectrogram = spectrogram_transform(waveform) + mel_spec = mel_scale_transform(spectrogram) + logmel_spec = torch.clamp(mel_spec, min=eps).log() + assert len(logmel_spec.shape) == 3 and logmel_spec.shape[0] == 1 + logmel_spec = logmel_spec.squeeze().t() # D x T -> T x D + if target_length is not None: + trim_or_pad_to_target_length(logmel_spec, target_length) + + if output_path is not None: + np.save(output_path.as_posix(), logmel_spec) + else: + return logmel_spec + + +def extract_pitch( + waveform: torch.Tensor, sample_rate: int, + output_path: Optional[Path] = None, hop_length: int = 256, + log_scale: bool = True, phoneme_durations: Optional[List[int]] = None +): + if output_path is not None and output_path.is_file(): + return + + try: + import pyworld + except ImportError: + raise ImportError("Please install PyWORLD: pip install pyworld") + + _waveform = waveform.squeeze(0).double().numpy() + pitch, t = pyworld.dio( + _waveform, sample_rate, frame_period=hop_length / sample_rate * 1000 + ) + pitch = pyworld.stonemask(_waveform, pitch, t, sample_rate) + + if phoneme_durations is not None: + pitch = trim_or_pad_to_target_length(pitch, sum(phoneme_durations)) + try: + from scipy.interpolate import interp1d + except ImportError: + raise ImportError("Please install SciPy: pip install scipy") + nonzero_ids = np.where(pitch != 0)[0] + interp_fn = interp1d( + nonzero_ids, + pitch[nonzero_ids], + fill_value=(pitch[nonzero_ids[0]], pitch[nonzero_ids[-1]]), + bounds_error=False, + ) + pitch = interp_fn(np.arange(0, len(pitch))) + d_cumsum = np.cumsum(np.concatenate([np.array([0]), phoneme_durations])) + pitch = np.array( + [ + np.mean(pitch[d_cumsum[i-1]: d_cumsum[i]]) + for i in range(1, len(d_cumsum)) + ] + ) + assert len(pitch) == len(phoneme_durations) + + if log_scale: + pitch = np.log(pitch + 1) + + if output_path is not None: + np.save(output_path.as_posix(), pitch) + else: + return pitch + + +def extract_energy( + waveform: torch.Tensor, output_path: Optional[Path] = None, + hop_length: int = 256, n_fft: int = 1024, log_scale: bool = True, + phoneme_durations: Optional[List[int]] = None +): + if output_path is not None and output_path.is_file(): + return + + assert len(waveform.shape) == 2 and waveform.shape[0] == 1 + waveform = waveform.view(1, 1, waveform.shape[1]) + waveform = F.pad( + waveform.unsqueeze(1), [n_fft // 2, n_fft // 2, 0, 0], + mode="reflect" + ) + waveform = waveform.squeeze(1) + + fourier_basis = np.fft.fft(np.eye(n_fft)) + cutoff = int((n_fft / 2 + 1)) + fourier_basis = np.vstack( + [np.real(fourier_basis[:cutoff, :]), + np.imag(fourier_basis[:cutoff, :])] + ) + + forward_basis = torch.FloatTensor(fourier_basis[:, None, :]) + forward_transform = F.conv1d( + waveform, forward_basis, stride=hop_length, padding=0 + ) + + real_part = forward_transform[:, :cutoff, :] + imag_part = forward_transform[:, cutoff:, :] + magnitude = torch.sqrt(real_part ** 2 + imag_part ** 2) + energy = torch.norm(magnitude, dim=1).squeeze(0).numpy() + + if phoneme_durations is not None: + energy = trim_or_pad_to_target_length(energy, sum(phoneme_durations)) + d_cumsum = np.cumsum(np.concatenate([np.array([0]), phoneme_durations])) + energy = np.array( + [ + np.mean(energy[d_cumsum[i - 1]: d_cumsum[i]]) + for i in range(1, len(d_cumsum)) + ] + ) + assert len(energy) == len(phoneme_durations) + + if log_scale: + energy = np.log(energy + 1) + + if output_path is not None: + np.save(output_path.as_posix(), energy) + else: + return energy + + +def get_global_cmvn(feature_root: Path, output_path: Optional[Path] = None): + mean_x, mean_x2, n_frames = None, None, 0 + feature_paths = feature_root.glob("*.npy") + for p in tqdm(feature_paths): + with open(p, 'rb') as f: + frames = np.load(f).squeeze() + + n_frames += frames.shape[0] + + cur_mean_x = frames.sum(axis=0) + if mean_x is None: + mean_x = cur_mean_x + else: + mean_x += cur_mean_x + + cur_mean_x2 = (frames ** 2).sum(axis=0) + if mean_x2 is None: + mean_x2 = cur_mean_x2 + else: + mean_x2 += cur_mean_x2 + + mean_x /= n_frames + mean_x2 /= n_frames + var_x = mean_x2 - mean_x ** 2 + std_x = np.sqrt(np.maximum(var_x, 1e-10)) + + if output_path is not None: + with open(output_path, 'wb') as f: + np.savez(f, mean=mean_x, std=std_x) + else: + return {"mean": mean_x, "std": std_x} + + +def ipa_phonemize(text, lang="en-us", use_g2p=False): + if use_g2p: + assert lang == "en-us", "g2pE phonemizer only works for en-us" + try: + from g2p_en import G2p + g2p = G2p() + return " ".join("|" if p == " " else p for p in g2p(text)) + except ImportError: + raise ImportError( + "Please install phonemizer: pip install g2p_en" + ) + else: + try: + from phonemizer import phonemize + from phonemizer.separator import Separator + return phonemize( + text, backend='espeak', language=lang, + separator=Separator(word="| ", phone=" ") + ) + except ImportError: + raise ImportError( + "Please install phonemizer: pip install phonemizer" + ) + + +@dataclass +class ForceAlignmentInfo(object): + tokens: List[str] + frame_durations: List[int] + start_sec: Optional[float] + end_sec: Optional[float] + + +def get_mfa_alignment_by_sample_id( + textgrid_zip_path: str, sample_id: str, sample_rate: int, + hop_length: int, silence_phones: List[str] = ("sil", "sp", "spn") +) -> ForceAlignmentInfo: + try: + import tgt + except ImportError: + raise ImportError("Please install TextGridTools: pip install tgt") + + filename = f"{sample_id}.TextGrid" + out_root = Path(tempfile.gettempdir()) + tgt_path = out_root / filename + with zipfile.ZipFile(textgrid_zip_path) as f_zip: + f_zip.extract(filename, path=out_root) + textgrid = tgt.io.read_textgrid(tgt_path.as_posix()) + os.remove(tgt_path) + + phones, frame_durations = [], [] + start_sec, end_sec, end_idx = 0, 0, 0 + for t in textgrid.get_tier_by_name("phones")._objects: + s, e, p = t.start_time, t.end_time, t.text + # Trim leading silences + if len(phones) == 0: + if p in silence_phones: + continue + else: + start_sec = s + phones.append(p) + if p not in silence_phones: + end_sec = e + end_idx = len(phones) + r = sample_rate / hop_length + frame_durations.append(int(np.round(e * r) - np.round(s * r))) + # Trim tailing silences + phones = phones[:end_idx] + frame_durations = frame_durations[:end_idx] + + return ForceAlignmentInfo( + tokens=phones, frame_durations=frame_durations, start_sec=start_sec, + end_sec=end_sec + ) + + +def get_mfa_alignment( + textgrid_zip_path: str, sample_ids: List[str], sample_rate: int, + hop_length: int +) -> Dict[str, ForceAlignmentInfo]: + return { + i: get_mfa_alignment_by_sample_id( + textgrid_zip_path, i, sample_rate, hop_length + ) for i in tqdm(sample_ids) + } + + +def get_unit_alignment( + id_to_unit_tsv_path: str, sample_ids: List[str] +) -> Dict[str, ForceAlignmentInfo]: + id_to_units = { + e["id"]: e["units"] for e in load_tsv_to_dicts(id_to_unit_tsv_path) + } + id_to_units = {i: id_to_units[i].split() for i in sample_ids} + id_to_units_collapsed = { + i: [uu for uu, _ in groupby(u)] for i, u in id_to_units.items() + } + id_to_durations = { + i: [len(list(g)) for _, g in groupby(u)] for i, u in id_to_units.items() + } + + return { + i: ForceAlignmentInfo( + tokens=id_to_units_collapsed[i], frame_durations=id_to_durations[i], + start_sec=None, end_sec=None + ) + for i in sample_ids + } diff --git a/examples/speech_synthesis/generate_waveform.py b/examples/speech_synthesis/generate_waveform.py new file mode 100644 index 0000000000..bfc2ef8eb3 --- /dev/null +++ b/examples/speech_synthesis/generate_waveform.py @@ -0,0 +1,191 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import logging +import matplotlib.pyplot as plt +import numpy as np +from pathlib import Path +import soundfile as sf +import sys +import torch +import torchaudio + +from fairseq import checkpoint_utils, options, tasks, utils +from fairseq.logging import progress_bar +from fairseq.tasks.text_to_speech import plot_tts_output +from fairseq.data.audio.text_to_speech_dataset import TextToSpeechDataset + + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def make_parser(): + parser = options.get_speech_generation_parser() + parser.add_argument("--dump-features", action="store_true") + parser.add_argument("--dump-waveforms", action="store_true") + parser.add_argument("--dump-attentions", action="store_true") + parser.add_argument("--dump-eos-probs", action="store_true") + parser.add_argument("--dump-plots", action="store_true") + parser.add_argument("--dump-target", action="store_true") + parser.add_argument("--output-sample-rate", default=22050, type=int) + parser.add_argument("--teacher-forcing", action="store_true") + parser.add_argument( + "--audio-format", type=str, default="wav", choices=["wav", "flac"] + ) + return parser + + +def postprocess_results( + dataset: TextToSpeechDataset, sample, hypos, resample_fn, dump_target +): + def to_np(x): + return None if x is None else x.detach().cpu().numpy() + + sample_ids = [dataset.ids[i] for i in sample["id"].tolist()] + texts = sample["src_texts"] + attns = [to_np(hypo["attn"]) for hypo in hypos] + eos_probs = [to_np(hypo.get("eos_prob", None)) for hypo in hypos] + feat_preds = [to_np(hypo["feature"]) for hypo in hypos] + wave_preds = [to_np(resample_fn(h["waveform"])) for h in hypos] + if dump_target: + feat_targs = [to_np(hypo["targ_feature"]) for hypo in hypos] + wave_targs = [to_np(resample_fn(h["targ_waveform"])) for h in hypos] + else: + feat_targs = [None for _ in hypos] + wave_targs = [None for _ in hypos] + + return zip(sample_ids, texts, attns, eos_probs, feat_preds, wave_preds, + feat_targs, wave_targs) + + +def dump_result( + is_na_model, + args, + vocoder, + sample_id, + text, + attn, + eos_prob, + feat_pred, + wave_pred, + feat_targ, + wave_targ, +): + sample_rate = args.output_sample_rate + out_root = Path(args.results_path) + if args.dump_features: + feat_dir = out_root / "feat" + feat_dir.mkdir(exist_ok=True, parents=True) + np.save(feat_dir / f"{sample_id}.npy", feat_pred) + if args.dump_target: + feat_tgt_dir = out_root / "feat_tgt" + feat_tgt_dir.mkdir(exist_ok=True, parents=True) + np.save(feat_tgt_dir / f"{sample_id}.npy", feat_targ) + if args.dump_attentions: + attn_dir = out_root / "attn" + attn_dir.mkdir(exist_ok=True, parents=True) + np.save(attn_dir / f"{sample_id}.npy", attn.numpy()) + if args.dump_eos_probs and not is_na_model: + eos_dir = out_root / "eos" + eos_dir.mkdir(exist_ok=True, parents=True) + np.save(eos_dir / f"{sample_id}.npy", eos_prob) + + if args.dump_plots: + images = [feat_pred.T] if is_na_model else [feat_pred.T, attn] + names = ["output"] if is_na_model else ["output", "alignment"] + if feat_targ is not None: + images = [feat_targ.T] + images + names = [f"target (idx={sample_id})"] + names + if is_na_model: + plot_tts_output(images, names, attn, "alignment", suptitle=text) + else: + plot_tts_output(images, names, eos_prob, "eos prob", suptitle=text) + plot_dir = out_root / "plot" + plot_dir.mkdir(exist_ok=True, parents=True) + plt.savefig(plot_dir / f"{sample_id}.png") + plt.close() + + if args.dump_waveforms: + ext = args.audio_format + if wave_pred is not None: + wav_dir = out_root / f"{ext}_{sample_rate}hz_{vocoder}" + wav_dir.mkdir(exist_ok=True, parents=True) + sf.write(wav_dir / f"{sample_id}.{ext}", wave_pred, sample_rate) + if args.dump_target and wave_targ is not None: + wav_tgt_dir = out_root / f"{ext}_{sample_rate}hz_{vocoder}_tgt" + wav_tgt_dir.mkdir(exist_ok=True, parents=True) + sf.write(wav_tgt_dir / f"{sample_id}.{ext}", wave_targ, sample_rate) + + +def main(args): + assert(args.dump_features or args.dump_waveforms or args.dump_attentions + or args.dump_eos_probs or args.dump_plots) + if args.max_tokens is None and args.batch_size is None: + args.max_tokens = 8000 + logger.info(args) + + use_cuda = torch.cuda.is_available() and not args.cpu + task = tasks.setup_task(args) + models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( + [args.path], + task=task, + ) + model = models[0].cuda() if use_cuda else models[0] + # use the original n_frames_per_step + task.args.n_frames_per_step = saved_cfg.task.n_frames_per_step + task.load_dataset(args.gen_subset, task_cfg=saved_cfg.task) + + data_cfg = task.data_cfg + sample_rate = data_cfg.config.get("features", {}).get("sample_rate", 22050) + resample_fn = { + False: lambda x: x, + True: lambda x: torchaudio.sox_effects.apply_effects_tensor( + x.detach().cpu().unsqueeze(0), sample_rate, + [['rate', str(args.output_sample_rate)]] + )[0].squeeze(0) + }.get(args.output_sample_rate != sample_rate) + if args.output_sample_rate != sample_rate: + logger.info(f"resampling to {args.output_sample_rate}Hz") + + generator = task.build_generator([model], args) + itr = task.get_batch_iterator( + dataset=task.dataset(args.gen_subset), + max_tokens=args.max_tokens, + max_sentences=args.batch_size, + max_positions=(sys.maxsize, sys.maxsize), + ignore_invalid_inputs=args.skip_invalid_size_inputs_valid_test, + required_batch_size_multiple=args.required_batch_size_multiple, + num_shards=args.num_shards, + shard_id=args.shard_id, + num_workers=args.num_workers, + data_buffer_size=args.data_buffer_size, + ).next_epoch_itr(shuffle=False) + + Path(args.results_path).mkdir(exist_ok=True, parents=True) + is_na_model = getattr(model, "NON_AUTOREGRESSIVE", False) + dataset = task.dataset(args.gen_subset) + vocoder = task.args.vocoder + with progress_bar.build_progress_bar(args, itr) as t: + for sample in t: + sample = utils.move_to_cuda(sample) if use_cuda else sample + hypos = generator.generate(model, sample, has_targ=args.dump_target) + for result in postprocess_results( + dataset, sample, hypos, resample_fn, args.dump_target + ): + dump_result(is_na_model, args, vocoder, *result) + + +def cli_main(): + parser = make_parser() + args = options.parse_args_and_arch(parser) + main(args) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/speech_synthesis/utils.py b/examples/speech_synthesis/utils.py new file mode 100644 index 0000000000..2c7b03733d --- /dev/null +++ b/examples/speech_synthesis/utils.py @@ -0,0 +1,101 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +import torch +from scipy.interpolate import interp1d +import torchaudio + +from fairseq.tasks.text_to_speech import ( + batch_compute_distortion, compute_rms_dist +) + + +def batch_mel_spectral_distortion( + y1, y2, sr, normalize_type="path", mel_fn=None +): + """ + https://arxiv.org/pdf/2011.03568.pdf + + Same as Mel Cepstral Distortion, but computed on log-mel spectrograms. + """ + if mel_fn is None or mel_fn.sample_rate != sr: + mel_fn = torchaudio.transforms.MelSpectrogram( + sr, n_fft=int(0.05 * sr), win_length=int(0.05 * sr), + hop_length=int(0.0125 * sr), f_min=20, n_mels=80, + window_fn=torch.hann_window + ).to(y1[0].device) + offset = 1e-6 + return batch_compute_distortion( + y1, y2, sr, lambda y: torch.log(mel_fn(y) + offset).transpose(-1, -2), + compute_rms_dist, normalize_type + ) + + +# This code is based on +# "https://github.com/bastibe/MAPS-Scripts/blob/master/helper.py" +def _same_t_in_true_and_est(func): + def new_func(true_t, true_f, est_t, est_f): + assert type(true_t) is np.ndarray + assert type(true_f) is np.ndarray + assert type(est_t) is np.ndarray + assert type(est_f) is np.ndarray + + interpolated_f = interp1d( + est_t, est_f, bounds_error=False, kind='nearest', fill_value=0 + )(true_t) + return func(true_t, true_f, true_t, interpolated_f) + + return new_func + + +@_same_t_in_true_and_est +def gross_pitch_error(true_t, true_f, est_t, est_f): + """The relative frequency in percent of pitch estimates that are + outside a threshold around the true pitch. Only frames that are + considered pitched by both the ground truth and the estimator (if + applicable) are considered. + """ + + correct_frames = _true_voiced_frames(true_t, true_f, est_t, est_f) + gross_pitch_error_frames = _gross_pitch_error_frames( + true_t, true_f, est_t, est_f + ) + return np.sum(gross_pitch_error_frames) / np.sum(correct_frames) + + +def _gross_pitch_error_frames(true_t, true_f, est_t, est_f, eps=1e-8): + voiced_frames = _true_voiced_frames(true_t, true_f, est_t, est_f) + true_f_p_eps = [x + eps for x in true_f] + pitch_error_frames = np.abs(est_f / true_f_p_eps - 1) > 0.2 + return voiced_frames & pitch_error_frames + + +def _true_voiced_frames(true_t, true_f, est_t, est_f): + return (est_f != 0) & (true_f != 0) + + +def _voicing_decision_error_frames(true_t, true_f, est_t, est_f): + return (est_f != 0) != (true_f != 0) + + +@_same_t_in_true_and_est +def f0_frame_error(true_t, true_f, est_t, est_f): + gross_pitch_error_frames = _gross_pitch_error_frames( + true_t, true_f, est_t, est_f + ) + voicing_decision_error_frames = _voicing_decision_error_frames( + true_t, true_f, est_t, est_f + ) + return (np.sum(gross_pitch_error_frames) + + np.sum(voicing_decision_error_frames)) / (len(true_t)) + + +@_same_t_in_true_and_est +def voicing_decision_error(true_t, true_f, est_t, est_f): + voicing_decision_error_frames = _voicing_decision_error_frames( + true_t, true_f, est_t, est_f + ) + return np.sum(voicing_decision_error_frames) / (len(true_t)) diff --git a/fairseq/criterions/fastspeech2_loss.py b/fairseq/criterions/fastspeech2_loss.py new file mode 100644 index 0000000000..085d5628d4 --- /dev/null +++ b/fairseq/criterions/fastspeech2_loss.py @@ -0,0 +1,125 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +from typing import List, Dict, Any +from dataclasses import dataclass, field + +import torch +import torch.nn.functional as F + +from fairseq import metrics, utils +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass +from fairseq.data.data_utils import lengths_to_mask +from fairseq.models.fairseq_model import FairseqEncoderModel + + +@dataclass +class FastSpeech2CriterionConfig(FairseqDataclass): + ctc_weight: float = field( + default=0.0, metadata={"help": "weight for CTC loss"} + ) + + +@register_criterion("fastspeech2", dataclass=FastSpeech2CriterionConfig) +class FastSpeech2Loss(FairseqCriterion): + def __init__(self, task, ctc_weight): + super().__init__(task) + self.ctc_weight = ctc_weight + + def forward(self, model: FairseqEncoderModel, sample, reduction="mean"): + src_tokens = sample["net_input"]["src_tokens"] + src_lens = sample["net_input"]["src_lengths"] + tgt_lens = sample["target_lengths"] + _feat_out, _, log_dur_out, pitch_out, energy_out = model( + src_tokens=src_tokens, + src_lengths=src_lens, + prev_output_tokens=sample["net_input"]["prev_output_tokens"], + incremental_state=None, + target_lengths=tgt_lens, + speaker=sample["speaker"], + durations=sample["durations"], + pitches=sample["pitches"], + energies=sample["energies"] + ) + + src_mask = lengths_to_mask(sample["net_input"]["src_lengths"]) + tgt_mask = lengths_to_mask(sample["target_lengths"]) + + pitches, energies = sample["pitches"], sample["energies"] + pitch_out, pitches = pitch_out[src_mask], pitches[src_mask] + energy_out, energies = energy_out[src_mask], energies[src_mask] + + feat_out, feat = _feat_out[tgt_mask], sample["target"][tgt_mask] + l1_loss = F.l1_loss(feat_out, feat, reduction=reduction) + + pitch_loss = F.mse_loss(pitch_out, pitches, reduction=reduction) + energy_loss = F.mse_loss(energy_out, energies, reduction=reduction) + + log_dur_out = log_dur_out[src_mask] + dur = sample["durations"].float() + dur = dur.half() if log_dur_out.type().endswith(".HalfTensor") else dur + log_dur = torch.log(dur + 1)[src_mask] + dur_loss = F.mse_loss(log_dur_out, log_dur, reduction=reduction) + + ctc_loss = torch.tensor(0.).type_as(l1_loss) + if self.ctc_weight > 0.: + lprobs = model.get_normalized_probs((_feat_out,), log_probs=True) + lprobs = lprobs.transpose(0, 1) # T x B x C + src_mask = lengths_to_mask(src_lens) + src_tokens_flat = src_tokens.masked_select(src_mask) + ctc_loss = F.ctc_loss( + lprobs, src_tokens_flat, tgt_lens, src_lens, + reduction=reduction, zero_infinity=True + ) * self.ctc_weight + + loss = l1_loss + dur_loss + pitch_loss + energy_loss + ctc_loss + + sample_size = sample["nsentences"] + logging_output = { + "loss": utils.item(loss.data), + "ntokens": sample["ntokens"], + "nsentences": sample["nsentences"], + "sample_size": sample_size, + "l1_loss": utils.item(l1_loss.data), + "dur_loss": utils.item(dur_loss.data), + "pitch_loss": utils.item(pitch_loss.data), + "energy_loss": utils.item(energy_loss.data), + "ctc_loss": utils.item(ctc_loss.data), + } + return loss, sample_size, logging_output + + @classmethod + def reduce_metrics(cls, logging_outputs: List[Dict[str, Any]]) -> None: + ns = [log.get("sample_size", 0) for log in logging_outputs] + ntot = sum(ns) + ws = [n / (ntot + 1e-8) for n in ns] + for key in [ + "loss", "l1_loss", "dur_loss", "pitch_loss", "energy_loss", + "ctc_loss" + ]: + vals = [log.get(key, 0) for log in logging_outputs] + val = sum(val * w for val, w in zip(vals, ws)) + metrics.log_scalar(key, val, ntot, round=3) + metrics.log_scalar("sample_size", ntot, len(logging_outputs)) + + # inference metrics + if "targ_frames" not in logging_outputs[0]: + return + n = sum(log.get("targ_frames", 0) for log in logging_outputs) + for key, new_key in [ + ("mcd_loss", "mcd_loss"), + ("pred_frames", "pred_ratio"), + ("nins", "ins_rate"), + ("ndel", "del_rate"), + ]: + val = sum(log.get(key, 0) for log in logging_outputs) + metrics.log_scalar(new_key, val / n, n, round=3) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + return False diff --git a/fairseq/criterions/tacotron2_loss.py b/fairseq/criterions/tacotron2_loss.py new file mode 100644 index 0000000000..8c7b655c8c --- /dev/null +++ b/fairseq/criterions/tacotron2_loss.py @@ -0,0 +1,210 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +from typing import Any, Dict, List +from functools import lru_cache +from dataclasses import dataclass, field + +import torch +from omegaconf import II + +from fairseq import metrics, utils +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass +from fairseq.data.data_utils import lengths_to_mask +import torch.nn.functional as F + + +logger = logging.getLogger(__name__) + + +@dataclass +class Tacotron2CriterionConfig(FairseqDataclass): + bce_pos_weight: float = field( + default=1.0, + metadata={"help": "weight of positive examples for BCE loss"}, + ) + n_frames_per_step: int = field( + default=0, + metadata={"help": "Number of frames per decoding step"}, + ) + use_guided_attention_loss: bool = field( + default=False, + metadata={"help": "use guided attention loss"}, + ) + guided_attention_loss_sigma: float = field( + default=0.4, + metadata={"help": "weight of positive examples for BCE loss"}, + ) + ctc_weight: float = field( + default=0.0, metadata={"help": "weight for CTC loss"} + ) + sentence_avg: bool = II("optimization.sentence_avg") + + +class GuidedAttentionLoss(torch.nn.Module): + """ + Efficiently Trainable Text-to-Speech System Based on Deep Convolutional + Networks with Guided Attention (https://arxiv.org/abs/1710.08969) + """ + + def __init__(self, sigma): + super().__init__() + self.sigma = sigma + + @staticmethod + @lru_cache(maxsize=8) + def _get_weight(s_len, t_len, sigma): + grid_x, grid_y = torch.meshgrid(torch.arange(t_len), torch.arange(s_len)) + grid_x = grid_x.to(s_len.device) + grid_y = grid_y.to(s_len.device) + w = (grid_y.float() / s_len - grid_x.float() / t_len) ** 2 + return 1.0 - torch.exp(-w / (2 * (sigma ** 2))) + + def _get_weights(self, src_lens, tgt_lens): + bsz, max_s_len, max_t_len = len(src_lens), max(src_lens), max(tgt_lens) + weights = torch.zeros((bsz, max_t_len, max_s_len)) + for i, (s_len, t_len) in enumerate(zip(src_lens, tgt_lens)): + weights[i, :t_len, :s_len] = self._get_weight(s_len, t_len, + self.sigma) + return weights + + @staticmethod + def _get_masks(src_lens, tgt_lens): + in_masks = lengths_to_mask(src_lens) + out_masks = lengths_to_mask(tgt_lens) + return out_masks.unsqueeze(2) & in_masks.unsqueeze(1) + + def forward(self, attn, src_lens, tgt_lens, reduction="mean"): + weights = self._get_weights(src_lens, tgt_lens).to(attn.device) + masks = self._get_masks(src_lens, tgt_lens).to(attn.device) + loss = (weights * attn.transpose(1, 2)).masked_select(masks) + loss = torch.sum(loss) if reduction == "sum" else torch.mean(loss) + return loss + + +@register_criterion("tacotron2", dataclass=Tacotron2CriterionConfig) +class Tacotron2Criterion(FairseqCriterion): + def __init__(self, task, sentence_avg, n_frames_per_step, + use_guided_attention_loss, guided_attention_loss_sigma, + bce_pos_weight, ctc_weight): + super().__init__(task) + self.sentence_avg = sentence_avg + self.n_frames_per_step = n_frames_per_step + self.bce_pos_weight = bce_pos_weight + + self.guided_attn = None + if use_guided_attention_loss: + self.guided_attn = GuidedAttentionLoss(guided_attention_loss_sigma) + self.ctc_weight = ctc_weight + + def forward(self, model, sample, reduction="mean"): + bsz, max_len, _ = sample["target"].size() + feat_tgt = sample["target"] + feat_len = sample["target_lengths"].view(bsz, 1).expand(-1, max_len) + eos_tgt = torch.arange(max_len).to(sample["target"].device) + eos_tgt = eos_tgt.view(1, max_len).expand(bsz, -1) + eos_tgt = (eos_tgt == (feat_len - 1)).float() + src_tokens = sample["net_input"]["src_tokens"] + src_lens = sample["net_input"]["src_lengths"] + tgt_lens = sample["target_lengths"] + + feat_out, eos_out, extra = model( + src_tokens=src_tokens, + src_lengths=src_lens, + prev_output_tokens=sample["net_input"]["prev_output_tokens"], + incremental_state=None, + target_lengths=tgt_lens, + speaker=sample["speaker"] + ) + + l1_loss, mse_loss, eos_loss = self.compute_loss( + extra["feature_out"], feat_out, eos_out, feat_tgt, eos_tgt, + tgt_lens, reduction, + ) + attn_loss = torch.tensor(0.).type_as(l1_loss) + if self.guided_attn is not None: + attn_loss = self.guided_attn(extra['attn'], src_lens, tgt_lens, reduction) + ctc_loss = torch.tensor(0.).type_as(l1_loss) + if self.ctc_weight > 0.: + net_output = (feat_out, eos_out, extra) + lprobs = model.get_normalized_probs(net_output, log_probs=True) + lprobs = lprobs.transpose(0, 1) # T x B x C + src_mask = lengths_to_mask(src_lens) + src_tokens_flat = src_tokens.masked_select(src_mask) + ctc_loss = F.ctc_loss( + lprobs, src_tokens_flat, tgt_lens, src_lens, + reduction=reduction, zero_infinity=True + ) * self.ctc_weight + loss = l1_loss + mse_loss + eos_loss + attn_loss + ctc_loss + + sample_size = sample["nsentences"] if self.sentence_avg \ + else sample["ntokens"] + logging_output = { + "loss": utils.item(loss.data), + "ntokens": sample["ntokens"], + "nsentences": sample["nsentences"], + "sample_size": sample_size, + "l1_loss": utils.item(l1_loss.data), + "mse_loss": utils.item(mse_loss.data), + "eos_loss": utils.item(eos_loss.data), + "attn_loss": utils.item(attn_loss.data), + "ctc_loss": utils.item(ctc_loss.data), + } + return loss, sample_size, logging_output + + def compute_loss(self, feat_out, feat_out_post, eos_out, feat_tgt, + eos_tgt, tgt_lens, reduction="mean"): + mask = lengths_to_mask(tgt_lens) + _eos_out = eos_out[mask].squeeze() + _eos_tgt = eos_tgt[mask] + _feat_tgt = feat_tgt[mask] + _feat_out = feat_out[mask] + _feat_out_post = feat_out_post[mask] + + l1_loss = ( + F.l1_loss(_feat_out, _feat_tgt, reduction=reduction) + + F.l1_loss(_feat_out_post, _feat_tgt, reduction=reduction) + ) + mse_loss = ( + F.mse_loss(_feat_out, _feat_tgt, reduction=reduction) + + F.mse_loss(_feat_out_post, _feat_tgt, reduction=reduction) + ) + eos_loss = F.binary_cross_entropy_with_logits( + _eos_out, _eos_tgt, pos_weight=torch.tensor(self.bce_pos_weight), + reduction=reduction + ) + return l1_loss, mse_loss, eos_loss + + @classmethod + def reduce_metrics(cls, logging_outputs: List[Dict[str, Any]]) -> None: + ns = [log.get("sample_size", 0) for log in logging_outputs] + ntot = sum(ns) + ws = [n / (ntot + 1e-8) for n in ns] + for key in ["loss", "l1_loss", "mse_loss", "eos_loss", "attn_loss", "ctc_loss"]: + vals = [log.get(key, 0) for log in logging_outputs] + val = sum(val * w for val, w in zip(vals, ws)) + metrics.log_scalar(key, val, ntot, round=3) + metrics.log_scalar("sample_size", ntot, len(logging_outputs)) + + # inference metrics + if "targ_frames" not in logging_outputs[0]: + return + n = sum(log.get("targ_frames", 0) for log in logging_outputs) + for key, new_key in [ + ("mcd_loss", "mcd_loss"), + ("pred_frames", "pred_ratio"), + ("nins", "ins_rate"), + ("ndel", "del_rate"), + ]: + val = sum(log.get(key, 0) for log in logging_outputs) + metrics.log_scalar(new_key, val / n, n, round=3) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + return False diff --git a/fairseq/data/audio/frm_text_to_speech_dataset.py b/fairseq/data/audio/frm_text_to_speech_dataset.py new file mode 100644 index 0000000000..125b1fc0c0 --- /dev/null +++ b/fairseq/data/audio/frm_text_to_speech_dataset.py @@ -0,0 +1,207 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory.abs + +import csv +import logging +import os.path as op +from typing import List, Optional + +import numpy as np +import torch +from fairseq.data import Dictionary +from fairseq.data.audio.speech_to_text_dataset import ( + S2TDataConfig +) +from fairseq.data.audio.text_to_speech_dataset import ( + TextToSpeechDataset, TextToSpeechDatasetCreator +) + +logger = logging.getLogger(__name__) + + +class FrmTextToSpeechDataset(TextToSpeechDataset): + def __init__( + self, + split: str, + is_train_split: bool, + data_cfg: S2TDataConfig, + audio_paths: List[str], + n_frames: List[int], + src_texts: Optional[List[str]] = None, + tgt_texts: Optional[List[str]] = None, + speakers: Optional[List[str]] = None, + src_langs: Optional[List[str]] = None, + tgt_langs: Optional[List[str]] = None, + ids: Optional[List[str]] = None, + tgt_dict: Optional[Dictionary] = None, + pre_tokenizer=None, + bpe_tokenizer=None, + n_frames_per_step=1, + speaker_to_id=None, + do_chunk=False, + chunk_bound=-1, + chunk_init=50, + chunk_incr=5, + add_eos=True, + dedup=True, + ref_fpu=-1 + ): + # It assumes texts are encoded at a fixed frame-rate + super().__init__( + split=split, + is_train_split=is_train_split, + data_cfg=data_cfg, + audio_paths=audio_paths, + n_frames=n_frames, + src_texts=src_texts, + tgt_texts=tgt_texts, + speakers=speakers, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + tgt_dict=tgt_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + n_frames_per_step=n_frames_per_step, + speaker_to_id=speaker_to_id + ) + + self.do_chunk = do_chunk + self.chunk_bound = chunk_bound + self.chunk_init = chunk_init + self.chunk_incr = chunk_incr + self.add_eos = add_eos + self.dedup = dedup + self.ref_fpu = ref_fpu + + self.chunk_size = -1 + + if do_chunk: + assert self.chunk_incr >= 0 + assert self.pre_tokenizer is None + + def __getitem__(self, index): + index, source, target, speaker_id, _, _, _ = super().__getitem__(index) + if target[-1].item() == self.tgt_dict.eos_index: + target = target[:-1] + + fpu = source.size(0) / target.size(0) # frame-per-unit + fps = self.n_frames_per_step + assert ( + self.ref_fpu == -1 or + abs((fpu * fps - self.ref_fpu) / self.ref_fpu) < 0.1 + ), f"{fpu*fps} != {self.ref_fpu}" + + # only chunk training split + if self.is_train_split and self.do_chunk and self.chunk_size > 0: + lang = target[:int(self.data_cfg.prepend_tgt_lang_tag)] + text = target[int(self.data_cfg.prepend_tgt_lang_tag):] + size = len(text) + chunk_size = min(self.chunk_size, size) + chunk_start = np.random.randint(size - chunk_size + 1) + text = text[chunk_start:chunk_start+chunk_size] + target = torch.cat((lang, text), 0) + + f_size = int(np.floor(chunk_size * fpu)) + f_start = int(np.floor(chunk_start * fpu)) + assert(f_size > 0) + source = source[f_start:f_start+f_size, :] + + if self.dedup: + target = torch.unique_consecutive(target) + + if self.add_eos: + eos_idx = self.tgt_dict.eos_index + target = torch.cat((target, torch.LongTensor([eos_idx])), 0) + + return index, source, target, speaker_id + + def set_epoch(self, epoch): + if self.is_train_split and self.do_chunk: + old = self.chunk_size + self.chunk_size = self.chunk_init + epoch * self.chunk_incr + if self.chunk_bound > 0: + self.chunk_size = min(self.chunk_size, self.chunk_bound) + logger.info(( + f"{self.split}: setting chunk size " + f"from {old} to {self.chunk_size}" + )) + + +class FrmTextToSpeechDatasetCreator(TextToSpeechDatasetCreator): + # inherit for key names + @classmethod + def from_tsv( + cls, + root: str, + data_cfg: S2TDataConfig, + split: str, + tgt_dict, + pre_tokenizer, + bpe_tokenizer, + is_train_split: bool, + n_frames_per_step: int, + speaker_to_id, + do_chunk: bool = False, + chunk_bound: int = -1, + chunk_init: int = 50, + chunk_incr: int = 5, + add_eos: bool = True, + dedup: bool = True, + ref_fpu: float = -1 + ) -> FrmTextToSpeechDataset: + tsv_path = op.join(root, f"{split}.tsv") + if not op.isfile(tsv_path): + raise FileNotFoundError(f"Dataset not found: {tsv_path}") + with open(tsv_path) as f: + reader = csv.DictReader( + f, + delimiter="\t", + quotechar=None, + doublequote=False, + lineterminator="\n", + quoting=csv.QUOTE_NONE, + ) + s = [dict(e) for e in reader] + assert len(s) > 0 + + ids = [ss[cls.KEY_ID] for ss in s] + audio_paths = [ + op.join(data_cfg.audio_root, ss[cls.KEY_AUDIO]) for ss in s + ] + n_frames = [int(ss[cls.KEY_N_FRAMES]) for ss in s] + tgt_texts = [ss[cls.KEY_TGT_TEXT] for ss in s] + src_texts = [ss.get(cls.KEY_SRC_TEXT, cls.DEFAULT_SRC_TEXT) for ss in s] + speakers = [ss.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for ss in s] + src_langs = [ss.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for ss in s] + tgt_langs = [ss.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for ss in s] + + return FrmTextToSpeechDataset( + split=split, + is_train_split=is_train_split, + data_cfg=data_cfg, + audio_paths=audio_paths, + n_frames=n_frames, + src_texts=src_texts, + tgt_texts=tgt_texts, + speakers=speakers, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + tgt_dict=tgt_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + n_frames_per_step=n_frames_per_step, + speaker_to_id=speaker_to_id, + do_chunk=do_chunk, + chunk_bound=chunk_bound, + chunk_init=chunk_init, + chunk_incr=chunk_incr, + add_eos=add_eos, + dedup=dedup, + ref_fpu=ref_fpu + ) diff --git a/fairseq/data/audio/text_to_speech_dataset.py b/fairseq/data/audio/text_to_speech_dataset.py new file mode 100644 index 0000000000..abfcb2be40 --- /dev/null +++ b/fairseq/data/audio/text_to_speech_dataset.py @@ -0,0 +1,215 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory.abs + +from pathlib import Path +from typing import List, Dict, Optional, Any +from dataclasses import dataclass + +import numpy as np +import torch + +from fairseq.data.audio.speech_to_text_dataset import ( + SpeechToTextDataset, SpeechToTextDatasetCreator, S2TDataConfig, + _collate_frames, get_features_or_waveform +) +from fairseq.data import Dictionary, data_utils as fairseq_data_utils + + +@dataclass +class TextToSpeechDatasetItem(object): + index: int + source: torch.Tensor + target: Optional[torch.Tensor] = None + speaker_id: Optional[int] = None + duration: Optional[torch.Tensor] = None + pitch: Optional[torch.Tensor] = None + energy: Optional[torch.Tensor] = None + + +class TextToSpeechDataset(SpeechToTextDataset): + def __init__( + self, + split: str, + is_train_split: bool, + cfg: S2TDataConfig, + audio_paths: List[str], + n_frames: List[int], + src_texts: Optional[List[str]] = None, + tgt_texts: Optional[List[str]] = None, + speakers: Optional[List[str]] = None, + src_langs: Optional[List[str]] = None, + tgt_langs: Optional[List[str]] = None, + ids: Optional[List[str]] = None, + tgt_dict: Optional[Dictionary] = None, + pre_tokenizer=None, + bpe_tokenizer=None, + n_frames_per_step=1, + speaker_to_id=None, + durations: Optional[List[List[int]]] = None, + pitches: Optional[List[str]] = None, + energies: Optional[List[str]] = None + ): + super(TextToSpeechDataset, self).__init__( + split, is_train_split, cfg, audio_paths, n_frames, + src_texts=src_texts, tgt_texts=tgt_texts, speakers=speakers, + src_langs=src_langs, tgt_langs=tgt_langs, ids=ids, + tgt_dict=tgt_dict, pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, n_frames_per_step=n_frames_per_step, + speaker_to_id=speaker_to_id + ) + self.durations = durations + self.pitches = pitches + self.energies = energies + + def __getitem__(self, index: int) -> TextToSpeechDatasetItem: + s2t_item = super().__getitem__(index) + + duration, pitch, energy = None, None, None + if self.durations is not None: + duration = torch.tensor( + self.durations[index] + [0], dtype=torch.long # pad 0 for EOS + ) + if self.pitches is not None: + pitch = get_features_or_waveform(self.pitches[index]) + pitch = torch.from_numpy( + np.concatenate((pitch, [0])) # pad 0 for EOS + ).float() + if self.energies is not None: + energy = get_features_or_waveform(self.energies[index]) + energy = torch.from_numpy( + np.concatenate((energy, [0])) # pad 0 for EOS + ).float() + return TextToSpeechDatasetItem( + index=index, source=s2t_item.source, target=s2t_item.target, + speaker_id=s2t_item.speaker_id, duration=duration, pitch=pitch, + energy=energy + ) + + def collater(self, samples: List[TextToSpeechDatasetItem]) -> Dict[str, Any]: + if len(samples) == 0: + return {} + + src_lengths, order = torch.tensor( + [s.target.shape[0] for s in samples], dtype=torch.long + ).sort(descending=True) + id_ = torch.tensor([s.index for s in samples], + dtype=torch.long).index_select(0, order) + feat = _collate_frames( + [s.source for s in samples], self.cfg.use_audio_input + ).index_select(0, order) + target_lengths = torch.tensor( + [s.source.shape[0] for s in samples], dtype=torch.long + ).index_select(0, order) + + src_tokens = fairseq_data_utils.collate_tokens( + [s.target for s in samples], + self.tgt_dict.pad(), + self.tgt_dict.eos(), + left_pad=False, + move_eos_to_beginning=False, + ).index_select(0, order) + + speaker = None + if self.speaker_to_id is not None: + speaker = torch.tensor( + [s.speaker_id for s in samples], dtype=torch.long + ).index_select(0, order).view(-1, 1) + + bsz, _, d = feat.size() + prev_output_tokens = torch.cat( + (feat.new_zeros((bsz, 1, d)), feat[:, :-1, :]), dim=1 + ) + + durations, pitches, energies = None, None, None + if self.durations is not None: + durations = fairseq_data_utils.collate_tokens( + [s.duration for s in samples], 0 + ).index_select(0, order) + assert src_tokens.shape[1] == durations.shape[1] + if self.pitches is not None: + pitches = _collate_frames([s.pitch for s in samples], True) + pitches = pitches.index_select(0, order) + assert src_tokens.shape[1] == pitches.shape[1] + if self.energies is not None: + energies = _collate_frames([s.energy for s in samples], True) + energies = energies.index_select(0, order) + assert src_tokens.shape[1] == energies.shape[1] + src_texts = [self.tgt_dict.string(samples[i].target) for i in order] + + return { + "id": id_, + "net_input": { + "src_tokens": src_tokens, + "src_lengths": src_lengths, + "prev_output_tokens": prev_output_tokens, + }, + "speaker": speaker, + "target": feat, + "durations": durations, + "pitches": pitches, + "energies": energies, + "target_lengths": target_lengths, + "ntokens": sum(target_lengths).item(), + "nsentences": len(samples), + "src_texts": src_texts, + } + + +class TextToSpeechDatasetCreator(SpeechToTextDatasetCreator): + KEY_DURATION = "duration" + KEY_PITCH = "pitch" + KEY_ENERGY = "energy" + + @classmethod + def _from_list( + cls, + split_name: str, + is_train_split, + samples: List[Dict], + cfg: S2TDataConfig, + tgt_dict, + pre_tokenizer, + bpe_tokenizer, + n_frames_per_step, + speaker_to_id + ) -> TextToSpeechDataset: + audio_root = Path(cfg.audio_root) + ids = [s[cls.KEY_ID] for s in samples] + audio_paths = [(audio_root / s[cls.KEY_AUDIO]).as_posix() for s in samples] + n_frames = [int(s[cls.KEY_N_FRAMES]) for s in samples] + tgt_texts = [s[cls.KEY_TGT_TEXT] for s in samples] + src_texts = [s.get(cls.KEY_SRC_TEXT, cls.DEFAULT_SRC_TEXT) for s in samples] + speakers = [s.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for s in samples] + src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] + tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] + + durations = [s.get(cls.KEY_DURATION, None) for s in samples] + durations = [ + None if dd is None else [int(d) for d in dd.split(" ")] + for dd in durations + ] + durations = None if any(dd is None for dd in durations) else durations + + pitches = [s.get(cls.KEY_PITCH, None) for s in samples] + pitches = [ + None if pp is None else (audio_root / pp).as_posix() + for pp in pitches + ] + pitches = None if any(pp is None for pp in pitches) else pitches + + energies = [s.get(cls.KEY_ENERGY, None) for s in samples] + energies = [ + None if ee is None else (audio_root / ee).as_posix() + for ee in energies] + energies = None if any(ee is None for ee in energies) else energies + + return TextToSpeechDataset( + split_name, is_train_split, cfg, audio_paths, n_frames, + src_texts, tgt_texts, speakers, src_langs, tgt_langs, ids, tgt_dict, + pre_tokenizer, bpe_tokenizer, n_frames_per_step, speaker_to_id, + durations, pitches, energies + ) diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index d3ef0f9896..d6495389f0 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -92,7 +92,8 @@ def string( ) extra_symbols_to_ignore = set(extra_symbols_to_ignore or []) - extra_symbols_to_ignore.add(self.eos()) + if not include_eos: + extra_symbols_to_ignore.add(self.eos()) def token_string(i): if i == self.unk(): diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index cac365cbb8..1c5189c0f7 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -5,5 +5,5 @@ from .berard import * # noqa from .convtransformer import * # noqa -from .s2t_transformer import * # noqa -from .xm_transformer import * # noqa +from .s2t_transformer import * # noqa +from .xm_transformer import * # noqa diff --git a/fairseq/models/speech_to_text/utils.py b/fairseq/models/speech_to_text/utils.py index 573f8537c9..168b8bf13b 100644 --- a/fairseq/models/speech_to_text/utils.py +++ b/fairseq/models/speech_to_text/utils.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # Copyright (c) 2017-present, Facebook, Inc. # All rights reserved. # diff --git a/fairseq/models/text_to_speech/__init__.py b/fairseq/models/text_to_speech/__init__.py new file mode 100644 index 0000000000..652fee0d68 --- /dev/null +++ b/fairseq/models/text_to_speech/__init__.py @@ -0,0 +1,8 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .tacotron2 import * # noqa +from .tts_transformer import * # noqa +from .fastspeech2 import * # noqa diff --git a/fairseq/models/text_to_speech/fastspeech2.py b/fairseq/models/text_to_speech/fastspeech2.py new file mode 100644 index 0000000000..9c38d0917d --- /dev/null +++ b/fairseq/models/text_to_speech/fastspeech2.py @@ -0,0 +1,352 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +import torch +from torch import nn + +from fairseq.models import (FairseqEncoder, FairseqEncoderModel, register_model, + register_model_architecture) +from fairseq.modules import ( + LayerNorm, PositionalEmbedding, FairseqDropout, MultiheadAttention +) +from fairseq import utils +from fairseq.data.data_utils import lengths_to_padding_mask + + +logger = logging.getLogger(__name__) + + +def model_init(m): + if isinstance(m, nn.Conv1d): + nn.init.xavier_uniform_(m.weight, torch.nn.init.calculate_gain("relu")) + + +def Embedding(num_embeddings, embedding_dim, padding_idx=None): + m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) + nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + return m + + +class PositionwiseFeedForward(nn.Module): + def __init__(self, in_dim, hidden_dim, kernel_size, dropout): + super().__init__() + self.ffn = nn.Sequential( + nn.Conv1d(in_dim, hidden_dim, kernel_size=kernel_size, + padding=(kernel_size - 1) // 2), + nn.ReLU(), + nn.Conv1d(hidden_dim, in_dim, kernel_size=kernel_size, + padding=(kernel_size - 1) // 2) + ) + self.layer_norm = LayerNorm(in_dim) + self.dropout = self.dropout_module = FairseqDropout( + p=dropout, module_name=self.__class__.__name__ + ) + + def forward(self, x): + # B x T x C + residual = x + x = self.ffn(x.transpose(1, 2)).transpose(1, 2) + x = self.dropout(x) + return self.layer_norm(x + residual) + + +class FFTLayer(torch.nn.Module): + def __init__( + self, embed_dim, n_heads, hidden_dim, kernel_size, dropout, + attention_dropout + ): + super().__init__() + self.self_attn = MultiheadAttention( + embed_dim, n_heads, dropout=attention_dropout, self_attention=True + ) + self.layer_norm = LayerNorm(embed_dim) + self.ffn = PositionwiseFeedForward( + embed_dim, hidden_dim, kernel_size, dropout=dropout + ) + + def forward(self, x, padding_mask=None): + # B x T x C + residual = x + x = x.transpose(0, 1) + x, _ = self.self_attn( + query=x, key=x, value=x, key_padding_mask=padding_mask, + need_weights=False + ) + x = x.transpose(0, 1) + x = self.layer_norm(x + residual) + return self.ffn(x) + + +class LengthRegulator(nn.Module): + def forward(self, x, durations): + # x: B x T x C + out_lens = durations.sum(dim=1) + max_len = out_lens.max() + bsz, seq_len, dim = x.size() + out = x.new_zeros((bsz, max_len, dim)) + + for b in range(bsz): + indices = [] + for t in range(seq_len): + indices.extend([t] * utils.item(durations[b, t])) + indices = torch.tensor(indices, dtype=torch.long).to(x.device) + out_len = utils.item(out_lens[b]) + out[b, :out_len] = x[b].index_select(0, indices) + + return out, out_lens + + +class VariancePredictor(nn.Module): + def __init__(self, args): + super().__init__() + self.conv1 = nn.Sequential( + nn.Conv1d( + args.encoder_embed_dim, args.var_pred_hidden_dim, + kernel_size=args.var_pred_kernel_size, + padding=(args.var_pred_kernel_size - 1) // 2 + ), + nn.ReLU() + ) + self.ln1 = nn.LayerNorm(args.var_pred_hidden_dim) + self.dropout_module = FairseqDropout( + p=args.var_pred_dropout, module_name=self.__class__.__name__ + ) + self.conv2 = nn.Sequential( + nn.Conv1d( + args.var_pred_hidden_dim, args.var_pred_hidden_dim, + kernel_size=args.var_pred_kernel_size, padding=1 + ), + nn.ReLU() + ) + self.ln2 = nn.LayerNorm(args.var_pred_hidden_dim) + self.proj = nn.Linear(args.var_pred_hidden_dim, 1) + + def forward(self, x): + # Input: B x T x C; Output: B x T + x = self.conv1(x.transpose(1, 2)).transpose(1, 2) + x = self.dropout_module(self.ln1(x)) + x = self.conv2(x.transpose(1, 2)).transpose(1, 2) + x = self.dropout_module(self.ln2(x)) + return self.proj(x).squeeze(dim=2) + + +class VarianceAdaptor(nn.Module): + def __init__(self, args): + super().__init__() + self.args = args + self.length_regulator = LengthRegulator() + self.duration_predictor = VariancePredictor(args) + self.pitch_predictor = VariancePredictor(args) + self.energy_predictor = VariancePredictor(args) + + n_bins, steps = self.args.var_pred_n_bins, self.args.var_pred_n_bins - 1 + self.pitch_bins = torch.linspace(args.pitch_min, args.pitch_max, steps) + self.embed_pitch = Embedding(n_bins, args.encoder_embed_dim) + self.energy_bins = torch.linspace(args.energy_min, args.energy_max, steps) + self.embed_energy = Embedding(n_bins, args.encoder_embed_dim) + + def get_pitch_emb(self, x, tgt=None, factor=1.0): + out = self.pitch_predictor(x) + bins = self.pitch_bins.to(x.device) + if tgt is None: + out = out * factor + emb = self.embed_pitch(torch.bucketize(out, bins)) + else: + emb = self.embed_pitch(torch.bucketize(tgt, bins)) + return out, emb + + def get_energy_emb(self, x, tgt=None, factor=1.0): + out = self.energy_predictor(x) + bins = self.energy_bins.to(x.device) + if tgt is None: + out = out * factor + emb = self.embed_energy(torch.bucketize(out, bins)) + else: + emb = self.embed_energy(torch.bucketize(tgt, bins)) + return out, emb + + def forward( + self, x, padding_mask, durations=None, pitches=None, energies=None, + d_factor=1.0, p_factor=1.0, e_factor=1.0 + ): + # x: B x T x C + log_dur_out = self.duration_predictor(x) + dur_out = torch.clamp( + torch.round((torch.exp(log_dur_out) - 1) * d_factor).long(), min=0 + ) + dur_out.masked_fill_(padding_mask, 0) + + pitch_out, pitch_emb = self.get_pitch_emb(x, pitches, p_factor) + x = x + pitch_emb + energy_out, energy_emb = self.get_energy_emb(x, energies, e_factor) + x = x + energy_emb + + x, out_lens = self.length_regulator( + x, dur_out if durations is None else durations + ) + + return x, out_lens, log_dur_out, pitch_out, energy_out + + +class FastSpeech2Encoder(FairseqEncoder): + def __init__(self, args, src_dict, embed_speaker): + super().__init__(src_dict) + self.args = args + self.padding_idx = src_dict.pad() + self.n_frames_per_step = args.n_frames_per_step + self.out_dim = args.output_frame_dim * args.n_frames_per_step + + self.embed_speaker = embed_speaker + self.spk_emb_proj = None + if embed_speaker is not None: + self.spk_emb_proj = nn.Linear( + args.encoder_embed_dim + args.speaker_embed_dim, + args.encoder_embed_dim + ) + + self.dropout_module = FairseqDropout( + p=args.dropout, module_name=self.__class__.__name__ + ) + self.embed_tokens = Embedding( + len(src_dict), args.encoder_embed_dim, padding_idx=self.padding_idx + ) + + self.embed_positions = PositionalEmbedding( + args.max_source_positions, args.encoder_embed_dim, self.padding_idx + ) + self.pos_emb_alpha = nn.Parameter(torch.ones(1)) + self.dec_pos_emb_alpha = nn.Parameter(torch.ones(1)) + + self.encoder_fft_layers = nn.ModuleList( + FFTLayer( + args.encoder_embed_dim, args.encoder_attention_heads, + args.fft_hidden_dim, args.fft_kernel_size, + dropout=args.dropout, attention_dropout=args.attention_dropout + ) + for _ in range(args.encoder_layers) + ) + + self.var_adaptor = VarianceAdaptor(args) + + self.decoder_fft_layers = nn.ModuleList( + FFTLayer( + args.decoder_embed_dim, args.decoder_attention_heads, + args.fft_hidden_dim, args.fft_kernel_size, + dropout=args.dropout, attention_dropout=args.attention_dropout + ) + for _ in range(args.decoder_layers) + ) + + self.out_proj = nn.Linear(args.decoder_embed_dim, self.out_dim) + + self.apply(model_init) + + def forward(self, src_tokens, src_lengths=None, speaker=None, + durations=None, pitches=None, energies=None, **kwargs): + x = self.embed_tokens(src_tokens) + + enc_padding_mask = src_tokens.eq(self.padding_idx) + x += self.pos_emb_alpha * self.embed_positions(enc_padding_mask) + x = self.dropout_module(x) + + for layer in self.encoder_fft_layers: + x = layer(x, enc_padding_mask) + + if self.embed_speaker is not None: + bsz, seq_len, _ = x.size() + emb = self.embed_speaker(speaker).expand(bsz, seq_len, -1) + x = self.spk_emb_proj(torch.cat([x, emb], dim=2)) + + x, out_lens, log_dur_out, pitch_out, energy_out = \ + self.var_adaptor(x, enc_padding_mask, durations, pitches, energies) + + dec_padding_mask = lengths_to_padding_mask(out_lens) + x += self.dec_pos_emb_alpha * self.embed_positions(dec_padding_mask) + for layer in self.decoder_fft_layers: + x = layer(x, dec_padding_mask) + + x = self.out_proj(x) + + return x, out_lens, log_dur_out, pitch_out, energy_out + + +@register_model("fastspeech2") +class FastSpeech2Model(FairseqEncoderModel): + """ + Implementation for https://arxiv.org/abs/2006.04558 + """ + + NON_AUTOREGRESSIVE = True + + @staticmethod + def add_args(parser): + parser.add_argument("--dropout", type=float) + parser.add_argument("--output-frame-dim", type=int) + parser.add_argument("--speaker-embed-dim", type=int) + # FFT blocks + parser.add_argument("--fft-hidden-dim", type=int) + parser.add_argument("--fft-kernel-size", type=int) + parser.add_argument("--attention-dropout", type=float) + parser.add_argument("--encoder-layers", type=int) + parser.add_argument("--encoder-embed-dim", type=int) + parser.add_argument("--encoder-attention-heads", type=int) + parser.add_argument("--decoder-layers", type=int) + parser.add_argument("--decoder-embed-dim", type=int) + parser.add_argument("--decoder-attention-heads", type=int) + # variance predictor + parser.add_argument("--var-pred-n-bins", type=int) + parser.add_argument("--var-pred-hidden-dim", type=int) + parser.add_argument("--var-pred-kernel-size", type=int) + parser.add_argument("--var-pred-dropout", type=float) + + def __init__(self, encoder, args, src_dict): + super().__init__(encoder) + self._num_updates = 0 + + out_dim = args.output_frame_dim * args.n_frames_per_step + self.ctc_proj = None + if getattr(args, "ctc_weight", 0.) > 0.: + self.ctc_proj = nn.Linear(out_dim, len(src_dict)) + + @classmethod + def build_model(cls, args, task): + embed_speaker = task.get_speaker_embeddings(args) + encoder = FastSpeech2Encoder(args, task.src_dict, embed_speaker) + return cls(encoder, args, task.src_dict) + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + self._num_updates = num_updates + + def get_normalized_probs(self, net_output, log_probs, sample=None): + logits = self.ctc_proj(net_output[0]) + if log_probs: + return utils.log_softmax(logits.float(), dim=-1) + else: + return utils.softmax(logits.float(), dim=-1) + + +@register_model_architecture("fastspeech2", "fastspeech2") +def base_architecture(args): + args.dropout = getattr(args, "dropout", 0.2) + args.output_frame_dim = getattr(args, "output_frame_dim", 80) + args.speaker_embed_dim = getattr(args, "speaker_embed_dim", 64) + # FFT blocks + args.fft_hidden_dim = getattr(args, "fft_hidden_dim", 1024) + args.fft_kernel_size = getattr(args, "fft_kernel_size", 9) + args.attention_dropout = getattr(args, "attention_dropout", 0.0) + args.encoder_layers = getattr(args, "encoder_layers", 4) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 2) + args.decoder_layers = getattr(args, "decoder_layers", 4) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 256) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 2) + # variance predictor + args.var_pred_n_bins = getattr(args, "var_pred_n_bins", 256) + args.var_pred_hidden_dim = getattr(args, "var_pred_hidden_dim", 256) + args.var_pred_kernel_size = getattr(args, "var_pred_kernel_size", 3) + args.var_pred_dropout = getattr(args, "var_pred_dropout", 0.5) diff --git a/fairseq/models/text_to_speech/hifigan.py b/fairseq/models/text_to_speech/hifigan.py new file mode 100644 index 0000000000..edc7db6015 --- /dev/null +++ b/fairseq/models/text_to_speech/hifigan.py @@ -0,0 +1,173 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn import Conv1d, ConvTranspose1d +from torch.nn.utils import weight_norm, remove_weight_norm + +LRELU_SLOPE = 0.1 + + +def init_weights(m, mean=0.0, std=0.01): + classname = m.__class__.__name__ + if classname.find("Conv") != -1: + m.weight.data.normal_(mean, std) + + +def get_padding(kernel_size, dilation=1): + return (kernel_size * dilation - dilation) // 2 + + +class ResBlock(torch.nn.Module): + def __init__(self, channels, kernel_size=3, dilation=(1, 3, 5)): + super(ResBlock, self).__init__() + self.convs1 = nn.ModuleList( + [ + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[0], + padding=get_padding(kernel_size, dilation[0]), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[1], + padding=get_padding(kernel_size, dilation[1]), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=dilation[2], + padding=get_padding(kernel_size, dilation[2]), + ) + ), + ] + ) + self.convs1.apply(init_weights) + + self.convs2 = nn.ModuleList( + [ + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + weight_norm( + Conv1d( + channels, + channels, + kernel_size, + 1, + dilation=1, + padding=get_padding(kernel_size, 1), + ) + ), + ] + ) + self.convs2.apply(init_weights) + + def forward(self, x): + for c1, c2 in zip(self.convs1, self.convs2): + xt = F.leaky_relu(x, LRELU_SLOPE) + xt = c1(xt) + xt = F.leaky_relu(xt, LRELU_SLOPE) + xt = c2(xt) + x = xt + x + return x + + def remove_weight_norm(self): + for layer in self.convs1: + remove_weight_norm(layer) + for layer in self.convs2: + remove_weight_norm(layer) + + +class Generator(torch.nn.Module): + def __init__(self, cfg): + super(Generator, self).__init__() + self.num_kernels = len(cfg["resblock_kernel_sizes"]) + self.num_upsamples = len(cfg["upsample_rates"]) + self.conv_pre = weight_norm( + Conv1d(80, cfg["upsample_initial_channel"], 7, 1, padding=3) + ) + + self.ups = nn.ModuleList() + for i, (u, k) in enumerate( + zip(cfg["upsample_rates"], cfg["upsample_kernel_sizes"]) + ): + self.ups.append( + weight_norm( + ConvTranspose1d( + cfg["upsample_initial_channel"] // (2 ** i), + cfg["upsample_initial_channel"] // (2 ** (i + 1)), + k, + u, + padding=(k - u) // 2, + ) + ) + ) + + self.resblocks = nn.ModuleList() + for i in range(len(self.ups)): + ch = cfg["upsample_initial_channel"] // (2 ** (i + 1)) + for k, d in zip( + cfg["resblock_kernel_sizes"], cfg["resblock_dilation_sizes"] + ): + self.resblocks.append(ResBlock(ch, k, d)) + + self.conv_post = weight_norm(Conv1d(ch, 1, 7, 1, padding=3)) + self.ups.apply(init_weights) + self.conv_post.apply(init_weights) + + def forward(self, x): + x = self.conv_pre(x) + for i in range(self.num_upsamples): + x = F.leaky_relu(x, LRELU_SLOPE) + x = self.ups[i](x) + xs = None + for j in range(self.num_kernels): + if xs is None: + xs = self.resblocks[i * self.num_kernels + j](x) + else: + xs += self.resblocks[i * self.num_kernels + j](x) + x = xs / self.num_kernels + x = F.leaky_relu(x) + x = self.conv_post(x) + x = torch.tanh(x) + + return x + + def remove_weight_norm(self): + print("Removing weight norm...") + for layer in self.ups: + remove_weight_norm(layer) + for layer in self.resblocks: + layer.remove_weight_norm() + remove_weight_norm(self.conv_pre) + remove_weight_norm(self.conv_post) diff --git a/fairseq/models/text_to_speech/tacotron2.py b/fairseq/models/text_to_speech/tacotron2.py new file mode 100644 index 0000000000..bb327e81e7 --- /dev/null +++ b/fairseq/models/text_to_speech/tacotron2.py @@ -0,0 +1,350 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +import torch +from torch import nn +from torch.nn import functional as F + +from fairseq.models import (FairseqEncoder, FairseqEncoderDecoderModel, + FairseqIncrementalDecoder, register_model, + register_model_architecture) +from fairseq.modules import LSTMCellWithZoneOut, LocationAttention + + +logger = logging.getLogger(__name__) + + +def encoder_init(m): + if isinstance(m, nn.Conv1d): + nn.init.xavier_uniform_(m.weight, torch.nn.init.calculate_gain("relu")) + + +class Tacotron2Encoder(FairseqEncoder): + def __init__(self, args, src_dict, embed_speaker): + super().__init__(src_dict) + self.padding_idx = src_dict.pad() + self.embed_speaker = embed_speaker + self.spk_emb_proj = None + if embed_speaker is not None: + self.spk_emb_proj = nn.Linear( + args.encoder_embed_dim + args.speaker_embed_dim, + args.encoder_embed_dim + ) + + self.embed_tokens = nn.Embedding(len(src_dict), args.encoder_embed_dim, + padding_idx=self.padding_idx) + + assert(args.encoder_conv_kernel_size % 2 == 1) + self.convolutions = nn.ModuleList( + nn.Sequential( + nn.Conv1d(args.encoder_embed_dim, args.encoder_embed_dim, + kernel_size=args.encoder_conv_kernel_size, + padding=((args.encoder_conv_kernel_size - 1) // 2)), + nn.BatchNorm1d(args.encoder_embed_dim), + nn.ReLU(), + nn.Dropout(args.encoder_dropout) + ) + for _ in range(args.encoder_conv_layers) + ) + + self.lstm = nn.LSTM(args.encoder_embed_dim, args.encoder_embed_dim // 2, + num_layers=args.encoder_lstm_layers, + batch_first=True, bidirectional=True) + + self.apply(encoder_init) + + def forward(self, src_tokens, src_lengths=None, speaker=None, **kwargs): + x = self.embed_tokens(src_tokens) + x = x.transpose(1, 2).contiguous() # B x T x C -> B x C x T + for conv in self.convolutions: + x = conv(x) + x = x.transpose(1, 2).contiguous() # B x C x T -> B x T x C + + src_lengths = src_lengths.cpu().long() + x = nn.utils.rnn.pack_padded_sequence(x, src_lengths, batch_first=True) + x = self.lstm(x)[0] + x = nn.utils.rnn.pad_packed_sequence(x, batch_first=True)[0] + + encoder_padding_mask = src_tokens.eq(self.padding_idx) + + if self.embed_speaker is not None: + seq_len, bsz, _ = x.size() + emb = self.embed_speaker(speaker).expand(seq_len, bsz, -1) + x = self.spk_emb_proj(torch.cat([x, emb], dim=2)) + + return { + "encoder_out": [x], # B x T x C + "encoder_padding_mask": encoder_padding_mask, # B x T + } + + +class Prenet(nn.Module): + def __init__(self, in_dim, n_layers, n_units, dropout): + super().__init__() + self.layers = nn.ModuleList( + nn.Sequential(nn.Linear(in_dim if i == 0 else n_units, n_units), + nn.ReLU()) + for i in range(n_layers) + ) + self.dropout = dropout + + def forward(self, x): + for layer in self.layers: + x = F.dropout(layer(x), p=self.dropout) # always applies dropout + return x + + +class Postnet(nn.Module): + def __init__(self, in_dim, n_channels, kernel_size, n_layers, dropout): + super(Postnet, self).__init__() + self.convolutions = nn.ModuleList() + assert(kernel_size % 2 == 1) + for i in range(n_layers): + cur_layers = [ + nn.Conv1d(in_dim if i == 0 else n_channels, + n_channels if i < n_layers - 1 else in_dim, + kernel_size=kernel_size, + padding=((kernel_size - 1) // 2)), + nn.BatchNorm1d(n_channels if i < n_layers - 1 else in_dim) + ] + ([nn.Tanh()] if i < n_layers - 1 else []) + [nn.Dropout(dropout)] + nn.init.xavier_uniform_( + cur_layers[0].weight, + torch.nn.init.calculate_gain( + "tanh" if i < n_layers - 1 else "linear" + ) + ) + self.convolutions.append(nn.Sequential(*cur_layers)) + + def forward(self, x): + x = x.transpose(1, 2) # B x T x C -> B x C x T + for conv in self.convolutions: + x = conv(x) + return x.transpose(1, 2) + + +def decoder_init(m): + if isinstance(m, torch.nn.Conv1d): + nn.init.xavier_uniform_(m.weight, torch.nn.init.calculate_gain("tanh")) + + +class Tacotron2Decoder(FairseqIncrementalDecoder): + def __init__(self, args, src_dict): + super().__init__(None) + self.args = args + self.n_frames_per_step = args.n_frames_per_step + self.out_dim = args.output_frame_dim * args.n_frames_per_step + + self.prenet = Prenet(self.out_dim, args.prenet_layers, args.prenet_dim, + args.prenet_dropout) + + # take prev_context, prev_frame, (speaker embedding) as input + self.attention_lstm = LSTMCellWithZoneOut( + args.zoneout, + args.prenet_dim + args.encoder_embed_dim, + args.decoder_lstm_dim + ) + + # take attention_lstm output, attention_state, encoder_out as input + self.attention = LocationAttention( + args.attention_dim, args.encoder_embed_dim, args.decoder_lstm_dim, + (1 + int(args.attention_use_cumprob)), + args.attention_conv_dim, args.attention_conv_kernel_size + ) + + # take attention_lstm output, context, (gated_latent) as input + self.lstm = nn.ModuleList( + LSTMCellWithZoneOut( + args.zoneout, + args.encoder_embed_dim + args.decoder_lstm_dim, + args.decoder_lstm_dim + ) + for i in range(args.decoder_lstm_layers) + ) + + proj_in_dim = args.encoder_embed_dim + args.decoder_lstm_dim + self.feat_proj = nn.Linear(proj_in_dim, self.out_dim) + self.eos_proj = nn.Linear(proj_in_dim, 1) + + self.postnet = Postnet(self.out_dim, args.postnet_conv_dim, + args.postnet_conv_kernel_size, + args.postnet_layers, args.postnet_dropout) + + self.ctc_proj = None + if getattr(args, "ctc_weight", 0.) > 0.: + self.ctc_proj = nn.Linear(self.out_dim, len(src_dict)) + + self.apply(decoder_init) + + def _get_states(self, incremental_state, enc_out): + bsz, in_len, _ = enc_out.size() + alstm_h = self.get_incremental_state(incremental_state, "alstm_h") + if alstm_h is None: + alstm_h = enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) + alstm_c = self.get_incremental_state(incremental_state, "alstm_c") + if alstm_c is None: + alstm_c = enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) + + lstm_h = self.get_incremental_state(incremental_state, "lstm_h") + if lstm_h is None: + lstm_h = [enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) + for _ in range(self.args.decoder_lstm_layers)] + lstm_c = self.get_incremental_state(incremental_state, "lstm_c") + if lstm_c is None: + lstm_c = [enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) + for _ in range(self.args.decoder_lstm_layers)] + + attn_w = self.get_incremental_state(incremental_state, "attn_w") + if attn_w is None: + attn_w = enc_out.new_zeros(bsz, in_len) + attn_w_cum = self.get_incremental_state(incremental_state, "attn_w_cum") + if attn_w_cum is None: + attn_w_cum = enc_out.new_zeros(bsz, in_len) + return alstm_h, alstm_c, lstm_h, lstm_c, attn_w, attn_w_cum + + def _get_init_attn_c(self, enc_out, enc_mask): + bsz = enc_out.size(0) + if self.args.init_attn_c == "zero": + return enc_out.new_zeros(bsz, self.args.encoder_embed_dim) + elif self.args.init_attn_c == "avg": + enc_w = (~enc_mask).type(enc_out.type()) + enc_w = enc_w / enc_w.sum(dim=1, keepdim=True) + return torch.sum(enc_out * enc_w.unsqueeze(2), dim=1) + else: + raise ValueError(f"{self.args.init_attn_c} not supported") + + def forward(self, prev_output_tokens, encoder_out=None, + incremental_state=None, target_lengths=None, **kwargs): + enc_mask = encoder_out["encoder_padding_mask"] + enc_out = encoder_out["encoder_out"][0] + in_len = enc_out.size(1) + + if incremental_state is not None: + prev_output_tokens = prev_output_tokens[:, -1:, :] + bsz, out_len, _ = prev_output_tokens.size() + + prenet_out = self.prenet(prev_output_tokens) + (alstm_h, alstm_c, lstm_h, lstm_c, + attn_w, attn_w_cum) = self._get_states(incremental_state, enc_out) + attn_ctx = self._get_init_attn_c(enc_out, enc_mask) + + attn_out = enc_out.new_zeros(bsz, in_len, out_len) + feat_out = enc_out.new_zeros(bsz, out_len, self.out_dim) + eos_out = enc_out.new_zeros(bsz, out_len) + for t in range(out_len): + alstm_in = torch.cat((attn_ctx, prenet_out[:, t, :]), dim=1) + alstm_h, alstm_c = self.attention_lstm(alstm_in, (alstm_h, alstm_c)) + + attn_state = attn_w.unsqueeze(1) + if self.args.attention_use_cumprob: + attn_state = torch.stack((attn_w, attn_w_cum), dim=1) + attn_ctx, attn_w = self.attention( + enc_out, enc_mask, alstm_h, attn_state + ) + attn_w_cum = attn_w_cum + attn_w + attn_out[:, :, t] = attn_w + + for i, cur_lstm in enumerate(self.lstm): + if i == 0: + lstm_in = torch.cat((attn_ctx, alstm_h), dim=1) + else: + lstm_in = torch.cat((attn_ctx, lstm_h[i - 1]), dim=1) + lstm_h[i], lstm_c[i] = cur_lstm(lstm_in, (lstm_h[i], lstm_c[i])) + + proj_in = torch.cat((attn_ctx, lstm_h[-1]), dim=1) + feat_out[:, t, :] = self.feat_proj(proj_in) + eos_out[:, t] = self.eos_proj(proj_in).squeeze(1) + self.attention.clear_cache() + + self.set_incremental_state(incremental_state, "alstm_h", alstm_h) + self.set_incremental_state(incremental_state, "alstm_c", alstm_c) + self.set_incremental_state(incremental_state, "lstm_h", lstm_h) + self.set_incremental_state(incremental_state, "lstm_c", lstm_c) + self.set_incremental_state(incremental_state, "attn_w", attn_w) + self.set_incremental_state(incremental_state, "attn_w_cum", attn_w_cum) + + post_feat_out = feat_out + self.postnet(feat_out) + eos_out = eos_out.view(bsz, out_len, 1) + return post_feat_out, eos_out, {"attn": attn_out, "feature_out": feat_out} + + +@register_model("tacotron_2") +class Tacotron2Model(FairseqEncoderDecoderModel): + """ + Implementation for https://arxiv.org/pdf/1712.05884.pdf + """ + + @staticmethod + def add_args(parser): + # encoder + parser.add_argument("--encoder-dropout", type=float) + parser.add_argument("--encoder-embed-dim", type=int) + parser.add_argument("--encoder-conv-layers", type=int) + parser.add_argument("--encoder-conv-kernel-size", type=int) + parser.add_argument("--encoder-lstm-layers", type=int) + # decoder + parser.add_argument("--attention-dim", type=int) + parser.add_argument("--attention-conv-dim", type=int) + parser.add_argument("--attention-conv-kernel-size", type=int) + parser.add_argument("--prenet-dropout", type=float) + parser.add_argument("--prenet-layers", type=int) + parser.add_argument("--prenet-dim", type=int) + parser.add_argument("--postnet-dropout", type=float) + parser.add_argument("--postnet-layers", type=int) + parser.add_argument("--postnet-conv-dim", type=int) + parser.add_argument("--postnet-conv-kernel-size", type=int) + parser.add_argument("--init-attn-c", type=str) + parser.add_argument("--attention-use-cumprob", action='store_true') + parser.add_argument("--zoneout", type=float) + parser.add_argument("--decoder-lstm-layers", type=int) + parser.add_argument("--decoder-lstm-dim", type=int) + parser.add_argument("--output-frame-dim", type=int) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._num_updates = 0 + + @classmethod + def build_model(cls, args, task): + embed_speaker = task.get_speaker_embeddings(args) + encoder = Tacotron2Encoder(args, task.src_dict, embed_speaker) + decoder = Tacotron2Decoder(args, task.src_dict) + return cls(encoder, decoder) + + def forward_encoder(self, src_tokens, src_lengths, **kwargs): + return self.encoder(src_tokens, src_lengths=src_lengths, **kwargs) + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + self._num_updates = num_updates + + +@register_model_architecture("tacotron_2", "tacotron_2") +def base_architecture(args): + # encoder + args.encoder_dropout = getattr(args, "encoder_dropout", 0.5) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_conv_layers = getattr(args, "encoder_conv_layers", 3) + args.encoder_conv_kernel_size = getattr(args, "encoder_conv_kernel_size", 5) + args.encoder_lstm_layers = getattr(args, "encoder_lstm_layers", 1) + # decoder + args.attention_dim = getattr(args, "attention_dim", 128) + args.attention_conv_dim = getattr(args, "attention_conv_dim", 32) + args.attention_conv_kernel_size = getattr(args, + "attention_conv_kernel_size", 15) + args.prenet_dropout = getattr(args, "prenet_dropout", 0.5) + args.prenet_layers = getattr(args, "prenet_layers", 2) + args.prenet_dim = getattr(args, "prenet_dim", 256) + args.postnet_dropout = getattr(args, "postnet_dropout", 0.5) + args.postnet_layers = getattr(args, "postnet_layers", 5) + args.postnet_conv_dim = getattr(args, "postnet_conv_dim", 512) + args.postnet_conv_kernel_size = getattr(args, "postnet_conv_kernel_size", 5) + args.init_attn_c = getattr(args, "init_attn_c", "zero") + args.attention_use_cumprob = getattr(args, "attention_use_cumprob", True) + args.zoneout = getattr(args, "zoneout", 0.1) + args.decoder_lstm_layers = getattr(args, "decoder_lstm_layers", 2) + args.decoder_lstm_dim = getattr(args, "decoder_lstm_dim", 1024) + args.output_frame_dim = getattr(args, "output_frame_dim", 80) diff --git a/fairseq/models/text_to_speech/tts_transformer.py b/fairseq/models/text_to_speech/tts_transformer.py new file mode 100644 index 0000000000..ff7af78bd4 --- /dev/null +++ b/fairseq/models/text_to_speech/tts_transformer.py @@ -0,0 +1,371 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import List, Optional + +import torch +from torch import nn + +from fairseq.models import (FairseqEncoder, FairseqEncoderDecoderModel, + FairseqIncrementalDecoder, register_model, + register_model_architecture) +from fairseq.modules import ( + TransformerEncoderLayer, TransformerDecoderLayer +) +from fairseq.models.text_to_speech.tacotron2 import Prenet, Postnet +from fairseq.modules import LayerNorm, PositionalEmbedding, FairseqDropout +from fairseq.data.data_utils import lengths_to_padding_mask +from fairseq import utils + +logger = logging.getLogger(__name__) + + +def encoder_init(m): + if isinstance(m, nn.Conv1d): + nn.init.xavier_uniform_(m.weight, torch.nn.init.calculate_gain("relu")) + + +def Embedding(num_embeddings, embedding_dim): + m = nn.Embedding(num_embeddings, embedding_dim) + nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + return m + + +class TTSTransformerEncoder(FairseqEncoder): + def __init__(self, args, src_dict, embed_speaker): + super().__init__(src_dict) + self.padding_idx = src_dict.pad() + self.embed_speaker = embed_speaker + self.spk_emb_proj = None + if embed_speaker is not None: + self.spk_emb_proj = nn.Linear( + args.encoder_embed_dim + args.speaker_embed_dim, + args.encoder_embed_dim + ) + + self.dropout_module = FairseqDropout( + p=args.dropout, module_name=self.__class__.__name__ + ) + self.embed_tokens = nn.Embedding(len(src_dict), args.encoder_embed_dim, + padding_idx=self.padding_idx) + assert(args.encoder_conv_kernel_size % 2 == 1) + self.prenet = nn.ModuleList( + nn.Sequential( + nn.Conv1d(args.encoder_embed_dim, args.encoder_embed_dim, + kernel_size=args.encoder_conv_kernel_size, + padding=((args.encoder_conv_kernel_size - 1) // 2)), + nn.BatchNorm1d(args.encoder_embed_dim), + nn.ReLU(), + nn.Dropout(args.encoder_dropout), + ) + for _ in range(args.encoder_conv_layers) + ) + self.prenet_proj = nn.Linear( + args.encoder_embed_dim, args.encoder_embed_dim + ) + self.embed_positions = PositionalEmbedding( + args.max_source_positions, args.encoder_embed_dim, self.padding_idx + ) + self.pos_emb_alpha = nn.Parameter(torch.ones(1)) + + self.transformer_layers = nn.ModuleList( + TransformerEncoderLayer(args) + for _ in range(args.encoder_transformer_layers) + ) + if args.encoder_normalize_before: + self.layer_norm = LayerNorm(args.encoder_embed_dim) + else: + self.layer_norm = None + + self.apply(encoder_init) + + def forward(self, src_tokens, src_lengths=None, speaker=None, **kwargs): + x = self.embed_tokens(src_tokens) + x = x.transpose(1, 2).contiguous() # B x T x C -> B x C x T + for conv in self.prenet: + x = conv(x) + x = x.transpose(1, 2).contiguous() # B x C x T -> B x T x C + x = self.prenet_proj(x) + + padding_mask = src_tokens.eq(self.padding_idx) + positions = self.embed_positions(padding_mask) + x += self.pos_emb_alpha * positions + x = self.dropout_module(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + for layer in self.transformer_layers: + x = layer(x, padding_mask) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + if self.embed_speaker is not None: + seq_len, bsz, _ = x.size() + emb = self.embed_speaker(speaker).transpose(0, 1) + emb = emb.expand(seq_len, bsz, -1) + x = self.spk_emb_proj(torch.cat([x, emb], dim=2)) + + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [padding_mask] if padding_mask.any() else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": [], # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + + +def decoder_init(m): + if isinstance(m, torch.nn.Conv1d): + nn.init.xavier_uniform_(m.weight, torch.nn.init.calculate_gain("tanh")) + + +class TTSTransformerDecoder(FairseqIncrementalDecoder): + def __init__(self, args, src_dict): + super().__init__(None) + self._future_mask = torch.empty(0) + + self.args = args + self.padding_idx = src_dict.pad() + self.n_frames_per_step = args.n_frames_per_step + self.out_dim = args.output_frame_dim * args.n_frames_per_step + + self.dropout_module = FairseqDropout( + args.dropout, module_name=self.__class__.__name__ + ) + self.embed_positions = PositionalEmbedding( + args.max_target_positions, args.decoder_embed_dim, self.padding_idx + ) + self.pos_emb_alpha = nn.Parameter(torch.ones(1)) + self.prenet = nn.Sequential( + Prenet(self.out_dim, args.prenet_layers, args.prenet_dim, + args.prenet_dropout), + nn.Linear(args.prenet_dim, args.decoder_embed_dim), + ) + + self.n_transformer_layers = args.decoder_transformer_layers + self.transformer_layers = nn.ModuleList( + TransformerDecoderLayer(args) + for _ in range(self.n_transformer_layers) + ) + if args.decoder_normalize_before: + self.layer_norm = LayerNorm(args.decoder_embed_dim) + else: + self.layer_norm = None + + self.feat_proj = nn.Linear(args.decoder_embed_dim, self.out_dim) + self.eos_proj = nn.Linear(args.decoder_embed_dim, 1) + + self.postnet = Postnet(self.out_dim, args.postnet_conv_dim, + args.postnet_conv_kernel_size, + args.postnet_layers, args.postnet_dropout) + + self.ctc_proj = None + if getattr(args, "ctc_weight", 0.) > 0.: + self.ctc_proj = nn.Linear(self.out_dim, len(src_dict)) + + self.apply(decoder_init) + + def extract_features( + self, prev_outputs, encoder_out=None, incremental_state=None, + target_lengths=None, speaker=None, **kwargs + ): + alignment_layer = self.n_transformer_layers - 1 + self_attn_padding_mask = lengths_to_padding_mask(target_lengths) + positions = self.embed_positions( + self_attn_padding_mask, incremental_state=incremental_state + ) + + if incremental_state is not None: + prev_outputs = prev_outputs[:, -1:, :] + self_attn_padding_mask = self_attn_padding_mask[:, -1:] + if positions is not None: + positions = positions[:, -1:] + + x = self.prenet(prev_outputs) + x += self.pos_emb_alpha * positions + x = self.dropout_module(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + if not self_attn_padding_mask.any(): + self_attn_padding_mask = None + + attn: Optional[torch.Tensor] = None + inner_states: List[Optional[torch.Tensor]] = [x] + for idx, transformer_layer in enumerate(self.transformer_layers): + if incremental_state is None: + self_attn_mask = self.buffered_future_mask(x) + else: + self_attn_mask = None + + x, layer_attn, _ = transformer_layer( + x, + encoder_out["encoder_out"][0] + if (encoder_out is not None and len(encoder_out["encoder_out"]) > 0) + else None, + encoder_out["encoder_padding_mask"][0] + if ( + encoder_out is not None + and len(encoder_out["encoder_padding_mask"]) > 0 + ) + else None, + incremental_state, + self_attn_mask=self_attn_mask, + self_attn_padding_mask=self_attn_padding_mask, + need_attn=bool((idx == alignment_layer)), + need_head_weights=bool((idx == alignment_layer)), + ) + inner_states.append(x) + if layer_attn is not None and idx == alignment_layer: + attn = layer_attn.float().to(x) + + if attn is not None: + # average probabilities over heads, transpose to + # (B, src_len, tgt_len) + attn = attn.mean(dim=0).transpose(2, 1) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + return x, {"attn": attn, "inner_states": inner_states} + + def forward(self, prev_output_tokens, encoder_out=None, + incremental_state=None, target_lengths=None, speaker=None, + **kwargs): + x, extra = self.extract_features( + prev_output_tokens, encoder_out=encoder_out, + incremental_state=incremental_state, target_lengths=target_lengths, + speaker=speaker, **kwargs + ) + attn = extra["attn"] + feat_out = self.feat_proj(x) + bsz, seq_len, _ = x.size() + eos_out = self.eos_proj(x) + post_feat_out = feat_out + self.postnet(feat_out) + return post_feat_out, eos_out, {"attn": attn, "feature_out": feat_out} + + def get_normalized_probs(self, net_output, log_probs, sample): + logits = self.ctc_proj(net_output[2]["feature_out"]) + if log_probs: + return utils.log_softmax(logits.float(), dim=-1) + else: + return utils.softmax(logits.float(), dim=-1) + + def buffered_future_mask(self, tensor): + dim = tensor.size(0) + # self._future_mask.device != tensor.device is not working in TorchScript. This is a workaround. + if ( + self._future_mask.size(0) == 0 + or (not self._future_mask.device == tensor.device) + or self._future_mask.size(0) < dim + ): + self._future_mask = torch.triu( + utils.fill_with_neg_inf(torch.zeros([dim, dim])), 1 + ) + self._future_mask = self._future_mask.to(tensor) + return self._future_mask[:dim, :dim] + + +@register_model("tts_transformer") +class TTSTransformerModel(FairseqEncoderDecoderModel): + """ + Implementation for https://arxiv.org/pdf/1809.08895.pdf + """ + + @staticmethod + def add_args(parser): + parser.add_argument("--dropout", type=float) + parser.add_argument("--output-frame-dim", type=int) + parser.add_argument("--speaker-embed-dim", type=int) + # encoder prenet + parser.add_argument("--encoder-dropout", type=float) + parser.add_argument("--encoder-conv-layers", type=int) + parser.add_argument("--encoder-conv-kernel-size", type=int) + # encoder transformer layers + parser.add_argument("--encoder-transformer-layers", type=int) + parser.add_argument("--encoder-embed-dim", type=int) + parser.add_argument("--encoder-ffn-embed-dim", type=int) + parser.add_argument("--encoder-normalize-before", action="store_true") + parser.add_argument("--encoder-attention-heads", type=int) + parser.add_argument("--attention-dropout", type=float) + parser.add_argument("--activation-dropout", "--relu-dropout", type=float) + parser.add_argument("--activation-fn", type=str, default="relu") + # decoder prenet + parser.add_argument("--prenet-dropout", type=float) + parser.add_argument("--prenet-layers", type=int) + parser.add_argument("--prenet-dim", type=int) + # decoder postnet + parser.add_argument("--postnet-dropout", type=float) + parser.add_argument("--postnet-layers", type=int) + parser.add_argument("--postnet-conv-dim", type=int) + parser.add_argument("--postnet-conv-kernel-size", type=int) + # decoder transformer layers + parser.add_argument("--decoder-transformer-layers", type=int) + parser.add_argument("--decoder-embed-dim", type=int) + parser.add_argument("--decoder-ffn-embed-dim", type=int) + parser.add_argument("--decoder-normalize-before", action="store_true") + parser.add_argument("--decoder-attention-heads", type=int) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._num_updates = 0 + + @classmethod + def build_model(cls, args, task): + embed_speaker = task.get_speaker_embeddings(args) + encoder = TTSTransformerEncoder(args, task.src_dict, embed_speaker) + decoder = TTSTransformerDecoder(args, task.src_dict) + return cls(encoder, decoder) + + def forward_encoder(self, src_tokens, src_lengths, speaker=None, **kwargs): + return self.encoder(src_tokens, src_lengths=src_lengths, + speaker=speaker, **kwargs) + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + self._num_updates = num_updates + + +@register_model_architecture("tts_transformer", "tts_transformer") +def base_architecture(args): + args.dropout = getattr(args, "dropout", 0.1) + args.output_frame_dim = getattr(args, "output_frame_dim", 80) + args.speaker_embed_dim = getattr(args, "speaker_embed_dim", 64) + # encoder prenet + args.encoder_dropout = getattr(args, "encoder_dropout", 0.5) + args.encoder_conv_layers = getattr(args, "encoder_conv_layers", 3) + args.encoder_conv_kernel_size = getattr(args, "encoder_conv_kernel_size", 5) + # encoder transformer layers + args.encoder_transformer_layers = getattr(args, "encoder_transformer_layers", 6) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4 * args.encoder_embed_dim) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.attention_dropout = getattr(args, "attention_dropout", 0.0) + args.activation_dropout = getattr(args, "activation_dropout", 0.0) + args.activation_fn = getattr(args, "activation_fn", "relu") + # decoder prenet + args.prenet_dropout = getattr(args, "prenet_dropout", 0.5) + args.prenet_layers = getattr(args, "prenet_layers", 2) + args.prenet_dim = getattr(args, "prenet_dim", 256) + # decoder postnet + args.postnet_dropout = getattr(args, "postnet_dropout", 0.5) + args.postnet_layers = getattr(args, "postnet_layers", 5) + args.postnet_conv_dim = getattr(args, "postnet_conv_dim", 512) + args.postnet_conv_kernel_size = getattr(args, "postnet_conv_kernel_size", 5) + # decoder transformer layers + args.decoder_transformer_layers = getattr(args, "decoder_transformer_layers", 6) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4 * args.decoder_embed_dim) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py new file mode 100644 index 0000000000..65d9f9f06b --- /dev/null +++ b/fairseq/models/text_to_speech/vocoder.py @@ -0,0 +1,197 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import json +from typing import Dict + +import numpy as np +import torch +from torch import nn +import torch.nn.functional as F + +from fairseq.data.audio.audio_utils import ( + get_window, get_fourier_basis, get_mel_filters, TTSSpectrogram +) +from fairseq.data.audio.speech_to_text_dataset import S2TDataConfig +from fairseq.models.text_to_speech.hifigan import Generator as HiFiGANModel + +logger = logging.getLogger(__name__) + + +class PseudoInverseMelScale(torch.nn.Module): + def __init__(self, n_stft, n_mels, sample_rate, f_min, f_max) -> None: + super(PseudoInverseMelScale, self).__init__() + self.n_mels = n_mels + basis = get_mel_filters( + sample_rate, (n_stft - 1) * 2, n_mels, f_min, f_max + ) + basis = torch.pinverse(basis) # F x F_mel + self.register_buffer('basis', basis) + + def forward(self, melspec: torch.Tensor) -> torch.Tensor: + # pack batch + shape = melspec.shape # B_1 x ... x B_K x F_mel x T + n_mels, time = shape[-2], shape[-1] + melspec = melspec.view(-1, n_mels, time) + + freq, _ = self.basis.size() # F x F_mel + assert self.n_mels == n_mels, (self.n_mels, n_mels) + specgram = self.basis.matmul(melspec).clamp(min=0) + + # unpack batch + specgram = specgram.view(shape[:-2] + (freq, time)) + return specgram + + +class GriffinLim(torch.nn.Module): + def __init__( + self, n_fft: int, win_length: int, hop_length: int, n_iter: int, + window_fn=torch.hann_window + ): + super(GriffinLim, self).__init__() + self.transform = TTSSpectrogram( + n_fft, win_length, hop_length, return_phase=True + ) + + basis = get_fourier_basis(n_fft) + basis = torch.pinverse(n_fft / hop_length * basis).T[:, None, :] + basis *= get_window(window_fn, n_fft, win_length) + self.register_buffer('basis', basis) + + self.n_fft = n_fft + self.win_length = win_length + self.hop_length = hop_length + self.n_iter = n_iter + + self.tiny = 1.1754944e-38 + + @classmethod + def get_window_sum_square( + cls, n_frames, hop_length, win_length, n_fft, + window_fn=torch.hann_window + ) -> torch.Tensor: + w_sq = get_window(window_fn, n_fft, win_length) ** 2 + n = n_fft + hop_length * (n_frames - 1) + x = torch.zeros(n, dtype=torch.float32) + for i in range(n_frames): + ofst = i * hop_length + x[ofst: min(n, ofst + n_fft)] += w_sq[:max(0, min(n_fft, n - ofst))] + return x + + def inverse(self, magnitude: torch.Tensor, phase) -> torch.Tensor: + x = torch.cat( + [magnitude * torch.cos(phase), magnitude * torch.sin(phase)], + dim=1 + ) + x = F.conv_transpose1d(x, self.basis, stride=self.hop_length) + win_sum_sq = self.get_window_sum_square( + magnitude.shape[-1], hop_length=self.hop_length, + win_length=self.win_length, n_fft=self.n_fft + ).to(magnitude.device) + # remove modulation effects + approx_nonzero_indices = win_sum_sq > self.tiny + x[:, :, approx_nonzero_indices] /= win_sum_sq[approx_nonzero_indices] + x *= self.n_fft / self.hop_length + x = x[:, :, self.n_fft // 2:] + x = x[:, :, :-self.n_fft // 2:] + return x + + def forward(self, specgram: torch.Tensor) -> torch.Tensor: + angles = np.angle(np.exp(2j * np.pi * np.random.rand(*specgram.shape))) + angles = torch.from_numpy(angles).to(specgram) + _specgram = specgram.view(-1, specgram.shape[-2], specgram.shape[-1]) + waveform = self.inverse(_specgram, angles).squeeze(1) + for _ in range(self.n_iter): + _, angles = self.transform(waveform) + waveform = self.inverse(_specgram, angles).squeeze(1) + return waveform.squeeze(0) + + +class GriffinLimVocoder(nn.Module): + def __init__(self, sample_rate, win_size, hop_size, n_fft, + n_mels, f_min, f_max, window_fn, + spec_bwd_max_iter=32, + fp16=False): + super().__init__() + self.inv_mel_transform = PseudoInverseMelScale( + n_stft=n_fft // 2 + 1, n_mels=n_mels, sample_rate=sample_rate, + f_min=f_min, f_max=f_max + ) + self.gl_transform = GriffinLim( + n_fft=n_fft, win_length=win_size, hop_length=hop_size, + window_fn=window_fn, n_iter=spec_bwd_max_iter + ) + if fp16: + self.half() + self.inv_mel_transform.half() + self.gl_transform.half() + else: + self.float() + self.inv_mel_transform.float() + self.gl_transform.float() + + def forward(self, x): + # x: (B x) T x D -> (B x) 1 x T + # NOTE: batched forward produces noisier waveform. recommend running + # one utterance at a time + self.eval() + x = x.exp().transpose(-1, -2) + x = self.inv_mel_transform(x) + x = self.gl_transform(x) + return x + + @classmethod + def from_data_cfg(cls, args, data_cfg: S2TDataConfig): + feat_cfg = data_cfg.config["features"] + window_fn = getattr(torch, feat_cfg["window_fn"] + "_window") + return cls( + sample_rate=feat_cfg["sample_rate"], + win_size=int(feat_cfg["win_len_t"] * feat_cfg["sample_rate"]), + hop_size=int(feat_cfg["hop_len_t"] * feat_cfg["sample_rate"]), + n_fft=feat_cfg["n_fft"], n_mels=feat_cfg["n_mels"], + f_min=feat_cfg["f_min"], f_max=feat_cfg["f_max"], + window_fn=window_fn, spec_bwd_max_iter=args.spec_bwd_max_iter, + fp16=args.fp16 + ) + + +class HiFiGANVocoder(nn.Module): + def __init__( + self, checkpoint_path: str, model_cfg: Dict[str, str], + fp16: bool = False + ) -> None: + super().__init__() + self.model = HiFiGANModel(model_cfg) + state_dict = torch.load(checkpoint_path) + self.model.load_state_dict(state_dict["generator"]) + if fp16: + self.model.half() + logger.info(f"loaded HiFiGAN checkpoint from {checkpoint_path}") + + def forward(self, x: torch.Tensor) -> torch.Tensor: + # (B x) T x D -> (B x) 1 x T + model = self.model.eval() + if len(x.shape) == 2: + return model(x.unsqueeze(0).transpose(1, 2)).detach().squeeze(0) + else: + return model(x.transpose(-1, -2)).detach() + + @classmethod + def from_data_cfg(cls, args, data_cfg: S2TDataConfig): + vocoder_cfg = data_cfg.vocoder + assert vocoder_cfg.get("type", "griffin_lim") == "hifigan" + with open(vocoder_cfg["config"]) as f: + model_cfg = json.load(f) + return cls(vocoder_cfg["checkpoint"], model_cfg, fp16=args.fp16) + + +def get_vocoder(args, data_cfg: S2TDataConfig): + if args.vocoder == "griffin_lim": + return GriffinLimVocoder.from_data_cfg(args, data_cfg) + elif args.vocoder == "hifigan": + return HiFiGANVocoder.from_data_cfg(args, data_cfg) + else: + raise ValueError("Unknown vocoder") diff --git a/fairseq/modules/__init__.py b/fairseq/modules/__init__.py index 81930aa71c..d7a030e2b5 100644 --- a/fairseq/modules/__init__.py +++ b/fairseq/modules/__init__.py @@ -25,6 +25,8 @@ from .learned_positional_embedding import LearnedPositionalEmbedding from .lightweight_convolution import LightweightConv, LightweightConv1dTBC from .linearized_convolution import LinearizedConvolution +from .location_attention import LocationAttention +from .lstm_cell_with_zoneout import LSTMCellWithZoneOut from .multihead_attention import MultiheadAttention from .positional_embedding import PositionalEmbedding from .same_pad import SamePad @@ -63,6 +65,8 @@ "LightweightConv1dTBC", "LightweightConv", "LinearizedConvolution", + "LocationAttention", + "LSTMCellWithZoneOut", "MultiheadAttention", "PositionalEmbedding", "SamePad", diff --git a/fairseq/modules/location_attention.py b/fairseq/modules/location_attention.py new file mode 100644 index 0000000000..a970876bba --- /dev/null +++ b/fairseq/modules/location_attention.py @@ -0,0 +1,72 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch.nn as nn +import torch +import torch.nn.functional as F + + +class LocationAttention(nn.Module): + """ + Attention-Based Models for Speech Recognition + https://arxiv.org/pdf/1506.07503.pdf + + :param int encoder_dim: # projection-units of encoder + :param int decoder_dim: # units of decoder + :param int attn_dim: attention dimension + :param int conv_dim: # channels of attention convolution + :param int conv_kernel_size: filter size of attention convolution + """ + + def __init__(self, attn_dim, encoder_dim, decoder_dim, + attn_state_kernel_size, conv_dim, conv_kernel_size, + scaling=2.0): + super(LocationAttention, self).__init__() + self.attn_dim = attn_dim + self.decoder_dim = decoder_dim + self.scaling = scaling + self.proj_enc = nn.Linear(encoder_dim, attn_dim) + self.proj_dec = nn.Linear(decoder_dim, attn_dim, bias=False) + self.proj_attn = nn.Linear(conv_dim, attn_dim, bias=False) + self.conv = nn.Conv1d(attn_state_kernel_size, conv_dim, + 2 * conv_kernel_size + 1, + padding=conv_kernel_size, bias=False) + self.proj_out = nn.Sequential(nn.Tanh(), nn.Linear(attn_dim, 1)) + + self.proj_enc_out = None # cache + + def clear_cache(self): + self.proj_enc_out = None + + def forward(self, encoder_out, encoder_padding_mask, decoder_h, attn_state): + """ + :param torch.Tensor encoder_out: padded encoder hidden state B x T x D + :param torch.Tensor encoder_padding_mask: encoder padding mask + :param torch.Tensor decoder_h: decoder hidden state B x D + :param torch.Tensor attn_prev: previous attention weight B x K x T + :return: attention weighted encoder state (B, D) + :rtype: torch.Tensor + :return: previous attention weights (B x T) + :rtype: torch.Tensor + """ + bsz, seq_len, _ = encoder_out.size() + if self.proj_enc_out is None: + self.proj_enc_out = self.proj_enc(encoder_out) + + # B x K x T -> B x C x T + attn = self.conv(attn_state) + # B x C x T -> B x T x C -> B x T x D + attn = self.proj_attn(attn.transpose(1, 2)) + + if decoder_h is None: + decoder_h = encoder_out.new_zeros(bsz, self.decoder_dim) + dec_h = self.proj_dec(decoder_h).view(bsz, 1, self.attn_dim) + + out = self.proj_out(attn + self.proj_enc_out + dec_h).squeeze(2) + out.masked_fill_(encoder_padding_mask, -float("inf")) + + w = F.softmax(self.scaling * out, dim=1) + c = torch.sum(encoder_out * w.view(bsz, seq_len, 1), dim=1) + return c, w diff --git a/fairseq/modules/lstm_cell_with_zoneout.py b/fairseq/modules/lstm_cell_with_zoneout.py new file mode 100644 index 0000000000..f04e5db255 --- /dev/null +++ b/fairseq/modules/lstm_cell_with_zoneout.py @@ -0,0 +1,37 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch.nn as nn + + +class LSTMCellWithZoneOut(nn.Module): + """ + Zoneout: Regularizing RNNs by Randomly Preserving Hidden Activations + https://arxiv.org/abs/1606.01305 + """ + + def __init__(self, prob: float, input_size: int, hidden_size: int, + bias: bool = True): + super(LSTMCellWithZoneOut, self).__init__() + self.lstm_cell = nn.LSTMCell(input_size, hidden_size, bias=bias) + self.prob = prob + if prob > 1.0 or prob < 0.0: + raise ValueError("zoneout probability must be in the range from " + "0.0 to 1.0.") + + def zoneout(self, h, next_h, prob): + if isinstance(h, tuple): + return tuple( + [self.zoneout(h[i], next_h[i], prob) for i in range(len(h))] + ) + + if self.training: + mask = h.new_zeros(*h.size()).bernoulli_(prob) + return mask * h + (1 - mask) * next_h + + return prob * h + (1 - prob) * next_h + + def forward(self, x, h): + return self.zoneout(h, self.lstm_cell(x, h), self.prob) diff --git a/fairseq/optim/lr_scheduler/step_lr_scheduler.py b/fairseq/optim/lr_scheduler/step_lr_scheduler.py new file mode 100644 index 0000000000..8cb2006860 --- /dev/null +++ b/fairseq/optim/lr_scheduler/step_lr_scheduler.py @@ -0,0 +1,86 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from collections.abc import Collection +from dataclasses import dataclass, field +from typing import List + +from omegaconf import II + +from fairseq.dataclass import FairseqDataclass +from fairseq.optim.lr_scheduler import FairseqLRScheduler, register_lr_scheduler + + +@dataclass +class StepLRScheduleConfig(FairseqDataclass): + warmup_updates: int = field( + default=0, + metadata={"help": "warmup the learning rate linearly for the first N updates"}, + ) + warmup_init_lr: float = field( + default=-1, + metadata={ + "help": "initial learning rate during warmup phase; default is cfg.lr" + }, + ) + lr: List[float] = field( + default=II("optimization.lr"), + metadata={"help": "max learning rate, must be more than cfg.min_lr"}, + ) + min_lr: float = field(default=0.0, metadata={"help": "min learning rate"}) + lr_deacy_period: int = field(default=25000, metadata={"help": "decay period"}) + lr_decay: float = field(default=0.5, metadata={"help": "decay factor"}) + + +@register_lr_scheduler("step", dataclass=StepLRScheduleConfig) +class StepLRSchedule(FairseqLRScheduler): + """Decay learning rate every k updates by a fixed factor + """ + + def __init__(self, cfg: StepLRScheduleConfig, fairseq_optimizer): + super().__init__(cfg, fairseq_optimizer) + self.max_lr = cfg.lr[0] if isinstance(cfg.lr, Collection) else cfg.lr + self.min_lr = cfg.min_lr + self.lr_deacy_period = cfg.lr_deacy_period + self.lr_decay = cfg.lr_decay + self.warmup_updates = cfg.warmup_updates + self.warmup_init_lr = ( + cfg.warmup_init_lr if cfg.warmup_init_lr >= 0 else self.min_lr + ) + + assert(self.lr_deacy_period > 0) + assert(self.lr_decay <= 1) + assert(self.min_lr >= 0) + assert(self.max_lr > self.min_lr) + + if cfg.warmup_updates > 0: + # linearly warmup for the first cfg.warmup_updates + self.warmup_lr_step = ( + (self.max_lr - self.warmup_init_lr) / self.warmup_updates + ) + else: + self.warmup_lr_step = 1 + + # initial learning rate + self.lr = self.warmup_init_lr + self.optimizer.set_lr(self.lr) + + def step(self, epoch, val_loss=None): + """Update the learning rate at the end of the given epoch.""" + super().step(epoch, val_loss) + # we don't change the learning rate at epoch boundaries + return self.optimizer.get_lr() + + def step_update(self, num_updates): + """Update the learning rate after each update.""" + if num_updates < self.cfg.warmup_updates: + self.lr = self.warmup_init_lr + num_updates * self.warmup_lr_step + else: + curr_updates = num_updates - self.cfg.warmup_updates + lr_mult = self.lr_decay ** (curr_updates // self.lr_deacy_period) + self.lr = max(self.max_lr * lr_mult, self.min_lr) + + self.optimizer.set_lr(self.lr) + return self.lr diff --git a/fairseq/options.py b/fairseq/options.py index 03883fc561..b4d350f902 100644 --- a/fairseq/options.py +++ b/fairseq/options.py @@ -56,6 +56,14 @@ def get_generation_parser(interactive=False, default_task="translation"): return parser +def get_speech_generation_parser(default_task="text_to_speech"): + parser = get_parser("Speech Generation", default_task) + add_dataset_args(parser, gen=True) + add_distributed_training_args(parser, default_world_size=1) + add_speech_generation_args(parser) + return parser + + def get_interactive_generation_parser(default_task="translation"): return get_generation_parser(interactive=True, default_task=default_task) @@ -344,6 +352,16 @@ def add_generation_args(parser): return group +def add_speech_generation_args(parser): + group = parser.add_argument_group("Speech Generation") + add_common_eval_args(group) # NOTE: remove_bpe is not needed + # fmt: off + group.add_argument('--eos_prob_threshold', default=0.5, type=float, + help='terminate when eos probability exceeds this') + # fmt: on + return group + + def add_interactive_args(parser): group = parser.add_argument_group("Interactive") gen_parser_from_dataclass(group, InteractiveConfig()) diff --git a/fairseq/speech_generator.py b/fairseq/speech_generator.py new file mode 100644 index 0000000000..8086e34d2b --- /dev/null +++ b/fairseq/speech_generator.py @@ -0,0 +1,219 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import numpy as np + +from fairseq.data.audio.speech_to_text_dataset import S2TDataConfig + + +class SpeechGenerator(object): + def __init__(self, model, vocoder, data_cfg: S2TDataConfig): + self.model = model + self.vocoder = vocoder + stats_npz_path = data_cfg.global_cmvn_stats_npz + self.gcmvn_stats = None + if stats_npz_path is not None: + self.gcmvn_stats = np.load(stats_npz_path) + + def gcmvn_denormalize(self, x): + # x: B x T x C + if self.gcmvn_stats is None: + return x + mean = torch.from_numpy(self.gcmvn_stats["mean"]).to(x) + std = torch.from_numpy(self.gcmvn_stats["std"]).to(x) + assert len(x.shape) == 3 and mean.shape[0] == std.shape[0] == x.shape[2] + x = x * std.view(1, 1, -1).expand_as(x) + return x + mean.view(1, 1, -1).expand_as(x) + + def get_waveform(self, feat): + # T x C -> T + return None if self.vocoder is None else self.vocoder(feat).squeeze(0) + + +class AutoRegressiveSpeechGenerator(SpeechGenerator): + def __init__( + self, model, vocoder, data_cfg, max_iter: int = 6000, + eos_prob_threshold: float = 0.5, + ): + super().__init__(model, vocoder, data_cfg) + self.max_iter = max_iter + self.eos_prob_threshold = eos_prob_threshold + + @torch.no_grad() + def generate(self, model, sample, has_targ=False, **kwargs): + model.eval() + + src_tokens = sample["net_input"]["src_tokens"] + src_lengths = sample["net_input"]["src_lengths"] + bsz, src_len = src_tokens.size() + n_frames_per_step = model.decoder.n_frames_per_step + out_dim = model.decoder.out_dim + raw_dim = out_dim // n_frames_per_step + + # initialize + encoder_out = model.forward_encoder(src_tokens, src_lengths, + speaker=sample["speaker"]) + incremental_state = {} + feat, attn, eos_prob = [], [], [] + finished = src_tokens.new_zeros((bsz,)).bool() + out_lens = src_lengths.new_zeros((bsz,)).long().fill_(self.max_iter) + + prev_feat_out = encoder_out["encoder_out"][0].new_zeros(bsz, 1, out_dim) + for step in range(self.max_iter): + cur_out_lens = out_lens.clone() + cur_out_lens.masked_fill_(cur_out_lens.eq(self.max_iter), step + 1) + _, cur_eos_out, cur_extra = model.forward_decoder( + prev_feat_out, encoder_out=encoder_out, + incremental_state=incremental_state, + target_lengths=cur_out_lens, speaker=sample["speaker"], **kwargs + ) + cur_eos_prob = torch.sigmoid(cur_eos_out).squeeze(2) + feat.append(cur_extra['feature_out']) + attn.append(cur_extra['attn']) + eos_prob.append(cur_eos_prob) + + cur_finished = (cur_eos_prob.squeeze(1) > self.eos_prob_threshold) + out_lens.masked_fill_((~finished) & cur_finished, step + 1) + finished = finished | cur_finished + if finished.sum().item() == bsz: + break + prev_feat_out = cur_extra['feature_out'] + + feat = torch.cat(feat, dim=1) + feat = model.decoder.postnet(feat) + feat + eos_prob = torch.cat(eos_prob, dim=1) + attn = torch.cat(attn, dim=2) + alignment = attn.max(dim=1)[1] + + feat = feat.reshape(bsz, -1, raw_dim) + feat = self.gcmvn_denormalize(feat) + + eos_prob = eos_prob.repeat_interleave(n_frames_per_step, dim=1) + attn = attn.repeat_interleave(n_frames_per_step, dim=2) + alignment = alignment.repeat_interleave(n_frames_per_step, dim=1) + out_lens = out_lens * n_frames_per_step + + finalized = [ + { + 'feature': feat[b, :out_len], + 'eos_prob': eos_prob[b, :out_len], + 'attn': attn[b, :, :out_len], + 'alignment': alignment[b, :out_len], + 'waveform': self.get_waveform(feat[b, :out_len]), + } + for b, out_len in zip(range(bsz), out_lens) + ] + + if has_targ: + assert sample["target"].size(-1) == out_dim + tgt_feats = sample["target"].view(bsz, -1, raw_dim) + tgt_feats = self.gcmvn_denormalize(tgt_feats) + tgt_lens = sample["target_lengths"] * n_frames_per_step + for b, (f, l) in enumerate(zip(tgt_feats, tgt_lens)): + finalized[b]["targ_feature"] = f[:l] + finalized[b]["targ_waveform"] = self.get_waveform(f[:l]) + return finalized + + +class NonAutoregressiveSpeechGenerator(SpeechGenerator): + @torch.no_grad() + def generate(self, model, sample, has_targ=False, **kwargs): + model.eval() + + bsz, max_src_len = sample["net_input"]["src_tokens"].size() + n_frames_per_step = model.encoder.n_frames_per_step + out_dim = model.encoder.out_dim + raw_dim = out_dim // n_frames_per_step + + feat, out_lens, log_dur_out, _, _ = model( + src_tokens=sample["net_input"]["src_tokens"], + src_lengths=sample["net_input"]["src_lengths"], + prev_output_tokens=sample["net_input"]["prev_output_tokens"], + incremental_state=None, + target_lengths=sample["target_lengths"], + speaker=sample["speaker"] + ) + + feat = feat.view(bsz, -1, raw_dim) + feat = self.gcmvn_denormalize(feat) + + dur_out = torch.clamp( + torch.round(torch.exp(log_dur_out) - 1).long(), min=0 + ) + + def get_dur_plot_data(d): + r = [] + for i, dd in enumerate(d): + r += [i + 1] * dd.item() + return r + + out_lens = out_lens * n_frames_per_step + finalized = [ + { + 'feature': feat[b, :l] if l > 0 else feat.new_zeros([1, raw_dim]), + 'waveform': self.get_waveform( + feat[b, :l] if l > 0 else feat.new_zeros([1, raw_dim]) + ), + 'attn': feat.new_tensor(get_dur_plot_data(dur_out[b])), + } + for b, l in zip(range(bsz), out_lens) + ] + + if has_targ: + tgt_feats = sample["target"].view(bsz, -1, raw_dim) + tgt_feats = self.gcmvn_denormalize(tgt_feats) + tgt_lens = sample["target_lengths"] * n_frames_per_step + for b, (f, l) in enumerate(zip(tgt_feats, tgt_lens)): + finalized[b]["targ_feature"] = f[:l] + finalized[b]["targ_waveform"] = self.get_waveform(f[:l]) + return finalized + + +class TeacherForcingAutoRegressiveSpeechGenerator(AutoRegressiveSpeechGenerator): + @torch.no_grad() + def generate(self, model, sample, has_targ=False, **kwargs): + model.eval() + + src_tokens = sample["net_input"]["src_tokens"] + src_lens = sample["net_input"]["src_lengths"] + prev_out_tokens = sample["net_input"]["prev_output_tokens"] + tgt_lens = sample["target_lengths"] + n_frames_per_step = model.decoder.n_frames_per_step + raw_dim = model.decoder.out_dim // n_frames_per_step + bsz = src_tokens.shape[0] + + feat, eos_prob, extra = model( + src_tokens, src_lens, prev_out_tokens, incremental_state=None, + target_lengths=tgt_lens, speaker=sample["speaker"] + ) + + attn = extra["attn"] # B x T_s x T_t + alignment = attn.max(dim=1)[1] + feat = feat.reshape(bsz, -1, raw_dim) + feat = self.gcmvn_denormalize(feat) + eos_prob = eos_prob.repeat_interleave(n_frames_per_step, dim=1) + attn = attn.repeat_interleave(n_frames_per_step, dim=2) + alignment = alignment.repeat_interleave(n_frames_per_step, dim=1) + tgt_lens = sample["target_lengths"] * n_frames_per_step + + finalized = [ + { + 'feature': feat[b, :tgt_len], + 'eos_prob': eos_prob[b, :tgt_len], + 'attn': attn[b, :, :tgt_len], + 'alignment': alignment[b, :tgt_len], + 'waveform': self.get_waveform(feat[b, :tgt_len]), + } + for b, tgt_len in zip(range(bsz), tgt_lens) + ] + + if has_targ: + tgt_feats = sample["target"].view(bsz, -1, raw_dim) + tgt_feats = self.gcmvn_denormalize(tgt_feats) + for b, (f, l) in enumerate(zip(tgt_feats, tgt_lens)): + finalized[b]["targ_feature"] = f[:l] + finalized[b]["targ_waveform"] = self.get_waveform(f[:l]) + return finalized diff --git a/fairseq/tasks/frm_text_to_speech.py b/fairseq/tasks/frm_text_to_speech.py new file mode 100644 index 0000000000..1fa9b0f83e --- /dev/null +++ b/fairseq/tasks/frm_text_to_speech.py @@ -0,0 +1,56 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +from fairseq.data.audio.frm_text_to_speech_dataset import FrmTextToSpeechDatasetCreator +from fairseq.tasks import register_task +from fairseq.tasks.text_to_speech import TextToSpeechTask + + +logging.basicConfig( + format='%(asctime)s | %(levelname)s | %(name)s | %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', level=logging.INFO +) +logger = logging.getLogger(__name__) + + +@register_task('frm_text_to_speech') +class FrmTextToSpeechTask(TextToSpeechTask): + @staticmethod + def add_args(parser): + TextToSpeechTask.add_args(parser) + parser.add_argument( + "--do_chunk", action="store_true", help="train on chunks" + ) + parser.add_argument("--chunk_bound", default=-1, type=int) + parser.add_argument("--chunk_init", default=50, type=int) + parser.add_argument("--chunk_incr", default=5, type=int) + parser.add_argument("--add_eos", action="store_true") + parser.add_argument("--dedup", action="store_true") + parser.add_argument("--ref_fpu", default=-1, type=float) + + def load_dataset(self, split, **unused_kwargs): + is_train_split = split.startswith("train") + pre_tokenizer = self.build_tokenizer(self.args) + bpe_tokenizer = self.build_bpe(self.args) + self.datasets[split] = FrmTextToSpeechDatasetCreator.from_tsv( + self.args.data, + self.data_cfg, + split, + self.src_dict, + pre_tokenizer, + bpe_tokenizer, + is_train_split=is_train_split, + n_frames_per_step=self.args.n_frames_per_step, + speaker_to_id=self.speaker_to_id, + do_chunk=self.args.do_chunk, + chunk_bound=self.args.chunk_bound, + chunk_init=self.args.chunk_init, + chunk_incr=self.args.chunk_incr, + add_eos=self.args.add_eos, + dedup=self.args.dedup, + ref_fpu=self.args.ref_fpu + ) diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 5795c04bf7..06e292103e 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -50,6 +50,16 @@ def __init__(self, args, tgt_dict): super().__init__(args) self.tgt_dict = tgt_dict self.data_cfg = S2TDataConfig(Path(args.data) / args.config_yaml) + self.speaker_to_id = self._get_speaker_to_id() + + def _get_speaker_to_id(self): + speaker_to_id = None + speaker_set_filename = self.data_cfg.config.get("speaker_set_filename") + if speaker_set_filename is not None: + speaker_set_path = Path(self.args.data) / speaker_set_filename + with open(speaker_set_path) as f: + speaker_to_id = {r.strip(): i for i, r in enumerate(f)} + return speaker_to_id @classmethod def setup_task(cls, args, **kwargs): @@ -91,6 +101,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): is_train_split=is_train_split, epoch=epoch, seed=self.args.seed, + speaker_to_id=self.speaker_to_id ) @property @@ -107,6 +118,7 @@ def max_positions(self): def build_model(self, args): args.input_feat_per_channel = self.data_cfg.input_feat_per_channel args.input_channels = self.data_cfg.input_channels + args.speaker_to_id = self.speaker_to_id return super(SpeechToTextTask, self).build_model(args) def build_generator( @@ -126,12 +138,13 @@ def build_generator( for s, i in self.tgt_dict.indices.items() if SpeechToTextDataset.is_lang_tag(s) } + if extra_gen_cls_kwargs is None: - extra_gen_cls_kwargs = {"symbols_to_strip_from_output": lang_token_ids} - else: - extra_gen_cls_kwargs["symbols_to_strip_from_output"] = lang_token_ids + extra_gen_cls_kwargs = {} + extra_gen_cls_kwargs["symbols_to_strip_from_output"] = lang_token_ids return super().build_generator( - models, args, seq_gen_cls=None, extra_gen_cls_kwargs=extra_gen_cls_kwargs + models, args, seq_gen_cls=None, + extra_gen_cls_kwargs=extra_gen_cls_kwargs ) def build_tokenizer(self, args): diff --git a/fairseq/tasks/text_to_speech.py b/fairseq/tasks/text_to_speech.py new file mode 100644 index 0000000000..5646e41d39 --- /dev/null +++ b/fairseq/tasks/text_to_speech.py @@ -0,0 +1,467 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import os.path as op + +import torch +import torch.nn.functional as F +import numpy as np + +from fairseq.data.audio.text_to_speech_dataset import TextToSpeechDatasetCreator +from fairseq.tasks import register_task +from fairseq.tasks.speech_to_text import SpeechToTextTask +from fairseq.speech_generator import ( + AutoRegressiveSpeechGenerator, NonAutoregressiveSpeechGenerator, + TeacherForcingAutoRegressiveSpeechGenerator +) + +logging.basicConfig( + format='%(asctime)s | %(levelname)s | %(name)s | %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', level=logging.INFO +) +logger = logging.getLogger(__name__) + + +try: + from tensorboardX import SummaryWriter +except ImportError: + logger.info("Please install tensorboardX: pip install tensorboardX") + SummaryWriter = None + + +@register_task('text_to_speech') +class TextToSpeechTask(SpeechToTextTask): + @staticmethod + def add_args(parser): + parser.add_argument('data', help='manifest root path') + parser.add_argument( + '--config-yaml', type=str, default='config.yaml', + help='Configuration YAML filename (under manifest root)' + ) + parser.add_argument('--max-source-positions', default=1024, type=int, + metavar='N', + help='max number of tokens in the source sequence') + parser.add_argument('--max-target-positions', default=1200, type=int, + metavar='N', + help='max number of tokens in the target sequence') + parser.add_argument("--n-frames-per-step", type=int, default=1) + parser.add_argument("--eos-prob-threshold", type=float, default=0.5) + parser.add_argument("--eval-inference", action="store_true") + parser.add_argument("--eval-tb-nsample", type=int, default=8) + parser.add_argument("--vocoder", type=str, default="griffin_lim") + parser.add_argument("--spec-bwd-max-iter", type=int, default=8) + + def __init__(self, args, src_dict): + super().__init__(args, src_dict) + self.src_dict = src_dict + self.sr = self.data_cfg.config.get("features").get("sample_rate") + + self.tensorboard_writer = None + self.tensorboard_dir = "" + if args.tensorboard_logdir and SummaryWriter is not None: + self.tensorboard_dir = os.path.join(args.tensorboard_logdir, + "valid_extra") + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + is_train_split = split.startswith('train') + pre_tokenizer = self.build_tokenizer(self.args) + bpe_tokenizer = self.build_bpe(self.args) + self.datasets[split] = TextToSpeechDatasetCreator.from_tsv( + self.args.data, self.data_cfg, split, self.src_dict, + pre_tokenizer, bpe_tokenizer, is_train_split=is_train_split, + epoch=epoch, seed=self.args.seed, + n_frames_per_step=self.args.n_frames_per_step, + speaker_to_id=self.speaker_to_id + ) + + @property + def target_dictionary(self): + return None + + @property + def source_dictionary(self): + return self.src_dict + + def get_speaker_embeddings_path(self): + speaker_emb_path = None + if self.data_cfg.config.get("speaker_emb_filename") is not None: + speaker_emb_path = op.join( + self.args.data, self.data_cfg.config.get("speaker_emb_filename") + ) + return speaker_emb_path + + @classmethod + def get_speaker_embeddings(cls, args): + embed_speaker = None + if args.speaker_to_id is not None: + if args.speaker_emb_path is None: + embed_speaker = torch.nn.Embedding( + len(args.speaker_to_id), args.speaker_embed_dim + ) + else: + speaker_emb_mat = np.load(args.speaker_emb_path) + assert speaker_emb_mat.shape[1] == args.speaker_embed_dim + embed_speaker = torch.nn.Embedding.from_pretrained( + torch.from_numpy(speaker_emb_mat), freeze=True, + ) + logger.info( + f"load speaker embeddings from {args.speaker_emb_path}. " + f"train embedding? {embed_speaker.weight.requires_grad}\n" + f"embeddings:\n{speaker_emb_mat}" + ) + return embed_speaker + + def build_model(self, cfg): + cfg.pitch_min = self.data_cfg.config["features"].get("pitch_min", None) + cfg.pitch_max = self.data_cfg.config["features"].get("pitch_max", None) + cfg.energy_min = self.data_cfg.config["features"].get("energy_min", None) + cfg.energy_max = self.data_cfg.config["features"].get("energy_max", None) + cfg.speaker_emb_path = self.get_speaker_embeddings_path() + model = super().build_model(cfg) + self.generator = None + if getattr(cfg, "eval_inference", False): + self.generator = self.build_generator([model], cfg) + return model + + def build_generator(self, models, cfg, vocoder=None, **unused): + if vocoder is None: + vocoder = self.build_default_vocoder() + model = models[0] + if getattr(model, "NON_AUTOREGRESSIVE", False): + return NonAutoregressiveSpeechGenerator( + model, vocoder, self.data_cfg + ) + else: + generator = AutoRegressiveSpeechGenerator + if getattr(cfg, "teacher_forcing", False): + generator = TeacherForcingAutoRegressiveSpeechGenerator + logger.info("Teacher forcing mode for generation") + return generator( + model, vocoder, self.data_cfg, + max_iter=self.args.max_target_positions, + eos_prob_threshold=self.args.eos_prob_threshold + ) + + def build_default_vocoder(self): + from fairseq.models.text_to_speech.vocoder import get_vocoder + vocoder = get_vocoder(self.args, self.data_cfg) + if torch.cuda.is_available() and not self.args.cpu: + vocoder = vocoder.cuda() + else: + vocoder = vocoder.cpu() + return vocoder + + def valid_step(self, sample, model, criterion): + loss, sample_size, logging_output = super().valid_step( + sample, model, criterion + ) + + if getattr(self.args, "eval_inference", False): + hypos, inference_losses = self.valid_step_with_inference( + sample, model, self.generator + ) + for k, v in inference_losses.items(): + assert(k not in logging_output) + logging_output[k] = v + + picked_id = 0 + if self.tensorboard_dir and (sample["id"] == picked_id).any(): + self.log_tensorboard( + sample, + hypos[:self.args.eval_tb_nsample], + model._num_updates, + is_na_model=getattr(model, "NON_AUTOREGRESSIVE", False) + ) + return loss, sample_size, logging_output + + def valid_step_with_inference(self, sample, model, generator): + hypos = generator.generate(model, sample, has_targ=True) + + losses = { + "mcd_loss": 0., + "targ_frames": 0., + "pred_frames": 0., + "nins": 0., + "ndel": 0., + } + rets = batch_mel_cepstral_distortion( + [hypo["targ_waveform"] for hypo in hypos], + [hypo["waveform"] for hypo in hypos], + self.sr, + normalize_type=None + ) + for d, extra in rets: + pathmap = extra[-1] + losses["mcd_loss"] += d.item() + losses["targ_frames"] += pathmap.size(0) + losses["pred_frames"] += pathmap.size(1) + losses["nins"] += (pathmap.sum(dim=1) - 1).sum().item() + losses["ndel"] += (pathmap.sum(dim=0) - 1).sum().item() + + return hypos, losses + + def log_tensorboard(self, sample, hypos, num_updates, is_na_model=False): + if self.tensorboard_writer is None: + self.tensorboard_writer = SummaryWriter(self.tensorboard_dir) + tb_writer = self.tensorboard_writer + for b in range(len(hypos)): + idx = sample["id"][b] + text = sample["src_texts"][b] + targ = hypos[b]["targ_feature"] + pred = hypos[b]["feature"] + attn = hypos[b]["attn"] + + if is_na_model: + data = plot_tts_output( + [targ.transpose(0, 1), pred.transpose(0, 1)], + [f"target (idx={idx})", "output"], attn, + "alignment", ret_np=True, suptitle=text, + ) + else: + eos_prob = hypos[b]["eos_prob"] + data = plot_tts_output( + [targ.transpose(0, 1), pred.transpose(0, 1), attn], + [f"target (idx={idx})", "output", "alignment"], eos_prob, + "eos prob", ret_np=True, suptitle=text, + ) + + tb_writer.add_image( + f"inference_sample_{b}", data, num_updates, + dataformats="HWC" + ) + + if hypos[b]["waveform"] is not None: + targ_wave = hypos[b]["targ_waveform"].detach().cpu().float() + pred_wave = hypos[b]["waveform"].detach().cpu().float() + tb_writer.add_audio( + f"inference_targ_{b}", + targ_wave, + num_updates, + sample_rate=self.sr + ) + tb_writer.add_audio( + f"inference_pred_{b}", + pred_wave, + num_updates, + sample_rate=self.sr + ) + + +def save_figure_to_numpy(fig): + data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='') + data = data.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + return data + + +DEFAULT_V_MIN = np.log(1e-5) + + +def plot_tts_output( + data_2d, title_2d, data_1d, title_1d, figsize=(24, 4), + v_min=DEFAULT_V_MIN, v_max=3, ret_np=False, suptitle="" +): + try: + import matplotlib.pyplot as plt + from mpl_toolkits.axes_grid1 import make_axes_locatable + except ImportError: + raise ImportError("Please install Matplotlib: pip install matplotlib") + + data_2d = [ + x.detach().cpu().float().numpy() + if isinstance(x, torch.Tensor) else x for x in data_2d + ] + fig, axes = plt.subplots(1, len(data_2d) + 1, figsize=figsize) + if suptitle: + fig.suptitle(suptitle[:400]) # capped at 400 chars + axes = [axes] if len(data_2d) == 0 else axes + for ax, x, name in zip(axes, data_2d, title_2d): + ax.set_title(name) + divider = make_axes_locatable(ax) + cax = divider.append_axes('right', size='5%', pad=0.05) + im = ax.imshow( + x, origin="lower", aspect="auto", vmin=max(x.min(), v_min), + vmax=min(x.max(), v_max) + ) + fig.colorbar(im, cax=cax, orientation='vertical') + + if isinstance(data_1d, torch.Tensor): + data_1d = data_1d.detach().cpu().numpy() + axes[-1].plot(data_1d) + axes[-1].set_title(title_1d) + plt.tight_layout() + + if ret_np: + fig.canvas.draw() + data = save_figure_to_numpy(fig) + plt.close(fig) + return data + + +def antidiag_indices(offset, min_i=0, max_i=None, min_j=0, max_j=None): + """ + for a (3, 4) matrix with min_i=1, max_i=3, min_j=1, max_j=4, outputs + + offset=2 (1, 1), + offset=3 (2, 1), (1, 2) + offset=4 (2, 2), (1, 3) + offset=5 (2, 3) + + constraints: + i + j = offset + min_j <= j < max_j + min_i <= offset - j < max_i + """ + if max_i is None: + max_i = offset + 1 + if max_j is None: + max_j = offset + 1 + min_j = max(min_j, offset - max_i + 1, 0) + max_j = min(max_j, offset - min_i + 1, offset + 1) + j = torch.arange(min_j, max_j) + i = offset - j + return torch.stack([i, j]) + + +def batch_dynamic_time_warping(distance, shapes=None): + """full batched DTW without any constraints + + distance: (batchsize, max_M, max_N) matrix + shapes: (batchsize,) vector specifying (M, N) for each entry + """ + # ptr: 0=left, 1=up-left, 2=up + ptr2dij = {0: (0, -1), 1: (-1, -1), 2: (-1, 0)} + + bsz, m, n = distance.size() + cumdist = torch.zeros_like(distance) + backptr = torch.zeros_like(distance).type(torch.int32) - 1 + + # initialize + cumdist[:, 0, :] = distance[:, 0, :].cumsum(dim=-1) + cumdist[:, :, 0] = distance[:, :, 0].cumsum(dim=-1) + backptr[:, 0, :] = 0 + backptr[:, :, 0] = 2 + + # DP with optimized anti-diagonal parallelization, O(M+N) steps + for offset in range(2, m + n - 1): + ind = antidiag_indices(offset, 1, m, 1, n) + c = torch.stack( + [cumdist[:, ind[0], ind[1] - 1], cumdist[:, ind[0] - 1, ind[1] - 1], + cumdist[:, ind[0] - 1, ind[1]], ], + dim=2 + ) + v, b = c.min(axis=-1) + backptr[:, ind[0], ind[1]] = b.int() + cumdist[:, ind[0], ind[1]] = v + distance[:, ind[0], ind[1]] + + # backtrace + pathmap = torch.zeros_like(backptr) + for b in range(bsz): + i = m - 1 if shapes is None else (shapes[b][0] - 1).item() + j = n - 1 if shapes is None else (shapes[b][1] - 1).item() + dtwpath = [(i, j)] + while (i != 0 or j != 0) and len(dtwpath) < 10000: + assert (i >= 0 and j >= 0) + di, dj = ptr2dij[backptr[b, i, j].item()] + i, j = i + di, j + dj + dtwpath.append((i, j)) + dtwpath = dtwpath[::-1] + indices = torch.from_numpy(np.array(dtwpath)) + pathmap[b, indices[:, 0], indices[:, 1]] = 1 + + return cumdist, backptr, pathmap + + +def compute_l2_dist(x1, x2): + """compute an (m, n) L2 distance matrix from (m, d) and (n, d) matrices""" + return torch.cdist(x1.unsqueeze(0), x2.unsqueeze(0), p=2).squeeze(0).pow(2) + + +def compute_rms_dist(x1, x2): + l2_dist = compute_l2_dist(x1, x2) + return (l2_dist / x1.size(1)).pow(0.5) + + +def get_divisor(pathmap, normalize_type): + if normalize_type is None: + return 1 + elif normalize_type == "len1": + return pathmap.size(0) + elif normalize_type == "len2": + return pathmap.size(1) + elif normalize_type == "path": + return pathmap.sum().item() + else: + raise ValueError(f"normalize_type {normalize_type} not supported") + + +def batch_compute_distortion(y1, y2, sr, feat_fn, dist_fn, normalize_type): + d, s, x1, x2 = [], [], [], [] + for cur_y1, cur_y2 in zip(y1, y2): + assert (cur_y1.ndim == 1 and cur_y2.ndim == 1) + cur_x1 = feat_fn(cur_y1) + cur_x2 = feat_fn(cur_y2) + x1.append(cur_x1) + x2.append(cur_x2) + + cur_d = dist_fn(cur_x1, cur_x2) + d.append(cur_d) + s.append(d[-1].size()) + max_m = max(ss[0] for ss in s) + max_n = max(ss[1] for ss in s) + d = torch.stack( + [F.pad(dd, (0, max_n - dd.size(1), 0, max_m - dd.size(0))) for dd in d] + ) + s = torch.LongTensor(s).to(d.device) + cumdists, backptrs, pathmaps = batch_dynamic_time_warping(d, s) + + rets = [] + itr = zip(s, x1, x2, d, cumdists, backptrs, pathmaps) + for (m, n), cur_x1, cur_x2, dist, cumdist, backptr, pathmap in itr: + cumdist = cumdist[:m, :n] + backptr = backptr[:m, :n] + pathmap = pathmap[:m, :n] + divisor = get_divisor(pathmap, normalize_type) + + distortion = cumdist[-1, -1] / divisor + ret = distortion, (cur_x1, cur_x2, dist, cumdist, backptr, pathmap) + rets.append(ret) + return rets + + +def batch_mel_cepstral_distortion( + y1, y2, sr, normalize_type="path", mfcc_fn=None +): + """ + https://arxiv.org/pdf/2011.03568.pdf + + The root mean squared error computed on 13-dimensional MFCC using DTW for + alignment. MFCC features are computed from an 80-channel log-mel + spectrogram using a 50ms Hann window and hop of 12.5ms. + + y1: list of waveforms + y2: list of waveforms + sr: sampling rate + """ + + try: + import torchaudio + except ImportError: + raise ImportError("Please install torchaudio: pip install torchaudio") + + if mfcc_fn is None or mfcc_fn.sample_rate != sr: + melkwargs = { + "n_fft": int(0.05 * sr), "win_length": int(0.05 * sr), + "hop_length": int(0.0125 * sr), "f_min": 20, + "n_mels": 80, "window_fn": torch.hann_window + } + mfcc_fn = torchaudio.transforms.MFCC( + sr, n_mfcc=13, log_mels=True, melkwargs=melkwargs + ).to(y1[0].device) + return batch_compute_distortion( + y1, y2, sr, lambda y: mfcc_fn(y).transpose(-1, -2), compute_rms_dist, + normalize_type + ) diff --git a/setup.py b/setup.py index c699936a99..1f3998de80 100644 --- a/setup.py +++ b/setup.py @@ -210,6 +210,7 @@ def do_setup(package_data): "torch", "tqdm", "bitarray", + "torchaudio>=0.8.0", ], dependency_links=dependency_links, packages=find_packages( From 8adff65ab30dd5f3a3589315bbc1fafad52943e7 Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Tue, 14 Sep 2021 21:42:39 -0700 Subject: [PATCH 458/774] Use batch_by_size in dataset in aligned training task Summary: Aligned training was not using batch_by_size in the dataset. Due to this, it was not possible to use batch sampling in MultiCorpusDataset with different transforms and collators for different datasets. Reviewed By: xiaoxiao26 Differential Revision: D30889985 fbshipit-source-id: 224ad55d2337681a06a82caf19900e5a241a3d6a --- fairseq/data/multi_corpus_dataset.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index 1bd61c32eb..746155e515 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -170,7 +170,12 @@ def collater(self, samples): return None if "full_id" in samples[0]: _, key = self._map_index(samples[0]["full_id"]) - return self.datasets[key].collater(samples) + try: + batch = self.datasets[key].collater(samples) + except Exception: + print(f"Collating failed for key {key}", flush=True) + raise + return batch else: # Subclasses may override __getitem__ to not specify full_id return list(self.datasets.values())[0].collater(samples) From 98d638c70cdbe751153c10fc571c34beac228347 Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Wed, 15 Sep 2021 01:48:57 -0700 Subject: [PATCH 459/774] Mma refactor (#2087) Summary: Fixing issues ([3546](https://github.com/pytorch/fairseq/issues/3546)) with latency augmented training for mma due to the change of fairseq APIs Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2087 Reviewed By: hygong-fb Differential Revision: D29851286 Pulled By: xutaima fbshipit-source-id: 6c3077db06b89c23b312b28527d7395a725f3b3a --- .../models/transformer_monotonic_attention.py | 4 + .../modules/monotonic_multihead_attention.py | 4 +- .../utils/data_utils.py | 100 ---- .../utils/functions.py | 5 +- .../simultaneous_translation/utils/latency.py | 451 ------------------ .../utils/monotonic_attention.py | 2 + ...moothed_cross_entropy_latency_augmented.py | 275 ++++++++--- fairseq/modules/transformer_layer.py | 5 +- 8 files changed, 215 insertions(+), 631 deletions(-) delete mode 100644 examples/simultaneous_translation/utils/data_utils.py delete mode 100644 examples/simultaneous_translation/utils/latency.py diff --git a/examples/simultaneous_translation/models/transformer_monotonic_attention.py b/examples/simultaneous_translation/models/transformer_monotonic_attention.py index b0cdc43483..7b9414b0eb 100644 --- a/examples/simultaneous_translation/models/transformer_monotonic_attention.py +++ b/examples/simultaneous_translation/models/transformer_monotonic_attention.py @@ -100,6 +100,10 @@ def __init__(self, args, dictionary, embed_tokens, no_encoder_attn=False): ] ) self.policy_criterion = getattr(args, "policy_criterion", "any") + self.num_updates = None + + def set_num_updates(self, num_updates): + self.num_updates = num_updates def pre_attention( self, diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index 2b8a48b1de..11ef60c945 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -131,7 +131,7 @@ def energy_from_qk( return energy - def p_choose_from_qk(self, query, key, key_padding_mask): + def p_choose_from_qk(self, query, key, key_padding_mask, incremental_states=None): monotonic_energy = self.energy_from_qk( query, key, @@ -148,7 +148,7 @@ def p_choose_from_qk(self, query, key, key_padding_mask): ) return p_choose - def p_choose(self, query, key, key_padding_mask): + def p_choose(self, query, key, key_padding_mask, incremental_states=None): return self.p_choose_from_qk(self, query, key, key_padding_mask) def monotonic_attention_process_infer( diff --git a/examples/simultaneous_translation/utils/data_utils.py b/examples/simultaneous_translation/utils/data_utils.py deleted file mode 100644 index a763ea6686..0000000000 --- a/examples/simultaneous_translation/utils/data_utils.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import torch - - -def calc_mean_invstddev(feature): - if len(feature.size()) != 2: - raise ValueError("We expect the input feature to be 2-D tensor") - mean = feature.mean(0) - var = feature.var(0) - # avoid division by ~zero - eps = 1e-8 - if (var < eps).any(): - return mean, 1.0 / (torch.sqrt(var) + eps) - return mean, 1.0 / torch.sqrt(var) - - -def apply_mv_norm(features): - # If there is less than 2 spectrograms, the variance cannot be computed (is NaN) - # and normalization is not possible, so return the item as it is - if features.size(0) < 2: - return features - mean, invstddev = calc_mean_invstddev(features) - res = (features - mean) * invstddev - return res - - -def lengths_to_encoder_padding_mask(lengths, batch_first: bool = False): - """ - convert lengths (a 1-D Long/Int tensor) to 2-D binary tensor - - Args: - lengths: a (B, )-shaped tensor - - Return: - max_length: maximum length of B sequences - encoder_padding_mask: a (max_length, B) binary mask, where - [t, b] = 0 for t < lengths[b] and 1 otherwise - - TODO: - kernelize this function if benchmarking shows this function is slow - """ - max_lengths = torch.max(lengths).item() - bsz = lengths.size(0) - encoder_padding_mask = torch.arange( - max_lengths - ).to( # a (T, ) tensor with [0, ..., T-1] - lengths.device - ).view( # move to the right device - 1, max_lengths - ).expand( # reshape to (1, T)-shaped tensor - bsz, -1 - ) >= lengths.view( # expand to (B, T)-shaped tensor - bsz, 1 - ).expand( - -1, max_lengths - ) - if not batch_first: - return encoder_padding_mask.t(), max_lengths - else: - return encoder_padding_mask, max_lengths - - -def encoder_padding_mask_to_lengths( - encoder_padding_mask, max_lengths, batch_size, device -): - """ - convert encoder_padding_mask (2-D binary tensor) to a 1-D tensor - - Conventionally, encoder output contains a encoder_padding_mask, which is - a 2-D mask in a shape (T, B), whose (t, b) element indicate whether - encoder_out[t, b] is a valid output (=0) or not (=1). Occasionally, we - need to convert this mask tensor to a 1-D tensor in shape (B, ), where - [b] denotes the valid length of b-th sequence - - Args: - encoder_padding_mask: a (T, B)-shaped binary tensor or None; if None, - indicating all are valid - Return: - seq_lengths: a (B,)-shaped tensor, where its (b, )-th element is the - number of valid elements of b-th sequence - - max_lengths: maximum length of all sequence, if encoder_padding_mask is - not None, max_lengths must equal to encoder_padding_mask.size(0) - - batch_size: batch size; if encoder_padding_mask is - not None, max_lengths must equal to encoder_padding_mask.size(1) - - device: which device to put the result on - """ - if encoder_padding_mask is None: - return torch.Tensor([max_lengths] * batch_size).to(torch.int32).to(device) - - assert encoder_padding_mask.size(0) == max_lengths, "max_lengths does not match" - assert encoder_padding_mask.size(1) == batch_size, "batch_size does not match" - - return max_lengths - torch.sum(encoder_padding_mask, dim=0) diff --git a/examples/simultaneous_translation/utils/functions.py b/examples/simultaneous_translation/utils/functions.py index 0ced35a9d5..590a6c11ce 100644 --- a/examples/simultaneous_translation/utils/functions.py +++ b/examples/simultaneous_translation/utils/functions.py @@ -6,11 +6,12 @@ import torch -def prob_check(tensor): +def prob_check(tensor, eps=1e-10): assert not torch.isnan(tensor).any(), ( "Nan in a probability tensor." ) - assert tensor.le(1.0).all() and tensor.ge(0.0).all(), ( + # Add the eps here to prevent errors introduced by precision + assert tensor.le(1.0 + eps).all() and tensor.ge(0.0 - eps).all(), ( "Incorrect values in a probability tensor" ", 0.0 <= tensor <= 1.0" ) diff --git a/examples/simultaneous_translation/utils/latency.py b/examples/simultaneous_translation/utils/latency.py deleted file mode 100644 index 5d800a5d9e..0000000000 --- a/examples/simultaneous_translation/utils/latency.py +++ /dev/null @@ -1,451 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import torch - - -class LatencyMetric(object): - @staticmethod - def length_from_padding_mask(padding_mask, batch_first: bool = False): - dim = 1 if batch_first else 0 - return padding_mask.size(dim) - padding_mask.sum(dim=dim, keepdim=True) - - def prepare_latency_metric( - self, - delays, - src_lens, - target_padding_mask=None, - batch_first: bool = False, - start_from_zero: bool = True, - ): - assert len(delays.size()) == 2 - assert len(src_lens.size()) == 2 - - if start_from_zero: - delays = delays + 1 - - if batch_first: - # convert to batch_last - delays = delays.t() - src_lens = src_lens.t() - tgt_len, bsz = delays.size() - _, bsz_1 = src_lens.size() - - if target_padding_mask is not None: - target_padding_mask = target_padding_mask.t() - tgt_len_1, bsz_2 = target_padding_mask.size() - assert tgt_len == tgt_len_1 - assert bsz == bsz_2 - - assert bsz == bsz_1 - - if target_padding_mask is None: - tgt_lens = tgt_len * delays.new_ones([1, bsz]).float() - else: - # 1, batch_size - tgt_lens = self.length_from_padding_mask(target_padding_mask, False).float() - delays = delays.masked_fill(target_padding_mask, 0) - - return delays, src_lens, tgt_lens, target_padding_mask - - def __call__( - self, - delays, - src_lens, - target_padding_mask=None, - batch_first: bool = False, - start_from_zero: bool = True, - ): - delays, src_lens, tgt_lens, target_padding_mask = self.prepare_latency_metric( - delays, src_lens, target_padding_mask, batch_first, start_from_zero - ) - return self.cal_metric(delays, src_lens, tgt_lens, target_padding_mask) - - @staticmethod - def cal_metric(delays, src_lens, tgt_lens, target_padding_mask): - """ - Expected sizes: - delays: tgt_len, batch_size - src_lens: 1, batch_size - target_padding_mask: tgt_len, batch_size - """ - raise NotImplementedError - - -class AverageProportion(LatencyMetric): - """ - Function to calculate Average Proportion from - Can neural machine translation do simultaneous translation? - (https://arxiv.org/abs/1606.02012) - - Delays are monotonic steps, range from 1 to src_len. - Give src x tgt y, AP is calculated as: - - AP = 1 / (|x||y]) sum_i^|Y| deleys_i - """ - - @staticmethod - def cal_metric(delays, src_lens, tgt_lens, target_padding_mask): - if target_padding_mask is not None: - AP = torch.sum( - delays.masked_fill(target_padding_mask, 0), dim=0, keepdim=True - ) - else: - AP = torch.sum(delays, dim=0, keepdim=True) - - AP = AP / (src_lens * tgt_lens) - return AP - - -class AverageLagging(LatencyMetric): - """ - Function to calculate Average Lagging from - STACL: Simultaneous Translation with Implicit Anticipation - and Controllable Latency using Prefix-to-Prefix Framework - (https://arxiv.org/abs/1810.08398) - - Delays are monotonic steps, range from 1 to src_len. - Give src x tgt y, AP is calculated as: - - AL = 1 / tau sum_i^tau delays_i - (i - 1) / gamma - - Where - gamma = |y| / |x| - tau = argmin_i(delays_i = |x|) - """ - - @staticmethod - def cal_metric(delays, src_lens, tgt_lens, target_padding_mask): - # tau = argmin_i(delays_i = |x|) - tgt_len, bsz = delays.size() - lagging_padding_mask = delays >= src_lens - lagging_padding_mask = torch.nn.functional.pad( - lagging_padding_mask.t(), (1, 0) - ).t()[:-1, :] - gamma = tgt_lens / src_lens - lagging = ( - delays - - torch.arange(delays.size(0)) - .unsqueeze(1) - .type_as(delays) - .expand_as(delays) - / gamma - ) - lagging.masked_fill_(lagging_padding_mask, 0) - tau = (1 - lagging_padding_mask.type_as(lagging)).sum(dim=0, keepdim=True) - AL = lagging.sum(dim=0, keepdim=True) / tau - - return AL - - -class DifferentiableAverageLagging(LatencyMetric): - """ - Function to calculate Differentiable Average Lagging from - Monotonic Infinite Lookback Attention for Simultaneous Machine Translation - (https://arxiv.org/abs/1906.05218) - - Delays are monotonic steps, range from 0 to src_len-1. - (In the original paper thery are from 1 to src_len) - Give src x tgt y, AP is calculated as: - - DAL = 1 / |Y| sum_i^|Y| delays'_i - (i - 1) / gamma - - Where - delays'_i = - 1. delays_i if i == 1 - 2. max(delays_i, delays'_{i-1} + 1 / gamma) - - """ - - @staticmethod - def cal_metric(delays, src_lens, tgt_lens, target_padding_mask): - tgt_len, bsz = delays.size() - - gamma = tgt_lens / src_lens - new_delays = torch.zeros_like(delays) - - for i in range(delays.size(0)): - if i == 0: - new_delays[i] = delays[i] - else: - new_delays[i] = torch.cat( - [ - new_delays[i - 1].unsqueeze(0) + 1 / gamma, - delays[i].unsqueeze(0), - ], - dim=0, - ).max(dim=0)[0] - - DAL = ( - new_delays - - torch.arange(delays.size(0)) - .unsqueeze(1) - .type_as(delays) - .expand_as(delays) - / gamma - ) - if target_padding_mask is not None: - DAL = DAL.masked_fill(target_padding_mask, 0) - - DAL = DAL.sum(dim=0, keepdim=True) / tgt_lens - - return DAL - - -class LatencyMetricVariance(LatencyMetric): - def prepare_latency_metric( - self, - delays, - src_lens, - target_padding_mask=None, - batch_first: bool = True, - start_from_zero: bool = True, - ): - assert batch_first - assert len(delays.size()) == 3 - assert len(src_lens.size()) == 2 - - if start_from_zero: - delays = delays + 1 - - # convert to batch_last - bsz, num_heads_x_layers, tgt_len = delays.size() - bsz_1, _ = src_lens.size() - assert bsz == bsz_1 - - if target_padding_mask is not None: - bsz_2, tgt_len_1 = target_padding_mask.size() - assert tgt_len == tgt_len_1 - assert bsz == bsz_2 - - if target_padding_mask is None: - tgt_lens = tgt_len * delays.new_ones([bsz, tgt_len]).float() - else: - # batch_size, 1 - tgt_lens = self.length_from_padding_mask(target_padding_mask, True).float() - delays = delays.masked_fill(target_padding_mask.unsqueeze(1), 0) - - return delays, src_lens, tgt_lens, target_padding_mask - - -class VarianceDelay(LatencyMetricVariance): - @staticmethod - def cal_metric(delays, src_lens, tgt_lens, target_padding_mask): - """ - delays : bsz, num_heads_x_layers, tgt_len - src_lens : bsz, 1 - target_lens : bsz, 1 - target_padding_mask: bsz, tgt_len or None - """ - if delays.size(1) == 1: - return delays.new_zeros([1]) - - variance_delays = delays.var(dim=1) - - if target_padding_mask is not None: - variance_delays.masked_fill_(target_padding_mask, 0) - - return variance_delays.sum(dim=1, keepdim=True) / tgt_lens - - -class LatencyInference(object): - def __init__(self, start_from_zero=True): - self.metric_calculator = { - "differentiable_average_lagging": DifferentiableAverageLagging(), - "average_lagging": AverageLagging(), - "average_proportion": AverageProportion(), - } - - self.start_from_zero = start_from_zero - - def __call__(self, monotonic_step, src_lens): - """ - monotonic_step range from 0 to src_len. src_len means eos - delays: bsz, tgt_len - src_lens: bsz, 1 - """ - if not self.start_from_zero: - monotonic_step -= 1 - - src_lens = src_lens - - delays = monotonic_step.view( - monotonic_step.size(0), -1, monotonic_step.size(-1) - ).max(dim=1)[0] - - delays = delays.masked_fill(delays >= src_lens, 0) + (src_lens - 1).expand_as( - delays - ).masked_fill(delays < src_lens, 0) - return_dict = {} - for key, func in self.metric_calculator.items(): - return_dict[key] = func( - delays.float(), - src_lens.float(), - target_padding_mask=None, - batch_first=True, - start_from_zero=True, - ).t() - - return return_dict - - -class LatencyTraining(object): - def __init__( - self, - avg_weight, - var_weight, - avg_type, - var_type, - stay_on_last_token, - average_method, - ): - self.avg_weight = avg_weight - self.var_weight = var_weight - self.avg_type = avg_type - self.var_type = var_type - self.stay_on_last_token = stay_on_last_token - self.average_method = average_method - - self.metric_calculator = { - "differentiable_average_lagging": DifferentiableAverageLagging(), - "average_lagging": AverageLagging(), - "average_proportion": AverageProportion(), - } - - self.variance_calculator = { - "variance_delay": VarianceDelay(), - } - - def expected_delays_from_attention( - self, attention, source_padding_mask=None, target_padding_mask=None - ): - if type(attention) == list: - # bsz, num_heads, tgt_len, src_len - bsz, num_heads, tgt_len, src_len = attention[0].size() - attention = torch.cat(attention, dim=1) - bsz, num_heads_x_layers, tgt_len, src_len = attention.size() - # bsz * num_heads * num_layers, tgt_len, src_len - attention = attention.view(-1, tgt_len, src_len) - else: - # bsz * num_heads * num_layers, tgt_len, src_len - bsz, tgt_len, src_len = attention.size() - num_heads_x_layers = 1 - attention = attention.view(-1, tgt_len, src_len) - - if not self.stay_on_last_token: - residual_attention = 1 - attention[:, :, :-1].sum(dim=2, keepdim=True) - attention = torch.cat([attention[:, :, :-1], residual_attention], dim=2) - - # bsz * num_heads_x_num_layers, tgt_len, src_len for MMA - steps = ( - torch.arange(1, 1 + src_len) - .unsqueeze(0) - .unsqueeze(1) - .expand_as(attention) - .type_as(attention) - ) - - if source_padding_mask is not None: - src_offset = ( - source_padding_mask.type_as(attention) - .sum(dim=1, keepdim=True) - .expand(bsz, num_heads_x_layers) - .contiguous() - .view(-1, 1) - ) - src_lens = src_len - src_offset - if source_padding_mask[:, 0].any(): - # Pad left - src_offset = src_offset.view(-1, 1, 1) - steps = steps - src_offset - steps = steps.masked_fill(steps <= 0, 0) - else: - src_lens = attention.new_ones([bsz, num_heads_x_layers]) * src_len - src_lens = src_lens.view(-1, 1) - - # bsz * num_heads_num_layers, tgt_len, src_len - expected_delays = ( - (steps * attention).sum(dim=2).view(bsz, num_heads_x_layers, tgt_len) - ) - - if target_padding_mask is not None: - expected_delays.masked_fill_(target_padding_mask.unsqueeze(1), 0) - - return expected_delays, src_lens - - def avg_loss(self, expected_delays, src_lens, target_padding_mask): - - bsz, num_heads_x_layers, tgt_len = expected_delays.size() - target_padding_mask = ( - target_padding_mask.unsqueeze(1) - .expand_as(expected_delays) - .contiguous() - .view(-1, tgt_len) - ) - - if self.average_method == "average": - # bsz * tgt_len - expected_delays = expected_delays.mean(dim=1) - elif self.average_method == "weighted_average": - weights = torch.nn.functional.softmax(expected_delays, dim=1) - expected_delays = torch.sum(expected_delays * weights, dim=1) - elif self.average_method == "max": - # bsz * num_heads_x_num_layers, tgt_len - expected_delays = expected_delays.max(dim=1)[0] - else: - raise RuntimeError(f"{self.average_method} is not supported") - - src_lens = src_lens.view(bsz, -1)[:, :1] - target_padding_mask = target_padding_mask.view(bsz, -1, tgt_len)[:, 0] - - if self.avg_weight > 0.0: - if self.avg_type in self.metric_calculator: - average_delays = self.metric_calculator[self.avg_type]( - expected_delays, - src_lens, - target_padding_mask, - batch_first=True, - start_from_zero=False, - ) - else: - raise RuntimeError(f"{self.avg_type} is not supported.") - - # bsz * num_heads_x_num_layers, 1 - return self.avg_weight * average_delays.sum() - else: - return 0.0 - - def var_loss(self, expected_delays, src_lens, target_padding_mask): - src_lens = src_lens.view(expected_delays.size(0), expected_delays.size(1))[ - :, :1 - ] - if self.var_weight > 0.0: - if self.var_type in self.variance_calculator: - variance_delays = self.variance_calculator[self.var_type]( - expected_delays, - src_lens, - target_padding_mask, - batch_first=True, - start_from_zero=False, - ) - else: - raise RuntimeError(f"{self.var_type} is not supported.") - - return self.var_weight * variance_delays.sum() - else: - return 0.0 - - def loss(self, attention, source_padding_mask=None, target_padding_mask=None): - expected_delays, src_lens = self.expected_delays_from_attention( - attention, source_padding_mask, target_padding_mask - ) - - latency_loss = 0 - - latency_loss += self.avg_loss(expected_delays, src_lens, target_padding_mask) - - latency_loss += self.var_loss(expected_delays, src_lens, target_padding_mask) - - return latency_loss diff --git a/examples/simultaneous_translation/utils/monotonic_attention.py b/examples/simultaneous_translation/utils/monotonic_attention.py index fd45137735..61dbb112bf 100644 --- a/examples/simultaneous_translation/utils/monotonic_attention.py +++ b/examples/simultaneous_translation/utils/monotonic_attention.py @@ -145,6 +145,8 @@ def expected_soft_attention( # Mix precision to prevent overflow for fp16 beta = beta.type(dtype) + beta = beta.clamp(0, 1) + prob_check(beta) return beta diff --git a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py index 051785238f..223a16f740 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py @@ -3,13 +3,63 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from dataclasses import dataclass, field +import torch +from fairseq import metrics, utils from fairseq.criterions import register_criterion from fairseq.criterions.label_smoothed_cross_entropy import ( LabelSmoothedCrossEntropyCriterion, + LabelSmoothedCrossEntropyCriterionConfig ) +try: + from simuleval.metrics.latency import ( + AverageLagging, + AverageProportion, + DifferentiableAverageLagging + ) + LATENCY_METRICS = { + "average_lagging": AverageLagging, + "average_proportion": AverageProportion, + "differentiable_average_lagging": DifferentiableAverageLagging, + } +except ImportError: + LATENCY_METRICS = None -@register_criterion("latency_augmented_label_smoothed_cross_entropy") + +@dataclass +class LabelSmoothedCrossEntropyCriterionLatencyAugmentConfig( + LabelSmoothedCrossEntropyCriterionConfig +): + latency_avg_weight: float = field( + default=0.0, + metadata={"help": "weight fot average latency loss."}, + ) + latency_var_weight: float = field( + default=0.0, + metadata={"help": "weight fot variance latency loss."}, + ) + latency_avg_type: str = field( + default="differentiable_average_lagging", + metadata={"help": "latency type for average loss"}, + ) + latency_var_type: str = field( + default="variance_delay", + metadata={"help": "latency typ for variance loss"}, + ) + latency_gather_method: str = field( + default="weighted_average", + metadata={"help": "method to gather latency loss for all heads"}, + ) + latency_update_after: int = field( + default=0, + metadata={"help": "Add latency loss after certain steps"}, + ) + +@register_criterion( + "latency_augmented_label_smoothed_cross_entropy", + dataclass=LabelSmoothedCrossEntropyCriterionLatencyAugmentConfig +) class LatencyAugmentedLabelSmoothedCrossEntropyCriterion( LabelSmoothedCrossEntropyCriterion ): @@ -20,89 +70,164 @@ def __init__( label_smoothing, ignore_prefix_size, report_accuracy, - latency_weight_avg, - latency_weight_avg_type, - latency_weight_var, - latency_weight_var_type, - mass_preservation, - average_method, + latency_avg_weight, + latency_var_weight, + latency_avg_type, + latency_var_type, + latency_gather_method, + latency_update_after, ): super().__init__( task, sentence_avg, label_smoothing, ignore_prefix_size, report_accuracy ) - from examples.simultaneous_translation.utils.latency import LatencyTraining - self.eps = label_smoothing - self.latency_weight_avg = latency_weight_avg - self.latency_weight_avg_type = latency_weight_avg_type - self.latency_weight_var = latency_weight_var - self.latency_weight_var_type = latency_weight_var_type - self.mass_preservation = mass_preservation - self.average_method = average_method - self.latency_train = LatencyTraining( - self.latency_weight_avg, - self.latency_weight_var, - self.latency_weight_avg_type, - self.latency_weight_var_type, - self.mass_preservation, - self.average_method, + assert LATENCY_METRICS is not None, "Please make sure SimulEval is installed." + + self.latency_avg_weight = latency_avg_weight + self.latency_var_weight = latency_var_weight + self.latency_avg_type = latency_avg_type + self.latency_var_type = latency_var_type + self.latency_gather_method = latency_gather_method + self.latency_update_after = latency_update_after + + def forward(self, model, sample, reduce=True): + net_output = model(**sample["net_input"]) + # 1. Compute cross entropy loss + loss, nll_loss = self.compute_loss(model, net_output, sample, reduce=reduce) + + # 2. Compute cross latency loss + latency_loss, expected_latency, expected_delays_var = self.compute_latency_loss( + model, sample, net_output + ) + + if self.latency_update_after > 0: + num_updates = getattr(model.decoder, "num_updates", None) + assert num_updates is not None, ( + "model.decoder doesn't have attribute 'num_updates'" + ) + if num_updates <= self.latency_update_after: + latency_loss = 0 + + loss += latency_loss + + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + + logging_output = { + "loss": loss.data, + "nll_loss": nll_loss.data, + "ntokens": sample["ntokens"], + "nsentences": sample["target"].size(0), + "sample_size": sample_size, + "latency": expected_latency, + "delays_var": expected_delays_var, + "latency_loss": latency_loss, + } + + if self.report_accuracy: + n_correct, total = self.compute_accuracy(model, net_output, sample) + logging_output["n_correct"] = utils.item(n_correct.data) + logging_output["total"] = utils.item(total.data) + return loss, sample_size, logging_output + + def compute_latency_loss(self, model, sample, net_output): + assert ( + net_output[-1].encoder_padding_mask is None + or not net_output[-1].encoder_padding_mask[:, 0].any() + ), ( + "Only right padding on source is supported." + ) + # 1. Obtain the expected alignment + alpha_list = [item["alpha"] for item in net_output[1].attn_list] + num_layers = len(alpha_list) + bsz, num_heads, tgt_len, src_len = alpha_list[0].size() + + # bsz * num_layers * num_heads, tgt_len, src_len + alpha_all = torch.cat(alpha_list, dim=1).view(-1, tgt_len, src_len) + + # 2 compute expected delays + # bsz * num_heads * num_layers, tgt_len, src_len for MMA + steps = ( + torch.arange(1, 1 + src_len) + .unsqueeze(0) + .unsqueeze(1) + .expand_as(alpha_all) + .type_as(alpha_all) ) - @staticmethod - def add_args(parser): - super( - LatencyAugmentedLabelSmoothedCrossEntropyCriterion, - LatencyAugmentedLabelSmoothedCrossEntropyCriterion, - ).add_args(parser) - # fmt: off - - """Add criterion-specific arguments to the parser.""" - parser.add_argument( - "--label-smoothing", - default=0.0, - type=float, - metavar="D", - help="epsilon for label smoothing, 0 means no label smoothing", + expected_delays = torch.sum(steps * alpha_all, dim=-1) + + target_padding_mask = ( + model.get_targets(sample, net_output) + .eq(self.padding_idx) + .unsqueeze(1) + .expand(bsz, num_layers * num_heads, tgt_len) + .contiguous() + .view(-1, tgt_len) ) - parser.add_argument( - "--ignore_prefix_size", - default=0, - type=int, - help="ignore first N tokens", + + src_lengths = ( + sample["net_input"]["src_lengths"] + .unsqueeze(1) + .expand(bsz, num_layers * num_heads) + .contiguous() + .view(-1) ) - parser.add_argument( - "--report-accuracy", - default=False, - type=bool, - help="report accuracy metric", + expected_latency = LATENCY_METRICS[self.latency_avg_type]( + expected_delays, src_lengths, None, + target_padding_mask=target_padding_mask ) - parser.add_argument("--latency-weight-avg", default=0., type=float, metavar='D', - help="Average loss weight") - parser.add_argument("--latency-weight-var", default=0., type=float, metavar='D', - help="Variance loss weight") - parser.add_argument("--latency-weight-avg-type", default="differentiable_average_lagging", - help="Statistics for Average loss type") - parser.add_argument("--latency-weight-var-type", default="variance_delay", - help="Statistics for variance loss type") - parser.add_argument("--average-method", default="weighted_average", - help="Average loss type") - # fmt: on - - def compute_loss(self, model, net_output, sample, reduce=True): - # Compute cross entropy loss first - loss, nll_loss = super().compute_loss(model, net_output, sample, reduce) - - # Obtain the expected alignment - attn_list = [item["alpha"] for item in net_output[-1]["attn_list"]] - - target_padding_mask = model.get_targets(sample, net_output).eq(self.padding_idx) - - source_padding_mask = net_output[-1].get("encoder_padding_mask", None) - - # Get latency loss - latency_loss = self.latency_train.loss( - attn_list, source_padding_mask, target_padding_mask + + # 2.1 average expected latency of heads + # bsz, num_layers * num_heads + expected_latency = expected_latency.view(bsz, -1) + if self.latency_gather_method == "average": + # bsz * tgt_len + expected_latency = expected_delays.mean(dim=1) + elif self.latency_gather_method == "weighted_average": + weights = torch.nn.functional.softmax(expected_latency, dim=1) + expected_latency = torch.sum(expected_latency * weights, dim=1) + elif self.latency_gather_method == "max": + expected_latency = expected_latency.max(dim=1)[0] + else: + raise NotImplementedError + + expected_latency = expected_latency.sum() + avg_loss = self.latency_avg_weight * expected_latency + + # 2.2 variance of expected delays + expected_delays_var = ( + expected_delays.view(bsz, -1, tgt_len).var(dim=1).mean(dim=1) ) + expected_delays_var = expected_delays_var.sum() + var_loss = self.latency_avg_weight * expected_delays_var - loss += latency_loss + # 3. Final loss + latency_loss = avg_loss + var_loss + + return latency_loss, expected_latency, expected_delays_var - return loss, nll_loss + @classmethod + def reduce_metrics(cls, logging_outputs) -> None: + super().reduce_metrics(logging_outputs) + latency = sum( + log.get("latency", 0) for log in logging_outputs + ) + delays_var = sum( + log.get("delays_var", 0) for log in logging_outputs + ) + latency_loss = sum( + log.get("latency_loss", 0) for log in logging_outputs + ) + nsentences = sum(log.get("nsentences", 0) for log in logging_outputs) + metrics.log_scalar( + "latency", latency.float() / nsentences, nsentences, round=3 + ) + metrics.log_scalar( + "delays_var", delays_var / nsentences, + nsentences, round=3 + ) + metrics.log_scalar( + "latency_loss", latency_loss / nsentences, + nsentences, round=3 + ) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index de25de6564..347b8118da 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -131,7 +131,10 @@ def forward( # the attention weight (before softmax) for some padded element in query # will become -inf, which results in NaN in model parameters if attn_mask is not None: - attn_mask = attn_mask.masked_fill(attn_mask.to(torch.bool), -1e8) + attn_mask = attn_mask.masked_fill( + attn_mask.to(torch.bool), + -1e8 if x.dtype == torch.float32 else -1e4 + ) residual = x if self.normalize_before: From f6abcc2a67328bee8b15c596bb626ce2d720aae6 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 16 Sep 2021 10:01:11 -0700 Subject: [PATCH 460/774] update on branch renaming (#3879) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3879 Reviewed By: myleott Differential Revision: D30969142 Pulled By: dianaml0 fbshipit-source-id: 902154c03fd68ae6645d3e0ac07b7d729dfc7934 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cd9654cf31..3316c963ce 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ We provide reference implementations of various sequence modeling papers: ### What's New: +* September 2021 [`master` branch renamed to `main`](https://github.com/github/renaming). * July 2021 [Released DrNMT code](examples/discriminative_reranking_nmt/README.md) * July 2021 [Released Robust wav2vec 2.0 model](examples/wav2vec/README.md) * June 2021 [Released XLMR-XL and XLMR-XXL models](examples/xlmr/README.md) From 5adfeaccf9a70cf8ad25eb0d3a0826a6665ac8d2 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Mon, 20 Sep 2021 08:04:06 -0700 Subject: [PATCH 461/774] Rename references from master -> main in preparation for branch name change (#2297) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2297 Reviewed By: alexeib Differential Revision: D30906090 Pulled By: dianaml0 fbshipit-source-id: 941d30db7f766c9077a1b5bb2a04680f57e2e070 --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- .github/ISSUE_TEMPLATE/how-to-question.md | 10 +++++----- .github/PULL_REQUEST_TEMPLATE.md | 10 +++++----- .github/workflows/build.yml | 4 ++-- CONTRIBUTING.md | 2 +- README.md | 6 +++--- docs/conf.py | 2 +- examples/adaptive_span/README.md | 2 +- examples/constrained_decoding/README.md | 2 +- .../discriminative_reranking_nmt/README.md | 2 +- examples/fast_noisy_channel/README.md | 4 ++-- examples/layerdrop/README.md | 6 +++--- examples/m2m_100/README.md | 2 +- examples/multilingual/README.md | 6 +++--- examples/quant_noise/README.md | 20 +++++++++---------- examples/roberta/README.md | 8 ++++---- examples/roberta/commonsense_qa/README.md | 2 +- examples/shuffled_word_order/README.md | 6 +++--- .../speech_synthesis/docs/ljspeech_example.md | 4 ++-- examples/textless_nlp/gslm/README.md | 4 ++-- examples/wav2vec/unsupervised/README.md | 4 ++-- fairseq/models/bart/hub_interface.py | 2 +- fairseq/models/roberta/hub_interface.py | 2 +- 23 files changed, 57 insertions(+), 57 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a7f4f0a902..aa15123d8e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -19,7 +19,7 @@ Steps to reproduce the behavior (**always include the command you ran**): #### Code sample -<!-- Ideally attach a minimal code sample to reproduce the decried issue. +<!-- Ideally attach a minimal code sample to reproduce the decried issue. Minimal means having the shortest code but still preserving the bug. --> ### Expected behavior @@ -28,7 +28,7 @@ Minimal means having the shortest code but still preserving the bug. --> ### Environment - - fairseq Version (e.g., 1.0 or master): + - fairseq Version (e.g., 1.0 or main): - PyTorch Version (e.g., 1.0) - OS (e.g., Linux): - How you installed fairseq (`pip`, source): diff --git a/.github/ISSUE_TEMPLATE/how-to-question.md b/.github/ISSUE_TEMPLATE/how-to-question.md index 4beb180dbf..04f3f15d3e 100644 --- a/.github/ISSUE_TEMPLATE/how-to-question.md +++ b/.github/ISSUE_TEMPLATE/how-to-question.md @@ -6,9 +6,9 @@ labels: 'question, needs triage' ## ❓ Questions and Help -### Before asking: -1. search the issues. -2. search the docs. +### Before asking: +1. search the issues. +2. search the docs. <!-- If you still can't find what you need: --> @@ -16,13 +16,13 @@ labels: 'question, needs triage' #### Code -<!-- Please paste a code snippet if your question requires it! --> +<!-- Please paste a code snippet if your question requires it! --> #### What have you tried? #### What's your environment? - - fairseq Version (e.g., 1.0 or master): + - fairseq Version (e.g., 1.0 or main): - PyTorch Version (e.g., 1.0) - OS (e.g., Linux): - How you installed fairseq (`pip`, source): diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b28ff98e7b..d005e2df4f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,15 +1,15 @@ # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) -- [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? -- [ ] Did you make sure to update the docs? -- [ ] Did you write any new necessary tests? +- [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? +- [ ] Did you make sure to update the docs? +- [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). -## PR review -Anyone in the community is free to review the PR once the tests have passed. +## PR review +Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 105c42a503..f493f91f0d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,10 @@ name: build on: - # Trigger the workflow on push to master or any pull request + # Trigger the workflow on push to main or any pull request push: branches: - - master + - main pull_request: jobs: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4d7ca6a98e..3930c46196 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ possible. ## Pull Requests We actively welcome your pull requests. -1. Fork the repo and create your branch from `master`. +1. Fork the repo and create your branch from `main`. 2. If you've added code that should be tested, add tests. 3. If you've changed APIs, update the documentation. 4. Ensure the test suite passes. diff --git a/README.md b/README.md index 3316c963ce..dd68717480 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ <img src="docs/fairseq_logo.png" width="150"> <br /> <br /> - <a href="https://github.com/pytorch/fairseq/blob/master/LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-blue.svg" /></a> + <a href="https://github.com/pytorch/fairseq/blob/main/LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-blue.svg" /></a> <a href="https://github.com/pytorch/fairseq/releases"><img alt="Latest Release" src="https://img.shields.io/github/release/pytorch/fairseq.svg" /></a> <a href="https://github.com/pytorch/fairseq/actions?query=workflow:build"><img alt="Build Status" src="https://github.com/pytorch/fairseq/workflows/build/badge.svg" /></a> <a href="https://fairseq.readthedocs.io/en/latest/?badge=latest"><img alt="Documentation Status" src="https://readthedocs.org/projects/fairseq/badge/?version=latest" /></a> @@ -48,7 +48,7 @@ We provide reference implementations of various sequence modeling papers: + [Linformer: Self-Attention with Linear Complexity (Wang et al., 2020)](examples/linformer/README.md) + [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) + [Deep Transformers with Latent Depth (Li et al., 2020)](examples/latent_depth/README.md) - + [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979) + + [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979) + [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027) + [Unsupervised Speech Recognition (Baevski, et al., 2021)](https://arxiv.org/abs/2105.11084) * **Non-autoregressive Transformers** @@ -93,7 +93,7 @@ We provide reference implementations of various sequence modeling papers: * April 2020: [Initial model parallel support and 11B parameters unidirectional LM released](examples/megatron_11b/README.md) * March 2020: [Byte-level BPE code released](examples/byte_level_bpe/README.md) * February 2020: [mBART model and code released](examples/mbart/README.md) -* February 2020: [Added tutorial for back-translation](https://github.com/pytorch/fairseq/tree/master/examples/backtranslation#training-your-own-model-wmt18-english-german) +* February 2020: [Added tutorial for back-translation](https://github.com/pytorch/fairseq/tree/main/examples/backtranslation#training-your-own-model-wmt18-english-german) * December 2019: [fairseq 0.9.0 released](https://github.com/pytorch/fairseq/releases/tag/v0.9.0) * November 2019: [VizSeq released (a visual analysis toolkit for evaluating fairseq models)](https://facebookresearch.github.io/vizseq/docs/getting_started/fairseq_example) * November 2019: [CamemBERT model and code released](examples/camembert/README.md) diff --git a/docs/conf.py b/docs/conf.py index 440784bfae..87b0db98c7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -55,7 +55,7 @@ copyright = "Facebook AI Research (FAIR)" author = "Facebook AI Research (FAIR)" -github_doc_root = "https://github.com/pytorch/fairseq/tree/master/docs/" +github_doc_root = "https://github.com/pytorch/fairseq/tree/main/docs/" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/examples/adaptive_span/README.md b/examples/adaptive_span/README.md index 913a873386..d5224fb289 100644 --- a/examples/adaptive_span/README.md +++ b/examples/adaptive_span/README.md @@ -4,7 +4,7 @@ Adaptive Span is a novel self-attention mechanism that can learn its optimal attention span. This allows us to extend significantly the maximum context size used in Transformer, while maintaining control over their memory footprint and computational time. It uses the Truncated BPTT technique for training, -as in [transformerXL](https://github.com/pytorch/fairseq/blob/master/examples/truncated_bptt/README.md). +as in [transformerXL](https://github.com/pytorch/fairseq/blob/main/examples/truncated_bptt/README.md). Adaptive Span was introduced by paper: [Adaptive Attention Span in Transformers](https://arxiv.org/abs/1905.07799), diff --git a/examples/constrained_decoding/README.md b/examples/constrained_decoding/README.md index cfca9c91fd..e04b8b6a01 100644 --- a/examples/constrained_decoding/README.md +++ b/examples/constrained_decoding/README.md @@ -12,7 +12,7 @@ Constrained search is enabled by adding the command-line argument `--constraints Constraints are appended to each line of input, separated by tabs. Each constraint (one or more tokens) is a separate field. -The following command, using [Fairseq's WMT19 German--English model](https://github.com/pytorch/fairseq/blob/master/examples/wmt19/README.md), +The following command, using [Fairseq's WMT19 German--English model](https://github.com/pytorch/fairseq/blob/main/examples/wmt19/README.md), translates the sentence *Die maschinelle Übersetzung ist schwer zu kontrollieren.* with the constraints "hard" and "to influence". diff --git a/examples/discriminative_reranking_nmt/README.md b/examples/discriminative_reranking_nmt/README.md index e6f42b1278..b155e855f2 100644 --- a/examples/discriminative_reranking_nmt/README.md +++ b/examples/discriminative_reranking_nmt/README.md @@ -38,7 +38,7 @@ source_sentence_L_hypo_1 source_sentence_L_hypo_N ``` -2. Download the [XLMR model](https://github.com/fairinternal/fairseq-py/tree/master/examples/xlmr#pre-trained-models). +2. Download the [XLMR model](https://github.com/fairinternal/fairseq-py/tree/main/examples/xlmr#pre-trained-models). ``` wget https://dl.fbaipublicfiles.com/fairseq/models/xlmr.base.tar.gz tar zxvf xlmr.base.tar.gz diff --git a/examples/fast_noisy_channel/README.md b/examples/fast_noisy_channel/README.md index a04151a796..f2631a8c34 100644 --- a/examples/fast_noisy_channel/README.md +++ b/examples/fast_noisy_channel/README.md @@ -29,9 +29,9 @@ This framework provides a great way to utlize strong target language models trai ### Training Translation Models and Language Models -For training Transformer models in fairseq for machine translation, refer to instructions [here](https://github.com/pytorch/fairseq/tree/master/examples/translation) +For training Transformer models in fairseq for machine translation, refer to instructions [here](https://github.com/pytorch/fairseq/tree/main/examples/translation) -For training Transformer models in fairseq for language modeling, refer to instructions [here](https://github.com/pytorch/fairseq/tree/master/examples/language_model) +For training Transformer models in fairseq for language modeling, refer to instructions [here](https://github.com/pytorch/fairseq/tree/main/examples/language_model) ### Generation with Language Model for German-English translation with fairseq diff --git a/examples/layerdrop/README.md b/examples/layerdrop/README.md index 394e710b0f..4d48ee9615 100644 --- a/examples/layerdrop/README.md +++ b/examples/layerdrop/README.md @@ -126,9 +126,9 @@ This model override command overrides the training parameters and updates the mo Looking to reproduce the results in the paper? -1. For Translation on WMT16 en-de, we followed this setting [here](https://github.com/pytorch/fairseq/blob/master/examples/scaling_nmt/README.md) -2. To train RoBERTa, we followed this setting [here](https://github.com/pytorch/fairseq/tree/master/examples/roberta) -3. To train Language Models on Wikitext-103, we followed this setting [here](https://github.com/pytorch/fairseq/tree/master/examples/language_model) +1. For Translation on WMT16 en-de, we followed this setting [here](https://github.com/pytorch/fairseq/blob/main/examples/scaling_nmt/README.md) +2. To train RoBERTa, we followed this setting [here](https://github.com/pytorch/fairseq/tree/main/examples/roberta) +3. To train Language Models on Wikitext-103, we followed this setting [here](https://github.com/pytorch/fairseq/tree/main/examples/language_model) ## Tips diff --git a/examples/m2m_100/README.md b/examples/m2m_100/README.md index 05801584d6..02a68a5f09 100644 --- a/examples/m2m_100/README.md +++ b/examples/m2m_100/README.md @@ -82,7 +82,7 @@ fairseq-preprocess \ 3. **Training Scripts** -To reproduce the training of our models, we train with fairseq-py's multilingual translation [task](https://github.com/pytorch/fairseq/tree/master/examples/multilingual). If you are interested in model parallel training, also check out [fairscale](https://github.com/facebookresearch/fairscale). +To reproduce the training of our models, we train with fairseq-py's multilingual translation [task](https://github.com/pytorch/fairseq/tree/main/examples/multilingual). If you are interested in model parallel training, also check out [fairscale](https://github.com/facebookresearch/fairscale). 4. **Generation** diff --git a/examples/multilingual/README.md b/examples/multilingual/README.md index 0076f5e8f0..46ff9c351b 100644 --- a/examples/multilingual/README.md +++ b/examples/multilingual/README.md @@ -17,9 +17,9 @@ This work is for training multilingual translation models with multiple bitext d - --finetune-from-model to specify the path from which to load the pretrained model ## Preprocessing data -Multilingual training requires a joint BPE vocab. Please follow [mBART's preprocessing steps](https://github.com/pytorch/fairseq/tree/master/examples/mbart#bpe-data) to reuse our pretrained sentence-piece model. +Multilingual training requires a joint BPE vocab. Please follow [mBART's preprocessing steps](https://github.com/pytorch/fairseq/tree/main/examples/mbart#bpe-data) to reuse our pretrained sentence-piece model. -You can also train a joint BPE model on your own dataset and then follow the steps in [[link]](https://github.com/pytorch/fairseq/tree/master/examples/translation#multilingual-translation). +You can also train a joint BPE model on your own dataset and then follow the steps in [[link]](https://github.com/pytorch/fairseq/tree/main/examples/translation#multilingual-translation). ## Training @@ -49,7 +49,7 @@ fairseq-train $path_2_data \ ``` ## Finetuning -We can also finetune multilingual models from a monolingual pretrained models, e.g. [mMBART](https://github.com/pytorch/fairseq/tree/master/examples/mbart). +We can also finetune multilingual models from a monolingual pretrained models, e.g. [mMBART](https://github.com/pytorch/fairseq/tree/main/examples/mbart). ```bash lang_pairs=<language pairs to be trained, e.g. "en-cs,cs-en"> path_2_data=<set to data path> diff --git a/examples/quant_noise/README.md b/examples/quant_noise/README.md index 539c3d5af9..a04d7e4e8a 100644 --- a/examples/quant_noise/README.md +++ b/examples/quant_noise/README.md @@ -33,7 +33,7 @@ Unlike the section [Iterative Product Quantization](#iterative-product-quantizat #### Training -Scalar quantization with Quant-Noise consists in randomly quantizing a proportion `p` of the weights during training. Scalar quantization is implemented [here](https://github.com/pytorch/fairseq/tree/master/fairseq/modules/quantization/scalar) under the form of Fake Quantization, meaning that we emulate int8 on GPU by quantizing and de-quantizing both the weights and the activations. We rely on PyTorch's [quantization primitives](https://github.com/pytorch/pytorch/tree/master/torch/quantization). +Scalar quantization with Quant-Noise consists in randomly quantizing a proportion `p` of the weights during training. Scalar quantization is implemented [here](https://github.com/pytorch/fairseq/tree/main/fairseq/modules/quantization/scalar) under the form of Fake Quantization, meaning that we emulate int8 on GPU by quantizing and de-quantizing both the weights and the activations. We rely on PyTorch's [quantization primitives](https://github.com/pytorch/pytorch/tree/master/torch/quantization). To train a model with Quant-Noise, add the following flag: ``` @@ -49,7 +49,7 @@ When evaluating a network, all quantized modules and activation hooks automatica #### Integration with your own code Looking to quantize your own models with Quant-Noise + Scalar Quantization? -- Use the function `quantize_model_` implemented [here](https://github.com/pytorch/fairseq/tree/master/fairseq/modules/quantization/scalar/utils.py) to (1) replace all your modules by their quantized counterparts and (2) add hooks to those modules to quantize the activations. +- Use the function `quantize_model_` implemented [here](https://github.com/pytorch/fairseq/tree/main/fairseq/modules/quantization/scalar/utils.py) to (1) replace all your modules by their quantized counterparts and (2) add hooks to those modules to quantize the activations. - Then, perform your training as usual. Note that in `eval()` mode, the network is always fully quantized (weights and activations) by default (`p=1`). @@ -66,12 +66,12 @@ To train a model with Quant-Noise, add the following flags: --quant-noise-pq 0.1 --quant-noise-pq-block-size 8 ``` `quant-noise-pq` controls how much dropout is applied to the blocks of the weight matrix. `quant-noise-pq-block-size` controls the size of the weight matrix blocks. -We recommend training with 0.05 to 0.2 Quant-Noise, a value that worked well in our experiments. For the block-size, we recommend training with block-size of 8. Note that the block size must be a multiple of `input_features`, see the size checks [here](https://github.com/pytorch/fairseq/tree/master/fairseq/modules/quant_noise.py). Large block sizes result in higher compression ratio but may induce a loss in accuracy. +We recommend training with 0.05 to 0.2 Quant-Noise, a value that worked well in our experiments. For the block-size, we recommend training with block-size of 8. Note that the block size must be a multiple of `input_features`, see the size checks [here](https://github.com/pytorch/fairseq/tree/main/fairseq/modules/quant_noise.py). Large block sizes result in higher compression ratio but may induce a loss in accuracy. -We currently support training Transformer based models, such as sequence-to-sequence, language models, and BERT architectures. The `quant_noise` function [here](https://github.com/pytorch/fairseq/tree/master/fairseq/modules/quant_noise.py) wraps a module. It splits a weight matrix into blocks and applies random dropout to these blocks. +We currently support training Transformer based models, such as sequence-to-sequence, language models, and BERT architectures. The `quant_noise` function [here](https://github.com/pytorch/fairseq/tree/main/fairseq/modules/quant_noise.py) wraps a module. It splits a weight matrix into blocks and applies random dropout to these blocks. In the Transformer architectures, quant-noise is applied to the input and output embeddings, the attention, and the FFN. -Quant-Noise can also be combined with **LayerDrop** (see [here](https://github.com/pytorch/fairseq/tree/master/examples/layerdrop)) to add its pruning effect to the quantized model and make the model even smaller. We recommend training with LayerDrop 0.1 or 0.2. +Quant-Noise can also be combined with **LayerDrop** (see [here](https://github.com/pytorch/fairseq/tree/main/examples/layerdrop)) to add its pruning effect to the quantized model and make the model even smaller. We recommend training with LayerDrop 0.1 or 0.2. #### Quantization @@ -84,8 +84,8 @@ For the particular case of PQ, quantization is made sequentially. We recommend f #### Integration with your own code Looking to quantize your own models with Quant-Noise + iPQ? -- First wrap your modules with the `quant_noise` function [here](https://github.com/pytorch/fairseq/tree/master/fairseq/modules/quant_noise.py), which is module-agnostic and train your favorite model. -- Then, quantize your trained model using the code [here](https://github.com/pytorch/fairseq/tree/master/fairseq/modules/quantization/pq). This can be done *without any changes to your training loop*. Below is an example code for integration. +- First wrap your modules with the `quant_noise` function [here](https://github.com/pytorch/fairseq/tree/main/fairseq/modules/quant_noise.py), which is module-agnostic and train your favorite model. +- Then, quantize your trained model using the code [here](https://github.com/pytorch/fairseq/tree/main/fairseq/modules/quantization/pq). This can be done *without any changes to your training loop*. Below is an example code for integration. Note that we tried our approach only on Transformers and various Convolutional Models such as EfficientNets. ```python @@ -128,7 +128,7 @@ We detail below how to reproduce the state-of-the-art results in reported in the ### Training with Quant-Noise -To **train** RoBERTa + QuantNoise, we followed this setting [here](https://github.com/pytorch/fairseq/tree/master/examples/roberta). +To **train** RoBERTa + QuantNoise, we followed this setting [here](https://github.com/pytorch/fairseq/tree/main/examples/roberta). The following command can be used to train a RoBERTa Base + QuantNoise model: ```bash @@ -158,7 +158,7 @@ fairseq-train $DATA_DIR \ --quant-noise-pq 0.2 --quant-noise-pq-block-size 8 --untie-weights-roberta ``` -To **finetune** RoBERTa + QuantNoise, we followed this setting [here](https://github.com/pytorch/fairseq/blob/master/examples/roberta/README.glue.md). +To **finetune** RoBERTa + QuantNoise, we followed this setting [here](https://github.com/pytorch/fairseq/blob/main/examples/roberta/README.glue.md). The following command can be used to finetune a RoBERTa Base + QuantNoise model on the RTE dataset: ```bash @@ -193,7 +193,7 @@ fairseq-train /path/to/rte/data/ \ --quant-noise-pq 0.2 --quant-noise-pq-block-size 8 ``` -To **train** Language Models on Wikitext-103, we followed this setting [here](https://github.com/pytorch/fairseq/tree/master/examples/language_model). +To **train** Language Models on Wikitext-103, we followed this setting [here](https://github.com/pytorch/fairseq/tree/main/examples/language_model). The following command can be used to train a Transformer + QuantNoise model on Wikitext-103: ```bash diff --git a/examples/roberta/README.md b/examples/roberta/README.md index 58091b2c7d..ed4d5df52c 100644 --- a/examples/roberta/README.md +++ b/examples/roberta/README.md @@ -8,13 +8,13 @@ RoBERTa iterates on BERT's pretraining procedure, including training the model l ### What's New: -- December 2020: German model (GottBERT) is available: [GottBERT](https://github.com/pytorch/fairseq/tree/master/examples/gottbert). +- December 2020: German model (GottBERT) is available: [GottBERT](https://github.com/pytorch/fairseq/tree/main/examples/gottbert). - January 2020: Italian model (UmBERTo) is available from Musixmatch Research: [UmBERTo](https://github.com/musixmatchresearch/umberto). -- November 2019: French model (CamemBERT) is available: [CamemBERT](https://github.com/pytorch/fairseq/tree/master/examples/camembert). -- November 2019: Multilingual encoder (XLM-RoBERTa) is available: [XLM-R](https://github.com/pytorch/fairseq/tree/master/examples/xlmr). +- November 2019: French model (CamemBERT) is available: [CamemBERT](https://github.com/pytorch/fairseq/tree/main/examples/camembert). +- November 2019: Multilingual encoder (XLM-RoBERTa) is available: [XLM-R](https://github.com/pytorch/fairseq/tree/main/examples/xlmr). - September 2019: TensorFlow and TPU support via the [transformers library](https://github.com/huggingface/transformers). - August 2019: RoBERTa is now supported in the [pytorch-transformers library](https://github.com/huggingface/pytorch-transformers). -- August 2019: Added [tutorial for finetuning on WinoGrande](https://github.com/pytorch/fairseq/tree/master/examples/roberta/wsc#roberta-training-on-winogrande-dataset). +- August 2019: Added [tutorial for finetuning on WinoGrande](https://github.com/pytorch/fairseq/tree/main/examples/roberta/wsc#roberta-training-on-winogrande-dataset). - August 2019: Added [tutorial for pretraining RoBERTa using your own data](README.pretraining.md). ## Pre-trained models diff --git a/examples/roberta/commonsense_qa/README.md b/examples/roberta/commonsense_qa/README.md index 05c6f841a8..7f386decd8 100644 --- a/examples/roberta/commonsense_qa/README.md +++ b/examples/roberta/commonsense_qa/README.md @@ -96,4 +96,4 @@ print('Accuracy: ' + str(ncorrect / float(nsamples))) ``` The above snippet is not batched, which makes it quite slow. See [instructions -for batched prediction with RoBERTa](https://github.com/pytorch/fairseq/tree/master/examples/roberta#batched-prediction). +for batched prediction with RoBERTa](https://github.com/pytorch/fairseq/tree/main/examples/roberta#batched-prediction). diff --git a/examples/shuffled_word_order/README.md b/examples/shuffled_word_order/README.md index 14c240cb56..f20483849a 100644 --- a/examples/shuffled_word_order/README.md +++ b/examples/shuffled_word_order/README.md @@ -40,7 +40,7 @@ For more results on probing tasks, please refer to [our paper](https://arxiv.org ## Example Usage -Follow the same usage as in [RoBERTa](https://github.com/pytorch/fairseq/tree/master/examples/roberta) to load and test your models: +Follow the same usage as in [RoBERTa](https://github.com/pytorch/fairseq/tree/main/examples/roberta) to load and test your models: ```python # Download roberta.base.shuffle.n1 model @@ -53,11 +53,11 @@ roberta = RoBERTaModel.from_pretrained('/path/to/roberta.base.shuffle.n1', check roberta.eval() # disable dropout (or leave in train mode to finetune) ``` -**Note**: The model trained without positional embeddings (`roberta.base.nopos`) is a modified `RoBERTa` model, where the positional embeddings are not used. Thus, the typical `from_pretrained` method on fairseq version of RoBERTa will not be able to load the above model weights. To do so, construct a new `RoBERTaModel` object by setting the flag `use_positional_embeddings` to `False` (or [in the latest code](https://github.com/pytorch/fairseq/blob/master/fairseq/models/roberta/model.py#L543), set `no_token_positional_embeddings` to `True`), and then load the individual weights. +**Note**: The model trained without positional embeddings (`roberta.base.nopos`) is a modified `RoBERTa` model, where the positional embeddings are not used. Thus, the typical `from_pretrained` method on fairseq version of RoBERTa will not be able to load the above model weights. To do so, construct a new `RoBERTaModel` object by setting the flag `use_positional_embeddings` to `False` (or [in the latest code](https://github.com/pytorch/fairseq/blob/main/fairseq/models/roberta/model.py#L543), set `no_token_positional_embeddings` to `True`), and then load the individual weights. ## Fine-tuning Evaluation -We provide the trained fine-tuned models on MNLI here for each model above for quick evaluation (1 seed for each model). Please refer to [finetuning details](README.finetuning.md) for the parameters of these models. Follow [RoBERTa](https://github.com/pytorch/fairseq/tree/master/examples/roberta) instructions to evaluate these models. +We provide the trained fine-tuned models on MNLI here for each model above for quick evaluation (1 seed for each model). Please refer to [finetuning details](README.finetuning.md) for the parameters of these models. Follow [RoBERTa](https://github.com/pytorch/fairseq/tree/main/examples/roberta) instructions to evaluate these models. | Model | MNLI M Dev Accuracy | Link | | :----------------------------------------- | :------------------ | :--------------------------------------------------------------------------------------------------------------- | diff --git a/examples/speech_synthesis/docs/ljspeech_example.md b/examples/speech_synthesis/docs/ljspeech_example.md index 2b8d21abf9..90c524fac8 100644 --- a/examples/speech_synthesis/docs/ljspeech_example.md +++ b/examples/speech_synthesis/docs/ljspeech_example.md @@ -38,7 +38,7 @@ For your convenience, we provide pre-computed [force-alignment](https://dl.fbaipublicfiles.com/fairseq/s2/ljspeech_mfa.zip) from [Montreal Forced Aligner](https://github.com/MontrealCorpusTools/Montreal-Forced-Aligner) and [pseudo-text units](s3://dl.fbaipublicfiles.com/fairseq/s2/ljspeech_hubert.tsv) from -[HuBERT](https://github.com/pytorch/fairseq/tree/master/examples/hubert). You can also generate them by yourself using +[HuBERT](https://github.com/pytorch/fairseq/tree/main/examples/hubert). You can also generate them by yourself using a different software or model. @@ -106,7 +106,7 @@ use `--sample-rate 16000` for `get_eval_manifest.py`. #### WER/CER metric -We use wav2vec 2.0 ASR model as example. [Download](https://github.com/pytorch/fairseq/tree/master/examples/wav2vec) +We use wav2vec 2.0 ASR model as example. [Download](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec) the model checkpoint and dictionary, then compute WER/CER with ```bash python -m examples.speech_synthesis.evaluation.eval_asr \ diff --git a/examples/textless_nlp/gslm/README.md b/examples/textless_nlp/gslm/README.md index 79de55d96e..7a76ffd57c 100644 --- a/examples/textless_nlp/gslm/README.md +++ b/examples/textless_nlp/gslm/README.md @@ -3,7 +3,7 @@ * [Paper](https://arxiv.org/abs/2102.01192) * [Demo](https://speechbot.github.io/gslm/index.html) -We build and evaluate generative speech2speech systems using [Log Mel Filtebank](https://pytorch.org/audio/stable/compliance.kaldi.html#fbank), [Modified CPC](https://github.com/facebookresearch/CPC_audio), [HuBERT Base](https://github.com/pytorch/fairseq/tree/master/examples/hubert) and [Wav2Vec 2.0 Large](https://github.com/pytorch/fairseq/tree/master/examples/wav2vec). Our system is composed of three components, namely, *speech2unit*, *ulm* and *unit2speech*. We explain about models and usage of these components in their respective sub-directories. See the links below. +We build and evaluate generative speech2speech systems using [Log Mel Filtebank](https://pytorch.org/audio/stable/compliance.kaldi.html#fbank), [Modified CPC](https://github.com/facebookresearch/CPC_audio), [HuBERT Base](https://github.com/pytorch/fairseq/tree/main/examples/hubert) and [Wav2Vec 2.0 Large](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec). Our system is composed of three components, namely, *speech2unit*, *ulm* and *unit2speech*. We explain about models and usage of these components in their respective sub-directories. See the links below. ## Speech to Unit Model (speech2unit) Speech to unit model is used for quantizing raw speech into learned discrete speech units. [More details](speech2unit) @@ -18,4 +18,4 @@ Unit to speech model is used for synthesizing speech from discrete speech units. We show how to compute ASR based metrics as well as zero-shot metrics proposed in our paper [here](metrics). ## Tools -We share two tools to resynthesize a given spoken utterance, and generate novel spoken language given a spoken prompt. [More detail](tools) \ No newline at end of file +We share two tools to resynthesize a given spoken utterance, and generate novel spoken language given a spoken prompt. [More detail](tools) diff --git a/examples/wav2vec/unsupervised/README.md b/examples/wav2vec/unsupervised/README.md index 046202e01c..0b213fd202 100644 --- a/examples/wav2vec/unsupervised/README.md +++ b/examples/wav2vec/unsupervised/README.md @@ -1,6 +1,6 @@ # wav2vec Unsupervised (wav2vec-U) -Wav2vec Unsupervised (wav2vec-U) is a framework for building speech recognition systems without any labeled training data as described in [Unsupervised Speech Recognition (Baevski et al., 2021)](https://ai.facebook.com/research/publications/unsupervised-speech-recognition). The model takes as input wav2vec 2.0 or XLSR representations (see [pretrained models](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec)) as well as unlabeled speech and text data. +Wav2vec Unsupervised (wav2vec-U) is a framework for building speech recognition systems without any labeled training data as described in [Unsupervised Speech Recognition (Baevski et al., 2021)](https://ai.facebook.com/research/publications/unsupervised-speech-recognition). The model takes as input wav2vec 2.0 or XLSR representations (see [pretrained models](https://github.com/pytorch/fairseq/blob/main/examples/wav2vec)) as well as unlabeled speech and text data. The wav2vec-U training procedure consists of three consecutive main steps: * Preparation of speech representations and text data @@ -8,7 +8,7 @@ Wav2vec Unsupervised (wav2vec-U) is a framework for building speech recognition * Iterative self-training + Kaldi LM-decoding ## Preparation of speech and text data -Similar to [wav2vec 2.0](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec/README.md), data folders contain {train,valid,test}.{tsv,wrd,phn} files, where audio paths are stored in tsv files, and word, letter or phoneme transcriptions are stored in .{wrd,ltr,phn}. +Similar to [wav2vec 2.0](https://github.com/pytorch/fairseq/blob/main/examples/wav2vec/README.md), data folders contain {train,valid,test}.{tsv,wrd,phn} files, where audio paths are stored in tsv files, and word, letter or phoneme transcriptions are stored in .{wrd,ltr,phn}. In **/path/to/data/with_silence** you need a *train.tsv* file as well as (optionally) *{valid,test}.{tsv,wrd,phn}*. It is nice to have *10h.{tsv,phn}* files there too for reproducing the ablation study on layer selection. In **/path/to/data/without_silence** you have the same files, except *.tsv* files contain audios with silences removed using rVAD. diff --git a/fairseq/models/bart/hub_interface.py b/fairseq/models/bart/hub_interface.py index 9afe385b9d..4d47d97518 100644 --- a/fairseq/models/bart/hub_interface.py +++ b/fairseq/models/bart/hub_interface.py @@ -23,7 +23,7 @@ class BARTHubInterface(GeneratorHubInterface): """A simple PyTorch Hub interface to BART. - Usage: https://github.com/pytorch/fairseq/tree/master/examples/bart + Usage: https://github.com/pytorch/fairseq/tree/main/examples/bart """ def __init__(self, cfg, task, model): diff --git a/fairseq/models/roberta/hub_interface.py b/fairseq/models/roberta/hub_interface.py index c9af434bde..ba298d63ba 100644 --- a/fairseq/models/roberta/hub_interface.py +++ b/fairseq/models/roberta/hub_interface.py @@ -14,7 +14,7 @@ class RobertaHubInterface(nn.Module): """A simple PyTorch Hub interface to RoBERTa. - Usage: https://github.com/pytorch/fairseq/tree/master/examples/roberta + Usage: https://github.com/pytorch/fairseq/tree/main/examples/roberta """ def __init__(self, cfg, task, model): From 3dd70d8c0d17ef3268b22706805622826df7b6d3 Mon Sep 17 00:00:00 2001 From: freewym <freewym@gmail.com> Date: Mon, 20 Sep 2021 11:52:04 -0700 Subject: [PATCH 462/774] =?UTF-8?q?fix=20the=20problem=20that=20command=20?= =?UTF-8?q?line=20args=20for=20Transformer=20model=20do=20not=20o=E2=80=A6?= =?UTF-8?q?=20(#3773)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: …verride the defaults # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3761. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3773 Reviewed By: yuntang Differential Revision: D30310383 Pulled By: kahne fbshipit-source-id: cbfcbc032dbf53490a25ffdebe57f65c42d52e71 --- fairseq/models/transformer/transformer_base.py | 4 ++-- fairseq/models/transformer/transformer_legacy.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fairseq/models/transformer/transformer_base.py b/fairseq/models/transformer/transformer_base.py index 810c9b98db..b4d5604dbb 100644 --- a/fairseq/models/transformer/transformer_base.py +++ b/fairseq/models/transformer/transformer_base.py @@ -41,8 +41,8 @@ def __init__(self, cfg, encoder, decoder): self.cfg = cfg self.supports_align_args = True - @staticmethod - def add_args(parser): + @classmethod + def add_args(cls, parser): """Add model-specific arguments to the parser.""" # we want to build the args recursively in this case. gen_parser_from_dataclass( diff --git a/fairseq/models/transformer/transformer_legacy.py b/fairseq/models/transformer/transformer_legacy.py index 9534e400b5..af9646740a 100644 --- a/fairseq/models/transformer/transformer_legacy.py +++ b/fairseq/models/transformer/transformer_legacy.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from fairseq.dataclass.utils import gen_parser_from_dataclass from fairseq.models import ( register_model, register_model_architecture, @@ -78,6 +79,15 @@ def __init__(self, args, encoder, decoder): super().__init__(cfg, encoder, decoder) self.args = args + @classmethod + def add_args(cls, parser): + """Add model-specific arguments to the parser.""" + # we want to build the args recursively in this case. + # do not set defaults so that settings defaults from various architectures still works + gen_parser_from_dataclass( + parser, TransformerConfig(), delete_default=True, with_prefix="" + ) + @classmethod def build_model(cls, args, task): """Build a new model instance.""" From fcca32258c8e8bcc9f9890bf4714fa2f96b6b3e1 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@fb.com> Date: Mon, 20 Sep 2021 14:30:04 -0700 Subject: [PATCH 463/774] Update reference from master to main elsewhere in fbcode Summary: Update reference from master to main elsewhere in fbcode Reviewed By: alexeib Differential Revision: D30938472 fbshipit-source-id: 243b98550207f241c9d3265bf3d4060350aaf0a8 --- examples/fully_sharded_data_parallel/README.md | 2 +- examples/speech_text_joint_to_text/docs/ende-mustc.md | 4 ++-- examples/speech_text_joint_to_text/docs/iwslt2021.md | 2 +- examples/textless_nlp/gslm/metrics/asr_metrics/README.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/fully_sharded_data_parallel/README.md b/examples/fully_sharded_data_parallel/README.md index d620f0e4f1..b9e44fef48 100644 --- a/examples/fully_sharded_data_parallel/README.md +++ b/examples/fully_sharded_data_parallel/README.md @@ -48,7 +48,7 @@ CPU, or on 8 GPUs by fully sharding the params and optimizer states across GPUs. These examples use the WikiText-103 dataset for demonstration purposes, but in practice a much larger dataset will be needed to achieve good results. -Follow the [instructions here](https://github.com/pytorch/fairseq/blob/master/examples/roberta/README.pretraining.md#1-preprocess-the-data) +Follow the [instructions here](https://github.com/pytorch/fairseq/blob/main/examples/roberta/README.pretraining.md#1-preprocess-the-data) to preprocess the WikiText-103 dataset using the GPT-2/RoBERTa vocabulary. ### 13B params on 1 V100 GPU (with CPU offloading) diff --git a/examples/speech_text_joint_to_text/docs/ende-mustc.md b/examples/speech_text_joint_to_text/docs/ende-mustc.md index 3487af6671..2897c4e27b 100644 --- a/examples/speech_text_joint_to_text/docs/ende-mustc.md +++ b/examples/speech_text_joint_to_text/docs/ende-mustc.md @@ -12,7 +12,7 @@ Enhanced Joint Training: the joint training is enhanced with pre-trained models, - Dictionary [dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/dict.txt) - config [config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/config.yaml) #### Prepare MuST-C data set -- [Please follow the data preparation in the S2T example](https://github.com/pytorch/fairseq/blob/master/examples/speech_to_text/docs/mustc_example.md) +- [Please follow the data preparation in the S2T example](https://github.com/pytorch/fairseq/blob/main/examples/speech_to_text/docs/mustc_example.md) - Append src_text in the tsv file with phoneme representation. ```bash python examples/speech_text_joint_to_text/scripts/g2p_encode.py \ @@ -24,7 +24,7 @@ Enhanced Joint Training: the joint training is enhanced with pre-trained models, - Update tsv data with src_text generated above and save to $MANIFEST_ROOT - Prepare phoneme dictionary and save to $MANIFEST_ROOT as [src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/src_dict.txt) #### Prepare WMT text data -- [Download wmt data](https://github.com/pytorch/fairseq/blob/master/examples/translation/prepare-wmt14en2de.sh) +- [Download wmt data](https://github.com/pytorch/fairseq/blob/main/examples/translation/prepare-wmt14en2de.sh) - Convert source text (English) into phoneme representation as above - Generate binary parallel file for training (as translation example) and save data in $parallel_text_data diff --git a/examples/speech_text_joint_to_text/docs/iwslt2021.md b/examples/speech_text_joint_to_text/docs/iwslt2021.md index 37a07c4a05..920ff271c2 100644 --- a/examples/speech_text_joint_to_text/docs/iwslt2021.md +++ b/examples/speech_text_joint_to_text/docs/iwslt2021.md @@ -11,7 +11,7 @@ This directory contains the code from paper ["FST: the FAIR Speech Translation S - Config [config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/config.yaml) #### Prepare -- [Please follow the data preparation in speech-to-text](https://github.com/pytorch/fairseq/blob/master/examples/speech_to_text/docs/mtedx_example.md) +- [Please follow the data preparation in speech-to-text](https://github.com/pytorch/fairseq/blob/main/examples/speech_to_text/docs/mtedx_example.md) diff --git a/examples/textless_nlp/gslm/metrics/asr_metrics/README.md b/examples/textless_nlp/gslm/metrics/asr_metrics/README.md index d05bc73d0d..90741f42b0 100644 --- a/examples/textless_nlp/gslm/metrics/asr_metrics/README.md +++ b/examples/textless_nlp/gslm/metrics/asr_metrics/README.md @@ -29,7 +29,7 @@ Here `ground_truth_continuation_dev.json` is a json file with ground-truth text ## Running ASR We use a pre-trained wav2vec model to run the ASR step. We firstly need to prepare manifest files which, roughly, tell the ASR system which files we want to transcribe. You can find more details and download the `960h_scratch.pt` checkpoint -[[here]](https://github.com/pytorch/fairseq/blob/master/examples/wav2vec/README.md)). To run ASR, you would also need to +[[here]](https://github.com/pytorch/fairseq/blob/main/examples/wav2vec/README.md)). To run ASR, you would also need to install KenLM, Flashlight decoder, and download the KenLM 4-gram English language model. ```bash From f34abcf2b64d8659bae7d3eb2e0caf80cf1d6e7d Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Mon, 27 Sep 2021 10:21:37 -0700 Subject: [PATCH 464/774] Use safe_getattr and safe_hasattr (#2347) Summary: We use omegaconf.DictConfig objects in non-strict mode, so hasattr behaves weirdly: ``` >>> import omegaconf >>> omegaconf.__version__ '2.0.6' >>> x = omegaconf.DictConfig({"a": 1}) >>> hasattr(x, "foo") True ``` This violates some assumptions in various parts of the code. For example, previously this command was incorrectly missing the final layer norm due to upgrade logic that relied on `hasattr`, but is fixed after this diff: ``` CUDA_VISIBLE_DEVICES=0 python train.py --task dummy_lm --arch transformer_lm_gpt3_small --optimizer adam --lr 0.0001 --max-sentences 8 --log-format json --log-interval 1 ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2347 Reviewed By: alexeib Differential Revision: D31170584 Pulled By: myleott fbshipit-source-id: bd767b7497794314f58f0f8073cdd4332b214006 --- .github/workflows/build.yml | 2 +- examples/criss/save_encoder.py | 5 +- .../models/latent_multilingual_transformer.py | 5 +- .../multilingual_translation_latent_depth.py | 5 +- .../linformer_src/models/linformer_roberta.py | 3 +- .../models/s2t_dualinputxmtransformer.py | 7 +- fairseq/models/fconv_lm.py | 3 +- fairseq/models/lightconv.py | 5 +- fairseq/models/masked_lm.py | 3 +- fairseq/models/multilingual_transformer.py | 5 +- fairseq/models/roberta/model.py | 13 +- .../models/speech_to_text/xm_transformer.py | 5 +- fairseq/models/transformer_lm.py | 255 +++++++++--------- fairseq/utils.py | 15 ++ 14 files changed, 175 insertions(+), 156 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f493f91f0d..981b59416f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,7 +40,7 @@ jobs: - name: Install optional test requirements run: | python -m pip install iopath transformers pyarrow - python -m pip install git+https://github.com/facebookresearch/fairscale.git@master + python -m pip install git+https://github.com/facebookresearch/fairscale.git@main - name: Lint with flake8 run: | diff --git a/examples/criss/save_encoder.py b/examples/criss/save_encoder.py index d911d066e3..24a842e409 100644 --- a/examples/criss/save_encoder.py +++ b/examples/criss/save_encoder.py @@ -11,6 +11,7 @@ import torch from fairseq import checkpoint_utils, options, progress_bar, tasks, utils from fairseq.sequence_generator import EnsembleModel +from fairseq.utils import safe_hasattr def get_avg_pool( @@ -109,9 +110,9 @@ def main(args): shard_id = 0 all_avg_pool = None encoder_has_langtok = ( - hasattr(task.args, "encoder_langtok") + safe_hasattr(task.args, "encoder_langtok") and task.args.encoder_langtok is not None - and hasattr(task.args, "lang_tok_replacing_bos_eos") + and safe_hasattr(task.args, "lang_tok_replacing_bos_eos") and not task.args.lang_tok_replacing_bos_eos ) with progress_bar.build_progress_bar(args, itr) as t: diff --git a/examples/latent_depth/latent_depth_src/models/latent_multilingual_transformer.py b/examples/latent_depth/latent_depth_src/models/latent_multilingual_transformer.py index 12b7e67d03..9e7b655fee 100644 --- a/examples/latent_depth/latent_depth_src/models/latent_multilingual_transformer.py +++ b/examples/latent_depth/latent_depth_src/models/latent_multilingual_transformer.py @@ -10,6 +10,7 @@ TransformerEncoder, base_architecture, ) +from fairseq.utils import safe_hasattr from .latent_transformer import LatentTransformerDecoder, LatentTransformerEncoder @@ -40,14 +41,14 @@ def add_args(parser): @classmethod def _get_module_class(cls, is_encoder, args, lang_dict, embed_tokens, langs): if is_encoder: - if hasattr(args, "encoder_latent_layer") and args.encoder_latent_layer: + if safe_hasattr(args, "encoder_latent_layer") and args.encoder_latent_layer: return LatentTransformerEncoder( args, lang_dict, embed_tokens, num_logits=len(langs) ) else: return TransformerEncoder(args, lang_dict, embed_tokens) else: - if hasattr(args, "decoder_latent_layer") and args.decoder_latent_layer: + if safe_hasattr(args, "decoder_latent_layer") and args.decoder_latent_layer: return LatentTransformerDecoder( args, lang_dict, embed_tokens, num_logits=len(langs) ) diff --git a/examples/latent_depth/latent_depth_src/multilingual_translation_latent_depth.py b/examples/latent_depth/latent_depth_src/multilingual_translation_latent_depth.py index b5cd51a470..8cc2a7174b 100644 --- a/examples/latent_depth/latent_depth_src/multilingual_translation_latent_depth.py +++ b/examples/latent_depth/latent_depth_src/multilingual_translation_latent_depth.py @@ -5,6 +5,7 @@ from fairseq.tasks import register_task from fairseq.tasks.multilingual_translation import MultilingualTranslationTask +from fairseq.utils import safe_hasattr from .loss.latent_depth import LatentLayersKLLoss, LatentLayersSparsityLoss @@ -174,14 +175,14 @@ def inference_step( @property def encoder_latent_layer(self): return ( - hasattr(self.args, "encoder_latent_layer") + safe_hasattr(self.args, "encoder_latent_layer") and self.args.encoder_latent_layer ) @property def decoder_latent_layer(self): return ( - hasattr(self.args, "decoder_latent_layer") + safe_hasattr(self.args, "decoder_latent_layer") and self.args.decoder_latent_layer ) diff --git a/examples/linformer/linformer_src/models/linformer_roberta.py b/examples/linformer/linformer_src/models/linformer_roberta.py index 18ad44f079..b7bdbb1105 100644 --- a/examples/linformer/linformer_src/models/linformer_roberta.py +++ b/examples/linformer/linformer_src/models/linformer_roberta.py @@ -18,6 +18,7 @@ RobertaEncoder, RobertaModel, ) +from fairseq.utils import safe_hasattr from ..modules.linformer_sentence_encoder import LinformerTransformerEncoder @@ -58,7 +59,7 @@ def build_model(cls, args, task): # make sure all arguments are present base_architecture(args) - if not hasattr(args, "max_positions"): + if not safe_hasattr(args, "max_positions"): args.max_positions = args.tokens_per_sample encoder = LinformerEncoder(args, task.source_dictionary) diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py index 6c853b96ed..50683e6d7c 100644 --- a/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py @@ -21,6 +21,7 @@ ) from fairseq.models.transformer import TransformerEncoder, TransformerDecoder from fairseq.models.wav2vec import TransformerSentenceEncoderLayer +from fairseq.utils import safe_hasattr from .s2t_dualinputtransformer import ( DualInputS2TTransformerModel, @@ -441,7 +442,7 @@ def build_encoder(cls, args, task): for k, p in spch_encoder.named_parameters(): # Freeze pretrained models by default - if hasattr( + if safe_hasattr( args, "finetune_w2v_params" ) and XMTransformerModel.finetune_params(args.finetune_w2v_params, k): p.requires_grad = True @@ -449,7 +450,7 @@ def build_encoder(cls, args, task): p.requires_grad = False for k, p in text_encoder.named_parameters(): # Freeze pretrained models by default - if hasattr( + if safe_hasattr( args, "finetune_mbart_encoder_params" ) and XMTransformerModel.finetune_params( args.finetune_mbart_encoder_params, k @@ -488,7 +489,7 @@ def build_decoder(cls, args, task): decoder.layer_norm = None for k, p in decoder.named_parameters(): # Freeze pretrained models by default - if hasattr( + if safe_hasattr( args, "finetune_mbart_decoder_params" ) and XMTransformerModel.finetune_params( args.finetune_mbart_decoder_params, k diff --git a/fairseq/models/fconv_lm.py b/fairseq/models/fconv_lm.py index 07391eaa29..4b243d6669 100644 --- a/fairseq/models/fconv_lm.py +++ b/fairseq/models/fconv_lm.py @@ -10,6 +10,7 @@ register_model_architecture, ) from fairseq.models.fconv import FConvDecoder +from fairseq.utils import safe_hasattr @register_model("fconv_lm") @@ -66,7 +67,7 @@ def build_model(cls, args, task): # make sure all arguments are present in older models base_lm_architecture(args) - if hasattr(args, "max_target_positions") and not hasattr( + if safe_hasattr(args, "max_target_positions") and not safe_hasattr( args, "tokens_per_sample" ): args.tokens_per_sample = args.max_target_positions diff --git a/fairseq/models/lightconv.py b/fairseq/models/lightconv.py index b614da3665..4edfe35937 100644 --- a/fairseq/models/lightconv.py +++ b/fairseq/models/lightconv.py @@ -25,6 +25,7 @@ MultiheadAttention, PositionalEmbedding, ) +from fairseq.utils import safe_hasattr @register_model("lightconv") @@ -257,9 +258,9 @@ def build_model(cls, args, task): # make sure all arguments are present in older models base_architecture(args) - if not hasattr(args, "max_source_positions"): + if not safe_hasattr(args, "max_source_positions"): args.max_source_positions = 1024 - if not hasattr(args, "max_target_positions"): + if not safe_hasattr(args, "max_target_positions"): args.max_target_positions = 1024 src_dict, tgt_dict = task.source_dictionary, task.target_dictionary diff --git a/fairseq/models/masked_lm.py b/fairseq/models/masked_lm.py index c786de9125..5cb49dd77c 100644 --- a/fairseq/models/masked_lm.py +++ b/fairseq/models/masked_lm.py @@ -21,6 +21,7 @@ TransformerSentenceEncoder, ) from fairseq.modules.transformer_sentence_encoder import init_bert_params +from fairseq.utils import safe_hasattr logger = logging.getLogger(__name__) @@ -158,7 +159,7 @@ def build_model(cls, args, task): # make sure all arguments are present in older models base_architecture(args) - if not hasattr(args, "max_positions"): + if not safe_hasattr(args, "max_positions"): args.max_positions = args.tokens_per_sample logger.info(args) diff --git a/fairseq/models/multilingual_transformer.py b/fairseq/models/multilingual_transformer.py index 2e1f86f36e..e722b647ed 100644 --- a/fairseq/models/multilingual_transformer.py +++ b/fairseq/models/multilingual_transformer.py @@ -18,6 +18,7 @@ TransformerModel, base_architecture, ) +from fairseq.utils import safe_hasattr @register_model("multilingual_transformer") @@ -75,9 +76,9 @@ def build_model(cls, args, task): # make sure all arguments are present in older models base_multilingual_architecture(args) - if not hasattr(args, "max_source_positions"): + if not safe_hasattr(args, "max_source_positions"): args.max_source_positions = 1024 - if not hasattr(args, "max_target_positions"): + if not safe_hasattr(args, "max_target_positions"): args.max_target_positions = 1024 src_langs = [lang_pair.split("-")[0] for lang_pair in task.model_lang_pairs] diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 3337616be6..bb205b910d 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -22,6 +22,7 @@ from fairseq.modules import LayerNorm from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ from fairseq.modules.transformer_sentence_encoder import init_bert_params +from fairseq.utils import safe_getattr, safe_hasattr from .hub_interface import RobertaHubInterface @@ -197,8 +198,8 @@ def build_model(cls, args, task): # make sure all arguments are present base_architecture(args) - if not hasattr(args, "max_positions"): - if not hasattr(args, "tokens_per_sample"): + if not safe_hasattr(args, "max_positions"): + if not safe_hasattr(args, "tokens_per_sample"): args.tokens_per_sample = task.max_positions() args.max_positions = args.tokens_per_sample @@ -519,14 +520,6 @@ def max_positions(self): return self.args.max_positions -def safe_getattr(obj, k, default=None): - from omegaconf import OmegaConf - - if OmegaConf.is_config(obj): - return obj[k] if k in obj and obj[k] is not None else default - - return getattr(obj, k, default) - @register_model_architecture("roberta", "roberta") def base_architecture(args): args.encoder_layers = safe_getattr(args, "encoder_layers", 12) diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index 03c434b5ea..5eecbfa215 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -15,6 +15,7 @@ from fairseq.models.wav2vec import Wav2VecEncoder from fairseq.modules.layer_norm import LayerNorm from fairseq.data.data_utils import lengths_to_padding_mask +from fairseq.utils import safe_hasattr from torch import Tensor import torch.nn as nn @@ -203,7 +204,7 @@ def __init__(self, args): ) for k, p in self.w2v_encoder.w2v_model.named_parameters(): # Freeze pretrained models by default - if hasattr(args, 'finetune_w2v_params') and XMTransformerModel.finetune_params( + if safe_hasattr(args, 'finetune_w2v_params') and XMTransformerModel.finetune_params( args.finetune_w2v_params, k): p.requires_grad = True else: @@ -349,7 +350,7 @@ def build_decoder(cls, args, task, embed_tokens): ) for k, p in decoder.named_parameters(): # Freeze pretrained models by default - if hasattr(args, 'finetune_decoder_params') and XMTransformerModel.finetune_params( + if safe_hasattr(args, 'finetune_decoder_params') and XMTransformerModel.finetune_params( args.finetune_decoder_params, k): p.requires_grad = True else: diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index a546776912..eedd5151ba 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -18,6 +18,7 @@ DEFAULT_MIN_PARAMS_TO_WRAP, Embedding, TransformerDecoder ) from fairseq.modules import AdaptiveInput, CharacterTokenEmbedder +from fairseq.utils import safe_getattr, safe_hasattr from omegaconf import II @@ -243,8 +244,8 @@ def build_model(cls, args, task): if args.decoder_layers_to_keep: args.decoder_layers = len(args.decoder_layers_to_keep.split(",")) - if getattr(args, "max_target_positions", None) is None: - args.max_target_positions = getattr( + if safe_getattr(args, "max_target_positions", None) is None: + args.max_target_positions = safe_getattr( args, "tokens_per_sample", DEFAULT_MAX_TARGET_POSITIONS ) @@ -295,179 +296,179 @@ def build_embedding(cls, args, dictionary, embed_dim, path=None): def base_lm_architecture(args): # backward compatibility for older model checkpoints - if hasattr(args, "no_tie_adaptive_proj"): + if safe_hasattr(args, "no_tie_adaptive_proj"): # previous models defined --no-tie-adaptive-proj, so use the existence of # that option to determine if this is an "old" model checkpoint args.no_decoder_final_norm = True # old models always set this to True if args.no_tie_adaptive_proj is False: args.tie_adaptive_proj = True - if hasattr(args, "decoder_final_norm"): + if safe_hasattr(args, "decoder_final_norm"): args.no_decoder_final_norm = not args.decoder_final_norm - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.0) - - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 2048) - args.decoder_layers = getattr(args, "decoder_layers", 6) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) - args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) - args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) - args.adaptive_softmax_factor = getattr(args, "adaptive_softmax_factor", 4) - args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) - args.activation_fn = getattr(args, "activation_fn", "relu") - - args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0) - args.decoder_layers_to_keep = getattr(args, "decoder_layers_to_keep", None) - args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) - args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8) - args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0) - - args.base_layers = getattr(args, "base_layers", 0) - args.base_sublayers = getattr(args, "base_sublayers", 1) - args.base_shuffle = getattr(args, "base_shuffle", False) - - args.add_bos_token = getattr(args, "add_bos_token", False) - args.no_token_positional_embeddings = getattr( + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.0) + + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 512) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", 2048) + args.decoder_layers = safe_getattr(args, "decoder_layers", 6) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 8) + args.adaptive_softmax_cutoff = safe_getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = safe_getattr(args, "adaptive_softmax_dropout", 0) + args.adaptive_softmax_factor = safe_getattr(args, "adaptive_softmax_factor", 4) + args.decoder_learned_pos = safe_getattr(args, "decoder_learned_pos", False) + args.activation_fn = safe_getattr(args, "activation_fn", "relu") + + args.decoder_layerdrop = safe_getattr(args, "decoder_layerdrop", 0) + args.decoder_layers_to_keep = safe_getattr(args, "decoder_layers_to_keep", None) + args.quant_noise_pq = safe_getattr(args, "quant_noise_pq", 0) + args.quant_noise_pq_block_size = safe_getattr(args, "quant_noise_pq_block_size", 8) + args.quant_noise_scalar = safe_getattr(args, "quant_noise_scalar", 0) + + args.base_layers = safe_getattr(args, "base_layers", 0) + args.base_sublayers = safe_getattr(args, "base_sublayers", 1) + args.base_shuffle = safe_getattr(args, "base_shuffle", False) + + args.add_bos_token = safe_getattr(args, "add_bos_token", False) + args.no_token_positional_embeddings = safe_getattr( args, "no_token_positional_embeddings", False ) - args.share_decoder_input_output_embed = getattr( + args.share_decoder_input_output_embed = safe_getattr( args, "share_decoder_input_output_embed", False ) - args.character_embeddings = getattr(args, "character_embeddings", False) + args.character_embeddings = safe_getattr(args, "character_embeddings", False) - args.decoder_output_dim = getattr( + args.decoder_output_dim = safe_getattr( args, "decoder_output_dim", args.decoder_embed_dim ) - args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) + args.decoder_input_dim = safe_getattr(args, "decoder_input_dim", args.decoder_embed_dim) # Model training is not stable without this args.decoder_normalize_before = True - args.no_decoder_final_norm = getattr(args, "no_decoder_final_norm", False) + args.no_decoder_final_norm = safe_getattr(args, "no_decoder_final_norm", False) - args.adaptive_input = getattr(args, "adaptive_input", False) - args.adaptive_input_factor = getattr(args, "adaptive_input_factor", 4) - args.adaptive_input_cutoff = getattr(args, "adaptive_input_cutoff", None) + args.adaptive_input = safe_getattr(args, "adaptive_input", False) + args.adaptive_input_factor = safe_getattr(args, "adaptive_input_factor", 4) + args.adaptive_input_cutoff = safe_getattr(args, "adaptive_input_cutoff", None) - args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) - args.tie_adaptive_proj = getattr(args, "tie_adaptive_proj", False) + args.tie_adaptive_weights = safe_getattr(args, "tie_adaptive_weights", False) + args.tie_adaptive_proj = safe_getattr(args, "tie_adaptive_proj", False) - args.no_scale_embedding = getattr(args, "no_scale_embedding", False) - args.layernorm_embedding = getattr(args, "layernorm_embedding", False) - args.checkpoint_activations = getattr(args, "checkpoint_activations", False) - args.offload_activations = getattr(args, "offload_activations", False) + args.no_scale_embedding = safe_getattr(args, "no_scale_embedding", False) + args.layernorm_embedding = safe_getattr(args, "layernorm_embedding", False) + args.checkpoint_activations = safe_getattr(args, "checkpoint_activations", False) + args.offload_activations = safe_getattr(args, "offload_activations", False) if args.offload_activations: args.checkpoint_activations = True @register_model_architecture("transformer_lm", "transformer_lm_big") def transformer_lm_big(args): - args.decoder_layers = getattr(args, "decoder_layers", 12) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4096) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + args.decoder_layers = safe_getattr(args, "decoder_layers", 12) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 1024) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", 4096) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 16) base_lm_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_wiki103") @register_model_architecture("transformer_lm", "transformer_lm_baevski_wiki103") def transformer_lm_baevski_wiki103(args): - args.decoder_layers = getattr(args, "decoder_layers", 16) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) - args.dropout = getattr(args, "dropout", 0.3) - args.adaptive_input = getattr(args, "adaptive_input", True) - args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", True) - args.adaptive_input_cutoff = getattr(args, "adaptive_input_cutoff", "20000,60000") - args.adaptive_softmax_cutoff = getattr( + args.decoder_layers = safe_getattr(args, "decoder_layers", 16) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 8) + args.dropout = safe_getattr(args, "dropout", 0.3) + args.adaptive_input = safe_getattr(args, "adaptive_input", True) + args.tie_adaptive_weights = safe_getattr(args, "tie_adaptive_weights", True) + args.adaptive_input_cutoff = safe_getattr(args, "adaptive_input_cutoff", "20000,60000") + args.adaptive_softmax_cutoff = safe_getattr( args, "adaptive_softmax_cutoff", "20000,60000" ) - args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0.2) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_dropout = getattr(args, "activation_dropout", 0.1) - args.no_decoder_final_norm = getattr(args, "no_decoder_final_norm", True) - args.tie_adaptive_proj = getattr(args, "tie_adaptive_proj", True) + args.adaptive_softmax_dropout = safe_getattr(args, "adaptive_softmax_dropout", 0.2) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.activation_dropout = safe_getattr(args, "activation_dropout", 0.1) + args.no_decoder_final_norm = safe_getattr(args, "no_decoder_final_norm", True) + args.tie_adaptive_proj = safe_getattr(args, "tie_adaptive_proj", True) transformer_lm_big(args) @register_model_architecture("transformer_lm", "transformer_lm_gbw") @register_model_architecture("transformer_lm", "transformer_lm_baevski_gbw") def transformer_lm_baevski_gbw(args): - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.no_decoder_final_norm = getattr(args, "no_decoder_final_norm", True) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 512) + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.no_decoder_final_norm = safe_getattr(args, "no_decoder_final_norm", True) transformer_lm_big(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt") def transformer_lm_gpt(args): - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 768) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 3072) - args.decoder_layers = getattr(args, "decoder_layers", 12) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 12) - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_fn = getattr(args, "activation_fn", "gelu") + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 768) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", 3072) + args.decoder_layers = safe_getattr(args, "decoder_layers", 12) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 12) + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.activation_fn = safe_getattr(args, "activation_fn", "gelu") base_lm_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt2_small") def transformer_lm_gpt2_small(args): - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4096) - args.decoder_layers = getattr(args, "decoder_layers", 24) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_fn = getattr(args, "activation_fn", "gelu") + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 1024) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", 4096) + args.decoder_layers = safe_getattr(args, "decoder_layers", 24) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 16) + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.activation_fn = safe_getattr(args, "activation_fn", "gelu") base_lm_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt2_tiny") def transformer_lm_gpt2_tiny(args): - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 64) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 64) - args.decoder_layers = getattr(args, "decoder_layers", 2) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 1) - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_fn = getattr(args, "activation_fn", "gelu") + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 64) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", 64) + args.decoder_layers = safe_getattr(args, "decoder_layers", 2) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 1) + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.activation_fn = safe_getattr(args, "activation_fn", "gelu") base_lm_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt2_medium") def transformer_lm_gpt2_medium(args): - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1280) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 5120) - args.decoder_layers = getattr(args, "decoder_layers", 36) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 20) - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_fn = getattr(args, "activation_fn", "gelu") + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 1280) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", 5120) + args.decoder_layers = safe_getattr(args, "decoder_layers", 36) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 20) + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.activation_fn = safe_getattr(args, "activation_fn", "gelu") base_lm_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt2_big") def transformer_lm_gpt2_big(args): - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1600) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 6400) - args.decoder_layers = getattr(args, "decoder_layers", 48) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 25) - args.dropout = getattr(args, "dropout", 0.1) - args.attention_dropout = getattr(args, "attention_dropout", 0.1) - args.activation_fn = getattr(args, "activation_fn", "gelu") + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 1600) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", 6400) + args.decoder_layers = safe_getattr(args, "decoder_layers", 48) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 25) + args.dropout = safe_getattr(args, "dropout", 0.1) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.1) + args.activation_fn = safe_getattr(args, "activation_fn", "gelu") base_lm_architecture(args) def base_gpt3_architecture(args): args.decoder_input_dim = args.decoder_embed_dim args.decoder_output_dim = args.decoder_embed_dim - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", args.decoder_embed_dim * 4) + args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", args.decoder_embed_dim * 4) # GPT-3 used learned positional embeddings, rather than sinusoidal - args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) - args.dropout = getattr(args, "dropout", 0.0) - args.attention_dropout = getattr(args, "attention_dropout", 0.0) - args.activation_fn = getattr(args, "activation_fn", "gelu") + args.decoder_learned_pos = safe_getattr(args, "decoder_learned_pos", True) + args.dropout = safe_getattr(args, "dropout", 0.0) + args.attention_dropout = safe_getattr(args, "attention_dropout", 0.0) + args.activation_fn = safe_getattr(args, "activation_fn", "gelu") args.share_decoder_input_output_embed = True base_lm_architecture(args) @@ -475,70 +476,70 @@ def base_gpt3_architecture(args): @register_model_architecture("transformer_lm", "transformer_lm_gpt3_small") def transformer_lm_gpt3_small(args): # 125M params - args.decoder_layers = getattr(args, "decoder_layers", 12) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 768) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 12) + args.decoder_layers = safe_getattr(args, "decoder_layers", 12) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 768) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 12) base_gpt3_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt3_medium") def transformer_lm_gpt3_medium(args): # 350M params - args.decoder_layers = getattr(args, "decoder_layers", 24) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + args.decoder_layers = safe_getattr(args, "decoder_layers", 24) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 1024) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 16) base_gpt3_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt3_large") def transformer_lm_gpt3_large(args): # 760M params - args.decoder_layers = getattr(args, "decoder_layers", 24) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1536) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + args.decoder_layers = safe_getattr(args, "decoder_layers", 24) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 1536) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 16) base_gpt3_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt3_xl") def transformer_lm_gpt3_xl(args): # 1.3B params - args.decoder_layers = getattr(args, "decoder_layers", 24) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 2048) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) + args.decoder_layers = safe_getattr(args, "decoder_layers", 24) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 2048) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 32) base_gpt3_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt3_2_7") def transformer_lm_gpt3_2_7(args): # 2.7B params - args.decoder_layers = getattr(args, "decoder_layers", 32) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 2560) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) + args.decoder_layers = safe_getattr(args, "decoder_layers", 32) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 2560) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 32) base_gpt3_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt3_6_7") def transformer_lm_gpt3_6_7(args): # 6.7B params - args.decoder_layers = getattr(args, "decoder_layers", 32) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 4096) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) + args.decoder_layers = safe_getattr(args, "decoder_layers", 32) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 4096) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 32) base_gpt3_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt3_13") def transformer_lm_gpt3_13(args): # 13B params - args.decoder_layers = getattr(args, "decoder_layers", 40) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 5120) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 40) + args.decoder_layers = safe_getattr(args, "decoder_layers", 40) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 5120) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 40) base_gpt3_architecture(args) @register_model_architecture("transformer_lm", "transformer_lm_gpt3_175") def transformer_lm_gpt3_175(args): # 175B params - args.decoder_layers = getattr(args, "decoder_layers", 96) - args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 12288) - args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 96) + args.decoder_layers = safe_getattr(args, "decoder_layers", 96) + args.decoder_embed_dim = safe_getattr(args, "decoder_embed_dim", 12288) + args.decoder_attention_heads = safe_getattr(args, "decoder_attention_heads", 96) base_gpt3_architecture(args) diff --git a/fairseq/utils.py b/fairseq/utils.py index 623ff87a8c..f61a8d38d4 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -812,3 +812,18 @@ def reset_logging(): ) ) root.addHandler(handler) + + +def safe_getattr(obj, k, default=None): + """Returns obj[k] if it exists and is not None, otherwise returns default.""" + from omegaconf import OmegaConf + + if OmegaConf.is_config(obj): + return obj[k] if k in obj and obj[k] is not None else default + + return getattr(obj, k, default) + + +def safe_hasattr(obj, k): + """Returns True if the given key exists and is not None.""" + return getattr(obj, k, None) is not None From c0d098eafa3638301107e2cff7d3be03a936e8f5 Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Thu, 30 Sep 2021 10:01:42 -0700 Subject: [PATCH 465/774] Update speech_text_joint_to_text example to the latest fairseq Summary: There are mismatches for the code in speech_text_joint_to_text example and the code in the latest fairseq codebase 1. import task class twice 2. newly added TransformerEncoderLayerBase is equal to TransformerEncoderLayer 3. Wav2VecEncoder API change (wav2vec2_asr.py) Reviewed By: kahne Differential Revision: D31299458 fbshipit-source-id: 6eb64e2692ca3c2729248d55ccefe74283fe4ef0 --- examples/speech_text_joint_to_text/docs/ende-mustc.md | 6 +++--- examples/speech_text_joint_to_text/docs/iwslt2021.md | 4 ++-- examples/speech_text_joint_to_text/models/__init__.py | 6 ------ .../models/s2t_dualinputtransformer.py | 4 +++- .../models/s2t_dualinputxmtransformer.py | 6 ++---- examples/speech_text_joint_to_text/tasks/__init__.py | 4 ---- 6 files changed, 10 insertions(+), 20 deletions(-) diff --git a/examples/speech_text_joint_to_text/docs/ende-mustc.md b/examples/speech_text_joint_to_text/docs/ende-mustc.md index 2897c4e27b..e47ff3c550 100644 --- a/examples/speech_text_joint_to_text/docs/ende-mustc.md +++ b/examples/speech_text_joint_to_text/docs/ende-mustc.md @@ -12,8 +12,8 @@ Enhanced Joint Training: the joint training is enhanced with pre-trained models, - Dictionary [dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/dict.txt) - config [config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/config.yaml) #### Prepare MuST-C data set -- [Please follow the data preparation in the S2T example](https://github.com/pytorch/fairseq/blob/main/examples/speech_to_text/docs/mustc_example.md) -- Append src_text in the tsv file with phoneme representation. +- Please follow the data preparation in the [S2T example](https://github.com/pytorch/fairseq/blob/main/examples/speech_to_text/docs/mustc_example.md) +- Convert source text under the "src_text" column in the tsv file into phoneme representation. ```bash python examples/speech_text_joint_to_text/scripts/g2p_encode.py \ --lower-case --do-filter --use-word-start --no-punc \ @@ -21,7 +21,7 @@ Enhanced Joint Training: the joint training is enhanced with pre-trained models, --data-path ${must_c_en_de_src_text} \ --out-path ${must_c_en_de_src_text_pho} ``` -- Update tsv data with src_text generated above and save to $MANIFEST_ROOT +- Replace the source text under the "src_text" column in the tsv file with the corresponding phoneme reprentation generated in the step above. - Prepare phoneme dictionary and save to $MANIFEST_ROOT as [src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/src_dict.txt) #### Prepare WMT text data - [Download wmt data](https://github.com/pytorch/fairseq/blob/main/examples/translation/prepare-wmt14en2de.sh) diff --git a/examples/speech_text_joint_to_text/docs/iwslt2021.md b/examples/speech_text_joint_to_text/docs/iwslt2021.md index 920ff271c2..0af0fbff1b 100644 --- a/examples/speech_text_joint_to_text/docs/iwslt2021.md +++ b/examples/speech_text_joint_to_text/docs/iwslt2021.md @@ -11,8 +11,8 @@ This directory contains the code from paper ["FST: the FAIR Speech Translation S - Config [config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/iwslt/iwslt_data/config.yaml) #### Prepare -- [Please follow the data preparation in speech-to-text](https://github.com/pytorch/fairseq/blob/main/examples/speech_to_text/docs/mtedx_example.md) - +- Please follow the data preparation in [speech-to-text](https://github.com/pytorch/fairseq/blob/main/examples/speech_to_text/docs/mtedx_example.md) with option "--use-audio-input" for raw audio tsv files. +- Prepare tsv files with phoneme based source text (under column 'src_text') as [MuST-C](ende-mustc.md) example. ## Training diff --git a/examples/speech_text_joint_to_text/models/__init__.py b/examples/speech_text_joint_to_text/models/__init__.py index 7a394c7e4f..5fc5d9e21b 100644 --- a/examples/speech_text_joint_to_text/models/__init__.py +++ b/examples/speech_text_joint_to_text/models/__init__.py @@ -6,9 +6,3 @@ import importlib import os -for file in os.listdir(os.path.dirname(__file__)): - if file.endswith(".py") and not file.startswith("_"): - model_name = file[: file.find(".py")] - importlib.import_module( - "examples.speech_text_joint_to_text.models." + model_name - ) diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py index 7970a3c714..f643b98265 100644 --- a/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py @@ -265,7 +265,9 @@ def build_text_encoder(cls, args, src_dictionary, spch_encoder): spch_encoder.transformer_layers[-args.encoder_shared_layers :] ): ly_id = i + args.text_encoder_layers - args.encoder_shared_layers - assert isinstance(text_encoder.layers[ly_id], type(ly)) + if not isinstance(text_encoder.layers[ly_id], type(ly)): + if text_encoder.layers[ly_id]._get_name() not in ('TransformerEncoderLayerBase', 'TransformerEncoderLayer'): + raise ValueError("The shared layers are expected from the same class") text_encoder.layers[ly_id] = cls.set_shared_layer( args.encoder_shared_layer_level, text_encoder.layers[ly_id], diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py index 50683e6d7c..41ec2bdb4d 100644 --- a/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py @@ -150,10 +150,8 @@ def forward(self, src_tokens, src_lengths=None, return_all_hiddens=False, **kwar out = self.w2v_encoder.forward(src_tokens, padding_mask, tbc=True) x = out["encoder_out"] enc_padding_mask = None - if out["encoder_padding_mask"] is not None: - enc_padding_mask = out["encoder_padding_mask"].transpose( - 0, 1 - ) # T X B --> B X T + if out["padding_mask"] is not None: + enc_padding_mask = out["padding_mask"] # B X T x, enc_padding_mask = self.adaptor(x, enc_padding_mask) encoder_states = [] diff --git a/examples/speech_text_joint_to_text/tasks/__init__.py b/examples/speech_text_joint_to_text/tasks/__init__.py index d878278475..5fc5d9e21b 100644 --- a/examples/speech_text_joint_to_text/tasks/__init__.py +++ b/examples/speech_text_joint_to_text/tasks/__init__.py @@ -6,7 +6,3 @@ import importlib import os -for file in os.listdir(os.path.dirname(__file__)): - if file.endswith(".py") and not file.startswith("_"): - task_name = file[: file.find(".py")] - importlib.import_module("examples.speech_text_joint_to_text.tasks." + task_name) From 666d8c26e1feb4fa1fa5369f15086999f64744e0 Mon Sep 17 00:00:00 2001 From: Po-Yao Huang <berniehuang@fb.com> Date: Thu, 30 Sep 2021 14:13:12 -0700 Subject: [PATCH 466/774] MMPT (#2373) Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Release the code and model for two of our papers at FAIR: 1. VideoCLIP: Contrastive Pre-training for Zero-shot Video-Text Understanding (Xu et. al., EMNLP 2021) 2. VLM: Task-agnostic Video-Language Model Pre-training for Video Understanding (Xu et. al., ACL Findings 2021) ## PR review dianaml0 (Diana Liskovich, referred by Myle Ott) ## Did you have fun? Yes! {emoji:1f44d} Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2373 Reviewed By: dianaml0 Differential Revision: D31278832 Pulled By: berniebear fbshipit-source-id: b6a0fad4caf44b062be0c46c12842b26792b35a3 --- examples/MMPT/.gitignore | 138 +++ examples/MMPT/CONFIG.md | 41 + examples/MMPT/DATASET.md | 34 + examples/MMPT/README.md | 166 +++ examples/MMPT/endtask.md | 41 + examples/MMPT/locallaunch.py | 148 +++ examples/MMPT/mmpt/__init__.py | 12 + examples/MMPT/mmpt/datasets/__init__.py | 10 + .../MMPT/mmpt/datasets/fairseqmmdataset.py | 57 + examples/MMPT/mmpt/datasets/mmdataset.py | 111 ++ examples/MMPT/mmpt/evaluators/__init__.py | 13 + examples/MMPT/mmpt/evaluators/evaluator.py | 54 + examples/MMPT/mmpt/evaluators/metric.py | 313 ++++++ examples/MMPT/mmpt/evaluators/predictor.py | 595 +++++++++++ examples/MMPT/mmpt/losses/__init__.py | 16 + examples/MMPT/mmpt/losses/fairseqmmloss.py | 63 ++ examples/MMPT/mmpt/losses/loss.py | 87 ++ examples/MMPT/mmpt/losses/nce.py | 156 +++ examples/MMPT/mmpt/models/__init__.py | 17 + examples/MMPT/mmpt/models/fairseqmmmodel.py | 51 + examples/MMPT/mmpt/models/mmfusion.py | 920 ++++++++++++++++ examples/MMPT/mmpt/models/mmfusionnlg.py | 999 ++++++++++++++++++ examples/MMPT/mmpt/models/transformermodel.py | 734 +++++++++++++ examples/MMPT/mmpt/modules/__init__.py | 10 + examples/MMPT/mmpt/modules/mm.py | 145 +++ examples/MMPT/mmpt/modules/retri.py | 429 ++++++++ examples/MMPT/mmpt/modules/vectorpool.py | 246 +++++ examples/MMPT/mmpt/processors/__init__.py | 23 + .../MMPT/mmpt/processors/dedupprocessor.py | 242 +++++ examples/MMPT/mmpt/processors/dsprocessor.py | 836 +++++++++++++++ .../MMPT/mmpt/processors/how2processor.py | 887 ++++++++++++++++ .../mmpt/processors/how2retriprocessor.py | 100 ++ examples/MMPT/mmpt/processors/models/s3dg.py | 336 ++++++ examples/MMPT/mmpt/processors/processor.py | 274 +++++ examples/MMPT/mmpt/tasks/__init__.py | 22 + examples/MMPT/mmpt/tasks/fairseqmmtask.py | 92 ++ examples/MMPT/mmpt/tasks/milncetask.py | 27 + examples/MMPT/mmpt/tasks/retritask.py | 253 +++++ examples/MMPT/mmpt/tasks/task.py | 184 ++++ examples/MMPT/mmpt/tasks/vlmtask.py | 27 + examples/MMPT/mmpt/utils/__init__.py | 68 ++ examples/MMPT/mmpt/utils/load_config.py | 81 ++ examples/MMPT/mmpt/utils/shardedtensor.py | 46 + examples/MMPT/mmpt_cli/localjob.py | 117 ++ examples/MMPT/mmpt_cli/predict.py | 113 ++ examples/MMPT/pretraining.md | 29 + examples/MMPT/projects/mfmmlm.yaml | 59 ++ examples/MMPT/projects/mtm/mmfusionmtm.yaml | 19 + examples/MMPT/projects/mtm/vlm.yaml | 8 + examples/MMPT/projects/mtm/vlm/coin.yaml | 46 + examples/MMPT/projects/mtm/vlm/crosstask.yaml | 52 + examples/MMPT/projects/mtm/vlm/how2.yaml | 52 + examples/MMPT/projects/mtm/vlm/test_coin.yaml | 31 + .../MMPT/projects/mtm/vlm/test_crosstask.yaml | 38 + .../projects/mtm/vlm/test_crosstask_zs.yaml | 38 + examples/MMPT/projects/mtm/vlm/test_vtt.yaml | 29 + .../MMPT/projects/mtm/vlm/test_vttqa.yaml | 29 + .../MMPT/projects/mtm/vlm/test_youcook.yaml | 31 + .../projects/mtm/vlm/test_youcookcap.yaml | 32 + examples/MMPT/projects/mtm/vlm/vtt.yaml | 48 + examples/MMPT/projects/mtm/vlm/vttqa.yaml | 46 + examples/MMPT/projects/mtm/vlm/youcook.yaml | 46 + .../MMPT/projects/mtm/vlm/youcookcap.yaml | 44 + examples/MMPT/projects/retri/videoclip.yaml | 10 + .../retri/videoclip/coin_videoclip.yaml | 48 + .../retri/videoclip/crosstask_videoclip.yaml | 54 + .../MMPT/projects/retri/videoclip/how2.yaml | 62 ++ .../retri/videoclip/test_coin_videoclip.yaml | 33 + .../retri/videoclip/test_coin_zs.yaml | 33 + .../videoclip/test_crosstask_videoclip.yaml | 40 + .../test_crosstask_zs_videoclip.yaml | 40 + .../retri/videoclip/test_didemo_zs.yaml | 31 + .../retri/videoclip/test_vtt_videoclip.yaml | 31 + .../projects/retri/videoclip/test_vtt_zs.yaml | 31 + .../retri/videoclip/test_vttqa_videoclip.yaml | 31 + .../retri/videoclip/test_vttqa_zs.yaml | 31 + .../videoclip/test_youcook_videoclip.yaml | 33 + .../retri/videoclip/test_youcook_zs.yaml | 33 + .../retri/videoclip/vtt_videoclip.yaml | 50 + .../retri/videoclip/vttqa_videoclip.yaml | 48 + .../retri/videoclip/youcook_videoclip.yaml | 48 + examples/MMPT/projects/retri/videoretri.yaml | 51 + examples/MMPT/projects/task/coin.yaml | 25 + .../MMPT/projects/task/coin_videoclip.yaml | 7 + examples/MMPT/projects/task/crosstask.yaml | 31 + .../projects/task/crosstask_videoclip.yaml | 10 + examples/MMPT/projects/task/default.yaml | 19 + examples/MMPT/projects/task/ft.yaml | 13 + examples/MMPT/projects/task/how2.yaml | 22 + examples/MMPT/projects/task/test.yaml | 13 + examples/MMPT/projects/task/test_coin.yaml | 24 + .../projects/task/test_coin_videoclip.yaml | 7 + examples/MMPT/projects/task/test_coin_zs.yaml | 13 + .../MMPT/projects/task/test_crosstask.yaml | 32 + .../task/test_crosstask_videoclip.yaml | 7 + .../MMPT/projects/task/test_crosstask_zs.yaml | 32 + .../task/test_crosstask_zs_videoclip.yaml | 7 + .../MMPT/projects/task/test_didemo_zs.yaml | 23 + examples/MMPT/projects/task/test_vtt.yaml | 19 + .../projects/task/test_vtt_videoclip.yaml | 8 + examples/MMPT/projects/task/test_vtt_zs.yaml | 13 + examples/MMPT/projects/task/test_vttqa.yaml | 20 + .../projects/task/test_vttqa_videoclip.yaml | 8 + .../MMPT/projects/task/test_vttqa_zs.yaml | 13 + examples/MMPT/projects/task/test_youcook.yaml | 22 + .../projects/task/test_youcook_videoclip.yaml | 8 + .../MMPT/projects/task/test_youcook_zs.yaml | 13 + .../MMPT/projects/task/test_youcookcap.yaml | 23 + examples/MMPT/projects/task/vtt.yaml | 25 + .../MMPT/projects/task/vtt_videoclip.yaml | 12 + examples/MMPT/projects/task/vttqa.yaml | 23 + .../MMPT/projects/task/vttqa_videoclip.yaml | 10 + examples/MMPT/projects/task/youcook.yaml | 25 + .../MMPT/projects/task/youcook_videoclip.yaml | 9 + examples/MMPT/projects/task/youcookcap.yaml | 23 + .../configs/bert-base-uncased.yaml | 5 + .../text_token_extractor/pretokenization.py | 106 ++ .../video_feature_extractor/extract.py | 157 +++ .../video_feature_extractor/how2/s3d.sh | 8 + .../scripts/video_feature_extractor/model.py | 58 + .../video_feature_extractor/pathbuilder.py | 89 ++ .../video_feature_extractor/preprocessing.py | 57 + .../random_sequence_shuffler.py | 29 + .../video_feature_extractor/shard_feature.py | 64 ++ .../video_feature_extractor/videoreader.py | 242 +++++ examples/MMPT/setup.py | 24 + examples/MMPT/videoclip.png | Bin 0 -> 385871 bytes examples/MMPT/vlm.png | Bin 0 -> 418405 bytes 128 files changed, 12147 insertions(+) create mode 100644 examples/MMPT/.gitignore create mode 100644 examples/MMPT/CONFIG.md create mode 100644 examples/MMPT/DATASET.md create mode 100644 examples/MMPT/README.md create mode 100644 examples/MMPT/endtask.md create mode 100644 examples/MMPT/locallaunch.py create mode 100644 examples/MMPT/mmpt/__init__.py create mode 100644 examples/MMPT/mmpt/datasets/__init__.py create mode 100644 examples/MMPT/mmpt/datasets/fairseqmmdataset.py create mode 100644 examples/MMPT/mmpt/datasets/mmdataset.py create mode 100644 examples/MMPT/mmpt/evaluators/__init__.py create mode 100644 examples/MMPT/mmpt/evaluators/evaluator.py create mode 100644 examples/MMPT/mmpt/evaluators/metric.py create mode 100644 examples/MMPT/mmpt/evaluators/predictor.py create mode 100644 examples/MMPT/mmpt/losses/__init__.py create mode 100644 examples/MMPT/mmpt/losses/fairseqmmloss.py create mode 100644 examples/MMPT/mmpt/losses/loss.py create mode 100644 examples/MMPT/mmpt/losses/nce.py create mode 100644 examples/MMPT/mmpt/models/__init__.py create mode 100644 examples/MMPT/mmpt/models/fairseqmmmodel.py create mode 100644 examples/MMPT/mmpt/models/mmfusion.py create mode 100644 examples/MMPT/mmpt/models/mmfusionnlg.py create mode 100644 examples/MMPT/mmpt/models/transformermodel.py create mode 100644 examples/MMPT/mmpt/modules/__init__.py create mode 100644 examples/MMPT/mmpt/modules/mm.py create mode 100644 examples/MMPT/mmpt/modules/retri.py create mode 100644 examples/MMPT/mmpt/modules/vectorpool.py create mode 100644 examples/MMPT/mmpt/processors/__init__.py create mode 100644 examples/MMPT/mmpt/processors/dedupprocessor.py create mode 100644 examples/MMPT/mmpt/processors/dsprocessor.py create mode 100644 examples/MMPT/mmpt/processors/how2processor.py create mode 100644 examples/MMPT/mmpt/processors/how2retriprocessor.py create mode 100644 examples/MMPT/mmpt/processors/models/s3dg.py create mode 100644 examples/MMPT/mmpt/processors/processor.py create mode 100644 examples/MMPT/mmpt/tasks/__init__.py create mode 100644 examples/MMPT/mmpt/tasks/fairseqmmtask.py create mode 100644 examples/MMPT/mmpt/tasks/milncetask.py create mode 100644 examples/MMPT/mmpt/tasks/retritask.py create mode 100644 examples/MMPT/mmpt/tasks/task.py create mode 100644 examples/MMPT/mmpt/tasks/vlmtask.py create mode 100644 examples/MMPT/mmpt/utils/__init__.py create mode 100644 examples/MMPT/mmpt/utils/load_config.py create mode 100644 examples/MMPT/mmpt/utils/shardedtensor.py create mode 100644 examples/MMPT/mmpt_cli/localjob.py create mode 100644 examples/MMPT/mmpt_cli/predict.py create mode 100644 examples/MMPT/pretraining.md create mode 100644 examples/MMPT/projects/mfmmlm.yaml create mode 100644 examples/MMPT/projects/mtm/mmfusionmtm.yaml create mode 100644 examples/MMPT/projects/mtm/vlm.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/coin.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/crosstask.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/how2.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/test_coin.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/test_crosstask.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/test_crosstask_zs.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/test_vtt.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/test_vttqa.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/test_youcook.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/test_youcookcap.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/vtt.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/vttqa.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/youcook.yaml create mode 100644 examples/MMPT/projects/mtm/vlm/youcookcap.yaml create mode 100644 examples/MMPT/projects/retri/videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/how2.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_coin_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_coin_zs.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_crosstask_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_crosstask_zs_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_didemo_zs.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_vtt_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_vtt_zs.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_vttqa_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_vttqa_zs.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_youcook_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/test_youcook_zs.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml create mode 100644 examples/MMPT/projects/retri/videoretri.yaml create mode 100644 examples/MMPT/projects/task/coin.yaml create mode 100644 examples/MMPT/projects/task/coin_videoclip.yaml create mode 100644 examples/MMPT/projects/task/crosstask.yaml create mode 100644 examples/MMPT/projects/task/crosstask_videoclip.yaml create mode 100644 examples/MMPT/projects/task/default.yaml create mode 100644 examples/MMPT/projects/task/ft.yaml create mode 100644 examples/MMPT/projects/task/how2.yaml create mode 100644 examples/MMPT/projects/task/test.yaml create mode 100644 examples/MMPT/projects/task/test_coin.yaml create mode 100644 examples/MMPT/projects/task/test_coin_videoclip.yaml create mode 100644 examples/MMPT/projects/task/test_coin_zs.yaml create mode 100644 examples/MMPT/projects/task/test_crosstask.yaml create mode 100644 examples/MMPT/projects/task/test_crosstask_videoclip.yaml create mode 100644 examples/MMPT/projects/task/test_crosstask_zs.yaml create mode 100644 examples/MMPT/projects/task/test_crosstask_zs_videoclip.yaml create mode 100644 examples/MMPT/projects/task/test_didemo_zs.yaml create mode 100644 examples/MMPT/projects/task/test_vtt.yaml create mode 100644 examples/MMPT/projects/task/test_vtt_videoclip.yaml create mode 100644 examples/MMPT/projects/task/test_vtt_zs.yaml create mode 100644 examples/MMPT/projects/task/test_vttqa.yaml create mode 100644 examples/MMPT/projects/task/test_vttqa_videoclip.yaml create mode 100644 examples/MMPT/projects/task/test_vttqa_zs.yaml create mode 100644 examples/MMPT/projects/task/test_youcook.yaml create mode 100644 examples/MMPT/projects/task/test_youcook_videoclip.yaml create mode 100644 examples/MMPT/projects/task/test_youcook_zs.yaml create mode 100644 examples/MMPT/projects/task/test_youcookcap.yaml create mode 100644 examples/MMPT/projects/task/vtt.yaml create mode 100644 examples/MMPT/projects/task/vtt_videoclip.yaml create mode 100644 examples/MMPT/projects/task/vttqa.yaml create mode 100644 examples/MMPT/projects/task/vttqa_videoclip.yaml create mode 100644 examples/MMPT/projects/task/youcook.yaml create mode 100644 examples/MMPT/projects/task/youcook_videoclip.yaml create mode 100644 examples/MMPT/projects/task/youcookcap.yaml create mode 100644 examples/MMPT/scripts/text_token_extractor/configs/bert-base-uncased.yaml create mode 100644 examples/MMPT/scripts/text_token_extractor/pretokenization.py create mode 100755 examples/MMPT/scripts/video_feature_extractor/extract.py create mode 100644 examples/MMPT/scripts/video_feature_extractor/how2/s3d.sh create mode 100755 examples/MMPT/scripts/video_feature_extractor/model.py create mode 100644 examples/MMPT/scripts/video_feature_extractor/pathbuilder.py create mode 100755 examples/MMPT/scripts/video_feature_extractor/preprocessing.py create mode 100755 examples/MMPT/scripts/video_feature_extractor/random_sequence_shuffler.py create mode 100644 examples/MMPT/scripts/video_feature_extractor/shard_feature.py create mode 100644 examples/MMPT/scripts/video_feature_extractor/videoreader.py create mode 100644 examples/MMPT/setup.py create mode 100644 examples/MMPT/videoclip.png create mode 100644 examples/MMPT/vlm.png diff --git a/examples/MMPT/.gitignore b/examples/MMPT/.gitignore new file mode 100644 index 0000000000..07fe191048 --- /dev/null +++ b/examples/MMPT/.gitignore @@ -0,0 +1,138 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ +runs +data +pretrained_models +projects/mmfusion_* +log_test +third-party +python_log +slurm_snapshot_code +lightning_logs diff --git a/examples/MMPT/CONFIG.md b/examples/MMPT/CONFIG.md new file mode 100644 index 0000000000..bbd1403dfa --- /dev/null +++ b/examples/MMPT/CONFIG.md @@ -0,0 +1,41 @@ +### Config Files Explained + +Taking `projects/mfmmlm.yaml` for example, which run pretraining using masked frame model (MFM) and masked language model (MLM) on a single BERT: + +```yaml +project_dir: mfmmlm # specify the project dir for this baseline. +run_task: + - how2.yaml # run pretraining on how2 when launching `projects/taskmfmmlm.yaml` + - [vtt.yaml, vttcap.yaml, vttqa.yaml, youcook.yaml, youcookcap.yaml, crosstask.yaml, coin.yaml] # run fine-tuning tasks. +base_dir: task # a global template folder to specify each training task. +task_group: + pretrain: # section for pretraining. Most baselines differs in this section. + task_list: + - how2.yaml # reconfig `projects/task/how2.yaml` + dataset: + aligner: MFMMLMAligner # overwrite the aligner for MFMMLM training task. + model: + model_cls: MMFusionMFMMLM # overwrite the model, which constructs negative examples for MFM on-the-fly. + loss: + loss_cls: MFMMLM # overwrite the loss as MFMMLM, which combines MFM and MLM together. + fairseq: # all fairseq args can be expecified under this name. + dataset: + batch_size: 128 + finetune: # section for fine-tuning tasks, we don't need to change anything here mostly since we want to see how pretraining can contribute to finetuning. + task_list: # specify the list of downstream tasks, e.g., copy `projects/task/vtt.yaml` to `projects/mfmmlm`. + - vtt.yaml + - vttqa.yaml + - youcook.yaml + - youcookcap.yaml + - crosstask.yaml + - coin.yaml + test: # section for testing. + task_list: + - test_vtt.yaml + - test_vttqa.yaml + - test_youcook.yaml + - test_youcookcap.yaml + - test_crosstask.yaml + - test_crosstask_zs.yaml + - test_coin.yaml +``` diff --git a/examples/MMPT/DATASET.md b/examples/MMPT/DATASET.md new file mode 100644 index 0000000000..930403eb36 --- /dev/null +++ b/examples/MMPT/DATASET.md @@ -0,0 +1,34 @@ +# Dataset + +We understand video data are challenging to download and process. For videos, we provide our preprocessing scripts under `scripts/video_feature_extractor` (deeply adapted from `https://github.com/antoine77340/video_feature_extractor`); for text, we pre-tokenizing scripts under `scripts/text_token_extractor`. + +### S3D Feature Extraction +We use pre-trained [S3D](https://github.com/antoine77340/S3D_HowTo100M) for video feature extraction. Please place the models as `pretrained_models/s3d_dict.npy` and `pretrained_models/s3d_howto100m.pth`. + +We implement a `PathBuilder` to automatically track video ids, source video paths to their feature locations (you may need `conda install -c anaconda pandas`). Decoding may need `pip install ffmpeg-python`. + +### Howto100M +[Howto100M](https://www.di.ens.fr/willow/research/howto100m/) is a large-scale video pre-training datasets. You may download videos by yourself and run preprocessing of our scripts. + +Several key differences of our preprocessing from existing papers: (1) we use `raw_caption.json` instead of `caption.json` to have pure self-supervision on text (`caption.json` has manual removal of stop words); (2) we remove partially duplicated texts that are originally designed for real-time readability (see `mmpt/processors/dedupprocessor.py`); (3) then we shard video/text features using `SharedTensor` in `mmpt/utils/shardedtensor.py` for fast loading during training (faster than `h5py`). + +#### Steps +##### video +To extract video features: edit and run `bash scripts/video_feature_extractor/how2/s3d.sh`. (consider to run this on multiple machines; by default, we store features in fp16 to save space and also for faster training). + +Split available video ids as `data/how2/how2_s3d_train.lst` and `data/how2/how2_s3d_val.lst`. + +Lastly, pack video features into `ShardedTensor` using `python scripts/video_feature_extractor/shard_feature.py`. + +##### text +Clean captions using `python -m mmpt.processors.dedupprocessor`. + +Tokenize dedupped captions `data/how2/raw_caption_dedup.pkl` into sharded numpy arrays: +``` +python scripts/text_token_extractor/pretokenization.py scripts/text_token_extractor/configs/bert-base-uncased.yaml +``` + +### Youcook, MSRVTT etc. +We use the version of Youcook and MSRVTT come with Howto100M and MILNCE. Please download the data to `data/youcook` and `data/msrvtt` accordingly, you can also check `projects/task/youcook.yaml` and `projects/task/vtt.yaml` etc. in details. +We extract features for Youcook, MSRVTT similar to the first step of Howto100M but we read text from meta data directly and perform on-the-fly tokenization. + diff --git a/examples/MMPT/README.md b/examples/MMPT/README.md new file mode 100644 index 0000000000..4a84819d9d --- /dev/null +++ b/examples/MMPT/README.md @@ -0,0 +1,166 @@ +# VideoCLIP and VLM + +You just find this toolkit for multimodal video understanding! It contains implementation of two recent multi-modal video understanding papers [VideoCLIP](https://arxiv.org/pdf/2109.14084.pdf) (EMNLP, 2021) and [VLM](https://aclanthology.org/2021.findings-acl.370.pdf) (ACL Findings, 2021), along with high-performance toolkits that are typically lacking in existing codebase. The toolkit is desigend to contain generic performance-tuned components that can be potentially adapted to other frameworks (we initially use fairseq). + +VideoCLIP is a contrastive learning model for zero-shot transfer to retrieval/classification/sequence labeling style tasks. + +<img src="videoclip.png" width="350" class="center"> + +VLM is a masked language model style pre-training using only one encoder with masked modality model (MMM) for retrieval/generation/sequence labeling style tasks. + +<img src="vlm.png" width="350" class="center"> + +### News +[Oct. 2021] Initial release of implementation for the following papers: +[VideoCLIP: Contrastive Pre-training for Zero-shot Video-Text Understanding](https://arxiv.org/pdf/2109.14084.pdf) (Xu et. al., EMNLP 2021) +[VLM: Task-agnostic Video-Language Model Pre-training for Video Understanding](https://aclanthology.org/2021.findings-acl.370.pdf) (Xu et. al., ACL Findings 2021) + + +### Installation +We aim to minimize the dependency of this repo on other packages. +We use fairseq as the main trainer (no models/datasets dependency on fairseq. We will support other trainer in future): +``` +git clone https://github.com/pytorch/fairseq +cd fairseq +pip install -e . # also optionally follow fairseq README for apex installation for fp16 training. +export MKL_THREADING_LAYER=GNU # fairseq may need this for numpy. +``` + +Then install this toolkit: +``` +cd examples/MMPT # MMPT can be in any folder, not necessarily under fairseq/examples. +pip install -e . +``` + +The code is developed under Python=3.8.8, Pytorch=1.8, cuda=11.0 with fairseq=1.0.0a0+af0389f and tested under Python=3.8.8 pytorch=1.9 cuda=11.0 fairseq=1.0.0a0+8e7bc73 during code release. +Most models require `transformers==3.4` for API compatibility `pip install transformers==3.4`. +In addition, some downstream tasks may need `conda install pandas`. + + +### Usage +#### Download Checkpoints +We use pre-trained [S3D](https://github.com/antoine77340/S3D_HowTo100M) for video feature extraction. Please place the models as `pretrained_models/s3d_dict.npy` and `pretrained_models/s3d_howto100m.pth`. + +Download VideoCLIP checkpoint `https://dl.fbaipublicfiles.com/MMPT/retri/videoclip/checkpoint_best.pt` to `runs/retri/videoclip` or VLM checkpoint `https://dl.fbaipublicfiles.com/MMPT/mtm/vlm/checkpoint_best.pt` to `runs/mtm/vlm`. + +#### Demo of Inference +run `python locallaunch.py projects/retri/videoclip.yaml --dryrun` to get all `.yaml`s for VideoCLIP. + +```python +import torch + +from mmpt.models import MMPTModel + + +model, tokenizer, aligner = MMPTModel.from_pretrained( + "projects/retri/videoclip/how2.yaml") + +model.eval() + + +# B, T, FPS, H, W, C (VideoCLIP is trained on 30 fps of s3d) +video_frames = torch.randn(1, 2, 30, 224, 224, 3) +caps, cmasks = aligner._build_text_seq( + tokenizer("some text", add_special_tokens=False)["input_ids"] +) + +caps, cmasks = caps[None, :], cmasks[None, :] # bsz=1 + +with torch.no_grad(): + output = model(video_frames, caps, cmasks, return_score=True) +print(output["score"]) # dot-product +``` + +#### Data Preparation +See [dataset](DATASET.md) for each dataset. + +#### Global Config for Training Pipeline +We organize a global config file for a training/testing pipeline under projects (see a detailed [explanation](CONFIG.md)). For example, VideoCLIP in `projects/retri/videoclip.yaml` and VLM is in `projects/mtm/vlm.yaml`. + +We wrap all cmds into `locallaunch.py` and `mmpt_cli/localjob.py`. You can check concrete cmds by `--dryrun` and then drop it for actual run. + +First, run `python locallaunch.py projects/retri/videoclip.yaml --dryrun` will generate configs for all configs of pre-training, zero-shot evaluation, fine-tuning and testing, for VideoCLIP under `projects/retri/videoclip`. + +Then each (either training or evaluation) process will be configed by a concrete config file (we save all complex arguments into the concrete config file for reproducibility, including fairseq args). For example, run zero-shot evaluation on youcook, +``` +python locallaunch.py projects/retri/videoclip/test_youcook_zs.yaml --jobtype local_predict # zero-shot evaluation. +python locallaunch.py projects/retri/videoclip/youcook_videoclip.yaml --jobtype local_single --dryrun # fine-tuning: use --dryrun to check cmds and drop it to make an actual run; local_small will run on two gpus (as in paper). +python locallaunch.py projects/retri/videoclip/test_youcook_videoclip.yaml --jobtype local_predict # testing on fine-tuned model. +``` + +Pretraining can be run as: +``` +python locallaunch.py projects/retri/videoclip/how2.yaml --jobtype local_single --dryrun # check then drop dryrun; paper is ran on local_big as 8 gpus. +``` +You may need to change `--jobtype`, check/extend `LocalJob` in `mmpt_cli/localjob.py` for multi-gpu/multi-node pre-training. + +The detailed instructions of pretraining and fine-tuning can be found at [pretraining instruction](pretraining.md) and [finetuning instruction](endtask.md). + + +### Development +Several components of this toolkit can be re-used for future research (and also our ongoing research). + +#### Framework Wrapper +We currently only support fairseq, but most components can be easily fit into other frameworks like huggingface. This repo is a `--user-dir` of fairseq with fairseq wrapper. For example, `mmpt/tasks` includes a `FairseqMMTTask`, which manages `mmpt/datasets` with `FairseqDataset`, `mmpt/models` with `FairseqModel`, `mmpt/losses` with `FairseqCriterion`. + +#### Processors +**Multi**modal research introduces the complexity on modality alignment from different input sources to losses. Inspired by [MMF](https://github.com/facebookresearch/mmf), this toolkit leverages `mmpt/processors` to handle various needs of data preprocessing and loading, **alleviating** the needs of multiple `torch.data.utils.Dataset` (that can be tricky for ablation study). +Processors can also be decoupled from `torch.data.utils.Dataset` for offline preprocessing instead of on-the-fly data preprocessing. + +We decouple a `mmpt.MMDataset` as 3 types of processors: `MetaProcessor`, `VideoProcessor`, `TextProcessor` and `Aligner`. They can be configed in `dataset` field of a config file (e.g., see `projects/task/how2.yaml`). +`MetaProcessor` is used to load the meta data about a dataset, aka, all video_ids of how2 dataset. +`VideoProcessor` is used to load the video features about a dataset. For example, S3D features for each second of a video. +`TextProcessor` is used to load the text (feature). For example, BERT pre-tokenized text clips for how2 dataset (with `start`s, `end`s of timestamps and `cap` for `token_ids`). +`Aligner` is the core class for different baselines that prepares the training data. For example, sampling a clip, masking tokens for MLM, etc. + +#### Performance-tuned Components +To speed up pre-training, this toolkit uses sharded features stored in mmaped numpy, backed by `ShardedTensor` in `mmpt/utils/shardedtensor.py` (adopted from MARGE paper). This reduces the loads of IO for multi-GPU training without loading all features for a video into the memory each time and `ShardedTensor` ensure features are stored in continuous disk space for near random access. This is used for both How2 video features and texts in `mmpt/processors/how2processor.py`. + + +### Citation +If this codebase is useful for your work, please cite the following papers: + +```BibTeX +@inproceedings{xu-etal-2021-videoclip, + title = "{VideoCLIP}: Contrastive Pre-training for\\Zero-shot Video-Text Understanding", + author = "Xu, Hu and + Ghosh, Gargi and + Huang, Po-Yao and + Okhonko, Dmytro and + Aghajanyan, Armen and + Metze, Florian and + Zettlemoyer, Luke and + Feichtenhofer, Christoph", + booktitle = "Proceedings of the 2021 Conference on Empirical Methods in Natural Language Processing (EMNLP)", + month = nov, + year = "2021", + address = "Online", + publisher = "Association for Computational Linguistics", +} + +@inproceedings{xu-etal-2021-vlm, + title = "{VLM}: Task-agnostic Video-Language Model Pre-training for Video Understanding", + author = "Xu, Hu and + Ghosh, Gargi and + Huang, Po-Yao and + Arora, Prahal and + Aminzadeh, Masoumeh and + Feichtenhofer, Christoph and + Metze, Florian and + Zettlemoyer, Luke", + booktitle = "Findings of the Association for Computational Linguistics: ACL-IJCNLP 2021", + month = aug, + year = "2021", + address = "Online", + publisher = "Association for Computational Linguistics", + url = "https://aclanthology.org/2021.findings-acl.370", + doi = "10.18653/v1/2021.findings-acl.370", + pages = "4227--4239", +} +``` + +### Bug Reports +This repo is in its initial stage, welcome bug reports to huxu@fb.com + +### Copyright +The majority of Multimodal Pre-training (MMPT) is licensed under CC-BY-NC, however portions of the project are available under separate license terms: Evaluation Codes/Models: Howto100M and HuggingFace Transformers are licensed under the Apache2.0 license; COIN and NLG-eval are licensed under the MIT license; CrossTask is licensed under the BSD-3; DiDeMo is licensed under the BSD-2 license. diff --git a/examples/MMPT/endtask.md b/examples/MMPT/endtask.md new file mode 100644 index 0000000000..7690955327 --- /dev/null +++ b/examples/MMPT/endtask.md @@ -0,0 +1,41 @@ +# Zero-shot Transfer and Finetuning + +(If you are new to the ideas of `mmpt.processors`, see [README](README.md) first.) +All finetuning datasets (specifically `processors`) are defined in `mmpt.processors.dsprocessor`. +Given the complexity of different types of finetuning tasks, each task may have their own meta/video/text/aligner processors and `mmpt/evaluators/{Predictor,Metric}`. + +### Tasks + +Currently, we support 5 end datasets: `MSRVTT`, `Youcook`, `COIN`, `Crosstask` and `DiDeMo` with the following tasks: +text-video retrieval: `MSRVTT`, `Youcook`, `DiDeMo`; +video captioning: `Youcook`; +Video Question and Answering: `MSRVTT-QA`. + +To add your own dataset, you can specify the corresponding processors and config them in the `dataset` field of a config file, such as `projects/task/vtt.yaml`. + +### Zero-shot Transfer (no Training) +Zero-shot transfer will run the pre-trained model (e.g., VideoCLIP) directly on testing data. Configs with pattern: `projects/task/*_zs_*.yaml` are dedicated for zero-shot transfer. + +### Fine-tuning + +The training of a downstream task is similar to pretraining, execept you may need to specify the `restore_file` in `fairseq.checkpoint` and reset optimizers, see `projects/task/ft.yaml` that is included by `projects/task/vtt.yaml`. + +We typically do finetuning on 2 gpus (`local_small`). + +### Testing +For each finetuning dataset, you may need to specify a testing config, similar to `projects/task/test_vtt.yaml`. + +We define `mmpt.evaluators.Predictor` for different types of prediction. For example, `MSRVTT` and `Youcook` are video-retrieval tasks and expecting to use `RetrievalPredictor`. You may need to define your new type of predictors and specify that in `predictor` field of a testing config. + +Each task may also have their own metric for evaluation. This can be created in `mmpt.evaluators.Metric` and specified in the `metric` field of a testing config. + +Launching a testing is as simple as training by specifying the path of a testing config: +```python locallaunch.py projects/mfmmlm/test_vtt.yaml``` +Testing will be launched locally by default since prediction is computationally less expensive. + +### Third-party Libraries +We list the following finetuning tasks that require third-party libraries. + +Youcook captioning: `https://github.com/Maluuba/nlg-eval` + +CrossTask: `https://github.com/DmZhukov/CrossTask`'s `dp` under `third-party/CrossTask` (`python setup.py build_ext --inplace`) diff --git a/examples/MMPT/locallaunch.py b/examples/MMPT/locallaunch.py new file mode 100644 index 0000000000..e20fd816fa --- /dev/null +++ b/examples/MMPT/locallaunch.py @@ -0,0 +1,148 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import argparse +import os + +from omegaconf import OmegaConf + +from mmpt.utils import recursive_config, overwrite_dir +from mmpt_cli.localjob import LocalJob + + +class JobLauncher(object): + JOB_CONFIG = { + "local": LocalJob, + } + + def __init__(self, yaml_file): + self.yaml_file = yaml_file + job_key = "local" + + if yaml_file.endswith(".yaml"): + config = recursive_config(yaml_file) + if config.task_type is not None: + job_key = config.task_type.split("_")[0] + else: + raise ValueError("unknown extension of job file:", yaml_file) + self.job_key = job_key + + def __call__(self, job_type=None, dryrun=False): + if job_type is not None: + self.job_key = job_type.split("_")[0] + print("[JobLauncher] job_key", self.job_key) + job = JobLauncher.JOB_CONFIG[self.job_key]( + self.yaml_file, job_type=job_type, dryrun=dryrun) + return job.submit() + + +class Pipeline(object): + """a job that loads yaml config.""" + + def __init__(self, fn): + """ + load a yaml config of a job and save generated configs as yaml for each task. + return: a list of files to run as specified by `run_task`. + """ + if fn.endswith(".py"): + # a python command. + self.backend = "python" + self.run_yamls = [fn] + return + + job_config = recursive_config(fn) + if job_config.base_dir is None: # single file job config. + self.run_yamls = [fn] + return + + self.project_dir = os.path.join("projects", job_config.project_dir) + self.run_dir = os.path.join("runs", job_config.project_dir) + + if job_config.run_task is not None: + run_yamls = [] + for stage in job_config.run_task: + # each stage can have multiple tasks running in parallel. + if OmegaConf.is_list(stage): + stage_yamls = [] + for task_file in stage: + stage_yamls.append( + os.path.join(self.project_dir, task_file)) + run_yamls.append(stage_yamls) + else: + run_yamls.append(os.path.join(self.project_dir, stage)) + self.run_yamls = run_yamls + configs_to_save = self._overwrite_task(job_config) + self._save_configs(configs_to_save) + + def __getitem__(self, idx): + yaml_files = self.run_yamls[idx] + if isinstance(yaml_files, list): + return [JobLauncher(yaml_file) for yaml_file in yaml_files] + return [JobLauncher(yaml_files)] + + def __len__(self): + return len(self.run_yamls) + + def _save_configs(self, configs_to_save: dict): + # save + os.makedirs(self.project_dir, exist_ok=True) + for config_file in configs_to_save: + config = configs_to_save[config_file] + print("saving", config_file) + OmegaConf.save(config=config, f=config_file) + + def _overwrite_task(self, job_config): + configs_to_save = {} + self.base_project_dir = os.path.join("projects", job_config.base_dir) + self.base_run_dir = os.path.join("runs", job_config.base_dir) + + for config_sets in job_config.task_group: + overwrite_config = job_config.task_group[config_sets] + if ( + overwrite_config.task_list is None + or len(overwrite_config.task_list) == 0 + ): + print( + "[warning]", + job_config.task_group, + "has no task_list specified.") + # we don't want this added to a final config. + task_list = overwrite_config.pop("task_list", None) + for config_file in task_list: + config_file_path = os.path.join( + self.base_project_dir, config_file) + config = recursive_config(config_file_path) + # overwrite it. + if overwrite_config: + config = OmegaConf.merge(config, overwrite_config) + overwrite_dir(config, self.run_dir, basedir=self.base_run_dir) + save_file_path = os.path.join(self.project_dir, config_file) + configs_to_save[save_file_path] = config + return configs_to_save + + +def main(args): + job_type = args.jobtype if args.jobtype else None + # parse multiple pipelines. + pipelines = [Pipeline(fn) for fn in args.yamls.split(",")] + + for pipe_id, pipeline in enumerate(pipelines): + if not hasattr(pipeline, "project_dir"): + for job in pipeline[0]: + job(job_type=job_type, dryrun=args.dryrun) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("yamls", type=str) + parser.add_argument( + "--dryrun", + action="store_true", + help="run config and prepare to submit without launch the job.", + ) + parser.add_argument( + "--jobtype", type=str, default="", + help="force to run jobs as specified.") + args = parser.parse_args() + main(args) diff --git a/examples/MMPT/mmpt/__init__.py b/examples/MMPT/mmpt/__init__.py new file mode 100644 index 0000000000..6ff86ddd5c --- /dev/null +++ b/examples/MMPT/mmpt/__init__.py @@ -0,0 +1,12 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +try: + # fairseq user dir + from .datasets import FairseqMMDataset + from .losses import FairseqCriterion + from .models import FairseqMMModel + from .tasks import FairseqMMTask +except ImportError: + pass diff --git a/examples/MMPT/mmpt/datasets/__init__.py b/examples/MMPT/mmpt/datasets/__init__.py new file mode 100644 index 0000000000..2578235e17 --- /dev/null +++ b/examples/MMPT/mmpt/datasets/__init__.py @@ -0,0 +1,10 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +from .mmdataset import * + +try: + from .fairseqmmdataset import * +except ImportError: + pass diff --git a/examples/MMPT/mmpt/datasets/fairseqmmdataset.py b/examples/MMPT/mmpt/datasets/fairseqmmdataset.py new file mode 100644 index 0000000000..02c49141db --- /dev/null +++ b/examples/MMPT/mmpt/datasets/fairseqmmdataset.py @@ -0,0 +1,57 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +""" +TODO (huxu): fairseq wrapper class for all dataset you defined: mostly MMDataset. +""" + +from collections import OrderedDict + +from torch.utils.data import Dataset +from torch.utils.data.dataloader import default_collate +from fairseq.data import FairseqDataset, data_utils + + +class FairseqMMDataset(FairseqDataset): + """ + A wrapper class for MMDataset for fairseq. + """ + + def __init__(self, mmdataset): + if not isinstance(mmdataset, Dataset): + raise TypeError("mmdataset must be of type `torch.utils.data.dataset`.") + self.mmdataset = mmdataset + + def set_epoch(self, epoch, **unused): + super().set_epoch(epoch) + self.epoch = epoch + + def __getitem__(self, idx): + with data_utils.numpy_seed(43211, self.epoch, idx): + return self.mmdataset[idx] + + def __len__(self): + return len(self.mmdataset) + + def collater(self, samples): + if hasattr(self.mmdataset, "collator"): + return self.mmdataset.collator(samples) + if len(samples) == 0: + return {} + if isinstance(samples[0], dict): + batch = OrderedDict() + for key in samples[0]: + if samples[0][key] is not None: + batch[key] = default_collate([sample[key] for sample in samples]) + return batch + else: + return default_collate(samples) + + def size(self, index): + """dummy implementation: we don't use --max-tokens""" + return 1 + + def num_tokens(self, index): + """dummy implementation: we don't use --max-tokens""" + return 1 diff --git a/examples/MMPT/mmpt/datasets/mmdataset.py b/examples/MMPT/mmpt/datasets/mmdataset.py new file mode 100644 index 0000000000..3d07283f91 --- /dev/null +++ b/examples/MMPT/mmpt/datasets/mmdataset.py @@ -0,0 +1,111 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + +from collections import OrderedDict + +from torch.utils.data import Dataset +from torch.utils.data.dataloader import default_collate + +from ..utils import set_seed + + +class MMDataset(Dataset): + """ + A generic multi-modal dataset. + Args: + `meta_processor`: a meta processor, + handling loading meta data and return video_id and text_id. + `video_processor`: a video processor, + handling e.g., decoding, loading .np files. + `text_processor`: a text processor, + handling e.g., tokenization. + `aligner`: combine the video and text feature + as one training example. + """ + + def __init__( + self, + meta_processor, + video_processor, + text_processor, + align_processor, + ): + self.split = meta_processor.split + self.meta_processor = meta_processor + self.video_processor = video_processor + self.text_processor = text_processor + self.align_processor = align_processor + + def __len__(self): + return len(self.meta_processor) + + def __getitem__(self, idx): + if self.split == "test": + set_seed(idx) + video_id, text_id = self.meta_processor[idx] + video_feature = self.video_processor(video_id) + text_feature = self.text_processor(text_id) + output = self.align_processor(video_id, video_feature, text_feature) + # TODO (huxu): the following is for debug purpose. + output.update({"idx": idx}) + return output + + def collater(self, samples): + """This collator is deprecated. + set self.collator = MMDataset.collater. + see collator in FairseqMMDataset. + """ + + if len(samples) == 0: + return {} + if isinstance(samples[0], dict): + batch = OrderedDict() + for key in samples[0]: + if samples[0][key] is not None: + batch[key] = default_collate( + [sample[key] for sample in samples]) + # if torch.is_tensor(batch[key]): + # print(key, batch[key].size()) + # else: + # print(key, len(batch[key])) + return batch + else: + return default_collate(samples) + + def print_example(self, output): + print("[one example]", output["video_id"]) + if ( + hasattr(self.align_processor, "subsampling") + and self.align_processor.subsampling is not None + and self.align_processor.subsampling > 1 + ): + for key in output: + if torch.is_tensor(output[key]): + output[key] = output[key][0] + + # search tokenizer to translate ids back. + tokenizer = None + if hasattr(self.text_processor, "tokenizer"): + tokenizer = self.text_processor.tokenizer + elif hasattr(self.align_processor, "tokenizer"): + tokenizer = self.align_processor.tokenizer + if tokenizer is not None: + caps = output["caps"].tolist() + if isinstance(caps[0], list): + caps = caps[0] + print("caps", tokenizer.decode(caps)) + print("caps", tokenizer.convert_ids_to_tokens(caps)) + + for key, value in output.items(): + if torch.is_tensor(value): + if len(value.size()) >= 3: # attention_mask. + print(key, value.size()) + print(key, "first", value[0, :, :]) + print(key, "last", value[-1, :, :]) + else: + print(key, value) + print("[end of one example]") diff --git a/examples/MMPT/mmpt/evaluators/__init__.py b/examples/MMPT/mmpt/evaluators/__init__.py new file mode 100644 index 0000000000..2d06b9d797 --- /dev/null +++ b/examples/MMPT/mmpt/evaluators/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +from .metric import * +from .evaluator import * + + +# experimental. +try: + from .expmetric import * +except ImportError: + pass diff --git a/examples/MMPT/mmpt/evaluators/evaluator.py b/examples/MMPT/mmpt/evaluators/evaluator.py new file mode 100644 index 0000000000..94d9c5ec9a --- /dev/null +++ b/examples/MMPT/mmpt/evaluators/evaluator.py @@ -0,0 +1,54 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import glob +import numpy as np + +from . import metric as metric_path +from . import predictor as predictor_path + + +class Evaluator(object): + """ + perform evaluation on a single (downstream) task. + make this both offline and online. + TODO(huxu) saving evaluation results. + """ + + def __init__(self, config, eval_dataloader=None): + if config.metric is None: + raise ValueError("config.metric is", config.metric) + metric_cls = getattr(metric_path, config.metric) + self.metric = metric_cls(config) + if config.predictor is None: + raise ValueError("config.predictor is", config.predictor) + predictor_cls = getattr(predictor_path, config.predictor) + self.predictor = predictor_cls(config) + self.eval_dataloader = eval_dataloader + + def __call__(self): + try: + print(self.predictor.pred_dir) + for pred_file in glob.glob( + self.predictor.pred_dir + "/*_merged.npy"): + outputs = np.load(pred_file) + results = self.metric.compute_metrics(outputs) + self.metric.print_computed_metrics(results) + + outputs = np.load(os.path.join( + self.predictor.pred_dir, "merged.npy")) + results = self.metric.compute_metrics(outputs) + return {"results": results, "metric": self.metric} + except FileNotFoundError: + print("\n[missing]", self.predictor.pred_dir) + return {} + + def evaluate(self, model, eval_dataloader=None, output_file="merged"): + if eval_dataloader is None: + eval_dataloader = self.eval_dataloader + outputs = self.predictor.predict_loop( + model, eval_dataloader, output_file) + results = self.metric.compute_metrics(**outputs) + return results diff --git a/examples/MMPT/mmpt/evaluators/metric.py b/examples/MMPT/mmpt/evaluators/metric.py new file mode 100644 index 0000000000..163724bb25 --- /dev/null +++ b/examples/MMPT/mmpt/evaluators/metric.py @@ -0,0 +1,313 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +import json + + +class Metric(object): + def __init__(self, config, metric_names): + self.metric_names = metric_names + + def best_metric(self, metric): + return metric[self.metric_names[0]] + + def save_metrics(self, fn, metrics): + with open(fn, "w") as fw: + json.dump(fw, metrics) + + def print_computed_metrics(self, metrics): + raise NotImplementedError + + +class RetrievalMetric(Metric): + """ + this is modified from `howto100m/metrics.py`. + History of changes: + refactor as a class. + add metric_key in __init__ + """ + + def __init__(self, config, metric_names=["R1", "R5", "R10", "MR"]): + super().__init__(config, metric_names) + self.error = False # TODO(huxu): add to config to print error. + + def compute_metrics(self, outputs, texts, **kwargs): + x = outputs + sx = np.sort(-x, axis=1) + d = np.diag(-x) + d = d[:, np.newaxis] + ind = sx - d + ind = np.where(ind == 0) + ind = ind[1] + metrics = {} + metrics["R1"] = float(np.sum(ind == 0)) / len(ind) + metrics["R5"] = float(np.sum(ind < 5)) / len(ind) + metrics["R10"] = float(np.sum(ind < 10)) / len(ind) + metrics["MR"] = np.median(ind) + 1 + + max_idx = np.argmax(outputs, axis=1) + if self.error: + # print top-20 errors. + error = [] + for ex_idx in range(20): + error.append((texts[ex_idx], texts[max_idx[ex_idx]])) + metrics["error"] = error + return metrics + + def print_computed_metrics(self, metrics): + r1 = metrics["R1"] + r5 = metrics["R5"] + r10 = metrics["R10"] + mr = metrics["MR"] + print( + "R@1: {:.4f} - R@5: {:.4f} - R@10: {:.4f} - Median R: {}".format( + r1, r5, r10, mr + ) + ) + if "error" in metrics: + print(metrics["error"]) + + +class DiDeMoMetric(Metric): + """ + History of changes: + python 2.x to python 3.x. + merge utils.py into eval to save one file. + reference: https://github.com/LisaAnne/LocalizingMoments/blob/master/utils/eval.py + Code to evaluate your results on the DiDeMo dataset. + """ + def __init__(self, config, metric_names=["rank1", "rank5", "miou"]): + super().__init__(config, metric_names) + + def compute_metrics(self, outputs, targets, **kwargs): + assert len(outputs) == len(targets) + rank1, rank5, miou = self._eval_predictions(outputs, targets) + metrics = { + "rank1": rank1, + "rank5": rank5, + "miou": miou + } + return metrics + + def print_computed_metrics(self, metrics): + rank1 = metrics["rank1"] + rank5 = metrics["rank5"] + miou = metrics["miou"] + # print("Average rank@1: %f" % rank1) + # print("Average rank@5: %f" % rank5) + # print("Average iou: %f" % miou) + + print( + "Average rank@1: {:.4f} Average rank@5: {:.4f} Average iou: {:.4f}".format( + rank1, rank5, miou + ) + ) + + def _iou(self, pred, gt): + intersection = max(0, min(pred[1], gt[1]) + 1 - max(pred[0], gt[0])) + union = max(pred[1], gt[1]) + 1 - min(pred[0], gt[0]) + return float(intersection)/union + + def _rank(self, pred, gt): + return pred.index(tuple(gt)) + 1 + + def _eval_predictions(self, segments, data): + ''' + Inputs: + segments: For each item in the ground truth data, rank possible video segments given the description and video. + In DiDeMo, there are 21 posible moments extracted for each video so the list of video segments will be of length 21. + The first video segment should be the video segment that best corresponds to the text query. + There are 4180 sentence in the validation data, so when evaluating a model on the val dataset, + segments should be a list of lenght 4180, and each item in segments should be a list of length 21. + data: ground truth data + ''' + average_ranks = [] + average_iou = [] + for s, d in zip(segments, data): + pred = s[0] + ious = [self._iou(pred, t) for t in d['times']] + average_iou.append(np.mean(np.sort(ious)[-3:])) + ranks = [self._rank(s, t) for t in d['times'] if tuple(t) in s] # if t in s] is added for s, e not in prediction. + average_ranks.append(np.mean(np.sort(ranks)[:3])) + rank1 = np.sum(np.array(average_ranks) <= 1)/float(len(average_ranks)) + rank5 = np.sum(np.array(average_ranks) <= 5)/float(len(average_ranks)) + miou = np.mean(average_iou) + + # print("Average rank@1: %f" % rank1) + # print("Average rank@5: %f" % rank5) + # print("Average iou: %f" % miou) + return rank1, rank5, miou + + +class NLGMetric(Metric): + def __init__( + self, + config, + metric_names=[ + "Bleu_1", "Bleu_2", "Bleu_3", "Bleu_4", + "METEOR", "ROUGE_L", "CIDEr" + ] + ): + super().__init__(config, metric_names) + # please install NLGEval from `https://github.com/Maluuba/nlg-eval` + from nlgeval import NLGEval + self.nlg = NLGEval() + + def compute_metrics(self, outputs, targets, **kwargs): + return self.nlg.compute_metrics( + hyp_list=outputs, ref_list=targets) + + def print_computed_metrics(self, metrics): + Bleu_1 = metrics["Bleu_1"] + Bleu_2 = metrics["Bleu_2"] + Bleu_3 = metrics["Bleu_3"] + Bleu_4 = metrics["Bleu_4"] + METEOR = metrics["METEOR"] + ROUGE_L = metrics["ROUGE_L"] + CIDEr = metrics["CIDEr"] + + print( + "Bleu_1: {:.4f} - Bleu_2: {:.4f} - Bleu_3: {:.4f} - Bleu_4: {:.4f} - METEOR: {:.4f} - ROUGE_L: {:.4f} - CIDEr: {:.4f}".format( + Bleu_1, Bleu_2, Bleu_3, Bleu_4, METEOR, ROUGE_L, CIDEr + ) + ) + + +class QAMetric(Metric): + def __init__( + self, + config, + metric_names=["acc"] + ): + super().__init__(config, metric_names) + + def compute_metrics(self, outputs, targets, **kwargs): + from sklearn.metrics import accuracy_score + return {"acc": accuracy_score(targets, outputs)} + + def print_computed_metrics(self, metrics): + print("acc: {:.4f}".format(metrics["acc"])) + + +class COINActionSegmentationMetric(Metric): + """ + COIN dataset listed 3 repos for Action Segmentation. + Action Sets, NeuralNetwork-Viterbi, TCFPN-ISBA. + The first and second are the same. + https://github.com/alexanderrichard/action-sets/blob/master/eval.py + + Future reference for the third: + `https://github.com/Zephyr-D/TCFPN-ISBA/blob/master/utils/metrics.py` + """ + def __init__(self, config, metric_name=["frame_acc"]): + super().__init__(config, metric_name) + + def compute_metrics(self, outputs, targets): + n_frames = 0 + n_errors = 0 + n_errors = sum(outputs != targets) + n_frames = len(targets) + return {"frame_acc": 1.0 - float(n_errors) / n_frames} + + def print_computed_metrics(self, metrics): + fa = metrics["frame_acc"] + print("frame accuracy:", fa) + + +class CrossTaskMetric(Metric): + def __init__(self, config, metric_names=["recall"]): + super().__init__(config, metric_names) + + def compute_metrics(self, outputs, targets, **kwargs): + """refactored from line 166: + https://github.com/DmZhukov/CrossTask/blob/master/train.py""" + + recalls = self._get_recalls(Y_true=targets, Y_pred=outputs) + results = {} + for task, rec in recalls.items(): + results[str(task)] = rec + + avg_recall = np.mean(list(recalls.values())) + results["recall"] = avg_recall + return results + + def print_computed_metrics(self, metrics): + print('Recall: {0:0.3f}'.format(metrics["recall"])) + for task in metrics: + if task != "recall": + print('Task {0}. Recall = {1:0.3f}'.format( + task, metrics[task])) + + def _get_recalls(self, Y_true, Y_pred): + """refactored from + https://github.com/DmZhukov/CrossTask/blob/master/train.py""" + + step_match = {task: 0 for task in Y_true.keys()} + step_total = {task: 0 for task in Y_true.keys()} + for task, ys_true in Y_true.items(): + ys_pred = Y_pred[task] + for vid in set(ys_pred.keys()).intersection(set(ys_true.keys())): + y_true = ys_true[vid] + y_pred = ys_pred[vid] + step_total[task] += (y_true.sum(axis=0) > 0).sum() + step_match[task] += (y_true*y_pred).sum() + recalls = { + task: step_match[task] / n for task, n in step_total.items()} + return recalls + + +class ActionRecognitionMetric(Metric): + def __init__( + self, + config, + metric_names=["acc", "acc_splits", "r1_splits", "r5_splits", "r10_splits"] + ): + super().__init__(config, metric_names) + + def compute_metrics(self, outputs, targets, splits, **kwargs): + all_video_embd = outputs + labels = targets + split1, split2, split3 = splits + accs = [] + r1s = [] + r5s = [] + r10s = [] + for split in range(3): + if split == 0: + s = split1 + elif split == 1: + s = split2 + else: + s = split3 + + X_pred = all_video_embd[np.where(s == 2)[0]] + label_test = labels[np.where(s == 2)[0]] + logits = X_pred + X_pred = np.argmax(X_pred, axis=1) + acc = np.sum(X_pred == label_test) / float(len(X_pred)) + accs.append(acc) + # compute recall. + sorted_pred = (-logits).argsort(axis=-1) + label_test_sp = label_test.reshape(-1, 1) + + r1 = np.mean((sorted_pred[:, :1] == label_test_sp).sum(axis=1), axis=0) + r5 = np.mean((sorted_pred[:, :5] == label_test_sp).sum(axis=1), axis=0) + r10 = np.mean((sorted_pred[:, :10] == label_test_sp).sum(axis=1), axis=0) + r1s.append(r1) + r5s.append(r5) + r10s.append(r10) + + return {"acc": accs[0], "acc_splits": accs, "r1_splits": r1s, "r5_splits": r5s, "r10_splits": r10s} + + def print_computed_metrics(self, metrics): + for split, acc in enumerate(metrics["acc_splits"]): + print("Top 1 accuracy on split {}: {}; r1 {}; r5 {}; r10 {}".format( + split + 1, acc, + metrics["r1_splits"][split], + metrics["r5_splits"][split], + metrics["r10_splits"][split], + ) + ) diff --git a/examples/MMPT/mmpt/evaluators/predictor.py b/examples/MMPT/mmpt/evaluators/predictor.py new file mode 100644 index 0000000000..2ffef6ab47 --- /dev/null +++ b/examples/MMPT/mmpt/evaluators/predictor.py @@ -0,0 +1,595 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import random +import json +import numpy as np +import torch +import pickle +import math + +from tqdm import tqdm + + +class Predictor(object): + """this base class is used to save predictions to disk + (and being called by a evaluator later). + Predictor has minimum support of single gpu prediction. + """ + def __init__(self, config): + self.pred_dir = None # on-the-fly eval does not save the results. + if hasattr(config, "eval") and config.eval is not None: + self.pred_dir = config.eval.save_path + os.makedirs(self.pred_dir, exist_ok=True) + + def __call__(self, outputs): + """extract the prediction and save it.""" + raise NotImplementedError + + def predict_loop(self, model, eval_dataloader, output_file=None): + """on-the-fly prediction on a single gpu.""" + self.full_scores = [] + model.eval() + model = model.to(0) + with torch.no_grad(): + for data in eval_dataloader: + data = self.to_ctx(data) + outputs = model(**data) + outputs.update(data) + self(outputs) + return self.finalize(output_file) + + def finalize(self, output_file): + pass + + def to_ctx(self, data, ctx=0, dtype=None): + if isinstance(data, dict): + for key in data: + if torch.is_tensor(data[key]): + if dtype is not None and data[key].dtype == torch.float32: + data[key] = data[key].to(dtype) + data[key] = data[key].to(ctx) + return data + else: + raise ValueError("non-dict type of batch is not supported yet.") + + +class NLGPredictor(Predictor): + """Predicting Text from MMFusion models.""" + """TODO: make a context.""" + def __init__(self, config): + super().__init__(config) + from transformers import AutoTokenizer + + self.tokenizer = AutoTokenizer.from_pretrained( + config.dataset.bert_name, + bos_token="[CLS]", eos_token="[SEP]") + self.bos_token_id = self.tokenizer.bos_token_id + self.eos_token_id = self.tokenizer.eos_token_id + + def predict_loop(self, model, eval_dataloader, output_file=None): + """TODO: refactor base classes.""" + ctx = 0 + outputs = {"outputs": [], "targets": [[]]} + model.eval() + model = model.to(ctx) + with torch.no_grad(): + for data in tqdm(eval_dataloader): + data = self.to_ctx(data, ctx) + self(data, model, outputs) + return self.finalize(outputs, output_file) + + def __call__(self, data, model, outputs): + data.update({ + "bos_token_id": self.bos_token_id, + "eos_token_id": self.eos_token_id + }) + + output = model.generate(**data) + assert len(output) == len(data["ref"]) + for idx, _output in enumerate(output): + generated_text = self.tokenizer.decode( + _output, skip_special_tokens=True) + if generated_text == "": + generated_text = "none" + outputs["outputs"].append(generated_text) + outputs["targets"][0].append(data["ref"][idx]) + if random.random() < 0.001: + print("_output", _output) + print("generated_text", generated_text) + print("ref", data["ref"][idx]) + + def finalize(self, outputs, output_file=None): + if output_file is not None: + with open(os.path.join( + self.pred_dir, output_file + ".json"), "w") as fw: + json.dump(outputs, fw, indent=4) + return outputs + + +class RetrievalPredictor(Predictor): + """generated `pooled_video` and `pooled_text`.""" + def __init__(self, config): + super().__init__(config) + from transformers import AutoTokenizer + self.tokenizer = AutoTokenizer.from_pretrained( + config.dataset.bert_name) + + def predict_loop( + self, + model, + eval_dataloader, + output_file="retrieval.npy" + ): + """on-the-fly prediction on a single gpu.""" + full_scores = [] + texts = [] + model.eval() + model = model.cuda() + with torch.no_grad(): + for data in eval_dataloader: + # convert to dict. + if not isinstance(data, dict): + data = { + "caps": data[0], + "cmasks": data[1], + "vfeats": data[2], + "vmasks": data[3], + "video_id": data[4] + } + data = self.to_ctx(data) + outputs = model(**data) + outputs.update(data) + self(outputs, full_scores) + for _cap in data["caps"]: + texts.append( + self.tokenizer.decode(_cap, skip_special_tokens=True) + ) + + return self.finalize(full_scores, texts, output_file) + + def __call__(self, sample, full_scores): + scores = self._get_pooled_outputs(sample) + self._append_scores(scores, full_scores) + + def finalize(self, full_scores, texts, output_file=None): + outputs = self._aggregate_scores(full_scores) + if output_file is not None: + np.save(os.path.join(self.pred_dir, output_file + ".npy"), outputs) + return {"outputs": outputs, "texts": texts} + + def _get_pooled_outputs(self, outputs): + if "pooled_video" in outputs: + return outputs["pooled_video"], outputs["pooled_text"] + else: + raise ValueError("unknown format of outputs.") + + def _append_scores(self, scores, full_scores): + assert len(scores) == 2 + if len(full_scores) == 0: + full_scores.append([]) + full_scores.append([]) + full_scores[0].append(scores[0].cpu().detach().numpy()) + full_scores[1].append(scores[1].cpu().detach().numpy()) + + def _aggregate_scores(self, scores): + assert len(scores) == 2 + video_hidden = np.concatenate(scores[0], axis=0) + text_hidden = np.concatenate(scores[1], axis=0) + # clear up. + self.full_scores = [] + return np.matmul(text_hidden, video_hidden.T) + + +class QAPredictor(Predictor): + """generated `pooled_video` and `pooled_text`.""" + def __init__(self, config): + super().__init__(config) + """predictor maintains scores and aggregate them.""" + + def predict_loop(self, model, eval_dataloader, output_file="qa.npy"): + """on-the-fly prediction on a single gpu.""" + self.full_scores = [] + model.eval() + model = model.cuda() + with torch.no_grad(): + for data in eval_dataloader: + # reshape ans and dup video 5 times. + v_len = data["vfeats"].size(1) + hidden_size = data["vfeats"].size(2) + data["vfeats"] = data["vfeats"].unsqueeze(1).repeat(1, 5, 1, 1).view(-1, v_len, hidden_size) + data["vmasks"] = data["vmasks"].unsqueeze(1).repeat(1, 5, 1).view(-1, v_len) + + t_len = data["caps"].size(-1) + data["caps"] = data["caps"].view(-1, t_len) + data["cmasks"] = data["cmasks"].view(-1, t_len) + + data = self.to_ctx(data) + outputs = model(**data) + outputs.update(data) + self(outputs) + return self.finalize(output_file) + + def __call__(self, sample): + hidden_size = sample["pooled_video"].size(-1) + pooled_video = sample["pooled_video"].view(-1, 5, hidden_size) + pooled_text = sample["pooled_text"].view(-1, 5, hidden_size) + scores = torch.bmm(pooled_video, pooled_text.transpose(2, 1)) + scores = scores.argmax(-1) + self._append_scores(scores[:, 0], sample["answers"], self.full_scores) + + def finalize(self, output_file=None): + outputs, targets = self._aggregate_scores(self.full_scores) + if output_file is not None: + np.save(os.path.join(self.pred_dir, output_file + ".npy"), outputs) + return {"outputs": outputs, "targets": targets} + + def _append_scores(self, scores, answers, full_scores): + if len(full_scores) == 0: + full_scores.append([]) + full_scores.append([]) + full_scores[0].append(scores.cpu().detach().numpy()) + full_scores[1].append(answers.cpu().detach().numpy()) + + def _aggregate_scores(self, scores): + assert len(scores) == 2 + outputs = np.concatenate(scores[0], axis=0) + targets = np.concatenate(scores[1], axis=0) + # clear up. + self.full_scores = [] + return outputs, targets + + +class CrossTaskPredictor(Predictor): + """ + CrossTaskPredictor needs to compute the average of logits + for overlapped sliding-window. + """ + def __init__(self, config): + super().__init__(config) + self.lsm = torch.nn.LogSoftmax(dim=1) + self.max_video_len = config.dataset.max_video_len + self.sliding_window = config.dataset.sliding_window + self.sliding_window_size = config.dataset.sliding_window_size + self.annotation_path = config.dataset.annotation_path + + def predict_loop(self, model, eval_dataloader, output_file="result.pkl"): + """refactored from line 144: + https://github.com/DmZhukov/CrossTask/blob/master/train.py + """ + ctx = 0 + model.eval() + model = model.to(ctx) + # this is not a loss but just compute neg_log_prob. + Y_pred = {} + Y_true = {} + with torch.no_grad(): + for batch in eval_dataloader: + self(batch, model, Y_pred, Y_true) + return self.finalize(Y_pred, Y_true, output_file) + + def __call__(self, sample, model, Y_pred, Y_true): + # please install dp from `https://github.com/DmZhukov/CrossTask` + from dp import dp + vid, task = sample['video_id'][0], sample['task'][0] + sample = self.to_ctx(sample) + # compute the average logits over sliding windows. + output = model(**sample) + batch_logits = output["logits"].cpu() + + video_len = sample["video_len"][0] + + # the following version is slow. + logits = torch.zeros((video_len, batch_logits.size(1))) + logits_counts = torch.zeros((video_len, 1), dtype=torch.long) + # use the same loop as aligner to recover. + batch_logit_idx = 0 + for window_start in range(0, video_len, self.sliding_window): + video_end = min(video_len - window_start, self.sliding_window_size) + logits[window_start: window_start + video_end] += batch_logits[ + batch_logit_idx: batch_logit_idx + video_end] + batch_logit_idx += video_end + logits_counts[window_start: window_start + video_end] += torch.ones((video_end, 1), dtype=torch.long) + + if (video_len - window_start) <= self.sliding_window_size: + break + + logits /= logits_counts + assert logits.size() == (video_len, batch_logits.size(1)), "{}, {}".format(logits.size(), video_len) + + O = self.lsm(logits) + y = np.zeros(O.size(), dtype=np.float32) + dp(y, -O.detach().cpu().numpy()) + if task not in Y_pred: + Y_pred[task] = {} + Y_pred[task][vid] = y + annot_path = os.path.join( + self.annotation_path, task+'_'+vid+'.csv') + if os.path.exists(annot_path): + if task not in Y_true: + Y_true[task] = {} + Y_true[task][vid] = self._read_assignment( + *y.shape, annot_path) + + def finalize(self, Y_pred, Y_true, output_file=None): + if output_file is not None: + with open( + os.path.join(self.pred_dir, output_file + ".pkl"), + "wb") as fw: + pickle.dump( + {"Y_pred": Y_pred, "Y_true": Y_true}, fw, + protocol=pickle.HIGHEST_PROTOCOL) + return {"outputs": Y_pred, "targets": Y_true} + + def _read_assignment(self, T, K, path): + """ + refactored from https://github.com/DmZhukov/CrossTask/blob/master/data.py + Howto interpret contraints on loss that is going to be minimized: + lambd is a big number; + self.lambd * C is a big number for all valid position (csv stores invalids) + + def forward(self, O, Y, C): + return (Y*(self.lambd * C - self.lsm(O))).mean(dim=0).sum() + + This will load the csv file and fill-in the step col from start to end rows. + """ + + Y = np.zeros([T, K], dtype=np.uint8) + with open(path, 'r') as f: + for line in f: + step, start, end = line.strip().split(',') + start = int(math.floor(float(start))) + end = int(math.ceil(float(end))) + step = int(step) - 1 + Y[start:end, step] = 1 + return Y + + +class COINPredictor(Predictor): + """ + COINPredictor is similar to CrossTask on sliding windows. + """ + def __init__(self, config): + super().__init__(config) + self.max_video_len = config.dataset.max_video_len + self.sliding_window = config.dataset.sliding_window + self.sliding_window_size = config.dataset.sliding_window_size + + def predict_loop(self, model, eval_dataloader, output_file="result.pkl"): + """refactored from line 144: + https://github.com/DmZhukov/CrossTask/blob/master/train.py + """ + ctx = 0 + model.eval() + model = model.to(ctx) + # this is not a loss but just compute neg_log_prob. + Y_pred = [] + Y_true = [] + with torch.no_grad(): + for batch in eval_dataloader: + self(batch, model, Y_pred, Y_true) + return self.finalize(Y_pred, Y_true, output_file) + + def __call__(self, sample, model, Y_pred, Y_true): + sample = self.to_ctx(sample) + # compute the average logits over sliding windows. + output = model(**sample) + logits = self._merge_windows(sample, output) + Y_pred.append(logits.argmax(dim=1)) + Y_true.append(sample["video_targets"].squeeze(0).cpu()) + + def _merge_windows(self, sample, output): + targets = sample["targets"].reshape(-1).cpu() + valid_mask = targets != -100 + targets = targets[valid_mask] + batch_logits = output["logits"].cpu() + batch_logits = batch_logits.reshape(-1, batch_logits.size(-1)) + batch_logits = batch_logits[valid_mask] + + video_len = sample["video_len"][0] + + # the following version is slow. + logits = torch.zeros((video_len, batch_logits.size(1))) + logits_counts = torch.zeros((video_len, 1), dtype=torch.long) + # use the same loop as aligner to recover. + batch_logit_idx = 0 + for window_start in range(0, video_len, self.sliding_window): + video_end = min(video_len - window_start, self.sliding_window_size) + logits[window_start: window_start + video_end] += batch_logits[ + batch_logit_idx: batch_logit_idx + video_end] + batch_logit_idx += video_end + logits_counts[window_start: window_start + video_end] += torch.ones((video_end, 1), dtype=torch.long) + if (video_len - window_start) <= self.sliding_window_size: + break + logits /= logits_counts + assert logits.size() == (video_len, batch_logits.size(1)), "{}, {}".format(logits.size(), video_len) + return logits + + def finalize(self, Y_pred, Y_true, output_file=None): + Y_pred = torch.cat(Y_pred, dim=0).numpy() + Y_true = torch.cat(Y_true, dim=0).numpy() + assert len(Y_pred) == len(Y_true) + + error_mask = Y_pred != Y_true + print("sample error", Y_pred[error_mask][:10], Y_true[error_mask][:10]) + print("sample error", Y_pred[error_mask][10:20], Y_true[error_mask][10:20]) + + if output_file is not None: + with open( + os.path.join(self.pred_dir, output_file + ".pkl"), + "wb") as fw: + pickle.dump( + {"Y_pred": Y_pred, "Y_true": Y_true}, fw, + protocol=pickle.HIGHEST_PROTOCOL) + return {"outputs": Y_pred, "targets": Y_true} + + +class COINZSPredictor(COINPredictor): + """ + COINZSPredictor for COIN zero-shot prediction. + """ + + def __init__(self, config): + super().__init__(config) + self.dataset_config = config.dataset + + def predict_loop(self, model, eval_dataloader, output_file="result.pkl"): + """refactored from line 144: + https://github.com/DmZhukov/CrossTask/blob/master/train.py + """ + ctx = 0 + model.eval() + model = model.to(ctx) + + with torch.no_grad(): + outputs = eval_dataloader.dataset.meta_processor.meta_text_labels( + self.dataset_config) + outputs = self.to_ctx(outputs, ctx) + label_hidden_states = model.forward_text(**outputs).cpu() + label_sim = label_hidden_states @ label_hidden_states.t() + num_labels = label_sim.size(0) + eye_mask = ~torch.eye(num_labels, dtype=torch.bool) + label_sim = label_sim.masked_select(eye_mask).view(num_labels, num_labels - 1) + lbd = label_sim.max() + + # this is not a loss but just compute neg_log_prob. + Y_pred = [] + Y_true = [] + with torch.no_grad(): + for batch in eval_dataloader: + self(batch, label_hidden_states, model, lbd, Y_pred, Y_true) + return self.finalize(Y_pred, Y_true, output_file) + + def reshape_subsample(self, sample): + for key in sample: + if torch.is_tensor(sample[key]): + sample[key] = self.flat_subsample(sample[key]) + return sample + + def flat_subsample(self, tensor): + if len(tensor.size()) > 1 and tensor.size(0) == 1: + tensor = tensor.squeeze(0) + return tensor + + def __call__(self, sample, label_hidden_states, model, lbd, Y_pred, Y_true): + sample = self.reshape_subsample(sample) + sample = self.to_ctx(sample) + # compute the average logits over sliding windows. + sample["output_hidden_states"] = True + video_outputs = model.forward_video(**sample).cpu() + output = {"logits": video_outputs[:, 1:sample["vmasks"].size(1)+1] @ label_hidden_states.t()} + logits = self._merge_windows(sample, output) + # logic of zero-shot for sequence labeling. + logits_argmax = logits.argmax(dim=1) + 1 # 0 is "O" label. + logits_max = logits.max(dim=1)[0] + + pred = torch.zeros_like(logits_argmax) + label_select = logits_max > lbd # 73 or 74 + pred[label_select] = logits_argmax[label_select] + + Y_pred.append(pred) + Y_true.append(sample["video_targets"].squeeze(0).cpu()) + + def finalize(self, Y_pred, Y_true, output_file=None): + Y_pred = torch.cat(Y_pred, dim=0).numpy() + Y_true = torch.cat(Y_true, dim=0).numpy() + assert len(Y_pred) == len(Y_true) + + error_mask = Y_pred != Y_true + print("sample error", Y_pred[error_mask][:10], Y_true[error_mask][:10]) + print("sample error", Y_pred[error_mask][10:20], Y_true[error_mask][10:20]) + + if output_file is not None: + with open( + os.path.join(self.pred_dir, output_file + ".pkl"), + "wb") as fw: + pickle.dump( + {"Y_pred": Y_pred, "Y_true": Y_true}, fw, + protocol=pickle.HIGHEST_PROTOCOL) + return {"outputs": Y_pred, "targets": Y_true} + + +class DiDeMoPredictor(Predictor): + """reference: https://github.com/LisaAnne/LocalizingMoments/blob/master/utils/eval.py + https://github.com/LisaAnne/LocalizingMoments/blob/master/utils/data_processing.py + """ + def __init__(self, config): + super().__init__(config) + # load targets. + with open(config.dataset.test_path) as data_file: + self.test_data = json.load(data_file) + + def predict_loop(self, model, eval_dataloader, output_file="didemo.npy"): + """ + TODO: two solutions here. + """ + import itertools + # 21 chunks. + self.possible_segments = [(0,0), (1,1), (2,2), (3,3), (4,4), (5,5)] + for i in itertools.combinations(range(6), 2): + self.possible_segments.append(i) + # pick segments from a video. + + """on-the-fly prediction on a single gpu.""" + self.full_scores = [] + model.eval() + model = model.cuda() + with torch.no_grad(): + for data in eval_dataloader: + # TODO special forwarding logic here. + data = self.to_ctx(data) + data["output_hidden_states"] = True + hidden_video = model.forward_video(**data) + data["output_hidden_states"] = False + pooled_text = model.forward_text(**data) + outputs = { + "hidden_video": hidden_video, + "pooled_text": pooled_text + } + outputs.update(data) + self(outputs) + return self.finalize(output_file) + + def __call__(self, sample): + # TODO: make an index select from self.possible_segments. + hidden_video = sample["hidden_video"] + pooled_text = sample["pooled_text"] + vmasks = sample["vmasks"] + # probably maintain valid results here. + + hidden_video = hidden_video[:, 1:-1, :] + # probably maintain valid results here. + pooled_video = [] + for s, e in self.possible_segments: + pooled_video.append( + torch.mean( + hidden_video[:, int(s*5):int((e+1)*5), :], + dim=1, keepdim=True) + ) + pooled_video = torch.cat(pooled_video, dim=1) + scores = torch.bmm( + pooled_video, pooled_text.unsqueeze(-1)).squeeze(-1).cpu() + + ranks = scores.argsort(dim=-1, descending=True) + + for batch_idx, rank in enumerate(ranks): + rank_of_moment = [] + for m_idx, moment in enumerate(rank): + s, e = self.possible_segments[moment.item()] + if torch.any( + vmasks[batch_idx, int(s*5):int((e+1)*5)] + ): + rank_of_moment.append((s, e)) + self.full_scores.append(rank_of_moment) + + def finalize(self, output_file=None): + outputs = self._aggregate_scores(self.full_scores) + if output_file is not None: + np.save(os.path.join(self.pred_dir, output_file + ".npy"), outputs) + return {"outputs": outputs, "targets": self.test_data} + + def _aggregate_scores(self, scores): + self.full_scores = [] + return scores diff --git a/examples/MMPT/mmpt/losses/__init__.py b/examples/MMPT/mmpt/losses/__init__.py new file mode 100644 index 0000000000..8dc32c96d2 --- /dev/null +++ b/examples/MMPT/mmpt/losses/__init__.py @@ -0,0 +1,16 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +from .loss import * +from .nce import * + +try: + from .fairseqmmloss import * +except ImportError: + pass + +try: + from .expnce import * +except ImportError: + pass diff --git a/examples/MMPT/mmpt/losses/fairseqmmloss.py b/examples/MMPT/mmpt/losses/fairseqmmloss.py new file mode 100644 index 0000000000..c0415d1077 --- /dev/null +++ b/examples/MMPT/mmpt/losses/fairseqmmloss.py @@ -0,0 +1,63 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +TODO (huxu): a general fairseq criterion for all your pre-defined losses. +""" + +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq import metrics + + +@register_criterion("mmloss") +class MMCriterion(FairseqCriterion): + def __init__(self, task): + super().__init__(task) + # TODO (huxu): wrap forward call of loss_fn and eval_fn into task. + self.mmtask = task.mmtask + + def forward(self, model, sample): + """Compute the loss for the given sample. + Returns a tuple with three elements: + 1) the loss + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + outputs = self.mmtask(model, sample) + + loss, loss_scalar, max_len, batch_size, sample_size = ( + outputs["loss"], + outputs["loss_scalar"], + outputs["max_len"], + outputs["batch_size"], + outputs["sample_size"], + ) + + logging_output = { + "loss": loss_scalar, + "ntokens": max_len * batch_size, # dummy report. + "nsentences": batch_size, # dummy report. + "sample_size": sample_size, + } + + return loss, 1, logging_output + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + """since we use NCE, our actual batch_size is 1 per GPU. + Then we take the mean of each worker.""" + loss_sum = sum(log.get("loss", 0.0) for log in logging_outputs) + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + metrics.log_scalar("loss", loss_sum / sample_size, round=3) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return True diff --git a/examples/MMPT/mmpt/losses/loss.py b/examples/MMPT/mmpt/losses/loss.py new file mode 100644 index 0000000000..99c05d067e --- /dev/null +++ b/examples/MMPT/mmpt/losses/loss.py @@ -0,0 +1,87 @@ +# Copyright (c) Facebook, Inc. All Rights Reserved + +import torch + +from torch import nn + + +class Loss(object): + def __call__(self, *args, **kwargs): + raise NotImplementedError + + +# Dummy Loss for testing. +class DummyLoss(Loss): + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__(self, logits, targets, **kwargs): + return self.loss(logits, targets) + + +class DummyK400Loss(Loss): + """dummy k400 loss for MViT.""" + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__(self, logits, targets, **kwargs): + return self.loss( + logits, torch.randint(0, 400, (logits.size(0),), device=logits.device)) + + +class CrossEntropy(Loss): + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__(self, logits, targets, **kwargs): + return self.loss(logits.reshape(-1, logits.size(-1)), targets.reshape(-1)) + + +class ArgmaxCrossEntropy(Loss): + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__(self, logits, targets, **kwargs): + return self.loss(logits, targets.argmax(dim=1)) + + +class BCE(Loss): + def __init__(self): + self.loss = nn.BCEWithLogitsLoss() + + def __call__(self, logits, targets, **kwargs): + targets = targets.squeeze(0) + return self.loss(logits, targets) + + +class NLGLoss(Loss): + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__(self, logits, text_label, **kwargs): + targets = text_label[text_label != -100] + return self.loss(logits, targets) + + +class MSE(Loss): + def __init__(self): + self.loss = nn.MSELoss() + + def __call__(self, logits, targets, **kwargs): + return self.loss(logits, targets) + + +class L1(Loss): + def __init__(self): + self.loss = nn.L1Loss() + + def __call__(self, logits, targets, **kwargs): + return self.loss(logits, targets) + + +class SmoothL1(Loss): + def __init__(self): + self.loss = nn.SmoothL1Loss() + + def __call__(self, logits, targets, **kwargs): + return self.loss(logits, targets) diff --git a/examples/MMPT/mmpt/losses/nce.py b/examples/MMPT/mmpt/losses/nce.py new file mode 100644 index 0000000000..ed7be8d372 --- /dev/null +++ b/examples/MMPT/mmpt/losses/nce.py @@ -0,0 +1,156 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +softmax-based NCE loss, used by this project. +""" + +import torch + +from torch import nn + +from .loss import Loss + + +class NCE(Loss): + def __init__(self): + # TODO (huxu): define temperature. + self.loss = nn.CrossEntropyLoss() + + def __call__(self, align_scores, **kargs): + # note: we reuse the same shape as cls head in BERT (batch_size, 2) + # but NCE only needs one logits. + # (so we drop all weights in the second neg logits.) + align_scores = align_scores[:, :1] + # duplicate negative examples + batch_size = align_scores.size(0) // 2 + pos_scores = align_scores[:batch_size] + neg_scores = align_scores[batch_size:].view(1, batch_size).repeat( + batch_size, 1) + scores = torch.cat([pos_scores, neg_scores], dim=1) + return self.loss( + scores, + torch.zeros( + (batch_size,), + dtype=torch.long, + device=align_scores.device), + ) + + +class T2VContraLoss(Loss): + """NCE for MM joint space, on softmax text2video matrix. + """ + def __init__(self): + # TODO (huxu): define temperature. + self.loss = nn.CrossEntropyLoss() + + def __call__(self, pooled_video, pooled_text, **kargs): + batch_size = pooled_video.size(0) + logits = torch.mm(pooled_text, pooled_video.transpose(1, 0)) + targets = torch.arange( + batch_size, + dtype=torch.long, + device=pooled_video.device) + return self.loss(logits, targets) + + +class V2TContraLoss(Loss): + """NCE for MM joint space, with softmax on video2text matrix.""" + + def __init__(self): + # TODO (huxu): define temperature. + self.loss = nn.CrossEntropyLoss() + + def __call__(self, pooled_video, pooled_text, **kargs): + batch_size = pooled_video.size(0) + logits = torch.mm(pooled_video, pooled_text.transpose(1, 0)) + targets = torch.arange( + batch_size, + dtype=torch.long, + device=pooled_video.device) + return self.loss(logits, targets) + + +class MMContraLoss(Loss): + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__(self, pooled_video, pooled_text, **kwargs): + logits_per_video = pooled_video @ pooled_text.t() + logits_per_text = pooled_text @ pooled_video.t() + + targets = torch.arange( + pooled_video.size(0), + dtype=torch.long, + device=pooled_video.device) + loss_video = self.loss(logits_per_video, targets) + loss_text = self.loss(logits_per_text, targets) + return loss_video + loss_text + + +class MTM(Loss): + """Combination of MFM and MLM.""" + + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__( + self, + video_logits, + text_logits, + video_label, + text_label, + **kwargs + ): + text_logits = torch.cat([ + text_logits, + torch.zeros( + (text_logits.size(0), 1), device=text_logits.device) + ], dim=1) + vt_logits = torch.cat([video_logits, text_logits], dim=0) + # loss for video. + video_label = torch.zeros( + (video_logits.size(0),), + dtype=torch.long, + device=video_logits.device + ) + + # loss for text. + text_label = text_label.reshape(-1) + labels_mask = text_label != -100 + selected_text_label = text_label[labels_mask] + + vt_label = torch.cat([video_label, selected_text_label], dim=0) + return self.loss(vt_logits, vt_label) + + +class MFMMLM(Loss): + """Combination of MFM and MLM.""" + + def __init__(self): + self.loss = nn.CrossEntropyLoss() + + def __call__( + self, + video_logits, + text_logits, + video_label, + text_label, + **kwargs + ): + # loss for video. + video_label = torch.zeros( + (video_logits.size(0),), + dtype=torch.long, + device=video_logits.device + ) + masked_frame_loss = self.loss(video_logits, video_label) + + # loss for text. + text_label = text_label.reshape(-1) + labels_mask = text_label != -100 + selected_text_label = text_label[labels_mask] + masked_lm_loss = self.loss(text_logits, selected_text_label) + return masked_frame_loss + masked_lm_loss diff --git a/examples/MMPT/mmpt/models/__init__.py b/examples/MMPT/mmpt/models/__init__.py new file mode 100644 index 0000000000..825250cd00 --- /dev/null +++ b/examples/MMPT/mmpt/models/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +from .mmfusion import * +from .transformermodel import * +from .mmfusionnlg import * + +try: + from .fairseqmmmodel import * +except ImportError: + pass + +try: + from .expmmfusion import * +except ImportError: + pass diff --git a/examples/MMPT/mmpt/models/fairseqmmmodel.py b/examples/MMPT/mmpt/models/fairseqmmmodel.py new file mode 100644 index 0000000000..b7dd643693 --- /dev/null +++ b/examples/MMPT/mmpt/models/fairseqmmmodel.py @@ -0,0 +1,51 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from fairseq.models import ( + BaseFairseqModel, + register_model, + register_model_architecture +) + + +@register_model("mmmodel") +class FairseqMMModel(BaseFairseqModel): + """a fairseq wrapper of model built by `task`.""" + + @classmethod + def build_model(cls, args, task): + return FairseqMMModel(task.mmtask.model) + + def __init__(self, mmmodel): + super().__init__() + self.mmmodel = mmmodel + + def forward(self, *args, **kwargs): + return self.mmmodel(*args, **kwargs) + + def upgrade_state_dict_named(self, state_dict, name): + + super().upgrade_state_dict_named(state_dict, name) + + keys_to_delete = [] + + for key in state_dict: + if key not in self.state_dict(): + keys_to_delete.append(key) + for key in keys_to_delete: + print("[INFO]", key, "not used anymore.") + del state_dict[key] + + # copy any newly defined parameters. + for key in self.state_dict(): + if key not in state_dict: + print("[INFO] adding", key) + state_dict[key] = self.state_dict()[key] + + +# a dummy arch, we config the model. +@register_model_architecture("mmmodel", "mmarch") +def mmarch(args): + pass diff --git a/examples/MMPT/mmpt/models/mmfusion.py b/examples/MMPT/mmpt/models/mmfusion.py new file mode 100644 index 0000000000..fcdc7c5c04 --- /dev/null +++ b/examples/MMPT/mmpt/models/mmfusion.py @@ -0,0 +1,920 @@ +# coding=utf-8 +# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team. +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Copyright (c) Facebook, Inc. All Rights Reserved + + +import torch + +from torch import nn + +try: + from transformers import AutoConfig, AutoTokenizer +except ImportError: + pass + +from . import transformermodel + + +class MMPTModel(nn.Module): + """An e2e wrapper of inference model. + """ + @classmethod + def from_pretrained(cls, config, checkpoint="checkpoint_best.pt"): + import os + from ..utils import recursive_config + from ..tasks import Task + config = recursive_config(config) + mmtask = Task.config_task(config) + checkpoint_path = os.path.join(config.eval.save_path, checkpoint) + mmtask.build_model(checkpoint=checkpoint_path) + # TODO(huxu): make the video encoder configurable. + from ..processors.models.s3dg import S3D + video_encoder = S3D('pretrained_models/s3d_dict.npy', 512) + video_encoder.load_state_dict( + torch.load('pretrained_models/s3d_howto100m.pth')) + from transformers import AutoTokenizer + tokenizer = AutoTokenizer.from_pretrained( + config.dataset.bert_name, use_fast=config.dataset.use_fast + ) + from ..processors import Aligner + aligner = Aligner(config.dataset) + return ( + MMPTModel(config, mmtask.model, video_encoder), + tokenizer, + aligner + ) + + def __init__(self, config, model, video_encoder, **kwargs): + super().__init__() + self.max_video_len = config.dataset.max_video_len + self.video_encoder = video_encoder + self.model = model + + def forward(self, video_frames, caps, cmasks, return_score=False): + bsz = video_frames.size(0) + seq_len = video_frames.size(1) + video_frames = video_frames.view(-1, *video_frames.size()[2:]) + vfeats = self.video_encoder(video_frames.permute(0, 4, 1, 2, 3)) + vfeats = vfeats['video_embedding'] + vfeats = vfeats.view(bsz, seq_len, vfeats.size(-1)) + padding = torch.zeros( + bsz, self.max_video_len - seq_len, vfeats.size(-1)) + vfeats = torch.cat([vfeats, padding], dim=1) + vmasks = torch.zeros((bsz, self.max_video_len), dtype=torch.bool) + output = self.model(caps, cmasks, vfeats, vmasks) + if return_score: + output = {"score": torch.bmm( + output["pooled_video"][:, None, :], + output["pooled_video"][:, :, None] + ).squeeze(-1).squeeze(-1)} + return output + + +class MMFusion(nn.Module): + """a MMPT wrapper class for MMBert style models. + TODO: move isolated mask to a subclass. + """ + def __init__(self, config, **kwargs): + super().__init__() + transformer_config = AutoConfig.from_pretrained( + config.dataset.bert_name) + self.hidden_size = transformer_config.hidden_size + self.is_train = False + if config.dataset.train_path is not None: + self.is_train = True + # 0 means no iso; 1-12 means iso up to that layer. + self.num_hidden_layers = transformer_config.num_hidden_layers + self.last_iso_layer = 0 + if config.dataset.num_iso_layer is not None: + self.last_iso_layer = config.dataset.num_iso_layer - 1 + 1 + + if config.model.mm_encoder_cls is not None: + mm_encoder_cls = getattr(transformermodel, config.model.mm_encoder_cls) + model_config = AutoConfig.from_pretrained(config.dataset.bert_name) + model_config.max_video_len = config.dataset.max_video_len + # TODO: a general way to add parameter for a model. + model_config.use_seg_emb = config.model.use_seg_emb + self.mm_encoder = mm_encoder_cls.from_pretrained( + config.dataset.bert_name, config=model_config) + elif config.model.video_encoder_cls is not None\ + and config.model.text_encoder_cls is not None: + video_encoder_cls = getattr(transformermodel, config.model.video_encoder_cls) + model_config = AutoConfig.from_pretrained(config.dataset.bert_name) + model_config.max_video_len = config.dataset.max_video_len + # TODO: make each model a set of config class. + if hasattr(model_config, "num_layers"): + model_config.num_layers = config.model.num_hidden_video_layers + else: + model_config.num_hidden_layers = config.model.num_hidden_video_layers + self.video_encoder = video_encoder_cls.from_pretrained( + config.dataset.bert_name, config=model_config) + # exact same NLP model from Huggingface. + text_encoder_cls = getattr(transformermodel, config.model.text_encoder_cls) + self.text_encoder = text_encoder_cls.from_pretrained( + config.dataset.bert_name) + else: + raise ValueError("the encoder must be either MM or two backbones.") + + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + **kwargs + ): + raise NotImplementedError( + "Please derive MMFusion module." + ) + + def _mm_on_the_fly( + self, + cmasks, + vmasks, + attention_mask + ): + """helper function for mask, seg_ids and token_type_ids.""" + if attention_mask is None: + attention_mask = self._mm_attention_mask(cmasks, vmasks) + + """ + 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 + | first sequence | second sequence | + """ + token_type_ids = torch.cat( + [ + torch.zeros( + (vmasks.size(0), vmasks.size(1) + 2), + dtype=torch.long, + device=vmasks.device, + ), + torch.ones( + (cmasks.size(0), cmasks.size(1) - 2), + dtype=torch.long, + device=cmasks.device, + ), + ], + dim=1, + ) + return attention_mask, token_type_ids + + def _mm_attention_mask(self, cmasks, vmasks): + assert cmasks.size(0) == vmasks.size(0), "{}, {}, {}, {}".format( + str(cmasks.size()), + str(vmasks.size()), + str(cmasks.size(0)), + str(vmasks.size(0)), + ) + + mm_mask = torch.cat([cmasks[:, :1], vmasks, cmasks[:, 1:]], dim=1) + if self.last_iso_layer == 0: + # hard attention mask. + return mm_mask + else: + # a gpu iso mask; 0 : num_iso_layer is isolated; + # num_iso_layer: are MM-fused. + # make an iso layer + batch_size = cmasks.size(0) + iso_mask = self._make_iso_mask(batch_size, cmasks, vmasks) + mm_mask = mm_mask[:, None, :].repeat(1, mm_mask.size(-1), 1) + iso_mm_masks = [] + # hard attention mask. + iso_mask = iso_mask[:, None, :, :].repeat( + 1, self.last_iso_layer, 1, 1) + iso_mm_masks.append(iso_mask) + if self.last_iso_layer < self.num_hidden_layers: + mm_mask = mm_mask[:, None, :, :].repeat( + 1, self.num_hidden_layers - self.last_iso_layer, 1, 1 + ) + iso_mm_masks.append(mm_mask) + iso_mm_masks = torch.cat(iso_mm_masks, dim=1) + return iso_mm_masks + + def _make_iso_mask(self, batch_size, cmasks, vmasks): + cls_self_mask = torch.cat( + [ + torch.ones( + (batch_size, 1), dtype=torch.bool, device=cmasks.device), + torch.zeros( + (batch_size, cmasks.size(1) + vmasks.size(1) - 1), + dtype=torch.bool, device=cmasks.device) + ], dim=1) + + iso_video_mask = torch.cat( + [ + # [CLS] is not used. + torch.zeros( + (batch_size, 1), dtype=torch.bool, device=cmasks.device + ), + vmasks, + # assume to be 1. + cmasks[:, 1:2], + # 2 means [CLS] + [SEP] + torch.zeros( + (batch_size, cmasks.size(1) - 2), + dtype=torch.bool, + device=cmasks.device, + ), + ], + dim=1, + ) + iso_text_mask = torch.cat( + [ + torch.zeros( + (batch_size, 2 + vmasks.size(1)), + dtype=torch.bool, + device=cmasks.device, + ), # [CLS] is not used. + cmasks[:, 2:], # assume to be 1. + ], + dim=1, + ) + cls_self_mask = cls_self_mask[:, None, :] + iso_video_mask = iso_video_mask[:, None, :].repeat( + 1, vmasks.size(1) + 1, 1) + iso_text_mask = iso_text_mask[:, None, :].repeat( + 1, cmasks.size(1) - 2, 1) + return torch.cat([cls_self_mask, iso_video_mask, iso_text_mask], dim=1) + + def _pooling_vt_layer( + self, + layered_sequence_output, + cmasks, + vmasks + ): + layer_idx = self.last_iso_layer \ + if self.last_iso_layer > 0 else self.num_hidden_layers + hidden_state = layered_sequence_output[layer_idx] + # also output pooled_video and pooled_text. + batch_size = cmasks.size(0) + # pool the modality. + text_offset = vmasks.size(1) + 2 # [CLS] + [SEP] + # video tokens + [SEP] + video_outputs = hidden_state[:, 1:text_offset] + video_attention_mask = torch.cat( + [ + vmasks, + torch.ones( + (batch_size, 1), dtype=torch.bool, device=vmasks.device), + ], + dim=1, + ) + assert video_outputs.size(1) == video_attention_mask.size(1) + pooled_video = torch.sum( + video_outputs * video_attention_mask.unsqueeze(-1), dim=1 + ) / video_attention_mask.sum(1, keepdim=True) + # pooled_video = torch.mean(video_outputs[0], dim=1) + + # text tokens + [SEP] + text_attention_mask = cmasks[:, 2:] + text_outputs = hidden_state[:, text_offset:] + assert text_outputs.size(1) == text_attention_mask.size(1) + pooled_text = torch.sum( + text_outputs * text_attention_mask.unsqueeze(-1), dim=1 + ) / text_attention_mask.sum(1, keepdim=True) + return pooled_video, pooled_text + + +class MMFusionMFMMLM(MMFusion): + """forward function for MFM and MLM.""" + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + attention_mask=None, + video_label=None, + text_label=None, + **kwargs + ): + output_hidden_states = False if self.is_train else True + + target_vfeats, non_masked_frame_mask = None, None + if video_label is not None: + target_vfeats = vfeats.masked_select( + video_label.unsqueeze(-1)).view( + -1, vfeats.size(-1) + ) + # mask video token. + vfeats[video_label] = 0.0 + non_masked_frame_mask = vmasks.clone() + non_masked_frame_mask[video_label] = False + + attention_mask, token_type_ids = self._mm_on_the_fly( + cmasks, vmasks, attention_mask) + + outputs = self.mm_encoder( + input_ids=caps, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + masked_frame_labels=video_label, + target_video_hidden_states=target_vfeats, + non_masked_frame_mask=non_masked_frame_mask, + masked_lm_labels=text_label, + output_hidden_states=output_hidden_states, + ) + + video_logits, text_logits = outputs[0], outputs[1] + + if self.is_train: # return earlier for training. + return { + "video_logits": video_logits, + "text_logits": text_logits, + } + + pooled_video, pooled_text = self._pooling_vt_layer( + outputs[2], cmasks, vmasks) + return {"pooled_video": pooled_video, "pooled_text": pooled_text} + + +class MMFusionMTM(MMFusionMFMMLM): + def __init__(self, config, **kwargs): + super().__init__(config) + """ + For reproducibility: + self.mm_encoder will be initialized then discarded. + """ + from .transformermodel import MMBertForMTM + model_config = AutoConfig.from_pretrained(config.dataset.bert_name) + model_config.max_video_len = config.dataset.max_video_len + model_config.use_seg_emb = config.model.use_seg_emb + self.mm_encoder = MMBertForMTM.from_pretrained( + config.dataset.bert_name, config=model_config) + + +class MMFusionShare(MMFusion): + """A retrival wrapper using mm_encoder as both video/text backbone. + TODO: move formally. + """ + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + attention_mask=None, + video_label=None, + text_label=None, + output_hidden_states=False, + **kwargs + ): + pooled_video = self.forward_video( + vfeats, + vmasks, + caps, + cmasks, + output_hidden_states + ) + + pooled_text = self.forward_text( + caps, + cmasks, + output_hidden_states + ) + + return {"pooled_video": pooled_video, "pooled_text": pooled_text} + + def forward_video( + self, + vfeats, + vmasks, + caps, + cmasks, + output_hidden_states=False, + **kwargs + ): + input_ids = caps[:, :2] + + attention_mask = torch.cat([ + cmasks[:, :1], + vmasks, + cmasks[:, 1:2] + ], dim=1) + + token_type_ids = torch.zeros( + (vmasks.size(0), vmasks.size(1) + 2), + dtype=torch.long, + device=vmasks.device) + + outputs = self.mm_encoder( + input_ids=input_ids, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=True + ) + video_outputs = outputs[0] + + if output_hidden_states: + return video_outputs + + batch_size = cmasks.size(0) + + video_attention_mask = torch.cat( + [ + torch.zeros( + (batch_size, 1), dtype=torch.bool, device=vmasks.device), + vmasks, + torch.ones( + (batch_size, 1), dtype=torch.bool, device=vmasks.device), + ], + dim=1, + ) + assert video_outputs.size(1) == video_attention_mask.size(1) + + video_attention_mask = video_attention_mask.type(video_outputs.dtype) \ + / video_attention_mask.sum(1, keepdim=True) + + pooled_video = torch.bmm( + video_outputs.transpose(2, 1), + video_attention_mask.unsqueeze(2) + ).squeeze(-1) + return pooled_video # video_outputs + + def forward_text( + self, + caps, + cmasks, + output_hidden_states=False, + **kwargs + ): + input_ids = torch.cat([ + caps[:, :1], caps[:, 2:], + ], dim=1) + + attention_mask = torch.cat([ + cmasks[:, :1], + cmasks[:, 2:] + ], dim=1) + + token_type_ids = torch.cat([ + torch.zeros( + (cmasks.size(0), 1), + dtype=torch.long, + device=cmasks.device), + torch.ones( + (cmasks.size(0), cmasks.size(1) - 2), + dtype=torch.long, + device=cmasks.device) + ], dim=1) + + outputs = self.mm_encoder( + input_ids=input_ids, + input_video_embeds=None, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=True + ) + text_outputs = outputs[0] + + if output_hidden_states: + return text_outputs + + batch_size = caps.size(0) + # text tokens + [SEP] + text_attention_mask = torch.cat([ + torch.zeros( + (batch_size, 1), dtype=torch.bool, device=cmasks.device), + cmasks[:, 2:] + ], dim=1) + + assert text_outputs.size(1) == text_attention_mask.size(1) + + text_attention_mask = text_attention_mask.type(text_outputs.dtype) \ + / text_attention_mask.sum(1, keepdim=True) + + pooled_text = torch.bmm( + text_outputs.transpose(2, 1), + text_attention_mask.unsqueeze(2) + ).squeeze(-1) + return pooled_text # text_outputs + + +class MMFusionSeparate(MMFusionShare): + def forward_video( + self, + vfeats, + vmasks, + caps, + cmasks, + output_hidden_states=False, + **kwargs + ): + input_ids = caps[:, :2] + + attention_mask = torch.cat([ + cmasks[:, :1], + vmasks, + cmasks[:, 1:2] + ], dim=1) + + token_type_ids = torch.zeros( + (vmasks.size(0), vmasks.size(1) + 2), + dtype=torch.long, + device=vmasks.device) + + outputs = self.video_encoder( + input_ids=input_ids, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=True + ) + video_outputs = outputs[0] + + if output_hidden_states: + return video_outputs + + batch_size = cmasks.size(0) + + video_attention_mask = torch.cat( + [ + torch.zeros( + (batch_size, 1), dtype=torch.bool, device=vmasks.device), + vmasks, + torch.ones( + (batch_size, 1), dtype=torch.bool, device=vmasks.device), + ], + dim=1, + ) + assert video_outputs.size(1) == video_attention_mask.size(1) + + video_attention_mask = video_attention_mask.type(video_outputs.dtype) \ + / video_attention_mask.sum(1, keepdim=True) + + pooled_video = torch.bmm( + video_outputs.transpose(2, 1), + video_attention_mask.unsqueeze(2) + ).squeeze(-1) + return pooled_video # video_outputs + + def forward_text( + self, + caps, + cmasks, + output_hidden_states=False, + **kwargs + ): + input_ids = torch.cat([ + caps[:, :1], caps[:, 2:], + ], dim=1) + + attention_mask = torch.cat([ + cmasks[:, :1], + cmasks[:, 2:] + ], dim=1) + # different from sharing, we use all-0 type. + token_type_ids = torch.zeros( + (cmasks.size(0), cmasks.size(1) - 1), + dtype=torch.long, + device=cmasks.device) + + outputs = self.text_encoder( + input_ids=input_ids, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=True + ) + text_outputs = outputs[0] + + if output_hidden_states: + return text_outputs + + batch_size = caps.size(0) + # text tokens + [SEP] + text_attention_mask = torch.cat([ + torch.zeros( + (batch_size, 1), dtype=torch.bool, device=cmasks.device), + cmasks[:, 2:] + ], dim=1) + + assert text_outputs.size(1) == text_attention_mask.size(1) + + text_attention_mask = text_attention_mask.type(text_outputs.dtype) \ + / text_attention_mask.sum(1, keepdim=True) + + pooled_text = torch.bmm( + text_outputs.transpose(2, 1), + text_attention_mask.unsqueeze(2) + ).squeeze(-1) + return pooled_text # text_outputs + + +class MMFusionJoint(MMFusion): + """fine-tuning wrapper for retrival task.""" + + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + attention_mask=None, + video_label=None, + text_label=None, + **kwargs + ): + # TODO (huxu): other ways to do negative examples; move the following + # into your criterion forward. + output_hidden_states = True + + attention_mask, token_type_ids = self._mm_on_the_fly( + cmasks, vmasks, attention_mask) + + separate_forward_split = ( + None if self.is_train else vmasks.size(1) + 2 + ) # [CLS] + [SEP] + + outputs = self.mm_encoder( + input_ids=caps, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=output_hidden_states, + separate_forward_split=separate_forward_split, + ) + + pooled_video, pooled_text = self._pooling_vt_layer( + outputs[2], cmasks, vmasks) + return {"pooled_video": pooled_video, "pooled_text": pooled_text} + + +class MMFusionActionSegmentation(MMFusion): + """Fine-tuning wrapper for action segmentation. + TODO: rename this for VLM. + """ + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + attention_mask=None, + **kwargs + ): + # ActionLocalization assume of batch_size=1, squeeze it. + caps = caps.view(-1, caps.size(-1)) + cmasks = cmasks.view(-1, cmasks.size(-1)) + vfeats = vfeats.view(-1, vfeats.size(2), vfeats.size(3)) + vmasks = vmasks.view(-1, vmasks.size(-1)) + + # this may not cover all shapes of attention_mask. + attention_mask = attention_mask.view( + -1, attention_mask.size(2), attention_mask.size(3)) \ + if attention_mask is not None else None + + # TODO (huxu): other ways to do negative examples; move the following + # into your criterion forward. + output_hidden_states = True + + # video forwarding, text is dummy; never use attention_mask. + attention_mask, token_type_ids = self._mm_on_the_fly( + cmasks, vmasks, attention_mask) + + logits = self.mm_encoder( + input_ids=caps, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=output_hidden_states, + ) + return {"logits": logits[0][:, 1:vmasks.size(1)+1]} + + +class MMFusionActionLocalization(MMFusion): + """fine-tuning model for retrival task.""" + + def __init__(self, config, **kwargs): + super().__init__(config) + tokenizer = AutoTokenizer.from_pretrained( + config.dataset.bert_name) + self.cls_token_id = tokenizer.cls_token_id + self.sep_token_id = tokenizer.sep_token_id + self.pad_token_id = tokenizer.pad_token_id + + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + attention_mask=None, + **kwargs + ): + # ActionLocalization assume of batch_size=1, squeeze it. + caps = caps.squeeze(0) + cmasks = cmasks.squeeze(0) + vfeats = vfeats.squeeze(0) + vmasks = vmasks.squeeze(0) + attention_mask = attention_mask.squeeze(0) if attention_mask is not None else None + + # TODO (huxu): other ways to do negative examples; move the following + # into your criterion forward. + output_hidden_states = True + + # a len1 dummy video token. + dummy_vfeats = torch.zeros( + (caps.size(0), 1, vfeats.size(-1)), device=vfeats.device, dtype=vfeats.dtype) + dummy_vmasks = torch.ones( + (caps.size(0), 1), dtype=torch.bool, + device=vfeats.device) + + dummy_caps = torch.LongTensor( + [[self.cls_token_id, self.sep_token_id, + self.pad_token_id, self.sep_token_id]], + ).to(caps.device).repeat(vfeats.size(0), 1) + dummy_cmasks = torch.BoolTensor( + [[0, 1, 0, 1]] # pad are valid for attention. + ).to(caps.device).repeat(vfeats.size(0), 1) + + # video forwarding, text is dummy; never use attention_mask. + attention_mask, token_type_ids = self._mm_on_the_fly( + dummy_cmasks, vmasks, None) + + outputs = self.mm_encoder( + input_ids=dummy_caps, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=output_hidden_states, + ) + + layer_idx = self.last_iso_layer \ + if self.last_iso_layer > 0 else self.num_hidden_layers + + video_seq = outputs[2][layer_idx][:, 1:vmasks.size(1)+1].masked_select( + vmasks.unsqueeze(-1) + ).view(-1, self.hidden_size) + + # text forwarding, video is dummy + attention_mask, token_type_ids = self._mm_on_the_fly( + cmasks, dummy_vmasks, None) + + outputs = self.mm_encoder( + input_ids=caps, + input_video_embeds=dummy_vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + output_hidden_states=output_hidden_states, + ) + + _, pooled_text = self._pooling_vt_layer( + outputs[2], cmasks, dummy_vmasks) + # this line is not right. + logits = torch.mm(video_seq, pooled_text.transpose(1, 0)) + return {"logits": logits} + + +# --------------- MMFusionSeparate for end tasks --------------- + +class MMFusionSeparateActionSegmentation(MMFusionSeparate): + """Fine-tuning wrapper for action segmentation.""" + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + attention_mask=None, + **kwargs + ): + # ActionLocalization assume of batch_size=1, squeeze it. + caps = caps.view(-1, caps.size(-1)) + cmasks = cmasks.view(-1, cmasks.size(-1)) + vfeats = vfeats.view(-1, vfeats.size(2), vfeats.size(3)) + vmasks = vmasks.view(-1, vmasks.size(-1)) + logits = self.forward_video( + vfeats, + vmasks, + caps, + cmasks, + output_hidden_states=True + ) + return {"logits": logits[:, 1:vmasks.size(1)+1]} + + +class MMFusionSeparateActionLocalization(MMFusionSeparate): + def __init__(self, config, **kwargs): + super().__init__(config) + tokenizer = AutoTokenizer.from_pretrained( + config.dataset.bert_name) + self.cls_token_id = tokenizer.cls_token_id + self.sep_token_id = tokenizer.sep_token_id + self.pad_token_id = tokenizer.pad_token_id + + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + **kwargs + ): + # ActionLocalization assume of batch_size=1, squeeze it. + caps = caps.squeeze(0) + cmasks = cmasks.squeeze(0) + vfeats = vfeats.squeeze(0) + vmasks = vmasks.squeeze(0) + + # TODO (huxu): other ways to do negative examples; move the following + # into your criterion forward. + dummy_caps = torch.LongTensor( + [[self.cls_token_id, self.sep_token_id, + self.pad_token_id, self.sep_token_id]], + ).to(caps.device).repeat(vfeats.size(0), 1) + dummy_cmasks = torch.BoolTensor( + [[0, 1, 0, 1]] # pad are valid for attention. + ).to(caps.device).repeat(vfeats.size(0), 1) + + outputs = self.forward_video( + vfeats, + vmasks, + dummy_caps, + dummy_cmasks, + output_hidden_states=True + ) + + video_seq = outputs[:, 1:vmasks.size(1)+1].masked_select( + vmasks.unsqueeze(-1) + ).view(-1, self.hidden_size) + + pooled_text = self.forward_text( + caps, + cmasks, + output_hidden_states=False + ) + + # this line is not right. + logits = torch.mm(video_seq, pooled_text.transpose(1, 0)) + return {"logits": logits} + + +class MMFusionShareActionLocalization(MMFusionShare): + def __init__(self, config, **kwargs): + super().__init__(config) + tokenizer = AutoTokenizer.from_pretrained( + config.dataset.bert_name) + self.cls_token_id = tokenizer.cls_token_id + self.sep_token_id = tokenizer.sep_token_id + self.pad_token_id = tokenizer.pad_token_id + + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + **kwargs + ): + # ActionLocalization assume of batch_size=1, squeeze it. + caps = caps.squeeze(0) + cmasks = cmasks.squeeze(0) + vfeats = vfeats.squeeze(0) + vmasks = vmasks.squeeze(0) + + # TODO (huxu): other ways to do negative examples; move the following + # into your criterion forward. + dummy_caps = torch.LongTensor( + [[self.cls_token_id, self.sep_token_id, + self.pad_token_id, self.sep_token_id]], + ).to(caps.device).repeat(vfeats.size(0), 1) + dummy_cmasks = torch.BoolTensor( + [[0, 1, 0, 1]] # pad are valid for attention. + ).to(caps.device).repeat(vfeats.size(0), 1) + + outputs = self.forward_video( + vfeats, + vmasks, + dummy_caps, + dummy_cmasks, + output_hidden_states=True + ) + + video_seq = outputs[:, 1:vmasks.size(1)+1].masked_select( + vmasks.unsqueeze(-1) + ).view(-1, self.hidden_size) + + pooled_text = self.forward_text( + caps, + cmasks, + output_hidden_states=False + ) + + # this line is not right. + logits = torch.mm(video_seq, pooled_text.transpose(1, 0)) + return {"logits": logits} diff --git a/examples/MMPT/mmpt/models/mmfusionnlg.py b/examples/MMPT/mmpt/models/mmfusionnlg.py new file mode 100644 index 0000000000..9207e77dab --- /dev/null +++ b/examples/MMPT/mmpt/models/mmfusionnlg.py @@ -0,0 +1,999 @@ +# coding=utf-8 +# Copyright 2018 The Google AI Language Team Authors, Facebook AI Research authors and The HuggingFace Inc. team. +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Copyright (c) Facebook, Inc. All Rights Reserved + + +import torch + +from torch.nn import functional as F + +from typing import Optional, Iterable + +try: + from transformers import BertPreTrainedModel + from transformers.modeling_bert import BertOnlyMLMHead + + from transformers.file_utils import ModelOutput + from transformers.modeling_outputs import CausalLMOutput + from transformers.generation_utils import ( + BeamHypotheses, + top_k_top_p_filtering + ) +except ImportError: + pass + +from .mmfusion import MMFusion +from .transformermodel import MMBertModel +from ..modules import VideoTokenMLP + + +class MMFusionNLG(MMFusion): + def __init__(self, config, **kwargs): + super().__init__(config) + if config.model.max_decode_length is not None: + self.max_length = min( + config.model.max_decode_length, + config.dataset.max_len - config.dataset.max_video_len - 3 + ) + else: + self.max_length = \ + config.dataset.max_len - config.dataset.max_video_len - 3 + self.gen_param = config.gen_param if config.gen_param is not None \ + else {} + + def forward( + self, + caps, + cmasks, + vfeats, + vmasks, + attention_mask, + video_label=None, + text_label=None, + **kwargs + ): + """use pre-trained LM header for generation.""" + attention_mask, token_type_ids = self._mm_on_the_fly( + cmasks, vmasks, attention_mask) + + outputs = self.mm_encoder( + input_ids=caps, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + masked_lm_labels=text_label, + ) + return {"logits": outputs[0]} + + @torch.no_grad() + def generate( + self, + caps, cmasks, vfeats, vmasks, + attention_mask=None, + bos_token_id=None, + eos_token_id=None, + **kwargs + ): + # a simplified interface from + # https://huggingface.co/transformers/v3.4.0/_modules/transformers/generation_utils.html#GenerationMixin.generate + + # caps now only have + # [CLS], [SEP] (for video) and [CLS] (as bos_token) + assert caps.size(1) == 3 + + attention_mask, token_type_ids = self._mm_on_the_fly( + cmasks, vmasks, attention_mask) + + output = self.mm_encoder.generate( + input_ids=caps, + input_video_embeds=vfeats, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + bos_token_id=bos_token_id, + eos_token_id=eos_token_id, + max_length=self.max_length, + **self.gen_param + ) + return output + + +class MMBertForNLG(BertPreTrainedModel): + def __init__(self, config): + super().__init__(config) + self.bert = MMBertModel(config) + self.videomlp = VideoTokenMLP(config) + # we do not use `BertGenerationOnlyLMHead` + # because we can reuse pretraining. + self.cls = BertOnlyMLMHead(config) + self.hidden_size = config.hidden_size + self.init_weights() + + def get_output_embeddings(self): + return self.cls.predictions.decoder + + def forward( + self, + input_ids=None, + input_video_embeds=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + masked_lm_labels=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + ): + # similar to MMBertForMFMMLM without MFM. + video_tokens = self.videomlp(input_video_embeds) + outputs = self.bert( + input_ids, + video_tokens, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + position_ids=position_ids, + head_mask=head_mask, + inputs_embeds=inputs_embeds, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + sequence_output = outputs[0] + + prediction_scores = None + if masked_lm_labels is not None: + text_offset = input_video_embeds.size(1) + 1 # [CLS] + # recover caps format: [CLS] [SEP] text [SEP] + text_sequence_output = torch.cat( + [sequence_output[:, :1], sequence_output[:, text_offset:]], + dim=1 + ) + + # only compute select tokens to training to speed up. + hidden_size = text_sequence_output.size(-1) + # masked_lm_labels = masked_lm_labels.reshape(-1) + labels_mask = masked_lm_labels != -100 + + selected_text_output = text_sequence_output.masked_select( + labels_mask.unsqueeze(-1) + ).view(-1, hidden_size) + prediction_scores = self.cls(selected_text_output) + + if not return_dict: + output = ( + prediction_scores, + ) + outputs[2:] + return output + + # for generation. + text_offset = input_video_embeds.size(1) + 2 # [CLS] + text_sequence_output = sequence_output[:, text_offset:] + prediction_scores = self.cls(text_sequence_output) + return CausalLMOutput( + loss=None, + logits=prediction_scores, + ) + + def prepare_inputs_for_generation( + self, + input_ids, + input_video_embeds, + attention_mask=None, + token_type_ids=None, + **model_kwargs + ): + # must return a dictionary. + seq_len = input_ids.size(1) + input_video_embeds.size(1) + if attention_mask is not None: + if len(attention_mask.size()) == 4: + attention_mask = attention_mask[:, :, :seq_len, :seq_len] + elif len(attention_mask.size()) == 3: + attention_mask = attention_mask[:, :seq_len, :seq_len] + else: + attention_mask = attention_mask[:, :seq_len] + if token_type_ids is not None: + token_type_ids = token_type_ids[:, :seq_len] + + return { + "input_ids": input_ids, + "input_video_embeds": input_video_embeds, + "attention_mask": attention_mask, + "token_type_ids": token_type_ids, + } + + @torch.no_grad() + def generate( + self, + input_ids: Optional[torch.LongTensor] = None, + decoder_input_ids: Optional[torch.LongTensor] = None, + max_length: Optional[int] = None, + min_length: Optional[int] = None, + do_sample: Optional[bool] = None, + early_stopping: Optional[bool] = None, + num_beams: Optional[int] = None, + temperature: Optional[float] = None, + top_k: Optional[int] = None, + top_p: Optional[float] = None, + repetition_penalty: Optional[float] = None, + bad_words_ids: Optional[Iterable[int]] = None, + bos_token_id: Optional[int] = None, + pad_token_id: Optional[int] = None, + eos_token_id: Optional[int] = None, + length_penalty: Optional[float] = None, + no_repeat_ngram_size: Optional[int] = None, + num_return_sequences: Optional[int] = None, + attention_mask: Optional[torch.LongTensor] = None, + decoder_start_token_id: Optional[int] = None, + use_cache: Optional[bool] = None, + **model_kwargs + ) -> torch.LongTensor: + r""" + Generates sequences for models with a language modeling head. The method currently supports greedy decoding, + beam-search decoding, sampling with temperature, sampling with top-k or nucleus sampling. + Adapted in part from `Facebook's XLM beam search code + <https://github.com/facebookresearch/XLM/blob/9e6f6814d17be4fe5b15f2e6c43eb2b2d76daeb4/src/model/transformer.py#L529>`__. + Apart from :obj:`input_ids` and :obj:`attention_mask`, all the arguments below will default to the value of the + attribute of the same name inside the :class:`~transformers.PretrainedConfig` of the model. The default values + indicated are the default values of those config. + Most of these parameters are explained in more detail in `this blog post + <https://huggingface.co/blog/how-to-generate>`__. + Parameters: + input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`): + The sequence used as a prompt for the generation. If :obj:`None` the method initializes + it as an empty :obj:`torch.LongTensor` of shape :obj:`(1,)`. + decoder_input_ids (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`): + initial input_ids for the decoder of encoder-decoder type models. If :obj:`None` then only + decoder_start_token_id is passed as the first token to the decoder. + max_length (:obj:`int`, `optional`, defaults to 20): + The maximum length of the sequence to be generated. + min_length (:obj:`int`, `optional`, defaults to 10): + The minimum length of the sequence to be generated. + do_sample (:obj:`bool`, `optional`, defaults to :obj:`False`): + Whether or not to use sampling ; use greedy decoding otherwise. + early_stopping (:obj:`bool`, `optional`, defaults to :obj:`False`): + Whether to stop the beam search when at least ``num_beams`` sentences are finished per batch or not. + num_beams (:obj:`int`, `optional`, defaults to 1): + Number of beams for beam search. 1 means no beam search. + temperature (:obj:`float`, `optional`, defaults tp 1.0): + The value used to module the next token probabilities. + top_k (:obj:`int`, `optional`, defaults to 50): + The number of highest probability vocabulary tokens to keep for top-k-filtering. + top_p (:obj:`float`, `optional`, defaults to 1.0): + If set to float < 1, only the most probable tokens with probabilities that add up to ``top_p`` or + higher are kept for generation. + repetition_penalty (:obj:`float`, `optional`, defaults to 1.0): + The parameter for repetition penalty. 1.0 means no penalty. See `this paper + <https://arxiv.org/pdf/1909.05858.pdf>`__ for more details. + pad_token_id (:obj:`int`, `optional`): + The id of the `padding` token. + bos_token_id (:obj:`int`, `optional`): + The id of the `beginning-of-sequence` token. + eos_token_id (:obj:`int`, `optional`): + The id of the `end-of-sequence` token. + length_penalty (:obj:`float`, `optional`, defaults to 1.0): + Exponential penalty to the length. 1.0 means no penalty. + Set to values < 1.0 in order to encourage the model to generate shorter sequences, to a value > 1.0 in + order to encourage the model to produce longer sequences. + no_repeat_ngram_size (:obj:`int`, `optional`, defaults to 0): + If set to int > 0, all ngrams of that size can only occur once. + bad_words_ids(:obj:`List[int]`, `optional`): + List of token ids that are not allowed to be generated. In order to get the tokens of the words that + should not appear in the generated text, use :obj:`tokenizer.encode(bad_word, add_prefix_space=True)`. + num_return_sequences(:obj:`int`, `optional`, defaults to 1): + The number of independently computed returned sequences for each element in the batch. + attention_mask (:obj:`torch.LongTensor` of shape :obj:`(batch_size, sequence_length)`, `optional`): + Mask to avoid performing attention on padding token indices. Mask values are in ``[0, 1]``, 1 for + tokens that are not masked, and 0 for masked tokens. + If not provided, will default to a tensor the same shape as :obj:`input_ids` that masks the pad token. + `What are attention masks? <../glossary.html#attention-mask>`__ + decoder_start_token_id (:obj:`int`, `optional`): + If an encoder-decoder model starts decoding with a different token than `bos`, the id of that token. + use_cache: (:obj:`bool`, `optional`, defaults to :obj:`True`): + Whether or not the model should use the past last key/values attentions (if applicable to the model) to + speed up decoding. + model_kwargs: + Additional model specific kwargs will be forwarded to the :obj:`forward` function of the model. + Return: + :obj:`torch.LongTensor` of shape :obj:`(batch_size * num_return_sequences, sequence_length)`: + The generated sequences. The second dimension (sequence_length) is either equal to :obj:`max_length` or + shorter if all batches finished early due to the :obj:`eos_token_id`. + Examples:: + tokenizer = AutoTokenizer.from_pretrained('distilgpt2') # Initialize tokenizer + model = AutoModelWithLMHead.from_pretrained('distilgpt2') # Download model and configuration from S3 and cache. + outputs = model.generate(max_length=40) # do greedy decoding + print('Generated: {}'.format(tokenizer.decode(outputs[0], skip_special_tokens=True))) + tokenizer = AutoTokenizer.from_pretrained('openai-gpt') # Initialize tokenizer + model = AutoModelWithLMHead.from_pretrained('openai-gpt') # Download model and configuration from S3 and cache. + input_context = 'The dog' + input_ids = tokenizer.encode(input_context, return_tensors='pt') # encode input context + outputs = model.generate(input_ids=input_ids, num_beams=5, num_return_sequences=3, temperature=1.5) # generate 3 independent sequences using beam search decoding (5 beams) with sampling from initial context 'The dog' + for i in range(3): # 3 output sequences were generated + print('Generated {}: {}'.format(i, tokenizer.decode(outputs[i], skip_special_tokens=True))) + tokenizer = AutoTokenizer.from_pretrained('distilgpt2') # Initialize tokenizer + model = AutoModelWithLMHead.from_pretrained('distilgpt2') # Download model and configuration from S3 and cache. + input_context = 'The dog' + input_ids = tokenizer.encode(input_context, return_tensors='pt') # encode input context + outputs = model.generate(input_ids=input_ids, max_length=40, temperature=0.7, num_return_sequences=3, do_sample=True) # generate 3 candidates using sampling + for i in range(3): # 3 output sequences were generated + print('Generated {}: {}'.format(i, tokenizer.decode(outputs[i], skip_special_tokens=True))) + tokenizer = AutoTokenizer.from_pretrained('ctrl') # Initialize tokenizer + model = AutoModelWithLMHead.from_pretrained('ctrl') # Download model and configuration from S3 and cache. + input_context = 'Legal My neighbor is' # "Legal" is one of the control codes for ctrl + input_ids = tokenizer.encode(input_context, return_tensors='pt') # encode input context + outputs = model.generate(input_ids=input_ids, max_length=50, temperature=0.7, repetition_penalty=1.2) # generate sequences + print('Generated: {}'.format(tokenizer.decode(outputs[0], skip_special_tokens=True))) + tokenizer = AutoTokenizer.from_pretrained('gpt2') # Initialize tokenizer + model = AutoModelWithLMHead.from_pretrained('gpt2') # Download model and configuration from S3 and cache. + input_context = 'My cute dog' # "Legal" is one of the control codes for ctrl + bad_words_ids = [tokenizer.encode(bad_word, add_prefix_space=True) for bad_word in ['idiot', 'stupid', 'shut up']] + input_ids = tokenizer.encode(input_context, return_tensors='pt') # encode input context + outputs = model.generate(input_ids=input_ids, max_length=100, do_sample=True, bad_words_ids=bad_words_ids) # generate sequences without allowing bad_words to be generated + """ + + # We cannot generate if the model does not have a LM head + if self.get_output_embeddings() is None: + raise AttributeError( + "You tried to generate sequences with a model that does not have a LM Head." + "Please use another model class (e.g. `OpenAIGPTLMHeadModel`, `XLNetLMHeadModel`, `GPT2LMHeadModel`, `CTRLLMHeadModel`, `T5WithLMHeadModel`, `TransfoXLLMHeadModel`, `XLMWithLMHeadModel`, `BartForConditionalGeneration` )" + ) + + max_length = max_length if max_length is not None else self.config.max_length + min_length = min_length if min_length is not None else self.config.min_length + do_sample = do_sample if do_sample is not None else self.config.do_sample + early_stopping = early_stopping if early_stopping is not None else self.config.early_stopping + use_cache = use_cache if use_cache is not None else self.config.use_cache + num_beams = num_beams if num_beams is not None else self.config.num_beams + temperature = temperature if temperature is not None else self.config.temperature + top_k = top_k if top_k is not None else self.config.top_k + top_p = top_p if top_p is not None else self.config.top_p + repetition_penalty = repetition_penalty if repetition_penalty is not None else self.config.repetition_penalty + bos_token_id = bos_token_id if bos_token_id is not None else self.config.bos_token_id + pad_token_id = pad_token_id if pad_token_id is not None else self.config.pad_token_id + eos_token_id = eos_token_id if eos_token_id is not None else self.config.eos_token_id + length_penalty = length_penalty if length_penalty is not None else self.config.length_penalty + no_repeat_ngram_size = ( + no_repeat_ngram_size if no_repeat_ngram_size is not None else self.config.no_repeat_ngram_size + ) + bad_words_ids = bad_words_ids if bad_words_ids is not None else self.config.bad_words_ids + num_return_sequences = ( + num_return_sequences if num_return_sequences is not None else self.config.num_return_sequences + ) + decoder_start_token_id = ( + decoder_start_token_id if decoder_start_token_id is not None else self.config.decoder_start_token_id + ) + + if input_ids is not None: + batch_size = input_ids.shape[0] # overriden by the input batch_size + else: + batch_size = 1 + + assert isinstance(max_length, int) and max_length > 0, "`max_length` should be a strictly positive integer." + assert isinstance(min_length, int) and min_length >= 0, "`min_length` should be a positive integer." + assert isinstance(do_sample, bool), "`do_sample` should be a boolean." + assert isinstance(early_stopping, bool), "`early_stopping` should be a boolean." + assert isinstance(use_cache, bool), "`use_cache` should be a boolean." + assert isinstance(num_beams, int) and num_beams > 0, "`num_beams` should be a strictly positive integer." + assert temperature > 0, "`temperature` should be strictly positive." + assert isinstance(top_k, int) and top_k >= 0, "`top_k` should be a positive integer." + assert 0 <= top_p <= 1, "`top_p` should be between 0 and 1." + assert repetition_penalty >= 1.0, "`repetition_penalty` should be >= 1." + assert input_ids is not None or ( + isinstance(bos_token_id, int) and bos_token_id >= 0 + ), "If input_ids is not defined, `bos_token_id` should be a positive integer." + assert pad_token_id is None or ( + isinstance(pad_token_id, int) and (pad_token_id >= 0) + ), "`pad_token_id` should be a positive integer." + assert (eos_token_id is None) or ( + isinstance(eos_token_id, int) and (eos_token_id >= 0) + ), "`eos_token_id` should be a positive integer." + assert length_penalty > 0, "`length_penalty` should be strictly positive." + assert ( + isinstance(no_repeat_ngram_size, int) and no_repeat_ngram_size >= 0 + ), "`no_repeat_ngram_size` should be a positive integer." + assert ( + isinstance(num_return_sequences, int) and num_return_sequences > 0 + ), "`num_return_sequences` should be a strictly positive integer." + assert ( + bad_words_ids is None or isinstance(bad_words_ids, list) and isinstance(bad_words_ids[0], list) + ), "`bad_words_ids` is either `None` or a list of lists of tokens that should not be generated" + + if input_ids is None: + assert isinstance(bos_token_id, int) and bos_token_id >= 0, ( + "you should either supply a context to complete as `input_ids` input " + "or a `bos_token_id` (integer >= 0) as a first token to start the generation." + ) + input_ids = torch.full( + (batch_size, 1), + bos_token_id, + dtype=torch.long, + device=next(self.parameters()).device, + ) + else: + assert input_ids.dim() == 2, "Input prompt should be of shape (batch_size, sequence length)." + + # not allow to duplicate outputs when greedy decoding + if do_sample is False: + if num_beams == 1: + # no_beam_search greedy generation conditions + assert ( + num_return_sequences == 1 + ), "Greedy decoding will always produce the same output for num_beams == 1 and num_return_sequences > 1. Please set num_return_sequences = 1" + + else: + # beam_search greedy generation conditions + assert ( + num_beams >= num_return_sequences + ), "Greedy beam search decoding cannot return more sequences than it has beams. Please set num_beams >= num_return_sequences" + + # create attention mask if necessary + # TODO (PVP): this should later be handled by the forward fn() in each model in the future see PR 3140 + if (attention_mask is None) and (pad_token_id is not None) and (pad_token_id in input_ids): + attention_mask = input_ids.ne(pad_token_id).long() + elif attention_mask is None: + attention_mask = input_ids.new_ones(input_ids.shape) + + # set pad_token_id to eos_token_id if not set. Important that this is done after + # attention_mask is created + if pad_token_id is None and eos_token_id is not None: + print( + "Setting `pad_token_id` to {} (first `eos_token_id`) to generate sequence".format(eos_token_id) + ) + pad_token_id = eos_token_id + + # vocab size + if hasattr(self.config, "vocab_size"): + vocab_size = self.config.vocab_size + elif ( + self.config.is_encoder_decoder + and hasattr(self.config, "decoder") + and hasattr(self.config.decoder, "vocab_size") + ): + vocab_size = self.config.decoder.vocab_size + else: + raise ValueError("either self.config.vocab_size or self.config.decoder.vocab_size needs to be defined") + + # set effective batch size and effective batch multiplier according to do_sample + if do_sample: + effective_batch_size = batch_size * num_return_sequences + effective_batch_mult = num_return_sequences + else: + effective_batch_size = batch_size + effective_batch_mult = 1 + + if self.config.is_encoder_decoder: + if decoder_start_token_id is None: + # see if BOS token can be used for decoder_start_token_id + if bos_token_id is not None: + decoder_start_token_id = bos_token_id + elif ( + hasattr(self.config, "decoder") + and hasattr(self.config.decoder, "bos_token_id") + and self.config.decoder.bos_token_id is not None + ): + decoder_start_token_id = self.config.decoder.bos_token_id + else: + raise ValueError( + "decoder_start_token_id or bos_token_id has to be defined for encoder-decoder generation" + ) + + assert hasattr(self, "get_encoder"), "{} should have a 'get_encoder' function defined".format(self) + assert callable(self.get_encoder), "{} should be a method".format(self.get_encoder) + + # get encoder and store encoder outputs + encoder = self.get_encoder() + encoder_outputs: ModelOutput = encoder(input_ids, attention_mask=attention_mask, return_dict=True) + + # Expand input ids if num_beams > 1 or num_return_sequences > 1 + if num_return_sequences > 1 or num_beams > 1: + # TODO: make this a call-back function. + # input_ids=caps, + # input_video_embeds=vfeats, + # attention_mask=attention_mask, + # token_type_ids=token_type_ids, + input_video_embeds = model_kwargs.pop("input_video_embeds", None) + token_type_ids = model_kwargs.pop("token_type_ids", None) + + input_ids_len = input_ids.shape[-1] + input_ids = input_ids.unsqueeze(1).expand( + batch_size, effective_batch_mult * num_beams, input_ids_len) + + input_video_embeds_len, input_video_embeds_hidden = input_video_embeds.size(1), input_video_embeds.size(2) + input_video_embeds = input_video_embeds.unsqueeze(1).expand( + batch_size, effective_batch_mult * num_beams, input_video_embeds_len, input_video_embeds_hidden) + + attention_mask_from_len, attention_mask_to_len = attention_mask.size(1), attention_mask.size(2) + attention_mask = attention_mask.unsqueeze(1).expand( + batch_size, effective_batch_mult * num_beams, attention_mask_from_len, attention_mask_to_len + ) + + token_type_ids_len = token_type_ids.size(1) + token_type_ids = token_type_ids.unsqueeze(1).expand( + batch_size, effective_batch_mult * num_beams, token_type_ids_len + ) + + # contiguous ... + input_ids = input_ids.contiguous().view( + effective_batch_size * num_beams, input_ids_len + ) # shape: (batch_size * num_return_sequences * num_beams, cur_len) + + input_video_embeds = input_video_embeds.contiguous().view( + effective_batch_size * num_beams, input_video_embeds_len, input_video_embeds_hidden) + + attention_mask = attention_mask.contiguous().view( + effective_batch_size * num_beams, attention_mask_from_len, attention_mask_to_len + ) # shape: (batch_size * num_return_sequences * num_beams, cur_len) + + token_type_ids = token_type_ids.contiguous().view( + effective_batch_size * num_beams, token_type_ids_len + ) + + model_kwargs["input_video_embeds"] = input_video_embeds + model_kwargs["token_type_ids"] = token_type_ids + + if self.config.is_encoder_decoder: + device = next(self.parameters()).device + if decoder_input_ids is not None: + # give initial decoder input ids + input_ids = decoder_input_ids.repeat(effective_batch_size * num_beams, 1).to(device) + else: + # create empty decoder input_ids + input_ids = torch.full( + (effective_batch_size * num_beams, 1), + decoder_start_token_id, + dtype=torch.long, + device=device, + ) + cur_len = input_ids.shape[-1] + + assert ( + batch_size == encoder_outputs.last_hidden_state.shape[0] + ), f"expected encoder_outputs.last_hidden_state to have 1st dimension bs={batch_size}, got {encoder_outputs.last_hidden_state.shape[0]} " + + # expand batch_idx to assign correct encoder output for expanded input_ids (due to num_beams > 1 and num_return_sequences > 1) + expanded_batch_idxs = ( + torch.arange(batch_size) + .view(-1, 1) + .repeat(1, num_beams * effective_batch_mult) + .view(-1) + .to(input_ids.device) + ) + + # expand encoder_outputs + encoder_outputs["last_hidden_state"] = encoder_outputs.last_hidden_state.index_select( + 0, expanded_batch_idxs + ) + + # save encoder_outputs in `model_kwargs` + model_kwargs["encoder_outputs"] = encoder_outputs + + else: + cur_len = input_ids.shape[-1] + + assert ( + cur_len < max_length + ), f"The context has {cur_len} number of tokens, but `max_length` is only {max_length}. Please make sure that `max_length` is bigger than the number of tokens, by setting either `generate(max_length=...,...)` or `config.max_length = ...`" + + if num_beams > 1: + output = self._generate_beam_search( + input_ids, + cur_len=cur_len, + max_length=max_length, + min_length=min_length, + do_sample=do_sample, + early_stopping=early_stopping, + temperature=temperature, + top_k=top_k, + top_p=top_p, + repetition_penalty=repetition_penalty, + no_repeat_ngram_size=no_repeat_ngram_size, + bad_words_ids=bad_words_ids, + pad_token_id=pad_token_id, + eos_token_id=eos_token_id, + batch_size=effective_batch_size, + num_return_sequences=num_return_sequences, + length_penalty=length_penalty, + num_beams=num_beams, + vocab_size=vocab_size, + attention_mask=attention_mask, + use_cache=use_cache, + model_kwargs=model_kwargs, + ) + else: + output = self._generate_no_beam_search( + input_ids, + cur_len=cur_len, + max_length=max_length, + min_length=min_length, + do_sample=do_sample, + temperature=temperature, + top_k=top_k, + top_p=top_p, + repetition_penalty=repetition_penalty, + no_repeat_ngram_size=no_repeat_ngram_size, + bad_words_ids=bad_words_ids, + pad_token_id=pad_token_id, + eos_token_id=eos_token_id, + batch_size=effective_batch_size, + attention_mask=attention_mask, + use_cache=use_cache, + model_kwargs=model_kwargs, + ) + + return output + + def _generate_beam_search( + self, + input_ids, + cur_len, + max_length, + min_length, + do_sample, + early_stopping, + temperature, + top_k, + top_p, + repetition_penalty, + no_repeat_ngram_size, + bad_words_ids, + pad_token_id, + eos_token_id, + batch_size, + num_return_sequences, + length_penalty, + num_beams, + vocab_size, + attention_mask, + use_cache, + model_kwargs, + ): + """Generate sequences for each example with beam search.""" + + # generated hypotheses + generated_hyps = [ + BeamHypotheses(num_beams, max_length, length_penalty, early_stopping=early_stopping) + for _ in range(batch_size) + ] + + # scores for each sentence in the beam + beam_scores = torch.zeros((batch_size, num_beams), dtype=torch.float, device=input_ids.device) + + # for greedy decoding it is made sure that only tokens of the first beam are considered to avoid sampling the exact same tokens three times + if do_sample is False: + beam_scores[:, 1:] = -1e9 + beam_scores = beam_scores.view(-1) # shape (batch_size * num_beams,) + + # cache compute states + past = None + + # done sentences + done = [False for _ in range(batch_size)] + + while cur_len < max_length: + model_inputs = self.prepare_inputs_for_generation( + input_ids, past=past, attention_mask=attention_mask, use_cache=use_cache, **model_kwargs + ) + outputs = self(**model_inputs, return_dict=True) # (batch_size * num_beams, cur_len, vocab_size) + next_token_logits = outputs.logits[:, -1, :] # (batch_size * num_beams, vocab_size) + + # if model has past, then set the past variable to speed up decoding + if "past_key_values" in outputs: + past = outputs.past_key_values + elif "mems" in outputs: + past = outputs.mems + + if self.config.is_encoder_decoder and do_sample is False: + # TODO (PVP) still a bit hacky here - there might be a better solution + next_token_logits = self.adjust_logits_during_generation( + next_token_logits, cur_len=cur_len, max_length=max_length + ) + + scores = F.log_softmax(next_token_logits, dim=-1) # (batch_size * num_beams, vocab_size) + + scores = self.postprocess_next_token_scores( + scores=scores, + input_ids=input_ids, + no_repeat_ngram_size=no_repeat_ngram_size, + bad_words_ids=bad_words_ids, + cur_len=cur_len, + min_length=min_length, + max_length=max_length, + eos_token_id=eos_token_id, + repetition_penalty=repetition_penalty, + batch_size=batch_size, + num_beams=num_beams, + ) + + assert scores.shape == (batch_size * num_beams, vocab_size), "Shapes of scores: {} != {}".format( + scores.shape, (batch_size * num_beams, vocab_size) + ) + + if do_sample: + _scores = scores + beam_scores[:, None].expand_as(scores) # (batch_size * num_beams, vocab_size) + # Temperature + if temperature != 1.0: + _scores = _scores / temperature + # Top-p/top-k filtering + _scores = top_k_top_p_filtering( + _scores, top_k=top_k, top_p=top_p, min_tokens_to_keep=2 + ) # (batch_size * num_beams, vocab_size) + # re-organize to group the beam together to sample from all beam_idxs + _scores = _scores.contiguous().view( + batch_size, num_beams * vocab_size + ) # (batch_size, num_beams * vocab_size) + + # Sample 2 next tokens for each beam (so we have some spare tokens and match output of greedy beam search) + probs = F.softmax(_scores, dim=-1) + next_tokens = torch.multinomial(probs, num_samples=2 * num_beams) # (batch_size, num_beams * 2) + # Compute next scores + next_scores = torch.gather(_scores, -1, next_tokens) # (batch_size, num_beams * 2) + # sort the sampled vector to make sure that the first num_beams samples are the best + next_scores, next_scores_indices = torch.sort(next_scores, descending=True, dim=1) + next_tokens = torch.gather(next_tokens, -1, next_scores_indices) # (batch_size, num_beams * 2) + + else: + next_scores = scores + beam_scores[:, None].expand_as(scores) # (batch_size * num_beams, vocab_size) + + # re-organize to group the beam together (we are keeping top hypothesis accross beams) + next_scores = next_scores.view( + batch_size, num_beams * vocab_size + ) # (batch_size, num_beams * vocab_size) + + next_scores, next_tokens = torch.topk(next_scores, 2 * num_beams, dim=1, largest=True, sorted=True) + + assert next_scores.size() == next_tokens.size() == (batch_size, 2 * num_beams) + + # next batch beam content + next_batch_beam = [] + + # for each sentence + for batch_idx in range(batch_size): + + # if we are done with this sentence, add a pad token + if done[batch_idx]: + assert ( + len(generated_hyps[batch_idx]) >= num_beams + ), "Batch can only be done if at least {} beams have been generated".format(num_beams) + assert ( + eos_token_id is not None and pad_token_id is not None + ), "generated beams >= num_beams -> eos_token_id and pad_token have to be defined" + next_batch_beam.extend([(0, pad_token_id, 0)] * num_beams) # pad the batch + continue + + # next sentence beam content, this will get added to next_batch_beam + next_sent_beam = [] + + # next tokens for this sentence + for beam_token_rank, (beam_token_id, beam_token_score) in enumerate( + zip(next_tokens[batch_idx], next_scores[batch_idx]) + ): + # get beam and token IDs + beam_id = beam_token_id // vocab_size + token_id = beam_token_id % vocab_size + + effective_beam_id = batch_idx * num_beams + beam_id + # add to generated hypotheses if end of sentence + if (eos_token_id is not None) and (token_id.item() == eos_token_id): + # if beam_token does not belong to top num_beams tokens, it should not be added + is_beam_token_worse_than_top_num_beams = beam_token_rank >= num_beams + if is_beam_token_worse_than_top_num_beams: + continue + generated_hyps[batch_idx].add( + input_ids[effective_beam_id].clone(), + beam_token_score.item(), + ) + else: + # add next predicted token since it is not eos_token + next_sent_beam.append((beam_token_score, token_id, effective_beam_id)) + + # once the beam for next step is full, don't add more tokens to it. + if len(next_sent_beam) == num_beams: + break + + # Check if we are done so that we can save a pad step if all(done) + done[batch_idx] = done[batch_idx] or generated_hyps[batch_idx].is_done( + next_scores[batch_idx].max().item(), cur_len + ) + + # update next beam content + assert len(next_sent_beam) == num_beams, "Beam should always be full" + next_batch_beam.extend(next_sent_beam) + assert len(next_batch_beam) == num_beams * (batch_idx + 1), "We should have added num_beams each step" + + # stop when we are done with each sentence + if all(done): + break + + # sanity check / prepare next batch + assert len(next_batch_beam) == batch_size * num_beams + beam_scores = beam_scores.new([x[0] for x in next_batch_beam]) + beam_tokens = input_ids.new([x[1] for x in next_batch_beam]) + beam_idx = input_ids.new([x[2] for x in next_batch_beam]) + + # re-order batch and update current length + input_ids = input_ids[beam_idx, :] + input_ids = torch.cat([input_ids, beam_tokens.unsqueeze(1)], dim=-1) + cur_len = cur_len + 1 + + # re-order internal states + if past is not None: + past = self._reorder_cache(past, beam_idx) + + # extend attention_mask for new generated input if only decoder + # (huxu): move out since we trim attention_mask by ourselves. + # if self.config.is_encoder_decoder is False: + # attention_mask = torch.cat( + # [attention_mask, attention_mask.new_ones((attention_mask.shape[0], 1))], dim=-1 + # ) + + # finalize all open beam hypotheses and add to generated hypotheses + for batch_idx in range(batch_size): + if done[batch_idx]: + continue + + # test that beam scores match previously calculated scores if not eos and batch_idx not done + if eos_token_id is not None and all( + (token_id % vocab_size).item() != eos_token_id for token_id in next_tokens[batch_idx] + ): + assert torch.all( + next_scores[batch_idx, :num_beams] == beam_scores.view(batch_size, num_beams)[batch_idx] + ), "If batch_idx is not done, final next scores: {} have to equal to accumulated beam_scores: {}".format( + next_scores[:, :num_beams][batch_idx], + beam_scores.view(batch_size, num_beams)[batch_idx], + ) + + # need to add best num_beams hypotheses to generated hyps + for beam_id in range(num_beams): + effective_beam_id = batch_idx * num_beams + beam_id + final_score = beam_scores[effective_beam_id].item() + final_tokens = input_ids[effective_beam_id] + generated_hyps[batch_idx].add(final_tokens, final_score) + + # depending on whether greedy generation is wanted or not define different output_batch_size and output_num_return_sequences_per_batch + output_batch_size = batch_size if do_sample else batch_size * num_return_sequences + output_num_return_sequences_per_batch = 1 if do_sample else num_return_sequences + + # select the best hypotheses + sent_lengths = input_ids.new(output_batch_size) + best = [] + + # retrieve best hypotheses + for i, hypotheses in enumerate(generated_hyps): + sorted_hyps = sorted(hypotheses.beams, key=lambda x: x[0]) + for j in range(output_num_return_sequences_per_batch): + effective_batch_idx = output_num_return_sequences_per_batch * i + j + best_hyp = sorted_hyps.pop()[1] + sent_lengths[effective_batch_idx] = len(best_hyp) + best.append(best_hyp) + + # prepare for adding eos + sent_max_len = min(sent_lengths.max().item() + 1, max_length) + decoded = input_ids.new(output_batch_size, sent_max_len) + # shorter batches are padded if needed + if sent_lengths.min().item() != sent_lengths.max().item(): + assert pad_token_id is not None, "`pad_token_id` has to be defined" + decoded.fill_(pad_token_id) + + # fill with hypotheses and eos_token_id if the latter fits in + for i, hypo in enumerate(best): + decoded[i, : sent_lengths[i]] = hypo + if sent_lengths[i] < max_length: + decoded[i, sent_lengths[i]] = eos_token_id + + return decoded + + def _generate_no_beam_search( + self, + input_ids, + cur_len, + max_length, + min_length, + do_sample, + temperature, + top_k, + top_p, + repetition_penalty, + no_repeat_ngram_size, + bad_words_ids, + pad_token_id, + eos_token_id, + batch_size, + attention_mask, + use_cache, + model_kwargs, + ): + """Generate sequences for each example without beam search (num_beams == 1). + All returned sequence are generated independantly. + """ + # length of generated sentences / unfinished sentences + unfinished_sents = input_ids.new(batch_size).fill_(1) + sent_lengths = input_ids.new(batch_size).fill_(max_length) + + past = None + while cur_len < max_length: + model_inputs = self.prepare_inputs_for_generation( + input_ids, past=past, attention_mask=attention_mask, use_cache=use_cache, **model_kwargs + ) + + outputs = self(**model_inputs, return_dict=True) + next_token_logits = outputs.logits[:, -1, :] + scores = self.postprocess_next_token_scores( + scores=next_token_logits, + input_ids=input_ids, + no_repeat_ngram_size=no_repeat_ngram_size, + bad_words_ids=bad_words_ids, + cur_len=cur_len, + min_length=min_length, + max_length=max_length, + eos_token_id=eos_token_id, + repetition_penalty=repetition_penalty, + batch_size=batch_size, + num_beams=1, + ) + + # if model has past, then set the past variable to speed up decoding + if "past_key_values" in outputs: + past = outputs.past_key_values + elif "mems" in outputs: + past = outputs.mems + + if do_sample: + # Temperature (higher temperature => more likely to sample low probability tokens) + if temperature != 1.0: + scores = scores / temperature + # Top-p/top-k filtering + next_token_logscores = top_k_top_p_filtering(scores, top_k=top_k, top_p=top_p) + # Sample + probs = F.softmax(next_token_logscores, dim=-1) + next_token = torch.multinomial(probs, num_samples=1).squeeze(1) + else: + # Greedy decoding + next_token = torch.argmax(next_token_logits, dim=-1) + + # print(next_token_logits[0,next_token[0]], next_token_logits[0,eos_token_id]) + + # update generations and finished sentences + if eos_token_id is not None: + # pad finished sentences if eos_token_id exist + tokens_to_add = next_token * unfinished_sents + (pad_token_id) * (1 - unfinished_sents) + else: + tokens_to_add = next_token + + # add token and increase length by one + input_ids = torch.cat([input_ids, tokens_to_add.unsqueeze(-1)], dim=-1) + cur_len = cur_len + 1 + + if eos_token_id is not None: + eos_in_sents = tokens_to_add == eos_token_id + # if sentence is unfinished and the token to add is eos, sent_lengths is filled with current length + is_sents_unfinished_and_token_to_add_is_eos = unfinished_sents.mul(eos_in_sents.long()).bool() + sent_lengths.masked_fill_(is_sents_unfinished_and_token_to_add_is_eos, cur_len) + # unfinished_sents is set to zero if eos in sentence + unfinished_sents.mul_((~eos_in_sents).long()) + + # stop when there is a </s> in each sentence, or if we exceed the maximul length + if unfinished_sents.max() == 0: + break + + + # extend attention_mask for new generated input if only decoder + # if self.config.is_encoder_decoder is False: + # attention_mask = torch.cat( + # [attention_mask, attention_mask.new_ones((attention_mask.shape[0], 1))], dim=-1 + # ) + + return input_ids diff --git a/examples/MMPT/mmpt/models/transformermodel.py b/examples/MMPT/mmpt/models/transformermodel.py new file mode 100644 index 0000000000..6acc419f09 --- /dev/null +++ b/examples/MMPT/mmpt/models/transformermodel.py @@ -0,0 +1,734 @@ +# coding=utf-8 +# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team. +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Copyright (c) Facebook, Inc. All Rights Reserved + +import torch + +from torch import nn + +try: + from transformers.modeling_bert import ( + BertPreTrainedModel, + BertModel, + BertEncoder, + BertPredictionHeadTransform, + ) +except ImportError: + pass + +from ..modules import VideoTokenMLP, MMBertEmbeddings + + +# --------------- fine-tuning models --------------- +class MMBertForJoint(BertPreTrainedModel): + """A BertModel with isolated attention mask to separate modality.""" + + def __init__(self, config): + super().__init__(config) + self.videomlp = VideoTokenMLP(config) + self.bert = MMBertModel(config) + self.init_weights() + + def forward( + self, + input_ids=None, + input_video_embeds=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + next_sentence_label=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + separate_forward_split=None, + ): + return_dict = ( + return_dict if return_dict is not None + else self.config.use_return_dict + ) + video_tokens = self.videomlp(input_video_embeds) + + outputs = self.bert( + input_ids, + video_tokens, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + position_ids=position_ids, + head_mask=head_mask, + inputs_embeds=inputs_embeds, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + separate_forward_split=separate_forward_split, + ) + + return outputs + + +class MMBertForTokenClassification(BertPreTrainedModel): + """A BertModel similar to MMJointUni, with extra wrapper layer + to be fine-tuned from other pretrained MMFusion model.""" + + def __init__(self, config): + super().__init__(config) + self.videomlp = VideoTokenMLP(config) + self.bert = MMBertModel(config) + self.dropout = nn.Dropout(config.hidden_dropout_prob) + # TODO(huxu): 779 is the number of classes for COIN: move to config? + self.classifier = nn.Linear(config.hidden_size, 779) + self.init_weights() + + def forward( + self, + input_ids=None, + input_video_embeds=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + next_sentence_label=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + separate_forward_split=None, + ): + return_dict = ( + return_dict if return_dict is not None + else self.config.use_return_dict + ) + + video_tokens = self.videomlp(input_video_embeds) + outputs = self.bert( + input_ids, + video_tokens, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + position_ids=position_ids, + head_mask=head_mask, + inputs_embeds=inputs_embeds, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + separate_forward_split=separate_forward_split, + ) + + return (self.classifier(outputs[0]),) + + +# ------------ pre-training models ---------------- + +class MMBertForEncoder(BertPreTrainedModel): + """A BertModel for Contrastive Learning.""" + def __init__(self, config): + super().__init__(config) + self.videomlp = VideoTokenMLP(config) + self.bert = MMBertModel(config) + self.init_weights() + + def forward( + self, + input_ids=None, + input_video_embeds=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + ): + return_dict = ( + return_dict if return_dict is not None + else self.config.use_return_dict + ) + if input_video_embeds is not None: + video_tokens = self.videomlp(input_video_embeds) + else: + video_tokens = None + + outputs = self.bert( + input_ids, + video_tokens, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + position_ids=position_ids, + head_mask=head_mask, + inputs_embeds=inputs_embeds, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + return outputs + + +class MMBertForMFMMLM(BertPreTrainedModel): + """A BertModel with shared prediction head on MFM-MLM.""" + def __init__(self, config): + super().__init__(config) + self.videomlp = VideoTokenMLP(config) + self.bert = MMBertModel(config) + self.cls = MFMMLMHead(config) + self.hidden_size = config.hidden_size + self.init_weights() + + def get_output_embeddings(self): + return self.cls.predictions.decoder + + def forward( + self, + input_ids=None, + input_video_embeds=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + masked_frame_labels=None, + target_video_hidden_states=None, + non_masked_frame_mask=None, + masked_lm_labels=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + ): + return_dict = ( + return_dict if return_dict is not None + else self.config.use_return_dict + ) + if input_video_embeds is not None: + video_tokens = self.videomlp(input_video_embeds) + else: + video_tokens = None + + if target_video_hidden_states is not None: + target_video_hidden_states = self.videomlp( + target_video_hidden_states) + + non_masked_frame_hidden_states = video_tokens.masked_select( + non_masked_frame_mask.unsqueeze(-1) + ).view(-1, self.hidden_size) + + outputs = self.bert( + input_ids, + video_tokens, + attention_mask=attention_mask, + token_type_ids=token_type_ids, + position_ids=position_ids, + head_mask=head_mask, + inputs_embeds=inputs_embeds, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + sequence_output = outputs[0] + + mfm_scores, prediction_scores = None, None + if masked_frame_labels is not None and masked_lm_labels is not None: + # split the sequence. + text_offset = masked_frame_labels.size(1) + 1 # [CLS] + video_sequence_output = sequence_output[ + :, 1:text_offset + ] # remove [SEP] as not in video_label. + text_sequence_output = torch.cat( + [sequence_output[:, :1], sequence_output[:, text_offset:]], + dim=1 + ) + + hidden_size = video_sequence_output.size(-1) + selected_video_output = video_sequence_output.masked_select( + masked_frame_labels.unsqueeze(-1) + ).view(-1, hidden_size) + + # only compute select tokens to training to speed up. + hidden_size = text_sequence_output.size(-1) + # masked_lm_labels = masked_lm_labels.reshape(-1) + labels_mask = masked_lm_labels != -100 + + selected_text_output = text_sequence_output.masked_select( + labels_mask.unsqueeze(-1) + ).view(-1, hidden_size) + mfm_scores, prediction_scores = self.cls( + selected_video_output, + target_video_hidden_states, + non_masked_frame_hidden_states, + selected_text_output, + ) + + output = ( + mfm_scores, + prediction_scores, + ) + outputs + return output + + +class BertMFMMLMPredictionHead(nn.Module): + def __init__(self, config): + super().__init__() + self.transform = BertPredictionHeadTransform(config) + # The output weights are the same as the input embeddings, but there is + # an output-only bias for each token. + self.decoder = nn.Linear( + config.hidden_size, config.vocab_size, bias=False) + + self.bias = nn.Parameter(torch.zeros(config.vocab_size)) + + # Need a link between the two variables so that the bias is correctly + # resized with `resize_token_embeddings` + self.decoder.bias = self.bias + + def forward( + self, + video_hidden_states=None, + target_video_hidden_states=None, + non_masked_frame_hidden_states=None, + text_hidden_states=None, + ): + video_logits, text_logits = None, None + if video_hidden_states is not None: + video_hidden_states = self.transform(video_hidden_states) + non_masked_frame_logits = torch.mm( + video_hidden_states, + non_masked_frame_hidden_states.transpose(1, 0) + ) + masked_frame_logits = torch.bmm( + video_hidden_states.unsqueeze(1), + target_video_hidden_states.unsqueeze(-1), + ).squeeze(-1) + video_logits = torch.cat( + [masked_frame_logits, non_masked_frame_logits], dim=1 + ) + + if text_hidden_states is not None: + text_hidden_states = self.transform(text_hidden_states) + text_logits = self.decoder(text_hidden_states) + return video_logits, text_logits + + +class MFMMLMHead(nn.Module): + def __init__(self, config): + super().__init__() + self.predictions = BertMFMMLMPredictionHead(config) + + def forward( + self, + video_hidden_states=None, + target_video_hidden_states=None, + non_masked_frame_hidden_states=None, + text_hidden_states=None, + ): + video_logits, text_logits = self.predictions( + video_hidden_states, + target_video_hidden_states, + non_masked_frame_hidden_states, + text_hidden_states, + ) + return video_logits, text_logits + + +class MMBertForMTM(MMBertForMFMMLM): + def __init__(self, config): + BertPreTrainedModel.__init__(self, config) + self.videomlp = VideoTokenMLP(config) + self.bert = MMBertModel(config) + self.cls = MTMHead(config) + self.hidden_size = config.hidden_size + self.init_weights() + + +class BertMTMPredictionHead(nn.Module): + def __init__(self, config): + super().__init__() + self.transform = BertPredictionHeadTransform(config) + self.decoder = nn.Linear( + config.hidden_size, config.vocab_size, bias=False) + + def forward( + self, + video_hidden_states=None, + target_video_hidden_states=None, + non_masked_frame_hidden_states=None, + text_hidden_states=None, + ): + non_masked_frame_hidden_states = non_masked_frame_hidden_states.transpose(1, 0) + video_logits, text_logits = None, None + if video_hidden_states is not None: + video_hidden_states = self.transform(video_hidden_states) + + masked_frame_logits = torch.bmm( + video_hidden_states.unsqueeze(1), + target_video_hidden_states.unsqueeze(-1), + ).squeeze(-1) + + non_masked_frame_logits = torch.mm( + video_hidden_states, + non_masked_frame_hidden_states + ) + video_on_vocab_logits = self.decoder(video_hidden_states) + video_logits = torch.cat([ + masked_frame_logits, + non_masked_frame_logits, + video_on_vocab_logits], dim=1) + + if text_hidden_states is not None: + text_hidden_states = self.transform(text_hidden_states) + # text first so label does not need to be shifted. + text_on_vocab_logits = self.decoder(text_hidden_states) + text_on_video_logits = torch.mm( + text_hidden_states, + non_masked_frame_hidden_states + ) + text_logits = torch.cat([ + text_on_vocab_logits, + text_on_video_logits + ], dim=1) + + return video_logits, text_logits + + +class MTMHead(nn.Module): + def __init__(self, config): + super().__init__() + self.predictions = BertMTMPredictionHead(config) + + def forward( + self, + video_hidden_states=None, + target_video_hidden_states=None, + non_masked_frame_hidden_states=None, + text_hidden_states=None, + ): + video_logits, text_logits = self.predictions( + video_hidden_states, + target_video_hidden_states, + non_masked_frame_hidden_states, + text_hidden_states, + ) + return video_logits, text_logits + + +class MMBertModel(BertModel): + """MMBertModel has MMBertEmbedding to support video tokens.""" + + def __init__(self, config, add_pooling_layer=True): + super().__init__(config) + # overwrite embedding + self.embeddings = MMBertEmbeddings(config) + self.encoder = MultiLayerAttentionMaskBertEncoder(config) + self.init_weights() + + def forward( + self, + input_ids=None, + input_video_embeds=None, + attention_mask=None, + token_type_ids=None, + position_ids=None, + head_mask=None, + inputs_embeds=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + output_attentions=None, + output_hidden_states=None, + return_dict=None, + separate_forward_split=None, + ): + output_attentions = ( + output_attentions + if output_attentions is not None + else self.config.output_attentions + ) + output_hidden_states = ( + output_hidden_states + if output_hidden_states is not None + else self.config.output_hidden_states + ) + return_dict = ( + return_dict if return_dict is not None + else self.config.use_return_dict + ) + + if input_ids is not None and inputs_embeds is not None: + raise ValueError( + "You cannot specify both input_ids " + "and inputs_embeds at the same time" + ) + elif input_ids is not None: + if input_video_embeds is not None: + input_shape = ( + input_ids.size(0), + input_ids.size(1) + input_video_embeds.size(1), + ) + else: + input_shape = ( + input_ids.size(0), + input_ids.size(1), + ) + elif inputs_embeds is not None: + if input_video_embeds is not None: + input_shape = ( + inputs_embeds.size(0), + inputs_embeds.size(1) + input_video_embeds.size(1), + ) + else: + input_shape = ( + input_ids.size(0), + input_ids.size(1), + ) + else: + raise ValueError( + "You have to specify either input_ids or inputs_embeds") + + device = input_ids.device if input_ids is not None \ + else inputs_embeds.device + + if attention_mask is None: + attention_mask = torch.ones(input_shape, device=device) + if token_type_ids is None: + token_type_ids = torch.zeros( + input_shape, dtype=torch.long, device=device) + + # We can provide a self-attention mask of dimensions + # [batch_size, from_seq_length, to_seq_length] + # ourselves in which case + # we just need to make it broadcastable to all heads. + extended_attention_mask: torch.Tensor = \ + self.get_extended_attention_mask( + attention_mask, input_shape, device) + + # If a 2D or 3D attention mask is provided for the cross-attention + # we need to make broadcastable to + # [batch_size, num_heads, seq_length, seq_length] + if self.config.is_decoder and encoder_hidden_states is not None: + ( + encoder_batch_size, + encoder_sequence_length, + _, + ) = encoder_hidden_states.size() + encoder_hidden_shape = ( + encoder_batch_size, encoder_sequence_length) + if encoder_attention_mask is None: + encoder_attention_mask = torch.ones( + encoder_hidden_shape, device=device) + encoder_extended_attention_mask = self.invert_attention_mask( + encoder_attention_mask + ) + else: + encoder_extended_attention_mask = None + + # Prepare head mask if needed + # 1.0 in head_mask indicate we keep the head + # attention_probs has shape bsz x n_heads x N x N + # input head_mask has shape [num_heads] or + # [num_hidden_layers x num_heads] + # and head_mask is converted to shape + # [num_hidden_layers x batch x num_heads x seq_length x seq_length] + + head_mask = self.get_head_mask( + head_mask, self.config.num_hidden_layers) + + embedding_output = self.embeddings( + input_ids, + input_video_embeds, + position_ids=position_ids, + token_type_ids=token_type_ids, + inputs_embeds=inputs_embeds, + ) + + if separate_forward_split is not None: + split_embedding_output = \ + embedding_output[:, :separate_forward_split] + split_extended_attention_mask = extended_attention_mask[ + :, :, :, :separate_forward_split, :separate_forward_split + ] + split_encoder_outputs = self.encoder( + split_embedding_output, + attention_mask=split_extended_attention_mask, + head_mask=head_mask, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_extended_attention_mask, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + assert ( + len(split_encoder_outputs) <= 2 + ), "we do not support merge on attention for now." + encoder_outputs = [] + encoder_outputs.append([split_encoder_outputs[0]]) + if len(split_encoder_outputs) == 2: + encoder_outputs.append([]) + for _all_hidden_states in split_encoder_outputs[1]: + encoder_outputs[-1].append([_all_hidden_states]) + + split_embedding_output = \ + embedding_output[:, separate_forward_split:] + split_extended_attention_mask = extended_attention_mask[ + :, :, :, separate_forward_split:, separate_forward_split: + ] + + split_encoder_outputs = self.encoder( + split_embedding_output, + attention_mask=split_extended_attention_mask, + head_mask=head_mask, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_extended_attention_mask, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + assert ( + len(split_encoder_outputs) <= 2 + ), "we do not support merge on attention for now." + encoder_outputs[0].append(split_encoder_outputs[0]) + encoder_outputs[0] = torch.cat(encoder_outputs[0], dim=1) + if len(split_encoder_outputs) == 2: + for layer_idx, _all_hidden_states in enumerate( + split_encoder_outputs[1] + ): + encoder_outputs[1][layer_idx].append(_all_hidden_states) + encoder_outputs[1][layer_idx] = torch.cat( + encoder_outputs[1][layer_idx], dim=1 + ) + encoder_outputs = tuple(encoder_outputs) + else: + encoder_outputs = self.encoder( + embedding_output, + attention_mask=extended_attention_mask, + head_mask=head_mask, + encoder_hidden_states=encoder_hidden_states, + encoder_attention_mask=encoder_extended_attention_mask, + output_attentions=output_attentions, + output_hidden_states=output_hidden_states, + return_dict=return_dict, + ) + + sequence_output = encoder_outputs[0] + pooled_output = ( + self.pooler(sequence_output) if self.pooler is not None else None + ) + + return (sequence_output, pooled_output) + encoder_outputs[1:] + + def get_extended_attention_mask(self, attention_mask, input_shape, device): + """This is borrowed from `modeling_utils.py` with the support of + multi-layer attention masks. + The second dim is expected to be number of layers. + See `MMAttentionMaskProcessor`. + Makes broadcastable attention and causal masks so that future + and masked tokens are ignored. + + Arguments: + attention_mask (:obj:`torch.Tensor`): + Mask with ones indicating tokens to attend to, + zeros for tokens to ignore. + input_shape (:obj:`Tuple[int]`): + The shape of the input to the model. + device: (:obj:`torch.device`): + The device of the input to the model. + + Returns: + :obj:`torch.Tensor` The extended attention mask, \ + with a the same dtype as :obj:`attention_mask.dtype`. + """ + # We can provide a self-attention mask of dimensions + # [batch_size, from_seq_length, to_seq_length] + # ourselves in which case we just need to make it broadcastable + # to all heads. + if attention_mask.dim() == 4: + extended_attention_mask = attention_mask[:, :, None, :, :] + extended_attention_mask = extended_attention_mask.to( + dtype=self.dtype + ) # fp16 compatibility + extended_attention_mask = (1.0 - extended_attention_mask) \ + * -10000.0 + return extended_attention_mask + else: + return super().get_extended_attention_mask( + attention_mask, input_shape, device + ) + + +class MultiLayerAttentionMaskBertEncoder(BertEncoder): + """extend BertEncoder with the capability of + multiple layers of attention mask.""" + + def forward( + self, + hidden_states, + attention_mask=None, + head_mask=None, + encoder_hidden_states=None, + encoder_attention_mask=None, + output_attentions=False, + output_hidden_states=False, + return_dict=False, + ): + all_hidden_states = () if output_hidden_states else None + all_attentions = () if output_attentions else None + for i, layer_module in enumerate(self.layer): + if output_hidden_states: + all_hidden_states = all_hidden_states + (hidden_states,) + layer_head_mask = head_mask[i] if head_mask is not None else None + + layer_attention_mask = ( + attention_mask[:, i, :, :, :] + if attention_mask.dim() == 5 + else attention_mask + ) + + if getattr(self.config, "gradient_checkpointing", False): + + def create_custom_forward(module): + def custom_forward(*inputs): + return module(*inputs, output_attentions) + + return custom_forward + + layer_outputs = torch.utils.checkpoint.checkpoint( + create_custom_forward(layer_module), + hidden_states, + layer_attention_mask, + layer_head_mask, + encoder_hidden_states, + encoder_attention_mask, + ) + else: + layer_outputs = layer_module( + hidden_states, + layer_attention_mask, + layer_head_mask, + encoder_hidden_states, + encoder_attention_mask, + output_attentions, + ) + hidden_states = layer_outputs[0] + if output_attentions: + all_attentions = all_attentions + (layer_outputs[1],) + + if output_hidden_states: + all_hidden_states = all_hidden_states + (hidden_states,) + + return tuple( + v + for v in [hidden_states, all_hidden_states, all_attentions] + if v is not None + ) diff --git a/examples/MMPT/mmpt/modules/__init__.py b/examples/MMPT/mmpt/modules/__init__.py new file mode 100644 index 0000000000..4c78594c21 --- /dev/null +++ b/examples/MMPT/mmpt/modules/__init__.py @@ -0,0 +1,10 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +from .mm import * + +try: + from .expmm import * +except ImportError: + pass diff --git a/examples/MMPT/mmpt/modules/mm.py b/examples/MMPT/mmpt/modules/mm.py new file mode 100644 index 0000000000..5d9777371a --- /dev/null +++ b/examples/MMPT/mmpt/modules/mm.py @@ -0,0 +1,145 @@ +# coding=utf-8 +# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team. +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Copyright (c) Facebook, Inc. All Rights Reserved + + +import torch + +from torch import nn + +try: + from transformers.modeling_bert import ( + BertEmbeddings, + ACT2FN, + ) +except ImportError: + pass + + +class VideoTokenMLP(nn.Module): + def __init__(self, config): + super().__init__() + input_dim = config.input_dim if hasattr(config, "input_dim") else 512 + self.linear1 = nn.Linear(input_dim, config.hidden_size) + self.LayerNorm = nn.LayerNorm(config.hidden_size) + self.activation = ACT2FN[config.hidden_act] + self.linear2 = nn.Linear(config.hidden_size, config.hidden_size) + + def forward(self, hidden_states): + hidden_states = self.linear1(hidden_states) + hidden_states = self.activation(hidden_states) + hidden_states = self.LayerNorm(hidden_states) + hidden_states = self.linear2(hidden_states) + return hidden_states + + +class MMBertEmbeddings(BertEmbeddings): + def __init__(self, config): + super().__init__(config) + self.max_video_len = config.max_video_len + if hasattr(config, "use_seg_emb") and config.use_seg_emb: + """the original VLM paper uses seg_embeddings for temporal space. + although not used it changed the randomness of initialization. + we keep it for reproducibility. + """ + self.seg_embeddings = nn.Embedding(256, config.hidden_size) + + def forward( + self, + input_ids, + input_video_embeds, + token_type_ids=None, + position_ids=None, + inputs_embeds=None, + ): + input_tensor = input_ids if input_ids is not None else inputs_embeds + if input_video_embeds is not None: + input_shape = ( + input_tensor.size(0), + input_tensor.size(1) + input_video_embeds.size(1), + ) + else: + input_shape = (input_tensor.size(0), input_tensor.size(1)) + + if position_ids is None: + """ + Auto skip position embeddings for text only case. + use cases: + (1) action localization and segmentation: + feed in len-1 dummy video token needs text part to + skip input_video_embeds.size(1) for the right + position_ids for video [SEP] and rest text tokens. + (2) MMFusionShare for two forward passings: + in `forward_text`: input_video_embeds is None. + need to skip video [SEP] token. + + # video_len + 1: [CLS] + video_embed + # self.max_video_len + 1: [SEP] for video. + # self.max_video_len + 2: [SEP] for video. + # self.max_video_len + input_ids.size(1): rest for text. + """ + if input_video_embeds is not None: + video_len = input_video_embeds.size(1) + starting_offset = self.max_video_len + 1 # video [SEP] + ending_offset = self.max_video_len + input_ids.size(1) + else: + video_len = 0 + starting_offset = self.max_video_len + 2 # first text token. + ending_offset = self.max_video_len + input_ids.size(1) + 1 + position_ids = torch.cat([ + self.position_ids[:, :video_len + 1], + self.position_ids[:, starting_offset:ending_offset] + ], dim=1) + + if token_type_ids is None: + token_type_ids = torch.zeros( + input_shape, dtype=torch.long, device=self.position_ids.device + ) + + """ + the format of input_ids is [CLS] [SEP] caption [SEP] padding. + the goal is to build [CLS] video tokens [SEP] caption [SEP] . + """ + if inputs_embeds is None: + inputs_embeds = self.word_embeddings(input_ids) + if input_video_embeds is not None: + inputs_mm_embeds = torch.cat([ + inputs_embeds[:, :1], input_video_embeds, inputs_embeds[:, 1:] + ], dim=1) + else: + # text only for `MMFusionShare`. + inputs_mm_embeds = inputs_embeds + + position_embeddings = self.position_embeddings(position_ids) + token_type_embeddings = self.token_type_embeddings(token_type_ids) + embeddings = inputs_mm_embeds + position_embeddings + embeddings += token_type_embeddings + + embeddings = self.LayerNorm(embeddings) + embeddings = self.dropout(embeddings) + return embeddings + + +class AlignHead(nn.Module): + """this will load pre-trained weights for NSP, which is desirable.""" + + def __init__(self, config): + super().__init__() + self.seq_relationship = nn.Linear(config.hidden_size, 2) + + def forward(self, dropout_pooled_output): + logits = self.seq_relationship(dropout_pooled_output) + return logits diff --git a/examples/MMPT/mmpt/modules/retri.py b/examples/MMPT/mmpt/modules/retri.py new file mode 100644 index 0000000000..d1b288f8e5 --- /dev/null +++ b/examples/MMPT/mmpt/modules/retri.py @@ -0,0 +1,429 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import numpy as np +import pickle +import time + +try: + import faiss +except ImportError: + pass + +from collections import defaultdict + +from ..utils import get_local_rank, print_on_rank0 + + +class VectorRetriever(object): + """ + How2 Video Retriver. + Reference usage of FAISS: + https://github.com/fairinternal/fairseq-py/blob/paraphrase_pretraining/fairseq/data/multilingual_faiss_dataset.py + """ + + def __init__(self, hidden_size, cent, db_type, examples_per_cent_to_train): + if db_type == "flatl2": + quantizer = faiss.IndexFlatL2(hidden_size) # the other index + self.db = faiss.IndexIVFFlat( + quantizer, hidden_size, cent, faiss.METRIC_L2) + elif db_type == "pq": + self.db = faiss.index_factory( + hidden_size, f"IVF{cent}_HNSW32,PQ32" + ) + else: + raise ValueError("unknown type of db", db_type) + self.train_thres = cent * examples_per_cent_to_train + self.train_cache = [] + self.train_len = 0 + self.videoid_to_vectoridx = {} + self.vectoridx_to_videoid = None + self.make_direct_maps_done = False + + def make_direct_maps(self): + faiss.downcast_index(self.db).make_direct_map() + + def __len__(self): + return self.db.ntotal + + def save(self, out_dir): + faiss.write_index( + self.db, + os.path.join(out_dir, "faiss_idx") + ) + with open( + os.path.join( + out_dir, "videoid_to_vectoridx.pkl"), + "wb") as fw: + pickle.dump( + self.videoid_to_vectoridx, fw, + protocol=pickle.HIGHEST_PROTOCOL + ) + + def load(self, out_dir): + fn = os.path.join(out_dir, "faiss_idx") + self.db = faiss.read_index(fn) + with open( + os.path.join(out_dir, "videoid_to_vectoridx.pkl"), "rb") as fr: + self.videoid_to_vectoridx = pickle.load(fr) + + def add(self, hidden_states, video_ids, last=False): + assert len(hidden_states) == len(video_ids), "{}, {}".format( + str(len(hidden_states)), str(len(video_ids))) + assert len(hidden_states.shape) == 2 + assert hidden_states.dtype == np.float32 + + valid_idx = [] + for idx, video_id in enumerate(video_ids): + if video_id not in self.videoid_to_vectoridx: + valid_idx.append(idx) + self.videoid_to_vectoridx[video_id] = \ + len(self.videoid_to_vectoridx) + + hidden_states = hidden_states[valid_idx] + if not self.db.is_trained: + self.train_cache.append(hidden_states) + self.train_len += hidden_states.shape[0] + if self.train_len < self.train_thres: + return + self.finalize_training() + else: + self.db.add(hidden_states) + + def finalize_training(self): + hidden_states = np.concatenate(self.train_cache, axis=0) + del self.train_cache + local_rank = get_local_rank() + if local_rank == 0: + start = time.time() + print("training db on", self.train_thres, "/", self.train_len) + self.db.train(hidden_states[:self.train_thres]) + if local_rank == 0: + print("training db for", time.time() - start) + self.db.add(hidden_states) + + def search( + self, + query_hidden_states, + orig_dist, + ): + if len(self.videoid_to_vectoridx) != self.db.ntotal: + raise ValueError( + "cannot search: size mismatch in-between index and db", + len(self.videoid_to_vectoridx), + self.db.ntotal + ) + + if self.vectoridx_to_videoid is None: + self.vectoridx_to_videoid = { + self.videoid_to_vectoridx[videoid]: videoid + for videoid in self.videoid_to_vectoridx + } + assert len(self.vectoridx_to_videoid) \ + == len(self.videoid_to_vectoridx) + + # MultilingualFaissDataset uses the following; not sure the purpose. + # faiss.ParameterSpace().set_index_parameter(self.db, "nprobe", 10) + queried_dist, index = self.db.search(query_hidden_states, 1) + queried_dist, index = queried_dist[:, 0], index[:, 0] + + outputs = np.array( + [self.vectoridx_to_videoid[_index] + if _index != -1 else (-1, -1, -1) for _index in index], + dtype=np.int32) + outputs[queried_dist <= orig_dist] = -1 + return outputs + + def search_by_video_ids( + self, + video_ids, + retri_factor + ): + if len(self.videoid_to_vectoridx) != self.db.ntotal: + raise ValueError( + len(self.videoid_to_vectoridx), + self.db.ntotal + ) + + if not self.make_direct_maps_done: + self.make_direct_maps() + + if self.vectoridx_to_videoid is None: + self.vectoridx_to_videoid = { + self.videoid_to_vectoridx[videoid]: videoid + for videoid in self.videoid_to_vectoridx + } + assert len(self.vectoridx_to_videoid) \ + == len(self.videoid_to_vectoridx) + + query_hidden_states = [] + vector_ids = [] + for video_id in video_ids: + vector_id = self.videoid_to_vectoridx[video_id] + vector_ids.append(vector_id) + query_hidden_state = self.db.reconstruct(vector_id) + query_hidden_states.append(query_hidden_state) + query_hidden_states = np.stack(query_hidden_states) + + # MultilingualFaissDataset uses the following; not sure the reason. + # faiss.ParameterSpace().set_index_parameter(self.db, "nprobe", 10) + _, index = self.db.search(query_hidden_states, retri_factor) + outputs = [] + for sample_idx, sample in enumerate(index): + # the first video_id is always the video itself. + cands = [video_ids[sample_idx]] + for vector_idx in sample: + if vector_idx >= 0 \ + and vector_ids[sample_idx] != vector_idx: + cands.append( + self.vectoridx_to_videoid[vector_idx] + ) + outputs.append(cands) + return outputs + + +class VectorRetrieverDM(VectorRetriever): + """ + with direct map. + How2 Video Retriver. + Reference usage of FAISS: + https://github.com/fairinternal/fairseq-py/blob/paraphrase_pretraining/fairseq/data/multilingual_faiss_dataset.py + """ + + def __init__( + self, + hidden_size, + cent, + db_type, + examples_per_cent_to_train + ): + super().__init__( + hidden_size, cent, db_type, examples_per_cent_to_train) + self.make_direct_maps_done = False + + def make_direct_maps(self): + faiss.downcast_index(self.db).make_direct_map() + self.make_direct_maps_done = True + + def search( + self, + query_hidden_states, + orig_dist, + ): + if len(self.videoid_to_vectoridx) != self.db.ntotal: + raise ValueError( + len(self.videoid_to_vectoridx), + self.db.ntotal + ) + + if not self.make_direct_maps_done: + self.make_direct_maps() + if self.vectoridx_to_videoid is None: + self.vectoridx_to_videoid = { + self.videoid_to_vectoridx[videoid]: videoid + for videoid in self.videoid_to_vectoridx + } + assert len(self.vectoridx_to_videoid) \ + == len(self.videoid_to_vectoridx) + + # MultilingualFaissDataset uses the following; not sure the reason. + # faiss.ParameterSpace().set_index_parameter(self.db, "nprobe", 10) + queried_dist, index = self.db.search(query_hidden_states, 1) + outputs = [] + for sample_idx, sample in enumerate(index): + # and queried_dist[sample_idx] < thres \ + if sample >= 0 \ + and queried_dist[sample_idx] < orig_dist[sample_idx]: + outputs.append(self.vectoridx_to_videoid[sample]) + else: + outputs.append(None) + return outputs + + def search_by_video_ids( + self, + video_ids, + retri_factor=8 + ): + if len(self.videoid_to_vectoridx) != self.db.ntotal: + raise ValueError( + len(self.videoid_to_vectoridx), + self.db.ntotal + ) + + if not self.make_direct_maps_done: + self.make_direct_maps() + if self.vectoridx_to_videoid is None: + self.vectoridx_to_videoid = { + self.videoid_to_vectoridx[videoid]: videoid + for videoid in self.videoid_to_vectoridx + } + assert len(self.vectoridx_to_videoid) \ + == len(self.videoid_to_vectoridx) + + query_hidden_states = [] + vector_ids = [] + for video_id in video_ids: + vector_id = self.videoid_to_vectoridx[video_id] + vector_ids.append(vector_id) + query_hidden_state = self.db.reconstruct(vector_id) + query_hidden_states.append(query_hidden_state) + query_hidden_states = np.stack(query_hidden_states) + + # MultilingualFaissDataset uses the following; not sure the reason. + # faiss.ParameterSpace().set_index_parameter(self.db, "nprobe", 10) + _, index = self.db.search(query_hidden_states, retri_factor) + outputs = [] + for sample_idx, sample in enumerate(index): + # the first video_id is always the video itself. + cands = [video_ids[sample_idx]] + for vector_idx in sample: + if vector_idx >= 0 \ + and vector_ids[sample_idx] != vector_idx: + cands.append( + self.vectoridx_to_videoid[vector_idx] + ) + outputs.append(cands) + return outputs + + +class MMVectorRetriever(VectorRetrieverDM): + """ + multimodal vector retriver: + text retrieve video or video retrieve text. + """ + + def __init__(self, hidden_size, cent, db_type, examples_per_cent_to_train): + super().__init__( + hidden_size, cent, db_type, examples_per_cent_to_train) + video_db = self.db + super().__init__( + hidden_size, cent, db_type, examples_per_cent_to_train) + text_db = self.db + self.db = {"video": video_db, "text": text_db} + self.video_to_videoid = defaultdict(list) + + def __len__(self): + assert self.db["video"].ntotal == self.db["text"].ntotal + return self.db["video"].ntotal + + def make_direct_maps(self): + faiss.downcast_index(self.db["video"]).make_direct_map() + faiss.downcast_index(self.db["text"]).make_direct_map() + + def save(self, out_dir): + faiss.write_index( + self.db["video"], + os.path.join(out_dir, "video_faiss_idx") + ) + faiss.write_index( + self.db["text"], + os.path.join(out_dir, "text_faiss_idx") + ) + + with open( + os.path.join( + out_dir, "videoid_to_vectoridx.pkl"), + "wb") as fw: + pickle.dump( + self.videoid_to_vectoridx, fw, + protocol=pickle.HIGHEST_PROTOCOL + ) + + def load(self, out_dir): + fn = os.path.join(out_dir, "video_faiss_idx") + video_db = faiss.read_index(fn) + fn = os.path.join(out_dir, "text_faiss_idx") + text_db = faiss.read_index(fn) + self.db = {"video": video_db, "text": text_db} + with open( + os.path.join(out_dir, "videoid_to_vectoridx.pkl"), "rb") as fr: + self.videoid_to_vectoridx = pickle.load(fr) + self.video_to_videoid = defaultdict(list) + + def add(self, hidden_states, video_ids): + """hidden_states is a pair `(video, text)`""" + assert len(hidden_states) == len(video_ids), "{}, {}".format( + str(len(hidden_states)), str(len(video_ids))) + assert len(hidden_states.shape) == 3 + assert len(self.video_to_videoid) == 0 + + valid_idx = [] + for idx, video_id in enumerate(video_ids): + if video_id not in self.videoid_to_vectoridx: + valid_idx.append(idx) + self.videoid_to_vectoridx[video_id] = \ + len(self.videoid_to_vectoridx) + + batch_size = hidden_states.shape[0] + hidden_states = hidden_states[valid_idx] + + hidden_states = np.transpose(hidden_states, (1, 0, 2)).copy() + if not self.db["video"].is_trained: + self.train_cache.append(hidden_states) + train_len = batch_size * len(self.train_cache) + if train_len < self.train_thres: + return + + hidden_states = np.concatenate(self.train_cache, axis=1) + del self.train_cache + self.db["video"].train(hidden_states[0, :self.train_thres]) + self.db["text"].train(hidden_states[1, :self.train_thres]) + self.db["video"].add(hidden_states[0]) + self.db["text"].add(hidden_states[1]) + + def get_clips_by_video_id(self, video_id): + if not self.video_to_videoid: + for video_id, video_clip, text_clip in self.videoid_to_vectoridx: + self.video_to_videoid[video_id].append( + (video_id, video_clip, text_clip)) + return self.video_to_videoid[video_id] + + def search( + self, + video_ids, + target_modality, + retri_factor=8 + ): + if len(self.videoid_to_vectoridx) != len(self): + raise ValueError( + len(self.videoid_to_vectoridx), + len(self) + ) + + if not self.make_direct_maps_done: + self.make_direct_maps() + if self.vectoridx_to_videoid is None: + self.vectoridx_to_videoid = { + self.videoid_to_vectoridx[videoid]: videoid + for videoid in self.videoid_to_vectoridx + } + assert len(self.vectoridx_to_videoid) \ + == len(self.videoid_to_vectoridx) + + src_modality = "text" if target_modality == "video" else "video" + + query_hidden_states = [] + vector_ids = [] + for video_id in video_ids: + vector_id = self.videoid_to_vectoridx[video_id] + vector_ids.append(vector_id) + query_hidden_state = self.db[src_modality].reconstruct(vector_id) + query_hidden_states.append(query_hidden_state) + query_hidden_states = np.stack(query_hidden_states) + + # MultilingualFaissDataset uses the following; not sure the reason. + # faiss.ParameterSpace().set_index_parameter(self.db, "nprobe", 10) + _, index = self.db[target_modality].search( + query_hidden_states, retri_factor) + outputs = [] + for sample_idx, sample in enumerate(index): + cands = [] + for vector_idx in sample: + if vector_idx >= 0: + cands.append( + self.vectoridx_to_videoid[vector_idx] + ) + outputs.append(cands) + return outputs diff --git a/examples/MMPT/mmpt/modules/vectorpool.py b/examples/MMPT/mmpt/modules/vectorpool.py new file mode 100644 index 0000000000..d2b23d2da8 --- /dev/null +++ b/examples/MMPT/mmpt/modules/vectorpool.py @@ -0,0 +1,246 @@ +# Copyright (c) Facebook, Inc. All Rights Reserved + +import torch +import os +import numpy as np +import pickle + +from . import retri +from ..utils import get_local_rank + + +class VectorPool(object): + """ + Base class of retrieval space. + """ + + def __init__(self, config): + from transformers import AutoConfig + self.hidden_size = AutoConfig.from_pretrained( + config.dataset.bert_name).hidden_size + self.retriever_cls = getattr(retri, config.retriever_cls) + + def __call__(self, sample, **kwargs): + raise NotImplementedError + + def build_retriver( + self, + retriever_cls=None, + hidden_size=None, + centroids=512, + db_type="flatl2", + examples_per_cent_to_train=48 + ): + + """merge results from multiple gpus and return a retriver..""" + self.retriver = retriever_cls( + hidden_size, centroids, db_type, examples_per_cent_to_train) + return self.retriver + + def __repr__(self): + if hasattr(self, "retriver"): + retriver_name = str(len(self.retriver)) + else: + retriver_name = "no retriver field yet" + return self.__class__.__name__ \ + + "(" + retriver_name + ")" + + +class VideoVectorPool(VectorPool): + """ + average clips of a video as video representation. + """ + def __init__(self, config): + super().__init__(config) + self.build_retriver(self.retriever_cls, self.hidden_size) + + def __call__(self, sample, subsampling, **kwargs): + hidden_states = ( + sample["pooled_video"] + sample["pooled_text"]) / 2. + hidden_states = hidden_states.view( + -1, subsampling, + hidden_states.size(-1)) + hidden_states = torch.mean(hidden_states, dim=1) + hidden_states = hidden_states.cpu().detach().numpy() + video_ids = [] + for offset_idx, video_id in enumerate(sample["video_id"]): + if isinstance(video_id, tuple) and len(video_id) == 3: + # a sharded video_id. + video_id = video_id[0] + video_ids.append(video_id) + assert len(video_ids) == len(hidden_states) + self.retriver.add( + hidden_states.astype("float32"), + video_ids + ) + + +class DistributedVectorPool(VectorPool): + """ + support sync of multiple gpus/nodes. + """ + def __init__(self, config): + super().__init__(config) + self.out_dir = os.path.join( + config.fairseq.checkpoint.save_dir, + "retri") + os.makedirs(self.out_dir, exist_ok=True) + self.hidden_states = [] + self.video_ids = [] + + def build_retriver( + self, + retriever_cls=None, + hidden_size=None, + centroids=4096, + db_type="flatl2", + examples_per_cent_to_train=48 + ): + if retriever_cls is None: + retriever_cls = self.retriever_cls + if hidden_size is None: + hidden_size = self.hidden_size + """merge results from multiple gpus and return a retriver..""" + if torch.distributed.is_initialized(): + self.save() + # sync saving. + torch.distributed.barrier() + world_size = torch.distributed.get_world_size() + else: + world_size = 1 + self.retriver = retriever_cls( + hidden_size, centroids, db_type, examples_per_cent_to_train) + # each gpu process has its own retriever. + for local_rank in range(world_size): + if get_local_rank() == 0: + print("load local_rank", local_rank) + hidden_states, video_ids = self.load(local_rank) + hidden_states = hidden_states.astype("float32") + self.retriver.add(hidden_states, video_ids) + return self.retriver + + def load(self, local_rank): + hidden_states = np.load( + os.path.join( + self.out_dir, + "hidden_state" + str(local_rank) + ".npy" + ) + ) + + with open( + os.path.join( + self.out_dir, "video_id" + str(local_rank) + ".pkl"), + "rb") as fr: + video_ids = pickle.load(fr) + return hidden_states, video_ids + + def save(self): + hidden_states = np.vstack(self.hidden_states) + assert len(hidden_states) == len(self.video_ids), "{}, {}".format( + len(hidden_states), + len(self.video_ids) + ) + local_rank = torch.distributed.get_rank() \ + if torch.distributed.is_initialized() else 0 + + np.save( + os.path.join( + self.out_dir, + "hidden_state" + str(local_rank) + ".npy"), + hidden_states) + + with open( + os.path.join( + self.out_dir, + "video_id" + str(local_rank) + ".pkl"), + "wb") as fw: + pickle.dump( + self.video_ids, + fw, + protocol=pickle.HIGHEST_PROTOCOL + ) + + +class DistributedVideoVectorPool(DistributedVectorPool): + """ + average clips of a video as video representation. + """ + def __call__(self, sample, subsampling, **kwargs): + hidden_states = ( + sample["pooled_video"] + sample["pooled_text"]) / 2. + hidden_states = hidden_states.view( + -1, subsampling, + hidden_states.size(-1)) + hidden_states = torch.mean(hidden_states, dim=1) + hidden_states = hidden_states.cpu().detach().numpy() + video_ids = [] + for offset_idx, video_id in enumerate(sample["video_id"]): + if isinstance(video_id, tuple) and len(video_id) == 3: + # a sharded video_id. + video_id = video_id[0] + video_ids.append(video_id) + assert len(video_ids) == len(hidden_states) + self.hidden_states.append(hidden_states) + self.video_ids.extend(video_ids) + + +# ------------ the following are deprecated -------------- + +class TextClipVectorPool(VectorPool): + def __init__(self, config): + from transformers import AutoConfig + hidden_size = AutoConfig.from_pretrained( + config.dataset.bert_name).hidden_size + retriever_cls = getattr(retri, config.retriever_cls) + self.build_retriver(retriever_cls, hidden_size) + + def __call__(self, sample, **kwargs): + clip_meta = sample["clip_meta"].cpu() + assert torch.all(torch.le(clip_meta[:, 4], clip_meta[:, 5])) + text_meta = [tuple(item.tolist()) for item in clip_meta[:, 3:]] + + if hasattr(self, "retriver"): + # build_retriver is called. + self.retriver.add( + sample["pooled_text"].cpu().numpy().astype("float32"), + text_meta + ) + else: + raise NotImplementedError + + +class MMClipVectorPool(VectorPool): + """ + Multimodal Clip-level vector pool. + """ + def __init__(self, out_dir): + """use hidden_states to store `(video, text)`.""" + """use video_ids to store `(video_id, start, end)`.""" + super().__init__(out_dir) + + def __call__(self, sample, **kwargs): + pooled_video = sample["pooled_video"].cpu().unsqueeze(1).numpy() + pooled_text = sample["pooled_text"].cpu().unsqueeze(1).numpy() + + self.hidden_states.append( + np.concatenate([pooled_video, pooled_text], axis=1) + ) + + video_starts = sample["video_start"].cpu() + video_ends = sample["video_end"].cpu() + assert torch.all(torch.le(video_starts, video_ends)) + + text_starts = sample["text_start"].cpu() + text_ends = sample["text_end"].cpu() + assert torch.all(torch.le(text_starts, text_ends)) + subsample_size = sample["pooled_video"].size(0) // len(sample["video_id"]) + video_ids = [video_id for video_id in sample["video_id"] + for _ in range(subsample_size) + ] + for video_id, video_start, video_end, text_start, text_end in zip( + video_ids, video_starts, video_ends, text_starts, text_ends): + self.video_ids.append(( + video_id, + (int(video_start), int(video_end)), + (int(text_start), int(text_end)) + )) diff --git a/examples/MMPT/mmpt/processors/__init__.py b/examples/MMPT/mmpt/processors/__init__.py new file mode 100644 index 0000000000..434d1d92b9 --- /dev/null +++ b/examples/MMPT/mmpt/processors/__init__.py @@ -0,0 +1,23 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +from .processor import * + +from .how2processor import * +from .how2retriprocessor import * + +from .dsprocessor import * + +try: + from .rawvideoprocessor import * + from .codecprocessor import * + from .webvidprocessor import * + from .expprocessor import * + from .exphow2processor import * + from .exphow2retriprocessor import * + from .expcodecprocessor import * + from .expfeatureencoder import * + from .expdsprocessor import * +except ImportError: + pass diff --git a/examples/MMPT/mmpt/processors/dedupprocessor.py b/examples/MMPT/mmpt/processors/dedupprocessor.py new file mode 100644 index 0000000000..8a1ad402cd --- /dev/null +++ b/examples/MMPT/mmpt/processors/dedupprocessor.py @@ -0,0 +1,242 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import random +import json +import pickle +from tqdm import tqdm +import os +import numpy as np + + +class CaptionDedupProcessor(object): + """remove overlapping of caption sentences(clip). + Some statistics: + caption: + {'t_clip_len': 246.6448431320854, + 'video_len': 281.09174795676245, + 'clip_tps': 0.8841283727427481, + 'video_tps': 0.7821156477732097, + 'min_clip_len': 0.0, + 'max_clip_len': 398.3, + 'mean_clip_len': 3.196580003006861, + 'num_clip': 77.15897706301081} + + raw_caption: + {'t_clip_len': 238.95908778424115, + 'video_len': 267.5914859862507, + 'clip_tps': 2.4941363624267963, + 'video_tps': 2.258989769647173, + 'min_clip_len': 0.0, + 'max_clip_len': 398.3, + 'mean_clip_len': 3.0537954186814265, + 'num_clip': 78.24986779481756} + """ + + def __init__(self, pkl_file): + with open(pkl_file, "rb") as fd: + self.data = pickle.load(fd) + self.stat = { + "t_clip_len": [], + "video_len": [], + "clip_tps": [], + "video_tps": [], + "clip_len": [], + } + + def __call__(self): + for idx, video_id in enumerate(tqdm(self.data)): + caption = json.loads(self.data[video_id]) + caption = self._dedup(caption) + if idx < 4096: # for the first 4096 examples, compute the statistics. + self.save_stat(video_id, caption) + self.data[video_id] = json.dumps(caption) + self.print_stat() + + def single(self, video_id): + caption = json.loads(self.data[video_id]) + for clip_idx, (start, end, text) in enumerate( + zip(caption["start"], caption["end"], caption["text"]) + ): + print(start, end, text) + print("@" * 100) + caption = self._dedup(caption) + for clip_idx, (start, end, text) in enumerate( + zip(caption["start"], caption["end"], caption["text"]) + ): + print(start, end, text) + print("#" * 100) + self.save_stat(video_id, caption) + self.print_stat() + + def finalize(self, tgt_fn): + with open(tgt_fn, "wb") as fw: + pickle.dump(self.data, fw, pickle.HIGHEST_PROTOCOL) + + def save_stat(self, video_id, caption): + video_fn = os.path.join( + "data/feat/feat_how2_s3d", video_id + ".npy" + ) + if os.path.isfile(video_fn): + with open(video_fn, "rb", 1) as fr: # 24 is the buffer size. buffered + version = np.lib.format.read_magic(fr) + shape, fortran, dtype = np.lib.format._read_array_header(fr, version) + video_len = shape[0] + + t_clip_len = 0.0 + t_tokens = 0 + for idx, (start, end, text) in enumerate( + zip(caption["start"], caption["end"], caption["text"]) + ): + clip_len = ( + (end - max(caption["end"][idx - 1], start)) + if idx > 0 + else end - start + ) + t_clip_len += clip_len + t_tokens += len(text.split(" ")) + self.stat["clip_len"].append(clip_len) + self.stat["t_clip_len"].append(t_clip_len) + self.stat["video_len"].append(video_len) + self.stat["clip_tps"].append(t_tokens / t_clip_len) + self.stat["video_tps"].append(t_tokens / video_len) + + def print_stat(self): + result = { + "t_clip_len": np.mean(self.stat["t_clip_len"]), + "video_len": np.mean(self.stat["video_len"]), + "clip_tps": np.mean(self.stat["clip_tps"]), + "video_tps": np.mean(self.stat["video_tps"]), + "min_clip_len": min(self.stat["clip_len"]), + "max_clip_len": max(self.stat["clip_len"]), + "mean_clip_len": np.mean(self.stat["clip_len"]), + "num_clip": len(self.stat["clip_len"]) / len(self.stat["video_tps"]), + } + print(result) + + def _dedup(self, caption): + def random_merge(end_idx, start, end, text, starts, ends, texts): + if random.random() > 0.5: + # print(clip_idx, "[PARTIAL INTO PREV]", end_idx) + # overlapped part goes to the end of previous. + ends[-1] = max(ends[-1], start) # ? + rest_text = text[end_idx:].strip() + if rest_text: + starts.append(max(ends[-1], start)) + ends.append(max(end, starts[-1])) + texts.append(rest_text) + else: # goes to the beginning of the current. + # strip the previous. + left_text = texts[-1][:-end_idx].strip() + if left_text: + # print(clip_idx, "[PREV PARTIAL INTO CUR]", end_idx) + ends[-1] = min(ends[-1], start) + texts[-1] = left_text + else: + # print(clip_idx, "[PREV LEFT NOTHING ALL INTO CUR]", end_idx) + starts.pop(-1) + ends.pop(-1) + texts.pop(-1) + starts.append(start) + ends.append(end) + texts.append(text) + + starts, ends, texts = [], [], [] + for clip_idx, (start, end, text) in enumerate( + zip(caption["start"], caption["end"], caption["text"]) + ): + if not isinstance(text, str): + continue + text = text.replace("\n", " ").strip() + if len(text) == 0: + continue + starts.append(start) + ends.append(end) + texts.append(text) + break + + for clip_idx, (start, end, text) in enumerate( + zip( + caption["start"][clip_idx + 1:], + caption["end"][clip_idx + 1:], + caption["text"][clip_idx + 1:], + ) + ): + if not isinstance(text, str): + continue + text = text.replace("\n", " ").strip() + if len(text) == 0: + continue + + # print(clip_idx, texts[-5:]) + # print(clip_idx, start, end, text) + if texts[-1].endswith(text): # subset of prev caption -> merge + # print(clip_idx, "[MERGE INTO PREV]") + ends[-1] = max(ends[-1], end) + elif text.startswith(texts[-1]): # superset of prev caption -> merge + # print(clip_idx, "[PREV MERGE INTO CUR]") + texts[-1] = text + starts[-1] = min(starts[-1], start) + ends[-1] = max(ends[-1], end) + else: # overlapping or non-overlapping. + for end_idx in range(1, len(text) + 1): + if texts[-1].endswith(text[:end_idx]): + random_merge(end_idx, start, end, text, starts, ends, texts) + break + else: + starts.append(start) + ends.append(end) + texts.append(text) + + assert (ends[-1] + 0.001) >= starts[-1] and len( + texts[-1] + ) > 0, "{} {} {} <- {} {} {}, {} {} {}".format( + str(starts[-1]), + str(ends[-1]), + texts[-1], + caption["start"][clip_idx - 1], + caption["end"][clip_idx - 1], + caption["text"][clip_idx - 1], + str(start), + str(end), + text, + ) + + return {"start": starts, "end": ends, "text": texts} + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description="dedup how2 caption") + parser.add_argument('--how2dir', default="data/how2") + args = parser.parse_args() + + raw_caption_json = os.path.join(args.how2dir, "raw_caption.json") + raw_caption_pickle = os.path.join(args.how2dir, "raw_caption.pkl") + raw_caption_dedup_pickle = os.path.join(args.how2dir, "raw_caption_dedup.pkl") + + def convert_to_pickle(src_fn, tgt_fn): + with open(src_fn) as fd: + captions = json.load(fd) + + for video_id in captions: + captions[video_id] = json.dumps(captions[video_id]) + + with open(tgt_fn, "wb") as fw: + pickle.dump(captions, fw, pickle.HIGHEST_PROTOCOL) + + if not os.path.isfile(raw_caption_pickle): + convert_to_pickle(raw_caption_json, raw_caption_pickle) + + deduper = CaptionDedupProcessor(raw_caption_pickle) + deduper() + deduper.finalize(raw_caption_dedup_pickle) + + """ + # demo + deduper = CaptionDedupProcessor("data/how2/raw_caption.pkl") + deduper.single("HfIeQ9pzL5U") + """ diff --git a/examples/MMPT/mmpt/processors/dsprocessor.py b/examples/MMPT/mmpt/processors/dsprocessor.py new file mode 100644 index 0000000000..1ec7f2201a --- /dev/null +++ b/examples/MMPT/mmpt/processors/dsprocessor.py @@ -0,0 +1,836 @@ +# Copyright (c) Facebook, Inc. All Rights Reserved + +""" +Processors for all downstream (ds) tasks. +""" + +import json +import os +import pickle +import random +import math +import numpy as np +import torch + +from collections import defaultdict + +from .processor import ( + MetaProcessor, + VideoProcessor, + TextProcessor, + Aligner, + MMAttentionMask2DProcessor, +) + +from .how2processor import TextGenerationProcessor + + +# ------------- A General Aligner for all downstream tasks----------------- + + +class DSAligner(Aligner): + """ + Downstream (DS) aligner shared by all datasets. + """ + + def __call__(self, video_id, video_feature, text_feature, wps=0.7): + # random sample a starting sec for video. + video_start = 0 + video_end = min(len(video_feature), self.max_video_len) + # the whole sequence is a single clip. + video_clips = {"start": [video_start], "end": [video_end]} + + text_feature = { + "cap": [text_feature], + "start": [video_start], + "end": [len(text_feature) / wps], + } + text_clip_indexs = [0] + + vfeats, vmasks = self._build_video_seq( + video_feature, video_clips + ) + caps, cmasks = self._build_text_seq( + text_feature, text_clip_indexs + ) + + return { + "caps": caps, + "cmasks": cmasks, + "vfeats": vfeats, + "vmasks": vmasks, + "video_id": video_id, + } + + +class NLGTextProcessor(TextProcessor): + """ + Also return the original text as ref. + """ + def __call__(self, text_id): + return super().__call__(text_id), text_id + + +class DSNLGAligner(DSAligner): + """extend with the capability of 2d mask for generation.""" + def __init__(self, config): + super().__init__(config) + self.attnmasker = MMAttentionMask2DProcessor() + from transformers import AutoTokenizer + tokenizer = AutoTokenizer.from_pretrained( + self.bert_name, use_fast=self.use_fast, + bos_token="[CLS]", eos_token="[SEP]" + ) + self.tokenizer = tokenizer + self.bos_token_id = tokenizer.bos_token_id + self.eos_token_id = tokenizer.eos_token_id + self.textgen = TextGenerationProcessor(tokenizer) + + def __call__(self, video_id, video_feature, text_feature): + output = super().__call__(video_id, video_feature, text_feature[0]) + if self.split == "test": + # output.update({"ref": text_feature[1]}) + output.update({"ref": self.tokenizer.decode( + output["caps"], skip_special_tokens=True)}) + text_label = output["caps"] + cmasks = torch.BoolTensor([1] * text_label.size(0)) + caps = torch.LongTensor([ + self.cls_token_id, + self.sep_token_id, + self.bos_token_id]) + else: + caps, text_label = self.textgen(output["caps"]) + cmasks = output["cmasks"] + + attention_mask = self.attnmasker( + output["vmasks"], cmasks, "textgen") + + output.update({ + "caps": caps, + "cmasks": cmasks, + "text_label": text_label, + "attention_mask": attention_mask, + }) + return output + + +# -------------------- MSRVTT ------------------------ + + +class MSRVTTMetaProcessor(MetaProcessor): + """MSRVTT dataset. + reference: `howto100m/msrvtt_dataloader.py` + """ + + def __init__(self, config): + super().__init__(config) + import pandas as pd + data = pd.read_csv(self._get_split_path(config)) + # TODO: add a text1ka flag. + if config.split == "train" \ + and config.full_test_path is not None \ + and config.jsfusion_path is not None: + # add testing videos from full_test_path not used by jfusion. + additional_data = pd.read_csv(config.full_test_path) + jsfusion_data = pd.read_csv(config.jsfusion_path) + + for video_id in additional_data["video_id"]: + if video_id not in jsfusion_data["video_id"].values: + data = data.append( + {"video_id": video_id}, ignore_index=True) + + if config.dup is not None and config.split == "train": + data = data.append([data] * (config.dup - 1), ignore_index=True) + self.data = data + + def __len__(self): + return len(self.data) + + def __getitem__(self, idx): + """slightly modify with if condition to combine train/test.""" + vid, sentence = None, None + vid = self.data["video_id"].values[idx] + if "sentence" in self.data: # for testing. + sentence = self.data["sentence"].values[idx] + else: # for training. + sentence = vid + return vid, sentence + + +class MSRVTTTextProcessor(TextProcessor): + """MSRVTT dataset. + reference: `msrvtt_dataloader.py` `MSRVTT_TrainDataLoader`. + TODO (huxu): add max_words. + """ + + def __init__(self, config): + super().__init__(config) + self.sentences = None + if config.json_path is not None and config.split == "train": + with open(config.json_path) as fd: + self.data = json.load(fd) + self.sentences = defaultdict(list) + for s in self.data["sentences"]: + self.sentences[s["video_id"]].append(s["caption"]) + + def __call__(self, text_id): + if self.sentences is not None: + rind = random.randint(0, len(self.sentences[text_id]) - 1) + sentence = self.sentences[text_id][rind] + else: + sentence = text_id + caption = self.tokenizer(sentence, add_special_tokens=False) + return caption["input_ids"] + + +class MSRVTTNLGTextProcessor(MSRVTTTextProcessor): + """TODO: change dsaligner and merge to avoid any NLG text processor.""" + def __call__(self, text_id): + if self.sentences is not None: + rind = random.randint(0, len(self.sentences[text_id]) - 1) + sentence = self.sentences[text_id][rind] + else: + sentence = text_id + caption = self.tokenizer(sentence, add_special_tokens=False) + return caption["input_ids"], sentence + + +class MSRVTTQAMetaProcessor(MetaProcessor): + """MSRVTT-QA: retrieval-based multi-choice QA from JSFusion dataset. + For simplicity, we use the train retrieval model. + reference: `https://github.com/yj-yu/lsmdc` + """ + + def __init__(self, config): + super().__init__(config) + import pandas as pd + csv_data = pd.read_csv(self._get_split_path(config), sep="\t") + data = [] + for video_id, a1, a2, a3, a4, a5, answer in zip( + csv_data["vid_key"].values, + csv_data["a1"].values, + csv_data["a2"].values, + csv_data["a3"].values, + csv_data["a4"].values, + csv_data["a5"].values, + csv_data["answer"].values): + video_id = video_id.replace("msr", "video") + data.append((video_id, (answer, [a1, a2, a3, a4, a5]))) + self.data = data + + def __len__(self): + return len(self.data) + + def __getitem__(self, idx): + return self.data[idx] + + +class MSRVTTQATextProcessor(TextProcessor): + """MSRVTT-QA dataset. + text_ans is of format `(answer, [a1, a2, a3, a4, a5])`. + """ + + def __call__(self, text_ans): + for ans_idx, ans in enumerate(text_ans[1]): + if isinstance(ans, str): + text_ans[1][ans_idx] = self.tokenizer(ans, add_special_tokens=False)["input_ids"] + return text_ans + + +class MSRVTTQAAligner(DSAligner): + """MSRVTT dataset. + similar to sample in how2. + we call __call__ multiple times. + """ + + def __call__(self, video_id, video_feature, text_feature, wps=0.7): + caps = [] + cmasks = [] + answer = text_feature[0] + for ans_idx, _text_feature in enumerate(text_feature[1]): + output = super().__call__( + video_id, video_feature, _text_feature, wps) + caps.append(output["caps"]) + cmasks.append(output["cmasks"]) + output.update({ + "caps": torch.stack(caps), + "cmasks": torch.stack(cmasks), + "answers": torch.LongTensor([answer]), + }) + return output + + +# -------------------- Youcook ----------------------- + + +class YoucookMetaProcessor(MetaProcessor): + """Youcook dataset. + reference: `howto100m/youcook_dataloader.py` + note that the data can be different as the + (1) some videos already in Howto100m are removed. + (2) stop words are removed from caption + TODO (huxu): make a flag to load the original caption. + (see + /datasets01/YouCookII/062920/YouCookII/annotations/youcookii_annotations_trainval.json). + + The max_video_len can be 264 and text can be 64 tokens. + In reality we may not need that long. see projects/mmfusion/youcook.yaml + """ + + def __init__(self, config): + super().__init__(config) + vfeat_dir = config.vfeat_dir + print(self._get_split_path(config)) + with open(self._get_split_path(config), "rb") as fd: + data = pickle.load(fd) + all_valid_video_ids = set( + [os.path.splitext(fn)[0] for fn in os.listdir(vfeat_dir)] + ) + recs = [] + video_ids = set() + valid_video_ids = set() + for rec in data: # filter videos not available. + udl_idx = rec["id"].rindex("_") + video_id = rec["id"][:udl_idx] + video_ids.add(video_id) + if video_id in all_valid_video_ids: + valid_video_ids.add(video_id) + recs.append(rec) + print("total video_ids in .pkl", len(video_ids)) + print("valid video_ids in .pkl", len(valid_video_ids)) + print("please verify /datasets01/YouCookII/062920/YouCookII/splits/{train,val}_list.txt") + data = recs + self.data = data + + with open(config.trainval_annotation) as fd: + self.youcook_annotation = json.load(fd)["database"] + if config.use_annotation_text is True: + print("using text in annotation.") + self.use_annotation_caption = True + else: + self.use_annotation_caption = False + + def __getitem__(self, idx): + def _get_video_and_caption(rec): + vid = rec["id"] + udl_idx = vid.rindex("_") + video_id, clip_id = vid[:udl_idx], int(vid[udl_idx + 1:]) + clip = self.youcook_annotation[video_id]["annotations"][clip_id] + start, end = clip["segment"] + if self.use_annotation_caption: + caption = clip["sentence"] + else: + caption = rec["caption"] + return (video_id, start, end), caption + + rec = self.data[idx] + video_info, text_info = _get_video_and_caption(rec) + return video_info, text_info + + +class YoucookVideoProcessor(VideoProcessor): + """video_fn is a tuple of (video_id, start, end) now.""" + + def __call__(self, video_fn): + video_id, start, end = video_fn + feat = np.load(os.path.join(self.vfeat_dir, video_id + ".npy")) + return feat[start:end] + + +class YoucookNLGMetaProcessor(MetaProcessor): + """NLG uses the original split: + `/datasets01/YouCookII/062920/YouCookII/splits/train_list.txt` + `/datasets01/YouCookII/062920/YouCookII/splits/val_list.txt` + """ + + def __init__(self, config): + super().__init__(config) + vfeat_dir = config.vfeat_dir + print(self._get_split_path(config)) + with open(self._get_split_path(config)) as fd: + video_ids = [ + line.strip().split("/")[1] for line in fd.readlines()] + print("total video_ids in train/val_list.txt", len(video_ids)) + + all_valid_video_ids = set( + [os.path.splitext(fn)[0] for fn in os.listdir(vfeat_dir)] + ) + video_ids = [ + video_id for video_id in video_ids + if video_id in all_valid_video_ids] + + print("valid video_ids in train/val_list.txt", len(video_ids)) + with open(config.trainval_annotation) as fd: + self.youcook_annotation = json.load(fd)["database"] + + data = [] + for video_id in video_ids: + for clip in self.youcook_annotation[video_id]["annotations"]: + start, end = clip["segment"] + caption = clip["sentence"] + data.append(((video_id, start, end), caption)) + self.data = data + + def __getitem__(self, idx): + return self.data[idx] + + +# --------------------- CrossTask ------------------------- + +class CrossTaskMetaProcessor(MetaProcessor): + def __init__(self, config): + super().__init__(config) + np.random.seed(0) # deterministic random split. + task_vids = self._get_vids( + config.train_csv_path, + config.vfeat_dir, + config.annotation_path) + + val_vids = self._get_vids( + config.val_csv_path, + config.vfeat_dir, + config.annotation_path) + + # filter out those task and vids appear in val_vids. + task_vids = { + task: [ + vid for vid in vids + if task not in val_vids or vid not in val_vids[task]] + for task, vids in task_vids.items()} + + primary_info = self._read_task_info(config.primary_path) + test_tasks = set(primary_info['steps'].keys()) + + # if args.use_related: + related_info = self._read_task_info(config.related_path) + task_steps = {**primary_info['steps'], **related_info['steps']} + n_steps = {**primary_info['n_steps'], **related_info['n_steps']} + # else: + # task_steps = primary_info['steps'] + # n_steps = primary_info['n_steps'] + all_tasks = set(n_steps.keys()) + # filter and keep task in primary or related. + task_vids = { + task: vids for task, vids in task_vids.items() + if task in all_tasks} + # vocab-by-step matrix (A) and vocab (M) + # (huxu): we do not use BoW. + # A, M = self._get_A(task_steps, share="words") + + train_vids, test_vids = self._random_split( + task_vids, test_tasks, config.n_train) + print("train_num_videos", sum(len(vids) for vids in train_vids.values())) + print("test_num_videos", sum(len(vids) for vids in test_vids.values())) + # added by huxu to automatically determine the split. + split_map = { + "train": train_vids, + "valid": test_vids, + "test": test_vids + } + task_vids = split_map[config.split] + + self.vids = [] + for task, vids in task_vids.items(): + self.vids.extend([(task, vid) for vid in vids]) + self.task_steps = task_steps + self.n_steps = n_steps + + def __getitem__(self, idx): + task, vid = self.vids[idx] + n_steps = self.n_steps[task] + steps = self.task_steps[task] + assert len(steps) == n_steps + return (task, vid, steps, n_steps), (task, vid, steps, n_steps) + + def __len__(self): + return len(self.vids) + + def _random_split(self, task_vids, test_tasks, n_train): + train_vids = {} + test_vids = {} + for task, vids in task_vids.items(): + if task in test_tasks and len(vids) > n_train: + train_vids[task] = np.random.choice( + vids, n_train, replace=False).tolist() + test_vids[task] = [ + vid for vid in vids if vid not in train_vids[task]] + else: + train_vids[task] = vids + return train_vids, test_vids + + def _get_vids(self, path, vfeat_dir, annotation_path): + """refactored from + https://github.com/DmZhukov/CrossTask/blob/master/data.py + changes: add `vfeat_dir` to check if the video is available. + add `annotation_path` to check if the video is available. + """ + + task_vids = {} + with open(path, 'r') as f: + for line in f: + task, vid, url = line.strip().split(',') + # double check the video is available. + if not os.path.exists( + os.path.join(vfeat_dir, vid + ".npy")): + continue + # double check the annotation is available. + if not os.path.exists(os.path.join( + annotation_path, + task + "_" + vid + ".csv")): + continue + if task not in task_vids: + task_vids[task] = [] + task_vids[task].append(vid) + return task_vids + + def _read_task_info(self, path): + titles = {} + urls = {} + n_steps = {} + steps = {} + with open(path, 'r') as f: + idx = f.readline() + while idx != '': + idx = idx.strip() + titles[idx] = f.readline().strip() + urls[idx] = f.readline().strip() + n_steps[idx] = int(f.readline().strip()) + steps[idx] = f.readline().strip().split(',') + next(f) + idx = f.readline() + return { + 'title': titles, + 'url': urls, + 'n_steps': n_steps, + 'steps': steps + } + + def _get_A(self, task_steps, share="words"): + raise ValueError("running get_A is not allowed for BERT.") + """Step-to-component matrices.""" + if share == 'words': + # share words + task_step_comps = { + task: [step.split(' ') for step in steps] + for task, steps in task_steps.items()} + elif share == 'task_words': + # share words within same task + task_step_comps = { + task: [[task+'_'+tok for tok in step.split(' ')] for step in steps] + for task, steps in task_steps.items()} + elif share == 'steps': + # share whole step descriptions + task_step_comps = { + task: [[step] for step in steps] for task, steps in task_steps.items()} + else: + # no sharing + task_step_comps = { + task: [[task+'_'+step] for step in steps] + for task, steps in task_steps.items()} + # BERT tokenizer here? + vocab = [] + for task, steps in task_step_comps.items(): + for step in steps: + vocab.extend(step) + vocab = {comp: m for m, comp in enumerate(set(vocab))} + M = len(vocab) + A = {} + for task, steps in task_step_comps.items(): + K = len(steps) + a = torch.zeros(M, K) + for k, step in enumerate(steps): + a[[vocab[comp] for comp in step], k] = 1 + a /= a.sum(dim=0) + A[task] = a + return A, M + + +class CrossTaskVideoProcessor(VideoProcessor): + def __call__(self, video_fn): + task, vid, steps, n_steps = video_fn + video_fn = os.path.join(self.vfeat_dir, vid + ".npy") + feat = np.load(video_fn) + return feat + + +class CrossTaskTextProcessor(TextProcessor): + def __call__(self, text_id): + task, vid, steps, n_steps = text_id + step_ids = [] + for step_str in steps: + step_ids.append( + self.tokenizer(step_str, add_special_tokens=False)["input_ids"] + ) + return step_ids + + +class CrossTaskAligner(Aligner): + """ + TODO: it's not clear yet the formulation of the task; finish this later. + """ + def __init__(self, config): + super().__init__(config) + self.annotation_path = config.annotation_path + self.sliding_window = config.sliding_window + self.sliding_window_size = config.sliding_window_size + + def __call__(self, video_id, video_feature, text_feature): + task, vid, steps, n_steps = video_id + annot_path = os.path.join( + self.annotation_path, task + '_' + vid + '.csv') + video_len = len(video_feature) + + labels = torch.from_numpy(self._read_assignment( + video_len, n_steps, annot_path)).float() + + vfeats, vmasks, targets = [], [], [] + # sliding window on video features and targets. + for window_start in range(0, video_len, self.sliding_window): + video_start = 0 + video_end = min(video_len - window_start, self.sliding_window_size) + video_clip = {"start": [video_start], "end": [video_end]} + + vfeat, vmask = self._build_video_seq( + video_feature[window_start: window_start + video_end], + video_clip + ) + + target = labels[window_start: window_start + video_end] + assert len(vfeat) >= len(target), "{},{}".format(len(vfeat), len(target)) + # TODO: randomly drop all zero targets for training ? + # if self.split == "train" and target.sum() == 0: + # continue + vfeats.append(vfeat) + vmasks.append(vmask) + targets.append(target) + + if (video_len - window_start) <= self.sliding_window_size: + break + + vfeats = torch.stack(vfeats) + vmasks = torch.stack(vmasks) + targets = torch.cat(targets, dim=0) + + caps, cmasks = [], [] + for step in text_feature: + step_text_feature = {"start": [0], "end": [1], "cap": [step]} + step_text_clip_index = [0] + cap, cmask = self._build_text_seq( + step_text_feature, step_text_clip_index + ) + caps.append(cap) + cmasks.append(cmask) + caps = torch.stack(caps) + cmasks = torch.stack(cmasks) + + return { + "caps": caps, + "cmasks": cmasks, + "vfeats": vfeats, # X for original code. + "vmasks": vmasks, + "targets": targets, + "video_id": vid, + "task": task, + "video_len": video_len # for later checking. + } + + def _read_assignment(self, T, K, path): + """ + refactored from https://github.com/DmZhukov/CrossTask/blob/master/data.py + Howto interpret contraints on loss that is going to be minimized: + lambd is a big number; + self.lambd * C is a big number for all valid position (csv stores invalids) + + def forward(self, O, Y, C): + return (Y*(self.lambd * C - self.lsm(O))).mean(dim=0).sum() + + This will load the csv file and fill-in the step col from start to end rows. + """ + + Y = np.zeros([T, K], dtype=np.uint8) + with open(path, 'r') as f: + for line in f: + step, start, end = line.strip().split(',') + start = int(math.floor(float(start))) + end = int(math.ceil(float(end))) + step = int(step) - 1 + Y[start:end, step] = 1 + return Y + + +# --------------------- COIN ------------------------- + +class COINActionSegmentationMetaProcessor(MetaProcessor): + split_map = { + "train": "training", + "valid": "testing", + "test": "testing", + } + + def __init__(self, config): + super().__init__(config) + with open(self._get_split_path(config)) as fr: + database = json.load(fr)["database"] + id2label = {} + data = [] + # filter the data by split. + for video_id, rec in database.items(): + # always use testing to determine label_set + if rec["subset"] == "testing": + for segment in rec["annotation"]: + id2label[int(segment["id"])] = segment["label"] + # text_labels is used for ZS setting + self.text_labels = ["none"] * len(id2label) + for label_id in id2label: + self.text_labels[label_id-1] = id2label[label_id] + + id2label[0] = "O" + print("num of labels", len(id2label)) + + for video_id, rec in database.items(): + if not os.path.isfile(os.path.join(config.vfeat_dir, video_id + ".npy")): + continue + if rec["subset"] == COINActionSegmentationMetaProcessor.split_map[self.split]: + starts, ends, labels = [], [], [] + for segment in rec["annotation"]: + start, end = segment["segment"] + label = int(segment["id"]) + starts.append(start) + ends.append(end) + labels.append(label) + data.append( + (video_id, {"start": starts, "end": ends, "label": labels})) + self.data = data + + def meta_text_labels(self, config): + from transformers import default_data_collator + from .expdsprocessor import MetaTextBinarizer + from ..utils import get_local_rank + + text_processor = TextProcessor(config) + binarizer = MetaTextBinarizer(config) + # TODO: add prompts to .yaml. + text_labels = [label for label in self.text_labels] + + if get_local_rank() == 0: + print(text_labels) + + outputs = [] + for text_label in text_labels: + text_feature = text_processor(text_label) + outputs.append(binarizer(text_feature)) + return default_data_collator(outputs) + + def __getitem__(self, idx): + return self.data[idx] + + +class COINActionSegmentationTextProcessor(TextProcessor): + def __call__(self, text_label): + return text_label + + +class COINActionSegmentationAligner(Aligner): + def __init__(self, config): + super().__init__(config) + self.sliding_window = config.sliding_window + self.sliding_window_size = config.sliding_window_size + + def __call__(self, video_id, video_feature, text_feature): + starts, ends, label_ids = text_feature["start"], text_feature["end"], text_feature["label"] + # sliding window. + video_len = len(video_feature) + + vfeats, vmasks, targets = [], [], [] + # sliding window on video features and targets. + for window_start in range(0, video_len, self.sliding_window): + video_start = 0 + video_end = min(video_len - window_start, self.sliding_window_size) + video_clip = {"start": [video_start], "end": [video_end]} + vfeat, vmask = self._build_video_seq( + video_feature[window_start: window_start + video_end], + video_clip + ) + # covers video length only. + target = torch.full_like(vmask, -100, dtype=torch.long) + target[vmask] = 0 + for start, end, label_id in zip(starts, ends, label_ids): + if (window_start < end) and (start < (window_start + video_end)): + start_offset = max(0, math.floor(start) - window_start) + end_offset = min(video_end, math.ceil(end) - window_start) + target[start_offset:end_offset] = label_id + vfeats.append(vfeat) + vmasks.append(vmask) + targets.append(target) + if (video_len - window_start) <= self.sliding_window_size: + break + + vfeats = torch.stack(vfeats) + vmasks = torch.stack(vmasks) + targets = torch.stack(targets) + video_targets = torch.full((video_len,), 0) + for start, end, label_id in zip(starts, ends, label_ids): + start_offset = max(0, math.floor(start)) + end_offset = min(video_len, math.ceil(end)) + video_targets[start_offset:end_offset] = label_id + + caps = torch.LongTensor( + [[self.cls_token_id, self.sep_token_id, + self.pad_token_id, self.sep_token_id]], + ).repeat(vfeats.size(0), 1) + cmasks = torch.BoolTensor( + [[0, 1, 0, 1]] # pad are valid for attention. + ).repeat(vfeats.size(0), 1) + return { + "caps": caps, + "cmasks": cmasks, + "vfeats": vfeats, # X for original code. + "vmasks": vmasks, + "targets": targets, + "video_id": video_id, + "video_len": video_len, # for later checking. + "video_targets": video_targets + } + + +class DiDeMoMetaProcessor(MetaProcessor): + """reference: https://github.com/LisaAnne/LocalizingMoments/blob/master/utils/eval.py + https://github.com/LisaAnne/LocalizingMoments/blob/master/utils/data_processing.py + """ + def __init__(self, config): + super().__init__(config) + + assert "test" in self._get_split_path(config), "DiDeMo only supports zero-shot testing for now." + + with open(self._get_split_path(config)) as data_file: + json_data = json.load(data_file) + + data = [] + for record in json_data: + data.append((record["video"], record["description"])) + self.data = data + + def __len__(self): + return len(self.data) + + def __getitem__(self, idx): + return self.data[idx] + + +class DiDeMoTextProcessor(TextProcessor): + """reference: https://github.com/LisaAnne/LocalizingMoments/blob/master/utils/eval.py + https://github.com/LisaAnne/LocalizingMoments/blob/master/utils/data_processing.py + """ + + def __call__(self, text): + return self.tokenizer(text, add_special_tokens=False)["input_ids"] + + +class DiDeMoAligner(DSAligner): + """ + check video length. + """ + + def __call__(self, video_id, video_feature, text_feature): + # print(video_feature.shape[0]) + return super().__call__(video_id, video_feature, text_feature) diff --git a/examples/MMPT/mmpt/processors/how2processor.py b/examples/MMPT/mmpt/processors/how2processor.py new file mode 100644 index 0000000000..bed2168b1d --- /dev/null +++ b/examples/MMPT/mmpt/processors/how2processor.py @@ -0,0 +1,887 @@ +# coding=utf-8 +# Copyright 2018 The Google AI Language Team Authors and The HuggingFace Inc. team. +# Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Copyright (c) Facebook, Inc. All Rights Reserved + + +import torch +import math +import pickle +import random +import os +import numpy as np + +from collections import deque +from typing import Optional, Tuple, List +from .processor import ( + Processor, + MetaProcessor, + TextProcessor, + Aligner, + MMAttentionMask2DProcessor +) + +from ..utils import ShardedTensor + + +class How2MetaProcessor(MetaProcessor): + def __init__(self, config): + super().__init__(config) + path = self._get_split_path(config) + with open(path) as fd: + self.data = [line.strip() for line in fd] + + def __getitem__(self, idx): + video_id = self.data[idx] + return video_id, video_id + + +class ShardedHow2MetaProcessor(How2MetaProcessor): + def __init__(self, config): + super().__init__(config) + self.split = str(config.split) + self.vfeat_dir = config.vfeat_dir + self._init_shard() + + def _init_shard(self): + if self.split == "train": + meta_fn = os.path.join(self.vfeat_dir, "train" + "_meta.pkl") + with open(meta_fn, "rb") as fr: + meta = pickle.load(fr) + elif self.split == "valid": + meta_fn = os.path.join(self.vfeat_dir, "val" + "_meta.pkl") + with open(meta_fn, "rb") as fr: + meta = pickle.load(fr) + elif self.split == "test": + print("use how2 val as test.") + meta_fn = os.path.join(self.vfeat_dir, "val" + "_meta.pkl") + with open(meta_fn, "rb") as fr: + meta = pickle.load(fr) + else: + raise ValueError("unsupported for MetaProcessor:", self.split) + video_id_to_shard = {} + for shard_id in meta: + for video_idx, video_id in enumerate(meta[shard_id]): + video_id_to_shard[video_id] = (shard_id, video_idx) + self.video_id_to_shard = video_id_to_shard + + def __getitem__(self, idx): + video_id, video_id = super().__getitem__(idx) + shard_id, shard_idx = self.video_id_to_shard[video_id] + meta = (video_id, idx, shard_id, shard_idx) + return meta, meta + + +class ShardedVideoProcessor(Processor): + """ + mmaped shards of numpy video features. + """ + + def __init__(self, config): + self.split = str(config.split) + self.vfeat_dir = config.vfeat_dir + + def __call__(self, video_id): + _, _, shard_id, video_idx = video_id + if self.split == "train": + shard = ShardedTensor.load( + os.path.join(self.vfeat_dir, "train" + "_" + str(shard_id)), + "r" + ) + elif self.split == "valid": + shard = ShardedTensor.load( + os.path.join(self.vfeat_dir, "val" + "_" + str(shard_id)), + "r" + ) + elif self.split == "test": + shard = ShardedTensor.load( + os.path.join(self.vfeat_dir, "val" + "_" + str(shard_id)), + "r" + ) + else: + raise ValueError("unknown split", self.split) + feat = shard[video_idx] + return feat + + +class ShardedTextProcessor(Processor): + def __init__(self, config): + self.tfeat_dir = str(config.tfeat_dir) + self.split = str(config.split) + + def __call__(self, video_id): + _, _, shard_id, shard_idx = video_id + if self.split == "train": + target_path = self.tfeat_dir + "train" + "_" + str(shard_id) + elif self.split == "valid": + target_path = self.tfeat_dir + "val" + "_" + str(shard_id) + elif self.split == "test": + target_path = self.tfeat_dir + "val" + "_" + str(shard_id) + else: + raise ValueError("unknown split", self.split) + + startend = ShardedTensor.load( + target_path + ".startends", "r")[shard_idx] + cap_ids = ShardedTensor.load( + target_path + ".caps_ids", "r")[shard_idx] + cap = [] + for clip_idx in range(len(cap_ids)): + clip = cap_ids[clip_idx] + cap.append(clip[clip != -1].tolist()) + start, end = startend[:, 0].tolist(), startend[:, 1].tolist() + return {"start": start, "end": end, "cap": cap} + + +class FixedLenAligner(Aligner): + """ + In the model we assume text is on the left (closer to BERT formulation) + and video is on the right. + We fix the total length of text + video. + max_video_len is in number of secs. + max_text_len is in number of tokens. + + special tokens formats: + we use the format [CLS] [SEP] text tokens [SEP] [PAD] ... + [CLS] will be splitted out into: + [CLS] video tokens [SEP] text tokens [SEP] [PAD] ... + token_type_ids will be generated by the model (for now). + 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 + | first sequence | second sequence | + so each sequence owns a [SEP] token for no-ops. + """ + + def __init__(self, config): + super().__init__(config) + self.text_clip_sampler = TextClipSamplingProcessor( + self.max_len - self.max_video_len - 3 + ) + """ + decide subsampling: + `config.subsampling` will change batch_size in trainer. + `config.clip_per_video` (used by RetriTask) doesn't + change batch_size in trainer. + """ + subsampling = config.subsampling \ + if config.subsampling is not None else None + if config.clip_per_video is not None: + subsampling = config.clip_per_video + self.subsampling = subsampling + + def _get_text_maxlen(self): + # use max text len + return self.text_clip_sampler.max_text_len + + def __call__(self, video_id, video_feature, text_feature): + from transformers import default_data_collator + video_idx = video_id[1] + if self.subsampling is not None and self.subsampling >= 1: + batch = [] + for _ in range(self.subsampling): + centerclip_idx = random.randint( + 0, len(text_feature["start"]) - 1) + batch.append( + self.sampling( + video_idx, + video_feature, + text_feature, + centerclip_idx, + self._get_text_maxlen() + )) + batch = self.batch_post_processing(batch, video_feature) + batch = default_data_collator(batch) + else: + raise ValueError( + "dataset.subsampling must be >= 1 for efficient video loading.") + batch = self.sampling(video_idx, video_feature, text_feature) + batch = self.batch_post_processing(batch, video_feature) + + batch["video_id"] = video_id if isinstance(video_id, str) \ + else video_id[0] + # e2e: make sure frame ids is into tensor. + assert torch.is_tensor(batch["vfeats"]) + return batch + + def sampling( + self, + video_idx, + video_feature, + text_feature, + centerclip_idx=None, + sampled_max_text_len=None, + ): + text_clip_indexs = self.text_clip_sampler( + text_feature, centerclip_idx, + sampled_max_text_len + ) + if isinstance(video_feature, np.ndarray): + video_len = len(video_feature) + else: + video_len = math.ceil(text_feature["end"][-1]) + + video_end = min( + math.ceil(text_feature["end"][text_clip_indexs[-1]]), + video_len + ) + video_start = max( + min( + math.floor(text_feature["start"][text_clip_indexs[0]]), + video_end), + 0 + ) + + video_clips = {"start": [video_start], "end": [video_end]} + + # tensorize. + vfeats, vmasks = self._build_video_seq( + video_feature, video_clips + ) + caps, cmasks = self._build_text_seq( + text_feature, text_clip_indexs + ) + + text_start = text_clip_indexs[0] + text_end = text_clip_indexs[-1] + 1 + + return { + "caps": caps, + "cmasks": cmasks, + "vfeats": vfeats, + "vmasks": vmasks, + "video_start": video_start, + "video_end": video_end, + "text_start": text_start, + "text_end": text_end, + } + + +class VariedLenAligner(FixedLenAligner): + def __init__(self, config): + super().__init__(config) + self.sampled_min_len = config.sampled_min_len + self.sampled_max_len = config.sampled_max_len + + def _get_text_maxlen(self): + return random.randint(self.sampled_min_len, self.sampled_max_len) + + +class StartClipAligner(VariedLenAligner): + def sampling( + self, + video_idx, + video_feature, + text_feature, + centerclip_idx=None, + sampled_max_text_len=None, + ): + return super().sampling( + video_idx, video_feature, text_feature, 0) + + +class OverlappedAligner(VariedLenAligner): + """video clip and text clip has overlappings + but may not be the same start/end.""" + def __init__(self, config): + super().__init__(config) + self.sampled_video_min_len = config.sampled_video_min_len + self.sampled_video_max_len = config.sampled_video_max_len + + self.video_clip_sampler = VideoClipSamplingProcessor() + + def _get_video_maxlen(self): + return random.randint( + self.sampled_video_min_len, self.sampled_video_max_len) + + def sampling( + self, + video_idx, + video_feature, + text_feature, + centerclip_idx=None, + sampled_max_text_len=None, + ): + text_clip_indexs = self.text_clip_sampler( + text_feature, centerclip_idx, + sampled_max_text_len + ) + if isinstance(video_feature, np.ndarray): + video_len = len(video_feature) + else: + video_len = math.ceil(text_feature["end"][-1]) + low = math.floor(text_feature["start"][text_clip_indexs[0]]) + high = math.ceil(text_feature["end"][text_clip_indexs[-1]]) + if low < high: + center = random.randint(low, high) + else: + center = int((low + high) // 2) + center = max(0, min(video_feature.shape[0] - 1, center)) + + assert 0 <= center < video_feature.shape[0] + + video_clips = self.video_clip_sampler( + video_len, self._get_video_maxlen(), center + ) + video_start = video_clips["start"][0] + video_end = video_clips["end"][0] + + # tensorize. + vfeats, vmasks = self._build_video_seq( + video_feature, video_clips + ) + caps, cmasks = self._build_text_seq( + text_feature, text_clip_indexs + ) + + text_start = text_clip_indexs[0] + text_end = text_clip_indexs[-1] + 1 + + return { + "caps": caps, + "cmasks": cmasks, + "vfeats": vfeats, + "vmasks": vmasks, + "video_start": video_start, + "video_end": video_end, + "text_start": text_start, + "text_end": text_end, + } + + +class MFMMLMAligner(FixedLenAligner): + """ + `FixedLenAligner` with Masked Language Model and Masked Frame Model. + """ + + def __init__(self, config): + super().__init__(config) + keep_prob = config.keep_prob if config.keep_prob is not None else 1.0 + self.text_clip_sampler = TextClipSamplingProcessor( + self.max_len - self.max_video_len - 3, keep_prob + ) + self.sampled_min_len = config.sampled_min_len + self.sampled_max_len = config.sampled_max_len + self.masked_token_sampler = TextMaskingProcessor(config) + self.mm_type = config.mm_type \ + if config.mm_type is not None else "full" + self.attnmasker = MMAttentionMask2DProcessor() \ + if self.mm_type == "textgen" else None + self.masked_frame_sampler = FrameMaskingProcessor(config) + self.lazy_vfeat_mask = ( + False if config.lazy_vfeat_mask is None else config.lazy_vfeat_mask + ) + self.mm_prob = config.mm_prob if config.mm_prob is not None else 0. + + def __call__(self, video_id, video_feature, text_feature): + from transformers import default_data_collator + if self.subsampling is not None and self.subsampling > 1: + batch = [] + for _ in range(self.subsampling): + centerclip_idx = random.randint( + 0, len(text_feature["start"]) - 1) + sampled_max_text_len = random.randint( + self.sampled_min_len, self.sampled_max_len + ) + batch.append( + self.sampling( + video_id, + video_feature, + text_feature, + centerclip_idx, + sampled_max_text_len, + ) + ) + batch = self.batch_post_processing(batch, video_feature) + batch = default_data_collator(batch) + else: + batch = self.sampling(video_id, video_feature, text_feature) + batch = self.batch_post_processing(batch, video_feature) + batch["video_id"] = video_id if isinstance(video_id, str) \ + else video_id[0] + return batch + + def sampling( + self, + video_id, + video_feature, + text_feature, + centerclip_idx=None, + sampled_max_text_len=None, + ): + output = FixedLenAligner.sampling(self, + video_id, video_feature, text_feature, + centerclip_idx, sampled_max_text_len) + + masking_text, masking_video = None, None + if random.random() < self.mm_prob: + if random.random() > 0.5: + masking_text, masking_video = self.mm_type, "no" + else: + masking_text, masking_video = "no", "full" + video_feats = output["vfeats"] if not self.lazy_vfeat_mask else None + video_label = self.masked_frame_sampler( + output["vmasks"], masking_video, vfeats=video_feats) + caps, text_label = self.masked_token_sampler( + output["caps"], masking_text) + + output.update({ + "caps": caps, + "video_label": video_label, + "text_label": text_label, + }) + + if self.attnmasker is not None: + attention_mask = self.attnmasker( + output["vmasks"], output["cmasks"], masking_text) + output.update({ + "attention_mask": attention_mask + }) + return output + + +class FrameMaskingProcessor(Processor): + def __init__(self, config): + self.mfm_probability = 0.15 + if config.mfm_probability is not None: + self.mfm_probability = config.mfm_probability + + def __call__(self, vmasks, modality_masking=None, vfeats=None): + """ + We perform lazy masking to save data transfer time. + It only generates video_labels by default and MFM model + will do actualy masking. + Return: `video_label` is a binary mask. + """ + video_label = vmasks.clone() + if modality_masking is not None: + if modality_masking == "full": + probability_matrix = torch.full(video_label.shape, 1.) + elif modality_masking == "no": + probability_matrix = torch.full(video_label.shape, 0.) + elif modality_masking == "inverse": + probability_matrix = torch.full( + video_label.shape, 1. - self.mfm_probability) + else: + raise ValueError("unknown modality masking.", modality_masking) + else: + probability_matrix = torch.full( + video_label.shape, self.mfm_probability) + masked_indices = torch.bernoulli(probability_matrix).bool() + # We only compute loss on masked tokens + video_label[~masked_indices] = 0 + if vfeats is not None: + vfeats[video_label, :] = 0.0 + return video_label + + +class TextGenerationProcessor(Processor): + def __init__(self, tokenizer): + self.bos_token_id = tokenizer.bos_token_id + self.pad_token_id = tokenizer.pad_token_id + + def __call__(self, inputs): + labels = inputs.clone() + # [CLS] [SEP] for video + labels[:2] = -100 + # keep [SEP] for text. + pad_mask = labels == self.pad_token_id + labels[pad_mask] = -100 + inputs[2:] = torch.cat([ + torch.LongTensor([self.bos_token_id]), + inputs[2:-1]]) + inputs[pad_mask] = self.pad_token_id + assert len(inputs) == len(labels) + return inputs, labels + + +class TextMaskingProcessor(Processor): + def __init__(self, config): + """this function is borrowed from + `transformers/data/data_collator.DataCollatorForLanguageModeling`""" + self.mlm_probability = 0.15 + if config.mlm_probability is not None: + self.mlm_probability = config.mlm_probability + self.bert_name = config.bert_name + # [CLS] is used as bos_token and [SEP] is used as eos_token. + # https://huggingface.co/transformers/master/model_doc/bertgeneration.html + from transformers import AutoTokenizer + self.tokenizer = AutoTokenizer.from_pretrained( + self.bert_name, bos_token="[CLS]", eos_token="[SEP]") + self.textgen = TextGenerationProcessor(self.tokenizer) + + def __call__( + self, inputs: torch.Tensor, + modality_masking=None, + special_tokens_mask: Optional[torch.Tensor] = None + ) -> Tuple[torch.Tensor, torch.Tensor]: + """ + expand modality_masking into + None: traditional bert masking. + "no": no masking. + "full": all [MASK] token for generation. + "gen": autoregressive generation. + """ + """ + Prepare masked tokens inputs/labels for masked language modeling: + 80% MASK, 10% random, 10% original. + """ + labels = inputs.clone() + # We sample a few tokens in each sequence for MLM training + # (with probability `self.mlm_probability`) + if modality_masking is not None: + if modality_masking == "full": + probability_matrix = torch.full(labels.shape, 1.) + elif modality_masking == "no": + probability_matrix = torch.full(labels.shape, 0.) + elif modality_masking.startswith("textgen"): + # [CLS] [SEP] <s> ... + inputs, labels = self.textgen(inputs) + if "mask" not in modality_masking: + return inputs, labels + inputs = self.mask_input(inputs, special_tokens_mask) + return inputs, labels + elif modality_masking == "mask": + inputs = self.mask_input(inputs, special_tokens_mask) + labels = torch.full(inputs.shape, -100) + return inputs, labels + elif modality_masking == "inverse": + probability_matrix = torch.full(labels.shape, 1. - self.mlm_probability) + else: + raise ValueError("unknown modality masking.", modality_masking) + else: + probability_matrix = torch.full(labels.shape, self.mlm_probability) + + if special_tokens_mask is None: + special_tokens_mask = self.get_special_tokens_mask( + labels.tolist(), already_has_special_tokens=True + ) + special_tokens_mask = torch.tensor( + special_tokens_mask, dtype=torch.bool) + else: + special_tokens_mask = special_tokens_mask.bool() + + probability_matrix.masked_fill_(special_tokens_mask, value=0.0) + masked_indices = torch.bernoulli(probability_matrix).bool() + labels[~masked_indices] = -100 # We only compute loss on masked tokens + + # 80% of the time, + # we replace masked input tokens with tokenizer.mask_token ([MASK]) + indices_replaced = ( + torch.bernoulli( + torch.full(labels.shape, 0.8)).bool() & masked_indices + ) + inputs[indices_replaced] = self.tokenizer.convert_tokens_to_ids( + self.tokenizer.mask_token + ) + + # 10% of the time, we replace masked input tokens with random word + indices_random = ( + torch.bernoulli(torch.full(labels.shape, 0.5)).bool() + & masked_indices + & ~indices_replaced + ) + random_words = torch.randint( + len(self.tokenizer), labels.shape, dtype=torch.long + ) + inputs[indices_random] = random_words[indices_random] + + # The rest of the time (10% of the time) we keep the masked input + # tokens unchanged + return inputs, labels + + def mask_input(self, inputs, special_tokens_mask=None): + # the following is new with masked autoregressive. + probability_matrix = torch.full( + inputs.shape, self.mlm_probability) + if special_tokens_mask is None: + special_tokens_mask = self.get_special_tokens_mask( + inputs.tolist(), already_has_special_tokens=True + ) + special_tokens_mask = torch.tensor( + special_tokens_mask, dtype=torch.bool) + else: + special_tokens_mask = special_tokens_mask.bool() + probability_matrix.masked_fill_(special_tokens_mask, value=0.0) + masked_indices = torch.bernoulli(probability_matrix).bool() + indices_replaced = ( + torch.bernoulli( + torch.full(inputs.shape, 0.8)).bool() & masked_indices + ) + inputs[indices_replaced] = self.tokenizer.convert_tokens_to_ids( + self.tokenizer.mask_token + ) + + # 10% of the time, we replace masked input tokens with random word + indices_random = ( + torch.bernoulli(torch.full(inputs.shape, 0.5)).bool() + & masked_indices + & ~indices_replaced + ) + random_words = torch.randint( + len(self.tokenizer), inputs.shape, dtype=torch.long + ) + inputs[indices_random] = random_words[indices_random] + return inputs + + def get_special_tokens_mask( + self, token_ids_0: List[int], + token_ids_1: Optional[List[int]] = None, + already_has_special_tokens: bool = False + ) -> List[int]: + """ + Note: the version from transformers do not consider pad + as special tokens. + """ + + if already_has_special_tokens: + if token_ids_1 is not None: + raise ValueError( + "You should not supply a second sequence if" + "the provided sequence of " + "ids is already formated with special tokens " + "for the model." + ) + return list(map(lambda x: 1 if x in [ + self.tokenizer.sep_token_id, + self.tokenizer.cls_token_id, + self.tokenizer.pad_token_id] else 0, token_ids_0)) + + if token_ids_1 is not None: + return [1] + ([0] * len(token_ids_0)) + [1] + ([0] * len(token_ids_1)) + [1] + return [1] + ([0] * len(token_ids_0)) + [1] + + +class TextClipSamplingProcessor(Processor): + def __init__(self, max_text_len, keep_prob=1.0): + self.max_text_len = max_text_len + self.max_video_len = 256 # always hold. + self.keep_prob = keep_prob + + def __call__( + self, + text_feature, + centerclip_idx=None, + sampled_max_text_len=None, + sampled_max_video_len=None, + ): + # Let's use all caps for now and see if 256 can cover all of them. + if sampled_max_text_len is not None: + max_text_len = sampled_max_text_len + else: + max_text_len = self.max_text_len + if sampled_max_video_len is not None: + max_video_len = sampled_max_video_len + else: + max_video_len = self.max_video_len + + t_num_clips = len(text_feature["start"]) + + if centerclip_idx is None: + centerclip_idx = random.randint(0, t_num_clips - 1) + + start_idx, end_idx = centerclip_idx, centerclip_idx + 1 + text_clip_indexs = deque() + text_clip_indexs.append(start_idx) + text_len = len(text_feature["cap"][start_idx]) + + video_len = max( + 0, + text_feature["end"][start_idx] + - text_feature["start"][start_idx], + ) + + while ( + (start_idx > 0 or end_idx < t_num_clips) + and text_len < max_text_len + and video_len < max_video_len + ): + if random.random() > 0.5 and end_idx < t_num_clips: + # skip the next one? + if random.random() > self.keep_prob and (end_idx + 1) < t_num_clips: + end_idx = end_idx + 1 + text_clip_indexs.append(end_idx) + text_len += len(text_feature["cap"][end_idx]) + end_idx += 1 + elif start_idx > 0: + if random.random() > self.keep_prob and (start_idx - 1) > 0: + start_idx = start_idx - 1 + start_idx -= 1 + text_clip_indexs.insert(0, start_idx) + text_len += len(text_feature["cap"][start_idx]) + else: + if end_idx < t_num_clips: + if random.random() > self.keep_prob and (end_idx + 1) < t_num_clips: + end_idx = end_idx + 1 + text_clip_indexs.append(end_idx) + text_len += len(text_feature["cap"][end_idx]) + end_idx += 1 + else: + return text_clip_indexs + video_len = max( + 0, + text_feature["end"][text_clip_indexs[-1]] + - text_feature["start"][text_clip_indexs[0]], + ) + return text_clip_indexs + + +class VideoClipSamplingProcessor(Processor): + def __call__(self, video_len, max_video_len, center): + """ + `video_len`: length of the video. + `max_video_len`: maximum video tokens allowd in a sequence. + `center`: initial starting index. + """ + assert center >= 0 and center < video_len + t_clip_len = 0 + start, end = center, center + while (start > 0 or end < video_len) and t_clip_len < max_video_len: + # decide the direction to grow. + if start <= 0: + end += 1 + elif end >= video_len: + start -= 1 + elif random.random() > 0.5: + end += 1 + else: + start -= 1 + t_clip_len += 1 + return {"start": [start], "end": [end]} + + +class How2MILNCEAligner(FixedLenAligner): + """reference: `antoine77340/MIL-NCE_HowTo100M/video_loader.py`""" + + def __init__(self, config): + super().__init__(config) + self.num_candidates = 4 + self.min_time = 5.0 + self.num_sec = 3.2 + # self.num_sec = self.num_frames / float(self.fps) num_frames=16 / fps = 5 + # self.num_frames = 16 + + def sampling( + self, + video_id, + video_feature, + text_feature, + centerclip_idx=None, # will be ignored. + sampled_max_text_len=None # will be ignored. + ): + text, start, end = self._get_text(text_feature) + video = self._get_video(video_feature, start, end) + + vfeats = torch.zeros((self.max_video_len, video_feature.shape[1])) + vmasks = torch.zeros((self.max_video_len,), dtype=torch.bool) + vfeats[: video.shape[0]] = torch.from_numpy(np.array(video)) + vmasks[: video.shape[0]] = 1 + + caps, cmasks = [], [] + for words in text: + cap, cmask = self._build_text_seq(text_feature, words) + caps.append(cap) + cmasks.append(cmask) + caps = torch.stack(caps) + cmasks = torch.stack(cmasks) + # video of shape: (video_len) + # text of shape (num_candidates, max_text_len) + + return { + "caps": caps, + "cmasks": cmasks, + "vfeats": vfeats, + "vmasks": vmasks, + # "video_id": video_id, + } + + def _get_video(self, video_feature, start, end): + start_seek = random.randint(start, int(max(start, end - self.num_sec))) + # duration = self.num_sec + 0.1 + return video_feature[start_seek : int(start_seek + self.num_sec)] + + def _get_text(self, cap): + ind = random.randint(0, len(cap["start"]) - 1) + if self.num_candidates == 1: + words = [ind] + else: + words = [] + cap_start = self._find_nearest_candidates(cap, ind) + for i in range(self.num_candidates): + words.append([max(0, min(len(cap["cap"]) - 1, cap_start + i))]) + + start, end = cap["start"][ind], cap["end"][ind] + # TODO: May need to be improved for edge cases. + # expand the min time. + if end - start < self.min_time: + diff = self.min_time - end + start + start = max(0, start - diff / 2) + end = start + self.min_time + return words, int(start), int(end) + + def _find_nearest_candidates(self, caption, ind): + """find the range of the clips.""" + start, end = ind, ind + #diff = caption["end"][end] - caption["start"][start] + n_candidate = 1 + while n_candidate < self.num_candidates: + # the first clip + if start == 0: + return 0 + # we add () in the following condition to fix the bug. + elif end == (len(caption["start"]) - 1): + return start - (self.num_candidates - n_candidate) + elif (caption["end"][end] - caption["start"][start - 1]) < ( + caption["end"][end + 1] - caption["start"][start] + ): + start -= 1 + else: + end += 1 + n_candidate += 1 + return start + + +class PKLJSONStrTextProcessor(TextProcessor): + """`caption.json` from howto100m are preprocessed as a + dict `[video_id, json_str]`. + Json parsing tokenization are conducted on-the-fly and cached into dict. + """ + + def __init__(self, config, max_clip_text_len=96): + print("[Warning] PKLJSONStrTextProcessor is slow for num_workers > 0.") + self.caption_pkl_path = str(config.caption_pkl_path) + with open(self.caption_pkl_path, "rb") as fd: + self.data = pickle.load(fd) + self.max_clip_text_len = max_clip_text_len + from transformers import AutoTokenizer + self.tokenizer = AutoTokenizer.from_pretrained( + str(config.bert_name), use_fast=config.use_fast + ) + + def __call__(self, video_id): + caption = self.data[video_id] + if isinstance(caption, str): + import json + caption = json.loads(caption) + cap = [] + for clip_idx, text_clip in enumerate(caption["text"]): + clip_ids = [] + if isinstance(text_clip, str): + clip_ids = self.tokenizer( + text_clip[: self.max_clip_text_len], + add_special_tokens=False + )["input_ids"] + cap.append(clip_ids) + caption["cap"] = cap + caption.pop("text") # save space. + self.data[video_id] = caption + return caption diff --git a/examples/MMPT/mmpt/processors/how2retriprocessor.py b/examples/MMPT/mmpt/processors/how2retriprocessor.py new file mode 100644 index 0000000000..b5a7730ec0 --- /dev/null +++ b/examples/MMPT/mmpt/processors/how2retriprocessor.py @@ -0,0 +1,100 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .how2processor import ( + ShardedHow2MetaProcessor, + ShardedVideoProcessor, + ShardedTextProcessor, + VariedLenAligner, + OverlappedAligner +) + + +class ShardedHow2VideoRetriMetaProcessor(ShardedHow2MetaProcessor): + def __init__(self, config): + super().__init__(config) + self.num_video_per_batch = config.num_video_per_batch + self.cands = [ + self.data[batch_offset:batch_offset + self.num_video_per_batch] + for batch_offset in + range(0, (len(self.data) // (8 * self.num_video_per_batch)) * 8 * self.num_video_per_batch, self.num_video_per_batch)] + + def __len__(self): + return len(self.cands) + + def set_candidates(self, cands): + # no changes on num of batches. + print(len(self.cands), "->", len(cands)) + # assert len(self.cands) == len(cands) + self.cands = cands + + def __getitem__(self, idx): + video_ids = self.cands[idx] + assert isinstance(video_ids, list) + sharded_video_idxs = [] + for video_id in video_ids: + shard_id, video_idx = self.video_id_to_shard[video_id] + sharded_video_idxs.append((video_id, -1, shard_id, video_idx)) + return sharded_video_idxs, sharded_video_idxs + + +class ShardedVideoRetriVideoProcessor(ShardedVideoProcessor): + """In retrival case the video_id + is a list of tuples: `(shard_id, video_idx)` .""" + + def __call__(self, sharded_video_idxs): + assert isinstance(sharded_video_idxs, list) + cand_feats = [] + for shared_video_idx in sharded_video_idxs: + feat = super().__call__(shared_video_idx) + cand_feats.append(feat) + return cand_feats + + +class ShardedVideoRetriTextProcessor(ShardedTextProcessor): + """In retrival case the video_id + is a list of tuples: `(shard_id, video_idx)` .""" + + def __call__(self, sharded_video_idxs): + assert isinstance(sharded_video_idxs, list) + cand_caps = [] + for shared_video_idx in sharded_video_idxs: + caps = super().__call__(shared_video_idx) + cand_caps.append(caps) + return cand_caps + + +class VideoRetriAligner(VariedLenAligner): + # Retritask will trim dim-0. + def __call__(self, sharded_video_idxs, video_features, text_features): + from transformers import default_data_collator + batch, video_ids = [], [] + for video_id, video_feature, text_feature in \ + zip(sharded_video_idxs, video_features, text_features): + sub_batch = super().__call__(video_id, video_feature, text_feature) + batch.append(sub_batch) + if isinstance(video_id, tuple): + video_id = video_id[0] + video_ids.append(video_id) + batch = default_data_collator(batch) + batch["video_id"] = video_ids + return batch + + +class VideoRetriOverlappedAligner(OverlappedAligner): + # Retritask will trim dim-0. + def __call__(self, sharded_video_idxs, video_features, text_features): + from transformers import default_data_collator + batch, video_ids = [], [] + for video_id, video_feature, text_feature in \ + zip(sharded_video_idxs, video_features, text_features): + sub_batch = super().__call__(video_id, video_feature, text_feature) + batch.append(sub_batch) + if isinstance(video_id, tuple): + video_id = video_id[0] + video_ids.append(video_id) + batch = default_data_collator(batch) + batch["video_id"] = video_ids + return batch diff --git a/examples/MMPT/mmpt/processors/models/s3dg.py b/examples/MMPT/mmpt/processors/models/s3dg.py new file mode 100644 index 0000000000..6c7a691e33 --- /dev/null +++ b/examples/MMPT/mmpt/processors/models/s3dg.py @@ -0,0 +1,336 @@ +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +"""Contains a PyTorch definition for Gated Separable 3D network (S3D-G) +with a text module for computing joint text-video embedding from raw text +and video input. The following code will enable you to load the HowTo100M +pretrained S3D Text-Video model from: + A. Miech, J.-B. Alayrac, L. Smaira, I. Laptev, J. Sivic and A. Zisserman, + End-to-End Learning of Visual Representations from Uncurated Instructional Videos. + https://arxiv.org/abs/1912.06430. + +S3D-G was proposed by: + S. Xie, C. Sun, J. Huang, Z. Tu and K. Murphy, + Rethinking Spatiotemporal Feature Learning For Video Understanding. + https://arxiv.org/abs/1712.04851. + Tensorflow code: https://github.com/tensorflow/models/blob/master/research/slim/nets/s3dg.py + +The S3D architecture was slightly modified with a space to depth trick for TPU +optimization. +""" + +import torch as th +import torch.nn.functional as F +import torch.nn as nn +import os +import numpy as np +import re + + +class InceptionBlock(nn.Module): + def __init__( + self, + input_dim, + num_outputs_0_0a, + num_outputs_1_0a, + num_outputs_1_0b, + num_outputs_2_0a, + num_outputs_2_0b, + num_outputs_3_0b, + gating=True, + ): + super(InceptionBlock, self).__init__() + self.conv_b0 = STConv3D(input_dim, num_outputs_0_0a, [1, 1, 1]) + self.conv_b1_a = STConv3D(input_dim, num_outputs_1_0a, [1, 1, 1]) + self.conv_b1_b = STConv3D( + num_outputs_1_0a, num_outputs_1_0b, [3, 3, 3], padding=1, separable=True + ) + self.conv_b2_a = STConv3D(input_dim, num_outputs_2_0a, [1, 1, 1]) + self.conv_b2_b = STConv3D( + num_outputs_2_0a, num_outputs_2_0b, [3, 3, 3], padding=1, separable=True + ) + self.maxpool_b3 = th.nn.MaxPool3d((3, 3, 3), stride=1, padding=1) + self.conv_b3_b = STConv3D(input_dim, num_outputs_3_0b, [1, 1, 1]) + self.gating = gating + self.output_dim = ( + num_outputs_0_0a + num_outputs_1_0b + num_outputs_2_0b + num_outputs_3_0b + ) + if gating: + self.gating_b0 = SelfGating(num_outputs_0_0a) + self.gating_b1 = SelfGating(num_outputs_1_0b) + self.gating_b2 = SelfGating(num_outputs_2_0b) + self.gating_b3 = SelfGating(num_outputs_3_0b) + + def forward(self, input): + """Inception block + """ + b0 = self.conv_b0(input) + b1 = self.conv_b1_a(input) + b1 = self.conv_b1_b(b1) + b2 = self.conv_b2_a(input) + b2 = self.conv_b2_b(b2) + b3 = self.maxpool_b3(input) + b3 = self.conv_b3_b(b3) + if self.gating: + b0 = self.gating_b0(b0) + b1 = self.gating_b1(b1) + b2 = self.gating_b2(b2) + b3 = self.gating_b3(b3) + return th.cat((b0, b1, b2, b3), dim=1) + + +class SelfGating(nn.Module): + def __init__(self, input_dim): + super(SelfGating, self).__init__() + self.fc = nn.Linear(input_dim, input_dim) + + def forward(self, input_tensor): + """Feature gating as used in S3D-G. + """ + spatiotemporal_average = th.mean(input_tensor, dim=[2, 3, 4]) + weights = self.fc(spatiotemporal_average) + weights = th.sigmoid(weights) + return weights[:, :, None, None, None] * input_tensor + + +class STConv3D(nn.Module): + def __init__( + self, input_dim, output_dim, kernel_size, stride=1, padding=0, separable=False + ): + super(STConv3D, self).__init__() + self.separable = separable + self.relu = nn.ReLU(inplace=True) + assert len(kernel_size) == 3 + if separable and kernel_size[0] != 1: + spatial_kernel_size = [1, kernel_size[1], kernel_size[2]] + temporal_kernel_size = [kernel_size[0], 1, 1] + if isinstance(stride, list) and len(stride) == 3: + spatial_stride = [1, stride[1], stride[2]] + temporal_stride = [stride[0], 1, 1] + else: + spatial_stride = [1, stride, stride] + temporal_stride = [stride, 1, 1] + if isinstance(padding, list) and len(padding) == 3: + spatial_padding = [0, padding[1], padding[2]] + temporal_padding = [padding[0], 0, 0] + else: + spatial_padding = [0, padding, padding] + temporal_padding = [padding, 0, 0] + if separable: + self.conv1 = nn.Conv3d( + input_dim, + output_dim, + kernel_size=spatial_kernel_size, + stride=spatial_stride, + padding=spatial_padding, + bias=False, + ) + self.bn1 = nn.BatchNorm3d(output_dim) + self.conv2 = nn.Conv3d( + output_dim, + output_dim, + kernel_size=temporal_kernel_size, + stride=temporal_stride, + padding=temporal_padding, + bias=False, + ) + self.bn2 = nn.BatchNorm3d(output_dim) + else: + self.conv1 = nn.Conv3d( + input_dim, + output_dim, + kernel_size=kernel_size, + stride=stride, + padding=padding, + bias=False, + ) + self.bn1 = nn.BatchNorm3d(output_dim) + + def forward(self, input): + out = self.relu(self.bn1(self.conv1(input))) + if self.separable: + out = self.relu(self.bn2(self.conv2(out))) + return out + + +class MaxPool3dTFPadding(th.nn.Module): + def __init__(self, kernel_size, stride=None, padding="SAME"): + super(MaxPool3dTFPadding, self).__init__() + if padding == "SAME": + padding_shape = self._get_padding_shape(kernel_size, stride) + self.padding_shape = padding_shape + self.pad = th.nn.ConstantPad3d(padding_shape, 0) + self.pool = th.nn.MaxPool3d(kernel_size, stride, ceil_mode=True) + + def _get_padding_shape(self, filter_shape, stride): + def _pad_top_bottom(filter_dim, stride_val): + pad_along = max(filter_dim - stride_val, 0) + pad_top = pad_along // 2 + pad_bottom = pad_along - pad_top + return pad_top, pad_bottom + + padding_shape = [] + for filter_dim, stride_val in zip(filter_shape, stride): + pad_top, pad_bottom = _pad_top_bottom(filter_dim, stride_val) + padding_shape.append(pad_top) + padding_shape.append(pad_bottom) + depth_top = padding_shape.pop(0) + depth_bottom = padding_shape.pop(0) + padding_shape.append(depth_top) + padding_shape.append(depth_bottom) + return tuple(padding_shape) + + def forward(self, inp): + inp = self.pad(inp) + out = self.pool(inp) + return out + + +class Sentence_Embedding(nn.Module): + def __init__( + self, + embd_dim, + num_embeddings=66250, + word_embedding_dim=300, + token_to_word_path="dict.npy", + max_words=16, + output_dim=2048, + ): + super(Sentence_Embedding, self).__init__() + self.word_embd = nn.Embedding(num_embeddings, word_embedding_dim) + self.fc1 = nn.Linear(word_embedding_dim, output_dim) + self.fc2 = nn.Linear(output_dim, embd_dim) + self.word_to_token = {} + self.max_words = max_words + token_to_word = np.load(token_to_word_path) + for i, t in enumerate(token_to_word): + self.word_to_token[t] = i + 1 + + def _zero_pad_tensor_token(self, tensor, size): + if len(tensor) >= size: + return tensor[:size] + else: + zero = th.zeros(size - len(tensor)).long() + return th.cat((tensor, zero), dim=0) + + def _split_text(self, sentence): + w = re.findall(r"[\w']+", str(sentence)) + return w + + def _words_to_token(self, words): + words = [ + self.word_to_token[word] for word in words if word in self.word_to_token + ] + if words: + we = self._zero_pad_tensor_token(th.LongTensor(words), self.max_words) + return we + else: + return th.zeros(self.max_words).long() + + def _words_to_ids(self, x): + split_x = [self._words_to_token(self._split_text(sent.lower())) for sent in x] + return th.stack(split_x, dim=0) + + def forward(self, x): + x = self._words_to_ids(x) + x = self.word_embd(x) + x = F.relu(self.fc1(x)) + x = th.max(x, dim=1)[0] + x = self.fc2(x) + return {'text_embedding': x} + + +class S3D(nn.Module): + def __init__(self, dict_path, num_classes=512, gating=True, space_to_depth=True): + super(S3D, self).__init__() + self.num_classes = num_classes + self.gating = gating + self.space_to_depth = space_to_depth + if space_to_depth: + self.conv1 = STConv3D( + 24, 64, [2, 4, 4], stride=1, padding=(1, 2, 2), separable=False + ) + else: + self.conv1 = STConv3D( + 3, 64, [3, 7, 7], stride=2, padding=(1, 3, 3), separable=False + ) + self.conv_2b = STConv3D(64, 64, [1, 1, 1], separable=False) + self.conv_2c = STConv3D(64, 192, [3, 3, 3], padding=1, separable=True) + self.gating = SelfGating(192) + self.maxpool_2a = MaxPool3dTFPadding( + kernel_size=(1, 3, 3), stride=(1, 2, 2), padding="SAME" + ) + self.maxpool_3a = MaxPool3dTFPadding( + kernel_size=(1, 3, 3), stride=(1, 2, 2), padding="SAME" + ) + self.mixed_3b = InceptionBlock(192, 64, 96, 128, 16, 32, 32) + self.mixed_3c = InceptionBlock( + self.mixed_3b.output_dim, 128, 128, 192, 32, 96, 64 + ) + self.maxpool_4a = MaxPool3dTFPadding( + kernel_size=(3, 3, 3), stride=(2, 2, 2), padding="SAME" + ) + self.mixed_4b = InceptionBlock( + self.mixed_3c.output_dim, 192, 96, 208, 16, 48, 64 + ) + self.mixed_4c = InceptionBlock( + self.mixed_4b.output_dim, 160, 112, 224, 24, 64, 64 + ) + self.mixed_4d = InceptionBlock( + self.mixed_4c.output_dim, 128, 128, 256, 24, 64, 64 + ) + self.mixed_4e = InceptionBlock( + self.mixed_4d.output_dim, 112, 144, 288, 32, 64, 64 + ) + self.mixed_4f = InceptionBlock( + self.mixed_4e.output_dim, 256, 160, 320, 32, 128, 128 + ) + self.maxpool_5a = self.maxPool3d_5a_2x2 = MaxPool3dTFPadding( + kernel_size=(2, 2, 2), stride=(2, 2, 2), padding="SAME" + ) + self.mixed_5b = InceptionBlock( + self.mixed_4f.output_dim, 256, 160, 320, 32, 128, 128 + ) + self.mixed_5c = InceptionBlock( + self.mixed_5b.output_dim, 384, 192, 384, 48, 128, 128 + ) + self.fc = nn.Linear(self.mixed_5c.output_dim, num_classes) + self.text_module = Sentence_Embedding(num_classes, + token_to_word_path=dict_path) + + def _space_to_depth(self, input): + """3D space to depth trick for TPU optimization. + """ + B, C, T, H, W = input.shape + input = input.view(B, C, T // 2, 2, H // 2, 2, W // 2, 2) + input = input.permute(0, 3, 5, 7, 1, 2, 4, 6) + input = input.contiguous().view(B, 8 * C, T // 2, H // 2, W // 2) + return input + + def forward(self, inputs): + """Defines the S3DG base architecture.""" + if self.space_to_depth: + inputs = self._space_to_depth(inputs) + net = self.conv1(inputs) + if self.space_to_depth: + # we need to replicate 'SAME' tensorflow padding + net = net[:, :, 1:, 1:, 1:] + net = self.maxpool_2a(net) + net = self.conv_2b(net) + net = self.conv_2c(net) + if self.gating: + net = self.gating(net) + net = self.maxpool_3a(net) + net = self.mixed_3b(net) + net = self.mixed_3c(net) + net = self.maxpool_4a(net) + net = self.mixed_4b(net) + net = self.mixed_4c(net) + net = self.mixed_4d(net) + net = self.mixed_4e(net) + net = self.mixed_4f(net) + net = self.maxpool_5a(net) + net = self.mixed_5b(net) + net = self.mixed_5c(net) + net = th.mean(net, dim=[2, 3, 4]) + return {'video_embedding': self.fc(net), 'mixed_5c': net} diff --git a/examples/MMPT/mmpt/processors/processor.py b/examples/MMPT/mmpt/processors/processor.py new file mode 100644 index 0000000000..98edb051f1 --- /dev/null +++ b/examples/MMPT/mmpt/processors/processor.py @@ -0,0 +1,274 @@ +# Copyright (c) Facebook, Inc. All Rights Reserved + +import numpy as np +import os +import torch + + +class Processor(object): + """ + A generic processor for video (codec, feature etc.) and text. + """ + + def __call__(self, **kwargs): + raise NotImplementedError + + +class MetaProcessor(Processor): + """ + A meta processor is expected to load the metadata of a dataset: + (e.g., video_ids, or captions). + You must implement the `__getitem__` (meta datasets are rather diverse.). + """ + + def __init__(self, config): + self.split = config.split + + def __len__(self): + return len(self.data) + + def __getitem__(self, idx): + raise NotImplementedError + + def _get_split_path(self, config): + splits = { + "train": config.train_path, + "valid": config.val_path, + "test": config.test_path, + } + if config.split is not None: + return splits[config.split] + return config.train_path + + +class TextProcessor(Processor): + """ + A generic Text processor: rename this as `withTokenizer`. + tokenize a string of text on-the-fly. + Warning: mostly used for end tasks. + (on-the-fly tokenization is slow for how2.) + TODO(huxu): move this class as a subclass. + """ + + def __init__(self, config): + self.bert_name = str(config.bert_name) + self.use_fast = config.use_fast + from transformers import AutoTokenizer + self.tokenizer = AutoTokenizer.from_pretrained( + self.bert_name, use_fast=self.use_fast + ) + + def __call__(self, text_id): + caption = self.tokenizer(text_id, add_special_tokens=False) + return caption["input_ids"] + + +class VideoProcessor(Processor): + """ + A generic video processor: load a numpy video tokens by default. + """ + + def __init__(self, config): + self.vfeat_dir = config.vfeat_dir + + def __call__(self, video_fn): + if isinstance(video_fn, tuple): + video_fn = video_fn[0] + assert isinstance(video_fn, str) + video_fn = os.path.join(self.vfeat_dir, video_fn + ".npy") + feat = np.load(video_fn) + return feat + + +class Aligner(object): + """ + An alignprocessor align video and text and output a dict of tensors (for a model). + """ + def __init__(self, config): + """__init__ needs to be light weight for more workers/threads.""" + self.split = config.split + self.max_video_len = config.max_video_len + self.max_len = config.max_len + from transformers import AutoTokenizer + tokenizer = AutoTokenizer.from_pretrained( + str(config.bert_name), use_fast=config.use_fast + ) + self.cls_token_id = tokenizer.cls_token_id + self.sep_token_id = tokenizer.sep_token_id + self.pad_token_id = tokenizer.pad_token_id + self.mask_token_id = tokenizer.mask_token_id + + def __call__(self, video_id, video_feature, text_feature): + raise NotImplementedError + + def _build_video_seq(self, video_feature, video_clips=None): + """ + `video_feature`: available video tokens. + `video_clips`: video clip sequence to build. + """ + if not isinstance(video_feature, np.ndarray): + raise ValueError( + "unsupported type of video_feature", type(video_feature) + ) + + if video_clips is None: + # this is borrowed from DSAligner + video_start = 0 + video_end = min(len(video_feature), self.max_video_len) + # the whole sequence is a single clip. + video_clips = {"start": [video_start], "end": [video_end]} + + vfeats = np.zeros( + (self.max_video_len, video_feature.shape[1]), dtype=np.float32 + ) + vmasks = torch.zeros((self.max_video_len,), dtype=torch.bool) + video_len = 0 + for start, end in zip(video_clips["start"], video_clips["end"]): + clip_len = min(self.max_video_len - video_len, (end - start)) + if clip_len > 0: + vfeats[video_len: video_len + clip_len] = video_feature[ + start: start + clip_len + ] + vmasks[video_len: video_len + clip_len] = 1 + video_len += clip_len + vfeats = torch.from_numpy(vfeats) + + return vfeats, vmasks + + def _build_text_seq(self, text_feature, text_clip_indexs=None): + """ + `text_feature`: all available clips. + `text_clip_indexes`: clip sequence to build. + """ + if text_clip_indexs is None: + text_clip_indexs = [0] + + full_caps = [] + if isinstance(text_feature, dict): + for clip_idx in text_clip_indexs: + full_caps.extend(text_feature["cap"][clip_idx]) + else: + full_caps = text_feature + max_text_len = self.max_len - self.max_video_len - 3 + full_caps = full_caps[:max_text_len] + full_caps = ( + [self.cls_token_id, self.sep_token_id] + full_caps + [self.sep_token_id] + ) + text_pad_len = self.max_len - len(full_caps) - self.max_video_len + padded_full_caps = full_caps + [self.pad_token_id] * text_pad_len + caps = torch.LongTensor(padded_full_caps) + cmasks = torch.zeros((len(padded_full_caps),), dtype=torch.bool) + cmasks[: len(full_caps)] = 1 + + return caps, cmasks + + def batch_post_processing(self, batch, video_feature): + return batch + + +class MMAttentionMask2DProcessor(Processor): + """text generation requires 2d mask + that is harder to generate by GPU at this stage.""" + + def __call__(self, vmask, cmask, mtype): + if mtype == "textgen": + return self._build_textgeneration_mask(vmask, cmask) + elif mtype == "videogen": + return self._build_videogeneration_mask(vmask, cmask) + else: + return self._build_mm_mask(vmask, cmask) + + def _build_mm_mask(self, vmask, cmask): + mask_1d = torch.cat([cmask[:1], vmask, cmask[1:]], dim=0) + return mask_1d[None, :].repeat(mask_1d.size(0), 1) + + def _build_videogeneration_mask(self, vmask, cmask): + # cls_mask is only about text otherwise it will leak generation. + cls_text_mask = torch.cat([ + # [CLS] + torch.ones( + (1,), dtype=torch.bool, device=cmask.device), + # video tokens and [SEP] for video. + torch.zeros( + (vmask.size(0) + 1,), dtype=torch.bool, device=cmask.device), + cmask[2:] + ], dim=0) + + # concat horizontially. + video_len = int(vmask.sum()) + video_masks = torch.cat([ + # [CLS] + torch.ones( + (video_len, 1), dtype=torch.bool, device=cmask.device + ), + torch.tril( + torch.ones( + (video_len, video_len), + dtype=torch.bool, device=cmask.device)), + # video_padding + torch.zeros( + (video_len, vmask.size(0) - video_len), + dtype=torch.bool, device=cmask.device + ), + # [SEP] for video (unused). + torch.zeros( + (video_len, 1), dtype=torch.bool, device=cmask.device + ), + cmask[2:].unsqueeze(0).repeat(video_len, 1) + ], dim=1) + + text_masks = cls_text_mask[None, :].repeat( + cmask.size(0) - 2, 1) + video_padding_masks = cls_text_mask[None, :].repeat( + vmask.size(0) - video_len, 1) + + return torch.cat([ + cls_text_mask[None, :], + video_masks, + video_padding_masks, + torch.cat([cmask[:1], vmask, cmask[1:]], dim=0)[None,:], + text_masks + ], dim=0) + + def _build_textgeneration_mask(self, vmask, cmask): + # cls_mask is only about video otherwise it will leak generation. + cls_video_mask = torch.cat([ + # [CLS] + torch.ones( + (1,), dtype=torch.bool, device=cmask.device), + vmask, + # [SEP] + torch.ones((1,), dtype=torch.bool, device=cmask.device), + torch.zeros( + (cmask.size(0)-2,), dtype=torch.bool, device=cmask.device) + ], dim=0) + + # concat horizontially. + text_len = int(cmask[2:].sum()) + text_masks = torch.cat([ + # [CLS] + torch.ones( + (text_len, 1), dtype=torch.bool, device=cmask.device + ), + vmask.unsqueeze(0).repeat(text_len, 1), + # [SEP] for video. + torch.ones( + (text_len, 1), dtype=torch.bool, device=cmask.device + ), + torch.tril( + torch.ones( + (text_len, text_len), + dtype=torch.bool, device=cmask.device)), + # padding. + torch.zeros( + (text_len, cmask.size(0) - text_len - 2), + dtype=torch.bool, device=cmask.device + ) + ], dim=1) + + cls_video_masks = cls_video_mask[None, :].repeat( + vmask.size(0) + 2, 1) + text_padding_masks = cls_video_mask[None, :].repeat( + cmask.size(0) - text_len - 2, 1) + return torch.cat([ + cls_video_masks, text_masks, text_padding_masks], dim=0) diff --git a/examples/MMPT/mmpt/tasks/__init__.py b/examples/MMPT/mmpt/tasks/__init__.py new file mode 100644 index 0000000000..e2e9323a53 --- /dev/null +++ b/examples/MMPT/mmpt/tasks/__init__.py @@ -0,0 +1,22 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +from .task import * +from .vlmtask import * +from .retritask import * + +try: + from .fairseqmmtask import * +except ImportError: + pass + +try: + from .milncetask import * +except ImportError: + pass + +try: + from .expretritask import * +except ImportError: + pass diff --git a/examples/MMPT/mmpt/tasks/fairseqmmtask.py b/examples/MMPT/mmpt/tasks/fairseqmmtask.py new file mode 100644 index 0000000000..fa7dae7a6c --- /dev/null +++ b/examples/MMPT/mmpt/tasks/fairseqmmtask.py @@ -0,0 +1,92 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +""" +make a general fairseq task for MM pretraining. +""" + +import random + +from fairseq.tasks import LegacyFairseqTask, register_task + +from .task import Task +from .retritask import RetriTask +from ..datasets import FairseqMMDataset +from .. import utils + + +@register_task("mmtask") +class FairseqMMTask(LegacyFairseqTask): + @staticmethod + def add_args(parser): + # Add some command-line arguments for specifying where the data is + # located and the maximum supported input length. + parser.add_argument( + "taskconfig", + metavar="FILE", + help=( + "taskconfig to load all configurations" + "outside fairseq parser."), + ) + + @classmethod + def setup_task(cls, args, **kwargs): + return FairseqMMTask(args) + + def __init__(self, args): + super().__init__(args) + config = utils.load_config(args) + self.mmtask = Task.config_task(config) + self.mmtask.build_dataset() + self.mmtask.build_model() + self.mmtask.build_loss() + + def load_dataset(self, split, **kwargs): + split_map = { + "train": self.mmtask.train_data, + "valid": self.mmtask.val_data, + "test": self.mmtask.test_data, + } + if split not in split_map: + raise ValueError("unknown split type.") + if split_map[split] is not None: + self.datasets[split] = FairseqMMDataset(split_map[split]) + + def get_batch_iterator( + self, + dataset, + max_tokens=None, + max_sentences=None, + max_positions=None, + ignore_invalid_inputs=False, + required_batch_size_multiple=1, + seed=1, + num_shards=1, + shard_id=0, + num_workers=0, + epoch=1, + data_buffer_size=0, + disable_iterator_cache=False, + ): + random.seed(epoch) + if dataset.mmdataset.split == "train" \ + and isinstance(self.mmtask, RetriTask): + if epoch >= self.mmtask.config.retri_epoch: + if not hasattr(self.mmtask, "retri_dataloader"): + self.mmtask.build_dataloader() + self.mmtask.retrive_candidates(epoch) + + return super().get_batch_iterator( + dataset, max_tokens, max_sentences, max_positions, + ignore_invalid_inputs, required_batch_size_multiple, + seed, num_shards, shard_id, num_workers, epoch, + data_buffer_size, disable_iterator_cache) + + @property + def source_dictionary(self): + return None + + @property + def target_dictionary(self): + return None diff --git a/examples/MMPT/mmpt/tasks/milncetask.py b/examples/MMPT/mmpt/tasks/milncetask.py new file mode 100644 index 0000000000..61b6ab0597 --- /dev/null +++ b/examples/MMPT/mmpt/tasks/milncetask.py @@ -0,0 +1,27 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + +from .task import Task + + +class MILNCETask(Task): + def reshape_subsample(self, sample): + if ( + hasattr(self.config.dataset, "subsampling") + and self.config.dataset.subsampling is not None + and self.config.dataset.subsampling > 1 + ): + for key in sample: + if torch.is_tensor(sample[key]): + tensor = self.flat_subsample(sample[key]) + if key in ["caps", "cmasks"]: + size = tensor.size() + batch_size = size[0] * size[1] + expanded_size = (batch_size,) + size[2:] + tensor = tensor.view(expanded_size) + sample[key] = tensor + return sample diff --git a/examples/MMPT/mmpt/tasks/retritask.py b/examples/MMPT/mmpt/tasks/retritask.py new file mode 100644 index 0000000000..b43f20fddb --- /dev/null +++ b/examples/MMPT/mmpt/tasks/retritask.py @@ -0,0 +1,253 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import torch +import pickle +import random + +from tqdm import tqdm +from torch.utils.data import DataLoader +from torch.utils.data.distributed import DistributedSampler + +from ..processors import ( + ShardedHow2MetaProcessor, + ShardedVideoProcessor, + ShardedTextProcessor, + VariedLenAligner, +) + +from ..datasets import MMDataset +from .task import Task +from ..modules import vectorpool +from ..evaluators.predictor import Predictor +from ..utils import set_seed, get_local_rank, get_world_size + + +class RetriTask(Task): + """abstract class for task with retrival.""" + + def reshape_subsample(self, sample): + for key in sample: + if torch.is_tensor(sample[key]): + sample[key] = self.flat_subsample(sample[key]) + return sample + + def flat_subsample(self, tensor): + if tensor.size(0) == 1: + tensor = tensor.squeeze(0) + return tensor + + def build_dataloader(self): + """called by `get_batch_iterator` in fairseqmmtask. """ + # TODO: hard-code dataloader for retri for now and configurable in .yaml. + # reuse the `train.lst`. + self.config.dataset.split = "train" + meta_processor = ShardedHow2MetaProcessor(self.config.dataset) + video_processor = ShardedVideoProcessor(self.config.dataset) + text_processor = ShardedTextProcessor(self.config.dataset) + + aligner = VariedLenAligner(self.config.dataset) + aligner.subsampling = self.config.dataset.clip_per_video + + self.retri_data = MMDataset( + meta_processor, video_processor, text_processor, aligner + ) + + retri_sampler = DistributedSampler(self.retri_data) + infer_scale = 16 + batch_size = self.config.dataset.num_video_per_batch \ + * infer_scale + + self.retri_dataloader = DataLoader( + self.retri_data, + collate_fn=self.retri_data.collater, + batch_size=batch_size, + shuffle=False, + sampler=retri_sampler, + num_workers=self.config.fairseq.dataset.num_workers + ) + return self.retri_dataloader + + def retrive_candidates(self, epoch, dataloader=None): + if get_local_rank() == 0: + print("running retrieval model.") + out_dir = os.path.join( + self.config.fairseq.checkpoint.save_dir, "retri") + os.makedirs(out_dir, exist_ok=True) + + if not os.path.isfile( + os.path.join( + out_dir, "batched_e" + str(epoch) + "_videos0.pkl") + ): + if dataloader is None: + dataloader = self.retri_dataloader + + self.model.eval() + self.model.is_train = False + + assert self.retri_data.meta_processor.data == \ + self.train_data.meta_processor.data # video_ids not mutated. + + self._retri_predict(epoch, dataloader) + + self.model.train() + self.model.is_train = True + + torch.distributed.barrier() + output = self._retri_sync(epoch, out_dir) + torch.distributed.barrier() + self.train_data.meta_processor.set_candidates(output) + return output + + +class VideoRetriTask(RetriTask): + """RetriTask on video level.""" + + def reshape_subsample(self, sample): + if ( + hasattr(self.config.dataset, "clip_per_video") + and self.config.dataset.clip_per_video is not None + and self.config.dataset.clip_per_video > 1 + ): + for key in sample: + if torch.is_tensor(sample[key]): + sample[key] = self.flat_subsample(sample[key]) + return sample + + def flat_subsample(self, tensor): + if tensor.size(0) == 1: + tensor = tensor.squeeze(0) + return Task.flat_subsample(self, tensor) + + def _retri_predict(self, epoch, dataloader): + set_seed(epoch) + # save for retrival. + predictor = VideoPredictor(self.config) + predictor.predict_loop( + self.model, dataloader) + set_seed(epoch) # get the same text clips. + # retrival. + retri_predictor = VideoRetriPredictor( + self.config) + retri_predictor.predict_loop( + self.model, predictor.vecpool.retriver, epoch) + del predictor + del retri_predictor + + def _retri_sync(self, epoch, out_dir): + # gpu do the same merge. + batched_videos = [] + for local_rank in range(get_world_size()): + fn = os.path.join( + out_dir, + "batched_e" + str(epoch) + "_videos" + str(local_rank) + ".pkl") + with open(fn, "rb") as fr: + batched_videos.extend(pickle.load(fr)) + print( + "[INFO] batched_videos", + len(batched_videos), len(batched_videos[0])) + return batched_videos + + +class VideoPredictor(Predictor): + def __init__(self, config): + vectorpool_cls = getattr(vectorpool, config.vectorpool_cls) + self.vecpool = vectorpool_cls(config) + + def predict_loop( + self, + model, + dataloader, + early_stop=-1, + ): + with torch.no_grad(): + if get_local_rank() == 0: + dataloader = tqdm(dataloader) + for batch_idx, batch in enumerate(dataloader): + if batch_idx == early_stop: + break + self(batch, model) + return self.finalize() + + def __call__(self, sample, model, **kwargs): + param = next(model.parameters()) + dtype = param.dtype + device = param.device + subsample = sample["vfeats"].size(1) + sample = self.to_ctx(sample, device, dtype) + for key in sample: + if torch.is_tensor(sample[key]): + size = sample[key].size() + if len(size) >= 2: + batch_size = size[0] * size[1] + expanded_size = ( + (batch_size,) + size[2:] if len(size) > 2 + else (batch_size,) + ) + sample[key] = sample[key].view(expanded_size) + + outputs = model(**sample) + sample.update(outputs) + self.vecpool(sample, subsample) + + def finalize(self): + print("[INFO]", self.vecpool) + if not self.vecpool.retriver.db.is_trained: + self.vecpool.retriver.finalize_training() + return self.vecpool.retriver + + +class VideoRetriPredictor(Predictor): + """ + Online Retrieval Predictor for Clips (used by RetriTask). + TODO: merge this with VisPredictor? + """ + + def __init__(self, config): + self.pred_dir = os.path.join( + config.fairseq.checkpoint.save_dir, + "retri") + self.num_cands = config.num_cands + self.num_video_per_batch = config.dataset.num_video_per_batch + + def predict_loop( + self, + model, + retriver, + epoch, + early_stop=-1 + ): + # a fake loop that only try to recover video vector + # from video_id. + batched_videos = [] + # obtain available video_ids. + video_ids = list(retriver.videoid_to_vectoridx.keys()) + + dataloader = random.sample( + video_ids, + len(video_ids) // self.num_video_per_batch + ) + + if get_local_rank() == 0: + dataloader = tqdm(dataloader) + for batch_idx, batch in enumerate(dataloader): + # batch is one video id. + if batch_idx == early_stop: + break + video_ids = retriver.search_by_video_ids( + [batch], self.num_cands)[0] + if len(video_ids) > self.num_video_per_batch: + # we moved the center to make cluster robust. + video_ids = random.sample(video_ids, self.num_video_per_batch) + batched_videos.append(video_ids) + return self.finalize(batched_videos, epoch) + + def finalize(self, batched_videos, epoch): + fn = os.path.join( + self.pred_dir, + "batched_e" + str(epoch) + "_videos" + str(get_local_rank()) + ".pkl") + with open(fn, "wb") as fw: + pickle.dump(batched_videos, fw, pickle.HIGHEST_PROTOCOL) + return batched_videos diff --git a/examples/MMPT/mmpt/tasks/task.py b/examples/MMPT/mmpt/tasks/task.py new file mode 100644 index 0000000000..8bb50f24df --- /dev/null +++ b/examples/MMPT/mmpt/tasks/task.py @@ -0,0 +1,184 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import torch + +from .. import tasks +from .. import models +from .. import losses +from ..datasets import MMDataset +from .. import processors + + +class Task(object): + """ + A task refers to one generic training task (e.g., training one model). + """ + + @classmethod + def config_task(cls, config): + """ + determine whether to load a hard-coded task or config from a generic one. + via if a task string is available in config. + """ + if config.task is not None: + # TODO (huxu): expand the search scope. + task_cls = getattr(tasks, config.task) + return task_cls(config) + else: + return Task(config) + + def __init__(self, config): + self.config = config + self.train_data = None + self.val_data = None + self.test_data = None + + self.model = None + self.loss_fn = None + self.eval_fn = None + + def build_dataset(self): + """TODO (huxu): move processor breakdown to MMDataset.""" + """fill-in `self.train_data`, `self.val_data` and `self.test_data`.""" + + meta_processor_cls = getattr( + processors, self.config.dataset.meta_processor) + video_processor_cls = getattr( + processors, self.config.dataset.video_processor) + text_processor_cls = getattr( + processors, self.config.dataset.text_processor) + aligner_cls = getattr( + processors, self.config.dataset.aligner) + + if self.config.dataset.train_path is not None: + self.config.dataset.split = "train" + # may be used by meta processor. + # meta_processor controls different dataset. + meta_processor = meta_processor_cls(self.config.dataset) + video_processor = video_processor_cls(self.config.dataset) + text_processor = text_processor_cls(self.config.dataset) + aligner = aligner_cls(self.config.dataset) + self.train_data = MMDataset( + meta_processor, video_processor, text_processor, aligner + ) + print("train_len", len(self.train_data)) + output = self.train_data[0] + self.train_data.print_example(output) + if self.config.dataset.val_path is not None: + self.config.dataset.split = "valid" + # may be used by meta processor. + meta_processor = meta_processor_cls(self.config.dataset) + video_processor = video_processor_cls(self.config.dataset) + text_processor = text_processor_cls(self.config.dataset) + aligner = aligner_cls(self.config.dataset) + self.val_data = MMDataset( + meta_processor, video_processor, text_processor, aligner + ) + print("val_len", len(self.val_data)) + output = self.val_data[0] + self.val_data.print_example(output) + + if self.config.dataset.split == "test": + # the following is run via lauching fairseq-validate. + meta_processor = meta_processor_cls(self.config.dataset) + video_processor = video_processor_cls(self.config.dataset) + text_processor = text_processor_cls(self.config.dataset) + + self.test_data = MMDataset( + meta_processor, video_processor, text_processor, aligner + ) + print("test_len", len(self.test_data)) + output = self.test_data[0] + self.test_data.print_example(output) + + def build_model(self, checkpoint=None): + if self.model is None: + model_cls = getattr(models, self.config.model.model_cls) + self.model = model_cls(self.config) + if checkpoint is not None: + self.load_checkpoint(checkpoint) + return self.model + + def load_checkpoint(self, checkpoint): + if self.model is None: + raise ValueError("model is not initialized.") + state_dict = torch.load(checkpoint) + state_dict = self._trim_state_dict(state_dict) + self.model.load_state_dict(state_dict, strict=False) + # if it's a fp16 model, turn it back. + if next(self.model.parameters()).dtype == torch.float16: + self.model = self.model.float() + return self.model + + def _trim_state_dict(self, state_dict): + from collections import OrderedDict + + if "state_dict" in state_dict: + state_dict = state_dict["state_dict"] + if "model" in state_dict: # fairseq checkpoint format. + state_dict = state_dict["model"] + ret_state_dict = OrderedDict() + for ( + key, + value, + ) in state_dict.items(): + # remove fairseq wrapper since this is a task. + if key.startswith("mmmodel"): + key = key[len("mmmodel."):] + ret_state_dict[key] = value + return ret_state_dict + + def build_loss(self): + if self.loss_fn is None and self.config.loss is not None: + loss_cls = getattr(losses, self.config.loss.loss_cls) + self.loss_fn = loss_cls() + return self.loss_fn + + def flat_subsample(self, tensor): + size = tensor.size() + if len(size) >= 2: + batch_size = size[0] * size[1] + expanded_size = ( + (batch_size,) + size[2:] if len(size) > 2 + else (batch_size,) + ) + tensor = tensor.view(expanded_size) + return tensor + + def reshape_subsample(self, sample): + if ( + hasattr(self.config.dataset, "subsampling") + and self.config.dataset.subsampling is not None + and self.config.dataset.subsampling > 1 + ): + for key in sample: + if torch.is_tensor(sample[key]): + sample[key] = self.flat_subsample(sample[key]) + return sample + + def __call__(self, model, sample): + loss = None + loss_scalar = float("inf") + + sample = self.reshape_subsample(sample) + outputs = self.model(**sample) + sample.update(outputs) + if self.loss_fn is not None: + loss = self.loss_fn(**sample) + loss_scalar = loss.item() + + batch_size = sample["caps"].size(0) + sample_size = 1 + return { + "loss": loss, + "loss_scalar": loss_scalar, + "max_len": self.config.dataset.max_len, + "batch_size": batch_size, + "sample_size": sample_size, + } + + def build_dataloader(self): + """only used for trainer that lacks building loaders.""" + raise NotImplementedError diff --git a/examples/MMPT/mmpt/tasks/vlmtask.py b/examples/MMPT/mmpt/tasks/vlmtask.py new file mode 100644 index 0000000000..57dc4c9170 --- /dev/null +++ b/examples/MMPT/mmpt/tasks/vlmtask.py @@ -0,0 +1,27 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import torch + +from .task import Task + + +class VLMTask(Task): + """A VLM task for reproducibility. + the collator split subsamples into two sub-batches. + This has should have no logic changes. + but changed the randomness in frame masking. + """ + + def flat_subsample(self, tensor): + size = tensor.size() + if len(size) >= 2: + batch_size = size[0] * (size[1] // 2) + expanded_size = ( + (batch_size, 2) + size[2:] if len(size) > 2 + else (batch_size, 2) + ) + tensor = tensor.view(expanded_size) + tensor = torch.cat([tensor[:, 0], tensor[:, 1]], dim=0) + return tensor diff --git a/examples/MMPT/mmpt/utils/__init__.py b/examples/MMPT/mmpt/utils/__init__.py new file mode 100644 index 0000000000..2429ee3757 --- /dev/null +++ b/examples/MMPT/mmpt/utils/__init__.py @@ -0,0 +1,68 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import random +import numpy as np +import torch + +from .shardedtensor import * +from .load_config import * + + +def set_seed(seed=43211): + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + if torch.backends.cudnn.enabled: + torch.backends.cudnn.benchmark = False + torch.backends.cudnn.deterministic = True + + +def get_world_size(): + if torch.distributed.is_initialized(): + world_size = torch.distributed.get_world_size() + else: + world_size = 1 + return world_size + + +def get_local_rank(): + return torch.distributed.get_rank() \ + if torch.distributed.is_initialized() else 0 + + +def print_on_rank0(func): + local_rank = get_local_rank() + if local_rank == 0: + print("[INFO]", func) + + +class RetriMeter(object): + """ + Statistics on whether retrieval yields a better pair. + """ + def __init__(self, freq=1024): + self.freq = freq + self.total = 0 + self.replace = 0 + self.updates = 0 + + def __call__(self, data): + if isinstance(data, np.ndarray): + self.replace += data.shape[0] - int((data[:, 0] == -1).sum()) + self.total += data.shape[0] + elif torch.is_tensor(data): + self.replace += int(data.sum()) + self.total += data.size(0) + else: + raise ValueError("unsupported RetriMeter data type.", type(data)) + + self.updates += 1 + if get_local_rank() == 0 and self.updates % self.freq == 0: + print("[INFO]", self) + + def __repr__(self): + return "RetriMeter (" + str(self.replace / self.total) \ + + "/" + str(self.replace) + "/" + str(self.total) + ")" diff --git a/examples/MMPT/mmpt/utils/load_config.py b/examples/MMPT/mmpt/utils/load_config.py new file mode 100644 index 0000000000..ede4f94117 --- /dev/null +++ b/examples/MMPT/mmpt/utils/load_config.py @@ -0,0 +1,81 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import omegaconf +from omegaconf import OmegaConf + + +def load_config(args=None, config_file=None, overwrite_fairseq=False): + """TODO (huxu): move fairseq overwrite to another function.""" + if args is not None: + config_file = args.taskconfig + config = recursive_config(config_file) + + if config.dataset.subsampling is not None: + batch_size = config.fairseq.dataset.batch_size // config.dataset.subsampling + print( + "adjusting batch_size to {} due to subsampling {}.".format( + batch_size, config.dataset.subsampling + ) + ) + config.fairseq.dataset.batch_size = batch_size + + is_test = config.dataset.split is not None and config.dataset.split == "test" + if not is_test: + if ( + config.fairseq.checkpoint is None + or config.fairseq.checkpoint.save_dir is None + ): + raise ValueError("fairseq save_dir or save_path must be specified.") + + save_dir = config.fairseq.checkpoint.save_dir + os.makedirs(save_dir, exist_ok=True) + if config.fairseq.common.tensorboard_logdir is not None: + tb_run_dir = suffix_rundir( + save_dir, config.fairseq.common.tensorboard_logdir + ) + config.fairseq.common.tensorboard_logdir = tb_run_dir + print( + "update tensorboard_logdir as", config.fairseq.common.tensorboard_logdir + ) + os.makedirs(save_dir, exist_ok=True) + OmegaConf.save(config=config, f=os.path.join(save_dir, "config.yaml")) + + if overwrite_fairseq and config.fairseq is not None and args is not None: + # flatten fields. + for group in config.fairseq: + for field in config.fairseq[group]: + print("overwrite args." + field, "as", config.fairseq[group][field]) + setattr(args, field, config.fairseq[group][field]) + return config + + +def recursive_config(config_path): + """allows for stacking of configs in any depth.""" + config = OmegaConf.load(config_path) + if config.includes is not None: + includes = config.includes + config.pop("includes") + base_config = recursive_config(includes) + config = OmegaConf.merge(base_config, config) + return config + + +def suffix_rundir(save_dir, run_dir): + max_id = -1 + for search_dir in os.listdir(save_dir): + if search_dir.startswith(run_dir): + splits = search_dir.split("_") + cur_id = int(splits[1]) if len(splits) > 1 else 0 + max_id = max(max_id, cur_id) + return os.path.join(save_dir, run_dir + "_" + str(max_id + 1)) + + +def overwrite_dir(config, replace, basedir): + for key in config: + if isinstance(config[key], str) and config[key].startswith(basedir): + config[key] = config[key].replace(basedir, replace) + if isinstance(config[key], omegaconf.dictconfig.DictConfig): + overwrite_dir(config[key], replace, basedir) diff --git a/examples/MMPT/mmpt/utils/shardedtensor.py b/examples/MMPT/mmpt/utils/shardedtensor.py new file mode 100644 index 0000000000..2424f360ef --- /dev/null +++ b/examples/MMPT/mmpt/utils/shardedtensor.py @@ -0,0 +1,46 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import pickle +import numpy as np + + +class ShardedTensor(object): + def __init__(self, data, starts): + self.data = data + self.starts = starts + assert self.starts[0] == 0 + assert self.starts[-1] == len(self.data) + assert (self.starts[1:] >= self.starts[:-1]).all() + assert (self.starts > -1).all() + + @staticmethod + def from_list(xs): + starts = np.full((len(xs) + 1,), -1, dtype=np.long) + data = np.concatenate(xs, axis=0) + starts[0] = 0 + for i, x in enumerate(xs): + starts[i + 1] = starts[i] + x.shape[0] + assert (starts > -1).all() + return ShardedTensor(data, starts) + + def __getitem__(self, i): + return self.data[self.starts[i] : self.starts[i + 1]] + + def __len__(self): + return len(self.starts) - 1 + + def lengths(self): + return self.starts[1:] - self.starts[:-1] + + def save(self, path): + np.save(path + "_starts", self.starts) + np.save(path + "_data", self.data) + + @staticmethod + def load(path, mmap_mode=None): + starts = np.load(path + "_starts.npy", mmap_mode) + data = np.load(path + "_data.npy", mmap_mode) + return ShardedTensor(data, starts) diff --git a/examples/MMPT/mmpt_cli/localjob.py b/examples/MMPT/mmpt_cli/localjob.py new file mode 100644 index 0000000000..2675d3511a --- /dev/null +++ b/examples/MMPT/mmpt_cli/localjob.py @@ -0,0 +1,117 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os + +from mmpt.utils import recursive_config + + +class BaseJob(object): + def __init__(self, yaml_file, dryrun=False): + self.yaml_file = yaml_file + self.config = recursive_config(yaml_file) + self.dryrun = dryrun + + def submit(self, **kwargs): + raise NotImplementedError + + def _normalize_cmd(self, cmd_list): + cmd_list = list(cmd_list) + yaml_index = cmd_list.index("[yaml]") + cmd_list[yaml_index] = self.yaml_file + return cmd_list + + +class LocalJob(BaseJob): + + CMD_CONFIG = { + "local_single": [ + "fairseq-train", "[yaml]", "--user-dir", "mmpt", + "--task", "mmtask", "--arch", "mmarch", + "--criterion", "mmloss", + ], + "local_small": [ + "fairseq-train", "[yaml]", "--user-dir", "mmpt", + "--task", "mmtask", "--arch", "mmarch", + "--criterion", "mmloss", + "--distributed-world-size", "2" + ], + "local_big": [ + "fairseq-train", "[yaml]", "--user-dir", "mmpt", + "--task", "mmtask", "--arch", "mmarch", + "--criterion", "mmloss", + "--distributed-world-size", "8" + ], + "local_predict": ["python", "mmpt_cli/predict.py", "[yaml]"], + } + + def __init__(self, yaml_file, job_type=None, dryrun=False): + super().__init__(yaml_file, dryrun) + if job_type is None: + self.job_type = "local_single" + if self.config.task_type is not None: + self.job_type = self.config.task_type + else: + self.job_type = job_type + if self.job_type in ["local_single", "local_small"]: + if self.config.fairseq.dataset.batch_size > 32: + print("decreasing batch_size to 32 for local testing?") + + def submit(self): + cmd_list = self._normalize_cmd(LocalJob.CMD_CONFIG[self.job_type]) + if "predict" not in self.job_type: + # append fairseq args. + from mmpt.utils import load_config + + config = load_config(config_file=self.yaml_file) + for field in config.fairseq: + for key in config.fairseq[field]: + if key in ["fp16", "reset_optimizer", "reset_dataloader", "reset_meters"]: # a list of binary flag. + param = ["--" + key.replace("_", "-")] + else: + if key == "lr": + value = str(config.fairseq[field][key][0]) + elif key == "adam_betas": + value = "'"+str(config.fairseq[field][key])+"'" + else: + value = str(config.fairseq[field][key]) + param = [ + "--" + key.replace("_", "-"), + value + ] + cmd_list.extend(param) + + print("launching", " ".join(cmd_list)) + if not self.dryrun: + os.system(" ".join(cmd_list)) + return JobStatus("12345678") + + +class JobStatus(object): + def __init__(self, job_id): + self.job_id = job_id + + def __repr__(self): + return self.job_id + + def __str__(self): + return self.job_id + + def done(self): + return False + + def running(self): + return False + + def result(self): + if self.done(): + return "{} is done.".format(self.job_id) + else: + return "{} is running.".format(self.job_id) + + def stderr(self): + return self.result() + + def stdout(self): + return self.result() diff --git a/examples/MMPT/mmpt_cli/predict.py b/examples/MMPT/mmpt_cli/predict.py new file mode 100644 index 0000000000..4071e196d2 --- /dev/null +++ b/examples/MMPT/mmpt_cli/predict.py @@ -0,0 +1,113 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import glob +import argparse +import pprint +import omegaconf + +from omegaconf import OmegaConf +from torch.utils.data import DataLoader + +from mmpt.utils import load_config, set_seed +from mmpt.evaluators import Evaluator +from mmpt.evaluators import predictor as predictor_path +from mmpt.tasks import Task +from mmpt import processors +from mmpt.datasets import MMDataset + + +def get_dataloader(config): + meta_processor_cls = getattr(processors, config.dataset.meta_processor) + video_processor_cls = getattr(processors, config.dataset.video_processor) + text_processor_cls = getattr(processors, config.dataset.text_processor) + aligner_cls = getattr(processors, config.dataset.aligner) + + meta_processor = meta_processor_cls(config.dataset) + video_processor = video_processor_cls(config.dataset) + text_processor = text_processor_cls(config.dataset) + aligner = aligner_cls(config.dataset) + + test_data = MMDataset( + meta_processor, + video_processor, + text_processor, + aligner, + ) + print("test_len", len(test_data)) + output = test_data[0] + test_data.print_example(output) + + test_dataloader = DataLoader( + test_data, + batch_size=config.fairseq.dataset.batch_size, + shuffle=False, + num_workers=6, + collate_fn=test_data.collater, + ) + return test_dataloader + + +def main(args): + config = load_config(args) + + if isinstance(config, omegaconf.dictconfig.DictConfig): + print(OmegaConf.to_yaml(config)) + else: + pp = pprint.PrettyPrinter(indent=4) + pp.print(config) + + mmtask = Task.config_task(config) + mmtask.build_model() + + test_dataloader = get_dataloader(config) + checkpoint_search_path = os.path.dirname(config.eval.save_path) + results = [] + + prefix = os.path.basename(args.taskconfig) + if prefix.startswith("test"): + # loop all checkpoint for datasets without validation set. + if "best" not in config.fairseq.common_eval.path: + print("eval each epoch.") + for checkpoint in glob.glob(checkpoint_search_path + "/checkpoint*"): + model = mmtask.load_checkpoint(checkpoint) + ckpt = os.path.basename(checkpoint) + evaluator = Evaluator(config) + output = evaluator.evaluate( + model, test_dataloader, ckpt + "_merged") + results.append((checkpoint, output)) + # use the one specified by the config lastly. + model = mmtask.load_checkpoint(config.fairseq.common_eval.path) + evaluator = Evaluator(config) + output = evaluator.evaluate(model, test_dataloader) + results.append((config.fairseq.common_eval.path, output)) + + best_result = None + best_metric = 0. + for checkpoint, result in results: + print(checkpoint) + evaluator.metric.print_computed_metrics(result) + best_score = evaluator.metric.best_metric(result) + if best_score > best_metric: + best_result = (checkpoint, result) + best_metric = best_score + print("best results:") + print(best_result[0]) + evaluator.metric.print_computed_metrics(best_result[1]) + + elif prefix.startswith("vis"): + model = mmtask.load_checkpoint(config.fairseq.common_eval.path) + predictor_cls = getattr(predictor_path, config.predictor) + predictor = predictor_cls(config) + predictor.predict_loop(model, test_dataloader, mmtask, None) + else: + raise ValueError("unknown prefix of the config file", args.taskconfig) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("taskconfig", type=str) + args = parser.parse_args() + main(args) diff --git a/examples/MMPT/pretraining.md b/examples/MMPT/pretraining.md new file mode 100644 index 0000000000..8f8e6d0fac --- /dev/null +++ b/examples/MMPT/pretraining.md @@ -0,0 +1,29 @@ +# Pretraining + +(If you are new to the ideas of `mmpt.processors`, see [README](README.md) first.) +We mostly use [howto100M](https://github.com/antoine77340/howto100m) dataset for pretraining (other datasets are coming). So you are less likely to write a new `MetaProcessor`, `VideoProcessor` or `TextProcessor` but only working on a new `Aligner`, a new model and loss. + +### Data Sharding +Pretraining on Howto100M is heavy on IO since we have millions of videos or captions on the hard disk that cannot be fit into the memory. +It is desirable to have an optimized preprocessing step before the actual dataloading. + +We support data sharding to pack multiple videos into a shards of training data for both videos and captions. (see [dataset](DATASET.md) for preprocessing). +These shards will be mapped into memory to reduce the frequency of IO access on millions of files. See (processors starting with `Sharded*`). +This will be the default config for a how2 dataset `projects/task/how2.yaml`. + +Great thanks to Dmytro Okhonko for sharing the code from MARGE project. + +### Training +Pretraining on Howto100m is expected on one or multiple nodes, where each node has 8 GPUS with 32 GB mem. +launching a pretraing on MFM+MLM can be done, via: +```python locallaunch.py projects/mfmmlm/how2.yaml``` + +### Pre-training with a Retrieval Model (VideoCLIP) +This projects now support alternatively run a retrieval model and pre-training. +We implement a basic retrieval model that is built on the hidden states of a video and faiss. + +You may need to install faiss via `conda install faiss-cpu -c pytorch`. + +Right now, the hidden states of a video is computed as the average of 8 clips of their pooled visual/text hidden states. +See `mmpt/tasks/retritask.py` for more details. +The `.yaml` config for running pre-training with a retrieval model can be found at `projects/retri/videoretri.yaml`. diff --git a/examples/MMPT/projects/mfmmlm.yaml b/examples/MMPT/projects/mfmmlm.yaml new file mode 100644 index 0000000000..0f3450a1e0 --- /dev/null +++ b/examples/MMPT/projects/mfmmlm.yaml @@ -0,0 +1,59 @@ +project_dir: mfmmlm +run_task: + - how2.yaml + - [vtt.yaml, vttcap.yaml, vttqa.yaml, youcook.yaml, youcookcap.yaml, crosstask.yaml, coin.yaml] +base_dir: task +task_group: + pretrain: + task_list: + - how2.yaml + dataset: + subsampling: 32 + sampled_min_len: 10 + sampled_max_len: 64 + max_video_len: 32 + max_len: 96 + aligner: MFMMLMAligner + lazy_vfeat_mask: True + mfm_probability: 0.15 + mlm_probability: 0.15 + mm_prob: 0.5 + model: + model_cls: MMFusionMFMMLM + mm_encoder_cls: MMFusionForMFMMLM + loss: + loss_cls: MFMMLM + fairseq: + common: + fp16: true + dataset: + batch_size: 256 + optimization: + max_epoch: 15 + finetune: + task_list: + - vtt.yaml + - vttqa.yaml + - youcook.yaml + - youcookcap.yaml + - crosstask.yaml + - coin.yaml + dataset: + max_video_len: 32 + max_len: 96 + fairseq: + common: + fp16: true + # do not write any model or loss here (they are expected to be fixed in mmfusion). + test: + task_list: + - test_vtt.yaml + - test_vttqa.yaml + - test_youcook.yaml + - test_youcookcap.yaml + - test_crosstask.yaml + - test_crosstask_zs.yaml + - test_coin.yaml + dataset: + max_video_len: 32 + max_len: 96 diff --git a/examples/MMPT/projects/mtm/mmfusionmtm.yaml b/examples/MMPT/projects/mtm/mmfusionmtm.yaml new file mode 100644 index 0000000000..337d66a2aa --- /dev/null +++ b/examples/MMPT/projects/mtm/mmfusionmtm.yaml @@ -0,0 +1,19 @@ +includes: projects/mfmmlm.yaml +project_dir: mtm/mmfusionmtm +task_group: + pretrain: + task: VLMTask # reproducible + dataset: + aligner: MFMMLMAligner + model: + use_seg_emb: True # reproducible + model_cls: MMFusionMTM + mm_encoder_cls: MMBertForMFMMLM + loss: + loss_cls: MTM + finetune: + model: + use_seg_emb: True # reproducible + test: + model: + use_seg_emb: True # reproducible diff --git a/examples/MMPT/projects/mtm/vlm.yaml b/examples/MMPT/projects/mtm/vlm.yaml new file mode 100644 index 0000000000..022a2623c5 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm.yaml @@ -0,0 +1,8 @@ +includes: projects/mtm/mmfusionmtm.yaml +project_dir: mtm/vlm +task_group: + pretrain: + dataset: + sampled_min_len: 8 + loss: + loss_cls: MTM diff --git a/examples/MMPT/projects/mtm/vlm/coin.yaml b/examples/MMPT/projects/mtm/vlm/coin.yaml new file mode 100644 index 0000000000..4060b55a63 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/coin.yaml @@ -0,0 +1,46 @@ +dataset: + video_processor: VideoProcessor + bert_name: bert-base-uncased + meta_processor: COINActionSegmentationMetaProcessor + train_path: data/coin/COIN.json + val_path: data/coin/COIN.json + vfeat_dir: data/feat/feat_coin_s3d + text_processor: COINActionSegmentationTextProcessor + aligner: COINActionSegmentationAligner + num_iso_layer: 12 + sliding_window: 8 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 1 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 8 + checkpoint: + restore_file: runs/mtm/vlm/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/mtm/vlm/coin +task_type: sweep_big +model: + model_cls: MMFusionActionSegmentation + mm_encoder_cls: MMBertForTokenClassification + use_seg_emb: true +loss: + loss_cls: CrossEntropy diff --git a/examples/MMPT/projects/mtm/vlm/crosstask.yaml b/examples/MMPT/projects/mtm/vlm/crosstask.yaml new file mode 100644 index 0000000000..b961fd9822 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/crosstask.yaml @@ -0,0 +1,52 @@ +dataset: + video_processor: CrossTaskVideoProcessor + bert_name: bert-base-uncased + meta_processor: CrossTaskMetaProcessor + train_path: data/crosstask/crosstask_release/videos.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + text_processor: CrossTaskTextProcessor + aligner: CrossTaskAligner + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 1 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 5 + checkpoint: + restore_file: runs/mtm/vlm/checkpoint11.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/mtm/vlm/crosstask +task_type: sweep_small +model: + model_cls: MMFusionActionLocalization + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +loss: + loss_cls: BCE diff --git a/examples/MMPT/projects/mtm/vlm/how2.yaml b/examples/MMPT/projects/mtm/vlm/how2.yaml new file mode 100644 index 0000000000..c0b497b401 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/how2.yaml @@ -0,0 +1,52 @@ +dataset: + video_processor: ShardedVideoProcessor + bert_name: bert-base-uncased + meta_processor: ShardedHow2MetaProcessor + train_path: data/how2/how2_s3d_train.lst + val_path: data/how2/how2_s3d_val.lst + vfeat_dir: data/feat/feat_how2_s3d_shard_small + text_processor: ShardedTextProcessor + tfeat_dir: data/feat/feat_how2_s3d_shard_small/raw_caption_dedup.bert-base-uncased. + aligner: MFMMLMAligner + subsampling: 32 + sampled_min_len: 8 + sampled_max_len: 64 + max_video_len: 32 + max_len: 96 + lazy_vfeat_mask: true + mfm_probability: 0.15 + mlm_probability: 0.15 + mm_prob: 0.5 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 256 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 1000 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 15 + checkpoint: + save_dir: runs/mtm/vlm + save_interval_updates: 1024 + keep_interval_updates: 2 + keep_last_epochs: 30 +task_type: sweep_big +slurm_config: big +model: + model_cls: MMFusionMTM + mm_encoder_cls: MMBertForMFMMLM + use_seg_emb: true +loss: + loss_cls: MTM +task: VLMTask diff --git a/examples/MMPT/projects/mtm/vlm/test_coin.yaml b/examples/MMPT/projects/mtm/vlm/test_coin.yaml new file mode 100644 index 0000000000..8df2e66ad1 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/test_coin.yaml @@ -0,0 +1,31 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: COINActionSegmentationAligner + bert_name: bert-base-uncased + test_path: data/coin/COIN.json + meta_processor: COINActionSegmentationMetaProcessor + vfeat_dir: data/feat/feat_coin_s3d + text_processor: COINActionSegmentationTextProcessor + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 1 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/mtm/vlm/coin/checkpoint_best.pt +model: + model_cls: MMFusionActionSegmentation + mm_encoder_cls: MMBertForTokenClassification + use_seg_emb: true +eval: + save_path: runs/mtm/vlm/coin/eval +metric: COINActionSegmentationMetric +predictor: COINPredictor diff --git a/examples/MMPT/projects/mtm/vlm/test_crosstask.yaml b/examples/MMPT/projects/mtm/vlm/test_crosstask.yaml new file mode 100644 index 0000000000..d159847875 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/test_crosstask.yaml @@ -0,0 +1,38 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: CrossTaskVideoProcessor + aligner: CrossTaskAligner + bert_name: bert-base-uncased + meta_processor: CrossTaskMetaProcessor + test_path: data/crosstask/crosstask_release/videos_val.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + text_processor: CrossTaskTextProcessor + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 1 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/mtm/vlm/crosstask/checkpoint_best.pt +model: + model_cls: MMFusionActionLocalization + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +eval: + save_path: runs/mtm/vlm/crosstask/eval +metric: CrossTaskMetric +predictor: CrossTaskPredictor diff --git a/examples/MMPT/projects/mtm/vlm/test_crosstask_zs.yaml b/examples/MMPT/projects/mtm/vlm/test_crosstask_zs.yaml new file mode 100644 index 0000000000..59833c5540 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/test_crosstask_zs.yaml @@ -0,0 +1,38 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: CrossTaskVideoProcessor + aligner: CrossTaskAligner + bert_name: bert-base-uncased + meta_processor: CrossTaskMetaProcessor + test_path: data/crosstask/crosstask_release/videos_val.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + text_processor: CrossTaskTextProcessor + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 1 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/mtm/vlm/checkpoint_best.pt +model: + model_cls: MMFusionActionLocalization + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +eval: + save_path: runs/mtm/vlm/crosstask_zs/eval +metric: CrossTaskMetric +predictor: CrossTaskPredictor diff --git a/examples/MMPT/projects/mtm/vlm/test_vtt.yaml b/examples/MMPT/projects/mtm/vlm/test_vtt.yaml new file mode 100644 index 0000000000..a41557df6a --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/test_vtt.yaml @@ -0,0 +1,29 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: DSAligner + bert_name: bert-base-uncased + meta_processor: MSRVTTMetaProcessor + test_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/mtm/vlm/vtt/checkpoint_last.pt +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +eval: + save_path: runs/mtm/vlm/vtt/eval +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/mtm/vlm/test_vttqa.yaml b/examples/MMPT/projects/mtm/vlm/test_vttqa.yaml new file mode 100644 index 0000000000..abf3309f70 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/test_vttqa.yaml @@ -0,0 +1,29 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: MSRVTTQAAligner + bert_name: bert-base-uncased + meta_processor: MSRVTTQAMetaProcessor + test_path: data/msrvtt-qa/MSR_MC_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTQATextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/mtm/vlm/vttqa/checkpoint_last.pt +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +eval: + save_path: runs/mtm/vlm/vttqa/eval +metric: QAMetric +predictor: QAPredictor diff --git a/examples/MMPT/projects/mtm/vlm/test_youcook.yaml b/examples/MMPT/projects/mtm/vlm/test_youcook.yaml new file mode 100644 index 0000000000..3a57d25c24 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/test_youcook.yaml @@ -0,0 +1,31 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: YoucookVideoProcessor + aligner: DSAligner + bert_name: bert-base-uncased + meta_processor: YoucookMetaProcessor + test_path: data/youcook/youcook_val.pkl + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + use_annotation_text: true + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: TextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/mtm/vlm/youcook/checkpoint_last.pt +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +eval: + save_path: runs/mtm/vlm/youcook/eval +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/mtm/vlm/test_youcookcap.yaml b/examples/MMPT/projects/mtm/vlm/test_youcookcap.yaml new file mode 100644 index 0000000000..b2595d7c3c --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/test_youcookcap.yaml @@ -0,0 +1,32 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: YoucookVideoProcessor + aligner: DSNLGAligner + bert_name: bert-base-uncased + meta_processor: YoucookNLGMetaProcessor + test_path: data/youcook/val_list.txt + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: NLGTextProcessor + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/mtm/vlm/youcookcap/checkpoint_best.pt +model: + model_cls: MMFusionNLG + mm_encoder_cls: MMBertForNLG + max_decode_length: 24 + use_seg_emb: true +eval: + save_path: runs/mtm/vlm/youcookcap/eval +metric: NLGMetric +predictor: NLGPredictor +gen_param: + num_beams: 5 diff --git a/examples/MMPT/projects/mtm/vlm/vtt.yaml b/examples/MMPT/projects/mtm/vlm/vtt.yaml new file mode 100644 index 0000000000..49998257f9 --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/vtt.yaml @@ -0,0 +1,48 @@ +dataset: + video_processor: VideoProcessor + bert_name: bert-base-uncased + meta_processor: MSRVTTMetaProcessor + train_path: data/msrvtt/MSRVTT_train.csv + jsfusion_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + full_test_path: data/msrvtt/MSRVTT_FULL_test.csv + dup: 20 + val_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + json_path: data/msrvtt/MSRVTT_data.json + aligner: DSAligner + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 256 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 10 + checkpoint: + restore_file: runs/mtm/vlm/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/mtm/vlm/vtt +task_type: sweep_small +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +loss: + loss_cls: T2VContraLoss diff --git a/examples/MMPT/projects/mtm/vlm/vttqa.yaml b/examples/MMPT/projects/mtm/vlm/vttqa.yaml new file mode 100644 index 0000000000..f09d879b1e --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/vttqa.yaml @@ -0,0 +1,46 @@ +dataset: + video_processor: VideoProcessor + bert_name: bert-base-uncased + meta_processor: MSRVTTMetaProcessor + train_path: data/msrvtt/MSRVTT_train.csv + dup: 20 + val_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + json_path: data/msrvtt/MSRVTT_data.json + aligner: DSAligner + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 128 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 5 + checkpoint: + restore_file: runs/mtm/vlm/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/mtm/vlm/vttqa +task_type: sweep_small +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +loss: + loss_cls: V2TContraLoss diff --git a/examples/MMPT/projects/mtm/vlm/youcook.yaml b/examples/MMPT/projects/mtm/vlm/youcook.yaml new file mode 100644 index 0000000000..5b57ee158b --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/youcook.yaml @@ -0,0 +1,46 @@ +dataset: + video_processor: YoucookVideoProcessor + bert_name: bert-base-uncased + meta_processor: YoucookMetaProcessor + train_path: data/youcook/youcook_train.pkl + val_path: data/youcook/youcook_val.pkl + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + use_annotation_text: true + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: TextProcessor + aligner: DSAligner + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 128 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 10 + checkpoint: + restore_file: runs/mtm/vlm/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/mtm/vlm/youcook +task_type: sweep_small +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint + use_seg_emb: true +loss: + loss_cls: T2VContraLoss diff --git a/examples/MMPT/projects/mtm/vlm/youcookcap.yaml b/examples/MMPT/projects/mtm/vlm/youcookcap.yaml new file mode 100644 index 0000000000..34ac0b218a --- /dev/null +++ b/examples/MMPT/projects/mtm/vlm/youcookcap.yaml @@ -0,0 +1,44 @@ +dataset: + video_processor: YoucookVideoProcessor + bert_name: bert-base-uncased + meta_processor: YoucookNLGMetaProcessor + train_path: data/youcook/train_list.txt + val_path: data/youcook/val_list.txt + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: NLGTextProcessor + aligner: DSNLGAligner + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 128 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 10 + checkpoint: + restore_file: runs/mtm/vlm/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/mtm/vlm/youcookcap +task_type: sweep_small +model: + model_cls: MMFusionNLG + mm_encoder_cls: MMBertForNLG + use_seg_emb: true +loss: + loss_cls: NLGLoss diff --git a/examples/MMPT/projects/retri/videoclip.yaml b/examples/MMPT/projects/retri/videoclip.yaml new file mode 100644 index 0000000000..afd040ab05 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip.yaml @@ -0,0 +1,10 @@ +includes: projects/retri/videoretri.yaml +project_dir: retri/videoclip +task_group: + pretrain: + model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 diff --git a/examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml new file mode 100644 index 0000000000..bf106fa65e --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml @@ -0,0 +1,48 @@ +dataset: + video_processor: VideoProcessor + bert_name: bert-base-uncased + meta_processor: COINActionSegmentationMetaProcessor + train_path: data/coin/COIN.json + val_path: data/coin/COIN.json + vfeat_dir: data/feat/feat_coin_s3d + text_processor: COINActionSegmentationTextProcessor + aligner: COINActionSegmentationAligner + num_iso_layer: 12 + sliding_window: 8 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 1 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 8 + checkpoint: + restore_file: runs/retri/videoclip/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/retri/videoclip/coin +task_type: sweep_big +model: + model_cls: MMFusionSeparateActionSegmentation + mm_encoder_cls: null + video_encoder_cls: MMBertForTokenClassification + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +loss: + loss_cls: CrossEntropy diff --git a/examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml new file mode 100644 index 0000000000..6fa60b6761 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml @@ -0,0 +1,54 @@ +dataset: + video_processor: CrossTaskVideoProcessor + bert_name: bert-base-uncased + meta_processor: CrossTaskMetaProcessor + train_path: data/crosstask/crosstask_release/videos.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + text_processor: CrossTaskTextProcessor + aligner: CrossTaskAligner + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 1 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 5 + checkpoint: + restore_file: runs/retri/videoclip/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/retri/videoclip/crosstask +task_type: sweep_small +model: + model_cls: MMFusionSeparateActionLocalization + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +loss: + loss_cls: BCE diff --git a/examples/MMPT/projects/retri/videoclip/how2.yaml b/examples/MMPT/projects/retri/videoclip/how2.yaml new file mode 100644 index 0000000000..958c487ccb --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/how2.yaml @@ -0,0 +1,62 @@ +dataset: + video_processor: ShardedVideoRetriVideoProcessor + bert_name: bert-base-uncased + meta_processor: ShardedHow2VideoRetriMetaProcessor + train_path: data/how2/how2_s3d_train.lst + val_path: data/how2/how2_s3d_val.lst + vfeat_dir: data/feat/feat_how2_s3d_shard_small + text_processor: ShardedVideoRetriTextProcessor + tfeat_dir: data/feat/feat_how2_s3d_shard_small/raw_caption_dedup.bert-base-uncased. + aligner: VideoRetriOverlappedAligner + subsampling: 1 + sampled_min_len: 8 + sampled_max_len: 64 + max_video_len: 32 + max_len: 96 + lazy_vfeat_mask: true + mfm_probability: 0.15 + mlm_probability: 0.15 + mm_prob: 0.5 + sampled_video_min_len: 3 + sampled_video_max_len: 32 + num_video_per_batch: 32 + clip_per_video: 16 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 1 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 1000 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 25 + checkpoint: + save_dir: runs/retri/videoclip + save_interval_updates: 1024 + keep_interval_updates: 2 + keep_last_epochs: 30 +task_type: sweep_big +slurm_config: big +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +loss: + loss_cls: MMContraLoss +task: VideoRetriTask +retri_epoch: 1 +vectorpool_cls: VideoVectorPool +retriever_cls: VectorRetriever +num_cands: 64 diff --git a/examples/MMPT/projects/retri/videoclip/test_coin_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/test_coin_videoclip.yaml new file mode 100644 index 0000000000..409906203c --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_coin_videoclip.yaml @@ -0,0 +1,33 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: COINActionSegmentationAligner + bert_name: bert-base-uncased + test_path: data/coin/COIN.json + meta_processor: COINActionSegmentationMetaProcessor + vfeat_dir: data/feat/feat_coin_s3d + text_processor: COINActionSegmentationTextProcessor + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 1 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/coin/checkpoint_best.pt +model: + model_cls: MMFusionSeparateActionSegmentation + mm_encoder_cls: null + video_encoder_cls: MMBertForTokenClassification + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/coin/eval +metric: COINActionSegmentationMetric +predictor: COINPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_coin_zs.yaml b/examples/MMPT/projects/retri/videoclip/test_coin_zs.yaml new file mode 100644 index 0000000000..b33739c7b6 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_coin_zs.yaml @@ -0,0 +1,33 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: COINActionSegmentationAligner + bert_name: bert-base-uncased + test_path: data/coin/COIN.json + meta_processor: COINActionSegmentationMetaProcessor + vfeat_dir: data/feat/feat_coin_s3d + text_processor: COINActionSegmentationTextProcessor + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 1 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/checkpoint_best.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/coin_zs/eval +metric: COINActionSegmentationMetric +predictor: COINZSPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_crosstask_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/test_crosstask_videoclip.yaml new file mode 100644 index 0000000000..e82f54fbe5 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_crosstask_videoclip.yaml @@ -0,0 +1,40 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: CrossTaskVideoProcessor + aligner: CrossTaskAligner + bert_name: bert-base-uncased + meta_processor: CrossTaskMetaProcessor + test_path: data/crosstask/crosstask_release/videos_val.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + text_processor: CrossTaskTextProcessor + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 1 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/crosstask/checkpoint_best.pt +model: + model_cls: MMFusionSeparateActionLocalization + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/crosstask/eval +metric: CrossTaskMetric +predictor: CrossTaskPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_crosstask_zs_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/test_crosstask_zs_videoclip.yaml new file mode 100644 index 0000000000..6fc357cc1f --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_crosstask_zs_videoclip.yaml @@ -0,0 +1,40 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: CrossTaskVideoProcessor + aligner: CrossTaskAligner + bert_name: bert-base-uncased + meta_processor: CrossTaskMetaProcessor + test_path: data/crosstask/crosstask_release/videos_val.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + text_processor: CrossTaskTextProcessor + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 1 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/checkpoint_best.pt +model: + model_cls: MMFusionSeparateActionLocalization + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/crosstask_zs/eval +metric: CrossTaskMetric +predictor: CrossTaskPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_didemo_zs.yaml b/examples/MMPT/projects/retri/videoclip/test_didemo_zs.yaml new file mode 100644 index 0000000000..8dc716815d --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_didemo_zs.yaml @@ -0,0 +1,31 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: DiDeMoAligner + bert_name: bert-base-uncased + meta_processor: DiDeMoMetaProcessor + test_path: data/didemo/test_data.json + vfeat_dir: data/feat/feat_didemo_s3d + text_processor: DiDeMoTextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/checkpoint_best.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/didemo_zs/eval +metric: DiDeMoMetric +predictor: DiDeMoPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_vtt_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/test_vtt_videoclip.yaml new file mode 100644 index 0000000000..19321ad5f4 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_vtt_videoclip.yaml @@ -0,0 +1,31 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: DSAligner + bert_name: bert-base-uncased + meta_processor: MSRVTTMetaProcessor + test_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/vtt/checkpoint_last.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/vtt/eval +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_vtt_zs.yaml b/examples/MMPT/projects/retri/videoclip/test_vtt_zs.yaml new file mode 100644 index 0000000000..d149fa3960 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_vtt_zs.yaml @@ -0,0 +1,31 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: DSAligner + bert_name: bert-base-uncased + meta_processor: MSRVTTMetaProcessor + test_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/checkpoint_best.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/vtt_zs/eval +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_vttqa_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/test_vttqa_videoclip.yaml new file mode 100644 index 0000000000..295aeedbb0 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_vttqa_videoclip.yaml @@ -0,0 +1,31 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: MSRVTTQAAligner + bert_name: bert-base-uncased + meta_processor: MSRVTTQAMetaProcessor + test_path: data/msrvtt-qa/MSR_MC_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTQATextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/vttqa/checkpoint_last.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/vttqa/eval +metric: QAMetric +predictor: QAPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_vttqa_zs.yaml b/examples/MMPT/projects/retri/videoclip/test_vttqa_zs.yaml new file mode 100644 index 0000000000..7a876c822a --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_vttqa_zs.yaml @@ -0,0 +1,31 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: MSRVTTQAAligner + bert_name: bert-base-uncased + meta_processor: MSRVTTQAMetaProcessor + test_path: data/msrvtt-qa/MSR_MC_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTQATextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/checkpoint_best.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/vttqa_zs/eval +metric: QAMetric +predictor: QAPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_youcook_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/test_youcook_videoclip.yaml new file mode 100644 index 0000000000..86a4ab203e --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_youcook_videoclip.yaml @@ -0,0 +1,33 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: YoucookVideoProcessor + aligner: DSAligner + bert_name: bert-base-uncased + meta_processor: YoucookMetaProcessor + test_path: data/youcook/youcook_val.pkl + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + use_annotation_text: true + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: TextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/youcook/checkpoint_last.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/youcook/eval +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/retri/videoclip/test_youcook_zs.yaml b/examples/MMPT/projects/retri/videoclip/test_youcook_zs.yaml new file mode 100644 index 0000000000..fd2941708b --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/test_youcook_zs.yaml @@ -0,0 +1,33 @@ +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: YoucookVideoProcessor + aligner: DSAligner + bert_name: bert-base-uncased + meta_processor: YoucookMetaProcessor + test_path: data/youcook/youcook_val.pkl + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + use_annotation_text: true + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: TextProcessor + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 + common_eval: + path: runs/retri/videoclip/checkpoint_best.pt +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/retri/videoclip/youcook_zs/eval +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml new file mode 100644 index 0000000000..26f64af17d --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml @@ -0,0 +1,50 @@ +dataset: + video_processor: VideoProcessor + bert_name: bert-base-uncased + meta_processor: MSRVTTMetaProcessor + train_path: data/msrvtt/MSRVTT_train.csv + jsfusion_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + full_test_path: data/msrvtt/MSRVTT_FULL_test.csv + dup: 20 + val_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + json_path: data/msrvtt/MSRVTT_data.json + aligner: DSAligner + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 224 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 10 + checkpoint: + restore_file: runs/retri/videoclip/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/retri/videoclip/vtt +task_type: sweep_small +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +loss: + loss_cls: T2VContraLoss diff --git a/examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml new file mode 100644 index 0000000000..0d878917fa --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml @@ -0,0 +1,48 @@ +dataset: + video_processor: VideoProcessor + bert_name: bert-base-uncased + meta_processor: MSRVTTMetaProcessor + train_path: data/msrvtt/MSRVTT_train.csv + dup: 20 + val_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + json_path: data/msrvtt/MSRVTT_data.json + aligner: DSAligner + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 128 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 5 + checkpoint: + restore_file: runs/retri/videoclip/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/retri/videoclip/vttqa +task_type: sweep_small +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +loss: + loss_cls: V2TContraLoss diff --git a/examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml new file mode 100644 index 0000000000..31be2b4cc5 --- /dev/null +++ b/examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml @@ -0,0 +1,48 @@ +dataset: + video_processor: YoucookVideoProcessor + bert_name: bert-base-uncased + meta_processor: YoucookMetaProcessor + train_path: data/youcook/youcook_train.pkl + val_path: data/youcook/youcook_val.pkl + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + use_annotation_text: true + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: TextProcessor + aligner: DSAligner + num_iso_layer: 12 + max_video_len: 32 + max_len: 96 +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + fp16: true + dataset: + num_workers: 4 + batch_size: 128 + optimization: + lr: + - 5.0e-05 + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 122 + weight_decay: 0.0 + ddp_backend: no_c10d + max_epoch: 10 + checkpoint: + restore_file: runs/retri/videoclip/checkpoint_best.pt + reset_optimizer: true + reset_dataloader: true + reset_meters: true + save_dir: runs/retri/videoclip/youcook +task_type: sweep_small +model: + model_cls: MMFusionSeparate + mm_encoder_cls: null + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +loss: + loss_cls: T2VContraLoss diff --git a/examples/MMPT/projects/retri/videoretri.yaml b/examples/MMPT/projects/retri/videoretri.yaml new file mode 100644 index 0000000000..969e1fb279 --- /dev/null +++ b/examples/MMPT/projects/retri/videoretri.yaml @@ -0,0 +1,51 @@ +includes: projects/mfmmlm.yaml +project_dir: retri/videoretri +run_task: + - how2.yaml +task_group: + pretrain: + task: VideoRetriTask + retri_epoch: 1 + vectorpool_cls: VideoVectorPool + retriever_cls: VectorRetriever + num_cands: 64 + dataset: + train_path: data/how2/how2_s3d_train.lst + meta_processor: ShardedHow2VideoRetriMetaProcessor + video_processor: ShardedVideoRetriVideoProcessor + text_processor: ShardedVideoRetriTextProcessor + aligner: VideoRetriOverlappedAligner + sampled_video_min_len: 3 + sampled_video_max_len: 32 + sampled_min_len: 8 + sampled_max_len: 64 + num_video_per_batch: 32 + # do not use subsampling as it changes fairseq batch_size. + subsampling: 1 # disable subsampling + clip_per_video: 16 + fairseq: + dataset: + batch_size: 1 + optimization: + max_epoch: 25 + model: + model_cls: MMFusionShare + mm_encoder_cls: MMBertForEncoder + loss: + loss_cls: MMContraLoss + finetune: + task_list: [vtt_videoclip.yaml, youcook_videoclip.yaml, vttqa_videoclip.yaml, crosstask_videoclip.yaml, coin_videoclip.yaml] + test: + task_list: + - test_youcook_zs.yaml + - test_vtt_zs.yaml + - test_vttqa_zs.yaml + - test_crosstask_zs_videoclip.yaml + - test_coin_zs.yaml + - test_didemo_zs.yaml + - test_youcook_videoclip.yaml + - test_vtt_videoclip.yaml + - test_vttqa_videoclip.yaml + - test_crosstask_videoclip.yaml + - test_coin_videoclip.yaml + diff --git a/examples/MMPT/projects/task/coin.yaml b/examples/MMPT/projects/task/coin.yaml new file mode 100644 index 0000000000..e7772486e1 --- /dev/null +++ b/examples/MMPT/projects/task/coin.yaml @@ -0,0 +1,25 @@ +includes: projects/task/ft.yaml +task_type: sweep_big +dataset: + meta_processor: COINActionSegmentationMetaProcessor + train_path: data/coin/COIN.json + val_path: data/coin/COIN.json + vfeat_dir: data/feat/feat_coin_s3d + video_processor: VideoProcessor + text_processor: COINActionSegmentationTextProcessor + aligner: COINActionSegmentationAligner + num_iso_layer: 12 + sliding_window: 8 + sliding_window_size: 32 +model: + model_cls: MMFusionActionSegmentation + mm_encoder_cls: MMBertForTokenClassification +loss: + loss_cls: CrossEntropy +fairseq: + dataset: + batch_size: 1 + optimization: + max_epoch: 8 + checkpoint: + save_dir: runs/task/coin diff --git a/examples/MMPT/projects/task/coin_videoclip.yaml b/examples/MMPT/projects/task/coin_videoclip.yaml new file mode 100644 index 0000000000..69988bc18a --- /dev/null +++ b/examples/MMPT/projects/task/coin_videoclip.yaml @@ -0,0 +1,7 @@ +includes: projects/task/coin.yaml +model: + model_cls: MMFusionSeparateActionSegmentation + mm_encoder_cls: + video_encoder_cls: MMBertForTokenClassification + text_encoder_cls: BertModel # dummy, not used. + num_hidden_video_layers: 6 diff --git a/examples/MMPT/projects/task/crosstask.yaml b/examples/MMPT/projects/task/crosstask.yaml new file mode 100644 index 0000000000..cb4dbb0cb4 --- /dev/null +++ b/examples/MMPT/projects/task/crosstask.yaml @@ -0,0 +1,31 @@ +includes: projects/task/ft.yaml +dataset: + meta_processor: CrossTaskMetaProcessor + train_path: data/crosstask/crosstask_release/videos.csv # dummy + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv # dummy + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + video_processor: CrossTaskVideoProcessor + text_processor: CrossTaskTextProcessor + aligner: CrossTaskAligner + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 +model: + model_cls: MMFusionActionLocalization + mm_encoder_cls: MMBertForJoint +loss: + loss_cls: BCE +fairseq: + dataset: + batch_size: 1 + optimization: + max_epoch: 5 + checkpoint: + save_dir: runs/task/crosstask + restore_file: runs/task/checkpoint11.pt # for VLM diff --git a/examples/MMPT/projects/task/crosstask_videoclip.yaml b/examples/MMPT/projects/task/crosstask_videoclip.yaml new file mode 100644 index 0000000000..6ec613c07f --- /dev/null +++ b/examples/MMPT/projects/task/crosstask_videoclip.yaml @@ -0,0 +1,10 @@ +includes: projects/task/crosstask.yaml +model: + model_cls: MMFusionSeparateActionLocalization + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel # dummy, not used. + num_hidden_video_layers: 6 +fairseq: + checkpoint: + restore_file: runs/task/checkpoint_best.pt # overwrite the default of VLM. diff --git a/examples/MMPT/projects/task/default.yaml b/examples/MMPT/projects/task/default.yaml new file mode 100644 index 0000000000..927942a794 --- /dev/null +++ b/examples/MMPT/projects/task/default.yaml @@ -0,0 +1,19 @@ +# this yaml cannot be run alone. you must use `how2.yaml`, `vtt.yaml` etc for training. +dataset: + video_processor: VideoProcessor + bert_name: bert-base-uncased +fairseq: + common: + tensorboard_logdir: run + log_interval: 1000 + dataset: + num_workers: 4 + optimization: + lr: [ 0.00005 ] + clip_norm: 2.0 + optimizer: adam + adam_betas: (0.9, 0.98) + lr_scheduler: polynomial_decay + warmup_updates: 1000 + weight_decay: 0.0 + ddp_backend: no_c10d diff --git a/examples/MMPT/projects/task/ft.yaml b/examples/MMPT/projects/task/ft.yaml new file mode 100644 index 0000000000..c93b8a73ea --- /dev/null +++ b/examples/MMPT/projects/task/ft.yaml @@ -0,0 +1,13 @@ +includes: projects/task/default.yaml +# all derived config will be run by fairseq-train. +task_type: sweep_small +fairseq: + optimization: + warmup_updates: 122 # copied from roberta glue: https://github.com/pytorch/fairseq/blob/master/examples/roberta/README.glue.md + checkpoint: + # save_interval_updates: 512 + # borrowed from Roberta script. + restore_file: runs/task/checkpoint_best.pt + reset_optimizer: True + reset_dataloader: True + reset_meters: True diff --git a/examples/MMPT/projects/task/how2.yaml b/examples/MMPT/projects/task/how2.yaml new file mode 100644 index 0000000000..094dd04bfc --- /dev/null +++ b/examples/MMPT/projects/task/how2.yaml @@ -0,0 +1,22 @@ +includes: projects/task/default.yaml +task_type: sweep_big +slurm_config: big +dataset: + meta_processor: ShardedHow2MetaProcessor + train_path: data/how2/how2_s3d_train.lst + val_path: data/how2/how2_s3d_val.lst + video_processor: ShardedVideoProcessor + vfeat_dir: data/feat/feat_how2_s3d_shard_small + text_processor: ShardedTextProcessor + tfeat_dir: data/feat/feat_how2_s3d_shard_small/raw_caption_dedup.bert-base-uncased. + aligner: FixedLenAligner +# disable direct running of this yaml +eval: + save_path: runs/task +fairseq: + checkpoint: + save_dir: runs/task + save_interval_updates: 1024 + keep_interval_updates: 2 + keep_last_epochs: 30 + diff --git a/examples/MMPT/projects/task/test.yaml b/examples/MMPT/projects/task/test.yaml new file mode 100644 index 0000000000..0a98445241 --- /dev/null +++ b/examples/MMPT/projects/task/test.yaml @@ -0,0 +1,13 @@ +# this yaml cannot be run alone: implement a test_${dataset}.yaml +slurm_config: big +task_type: local_predict +dataset: + split: test + video_processor: VideoProcessor + aligner: DSAligner + bert_name: bert-base-uncased +fairseq: + dataset: + batch_size: 256 + valid_subset: test + num_workers: 2 diff --git a/examples/MMPT/projects/task/test_coin.yaml b/examples/MMPT/projects/task/test_coin.yaml new file mode 100644 index 0000000000..6d919df7c2 --- /dev/null +++ b/examples/MMPT/projects/task/test_coin.yaml @@ -0,0 +1,24 @@ +includes: projects/task/test.yaml +dataset: + split: test + test_path: data/coin/COIN.json + meta_processor: COINActionSegmentationMetaProcessor + vfeat_dir: data/feat/feat_coin_s3d + video_processor: VideoProcessor + text_processor: COINActionSegmentationTextProcessor + aligner: COINActionSegmentationAligner + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 +model: + model_cls: MMFusionActionSegmentation + mm_encoder_cls: MMBertForTokenClassification +eval: + save_path: runs/task/coin/eval +fairseq: + dataset: + batch_size: 1 + common_eval: + path: runs/task/coin/checkpoint_best.pt +metric: COINActionSegmentationMetric +predictor: COINPredictor diff --git a/examples/MMPT/projects/task/test_coin_videoclip.yaml b/examples/MMPT/projects/task/test_coin_videoclip.yaml new file mode 100644 index 0000000000..b41f5bc489 --- /dev/null +++ b/examples/MMPT/projects/task/test_coin_videoclip.yaml @@ -0,0 +1,7 @@ +includes: projects/task/test_coin.yaml +model: + model_cls: MMFusionSeparateActionSegmentation + mm_encoder_cls: + video_encoder_cls: MMBertForTokenClassification + text_encoder_cls: BertModel # dummy, not used. + num_hidden_video_layers: 6 diff --git a/examples/MMPT/projects/task/test_coin_zs.yaml b/examples/MMPT/projects/task/test_coin_zs.yaml new file mode 100644 index 0000000000..5d19b09f1d --- /dev/null +++ b/examples/MMPT/projects/task/test_coin_zs.yaml @@ -0,0 +1,13 @@ +includes: projects/task/test_coin.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/task/coin_zs/eval +fairseq: + common_eval: + path: runs/task/checkpoint_best.pt +predictor: COINZSPredictor diff --git a/examples/MMPT/projects/task/test_crosstask.yaml b/examples/MMPT/projects/task/test_crosstask.yaml new file mode 100644 index 0000000000..6dd778e30b --- /dev/null +++ b/examples/MMPT/projects/task/test_crosstask.yaml @@ -0,0 +1,32 @@ +includes: projects/task/test.yaml +dataset: + split: test + meta_processor: CrossTaskMetaProcessor + test_path: data/crosstask/crosstask_release/videos_val.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv # dummy + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + video_processor: CrossTaskVideoProcessor + text_processor: CrossTaskTextProcessor + aligner: CrossTaskAligner + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 +model: + model_cls: MMFusionActionLocalization + mm_encoder_cls: MMBertForJoint +eval: + save_path: runs/task/crosstask/eval +fairseq: + # read code and find what is the checkpoint arg. + dataset: + batch_size: 1 + common_eval: + path: runs/task/crosstask/checkpoint_best.pt +metric: CrossTaskMetric +predictor: CrossTaskPredictor diff --git a/examples/MMPT/projects/task/test_crosstask_videoclip.yaml b/examples/MMPT/projects/task/test_crosstask_videoclip.yaml new file mode 100644 index 0000000000..df12535d23 --- /dev/null +++ b/examples/MMPT/projects/task/test_crosstask_videoclip.yaml @@ -0,0 +1,7 @@ +includes: projects/task/test_crosstask.yaml +model: + model_cls: MMFusionSeparateActionLocalization + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel # dummy, not used. + num_hidden_video_layers: 6 diff --git a/examples/MMPT/projects/task/test_crosstask_zs.yaml b/examples/MMPT/projects/task/test_crosstask_zs.yaml new file mode 100644 index 0000000000..19386e495b --- /dev/null +++ b/examples/MMPT/projects/task/test_crosstask_zs.yaml @@ -0,0 +1,32 @@ +includes: projects/task/test.yaml +dataset: + split: test + meta_processor: CrossTaskMetaProcessor + test_path: data/crosstask/crosstask_release/videos_val.csv + train_csv_path: data/crosstask/crosstask_release/videos.csv + val_path: data/crosstask/crosstask_release/videos_val.csv # dummy + val_csv_path: data/crosstask/crosstask_release/videos_val.csv + primary_path: data/crosstask/crosstask_release/tasks_primary.txt + related_path: data/crosstask/crosstask_release/tasks_related.txt + vfeat_dir: data/feat/feat_crosstask_s3d + annotation_path: data/crosstask/crosstask_release/annotations + n_train: 30 + video_processor: CrossTaskVideoProcessor + text_processor: CrossTaskTextProcessor + aligner: CrossTaskAligner + num_iso_layer: 12 + sliding_window: 16 + sliding_window_size: 32 +model: + model_cls: MMFusionActionLocalization + mm_encoder_cls: MMBertForJoint +eval: + save_path: runs/task/crosstask_zs/eval +fairseq: + # read code and find what is the checkpoint arg. + dataset: + batch_size: 1 + common_eval: + path: runs/task/checkpoint_best.pt # load the best from how2 on ACL submission: runs/task/checkpoint11.pt +metric: CrossTaskMetric +predictor: CrossTaskPredictor diff --git a/examples/MMPT/projects/task/test_crosstask_zs_videoclip.yaml b/examples/MMPT/projects/task/test_crosstask_zs_videoclip.yaml new file mode 100644 index 0000000000..7f0198276f --- /dev/null +++ b/examples/MMPT/projects/task/test_crosstask_zs_videoclip.yaml @@ -0,0 +1,7 @@ +includes: projects/task/test_crosstask_zs.yaml +model: + model_cls: MMFusionSeparateActionLocalization + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel # dummy, not used. + num_hidden_video_layers: 6 diff --git a/examples/MMPT/projects/task/test_didemo_zs.yaml b/examples/MMPT/projects/task/test_didemo_zs.yaml new file mode 100644 index 0000000000..4b53dca71e --- /dev/null +++ b/examples/MMPT/projects/task/test_didemo_zs.yaml @@ -0,0 +1,23 @@ +includes: projects/task/test.yaml +dataset: + meta_processor: DiDeMoMetaProcessor + test_path: data/didemo/test_data.json + video_processor: VideoProcessor + vfeat_dir: data/feat/feat_didemo_s3d + text_processor: DiDeMoTextProcessor + aligner: DiDeMoAligner + num_iso_layer: 12 +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/task/didemo_zs/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/checkpoint_best.pt +metric: DiDeMoMetric +predictor: DiDeMoPredictor diff --git a/examples/MMPT/projects/task/test_vtt.yaml b/examples/MMPT/projects/task/test_vtt.yaml new file mode 100644 index 0000000000..2f809b306d --- /dev/null +++ b/examples/MMPT/projects/task/test_vtt.yaml @@ -0,0 +1,19 @@ +includes: projects/task/test.yaml +dataset: + meta_processor: MSRVTTMetaProcessor + test_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + video_processor: VideoProcessor + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + num_iso_layer: 12 +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint +eval: + save_path: runs/task/vtt/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/vtt/checkpoint_last.pt +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/task/test_vtt_videoclip.yaml b/examples/MMPT/projects/task/test_vtt_videoclip.yaml new file mode 100644 index 0000000000..cb6564394c --- /dev/null +++ b/examples/MMPT/projects/task/test_vtt_videoclip.yaml @@ -0,0 +1,8 @@ +includes: projects/task/test_vtt.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 + diff --git a/examples/MMPT/projects/task/test_vtt_zs.yaml b/examples/MMPT/projects/task/test_vtt_zs.yaml new file mode 100644 index 0000000000..57340924b4 --- /dev/null +++ b/examples/MMPT/projects/task/test_vtt_zs.yaml @@ -0,0 +1,13 @@ +includes: projects/task/test_vtt.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/task/vtt_zs/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/checkpoint_best.pt diff --git a/examples/MMPT/projects/task/test_vttqa.yaml b/examples/MMPT/projects/task/test_vttqa.yaml new file mode 100644 index 0000000000..ddf813c535 --- /dev/null +++ b/examples/MMPT/projects/task/test_vttqa.yaml @@ -0,0 +1,20 @@ +includes: projects/task/test.yaml +dataset: + meta_processor: MSRVTTQAMetaProcessor + test_path: data/msrvtt-qa/MSR_MC_test.csv + video_processor: VideoProcessor + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTQATextProcessor + aligner: MSRVTTQAAligner + num_iso_layer: 12 +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint +eval: + save_path: runs/task/vttqa/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/vttqa/checkpoint_last.pt +metric: QAMetric +predictor: QAPredictor diff --git a/examples/MMPT/projects/task/test_vttqa_videoclip.yaml b/examples/MMPT/projects/task/test_vttqa_videoclip.yaml new file mode 100644 index 0000000000..32a41e861c --- /dev/null +++ b/examples/MMPT/projects/task/test_vttqa_videoclip.yaml @@ -0,0 +1,8 @@ +includes: projects/task/test_vttqa.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 + diff --git a/examples/MMPT/projects/task/test_vttqa_zs.yaml b/examples/MMPT/projects/task/test_vttqa_zs.yaml new file mode 100644 index 0000000000..5e0e29d207 --- /dev/null +++ b/examples/MMPT/projects/task/test_vttqa_zs.yaml @@ -0,0 +1,13 @@ +includes: projects/task/test_vttqa.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/task/vttqa_zs/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/checkpoint_best.pt diff --git a/examples/MMPT/projects/task/test_youcook.yaml b/examples/MMPT/projects/task/test_youcook.yaml new file mode 100644 index 0000000000..092b680fa6 --- /dev/null +++ b/examples/MMPT/projects/task/test_youcook.yaml @@ -0,0 +1,22 @@ +includes: projects/task/test.yaml +dataset: + meta_processor: YoucookMetaProcessor + test_path: data/youcook/youcook_val.pkl + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + use_annotation_text: True + video_processor: YoucookVideoProcessor + vfeat_dir: data/feat/feat_youcook_s3d # /checkpoint/huxu/feat/youcook_vmz # /checkpoint/prarora/berniehuang/feat_youcook_vmz + text_processor: TextProcessor + aligner: DSAligner + num_iso_layer: 12 +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint +eval: + save_path: runs/task/youcook/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/youcook/checkpoint_last.pt +metric: RetrievalMetric +predictor: RetrievalPredictor diff --git a/examples/MMPT/projects/task/test_youcook_videoclip.yaml b/examples/MMPT/projects/task/test_youcook_videoclip.yaml new file mode 100644 index 0000000000..b85ea43474 --- /dev/null +++ b/examples/MMPT/projects/task/test_youcook_videoclip.yaml @@ -0,0 +1,8 @@ +includes: projects/task/test_youcook.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 + diff --git a/examples/MMPT/projects/task/test_youcook_zs.yaml b/examples/MMPT/projects/task/test_youcook_zs.yaml new file mode 100644 index 0000000000..0a5875bea4 --- /dev/null +++ b/examples/MMPT/projects/task/test_youcook_zs.yaml @@ -0,0 +1,13 @@ +includes: projects/task/test_youcook.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +eval: + save_path: runs/task/youcook_zs/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/checkpoint_best.pt diff --git a/examples/MMPT/projects/task/test_youcookcap.yaml b/examples/MMPT/projects/task/test_youcookcap.yaml new file mode 100644 index 0000000000..24f6518b7b --- /dev/null +++ b/examples/MMPT/projects/task/test_youcookcap.yaml @@ -0,0 +1,23 @@ +includes: projects/task/test.yaml +dataset: + meta_processor: YoucookNLGMetaProcessor + test_path: data/youcook/val_list.txt + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + video_processor: YoucookVideoProcessor + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: NLGTextProcessor + aligner: DSNLGAligner +model: + model_cls: MMFusionNLG + mm_encoder_cls: MMBertForNLG + max_decode_length: 24 +eval: + save_path: runs/task/youcookcap/eval +fairseq: + # read code and find what is the checkpoint arg. + common_eval: + path: runs/task/youcookcap/checkpoint_best.pt +metric: NLGMetric +predictor: NLGPredictor +gen_param: + num_beams: 5 diff --git a/examples/MMPT/projects/task/vtt.yaml b/examples/MMPT/projects/task/vtt.yaml new file mode 100644 index 0000000000..395e2ee6fe --- /dev/null +++ b/examples/MMPT/projects/task/vtt.yaml @@ -0,0 +1,25 @@ +includes: projects/task/ft.yaml +dataset: + meta_processor: MSRVTTMetaProcessor + train_path: data/msrvtt/MSRVTT_train.csv + jsfusion_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + full_test_path: data/msrvtt/MSRVTT_FULL_test.csv + dup: 20 + val_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + json_path: data/msrvtt/MSRVTT_data.json + aligner: DSAligner + num_iso_layer: 12 +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint +loss: + loss_cls: T2VContraLoss +fairseq: + dataset: + batch_size: 256 + optimization: + max_epoch: 10 + checkpoint: + save_dir: runs/task/vtt diff --git a/examples/MMPT/projects/task/vtt_videoclip.yaml b/examples/MMPT/projects/task/vtt_videoclip.yaml new file mode 100644 index 0000000000..a9892cab01 --- /dev/null +++ b/examples/MMPT/projects/task/vtt_videoclip.yaml @@ -0,0 +1,12 @@ +includes: projects/task/vtt.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 +fairseq: + dataset: + batch_size: 224 +# model_cls: MMFusionShare +# mm_encoder_cls: MMBertForEncoder diff --git a/examples/MMPT/projects/task/vttqa.yaml b/examples/MMPT/projects/task/vttqa.yaml new file mode 100644 index 0000000000..56d578eff0 --- /dev/null +++ b/examples/MMPT/projects/task/vttqa.yaml @@ -0,0 +1,23 @@ +includes: projects/task/ft.yaml +dataset: + meta_processor: MSRVTTMetaProcessor + train_path: data/msrvtt/MSRVTT_train.csv + dup: 20 + val_path: data/msrvtt/MSRVTT_JSFUSION_test.csv + vfeat_dir: data/feat/feat_vtt_s3d + text_processor: MSRVTTTextProcessor + json_path: data/msrvtt/MSRVTT_data.json + aligner: DSAligner + num_iso_layer: 12 +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint +loss: + loss_cls: V2TContraLoss +fairseq: + dataset: + batch_size: 128 + optimization: + max_epoch: 5 + checkpoint: + save_dir: runs/task/vttqa diff --git a/examples/MMPT/projects/task/vttqa_videoclip.yaml b/examples/MMPT/projects/task/vttqa_videoclip.yaml new file mode 100644 index 0000000000..2d484ca8a5 --- /dev/null +++ b/examples/MMPT/projects/task/vttqa_videoclip.yaml @@ -0,0 +1,10 @@ +includes: projects/task/vttqa.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 + +# model_cls: MMFusionShare +# mm_encoder_cls: MMBertForEncoder diff --git a/examples/MMPT/projects/task/youcook.yaml b/examples/MMPT/projects/task/youcook.yaml new file mode 100644 index 0000000000..e0cd841747 --- /dev/null +++ b/examples/MMPT/projects/task/youcook.yaml @@ -0,0 +1,25 @@ +includes: projects/task/ft.yaml +dataset: + meta_processor: YoucookMetaProcessor + train_path: data/youcook/youcook_train.pkl + val_path: data/youcook/youcook_val.pkl + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + use_annotation_text: True + video_processor: YoucookVideoProcessor + vfeat_dir: data/feat/feat_youcook_s3d # /checkpoint/huxu/feat/youcook_vmz # /checkpoint/prarora/berniehuang/feat_youcook_vmz + text_processor: TextProcessor + aligner: DSAligner + num_iso_layer: 12 +model: + model_cls: MMFusionJoint + mm_encoder_cls: MMBertForJoint +loss: + loss_cls: T2VContraLoss +fairseq: + dataset: + batch_size: 128 + optimization: + max_epoch: 10 + checkpoint: + save_dir: runs/task/youcook + diff --git a/examples/MMPT/projects/task/youcook_videoclip.yaml b/examples/MMPT/projects/task/youcook_videoclip.yaml new file mode 100644 index 0000000000..e3e901c30c --- /dev/null +++ b/examples/MMPT/projects/task/youcook_videoclip.yaml @@ -0,0 +1,9 @@ +includes: projects/task/youcook.yaml +model: + model_cls: MMFusionSeparate + mm_encoder_cls: + video_encoder_cls: MMBertForEncoder + text_encoder_cls: BertModel + num_hidden_video_layers: 6 + # model_cls: MMFusionShare + # mm_encoder_cls: MMBertForEncoder diff --git a/examples/MMPT/projects/task/youcookcap.yaml b/examples/MMPT/projects/task/youcookcap.yaml new file mode 100644 index 0000000000..047735f217 --- /dev/null +++ b/examples/MMPT/projects/task/youcookcap.yaml @@ -0,0 +1,23 @@ +# finetuning for youcook captioning. +includes: projects/task/ft.yaml +dataset: + meta_processor: YoucookNLGMetaProcessor + train_path: data/youcook/train_list.txt + val_path: data/youcook/val_list.txt + trainval_annotation: data/youcook/youcookii_annotations_trainval.json + video_processor: YoucookVideoProcessor + vfeat_dir: data/feat/feat_youcook_s3d + text_processor: NLGTextProcessor + aligner: DSNLGAligner +model: + model_cls: MMFusionNLG + mm_encoder_cls: MMBertForNLG +loss: + loss_cls: NLGLoss +fairseq: + dataset: + batch_size: 128 + optimization: + max_epoch: 10 + checkpoint: + save_dir: runs/task/youcookcap diff --git a/examples/MMPT/scripts/text_token_extractor/configs/bert-base-uncased.yaml b/examples/MMPT/scripts/text_token_extractor/configs/bert-base-uncased.yaml new file mode 100644 index 0000000000..473dd9b45b --- /dev/null +++ b/examples/MMPT/scripts/text_token_extractor/configs/bert-base-uncased.yaml @@ -0,0 +1,5 @@ +dataset: + bert_name: bert-base-uncased + caption_pkl_path: data/how2/raw_caption_dedup.pkl + use_fast: true + target_dir: data/feat/feat_how2_s3d_shard_small diff --git a/examples/MMPT/scripts/text_token_extractor/pretokenization.py b/examples/MMPT/scripts/text_token_extractor/pretokenization.py new file mode 100644 index 0000000000..29ae5dc151 --- /dev/null +++ b/examples/MMPT/scripts/text_token_extractor/pretokenization.py @@ -0,0 +1,106 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import pickle +import os +import argparse +import numpy as np + +from torch.utils.data import Dataset, DataLoader +from mmpt.processors import PKLJSONStrTextProcessor +from mmpt.utils import ShardedTensor, recursive_config + + +class TokenizerDataset(Dataset): + def __init__(self, config): + self.text_processor = PKLJSONStrTextProcessor(config) + self.video_ids = list(self.text_processor.data.keys()) + + def __getitem__(self, idx): + video_id = self.video_ids[idx] + return video_id, self.text_processor(video_id) + + def __len__(self): + return len(self.video_ids) + + +def numpify(shard_idx, video_ids, captions, target_dir, split, prefix, max_cap_len=32): + startends = [] + caps_ids = [] + for video_id in video_ids: + caption = captions[video_id] + startend = [] + cap_ids = [] + for start, end, cap in zip( + caption["start"], caption["end"], caption["cap"]): + startend.append(np.array([start, end]).astype("float32")) + cap_id = np.full((max_cap_len,), -1, dtype=np.int32) + cap = cap[:max_cap_len] + cap_id[:len(cap)] = cap + cap_ids.append(cap_id) + startends.append(np.stack(startend)) + caps_ids.append(np.stack(cap_ids)) + + startends = ShardedTensor.from_list(startends) + target_path = os.path.join( + target_dir, + prefix + split + "_" + str(shard_idx) + ) + print("save to", target_path) + startends.save(target_path + ".startends") + caps_ids = ShardedTensor.from_list(caps_ids) + caps_ids.save(target_path + ".caps_ids") + + +def sharding(config, out_file): + with open(out_file, "rb") as fr: + captions = pickle.load(fr) + target_dir = config.target_dir + prefix = os.path.basename( + os.path.splitext(config.caption_pkl_path)[0] + ) + "." + config.bert_name + "." + for split in ["train", "val"]: + target_path = os.path.join(target_dir, split + "_meta") + with open(target_path + ".pkl", "rb") as fr: + meta = pickle.load(fr) + print("load meta", target_path, len(meta)) + for shard_id in meta: + numpify( + shard_id, meta[shard_id], captions, + target_dir, split, prefix + ) + + +def tokenize(config, out_file): + def collator(samples): + return samples + dataset = TokenizerDataset(config) + data = {} + for idx, batch in enumerate( + DataLoader(dataset, collate_fn=collator, num_workers=16)): + for video_id, caption in batch: + data[video_id] = caption + if idx % 5000 == 0: + print(idx) + with open(out_file, "wb") as fw: + pickle.dump(data, fw, pickle.HIGHEST_PROTOCOL) + + +def main(args): + config = recursive_config(args.config).dataset + + out_file = os.path.splitext(config.caption_pkl_path)[0] \ + + "." + config.bert_name + ".pkl" + if not os.path.isfile(out_file): + tokenize(config, out_file) + sharding(config, out_file) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="pretokenize (raw_)caption.json into pkl.") + parser.add_argument('config', type=str) + args = parser.parse_args() + main(args) diff --git a/examples/MMPT/scripts/video_feature_extractor/extract.py b/examples/MMPT/scripts/video_feature_extractor/extract.py new file mode 100755 index 0000000000..b5ee7b7788 --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/extract.py @@ -0,0 +1,157 @@ +# Copyright Howto100M authors. +# Copyright (c) Facebook, Inc. All Rights Reserved + +import torch as th +import torch.nn.functional as F +import math +import numpy as np +import argparse + +from torch.utils.data import DataLoader +from model import get_model +from preprocessing import Preprocessing +from random_sequence_shuffler import RandomSequenceSampler + +from tqdm import tqdm +from pathbuilder import PathBuilder +from videoreader import VideoLoader + + +parser = argparse.ArgumentParser(description='Easy video feature extractor') + +parser.add_argument('--vdir', type=str) +parser.add_argument('--fdir', type=str) +parser.add_argument('--hflip', type=int, default=0) + +parser.add_argument('--batch_size', type=int, default=64, + help='batch size') +parser.add_argument('--type', type=str, default='2d', + help='CNN type') +parser.add_argument('--half_precision', type=int, default=0, + help='output half precision float') +parser.add_argument('--num_decoding_thread', type=int, default=4, + help='Num parallel thread for video decoding') +parser.add_argument('--l2_normalize', type=int, default=1, + help='l2 normalize feature') +parser.add_argument('--resnext101_model_path', type=str, default='model/resnext101.pth', + help='Resnext model path') +parser.add_argument('--vmz_model_path', type=str, default='model/r2plus1d_34_clip8_ig65m_from_scratch-9bae36ae.pth', + help='vmz model path') + +args = parser.parse_args() + + +# TODO: refactor all args into config. (current code is from different people.) +CONFIGS = { + "2d": { + "fps": 1, + "size": 224, + "centercrop": False, + "shards": 0, + }, + "3d": { + "fps": 24, + "size": 112, + "centercrop": True, + "shards": 0, + }, + "s3d": { + "fps": 30, + "size": 224, + "centercrop": True, + "shards": 0, + }, + "vmz": { + "fps": 24, + "size": 112, + "centercrop": True, + "shards": 0, + }, + "vae": { + "fps": 2, + "size": 256, + "centercrop": True, + "shards": 100, + } +} + +config = CONFIGS[args.type] + + +video_dirs = args.vdir +feature_dir = args.fdir + +video_dict = PathBuilder.build(video_dirs, feature_dir, ".npy", config["shards"]) + +dataset = VideoLoader( + video_dict=video_dict, + framerate=config["fps"], + size=config["size"], + centercrop=config["centercrop"], + hflip=args.hflip +) +n_dataset = len(dataset) +sampler = RandomSequenceSampler(n_dataset, 10) +loader = DataLoader( + dataset, + batch_size=1, + shuffle=False, + num_workers=args.num_decoding_thread, + sampler=sampler if n_dataset > 10 else None, +) +preprocess = Preprocessing(args.type) +model = get_model(args) + +with th.no_grad(): + for k, data in tqdm(enumerate(loader), total=loader.__len__(), ascii=True): + input_file = data['input'][0] + output_file = data['output'][0] + if len(data['video'].shape) > 3: + video = data['video'].squeeze() + if len(video.shape) == 4: + video = preprocess(video) + n_chunk = len(video) + if args.type == 'vmz': + n_chunk = math.ceil(n_chunk/float(3)) + features = th.cuda.FloatTensor(n_chunk, 512).fill_(0) + elif args.type == 's3d': + features = th.cuda.FloatTensor(n_chunk, 512).fill_(0) + elif args.type == "vae": + features = th.cuda.LongTensor(n_chunk, 1024).fill_(0) + else: + features = th.cuda.FloatTensor(n_chunk, 2048).fill_(0) + n_iter = int(math.ceil(n_chunk / float(args.batch_size))) + for i in range(n_iter): + factor = 1 + if args.type == 'vmz': + factor = 3 + min_ind = factor * i * args.batch_size + max_ind = factor * (i + 1) * args.batch_size + video_batch = video[min_ind:max_ind:factor].cuda() + if args.type == '2d': + batch_features = model(video_batch) # (51, 487), (51, 512) + elif args.type == 's3d': + batch_features = model(video_batch) + batch_features = batch_features['video_embedding'] + elif args.type == "vae": + # image_code. + batch_features = model(video_batch) + else: + batch_pred, batch_features = model(video_batch) # (51, 487), (51, 512) + if args.l2_normalize: + batch_features = F.normalize(batch_features, dim=1) + features[i*args.batch_size:(i+1)*args.batch_size] = batch_features + features = features.cpu().numpy() + if args.half_precision: + if args.type == "vae": + features = features.astype(np.int16) + else: + features = features.astype('float16') + else: + if args.type == "vae": + features = features.astype(np.int32) + else: + features = features.astype('float32') + np.save(output_file, features) + else: + print('Video {} error.'.format(input_file)) diff --git a/examples/MMPT/scripts/video_feature_extractor/how2/s3d.sh b/examples/MMPT/scripts/video_feature_extractor/how2/s3d.sh new file mode 100644 index 0000000000..90102c89fb --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/how2/s3d.sh @@ -0,0 +1,8 @@ +#!/bin/bash + + +python scripts/video_feature_extractor/extract.py \ + --vdir <path_to_video_folder> \ + --fdir data/feat/feat_how2_s3d \ + --type=s3d --num_decoding_thread=4 \ + --batch_size 32 --half_precision 1 diff --git a/examples/MMPT/scripts/video_feature_extractor/model.py b/examples/MMPT/scripts/video_feature_extractor/model.py new file mode 100755 index 0000000000..ac266e844c --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/model.py @@ -0,0 +1,58 @@ +# Copyright (c) Howto100M authors and Facebook, Inc. All Rights Reserved + +import torch as th + +from torch import nn + + +class GlobalAvgPool(nn.Module): + def __init__(self): + super(GlobalAvgPool, self).__init__() + + def forward(self, x): + return th.mean(x, dim=[-2, -1]) + + +def get_model(args): + assert args.type in ['2d', '3d', 'vmz', 's3d', 'vae'] + if args.type == '2d': + print('Loading 2D-ResNet-152 ...') + import torchvision.models as models + model = models.resnet152(pretrained=True) + model = nn.Sequential(*list(model.children())[:-2], GlobalAvgPool()) + model = model.cuda() + elif args.type == 'vmz': + print('Loading VMZ ...') + from vmz34 import r2plus1d_34 + model = r2plus1d_34(pretrained_path=args.vmz_model_path, pretrained_num_classes=487) + model = model.cuda() + elif args.type == 's3d': + # we use one copy of s3d instead of dup another one for feature extraction. + from mmpt.processors.models.s3dg import S3D + model = S3D('pretrained_models/s3d_dict.npy', 512) + model.load_state_dict(th.load('pretrained_models/s3d_howto100m.pth')) + model = model.cuda() + + elif args.type == '3d': + print('Loading 3D-ResneXt-101 ...') + from videocnn.models import resnext + model = resnext.resnet101( + num_classes=400, + shortcut_type='B', + cardinality=32, + sample_size=112, + sample_duration=16, + last_fc=False) + model = model.cuda() + model_data = th.load(args.resnext101_model_path) + model.load_state_dict(model_data) + elif args.type == 'vae': + from openaivae import OpenAIParallelDiscreteVAE + model = OpenAIParallelDiscreteVAE() + model = model.cuda() + else: + raise ValueError("model not supported yet.") + + model.eval() + print('loaded') + return model diff --git a/examples/MMPT/scripts/video_feature_extractor/pathbuilder.py b/examples/MMPT/scripts/video_feature_extractor/pathbuilder.py new file mode 100644 index 0000000000..2392d6d63b --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/pathbuilder.py @@ -0,0 +1,89 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import os +import urllib.parse +import json +import pandas as pd + +from tqdm import tqdm + + +# TODO: extending to other datasets. +supported_formats = {} + + +class PathBuilder(object): + @classmethod + def build(cls, video_dirs, feature_dir, ext, shards=0, split=None): + meta_fn = os.path.join(feature_dir, "meta_plan.json") + os.makedirs(feature_dir, exist_ok=True) + if os.path.isfile(meta_fn): + with open(meta_fn) as fr: + meta = json.load(fr) + return meta + print("searching videos...") + + video_id_to_path = {} + for video_dir in video_dirs.split(","): + # TODO: add supports of recursive listdir. + if video_dir in supported_formats: + supported_formats[video_dir].load(video_dir, video_id_to_path) + else: + for idx, fn in enumerate(tqdm(os.listdir(video_dir))): + video_fn = os.path.join(video_dir, fn) + if os.path.isfile(video_fn): + video_id = os.path.splitext(fn)[0] + video_id_to_path[video_id] = video_fn + elif os.path.isdir(video_fn): + # shards of folders. + shard_dir = video_fn + for idx, fn in enumerate(os.listdir(shard_dir)): + video_fn = os.path.join(shard_dir, fn) + if os.path.isfile(video_fn): + video_id = os.path.splitext(fn)[0] + video_id_to_path[video_id] = video_fn + + video_path, feature_path = [], [] + valid_ext = set() + for idx, video_id in enumerate(video_id_to_path): + video_path.append(video_id_to_path[video_id]) + if ext is None: + # use original file ext for format compatibility. + video_id_to_path[video_id] + path = urllib.parse.urlparse(video_id_to_path[video_id]).path + ext = os.path.splitext(path)[1] + if ext not in valid_ext: + valid_ext.add(ext) + print("adding", ext) + if shards: + shard_id = str(idx % shards) + feature_fn = os.path.join( + feature_dir, shard_id, video_id + ext) + else: + feature_fn = os.path.join( + feature_dir, video_id + ext) + feature_path.append(feature_fn) + + print("targeting", len(feature_path), "videos") + meta = { + "video_path": video_path, "feature_path": feature_path} + with open(meta_fn, "w") as fw: + json.dump(meta, fw) + + if split is not None: + splits = split.split("/") + assert len(splits) == 2 + cur, total = int(splits[0]), int(splits[1]) + assert cur < total + import math + chunk = math.ceil(len(meta["video_path"]) / total) + start = cur * chunk + end = (cur + 1) * chunk + meta = { + "video_path": meta["video_path"][start:end], + "feature_path": meta["feature_path"][start:end] + } + + return meta diff --git a/examples/MMPT/scripts/video_feature_extractor/preprocessing.py b/examples/MMPT/scripts/video_feature_extractor/preprocessing.py new file mode 100755 index 0000000000..fa0cec3a76 --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/preprocessing.py @@ -0,0 +1,57 @@ +# Copyright Howto100m authors. +# Copyright (c) Facebook, Inc. All Rights Reserved + +import torch as th + +class Normalize(object): + + def __init__(self, mean, std): + self.mean = th.FloatTensor(mean).view(1, 3, 1, 1) + self.std = th.FloatTensor(std).view(1, 3, 1, 1) + + def __call__(self, tensor): + tensor = (tensor - self.mean) / (self.std + 1e-8) + return tensor + +class Preprocessing(object): + + def __init__(self, type): + self.type = type + if type == '2d': + self.norm = Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + elif type == '3d': + self.norm = Normalize(mean=[110.6, 103.2, 96.3], std=[1.0, 1.0, 1.0]) + elif type == 'vmz': + self.norm = Normalize(mean=[110.201, 100.64, 95.997], std=[58.1489, 56.4701, 55.3324]) + + def _zero_pad(self, tensor, size): + n = size - len(tensor) % size + if n == size: + return tensor + else: + z = th.zeros(n, tensor.shape[1], tensor.shape[2], tensor.shape[3]) + return th.cat((tensor, z), 0) + + def __call__(self, tensor): + if self.type == '2d': + tensor = tensor / 255.0 + tensor = self.norm(tensor) + elif self.type == 'vmz': + #tensor = self._zero_pad(tensor, 8) + tensor = self._zero_pad(tensor, 10) + tensor = self.norm(tensor) + #tensor = tensor.view(-1, 8, 3, 112, 112) + tensor = tensor.view(-1, 10, 3, 112, 112) + tensor = tensor.transpose(1, 2) + elif self.type == '3d': + tensor = self._zero_pad(tensor, 16) + tensor = self.norm(tensor) + tensor = tensor.view(-1, 16, 3, 112, 112) + tensor = tensor.transpose(1, 2) + elif self.type == 's3d': + tensor = tensor / 255.0 + tensor = self._zero_pad(tensor, 30) + tensor = tensor.view(-1, 30, 3, 224, 224) # N x 30 x 3 x H x W + tensor = tensor.transpose(1, 2) # N x 3 x 30 x H x W + # for vae do nothing + return tensor diff --git a/examples/MMPT/scripts/video_feature_extractor/random_sequence_shuffler.py b/examples/MMPT/scripts/video_feature_extractor/random_sequence_shuffler.py new file mode 100755 index 0000000000..1f3e4aceaa --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/random_sequence_shuffler.py @@ -0,0 +1,29 @@ +# Copyright (c) Facebook, Inc. All Rights Reserved + +import numpy as np + +from torch.utils.data.sampler import Sampler + + +class RandomSequenceSampler(Sampler): + + def __init__(self, n_sample, seq_len): + self.n_sample = n_sample + self.seq_len = seq_len + + def _pad_ind(self, ind): + zeros = np.zeros(self.seq_len - self.n_sample % self.seq_len) + ind = np.concatenate((ind, zeros)) + return ind + + def __iter__(self): + idx = np.arange(self.n_sample) + if self.n_sample % self.seq_len != 0: + idx = self._pad_ind(idx) + idx = np.reshape(idx, (-1, self.seq_len)) + np.random.shuffle(idx) + idx = np.reshape(idx, (-1)) + return iter(idx.astype(int)) + + def __len__(self): + return self.n_sample + (self.seq_len - self.n_sample % self.seq_len) diff --git a/examples/MMPT/scripts/video_feature_extractor/shard_feature.py b/examples/MMPT/scripts/video_feature_extractor/shard_feature.py new file mode 100644 index 0000000000..f75e1dfae5 --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/shard_feature.py @@ -0,0 +1,64 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import numpy as np +import os +import pickle + +from mmpt.utils import ShardedTensor + + +class Shard(object): + def __init__( + self, + vfeat_dir, + tfeat_dir, + target_dir, + file_paths, + shard_size=4096 + ): + self.vfeat_dir = vfeat_dir + self.tfeat_dir = tfeat_dir + self.target_dir = target_dir + self.video_ids = {} + for split, file_path in zip(["train", "val"], file_paths): + with open(file_path) as fr: + self.video_ids[split] = [ + line.strip() for line in fr.readlines()] + self.shard_size = shard_size + + def __call__(self, split="train"): + for split in ["train", "val"]: + meta = {} + for shard_idx, shard_offset in enumerate( + range(0, len(self.video_ids[split]), self.shard_size) + ): + print(shard_idx) + meta_shard = [] + video_shard = [] + for video_id in self.video_ids[split][shard_offset:shard_offset+self.shard_size]: + meta_shard.append(video_id) + npy_file = os.path.join(self.vfeat_dir, video_id + ".npy") + video_shard.append(np.load(npy_file)) + + meta[shard_idx] = meta_shard + video_shard = ShardedTensor.from_list(video_shard) + target_path = os.path.join( + self.target_dir, split + "_" + str(shard_idx)) + video_shard.save(target_path) + + target_path = os.path.join(self.target_dir, split + "_meta") + with open(target_path + ".pkl", "wb") as fw: + pickle.dump(meta, fw, pickle.HIGHEST_PROTOCOL) + + +if __name__ == "__main__": + shard = Shard( + "data/feat/feat_how2_s3d", + "data/how2/raw_caption_dedup.bert-base-uncased", + "data/feat/feat_how2_s3d_shard_small", + ["data/how2/how2_s3d_train.lst", "data/how2/how2_s3d_val.lst"] + ) + + shard() diff --git a/examples/MMPT/scripts/video_feature_extractor/videoreader.py b/examples/MMPT/scripts/video_feature_extractor/videoreader.py new file mode 100644 index 0000000000..429e05f8bc --- /dev/null +++ b/examples/MMPT/scripts/video_feature_extractor/videoreader.py @@ -0,0 +1,242 @@ +# Copyright Howto100M authors. +# Copyright (c) Facebook, Inc. All Rights Reserved + +import torch as th +import pandas as pd +import os +import numpy as np +import ffmpeg +import random + +from torch.utils.data import Dataset + + +class VideoLoader(Dataset): + """modified from how2's video_feature_extractor.""" + def __init__( + self, + csv=None, + video_dict=None, + framerate=1, + size=112, + centercrop=False, + hflip=False, + **kwargs + ): + if csv is None and video_dict is None: + raise ValueError("csv and video_dict cannot be both None.") + if csv is not None: + self.csv = pd.read_csv(csv) + if video_dict is not None: + self.csv = pd.DataFrame.from_dict(video_dict) + + self.centercrop = centercrop + self.size = size + self.framerate = framerate + self.hflip = hflip + + def __len__(self): + return len(self.csv) + + def _get_video_dim(self, video_path): + probe = ffmpeg.probe(video_path) + video_stream = next((stream for stream in probe['streams'] + if stream['codec_type'] == 'video'), None) + width = int(video_stream['width']) + height = int(video_stream['height']) + return height, width + + def _get_video_info(self, video_path): + probe = ffmpeg.probe(video_path) + video_stream = next((stream for stream in probe['streams'] + if stream['codec_type'] == 'video'), None) + return video_stream + + def _get_output_dim(self, h, w): + if isinstance(self.size, tuple) and len(self.size) == 2: + return self.size + elif h >= w: + return int(h * self.size / w), self.size + else: + return self.size, int(w * self.size / h) + + def __getitem__(self, idx): + video_path = self.csv['video_path'].values[idx] + output_file = self.csv['feature_path'].values[idx] + return self._decode(output_file, video_path) + + def _decode(self, output_file, video_path): + if not(os.path.isfile(output_file)) and os.path.isfile(video_path): + try: + h, w = self._get_video_dim(video_path) + except Exception: + print('ffprobe failed at: {}'.format(video_path)) + return {'video': th.zeros(1), 'input': video_path, + 'output': output_file} + try: + os.makedirs(os.path.dirname(output_file), exist_ok=True) + height, width = self._get_output_dim(h, w) + + cmd = ( + ffmpeg + .input(video_path) + .filter('fps', fps=self.framerate) + .filter('scale', width, height) + ) + if self.hflip: + cmd = cmd.filter('hflip') + + if self.centercrop: + x = int((width - self.size) / 2.0) + y = int((height - self.size) / 2.0) + cmd = cmd.crop(x, y, self.size, self.size) + video = self._run(cmd, output_file) + except Exception: + video = th.zeros(1) + else: + video = th.zeros(1) + + return {'video': video, 'input': video_path, 'output': output_file} + + def _run(self, cmd, output_file): + out, _ = ( + cmd.output('pipe:', format='rawvideo', pix_fmt='rgb24') + .run(capture_stdout=True, quiet=True) + ) + if self.centercrop and isinstance(self.size, int): + height, width = self.size, self.size + video = np.frombuffer(out, np.uint8).reshape([-1, height, width, 3]) + video = th.from_numpy(video.astype('float32')) + return video.permute(0, 3, 1, 2) + + +class VideoVerifier(VideoLoader): + def __getitem__(self, idx): + video_path = self.csv['video_path'].values[idx] + try: + return self._get_video_info(video_path) + except Exception: + # print('ffprobe failed at: {}'.format(video_path)) + return None + + +class VideoCompressor(VideoLoader): + def __init__( + self, + csv=None, + video_dict=None, + framerate=1, + size=112, + centercrop=False, + hflip=False, + crf=32, + **kwargs + ): + super().__init__( + csv, + video_dict, + framerate, + size, + centercrop, + hflip + ) + self.crf = crf + + def _run(self, cmd, output_file): + out, _ = ( + cmd.output(filename=output_file, crf=self.crf) + .run(quiet=True) + ) + video = None + return video + + +class VideoDownloader(VideoCompressor): + """download""" + def __getitem__(self, idx): + video_path = self.csv['video_path'].values[idx] + output_file = self.csv['feature_path'].values[idx] + if not(os.path.isfile(output_file)): + os.makedirs(os.path.dirname(output_file), exist_ok=True) + cmd = "wget -O" + output_file + " " + video_path + # import subprocess + # subprocess.check_output( + # cmd, + # stderr=subprocess.STDOUT, shell=True) + os.system(cmd) + return {'video': None, 'input': video_path, 'output': output_file} + + +class AvKeyframeVideoCompressor(VideoLoader): + """extract keyframes from a video and save it as jpg. + TODO: consider to merge with `CodecProcessor`. + """ + def __init__( + self, + csv=None, + video_dict=None, + framerate=1, + size=112, + centercrop=False, + max_num_frames=5, + **kwargs + ): + super().__init__(csv, video_dict, framerate, size, centercrop) + self.max_num_frames = max_num_frames + + def _get_video_dim(self, video_fn): + """decord cannot probe the size of a video, we use pyav instead.""" + import av + with av.open(video_fn) as container: + height = container.streams.video[0].codec_context.height + width = container.streams.video[0].codec_context.width + return height, width + + def _get_output_dim(self, height, width): + """ + keep the shorter side be `self.size`, strech the other. + """ + if height >= width: + return int(height * self.size / width), self.size + else: + return self.size, int(width * self.size / height) + + def __getitem__(self, idx): + import av + video_path = self.csv['video_path'].values[idx] + output_file = self.csv['feature_path'].values[idx] + if not(os.path.isdir(output_file)) and os.path.isfile(video_path): + try: + h, w = self._get_video_dim(video_path) + except Exception: + print('probe failed at: {}'.format(video_path)) + return {'video': th.zeros(1), 'input': video_path, + 'output': output_file} + + try: + height, width = self._get_output_dim(h, w) + + # new for av. + with av.open(video_path) as container: + container.streams.video[0].thread_type = "AUTO" + container.streams.video[0].codec_context.height = height + container.streams.video[0].codec_context.width = width + if self.framerate == 0: # keyframe. + container.streams.video[0].codec_context.skip_frame = 'NONKEY' + frames = [] + for frame in container.decode(video=0): + frames.append(frame) + frames = random.sample(frames, self.max_num_frames) + + os.makedirs(output_file, exist_ok=True) + for frame in frames: + frame.to_image().save( + os.path.join( + output_file, + "%04d.jpg" % frame.index)) + except Exception: + print('extract failed at: {}'.format(video_path)) + return {'video': th.zeros(1), 'input': video_path, + 'output': output_file} + video = th.zeros(1) + return {'video': video, 'input': video_path, 'output': output_file} diff --git a/examples/MMPT/setup.py b/examples/MMPT/setup.py new file mode 100644 index 0000000000..a9a82296ea --- /dev/null +++ b/examples/MMPT/setup.py @@ -0,0 +1,24 @@ +import setuptools + +with open("README.md", "r") as fh: + long_description = fh.read() + +setuptools.setup( + name="mmpt", + version="0.0.1", + author="Hu Xu, Po-yao Huang", + author_email="huxu@fb.com", + description="A package for multimodal pretraining.", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/pytorch/fairseq/examples/MMPT", + packages=setuptools.find_packages(), + install_requires=[ + ], + classifiers=[ + "Programming Language :: Python :: 3", + "License :: CC-BY-NC", + "Operating System :: OS Independent", + ], + python_requires='>=3.6', +) diff --git a/examples/MMPT/videoclip.png b/examples/MMPT/videoclip.png new file mode 100644 index 0000000000000000000000000000000000000000..50dd0abfe4ebf705a0730d79f92d709dfd366528 GIT binary patch literal 385871 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%0A0FznKF}{Ua&!$yVZbq}Hx{5uU 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 QjZJa=FNX<5RE<gANM=8Dy0lOu_~`W|Ges_!WZ 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≫GySvdjeSyS&G+Dw?gk^9zRD>xd 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�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 wwwZtPS0*6^=<(@vKQ{z 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 literal 0 HcmV?d00001 diff --git a/examples/MMPT/vlm.png b/examples/MMPT/vlm.png new file mode 100644 index 0000000000000000000000000000000000000000..55c97dbc9fc7079ff1e5a33107404292b950df96 GIT binary patch literal 418405 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�NFI&|;1{@`qS{SSod7FZWrji1A|A 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μ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Œ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%0Axy2CsnJNq0YniLWU5s{!$kd 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 A{r~^~ literal 0 HcmV?d00001 From 72bb4447d7e87664ae98c576cb7272446a5cc038 Mon Sep 17 00:00:00 2001 From: Juan Miguel Pino <juancarabina@fb.com> Date: Fri, 1 Oct 2021 19:20:05 -0700 Subject: [PATCH 467/774] Bug fix for speech translation data preparation (#3921) Summary: Bug introduced in https://github.com/pytorch/fairseq/commit/d974c709bf57cf494738a824a1597e1886bebb7a I believe. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3921 Reviewed By: kahne Differential Revision: D31296530 Pulled By: jmp84 fbshipit-source-id: cd24728ef06575853579496a9062c3dbd5dd2e93 --- examples/speech_to_text/data_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index 41afac0bf8..07d24f8d22 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -83,7 +83,7 @@ def extract_fbank_features( _waveform = convert_waveform(waveform, sample_rate, to_mono=True) # Kaldi compliance: 16-bit signed integers _waveform = _waveform * (2 ** 15) - _waveform = _waveform.numpy() + _waveform = _waveform[0].numpy() features = _get_kaldi_fbank(_waveform, sample_rate, n_mel_bins) if features is None: From 35cc605b861e368b1e1839d568489cfed6aeae1e Mon Sep 17 00:00:00 2001 From: Jerry Zhang <jerryzh@fb.com> Date: Mon, 4 Oct 2021 22:05:01 -0700 Subject: [PATCH 468/774] torch.quantization --> torch.ao.quantization in deeplearning/projects/fairseq-py Summary: codemod -m -d $dir --extensions py \ 'torch.quantization' \ 'torch.ao.quantization' Reviewed By: z-a-f Differential Revision: D31294192 fbshipit-source-id: fcad50d07a8397fc2ab8fd7188ab338f51f3ba10 --- fairseq/models/speech_to_text/modules/emformer.py | 8 ++++---- fairseq/modules/quantization/scalar/ops.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fairseq/models/speech_to_text/modules/emformer.py b/fairseq/models/speech_to_text/modules/emformer.py index 6ef76bd012..6233546ab8 100644 --- a/fairseq/models/speech_to_text/modules/emformer.py +++ b/fairseq/models/speech_to_text/modules/emformer.py @@ -27,7 +27,7 @@ layer_norm_backward_hook, ) from torch import Tensor, device as Device -from torch.quantization.qconfig import ( +from torch.ao.quantization.qconfig import ( default_dynamic_qconfig, per_channel_dynamic_qconfig, ) @@ -140,7 +140,7 @@ def quantize_(self, params=None): qconfig = per_channel_dynamic_qconfig else: qconfig = default_dynamic_qconfig - torch.quantization.quantize_dynamic( + torch.ao.quantization.quantize_dynamic( self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True ) return self @@ -728,7 +728,7 @@ def quantize_(self, params=None): qconfig = per_channel_dynamic_qconfig else: qconfig = default_dynamic_qconfig - torch.quantization.quantize_dynamic( + torch.ao.quantization.quantize_dynamic( self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True ) return self @@ -1771,7 +1771,7 @@ def quantize_(self, params=None): qconfig = per_channel_dynamic_qconfig else: qconfig = default_dynamic_qconfig - torch.quantization.quantize_dynamic( + torch.ao.quantization.quantize_dynamic( self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True ) return self diff --git a/fairseq/modules/quantization/scalar/ops.py b/fairseq/modules/quantization/scalar/ops.py index c74f530380..9144083ac7 100644 --- a/fairseq/modules/quantization/scalar/ops.py +++ b/fairseq/modules/quantization/scalar/ops.py @@ -21,7 +21,7 @@ def quantize(w, scale, zero_point, bits=8): def emulate_int8_histogram(w, scale=None, zero_point=None, bits=8): if scale is None: - obs = torch.quantization.observer.HistogramObserver() + obs = torch.ao.quantization.observer.HistogramObserver() obs.to(device=w.device) _ = obs(w.float()) scale, zero_point = obs.calculate_qparams() @@ -32,7 +32,7 @@ def emulate_int8_histogram(w, scale=None, zero_point=None, bits=8): def emulate_int8_channel(w, scale=None, zero_point=None, bits=8): if scale is None: - obs = torch.quantization.observer.PerChannelMinMaxObserver( + obs = torch.ao.quantization.observer.PerChannelMinMaxObserver( ch_axis=-1, qscheme=torch.per_channel_symmetric ) obs.to(device=w.device) @@ -45,7 +45,7 @@ def emulate_int8_channel(w, scale=None, zero_point=None, bits=8): def emulate_int8_tensor(w, scale=None, zero_point=None, bits=8): if scale is None: - obs = torch.quantization.observer.MinMaxObserver() + obs = torch.ao.quantization.observer.MinMaxObserver() obs.to(device=w.device) _ = obs(w) scale, zero_point = obs.calculate_qparams() From 6639842016877d969b5ef5125145a860806ddd73 Mon Sep 17 00:00:00 2001 From: Qiantong Xu <qx57@cornell.edu> Date: Tue, 5 Oct 2021 18:30:41 -0700 Subject: [PATCH 469/774] zero-shot model release (#2407) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? zero-shot model release ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2407 Reviewed By: alexeib Differential Revision: D31417241 Pulled By: xuqiantong fbshipit-source-id: 576644694638d3b2606f1751b74feb0531b50eb7 --- README.md | 3 +++ examples/wav2vec/README.md | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dd68717480..232d3408f9 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,10 @@ We provide reference implementations of various sequence modeling papers: + [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) + [Deep Transformers with Latent Depth (Li et al., 2020)](examples/latent_depth/README.md) + [Unsupervised Cross-lingual Representation Learning for Speech Recognition (Conneau et al., 2020)](https://arxiv.org/abs/2006.13979) + + [Self-training and Pre-training are Complementary for Speech Recognition (Xu et al., 2020)](https://arxiv.org/abs/2010.11430) + [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027) + [Unsupervised Speech Recognition (Baevski, et al., 2021)](https://arxiv.org/abs/2105.11084) + + [Simple and Effective Zero-shot Cross-lingual Phoneme Recognition (Xu et al., 2021)](https://arxiv.org/abs/2109.11680) * **Non-autoregressive Transformers** + Non-Autoregressive Neural Machine Translation (Gu et al., 2017) + Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement (Lee et al. 2018) @@ -64,6 +66,7 @@ We provide reference implementations of various sequence modeling papers: ### What's New: +* October 2021 [Released multilingual finetuned XLSR-53 model](examples/wav2vec/README.md) * September 2021 [`master` branch renamed to `main`](https://github.com/github/renaming). * July 2021 [Released DrNMT code](examples/discriminative_reranking_nmt/README.md) * July 2021 [Released Robust wav2vec 2.0 model](examples/wav2vec/README.md) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 253c8af251..7d7c0d71ce 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -6,7 +6,10 @@ We learned speech representations in multiple languages as well in [Unsupervised We also combined wav2vec 2.0 with self-training in [Self-training and Pre-training are Complementary for Speech Recognition (Xu et al., 2020)](https://arxiv.org/abs/2010.11430). -We combined speech data from multiple domains in [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027) +We combined speech data from multiple domains in [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027). + +We finetuned XLSR-53 on multiple languages to transcribe unseen languages in [Simple and Effective Zero-shot Cross-lingual Phoneme Recognition (Xu et al., 2021)](https://arxiv.org/abs/2109.11680). + ## Pre-trained models @@ -48,6 +51,14 @@ The XLSR model uses the following datasets for multilingual pretraining: * **[Babel](https://catalog.ldc.upenn.edu/byyear)** (17 languages, 1.7k hours): *Assamese, Bengali, Cantonese, Cebuano, Georgian, Haitian, Kazakh, Kurmanji, Lao, Pashto, Swahili, Tagalog, Tamil, Tok, Turkish, Vietnamese, Zulu* +We also finetuned XLSR-53 on languages from [CommonVoice](https://commonvoice.mozilla.org/en/languages) version 6.1. Please refer to [our paper](https://arxiv.org/abs/2109.11680) for details about which languages are used. + +Pretrained Model | Fintune Dataset | # Languages | Phonemizer | Model | Dictionary +|---|---|---|---|---|--- +XLSR-53 | CommonVoice | 26 | [Espeak](https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md) | [download](https://dl.fbaipublicfiles.com/fairseq/zero_shot/espeak_26lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_dict.txt) +XLSR-53 | CommonVoice | 21 | [Phonetisaurus](https://github.com/AdolfVonKleist/Phonetisaurus) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_21lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_dict.txt) + +We release 2 models that are finetuned on data from 2 different phonemizers. Although the phonemes are all [IPA](https://en.wikipedia.org/wiki/International_Phonetic_Alphabet) symbols, there are still subtle differences between the phonemized transcriptions from the 2 phonemizers. Thus, it's better to use the corresponding model, if your data is phonemized by either phonemizer above. ## Training a new model with the CLI tools From dd3bd3c0497ae9a7ae7364404a6b0a4c501780b3 Mon Sep 17 00:00:00 2001 From: Qiantong Xu <qx57@cornell.edu> Date: Tue, 5 Oct 2021 21:19:16 -0700 Subject: [PATCH 470/774] fix model link (#2408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2408 Reviewed By: alexeib Differential Revision: D31422844 Pulled By: xuqiantong fbshipit-source-id: 348050118621de922c08632ca7f31dedba109da1 --- examples/wav2vec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 7d7c0d71ce..b48d42af9a 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -55,7 +55,7 @@ We also finetuned XLSR-53 on languages from [CommonVoice](https://commonvoice.mo Pretrained Model | Fintune Dataset | # Languages | Phonemizer | Model | Dictionary |---|---|---|---|---|--- -XLSR-53 | CommonVoice | 26 | [Espeak](https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md) | [download](https://dl.fbaipublicfiles.com/fairseq/zero_shot/espeak_26lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_dict.txt) +XLSR-53 | CommonVoice | 26 | [Espeak](https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_26lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_dict.txt) XLSR-53 | CommonVoice | 21 | [Phonetisaurus](https://github.com/AdolfVonKleist/Phonetisaurus) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_21lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_dict.txt) We release 2 models that are finetuned on data from 2 different phonemizers. Although the phonemes are all [IPA](https://en.wikipedia.org/wiki/International_Phonetic_Alphabet) symbols, there are still subtle differences between the phonemized transcriptions from the 2 phonemizers. Thus, it's better to use the corresponding model, if your data is phonemized by either phonemizer above. From ecea95c063df96fc7ca3032a5ced2158417d57b0 Mon Sep 17 00:00:00 2001 From: Rengan Xu <renganxu@fb.com> Date: Wed, 6 Oct 2021 16:48:08 -0700 Subject: [PATCH 471/774] Alignment train optimization (#2200) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2200 The expected alignment for p-choose is the performance bottleneck that needs to be optimized. The solution is to implement a custom operator to reduce the kernel launch overhead, and optimize the implementations of some operations. Some key optimizations: * Use a contiguous alpha array to avoid array concatenation. The original version create an array for each slice of alpha and concat them in the end. * Implement cumprod using prod operation directly. It used log-cumsum-exp operations before. * Implement cumprod using cuda CUB library which is more efficient than scan operation in pytorch. Reviewed By: cndn Differential Revision: D30033767 fbshipit-source-id: 853c1c2d366838d6bcfa0863999f217a394e46a7 --- examples/operators/alignment_train_cpu.cpp | 166 ++++++++ examples/operators/alignment_train_cuda.cpp | 31 ++ examples/operators/alignment_train_cuda.h | 16 + examples/operators/alignment_train_kernel.cu | 354 ++++++++++++++++++ examples/operators/utils.h | 19 + .../tests/test_alignment_train.py | 88 +++++ .../utils/monotonic_attention.py | 32 +- setup.py | 15 +- 8 files changed, 695 insertions(+), 26 deletions(-) create mode 100644 examples/operators/alignment_train_cpu.cpp create mode 100644 examples/operators/alignment_train_cuda.cpp create mode 100644 examples/operators/alignment_train_cuda.h create mode 100644 examples/operators/alignment_train_kernel.cu create mode 100644 examples/operators/utils.h create mode 100644 examples/simultaneous_translation/tests/test_alignment_train.py diff --git a/examples/operators/alignment_train_cpu.cpp b/examples/operators/alignment_train_cpu.cpp new file mode 100644 index 0000000000..13c015308e --- /dev/null +++ b/examples/operators/alignment_train_cpu.cpp @@ -0,0 +1,166 @@ +/** + * Copyright 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include <torch/extension.h> // @manual=//caffe2:torch_extension +#include <algorithm> + +namespace { + +template <typename T> +void exclusiveCumprod( + const T* p_choose, + T* cumprod_1mp, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len) { + // cumprod_1mp = 1 - p_choose + for (uint32_t b = 0; b < bsz; b++) { + for (uint32_t tgt = 0; tgt < tgt_len; tgt++) { + for (uint32_t src = 0; src < src_len; src++) { + uint32_t idx = b * tgt_len * src_len + tgt * src_len + src; + cumprod_1mp[idx] = 1 - p_choose[idx]; + } + } + } + + // Implementing exclusive cumprod in the innermost dimension + // cumprod_1mp = cumprod(1 - p_choose) + // There is cumprod in pytorch, however there is no exclusive mode. + // cumprod(x) = [x1, x1x2, x2x3x4, ..., prod_{i=1}^n x_i] + // exclusive means + // cumprod(x) = [1, x1, x1x2, x1x2x3, ..., prod_{i=1}^{n-1} x_i] + for (uint32_t b = 0; b < bsz; b++) { + for (uint32_t tgt = 0; tgt < tgt_len; tgt++) { + uint32_t idx_offset = b * tgt_len * src_len + tgt * src_len; + T prev = cumprod_1mp[idx_offset]; + // index [b][tgt][0] + cumprod_1mp[idx_offset] = (T)1.0; + T curr; + for (uint32_t src = 1; src < src_len; src++) { + uint32_t idx = idx_offset + src; + curr = cumprod_1mp[idx]; + cumprod_1mp[idx] = cumprod_1mp[idx - 1] * prev; + prev = curr; + } + } + } +} + +template <typename T> +void clamp( + const T* cumprod_1mp, + T* cumprod_1mp_clamp, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len, + T min_val, + T max_val) { + for (uint32_t b = 0; b < bsz; b++) { + for (uint32_t tgt = 0; tgt < tgt_len; tgt++) { + for (uint32_t src = 0; src < src_len; src++) { + uint32_t idx = b * tgt_len * src_len + tgt * src_len + src; + if (cumprod_1mp[idx] < min_val) { + cumprod_1mp_clamp[idx] = min_val; + } else if (cumprod_1mp[idx] > max_val) { + cumprod_1mp_clamp[idx] = max_val; + } else { + cumprod_1mp_clamp[idx] = cumprod_1mp[idx]; + } + } + } + } +} + +template <typename T> +void alignmentTrainCPUImpl( + const T* p_choose, + T* alpha, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len, + float eps) { + // p_choose: bsz , tgt_len, src_len + // cumprod_1mp: bsz , tgt_len, src_len + // cumprod_1mp_clamp : bsz, tgt_len, src_len + // alpha: bsz + 1, tgt_len, src_len + + uint32_t elements = bsz * tgt_len * src_len; + T* cumprod_1mp = new T[elements]; + T* cumprod_1mp_clamp = new T[elements]; + + exclusiveCumprod<T>(p_choose, cumprod_1mp, bsz, tgt_len, src_len); + clamp<T>( + cumprod_1mp, cumprod_1mp_clamp, bsz, tgt_len, src_len, (T)eps, (T)1.0); + + // ai = p_i * cumprod(1 − pi) * cumsum(a_i / cumprod(1 − pi)) + + // Initialize alpha [:, 0, 0] + for (uint32_t b = 0; b < bsz; b++) { + alpha[b * tgt_len * src_len] = 1.0; + } + + for (uint32_t tgt = 0; tgt < tgt_len; tgt++) { + for (uint32_t b = 0; b < bsz; b++) { + uint32_t alpha_idx, inout_idx; + T prev_scan = 0, curr_scan, out; + for (uint32_t src = 0; src < src_len; src++) { + // Apply scan/cumsum + if (tgt == 0) { + // alpha index is [b][tgt][src] + alpha_idx = b * tgt_len * src_len + src; + } else { + // alpha index is [b][tgt-1][src] + alpha_idx = b * tgt_len * src_len + (tgt - 1) * src_len + src; + } + // input index is [b][tgt][src] + inout_idx = b * tgt_len * src_len + tgt * src_len + src; + curr_scan = prev_scan + alpha[alpha_idx] / cumprod_1mp_clamp[inout_idx]; + + out = curr_scan * p_choose[inout_idx] * cumprod_1mp[inout_idx]; + alpha[inout_idx] = std::min<T>(std::max<T>(out, 0), 1.0); + prev_scan = curr_scan; + } + } + } + + free(cumprod_1mp); + free(cumprod_1mp_clamp); +} + +void alignmentTrainCPU( + const torch::Tensor& p_choose, + torch::Tensor& alpha, + float eps) { + uint32_t bsz = p_choose.size(0); + uint32_t tgt_len = p_choose.size(1); + uint32_t src_len = p_choose.size(2); + + AT_DISPATCH_FLOATING_TYPES_AND2( + torch::ScalarType::Half, + torch::ScalarType::BFloat16, + p_choose.scalar_type(), + "alignmentCPUImpl", + [&]() { + alignmentTrainCPUImpl<scalar_t>( + p_choose.data_ptr<scalar_t>(), + alpha.data_ptr<scalar_t>(), + bsz, + tgt_len, + src_len, + eps); + }); +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def( + "alignment_train_cpu", + &alignmentTrainCPU, + "expected_alignment_from_p_choose (CPU)"); +} + +} // namespace diff --git a/examples/operators/alignment_train_cuda.cpp b/examples/operators/alignment_train_cuda.cpp new file mode 100644 index 0000000000..430e048139 --- /dev/null +++ b/examples/operators/alignment_train_cuda.cpp @@ -0,0 +1,31 @@ +/** + * Copyright 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "alignment_train_cuda.h" +#include "utils.h" + +namespace { + +void alignmentTrainCUDA( + const torch::Tensor& p_choose, + torch::Tensor& alpha, + float eps) { + CHECK_INPUT(p_choose); + CHECK_INPUT(alpha); + + alignmentTrainCUDAWrapper(p_choose, alpha, eps); +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { + m.def( + "alignment_train_cuda", + &alignmentTrainCUDA, + "expected_alignment_from_p_choose (CUDA)"); +} + +} // namespace diff --git a/examples/operators/alignment_train_cuda.h b/examples/operators/alignment_train_cuda.h new file mode 100644 index 0000000000..8289d1a690 --- /dev/null +++ b/examples/operators/alignment_train_cuda.h @@ -0,0 +1,16 @@ +/** + * Copyright 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include <torch/extension.h> // @manual=//caffe2:torch_extension + +void alignmentTrainCUDAWrapper( + const torch::Tensor& p_choose, + torch::Tensor& alpha, + float eps); diff --git a/examples/operators/alignment_train_kernel.cu b/examples/operators/alignment_train_kernel.cu new file mode 100644 index 0000000000..efae7cc76f --- /dev/null +++ b/examples/operators/alignment_train_kernel.cu @@ -0,0 +1,354 @@ +/** + * Copyright 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include <ATen/ATen.h> +#include <ATen/cuda/CUDAContext.h> // @manual=//caffe2/aten:ATen-cu +#include <cuda_runtime.h> +#include <algorithm> // std::min/max +#include <cub/cub.cuh> + +#include "alignment_train_cuda.h" +#include "utils.h" + +namespace { + +// The thread block length in threads along the X dimension +constexpr int BLOCK_DIM_X = 128; +// The thread block length in threads along the Y dimension +constexpr int BLOCK_DIM_Y = 8; +// The thread block length in threads for scan operation +constexpr int SCAN_BLOCK = 512; + +#define gpuErrchk(ans) \ + { gpuAssert((ans), __FILE__, __LINE__); } + +inline void +gpuAssert(cudaError_t code, const char* file, int line, bool abort = true) { + if (code != cudaSuccess) { + fprintf( + stderr, + "\nGPUassert: %s %s %d\n", + cudaGetErrorString(code), + file, + line); + if (abort) + exit(code); + } +} + +template <typename T> +struct Prod { + /// prod operator, returns <tt>a * b</tt> + __host__ __device__ __forceinline__ T + operator()(const T& a, const T& b) const { + return a * b; + } +}; + +template <typename T> +struct BlockPrefixProdCallbackOp { + // Running prefix + T running_total; + + // Constructor + __device__ BlockPrefixProdCallbackOp(T running_total) + : running_total(running_total) {} + + // Callback operator to be entered by the first warp of threads in the block. + // Thread-0 is responsible for returning a value for seeding the block-wide + // scan. + __device__ T operator()(const T block_aggregate) { + T old_prefix = running_total; + running_total *= block_aggregate; + return old_prefix; + } +}; + +template <typename T> +struct BlockPrefixSumCallbackOp { + // Running prefix + T running_total; + + // Constructor + __device__ BlockPrefixSumCallbackOp(T running_total) + : running_total(running_total) {} + + // Callback operator to be entered by the first warp of threads in the block. + // Thread-0 is responsible for returning a value for seeding the block-wide + // scan. + __device__ T operator()(const T block_aggregate) { + T old_prefix = running_total; + running_total += block_aggregate; + return old_prefix; + } +}; + +template <typename T> +__global__ void oneMinusPKernel( + const T* __restrict__ p_choose, + T* __restrict__ cumprod_1mp, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len) { + for (uint32_t b = blockIdx.x; b < bsz; b += gridDim.x) { + for (uint32_t tgt = threadIdx.y; tgt < tgt_len; tgt += blockDim.y) { + for (uint32_t src = threadIdx.x; src < src_len; src += blockDim.x) { + uint32_t idx = b * tgt_len * src_len + tgt * src_len + src; + cumprod_1mp[idx] = 1 - p_choose[idx]; + } + } + } +} + +template <typename T, int TPB> +__global__ void innermostScanKernel( + T* __restrict__ cumprod_1mp, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len) { + for (uint32_t b = blockIdx.y; b < bsz; b += gridDim.y) { + for (uint32_t tgt = blockIdx.x; tgt < tgt_len; tgt += gridDim.x) { + // Specialize BlockScan for a 1D block of TPB threads on type T + typedef cub::BlockScan<T, TPB> BlockScan; + // Allocate shared memory for BlockScan + __shared__ typename BlockScan::TempStorage temp_storage; + // Initialize running total + BlockPrefixProdCallbackOp<T> prefix_op(1); + + const uint32_t tid = threadIdx.x; + for (uint32_t block_src = 0; block_src < src_len; + block_src += blockDim.x) { + uint32_t src = block_src + tid; + uint32_t idx = b * tgt_len * src_len + tgt * src_len + src; + T thread_data = (src < src_len) ? cumprod_1mp[idx] : (T)0; + + // Collectively compute the block-wide inclusive prefix sum + BlockScan(temp_storage) + .ExclusiveScan(thread_data, thread_data, Prod<T>(), prefix_op); + __syncthreads(); + + // write the scanned value to output + if (src < src_len) { + cumprod_1mp[idx] = thread_data; + } + } + } + } +} + +template <typename T> +__global__ void clampKernel( + const T* __restrict__ cumprod_1mp, + T* __restrict__ cumprod_1mp_clamp, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len, + T min_val, + T max_val) { + for (uint32_t b = blockIdx.x; b < bsz; b += gridDim.x) { + for (uint32_t tgt = threadIdx.y; tgt < tgt_len; tgt += blockDim.y) { + for (uint32_t src = threadIdx.x; src < src_len; src += blockDim.x) { + uint32_t idx = b * tgt_len * src_len + tgt * src_len + src; + if (cumprod_1mp[idx] < min_val) { + cumprod_1mp_clamp[idx] = min_val; + } else if (cumprod_1mp[idx] > max_val) { + cumprod_1mp_clamp[idx] = max_val; + } else { + cumprod_1mp_clamp[idx] = cumprod_1mp[idx]; + } + } + } + } +} + +template <typename T> +__global__ void initAlphaCUDAKernel( + T* alpha, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len) { + // alpha[:, 0, 0] = 1.0 + for (uint32_t b = blockIdx.x; b < bsz; b += gridDim.x) { + alpha[b * tgt_len * src_len] = (T)1.0; + } +} + +template <typename T, int TPB> +__global__ void alignmentTrainCUDAKernel( + const T* __restrict__ p_choose, + const T* __restrict__ cumprod_1mp, + const T* __restrict__ cumprod_1mp_clamp, + T* __restrict__ alpha, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len, + uint32_t tgt) { + for (uint32_t b = blockIdx.x; b < bsz; b += gridDim.x) { + // Specialize BlockScan for a 1D block of TPB threads on type T + typedef cub::BlockScan<T, TPB> BlockScan; + + // Allocate shared memory for BlockScan + __shared__ typename BlockScan::TempStorage temp_storage; + // Initialize running total + BlockPrefixSumCallbackOp<T> prefix_op(0); + + uint32_t b_offset = b * tgt_len * src_len; + const uint32_t tid = threadIdx.x; + for (uint32_t block_src = 0; block_src < src_len; block_src += blockDim.x) { + uint32_t src = block_src + tid; + // Obtain a segment of consecutive items that are blocked across threads + uint32_t inout_idx, alpha_idx; + if (tgt == 0) { + // both alpha and other input index is [b][0][src] + alpha_idx = b_offset + src; + } else { + // alpha index is [b][tgt-1][src] + alpha_idx = b_offset + (tgt - 1) * src_len + src; + } + inout_idx = b_offset + tgt * src_len + src; + T thread_data = (T)0; + if (src < src_len) { + thread_data = alpha[alpha_idx] / cumprod_1mp_clamp[inout_idx]; + } + + // Collectively compute the block-wide inclusive prefix sum + BlockScan(temp_storage).InclusiveSum(thread_data, thread_data, prefix_op); + __syncthreads(); + + if (src < src_len) { + T out = thread_data * p_choose[inout_idx] * cumprod_1mp[inout_idx]; + // Clamps all elements into the range [ 0, 1.0 ] + alpha[inout_idx] = std::min<T>(std::max<T>(out, 0), (T)1.0); + } + } + } +} + +template <typename T> +void exclusiveCumprod( + const T* p_choose, + T* cumprod_1mp, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len, + uint32_t max_grid_x, + uint32_t max_grid_y, + cudaStream_t& stream) { + // cumprod_1mp = 1 - p_choose + dim3 grid(std::min<T>(max_grid_x, bsz), 1, 1); + dim3 block(BLOCK_DIM_X, BLOCK_DIM_Y, 1); + oneMinusPKernel<T><<<grid, block, 0, stream>>>( + p_choose, cumprod_1mp, bsz, tgt_len, src_len); + gpuErrchk(cudaGetLastError()); + + // scan on the innermost dimension of cumprod_1mp + // cumprod_1mp = cumprod(cumprod_1mp) + dim3 grid_scan( + std::min<T>(max_grid_x, tgt_len), std::min<T>(max_grid_y, bsz), 1); + innermostScanKernel<T, SCAN_BLOCK><<<grid_scan, SCAN_BLOCK, 0, stream>>>( + cumprod_1mp, bsz, tgt_len, src_len); + gpuErrchk(cudaGetLastError()); +} + +template <typename T> +void alignmentTrainCUDAImpl( + const T* p_choose, + T* alpha, + uint32_t bsz, + uint32_t tgt_len, + uint32_t src_len, + float eps) { + // p_choose: bsz , tgt_len, src_len + // cumprod_1mp: bsz , tgt_len, src_len + // cumprod_1mp_clamp : bsz, tgt_len, src_len + // alpha: bsz, tgt_len, src_len + cudaStream_t stream = at::cuda::getCurrentCUDAStream(); + uint32_t max_grid_x = at::cuda::getCurrentDeviceProperties()->maxGridSize[0]; + uint32_t max_grid_y = at::cuda::getCurrentDeviceProperties()->maxGridSize[1]; + + // Implementing exclusive cumprod. + // cumprod_1mp = cumprod(1 - p_choose) + // There is cumprod in pytorch, however there is no exclusive mode. + // cumprod(x) = [x1, x1x2, x2x3x4, ..., prod_{i=1}^n x_i] + // exclusive means + // cumprod(x) = [1, x1, x1x2, x1x2x3, ..., prod_{i=1}^{n-1} x_i] + uint32_t elements = bsz * tgt_len * src_len; + T* cumprod_1mp; + gpuErrchk(cudaMalloc(&cumprod_1mp, elements * sizeof(T))); + exclusiveCumprod<T>( + p_choose, + cumprod_1mp, + bsz, + tgt_len, + src_len, + max_grid_x, + max_grid_y, + stream); + + // clamp cumprod_1mp to the range [eps, 1.0] + T* cumprod_1mp_clamp; + gpuErrchk(cudaMalloc(&cumprod_1mp_clamp, elements * sizeof(T))); + dim3 grid_clamp(std::min<T>(max_grid_x, bsz), 1, 1); + dim3 block_clamp(BLOCK_DIM_X, BLOCK_DIM_Y, 1); + clampKernel<T><<<grid_clamp, block_clamp, 0, stream>>>( + cumprod_1mp, cumprod_1mp_clamp, bsz, tgt_len, src_len, (T)eps, (T)1.0); + gpuErrchk(cudaGetLastError()); + + // ai = p_i * cumprod(1 − pi) * cumsum(a_i / cumprod(1 − pi)) + dim3 grid_init(std::min<int>(max_grid_x, bsz), 1, 1); + initAlphaCUDAKernel<T> + <<<grid_init, 1, 0, stream>>>(alpha, bsz, tgt_len, src_len); + gpuErrchk(cudaGetLastError()); + + const int grid = std::min(bsz, max_grid_x); + + for (uint32_t i = 0; i < tgt_len; i++) { + alignmentTrainCUDAKernel<T, SCAN_BLOCK><<<grid, SCAN_BLOCK, 0, stream>>>( + p_choose, + cumprod_1mp, + cumprod_1mp_clamp, + alpha, + bsz, + tgt_len, + src_len, + i); + gpuErrchk(cudaGetLastError()); + } + + gpuErrchk(cudaFree(cumprod_1mp)); + gpuErrchk(cudaFree(cumprod_1mp_clamp)); +} + +} // namespace + +void alignmentTrainCUDAWrapper( + const torch::Tensor& p_choose, + torch::Tensor& alpha, + float eps) { + // p_choose dimension: bsz, tgt_len, src_len + uint32_t bsz = p_choose.size(0); + uint32_t tgt_len = p_choose.size(1); + uint32_t src_len = p_choose.size(2); + + cudaSetDevice(p_choose.get_device()); + + AT_DISPATCH_FLOATING_TYPES_AND2( + torch::ScalarType::Half, + torch::ScalarType::BFloat16, + p_choose.scalar_type(), + "alignmentTrainCUDAImpl", + [&]() { + alignmentTrainCUDAImpl<scalar_t>( + p_choose.data_ptr<scalar_t>(), + alpha.data_ptr<scalar_t>(), + bsz, + tgt_len, + src_len, + eps); + }); +} diff --git a/examples/operators/utils.h b/examples/operators/utils.h new file mode 100644 index 0000000000..0ef5b4383f --- /dev/null +++ b/examples/operators/utils.h @@ -0,0 +1,19 @@ +/** + * Copyright 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include <torch/extension.h> // @manual=//caffe2:torch_extension + +#define CHECK_CUDA(x) \ + TORCH_CHECK(x.type().is_cuda(), #x " must be a CUDA tensor") +#define CHECK_CONTIGUOUS(x) \ + TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") +#define CHECK_INPUT(x) \ + CHECK_CUDA(x); \ + CHECK_CONTIGUOUS(x) diff --git a/examples/simultaneous_translation/tests/test_alignment_train.py b/examples/simultaneous_translation/tests/test_alignment_train.py new file mode 100644 index 0000000000..2ad4ef1f6d --- /dev/null +++ b/examples/simultaneous_translation/tests/test_alignment_train.py @@ -0,0 +1,88 @@ +import unittest + +import numpy as np +import torch + +import hypothesis.strategies as st +from hypothesis import assume, given, settings +from torch.testing._internal.common_utils import TestCase +from examples.simultaneous_translation.utils.functions import exclusive_cumprod + + +TEST_CUDA = torch.cuda.is_available() + + +class AlignmentTrainTest(TestCase): + def _test_custom_alignment_train_ref(self, p_choose, eps): + cumprod_1mp = exclusive_cumprod(1 - p_choose, dim=2, eps=eps) + cumprod_1mp_clamp = torch.clamp(cumprod_1mp, eps, 1.0) + + bsz = p_choose.size(0) + tgt_len = p_choose.size(1) + src_len = p_choose.size(2) + + alpha_0 = p_choose.new_zeros([bsz, 1, src_len]) + alpha_0[:, :, 0] = 1.0 + + previous_alpha = [alpha_0] + + for i in range(tgt_len): + # p_choose: bsz , tgt_len, src_len + # cumprod_1mp_clamp : bsz, tgt_len, src_len + # previous_alpha[i]: bsz, 1, src_len + # alpha_i: bsz, src_len + alpha_i = ( + p_choose[:, i] + * cumprod_1mp[:, i] + * torch.cumsum( + previous_alpha[i][:, 0] / cumprod_1mp_clamp[:, i], dim=1 + ) + ).clamp(0, 1.0) + + previous_alpha.append(alpha_i.unsqueeze(1)) + + # alpha: bsz * num_heads, tgt_len, src_len + alpha = torch.cat(previous_alpha[1:], dim=1) + return alpha + + def _test_custom_alignment_train_impl(self, p_choose, alpha, eps): + if p_choose.is_cuda: + from alignment_train_cuda_binding import alignment_train_cuda # @manual=//deeplearning/projects/fairseq-py:alignment_train_cuda_binding + alignment_train_cuda(p_choose, alpha, eps) + else: + from alignment_train_cpu_binding import alignment_train_cpu # @manual=//deeplearning/projects/fairseq-py:alignment_train_cpu_binding + alignment_train_cpu(p_choose, alpha, eps) + + @settings(deadline=None) + @given( + bsz=st.integers(1, 100), + tgt_len=st.integers(1, 100), + src_len=st.integers(1, 550), + device=st.sampled_from(["cpu", "cuda"]), + ) + def test_alignment_train(self, bsz, tgt_len, src_len, device): + eps = 1e-6 + + assume(device == "cpu" or TEST_CUDA) + p_choose = torch.rand(bsz, tgt_len, src_len, device=device) + + # run the alignment with the custom operator + alpha_act = p_choose.new_zeros([bsz, tgt_len, src_len]) + self._test_custom_alignment_train_impl(p_choose, alpha_act, eps) + + # runu the alignment with the ref implementation + alpha_ref = self._test_custom_alignment_train_ref(p_choose, eps) + + # verify the results + alpha_act = alpha_act.cpu().detach().numpy() + alpha_ref = alpha_ref.cpu().detach().numpy() + np.testing.assert_allclose( + alpha_act, + alpha_ref, + atol=1e-3, + rtol=1e-3, + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/examples/simultaneous_translation/utils/monotonic_attention.py b/examples/simultaneous_translation/utils/monotonic_attention.py index 61dbb112bf..3b8e0a858c 100644 --- a/examples/simultaneous_translation/utils/monotonic_attention.py +++ b/examples/simultaneous_translation/utils/monotonic_attention.py @@ -42,32 +42,14 @@ def expected_alignment_from_p_choose( if padding_mask is not None: p_choose = p_choose.masked_fill(padding_mask.unsqueeze(1), 0.0) - # cumprod_1mp : bsz, tgt_len, src_len - cumprod_1mp = exclusive_cumprod(1 - p_choose, dim=2, eps=eps) - cumprod_1mp_clamp = torch.clamp(cumprod_1mp, eps, 1.0) - - alpha_0 = p_choose.new_zeros([bsz, 1, src_len]) - alpha_0[:, :, 0] = 1.0 - - previous_alpha = [alpha_0] - - for i in range(tgt_len): - # p_choose: bsz , tgt_len, src_len - # cumprod_1mp_clamp : bsz, tgt_len, src_len - # previous_alpha[i]: bsz, 1, src_len - # alpha_i: bsz, src_len - alpha_i = ( - p_choose[:, i] - * cumprod_1mp[:, i] - * torch.cumsum( - previous_alpha[i][:, 0] / cumprod_1mp_clamp[:, i], dim=1 - ) - ).clamp(0, 1.0) - - previous_alpha.append(alpha_i.unsqueeze(1)) + if p_choose.is_cuda: + p_choose = p_choose.contiguous() + from alignment_train_cuda_binding import alignment_train_cuda as alignment_train + else: + from alignment_train_cpu_binding import alignment_train_cpu as alignment_train - # alpha: bsz * num_heads, tgt_len, src_len - alpha = torch.cat(previous_alpha[1:], dim=1) + alpha = p_choose.new_zeros([bsz, tgt_len, src_len]) + alignment_train(p_choose, alpha, eps) # Mix precision to prevent overflow for fp16 alpha = alpha.type(dtype) diff --git a/setup.py b/setup.py index 1f3998de80..4bf1e60dd1 100644 --- a/setup.py +++ b/setup.py @@ -117,7 +117,13 @@ def include_dirs(self, dirs): sources=[ "fairseq/clib/libnat/edit_dist.cpp", ], - ) + ), + cpp_extension.CppExtension( + "alignment_train_cpu_binding", + sources=[ + "examples/operators/alignment_train_cpu.cpp", + ], + ), ] ) if "CUDA_HOME" in os.environ: @@ -137,6 +143,13 @@ def include_dirs(self, dirs): "fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu", ], ), + cpp_extension.CppExtension( + "alignment_train_cuda_binding", + sources=[ + "examples/operators/alignment_train_kernel.cu", + "examples/operators/alignment_train_cuda.cpp", + ], + ), ] ) cmdclass["build_ext"] = cpp_extension.BuildExtension From ce6c9eeae163ac04b79539c78e74f292f29eaa18 Mon Sep 17 00:00:00 2001 From: Qiantong Xu <qx57@cornell.edu> Date: Thu, 7 Oct 2021 11:11:05 -0700 Subject: [PATCH 472/774] added 2 new models (#2415) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2415 Reviewed By: alexeib Differential Revision: D31455210 Pulled By: xuqiantong fbshipit-source-id: d3b45a3b60800f0fc5da0efeddbd8213dee4878f --- examples/wav2vec/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index b48d42af9a..47aad5e71b 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -51,12 +51,14 @@ The XLSR model uses the following datasets for multilingual pretraining: * **[Babel](https://catalog.ldc.upenn.edu/byyear)** (17 languages, 1.7k hours): *Assamese, Bengali, Cantonese, Cebuano, Georgian, Haitian, Kazakh, Kurmanji, Lao, Pashto, Swahili, Tagalog, Tamil, Tok, Turkish, Vietnamese, Zulu* -We also finetuned XLSR-53 on languages from [CommonVoice](https://commonvoice.mozilla.org/en/languages) version 6.1. Please refer to [our paper](https://arxiv.org/abs/2109.11680) for details about which languages are used. +We also finetuned several models on languages from [CommonVoice](https://commonvoice.mozilla.org/en/languages) (version 6.1) and [Babel](https://catalog.ldc.upenn.edu/byyear). Please refer to [our paper](https://arxiv.org/abs/2109.11680) for details about which languages are used. Pretrained Model | Fintune Dataset | # Languages | Phonemizer | Model | Dictionary |---|---|---|---|---|--- +LV-60 | CommonVoice | 26 | [Espeak](https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_en_26lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_dict.txt) XLSR-53 | CommonVoice | 26 | [Espeak](https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_26lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/espeak_dict.txt) XLSR-53 | CommonVoice | 21 | [Phonetisaurus](https://github.com/AdolfVonKleist/Phonetisaurus) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_21lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_dict.txt) +XLSR-53 | CommonVoice, BABEL | 21, 19 | [Phonetisaurus](https://github.com/AdolfVonKleist/Phonetisaurus) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_40lang_m10.pt) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/zero_shot/phonetisaurus_40lang.dict.txt) We release 2 models that are finetuned on data from 2 different phonemizers. Although the phonemes are all [IPA](https://en.wikipedia.org/wiki/International_Phonetic_Alphabet) symbols, there are still subtle differences between the phonemized transcriptions from the 2 phonemizers. Thus, it's better to use the corresponding model, if your data is phonemized by either phonemizer above. From 36eac86d6c50a24069777251cec1bd32c1271b06 Mon Sep 17 00:00:00 2001 From: erichan1 <30481032+erichan1@users.noreply.github.com> Date: Thu, 7 Oct 2021 12:16:44 -0700 Subject: [PATCH 473/774] Update README to match master->main branch change (#3922) Summary: Loading xlmr doesn't work because trying to pull from master branch, which has been changed to main. Pull Request resolved: https://github.com/pytorch/fairseq/pull/3922 Reviewed By: erichan1 Differential Revision: D31415771 Pulled By: dianaml0 fbshipit-source-id: a4b1b533b5596a4d3556c97c2f15847e444aeea9 --- examples/xlmr/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/xlmr/README.md b/examples/xlmr/README.md index b95bfe15d3..bba7910e30 100644 --- a/examples/xlmr/README.md +++ b/examples/xlmr/README.md @@ -71,7 +71,7 @@ Model | average | en | es | de | ar | hi | vi | zh ##### Load XLM-R from torch.hub (PyTorch >= 1.1): ```python import torch -xlmr = torch.hub.load('pytorch/fairseq', 'xlmr.large') +xlmr = torch.hub.load('pytorch/fairseq:main', 'xlmr.large') xlmr.eval() # disable dropout (or leave in train mode to finetune) ``` From 027fc8e77ee2f27b4250ccd0a11df4edf73ec4c2 Mon Sep 17 00:00:00 2001 From: Kushal Lakhotia <kushal.lakhotia@outreach.io> Date: Fri, 8 Oct 2021 10:02:38 -0700 Subject: [PATCH 474/774] GSLM: Fix absence of code dict file for resynthesis (#3934) Summary: # Before submitting - [ X] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ X] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ X] Did you make sure to update the docs? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3870 Pull Request resolved: https://github.com/pytorch/fairseq/pull/3934 Reviewed By: Abdel-rahmanMohamed Differential Revision: D31503773 Pulled By: wnhsu fbshipit-source-id: dfb976e2f37d25282daca20c290a718ab8c27f64 --- examples/textless_nlp/gslm/tools/README.md | 7 ++-- .../gslm/tools/resynthesize_speech.py | 36 ++++++++----------- .../gslm/unit2speech/tacotron2/utils.py | 6 +++- .../textless_nlp/gslm/unit2speech/tts_data.py | 4 ++- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/textless_nlp/gslm/tools/README.md b/examples/textless_nlp/gslm/tools/README.md index 61fcbbded8..385834841c 100644 --- a/examples/textless_nlp/gslm/tools/README.md +++ b/examples/textless_nlp/gslm/tools/README.md @@ -9,14 +9,17 @@ ACOUSTIC_MODEL_PATH=<path_of_pretrained_acoustic_model> LAYER=<layer_of_acoustic_model_to_extract_features_from> KM_MODEL_PATH=<output_path_of_the_kmeans_model> TTS_MODEL_PATH=<unit2speech_model_file_path> +# A text file containing the codes, one per line +CODE_DICT_PATH=<unit2speech_code_dict_path> WAVEGLOW_PATH=<path_where_you_have_downloaded_waveglow_checkpoint> -PYTHONPATH=${FAIRSEQ_ROOT}:${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/unit2speech python ${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/tools/gen_speech.py \ +PYTHONPATH=${FAIRSEQ_ROOT}:${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/unit2speech python ${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/tools/resynthesize_speech.py \ --feature_type $TYPE \ --acoustic_model_path $ACOUSTIC_MODEL_PATH \ --layer $LAYER \ --kmeans_model_path $KM_MODEL_PATH \ --tts_model_path $TTS_MODEL_PATH \ - --waveglow_path $WAVEGLOW_PATH \ + --code_dict_path $CODE_DICT_PATH \ + --waveglow_path $WAVEGLOW_PATH \ --max_decoder_steps 2000 ``` \ No newline at end of file diff --git a/examples/textless_nlp/gslm/tools/resynthesize_speech.py b/examples/textless_nlp/gslm/tools/resynthesize_speech.py index 2b6215d372..309877212e 100644 --- a/examples/textless_nlp/gslm/tools/resynthesize_speech.py +++ b/examples/textless_nlp/gslm/tools/resynthesize_speech.py @@ -6,16 +6,13 @@ import argparse import gc import logging +import os import joblib import soundfile as sf import torch -from examples.textless_nlp.gslm.speech2unit.pretrained.utils import ( - get_feature_reader, -) -from examples.textless_nlp.gslm.unit2speech.tts_data import ( - TacotronInputDataset, -) +from examples.textless_nlp.gslm.speech2unit.pretrained.utils import get_feature_reader +from examples.textless_nlp.gslm.unit2speech.tts_data import TacotronInputDataset from examples.textless_nlp.gslm.unit2speech.utils import ( load_tacotron, load_waveglow, @@ -31,9 +28,7 @@ def get_logger(): def get_parser(): - parser = argparse.ArgumentParser( - description="GSLM speech resynthesis tool." - ) + parser = argparse.ArgumentParser(description="GSLM U2S tool") parser.add_argument( "--feature_type", type=str, @@ -47,9 +42,7 @@ def get_parser(): type=str, help="Pretrained acoustic model checkpoint", ) - parser.add_argument( - "--layer", type=int, help="Layer of acoustic model" - ) + parser.add_argument("--layer", type=int, help="Layer of acoustic model") parser.add_argument( "--kmeans_model_path", type=str, @@ -61,6 +54,11 @@ def get_parser(): type=str, help="TTS model file path to use for inference", ) + parser.add_argument( + "--code_dict_path", + type=str, + help="Code dict file path to use for inference", + ) parser.add_argument( "--waveglow_path", type=str, @@ -97,16 +95,14 @@ def main(args, logger): waveglow, denoiser = load_waveglow(waveglow_path=args.waveglow_path) # Dataset + if not os.path.exists(hparams.code_dict): + hparams.code_dict = args.code_dict_path tts_dataset = TacotronInputDataset(hparams) iters = 0 while True: - in_file_path = input( - "Input: Enter the full file path of audio file...\n" - ) - out_file_path = input( - "Output: Enter the full file path of audio file...\n" - ) + in_file_path = input("Input: Enter the full file path of audio file...\n") + out_file_path = input("Output: Enter the full file path of audio file...\n") feats = reader.get_feats(in_file_path).cpu().numpy() iters += 1 if iters == 1000: @@ -124,9 +120,7 @@ def main(args, logger): tts_input.unsqueeze(0), strength=args.denoiser_strength, ) - sf.write( - f"{out_file_path}", aud_dn[0].cpu().float().numpy(), sample_rate - ) + sf.write(f"{out_file_path}", aud_dn[0].cpu().float().numpy(), sample_rate) logger.info("Resynthesis done!\n") diff --git a/examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py b/examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py index 66a426d222..b72ae0e35b 100644 --- a/examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py +++ b/examples/textless_nlp/gslm/unit2speech/tacotron2/utils.py @@ -1,3 +1,8 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + import collections import io import json @@ -164,4 +169,3 @@ def value(self): else: vals[k] = self.total_time[k] / self.n[k] return vals - diff --git a/examples/textless_nlp/gslm/unit2speech/tts_data.py b/examples/textless_nlp/gslm/unit2speech/tts_data.py index eb0f7c360d..d2b04c0fee 100644 --- a/examples/textless_nlp/gslm/unit2speech/tts_data.py +++ b/examples/textless_nlp/gslm/unit2speech/tts_data.py @@ -21,7 +21,9 @@ class TacotronInputDataset: def __init__(self, hparams, append_str=""): self.is_text = getattr(hparams, "text_or_code", "text") == "text" if not self.is_text: - self.code_dict = load_code_dict(hparams.code_dict) + self.code_dict = load_code_dict( + hparams.code_dict, hparams.add_sos, hparams.add_eos + ) self.code_key = hparams.code_key self.add_sos = hparams.add_sos self.add_eos = hparams.add_eos From a61107ecb5c2d212b57879d5d4167030a383d82b Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Fri, 8 Oct 2021 12:59:45 -0700 Subject: [PATCH 475/774] update code dict prep (#2424) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3930 https://github.com/pytorch/fairseq/issues/3795 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2424 Reviewed By: Abdel-rahmanMohamed Differential Revision: D31506758 Pulled By: wnhsu fbshipit-source-id: 895c0b034637f081dccb9905f38aced8a18ce5ff --- examples/hubert/README.md | 3 ++- examples/hubert/simple_kmeans/README.md | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/hubert/README.md b/examples/hubert/README.md index b501a6eb2a..f88a34dc3c 100644 --- a/examples/hubert/README.md +++ b/examples/hubert/README.md @@ -23,6 +23,7 @@ model = models[0] Follow the steps in `./simple_kmeans` to create: - `{train,valid}.tsv` waveform list files - `{train,valid}.km` frame-aligned pseudo label files. +- `dict.km.txt` a dummy dictionary The `label_rate` is the same as the feature frame rate used for clustering, which is 100Hz for MFCC features and 50Hz for HuBERT features by default. @@ -36,7 +37,7 @@ To train a base model (12 layer transformer), run: $ python fairseq_cli/hydra_train.py \ --config-dir /path/to/fairseq-py/examples/hubert/config/pretrain \ --config-name hubert_base_librispeech \ - task.data=/path/to/data task.label_dir=/path/to/labels model.label_rate=100 + task.data=/path/to/data task.label_dir=/path/to/labels task.labels='["km"]' model.label_rate=100 ``` ### Fine-tune a HuBERT model with a CTC loss diff --git a/examples/hubert/simple_kmeans/README.md b/examples/hubert/simple_kmeans/README.md index cd17da3b3e..847475c23f 100644 --- a/examples/hubert/simple_kmeans/README.md +++ b/examples/hubert/simple_kmeans/README.md @@ -69,3 +69,12 @@ for rank in $(seq 0 $((nshard - 1))); do cat $lab_dir/${split}_${rank}_${nshard}.km done > $lab_dir/${split}.km ``` + + +## Create a dummy dict +To create a dummy dictionary, run +```sh +for x in $(seq 0 $((n_clusters - 1))); do + echo "$x 1" +done >> $lab_dir/dict.km.txt +``` From 862efab86f649c04ea31545ce28d13c59560113d Mon Sep 17 00:00:00 2001 From: Hu Xu <activebus@gmail.com> Date: Sun, 10 Oct 2021 02:20:36 -0700 Subject: [PATCH 476/774] MMPT bug fixes (#2428) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes argument for `lr_scheduler.total_num_update`; missing import of `dsprocessor` for COIN; `vmasks` on demo inference; update README.md of fairseq for examples/MMPT. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2428 Reviewed By: berniebear Differential Revision: D31528947 Pulled By: howardhsu fbshipit-source-id: 1fecf34bdab82cbf6001e3905a532e4e6eb38e01 --- README.md | 4 ++- examples/MMPT/.gitignore | 1 + examples/MMPT/mmpt/models/mmfusion.py | 10 +++++-- examples/MMPT/mmpt/processors/dsprocessor.py | 26 ++++++++++++++----- examples/MMPT/projects/mtm/vlm/coin.yaml | 1 + examples/MMPT/projects/mtm/vlm/crosstask.yaml | 1 + examples/MMPT/projects/mtm/vlm/how2.yaml | 3 +++ examples/MMPT/projects/mtm/vlm/vtt.yaml | 1 + examples/MMPT/projects/mtm/vlm/vttqa.yaml | 1 + examples/MMPT/projects/mtm/vlm/youcook.yaml | 1 + .../MMPT/projects/mtm/vlm/youcookcap.yaml | 1 + .../retri/videoclip/coin_videoclip.yaml | 1 + .../retri/videoclip/crosstask_videoclip.yaml | 1 + .../MMPT/projects/retri/videoclip/how2.yaml | 3 +++ .../retri/videoclip/vtt_videoclip.yaml | 1 + .../retri/videoclip/vttqa_videoclip.yaml | 1 + .../retri/videoclip/youcook_videoclip.yaml | 1 + examples/MMPT/projects/task/default.yaml | 1 + 18 files changed, 49 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 232d3408f9..c8e0b969dc 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,8 @@ We provide reference implementations of various sequence modeling papers: + [Robust wav2vec 2.0: Analyzing Domain Shift in Self-Supervised Pre-Training (Hsu, et al., 2021)](https://arxiv.org/abs/2104.01027) + [Unsupervised Speech Recognition (Baevski, et al., 2021)](https://arxiv.org/abs/2105.11084) + [Simple and Effective Zero-shot Cross-lingual Phoneme Recognition (Xu et al., 2021)](https://arxiv.org/abs/2109.11680) + + [VideoCLIP: Contrastive Pre-training for Zero-shot Video-Text Understanding (Xu et. al., 2021)](https://arxiv.org/pdf/2109.14084.pdf) + + [VLM: Task-agnostic Video-Language Model Pre-training for Video Understanding (Xu et. al., 2021)](https://aclanthology.org/2021.findings-acl.370.pdf) * **Non-autoregressive Transformers** + Non-Autoregressive Neural Machine Translation (Gu et al., 2017) + Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement (Lee et al. 2018) @@ -65,7 +67,7 @@ We provide reference implementations of various sequence modeling papers: </p></details> ### What's New: - +* October 2021 [Released VideoCLIP and VLM models](examples/MMPT/README.md) * October 2021 [Released multilingual finetuned XLSR-53 model](examples/wav2vec/README.md) * September 2021 [`master` branch renamed to `main`](https://github.com/github/renaming). * July 2021 [Released DrNMT code](examples/discriminative_reranking_nmt/README.md) diff --git a/examples/MMPT/.gitignore b/examples/MMPT/.gitignore index 07fe191048..70a255dc91 100644 --- a/examples/MMPT/.gitignore +++ b/examples/MMPT/.gitignore @@ -136,3 +136,4 @@ third-party python_log slurm_snapshot_code lightning_logs +demos diff --git a/examples/MMPT/mmpt/models/mmfusion.py b/examples/MMPT/mmpt/models/mmfusion.py index fcdc7c5c04..2509e26b67 100644 --- a/examples/MMPT/mmpt/models/mmfusion.py +++ b/examples/MMPT/mmpt/models/mmfusion.py @@ -65,6 +65,7 @@ def __init__(self, config, model, video_encoder, **kwargs): def forward(self, video_frames, caps, cmasks, return_score=False): bsz = video_frames.size(0) + assert bsz == 1, "only bsz=1 is supported now." seq_len = video_frames.size(1) video_frames = video_frames.view(-1, *video_frames.size()[2:]) vfeats = self.video_encoder(video_frames.permute(0, 4, 1, 2, 3)) @@ -73,12 +74,17 @@ def forward(self, video_frames, caps, cmasks, return_score=False): padding = torch.zeros( bsz, self.max_video_len - seq_len, vfeats.size(-1)) vfeats = torch.cat([vfeats, padding], dim=1) - vmasks = torch.zeros((bsz, self.max_video_len), dtype=torch.bool) + vmasks = torch.cat([ + torch.ones((bsz, seq_len), dtype=torch.bool), + torch.zeros((bsz, self.max_video_len - seq_len), dtype=torch.bool) + ], + dim=1 + ) output = self.model(caps, cmasks, vfeats, vmasks) if return_score: output = {"score": torch.bmm( output["pooled_video"][:, None, :], - output["pooled_video"][:, :, None] + output["pooled_text"][:, :, None] ).squeeze(-1).squeeze(-1)} return output diff --git a/examples/MMPT/mmpt/processors/dsprocessor.py b/examples/MMPT/mmpt/processors/dsprocessor.py index 1ec7f2201a..ecebf0eea5 100644 --- a/examples/MMPT/mmpt/processors/dsprocessor.py +++ b/examples/MMPT/mmpt/processors/dsprocessor.py @@ -270,11 +270,10 @@ class YoucookMetaProcessor(MetaProcessor): (1) some videos already in Howto100m are removed. (2) stop words are removed from caption TODO (huxu): make a flag to load the original caption. - (see - /datasets01/YouCookII/062920/YouCookII/annotations/youcookii_annotations_trainval.json). + (see youcookii_annotations_trainval.json). The max_video_len can be 264 and text can be 64 tokens. - In reality we may not need that long. see projects/mmfusion/youcook.yaml + In reality we may not need that long. see projects/task/youcook.yaml """ def __init__(self, config): @@ -298,7 +297,7 @@ def __init__(self, config): recs.append(rec) print("total video_ids in .pkl", len(video_ids)) print("valid video_ids in .pkl", len(valid_video_ids)) - print("please verify /datasets01/YouCookII/062920/YouCookII/splits/{train,val}_list.txt") + print("please verify {train,val}_list.txt") data = recs self.data = data @@ -339,8 +338,7 @@ def __call__(self, video_fn): class YoucookNLGMetaProcessor(MetaProcessor): """NLG uses the original split: - `/datasets01/YouCookII/062920/YouCookII/splits/train_list.txt` - `/datasets01/YouCookII/062920/YouCookII/splits/val_list.txt` + `train_list.txt` and `val_list.txt` """ def __init__(self, config): @@ -660,6 +658,21 @@ def forward(self, O, Y, C): # --------------------- COIN ------------------------- +class MetaTextBinarizer(Aligner): + def __call__(self, text_feature): + text_feature = { + "cap": [text_feature], + "start": [0.], + "end": [100.], + } + text_clip_indexs = [0] + + caps, cmasks = self._build_text_seq( + text_feature, text_clip_indexs + ) + return {"caps": caps, "cmasks": cmasks} + + class COINActionSegmentationMetaProcessor(MetaProcessor): split_map = { "train": "training", @@ -704,7 +717,6 @@ def __init__(self, config): def meta_text_labels(self, config): from transformers import default_data_collator - from .expdsprocessor import MetaTextBinarizer from ..utils import get_local_rank text_processor = TextProcessor(config) diff --git a/examples/MMPT/projects/mtm/vlm/coin.yaml b/examples/MMPT/projects/mtm/vlm/coin.yaml index 4060b55a63..48fd64a5f4 100644 --- a/examples/MMPT/projects/mtm/vlm/coin.yaml +++ b/examples/MMPT/projects/mtm/vlm/coin.yaml @@ -27,6 +27,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/mtm/vlm/crosstask.yaml b/examples/MMPT/projects/mtm/vlm/crosstask.yaml index b961fd9822..4e706b549e 100644 --- a/examples/MMPT/projects/mtm/vlm/crosstask.yaml +++ b/examples/MMPT/projects/mtm/vlm/crosstask.yaml @@ -33,6 +33,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/mtm/vlm/how2.yaml b/examples/MMPT/projects/mtm/vlm/how2.yaml index c0b497b401..7ca40ad815 100644 --- a/examples/MMPT/projects/mtm/vlm/how2.yaml +++ b/examples/MMPT/projects/mtm/vlm/how2.yaml @@ -32,6 +32,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 1000 weight_decay: 0.0 ddp_backend: no_c10d @@ -43,6 +44,8 @@ fairseq: keep_last_epochs: 30 task_type: sweep_big slurm_config: big +eval: + save_path: runs/mtm/vlm model: model_cls: MMFusionMTM mm_encoder_cls: MMBertForMFMMLM diff --git a/examples/MMPT/projects/mtm/vlm/vtt.yaml b/examples/MMPT/projects/mtm/vlm/vtt.yaml index 49998257f9..c6c5b1ab40 100644 --- a/examples/MMPT/projects/mtm/vlm/vtt.yaml +++ b/examples/MMPT/projects/mtm/vlm/vtt.yaml @@ -29,6 +29,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/mtm/vlm/vttqa.yaml b/examples/MMPT/projects/mtm/vlm/vttqa.yaml index f09d879b1e..0a440c7dd2 100644 --- a/examples/MMPT/projects/mtm/vlm/vttqa.yaml +++ b/examples/MMPT/projects/mtm/vlm/vttqa.yaml @@ -27,6 +27,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/mtm/vlm/youcook.yaml b/examples/MMPT/projects/mtm/vlm/youcook.yaml index 5b57ee158b..9ee82b81b8 100644 --- a/examples/MMPT/projects/mtm/vlm/youcook.yaml +++ b/examples/MMPT/projects/mtm/vlm/youcook.yaml @@ -27,6 +27,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/mtm/vlm/youcookcap.yaml b/examples/MMPT/projects/mtm/vlm/youcookcap.yaml index 34ac0b218a..d29dfad5cd 100644 --- a/examples/MMPT/projects/mtm/vlm/youcookcap.yaml +++ b/examples/MMPT/projects/mtm/vlm/youcookcap.yaml @@ -25,6 +25,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml index bf106fa65e..aaed5e47f6 100644 --- a/examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml +++ b/examples/MMPT/projects/retri/videoclip/coin_videoclip.yaml @@ -27,6 +27,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml index 6fa60b6761..758601e359 100644 --- a/examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml +++ b/examples/MMPT/projects/retri/videoclip/crosstask_videoclip.yaml @@ -33,6 +33,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/retri/videoclip/how2.yaml b/examples/MMPT/projects/retri/videoclip/how2.yaml index 958c487ccb..b49581e878 100644 --- a/examples/MMPT/projects/retri/videoclip/how2.yaml +++ b/examples/MMPT/projects/retri/videoclip/how2.yaml @@ -36,6 +36,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 1000 weight_decay: 0.0 ddp_backend: no_c10d @@ -47,6 +48,8 @@ fairseq: keep_last_epochs: 30 task_type: sweep_big slurm_config: big +eval: + save_path: runs/retri/videoclip model: model_cls: MMFusionSeparate mm_encoder_cls: null diff --git a/examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml index 26f64af17d..d8b4079ac2 100644 --- a/examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml +++ b/examples/MMPT/projects/retri/videoclip/vtt_videoclip.yaml @@ -29,6 +29,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml index 0d878917fa..f0566d784a 100644 --- a/examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml +++ b/examples/MMPT/projects/retri/videoclip/vttqa_videoclip.yaml @@ -27,6 +27,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml b/examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml index 31be2b4cc5..c2b13e5519 100644 --- a/examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml +++ b/examples/MMPT/projects/retri/videoclip/youcook_videoclip.yaml @@ -27,6 +27,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 warmup_updates: 122 weight_decay: 0.0 ddp_backend: no_c10d diff --git a/examples/MMPT/projects/task/default.yaml b/examples/MMPT/projects/task/default.yaml index 927942a794..087fef71a4 100644 --- a/examples/MMPT/projects/task/default.yaml +++ b/examples/MMPT/projects/task/default.yaml @@ -14,6 +14,7 @@ fairseq: optimizer: adam adam_betas: (0.9, 0.98) lr_scheduler: polynomial_decay + total_num_update: 1000000 # backward compatible on fairseq 1.0.0a0+af0389f for reproducibility. warmup_updates: 1000 weight_decay: 0.0 ddp_backend: no_c10d From 92cae454252850ddc56bde59232909c55943f363 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Wed, 13 Oct 2021 10:04:15 -0700 Subject: [PATCH 477/774] Use safe_getattr and safe_hasattr (#3953) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: hasattr should not default to True if field doesn't exist # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3953 Reviewed By: myleott, Lynx1820 Differential Revision: D31591929 Pulled By: dianaml0 fbshipit-source-id: f78397d2b06867c61fc04a6bd2aa9579265e2d21 --- .../models/transformer/transformer_config.py | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/fairseq/models/transformer/transformer_config.py b/fairseq/models/transformer/transformer_config.py index 2580d20aac..4ebd292b0d 100644 --- a/fairseq/models/transformer/transformer_config.py +++ b/fairseq/models/transformer/transformer_config.py @@ -8,10 +8,12 @@ from dataclasses import dataclass, field, fields from typing import List, Optional -from fairseq import utils -from fairseq.dataclass import FairseqDataclass, ChoiceEnum from omegaconf import II +from fairseq import utils +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.utils import safe_getattr, safe_hasattr + DEFAULT_MAX_SOURCE_POSITIONS = 1024 DEFAULT_MAX_TARGET_POSITIONS = 1024 @@ -228,14 +230,14 @@ class TransformerConfig(FairseqDataclass): def __getattr__(self, name): match = re.match(_NAME_PARSER, name) if match: - sub = getattr(self, match[1]) - return getattr(sub, match[2]) + sub = safe_getattr(self, match[1]) + return safe_getattr(sub, match[2]) raise AttributeError(f"invalid argument {name}.") def __setattr__(self, name, value): match = re.match(_NAME_PARSER, name) if match: - sub = getattr(self, match[1]) + sub = safe_getattr(self, match[1]) setattr(sub, match[2], value) else: super().__setattr__(name, value) @@ -243,7 +245,7 @@ def __setattr__(self, name, value): @staticmethod def _copy_keys(args, cls, prefix, seen): """ - copy the prefixed keys (decoder_embed_dim) to the DC fields: decoder.embed_dim + copy the prefixed keys (decoder_embed_dim) to the DC fields: decoder.embed_dim """ cfg = cls() for fld in fields(cls): @@ -251,12 +253,12 @@ def _copy_keys(args, cls, prefix, seen): # in the namespace with the prefix (e.g. decoder) # and set it on the dc. args_key = f"{prefix}_{fld.name}" - if hasattr(args, args_key): + if safe_hasattr(args, args_key): seen.add(args_key) - setattr(cfg, fld.name, getattr(args, args_key)) - if hasattr(args, fld.name): + setattr(cfg, fld.name, safe_getattr(args, args_key)) + if safe_hasattr(args, fld.name): seen.add(fld.name) - setattr(cfg, fld.name, getattr(args, fld.name)) + setattr(cfg, fld.name, safe_getattr(args, fld.name)) return cfg @classmethod @@ -275,7 +277,7 @@ def from_namespace(cls, args): # concretelly, the transformer_config know what sub-dc it has, so we go through all the dc fields # and if it's one that has a sub-dc, we build that sub-dc with `copy_keys()` if fld.name == "decoder": - if hasattr(args, "decoder"): + if safe_hasattr(args, "decoder"): # in some cases, the args we receive is already structured (as DictConfigs), so let's just build the correct DC seen.add("decoder") config.decoder = DecoderConfig(**args.decoder) @@ -285,7 +287,7 @@ def from_namespace(cls, args): ) elif fld.name == "encoder": # same but for encoder - if hasattr(args, "encoder"): + if safe_hasattr(args, "encoder"): seen.add("encoder") config.encoder = EncDecBaseConfig(**args.encoder) else: @@ -294,22 +296,28 @@ def from_namespace(cls, args): ) elif fld.name == "quant_noise": # same but for quant_noise - if hasattr(args, "quant_noise"): + if safe_hasattr(args, "quant_noise"): seen.add("quant_noise") config.quant_noise = QuantNoiseConfig(**args.quant_noise) else: config.quant_noise = cls._copy_keys( args, QuantNoiseConfig, "quant_noise", seen ) - elif hasattr(args, fld.name): + elif safe_hasattr(args, fld.name): # if it's not a structure field, it's just a normal field, copy it over seen.add(fld.name) - setattr(config, fld.name, getattr(args, fld.name)) + setattr(config, fld.name, safe_getattr(args, fld.name)) # we got all the fields defined in the dataclass, but # the argparse namespace might have extra args for two reasons: # - we are in a legacy class so all the args are not declared in the dataclass. Ideally once everyone has defined a dataclass for their model, we won't need this # - some places expect args to be there but never define them - args_dict = args._asdict() if hasattr(args, '_asdict') else vars(args) if hasattr(args, '__dict__') else {} # namedtupled doesn't have __dict__ :-/ + args_dict = ( + args._asdict() + if safe_hasattr(args, "_asdict") + else vars(args) + if safe_hasattr(args, "__dict__") + else {} + ) # namedtupled doesn't have __dict__ :-/ for key, value in args_dict.items(): if key not in seen: setattr(config, key, value) From f670d9f1f299a604884c0b1ce58f36661ae1167e Mon Sep 17 00:00:00 2001 From: Apoorv Vyas <vyasapoorv@devfair0164.h2.fair> Date: Thu, 14 Oct 2021 21:08:11 -0700 Subject: [PATCH 478/774] Fixes fp16 inference for speech recognition example (#2438) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Currently the speech recognition fails for fp16 option as the input is not converted to half. This fixes this issue. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes fp16 inference for speech recognition example. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2438 Reviewed By: apoorv2904, xuqiantong Differential Revision: D31594529 Pulled By: alexeib fbshipit-source-id: 75d1fe3f00b2e86381f28f79daea2cd516233e22 --- examples/speech_recognition/infer.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/examples/speech_recognition/infer.py b/examples/speech_recognition/infer.py index 6e9a878af4..ce16bf47cf 100644 --- a/examples/speech_recognition/infer.py +++ b/examples/speech_recognition/infer.py @@ -191,6 +191,12 @@ def optimize_models(args, use_cuda, models): model.cuda() +def apply_half(t): + if t.dtype is torch.float32: + return t.to(dtype=torch.half) + return t + + class ExistingEmissionsDecoder(object): def __init__(self, decoder, emissions): self.decoder = decoder @@ -210,6 +216,7 @@ def generate(self, models, sample, **unused): def main(args, task=None, model_state=None): check_args(args) + use_fp16 = args.fp16 if args.max_tokens is None and args.batch_size is None: args.max_tokens = 4000000 logger.info(args) @@ -317,6 +324,8 @@ def build_generator(args): wps_meter = TimeMeter() for sample in t: sample = utils.move_to_cuda(sample) if use_cuda else sample + if use_fp16: + sample = utils.apply_to_sample(apply_half, sample) if "net_input" not in sample: continue From 1ef3d6a1a2cb7fa9937233c8bf796957871bfc94 Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Thu, 14 Oct 2021 22:07:55 -0700 Subject: [PATCH 479/774] CPLTask for training with continuous pseudo labeling Summary: CPLTaskImpl provides implementation to augment existing tasks to take additional input of ema_model in its train_step and valid_step for continous pseudo-labeling (CPL) during training. It passes this ema_model to the criterion. See Kaizen semi-supervised training paper for more details https://arxiv.org/abs/2106.07759. This implementation also supports using CPLDataset which enables using unsupervised data only for `cpl_finetune_epoch > epochs >= cpl_start_epoch`. CPLDataset is like MultiCorpusDataset but ignores the unsupervised datasets while sampling. Another addition in this diff is to skip dataset in MultiCorpusDataset if the sampling probability is 0. Reviewed By: cruvadom Differential Revision: D30701536 fbshipit-source-id: 1d840eacfd538ed7aed3baaefc8b254390642b45 --- fairseq/data/multi_corpus_dataset.py | 29 ++++++++++++++++++---------- tests/test_multi_corpus_dataset.py | 2 +- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index 746155e515..1566d8e0cd 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -6,7 +6,7 @@ import logging import time from collections import OrderedDict -from typing import Dict, List +from typing import Dict, List, Optional import numpy as np from fairseq.data import data_utils @@ -18,13 +18,15 @@ class MultiCorpusDataset(FairseqDataset): """ - Stores multiple instances of FairseqDataset together. Requires each instance + Stores multiple instances of FairseqDataset together. + Unless batch_sample=True, requires each instance to be the same dataset, as the collate method needs to work on batches with samples from each dataset. Allows specifying a distribution over the datasets to use. Note that unlike MultiCorpusSampledDataset, this distribution allows sampling for each item, - rather than on a batch level. + rather than on a batch level. Note that datasets with sampling probabilty + of 0 will be skipped. Each time ordered_indices() is called, a new sample is generated with the specified distribution. @@ -45,7 +47,7 @@ def __init__( seed: int, sort_indices: bool = False, batch_sample: bool = False, - distributed_rank=None, + distributed_rank: Optional[int] = None, ): super().__init__() assert isinstance(datasets, OrderedDict) @@ -62,14 +64,18 @@ def __init__( self.dataset_list = list(datasets.values()) self.total_num_instances = 0 - first_dataset = list(self.datasets.values())[0] + first_dataset = self.dataset_list[0] + self.num_instances_per_dataset = [] self.dataset_offsets = [] - for dataset in datasets.values(): + for i, dataset in enumerate(self.dataset_list): assert isinstance(dataset, FairseqDataset) assert type(dataset) is type(first_dataset) + self.num_instances_per_dataset.append( + 0 if self.distribution[i] == 0 else len(dataset) + ) self.dataset_offsets.append(self.total_num_instances) - self.total_num_instances += len(dataset) + self.total_num_instances += self.num_instances_per_dataset[i] def ordered_indices(self): start = time.time() @@ -80,6 +86,9 @@ def ordered_indices(self): # For each dataset i, sample self.distribution[i] * self.total_num_instances for i, key in enumerate(self.datasets): + if self.distribution[i] == 0: + # skip dataset if sampling probability is 0 + continue if i < len(self.datasets) - 1: num_instances = int(self.distribution[i] * self.total_num_instances) @@ -136,10 +145,10 @@ def _map_index(self, index: int): maps to index 1 of B. """ counter = 0 - for key, dataset in self.datasets.items(): - if index < counter + len(dataset): + for num_instances, key in zip(self.num_instances_per_dataset, self.datasets): + if index < counter + num_instances: return index - counter, key - counter += len(dataset) + counter += num_instances raise ValueError( "Invalid index: {}, max: {}".format(index, self.total_num_instances) ) diff --git a/tests/test_multi_corpus_dataset.py b/tests/test_multi_corpus_dataset.py index 5a79f4b680..278bdb73c1 100644 --- a/tests/test_multi_corpus_dataset.py +++ b/tests/test_multi_corpus_dataset.py @@ -75,5 +75,5 @@ def _test_sample_helper( print(distribution) def test_multi_corpus_dataset(self): - for distribution in [[0.5, 0.5], [0.1, 0.9], [0.9, 0.1]]: + for distribution in [[0.5, 0.5], [0.1, 0.9], [0.9, 0.1], [0.0, 1.0]]: self._test_sample_helper(distribution=distribution) From 29be3fe1414cffaf80edc5511c8dc87559f8cd80 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Mon, 18 Oct 2021 08:25:24 -0700 Subject: [PATCH 480/774] --activation relu-squared (#2458) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2458 Reviewed By: ngoyal2707 Differential Revision: D31721732 Pulled By: sshleifer fbshipit-source-id: 620fbeece5ad4101baaf98cf2150027288ebad33 --- fairseq/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fairseq/utils.py b/fairseq/utils.py index f61a8d38d4..94114ce15c 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -536,6 +536,9 @@ def deprecation_warning(message, stacklevel=3): # don't use DeprecationWarning, since it's ignored by default warnings.warn(message, stacklevel=stacklevel) +def relu_squared(x: torch.Tensor): + return F.relu(x).pow(2) + def get_activation_fn(activation: str) -> Callable: """Returns the activation function corresponding to `activation`""" @@ -543,6 +546,8 @@ def get_activation_fn(activation: str) -> Callable: if activation == "relu": return F.relu + elif activation == "relu_squared": + return relu_squared elif activation == "gelu": return gelu elif activation == "gelu_fast": From c5ff181125c7e6126b49a85e5ebdd5f5b6a07914 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Tue, 19 Oct 2021 17:12:02 -0700 Subject: [PATCH 481/774] NormFormer: flags and docs (#2460) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2460 Reviewed By: myleott Differential Revision: D31731798 Pulled By: sshleifer fbshipit-source-id: 938456c17aa004cacffdcdd124aebe390da83d5f --- README.md | 1 + examples/normformer/README.md | 70 +++++++++++++++++++++++++ examples/normformer/train_lm.sh | 78 ++++++++++++++++++++++++++++ fairseq/models/transformer_lm.py | 9 ++++ fairseq/modules/transformer_layer.py | 20 +++++++ tests/test_binaries.py | 24 +++++++++ 6 files changed, 202 insertions(+) create mode 100644 examples/normformer/README.md create mode 100644 examples/normformer/train_lm.sh diff --git a/README.md b/README.md index c8e0b969dc..4a3c6b29d6 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ We provide reference implementations of various sequence modeling papers: + [Simple and Effective Zero-shot Cross-lingual Phoneme Recognition (Xu et al., 2021)](https://arxiv.org/abs/2109.11680) + [VideoCLIP: Contrastive Pre-training for Zero-shot Video-Text Understanding (Xu et. al., 2021)](https://arxiv.org/pdf/2109.14084.pdf) + [VLM: Task-agnostic Video-Language Model Pre-training for Video Understanding (Xu et. al., 2021)](https://aclanthology.org/2021.findings-acl.370.pdf) + + [NormFormer: Improved Transformer Pretraining with Extra Normalization (Shleifer et. al, 2021)](examples/normformer/README.md) * **Non-autoregressive Transformers** + Non-Autoregressive Neural Machine Translation (Gu et al., 2017) + Deterministic Non-Autoregressive Neural Sequence Modeling by Iterative Refinement (Lee et al. 2018) diff --git a/examples/normformer/README.md b/examples/normformer/README.md new file mode 100644 index 0000000000..037b453ff1 --- /dev/null +++ b/examples/normformer/README.md @@ -0,0 +1,70 @@ +### NormFormer +This is the code for the ["NormFormer: Improved Transformer Pretraining with Extra Normalization"](https://arxiv.org/abs/2110.09456) +- 2021-10-19: Commands for CLM Experiments +- Coming soon: Commands for MLM experiments + +If you have any issues or questions please post a github issue and tag `@sshleifer`. + + +### Data +- To preprocess language modeling data, see [here](https://github.com/pytorch/fairseq/blob/d0fbcb0baef6f6ff3425ded62d8daea0e8b12114/examples/language_model/README.md#1-preprocess-the-data). +- The replication commands below expect `$DATA` to be the path to the binarized data directory. +- Note that NormFormer results in Table 2 use a much larger private dataset, and to get good results you should adapt the pre-processing instructions to your dataset and compare to a baseline on the same data, rather than Table 2. +- The code uses `FSDP`, which requires `pip install fairscale>=0.4.0`. + + +### Modify existing Command +To modify an existing `fairseq-train` command to use NormFormer, simply add the following flags: +```bash +fairseq-train ... \ + --scale-attn --scale-fc --scale-heads +``` +- you probably also want to increase your learning rate +- if your model is small, you may want to add `--scale-resids` + +### Exact Training Commands + +- Note that NormFormer results in Table 2 use a much larger private dataset, and to get good results you should adapt the pre-processing instructions to your dataset. +The full commands are functions defined here, so to run them you must `source examples/normformer/train_lm.sh`. +- We default `--distributed-world-size 8`. You should adjust `--update-freq` and `--batch-size` and such that the effective batch size is (1024x1024x0.5) tokens for 125M and 355M, + and (1024x1024) for 1.3B parameter and above. For small models, `--update-freq`=256/`global_bs`. For large models, `--update-freq`=512/`global_bs`, where `global_bs` = `--batch-size` * `--distributed-world-size` +- The small models will all train on as few as 8 GPUs. + +```bash +train_125M --lr 6e-4 # GPT-3 Replicated +train_125M --lr 1e-3 # stronger high-lr baseline +train_125M --lr 3e-3 --scale-attn --scale-fc --scale-heads # No scale-resids +train_125M --lr 3e-3 --scale-attn --scale-fc --scale-heads --scale-resids # Best command +``` + +```bash +train_355M --lr 6e-4 # GPT-3 Replicated +train_355M --lr 1e-3 # stronger high-lr baseline +train_355M --lr 1e-3 --scale-attn --scale-fc --scale-heads # No scale-resids +train_355M --lr 1e-3 --scale-attn --scale-fc --scale-heads --scale-resids # Slightly better +``` + +```bash +train_1.3B --lr 2e-4 # GPT-3 Replicated +train_1.3B --lr 6e-4 # stronger high-lr baseline +train_1.3B --lr 6e-4 --scale-attn --scale-fc --scale-heads # NormFormer +``` + +```bash +train_2.7B --lr 1.6e-4 # GPT-3 Replicated +train_2.7B --lr 1.6e-4 --activation-fn relu_squared # stronger Relu^2 baseline +train_2.7B --lr 6e-4 --activation-fn relu_squared --scale-attn --scale-fc --scale-heads # NormFormer 2.7B +``` + + +### Citation +```bibtex +@misc{shleifer2021normformer, + title={NormFormer: Improved Transformer Pretraining with Extra Normalization}, + author={Sam Shleifer and Jason Weston and Myle Ott}, + year={2021}, + eprint={2110.09456}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} +``` diff --git a/examples/normformer/train_lm.sh b/examples/normformer/train_lm.sh new file mode 100644 index 0000000000..b081f2ddd3 --- /dev/null +++ b/examples/normformer/train_lm.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +train_common () { + fairseq-train "$DATA" \ + --combine-val \ + --train-subset train \ + --num-workers 2 \ + --validate-interval-updates 1000 \ + --save-interval-updates 1000 \ + --no-epoch-checkpoints \ + --ddp-backend fully_sharded \ + --memory-efficient-fp16 \ + --fp16-init-scale 4 \ + --checkpoint-activations \ + --arch transformer_lm_gpt \ + --activation-fn gelu \ + --share-decoder-input-output-embed \ + --task language_modeling \ + --sample-break-mode none \ + --tokens-per-sample 2048 \ + --optimizer adam --adam-betas "(0.9, 0.98)" \ + --adam-eps 1e-08 \ + --clip-norm 0.0 \ + --lr-scheduler polynomial_decay \ + --warmup-updates 750 \ + --dropout 0.1 \ + --attention-dropout 0.1 \ + --weight-decay 0.01 \ + --batch-size 16 \ + --update-freq 2 \ + --required-batch-size-multiple 1 \ + --total-num-update 572204 \ + --max-update 572204 \ + --seed 1 \ + --log-format json --log-interval 1 \ + --distributed-world-size 8 --distributed-port 13177 \ + "$@" +} + +train_125M () { + train_common --decoder-layers 12 \ + --decoder-embed-dim 768 \ + --decoder-ffn-embed-dim 3072 \ + --decoder-attention-heads 12 "$@" +} + +train_355M () { + train_common --decoder-layers 24 \ + --decoder-embed-dim 1024\ + --decoder-ffn-embed-dim 4096 \ + --decoder-attention-heads 16 \ + --dropout 0.0 \ + --attention-dropout 0.0 \ + "$@" +} + +train_1.3B () { + train_common --decoder-layers 24 \ + --decoder-embed-dim 2048 \ + --decoder-ffn-embed-dim 8192 \ + --decoder-attention-heads 32 \ + --batch-size 4 \ + --update-freq 16 \ + --total-num-update 286102 \ + --max-update 286102 \ + "$@" +} + +train_2.7B () { + train_common --decoder-layers 32 \ + --decoder-embed-dim 2560 \ + --decoder-ffn-embed-dim 10240 \ + --decoder-attention-heads 32 \ + --batch-size 4 \ + --update-freq 16 \ + --total-num-update 286102 \ + --max-update 286102 \ + "$@" +} diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index eedd5151ba..14cbb089fd 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -191,6 +191,11 @@ class TransformerLanguageModelConfig(FairseqDataclass): base_shuffle: Optional[int] = field( default=1, metadata={"help": "shuffle tokens between workers before computing assignment"} ) + # NormFormer + scale_fc: Optional[bool] = field(default=False, metadata={"help": 'Insert LayerNorm between fully connected layers'}) + scale_attn: Optional[bool] = field(default=False, metadata={"help": 'Insert LayerNorm after attention'}) + scale_heads: Optional[bool] = field(default=False, metadata={"help": 'Learn a scale coefficient for each attention head'}) + scale_resids: Optional[bool] = field(default=False, metadata={"help": 'Learn a scale coefficient for each residual connection'}) # options from other parts of the config add_bos_token: bool = II("task.add_bos_token") tokens_per_sample: int = II("task.tokens_per_sample") @@ -357,6 +362,10 @@ def base_lm_architecture(args): args.layernorm_embedding = safe_getattr(args, "layernorm_embedding", False) args.checkpoint_activations = safe_getattr(args, "checkpoint_activations", False) args.offload_activations = safe_getattr(args, "offload_activations", False) + args.scale_fc = safe_getattr(args, 'scale_fc', False) + args.scale_attn = safe_getattr(args, 'scale_attn', False) + args.scale_heads = safe_getattr(args, 'scale_heads', False) + args.scale_resids = safe_getattr(args, 'scale_resids', False) if args.offload_activations: args.checkpoint_activations = True diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 347b8118da..d685f72bb7 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -213,6 +213,11 @@ def __init__( add_bias_kv=add_bias_kv, add_zero_attn=add_zero_attn, ) + self.attn_ln = LayerNorm(self.embed_dim) if utils.safe_getattr(cfg, 'scale_attn', False) else None + self.nh = self.self_attn.num_heads + self.head_dim = self.self_attn.head_dim + scale_heads = utils.safe_getattr(cfg, 'scale_heads', False) + self.c_attn = nn.Parameter(torch.ones((self.nh,)), requires_grad=True) if scale_heads else None self.activation_fn = utils.get_activation_fn(activation=cfg.activation_fn) activation_dropout_p = cfg.activation_dropout @@ -233,6 +238,9 @@ def __init__( self.encoder_attn = self.build_encoder_attention(self.embed_dim, cfg) self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) + self.ffn_layernorm = LayerNorm(cfg.decoder.ffn_embed_dim) if utils.safe_getattr(cfg, 'scale_fc', False) else None + self.w_resid = nn.Parameter(torch.ones(self.embed_dim, ), requires_grad=True) if utils.safe_getattr(cfg, 'scale_resids', False) else None + self.fc1 = self.build_fc1( self.embed_dim, cfg.decoder.ffn_embed_dim, @@ -289,6 +297,7 @@ def prepare_for_onnx_export_(self): def residual_connection(self, x, residual): return residual + x + def forward( self, x, @@ -365,6 +374,13 @@ def forward( need_weights=False, attn_mask=self_attn_mask, ) + if self.c_attn is not None: + tgt_len, bsz = x.size(0), x.size(1) + x = x.view(tgt_len, bsz, self.nh, self.head_dim) + x = torch.einsum('tbhd,h->tbdh', x, self.c_attn) + x = x.reshape(tgt_len, bsz, self.embed_dim) + if self.attn_ln is not None: + x = self.attn_ln(x) x = self.dropout_module(x) x = self.residual_connection(x, residual) if not self.normalize_before: @@ -406,8 +422,12 @@ def forward( x = self.activation_fn(self.fc1(x)) x = self.activation_dropout_module(x) + if self.ffn_layernorm is not None: + x = self.ffn_layernorm(x) x = self.fc2(x) x = self.dropout_module(x) + if self.w_resid is not None: + residual = torch.mul(self.w_resid, residual) x = self.residual_connection(x, residual) if not self.normalize_before: x = self.final_layer_norm(x) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 4e20774262..bc233192f9 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -1178,6 +1178,30 @@ def test_transformer_lm(self): ], ) + def test_normformer_lm(self): + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_transformer_lm") as data_dir: + create_dummy_data(data_dir) + preprocess_lm_data(data_dir) + train_language_model( + data_dir, + "transformer_lm", + ["--add-bos-token", '--nval', '1', '--scale-fc', '--scale-heads', '--scale-attn', '--scale-fc'], + run_validation=True, + ) + eval_lm_main(data_dir) + eval_lm_main(data_dir, extra_flags=["--context-window", "25"]) + generate_main( + data_dir, + [ + "--task", + "language_modeling", + "--sample-break-mode", + "eos", + "--tokens-per-sample", + "500", + ], + ) def test_transformer_lm_with_adaptive_softmax(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory( From a38c86c09ef48a80c4d8cfb8e48a703dfdb57ea8 Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Fri, 22 Oct 2021 08:44:25 -0700 Subject: [PATCH 482/774] Fix quantization with checkpoint wrapper Summary: checkpoint wrapper deepcopy fix wasn't compatible with jitting. e.g f304176613 Reviewed By: diptanu Differential Revision: D31839350 fbshipit-source-id: d3ae64ac42e82a5dd103a7e1c03f6a5fbe7234ee --- fairseq/modules/checkpoint_activations.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index 7489e09eb7..dc73c662e2 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -46,6 +46,9 @@ def unwrap_checkpoint(m: torch.nn.Module): if hasattr(module, "precheckpoint_forward"): module.forward = module.precheckpoint_forward del module.precheckpoint_forward + if hasattr(module, "old_deepcopy_method"): + module.__deepcopy__ = module.old_deepcopy_method + del module.old_deepcopy_method return m From 265df7144c79446f5ea8d835bda6e727f54dad9d Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Fri, 22 Oct 2021 19:50:18 -0700 Subject: [PATCH 483/774] set num_update before loading state dict (#2491) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## What does this PR do? Set `model.num_updates` in `load_model_ensemble_and_task()` before loading `state_dict`, like what's done in `fairseq/trainer.py`, because a model's `state_dict` may depend on `num_update`. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2491 Reviewed By: xuqiantong Differential Revision: D31863368 Pulled By: wnhsu fbshipit-source-id: c70051f898819cc43b02c9f5765429e9f194aed5 --- fairseq/checkpoint_utils.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index ef5d4c9022..e9698b58c2 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -449,12 +449,28 @@ def load_model_ensemble_and_task( shard_metadata=model_shard_state["shard_metadata"], ) model = task.build_model(cfg.model) + if ( + "optimizer_history" in state + and len(state["optimizer_history"]) > 0 + and "num_updates" in state["optimizer_history"][-1] + ): + model.set_num_updates( + state["optimizer_history"][-1]["num_updates"] + ) model.load_state_dict( consolidated_model_state, strict=strict, model_cfg=cfg.model ) else: # model parallel checkpoint or unsharded checkpoint model = task.build_model(cfg.model) + if ( + "optimizer_history" in state + and len(state["optimizer_history"]) > 0 + and "num_updates" in state["optimizer_history"][-1] + ): + model.set_num_updates( + state["optimizer_history"][-1]["num_updates"] + ) model.load_state_dict( state["model"], strict=strict, model_cfg=cfg.model ) From 72e524b2fbd705bcf12bbe50f7b25a98b076e6f6 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Fri, 29 Oct 2021 13:10:59 -0700 Subject: [PATCH 484/774] add SNR and CER filtering to S^2; add S^2 citation Summary: add SNR and CER filtering to S^2; add S^2 citation Reviewed By: wnhsu Differential Revision: D31566968 fbshipit-source-id: b8a651f4bf0dd088e2f03fb759d1869c6af7730f --- examples/speech_synthesis/README.md | 26 +++++++++++- examples/speech_synthesis/data_utils.py | 42 +++++++++++++++---- .../docs/common_voice_example.md | 29 +++++++++---- .../speech_synthesis/docs/vctk_example.md | 28 +++++++++---- .../evaluation/get_eval_manifest.py | 6 +++ .../preprocessing/get_feature_manifest.py | 33 ++++++++++++++- 6 files changed, 133 insertions(+), 31 deletions(-) diff --git a/examples/speech_synthesis/README.md b/examples/speech_synthesis/README.md index 4a3ae54b85..a31e7f68bd 100644 --- a/examples/speech_synthesis/README.md +++ b/examples/speech_synthesis/README.md @@ -1,12 +1,15 @@ Speech Synthesis (S^2) === +[https://arxiv.org/abs/2109.06912](https://arxiv.org/abs/2109.06912) Speech synthesis with fairseq. +## Features + - Autoregressive and non-autoregressive models - Multi-speaker synthesis -- Audio preprocessing -- Automatic metrics +- Audio preprocessing (denoising, VAD, etc.) for less curated data +- Automatic metrics for model development - Similar data configuration as [S2T](../speech_to_text/README.md) @@ -14,3 +17,22 @@ Speech synthesis with fairseq. - [Single-speaker synthesis on LJSpeech](docs/ljspeech_example.md) - [Multi-speaker synthesis on VCTK](docs/vctk_example.md) - [Multi-speaker synthesis on Common Voice](docs/common_voice_example.md) + + +## Citation +Please cite as: +``` +@article{wang2021fairseqs2, + title={fairseq S\^{} 2: A Scalable and Integrable Speech Synthesis Toolkit}, + author={Wang, Changhan and Hsu, Wei-Ning and Adi, Yossi and Polyak, Adam and Lee, Ann and Chen, Peng-Jen and Gu, Jiatao and Pino, Juan}, + journal={arXiv preprint arXiv:2109.06912}, + year={2021} +} + +@inproceedings{ott2019fairseq, + title = {fairseq: A Fast, Extensible Toolkit for Sequence Modeling}, + author = {Myle Ott and Sergey Edunov and Alexei Baevski and Angela Fan and Sam Gross and Nathan Ng and David Grangier and Michael Auli}, + booktitle = {Proceedings of NAACL-HLT 2019: Demonstrations}, + year = {2019}, +} +``` diff --git a/examples/speech_synthesis/data_utils.py b/examples/speech_synthesis/data_utils.py index f43a4a9004..3b2d079a9a 100644 --- a/examples/speech_synthesis/data_utils.py +++ b/examples/speech_synthesis/data_utils.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import io import os from pathlib import Path from typing import Optional, List, Dict @@ -17,7 +18,9 @@ from tqdm import tqdm from examples.speech_to_text.data_utils import load_tsv_to_dicts -from fairseq.data.audio.audio_utils import TTSSpectrogram, TTSMelScale +from fairseq.data.audio.audio_utils import ( + TTSSpectrogram, TTSMelScale, parse_path, read_from_stored_zip, is_npy_data +) def trim_or_pad_to_target_length( @@ -65,7 +68,7 @@ def extract_logmel_spectrogram( assert len(logmel_spec.shape) == 3 and logmel_spec.shape[0] == 1 logmel_spec = logmel_spec.squeeze().t() # D x T -> T x D if target_length is not None: - trim_or_pad_to_target_length(logmel_spec, target_length) + logmel_spec = trim_or_pad_to_target_length(logmel_spec, target_length) if output_path is not None: np.save(output_path.as_posix(), logmel_spec) @@ -99,13 +102,20 @@ def extract_pitch( except ImportError: raise ImportError("Please install SciPy: pip install scipy") nonzero_ids = np.where(pitch != 0)[0] - interp_fn = interp1d( - nonzero_ids, - pitch[nonzero_ids], - fill_value=(pitch[nonzero_ids[0]], pitch[nonzero_ids[-1]]), - bounds_error=False, - ) - pitch = interp_fn(np.arange(0, len(pitch))) + if len(nonzero_ids) == 0: + print((f"{output_path} has all empty values in the pitch contour")) + return + elif len(nonzero_ids) == 1: + print((f"{output_path} has only one non-zero values in the pitch contour")) + return + else: + interp_fn = interp1d( + nonzero_ids, + pitch[nonzero_ids], + fill_value=(pitch[nonzero_ids[0]], pitch[nonzero_ids[-1]]), + bounds_error=False, + ) + pitch = interp_fn(np.arange(0, len(pitch))) d_cumsum = np.cumsum(np.concatenate([np.array([0]), phoneme_durations])) pitch = np.array( [ @@ -318,3 +328,17 @@ def get_unit_alignment( ) for i in sample_ids } + + +def get_feature_value_min_max(feature_paths: List[str]): + v_min, v_max = 1e-8, -1e-8 + for p in tqdm(feature_paths): + _path, slice_ptr = parse_path(p) + assert len(slice_ptr) == 2 + byte_data = read_from_stored_zip(_path, slice_ptr[0], slice_ptr[1]) + assert is_npy_data(byte_data) + path_or_fp = io.BytesIO(byte_data) + features = np.load(path_or_fp).squeeze() + v_min = min(v_min, features.min().item()) + v_max = max(v_max, features.max().item()) + return v_min, v_max diff --git a/examples/speech_synthesis/docs/common_voice_example.md b/examples/speech_synthesis/docs/common_voice_example.md index 40e841b284..1c0eef69a0 100644 --- a/examples/speech_synthesis/docs/common_voice_example.md +++ b/examples/speech_synthesis/docs/common_voice_example.md @@ -17,15 +17,6 @@ python -m examples.speech_synthesis.preprocessing.get_common_voice_audio_manifes --output-manifest-root ${AUDIO_MANIFEST_ROOT} --convert-to-wav ``` -Then, extract log-Mel spectrograms, generate feature manifest and create data configuration YAML with -```bash -python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ - --audio-manifest-root ${AUDIO_MANIFEST_ROOT} \ - --output-root ${FEATURE_MANIFEST_ROOT} \ - --ipa-vocab --lang ${LANG_ID} -``` -where we use phoneme inputs (`--ipa-vocab`) as example. - To denoise audio and trim leading/trailing silence using signal processing based VAD, run ```bash for SPLIT in dev test train; do @@ -36,6 +27,26 @@ for SPLIT in dev test train; do done ``` +which generates a new audio TSV manifest under `${PROCESSED_DATA_ROOT}` with updated path to the processed audio and +a new column for SNR. + +To do filtering by CER, follow the [Automatic Evaluation](../docs/ljspeech_example.md#automatic-evaluation) section to +run ASR model (add `--eval-target` to `get_eval_manifest` for evaluation on the reference audio; add `--err-unit char` +to `eval_asr` to compute CER instead of WER). The example-level CER is saved to +`${EVAL_OUTPUT_ROOT}/uer_cer.${SPLIT}.tsv`. + +Then, extract log-Mel spectrograms, generate feature manifest and create data configuration YAML with +```bash +python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ + --audio-manifest-root ${AUDIO_MANIFEST_ROOT} \ + --output-root ${FEATURE_MANIFEST_ROOT} \ + --ipa-vocab --lang ${LANG_ID} \ + --snr-threshold 15 \ + --cer-threshold 0.1 --cer-tsv-path ${EVAL_OUTPUT_ROOT}/uer_cer.${SPLIT}.tsv +``` +where we use phoneme inputs (`--ipa-vocab`) as example. For sample filtering, we set the SNR and CER threshold +to 15 and 10%, respectively. + ## Training (Please refer to [the LJSpeech example](../docs/ljspeech_example.md#transformer).) diff --git a/examples/speech_synthesis/docs/vctk_example.md b/examples/speech_synthesis/docs/vctk_example.md index 2ba78f3f73..6808256d44 100644 --- a/examples/speech_synthesis/docs/vctk_example.md +++ b/examples/speech_synthesis/docs/vctk_example.md @@ -14,15 +14,6 @@ python -m examples.speech_synthesis.preprocessing.get_vctk_audio_manifest \ --output-manifest-root ${AUDIO_MANIFEST_ROOT} ``` -Then, extract log-Mel spectrograms, generate feature manifest and create data configuration YAML with -```bash -python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ - --audio-manifest-root ${AUDIO_MANIFEST_ROOT} \ - --output-root ${FEATURE_MANIFEST_ROOT} \ - --ipa-vocab --use-g2p -``` -where we use phoneme inputs (`--ipa-vocab --use-g2p`) as example. - To denoise audio and trim leading/trailing silence using signal processing based VAD, run ```bash for SPLIT in dev test train; do @@ -32,6 +23,25 @@ for SPLIT in dev test train; do --denoise --vad --vad-agg-level 3 done ``` +which generates a new audio TSV manifest under `${PROCESSED_DATA_ROOT}` with updated path to the processed audio and +a new column for SNR. + +To do filtering by CER, follow the [Automatic Evaluation](../docs/ljspeech_example.md#automatic-evaluation) section to +run ASR model (add `--eval-target` to `get_eval_manifest` for evaluation on the reference audio; add `--err-unit char` +to `eval_asr` to compute CER instead of WER). The example-level CER is saved to +`${EVAL_OUTPUT_ROOT}/uer_cer.${SPLIT}.tsv`. + +Then, extract log-Mel spectrograms, generate feature manifest and create data configuration YAML with +```bash +python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ + --audio-manifest-root ${PROCESSED_DATA_ROOT} \ + --output-root ${FEATURE_MANIFEST_ROOT} \ + --ipa-vocab --use-g2p \ + --snr-threshold 15 \ + --cer-threshold 0.1 --cer-tsv-path ${EVAL_OUTPUT_ROOT}/uer_cer.${SPLIT}.tsv +``` +where we use phoneme inputs (`--ipa-vocab --use-g2p`) as example. For sample filtering, we set the SNR and CER threshold +to 15 and 10%, respectively. ## Training (Please refer to [the LJSpeech example](../docs/ljspeech_example.md#transformer).) diff --git a/examples/speech_synthesis/evaluation/get_eval_manifest.py b/examples/speech_synthesis/evaluation/get_eval_manifest.py index a28cd607a0..44b3685bb2 100644 --- a/examples/speech_synthesis/evaluation/get_eval_manifest.py +++ b/examples/speech_synthesis/evaluation/get_eval_manifest.py @@ -28,6 +28,8 @@ def main(args): ref = row["audio"] if args.use_resynthesized_target: ref = (in_root / f"{dir_name}_tgt" / f"{id_}.{ext}").as_posix() + if args.eval_target: + syn = row["audio"] sample = [id_, syn, ref, row["tgt_text"], row["speaker"]] f_out.write("\t".join(sample) + "\n") print(f"wrote evaluation file to {args.output_path}") @@ -50,6 +52,10 @@ def main(args): "--use-resynthesized-target", action="store_true", help="use resynthesized reference instead of the original audio" ) + parser.add_argument( + "--eval-target", action="store_true", + help="evaluate reference instead of model prediction" + ) parser.add_argument("--vocoder", type=str, default="griffin_lim") parser.add_argument("--sample-rate", type=int, default=22_050) parser.add_argument("--audio-format", type=str, default="wav") diff --git a/examples/speech_synthesis/preprocessing/get_feature_manifest.py b/examples/speech_synthesis/preprocessing/get_feature_manifest.py index 516f2cc469..4a1e119b32 100644 --- a/examples/speech_synthesis/preprocessing/get_feature_manifest.py +++ b/examples/speech_synthesis/preprocessing/get_feature_manifest.py @@ -25,7 +25,8 @@ ) from examples.speech_synthesis.data_utils import ( extract_logmel_spectrogram, extract_pitch, extract_energy, get_global_cmvn, - ipa_phonemize, get_mfa_alignment, get_unit_alignment + ipa_phonemize, get_mfa_alignment, get_unit_alignment, + get_feature_value_min_max ) @@ -126,9 +127,23 @@ def process(args): energy_paths, energy_lengths = get_zip_manifest(energy_zip_path) # Generate TSV manifest print("Generating manifest...") + id_to_cer = None + if args.cer_threshold is not None: + assert Path(args.cer_tsv_path).is_file() + id_to_cer = { + x["id"]: x["uer"] for x in load_tsv_to_dicts(args.cer_tsv_path) + } manifest_by_split = {split: defaultdict(list) for split in args.splits} for sample in tqdm(samples): sample_id, split = sample["id"], sample["split"] + + if args.snr_threshold is not None and "snr" in sample \ + and sample["snr"] < args.snr_threshold: + continue + if args.cer_threshold is not None \ + and id_to_cer[sample_id] > args.cer_threhold: + continue + normalized_utt = sample["tgt_text"] if id_to_alignment is not None: normalized_utt = " ".join(id_to_alignment[sample_id].tokens) @@ -186,7 +201,7 @@ def process(args): "sample_rate": args.sample_rate, "features": { "type": "spectrogram+melscale+log", - "eps": 1e-2, "n_mels": args.n_mels, "n_fft": args.n_fft, + "eps": 1e-5, "n_mels": args.n_mels, "n_fft": args.n_fft, "window_fn": "hann", "win_length": args.win_length, "hop_length": args.hop_length, "sample_rate": args.sample_rate, "win_len_t": win_len_t, "hop_len_t": hop_len_t, @@ -196,6 +211,17 @@ def process(args): } if len(speakers) > 1: extra["speaker_set_filename"] = "speakers.txt" + if args.add_fastspeech_targets: + pitch_min, pitch_max = get_feature_value_min_max( + [(out_root / n).as_posix() for n in pitch_paths.values()] + ) + energy_min, energy_max = get_feature_value_min_max( + [(out_root / n).as_posix() for n in energy_paths.values()] + ) + extra["features"]["pitch_min"] = pitch_min + extra["features"]["pitch_max"] = pitch_max + extra["features"]["energy_min"] = energy_min + extra["features"]["energy_max"] = energy_max gen_config_yaml( out_root, spm_filename=spm_filename, vocab_name=vocab_name, audio_root=out_root.as_posix(), input_channels=None, @@ -224,6 +250,9 @@ def main(): parser.add_argument("--textgrid-zip", type=str, default=None) parser.add_argument("--id-to-units-tsv", type=str, default=None) parser.add_argument("--add-fastspeech-targets", action="store_true") + parser.add_argument("--snr-threshold", type=float, default=None) + parser.add_argument("--cer-threshold", type=float, default=None) + parser.add_argument("--cer-tsv-path", type=str, default="") args = parser.parse_args() process(args) From bba000d8bac8a1678bd00f2ba4ffce5a0c982eae Mon Sep 17 00:00:00 2001 From: Evgeny Kharitonov <kharitonov@devfair0136.h2.fair> Date: Fri, 29 Oct 2021 13:40:04 -0700 Subject: [PATCH 485/774] Fixes for GSLM TTS Checkpoints (#2519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: 1. Add links to corresponding code_dict files, required by the TTS checkpoints 2. synthesize_audio_from_units.py has code_dict path configurable 3. Removed links to 5000-unit models, as those will not be supported. # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) Fixes https://github.com/pytorch/fairseq/issues/3970 and https://github.com/pytorch/fairseq/issues/3870 - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? Manually verified CPC50 & 100, HUBERT 50-200 ## What does this PR do? Fixes issues 3970 and and 3870 in the public repo 1. Add links to corresponding code_dict files, required by the TTS checkpoints 2. synthesize_audio_from_units.py has code_dict path configurable 3. Removed links to 500-unit models, as those will not be supported. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2519 Reviewed By: wnhsu Differential Revision: D32019362 Pulled By: eugene-kharitonov fbshipit-source-id: a2a1db99898e4d025c5a1e439bd63264406aad0a --- .../textless_nlp/gslm/speech2unit/README.md | 7 ++-- .../textless_nlp/gslm/unit2speech/README.md | 36 +++++++++---------- .../synthesize_audio_from_units.py | 8 +++++ 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/examples/textless_nlp/gslm/speech2unit/README.md b/examples/textless_nlp/gslm/speech2unit/README.md index 1a3d131ec1..434333f555 100644 --- a/examples/textless_nlp/gslm/speech2unit/README.md +++ b/examples/textless_nlp/gslm/speech2unit/README.md @@ -14,19 +14,15 @@ K-Means Model | Download Link Log Mel Filterbank + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km50/km.bin) Log Mel Filterbank + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km100/km.bin) Log Mel Filterbank + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km200/km.bin) -Log Mel Filterbank + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/km500/km.bin) Modified CPC + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km50/km.bin) Modified CPC + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km100/km.bin) Modified CPC + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km200/km.bin) -Modified CPC + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/km500/km.bin) HuBERT Base + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km50/km.bin) HuBERT Base + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km100/km.bin) HuBERT Base + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km200/km.bin) -HuBERT Base + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km500/km.bin) wav2vec 2.0 Large + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km50/km.bin) wav2vec 2.0 Large + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km100/km.bin) wav2vec 2.0 Large + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km200/km.bin) -wav2vec 2.0 Large + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/km500/km.bin) ### Quantization For quantizing speech with a given acoustic representation, please follow the steps below. @@ -68,4 +64,5 @@ Note about the manifest file is a file with paths and length of input audio file <relative_path_of_audio_file_1>\t<number_of_frames_1> <relative_path_of_audio_file_2>\t<number_of_frames_1> ... -``` \ No newline at end of file +``` + diff --git a/examples/textless_nlp/gslm/unit2speech/README.md b/examples/textless_nlp/gslm/unit2speech/README.md index 5710423065..e61601392b 100644 --- a/examples/textless_nlp/gslm/unit2speech/README.md +++ b/examples/textless_nlp/gslm/unit2speech/README.md @@ -2,24 +2,20 @@ Unit to speech model is modified Tacotron2 model that learns to synthesize speech from discrete speech units. All models are trained on quantized [LJSpeech](https://keithito.com/LJ-Speech-Dataset/). -Upstream Units | Download Link -|-|- -Log Mel Filterbank + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km50/tts_checkpoint_best.pt) -Log Mel Filterbank + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km100/tts_checkpoint_best.pt) -Log Mel Filterbank + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km200/tts_checkpoint_best.pt) -Log Mel Filterbank + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km500/tts_checkpoint_best.pt) -Modified CPC + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km50/tts_checkpoint_best.pt) -Modified CPC + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km100/tts_checkpoint_best.pt) -Modified CPC + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km200/tts_checkpoint_best.pt) -Modified CPC + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km500/tts_checkpoint_best.pt) -HuBERT Base + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km50/tts_checkpoint_best.pt) -HuBERT Base + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km100/tts_checkpoint_best.pt) -HuBERT Base + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km200/tts_checkpoint_best.pt) -HuBERT Base + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km500/tts_checkpoint_best.pt) -wav2vec 2.0 Large + KM50 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km50/tts_checkpoint_best.pt) -wav2vec 2.0 Large + KM100 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km100/tts_checkpoint_best.pt) -wav2vec 2.0 Large + KM200 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km200/tts_checkpoint_best.pt) -wav2vec 2.0 Large + KM500 | [download](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km500/tts_checkpoint_best.pt) +Upstream Units | Download Links | model md5 +|-|-|- +Log Mel Filterbank + KM50 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km50/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km50/code_dict) | 932b3b8527c0125f5f964b57762eba49 +Log Mel Filterbank + KM100 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km100/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km100/code_dict) | cde0b0d278a39011d0acbd5df27abdf4 +Log Mel Filterbank + KM200 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km200/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/logmel/tts_km200/code_dict) | dba0f1d4de64bc7976718834010b23e7 +Modified CPC + KM50 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km50/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km50/code_dict) | a585e8dd8890ea56164f17635dd8e613 +Modified CPC + KM100 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km100/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km100/code_dict) | 5c0ee2869b4f483d17f37f1a41a548e0 +Modified CPC + KM200 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km200/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/cpc/tts_km200/code_dict) | 2f0c9951cf37020d9464514bff48bc5d +HuBERT Base + KM50 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km50/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km50/code_dict) | 85ffce8baec5aa90035ab696fe676fce +HuBERT Base + KM100 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km100/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km100/code_dict) | df4a9c6ffd1bb00c91405432c234aba3 +HuBERT Base + KM200 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km200/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/tts_km200/code_dict) | ac72f2c0c563589819bec116c7f8d274 +wav2vec 2.0 Large + KM50 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km50/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km50/code_dict) | e3503d0ad822b2c24b89f68b857fedff +wav2vec 2.0 Large + KM100 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km100/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km100/code_dict) | eb3666e456ae4c96bf2a1eec825c13ed +wav2vec 2.0 Large + KM200 | [model](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km200/tts_checkpoint_best.pt) - [code_dict](https://dl.fbaipublicfiles.com/textless_nlp/gslm/w2v2/tts_km200/code_dict) | 777d343e963c4d64f04d78eef032f4e8 ## Run inference using a unit2speech model * Install librosa, unidecode and inflect using `pip install librosa, unidecode, inflect` @@ -32,11 +28,13 @@ TTS_MODEL_PATH=<unit2speech_model_file_path> QUANTIZED_UNIT_PATH=<quantized_audio_file_path> OUT_DIR=<dir_to_dump_synthesized_audio_files> WAVEGLOW_PATH=<path_where_you_have_downloaded_waveglow_checkpoint> +CODE_DICT_PATH=<unit2speech_code_dict_path> PYTHONPATH=${FAIRSEQ_ROOT}:${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/unit2speech python ${FAIRSEQ_ROOT}/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py \ --tts_model_path $TTS_MODEL_PATH \ --quantized_unit_path $QUANTIZED_UNIT_PATH \ --out_audio_dir $OUT_DIR \ --waveglow_path $WAVEGLOW_PATH \ + --code_dict_path $CODE_DICT_PATH \ --max_decoder_steps 2000 -``` \ No newline at end of file +``` diff --git a/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py b/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py index f226d5f505..80730843bf 100644 --- a/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py +++ b/examples/textless_nlp/gslm/unit2speech/synthesize_audio_from_units.py @@ -45,6 +45,11 @@ def get_parser(): type=str, help="Path to the waveglow checkpoint (vocoder).", ) + parser.add_argument( + "--code_dict_path", + type=str, + help="Code dict file path to use for inference", + ) parser.add_argument("--max_decoder_steps", type=int, default=2000) parser.add_argument("--denoiser_strength", type=float, default=0.1) parser.add_argument( @@ -72,7 +77,10 @@ def main(args, logger): logger.info(f"Loading Waveglow model from {args.waveglow_path}...") waveglow, denoiser = load_waveglow(waveglow_path=args.waveglow_path) + if not os.path.exists(hparams.code_dict): + hparams.code_dict = args.code_dict_path tts_dataset = TacotronInputDataset(hparams) + for name, quantized_units in zip(names_batch, quantized_units_batch): quantized_units_str = " ".join(map(str, quantized_units)) tts_input = tts_dataset.get_tensor(quantized_units_str) From d792b793a777bf660d2aaeb095c2381af189e626 Mon Sep 17 00:00:00 2001 From: Elizabeth Salesky <elizabeth.salesky@gmail.com> Date: Tue, 2 Nov 2021 13:05:51 -0700 Subject: [PATCH 486/774] update mtedx bibtex to conf proceedings (#3984) Summary: ## What does this PR do? Updates the bibtex to cite the mtedx dataset in the speech-to-text example, now that mtedx has been published (Interspeech 2021) Pull Request resolved: https://github.com/pytorch/fairseq/pull/3984 Reviewed By: yuntang Differential Revision: D32102153 Pulled By: kahne fbshipit-source-id: 1eea532e9032c116da447a4da30669305559a787 --- examples/speech_to_text/docs/mtedx_example.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/speech_to_text/docs/mtedx_example.md b/examples/speech_to_text/docs/mtedx_example.md index 25b4556aff..7e3d759557 100644 --- a/examples/speech_to_text/docs/mtedx_example.md +++ b/examples/speech_to_text/docs/mtedx_example.md @@ -176,10 +176,11 @@ For multilingual models, we force decoding from the target language ID token (as ## Citation Please cite as: ``` -@misc{salesky2021mtedx, - title={Multilingual TEDx Corpus for Speech Recognition and Translation}, - author={Elizabeth Salesky and Matthew Wiesner and Jacob Bremerman and Roldano Cattoni and Matteo Negri and Marco Turchi and Douglas W. Oard and Matt Post}, - year={2021}, +@inproceedings{salesky2021mtedx, + title={Multilingual TEDx Corpus for Speech Recognition and Translation}, + author={Elizabeth Salesky and Matthew Wiesner and Jacob Bremerman and Roldano Cattoni and Matteo Negri and Marco Turchi and Douglas W. Oard and Matt Post}, + booktitle={Proceedings of Interspeech}, + year={2021}, } @inproceedings{wang2020fairseqs2t, From c6360917ff93acebecfe09b28461166006b0c653 Mon Sep 17 00:00:00 2001 From: Yossi Adi <yossiadidrum@gmail.com> Date: Wed, 3 Nov 2021 08:58:36 -0700 Subject: [PATCH 487/774] Add a README for Textless NLP speech resynthesis (#3992) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/3992 ## What does this PR do? Add a readme pointing to the separate repo for the Textless NLP milestone https://github.com/fairinternal/fairseq-py/issues/2: speech resynthesis Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2537 Reviewed By: adiyoss, Abdel-rahmanMohamed Differential Revision: D32068424 Pulled By: wnhsu fbshipit-source-id: 9958c4d5aaf29a235e0af33d26b814120b4f688d --- .../textless_nlp/speech-resynth/README.md | 28 ++++++++++++++++++ .../textless_nlp/speech-resynth/img/fig.png | Bin 0 -> 307833 bytes 2 files changed, 28 insertions(+) create mode 100644 examples/textless_nlp/speech-resynth/README.md create mode 100644 examples/textless_nlp/speech-resynth/img/fig.png diff --git a/examples/textless_nlp/speech-resynth/README.md b/examples/textless_nlp/speech-resynth/README.md new file mode 100644 index 0000000000..a099682cdb --- /dev/null +++ b/examples/textless_nlp/speech-resynth/README.md @@ -0,0 +1,28 @@ + +# Speech Resynthesis from Discrete Disentangled Self-Supervised Representations +Landing page with usfull resources for the [Speech Resynthesis from Discrete Disentangled Self-Supervised Representations](https://arxiv.org/abs/2104.00355) paper. + +<p align="center"><img width="70%" src="img/fig.png" /></p> + +__Abstract__: We propose using self-supervised discrete representations for the task of speech resynthesis. To generate disentangled representation, we separately extract low-bitrate representations for speech content, prosodic information, and speaker identity. This allows to synthesize speech in a controllable manner. We analyze various state-of-the-art, self-supervised representation learning methods and shed light on the advantages of each method while considering reconstruction quality and disentanglement properties. Specifically, we evaluate the F0 reconstruction, speaker identification performance (for both resynthesis and voice conversion), recordings' intelligibility, and overall quality using subjective human evaluation. Lastly, we demonstrate how these representations can be used for an ultra-lightweight speech codec. Using the obtained representations, we can get to a rate of 365 bits per second while providing better speech quality than the baseline methods. + + +## Quick Links +- [Paper](https://arxiv.org/pdf/2104.00355.pdf) +- [Samples](https://speechbot.github.io/resynthesis/index.html) +- [Code](https://github.com/facebookresearch/speech-resynthesis) + +The codebase for the [Speech Resynthesis from Discrete Disentangled Self-Supervised Representations](https://arxiv.org/abs/2104.00355) paper can be found under the following [repository](https://github.com/facebookresearch/speech-resynthesis). + + +## Citation +``` +@inproceedings{polyak21_interspeech, + author={Adam Polyak and Yossi Adi and Jade Copet and + Eugene Kharitonov and Kushal Lakhotia and + Wei-Ning Hsu and Abdelrahman Mohamed and Emmanuel Dupoux}, + title={{Speech Resynthesis from Discrete Disentangled Self-Supervised Representations}}, + year=2021, + booktitle={Proc. Interspeech 2021}, +} +``` diff --git a/examples/textless_nlp/speech-resynth/img/fig.png b/examples/textless_nlp/speech-resynth/img/fig.png new file mode 100644 index 0000000000000000000000000000000000000000..585bbbce149e5420d67532d6473da4d188e13432 GIT binary patch literal 307833 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 literal 0 HcmV?d00001 From 7fb3792845b474a41de7c2fe47141dcc37243ef6 Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 3 Nov 2021 08:59:14 -0700 Subject: [PATCH 488/774] Fix einsum transpose (#2532) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2532 Reviewed By: myleott Differential Revision: D32049520 Pulled By: sshleifer fbshipit-source-id: 9036c6db48c15e8a04a27a7d3660bdb2a248f0a5 --- fairseq/modules/transformer_layer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index d685f72bb7..3ad2be959d 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -377,7 +377,7 @@ def forward( if self.c_attn is not None: tgt_len, bsz = x.size(0), x.size(1) x = x.view(tgt_len, bsz, self.nh, self.head_dim) - x = torch.einsum('tbhd,h->tbdh', x, self.c_attn) + x = torch.einsum('tbhd,h->tbhd', x, self.c_attn) x = x.reshape(tgt_len, bsz, self.embed_dim) if self.attn_ln is not None: x = self.attn_ln(x) From e69a7c1d8a7ca09435f6406c4ef6aaa63c9a093c Mon Sep 17 00:00:00 2001 From: Torge Berckmann <tucker.berckmann@dfki.de> Date: Wed, 3 Nov 2021 19:50:33 -0700 Subject: [PATCH 489/774] Joint s2t fixes (#3940) Summary: # Before submitting - [-] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3939 Fixes https://github.com/pytorch/fairseq/issues/3941 ## PR review Awaiting review. ## Did you have fun? Of course! Pull Request resolved: https://github.com/pytorch/fairseq/pull/3940 Reviewed By: yuntang Differential Revision: D32102157 Pulled By: kahne fbshipit-source-id: ec68dc3c7738473406b6a5ddabdb035e13a261b4 --- examples/speech_text_joint_to_text/docs/ende-mustc.md | 4 ++-- .../models/s2t_dualinputtransformer.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/speech_text_joint_to_text/docs/ende-mustc.md b/examples/speech_text_joint_to_text/docs/ende-mustc.md index e47ff3c550..86b8fa91fe 100644 --- a/examples/speech_text_joint_to_text/docs/ende-mustc.md +++ b/examples/speech_text_joint_to_text/docs/ende-mustc.md @@ -97,8 +97,8 @@ python ./fairseq_cli/generate.py \ --results-path ${infer_results} \ --batch-size 512 \ --path ${model} \ - --gen-subset tst-COMMON \ - --config-yaml config_spm.yaml \ + --gen-subset tst-COMMON_st \ + --config-yaml config.yaml \ --scoring sacrebleu \ --beam 5 --lenpen 1.0 \ --user-dir examples/speech_text_joint_to_text \ diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py index f643b98265..c4ec41bda1 100644 --- a/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py @@ -850,6 +850,7 @@ def build_decoder(cls, args, task): "adaptive_softmax_cutoff": args.adaptive_softmax_cutoff, "tie_adaptive_weights": args.tie_adaptive_weights, "no_token_positional_embeddings": args.no_token_positional_embeddings, + "encoder": {"embed_dim":args.encoder_embed_dim} } dec_cfg = namedtuple("args", dec_cfg.keys())(*dec_cfg.values()) dec_emb = nn.Embedding( From 199733f4de94bef3080c0fc022667a66a69cd465 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 4 Nov 2021 09:23:20 -0700 Subject: [PATCH 490/774] improve audio_utils.read_from_stored_zip with mmap IO Summary: Improve audio_utils.read_from_stored_zip with mmap IO. Benchmarking: 50k random read - mmap 1.49 ms/item - regular: 1.63 ms/item Reviewed By: yuntang Differential Revision: D32162298 fbshipit-source-id: 502f1dfafe32f425086e999e0b6d542eb3e9d8f0 --- fairseq/data/audio/audio_utils.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index b9444cb8d0..35e7fb2a2a 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -6,6 +6,7 @@ from pathlib import Path from typing import BinaryIO, Optional, Tuple, Union, List +import mmap import numpy as np import torch @@ -178,13 +179,17 @@ def is_sf_audio_data(data: bytes) -> bool: return is_wav or is_flac or is_ogg -def read_from_stored_zip(zip_path: str, offset: int, file_size: int) -> bytes: - with open(zip_path, "rb") as f: - f.seek(offset) - data = f.read(file_size) +def mmap_read(path: str, offset: int, length: int) -> bytes: + with open(path, "rb") as f: + with mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) as mmap_o: + data = mmap_o[offset: offset + length] return data +def read_from_stored_zip(zip_path: str, offset: int, length: int) -> bytes: + return mmap_read(zip_path, offset, length) + + def parse_path(path: str) -> Tuple[str, List[int]]: """Parse data path which is either a path to 1. a .npy/.wav/.flac/.ogg file From 30dc8b73312087674095f6f2684c2d6aad208b96 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 4 Nov 2021 09:23:44 -0700 Subject: [PATCH 491/774] enable BPE-dropout / unigram sampling Summary: enable BPE-dropout / unigram sampling Reviewed By: yuntang Differential Revision: D32162340 fbshipit-source-id: 3829e84fb572adeb7b0302ccfa15cbe88a782e3f --- fairseq/data/encoders/sentencepiece_bpe.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/fairseq/data/encoders/sentencepiece_bpe.py b/fairseq/data/encoders/sentencepiece_bpe.py index a76d46a201..fc830f6e0d 100644 --- a/fairseq/data/encoders/sentencepiece_bpe.py +++ b/fairseq/data/encoders/sentencepiece_bpe.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. from dataclasses import dataclass, field +from typing import Optional from fairseq import file_utils from fairseq.data.encoders import register_bpe @@ -15,11 +16,21 @@ class SentencepieceConfig(FairseqDataclass): sentencepiece_model: str = field( default="???", metadata={"help": "path to sentencepiece model"} ) + sentencepiece_enable_sampling: bool = field( + default=False, metadata={"help": "enable sampling"} + ) + sentencepiece_alpha: Optional[float] = field( + default=None, + metadata={"help": "soothing parameter for unigram sampling, " + "and merge probability for BPE-dropout"} + ) @register_bpe("sentencepiece", dataclass=SentencepieceConfig) class SentencepieceBPE(object): def __init__(self, cfg): + self.enable_sampling = cfg.sentencepiece_enable_sampling + self.alpha = cfg.sentencepiece_alpha sentencepiece_model = file_utils.cached_path(cfg.sentencepiece_model) try: import sentencepiece as spm @@ -32,7 +43,12 @@ def __init__(self, cfg): ) def encode(self, x: str) -> str: - return " ".join(self.sp.EncodeAsPieces(x)) + return " ".join( + self.sp.Encode( + x, out_type=str, enable_sampling=self.enable_sampling, + alpha=self.alpha + ) + ) def decode(self, x: str) -> str: return x.replace(" ", "").replace("\u2581", " ").strip() From 0b21875e45f332bedbcc0617dcf9379d3c03855f Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 4 Nov 2021 12:27:52 -0700 Subject: [PATCH 492/774] add postnet to fastspeech2 Summary: add postnet to fastspeech2 Reviewed By: wnhsu Differential Revision: D32162463 fbshipit-source-id: 0c07312985602b4332f73c89d1a536fac53b6a29 --- fairseq/criterions/fastspeech2_loss.py | 5 +++- fairseq/models/text_to_speech/fastspeech2.py | 27 ++++++++++++++++++-- fairseq/speech_generator.py | 4 ++- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/fairseq/criterions/fastspeech2_loss.py b/fairseq/criterions/fastspeech2_loss.py index 085d5628d4..b17b507023 100644 --- a/fairseq/criterions/fastspeech2_loss.py +++ b/fairseq/criterions/fastspeech2_loss.py @@ -35,7 +35,7 @@ def forward(self, model: FairseqEncoderModel, sample, reduction="mean"): src_tokens = sample["net_input"]["src_tokens"] src_lens = sample["net_input"]["src_lengths"] tgt_lens = sample["target_lengths"] - _feat_out, _, log_dur_out, pitch_out, energy_out = model( + _feat_out, _feat_out_post, _, log_dur_out, pitch_out, energy_out = model( src_tokens=src_tokens, src_lengths=src_lens, prev_output_tokens=sample["net_input"]["prev_output_tokens"], @@ -56,6 +56,9 @@ def forward(self, model: FairseqEncoderModel, sample, reduction="mean"): feat_out, feat = _feat_out[tgt_mask], sample["target"][tgt_mask] l1_loss = F.l1_loss(feat_out, feat, reduction=reduction) + if _feat_out_post is not None: + l1_loss += F.l1_loss(_feat_out_post[tgt_mask], feat, + reduction=reduction) pitch_loss = F.mse_loss(pitch_out, pitches, reduction=reduction) energy_loss = F.mse_loss(energy_out, energies, reduction=reduction) diff --git a/fairseq/models/text_to_speech/fastspeech2.py b/fairseq/models/text_to_speech/fastspeech2.py index 9c38d0917d..4fe9cc4d2a 100644 --- a/fairseq/models/text_to_speech/fastspeech2.py +++ b/fairseq/models/text_to_speech/fastspeech2.py @@ -15,6 +15,7 @@ ) from fairseq import utils from fairseq.data.data_utils import lengths_to_padding_mask +from fairseq.models.text_to_speech.tacotron2 import Postnet logger = logging.getLogger(__name__) @@ -243,6 +244,14 @@ def __init__(self, args, src_dict, embed_speaker): self.out_proj = nn.Linear(args.decoder_embed_dim, self.out_dim) + self.postnet = None + if args.add_postnet: + self.postnet = Postnet( + self.out_dim, args.postnet_conv_dim, + args.postnet_conv_kernel_size, + args.postnet_layers, args.postnet_dropout + ) + self.apply(model_init) def forward(self, src_tokens, src_lengths=None, speaker=None, @@ -270,8 +279,10 @@ def forward(self, src_tokens, src_lengths=None, speaker=None, x = layer(x, dec_padding_mask) x = self.out_proj(x) - - return x, out_lens, log_dur_out, pitch_out, energy_out + x_post = None + if self.postnet is not None: + x_post = x + self.postnet(x) + return x, x_post, out_lens, log_dur_out, pitch_out, energy_out @register_model("fastspeech2") @@ -302,6 +313,12 @@ def add_args(parser): parser.add_argument("--var-pred-hidden-dim", type=int) parser.add_argument("--var-pred-kernel-size", type=int) parser.add_argument("--var-pred-dropout", type=float) + # postnet + parser.add_argument("--add-postnet", action="store_true") + parser.add_argument("--postnet-dropout", type=float) + parser.add_argument("--postnet-layers", type=int) + parser.add_argument("--postnet-conv-dim", type=int) + parser.add_argument("--postnet-conv-kernel-size", type=int) def __init__(self, encoder, args, src_dict): super().__init__(encoder) @@ -350,3 +367,9 @@ def base_architecture(args): args.var_pred_hidden_dim = getattr(args, "var_pred_hidden_dim", 256) args.var_pred_kernel_size = getattr(args, "var_pred_kernel_size", 3) args.var_pred_dropout = getattr(args, "var_pred_dropout", 0.5) + # postnet + args.add_postnet = getattr(args, "add_postnet", False) + args.postnet_dropout = getattr(args, "postnet_dropout", 0.5) + args.postnet_layers = getattr(args, "postnet_layers", 5) + args.postnet_conv_dim = getattr(args, "postnet_conv_dim", 512) + args.postnet_conv_kernel_size = getattr(args, "postnet_conv_kernel_size", 5) diff --git a/fairseq/speech_generator.py b/fairseq/speech_generator.py index 8086e34d2b..8276335eae 100644 --- a/fairseq/speech_generator.py +++ b/fairseq/speech_generator.py @@ -128,7 +128,7 @@ def generate(self, model, sample, has_targ=False, **kwargs): out_dim = model.encoder.out_dim raw_dim = out_dim // n_frames_per_step - feat, out_lens, log_dur_out, _, _ = model( + feat, feat_post, out_lens, log_dur_out, _, _ = model( src_tokens=sample["net_input"]["src_tokens"], src_lengths=sample["net_input"]["src_lengths"], prev_output_tokens=sample["net_input"]["prev_output_tokens"], @@ -136,6 +136,8 @@ def generate(self, model, sample, has_targ=False, **kwargs): target_lengths=sample["target_lengths"], speaker=sample["speaker"] ) + if feat_post is not None: + feat = feat_post feat = feat.view(bsz, -1, raw_dim) feat = self.gcmvn_denormalize(feat) From 3a5838c320c5b7afc3a6fba5736bca22503ef804 Mon Sep 17 00:00:00 2001 From: Vinayak Tantia <tantia.vinayak1@gmail.com> Date: Tue, 9 Nov 2021 09:41:21 -0800 Subject: [PATCH 493/774] Update implemention of SlowMo to its implementation in Fairscale (#3996) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? SlowMo is being moved to [Fairscale](https://fairscale.readthedocs.io/en/latest/). This commit updates the implementation of SlowMo to the Fairscale version. It also adds tests for SlowMo. Note: This PR is currently for review. It will be merged at a later date once SlowMo has been updated to Fairscale. SlowMo is being merged to Fairscale as part of [a PR](https://github.com/facebookresearch/fairscale/pull/378). So, once that PR is merged to Fairscale, this PR on Fairseq will be ready for merge ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3996 Reviewed By: dianaml0 Differential Revision: D32280163 Pulled By: vtantia fbshipit-source-id: 70c97b04a7cdc90ada7099375c2a31b0c978ba70 --- fairseq/dataclass/configs.py | 10 ++++++++-- fairseq/dataclass/constants.py | 2 +- fairseq/models/distributed_fairseq_model.py | 21 ++++++++++----------- fairseq/trainer.py | 18 +++++++----------- tests/gpu/test_binaries_gpu.py | 21 +++++++++++++++++++-- 5 files changed, 45 insertions(+), 27 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 80caa0f2da..289bb8896b 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -338,8 +338,14 @@ class DistributedTrainingConfig(FairseqDataclass): "0.2 for 32 GPUs; 0.5 for 64 GPUs, 0.6 for > 64 GPUs" }, ) - slowmo_algorithm: str = field( - default="LocalSGD", metadata={"help": "whether to use LocalSGD or SGP"} + slowmo_base_algorithm: str = field( + default="localsgd", + metadata={ + "help": "Base algorithm. Either 'localsgd' or 'sgp'. Please refer " + "to the documentation of 'slowmo_base_algorithm' parameter in " + "https://fairscale.readthedocs.io/en/latest/api/experimental/nn/slowmo_ddp.html " + "for more details" + }, ) localsgd_frequency: int = field( default=3, metadata={"help": "Local SGD allreduce frequency"} diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 4f159cfe9a..7e5aef7067 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -41,7 +41,7 @@ def ChoiceEnum(choices: List[str]): "legacy_ddp", "no_c10d", # alias for legacy_ddp "pytorch_ddp", - "slow_mo", + "slowmo", ]) DDP_COMM_HOOK_CHOICES = ChoiceEnum(["none", "fp16"]) DATASET_IMPL_CHOICES = ChoiceEnum(["raw", "lazy", "cached", "mmap", "fasta", "huffman"]) diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index 5eda227640..de8d6ac115 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -23,11 +23,11 @@ logger = logging.getLogger(__name__) -_GOSSIP_DISABLED = False +_SLOWMO_DDP_DISABLED = False try: - import gossip + from fairscale.experimental.nn.data_parallel import SlowMoBaseAlgorithm, SlowMoDistributedDataParallel except ImportError: - _GOSSIP_DISABLED = True + _SLOWMO_DDP_DISABLED = True def DistributedFairseqModel(args, model, process_group, device): @@ -89,11 +89,11 @@ def DistributedFairseqModel(args, model, process_group, device): ) # forward missing getattr and state_dict/load_state_dict to orig model wrapped_model = ModuleProxyWrapper(wrapped_model) - elif args.ddp_backend == "slow_mo": - if _GOSSIP_DISABLED: + elif args.ddp_backend == "slowmo": + if _SLOWMO_DDP_DISABLED: raise ImportError( - "Cannot find gossip library. Please install from: " - "github.com/facebookresearch/stochastic_gradient_push" + "Cannot find SlowMoDistributedDataParallel. " + "Please install fairscale with: pip install fairscale" ) # The values of slowmo_momentum below were obtained by tuning on the @@ -107,15 +107,14 @@ def DistributedFairseqModel(args, model, process_group, device): args.slowmo_momentum = 0.5 else: args.slowmo_momentum = 0.6 + slowmo_base_algorithm = SlowMoBaseAlgorithm[args.slowmo_base_algorithm.upper()] - wrapped_model = gossip.GossipDataParallel( + wrapped_model = SlowMoDistributedDataParallel( module=model.to(device), - device_ids=[args.device_id], - output_device=args.device_id, broadcast_buffers=args.broadcast_buffers, nprocs_per_node=args.nprocs_per_node, slowmo_momentum=args.slowmo_momentum, - localsgd=(args.slowmo_algorithm == "LocalSGD"), + slowmo_base_algorithm=slowmo_base_algorithm, localsgd_frequency=args.localsgd_frequency, ) # forward missing getattr and state_dict/load_state_dict to orig model diff --git a/fairseq/trainer.py b/fairseq/trainer.py index e46ccfe0b8..94130c8c3a 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -855,7 +855,7 @@ def maybe_no_sync(): if not self.tpu: if ( not self.cfg.optimization.use_bmuf - and self.cfg.distributed_training.ddp_backend != "slow_mo" + and self.cfg.distributed_training.ddp_backend != "slowmo" ): self._check_grad_norms(grad_norm) if not torch.isfinite(grad_norm).all(): @@ -912,18 +912,14 @@ def maybe_no_sync(): # Some distributed wrappers (e.g., SlowMo) need access to the optimizer # after the step - if hasattr(self.model, "perform_additional_optimizer_actions"): - if hasattr(self.optimizer, "fp32_params"): - self.model.perform_additional_optimizer_actions( - self.optimizer.optimizer, self.optimizer.fp32_params - ) - else: - self.model.perform_additional_optimizer_actions( - self.optimizer.optimizer - ) + if hasattr(self.model, "perform_slowmo"): + self.model.perform_slowmo( + self.optimizer.optimizer, + getattr(self.optimizer, "fp32_params", None) + ) logging_output = None - if not overflow or self.cfg.distributed_training.ddp_backend == "slow_mo": + if not overflow or self.cfg.distributed_training.ddp_backend == "slowmo": self.set_num_updates(self.get_num_updates() + 1) if self.cfg.ema.store_ema: diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index de8c242613..99eb7f558e 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -32,15 +32,32 @@ def tearDown(self): logging.disable(logging.NOTSET) def test_fp16_multigpu(self): + self._test_multigpu( + "test_fp16", ["--fp16"] + ) + + def test_slowmo_multigpu(self): + self._test_multigpu( + "test_slowmo", + ["--ddp-backend", "slowmo", "--nprocs-per-node", "1"] + ) + + def test_slowmo_single_node_multigpu(self): + self._test_multigpu( + "test_slowmo_single_node", + ["--ddp-backend", "slowmo", "--nprocs-per-node", "2"] + ) + + def _test_multigpu(self, test_name, test_args): with contextlib.redirect_stdout(StringIO()): - with tempfile.TemporaryDirectory("test_fp16") as data_dir: + with tempfile.TemporaryDirectory(test_name) as data_dir: log = os.path.join(data_dir, "train.log") create_dummy_data(data_dir) preprocess_translation_data(data_dir) train_translation_model( data_dir, "fconv_iwslt_de_en", - ["--fp16", "--log-file", log], + test_args + ["--log-file", log], world_size=min(torch.cuda.device_count(), 2), ) generate_main(data_dir) From 47c58f0858b5484a18f39549845790267cffee1a Mon Sep 17 00:00:00 2001 From: Chau Tran <chau@fb.com> Date: Wed, 10 Nov 2021 04:13:50 -0800 Subject: [PATCH 494/774] wmt21 scripts and models (#2613) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2613 Pull Request resolved: https://github.com/pytorch/fairseq/pull/4009 add wmt21 models and scripts Reviewed By: huihuifan Differential Revision: D32311009 fbshipit-source-id: b269ce732ba9b02634947134d4f0cd774b565b2c --- examples/wmt21/README.md | 25 ++++++ examples/wmt21/eval.sh | 49 ++++++++++ .../wmt21/scripts/normalize-punctuation.perl | 90 +++++++++++++++++++ .../scripts/replace-unicode-punctuation.perl | 55 ++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 examples/wmt21/README.md create mode 100644 examples/wmt21/eval.sh create mode 100644 examples/wmt21/scripts/normalize-punctuation.perl create mode 100644 examples/wmt21/scripts/replace-unicode-punctuation.perl diff --git a/examples/wmt21/README.md b/examples/wmt21/README.md new file mode 100644 index 0000000000..524fffb724 --- /dev/null +++ b/examples/wmt21/README.md @@ -0,0 +1,25 @@ +# WMT 21 + +This page provides pointers to the models of Facebook AI's WMT'21 news translation task submission [(Tran et al., 2021)](https://arxiv.org/abs/2108.03265). + +## Single best dense models + +Model | Description | Download +---|---|--- +`wmt21.dense-24-wide.X-En` | X-En | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt21.dense-24-wide.X-En.tar.gz) +`wmt21.dense-24-wide.En-X` | En-X | [download (.tar.gz)](https://dl.fbaipublicfiles.com/fairseq/models/wmt21.dense-24-wide.En-X.tar.gz) + +## Example usage + +See eval.sh + + +## Citation +```bibtex +@inproceedings{tran2021facebook + title={Facebook AI’s WMT21 News Translation Task Submission}, + author={Chau Tran and Shruti Bhosale and James Cross and Philipp Koehn and Sergey Edunov and Angela Fan}, + booktitle={Proc. of WMT}, + year={2021}, +} +``` diff --git a/examples/wmt21/eval.sh b/examples/wmt21/eval.sh new file mode 100644 index 0000000000..b36d934c51 --- /dev/null +++ b/examples/wmt21/eval.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. +# All rights reserved. +# +# This source code is licensed under the license found in the +# LICENSE file in the root directory of this source tree. +SRC=en +TGT=is +MODEL_NAME=wmt21.dense-24-wide.En-X + +PATH_TO_FAIRSEQ_PY=. +TMP_DIR=generation_tmp +mkdir -p $TMP_DIR + +REPLACE_UNICODE_PUNCT=$PATH_TO_FAIRSEQ_PY/examples/wmt21/scripts/replace-unicode-punctuation.perl +NORM_PUNCT=$PATH_TO_FAIRSEQ_PY/examples/wmt21/scripts/normalize-punctuation.perl +if [ ! -d "${TMP_DIR}/${MODEL_NAME}" ]; then + wget https://dl.fbaipublicfiles.com/fairseq/models/${MODEL_NAME}.tar.gz -P $TMP_DIR/ + tar -xvf $TMP_DIR/${MODEL_NAME}.tar.gz -C $TMP_DIR +fi +MODEL_DIR=$TMP_DIR/${MODEL_NAME} +if [ ! -d "${TMP_DIR}/wmt21-news-systems" ]; then + git clone https://github.com/wmt-conference/wmt21-news-systems $TMP_DIR/wmt21-news-systems +fi + +DOMAIN_TAG="wmtdata newsdomain" +INPUT_FILE=$TMP_DIR/wmt21-news-systems/txt/sources/newstest2021.${SRC}-${TGT}.src.${SRC} +REF_FILE=$TMP_DIR/wmt21-news-systems/txt/references/newstest2021.${SRC}-${TGT}.ref.A.${TGT} + +# Translate +cat ${INPUT_FILE} | sed "s/^/${DOMAIN_TAG} /" | $REPLACE_UNICODE_PUNCT | $NORM_PUNCT -l ${SRC} | python $PATH_TO_FAIRSEQ_PY/fairseq_cli/interactive.py $MODEL_DIR \ + --path ${MODEL_DIR}/checkpoint.pt \ + --task translation_multi_simple_epoch \ + --langs "en,ha,is,ja,cs,ru,zh,de" \ + --lang-pairs $SRC-$TGT \ + --bpe "sentencepiece" \ + --sentencepiece-model ${MODEL_DIR}/sentencepiece.model \ + --buffer-size 1024 \ + --batch-size 10 -s $SRC -t $TGT \ + --decoder-langtok \ + --encoder-langtok src \ + --beam 5 \ + --lenpen 1.0 \ + --fp16 > $TMP_DIR/${SRC}-${TGT}.gen_log + +cat $TMP_DIR/$SRC-$TGT.gen_log | grep -P "^D-" | cut -f3 > $TMP_DIR/$SRC-$TGT.hyp + +# Calculate BLEU score +sacrebleu -l $SRC-$TGT $REF_FILE < $TMP_DIR/$SRC-$TGT.hyp diff --git a/examples/wmt21/scripts/normalize-punctuation.perl b/examples/wmt21/scripts/normalize-punctuation.perl new file mode 100644 index 0000000000..a7c0750f58 --- /dev/null +++ b/examples/wmt21/scripts/normalize-punctuation.perl @@ -0,0 +1,90 @@ +#!/usr/bin/env perl +# +# This file is part of moses. Its use is licensed under the GNU Lesser General +# Public License version 2.1 or, at your option, any later version. + +use warnings; +use strict; + +my $language = "en"; +my $PENN = 0; + +while (@ARGV) { + $_ = shift; + /^-b$/ && ($| = 1, next); # not buffered (flush each line) + /^-l$/ && ($language = shift, next); + /^[^\-]/ && ($language = $_, next); + /^-penn$/ && ($PENN = 1, next); +} + +while(<STDIN>) { + s/\r//g; + # remove extra spaces + s/\(/ \(/g; + s/\)/\) /g; s/ +/ /g; + s/\) ([\.\!\:\?\;\,])/\)$1/g; + s/\( /\(/g; + s/ \)/\)/g; + s/(\d) \%/$1\%/g; + s/ :/:/g; + s/ ;/;/g; + # normalize unicode punctuation + if ($PENN == 0) { + s/\`/\'/g; + s/\'\'/ \" /g; + } + + s/„/\"/g; + s/“/\"/g; + s/”/\"/g; + s/–/-/g; + s/—/ - /g; s/ +/ /g; + s/´/\'/g; + s/([a-z])‘([a-z])/$1\'$2/gi; + s/([a-z])’([a-z])/$1\'$2/gi; + s/‘/\'/g; + s/‚/\'/g; + s/’/\"/g; + s/''/\"/g; + s/´´/\"/g; + s/…/.../g; + # French quotes + s/ « / \"/g; + s/« /\"/g; + s/«/\"/g; + s/ » /\" /g; + s/ »/\"/g; + s/»/\"/g; + # handle pseudo-spaces + s/ \%/\%/g; + s/nº /nº /g; + s/ :/:/g; + s/ ºC/ ºC/g; + s/ cm/ cm/g; + s/ \?/\?/g; + s/ \!/\!/g; + s/ ;/;/g; + s/, /, /g; s/ +/ /g; + + # English "quotation," followed by comma, style + if ($language eq "en") { + s/\"([,\.]+)/$1\"/g; + } + # Czech is confused + elsif ($language eq "cs" || $language eq "cz") { + } + # German/Spanish/French "quotation", followed by comma, style + else { + s/,\"/\",/g; + s/(\.+)\"(\s*[^<])/\"$1$2/g; # don't fix period at end of sentence + } + + + if ($language eq "de" || $language eq "es" || $language eq "cz" || $language eq "cs" || $language eq "fr") { + s/(\d) (\d)/$1,$2/g; + } + else { + s/(\d) (\d)/$1.$2/g; + } + print $_; +} diff --git a/examples/wmt21/scripts/replace-unicode-punctuation.perl b/examples/wmt21/scripts/replace-unicode-punctuation.perl new file mode 100644 index 0000000000..faed2cd9d8 --- /dev/null +++ b/examples/wmt21/scripts/replace-unicode-punctuation.perl @@ -0,0 +1,55 @@ +#!/usr/bin/env perl +# +# This file is part of moses. Its use is licensed under the GNU Lesser General +# Public License version 2.1 or, at your option, any later version. + +use warnings; +use strict; + +while (@ARGV) { + $_ = shift; + /^-b$/ && ($| = 1, next); # not buffered (flush each line) +} + +#binmode(STDIN, ":utf8"); +#binmode(STDOUT, ":utf8"); + +while(<STDIN>) { + s/,/,/g; + s/。 */. /g; + s/、/,/g; + s/”/"/g; + s/“/"/g; + s/∶/:/g; + s/:/:/g; + s/?/\?/g; + s/《/"/g; + s/》/"/g; + s/)/\)/g; + s/!/\!/g; + s/(/\(/g; + s/;/;/g; + s/1/1/g; + s/」/"/g; + s/「/"/g; + s/0/0/g; + s/3/3/g; + s/2/2/g; + s/5/5/g; + s/6/6/g; + s/9/9/g; + s/7/7/g; + s/8/8/g; + s/4/4/g; + s/. */. /g; + s/~/\~/g; + s/’/\'/g; + s/…/\.\.\./g; + s/━/\-/g; + s/〈/\</g; + s/〉/\>/g; + s/【/\[/g; + s/】/\]/g; + s/%/\%/g; + print $_; +} From 68ce4c7f85b5ab26c8f2f7b7faaba6b30636d7ce Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 11 Nov 2021 19:39:44 -0800 Subject: [PATCH 495/774] fix crash when num procs > 1 (#2623) Summary: this fixes a crash when using num_workers > 0 and num processes > 1 (e.g. by launching on slurm with tasks-per-node > 1 or using torch.distributed/torchrun with num gpus > 1). the root cause is some kind of bug in torch.split() that holds on to memory. when data loaders recycle, the program crashes when trying to release already released memory Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2623 Reviewed By: arbabu123 Differential Revision: D32342431 Pulled By: alexeib fbshipit-source-id: 278c7e0b09cfd770f375865d472bc52fb5835bd2 --- fairseq/distributed/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index b7736116f9..e6459447d7 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -662,7 +662,7 @@ def _all_reduce_dict(data: OrderedDict): return data buf = torch.cat([t.view(-1) for t in data.values()]).to(device=device) all_reduce(buf, group=group) - split_buf = torch.split(buf, [t.numel() for t in data.values()]) + split_buf = torch.split(buf.clone(), [t.numel() for t in data.values()]) reduced_data = [t.view_as(orig) for t, orig in zip(split_buf, data.values())] return OrderedDict(zip(data.keys(), reduced_data)) From eb2bed115497834a800ff787d36d6615205462d0 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Sat, 13 Nov 2021 12:10:46 -0800 Subject: [PATCH 496/774] update wav2vec readme for updated rw2v model (#2636) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: ## What does this PR do? - Update robust wav2vec2 fine-tuned checkpoints to include dictionary and w2v_args. - Update README to point to the updated checkpoints ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2636 Reviewed By: alexeib Differential Revision: D32414361 Pulled By: wnhsu fbshipit-source-id: e4bf41e78593cde8dc08a1bfacdd3ec5005e54bc --- examples/wav2vec/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 47aad5e71b..db363f3f12 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -31,11 +31,11 @@ Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https:/ Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv.pt) -Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | 960 hours Librispeech | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv_ftls960.pt) -Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | 300 hours Switchboard | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv_ftsb300.pt) +Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | 960 hours Librispeech | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv_ftls960_updated.pt) +Wav2Vec 2.0 Large (LV-60 + CV + SWBD + FSH) ** | 300 hours Switchboard | [Libri-Light](https://github.com/facebookresearch/libri-light) + [CommonVoice](https://commonvoice.mozilla.org/en/languages) + [Switchboard](https://catalog.ldc.upenn.edu/LDC97S62) + [Fisher](https://catalog.ldc.upenn.edu/LDC2004T19) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/w2v_large_lv_fsh_swbd_cv_ftsb300_updated.pt) \* updated (Oct. 24, 2020)\ -** updated (Jul. 8, 2021) +** updated (Nov. 13, 2021) We also release multilingual pre-trained wav2vec 2.0 (XLSR) models: From 4ccb288ff56aee7083cd1d5b23dfdbde86957304 Mon Sep 17 00:00:00 2001 From: Apoorv Vyas <vyasapoorv@devfair0164.h2.fair> Date: Tue, 16 Nov 2021 13:14:33 -0800 Subject: [PATCH 497/774] Fix logits padding mask for wav2vec asr model (#2469) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: The logits were not correctly masked leading to significant WER degradation for batched inference with padded inputs. This resolves it. However there is minor degradation still from somewhere else. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes logits padding mask for wav2vec asr model. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2469 Reviewed By: arbabu123 Differential Revision: D32469676 Pulled By: alexeib fbshipit-source-id: 154bb6523f9300e4b6c1cf2631424fd22f582bc5 --- fairseq/models/wav2vec/wav2vec2_asr.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index eb5d819da5..3ce05a30b8 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -187,8 +187,10 @@ def get_logits(self, net_output, normalize=False): raise Exception(f"invalid blank mode {self.blank_mode}") if net_output["padding_mask"] is not None and net_output["padding_mask"].any(): - logits[net_output["padding_mask"].T][..., 0] = float("inf") - logits[net_output["padding_mask"].T][..., 1:] = float("-inf") + number_of_classes = logits.size(-1) + masking_tensor = torch.ones(number_of_classes) * float("-inf") + masking_tensor[0] = float("inf") + logits[net_output["padding_mask"].T] = masking_tensor.type_as(logits) if normalize: logits = utils.log_softmax(logits.float(), dim=-1) From 89ec6e7efff867d258947acafc57189b257212d0 Mon Sep 17 00:00:00 2001 From: Apoorv Vyas <vyasapoorv@learnfair2274.h2.fair> Date: Tue, 16 Nov 2021 13:52:15 -0800 Subject: [PATCH 498/774] Add "grouped_shuffling" for batch shuffling in groups of total workers (#2391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - Allows for faster training on multiple GPUs when batches are based on sorted input sequences. - Instead of shuffling batches randomly followed by distribution on workers, we group the batches in sets of total workers and then shuffle the groups. When the batches are sorted by length this ensures that each worker receives similar length inputs. # Before submitting - [N] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [Y] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [N] Did you write any new necessary tests? ## What does this PR do? Adds option "grouped_shuffling" to the dataclass to allow batches to be first grouped in set of total workers followed by shuffling of the groups. This reduces the sequence length discrepancy among the workers when the batches were created from inputs sorted by sequence lengths. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2391 Reviewed By: arbabu123 Differential Revision: D31352971 Pulled By: alexeib fbshipit-source-id: c045bedecb03339c8eb46e7e8c9804a53b35615b --- examples/MMPT/mmpt/tasks/fairseqmmtask.py | 5 +++- examples/laser/laser_src/laser_task.py | 2 ++ .../tasks/speech_text_joint.py | 3 +++ fairseq/data/iterators.py | 24 ++++++++++++++++--- fairseq/dataclass/configs.py | 18 ++++++++++++++ fairseq/options.py | 7 ++++++ fairseq/tasks/fairseq_task.py | 15 ++++++++++-- .../tasks/translation_multi_simple_epoch.py | 9 +++++++ fairseq/trainer.py | 6 ++++- 9 files changed, 82 insertions(+), 7 deletions(-) diff --git a/examples/MMPT/mmpt/tasks/fairseqmmtask.py b/examples/MMPT/mmpt/tasks/fairseqmmtask.py index fa7dae7a6c..78ef7ba17c 100644 --- a/examples/MMPT/mmpt/tasks/fairseqmmtask.py +++ b/examples/MMPT/mmpt/tasks/fairseqmmtask.py @@ -68,6 +68,8 @@ def get_batch_iterator( epoch=1, data_buffer_size=0, disable_iterator_cache=False, + grouped_shuffling=False, + update_epoch_batch_itr=False, ): random.seed(epoch) if dataset.mmdataset.split == "train" \ @@ -81,7 +83,8 @@ def get_batch_iterator( dataset, max_tokens, max_sentences, max_positions, ignore_invalid_inputs, required_batch_size_multiple, seed, num_shards, shard_id, num_workers, epoch, - data_buffer_size, disable_iterator_cache) + data_buffer_size, disable_iterator_cache, + grouped_shuffling, update_epoch_batch_itr) @property def source_dictionary(self): diff --git a/examples/laser/laser_src/laser_task.py b/examples/laser/laser_src/laser_task.py index e4152fde68..43416e0a0d 100644 --- a/examples/laser/laser_src/laser_task.py +++ b/examples/laser/laser_src/laser_task.py @@ -282,6 +282,8 @@ def get_batch_iterator( epoch=1, data_buffer_size=0, disable_iterator_cache=False, + grouped_shuffling=False, + update_epoch_batch_itr=False, ): assert isinstance(dataset, OrderedDict) diff --git a/examples/speech_text_joint_to_text/tasks/speech_text_joint.py b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py index f2b3966d2d..800ccd782a 100644 --- a/examples/speech_text_joint_to_text/tasks/speech_text_joint.py +++ b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py @@ -326,6 +326,8 @@ def get_batch_iterator( epoch=0, data_buffer_size=0, disable_iterator_cache=False, + grouped_shuffling=False, + update_epoch_batch_itr=False, ): if not isinstance(dataset, MultiModalityDataset): @@ -343,6 +345,7 @@ def get_batch_iterator( epoch, data_buffer_size, disable_iterator_cache, + update_epoch_batch_itr=update_epoch_batch_itr, ) mult_ratio = [self.args.speech_sample_ratio, self.args.text_sample_ratio] diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 1ce26e57e5..14b4f83330 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -55,8 +55,10 @@ def __next__(self): try: x = next(self._itr) except StopIteration: - raise IndexError(f"Iterator expected to have length {self.total}, " - "but exhausted at position {self.n}.") + raise IndexError( + f"Iterator expected to have length {self.total}, " + "but exhausted at position {self.n}." + ) self.n += 1 return x @@ -263,6 +265,9 @@ class EpochBatchIterator(EpochBatchIterating): from workers. Should always be non-negative (default: ``0``). disable_shuffling (bool, optional): force disable shuffling (default: ``False``). + grouped_shuffling (bool, optional): enable shuffling batches in groups + of num_shards. Ensures that each GPU receives similar length sequences when + batches are sorted by length. """ def __init__( @@ -278,6 +283,7 @@ def __init__( buffer_size=0, timeout=0, disable_shuffling=False, + grouped_shuffling=False, ): assert isinstance(dataset, torch.utils.data.Dataset) self.dataset = dataset @@ -295,6 +301,7 @@ def __init__( self.buffer_size = min(buffer_size, 20) self.timeout = timeout self.disable_shuffling = disable_shuffling + self.grouped_shuffling = grouped_shuffling self.epoch = max(epoch, 1) # we use 1-based indexing for epochs self.shuffle = not disable_shuffling @@ -433,7 +440,17 @@ def _get_iterator_for_epoch( ): def shuffle_batches(batches, seed): with data_utils.numpy_seed(seed): - np.random.shuffle(batches) + + if self.grouped_shuffling: + grouped_batches = [ + batches[(i * self.num_shards) : ((i + 1) * self.num_shards)] + for i in range((len(batches) // self.num_shards)) + ] + np.random.shuffle(grouped_batches) + batches = list(itertools.chain(*grouped_batches)) + else: + np.random.shuffle(batches) + return batches if self._supports_prefetch: @@ -639,6 +656,7 @@ def __next__(self): raise StopIteration() return item + class GroupedEpochBatchIterator(EpochBatchIterator): """Grouped version of EpochBatchIterator It takes several samplers from different datasets. diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 289bb8896b..fcf2678244 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -540,6 +540,24 @@ class DatasetConfig(FairseqDataclass): shard_id: int = field( default=0, metadata={"help": "id of the shard to generate (id < num_shards)"} ) + grouped_shuffling: bool = field( + default=False, + metadata={ + "help": "shuffle batches in groups of num_shards to enable similar sequence lengths on each GPU worker when batches are sorted by length", + }, + ) + update_epoch_batch_itr: bool = field( + default=II("dataset.grouped_shuffling"), + metadata={ + "help": "if true then prevents the reuse the epoch batch iterator by setting can_reuse_epoch_itr to false, defaults to --grouped-shuffling )", + }, + ) + update_ordered_indices_seed: bool = field( + default=False, + metadata={ + "help": "if true then increment seed with epoch for getting batch iterators, defautls to False.", + } + ) @dataclass diff --git a/fairseq/options.py b/fairseq/options.py index b4d350f902..920591635a 100644 --- a/fairseq/options.py +++ b/fairseq/options.py @@ -208,6 +208,13 @@ def parse_args_and_arch( else: args.no_seed_provided = False + if getattr(args, "update_epoch_batch_itr", None) is None: + if hasattr(args, "grouped_shuffling"): + args.update_epoch_batch_itr = args.grouped_shuffling + else: + args.grouped_shuffling = False + args.update_epoch_batch_itr = False + # Apply architecture configuration. if hasattr(args, "arch") and args.arch in ARCH_CONFIG_REGISTRY: ARCH_CONFIG_REGISTRY[args.arch](args) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 8148c77fe1..ec62464f03 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -220,6 +220,8 @@ def get_batch_iterator( epoch=1, data_buffer_size=0, disable_iterator_cache=False, + grouped_shuffling=False, + update_epoch_batch_itr=False, ): """ Get an iterator that yields batches of data from the given dataset. @@ -252,12 +254,20 @@ def get_batch_iterator( disable_iterator_cache (bool, optional): don't cache the EpochBatchIterator (ignores `FairseqTask::can_reuse_epoch_itr`) (default: False). + grouped_shuffling (bool, optional): group batches with each groups + containing num_shards batches and shuffle groups. Reduces difference + between sequence lengths among workers for batches sorted by length. + update_epoch_batch_itr (bool optional): if true then donot use the cached + batch iterator for the epoch + Returns: ~fairseq.iterators.EpochBatchIterator: a batched iterator over the given dataset split """ - can_reuse_epoch_itr = not disable_iterator_cache and self.can_reuse_epoch_itr( - dataset + can_reuse_epoch_itr = ( + not disable_iterator_cache + and not update_epoch_batch_itr + and self.can_reuse_epoch_itr(dataset) ) if can_reuse_epoch_itr and dataset in self.dataset_to_epoch_iter: logger.debug("reusing EpochBatchIterator for epoch {}".format(epoch)) @@ -297,6 +307,7 @@ def get_batch_iterator( num_workers=num_workers, epoch=epoch, buffer_size=data_buffer_size, + grouped_shuffling=grouped_shuffling, ) if can_reuse_epoch_itr: diff --git a/fairseq/tasks/translation_multi_simple_epoch.py b/fairseq/tasks/translation_multi_simple_epoch.py index 6f36e5b93e..f4797f5676 100644 --- a/fairseq/tasks/translation_multi_simple_epoch.py +++ b/fairseq/tasks/translation_multi_simple_epoch.py @@ -349,6 +349,8 @@ def get_batch_iterator( epoch=1, data_buffer_size=0, disable_iterator_cache=False, + grouped_shuffling=False, + update_epoch_batch_itr=False, ): """ Get an iterator that yields batches of data from the given dataset. @@ -381,6 +383,12 @@ def get_batch_iterator( disable_iterator_cache (bool, optional): don't cache the EpochBatchIterator (ignores `FairseqTask::can_reuse_epoch_itr`) (default: False). + grouped_shuffling (bool, optional): group batches with each groups + containing num_shards batches and shuffle groups. Reduces difference + between sequence lengths among workers for batches sorted by length. + update_epoch_batch_itr (bool optional): if true then donot use the cached + batch iterator for the epoch + Returns: ~fairseq.iterators.EpochBatchIterator: a batched iterator over the given dataset split @@ -404,6 +412,7 @@ def get_batch_iterator( epoch=epoch, data_buffer_size=data_buffer_size, disable_iterator_cache=disable_iterator_cache, + update_epoch_batch_itr=update_epoch_batch_itr, ) self.dataset_to_epoch_iter[dataset] = batch_iter return batch_iter diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 94130c8c3a..6413411604 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -639,13 +639,17 @@ def get_train_iterator( ), ignore_invalid_inputs=True, required_batch_size_multiple=self.cfg.dataset.required_batch_size_multiple, - seed=self.cfg.common.seed, + seed=(self.cfg.common.seed + epoch) + if self.cfg.dataset.update_ordered_indices_seed + else self.cfg.common.seed, num_shards=self.data_parallel_world_size if shard_batch_itr else 1, shard_id=self.data_parallel_rank if shard_batch_itr else 0, num_workers=self.cfg.dataset.num_workers, epoch=epoch, data_buffer_size=self.cfg.dataset.data_buffer_size, disable_iterator_cache=disable_iterator_cache, + grouped_shuffling=self.cfg.dataset.grouped_shuffling, + update_epoch_batch_itr=self.cfg.dataset.update_epoch_batch_itr, ) self.reset_dummy_batch(batch_iterator.first_batch) return batch_iterator From 7fd643552041f9aa81dd3085068176a97ef62e84 Mon Sep 17 00:00:00 2001 From: arbabu123 <toarunbabu@gmail.com> Date: Tue, 16 Nov 2021 16:27:54 -0800 Subject: [PATCH 499/774] Add activation checkpoint for wav2vec (#2545) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2545 Reviewed By: alexeib Differential Revision: D32150553 Pulled By: arbabu123 fbshipit-source-id: 1acff92dd69db128bc97ee36ca55b44dd59e08f5 --- fairseq/dataclass/configs.py | 4 ++- .../fully_sharded_data_parallel.py | 2 +- fairseq/models/wav2vec/wav2vec2.py | 21 +++++++---- fairseq/models/wav2vec/wav2vec2_asr.py | 36 +++++++++++++++++-- 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index fcf2678244..452deb1a19 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -436,7 +436,9 @@ class DistributedTrainingConfig(FairseqDataclass): use_sharded_state: bool = field( default=False, metadata={"help": "use sharded checkpoint files"}, ) - + not_fsdp_flatten_parameters: bool = field( + default=False, metadata={"help": "not flatten parameter param for fsdp"}, + ) @dataclass class DatasetConfig(FairseqDataclass): diff --git a/fairseq/distributed/fully_sharded_data_parallel.py b/fairseq/distributed/fully_sharded_data_parallel.py index 8a96bfc765..88dc698b4d 100644 --- a/fairseq/distributed/fully_sharded_data_parallel.py +++ b/fairseq/distributed/fully_sharded_data_parallel.py @@ -97,7 +97,7 @@ def fsdp_enable_wrap(cfg: DistributedTrainingConfig): "reshard_after_forward": not cfg.no_reshard_after_forward, "mixed_precision": cfg.fp16 and not cfg.memory_efficient_fp16, "fp32_reduce_scatter": cfg.fp32_reduce_scatter, - "flatten_parameters": True, + "flatten_parameters": not cfg.not_fsdp_flatten_parameters, "cpu_offload": cfg.cpu_offload, "compute_dtype": torch.float16 if cfg.fp16 else torch.float32, "bucket_cap_mb": cfg.bucket_cap_mb, diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 714fd3ab50..af722a5318 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -25,8 +25,10 @@ SamePad, TransposeLast, ) +from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.transformer_sentence_encoder import init_bert_params from fairseq.utils import buffered_arange, index_put, is_xla_tensor +from fairseq.distributed import fsdp_wrap EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) @@ -229,6 +231,9 @@ class Wav2Vec2Config(FairseqDataclass): }, ) + checkpoint_activations: bool = field( + default=False, metadata={"help": "recompute activations and save memory for extra compute"} + ) @register_model("wav2vec2", dataclass=Wav2Vec2Config) class Wav2Vec2Model(BaseFairseqModel): @@ -836,9 +841,9 @@ def __init__(self, args): self.pos_conv = nn.utils.weight_norm(self.pos_conv, name="weight", dim=2) self.pos_conv = nn.Sequential(self.pos_conv, SamePad(args.conv_pos), nn.GELU()) - self.layers = nn.ModuleList( - [ - TransformerSentenceEncoderLayer( + layers = [] + for _ in range(args.encoder_layers): + layer = TransformerSentenceEncoderLayer( embedding_dim=self.embedding_dim, ffn_embedding_dim=args.encoder_ffn_embed_dim, num_attention_heads=args.encoder_attention_heads, @@ -847,10 +852,12 @@ def __init__(self, args): activation_dropout=args.activation_dropout, activation_fn=args.activation_fn, layer_norm_first=args.layer_norm_first, - ) - for _ in range(args.encoder_layers) - ] - ) + ) + if args.checkpoint_activations: + layer = fsdp_wrap(layer) + layer = checkpoint_wrapper(layer) + layers.append(layer) + self.layers = nn.ModuleList(layers) self.layer_norm_first = args.layer_norm_first self.layer_norm = LayerNorm(self.embedding_dim) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 3ce05a30b8..612db5d95f 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -8,6 +8,7 @@ import copy import math import numpy as np +import re import torch import torch.nn as nn import torch.nn.functional as F @@ -150,6 +151,10 @@ class Wav2Vec2AsrConfig(FairseqDataclass): # this holds the loaded wav2vec args w2v_args: Any = None + checkpoint_activations: bool = field( + default=False, metadata={"help": "recompute activations and save memory for extra compute"} + ) + ddp_backend: str = II("distributed_training.ddp_backend") @dataclass class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): @@ -263,7 +268,6 @@ class Wav2Vec2Seq2SeqConfig(Wav2Vec2AsrConfig): ) autoregressive: bool = II("task.autoregressive") - @register_model("wav2vec_seq2seq", dataclass=Wav2Vec2Seq2SeqConfig) class Wav2Vec2Seq2SeqModel(FairseqEncoderDecoderModel): def __init__(self, encoder, decoder): @@ -353,12 +357,16 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): "Please check that --normalize is set or unset for both pre-training and here" ) + if hasattr(cfg, "checkpoint_activations") and cfg.checkpoint_activations: + with open_dict(w2v_args): + w2v_args.model.checkpoint_activations = cfg.checkpoint_activations + w2v_args.task.data = cfg.data task = tasks.setup_task(w2v_args.task) model = task.build_model(w2v_args.model) if state is not None and not cfg.no_pretrained_weights: - model.load_state_dict(state["model"], strict=True) + self.load_model_weights(state, model, cfg) model.remove_pretraining_modules() @@ -383,6 +391,30 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): if targ_d is not None: self.proj = Linear(d, targ_d) + def load_model_weights(self, state, model, cfg): + if cfg.ddp_backend == "fully_sharded": + from fairseq.distributed import FullyShardedDataParallel + for name, module in model.named_modules(): + if "encoder.layers" in name and len(name.split(".")) == 3: + # Only for layers, we do a special handling and load the weights one by one + # We dont load all weights together as that wont be memory efficient and may + # cause oom + new_dict = {k.replace(name+".", "") : v for (k, v) in state["model"].items() if name+"." in k} + assert isinstance(module, FullyShardedDataParallel) + with module.summon_full_params(): + module.load_state_dict(new_dict, strict=True) + module._reset_lazy_init() + + # Once layers are loaded, filter them out and load everything else. + r = re.compile("encoder.layers.\d.") + filtered_list = list(filter(r.match, state["model"].keys())) + + new_big_dict = {k: v for (k, v) in state["model"].items() if k not in filtered_list} + + model.load_state_dict(new_big_dict, strict=False) + else: + model.load_state_dict(state["model"], strict=True) + def set_num_updates(self, num_updates): """Set the number of parameters updates.""" super().set_num_updates(num_updates) From 30c912b73c0f88d41171879b2f03226a171004ef Mon Sep 17 00:00:00 2001 From: Arun Babu <arbabu@devfair0164.h2.fair> Date: Wed, 17 Nov 2021 11:36:17 -0800 Subject: [PATCH 500/774] Xlsr readme (#2652) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2652 Reviewed By: michaelauli Differential Revision: D32499609 Pulled By: arbabu123 fbshipit-source-id: 1d91f0c5dda8f4e0d0a8d3c8f4854188e91500c3 --- examples/wav2vec/xlsr/README.md | 68 ++++++++++++++++++++++ examples/wav2vec/xlsr/config/finetune.yaml | 66 +++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 examples/wav2vec/xlsr/README.md create mode 100644 examples/wav2vec/xlsr/config/finetune.yaml diff --git a/examples/wav2vec/xlsr/README.md b/examples/wav2vec/xlsr/README.md new file mode 100644 index 0000000000..6a1e68a359 --- /dev/null +++ b/examples/wav2vec/xlsr/README.md @@ -0,0 +1,68 @@ +# XLS-R + +XLS-R is a set of large-scale models for self-supervised cross-lingual speech representation learning based on wav2vec 2.0. It was pretrained on 128 languages and approximately 436K hours of unlabeled speech data. With finetuning, these models achieve state of the art performance in speech translation, speech recognition and language identification. We evaluate the model across multiple benchmarks such as CoVoST-2 for speech translation, BABEL / MLS / CommonVoice / VoxPopuli for automatic speech recognition, and VoxLingua107 for language identification as we llas VoxCeleb1 for speaker identification. More details about this work can be found in our [paper](https://link-to-xlsr-paper.com) + +Model | Link +|------|------ +XLS-R 300M | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_300m.pt) +XLS-R 1B | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_960m_1000k.pt) +XLS-R 2B | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_2B_1000k.pt) + +You can find these models [here](https://huggingface.co/models?other=xls_r) with Hugging Face. + +## Speech Translation Finetuned Models + +We multilingually finetune XLS-R models on [CoVoST 2](https://github.com/facebookresearch/covost), which has 21 +into-English and 15 out-of-English directions. + +Model | Directions | Link +|------|------|------ +XLS-R 300M | 21 langs → En | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_300m_21_en.pt) +XLS-R 300M | En → 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_300m_en_15.pt) +XLS-R 1B | 21 langs → En | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_1b_21_en.pt) +XLS-R 1B | En → 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_1b_en_15.pt) +XLS-R 2B | 21 langs → En | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_2b_21_en.pt) +XLS-R 2B | En → 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_2b_en_15.pt) +XLS-R 2B | 21 langs → En + En → 15 langs | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xls_r_2b_22_16.pt) + +## ASR Finetuning + +You can refer the original wav2vec documentation on detailed instructions about how to finetune a pretrained model with CTC [here](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). Below is an example command and you can find the values for different hyperparameters to reproduce the results in our paper. + +```shell script +$ fairseq-hydra-train \ + distributed_training.distributed_port=$PORT \ + task.data=/path/to/data \ + model.w2v_path=/path/to/model.pt \ + --config-dir /path/to/fairseq-py/examples/wav2vec/xlsr/config \ + --config-name finetune +``` + +For finetuning the 300M as well as 1B model, we use the same hyperparameter setting defined in `finetune.yaml`. We vary `optimization.max_update` as described in the below table and the `optimization.lr` is picked from the interval [2e-5, 3e-4] based on dev word error rate. + +Benchmark | Total Number of Updates +|------|------ +Babel | 26000 +Common Voice | 13000 +VoxPopuli | 50000 +MLS 10h | 20000 + +For finetuning the 2B model, we make some additional changes for `finetune.yaml` . We use the fully_sharded `distributed_training.ddp_backend` provided by the [fairscale](https://github.com/facebookresearch/fairscale) library and and set `model.activation_checkpoint` to true. We also increase `dataset.max_tokens` to 2560000 and use a total effective batch size of 2560000*24. We sweep for the best `optimization.lr` within the interval [3e−6,3e−5] using dev error rate. For common voice dataset, we pick the `model.mask_prob` for different languages among {0.30, 0.40} based on best dev error rate. + + + +## Citation + +Please cite as: + +``` bibtex +@inproceedings{xx, + title = {XLSR}, + author = {placeholder}, + booktitle = {placeholder}, + year = {2019}, +} +``` + + + diff --git a/examples/wav2vec/xlsr/config/finetune.yaml b/examples/wav2vec/xlsr/config/finetune.yaml new file mode 100644 index 0000000000..109a36511a --- /dev/null +++ b/examples/wav2vec/xlsr/config/finetune.yaml @@ -0,0 +1,66 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + +checkpoint: + save_interval: 1000 + save_interval_updates: 1000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: ??? + normalize: true + labels: ltr + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval_updates: 1000 + valid_subset: valid + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: ??? + lr: [0.0003] + sentence_avg: true + update_freq: [5] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.75 + mask_channel_prob: 0.25 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + + checkpoint_activation: false From 7105d7f4b14725ce5798d2cbaa59a649513205fb Mon Sep 17 00:00:00 2001 From: Arun Babu <arbabu@fb.com> Date: Wed, 17 Nov 2021 20:55:15 -0800 Subject: [PATCH 501/774] attempt5 (#2658) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2658 Reviewed By: ngoyal2707 Differential Revision: D32520446 Pulled By: arbabu123 fbshipit-source-id: a4cbc12624c9c8c1b5bc3d64eb47c2fdec01eb87 --- README.md | 1 + examples/wav2vec/xlsr/README.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4a3c6b29d6..8d60fbd8ea 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ as well as example training and evaluation commands. We also have more detailed READMEs to reproduce results from specific papers: +* [XLS-R: Self-supervised Cross-lingual Speech Representation Learning at Scale (Babu et al., 2021)](examples/wav2vec/xlsr/README.md) * [Cross-lingual Retrieval for Iterative Self-Supervised Training (Tran et al., 2020)](examples/criss/README.md) * [wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations (Baevski et al., 2020)](examples/wav2vec/README.md) * [Unsupervised Quality Estimation for Neural Machine Translation (Fomicheva et al., 2020)](examples/unsupervised_quality_estimation/README.md) diff --git a/examples/wav2vec/xlsr/README.md b/examples/wav2vec/xlsr/README.md index 6a1e68a359..84e9de36a6 100644 --- a/examples/wav2vec/xlsr/README.md +++ b/examples/wav2vec/xlsr/README.md @@ -1,6 +1,6 @@ # XLS-R -XLS-R is a set of large-scale models for self-supervised cross-lingual speech representation learning based on wav2vec 2.0. It was pretrained on 128 languages and approximately 436K hours of unlabeled speech data. With finetuning, these models achieve state of the art performance in speech translation, speech recognition and language identification. We evaluate the model across multiple benchmarks such as CoVoST-2 for speech translation, BABEL / MLS / CommonVoice / VoxPopuli for automatic speech recognition, and VoxLingua107 for language identification as we llas VoxCeleb1 for speaker identification. More details about this work can be found in our [paper](https://link-to-xlsr-paper.com) +XLS-R is a set of large-scale models for self-supervised cross-lingual speech representation learning based on wav2vec 2.0. It was pretrained on 128 languages and approximately 436K hours of unlabeled speech data. With finetuning, these models achieve state of the art performance in speech translation, speech recognition and language identification. We evaluate the model across multiple benchmarks such as CoVoST-2 for speech translation, BABEL / MLS / CommonVoice / VoxPopuli for automatic speech recognition, and VoxLingua107 for language identification as we llas VoxCeleb1 for speaker identification. More details about this work can be found in our [paper](https://arxiv.org/pdf/2111.09296.pdf) and download links can be found below. Model | Link |------|------ @@ -8,7 +8,7 @@ XLS-R 300M | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_300 XLS-R 1B | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_960m_1000k.pt) XLS-R 2B | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr2_2B_1000k.pt) -You can find these models [here](https://huggingface.co/models?other=xls_r) with Hugging Face. +You can also download these models [here](https://huggingface.co/models?other=xls_r) and read more about it in the [blogpost](https://huggingface.co/blog/fine-tune-xlsr-wav2vec2) from Hugging Face. ## Speech Translation Finetuned Models @@ -56,13 +56,13 @@ For finetuning the 2B model, we make some additional changes for `finetune.yaml` Please cite as: ``` bibtex -@inproceedings{xx, - title = {XLSR}, - author = {placeholder}, - booktitle = {placeholder}, - year = {2019}, +@article{babu2021xlsr, + title={XLS-R: Self-supervised Cross-lingual Speech Representation Learning at Scale}, + author={Arun Babu and Changhan Wang and Andros Tjandra and Kushal Lakhotia and Qiantong Xu and Naman Goyal and Kritika Singh and Patrick von Platen and Yatharth Saraf and Juan Pino and Alexei Baevski and Alexis Conneau and Michael Auli}, + year={2021}, + volume={abs/2111.09296}, + journal={arXiv}, } ``` - From bf61974ee879cb1a5b188440ddb06a2f43a8fef9 Mon Sep 17 00:00:00 2001 From: Yun Wang <yunwang@fb.com> Date: Thu, 18 Nov 2021 16:37:43 -0800 Subject: [PATCH 502/774] Merge --use-ontology-for-* into --use-ontology Summary: There are three options for the ontology: * `--use-ontology-for-training` * `--use-ontology-for-validation` * `--use-ontology-for-balancing` The first two must always be set together. In the past, I observed that it's best not to use ontology for data balancing even if we use ontology for training and validation. But now I no longer observe this. Therefore, I'm merging all these three options into one (`--use-ontology`). In addition, I'm also moving the logic of avoiding loading teacher models out of `checkpoint_utils.py`. If you want to load a student model without loading its teachers (e.g. for prediction only), specify `arg_overrides={"ignore_teachers": True}` when calling `load_model_ensemble`. Reviewed By: xiaoxiao26 Differential Revision: D32518830 fbshipit-source-id: 103c6458f7927ec5ca7470109c8f956c00f514a2 --- fairseq/checkpoint_utils.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index e9698b58c2..289053e53d 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -578,14 +578,6 @@ def _upgrade_state_dict(state): # keep track of number of updates if "num_updates" not in state["optimizer_history"][-1]: state["optimizer_history"][-1]["num_updates"] = 0 - # old model checkpoints may not have separate source/target positions - if ( - "args" in state - and hasattr(state["args"], "max_positions") - and not hasattr(state["args"], "max_source_positions") - ): - state["args"].max_source_positions = state["args"].max_positions - state["args"].max_target_positions = state["args"].max_positions # use stateful training data iterator if "train_iterator" not in state["extra_state"]: state["extra_state"]["train_iterator"] = { @@ -595,6 +587,13 @@ def _upgrade_state_dict(state): # backward compatibility, cfg updates if "args" in state and state["args"] is not None: + # old model checkpoints may not have separate source/target positions + if ( + hasattr(state["args"], "max_positions") + and not hasattr(state["args"], "max_source_positions") + ): + state["args"].max_source_positions = state["args"].max_positions + state["args"].max_target_positions = state["args"].max_positions # default to translation task if not hasattr(state["args"], "task"): state["args"].task = "translation" @@ -646,15 +645,6 @@ def _upgrade_state_dict(state): and len(state["args"].data) > 0 ): state["args"].data = state["args"].data[0] - # remove keys in state["args"] related to teacher-student learning - for key in [ - "static_teachers", - "static_teacher_weights", - "dynamic_teachers", - "dynamic_teacher_weights", - ]: - if key in state["args"]: - delattr(state["args"], key) state["cfg"] = convert_namespace_to_omegaconf(state["args"]) From 7f5ec30b25d906b564cc0ee0e50d1d9193940f58 Mon Sep 17 00:00:00 2001 From: Arun Babu <arbabu@fb.com> Date: Fri, 19 Nov 2021 19:48:50 -0800 Subject: [PATCH 503/774] Update finetune.yaml (#2664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Fix a typo # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2664 Reviewed By: alexeib Differential Revision: D32577174 Pulled By: arbabu123 fbshipit-source-id: 9b65619843fd9684be319024ccc9e6b0681db7de --- examples/wav2vec/xlsr/config/finetune.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/wav2vec/xlsr/config/finetune.yaml b/examples/wav2vec/xlsr/config/finetune.yaml index 109a36511a..8736e101c5 100644 --- a/examples/wav2vec/xlsr/config/finetune.yaml +++ b/examples/wav2vec/xlsr/config/finetune.yaml @@ -63,4 +63,4 @@ model: feature_grad_mult: 0.0 freeze_finetune_updates: 10000 - checkpoint_activation: false + checkpoint_activations: false From fb64e43c67b146cc9f28b35facd59a44c1e6031b Mon Sep 17 00:00:00 2001 From: Sam Shleifer <sshleifer@gmail.com> Date: Wed, 24 Nov 2021 07:49:55 -0800 Subject: [PATCH 504/774] skip remainder batch (#2464) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2464 Reviewed By: myleott Differential Revision: D31742871 Pulled By: sshleifer fbshipit-source-id: e5d29ca9d594abd92212eb24b60c991f2840a4e8 --- examples/MMPT/mmpt/tasks/fairseqmmtask.py | 29 +++-- examples/laser/laser_src/laser_task.py | 1 + .../tasks/speech_text_joint.py | 23 ++-- .../truncated_bptt/truncated_bptt_lm_task.py | 18 +-- fairseq/data/iterators.py | 62 +++++++--- fairseq/dataclass/configs.py | 54 +++++---- fairseq/tasks/fairseq_task.py | 15 ++- .../tasks/translation_multi_simple_epoch.py | 10 +- fairseq/trainer.py | 114 ++++++++---------- fairseq_cli/train.py | 60 ++++++--- tests/test_iterators.py | 59 ++++++++- 11 files changed, 285 insertions(+), 160 deletions(-) diff --git a/examples/MMPT/mmpt/tasks/fairseqmmtask.py b/examples/MMPT/mmpt/tasks/fairseqmmtask.py index 78ef7ba17c..f6b6115a39 100644 --- a/examples/MMPT/mmpt/tasks/fairseqmmtask.py +++ b/examples/MMPT/mmpt/tasks/fairseqmmtask.py @@ -25,9 +25,7 @@ def add_args(parser): parser.add_argument( "taskconfig", metavar="FILE", - help=( - "taskconfig to load all configurations" - "outside fairseq parser."), + help=("taskconfig to load all configurations" "outside fairseq parser."), ) @classmethod @@ -68,23 +66,34 @@ def get_batch_iterator( epoch=1, data_buffer_size=0, disable_iterator_cache=False, + skip_remainder_batch=False, grouped_shuffling=False, update_epoch_batch_itr=False, ): random.seed(epoch) - if dataset.mmdataset.split == "train" \ - and isinstance(self.mmtask, RetriTask): + if dataset.mmdataset.split == "train" and isinstance(self.mmtask, RetriTask): if epoch >= self.mmtask.config.retri_epoch: if not hasattr(self.mmtask, "retri_dataloader"): self.mmtask.build_dataloader() self.mmtask.retrive_candidates(epoch) return super().get_batch_iterator( - dataset, max_tokens, max_sentences, max_positions, - ignore_invalid_inputs, required_batch_size_multiple, - seed, num_shards, shard_id, num_workers, epoch, - data_buffer_size, disable_iterator_cache, - grouped_shuffling, update_epoch_batch_itr) + dataset, + max_tokens, + max_sentences, + max_positions, + ignore_invalid_inputs, + required_batch_size_multiple, + seed, + num_shards, + shard_id, + num_workers, + epoch, + data_buffer_size, + disable_iterator_cache, + grouped_shuffling, + update_epoch_batch_itr, + ) @property def source_dictionary(self): diff --git a/examples/laser/laser_src/laser_task.py b/examples/laser/laser_src/laser_task.py index 43416e0a0d..72d069fe8e 100644 --- a/examples/laser/laser_src/laser_task.py +++ b/examples/laser/laser_src/laser_task.py @@ -284,6 +284,7 @@ def get_batch_iterator( disable_iterator_cache=False, grouped_shuffling=False, update_epoch_batch_itr=False, + **kwargs, ): assert isinstance(dataset, OrderedDict) diff --git a/examples/speech_text_joint_to_text/tasks/speech_text_joint.py b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py index 800ccd782a..cd9aabd583 100644 --- a/examples/speech_text_joint_to_text/tasks/speech_text_joint.py +++ b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py @@ -21,7 +21,10 @@ LangPairMaskDataset, ModalityDatasetItem, ) -from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset, SpeechToTextDatasetCreator +from fairseq.data.audio.speech_to_text_dataset import ( + SpeechToTextDataset, + SpeechToTextDatasetCreator, +) from fairseq.data.audio.speech_to_text_joint_dataset import ( S2TJointDataConfig, SpeechToTextJointDatasetCreator, @@ -89,9 +92,7 @@ def add_args(cls, parser): help="use mixed data in one update when update-freq > 1", ) parser.add_argument( - "--load-speech-only", - action="store_true", - help="load speech data only", + "--load-speech-only", action="store_true", help="load speech data only", ) parser.add_argument( "--mask-text-ratio", @@ -160,7 +161,9 @@ def setup_task(cls, args, **kwargs): assert infer_tgt_lang_id != tgt_dict.unk() return cls(args, src_dict, tgt_dict, infer_tgt_lang_id=infer_tgt_lang_id) - def load_langpair_dataset(self, prepend_tgt_lang_tag=False, sampling_alpha=1.0, epoch=0): + def load_langpair_dataset( + self, prepend_tgt_lang_tag=False, sampling_alpha=1.0, epoch=0 + ): lang_pairs = [] text_dataset = None split = "train" @@ -200,9 +203,7 @@ def load_langpair_dataset(self, prepend_tgt_lang_tag=False, sampling_alpha=1.0, alpha=sampling_alpha, ) lang_pairs = [ - ResamplingDataset( - d, size_ratio=r, epoch=epoch, replace=(r >= 1.0) - ) + ResamplingDataset(d, size_ratio=r, epoch=epoch, replace=(r >= 1.0)) for d, r in zip(lang_pairs, size_ratios) ] return ConcatDataset(lang_pairs) @@ -257,9 +258,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): text_dataset = None if self.args.parallel_text_data != "" and is_train_split: text_dataset = self.load_langpair_dataset( - self.data_cfg.prepend_tgt_lang_tag_no_change, - 1.0, - epoch=epoch, + self.data_cfg.prepend_tgt_lang_tag_no_change, 1.0, epoch=epoch, ) if self.args.mask_text_ratio > 0: # add mask @@ -326,6 +325,7 @@ def get_batch_iterator( epoch=0, data_buffer_size=0, disable_iterator_cache=False, + skip_remainder_batch=False, grouped_shuffling=False, update_epoch_batch_itr=False, ): @@ -345,6 +345,7 @@ def get_batch_iterator( epoch, data_buffer_size, disable_iterator_cache, + skip_remainder_batch=skip_remainder_batch, update_epoch_batch_itr=update_epoch_batch_itr, ) diff --git a/examples/truncated_bptt/truncated_bptt_lm_task.py b/examples/truncated_bptt/truncated_bptt_lm_task.py index 02be0e7fb4..9978481b6d 100644 --- a/examples/truncated_bptt/truncated_bptt_lm_task.py +++ b/examples/truncated_bptt/truncated_bptt_lm_task.py @@ -29,8 +29,7 @@ class TruncatedBPTTLMConfig(FairseqDataclass): data: str = field(default="???", metadata={"help": "path to data directory"}) tokens_per_sample: int = field( - default=1024, - metadata={"help": "max number of tokens per sequence"}, + default=1024, metadata={"help": "max number of tokens per sequence"}, ) batch_size: int = II("dataset.batch_size") # Some models use *max_target_positions* to know how many positional @@ -103,7 +102,13 @@ def dataset(self, split): return self.datasets[split] def get_batch_iterator( - self, dataset, num_workers=0, epoch=1, data_buffer_size=0, **kwargs + self, + dataset, + num_workers=0, + epoch=1, + data_buffer_size=0, + skip_remainder_batch=False, + **kwargs ): return iterators.EpochBatchIterator( dataset=dataset, @@ -115,6 +120,7 @@ def get_batch_iterator( # instead every item in *dataset* is a whole batch batch_sampler=[[i] for i in range(len(dataset))], disable_shuffling=True, + skip_remainder_batch=skip_remainder_batch, ) def _collate_fn(self, items: List[List[torch.Tensor]]): @@ -134,10 +140,8 @@ def _collate_fn(self, items: List[List[torch.Tensor]]): # fairseq expects batches to have the following structure return { - "id": torch.tensor([id]*item.size(0)), - "net_input": { - "src_tokens": item, - }, + "id": torch.tensor([id] * item.size(0)), + "net_input": {"src_tokens": item,}, "target": target, "nsentences": item.size(0), "ntokens": item.numel(), diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 14b4f83330..81b5f56547 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -41,7 +41,7 @@ class CountingIterator(object): def __init__(self, iterable, start=None, total=None): self._itr = iter(iterable) self.n = start or getattr(iterable, "n", 0) - self.total = total or self.n + len(iterable) + self.total = total if total is not None else self.n + len(iterable) def __len__(self): return self.total @@ -265,6 +265,9 @@ class EpochBatchIterator(EpochBatchIterating): from workers. Should always be non-negative (default: ``0``). disable_shuffling (bool, optional): force disable shuffling (default: ``False``). + skip_remainder_batch (bool, optional): if set, discard the last batch in an epoch + for the sake of training stability, as the last batch is usually smaller than + local_batch_size * distributed_word_size (default: ``False``). grouped_shuffling (bool, optional): enable shuffling batches in groups of num_shards. Ensures that each GPU receives similar length sequences when batches are sorted by length. @@ -283,6 +286,7 @@ def __init__( buffer_size=0, timeout=0, disable_shuffling=False, + skip_remainder_batch=False, grouped_shuffling=False, ): assert isinstance(dataset, torch.utils.data.Dataset) @@ -301,6 +305,7 @@ def __init__( self.buffer_size = min(buffer_size, 20) self.timeout = timeout self.disable_shuffling = disable_shuffling + self.skip_remainder_batch = skip_remainder_batch self.grouped_shuffling = grouped_shuffling self.epoch = max(epoch, 1) # we use 1-based indexing for epochs @@ -375,9 +380,7 @@ def next_epoch_itr( # reset _frozen_batches to refresh the next epoch self._frozen_batches = None self._cur_epoch_itr = self._get_iterator_for_epoch( - self.epoch, - shuffle, - fix_batches_to_gpus=fix_batches_to_gpus, + self.epoch, shuffle, fix_batches_to_gpus=fix_batches_to_gpus, ) self.shuffle = shuffle return self._cur_epoch_itr @@ -418,9 +421,7 @@ def load_state_dict(self, state_dict): if itr_pos > 0: # fast-forward epoch iterator self._next_epoch_itr = self._get_iterator_for_epoch( - self.epoch, - shuffle=state_dict.get("shuffle", True), - offset=itr_pos, + self.epoch, shuffle=state_dict.get("shuffle", True), offset=itr_pos, ) if self._next_epoch_itr is None: if version == 1: @@ -497,6 +498,14 @@ def shuffle_batches(batches, seed): # Wrap with CountingIterator itr = CountingIterator(itr, start=offset) + + if self.skip_remainder_batch: + # TODO: Below is a lazy implementation which discard the final batch regardless + # of whether it is a full batch or not. + total_num_itrs = len(batches) - 1 + itr.take(total_num_itrs) + logger.info(f"skip final residual batch, total_num_itrs = {total_num_itrs}") + return itr @@ -506,29 +515,47 @@ class GroupedIterator(CountingIterator): Args: iterable (iterable): iterable to wrap chunk_size (int): size of each chunk - + skip_remainder_batch (bool, optional): if set, discard the last grouped batch in + each training epoch, as the last grouped batch is usually smaller than + local_batch_size * distributed_word_size * chunk_size (default: ``False``). Attributes: n (int): number of elements consumed from this iterator """ - def __init__(self, iterable, chunk_size): - itr = _chunk_iterator(iterable, chunk_size) + def __init__(self, iterable, chunk_size, skip_remainder_batch=False): + if skip_remainder_batch: + total_num_itrs = int(math.floor(len(iterable) / float(chunk_size))) + logger.info( + f"skip final residual batch, grouped total_num_itrs = {total_num_itrs}" + ) + else: + total_num_itrs = int(math.ceil(len(iterable) / float(chunk_size))) + logger.info(f"grouped total_num_itrs = {total_num_itrs}") + + itr = _chunk_iterator(iterable, chunk_size, skip_remainder_batch) super().__init__( itr, start=int(math.ceil(getattr(iterable, "n", 0) / float(chunk_size))), - total=int(math.ceil(len(iterable) / float(chunk_size))), + total=total_num_itrs, ) self.chunk_size = chunk_size + if skip_remainder_batch: + self.take(total_num_itrs) + # TODO: [Hack] Here the grouped iterator modifies the base iterator size so that + # training can move into the next epoch once the grouped iterator is exhausted. + # Double-check this implementation in case unexpected behavior occurs. + iterable.take(total_num_itrs * chunk_size) -def _chunk_iterator(itr, chunk_size): + +def _chunk_iterator(itr, chunk_size, skip_remainder_batch=False): chunk = [] for x in itr: chunk.append(x) if len(chunk) == chunk_size: yield chunk chunk = [] - if len(chunk) > 0: + if not skip_remainder_batch and len(chunk) > 0: yield chunk @@ -546,7 +573,12 @@ class ShardedIterator(CountingIterator): n (int): number of elements consumed from this iterator """ - def __init__(self, iterable, num_shards, shard_id, fill_value=None): + def __init__( + self, iterable, num_shards, shard_id, fill_value=None, skip_remainder_batch=None + ): + """ + Args: + skip_remainder_batch: ignored""" if shard_id < 0 or shard_id >= num_shards: raise ValueError("shard_id must be between 0 and num_shards") sharded_len = int(math.ceil(len(iterable) / float(num_shards))) @@ -611,7 +643,7 @@ def _create_consumer(self): self._queue, self._iterable, self.total, - torch.cuda.current_device() if torch.cuda.is_available() else None + torch.cuda.current_device() if torch.cuda.is_available() else None, ) self._consumer.daemon = True self._consumer.start() diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 452deb1a19..b081e6cabf 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -95,7 +95,6 @@ def from_namespace(cls, args): return config - @dataclass class CommonConfig(FairseqDataclass): # This is the core dataclass including common parameters shared by all different jobs. Please append your params to other dataclasses if they were @@ -169,11 +168,13 @@ class CommonConfig(FairseqDataclass): metadata={ "help": "if set, the floating point conversion to fp16/bf16 runs on CPU. " "This reduces bus transfer time and GPU memory usage." - } + }, ) min_loss_scale: float = field( default=1e-4, - metadata={"help": "minimum FP16/AMP loss scale, after which training is stopped"}, + metadata={ + "help": "minimum FP16/AMP loss scale, after which training is stopped" + }, ) threshold_loss_scale: Optional[float] = field( default=None, metadata={"help": "threshold FP16 loss scale from below"} @@ -181,7 +182,9 @@ class CommonConfig(FairseqDataclass): amp: bool = field(default=False, metadata={"help": "use automatic mixed precision"}) amp_batch_retries: int = field( default=2, - metadata={"help": "number of retries of same batch after reducing loss scale with AMP"}, + metadata={ + "help": "number of retries of same batch after reducing loss scale with AMP" + }, ) amp_init_scale: int = field( default=2 ** 7, metadata={"help": "default AMP loss scale"} @@ -223,7 +226,7 @@ class CommonConfig(FairseqDataclass): default=False, metadata={ "help": "suppress crashes when training with the hydra_train entry point so that the " - "main method can return a value (useful for sweeps)" + "main method can return a value (useful for sweeps)" }, ) use_plasma_view: bool = field( @@ -440,6 +443,7 @@ class DistributedTrainingConfig(FairseqDataclass): default=False, metadata={"help": "not flatten parameter param for fsdp"}, ) + @dataclass class DatasetConfig(FairseqDataclass): num_workers: int = field( @@ -489,7 +493,7 @@ class DatasetConfig(FairseqDataclass): default=None, metadata={ "help": "comma separated list of data subsets to use for validation" - " (e.g. train, valid, test)", + " (e.g. train, valid, test)", "argparse_alias": "--combine-val", }, ) @@ -527,8 +531,10 @@ class DatasetConfig(FairseqDataclass): "argparse_alias": "--max-sentences-valid", }, ) - max_valid_steps: Optional[int] = field(default=None, metadata={'help': 'How many batches to evaluate', - "argparse_alias": "--nval"}) + max_valid_steps: Optional[int] = field( + default=None, + metadata={"help": "How many batches to evaluate", "argparse_alias": "--nval"}, + ) curriculum: int = field( default=0, metadata={"help": "don't shuffle batches for first N epochs"} ) @@ -558,7 +564,7 @@ class DatasetConfig(FairseqDataclass): default=False, metadata={ "help": "if true then increment seed with epoch for getting batch iterators, defautls to False.", - } + }, ) @@ -607,6 +613,13 @@ class OptimizationConfig(FairseqDataclass): "help": "specify global optimizer for syncing models on different GPUs/shards" }, ) + skip_remainder_batch: Optional[bool] = field( + default=False, + metadata={ + "help": "if set, include the last (partial) batch of each epoch in training" + " (default is to skip it)." + }, + ) @dataclass @@ -669,8 +682,8 @@ class CheckpointConfig(FairseqDataclass): default=-1, metadata={ "help": "when used with --keep-interval-updates, skips deleting " - "any checkpoints with update X where " - "X %% keep_interval_updates_pattern == 0" + "any checkpoints with update X where " + "X %% keep_interval_updates_pattern == 0" }, ) keep_last_epochs: int = field( @@ -1020,25 +1033,22 @@ class InteractiveConfig(FairseqDataclass): @dataclass class EMAConfig(FairseqDataclass): store_ema: bool = field( - default=False, metadata={ - help: "store exponential moving average shadow model" - } + default=False, metadata={help: "store exponential moving average shadow model"} ) ema_decay: float = field( - default=0.9999, metadata={ - "help": 'decay for exponential moving average model' - } + default=0.9999, metadata={"help": "decay for exponential moving average model"} ) - ema_start_update : int = field( + ema_start_update: int = field( default=0, metadata={"help": "start EMA update after this many model updates"} ) - ema_seed_model : Optional[str] = field( - default=None, metadata={ + ema_seed_model: Optional[str] = field( + default=None, + metadata={ "help": "Seed to load EMA model from. " "Used to load EMA model separately from the actual model." - } + }, ) - ema_update_freq : int = field( + ema_update_freq: int = field( default=1, metadata={"help": "Do EMA update every this many model updates"} ) ema_fp32: bool = field( diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index ec62464f03..9cbdf89e6f 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -22,7 +22,6 @@ class StatefulContainer(object): - def __init__(self): self._state = dict() self._factories = dict() @@ -135,7 +134,7 @@ def load_dataset( split: str, combine: bool = False, task_cfg: FairseqDataclass = None, - **kwargs + **kwargs, ): """Load a given dataset split. @@ -220,6 +219,7 @@ def get_batch_iterator( epoch=1, data_buffer_size=0, disable_iterator_cache=False, + skip_remainder_batch=False, grouped_shuffling=False, update_epoch_batch_itr=False, ): @@ -254,6 +254,9 @@ def get_batch_iterator( disable_iterator_cache (bool, optional): don't cache the EpochBatchIterator (ignores `FairseqTask::can_reuse_epoch_itr`) (default: False). + skip_remainder_batch (bool, optional): if set, discard the last + batch in each training epoch, as the last batch is often smaller than + local_batch_size * distributed_word_size (default: ``True``). grouped_shuffling (bool, optional): group batches with each groups containing num_shards batches and shuffle groups. Reduces difference between sequence lengths among workers for batches sorted by length. @@ -307,6 +310,7 @@ def get_batch_iterator( num_workers=num_workers, epoch=epoch, buffer_size=data_buffer_size, + skip_remainder_batch=skip_remainder_batch, grouped_shuffling=grouped_shuffling, ) @@ -348,7 +352,12 @@ def build_criterion(self, cfg: DictConfig): return criterions.build_criterion(cfg, self) def build_generator( - self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None, prefix_allowed_tokens_fn=None, + self, + models, + args, + seq_gen_cls=None, + extra_gen_cls_kwargs=None, + prefix_allowed_tokens_fn=None, ): """ Build a :class:`~fairseq.SequenceGenerator` instance for this diff --git a/fairseq/tasks/translation_multi_simple_epoch.py b/fairseq/tasks/translation_multi_simple_epoch.py index f4797f5676..e64ab9a687 100644 --- a/fairseq/tasks/translation_multi_simple_epoch.py +++ b/fairseq/tasks/translation_multi_simple_epoch.py @@ -125,7 +125,7 @@ def check_dicts(self, dicts, source_langs, target_langs): @classmethod def setup_task(cls, args, **kwargs): langs, dicts, training = MultilingualDatasetManager.prepare( - cls.load_dictionary, args, **kwargs + cls.load_dictionary, args, **kwargs ) return cls(args, langs, dicts, training) @@ -197,11 +197,7 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None) return dataset def build_generator( - self, - models, - args, - seq_gen_cls=None, - extra_gen_cls_kwargs=None, + self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None, ): if not getattr(args, "keep_inference_langtok", False): _, tgt_langtok_spec = self.args.langtoks["main"] @@ -349,6 +345,7 @@ def get_batch_iterator( epoch=1, data_buffer_size=0, disable_iterator_cache=False, + skip_remainder_batch=False, grouped_shuffling=False, update_epoch_batch_itr=False, ): @@ -412,6 +409,7 @@ def get_batch_iterator( epoch=epoch, data_buffer_size=data_buffer_size, disable_iterator_cache=disable_iterator_cache, + skip_remainder_batch=skip_remainder_batch, update_epoch_batch_itr=update_epoch_batch_itr, ) self.dataset_to_epoch_iter[dataset] = batch_iter diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 6413411604..30e12dcc98 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -64,6 +64,7 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): if self.is_fsdp: import fairscale + if self.cfg.common.bf16: raise ValueError( "FullyShardedDataParallel is not compatible with --bf16 or " @@ -74,7 +75,10 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, quantizer=None): "FullyShardedDataParallel is not compatible with --zero-sharding " "option (it's already built in)" ) - if max(self.cfg.optimization.update_freq) > 1 and fairscale.__version__ < "0.4.0": + if ( + max(self.cfg.optimization.update_freq) > 1 + and fairscale.__version__ < "0.4.0" + ): raise RuntimeError( "Please update to fairscale 0.4.0 or newer when combining " "--update-freq with FullyShardedDataParallel" @@ -198,9 +202,7 @@ def is_data_parallel_master(self): def use_distributed_wrapper(self) -> bool: return ( self.data_parallel_world_size > 1 and not self.cfg.optimization.use_bmuf - ) or ( - self.is_fsdp and self.cfg.distributed_training.cpu_offload - ) + ) or (self.is_fsdp and self.cfg.distributed_training.cpu_offload) @property def should_save_checkpoint_on_current_rank(self) -> bool: @@ -267,9 +269,7 @@ def ema(self): def _build_ema(self): if self.cfg.ema.store_ema: self._ema = build_ema(self._model, self.cfg.ema, self.device) - logger.info( - "Exponential Moving Average Shadow Model is initialized." - ) + logger.info("Exponential Moving Average Shadow Model is initialized.") @property def optimizer(self): @@ -320,7 +320,9 @@ def _build_optimizer(self): self._optimizer = optim.FP16Optimizer.build_optimizer(self.cfg, params) else: if self.cuda and torch.cuda.get_device_capability(0)[0] >= 7: - logger.info("NOTE: your device may support faster training with --fp16 or --amp") + logger.info( + "NOTE: your device may support faster training with --fp16 or --amp" + ) self._optimizer = optim.build_optimizer(self.cfg.optimizer, params) if self.is_fsdp: @@ -335,10 +337,7 @@ def _build_optimizer(self): ) if self.cfg.optimization.use_bmuf: - self._optimizer = optim.FairseqBMUF( - self.cfg.bmuf, - self._optimizer, - ) + self._optimizer = optim.FairseqBMUF(self.cfg.bmuf, self._optimizer,) if self.cfg.distributed_training.zero_sharding == "os": if ( @@ -356,8 +355,7 @@ def _build_optimizer(self): # We should initialize the learning rate scheduler immediately after # building the optimizer, so that the initial learning rate is set. self._lr_scheduler = lr_scheduler.build_lr_scheduler( - self.cfg.lr_scheduler, - self.optimizer, + self.cfg.lr_scheduler, self.optimizer, ) self._lr_scheduler.step_update(0) @@ -579,18 +577,16 @@ def load_checkpoint( "EMA not found in checkpoint. But store_ema is True. " "EMA is re-initialized from checkpoint." ) - self.ema.restore(state["model"], build_fp32_params=self.cfg.ema.ema_fp32) - else: - logger.info( - "Loading EMA from checkpoint" + self.ema.restore( + state["model"], build_fp32_params=self.cfg.ema.ema_fp32 ) + else: + logger.info("Loading EMA from checkpoint") self.ema.restore(extra_state["ema"], build_fp32_params=False) if self.cfg.ema.ema_fp32: if "ema_fp32_params" in extra_state: - logger.info( - "Loading EMA fp32 params from checkpoint" - ) + logger.info("Loading EMA fp32 params from checkpoint") self.ema.build_fp32_params(extra_state["ema_fp32_params"]) else: logger.info( @@ -648,6 +644,7 @@ def get_train_iterator( epoch=epoch, data_buffer_size=self.cfg.dataset.data_buffer_size, disable_iterator_cache=disable_iterator_cache, + skip_remainder_batch=self.cfg.optimization.skip_remainder_batch, grouped_shuffling=self.cfg.dataset.grouped_shuffling, update_epoch_batch_itr=self.cfg.dataset.update_epoch_batch_itr, ) @@ -655,9 +652,7 @@ def get_train_iterator( return batch_iterator def get_valid_iterator( - self, - subset, - disable_iterator_cache=False, + self, subset, disable_iterator_cache=False, ): """Return an EpochBatchIterator over given validation subset for a given epoch.""" batch_iterator = self.task.get_batch_iterator( @@ -665,8 +660,7 @@ def get_valid_iterator( max_tokens=self.cfg.dataset.max_tokens_valid, max_sentences=self.cfg.dataset.batch_size_valid, max_positions=utils.resolve_max_positions( - self.task.max_positions(), - self.model.max_positions(), + self.task.max_positions(), self.model.max_positions(), ), ignore_invalid_inputs=self.cfg.dataset.skip_invalid_size_inputs_valid_test, required_batch_size_multiple=self.cfg.dataset.required_batch_size_multiple, @@ -679,6 +673,7 @@ def get_valid_iterator( epoch=1, data_buffer_size=self.cfg.dataset.data_buffer_size, disable_iterator_cache=disable_iterator_cache, + skip_remainder_batch=False, ) self.reset_dummy_batch(batch_iterator.first_batch) return batch_iterator @@ -812,10 +807,9 @@ def maybe_no_sync(): # gather logging outputs from all replicas if self._sync_stats(): train_time = self._local_cumulative_training_time() - logging_outputs, ( - sample_size, - ooms, - total_train_time, + ( + logging_outputs, + (sample_size, ooms, total_train_time,), ) = self._aggregate_logging_outputs( logging_outputs, sample_size, ooms, train_time, ignore=is_dummy_batch ) @@ -882,7 +876,9 @@ def maybe_no_sync(): self._amp_retries = 0 else: self._amp_retries += 1 - return self.train_step(samples, raise_oom) # recursion to feed in same batch + return self.train_step( + samples, raise_oom + ) # recursion to feed in same batch except FloatingPointError: # re-run the forward and backward pass with hooks attached to print @@ -918,8 +914,7 @@ def maybe_no_sync(): # after the step if hasattr(self.model, "perform_slowmo"): self.model.perform_slowmo( - self.optimizer.optimizer, - getattr(self.optimizer, "fp32_params", None) + self.optimizer.optimizer, getattr(self.optimizer, "fp32_params", None) ) logging_output = None @@ -929,8 +924,7 @@ def maybe_no_sync(): if self.cfg.ema.store_ema: # Step EMA forward with new model. self.ema.step( - self.get_model(), - self.get_num_updates(), + self.get_model(), self.get_num_updates(), ) metrics.log_scalar( "ema_decay", @@ -1064,9 +1058,7 @@ def valid_step(self, sample, raise_oom=False): # gather logging outputs from all replicas if self.data_parallel_world_size > 1: logging_outputs, (sample_size,) = self._aggregate_logging_outputs( - logging_outputs, - sample_size, - ignore=is_dummy_batch, + logging_outputs, sample_size, ignore=is_dummy_batch, ) # log validation stats @@ -1175,12 +1167,9 @@ def agg_norm_fn(total_norm): ) return total_norm ** 0.5 - should_agg_norm = ( - self.is_fsdp - and ( - self.data_parallel_process_group is not None - or torch.distributed.is_initialized() - ) + should_agg_norm = self.is_fsdp and ( + self.data_parallel_process_group is not None + or torch.distributed.is_initialized() ) return self.optimizer.clip_grad_norm( clip_norm, aggregate_norm_fn=agg_norm_fn if should_agg_norm else None @@ -1240,8 +1229,10 @@ def _prepare_sample(self, sample, is_dummy=False): if self.cuda: if self.pipeline_model_parallel: - if 'target' in sample: - sample['target'] = utils.move_to_cuda(sample['target'], device=self.last_device) + if "target" in sample: + sample["target"] = utils.move_to_cuda( + sample["target"], device=self.last_device + ) else: sample = utils.move_to_cuda(sample) elif self.tpu and is_dummy: @@ -1269,10 +1260,9 @@ def _sync_stats(self): return False elif self.cfg.optimization.use_bmuf: return ( - self.get_num_updates() + 1 - ) % self.cfg.bmuf.global_sync_iter == 0 and ( - self.get_num_updates() + 1 - ) > self.cfg.bmuf.warmup_iterations + (self.get_num_updates() + 1) % self.cfg.bmuf.global_sync_iter == 0 + and (self.get_num_updates() + 1) > self.cfg.bmuf.warmup_iterations + ) else: return True @@ -1285,10 +1275,7 @@ def _log_oom(self, exc): sys.stderr.flush() def _aggregate_logging_outputs( - self, - logging_outputs: List[Dict[str, Any]], - *extra_stats_to_sum, - ignore=False, + self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, ): if self.task.__class__.logging_outputs_can_be_summed(self.get_criterion()): return self._fast_stat_sync_sum( @@ -1300,10 +1287,7 @@ def _aggregate_logging_outputs( ) def _all_gather_list_sync( - self, - logging_outputs: List[Dict[str, Any]], - *extra_stats_to_sum, - ignore=False, + self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, ): """ Sync logging outputs across workers. all_gather_list_sync is @@ -1328,10 +1312,7 @@ def _all_gather_list_sync( return logging_outputs, extra_stats_to_sum def _fast_stat_sync_sum( - self, - logging_outputs: List[Dict[str, Any]], - *extra_stats_to_sum, - ignore=False, + self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, ): """ Sync logging outputs across workers. fast_stat_sync_sum is @@ -1379,10 +1360,11 @@ def _check_grad_norms(self, grad_norm): def is_consistent(tensor): max_abs_diff = torch.max(torch.abs(tensor - tensor[0])) return ( - (torch.isfinite(tensor).all() - and (max_abs_diff / (tensor[0] + 1e-6) < 1e-6).all()) - or - (self.cfg.common.amp and not torch.isfinite(tensor).all()) + ( + torch.isfinite(tensor).all() + and (max_abs_diff / (tensor[0] + 1e-6) < 1e-6).all() + ) + or (self.cfg.common.amp and not torch.isfinite(tensor).all()) # in case of amp non-finite grads are fine ) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 8347587313..369a8a82c5 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -44,15 +44,16 @@ from omegaconf import DictConfig, OmegaConf - - def main(cfg: FairseqConfig) -> None: if isinstance(cfg, argparse.Namespace): cfg = convert_namespace_to_omegaconf(cfg) utils.import_user_module(cfg.common) - if distributed_utils.is_master(cfg.distributed_training) and "job_logging_cfg" in cfg: + if ( + distributed_utils.is_master(cfg.distributed_training) + and "job_logging_cfg" in cfg + ): # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) logging.config.dictConfig(OmegaConf.to_container(cfg.job_logging_cfg)) @@ -102,15 +103,25 @@ def main(cfg: FairseqConfig) -> None: logger.info("criterion: {}".format(criterion.__class__.__name__)) logger.info( "num. shared model params: {:,} (num. trained: {:,})".format( - sum(p.numel() for p in model.parameters() if not getattr(p, "expert", False)), - sum(p.numel() for p in model.parameters() if not getattr(p, "expert", False) and p.requires_grad) + sum( + p.numel() for p in model.parameters() if not getattr(p, "expert", False) + ), + sum( + p.numel() + for p in model.parameters() + if not getattr(p, "expert", False) and p.requires_grad + ), ) ) logger.info( "num. expert model params: {} (num. trained: {})".format( sum(p.numel() for p in model.parameters() if getattr(p, "expert", False)), - sum(p.numel() for p in model.parameters() if getattr(p, "expert", False) and p.requires_grad), + sum( + p.numel() + for p in model.parameters() + if getattr(p, "expert", False) and p.requires_grad + ), ) ) @@ -145,8 +156,7 @@ def main(cfg: FairseqConfig) -> None: ) logger.info( "max tokens per device = {} and max sentences per device = {}".format( - cfg.dataset.max_tokens, - cfg.dataset.batch_size, + cfg.dataset.max_tokens, cfg.dataset.batch_size, ) ) @@ -160,6 +170,7 @@ def main(cfg: FairseqConfig) -> None: ) if cfg.common.tpu: import torch_xla.core.xla_model as xm + xm.rendezvous("load_checkpoint") # wait for all workers max_epoch = cfg.optimization.max_epoch or math.inf @@ -247,7 +258,9 @@ def train( if epoch_itr.epoch <= len(cfg.optimization.update_freq) else cfg.optimization.update_freq[-1] ) - itr = iterators.GroupedIterator(itr, update_freq) + itr = iterators.GroupedIterator( + itr, update_freq, skip_remainder_batch=cfg.optimization.skip_remainder_batch, + ) if cfg.common.tpu: itr = utils.tpu_data_loader(itr) progress = progress_bar.progress_bar( @@ -376,15 +389,19 @@ def validate_and_save( ) ) do_validate = ( - (not end_of_epoch and do_save) # validate during mid-epoch saves - or (end_of_epoch and epoch_itr.epoch % cfg.dataset.validate_interval == 0) - or should_stop - or ( - cfg.dataset.validate_interval_updates > 0 - and num_updates > 0 - and num_updates % cfg.dataset.validate_interval_updates == 0 + ( + (not end_of_epoch and do_save) # validate during mid-epoch saves + or (end_of_epoch and epoch_itr.epoch % cfg.dataset.validate_interval == 0) + or should_stop + or ( + cfg.dataset.validate_interval_updates > 0 + and num_updates > 0 + and num_updates % cfg.dataset.validate_interval_updates == 0 + ) ) - ) and not cfg.dataset.disable_validation and num_updates >= cfg.dataset.validate_after_updates + and not cfg.dataset.disable_validation + and num_updates >= cfg.dataset.validate_after_updates + ) # Validate valid_losses = [None] @@ -457,7 +474,10 @@ def validate( # don't pollute other aggregators (e.g., train meters) with metrics.aggregate(new_root=True) as agg: for i, sample in enumerate(progress): - if cfg.dataset.max_valid_steps is not None and i > cfg.dataset.max_valid_steps: + if ( + cfg.dataset.max_valid_steps is not None + and i > cfg.dataset.max_valid_steps + ): break trainer.valid_step(sample) @@ -497,7 +517,9 @@ def cli_main( if cfg.common.use_plasma_view: server = PlasmaStore(path=cfg.common.plasma_path) - logger.info(f"Started plasma server pid {server.server.pid} {cfg.common.plasma_path}") + logger.info( + f"Started plasma server pid {server.server.pid} {cfg.common.plasma_path}" + ) if args.profile: with torch.cuda.profiler.profile(): diff --git a/tests/test_iterators.py b/tests/test_iterators.py index 7b3dd48485..2e2eb2f0a8 100644 --- a/tests/test_iterators.py +++ b/tests/test_iterators.py @@ -5,7 +5,7 @@ import unittest -from fairseq.data import iterators +from fairseq.data import iterators, ListDataset class TestIterators(unittest.TestCase): @@ -132,6 +132,63 @@ def test_counting_iterator_buffered_iterator_take(self): self.assertFalse(itr.has_next()) self.assertRaises(StopIteration, next, buffered_itr) + def test_epoch_batch_iterator_skip_remainder_batch(self): + reference = [1, 2, 3] + itr1 = _get_epoch_batch_itr(reference, 2, True) + self.assertEqual(len(itr1), 1) + itr2 = _get_epoch_batch_itr(reference, 2, False) + self.assertEqual(len(itr2), 2) + itr3 = _get_epoch_batch_itr(reference, 1, True) + self.assertEqual(len(itr3), 2) + itr4 = _get_epoch_batch_itr(reference, 1, False) + self.assertEqual(len(itr4), 3) + itr5 = _get_epoch_batch_itr(reference, 4, True) + self.assertEqual(len(itr5), 0) + self.assertFalse(itr5.has_next()) + itr6 = _get_epoch_batch_itr(reference, 4, False) + self.assertEqual(len(itr6), 1) + + def test_grouped_iterator_skip_remainder_batch(self): + reference = [1, 2, 3, 4, 5, 6, 7, 8, 9] + itr1 = _get_epoch_batch_itr(reference, 3, False) + grouped_itr1 = iterators.GroupedIterator(itr1, 2, True) + self.assertEqual(len(grouped_itr1), 1) + + itr2 = _get_epoch_batch_itr(reference, 3, False) + grouped_itr2 = iterators.GroupedIterator(itr2, 2, False) + self.assertEqual(len(grouped_itr2), 2) + + itr3 = _get_epoch_batch_itr(reference, 3, True) + grouped_itr3 = iterators.GroupedIterator(itr3, 2, True) + self.assertEqual(len(grouped_itr3), 1) + + itr4 = _get_epoch_batch_itr(reference, 3, True) + grouped_itr4 = iterators.GroupedIterator(itr4, 2, False) + self.assertEqual(len(grouped_itr4), 1) + + itr5 = _get_epoch_batch_itr(reference, 5, True) + grouped_itr5 = iterators.GroupedIterator(itr5, 2, True) + self.assertEqual(len(grouped_itr5), 0) + + itr6 = _get_epoch_batch_itr(reference, 5, True) + grouped_itr6 = iterators.GroupedIterator(itr6, 2, False) + self.assertEqual(len(grouped_itr6), 1) + + +def _get_epoch_batch_itr(ref, bsz, skip_remainder_batch): + dsz = len(ref) + indices = range(dsz) + starts = indices[::bsz] + batch_sampler = [indices[s : s + bsz] for s in starts] + dataset = ListDataset(ref) + itr = iterators.EpochBatchIterator( + dataset=dataset, + collate_fn=dataset.collater, + batch_sampler=batch_sampler, + skip_remainder_batch=skip_remainder_batch, + ) + return itr.next_epoch_itr() + if __name__ == "__main__": unittest.main() From 91f029380bcedaed3b36c290ea98b5fbe66465fc Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Wed, 24 Nov 2021 13:17:54 -0800 Subject: [PATCH 505/774] Update python versions used for testing in main (#2679) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: New version of fairscale breaks with python3.6. Moving to higher versions of python. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2679 Reviewed By: alexeib Differential Revision: D32653241 Pulled By: dianaml0 fbshipit-source-id: bb81023b967f7d585fe9fb808f65cfd60cf51490 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 981b59416f..bd1d3b3c6d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: max-parallel: 4 matrix: platform: [ubuntu-latest, macos-latest] - python-version: [3.6, 3.7] + python-version: [3.8, 3.9] runs-on: ${{ matrix.platform }} From 2380a6e46675ca17bdf22be06bc7c6d138736e59 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Wed, 24 Nov 2021 18:02:34 -0800 Subject: [PATCH 506/774] Add pre commit config and flake8 config (#2676) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting Separating https://github.com/fairinternal/fairseq-py/issues/2212 into separate PR's to be cleaner. - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2676 Reviewed By: alexeib Differential Revision: D32653505 Pulled By: dianaml0 fbshipit-source-id: fd338289d23b340ef56b0188f9c73b37c367d6ca --- .isort.cfg | 2 ++ .pre-commit-config.yaml | 40 ++++++++++++++++++++++++++++++ CONTRIBUTING.md | 54 +++++++++++++++++++++++++++++++++++++++++ setup.cfg | 3 +++ 4 files changed, 99 insertions(+) create mode 100644 .isort.cfg create mode 100644 .pre-commit-config.yaml create mode 100644 setup.cfg diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000000..aed482f47e --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +known_third_party = _cffi_backend,agg_results,aml,bitarray,boto3,botocore,dump_hubert_feature,dynamicconv_cuda,editdistance,faiss,fasttext,feature_utils,ffmpeg,g2p_en,h5py,hydra,hypothesis,indicnlp,inflect,iopath,joblib,kaldi_io,kenlm,libfb,librosa,lightconv_cuda,matplotlib,misc,mmpt,mmpt_cli,model,nltk,npy_append_array,numpy,omegaconf,pandas,pathbuilder,preprocessing,progressbar,pythainlp,random_sequence_shuffler,regex,sacrebleu,sacremoses,scipy,sentencepiece,setuptools,six,sklearn,soundfile,sweep,sweep_wmt_en2de_transformer_big_common,tabulate,torch,torchaudio,tqdm,unidecode,utils,videoreader,wav2vec_cluster_faiss,wget,yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..f9efb2e96e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,40 @@ +exclude: 'build|stubs' + +default_language_version: + python: python3 + +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: trailing-whitespace + - id: check-ast + - id: check-merge-conflict + - id: no-commit-to-branch + args: ['--branch=master'] + - id: check-added-large-files + args: ['--maxkb=500'] + - id: end-of-file-fixer + +- repo: https://github.com/ambv/black + rev: 20.8b1 + hooks: + - id: black + language_version: python3.8 + +- repo: https://gitlab.com/pycqa/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + args: [ + # only error for syntax errors and undefined names + "--select=E9,F63,F7,F82", + ] + +- repo: https://github.com/pycqa/isort + rev: 5.10.1 + hooks: + - id: isort + exclude: README.md + additional_dependencies: [toml] + args: ["--profile", "black"] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3930c46196..60e9025887 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,3 +26,57 @@ clear and has sufficient instructions to be able to reproduce the issue. By contributing to Facebook AI Research Sequence-to-Sequence Toolkit (fairseq), you agree that your contributions will be licensed under the LICENSE file in the root directory of this source tree. + +## Pre-commit hooks +In order to ensure your code lints, there are pre-commit hooks configured in the repository which you can install. +After installation, they will automatically run each time you commit. +An abbreviated guide is given below; for more information, refer to [the offical pre-commit documentation](https://pre-commit.com/). + +### Installation +``` +pip install pre-commit +pre-commit install +``` + +### Usage +Just commit your changes: +``` +git commit -m "My informative commit message" +``` + +If there was a failure, you will get feedback +``` +[INFO] Initializing environment for https://github.com/PyCQA/flake8. +[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks. +[INFO] Once installed this environment will be reused. +[INFO] This may take a few minutes... +[INFO] Installing environment for https://github.com/PyCQA/flake8. +[INFO] Once installed this environment will be reused. +[INFO] This may take a few minutes... +Trim Trailing Whitespace.................................................Failed +- hook id: trailing-whitespace +- exit code: 1 +- files were modified by this hook +Fixing examples/nllb/modeling/wmt15_benchmark/eval_langs2.sh +Fix End of Files.........................................................Failed +- hook id: end-of-file-fixer +- exit code: 1 +- files were modified by this hook +Fixing examples/few_shot/scripts/schedule_jobs_few_shot.py +flake8...................................................................Passed +``` + +Certain hooks modify your files to comply. +To include these modifications, you will need to add them (i.e. `git add ...`) and commit again. + +If all is well, you should see something like: +``` +Trim Trailing Whitespace.................................................Passed +Fix End of Files.........................................................Passed +flake8...................................................................Passed +[gshard-fix-ci 8698644e1] Fix lint, add pre-commit hooks + 10 files changed, 148 insertions(+), 110 deletions(-) + create mode 100644 .flake8 + create mode 100644 .pre-commit-config.yaml + rename examples/nllb/modeling/wmt15_benchmark/{eval_langs2.py => eval_langs2.sh} (99%) + ``` diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000..3ea6243324 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 127 +extend-ignore = E203, W503 From 3dc1691df1fcf98e6518f0d8cb553c85387e0cab Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Sun, 28 Nov 2021 17:44:06 -0800 Subject: [PATCH 507/774] Add circleci config similar to one in gshard (#2677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Adds circleCI config to `main` similar to the one added in https://github.com/fairinternal/fairseq-py/issues/2455 by vedanuj Splitting out changes in https://github.com/fairinternal/fairseq-py/issues/2570 to be cleaner. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2677 Reviewed By: Mortimerp9 Differential Revision: D32653411 Pulled By: dianaml0 fbshipit-source-id: 24950ecebfb569b552675e65bee1451b8070f8ee --- .circleci/config.yml | 158 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..25f3a73881 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,158 @@ +# Use 2.1 for orbs +version: 2.1 + +# ------------------------------------------------------------------------------------- +# Environments to run the jobs in +# ------------------------------------------------------------------------------------- +gpu: &gpu + environment: + CUDA_VERSION: "11.1" + machine: + image: ubuntu-1604-cuda-11.1:202012-01 + resource_class: gpu.nvidia.medium.multi + + +# ------------------------------------------------------------------------------------- +# Re-usable commands +# ------------------------------------------------------------------------------------- +cache_key: &cache_key cache-key-{{ .Environment.CIRCLE_JOB }}-{{ checksum ".circleci/config.yml" }}-{{ checksum "setup.py"}} + +install_dep_common: &install_dep_common + - run: + name: Install Common Dependencies + command: | + source activate fairseq + pip install --upgrade setuptools + pip install bitarray boto3 deepspeed editdistance fastBPE iopath ipdb ipython pyarrow pytest sacremoses sentencepiece subword-nmt hydra-core==1.0.7 omegaconf==2.0.6 + pip install --progress-bar off pytest + pip install --progress-bar off fairscale==0.4.1 + pip install -i https://test.pypi.org/simple/ bitsandbytes-cuda111 -U + python -c 'import torch; print("Torch version:", torch.__version__)' + python -m torch.utils.collect_env + +install_dep_fused_ops: &install_dep_fused_ops + - run: + name: Install Megatron/Apex Dependencies + working_directory: ~/ + command: | + source activate fairseq + git clone https://github.com/NVIDIA/apex + cd apex + pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" --global-option="--deprecated_fused_adam" --global-option="--xentropy" --global-option="--fast_multihead_attn" ./ + cd ~/ + git clone --depth=1 --branch v2.4 https://github.com/NVIDIA/Megatron-LM.git + cd Megatron-LM + pip install -e . + + +install_dep_pt19: &install_dep_pt19 + - run: + name: Install Pytorch Dependencies + command: | + source activate fairseq + pip install --upgrade setuptools + pip install torch==1.9.1+cu111 torchvision==0.10.1+cu111 torchaudio==0.9.1 -f https://download.pytorch.org/whl/torch_stable.html + python -c 'import torch; print("Torch version:", torch.__version__)' + +install_dep_pt18: &install_dep_pt18 + - run: + name: Install Pytorch Dependencies + command: | + source activate fairseq + pip install --upgrade setuptools + pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html + python -c 'import torch; print("Torch version:", torch.__version__)' + +install_repo: &install_repo + - run: + name: Install Repository + command: | + source activate fairseq + pip install . + python setup.py build_ext --inplace + +run_unittests: &run_unittests + - run: + name: Run Unit Tests + command: | + source activate fairseq + pytest tests/gpu/test_binaries_gpu.py + +check_nvidia_driver: &check_nvidia_driver + - run: + name: Check NVIDIA Driver + working_directory: ~/ + command: | + pyenv versions + nvidia-smi + +create_conda_env: &create_conda_env + - run: + name: Install and Create Conda Environment + command: | + curl -o ~/miniconda.sh -O https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh + chmod +x ~/miniconda.sh + ~/miniconda.sh -b -p $HOME/miniconda + rm ~/miniconda.sh + echo 'export PATH=$HOME/miniconda/bin:$PATH' >> $BASH_ENV + source $BASH_ENV + if [ ! -d ~/miniconda/envs/fairseq ] + then + conda create -y -n fairseq python=3.8 + fi + source activate fairseq + python --version + pip install --upgrade pip +# ------------------------------------------------------------------------------------- +# Jobs to run +# ------------------------------------------------------------------------------------- + +jobs: + gpu_tests_pt19: + <<: *gpu + + working_directory: ~/fairseq-py + + steps: + - checkout + - <<: *check_nvidia_driver + - <<: *create_conda_env + - restore_cache: + key: *cache_key + - <<: *install_dep_pt19 + - <<: *install_dep_common + - <<: *install_dep_fused_ops + - save_cache: + paths: + - ~/miniconda/ + key: *cache_key + - <<: *install_repo + - <<: *run_unittests + + gpu_tests_pt18: + <<: *gpu + + working_directory: ~/fairseq-py + + steps: + - checkout + - <<: *check_nvidia_driver + - <<: *create_conda_env + - restore_cache: + key: *cache_key + - <<: *install_dep_pt18 + - <<: *install_dep_common + - <<: *install_dep_fused_ops + - save_cache: + paths: + - ~/miniconda/ + key: *cache_key + - <<: *install_repo + - <<: *run_unittests + +workflows: + version: 2 + build: + jobs: + - gpu_tests_pt18 + - gpu_tests_pt19 From 0dfd6b624081fc4e1c72fc74ae0cd2de199c334c Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Mon, 29 Nov 2021 12:30:10 -0800 Subject: [PATCH 508/774] Add linting with black (#2678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2678 Reviewed By: Mortimerp9 Differential Revision: D32653381 Pulled By: dianaml0 fbshipit-source-id: 2810d14867cd7d64f4d340740e2b590b82de47fe --- .github/workflows/build.yml | 5 + fairseq/__init__.py | 1 + fairseq/benchmark/dummy_mt.py | 4 +- fairseq/checkpoint_utils.py | 37 +-- fairseq/criterions/fastspeech2_loss.py | 44 +-- fairseq/criterions/hubert_criterion.py | 31 +- ...moothed_cross_entropy_latency_augmented.py | 47 ++-- fairseq/criterions/tacotron2_loss.py | 93 +++--- fairseq/criterions/wav2vec_criterion.py | 15 +- fairseq/data/add_target_dataset.py | 2 +- fairseq/data/audio/audio_utils.py | 93 +++--- .../data/audio/frm_text_to_speech_dataset.py | 42 ++- fairseq/data/audio/hubert_dataset.py | 30 +- fairseq/data/audio/multi_modality_dataset.py | 1 + fairseq/data/audio/raw_audio_dataset.py | 1 + fairseq/data/audio/speech_to_text_dataset.py | 68 +++-- fairseq/data/audio/text_to_speech_dataset.py | 127 +++++---- fairseq/data/colorize_dataset.py | 2 +- fairseq/data/data_utils.py | 11 +- fairseq/data/encoders/sentencepiece_bpe.py | 9 +- fairseq/data/fairseq_dataset.py | 2 +- fairseq/data/huffman/huffman_coder.py | 4 +- fairseq/data/indexed_dataset.py | 4 +- fairseq/data/iterators.py | 8 +- fairseq/data/language_pair_dataset.py | 10 +- fairseq/data/multi_corpus_dataset.py | 4 +- .../multilingual/multilingual_data_manager.py | 56 ++-- fairseq/data/noising.py | 1 - fairseq/data/text_compressor.py | 6 +- fairseq/data/token_block_dataset.py | 8 +- .../data/transform_eos_lang_pair_dataset.py | 2 +- fairseq/dataclass/configs.py | 69 +++-- fairseq/dataclass/constants.py | 18 +- fairseq/dataclass/initialize.py | 2 +- fairseq/dataclass/utils.py | 14 +- fairseq/distributed/__init__.py | 6 +- .../distributed_timeout_wrapper.py | 11 +- .../legacy_distributed_data_parallel.py | 2 +- fairseq/distributed/module_proxy_wrapper.py | 5 +- .../tpu_distributed_data_parallel.py | 6 +- fairseq/distributed/utils.py | 17 +- fairseq/file_io.py | 2 + fairseq/file_utils.py | 1 + fairseq/logging/metrics.py | 2 + fairseq/model_parallel/megatron_trainer.py | 16 +- .../pipeline_parallel_transformer/layers.py | 6 +- .../pipeline_parallel_transformer/model.py | 50 +++- .../model_parallel/models/transformer_lm.py | 7 +- fairseq/models/__init__.py | 4 +- fairseq/models/bart/hub_interface.py | 31 +- fairseq/models/bart/model.py | 8 +- fairseq/models/distributed_fairseq_model.py | 5 +- fairseq/models/ema/ema.py | 22 +- fairseq/models/fairseq_decoder.py | 1 - fairseq/models/fairseq_model.py | 13 +- fairseq/models/hubert/hubert.py | 70 ++--- fairseq/models/hubert/hubert_asr.py | 41 +-- fairseq/models/lstm.py | 12 +- fairseq/models/nat/fairseq_nat_model.py | 8 +- .../models/nat/nonautoregressive_ensembles.py | 3 +- fairseq/models/roberta/model.py | 6 +- fairseq/models/roberta/model_gottbert.py | 28 +- .../models/speech_to_text/s2t_transformer.py | 38 ++- .../models/speech_to_text/xm_transformer.py | 264 +++++++++++------- fairseq/models/text_to_speech/fastspeech2.py | 107 ++++--- fairseq/models/text_to_speech/hifigan.py | 4 +- fairseq/models/text_to_speech/tacotron2.py | 136 +++++---- .../models/text_to_speech/tts_transformer.py | 106 ++++--- fairseq/models/text_to_speech/vocoder.py | 84 ++++-- .../models/transformer/transformer_decoder.py | 4 +- .../models/transformer/transformer_encoder.py | 11 +- fairseq/models/transformer_lm.py | 48 +++- fairseq/models/wav2vec/wav2vec2.py | 20 +- fairseq/models/wav2vec/wav2vec2_asr.py | 24 +- fairseq/modules/base_layer.py | 75 +++-- fairseq/modules/checkpoint_activations.py | 7 +- fairseq/modules/gumbel_vector_quantizer.py | 1 + fairseq/modules/kmeans_attention.py | 237 ++++++++++++---- fairseq/modules/linearized_convolution.py | 23 +- fairseq/modules/location_attention.py | 23 +- fairseq/modules/lstm_cell_with_zoneout.py | 14 +- fairseq/modules/quantization/pq/utils.py | 10 +- fairseq/modules/quantization/scalar/utils.py | 4 +- fairseq/modules/transformer_layer.py | 37 ++- .../modules/transformer_sentence_encoder.py | 8 +- fairseq/ngram_repeat_block.py | 10 +- fairseq/optim/adam.py | 8 +- fairseq/optim/amp_optimizer.py | 5 +- fairseq/optim/composite.py | 4 +- fairseq/optim/cpu_adam.py | 4 + fairseq/optim/fp16_optimizer.py | 12 +- fairseq/optim/fused_adam.py | 7 +- .../optim/lr_scheduler/manual_lr_scheduler.py | 23 +- .../optim/lr_scheduler/step_lr_scheduler.py | 15 +- fairseq/sequence_generator.py | 22 +- fairseq/speech_generator.py | 68 +++-- fairseq/tasks/audio_finetuning.py | 75 +++-- fairseq/tasks/audio_pretraining.py | 7 +- fairseq/tasks/denoising.py | 1 - fairseq/tasks/frm_text_to_speech.py | 13 +- fairseq/tasks/hubert_pretraining.py | 28 +- fairseq/tasks/language_modeling.py | 10 +- fairseq/tasks/simultaneous_translation.py | 9 +- fairseq/tasks/speech_to_text.py | 7 +- fairseq/tasks/text_to_speech.py | 184 +++++++----- fairseq/tasks/translation.py | 6 +- fairseq/tasks/translation_lev.py | 12 +- .../tasks/translation_multi_simple_epoch.py | 6 +- fairseq/trainer.py | 50 +++- fairseq/utils.py | 5 +- fairseq_cli/generate.py | 23 +- fairseq_cli/hydra_train.py | 23 +- fairseq_cli/interactive.py | 7 +- fairseq_cli/preprocess.py | 4 +- fairseq_cli/train.py | 25 +- fairseq_cli/validate.py | 8 +- setup.py | 5 +- tests/distributed/test_bmuf.py | 8 +- .../test_distributed_timeout_wrapper.py | 2 - .../distributed/test_module_proxy_wrapper.py | 1 - tests/distributed/utils.py | 5 +- tests/gpu/test_binaries_gpu.py | 29 +- tests/gpu/test_ema_gpu.py | 44 ++- tests/test_amp_optimizer.py | 11 +- tests/test_binaries.py | 24 +- tests/test_checkpoint_utils.py | 34 +-- tests/test_data_utils.py | 6 +- tests/test_dataclass_utils.py | 2 +- tests/test_ema.py | 44 ++- tests/test_export.py | 3 +- tests/test_file_io.py | 1 + tests/test_iopath.py | 1 - tests/test_lm_context_window.py | 16 +- tests/test_multi_corpus_dataset.py | 7 +- tests/test_noising.py | 7 +- tests/test_sequence_generator.py | 18 +- tests/utils.py | 10 +- 137 files changed, 2142 insertions(+), 1356 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd1d3b3c6d..a80e0f92c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,3 +53,8 @@ jobs: - name: Run tests run: | python setup.py test + + - name: Lint with black + run: | + pip install black + black --check . --extend-exclude 'examples|fairseq\/model_parallel\/megatron' diff --git a/fairseq/__init__.py b/fairseq/__init__.py index dc9fd1886d..080c988b2d 100644 --- a/fairseq/__init__.py +++ b/fairseq/__init__.py @@ -27,6 +27,7 @@ # initialize hydra from fairseq.dataclass.initialize import hydra_init + hydra_init() import fairseq.criterions # noqa diff --git a/fairseq/benchmark/dummy_mt.py b/fairseq/benchmark/dummy_mt.py index 4ca7be93a3..28d78cffdb 100644 --- a/fairseq/benchmark/dummy_mt.py +++ b/fairseq/benchmark/dummy_mt.py @@ -7,10 +7,10 @@ import numpy as np import torch + from fairseq.data import Dictionary, FairseqDataset from fairseq.tasks import LegacyFairseqTask, register_task - logger = logging.getLogger(__name__) @@ -36,7 +36,7 @@ def __init__(self, args, dictionary): @classmethod def setup_task(cls, args, **kwargs): - """Setup the task. """ + """Setup the task.""" dictionary = Dictionary() for i in range(args.dict_size): dictionary.add_symbol("word{}".format(i)) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 289053e53d..a5be928f0a 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -96,10 +96,7 @@ def is_better(a, b): checkpoint_conds[ "checkpoint.best_{}_{:.3f}{}{}.pt".format( - cfg.best_checkpoint_metric, - val_loss, - rand_sfx, - suffix + cfg.best_checkpoint_metric, val_loss, rand_sfx, suffix ) ] = worst_best is None or is_better(val_loss, worst_best) checkpoint_conds[ @@ -468,9 +465,7 @@ def load_model_ensemble_and_task( and len(state["optimizer_history"]) > 0 and "num_updates" in state["optimizer_history"][-1] ): - model.set_num_updates( - state["optimizer_history"][-1]["num_updates"] - ) + model.set_num_updates(state["optimizer_history"][-1]["num_updates"]) model.load_state_dict( state["model"], strict=strict, model_cfg=cfg.model ) @@ -588,9 +583,8 @@ def _upgrade_state_dict(state): # backward compatibility, cfg updates if "args" in state and state["args"] is not None: # old model checkpoints may not have separate source/target positions - if ( - hasattr(state["args"], "max_positions") - and not hasattr(state["args"], "max_source_positions") + if hasattr(state["args"], "max_positions") and not hasattr( + state["args"], "max_source_positions" ): state["args"].max_source_positions = state["args"].max_positions state["args"].max_target_positions = state["args"].max_positions @@ -615,13 +609,10 @@ def _upgrade_state_dict(state): state["args"].stop_min_lr = state["args"].min_lr del state["args"].min_lr # binary_cross_entropy / kd_binary_cross_entropy => wav2vec criterion - if ( - hasattr(state["args"], "criterion") - and state["args"].criterion in [ - "binary_cross_entropy", - "kd_binary_cross_entropy", - ] - ): + if hasattr(state["args"], "criterion") and state["args"].criterion in [ + "binary_cross_entropy", + "kd_binary_cross_entropy", + ]: state["args"].criterion = "wav2vec" # remove log_keys if it's None (criteria will supply a default value of []) if hasattr(state["args"], "log_keys") and state["args"].log_keys is None: @@ -659,7 +650,9 @@ def _upgrade_state_dict(state): ): cfg.task.eval_wer_config.print_alignment = "hard" if "generation" in cfg and isinstance(cfg.generation.print_alignment, bool): - cfg.generation.print_alignment = "hard" if cfg.generation.print_alignment else None + cfg.generation.print_alignment = ( + "hard" if cfg.generation.print_alignment else None + ) if ( "model" in cfg and "w2v_args" in cfg.model @@ -833,16 +826,16 @@ def load_ema_from_checkpoint(fpath): params_dict = collections.OrderedDict() new_state = None - with PathManager.open(fpath, 'rb') as f: + with PathManager.open(fpath, "rb") as f: new_state = torch.load( f, map_location=( - lambda s, _: torch.serialization.default_restore_location(s, 'cpu') + lambda s, _: torch.serialization.default_restore_location(s, "cpu") ), ) # EMA model is stored in a separate "extra state" - model_params = new_state['extra_state']['ema'] + model_params = new_state["extra_state"]["ema"] for key in list(model_params.keys()): p = model_params[key] @@ -860,5 +853,5 @@ def load_ema_from_checkpoint(fpath): "ema model weights, is this model trained with EMA?" ) - new_state['model'] = params_dict + new_state["model"] = params_dict return new_state diff --git a/fairseq/criterions/fastspeech2_loss.py b/fairseq/criterions/fastspeech2_loss.py index b17b507023..b317409e26 100644 --- a/fairseq/criterions/fastspeech2_loss.py +++ b/fairseq/criterions/fastspeech2_loss.py @@ -20,9 +20,7 @@ @dataclass class FastSpeech2CriterionConfig(FairseqDataclass): - ctc_weight: float = field( - default=0.0, metadata={"help": "weight for CTC loss"} - ) + ctc_weight: float = field(default=0.0, metadata={"help": "weight for CTC loss"}) @register_criterion("fastspeech2", dataclass=FastSpeech2CriterionConfig) @@ -44,7 +42,7 @@ def forward(self, model: FairseqEncoderModel, sample, reduction="mean"): speaker=sample["speaker"], durations=sample["durations"], pitches=sample["pitches"], - energies=sample["energies"] + energies=sample["energies"], ) src_mask = lengths_to_mask(sample["net_input"]["src_lengths"]) @@ -57,8 +55,7 @@ def forward(self, model: FairseqEncoderModel, sample, reduction="mean"): feat_out, feat = _feat_out[tgt_mask], sample["target"][tgt_mask] l1_loss = F.l1_loss(feat_out, feat, reduction=reduction) if _feat_out_post is not None: - l1_loss += F.l1_loss(_feat_out_post[tgt_mask], feat, - reduction=reduction) + l1_loss += F.l1_loss(_feat_out_post[tgt_mask], feat, reduction=reduction) pitch_loss = F.mse_loss(pitch_out, pitches, reduction=reduction) energy_loss = F.mse_loss(energy_out, energies, reduction=reduction) @@ -69,16 +66,23 @@ def forward(self, model: FairseqEncoderModel, sample, reduction="mean"): log_dur = torch.log(dur + 1)[src_mask] dur_loss = F.mse_loss(log_dur_out, log_dur, reduction=reduction) - ctc_loss = torch.tensor(0.).type_as(l1_loss) - if self.ctc_weight > 0.: + ctc_loss = torch.tensor(0.0).type_as(l1_loss) + if self.ctc_weight > 0.0: lprobs = model.get_normalized_probs((_feat_out,), log_probs=True) lprobs = lprobs.transpose(0, 1) # T x B x C src_mask = lengths_to_mask(src_lens) src_tokens_flat = src_tokens.masked_select(src_mask) - ctc_loss = F.ctc_loss( - lprobs, src_tokens_flat, tgt_lens, src_lens, - reduction=reduction, zero_infinity=True - ) * self.ctc_weight + ctc_loss = ( + F.ctc_loss( + lprobs, + src_tokens_flat, + tgt_lens, + src_lens, + reduction=reduction, + zero_infinity=True, + ) + * self.ctc_weight + ) loss = l1_loss + dur_loss + pitch_loss + energy_loss + ctc_loss @@ -102,8 +106,12 @@ def reduce_metrics(cls, logging_outputs: List[Dict[str, Any]]) -> None: ntot = sum(ns) ws = [n / (ntot + 1e-8) for n in ns] for key in [ - "loss", "l1_loss", "dur_loss", "pitch_loss", "energy_loss", - "ctc_loss" + "loss", + "l1_loss", + "dur_loss", + "pitch_loss", + "energy_loss", + "ctc_loss", ]: vals = [log.get(key, 0) for log in logging_outputs] val = sum(val * w for val, w in zip(vals, ws)) @@ -115,10 +123,10 @@ def reduce_metrics(cls, logging_outputs: List[Dict[str, Any]]) -> None: return n = sum(log.get("targ_frames", 0) for log in logging_outputs) for key, new_key in [ - ("mcd_loss", "mcd_loss"), - ("pred_frames", "pred_ratio"), - ("nins", "ins_rate"), - ("ndel", "del_rate"), + ("mcd_loss", "mcd_loss"), + ("pred_frames", "pred_ratio"), + ("nins", "ins_rate"), + ("ndel", "del_rate"), ]: val = sum(log.get(key, 0) for log in logging_outputs) metrics.log_scalar(new_key, val / n, n, round=3) diff --git a/fairseq/criterions/hubert_criterion.py b/fairseq/criterions/hubert_criterion.py index 68cb24e6f1..83b514aeef 100644 --- a/fairseq/criterions/hubert_criterion.py +++ b/fairseq/criterions/hubert_criterion.py @@ -37,7 +37,14 @@ class HubertCriterionConfig(FairseqDataclass): @register_criterion("hubert", dataclass=HubertCriterionConfig) class HubertCriterion(FairseqCriterion): - def __init__(self, task, pred_masked_weight, pred_nomask_weight, loss_weights=None, log_keys=None): + def __init__( + self, + task, + pred_masked_weight, + pred_nomask_weight, + loss_weights=None, + log_keys=None, + ): super().__init__(task) self.pred_masked_weight = pred_masked_weight self.pred_nomask_weight = pred_nomask_weight @@ -52,7 +59,7 @@ def forward(self, model, sample, reduce=True, log_pred=False): 3) logging outputs to display while training """ net_output = model(target_list=sample["target_list"], **sample["net_input"]) - loss = 0. + loss = 0.0 sample_size = 0 logging_output = {} reduction = "sum" if reduce else "none" @@ -89,7 +96,9 @@ def forward(self, model, sample, reduce=True, log_pred=False): names = [names] if len(self.loss_weights) == 1 and len(extra_losses) != 1: self.loss_weights = [self.loss_weights[0]] * len(extra_losses) - assert len(extra_losses) == len(self.loss_weights), f"{len(extra_losses)}, {len(self.loss_weights)}" + assert len(extra_losses) == len( + self.loss_weights + ), f"{len(extra_losses)}, {len(self.loss_weights)}" for p, n, coef in zip(extra_losses, names, self.loss_weights): if coef != 0 and p is not None: p = coef * p.float() * sample_size @@ -140,12 +149,20 @@ def reduce_metrics(logging_outputs) -> None: ntokens = sum(log.get("ntokens", 0) for log in logging_outputs) sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) - metrics.log_scalar("loss", loss_sum / sample_size / math.log(2), sample_size, round=3) + metrics.log_scalar( + "loss", loss_sum / sample_size / math.log(2), sample_size, round=3 + ) if sample_size != ntokens: - metrics.log_scalar("nll_loss", loss_sum / ntokens / math.log(2), ntokens, round=3) - metrics.log_derived("ppl", lambda meters: utils.get_perplexity(meters["nll_loss"].avg)) + metrics.log_scalar( + "nll_loss", loss_sum / ntokens / math.log(2), ntokens, round=3 + ) + metrics.log_derived( + "ppl", lambda meters: utils.get_perplexity(meters["nll_loss"].avg) + ) else: - metrics.log_derived("ppl", lambda meters: utils.get_perplexity(meters["loss"].avg)) + metrics.log_derived( + "ppl", lambda meters: utils.get_perplexity(meters["loss"].avg) + ) counts = {} for lk in logging_outputs[0].keys(): diff --git a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py index 223a16f740..d5fb390f84 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py @@ -9,19 +9,20 @@ from fairseq.criterions import register_criterion from fairseq.criterions.label_smoothed_cross_entropy import ( LabelSmoothedCrossEntropyCriterion, - LabelSmoothedCrossEntropyCriterionConfig + LabelSmoothedCrossEntropyCriterionConfig, ) try: from simuleval.metrics.latency import ( AverageLagging, AverageProportion, - DifferentiableAverageLagging + DifferentiableAverageLagging, ) + LATENCY_METRICS = { "average_lagging": AverageLagging, "average_proportion": AverageProportion, - "differentiable_average_lagging": DifferentiableAverageLagging, + "differentiable_average_lagging": DifferentiableAverageLagging, } except ImportError: LATENCY_METRICS = None @@ -56,9 +57,10 @@ class LabelSmoothedCrossEntropyCriterionLatencyAugmentConfig( metadata={"help": "Add latency loss after certain steps"}, ) + @register_criterion( "latency_augmented_label_smoothed_cross_entropy", - dataclass=LabelSmoothedCrossEntropyCriterionLatencyAugmentConfig + dataclass=LabelSmoothedCrossEntropyCriterionLatencyAugmentConfig, ) class LatencyAugmentedLabelSmoothedCrossEntropyCriterion( LabelSmoothedCrossEntropyCriterion @@ -101,9 +103,9 @@ def forward(self, model, sample, reduce=True): if self.latency_update_after > 0: num_updates = getattr(model.decoder, "num_updates", None) - assert num_updates is not None, ( - "model.decoder doesn't have attribute 'num_updates'" - ) + assert ( + num_updates is not None + ), "model.decoder doesn't have attribute 'num_updates'" if num_updates <= self.latency_update_after: latency_loss = 0 @@ -134,9 +136,7 @@ def compute_latency_loss(self, model, sample, net_output): assert ( net_output[-1].encoder_padding_mask is None or not net_output[-1].encoder_padding_mask[:, 0].any() - ), ( - "Only right padding on source is supported." - ) + ), "Only right padding on source is supported." # 1. Obtain the expected alignment alpha_list = [item["alpha"] for item in net_output[1].attn_list] num_layers = len(alpha_list) @@ -174,8 +174,7 @@ def compute_latency_loss(self, model, sample, net_output): .view(-1) ) expected_latency = LATENCY_METRICS[self.latency_avg_type]( - expected_delays, src_lengths, None, - target_padding_mask=target_padding_mask + expected_delays, src_lengths, None, target_padding_mask=target_padding_mask ) # 2.1 average expected latency of heads @@ -210,24 +209,12 @@ def compute_latency_loss(self, model, sample, net_output): @classmethod def reduce_metrics(cls, logging_outputs) -> None: super().reduce_metrics(logging_outputs) - latency = sum( - log.get("latency", 0) for log in logging_outputs - ) - delays_var = sum( - log.get("delays_var", 0) for log in logging_outputs - ) - latency_loss = sum( - log.get("latency_loss", 0) for log in logging_outputs - ) + latency = sum(log.get("latency", 0) for log in logging_outputs) + delays_var = sum(log.get("delays_var", 0) for log in logging_outputs) + latency_loss = sum(log.get("latency_loss", 0) for log in logging_outputs) nsentences = sum(log.get("nsentences", 0) for log in logging_outputs) + metrics.log_scalar("latency", latency.float() / nsentences, nsentences, round=3) + metrics.log_scalar("delays_var", delays_var / nsentences, nsentences, round=3) metrics.log_scalar( - "latency", latency.float() / nsentences, nsentences, round=3 - ) - metrics.log_scalar( - "delays_var", delays_var / nsentences, - nsentences, round=3 - ) - metrics.log_scalar( - "latency_loss", latency_loss / nsentences, - nsentences, round=3 + "latency_loss", latency_loss / nsentences, nsentences, round=3 ) diff --git a/fairseq/criterions/tacotron2_loss.py b/fairseq/criterions/tacotron2_loss.py index 8c7b655c8c..11ebf2d836 100644 --- a/fairseq/criterions/tacotron2_loss.py +++ b/fairseq/criterions/tacotron2_loss.py @@ -41,9 +41,7 @@ class Tacotron2CriterionConfig(FairseqDataclass): default=0.4, metadata={"help": "weight of positive examples for BCE loss"}, ) - ctc_weight: float = field( - default=0.0, metadata={"help": "weight for CTC loss"} - ) + ctc_weight: float = field(default=0.0, metadata={"help": "weight for CTC loss"}) sentence_avg: bool = II("optimization.sentence_avg") @@ -70,8 +68,7 @@ def _get_weights(self, src_lens, tgt_lens): bsz, max_s_len, max_t_len = len(src_lens), max(src_lens), max(tgt_lens) weights = torch.zeros((bsz, max_t_len, max_s_len)) for i, (s_len, t_len) in enumerate(zip(src_lens, tgt_lens)): - weights[i, :t_len, :s_len] = self._get_weight(s_len, t_len, - self.sigma) + weights[i, :t_len, :s_len] = self._get_weight(s_len, t_len, self.sigma) return weights @staticmethod @@ -90,9 +87,16 @@ def forward(self, attn, src_lens, tgt_lens, reduction="mean"): @register_criterion("tacotron2", dataclass=Tacotron2CriterionConfig) class Tacotron2Criterion(FairseqCriterion): - def __init__(self, task, sentence_avg, n_frames_per_step, - use_guided_attention_loss, guided_attention_loss_sigma, - bce_pos_weight, ctc_weight): + def __init__( + self, + task, + sentence_avg, + n_frames_per_step, + use_guided_attention_loss, + guided_attention_loss_sigma, + bce_pos_weight, + ctc_weight, + ): super().__init__(task) self.sentence_avg = sentence_avg self.n_frames_per_step = n_frames_per_step @@ -120,31 +124,42 @@ def forward(self, model, sample, reduction="mean"): prev_output_tokens=sample["net_input"]["prev_output_tokens"], incremental_state=None, target_lengths=tgt_lens, - speaker=sample["speaker"] + speaker=sample["speaker"], ) l1_loss, mse_loss, eos_loss = self.compute_loss( - extra["feature_out"], feat_out, eos_out, feat_tgt, eos_tgt, - tgt_lens, reduction, + extra["feature_out"], + feat_out, + eos_out, + feat_tgt, + eos_tgt, + tgt_lens, + reduction, ) - attn_loss = torch.tensor(0.).type_as(l1_loss) + attn_loss = torch.tensor(0.0).type_as(l1_loss) if self.guided_attn is not None: - attn_loss = self.guided_attn(extra['attn'], src_lens, tgt_lens, reduction) - ctc_loss = torch.tensor(0.).type_as(l1_loss) - if self.ctc_weight > 0.: + attn_loss = self.guided_attn(extra["attn"], src_lens, tgt_lens, reduction) + ctc_loss = torch.tensor(0.0).type_as(l1_loss) + if self.ctc_weight > 0.0: net_output = (feat_out, eos_out, extra) lprobs = model.get_normalized_probs(net_output, log_probs=True) lprobs = lprobs.transpose(0, 1) # T x B x C src_mask = lengths_to_mask(src_lens) src_tokens_flat = src_tokens.masked_select(src_mask) - ctc_loss = F.ctc_loss( - lprobs, src_tokens_flat, tgt_lens, src_lens, - reduction=reduction, zero_infinity=True - ) * self.ctc_weight + ctc_loss = ( + F.ctc_loss( + lprobs, + src_tokens_flat, + tgt_lens, + src_lens, + reduction=reduction, + zero_infinity=True, + ) + * self.ctc_weight + ) loss = l1_loss + mse_loss + eos_loss + attn_loss + ctc_loss - sample_size = sample["nsentences"] if self.sentence_avg \ - else sample["ntokens"] + sample_size = sample["nsentences"] if self.sentence_avg else sample["ntokens"] logging_output = { "loss": utils.item(loss.data), "ntokens": sample["ntokens"], @@ -158,8 +173,16 @@ def forward(self, model, sample, reduction="mean"): } return loss, sample_size, logging_output - def compute_loss(self, feat_out, feat_out_post, eos_out, feat_tgt, - eos_tgt, tgt_lens, reduction="mean"): + def compute_loss( + self, + feat_out, + feat_out_post, + eos_out, + feat_tgt, + eos_tgt, + tgt_lens, + reduction="mean", + ): mask = lengths_to_mask(tgt_lens) _eos_out = eos_out[mask].squeeze() _eos_tgt = eos_tgt[mask] @@ -167,17 +190,17 @@ def compute_loss(self, feat_out, feat_out_post, eos_out, feat_tgt, _feat_out = feat_out[mask] _feat_out_post = feat_out_post[mask] - l1_loss = ( - F.l1_loss(_feat_out, _feat_tgt, reduction=reduction) + - F.l1_loss(_feat_out_post, _feat_tgt, reduction=reduction) + l1_loss = F.l1_loss(_feat_out, _feat_tgt, reduction=reduction) + F.l1_loss( + _feat_out_post, _feat_tgt, reduction=reduction ) - mse_loss = ( - F.mse_loss(_feat_out, _feat_tgt, reduction=reduction) + - F.mse_loss(_feat_out_post, _feat_tgt, reduction=reduction) + mse_loss = F.mse_loss(_feat_out, _feat_tgt, reduction=reduction) + F.mse_loss( + _feat_out_post, _feat_tgt, reduction=reduction ) eos_loss = F.binary_cross_entropy_with_logits( - _eos_out, _eos_tgt, pos_weight=torch.tensor(self.bce_pos_weight), - reduction=reduction + _eos_out, + _eos_tgt, + pos_weight=torch.tensor(self.bce_pos_weight), + reduction=reduction, ) return l1_loss, mse_loss, eos_loss @@ -197,10 +220,10 @@ def reduce_metrics(cls, logging_outputs: List[Dict[str, Any]]) -> None: return n = sum(log.get("targ_frames", 0) for log in logging_outputs) for key, new_key in [ - ("mcd_loss", "mcd_loss"), - ("pred_frames", "pred_ratio"), - ("nins", "ins_rate"), - ("ndel", "del_rate"), + ("mcd_loss", "mcd_loss"), + ("pred_frames", "pred_ratio"), + ("nins", "ins_rate"), + ("ndel", "del_rate"), ]: val = sum(log.get(key, 0) for log in logging_outputs) metrics.log_scalar(new_key, val / n, n, round=3) diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index e04786cc3b..e37274d5a8 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -33,6 +33,7 @@ class Wav2VecCriterionConfig(FairseqDataclass): metadata={"help": "output keys to log"}, ) + @register_criterion("wav2vec", dataclass=Wav2VecCriterionConfig) class Wav2vecCriterion(FairseqCriterion): def __init__(self, task, infonce=False, loss_weights=None, log_keys=None): @@ -76,16 +77,16 @@ def forward(self, model, sample, reduce=True): # we don't shrink tensors using mask_indices. # Instead, we use mask indices to adjust loss. mi = ( - sample['net_input']['mask_indices'] + sample["net_input"]["mask_indices"] .transpose(0, 1) # logits are transposed in `model.get_logits` .reshape(logits.size(0)) ) loss = (loss * mi).sum() if reduce else (loss * mi) - if 'sample_size' in sample: - sample_size = sample['sample_size'] - elif 'mask_indices' in sample['net_input']: - sample_size = sample['net_input']['mask_indices'].sum() + if "sample_size" in sample: + sample_size = sample["sample_size"] + elif "mask_indices" in sample["net_input"]: + sample_size = sample["net_input"]["mask_indices"].sum() else: sample_size = target.numel() if self.infonce else target.long().sum().item() losses.append(loss.detach().clone()) @@ -216,8 +217,8 @@ def reduce_metrics(logging_outputs) -> None: metrics.log_scalar(k, val / len(logging_outputs), round=3) # FIXME: revert when gather based xla reduction is implemented - #@staticmethod - #def logging_outputs_can_be_summed() -> bool: + # @staticmethod + # def logging_outputs_can_be_summed() -> bool: def logging_outputs_can_be_summed(self) -> bool: """ Whether the logging outputs returned by `forward` can be summed diff --git a/fairseq/data/add_target_dataset.py b/fairseq/data/add_target_dataset.py index d8a08e746d..bf89f25656 100644 --- a/fairseq/data/add_target_dataset.py +++ b/fairseq/data/add_target_dataset.py @@ -20,7 +20,7 @@ def __init__( process_label=None, label_len_fn=None, add_to_input=False, - text_compression_level=TextCompressionLevel.none + text_compression_level=TextCompressionLevel.none, ): super().__init__(dataset) self.labels = labels diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index 35e7fb2a2a..ac6b13d813 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -18,26 +18,28 @@ def convert_waveform( - waveform: Union[np.ndarray, torch.Tensor], sample_rate: int, - normalize_volume: bool = False, to_mono: bool = False, - to_sample_rate: Optional[int] = None + waveform: Union[np.ndarray, torch.Tensor], + sample_rate: int, + normalize_volume: bool = False, + to_mono: bool = False, + to_sample_rate: Optional[int] = None, ) -> Tuple[Union[np.ndarray, torch.Tensor], int]: """convert a waveform: - - to a target sample rate - - from multi-channel to mono channel - - volume normalization - - Args: - waveform (numpy.ndarray or torch.Tensor): 2D original waveform - (channels x length) - sample_rate (int): original sample rate - normalize_volume (bool): perform volume normalization - to_mono (bool): convert to mono channel if having multiple channels - to_sample_rate (Optional[int]): target sample rate - Returns: - waveform (numpy.ndarray): converted 2D waveform (channels x length) - sample_rate (float): target sample rate - """ + - to a target sample rate + - from multi-channel to mono channel + - volume normalization + + Args: + waveform (numpy.ndarray or torch.Tensor): 2D original waveform + (channels x length) + sample_rate (int): original sample rate + normalize_volume (bool): perform volume normalization + to_mono (bool): convert to mono channel if having multiple channels + to_sample_rate (Optional[int]): target sample rate + Returns: + waveform (numpy.ndarray): converted 2D waveform (channels x length) + sample_rate (float): target sample rate + """ try: import torchaudio.sox_effects as ta_sox except ImportError: @@ -63,10 +65,14 @@ def convert_waveform( def get_waveform( - path_or_fp: Union[str, BinaryIO], normalization: bool = True, - mono: bool = True, frames: int = -1, start: int = 0, - always_2d: bool = True, output_sample_rate: Optional[int] = None, - normalize_volume: bool = False + path_or_fp: Union[str, BinaryIO], + normalization: bool = True, + mono: bool = True, + frames: int = -1, + start: int = 0, + always_2d: bool = True, + output_sample_rate: Optional[int] = None, + normalize_volume: bool = False, ) -> Tuple[np.ndarray, int]: """Get the waveform and sample rate of a 16-bit WAV/FLAC/OGG Vorbis audio. @@ -98,8 +104,11 @@ def get_waveform( ) waveform = waveform.T # T x C -> C x T waveform, sample_rate = convert_waveform( - waveform, sample_rate, normalize_volume=normalize_volume, to_mono=mono, - to_sample_rate=output_sample_rate + waveform, + sample_rate, + normalize_volume=normalize_volume, + to_mono=mono, + to_sample_rate=output_sample_rate, ) if not normalization: @@ -182,7 +191,7 @@ def is_sf_audio_data(data: bytes) -> bool: def mmap_read(path: str, offset: int, length: int) -> bytes: with open(path, "rb") as f: with mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) as mmap_o: - data = mmap_o[offset: offset + length] + data = mmap_o[offset : offset + length] return data @@ -215,9 +224,7 @@ def parse_path(path: str) -> Tuple[str, List[int]]: return _path, slice_ptr -def get_window( - window_fn: callable, n_fft: int, win_length: int -) -> torch.Tensor: +def get_window(window_fn: callable, n_fft: int, win_length: int) -> torch.Tensor: padding = n_fft - win_length assert padding >= 0 return F.pad(window_fn(win_length), (padding // 2, padding - padding // 2)) @@ -226,13 +233,13 @@ def get_window( def get_fourier_basis(n_fft: int) -> torch.Tensor: basis = np.fft.fft(np.eye(n_fft)) basis = np.vstack( - [np.real(basis[:n_fft // 2 + 1, :]), np.imag(basis[:n_fft // 2 + 1, :])] + [np.real(basis[: n_fft // 2 + 1, :]), np.imag(basis[: n_fft // 2 + 1, :])] ) return torch.from_numpy(basis).float() def get_mel_filters( - sample_rate: int, n_fft: int, n_mels: int, f_min: float, f_max: float + sample_rate: int, n_fft: int, n_mels: int, f_min: float, f_max: float ) -> torch.Tensor: try: import librosa @@ -244,8 +251,12 @@ def get_mel_filters( class TTSSpectrogram(torch.nn.Module): def __init__( - self, n_fft: int, win_length: int, hop_length: int, - window_fn: callable = torch.hann_window, return_phase: bool = False + self, + n_fft: int, + win_length: int, + hop_length: int, + window_fn: callable = torch.hann_window, + return_phase: bool = False, ) -> None: super(TTSSpectrogram, self).__init__() self.n_fft = n_fft @@ -254,16 +265,16 @@ def __init__( basis = get_fourier_basis(n_fft).unsqueeze(1) basis *= get_window(window_fn, n_fft, win_length) - self.register_buffer('basis', basis) + self.register_buffer("basis", basis) def forward( - self, waveform: torch.Tensor + self, waveform: torch.Tensor ) -> Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]]: padding = (self.n_fft // 2, self.n_fft // 2) - x = F.pad(waveform.unsqueeze(1), padding, mode='reflect') + x = F.pad(waveform.unsqueeze(1), padding, mode="reflect") x = F.conv1d(x, self.basis, stride=self.hop_length) - real_part = x[:, :self.n_fft // 2 + 1, :] - imag_part = x[:, self.n_fft // 2 + 1:, :] + real_part = x[:, : self.n_fft // 2 + 1, :] + imag_part = x[:, self.n_fft // 2 + 1 :, :] magnitude = torch.sqrt(real_part ** 2 + imag_part ** 2) if self.return_phase: phase = torch.atan2(imag_part, real_part) @@ -273,13 +284,11 @@ def forward( class TTSMelScale(torch.nn.Module): def __init__( - self, n_mels: int, sample_rate: int, f_min: float, f_max: float, - n_stft: int + self, n_mels: int, sample_rate: int, f_min: float, f_max: float, n_stft: int ) -> None: super(TTSMelScale, self).__init__() - basis = get_mel_filters(sample_rate, (n_stft - 1) * 2, n_mels, f_min, - f_max) - self.register_buffer('basis', basis) + basis = get_mel_filters(sample_rate, (n_stft - 1) * 2, n_mels, f_min, f_max) + self.register_buffer("basis", basis) def forward(self, specgram: torch.Tensor) -> torch.Tensor: return torch.matmul(self.basis, specgram) diff --git a/fairseq/data/audio/frm_text_to_speech_dataset.py b/fairseq/data/audio/frm_text_to_speech_dataset.py index 125b1fc0c0..b54654d492 100644 --- a/fairseq/data/audio/frm_text_to_speech_dataset.py +++ b/fairseq/data/audio/frm_text_to_speech_dataset.py @@ -13,11 +13,10 @@ import numpy as np import torch from fairseq.data import Dictionary -from fairseq.data.audio.speech_to_text_dataset import ( - S2TDataConfig -) +from fairseq.data.audio.speech_to_text_dataset import S2TDataConfig from fairseq.data.audio.text_to_speech_dataset import ( - TextToSpeechDataset, TextToSpeechDatasetCreator + TextToSpeechDataset, + TextToSpeechDatasetCreator, ) logger = logging.getLogger(__name__) @@ -48,7 +47,7 @@ def __init__( chunk_incr=5, add_eos=True, dedup=True, - ref_fpu=-1 + ref_fpu=-1, ): # It assumes texts are encoded at a fixed frame-rate super().__init__( @@ -67,7 +66,7 @@ def __init__( pre_tokenizer=pre_tokenizer, bpe_tokenizer=bpe_tokenizer, n_frames_per_step=n_frames_per_step, - speaker_to_id=speaker_to_id + speaker_to_id=speaker_to_id, ) self.do_chunk = do_chunk @@ -92,24 +91,23 @@ def __getitem__(self, index): fpu = source.size(0) / target.size(0) # frame-per-unit fps = self.n_frames_per_step assert ( - self.ref_fpu == -1 or - abs((fpu * fps - self.ref_fpu) / self.ref_fpu) < 0.1 + self.ref_fpu == -1 or abs((fpu * fps - self.ref_fpu) / self.ref_fpu) < 0.1 ), f"{fpu*fps} != {self.ref_fpu}" # only chunk training split if self.is_train_split and self.do_chunk and self.chunk_size > 0: - lang = target[:int(self.data_cfg.prepend_tgt_lang_tag)] - text = target[int(self.data_cfg.prepend_tgt_lang_tag):] + lang = target[: int(self.data_cfg.prepend_tgt_lang_tag)] + text = target[int(self.data_cfg.prepend_tgt_lang_tag) :] size = len(text) chunk_size = min(self.chunk_size, size) chunk_start = np.random.randint(size - chunk_size + 1) - text = text[chunk_start:chunk_start+chunk_size] + text = text[chunk_start : chunk_start + chunk_size] target = torch.cat((lang, text), 0) f_size = int(np.floor(chunk_size * fpu)) f_start = int(np.floor(chunk_start * fpu)) - assert(f_size > 0) - source = source[f_start:f_start+f_size, :] + assert f_size > 0 + source = source[f_start : f_start + f_size, :] if self.dedup: target = torch.unique_consecutive(target) @@ -126,10 +124,12 @@ def set_epoch(self, epoch): self.chunk_size = self.chunk_init + epoch * self.chunk_incr if self.chunk_bound > 0: self.chunk_size = min(self.chunk_size, self.chunk_bound) - logger.info(( - f"{self.split}: setting chunk size " - f"from {old} to {self.chunk_size}" - )) + logger.info( + ( + f"{self.split}: setting chunk size " + f"from {old} to {self.chunk_size}" + ) + ) class FrmTextToSpeechDatasetCreator(TextToSpeechDatasetCreator): @@ -152,7 +152,7 @@ def from_tsv( chunk_incr: int = 5, add_eos: bool = True, dedup: bool = True, - ref_fpu: float = -1 + ref_fpu: float = -1, ) -> FrmTextToSpeechDataset: tsv_path = op.join(root, f"{split}.tsv") if not op.isfile(tsv_path): @@ -170,9 +170,7 @@ def from_tsv( assert len(s) > 0 ids = [ss[cls.KEY_ID] for ss in s] - audio_paths = [ - op.join(data_cfg.audio_root, ss[cls.KEY_AUDIO]) for ss in s - ] + audio_paths = [op.join(data_cfg.audio_root, ss[cls.KEY_AUDIO]) for ss in s] n_frames = [int(ss[cls.KEY_N_FRAMES]) for ss in s] tgt_texts = [ss[cls.KEY_TGT_TEXT] for ss in s] src_texts = [ss.get(cls.KEY_SRC_TEXT, cls.DEFAULT_SRC_TEXT) for ss in s] @@ -203,5 +201,5 @@ def from_tsv( chunk_incr=chunk_incr, add_eos=add_eos, dedup=dedup, - ref_fpu=ref_fpu + ref_fpu=ref_fpu, ) diff --git a/fairseq/data/audio/hubert_dataset.py b/fairseq/data/audio/hubert_dataset.py index f00fe301a6..1c0267bbc0 100644 --- a/fairseq/data/audio/hubert_dataset.py +++ b/fairseq/data/audio/hubert_dataset.py @@ -152,10 +152,7 @@ def __init__( self.label_offsets_list = [ load_label_offset(p, inds, tot) for p in label_paths ] - assert ( - label_processors is None - or len(label_processors) == self.num_labels - ) + assert label_processors is None or len(label_processors) == self.num_labels for label_path, label_rate in zip(label_paths, self.label_rates): verify_label_lengths( self.sizes, sample_rate, label_path, label_rate, inds, tot @@ -234,8 +231,7 @@ def collater(self, samples): ) targets_by_label = [ - [s["label_list"][i] for s in samples] - for i in range(self.num_labels) + [s["label_list"][i] for s in samples] for i in range(self.num_labels) ] targets_list, lengths_list, ntokens_list = self.collater_label( targets_by_label, audio_size, audio_starts @@ -270,9 +266,7 @@ def collater_audio(self, audios, audio_size): collated_audios[i] = audio elif diff < 0: assert self.pad_audio - collated_audios[i] = torch.cat( - [audio, audio.new_full((-diff,), 0.0)] - ) + collated_audios[i] = torch.cat([audio, audio.new_full((-diff,), 0.0)]) padding_mask[i, diff:] = True else: collated_audios[i], audio_starts[i] = self.crop_to_max_size( @@ -280,9 +274,7 @@ def collater_audio(self, audios, audio_size): ) return collated_audios, padding_mask, audio_starts - def collater_frm_label( - self, targets, audio_size, audio_starts, label_rate, pad - ): + def collater_frm_label(self, targets, audio_size, audio_starts, label_rate, pad): assert label_rate > 0 s2f = label_rate / self.sample_rate frm_starts = [int(round(s * s2f)) for s in audio_starts] @@ -290,24 +282,20 @@ def collater_frm_label( if not self.pad_audio: rem_size = [len(t) - s for t, s in zip(targets, frm_starts)] frm_size = min(frm_size, *rem_size) - targets = [t[s: s + frm_size] for t, s in zip(targets, frm_starts)] + targets = [t[s : s + frm_size] for t, s in zip(targets, frm_starts)] logger.debug(f"audio_starts={audio_starts}") logger.debug(f"frame_starts={frm_starts}") logger.debug(f"frame_size={frm_size}") lengths = torch.LongTensor([len(t) for t in targets]) ntokens = lengths.sum().item() - targets = data_utils.collate_tokens( - targets, pad_idx=pad, left_pad=False - ) + targets = data_utils.collate_tokens(targets, pad_idx=pad, left_pad=False) return targets, lengths, ntokens def collater_seq_label(self, targets, pad): lengths = torch.LongTensor([len(t) for t in targets]) ntokens = lengths.sum().item() - targets = data_utils.collate_tokens( - targets, pad_idx=pad, left_pad=False - ) + targets = data_utils.collate_tokens(targets, pad_idx=pad, left_pad=False) return targets, lengths, ntokens def collater_label(self, targets_by_label, audio_size, audio_starts): @@ -315,9 +303,7 @@ def collater_label(self, targets_by_label, audio_size, audio_starts): itr = zip(targets_by_label, self.label_rates, self.pad_list) for targets, label_rate, pad in itr: if label_rate == -1: - targets, lengths, ntokens = self.collater_seq_label( - targets, pad - ) + targets, lengths, ntokens = self.collater_seq_label(targets, pad) else: targets, lengths, ntokens = self.collater_frm_label( targets, audio_size, audio_starts, label_rate, pad diff --git a/fairseq/data/audio/multi_modality_dataset.py b/fairseq/data/audio/multi_modality_dataset.py index 69d23d31c1..625a16ec94 100644 --- a/fairseq/data/audio/multi_modality_dataset.py +++ b/fairseq/data/audio/multi_modality_dataset.py @@ -29,6 +29,7 @@ class ModalityDatasetItem(NamedTuple): max_tokens: Optional[int] = None max_sentences: Optional[int] = None + # MultiModalityDataset: it concate multiple datasets with different modalities. # Compared with ConcatDataset it can 1) sample data given the ratios for different datasets # 2) it adds mode to indicate what type of the data samples come from. diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index f4e965493c..181e2bbc9a 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -308,6 +308,7 @@ def __init__( def __getitem__(self, index): import soundfile as sf + fn = self.fnames[index] fn = fn if isinstance(self.fnames, list) else fn.as_py() fn = self.text_compressor.decompress(fn) diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index 164bf413e4..b6dfd9ae2d 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -45,7 +45,11 @@ def get_features_from_npy_or_audio(path): def get_features_or_waveform_from_stored_zip( - path, byte_offset, byte_size, need_waveform=False, use_sample_rate=None, + path, + byte_offset, + byte_size, + need_waveform=False, + use_sample_rate=None, ): assert path.endswith(".zip") data = read_from_stored_zip(path, byte_offset, byte_size) @@ -53,18 +57,17 @@ def get_features_or_waveform_from_stored_zip( if is_npy_data(data): features_or_waveform = np.load(f) elif is_sf_audio_data(data): - features_or_waveform = \ - get_waveform( - f, always_2d=False, output_sample_rate=use_sample_rate - )[0] if need_waveform else get_fbank(f) + features_or_waveform = ( + get_waveform(f, always_2d=False, output_sample_rate=use_sample_rate)[0] + if need_waveform + else get_fbank(f) + ) else: raise ValueError(f'Unknown file format for "{path}"') return features_or_waveform -def get_features_or_waveform( - path: str, need_waveform=False, use_sample_rate=None -): +def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=None): """Get speech features from .npy file or waveform from .wav/.flac file. The file may be inside an uncompressed ZIP file and is accessed via byte offset and length. @@ -87,8 +90,11 @@ def get_features_or_waveform( return get_features_from_npy_or_audio(_path) elif len(slice_ptr) == 2: features_or_waveform = get_features_or_waveform_from_stored_zip( - _path, slice_ptr[0], slice_ptr[1], need_waveform=need_waveform, - use_sample_rate=use_sample_rate + _path, + slice_ptr[0], + slice_ptr[1], + need_waveform=need_waveform, + use_sample_rate=use_sample_rate, ) else: raise ValueError(f"Invalid path: {path}") @@ -145,7 +151,7 @@ def __init__( pre_tokenizer=None, bpe_tokenizer=None, n_frames_per_step=1, - speaker_to_id=None + speaker_to_id=None, ): self.split, self.is_train_split = split, is_train_split self.cfg = cfg @@ -235,7 +241,7 @@ def pack_frames(self, feature: torch.Tensor): if self.n_frames_per_step == 1: return feature n_packed_frames = feature.shape[0] // self.n_frames_per_step - feature = feature[:self.n_frames_per_step * n_packed_frames] + feature = feature[: self.n_frames_per_step * n_packed_frames] return feature.reshape(n_packed_frames, -1) @classmethod @@ -318,9 +324,11 @@ def collater( speaker = None if self.speaker_to_id is not None: - speaker = torch.tensor( - [s.speaker_id for s in samples], dtype=torch.long - ).index_select(0, order).view(-1, 1) + speaker = ( + torch.tensor([s.speaker_id for s in samples], dtype=torch.long) + .index_select(0, order) + .view(-1, 1) + ) net_input = { "src_tokens": frames, @@ -388,7 +396,7 @@ def _from_list( pre_tokenizer, bpe_tokenizer, n_frames_per_step, - speaker_to_id + speaker_to_id, ) -> SpeechToTextDataset: audio_root = Path(cfg.audio_root) ids = [s[cls.KEY_ID] for s in samples] @@ -415,7 +423,7 @@ def _from_list( pre_tokenizer=pre_tokenizer, bpe_tokenizer=bpe_tokenizer, n_frames_per_step=n_frames_per_step, - speaker_to_id=speaker_to_id + speaker_to_id=speaker_to_id, ) @classmethod @@ -481,12 +489,19 @@ def _from_tsv( pre_tokenizer, bpe_tokenizer, n_frames_per_step, - speaker_to_id + speaker_to_id, ) -> SpeechToTextDataset: samples = cls._load_samples_from_tsv(root, split) return cls._from_list( - split, is_train_split, samples, cfg, tgt_dict, pre_tokenizer, - bpe_tokenizer, n_frames_per_step, speaker_to_id + split, + is_train_split, + samples, + cfg, + tgt_dict, + pre_tokenizer, + bpe_tokenizer, + n_frames_per_step, + speaker_to_id, ) @classmethod @@ -502,12 +517,19 @@ def from_tsv( epoch: int, seed: int, n_frames_per_step: int = 1, - speaker_to_id=None + speaker_to_id=None, ) -> SpeechToTextDataset: datasets = [ cls._from_tsv( - root, cfg, split, tgt_dict, is_train_split, pre_tokenizer, - bpe_tokenizer, n_frames_per_step, speaker_to_id + root, + cfg, + split, + tgt_dict, + is_train_split, + pre_tokenizer, + bpe_tokenizer, + n_frames_per_step, + speaker_to_id, ) for split in splits.split(",") ] diff --git a/fairseq/data/audio/text_to_speech_dataset.py b/fairseq/data/audio/text_to_speech_dataset.py index abfcb2be40..0e1489ae83 100644 --- a/fairseq/data/audio/text_to_speech_dataset.py +++ b/fairseq/data/audio/text_to_speech_dataset.py @@ -13,8 +13,11 @@ import torch from fairseq.data.audio.speech_to_text_dataset import ( - SpeechToTextDataset, SpeechToTextDatasetCreator, S2TDataConfig, - _collate_frames, get_features_or_waveform + SpeechToTextDataset, + SpeechToTextDatasetCreator, + S2TDataConfig, + _collate_frames, + get_features_or_waveform, ) from fairseq.data import Dictionary, data_utils as fairseq_data_utils @@ -32,34 +35,44 @@ class TextToSpeechDatasetItem(object): class TextToSpeechDataset(SpeechToTextDataset): def __init__( - self, - split: str, - is_train_split: bool, - cfg: S2TDataConfig, - audio_paths: List[str], - n_frames: List[int], - src_texts: Optional[List[str]] = None, - tgt_texts: Optional[List[str]] = None, - speakers: Optional[List[str]] = None, - src_langs: Optional[List[str]] = None, - tgt_langs: Optional[List[str]] = None, - ids: Optional[List[str]] = None, - tgt_dict: Optional[Dictionary] = None, - pre_tokenizer=None, - bpe_tokenizer=None, - n_frames_per_step=1, - speaker_to_id=None, - durations: Optional[List[List[int]]] = None, - pitches: Optional[List[str]] = None, - energies: Optional[List[str]] = None + self, + split: str, + is_train_split: bool, + cfg: S2TDataConfig, + audio_paths: List[str], + n_frames: List[int], + src_texts: Optional[List[str]] = None, + tgt_texts: Optional[List[str]] = None, + speakers: Optional[List[str]] = None, + src_langs: Optional[List[str]] = None, + tgt_langs: Optional[List[str]] = None, + ids: Optional[List[str]] = None, + tgt_dict: Optional[Dictionary] = None, + pre_tokenizer=None, + bpe_tokenizer=None, + n_frames_per_step=1, + speaker_to_id=None, + durations: Optional[List[List[int]]] = None, + pitches: Optional[List[str]] = None, + energies: Optional[List[str]] = None, ): super(TextToSpeechDataset, self).__init__( - split, is_train_split, cfg, audio_paths, n_frames, - src_texts=src_texts, tgt_texts=tgt_texts, speakers=speakers, - src_langs=src_langs, tgt_langs=tgt_langs, ids=ids, - tgt_dict=tgt_dict, pre_tokenizer=pre_tokenizer, - bpe_tokenizer=bpe_tokenizer, n_frames_per_step=n_frames_per_step, - speaker_to_id=speaker_to_id + split, + is_train_split, + cfg, + audio_paths, + n_frames, + src_texts=src_texts, + tgt_texts=tgt_texts, + speakers=speakers, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + tgt_dict=tgt_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + n_frames_per_step=n_frames_per_step, + speaker_to_id=speaker_to_id, ) self.durations = durations self.pitches = pitches @@ -84,9 +97,13 @@ def __getitem__(self, index: int) -> TextToSpeechDatasetItem: np.concatenate((energy, [0])) # pad 0 for EOS ).float() return TextToSpeechDatasetItem( - index=index, source=s2t_item.source, target=s2t_item.target, - speaker_id=s2t_item.speaker_id, duration=duration, pitch=pitch, - energy=energy + index=index, + source=s2t_item.source, + target=s2t_item.target, + speaker_id=s2t_item.speaker_id, + duration=duration, + pitch=pitch, + energy=energy, ) def collater(self, samples: List[TextToSpeechDatasetItem]) -> Dict[str, Any]: @@ -96,8 +113,9 @@ def collater(self, samples: List[TextToSpeechDatasetItem]) -> Dict[str, Any]: src_lengths, order = torch.tensor( [s.target.shape[0] for s in samples], dtype=torch.long ).sort(descending=True) - id_ = torch.tensor([s.index for s in samples], - dtype=torch.long).index_select(0, order) + id_ = torch.tensor([s.index for s in samples], dtype=torch.long).index_select( + 0, order + ) feat = _collate_frames( [s.source for s in samples], self.cfg.use_audio_input ).index_select(0, order) @@ -115,9 +133,11 @@ def collater(self, samples: List[TextToSpeechDatasetItem]) -> Dict[str, Any]: speaker = None if self.speaker_to_id is not None: - speaker = torch.tensor( - [s.speaker_id for s in samples], dtype=torch.long - ).index_select(0, order).view(-1, 1) + speaker = ( + torch.tensor([s.speaker_id for s in samples], dtype=torch.long) + .index_select(0, order) + .view(-1, 1) + ) bsz, _, d = feat.size() prev_output_tokens = torch.cat( @@ -175,7 +195,7 @@ def _from_list( pre_tokenizer, bpe_tokenizer, n_frames_per_step, - speaker_to_id + speaker_to_id, ) -> TextToSpeechDataset: audio_root = Path(cfg.audio_root) ids = [s[cls.KEY_ID] for s in samples] @@ -189,27 +209,40 @@ def _from_list( durations = [s.get(cls.KEY_DURATION, None) for s in samples] durations = [ - None if dd is None else [int(d) for d in dd.split(" ")] - for dd in durations + None if dd is None else [int(d) for d in dd.split(" ")] for dd in durations ] durations = None if any(dd is None for dd in durations) else durations pitches = [s.get(cls.KEY_PITCH, None) for s in samples] pitches = [ - None if pp is None else (audio_root / pp).as_posix() - for pp in pitches + None if pp is None else (audio_root / pp).as_posix() for pp in pitches ] pitches = None if any(pp is None for pp in pitches) else pitches energies = [s.get(cls.KEY_ENERGY, None) for s in samples] energies = [ - None if ee is None else (audio_root / ee).as_posix() - for ee in energies] + None if ee is None else (audio_root / ee).as_posix() for ee in energies + ] energies = None if any(ee is None for ee in energies) else energies return TextToSpeechDataset( - split_name, is_train_split, cfg, audio_paths, n_frames, - src_texts, tgt_texts, speakers, src_langs, tgt_langs, ids, tgt_dict, - pre_tokenizer, bpe_tokenizer, n_frames_per_step, speaker_to_id, - durations, pitches, energies + split_name, + is_train_split, + cfg, + audio_paths, + n_frames, + src_texts, + tgt_texts, + speakers, + src_langs, + tgt_langs, + ids, + tgt_dict, + pre_tokenizer, + bpe_tokenizer, + n_frames_per_step, + speaker_to_id, + durations, + pitches, + energies, ) diff --git a/fairseq/data/colorize_dataset.py b/fairseq/data/colorize_dataset.py index 6ef097bff1..7a6d271379 100644 --- a/fairseq/data/colorize_dataset.py +++ b/fairseq/data/colorize_dataset.py @@ -9,7 +9,7 @@ class ColorizeDataset(BaseWrapperDataset): - """ Adds 'colors' property to net input that is obtained from the provided color getter for use by models """ + """Adds 'colors' property to net input that is obtained from the provided color getter for use by models""" def __init__(self, dataset, color_getter): super().__init__(dataset) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index b3de57681e..7914e6055b 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -69,6 +69,7 @@ def copy_tensor(src, dst): copy_tensor(v, res[i][size - len(v) :] if left_pad else res[i][: len(v)]) return res + def load_indexed_dataset( path, dictionary=None, dataset_impl=None, combine=False, default="cached" ): @@ -324,9 +325,7 @@ def batch_by_size( ) # added int() to avoid TypeError: an integer is required - max_tokens = ( - int(max_tokens) if max_tokens is not None else -1 - ) + max_tokens = int(max_tokens) if max_tokens is not None else -1 max_sentences = max_sentences if max_sentences is not None else -1 bsz_mult = required_batch_size_multiple @@ -375,8 +374,9 @@ def post_process(sentence: str, symbol: str): sentence = sentence.replace(" ", "").replace("|", " ").strip() elif symbol == "silence": import re + sentence = sentence.replace("<SIL>", "") - sentence = re.sub(' +', ' ', sentence).strip() + sentence = re.sub(" +", " ", sentence).strip() elif symbol == "_EOW": sentence = sentence.replace(" ", "").replace("_EOW", " ").strip() elif symbol in {"subword_nmt", "@@ ", "@@"}: @@ -547,7 +547,7 @@ def get_buckets(sizes, num_buckets): np.percentile( sizes, np.linspace(0, 100, num_buckets + 1), - interpolation='lower', + interpolation="lower", )[1:] ) return buckets @@ -564,7 +564,6 @@ def get_bucketed_sizes(orig_sizes, buckets): return sizes - def _find_extra_valid_paths(dataset_path: str) -> set: paths = utils.split_paths(dataset_path) all_valid_paths = set() diff --git a/fairseq/data/encoders/sentencepiece_bpe.py b/fairseq/data/encoders/sentencepiece_bpe.py index fc830f6e0d..0aa6cd7681 100644 --- a/fairseq/data/encoders/sentencepiece_bpe.py +++ b/fairseq/data/encoders/sentencepiece_bpe.py @@ -21,8 +21,10 @@ class SentencepieceConfig(FairseqDataclass): ) sentencepiece_alpha: Optional[float] = field( default=None, - metadata={"help": "soothing parameter for unigram sampling, " - "and merge probability for BPE-dropout"} + metadata={ + "help": "soothing parameter for unigram sampling, " + "and merge probability for BPE-dropout" + }, ) @@ -45,8 +47,7 @@ def __init__(self, cfg): def encode(self, x: str) -> str: return " ".join( self.sp.Encode( - x, out_type=str, enable_sampling=self.enable_sampling, - alpha=self.alpha + x, out_type=str, enable_sampling=self.enable_sampling, alpha=self.alpha ) ) diff --git a/fairseq/data/fairseq_dataset.py b/fairseq/data/fairseq_dataset.py index 23e6992dba..2bde7fc57b 100644 --- a/fairseq/data/fairseq_dataset.py +++ b/fairseq/data/fairseq_dataset.py @@ -138,7 +138,7 @@ def adjust_bsz(bsz, num_tokens): ) try: - num_tokens_vec = self.num_tokens_vec(indices).astype('int64') + num_tokens_vec = self.num_tokens_vec(indices).astype("int64") except NotImplementedError: num_tokens_vec = None diff --git a/fairseq/data/huffman/huffman_coder.py b/fairseq/data/huffman/huffman_coder.py index 6531f1547c..c04f84564e 100644 --- a/fairseq/data/huffman/huffman_coder.py +++ b/fairseq/data/huffman/huffman_coder.py @@ -140,7 +140,9 @@ class HuffmanNode: def is_leaf(self) -> bool: return self.left is None and self.right is None - def code_table(self, prefix: tp.Optional[bitarray] = None) -> tp.Dict[str, "HuffmanNode"]: + def code_table( + self, prefix: tp.Optional[bitarray] = None + ) -> tp.Dict[str, "HuffmanNode"]: defaulted_prefix = prefix if prefix is not None else bitarray() if self.is_leaf(): self.code = ( diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index 23afb43356..d0843926ae 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -67,7 +67,9 @@ def make_builder(out_file, impl, vocab_size=None): elif impl == "fasta": raise NotImplementedError elif impl == "huffman": - raise ValueError("Use HuffmanCodeBuilder directly as it has a different interface.") + raise ValueError( + "Use HuffmanCodeBuilder directly as it has a different interface." + ) else: return IndexedDatasetBuilder(out_file) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 81b5f56547..e16d91ef72 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -380,7 +380,9 @@ def next_epoch_itr( # reset _frozen_batches to refresh the next epoch self._frozen_batches = None self._cur_epoch_itr = self._get_iterator_for_epoch( - self.epoch, shuffle, fix_batches_to_gpus=fix_batches_to_gpus, + self.epoch, + shuffle, + fix_batches_to_gpus=fix_batches_to_gpus, ) self.shuffle = shuffle return self._cur_epoch_itr @@ -421,7 +423,9 @@ def load_state_dict(self, state_dict): if itr_pos > 0: # fast-forward epoch iterator self._next_epoch_itr = self._get_iterator_for_epoch( - self.epoch, shuffle=state_dict.get("shuffle", True), offset=itr_pos, + self.epoch, + shuffle=state_dict.get("shuffle", True), + offset=itr_pos, ) if self._next_epoch_itr is None: if version == 1: diff --git a/fairseq/data/language_pair_dataset.py b/fairseq/data/language_pair_dataset.py index ff3e14bf14..fd356ddd04 100644 --- a/fairseq/data/language_pair_dataset.py +++ b/fairseq/data/language_pair_dataset.py @@ -114,7 +114,10 @@ def compute_alignment_weights(alignments): "id": id, "nsentences": len(samples), "ntokens": ntokens, - "net_input": {"src_tokens": src_tokens, "src_lengths": src_lengths,}, + "net_input": { + "src_tokens": src_tokens, + "src_lengths": src_lengths, + }, "target": target, } if prev_output_tokens is not None: @@ -467,5 +470,8 @@ def filter_indices_by_size(self, indices, max_sizes): list: list of removed indices """ return data_utils.filter_paired_dataset_indices_by_size( - self.src_sizes, self.tgt_sizes, indices, max_sizes, + self.src_sizes, + self.tgt_sizes, + indices, + max_sizes, ) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index 1566d8e0cd..a3f47c720d 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -80,7 +80,9 @@ def __init__( def ordered_indices(self): start = time.time() with data_utils.numpy_seed(self.seed, self.epoch): - logger.info(f"sampling new dataset with seed {self.seed} epoch {self.epoch}") + logger.info( + f"sampling new dataset with seed {self.seed} epoch {self.epoch}" + ) sampled_indices = [] num_selected_instances = 0 diff --git a/fairseq/data/multilingual/multilingual_data_manager.py b/fairseq/data/multilingual/multilingual_data_manager.py index 137481b449..8dae99d99f 100644 --- a/fairseq/data/multilingual/multilingual_data_manager.py +++ b/fairseq/data/multilingual/multilingual_data_manager.py @@ -40,8 +40,8 @@ logger = logging.getLogger(__name__) -SRC_DICT_NAME = 'src' -TGT_DICT_NAME = 'tgt' +SRC_DICT_NAME = "src" +TGT_DICT_NAME = "tgt" def _lang_id(dic: Dictionary, lang: str): @@ -64,14 +64,16 @@ def __init__(self, args, lang_pairs, langs, dicts, sampling_method): self.seed = args.seed self.lang_pairs = lang_pairs self.extra_lang_pairs = ( - list( - {p for _, v in args.extra_lang_pairs.items() for p in v.split(",")} - ) - if args.extra_lang_pairs - else [] - ) - self.src_langs = {p.split("-")[0] for p in args.lang_pairs + self.extra_lang_pairs} - self.tgt_langs = {p.split("-")[1] for p in args.lang_pairs + self.extra_lang_pairs} + list({p for _, v in args.extra_lang_pairs.items() for p in v.split(",")}) + if args.extra_lang_pairs + else [] + ) + self.src_langs = { + p.split("-")[0] for p in args.lang_pairs + self.extra_lang_pairs + } + self.tgt_langs = { + p.split("-")[1] for p in args.lang_pairs + self.extra_lang_pairs + } self.langs = langs self.dicts = dicts self.lang_dict = self.create_lang_dictionary(self.langs) @@ -111,10 +113,18 @@ def add_args(parser): "note that the ordering determines language token IDs; " "--langs and --lang-dict are two exclusive options", ) - parser.add_argument('--source-dict', default=None, type=str, - help='path to source dictionary; if specified it will override per language dictionary loading') - parser.add_argument('--target-dict', default=None, type=str, - help='path to target dictionary; if specified it will override per language dictionary loading') + parser.add_argument( + "--source-dict", + default=None, + type=str, + help="path to source dictionary; if specified it will override per language dictionary loading", + ) + parser.add_argument( + "--target-dict", + default=None, + type=str, + help="path to target dictionary; if specified it will override per language dictionary loading", + ) parser.add_argument( "--lang-tok-style", default=LangTokStyle.multilingual.value, @@ -378,7 +388,9 @@ def load_dictionary_and_postproc(path): ) return d - dicts = cls.load_all_dictionaries(args, language_list, load_dictionary_and_postproc, training) + dicts = cls.load_all_dictionaries( + args, language_list, load_dictionary_and_postproc, training + ) return language_list, dicts, training @classmethod @@ -424,7 +436,10 @@ def load_dicts(langs_to_load_dicts): if args.fixed_dictionary is not None: fixed_dict = load_dictionary(args.fixed_dictionary) - dicts = {lang: fixed_dict for lang in src_langs_to_load_dicts + tgt_langs_to_load_dicts} + dicts = { + lang: fixed_dict + for lang in src_langs_to_load_dicts + tgt_langs_to_load_dicts + } else: if args.source_dict is None: load_dicts(src_langs_to_load_dicts) @@ -477,7 +492,10 @@ def get_encoder_langtok(self, src_lang, tgt_lang, spec=None): lang=tgt_lang, lang_tok_style=self.args.lang_tok_style, spec=spec ) return self.get_langtok_index( - langtok, self.get_source_dictionary(src_lang) if src_lang else self.get_target_dictionary(tgt_lang) + langtok, + self.get_source_dictionary(src_lang) + if src_lang + else self.get_target_dictionary(tgt_lang), ) def get_decoder_langtok(self, tgt_lang, spec=None): @@ -819,7 +837,9 @@ def load_a_dataset( if self.args.lang_tok_replacing_bos_eos: ds = self.alter_dataset_langtok( langpair_ds, - src_eos=self.get_source_dictionary(src).eos() if src else self.get_target_dictionary(tgt).eos(), + src_eos=self.get_source_dictionary(src).eos() + if src + else self.get_target_dictionary(tgt).eos(), src_lang=src, tgt_eos=self.get_target_dictionary(tgt).eos(), tgt_lang=tgt, diff --git a/fairseq/data/noising.py b/fairseq/data/noising.py index 2b1cc34720..e92e83c2cd 100644 --- a/fairseq/data/noising.py +++ b/fairseq/data/noising.py @@ -298,7 +298,6 @@ def __init__( ) self.sizes = src_dataset.sizes - def __getitem__(self, index): """ Returns a single noisy sample. Multiple samples are fed to the collater diff --git a/fairseq/data/text_compressor.py b/fairseq/data/text_compressor.py index 561e9ac89a..8a4e8daa35 100644 --- a/fairseq/data/text_compressor.py +++ b/fairseq/data/text_compressor.py @@ -14,8 +14,7 @@ class TextCompressionLevel(Enum): class TextCompressor(object): def __init__( - self, level: TextCompressionLevel, - max_input_byte_length: int = 2 ** 16 + self, level: TextCompressionLevel, max_input_byte_length: int = 2 ** 16 ): self.level = level self.max_input_length = max_input_byte_length @@ -23,11 +22,13 @@ def __init__( def compress(self, text: str) -> bytes: if self.level == TextCompressionLevel.low: import zlib + # zlib: built-in, fast return zlib.compress(text.encode(), level=0) elif self.level == TextCompressionLevel.high: try: import unishox2 + # unishox2: optimized for short text but slower except ImportError: raise ImportError( @@ -42,6 +43,7 @@ def compress(self, text: str) -> bytes: def decompress(self, compressed: bytes) -> str: if self.level == TextCompressionLevel.low: import zlib + return zlib.decompress(compressed).decode() elif self.level == TextCompressionLevel.high: try: diff --git a/fairseq/data/token_block_dataset.py b/fairseq/data/token_block_dataset.py index d2c65fd7e0..a414e7ef64 100644 --- a/fairseq/data/token_block_dataset.py +++ b/fairseq/data/token_block_dataset.py @@ -69,7 +69,10 @@ def __init__( _sizes, split_path, (plasma_id, 1), plasma_path=plasma_path ) self._block_to_dataset_index = plasma_utils.PlasmaView( - block_to_dataset_index, split_path, (plasma_id, 2), plasma_path=plasma_path, + block_to_dataset_index, + split_path, + (plasma_id, 2), + plasma_path=plasma_path, ) else: self._slice_indices = plasma_utils.PlasmaArray(slice_indices) @@ -127,7 +130,8 @@ def _build_slice_indices( ) else: block_to_dataset_index = _get_block_to_dataset_index_fast( - sizes, slice_indices, + sizes, + slice_indices, ) size_dtype = np.uint16 if block_size < 65535 else np.uint32 num_tokens = slice_indices[-1].max() diff --git a/fairseq/data/transform_eos_lang_pair_dataset.py b/fairseq/data/transform_eos_lang_pair_dataset.py index e21144a88e..d8b2109014 100644 --- a/fairseq/data/transform_eos_lang_pair_dataset.py +++ b/fairseq/data/transform_eos_lang_pair_dataset.py @@ -52,7 +52,7 @@ def collater(self, samples, **extra_args): if len(samples) == 0: return samples - if 'net_input' not in samples: + if "net_input" not in samples: return samples if self.new_src_eos is not None: diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index b081e6cabf..b6150ea3f7 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -126,7 +126,8 @@ class CommonConfig(FairseqDataclass): metadata={"help": "Weights and Biases project name to use for logging"}, ) azureml_logging: Optional[bool] = field( - default=False, metadata={"help": "Log scalars to AzureML context"}, + default=False, + metadata={"help": "Log scalars to AzureML context"}, ) seed: int = field( default=1, metadata={"help": "pseudo random number generator seed"} @@ -428,19 +429,23 @@ class DistributedTrainingConfig(FairseqDataclass): tpu: bool = II("common.tpu") # configuration for --ddp-backend=fully_sharded no_reshard_after_forward: bool = field( - default=False, metadata={"help": "don't reshard parameters after forward pass"}, + default=False, + metadata={"help": "don't reshard parameters after forward pass"}, ) fp32_reduce_scatter: bool = field( - default=False, metadata={"help": "reduce-scatter grads in FP32"}, + default=False, + metadata={"help": "reduce-scatter grads in FP32"}, ) cpu_offload: bool = field( default=False, metadata={"help": "offload FP32 params to CPU"} ) use_sharded_state: bool = field( - default=False, metadata={"help": "use sharded checkpoint files"}, + default=False, + metadata={"help": "use sharded checkpoint files"}, ) not_fsdp_flatten_parameters: bool = field( - default=False, metadata={"help": "not flatten parameter param for fsdp"}, + default=False, + metadata={"help": "not flatten parameter param for fsdp"}, ) @@ -786,10 +791,12 @@ class FairseqBMUFConfig(FairseqDataclass): @dataclass class GenerationConfig(FairseqDataclass): beam: int = field( - default=5, metadata={"help": "beam size"}, + default=5, + metadata={"help": "beam size"}, ) nbest: int = field( - default=1, metadata={"help": "number of hypotheses to output"}, + default=1, + metadata={"help": "number of hypotheses to output"}, ) max_len_a: float = field( default=0, @@ -804,19 +811,24 @@ class GenerationConfig(FairseqDataclass): }, ) min_len: int = field( - default=1, metadata={"help": "minimum generation length"}, + default=1, + metadata={"help": "minimum generation length"}, ) match_source_len: bool = field( - default=False, metadata={"help": "generations should match the source length"}, + default=False, + metadata={"help": "generations should match the source length"}, ) unnormalized: bool = field( - default=False, metadata={"help": "compare unnormalized hypothesis scores"}, + default=False, + metadata={"help": "compare unnormalized hypothesis scores"}, ) no_early_stop: bool = field( - default=False, metadata={"help": "deprecated"}, + default=False, + metadata={"help": "deprecated"}, ) no_beamable_mm: bool = field( - default=False, metadata={"help": "don't use BeamableMM in attention layers"}, + default=False, + metadata={"help": "don't use BeamableMM in attention layers"}, ) lenpen: float = field( default=1, @@ -838,10 +850,12 @@ class GenerationConfig(FairseqDataclass): }, ) sacrebleu: bool = field( - default=False, metadata={"help": "score with sacrebleu"}, + default=False, + metadata={"help": "score with sacrebleu"}, ) score_reference: bool = field( - default=False, metadata={"help": "just score the reference translation"}, + default=False, + metadata={"help": "just score the reference translation"}, ) prefix_size: int = field( default=0, @@ -875,10 +889,12 @@ class GenerationConfig(FairseqDataclass): }, ) temperature: float = field( - default=1.0, metadata={"help": "temperature for generation"}, + default=1.0, + metadata={"help": "temperature for generation"}, ) diverse_beam_groups: int = field( - default=-1, metadata={"help": "number of groups for Diverse Beam Search"}, + default=-1, + metadata={"help": "number of groups for Diverse Beam Search"}, ) diverse_beam_strength: float = field( default=0.5, @@ -897,13 +913,16 @@ class GenerationConfig(FairseqDataclass): }, ) print_step: bool = field( - default=False, metadata={"help": "print steps"}, + default=False, + metadata={"help": "print steps"}, ) lm_path: Optional[str] = field( - default=None, metadata={"help": "path to lm checkpoint for lm fusion"}, + default=None, + metadata={"help": "path to lm checkpoint for lm fusion"}, ) lm_weight: float = field( - default=0.0, metadata={"help": "weight for lm probs for lm fusion"}, + default=0.0, + metadata={"help": "weight for lm probs for lm fusion"}, ) # arguments for iterative refinement generator @@ -912,7 +931,8 @@ class GenerationConfig(FairseqDataclass): metadata={"help": "if > 0.0, it penalized early-stopping in decoding."}, ) iter_decode_max_iter: int = field( - default=10, metadata={"help": "maximum iterations for iterative refinement."}, + default=10, + metadata={"help": "maximum iterations for iterative refinement."}, ) iter_decode_force_max_iter: bool = field( default=False, @@ -939,7 +959,8 @@ class GenerationConfig(FairseqDataclass): }, ) retain_dropout: bool = field( - default=False, metadata={"help": "Use dropout at inference time"}, + default=False, + metadata={"help": "Use dropout at inference time"}, ) # temporarily set to Any until https://github.com/facebookresearch/hydra/issues/1117 is fixed # retain_dropout_modules: Optional[List[str]] = field( @@ -964,7 +985,8 @@ class GenerationConfig(FairseqDataclass): @dataclass class CommonEvalConfig(FairseqDataclass): path: Optional[str] = field( - default=None, metadata={"help": "path(s) to model file(s), colon separated"}, + default=None, + metadata={"help": "path(s) to model file(s), colon separated"}, ) post_process: Optional[str] = field( default=None, @@ -1026,7 +1048,8 @@ class InteractiveConfig(FairseqDataclass): }, ) input: str = field( - default="-", metadata={"help": "file to read from; use - for stdin"}, + default="-", + metadata={"help": "file to read from; use - for stdin"}, ) diff --git a/fairseq/dataclass/constants.py b/fairseq/dataclass/constants.py index 7e5aef7067..5af92f2b3a 100644 --- a/fairseq/dataclass/constants.py +++ b/fairseq/dataclass/constants.py @@ -35,14 +35,16 @@ def ChoiceEnum(choices: List[str]): LOG_FORMAT_CHOICES = ChoiceEnum(["json", "none", "simple", "tqdm"]) -DDP_BACKEND_CHOICES = ChoiceEnum([ - "c10d", # alias for pytorch_ddp - "fully_sharded", # FullyShardedDataParallel from fairscale - "legacy_ddp", - "no_c10d", # alias for legacy_ddp - "pytorch_ddp", - "slowmo", -]) +DDP_BACKEND_CHOICES = ChoiceEnum( + [ + "c10d", # alias for pytorch_ddp + "fully_sharded", # FullyShardedDataParallel from fairscale + "legacy_ddp", + "no_c10d", # alias for legacy_ddp + "pytorch_ddp", + "slowmo", + ] +) DDP_COMM_HOOK_CHOICES = ChoiceEnum(["none", "fp16"]) DATASET_IMPL_CHOICES = ChoiceEnum(["raw", "lazy", "cached", "mmap", "fasta", "huffman"]) GENERATION_CONSTRAINTS_CHOICES = ChoiceEnum(["ordered", "unordered"]) diff --git a/fairseq/dataclass/initialize.py b/fairseq/dataclass/initialize.py index 8f6cbafb80..5a7784bad1 100644 --- a/fairseq/dataclass/initialize.py +++ b/fairseq/dataclass/initialize.py @@ -28,7 +28,7 @@ def hydra_init(cfg_name="config") -> None: def add_defaults(cfg: DictConfig) -> None: - """This function adds default values that are stored in dataclasses that hydra doesn't know about """ + """This function adds default values that are stored in dataclasses that hydra doesn't know about""" from fairseq.registry import REGISTRIES from fairseq.tasks import TASK_DATACLASS_REGISTRY diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 1320ec4737..b80315ddc9 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -57,21 +57,21 @@ def gen_parser_from_dataclass( with_prefix: Optional[str] = None, ) -> None: """ - convert a dataclass instance to tailing parser arguments. + convert a dataclass instance to tailing parser arguments. - If `with_prefix` is provided, prefix all the keys in the resulting parser with it. It means that we are - building a flat namespace from a structured dataclass (see transformer_config.py for example). + If `with_prefix` is provided, prefix all the keys in the resulting parser with it. It means that we are + building a flat namespace from a structured dataclass (see transformer_config.py for example). """ def argparse_name(name: str): - if name == "data" and (with_prefix is None or with_prefix == ''): + if name == "data" and (with_prefix is None or with_prefix == ""): # normally data is positional args, so we don't add the -- nor the prefix return name if name == "_name": # private member, skip return None full_name = "--" + name.replace("_", "-") - if with_prefix is not None and with_prefix != '': + if with_prefix is not None and with_prefix != "": # if a prefix is specified, construct the prefixed arg name full_name = with_prefix + "-" + full_name[2:] # strip -- when composing return full_name @@ -143,8 +143,8 @@ def get_kwargs_from_dc( kwargs["default"] = field_default # build the help with the hierarchical prefix - if with_prefix is not None and with_prefix != '' and field_help is not None: - field_help = with_prefix[2:] + ': ' + field_help + if with_prefix is not None and with_prefix != "" and field_help is not None: + field_help = with_prefix[2:] + ": " + field_help kwargs["help"] = field_help if field_const is not None: diff --git a/fairseq/distributed/__init__.py b/fairseq/distributed/__init__.py index d0b96b734c..9130db8f5d 100644 --- a/fairseq/distributed/__init__.py +++ b/fairseq/distributed/__init__.py @@ -4,7 +4,11 @@ # LICENSE file in the root directory of this source tree. from .distributed_timeout_wrapper import DistributedTimeoutWrapper -from .fully_sharded_data_parallel import fsdp_enable_wrap, fsdp_wrap, FullyShardedDataParallel +from .fully_sharded_data_parallel import ( + fsdp_enable_wrap, + fsdp_wrap, + FullyShardedDataParallel, +) from .legacy_distributed_data_parallel import LegacyDistributedDataParallel from .module_proxy_wrapper import ModuleProxyWrapper from .tpu_distributed_data_parallel import TPUDistributedDataParallel diff --git a/fairseq/distributed/distributed_timeout_wrapper.py b/fairseq/distributed/distributed_timeout_wrapper.py index 18107ef27e..6e06b4b6dd 100644 --- a/fairseq/distributed/distributed_timeout_wrapper.py +++ b/fairseq/distributed/distributed_timeout_wrapper.py @@ -33,6 +33,7 @@ class DistributedTimeoutWrapper(nn.Module): (set to a value <= 0 to disable the timeout) signal (Optional): signal to send once timeout is triggered """ + def __init__(self, module: nn.Module, timeout: int, signal=signal.SIGINT): super().__init__() self.module = module @@ -86,9 +87,11 @@ def _check_heartbeat(self, parent_pid): if self._terminated: break elif not success: - logger.error(( - "Killing job for not making progress in {} seconds. " - "Set --heartbeat-timeout=-1 to disable this timeout." - ).format(int(self.timeout))) + logger.error( + ( + "Killing job for not making progress in {} seconds. " + "Set --heartbeat-timeout=-1 to disable this timeout." + ).format(int(self.timeout)) + ) os.kill(parent_pid, self.signal) return diff --git a/fairseq/distributed/legacy_distributed_data_parallel.py b/fairseq/distributed/legacy_distributed_data_parallel.py index f2308f87c5..5f89e6c0ee 100644 --- a/fairseq/distributed/legacy_distributed_data_parallel.py +++ b/fairseq/distributed/legacy_distributed_data_parallel.py @@ -137,7 +137,7 @@ def reduction_fn(): if param.grad is None: param.grad = torch.zeros_like(param) - if hasattr(param, 'expert'): + if hasattr(param, "expert"): # Skip gradient sync for unshared parameters continue diff --git a/fairseq/distributed/module_proxy_wrapper.py b/fairseq/distributed/module_proxy_wrapper.py index fc2c6f8c71..904dc0c202 100644 --- a/fairseq/distributed/module_proxy_wrapper.py +++ b/fairseq/distributed/module_proxy_wrapper.py @@ -26,8 +26,9 @@ class ModuleProxyWrapper(nn.Module): def __init__(self, module: nn.Module): super().__init__() - assert hasattr(module, "module"), \ - "ModuleProxyWrapper expects input to wrap another module" + assert hasattr( + module, "module" + ), "ModuleProxyWrapper expects input to wrap another module" self.module = module def __getattr__(self, name): diff --git a/fairseq/distributed/tpu_distributed_data_parallel.py b/fairseq/distributed/tpu_distributed_data_parallel.py index e971cf07c5..3b9e103301 100644 --- a/fairseq/distributed/tpu_distributed_data_parallel.py +++ b/fairseq/distributed/tpu_distributed_data_parallel.py @@ -10,7 +10,6 @@ class TPUDistributedDataParallel(nn.Module): - def __init__(self, module, process_group): super().__init__() self.module = module @@ -35,9 +34,10 @@ def all_reduce_grads(self): gradients.append(p.grad) import torch_xla.core.xla_model as xm + xm.all_reduce( - 'sum', + "sum", gradients, - scale=1. / self.world_size, + scale=1.0 / self.world_size, groups=self.process_group[1], ) diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index e6459447d7..2c52f76aa7 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -201,9 +201,7 @@ def _pipeline_parallel_post_init( # distributed_world_size to be based on the total number of GPUs, so # we need to correct them to be based on the number of pipelines. assert cfg.distributed_world_size % num_pipeline_devices == 0 - cfg.distributed_world_size = ( - cfg.distributed_world_size // num_pipeline_devices - ) + cfg.distributed_world_size = cfg.distributed_world_size // num_pipeline_devices # In the case of 4-way MP on nodes with 8 GPUs, we want # distributed_rank to be the starting GPU index for each pipeline # i.e., 0, 2, ... @@ -306,8 +304,10 @@ def distributed_init(cfg: FairseqConfig): model_part_number = get_model_parallel_rank() cfg.checkpoint.checkpoint_suffix += "-model_part-{0}".format(model_part_number) - if hasattr(cfg, "model") and getattr(cfg.model, "base_layers", 0) > 0: - cfg.checkpoint.checkpoint_suffix = f"-rank-{cfg.distributed_training.distributed_rank}" + if hasattr(cfg, "model") and getattr(cfg.model, "base_layers", 0) > 0: + cfg.checkpoint.checkpoint_suffix = ( + f"-rank-{cfg.distributed_training.distributed_rank}" + ) return cfg.distributed_training.distributed_rank @@ -696,7 +696,7 @@ def broadcast_tensors( dist_device = torch.device("cpu") # share metadata first to simplify transfer - is_src_rank = (get_rank(group) == src_rank) + is_src_rank = get_rank(group) == src_rank if is_src_rank: metadata = [ {"size": t.size(), "dtype": t.dtype, "device": t.device} for t in tensors @@ -747,7 +747,10 @@ def broadcast_object( def _broadcast_object_slow( - obj: Any, src_rank: int, group: object, dist_device: torch.device, + obj: Any, + src_rank: int, + group: object, + dist_device: torch.device, ) -> Any: if get_rank(group) == src_rank: # Emit data diff --git a/fairseq/file_io.py b/fairseq/file_io.py index dba663d4aa..8eca70a066 100644 --- a/fairseq/file_io.py +++ b/fairseq/file_io.py @@ -152,6 +152,7 @@ def rename(src: str, dst: str): """ ioPath async PathManager methods: """ + @staticmethod def opena( path: str, @@ -169,6 +170,7 @@ def opena( logging.info("ioPath is initializing PathManager.") try: from iopath.common.file_io import PathManager + IOPathManager = PathManager() except Exception: logging.exception("Failed to initialize ioPath PathManager object.") diff --git a/fairseq/file_utils.py b/fairseq/file_utils.py index d1d5ea6574..b99da2e8cd 100644 --- a/fairseq/file_utils.py +++ b/fairseq/file_utils.py @@ -146,6 +146,7 @@ def cached_path_from_pm(url_or_filename): """ try: from fairseq.file_io import PathManager + local_path = PathManager.get_local_path(url_or_filename) return local_path except Exception: diff --git a/fairseq/logging/metrics.py b/fairseq/logging/metrics.py index 58c2fb64e1..892b0ea4dd 100644 --- a/fairseq/logging/metrics.py +++ b/fairseq/logging/metrics.py @@ -130,6 +130,7 @@ def log_scalar( agg.add_meter(key, AverageMeter(round=round), priority) agg[key].update(value, weight) + def log_scalar_sum( key: str, value: float, @@ -309,6 +310,7 @@ def load_state_dict(state_dict): def xla_metrics_report(): try: import torch_xla.debug.metrics as met + print(met.metrics_report()) except ImportError: return diff --git a/fairseq/model_parallel/megatron_trainer.py b/fairseq/model_parallel/megatron_trainer.py index 8ab4657f73..ca42118648 100644 --- a/fairseq/model_parallel/megatron_trainer.py +++ b/fairseq/model_parallel/megatron_trainer.py @@ -52,8 +52,7 @@ def _aggregate_model_parallel_grad_norm(total_norm): def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" - extra_state['rng_tracker_states'] \ - = get_cuda_rng_tracker().get_states() + extra_state["rng_tracker_states"] = get_cuda_rng_tracker().get_states() super().save_checkpoint(filename, extra_state) def load_checkpoint( @@ -64,8 +63,13 @@ def load_checkpoint( optimizer_overrides=None, reset_meters=False, ): - extra_state = super().load_checkpoint(filename, reset_optimizer=reset_optimizer, reset_lr_scheduler=reset_lr_scheduler, optimizer_overrides=optimizer_overrides, reset_meters=reset_meters) - if extra_state is not None and 'rng_tracker_states' in extra_state: - get_cuda_rng_tracker().set_states( - extra_state['rng_tracker_states']) + extra_state = super().load_checkpoint( + filename, + reset_optimizer=reset_optimizer, + reset_lr_scheduler=reset_lr_scheduler, + optimizer_overrides=optimizer_overrides, + reset_meters=reset_meters, + ) + if extra_state is not None and "rng_tracker_states" in extra_state: + get_cuda_rng_tracker().set_states(extra_state["rng_tracker_states"]) return extra_state diff --git a/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py b/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py index eb81ded341..c07a027a31 100644 --- a/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py +++ b/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py @@ -9,6 +9,7 @@ import torch import torch.nn as nn import torch.nn.functional as F + from fairseq import options, utils from fairseq.modules import ( AdaptiveSoftmax, @@ -17,7 +18,6 @@ PositionalEmbedding, ) - EncoderOut = namedtuple( "TransformerEncoderOut", [ @@ -30,7 +30,7 @@ class TransformerEncoderEmbedding(nn.Module): - """ Encoder Embedding + Positional Embedding """ + """Encoder Embedding + Positional Embedding""" def __init__(self, args, embed_tokens): super().__init__() @@ -109,7 +109,7 @@ def forward(self, input): class TransformerDecoderEmbedding(nn.Module): - """ Decoder Embedding + Positional Embedding """ + """Decoder Embedding + Positional Embedding""" def __init__(self, args, embed_tokens): super().__init__() diff --git a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py index 7f30dd98bb..7bb0c9ada8 100644 --- a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py +++ b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py @@ -42,16 +42,20 @@ TORCH_PIPE = False RPC_INIT = False + def import_pipe(): global TORCH_PIPE global RPC_INIT try: - from torch.distributed.pipeline.sync import Pipe # noqa + from torch.distributed.pipeline.sync import Pipe # noqa + global Pipe from torch.distributed.pipeline.sync.utils import partition_model + global partition_model from torch.distributed import rpc import tempfile + TORCH_PIPE = True # Initialize single process RPC agent since TORCH_PIPE requires # RRef. RRef depends on RPC being initialized and as a result we initialize @@ -64,14 +68,15 @@ def import_pipe(): world_size=1, rpc_backend_options=rpc.TensorPipeRpcBackendOptions( init_method="file://{}".format(tmpfile.name), - ) + ), ) RPC_INIT = True - logger.info('Using torch pipe') + logger.info("Using torch pipe") except ImportError: try: - from fairscale.nn import Pipe # noqa - logger.info('Using fairscale pipe') + from fairscale.nn import Pipe # noqa + + logger.info("Using fairscale pipe") except ImportError: raise ImportError("Please install fairscale with: pip install fairscale") @@ -153,9 +158,14 @@ def prepare_for_inference_(self, cfg): decoder_module_list.append(module) module_count += 1 self.model = None - self.encoder = TransformerEncoder(cfg.distributed_training, None, None, encoder_module_list) + self.encoder = TransformerEncoder( + cfg.distributed_training, None, None, encoder_module_list + ) self.decoder = TransformerDecoder( - cfg.distributed_training, None, None, decoder_module_list=decoder_module_list + cfg.distributed_training, + None, + None, + decoder_module_list=decoder_module_list, ) @staticmethod @@ -471,7 +481,9 @@ def __init__(self, args, dictionary, embed_tokens, encoder_module_list=None): self.use_pipeline = encoder_module_list is not None if not self.use_pipeline: self.embedding_layer = TransformerEncoderEmbedding(args, embed_tokens) - self.encoder_layers = nn.Sequential(*[TransformerEncoderLayer(args) for i in range(args.encoder_layers)]) + self.encoder_layers = nn.Sequential( + *[TransformerEncoderLayer(args) for i in range(args.encoder_layers)] + ) if isinstance(embed_tokens, nn.ModuleList): emb_dim = sum(e.embedding_dim for e in embed_tokens) else: @@ -490,7 +502,11 @@ def __init__(self, args, dictionary, embed_tokens, encoder_module_list=None): ) if TORCH_PIPE: self.model = Pipe( - module=partition_model(nn.Sequential(*encoder_module_list), encoder_balance, encoder_devices), + module=partition_model( + nn.Sequential(*encoder_module_list), + encoder_balance, + encoder_devices, + ), chunks=args.pipeline_chunks, checkpoint=args.pipeline_checkpoint, ) @@ -614,10 +630,12 @@ def __init__( self.use_pipeline = decoder_module_list is not None if not self.use_pipeline: self.embedding_layer = TransformerDecoderEmbedding(args, embed_tokens) - self.decoder_layers = nn.Sequential(*[ - TransformerDecoderLayer(args, no_encoder_attn) - for _ in range(args.decoder_layers) - ]) + self.decoder_layers = nn.Sequential( + *[ + TransformerDecoderLayer(args, no_encoder_attn) + for _ in range(args.decoder_layers) + ] + ) self.decoder_output_layer = TransformerDecoderOutputLayer( args, embed_tokens, dictionary ) @@ -634,7 +652,11 @@ def __init__( ) if TORCH_PIPE: self.model = Pipe( - module=partition_model(nn.Sequential(*decoder_module_list), decoder_balance, decoder_devices), + module=partition_model( + nn.Sequential(*decoder_module_list), + decoder_balance, + decoder_devices, + ), chunks=args.pipeline_chunks, checkpoint=args.pipeline_checkpoint, ) diff --git a/fairseq/model_parallel/models/transformer_lm.py b/fairseq/model_parallel/models/transformer_lm.py index dc52f6e8dd..a7ca5c9fe6 100644 --- a/fairseq/model_parallel/models/transformer_lm.py +++ b/fairseq/model_parallel/models/transformer_lm.py @@ -4,11 +4,11 @@ # LICENSE file in the root directory of this source tree. import torch.nn as nn + from fairseq.model_parallel.models.transformer import ModelParallelTransformerDecoder from fairseq.models import register_model, register_model_architecture from fairseq.models.transformer_lm import TransformerLanguageModel - try: from fairseq.model_parallel.megatron.mpu import VocabParallelEmbedding @@ -22,7 +22,6 @@ @register_model("model_parallel_transformer_lm") class ModelParallelTransformerLanguageModel(TransformerLanguageModel): - @staticmethod def add_args(parser): TransformerLanguageModel.add_args(parser) @@ -72,10 +71,6 @@ def build_model(cls, args, task): ) return cls(decoder) - @staticmethod - def add_args(parser): - TransformerLanguageModel.add_args(parser) - @classmethod def build_embedding(cls, args, dictionary, embed_dim, path=None): def _vocab_init(tensor, **kwargs): diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 337c77ac7b..320f5e1725 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -98,9 +98,7 @@ def build_model(cfg: FairseqDataclass, task): assert model is not None, ( f"Could not infer model type from {cfg}. " - "Available models: {}".format( - MODEL_DATACLASS_REGISTRY.keys() - ) + "Available models: {}".format(MODEL_DATACLASS_REGISTRY.keys()) + f" Requested model type: {model_type}" ) diff --git a/fairseq/models/bart/hub_interface.py b/fairseq/models/bart/hub_interface.py index 4d47d97518..6b647c9642 100644 --- a/fairseq/models/bart/hub_interface.py +++ b/fairseq/models/bart/hub_interface.py @@ -100,8 +100,8 @@ def generate( raise NotImplementedError("prefix generation not implemented for BART") res = [] for batch in self._build_batches(tokenized_sentences, skip_invalid_size_inputs): - src_tokens = batch['net_input']['src_tokens'] - inference_step_args["prefix_tokens"] =src_tokens.new_full( + src_tokens = batch["net_input"]["src_tokens"] + inference_step_args["prefix_tokens"] = src_tokens.new_full( (src_tokens.size(0), 1), fill_value=self.task.source_dictionary.bos() ).to(device=self.device) results = super().generate( @@ -111,7 +111,7 @@ def generate( skip_invalid_size_inputs=skip_invalid_size_inputs, **kwargs ) - for id, hypos in zip(batch['id'].tolist(), results): + for id, hypos in zip(batch["id"].tolist(), results): res.append((id, hypos)) res = [hypos for _, hypos in sorted(res, key=lambda x: x[0])] return res @@ -177,32 +177,35 @@ def fill_mask( match_source_len: bool = True, **generate_kwargs ): - masked_token = '<mask>' + masked_token = "<mask>" batch_tokens = [] for masked_input in masked_inputs: - assert masked_token in masked_input, \ - "please add one {} token for the input".format(masked_token) + assert ( + masked_token in masked_input + ), "please add one {} token for the input".format(masked_token) text_spans = masked_input.split(masked_token) - text_spans_bpe = (' {0} '.format(masked_token)).join( - [self.bpe.encode(text_span.rstrip()) for text_span in text_spans] - ).strip() + text_spans_bpe = ( + (" {0} ".format(masked_token)) + .join([self.bpe.encode(text_span.rstrip()) for text_span in text_spans]) + .strip() + ) tokens = self.task.source_dictionary.encode_line( - '<s> ' + text_spans_bpe + ' </s>', + "<s> " + text_spans_bpe + " </s>", append_eos=False, add_if_not_exist=False, ).long() batch_tokens.append(tokens) # ensure beam size is at least as big as topk - generate_kwargs['beam'] = max( + generate_kwargs["beam"] = max( topk, - generate_kwargs.get('beam', -1), + generate_kwargs.get("beam", -1), ) - generate_kwargs['match_source_len'] = match_source_len + generate_kwargs["match_source_len"] = match_source_len batch_hypos = self.generate(batch_tokens, **generate_kwargs) return [ - [(self.decode(hypo['tokens']), hypo['score']) for hypo in hypos[:topk]] + [(self.decode(hypo["tokens"]), hypo["score"]) for hypo in hypos[:topk]] for hypos in batch_hypos ] diff --git a/fairseq/models/bart/model.py b/fairseq/models/bart/model.py index 71d0b27cd2..bdb12b02f7 100644 --- a/fairseq/models/bart/model.py +++ b/fairseq/models/bart/model.py @@ -90,7 +90,7 @@ def forward( src_tokens, src_lengths=src_lengths, token_embeddings=token_embeddings, - return_all_hiddens=return_all_hiddens + return_all_hiddens=return_all_hiddens, ) x, extra = self.decoder( prev_output_tokens, @@ -103,9 +103,9 @@ def forward( ) eos: int = self.eos if classification_head_name is not None: - sentence_representation = x[ - src_tokens.eq(eos), : - ].view(x.size(0), -1, x.size(-1))[:, -1, :] + sentence_representation = x[src_tokens.eq(eos), :].view( + x.size(0), -1, x.size(-1) + )[:, -1, :] for k, head in self.classification_heads.items(): # for torch script only supports iteration if k == classification_head_name: diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index de8d6ac115..7c4ab558c0 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -25,7 +25,10 @@ _SLOWMO_DDP_DISABLED = False try: - from fairscale.experimental.nn.data_parallel import SlowMoBaseAlgorithm, SlowMoDistributedDataParallel + from fairscale.experimental.nn.data_parallel import ( + SlowMoBaseAlgorithm, + SlowMoDistributedDataParallel, + ) except ImportError: _SLOWMO_DDP_DISABLED = True diff --git a/fairseq/models/ema/ema.py b/fairseq/models/ema/ema.py index 6c0af69325..c43d9693a4 100644 --- a/fairseq/models/ema/ema.py +++ b/fairseq/models/ema/ema.py @@ -22,6 +22,7 @@ import logging import torch + from fairseq import checkpoint_utils @@ -78,7 +79,9 @@ def __init__(self, model, config, device=None): self.fp32_params = {} if self.config.ema_seed_model is not None: - state = checkpoint_utils.load_ema_from_checkpoint(self.config.ema_seed_model) + state = checkpoint_utils.load_ema_from_checkpoint( + self.config.ema_seed_model + ) self.model.load_state_dict(state["model"], strict=True) if device is not None: @@ -119,7 +122,7 @@ def _to_float(t): self.fp32_params[param_key] = _to_float(state_dict[param_key]) def restore(self, state_dict, build_fp32_params=False): - """ Load data from a model spec into EMA model """ + """Load data from a model spec into EMA model""" self.model.load_state_dict(state_dict, strict=False) if build_fp32_params: self.build_fp32_params(state_dict) @@ -131,16 +134,20 @@ def get_decay(self): return self.decay def _step_internal(self, new_model, updates=None): - """ One update of the EMA model based on new model weights """ + """One update of the EMA model based on new model weights""" decay = self.decay ema_state_dict = {} - ema_params = self.fp32_params if self.config.ema_fp32 else self.model.state_dict() + ema_params = ( + self.fp32_params if self.config.ema_fp32 else self.model.state_dict() + ) for key, param in new_model.state_dict().items(): try: ema_param = ema_params[key] except KeyError: - ema_param = param.float().clone() if param.ndim == 1 else copy.deepcopy(param) + ema_param = ( + param.float().clone() if param.ndim == 1 else copy.deepcopy(param) + ) if param.shape != ema_param.shape: raise ValueError( @@ -151,7 +158,7 @@ def _step_internal(self, new_model, updates=None): # Do not decay a model.version pytorch param continue ema_param.mul_(decay) - ema_param.add_(param.to(dtype=ema_param.dtype), alpha=1-decay) + ema_param.add_(param.to(dtype=ema_param.dtype), alpha=1 - decay) ema_state_dict[key] = ema_param self.restore(ema_state_dict, build_fp32_params=False) @@ -168,8 +175,7 @@ def step(self, new_model, updates=None): """ self._set_decay( 0 - if updates is not None - and updates < self.config.ema_start_update + if updates is not None and updates < self.config.ema_start_update else self.config.ema_decay ) if updates is not None and self.config.ema_update_freq > 1: diff --git a/fairseq/models/fairseq_decoder.py b/fairseq/models/fairseq_decoder.py index 4f1e8b52a2..13b73d639e 100644 --- a/fairseq/models/fairseq_decoder.py +++ b/fairseq/models/fairseq_decoder.py @@ -19,7 +19,6 @@ def __init__(self, dictionary): self.onnx_trace = False self.adaptive_softmax = None - def forward(self, prev_output_tokens, encoder_out=None, **kwargs): """ Args: diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index e55c7ba1ad..42f9134a3e 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -29,8 +29,9 @@ def check_type(module, expected_type): if hasattr(module, "unwrapped_module"): - assert isinstance(module.unwrapped_module, expected_type), \ - f"{type(module.unwrapped_module)} != {expected_type}" + assert isinstance( + module.unwrapped_module, expected_type + ), f"{type(module.unwrapped_module)} != {expected_type}" else: assert isinstance(module, expected_type), f"{type(module)} != {expected_type}" @@ -114,7 +115,9 @@ def load_state_dict( """ if model_cfg is None and args is not None: - logger.warn("using 'args' is deprecated, please update your code to use dataclass config") + logger.warn( + "using 'args' is deprecated, please update your code to use dataclass config" + ) model_cfg = convert_namespace_to_omegaconf(args).model self.upgrade_state_dict(state_dict) @@ -454,7 +457,9 @@ def load_state_dict( """ if model_cfg is None and args is not None: - logger.warn("using 'args' is deprecated, please update your code to use dataclass config") + logger.warn( + "using 'args' is deprecated, please update your code to use dataclass config" + ) model_cfg = convert_namespace_to_omegaconf(args).model self.upgrade_state_dict(state_dict) diff --git a/fairseq/models/hubert/hubert.py b/fairseq/models/hubert/hubert.py index 232a5e402a..4306af03ca 100644 --- a/fairseq/models/hubert/hubert.py +++ b/fairseq/models/hubert/hubert.py @@ -30,9 +30,7 @@ logger = logging.getLogger(__name__) EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) -MASKING_DISTRIBUTION_CHOICES = ChoiceEnum( - ["static", "uniform", "normal", "poisson"] -) +MASKING_DISTRIBUTION_CHOICES = ChoiceEnum(["static", "uniform", "normal", "poisson"]) @dataclass @@ -86,9 +84,7 @@ class HubertConfig(FairseqDataclass): ) dropout_features: float = field( default=0.0, - metadata={ - "help": "dropout to apply to the features (after feat extr)" - }, + metadata={"help": "dropout to apply to the features (after feat extr)"}, ) final_dim: int = field( @@ -150,9 +146,7 @@ class HubertConfig(FairseqDataclass): ) mask_min_space: int = field( default=1, - metadata={ - "help": "min space between spans (if no overlap is enabled)" - }, + metadata={"help": "min space between spans (if no overlap is enabled)"}, ) # channel masking @@ -182,23 +176,17 @@ class HubertConfig(FairseqDataclass): ) mask_channel_min_space: int = field( default=1, - metadata={ - "help": "min space between spans (if no overlap is enabled)" - }, + metadata={"help": "min space between spans (if no overlap is enabled)"}, ) # positional embeddings conv_pos: int = field( default=128, - metadata={ - "help": "number of filters for convolutional positional embeddings" - }, + metadata={"help": "number of filters for convolutional positional embeddings"}, ) conv_pos_groups: int = field( default=16, - metadata={ - "help": "number of groups for convolutional positional embedding" - }, + metadata={"help": "number of groups for convolutional positional embedding"}, ) latent_temp: Tuple[float, float, float] = field( @@ -238,9 +226,7 @@ def __init__( conv_bias=cfg.conv_bias, ) feature_ds_rate = np.prod([s for _, _, s in feature_enc_layers]) - self.feat2tar_ratio = ( - cfg.label_rate * feature_ds_rate / task_cfg.sample_rate - ) + self.feat2tar_ratio = cfg.label_rate * feature_ds_rate / task_cfg.sample_rate self.post_extract_proj = ( nn.Linear(self.embed, cfg.encoder_embed_dim) @@ -270,9 +256,7 @@ def __init__( self.skip_masked = cfg.skip_masked self.skip_nomask = cfg.skip_nomask - final_dim = ( - cfg.final_dim if cfg.final_dim > 0 else cfg.encoder_embed_dim - ) + final_dim = cfg.final_dim if cfg.final_dim > 0 else cfg.encoder_embed_dim self.mask_emb = nn.Parameter( torch.FloatTensor(cfg.encoder_embed_dim).uniform_() @@ -297,9 +281,7 @@ def __init__( # modules below are not needed during fine-tuning if any([d is None for d in dictionaries]): - logger.info( - "cannot find dictionary. assume will be used for fine-tuning" - ) + logger.info("cannot find dictionary. assume will be used for fine-tuning") else: self.num_classes = [len(d) for d in dictionaries] self.label_embs_concat = nn.Parameter( @@ -365,9 +347,7 @@ def compute_nce(self, x, pos, negs): pos = pos.unsqueeze(0) targets = torch.cat([pos, negs], dim=0) - logits = torch.cosine_similarity( - x.float(), targets.float(), dim=-1 - ).type_as(x) + logits = torch.cosine_similarity(x.float(), targets.float(), dim=-1).type_as(x) logits /= self.logit_temp if neg_is_pos.any(): logits[1:][neg_is_pos] = float("-inf") @@ -385,7 +365,9 @@ def forward_features(self, source: torch.Tensor) -> torch.Tensor: return features def forward_targets( - self, features: torch.Tensor, target_list: List[torch.Tensor], + self, + features: torch.Tensor, + target_list: List[torch.Tensor], ) -> Tuple[torch.Tensor, torch.Tensor]: # Trim features to ensure labels exist and then get aligned labels feat_tsz = features.size(2) @@ -398,14 +380,14 @@ def forward_targets( return features, target_list def forward_padding_mask( - self, features: torch.Tensor, padding_mask: torch.Tensor, + self, + features: torch.Tensor, + padding_mask: torch.Tensor, ) -> torch.Tensor: extra = padding_mask.size(1) % features.size(1) if extra > 0: padding_mask = padding_mask[:, :-extra] - padding_mask = padding_mask.view( - padding_mask.size(0), features.size(1), -1 - ) + padding_mask = padding_mask.view(padding_mask.size(0), features.size(1), -1) padding_mask = padding_mask.all(-1) return padding_mask @@ -439,9 +421,7 @@ def forward( unmasked_features = self.dropout_features(unmasked_features) if mask: - x, mask_indices = self.apply_mask( - features, padding_mask, target_list - ) + x, mask_indices = self.apply_mask(features, padding_mask, target_list) else: x = features mask_indices = None @@ -454,7 +434,7 @@ def forward( x, _ = self.encoder( x, padding_mask=padding_mask, - layer=None if output_layer is None else output_layer - 1 + layer=None if output_layer is None else output_layer - 1, ) if features_only: @@ -483,9 +463,7 @@ def compute_pred(proj_x, target, label_embs): proj_x_m_list = [proj_x_m for _ in range(len(target_list))] logit_m_list = [ compute_pred(proj_x_m, t[masked_indices], label_embs_list[i]) - for i, (proj_x_m, t) in enumerate( - zip(proj_x_m_list, target_list) - ) + for i, (proj_x_m, t) in enumerate(zip(proj_x_m_list, target_list)) ] else: logit_m_list = [None for _ in target_list] @@ -500,9 +478,7 @@ def compute_pred(proj_x, target, label_embs): logit_u_list = [ compute_pred(proj_x_u, t[nomask_indices], label_embs_list[i]) - for i, (proj_x_u, t) in enumerate( - zip(proj_x_u_list, target_list) - ) + for i, (proj_x_u, t) in enumerate(zip(proj_x_u_list, target_list)) ] else: logit_u_list = [None for _ in target_list] @@ -543,9 +519,7 @@ def get_logits(self, net_output, is_masked=True): def get_targets(self, net_output, is_masked=True): logits_list = self.get_logits(net_output, is_masked) - targets_list = [ - x.new_zeros(x.size(0), dtype=torch.long) for x in logits_list - ] + targets_list = [x.new_zeros(x.size(0), dtype=torch.long) for x in logits_list] return targets_list def get_extra_losses(self, net_output): diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index dce899c9de..e336370b3e 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -21,9 +21,7 @@ @dataclass class HubertAsrConfig(FairseqDataclass): - w2v_path: str = field( - default=MISSING, metadata={"help": "path to hubert model"} - ) + w2v_path: str = field(default=MISSING, metadata={"help": "path to hubert model"}) no_pretrained_weights: bool = field( default=False, metadata={"help": "if true, does not load pretrained weights"}, @@ -34,9 +32,7 @@ class HubertAsrConfig(FairseqDataclass): ) final_dropout: float = field( default=0.0, - metadata={ - "help": "dropout after transformer and before final projection" - }, + metadata={"help": "dropout after transformer and before final projection"}, ) dropout: float = field( default=0.0, @@ -45,15 +41,13 @@ class HubertAsrConfig(FairseqDataclass): attention_dropout: float = field( default=0.0, metadata={ - "help": "dropout probability for attention weights " - "inside hubert model" + "help": "dropout probability for attention weights " "inside hubert model" }, ) activation_dropout: float = field( default=0.0, metadata={ - "help": "dropout probability after activation in FFN " - "inside hubert model" + "help": "dropout probability after activation in FFN " "inside hubert model" }, ) @@ -184,9 +178,7 @@ class HubertSeq2SeqConfig(HubertAsrConfig): decoder_ffn_embed_dim: int = field( default=3072, metadata={"help": "decoder embedding dimension for FFN"} ) - decoder_layers: int = field( - default=6, metadata={"help": "num of decoder layers"} - ) + decoder_layers: int = field(default=6, metadata={"help": "num of decoder layers"}) decoder_layerdrop: float = field( default=0.0, metadata={"help": "decoder layerdrop chance"} ) @@ -204,8 +196,7 @@ class HubertSeq2SeqConfig(HubertAsrConfig): no_token_positional_embeddings: bool = field( default=False, metadata={ - "help": "if set, disables positional embeddings " - "(outside self attention)" + "help": "if set, disables positional embeddings " "(outside self attention)" }, ) decoder_dropout: float = field( @@ -214,15 +205,13 @@ class HubertSeq2SeqConfig(HubertAsrConfig): decoder_attention_dropout: float = field( default=0.0, metadata={ - "help": "dropout probability for attention weights " - "inside the decoder" + "help": "dropout probability for attention weights " "inside the decoder" }, ) decoder_activation_dropout: float = field( default=0.0, metadata={ - "help": "dropout probability after activation in FFN " - "inside the decoder" + "help": "dropout probability after activation in FFN " "inside the decoder" }, ) max_target_positions: int = field( @@ -258,9 +247,7 @@ def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): } if cfg.w2v_args is None: - state = checkpoint_utils.load_checkpoint_to_cpu( - cfg.w2v_path, arg_overrides - ) + state = checkpoint_utils.load_checkpoint_to_cpu(cfg.w2v_path, arg_overrides) w2v_args = state.get("cfg", None) if w2v_args is None: w2v_args = convert_namespace_to_omegaconf(state["args"]) @@ -269,9 +256,7 @@ def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): state = None w2v_args = cfg.w2v_args if isinstance(w2v_args, Namespace): - cfg.w2v_args = w2v_args = convert_namespace_to_omegaconf( - w2v_args - ) + cfg.w2v_args = w2v_args = convert_namespace_to_omegaconf(w2v_args) assert cfg.normalize == w2v_args.task.normalize, ( "Fine-tuning works best when data normalization is the same. " @@ -344,9 +329,9 @@ def forward(self, source, padding_mask, tbc=True, **kwargs): def reorder_encoder_out(self, encoder_out, new_order): if encoder_out["encoder_out"] is not None: - encoder_out["encoder_out"] = encoder_out[ - "encoder_out" - ].index_select(1, new_order) + encoder_out["encoder_out"] = encoder_out["encoder_out"].index_select( + 1, new_order + ) if encoder_out["encoder_padding_mask"] is not None: encoder_out["encoder_padding_mask"] = encoder_out[ "encoder_padding_mask" diff --git a/fairseq/models/lstm.py b/fairseq/models/lstm.py index e1e66a7d50..8a29156270 100644 --- a/fairseq/models/lstm.py +++ b/fairseq/models/lstm.py @@ -225,10 +225,10 @@ def __init__( super().__init__(dictionary) self.num_layers = num_layers self.dropout_in_module = FairseqDropout( - dropout_in*1.0, module_name=self.__class__.__name__ + dropout_in * 1.0, module_name=self.__class__.__name__ ) self.dropout_out_module = FairseqDropout( - dropout_out*1.0, module_name=self.__class__.__name__ + dropout_out * 1.0, module_name=self.__class__.__name__ ) self.bidirectional = bidirectional self.hidden_size = hidden_size @@ -329,7 +329,9 @@ def combine_bidir(self, outs, bsz: int): out = outs.view(self.num_layers, 2, bsz, -1).transpose(1, 2).contiguous() return out.view(self.num_layers, bsz, -1) - def reorder_encoder_out(self, encoder_out: Tuple[Tensor, Tensor, Tensor, Tensor], new_order): + def reorder_encoder_out( + self, encoder_out: Tuple[Tensor, Tensor, Tensor, Tensor], new_order + ): return tuple( ( encoder_out[0].index_select(1, new_order), @@ -402,10 +404,10 @@ def __init__( ): super().__init__(dictionary) self.dropout_in_module = FairseqDropout( - dropout_in*1.0, module_name=self.__class__.__name__ + dropout_in * 1.0, module_name=self.__class__.__name__ ) self.dropout_out_module = FairseqDropout( - dropout_out*1.0, module_name=self.__class__.__name__ + dropout_out * 1.0, module_name=self.__class__.__name__ ) self.hidden_size = hidden_size self.share_input_output_embed = share_input_output_embed diff --git a/fairseq/models/nat/fairseq_nat_model.py b/fairseq/models/nat/fairseq_nat_model.py index b09394112f..a5594a4ed9 100644 --- a/fairseq/models/nat/fairseq_nat_model.py +++ b/fairseq/models/nat/fairseq_nat_model.py @@ -18,7 +18,10 @@ def ensemble_encoder(func): def wrapper(self, *args, **kwargs): if self.ensemble_models is None or len(self.ensemble_models) == 1: return func(self, *args, **kwargs) - encoder_outs = [func(model, *args, **kwargs, return_all_hiddens=True) for model in self.ensemble_models] + encoder_outs = [ + func(model, *args, **kwargs, return_all_hiddens=True) + for model in self.ensemble_models + ] _encoder_out = encoder_outs[0].copy() def stack(key): @@ -56,8 +59,7 @@ def _replace(encoder_out, new_val): model, normalize=normalize, encoder_out=_replace( - encoder_out, - encoder_out["encoder_out"][0][:, :, :, i] + encoder_out, encoder_out["encoder_out"][0][:, :, :, i] ), *args, **kwargs diff --git a/fairseq/models/nat/nonautoregressive_ensembles.py b/fairseq/models/nat/nonautoregressive_ensembles.py index 705a04fb49..0a0221f9c4 100644 --- a/fairseq/models/nat/nonautoregressive_ensembles.py +++ b/fairseq/models/nat/nonautoregressive_ensembles.py @@ -85,7 +85,8 @@ def forward_decoder( else: if not encoder_outs[0]["encoder_padding_mask"]: src_lens = ( - encoder_outs[0]["encoder_out"][0].new(bsz) + encoder_outs[0]["encoder_out"][0] + .new(bsz) .fill_(encoder_outs[0]["encoder_out"][0].size(1)) ) else: diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index bb205b910d..6e59ece5c0 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -183,7 +183,7 @@ def add_args(parser): "communication less efficient due to smaller input sizes. This option " "is set to 0 (i.e., always wrap) when --checkpoint-activations or " "--offload-activations are passed." - ) + ), ) @classmethod @@ -542,7 +542,9 @@ def base_architecture(args): args.layernorm_embedding = safe_getattr(args, "layernorm_embedding", True) args.no_scale_embedding = safe_getattr(args, "no_scale_embedding", True) args.activation_fn = safe_getattr(args, "activation_fn", "gelu") - args.encoder_normalize_before = safe_getattr(args, "encoder_normalize_before", False) + args.encoder_normalize_before = safe_getattr( + args, "encoder_normalize_before", False + ) args.pooler_activation_fn = safe_getattr(args, "pooler_activation_fn", "tanh") args.untie_weights_roberta = safe_getattr(args, "untie_weights_roberta", False) diff --git a/fairseq/models/roberta/model_gottbert.py b/fairseq/models/roberta/model_gottbert.py index 2e8c66354a..dc7a019b33 100644 --- a/fairseq/models/roberta/model_gottbert.py +++ b/fairseq/models/roberta/model_gottbert.py @@ -12,26 +12,26 @@ from .model import RobertaModel -@register_model('gottbert') +@register_model("gottbert") class GottbertModel(RobertaModel): - @classmethod def hub_models(cls): return { - 'gottbert-base': 'https://dl.gottbert.de/fairseq/models/gottbert-base.tar.gz', + "gottbert-base": "https://dl.gottbert.de/fairseq/models/gottbert-base.tar.gz", } @classmethod - def from_pretrained(cls, - model_name_or_path, - checkpoint_file='model.pt', - data_name_or_path='.', - bpe='hf_byte_bpe', - bpe_vocab='vocab.json', - bpe_merges='merges.txt', - bpe_add_prefix_space=False, - **kwargs - ): + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + bpe="hf_byte_bpe", + bpe_vocab="vocab.json", + bpe_merges="merges.txt", + bpe_add_prefix_space=False, + **kwargs + ): from fairseq import hub_utils x = hub_utils.from_pretrained( @@ -46,4 +46,4 @@ def from_pretrained(cls, bpe_add_prefix_space=bpe_add_prefix_space, **kwargs, ) - return RobertaHubInterface(x['args'], x['task'], x['models'][0]) + return RobertaHubInterface(x["args"], x["task"], x["models"][0]) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index aff9d0ffc7..cc10848509 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -202,10 +202,10 @@ def add_args(parser): help="model to take encoder weights from (for initialization)", ) parser.add_argument( - '--encoder-freezing-updates', + "--encoder-freezing-updates", type=int, - metavar='N', - help='freeze encoder for first N updates' + metavar="N", + help="freeze encoder for first N updates", ) @classmethod @@ -329,7 +329,9 @@ def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): return { "encoder_out": [x], # T x B x C - "encoder_padding_mask": [encoder_padding_mask] if encoder_padding_mask.any() else [], # B x T + "encoder_padding_mask": [encoder_padding_mask] + if encoder_padding_mask.any() + else [], # B x T "encoder_embedding": [], # B x T x C "encoder_states": encoder_states, # List[T x B x C] "src_tokens": [], @@ -339,27 +341,37 @@ def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): def forward(self, src_tokens, src_lengths, return_all_hiddens=False): if self.num_updates < self.encoder_freezing_updates: with torch.no_grad(): - x = self._forward(src_tokens, src_lengths, - return_all_hiddens=return_all_hiddens) + x = self._forward( + src_tokens, src_lengths, return_all_hiddens=return_all_hiddens + ) else: - x = self._forward(src_tokens, src_lengths, - return_all_hiddens=return_all_hiddens) + x = self._forward( + src_tokens, src_lengths, return_all_hiddens=return_all_hiddens + ) return x def reorder_encoder_out(self, encoder_out, new_order): new_encoder_out = ( - [] if len(encoder_out["encoder_out"]) == 0 + [] + if len(encoder_out["encoder_out"]) == 0 else [x.index_select(1, new_order) for x in encoder_out["encoder_out"]] ) new_encoder_padding_mask = ( - [] if len(encoder_out["encoder_padding_mask"]) == 0 - else [x.index_select(0, new_order) for x in encoder_out["encoder_padding_mask"]] + [] + if len(encoder_out["encoder_padding_mask"]) == 0 + else [ + x.index_select(0, new_order) + for x in encoder_out["encoder_padding_mask"] + ] ) new_encoder_embedding = ( - [] if len(encoder_out["encoder_embedding"]) == 0 - else [x.index_select(0, new_order) for x in encoder_out["encoder_embedding"]] + [] + if len(encoder_out["encoder_embedding"]) == 0 + else [ + x.index_select(0, new_order) for x in encoder_out["encoder_embedding"] + ] ) encoder_states = encoder_out["encoder_states"] diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index 5eecbfa215..c2cc86bb3f 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -9,8 +9,12 @@ from typing import Dict, List, Optional, Tuple from fairseq import utils, checkpoint_utils -from fairseq.models import (FairseqEncoderDecoderModel, FairseqEncoder, - register_model, register_model_architecture) +from fairseq.models import ( + FairseqEncoderDecoderModel, + FairseqEncoder, + register_model, + register_model_architecture, +) from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.models.wav2vec import Wav2VecEncoder from fairseq.modules.layer_norm import LayerNorm @@ -24,18 +28,23 @@ class Conv1dAdaptor(nn.Module): - def __init__(self, in_dim, out_dim, n_layers=3, kernel_size=3, stride=2, - add_layernorm=False): + def __init__( + self, in_dim, out_dim, n_layers=3, kernel_size=3, stride=2, add_layernorm=False + ): super().__init__() self.layers = nn.ModuleList( - nn.Conv1d(in_dim if i == 0 else out_dim, out_dim * 2, kernel_size, - stride=stride, padding=kernel_size // 2) + nn.Conv1d( + in_dim if i == 0 else out_dim, + out_dim * 2, + kernel_size, + stride=stride, + padding=kernel_size // 2, + ) for i in range(n_layers) ) self.layernorms = None if add_layernorm: - self.layernorms = nn.ModuleList(LayerNorm(out_dim) - for _ in range(n_layers)) + self.layernorms = nn.ModuleList(LayerNorm(out_dim) for _ in range(n_layers)) self.stride = stride @classmethod @@ -43,7 +52,7 @@ def add_args(cls, parser): parser.add_argument("--adaptor-n-layers", type=int) parser.add_argument("--adaptor-kernel-size", type=int) parser.add_argument("--adaptor-stride", type=int) - parser.add_argument("--adaptor-layernorm", action='store_true') + parser.add_argument("--adaptor-layernorm", action="store_true") def get_out_seq_lens_tensor(self, in_seq_lens_tensor): out = in_seq_lens_tensor.clone() @@ -197,15 +206,18 @@ def __init__(self, args): encoder_out_dim = self.w2v_encoder.w2v_model.encoder.embedding_dim # Projection + 8x shrinking self.adaptor = Conv1dAdaptor( - encoder_out_dim, args.decoder_embed_dim, + encoder_out_dim, + args.decoder_embed_dim, n_layers=args.adaptor_n_layers, - kernel_size=args.adaptor_kernel_size, stride=args.adaptor_stride, - add_layernorm=args.adaptor_layernorm + kernel_size=args.adaptor_kernel_size, + stride=args.adaptor_stride, + add_layernorm=args.adaptor_layernorm, ) for k, p in self.w2v_encoder.w2v_model.named_parameters(): # Freeze pretrained models by default - if safe_hasattr(args, 'finetune_w2v_params') and XMTransformerModel.finetune_params( - args.finetune_w2v_params, k): + if safe_hasattr( + args, "finetune_w2v_params" + ) and XMTransformerModel.finetune_params(args.finetune_w2v_params, k): p.requires_grad = True else: p.requires_grad = False @@ -214,11 +226,16 @@ def __init__(self, args): def add_args(cls, parser): add_wav2vec_asr_args(parser) parser.add_argument( - "--normalize", action="store_true", + "--normalize", + action="store_true", help="if set, normalizes input to have 0 mean and unit variance", ) - parser.add_argument("--finetune-w2v-params", type=str, metavar="STR", - help="comma-separated param strings to finetune.") + parser.add_argument( + "--finetune-w2v-params", + type=str, + metavar="STR", + help="comma-separated param strings to finetune.", + ) Conv1dAdaptor.add_args(parser) def forward(self, src_tokens, src_lengths=None, **kwargs): @@ -227,13 +244,17 @@ def forward(self, src_tokens, src_lengths=None, **kwargs): x = out["encoder_out"] enc_padding_mask = None if out["encoder_padding_mask"] is not None: - enc_padding_mask = out["encoder_padding_mask"].transpose(0, 1) # T X B --> B X T + enc_padding_mask = out["encoder_padding_mask"].transpose( + 0, 1 + ) # T X B --> B X T x, enc_padding_mask = self.adaptor(x, enc_padding_mask) return { "encoder_out": [x], # T x B x C - "encoder_padding_mask": [enc_padding_mask] if enc_padding_mask.any() else [], # B x T + "encoder_padding_mask": [enc_padding_mask] + if enc_padding_mask.any() + else [], # B x T "encoder_embedding": [], # B x T x C "encoder_states": [], # List[T x B x C] "src_tokens": [], @@ -242,20 +263,26 @@ def forward(self, src_tokens, src_lengths=None, **kwargs): def reorder_encoder_out(self, encoder_out, new_order): new_encoder_out = ( - [] if len(encoder_out["encoder_out"]) == 0 + [] + if len(encoder_out["encoder_out"]) == 0 else [x.index_select(1, new_order) for x in encoder_out["encoder_out"]] ) new_encoder_padding_mask = ( - [] if len(encoder_out["encoder_padding_mask"]) == 0 - else [x.index_select(0, new_order) for x in - encoder_out["encoder_padding_mask"]] + [] + if len(encoder_out["encoder_padding_mask"]) == 0 + else [ + x.index_select(0, new_order) + for x in encoder_out["encoder_padding_mask"] + ] ) new_encoder_embedding = ( - [] if len(encoder_out["encoder_embedding"]) == 0 - else [x.index_select(0, new_order) for x in - encoder_out["encoder_embedding"]] + [] + if len(encoder_out["encoder_embedding"]) == 0 + else [ + x.index_select(0, new_order) for x in encoder_out["encoder_embedding"] + ] ) encoder_states = encoder_out["encoder_states"] @@ -274,38 +301,71 @@ def reorder_encoder_out(self, encoder_out, new_order): def add_decoder_args(parser): - parser.add_argument("--activation-fn", type=str, default='relu', - choices=utils.get_available_activation_fns(), - help="activation function to use") - parser.add_argument("--decoder-dropout", type=float, metavar="D", - help="dropout probability") - parser.add_argument("--decoder-attention-dropout", type=float, - metavar="D", - help="dropout probability for attention weights") - parser.add_argument("--decoder-activation-dropout", type=float, - metavar="D", - help="dropout probability after activation in FFN.") - parser.add_argument("--decoder-embed-dim", type=int, metavar="N", - help="decoder embedding dimension") - parser.add_argument("--decoder-ffn-embed-dim", type=int, metavar="N", - help="decoder embedding dimension for FFN") - parser.add_argument("--decoder-layers", type=int, metavar="N", - help="num decoder layers") - parser.add_argument("--decoder-attention-heads", type=int, metavar="N", - help="num decoder attention heads") - parser.add_argument("--decoder-normalize-before", action="store_true", - help="apply layernorm before each decoder block") - parser.add_argument("--layernorm-embedding", action="store_true", - help="add layernorm to embedding") - parser.add_argument("--no-scale-embedding", action="store_true", - help="if True, dont scale embeddings") - parser.add_argument( - "--load-pretrained-decoder-from", type=str, metavar="STR", - help="model to take decoder weights from (for initialization)" - ) - parser.add_argument("--finetune-decoder-params", type=str, - metavar="STR", - help="comma-separated param strings to finetune.") + parser.add_argument( + "--activation-fn", + type=str, + default="relu", + choices=utils.get_available_activation_fns(), + help="activation function to use", + ) + parser.add_argument( + "--decoder-dropout", type=float, metavar="D", help="dropout probability" + ) + parser.add_argument( + "--decoder-attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights", + ) + parser.add_argument( + "--decoder-activation-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN.", + ) + parser.add_argument( + "--decoder-embed-dim", type=int, metavar="N", help="decoder embedding dimension" + ) + parser.add_argument( + "--decoder-ffn-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension for FFN", + ) + parser.add_argument( + "--decoder-layers", type=int, metavar="N", help="num decoder layers" + ) + parser.add_argument( + "--decoder-attention-heads", + type=int, + metavar="N", + help="num decoder attention heads", + ) + parser.add_argument( + "--decoder-normalize-before", + action="store_true", + help="apply layernorm before each decoder block", + ) + parser.add_argument( + "--layernorm-embedding", action="store_true", help="add layernorm to embedding" + ) + parser.add_argument( + "--no-scale-embedding", + action="store_true", + help="if True, dont scale embeddings", + ) + parser.add_argument( + "--load-pretrained-decoder-from", + type=str, + metavar="STR", + help="model to take decoder weights from (for initialization)", + ) + parser.add_argument( + "--finetune-decoder-params", + type=str, + metavar="STR", + help="comma-separated param strings to finetune.", + ) parser.add_argument("--checkpoint-activations", action="store_true") @@ -342,16 +402,16 @@ def build_decoder(cls, args, task, embed_tokens): _args.activation_dropout = args.decoder_activation_dropout _args.max_target_positions = 1024 - decoder = TransformerDecoder(_args, task.target_dictionary, - embed_tokens) + decoder = TransformerDecoder(_args, task.target_dictionary, embed_tokens) if getattr(args, "load_pretrained_decoder_from", None): decoder = checkpoint_utils.load_pretrained_component_from_model( component=decoder, checkpoint=args.load_pretrained_decoder_from ) for k, p in decoder.named_parameters(): # Freeze pretrained models by default - if safe_hasattr(args, 'finetune_decoder_params') and XMTransformerModel.finetune_params( - args.finetune_decoder_params, k): + if safe_hasattr( + args, "finetune_decoder_params" + ) and XMTransformerModel.finetune_params(args.finetune_decoder_params, k): p.requires_grad = True else: p.requires_grad = False @@ -369,8 +429,9 @@ def build_embedding(dictionary, embed_dim): padding_idx = dictionary.pad() return Embedding(num_embeddings, embed_dim, padding_idx) - decoder_embed_tokens = build_embedding(task.target_dictionary, - args.decoder_embed_dim) + decoder_embed_tokens = build_embedding( + task.target_dictionary, args.decoder_embed_dim + ) encoder = cls.build_encoder(args) decoder = cls.build_decoder(args, task, decoder_embed_tokens) return cls(encoder, decoder) @@ -382,8 +443,7 @@ def get_normalized_probs( sample: Optional[Dict[str, Tensor]] = None, ): # net_output['encoder_out'] is a (B, T, D) tensor - lprobs = self.get_normalized_probs_scriptable(net_output, log_probs, - sample) + lprobs = self.get_normalized_probs_scriptable(net_output, log_probs, sample) lprobs.batch_first = True return lprobs @@ -393,17 +453,19 @@ def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): argument in its input, which is not supported in torchscript. This method overrites the forward method definition without **kwargs. """ - encoder_out = self.encoder(src_tokens=src_tokens, - src_lengths=src_lengths, **kwargs) - decoder_out = self.decoder(prev_output_tokens=prev_output_tokens, - encoder_out=encoder_out) + encoder_out = self.encoder( + src_tokens=src_tokens, src_lengths=src_lengths, **kwargs + ) + decoder_out = self.decoder( + prev_output_tokens=prev_output_tokens, encoder_out=encoder_out + ) return decoder_out def upgrade_state_dict(self, state_dict): for k, _ in state_dict.items(): - if 'adaptor.layers' in state_dict: + if "adaptor.layers" in state_dict: print(k) - new = k.replace('adaptor.layers', 'adaptor_layers') + new = k.replace("adaptor.layers", "adaptor_layers") state_dict[new] = state_dict[k] del state_dict[k] @@ -435,11 +497,9 @@ def set_default_w2v_encoder_args(args): args.mask_channel_length = getattr(args, "mask_channel_length", 10) args.mask_channel_prob = getattr(args, "mask_channel_prob", 0.5) args.mask_channel_before = getattr(args, "mask_channel_before", False) - args.mask_channel_selection = getattr(args, "mask_channel_selection", - "static") + args.mask_channel_selection = getattr(args, "mask_channel_selection", "static") args.mask_channel_other = getattr(args, "mask_channel_other", 0) - args.no_mask_channel_overlap = getattr(args, "no_mask_channel_overlap", - False) + args.no_mask_channel_overlap = getattr(args, "no_mask_channel_overlap", False) args.freeze_finetune_updates = getattr(args, "freeze_finetune_updates", 0) args.feature_grad_mult = 0.1 @@ -456,49 +516,43 @@ def set_default_adaptor_args(args): def set_default_mbart_decoder_args(args): - args.decoder_embed_path = getattr(args, 'decoder_embed_path', None) - args.decoder_embed_dim = getattr(args, 'decoder_embed_dim', 1024) - args.decoder_ffn_embed_dim = getattr(args, 'decoder_ffn_embed_dim', - 4 * 1024) - args.decoder_layers = getattr(args, 'decoder_layers', 12) - args.decoder_attention_heads = getattr(args, 'decoder_attention_heads', 16) - args.decoder_normalize_before = getattr(args, 'decoder_normalize_before', - True) - args.decoder_learned_pos = getattr(args, 'decoder_learned_pos', True) + args.decoder_embed_path = getattr(args, "decoder_embed_path", None) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4 * 1024) + args.decoder_layers = getattr(args, "decoder_layers", 12) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) args.adaptive_input = getattr(args, "adaptive_input", False) - args.decoder_attention_dropout = getattr(args, 'decoder_attention_dropout', - 0.) - args.decoder_activation_dropout = getattr(args, - 'decoder_activation_dropout', 0.) - args.decoder_dropout = getattr(args, 'decoder_dropout', 0.1) - args.adaptive_softmax_cutoff = getattr(args, 'adaptive_softmax_cutoff', - None) - args.adaptive_softmax_dropout = getattr(args, 'adaptive_softmax_dropout', 0) + args.decoder_attention_dropout = getattr(args, "decoder_attention_dropout", 0.0) + args.decoder_activation_dropout = getattr(args, "decoder_activation_dropout", 0.0) + args.decoder_dropout = getattr(args, "decoder_dropout", 0.1) + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) args.share_decoder_input_output_embed = getattr( - args, 'share_decoder_input_output_embed', True + args, "share_decoder_input_output_embed", True ) args.no_token_positional_embeddings = getattr( args, "no_token_positional_embeddings", False ) - args.decoder_output_dim = getattr(args, 'decoder_output_dim', - args.decoder_embed_dim) - args.decoder_input_dim = getattr(args, 'decoder_input_dim', - args.decoder_embed_dim) + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) - args.no_scale_embedding = getattr(args, 'no_scale_embedding', False) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) - args.layernorm_embedding = getattr(args, 'layernorm_embedding', True) + args.layernorm_embedding = getattr(args, "layernorm_embedding", True) - args.activation_fn = getattr(args, 'activation_fn', 'gelu') - args.pooler_activation_fn = getattr(args, 'pooler_activation_fn', 'tanh') - args.pooler_dropout = getattr(args, 'pooler_dropout', 0.0) + args.activation_fn = getattr(args, "activation_fn", "gelu") + args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") + args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) args.checkpoint_activations = getattr(args, "checkpoint_activations", False) -@register_model_architecture(model_name="xm_transformer", - arch_name="xm_transformer") +@register_model_architecture(model_name="xm_transformer", arch_name="xm_transformer") def base_architecture(args): set_default_w2v_encoder_args(args) set_default_adaptor_args(args) diff --git a/fairseq/models/text_to_speech/fastspeech2.py b/fairseq/models/text_to_speech/fastspeech2.py index 4fe9cc4d2a..f2a0792b17 100644 --- a/fairseq/models/text_to_speech/fastspeech2.py +++ b/fairseq/models/text_to_speech/fastspeech2.py @@ -8,10 +8,17 @@ import torch from torch import nn -from fairseq.models import (FairseqEncoder, FairseqEncoderModel, register_model, - register_model_architecture) +from fairseq.models import ( + FairseqEncoder, + FairseqEncoderModel, + register_model, + register_model_architecture, +) from fairseq.modules import ( - LayerNorm, PositionalEmbedding, FairseqDropout, MultiheadAttention + LayerNorm, + PositionalEmbedding, + FairseqDropout, + MultiheadAttention, ) from fairseq import utils from fairseq.data.data_utils import lengths_to_padding_mask @@ -36,11 +43,19 @@ class PositionwiseFeedForward(nn.Module): def __init__(self, in_dim, hidden_dim, kernel_size, dropout): super().__init__() self.ffn = nn.Sequential( - nn.Conv1d(in_dim, hidden_dim, kernel_size=kernel_size, - padding=(kernel_size - 1) // 2), + nn.Conv1d( + in_dim, + hidden_dim, + kernel_size=kernel_size, + padding=(kernel_size - 1) // 2, + ), nn.ReLU(), - nn.Conv1d(hidden_dim, in_dim, kernel_size=kernel_size, - padding=(kernel_size - 1) // 2) + nn.Conv1d( + hidden_dim, + in_dim, + kernel_size=kernel_size, + padding=(kernel_size - 1) // 2, + ), ) self.layer_norm = LayerNorm(in_dim) self.dropout = self.dropout_module = FairseqDropout( @@ -57,8 +72,7 @@ def forward(self, x): class FFTLayer(torch.nn.Module): def __init__( - self, embed_dim, n_heads, hidden_dim, kernel_size, dropout, - attention_dropout + self, embed_dim, n_heads, hidden_dim, kernel_size, dropout, attention_dropout ): super().__init__() self.self_attn = MultiheadAttention( @@ -74,8 +88,7 @@ def forward(self, x, padding_mask=None): residual = x x = x.transpose(0, 1) x, _ = self.self_attn( - query=x, key=x, value=x, key_padding_mask=padding_mask, - need_weights=False + query=x, key=x, value=x, key_padding_mask=padding_mask, need_weights=False ) x = x.transpose(0, 1) x = self.layer_norm(x + residual) @@ -106,11 +119,12 @@ def __init__(self, args): super().__init__() self.conv1 = nn.Sequential( nn.Conv1d( - args.encoder_embed_dim, args.var_pred_hidden_dim, + args.encoder_embed_dim, + args.var_pred_hidden_dim, kernel_size=args.var_pred_kernel_size, - padding=(args.var_pred_kernel_size - 1) // 2 + padding=(args.var_pred_kernel_size - 1) // 2, ), - nn.ReLU() + nn.ReLU(), ) self.ln1 = nn.LayerNorm(args.var_pred_hidden_dim) self.dropout_module = FairseqDropout( @@ -118,10 +132,12 @@ def __init__(self, args): ) self.conv2 = nn.Sequential( nn.Conv1d( - args.var_pred_hidden_dim, args.var_pred_hidden_dim, - kernel_size=args.var_pred_kernel_size, padding=1 + args.var_pred_hidden_dim, + args.var_pred_hidden_dim, + kernel_size=args.var_pred_kernel_size, + padding=1, ), - nn.ReLU() + nn.ReLU(), ) self.ln2 = nn.LayerNorm(args.var_pred_hidden_dim) self.proj = nn.Linear(args.var_pred_hidden_dim, 1) @@ -171,8 +187,15 @@ def get_energy_emb(self, x, tgt=None, factor=1.0): return out, emb def forward( - self, x, padding_mask, durations=None, pitches=None, energies=None, - d_factor=1.0, p_factor=1.0, e_factor=1.0 + self, + x, + padding_mask, + durations=None, + pitches=None, + energies=None, + d_factor=1.0, + p_factor=1.0, + e_factor=1.0, ): # x: B x T x C log_dur_out = self.duration_predictor(x) @@ -205,8 +228,7 @@ def __init__(self, args, src_dict, embed_speaker): self.spk_emb_proj = None if embed_speaker is not None: self.spk_emb_proj = nn.Linear( - args.encoder_embed_dim + args.speaker_embed_dim, - args.encoder_embed_dim + args.encoder_embed_dim + args.speaker_embed_dim, args.encoder_embed_dim ) self.dropout_module = FairseqDropout( @@ -224,9 +246,12 @@ def __init__(self, args, src_dict, embed_speaker): self.encoder_fft_layers = nn.ModuleList( FFTLayer( - args.encoder_embed_dim, args.encoder_attention_heads, - args.fft_hidden_dim, args.fft_kernel_size, - dropout=args.dropout, attention_dropout=args.attention_dropout + args.encoder_embed_dim, + args.encoder_attention_heads, + args.fft_hidden_dim, + args.fft_kernel_size, + dropout=args.dropout, + attention_dropout=args.attention_dropout, ) for _ in range(args.encoder_layers) ) @@ -235,9 +260,12 @@ def __init__(self, args, src_dict, embed_speaker): self.decoder_fft_layers = nn.ModuleList( FFTLayer( - args.decoder_embed_dim, args.decoder_attention_heads, - args.fft_hidden_dim, args.fft_kernel_size, - dropout=args.dropout, attention_dropout=args.attention_dropout + args.decoder_embed_dim, + args.decoder_attention_heads, + args.fft_hidden_dim, + args.fft_kernel_size, + dropout=args.dropout, + attention_dropout=args.attention_dropout, ) for _ in range(args.decoder_layers) ) @@ -247,15 +275,25 @@ def __init__(self, args, src_dict, embed_speaker): self.postnet = None if args.add_postnet: self.postnet = Postnet( - self.out_dim, args.postnet_conv_dim, + self.out_dim, + args.postnet_conv_dim, args.postnet_conv_kernel_size, - args.postnet_layers, args.postnet_dropout + args.postnet_layers, + args.postnet_dropout, ) self.apply(model_init) - def forward(self, src_tokens, src_lengths=None, speaker=None, - durations=None, pitches=None, energies=None, **kwargs): + def forward( + self, + src_tokens, + src_lengths=None, + speaker=None, + durations=None, + pitches=None, + energies=None, + **kwargs + ): x = self.embed_tokens(src_tokens) enc_padding_mask = src_tokens.eq(self.padding_idx) @@ -270,8 +308,9 @@ def forward(self, src_tokens, src_lengths=None, speaker=None, emb = self.embed_speaker(speaker).expand(bsz, seq_len, -1) x = self.spk_emb_proj(torch.cat([x, emb], dim=2)) - x, out_lens, log_dur_out, pitch_out, energy_out = \ - self.var_adaptor(x, enc_padding_mask, durations, pitches, energies) + x, out_lens, log_dur_out, pitch_out, energy_out = self.var_adaptor( + x, enc_padding_mask, durations, pitches, energies + ) dec_padding_mask = lengths_to_padding_mask(out_lens) x += self.dec_pos_emb_alpha * self.embed_positions(dec_padding_mask) @@ -326,7 +365,7 @@ def __init__(self, encoder, args, src_dict): out_dim = args.output_frame_dim * args.n_frames_per_step self.ctc_proj = None - if getattr(args, "ctc_weight", 0.) > 0.: + if getattr(args, "ctc_weight", 0.0) > 0.0: self.ctc_proj = nn.Linear(out_dim, len(src_dict)) @classmethod diff --git a/fairseq/models/text_to_speech/hifigan.py b/fairseq/models/text_to_speech/hifigan.py index edc7db6015..e30fe77f11 100644 --- a/fairseq/models/text_to_speech/hifigan.py +++ b/fairseq/models/text_to_speech/hifigan.py @@ -119,7 +119,7 @@ def __init__(self, cfg): self.ups = nn.ModuleList() for i, (u, k) in enumerate( - zip(cfg["upsample_rates"], cfg["upsample_kernel_sizes"]) + zip(cfg["upsample_rates"], cfg["upsample_kernel_sizes"]) ): self.ups.append( weight_norm( @@ -137,7 +137,7 @@ def __init__(self, cfg): for i in range(len(self.ups)): ch = cfg["upsample_initial_channel"] // (2 ** (i + 1)) for k, d in zip( - cfg["resblock_kernel_sizes"], cfg["resblock_dilation_sizes"] + cfg["resblock_kernel_sizes"], cfg["resblock_dilation_sizes"] ): self.resblocks.append(ResBlock(ch, k, d)) diff --git a/fairseq/models/text_to_speech/tacotron2.py b/fairseq/models/text_to_speech/tacotron2.py index bb327e81e7..4df4075617 100644 --- a/fairseq/models/text_to_speech/tacotron2.py +++ b/fairseq/models/text_to_speech/tacotron2.py @@ -9,9 +9,13 @@ from torch import nn from torch.nn import functional as F -from fairseq.models import (FairseqEncoder, FairseqEncoderDecoderModel, - FairseqIncrementalDecoder, register_model, - register_model_architecture) +from fairseq.models import ( + FairseqEncoder, + FairseqEncoderDecoderModel, + FairseqIncrementalDecoder, + register_model, + register_model_architecture, +) from fairseq.modules import LSTMCellWithZoneOut, LocationAttention @@ -31,29 +35,36 @@ def __init__(self, args, src_dict, embed_speaker): self.spk_emb_proj = None if embed_speaker is not None: self.spk_emb_proj = nn.Linear( - args.encoder_embed_dim + args.speaker_embed_dim, - args.encoder_embed_dim + args.encoder_embed_dim + args.speaker_embed_dim, args.encoder_embed_dim ) - self.embed_tokens = nn.Embedding(len(src_dict), args.encoder_embed_dim, - padding_idx=self.padding_idx) + self.embed_tokens = nn.Embedding( + len(src_dict), args.encoder_embed_dim, padding_idx=self.padding_idx + ) - assert(args.encoder_conv_kernel_size % 2 == 1) + assert args.encoder_conv_kernel_size % 2 == 1 self.convolutions = nn.ModuleList( nn.Sequential( - nn.Conv1d(args.encoder_embed_dim, args.encoder_embed_dim, - kernel_size=args.encoder_conv_kernel_size, - padding=((args.encoder_conv_kernel_size - 1) // 2)), + nn.Conv1d( + args.encoder_embed_dim, + args.encoder_embed_dim, + kernel_size=args.encoder_conv_kernel_size, + padding=((args.encoder_conv_kernel_size - 1) // 2), + ), nn.BatchNorm1d(args.encoder_embed_dim), nn.ReLU(), - nn.Dropout(args.encoder_dropout) + nn.Dropout(args.encoder_dropout), ) for _ in range(args.encoder_conv_layers) ) - self.lstm = nn.LSTM(args.encoder_embed_dim, args.encoder_embed_dim // 2, - num_layers=args.encoder_lstm_layers, - batch_first=True, bidirectional=True) + self.lstm = nn.LSTM( + args.encoder_embed_dim, + args.encoder_embed_dim // 2, + num_layers=args.encoder_lstm_layers, + batch_first=True, + bidirectional=True, + ) self.apply(encoder_init) @@ -78,7 +89,7 @@ def forward(self, src_tokens, src_lengths=None, speaker=None, **kwargs): return { "encoder_out": [x], # B x T x C - "encoder_padding_mask": encoder_padding_mask, # B x T + "encoder_padding_mask": encoder_padding_mask, # B x T } @@ -86,8 +97,7 @@ class Prenet(nn.Module): def __init__(self, in_dim, n_layers, n_units, dropout): super().__init__() self.layers = nn.ModuleList( - nn.Sequential(nn.Linear(in_dim if i == 0 else n_units, n_units), - nn.ReLU()) + nn.Sequential(nn.Linear(in_dim if i == 0 else n_units, n_units), nn.ReLU()) for i in range(n_layers) ) self.dropout = dropout @@ -102,20 +112,24 @@ class Postnet(nn.Module): def __init__(self, in_dim, n_channels, kernel_size, n_layers, dropout): super(Postnet, self).__init__() self.convolutions = nn.ModuleList() - assert(kernel_size % 2 == 1) + assert kernel_size % 2 == 1 for i in range(n_layers): - cur_layers = [ - nn.Conv1d(in_dim if i == 0 else n_channels, - n_channels if i < n_layers - 1 else in_dim, - kernel_size=kernel_size, - padding=((kernel_size - 1) // 2)), - nn.BatchNorm1d(n_channels if i < n_layers - 1 else in_dim) - ] + ([nn.Tanh()] if i < n_layers - 1 else []) + [nn.Dropout(dropout)] + cur_layers = ( + [ + nn.Conv1d( + in_dim if i == 0 else n_channels, + n_channels if i < n_layers - 1 else in_dim, + kernel_size=kernel_size, + padding=((kernel_size - 1) // 2), + ), + nn.BatchNorm1d(n_channels if i < n_layers - 1 else in_dim), + ] + + ([nn.Tanh()] if i < n_layers - 1 else []) + + [nn.Dropout(dropout)] + ) nn.init.xavier_uniform_( cur_layers[0].weight, - torch.nn.init.calculate_gain( - "tanh" if i < n_layers - 1 else "linear" - ) + torch.nn.init.calculate_gain("tanh" if i < n_layers - 1 else "linear"), ) self.convolutions.append(nn.Sequential(*cur_layers)) @@ -138,21 +152,25 @@ def __init__(self, args, src_dict): self.n_frames_per_step = args.n_frames_per_step self.out_dim = args.output_frame_dim * args.n_frames_per_step - self.prenet = Prenet(self.out_dim, args.prenet_layers, args.prenet_dim, - args.prenet_dropout) + self.prenet = Prenet( + self.out_dim, args.prenet_layers, args.prenet_dim, args.prenet_dropout + ) # take prev_context, prev_frame, (speaker embedding) as input self.attention_lstm = LSTMCellWithZoneOut( args.zoneout, args.prenet_dim + args.encoder_embed_dim, - args.decoder_lstm_dim + args.decoder_lstm_dim, ) # take attention_lstm output, attention_state, encoder_out as input self.attention = LocationAttention( - args.attention_dim, args.encoder_embed_dim, args.decoder_lstm_dim, + args.attention_dim, + args.encoder_embed_dim, + args.decoder_lstm_dim, (1 + int(args.attention_use_cumprob)), - args.attention_conv_dim, args.attention_conv_kernel_size + args.attention_conv_dim, + args.attention_conv_kernel_size, ) # take attention_lstm output, context, (gated_latent) as input @@ -160,7 +178,7 @@ def __init__(self, args, src_dict): LSTMCellWithZoneOut( args.zoneout, args.encoder_embed_dim + args.decoder_lstm_dim, - args.decoder_lstm_dim + args.decoder_lstm_dim, ) for i in range(args.decoder_lstm_layers) ) @@ -169,12 +187,16 @@ def __init__(self, args, src_dict): self.feat_proj = nn.Linear(proj_in_dim, self.out_dim) self.eos_proj = nn.Linear(proj_in_dim, 1) - self.postnet = Postnet(self.out_dim, args.postnet_conv_dim, - args.postnet_conv_kernel_size, - args.postnet_layers, args.postnet_dropout) + self.postnet = Postnet( + self.out_dim, + args.postnet_conv_dim, + args.postnet_conv_kernel_size, + args.postnet_layers, + args.postnet_dropout, + ) self.ctc_proj = None - if getattr(args, "ctc_weight", 0.) > 0.: + if getattr(args, "ctc_weight", 0.0) > 0.0: self.ctc_proj = nn.Linear(self.out_dim, len(src_dict)) self.apply(decoder_init) @@ -190,12 +212,16 @@ def _get_states(self, incremental_state, enc_out): lstm_h = self.get_incremental_state(incremental_state, "lstm_h") if lstm_h is None: - lstm_h = [enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) - for _ in range(self.args.decoder_lstm_layers)] + lstm_h = [ + enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) + for _ in range(self.args.decoder_lstm_layers) + ] lstm_c = self.get_incremental_state(incremental_state, "lstm_c") if lstm_c is None: - lstm_c = [enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) - for _ in range(self.args.decoder_lstm_layers)] + lstm_c = [ + enc_out.new_zeros(bsz, self.args.decoder_lstm_dim) + for _ in range(self.args.decoder_lstm_layers) + ] attn_w = self.get_incremental_state(incremental_state, "attn_w") if attn_w is None: @@ -216,8 +242,14 @@ def _get_init_attn_c(self, enc_out, enc_mask): else: raise ValueError(f"{self.args.init_attn_c} not supported") - def forward(self, prev_output_tokens, encoder_out=None, - incremental_state=None, target_lengths=None, **kwargs): + def forward( + self, + prev_output_tokens, + encoder_out=None, + incremental_state=None, + target_lengths=None, + **kwargs, + ): enc_mask = encoder_out["encoder_padding_mask"] enc_out = encoder_out["encoder_out"][0] in_len = enc_out.size(1) @@ -227,8 +259,9 @@ def forward(self, prev_output_tokens, encoder_out=None, bsz, out_len, _ = prev_output_tokens.size() prenet_out = self.prenet(prev_output_tokens) - (alstm_h, alstm_c, lstm_h, lstm_c, - attn_w, attn_w_cum) = self._get_states(incremental_state, enc_out) + (alstm_h, alstm_c, lstm_h, lstm_c, attn_w, attn_w_cum) = self._get_states( + incremental_state, enc_out + ) attn_ctx = self._get_init_attn_c(enc_out, enc_mask) attn_out = enc_out.new_zeros(bsz, in_len, out_len) @@ -241,9 +274,7 @@ def forward(self, prev_output_tokens, encoder_out=None, attn_state = attn_w.unsqueeze(1) if self.args.attention_use_cumprob: attn_state = torch.stack((attn_w, attn_w_cum), dim=1) - attn_ctx, attn_w = self.attention( - enc_out, enc_mask, alstm_h, attn_state - ) + attn_ctx, attn_w = self.attention(enc_out, enc_mask, alstm_h, attn_state) attn_w_cum = attn_w_cum + attn_w attn_out[:, :, t] = attn_w @@ -297,7 +328,7 @@ def add_args(parser): parser.add_argument("--postnet-conv-dim", type=int) parser.add_argument("--postnet-conv-kernel-size", type=int) parser.add_argument("--init-attn-c", type=str) - parser.add_argument("--attention-use-cumprob", action='store_true') + parser.add_argument("--attention-use-cumprob", action="store_true") parser.add_argument("--zoneout", type=float) parser.add_argument("--decoder-lstm-layers", type=int) parser.add_argument("--decoder-lstm-dim", type=int) @@ -333,8 +364,7 @@ def base_architecture(args): # decoder args.attention_dim = getattr(args, "attention_dim", 128) args.attention_conv_dim = getattr(args, "attention_conv_dim", 32) - args.attention_conv_kernel_size = getattr(args, - "attention_conv_kernel_size", 15) + args.attention_conv_kernel_size = getattr(args, "attention_conv_kernel_size", 15) args.prenet_dropout = getattr(args, "prenet_dropout", 0.5) args.prenet_layers = getattr(args, "prenet_layers", 2) args.prenet_dim = getattr(args, "prenet_dim", 256) diff --git a/fairseq/models/text_to_speech/tts_transformer.py b/fairseq/models/text_to_speech/tts_transformer.py index ff7af78bd4..32bdd3747a 100644 --- a/fairseq/models/text_to_speech/tts_transformer.py +++ b/fairseq/models/text_to_speech/tts_transformer.py @@ -9,12 +9,14 @@ import torch from torch import nn -from fairseq.models import (FairseqEncoder, FairseqEncoderDecoderModel, - FairseqIncrementalDecoder, register_model, - register_model_architecture) -from fairseq.modules import ( - TransformerEncoderLayer, TransformerDecoderLayer +from fairseq.models import ( + FairseqEncoder, + FairseqEncoderDecoderModel, + FairseqIncrementalDecoder, + register_model, + register_model_architecture, ) +from fairseq.modules import TransformerEncoderLayer, TransformerDecoderLayer from fairseq.models.text_to_speech.tacotron2 import Prenet, Postnet from fairseq.modules import LayerNorm, PositionalEmbedding, FairseqDropout from fairseq.data.data_utils import lengths_to_padding_mask @@ -42,30 +44,31 @@ def __init__(self, args, src_dict, embed_speaker): self.spk_emb_proj = None if embed_speaker is not None: self.spk_emb_proj = nn.Linear( - args.encoder_embed_dim + args.speaker_embed_dim, - args.encoder_embed_dim + args.encoder_embed_dim + args.speaker_embed_dim, args.encoder_embed_dim ) self.dropout_module = FairseqDropout( p=args.dropout, module_name=self.__class__.__name__ ) - self.embed_tokens = nn.Embedding(len(src_dict), args.encoder_embed_dim, - padding_idx=self.padding_idx) - assert(args.encoder_conv_kernel_size % 2 == 1) + self.embed_tokens = nn.Embedding( + len(src_dict), args.encoder_embed_dim, padding_idx=self.padding_idx + ) + assert args.encoder_conv_kernel_size % 2 == 1 self.prenet = nn.ModuleList( nn.Sequential( - nn.Conv1d(args.encoder_embed_dim, args.encoder_embed_dim, - kernel_size=args.encoder_conv_kernel_size, - padding=((args.encoder_conv_kernel_size - 1) // 2)), + nn.Conv1d( + args.encoder_embed_dim, + args.encoder_embed_dim, + kernel_size=args.encoder_conv_kernel_size, + padding=((args.encoder_conv_kernel_size - 1) // 2), + ), nn.BatchNorm1d(args.encoder_embed_dim), nn.ReLU(), nn.Dropout(args.encoder_dropout), ) for _ in range(args.encoder_conv_layers) ) - self.prenet_proj = nn.Linear( - args.encoder_embed_dim, args.encoder_embed_dim - ) + self.prenet_proj = nn.Linear(args.encoder_embed_dim, args.encoder_embed_dim) self.embed_positions = PositionalEmbedding( args.max_source_positions, args.encoder_embed_dim, self.padding_idx ) @@ -112,7 +115,9 @@ def forward(self, src_tokens, src_lengths=None, speaker=None, **kwargs): return { "encoder_out": [x], # T x B x C - "encoder_padding_mask": [padding_mask] if padding_mask.any() else [], # B x T + "encoder_padding_mask": [padding_mask] + if padding_mask.any() + else [], # B x T "encoder_embedding": [], # B x T x C "encoder_states": [], # List[T x B x C] "src_tokens": [], @@ -143,15 +148,15 @@ def __init__(self, args, src_dict): ) self.pos_emb_alpha = nn.Parameter(torch.ones(1)) self.prenet = nn.Sequential( - Prenet(self.out_dim, args.prenet_layers, args.prenet_dim, - args.prenet_dropout), + Prenet( + self.out_dim, args.prenet_layers, args.prenet_dim, args.prenet_dropout + ), nn.Linear(args.prenet_dim, args.decoder_embed_dim), ) self.n_transformer_layers = args.decoder_transformer_layers self.transformer_layers = nn.ModuleList( - TransformerDecoderLayer(args) - for _ in range(self.n_transformer_layers) + TransformerDecoderLayer(args) for _ in range(self.n_transformer_layers) ) if args.decoder_normalize_before: self.layer_norm = LayerNorm(args.decoder_embed_dim) @@ -161,19 +166,28 @@ def __init__(self, args, src_dict): self.feat_proj = nn.Linear(args.decoder_embed_dim, self.out_dim) self.eos_proj = nn.Linear(args.decoder_embed_dim, 1) - self.postnet = Postnet(self.out_dim, args.postnet_conv_dim, - args.postnet_conv_kernel_size, - args.postnet_layers, args.postnet_dropout) + self.postnet = Postnet( + self.out_dim, + args.postnet_conv_dim, + args.postnet_conv_kernel_size, + args.postnet_layers, + args.postnet_dropout, + ) self.ctc_proj = None - if getattr(args, "ctc_weight", 0.) > 0.: + if getattr(args, "ctc_weight", 0.0) > 0.0: self.ctc_proj = nn.Linear(self.out_dim, len(src_dict)) self.apply(decoder_init) def extract_features( - self, prev_outputs, encoder_out=None, incremental_state=None, - target_lengths=None, speaker=None, **kwargs + self, + prev_outputs, + encoder_out=None, + incremental_state=None, + target_lengths=None, + speaker=None, + **kwargs ): alignment_layer = self.n_transformer_layers - 1 self_attn_padding_mask = lengths_to_padding_mask(target_lengths) @@ -212,8 +226,8 @@ def extract_features( else None, encoder_out["encoder_padding_mask"][0] if ( - encoder_out is not None - and len(encoder_out["encoder_padding_mask"]) > 0 + encoder_out is not None + and len(encoder_out["encoder_padding_mask"]) > 0 ) else None, incremental_state, @@ -239,13 +253,22 @@ def extract_features( return x, {"attn": attn, "inner_states": inner_states} - def forward(self, prev_output_tokens, encoder_out=None, - incremental_state=None, target_lengths=None, speaker=None, - **kwargs): + def forward( + self, + prev_output_tokens, + encoder_out=None, + incremental_state=None, + target_lengths=None, + speaker=None, + **kwargs + ): x, extra = self.extract_features( - prev_output_tokens, encoder_out=encoder_out, - incremental_state=incremental_state, target_lengths=target_lengths, - speaker=speaker, **kwargs + prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + target_lengths=target_lengths, + speaker=speaker, + **kwargs ) attn = extra["attn"] feat_out = self.feat_proj(x) @@ -328,8 +351,9 @@ def build_model(cls, args, task): return cls(encoder, decoder) def forward_encoder(self, src_tokens, src_lengths, speaker=None, **kwargs): - return self.encoder(src_tokens, src_lengths=src_lengths, - speaker=speaker, **kwargs) + return self.encoder( + src_tokens, src_lengths=src_lengths, speaker=speaker, **kwargs + ) def set_num_updates(self, num_updates): super().set_num_updates(num_updates) @@ -348,7 +372,9 @@ def base_architecture(args): # encoder transformer layers args.encoder_transformer_layers = getattr(args, "encoder_transformer_layers", 6) args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) - args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4 * args.encoder_embed_dim) + args.encoder_ffn_embed_dim = getattr( + args, "encoder_ffn_embed_dim", 4 * args.encoder_embed_dim + ) args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) args.attention_dropout = getattr(args, "attention_dropout", 0.0) @@ -366,6 +392,8 @@ def base_architecture(args): # decoder transformer layers args.decoder_transformer_layers = getattr(args, "decoder_transformer_layers", 6) args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) - args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4 * args.decoder_embed_dim) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", 4 * args.decoder_embed_dim + ) args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index 65d9f9f06b..af3042eeea 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -13,7 +13,10 @@ import torch.nn.functional as F from fairseq.data.audio.audio_utils import ( - get_window, get_fourier_basis, get_mel_filters, TTSSpectrogram + get_window, + get_fourier_basis, + get_mel_filters, + TTSSpectrogram, ) from fairseq.data.audio.speech_to_text_dataset import S2TDataConfig from fairseq.models.text_to_speech.hifigan import Generator as HiFiGANModel @@ -25,11 +28,9 @@ class PseudoInverseMelScale(torch.nn.Module): def __init__(self, n_stft, n_mels, sample_rate, f_min, f_max) -> None: super(PseudoInverseMelScale, self).__init__() self.n_mels = n_mels - basis = get_mel_filters( - sample_rate, (n_stft - 1) * 2, n_mels, f_min, f_max - ) + basis = get_mel_filters(sample_rate, (n_stft - 1) * 2, n_mels, f_min, f_max) basis = torch.pinverse(basis) # F x F_mel - self.register_buffer('basis', basis) + self.register_buffer("basis", basis) def forward(self, melspec: torch.Tensor) -> torch.Tensor: # pack batch @@ -48,8 +49,12 @@ def forward(self, melspec: torch.Tensor) -> torch.Tensor: class GriffinLim(torch.nn.Module): def __init__( - self, n_fft: int, win_length: int, hop_length: int, n_iter: int, - window_fn=torch.hann_window + self, + n_fft: int, + win_length: int, + hop_length: int, + n_iter: int, + window_fn=torch.hann_window, ): super(GriffinLim, self).__init__() self.transform = TTSSpectrogram( @@ -59,7 +64,7 @@ def __init__( basis = get_fourier_basis(n_fft) basis = torch.pinverse(n_fft / hop_length * basis).T[:, None, :] basis *= get_window(window_fn, n_fft, win_length) - self.register_buffer('basis', basis) + self.register_buffer("basis", basis) self.n_fft = n_fft self.win_length = win_length @@ -70,33 +75,33 @@ def __init__( @classmethod def get_window_sum_square( - cls, n_frames, hop_length, win_length, n_fft, - window_fn=torch.hann_window + cls, n_frames, hop_length, win_length, n_fft, window_fn=torch.hann_window ) -> torch.Tensor: w_sq = get_window(window_fn, n_fft, win_length) ** 2 n = n_fft + hop_length * (n_frames - 1) x = torch.zeros(n, dtype=torch.float32) for i in range(n_frames): ofst = i * hop_length - x[ofst: min(n, ofst + n_fft)] += w_sq[:max(0, min(n_fft, n - ofst))] + x[ofst : min(n, ofst + n_fft)] += w_sq[: max(0, min(n_fft, n - ofst))] return x def inverse(self, magnitude: torch.Tensor, phase) -> torch.Tensor: x = torch.cat( - [magnitude * torch.cos(phase), magnitude * torch.sin(phase)], - dim=1 + [magnitude * torch.cos(phase), magnitude * torch.sin(phase)], dim=1 ) x = F.conv_transpose1d(x, self.basis, stride=self.hop_length) win_sum_sq = self.get_window_sum_square( - magnitude.shape[-1], hop_length=self.hop_length, - win_length=self.win_length, n_fft=self.n_fft + magnitude.shape[-1], + hop_length=self.hop_length, + win_length=self.win_length, + n_fft=self.n_fft, ).to(magnitude.device) # remove modulation effects approx_nonzero_indices = win_sum_sq > self.tiny x[:, :, approx_nonzero_indices] /= win_sum_sq[approx_nonzero_indices] x *= self.n_fft / self.hop_length - x = x[:, :, self.n_fft // 2:] - x = x[:, :, :-self.n_fft // 2:] + x = x[:, :, self.n_fft // 2 :] + x = x[:, :, : -self.n_fft // 2 :] return x def forward(self, specgram: torch.Tensor) -> torch.Tensor: @@ -111,18 +116,33 @@ def forward(self, specgram: torch.Tensor) -> torch.Tensor: class GriffinLimVocoder(nn.Module): - def __init__(self, sample_rate, win_size, hop_size, n_fft, - n_mels, f_min, f_max, window_fn, - spec_bwd_max_iter=32, - fp16=False): + def __init__( + self, + sample_rate, + win_size, + hop_size, + n_fft, + n_mels, + f_min, + f_max, + window_fn, + spec_bwd_max_iter=32, + fp16=False, + ): super().__init__() self.inv_mel_transform = PseudoInverseMelScale( - n_stft=n_fft // 2 + 1, n_mels=n_mels, sample_rate=sample_rate, - f_min=f_min, f_max=f_max + n_stft=n_fft // 2 + 1, + n_mels=n_mels, + sample_rate=sample_rate, + f_min=f_min, + f_max=f_max, ) self.gl_transform = GriffinLim( - n_fft=n_fft, win_length=win_size, hop_length=hop_size, - window_fn=window_fn, n_iter=spec_bwd_max_iter + n_fft=n_fft, + win_length=win_size, + hop_length=hop_size, + window_fn=window_fn, + n_iter=spec_bwd_max_iter, ) if fp16: self.half() @@ -151,17 +171,19 @@ def from_data_cfg(cls, args, data_cfg: S2TDataConfig): sample_rate=feat_cfg["sample_rate"], win_size=int(feat_cfg["win_len_t"] * feat_cfg["sample_rate"]), hop_size=int(feat_cfg["hop_len_t"] * feat_cfg["sample_rate"]), - n_fft=feat_cfg["n_fft"], n_mels=feat_cfg["n_mels"], - f_min=feat_cfg["f_min"], f_max=feat_cfg["f_max"], - window_fn=window_fn, spec_bwd_max_iter=args.spec_bwd_max_iter, - fp16=args.fp16 + n_fft=feat_cfg["n_fft"], + n_mels=feat_cfg["n_mels"], + f_min=feat_cfg["f_min"], + f_max=feat_cfg["f_max"], + window_fn=window_fn, + spec_bwd_max_iter=args.spec_bwd_max_iter, + fp16=args.fp16, ) class HiFiGANVocoder(nn.Module): def __init__( - self, checkpoint_path: str, model_cfg: Dict[str, str], - fp16: bool = False + self, checkpoint_path: str, model_cfg: Dict[str, str], fp16: bool = False ) -> None: super().__init__() self.model = HiFiGANModel(model_cfg) diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py index 49e37917cc..5046fa24fc 100644 --- a/fairseq/models/transformer/transformer_decoder.py +++ b/fairseq/models/transformer/transformer_decoder.py @@ -29,8 +29,8 @@ # rewrite name for backward compatibility in `make_generation_fast_` def module_name_fordropout(module_name: str) -> str: - if module_name == 'TransformerDecoderBase': - return 'TransformerDecoder' + if module_name == "TransformerDecoderBase": + return "TransformerDecoder" else: return module_name diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index f007776a6f..578f03d9de 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -29,8 +29,8 @@ # rewrite name for backward compatibility in `make_generation_fast_` def module_name_fordropout(module_name: str) -> str: - if module_name == 'TransformerEncoderBase': - return 'TransformerEncoder' + if module_name == "TransformerEncoderBase": + return "TransformerEncoder" else: return module_name @@ -232,7 +232,12 @@ def forward_scriptable( # `forward` so we use a dictionary instead. # TorchScript does not support mixed values so the values are all lists. # The empty list is equivalent to None. - src_lengths = src_tokens.ne(self.padding_idx).sum(dim=1, dtype=torch.int32).reshape(-1, 1).contiguous() + src_lengths = ( + src_tokens.ne(self.padding_idx) + .sum(dim=1, dtype=torch.int32) + .reshape(-1, 1) + .contiguous() + ) return { "encoder_out": [x], # T x B x C "encoder_padding_mask": [encoder_padding_mask], # B x T diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index 14cbb089fd..f029cf05de 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -15,7 +15,9 @@ register_model_architecture, ) from fairseq.models.transformer import ( - DEFAULT_MIN_PARAMS_TO_WRAP, Embedding, TransformerDecoder + DEFAULT_MIN_PARAMS_TO_WRAP, + Embedding, + TransformerDecoder, ) from fairseq.modules import AdaptiveInput, CharacterTokenEmbedder from fairseq.utils import safe_getattr, safe_hasattr @@ -179,7 +181,7 @@ class TransformerLanguageModelConfig(FairseqDataclass): "is set to 0 (i.e., always wrap) when --checkpoint-activations or " "--offload-activations are passed." ) - } + }, ) # config for "BASE Layers: Simplifying Training of Large, Sparse Models" base_layers: Optional[int] = field( @@ -189,13 +191,25 @@ class TransformerLanguageModelConfig(FairseqDataclass): default=1, metadata={"help": "number of sublayers in each BASE layer"} ) base_shuffle: Optional[int] = field( - default=1, metadata={"help": "shuffle tokens between workers before computing assignment"} + default=1, + metadata={"help": "shuffle tokens between workers before computing assignment"}, ) # NormFormer - scale_fc: Optional[bool] = field(default=False, metadata={"help": 'Insert LayerNorm between fully connected layers'}) - scale_attn: Optional[bool] = field(default=False, metadata={"help": 'Insert LayerNorm after attention'}) - scale_heads: Optional[bool] = field(default=False, metadata={"help": 'Learn a scale coefficient for each attention head'}) - scale_resids: Optional[bool] = field(default=False, metadata={"help": 'Learn a scale coefficient for each residual connection'}) + scale_fc: Optional[bool] = field( + default=False, + metadata={"help": "Insert LayerNorm between fully connected layers"}, + ) + scale_attn: Optional[bool] = field( + default=False, metadata={"help": "Insert LayerNorm after attention"} + ) + scale_heads: Optional[bool] = field( + default=False, + metadata={"help": "Learn a scale coefficient for each attention head"}, + ) + scale_resids: Optional[bool] = field( + default=False, + metadata={"help": "Learn a scale coefficient for each residual connection"}, + ) # options from other parts of the config add_bos_token: bool = II("task.add_bos_token") tokens_per_sample: int = II("task.tokens_per_sample") @@ -345,7 +359,9 @@ def base_lm_architecture(args): args.decoder_output_dim = safe_getattr( args, "decoder_output_dim", args.decoder_embed_dim ) - args.decoder_input_dim = safe_getattr(args, "decoder_input_dim", args.decoder_embed_dim) + args.decoder_input_dim = safe_getattr( + args, "decoder_input_dim", args.decoder_embed_dim + ) # Model training is not stable without this args.decoder_normalize_before = True @@ -362,10 +378,10 @@ def base_lm_architecture(args): args.layernorm_embedding = safe_getattr(args, "layernorm_embedding", False) args.checkpoint_activations = safe_getattr(args, "checkpoint_activations", False) args.offload_activations = safe_getattr(args, "offload_activations", False) - args.scale_fc = safe_getattr(args, 'scale_fc', False) - args.scale_attn = safe_getattr(args, 'scale_attn', False) - args.scale_heads = safe_getattr(args, 'scale_heads', False) - args.scale_resids = safe_getattr(args, 'scale_resids', False) + args.scale_fc = safe_getattr(args, "scale_fc", False) + args.scale_attn = safe_getattr(args, "scale_attn", False) + args.scale_heads = safe_getattr(args, "scale_heads", False) + args.scale_resids = safe_getattr(args, "scale_resids", False) if args.offload_activations: args.checkpoint_activations = True @@ -387,7 +403,9 @@ def transformer_lm_baevski_wiki103(args): args.dropout = safe_getattr(args, "dropout", 0.3) args.adaptive_input = safe_getattr(args, "adaptive_input", True) args.tie_adaptive_weights = safe_getattr(args, "tie_adaptive_weights", True) - args.adaptive_input_cutoff = safe_getattr(args, "adaptive_input_cutoff", "20000,60000") + args.adaptive_input_cutoff = safe_getattr( + args, "adaptive_input_cutoff", "20000,60000" + ) args.adaptive_softmax_cutoff = safe_getattr( args, "adaptive_softmax_cutoff", "20000,60000" ) @@ -472,7 +490,9 @@ def transformer_lm_gpt2_big(args): def base_gpt3_architecture(args): args.decoder_input_dim = args.decoder_embed_dim args.decoder_output_dim = args.decoder_embed_dim - args.decoder_ffn_embed_dim = safe_getattr(args, "decoder_ffn_embed_dim", args.decoder_embed_dim * 4) + args.decoder_ffn_embed_dim = safe_getattr( + args, "decoder_ffn_embed_dim", args.decoder_embed_dim * 4 + ) # GPT-3 used learned positional embeddings, rather than sinusoidal args.decoder_learned_pos = safe_getattr(args, "decoder_learned_pos", True) args.dropout = safe_getattr(args, "dropout", 0.0) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index af722a5318..6431ccb964 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -232,9 +232,11 @@ class Wav2Vec2Config(FairseqDataclass): ) checkpoint_activations: bool = field( - default=False, metadata={"help": "recompute activations and save memory for extra compute"} + default=False, + metadata={"help": "recompute activations and save memory for extra compute"}, ) + @register_model("wav2vec2", dataclass=Wav2Vec2Config) class Wav2Vec2Model(BaseFairseqModel): def __init__(self, cfg: Wav2Vec2Config): @@ -844,14 +846,14 @@ def __init__(self, args): layers = [] for _ in range(args.encoder_layers): layer = TransformerSentenceEncoderLayer( - embedding_dim=self.embedding_dim, - ffn_embedding_dim=args.encoder_ffn_embed_dim, - num_attention_heads=args.encoder_attention_heads, - dropout=self.dropout, - attention_dropout=args.attention_dropout, - activation_dropout=args.activation_dropout, - activation_fn=args.activation_fn, - layer_norm_first=args.layer_norm_first, + embedding_dim=self.embedding_dim, + ffn_embedding_dim=args.encoder_ffn_embed_dim, + num_attention_heads=args.encoder_attention_heads, + dropout=self.dropout, + attention_dropout=args.attention_dropout, + activation_dropout=args.activation_dropout, + activation_fn=args.activation_fn, + layer_norm_first=args.layer_norm_first, ) if args.checkpoint_activations: layer = fsdp_wrap(layer) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 612db5d95f..ed40f6d8fe 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -152,10 +152,12 @@ class Wav2Vec2AsrConfig(FairseqDataclass): w2v_args: Any = None checkpoint_activations: bool = field( - default=False, metadata={"help": "recompute activations and save memory for extra compute"} + default=False, + metadata={"help": "recompute activations and save memory for extra compute"}, ) ddp_backend: str = II("distributed_training.ddp_backend") + @dataclass class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): blank_weight: float = 0 @@ -268,6 +270,7 @@ class Wav2Vec2Seq2SeqConfig(Wav2Vec2AsrConfig): ) autoregressive: bool = II("task.autoregressive") + @register_model("wav2vec_seq2seq", dataclass=Wav2Vec2Seq2SeqConfig) class Wav2Vec2Seq2SeqModel(FairseqEncoderDecoderModel): def __init__(self, encoder, decoder): @@ -394,12 +397,17 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): def load_model_weights(self, state, model, cfg): if cfg.ddp_backend == "fully_sharded": from fairseq.distributed import FullyShardedDataParallel + for name, module in model.named_modules(): if "encoder.layers" in name and len(name.split(".")) == 3: # Only for layers, we do a special handling and load the weights one by one # We dont load all weights together as that wont be memory efficient and may # cause oom - new_dict = {k.replace(name+".", "") : v for (k, v) in state["model"].items() if name+"." in k} + new_dict = { + k.replace(name + ".", ""): v + for (k, v) in state["model"].items() + if name + "." in k + } assert isinstance(module, FullyShardedDataParallel) with module.summon_full_params(): module.load_state_dict(new_dict, strict=True) @@ -409,7 +417,9 @@ def load_model_weights(self, state, model, cfg): r = re.compile("encoder.layers.\d.") filtered_list = list(filter(r.match, state["model"].keys())) - new_big_dict = {k: v for (k, v) in state["model"].items() if k not in filtered_list} + new_big_dict = { + k: v for (k, v) in state["model"].items() if k not in filtered_list + } model.load_state_dict(new_big_dict, strict=False) else: @@ -462,9 +472,9 @@ def reorder_encoder_out(self, encoder_out, new_order): 1, new_order ) if encoder_out["padding_mask"] is not None: - encoder_out["padding_mask"] = encoder_out[ - "padding_mask" - ].index_select(0, new_order) + encoder_out["padding_mask"] = encoder_out["padding_mask"].index_select( + 0, new_order + ) return encoder_out def max_positions(self): @@ -640,7 +650,7 @@ def extract_features( self_attn_mask=self.buffered_future_mask(x) if incremental_state is None else None, - self_attn_padding_mask=self_attn_padding_mask + self_attn_padding_mask=self_attn_padding_mask, ) inner_states.append(x) diff --git a/fairseq/modules/base_layer.py b/fairseq/modules/base_layer.py index e7ef155b25..e823f7bae2 100644 --- a/fairseq/modules/base_layer.py +++ b/fairseq/modules/base_layer.py @@ -12,14 +12,17 @@ class BaseLayer(nn.Module): - def __init__(self, args): super().__init__() self.num_workers = distributed_utils.get_data_parallel_world_size() expert_centroids = torch.empty(self.num_workers, args.decoder_embed_dim) torch.nn.init.orthogonal_(expert_centroids, gain=0.1) - self.register_parameter("expert_centroids", torch.nn.Parameter(expert_centroids)) - self.expert_network = nn.Sequential(*([BaseSublayer(args) for _ in range(args.base_sublayers)])) + self.register_parameter( + "expert_centroids", torch.nn.Parameter(expert_centroids) + ) + self.expert_network = nn.Sequential( + *([BaseSublayer(args) for _ in range(args.base_sublayers)]) + ) self.expert_id = distributed_utils.get_data_parallel_rank() self.shuffle = args.base_shuffle self.cpp = self.load_assignment() @@ -39,20 +42,34 @@ def forward(self, input_features, *args, **kwargs): with torch.no_grad(): # Compute similarity of each token to each expert, for routing - token_expert_affinities = features.matmul(self.expert_centroids.transpose(0, 1)) + token_expert_affinities = features.matmul( + self.expert_centroids.transpose(0, 1) + ) # Compute which token goes to which expert - sort_by_expert, input_splits, output_splits = self.balanced_assignment(token_expert_affinities) \ - if is_training else self.greedy_assignment(token_expert_affinities) + sort_by_expert, input_splits, output_splits = ( + self.balanced_assignment(token_expert_affinities) + if is_training + else self.greedy_assignment(token_expert_affinities) + ) # Swap these tokens for the right ones for our expert - routed_features = All2All.apply(features[sort_by_expert], output_splits, input_splits) + routed_features = All2All.apply( + features[sort_by_expert], output_splits, input_splits + ) if routed_features.size(0) > 0: # Mix in the expert network based on how appropriate it is for these tokens - alpha = torch.sigmoid(routed_features.mv(self.expert_centroids[self.expert_id])).unsqueeze(1) - routed_features = alpha * self.expert_network(routed_features) + (1 - alpha) * routed_features + alpha = torch.sigmoid( + routed_features.mv(self.expert_centroids[self.expert_id]) + ).unsqueeze(1) + routed_features = ( + alpha * self.expert_network(routed_features) + + (1 - alpha) * routed_features + ) # Return to original worker and ordering - result = All2All.apply(routed_features, input_splits, output_splits)[self.inverse_sort(sort_by_expert)] + result = All2All.apply(routed_features, input_splits, output_splits)[ + self.inverse_sort(sort_by_expert) + ] if self.shuffle and is_training: # Undo shuffling @@ -63,7 +80,9 @@ def forward(self, input_features, *args, **kwargs): def inverse_sort(self, order): # Creates an index that undoes a sort: xs==xs[order][inverse_sort(order)] - return torch.empty_like(order).scatter_(0, order, torch.arange(0, order.size(0), device=order.device)) + return torch.empty_like(order).scatter_( + 0, order, torch.arange(0, order.size(0), device=order.device) + ) def balanced_assignment(self, scores): ok = scores.isfinite() @@ -79,7 +98,9 @@ def greedy_assignment(self, scores, k=1): worker2token = sort_ordering // k # Find how many tokens we're sending to each other worker (being careful for sending 0 tokens to some workers) - output_splits = torch.zeros((self.num_workers,), dtype=torch.long, device=scores.device) + output_splits = torch.zeros( + (self.num_workers,), dtype=torch.long, device=scores.device + ) workers, counts = torch.unique_consecutive(token_to_workers, return_counts=True) output_splits[workers] = counts # Tell other workers how many tokens to expect from us @@ -103,7 +124,7 @@ class BaseSublayer(nn.Module): def __init__(self, args): super().__init__() self.activation_fn = utils.get_activation_fn( - activation=getattr(args, 'activation_fn', 'relu') or "relu" + activation=getattr(args, "activation_fn", "relu") or "relu" ) self.norm = LayerNorm(args.decoder_embed_dim, export=False) self.ff1 = torch.nn.Linear(args.decoder_embed_dim, args.decoder_ffn_embed_dim) @@ -121,15 +142,29 @@ def forward(ctx, xs, input_splits=None, output_splits=None): ctx.input_splits = input_splits ctx.output_splits = output_splits - ys = torch.empty_like(xs) if output_splits is None else \ - xs.new_empty(size=[sum(output_splits)] + list(xs.size()[1:])) - torch.distributed.all_to_all_single(ys, xs, output_split_sizes=output_splits, input_split_sizes=input_splits) + ys = ( + torch.empty_like(xs) + if output_splits is None + else xs.new_empty(size=[sum(output_splits)] + list(xs.size()[1:])) + ) + torch.distributed.all_to_all_single( + ys, xs, output_split_sizes=output_splits, input_split_sizes=input_splits + ) return ys @staticmethod def backward(ctx, grad_output): - result = torch.empty_like(grad_output) if ctx.input_splits is None else \ - grad_output.new_empty(size=[sum(ctx.input_splits)] + list(grad_output.size()[1:])) - torch.distributed.all_to_all_single(result, grad_output, - output_split_sizes=ctx.input_splits, input_split_sizes=ctx.output_splits) + result = ( + torch.empty_like(grad_output) + if ctx.input_splits is None + else grad_output.new_empty( + size=[sum(ctx.input_splits)] + list(grad_output.size()[1:]) + ) + ) + torch.distributed.all_to_all_single( + result, + grad_output, + output_split_sizes=ctx.input_splits, + input_split_sizes=ctx.output_splits, + ) return result, None, None diff --git a/fairseq/modules/checkpoint_activations.py b/fairseq/modules/checkpoint_activations.py index dc73c662e2..aa0b5929a3 100644 --- a/fairseq/modules/checkpoint_activations.py +++ b/fairseq/modules/checkpoint_activations.py @@ -166,7 +166,9 @@ def forward(ctx, run_function, parent_ctx_dict, kwarg_keys, *args): if parent_ctx_dict["offload"]: ctx.fwd_device = tuple(x.device for x in tensor_inputs) ctx.grad_requirements = tuple(x.requires_grad for x in tensor_inputs) - tensor_inputs = tuple(x.to(torch.device("cpu"), non_blocking=True) for x in tensor_inputs) + tensor_inputs = tuple( + x.to(torch.device("cpu"), non_blocking=True) for x in tensor_inputs + ) else: ctx.fwd_device, ctx.grad_requirements = None, None @@ -199,7 +201,8 @@ def backward(ctx, *args): tensor_inputs = checkpoint.detach_variable(tensor_inputs) if ctx.fwd_device is not None: tensor_inputs = [ - t.to(ctx.fwd_device[i], non_blocking=True) for i, t in enumerate(tensor_inputs) + t.to(ctx.fwd_device[i], non_blocking=True) + for i, t in enumerate(tensor_inputs) ] for i, need_grad in enumerate(ctx.grad_requirements): tensor_inputs[i].requires_grad = need_grad diff --git a/fairseq/modules/gumbel_vector_quantizer.py b/fairseq/modules/gumbel_vector_quantizer.py index 7113438888..a0e40c36dc 100644 --- a/fairseq/modules/gumbel_vector_quantizer.py +++ b/fairseq/modules/gumbel_vector_quantizer.py @@ -75,6 +75,7 @@ def block(input_dim, output_dim): if isinstance(temp, str): import ast + temp = ast.literal_eval(temp) assert len(temp) == 3, f"{temp}, {len(temp)}" diff --git a/fairseq/modules/kmeans_attention.py b/fairseq/modules/kmeans_attention.py index 11a7debcf2..ca5063010a 100644 --- a/fairseq/modules/kmeans_attention.py +++ b/fairseq/modules/kmeans_attention.py @@ -47,11 +47,12 @@ def cached_fn(*args, **kwargs): return cache cache = f(*args, **kwargs) return cache + return cached_fn def to(t): - return {'device': t.device, 'dtype': t.dtype} + return {"device": t.device, "dtype": t.dtype} def find_modules(nn_module, type): @@ -102,7 +103,7 @@ def reshape_dim(t, dim, split_dims): shape = list(t.shape) num_dims = len(shape) dim = (dim + num_dims) % num_dims - shape[dim:dim+1] = split_dims + shape[dim : dim + 1] = split_dims return t.reshape(shape) @@ -118,6 +119,7 @@ def ema_inplace(moving_avg, new, decay): return moving_avg.data.mul_(decay).add_(new, alpha=(1 - decay)) + # helper classes @@ -173,6 +175,7 @@ def forward(self, x): def norm(t): n = torch.norm(t, dim=-1, keepdim=True).clamp(min=self.eps) return t / n * self.g + return map_first_tuple_or_el(x, norm) @@ -202,51 +205,62 @@ def forward(self, x): tensor = tensor.t() return x @ tensor + # positional embeddings class DepthWiseConv1d(nn.Module): def __init__(self, dim_in, dim_out, kernel_size, stride=1, bias=True, causal=False): super().__init__() - self.padding = ((kernel_size - 1), 0) if causal else (kernel_size // 2, kernel_size // 2) + self.padding = ( + ((kernel_size - 1), 0) if causal else (kernel_size // 2, kernel_size // 2) + ) self.net = nn.Sequential( - nn.Conv1d(dim_in, dim_in, kernel_size=kernel_size, groups=dim_in, stride=stride, bias=bias), - nn.Conv1d(dim_in, dim_out, 1, bias=bias) + nn.Conv1d( + dim_in, + dim_in, + kernel_size=kernel_size, + groups=dim_in, + stride=stride, + bias=bias, + ), + nn.Conv1d(dim_in, dim_out, 1, bias=bias), ) def forward(self, x): - x = F.pad(x, self.padding, value=0.) + x = F.pad(x, self.padding, value=0.0) return self.net(x) class FixedPositionalEmbedding(nn.Module): def __init__(self, dim, max_seq_len): super().__init__() - inv_freq = 1. / (10000 ** (torch.arange(0, dim, 2).float() / dim)) + inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2).float() / dim)) position = torch.arange(0, max_seq_len, dtype=torch.float) sinusoid_inp = torch.einsum("i,j->ij", position, inv_freq) emb = torch.cat((sinusoid_inp.sin(), sinusoid_inp.cos()), dim=-1) - self.register_buffer('emb', emb) + self.register_buffer("emb", emb) def forward(self, x): - return self.emb[None, :x.shape[1], :].to(x) + return self.emb[None, : x.shape[1], :].to(x) def rotate_every_two(x): - x = rearrange(x, '... (d j) -> ... d j', j=2) + x = rearrange(x, "... (d j) -> ... d j", j=2) x1, x2 = x.unbind(dim=-1) x = torch.stack((-x2, x1), dim=-1) - return rearrange(x, '... d j -> ... (d j)') + return rearrange(x, "... d j -> ... (d j)") def apply_rotary_pos_emb(q, k, sinu_pos): - sinu_pos = rearrange(sinu_pos, '() n (j d) -> n j d', j=2) + sinu_pos = rearrange(sinu_pos, "() n (j d) -> n j d", j=2) sin, cos = sinu_pos.unbind(dim=-2) - sin, cos = map(lambda t: repeat(t, 'b n -> b (n j)', j=2), (sin, cos)) + sin, cos = map(lambda t: repeat(t, "b n -> b (n j)", j=2), (sin, cos)) q, k = map(lambda t: (t * cos) + (rotate_every_two(t) * sin), (q, k)) return q, k + # kmeans related function and class @@ -261,7 +275,7 @@ def hook(_, grad_in, grad_out): def similarity(x, means): - return torch.einsum('bhld,hcd->bhlc', x, means) + return torch.einsum("bhld,hcd->bhlc", x, means) def dists_and_buckets(x, means): @@ -303,13 +317,15 @@ def distribution(dists, window_size): class Kmeans(nn.Module): - def __init__(self, num_heads, head_dim, num_clusters, ema_decay=0.999, commitment=1e-4): + def __init__( + self, num_heads, head_dim, num_clusters, ema_decay=0.999, commitment=1e-4 + ): super().__init__() self.commitment = commitment self.ema_decay = ema_decay - self.register_buffer('means', torch.randn(num_heads, num_clusters, head_dim)) - self.register_buffer('initted', torch.tensor(False)) + self.register_buffer("means", torch.randn(num_heads, num_clusters, head_dim)) + self.register_buffer("initted", torch.tensor(False)) self.num_new_means = 0 self.new_means = None @@ -341,7 +357,7 @@ def init(self, x): @torch.no_grad() def update(self, new_means=None): new_means = default(new_means, self.new_means) - assert exists(new_means), 'new kmeans has not been supplied' + assert exists(new_means), "new kmeans has not been supplied" ema_inplace(self.means, new_means, self.ema_decay) del self.new_means @@ -364,16 +380,33 @@ def forward(self, x, update_means=False): if update_means: with torch.no_grad(): means = kmeans_iter(x, means, buckets) - self.new_means = ema(self.new_means, means, self.num_new_means / (self.num_new_means + 1)) + self.new_means = ema( + self.new_means, means, self.num_new_means / (self.num_new_means + 1) + ) self.num_new_means += 1 return dists, loss + # kmeans attention class class KmeansAttention(nn.Module): - def __init__(self, num_clusters, window_size, num_heads, head_dim, causal=False, dropout=0., ema_decay=0.999, commitment=1e-4, context_window_size=None, receives_context=False, num_mem_kv=0, shared_qk=False): + def __init__( + self, + num_clusters, + window_size, + num_heads, + head_dim, + causal=False, + dropout=0.0, + ema_decay=0.999, + commitment=1e-4, + context_window_size=None, + receives_context=False, + num_mem_kv=0, + shared_qk=False, + ): super().__init__() self.num_heads = num_heads self.num_clusters = num_clusters @@ -389,18 +422,32 @@ def __init__(self, num_clusters, window_size, num_heads, head_dim, causal=False, self.dropout = nn.Dropout(dropout) self.num_mem_kv = max(num_mem_kv, 1 if causal and not shared_qk else 0) - self.mem_key = nn.Parameter(torch.randn(num_heads, num_clusters, self.num_mem_kv, head_dim)) - self.mem_value = nn.Parameter(torch.randn(num_heads, num_clusters, self.num_mem_kv, head_dim)) + self.mem_key = nn.Parameter( + torch.randn(num_heads, num_clusters, self.num_mem_kv, head_dim) + ) + self.mem_value = nn.Parameter( + torch.randn(num_heads, num_clusters, self.num_mem_kv, head_dim) + ) def forward(self, q, k, v, query_mask=None, key_mask=None, **kwargs): - b, h, t, d, kv_t, wsz, c_wsz, nc, device, dtype = *q.shape, k.shape[2], self.window_size, self.context_window_size, self.num_clusters, q.device, q.dtype - is_reverse = kwargs.pop('_reverse', False) + b, h, t, d, kv_t, wsz, c_wsz, nc, device, dtype = ( + *q.shape, + k.shape[2], + self.window_size, + self.context_window_size, + self.num_clusters, + q.device, + q.dtype, + ) + is_reverse = kwargs.pop("_reverse", False) out = torch.zeros_like(q, dtype=dtype) update_kmeans = self.training and not is_reverse - key_mask = default(key_mask, query_mask) if not self.receives_context else key_mask + key_mask = ( + default(key_mask, query_mask) if not self.receives_context else key_mask + ) kv_wsz = wsz if not self.receives_context else c_wsz wsz = min(wsz, t) @@ -424,16 +471,22 @@ def forward(self, q, k, v, query_mask=None, key_mask=None, **kwargs): reshape_with_window = lambda x: x.reshape(b, h, nc, -1, d) q, k, v = map(reshape_with_window, (q, k, v)) - m_k, m_v = map(lambda x: expand_dim(x, 0, b).to(q), (self.mem_key, self.mem_value)) + m_k, m_v = map( + lambda x: expand_dim(x, 0, b).to(q), (self.mem_key, self.mem_value) + ) k, v = map(lambda x: torch.cat(x, dim=3), ((m_k, k), (m_v, v))) - dots = torch.einsum('bhnid,bhnjd->bhnij', q, k) * (d ** -0.5) + dots = torch.einsum("bhnid,bhnjd->bhnij", q, k) * (d ** -0.5) mask_value = max_neg_value(dots) if exists(query_mask) or exists(key_mask): - query_mask = default(query_mask, lambda: torch.ones((b, t), device=device).bool()) - key_mask = default(key_mask, lambda: torch.ones((b, kv_t), device=device).bool()) + query_mask = default( + query_mask, lambda: torch.ones((b, t), device=device).bool() + ) + key_mask = default( + key_mask, lambda: torch.ones((b, kv_t), device=device).bool() + ) q_mask = expand_dim(query_mask, 1, h).gather(2, indices) kv_mask = expand_dim(key_mask, 1, h).gather(2, kv_indices) @@ -444,14 +497,18 @@ def forward(self, q, k, v, query_mask=None, key_mask=None, **kwargs): del mask if self.causal: - q_mask, kv_mask = map(lambda t: t.reshape(b, h, nc, -1), (indices, kv_indices)) + q_mask, kv_mask = map( + lambda t: t.reshape(b, h, nc, -1), (indices, kv_indices) + ) mask = q_mask[:, :, :, :, None] >= kv_mask[:, :, :, None, :] mask = F.pad(mask, (self.num_mem_kv, 0), value=1) dots.masked_fill_(~mask, mask_value) del mask if self.shared_qk: - q_mask, kv_mask = map(lambda t: t.reshape(b, h, nc, -1), (indices, kv_indices)) + q_mask, kv_mask = map( + lambda t: t.reshape(b, h, nc, -1), (indices, kv_indices) + ) mask = q_mask[:, :, :, :, None] == kv_mask[:, :, :, None, :] mask = F.pad(mask, (self.num_mem_kv, 0), value=0) dots.masked_fill_(mask, TOKEN_SELF_ATTN_VALUE) @@ -460,24 +517,32 @@ def forward(self, q, k, v, query_mask=None, key_mask=None, **kwargs): dots = dots.softmax(dim=-1) dots = self.dropout(dots) - bo = torch.einsum('bhcij,bhcjd->bhcid', dots, v) + bo = torch.einsum("bhcij,bhcjd->bhcid", dots, v) so = torch.reshape(bo, (b, h, -1, bo.shape[-1])).type(dtype) out = scatter_mean(out, so, indices.unsqueeze(-1).expand_as(so), -2) return out, aux_loss + # feedforward class GELU_(nn.Module): def forward(self, x): - return 0.5 * x * (1 + torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3)))) + return ( + 0.5 + * x + * ( + 1 + + torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3))) + ) + ) -GELU = nn.GELU if hasattr(nn, 'GELU') else GELU_ +GELU = nn.GELU if hasattr(nn, "GELU") else GELU_ class FeedForward(nn.Module): - def __init__(self, dim, mult=4, dropout=0., activation=None, glu=False): + def __init__(self, dim, mult=4, dropout=0.0, activation=None, glu=False): super().__init__() activation = default(activation, GELU) @@ -499,17 +564,49 @@ def forward(self, x, **kwargs): x = self.w2(x) return x + # self attention class SelfAttention(nn.Module): - def __init__(self, dim, max_seq_len, heads, local_attn_heads, window_size, dim_head=None, local_attn_window_size=None, local_attn_radius_blocks=1, causal=False, attn_dropout=0., dropout=0., kmeans_ema_decay=0.999, commitment_factor=1e-4, receives_context=False, context_window_size=None, rel_pos_emb=True, num_mem_kv=0, shared_qk=False, conv_query_kernel=9): + def __init__( + self, + dim, + max_seq_len, + heads, + local_attn_heads, + window_size, + dim_head=None, + local_attn_window_size=None, + local_attn_radius_blocks=1, + causal=False, + attn_dropout=0.0, + dropout=0.0, + kmeans_ema_decay=0.999, + commitment_factor=1e-4, + receives_context=False, + context_window_size=None, + rel_pos_emb=True, + num_mem_kv=0, + shared_qk=False, + conv_query_kernel=9, + ): super().__init__() - assert dim_head or (dim % heads) == 0, 'hidden dimension must be divisible by number of heads' - assert (max_seq_len % window_size) == 0, 'maximum sequence length must be divisible by the target window size' - assert local_attn_heads <= heads, 'number of local attention heads must be less than total heads' - assert not (receives_context and local_attn_heads > 0), 'local attention cannot be used for self attention with context' - assert not (receives_context and causal), 'contextual attention layer cannot be causal' + assert ( + dim_head or (dim % heads) == 0 + ), "hidden dimension must be divisible by number of heads" + assert ( + max_seq_len % window_size + ) == 0, "maximum sequence length must be divisible by the target window size" + assert ( + local_attn_heads <= heads + ), "number of local attention heads must be less than total heads" + assert not ( + receives_context and local_attn_heads > 0 + ), "local attention cannot be used for self attention with context" + assert not ( + receives_context and causal + ), "contextual attention layer cannot be causal" local_attn_window_size = default(local_attn_window_size, window_size) context_window_size = default(context_window_size, window_size) @@ -535,7 +632,15 @@ def __init__(self, dim, max_seq_len, heads, local_attn_heads, window_size, dim_h if self.local_attn_heads > 0: rel_pos_emb_config = (dim_head, local_attn_heads) if rel_pos_emb else None - self.local_attn = LocalAttention(dim=dim_head, window_size=local_attn_window_size, causal=causal, dropout=attn_dropout, rel_pos_emb_config=rel_pos_emb_config, look_backward=local_attn_radius_blocks, look_forward=0 if causal else local_attn_radius_blocks) + self.local_attn = LocalAttention( + dim=dim_head, + window_size=local_attn_window_size, + causal=causal, + dropout=attn_dropout, + rel_pos_emb_config=rel_pos_emb_config, + look_backward=local_attn_radius_blocks, + look_forward=0 if causal else local_attn_radius_blocks, + ) self.local_to_qkv = nn.Linear(dim, 3 * local_dim_heads) # global @@ -543,12 +648,24 @@ def __init__(self, dim, max_seq_len, heads, local_attn_heads, window_size, dim_h global_dim_heads = dim_head * self.global_attn_heads if self.global_attn_heads > 0: - self.global_attn = KmeansAttention(num_clusters, window_size, self.global_attn_heads, dim_head, causal=causal, dropout=attn_dropout, ema_decay=kmeans_ema_decay, commitment=commitment_factor, receives_context=receives_context, num_mem_kv=num_mem_kv, shared_qk=shared_qk) + self.global_attn = KmeansAttention( + num_clusters, + window_size, + self.global_attn_heads, + dim_head, + causal=causal, + dropout=attn_dropout, + ema_decay=kmeans_ema_decay, + commitment=commitment_factor, + receives_context=receives_context, + num_mem_kv=num_mem_kv, + shared_qk=shared_qk, + ) self.to_q = nn.Sequential( - Rearrange('b n c -> b c n'), + Rearrange("b n c -> b c n"), DepthWiseConv1d(dim, global_dim_heads, conv_query_kernel, causal=causal), - Rearrange('b c n -> b n c') + Rearrange("b c n -> b n c"), ) self.to_v = nn.Linear(dim, global_dim_heads, bias=False) @@ -561,14 +678,30 @@ def __init__(self, dim, max_seq_len, heads, local_attn_heads, window_size, dim_h self.to_out = nn.Linear(dim_heads, dim, bias=False) self.dropout = nn.Dropout(dropout) - def forward(self, query, key, value, context=None, key_padding_mask=None, context_mask=None, pos_emb=None, **kwargs): - assert not (self.receives_context and not exists(context)), 'context must be passed if self attention is set to receive context' + def forward( + self, + query, + key, + value, + context=None, + key_padding_mask=None, + context_mask=None, + pos_emb=None, + **kwargs + ): + assert not ( + self.receives_context and not exists(context) + ), "context must be passed if self attention is set to receive context" input_mask = key_padding_mask x = query.transpose(0, 1) b, t, _, h, dh = *x.shape, self.heads, self.dim_head - has_local, has_global = map(lambda x: x > 0, (self.local_attn_heads, self.global_attn_heads)) + has_local, has_global = map( + lambda x: x > 0, (self.local_attn_heads, self.global_attn_heads) + ) - split_heads = lambda v: reshape_dim(v, -1, (-1, dh)).transpose(1, 2).contiguous() + split_heads = ( + lambda v: reshape_dim(v, -1, (-1, dh)).transpose(1, 2).contiguous() + ) if has_local: local_qkv = self.local_to_qkv(x).chunk(3, dim=-1) @@ -587,7 +720,7 @@ def forward(self, query, key, value, context=None, key_padding_mask=None, contex q, k, v = map(split_heads, (q, k, v)) out = [] - total_loss = torch.tensor(0., requires_grad=True, **to(x)) + total_loss = torch.tensor(0.0, requires_grad=True, **to(x)) if has_local: local_out = self.local_attn(lq, lk, lv, input_mask=input_mask) @@ -597,7 +730,9 @@ def forward(self, query, key, value, context=None, key_padding_mask=None, contex if not self.receives_context and exists(pos_emb): q, k = apply_rotary_pos_emb(q, k, pos_emb) - global_out, loss = self.global_attn(q, k, v, query_mask=input_mask, key_mask=context_mask) + global_out, loss = self.global_attn( + q, k, v, query_mask=input_mask, key_mask=context_mask + ) total_loss = total_loss + loss out.append(global_out) diff --git a/fairseq/modules/linearized_convolution.py b/fairseq/modules/linearized_convolution.py index f7e156cb0c..1c7a9f09ac 100644 --- a/fairseq/modules/linearized_convolution.py +++ b/fairseq/modules/linearized_convolution.py @@ -13,6 +13,7 @@ from typing import Dict, Optional from torch import Tensor + @with_incremental_state class LinearizedConvolution(ConvTBC): """An optimized version of nn.Conv1d. @@ -41,7 +42,11 @@ def upgrade_state_dict_named(self, state_dict, name): del state_dict[prefix + "_linearized_weight"] @torch.jit.export - def forward(self, input, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None): + def forward( + self, + input, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + ): """ Args: incremental_state: Used to buffer signal; if not None, then input is @@ -80,18 +85,28 @@ def forward(self, input, incremental_state: Optional[Dict[str, Dict[str, Optiona return output.view(bsz, 1, -1) @torch.jit.unused - def reorder_incremental_state(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], new_order): + def reorder_incremental_state( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + new_order, + ): input_buffer = self._get_input_buffer(incremental_state) if input_buffer is not None: input_buffer = input_buffer.index_select(0, new_order) self._set_input_buffer(incremental_state, input_buffer) @torch.jit.unused - def _get_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): + def _get_input_buffer( + self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] + ): return utils.get_incremental_state(self, incremental_state, "input_buffer") @torch.jit.unused - def _set_input_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], new_buffer): + def _set_input_buffer( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + new_buffer, + ): return utils.set_incremental_state( self, incremental_state, "input_buffer", new_buffer ) diff --git a/fairseq/modules/location_attention.py b/fairseq/modules/location_attention.py index a970876bba..dbbbfb9f2d 100644 --- a/fairseq/modules/location_attention.py +++ b/fairseq/modules/location_attention.py @@ -20,9 +20,16 @@ class LocationAttention(nn.Module): :param int conv_kernel_size: filter size of attention convolution """ - def __init__(self, attn_dim, encoder_dim, decoder_dim, - attn_state_kernel_size, conv_dim, conv_kernel_size, - scaling=2.0): + def __init__( + self, + attn_dim, + encoder_dim, + decoder_dim, + attn_state_kernel_size, + conv_dim, + conv_kernel_size, + scaling=2.0, + ): super(LocationAttention, self).__init__() self.attn_dim = attn_dim self.decoder_dim = decoder_dim @@ -30,9 +37,13 @@ def __init__(self, attn_dim, encoder_dim, decoder_dim, self.proj_enc = nn.Linear(encoder_dim, attn_dim) self.proj_dec = nn.Linear(decoder_dim, attn_dim, bias=False) self.proj_attn = nn.Linear(conv_dim, attn_dim, bias=False) - self.conv = nn.Conv1d(attn_state_kernel_size, conv_dim, - 2 * conv_kernel_size + 1, - padding=conv_kernel_size, bias=False) + self.conv = nn.Conv1d( + attn_state_kernel_size, + conv_dim, + 2 * conv_kernel_size + 1, + padding=conv_kernel_size, + bias=False, + ) self.proj_out = nn.Sequential(nn.Tanh(), nn.Linear(attn_dim, 1)) self.proj_enc_out = None # cache diff --git a/fairseq/modules/lstm_cell_with_zoneout.py b/fairseq/modules/lstm_cell_with_zoneout.py index f04e5db255..273308951f 100644 --- a/fairseq/modules/lstm_cell_with_zoneout.py +++ b/fairseq/modules/lstm_cell_with_zoneout.py @@ -12,20 +12,20 @@ class LSTMCellWithZoneOut(nn.Module): https://arxiv.org/abs/1606.01305 """ - def __init__(self, prob: float, input_size: int, hidden_size: int, - bias: bool = True): + def __init__( + self, prob: float, input_size: int, hidden_size: int, bias: bool = True + ): super(LSTMCellWithZoneOut, self).__init__() self.lstm_cell = nn.LSTMCell(input_size, hidden_size, bias=bias) self.prob = prob if prob > 1.0 or prob < 0.0: - raise ValueError("zoneout probability must be in the range from " - "0.0 to 1.0.") + raise ValueError( + "zoneout probability must be in the range from " "0.0 to 1.0." + ) def zoneout(self, h, next_h, prob): if isinstance(h, tuple): - return tuple( - [self.zoneout(h[i], next_h[i], prob) for i in range(len(h))] - ) + return tuple([self.zoneout(h[i], next_h[i], prob) for i in range(len(h))]) if self.training: mask = h.new_zeros(*h.size()).bernoulli_(prob) diff --git a/fairseq/modules/quantization/pq/utils.py b/fairseq/modules/quantization/pq/utils.py index 14c015b7c1..eceeef8ba3 100644 --- a/fairseq/modules/quantization/pq/utils.py +++ b/fairseq/modules/quantization/pq/utils.py @@ -60,7 +60,9 @@ def quantize_model_( to layers_to_quantize[step] """ - quantized_layers = get_layers(model, layers_to_quantize[step], remove_weights=remove_weights) + quantized_layers = get_layers( + model, layers_to_quantize[step], remove_weights=remove_weights + ) for layer in quantized_layers: @@ -108,8 +110,8 @@ def quantize_model_( centroids = torch.rand(centroids.size()) centroids.cuda() # Get counts and assignment keys from layer in loaded checkpoint. - counts_key = layer+"."+"counts" - assignment_key = layer+"."+"assignments" + counts_key = layer + "." + "counts" + assignment_key = layer + "." + "assignments" # Get number of different bins to include. counts = list(state_dict[counts_key].shape)[0] print(layer) @@ -122,7 +124,7 @@ def quantize_model_( print(num_assignments) print(num_extra) assignments_bins = torch.arange(counts) - assignments_rand = torch.randint(0, counts-1, (num_extra, )) + assignments_rand = torch.randint(0, counts - 1, (num_extra,)) assignments = torch.cat((assignments_bins, assignments_rand), 0) # assignments = assignments.type(torch.IntTensor) assignments.cuda() diff --git a/fairseq/modules/quantization/scalar/utils.py b/fairseq/modules/quantization/scalar/utils.py index 2ec6af3fcb..d4b1cc255b 100644 --- a/fairseq/modules/quantization/scalar/utils.py +++ b/fairseq/modules/quantization/scalar/utils.py @@ -16,7 +16,9 @@ MAPPING = {nn.Linear: IntLinear, nn.Embedding: IntEmbedding, nn.Conv2d: IntConv2d} -def quantize_model_(model, p=0.2, bits=8, update_step=3000, method="histogram", remove_weights=False): +def quantize_model_( + model, p=0.2, bits=8, update_step=3000, method="histogram", remove_weights=False +): """ Replaces all modules with their scalar quantized counterpart and registers hooks to quantize the post-ativations of those modules. diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 3ad2be959d..d2b57ac807 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -132,8 +132,7 @@ def forward( # will become -inf, which results in NaN in model parameters if attn_mask is not None: attn_mask = attn_mask.masked_fill( - attn_mask.to(torch.bool), - -1e8 if x.dtype == torch.float32 else -1e4 + attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 ) residual = x @@ -213,11 +212,19 @@ def __init__( add_bias_kv=add_bias_kv, add_zero_attn=add_zero_attn, ) - self.attn_ln = LayerNorm(self.embed_dim) if utils.safe_getattr(cfg, 'scale_attn', False) else None + self.attn_ln = ( + LayerNorm(self.embed_dim) + if utils.safe_getattr(cfg, "scale_attn", False) + else None + ) self.nh = self.self_attn.num_heads self.head_dim = self.self_attn.head_dim - scale_heads = utils.safe_getattr(cfg, 'scale_heads', False) - self.c_attn = nn.Parameter(torch.ones((self.nh,)), requires_grad=True) if scale_heads else None + scale_heads = utils.safe_getattr(cfg, "scale_heads", False) + self.c_attn = ( + nn.Parameter(torch.ones((self.nh,)), requires_grad=True) + if scale_heads + else None + ) self.activation_fn = utils.get_activation_fn(activation=cfg.activation_fn) activation_dropout_p = cfg.activation_dropout @@ -238,8 +245,21 @@ def __init__( self.encoder_attn = self.build_encoder_attention(self.embed_dim, cfg) self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) - self.ffn_layernorm = LayerNorm(cfg.decoder.ffn_embed_dim) if utils.safe_getattr(cfg, 'scale_fc', False) else None - self.w_resid = nn.Parameter(torch.ones(self.embed_dim, ), requires_grad=True) if utils.safe_getattr(cfg, 'scale_resids', False) else None + self.ffn_layernorm = ( + LayerNorm(cfg.decoder.ffn_embed_dim) + if utils.safe_getattr(cfg, "scale_fc", False) + else None + ) + self.w_resid = ( + nn.Parameter( + torch.ones( + self.embed_dim, + ), + requires_grad=True, + ) + if utils.safe_getattr(cfg, "scale_resids", False) + else None + ) self.fc1 = self.build_fc1( self.embed_dim, @@ -297,7 +317,6 @@ def prepare_for_onnx_export_(self): def residual_connection(self, x, residual): return residual + x - def forward( self, x, @@ -377,7 +396,7 @@ def forward( if self.c_attn is not None: tgt_len, bsz = x.size(0), x.size(1) x = x.view(tgt_len, bsz, self.nh, self.head_dim) - x = torch.einsum('tbhd,h->tbhd', x, self.c_attn) + x = torch.einsum("tbhd,h->tbhd", x, self.c_attn) x = x.reshape(tgt_len, bsz, self.embed_dim) if self.attn_ln is not None: x = self.attn_ln(x) diff --git a/fairseq/modules/transformer_sentence_encoder.py b/fairseq/modules/transformer_sentence_encoder.py index d0540d6922..5d2db91ad7 100644 --- a/fairseq/modules/transformer_sentence_encoder.py +++ b/fairseq/modules/transformer_sentence_encoder.py @@ -35,9 +35,7 @@ def init_bert_params(module): def normal_(data): # with FSDP, module params will be on CUDA, so we cast them back to CPU # so that the RNG is consistent with and without FSDP - data.copy_( - data.cpu().normal_(mean=0.0, std=0.02).to(data.device) - ) + data.copy_(data.cpu().normal_(mean=0.0, std=0.02).to(data.device)) if isinstance(module, nn.Linear): normal_(module.weight.data) @@ -276,7 +274,9 @@ def forward( inner_states.append(x) for layer in self.layers: - x, _ = layer(x, self_attn_padding_mask=padding_mask, self_attn_mask=attn_mask) + x, _ = layer( + x, self_attn_padding_mask=padding_mask, self_attn_mask=attn_mask + ) if not last_state_only: inner_states.append(x) diff --git a/fairseq/ngram_repeat_block.py b/fairseq/ngram_repeat_block.py index 8541251494..98e707d1b8 100644 --- a/fairseq/ngram_repeat_block.py +++ b/fairseq/ngram_repeat_block.py @@ -2,12 +2,12 @@ # Licensed under the MIT License. """ Wrapper for ngram_repeat_block cuda extension """ -import torch -from torch import nn - import math -from typing import Dict, List, Optional import warnings +from typing import Dict, List, Optional + +import torch +from torch import nn try: from fairseq import ngram_repeat_block_cuda @@ -37,7 +37,7 @@ def is_cuda_extension_usable() -> bool: class NGramRepeatBlock(nn.Module): - """ Wrapper class for calling ngram_repeat_block cuda extension """ + """Wrapper class for calling ngram_repeat_block cuda extension""" def __init__(self, no_repeat_ngram_size: int, use_extension: bool = True): super().__init__() diff --git a/fairseq/optim/adam.py b/fairseq/optim/adam.py index d3ae9e64a7..678ec7c617 100644 --- a/fairseq/optim/adam.py +++ b/fairseq/optim/adam.py @@ -67,13 +67,13 @@ def __init__(self, cfg: FairseqAdamConfig, params): elif use_fused_adam: logger.info("using FusedAdam") self._optimizer = fused_adam_cls( - params, - use_fp16_stats=self.cfg.fp16_adam_stats, - **self.optimizer_config + params, use_fp16_stats=self.cfg.fp16_adam_stats, **self.optimizer_config ) else: if self.cfg.fp16_adam_stats: - raise NotImplementedError("--fp16-adam-stats is only supported with FusedAdamV1") + raise NotImplementedError( + "--fp16-adam-stats is only supported with FusedAdamV1" + ) self._optimizer = Adam(params, **self.optimizer_config) @property diff --git a/fairseq/optim/amp_optimizer.py b/fairseq/optim/amp_optimizer.py index 3b7958e50c..cfe57d07f9 100644 --- a/fairseq/optim/amp_optimizer.py +++ b/fairseq/optim/amp_optimizer.py @@ -63,8 +63,9 @@ def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): ).format(self.min_loss_scale, new_loss_scale) ) else: - logger.info("AMP: overflow detected, setting scale to " - f"to {new_loss_scale}") + logger.info( + "AMP: overflow detected, setting scale to " f"to {new_loss_scale}" + ) return grad_norm @property diff --git a/fairseq/optim/composite.py b/fairseq/optim/composite.py index a5366d6243..63701ee8b1 100644 --- a/fairseq/optim/composite.py +++ b/fairseq/optim/composite.py @@ -23,7 +23,9 @@ class OptimizerAndSchedulerConfig(FairseqDataclass): optimizer: Any = None lr_scheduler: Optional[Any] = None lr: List = II("optimization.lr") - lr_float: Optional[float] = None # this makes it easier to sweep on learning rate with auto sweepers + lr_float: Optional[ + float + ] = None # this makes it easier to sweep on learning rate with auto sweepers @dataclass diff --git a/fairseq/optim/cpu_adam.py b/fairseq/optim/cpu_adam.py index b2f893aeda..b218934e71 100644 --- a/fairseq/optim/cpu_adam.py +++ b/fairseq/optim/cpu_adam.py @@ -16,6 +16,7 @@ try: import deepspeed + has_deepspeed = True except ImportError as e: has_deepspeed = False @@ -24,12 +25,15 @@ def _get_cpu_adam(): try: from deepspeed.ops.op_builder import CPUAdamBuilder + return CPUAdamBuilder().load() except ImportError: # fbcode from deepspeed.ops.adam import DeepSpeedCPUAdam as ds_opt_adam + return ds_opt_adam + @dataclass class FairseqCPUAdamConfig(FairseqDataclass): adam_betas: str = field( diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index c59b21cf6b..f8af2883a6 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -64,9 +64,9 @@ def build_fp32_params(cls, args, params, flatten=True): fp32_params = [] for p in params: p32 = torch.nn.Parameter(p.data.float()) - if hasattr(p, 'expert'): + if hasattr(p, "expert"): p32.expert = True - elif hasattr(p, 'base_expert'): + elif hasattr(p, "base_expert"): p32.base_expert = True p32.grad = torch.zeros_like(p32.data) if hasattr(p, "param_group"): @@ -209,7 +209,9 @@ def step(self, closure=None, groups=None): self._sync_fp16_grads_to_fp32() if getattr(self, "supports_step_with_scale", False): - self.fp32_optimizer.step(closure, scale=(1.0 / self._multiply_factor), groups=groups) + self.fp32_optimizer.step( + closure, scale=(1.0 / self._multiply_factor), groups=groups + ) else: self._unscale_grads() self.fp32_optimizer.step(closure, groups=groups) @@ -434,7 +436,9 @@ def step(self, closure=None, groups=None): """Performs a single optimization step.""" if getattr(self, "supports_step_with_scale", False): # NOTE(msb) optimizer divides by scale factor - self.wrapped_optimizer.step(closure, scale=(1.0 / self._multiply_factor), groups=groups) + self.wrapped_optimizer.step( + closure, scale=(1.0 / self._multiply_factor), groups=groups + ) else: self._unscale_grads() self.wrapped_optimizer.step(closure, groups=groups) diff --git a/fairseq/optim/fused_adam.py b/fairseq/optim/fused_adam.py index 7a6d1f73d5..da872033d1 100644 --- a/fairseq/optim/fused_adam.py +++ b/fairseq/optim/fused_adam.py @@ -179,7 +179,7 @@ def step(self, closure=None, grads=None, scale=1.0, grad_norms=None): if p.device.type == "cpu": p_data_fp32 = p.data.cuda(non_blocking=True).float() - out_p = torch.tensor([], dtype = torch.float) + out_p = torch.tensor([], dtype=torch.float) else: p_data_fp32 = p.data.float() out_p = p.data @@ -234,6 +234,7 @@ def step(self, closure=None, grads=None, scale=1.0, grad_norms=None): p.data.copy_(p_data_fp32, non_blocking=True) if self.use_fp16_stats: + def inf_norm(t): return torch.norm(t, float("inf")) @@ -262,7 +263,9 @@ class FusedAdamV2(FusedAdam): def __init__(self, *args, use_fp16_stats=False, **kwargs): if use_fp16_stats: - raise NotImplementedError("--fp16-adam-stats is only supported with FusedAdamV1") + raise NotImplementedError( + "--fp16-adam-stats is only supported with FusedAdamV1" + ) super().__init__(*args, **kwargs) if not hasattr(self, "multi_tensor_adam"): raise Exception( diff --git a/fairseq/optim/lr_scheduler/manual_lr_scheduler.py b/fairseq/optim/lr_scheduler/manual_lr_scheduler.py index 0269a1e285..57edc256fd 100644 --- a/fairseq/optim/lr_scheduler/manual_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/manual_lr_scheduler.py @@ -32,7 +32,7 @@ def __init__(self, args, optimizer): self.optimizer.set_lr(self.lr) # Set the beginning of the epoch. def parse_manuallr_args(self, lr_args_str): - lr_dict = ast.literal_eval(lr_args_str.replace(' ', '')) + lr_dict = ast.literal_eval(lr_args_str.replace(" ", "")) if not isinstance(lr_dict, dict): raise ValueError("epoch2lr/update2lr must be abel to evaluated to a dict") @@ -84,9 +84,14 @@ def get_next_lr(self, epoch): if manual_keys: manual_lr = self.epoch2lr[max(manual_keys)] else: - logger.warning("@@@ epoch={} does not exist in manual lr input. epoch2lr={}...".format( - epoch, list(self.epoch2lr.items())[:min(10, len(self.epoch2lr.keys())-1)] - )) + logger.warning( + "@@@ epoch={} does not exist in manual lr input. epoch2lr={}...".format( + epoch, + list(self.epoch2lr.items())[ + : min(10, len(self.epoch2lr.keys()) - 1) + ], + ) + ) manual_lr = self.optimizer.get_lr() return manual_lr @@ -102,8 +107,14 @@ def step_update(self, num_updates): if manual_keys: manual_lr = self.update2lr[max(manual_keys)] else: - logger.warning("epoch={} does not exist in manual lr input update2lr={}...".format( - num_updates, list(self.update2lr.items())[:min(10, len(self.update2lr.keys())-1)])) + logger.warning( + "epoch={} does not exist in manual lr input update2lr={}...".format( + num_updates, + list(self.update2lr.items())[ + : min(10, len(self.update2lr.keys()) - 1) + ], + ) + ) manual_lr = self.optimizer.get_lr() self.optimizer.set_lr(manual_lr) diff --git a/fairseq/optim/lr_scheduler/step_lr_scheduler.py b/fairseq/optim/lr_scheduler/step_lr_scheduler.py index 8cb2006860..db99d4eee8 100644 --- a/fairseq/optim/lr_scheduler/step_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/step_lr_scheduler.py @@ -36,8 +36,7 @@ class StepLRScheduleConfig(FairseqDataclass): @register_lr_scheduler("step", dataclass=StepLRScheduleConfig) class StepLRSchedule(FairseqLRScheduler): - """Decay learning rate every k updates by a fixed factor - """ + """Decay learning rate every k updates by a fixed factor""" def __init__(self, cfg: StepLRScheduleConfig, fairseq_optimizer): super().__init__(cfg, fairseq_optimizer) @@ -50,16 +49,16 @@ def __init__(self, cfg: StepLRScheduleConfig, fairseq_optimizer): cfg.warmup_init_lr if cfg.warmup_init_lr >= 0 else self.min_lr ) - assert(self.lr_deacy_period > 0) - assert(self.lr_decay <= 1) - assert(self.min_lr >= 0) - assert(self.max_lr > self.min_lr) + assert self.lr_deacy_period > 0 + assert self.lr_decay <= 1 + assert self.min_lr >= 0 + assert self.max_lr > self.min_lr if cfg.warmup_updates > 0: # linearly warmup for the first cfg.warmup_updates self.warmup_lr_step = ( - (self.max_lr - self.warmup_init_lr) / self.warmup_updates - ) + self.max_lr - self.warmup_init_lr + ) / self.warmup_updates else: self.warmup_lr_step = 1 diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 2e61140dd8..bfa791a018 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -171,7 +171,9 @@ def generate_batched_itr(self, data_itr, beam_size=None, cuda=False, timer=None) yield id, src, ref, hypos[i] @torch.no_grad() - def generate(self, models, sample: Dict[str, Dict[str, Tensor]], **kwargs) -> List[List[Dict[str, Tensor]]]: + def generate( + self, models, sample: Dict[str, Dict[str, Tensor]], **kwargs + ) -> List[List[Dict[str, Tensor]]]: """Generate translations. Match the api of other fairseq generators. Args: @@ -223,7 +225,10 @@ def _generate( else torch.tensor(src_tokens.size(-1)).to(src_tokens) ) else: - raise Exception("expected src_tokens or source in net input. input keys: " + str(net_input.keys())) + raise Exception( + "expected src_tokens or source in net input. input keys: " + + str(net_input.keys()) + ) # bsz: total number of sentences in beam # Note that src_tokens may have more than 2 dimensions (i.e. audio features) @@ -328,7 +333,9 @@ def _generate( encoder_outs = self.model.reorder_encoder_out( encoder_outs, reorder_state ) - with torch.autograd.profiler.record_function("EnsembleModel: forward_decoder"): + with torch.autograd.profiler.record_function( + "EnsembleModel: forward_decoder" + ): lprobs, avg_attn_scores = self.model.forward_decoder( tokens[:, : step + 1], encoder_outs, @@ -751,7 +758,14 @@ def has_incremental_states(self): return self.has_incremental def max_decoder_positions(self): - return min([m.max_decoder_positions() for m in self.models if hasattr(m, "max_decoder_positions")] + [sys.maxsize]) + return min( + [ + m.max_decoder_positions() + for m in self.models + if hasattr(m, "max_decoder_positions") + ] + + [sys.maxsize] + ) @torch.jit.export def forward_encoder(self, net_input: Dict[str, Tensor]): diff --git a/fairseq/speech_generator.py b/fairseq/speech_generator.py index 8276335eae..d75338ecd5 100644 --- a/fairseq/speech_generator.py +++ b/fairseq/speech_generator.py @@ -35,8 +35,12 @@ def get_waveform(self, feat): class AutoRegressiveSpeechGenerator(SpeechGenerator): def __init__( - self, model, vocoder, data_cfg, max_iter: int = 6000, - eos_prob_threshold: float = 0.5, + self, + model, + vocoder, + data_cfg, + max_iter: int = 6000, + eos_prob_threshold: float = 0.5, ): super().__init__(model, vocoder, data_cfg) self.max_iter = max_iter @@ -54,8 +58,9 @@ def generate(self, model, sample, has_targ=False, **kwargs): raw_dim = out_dim // n_frames_per_step # initialize - encoder_out = model.forward_encoder(src_tokens, src_lengths, - speaker=sample["speaker"]) + encoder_out = model.forward_encoder( + src_tokens, src_lengths, speaker=sample["speaker"] + ) incremental_state = {} feat, attn, eos_prob = [], [], [] finished = src_tokens.new_zeros((bsz,)).bool() @@ -66,21 +71,24 @@ def generate(self, model, sample, has_targ=False, **kwargs): cur_out_lens = out_lens.clone() cur_out_lens.masked_fill_(cur_out_lens.eq(self.max_iter), step + 1) _, cur_eos_out, cur_extra = model.forward_decoder( - prev_feat_out, encoder_out=encoder_out, + prev_feat_out, + encoder_out=encoder_out, incremental_state=incremental_state, - target_lengths=cur_out_lens, speaker=sample["speaker"], **kwargs + target_lengths=cur_out_lens, + speaker=sample["speaker"], + **kwargs ) cur_eos_prob = torch.sigmoid(cur_eos_out).squeeze(2) - feat.append(cur_extra['feature_out']) - attn.append(cur_extra['attn']) + feat.append(cur_extra["feature_out"]) + attn.append(cur_extra["attn"]) eos_prob.append(cur_eos_prob) - cur_finished = (cur_eos_prob.squeeze(1) > self.eos_prob_threshold) + cur_finished = cur_eos_prob.squeeze(1) > self.eos_prob_threshold out_lens.masked_fill_((~finished) & cur_finished, step + 1) finished = finished | cur_finished if finished.sum().item() == bsz: break - prev_feat_out = cur_extra['feature_out'] + prev_feat_out = cur_extra["feature_out"] feat = torch.cat(feat, dim=1) feat = model.decoder.postnet(feat) + feat @@ -98,11 +106,11 @@ def generate(self, model, sample, has_targ=False, **kwargs): finalized = [ { - 'feature': feat[b, :out_len], - 'eos_prob': eos_prob[b, :out_len], - 'attn': attn[b, :, :out_len], - 'alignment': alignment[b, :out_len], - 'waveform': self.get_waveform(feat[b, :out_len]), + "feature": feat[b, :out_len], + "eos_prob": eos_prob[b, :out_len], + "attn": attn[b, :, :out_len], + "alignment": alignment[b, :out_len], + "waveform": self.get_waveform(feat[b, :out_len]), } for b, out_len in zip(range(bsz), out_lens) ] @@ -134,7 +142,7 @@ def generate(self, model, sample, has_targ=False, **kwargs): prev_output_tokens=sample["net_input"]["prev_output_tokens"], incremental_state=None, target_lengths=sample["target_lengths"], - speaker=sample["speaker"] + speaker=sample["speaker"], ) if feat_post is not None: feat = feat_post @@ -142,9 +150,7 @@ def generate(self, model, sample, has_targ=False, **kwargs): feat = feat.view(bsz, -1, raw_dim) feat = self.gcmvn_denormalize(feat) - dur_out = torch.clamp( - torch.round(torch.exp(log_dur_out) - 1).long(), min=0 - ) + dur_out = torch.clamp(torch.round(torch.exp(log_dur_out) - 1).long(), min=0) def get_dur_plot_data(d): r = [] @@ -155,11 +161,11 @@ def get_dur_plot_data(d): out_lens = out_lens * n_frames_per_step finalized = [ { - 'feature': feat[b, :l] if l > 0 else feat.new_zeros([1, raw_dim]), - 'waveform': self.get_waveform( + "feature": feat[b, :l] if l > 0 else feat.new_zeros([1, raw_dim]), + "waveform": self.get_waveform( feat[b, :l] if l > 0 else feat.new_zeros([1, raw_dim]) ), - 'attn': feat.new_tensor(get_dur_plot_data(dur_out[b])), + "attn": feat.new_tensor(get_dur_plot_data(dur_out[b])), } for b, l in zip(range(bsz), out_lens) ] @@ -188,8 +194,12 @@ def generate(self, model, sample, has_targ=False, **kwargs): bsz = src_tokens.shape[0] feat, eos_prob, extra = model( - src_tokens, src_lens, prev_out_tokens, incremental_state=None, - target_lengths=tgt_lens, speaker=sample["speaker"] + src_tokens, + src_lens, + prev_out_tokens, + incremental_state=None, + target_lengths=tgt_lens, + speaker=sample["speaker"], ) attn = extra["attn"] # B x T_s x T_t @@ -203,11 +213,11 @@ def generate(self, model, sample, has_targ=False, **kwargs): finalized = [ { - 'feature': feat[b, :tgt_len], - 'eos_prob': eos_prob[b, :tgt_len], - 'attn': attn[b, :, :tgt_len], - 'alignment': alignment[b, :tgt_len], - 'waveform': self.get_waveform(feat[b, :tgt_len]), + "feature": feat[b, :tgt_len], + "eos_prob": eos_prob[b, :tgt_len], + "attn": attn[b, :, :tgt_len], + "alignment": alignment[b, :tgt_len], + "waveform": self.get_waveform(feat[b, :tgt_len]), } for b, tgt_len in zip(range(bsz), tgt_lens) ] diff --git a/fairseq/tasks/audio_finetuning.py b/fairseq/tasks/audio_finetuning.py index 4ef87c604f..70aa6a8da8 100644 --- a/fairseq/tasks/audio_finetuning.py +++ b/fairseq/tasks/audio_finetuning.py @@ -67,31 +67,31 @@ class AudioFinetuningConfig(AudioPretrainingConfig): default=False, metadata={"help": "evaluation with BLEU scores"} ) eval_bleu_detok: Optional[str] = field( - default=None, metadata={ + default=None, + metadata={ "help": "detokenize before computing BLEU (e.g., 'moses'); " - "required if using --eval-bleu; use 'space' to disable " - "detokenization; see fairseq.data.encoders for other options" - } + "required if using --eval-bleu; use 'space' to disable " + "detokenization; see fairseq.data.encoders for other options" + }, ) eval_bleu_detok_args: str = field( - default="{}", - metadata={"help": "args for building the tokenizer, if needed"} + default="{}", metadata={"help": "args for building the tokenizer, if needed"} ) eval_tokenized_bleu: bool = field( - default=False, - metadata={"help": "compute tokenized BLEU instead of sacrebleu"} + default=False, metadata={"help": "compute tokenized BLEU instead of sacrebleu"} ) eval_bleu_remove_bpe: Optional[str] = field( default=None, metadata={"help": "remove BPE before computing BLEU"} ) eval_bleu_args: str = field( default="{}", - metadata={"help": "generation args for BLUE scoring, e.g., " - "'{\"beam\": 4, \"lenpen\": 0.6}'"} + metadata={ + "help": "generation args for BLUE scoring, e.g., " + '\'{"beam": 4, "lenpen": 0.6}\'' + }, ) eval_bleu_print_samples: bool = field( - default=False, - metadata={"help": "print sample generations during validation"} + default=False, metadata={"help": "print sample generations during validation"} ) autoregressive: bool = field( default=False, @@ -123,7 +123,9 @@ def load_target_dictionary(self): return Dictionary.load(dict_path) return None - def load_dataset(self, split: str, task_cfg: AudioFinetuningConfig = None, **kwargs): + def load_dataset( + self, split: str, task_cfg: AudioFinetuningConfig = None, **kwargs + ): super().load_dataset(split, task_cfg, **kwargs) task_cfg = task_cfg or self.cfg @@ -138,7 +140,8 @@ def load_dataset(self, split: str, task_cfg: AudioFinetuningConfig = None, **kwa with open(label_path, "r") as f: labels = [ text_compressor.compress(l) - for i, l in enumerate(f) if i not in skipped_indices + for i, l in enumerate(f) + if i not in skipped_indices ] assert len(labels) == len(self.datasets[split]), ( @@ -157,7 +160,7 @@ def load_dataset(self, split: str, task_cfg: AudioFinetuningConfig = None, **kwa process_label=process_label, label_len_fn=label_len_fn, add_to_input=task_cfg.get("autoregressive", False), - text_compression_level=text_compression_level + text_compression_level=text_compression_level, ) @property @@ -176,8 +179,8 @@ def valid_step(self, sample, model, criterion): logging_output["_num_words"] = metrics["num_words"] if self.cfg.eval_bleu and self.cfg.autoregressive: metrics = self._inference_with_bleu(self.sequence_generator, sample, model) - logging_output['_bleu_sys_len'] = metrics.sys_len - logging_output['_bleu_ref_len'] = metrics.ref_len + logging_output["_bleu_sys_len"] = metrics.sys_len + logging_output["_bleu_ref_len"] = metrics.ref_len # we split counts into separate entries so that they can be # summed efficiently across workers using fast-stat-sync assert len(metrics.counts) == 4 @@ -200,9 +203,9 @@ def build_model(self, model_cfg: FairseqDataclass): self.tokenizer = None if self.cfg.eval_bleu and self.cfg.autoregressive: assert self.cfg.eval_bleu_detok is not None, ( - '--eval-bleu-detok is required if using --eval-bleu; ' - 'try --eval-bleu-detok=moses (or --eval-bleu-detok=space ' - 'to disable detokenization, e.g., when using sentencepiece)' + "--eval-bleu-detok is required if using --eval-bleu; " + "try --eval-bleu-detok=moses (or --eval-bleu-detok=space " + "to disable detokenization, e.g., when using sentencepiece)" ) detok_args = json.loads(self.cfg.eval_bleu_detok_args) self.tokenizer = encoders.build_tokenizer( @@ -261,9 +264,7 @@ def decode(toks, is_ref): # BLEU scores. Instead, we use a somewhat more verbose # alternative that is unlikely to appear in the real # reference, but doesn't get split into multiple tokens. - unk_string=( - "UNKNOWNTOKENINREF" if is_ref else "UNKNOWNTOKENINHYP" - ), + unk_string=("UNKNOWNTOKENINREF" if is_ref else "UNKNOWNTOKENINHYP"), ) if self.tokenizer: s = self.tokenizer.decode(s) @@ -272,21 +273,18 @@ def decode(toks, is_ref): gen_out = self.inference_step(generator, [model], sample) hyps, refs = [], [] for i in range(len(gen_out)): - hyps.append(decode(gen_out[i][0]['tokens'], is_ref=False)) + hyps.append(decode(gen_out[i][0]["tokens"], is_ref=False)) refs.append( decode( - utils.strip_pad( - sample['target'][i], - self.target_dictionary.pad() - ), + utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), is_ref=True, # don't count <unk> as matches to the hypo ) ) if self.cfg.eval_bleu_print_samples: - logger.info('H-{} {}'.format(sample["id"][0], hyps[0])) - logger.info('T-{} {}'.format(sample["id"][0], refs[0])) + logger.info("H-{} {}".format(sample["id"][0], hyps[0])) + logger.info("T-{} {}".format(sample["id"][0], refs[0])) - eval_tokenization = 'none' if self.cfg.eval_tokenized_bleu else '13a' + eval_tokenization = "none" if self.cfg.eval_tokenized_bleu else "13a" return sacrebleu.corpus_bleu(hyps, [refs], tokenize=eval_tokenization) def reduce_metrics(self, logging_outputs, criterion): @@ -329,18 +327,17 @@ def reduce_metrics(self, logging_outputs, criterion): count_keys = [f"_bleu_counts_{i}" for i in range(4)] total_keys = [f"_bleu_totals_{i}" for i in range(4)] for k in len_keys + count_keys + total_keys: - metrics.log_scalar( - k, sum(log.get(k, 0) for log in logging_outputs) - ) + metrics.log_scalar(k, sum(log.get(k, 0) for log in logging_outputs)) import sacrebleu + metrics.log_derived( - 'bleu', + "bleu", lambda meters: sacrebleu.compute_bleu( correct=[meters[k].sum for k in count_keys], total=[meters[k].sum for k in total_keys], - sys_len=meters['_bleu_sys_len'].sum, - ref_len=meters['_bleu_ref_len'].sum, - smooth_method="exp" - ).score + sys_len=meters["_bleu_sys_len"].sum, + ref_len=meters["_bleu_ref_len"].sum, + smooth_method="exp", + ).score, ) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index cc310088db..debb269ddd 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -50,8 +50,7 @@ class AudioPretrainingConfig(FairseqDataclass): data: str = field(default=MISSING, metadata={"help": "path to data directory"}) labels: Optional[str] = field( default=None, - metadata={ - "help": "extension of the label file to load, used for fine-tuning"}, + metadata={"help": "extension of the label file to load, used for fine-tuning"}, ) binarized_dataset: bool = field( default=False, @@ -102,8 +101,8 @@ class AudioPretrainingConfig(FairseqDataclass): default="none", metadata={ "help": "compression level for texts (e.g. audio filenames, " - "target texts): none/low/high (default: none). " - } + "target texts): none/low/high (default: none). " + }, ) diff --git a/fairseq/tasks/denoising.py b/fairseq/tasks/denoising.py index d1dff26c36..1d4f84c08b 100644 --- a/fairseq/tasks/denoising.py +++ b/fairseq/tasks/denoising.py @@ -135,7 +135,6 @@ def add_args(parser): 'e.g., "train,valid" (default: all dataset splits)', ) - def __init__(self, args, dictionary): super().__init__(args) self.dictionary = dictionary diff --git a/fairseq/tasks/frm_text_to_speech.py b/fairseq/tasks/frm_text_to_speech.py index 1fa9b0f83e..667f5f8ee4 100644 --- a/fairseq/tasks/frm_text_to_speech.py +++ b/fairseq/tasks/frm_text_to_speech.py @@ -11,20 +11,19 @@ logging.basicConfig( - format='%(asctime)s | %(levelname)s | %(name)s | %(message)s', - datefmt='%Y-%m-%d %H:%M:%S', level=logging.INFO + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=logging.INFO, ) logger = logging.getLogger(__name__) -@register_task('frm_text_to_speech') +@register_task("frm_text_to_speech") class FrmTextToSpeechTask(TextToSpeechTask): @staticmethod def add_args(parser): TextToSpeechTask.add_args(parser) - parser.add_argument( - "--do_chunk", action="store_true", help="train on chunks" - ) + parser.add_argument("--do_chunk", action="store_true", help="train on chunks") parser.add_argument("--chunk_bound", default=-1, type=int) parser.add_argument("--chunk_init", default=50, type=int) parser.add_argument("--chunk_incr", default=5, type=int) @@ -52,5 +51,5 @@ def load_dataset(self, split, **unused_kwargs): chunk_incr=self.args.chunk_incr, add_eos=self.args.add_eos, dedup=self.args.dedup, - ref_fpu=self.args.ref_fpu + ref_fpu=self.args.ref_fpu, ) diff --git a/fairseq/tasks/hubert_pretraining.py b/fairseq/tasks/hubert_pretraining.py index f756080dd1..b8667d42ac 100644 --- a/fairseq/tasks/hubert_pretraining.py +++ b/fairseq/tasks/hubert_pretraining.py @@ -28,15 +28,15 @@ def __init__(self, dictionary: Dictionary) -> None: def __call__(self, label: str) -> List[str]: return self.dictionary.encode_line( - label, append_eos=False, add_if_not_exist=False, + label, + append_eos=False, + add_if_not_exist=False, ) @dataclass class HubertPretrainingConfig(FairseqDataclass): - data: str = field( - default=MISSING, metadata={"help": "path to data directory"} - ) + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) fine_tuning: bool = field( default=False, metadata={"help": "set to true if fine-tuning Hubert"} ) @@ -68,9 +68,7 @@ class HubertPretrainingConfig(FairseqDataclass): ) normalize: bool = field( default=False, - metadata={ - "help": "if set, normalizes input to have 0 mean and unit variance" - }, + metadata={"help": "if set, normalizes input to have 0 mean and unit variance"}, ) enable_padding: bool = field( default=False, @@ -91,8 +89,7 @@ class HubertPretrainingConfig(FairseqDataclass): single_target: Optional[bool] = field( default=False, metadata={ - "help": "if set, AddTargetDatasets outputs same keys " - "as AddTargetDataset" + "help": "if set, AddTargetDatasets outputs same keys " "as AddTargetDataset" }, ) random_crop: Optional[bool] = field( @@ -149,7 +146,10 @@ def setup_task( def load_dictionaries(self): label_dir = self.cfg.data if self.cfg.label_dir is None else self.cfg.label_dir - dictionaries = [Dictionary.load(f"{label_dir}/dict.{label}.txt") for label in self.cfg.labels] + dictionaries = [ + Dictionary.load(f"{label_dir}/dict.{label}.txt") + for label in self.cfg.labels + ] return dictionaries[0] if self.cfg.fine_tuning else dictionaries def get_label_dir(self) -> str: @@ -163,9 +163,7 @@ def load_dataset(self, split: str, **kwargs) -> None: pad_list = [dict.pad() for dict in dicts] eos_list = [dict.eos() for dict in dicts] procs = [LabelEncoder(dict) for dict in dicts] - paths = [ - f"{self.get_label_dir()}/{split}.{l}" for l in self.cfg.labels - ] + paths = [f"{self.get_label_dir()}/{split}.{l}" for l in self.cfg.labels] # hubert v1: pad_audio=True, random_crop=False; self.datasets[split] = HubertDataset( @@ -189,7 +187,5 @@ def load_dataset(self, split: str, **kwargs) -> None: def max_positions(self) -> Tuple[int, int]: return (sys.maxsize, sys.maxsize) - def filter_indices_by_size( - self, indices: np.array, *args, **kwargs - ) -> np.array: + def filter_indices_by_size(self, indices: np.array, *args, **kwargs) -> np.array: return indices diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index 4b76a51c61..aa397de950 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -85,10 +85,12 @@ class LanguageModelingConfig(FairseqDataclass): }, ) pad_to_fixed_length: Optional[bool] = field( - default=False, metadata={"help": "pad to fixed length"}, + default=False, + metadata={"help": "pad to fixed length"}, ) pad_to_fixed_bsz: Optional[bool] = field( - default=False, metadata={"help": "boolean to pad to fixed batch size"}, + default=False, + metadata={"help": "boolean to pad to fixed batch size"}, ) # TODO common vars below add to parent @@ -247,7 +249,9 @@ def load_dataset( pad_to_bsz = None if self.args.pad_to_fixed_bsz: - pad_to_bsz = self.args.batch_size_valid if 'valid' in split else self.args.batch_size + pad_to_bsz = ( + self.args.batch_size_valid if "valid" in split else self.args.batch_size + ) self.datasets[split] = MonolingualDataset( dataset=dataset, diff --git a/fairseq/tasks/simultaneous_translation.py b/fairseq/tasks/simultaneous_translation.py index 11c7dc1ea9..9576b26801 100644 --- a/fairseq/tasks/simultaneous_translation.py +++ b/fairseq/tasks/simultaneous_translation.py @@ -6,12 +6,11 @@ import logging from fairseq.tasks import register_task from fairseq.tasks.speech_to_text import SpeechToTextTask -from fairseq.tasks.translation import ( - TranslationTask, TranslationConfig -) +from fairseq.tasks.translation import TranslationTask, TranslationConfig try: - import examples.simultaneous_translation # noqa + import examples.simultaneous_translation # noqa + import_successful = True except BaseException: import_successful = False @@ -35,7 +34,7 @@ def __init__(self, args, tgt_dict): super().__init__(args, tgt_dict) -@register_task("simul_text_to_text", dataclass=TranslationConfig) +@register_task("simul_text_to_text", dataclass=TranslationConfig) class SimulTextToTextTask(TranslationTask): def __init__(self, cfg, src_dict, tgt_dict): check_import(import_successful) diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 06e292103e..3e568052cb 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -12,7 +12,7 @@ S2TDataConfig, SpeechToTextDataset, SpeechToTextDatasetCreator, - get_features_or_waveform + get_features_or_waveform, ) from fairseq.tasks import LegacyFairseqTask, register_task @@ -101,7 +101,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): is_train_split=is_train_split, epoch=epoch, seed=self.args.seed, - speaker_to_id=self.speaker_to_id + speaker_to_id=self.speaker_to_id, ) @property @@ -143,8 +143,7 @@ def build_generator( extra_gen_cls_kwargs = {} extra_gen_cls_kwargs["symbols_to_strip_from_output"] = lang_token_ids return super().build_generator( - models, args, seq_gen_cls=None, - extra_gen_cls_kwargs=extra_gen_cls_kwargs + models, args, seq_gen_cls=None, extra_gen_cls_kwargs=extra_gen_cls_kwargs ) def build_tokenizer(self, args): diff --git a/fairseq/tasks/text_to_speech.py b/fairseq/tasks/text_to_speech.py index 5646e41d39..bdbf87f6e9 100644 --- a/fairseq/tasks/text_to_speech.py +++ b/fairseq/tasks/text_to_speech.py @@ -15,13 +15,15 @@ from fairseq.tasks import register_task from fairseq.tasks.speech_to_text import SpeechToTextTask from fairseq.speech_generator import ( - AutoRegressiveSpeechGenerator, NonAutoregressiveSpeechGenerator, - TeacherForcingAutoRegressiveSpeechGenerator + AutoRegressiveSpeechGenerator, + NonAutoregressiveSpeechGenerator, + TeacherForcingAutoRegressiveSpeechGenerator, ) logging.basicConfig( - format='%(asctime)s | %(levelname)s | %(name)s | %(message)s', - datefmt='%Y-%m-%d %H:%M:%S', level=logging.INFO + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=logging.INFO, ) logger = logging.getLogger(__name__) @@ -33,21 +35,31 @@ SummaryWriter = None -@register_task('text_to_speech') +@register_task("text_to_speech") class TextToSpeechTask(SpeechToTextTask): @staticmethod def add_args(parser): - parser.add_argument('data', help='manifest root path') + parser.add_argument("data", help="manifest root path") parser.add_argument( - '--config-yaml', type=str, default='config.yaml', - help='Configuration YAML filename (under manifest root)' + "--config-yaml", + type=str, + default="config.yaml", + help="Configuration YAML filename (under manifest root)", + ) + parser.add_argument( + "--max-source-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the source sequence", + ) + parser.add_argument( + "--max-target-positions", + default=1200, + type=int, + metavar="N", + help="max number of tokens in the target sequence", ) - parser.add_argument('--max-source-positions', default=1024, type=int, - metavar='N', - help='max number of tokens in the source sequence') - parser.add_argument('--max-target-positions', default=1200, type=int, - metavar='N', - help='max number of tokens in the target sequence') parser.add_argument("--n-frames-per-step", type=int, default=1) parser.add_argument("--eos-prob-threshold", type=float, default=0.5) parser.add_argument("--eval-inference", action="store_true") @@ -63,19 +75,24 @@ def __init__(self, args, src_dict): self.tensorboard_writer = None self.tensorboard_dir = "" if args.tensorboard_logdir and SummaryWriter is not None: - self.tensorboard_dir = os.path.join(args.tensorboard_logdir, - "valid_extra") + self.tensorboard_dir = os.path.join(args.tensorboard_logdir, "valid_extra") def load_dataset(self, split, epoch=1, combine=False, **kwargs): - is_train_split = split.startswith('train') + is_train_split = split.startswith("train") pre_tokenizer = self.build_tokenizer(self.args) bpe_tokenizer = self.build_bpe(self.args) self.datasets[split] = TextToSpeechDatasetCreator.from_tsv( - self.args.data, self.data_cfg, split, self.src_dict, - pre_tokenizer, bpe_tokenizer, is_train_split=is_train_split, - epoch=epoch, seed=self.args.seed, + self.args.data, + self.data_cfg, + split, + self.src_dict, + pre_tokenizer, + bpe_tokenizer, + is_train_split=is_train_split, + epoch=epoch, + seed=self.args.seed, n_frames_per_step=self.args.n_frames_per_step, - speaker_to_id=self.speaker_to_id + speaker_to_id=self.speaker_to_id, ) @property @@ -106,7 +123,8 @@ def get_speaker_embeddings(cls, args): speaker_emb_mat = np.load(args.speaker_emb_path) assert speaker_emb_mat.shape[1] == args.speaker_embed_dim embed_speaker = torch.nn.Embedding.from_pretrained( - torch.from_numpy(speaker_emb_mat), freeze=True, + torch.from_numpy(speaker_emb_mat), + freeze=True, ) logger.info( f"load speaker embeddings from {args.speaker_emb_path}. " @@ -132,22 +150,23 @@ def build_generator(self, models, cfg, vocoder=None, **unused): vocoder = self.build_default_vocoder() model = models[0] if getattr(model, "NON_AUTOREGRESSIVE", False): - return NonAutoregressiveSpeechGenerator( - model, vocoder, self.data_cfg - ) + return NonAutoregressiveSpeechGenerator(model, vocoder, self.data_cfg) else: generator = AutoRegressiveSpeechGenerator if getattr(cfg, "teacher_forcing", False): generator = TeacherForcingAutoRegressiveSpeechGenerator logger.info("Teacher forcing mode for generation") return generator( - model, vocoder, self.data_cfg, + model, + vocoder, + self.data_cfg, max_iter=self.args.max_target_positions, - eos_prob_threshold=self.args.eos_prob_threshold + eos_prob_threshold=self.args.eos_prob_threshold, ) def build_default_vocoder(self): from fairseq.models.text_to_speech.vocoder import get_vocoder + vocoder = get_vocoder(self.args, self.data_cfg) if torch.cuda.is_available() and not self.args.cpu: vocoder = vocoder.cuda() @@ -156,25 +175,23 @@ def build_default_vocoder(self): return vocoder def valid_step(self, sample, model, criterion): - loss, sample_size, logging_output = super().valid_step( - sample, model, criterion - ) + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) if getattr(self.args, "eval_inference", False): hypos, inference_losses = self.valid_step_with_inference( sample, model, self.generator ) for k, v in inference_losses.items(): - assert(k not in logging_output) + assert k not in logging_output logging_output[k] = v picked_id = 0 if self.tensorboard_dir and (sample["id"] == picked_id).any(): self.log_tensorboard( sample, - hypos[:self.args.eval_tb_nsample], + hypos[: self.args.eval_tb_nsample], model._num_updates, - is_na_model=getattr(model, "NON_AUTOREGRESSIVE", False) + is_na_model=getattr(model, "NON_AUTOREGRESSIVE", False), ) return loss, sample_size, logging_output @@ -182,17 +199,17 @@ def valid_step_with_inference(self, sample, model, generator): hypos = generator.generate(model, sample, has_targ=True) losses = { - "mcd_loss": 0., - "targ_frames": 0., - "pred_frames": 0., - "nins": 0., - "ndel": 0., + "mcd_loss": 0.0, + "targ_frames": 0.0, + "pred_frames": 0.0, + "nins": 0.0, + "ndel": 0.0, } rets = batch_mel_cepstral_distortion( [hypo["targ_waveform"] for hypo in hypos], [hypo["waveform"] for hypo in hypos], self.sr, - normalize_type=None + normalize_type=None, ) for d, extra in rets: pathmap = extra[-1] @@ -218,41 +235,40 @@ def log_tensorboard(self, sample, hypos, num_updates, is_na_model=False): if is_na_model: data = plot_tts_output( [targ.transpose(0, 1), pred.transpose(0, 1)], - [f"target (idx={idx})", "output"], attn, - "alignment", ret_np=True, suptitle=text, + [f"target (idx={idx})", "output"], + attn, + "alignment", + ret_np=True, + suptitle=text, ) else: eos_prob = hypos[b]["eos_prob"] data = plot_tts_output( [targ.transpose(0, 1), pred.transpose(0, 1), attn], - [f"target (idx={idx})", "output", "alignment"], eos_prob, - "eos prob", ret_np=True, suptitle=text, + [f"target (idx={idx})", "output", "alignment"], + eos_prob, + "eos prob", + ret_np=True, + suptitle=text, ) tb_writer.add_image( - f"inference_sample_{b}", data, num_updates, - dataformats="HWC" + f"inference_sample_{b}", data, num_updates, dataformats="HWC" ) if hypos[b]["waveform"] is not None: targ_wave = hypos[b]["targ_waveform"].detach().cpu().float() pred_wave = hypos[b]["waveform"].detach().cpu().float() tb_writer.add_audio( - f"inference_targ_{b}", - targ_wave, - num_updates, - sample_rate=self.sr + f"inference_targ_{b}", targ_wave, num_updates, sample_rate=self.sr ) tb_writer.add_audio( - f"inference_pred_{b}", - pred_wave, - num_updates, - sample_rate=self.sr + f"inference_pred_{b}", pred_wave, num_updates, sample_rate=self.sr ) def save_figure_to_numpy(fig): - data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='') + data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep="") data = data.reshape(fig.canvas.get_width_height()[::-1] + (3,)) return data @@ -261,8 +277,15 @@ def save_figure_to_numpy(fig): def plot_tts_output( - data_2d, title_2d, data_1d, title_1d, figsize=(24, 4), - v_min=DEFAULT_V_MIN, v_max=3, ret_np=False, suptitle="" + data_2d, + title_2d, + data_1d, + title_1d, + figsize=(24, 4), + v_min=DEFAULT_V_MIN, + v_max=3, + ret_np=False, + suptitle="", ): try: import matplotlib.pyplot as plt @@ -271,8 +294,8 @@ def plot_tts_output( raise ImportError("Please install Matplotlib: pip install matplotlib") data_2d = [ - x.detach().cpu().float().numpy() - if isinstance(x, torch.Tensor) else x for x in data_2d + x.detach().cpu().float().numpy() if isinstance(x, torch.Tensor) else x + for x in data_2d ] fig, axes = plt.subplots(1, len(data_2d) + 1, figsize=figsize) if suptitle: @@ -281,12 +304,15 @@ def plot_tts_output( for ax, x, name in zip(axes, data_2d, title_2d): ax.set_title(name) divider = make_axes_locatable(ax) - cax = divider.append_axes('right', size='5%', pad=0.05) + cax = divider.append_axes("right", size="5%", pad=0.05) im = ax.imshow( - x, origin="lower", aspect="auto", vmin=max(x.min(), v_min), - vmax=min(x.max(), v_max) + x, + origin="lower", + aspect="auto", + vmin=max(x.min(), v_min), + vmax=min(x.max(), v_max), ) - fig.colorbar(im, cax=cax, orientation='vertical') + fig.colorbar(im, cax=cax, orientation="vertical") if isinstance(data_1d, torch.Tensor): data_1d = data_1d.detach().cpu().numpy() @@ -349,9 +375,12 @@ def batch_dynamic_time_warping(distance, shapes=None): for offset in range(2, m + n - 1): ind = antidiag_indices(offset, 1, m, 1, n) c = torch.stack( - [cumdist[:, ind[0], ind[1] - 1], cumdist[:, ind[0] - 1, ind[1] - 1], - cumdist[:, ind[0] - 1, ind[1]], ], - dim=2 + [ + cumdist[:, ind[0], ind[1] - 1], + cumdist[:, ind[0] - 1, ind[1] - 1], + cumdist[:, ind[0] - 1, ind[1]], + ], + dim=2, ) v, b = c.min(axis=-1) backptr[:, ind[0], ind[1]] = b.int() @@ -364,7 +393,7 @@ def batch_dynamic_time_warping(distance, shapes=None): j = n - 1 if shapes is None else (shapes[b][1] - 1).item() dtwpath = [(i, j)] while (i != 0 or j != 0) and len(dtwpath) < 10000: - assert (i >= 0 and j >= 0) + assert i >= 0 and j >= 0 di, dj = ptr2dij[backptr[b, i, j].item()] i, j = i + di, j + dj dtwpath.append((i, j)) @@ -401,7 +430,7 @@ def get_divisor(pathmap, normalize_type): def batch_compute_distortion(y1, y2, sr, feat_fn, dist_fn, normalize_type): d, s, x1, x2 = [], [], [], [] for cur_y1, cur_y2 in zip(y1, y2): - assert (cur_y1.ndim == 1 and cur_y2.ndim == 1) + assert cur_y1.ndim == 1 and cur_y2.ndim == 1 cur_x1 = feat_fn(cur_y1) cur_x2 = feat_fn(cur_y2) x1.append(cur_x1) @@ -432,9 +461,7 @@ def batch_compute_distortion(y1, y2, sr, feat_fn, dist_fn, normalize_type): return rets -def batch_mel_cepstral_distortion( - y1, y2, sr, normalize_type="path", mfcc_fn=None -): +def batch_mel_cepstral_distortion(y1, y2, sr, normalize_type="path", mfcc_fn=None): """ https://arxiv.org/pdf/2011.03568.pdf @@ -454,14 +481,21 @@ def batch_mel_cepstral_distortion( if mfcc_fn is None or mfcc_fn.sample_rate != sr: melkwargs = { - "n_fft": int(0.05 * sr), "win_length": int(0.05 * sr), - "hop_length": int(0.0125 * sr), "f_min": 20, - "n_mels": 80, "window_fn": torch.hann_window + "n_fft": int(0.05 * sr), + "win_length": int(0.05 * sr), + "hop_length": int(0.0125 * sr), + "f_min": 20, + "n_mels": 80, + "window_fn": torch.hann_window, } mfcc_fn = torchaudio.transforms.MFCC( sr, n_mfcc=13, log_mels=True, melkwargs=melkwargs ).to(y1[0].device) return batch_compute_distortion( - y1, y2, sr, lambda y: mfcc_fn(y).transpose(-1, -2), compute_rms_dist, - normalize_type + y1, + y2, + sr, + lambda y: mfcc_fn(y).transpose(-1, -2), + compute_rms_dist, + normalize_type, ) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 8647360867..f5a3cf6667 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -399,6 +399,7 @@ def reduce_metrics(self, logging_outputs, criterion): def sum_logs(key): import torch + result = sum(log.get(key, 0) for log in logging_outputs) if torch.is_tensor(result): result = result.cpu() @@ -418,12 +419,15 @@ def sum_logs(key): def compute_bleu(meters): import inspect + try: from sacrebleu.metrics import BLEU + comp_bleu = BLEU.compute_bleu except ImportError: # compatibility API for sacrebleu 1.x import sacrebleu + comp_bleu = sacrebleu.compute_bleu fn_sig = inspect.getfullargspec(comp_bleu)[0] @@ -436,7 +440,7 @@ def compute_bleu(meters): total=meters["_bleu_totals"].sum, sys_len=meters["_bleu_sys_len"].sum, ref_len=meters["_bleu_ref_len"].sum, - **smooth + **smooth, ) return round(bleu.score, 2) diff --git a/fairseq/tasks/translation_lev.py b/fairseq/tasks/translation_lev.py index 041279305d..b45fecd1f4 100644 --- a/fairseq/tasks/translation_lev.py +++ b/fairseq/tasks/translation_lev.py @@ -9,21 +9,25 @@ from fairseq.data import LanguagePairDataset from fairseq.dataclass import ChoiceEnum from fairseq.tasks import register_task -from fairseq.tasks.translation import TranslationConfig, TranslationTask, load_langpair_dataset +from fairseq.tasks.translation import ( + TranslationConfig, + TranslationTask, + load_langpair_dataset, +) from fairseq.utils import new_arange NOISE_CHOICES = ChoiceEnum(["random_delete", "random_mask", "no_noise", "full_mask"]) + @dataclass class TranslationLevenshteinConfig(TranslationConfig): noise: NOISE_CHOICES = field( default="random_delete", - metadata={ - "help": "type of noise" - }, + metadata={"help": "type of noise"}, ) + @register_task("translation_lev", dataclass=TranslationLevenshteinConfig) class TranslationLevenshteinTask(TranslationTask): """ diff --git a/fairseq/tasks/translation_multi_simple_epoch.py b/fairseq/tasks/translation_multi_simple_epoch.py index e64ab9a687..2ba012e88a 100644 --- a/fairseq/tasks/translation_multi_simple_epoch.py +++ b/fairseq/tasks/translation_multi_simple_epoch.py @@ -197,7 +197,11 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None) return dataset def build_generator( - self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None, + self, + models, + args, + seq_gen_cls=None, + extra_gen_cls_kwargs=None, ): if not getattr(args, "keep_inference_langtok", False): _, tgt_langtok_spec = self.args.langtoks["main"] diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 30e12dcc98..ac24edb2e5 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -337,7 +337,10 @@ def _build_optimizer(self): ) if self.cfg.optimization.use_bmuf: - self._optimizer = optim.FairseqBMUF(self.cfg.bmuf, self._optimizer,) + self._optimizer = optim.FairseqBMUF( + self.cfg.bmuf, + self._optimizer, + ) if self.cfg.distributed_training.zero_sharding == "os": if ( @@ -355,7 +358,8 @@ def _build_optimizer(self): # We should initialize the learning rate scheduler immediately after # building the optimizer, so that the initial learning rate is set. self._lr_scheduler = lr_scheduler.build_lr_scheduler( - self.cfg.lr_scheduler, self.optimizer, + self.cfg.lr_scheduler, + self.optimizer, ) self._lr_scheduler.step_update(0) @@ -652,7 +656,9 @@ def get_train_iterator( return batch_iterator def get_valid_iterator( - self, subset, disable_iterator_cache=False, + self, + subset, + disable_iterator_cache=False, ): """Return an EpochBatchIterator over given validation subset for a given epoch.""" batch_iterator = self.task.get_batch_iterator( @@ -660,7 +666,8 @@ def get_valid_iterator( max_tokens=self.cfg.dataset.max_tokens_valid, max_sentences=self.cfg.dataset.batch_size_valid, max_positions=utils.resolve_max_positions( - self.task.max_positions(), self.model.max_positions(), + self.task.max_positions(), + self.model.max_positions(), ), ignore_invalid_inputs=self.cfg.dataset.skip_invalid_size_inputs_valid_test, required_batch_size_multiple=self.cfg.dataset.required_batch_size_multiple, @@ -809,7 +816,11 @@ def maybe_no_sync(): train_time = self._local_cumulative_training_time() ( logging_outputs, - (sample_size, ooms, total_train_time,), + ( + sample_size, + ooms, + total_train_time, + ), ) = self._aggregate_logging_outputs( logging_outputs, sample_size, ooms, train_time, ignore=is_dummy_batch ) @@ -924,7 +935,8 @@ def maybe_no_sync(): if self.cfg.ema.store_ema: # Step EMA forward with new model. self.ema.step( - self.get_model(), self.get_num_updates(), + self.get_model(), + self.get_num_updates(), ) metrics.log_scalar( "ema_decay", @@ -1058,7 +1070,9 @@ def valid_step(self, sample, raise_oom=False): # gather logging outputs from all replicas if self.data_parallel_world_size > 1: logging_outputs, (sample_size,) = self._aggregate_logging_outputs( - logging_outputs, sample_size, ignore=is_dummy_batch, + logging_outputs, + sample_size, + ignore=is_dummy_batch, ) # log validation stats @@ -1260,9 +1274,10 @@ def _sync_stats(self): return False elif self.cfg.optimization.use_bmuf: return ( - (self.get_num_updates() + 1) % self.cfg.bmuf.global_sync_iter == 0 - and (self.get_num_updates() + 1) > self.cfg.bmuf.warmup_iterations - ) + self.get_num_updates() + 1 + ) % self.cfg.bmuf.global_sync_iter == 0 and ( + self.get_num_updates() + 1 + ) > self.cfg.bmuf.warmup_iterations else: return True @@ -1275,7 +1290,10 @@ def _log_oom(self, exc): sys.stderr.flush() def _aggregate_logging_outputs( - self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, + self, + logging_outputs: List[Dict[str, Any]], + *extra_stats_to_sum, + ignore=False, ): if self.task.__class__.logging_outputs_can_be_summed(self.get_criterion()): return self._fast_stat_sync_sum( @@ -1287,7 +1305,10 @@ def _aggregate_logging_outputs( ) def _all_gather_list_sync( - self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, + self, + logging_outputs: List[Dict[str, Any]], + *extra_stats_to_sum, + ignore=False, ): """ Sync logging outputs across workers. all_gather_list_sync is @@ -1312,7 +1333,10 @@ def _all_gather_list_sync( return logging_outputs, extra_stats_to_sum def _fast_stat_sync_sum( - self, logging_outputs: List[Dict[str, Any]], *extra_stats_to_sum, ignore=False, + self, + logging_outputs: List[Dict[str, Any]], + *extra_stats_to_sum, + ignore=False, ): """ Sync logging outputs across workers. fast_stat_sync_sum is diff --git a/fairseq/utils.py b/fairseq/utils.py index 94114ce15c..0f84896153 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -85,7 +85,9 @@ def _apply(x): return f(x) elif isinstance(x, collections.OrderedDict): # OrderedDict has attributes that needs to be preserved - od = collections.OrderedDict((key, _apply(value)) for key, value in x.items()) + od = collections.OrderedDict( + (key, _apply(value)) for key, value in x.items() + ) od.__dict__ = x.__dict__ return od elif isinstance(x, dict): @@ -536,6 +538,7 @@ def deprecation_warning(message, stacklevel=3): # don't use DeprecationWarning, since it's ignored by default warnings.warn(message, stacklevel=stacklevel) + def relu_squared(x: torch.Tensor): return F.relu(x).pow(2) diff --git a/fairseq_cli/generate.py b/fairseq_cli/generate.py index 7e887e8864..b8757835d4 100644 --- a/fairseq_cli/generate.py +++ b/fairseq_cli/generate.py @@ -17,11 +17,12 @@ import numpy as np import torch +from omegaconf import DictConfig + from fairseq import checkpoint_utils, options, scoring, tasks, utils from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar from fairseq.logging.meters import StopwatchMeter, TimeMeter -from omegaconf import DictConfig def main(cfg: DictConfig): @@ -81,7 +82,6 @@ def _main(cfg: DictConfig, output_file): # Load dataset splits task = tasks.setup_task(cfg.task) - # Set dictionaries try: src_dict = getattr(task, "source_dictionary", None) @@ -316,10 +316,7 @@ def decode_fn(x): "A-{}\t{}".format( sample_id, " ".join( - [ - ",".join(src_probs) - for src_probs in alignment - ] + [",".join(src_probs) for src_probs in alignment] ), ), file=output_file, @@ -348,7 +345,10 @@ def decode_fn(x): # Score only the top hypothesis if has_target and j == 0: - if align_dict is not None or cfg.common_eval.post_process is not None: + if ( + align_dict is not None + or cfg.common_eval.post_process is not None + ): # Convert back to tokens for evaluation with unk replacement and/or without BPE target_tokens = tgt_dict.encode_line( target_str, add_if_not_exist=True @@ -402,9 +402,12 @@ def cli_main(): parser = options.get_generation_parser() # TODO: replace this workaround with refactoring of `AudioPretraining` parser.add_argument( - '--arch', '-a', metavar='ARCH', default="wav2vec2", - help='Model architecture. For constructing tasks that rely on ' - 'model args (e.g. `AudioPretraining`)' + "--arch", + "-a", + metavar="ARCH", + default="wav2vec2", + help="Model architecture. For constructing tasks that rely on " + "model args (e.g. `AudioPretraining`)", ) args = options.parse_args_and_arch(parser) main(args) diff --git a/fairseq_cli/hydra_train.py b/fairseq_cli/hydra_train.py index 6555ab415e..607340af0d 100644 --- a/fairseq_cli/hydra_train.py +++ b/fairseq_cli/hydra_train.py @@ -7,18 +7,17 @@ import logging import os -from fairseq.dataclass.initialize import add_defaults, hydra_init -from fairseq_cli.train import main as pre_main -from fairseq import distributed_utils, metrics -from fairseq.dataclass.configs import FairseqConfig -from fairseq.dataclass.utils import omegaconf_no_object_check -from fairseq.utils import reset_logging - import hydra -from hydra.core.hydra_config import HydraConfig import torch +from hydra.core.hydra_config import HydraConfig from omegaconf import OmegaConf, open_dict +from fairseq import distributed_utils, metrics +from fairseq.dataclass.configs import FairseqConfig +from fairseq.dataclass.initialize import add_defaults, hydra_init +from fairseq.dataclass.utils import omegaconf_no_object_check +from fairseq.utils import reset_logging +from fairseq_cli.train import main as pre_main logger = logging.getLogger("fairseq_cli.hydra_train") @@ -38,10 +37,14 @@ def _hydra_main(cfg: FairseqConfig, **kwargs) -> float: if HydraConfig.initialized(): with open_dict(cfg): # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) - cfg.job_logging_cfg = OmegaConf.to_container(HydraConfig.get().job_logging, resolve=True) + cfg.job_logging_cfg = OmegaConf.to_container( + HydraConfig.get().job_logging, resolve=True + ) with omegaconf_no_object_check(): - cfg = OmegaConf.create(OmegaConf.to_container(cfg, resolve=True, enum_to_str=True)) + cfg = OmegaConf.create( + OmegaConf.to_container(cfg, resolve=True, enum_to_str=True) + ) OmegaConf.set_struct(cfg, True) try: diff --git a/fairseq_cli/interactive.py b/fairseq_cli/interactive.py index cadef2821a..03265d00e8 100644 --- a/fairseq_cli/interactive.py +++ b/fairseq_cli/interactive.py @@ -19,13 +19,13 @@ import numpy as np import torch + from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.token_generation_constraints import pack_constraints, unpack_constraints from fairseq_cli.generate import get_symbols_to_strip_from_output - logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", @@ -249,7 +249,7 @@ def decode_fn(x): # sort output to match input order for id_, src_tokens, hypos, info in sorted(results, key=lambda x: x[0]): - src_str = '' + src_str = "" if src_dict is not None: src_str = src_dict.string(src_tokens, cfg.common_eval.post_process) print("S-{}\t{}".format(id_, src_str)) @@ -257,7 +257,8 @@ def decode_fn(x): for constraint in info["constraints"]: print( "C-{}\t{}".format( - id_, tgt_dict.string(constraint, cfg.common_eval.post_process) + id_, + tgt_dict.string(constraint, cfg.common_eval.post_process), ) ) diff --git a/fairseq_cli/preprocess.py b/fairseq_cli/preprocess.py index 4ee9a1e3ba..6f24983d23 100644 --- a/fairseq_cli/preprocess.py +++ b/fairseq_cli/preprocess.py @@ -41,7 +41,9 @@ def main(args): ) logger.info(args) - assert args.dataset_impl != "huffman", "preprocessing.py doesn't support Huffman yet, use HuffmanCodeBuilder directly." + assert ( + args.dataset_impl != "huffman" + ), "preprocessing.py doesn't support Huffman yet, use HuffmanCodeBuilder directly." task = tasks.get_task(args.task) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 369a8a82c5..a707add735 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -12,7 +12,7 @@ import math import os import sys -from typing import Dict, Optional, Any, List, Tuple, Callable +from typing import Any, Callable, Dict, List, Optional, Tuple # We need to setup root logger before importing any fairseq libraries. logging.basicConfig( @@ -25,23 +25,19 @@ import numpy as np import torch -from fairseq import ( - checkpoint_utils, - options, - quantization_utils, - tasks, - utils, -) -from fairseq.data import iterators, data_utils +from omegaconf import DictConfig, OmegaConf + +from fairseq import checkpoint_utils, options, quantization_utils, tasks, utils +from fairseq.data import data_utils, iterators from fairseq.data.plasma_utils import PlasmaStore from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf -from fairseq.distributed import fsdp_enable_wrap, fsdp_wrap, utils as distributed_utils +from fairseq.distributed import fsdp_enable_wrap, fsdp_wrap +from fairseq.distributed import utils as distributed_utils from fairseq.file_io import PathManager from fairseq.logging import meters, metrics, progress_bar from fairseq.model_parallel.megatron_trainer import MegatronTrainer from fairseq.trainer import Trainer -from omegaconf import DictConfig, OmegaConf def main(cfg: FairseqConfig) -> None: @@ -156,7 +152,8 @@ def main(cfg: FairseqConfig) -> None: ) logger.info( "max tokens per device = {} and max sentences per device = {}".format( - cfg.dataset.max_tokens, cfg.dataset.batch_size, + cfg.dataset.max_tokens, + cfg.dataset.batch_size, ) ) @@ -259,7 +256,9 @@ def train( else cfg.optimization.update_freq[-1] ) itr = iterators.GroupedIterator( - itr, update_freq, skip_remainder_batch=cfg.optimization.skip_remainder_batch, + itr, + update_freq, + skip_remainder_batch=cfg.optimization.skip_remainder_batch, ) if cfg.common.tpu: itr = utils.tpu_data_loader(itr) diff --git a/fairseq_cli/validate.py b/fairseq_cli/validate.py index 22b93e9a6a..4617b6d542 100644 --- a/fairseq_cli/validate.py +++ b/fairseq_cli/validate.py @@ -11,12 +11,12 @@ from itertools import chain import torch +from omegaconf import DictConfig + from fairseq import checkpoint_utils, distributed_utils, options, utils from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import metrics, progress_bar from fairseq.utils import reset_logging -from omegaconf import DictConfig - logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -142,9 +142,7 @@ def cli_main(): # only override args that are explicitly given on the command line override_parser = options.get_validation_parser() - override_args = options.parse_args_and_arch( - override_parser, suppress_defaults=True - ) + override_args = options.parse_args_and_arch(override_parser, suppress_defaults=True) distributed_utils.call_main( convert_namespace_to_omegaconf(args), main, override_args=override_args diff --git a/setup.py b/setup.py index 4bf1e60dd1..c5591915fa 100644 --- a/setup.py +++ b/setup.py @@ -7,11 +7,9 @@ import os import subprocess import sys -from setuptools import setup, find_packages, Extension from setuptools import Extension, find_packages, setup - if sys.version_info < (3, 6): sys.exit("Sorry, Python >= 3.6 is required for fairseq.") @@ -277,7 +275,8 @@ def get_files(path, relative_to="fairseq"): package_data = { "fairseq": ( - get_files(fairseq_examples) + get_files(os.path.join("fairseq", "config")) + get_files(fairseq_examples) + + get_files(os.path.join("fairseq", "config")) ) } do_setup(package_data) diff --git a/tests/distributed/test_bmuf.py b/tests/distributed/test_bmuf.py index 8b7cadb094..2a0f20d0be 100644 --- a/tests/distributed/test_bmuf.py +++ b/tests/distributed/test_bmuf.py @@ -11,9 +11,10 @@ import torch import torch.nn as nn +from omegaconf import OmegaConf + from fairseq import optim from fairseq.distributed import utils as distributed_utils -from omegaconf import OmegaConf class Model(nn.Module): @@ -42,10 +43,7 @@ def setup_model_loss_criterion(cfg, args, rank, is_cuda): loss_fn = loss_fn.cuda() optimizer = optim.sgd.SGD(args, model.parameters()) - optimizer = optim.FairseqBMUF( - cfg=cfg.bmuf, - optimizer=optimizer - ) + optimizer = optim.FairseqBMUF(cfg=cfg.bmuf, optimizer=optimizer) return model, loss_fn, optimizer diff --git a/tests/distributed/test_distributed_timeout_wrapper.py b/tests/distributed/test_distributed_timeout_wrapper.py index 27908b9d3f..996093cb2d 100644 --- a/tests/distributed/test_distributed_timeout_wrapper.py +++ b/tests/distributed/test_distributed_timeout_wrapper.py @@ -15,7 +15,6 @@ class ModuleWithDelay(nn.Module): - def __init__(self, delay): super().__init__() self.delay = delay @@ -26,7 +25,6 @@ def forward(self, x): class TestDistributedTimeoutWrapper(unittest.TestCase): - def setUp(self): logging.disable(logging.CRITICAL) diff --git a/tests/distributed/test_module_proxy_wrapper.py b/tests/distributed/test_module_proxy_wrapper.py index 2803a044cd..2ac1a877c3 100644 --- a/tests/distributed/test_module_proxy_wrapper.py +++ b/tests/distributed/test_module_proxy_wrapper.py @@ -38,7 +38,6 @@ def get_xyz(self): class TestModuleProxyWrapper(unittest.TestCase): - def _get_module(self): module = Model() wrapped_module = MockDDPWrapper(module) diff --git a/tests/distributed/utils.py b/tests/distributed/utils.py index c8040392a8..be4e19cd1e 100644 --- a/tests/distributed/utils.py +++ b/tests/distributed/utils.py @@ -15,7 +15,10 @@ def spawn_and_init(fn, world_size, args=None): with tempfile.NamedTemporaryFile(delete=False) as tmp_file: torch.multiprocessing.spawn( fn=functools.partial(init_and_run, fn, args), - args=(world_size, tmp_file.name,), + args=( + world_size, + tmp_file.name, + ), nprocs=world_size, join=True, ) diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 99eb7f558e..550e751b1f 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -4,14 +4,15 @@ # LICENSE file in the root directory of this source tree. import contextlib -import logging import json +import logging import os import tempfile import unittest from io import StringIO import torch + from fairseq import options from fairseq_cli import train from tests.utils import ( @@ -32,20 +33,17 @@ def tearDown(self): logging.disable(logging.NOTSET) def test_fp16_multigpu(self): - self._test_multigpu( - "test_fp16", ["--fp16"] - ) + self._test_multigpu("test_fp16", ["--fp16"]) def test_slowmo_multigpu(self): self._test_multigpu( - "test_slowmo", - ["--ddp-backend", "slowmo", "--nprocs-per-node", "1"] + "test_slowmo", ["--ddp-backend", "slowmo", "--nprocs-per-node", "1"] ) def test_slowmo_single_node_multigpu(self): self._test_multigpu( "test_slowmo_single_node", - ["--ddp-backend", "slowmo", "--nprocs-per-node", "2"] + ["--ddp-backend", "slowmo", "--nprocs-per-node", "2"], ) def _test_multigpu(self, test_name, test_args): @@ -77,7 +75,9 @@ def test_resume_training_fsdp(self): self._test_resume_training(["--ddp-backend", "fully_sharded"]) def test_resume_training_fsdp_sharded_state(self): - self._test_resume_training(["--ddp-backend", "fully_sharded", "--use-sharded-state"]) + self._test_resume_training( + ["--ddp-backend", "fully_sharded", "--use-sharded-state"] + ) def test_resume_training_noc10d(self): self._test_resume_training([]) @@ -101,7 +101,10 @@ def _test_resume_training(self, extra_clargs, arch="fconv_iwslt_de_en"): create_dummy_data(data_dir) preprocess_translation_data(data_dir) train_translation_model( - data_dir, arch, flags + ["--log-file", log], world_size=world_size, + data_dir, + arch, + flags + ["--log-file", log], + world_size=world_size, ) log2 = os.path.join(data_dir, "resume.log") restore_file = os.path.join(data_dir, "checkpoint_1_2.pt") @@ -261,7 +264,13 @@ def test_fsdp_sharded_checkpoint_generate(self): train_translation_model( data_dir, "fconv_iwslt_de_en", - ["--log-file", log, "--ddp-backend", "fully_sharded", "--use-sharded-state"], + [ + "--log-file", + log, + "--ddp-backend", + "fully_sharded", + "--use-sharded-state", + ], world_size=world_size, ) generate_main(data_dir, ["--checkpoint-shard-count", str(world_size)]) diff --git a/tests/gpu/test_ema_gpu.py b/tests/gpu/test_ema_gpu.py index 337107d69a..34d9ccb788 100644 --- a/tests/gpu/test_ema_gpu.py +++ b/tests/gpu/test_ema_gpu.py @@ -9,6 +9,7 @@ from typing import Optional import torch + from fairseq.models.ema import EMA @@ -45,9 +46,7 @@ def assertTorchAllClose(self, x, y, atol=1e-8, rtol=1e-5, msg=None): other_norm = torch.norm(y.float()) if msg is None: - msg = "|input - other| > {} + {} * |other|".format( - atol, rtol - ) + msg = "|input - other| > {} + {} * |other|".format(atol, rtol) self.assertLessEqual( diff_norm, @@ -104,9 +103,7 @@ def test_ema(self): for key, param in model2.state_dict().items(): ema_param = ema_state_dict[key] - self.assertTrue( - torch.allclose(ema_param, param) - ) + self.assertTrue(torch.allclose(ema_param, param)) def test_ema_fp32(self): model = DummyModule().cuda().half() @@ -136,17 +133,27 @@ def test_ema_fp32(self): # closer to the EMA update done in fp32 than in fp16. self.assertLessEqual( torch.norm( - ema_param.float() - - (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ema_param.float() + - ( + config.ema_decay * prev_param.float() + + (1 - config.ema_decay) * param.float() + ) + .half() + .float() ), torch.norm( - ema_param.float() - - (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ema_param.float() + - ( + config.ema_decay * prev_param + (1 - config.ema_decay) * param + ).float() ), ) self.assertTorchAllClose( ema_param, - (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half(), + ( + config.ema_decay * prev_param.float() + + (1 - config.ema_decay) * param.float() + ).half(), ) def test_ema_fp16(self): @@ -179,12 +186,19 @@ def test_ema_fp16(self): # closer to the EMA update done in fp16 than in fp32. self.assertLessEqual( torch.norm( - ema_param.float() - - (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ema_param.float() + - ( + config.ema_decay * prev_param + (1 - config.ema_decay) * param + ).float() ), torch.norm( - ema_param.float() - - (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ema_param.float() + - ( + config.ema_decay * prev_param.float() + + (1 - config.ema_decay) * param.float() + ) + .half() + .float() ), ) self.assertTorchAllClose( diff --git a/tests/test_amp_optimizer.py b/tests/test_amp_optimizer.py index 3a785e1830..4d6073a926 100644 --- a/tests/test_amp_optimizer.py +++ b/tests/test_amp_optimizer.py @@ -8,7 +8,8 @@ import unittest import torch -from torch.cuda.amp import autocast, GradScaler +from torch.cuda.amp import GradScaler, autocast + from fairseq.optim import build_optimizer @@ -58,15 +59,11 @@ def run_iter(self, model, params, optimizer): self.scaler.update() self.assertEqual( model.weight, - torch.tensor( - [[3.1]], device="cuda:0", requires_grad=True - ), + torch.tensor([[3.1]], device="cuda:0", requires_grad=True), ) self.assertEqual( model.bias, - torch.tensor( - [5.1], device="cuda:0", requires_grad=True - ), + torch.tensor([5.1], device="cuda:0", requires_grad=True), ) self.assertEqual(self.scaler.get_scale(), 2.0) diff --git a/tests/test_binaries.py b/tests/test_binaries.py index bc233192f9..1ab92f5f7e 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -4,30 +4,31 @@ # LICENSE file in the root directory of this source tree. import contextlib -import logging import json +import logging import os import random import sys import tempfile import unittest from io import StringIO -from typing import List, Dict +from typing import Dict, List + import torch + from fairseq import options from fairseq_cli import eval_lm, train from tests.utils import ( create_dummy_data, + create_laser_data_and_config_json, generate_main, preprocess_lm_data, preprocess_summarization_data, preprocess_translation_data, - create_laser_data_and_config_json, - train_translation_model, train_language_model, + train_translation_model, ) - try: import transformers # noqa @@ -1161,7 +1162,7 @@ def test_transformer_lm(self): train_language_model( data_dir, "transformer_lm", - ["--add-bos-token", '--nval', '1'], + ["--add-bos-token", "--nval", "1"], run_validation=True, ) eval_lm_main(data_dir) @@ -1186,7 +1187,15 @@ def test_normformer_lm(self): train_language_model( data_dir, "transformer_lm", - ["--add-bos-token", '--nval', '1', '--scale-fc', '--scale-heads', '--scale-attn', '--scale-fc'], + [ + "--add-bos-token", + "--nval", + "1", + "--scale-fc", + "--scale-heads", + "--scale-attn", + "--scale-fc", + ], run_validation=True, ) eval_lm_main(data_dir) @@ -1202,6 +1211,7 @@ def test_normformer_lm(self): "500", ], ) + def test_transformer_lm_with_adaptive_softmax(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory( diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py index 0f28222633..23ba034f3f 100644 --- a/tests/test_checkpoint_utils.py +++ b/tests/test_checkpoint_utils.py @@ -11,9 +11,9 @@ from io import StringIO from unittest.mock import patch -from fairseq import checkpoint_utils from omegaconf import OmegaConf +from fairseq import checkpoint_utils from tests.utils import ( create_dummy_data, preprocess_translation_data, @@ -56,23 +56,23 @@ def _train_transformer(self, seed, extra_args=None): def test_load_model_ensemble_and_task(self): # with contextlib.redirect_stdout(StringIO()): - with self._train_transformer(seed=123) as model1: - with self._train_transformer(seed=456) as model2: - ensemble, cfg, task = checkpoint_utils.load_model_ensemble_and_task( - filenames=[model1, model2] - ) - self.assertEqual(len(ensemble), 2) + with self._train_transformer(seed=123) as model1: + with self._train_transformer(seed=456) as model2: + ensemble, cfg, task = checkpoint_utils.load_model_ensemble_and_task( + filenames=[model1, model2] + ) + self.assertEqual(len(ensemble), 2) - # after Transformer has been migrated to Hydra, this will probably - # become cfg.common.seed - self.assertEqual(ensemble[0].args.seed, 123) - self.assertEqual(ensemble[1].args.seed, 456) + # after Transformer has been migrated to Hydra, this will probably + # become cfg.common.seed + self.assertEqual(ensemble[0].args.seed, 123) + self.assertEqual(ensemble[1].args.seed, 456) - # the task from the first model should be returned - self.assertTrue("seed123" in task.cfg.data) + # the task from the first model should be returned + self.assertTrue("seed123" in task.cfg.data) - # last cfg is saved - self.assertEqual(cfg.common.seed, 456) + # last cfg is saved + self.assertEqual(cfg.common.seed, 456) def test_prune_state_dict(self): with contextlib.redirect_stdout(StringIO()): @@ -94,7 +94,9 @@ def test_torch_persistent_save_async(self): filename = "async_checkpoint.pt" with patch(f"{checkpoint_utils.__name__}.PathManager.opena") as mock_opena: - with patch(f"{checkpoint_utils.__name__}._torch_persistent_save") as mock_save: + with patch( + f"{checkpoint_utils.__name__}._torch_persistent_save" + ) as mock_save: checkpoint_utils.torch_persistent_save( state_dict, filename, async_write=True ) diff --git a/tests/test_data_utils.py b/tests/test_data_utils.py index 2acfc8dc18..c48d02c5c6 100644 --- a/tests/test_data_utils.py +++ b/tests/test_data_utils.py @@ -6,8 +6,8 @@ import unittest import numpy as np -from fairseq.data.data_utils_fast import batch_by_size_fn -from fairseq.data.data_utils_fast import batch_by_size_vec + +from fairseq.data.data_utils_fast import batch_by_size_fn, batch_by_size_vec class TestBatchBySize(unittest.TestCase): @@ -20,7 +20,7 @@ def batch_by_size_baseline( max_sentences, bsz_mult, ): - """Simple, reliable and slow implementation of batch by size """ + """Simple, reliable and slow implementation of batch by size""" batches = [] start = 0 while start < len(indices): diff --git a/tests/test_dataclass_utils.py b/tests/test_dataclass_utils.py index 45fc391a97..231f86b6ee 100644 --- a/tests/test_dataclass_utils.py +++ b/tests/test_dataclass_utils.py @@ -41,7 +41,7 @@ class TestDataclassUtils(unittest.TestCase): def test_argparse_convert_basic(self): parser = ArgumentParser() gen_parser_from_dataclass(parser, A(), True) - args = parser.parse_args(["--num-layers", '10', "the/data/path"]) + args = parser.parse_args(["--num-layers", "10", "the/data/path"]) self.assertEqual(args.num_layers, 10) self.assertEqual(args.data, "the/data/path") diff --git a/tests/test_ema.py b/tests/test_ema.py index 88ea65a434..e6f10ce9c2 100644 --- a/tests/test_ema.py +++ b/tests/test_ema.py @@ -9,6 +9,7 @@ from typing import Optional import torch + from fairseq.models.ema import EMA @@ -44,9 +45,7 @@ def assertTorchAllClose(self, x, y, atol=1e-8, rtol=1e-5, msg=None): other_norm = torch.norm(y.float()) if msg is None: - msg = "|input - other| > {} + {} * |other|".format( - atol, rtol - ) + msg = "|input - other| > {} + {} * |other|".format(atol, rtol) self.assertLessEqual( diff_norm, @@ -103,9 +102,7 @@ def test_ema(self): for key, param in model2.state_dict().items(): ema_param = ema_state_dict[key] - self.assertTrue( - torch.allclose(ema_param, param) - ) + self.assertTrue(torch.allclose(ema_param, param)) def test_ema_fp32(self): model = DummyModule().half() @@ -135,17 +132,27 @@ def test_ema_fp32(self): # closer to the EMA update done in fp32 than in fp16. self.assertLessEqual( torch.norm( - ema_param.float() - - (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ema_param.float() + - ( + config.ema_decay * prev_param.float() + + (1 - config.ema_decay) * param.float() + ) + .half() + .float() ), torch.norm( - ema_param.float() - - (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ema_param.float() + - ( + config.ema_decay * prev_param + (1 - config.ema_decay) * param + ).float() ), ) self.assertTorchAllClose( ema_param, - (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half(), + ( + config.ema_decay * prev_param.float() + + (1 - config.ema_decay) * param.float() + ).half(), ) def test_ema_fp16(self): @@ -178,12 +185,19 @@ def test_ema_fp16(self): # closer to the EMA update done in fp16 than in fp32. self.assertLessEqual( torch.norm( - ema_param.float() - - (config.ema_decay * prev_param + (1 - config.ema_decay) * param).float() + ema_param.float() + - ( + config.ema_decay * prev_param + (1 - config.ema_decay) * param + ).float() ), torch.norm( - ema_param.float() - - (config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float()).half().float() + ema_param.float() + - ( + config.ema_decay * prev_param.float() + + (1 - config.ema_decay) * param.float() + ) + .half() + .float() ), ) self.assertTorchAllClose( diff --git a/tests/test_export.py b/tests/test_export.py index b380697b9a..3e9a48d187 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -9,12 +9,12 @@ import unittest import torch + from fairseq.data.dictionary import Dictionary from fairseq.models.transformer import TransformerModel from fairseq.modules import multihead_attention, sinusoidal_positional_embedding from fairseq.tasks.fairseq_task import LegacyFairseqTask - DEFAULT_TEST_VOCAB_SIZE = 100 @@ -116,6 +116,5 @@ def test_export_transformer_no_token_pos_emb(self): _test_save_and_load(scripted) - if __name__ == "__main__": unittest.main() diff --git a/tests/test_file_io.py b/tests/test_file_io.py index 425812bf16..d1f33dadd1 100644 --- a/tests/test_file_io.py +++ b/tests/test_file_io.py @@ -50,6 +50,7 @@ def test_file_io_async(self): # ioPath `PathManager` is initialized after the first `opena` call. try: from fairseq.file_io import IOPathManager, PathManager + _asyncfile = os.path.join(self._tmpdir, "async.txt") f = PathManager.opena(_asyncfile, "wb") f.close() diff --git a/tests/test_iopath.py b/tests/test_iopath.py index 908261a661..48230a6379 100644 --- a/tests/test_iopath.py +++ b/tests/test_iopath.py @@ -8,7 +8,6 @@ class TestIOPath(unittest.TestCase): - def test_no_iopath(self): from .test_reproducibility import TestReproducibility diff --git a/tests/test_lm_context_window.py b/tests/test_lm_context_window.py index 7415e86abd..f8d7e7203c 100644 --- a/tests/test_lm_context_window.py +++ b/tests/test_lm_context_window.py @@ -6,23 +6,25 @@ import unittest import torch + from fairseq.data import MonolingualDataset -from fairseq.tasks.language_modeling import LanguageModelingTask, LanguageModelingConfig +from fairseq.tasks.language_modeling import LanguageModelingConfig, LanguageModelingTask from tests import utils as test_utils class TestLMContextWindow(unittest.TestCase): - def test_eval_dataloader(self): dictionary = test_utils.dummy_dictionary(10) assert len(dictionary) == 14 # 4 extra special symbols assert dictionary.pad() == 1 - dataset = test_utils.TestDataset([ - torch.tensor([4, 5, 6, 7], dtype=torch.long), - torch.tensor([8, 9, 10, 11], dtype=torch.long), - torch.tensor([12, 13], dtype=torch.long), - ]) + dataset = test_utils.TestDataset( + [ + torch.tensor([4, 5, 6, 7], dtype=torch.long), + torch.tensor([8, 9, 10, 11], dtype=torch.long), + torch.tensor([12, 13], dtype=torch.long), + ] + ) dataset = MonolingualDataset(dataset, sizes=[4, 4, 2], src_vocab=dictionary) config = LanguageModelingConfig(tokens_per_sample=4) diff --git a/tests/test_multi_corpus_dataset.py b/tests/test_multi_corpus_dataset.py index 278bdb73c1..79900abf61 100644 --- a/tests/test_multi_corpus_dataset.py +++ b/tests/test_multi_corpus_dataset.py @@ -7,6 +7,7 @@ from collections import OrderedDict import torch + from fairseq.data import LanguagePairDataset, TokenBlockDataset from fairseq.data.multi_corpus_dataset import MultiCorpusDataset from tests.test_train import mock_dict @@ -69,8 +70,10 @@ def _test_sample_helper( ) self.assertEqual( len(items), - int(min(len(self.dataset_1), len(indices) * distribution[0]) - + min(len(self.dataset_1), len(indices) * distribution[1])) + int( + min(len(self.dataset_1), len(indices) * distribution[0]) + + min(len(self.dataset_1), len(indices) * distribution[1]) + ), ) print(distribution) diff --git a/tests/test_noising.py b/tests/test_noising.py index b3d0d123c4..1956f6ad1d 100644 --- a/tests/test_noising.py +++ b/tests/test_noising.py @@ -6,8 +6,9 @@ import unittest from typing import Dict, List -import tests.utils as test_utils import torch + +import tests.utils as test_utils from fairseq import utils from fairseq.data import ( Dictionary, @@ -138,7 +139,7 @@ def _convert_src_tokens_to_tensor( return x, torch.LongTensor(src_len) def assert_eos_at_end(self, x, x_len, eos): - """Asserts last token of every sentence in x is EOS """ + """Asserts last token of every sentence in x is EOS""" for i in range(len(x_len)): self.assertEqual( x[x_len[i] - 1][i], @@ -373,7 +374,7 @@ def test_word_shuffle_without_eos_with_bpe_end_marker(self): ) def assert_no_eos_at_end(self, x, x_len, eos): - """Asserts that the last token of each sentence in x is not EOS """ + """Asserts that the last token of each sentence in x is not EOS""" for i in range(len(x_len)): self.assertNotEqual( x[x_len[i] - 1][i], diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index 9273191962..b9f91ffa76 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -4,22 +4,21 @@ # LICENSE file in the root directory of this source tree. import argparse +import math import tempfile import unittest -import math -import numpy as np +import numpy as np +import torch import tests.utils as test_utils -import torch from fairseq import search from fairseq.data.dictionary import Dictionary from fairseq.models.transformer import TransformerModel -from fairseq.sequence_generator import EnsembleModel, SequenceGenerator from fairseq.ngram_repeat_block import NGramRepeatBlock +from fairseq.sequence_generator import EnsembleModel, SequenceGenerator from fairseq.tasks.fairseq_task import LegacyFairseqTask - DEFAULT_TEST_VOCAB_SIZE = 100 @@ -590,9 +589,11 @@ def setUp(self): # prefix step 0: torch.FloatTensor( [ - # eos - [0.0, unk] + [1.0 / vocab_size] * vocab_size # beam 1 - ] * self.beam_size + # eos + [0.0, unk] + + [1.0 / vocab_size] * vocab_size # beam 1 + ] + * self.beam_size ), ] * vocab_size @@ -617,6 +618,7 @@ def test_prefix_beam_search(self): # make sure test sample doesn't break any assertion generator.forward(sample, prefix_tokens=self.tokens[:, :-1]) + class TestTopPSamplingSearch(TestSequenceGeneratorBase): def setUp(self): # construct dummy dictionary diff --git a/tests/utils.py b/tests/utils.py index 6e0c709517..ce2e361d9b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -12,9 +12,12 @@ import torch import torch.nn.functional as F + +import fairseq.distributed.utils as distributed_utils from fairseq import options, utils from fairseq.data import Dictionary from fairseq.data.language_pair_dataset import collate +from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.models import ( FairseqEncoder, FairseqEncoderDecoderModel, @@ -23,8 +26,6 @@ from fairseq.models.fairseq_encoder import EncoderOut from fairseq.tasks import LegacyFairseqTask from fairseq_cli import generate, interactive, preprocess, train, validate -import fairseq.distributed.utils as distributed_utils -from fairseq.dataclass.utils import convert_namespace_to_omegaconf def dummy_dictionary(vocab_size, prefix="token_"): @@ -37,7 +38,10 @@ def dummy_dictionary(vocab_size, prefix="token_"): def dummy_dataloader( - samples, padding_idx=1, eos_idx=2, batch_size=None, + samples, + padding_idx=1, + eos_idx=2, + batch_size=None, ): if batch_size is None: batch_size = len(samples) From c620ed066facb2d854338443cd740c9c75a5a598 Mon Sep 17 00:00:00 2001 From: Apoorv Vyas <vyasapoorv@learnfair0371.h2.fair> Date: Wed, 8 Dec 2021 18:18:48 -0800 Subject: [PATCH 509/774] Add vectorized implementation to wav2vec2 sample_negatives (#2683) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - Updates for loop to vectorized implementation which speeds up fairseq-hydra training by ~8-10%. - The for loop penalty is not incurred with torch distributed - fairseq-hydra train starts many more processes thread which probably slows this down as well. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Improves wav2vec2 pretraining speed with fairseq-hydra train ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2683 Reviewed By: arbabu123 Differential Revision: D32740855 Pulled By: alexeib fbshipit-source-id: 1003a819679521ae1ae011cd79517e1035107e35 --- fairseq/models/wav2vec/wav2vec2.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 6431ccb964..66a6951b54 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -464,8 +464,7 @@ def sample_negatives(self, y, num, padding_count=None): cross_neg_idxs[cross_neg_idxs >= tszs] += 1 if self.n_negatives > 0: - for i in range(1, bsz): - neg_idxs[i] += i * high + neg_idxs = neg_idxs + (torch.arange(bsz).unsqueeze(1) * high) else: neg_idxs = cross_neg_idxs From 88e7d2586b33fab1ade96a5a2390daeab368c57b Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 9 Dec 2021 02:33:35 -0800 Subject: [PATCH 510/774] fix flake8 issues (#2570) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? - [x] applies flake8 fixes to main branch (https://github.com/fairinternal/fairseq-py/issues/2546) - still more to be fixed Fix GPU tests: - [x] when torch.ao.quantization import doesn't work use torch.quantization - [x] build apex from earlier commit in circleci so that its compatible with pytorch 1.8 and 1.9 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2570 Reviewed By: Mortimerp9 Differential Revision: D32955312 Pulled By: dianaml0 fbshipit-source-id: e163cbd4998f171f819e31b0682c1c0f1986f9e1 --- .circleci/config.yml | 5 ++- .pre-commit-config.yaml | 2 +- fairseq/logging/meters.py | 2 - .../models/speech_to_text/modules/emformer.py | 37 +++++++++++-------- fairseq/modules/cross_entropy.py | 2 - fairseq/modules/layer_norm.py | 2 - fairseq/modules/quantization/scalar/ops.py | 11 ++++-- fairseq/optim/fused_adam.py | 5 +-- scripts/average_checkpoints.py | 14 ++++--- scripts/constraints/extract.py | 2 - scripts/spm_decode.py | 8 ++-- scripts/spm_encode.py | 8 ++-- setup.cfg | 1 + tests/distributed/test_bmuf.py | 1 - tests/gpu/test_binaries_gpu.py | 3 ++ tests/test_constraints.py | 12 ++++-- tests/test_file_io.py | 2 +- tests/test_fp16_optimizer.py | 1 - tests/test_multi_corpus_sampled_dataset.py | 2 +- tests/test_reproducibility.py | 2 - tests/test_roberta.py | 10 ++--- tests/test_sequence_generator.py | 2 +- 22 files changed, 73 insertions(+), 61 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 25f3a73881..de40a6e9c5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -10,7 +10,7 @@ gpu: &gpu machine: image: ubuntu-1604-cuda-11.1:202012-01 resource_class: gpu.nvidia.medium.multi - + # ------------------------------------------------------------------------------------- # Re-usable commands @@ -25,7 +25,7 @@ install_dep_common: &install_dep_common pip install --upgrade setuptools pip install bitarray boto3 deepspeed editdistance fastBPE iopath ipdb ipython pyarrow pytest sacremoses sentencepiece subword-nmt hydra-core==1.0.7 omegaconf==2.0.6 pip install --progress-bar off pytest - pip install --progress-bar off fairscale==0.4.1 + pip install --progress-bar off fairscale pip install -i https://test.pypi.org/simple/ bitsandbytes-cuda111 -U python -c 'import torch; print("Torch version:", torch.__version__)' python -m torch.utils.collect_env @@ -38,6 +38,7 @@ install_dep_fused_ops: &install_dep_fused_ops source activate fairseq git clone https://github.com/NVIDIA/apex cd apex + git checkout e2083df5eb96643c61613b9df48dd4eea6b07690 pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" --global-option="--deprecated_fused_adam" --global-option="--xentropy" --global-option="--fast_multihead_attn" ./ cd ~/ git clone --depth=1 --branch v2.4 https://github.com/NVIDIA/Megatron-LM.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f9efb2e96e..4817f6e876 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - id: end-of-file-fixer - repo: https://github.com/ambv/black - rev: 20.8b1 + rev: 21.12b0 hooks: - id: black language_version: python3.8 diff --git a/fairseq/logging/meters.py b/fairseq/logging/meters.py index 2100b1fa0b..d5f7c775d9 100644 --- a/fairseq/logging/meters.py +++ b/fairseq/logging/meters.py @@ -8,7 +8,6 @@ from collections import OrderedDict from typing import Dict, Optional - try: import torch @@ -18,7 +17,6 @@ def type_as(a, b): else: return a - except ImportError: torch = None diff --git a/fairseq/models/speech_to_text/modules/emformer.py b/fairseq/models/speech_to_text/modules/emformer.py index 6233546ab8..70339788f7 100644 --- a/fairseq/models/speech_to_text/modules/emformer.py +++ b/fairseq/models/speech_to_text/modules/emformer.py @@ -14,23 +14,30 @@ import torch import torch.nn as nn -from fairseq.models import ( - FairseqEncoder, -) +from torch import Tensor +from torch import device as Device + +from fairseq.models import FairseqEncoder from fairseq.models.speech_to_text.utils import ( NoOp, - lengths_to_padding_mask, - segments_to_sequence, -) -from fairseq.models.speech_to_text.utils import ( attention_suppression, layer_norm_backward_hook, + lengths_to_padding_mask, + segments_to_sequence, ) -from torch import Tensor, device as Device -from torch.ao.quantization.qconfig import ( - default_dynamic_qconfig, - per_channel_dynamic_qconfig, -) + +try: + import torch.ao.quantization as quantization + from torch.ao.quantization.qconfig import ( + default_dynamic_qconfig, + per_channel_dynamic_qconfig, + ) +except ImportError: + import torch.quantization as quantization + from torch.quantization.qconfig import ( + default_dynamic_qconfig, + per_channel_dynamic_qconfig, + ) class RelativePositionEmbedding(nn.Module): @@ -140,7 +147,7 @@ def quantize_(self, params=None): qconfig = per_channel_dynamic_qconfig else: qconfig = default_dynamic_qconfig - torch.ao.quantization.quantize_dynamic( + quantization.quantize_dynamic( self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True ) return self @@ -728,7 +735,7 @@ def quantize_(self, params=None): qconfig = per_channel_dynamic_qconfig else: qconfig = default_dynamic_qconfig - torch.ao.quantization.quantize_dynamic( + quantization.quantize_dynamic( self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True ) return self @@ -1771,7 +1778,7 @@ def quantize_(self, params=None): qconfig = per_channel_dynamic_qconfig else: qconfig = default_dynamic_qconfig - torch.ao.quantization.quantize_dynamic( + quantization.quantize_dynamic( self, {torch.nn.Linear: qconfig}, dtype=torch.qint8, inplace=True ) return self diff --git a/fairseq/modules/cross_entropy.py b/fairseq/modules/cross_entropy.py index 6f33c24cb5..286c00eecc 100644 --- a/fairseq/modules/cross_entropy.py +++ b/fairseq/modules/cross_entropy.py @@ -8,7 +8,6 @@ import torch import torch.nn.functional as F - logger = logging.getLogger(__name__) @@ -54,7 +53,6 @@ def cross_entropy(logits, target, ignore_index=-100, reduction="mean"): else: raise NotImplementedError - except ImportError: def cross_entropy(logits, target, ignore_index=-100, reduction="mean"): diff --git a/fairseq/modules/layer_norm.py b/fairseq/modules/layer_norm.py index 234609d9e2..78332d1749 100644 --- a/fairseq/modules/layer_norm.py +++ b/fairseq/modules/layer_norm.py @@ -7,7 +7,6 @@ import torch.nn as nn import torch.nn.functional as F - try: from apex.normalization import FusedLayerNorm as _FusedLayerNorm @@ -22,7 +21,6 @@ def forward(self, x): with torch.cuda.device(x.device): return super().forward(x) - except ImportError: has_fused_layernorm = False diff --git a/fairseq/modules/quantization/scalar/ops.py b/fairseq/modules/quantization/scalar/ops.py index 9144083ac7..ad1e14e051 100644 --- a/fairseq/modules/quantization/scalar/ops.py +++ b/fairseq/modules/quantization/scalar/ops.py @@ -5,6 +5,11 @@ import torch +try: + import torch.ao.quantization as quantization +except ImportError: + import torch.quantization as quantization + def emulate_int(w, bits, method, scale=None, zero_point=None): q = globals()[f"emulate_int8_{method}"] @@ -21,7 +26,7 @@ def quantize(w, scale, zero_point, bits=8): def emulate_int8_histogram(w, scale=None, zero_point=None, bits=8): if scale is None: - obs = torch.ao.quantization.observer.HistogramObserver() + obs = quantization.observer.HistogramObserver() obs.to(device=w.device) _ = obs(w.float()) scale, zero_point = obs.calculate_qparams() @@ -32,7 +37,7 @@ def emulate_int8_histogram(w, scale=None, zero_point=None, bits=8): def emulate_int8_channel(w, scale=None, zero_point=None, bits=8): if scale is None: - obs = torch.ao.quantization.observer.PerChannelMinMaxObserver( + obs = quantization.observer.PerChannelMinMaxObserver( ch_axis=-1, qscheme=torch.per_channel_symmetric ) obs.to(device=w.device) @@ -45,7 +50,7 @@ def emulate_int8_channel(w, scale=None, zero_point=None, bits=8): def emulate_int8_tensor(w, scale=None, zero_point=None, bits=8): if scale is None: - obs = torch.ao.quantization.observer.MinMaxObserver() + obs = quantization.observer.MinMaxObserver() obs.to(device=w.device) _ = obs(w) scale, zero_point = obs.calculate_qparams() diff --git a/fairseq/optim/fused_adam.py b/fairseq/optim/fused_adam.py index da872033d1..1290ecfdbf 100644 --- a/fairseq/optim/fused_adam.py +++ b/fairseq/optim/fused_adam.py @@ -27,8 +27,8 @@ def get_fused_adam_class(): except ImportError: try: # fallback to the newer interface - from apex.optimizers import FusedAdam as _FusedAdam # noqa from apex.multi_tensor_apply import multi_tensor_applier + from apex.optimizers import FusedAdam as _FusedAdam # noqa if multi_tensor_applier.available: return FusedAdamV2 @@ -252,8 +252,8 @@ def inf_norm(t): try: - from apex.optimizers import FusedAdam from apex.multi_tensor_apply import multi_tensor_applier + from apex.optimizers import FusedAdam class FusedAdamV2(FusedAdam): """ @@ -382,6 +382,5 @@ def step( return loss - except ImportError: pass diff --git a/scripts/average_checkpoints.py b/scripts/average_checkpoints.py index c512f802bc..a4711e4840 100644 --- a/scripts/average_checkpoints.py +++ b/scripts/average_checkpoints.py @@ -108,16 +108,18 @@ def main(): help='Write the new checkpoint containing the averaged weights to this path.') num_group = parser.add_mutually_exclusive_group() num_group.add_argument('--num-epoch-checkpoints', type=int, - help='if set, will try to find checkpoints with names checkpoint_xx.pt in the path specified by input, ' - 'and average last this many of them.') + help='if set, will try to find checkpoints with names checkpoint_xx.pt in the ' + 'path specified by input, and average last this many of them.') num_group.add_argument('--num-update-checkpoints', type=int, - help='if set, will try to find checkpoints with names checkpoint_ee_xx.pt in the path specified by input, ' - 'and average last this many of them.') + help='if set, will try to find checkpoints with names checkpoint_ee_xx.pt in the path specified by' + ' input, and average last this many of them.') parser.add_argument('--checkpoint-upper-bound', type=int, help='when using --num-epoch-checkpoints, this will set an upper bound on which epoch to use, ' 'when using --num-update-checkpoints, this will set an upper bound on which update to use' - 'e.g., with --num-epoch-checkpoints=10 --checkpoint-upper-bound=50, checkpoints 41-50 would be averaged.' - 'e.g., with --num-update-checkpoints=10 --checkpoint-upper-bound=50000, checkpoints 40500-50000 would be averaged assuming --save-interval-updates 500' + 'e.g., with --num-epoch-checkpoints=10 --checkpoint-upper-bound=50, checkpoints 41-50 would be' + ' averaged.' + 'e.g., with --num-update-checkpoints=10 --checkpoint-upper-bound=50000, checkpoints 40500-50000 would' + ' be averaged assuming --save-interval-updates 500' ) # fmt: on args = parser.parse_args() diff --git a/scripts/constraints/extract.py b/scripts/constraints/extract.py index f6155d0a05..437b373856 100755 --- a/scripts/constraints/extract.py +++ b/scripts/constraints/extract.py @@ -11,8 +11,6 @@ import random import sys -from sacrebleu import extract_ngrams - def get_phrase(words, index, length): assert index < len(words) - length + 1 diff --git a/scripts/spm_decode.py b/scripts/spm_decode.py index 1c18b1d2a7..7d7b68b240 100644 --- a/scripts/spm_decode.py +++ b/scripts/spm_decode.py @@ -26,13 +26,13 @@ def main(): if args.input_format == "piece": - def decode(l): - return "".join(sp.DecodePieces(l)) + def decode(input): + return "".join(sp.DecodePieces(input)) elif args.input_format == "id": - def decode(l): - return "".join(sp.DecodeIds(l)) + def decode(input): + return "".join(sp.DecodeIds(input)) else: raise NotImplementedError diff --git a/scripts/spm_encode.py b/scripts/spm_encode.py index 83facfb3b1..f91e0bb728 100644 --- a/scripts/spm_encode.py +++ b/scripts/spm_encode.py @@ -49,13 +49,13 @@ def main(): if args.output_format == "piece": - def encode(l): - return sp.EncodeAsPieces(l) + def encode(input): + return sp.EncodeAsPieces(input) elif args.output_format == "id": - def encode(l): - return list(map(str, sp.EncodeAsIds(l))) + def encode(input): + return list(map(str, sp.EncodeAsIds(input))) else: raise NotImplementedError diff --git a/setup.cfg b/setup.cfg index 3ea6243324..3fa679ddf1 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,4 @@ [flake8] max-line-length = 127 extend-ignore = E203, W503 +extend-exclude = fairseq/model_parallel/megatron diff --git a/tests/distributed/test_bmuf.py b/tests/distributed/test_bmuf.py index 2a0f20d0be..995d0db180 100644 --- a/tests/distributed/test_bmuf.py +++ b/tests/distributed/test_bmuf.py @@ -140,7 +140,6 @@ def setup_args(): @unittest.skipIf(torch.cuda.device_count() < 2, "test requires 2 GPUs") class TestBMUF(unittest.TestCase): def bmuf_process(self, cfg, args, iterations): - processes = [] results = Manager().dict() torch.multiprocessing.spawn( fn=functools.partial(single_gpu_training, cfg, args), diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 550e751b1f..1d5b6e62bc 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -399,6 +399,9 @@ def _quantize_language_model(data_dir, arch, extra_flags=None, run_validation=Fa train.main(quantize_args) +@unittest.skipIf( + int(torch.__version__[2]) < 10, reason="quantized kernels are only supported on CPU" +) @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") class TestQuantization(unittest.TestCase): def setUp(self): diff --git a/tests/test_constraints.py b/tests/test_constraints.py index 1c37f7e1fb..d766d5130f 100755 --- a/tests/test_constraints.py +++ b/tests/test_constraints.py @@ -3,11 +3,17 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import sys import unittest +from typing import List import torch -from fairseq.token_generation_constraints import * + +from fairseq.token_generation_constraints import ( + ConstraintNode, + OrderedConstraintState, + UnorderedConstraintState, + pack_constraints, +) def tensorize(constraints: List[List[int]]) -> torch.Tensor: @@ -53,7 +59,7 @@ def setUp(self): self.examples = [ ( tensorize([[1, 2, 3], [1, 3], [1, 4], [4, 5, 6, 7], [1], [4, 5]]), - "([None].False#6 ([1].True#4 ([2].False#1 [3].True#1) [3].True#1 [4].True#1) ([4].False#2 ([5].True#2 ([6].False#1 [7].True#1))))", + "([None].False#6 ([1].True#4 ([2].False#1 [3].True#1) [3].True#1 [4].True#1) ([4].False#2 ([5].True#2 ([6].False#1 [7].True#1))))", # noqa {1: 4, 2: 1, 3: 2, 4: 3, 5: 2, 6: 1, 7: 1}, ), ([], "[None].False#0", {}), diff --git a/tests/test_file_io.py b/tests/test_file_io.py index d1f33dadd1..af7c4cedb8 100644 --- a/tests/test_file_io.py +++ b/tests/test_file_io.py @@ -49,7 +49,7 @@ def test_file_io_oss(self): def test_file_io_async(self): # ioPath `PathManager` is initialized after the first `opena` call. try: - from fairseq.file_io import IOPathManager, PathManager + from fairseq.file_io import PathManager _asyncfile = os.path.join(self._tmpdir, "async.txt") f = PathManager.opena(_asyncfile, "wb") diff --git a/tests/test_fp16_optimizer.py b/tests/test_fp16_optimizer.py index ce4f1c055c..27085a12da 100644 --- a/tests/test_fp16_optimizer.py +++ b/tests/test_fp16_optimizer.py @@ -3,7 +3,6 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import argparse import copy import logging import unittest diff --git a/tests/test_multi_corpus_sampled_dataset.py b/tests/test_multi_corpus_sampled_dataset.py index 05b20328c5..88f0817a54 100644 --- a/tests/test_multi_corpus_sampled_dataset.py +++ b/tests/test_multi_corpus_sampled_dataset.py @@ -79,7 +79,7 @@ def test_multi_corpus_sampled_dataset_uniform_sample(self): def test_multi_corpus_sampled_dataset_weighted_sample(self): def naive_weighted_sample(weights): - def f(l): + def f(input): v = np.random.random() agg = 0 for i, weight in enumerate(weights): diff --git a/tests/test_reproducibility.py b/tests/test_reproducibility.py index 94931b2a07..b285593272 100644 --- a/tests/test_reproducibility.py +++ b/tests/test_reproducibility.py @@ -3,12 +3,10 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import contextlib import json import os import tempfile import unittest -from io import StringIO import torch diff --git a/tests/test_roberta.py b/tests/test_roberta.py index b0b9cfd31e..0030d3e5a9 100644 --- a/tests/test_roberta.py +++ b/tests/test_roberta.py @@ -292,18 +292,18 @@ def test_roberta_incremental_decoder(self, device: str): # Decode with incremental state inc_state = {} ro_dec_inc = [] - for l in range(tgt_len): + for i in range(tgt_len): ro, _ = model.decoder.forward( - ro_tokens[:, : l + 1], encoder_out=en_enc, incremental_state=inc_state + ro_tokens[:, : i + 1], encoder_out=en_enc, incremental_state=inc_state ) self.assertEqual(ro.shape, (bs, 1, VOCAB_SIZE)) ro_dec_inc.append(ro) - for l in range(tgt_len): + for i in range(tgt_len): # Intra-batch - self.assertTensorEqual(ro_dec_inc[l][0], ro_dec_inc[l][1]) + self.assertTensorEqual(ro_dec_inc[i][0], ro_dec_inc[i][1]) # Incremental vs non-incremental - self.assertTensorEqual(ro_dec_inc[l][:, 0], ro_dec[:, l]) + self.assertTensorEqual(ro_dec_inc[i][:, 0], ro_dec[:, i]) def params(model, name): diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index b9f91ffa76..a14d739898 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -320,7 +320,7 @@ def test_generation_with_additional_input(self): sample = self.sample.copy() sample["net_input"]["fancy_other_input"] = sample["net_input"]["src_tokens"] hypos = generator.forward(self.sample) - eos, w1, w2 = self.tgt_dict.eos(), self.w1, self.w2 + eos, w1 = self.tgt_dict.eos(), self.w1 # sentence 1, beam 1 self.assertHypoTokens(hypos[0][0], [w1, eos]) self.assertHypoScore(hypos[0][0], [0.9, 1.0]) From ce961a9fd26aef5130720cb6a171ddd5b51a8961 Mon Sep 17 00:00:00 2001 From: Apoorv Vyas <vyasapoorv@devfair0164.h2.fair> Date: Thu, 9 Dec 2021 19:00:59 -0800 Subject: [PATCH 511/774] Fix logits masking bug introduced in #2469 (#2774) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - Masking logits with float(inf) significantly degrades deconding performance with language model and flashlight decoder. This fixes it. # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes logits masking bug introduced in https://github.com/fairinternal/fairseq-py/issues/2469 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2774 Reviewed By: arbabu123 Differential Revision: D33003148 Pulled By: alexeib fbshipit-source-id: 19bf3da4f5104b33357fd4941e5e76b95174ee28 --- fairseq/models/wav2vec/wav2vec2_asr.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index ed40f6d8fe..a4057f6030 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -195,8 +195,10 @@ def get_logits(self, net_output, normalize=False): if net_output["padding_mask"] is not None and net_output["padding_mask"].any(): number_of_classes = logits.size(-1) - masking_tensor = torch.ones(number_of_classes) * float("-inf") - masking_tensor[0] = float("inf") + masking_tensor = torch.ones( + number_of_classes, device=logits.device + ) * float("-inf") + masking_tensor[0] = 0 logits[net_output["padding_mask"].T] = masking_tensor.type_as(logits) if normalize: From 8548f1d40124a036af7f9df55a45030451459823 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Fri, 10 Dec 2021 16:54:15 -0800 Subject: [PATCH 512/774] Add loading from HuggingFace Hub Summary: Add loading from HuggingFace Hub. Revised from and to replace D32697723 (accepted). Reviewed By: pipibjc, dianaml0 Differential Revision: D32964041 fbshipit-source-id: 39676aa0ecb10454ae76b70968d5abe96ab6da54 --- fairseq/checkpoint_utils.py | 30 ++++++++++++++++++++++++++++++ tests/test_hf_hub.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/test_hf_hub.py diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index a5be928f0a..4f74fb0255 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -27,6 +27,8 @@ from fairseq.models import FairseqDecoder, FairseqEncoder from omegaconf import DictConfig, open_dict, OmegaConf +from pathlib import Path + logger = logging.getLogger(__name__) @@ -483,6 +485,34 @@ def load_model_ensemble_and_task( return ensemble, cfg, task +def load_model_ensemble_and_task_from_hf_hub( + model_id, + cache_dir: Optional[str] = None, + arg_overrides: Optional[Dict[str, Any]] = None, + **kwargs: Any, +): + try: + from huggingface_hub import snapshot_download + except ImportError: + raise ImportError( + "You need to install huggingface_hub to use `load_from_hf_hub`. " + "See https://pypi.org/project/huggingface-hub/ for installation." + ) + + library_name = "fairseq" + cache_dir = cache_dir or (Path.home() / ".cache" / library_name).as_posix() + cache_dir = snapshot_download( + model_id, cache_dir=cache_dir, library_name=library_name, **kwargs + ) + + _arg_overrides = arg_overrides or {} + _arg_overrides["data"] = cache_dir + return load_model_ensemble_and_task( + [p.as_posix() for p in Path(cache_dir).glob("*.pt")], + arg_overrides=_arg_overrides + ) + + def checkpoint_paths(path, pattern=r"checkpoint(\d+)\.pt", keep_match=False): """Retrieves all checkpoints found in `path` directory. diff --git a/tests/test_hf_hub.py b/tests/test_hf_hub.py new file mode 100644 index 0000000000..f39d1fa8e7 --- /dev/null +++ b/tests/test_hf_hub.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import torch +try: + import huggingface_hub +except ImportError: + huggingface_hub = None + +from fairseq.checkpoint_utils import load_model_ensemble_and_task_from_hf_hub + + +@unittest.skipIf(not huggingface_hub, "Requires huggingface_hub install") +class TestHuggingFaceHub(unittest.TestCase): + @torch.no_grad() + def test_hf_fastspeech2(self): + hf_model_id = "facebook/fastspeech2-en-ljspeech" + models, cfg, task = load_model_ensemble_and_task_from_hf_hub(hf_model_id) + self.assertTrue(len(models) > 0) + + +if __name__ == "__main__": + unittest.main() From 771f85025ed59a1ebe3d47ac4f30251411cfc840 Mon Sep 17 00:00:00 2001 From: ftshijt <ftshijt@gmail.com> Date: Tue, 14 Dec 2021 11:54:18 -0800 Subject: [PATCH 513/774] Update hubert config for compatibility to recent wav2vec2 update (#4043) Summary: This PR fixes https://github.com/pytorch/fairseq/issues/4035 Pull Request resolved: https://github.com/pytorch/fairseq/pull/4043 Reviewed By: alexeib Differential Revision: D32741046 Pulled By: arbabu123 fbshipit-source-id: c75383b90a636d0bc7ce7b76ced58c110cb74ca9 --- fairseq/models/hubert/hubert.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fairseq/models/hubert/hubert.py b/fairseq/models/hubert/hubert.py index 4306af03ca..21bae4db19 100644 --- a/fairseq/models/hubert/hubert.py +++ b/fairseq/models/hubert/hubert.py @@ -204,6 +204,9 @@ class HubertConfig(FairseqDataclass): metadata={"help": "skip computing losses over unmasked frames"}, ) + checkpoint_activations: bool = field( + default=False, metadata={"help": "recompute activations and save memory for extra compute"} + ) @register_model("hubert", dataclass=HubertConfig) class HubertModel(BaseFairseqModel): From 16ebfa752cd653dc28ac0a1b9f6f60a041881ad0 Mon Sep 17 00:00:00 2001 From: Jingfei Du <jingfeidu@fb.com> Date: Tue, 14 Dec 2021 13:20:44 -0800 Subject: [PATCH 514/774] Revert preix beamsearch fix (#2763) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? reverting to fix issue mentioned [here](https://github.com/pytorch/fairseq/issues/3913). Having another PR for fixing the original issue later. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2763 Reviewed By: myleott Differential Revision: D33000411 Pulled By: jingfeidu fbshipit-source-id: 95a54cbdc612129a0eab4b5e6aa576a5bcf00588 --- fairseq/sequence_generator.py | 23 ++++++------- tests/test_sequence_generator.py | 56 -------------------------------- 2 files changed, 12 insertions(+), 67 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index bfa791a018..db730c624a 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -350,6 +350,17 @@ def _generate( ) probs = probs[:, -1, :] * self.lm_weight lprobs += probs + + lprobs[lprobs != lprobs] = torch.tensor(-math.inf).to(lprobs) + + lprobs[:, self.pad] = -math.inf # never select pad + lprobs[:, self.unk] -= self.unk_penalty # apply unk penalty + + # handle max length constraint + if step >= max_len: + lprobs[:, : self.eos] = -math.inf + lprobs[:, self.eos + 1 :] = -math.inf + # handle prefix tokens (possibly with different lengths) if ( prefix_tokens is not None @@ -363,16 +374,6 @@ def _generate( # minimum length constraint (does not apply if using prefix_tokens) lprobs[:, self.eos] = -math.inf - lprobs[lprobs != lprobs] = torch.tensor(-math.inf).to(lprobs) - - lprobs[:, self.pad] = -math.inf # never select pad - lprobs[:, self.unk] -= self.unk_penalty # apply unk penalty - - # handle max length constraint - if step >= max_len: - lprobs[:, : self.eos] = -math.inf - lprobs[:, self.eos + 1 :] = -math.inf - # Record attention scores, only support avg_attn_scores is a Tensor if avg_attn_scores is not None: if attn is None: @@ -574,7 +575,7 @@ def _prefix_tokens( prefix_toks = prefix_tokens[:, step].unsqueeze(-1).repeat(1, beam_size).view(-1) prefix_lprobs = lprobs.gather(-1, prefix_toks.unsqueeze(-1)) prefix_mask = prefix_toks.ne(self.pad) - lprobs[prefix_mask] = torch.min(prefix_lprobs) - 1 + lprobs[prefix_mask] = torch.tensor(-math.inf).to(lprobs) lprobs[prefix_mask] = lprobs[prefix_mask].scatter( -1, prefix_toks[prefix_mask].unsqueeze(-1), prefix_lprobs[prefix_mask] ) diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index a14d739898..823c917d23 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -562,62 +562,6 @@ def test_diverse_beam_search(self): self.assertHypoScore(hypos[1][1], [0.7, 0.35, 0.9], [0, 2, 1], 0.5) -class TestPrefixBeamSearch(TestSequenceGeneratorBase): - def setUp(self): - # construct dummy dictionary - vocab_size = 10 - d = test_utils.dummy_dictionary(vocab_size=vocab_size) - self.assertEqual(d.pad(), 1) - self.assertEqual(d.eos(), 2) - self.assertEqual(d.unk(), 3) - self.eos = d.eos() - self.w1 = 4 - self.w2 = 5 - self.beam_size = 3 - - # construct prefix data - self.tokens = torch.LongTensor( - [ - [self.w1, self.w2, self.eos], - ] - ) - self.token_lengths = torch.LongTensor([2]) - - args = argparse.Namespace() - unk = 0.0 - args.beam_probs = [ - # prefix step 0: - torch.FloatTensor( - [ - # eos - [0.0, unk] - + [1.0 / vocab_size] * vocab_size # beam 1 - ] - * self.beam_size - ), - ] * vocab_size - - task = test_utils.TestTranslationTask.setup_task(args, d, d) - self.model = task.build_model(args) - self.tgt_dict = task.target_dictionary - - def test_prefix_beam_search(self): - search_strategy = search.BeamSearch(self.tgt_dict) - generator = SequenceGenerator( - [self.model], - self.tgt_dict, - beam_size=self.beam_size, - search_strategy=search_strategy, - ) - sample = { - "net_input": { - "src_tokens": self.tokens, - "src_lengths": self.token_lengths, - } - } - # make sure test sample doesn't break any assertion - generator.forward(sample, prefix_tokens=self.tokens[:, :-1]) - class TestTopPSamplingSearch(TestSequenceGeneratorBase): def setUp(self): From c2b771b1beed56d03134aa0a807fbbec766e484c Mon Sep 17 00:00:00 2001 From: Apoorv Vyas <vyasapoorv@learnfair0928.h2.fair> Date: Tue, 14 Dec 2021 13:26:13 -0800 Subject: [PATCH 515/774] Add sequence length padding option for wav2vec2 (#2715) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: - Adds option to pad encoder input to be a multiple of specified value. - Speeds up pre-training time for wav2vec2 base model by ~15-20% # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Adds option to pad the encoder input to be a multiple of specified value which speeds up fP16 wav2vec2 pretraining by 15-25% for different configurations. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2715 Reviewed By: arbabu123 Differential Revision: D33004443 Pulled By: alexeib fbshipit-source-id: 13141c779f647f05535f66b7a9f3fd1241c8fb58 --- fairseq/models/wav2vec/utils.py | 21 ++++++++++++ fairseq/models/wav2vec/wav2vec2.py | 52 +++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 fairseq/models/wav2vec/utils.py diff --git a/fairseq/models/wav2vec/utils.py b/fairseq/models/wav2vec/utils.py new file mode 100644 index 0000000000..dd52d86242 --- /dev/null +++ b/fairseq/models/wav2vec/utils.py @@ -0,0 +1,21 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +import torch.nn.functional as F + + +def pad_to_multiple(x, multiple, dim=-1, value=0): + # Inspired from https://github.com/lucidrains/local-attention/blob/master/local_attention/local_attention.py#L41 + if x is None: + return None, 0 + tsz = x.size(dim) + m = tsz / multiple + remainder = math.ceil(m) * multiple - tsz + if m.is_integer(): + return x, 0 + pad_offset = (0,) * (-1 - dim) * 2 + + return F.pad(x, (*pad_offset, 0, remainder), value=value), remainder diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 66a6951b54..299cc6fd23 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -30,6 +30,7 @@ from fairseq.utils import buffered_arange, index_put, is_xla_tensor from fairseq.distributed import fsdp_wrap +from .utils import pad_to_multiple EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) MASKING_DISTRIBUTION_CHOICES = ChoiceEnum(["static", "uniform", "normal", "poisson"]) @@ -236,6 +237,20 @@ class Wav2Vec2Config(FairseqDataclass): metadata={"help": "recompute activations and save memory for extra compute"}, ) + # FP16 optimization + required_seq_len_multiple: int = field( + default=1, + metadata={ + "help": "pad the input to encoder such that the sequence length is divisible by multiple" + }, + ) + crop_seq_to_multiple: int = field( + default=1, + metadata={ + "help": "crop convolutional feature extractor output such that the sequence length is divisible by multiple" + }, + ) + @register_model("wav2vec2", dataclass=Wav2Vec2Config) class Wav2Vec2Model(BaseFairseqModel): @@ -259,6 +274,8 @@ def __init__(self, cfg: Wav2Vec2Config): else None ) + self.crop_seq_to_multiple = cfg.crop_seq_to_multiple + self.mask_prob = cfg.mask_prob self.mask_selection = cfg.mask_selection self.mask_other = cfg.mask_other @@ -565,6 +582,13 @@ def forward( else: padding_mask = None + time_steps_to_drop = features.size(1) % self.crop_seq_to_multiple + if time_steps_to_drop != 0: + features = features[:, :-time_steps_to_drop] + unmasked_features = unmasked_features[:, :-time_steps_to_drop] + if padding_mask is not None: + padding_mask = padding_mask[:, :-time_steps_to_drop] + if self.post_extract_proj is not None: features = self.post_extract_proj(features) @@ -826,6 +850,7 @@ def __init__(self, args): self.dropout = args.dropout self.embedding_dim = args.encoder_embed_dim + self.required_seq_len_multiple = args.required_seq_len_multiple self.pos_conv = nn.Conv1d( self.embedding_dim, @@ -886,6 +911,17 @@ def extract_features(self, x, padding_mask=None, tgt_layer=None): if not self.layer_norm_first: x = self.layer_norm(x) + # pad to the sequence length dimension + x, pad_length = pad_to_multiple( + x, self.required_seq_len_multiple, dim=-2, value=0 + ) + if pad_length > 0 and padding_mask is None: + padding_mask = x.new_zeros((x.size(0), x.size(1)), dtype=torch.bool) + padding_mask[:, -pad_length:] = True + else: + padding_mask, _ = pad_to_multiple( + padding_mask, self.required_seq_len_multiple, dim=-1, value=True + ) x = F.dropout(x, p=self.dropout, training=self.training) # B x T x C -> T x B x C @@ -898,7 +934,18 @@ def extract_features(self, x, padding_mask=None, tgt_layer=None): if not self.training or (dropout_probability > self.layerdrop): x, z = layer(x, self_attn_padding_mask=padding_mask, need_weights=False) if tgt_layer is not None: - layer_results.append((x, z)) + # unpad if needed + if pad_length > 0: + layer_results.append( + ( + x[:-pad_length], + z[:, :-pad_length, :-pad_length] + if z is not None + else z, + ) + ) + else: + layer_results.append((x, z)) if i == tgt_layer: r = x break @@ -908,6 +955,9 @@ def extract_features(self, x, padding_mask=None, tgt_layer=None): # T x B x C -> B x T x C x = x.transpose(0, 1) + # undo paddding + if pad_length > 0: + x = x[:, :-pad_length] return x, layer_results From ee833ed49d79da00faa396bd0509782841d3d688 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Tue, 14 Dec 2021 17:40:59 -0800 Subject: [PATCH 516/774] speech integration tests (batch 1) Summary: Adding the first batch of speech integration tests (based on test set scores on pre-trained checkpoints) for - S2T transformer - TTS transformer Reviewed By: yuntang Differential Revision: D33050653 fbshipit-source-id: fb5bb9f46e8e17cb705971ca1990c8e1cb99d5f9 --- tests/speech/__init__.py | 54 ++++++++++++++++++++++ tests/speech/test_s2t_transformer.py | 66 +++++++++++++++++++++++++++ tests/speech/test_tts_transformer.py | 67 ++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+) create mode 100644 tests/speech/__init__.py create mode 100644 tests/speech/test_s2t_transformer.py create mode 100644 tests/speech/test_tts_transformer.py diff --git a/tests/speech/__init__.py b/tests/speech/__init__.py new file mode 100644 index 0000000000..2ddfdfe64f --- /dev/null +++ b/tests/speech/__init__.py @@ -0,0 +1,54 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +from pathlib import Path +import unittest + +import torch + +S3_BASE_URL = "https://dl.fbaipublicfiles.com/fairseq" + + +class TestFairseqSpeech(unittest.TestCase): + @classmethod + def download(cls, base_url: str, out_root: Path, filename: str): + url = f"{base_url}/{filename}" + path = out_root / filename + if not path.exists(): + torch.hub.download_url_to_file(url, path.as_posix(), progress=True) + return path + + def set_up_librispeech(self): + self.use_cuda = torch.cuda.is_available() + self.root = Path.home() / ".cache" / "fairseq" / "librispeech" + self.root.mkdir(exist_ok=True, parents=True) + os.chdir(self.root) + self.data_filenames = [ + "cfg_librispeech.yaml", + "spm_librispeech_unigram10000.model", + "spm_librispeech_unigram10000.txt", + "librispeech_test-other.tsv", + "librispeech_test-other.zip" + ] + self.base_url = f"{S3_BASE_URL}/s2t/librispeech" + for filename in self.data_filenames: + self.download(self.base_url, self.root, filename) + + def set_up_ljspeech(self): + self.use_cuda = torch.cuda.is_available() + self.root = Path.home() / ".cache" / "fairseq" / "ljspeech" + self.root.mkdir(exist_ok=True, parents=True) + os.chdir(self.root) + self.data_filenames = [ + "cfg_ljspeech_g2p.yaml", + "ljspeech_g2p_gcmvn_stats.npz", + "ljspeech_g2p.txt", + "ljspeech_test.tsv", + "ljspeech_test.zip" + ] + self.base_url = f"{S3_BASE_URL}/s2/ljspeech" + for filename in self.data_filenames: + self.download(self.base_url, self.root, filename) diff --git a/tests/speech/test_s2t_transformer.py b/tests/speech/test_s2t_transformer.py new file mode 100644 index 0000000000..e5ab5262bb --- /dev/null +++ b/tests/speech/test_s2t_transformer.py @@ -0,0 +1,66 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from argparse import Namespace +import unittest + +import torch +from tqdm import tqdm + +from fairseq.checkpoint_utils import load_model_ensemble_and_task +from fairseq import utils +from fairseq.scoring.wer import WerScorer +from tests.speech import TestFairseqSpeech + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestS2TTransformer(TestFairseqSpeech): + def setUp(self): + self.set_up_librispeech() + + @torch.no_grad() + def test_librispeech_s2t_transformer_s_checkpoint(self): + checkpoint_filename = "librispeech_transformer_s.pt" + path = self.download(self.base_url, self.root, checkpoint_filename) + + models, cfg, task = load_model_ensemble_and_task( + [path.as_posix()], arg_overrides={ + "data": self.root.as_posix(), + "config_yaml": "cfg_librispeech.yaml" + } + ) + if self.use_cuda: + for model in models: + model.cuda() + generator = task.build_generator(models, cfg) + test_split = "librispeech_test-other" + task.load_dataset(test_split) + batch_iterator = task.get_batch_iterator( + dataset=task.dataset(test_split), + max_tokens=65_536, max_positions=(4_096, 1_024), num_workers=1 + ).next_epoch_itr(shuffle=False) + + scorer_args = {"wer_tokenizer": "none", "wer_lowercase": False, + "wer_remove_punct": False, "wer_char_level": False} + scorer = WerScorer(Namespace(**scorer_args)) + progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) + for batch_idx, sample in progress: + sample = utils.move_to_cuda(sample) if self.use_cuda else sample + hypo = task.inference_step(generator, models, sample) + for i, sample_id in enumerate(sample["id"].tolist()): + tgt_tokens = utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()).int().cpu() + tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") + hypo_str = task.tgt_dict.string(hypo[i][0]["tokens"].int().cpu(), "sentencepiece") + if batch_idx == 0 and i < 3: + print(f"T-{sample_id} {tgt_str}") + print(f"H-{sample_id} {hypo_str}") + scorer.add_string(tgt_str, hypo_str) + reference_wer = 9.0 + print(scorer.result_string() + f" (reference: {reference_wer})") + self.assertAlmostEqual(scorer.score(), reference_wer, delta=0.3) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/speech/test_tts_transformer.py b/tests/speech/test_tts_transformer.py new file mode 100644 index 0000000000..2ade981ec1 --- /dev/null +++ b/tests/speech/test_tts_transformer.py @@ -0,0 +1,67 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import torch +from tqdm import tqdm + +from fairseq.checkpoint_utils import load_model_ensemble_and_task +from fairseq import utils +from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion +from tests.speech import TestFairseqSpeech + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestTTSTransformer(TestFairseqSpeech): + def setUp(self): + self.set_up_ljspeech() + + @torch.no_grad() + def test_ljspeech_tts_transformer_checkpoint(self): + checkpoint_filename = "ljspeech_transformer_g2p.pt" + path = self.download(self.base_url, self.root, checkpoint_filename) + + models, cfg, task = load_model_ensemble_and_task( + [path.as_posix()], arg_overrides={ + "data": self.root.as_posix(), + "config_yaml": "cfg_ljspeech_g2p.yaml", + "vocoder": "griffin_lim", + "fp16": False + } + ) + if self.use_cuda: + for model in models: + model.cuda() + + test_split = "ljspeech_test" + task.load_dataset(test_split) + batch_iterator = task.get_batch_iterator( + dataset=task.dataset(test_split), + max_tokens=65_536, max_positions=768, num_workers=1 + ).next_epoch_itr(shuffle=False) + progress = tqdm(batch_iterator, total=len(batch_iterator)) + generator = task.build_generator(models, cfg) + + mcd, n_samples = 0., 0 + for sample in progress: + sample = utils.move_to_cuda(sample) if self.use_cuda else sample + hypos = generator.generate(models[0], sample, has_targ=True) + rets = batch_mel_cepstral_distortion( + [hypo["targ_waveform"] for hypo in hypos], + [hypo["waveform"] for hypo in hypos], + sr=task.sr + ) + mcd += sum(d.item() for d, _ in rets) + n_samples += len(sample["id"].tolist()) + + mcd = round(mcd / n_samples, 1) + reference_mcd = 3.3 + print(f"MCD: {mcd} (reference: {reference_mcd})") + self.assertAlmostEqual(mcd, reference_mcd, delta=0.1) + + +if __name__ == "__main__": + unittest.main() From eb102b3b94900716b7b6f93711e9b51657d9e61b Mon Sep 17 00:00:00 2001 From: Ann Lee <annl@fb.com> Date: Wed, 15 Dec 2021 15:47:29 -0800 Subject: [PATCH 517/774] S2ST oss main (step 1) (#2762) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Releasing code, model & recipe for the work "Direct speech-to-speech translation with discrete units". Main changes: * tasks/speech_to_speech * data/audio/speech_to_speech_dataset * models/speech_to_speech * criterions/speech_to_speech_criterion ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2762 Reviewed By: kahne Differential Revision: D32956114 Pulled By: an918tw fbshipit-source-id: 3e48f9ca9d099d80d81cbb58e83caef06ffbf40a --- .../speech_synthesis/generate_waveform.py | 5 +- examples/speech_to_speech/README.md | 4 + examples/speech_to_speech/__init__.py | 4 + .../generate_waveform_from_code.py | 116 +++ .../criterions/speech_to_speech_criterion.py | 310 ++++++++ fairseq/criterions/tacotron2_loss.py | 6 - fairseq/data/audio/data_cfg.py | 176 ++++- .../data/audio/speech_to_speech_dataset.py | 406 ++++++++++ fairseq/data/audio/speech_to_text_dataset.py | 6 +- fairseq/models/speech_to_speech/__init__.py | 7 + fairseq/models/speech_to_speech/modules.py | 59 ++ .../speech_to_speech/s2s_transformer.py | 703 ++++++++++++++++++ fairseq/models/text_to_speech/codehifigan.py | 77 ++ fairseq/models/text_to_speech/hifigan.py | 8 +- .../models/text_to_speech/tts_transformer.py | 14 +- fairseq/models/text_to_speech/vocoder.py | 33 + fairseq/speech_generator.py | 2 +- fairseq/tasks/speech_to_speech.py | 472 ++++++++++++ 18 files changed, 2377 insertions(+), 31 deletions(-) create mode 100644 examples/speech_to_speech/README.md create mode 100644 examples/speech_to_speech/__init__.py create mode 100644 examples/speech_to_speech/generate_waveform_from_code.py create mode 100644 fairseq/criterions/speech_to_speech_criterion.py create mode 100644 fairseq/data/audio/speech_to_speech_dataset.py create mode 100644 fairseq/models/speech_to_speech/__init__.py create mode 100644 fairseq/models/speech_to_speech/modules.py create mode 100644 fairseq/models/speech_to_speech/s2s_transformer.py create mode 100644 fairseq/models/text_to_speech/codehifigan.py create mode 100644 fairseq/tasks/speech_to_speech.py diff --git a/examples/speech_synthesis/generate_waveform.py b/examples/speech_synthesis/generate_waveform.py index bfc2ef8eb3..3b56190dbe 100644 --- a/examples/speech_synthesis/generate_waveform.py +++ b/examples/speech_synthesis/generate_waveform.py @@ -3,7 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +import ast import logging import matplotlib.pyplot as plt import numpy as np @@ -48,7 +48,7 @@ def to_np(x): return None if x is None else x.detach().cpu().numpy() sample_ids = [dataset.ids[i] for i in sample["id"].tolist()] - texts = sample["src_texts"] + texts = sample["src_texts"] if "src_texts" in sample else [""] * len(hypos) attns = [to_np(hypo["attn"]) for hypo in hypos] eos_probs = [to_np(hypo.get("eos_prob", None)) for hypo in hypos] feat_preds = [to_np(hypo["feature"]) for hypo in hypos] @@ -135,6 +135,7 @@ def main(args): models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( [args.path], task=task, + arg_overrides=ast.literal_eval(args.model_overrides), ) model = models[0].cuda() if use_cuda else models[0] # use the original n_frames_per_step diff --git a/examples/speech_to_speech/README.md b/examples/speech_to_speech/README.md new file mode 100644 index 0000000000..bb4e087f2c --- /dev/null +++ b/examples/speech_to_speech/README.md @@ -0,0 +1,4 @@ +# Speech to speech translation + +## Direct speech-to-speech translation with discrete units +[https://arxiv.org/abs/2107.05604](https://arxiv.org/abs/2107.05604) diff --git a/examples/speech_to_speech/__init__.py b/examples/speech_to_speech/__init__.py new file mode 100644 index 0000000000..6264236915 --- /dev/null +++ b/examples/speech_to_speech/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/speech_to_speech/generate_waveform_from_code.py b/examples/speech_to_speech/generate_waveform_from_code.py new file mode 100644 index 0000000000..82aa7acfb8 --- /dev/null +++ b/examples/speech_to_speech/generate_waveform_from_code.py @@ -0,0 +1,116 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import json +import logging +from pathlib import Path +import random +import soundfile as sf +import torch + +from tqdm import tqdm + +from fairseq import utils +from fairseq.models.text_to_speech.vocoder import CodeHiFiGANVocoder + + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def dump_result(args, sample_id, pred_wav, suffix=""): + sf.write( + f"{args.results_path}/{sample_id}{suffix}_pred.wav", + pred_wav.detach().cpu().numpy(), + 16000, + ) + + +def load_code(in_file): + with open(in_file) as f: + out = [list(map(int, line.strip().split())) for line in f] + return out + + +def main(args): + logger.info(args) + + use_cuda = torch.cuda.is_available() and not args.cpu + + with open(args.vocoder_cfg) as f: + vocoder_cfg = json.load(f) + vocoder = CodeHiFiGANVocoder(args.vocoder, vocoder_cfg) + if use_cuda: + vocoder = vocoder.cuda() + + multispkr = vocoder.model.multispkr + if multispkr: + logger.info("multi-speaker vocoder") + num_speakers = vocoder_cfg.get( + "num_speakers", 200 + ) # following the default in codehifigan to set to 200 + assert ( + args.speaker_id < num_speakers + ), f"invalid --speaker-id ({args.speaker_id}) with total #speakers = {num_speakers}" + + data = load_code(args.in_code_file) + Path(args.results_path).mkdir(exist_ok=True, parents=True) + for i, d in tqdm(enumerate(data), total=len(data)): + x = { + "code": torch.LongTensor(d).view(1, -1), + } + suffix = "" + if multispkr: + spk = ( + random.randint(0, num_speakers - 1) + if args.speaker_id == -1 + else args.speaker_id + ) + suffix = f"_spk{spk}" + x["spkr"] = torch.LongTensor([spk]).view(1, 1) + + x = utils.move_to_cuda(x) if use_cuda else x + wav = vocoder(x, args.dur_prediction) + dump_result(args, i, wav, suffix=suffix) + + +def cli_main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--in-code-file", type=str, required=True, help="one unit sequence per line" + ) + parser.add_argument( + "--vocoder", type=str, required=True, help="path to the CodeHiFiGAN vocoder" + ) + parser.add_argument( + "--vocoder-cfg", + type=str, + required=True, + help="path to the CodeHiFiGAN vocoder config", + ) + parser.add_argument("--results-path", type=str, required=True) + parser.add_argument( + "--dur-prediction", + action="store_true", + help="enable duration prediction (for reduced/unique code sequences)", + ) + parser.add_argument( + "--speaker-id", + type=int, + default=-1, + help="Speaker id (for vocoder that supports multispeaker). Set to -1 to randomly sample speakers.", + ) + parser.add_argument("--cpu", action="store_true", help="run on CPU") + + args = parser.parse_args() + + main(args) + + +if __name__ == "__main__": + cli_main() diff --git a/fairseq/criterions/speech_to_speech_criterion.py b/fairseq/criterions/speech_to_speech_criterion.py new file mode 100644 index 0000000000..7fba673d25 --- /dev/null +++ b/fairseq/criterions/speech_to_speech_criterion.py @@ -0,0 +1,310 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +import torch + +from fairseq import metrics, utils +from fairseq.criterions import register_criterion +from fairseq.criterions.ctc import CtcCriterion +from fairseq.criterions.label_smoothed_cross_entropy import ( + LabelSmoothedCrossEntropyCriterion, + LabelSmoothedCrossEntropyCriterionConfig, +) +from fairseq.criterions.tacotron2_loss import ( + Tacotron2Criterion, + Tacotron2CriterionConfig, +) + + +class MultitaskCriterion: + def __init__(self, multitask_tasks): + self.multitask_criterion = {} + self.multitask_loss_weight = {} + for task_name, task_obj in multitask_tasks.items(): + if task_obj.args.decoder_type == "ctc": + self.multitask_criterion[task_name] = CtcCriterion( + task_obj.args.criterion_cfg, task_obj + ) + else: + self.multitask_criterion[ + task_name + ] = LabelSmoothedCrossEntropyCriterion( + task_obj, + task_obj.args.criterion_cfg.sentence_avg, + label_smoothing=task_obj.args.criterion_cfg.label_smoothing, + ) + + def set_multitask_loss_weight(self, task_name, weight=0.0): + self.multitask_loss_weight[task_name] = weight + + def get_multitask_loss(self, model, sample, model_out): + logging_output = {} + loss = 0.0 + for task_name, task_criterion in self.multitask_criterion.items(): + layer_id = task_criterion.task.args.input_layer + if isinstance(task_criterion, CtcCriterion): + if task_criterion.task.args.input_from == "encoder": + non_padding_mask = ~model_out["encoder_padding_mask"][0] + input_lengths = non_padding_mask.long().sum(-1) + task_sample = { + "net_input": { + "src_tokens": model_out["encoder_states"][ + layer_id + ], # check batch idx + "src_lengths": input_lengths, + }, + "id": sample["id"], + } + else: + task_sample = { + "net_input": { + "src_tokens": model_out["inner_states"][layer_id], + "src_lengths": sample["target_lengths"], + }, + "id": sample["id"], + } + else: + task_sample = { + "net_input": { + "src_tokens": sample["multitask"][task_name]["net_input"][ + "prev_output_tokens" + ], + "encoder_out": { + "encoder_out": [model_out["encoder_states"][layer_id]], + "encoder_padding_mask": model_out["encoder_padding_mask"], + }, + } + } + + for key in ["target", "target_lengths", "ntokens"]: + task_sample[key] = sample["multitask"][task_name][key] + + task_loss, task_sample_size, task_logging_output = task_criterion( + model.multitask_decoders[task_name], task_sample + ) + + loss = loss + self.multitask_loss_weight[task_name] * task_loss + task_logging_output["loss_weight"] = self.multitask_loss_weight[task_name] + logging_output[task_name] = task_logging_output + return loss, logging_output + + @classmethod + def reduce_metrics(cls, logging_outputs) -> None: + for task_name in logging_outputs[0]["multitask"].keys(): + # different criterion may return different logging + # currently only reduce on loss, the most common one + # ideally the way that losses are reduced should also depend on the task type + loss_sum = sum( + log["multitask"][task_name].get("loss", 0) for log in logging_outputs + ) + sample_size = sum( + log["multitask"][task_name].get("sample_size", 0) + for log in logging_outputs + ) + + metrics.log_scalar( + f"multitask_{task_name}_loss", + loss_sum / sample_size / math.log(2), + sample_size, + round=3, + ) + + loss_weight = logging_outputs[0]["multitask"][task_name].get( + "loss_weight", 0 + ) + metrics.log_scalar( + f"multitask_{task_name}_loss_weight", + loss_weight, + weight=0, + priority=250, + ) + + +@register_criterion( + "speech_to_unit", dataclass=LabelSmoothedCrossEntropyCriterionConfig +) +class SpeechToUnitMultitaskTaskCriterion( + LabelSmoothedCrossEntropyCriterion, MultitaskCriterion +): + def __init__( + self, + task, + sentence_avg, + label_smoothing, + ignore_prefix_size=0, + report_accuracy=False, + ): + super().__init__( + task, sentence_avg, label_smoothing, ignore_prefix_size, report_accuracy + ) + MultitaskCriterion.__init__(self, task.multitask_tasks) + + def forward(self, model, sample, reduce=True): + net_output, extra = model( + src_tokens=sample["net_input"]["src_tokens"], + src_lengths=sample["net_input"]["src_lengths"], + prev_output_tokens=sample["net_input"]["prev_output_tokens"], + tgt_speaker=sample["net_input"]["tgt_speaker"], + return_all_hiddens=True, + ) + + loss, nll_loss = self.compute_loss(model, [net_output], sample, reduce=reduce) + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + logging_output = { + "loss": loss.data, + "nll_loss": nll_loss.data, + "ntokens": sample["ntokens"], + "nsentences": sample["target"].size(0), + "sample_size": sample_size, + } + if self.report_accuracy: + n_correct, total = self.compute_accuracy(model, [net_output], sample) + logging_output["n_correct"] = utils.item(n_correct.data) + logging_output["total"] = utils.item(total.data) + + if len(self.multitask_criterion) == 0: + return loss, sample_size, logging_output + + # multitask + multitask_loss, multitask_log = self.get_multitask_loss(model, sample, extra) + loss += multitask_loss + logging_output["multitask"] = multitask_log + + return loss, sample_size, logging_output + + @classmethod + def reduce_metrics(cls, logging_outputs) -> None: + super().reduce_metrics(logging_outputs) + + # inference metrics + if "targ_frames" in logging_outputs[0]: + n = sum(log.get("norm_frames", 0) for log in logging_outputs) + for key, new_key in [ + ("mcd_loss", "mcd_loss"), + ("pred_frames", "pred_ratio"), + ("nins", "ins_rate"), + ("ndel", "del_rate"), + ]: + val = sum(log.get(key, 0) for log in logging_outputs) + metrics.log_scalar(new_key, val / n, n, round=3) + + if "multitask" not in logging_outputs[0]: + return + + MultitaskCriterion.reduce_metrics(logging_outputs) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return False + + +@register_criterion("speech_to_spectrogram", dataclass=Tacotron2CriterionConfig) +class SpeechToSpectrogramMultitaskTaskCriterion(Tacotron2Criterion, MultitaskCriterion): + def __init__( + self, + task, + sentence_avg, + use_guided_attention_loss, + guided_attention_loss_sigma, + bce_pos_weight, + ctc_weight, + ): + super().__init__( + task, + sentence_avg, + use_guided_attention_loss, + guided_attention_loss_sigma, + bce_pos_weight, + ctc_weight, + ) + MultitaskCriterion.__init__(self, task.multitask_tasks) + + def forward(self, model, sample, reduction="mean"): + bsz, max_len, _ = sample["target"].size() + feat_tgt = sample["target"] + feat_len = sample["target_lengths"].view(bsz, 1).expand(-1, max_len) + eos_tgt = torch.arange(max_len).to(sample["target"].device) + eos_tgt = eos_tgt.view(1, max_len).expand(bsz, -1) + eos_tgt = (eos_tgt == (feat_len - 1)).float() + + feat_out, eos_out, extra = model( + src_tokens=sample["net_input"]["src_tokens"], + src_lengths=sample["net_input"]["src_lengths"], + prev_output_tokens=sample["net_input"]["prev_output_tokens"], + tgt_speaker=sample["net_input"]["tgt_speaker"], + target_lengths=sample["target_lengths"], + return_all_hiddens=True, + ) + + l1_loss, mse_loss, eos_loss = self.compute_loss( + extra["feature_out"], + feat_out, + eos_out, + feat_tgt, + eos_tgt, + sample["target_lengths"], + reduction, + ) + attn_loss = torch.tensor(0.0).type_as(l1_loss) + if self.guided_attn is not None: + attn_loss = self.guided_attn( + extra["attn"], + sample["net_input"]["src_lengths"], + sample["target_lengths"], + reduction, + ) + loss = ( + l1_loss + mse_loss + eos_loss + attn_loss + ) # do not include ctc loss as there's no text target + + sample_size = sample["nsentences"] if self.sentence_avg else sample["ntokens"] + logging_output = { + "loss": utils.item(loss.data), + "ntokens": sample["ntokens"], + "nsentences": sample["nsentences"], + "sample_size": sample_size, + "l1_loss": utils.item(l1_loss.data), + "mse_loss": utils.item(mse_loss.data), + "eos_loss": utils.item(eos_loss.data), + "attn_loss": utils.item(attn_loss.data), + } + + if len(self.multitask_criterion) == 0: + return loss, sample_size, logging_output + + # multitask + multitask_loss, multitask_log = self.get_multitask_loss(model, sample, extra) + loss += multitask_loss + logging_output["multitask"] = multitask_log + return loss, sample_size, logging_output + + @classmethod + def reduce_metrics(cls, logging_outputs) -> None: + super().reduce_metrics(logging_outputs) + + # inference metrics + if "targ_frames" in logging_outputs[0]: + n = sum(log.get("norm_frames", 0) for log in logging_outputs) + for key, new_key in [ + ("mcd_loss", "mcd_loss"), + ("pred_frames", "pred_ratio"), + ("nins", "ins_rate"), + ("ndel", "del_rate"), + ]: + val = sum(log.get(key, 0) for log in logging_outputs) + metrics.log_scalar(new_key, val / n, n, round=3) + + if "multitask" not in logging_outputs[0]: + return + + MultitaskCriterion.reduce_metrics(logging_outputs) diff --git a/fairseq/criterions/tacotron2_loss.py b/fairseq/criterions/tacotron2_loss.py index 11ebf2d836..04747bf1aa 100644 --- a/fairseq/criterions/tacotron2_loss.py +++ b/fairseq/criterions/tacotron2_loss.py @@ -29,10 +29,6 @@ class Tacotron2CriterionConfig(FairseqDataclass): default=1.0, metadata={"help": "weight of positive examples for BCE loss"}, ) - n_frames_per_step: int = field( - default=0, - metadata={"help": "Number of frames per decoding step"}, - ) use_guided_attention_loss: bool = field( default=False, metadata={"help": "use guided attention loss"}, @@ -91,7 +87,6 @@ def __init__( self, task, sentence_avg, - n_frames_per_step, use_guided_attention_loss, guided_attention_loss_sigma, bce_pos_weight, @@ -99,7 +94,6 @@ def __init__( ): super().__init__(task) self.sentence_avg = sentence_avg - self.n_frames_per_step = n_frames_per_step self.bce_pos_weight = bce_pos_weight self.guided_attn = None diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 95b403ad9c..734f9e7e5a 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -2,30 +2,36 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - +from argparse import Namespace from pathlib import Path from typing import Dict, Optional +from fairseq.data import Dictionary + + +def get_config_from_yaml(yaml_path: Path): + try: + import yaml + except ImportError: + print("Please install PyYAML: pip install PyYAML") + config = {} + if yaml_path.is_file(): + try: + with open(yaml_path) as f: + config = yaml.load(f, Loader=yaml.FullLoader) + except Exception as e: + raise Exception(f"Failed to load config from {yaml_path.as_posix()}: {e}") + else: + raise FileNotFoundError(f"{yaml_path.as_posix()} not found") + + return config + class S2TDataConfig(object): """Wrapper class for data config YAML""" def __init__(self, yaml_path: Path): - try: - import yaml - except ImportError: - print("Please install PyYAML: pip install PyYAML") - self.config = {} - if yaml_path.is_file(): - try: - with open(yaml_path) as f: - self.config = yaml.load(f, Loader=yaml.FullLoader) - except Exception as e: - raise Exception( - f"Failed to load config from {yaml_path.as_posix()}: {e}" - ) - else: - raise FileNotFoundError(f"{yaml_path.as_posix()} not found") + self.config = get_config_from_yaml(yaml_path) self.root = yaml_path.parent def _auto_convert_to_abs_path(self, x): @@ -43,7 +49,7 @@ def vocab_filename(self): @property def speaker_set_filename(self): - """fairseq vocabulary file under data root""" + """speaker set file under data root""" return self.config.get("speaker_set_filename", None) @property @@ -137,3 +143,139 @@ def global_cmvn_stats_npz(self) -> Optional[str]: @property def vocoder(self) -> Optional[Dict[str, str]]: return self.config.get("vocoder", None) + + +class S2SDataConfig(S2TDataConfig): + """Wrapper class for data config YAML""" + + @property + def vocab_filename(self): + return None + + @property + def pre_tokenizer(self) -> Dict: + return None + + @property + def bpe_tokenizer(self) -> Dict: + return None + + @property + def input_transformed_channels(self): + """The number of channels in the audio after feature transforms""" + # TODO: move this into individual transforms + _cur = self.config.get("transforms", {}) + cur = _cur.get("_train", []) + + _channels = self.input_channels + if "delta_deltas" in cur: + _channels *= 3 + + return _channels + + @property + def output_sample_rate(self): + """The audio sample rate of output target speech""" + return self.config.get("output_sample_rate", 22050) + + @property + def target_speaker_embed(self): + """Target speaker embedding file (one line per target audio sample)""" + return self.config.get("target_speaker_embed", None) + + +class MultitaskConfig(object): + """Wrapper class for data config YAML""" + + def __init__(self, yaml_path: Path): + config = get_config_from_yaml(yaml_path) + self.config = {} + for k, v in config.items(): + self.config[k] = SingleTaskConfig(k, v) + + def get_all_tasks(self): + return self.config + + def get_single_task(self, name): + assert name in self.config, f"multitask '{name}' does not exist!" + return self.config[name] + + +class SingleTaskConfig(object): + def __init__(self, name, config): + self.task_name = name + self.config = config + dict_path = config.get("dict", "") + self.tgt_dict = Dictionary.load(dict_path) if Path(dict_path).exists() else None + + @property + def data(self): + return self.config.get("data", "") + + @property + def decoder_type(self): + return self.config.get("decoder_type", "transformer") + + @property + def decoder_args(self): + """Decoder arch related args""" + args = self.config.get("decoder_args", {}) + return Namespace(**args) + + @property + def criterion_cfg(self): + """cfg for the multitask criterion""" + if self.decoder_type == "ctc": + from fairseq.criterions.ctc import CtcCriterionConfig + + cfg = CtcCriterionConfig + cfg.zero_infinity = self.config.get("zero_infinity", True) + else: + from fairseq.criterions.label_smoothed_cross_entropy import ( + LabelSmoothedCrossEntropyCriterionConfig, + ) + + cfg = LabelSmoothedCrossEntropyCriterionConfig + cfg.label_smoothing = self.config.get("label_smoothing", 0.2) + return cfg + + @property + def input_from(self): + """Condition on encoder/decoder of the main model""" + return "decoder" if "decoder_layer" in self.config else "encoder" + + @property + def input_layer(self): + if self.input_from == "decoder": + return self.config["decoder_layer"] - 1 + else: + # default using the output from the last encoder layer + # TODO: check if need to offset by 1 + return self.config.get("encoder_layer", -1) + + @property + def loss_weight_schedule(self): + return ( + "decay" + if "loss_weight_max" in self.config + and "loss_weight_decay_steps" in self.config + else "fixed" + ) + + def get_loss_weight(self, num_updates): + if self.loss_weight_schedule == "fixed": + weight = self.config.get("loss_weight", 1.0) + else: # "decay" + assert ( + self.config.get("loss_weight_decay_steps", 0) > 0 + ), "loss_weight_decay_steps must be greater than 0 for a decay schedule" + loss_weight_min = self.config.get("loss_weight_min", 0.0001) + loss_weight_decay_stepsize = ( + self.config["loss_weight_max"] - loss_weight_min + ) / self.config["loss_weight_decay_steps"] + weight = max( + self.config["loss_weight_max"] + - loss_weight_decay_stepsize * num_updates, + loss_weight_min, + ) + return weight diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py new file mode 100644 index 0000000000..3fed098375 --- /dev/null +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -0,0 +1,406 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass +import logging +from pathlib import Path +from typing import Dict, List, Optional, Tuple + +import torch +from fairseq.data import ( + ConcatDataset, + data_utils as fairseq_data_utils, + Dictionary, +) +from fairseq.data.audio.data_cfg import S2SDataConfig +from fairseq.data.audio.speech_to_text_dataset import ( + _collate_frames, + get_features_or_waveform, + SpeechToTextDataset, + SpeechToTextDatasetCreator, +) + + +logger = logging.getLogger(__name__) + + +@dataclass +class SpeechToSpeechDatasetItem(object): + index: int + source: torch.Tensor + target: Optional[torch.Tensor] = None + target_speaker: Optional[torch.Tensor] = None + + +class SpeechToSpeechDataset(SpeechToTextDataset): + def __init__( + self, + split: str, + is_train_split: bool, + data_cfg: S2SDataConfig, + src_audio_paths: List[str], + src_n_frames: List[int], + tgt_audio_paths: List[str], + tgt_n_frames: List[int], + ids: Optional[List[str]] = None, + target_is_code: bool = False, + tgt_dict: Dictionary = None, + n_frames_per_step: int = 1, + ): + tgt_texts = tgt_audio_paths if target_is_code else None + super().__init__( + split, + is_train_split, + data_cfg, + src_audio_paths, + src_n_frames, + ids=ids, + tgt_dict=tgt_dict, + tgt_texts=tgt_texts, + n_frames_per_step=n_frames_per_step, + ) + + self.tgt_audio_paths = tgt_audio_paths + self.tgt_lens = [t // self.n_frames_per_step for t in tgt_n_frames] + + assert not target_is_code or tgt_dict is not None + self.target_is_code = target_is_code + + assert len(tgt_audio_paths) == self.n_samples + assert len(tgt_n_frames) == self.n_samples + + self.tgt_speakers = None + if self.cfg.target_speaker_embed: + samples = SpeechToTextDatasetCreator._load_samples_from_tsv( + self.cfg.target_speaker_embed, split + ) + spk_emb_dict = {s["id"]: s["speaker_embed"] for s in samples} + self.tgt_speakers = [spk_emb_dict[id] for id in self.ids] + assert len(self.tgt_speakers) == self.n_samples + + logger.info(self.__repr__()) + + def pack_units(self, input: torch.Tensor) -> torch.Tensor: + if self.n_frames_per_step <= 1: + return input + + offset = 4 + vocab_size = ( + len(self.tgt_dict) - offset + ) # remove offset from <bos>, <pad>, <eos>, <unk>, which is specific to fairseq dictionary + + assert input.dim() == 1 + stacked_input = ( + input[:-1].view(-1, self.n_frames_per_step) - offset + ) # remove <eos> + scale = [ + pow(vocab_size, self.n_frames_per_step - 1 - i) + for i in range(self.n_frames_per_step) + ] + scale = torch.LongTensor(scale).squeeze(0) + res = input.new((len(input) - 1) // self.n_frames_per_step + 1).fill_(input[-1]) + res[:-1] = (stacked_input * scale).sum(dim=1) + offset + + return res + + def __getitem__(self, index: int) -> SpeechToSpeechDatasetItem: + source = self._get_source_audio(index) + + if not self.target_is_code: + target = get_features_or_waveform(self.tgt_audio_paths[index]) + target = torch.from_numpy(target).float() + target = self.pack_frames(target) + else: + target = self.tgt_dict.encode_line( + self.tgt_audio_paths[index], + add_if_not_exist=False, + append_eos=True, + ).long() + if self.n_frames_per_step > 1: + n_tgt_frame = target.size(0) - 1 # exclude <eos> + keep_n_tgt_frame = n_tgt_frame - n_tgt_frame % self.n_frames_per_step + target = torch.cat( + ( + target[:keep_n_tgt_frame], + target.new_full((1,), self.tgt_dict.eos()), + ), + dim=0, + ) + + if self.tgt_speakers: + tgt_spk = get_features_or_waveform(self.tgt_speakers[index]) + tgt_spk = torch.from_numpy(tgt_spk).float() + else: + tgt_spk = torch.FloatTensor([]) + + return SpeechToSpeechDatasetItem( + index=index, source=source, target=target, target_speaker=tgt_spk + ) + + def _collate_target(self, samples: List[SpeechToSpeechDatasetItem]) -> torch.Tensor: + if self.target_is_code: + target = fairseq_data_utils.collate_tokens( + [x.target for x in samples], + self.tgt_dict.pad(), + self.tgt_dict.eos(), + left_pad=False, + move_eos_to_beginning=False, + ) + # convert stacked units to a single id + pack_targets = [self.pack_units(x.target) for x in samples] + prev_output_tokens = fairseq_data_utils.collate_tokens( + pack_targets, + self.tgt_dict.pad(), + self.tgt_dict.eos(), + left_pad=False, + move_eos_to_beginning=True, + ) + target_lengths = torch.tensor( + [x.size(0) for x in pack_targets], dtype=torch.long + ) + else: + target = _collate_frames([x.target for x in samples], is_audio_input=False) + bsz, _, d = target.size() + prev_output_tokens = torch.cat( + (target.new_full((bsz, 1, d), 0.0), target[:, :-1, :]), dim=1 + ) + target_lengths = torch.tensor( + [x.target.size(0) for x in samples], dtype=torch.long + ) + + return target, prev_output_tokens, target_lengths + + def collater( + self, samples: List[SpeechToSpeechDatasetItem], return_order: bool = False + ) -> Dict: + if len(samples) == 0: + return {} + indices = torch.tensor([x.index for x in samples], dtype=torch.long) + frames = _collate_frames([x.source for x in samples], self.cfg.use_audio_input) + # sort samples by descending number of frames + n_frames = torch.tensor([x.source.size(0) for x in samples], dtype=torch.long) + n_frames, order = n_frames.sort(descending=True) + indices = indices.index_select(0, order) + frames = frames.index_select(0, order) + + target, prev_output_tokens, target_lengths = self._collate_target(samples) + target = target.index_select(0, order) + target_lengths = target_lengths.index_select(0, order) + prev_output_tokens = prev_output_tokens.index_select(0, order) + ntokens = sum(x.target.size(0) for x in samples) + + tgt_speakers = None + if self.cfg.target_speaker_embed: + tgt_speakers = _collate_frames( + [x.target_speaker for x in samples], is_audio_input=True + ).index_select(0, order) + + net_input = { + "src_tokens": frames, + "src_lengths": n_frames, + "prev_output_tokens": prev_output_tokens, + "tgt_speaker": tgt_speakers, # TODO: unify "speaker" and "tgt_speaker" + } + out = { + "id": indices, + "net_input": net_input, + "speaker": tgt_speakers, # to support Tacotron2 loss for speech-to-spectrogram model + "target": target, + "target_lengths": target_lengths, + "ntokens": ntokens, + "nsentences": len(samples), + } + if return_order: + out["order"] = order + return out + + +class TextTargetMultitaskData(object): + # mandatory columns + KEY_ID, KEY_TEXT = "id", "tgt_text" + + def __init__(self, args, split, tgt_dict): + samples = SpeechToTextDatasetCreator._load_samples_from_tsv(args.data, split) + self.data = {s[self.KEY_ID]: s[self.KEY_TEXT] for s in samples} + self.dict = tgt_dict + self.append_eos = args.decoder_type != "ctc" + + def get(self, sample_id): + if sample_id in self.data: + return self.dict.encode_line( + self.data[sample_id], + add_if_not_exist=False, + append_eos=self.append_eos, + ) + else: + logger.warning(f"no target for {sample_id}") + return torch.IntTensor([]) + + def collater(self, samples: List[torch.Tensor]) -> torch.Tensor: + out = fairseq_data_utils.collate_tokens( + samples, + self.dict.pad(), + self.dict.eos(), + left_pad=False, + move_eos_to_beginning=False, + ).long() + + prev_out = fairseq_data_utils.collate_tokens( + samples, + self.dict.pad(), + self.dict.eos(), + left_pad=False, + move_eos_to_beginning=True, + ).long() + + target_lengths = torch.tensor([t.size(0) for t in samples], dtype=torch.long) + ntokens = sum(t.size(0) for t in samples) + + output = { + "prev_output_tokens": prev_out, + "target": out, + "target_lengths": target_lengths, + "ntokens": ntokens, + } + + return output + + +class SpeechToSpeechMultitaskDataset(SpeechToSpeechDataset): + def __init__(self, *argv): + super().__init__(*argv) + self.multitask_data = {} + + def add_multitask_dataset(self, task_name, task_data): + self.multitask_data[task_name] = task_data + + def __getitem__( + self, index: int + ) -> Tuple[SpeechToSpeechDatasetItem, Dict[str, torch.Tensor]]: + s2s_data = super().__getitem__(index) + + multitask_target = {} + sample_id = self.ids[index] + for task_name, task_dataset in self.multitask_data.items(): + multitask_target[task_name] = task_dataset.get(sample_id) + + return s2s_data, multitask_target + + def collater( + self, samples: List[Tuple[SpeechToSpeechDatasetItem, Dict[str, torch.Tensor]]] + ) -> Dict: + if len(samples) == 0: + return {} + + out = super().collater([s for s, _ in samples], return_order=True) + order = out["order"] + del out["order"] + + for task_name, task_dataset in self.multitask_data.items(): + if "multitask" not in out: + out["multitask"] = {} + d = [s[task_name] for _, s in samples] + task_target = task_dataset.collater(d) + out["multitask"][task_name] = { + "target": task_target["target"].index_select(0, order), + "target_lengths": task_target["target_lengths"].index_select(0, order), + "ntokens": task_target["ntokens"], + } + out["multitask"][task_name]["net_input"] = { + "prev_output_tokens": task_target["prev_output_tokens"].index_select( + 0, order + ), + } + + return out + + +class SpeechToSpeechDatasetCreator(object): + # mandatory columns + KEY_ID, KEY_SRC_AUDIO, KEY_SRC_N_FRAMES = "id", "src_audio", "src_n_frames" + KEY_TGT_AUDIO, KEY_TGT_N_FRAMES = "tgt_audio", "tgt_n_frames" + + @classmethod + def _from_list( + cls, + split_name: str, + is_train_split, + samples: List[Dict], + data_cfg: S2SDataConfig, + target_is_code: bool = False, + target_dictionary: Dictionary = None, + n_frames_per_step: int = 1, + multitask: Optional[Dict] = None, + ) -> SpeechToSpeechDataset: + audio_root = Path(data_cfg.audio_root) + ids = [s[cls.KEY_ID] for s in samples] + src_audio_paths = [ + (audio_root / s[cls.KEY_SRC_AUDIO]).as_posix() for s in samples + ] + tgt_audio_paths = [ + s[cls.KEY_TGT_AUDIO] + if target_is_code + else (audio_root / s[cls.KEY_TGT_AUDIO]).as_posix() + for s in samples + ] + src_n_frames = [int(s[cls.KEY_SRC_N_FRAMES]) for s in samples] + tgt_n_frames = [int(s[cls.KEY_TGT_N_FRAMES]) for s in samples] + + has_multitask = len(multitask) > 0 + dataset_cls = ( + SpeechToSpeechMultitaskDataset if has_multitask else SpeechToSpeechDataset + ) + + ds = dataset_cls( + split_name, + is_train_split, + data_cfg, + src_audio_paths, + src_n_frames, + tgt_audio_paths, + tgt_n_frames, + ids, + target_is_code, + target_dictionary, + n_frames_per_step, + ) + + if has_multitask: + for task_name, task_obj in multitask.items(): + task_data = TextTargetMultitaskData( + task_obj.args, split_name, task_obj.target_dictionary + ) + ds.add_multitask_dataset(task_name, task_data) + return ds + + @classmethod + def from_tsv( + cls, + root: str, + data_cfg: S2SDataConfig, + splits: str, + is_train_split: bool, + epoch: int, + seed: int, + target_is_code: bool = False, + target_dictionary: Dictionary = None, + n_frames_per_step: int = 1, + multitask: Optional[Dict] = None, + ) -> SpeechToSpeechDataset: + datasets = [] + for split in splits.split(","): + samples = SpeechToTextDatasetCreator._load_samples_from_tsv(root, split) + ds = cls._from_list( + split, + is_train_split, + samples, + data_cfg, + target_is_code, + target_dictionary, + n_frames_per_step, + multitask, + ) + datasets.append(ds) + return ConcatDataset(datasets) if len(datasets) > 1 else datasets[0] diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index b6dfd9ae2d..f04d273574 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -250,7 +250,7 @@ def get_lang_tag_idx(cls, lang: str, dictionary: Dictionary): assert lang_tag_idx != dictionary.unk() return lang_tag_idx - def __getitem__(self, index: int) -> SpeechToTextDatasetItem: + def _get_source_audio(self, index: int) -> torch.Tensor: source = get_features_or_waveform( self.audio_paths[index], need_waveform=self.cfg.use_audio_input, @@ -260,6 +260,10 @@ def __getitem__(self, index: int) -> SpeechToTextDatasetItem: assert not self.cfg.use_audio_input source = self.feature_transforms(source) source = torch.from_numpy(source).float() + return source + + def __getitem__(self, index: int) -> SpeechToTextDatasetItem: + source = self._get_source_audio(index) source = self.pack_frames(source) target = None diff --git a/fairseq/models/speech_to_speech/__init__.py b/fairseq/models/speech_to_speech/__init__.py new file mode 100644 index 0000000000..d348835525 --- /dev/null +++ b/fairseq/models/speech_to_speech/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .modules import * # noqa +from .s2s_transformer import * # noqa diff --git a/fairseq/models/speech_to_speech/modules.py b/fairseq/models/speech_to_speech/modules.py new file mode 100644 index 0000000000..d07994b90e --- /dev/null +++ b/fairseq/models/speech_to_speech/modules.py @@ -0,0 +1,59 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from torch import nn + +from fairseq.models import FairseqEncoder +from fairseq.models.transformer import Linear + + +class CTCDecoder(FairseqEncoder): + def __init__(self, dictionary, in_dim): + super().__init__(dictionary) + self.proj = nn.Linear(in_dim, len(dictionary)) + + def forward(self, src_tokens, src_lengths=None, **kwargs): + encoder_out = self.proj(src_tokens) + return {"encoder_out": encoder_out} + + +class StackedEmbedding(nn.Embedding): + """Embedding module that supports stacked units -> single embedding""" + + def __init__(self, num_embeddings, embed_dim, padding_idx, num_stacked=1): + super().__init__(num_embeddings, embed_dim, padding_idx) + # follow transformer.Embedding + nn.init.normal_(self.weight, mean=0, std=embed_dim ** -0.5) + nn.init.constant_(self.weight[padding_idx], 0) + + self.offset = ( + 4 # skip <bos>, <pad>, <eos>, <unk>, specific to fairseq dictionary + ) + self.vocab_size = num_embeddings - self.offset + self.num_stacked = num_stacked + + if self.num_stacked > 1: + self.project_in_dim = Linear(embed_dim * num_stacked, embed_dim, bias=False) + + def forward(self, input): + if self.num_stacked == 1: + return super().forward(input) + + # expand input indices + mask = input >= self.offset + stacked_input = [] + cum_input = input.new_zeros(input.shape) + for i in range(1, self.num_stacked + 1): + div = pow(self.vocab_size, i) + next_input = torch.remainder(input - self.offset - cum_input, div) + cum_input += next_input + next_input = torch.floor_divide(next_input, div // self.vocab_size) + stacked_input.append((next_input + self.offset) * mask + input * ~mask) + + stacked_input = torch.stack(stacked_input[::-1], dim=2) + embed = super().forward(stacked_input).view(input.size(0), input.size(1), -1) + embed = self.project_in_dim(embed) + return embed diff --git a/fairseq/models/speech_to_speech/s2s_transformer.py b/fairseq/models/speech_to_speech/s2s_transformer.py new file mode 100644 index 0000000000..a5954a83e5 --- /dev/null +++ b/fairseq/models/speech_to_speech/s2s_transformer.py @@ -0,0 +1,703 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from pathlib import Path +from typing import Any, Dict, List, Optional + +import torch +from torch import Tensor + +from fairseq import checkpoint_utils, utils +from fairseq.models import ( + FairseqEncoderModel, + FairseqEncoderDecoderModel, + FairseqLanguageModel, + register_model, + register_model_architecture, +) +from fairseq.models.speech_to_text import S2TTransformerEncoder +from fairseq.models.speech_to_speech.modules import CTCDecoder, StackedEmbedding +from fairseq.models.text_to_speech import TTSTransformerDecoder +from fairseq.models.transformer import ( + Linear, + TransformerDecoder, + TransformerModelBase, +) + + +logger = logging.getLogger(__name__) + + +class S2STransformerEncoder(S2TTransformerEncoder): + """Based on S2T transformer encoder, with support + to incorporate target speaker embedding.""" + + def __init__(self, args): + super().__init__(args) + + self.spk_emb_proj = None + if args.target_speaker_embed: + self.spk_emb_proj = Linear( + args.encoder_embed_dim + args.speaker_embed_dim, args.encoder_embed_dim + ) + + def forward( + self, src_tokens, src_lengths, tgt_speaker=None, return_all_hiddens=False + ): + out = super().forward(src_tokens, src_lengths, return_all_hiddens) + + if self.spk_emb_proj: + x = out["encoder_out"][0] + seq_len, bsz, _ = x.size() + tgt_speaker_emb = tgt_speaker.view(1, bsz, -1).expand(seq_len, bsz, -1) + x = self.spk_emb_proj(torch.cat([x, tgt_speaker_emb], dim=2)) + out["encoder_out"][0] = x + + return out + + +class TransformerUnitDecoder(TransformerDecoder): + """Based on Transformer decoder, with support to decoding stacked units""" + + def __init__( + self, + args, + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=None, + ): + super().__init__( + args, dictionary, embed_tokens, no_encoder_attn, output_projection + ) + self.n_frames_per_step = args.n_frames_per_step + + self.out_proj_n_frames = ( + Linear( + self.output_embed_dim, + self.output_embed_dim * self.n_frames_per_step, + bias=False, + ) + if self.n_frames_per_step > 1 + else None + ) + + def forward( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + features_only: bool = False, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + src_lengths: Optional[Any] = None, + return_all_hiddens: bool = False, + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + encoder_out (optional): output from the encoder, used for + encoder-side attention, should be of size T x B x C + incremental_state (dict): dictionary used for storing state during + :ref:`Incremental decoding` + features_only (bool, optional): only return features without + applying output layer (default: False). + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + + x, extra = self.extract_features( + prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + full_context_alignment=full_context_alignment, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + ) + + if not features_only: + bsz, seq_len, d = x.size() + if self.out_proj_n_frames: + x = self.out_proj_n_frames(x) + x = self.output_layer(x.view(bsz, seq_len, self.n_frames_per_step, d)) + x = x.view(bsz, seq_len * self.n_frames_per_step, -1) + if ( + incremental_state is None and self.n_frames_per_step > 1 + ): # teacher-forcing mode in training + x = x[ + :, : -(self.n_frames_per_step - 1), : + ] # remove extra frames after <eos> + + return x, extra + + def upgrade_state_dict_named(self, state_dict, name): + if self.n_frames_per_step > 1: + move_keys = [ + ( + f"{name}.project_in_dim.weight", + f"{name}.embed_tokens.project_in_dim.weight", + ) + ] + for from_k, to_k in move_keys: + if from_k in state_dict and to_k not in state_dict: + state_dict[to_k] = state_dict[from_k] + del state_dict[from_k] + + +class S2STransformerMultitaskModelBase(FairseqEncoderDecoderModel): + @classmethod + def build_encoder(cls, args): + encoder = S2STransformerEncoder(args) + pretraining_path = getattr(args, "load_pretrained_encoder_from", None) + if pretraining_path is not None: + if not Path(pretraining_path).exists(): + logger.warning( + f"skipped pretraining because {pretraining_path} does not exist" + ) + else: + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=pretraining_path + ) + logger.info(f"loaded pretrained encoder from: {pretraining_path}") + return encoder + + @classmethod + def build_multitask_decoder(cls, args, tgt_dict, in_dim): + decoder_args = args.decoder_args + decoder_args.encoder_embed_dim = in_dim + if args.decoder_type == "transformer": + base_multitask_text_transformer_decoder_arch(decoder_args) + task_decoder = TransformerDecoder( + decoder_args, + tgt_dict, + embed_tokens=TransformerModelBase.build_embedding( + decoder_args, + tgt_dict, + decoder_args.decoder_embed_dim, + ), + ) + elif args.decoder_type == "ctc": + task_decoder = CTCDecoder( + dictionary=tgt_dict, + in_dim=in_dim, + ) + else: + raise NotImplementedError( + "currently only support multitask decoder_type 'transformer', 'ctc'" + ) + + return task_decoder + + @classmethod + def build_model(cls, args, task): + encoder = cls.build_encoder(args) + decoder = ( + cls.build_decoder(args, task.target_dictionary) + if task.args.target_is_code + else cls.build_decoder(args) + ) + base_model = cls(encoder, decoder) + + # set up multitask decoders + base_model.multitask_decoders = {} + for task_name, task_obj in task.multitask_tasks.items(): + in_dim = ( + args.encoder_embed_dim + if task_obj.args.input_from == "encoder" + else args.decoder_embed_dim + ) + task_decoder = cls.build_multitask_decoder( + task_obj.args, task_obj.target_dictionary, in_dim + ) + + setattr(base_model, f"{task_name}_decoder", task_decoder) + decoder_model_cls = ( + FairseqEncoderModel + if task_obj.args.decoder_type == "ctc" + else FairseqLanguageModel + ) + base_model.multitask_decoders[task_name] = decoder_model_cls( + getattr(base_model, f"{task_name}_decoder") + ) + + return base_model + + def forward_encoder(self, src_tokens, src_lengths, speaker=None, **kwargs): + return self.encoder( + src_tokens, src_lengths=src_lengths, tgt_speaker=speaker, **kwargs + ) + + +@register_model("s2ut_transformer") +class S2UTTransformerModel(S2STransformerMultitaskModelBase): + """ + Direct speech-to-speech translation model with S2T Transformer encoder + Transformer discrete unit decoder + https://arxiv.org/abs/2107.05604 + """ + + @staticmethod + def add_args(parser): + # input + parser.add_argument( + "--conv-kernel-sizes", + type=str, + metavar="N", + help="kernel sizes of Conv1d subsampling layers", + ) + parser.add_argument( + "--conv-channels", + type=int, + metavar="N", + help="# of channels in Conv1d subsampling layers", + ) + # Transformer + parser.add_argument( + "--activation-fn", + type=str, + default="relu", + choices=utils.get_available_activation_fns(), + help="activation function to use", + ) + parser.add_argument( + "--dropout", type=float, metavar="D", help="dropout probability" + ) + parser.add_argument( + "--attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights", + ) + parser.add_argument( + "--activation-dropout", + "--relu-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN.", + ) + parser.add_argument( + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension", + ) + parser.add_argument( + "--encoder-ffn-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension for FFN", + ) + parser.add_argument( + "--encoder-layers", type=int, metavar="N", help="num encoder layers" + ) + parser.add_argument( + "--encoder-attention-heads", + type=int, + metavar="N", + help="num encoder attention heads", + ) + parser.add_argument( + "--encoder-normalize-before", + action="store_true", + help="apply layernorm before each encoder block", + ) + parser.add_argument( + "--decoder-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension", + ) + parser.add_argument( + "--decoder-ffn-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension for FFN", + ) + parser.add_argument( + "--decoder-layers", type=int, metavar="N", help="num decoder layers" + ) + parser.add_argument( + "--decoder-attention-heads", + type=int, + metavar="N", + help="num decoder attention heads", + ) + parser.add_argument( + "--decoder-normalize-before", + action="store_true", + help="apply layernorm before each decoder block", + ) + parser.add_argument( + "--share-decoder-input-output-embed", + action="store_true", + help="share decoder input and output embeddings", + ) + parser.add_argument( + "--layernorm-embedding", + action="store_true", + help="add layernorm to embedding", + ) + parser.add_argument( + "--no-scale-embedding", + action="store_true", + help="if True, dont scale embeddings", + ) + parser.add_argument( + "--load-pretrained-encoder-from", + type=str, + metavar="STR", + help="model to take encoder weights from (for initialization)", + ) + parser.add_argument( + "--encoder-freezing-updates", + type=int, + metavar="N", + help="freeze encoder for first N updates", + ) + # speaker + parser.add_argument( + "--speaker-embed-dim", + type=int, + metavar="N", + help="speaker embedding dimension", + ) + + @classmethod + def build_decoder(cls, args, tgt_dict): + num_embeddings = len(tgt_dict) + padding_idx = tgt_dict.pad() + embed_tokens = StackedEmbedding( + num_embeddings, + args.decoder_embed_dim, + padding_idx, + num_stacked=args.n_frames_per_step, + ) + + return TransformerUnitDecoder( + args, + tgt_dict, + embed_tokens, + ) + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + tgt_speaker=None, + return_all_hiddens=False, + ): + encoder_out = self.encoder( + src_tokens, + src_lengths=src_lengths, + tgt_speaker=tgt_speaker, + return_all_hiddens=return_all_hiddens, + ) + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=encoder_out, + ) + if return_all_hiddens: + decoder_out[-1]["encoder_states"] = encoder_out["encoder_states"] + decoder_out[-1]["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ] + return decoder_out + + +@register_model("s2spect_transformer") +class S2SpecTTransformerModel(S2STransformerMultitaskModelBase): + """ + Speech-to-spectrogram model with S2T Transformer encoder + TTS Transformer decoder + """ + + @staticmethod + def add_args(parser): + # input + parser.add_argument( + "--conv-kernel-sizes", + type=str, + metavar="N", + help="kernel sizes of Conv1d subsampling layers", + ) + parser.add_argument( + "--conv-channels", + type=int, + metavar="N", + help="# of channels in Conv1d subsampling layers", + ) + # Transformer + parser.add_argument( + "--activation-fn", + type=str, + default="relu", + choices=utils.get_available_activation_fns(), + help="activation function to use", + ) + parser.add_argument( + "--dropout", type=float, metavar="D", help="dropout probability" + ) + parser.add_argument( + "--attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights", + ) + parser.add_argument( + "--activation-dropout", + "--relu-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN.", + ) + parser.add_argument( + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension", + ) + parser.add_argument( + "--encoder-ffn-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension for FFN", + ) + parser.add_argument( + "--encoder-layers", type=int, metavar="N", help="num encoder layers" + ) + parser.add_argument( + "--encoder-attention-heads", + type=int, + metavar="N", + help="num encoder attention heads", + ) + parser.add_argument( + "--encoder-normalize-before", + action="store_true", + help="apply layernorm before each encoder block", + ) + parser.add_argument( + "--no-scale-embedding", + action="store_true", + help="if True, dont scale embeddings", + ) + parser.add_argument( + "--load-pretrained-encoder-from", + type=str, + metavar="STR", + help="model to take encoder weights from (for initialization)", + ) + parser.add_argument( + "--encoder-freezing-updates", + type=int, + metavar="N", + help="freeze encoder for first N updates", + ) + # speaker + parser.add_argument( + "--speaker-embed-dim", + type=int, + metavar="N", + help="speaker embedding dimension", + ) + # decoder + parser.add_argument("--output-frame-dim", type=int) + # decoder prenet + parser.add_argument("--prenet-dropout", type=float) + parser.add_argument("--prenet-layers", type=int) + parser.add_argument("--prenet-dim", type=int) + # decoder postnet + parser.add_argument("--postnet-dropout", type=float) + parser.add_argument("--postnet-layers", type=int) + parser.add_argument("--postnet-conv-dim", type=int) + parser.add_argument("--postnet-conv-kernel-size", type=int) + # decoder transformer layers + parser.add_argument("--decoder-transformer-layers", type=int) + parser.add_argument("--decoder-embed-dim", type=int) + parser.add_argument("--decoder-ffn-embed-dim", type=int) + parser.add_argument("--decoder-normalize-before", action="store_true") + parser.add_argument("--decoder-attention-heads", type=int) + + @classmethod + def build_decoder(cls, args): + return TTSTransformerDecoder(args, None, padding_idx=1) + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + tgt_speaker=None, + incremental_state=None, + target_lengths=None, + speaker=None, + return_all_hiddens=False, + ): + encoder_out = self.encoder( + src_tokens, + src_lengths=src_lengths, + tgt_speaker=tgt_speaker, + return_all_hiddens=return_all_hiddens, + ) + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + target_lengths=target_lengths, + speaker=speaker, + ) + if return_all_hiddens: + decoder_out[-1]["encoder_states"] = encoder_out["encoder_states"] + decoder_out[-1]["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ] + return decoder_out + + +def base_multitask_text_transformer_decoder_arch(args): + args.dropout = getattr(args, "dropout", 0.3) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", True + ) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 256) + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) + + args.max_target_positions = getattr(args, "max_target_positions", 1024) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + + args.adaptive_input = getattr(args, "adaptive_input", False) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + + args.decoder_layers = getattr(args, "decoder_layers", 2) + + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + + # decoder layer + args.activation_dropout = getattr(args, "activation_dropout", args.dropout) + args.activation_fn = getattr(args, "activation_fn", "relu") + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 2048) + + args.attention_dropout = getattr(args, "attention_dropout", args.dropout) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) + + +def base_s2st_transformer_encoder_architecture(args): + args.encoder_freezing_updates = getattr(args, "encoder_freezing_updates", 0) + + # Convolutional subsampler + args.conv_kernel_sizes = getattr(args, "conv_kernel_sizes", "5,5") + args.conv_channels = getattr(args, "conv_channels", 1024) + # Transformer + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_layers = getattr(args, "encoder_layers", 12) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 8) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", args.dropout) + args.activation_dropout = getattr(args, "activation_dropout", args.dropout) + args.activation_fn = getattr(args, "activation_fn", "relu") + + args.speaker_embed_dim = getattr(args, "speaker_embed_dim", 256) + + +@register_model_architecture( + model_name="s2ut_transformer", arch_name="s2ut_transformer" +) +def s2ut_architecture_base(args): + base_s2st_transformer_encoder_architecture(args) + + # decoder + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim + ) + args.decoder_layers = getattr(args, "decoder_layers", 6) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + args.adaptive_input = getattr(args, "adaptive_input", False) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + + +@register_model_architecture("s2ut_transformer", "s2ut_transformer_fisher") +def s2ut_architecture_fisher(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + + s2ut_architecture_base(args) + + +@register_model_architecture( + model_name="s2spect_transformer", arch_name="s2spect_transformer" +) +def s2spect_architecture_base(args): + base_s2st_transformer_encoder_architecture(args) + + # decoder + args.output_frame_dim = getattr(args, "output_frame_dim", 80) + # decoder prenet + args.prenet_dropout = getattr(args, "prenet_dropout", 0.5) + args.prenet_layers = getattr(args, "prenet_layers", 2) + args.prenet_dim = getattr(args, "prenet_dim", 256) + # decoder postnet + args.postnet_dropout = getattr(args, "postnet_dropout", 0.5) + args.postnet_layers = getattr(args, "postnet_layers", 5) + args.postnet_conv_dim = getattr(args, "postnet_conv_dim", 512) + args.postnet_conv_kernel_size = getattr(args, "postnet_conv_kernel_size", 5) + # decoder transformer layers + args.decoder_transformer_layers = getattr(args, "decoder_transformer_layers", 6) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", 4 * args.decoder_embed_dim + ) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) + + +@register_model_architecture("s2spect_transformer", "s2spect_transformer_fisher") +def s2spect_architecture_fisher(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 256 * 8) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + + # decoder + args.prenet_dim = getattr(args, "prenet_dim", 32) + + s2spect_architecture_base(args) diff --git a/fairseq/models/text_to_speech/codehifigan.py b/fairseq/models/text_to_speech/codehifigan.py new file mode 100644 index 0000000000..ee4bb7d6f2 --- /dev/null +++ b/fairseq/models/text_to_speech/codehifigan.py @@ -0,0 +1,77 @@ +from argparse import Namespace +import torch +import torch.nn as nn + +from fairseq.models.text_to_speech.fastspeech2 import VariancePredictor +from fairseq.models.text_to_speech.hifigan import Generator + + +class CodeGenerator(Generator): + def __init__(self, cfg): + super().__init__(cfg) + self.dict = nn.Embedding(cfg["num_embeddings"], cfg["embedding_dim"]) + self.multispkr = cfg.get("multispkr", None) + self.embedder = cfg.get("embedder_params", None) + + if self.multispkr and not self.embedder: + self.spkr = nn.Embedding(cfg.get("num_speakers", 200), cfg["embedding_dim"]) + elif self.embedder: + self.spkr = nn.Linear(cfg.get("embedder_dim", 256), cfg["embedding_dim"]) + + self.dur_predictor = None + if cfg.get("dur_predictor_params", None): + self.dur_predictor = VariancePredictor( + Namespace(**cfg["dur_predictor_params"]) + ) + + @staticmethod + def _upsample(signal, max_frames): + if signal.dim() == 3: + bsz, channels, cond_length = signal.size() + elif signal.dim() == 2: + signal = signal.unsqueeze(2) + bsz, channels, cond_length = signal.size() + else: + signal = signal.view(-1, 1, 1) + bsz, channels, cond_length = signal.size() + + signal = signal.unsqueeze(3).repeat(1, 1, 1, max_frames // cond_length) + + # pad zeros as needed (if signal's shape does not divide completely with max_frames) + reminder = (max_frames - signal.shape[2] * signal.shape[3]) // signal.shape[3] + if reminder > 0: + raise NotImplementedError( + "Padding condition signal - misalignment between condition features." + ) + + signal = signal.view(bsz, channels, max_frames) + return signal + + def forward(self, **kwargs): + x = self.dict(kwargs["code"]).transpose(1, 2) + + if self.dur_predictor and kwargs.get("dur_prediction", False): + assert x.size(0) == 1, "only support single sample" + log_dur_pred = self.dur_predictor(x.transpose(1, 2)) + dur_out = torch.clamp( + torch.round((torch.exp(log_dur_pred) - 1)).long(), min=1 + ) + # B x C x T + x = torch.repeat_interleave(x, dur_out.view(-1), dim=2) + + if self.multispkr: + assert ( + "spkr" in kwargs + ), 'require "spkr" input for multispeaker CodeHiFiGAN vocoder' + spkr = self.spkr(kwargs["spkr"]).transpose(1, 2) + spkr = self._upsample(spkr, x.shape[-1]) + x = torch.cat([x, spkr], dim=1) + + for k, feat in kwargs.items(): + if k in ["spkr", "code", "dur_prediction"]: + continue + + feat = self._upsample(feat, x.shape[-1]) + x = torch.cat([x, feat], dim=1) + + return super().forward(x) diff --git a/fairseq/models/text_to_speech/hifigan.py b/fairseq/models/text_to_speech/hifigan.py index e30fe77f11..a777af5167 100644 --- a/fairseq/models/text_to_speech/hifigan.py +++ b/fairseq/models/text_to_speech/hifigan.py @@ -114,7 +114,13 @@ def __init__(self, cfg): self.num_kernels = len(cfg["resblock_kernel_sizes"]) self.num_upsamples = len(cfg["upsample_rates"]) self.conv_pre = weight_norm( - Conv1d(80, cfg["upsample_initial_channel"], 7, 1, padding=3) + Conv1d( + cfg.get("model_in_dim", 80), + cfg["upsample_initial_channel"], + 7, + 1, + padding=3, + ) ) self.ups = nn.ModuleList() diff --git a/fairseq/models/text_to_speech/tts_transformer.py b/fairseq/models/text_to_speech/tts_transformer.py index 32bdd3747a..22208d2d0b 100644 --- a/fairseq/models/text_to_speech/tts_transformer.py +++ b/fairseq/models/text_to_speech/tts_transformer.py @@ -131,12 +131,12 @@ def decoder_init(m): class TTSTransformerDecoder(FairseqIncrementalDecoder): - def __init__(self, args, src_dict): + def __init__(self, args, src_dict, padding_idx=1): super().__init__(None) self._future_mask = torch.empty(0) self.args = args - self.padding_idx = src_dict.pad() + self.padding_idx = src_dict.pad() if src_dict else padding_idx self.n_frames_per_step = args.n_frames_per_step self.out_dim = args.output_frame_dim * args.n_frames_per_step @@ -275,7 +275,15 @@ def forward( bsz, seq_len, _ = x.size() eos_out = self.eos_proj(x) post_feat_out = feat_out + self.postnet(feat_out) - return post_feat_out, eos_out, {"attn": attn, "feature_out": feat_out} + return ( + post_feat_out, + eos_out, + { + "attn": attn, + "feature_out": feat_out, + "inner_states": extra["inner_states"], + }, + ) def get_normalized_probs(self, net_output, log_probs, sample): logits = self.ctc_proj(net_output[2]["feature_out"]) diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index af3042eeea..abe2c1d840 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -19,6 +19,7 @@ TTSSpectrogram, ) from fairseq.data.audio.speech_to_text_dataset import S2TDataConfig +from fairseq.models.text_to_speech.codehifigan import CodeGenerator as CodeHiFiGANModel from fairseq.models.text_to_speech.hifigan import Generator as HiFiGANModel logger = logging.getLogger(__name__) @@ -210,10 +211,42 @@ def from_data_cfg(cls, args, data_cfg: S2TDataConfig): return cls(vocoder_cfg["checkpoint"], model_cfg, fp16=args.fp16) +class CodeHiFiGANVocoder(nn.Module): + def __init__( + self, checkpoint_path: str, model_cfg: Dict[str, str], fp16: bool = False + ) -> None: + super().__init__() + self.model = CodeHiFiGANModel(model_cfg) + state_dict = torch.load(checkpoint_path) + self.model.load_state_dict(state_dict["generator"]) + self.model.eval() + if fp16: + self.model.half() + self.model.remove_weight_norm() + logger.info(f"loaded CodeHiFiGAN checkpoint from {checkpoint_path}") + + def forward(self, x: Dict[str, torch.Tensor], dur_prediction=False) -> torch.Tensor: + assert "code" in x + x["dur_prediction"] = dur_prediction + mask = x["code"] >= 0 # remove invalid code + x["code"] = x["code"][mask].unsqueeze(dim=0) + + return self.model(**x).detach().squeeze() + + @classmethod + def from_data_cfg(cls, args, data_cfg): + vocoder_cfg = data_cfg.vocoder + with open(vocoder_cfg["config"]) as f: + model_cfg = json.load(f) + return cls(vocoder_cfg["checkpoint"], model_cfg, fp16=args.fp16) + + def get_vocoder(args, data_cfg: S2TDataConfig): if args.vocoder == "griffin_lim": return GriffinLimVocoder.from_data_cfg(args, data_cfg) elif args.vocoder == "hifigan": return HiFiGANVocoder.from_data_cfg(args, data_cfg) + elif args.vocoder == "code_hifigan": + return CodeHiFiGANVocoder.from_data_cfg(args, data_cfg) else: raise ValueError("Unknown vocoder") diff --git a/fairseq/speech_generator.py b/fairseq/speech_generator.py index d75338ecd5..90ec914e60 100644 --- a/fairseq/speech_generator.py +++ b/fairseq/speech_generator.py @@ -52,7 +52,7 @@ def generate(self, model, sample, has_targ=False, **kwargs): src_tokens = sample["net_input"]["src_tokens"] src_lengths = sample["net_input"]["src_lengths"] - bsz, src_len = src_tokens.size() + bsz, src_len = src_tokens.size()[:2] n_frames_per_step = model.decoder.n_frames_per_step out_dim = model.decoder.out_dim raw_dim = out_dim // n_frames_per_step diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py new file mode 100644 index 0000000000..fff8332034 --- /dev/null +++ b/fairseq/tasks/speech_to_speech.py @@ -0,0 +1,472 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from argparse import Namespace +import json +import logging +import math +from pathlib import Path +import torch +import torch.nn as nn + +from fairseq import utils +from fairseq.data import Dictionary +from fairseq.data.audio.data_cfg import S2SDataConfig, MultitaskConfig +from fairseq.data.audio.speech_to_speech_dataset import SpeechToSpeechDatasetCreator +from fairseq.tasks import LegacyFairseqTask, register_task +from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion + + +logger = logging.getLogger(__name__) + + +class StackUnitSequenceGenerator(nn.Module): + def __init__(self, tgt_dict, vocab_size): + super().__init__() + self.pad = tgt_dict.pad() + self.eos = tgt_dict.eos() + self.unk = tgt_dict.unk() + self.offset = len(tgt_dict) - vocab_size + self.vocab_size = vocab_size + + def pack_units(self, input: torch.Tensor, n_frames_per_step) -> torch.Tensor: + if n_frames_per_step <= 1: + return input + + bsz, _, n = input.shape + assert n == n_frames_per_step + + scale = [ + pow(self.vocab_size, n_frames_per_step - 1 - i) + for i in range(n_frames_per_step) + ] + scale = torch.LongTensor(scale).squeeze(0).to(input.device) + mask = input >= self.offset + res = ((input - self.offset) * scale * mask).sum(dim=2) + self.offset + return res + + @torch.no_grad() + def generate(self, models, sample, **kwargs): + # currently only support viterbi search for stacked units + model = models[0] + model.eval() + + max_len = model.max_decoder_positions() + # TODO: incorporate max_len_a and max_len_b + + src_tokens = sample["net_input"]["src_tokens"] + src_lengths = sample["net_input"]["src_lengths"] + bsz, src_len, _ = src_tokens.size() + n_frames_per_step = model.decoder.n_frames_per_step + + # initialize + encoder_out = model.forward_encoder( + src_tokens, src_lengths, speaker=sample["speaker"] + ) + incremental_state = {} + pred_out, attn, scores = [], [], [] + finished = src_tokens.new_zeros((bsz,)).bool() + + prev_output_tokens = src_lengths.new_zeros((bsz, 1)).long().fill_(self.eos) + for _ in range(max_len): + cur_out, cur_extra = model.forward_decoder( + prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + ) + + lprobs = model.get_normalized_probs([cur_out], log_probs=True) + # never select pad, unk + lprobs[:, :, self.pad] = -math.inf + lprobs[:, :, self.unk] = -math.inf + + cur_pred_lprob, cur_pred_out = torch.max(lprobs, dim=2) + scores.append(cur_pred_lprob) + pred_out.append(cur_pred_out) + + prev_output_tokens = torch.cat( + ( + prev_output_tokens, + self.pack_units( + cur_pred_out.view(bsz, 1, n_frames_per_step), n_frames_per_step + ), + ), + dim=1, + ) + + attn.append(cur_extra["attn"][0]) + + cur_finished = torch.any(cur_pred_out.squeeze(1) == self.eos, dim=1) + finished = finished | cur_finished + if finished.sum().item() == bsz: + break + + pred_out = torch.cat(pred_out, dim=1).view(bsz, -1) + attn = torch.cat(attn, dim=2) + alignment = attn.max(dim=1)[1] + attn = attn.repeat_interleave(n_frames_per_step, dim=2) + alignment = alignment.repeat_interleave(n_frames_per_step, dim=1) + scores = torch.cat(scores, dim=1) + eos_idx = (pred_out == self.eos).nonzero(as_tuple=True) + out_lens = src_lengths.new_zeros((bsz,)).long().fill_(max_len) + for b, l in zip(eos_idx[0], eos_idx[1]): + out_lens[b] = min(l, out_lens[b]) + + hypos = [ + [ + { + "tokens": pred_out[b, :out_len], + "attn": attn[b, :, :out_len], + "alignment": alignment[b, :out_len], + "positional_scores": scores[b, :out_len], + "score": utils.item(scores[b, :out_len].sum().data), + } + ] + for b, out_len in zip(range(bsz), out_lens) + ] + + return hypos + + +@register_task("speech_to_speech") +class SpeechToSpeechTask(LegacyFairseqTask): + @classmethod + def add_args(cls, parser): + parser.add_argument("data", help="manifest root path") + parser.add_argument( + "--config-yaml", + type=str, + default="config.yaml", + help="Configuration YAML filename (under manifest root)", + ) + parser.add_argument( + "--max-source-positions", + default=6000, + type=int, + metavar="N", + help="max number of tokens in the source sequence", + ) + parser.add_argument( + "--max-target-positions", + default=1024, + type=int, + metavar="N", + help="max number of tokens in the target sequence", + ) + parser.add_argument( + "--target-is-code", + action="store_true", + help="set if target is discrete unit instead of spectrogram", + ) + parser.add_argument( + "--target-code-size", type=int, default=None, help="# discrete units" + ) + parser.add_argument( + "--n-frames-per-step", + type=int, + default=1, + help="# stacked frames, use 0 for reduced discrete unit sequence", + ) + parser.add_argument( + "--multitask-config-yaml", + type=str, + default=None, + help="Configuration YAML filename for the multitasks (under manifest root)", + ) + parser.add_argument("--eval-inference", action="store_true") + parser.add_argument( + "--eval-args", + type=str, + default="{}", + help='generation args for speech-to-unit model , e.g., \'{"beam": 5, "max_len_a": 1}\', as JSON string', + ) + parser.add_argument("--eos-prob-threshold", type=float, default=0.5) + parser.add_argument( + "--mcd-normalize-type", + type=str, + default="targ", + choices=["targ", "pred", "path"], + ) + parser.add_argument( + "--vocoder", + type=str, + default="griffin_lim", + choices=["griffin_lim", "hifigan", "code_hifigan"], + ) + parser.add_argument("--spec-bwd-max-iter", type=int, default=8) + + def __init__(self, args, tgt_dict): + super().__init__(args) + self.tgt_dict = tgt_dict + self.data_cfg = S2SDataConfig(Path(args.data) / args.config_yaml) + self.multitask_tasks = {} + if args.multitask_config_yaml: + multitask_cfg = MultitaskConfig( + Path(args.data) / args.multitask_config_yaml + ) + for task_name, task_config in multitask_cfg.get_all_tasks().items(): + self.multitask_tasks[task_name] = DummyMultiTask( + task_config, task_config.tgt_dict + ) + + @classmethod + def setup_task(cls, args, **kwargs): + tgt_dict = None + if args.target_is_code: + assert args.target_code_size is not None + + tgt_dict = Dictionary() + for i in range(args.target_code_size): + tgt_dict.add_symbol(str(i)) + logger.info(f"dictionary size: " f"{len(tgt_dict):,}") + + if getattr(args, "train_subset", None) is not None: + if not all(s.startswith("train") for s in args.train_subset.split(",")): + raise ValueError('Train splits should be named like "train*".') + + assert args.n_frames_per_step >= 1 + assert ( + not args.eval_inference + or (args.target_is_code and args.vocoder == "code_hifigan") + or (not args.target_is_code and args.vocoder != "code_hifigan") + ) + + return cls(args, tgt_dict) + + def build_criterion(self, args): + from fairseq import criterions + + if len(self.multitask_tasks) > 0: + if self.args.target_is_code and args._name != "speech_to_unit": + raise ValueError( + "set --criterion speech_to_unit for speech-to-unit loss with multitask" + ) + elif not self.args.target_is_code and args._name != "speech_to_spectrogram": + raise ValueError( + "set --criterion speech_to_spectrogram for speech-to-spectrogram loss with multitask" + ) + + return criterions.build_criterion(args, self) + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + self.datasets[split] = SpeechToSpeechDatasetCreator.from_tsv( + self.args.data, + self.data_cfg, + split, + is_train_split=split.startswith("train"), + epoch=epoch, + seed=self.args.seed, + target_is_code=self.args.target_is_code, + target_dictionary=self.target_dictionary, + n_frames_per_step=self.args.n_frames_per_step, + multitask=self.multitask_tasks, + ) + + @property + def target_dictionary(self): + return self.tgt_dict + + @property + def source_dictionary(self): + return None + + def max_positions(self): + return self.args.max_source_positions, self.args.max_target_positions + + def build_model(self, args): + args.input_feat_per_channel = self.data_cfg.input_feat_per_channel + args.input_channels = self.data_cfg.input_transformed_channels + args.target_speaker_embed = self.data_cfg.target_speaker_embed is not None + args.n_frames_per_step = self.args.n_frames_per_step + + model = super().build_model(args) + + if len(self.multitask_tasks) > 0: + from fairseq.models.speech_to_speech.s2s_transformer import ( + S2STransformerMultitaskModelBase, + ) + + assert isinstance(model, S2STransformerMultitaskModelBase) + + if self.args.eval_inference: + self.eval_gen_args = json.loads(self.args.eval_args) + self.generator = self.build_generator( + [model], Namespace(**self.eval_gen_args) + ) + + return model + + def build_generator( + self, + models, + args, + seq_gen_cls=None, + extra_gen_cls_kwargs=None, + ): + + if not self.args.target_is_code or self.args.eval_inference: + from fairseq.models.text_to_speech.vocoder import get_vocoder + + self.vocoder = get_vocoder(self.args, self.data_cfg) + self.vocoder = ( + self.vocoder.cuda() + if torch.cuda.is_available() and not self.args.cpu + else self.vocoder.cpu() + ) + + if self.args.target_is_code: + if self.args.n_frames_per_step == 1: + seq_generator = super().build_generator( + models, + args, + seq_gen_cls=None, + extra_gen_cls_kwargs=extra_gen_cls_kwargs, + ) + else: + assert ( + getattr(args, "beam", 1) == 1 and getattr(args, "nbest", 1) == 1 + ), "only support viterbi search for stacked units" + seq_generator = StackUnitSequenceGenerator( + self.tgt_dict, + self.args.target_code_size, + ) + else: + if getattr(args, "teacher_forcing", False): + from fairseq.speech_generator import ( + TeacherForcingAutoRegressiveSpeechGenerator, + ) + + generator = TeacherForcingAutoRegressiveSpeechGenerator + logger.info("Teacher forcing mode for generation") + else: + from fairseq.speech_generator import AutoRegressiveSpeechGenerator + + generator = AutoRegressiveSpeechGenerator + seq_generator = generator( + models[0], + self.vocoder, + self.data_cfg, + max_iter=self.args.max_target_positions, + eos_prob_threshold=self.args.eos_prob_threshold, + ) + + return seq_generator + + def train_step( + self, sample, model, criterion, optimizer, update_num, ignore_grad=False + ): + for task_name, task_obj in self.multitask_tasks.items(): + criterion.set_multitask_loss_weight( + task_name, task_obj.args.get_loss_weight(update_num) + ) + + loss, sample_size, logging_output = super().train_step( + sample, model, criterion, optimizer, update_num, ignore_grad + ) + return loss, sample_size, logging_output + + def valid_step(self, sample, model, criterion): + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + + if self.args.eval_inference: + hypos, inference_losses = self.valid_step_with_inference( + sample, model, self.generator + ) + for k, v in inference_losses.items(): + assert k not in logging_output + logging_output[k] = v + + return loss, sample_size, logging_output + + def valid_step_with_inference(self, sample, model, generator): + if self.args.target_is_code: + hypos = generator.generate([model], sample) + tgt_lens = ( + sample["target_lengths"] - 1 + ) * self.args.n_frames_per_step # strip <eos> + for b, (f, l) in enumerate(zip(sample["target"], tgt_lens)): + hypos[b][0]["targ_waveform"] = self.vocoder( + {"code": f[:l] - 4}, # remove <bos>, <pad>, <eos>, <unk> + dur_prediction=self.eval_gen_args.get("dur_prediction", False), + ) + if len(hypos[b][0]["tokens"]) > 0: + hypos[b][0]["waveform"] = self.vocoder( + {"code": hypos[b][0]["tokens"] - 4}, + dur_prediction=self.eval_gen_args.get("dur_prediction", False), + ) + else: + hypos[b][0]["waveform"] = torch.flip( + hypos[b][0]["targ_waveform"], dims=[0] + ) + else: + hypos = [ + [hypo] for hypo in generator.generate(model, sample, has_targ=True) + ] + + losses = { + "mcd_loss": 0.0, + "targ_frames": 0.0, + "pred_frames": 0.0, + "path_frames": 0.0, + "nins": 0.0, + "ndel": 0.0, + } + rets = batch_mel_cepstral_distortion( + [hypo[0]["targ_waveform"] for hypo in hypos], + [hypo[0]["waveform"] for hypo in hypos], + self.data_cfg.output_sample_rate, + normalize_type=None, + ) + for d, extra in rets: + pathmap = extra[-1] + losses["mcd_loss"] += d.item() + losses["targ_frames"] += pathmap.size(0) + losses["pred_frames"] += pathmap.size(1) + losses["path_frames"] += pathmap.sum().item() + losses["nins"] += (pathmap.sum(dim=1) - 1).sum().item() + losses["ndel"] += (pathmap.sum(dim=0) - 1).sum().item() + losses["norm_frames"] = losses[ + f"{getattr(self.args, 'mcd_normalize_type', 'targ')}_frames" + ] + + return hypos, losses + + +class DummyMultiTask(LegacyFairseqTask): + def __init__(self, args, tgt_dict): + super().__init__(args) + self.tgt_dict = tgt_dict + + @property + def target_dictionary(self): + return self.tgt_dict + + def inference_step( + self, generator, models, sample, prefix_tokens=None, constraints=None + ): + if self.args.decoder_type == "ctc": + model = models[0] # only support single model + encoder_out = model(**sample) + if hasattr(model, "get_logits"): + emissions = model.get_logits( + encoder_out + ) # no need to normalize emissions + else: + emissions = model.get_normalized_probs(encoder_out, log_probs=True) + return generator.decode( + emissions.transpose(0, 1).float().cpu().contiguous() + ) + else: + raise NotImplementedError("only ctc decoder is supported at the moment") + + def build_generator( + self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None + ): + if self.args.decoder_type == "ctc": + from examples.speech_recognition.w2l_decoder import W2lViterbiDecoder + + return W2lViterbiDecoder(args, self.tgt_dict) + else: + raise NotImplementedError("only ctc decoder is supported at the moment") From 7b0159a20257dc748af41e4ecada67c8639d6630 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Wed, 15 Dec 2021 16:14:14 -0800 Subject: [PATCH 518/774] add integration test for fastspeech2 Summary: Adding integration test (based on test set scores on pre-trained checkpoints) for fastspeech2 Reviewed By: yuntang Differential Revision: D33143301 fbshipit-source-id: dca0841b43dd1cb2933ce5c652ed3cdff0fc4a52 --- tests/speech/test_fastspeech2.py | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/speech/test_fastspeech2.py diff --git a/tests/speech/test_fastspeech2.py b/tests/speech/test_fastspeech2.py new file mode 100644 index 0000000000..a4f074e5a3 --- /dev/null +++ b/tests/speech/test_fastspeech2.py @@ -0,0 +1,67 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import torch +from tqdm import tqdm + +from fairseq.checkpoint_utils import load_model_ensemble_and_task +from fairseq import utils +from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion +from tests.speech import TestFairseqSpeech + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestFastSpeech2(TestFairseqSpeech): + def setUp(self): + self.set_up_ljspeech() + + @torch.no_grad() + def test_ljspeech_fastspeech2_checkpoint(self): + checkpoint_filename = "ljspeech_fastspeech2_g2p.pt" + path = self.download(self.base_url, self.root, checkpoint_filename) + + models, cfg, task = load_model_ensemble_and_task( + [path.as_posix()], arg_overrides={ + "data": self.root.as_posix(), + "config_yaml": "cfg_ljspeech_g2p.yaml", + "vocoder": "griffin_lim", + "fp16": False + } + ) + if self.use_cuda: + for model in models: + model.cuda() + + test_split = "ljspeech_test" + task.load_dataset(test_split) + batch_iterator = task.get_batch_iterator( + dataset=task.dataset(test_split), + max_tokens=65_536, max_positions=4_096, num_workers=1 + ).next_epoch_itr(shuffle=False) + progress = tqdm(batch_iterator, total=len(batch_iterator)) + generator = task.build_generator(models, cfg) + + mcd, n_samples = 0., 0 + for sample in progress: + sample = utils.move_to_cuda(sample) if self.use_cuda else sample + hypos = generator.generate(models[0], sample, has_targ=True) + rets = batch_mel_cepstral_distortion( + [hypo["targ_waveform"] for hypo in hypos], + [hypo["waveform"] for hypo in hypos], + sr=task.sr + ) + mcd += sum(d.item() for d, _ in rets) + n_samples += len(sample["id"].tolist()) + + mcd = round(mcd / n_samples, 1) + reference_mcd = 3.2 + print(f"MCD: {mcd} (reference: {reference_mcd})") + self.assertAlmostEqual(mcd, reference_mcd, delta=0.1) + + +if __name__ == "__main__": + unittest.main() From c6912434b3059bd68e84d46e3e09d1c1491f02eb Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Thu, 16 Dec 2021 10:01:48 -0800 Subject: [PATCH 519/774] Merge STPT: Step 1 Summary: Update modified fairseq code; 1) add option to skip eos token in the target (ctc doesn't need eos in the target) 2) add option to add source tag as eos in the source sequence 3) add alignment support Reviewed By: kahne Differential Revision: D33081337 fbshipit-source-id: 1ea53dae45087ee0e5a6d35e0cabd5d022cf59a3 --- .../tasks/speech_text_joint.py | 1 + fairseq/data/audio/speech_to_text_dataset.py | 4 +- .../audio/speech_to_text_joint_dataset.py | 75 ++++++++++++++++++- fairseq/data/iterators.py | 2 + 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/examples/speech_text_joint_to_text/tasks/speech_text_joint.py b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py index cd9aabd583..bb04f14f13 100644 --- a/examples/speech_text_joint_to_text/tasks/speech_text_joint.py +++ b/examples/speech_text_joint_to_text/tasks/speech_text_joint.py @@ -371,6 +371,7 @@ def get_batch_iterator( epoch=epoch, mult_rate=1 if self.args.update_mix_data else max(self.args.update_freq), buffer_size=data_buffer_size, + skip_remainder_batch=skip_remainder_batch, ) self.dataset_to_epoch_iter[dataset] = {} # refresh it every epoch return epoch_iter diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index f04d273574..7bcc88b6bb 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -152,6 +152,7 @@ def __init__( bpe_tokenizer=None, n_frames_per_step=1, speaker_to_id=None, + append_eos=True, ): self.split, self.is_train_split = split, is_train_split self.cfg = cfg @@ -185,6 +186,7 @@ def __init__( self.speaker_to_id = speaker_to_id self.tgt_lens = self.get_tgt_lens_and_check_oov() + self.append_eos = append_eos logger.info(self.__repr__()) @@ -270,7 +272,7 @@ def __getitem__(self, index: int) -> SpeechToTextDatasetItem: if self.tgt_texts is not None: tokenized = self.get_tokenized_tgt_text(index) target = self.tgt_dict.encode_line( - tokenized, add_if_not_exist=False, append_eos=True + tokenized, add_if_not_exist=False, append_eos=self.append_eos ).long() if self.cfg.prepend_tgt_lang_tag: lang_tag_idx = self.get_lang_tag_idx( diff --git a/fairseq/data/audio/speech_to_text_joint_dataset.py b/fairseq/data/audio/speech_to_text_joint_dataset.py index 885ee7e0a3..505ee81f3b 100644 --- a/fairseq/data/audio/speech_to_text_joint_dataset.py +++ b/fairseq/data/audio/speech_to_text_joint_dataset.py @@ -55,6 +55,12 @@ def prepend_tgt_lang_tag_no_change(self) -> bool: """ return self.config.get("prepend_tgt_lang_tag_no_change", False) + @property + def sampling_text_alpha(self): + """Hyper-parameter alpha = 1/T for temperature-based resampling. (text + input only) (alpha = 1 for no resampling)""" + return self.config.get("sampling_text_alpha", 1.0) + class SpeechToTextJointDatasetItem(NamedTuple): index: int @@ -62,8 +68,13 @@ class SpeechToTextJointDatasetItem(NamedTuple): target: Optional[torch.Tensor] = None src_txt_tokens: Optional[torch.Tensor] = None tgt_lang_tag: Optional[int] = None + src_lang_tag: Optional[int] = None + tgt_alignment: Optional[torch.Tensor] = None +# use_src_lang_id: +# 0: don't use src_lang_id +# 1: attach src_lang_id to the src_txt_tokens as eos class SpeechToTextJointDataset(SpeechToTextDataset): def __init__( self, @@ -84,6 +95,9 @@ def __init__( bpe_tokenizer=None, src_pre_tokenizer=None, src_bpe_tokenizer=None, + append_eos: Optional[bool] = True, + alignment: Optional[List[str]] = None, + use_src_lang_id: Optional[int] = 0, ): super().__init__( split, @@ -100,11 +114,18 @@ def __init__( tgt_dict=tgt_dict, pre_tokenizer=pre_tokenizer, bpe_tokenizer=bpe_tokenizer, + append_eos=append_eos, ) self.src_dict = src_dict self.src_pre_tokenizer = src_pre_tokenizer self.src_bpe_tokenizer = src_bpe_tokenizer + self.alignment = None + self.use_src_lang_id = use_src_lang_id + if alignment is not None: + self.alignment = [ + [float(s) for s in sample.split()] for sample in alignment + ] def get_tokenized_src_text(self, index: int): text = self.tokenize(self.src_pre_tokenizer, self.src_texts[index]) @@ -114,15 +135,23 @@ def get_tokenized_src_text(self, index: int): def __getitem__(self, index: int) -> SpeechToTextJointDatasetItem: s2t_dataset_item = super().__getitem__(index) src_tokens = None + src_lang_tag = None if self.src_texts is not None and self.src_dict is not None: src_tokens = self.get_tokenized_src_text(index) src_tokens = self.src_dict.encode_line( src_tokens, add_if_not_exist=False, append_eos=True ).long() + if self.use_src_lang_id > 0: + src_lang_tag = self.get_lang_tag_idx( + self.src_langs[index], self.src_dict + ) tgt_lang_tag = None if self.cfg.prepend_tgt_lang_tag_no_change: # prepend_tgt_lang_tag_no_change: modify prev_output_tokens instead tgt_lang_tag = self.get_lang_tag_idx(self.tgt_langs[index], self.tgt_dict) + ali = None + if self.alignment is not None: + ali = torch.Tensor(self.alignment[index]).float() return SpeechToTextJointDatasetItem( index=index, @@ -130,6 +159,8 @@ def __getitem__(self, index: int) -> SpeechToTextJointDatasetItem: target=s2t_dataset_item.target, src_txt_tokens=src_tokens, tgt_lang_tag=tgt_lang_tag, + src_lang_tag=src_lang_tag, + tgt_alignment=ali, ) def __len__(self): @@ -149,13 +180,35 @@ def collater(self, samples: List[SpeechToTextJointDatasetItem]) -> Dict: left_pad=False, move_eos_to_beginning=False, ) - src_txt_tokens = src_txt_tokens.index_select(0, order) src_txt_lengths = torch.tensor( [x.src_txt_tokens.size()[0] for x in samples], dtype=torch.long - ).index_select(0, order) + ) + if self.use_src_lang_id > 0: + src_lang_idxs = torch.tensor( + [s.src_lang_tag for s in samples], dtype=src_txt_tokens.dtype + ) + if self.use_src_lang_id == 1: # replace eos with lang_id + eos_idx = src_txt_lengths - 1 + src_txt_tokens.scatter_( + 1, eos_idx.view(-1, 1), src_lang_idxs.view(-1, 1) + ) + else: + raise NotImplementedError("Implementation is required") + + src_txt_tokens = src_txt_tokens.index_select(0, order) + src_txt_lengths = src_txt_lengths.index_select(0, order) net_input["src_txt_tokens"] = src_txt_tokens net_input["src_txt_lengths"] = src_txt_lengths + net_input["alignment"] = None + if self.alignment is not None: + max_len = max([s.tgt_alignment.size(0) for s in samples]) + alignment = torch.ones(len(samples), max_len).float() + for i, s in enumerate(samples): + cur_len = s.tgt_alignment.size(0) + alignment[i][:cur_len].copy_(s.tgt_alignment) + net_input["alignment"] = alignment.index_select(0, order) + if self.tgt_texts is not None and samples[0].tgt_lang_tag is not None: for i in range(len(samples)): net_input["prev_output_tokens"][i][0] = samples[order[i]].tgt_lang_tag @@ -172,6 +225,8 @@ def collater(self, samples: List[SpeechToTextJointDatasetItem]) -> Dict: class SpeechToTextJointDatasetCreator(SpeechToTextDatasetCreator): + KEY_ALIGN = "align" + @classmethod def _from_list( cls, @@ -185,6 +240,8 @@ def _from_list( bpe_tokenizer, src_pre_tokenizer, src_bpe_tokenizer, + append_eos, + use_src_lang_id, ) -> SpeechToTextJointDataset: audio_root = Path(cfg.audio_root) ids = [s[cls.KEY_ID] for s in samples] @@ -195,6 +252,9 @@ def _from_list( speakers = [s.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for s in samples] src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] + tgt_alignment = None + if cls.KEY_ALIGN in samples[0].keys(): + tgt_alignment = [s[cls.KEY_ALIGN] for s in samples] return SpeechToTextJointDataset( split_name, is_train_split, @@ -213,6 +273,9 @@ def _from_list( bpe_tokenizer=bpe_tokenizer, src_pre_tokenizer=src_pre_tokenizer, src_bpe_tokenizer=src_bpe_tokenizer, + append_eos=append_eos, + alignment=tgt_alignment, + use_src_lang_id=use_src_lang_id, ) @classmethod @@ -228,6 +291,8 @@ def _from_tsv( bpe_tokenizer, src_pre_tokenizer, src_bpe_tokenizer, + append_eos: bool, + use_src_lang_id: int, ) -> SpeechToTextJointDataset: samples = cls._load_samples_from_tsv(root, split) return cls._from_list( @@ -241,6 +306,8 @@ def _from_tsv( bpe_tokenizer, src_pre_tokenizer, src_bpe_tokenizer, + append_eos, + use_src_lang_id, ) @classmethod @@ -258,6 +325,8 @@ def from_tsv( is_train_split: bool, epoch: int, seed: int, + append_eos: Optional[bool] = True, + use_src_lang_id: Optional[int] = 0, ) -> SpeechToTextJointDataset: datasets = [ cls._from_tsv( @@ -271,6 +340,8 @@ def from_tsv( bpe_tokenizer, src_pre_tokenizer, src_bpe_tokenizer, + append_eos=append_eos, + use_src_lang_id=use_src_lang_id, ) for split in splits.split(",") ] diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index e16d91ef72..1d8e179f8b 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -719,6 +719,7 @@ def __init__( epoch=0, mult_rate=1, buffer_size=0, + skip_remainder_batch=False, ): super().__init__( dataset, @@ -730,6 +731,7 @@ def __init__( num_workers, epoch, buffer_size, + skip_remainder_batch=skip_remainder_batch, ) # level 0: sub-samplers 1: batch_idx 2: batches self._frozen_batches = tuple([tuple(sub_batch) for sub_batch in batch_samplers]) From 86f20c7762a32f2ed7ac8c2deefb3b690adbd54b Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Thu, 16 Dec 2021 10:01:48 -0800 Subject: [PATCH 520/774] Merge STPT: Step 2 Summary: Add data class TransformEosConcatLangPairDataset Reviewed By: kahne Differential Revision: D33084736 fbshipit-source-id: 851446429920ac89b0b1418a9f42a010a8c42867 --- fairseq/data/__init__.py | 2 + .../transform_eos_concat_langpair_dataset.py | 139 ++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 fairseq/data/transform_eos_concat_langpair_dataset.py diff --git a/fairseq/data/__init__.py b/fairseq/data/__init__.py index 8b7eb2ec4f..8acf2ca173 100644 --- a/fairseq/data/__init__.py +++ b/fairseq/data/__init__.py @@ -57,6 +57,7 @@ from .multilingual.sampled_multi_dataset import SampledMultiDataset from .multilingual.sampled_multi_epoch_dataset import SampledMultiEpochDataset from .fasta_dataset import FastaDataset, EncodedFastaDataset +from .transform_eos_concat_langpair_dataset import TransformEosConcatLangPairDataset from .iterators import ( CountingIterator, @@ -123,6 +124,7 @@ "TokenBlockDataset", "TransformEosDataset", "TransformEosLangPairDataset", + "TransformEosConcatLangPairDataset", "TruncateDataset", "TruncatedDictionary", ] diff --git a/fairseq/data/transform_eos_concat_langpair_dataset.py b/fairseq/data/transform_eos_concat_langpair_dataset.py new file mode 100644 index 0000000000..638bd1a3d7 --- /dev/null +++ b/fairseq/data/transform_eos_concat_langpair_dataset.py @@ -0,0 +1,139 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +import torch +from torch.utils.data.dataloader import default_collate + +from fairseq.data import ConcatDataset + +logger = logging.getLogger(__name__) + + +class TransformEosConcatLangPairDataset(ConcatDataset): + """ + It is a combination of TransformEosLangPairDataset and ConcatDataset for multiple LangPairDataset datasets. + Assume all datasets share the same src_eos, tgt_bos, left_pad_source and left_pad_target + """ + + def __init__( + self, + datasets, + src_eos, + tgt_bos, + new_src_eos=None, + new_tgt_bos=None, + ): + super().__init__(datasets) + if new_src_eos is not None: + assert len(new_src_eos) == len(datasets) + else: + new_src_eos = [] + if new_tgt_bos is not None: + assert len(new_tgt_bos) == len(datasets) + else: + new_tgt_bos = [] + self.src_eos = src_eos + self.tgt_bos = tgt_bos + self.new_src_eos = ( + torch.LongTensor(new_src_eos).cpu() if len(new_src_eos) > 0 else [] + ) + self.new_tgt_bos = ( + torch.LongTensor(new_tgt_bos).cpu() if len(new_tgt_bos) > 0 else [] + ) + self.left_pad_source = self.is_left_pad_source(datasets) + self.left_pad_target = self.is_left_pad_target(datasets) + self.pad_idx = self.src_dict_pad() + + def src_dict_pad(self): + if hasattr(self.datasets[0], "src_dict"): + return self.datasets[0].src_dict.pad() + if hasattr(self.datasets[0], "dataset"): + return self.datasets[0].dataset.src_dict.pad() + raise NotImplementedError("No src_dict is found") + + def __getitem__(self, idx): + dataset_idx, sample_idx = self._get_dataset_and_sample_index(idx) + return dataset_idx, self.datasets[dataset_idx][sample_idx] + + def is_left_pad_source(self, datasets): + def _left_pad_source(ds): + if hasattr(ds, "left_pad_source"): + return ds.left_pad_source + if hasattr(ds, "dataset"): + return _left_pad_source(ds.dataset) + logger.warn(f"{type(ds)} has no left_pad_source, using default True") + return True + + left_pad_source = _left_pad_source(datasets[0]) + for ds in datasets: + if left_pad_source != _left_pad_source(ds): + raise ValueError("Different left_pad_source setting detected!") + return left_pad_source + + def is_left_pad_target(self, datasets): + def _left_pad_target(ds): + if hasattr(ds, "left_pad_target"): + return ds.left_pad_target + if hasattr(ds, "dataset"): + return _left_pad_target(ds.dataset) + logger.warn(f"{type(ds)} has no left_pad_target, using default False") + return False + + left_pad_target = _left_pad_target(datasets[0]) + for ds in datasets: + if left_pad_target != _left_pad_target(ds): + raise ValueError("Different left_pad_target setting detected!") + return left_pad_target + + def collater(self, samples, **extra_args): + if len(samples) == 0: + return samples + + dataset_ids = [s[0] for s in samples] + samples = [s[1] for s in samples] + + if hasattr(self.datasets[0], "collater"): + samples = self.datasets[0].collater(samples, **extra_args) + else: + samples = default_collate(samples, **extra_args) + + if len(self.new_src_eos) > 0: + if self.left_pad_source: + assert ( + samples["net_input"]["src_tokens"][:, -1] != self.src_eos + ).sum() == 0 + samples["net_input"]["src_tokens"][:, -1] = self.new_src_eos[ + dataset_ids + ] + + else: + eos_idx = samples["net_input"]["src_lengths"] - 1 + assert ( + samples["net_input"]["src_tokens"][ + torch.arange(eos_idx.size(0)), eos_idx + ] + != self.src_eos + ).sum() == 0 + samples["net_input"]["src_tokens"].scatter_( + 1, eos_idx.view(-1, 1), self.new_src_eos[dataset_ids].view(-1, 1) + ) + + if len(self.new_tgt_bos) > 0 and "prev_output_tokens" in samples["net_input"]: + if self.left_pad_target: + # TODO: support different padding direction on target side + raise NotImplementedError( + "TransformEosLangPairDataset does not implement --left-pad-target True option" + ) + else: + assert ( + samples["net_input"]["prev_output_tokens"][:, 0] != self.tgt_bos + ).sum() == 0 + samples["net_input"]["prev_output_tokens"][:, 0] = self.new_tgt_bos[ + dataset_ids + ] + + return samples From 1e4055da7d14355821d2d72b40b1e6d463fe4ecd Mon Sep 17 00:00:00 2001 From: Shreyan Bakshi <shreyanb@fb.com> Date: Thu, 16 Dec 2021 12:53:32 -0800 Subject: [PATCH 521/774] Fix Tracing mode TS export for LayerNorm layer Summary: When under TorchScript Tracing (instead of only doing this for Scripting) we set `export=True` for `LayerNorm` as `FusedLayerNorm `doesn't work with JIT yet (see `torch.jit.unused decorator`). Reviewed By: cndn Differential Revision: D33103054 fbshipit-source-id: f8c24a4a30a89dd4c70b19362fd60c51fcb9a1f0 --- fairseq/modules/layer_norm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fairseq/modules/layer_norm.py b/fairseq/modules/layer_norm.py index 78332d1749..8c08c044b7 100644 --- a/fairseq/modules/layer_norm.py +++ b/fairseq/modules/layer_norm.py @@ -21,12 +21,13 @@ def forward(self, x): with torch.cuda.device(x.device): return super().forward(x) + except ImportError: has_fused_layernorm = False def LayerNorm(normalized_shape, eps=1e-5, elementwise_affine=True, export=False): - if torch.jit.is_scripting(): + if torch.jit.is_scripting() or torch.jit.is_tracing(): export = True if not export and torch.cuda.is_available() and has_fused_layernorm: return FusedLayerNorm(normalized_shape, eps, elementwise_affine) From a54021305d6b3c4c5959ac9395135f63202db8f1 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Thu, 16 Dec 2021 16:10:22 -0800 Subject: [PATCH 522/774] formatting fix (#2816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? fix `black` failures ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2816 Reviewed By: alexeib Differential Revision: D33172615 Pulled By: dianaml0 fbshipit-source-id: 36b141f42941670f1bfa981041d878042feb0428 --- fairseq/checkpoint_utils.py | 11 ++++----- fairseq/models/hubert/hubert.py | 10 +++++--- fairseq/modules/layer_norm.py | 1 - tests/speech/__init__.py | 6 ++--- tests/speech/test_fastspeech2.py | 17 +++++++------ tests/speech/test_s2t_transformer.py | 37 +++++++++++++++++++--------- tests/speech/test_tts_transformer.py | 17 +++++++------ tests/test_hf_hub.py | 1 + tests/test_sequence_generator.py | 1 - 9 files changed, 60 insertions(+), 41 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 4f74fb0255..3156d0e27b 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -7,15 +7,18 @@ import collections import contextlib import logging -import numpy as np import os import re import time import traceback from collections import OrderedDict +from pathlib import Path from typing import Any, Dict, Optional, Union +import numpy as np import torch +from omegaconf import DictConfig, OmegaConf, open_dict + from fairseq.data import data_utils from fairseq.dataclass.configs import CheckpointConfig from fairseq.dataclass.utils import ( @@ -25,10 +28,6 @@ from fairseq.distributed.fully_sharded_data_parallel import FSDP, has_FSDP from fairseq.file_io import PathManager from fairseq.models import FairseqDecoder, FairseqEncoder -from omegaconf import DictConfig, open_dict, OmegaConf - -from pathlib import Path - logger = logging.getLogger(__name__) @@ -509,7 +508,7 @@ def load_model_ensemble_and_task_from_hf_hub( _arg_overrides["data"] = cache_dir return load_model_ensemble_and_task( [p.as_posix() for p in Path(cache_dir).glob("*.pt")], - arg_overrides=_arg_overrides + arg_overrides=_arg_overrides, ) diff --git a/fairseq/models/hubert/hubert.py b/fairseq/models/hubert/hubert.py index 21bae4db19..40f35be688 100644 --- a/fairseq/models/hubert/hubert.py +++ b/fairseq/models/hubert/hubert.py @@ -4,13 +4,14 @@ # LICENSE file in the root directory of this source tree. import logging +from dataclasses import dataclass, field from typing import Dict, List, Optional, Tuple import numpy as np - import torch import torch.nn as nn -from dataclasses import dataclass, field +from omegaconf import II + from fairseq import utils from fairseq.data.data_utils import compute_mask_indices from fairseq.data.dictionary import Dictionary @@ -25,7 +26,6 @@ HubertPretrainingConfig, HubertPretrainingTask, ) -from omegaconf import II logger = logging.getLogger(__name__) @@ -205,9 +205,11 @@ class HubertConfig(FairseqDataclass): ) checkpoint_activations: bool = field( - default=False, metadata={"help": "recompute activations and save memory for extra compute"} + default=False, + metadata={"help": "recompute activations and save memory for extra compute"}, ) + @register_model("hubert", dataclass=HubertConfig) class HubertModel(BaseFairseqModel): def __init__( diff --git a/fairseq/modules/layer_norm.py b/fairseq/modules/layer_norm.py index 8c08c044b7..0b276ce02f 100644 --- a/fairseq/modules/layer_norm.py +++ b/fairseq/modules/layer_norm.py @@ -21,7 +21,6 @@ def forward(self, x): with torch.cuda.device(x.device): return super().forward(x) - except ImportError: has_fused_layernorm = False diff --git a/tests/speech/__init__.py b/tests/speech/__init__.py index 2ddfdfe64f..a421139027 100644 --- a/tests/speech/__init__.py +++ b/tests/speech/__init__.py @@ -4,8 +4,8 @@ # LICENSE file in the root directory of this source tree. import os -from pathlib import Path import unittest +from pathlib import Path import torch @@ -31,7 +31,7 @@ def set_up_librispeech(self): "spm_librispeech_unigram10000.model", "spm_librispeech_unigram10000.txt", "librispeech_test-other.tsv", - "librispeech_test-other.zip" + "librispeech_test-other.zip", ] self.base_url = f"{S3_BASE_URL}/s2t/librispeech" for filename in self.data_filenames: @@ -47,7 +47,7 @@ def set_up_ljspeech(self): "ljspeech_g2p_gcmvn_stats.npz", "ljspeech_g2p.txt", "ljspeech_test.tsv", - "ljspeech_test.zip" + "ljspeech_test.zip", ] self.base_url = f"{S3_BASE_URL}/s2/ljspeech" for filename in self.data_filenames: diff --git a/tests/speech/test_fastspeech2.py b/tests/speech/test_fastspeech2.py index a4f074e5a3..5da614f17e 100644 --- a/tests/speech/test_fastspeech2.py +++ b/tests/speech/test_fastspeech2.py @@ -8,8 +8,8 @@ import torch from tqdm import tqdm -from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq import utils +from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion from tests.speech import TestFairseqSpeech @@ -25,12 +25,13 @@ def test_ljspeech_fastspeech2_checkpoint(self): path = self.download(self.base_url, self.root, checkpoint_filename) models, cfg, task = load_model_ensemble_and_task( - [path.as_posix()], arg_overrides={ + [path.as_posix()], + arg_overrides={ "data": self.root.as_posix(), "config_yaml": "cfg_ljspeech_g2p.yaml", "vocoder": "griffin_lim", - "fp16": False - } + "fp16": False, + }, ) if self.use_cuda: for model in models: @@ -40,19 +41,21 @@ def test_ljspeech_fastspeech2_checkpoint(self): task.load_dataset(test_split) batch_iterator = task.get_batch_iterator( dataset=task.dataset(test_split), - max_tokens=65_536, max_positions=4_096, num_workers=1 + max_tokens=65_536, + max_positions=4_096, + num_workers=1, ).next_epoch_itr(shuffle=False) progress = tqdm(batch_iterator, total=len(batch_iterator)) generator = task.build_generator(models, cfg) - mcd, n_samples = 0., 0 + mcd, n_samples = 0.0, 0 for sample in progress: sample = utils.move_to_cuda(sample) if self.use_cuda else sample hypos = generator.generate(models[0], sample, has_targ=True) rets = batch_mel_cepstral_distortion( [hypo["targ_waveform"] for hypo in hypos], [hypo["waveform"] for hypo in hypos], - sr=task.sr + sr=task.sr, ) mcd += sum(d.item() for d, _ in rets) n_samples += len(sample["id"].tolist()) diff --git a/tests/speech/test_s2t_transformer.py b/tests/speech/test_s2t_transformer.py index e5ab5262bb..d8a15275b4 100644 --- a/tests/speech/test_s2t_transformer.py +++ b/tests/speech/test_s2t_transformer.py @@ -3,14 +3,14 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from argparse import Namespace import unittest +from argparse import Namespace import torch from tqdm import tqdm -from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq import utils +from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq.scoring.wer import WerScorer from tests.speech import TestFairseqSpeech @@ -26,10 +26,11 @@ def test_librispeech_s2t_transformer_s_checkpoint(self): path = self.download(self.base_url, self.root, checkpoint_filename) models, cfg, task = load_model_ensemble_and_task( - [path.as_posix()], arg_overrides={ + [path.as_posix()], + arg_overrides={ "data": self.root.as_posix(), - "config_yaml": "cfg_librispeech.yaml" - } + "config_yaml": "cfg_librispeech.yaml", + }, ) if self.use_cuda: for model in models: @@ -38,21 +39,33 @@ def test_librispeech_s2t_transformer_s_checkpoint(self): test_split = "librispeech_test-other" task.load_dataset(test_split) batch_iterator = task.get_batch_iterator( - dataset=task.dataset(test_split), - max_tokens=65_536, max_positions=(4_096, 1_024), num_workers=1 - ).next_epoch_itr(shuffle=False) + dataset=task.dataset(test_split), + max_tokens=65_536, + max_positions=(4_096, 1_024), + num_workers=1, + ).next_epoch_itr(shuffle=False) - scorer_args = {"wer_tokenizer": "none", "wer_lowercase": False, - "wer_remove_punct": False, "wer_char_level": False} + scorer_args = { + "wer_tokenizer": "none", + "wer_lowercase": False, + "wer_remove_punct": False, + "wer_char_level": False, + } scorer = WerScorer(Namespace(**scorer_args)) progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) for batch_idx, sample in progress: sample = utils.move_to_cuda(sample) if self.use_cuda else sample hypo = task.inference_step(generator, models, sample) for i, sample_id in enumerate(sample["id"].tolist()): - tgt_tokens = utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()).int().cpu() + tgt_tokens = ( + utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()) + .int() + .cpu() + ) tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") - hypo_str = task.tgt_dict.string(hypo[i][0]["tokens"].int().cpu(), "sentencepiece") + hypo_str = task.tgt_dict.string( + hypo[i][0]["tokens"].int().cpu(), "sentencepiece" + ) if batch_idx == 0 and i < 3: print(f"T-{sample_id} {tgt_str}") print(f"H-{sample_id} {hypo_str}") diff --git a/tests/speech/test_tts_transformer.py b/tests/speech/test_tts_transformer.py index 2ade981ec1..0c01e20e56 100644 --- a/tests/speech/test_tts_transformer.py +++ b/tests/speech/test_tts_transformer.py @@ -8,8 +8,8 @@ import torch from tqdm import tqdm -from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq import utils +from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion from tests.speech import TestFairseqSpeech @@ -25,12 +25,13 @@ def test_ljspeech_tts_transformer_checkpoint(self): path = self.download(self.base_url, self.root, checkpoint_filename) models, cfg, task = load_model_ensemble_and_task( - [path.as_posix()], arg_overrides={ + [path.as_posix()], + arg_overrides={ "data": self.root.as_posix(), "config_yaml": "cfg_ljspeech_g2p.yaml", "vocoder": "griffin_lim", - "fp16": False - } + "fp16": False, + }, ) if self.use_cuda: for model in models: @@ -40,19 +41,21 @@ def test_ljspeech_tts_transformer_checkpoint(self): task.load_dataset(test_split) batch_iterator = task.get_batch_iterator( dataset=task.dataset(test_split), - max_tokens=65_536, max_positions=768, num_workers=1 + max_tokens=65_536, + max_positions=768, + num_workers=1, ).next_epoch_itr(shuffle=False) progress = tqdm(batch_iterator, total=len(batch_iterator)) generator = task.build_generator(models, cfg) - mcd, n_samples = 0., 0 + mcd, n_samples = 0.0, 0 for sample in progress: sample = utils.move_to_cuda(sample) if self.use_cuda else sample hypos = generator.generate(models[0], sample, has_targ=True) rets = batch_mel_cepstral_distortion( [hypo["targ_waveform"] for hypo in hypos], [hypo["waveform"] for hypo in hypos], - sr=task.sr + sr=task.sr, ) mcd += sum(d.item() for d, _ in rets) n_samples += len(sample["id"].tolist()) diff --git a/tests/test_hf_hub.py b/tests/test_hf_hub.py index f39d1fa8e7..5cfef70d06 100644 --- a/tests/test_hf_hub.py +++ b/tests/test_hf_hub.py @@ -7,6 +7,7 @@ import unittest import torch + try: import huggingface_hub except ImportError: diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index 823c917d23..2e42df0e56 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -562,7 +562,6 @@ def test_diverse_beam_search(self): self.assertHypoScore(hypos[1][1], [0.7, 0.35, 0.9], [0, 2, 1], 0.5) - class TestTopPSamplingSearch(TestSequenceGeneratorBase): def setUp(self): # construct dummy dictionary From 00b6adfbdc58d473c9039a96c124e75f922e3808 Mon Sep 17 00:00:00 2001 From: Myle Ott <myleott@fb.com> Date: Mon, 20 Dec 2021 10:59:59 -0800 Subject: [PATCH 523/774] Add README for Efficient Large Scale Language Modeling with Mixtures of Experts (#2823) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2823 Reviewed By: artetxem Differential Revision: D33236555 Pulled By: myleott fbshipit-source-id: 44dfa4b4ce44ad4ffdead2b707b187f181ef77a2 --- examples/moe_lm/README.md | 126 +++++++++++++++++++ examples/moe_lm/data_card.md | 221 ++++++++++++++++++++++++++++++++++ examples/moe_lm/model_card.md | 170 ++++++++++++++++++++++++++ fairseq/hub_utils.py | 15 ++- 4 files changed, 529 insertions(+), 3 deletions(-) create mode 100644 examples/moe_lm/README.md create mode 100644 examples/moe_lm/data_card.md create mode 100644 examples/moe_lm/model_card.md diff --git a/examples/moe_lm/README.md b/examples/moe_lm/README.md new file mode 100644 index 0000000000..64ee57ec22 --- /dev/null +++ b/examples/moe_lm/README.md @@ -0,0 +1,126 @@ +# Efficient Large Scale Language Modeling with Mixtures of Experts + +## Introduction + +Mixture of Experts layers (MoEs) enable efficient scaling of language models +through conditional computation. This work empirically compares how +autoregressive MoE language models scale in comparison with dense models in a +wide range of settings: in- and out-of-domain language modeling, zero- and +few-shot priming, and full fine-tuning. See the associated paper for more +details. + +This repo contains instructions for reproducing results from the paper. + +## Pre-trained models + +These models are intended for research purposes only in order to reproduce the +results from the paper, and to enable further research on the capabilities and +limitations of language models. Please see the [model card](model_card.md) for +more details about how the models were trained and evaluated, as well as their +limitations and intended use. + +#### Dense models + +Dense models can be run directly from the `main` branch. + +Model | Layers | Model Dim | Languages | Download +---|---|---|---|--- +`dense_125m` | 12 | 768 | English | [en_dense_lm_125m.tar.gz (0.2GB)](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_dense_lm_125m.tar.gz) +`dense_355m` | 24 | 1024 | English | [en_dense_lm_355m.tar.gz (0.6GB)](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_dense_lm_355m.tar.gz) +`dense_1_3b` | 24 | 2048 | English | [en_dense_lm_1_3b.tar.gz (2.3GB)](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_dense_lm_1_3b.tar.gz) +`dense_2_7b` | 32 | 2560 | English | [en_dense_lm_2_7b.tar.gz (4.6GB)](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_dense_lm_2_7b.tar.gz) +`dense_6_7b` | 32 | 4096 | English | [en_dense_lm_6_7b.tar.gz (12GB)](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_dense_lm_6_7b.tar.gz) +`dense_13b` | 40 | 5120 | English | [en_dense_lm_13b.tar.gz (23GB)](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_dense_lm_13b.tar.gz) + +#### Mixture of expert models + +MoE models must be run from the `moe` branch. Please see the +[MoE README](https://github.com/pytorch/fairseq/tree/moe#evaluating-moe-language-models) +for more details about how to load and evaluate MoE models. + +Model | Layers | Model Dim | Languages | Download +---|---|---|---|--- +`moe_15b` | 12 | 768 | English | [en_moe_lm_15b.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_moe_lm_15b.tar.gz) +`moe_52b` | 24 | 1024 | English | [en_moe_lm_52b.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/lm/en_moe_lm_52b.tar.gz) +`moe_207b` | 24 | 2048 | English | Available by request +`moe_1_1t` | 32 | 4096 | English | Available by request + +## Evaluation + +### Example (COPA) + +The following snippet shows how to evaluate our dense models on the [Choice of +Plausible Alternatives (COPA)](https://people.ict.usc.edu/~gordon/copa.html) task. + +```python +from fairseq.models.transformer_lm import TransformerLanguageModel +model_dir = '/path/to/en_dense_lm_125m' +lm = TransformerLanguageModel.from_pretrained(model_dir, bpe='gpt2') +lm = lm.eval(); # disable dropout +lm = lm.half(); # use FP16 for evaluation +lm = lm.cuda(); # move to GPU + +def get_logprobs(prompt): + import re + prompt = re.sub('\n+' , '\n', prompt) # collapse repeated newlines, which indicate separate documents + return lm.score(prompt, replace_newlines_with_eos=True)['positional_scores'] + +# Zero-shot evaluation for the Choice of Plausible Alternatives (COPA) task. +# A return value of 1 indicates that the first alternative is more plausible, +# while 2 indicates that the second alternative is more plausible. +def COPA_eval(prompt, alternative1, alternative2): + lprob1 = get_logprobs(prompt + "\n" + alternative1).sum() + lprob2 = get_logprobs(prompt + "\n" + alternative2).sum() + return 1 if lprob1 > lprob2 else 2 + +COPA_eval("The man broke his toe. What was the CAUSE of this?", "He got a hole in his sock.", "He dropped a hammer on his foot.") +# 2 +COPA_eval("I tipped the bottle. What happened as a RESULT?", "The liquid in the bottle froze.", "The liquid in the bottle poured out.") +# 2 +COPA_eval("I knocked on my neighbor's door. What happened as a RESULT?", "My neighbor invited me in.", "My neighbor left his house.") +# 1 +``` + +### Data format + +Few-shot prompting is known to be sensitive to the input formatting, and it is usually best to match the formatting used in pretraining. + +During pretraining our models were presented with data in the following format (i.e., one paragraph per line, with a blank line separating documents): +``` +<doc0,para0,tok0> ... <doc0,para0,tokX> +<doc0,para1,tok0> ... <doc0,para1,tokY> + +<doc1,para0,tok0> ... <doc0,para0,tokX> +... +``` + +#### Newlines + +While we use the byte-level BPE from GPT-2/3, fairseq's preprocessing replaces newlines with the end-of-sentence symbol (`</s>`), which corresponds to embedding index `2`. +Thus **the model never saw newline characters during pretraining** and newlines should not be used during few-shot prompting. + +This is more clearly illustrated in the following example, which uses fairseq's Hub Interface to tokenize two documents in the desired format: +```python +from fairseq.models.transformer_lm import TransformerLanguageModel +model_dir = '/path/to/en_dense_lm_125m' +lm = TransformerLanguageModel.from_pretrained(model_dir, bpe='gpt2') + +data = """\ +This is the first paragraph of the first document. +This is the second paragraph of the first document. + +This is the first paragraph of the second document.\ +""" + +# The following is wrong, since it will encode newlines present in `data`. +tokens_bad = lm.score(data)['tokens'] +assert '\n' in lm.decode(tokens_bad) # oops, we encoded a newline + +# Instead pass the replace_newlines_with_eos option to get the correct behavior. +tokens_good = lm.score(data, replace_newline_with_eos=True)['tokens'] +assert '\n' not in lm.decode(tokens_good) # no newlines were encoded +``` + +## Citation + +Coming soon. diff --git a/examples/moe_lm/data_card.md b/examples/moe_lm/data_card.md new file mode 100644 index 0000000000..a69cdc974b --- /dev/null +++ b/examples/moe_lm/data_card.md @@ -0,0 +1,221 @@ +# Data card for the paper "Efficient Large Scale Language Modeling with Mixtures of Experts" +## Version 1.0.0 + +We follow the recommendations of Gebru et al. (2018) and provide a datacard for the dataset used to train the 1.1T parameter model. + +## Motivation +* **For what purpose was the dataset created? Was there a specific task in mind? Was there a specific gap that needed to be filled? Please provide a description.** +The pre-training data for training the 1.1 T model was created by a union of six English language datasets, including five datasets used by RoBERTa (Liu et al 2019) and the English subset of CC 100. These purpose of creating this dataset was to pre-train the language model. + +* **Who created the dataset (e.g., which team, research group) and on behalf of which entity (e.g., company, institution, organization)?** +Meta AI. + +* **Who funded the creation of the dataset? If there is an associated grant, please provide the name of the grantor and the grant name and number.** +Meta AI. + +* **Any other comments?** +No. + +## Composition + +* **What do the instances that comprise the dataset represent (e.g., documents, photos, people, countries)? Are there multiple types of instances (e.g., movies, users, and ratings; people and interactions between them; nodes and edges)? Please provide a description.** +The instances are textual documents. The overall dataset is composed from a union of the following datasets - + * BookCorpus (Zhu et al., 2019) consists of more than 10K unpublished books (4GB); + * English Wikipedia, excluding lists, tables and headers (12GB); + * CC-News (Nagel,2016) contains 63 million English news articles crawled between September 2016 and February 2019 (76GB); + * OpenWebText (Gokaslan and Cohen, 2019), an open source recreation of the WebText dataset used to train GPT-2 (38GB); + * CC-Stories (Trinh and Le, 2018) contains a subset of CommonCrawl data filtered to match the story-like style of Winograd schemas (31GB); + * English CC100 (Wenzek et al., 2020), a dataset extracted from CommonCrawl snapshots between January 2018 and December 2018, filtered to match the style of Wikipedia (292GB). + +* **How many instances are there in total (of each type, if appropriate)?** +The training data contains 112B tokens corresponding to 453 GB of data. + +* **Does the dataset contain all possible instances or is it a sample (not necessarily random) of instances from a larger set? If the dataset is a sample, then what is the larger set? Is the sample representative of the larger set (e.g., geographic coverage)? If so, please describe how this representativeness was validated/verified. If it is not representative of the larger set, please describe why not (e.g., to cover a more diverse range of instances, because instances were withheld or unavailable).** +The English CC100 section of the dataset is a subset of CommonCrawl snapshots extracted between January 2018 to December 2018, filtered to match the style of Wikipedia. The CC-stories dataset contains a subset of CommonCrawl data filtered to match the story-like style of Winograd schemas. + +* **What data does each instance consist of? “Raw” data (e.g., unprocessed text or images) or features? In either case, please provide a description.** +Each instance consists of raw text data. + +* **Is there a label or target associated with each instance? If so, please provide a description.** +No. + +* **Is any information missing from individual instances? If so, please provide a description, explaining why this information is missing (e.g., because it was unavailable). This does not include intentionally removed information, but might include, e.g., redacted text.** +No. + +* **Are relationships between individual instances made explicit (e.g., users' movie ratings, social network links)? If so, please describe how these relationships are made explicit.** +There are no explicit relationships between individual instances. + +* **Are there recommended data splits (e.g., training, development/validation, testing)? If so, please provide a description of these splits, explaining the rationale behind them.** +We hold out a random validation set of approximately 150MB from the pretraining data, sampled proportionally to each dataset's size in the pretraining corpus. + +* **Are there any errors, sources of noise, or redundancies in the dataset? If so, please provide a description.** +N/A + +* **Is the dataset self-contained, or does it link to or otherwise rely on external resources (e.g., websites, tweets, other datasets)?** +It's self-contained. + +* **Does the dataset contain data that might be considered confidential (e.g., data that is protected by legal privilege or by doctor-patient confidentiality, data that includes the content of individuals' non-public communications)? If so, please provide a description.** +The datasets used are publicly available, and the information in them is not considered confidential. + +* **Does the dataset contain data that, if viewed directly, might be offensive, insulting, threatening, or might otherwise cause anxiety? If so, please describe why.** +Parts of the dataset are a subset of public Common Crawl data, which could contain sentences that, if viewed directly, might be offensive, insulting, threatening, or might otherwise cause anxiety. + +* **Does the dataset relate to people? If not, you may skip the remaining questions in this section.** +Some documents of this data relate to people, such as news articles, Wikipedia descriptions, etc. + +* **Does the dataset identify any subpopulations (e.g., by age, gender)? If so, please describe how these subpopulations are identified and provide a description of their respective distributions within the dataset.** +No. + +* **Is it possible to identify individuals (i.e., one or more natural persons), either directly or indirectly (i.e., in combination with other data) from the dataset? If so, please describe how** +In addition to individuals who have Wikipedia pages (celebrities, politicians, etc.), it may be possible to identify other individuals by their names, Twitter account names, etc. if that information is present in Common Crawl. + +* **Does the dataset contain data that might be considered sensitive in any way (e.g., data that reveals racial or ethnic origins, sexual orientations, religious beliefs, political opinions or union memberships, or locations; financial or health data; biometric or genetic data; forms of government identification, such as social security numbers; criminal history)? If so, please provide a description.** +The training dataset is partially derived from Common Crawl, which may contain some sensitive information. + +* **Any other comments?** +No + + +## Collection Process + +* **How was the data associated with each instance acquired? Was the data directly observable (e.g., raw text, movie ratings), reported by subjects (e.g., survey responses), or indirectly inferred/ derived from other data (e.g., part-of-speech tags, model-based guesses for age or language)? If data was reported by subjects or indirectly inferred/derived from other data, was the data validated/verified? If so, please describe how.** +N/A. The dataset is a union of six publicly available datasets. + +* **What mechanisms or procedures were used to collect the data (e.g., hardware apparatus or sensor, manual human curation, software program, software API)? How were these mechanisms or procedures validated?** +N/A + +* **If the dataset is a sample from a larger set, what was the sampling strategy (e.g., deterministic, probabilistic with specific sampling probabilities)?** +Please refer to the main document for details. + +* **Who was involved in the data collection process (e.g., students, crowdworkers, contractors) and how were they compensated (e.g., how much were crowdworkers paid)?** +This data is mined, filtered and sampled by machines. + +* **Over what timeframe was the data collected? Does this timeframe match the creation timeframe of the data associated with the instances (e.g., recent crawl of old news articles)? If not, please describe the timeframe in which the data associated with the instances was created.** +Different parts of the dataset were mined over different time periods. +1. The CC-News dataset contains English news articles crawled between September 2016 and February 2019. +2. The English CC-100 dataset was extracted from CommonCrawl snapshots between January 2018 and December 2018. + +* **Were any ethical review processes conducted (e.g., by an institutional review board)? If so, please provide a description of these review processes, including the outcomes, as well as a link or other access point to any supporting documentation.** +No. + +* **Does the dataset relate to people? If not, you may skip the remainder of the questions in this section.** +No. + +* **Did you collect the data from the individuals in question directly, or obtain it via third parties or other sources (e.g., websites)?** +N/A + +* **Were the individuals in question notified about the data collection? If so, please describe (or show with screenshots or other information) how notice was provided, and provide a link or other access point to, or otherwise reproduce, the exact language of the notification itself.** +N/A + +* **Did the individuals in question consent to the collection and use of their data? If so, please describe (or show with screenshots or other information) how consent was requested and provided, and provide a link or other access point to, or otherwise reproduce, the exact language to which the individuals consented.** +N/A + +* **If consent was obtained, were the consenting individuals provided with a mechanism to revoke their consent in the future or for certain uses? If so, please provide a description, as well as a link or other access point to the mechanism (if appropriate).** +N/A + +* **Has an analysis of the potential impact of the dataset and its use on data subjects (e.g., a data protection impact analysis) been conducted? If so, please provide a description of this analysis, including the outcomes, as well as a link or other access point to any supporting documentation.** +Some responsible AI related evaluations were performed. Please refer to the main document and the model card for the paper. + +* **Any other comments?** +No + + +## Preprocessing/cleaning/labeling + + +* **Was any preprocessing/cleaning/labeling of the data done (e.g., discretization or bucketing, tokenization, part-of-speech tagging, SIFT feature extraction, removal of instances, processing of missing values)? If so, please provide a description. If not, you may skip the remainder of the questions in this section.** +The component datasets went through standard cleaning and re-formatting practices, including removing repetitive/non informative text like "Chapter One", or "This ebook by Project Gutenberg". + +* **Was the “raw” data saved in addition to the preprocessed/cleaned/labeled data (e.g., to support unanticipated future uses)? If so, please provide a link or other access point to the “raw” data.** +The "raw" component datasets is publicly available in their respective locations (more details can be seen in the respective papers linked in references). + +* **Is the software used to preprocess/clean/label the instances available? If so, please provide a link or other access point.** +The software is proprietary to Meta Platforms and currently unavailable publicly. + +* **Any other comments?** +No + + +## Uses + +* **Has the dataset been used for any tasks already? If so, please provide a description.** +Yes, this dataset was used to pre-train the models described in the paper. + +* **Is there a repository that links to any or all papers or systems that use the dataset? If so, please provide a link or other access point.** +No. + +* **What (other) tasks could the dataset be used for?** +This data can be used to pretrain English language models, which are foundation to many current and future language tasks. + +* **Is there anything about the composition of the dataset or the way it was collected and preprocessed/cleaned/labeled that might impact future uses? For example, is there anything that a future user might need to know to avoid uses that could result in unfair treatment of individuals or groups (e.g., stereotyping, quality of service issues) or other undesirable harms (e.g., financial harms, legal risks) If so, please provide a description. Is there anything a future user could do to mitigate these undesirable harms?** +The pipeline for creating this dataset paves a way for building a scalable infrastructure for mining datasets to be be used for training large-scale models. + +* **Are there tasks for which the dataset should not be used? If so, please provide a description.** +No. + +* **Any other comments?** +No. + +## Distribution + + +* **Will the dataset be distributed to third parties outside of the entity (e.g., company, institution, organization) on behalf of which the dataset was created? If so, please provide a description.** +No. + +* **How will the dataset will be distributed (e.g., tarball on website, API, GitHub)? Does the dataset have a digital object identifier (DOI)?** +N/A + +* **When will the dataset be distributed?** +No. + +* **Will the dataset be distributed under a copyright or other intellectual property (IP) license, and/or under applicable terms of use (ToU)? If so, please describe this license and/or ToU, and provide a link or other access point to, or otherwise reproduce, any relevant licensing terms or ToU, as well as any fees associated with these restrictions.** +No. + +* **Have any third parties imposed IP-based or other restrictions on the data associated with the instances? If so, please describe these restrictions, and provide a link or other access point to, or otherwise reproduce, any relevant licensing terms, as well as any fees associated with these restrictions.** +No. + +* **Do any export controls or other regulatory restrictions apply to the dataset or to individual instances? If so, please describe these restrictions, and provide a link or other access point to, or otherwise reproduce, any supporting documentation.** +N/A + +* **Any other comments?** +No. + +## Maintenance + +* **Who is supporting/hosting/maintaining the dataset?** +Meta AI. + +* **How can the owner/curator/manager of the dataset be contacted (e.g., email address)?** +Refer to the main document. + +* **Is there an erratum? If so, please provide a link or other access point.** +N/A + +* **Will the dataset be updated (e.g., to correct labeling errors, add new instances, delete instances)? If so, please describe how often, by whom, and how updates will be communicated to users (e.g., mailing list, GitHub)?** +No plan for updating. + +* **If the dataset relates to people, are there applicable limits on the retention of the data associated with the instances (e.g., were individuals in question told that their data would be retained for a fixed period of time and then deleted)? If so, please describe these limits and explain how they will be enforced.** +N/A + +* **Will older versions of the dataset continue to be supported/hosted/maintained? If so, please describe how. If not, please describe how its obsolescence will be communicated to users.** +N/A + +* **If others want to extend/augment/build on/contribute to the dataset, is there a mechanism for them to do so? If so, please provide a description. Will these contributions be validated/ verified? If so, please describe how. If not, why not? Is there a process for communicating/ distributing these contributions to other users? If so, please provide a description.** +No. + +* **Any other comments?** +No. + +## References +Yinhan Liu, Myle Ott, Naman Goyal, Jingfei Du, Mandar Joshi, Danqi Chen, Omer Levy, Mike Lewis, Luke Zettlemoyer, and Veselin Stoyanov. 2019. Roberta: A robustly optimized bert pretraining approach. arXiv preprint arXiv:1907.11692. + +Yukun Zhu, Ryan Kiros, Richard Zemel, Ruslan Salakhutdinov, Raquel Urtasun, Antonio Torralba, and Sanja Fidler. 2019. Aligning books and movies: Towards story-like visual explanations by watching movies and reading books. arXiv:1506.06724. + +Sebastian Nagel. 2016. Cc-news. http: //web.archive.org/save/http: //commoncrawl.org/2016/10/news-dataset-available. + +Aaron Gokaslan and Vanya Cohen. 2019. Openwebtext corpus. http://web.archive.org/save/http://Skylion007.github.io/OpenWebTextCorpus + +Trieu H Trinh and Quoc V Le. 2018. A simple method for commonsense reasoning. arXiv preprint arXiv:1806.02847. + +Guillaume Wenzek, Marie-Anne Lachaux, Alexis Conneau, Vishrav Chaudhary, Francisco Guzmán, Armand Joulin, and Edouard Grave. 2020. CCNet: Extracting high quality monolingual datasets from web crawl data. In Proceedings of the 12th Language Resources and Evaluation Conference, pages 4003–4012, Marseille, France. European Language Resources Association. + diff --git a/examples/moe_lm/model_card.md b/examples/moe_lm/model_card.md new file mode 100644 index 0000000000..22cd551f8d --- /dev/null +++ b/examples/moe_lm/model_card.md @@ -0,0 +1,170 @@ +# Model card for the paper ``Efficient Large Scale Language Modeling with Mixtures of Experts" +## Version 1.0.0 + +### Model developer +Meta AI + +### Model type +An autoregressive English language model trained on a union of six English language models. We explore dense and sparse (MoE based) architectures in the paper. +* Dense models - Our dense models range from 125M parameters to 13B parameters. +* Sparse (MoE) models - Our MoE based models range from 15B parameters to 1.1 Trillion parameters. +This model card focuses on the 1.1 Trillion parameter model, but the discussion +applies to all of the models explored in this work. + +### Citation details +Artetxe et al. (2021): Efficient Large Scale Language Modeling with Mixtures of Experts + +### Model Feedback Channel +fairseq + +## Intended use +### Primary intended use +For research purposes only, e.g. reproducing model evaluation results. Generation is only used in a limited capacity for explanation/justification or for prompting/probing/priming for class labels. + +### Out of scope uses +The primary purpose of the model is not to generate language, although the model is capable of doing that. + +## Factors influencing model performance +This section discusses potential risks associated with using the model. + +### Relevant factors +Based on known problems with NLP technology, potential relevant factors include bias (gender, profession, race and religion). + +### Evaluation factors +The 1.1T model was evaluated on StereoSet and CrowS-Pairs datasets to quantify encoded bias in the model. + +## Metrics +### Model performance measures +The 1.1T parameter model was primarily evaluated on +1. In-domain and out-of-domain language modeling perplexity. +2. Zero-shot and few-shot priming. +3. Fully supervised finetuning. + +### Approaches to handle uncertainty +For few-shot learning, we report the average results across 25 runs, randomly sampling a different set of few-shot examples from the training set each time. + +## Evaluation data +## Zero Shot evaluation + +### HellaSwag +#### Description +HellaSwag is a dataset for evaluating commonsense reasoning. + +### PIQA +#### Description +PIQA is a dataset designed to evaluate reasoning about Physical Commonsense in Natural Language + +### ReCoRd +#### Description +Reading Comprehension with Commonsense Reasoning Dataset (ReCoRD) is a large-scale reading comprehension dataset which requires commonsense reasoning. ReCoRD consists of queries automatically generated from CNN/Daily Mail news articles; the answer to each query is a text span from a summarizing passage of the corresponding news. The goal of ReCoRD is to evaluate a machine's ability of commonsense reasoning in reading comprehension. + +## Few Shot evaluation +### Winogrande +#### Description +Winogrande is a benchmark for commonsense reasoning. The dataset contains pronoun resolution problems originally designed to be unsolvable for statistical models that rely on selectional preferences or word associations. + +### StoryCloze +#### Description +StoryCloze is a new commonsense reasoning framework for evaluating story understanding, story generation, and script learning. This test requires a system to choose the correct ending to a four-sentence story. + +### OpenBookQA +#### Description +OpenBookQA is a new kind of question-answering dataset modeled after open book exams for assessing human understanding of a subject. It consists of 5,957 multiple-choice elementary-level science questions (4,957 train, 500 dev, 500 test), which probe the understanding of a small “book” of 1,326 core science facts and the application of these facts to novel situations. + +## Fully supervised evaluation + +### BoolQ +#### Description +BoolQ is a question answering dataset for yes/no questions containing 15942 examples. These questions are naturally occurring – they are generated in unprompted and unconstrained settings. Each example is a triplet of (question, passage, answer), with the title of the page as optional additional context. + +### SST-2 +#### Description +SST-2 (or SST-binary) is a binary classification dataset where the goal is to differentiate between negative or somewhat negative vs somewhat positive or positive. + +### MNLI +#### Description +The Multi-Genre Natural Language Inference (MultiNLI) corpus is a crowd-sourced collection of 433k sentence pairs annotated with textual entailment information. The corpus is modeled on the SNLI corpus, but differs in that covers a range of genres of spoken and written text, and supports a distinctive cross-genre generalization evaluation. + +## Responsible AI (RAI) evaluation +### StereoSet +#### Description +A large-scale natural dataset in English to measure stereotypical biases in four domains: gender, profession, race, and religion + +#### Motivation for dataset use +The motivation for evaluating the 1.1T parameter model on this dataset is to evaluate the model's stereotype bias in gender, profession, race, and religion + +### CrowS +#### Description +Challenge Dataset for Measuring Social Biases in Masked Language Models + +#### Motivation for dataset use +The motivation for evaluating the 1.1T parameter model on this dataset is to evaluate the model’s bias in the domains of race, religion and age + +---- + +## Training data +### BookCorpus +#### Description +A dataset consisting of more than 10K unpublished books. 4GB in size. (Zhu et al., 2019) + +### English Wikipedia +#### Description +Data from English wikipedia, excluding lists, tables and headers. 12GB in size. + +### CC-News +#### Description +A dataset containing 63 millions English news articles crawled between September 2016 and February 2019. 76GB in size. (Nagel,2016) + +### OpenWebText +#### Description +An open source recreation of the WebText dataset used to train GPT-2. 38GB in size. (Gokaslan and Cohen, 2019) + +### CC-Stories +#### Description +A dataset containing a subset of CommonCrawl data filtered to match the story-like style of Winograd schemas. 31GB in size. (Trinh and Le, 2018) + +### English CC100 +#### Description +A dataset extracted from CommonCrawl snapshots between January 2018 and December 2018, filtered to match the style of Wikipedia following the methodology introduced in CCNet (https://arxiv.org/abs/1911.00359). 292GB in size. (Wenzek et al., 2020) + +## Responsible AI (RAI) Dimensions +### Fairness (Bias and inclusion) +The 1.1T parameter model was evaluated on the StereoSet and CrowS pairs dataset for inherent bias in the model, and bias as a result of the data. Similar to StereoSet, we observe that both the dense and MoE models get worse in terms of the Stereotype Score (SS) with scale. + +### Privacy and security +The 1.1T model did not have any special Privacy and Security considerations. The training data and evaluation data were both public and went through standard Meta AI Privacy and licensing procedures. + +### Transparency and control +In the spirit of transparency and accountability we have created this model card for the 1.1T parameter model and a data card for the training data (referenced in Artetxe et al. (2021)). + +### Efficiency (Green AI) +The 1.1T parameter model is trained as a Mixture of Experts (MoE) model. Mixture of expert (MoE) models are efficient because they leverage sparse computation, i.e., only a small fraction of parameters are active for any given input. For instance, our 1.1T parameter MoE model requires only 30% more FLOPS compared to a 6.7B parameter dense model, i.e., a 160x increase in parameters with only a 30% increase in FLOPS. Notably, MoE models achieve much better validation perplexity for a given compute budget compared to dense models. + +## References +Rowan Zellers, Ari Holtzman, Yonatan Bisk, Ali Farhadi, and Yejin Choi. 2019. HellaSwag: Can a machine really finish your sentence? In Proceedings of the 57th Annual Meeting of the Association for Computational Linguistics, pages 4791– 4800, Florence, Italy. Association for Computational Linguistics. + +Yonatan Bisk, Rowan Zellers, Ronan Le bras, Jianfeng Gao, and Yejin Choi. 2020. Piqa: Reasoning about physical commonsense in natural language. Proceedings of the AAAI Conference on Artificial Intelligence, 34(05):7432–7439. + +Sheng Zhang, Xiaodong Liu, Jingjing Liu, Jianfeng Gao, Kevin Duh, and Benjamin Van Durme. 2018. ReCoRD: Bridging the gap between human and machine commonsense reading comprehension. arXiv preprint 1810.12885. + +Keisuke Sakaguchi, Ronan Le Bras, Chandra Bhagavatula, and Yejin Choi. 2020. Winogrande: An adversarial winograd schema challenge at scale. Proceedings of the AAAI Conference on Artificial Intelligence, 34(05):8732–8740. + +Nasrin Mostafazadeh, Nathanael Chambers, Xiaodong He, Devi Parikh, Dhruv Batra, Lucy Vanderwende, Pushmeet Kohli, and James Allen. 2016. A corpus and cloze evaluation for deeper understanding of commonsense stories. In Proceedings of the 2016 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, pages 839–849, San Diego, California. Association for Computational Linguistics. + +Todor Mihaylov, Peter Clark, Tushar Khot, and Ashish Sabharwal. 2018. Can a suit of armor conduct electricity? a new dataset for open book question answering. In Proceedings of the 2018 Conference on Empirical Methods in Natural Language Processing, pages 2381–2391, Brussels, Belgium. Association for Computational Linguistics. + +Christopher Clark and Kenton Lee and Ming-Wei Chang and Tom Kwiatkowski and Michael Collins and Kristina Toutanova. 2019. BoolQ: Exploring the Surprising Difficulty of Natural Yes/No Questions + +Moin Nadeem, Anna Bethke, and Siva Reddy. 2021. StereoSet: Measuring stereotypical bias in pretrained language models. In Association for Computational Linguistics (ACL). + +Nikita Nangia, Clara Vania, Rasika Bhalerao, and Samuel R. Bowman. 2020. CrowS-pairs: A challenge dataset for measuring social biases in masked language models. In Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing (EMNLP), pages 1953–1967, Online. Association for Computational Linguistics. + +Yukun Zhu, Ryan Kiros, Richard Zemel, Ruslan Salakhutdinov, Raquel Urtasun, Antonio Torralba, and Sanja Fidler. 2019. Aligning books and movies: Towards story-like visual explanations by watching movies and reading books. arXiv:1506.06724. + +Sebastian Nagel. 2016. Cc-news. http: //web.archive.org/save/http: //commoncrawl.org/2016/10/news-dataset-available. + +Aaron Gokaslan and Vanya Cohen. 2019. Openwebtext corpus. http://web.archive.org/save/http://Skylion007.github.io/OpenWebTextCorpus + +Trieu H Trinh and Quoc V Le. 2018. A simple method for commonsense reasoning. arXiv preprint arXiv:1806.02847. + +Guillaume Wenzek, Marie-Anne Lachaux, Alexis Conneau, Vishrav Chaudhary, Francisco Guzmán, Armand Joulin, and Edouard Grave. 2020. CCNet: Extracting high quality monolingual datasets from web crawl data. In Proceedings of the 12th Language Resources and Evaluation Conference, pages 4003–4012, Marseille, France. European Language Resources Association. diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index d74470d2ec..1df2ee47d4 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -132,11 +132,20 @@ def sample( batched_hypos = self.generate(tokenized_sentences, beam, verbose, **kwargs) return [self.decode(hypos[0]["tokens"]) for hypos in batched_hypos] - def score(self, sentences: List[str], **kwargs): + def score(self, sentences: List[str], replace_newline_with_eos: bool = False, **kwargs): if isinstance(sentences, str): - return self.score([sentences], **kwargs)[0] + return self.score( + [sentences], replace_newline_with_eos=replace_newline_with_eos, **kwargs + )[0] + + def encode(sentence): + if replace_newline_with_eos: + return torch.cat([self.encode(line) for line in sentence.splitlines()]) + else: + return self.encode(sentence) + # NOTE: this doesn't support translation tasks currently - tokenized_sentences = [self.encode(sentence) for sentence in sentences] + tokenized_sentences = [encode(sentence) for sentence in sentences] return [ hypos[0] for hypos in self.generate( From 7f3967805fefb7468c0d59796e69deb015f48a64 Mon Sep 17 00:00:00 2001 From: Xian Li <xianl@devfair0251.h2.fair> Date: Mon, 20 Dec 2021 13:04:28 -0800 Subject: [PATCH 524/774] add readme for xglm models (#2808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Add readme and task for xglm models. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2808 Reviewed By: punitkoura Differential Revision: D33237928 Pulled By: xianxl fbshipit-source-id: 7773cf56e896210dab1f4311ae69f0e00c6d9aff --- examples/xglm/README.md | 24 + examples/xglm/model_card.md | 121 ++++ .../tasks/multilingual_language_modeling.py | 602 ++++++++++++++++++ tests/gpu/test_binaries_gpu.py | 84 +++ tests/utils.py | 75 ++- 5 files changed, 882 insertions(+), 24 deletions(-) create mode 100644 examples/xglm/README.md create mode 100644 examples/xglm/model_card.md create mode 100644 fairseq/tasks/multilingual_language_modeling.py diff --git a/examples/xglm/README.md b/examples/xglm/README.md new file mode 100644 index 0000000000..a4fc755d0f --- /dev/null +++ b/examples/xglm/README.md @@ -0,0 +1,24 @@ +# Few-shot Learning with Multilingual Language Models + +## Introduction + +In this work, we train multilingual generative language models, dubbed XGLM, on a balanced corpus covering a diverse set of languages, and study their few- and zero-shot learning capabilities in a wide range of tasks. Our largest model with 7.5 billion parameters sets new state of the art in few-shot learning on more than 20 representative languages, outperforming GPT-3 of comparable size in multilingual commonsense reasoning (+7.4 accuracy points for 0-shot, +9.4 for 4-shot) and natural language inference (+5.4 for 0-shot, +5.4 for 4-shot). We have included a [model card](model_card.md) of XGLM for transparency and accountability. + +## Data and Languages +XGLM models are trained on a new multilingual corpus extracted from CommonCrawl (CC100-XL), a significantly larger multilingual dataset covering 68 Common Crawl (CC) snapshots (from [Summer 2013](http://commoncrawl.org/2013/11/new-crawl-data-available/) to [March/April 2020](https://commoncrawl.org/2020/04/march-april-2020-crawl-archive-now-available/) consisting of 134 languages. The detailed languages and data statistics are reported in the paper (Table A.1). + +## Pre-trained models + +Model | Layers | Model Dim | Languages | Download +---|---|---|---|--- +`XGLM 564M` | 24 | 1024 | trained on 30 languages| [xglm.564M.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.564M.tar.gz) +`XGLM 1.7B` | 24 | 2048 | trained on 30 languages| [xglm.1.7B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.1.7B.tar.gz) +`XGLM 2.9B` | 48 | 2048 | trained on 30 languages| [xglm.2.9B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.2.9B.tar.gz) +`XGLM 7.5B` | 32 | 4096 | trained on 30 languages| [xglm.7.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.7.5B.tar.gz) +`XGLM 4.5B` | 48 | 2048 | trained on 134 languages| [xglm.4.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.4.5B.tar.gz) + +## Evaluation +Coming soon. + +## Citation +Coming soon. diff --git a/examples/xglm/model_card.md b/examples/xglm/model_card.md new file mode 100644 index 0000000000..75ddb1708a --- /dev/null +++ b/examples/xglm/model_card.md @@ -0,0 +1,121 @@ +# XGLM multilingual model +## Version 1.0.0 + +### Model developer +Meta AI + +### Model type +A multilingual autoregressive language model trained on a balanced corpus of a diverse set of languages. The largest trained model has 7.5 billion parameters. The language model can learn tasks from natural language descriptions and a few examples. + +### References +Coming soon. + +### Citation details +Coming soon. + +### Model Feedback Channel +https://github.com/pytorch/fairseq + +## Intended use +### Primary intended use +For research purposes only, e.g. reproducing model evaluation results. Generation is only used in a limited capacity for explanation/justification or for prompting/probing/priming for class labels. + +### Out of scope uses +The primary purpose of the model is not to generate language, although the model is capable of doing that. + +## Potential risks +This section lists the potential risks associated with using the model. + +### Relevant factors +Based on known problems with NLP technology, potential relevant factors include output correctness, robustness, bias (gender, profession, race and religion), etc. + +### Evaluation factors +The model was evaluated on hate speech detection and occupation identification. +* Hate speech detection (Huang et al. (2020)) - A safety task to test language models’ ability to identify hateful and offensive text. +* Occupation identification (De-Arteaga et al., 2019), (Zhao et al., 2020) - A bias task to study language models’ performance divergence between different gender groups on the task of occupation identification. + +## Metrics +### Model performance measures +The XGLM model was primarily evaluated on +1. Zero shot and few shot learning by looking at per-language performance on tasks spanning commonsense reasoning (XCOPA, XWinograd), natural language inference (XNLI) and paraphrasing (PAWS-X). The model is also evaluated on XStoryCloze, a new dataset created by Meta AI. +2. Cross lingual transfer through templates and few-shot examples. +3. Knowledge probing - Evaluate to what extent the XGLM model can effectively store factual knowledge in different languages using the mLAMA benchmark. +4. Translation - We report machine translation results on WMT benchmarks and a subset of FLORES-101 in the main paper. + +The model was also evaluated on hate speech datasets introduced by Huang et al. (2020) and an occupation identification dataset by De-Arteaga et al. 2019 to identify bias in the model. + +### Approaches to handle uncertainty +Report confidence intervals, variance metrics for the model performance metrics. Few-shot evaluation was conducted with different sampling with 5 seeds. We reported statistical significance. + +## Evaluation data +## Zero Shot and Few Shot evaluation + +### XNLI (Conneau et al., 2018) +#### Description +The Cross-lingual Natural Language Inference (XNLI) corpus is the extension of the Multi-Genre NLI (MultiNLI) corpus to 15 languages. The dataset was created by manually translating the validation and test sets of MultiNLI into each of those 15 languages. + +### XStoryCloze +#### Description +A new dataset created by Meta AI by translating the validation split of the English StoryCloze dataset (Mostafazadeh et al., 2016) (Spring 2016 version) to 10 other typologically diverse languages (ru, zh Simplified, es Latin America, ar, hi, id, te, sw, eu, my). + +### XCOPA (Ponti et al., 2020) +#### Description +The Cross-lingual Choice of Plausible Alternatives (XCOPA) dataset is a benchmark to evaluate the ability of machine learning models to transfer commonsense reasoning across languages. The dataset is the translation and reannotation of the English COPA (Roemmele et al. 2011) and covers 11 languages from 11 families and several areas around the globe. + +### XWinograd (Tikhonov and Ryabinin, 2021) +#### Description +XWinograd is a multilingual collection of Winograd Schemas in six languages that can be used for evaluation of cross-lingual commonsense reasoning capabilities. + +### PAWS-X (Yang et al., 2019) +#### Description +PAWS-X contains 23,659 human translated PAWS evaluation pairs and 296,406 machine translated training pairs in six typologically distinct languages: French, Spanish, German, Chinese, Japanese, and Korean. All translated pairs are sourced from examples in PAWS-Wiki. + +## Responsible AI (RAI) evaluation +### Hate speech +Hate speech datasets introduced by Huang et al. (2020). This dataset is a multilingual Twitter corpus for the task of hate speech detection with inferred four author demographic factors: age, country, gender and race/ethnicity. The corpus covers five languages: English, Italian, Polish, Portuguese and Spanish. + +### Bias dataset +This dataset by De-Arteaga et al. 2019 is a bias detection dataset, where the aim is to study gender bias based on identifying a person’s occupation from their bios. + +---- + +## Training data +### CC100-XL +#### Description +Following the recent success of multilingual self-supervised pre-training (Devlin et al., 2019; Lample and Conneau, 2019; Con; Xue et al., 2020; Goyal et al., 2021a; Liu et al., 2020), we train our language models on a mixture of monolingual text of different languages. We extended the pipeline used for mining the CC100 corpus to generate CC100-XL, a significantly larger multilingual dataset covering 68 Common Crawl snapshots (from Summer 2013 to March/April 2020) and 134 languages. + +More details on the CC100-XL dataset can be found in the Appendix section of the paper. + +## RAI Dimensions +### Fairness (Bias and inclusion) +The XGLM model was evaluated on Hate speech and bias identification datasets. For hate speech, we observe that across the 5 languages in the dataset, in context learning results are only slightly better than random (50%). Another interesting observation is that most few shot results are worse than zero-shot, which indicates that the model is not able to utilize examples using the templates described in the paper. For bias identification, the XGLM (6.7B) English only model achieves the best performance on English and Spanish, while the GPT-3 model of comparable size (6.7B) model achieves the best in French. On certain occupations (e.g. model and teacher), XGLM 6.7B En only model and GPT-3 (6.7B) have very significant bias while XGLM 7.5B is much less biased. + +### Privacy and security +The XGLM model did not have any special Privacy and Security considerations. The training data and evaluation data were both public and went through standard Meta AI Privacy and licensing procedures. + +### Transparency and control +In the spirit of transparency and accountability we have created this model card and a data card for the CC100-XL which can be found in the Appendix section of the paper. + +### Efficiency (Green AI) +From an engineering perspective, XGLM pertains to a family of models that represent single unified models catering to many languages which have wide application across many applications. Such a unified single model saves on carbon footprint as well as energy consumption (comparing to the alternative: separate models for different languages) leading to more energy efficiency. A single model, despite having the risk of being a single point of failure, has the powerful incentive of being easier to maintain, access, distribute, and track. + +## References +Edoardo Maria Ponti, Goran Glavas, Olga Majewska, Qianchu Liu, Ivan Vulic, and Anna Korhonen. 2020. XCOPA: A multilingual dataset for causal commonsense reasoning. In Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing, EMNLP 2020, Online, November 16-20, 2020, pages 2362–2376. Association for Computational Linguistics. +XCOPA Dataset | Papers With Code + +Alexey Tikhonov and Max Ryabinin. 2021. It’s all in the heads: Using attention heads as a baseline for cross-lingual transfer in commonsense reasoning. In Findings of the Association for Computational Linguistics: ACL/IJCNLP 2021, Online Event, August 1-6, 2021, volume ACL/IJCNLP 2021 of Findings of ACL, pages 3534–3546. Association for Computational Linguistics. +XWINO Dataset | Papers With Code (XWinograd) + +Yinfei Yang, Yuan Zhang, Chris Tar, and Jason Baldridge. 2019. PAWS-X: A cross-lingual adversarial dataset for paraphrase identification. CoRR, abs/1908.11828. +PAWS-X Dataset | Papers With Code + +Alexis Conneau, Guillaume Lample, Ruty Rinott, Adina Williams, Samuel R. Bowman, Holger Schwenk, and Veselin Stoyanov. 2018. XNLI: evaluating cross-lingual sentence representations. CoRR, abs/1809.05053. +XNLI Dataset | Papers With Code + +Xiaolei Huang, Linzi Xing, Franck Dernoncourt, and Michael Paul. 2020. Multilingual twitter corpus and baselines for evaluating demographic bias in hate speech recognition. In Proceedings of the 12th Language Resources and Evaluation Conference, pages 1440–1448. + +Maria De-Arteaga, Alexey Romanov, Hanna Wallach, Jennifer Chayes, Christian Borgs, Alexandra Chouldechova, Sahin Geyik, Krishnaram Kenthapadi, and Adam Tauman Kalai. 2019. Bias in bios: A case study of semantic representation bias in a high-stakes setting. In proceedings of the Conference on Fairness, Accountability, and Transparency, pages 120–128. + +Nasrin Mostafazadeh, Nathanael Chambers, Xiaodong He, Devi Parikh, Dhruv Batra, Lucy Vanderwende, Pushmeet Kohli, James F. Allen. A Corpus and Evaluation Framework for Deeper Understanding of Commonsense Stories. CoRR abs/1604.01696. + +Jieyu Zhao, Subhabrata Mukherjee, Saghar Hosseini, Kai-Wei Chang, and Ahmed Hassan Awadallah. 2020. Gender bias in multilingual embeddings and crosslingual transfer. In Proceedings of the 58th Annual Meeting of the Association for Computational Linguistics, pages 2896–2907. diff --git a/fairseq/tasks/multilingual_language_modeling.py b/fairseq/tasks/multilingual_language_modeling.py new file mode 100644 index 0000000000..0140667f2c --- /dev/null +++ b/fairseq/tasks/multilingual_language_modeling.py @@ -0,0 +1,602 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from dataclasses import dataclass, field +from typing import Optional + +import numpy as np +import torch +from fairseq import utils +from fairseq.data import ( + ConcatDataset, + AppendTokenDataset, + Dictionary, + IdDataset, + LMContextWindowDataset, + MonolingualDataset, + NestedDictionaryDataset, + NumelDataset, + PadDataset, + PrependTokenDataset, + ResamplingDataset, + SortDataset, + StripTokenDataset, + TokenBlockDataset, + TruncatedDictionary, + data_utils, +) +from fairseq.data.indexed_dataset import get_available_dataset_impl +from fairseq.data.shorten_dataset import maybe_shorten_dataset +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.tasks import LegacyFairseqTask, register_task +from omegaconf import II + + +SAMPLE_BREAK_MODE_CHOICES = ChoiceEnum(["none", "complete", "complete_doc", "eos"]) +SHORTEN_METHOD_CHOICES = ChoiceEnum(["none", "truncate", "random_crop"]) +logger = logging.getLogger(__name__) + + +def lang_token(lang): + return f"<{lang}>" + + +@dataclass +class MultilingualLanguageModelingConfig(FairseqDataclass): + # TODO common var add to parent + data: Optional[str] = field( + default=None, metadata={"help": "path to data directory"} + ) + sample_break_mode: SAMPLE_BREAK_MODE_CHOICES = field( + default="none", + metadata={ + "help": 'If omitted or "none", fills each sample with tokens-per-sample ' + 'tokens. If set to "complete", splits samples only at the end ' + "of sentence, but may include multiple sentences per sample. " + '"complete_doc" is similar but respects doc boundaries. ' + 'If set to "eos", includes only one sentence per sample.' + }, + ) + tokens_per_sample: int = field( + default=1024, + metadata={"help": "max number of tokens per sample for LM dataset"}, + ) + output_dictionary_size: int = field( + default=-1, metadata={"help": "limit the size of output dictionary"} + ) + self_target: bool = field(default=False, metadata={"help": "include self target"}) + future_target: bool = field( + default=False, metadata={"help": "include future target"} + ) + past_target: bool = field(default=False, metadata={"help": "include past target"}) + add_bos_token: bool = field( + default=False, metadata={"help": "prepend lang id token <dialect>"} + ) + max_source_positions: Optional[int] = field( + default=None, metadata={"help": "max number of tokens in the source sequence"} + ) + max_target_positions: Optional[int] = field( + default=None, metadata={"help": "max number of tokens in the target sequence"} + ) + pad_to_fixed_length: Optional[bool] = field( + default=False, metadata={"help": "pad to fixed length"} + ) + pad_to_fixed_bsz: Optional[bool] = field( + default=False, metadata={"help": "boolean to pad to fixed batch size"} + ) + + multilang_sampling_alpha: Optional[float] = field( + default=1.0, + metadata={ + "help": "smoothing alpha for sample rations across multiple datasets" + }, + ) + + shorten_method: SHORTEN_METHOD_CHOICES = field( + default="none", + metadata={ + "help": "if not none, shorten sequences that exceed --tokens-per-sample" + }, + ) + shorten_data_split_list: str = field( + default="", + metadata={ + "help": "comma-separated list of dataset splits to apply shortening to, " + 'e.g., "train,valid" (default: all dataset splits)' + }, + ) + + langs: str = field( + default="", + metadata={ + "help": "comma-separated list of languages (default: all directories in data path)" + }, + ) + baseline_model_langs: str = field( + default="", + metadata={ + "help": "comma-separated list of languages in the baseline model (default: none)" + }, + ) + # TODO: legacy parameter kept for compatibility + baseline_model: str = field( + default="", + metadata={ + "help": "path to the baseline model (default: none)" + }, + ) + + lang_to_offline_shard_ratio: str = field( + default="", + metadata={ + "help": "absolute path of tsv file location to indicate lang to offline shard ratio.", + } + ) + # TODO common vars below add to parent + seed: int = II("common.seed") + dataset_impl: Optional[ChoiceEnum(get_available_dataset_impl())] = II( + "dataset.dataset_impl" + ) + data_buffer_size: int = II("dataset.data_buffer_size") + tpu: bool = II("common.tpu") + batch_size: Optional[int] = II("dataset.batch_size") + batch_size_valid: Optional[int] = II("dataset.batch_size_valid") + train_subset: str = II("common.train_subset") + valid_subset: str = II("common.valid_subset") + + +@register_task("multilingual_language_modeling", dataclass=MultilingualLanguageModelingConfig) +class MultilingualLanguageModelingTask(LegacyFairseqTask): + """ + Train a language model. + + Args: + dictionary (~fairseq.data.Dictionary): the dictionary for the input of + the language model + output_dictionary (~fairseq.data.Dictionary): the dictionary for the + output of the language model. In most cases it will be the same as + *dictionary*, but could possibly be a more limited version of the + dictionary (if ``--output-dictionary-size`` is used). + targets (List[str]): list of the target types that the language model + should predict. Can be one of "self", "future", and "past". + Defaults to "future". + + .. note:: + + The language modeling task is compatible with :mod:`fairseq-train`, + :mod:`fairseq-generate`, :mod:`fairseq-interactive` and + :mod:`fairseq-eval-lm`. + + The language modeling task provides the following additional command-line + arguments: + + .. argparse:: + :ref: fairseq.tasks.language_modeling_parser + :prog: + """ + + def __init__(self, args, dictionary, output_dictionary=None, targets=None): + super().__init__(args) + self.dictionary = dictionary + self.output_dictionary = output_dictionary or dictionary + + if targets is None: + targets = ["future"] + self.targets = targets + + @staticmethod + def _get_langs(args, epoch=1): + paths = utils.split_paths(args.data) + assert len(paths) > 0 + data_path = paths[(epoch - 1) % len(paths)] + + languages = sorted( + name + for name in os.listdir(data_path) + if os.path.isdir(os.path.join(data_path, name)) + ) + if args.langs: + keep_langs = set(args.langs.split(",")) + languages = [lang for lang in languages if lang in keep_langs] + assert len(languages) == len(keep_langs) + + return languages, data_path + + @classmethod + def setup_dictionary(cls, args, **kwargs): + dictionary = None + output_dictionary = None + if args.data: + paths = utils.split_paths(args.data) + assert len(paths) > 0 + dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) + if args.add_bos_token: + languages, _ = cls._get_langs(args) + logger.info('----------------') + for lang in languages: + dictionary.add_symbol(lang_token(lang)) + logger.info(f'add language token: {lang_token(lang)}') + logger.info('----------------') + + logger.info("dictionary: {} types".format(len(dictionary))) + output_dictionary = dictionary + if args.output_dictionary_size >= 0: + output_dictionary = TruncatedDictionary( + dictionary, args.output_dictionary_size + ) + return (dictionary, output_dictionary) + + @classmethod + def setup_task(cls, args, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + args (argparse.Namespace): parsed command-line arguments + """ + dictionary, output_dictionary = cls.setup_dictionary(args, **kwargs) + + # upgrade old checkpoints + if hasattr(args, "exclude_self_target"): + args.self_target = not args.exclude_self_target + + targets = [] + if getattr(args, "self_target", False): + targets.append("self") + if getattr(args, "future_target", False): + targets.append("future") + if getattr(args, "past_target", False): + targets.append("past") + if len(targets) == 0: + # standard language modeling + targets = ["future"] + + return cls(args, dictionary, output_dictionary, targets=targets) + + def build_model(self, args): + model = super().build_model(args) + for target in self.targets: + if target not in model.supported_targets: + raise ValueError( + f"Unsupported language modeling target: {target} not in {model.supported_targets}" + ) + + return model + + def _get_sample_prob(self, dataset_lens): + """ + Get smoothed sampling porbability by languages. This helps low resource + languages by upsampling them. + """ + prob = dataset_lens / dataset_lens.sum() + smoothed_prob = prob ** self.args.multilang_sampling_alpha + smoothed_prob = smoothed_prob / smoothed_prob.sum() + return smoothed_prob + + def load_dataset( + self, split: str, epoch=1, combine=False, **kwargs + ): + """Load a given dataset split. + + Args: + split (str): name of the split (e.g., train, valid, test) + """ + languages, data_path = MultilingualLanguageModelingTask._get_langs( + self.args, epoch + ) + lang_to_offline_shard_ratio = None + if self.args.lang_to_offline_shard_ratio != "": + lang_to_offline_shard_ratio = {} + assert os.path.exists( + self.args.lang_to_offline_shard_ratio + ), "provided offline shard ratio file doesn't exist: {0}".format(self.args.lang_to_offline_shard_ratio) + with open(self.args.lang_to_offline_shard_ratio) as fin: + for line in fin: + lang, ratio = line.strip().split('\t') + ratio = float(ratio) + lang_to_offline_shard_ratio[lang] = ratio + + logger.info( + "Found offline sharded ratio: %s", lang_to_offline_shard_ratio, + ) + + if split == self.args.train_subset: + logger.info("Training on {0} languages: {1}".format(len(languages), languages)) + else: + logger.info("Evaluating on {0} languages: {1}".format(len(languages), languages)) + + tokens_per_sample = self.args.tokens_per_sample - int(self.args.add_bos_token) + + fixed_pad_length = None + if self.args.pad_to_fixed_length: + fixed_pad_length = self.args.tokens_per_sample + + pad_to_bsz = None + if self.args.pad_to_fixed_bsz: + pad_to_bsz = ( + self.args.batch_size_valid if "valid" in split else self.args.batch_size + ) + + lang_datasets = [] + for lang_id, language in enumerate(languages): + split_path = os.path.join(data_path, language, split) + dataset = data_utils.load_indexed_dataset( + split_path, self.dictionary, self.args.dataset_impl, combine=combine + ) + # print('len(dataset) =', len(dataset)) + if dataset is None: + raise FileNotFoundError( + "Dataset not found: {} ({})".format(split, split_path) + ) + + dataset = maybe_shorten_dataset( + dataset, + split, + self.args.shorten_data_split_list, + self.args.shorten_method, + tokens_per_sample, + self.args.seed, + ) + + dataset = TokenBlockDataset( + dataset, + dataset.sizes, + tokens_per_sample, + pad=self.dictionary.pad(), + eos=self.dictionary.eos(), + break_mode=self.args.sample_break_mode, + include_targets=True, + ) + + add_eos_for_other_targets = ( + self.args.sample_break_mode is not None + and self.args.sample_break_mode != "none" + ) + src_lang_idx, tgt_lang_idx = None, None + if self.args.add_bos_token: + src_lang_idx = self.dictionary.index(lang_token(language)) + tgt_lang_idx = self.output_dictionary.index(lang_token(language)) + + lang_datasets.append( + MonolingualDataset( + dataset=dataset, + sizes=dataset.sizes, + src_vocab=self.dictionary, + tgt_vocab=self.output_dictionary, + add_eos_for_other_targets=add_eos_for_other_targets, + shuffle=True, + targets=self.targets, + fixed_pad_length=fixed_pad_length, + pad_to_bsz=pad_to_bsz, + add_bos_token=self.args.add_bos_token, + src_lang_idx=src_lang_idx, + tgt_lang_idx=tgt_lang_idx, + ) + ) + + dataset_lengths = np.array( + [len(d) for d in lang_datasets], + dtype=float, + ) + logger.info( + "loaded total {} blocks for all languages".format( + dataset_lengths.sum(), + ) + ) + if split == self.args.train_subset: + dataset_lengths_ratio_multiplier = np.ones(len(dataset_lengths)) + if lang_to_offline_shard_ratio is not None: + dataset_lengths_ratio_multiplier = [] + for lang in languages: + assert lang in lang_to_offline_shard_ratio, "Lang: {0} missing in offline shard ratio file: {1}".format( + lang, self.args.lang_to_offline_shard_ratio, + ) + dataset_lengths_ratio_multiplier.append(lang_to_offline_shard_ratio[lang]) + dataset_lengths_ratio_multiplier = np.array(dataset_lengths_ratio_multiplier) + true_dataset_lengths = dataset_lengths * dataset_lengths_ratio_multiplier + else: + true_dataset_lengths = dataset_lengths + # For train subset, additionally up or down sample languages. + sample_probs = self._get_sample_prob(true_dataset_lengths) + + logger.info( + "Sample probability by language: %s", + { + lang: "{0:.4f}".format(sample_probs[id]) + for id, lang in enumerate(languages) + }, + ) + size_ratio = (sample_probs * true_dataset_lengths.sum()) / dataset_lengths + # TODO: add an option for shrinking all size ratios to below 1 + # if self.args.multilang_sampling_alpha != 1: + # size_ratio /= size_ratio.max() + + # Fix numeric errors in size ratio computation + # 0.999999999999999999 -> 1 + # 1.000000000000000002 -> 1 + for i in range(len(size_ratio)): + size_ratio[i] = round(size_ratio[i], 8) + + logger.info( + "Up/Down Sampling ratio by language: %s", + { + lang: "{0:.2f}".format(size_ratio[id]) + for id, lang in enumerate(languages) + }, + ) + logger.info( + "Actual dataset size by language: %s", + { + lang: "{0:.2f}".format(len(lang_datasets[id])) + for id, lang in enumerate(languages) + }, + ) + resampled_lang_datasets = [ + ResamplingDataset( + lang_datasets[i], + size_ratio=size_ratio[i], + seed=self.args.seed, + epoch=epoch, + replace=size_ratio[i] > 1.0, + ) + for i, d in enumerate(lang_datasets) + ] + logger.info( + "Resampled dataset size by language: %s", + { + lang: "{0:.2f}".format(len(resampled_lang_datasets[id])) + for id, lang in enumerate(languages) + }, + ) + dataset = ConcatDataset(resampled_lang_datasets) + else: + dataset = ConcatDataset(lang_datasets) + lang_splits = [split] + for lang_id, lang_dataset in enumerate(lang_datasets): + split_name = split + "_" + languages[lang_id] + lang_splits.append(split_name) + self.datasets[split_name] = lang_dataset + + # [TODO]: This is hacky for now to print validation ppl for each + # language individually. Maybe need task API changes to allow it + # in more generic ways. + if split in self.args.valid_subset: + self.args.valid_subset = self.args.valid_subset.replace( + split, ",".join(lang_splits) + ) + + with data_utils.numpy_seed(self.args.seed + epoch): + shuffle = np.random.permutation(len(dataset)) + + self.datasets[split] = SortDataset( + dataset, + sort_order=[ + shuffle, + dataset.sizes, + ], + ) + + def build_dataset_for_inference(self, src_tokens, src_lengths, language="en_XX", **kwargs): + """ + Generate batches for inference. We prepend an eos token to src_tokens + (or bos if `--add-bos-token` is set) and we append a <pad> to target. + This is convenient both for generation with a prefix and LM scoring. + """ + dataset = StripTokenDataset( + TokenBlockDataset( + src_tokens, + src_lengths, + block_size=None, # ignored for "eos" break mode + pad=self.source_dictionary.pad(), + eos=self.source_dictionary.eos(), + break_mode="eos", + ), + # remove eos from (end of) target sequence + self.source_dictionary.eos(), + ) + + src_lang_idx = self.dictionary.index(lang_token(language)) + src_dataset = PrependTokenDataset( + dataset, + token=( + (src_lang_idx or self.source_dictionary.bos()) + if getattr(self.args, "add_bos_token", False) + else self.source_dictionary.eos() + ), + ) + + max_seq_len = max(src_lengths) + 1 + tgt_dataset = AppendTokenDataset(dataset, token=self.source_dictionary.pad()) + return NestedDictionaryDataset( + { + "id": IdDataset(), + "net_input": { + "src_tokens": PadDataset( + src_dataset, + pad_idx=self.source_dictionary.pad(), + left_pad=False, + pad_length=max_seq_len + ), + "src_lengths": NumelDataset(src_dataset, reduce=False), + }, + "target": PadDataset( + tgt_dataset, pad_idx=self.source_dictionary.pad(), left_pad=False, pad_length=max_seq_len, + ), + }, + sizes=[np.array(src_lengths)], + ) + + @torch.no_grad() + def inference_step( + self, generator, models, sample, language="en_XX", prefix_tokens=None, constraints=None + ): + # Generation will always be conditioned on bos_token + if getattr(self.args, "add_bos_token", False): + src_lang_idx = self.dictionary.index(lang_token(language)) + bos_token = src_lang_idx or self.source_dictionary.bos() + else: + bos_token = self.source_dictionary.eos() + + if constraints is not None: + raise NotImplementedError( + "Constrained decoding with the language_modeling task is not supported" + ) + + # SequenceGenerator doesn't use src_tokens directly, we need to + # pass the `prefix_tokens` argument instead + if prefix_tokens is None and sample["net_input"]["src_tokens"].nelement(): + prefix_tokens = sample["net_input"]["src_tokens"] + if prefix_tokens[:, 0].eq(bos_token).all(): + prefix_tokens = prefix_tokens[:, 1:] + + return generator.generate( + models, sample, prefix_tokens=prefix_tokens, bos_token=bos_token + ) + + def eval_lm_dataloader( + self, + dataset, + max_tokens: Optional[int] = 36000, + batch_size: Optional[int] = None, + max_positions: Optional[int] = None, + num_shards: int = 1, + shard_id: int = 0, + num_workers: int = 1, + data_buffer_size: int = 10, + # ensures that every evaluated token has access to a context of at least + # this size, if possible + context_window: int = 0, + ): + if context_window > 0: + dataset = LMContextWindowDataset( + dataset=dataset, + tokens_per_sample=self.args.tokens_per_sample, + context_window=context_window, + pad_idx=self.source_dictionary.pad(), + ) + return self.get_batch_iterator( + dataset=dataset, + max_tokens=max_tokens, + max_sentences=batch_size, + max_positions=max_positions, + ignore_invalid_inputs=True, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + data_buffer_size=data_buffer_size, + ) + + @property + def source_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.dictionary + + @property + def target_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.output_dictionary \ No newline at end of file diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 1d5b6e62bc..5bdf5578af 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -21,8 +21,92 @@ preprocess_lm_data, preprocess_translation_data, train_translation_model, + train_language_model, ) +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestMultiGPU(unittest.TestCase): + + @staticmethod + def parse_logs(logfile): + logs = [] + for ln in open(logfile, "r").readlines(): + try: + logs.append(json.loads(ln)) + except json.JSONDecodeError: + continue + return logs + + @property + def world_size(self): + return torch.cuda.device_count() + + def train_flags(self, mu): + return [ + "--memory-efficient-fp16", + '--update-freq', '1', + '--seed', '1', + "--log-format", "json", + "--max-update", str(mu), + "--tokens-per-sample", "20", + "--batch-size", "2", + '--share-decoder-input-output-embed', + '--optimizer', 'adam', + '--max-valid-steps', '1', + '--pad-to-fixed-length', + '--sample-break-mode', 'none', + ] + + def _test_resume_multilingual_training(self, extra_clargs, arch="transformer_lm_gpt2_tiny"): + languages = ["en_XX", "fr_XX", "zh_CN"] + save_interval = 5 + mu = 10 + flags = self.train_flags(mu) + [ + "--save-interval-updates", str(save_interval), + "--log-interval", "1" + ] + extra_clargs + with contextlib.redirect_stdout(StringIO()): + with tempfile.TemporaryDirectory("test_fp16") as data_dir: + log = os.path.join(data_dir, "train.log") + create_dummy_data(data_dir, + num_examples=int(mu * 20 * self.world_size * 1.5), # make sure enough data for max updates + languages=languages) + preprocess_lm_data(data_dir, languages) + train_language_model( + data_dir, arch, + flags + ["--log-file", log], + task="multilingual_language_modeling", + world_size=self.world_size, + ) + log2 = os.path.join(data_dir, "resume.log") + ckpt_name = f"checkpoint_1_{save_interval}.pt" + restore_file = os.path.join(data_dir, ckpt_name) + train_language_model( + data_dir, arch, + flags + ["--log-file", log2, "--restore-file", restore_file, '--no-save'], + task="multilingual_language_modeling", + world_size=self.world_size, + ) + + l1 = self.parse_logs(log) + assert int(l1[-1]['train_num_updates']) == mu, f'The first run did not complete {mu} updates. Add more data' + l2 = self.parse_logs(log2) + + if int(l2[0]["num_updates"]) != save_interval+1: + all_ckpt_files = [x for x in os.listdir(data_dir) if x.endswith('.pt')] + import shutil + shutil.move(data_dir, 'last_failed_resume') + raise AssertionError(f"Likely failed to load {ckpt_name}. {all_ckpt_files} \n LOGS: {l1} \n\n {l2}. ") + for k in [ + "train_loss", + "train_num_updates", + "train_ppl", + "train_gnorm", + ]: + from_scratch, resumed = float(l1[-1][k]), float(l2[-1][k]) + # This fails without rounding! + assert from_scratch == resumed, f"difference at {k} {from_scratch} != {resumed}" + @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") class TestTranslationGPU(unittest.TestCase): diff --git a/tests/utils.py b/tests/utils.py index ce2e361d9b..4c0dae8c72 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -7,6 +7,7 @@ import json import os import random +import shutil import sys from io import StringIO @@ -163,11 +164,11 @@ def sequence_generator_setup(): return tgt_dict, w1, w2, src_tokens, src_lengths, model -def create_dummy_data(data_dir, num_examples=100, maxlen=20, alignment=False): - def _create_dummy_data(filename): +def create_dummy_data(data_dir, num_examples=100, maxlen=20, alignment=False, languages=None): + def _create_dummy_data(dir, filename): data = torch.rand(num_examples * maxlen) data = 97 + torch.floor(26 * data).int() - with open(os.path.join(data_dir, filename), "w") as h: + with open(os.path.join(dir, filename), "w") as h: offset = 0 for _ in range(num_examples): ex_len = random.randint(1, maxlen) @@ -194,12 +195,16 @@ def _create_dummy_alignment_data(filename_src, filename_tgt, filename): ) print(ex_str, file=h) - _create_dummy_data("train.in") - _create_dummy_data("train.out") - _create_dummy_data("valid.in") - _create_dummy_data("valid.out") - _create_dummy_data("test.in") - _create_dummy_data("test.out") + files_to_write = ['train.in', 'train.out', 'valid.in', 'valid.out', 'test.in', 'test.out'] + if languages is None: # En only dummy dataset + for f in files_to_write: + _create_dummy_data(data_dir, f) + else: + for lang in languages: + lang_dir = os.path.join(data_dir, lang) + os.makedirs(lang_dir, exist_ok=True) + for f in files_to_write: + _create_dummy_data(lang_dir, f) if alignment: _create_dummy_alignment_data("train.in", "train.out", "train.align") @@ -207,22 +212,44 @@ def _create_dummy_alignment_data(filename_src, filename_tgt, filename): _create_dummy_alignment_data("test.in", "test.out", "test.align") -def preprocess_lm_data(data_dir): +def preprocess_lm_data(data_dir, languages=None): preprocess_parser = options.get_preprocessing_parser() - preprocess_args = preprocess_parser.parse_args( - [ - "--only-source", - "--trainpref", - os.path.join(data_dir, "train.out"), - "--validpref", - os.path.join(data_dir, "valid.out"), - "--testpref", - os.path.join(data_dir, "test.out"), - "--destdir", - data_dir, - ] - ) - preprocess.main(preprocess_args) + if languages is None: + preprocess_args = preprocess_parser.parse_args( + [ + "--only-source", + "--trainpref", + os.path.join(data_dir, "train.out"), + "--validpref", + os.path.join(data_dir, "valid.out"), + "--testpref", + os.path.join(data_dir, "test.out"), + "--destdir", + data_dir, + ] + ) + preprocess.main(preprocess_args) + else: + for lang in languages: + lang_dir = os.path.join(data_dir, lang) + assert(os.path.exists(lang_dir)) + preprocess_args = preprocess_parser.parse_args( + [ + "--only-source", + "--trainpref", + os.path.join(lang_dir, "train.out"), + "--validpref", + os.path.join(lang_dir, "valid.out"), + "--testpref", + os.path.join(lang_dir, "test.out"), + "--destdir", + lang_dir, + ] + ) + preprocess.main(preprocess_args) + shutil.copyfile( + os.path.join(data_dir, languages[0], 'dict.txt'), os.path.join(data_dir, 'dict.txt')) + def preprocess_translation_data(data_dir, extra_flags=None): From 98ebe4f1ada75d006717d84f9d603519d8ff5579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerard=20I=2E=20G=C3=A1llego?= <gerard.gaol@gmail.com> Date: Tue, 21 Dec 2021 18:17:24 -0800 Subject: [PATCH 525/774] Fix bugs in MuST-C preprocessing (#3887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [X] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [X] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/3882 Fixes https://github.com/pytorch/fairseq/issues/3884 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3887 Reviewed By: yuntang Differential Revision: D33152073 Pulled By: kahne fbshipit-source-id: 7f5c90a9876320e7c5c406ed032681452c7c5056 --- examples/speech_to_text/data_utils.py | 3 ++- examples/speech_to_text/prep_mustc_data.py | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index 07d24f8d22..c9c69e2b46 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -80,7 +80,7 @@ def extract_fbank_features( if output_path is not None and output_path.is_file() and not overwrite: return - _waveform = convert_waveform(waveform, sample_rate, to_mono=True) + _waveform, _ = convert_waveform(waveform, sample_rate, to_mono=True) # Kaldi compliance: 16-bit signed integers _waveform = _waveform * (2 ** 15) _waveform = _waveform[0].numpy() @@ -100,6 +100,7 @@ def extract_fbank_features( def create_zip(data_root: Path, zip_path: Path): paths = list(data_root.glob("*.npy")) + paths.extend(data_root.glob("*.flac")) with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_STORED) as f: for path in tqdm(paths): f.write(path, arcname=path.name) diff --git a/examples/speech_to_text/prep_mustc_data.py b/examples/speech_to_text/prep_mustc_data.py index 3f0d3fcbd9..c2362f76fa 100644 --- a/examples/speech_to_text/prep_mustc_data.py +++ b/examples/speech_to_text/prep_mustc_data.py @@ -129,7 +129,7 @@ def process(args): ) sf.write( (audio_root / f"{utt_id}.flac").as_posix(), - _wavform.numpy(), tgt_sample_rate + _wavform.T.numpy(), tgt_sample_rate ) else: print("Extracting log mel filter bank features...") @@ -156,7 +156,10 @@ def process(args): print("ZIPing audios/features...") create_zip(audio_root, zip_path) print("Fetching ZIP manifest...") - audio_paths, audio_lengths = get_zip_manifest(zip_path) + audio_paths, audio_lengths = get_zip_manifest( + zip_path, + is_audio=args.use_audio_input, + ) # Generate TSV manifest print("Generating manifest...") train_text = [] From ca36b437e463c9f202efacd67ce80ae201361dc8 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Wed, 22 Dec 2021 15:44:37 -0800 Subject: [PATCH 526/774] add METEOR scorer; fix chrF scorer config Summary: add METEOR scorer; fix chrF scorer config Reviewed By: hygong-fb Differential Revision: D33273312 fbshipit-source-id: 3fcb5b2479fb6cc90e9f0235886c658e0c586fba --- fairseq/scoring/chrf.py | 11 +++++++++- fairseq/scoring/meteor.py | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 fairseq/scoring/meteor.py diff --git a/fairseq/scoring/chrf.py b/fairseq/scoring/chrf.py index 0d6cb77383..5df5a1c011 100644 --- a/fairseq/scoring/chrf.py +++ b/fairseq/scoring/chrf.py @@ -3,10 +3,19 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass + +from fairseq.dataclass import FairseqDataclass from fairseq.scoring import BaseScorer, register_scorer -@register_scorer("chrf") +@dataclass +class ChrFScorerConfig(FairseqDataclass): + pass + + +@register_scorer("chrf", dataclass=ChrFScorerConfig) class ChrFScorer(BaseScorer): def __init__(self, args): super(ChrFScorer, self).__init__(args) diff --git a/fairseq/scoring/meteor.py b/fairseq/scoring/meteor.py new file mode 100644 index 0000000000..32719956fe --- /dev/null +++ b/fairseq/scoring/meteor.py @@ -0,0 +1,42 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +from dataclasses import dataclass + +from fairseq.dataclass import FairseqDataclass +from fairseq.scoring import BaseScorer, register_scorer + + +@dataclass +class MeteorScorerConfig(FairseqDataclass): + pass + + +@register_scorer("meteor", dataclass=MeteorScorerConfig) +class MeteorScorer(BaseScorer): + def __init__(self, args): + super(MeteorScorer, self).__init__(args) + try: + import nltk + except ImportError: + raise ImportError("Please install nltk to use METEOR scorer") + + self.nltk = nltk + self.scores = [] + + def add_string(self, ref, pred): + self.ref.append(ref) + self.pred.append(pred) + + def score(self, order=4): + self.scores = [ + self.nltk.translate.meteor_score.single_meteor_score(r, p) + for r, p in zip(self.ref, self.pred) + ] + return np.mean(self.scores) + + def result_string(self, order=4): + return f"METEOR: {self.score():.4f}" From 0b128f42178e53ea0c61b814d678d6862bca82d1 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 23 Dec 2021 23:42:21 -0800 Subject: [PATCH 527/774] update ignore_prefix_size in label_smoothed_cross_entropy Summary: update ignore_prefix_size in label_smoothed_cross_entropy - lprobs is always B x T x C in the current models - lprobs.batch_first was default to `False` which contradicts the fact above Reviewed By: sravyapopuri388 Differential Revision: D33304121 fbshipit-source-id: 9391b48c7036642d9741d254b03c46389a4fe584 --- fairseq/criterions/label_smoothed_cross_entropy.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fairseq/criterions/label_smoothed_cross_entropy.py b/fairseq/criterions/label_smoothed_cross_entropy.py index 56d63e3e1b..cb43be0ca5 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy.py +++ b/fairseq/criterions/label_smoothed_cross_entropy.py @@ -98,12 +98,9 @@ def get_lprobs_and_target(self, model, net_output, sample): lprobs = model.get_normalized_probs(net_output, log_probs=True) target = model.get_targets(sample, net_output) if self.ignore_prefix_size > 0: - if getattr(lprobs, "batch_first", False): - lprobs = lprobs[:, self.ignore_prefix_size :, :].contiguous() - target = target[:, self.ignore_prefix_size :].contiguous() - else: - lprobs = lprobs[self.ignore_prefix_size :, :, :].contiguous() - target = target[self.ignore_prefix_size :, :].contiguous() + # lprobs: B x T x C + lprobs = lprobs[:, self.ignore_prefix_size :, :].contiguous() + target = target[:, self.ignore_prefix_size :].contiguous() return lprobs.view(-1, lprobs.size(-1)), target.view(-1) def compute_loss(self, model, net_output, sample, reduce=True): From 87d0ede93c06f564b7b985c1a9a0489ae946313d Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Fri, 24 Dec 2021 00:06:35 -0800 Subject: [PATCH 528/774] fix evaluation tokenizer for sacrebleu >= 2.0.0 Summary: fix evaluation tokenizer for sacrebleu >= 2.0.0 Reviewed By: sravyapopuri388 Differential Revision: D33306119 fbshipit-source-id: c0d0d45df201de7a869aae1680b7ae49b590414a --- fairseq/scoring/tokenizer.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/fairseq/scoring/tokenizer.py b/fairseq/scoring/tokenizer.py index 61cf6d4a7c..2aee4a7784 100644 --- a/fairseq/scoring/tokenizer.py +++ b/fairseq/scoring/tokenizer.py @@ -5,8 +5,12 @@ import unicodedata +import sacrebleu as sb + from fairseq.dataclass import ChoiceEnum +SACREBLEU_V2_ABOVE = int(sb.__version__[0]) >= 2 + class EvaluationTokenizer(object): """A generic evaluation-time tokenizer, which leverages built-in tokenizers @@ -24,7 +28,9 @@ class EvaluationTokenizer(object): SPACE = chr(32) SPACE_ESCAPE = chr(9601) - ALL_TOKENIZER_TYPES = ChoiceEnum(["none", "13a", "intl", "zh", "ja-mecab"]) + _ALL_TOKENIZER_TYPES = sb.BLEU.TOKENIZERS if SACREBLEU_V2_ABOVE \ + else ["none", "13a", "intl", "zh", "ja-mecab"] + ALL_TOKENIZER_TYPES = ChoiceEnum(_ALL_TOKENIZER_TYPES) def __init__( self, @@ -33,13 +39,16 @@ def __init__( punctuation_removal: bool = False, character_tokenization: bool = False, ): - from sacrebleu.tokenizers import TOKENIZERS - assert tokenizer_type in TOKENIZERS, f"{tokenizer_type}, {TOKENIZERS}" + assert tokenizer_type in self._ALL_TOKENIZER_TYPES, \ + f"{tokenizer_type}, {self._ALL_TOKENIZER_TYPES}" self.lowercase = lowercase self.punctuation_removal = punctuation_removal self.character_tokenization = character_tokenization - self.tokenizer = TOKENIZERS[tokenizer_type] + if SACREBLEU_V2_ABOVE: + self.tokenizer = sb.BLEU(tokenize=str(tokenizer_type)).tokenizer + else: + self.tokenizer = sb.tokenizers.TOKENIZERS[tokenizer_type]() @classmethod def remove_punctuation(cls, sent: str): @@ -51,7 +60,7 @@ def remove_punctuation(cls, sent: str): ) def tokenize(self, sent: str): - tokenized = self.tokenizer()(sent) + tokenized = self.tokenizer(sent) if self.punctuation_removal: tokenized = self.remove_punctuation(tokenized) From 5cd7a21cc138320dd850f6ee25593a6d3fef49fc Mon Sep 17 00:00:00 2001 From: Ann Lee <annl@fb.com> Date: Tue, 28 Dec 2021 08:06:46 -0800 Subject: [PATCH 529/774] S2ST oss (#2756) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Releasing code, model & recipe for the work "Direct speech-to-speech translation with discrete units". Main changes: 1. examples/speech_to_speech 2. tasks/speech_to_speech 3. data/audio/speech_to_speech_dataset 4. models/speech_to_speech 5. criterions/speech_to_speech_criterion ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2756 Reviewed By: sravyapopuri388, kahne Differential Revision: D32923969 Pulled By: an918tw fbshipit-source-id: 838ba42457f4684e9767d15b5b514681a9572b39 --- README.md | 1 + examples/speech_to_speech/README.md | 183 +++++++++++++++++- .../preprocessing/__init__.py | 4 + .../preprocessing/data_utils.py | 70 +++++++ .../preprocessing/prep_s2spect_data.py | 169 ++++++++++++++++ .../preprocessing/prep_s2ut_data.py | 128 ++++++++++++ .../textless_nlp/gslm/speech2unit/README.md | 4 +- fairseq/data/audio/data_cfg.py | 5 +- .../audio/feature_transforms/delta_deltas.py | 37 ++++ fairseq/models/text_to_speech/vocoder.py | 1 + 10 files changed, 594 insertions(+), 8 deletions(-) create mode 100644 examples/speech_to_speech/preprocessing/__init__.py create mode 100644 examples/speech_to_speech/preprocessing/data_utils.py create mode 100644 examples/speech_to_speech/preprocessing/prep_s2spect_data.py create mode 100644 examples/speech_to_speech/preprocessing/prep_s2ut_data.py create mode 100644 fairseq/data/audio/feature_transforms/delta_deltas.py diff --git a/README.md b/README.md index 8d60fbd8ea..f1db14a96e 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ We provide reference implementations of various sequence modeling papers: </p></details> ### What's New: +* December 2021 [Released Direct speech-to-speech translation code](examples/speech_to_speech/README.md) * October 2021 [Released VideoCLIP and VLM models](examples/MMPT/README.md) * October 2021 [Released multilingual finetuned XLSR-53 model](examples/wav2vec/README.md) * September 2021 [`master` branch renamed to `main`](https://github.com/github/renaming). diff --git a/examples/speech_to_speech/README.md b/examples/speech_to_speech/README.md index bb4e087f2c..2a055a605b 100644 --- a/examples/speech_to_speech/README.md +++ b/examples/speech_to_speech/README.md @@ -1,4 +1,181 @@ -# Speech to speech translation +# Speech to speech translation (S2ST) -## Direct speech-to-speech translation with discrete units -[https://arxiv.org/abs/2107.05604](https://arxiv.org/abs/2107.05604) +We provide the implementation for speech-to-unit translation (S2UT) proposed in "[Direct speech-to-speech translation with discrete units (Lee et al. 2021)](https://arxiv.org/abs/2107.05604)" and also the transformer-based implementation of the speech-to-spectrogram translation (S2SPECT, or transformer-based [Translatotron](https://arxiv.org/abs/1904.06037)) baseline in the paper. + +## Pretrained Models + +### Unit-based HiFi-GAN Vocoder +Unit config | Unit size | Vocoder dataset | Model +|---|---|---|--- +[HuBERT Base, Librispeech](https://github.com/fairinternal/fairseq-py/tree/main/examples/hubert), layer 6 | 100 | [LJSpeech](https://keithito.com/LJ-Speech-Dataset/) | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/hubert_base_100_lj/g_00500000), [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/hubert_base_100_lj/config.json) + + +## Data preparation +### Target speech +0. (optional) To prepare S2S data from a speech-to-text translation (ST) dataset, see [fairseq-S^2](https://github.com/pytorch/fairseq/tree/main/examples/speech_synthesis) for pre-trained TTS models and instructions on how to train and decode TTS models. +1. Prepare two folders, `$SRC_AUDIO` and `$TGT_AUDIO`, with `${SPLIT}/${SAMPLE_ID}.wav` for source and target speech under each folder, separately. Note that for S2UT experiments, target audio sampling rate should be in 16,000 Hz, and for S2SPECT experiments, target audio sampling rate is recommended to be in 22,050 Hz. +2. To prepare target discrete units for S2UT model training, see [Generative Spoken Language Modeling (speech2unit)](https://github.com/pytorch/fairseq/tree/main/examples/textless_nlp/gslm/speech2unit) for pre-trained k-means models, checkpoints, and instructions on how to decode units from speech. Set the output target unit files (`--out_quantized_file_path`) as `${TGT_AUDIO}/${SPLIT}.txt`. In [Lee et al. 2021](https://arxiv.org/abs/2107.05604), we use 100 units from the sixth layer (`--layer 6`) of the HuBERT Base model. + +### Formatting data +**Speech-to-speech data** + +_S2UT_ + * Set `--reduce-unit` for training S2UT _reduced_ model + * Pre-trained vocoder and config (`$VOCODER_CKPT`, `$VOCODER_CFG`) can be downloaded from the **Pretrained Models** section. They are not required if `--eval-inference` is not going to be set during model training. +``` +# $SPLIT1, $SPLIT2, etc. are split names such as train, dev, test, etc. + +python examples/speech_to_speech/preprocessing/prep_s2ut_data.py \ + --source-dir $SRC_AUDIO --target-dir $TGT_AUDIO --data-split $SPLIT1 $SPLIT2 \ + --output-root $DATA_ROOT --reduce-unit \ + --vocoder-checkpoint $VOCODER_CKPT --vocoder-cfg $VOCODER_CFG +``` + +_S2SPECT_ +``` +# $SPLIT1, $SPLIT2, etc. are split names such as train, dev, test, etc. + +python examples/speech_to_speech/preprocessing/prep_s2spect_data.py \ + --source-dir $SRC_AUDIO --target-dir $TGT_AUDIO --data-split $SPLIT1 $SPLIT2 \ + --output-root $DATA_ROOT +``` + +**Multitask data** + * For each multitask `$TASK_NAME`, prepare `${DATA_ROOT}/${TASK_NAME}/${SPLIT}.tsv` files for each split following the format below: (Two tab separated columns. The sample_ids should match with the sample_ids for the speech-to-speech data in `${DATA_ROOT}/${SPLIT}.tsv`.) +``` +id tgt_text +sample_id_0 token1 token2 token3 ... +sample_id_1 token1 token2 token3 ... +... +``` + * For each multitask `$TASK_NAME`, prepare `${DATA_ROOT}/${TASK_NAME}/dict.txt`, a dictionary in fairseq format with all tokens for the targets for `$TASK_NAME`. + * Create `config_multitask.yaml`. Below is an example of the config used for S2UT _reduced_ with Fisher experiments including two encoder multitasks (`source_letter`, `target_letter`) and one decoder CTC task (`decoder_target_ctc`). +``` +source_letter: # $TASK_NAME + decoder_type: transformer + dict: ${DATA_ROOT}/source_letter/dict.txt + data: ${DATA_ROOT}/source_letter + encoder_layer: 6 + loss_weight: 8.0 +target_letter: + decoder_type: transformer + dict: ${DATA_ROOT}/target_letter/dict.txt + data: ${DATA_ROOT}/target_letter + encoder_layer: 8 + loss_weight: 8.0 +decoder_target_ctc: + decoder_type: ctc + dict: ${DATA_ROOT}/decoder_target_ctc/dict.txt + data: ${DATA_ROOT}/decoder_target_ctc + decoder_layer: 3 + loss_weight: 1.6 +``` + + +## Training + +**Speech-to-unit translation (S2UT)** + +Here's an example for training Fisher S2UT models with 100 discrete units as target: +``` +fairseq-train $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --target-is-code --target-code-size 100 --vocoder code_hifigan \ + --criterion speech_to_unit --label-smoothing 0.2 \ + --arch s2ut_transformer_fisher --share-decoder-input-output-embed \ + --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.1 \ + --train-subset train --valid-subset dev \ + --save-dir ${MODEL_DIR} \ + --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-7 --warmup-updates 10000 \ + --optimizer adam --adam-betas "(0.9,0.98)" --clip-norm 10.0 \ + --max-update 400000 --max-tokens 20000 --max-target-positions 3000 --update-freq 4 \ + --seed 1 --fp16 --num-workers 8 +``` +* Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 4` to simulate training with 4 GPUs. +* Set `--n-frames-per-step 5` to train an S2UT _stacked_ system with reduction ratio r=5. (Use `$DATA_ROOT` prepared without `--reduce-unit`.) +* (optional) one can turn on tracking MCD loss during training for checkpoint selection by setting `--eval-inference --eval-args '{"beam": 1, "max_len_a": 1}' --best-checkpoint-metric mcd_loss`. It is recommended to sample a smaller subset as the validation set as MCD loss computation is time-consuming. + +**Speech-to-spectrogram translation (S2SPECT)** + +Here's an example for training Fisher S2SPECT models with reduction ratio r=5: +``` +fairseq-train $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --n-frames-per-step 5 \ + --criterion speech_to_spectrogram \ + --arch s2spect_transformer_fisher --decoder-normalize-before \ + --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.1 \ + --train-subset train --valid-subset dev \ + --save-dir ${MODEL_DIR} \ + --eval-inference --best-checkpoint-metric mcd_loss \ + --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-7 --warmup-updates 10000 \ + --optimizer adam --adam-betas "(0.9,0.98)" --clip-norm 10.0 --weight-decay 1e-6 \ + --max-update 400000 --max-tokens 80000 --max-tokens-valid 30000 --required-batch-size-multiple 1 \ + --max-target-positions 3000 --update-freq 16 \ + --seed 1 --fp16 --num-workers 8 +``` +* Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 16` to simulate training with 16 GPUs. +* We recommend turning on MCD loss during training for the best checkpoint selection. + +**Unit-based HiFi-GAN vocoder** + +Coming soon. + +## Inference + +**Speech-to-unit translation (S2UT)** + +1. Follow the same inference process as in [fairseq-S2T](https://github.com/pytorch/fairseq/tree/main/examples/speech_to_text) to generate unit sequences (`${RESULTS_PATH}/generate-${GEN_SUBSET}.txt`). +``` +fairseq-generate $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --target-is-code --target-code-size 100 --vocoder code_hifigan \ + --path $MODEL_DIR/checkpoint_best.pt --gen-subset $GEN_SUBSET \ + --max-tokens 50000 \ + --beam 10 --max-len-a 1 \ + --results-path ${RESULTS_PATH} +``` + * Set `--beam 1 --n-frames-per-step $r` for decoding with S2UT _stacked_ models. + +2. Convert unit sequences to waveform. +``` +grep "^D\-" ${RESULTS_PATH}/generate-${GEN_SUBSET}.txt | \ + sed 's/^D-//ig' | sort -nk1 | cut -f3 \ + > ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit + +python examples/speech_to_speech/generate_waveform_from_code.py \ + --in-code-file ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit \ + --vocoder $VOCODER_CKPT --vocoder-cfg $VOCODER_CFG \ + --results-path ${RESULTS_PATH} --dur-prediction +``` + * Set `--dur-prediction` for generating audio for S2UT _reduced_ models. + + +**Speech-to-spectrogram translation (S2SPECT)** + +Follow the same inference process as in [fairseq-S^2](https://github.com/pytorch/fairseq/tree/main/examples/speech_synthesis) to generate waveform. + +``` +# assume using a default Griffin-Lim vocoder + +python examples/speech_synthesis/generate_waveform.py $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --n-frames-per-step 5 \ + --path $MODEL_DIR/checkpoint_best.pt --gen-subset $GEN_SUBSET \ + --max-tokens 50000 \ + --results-path ${RESULTS_PATH} --dump-waveforms --output-sample-rate 16000 +``` + +In addition to using the default Griffin-Lim vocoder, one can also finetune a HiFi-GAN vocoder for the S2SPECT model by following the instructions in the [HiFi-GAN repo](https://github.com/jik876/hifi-gan). + +**Multitask decoding** + +Coming soon. + +## Evaluation + +To evaluate speech translation output, we first apply ASR on the speech output and then compute BLEU score betweent the ASR decoded text and the references using sacreBLEU. + +**En** +* ASR: We use the "[Wav2Vec 2.0 Large (LV-60) + Self Training / 960 hours / Libri-Light + Librispeech](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt)" En ASR model open-sourced by the [wav2vec](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec) project. See [instructions](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#evaluating-a-ctc-model) on how to run inference with a wav2vec-based ASR model. The model is also available on [Hugging Face](https://huggingface.co/facebook/wav2vec2-large-960h-lv60-self). +* Text normalization: We use the text cleaner at [https://github.com/keithito/tacotron](https://github.com/keithito/tacotron) for pre-processing reference English text for ASR BLEU evaluation. diff --git a/examples/speech_to_speech/preprocessing/__init__.py b/examples/speech_to_speech/preprocessing/__init__.py new file mode 100644 index 0000000000..6264236915 --- /dev/null +++ b/examples/speech_to_speech/preprocessing/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/speech_to_speech/preprocessing/data_utils.py b/examples/speech_to_speech/preprocessing/data_utils.py new file mode 100644 index 0000000000..48fe57b742 --- /dev/null +++ b/examples/speech_to_speech/preprocessing/data_utils.py @@ -0,0 +1,70 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from pathlib import Path +from typing import List, Optional + +from examples.speech_to_text.data_utils import S2TDataConfigWriter + + +def gen_config_yaml( + manifest_root: Path, + yaml_filename: str = "config.yaml", + specaugment_policy: Optional[str] = "lb", + feature_transform: Optional[List[str]] = None, + input_channels: Optional[int] = 1, + input_feat_per_channel: Optional[int] = 80, + audio_root: str = "", + vocoder_type: Optional[str] = None, + vocoder_checkpoint: Optional[str] = None, + vocoder_cfg: Optional[str] = None, + extra=None, +): + manifest_root = manifest_root.absolute() + writer = S2TDataConfigWriter(manifest_root / yaml_filename) + + if input_channels is not None: + writer.set_input_channels(input_channels) + if input_feat_per_channel is not None: + writer.set_input_feat_per_channel(input_feat_per_channel) + specaugment_setters = { + "lb": writer.set_specaugment_lb_policy, + "ld": writer.set_specaugment_ld_policy, + "sm": writer.set_specaugment_sm_policy, + "ss": writer.set_specaugment_ss_policy, + } + specaugment_setter = specaugment_setters.get(specaugment_policy, None) + if specaugment_setter is not None: + specaugment_setter() + + if feature_transform is None: + feature_transform = [] + else: + writer.set_feature_transforms("*", feature_transform) + + if specaugment_policy is not None: + writer.set_feature_transforms("_train", feature_transform + ["specaugment"]) + + if len(audio_root) > 0: + writer.set_audio_root(audio_root) + + if ( + vocoder_type is not None + and vocoder_checkpoint is not None + and vocoder_cfg is not None + ): + writer.set_extra( + { + "vocoder": { + "type": vocoder_type, + "config": vocoder_cfg, + "checkpoint": vocoder_checkpoint, + } + } + ) + + if extra is not None: + writer.set_extra(extra) + writer.flush() diff --git a/examples/speech_to_speech/preprocessing/prep_s2spect_data.py b/examples/speech_to_speech/preprocessing/prep_s2spect_data.py new file mode 100644 index 0000000000..2748b37aef --- /dev/null +++ b/examples/speech_to_speech/preprocessing/prep_s2spect_data.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +import os +from pathlib import Path +import shutil +import torchaudio + +import soundfile as sf +from tqdm import tqdm +import pandas as pd + +from examples.speech_synthesis.data_utils import extract_logmel_spectrogram +from examples.speech_to_speech.preprocessing.data_utils import gen_config_yaml +from examples.speech_to_text.data_utils import create_zip, get_zip_manifest, save_df_to_tsv +from fairseq.data.audio.audio_utils import convert_waveform + + +logger = logging.getLogger(__name__) + +MANIFEST_COLUMNS = ["id", "src_audio", "src_n_frames", "tgt_audio", "tgt_n_frames"] + + +def prepare_target_data(args, tgt_audios): + feature_name = "logmelspec80" + zip_path = args.output_root / f"{feature_name}.zip" + if zip_path.exists(): + print(f"{zip_path} exists.") + return zip_path + + feature_root = args.output_root / feature_name + feature_root.mkdir(exist_ok=True) + + print("Extracting Mel spectrogram features...") + for tgt_audio in tqdm(tgt_audios): + sample_id = tgt_audio.stem + waveform, sample_rate = torchaudio.load(tgt_audio.as_posix()) + waveform, sample_rate = convert_waveform( + waveform, sample_rate, normalize_volume=args.normalize_volume, + to_sample_rate=args.sample_rate + ) + extract_logmel_spectrogram( + waveform, sample_rate, feature_root / f"{sample_id}.npy", + win_length=args.win_length, hop_length=args.hop_length, + n_fft=args.n_fft, n_mels=args.n_mels, f_min=args.f_min, + f_max=args.f_max + ) + print("ZIPing features...") + create_zip(feature_root, zip_path) + shutil.rmtree(feature_root) + + return zip_path + + +def process(args): + os.makedirs(args.output_root, exist_ok=True) + + manifest = {} + tgt_audios = [] + for split in args.data_split: + print(f"Processing {split}...") + + manifest[split] = {c: [] for c in MANIFEST_COLUMNS} + missing_tgt_audios = [] + src_audios = list(args.source_dir.glob(f"{split}/*.wav")) + for src_audio in tqdm(src_audios): + sample_id = src_audio.stem + + tgt_audio = args.target_dir / split / f"{sample_id}.wav" + if not tgt_audio.is_file(): + missing_tgt_audios.append(sample_id) + continue + + tgt_audios.append(tgt_audio) + + src_n_frames = sf.info(src_audio.as_posix()).frames + manifest[split]["id"].append(sample_id) + manifest[split]["src_audio"].append(src_audio.as_posix()) + manifest[split]["src_n_frames"].append( + src_n_frames // 160 + ) # estimation of 10-ms frame for 16kHz audio + + print(f"Processed {len(manifest[split]['id'])} samples") + if len(missing_tgt_audios) > 0: + print( + f"{len(missing_tgt_audios)} with missing target data (first 3 examples: {', '.join(missing_tgt_audios[:3])})" + ) + + # Extract features and pack features into ZIP + zip_path = prepare_target_data(args, tgt_audios) + + print("Fetching ZIP manifest...") + tgt_audio_paths, tgt_audio_lengths = get_zip_manifest(zip_path) + + print("Generating manifest...") + for split in args.data_split: + print(f"Processing {split}...") + + for sample_id in tqdm(manifest[split]["id"]): + manifest[split]["tgt_audio"].append(tgt_audio_paths[sample_id]) + manifest[split]["tgt_n_frames"].append(tgt_audio_lengths[sample_id]) + + out_manifest = args.output_root / f"{split}.tsv" + print(f"Writing manifest to {out_manifest}...") + save_df_to_tsv(pd.DataFrame.from_dict(manifest[split]), out_manifest) + + # Generate config YAML + win_len_t = args.win_length / args.sample_rate + hop_len_t = args.hop_length / args.sample_rate + extra = { + "features": { + "type": "spectrogram+melscale+log", + "sample_rate": args.sample_rate, + "eps": 1e-5, "n_mels": args.n_mels, "n_fft": args.n_fft, + "window_fn": "hann", "win_length": args.win_length, + "hop_length": args.hop_length, + "win_len_t": win_len_t, "hop_len_t": hop_len_t, + "f_min": args.f_min, "f_max": args.f_max, + "n_stft": args.n_fft // 2 + 1 + } + } + gen_config_yaml( + args.output_root, + audio_root=args.output_root.as_posix(), + specaugment_policy="lb", + feature_transform=["utterance_cmvn", "delta_deltas"], + extra=extra, + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--source-dir", required=True, type=Path, help="source audio directory" + ) + parser.add_argument( + "--target-dir", required=True, type=Path, help="target audio directory" + ) + parser.add_argument( + "--data-split", + default=["train", "valid", "test"], + nargs="+", + help="data split names", + ) + parser.add_argument( + "--output-root", required=True, type=Path, help="output directory" + ) + # target feature related + parser.add_argument("--win-length", type=int, default=1024) + parser.add_argument("--hop-length", type=int, default=256) + parser.add_argument("--n-fft", type=int, default=1024) + parser.add_argument("--n-mels", type=int, default=80) + parser.add_argument("--f-min", type=int, default=20) + parser.add_argument("--f-max", type=int, default=8000) + parser.add_argument("--sample-rate", type=int, default=22050) + parser.add_argument("--normalize-volume", "-n", action="store_true") + + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_to_speech/preprocessing/prep_s2ut_data.py b/examples/speech_to_speech/preprocessing/prep_s2ut_data.py new file mode 100644 index 0000000000..beeffaa0e4 --- /dev/null +++ b/examples/speech_to_speech/preprocessing/prep_s2ut_data.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import logging +from pathlib import Path + +import soundfile as sf +from tqdm import tqdm +import pandas as pd + +from examples.speech_to_speech.preprocessing.data_utils import gen_config_yaml +from examples.speech_to_text.data_utils import save_df_to_tsv + +logger = logging.getLogger(__name__) + +MANIFEST_COLUMNS = ["id", "src_audio", "src_n_frames", "tgt_audio", "tgt_n_frames"] + + +def load_units(in_file): + out = {} + with open(in_file) as f: + for line in f: + sample_id, units = line.strip().split("|", 1) + out[sample_id] = units.split() + + return out + + +def process_units(units, reduce=False): + if not reduce: + return units + + out = [u for i, u in enumerate(units) if i == 0 or u != units[i - 1]] + return out + + +def process(args): + args.output_root.mkdir(exist_ok=True) + + print("Generating manifest...") + for split in args.data_split: + print(f"Processing {split}") + + # load target units + target_unit_data = load_units(args.target_dir / f"{split}.txt") + + manifest = {c: [] for c in MANIFEST_COLUMNS} + missing_tgt_audios = [] + src_audios = list(args.source_dir.glob(f"{split}/*.wav")) + for src_audio in tqdm(src_audios): + sample_id = src_audio.stem + + if sample_id not in target_unit_data: + missing_tgt_audios.append(sample_id) + continue + + src_n_frames = sf.info(src_audio.as_posix()).frames + manifest["id"].append(sample_id) + manifest["src_audio"].append(src_audio.as_posix()) + manifest["src_n_frames"].append( + src_n_frames // 160 + ) # estimation of 10-ms frame for 16kHz audio + + target_units = process_units(target_unit_data[sample_id], args.reduce_unit) + manifest["tgt_audio"].append(" ".join(target_units)) + manifest["tgt_n_frames"].append(len(target_units)) + + print(f"Processed {len(manifest['id'])} samples") + if len(missing_tgt_audios) > 0: + print( + f"{len(missing_tgt_audios)} with missing target data (first 3 examples: {', '.join(missing_tgt_audios[:3])})" + ) + + out_manifest = args.output_root / f"{split}.tsv" + print(f"Writing manifest to {out_manifest}...") + save_df_to_tsv(pd.DataFrame.from_dict(manifest), out_manifest) + + # Generate config YAML + gen_config_yaml( + args.output_root, + specaugment_policy="lb", + feature_transform=["utterance_cmvn"], + vocoder_type="code_hifigan", + vocoder_checkpoint=args.vocoder_checkpoint, + vocoder_cfg=args.vocoder_cfg, + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--source-dir", required=True, type=Path, help="source audio directory" + ) + parser.add_argument( + "--target-dir", required=True, type=Path, help="target audio directory" + ) + parser.add_argument( + "--data-split", + default=["train", "valid", "test"], + nargs="+", + help="data split names", + ) + parser.add_argument( + "--output-root", required=True, type=Path, help="output directory" + ) + parser.add_argument( + "--reduce-unit", + action="store_true", + help="reduce a target unit sequence to a unique unit sequence, i.e. '1 1 1 2 2' -> '1 2'", + ) + parser.add_argument( + "--vocoder-checkpoint", default=None, type=str, help="vocoder checkpoint" + ) + parser.add_argument( + "--vocoder-cfg", default=None, type=str, help="vocoder config file" + ) + + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/textless_nlp/gslm/speech2unit/README.md b/examples/textless_nlp/gslm/speech2unit/README.md index 434333f555..9dff9d33ac 100644 --- a/examples/textless_nlp/gslm/speech2unit/README.md +++ b/examples/textless_nlp/gslm/speech2unit/README.md @@ -48,10 +48,10 @@ PYTHONPATH=. python examples/textless_nlp/gslm/speech2unit/clustering/cluster_km MANIFEST=<tab_separated_manifest_of_audio_files_to_quantize> OUT_QUANTIZED_FILE=<output_quantized_audio_file_path> -python examples/textless_nlp/gslm/speech2unit/clustering/del/quantize_with_kmeans.py \ +python examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py \ --feature_type $TYPE \ --kmeans_model_path $KM_MODEL_PATH \ - --checkpoint_path $CKPT_PATH \ + --acoustic_model_path $CKPT_PATH \ --layer $LAYER \ --manifest_path $MANIFEST \ --out_quantized_file_path $OUT_QUANTIZED_FILE \ diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 734f9e7e5a..8ff0ba0397 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -249,9 +249,8 @@ def input_layer(self): if self.input_from == "decoder": return self.config["decoder_layer"] - 1 else: - # default using the output from the last encoder layer - # TODO: check if need to offset by 1 - return self.config.get("encoder_layer", -1) + # default using the output from the last encoder layer (-1) + return self.config.get("encoder_layer", 0) - 1 @property def loss_weight_schedule(self): diff --git a/fairseq/data/audio/feature_transforms/delta_deltas.py b/fairseq/data/audio/feature_transforms/delta_deltas.py new file mode 100644 index 0000000000..49d090b11e --- /dev/null +++ b/fairseq/data/audio/feature_transforms/delta_deltas.py @@ -0,0 +1,37 @@ +import numpy as np +import torch +from fairseq.data.audio.feature_transforms import ( + AudioFeatureTransform, + register_audio_feature_transform, +) + + +@register_audio_feature_transform("delta_deltas") +class DeltaDeltas(AudioFeatureTransform): + """Expand delta-deltas features from spectrum.""" + + @classmethod + def from_config_dict(cls, config=None): + _config = {} if config is None else config + return DeltaDeltas(_config.get("win_length", 5)) + + def __init__(self, win_length=5): + self.win_length = win_length + + def __repr__(self): + return self.__class__.__name__ + + def __call__(self, spectrogram): + from torchaudio.functional import compute_deltas + + assert len(spectrogram.shape) == 2, "spectrogram must be a 2-D tensor." + # spectrogram is T x F, while compute_deltas takes (…, F, T) + spectrogram = torch.from_numpy(spectrogram).transpose(0, 1) + delta = compute_deltas(spectrogram) + delta_delta = compute_deltas(delta) + + out_feat = np.concatenate( + [spectrogram, delta.numpy(), delta_delta.numpy()], axis=0 + ) + out_feat = np.transpose(out_feat) + return out_feat diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index abe2c1d840..69c9272063 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -236,6 +236,7 @@ def forward(self, x: Dict[str, torch.Tensor], dur_prediction=False) -> torch.Ten @classmethod def from_data_cfg(cls, args, data_cfg): vocoder_cfg = data_cfg.vocoder + assert vocoder_cfg is not None, "vocoder not specified in the data config" with open(vocoder_cfg["config"]) as f: model_cfg = json.load(f) return cls(vocoder_cfg["checkpoint"], model_cfg, fp16=args.fp16) From 7fddb9d9601102ee6767d702f19273a481562d50 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Wed, 29 Dec 2021 11:49:57 -0800 Subject: [PATCH 530/774] lint fixes (#2834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Applied `black` and `isort` to fix failing CI ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2834 Reviewed By: vedanuj Differential Revision: D33262876 Pulled By: dianaml0 fbshipit-source-id: 03215c276fcddda9f7c78971bf6ed7c5ac21b2ee --- fairseq/hub_utils.py | 8 +- .../tasks/multilingual_language_modeling.py | 95 ++++++++++++------- tests/gpu/test_binaries_gpu.py | 94 +++++++++++------- tests/utils.py | 22 +++-- 4 files changed, 142 insertions(+), 77 deletions(-) diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index 1df2ee47d4..b6fa2cb97d 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -11,11 +11,11 @@ from typing import Any, Dict, Iterator, List import torch -from fairseq import utils -from fairseq.data import encoders from omegaconf import open_dict from torch import nn +from fairseq import utils +from fairseq.data import encoders logger = logging.getLogger(__name__) @@ -132,7 +132,9 @@ def sample( batched_hypos = self.generate(tokenized_sentences, beam, verbose, **kwargs) return [self.decode(hypos[0]["tokens"]) for hypos in batched_hypos] - def score(self, sentences: List[str], replace_newline_with_eos: bool = False, **kwargs): + def score( + self, sentences: List[str], replace_newline_with_eos: bool = False, **kwargs + ): if isinstance(sentences, str): return self.score( [sentences], replace_newline_with_eos=replace_newline_with_eos, **kwargs diff --git a/fairseq/tasks/multilingual_language_modeling.py b/fairseq/tasks/multilingual_language_modeling.py index 0140667f2c..f9e8d91c5f 100644 --- a/fairseq/tasks/multilingual_language_modeling.py +++ b/fairseq/tasks/multilingual_language_modeling.py @@ -10,10 +10,12 @@ import numpy as np import torch +from omegaconf import II + from fairseq import utils from fairseq.data import ( - ConcatDataset, AppendTokenDataset, + ConcatDataset, Dictionary, IdDataset, LMContextWindowDataset, @@ -33,8 +35,6 @@ from fairseq.data.shorten_dataset import maybe_shorten_dataset from fairseq.dataclass import ChoiceEnum, FairseqDataclass from fairseq.tasks import LegacyFairseqTask, register_task -from omegaconf import II - SAMPLE_BREAK_MODE_CHOICES = ChoiceEnum(["none", "complete", "complete_doc", "eos"]) SHORTEN_METHOD_CHOICES = ChoiceEnum(["none", "truncate", "random_crop"]) @@ -125,16 +125,14 @@ class MultilingualLanguageModelingConfig(FairseqDataclass): # TODO: legacy parameter kept for compatibility baseline_model: str = field( default="", - metadata={ - "help": "path to the baseline model (default: none)" - }, + metadata={"help": "path to the baseline model (default: none)"}, ) - + lang_to_offline_shard_ratio: str = field( default="", metadata={ "help": "absolute path of tsv file location to indicate lang to offline shard ratio.", - } + }, ) # TODO common vars below add to parent seed: int = II("common.seed") @@ -149,7 +147,9 @@ class MultilingualLanguageModelingConfig(FairseqDataclass): valid_subset: str = II("common.valid_subset") -@register_task("multilingual_language_modeling", dataclass=MultilingualLanguageModelingConfig) +@register_task( + "multilingual_language_modeling", dataclass=MultilingualLanguageModelingConfig +) class MultilingualLanguageModelingTask(LegacyFairseqTask): """ Train a language model. @@ -216,11 +216,11 @@ def setup_dictionary(cls, args, **kwargs): dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) if args.add_bos_token: languages, _ = cls._get_langs(args) - logger.info('----------------') + logger.info("----------------") for lang in languages: dictionary.add_symbol(lang_token(lang)) - logger.info(f'add language token: {lang_token(lang)}') - logger.info('----------------') + logger.info(f"add language token: {lang_token(lang)}") + logger.info("----------------") logger.info("dictionary: {} types".format(len(dictionary))) output_dictionary = dictionary @@ -276,9 +276,7 @@ def _get_sample_prob(self, dataset_lens): smoothed_prob = smoothed_prob / smoothed_prob.sum() return smoothed_prob - def load_dataset( - self, split: str, epoch=1, combine=False, **kwargs - ): + def load_dataset(self, split: str, epoch=1, combine=False, **kwargs): """Load a given dataset split. Args: @@ -292,21 +290,28 @@ def load_dataset( lang_to_offline_shard_ratio = {} assert os.path.exists( self.args.lang_to_offline_shard_ratio - ), "provided offline shard ratio file doesn't exist: {0}".format(self.args.lang_to_offline_shard_ratio) + ), "provided offline shard ratio file doesn't exist: {0}".format( + self.args.lang_to_offline_shard_ratio + ) with open(self.args.lang_to_offline_shard_ratio) as fin: for line in fin: - lang, ratio = line.strip().split('\t') + lang, ratio = line.strip().split("\t") ratio = float(ratio) lang_to_offline_shard_ratio[lang] = ratio - + logger.info( - "Found offline sharded ratio: %s", lang_to_offline_shard_ratio, + "Found offline sharded ratio: %s", + lang_to_offline_shard_ratio, ) if split == self.args.train_subset: - logger.info("Training on {0} languages: {1}".format(len(languages), languages)) + logger.info( + "Training on {0} languages: {1}".format(len(languages), languages) + ) else: - logger.info("Evaluating on {0} languages: {1}".format(len(languages), languages)) + logger.info( + "Evaluating on {0} languages: {1}".format(len(languages), languages) + ) tokens_per_sample = self.args.tokens_per_sample - int(self.args.add_bos_token) @@ -388,15 +393,24 @@ def load_dataset( ) if split == self.args.train_subset: dataset_lengths_ratio_multiplier = np.ones(len(dataset_lengths)) - if lang_to_offline_shard_ratio is not None: + if lang_to_offline_shard_ratio is not None: dataset_lengths_ratio_multiplier = [] for lang in languages: - assert lang in lang_to_offline_shard_ratio, "Lang: {0} missing in offline shard ratio file: {1}".format( - lang, self.args.lang_to_offline_shard_ratio, + assert ( + lang in lang_to_offline_shard_ratio + ), "Lang: {0} missing in offline shard ratio file: {1}".format( + lang, + self.args.lang_to_offline_shard_ratio, ) - dataset_lengths_ratio_multiplier.append(lang_to_offline_shard_ratio[lang]) - dataset_lengths_ratio_multiplier = np.array(dataset_lengths_ratio_multiplier) - true_dataset_lengths = dataset_lengths * dataset_lengths_ratio_multiplier + dataset_lengths_ratio_multiplier.append( + lang_to_offline_shard_ratio[lang] + ) + dataset_lengths_ratio_multiplier = np.array( + dataset_lengths_ratio_multiplier + ) + true_dataset_lengths = ( + dataset_lengths * dataset_lengths_ratio_multiplier + ) else: true_dataset_lengths = dataset_lengths # For train subset, additionally up or down sample languages. @@ -410,7 +424,7 @@ def load_dataset( }, ) size_ratio = (sample_probs * true_dataset_lengths.sum()) / dataset_lengths - # TODO: add an option for shrinking all size ratios to below 1 + # TODO: add an option for shrinking all size ratios to below 1 # if self.args.multilang_sampling_alpha != 1: # size_ratio /= size_ratio.max() @@ -418,7 +432,7 @@ def load_dataset( # 0.999999999999999999 -> 1 # 1.000000000000000002 -> 1 for i in range(len(size_ratio)): - size_ratio[i] = round(size_ratio[i], 8) + size_ratio[i] = round(size_ratio[i], 8) logger.info( "Up/Down Sampling ratio by language: %s", @@ -479,7 +493,9 @@ def load_dataset( ], ) - def build_dataset_for_inference(self, src_tokens, src_lengths, language="en_XX", **kwargs): + def build_dataset_for_inference( + self, src_tokens, src_lengths, language="en_XX", **kwargs + ): """ Generate batches for inference. We prepend an eos token to src_tokens (or bos if `--add-bos-token` is set) and we append a <pad> to target. @@ -518,12 +534,15 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, language="en_XX", src_dataset, pad_idx=self.source_dictionary.pad(), left_pad=False, - pad_length=max_seq_len + pad_length=max_seq_len, ), "src_lengths": NumelDataset(src_dataset, reduce=False), }, "target": PadDataset( - tgt_dataset, pad_idx=self.source_dictionary.pad(), left_pad=False, pad_length=max_seq_len, + tgt_dataset, + pad_idx=self.source_dictionary.pad(), + left_pad=False, + pad_length=max_seq_len, ), }, sizes=[np.array(src_lengths)], @@ -531,7 +550,13 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, language="en_XX", @torch.no_grad() def inference_step( - self, generator, models, sample, language="en_XX", prefix_tokens=None, constraints=None + self, + generator, + models, + sample, + language="en_XX", + prefix_tokens=None, + constraints=None, ): # Generation will always be conditioned on bos_token if getattr(self.args, "add_bos_token", False): @@ -555,7 +580,7 @@ def inference_step( return generator.generate( models, sample, prefix_tokens=prefix_tokens, bos_token=bos_token ) - + def eval_lm_dataloader( self, dataset, @@ -599,4 +624,4 @@ def source_dictionary(self): def target_dictionary(self): """Return the :class:`~fairseq.data.Dictionary` for the language model.""" - return self.output_dictionary \ No newline at end of file + return self.output_dictionary diff --git a/tests/gpu/test_binaries_gpu.py b/tests/gpu/test_binaries_gpu.py index 5bdf5578af..5caf94cde7 100644 --- a/tests/gpu/test_binaries_gpu.py +++ b/tests/gpu/test_binaries_gpu.py @@ -20,13 +20,13 @@ generate_main, preprocess_lm_data, preprocess_translation_data, - train_translation_model, train_language_model, + train_translation_model, ) + @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") class TestMultiGPU(unittest.TestCase): - @staticmethod def parse_logs(logfile): logs = [] @@ -44,59 +44,85 @@ def world_size(self): def train_flags(self, mu): return [ "--memory-efficient-fp16", - '--update-freq', '1', - '--seed', '1', - "--log-format", "json", - "--max-update", str(mu), - "--tokens-per-sample", "20", - "--batch-size", "2", - '--share-decoder-input-output-embed', - '--optimizer', 'adam', - '--max-valid-steps', '1', - '--pad-to-fixed-length', - '--sample-break-mode', 'none', + "--update-freq", + "1", + "--seed", + "1", + "--log-format", + "json", + "--max-update", + str(mu), + "--tokens-per-sample", + "20", + "--batch-size", + "2", + "--share-decoder-input-output-embed", + "--optimizer", + "adam", + "--max-valid-steps", + "1", + "--pad-to-fixed-length", + "--sample-break-mode", + "none", ] - def _test_resume_multilingual_training(self, extra_clargs, arch="transformer_lm_gpt2_tiny"): + def _test_resume_multilingual_training( + self, extra_clargs, arch="transformer_lm_gpt2_tiny" + ): languages = ["en_XX", "fr_XX", "zh_CN"] save_interval = 5 mu = 10 - flags = self.train_flags(mu) + [ - "--save-interval-updates", str(save_interval), - "--log-interval", "1" - ] + extra_clargs + flags = ( + self.train_flags(mu) + + ["--save-interval-updates", str(save_interval), "--log-interval", "1"] + + extra_clargs + ) with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory("test_fp16") as data_dir: log = os.path.join(data_dir, "train.log") - create_dummy_data(data_dir, - num_examples=int(mu * 20 * self.world_size * 1.5), # make sure enough data for max updates - languages=languages) + create_dummy_data( + data_dir, + num_examples=int( + mu * 20 * self.world_size * 1.5 + ), # make sure enough data for max updates + languages=languages, + ) preprocess_lm_data(data_dir, languages) train_language_model( - data_dir, arch, - flags + ["--log-file", log], - task="multilingual_language_modeling", + data_dir, + arch, + flags + ["--log-file", log], + task="multilingual_language_modeling", world_size=self.world_size, ) log2 = os.path.join(data_dir, "resume.log") ckpt_name = f"checkpoint_1_{save_interval}.pt" restore_file = os.path.join(data_dir, ckpt_name) train_language_model( - data_dir, arch, - flags + ["--log-file", log2, "--restore-file", restore_file, '--no-save'], - task="multilingual_language_modeling", + data_dir, + arch, + flags + + ["--log-file", log2, "--restore-file", restore_file, "--no-save"], + task="multilingual_language_modeling", world_size=self.world_size, ) l1 = self.parse_logs(log) - assert int(l1[-1]['train_num_updates']) == mu, f'The first run did not complete {mu} updates. Add more data' + assert ( + int(l1[-1]["train_num_updates"]) == mu + ), f"The first run did not complete {mu} updates. Add more data" l2 = self.parse_logs(log2) - if int(l2[0]["num_updates"]) != save_interval+1: - all_ckpt_files = [x for x in os.listdir(data_dir) if x.endswith('.pt')] + if int(l2[0]["num_updates"]) != save_interval + 1: + all_ckpt_files = [ + x for x in os.listdir(data_dir) if x.endswith(".pt") + ] import shutil - shutil.move(data_dir, 'last_failed_resume') - raise AssertionError(f"Likely failed to load {ckpt_name}. {all_ckpt_files} \n LOGS: {l1} \n\n {l2}. ") + + shutil.move(data_dir, "last_failed_resume") + raise AssertionError( + f"Likely failed to load {ckpt_name}. {all_ckpt_files} \n LOGS: {l1} \n\n {l2}. " + ) for k in [ "train_loss", "train_num_updates", @@ -105,7 +131,9 @@ def _test_resume_multilingual_training(self, extra_clargs, arch="transformer_lm_ ]: from_scratch, resumed = float(l1[-1][k]), float(l2[-1][k]) # This fails without rounding! - assert from_scratch == resumed, f"difference at {k} {from_scratch} != {resumed}" + assert ( + from_scratch == resumed + ), f"difference at {k} {from_scratch} != {resumed}" @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") diff --git a/tests/utils.py b/tests/utils.py index 4c0dae8c72..6ce65d8eb9 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -164,7 +164,9 @@ def sequence_generator_setup(): return tgt_dict, w1, w2, src_tokens, src_lengths, model -def create_dummy_data(data_dir, num_examples=100, maxlen=20, alignment=False, languages=None): +def create_dummy_data( + data_dir, num_examples=100, maxlen=20, alignment=False, languages=None +): def _create_dummy_data(dir, filename): data = torch.rand(num_examples * maxlen) data = 97 + torch.floor(26 * data).int() @@ -195,8 +197,15 @@ def _create_dummy_alignment_data(filename_src, filename_tgt, filename): ) print(ex_str, file=h) - files_to_write = ['train.in', 'train.out', 'valid.in', 'valid.out', 'test.in', 'test.out'] - if languages is None: # En only dummy dataset + files_to_write = [ + "train.in", + "train.out", + "valid.in", + "valid.out", + "test.in", + "test.out", + ] + if languages is None: # En only dummy dataset for f in files_to_write: _create_dummy_data(data_dir, f) else: @@ -232,7 +241,7 @@ def preprocess_lm_data(data_dir, languages=None): else: for lang in languages: lang_dir = os.path.join(data_dir, lang) - assert(os.path.exists(lang_dir)) + assert os.path.exists(lang_dir) preprocess_args = preprocess_parser.parse_args( [ "--only-source", @@ -248,8 +257,9 @@ def preprocess_lm_data(data_dir, languages=None): ) preprocess.main(preprocess_args) shutil.copyfile( - os.path.join(data_dir, languages[0], 'dict.txt'), os.path.join(data_dir, 'dict.txt')) - + os.path.join(data_dir, languages[0], "dict.txt"), + os.path.join(data_dir, "dict.txt"), + ) def preprocess_translation_data(data_dir, extra_flags=None): From 2762a1cfef1550c4ccd48ef5e435e2b7abbcfb29 Mon Sep 17 00:00:00 2001 From: Liang Tan <liangtan@fb.com> Date: Thu, 30 Dec 2021 02:01:11 -0800 Subject: [PATCH 531/774] Add regularization for multihead attention module and ffn module Summary: [Fairseq] Add regularization for multihead attention module and ffn module Reviewed By: dianaml0 Differential Revision: D32441521 fbshipit-source-id: c648c1f8ec1a3310ba90c4952cdd40a21b959d26 --- fairseq/criterions/sentence_prediction.py | 44 +++++++++++++++++------ fairseq/models/roberta/model.py | 40 +++++++++++++++++++++ tests/test_roberta.py | 15 ++++++++ 3 files changed, 89 insertions(+), 10 deletions(-) diff --git a/fairseq/criterions/sentence_prediction.py b/fairseq/criterions/sentence_prediction.py index 482b97985a..87af5e8a7b 100644 --- a/fairseq/criterions/sentence_prediction.py +++ b/fairseq/criterions/sentence_prediction.py @@ -8,7 +8,7 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass @@ -54,18 +54,32 @@ def forward(self, model, sample, reduce=True): if not self.regression_target: lprobs = F.log_softmax(logits, dim=-1, dtype=torch.float32) - loss = F.nll_loss(lprobs, targets, reduction="sum") + task_loss = F.nll_loss(lprobs, targets, reduction="sum") else: logits = logits.view(-1).float() targets = targets.float() - loss = F.mse_loss(logits, targets, reduction="sum") - - logging_output = { - "loss": loss.data, - "ntokens": sample["ntokens"], - "nsentences": sample_size, - "sample_size": sample_size, - } + task_loss = F.mse_loss(logits, targets, reduction="sum") + + logging_output = {} + loss = task_loss + # mha & ffn regularization update + if hasattr(model.args, "mha_reg_scale_factor") and model.args.mha_reg_scale_factor != 0.0: + mha_reg_loss = model._get_adaptive_head_loss() + loss += mha_reg_loss + logging_output.update({"mha_reg_loss": mha_reg_loss}) + if hasattr(model.args, "ffn_reg_scale_factor") and model.args.ffn_reg_scale_factor != 0.0: + ffn_reg_loss = model._get_adaptive_ffn_loss() + loss += ffn_reg_loss + logging_output.update({"ffn_reg_loss": ffn_reg_loss}) + + logging_output.update( + { + "loss": loss.data, + "ntokens": sample["ntokens"], + "nsentences": sample_size, + "sample_size": sample_size, + } + ) if not self.regression_target: preds = logits.argmax(dim=1) logging_output["ncorrect"] = (preds == targets).sum() @@ -79,10 +93,20 @@ def reduce_metrics(logging_outputs) -> None: ntokens = sum(log.get("ntokens", 0) for log in logging_outputs) nsentences = sum(log.get("nsentences", 0) for log in logging_outputs) sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + mha_reg_loss_sum = sum(log.get("mha_reg_loss", 0) for log in logging_outputs) + ffn_reg_loss_sum = sum(log.get("ffn_reg_loss", 0) for log in logging_outputs) metrics.log_scalar( "loss", loss_sum / sample_size / math.log(2), sample_size, round=3 ) + if mha_reg_loss_sum: + metrics.log_scalar( + "mha_reg_loss", mha_reg_loss_sum / sample_size / math.log(2), sample_size, round=3 + ) + if ffn_reg_loss_sum: + metrics.log_scalar( + "ffn_reg_loss", ffn_reg_loss_sum / sample_size / math.log(2), sample_size, round=3 + ) if sample_size != ntokens: metrics.log_scalar( "nll_loss", loss_sum / ntokens / math.log(2), ntokens, round=3 diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 6e59ece5c0..b6315ffbfa 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -185,6 +185,23 @@ def add_args(parser): "--offload-activations are passed." ), ) + # args for AdaPruning + # In short, it adds regularizarion for the multihead attention module and feed forward neural nets + # For more details, please refer to the paper https://openreview.net/forum?id=_CMSV7FTzGI + parser.add_argument( + "--mha-reg-scale-factor", + type=float, + metavar="D", + default=0.0, + help="scaling factor for regularization term in adptive pruning, recommendation is 0.000375", + ) + parser.add_argument( + "--ffn-reg-scale-factor", + type=float, + metavar="D", + default=0.0, + help="scaling factor for regularization term in adptive pruning, recommendation is 0.000375", + ) @classmethod def build_model(cls, args, task): @@ -227,6 +244,29 @@ def forward( x = self.classification_heads[classification_head_name](x) return x, extra + def _get_adaptive_head_loss(self): + norm_loss = 0 + scaling = float(self.args.mha_reg_scale_factor) + for layer in self.encoder.sentence_encoder.layers: + norm_loss_layer = 0 + for i in range(layer.self_attn.num_heads): + start_idx = i * layer.self_attn.head_dim + end_idx = (i + 1) * layer.self_attn.head_dim + norm_loss_layer += scaling * (torch.sum(torch.abs(layer.self_attn.q_proj.weight[start_idx:end_idx, ])) + torch.sum(torch.abs(layer.self_attn.q_proj.bias[start_idx:end_idx]))) + norm_loss_layer += scaling * (torch.sum(torch.abs(layer.self_attn.k_proj.weight[start_idx:end_idx, ])) + torch.sum(torch.abs(layer.self_attn.k_proj.bias[start_idx:end_idx]))) + norm_loss_layer += scaling * (torch.sum(torch.abs(layer.self_attn.v_proj.weight[start_idx:end_idx, ])) + torch.sum(torch.abs(layer.self_attn.v_proj.bias[start_idx:end_idx]))) + + norm_loss += norm_loss_layer + return norm_loss + + def _get_adaptive_ffn_loss(self): + ffn_scale_factor = float(self.args.ffn_reg_scale_factor) + filter_loss = 0 + for layer in self.encoder.sentence_encoder.layers: + filter_loss += torch.sum(torch.abs(layer.fc1.weight * ffn_scale_factor)) + torch.sum(torch.abs(layer.fc2.weight * ffn_scale_factor)) + filter_loss += torch.sum(torch.abs(layer.fc1.bias * ffn_scale_factor)) + torch.sum(torch.abs(layer.fc2.bias * ffn_scale_factor)) + return filter_loss + def get_normalized_probs(self, net_output, log_probs, sample=None): """Get normalized probabilities (or log probs) from a net's output.""" logits = net_output[0].float() diff --git a/tests/test_roberta.py b/tests/test_roberta.py index 0030d3e5a9..75d4d797bf 100644 --- a/tests/test_roberta.py +++ b/tests/test_roberta.py @@ -305,6 +305,21 @@ def test_roberta_incremental_decoder(self, device: str): # Incremental vs non-incremental self.assertTensorEqual(ro_dec_inc[i][:, 0], ro_dec[:, i]) + @cpu_gpu + def test_regularize_for_adaprune_in_roberta(self, device: str): + _, model = get_toy_model( + device=device, + architecture="roberta_base", + mha_reg_scale_factor=0.000375, + ffn_reg_scale_factor=0.000375, + ) + sample = mk_sample("en", device, batch_size=1) + task_loss, _ = model.forward(**sample["net_input"]) + head_loss = model._get_adaptive_head_loss() + ffn_loss = model._get_adaptive_ffn_loss() + loss = task_loss.sum() + head_loss + ffn_loss + loss.backward() + def params(model, name): if "." not in name: From 6a183f37a0c4dd707822c9e58bcd53972b8ce0ac Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 30 Dec 2021 18:37:03 -0800 Subject: [PATCH 532/774] add strict option to checkpoint_utils. load_pretrained_component_from_model() Summary: Add strict option to checkpoint_utils. load_pretrained_component_from_model() Reviewed By: sravyapopuri388 Differential Revision: D33304224 fbshipit-source-id: 2284a21dfea7810ec212f15daadeeeb45c6dca1b --- fairseq/checkpoint_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 3156d0e27b..cebb77a7ba 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -794,7 +794,7 @@ def create_pruning_pass(layers_to_keep, layer_name): def load_pretrained_component_from_model( - component: Union[FairseqEncoder, FairseqDecoder], checkpoint: str + component: Union[FairseqEncoder, FairseqDecoder], checkpoint: str, strict: bool = True ): """ Load a pretrained FairseqEncoder or FairseqDecoder from checkpoint into the @@ -820,7 +820,7 @@ def load_pretrained_component_from_model( # encoder.input_layers.0.0.weight --> input_layers.0.0.weight component_subkey = key[len(component_type) + 1 :] component_state_dict[component_subkey] = state["model"][key] - component.load_state_dict(component_state_dict, strict=True) + component.load_state_dict(component_state_dict, strict=strict) return component From 75f8fa29c6919c9055cd1b1cb841c4e3aeafa465 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 30 Dec 2021 18:47:54 -0800 Subject: [PATCH 533/774] update xm_transformer Summary: Update xm_transformer - Added V1 arch (FFNs before/after convolutions in the adaptor, which didn't exist in the V0/ACL paper arch) - Added args for gradient checkpointing and fully sharded data parallele Reviewed By: sravyapopuri388 Differential Revision: D33144404 fbshipit-source-id: 548c917824ebd2aa926c83d5ba62fbf648cf4b97 --- .../models/s2t_dualinputxmtransformer.py | 9 +- .../models/speech_to_text/xm_transformer.py | 257 +++++++++++------- fairseq/models/wav2vec/wav2vec2_asr.py | 20 ++ 3 files changed, 190 insertions(+), 96 deletions(-) diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py index 41ec2bdb4d..7b4cbb0aa6 100644 --- a/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputxmtransformer.py @@ -14,10 +14,11 @@ register_model_architecture, FairseqEncoder, ) -from fairseq.models.speech_to_text import XMTransformerModel, Wav2VecEncoderWithAdaptor +from fairseq.models.speech_to_text import Wav2VecEncoderWithAdaptor from fairseq.models.speech_to_text.xm_transformer import ( set_default_adaptor_args, set_default_w2v_encoder_args, + need_finetuning ) from fairseq.models.transformer import TransformerEncoder, TransformerDecoder from fairseq.models.wav2vec import TransformerSentenceEncoderLayer @@ -442,7 +443,7 @@ def build_encoder(cls, args, task): # Freeze pretrained models by default if safe_hasattr( args, "finetune_w2v_params" - ) and XMTransformerModel.finetune_params(args.finetune_w2v_params, k): + ) and need_finetuning(args.finetune_w2v_params, k): p.requires_grad = True else: p.requires_grad = False @@ -450,7 +451,7 @@ def build_encoder(cls, args, task): # Freeze pretrained models by default if safe_hasattr( args, "finetune_mbart_encoder_params" - ) and XMTransformerModel.finetune_params( + ) and need_finetuning( args.finetune_mbart_encoder_params, k ): p.requires_grad = True @@ -489,7 +490,7 @@ def build_decoder(cls, args, task): # Freeze pretrained models by default if safe_hasattr( args, "finetune_mbart_decoder_params" - ) and XMTransformerModel.finetune_params( + ) and need_finetuning( args.finetune_mbart_decoder_params, k ): p.requires_grad = True diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index c2cc86bb3f..202f4b698d 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # Copyright (c) Facebook, Inc. and its affiliates. # # This source code is licensed under the MIT license found in the @@ -8,6 +7,9 @@ import copy from typing import Dict, List, Optional, Tuple +import numpy as np +import torch + from fairseq import utils, checkpoint_utils from fairseq.models import ( FairseqEncoderDecoderModel, @@ -19,7 +21,6 @@ from fairseq.models.wav2vec import Wav2VecEncoder from fairseq.modules.layer_norm import LayerNorm from fairseq.data.data_utils import lengths_to_padding_mask -from fairseq.utils import safe_hasattr from torch import Tensor import torch.nn as nn @@ -29,9 +30,26 @@ class Conv1dAdaptor(nn.Module): def __init__( - self, in_dim, out_dim, n_layers=3, kernel_size=3, stride=2, add_layernorm=False + self, in_dim, out_dim, n_layers=3, kernel_size=3, stride=2, + layerdrop=0., layernorm=False, proj=False ): super().__init__() + self.proj, self.proj_ln = None, None + self.post_proj, self.post_proj_ln = None, None + if proj: + self.proj = nn.Sequential( + nn.Linear(in_dim, in_dim * 4), + nn.ReLU(), + nn.Linear(in_dim * 4, in_dim) + ) + self.proj_ln = LayerNorm(in_dim) + self.post_proj = nn.Sequential( + nn.Linear(out_dim, out_dim * 4), + nn.ReLU(), + nn.Linear(out_dim * 4, out_dim) + ) + self.post_proj_ln = LayerNorm(out_dim) + self.layers = nn.ModuleList( nn.Conv1d( in_dim if i == 0 else out_dim, @@ -42,39 +60,49 @@ def __init__( ) for i in range(n_layers) ) - self.layernorms = None - if add_layernorm: - self.layernorms = nn.ModuleList(LayerNorm(out_dim) for _ in range(n_layers)) self.stride = stride + self.layerdrop = layerdrop + self.layernorm = LayerNorm(in_dim) if layernorm else None @classmethod def add_args(cls, parser): parser.add_argument("--adaptor-n-layers", type=int) parser.add_argument("--adaptor-kernel-size", type=int) parser.add_argument("--adaptor-stride", type=int) + parser.add_argument("--adaptor-layerdrop", type=float) parser.add_argument("--adaptor-layernorm", action="store_true") + parser.add_argument("--adaptor-proj", action="store_true") + + def forward(self, x, padding_mask: Optional[torch.Tensor]): + if self.layernorm is not None: + x = self.layernorm(x) - def get_out_seq_lens_tensor(self, in_seq_lens_tensor): - out = in_seq_lens_tensor.clone() - for _ in self.layers: - out = ((out.float() - 1) / self.stride + 1).floor().long() - return out + if self.proj is not None: + x = x + 0.5 * self.proj(x) + x = self.proj_ln(x) - def forward(self, x, padding_mask): # T x B x C -> B x C x T x = x.transpose(0, 1).transpose(1, 2) - for i, layer in enumerate(self.layers): - x = nn.functional.glu(layer(x), dim=1) - if self.layernorms is not None: - x = self.layernorms[i](x.transpose(1, 2)).transpose(1, 2) + out_lens = None + if padding_mask is not None: + out_lens = (~padding_mask).sum(1).float() + + for layer in self.layers: + layerdrop_prob = np.random.random() + if not self.training or (layerdrop_prob > self.layerdrop): + x = nn.functional.glu(layer(x), dim=1) + if padding_mask is not None: + out_lens = ((out_lens - 1) / self.stride + 1).floor() # B x C x T -> T x B x C x = x.transpose(1, 2).transpose(0, 1) - if padding_mask is None: - out_padding_mask = None - else: - out_lengths = self.get_out_seq_lens_tensor((~padding_mask).sum(1)) - out_padding_mask = lengths_to_padding_mask(out_lengths) + if self.post_proj is not None: + x = x + 0.5 * self.post_proj(x) + x = self.post_proj_ln(x) + + out_padding_mask = None + if padding_mask is not None: + out_padding_mask = lengths_to_padding_mask(out_lens.long()) return x, out_padding_mask @@ -199,28 +227,45 @@ def add_wav2vec_asr_args(parser): parser.add_argument("--w2v-args", default=None) +def need_finetuning(ft_params, param_name): + if ft_params == "all": + return True + ft_params_list = ft_params.split(",") + for ft_param in ft_params_list: + if ft_param in param_name: + return True + return False + + class Wav2VecEncoderWithAdaptor(FairseqEncoder): + def build_adaptor(self, args): + adaptor = None + if args.adaptor_n_layers > 0: + adaptor = Conv1dAdaptor( + args.decoder_embed_dim, args.decoder_embed_dim, + n_layers=args.adaptor_n_layers, + kernel_size=args.adaptor_kernel_size, + stride=args.adaptor_stride, + layerdrop=args.adaptor_layerdrop, + layernorm=args.adaptor_layernorm, + proj=args.adaptor_proj + ) + return adaptor + def __init__(self, args): super().__init__(None) self.w2v_encoder = Wav2VecEncoder(args) - encoder_out_dim = self.w2v_encoder.w2v_model.encoder.embedding_dim - # Projection + 8x shrinking - self.adaptor = Conv1dAdaptor( - encoder_out_dim, - args.decoder_embed_dim, - n_layers=args.adaptor_n_layers, - kernel_size=args.adaptor_kernel_size, - stride=args.adaptor_stride, - add_layernorm=args.adaptor_layernorm, - ) + self.is_v0_arch = not args.adaptor_proj + self.w2v_proj_ln = None + if not self.is_v0_arch and self.w2v_encoder.proj is not None: + self.w2v_proj_ln = LayerNorm(args.decoder_embed_dim) + self.adaptor = self.build_adaptor(args) + + self.num_updates = 0 + self.freezing_updates = args.w2v_freezing_updates + self.finetuning_params = args.finetune_w2v_params for k, p in self.w2v_encoder.w2v_model.named_parameters(): - # Freeze pretrained models by default - if safe_hasattr( - args, "finetune_w2v_params" - ) and XMTransformerModel.finetune_params(args.finetune_w2v_params, k): - p.requires_grad = True - else: - p.requires_grad = False + p.requires_grad = need_finetuning(self.finetuning_params, k) @classmethod def add_args(cls, parser): @@ -236,25 +281,32 @@ def add_args(cls, parser): metavar="STR", help="comma-separated param strings to finetune.", ) + parser.add_argument("--w2v-freezing-updates", type=int) + parser.add_argument("--load-pretrained-encoder-from", type=str, metavar="STR") Conv1dAdaptor.add_args(parser) + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + self.num_updates = num_updates + def forward(self, src_tokens, src_lengths=None, **kwargs): + if self.freezing_updates is not None and \ + self.num_updates > self.freezing_updates: + for p in self.w2v_encoder.w2v_model.parameters(): + p.requires_grad = True + padding_mask = lengths_to_padding_mask(src_lengths) out = self.w2v_encoder.forward(src_tokens, padding_mask, tbc=True) - x = out["encoder_out"] - enc_padding_mask = None - if out["encoder_padding_mask"] is not None: - enc_padding_mask = out["encoder_padding_mask"].transpose( - 0, 1 - ) # T X B --> B X T + x, padding_mask = out["encoder_out"], out["padding_mask"] + if self.w2v_proj_ln is not None: + x = self.w2v_proj_ln(x) - x, enc_padding_mask = self.adaptor(x, enc_padding_mask) + if self.adaptor is not None: + x, padding_mask = self.adaptor(x, padding_mask) return { "encoder_out": [x], # T x B x C - "encoder_padding_mask": [enc_padding_mask] - if enc_padding_mask.any() - else [], # B x T + "encoder_padding_mask": [] if padding_mask is None else [padding_mask], # B x T "encoder_embedding": [], # B x T x C "encoder_states": [], # List[T x B x C] "src_tokens": [], @@ -324,7 +376,8 @@ def add_decoder_args(parser): help="dropout probability after activation in FFN.", ) parser.add_argument( - "--decoder-embed-dim", type=int, metavar="N", help="decoder embedding dimension" + "--decoder-embed-dim", type=int, metavar="N", + help="decoder embedding dimension" ) parser.add_argument( "--decoder-ffn-embed-dim", @@ -347,8 +400,12 @@ def add_decoder_args(parser): help="apply layernorm before each decoder block", ) parser.add_argument( - "--layernorm-embedding", action="store_true", help="add layernorm to embedding" + "--layernorm-embedding", action="store_true", + help="add layernorm to embedding" ) + parser.add_argument("--decoder-layerdrop", type=float, metavar="D") + parser.add_argument("--decoder-learned-pos", action="store_true") + parser.add_argument("--share-decoder-input-output-embed", action="store_true") parser.add_argument( "--no-scale-embedding", action="store_true", @@ -366,7 +423,6 @@ def add_decoder_args(parser): metavar="STR", help="comma-separated param strings to finetune.", ) - parser.add_argument("--checkpoint-activations", action="store_true") @register_model("xm_transformer") @@ -379,42 +435,59 @@ def add_args(cls, parser): """Add model-specific arguments to the parser.""" Wav2VecEncoderWithAdaptor.add_args(parser) add_decoder_args(parser) + parser.add_argument("--checkpoint-activations", action="store_true") + parser.add_argument("--offload-activations", action="store_true") + parser.add_argument("--min-params-to-wrap", type=int) + + @classmethod + def maybe_load_pretrained(cls, component, checkpoint: Optional[str] = None): + if checkpoint is None: + return component + + _load = checkpoint_utils.load_pretrained_component_from_model + try: + return _load(component, checkpoint) + except RuntimeError as e: + logger.warning(e) + return _load(component, checkpoint, strict=False) @classmethod def build_encoder(cls, args): _args = copy.deepcopy(args) - state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) - if state.get("cfg") is not None: - encoder_embed_dim = state["cfg"]._content["model"]["encoder_embed_dim"] - elif state.get("args") is not None: - encoder_embed_dim = state["args"].encoder_embed_dim - else: - raise ValueError(f"Invalid config in {args.w2v_path}") - _args.decoder_embed_dim = encoder_embed_dim + if not args.adaptor_proj: # V0 arch + state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) + if state.get("cfg") is not None: + encoder_embed_dim = state["cfg"]._content["model"][ + "encoder_embed_dim"] + elif state.get("args") is not None: + encoder_embed_dim = state["args"].encoder_embed_dim + else: + raise ValueError(f"Invalid config in {args.w2v_path}") + _args.decoder_embed_dim = encoder_embed_dim + del state + encoder = Wav2VecEncoderWithAdaptor(_args) - return encoder + return cls.maybe_load_pretrained( + encoder, getattr(args, "load_pretrained_encoder_from", None) + ) @classmethod def build_decoder(cls, args, task, embed_tokens): _args = copy.deepcopy(args) + if args.adaptor_proj: # not V0 arch + _args.encoder_embed_dim = _args.decoder_embed_dim _args.dropout = args.decoder_dropout _args.attention_dropout = args.decoder_attention_dropout _args.activation_dropout = args.decoder_activation_dropout _args.max_target_positions = 1024 decoder = TransformerDecoder(_args, task.target_dictionary, embed_tokens) - if getattr(args, "load_pretrained_decoder_from", None): - decoder = checkpoint_utils.load_pretrained_component_from_model( - component=decoder, checkpoint=args.load_pretrained_decoder_from - ) + decoder = cls.maybe_load_pretrained( + decoder, getattr(args, "load_pretrained_decoder_from", None) + ) + for k, p in decoder.named_parameters(): - # Freeze pretrained models by default - if safe_hasattr( - args, "finetune_decoder_params" - ) and XMTransformerModel.finetune_params(args.finetune_decoder_params, k): - p.requires_grad = True - else: - p.requires_grad = False + p.requires_grad = need_finetuning(args.finetune_decoder_params, k) return decoder @classmethod @@ -432,6 +505,7 @@ def build_embedding(dictionary, embed_dim): decoder_embed_tokens = build_embedding( task.target_dictionary, args.decoder_embed_dim ) + encoder = cls.build_encoder(args) decoder = cls.build_decoder(args, task, decoder_embed_tokens) return cls(encoder, decoder) @@ -442,16 +516,13 @@ def get_normalized_probs( log_probs: bool, sample: Optional[Dict[str, Tensor]] = None, ): - # net_output['encoder_out'] is a (B, T, D) tensor - lprobs = self.get_normalized_probs_scriptable(net_output, log_probs, sample) - lprobs.batch_first = True - return lprobs + return self.get_normalized_probs_scriptable(net_output, log_probs, sample) def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): """ The forward method inherited from the base class has a **kwargs argument in its input, which is not supported in torchscript. This - method overrites the forward method definition without **kwargs. + method overwrites the forward method definition without **kwargs. """ encoder_out = self.encoder( src_tokens=src_tokens, src_lengths=src_lengths, **kwargs @@ -469,16 +540,6 @@ def upgrade_state_dict(self, state_dict): state_dict[new] = state_dict[k] del state_dict[k] - @staticmethod - def finetune_params(finetune_params, param_name): - if finetune_params == "all": - return True - finetune_params_list = finetune_params.split(",") - for finetune_param in finetune_params_list: - if finetune_param in param_name: - return True - return False - def set_default_w2v_encoder_args(args): args.no_pretrained_weights = getattr(args, "no_pretrained_weights", False) @@ -506,23 +567,27 @@ def set_default_w2v_encoder_args(args): args.layerdrop = getattr(args, "layerdrop", 0.0) args.normalize = getattr(args, "normalize", False) + args.finetune_w2v_params = getattr(args, "finetune_w2v_params", "all") + args.w2v_freezing_updates = getattr(args, "w2v_freezing_updates", None) def set_default_adaptor_args(args): args.adaptor_n_layers = getattr(args, "adaptor_n_layers", 3) args.adaptor_kernel_size = getattr(args, "adaptor_kernel_size", 3) args.adaptor_stride = getattr(args, "adaptor_stride", 2) + args.adaptor_layerdrop = getattr(args, "adaptor_layerdrop", 0.0) args.adaptor_layernorm = getattr(args, "adaptor_layernorm", False) + args.adaptor_proj = getattr(args, "adaptor_proj", False) -def set_default_mbart_decoder_args(args): +def set_default_transformer_decoder_args(args): args.decoder_embed_path = getattr(args, "decoder_embed_path", None) args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4 * 1024) args.decoder_layers = getattr(args, "decoder_layers", 12) args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) - args.decoder_normalize_before = getattr(args, "decoder_normalize_before", True) - args.decoder_learned_pos = getattr(args, "decoder_learned_pos", True) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) args.adaptive_input = getattr(args, "adaptive_input", False) args.decoder_attention_dropout = getattr(args, "decoder_attention_dropout", 0.0) @@ -531,7 +596,7 @@ def set_default_mbart_decoder_args(args): args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) args.share_decoder_input_output_embed = getattr( - args, "share_decoder_input_output_embed", True + args, "share_decoder_input_output_embed", False ) args.no_token_positional_embeddings = getattr( args, "no_token_positional_embeddings", False @@ -544,16 +609,24 @@ def set_default_mbart_decoder_args(args): args.no_scale_embedding = getattr(args, "no_scale_embedding", False) args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) - args.layernorm_embedding = getattr(args, "layernorm_embedding", True) + args.layernorm_embedding = getattr(args, "layernorm_embedding", False) args.activation_fn = getattr(args, "activation_fn", "gelu") args.pooler_activation_fn = getattr(args, "pooler_activation_fn", "tanh") args.pooler_dropout = getattr(args, "pooler_dropout", 0.0) + + args.finetune_decoder_params = getattr(args, "finetune_decoder_params", "all") + + +def set_default_general_args(args): args.checkpoint_activations = getattr(args, "checkpoint_activations", False) + args.offload_activations = getattr(args, "offload_activations", False) + args.min_params_to_wrap = getattr(args, "min_params_to_wrap", int(1e8)) @register_model_architecture(model_name="xm_transformer", arch_name="xm_transformer") def base_architecture(args): + set_default_general_args(args) set_default_w2v_encoder_args(args) set_default_adaptor_args(args) - set_default_mbart_decoder_args(args) + set_default_transformer_decoder_args(args) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index a4057f6030..191b99a740 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -150,6 +150,23 @@ class Wav2Vec2AsrConfig(FairseqDataclass): data: str = II("task.data") # this holds the loaded wav2vec args w2v_args: Any = None + checkpoint_activations: bool = field( + default=False, metadata={"help": "checkpoint_activations"} + ) + offload_activations: bool = field( + default=False, metadata={"help": "offload_activations"} + ) + min_params_to_wrap: int = field( + default=int(1e8), + metadata={ + "help": "minimum number of params for a layer to be wrapped with FSDP() when " + "training with --ddp-backend=fully_sharded. Smaller values will " + "improve memory efficiency, but may make torch.distributed " + "communication less efficient due to smaller input sizes. This option " + "is set to 0 (i.e., always wrap) when --checkpoint-activations or " + "--offload-activations are passed." + }, + ) checkpoint_activations: bool = field( default=False, @@ -341,6 +358,9 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): "no_mask_channel_overlap": cfg.no_mask_channel_overlap, "encoder_layerdrop": cfg.layerdrop, "feature_grad_mult": cfg.feature_grad_mult, + "checkpoint_activations": cfg.checkpoint_activations, + "offload_activations": cfg.offload_activations, + "min_params_to_wrap": cfg.min_params_to_wrap, } if cfg.w2v_args is None: From 59b3ada2e2bcc3f89fbe8d23db53212c0101b4b3 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 30 Dec 2021 22:13:39 -0800 Subject: [PATCH 534/774] fix SacrebleuScorer.score() Summary: fix SacrebleuScorer.score() Reviewed By: sravyapopuri388 Differential Revision: D33311843 fbshipit-source-id: 8536baceab6ef2e7c9c4a9a8a005abaa6a9229f0 --- fairseq/scoring/bleu.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fairseq/scoring/bleu.py b/fairseq/scoring/bleu.py index 97de5f966e..e55bd2f393 100644 --- a/fairseq/scoring/bleu.py +++ b/fairseq/scoring/bleu.py @@ -59,16 +59,17 @@ def add_string(self, ref, pred): self.ref.append(self.tokenizer.tokenize(ref)) self.pred.append(self.tokenizer.tokenize(pred)) - def score(self, order=4): - return self.result_string(order).score - - def result_string(self, order=4): + def _score(self, order=4): if order != 4: raise NotImplementedError # tokenization and lowercasing are performed by self.tokenizer instead. - return self.sacrebleu.corpus_bleu( - self.pred, [self.ref], tokenize="none" - ).format() + return self.sacrebleu.corpus_bleu(self.pred, [self.ref], tokenize="none") + + def score(self, order=4): + return self._score(order).score + + def result_string(self, order=4): + return self._score(order).format() @dataclass From ee177fc4fa06dcb3d5fd466559af1b46893c00e8 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Fri, 31 Dec 2021 12:29:14 -0800 Subject: [PATCH 535/774] add xm_transformer test; refactor speech tests Summary: add xm_transformer test; refactor speech tests Reviewed By: sravyapopuri388 Differential Revision: D33312231 fbshipit-source-id: a2b2695fc3c10d5420abbe23a4a3005777aa2ae1 --- tests/speech/__init__.py | 118 +++++++++++++++++++++------ tests/speech/test_fastspeech2.py | 23 +----- tests/speech/test_s2t_transformer.py | 41 ++-------- tests/speech/test_tts_transformer.py | 23 +----- tests/speech/test_xm_transformer.py | 56 +++++++++++++ 5 files changed, 164 insertions(+), 97 deletions(-) create mode 100644 tests/speech/test_xm_transformer.py diff --git a/tests/speech/__init__.py b/tests/speech/__init__.py index a421139027..4e07140c16 100644 --- a/tests/speech/__init__.py +++ b/tests/speech/__init__.py @@ -3,12 +3,18 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from argparse import Namespace import os import unittest from pathlib import Path +from typing import List, Dict, Optional import torch +from fairseq.checkpoint_utils import load_model_ensemble_and_task +from fairseq.scoring.wer import WerScorer +from fairseq.scoring.bleu import SacrebleuScorer + S3_BASE_URL = "https://dl.fbaipublicfiles.com/fairseq" @@ -21,34 +27,96 @@ def download(cls, base_url: str, out_root: Path, filename: str): torch.hub.download_url_to_file(url, path.as_posix(), progress=True) return path - def set_up_librispeech(self): + def _set_up(self, dataset_id: str, s3_dir: str, data_filenames: List[str]): self.use_cuda = torch.cuda.is_available() - self.root = Path.home() / ".cache" / "fairseq" / "librispeech" + self.root = Path.home() / ".cache" / "fairseq" / dataset_id self.root.mkdir(exist_ok=True, parents=True) os.chdir(self.root) - self.data_filenames = [ - "cfg_librispeech.yaml", - "spm_librispeech_unigram10000.model", - "spm_librispeech_unigram10000.txt", - "librispeech_test-other.tsv", - "librispeech_test-other.zip", - ] - self.base_url = f"{S3_BASE_URL}/s2t/librispeech" - for filename in self.data_filenames: + self.base_url = f"{S3_BASE_URL}/{s3_dir}" + for filename in data_filenames: self.download(self.base_url, self.root, filename) + def set_up_librispeech(self): + self._set_up( + "librispeech", + "s2t/librispeech", + [ + "cfg_librispeech.yaml", + "spm_librispeech_unigram10000.model", + "spm_librispeech_unigram10000.txt", + "librispeech_test-other.tsv", + "librispeech_test-other.zip", + ], + ) + def set_up_ljspeech(self): - self.use_cuda = torch.cuda.is_available() - self.root = Path.home() / ".cache" / "fairseq" / "ljspeech" - self.root.mkdir(exist_ok=True, parents=True) - os.chdir(self.root) - self.data_filenames = [ - "cfg_ljspeech_g2p.yaml", - "ljspeech_g2p_gcmvn_stats.npz", - "ljspeech_g2p.txt", - "ljspeech_test.tsv", - "ljspeech_test.zip", - ] - self.base_url = f"{S3_BASE_URL}/s2/ljspeech" - for filename in self.data_filenames: - self.download(self.base_url, self.root, filename) + self._set_up( + "ljspeech", + "s2/ljspeech", + [ + "cfg_ljspeech_g2p.yaml", + "ljspeech_g2p_gcmvn_stats.npz", + "ljspeech_g2p.txt", + "ljspeech_test.tsv", + "ljspeech_test.zip", + ], + ) + + def set_up_sotasty_es_en(self): + self._set_up( + "sotasty_es_en", + "s2t/big/es-en", + [ + "cfg_es_en.yaml", + "spm_bpe32768_es_en.model", + "spm_bpe32768_es_en.txt", + "sotasty_es_en_test_ted.tsv", + "sotasty_es_en_test_ted.zip", + ], + ) + + def download_and_load_checkpoint( + self, checkpoint_filename: str, arg_overrides: Optional[Dict[str, str]] = None + ): + path = self.download(self.base_url, self.root, checkpoint_filename) + _arg_overrides = arg_overrides or {} + _arg_overrides["data"] = self.root.as_posix() + models, cfg, task = load_model_ensemble_and_task( + [path.as_posix()], arg_overrides=_arg_overrides + ) + if self.use_cuda: + for model in models: + model.cuda() + generator = task.build_generator(models, cfg) + return models, cfg, task, generator + + @classmethod + def get_batch_iterator(cls, task, test_split, max_tokens, max_positions): + task.load_dataset(test_split) + return task.get_batch_iterator( + dataset=task.dataset(test_split), + max_tokens=max_tokens, + max_positions=max_positions, + num_workers=1, + ).next_epoch_itr(shuffle=False) + + @classmethod + def get_wer_scorer( + cls, tokenizer="none", lowercase=False, remove_punct=False, char_level=False + ): + scorer_args = { + "wer_tokenizer": tokenizer, + "wer_lowercase": lowercase, + "wer_remove_punct": remove_punct, + "wer_char_level": char_level, + } + return WerScorer(Namespace(**scorer_args)) + + @classmethod + def get_bleu_scorer(cls, tokenizer="13a", lowercase=False, char_level=False): + scorer_args = { + "sacrebleu_tokenizer": tokenizer, + "sacrebleu_lowercase": lowercase, + "sacrebleu_char_level": char_level, + } + return SacrebleuScorer(Namespace(**scorer_args)) diff --git a/tests/speech/test_fastspeech2.py b/tests/speech/test_fastspeech2.py index 5da614f17e..7150a3bda2 100644 --- a/tests/speech/test_fastspeech2.py +++ b/tests/speech/test_fastspeech2.py @@ -9,7 +9,6 @@ from tqdm import tqdm from fairseq import utils -from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion from tests.speech import TestFairseqSpeech @@ -21,33 +20,17 @@ def setUp(self): @torch.no_grad() def test_ljspeech_fastspeech2_checkpoint(self): - checkpoint_filename = "ljspeech_fastspeech2_g2p.pt" - path = self.download(self.base_url, self.root, checkpoint_filename) - - models, cfg, task = load_model_ensemble_and_task( - [path.as_posix()], + models, cfg, task, generator = self.download_and_load_checkpoint( + "ljspeech_fastspeech2_g2p.pt", arg_overrides={ - "data": self.root.as_posix(), "config_yaml": "cfg_ljspeech_g2p.yaml", "vocoder": "griffin_lim", "fp16": False, }, ) - if self.use_cuda: - for model in models: - model.cuda() - test_split = "ljspeech_test" - task.load_dataset(test_split) - batch_iterator = task.get_batch_iterator( - dataset=task.dataset(test_split), - max_tokens=65_536, - max_positions=4_096, - num_workers=1, - ).next_epoch_itr(shuffle=False) + batch_iterator = self.get_batch_iterator(task, "ljspeech_test", 65_536, 4_096) progress = tqdm(batch_iterator, total=len(batch_iterator)) - generator = task.build_generator(models, cfg) - mcd, n_samples = 0.0, 0 for sample in progress: sample = utils.move_to_cuda(sample) if self.use_cuda else sample diff --git a/tests/speech/test_s2t_transformer.py b/tests/speech/test_s2t_transformer.py index d8a15275b4..951660b323 100644 --- a/tests/speech/test_s2t_transformer.py +++ b/tests/speech/test_s2t_transformer.py @@ -4,54 +4,31 @@ # LICENSE file in the root directory of this source tree. import unittest -from argparse import Namespace import torch from tqdm import tqdm from fairseq import utils -from fairseq.checkpoint_utils import load_model_ensemble_and_task -from fairseq.scoring.wer import WerScorer from tests.speech import TestFairseqSpeech -@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") class TestS2TTransformer(TestFairseqSpeech): def setUp(self): self.set_up_librispeech() @torch.no_grad() def test_librispeech_s2t_transformer_s_checkpoint(self): - checkpoint_filename = "librispeech_transformer_s.pt" - path = self.download(self.base_url, self.root, checkpoint_filename) - - models, cfg, task = load_model_ensemble_and_task( - [path.as_posix()], - arg_overrides={ - "data": self.root.as_posix(), - "config_yaml": "cfg_librispeech.yaml", - }, + models, cfg, task, generator = self.download_and_load_checkpoint( + "librispeech_transformer_s.pt", + arg_overrides={"config_yaml": "cfg_librispeech.yaml"}, ) - if self.use_cuda: - for model in models: - model.cuda() - generator = task.build_generator(models, cfg) - test_split = "librispeech_test-other" - task.load_dataset(test_split) - batch_iterator = task.get_batch_iterator( - dataset=task.dataset(test_split), - max_tokens=65_536, - max_positions=(4_096, 1_024), - num_workers=1, - ).next_epoch_itr(shuffle=False) + if not self.use_cuda: + return - scorer_args = { - "wer_tokenizer": "none", - "wer_lowercase": False, - "wer_remove_punct": False, - "wer_char_level": False, - } - scorer = WerScorer(Namespace(**scorer_args)) + batch_iterator = self.get_batch_iterator( + task, "librispeech_test-other", 65_536, (4_096, 1_024) + ) + scorer = self.get_wer_scorer() progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) for batch_idx, sample in progress: sample = utils.move_to_cuda(sample) if self.use_cuda else sample diff --git a/tests/speech/test_tts_transformer.py b/tests/speech/test_tts_transformer.py index 0c01e20e56..b6330c6077 100644 --- a/tests/speech/test_tts_transformer.py +++ b/tests/speech/test_tts_transformer.py @@ -9,7 +9,6 @@ from tqdm import tqdm from fairseq import utils -from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion from tests.speech import TestFairseqSpeech @@ -21,33 +20,17 @@ def setUp(self): @torch.no_grad() def test_ljspeech_tts_transformer_checkpoint(self): - checkpoint_filename = "ljspeech_transformer_g2p.pt" - path = self.download(self.base_url, self.root, checkpoint_filename) - - models, cfg, task = load_model_ensemble_and_task( - [path.as_posix()], + models, cfg, task, generator = self.download_and_load_checkpoint( + "ljspeech_transformer_g2p.pt", arg_overrides={ - "data": self.root.as_posix(), "config_yaml": "cfg_ljspeech_g2p.yaml", "vocoder": "griffin_lim", "fp16": False, }, ) - if self.use_cuda: - for model in models: - model.cuda() - test_split = "ljspeech_test" - task.load_dataset(test_split) - batch_iterator = task.get_batch_iterator( - dataset=task.dataset(test_split), - max_tokens=65_536, - max_positions=768, - num_workers=1, - ).next_epoch_itr(shuffle=False) + batch_iterator = self.get_batch_iterator(task, "ljspeech_test", 65_536, 1024) progress = tqdm(batch_iterator, total=len(batch_iterator)) - generator = task.build_generator(models, cfg) - mcd, n_samples = 0.0, 0 for sample in progress: sample = utils.move_to_cuda(sample) if self.use_cuda else sample diff --git a/tests/speech/test_xm_transformer.py b/tests/speech/test_xm_transformer.py new file mode 100644 index 0000000000..60bb0dc6e1 --- /dev/null +++ b/tests/speech/test_xm_transformer.py @@ -0,0 +1,56 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest + +import torch +from tqdm import tqdm + +from fairseq import utils +from tests.speech import TestFairseqSpeech + + +class TestXMTransformer(TestFairseqSpeech): + def setUp(self): + self.set_up_sotasty_es_en() + + @torch.no_grad() + def test_sotasty_es_en_600m_checkpoint(self): + models, cfg, task, generator = self.download_and_load_checkpoint( + "xm_transformer_600m_es_en_md.pt", + arg_overrides={"config_yaml": "cfg_es_en.yaml"}, + ) + if not self.use_cuda: + return + + batch_iterator = self.get_batch_iterator( + task, "sotasty_es_en_test_ted", 3_000_000, (1_000_000, 1_024) + ) + scorer = self.get_bleu_scorer() + progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) + for batch_idx, sample in progress: + sample = utils.move_to_cuda(sample) if self.use_cuda else sample + hypo = task.inference_step(generator, models, sample) + for i, sample_id in enumerate(sample["id"].tolist()): + tgt_tokens = ( + utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()) + .int() + .cpu() + ) + tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") + hypo_str = task.tgt_dict.string( + hypo[i][0]["tokens"].int().cpu(), "sentencepiece" + ) + if batch_idx == 0 and i < 3: + print(f"T-{sample_id} {tgt_str}") + print(f"H-{sample_id} {hypo_str}") + scorer.add_string(tgt_str, hypo_str) + reference_bleu = 31.7 + print(f"{scorer.result_string()} (reference: {reference_bleu})") + self.assertAlmostEqual(scorer.score(), reference_bleu, delta=0.2) + + +if __name__ == "__main__": + unittest.main() From 43defa1bcb9cc3d5c532d12cba5e01f37dad0350 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Tue, 4 Jan 2022 09:08:49 -0800 Subject: [PATCH 536/774] add hub interface for TTS Summary: add hub interface for TTS Reviewed By: pipibjc Differential Revision: D33394399 fbshipit-source-id: 4efb5b08cf04ef77a469006f9822e22a27112ac6 --- fairseq/data/audio/data_cfg.py | 9 +- fairseq/models/text_to_speech/fastspeech2.py | 34 +++++ .../models/text_to_speech/hub_interface.py | 137 ++++++++++++++++++ .../models/text_to_speech/tts_transformer.py | 41 ++++++ 4 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 fairseq/models/text_to_speech/hub_interface.py diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 8ff0ba0397..18fcf416f7 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -141,8 +141,13 @@ def global_cmvn_stats_npz(self) -> Optional[str]: return self._auto_convert_to_abs_path(path) @property - def vocoder(self) -> Optional[Dict[str, str]]: - return self.config.get("vocoder", None) + def vocoder(self) -> Dict[str, str]: + vocoder = self.config.get("vocoder", {"type": "griffin_lim"}) + return self._auto_convert_to_abs_path(vocoder) + + @property + def hub(self) -> Dict[str, str]: + return self.config.get("hub", {}) class S2SDataConfig(S2TDataConfig): diff --git a/fairseq/models/text_to_speech/fastspeech2.py b/fairseq/models/text_to_speech/fastspeech2.py index f2a0792b17..bfdb95615a 100644 --- a/fairseq/models/text_to_speech/fastspeech2.py +++ b/fairseq/models/text_to_speech/fastspeech2.py @@ -23,6 +23,7 @@ from fairseq import utils from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models.text_to_speech.tacotron2 import Postnet +from fairseq.models.text_to_speech.hub_interface import TTSHubInterface logger = logging.getLogger(__name__) @@ -332,6 +333,39 @@ class FastSpeech2Model(FairseqEncoderModel): NON_AUTOREGRESSIVE = True + @classmethod + def hub_models(cls): + base_url = "http://dl.fbaipublicfiles.com/fairseq/s2" + model_ids = [ + "fastspeech2-en-ljspeech", + "fastspeech2-en-200_speaker-cv4", + ] + return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} + + @classmethod + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + vocoder: str = "griffin_lim", + fp16: bool = False, + **kwargs, + ): + from fairseq import hub_utils + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + config_yaml=config_yaml, + vocoder=vocoder, + fp16=fp16, + **kwargs, + ) + return TTSHubInterface(x["args"], x["task"], x["models"][0]) + @staticmethod def add_args(parser): parser.add_argument("--dropout", type=float) diff --git a/fairseq/models/text_to_speech/hub_interface.py b/fairseq/models/text_to_speech/hub_interface.py new file mode 100644 index 0000000000..8e367665da --- /dev/null +++ b/fairseq/models/text_to_speech/hub_interface.py @@ -0,0 +1,137 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from pathlib import Path +from typing import Optional, Dict, Tuple +import random + +import torch +import torch.nn as nn + +logger = logging.getLogger(__name__) + + +class TTSHubInterface(nn.Module): + def __init__(self, cfg, task, model): + super().__init__() + self.cfg = cfg + self.task = task + self.model = model + self.model.eval() + + self.update_cfg_with_data_cfg(self.cfg, self.task.data_cfg) + self.generator = self.task.build_generator([self.model], self.cfg) + + @classmethod + def phonemize( + cls, + text: str, + lang: Optional[str], + phonemizer: Optional[str] = None, + preserve_punct: bool = False, + to_simplified_zh: bool = False, + ): + if to_simplified_zh: + import hanziconv + + text = hanziconv.HanziConv.toSimplified(text) + + if phonemizer == "g2p": + import g2p_en + + g2p = g2p_en.G2p() + if preserve_punct: + return " ".join("|" if p == " " else p for p in g2p(text)) + else: + res = [{",": "sp", ";": "sp"}.get(p, p) for p in g2p(text)] + return " ".join(p for p in res if p.isalnum()) + if phonemizer == "g2pc": + import g2pc + + g2p = g2pc.G2pC() + return " ".join([w[3] for w in g2p(text)]) + elif phonemizer == "ipa": + assert lang is not None + import phonemizer + from phonemizer.separator import Separator + + lang_map = {"en": "en-us", "fr": "fr-fr"} + return phonemizer.phonemize( + text, + backend="espeak", + language=lang_map.get(lang, lang), + separator=Separator(word="| ", phone=" "), + ) + else: + return text + + @classmethod + def tokenize(cls, text: str, tkn_cfg: Dict[str, str]): + sentencepiece_model = tkn_cfg.get("sentencepiece_model", None) + if sentencepiece_model is not None: + assert Path(sentencepiece_model).exists() + import sentencepiece as sp + + spm = sp.SentencePieceProcessor() + spm.Load(sentencepiece_model) + return " ".join(spm.Encode(text, out_type=str)) + else: + return text + + @classmethod + def update_cfg_with_data_cfg(cls, cfg, data_cfg): + cfg["task"].vocoder = data_cfg.vocoder.get("type", "griffin_lim") + + @classmethod + def get_model_input( + cls, task, text: str, speaker: Optional[int] = None, verbose: bool = False + ): + phonemized = cls.phonemize( + text, + task.data_cfg.hub.get("lang", None), + task.data_cfg.hub.get("phonemizer", None), + task.data_cfg.hub.get("preserve_punct", False), + task.data_cfg.hub.get("to_simplified_zh", False), + ) + tkn_cfg = task.data_cfg.bpe_tokenizer + tokenized = cls.tokenize(phonemized, tkn_cfg) + if verbose: + logger.info(f"text: {text}") + logger.info(f"phonemized: {phonemized}") + logger.info(f"tokenized: {tokenized}") + + spk = task.data_cfg.hub.get("speaker", speaker) + n_speakers = len(task.speaker_to_id or {}) + if spk is None and n_speakers > 0: + spk = random.randint(0, n_speakers - 1) + if spk is not None: + spk = max(0, min(spk, n_speakers - 1)) + if verbose: + logger.info(f"speaker: {spk}") + spk = None if spk is None else torch.Tensor([[spk]]).long() + + src_tokens = task.src_dict.encode_line(tokenized).view(1, -1) + src_lengths = torch.Tensor([len(tokenized.split())]).long() + return { + "net_input": { + "src_tokens": src_tokens, + "src_lengths": src_lengths, + "prev_output_tokens": None, + }, + "target_lengths": None, + "speaker": spk, + } + + @classmethod + def get_prediction(cls, task, model, generator, sample) -> Tuple[torch.Tensor, int]: + prediction = generator.generate(model, sample) + return prediction[0]["waveform"], task.sr + + def predict( + self, text: str, speaker: Optional[int] = None, verbose: bool = False + ) -> Tuple[torch.Tensor, int]: + sample = self.get_model_input(self.task, text, speaker, verbose=verbose) + return self.get_prediction(self.task, self.model, self.generator, sample) diff --git a/fairseq/models/text_to_speech/tts_transformer.py b/fairseq/models/text_to_speech/tts_transformer.py index 22208d2d0b..fef56af6d5 100644 --- a/fairseq/models/text_to_speech/tts_transformer.py +++ b/fairseq/models/text_to_speech/tts_transformer.py @@ -21,6 +21,7 @@ from fairseq.modules import LayerNorm, PositionalEmbedding, FairseqDropout from fairseq.data.data_utils import lengths_to_padding_mask from fairseq import utils +from fairseq.models.text_to_speech.hub_interface import TTSHubInterface logger = logging.getLogger(__name__) @@ -313,6 +314,46 @@ class TTSTransformerModel(FairseqEncoderDecoderModel): Implementation for https://arxiv.org/pdf/1809.08895.pdf """ + @classmethod + def hub_models(cls): + base_url = "http://dl.fbaipublicfiles.com/fairseq/s2" + model_ids = [ + "tts_transformer-en-ljspeech", + "tts_transformer-en-200_speaker-cv4", + "tts_transformer-es-css10", + "tts_transformer-fr-cv7_css10", + "tts_transformer-ru-cv7_css10", + "tts_transformer-zh-cv7_css10", + "tts_transformer-ar-cv7_css10", + "tts_transformer-tr-cv7_css10", + "tts_transformer-vi-cv7" + ] + return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} + + @classmethod + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + vocoder: str = "griffin_lim", + fp16: bool = False, + **kwargs, + ): + from fairseq import hub_utils + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + config_yaml=config_yaml, + vocoder=vocoder, + fp16=fp16, + **kwargs, + ) + return TTSHubInterface(x["args"], x["task"], x["models"][0]) + @staticmethod def add_args(parser): parser.add_argument("--dropout", type=float) From 1d5da6d5b954ba01fc3df12d25d63df27437e20e Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Tue, 4 Jan 2022 12:32:43 -0800 Subject: [PATCH 537/774] add hub interface for S2T Summary: add hub interface for S2T Reviewed By: sravyapopuri388 Differential Revision: D33394412 fbshipit-source-id: bf844822261c213bafacd9b2c71d9d591bc0f3a6 --- .../models/speech_to_text/hub_interface.py | 126 ++++++++++++++++++ .../models/speech_to_text/s2t_transformer.py | 31 +++++ .../models/speech_to_text/xm_transformer.py | 45 +++++++ 3 files changed, 202 insertions(+) create mode 100644 fairseq/models/speech_to_text/hub_interface.py diff --git a/fairseq/models/speech_to_text/hub_interface.py b/fairseq/models/speech_to_text/hub_interface.py new file mode 100644 index 0000000000..ff6fd638a7 --- /dev/null +++ b/fairseq/models/speech_to_text/hub_interface.py @@ -0,0 +1,126 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from argparse import Namespace +import logging +from typing import Union, Tuple, Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from fairseq.data import encoders +from fairseq.data.audio.audio_utils import ( + get_waveform as get_wav, + convert_waveform as convert_wav, + get_fbank, +) +import fairseq.data.audio.feature_transforms.utterance_cmvn as utt_cmvn +from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset + +logger = logging.getLogger(__name__) + + +class S2THubInterface(nn.Module): + def __init__(self, cfg, task, model): + super().__init__() + self.cfg = cfg + self.task = task + self.model = model + self.model.eval() + self.generator = self.task.build_generator([self.model], self.cfg) + + @classmethod + def get_model_input(cls, task, audio: Union[str, torch.Tensor]): + input_type = task.data_cfg.hub.get("input_type", "fbank80") + if input_type == "fbank80_w_utt_cmvn": + if isinstance(audio, str): + feat = utt_cmvn.UtteranceCMVN()(get_fbank(audio)) + feat = feat.unsqueeze(0) # T x D -> 1 x T x D + else: + import torchaudio.compliance.kaldi as kaldi + + feat = kaldi.fbank(audio, num_mel_bins=80).numpy() # 1 x T x D + elif input_type in {"waveform", "standardized_waveform"}: + if isinstance(audio, str): + feat, sr = get_wav(audio) # C x T + feat, _ = convert_wav( + feat, sr, to_sample_rate=16_000, to_mono=True + ) # C x T -> 1 x T + else: + feat = audio.numpy() + else: + raise ValueError(f"Unknown value: input_type = {input_type}") + + src_lengths = torch.Tensor([feat.shape[1]]).long() + src_tokens = torch.from_numpy(feat) # 1 x T (x D) + if input_type == "standardized_waveform": + with torch.no_grad(): + src_tokens = F.layer_norm(src_tokens, src_tokens.shape) + + return { + "net_input": { + "src_tokens": src_tokens, + "src_lengths": src_lengths, + "prev_output_tokens": None, + }, + "target_lengths": None, + "speaker": None, + } + + @classmethod + def detokenize(cls, task, tokens): + text = task.tgt_dict.string(tokens) + tkn_cfg = task.data_cfg.bpe_tokenizer + tokenizer = encoders.build_bpe(Namespace(**tkn_cfg)) + return text if tokenizer is None else tokenizer.decode(text) + + @classmethod + def get_prefix_token(cls, task, lang): + prefix_size = int(task.data_cfg.prepend_tgt_lang_tag) + prefix_tokens = None + if prefix_size > 0: + assert lang is not None + lang_tag = SpeechToTextDataset.get_lang_tag_idx(lang, task.tgt_dict) + prefix_tokens = torch.Tensor([lang_tag]).long().unsqueeze(0) + return prefix_tokens + + @classmethod + def get_prediction( + cls, task, model, generator, sample, tgt_lang=None, synthesize_speech=False + ) -> Union[str, Tuple[str, Tuple[torch.Tensor, int]]]: + _tgt_lang = tgt_lang or task.data_cfg.hub.get("tgt_lang", None) + prefix = cls.get_prefix_token(task, _tgt_lang) + pred_tokens = generator.generate([model], sample, prefix_tokens=prefix) + pred = cls.detokenize(task, pred_tokens[0][0]["tokens"]) + + if synthesize_speech: + pfx = f"{_tgt_lang}_" if task.data_cfg.prepend_tgt_lang_tag else "" + tts_model_id = task.data_cfg.hub.get(f"{pfx}tts_model_id", None) + if tts_model_id is None: + logger.warning("TTS model configuration not found") + else: + _repo, _id = tts_model_id.split(":") + tts_model = torch.hub.load(_repo, _id, verbose=False) + pred = (pred, tts_model.predict(pred)) + return pred + + def predict( + self, + audio: Union[str, torch.Tensor], + tgt_lang: Optional[str] = None, + synthesize_speech: bool = False, + ) -> Union[str, Tuple[str, Tuple[torch.Tensor, int]]]: + # `audio` is either a file path or a 1xT Tensor + # return either text or (text, synthetic speech) + sample = self.get_model_input(self.task, audio) + return self.get_prediction( + self.task, + self.model, + self.generator, + sample, + tgt_lang=tgt_lang, + synthesize_speech=synthesize_speech, + ) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index cc10848509..a4b8c303cf 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -15,6 +15,7 @@ register_model, register_model_architecture, ) +from fairseq.models.speech_to_text.hub_interface import S2THubInterface from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.modules import ( FairseqDropout, @@ -85,6 +86,36 @@ class S2TTransformerModel(FairseqEncoderDecoderModel): project inputs into the encoder dimension as well as downsample input sequence for computational efficiency.""" + @classmethod + def hub_models(cls): + base_url = "http://dl.fbaipublicfiles.com/fairseq/s2t" + model_ids = [ + "s2t_transformer_s-en-asr-librispeech", + "s2t_transformer_m-en-asr-librispeech", + "s2t_transformer_l-en-asr-librispeech", + ] + return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} + + @classmethod + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + **kwargs, + ): + from fairseq import hub_utils + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + config_yaml=config_yaml, + **kwargs, + ) + return S2THubInterface(x["args"], x["task"], x["models"][0]) + def __init__(self, encoder, decoder): super().__init__(encoder, decoder) diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index 202f4b698d..fcc31ff6bb 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -17,6 +17,7 @@ register_model, register_model_architecture, ) +from fairseq.models.speech_to_text.hub_interface import S2THubInterface from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.models.wav2vec import Wav2VecEncoder from fairseq.modules.layer_norm import LayerNorm @@ -427,6 +428,50 @@ def add_decoder_args(parser): @register_model("xm_transformer") class XMTransformerModel(FairseqEncoderDecoderModel): + @classmethod + def hub_models(cls): + base_url = "http://dl.fbaipublicfiles.com/fairseq/s2t" + model_ids = [ + "xm_transformer_600m-es_en-multi_domain", + "xm_transformer_600m-ru_en-multi_domain", + "xm_transformer_600m-fr_en-multi_domain", + "xm_transformer_600m-en_es-multi_domain", + "xm_transformer_600m-en_ru-multi_domain", + "xm_transformer_600m-en_fr-multi_domain", + "xm_transformer_600m-en_zh-multi_domain", + "xm_transformer_600m-en_ar-multi_domain", + "xm_transformer_600m-en_tr-multi_domain", + "xm_transformer_600m-en_vi-multi_domain", + "xm_transformer-21_en-xls_r_300m", + "xm_transformer-en_15-xls_r_300m", + "xm_transformer-21_en-xls_r_1b", + "xm_transformer-en_15-xls_r_1b", + "xm_transformer-21_en-xls_r_2b", + "xm_transformer-en_15-xls_r_2b", + "xm_transformer-22_16-xls_r_2b", + ] + return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} + + @classmethod + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + **kwargs, + ): + from fairseq import hub_utils + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + config_yaml=config_yaml, + **kwargs, + ) + return S2THubInterface(x["args"], x["task"], x["models"][0]) + def __init__(self, encoder, decoder): super().__init__(encoder, decoder) From c9a8bea83ffbcc1dfb55fefc8fa33c6557aa1751 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Fri, 7 Jan 2022 00:37:39 -0800 Subject: [PATCH 538/774] Formatting fix: get CI green (#2860) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Applies `black` and `isort` to files ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2860 Reviewed By: Mortimerp9 Differential Revision: D33456637 Pulled By: dianaml0 fbshipit-source-id: 560b8d3a8f589cbecc92d0d21163596b5d47d609 --- fairseq/checkpoint_utils.py | 4 +- fairseq/criterions/sentence_prediction.py | 21 ++++-- fairseq/models/roberta/model.py | 49 ++++++++++++-- .../models/speech_to_text/s2t_transformer.py | 19 +++--- .../models/speech_to_text/xm_transformer.py | 67 ++++++++++--------- fairseq/models/text_to_speech/fastspeech2.py | 32 ++++----- .../models/text_to_speech/tts_transformer.py | 40 ++++++----- fairseq/models/wav2vec/wav2vec2_asr.py | 29 ++++---- fairseq/scoring/tokenizer.py | 10 ++- 9 files changed, 169 insertions(+), 102 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index cebb77a7ba..a5ef37d435 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -794,7 +794,9 @@ def create_pruning_pass(layers_to_keep, layer_name): def load_pretrained_component_from_model( - component: Union[FairseqEncoder, FairseqDecoder], checkpoint: str, strict: bool = True + component: Union[FairseqEncoder, FairseqDecoder], + checkpoint: str, + strict: bool = True, ): """ Load a pretrained FairseqEncoder or FairseqDecoder from checkpoint into the diff --git a/fairseq/criterions/sentence_prediction.py b/fairseq/criterions/sentence_prediction.py index 87af5e8a7b..b402d76039 100644 --- a/fairseq/criterions/sentence_prediction.py +++ b/fairseq/criterions/sentence_prediction.py @@ -8,6 +8,7 @@ import torch import torch.nn.functional as F + from fairseq import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass @@ -63,11 +64,17 @@ def forward(self, model, sample, reduce=True): logging_output = {} loss = task_loss # mha & ffn regularization update - if hasattr(model.args, "mha_reg_scale_factor") and model.args.mha_reg_scale_factor != 0.0: + if ( + hasattr(model.args, "mha_reg_scale_factor") + and model.args.mha_reg_scale_factor != 0.0 + ): mha_reg_loss = model._get_adaptive_head_loss() loss += mha_reg_loss logging_output.update({"mha_reg_loss": mha_reg_loss}) - if hasattr(model.args, "ffn_reg_scale_factor") and model.args.ffn_reg_scale_factor != 0.0: + if ( + hasattr(model.args, "ffn_reg_scale_factor") + and model.args.ffn_reg_scale_factor != 0.0 + ): ffn_reg_loss = model._get_adaptive_ffn_loss() loss += ffn_reg_loss logging_output.update({"ffn_reg_loss": ffn_reg_loss}) @@ -101,11 +108,17 @@ def reduce_metrics(logging_outputs) -> None: ) if mha_reg_loss_sum: metrics.log_scalar( - "mha_reg_loss", mha_reg_loss_sum / sample_size / math.log(2), sample_size, round=3 + "mha_reg_loss", + mha_reg_loss_sum / sample_size / math.log(2), + sample_size, + round=3, ) if ffn_reg_loss_sum: metrics.log_scalar( - "ffn_reg_loss", ffn_reg_loss_sum / sample_size / math.log(2), sample_size, round=3 + "ffn_reg_loss", + ffn_reg_loss_sum / sample_size / math.log(2), + sample_size, + round=3, ) if sample_size != ntokens: metrics.log_scalar( diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index b6315ffbfa..845a53aa44 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -11,6 +11,7 @@ import torch import torch.nn as nn import torch.nn.functional as F + from fairseq import utils from fairseq.models import ( FairseqEncoder, @@ -26,7 +27,6 @@ from .hub_interface import RobertaHubInterface - logger = logging.getLogger(__name__) @@ -252,9 +252,42 @@ def _get_adaptive_head_loss(self): for i in range(layer.self_attn.num_heads): start_idx = i * layer.self_attn.head_dim end_idx = (i + 1) * layer.self_attn.head_dim - norm_loss_layer += scaling * (torch.sum(torch.abs(layer.self_attn.q_proj.weight[start_idx:end_idx, ])) + torch.sum(torch.abs(layer.self_attn.q_proj.bias[start_idx:end_idx]))) - norm_loss_layer += scaling * (torch.sum(torch.abs(layer.self_attn.k_proj.weight[start_idx:end_idx, ])) + torch.sum(torch.abs(layer.self_attn.k_proj.bias[start_idx:end_idx]))) - norm_loss_layer += scaling * (torch.sum(torch.abs(layer.self_attn.v_proj.weight[start_idx:end_idx, ])) + torch.sum(torch.abs(layer.self_attn.v_proj.bias[start_idx:end_idx]))) + norm_loss_layer += scaling * ( + torch.sum( + torch.abs( + layer.self_attn.q_proj.weight[ + start_idx:end_idx, + ] + ) + ) + + torch.sum( + torch.abs(layer.self_attn.q_proj.bias[start_idx:end_idx]) + ) + ) + norm_loss_layer += scaling * ( + torch.sum( + torch.abs( + layer.self_attn.k_proj.weight[ + start_idx:end_idx, + ] + ) + ) + + torch.sum( + torch.abs(layer.self_attn.k_proj.bias[start_idx:end_idx]) + ) + ) + norm_loss_layer += scaling * ( + torch.sum( + torch.abs( + layer.self_attn.v_proj.weight[ + start_idx:end_idx, + ] + ) + ) + + torch.sum( + torch.abs(layer.self_attn.v_proj.bias[start_idx:end_idx]) + ) + ) norm_loss += norm_loss_layer return norm_loss @@ -263,8 +296,12 @@ def _get_adaptive_ffn_loss(self): ffn_scale_factor = float(self.args.ffn_reg_scale_factor) filter_loss = 0 for layer in self.encoder.sentence_encoder.layers: - filter_loss += torch.sum(torch.abs(layer.fc1.weight * ffn_scale_factor)) + torch.sum(torch.abs(layer.fc2.weight * ffn_scale_factor)) - filter_loss += torch.sum(torch.abs(layer.fc1.bias * ffn_scale_factor)) + torch.sum(torch.abs(layer.fc2.bias * ffn_scale_factor)) + filter_loss += torch.sum( + torch.abs(layer.fc1.weight * ffn_scale_factor) + ) + torch.sum(torch.abs(layer.fc2.weight * ffn_scale_factor)) + filter_loss += torch.sum( + torch.abs(layer.fc1.bias * ffn_scale_factor) + ) + torch.sum(torch.abs(layer.fc2.bias * ffn_scale_factor)) return filter_loss def get_normalized_probs(self, net_output, log_probs, sample=None): diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index a4b8c303cf..33c30e1b0b 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -2,11 +2,13 @@ import logging import math -from typing import Dict, List, Optional, Tuple from pathlib import Path +from typing import Dict, List, Optional, Tuple import torch import torch.nn as nn +from torch import Tensor + from fairseq import checkpoint_utils, utils from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import ( @@ -23,8 +25,6 @@ PositionalEmbedding, TransformerEncoderLayer, ) -from torch import Tensor - logger = logging.getLogger(__name__) @@ -98,14 +98,15 @@ def hub_models(cls): @classmethod def from_pretrained( - cls, - model_name_or_path, - checkpoint_file="model.pt", - data_name_or_path=".", - config_yaml="config.yaml", - **kwargs, + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + **kwargs, ): from fairseq import hub_utils + x = hub_utils.from_pretrained( model_name_or_path, checkpoint_file, diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index fcc31ff6bb..5d6f162d3e 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -3,17 +3,20 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import logging import copy +import logging from typing import Dict, List, Optional, Tuple import numpy as np import torch +import torch.nn as nn +from torch import Tensor -from fairseq import utils, checkpoint_utils +from fairseq import checkpoint_utils, utils +from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import ( - FairseqEncoderDecoderModel, FairseqEncoder, + FairseqEncoderDecoderModel, register_model, register_model_architecture, ) @@ -21,33 +24,34 @@ from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.models.wav2vec import Wav2VecEncoder from fairseq.modules.layer_norm import LayerNorm -from fairseq.data.data_utils import lengths_to_padding_mask -from torch import Tensor -import torch.nn as nn - logger = logging.getLogger(__name__) class Conv1dAdaptor(nn.Module): def __init__( - self, in_dim, out_dim, n_layers=3, kernel_size=3, stride=2, - layerdrop=0., layernorm=False, proj=False + self, + in_dim, + out_dim, + n_layers=3, + kernel_size=3, + stride=2, + layerdrop=0.0, + layernorm=False, + proj=False, ): super().__init__() self.proj, self.proj_ln = None, None self.post_proj, self.post_proj_ln = None, None if proj: self.proj = nn.Sequential( - nn.Linear(in_dim, in_dim * 4), - nn.ReLU(), - nn.Linear(in_dim * 4, in_dim) + nn.Linear(in_dim, in_dim * 4), nn.ReLU(), nn.Linear(in_dim * 4, in_dim) ) self.proj_ln = LayerNorm(in_dim) self.post_proj = nn.Sequential( nn.Linear(out_dim, out_dim * 4), nn.ReLU(), - nn.Linear(out_dim * 4, out_dim) + nn.Linear(out_dim * 4, out_dim), ) self.post_proj_ln = LayerNorm(out_dim) @@ -243,13 +247,14 @@ def build_adaptor(self, args): adaptor = None if args.adaptor_n_layers > 0: adaptor = Conv1dAdaptor( - args.decoder_embed_dim, args.decoder_embed_dim, + args.decoder_embed_dim, + args.decoder_embed_dim, n_layers=args.adaptor_n_layers, kernel_size=args.adaptor_kernel_size, stride=args.adaptor_stride, layerdrop=args.adaptor_layerdrop, layernorm=args.adaptor_layernorm, - proj=args.adaptor_proj + proj=args.adaptor_proj, ) return adaptor @@ -291,8 +296,10 @@ def set_num_updates(self, num_updates): self.num_updates = num_updates def forward(self, src_tokens, src_lengths=None, **kwargs): - if self.freezing_updates is not None and \ - self.num_updates > self.freezing_updates: + if ( + self.freezing_updates is not None + and self.num_updates > self.freezing_updates + ): for p in self.w2v_encoder.w2v_model.parameters(): p.requires_grad = True @@ -307,7 +314,9 @@ def forward(self, src_tokens, src_lengths=None, **kwargs): return { "encoder_out": [x], # T x B x C - "encoder_padding_mask": [] if padding_mask is None else [padding_mask], # B x T + "encoder_padding_mask": [] + if padding_mask is None + else [padding_mask], # B x T "encoder_embedding": [], # B x T x C "encoder_states": [], # List[T x B x C] "src_tokens": [], @@ -377,8 +386,7 @@ def add_decoder_args(parser): help="dropout probability after activation in FFN.", ) parser.add_argument( - "--decoder-embed-dim", type=int, metavar="N", - help="decoder embedding dimension" + "--decoder-embed-dim", type=int, metavar="N", help="decoder embedding dimension" ) parser.add_argument( "--decoder-ffn-embed-dim", @@ -401,8 +409,7 @@ def add_decoder_args(parser): help="apply layernorm before each decoder block", ) parser.add_argument( - "--layernorm-embedding", action="store_true", - help="add layernorm to embedding" + "--layernorm-embedding", action="store_true", help="add layernorm to embedding" ) parser.add_argument("--decoder-layerdrop", type=float, metavar="D") parser.add_argument("--decoder-learned-pos", action="store_true") @@ -454,14 +461,15 @@ def hub_models(cls): @classmethod def from_pretrained( - cls, - model_name_or_path, - checkpoint_file="model.pt", - data_name_or_path=".", - config_yaml="config.yaml", - **kwargs, + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + **kwargs, ): from fairseq import hub_utils + x = hub_utils.from_pretrained( model_name_or_path, checkpoint_file, @@ -502,8 +510,7 @@ def build_encoder(cls, args): if not args.adaptor_proj: # V0 arch state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) if state.get("cfg") is not None: - encoder_embed_dim = state["cfg"]._content["model"][ - "encoder_embed_dim"] + encoder_embed_dim = state["cfg"]._content["model"]["encoder_embed_dim"] elif state.get("args") is not None: encoder_embed_dim = state["args"].encoder_embed_dim else: diff --git a/fairseq/models/text_to_speech/fastspeech2.py b/fairseq/models/text_to_speech/fastspeech2.py index bfdb95615a..f6ccac5abf 100644 --- a/fairseq/models/text_to_speech/fastspeech2.py +++ b/fairseq/models/text_to_speech/fastspeech2.py @@ -8,23 +8,22 @@ import torch from torch import nn +from fairseq import utils +from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import ( FairseqEncoder, FairseqEncoderModel, register_model, register_model_architecture, ) +from fairseq.models.text_to_speech.hub_interface import TTSHubInterface +from fairseq.models.text_to_speech.tacotron2 import Postnet from fairseq.modules import ( - LayerNorm, - PositionalEmbedding, FairseqDropout, + LayerNorm, MultiheadAttention, + PositionalEmbedding, ) -from fairseq import utils -from fairseq.data.data_utils import lengths_to_padding_mask -from fairseq.models.text_to_speech.tacotron2 import Postnet -from fairseq.models.text_to_speech.hub_interface import TTSHubInterface - logger = logging.getLogger(__name__) @@ -293,7 +292,7 @@ def forward( durations=None, pitches=None, energies=None, - **kwargs + **kwargs, ): x = self.embed_tokens(src_tokens) @@ -344,16 +343,17 @@ def hub_models(cls): @classmethod def from_pretrained( - cls, - model_name_or_path, - checkpoint_file="model.pt", - data_name_or_path=".", - config_yaml="config.yaml", - vocoder: str = "griffin_lim", - fp16: bool = False, - **kwargs, + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + vocoder: str = "griffin_lim", + fp16: bool = False, + **kwargs, ): from fairseq import hub_utils + x = hub_utils.from_pretrained( model_name_or_path, checkpoint_file, diff --git a/fairseq/models/text_to_speech/tts_transformer.py b/fairseq/models/text_to_speech/tts_transformer.py index fef56af6d5..265d3998a2 100644 --- a/fairseq/models/text_to_speech/tts_transformer.py +++ b/fairseq/models/text_to_speech/tts_transformer.py @@ -9,6 +9,8 @@ import torch from torch import nn +from fairseq import utils +from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import ( FairseqEncoder, FairseqEncoderDecoderModel, @@ -16,12 +18,15 @@ register_model, register_model_architecture, ) -from fairseq.modules import TransformerEncoderLayer, TransformerDecoderLayer -from fairseq.models.text_to_speech.tacotron2 import Prenet, Postnet -from fairseq.modules import LayerNorm, PositionalEmbedding, FairseqDropout -from fairseq.data.data_utils import lengths_to_padding_mask -from fairseq import utils from fairseq.models.text_to_speech.hub_interface import TTSHubInterface +from fairseq.models.text_to_speech.tacotron2 import Postnet, Prenet +from fairseq.modules import ( + FairseqDropout, + LayerNorm, + PositionalEmbedding, + TransformerDecoderLayer, + TransformerEncoderLayer, +) logger = logging.getLogger(__name__) @@ -188,7 +193,7 @@ def extract_features( incremental_state=None, target_lengths=None, speaker=None, - **kwargs + **kwargs, ): alignment_layer = self.n_transformer_layers - 1 self_attn_padding_mask = lengths_to_padding_mask(target_lengths) @@ -261,7 +266,7 @@ def forward( incremental_state=None, target_lengths=None, speaker=None, - **kwargs + **kwargs, ): x, extra = self.extract_features( prev_output_tokens, @@ -269,7 +274,7 @@ def forward( incremental_state=incremental_state, target_lengths=target_lengths, speaker=speaker, - **kwargs + **kwargs, ) attn = extra["attn"] feat_out = self.feat_proj(x) @@ -326,22 +331,23 @@ def hub_models(cls): "tts_transformer-zh-cv7_css10", "tts_transformer-ar-cv7_css10", "tts_transformer-tr-cv7_css10", - "tts_transformer-vi-cv7" + "tts_transformer-vi-cv7", ] return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} @classmethod def from_pretrained( - cls, - model_name_or_path, - checkpoint_file="model.pt", - data_name_or_path=".", - config_yaml="config.yaml", - vocoder: str = "griffin_lim", - fp16: bool = False, - **kwargs, + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config_yaml="config.yaml", + vocoder: str = "griffin_lim", + fp16: bool = False, + **kwargs, ): from fairseq import hub_utils + x = hub_utils.from_pretrained( model_name_or_path, checkpoint_file, diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 191b99a740..26d589e5bb 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -3,23 +3,23 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from argparse import Namespace import contextlib import copy import math -import numpy as np import re +from argparse import Namespace +from dataclasses import dataclass, field +from typing import Any, Optional + +import numpy as np import torch import torch.nn as nn import torch.nn.functional as F -from dataclasses import dataclass, field -from omegaconf import MISSING, II, open_dict -from typing import Any, Optional +from omegaconf import II, MISSING, open_dict from fairseq import checkpoint_utils, tasks, utils from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import convert_namespace_to_omegaconf -from fairseq.tasks import FairseqTask from fairseq.models import ( BaseFairseqModel, FairseqEncoder, @@ -28,11 +28,8 @@ register_model, ) from fairseq.models.wav2vec.wav2vec2 import MASKING_DISTRIBUTION_CHOICES -from fairseq.modules import ( - LayerNorm, - PositionalEmbedding, - TransformerDecoderLayer, -) +from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerDecoderLayer +from fairseq.tasks import FairseqTask @dataclass @@ -160,11 +157,11 @@ class Wav2Vec2AsrConfig(FairseqDataclass): default=int(1e8), metadata={ "help": "minimum number of params for a layer to be wrapped with FSDP() when " - "training with --ddp-backend=fully_sharded. Smaller values will " - "improve memory efficiency, but may make torch.distributed " - "communication less efficient due to smaller input sizes. This option " - "is set to 0 (i.e., always wrap) when --checkpoint-activations or " - "--offload-activations are passed." + "training with --ddp-backend=fully_sharded. Smaller values will " + "improve memory efficiency, but may make torch.distributed " + "communication less efficient due to smaller input sizes. This option " + "is set to 0 (i.e., always wrap) when --checkpoint-activations or " + "--offload-activations are passed." }, ) diff --git a/fairseq/scoring/tokenizer.py b/fairseq/scoring/tokenizer.py index 2aee4a7784..b0cedd5099 100644 --- a/fairseq/scoring/tokenizer.py +++ b/fairseq/scoring/tokenizer.py @@ -28,8 +28,11 @@ class EvaluationTokenizer(object): SPACE = chr(32) SPACE_ESCAPE = chr(9601) - _ALL_TOKENIZER_TYPES = sb.BLEU.TOKENIZERS if SACREBLEU_V2_ABOVE \ + _ALL_TOKENIZER_TYPES = ( + sb.BLEU.TOKENIZERS + if SACREBLEU_V2_ABOVE else ["none", "13a", "intl", "zh", "ja-mecab"] + ) ALL_TOKENIZER_TYPES = ChoiceEnum(_ALL_TOKENIZER_TYPES) def __init__( @@ -40,8 +43,9 @@ def __init__( character_tokenization: bool = False, ): - assert tokenizer_type in self._ALL_TOKENIZER_TYPES, \ - f"{tokenizer_type}, {self._ALL_TOKENIZER_TYPES}" + assert ( + tokenizer_type in self._ALL_TOKENIZER_TYPES + ), f"{tokenizer_type}, {self._ALL_TOKENIZER_TYPES}" self.lowercase = lowercase self.punctuation_removal = punctuation_removal self.character_tokenization = character_tokenization From e69f1fa37fa2bb0099763e9e3649ae56c2850a58 Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Fri, 7 Jan 2022 12:44:15 -0800 Subject: [PATCH 539/774] speech integration tests for jointly trained models Summary: Add test for DualInputS2TTransformerModel at examples/speech_text_joint_to_text/models/s2t_dualinputtransformer.py Reviewed By: kahne Differential Revision: D33284188 fbshipit-source-id: c02b697fc7734425661e00bbb606852b5d94a587 --- tests/speech/__init__.py | 20 +++- .../speech/test_dualinput_s2t_transformer.py | 110 ++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 tests/speech/test_dualinput_s2t_transformer.py diff --git a/tests/speech/__init__.py b/tests/speech/__init__.py index 4e07140c16..345fe5708b 100644 --- a/tests/speech/__init__.py +++ b/tests/speech/__init__.py @@ -5,6 +5,7 @@ from argparse import Namespace import os +import re import unittest from pathlib import Path from typing import List, Dict, Optional @@ -32,7 +33,9 @@ def _set_up(self, dataset_id: str, s3_dir: str, data_filenames: List[str]): self.root = Path.home() / ".cache" / "fairseq" / dataset_id self.root.mkdir(exist_ok=True, parents=True) os.chdir(self.root) - self.base_url = f"{S3_BASE_URL}/{s3_dir}" + self.base_url = ( + s3_dir if re.search("^https:", s3_dir) else f"{S3_BASE_URL}/{s3_dir}" + ) for filename in data_filenames: self.download(self.base_url, self.root, filename) @@ -75,6 +78,21 @@ def set_up_sotasty_es_en(self): ], ) + def set_up_mustc_de_fbank(self): + self._set_up( + "mustc_de_fbank", + "https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de", + [ + "config.yaml", + "spm.model", + "dict.txt", + "src_dict.txt", + "tgt_dict.txt", + "tst-COMMON.tsv", + "tst-COMMON.zip", + ], + ) + def download_and_load_checkpoint( self, checkpoint_filename: str, arg_overrides: Optional[Dict[str, str]] = None ): diff --git a/tests/speech/test_dualinput_s2t_transformer.py b/tests/speech/test_dualinput_s2t_transformer.py new file mode 100644 index 0000000000..76675b9823 --- /dev/null +++ b/tests/speech/test_dualinput_s2t_transformer.py @@ -0,0 +1,110 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from argparse import Namespace +from collections import namedtuple +from pathlib import Path + +import torch +from tqdm import tqdm + +import fairseq +from fairseq import utils +from fairseq.checkpoint_utils import load_model_ensemble_and_task +from fairseq.scoring.bleu import SacrebleuScorer +from fairseq.tasks import import_tasks +from tests.speech import TestFairseqSpeech + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestDualInputS2TTransformer(TestFairseqSpeech): + def setUp(self): + self.set_up_mustc_de_fbank() + + def import_user_module(self): + user_dir = ( + Path(fairseq.__file__).parent.parent / "examples/speech_text_joint_to_text" + ) + Arg = namedtuple("Arg", ["user_dir"]) + arg = Arg(user_dir.__str__()) + utils.import_user_module(arg) + + @torch.no_grad() + def test_mustc_de_fbank_dualinput_s2t_transformer_checkpoint(self): + self.import_user_module() + checkpoint_filename = "checkpoint_ave_10.pt" + path = self.download(self.base_url, self.root, checkpoint_filename) + models, cfg, task = load_model_ensemble_and_task( + [path.as_posix()], + arg_overrides={ + "data": self.root.as_posix(), + "config_yaml": "config.yaml", + "load_pretrain_speech_encoder": "", + "load_pretrain_text_encoder_last": "", + "load_pretrain_decoder": "", + "beam": 10, + "nbest": 1, + "lenpen": 1.0, + "load_speech_only": True, + }, + ) + if self.use_cuda: + for model in models: + model.cuda() + generator = task.build_generator(models, cfg) + test_split = "tst-COMMON" + task.load_dataset(test_split) + batch_iterator = task.get_batch_iterator( + dataset=task.dataset(test_split), + max_tokens=250_000, + max_positions=(10_000, 1_024), + num_workers=1, + ).next_epoch_itr(shuffle=False) + + tokenizer = task.build_tokenizer(cfg.tokenizer) + bpe = task.build_bpe(cfg.bpe) + + def decode_fn(x): + if bpe is not None: + x = bpe.decode(x) + if tokenizer is not None: + x = tokenizer.decode(x) + return x + + scorer_args = { + "sacrebleu_tokenizer": "13a", + "sacrebleu_lowercase": False, + "sacrebleu_char_level": False, + } + scorer = SacrebleuScorer(Namespace(**scorer_args)) + progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) + for batch_idx, sample in progress: + sample = utils.move_to_cuda(sample) if self.use_cuda else sample + hypo = task.inference_step(generator, models, sample) + for i, sample_id in enumerate(sample["id"].tolist()): + tgt_tokens = ( + utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()) + .int() + .cpu() + ) + + tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") + hypo_str = task.tgt_dict.string( + hypo[i][0]["tokens"].int().cpu(), "sentencepiece" + ) + if batch_idx == 0 and i < 3: + print(f"T-{sample_id} {tgt_str}") + print(f"D-{sample_id} {hypo_str}") + scorer.add_string(tgt_str, hypo_str) + reference_bleu = 27.3 + result = scorer.result_string() + print(result + f" (reference: {reference_bleu})") + res_bleu = float(result.split()[2]) + self.assertAlmostEqual(res_bleu, reference_bleu, delta=0.3) + + +if __name__ == "__main__": + unittest.main() From 40ff55abbef3cb7345408a018b6cd25f3fcacb87 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Mon, 10 Jan 2022 16:16:36 -0800 Subject: [PATCH 540/774] conformer (#2859) Summary: **This PR** - Adds conformer layer based on https://arxiv.org/pdf/2005.08100.pdf. - Conformer implementation supports multihead attention based on 3 different positional embedding types - absolute positional embedding, relative positional encoding and rotational positional embedding. - Adds conformer encoder with conv1d subsampling, positional embedding followed by N conformer layers - Adds S2T_Conformer model based on the conformer encoder and transformer decoder. - Add conformer support in Wav2Vec2 - Add unit tests for core modules **Verfication** - Verified the set up on MUST-C En-De S2T, Covost2 Es-En S2T, Librispeech ASR to ensure the implementation is correct. - For S2T setups, the performance is either similar to the transformer based models or better. - Wav2vec2 pretraining and finetuning based on librispeech showed improvements over corresponding transformer baselines. - [WIP] Experiment log: https://docs.google.com/document/d/1QI-ROWVenUEXPJoHTaKD85Fq7T8ZXNc8bc54MzgwJjA/edit# **Next steps** - Add regression tests - Add README and open source checkpoints Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2859 Reviewed By: kahne Differential Revision: D33434092 Pulled By: sravyapopuri388 fbshipit-source-id: 62f22b917a332481370750e04a439e05832a2282 --- fairseq/models/speech_to_text/__init__.py | 1 + .../models/speech_to_text/s2t_conformer.py | 159 ++++++++++ fairseq/models/wav2vec/wav2vec2.py | 169 ++++++++-- fairseq/modules/__init__.py | 15 + fairseq/modules/conformer_layer.py | 296 ++++++++++++++++++ fairseq/modules/espnet_multihead_attention.py | 254 +++++++++++++++ fairseq/modules/positional_encoding.py | 129 ++++++++ .../modules/rotary_positional_embedding.py | 51 +++ fairseq/utils.py | 2 + tests/speech/__init__.py | 39 ++- tests/speech/test_s2t_conformer.py | 19 ++ tests/speech/test_s2t_transformer.py | 39 +-- tests/test_espnet_multihead_attention.py | 176 +++++++++++ tests/test_positional_encoding.py | 63 ++++ tests/test_rotary_positional_embedding.py | 64 ++++ 15 files changed, 1414 insertions(+), 62 deletions(-) create mode 100644 fairseq/models/speech_to_text/s2t_conformer.py create mode 100644 fairseq/modules/conformer_layer.py create mode 100644 fairseq/modules/espnet_multihead_attention.py create mode 100644 fairseq/modules/positional_encoding.py create mode 100644 fairseq/modules/rotary_positional_embedding.py create mode 100644 tests/speech/test_s2t_conformer.py create mode 100644 tests/test_espnet_multihead_attention.py create mode 100644 tests/test_positional_encoding.py create mode 100644 tests/test_rotary_positional_embedding.py diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index 1c5189c0f7..e5d2ede313 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -7,3 +7,4 @@ from .convtransformer import * # noqa from .s2t_transformer import * # noqa from .xm_transformer import * # noqa +from .s2t_conformer import * # noqa diff --git a/fairseq/models/speech_to_text/s2t_conformer.py b/fairseq/models/speech_to_text/s2t_conformer.py new file mode 100644 index 0000000000..fbac61d5a7 --- /dev/null +++ b/fairseq/models/speech_to_text/s2t_conformer.py @@ -0,0 +1,159 @@ +import logging +import torch +from fairseq.models.speech_to_text.s2t_transformer import ( + S2TTransformerEncoder, + S2TTransformerModel, + Conv1dSubsampler, + base_architecture as transformer_base_architecture, +) +from fairseq.data.data_utils import lengths_to_padding_mask +from fairseq.modules.conformer_layer import ConformerEncoderLayer +from fairseq.models import FairseqEncoder, register_model_architecture, register_model +from fairseq.modules import PositionalEmbedding, RelPositionalEncoding +import math + +logger = logging.getLogger(__name__) + + +class S2TConformerEncoder(FairseqEncoder): + """Conformer Encoder for speech translation based on https://arxiv.org/abs/2005.08100""" + + def __init__(self, args): + super().__init__(None) + self.embed_scale = math.sqrt(args.encoder_embed_dim) + if args.no_scale_embedding: + self.embed_scale = 1.0 + self.padding_idx = 1 + self.subsample = Conv1dSubsampler( + args.input_feat_per_channel * args.input_channels, + args.conv_channels, + args.encoder_embed_dim, + [int(k) for k in args.conv_kernel_sizes.split(",")], + ) + self.pos_enc_type = args.pos_enc_type + if self.pos_enc_type == "rel_pos": + self.embed_positions = RelPositionalEncoding( + args.max_source_positions, args.encoder_embed_dim + ) + elif self.pos_enc_type == "rope": + self.embed_positions = None + else: # Use absolute positional embedding + self.pos_enc_type = "abs" + self.embed_positions = PositionalEmbedding( + args.max_source_positions, args.encoder_embed_dim, self.padding_idx + ) + + self.linear = torch.nn.Linear(args.encoder_embed_dim, args.encoder_embed_dim) + self.dropout = torch.nn.Dropout(args.dropout) + self.conformer_layers = torch.nn.ModuleList( + [ + ConformerEncoderLayer( + embed_dim=args.encoder_embed_dim, + ffn_embed_dim=args.encoder_ffn_embed_dim, + attention_heads=args.encoder_attention_heads, + dropout=args.dropout, + depthwise_conv_kernel_size=args.depthwise_conv_kernel_size, + attn_type=args.attn_type, + pos_enc_type=self.pos_enc_type, + use_fp16=args.fp16, + ) + for _ in range(args.encoder_layers) + ] + ) + + def forward(self, src_tokens, src_lengths, return_all_hiddens=False): + """ + Args: + src_tokens: Input source tokens Tensor of shape B X T X C + src_lengths: Lengths Tensor corresponding to input source tokens + return_all_hiddens: If true will append the self attention states to the encoder states + Returns: + encoder_out: Tensor of shape B X T X C + encoder_padding_mask: Optional Tensor with mask + encoder_embedding: Optional Tensor. Always empty here + encoder_states: List of Optional Tensors wih self attention states + src_tokens: Optional Tensor. Always empty here + src_lengths: Optional Tensor. Always empty here + """ + x, input_lengths = self.subsample(src_tokens, src_lengths) # returns T X B X C + encoder_padding_mask = lengths_to_padding_mask(input_lengths) + x = self.embed_scale * x + if self.pos_enc_type == "rel_pos": + positions = self.embed_positions(x) + + elif self.pos_enc_type == "rope": + positions = None + + else: + positions = self.embed_positions(encoder_padding_mask).transpose(0, 1) + x += positions + positions = None + + x = self.linear(x) + x = self.dropout(x) + encoder_states = [] + + # x is T X B X C + for layer in self.conformer_layers: + x, _ = layer(x, encoder_padding_mask, positions) + if return_all_hiddens: + encoder_states.append(x) + + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [encoder_padding_mask] + if encoder_padding_mask.any() + else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + + def reorder_encoder_out(self, encoder_out, new_order): + """Required method for a FairseqEncoder. Calls the method from the parent class""" + return S2TTransformerEncoder.reorder_encoder_out(self, encoder_out, new_order) + + +@register_model("s2t_conformer") +class S2TConformerModel(S2TTransformerModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @staticmethod + def add_args(parser): + S2TTransformerModel.add_args(parser) + parser.add_argument("--input-feat-per-channel", default=80) + parser.add_argument("--depthwise-conv-kernel-size", default=31) + parser.add_argument("--input-channels", default=1) + parser.add_argument( + "--attn-type", + default=None, + help="If not specified uses fairseq MHA. Other valid option is espnet", + ) + parser.add_argument( + "--pos-enc-type", + default="abs", + help="Must be specified in addition to attn-type=espnet for rel_pos and rope", + ) + + @classmethod + def build_encoder(cls, args): + encoder = S2TConformerEncoder(args) + return encoder + + +@register_model_architecture("s2t_conformer", "s2t_conformer") +def base_architecture(args): + args.attn_type = getattr(args, "attn_type", None) + args.pos_enc_type = getattr(args, "pos_enc_type", "abs") + args.input_feat_per_channel = getattr(args, "input_feat_per_channel", 80) + args.input_channels = getattr(args, "input_channels", 1) + args.max_source_positions = getattr(args, "max_source_positions", 6000) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + args.encoder_layers = getattr(args, "encoder_layers", 16) + args.depthwise_conv_kernel_size = getattr(args, "depthwise_conv_kernel_size", 31) + transformer_base_architecture(args) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 299cc6fd23..8f41b60e0e 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -29,11 +29,13 @@ from fairseq.modules.transformer_sentence_encoder import init_bert_params from fairseq.utils import buffered_arange, index_put, is_xla_tensor from fairseq.distributed import fsdp_wrap - +from fairseq.modules.conformer_layer import ConformerWav2Vec2EncoderLayer +from fairseq.modules import RelPositionalEncoding from .utils import pad_to_multiple EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) MASKING_DISTRIBUTION_CHOICES = ChoiceEnum(["static", "uniform", "normal", "poisson"]) +LAYER_TYPE_CHOICES = ChoiceEnum(["transformer", "conformer"]) @dataclass @@ -61,7 +63,9 @@ class Wav2Vec2Config(FairseqDataclass): activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( default="gelu", metadata={"help": "activation function to use"} ) - + layer_type: LAYER_TYPE_CHOICES = field( + default="transformer", metadata={"help": "layer type in encoder"} + ) # dropouts dropout: float = field( default=0.1, metadata={"help": "dropout probability for the transformer"} @@ -231,7 +235,7 @@ class Wav2Vec2Config(FairseqDataclass): "can be tuple of 3 values (start, end, decay)" }, ) - + max_positions: int = field(default=100000, metadata={"help": "Max positions"}) checkpoint_activations: bool = field( default=False, metadata={"help": "recompute activations and save memory for extra compute"}, @@ -251,6 +255,23 @@ class Wav2Vec2Config(FairseqDataclass): }, ) + # Conformer + depthwise_conv_kernel_size: int = field( + default=31, + metadata={ + "help": "depthwise-conv-kernel-size for convolution in conformer layer" + }, + ) + attn_type: str = field( + default="", + metadata={"help": "if espnet use ESPNET MHA"}, + ) + pos_enc_type: str = field( + default="abs", + metadata={"help": "Positional encoding type to use in conformer"}, + ) + fp16: bool = field(default=False, metadata={"help": "If fp16 is being used"}) + @register_model("wav2vec2", dataclass=Wav2Vec2Config) class Wav2Vec2Model(BaseFairseqModel): @@ -347,8 +368,11 @@ def __init__(self, cfg: Wav2Vec2Config): self.mask_emb = nn.Parameter( torch.FloatTensor(cfg.encoder_embed_dim).uniform_() ) + encoder_cls = TransformerEncoder + if cfg.layer_type == "conformer" and cfg.pos_enc_type in ["rel_pos", "rope"]: + encoder_cls = ConformerEncoder - self.encoder = TransformerEncoder(cfg) + self.encoder = encoder_cls(cfg) self.layer_norm = LayerNorm(self.embed) self.target_glu = None @@ -845,6 +869,35 @@ def forward(self, x): class TransformerEncoder(nn.Module): + def build_encoder_layer(self, args): + if args.layer_type == "transformer": + layer = TransformerSentenceEncoderLayer( + embedding_dim=self.embedding_dim, + ffn_embedding_dim=args.encoder_ffn_embed_dim, + num_attention_heads=args.encoder_attention_heads, + dropout=self.dropout, + attention_dropout=args.attention_dropout, + activation_dropout=args.activation_dropout, + activation_fn=args.activation_fn, + layer_norm_first=args.layer_norm_first, + ) + elif args.layer_type == "conformer": + layer = ConformerWav2Vec2EncoderLayer( + embed_dim=self.embedding_dim, + ffn_embed_dim=args.encoder_ffn_embed_dim, + attention_heads=args.encoder_attention_heads, + dropout=args.dropout, + depthwise_conv_kernel_size=args.depthwise_conv_kernel_size, + activation_fn="swish", + attn_type=args.attn_type, + use_fp16=args.fp16, + pos_enc_type="abs", + ) + layer = fsdp_wrap(layer) + if args.checkpoint_activations: + layer = checkpoint_wrapper(layer) + return layer + def __init__(self, args): super().__init__() @@ -867,24 +920,9 @@ def __init__(self, args): self.pos_conv = nn.utils.weight_norm(self.pos_conv, name="weight", dim=2) self.pos_conv = nn.Sequential(self.pos_conv, SamePad(args.conv_pos), nn.GELU()) - layers = [] - for _ in range(args.encoder_layers): - layer = TransformerSentenceEncoderLayer( - embedding_dim=self.embedding_dim, - ffn_embedding_dim=args.encoder_ffn_embed_dim, - num_attention_heads=args.encoder_attention_heads, - dropout=self.dropout, - attention_dropout=args.attention_dropout, - activation_dropout=args.activation_dropout, - activation_fn=args.activation_fn, - layer_norm_first=args.layer_norm_first, - ) - if args.checkpoint_activations: - layer = fsdp_wrap(layer) - layer = checkpoint_wrapper(layer) - layers.append(layer) - self.layers = nn.ModuleList(layers) - + self.layers = nn.ModuleList( + [self.build_encoder_layer(args) for _ in range(args.encoder_layers)] + ) self.layer_norm_first = args.layer_norm_first self.layer_norm = LayerNorm(self.embedding_dim) self.layerdrop = args.encoder_layerdrop @@ -970,6 +1008,93 @@ def upgrade_state_dict_named(self, state_dict, name): return state_dict +class ConformerEncoder(TransformerEncoder): + def build_encoder_layer(self, args): + layer = ConformerWav2Vec2EncoderLayer( + embed_dim=self.embedding_dim, + ffn_embed_dim=args.encoder_ffn_embed_dim, + attention_heads=args.encoder_attention_heads, + dropout=args.dropout, + depthwise_conv_kernel_size=args.depthwise_conv_kernel_size, + activation_fn="swish", + attn_type=args.attn_type, + pos_enc_type=args.pos_enc_type, + use_fp16=args.fp16, # only used for rope + ) + layer = fsdp_wrap(layer) + if args.checkpoint_activations: + layer = checkpoint_wrapper(layer) + return layer + + def __init__(self, args): + super().__init__(args) + self.args = args + self.dropout = args.dropout + self.embedding_dim = args.encoder_embed_dim + self.pos_enc_type = args.pos_enc_type + max_source_positions = self.max_positions() + + if self.pos_enc_type == "rel_pos": + self.embed_positions = RelPositionalEncoding( + max_source_positions, self.embedding_dim + ) + elif self.pos_enc_type == "rope": + self.embed_positions = None + else: + raise Exception("Unsupported positional encoding type") + + self.layers = nn.ModuleList( + [self.build_encoder_layer(args) for _ in range(args.encoder_layers)] + ) + self.layer_norm_first = args.layer_norm_first + self.layer_norm = LayerNorm(self.embedding_dim) + self.layerdrop = args.encoder_layerdrop + + self.apply(init_bert_params) + + def extract_features(self, x, padding_mask=None, tgt_layer=None): + if padding_mask is not None: + x = index_put(x, padding_mask, 0) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + # B X T X C here + position_emb = None + if self.pos_enc_type == "rel_pos": + position_emb = self.embed_positions(x) + + if not self.layer_norm_first: + x = self.layer_norm(x) + + x = F.dropout(x, p=self.dropout, training=self.training) + + layer_results = [] + r = None + for i, layer in enumerate(self.layers): + dropout_probability = np.random.random() + if not self.training or (dropout_probability > self.layerdrop): + x, z = layer( + x, + self_attn_padding_mask=padding_mask, + need_weights=False, + position_emb=position_emb, + ) + if tgt_layer is not None: + layer_results.append((x, z)) + if i == tgt_layer: + r = x + break + + if r is not None: + x = r + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + return x, layer_results + + class TransformerSentenceEncoderLayer(nn.Module): """ Implements a Transformer Encoder Layer used in BERT/XLM style pre-trained diff --git a/fairseq/modules/__init__.py b/fairseq/modules/__init__.py index d7a030e2b5..9db8dea598 100644 --- a/fairseq/modules/__init__.py +++ b/fairseq/modules/__init__.py @@ -38,6 +38,15 @@ from .unfold import unfold1d from .transformer_layer import TransformerDecoderLayer, TransformerEncoderLayer from .vggblock import VGGBlock +from .espnet_multihead_attention import ( + ESPNETMultiHeadedAttention, + RelPositionMultiHeadedAttention, + RotaryPositionMultiHeadedAttention, +) +from .rotary_positional_embedding import RotaryPositionalEmbedding +from .positional_encoding import ( + RelPositionalEncoding, +) __all__ = [ "AdaptiveInput", @@ -79,4 +88,10 @@ "TransposeLast", "VGGBlock", "unfold1d", + "ESPNETMultiheadedAttention", + "PositionalEmbedding", + "RelPositionMultiHeadedAttention", + "RelPositionalEncoding", + "RotaryPositionalEmbedding", + "RotaryPositionMultiHeadedAttention", ] diff --git a/fairseq/modules/conformer_layer.py b/fairseq/modules/conformer_layer.py new file mode 100644 index 0000000000..f749eb4ff0 --- /dev/null +++ b/fairseq/modules/conformer_layer.py @@ -0,0 +1,296 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import torch +from typing import Optional +from fairseq.modules import ( + LayerNorm, + MultiheadAttention, + ESPNETMultiHeadedAttention, + RelPositionMultiHeadedAttention, + RotaryPositionMultiHeadedAttention, +) +from fairseq.utils import get_activation_fn + + +class ConvolutionModule(torch.nn.Module): + """Convolution block used in the conformer block""" + + def __init__( + self, + embed_dim, + channels, + depthwise_kernel_size, + dropout, + activation_fn="swish", + bias=False, + export=False, + ): + """ + Args: + embed_dim: Embedding dimension + channels: Number of channels in depthwise conv layers + depthwise_kernel_size: Depthwise conv layer kernel size + dropout: dropout value + activation_fn: Activation function to use after depthwise convolution kernel + bias: If bias should be added to conv layers + export: If layernorm should be exported to jit + """ + super(ConvolutionModule, self).__init__() + assert ( + depthwise_kernel_size - 1 + ) % 2 == 0, "kernel_size should be a odd number for 'SAME' padding" + self.layer_norm = LayerNorm(embed_dim, export=export) + self.pointwise_conv1 = torch.nn.Conv1d( + embed_dim, + 2 * channels, + kernel_size=1, + stride=1, + padding=0, + bias=bias, + ) + self.glu = torch.nn.GLU(dim=1) + self.depthwise_conv = torch.nn.Conv1d( + channels, + channels, + depthwise_kernel_size, + stride=1, + padding=(depthwise_kernel_size - 1) // 2, + groups=channels, + bias=bias, + ) + self.batch_norm = torch.nn.BatchNorm1d(channels) + self.activation = get_activation_fn(activation_fn)(channels) + self.pointwise_conv2 = torch.nn.Conv1d( + channels, + embed_dim, + kernel_size=1, + stride=1, + padding=0, + bias=bias, + ) + self.dropout = torch.nn.Dropout(dropout) + + def forward(self, x): + """ + Args: + x: Input of shape B X T X C + Returns: + Tensor of shape B X T X C + """ + x = self.layer_norm(x) + # exchange the temporal dimension and the feature dimension + x = x.transpose(1, 2) + + # GLU mechanism + x = self.pointwise_conv1(x) # (batch, 2*channel, dim) + x = self.glu(x) # (batch, channel, dim) + + # 1D Depthwise Conv + x = self.depthwise_conv(x) + x = self.batch_norm(x) + x = self.activation(x) + + x = self.pointwise_conv2(x) + x = self.dropout(x) + return x.transpose(1, 2) + + +class FeedForwardModule(torch.nn.Module): + """Positionwise feed forward layer used in conformer""" + + def __init__( + self, + input_feat, + hidden_units, + dropout1, + dropout2, + activation_fn="swish", + bias=True, + ): + """ + Args: + input_feat: Input feature dimension + hidden_units: Hidden unit dimension + dropout1: dropout value for layer1 + dropout2: dropout value for layer2 + activation_fn: Name of activation function + bias: If linear layers should have bias + """ + + super(FeedForwardModule, self).__init__() + self.layer_norm = LayerNorm(input_feat) + self.w_1 = torch.nn.Linear(input_feat, hidden_units, bias=bias) + self.w_2 = torch.nn.Linear(hidden_units, input_feat, bias=bias) + self.dropout1 = torch.nn.Dropout(dropout1) + self.dropout2 = torch.nn.Dropout(dropout2) + self.activation = get_activation_fn(activation_fn)(hidden_units) + + def forward(self, x): + """ + Args: + x: Input Tensor of shape T X B X C + Returns: + Tensor of shape T X B X C + """ + x = self.layer_norm(x) + x = self.w_1(x) + x = self.activation(x) + x = self.dropout1(x) + x = self.w_2(x) + return self.dropout2(x) + + +class ConformerEncoderLayer(torch.nn.Module): + """Conformer block based on https://arxiv.org/abs/2005.08100. We currently don't support relative positional encoding in MHA""" + + def __init__( + self, + embed_dim, + ffn_embed_dim, + attention_heads, + dropout, + use_fp16, + depthwise_conv_kernel_size=31, + activation_fn="swish", + attn_type=None, + pos_enc_type="abs", + ): + """ + Args: + embed_dim: Input embedding dimension + ffn_embed_dim: FFN layer dimension + attention_heads: Number of attention heads in MHA + dropout: dropout value + depthwise_conv_kernel_size: Size of kernel in depthwise conv layer in convolution module + activation_fn: Activation function name to use in convulation block and feed forward block + attn_type: MHA implementation from ESPNET vs fairseq + pos_enc_type: Positional encoding type - abs, rope, rel_pos + """ + self.pos_enc_type = pos_enc_type + super(ConformerEncoderLayer, self).__init__() + + self.ffn1 = FeedForwardModule( + embed_dim, + ffn_embed_dim, + dropout, + dropout, + ) + + self.self_attn_layer_norm = LayerNorm(embed_dim, export=False) + self.self_attn_dropout = torch.nn.Dropout(dropout) + if attn_type == "espnet": + if self.pos_enc_type == "rel_pos": + self.self_attn = RelPositionMultiHeadedAttention( + embed_dim, + attention_heads, + dropout=dropout, + ) + elif self.pos_enc_type == "rope": + self.self_attn = RotaryPositionMultiHeadedAttention( + embed_dim, attention_heads, dropout=dropout, precision=use_fp16 + ) + elif self.pos_enc_type == "abs": + self.self_attn = ESPNETMultiHeadedAttention( + embed_dim, + attention_heads, + dropout=dropout, + ) + else: + raise Exception(f"Unsupported attention type {self.pos_enc_type}") + else: + # Default to fairseq MHA + self.self_attn = MultiheadAttention( + embed_dim, + attention_heads, + dropout=dropout, + ) + + self.conv_module = ConvolutionModule( + embed_dim=embed_dim, + channels=embed_dim, + depthwise_kernel_size=depthwise_conv_kernel_size, + dropout=dropout, + activation_fn=activation_fn, + ) + + self.ffn2 = FeedForwardModule( + embed_dim, + ffn_embed_dim, + dropout, + dropout, + activation_fn=activation_fn, + ) + self.final_layer_norm = LayerNorm(embed_dim, export=False) + + def forward( + self, + x, + encoder_padding_mask: Optional[torch.Tensor], + position_emb: Optional[torch.Tensor] = None, + ): + """ + Args: + x: Tensor of shape T X B X C + encoder_padding_mask: Optional mask tensor + positions: + Returns: + Tensor of shape T X B X C + """ + residual = x + x = self.ffn1(x) + x = x * 0.5 + residual + residual = x + x = self.self_attn_layer_norm(x) + if self.pos_enc_type == "rel_pos": + x, attn = self.self_attn( + query=x, + key=x, + value=x, + key_padding_mask=encoder_padding_mask, + pos_emb=position_emb, + need_weights=False, + ) + else: + x, attn = self.self_attn( + query=x, + key=x, + value=x, + key_padding_mask=encoder_padding_mask, + need_weights=False, + ) + x = self.self_attn_dropout(x) + x = x + residual + + residual = x + # TBC to BTC + x = x.transpose(0, 1) + x = self.conv_module(x) + # BTC to TBC + x = x.transpose(0, 1) + x = residual + x + + residual = x + x = self.ffn2(x) + x = x * 0.5 + residual + + x = self.final_layer_norm(x) + return x, attn + + +class ConformerWav2Vec2EncoderLayer(ConformerEncoderLayer): + """Encoder layer for Wav2vec2 encoder""" + + def forward( + self, + x: torch.Tensor, + self_attn_mask: torch.Tensor = None, + self_attn_padding_mask: torch.Tensor = None, + need_weights: bool = False, + att_args=None, + position_emb=None, + ): + return super().forward(x, self_attn_padding_mask, position_emb) diff --git a/fairseq/modules/espnet_multihead_attention.py b/fairseq/modules/espnet_multihead_attention.py new file mode 100644 index 0000000000..d319a168f4 --- /dev/null +++ b/fairseq/modules/espnet_multihead_attention.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright 2019 Shigeki Karita +# Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + +"""Multi-Head Attention layer definition.""" + +import math +import torch +from torch import nn +from fairseq.modules.rotary_positional_embedding import ( + RotaryPositionalEmbedding, + apply_rotary_pos_emb, +) + + +class ESPNETMultiHeadedAttention(nn.Module): + """Multi-Head Attention layer. + Args: + n_head: The number of heads. + n_feat: The number of features. + dropout: Dropout rate. + """ + + def __init__(self, n_feat, n_head, dropout): + """Construct an MultiHeadedAttention object.""" + super(ESPNETMultiHeadedAttention, self).__init__() + assert n_feat % n_head == 0 + # We assume d_v always equals d_k + self.d_k = n_feat // n_head + self.h = n_head + self.linear_q = nn.Linear(n_feat, n_feat) + self.linear_k = nn.Linear(n_feat, n_feat) + self.linear_v = nn.Linear(n_feat, n_feat) + self.linear_out = nn.Linear(n_feat, n_feat) + self.attn = None + self.dropout = nn.Dropout(p=dropout) + + def forward_qkv(self, query, key, value, **kwargs): + """Transform query, key and value. + Args: + query: Query tensor B X T1 X C + key: Key tensor B X T2 X C + value: Value tensor B X T2 X C + Returns: + torch.Tensor: Transformed query tensor B X n_head X T1 X d_k + torch.Tensor: Transformed key tensor B X n_head X T2 X d_k + torch.Tensor: Transformed value tensor B X n_head X T2 X d_k + """ + n_batch = query.size(0) + q = self.linear_q(query).view(n_batch, -1, self.h, self.d_k) + k = self.linear_k(key).view(n_batch, -1, self.h, self.d_k) + v = self.linear_v(value).view(n_batch, -1, self.h, self.d_k) + q = q.transpose(1, 2) # (batch, head, time1, d_k) + k = k.transpose(1, 2) # (batch, head, time2, d_k) + v = v.transpose(1, 2) # (batch, head, time2, d_k) + return q, k, v + + def forward_attention(self, value, scores, mask): + """Compute attention context vector. + Args: + value: Transformed value B X n_head X T2 X d_k. + scores: Attention score B X n_head X T1 X T2 + mask: Mask T2 X B + Returns: + torch.Tensor: Transformed value B X T1 X d_model + weighted by the attention score B X T1 X T2 + """ + n_batch = value.size(0) + if mask is not None: + scores = scores.masked_fill( + mask.unsqueeze(1).unsqueeze(2).to(bool), + float("-inf"), # (batch, head, time1, time2) + ) + self.attn = torch.softmax(scores, dim=-1) # (batch, head, time1, time2) + + else: + self.attn = torch.softmax(scores, dim=-1) # (batch, head, time1, time2) + p_attn = self.dropout(self.attn) + x = torch.matmul(p_attn, value) # (batch, head, time1, d_k) + x = ( + x.transpose(1, 2).contiguous().view(n_batch, -1, self.h * self.d_k) + ) # (batch, time1, d_model) + + return self.linear_out(x) # (batch, time1, d_model) + + def forward(self, query, key, value, key_padding_mask=None, **kwargs): + """Compute scaled dot product attention. + Args: + query (torch.Tensor): Query tensor T X B X C + key (torch.Tensor): Key tensor T X B X C + value (torch.Tensor): Value tensor T X B X C + mask (torch.Tensor): Mask tensor T X B + Returns: + torch.Tensor: Output tensor T X B X D. + """ + query = query.transpose(0, 1) + key = key.transpose(0, 1) + value = value.transpose(0, 1) + + q, k, v = self.forward_qkv(query, key, value) + scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k) + scores = self.forward_attention(v, scores, key_padding_mask) + scores = scores.transpose(0, 1) + return scores, None + + +class RelPositionMultiHeadedAttention(ESPNETMultiHeadedAttention): + """Multi-Head Attention layer with relative position encoding. + Paper: https://arxiv.org/abs/1901.02860 + Args: + n_head: The number of heads. + n_feat: The number of features. + dropout: Dropout rate. + zero_triu: Whether to zero the upper triangular part of attention matrix. + """ + + def __init__(self, n_feat, n_head, dropout, zero_triu=False): + """Construct an RelPositionMultiHeadedAttention object.""" + super().__init__(n_feat, n_head, dropout) + self.zero_triu = zero_triu + # linear transformation for positional encoding + self.linear_pos = nn.Linear(n_feat, n_feat, bias=False) + # these two learnable bias are used in matrix c and matrix d + # as described in https://arxiv.org/abs/1901.02860 Section 3.3 + self.pos_bias_u = nn.Parameter(torch.Tensor(self.h, self.d_k)) + self.pos_bias_v = nn.Parameter(torch.Tensor(self.h, self.d_k)) + torch.nn.init.xavier_uniform_(self.pos_bias_u) + torch.nn.init.xavier_uniform_(self.pos_bias_v) + + def rel_shift(self, x): + """Compute relative positional encoding. + Args: + x: Input tensor B X n_head X T X 2T-1 + Returns: + torch.Tensor: Output tensor. + """ + zero_pad = torch.zeros((*x.size()[:3], 1), device=x.device, dtype=x.dtype) + x_padded = torch.cat([zero_pad, x], dim=-1) + + x_padded = x_padded.view(*x.size()[:2], x.size(3) + 1, x.size(2)) + x = x_padded[:, :, 1:].view_as(x)[ + :, :, :, : x.size(-1) // 2 + 1 + ] # only keep the positions from 0 to time2 + + if self.zero_triu: + ones = torch.ones((x.size(2), x.size(3)), device=x.device) + x = x * torch.tril(ones, x.size(3) - x.size(2))[None, None, :, :] + + return x + + def forward(self, query, key, value, pos_emb, key_padding_mask=None, **kwargs): + """Compute scaled dot product attention. + Args: + query: Query tensor T X B X C + key: Key tensor T X B X C + value: Value tensor T X B X C + pos_emb: Positional embedding tensor B X 2T-1 X C + key_padding_mask: Mask tensor T X B + Returns: + torch.Tensor: Output tensor T X B X C. + """ + query = query.transpose(0, 1) + key = key.transpose(0, 1) + value = value.transpose(0, 1) + pos_emb = pos_emb.transpose(0, 1) + q, k, v = self.forward_qkv(query, key, value) + q = q.transpose(1, 2) # (batch, time1, head, d_k) + n_batch_pos = pos_emb.size(0) + p = self.linear_pos(pos_emb).view(n_batch_pos, -1, self.h, self.d_k) + p = p.transpose(1, 2) # (batch, head, 2*time1-1, d_k) + + # (batch, head, time1, d_k) + q_with_bias_u = (q + self.pos_bias_u).transpose(1, 2) + # (batch, head, time1, d_k) + q_with_bias_v = (q + self.pos_bias_v).transpose(1, 2) + + # compute attention score + # first compute matrix a and matrix c + # as described in https://arxiv.org/abs/1901.02860 Section 3.3 + # (batch, head, time1, time2) + matrix_ac = torch.matmul(q_with_bias_u, k.transpose(-2, -1)) + + # compute matrix b and matrix d + # (batch, head, time1, 2*time1-1) + matrix_bd = torch.matmul(q_with_bias_v, p.transpose(-2, -1)) + matrix_bd = self.rel_shift(matrix_bd) + + scores = (matrix_ac + matrix_bd) / math.sqrt( + self.d_k + ) # (batch, head, time1, time2) + + scores = self.forward_attention(v, scores, key_padding_mask) + scores = scores.transpose(0, 1) + return scores, None + + +class RotaryPositionMultiHeadedAttention(ESPNETMultiHeadedAttention): + def __init__( + self, + n_feat, + n_head, + dropout, + precision, + rotary_emd_base=10000, + ): + """Construct an RotaryPositionMultiHeadedAttention object.""" + super().__init__(n_feat, n_head, dropout) + precision = torch.float + self.rotary_ndims = self.d_k # also try self.d_k//2 + if precision == "fp16": + precision = torch.half + + self.rotary_emb = RotaryPositionalEmbedding( + self.rotary_ndims, base=rotary_emd_base, precision=precision + ) + + def forward(self, query, key, value, key_padding_mask=None, **kwargs): + """Compute rotary position attention. + Args: + query: Query tensor T X B X C + key: Key tensor T X B X C + value: Value tensor T X B X C + key_padding_mask: Mask tensor T X B + Returns: + torch.Tensor: Output tensor T X B X D. + Notes: + Assumes self attn + """ + + T, B, C = value.size() + query = query.view(T, B, self.h, self.d_k) + key = key.view(T, B, self.h, self.d_k) + value = value.view(T, B, self.h, self.d_k) + cos, sin = self.rotary_emb(value, seq_len=T) + query, key = apply_rotary_pos_emb( + query, key, cos, sin, offset=0 + ) # offset is based on layer_past + + query = query.view(T, B, self.h * self.d_k) + key = key.view(T, B, self.h * self.d_k) + value = value.view(T, B, self.h * self.d_k) + + # TBD to BTD + query = query.transpose(0, 1) + key = key.transpose(0, 1) + value = value.transpose(0, 1) + + q, k, v = self.forward_qkv(query, key, value) + scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_k) + scores = self.forward_attention(v, scores, key_padding_mask) + scores = scores.transpose(0, 1) + return scores, None diff --git a/fairseq/modules/positional_encoding.py b/fairseq/modules/positional_encoding.py new file mode 100644 index 0000000000..67f6353539 --- /dev/null +++ b/fairseq/modules/positional_encoding.py @@ -0,0 +1,129 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch.nn as nn +import math +import torch + + +class PositionalEncoding(nn.Module): + """Positional encoding. + + Args: + d_model: Embedding dimension. + dropout_rate: Dropout rate. + max_len: Maximum input length. + reverse: Whether to reverse the input position. + """ + + def __init__(self, d_model, dropout_rate, max_len=5000, reverse=False): + """Construct an PositionalEncoding object.""" + super(PositionalEncoding, self).__init__() + self.d_model = d_model + self.reverse = reverse + self.xscale = math.sqrt(self.d_model) + self.dropout = nn.Dropout(p=dropout_rate) + self.pe = None + self.extend_pe(torch.tensor(0.0).expand(1, max_len)) + + def extend_pe(self, x): + """Reset the positional encodings.""" + if self.pe is not None: + if self.pe.size(1) >= x.size(1): + if self.pe.dtype != x.dtype or self.pe.device != x.device: + self.pe = self.pe.to(dtype=x.dtype, device=x.device) + return + pe = torch.zeros(x.size(1), self.d_model) + if self.reverse: + position = torch.arange( + x.size(1) - 1, -1, -1.0, dtype=torch.float32 + ).unsqueeze(1) + else: + position = torch.arange(0, x.size(1), dtype=torch.float32).unsqueeze(1) + div_term = torch.exp( + torch.arange(0, self.d_model, 2, dtype=torch.float32) + * -(math.log(10000.0) / self.d_model) + ) + pe[:, 0::2] = torch.sin(position * div_term) + pe[:, 1::2] = torch.cos(position * div_term) + pe = pe.unsqueeze(0) + self.pe = pe.to(device=x.device, dtype=x.dtype) + + def forward(self, x: torch.Tensor): + """Add positional encoding. + Args: + x (torch.Tensor): Input tensor B X T X C + Returns: + torch.Tensor: Encoded tensor B X T X C + """ + self.extend_pe(x) + x = x * self.xscale + self.pe[:, : x.size(1)] + return self.dropout(x) + + +class RelPositionalEncoding(nn.Module): + """Relative positional encoding module (new implementation). + + Args: + d_model: Embedding dimension. + dropout_rate: Dropout rate. + max_len: Maximum input length. + """ + + def __init__(self, max_len, d_model): + """Construct an PositionalEncoding object.""" + super(RelPositionalEncoding, self).__init__() + self.d_model = d_model + self.pe = None + self.extend_pe(torch.tensor(0.0).expand(1, max_len)) + + def extend_pe(self, x): + """Reset the positional encodings.""" + if self.pe is not None: + # self.pe contains both positive and negative parts + # the length of self.pe is 2 * input_len - 1 + if self.pe.size(1) >= x.size(1) * 2 - 1: + if self.pe.dtype != x.dtype or self.pe.device != x.device: + self.pe = self.pe.to(dtype=x.dtype, device=x.device) + return + # Suppose `i` means to the position of query vecotr and `j` means the + # position of key vector. We use position relative positions when keys + # are to the left (i>j) and negative relative positions otherwise (i<j). + pe_positive = torch.zeros(x.size(1), self.d_model) + pe_negative = torch.zeros(x.size(1), self.d_model) + position = torch.arange(0, x.size(1), dtype=torch.float32).unsqueeze(1) + div_term = torch.exp( + torch.arange(0, self.d_model, 2, dtype=torch.float32) + * -(math.log(10000.0) / self.d_model) + ) + pe_positive[:, 0::2] = torch.sin(position * div_term) + pe_positive[:, 1::2] = torch.cos(position * div_term) + pe_negative[:, 0::2] = torch.sin(-1 * position * div_term) + pe_negative[:, 1::2] = torch.cos(-1 * position * div_term) + + # Reserve the order of positive indices and concat both positive and + # negative indices. This is used to support the shifting trick + # as in https://arxiv.org/abs/1901.02860 + pe_positive = torch.flip(pe_positive, [0]).unsqueeze(0) + pe_negative = pe_negative[1:].unsqueeze(0) + pe = torch.cat([pe_positive, pe_negative], dim=1) + self.pe = pe.to(device=x.device, dtype=x.dtype) + + def forward(self, x: torch.Tensor): + """Add positional encoding. + Args: + x : Input tensor T X B X C. + Returns: + torch.Tensor: Encoded tensor T X B X C. + + """ + x = x.transpose(0, 1) # Change TBC to BTC + self.extend_pe(x) + pos_emb = self.pe[ + :, + self.pe.size(1) // 2 - x.size(1) + 1 : self.pe.size(1) // 2 + x.size(1), + ] + pos_emb = pos_emb.transpose(0, 1) # change to TBC + return pos_emb diff --git a/fairseq/modules/rotary_positional_embedding.py b/fairseq/modules/rotary_positional_embedding.py new file mode 100644 index 0000000000..84b88984ea --- /dev/null +++ b/fairseq/modules/rotary_positional_embedding.py @@ -0,0 +1,51 @@ +import torch + + +class RotaryPositionalEmbedding(torch.nn.Module): + def __init__(self, dim, base=10000, precision=torch.half): + """Rotary positional embedding + Reference : https://blog.eleuther.ai/rotary-embeddings/ + Paper: https://arxiv.org/pdf/2104.09864.pdf + Args: + dim: Dimension of embedding + base: Base value for exponential + precision: precision to use for numerical values + """ + super().__init__() + inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim)) + self.register_buffer("inv_freq", inv_freq) + self.seq_len_cached = None + self.cos_cached = None + self.sin_cached = None + self.precision = precision + + def forward(self, x, seq_len=None): + """ + Args: + x: Input x with T X B X C + seq_len: Sequence length of input x + """ + if seq_len != self.seq_len_cached: + self.seq_len_cached = seq_len + t = torch.arange(seq_len, device=x.device).type_as(self.inv_freq) + freqs = torch.einsum("i,j->ij", t, self.inv_freq) + emb = torch.cat((freqs, freqs), dim=-1).to(x.device) + self.cos_cached = emb.cos()[:, None, None, :] + self.sin_cached = emb.sin()[:, None, None, :] + return self.cos_cached, self.sin_cached + + +# rotary pos emb helpers: +def rotate_half(x): + x1, x2 = x[..., : x.shape[-1] // 2], x[..., x.shape[-1] // 2 :] + return torch.cat( + (-x2, x1), dim=x1.ndim - 1 + ) # dim=-1 triggers a bug in earlier torch versions + + +def apply_rotary_pos_emb(q, k, cos, sin, offset: int = 0): + cos, sin = ( + cos[offset : q.shape[0] + offset, ...], + sin[offset : q.shape[0] + offset, ...], + ) + return (q * cos) + (rotate_half(q) * sin), (k * cos) + (rotate_half(k) * sin) diff --git a/fairseq/utils.py b/fairseq/utils.py index 0f84896153..c7161fa6d3 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -564,6 +564,8 @@ def get_activation_fn(activation: str) -> Callable: return torch.tanh elif activation == "linear": return lambda x: x + elif activation == "swish": + return torch.nn.SiLU else: raise RuntimeError("--activation-fn {} not supported".format(activation)) diff --git a/tests/speech/__init__.py b/tests/speech/__init__.py index 345fe5708b..13b3ecf48c 100644 --- a/tests/speech/__init__.py +++ b/tests/speech/__init__.py @@ -8,13 +8,14 @@ import re import unittest from pathlib import Path +from tqdm import tqdm from typing import List, Dict, Optional - import torch - from fairseq.checkpoint_utils import load_model_ensemble_and_task from fairseq.scoring.wer import WerScorer from fairseq.scoring.bleu import SacrebleuScorer +from fairseq import utils + S3_BASE_URL = "https://dl.fbaipublicfiles.com/fairseq" @@ -138,3 +139,37 @@ def get_bleu_scorer(cls, tokenizer="13a", lowercase=False, char_level=False): "sacrebleu_char_level": char_level, } return SacrebleuScorer(Namespace(**scorer_args)) + + @torch.no_grad() + def librispeech_s2t_test_base(self, ckpt_name, reference_wer): + models, cfg, task, generator = self.download_and_load_checkpoint( + ckpt_name, + arg_overrides={"config_yaml": "cfg_librispeech.yaml"}, + ) + if not self.use_cuda: + return + + batch_iterator = self.get_batch_iterator( + task, "librispeech_test-other", 65_536, (4_096, 1_024) + ) + scorer = self.get_wer_scorer() + progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) + for batch_idx, sample in progress: + sample = utils.move_to_cuda(sample) if self.use_cuda else sample + hypo = task.inference_step(generator, models, sample) + for i, sample_id in enumerate(sample["id"].tolist()): + tgt_tokens = ( + utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()) + .int() + .cpu() + ) + tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") + hypo_str = task.tgt_dict.string( + hypo[i][0]["tokens"].int().cpu(), "sentencepiece" + ) + if batch_idx == 0 and i < 3: + print(f"T-{sample_id} {tgt_str}") + print(f"H-{sample_id} {hypo_str}") + scorer.add_string(tgt_str, hypo_str) + print(scorer.result_string() + f" (reference: {reference_wer})") + self.assertAlmostEqual(scorer.score(), reference_wer, delta=0.3) diff --git a/tests/speech/test_s2t_conformer.py b/tests/speech/test_s2t_conformer.py new file mode 100644 index 0000000000..2c7c57445a --- /dev/null +++ b/tests/speech/test_s2t_conformer.py @@ -0,0 +1,19 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from tests.speech import TestFairseqSpeech + + +class TestS2TConformer(TestFairseqSpeech): + def setUp(self): + self.set_up_librispeech() + + def test_librispeech_s2t_conformer_s_checkpoint(self): + self.librispeech_s2t_test_base("librispeech_conformer_rel_pos_s.pt", 12) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/speech/test_s2t_transformer.py b/tests/speech/test_s2t_transformer.py index 951660b323..edf9f64c9e 100644 --- a/tests/speech/test_s2t_transformer.py +++ b/tests/speech/test_s2t_transformer.py @@ -4,11 +4,6 @@ # LICENSE file in the root directory of this source tree. import unittest - -import torch -from tqdm import tqdm - -from fairseq import utils from tests.speech import TestFairseqSpeech @@ -16,40 +11,8 @@ class TestS2TTransformer(TestFairseqSpeech): def setUp(self): self.set_up_librispeech() - @torch.no_grad() def test_librispeech_s2t_transformer_s_checkpoint(self): - models, cfg, task, generator = self.download_and_load_checkpoint( - "librispeech_transformer_s.pt", - arg_overrides={"config_yaml": "cfg_librispeech.yaml"}, - ) - if not self.use_cuda: - return - - batch_iterator = self.get_batch_iterator( - task, "librispeech_test-other", 65_536, (4_096, 1_024) - ) - scorer = self.get_wer_scorer() - progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) - for batch_idx, sample in progress: - sample = utils.move_to_cuda(sample) if self.use_cuda else sample - hypo = task.inference_step(generator, models, sample) - for i, sample_id in enumerate(sample["id"].tolist()): - tgt_tokens = ( - utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()) - .int() - .cpu() - ) - tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") - hypo_str = task.tgt_dict.string( - hypo[i][0]["tokens"].int().cpu(), "sentencepiece" - ) - if batch_idx == 0 and i < 3: - print(f"T-{sample_id} {tgt_str}") - print(f"H-{sample_id} {hypo_str}") - scorer.add_string(tgt_str, hypo_str) - reference_wer = 9.0 - print(scorer.result_string() + f" (reference: {reference_wer})") - self.assertAlmostEqual(scorer.score(), reference_wer, delta=0.3) + self.librispeech_s2t_test_base("librispeech_transformer_s.pt", 9) if __name__ == "__main__": diff --git a/tests/test_espnet_multihead_attention.py b/tests/test_espnet_multihead_attention.py new file mode 100644 index 0000000000..ee71dd0e98 --- /dev/null +++ b/tests/test_espnet_multihead_attention.py @@ -0,0 +1,176 @@ +import torch +import numpy as np +import unittest +from fairseq.modules import ( + ESPNETMultiHeadedAttention, + RelPositionMultiHeadedAttention, + RotaryPositionMultiHeadedAttention, +) + +torch.use_deterministic_algorithms(True) + + +class TestESPNETMultiHeadedAttention(unittest.TestCase): + def setUp(self) -> None: + self.T = 3 + self.B = 1 + self.C = 2 + torch.manual_seed(0) + self.sample = torch.randn(self.T, self.B, self.C) # TBC + self.sample_scores = torch.randn(self.B, 1, self.T, self.T) + self.MHA = ESPNETMultiHeadedAttention(self.C, 1, dropout=0) + + def test_forward(self): + expected_scores = torch.tensor( + [[[0.1713, -0.3776]], [[0.2263, -0.4486]], [[0.2243, -0.4538]]] + ) + scores, _ = self.MHA(self.sample, self.sample, self.sample) + self.assertTrue( + np.allclose( + expected_scores.cpu().detach().numpy(), + scores.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + def test_forward_qkv(self): + expected_query = torch.tensor( + [[[[-1.0235, 0.0409], [0.4008, 1.3077], [0.5396, 2.0698]]]] + ) + expected_key = torch.tensor( + [[[[0.5053, -0.4965], [-0.3730, -0.9473], [-0.7019, -0.1935]]]] + ) + expected_val = torch.tensor( + [[[[-0.9940, 0.5403], [0.5924, -0.7619], [0.7504, -1.0892]]]] + ) + sample_t = self.sample.transpose(0, 1) + query, key, val = self.MHA.forward_qkv(sample_t, sample_t, sample_t) + self.assertTrue( + np.allclose( + expected_query.cpu().detach().numpy(), + query.cpu().detach().numpy(), + atol=1e-4, + ) + ) + self.assertTrue( + np.allclose( + expected_key.cpu().detach().numpy(), + key.cpu().detach().numpy(), + atol=1e-4, + ) + ) + self.assertTrue( + np.allclose( + expected_val.cpu().detach().numpy(), + val.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + def test_forward_attention(self): + expected_scores = torch.tensor( + [[[0.1627, -0.6249], [-0.2547, -0.6487], [-0.0711, -0.8545]]] + ) + scores = self.MHA.forward_attention( + self.sample.transpose(0, 1).view(self.B, 1, self.T, self.C), + self.sample_scores, + mask=None, + ) + self.assertTrue( + np.allclose( + expected_scores.cpu().detach().numpy(), + scores.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + +class TestRelPositionMultiHeadedAttention(unittest.TestCase): + def setUp(self) -> None: + self.T = 3 + self.B = 1 + self.C = 2 + torch.manual_seed(0) + self.sample = torch.randn(self.T, self.B, self.C) # TBC + self.sample_x = torch.randn(self.B, 1, self.T, self.T * 2 - 1) + self.sample_pos = torch.randn(self.B, self.T * 2 - 1, self.C) + self.MHA = RelPositionMultiHeadedAttention(self.C, 1, dropout=0) + + def test_rel_shift(self): + expected_x = torch.tensor( + [ + [ + [ + [-0.7193, -0.4033, -0.5966], + [-0.8567, 1.1006, -1.0712], + [-0.5663, 0.3731, -0.8920], + ] + ] + ] + ) + x = self.MHA.rel_shift(self.sample_x) + self.assertTrue( + np.allclose( + expected_x.cpu().detach().numpy(), + x.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + def test_forward(self): + expected_scores = torch.tensor( + [ + [[-0.9609, -0.5020]], + [[-0.9308, -0.4890]], + [[-0.9473, -0.4948]], + [[-0.9609, -0.5020]], + [[-0.9308, -0.4890]], + [[-0.9473, -0.4948]], + [[-0.9609, -0.5020]], + [[-0.9308, -0.4890]], + [[-0.9473, -0.4948]], + [[-0.9609, -0.5020]], + [[-0.9308, -0.4890]], + [[-0.9473, -0.4948]], + [[-0.9609, -0.5020]], + [[-0.9308, -0.4890]], + [[-0.9473, -0.4948]], + ] + ) + scores, _ = self.MHA(self.sample, self.sample, self.sample, self.sample_pos) + self.assertTrue( + np.allclose( + expected_scores.cpu().detach().numpy(), + scores.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + +class TestRotaryPositionMultiHeadedAttention(unittest.TestCase): + def setUp(self) -> None: + self.T = 3 + self.B = 1 + self.C = 2 + torch.manual_seed(0) + self.sample = torch.randn(self.T, self.B, self.C) # TBC + self.MHA = RotaryPositionMultiHeadedAttention( + self.C, 1, dropout=0, precision=None + ) + + def test_forward(self): + expected_scores = torch.tensor( + [[[-0.3220, -0.4726]], [[-1.2813, -0.0979]], [[-0.3138, -0.4758]]] + ) + scores, _ = self.MHA(self.sample, self.sample, self.sample) + self.assertTrue( + np.allclose( + expected_scores.cpu().detach().numpy(), + scores.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_positional_encoding.py b/tests/test_positional_encoding.py new file mode 100644 index 0000000000..4e38c4397d --- /dev/null +++ b/tests/test_positional_encoding.py @@ -0,0 +1,63 @@ +import unittest + +import torch +from fairseq.modules import RelPositionalEncoding +import numpy as np + + +class TestRelPositionalEncoding(unittest.TestCase): + def setUp(self) -> None: + self.T = 3 + self.B = 1 + self.C = 2 + torch.manual_seed(0) + self.sample = torch.randn(self.T, self.B, self.C) # TBC + self.rel_pos_enc = RelPositionalEncoding(max_len=4, d_model=self.C) + + def test_extend_pe(self): + inp = self.sample.transpose(0, 1) + self.rel_pos_enc.extend_pe(inp) + expected_pe = torch.tensor( + [ + [ + [0.1411, -0.9900], + [0.9093, -0.4161], + [0.8415, 0.5403], + [0.0000, 1.0000], + [-0.8415, 0.5403], + [-0.9093, -0.4161], + [-0.1411, -0.9900], + ] + ] + ) + + self.assertTrue( + np.allclose( + expected_pe.cpu().detach().numpy(), + self.rel_pos_enc.pe.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + def test_forward(self): + pos_enc = self.rel_pos_enc(self.sample) + expected_pos_enc = torch.tensor( + [ + [[0.9093, -0.4161]], + [[0.8415, 0.5403]], + [[0.0000, 1.0000]], + [[-0.8415, 0.5403]], + [[-0.9093, -0.4161]], + ] + ) + self.assertTrue( + np.allclose( + pos_enc.cpu().detach().numpy(), + expected_pos_enc.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_rotary_positional_embedding.py b/tests/test_rotary_positional_embedding.py new file mode 100644 index 0000000000..ea9f0bee12 --- /dev/null +++ b/tests/test_rotary_positional_embedding.py @@ -0,0 +1,64 @@ +import torch +import numpy as np +import unittest +from fairseq.modules.rotary_positional_embedding import apply_rotary_pos_emb +from fairseq.modules import RotaryPositionalEmbedding + + +class TestRotaryPositionalEmbedding(unittest.TestCase): + def setUp(self) -> None: + self.T = 3 + self.B = 1 + self.C = 2 + torch.manual_seed(0) + self.sample = torch.randn(self.T, self.B, self.C) # TBC + self.rope_pos_emd = RotaryPositionalEmbedding(dim=self.C) + + def test_forward(self): + expected_cos = torch.tensor( + [[[[1.0000, 1.0000]]], [[[0.5403, 0.5403]]], [[[-0.4161, -0.4161]]]] + ) + expected_sin = torch.tensor( + [[[[0.0000, 0.0000]]], [[[0.8415, 0.8415]]], [[[0.9093, 0.9093]]]] + ) + cos, sin = self.rope_pos_emd(self.sample, self.T) + self.assertTrue( + np.allclose( + expected_cos.cpu().detach().numpy(), + cos.cpu().detach().numpy(), + atol=1e-4, + ) + ) + self.assertTrue( + np.allclose( + expected_sin.cpu().detach().numpy(), + sin.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + def test_apply_rotary_pos_emb(self): + cos, sin = self.rope_pos_emd(self.sample, self.T) + query = self.sample.view(self.T, self.B, 1, self.C) + expected_query = torch.tensor( + [[[[1.5410, -0.2934]]], [[[-1.6555, -1.5263]]], [[[1.7231, -0.4041]]]] + ) + new_query, new_key = apply_rotary_pos_emb(query, query, cos, sin) + self.assertTrue( + np.allclose( + expected_query.cpu().detach().numpy(), + new_query.cpu().detach().numpy(), + atol=1e-4, + ) + ) + self.assertTrue( + np.allclose( + expected_query.cpu().detach().numpy(), + new_key.cpu().detach().numpy(), + atol=1e-4, + ) + ) + + +if __name__ == "__main__": + unittest.main() From da4851859b96901daca4e3807fe5227dbec240b5 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Tue, 11 Jan 2022 09:28:29 -0800 Subject: [PATCH 541/774] Benchmarking OSS (#2852) Summary: - The goal of this framework is to support benchmarking various speech to speech translation(S2ST) models in terms of runtime, max-memory consumption and total number of floating point operations(FLOPS). - It is a generic framework and can be easily extended to support any fairseq models. To accurately benchmark the performance, core inference modules are re-implemented based on fairseq_cli/generate.py (core.py/Processing) and examples/speech_to_text/generate_waveform.py(core.py/SpeechGeneration. - To ensure that the end to end models and cascaded models are compared fairly, for cascaded models we only consider the performance metrics for model inference at all stages ignoring any intermediate data and io processing consumption. - We run all the benchmarking runs on CPU as it is generally used in production environment and also due to lack of good benchmarking library support for GPUs. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2852 Reviewed By: an918tw Differential Revision: D33398060 Pulled By: sravyapopuri388 fbshipit-source-id: cffa19820deaa4ee7f629845944cbb6223498f4d --- .../speech_to_speech/benchmarking/README.md | 31 ++ .../benchmarking/configs/2StageS2ST.yaml | 19 + .../benchmarking/configs/3StageS2ST.yaml | 28 + .../benchmarking/configs/DirectS2U.yaml | 22 + .../benchmarking/configs/S2T.yaml | 13 + .../speech_to_speech/benchmarking/core.py | 487 ++++++++++++++++++ .../benchmarking/data_utils.py | 264 ++++++++++ .../benchmarking/get_metrics.py | 162 ++++++ fairseq/tasks/speech_to_speech.py | 2 +- 9 files changed, 1027 insertions(+), 1 deletion(-) create mode 100644 examples/speech_to_speech/benchmarking/README.md create mode 100644 examples/speech_to_speech/benchmarking/configs/2StageS2ST.yaml create mode 100644 examples/speech_to_speech/benchmarking/configs/3StageS2ST.yaml create mode 100644 examples/speech_to_speech/benchmarking/configs/DirectS2U.yaml create mode 100644 examples/speech_to_speech/benchmarking/configs/S2T.yaml create mode 100644 examples/speech_to_speech/benchmarking/core.py create mode 100644 examples/speech_to_speech/benchmarking/data_utils.py create mode 100644 examples/speech_to_speech/benchmarking/get_metrics.py diff --git a/examples/speech_to_speech/benchmarking/README.md b/examples/speech_to_speech/benchmarking/README.md new file mode 100644 index 0000000000..c62fe12963 --- /dev/null +++ b/examples/speech_to_speech/benchmarking/README.md @@ -0,0 +1,31 @@ +# Benchmarking + +## Overview + +The goal of this framework is to support benchmarking various speech to speech translation(S2ST) models in terms of runtime, max-memory consumption and total number of floating point operations(FLOPS). It is a generic framework and can be easily extended to support any fairseq models. To accurately benchmark the performance, core inference modules are re-implemented based on fairseq_cli/generate.py (core.py/Processing) and examples/speech_to_text/generate_waveform.py(core.py/SpeechGeneration. To ensure that the end to end models and cascaded models are compared fairly, for cascaded models we only consider the performance metrics for model inference at all stages ignoring any intermediate data and io processing consumption. We run all the benchmarking runs on CPU as it is generally used in production environment and also due to lack of good benchmarking library support for GPUs. + +1. Runtime: Average time in seconds to run model inference on an example from a given dataset. We use [timeit](https://docs.python.org/3/library/timeit.html) library to measure the runtime. +2. Max memory: Maximum memory in MiB averaged over by running the model inference on all examples from the given dataset. We use [memory_profiler](https://pypi.org/project/memory-profiler/) library to gather memory footprints for a code snippet and find the maximum to get the max memory used by the code. For cascaded models, we find the max of all stages to get the overall max_memory footprint. +3. FLOPS: We compute the average number of floating point operations needed to run model inference for an example from the given dataset. We use [PAPI library](http://www.bnikolic.co.uk/blog/python/flops/2019/10/01/pytorch-count-flops.html) to benchmark the number of flops. + +## CLI Commands + +```{python} +CUBLAS_WORKSPACE_CONFIG=:4096:8 python examples/speech_to_speech/benchmarking/get_metrics.py ‘’ --config $config +``` + + +## Note: + +1. The npy dataset is a list of samples saved as a .npy file. Each sample is a dictionary with id, net_input. +2. The raw dataset is a list of raw audio paths similar to wav2vec2 input tsv file + +```{python} +sample: { + "id": xx, + "net_input": { + "src_tokens": torch.tensor([]), + "src_lengths": torch.tensor([]) + } +} +``` diff --git a/examples/speech_to_speech/benchmarking/configs/2StageS2ST.yaml b/examples/speech_to_speech/benchmarking/configs/2StageS2ST.yaml new file mode 100644 index 0000000000..11deb42e7d --- /dev/null +++ b/examples/speech_to_speech/benchmarking/configs/2StageS2ST.yaml @@ -0,0 +1,19 @@ +general: + dataset_path: $npy_dataset + cpu: True + model_type: 2StageS2ST + dataset_size: 1 + +stage1: + data: $data_bin_stage1 + task: speech_to_text + path: $checkpoint_stage1 + config_yaml: config.yaml + max_len_a: 2 + max_len_b: 500 + +stage2: + data: $data_bin_stage2 + task: text_to_speech + path: $checkpoint_stage2 + config_yaml: config.yaml diff --git a/examples/speech_to_speech/benchmarking/configs/3StageS2ST.yaml b/examples/speech_to_speech/benchmarking/configs/3StageS2ST.yaml new file mode 100644 index 0000000000..9638136150 --- /dev/null +++ b/examples/speech_to_speech/benchmarking/configs/3StageS2ST.yaml @@ -0,0 +1,28 @@ +general: + dataset_path: $npy_dataset + cpu: True + model_type: 3StageS2ST + max_len_a: 2 + max_len_b: 500 + dataset_size: 1 + +stage1: + data: $data_bin_stage1 + task: speech_to_text + path: $checkpoint_stage1 + config_yaml: config.yaml + max_len_a: 2 + max_len_b: 500 + +stage2: + data: $data_bin_stage2 + task: translation + path: $checkpoint_stage2 + config_yaml: config.yaml + + +stage2: + data: $data_bin_stage3 + task: text_to_speech + path: $checkpoint_stage3 + config_yaml: config.yaml diff --git a/examples/speech_to_speech/benchmarking/configs/DirectS2U.yaml b/examples/speech_to_speech/benchmarking/configs/DirectS2U.yaml new file mode 100644 index 0000000000..96264cec68 --- /dev/null +++ b/examples/speech_to_speech/benchmarking/configs/DirectS2U.yaml @@ -0,0 +1,22 @@ +general: + dataset_path: $npy_dataset_path + cpu: True + model_type: S2UT + dataset_size: 5 + dump_speech_waveforms_dir: $dump_waveforms_dir_path + +stage1: + data: $data_bin + task: speech_to_speech + path: $checkpoint + config_yaml: config.yaml + max_len_b: 100000 + beam: 10 + target_is_code: True + max_target_positions: 3000 + target_code_size: 100 + +stage2: + vocoder: $vocoder_path + vocoder_cfg: $vocoder_cfg_json + dur_prediction: True diff --git a/examples/speech_to_speech/benchmarking/configs/S2T.yaml b/examples/speech_to_speech/benchmarking/configs/S2T.yaml new file mode 100644 index 0000000000..3a106a0441 --- /dev/null +++ b/examples/speech_to_speech/benchmarking/configs/S2T.yaml @@ -0,0 +1,13 @@ +general: + dataset_path: $npy_dataset + cpu: True + model_type: S2T + dataset_size: 1 + +stage1: + data: $data_bin + task: speech_to_text + path: $checkpoint + config_yaml: config.yaml + max_len_a: 2 + max_len_b: 500 diff --git a/examples/speech_to_speech/benchmarking/core.py b/examples/speech_to_speech/benchmarking/core.py new file mode 100644 index 0000000000..da22a34ece --- /dev/null +++ b/examples/speech_to_speech/benchmarking/core.py @@ -0,0 +1,487 @@ +import timeit +import logging +import torch +from pypapi import events, papi_high as high +from memory_profiler import memory_usage +from torch import nn +from argparse import Namespace +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.data import data_utils as fairseq_data_utils +from fairseq import checkpoint_utils, tasks, utils +from fairseq.models.text_to_speech.vocoder import CodeHiFiGANVocoder +from examples.hubert.simple_kmeans.dump_hubert_feature import HubertFeatureReader +from examples.hubert.simple_kmeans.dump_km_label import ApplyKmeans +from fairseq_cli.generate import get_symbols_to_strip_from_output +import soundfile as sf +import ast +import json + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +torch.manual_seed(1) +torch.set_deterministic(True) + + +class BenchmarkingBase(nn.Module): + def __init__(self): + nn.Module.__init__(self) + self.s2x_task = None + + def warm_up(self, sample, repeat): + """Warm up the model""" + for _i in range(repeat): + self.forward(sample) + logger.info(f"Model warmed up by running inference {repeat} times") + + def benchmark_run_time(self, dataset, repeat): + """Benchmark average runtime for the model by calling benchmark_run_time_single_sample function""" + logger.info("Starting run time benchmarking") + time_elapsed = 0 + for i, sample in enumerate(dataset): + time_elapsed += self.benchmark_run_time_single_sample(sample, repeat=repeat) + if i % 100 == 0: + logger.info(f"Benchmarked run time for {i}/{len(dataset)} samples") + total_time_elapsed = time_elapsed / len(dataset) + return total_time_elapsed + + def benchmark_run_time_single_sample(self, sample, repeat): + """Benchmark average runtime for a single sample using timeit library. Units are seconds""" + timer = timeit.Timer(lambda: self.forward(sample)) + time_elapsed = timer.timeit(repeat) + return time_elapsed / repeat + + def count_flops( + self, + dataset, + repeat, + ): + """Use PYPAPI library to count average flops for model inference. + Note: It only works if the model is being run on cpu""" + logger.info("Starting flop counter") + high.start_counters([events.PAPI_DP_OPS]) + for i, sample in enumerate(dataset): + for _r in range(repeat): + self.forward(sample) + if i % 100 == 0: + logger.info(f"Counted flops for {i}/{len(dataset)} samples") + flops = high.stop_counters() + flops = round(flops[0] / (repeat * len(dataset))) + return flops + + def max_memory(self, dataset, repeat): + """Compute average max memory consumed by model inference. Units are MiB""" + logger.info("Starting memory benchmarking") + total_memory = 0 + for i, sample in enumerate(dataset): + for _r in range(repeat): + total_memory += max(memory_usage((self.forward, (sample,), {}))) + if i % 100 == 0: + logger.info(f"Benchmarked memory for {i}/{len(dataset)} samples") + total_memory = total_memory / (repeat * len(dataset)) + return total_memory + + def gather_all_metrics(self, dataset, repeat): + run_time = self.benchmark_run_time(dataset, repeat) + max_memory = self.max_memory(dataset, repeat) + flops = self.count_flops(dataset, repeat) + + return run_time, max_memory, flops + + def dump_final_speech_output( + self, dataset, output_dir, resample_fn, sample_rate, prefix=None + ): + + for i, sample in enumerate(dataset): + hypo = self.forward(sample)[0] + + def to_np(x): + return x.detach().cpu().numpy() + + try: + wave_preds = to_np(resample_fn(hypo["waveform"])) + sf.write( + f"{output_dir}/{prefix}_{i}_pred.wav", + wave_preds, + sample_rate, + ) + except Exception as e: + raise Exception( + f" Encountered {e} - Invalid waveform. Make sure the model outputs a waveform" + ) + + +class Processing(BenchmarkingBase): + """Class similar to fairseq_cli/generate.py. Supports ASR, MT and ST model inference""" + + def __init__(self, args): + super().__init__() + self.use_cuda = not getattr(args, "cpu", False) + self.setUp(args) + self.training = False + self.s2x_task = self.task + + def setUp(self, cfg): + if isinstance(cfg, Namespace): + cfg = convert_namespace_to_omegaconf(cfg) + + self.task = tasks.setup_task(cfg.task) + self.tgt_dict = self.task.target_dictionary + + # Load ensemble + logger.info("loading model(s) from {}".format(cfg.common_eval.path)) + models, _ = checkpoint_utils.load_model_ensemble( + utils.split_paths(cfg.common_eval.path), + arg_overrides={}, + task=self.task, + suffix=cfg.checkpoint.checkpoint_suffix, + strict=False, + num_shards=cfg.checkpoint.checkpoint_shard_count, + ) + if len(models) > 1: + raise Exception("Currently loading multiple models is not supported") + self.model = models[0] + + # Optimize model for generation + if cfg.common.fp16: + self.model.half() + if self.use_cuda: + self.model.cuda() + self.model.prepare_for_inference_(cfg) + + self.generator = self.task.build_generator( + [self.model], + cfg.generation, + extra_gen_cls_kwargs={}, + ) + # Handle tokenization and BPE + self.tokenizer = self.task.build_tokenizer(cfg.tokenizer) + self.bpe = self.task.build_bpe(cfg.bpe) + self.remove_bpe = cfg.common_eval.post_process + + def encode_source(self, src): + """Method to generate source tokens from a string""" + if self.tokenizer is not None: + src = self.tokenizer.encode(src) + if self.bpe is not None: + src = self.bpe.encode(src) + src_tokens = self.task.source_dictionary.encode_line(src).long() + src_lens = src_tokens.size(0) + return { + "net_input": { + "src_tokens": src_tokens.view(1, src_lens), + "src_lengths": torch.tensor([src_lens]), + } + } + + def decode_target(self, hypos): + """Method to decode target string from tokens""" + hypo_str = self.tgt_dict.string( + hypos[0][0]["tokens"].int().cpu(), + self.remove_bpe, + get_symbols_to_strip_from_output(self.generator), + ) + if self.bpe is not None: + hypo_str = self.bpe.decode(hypo_str) + if self.tokenizer is not None: + hypo_str = self.tokenizer.decode(hypo_str) + return hypo_str + + def forward(self, sample): + hypos = self.task.inference_step( + self.generator, + [self.model], + sample, + prefix_tokens=None, + constraints=None, + ) + return hypos + + +class GenerateWaveformFromCode(BenchmarkingBase): + """Class to support waveform generation from code. Currently, vocoder only supports single speaker""" + + def __init__(self, args): + super().__init__() + with open(args.vocoder_cfg) as f: + vocoder_cfg = json.load(f) + self.dur_prediction = args.dur_prediction + self.vocoder = CodeHiFiGANVocoder(args.vocoder, vocoder_cfg) + + def format_units(self, input): + code = torch.LongTensor(list(map(int, input.strip().split()))).view(1, -1) + return {"code": code} + + def generate_vocoder_input(self, dataset): + return [self.format_units(sample) for sample in dataset] + + def forward(self, sample): + return [{"waveform": self.vocoder(sample, self.dur_prediction)}] + + +class HubertUnitExtractor(BenchmarkingBase): + def __init__(self, args): + self.feature_reader = HubertFeatureReader( + args.hubert_ckpt_path, args.hubert_layer + ) + self.kmeans = ApplyKmeans(args.hubert_km_path) + + def forward(self, sample): + with torch.no_grad(): + feat = [] + for start in range(0, sample.size(1), self.feature_reader.max_chunk): + x_chunk = sample[:, start : start + self.max_chunk] + feat_chunk, _ = self.feature_reader.model.extract_features( + source=x_chunk, + padding_mask=None, + mask=False, + output_layer=self.layer, + ) + feat.append(feat_chunk) + torch.cat(feat, 1).squeeze(0) + return self.kmeans(feat).tolist() + + +class SpeechGeneration(BenchmarkingBase): + """Class similar to examples/text_to_speech/generate_waveform.py. + Supports models with speech generation as end goal (TTS, Direct S2ST models etc)""" + + def __init__(self, args): + super().__init__() + self.use_cuda = not getattr(args, "cpu", False) + self.setUp(args) + self.s2x_task = self.task + + def setUp(self, args): + if args.task == "speech_to_speech": + args.normalize_waveform = False + self.task = tasks.setup_task(args) + self.pre_tokenizer = self.task.build_tokenizer(args) + self.bpe_tokenizer = self.task.build_bpe(args) + try: + self.src_dict = self.task.src_dict + except Exception: + self.src_dict = None + ensemble, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( + [args.path], + arg_overrides=ast.literal_eval(args.model_overrides), + task=self.task, + strict=False, + ) + self.model = ensemble[0] + if self.use_cuda: + self.model.cuda() + # criterion.cuda() + self.model.eval() + self.generator = self.task.build_generator( + [self.model], + args, + ) + + def processTextInput(self, text): + """Generate source tokens from text input""" + if self.pre_tokenizer is not None: + text = self.pre_tokenizer.encode(text) + if self.bpe_tokenizer is not None: + text = self.bpe_tokenizer.encode(text) + target = self.src_dict.encode_line( + text, add_if_not_exist=False, append_eos=True + ).long() + target = fairseq_data_utils.collate_tokens( + [target], + self.src_dict.pad(), + self.src_dict.eos(), + left_pad=False, + move_eos_to_beginning=False, + ) + src_lengths = torch.tensor([target.size(1)], dtype=torch.long) + prev_output_tokens = None + sample = { + "net_input": { + "src_tokens": target, + "src_lengths": src_lengths, + "prev_output_tokens": prev_output_tokens, + } + } + sample = utils.move_to_cuda(sample) if self.use_cuda else sample + return sample + + def forward(self, sample): + sample["speaker"] = None + output = self.generator.generate(self.model, sample) # , has_targ=False + return output + + +class S2UT(BenchmarkingBase): + """Class to support S2UT models. Also supports generating waveforms from the units predicted""" + + def __init__(self, s2u_args, vocoder_args=None): + super().__init__() + self.s2u = Processing(s2u_args) + self.vocoder = None + if vocoder_args: + self.vocoder = GenerateWaveformFromCode(vocoder_args) + self.vocoder_input = None + + def forward(self, sample): + s2u_hypos = self.s2u(sample) + s2u_output = self.s2u.decode_target(s2u_hypos) + if not self.vocoder: + return s2u_output + units = self.vocoder.format_units(s2u_output) + vocoder_output = self.vocoder(units) + return vocoder_output + + def generate_s2u_outputs(self, dataset): + return [self.s2u.decode_target(self.s2u(sample)) for sample in dataset] + + def compute_metrics(self, metric_type, dataset, repeat=None): + """Generic function to compute metrics ignoring the io processing time""" + if self.vocoder and not self.vocoder_input: + self.s2u_output = self.generate_s2u_outputs(dataset) + self.vocoder_input = self.vocoder.generate_vocoder_input(self.s2u_output) + + s2u_metrics = getattr(self.s2u, metric_type)( + dataset, + repeat, + ) + vocoder_metrics = 0 + if self.vocoder: + vocoder_metrics = getattr(self.vocoder, metric_type)( + self.vocoder_input, + repeat, + ) + print( + f"metric_type = {metric_type} s2u_metrics = {s2u_metrics} \t vocoder_metrics = {vocoder_metrics}" + ) + if metric_type == "max_memory": + return max(s2u_metrics, vocoder_metrics) + else: + return s2u_metrics + vocoder_metrics + + def benchmark_run_time(self, dataset, repeat): + return self.compute_metrics("benchmark_run_time", dataset, repeat) + + def count_flops(self, dataset, repeat): + return self.compute_metrics("count_flops", dataset, repeat) + + def max_memory(self, dataset, repeat): + return self.compute_metrics("max_memory", dataset, repeat) + + +class Cascaded2StageS2ST(BenchmarkingBase): + """ST + TTS""" + + def __init__(self, s2t_args, tts_args): + super().__init__() + self.s2t = Processing(s2t_args) + self.s2x_task = self.s2t.task + self.tts = SpeechGeneration(tts_args) if tts_args else None + self.training = False + self.tts_inputs = None + + def forward(self, sample): + if not self.tts: + raise Exception( + "Forward function is not callable without tts. Reinitialize the class with tts_args" + ) + s2t_hypos = self.s2t(sample) + s2t_output = self.s2t.decode_target(s2t_hypos) + tts_input = self.tts.processTextInput(s2t_output) + tts_output = self.tts(tts_input) + return tts_output + + def generate_s2t_outputs(self, dataset): + """Process dataset and generate s2t outputs""" + return [self.s2t.decode_target(self.s2t(sample)) for sample in dataset] + + def generate_tts_inputs(self, dataset): + """Process dataset and generate tts inputs""" + return [self.tts.processTextInput(sample) for sample in dataset] + + def compute_metrics(self, metric_type, dataset, repeat=None): + """Generic function to compute metrics ignoring the io processing time""" + if not self.tts_inputs: + s2t_outputs = self.generate_s2t_outputs(dataset) + self.tts_inputs = self.generate_tts_inputs(s2t_outputs) + + s2t_metrics = getattr(self.s2t, metric_type)( + dataset, + repeat, + ) + + tts_metrics = getattr(self.tts, metric_type)( + self.tts_inputs, + repeat, + ) + print( + f"metric_type = {metric_type} s2t_metrics = {s2t_metrics} \t tts_metrics = {tts_metrics}" + ) + if metric_type == "max_memory": + return max(s2t_metrics, tts_metrics) + else: + return s2t_metrics + tts_metrics + + def benchmark_run_time(self, dataset, repeat): + return self.compute_metrics("benchmark_run_time", dataset, repeat) + + def count_flops(self, dataset, repeat): + return self.compute_metrics("count_flops", dataset, repeat) + + def max_memory(self, dataset, repeat): + return self.compute_metrics("max_memory", dataset, repeat) + + +class Cascaded3StageS2ST(Cascaded2StageS2ST): + """ASR + MT + TTS""" + + def __init__(self, s2t_args, tts_args, mt_args): + super().__init__(s2t_args, tts_args) + self.mt = Processing(mt_args) + self.mt_inputs = [] + + def forward(self, sample): + s2t_hypos = self.s2t(sample) + s2t_output = self.s2t.decode_target(s2t_hypos) + mt_input = self.mt.encode_source(s2t_output) + mt_hypos = self.mt(mt_input) + mt_output = self.mt.decode_target(mt_hypos) + tts_input = self.tts.processTextInput(mt_output) + tts_output = self.tts(tts_input) + return tts_output + + def generate_mt_inputs(self, dataset): + """Process dataset to generate mt model inputs""" + return [self.mt.encode_source(sample) for sample in dataset] + + def generate_mt_outputs(self, dataset): + """Process dataset to generate mt model outputs""" + return [self.mt.decode_target(self.mt(sample)) for sample in dataset] + + def compute_metrics(self, metric_type, dataset, repeat=None): + """Generic function to compute metrics ignoring the io processing time""" + if not self.tts_inputs: + s2t_outputs = self.generate_s2t_outputs(dataset) + self.mt_inputs = self.generate_mt_inputs(s2t_outputs) + mt_outputs = self.generate_mt_outputs(self.mt_inputs) + self.tts_inputs = self.generate_tts_inputs(mt_outputs) + + s2t_metrics = getattr(self.s2t, metric_type)( + dataset, + repeat, + ) + mt_metrics = getattr(self.mt, metric_type)(self.mt_inputs, repeat) + tts_metrics = getattr(self.tts, metric_type)( + self.tts_inputs, + repeat, + ) + print( + f"metric_type = {metric_type} s2t_metrics = {s2t_metrics} \t mt_metrics = {mt_metrics} \t tts_metrics = {tts_metrics}" + ) + if metric_type == "max_memory": + return max(s2t_metrics, mt_metrics, tts_metrics) + else: + return s2t_metrics + mt_metrics + tts_metrics diff --git a/examples/speech_to_speech/benchmarking/data_utils.py b/examples/speech_to_speech/benchmarking/data_utils.py new file mode 100644 index 0000000000..c73a59951f --- /dev/null +++ b/examples/speech_to_speech/benchmarking/data_utils.py @@ -0,0 +1,264 @@ +from fairseq import tasks +import numpy as np +import logging +import random +from fairseq import options +import torch +import os +import soundfile as sf + +from fairseq.data.audio.audio_utils import ( + get_waveform, + parse_path, +) + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +random.seed(1) +np.random.seed(1) +random_number_generator = np.random.RandomState(30) + + +def generate_random_data_sample(T, B=1, D=80): + """Generate random data sample given the T, B, D values""" + net_input = { + "src_tokens": torch.tensor(random_number_generator.randn(B, T, D)).float(), + "src_lengths": torch.tensor([T]), + } + return {"net_input": net_input} + + +def generate_random_dataset(T_range_min, T_range_max, B=1, D=80, dataset_size=100): + """Generate random dataset with T values within a given range, B, D""" + T_values = [random.randint(T_range_min, T_range_max) for i in range(dataset_size)] + dataset = [] + for t in T_values: + dataset.append(generate_random_data_sample(t, B, D)) + return dataset, sum(T_values) / dataset_size + + +def load_dataset_npy(file_name, dataset_size=None): + """Load dataset from a .npy file.""" + data = np.load(file_name, allow_pickle=True) + if dataset_size: + data = data[:dataset_size] + return data + + +def load_dataset_raw_to_waveforms( + file_name, + dataset_size=None, + need_waveform=True, + sample_rate=16000, + read_using_soundfile=False, +): + """Load raw dataset from w2v tsv file. Optionally get waveforms""" + data = [] + with open(file_name, "r") as fp: + lines = fp.readlines() + data = [ + os.path.join(lines[0].strip(), line.strip().split("\t")[0]) + for line in lines[1:] + ] + + if dataset_size: + data = data[:dataset_size] + + if not need_waveform: + return data + + features = [] + if read_using_soundfile: + for _i, d in enumerate(data): + wav = sf.read(d)[0] + if wav.ndim == 2: + wav = wav.mean(-1) + features.append(torch.from_numpy(wav).float().view(1, -1)) + else: + for i, d in enumerate(data): + _path, slice_ptr = parse_path(d) + if len(slice_ptr) == 0: + feat = get_waveform( + _path, always_2d=True, output_sample_rate=sample_rate + )[0] + features.append( + { + "id": i, + "net_input": { + "src_tokens": torch.tensor(feat), + "src_lengths": torch.tensor([feat.shape[1]]), + }, + } + ) + else: + raise Exception("Currently unsupported data format") + return features + + +def load_dataset_task( + args, + batch_size=1, + limit_size=None, + ref_dataset=None, +): + """Loads dataset based on args by creating a task""" + if not args.data or not args.subset or not args.task: + raise Exception( + "Please provide necessary arguments to load the dataset - data, subset and task" + ) + task = tasks.setup_task(args) + + task.load_dataset(args.subset) + if not limit_size: + limit_size = len(task.dataset(args.subset)) + + iter = task.get_batch_iterator( + dataset=task.dataset(args.subset), max_sentences=batch_size + ).next_epoch_itr(shuffle=False) + dataset = [] + for i, sample in enumerate(iter): + sample = { + "id": task.datasets[args.subset].ids[sample["id"].item()], + "net_input": { + "src_tokens": sample["net_input"]["src_tokens"], + "src_lengths": sample["net_input"]["src_lengths"], + }, + } + dataset.append(sample) + if i == limit_size - 1: + break + + if ref_dataset: + try: + ids = get_ids_from_dataset(ref_dataset) + except Exception as e: + raise Exception(f"{e} - Cannot extract ids from reference dataset") + + filtered_dataset = [] + for sample in dataset: + if ( + sample["id"] in ids + or sample["id"][5:] in ids + or f"dev_{sample['id']}" in ids + ): + filtered_dataset.append(sample) + dataset = filtered_dataset + + max_len, min_len, avg_len = get_dataset_stats(dataset) + print( + f"{args.subset} dataset stats : num_samples={len(dataset)} max_len = {max_len} min_len = {min_len} avg_len = {avg_len}" + ) + + return dataset + + +def randomly_sample_subset(dataset, size=500): + """Randomly sample subset from a dataset""" + random_indices = [random.randint(0, len(dataset) - 1) for i in range(size)] + return [dataset[i] for i in random_indices] + + +def get_short_data_subset(dataset, size=500): + """Get a subset of desired size by sorting based on src_lengths""" + return sort_dataset(dataset)[:size] + + +def get_long_data_subset(dataset, size=500): + """Get a subset of desired size by sorting based on src_lengths descending""" + return sort_dataset(dataset, reverse=True)[:size] + + +def sort_dataset(dataset, reverse=False): + return sorted( + dataset, key=lambda x: x["net_input"]["src_lengths"].item(), reverse=reverse + ) + + +def save_dataset_npy(dataset, file_name): + """Save a dataset as .npy file""" + np.save(file_name, dataset) + + +def get_dataset_stats(dataset): + """Get stats about dataset based on src_lengths of samples""" + max_len = 0 + min_len = 100000 + avg_len = 0 + for d in dataset: + max_len = max(max_len, d["net_input"]["src_lengths"].item()) + min_len = min(min_len, d["net_input"]["src_lengths"].item()) + avg_len += d["net_input"]["src_lengths"].item() + + return max_len, min_len, avg_len / len(dataset) + + +def make_parser(): + """ + Additional args: + 1. Provide the dataset dir path using --data. + 2. Loading the dataset doesn't require config, provide --config-yaml to apply additional feature transforms + """ + parser = options.get_speech_generation_parser() + parser.add_argument( + "--subset", + default=None, + type=str, + required=True, + help="Subset to use for dataset generation", + ) + parser.add_argument( + "--dataset-save-dir", + default=None, + type=str, + required=False, + help="Dir path in which the datasets are to be saved", + ) + parser.add_argument( + "--ref-dataset", + default=None, + type=str, + required=False, + help="If provided, the ids in the reference dataset will be used to filter the new dataset generated.", + ) + parser.add_argument("--dataset-save-token", default="", type=str, required=False) + + options.add_generation_args(parser) + return parser + + +def get_ids_from_dataset(dataset): + return {sample["id"]: 1 for sample in dataset} + + +def cli_main(): + parser = make_parser() + args = options.parse_args_and_arch(parser) + dataset = load_dataset_task(args) + + random_dataset = randomly_sample_subset(dataset) + short_dataset = get_short_data_subset(dataset) + long_dataset = get_long_data_subset(dataset) + + if args.dataset_save_token: + args.dataset_save_token = f"_{args.dataset_save_token}_" + + if args.dataset_save_dir: + save_dataset_npy( + random_dataset, + f"{args.dataset_save_dir}/random_dataset{args.dataset_save_token}w_ids.npy", + ) + save_dataset_npy( + short_dataset, + f"{args.dataset_save_dir}/short_dataset{args.dataset_save_token}w_ids.npy", + ) + save_dataset_npy( + long_dataset, + f"{args.dataset_save_dir}/long_dataset{args.dataset_save_token}w_ids.npy", + ) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/speech_to_speech/benchmarking/get_metrics.py b/examples/speech_to_speech/benchmarking/get_metrics.py new file mode 100644 index 0000000000..773257f5da --- /dev/null +++ b/examples/speech_to_speech/benchmarking/get_metrics.py @@ -0,0 +1,162 @@ +import copy +import torch +import logging +from argparse import Namespace +import yaml +from fairseq import options +from examples.speech_to_speech.benchmarking.core import ( + Processing, + SpeechGeneration, + Cascaded2StageS2ST, + Cascaded3StageS2ST, + S2UT, +) +from examples.speech_to_speech.benchmarking.data_utils import ( + load_dataset_npy, + load_dataset_raw_to_waveforms, +) + + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +torch.manual_seed(1) +torch.set_deterministic(True) + + +def make_parser(): + """Note: As the names indicate use s2x_args(ex:ST, ASR etc) for models with speech input, + x2s_args for models with speech output(ex:TTS) and mt_args for translation models (ex: mt, T2U etc). + For direct S2ST models, use x2s_args to provide model details. + """ + parser = options.get_speech_generation_parser() + parser.add_argument("--target-is-code", action="store_true", default=False) + parser.add_argument("--config", type=str) + parser.add_argument( + "--model-type", + default="S2U", + choices=["S2S", "TTS", "S2UT", "MT", "S2T", "2StageS2ST", "3StageS2ST"], + help="Choose one of the models. For model inference implementation, refer to core.py", + ) + parser.add_argument( + "--dataset-path", + type=str, + help="""File to load dataset from. Assumes dataset is a list of samples. + Each sample is a dict of format {'net_input':{'src_tokens':torch.tenor(),'src_lengths':torch.tensor()}}""", + ) + parser.add_argument( + "--dataset-type", + type=str, + default="npy", + choices=["npy", "raw"], + help="""Type of input dataset file""", + ) + parser.add_argument( + "--read-using-sf", + type=str, + default=False, + help="""If sound file should be used to read the raw dataset""", + ) + parser.add_argument( + "--dataset-size", + default=None, + type=int, + help="Dataset size to use for benchmarking", + ) + parser.add_argument( + "--dump-speech-waveforms-dir", + default=None, + type=str, + help="Directory to dump the speech waveforms computed on the dataset.", + ) + parser.add_argument( + "--dump-waveform-file-prefix", + default="", + type=str, + help="File name prefix for the saved speech waveforms", + ) + parser.add_argument( + "--feat-dim", default=80, type=int, help="Input feature dimension" + ) + parser.add_argument( + "--target-sr", + default=16000, + type=int, + help="Target sample rate for dumping waveforms", + ) + + options.add_generation_args(parser) + options.get_interactive_generation_parser(parser) + return parser + + +def cli_main(): + parser = make_parser() + args = options.parse_args_and_arch(parser) + + with open( + args.config, + "r", + ) as f: + config = yaml.load(f, Loader=yaml.FullLoader) + dict_args = vars(args) + dict_args.update(config["general"]) + args = Namespace(**dict_args) + + i = 1 + stage_args = [] + while i <= 3: + var = f"stage{i}" + tmp_args = copy.deepcopy(dict_args) + if var in config: + tmp_args.update(config[var]) + stage_args.append(Namespace(**tmp_args)) + i += 1 + else: + break + + if args.model_type == "S2S" or args.model_type == "TTS": + model = SpeechGeneration(stage_args[0]) + elif args.model_type == "S2UT": + model = S2UT(stage_args[0], stage_args[1] if len(stage_args) > 1 else None) + elif args.model_type == "MT" or args.model_type == "S2T": + model = Processing(stage_args[0]) + elif args.model_type == "2StageS2ST": + model = Cascaded2StageS2ST(stage_args[0], stage_args[1]) + elif args.model_type == "3StageS2ST": + model = Cascaded3StageS2ST(stage_args[0], stage_args[2], stage_args[1]) + else: + raise Exception(f"Currently unsupported model type {args.model_type}") + + print(f"Evaluating on dataset - {args.dataset_path}\n") + + if args.dataset_type == "npy": + dataset = load_dataset_npy(args.dataset_path, dataset_size=args.dataset_size) + elif args.dataset_type == "raw": + dataset = load_dataset_raw_to_waveforms( + args.dataset_path, + dataset_size=args.dataset_size, + read_using_soundfile=args.read_using_sf, + ) + else: + raise Exception(f"Invalid dataset type {args.dataset_type}") + + model.warm_up(sample=dataset[0], repeat=2) + + run_time, memory, flops = model.gather_all_metrics(dataset, repeat=1) + print(f"run_time = {run_time}sec \tmemory = {memory}MiB \tflops = {flops}") + + if args.dump_speech_waveforms_dir: + model.dump_final_speech_output( + dataset, + args.dump_speech_waveforms_dir, + lambda x: x, + args.target_sr, + prefix=args.dump_waveform_file_prefix, + ) + + +if __name__ == "__main__": + cli_main() diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index fff8332034..c2667d9d00 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -202,7 +202,7 @@ def __init__(self, args, tgt_dict): self.tgt_dict = tgt_dict self.data_cfg = S2SDataConfig(Path(args.data) / args.config_yaml) self.multitask_tasks = {} - if args.multitask_config_yaml: + if getattr(args, "multitask_config_yaml", None) is not None: multitask_cfg = MultitaskConfig( Path(args.data) / args.multitask_config_yaml ) From b3fa5100c65a9e3a89f2f60f91c795309aefbfba Mon Sep 17 00:00:00 2001 From: Liang Tan <liangtan@fb.com> Date: Tue, 11 Jan 2022 10:08:20 -0800 Subject: [PATCH 542/774] Add mha prune to fairseq Summary: Support multihead attention prune for Fairseq. For example, user can apply pruning on top of Roberta base model by specify the argument "--mha-heads-to-keep 8". Also, user needs to provide a ckpt which is already pruned so that the pruned ckpt can be loaded correctly. The idea of prune can be summarized as 1. Fine tune model (e.g. roberta encoder) on a certain datasets with regularization 2. After the model is trained. User could use get_reserve_head_index and _adaptive_prune_heads functions to get the top X heads with most importance. Then user uses the rank to prune a new roberta encoder and save the pruned ckpt manually. 3. User will fine tune the the new roberta encoder via the ckpt saved above To get rid of registering different pruned version of Roberta, I use the argument --mha-heads-to-keep to prune the Roberta model into a pruned version which matches the pruned ckpt. Reviewed By: dianaml0 Differential Revision: D32449003 fbshipit-source-id: a952fd9ad723a6dbc5c2af574c42f2e9a1fa27dc --- fairseq/models/roberta/model.py | 8 ++ fairseq/modules/multihead_attention.py | 145 ++++++++++++++++++++++++- fairseq/trainer.py | 16 +++ tests/test_multihead_attention.py | 12 ++ 4 files changed, 177 insertions(+), 4 deletions(-) diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 845a53aa44..e8ff6acd6d 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -202,6 +202,14 @@ def add_args(parser): default=0.0, help="scaling factor for regularization term in adptive pruning, recommendation is 0.000375", ) + parser.add_argument( + "--mha-heads-to-keep", + type=int, + metavar="D", + default=-1, + help="number of heads to keep in each multi-head attention module, -1 means keeping all heads", + ) + @classmethod def build_model(cls, args, task): diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index a251635611..8780a9b9fe 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -4,7 +4,7 @@ # LICENSE file in the root directory of this source tree. import math -from typing import Dict, Optional, Tuple +from typing import Dict, List, Optional, Tuple import torch import torch.nn.functional as F @@ -87,6 +87,7 @@ def __init__( self.reset_parameters() self.onnx_trace = False + self.skip_embed_dim_check = False def prepare_for_onnx_export_(self): self.onnx_trace = True @@ -111,6 +112,134 @@ def reset_parameters(self): if self.bias_v is not None: nn.init.xavier_normal_(self.bias_v) + def _get_reserve_head_index(self, num_heads_to_keep: int): + k_proj_heads_norm = [] + q_proj_heads_norm = [] + v_proj_heads_norm = [] + + for i in range(self.num_heads): + start_idx = i * self.head_dim + end_idx = (i + 1) * self.head_dim + k_proj_heads_norm.append( + torch.sum( + torch.abs( + self.k_proj.weight[ + start_idx:end_idx, + ] + ) + ).tolist() + + torch.sum(torch.abs(self.k_proj.bias[start_idx:end_idx])).tolist() + ) + q_proj_heads_norm.append( + torch.sum( + torch.abs( + self.q_proj.weight[ + start_idx:end_idx, + ] + ) + ).tolist() + + torch.sum(torch.abs(self.q_proj.bias[start_idx:end_idx])).tolist() + ) + v_proj_heads_norm.append( + torch.sum( + torch.abs( + self.v_proj.weight[ + start_idx:end_idx, + ] + ) + ).tolist() + + torch.sum(torch.abs(self.v_proj.bias[start_idx:end_idx])).tolist() + ) + + heads_norm = [] + for i in range(self.num_heads): + heads_norm.append( + k_proj_heads_norm[i] + q_proj_heads_norm[i] + v_proj_heads_norm[i] + ) + + sorted_head_index = sorted( + range(self.num_heads), key=lambda k: heads_norm[k], reverse=True + ) + reserve_head_index = [] + for i in range(num_heads_to_keep): + start = sorted_head_index[i] * self.head_dim + end = (sorted_head_index[i] + 1) * self.head_dim + reserve_head_index.append((start, end)) + return reserve_head_index + + def _adaptive_prune_heads(self, reserve_head_index: List[Tuple[int, int]]): + new_q_weight = [] + new_q_bias = [] + new_k_weight = [] + new_k_bias = [] + new_v_weight = [] + new_v_bias = [] + new_out_proj_weight = [] + + for ele in reserve_head_index: + start_idx, end_idx = ele + new_q_weight.append( + self.q_proj.weight[ + start_idx:end_idx, + ] + ) + new_q_bias.append(self.q_proj.bias[start_idx:end_idx]) + + new_k_weight.append( + self.k_proj.weight[ + start_idx:end_idx, + ] + ) + + new_k_bias.append(self.k_proj.bias[start_idx:end_idx]) + + new_v_weight.append( + self.v_proj.weight[ + start_idx:end_idx, + ] + ) + new_v_bias.append(self.v_proj.bias[start_idx:end_idx]) + + new_out_proj_weight.append(self.out_proj.weight[:, start_idx:end_idx]) + + new_q_weight = torch.cat(new_q_weight).detach() + new_k_weight = torch.cat(new_k_weight).detach() + new_v_weight = torch.cat(new_v_weight).detach() + new_out_proj_weight = torch.cat(new_out_proj_weight, dim=-1).detach() + new_q_weight.requires_grad = True + new_k_weight.requires_grad = True + new_v_weight.requires_grad = True + new_out_proj_weight.requires_grad = True + + new_q_bias = torch.cat(new_q_bias).detach() + new_q_bias.requires_grad = True + + new_k_bias = torch.cat(new_k_bias).detach() + new_k_bias.requires_grad = True + + new_v_bias = torch.cat(new_v_bias).detach() + new_v_bias.requires_grad = True + + self.q_proj.weight = torch.nn.Parameter(new_q_weight) + self.q_proj.bias = torch.nn.Parameter(new_q_bias) + + self.k_proj.weight = torch.nn.Parameter(new_k_weight) + self.k_proj.bias = torch.nn.Parameter(new_k_bias) + + self.v_proj.weight = torch.nn.Parameter(new_v_weight) + self.v_proj.bias = torch.nn.Parameter(new_v_bias) + + self.out_proj.weight = torch.nn.Parameter(new_out_proj_weight) + + self.num_heads = len(reserve_head_index) + self.embed_dim = self.head_dim * self.num_heads + self.q_proj.out_features = self.embed_dim + self.k_proj.out_features = self.embed_dim + self.v_proj.out_features = self.embed_dim + + def _set_skip_embed_dim_check(self): + self.skip_embed_dim_check = True + def forward( self, query, @@ -148,7 +277,10 @@ def forward( tgt_len, bsz, embed_dim = query.size() src_len = tgt_len - assert embed_dim == self.embed_dim, f"query dim {embed_dim} != {self.embed_dim}" + if not self.skip_embed_dim_check: + assert ( + embed_dim == self.embed_dim + ), f"query dim {embed_dim} != {self.embed_dim}" assert list(query.size()) == [tgt_len, bsz, embed_dim] if key is not None: src_len, key_bsz, _ = key.size() @@ -165,6 +297,11 @@ def forward( # A workaround for quantization to work. Otherwise JIT compilation # treats bias in linear module as method. and not torch.jit.is_scripting() + # The Multihead attention implemented in pytorch forces strong dimension check + # for input embedding dimention and K,Q,V projection dimension. + # Since pruning will break the dimension check and it is not easy to modify the pytorch API, + # it is preferred to bypass the pytorch MHA when we need to skip embed_dim_check + and not self.skip_embed_dim_check ): assert key is not None and value is not None return F.multi_head_attention_forward( @@ -369,9 +506,9 @@ def forward( if self.onnx_trace and attn.size(1) == 1: # when ONNX tracing a single decoder step (sequence length == 1) # the transpose is a no-op copy before view, thus unnecessary - attn = attn.contiguous().view(tgt_len, bsz, embed_dim) + attn = attn.contiguous().view(tgt_len, bsz, self.embed_dim) else: - attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) + attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, self.embed_dim) attn = self.out_proj(attn) attn_weights: Optional[Tensor] = None if need_weights: diff --git a/fairseq/trainer.py b/fairseq/trainer.py index ac24edb2e5..ee71f7aaea 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -25,6 +25,7 @@ from fairseq.models.ema import build_ema from fairseq.nan_detector import NanDetector from fairseq.optim import lr_scheduler +from fairseq.utils import safe_hasattr from omegaconf import OmegaConf logger = logging.getLogger(__name__) @@ -501,6 +502,21 @@ def load_checkpoint( # load model parameters try: + # this is the code related to AdaPrune + # In short, it removes redundant heads in multi-head attention module based on heads importance provided + # For more info, please refer to the paper: https://openreview.net/forum?id=_CMSV7FTzGI + if ( + safe_hasattr(self.model, "args") + and safe_hasattr(self.model.args, "mha_heads_to_keep") + and self.model.args.mha_heads_to_keep != -1 + ): + logger.info(f"Prune model: keep {self.model.args.mha_heads_to_keep} heads for each multihead attention module") + for layer in self.model.encoder.sentence_encoder.layers: + reserve_head_index = layer.self_attn._get_reserve_head_index(num_heads_to_keep=self.model.args.mha_heads_to_keep) + layer.self_attn._adaptive_prune_heads(reserve_head_index=reserve_head_index) + layer.self_attn._set_skip_embed_dim_check() + logger.info(self.model) + self.model.load_state_dict( state["model"], strict=True, model_cfg=self.cfg.model ) diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index 620a2d6791..786357dbcd 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -68,6 +68,18 @@ def test_append_prev_key_padding_mask(self): else: self.assertIsNone(c[2]) + def test_pruning_heads(self): + embed_dim = 768 + num_heads = 12 + num_heads_to_keep = 8 + dummy_input = torch.randn(32, 2, embed_dim) + mha = MultiheadAttention(embed_dim=embed_dim, num_heads=num_heads) + reserve_head_index = mha._get_reserve_head_index(num_heads_to_keep=num_heads_to_keep) + mha._adaptive_prune_heads(reserve_head_index=reserve_head_index) + mha._set_skip_embed_dim_check() + mha(query=dummy_input, key=dummy_input, value=dummy_input) + self.assertEqual(mha.head_dim, embed_dim/num_heads) + self.assertEqual(mha.num_heads, num_heads_to_keep) if __name__ == "__main__": unittest.main() From 279796224f7c1e89d1c431a8a3d223b471b36bf9 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Tue, 11 Jan 2022 11:55:43 -0800 Subject: [PATCH 543/774] Preprocess Split (#2738) Summary: This is the equivalent to PR https://github.com/fairinternal/fairseq-py/issues/2697 but on top of main instead of gshard (cherry-picked and merged the squash): * reorganize preprocess.py code a bit * use Binarizers objects in the multiprocess code * clean up the make_binary * multiprocess logic * learn to count * format and doc string * add basic test for vocab binarizer * generalize to one line * move multiprocess in binarizer Testing: ``` python -m fairseq_cli.preprocess --only-source --trainpref ~/fixathon/small_vocab_test/train.in --destdir ~/fixathon/small_vocab_test/data-bin.cherry --workers 20 python -m fairseq_cli.preprocess --only-source --trainpref ~/fixathon/small_vocab_test/train.in --destdir ~/fixathon/small_vocab_test/data-bin.main --workers 20 ``` ``` md5sum ~/fixathon/small_vocab_test/data-bin.cherry/train.bin == md5sum ~/fixathon/small_vocab_test/data-bin.main/train.bin ``` ``` diff ~/fixathon/small_vocab_test/data-bin.main/dict.txt ~/fixathon/small_vocab_test/data-bin.cherry/dict.tx ``` Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2738 Reviewed By: sshleifer, dianaml0 Differential Revision: D32830875 Pulled By: Mortimerp9 fbshipit-source-id: e7463d5cdd96a877691bf39666daa319ebb3dcb8 --- fairseq/binarizer.py | 413 ++++++++++++++++++++++---- fairseq_cli/preprocess.py | 602 ++++++++++++++++++-------------------- tests/test_binarizer.py | 122 ++++++++ tests/test_huffman.py | 24 +- tests/utils.py | 30 ++ 5 files changed, 802 insertions(+), 389 deletions(-) create mode 100644 tests/test_binarizer.py diff --git a/fairseq/binarizer.py b/fairseq/binarizer.py index ae4d02a6db..6f03d7a2cb 100644 --- a/fairseq/binarizer.py +++ b/fairseq/binarizer.py @@ -3,78 +3,379 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import logging +import os +import typing as tp +from abc import ABC, abstractmethod from collections import Counter -from typing import Dict +from dataclasses import dataclass +from multiprocessing import Pool import torch -from fairseq.file_chunker_utils import Chunker +from fairseq.data import Dictionary, indexed_dataset +from fairseq.file_chunker_utils import Chunker, find_offsets from fairseq.file_io import PathManager from fairseq.tokenizer import tokenize_line +logger = logging.getLogger("binarizer") -class Binarizer: - @staticmethod - def binarize( - filename, - dict, - consumer, - tokenize=tokenize_line, - append_eos=True, - reverse_order=False, - offset=0, - end=-1, - already_numberized=False, - ) -> Dict[str, int]: - nseq, ntok = 0, 0 - replaced = Counter() - def replaced_consumer(word, idx): - if idx == dict.unk_index and word != dict.unk_word: - replaced.update([word]) +@dataclass +class BinarizeSummary: + """ + Keep track of what's going on in the binarizer + """ + + num_seq: int = 0 + replaced: tp.Optional[Counter] = None + num_tok: int = 0 + + @property + def num_replaced(self) -> int: + if self.replaced is None: + return 0 + return sum(self.replaced.values()) + + @property + def replaced_percent(self) -> float: + return 100 * self.num_replaced / self.num_tok + + def __str__(self) -> str: + base = f"{self.num_seq} sents, {self.num_tok} tokens" + if self.replaced is None: + return base + + return f"{base}, {self.replaced_percent:.3}% replaced" + + def merge(self, other: "BinarizeSummary"): + replaced = None + if self.replaced is not None: + replaced = self.replaced + if other.replaced is not None: + if replaced is None: + replaced = other.replaced + else: + replaced += other.replaced + self.replaced = replaced + self.num_seq += other.num_seq + self.num_tok += other.num_tok + + +class Binarizer(ABC): + """ + a binarizer describes how to take a string and build a tensor out of it + """ + + @abstractmethod + def binarize_line( + self, + line: str, + summary: BinarizeSummary, + ) -> torch.IntTensor: + ... + + +def _worker_prefix(output_prefix: str, worker_id: int): + return f"{output_prefix}.pt{worker_id}" + + +class FileBinarizer: + """ + An file binarizer can take a file, tokenize it, and binarize each line to a tensor + """ + + @classmethod + def multiprocess_dataset( + cls, + input_file: str, + dataset_impl: str, + binarizer: Binarizer, + output_prefix: str, + vocab_size=None, + num_workers=1, + ) -> BinarizeSummary: + final_summary = BinarizeSummary() + + offsets = find_offsets(input_file, num_workers) + # find_offsets returns a list of position [pos1, pos2, pos3, pos4] but we would want pairs: + # [(pos1, pos2), (pos2, pos3), (pos3, pos4)] to process the chunks with start/end info + # we zip the list with itself shifted by one to get all the pairs. + (first_chunk, *more_chunks) = zip(offsets, offsets[1:]) + pool = None + if num_workers > 1: + pool = Pool(processes=num_workers - 1) + worker_results = [ + pool.apply_async( + cls._binarize_chunk_and_finalize, + args=( + binarizer, + input_file, + start_offset, + end_offset, + _worker_prefix( + output_prefix, + worker_id, + ), + dataset_impl, + ), + kwds={ + "vocab_size": vocab_size, + } + if vocab_size is not None + else {}, + ) + for worker_id, (start_offset, end_offset) in enumerate( + more_chunks, start=1 + ) + ] + + pool.close() + pool.join() + for r in worker_results: + summ = r.get() + final_summary.merge(summ) + + # do not close the bin file as we need to merge the worker results in + final_ds, summ = cls._binarize_file_chunk( + binarizer, + input_file, + offset_start=first_chunk[0], + offset_end=first_chunk[1], + output_prefix=output_prefix, + dataset_impl=dataset_impl, + vocab_size=vocab_size if vocab_size is not None else None, + ) + final_summary.merge(summ) + + if num_workers > 1: + for worker_id in range(1, num_workers): + # merge the worker outputs + worker_output_prefix = _worker_prefix( + output_prefix, + worker_id, + ) + final_ds.merge_file_(worker_output_prefix) + try: + os.remove(indexed_dataset.data_file_path(worker_output_prefix)) + os.remove(indexed_dataset.index_file_path(worker_output_prefix)) + except Exception as e: + logger.error( + f"couldn't remove {worker_output_prefix}.*", exc_info=e + ) + + # now we can close the file + idx_file = indexed_dataset.index_file_path(output_prefix) + final_ds.finalize(idx_file) + return final_summary + + @staticmethod + def _binarize_file_chunk( + binarizer: Binarizer, + filename: str, + offset_start: int, + offset_end: int, + output_prefix: str, + dataset_impl: str, + vocab_size=None, + ) -> tp.Tuple[tp.Any, BinarizeSummary]: # (dataset builder, BinarizeSummary) + """ + creates a dataset builder and append binarized items to it. This function does not + finalize the builder, this is useful if you want to do other things with your bin file + like appending/merging other files + """ + bin_file = indexed_dataset.data_file_path(output_prefix) + ds = indexed_dataset.make_builder( + bin_file, + impl=dataset_impl, + vocab_size=vocab_size, + ) + summary = BinarizeSummary() with Chunker( - PathManager.get_local_path(filename), offset, end + PathManager.get_local_path(filename), offset_start, offset_end ) as line_iterator: for line in line_iterator: - if already_numberized: - id_strings = line.strip().split() - id_list = [int(id_string) for id_string in id_strings] - if reverse_order: - id_list.reverse() - if append_eos: - id_list.append(dict.eos()) - ids = torch.IntTensor(id_list) - else: - ids = dict.encode_line( - line=line, - line_tokenizer=tokenize, - add_if_not_exist=False, - consumer=replaced_consumer, - append_eos=append_eos, - reverse_order=reverse_order, - ) - nseq += 1 - ntok += len(ids) - consumer(ids) - return { - "nseq": nseq, - "nunk": sum(replaced.values()), - "ntok": ntok, - "replaced": replaced, - } + ds.add_item(binarizer.binarize_line(line, summary)) - @staticmethod + return ds, summary + + @classmethod + def _binarize_chunk_and_finalize( + cls, + binarizer: Binarizer, + filename: str, + offset_start: int, + offset_end: int, + output_prefix: str, + dataset_impl: str, + vocab_size=None, + ): + """ + same as above, but also finalizes the builder + """ + ds, summ = cls._binarize_file_chunk( + binarizer, + filename, + offset_start, + offset_end, + output_prefix, + dataset_impl, + vocab_size=vocab_size, + ) + + idx_file = indexed_dataset.index_file_path(output_prefix) + ds.finalize(idx_file) + + return summ + + +class VocabularyDatasetBinarizer(Binarizer): + """ + Takes a Dictionary/Vocabulary, assign ids to each + token using the dictionary encode_line function. + """ + + def __init__( + self, + dict: Dictionary, + tokenize: tp.Callable[[str], tp.List[str]] = tokenize_line, + append_eos: bool = True, + reverse_order: bool = False, + already_numberized: bool = False, + ) -> None: + self.dict = dict + self.tokenize = tokenize + self.append_eos = append_eos + self.reverse_order = reverse_order + self.already_numberized = already_numberized + super().__init__() + + def binarize_line( + self, + line: str, + summary: BinarizeSummary, + ): + if summary.replaced is None: + summary.replaced = Counter() + + def replaced_consumer(word, idx): + if idx == self.dict.unk_index and word != self.dict.unk_word: + summary.replaced.update([word]) + + if self.already_numberized: + id_strings = line.strip().split() + id_list = [int(id_string) for id_string in id_strings] + if self.reverse_order: + id_list.reverse() + if self.append_eos: + id_list.append(self.dict.eos()) + ids = torch.IntTensor(id_list) + else: + ids = self.dict.encode_line( + line=line, + line_tokenizer=self.tokenize, + add_if_not_exist=False, + consumer=replaced_consumer, + append_eos=self.append_eos, + reverse_order=self.reverse_order, + ) + + summary.num_seq += 1 + summary.num_tok += len(ids) + return ids + + +class AlignmentDatasetBinarizer(Binarizer): + """ + binarize by parsing a set of alignments and packing + them in a tensor (see utils.parse_alignment) + """ + + def __init__( + self, + alignment_parser: tp.Callable[[str], torch.IntTensor], + ) -> None: + super().__init__() + self.alignment_parser = alignment_parser + + def binarize_line( + self, + line: str, + summary: BinarizeSummary, + ): + ids = self.alignment_parser(line) + summary.num_seq += 1 + summary.num_tok += len(ids) + return ids + + +class LegacyBinarizer: + @classmethod + def binarize( + cls, + filename: str, + dico: Dictionary, + consumer: tp.Callable[[torch.IntTensor], None], + tokenize: tp.Callable[[str], tp.List[str]] = tokenize_line, + append_eos: bool = True, + reverse_order: bool = False, + offset: int = 0, + end: int = -1, + already_numberized: bool = False, + ) -> tp.Dict[str, int]: + binarizer = VocabularyDatasetBinarizer( + dict=dico, + tokenize=tokenize, + append_eos=append_eos, + reverse_order=reverse_order, + already_numberized=already_numberized, + ) + return cls._consume_file( + filename, + binarizer, + consumer, + offset_start=offset, + offset_end=end, + ) + + @classmethod def binarize_alignments( - filename, alignment_parser, consumer, offset=0, end=-1 - ) -> Dict[str, int]: - nseq = 0 + cls, + filename: str, + alignment_parser: tp.Callable[[str], torch.IntTensor], + consumer: tp.Callable[[torch.IntTensor], None], + offset: int = 0, + end: int = -1, + ) -> tp.Dict[str, int]: + binarizer = AlignmentDatasetBinarizer(alignment_parser) + return cls._consume_file( + filename, + binarizer, + consumer, + offset_start=offset, + offset_end=end, + ) + + @staticmethod + def _consume_file( + filename: str, + binarizer: Binarizer, + consumer: tp.Callable[[torch.IntTensor], None], + offset_start: int, + offset_end: int, + ) -> tp.Dict[str, int]: + summary = BinarizeSummary() with Chunker( - PathManager.get_local_path(filename), offset, end + PathManager.get_local_path(filename), offset_start, offset_end ) as line_iterator: for line in line_iterator: - ids = alignment_parser(line) - nseq += 1 - consumer(ids) - return {"nseq": nseq} + consumer(binarizer.binarize_line(line, summary)) + + return { + "nseq": summary.num_seq, + "nunk": summary.num_replaced, + "ntok": summary.num_tok, + "replaced": summary.replaced, + } diff --git a/fairseq_cli/preprocess.py b/fairseq_cli/preprocess.py index 6f24983d23..2ba9e09338 100644 --- a/fairseq_cli/preprocess.py +++ b/fairseq_cli/preprocess.py @@ -11,14 +11,17 @@ import os import shutil import sys -from collections import Counter +import typing as tp +from argparse import Namespace from itertools import zip_longest -from multiprocessing import Pool from fairseq import options, tasks, utils -from fairseq.binarizer import Binarizer -from fairseq.data import indexed_dataset -from fairseq.file_chunker_utils import find_offsets +from fairseq.binarizer import ( + AlignmentDatasetBinarizer, + FileBinarizer, + VocabularyDatasetBinarizer, +) +from fairseq.data import Dictionary logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -28,8 +31,251 @@ ) logger = logging.getLogger("fairseq_cli.preprocess") +##################################################################### +# file name tools +##################################################################### + + +def _train_path(lang, trainpref): + return "{}{}".format(trainpref, ("." + lang) if lang else "") + + +def _file_name(prefix, lang): + fname = prefix + if lang is not None: + fname += ".{lang}".format(lang=lang) + return fname + + +def _dest_path(prefix, lang, destdir): + return os.path.join(destdir, _file_name(prefix, lang)) + + +def _dict_path(lang, destdir): + return _dest_path("dict", lang, destdir) + ".txt" + + +def dataset_dest_prefix(args, output_prefix, lang): + base = os.path.join(args.destdir, output_prefix) + if lang is not None: + lang_part = f".{args.source_lang}-{args.target_lang}.{lang}" + elif args.only_source: + lang_part = "" + else: + lang_part = f".{args.source_lang}-{args.target_lang}" + + return "{}{}".format(base, lang_part) + + +def dataset_dest_file(args, output_prefix, lang, extension): + return "{}.{}".format(dataset_dest_prefix(args, output_prefix, lang), extension) + + +##################################################################### +# dictionary tools +##################################################################### + + +def _build_dictionary( + filenames, + task, + args, + src=False, + tgt=False, +): + assert src ^ tgt + return task.build_dictionary( + filenames, + workers=args.workers, + threshold=args.thresholdsrc if src else args.thresholdtgt, + nwords=args.nwordssrc if src else args.nwordstgt, + padding_factor=args.padding_factor, + ) + + +##################################################################### +# bin file creation logic +##################################################################### + + +def _make_binary_dataset( + vocab: Dictionary, + input_prefix: str, + output_prefix: str, + lang: tp.Optional[str], + num_workers: int, + args: Namespace, +): + logger.info("[{}] Dictionary: {} types".format(lang, len(vocab))) + + binarizer = VocabularyDatasetBinarizer( + vocab, + append_eos=True, + ) + + input_file = "{}{}".format(input_prefix, ("." + lang) if lang is not None else "") + full_output_prefix = dataset_dest_prefix(args, output_prefix, lang) + + final_summary = FileBinarizer.multiprocess_dataset( + input_file, + args.dataset_impl, + binarizer, + full_output_prefix, + vocab_size=len(vocab), + num_workers=num_workers, + ) + + logger.info(f"[{lang}] {input_file}: {final_summary} (by {vocab.unk_word})") + + +def _make_binary_alignment_dataset( + input_prefix: str, output_prefix: str, num_workers: int, args: Namespace +): + + binarizer = AlignmentDatasetBinarizer(utils.parse_alignment) + + input_file = input_prefix + full_output_prefix = dataset_dest_prefix(args, output_prefix, lang=None) + + final_summary = FileBinarizer.multiprocess_dataset( + input_file, + args.dataset_impl, + binarizer, + full_output_prefix, + vocab_size=None, + num_workers=num_workers, + ) + + logger.info( + "[alignments] {}: parsed {} alignments".format( + input_file, final_summary.num_seq + ) + ) + + +##################################################################### +# routing logic +##################################################################### + + +def _make_dataset( + vocab: Dictionary, + input_prefix: str, + output_prefix: str, + lang: tp.Optional[str], + args: Namespace, + num_workers: int, +): + if args.dataset_impl == "raw": + # Copy original text file to destination folder + output_text_file = _dest_path( + output_prefix + ".{}-{}".format(args.source_lang, args.target_lang), + lang, + args.destdir, + ) + shutil.copyfile(_file_name(input_prefix, lang), output_text_file) + else: + _make_binary_dataset( + vocab, input_prefix, output_prefix, lang, num_workers, args + ) + + +def _make_all(lang, vocab, args): + if args.trainpref: + _make_dataset( + vocab, args.trainpref, "train", lang, args=args, num_workers=args.workers + ) + if args.validpref: + for k, validpref in enumerate(args.validpref.split(",")): + outprefix = "valid{}".format(k) if k > 0 else "valid" + _make_dataset( + vocab, validpref, outprefix, lang, args=args, num_workers=args.workers + ) + if args.testpref: + for k, testpref in enumerate(args.testpref.split(",")): + outprefix = "test{}".format(k) if k > 0 else "test" + _make_dataset( + vocab, testpref, outprefix, lang, args=args, num_workers=args.workers + ) + + +def _make_all_alignments(args): + if args.trainpref and os.path.exists(args.trainpref + "." + args.align_suffix): + _make_binary_alignment_dataset( + args.trainpref + "." + args.align_suffix, + "train.align", + num_workers=args.workers, + args=args, + ) + if args.validpref and os.path.exists(args.validpref + "." + args.align_suffix): + _make_binary_alignment_dataset( + args.validpref + "." + args.align_suffix, + "valid.align", + num_workers=args.workers, + args=args, + ) + if args.testpref and os.path.exists(args.testpref + "." + args.align_suffix): + _make_binary_alignment_dataset( + args.testpref + "." + args.align_suffix, + "test.align", + num_workers=args.workers, + args=args, + ) + + +##################################################################### +# align +##################################################################### + + +def _align_files(args, src_dict, tgt_dict): + assert args.trainpref, "--trainpref must be set if --alignfile is specified" + src_file_name = _train_path(args.source_lang, args.trainpref) + tgt_file_name = _train_path(args.target_lang, args.trainpref) + freq_map = {} + with open(args.alignfile, "r", encoding="utf-8") as align_file: + with open(src_file_name, "r", encoding="utf-8") as src_file: + with open(tgt_file_name, "r", encoding="utf-8") as tgt_file: + for a, s, t in zip_longest(align_file, src_file, tgt_file): + si = src_dict.encode_line(s, add_if_not_exist=False) + ti = tgt_dict.encode_line(t, add_if_not_exist=False) + ai = list(map(lambda x: tuple(x.split("-")), a.split())) + for sai, tai in ai: + srcidx = si[int(sai)] + tgtidx = ti[int(tai)] + if srcidx != src_dict.unk() and tgtidx != tgt_dict.unk(): + assert srcidx != src_dict.pad() + assert srcidx != src_dict.eos() + assert tgtidx != tgt_dict.pad() + assert tgtidx != tgt_dict.eos() + if srcidx not in freq_map: + freq_map[srcidx] = {} + if tgtidx not in freq_map[srcidx]: + freq_map[srcidx][tgtidx] = 1 + else: + freq_map[srcidx][tgtidx] += 1 + align_dict = {} + for srcidx in freq_map.keys(): + align_dict[srcidx] = max(freq_map[srcidx], key=freq_map[srcidx].get) + with open( + os.path.join( + args.destdir, + "alignment.{}-{}.txt".format(args.source_lang, args.target_lang), + ), + "w", + encoding="utf-8", + ) as f: + for k, v in align_dict.items(): + print("{} {}".format(src_dict[k], tgt_dict[v]), file=f) + + +##################################################################### +# MAIN +##################################################################### + def main(args): + # setup some basic things utils.import_user_module(args) os.makedirs(args.destdir, exist_ok=True) @@ -45,39 +291,21 @@ def main(args): args.dataset_impl != "huffman" ), "preprocessing.py doesn't support Huffman yet, use HuffmanCodeBuilder directly." - task = tasks.get_task(args.task) - - def train_path(lang): - return "{}{}".format(args.trainpref, ("." + lang) if lang else "") - - def file_name(prefix, lang): - fname = prefix - if lang is not None: - fname += ".{lang}".format(lang=lang) - return fname - - def dest_path(prefix, lang): - return os.path.join(args.destdir, file_name(prefix, lang)) - - def dict_path(lang): - return dest_path("dict", lang) + ".txt" - - def build_dictionary(filenames, src=False, tgt=False): - assert src ^ tgt - return task.build_dictionary( - filenames, - workers=args.workers, - threshold=args.thresholdsrc if src else args.thresholdtgt, - nwords=args.nwordssrc if src else args.nwordstgt, - padding_factor=args.padding_factor, - ) + # build dictionaries target = not args.only_source - if not args.srcdict and os.path.exists(dict_path(args.source_lang)): - raise FileExistsError(dict_path(args.source_lang)) - if target and not args.tgtdict and os.path.exists(dict_path(args.target_lang)): - raise FileExistsError(dict_path(args.target_lang)) + if not args.srcdict and os.path.exists(_dict_path(args.source_lang, args.destdir)): + raise FileExistsError(_dict_path(args.source_lang, args.destdir)) + + if ( + target + and not args.tgtdict + and os.path.exists(_dict_path(args.target_lang, args.destdir)) + ): + raise FileExistsError(_dict_path(args.target_lang, args.destdir)) + + task = tasks.get_task(args.task) if args.joined_dictionary: assert ( @@ -92,8 +320,13 @@ def build_dictionary(filenames, src=False, tgt=False): assert ( args.trainpref ), "--trainpref must be set if --srcdict is not specified" - src_dict = build_dictionary( - {train_path(lang) for lang in [args.source_lang, args.target_lang]}, + src_dict = _build_dictionary( + { + _train_path(lang, args.trainpref) + for lang in [args.source_lang, args.target_lang] + }, + task=task, + args=args, src=True, ) tgt_dict = src_dict @@ -104,7 +337,12 @@ def build_dictionary(filenames, src=False, tgt=False): assert ( args.trainpref ), "--trainpref must be set if --srcdict is not specified" - src_dict = build_dictionary([train_path(args.source_lang)], src=True) + src_dict = _build_dictionary( + [_train_path(args.source_lang, args.trainpref)], + task=task, + args=args, + src=True, + ) if target: if args.tgtdict: @@ -113,292 +351,36 @@ def build_dictionary(filenames, src=False, tgt=False): assert ( args.trainpref ), "--trainpref must be set if --tgtdict is not specified" - tgt_dict = build_dictionary([train_path(args.target_lang)], tgt=True) + tgt_dict = _build_dictionary( + [_train_path(args.target_lang, args.trainpref)], + task=task, + args=args, + tgt=True, + ) else: tgt_dict = None - src_dict.save(dict_path(args.source_lang)) + # save dictionaries + + src_dict.save(_dict_path(args.source_lang, args.destdir)) if target and tgt_dict is not None: - tgt_dict.save(dict_path(args.target_lang)) + tgt_dict.save(_dict_path(args.target_lang, args.destdir)) if args.dict_only: return - def make_binary_dataset(vocab, input_prefix, output_prefix, lang, num_workers): - logger.info("[{}] Dictionary: {} types".format(lang, len(vocab))) - n_seq_tok = [0, 0] - replaced = Counter() - - def merge_result(worker_result): - replaced.update(worker_result["replaced"]) - n_seq_tok[0] += worker_result["nseq"] - n_seq_tok[1] += worker_result["ntok"] - - input_file = "{}{}".format( - input_prefix, ("." + lang) if lang is not None else "" - ) - offsets = find_offsets(input_file, num_workers) - (first_chunk, *more_chunks) = zip(offsets, offsets[1:]) - pool = None - if num_workers > 1: - pool = Pool(processes=num_workers - 1) - for worker_id, (start_offset, end_offset) in enumerate( - more_chunks, start=1 - ): - prefix = "{}{}".format(output_prefix, worker_id) - pool.apply_async( - binarize, - ( - args, - input_file, - vocab, - prefix, - lang, - start_offset, - end_offset, - ), - callback=merge_result, - ) - pool.close() - - ds = indexed_dataset.make_builder( - dataset_dest_file(args, output_prefix, lang, "bin"), - impl=args.dataset_impl, - vocab_size=len(vocab), - ) - merge_result( - Binarizer.binarize( - input_file, - vocab, - lambda t: ds.add_item(t), - offset=first_chunk[0], - end=first_chunk[1], - ) - ) - if num_workers > 1: - pool.join() - for worker_id in range(1, num_workers): - prefix = "{}{}".format(output_prefix, worker_id) - temp_file_path = dataset_dest_prefix(args, prefix, lang) - ds.merge_file_(temp_file_path) - os.remove(indexed_dataset.data_file_path(temp_file_path)) - os.remove(indexed_dataset.index_file_path(temp_file_path)) - - ds.finalize(dataset_dest_file(args, output_prefix, lang, "idx")) - - logger.info( - "[{}] {}: {} sents, {} tokens, {:.3}% replaced by {}".format( - lang, - input_file, - n_seq_tok[0], - n_seq_tok[1], - 100 * sum(replaced.values()) / n_seq_tok[1], - vocab.unk_word, - ) - ) - - def make_binary_alignment_dataset(input_prefix, output_prefix, num_workers): - nseq = [0] - - def merge_result(worker_result): - nseq[0] += worker_result["nseq"] - - input_file = input_prefix - offsets = find_offsets(input_file, num_workers) - (first_chunk, *more_chunks) = zip(offsets, offsets[1:]) - pool = None - if num_workers > 1: - pool = Pool(processes=num_workers - 1) - for worker_id, (start_offset, end_offset) in enumerate( - more_chunks, start=1 - ): - prefix = "{}{}".format(output_prefix, worker_id) - pool.apply_async( - binarize_alignments, - ( - args, - input_file, - utils.parse_alignment, - prefix, - start_offset, - end_offset, - ), - callback=merge_result, - ) - pool.close() - - ds = indexed_dataset.make_builder( - dataset_dest_file(args, output_prefix, None, "bin"), impl=args.dataset_impl - ) - - merge_result( - Binarizer.binarize_alignments( - input_file, - utils.parse_alignment, - lambda t: ds.add_item(t), - offset=first_chunk[0], - end=first_chunk[1], - ) - ) - if num_workers > 1: - pool.join() - for worker_id in range(1, num_workers): - prefix = "{}{}".format(output_prefix, worker_id) - temp_file_path = dataset_dest_prefix(args, prefix, None) - ds.merge_file_(temp_file_path) - os.remove(indexed_dataset.data_file_path(temp_file_path)) - os.remove(indexed_dataset.index_file_path(temp_file_path)) - - ds.finalize(dataset_dest_file(args, output_prefix, None, "idx")) - - logger.info("[alignments] {}: parsed {} alignments".format(input_file, nseq[0])) - - def make_dataset(vocab, input_prefix, output_prefix, lang, num_workers=1): - if args.dataset_impl == "raw": - # Copy original text file to destination folder - output_text_file = dest_path( - output_prefix + ".{}-{}".format(args.source_lang, args.target_lang), - lang, - ) - shutil.copyfile(file_name(input_prefix, lang), output_text_file) - else: - make_binary_dataset(vocab, input_prefix, output_prefix, lang, num_workers) - - def make_all(lang, vocab): - if args.trainpref: - make_dataset(vocab, args.trainpref, "train", lang, num_workers=args.workers) - if args.validpref: - for k, validpref in enumerate(args.validpref.split(",")): - outprefix = "valid{}".format(k) if k > 0 else "valid" - make_dataset( - vocab, validpref, outprefix, lang, num_workers=args.workers - ) - if args.testpref: - for k, testpref in enumerate(args.testpref.split(",")): - outprefix = "test{}".format(k) if k > 0 else "test" - make_dataset(vocab, testpref, outprefix, lang, num_workers=args.workers) - - def make_all_alignments(): - if args.trainpref and os.path.exists(args.trainpref + "." + args.align_suffix): - make_binary_alignment_dataset( - args.trainpref + "." + args.align_suffix, - "train.align", - num_workers=args.workers, - ) - if args.validpref and os.path.exists(args.validpref + "." + args.align_suffix): - make_binary_alignment_dataset( - args.validpref + "." + args.align_suffix, - "valid.align", - num_workers=args.workers, - ) - if args.testpref and os.path.exists(args.testpref + "." + args.align_suffix): - make_binary_alignment_dataset( - args.testpref + "." + args.align_suffix, - "test.align", - num_workers=args.workers, - ) - - make_all(args.source_lang, src_dict) + _make_all(args.source_lang, src_dict, args) if target: - make_all(args.target_lang, tgt_dict) + _make_all(args.target_lang, tgt_dict, args) + + # align the datasets if needed if args.align_suffix: - make_all_alignments() + _make_all_alignments(args) logger.info("Wrote preprocessed data to {}".format(args.destdir)) if args.alignfile: - assert args.trainpref, "--trainpref must be set if --alignfile is specified" - src_file_name = train_path(args.source_lang) - tgt_file_name = train_path(args.target_lang) - freq_map = {} - with open(args.alignfile, "r", encoding="utf-8") as align_file: - with open(src_file_name, "r", encoding="utf-8") as src_file: - with open(tgt_file_name, "r", encoding="utf-8") as tgt_file: - for a, s, t in zip_longest(align_file, src_file, tgt_file): - si = src_dict.encode_line(s, add_if_not_exist=False) - ti = tgt_dict.encode_line(t, add_if_not_exist=False) - ai = list(map(lambda x: tuple(x.split("-")), a.split())) - for sai, tai in ai: - srcidx = si[int(sai)] - tgtidx = ti[int(tai)] - if srcidx != src_dict.unk() and tgtidx != tgt_dict.unk(): - assert srcidx != src_dict.pad() - assert srcidx != src_dict.eos() - assert tgtidx != tgt_dict.pad() - assert tgtidx != tgt_dict.eos() - - if srcidx not in freq_map: - freq_map[srcidx] = {} - if tgtidx not in freq_map[srcidx]: - freq_map[srcidx][tgtidx] = 1 - else: - freq_map[srcidx][tgtidx] += 1 - - align_dict = {} - for srcidx in freq_map.keys(): - align_dict[srcidx] = max(freq_map[srcidx], key=freq_map[srcidx].get) - - with open( - os.path.join( - args.destdir, - "alignment.{}-{}.txt".format(args.source_lang, args.target_lang), - ), - "w", - encoding="utf-8", - ) as f: - for k, v in align_dict.items(): - print("{} {}".format(src_dict[k], tgt_dict[v]), file=f) - - -def binarize(args, filename, vocab, output_prefix, lang, offset, end, append_eos=True): - ds = indexed_dataset.make_builder( - dataset_dest_file(args, output_prefix, lang, "bin"), - impl=args.dataset_impl, - vocab_size=len(vocab), - ) - - def consumer(tensor): - ds.add_item(tensor) - - res = Binarizer.binarize( - filename, vocab, consumer, append_eos=append_eos, offset=offset, end=end - ) - ds.finalize(dataset_dest_file(args, output_prefix, lang, "idx")) - return res - - -def binarize_alignments(args, filename, parse_alignment, output_prefix, offset, end): - ds = indexed_dataset.make_builder( - dataset_dest_file(args, output_prefix, None, "bin"), - impl=args.dataset_impl, - vocab_size=None, - ) - - def consumer(tensor): - ds.add_item(tensor) - - res = Binarizer.binarize_alignments( - filename, parse_alignment, consumer, offset=offset, end=end - ) - ds.finalize(dataset_dest_file(args, output_prefix, None, "idx")) - return res - - -def dataset_dest_prefix(args, output_prefix, lang): - base = "{}/{}".format(args.destdir, output_prefix) - if lang is not None: - lang_part = ".{}-{}.{}".format(args.source_lang, args.target_lang, lang) - elif args.only_source: - lang_part = "" - else: - lang_part = ".{}-{}".format(args.source_lang, args.target_lang) - - return "{}{}".format(base, lang_part) - - -def dataset_dest_file(args, output_prefix, lang, extension): - base = dataset_dest_prefix(args, output_prefix, lang) - return "{}.{}".format(base, extension) + _align_files(args, src_dict=src_dict, tgt_dict=tgt_dict) def cli_main(): diff --git a/tests/test_binarizer.py b/tests/test_binarizer.py new file mode 100644 index 0000000000..50075eabcc --- /dev/null +++ b/tests/test_binarizer.py @@ -0,0 +1,122 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import os +import typing as tp +import unittest +from tempfile import TemporaryDirectory + +from fairseq.binarizer import BinarizeSummary, FileBinarizer, VocabularyDatasetBinarizer +from fairseq.data import Dictionary, indexed_dataset +from tests.utils import make_data, sizes + + +def build_vocab(data: tp.List[tp.List[str]]) -> Dictionary: + d = Dictionary() + for s in data: + for token in s: + d.add_symbol(token) + d.finalize() + return d + + +class TestBinarizer(unittest.TestCase): + def compare_ds_data(self, summary, data, prefix, impl, vocab): + self.assertEqual(summary.num_seq, len(data)) + self.assertEqual(summary.num_tok, sum([len(s) for s in data])) + + dataset = indexed_dataset.make_dataset(prefix, impl) + + self.assertEqual(len(dataset), len(data)) + decoded = [vocab.string(dataset[i]).split() for i in range(0, len(dataset))] + + self.assertEqual(decoded, data) + data_sizes = [i.item() for i in dataset.sizes] + self.assertEqual(data_sizes, sizes(data)) + + def test_can_binarize_line(self): + data = make_data(length=1) + vocab = build_vocab(data) + + binarizer = VocabularyDatasetBinarizer( + vocab, + ) + + sentence = data[0] + summary = BinarizeSummary() + + tensor = binarizer.binarize_line( + " ".join(sentence), + summary, + ) + + self.assertEqual(len(tensor), len(sentence) + 1) + + self.assertEqual(summary.num_tok, len(sentence) + 1) + self.assertEqual(summary.num_seq, 1) + + def test_can_binarize_file_chunk(self): + # test without multiprocess logic + with TemporaryDirectory() as dirname: + raw_file = os.path.join(dirname, "raw1") + prefix = os.path.join(dirname, "test1") + impl = "mmap" + + data = make_data(out_file=raw_file) + vocab = build_vocab(data) + + binarizer = VocabularyDatasetBinarizer( + vocab, + append_eos=False, + ) + + summary = FileBinarizer._binarize_chunk_and_finalize( + binarizer, + raw_file, + offset_start=0, + offset_end=-1, + output_prefix=prefix, + dataset_impl=impl, + vocab_size=len(vocab), + ) + + self.compare_ds_data(summary, data, prefix, impl, vocab) + + def test_can_multiprocess(self): + with TemporaryDirectory() as dirname: + raw_file = os.path.join(dirname, "raw1") + prefix = os.path.join(dirname, "test1") + impl = "mmap" + data = make_data(out_file=raw_file) + vocab = build_vocab(data) + binarizer = VocabularyDatasetBinarizer( + vocab, + append_eos=False, + ) + # with one worker + summary = FileBinarizer.multiprocess_dataset( + raw_file, + impl, + binarizer, + output_prefix=prefix, + vocab_size=len(vocab), + num_workers=1, + ) + + self.compare_ds_data(summary, data, prefix, impl, vocab) + + # with multiple worker + prefix_multi = os.path.join(dirname, "test2") + summary = FileBinarizer.multiprocess_dataset( + raw_file, + impl, + binarizer, + output_prefix=prefix_multi, + vocab_size=len(vocab), + num_workers=3, + ) + + self.compare_ds_data(summary, data, prefix_multi, impl, vocab) diff --git a/tests/test_huffman.py b/tests/test_huffman.py index a8cd5222b4..85d0c72a76 100644 --- a/tests/test_huffman.py +++ b/tests/test_huffman.py @@ -4,8 +4,6 @@ # LICENSE file in the root directory of this source tree. import os -import random -import string import typing as tp import unittest from collections import Counter @@ -18,23 +16,7 @@ HuffmanMMapIndexedDataset, HuffmanMMapIndexedDatasetBuilder, ) - -POPULATION = string.ascii_letters + string.digits - - -def make_sentence() -> tp.List[str]: - length = random.randint(10, 50) - return random.choices( - population=POPULATION, k=length, weights=range(1, len(POPULATION) + 1) - ) - - -def make_data(length=1000) -> tp.List[tp.List[str]]: - return ( - [make_sentence() for _ in range(0, length)] - # add all the symbols at least once - + [list(string.ascii_letters), list(string.digits)] - ) +from tests.utils import POPULATION, make_data, sizes def make_counts(data: tp.List[tp.List[str]]) -> Counter: @@ -112,10 +94,6 @@ def build_dataset(prefix, data, coder): builder.add_item(sentence) -def sizes(data): - return [len(sentence) for sentence in data] - - class TestHuffmanDataset(unittest.TestCase): def test_huffman_can_encode_decode(self): data = make_data() diff --git a/tests/utils.py b/tests/utils.py index 6ce65d8eb9..e3fa98ac25 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -8,7 +8,9 @@ import os import random import shutil +import string import sys +import typing as tp from io import StringIO import torch @@ -756,3 +758,31 @@ def train_language_model( + (extra_valid_flags or []), ) validate.main(validate_args) + + +def sizes(data): + return [len(sentence) for sentence in data] + + +POPULATION = string.ascii_letters + string.digits + + +def make_sentence() -> tp.List[str]: + length = random.randint(10, 50) + return random.choices( + population=POPULATION, k=length, weights=range(1, len(POPULATION) + 1) + ) + + +def make_data(length=1000, out_file=None) -> tp.List[tp.List[str]]: + data = ( + [make_sentence() for _ in range(0, length)] + # add all the symbols at least once + + [list(string.ascii_letters), list(string.digits)] + ) + if out_file is not None: + with open(out_file, "w", encoding="utf-8") as out: + for s in data: + print(" ".join(s), file=out) + + return data From fa7663c31419fc00db2dfb6a6431df25758d27ff Mon Sep 17 00:00:00 2001 From: Shagun Sodhani <1321193+shagunsodhani@users.noreply.github.com> Date: Wed, 12 Jan 2022 17:43:09 -0800 Subject: [PATCH 544/774] Update commands, checkpoints and contact info for shuffled word order paper (#4129) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ x ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ x ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ x ] Did you make sure to update the docs? - [ x ] Did you write any new necessary tests? ## What does this PR do? Update commands, checkpoints and contact info. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4129 Reviewed By: dianaml0 Differential Revision: D33556233 Pulled By: shruti-bh fbshipit-source-id: 3bad45b3e154fa11d4b13776d97408ce1a166113 --- examples/shuffled_word_order/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/shuffled_word_order/README.md b/examples/shuffled_word_order/README.md index f20483849a..6ce0b3927d 100644 --- a/examples/shuffled_word_order/README.md +++ b/examples/shuffled_word_order/README.md @@ -46,13 +46,19 @@ Follow the same usage as in [RoBERTa](https://github.com/pytorch/fairseq/tree/ma # Download roberta.base.shuffle.n1 model wget https://dl.fbaipublicfiles.com/unnatural_pretraining/roberta.base.shuffle.n1.tar.gz tar -xzvf roberta.base.shuffle.n1.tar.gz +# Copy the dictionary files +cd roberta.base.shuffle.n1.tar.gz +wget -O dict.txt https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/dict.txt && wget -O encoder.json https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/encoder.json && wget -O vocab.bpe https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/vocab.bpe +cd .. # Load the model in fairseq -from fairseq.models.roberta import RoBERTaModel -roberta = RoBERTaModel.from_pretrained('/path/to/roberta.base.shuffle.n1', checkpoint_file='model.pt') +from fairseq.models.roberta import RobertaModel +roberta = RobertaModel.from_pretrained('/path/to/roberta.base.shuffle.n1', checkpoint_file='model.pt') roberta.eval() # disable dropout (or leave in train mode to finetune) ``` +We have also provided a [Google Colab](https://colab.research.google.com/drive/1IJDVfNVWdvRfLjphQKBGzmob84t-OXpm) notebook to demonstrate the loading of the model. The models were trained on top of Fairseq from the following commit: [62cff008ebeeed855093837507d5e6bf52065ee6](https://github.com/pytorch/fairseq/commit/62cff008ebeeed855093837507d5e6bf52065ee6). + **Note**: The model trained without positional embeddings (`roberta.base.nopos`) is a modified `RoBERTa` model, where the positional embeddings are not used. Thus, the typical `from_pretrained` method on fairseq version of RoBERTa will not be able to load the above model weights. To do so, construct a new `RoBERTaModel` object by setting the flag `use_positional_embeddings` to `False` (or [in the latest code](https://github.com/pytorch/fairseq/blob/main/fairseq/models/roberta/model.py#L543), set `no_token_positional_embeddings` to `True`), and then load the individual weights. ## Fine-tuning Evaluation @@ -82,3 +88,7 @@ We provide the trained fine-tuned models on MNLI here for each model above for q primaryClass={cs.CL} } ``` + +## Contact + +For questions and comments, please reach out to Koustuv Sinha (koustuv.sinha@mail.mcgill.ca). From cf8ff8c3c5242e6e71e8feb40de45dd699f3cc08 Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Thu, 13 Jan 2022 01:52:50 -0800 Subject: [PATCH 545/774] Add unittests for jitting EMA model Summary: As title Reviewed By: nayansinghal Differential Revision: D32005717 fbshipit-source-id: ebdf1ed0e4a2b9fccffd841d0fa7be0b50ec6b79 --- tests/test_checkpoint_utils.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py index 23ba034f3f..1e58ddb112 100644 --- a/tests/test_checkpoint_utils.py +++ b/tests/test_checkpoint_utils.py @@ -19,6 +19,7 @@ preprocess_translation_data, train_translation_model, ) +import torch class TestCheckpointUtils(unittest.TestCase): @@ -103,6 +104,27 @@ def test_torch_persistent_save_async(self): mock_opena.assert_called_with(filename, "wb") mock_save.assert_called() + def test_load_ema_from_checkpoint(self): + dummy_state = {"a": torch.tensor([1]), "b": torch.tensor([0.1])} + with patch(f"{checkpoint_utils.__name__}.PathManager.open") as mock_open, patch( + f"{checkpoint_utils.__name__}.torch.load") as mock_load: + + mock_load.return_value = { + "extra_state": { + "ema": dummy_state + } + } + filename = "ema_checkpoint.pt" + state = checkpoint_utils.load_ema_from_checkpoint(filename) + + mock_open.assert_called_with(filename, "rb") + mock_load.assert_called() + + self.assertIn("a", state["model"]) + self.assertIn("b", state["model"]) + self.assertTrue(torch.allclose(dummy_state["a"], state["model"]["a"])) + self.assertTrue(torch.allclose(dummy_state["b"], state["model"]["b"])) + if __name__ == "__main__": unittest.main() From 1575f30dd0a9f7b3c499db0b4767aa4e9f79056c Mon Sep 17 00:00:00 2001 From: Liang Tan <liangtan@fb.com> Date: Fri, 14 Jan 2022 16:22:01 -0800 Subject: [PATCH 546/774] Add ffn prune to fairseq Summary: Support FFN prune for Fairseq. For example, user can apply pruning on top of Roberta base model by specify the argument "--ffn-blocks-to-remove 1024". Also, user needs to provide a ckpt which is already pruned so that the pruned ckpt can be loaded correctly. The idea of prune can be summarized as Fine tune model (e.g. roberta encoder) on a certain datasets with regularization After the model is trained. User could use _get_fc_rank and _prune_fc_layer functions to get the top X blocks with most importance in each transformer layer. Then user uses the rank to prune a new roberta encoder and save the pruned ckpt manually. User will fine tune the the new roberta encoder via the ckpt saved above Reviewed By: dianaml0 Differential Revision: D33525055 fbshipit-source-id: 5087140ee891d6ec9266726e3a477947c233412c --- fairseq/models/roberta/model.py | 8 ++++- fairseq/modules/transformer_layer.py | 49 ++++++++++++++++++++++++++++ fairseq/trainer.py | 25 ++++++++++++++ tests/test_roberta.py | 15 +++++++++ 4 files changed, 96 insertions(+), 1 deletion(-) diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index e8ff6acd6d..d27e05cf1b 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -209,7 +209,13 @@ def add_args(parser): default=-1, help="number of heads to keep in each multi-head attention module, -1 means keeping all heads", ) - + parser.add_argument( + "--ffn-blocks-to-remove", + type=int, + metavar="D", + default=-1, + help="number of feedforward blocks to remove in each transformer layer, -1 means keeping all ffn blocks", + ) @classmethod def build_model(cls, args, task): diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index d2b57ac807..638fef0f62 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -77,6 +77,55 @@ def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size): nn.Linear(input_dim, output_dim), p=q_noise, block_size=qn_block_size ) + def _get_fc_rank(self, remove_num: int) -> List[int]: + f1_filter_param = [] + for i in range(self.fc1.out_features): + f1_filter_param.append(torch.sum(torch.abs(self.fc1.weight[i])) + torch.sum(torch.abs(self.fc2.weight[:, i])) + torch.abs(self.fc1.bias[i])) + return sorted(range(len(f1_filter_param)), key=lambda k: f1_filter_param[k], reverse=False)[0:remove_num] + + def _prune_fc_layer(self, remove_index: List[int]): + new_fc1_weight = [] + new_fc1_bias = [] + for i in range(self.fc1.out_features): + if i not in remove_index: + new_fc1_weight.append(self.fc1.weight[i]) + new_fc1_bias.append(self.fc1.bias[i]) + + new_fc1_weight = torch.stack(new_fc1_weight).detach() + new_fc1_weight.requires_grad = True + + new_fc1_bias = torch.stack(new_fc1_bias).detach() + new_fc1_bias.requires_grad = True + + self.fc1 = quant_noise( + nn.Linear(self.fc1.in_features, self.fc1.out_features - len(remove_index)), + p=self.quant_noise, + block_size=self.quant_noise_block_size, + ) + self.fc1.weight = torch.nn.Parameter(new_fc1_weight) + self.fc1.bias = torch.nn.Parameter(new_fc1_bias) + + new_fc2_weight = [] + new_fc2_bias = [] + for i in range(self.fc2.in_features): + if i not in remove_index: + new_fc2_weight.append(self.fc2.weight[:, i]) + new_fc2_bias = self.fc2.bias.detach() + + new_fc2_weight = torch.stack(new_fc2_weight, dim=-1).detach() + new_fc2_weight.requires_grad = True + + new_fc2_bias = self.fc2.bias.detach() + new_fc2_bias.requires_grad = True + + self.fc2 = quant_noise( + nn.Linear(self.fc2.in_features - len(remove_index), self.fc2.out_features), + p=self.quant_noise, + block_size=self.quant_noise_block_size, + ) + self.fc2.weight = torch.nn.Parameter(new_fc2_weight) + self.fc2.bias = torch.nn.Parameter(new_fc2_bias) + def build_self_attention(self, embed_dim, cfg): return MultiheadAttention( embed_dim, diff --git a/fairseq/trainer.py b/fairseq/trainer.py index ee71f7aaea..dd341f9c87 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -505,6 +505,12 @@ def load_checkpoint( # this is the code related to AdaPrune # In short, it removes redundant heads in multi-head attention module based on heads importance provided # For more info, please refer to the paper: https://openreview.net/forum?id=_CMSV7FTzGI + # The idea of prune in mha can be summarized as + # Fine tune model (e.g. roberta encoder) on a certain datasets with regularization + # After the model is trained. User could use get_reserve_head_index and _adaptive_prune_heads functions to get the top X heads with most importance. + # Then user uses the rank to prune a new roberta encoder and save the pruned ckpt manually. + # User will fine tune the the new roberta encoder via the ckpt saved above + # To get rid of registering different pruned version of Roberta, I use the argument --mha-heads-to-keep to prune the Roberta model into a pruned version which matches the pruned ckpt. if ( safe_hasattr(self.model, "args") and safe_hasattr(self.model.args, "mha_heads_to_keep") @@ -516,6 +522,25 @@ def load_checkpoint( layer.self_attn._adaptive_prune_heads(reserve_head_index=reserve_head_index) layer.self_attn._set_skip_embed_dim_check() logger.info(self.model) + # this is the code related to AdaPrune + # In short, it removes redundant units in feedforward layer in each transformer layer based on importance + # For more info, please refer to the paper: https://openreview.net/forum?id=_CMSV7FTzGI + # The idea of prune in ffn can be summarized as + # Fine tune model (e.g. roberta encoder) on a certain datasets with regularization + # After the model is trained. User could use _get_fc_rank and _prune_fc_layer functions to get the top X units with most importance. + # Then user uses the rank to prune a new roberta encoder and save the pruned ckpt manually. + # User will fine tune the the new roberta encoder via the ckpt saved above + # To get rid of registering different pruned version of Roberta, I use the argument --ffn-blocks-to-remove to prune the Roberta model into a pruned version which matches the pruned ckpt. + if ( + safe_hasattr(self.model, "args") + and safe_hasattr(self.model.args, "ffn_blocks_to_remove") + and self.model.args.ffn_blocks_to_remove != -1 + ): + logger.info(f"Prune model: remove {self.model.args.ffn_blocks_to_remove} ffn blocks for each transformer layer") + for layer in self.model.encoder.sentence_encoder.layers: + remove_index = layer._get_fc_rank(remove_num=self.model.args.ffn_blocks_to_remove) + layer._prune_fc_layer(remove_index=remove_index) + logger.info(self.model) self.model.load_state_dict( state["model"], strict=True, model_cfg=self.cfg.model diff --git a/tests/test_roberta.py b/tests/test_roberta.py index 75d4d797bf..14f01f9cb7 100644 --- a/tests/test_roberta.py +++ b/tests/test_roberta.py @@ -320,6 +320,21 @@ def test_regularize_for_adaprune_in_roberta(self, device: str): loss = task_loss.sum() + head_loss + ffn_loss loss.backward() + @cpu_gpu + def test_ffn_prune_for_adaprune_in_roberta(self, device: str): + _, model = get_toy_model( + device=device, + architecture="roberta_base", + ) + sample = mk_sample("en", device, batch_size=1) + for layer in model.encoder.sentence_encoder.layers: + fc1_original_size = layer.fc1.out_features + remove_index = layer._get_fc_rank(remove_num=2) + layer._prune_fc_layer(remove_index=remove_index) + self.assertEqual(layer.fc1.out_features, fc1_original_size - 2) + + task_loss, _ = model.forward(**sample["net_input"]) + def params(model, name): if "." not in name: From 40eb7310be5b3c76f0f03f625cf630a5a3e5c506 Mon Sep 17 00:00:00 2001 From: Hongyu Gong <hygong@fb.com> Date: Tue, 18 Jan 2022 16:49:27 -0800 Subject: [PATCH 547/774] Code cleanup Summary: Add scripts for multihead attention selection in multilingual and multil-domain training from the following paper: "Pay Better Attention to Attention: Head Selection in Multilingual and Multi-Domain Sequence Modeling", NeurIPS 2021. Reviewed By: yuntang Differential Revision: D31781212 fbshipit-source-id: 8e1a596826f682f80730c251ec31c68df0de6516 --- examples/attention_head_selection/README.md | 164 ++++++++ .../attention_head_selection/src/__init__.py | 0 .../src/data/__init__.py | 0 .../speech_to_text_dataset_with_domain.py | 241 ++++++++++++ .../src/loss/__init__.py | 0 .../src/loss/attention_head_selection.py | 29 ++ .../src/models/__init__.py | 0 .../models/head_selection_s2t_transformer.py | 180 +++++++++ .../src/models/head_selection_transformer.py | 215 +++++++++++ .../src/modules/__init__.py | 0 .../src/modules/attn_head_selector.py | 81 ++++ .../head_selection_transformer_layer.py | 93 +++++ .../modules/multihead_attention_selection.py | 356 ++++++++++++++++++ .../src/modules/multihead_functional.py | 279 ++++++++++++++ .../src/speech_to_text_head_selection.py | 180 +++++++++ 15 files changed, 1818 insertions(+) create mode 100644 examples/attention_head_selection/README.md create mode 100644 examples/attention_head_selection/src/__init__.py create mode 100644 examples/attention_head_selection/src/data/__init__.py create mode 100644 examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py create mode 100644 examples/attention_head_selection/src/loss/__init__.py create mode 100644 examples/attention_head_selection/src/loss/attention_head_selection.py create mode 100644 examples/attention_head_selection/src/models/__init__.py create mode 100644 examples/attention_head_selection/src/models/head_selection_s2t_transformer.py create mode 100644 examples/attention_head_selection/src/models/head_selection_transformer.py create mode 100644 examples/attention_head_selection/src/modules/__init__.py create mode 100644 examples/attention_head_selection/src/modules/attn_head_selector.py create mode 100644 examples/attention_head_selection/src/modules/head_selection_transformer_layer.py create mode 100644 examples/attention_head_selection/src/modules/multihead_attention_selection.py create mode 100644 examples/attention_head_selection/src/modules/multihead_functional.py create mode 100644 examples/attention_head_selection/src/speech_to_text_head_selection.py diff --git a/examples/attention_head_selection/README.md b/examples/attention_head_selection/README.md new file mode 100644 index 0000000000..d55b82b07b --- /dev/null +++ b/examples/attention_head_selection/README.md @@ -0,0 +1,164 @@ +# Pay Better Attention to Attention: Head Selection in Multilingual and Multi-Domain Sequence Modeling (Gong et al., 2021) + +[https://arxiv.org/pdf/2106.10840.pdf](https://arxiv.org/pdf/2106.10840.pdf) + +## Introduction + +We present attention head selection strategies in multilingual and multi-domain sequence modeling including text translation, speech recognition and speech translation tasks. + +Below is an example of training multilingual/multi-domain speech recognition models. + +## Data Preparation +Prepare mTEDx data as in [mTEDx example](https://github.com/fairinternal/fairseq-py/blob/0d9c5851e6fac40f9e366b3633ccd615c2901788/examples/speech_to_text/docs/mtedx_example.md) and CoVoST data as in [CoVoST example](https://github.com/fairinternal/fairseq-py/blob/0d9c5851e6fac40f9e366b3633ccd615c2901788/examples/speech_to_text/docs/covost_example.md). Similarly prepare EuroParl data. + + +## Training a multilingual ASR model with attention head selection + +```bash +data_dir=<path to mtedx data> +train_subset="train_ar_ar_tedx,train_de_de_tedx,train_el_el_tedx,train_es_es_tedx,train_fr_fr_tedx,train_it_it_tedx,train_pt_pt_tedx,train_ru_ru_tedx" +valid_subset="valid_ar_ar_tedx,valid_de_de_tedx,valid_el_el_tedx,valid_es_es_tedx,valid_fr_fr_tedx,valid_it_it_tedx,valid_pt_pt_tedx,valid_ru_ru_tedx" +strateg=<subset or group> + +fairseq-train ${data_dir} \ + --user-dir examples/attention_head_selection/src \ + --train-subset "${train_subset}" \ + --valid-subset "${valid_subset}" \ + --config-yaml 'config_asr.yaml' \ + --arch 'head_selection_s2t_transformer_s' \ + --task 'speech_to_text_head_selection' \ + --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ + --lr-scheduler 'inverse_sqrt' --stop-min-lr -1.0 --warmup-updates 10000 \ + --lr 5e-4 \ + --clip-norm 10.0 \ + --seed 1 \ + --max-epoch 400 \ + --max-tokens 32000 \ + --ignore-prefix-size 1 \ + --dropout 0.3 \ + --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ + --skip-invalid-size-inputs-valid-test \ + --encoder-attn-head-select \ + --total-encoder-attention-heads 8 \ + --decoder-self-attn-head-select \ + --total-decoder-attention-heads 8 \ + --attn-head-select-strategy ${strategy} \ + --task-type lang \ +``` + +## Training a multi-domain ASR model with attention head selection + +```bash +data_dir=<path to multi-domain data> +train_subset="train_es_es_tedx,train_fr_fr_tedx,train_pt_pt_tedx,train_it_it_tedx,train_ru_ru_tedx,train_el_el_tedx,train_ar_ar_tedx,train_de_de_tedx,train_ar_ar_cv,train_de_de_cv,train_es_es_cv,train_fr_fr_cv,train_it_it_cv,train_pt_pt_cv,train_ru_ru_cv,train_de_de_ep,train_es_es_ep,train_fr_fr_ep,train_it_it_ep,train_pt_pt_ep" +valid_subset="dev_es_es_tedx,dev_fr_fr_tedx,dev_pt_pt_tedx,dev_it_it_tedx,dev_ru_ru_tedx,dev_el_el_tedx,dev_ar_ar_tedx,dev_de_de_tedx,dev_ar_ar_cv,dev_de_de_cv,dev_es_es_cv,dev_fr_fr_cv,dev_it_it_cv,dev_pt_pt_cv,dev_ru_ru_cv,dev_de_de_ep,dev_es_es_ep,dev_fr_fr_ep,dev_it_it_ep,dev_pt_pt_ep" +strateg=<subset or group> + +fairseq-train ${data_dir} \ + --user-dir examples/attention_head_selection/src \ + --train-subset "${train_subset}" \ + --valid-subset "${valid_subset}" \ + --config-yaml 'config_asr.yaml' \ + --arch head_selection_s2t_transformer_s \ + --task speech_to_text_head_selection \ + --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ + --lr-scheduler 'inverse_sqrt' --stop-min-lr -1.0 --warmup-updates 10000 \ + --lr 5e-4 \ + --clip-norm 10.0 \ + --seed 1 \ + --max-epoch 400 \ + --max-tokens 32000 \ + --ignore-prefix-size 1 \ + --dropout 0.3 \ + --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ + --skip-invalid-size-inputs-valid-test \ + --encoder-attn-head-select \ + --total-encoder-attention-heads 8 \ + --decoder-self-attn-head-select \ + --total-decoder-attention-heads 8 \ + --attn-head-select-strategy ${strategy} \ + --task-type domain +``` + +## Inference in multilingual setting + +```bash +MODEL_DIR=<checkpoint directory> +data_dir=<path to mtedx data> +gen_subset=<data to test, e.g., test_ar_ar_tedx> +train_subset="train_ar_ar_tedx,train_de_de_tedx,train_el_el_tedx,train_es_es_tedx,train_fr_fr_tedx,train_it_it_tedx,train_pt_pt_tedx,train_ru_ru_tedx" +last_n=10 +CHECKPOINT_FILENAME="avg_last_${last_n}_checkpoint.pt" +CHECKPOINT="_avg" +RESULTS="${MODEL_DIR}/ckpt${CHECKPOINT}" +if [ ! -d $RESULTS ]; then + mkdir -p $RESULTS +fi; + +python scripts/average_checkpoints.py \ + --inputs ${MODEL_DIR} --num-epoch-checkpoints ${last_n} \ + --output "${MODEL_DIR}/${CHECKPOINT_FILENAME}" + +fairseq-generate ${data_dir} \ + --user-dir examples/attention_head_selection/src \ + --arch 'head_selection_s2t_transformer_s' \ + --task 'speech_to_text_head_selection' \ + --train-subset ${train_subset} \ + --gen-subset ${gen_subset} \ + --path "${MODEL_DIR}/${CHECKPOINT_FILENAME}" \ + --config-yaml 'config_asr.yaml' \ + --prefix-size 1 \ + --max-tokens 40000 --beam 5 \ + --skip-invalid-size-inputs-valid-test \ + --results-path ${RESULTS} \ + --scoring wer --wer-tokenizer 13a \ + --wer-lowercase --wer-remove-punct --remove-bpe +``` + +## Inference in multi-domain setting + +```bash +MODEL_DIR=<checkpoint directory> +data_dir=<path to multi-domain data> +gen_subset=<data to test, e.g., test_pt_pt_cv> +train_subset="train_es_es_tedx,train_fr_fr_tedx,train_pt_pt_tedx,train_it_it_tedx,train_ru_ru_tedx,train_el_el_tedx,train_ar_ar_tedx,train_de_de_tedx,train_ar_ar_cv,train_de_de_cv,train_es_es_cv,train_fr_fr_cv,train_it_it_cv,train_pt_pt_cv,train_ru_ru_cv,train_de_de_ep,train_es_es_ep,train_fr_fr_ep,train_it_it_ep,train_pt_pt_ep" +last_n=10 +CHECKPOINT_FILENAME="avg_last_${last_n}_checkpoint.pt" +CHECKPOINT="_avg" +RESULTS="${MODEL_DIR}/ckpt${CHECKPOINT}" +if [ ! -d $RESULTS ]; then + mkdir -p $RESULTS +fi; + +python scripts/average_checkpoints.py \ + --inputs ${MODEL_DIR} --num-epoch-checkpoints ${last_n} \ + --output "${MODEL_DIR}/${CHECKPOINT_FILENAME}" + +fairseq-generate ${data_dir} \ + --user-dir examples/attention_head_selection/src \ + --arch 'head_selection_s2t_transformer_s' \ + --task 'speech_to_text_head_selection' \ + --train-subset ${train_subset} \ + --gen-subset ${gen_subset} \ + --path "${MODEL_DIR}/${CHECKPOINT_FILENAME}" \ + --config-yaml 'config_asr.yaml' \ + --prefix-size 1 \ + --max-tokens 40000 --beam 5 \ + --skip-invalid-size-inputs-valid-test \ + --results-path ${RESULTS} \ + --scoring wer --wer-tokenizer 13a \ + --wer-lowercase --wer-remove-punct --remove-bpe +``` + +## Citation +```bibtex +@article{gong2021attn, + title={Pay Better Attention to Attention: Head Selection in Multilingual and Multi-Domain Sequence Modeling}, + author={Hongyu Gong and + Yun Tang and + Juan Miguel Pino and + Xian Li}, + journal={arXiv preprint arXiv:2106.10840}, + year={2021} +} +''' diff --git a/examples/attention_head_selection/src/__init__.py b/examples/attention_head_selection/src/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/attention_head_selection/src/data/__init__.py b/examples/attention_head_selection/src/data/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py b/examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py new file mode 100644 index 0000000000..e80915e60c --- /dev/null +++ b/examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py @@ -0,0 +1,241 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from pathlib import Path +from typing import Dict, List, Optional +from dataclasses import dataclass + +import torch +from fairseq.data import ( + ConcatDataset, + Dictionary, + ResamplingDataset +) +from fairseq.data.audio.data_cfg import S2TDataConfig +from fairseq.data.audio.speech_to_text_dataset import ( + SpeechToTextDatasetItem, + SpeechToTextDataset, + SpeechToTextDatasetCreator +) + +logger = logging.getLogger(__name__) + + +@dataclass +class SpeechToTextDatasetItemWithDomain(SpeechToTextDatasetItem): + src_lang_id: Optional[torch.Tensor] = None + tgt_lang_id: Optional[torch.Tensor] = None + domain_id: Optional[torch.Tensor] = None + + +class SpeechToTextDatasetWithDomain(SpeechToTextDataset): + + def __init__( + self, + split: str, + is_train_split: bool, + cfg: S2TDataConfig, + audio_paths: List[str], + n_frames: List[int], + src_texts: Optional[List[str]] = None, + tgt_texts: Optional[List[str]] = None, + speakers: Optional[List[str]] = None, + src_langs: Optional[List[str]] = None, + tgt_langs: Optional[List[str]] = None, + ids: Optional[List[str]] = None, + tgt_dict: Optional[Dictionary] = None, + pre_tokenizer=None, + bpe_tokenizer=None, + n_frames_per_step=1, + speaker_to_id=None, + src_lang_ids: Optional[List[int]] = None, + tgt_lang_ids: Optional[List[int]] = None, + domain_ids: Optional[List[int]] = None + ): + super().__init__( + split, is_train_split, cfg, audio_paths, n_frames, + src_texts, tgt_texts, speakers, src_langs, tgt_langs, + ids, tgt_dict, pre_tokenizer, bpe_tokenizer, + n_frames_per_step, speaker_to_id + ) + assert src_lang_ids is None or len(src_lang_ids) == self.n_samples + assert tgt_lang_ids is None or len(tgt_lang_ids) == self.n_samples + assert domain_ids is None or len(domain_ids) == self.n_samples + + self.src_lang_ids = src_lang_ids + self.tgt_lang_ids = tgt_lang_ids + self.domain_ids = domain_ids + + def __getitem__(self, index: int) -> SpeechToTextDatasetItemWithDomain: + item = super().__getitem__(index) + src_lang_id = self.src_lang_ids[index] + tgt_lang_id = self.tgt_lang_ids[index] + domain_id = self.domain_ids[index] + return SpeechToTextDatasetItemWithDomain( + index=item.index, source=item.source, + target=item.target, speaker_id=item.speaker_id, + src_lang_id=src_lang_id, + tgt_lang_id=tgt_lang_id, + domain_id=domain_id + ) + + def collater( + self, samples: List[SpeechToTextDatasetItem], return_order: bool = False + ) -> Dict: + if len(samples) == 0: + return {} + out = super().collater(samples, return_order=True) + order = out["order"] + src_lang_ids = torch.tensor([x.src_lang_id for x in samples], dtype=torch.long).index_select(0, order) + tgt_lang_ids = torch.tensor([x.tgt_lang_id for x in samples], dtype=torch.long).index_select(0, order) + domain_ids = torch.tensor([x.domain_id for x in samples], dtype=torch.long).index_select(0, order) + + out["src_lang_ids"] = src_lang_ids + out["tgt_lang_ids"] = tgt_lang_ids + out["domain_ids"] = domain_ids + if not return_order: + del out["order"] + return out + + +class SpeechToTextDatasetCreatorWithDomain(SpeechToTextDatasetCreator): + KEY_SRC_LANG_ID, KEY_TGT_LANG_ID = "src_lang_id", "tgt_lang_id" + KEY_DOMAIN_ID = "domain_id" + # default values + DEFAULT_SRC_LANG_ID, DEFAULT_TGT_LANG_ID, DEFAULT_DOMAIN_ID = 0, 0, 0 + + @classmethod + def _from_list( + cls, + split_name: str, + is_train_split, + samples: List[Dict], + cfg: S2TDataConfig, + tgt_dict, + pre_tokenizer, + bpe_tokenizer, + n_frames_per_step, + speaker_to_id + ) -> SpeechToTextDatasetWithDomain: + audio_root = Path(cfg.audio_root) + ids = [s[cls.KEY_ID] for s in samples] + audio_paths = [(audio_root / s[cls.KEY_AUDIO]).as_posix() for s in samples] + n_frames = [int(s[cls.KEY_N_FRAMES]) for s in samples] + tgt_texts = [s[cls.KEY_TGT_TEXT] for s in samples] + src_texts = [s.get(cls.KEY_SRC_TEXT, cls.DEFAULT_SRC_TEXT) for s in samples] + speakers = [s.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for s in samples] + src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] + tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] + src_lang_ids = [s.get(cls.KEY_SRC_LANG_ID, cls.DEFAULT_SRC_LANG_ID) for s in samples] + tgt_lang_ids = [s.get(cls.KEY_TGT_LANG_ID, cls.DEFAULT_TGT_LANG_ID) for s in samples] + domain_ids = [s.get(cls.KEY_DOMAIN_ID, cls.DEFAULT_DOMAIN_ID) for s in samples] + return SpeechToTextDatasetWithDomain( + split_name, + is_train_split, + cfg, + audio_paths, + n_frames, + src_texts=src_texts, + tgt_texts=tgt_texts, + speakers=speakers, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + tgt_dict=tgt_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + n_frames_per_step=n_frames_per_step, + speaker_to_id=speaker_to_id, + src_lang_ids=src_lang_ids, + tgt_lang_ids=tgt_lang_ids, + domain_ids=domain_ids + ) + + @classmethod + def _load_samples_from_tsv( + cls, + root: str, + split: str, + src_lang_map, + tgt_lang_map, + domain_map + ): + # metadata from split + _, src_lang, tgt_lang, domain = split.split("_") + src_lang_id = src_lang_map[src_lang] + tgt_lang_id = tgt_lang_map[tgt_lang] + domain_id = domain_map[domain] + + samples = SpeechToTextDatasetCreator._load_samples_from_tsv(root, split) + for s in samples: + s.update({ + cls.KEY_SRC_LANG_ID: src_lang_id, + cls.KEY_TGT_LANG_ID: tgt_lang_id, + cls.KEY_DOMAIN_ID: domain_id + }) + return samples + + @classmethod + def _from_tsv( + cls, + root: str, + cfg: S2TDataConfig, + split: str, + tgt_dict, + is_train_split: bool, + pre_tokenizer, + bpe_tokenizer, + n_frames_per_step, + speaker_to_id, + src_lang_map, + tgt_lang_map, + domain_map + ) -> SpeechToTextDatasetItemWithDomain: + samples = cls._load_samples_from_tsv( + root, split, src_lang_map, + tgt_lang_map, domain_map + ) + return cls._from_list( + split, is_train_split, samples, cfg, tgt_dict, pre_tokenizer, + bpe_tokenizer, n_frames_per_step, speaker_to_id + ) + + @classmethod + def from_tsv( + cls, + root: str, + cfg: S2TDataConfig, + splits: str, + tgt_dict, + pre_tokenizer, + bpe_tokenizer, + is_train_split: bool, + epoch: int, + seed: int, + n_frames_per_step: int, + speaker_to_id, + src_lang_map: Dict[str, int], + tgt_lang_map: Dict[str, int], + domain_map: Dict[str, int] + ) -> SpeechToTextDatasetWithDomain: + datasets = [ + cls._from_tsv( + root, cfg, split, tgt_dict, is_train_split, pre_tokenizer, bpe_tokenizer, n_frames_per_step, speaker_to_id, src_lang_map, tgt_lang_map, domain_map + ) + for split in splits.split(",") + ] + + if is_train_split and len(datasets) > 1 and cfg.sampling_alpha != 1.0: + # temperature-based sampling + size_ratios = cls.get_size_ratios(datasets, alpha=cfg.sampling_alpha) + datasets = [ + ResamplingDataset( + d, size_ratio=r, seed=seed, epoch=epoch, replace=(r >= 1.0) + ) + for r, d in zip(size_ratios, datasets) + ] + + return ConcatDataset(datasets) if len(datasets) > 1 else datasets[0] diff --git a/examples/attention_head_selection/src/loss/__init__.py b/examples/attention_head_selection/src/loss/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/attention_head_selection/src/loss/attention_head_selection.py b/examples/attention_head_selection/src/loss/attention_head_selection.py new file mode 100644 index 0000000000..296441b0a3 --- /dev/null +++ b/examples/attention_head_selection/src/loss/attention_head_selection.py @@ -0,0 +1,29 @@ + + +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math + +import torch +from torch.nn.modules.loss import _Loss + + +class HeadSelectionLoss(_Loss): + + def __init__(self, args): + super().__init__() + self.args = args + self.kl_weight = getattr(args, "kl_weight", 0.0) + + def forward(self, head_samples, sample_sizes, prior=0.5, eps=1e-7): + """ + head_scores: (num_tasks, num_layers, num_heads) + sample_sizes: (num_tasks, ) + """ + kl_loss = (head_samples * (torch.log(head_samples + eps) - math.log(prior))).sum(-1).sum(-1) + kl_loss /= (torch.numel(head_samples) / head_samples.size(0)) + kl_loss = self.kl_weight * torch.matmul(kl_loss, sample_sizes) + return kl_loss diff --git a/examples/attention_head_selection/src/models/__init__.py b/examples/attention_head_selection/src/models/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/attention_head_selection/src/models/head_selection_s2t_transformer.py b/examples/attention_head_selection/src/models/head_selection_s2t_transformer.py new file mode 100644 index 0000000000..8938fffd82 --- /dev/null +++ b/examples/attention_head_selection/src/models/head_selection_s2t_transformer.py @@ -0,0 +1,180 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from typing import Dict, List, Optional +from pathlib import Path +import torch.nn as nn +from torch import Tensor +from fairseq import checkpoint_utils + +from fairseq.models import register_model, register_model_architecture +from fairseq.utils import safe_hasattr +from fairseq.models.speech_to_text.s2t_transformer import ( + S2TTransformerModel, + S2TTransformerEncoder, + TransformerDecoderScriptable +) +from fairseq.models.speech_to_text.s2t_transformer import base_architecture as s2t_base_architecture + +from ..modules.attn_head_selector import AttnHeadSelector +from ..modules.head_selection_transformer_layer import HeadSelectionTransformerEncoderLayer +from .head_selection_transformer import HeadSelectionTransformerDecoder + + +logger = logging.getLogger(__name__) + + +@register_model("head_selection_s2t_transformer") +class HeadSelectionS2TTransformerModel(S2TTransformerModel): + """ + Head selection implemented in S2TTransformer + """ + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @staticmethod + def add_args(parser): + S2TTransformerModel.add_args(parser) + # encoder head selection + parser.add_argument( + "--encoder-attn-head-select", + action="store_true", + default=False, + help="encoder head selection" + ) + parser.add_argument( + "--total-encoder-attention-heads", + type=int, + help="total number of encoder attention heads" + ) + # parser.add_argument( + # "--encoder-tasks", + # type=int, + # help="the number of encoder tasks (input languages or input domains)" + # ) + # decoder self attention + parser.add_argument( + "--decoder-self-attn-head-select", + action="store_true", + default=False, + help="decoder self-attention head selection" + ) + # decoder-encoder attention + parser.add_argument( + "--dec-enc-attn-head-select", + action="store_true", + default=False, + help="decoder-encoder attention head selection" + ) + parser.add_argument( + "--total-decoder-attention-heads", + type=int, + help="total number of decoder attention heads" + ) + # parser.add_argument( + # "--decoder-tasks", + # type=int, + # help="the number of decoder tasks (output languages or output domains)" + # ) + # selection strategy + parser.add_argument( + "--attn-head-select-strategy", + type=str, + help="attention head selection strategy, subset or group" + ) + + @classmethod + def build_encoder(cls, args): + if safe_hasattr(args, "encoder_attn_head_select") and args.encoder_attn_head_select: + encoder = HeadSelectionS2TTransformerEncoder(args) + else: + encoder = S2TTransformerEncoder(args) + pretraining_path = getattr(args, "load_pretrained_encoder_from", None) + if pretraining_path is not None: + if not Path(pretraining_path).exists(): + logger.warning( + f"skipped pretraining because {pretraining_path} does not exist" + ) + else: + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=pretraining_path + ) + logger.info(f"loaded pretrained encoder from: {pretraining_path}") + return encoder + + @classmethod + def build_decoder(cls, args, task, embed_tokens): + if (safe_hasattr(args, "decoder_self_attn_head_select") and args.decoder_self_attn_head_select) or (safe_hasattr(args, "dec_enc_attn_head_select") and args.dec_enc_attn_head_select): + return HeadSelectionTransformerDecoderScriptable(args, task.target_dictionary, embed_tokens) + else: + return TransformerDecoderScriptable(args, task.target_dictionary, embed_tokens) + + +class HeadSelectionS2TTransformerEncoder(S2TTransformerEncoder): + + def __init__(self, args): + super().__init__(args) + self.attn_head_selector = AttnHeadSelector( + args.encoder_tasks, + args.encoder_layers, + args.total_encoder_attention_heads, + args.encoder_attention_heads, + args.attn_head_select_strategy, + ) + self.task_ids = None + self.transformer_layers = nn.ModuleList([ + HeadSelectionTransformerEncoderLayer(args, layer_idx, attn_head_selector=self.attn_head_selector) for layer_idx in range(args.encoder_layers) + ]) + + def set_task_ids(self, task_ids): + self.task_ids = task_ids + + def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): + self.attn_head_selector.head_select(self.task_ids) + return super()._forward(src_tokens, src_lengths, return_all_hiddens) + + +class HeadSelectionTransformerDecoderScriptable(HeadSelectionTransformerDecoder): + def extract_features( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + # call scriptable method from parent class + x, _ = self.extract_features_scriptable( + prev_output_tokens, + encoder_out, + incremental_state, + full_context_alignment, + alignment_layer, + alignment_heads, + ) + return x, None + + +@register_model_architecture(model_name="head_selection_s2t_transformer", arch_name="head_selection_s2t_transformer") +def base_architecture(args): + s2t_base_architecture(args) + args.encoder_attn_head_select = getattr(args, "encoder_attn_head_select", False) + args.decoder_self_attn_head_select = getattr(args, "decoder_self_attn_head_select", False) + args.dec_enc_attn_head_select = getattr(args, "dec_enc_attn_head_select", False) + args.total_encoder_attention_heads = getattr(args, "total_encoder_attention_heads", 8) + args.total_decoder_attention_heads = getattr(args, "total_decoder_attention_heads", 8) + args.attn_head_select_strategy = getattr(args, "attn_head_select_strategy", "group") + + +@register_model_architecture("head_selection_s2t_transformer", "head_selection_s2t_transformer_s") +def head_selection_s2t_transformer_s(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 256 * 8) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + base_architecture(args) diff --git a/examples/attention_head_selection/src/models/head_selection_transformer.py b/examples/attention_head_selection/src/models/head_selection_transformer.py new file mode 100644 index 0000000000..b9d595699d --- /dev/null +++ b/examples/attention_head_selection/src/models/head_selection_transformer.py @@ -0,0 +1,215 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, List, Dict, Optional +import torch +import torch.nn as nn +from torch import Tensor + +from fairseq.utils import safe_hasattr +from fairseq.models.transformer import ( + TransformerModel, + TransformerEncoder, + TransformerDecoder +) + +from ..modules.attn_head_selector import AttnHeadSelector +from ..modules.head_selection_transformer_layer import ( + HeadSelectionTransformerEncoderLayer, + HeadSelectionTransformerDecoderLayer +) + + +class HeadSelectionTransformerModel(TransformerModel): + def __init__(self, args, encoder, decoder): + super().__init__(args, encoder, decoder) + + @staticmethod + def add_args(parser): + TransformerModel.add_args(parser) + # encoder head selection + parser.add_argument( + "--encoder-attn-head-select", + action="store_true", + default=False, + help="encoder head selection" + ) + parser.add_argument( + "--total-encoder-attention-heads", + type=int, + help="total number of encoder attention heads" + ) + # decoder self attention + parser.add_argument( + "--decoder-self-attn-head-select", + action="store_true", + default=False, + help="decoder self-attention head selection" + ) + # decoder-encoder attention + parser.add_argument( + "--dec-enc-attn-head-select", + action="store_true", + default=False, + help="decoder-encoder attention head selection" + ) + parser.add_argument( + "--total-decoder-attention-heads", + type=int, + help="total number of decoder attention heads" + ) + # selection strategy + parser.add_argument( + "--attn-head-select-strategy", + type=str, + help="attention head selection strategy, subset or group" + ) + + @classmethod + def build_encoder(cls, args, src_dict, embed_tokens): + if safe_hasattr(args, "encoder_attn_head_select") and args.encoder_attn_head_select: + return HeadSelectionTransformerEncoder( + args, src_dict, embed_tokens + ) + else: + return TransformerEncoder(args, src_dict, embed_tokens) + + @classmethod + def build_decoder(cls, args, tgt_dict, embed_tokens): + if (safe_hasattr(args, "decoder_self_attn_head_select") and args.decoder_self_attn_head_select) or (safe_hasattr(args, "dec_enc_attn_head_select") and args.dec_enc_attn_head_select): + return HeadSelectionTransformerDecoder( + args, tgt_dict, embed_tokens + ) + else: + return TransformerDecoder(args, tgt_dict, embed_tokens) + + +class HeadSelectionTransformerEncoder(TransformerEncoder): + + def __init__(self, args, dictionary, embed_tokens): + self.num_tasks = args.encoder_tasks + self.num_layers = args.encoder_layers + self.total_num_heads = args.total_encoder_attention_heads + self.num_heads = args.encoder_attention_heads + self.select_strategy = args.attn_head_select_strategy + + super().__init__(args, dictionary, embed_tokens) + self.attn_head_selector = AttnHeadSelector( + self.num_tasks, + self.num_layers, + self.total_num_heads, + self.num_heads, + self.select_strategy + ) + self.task_ids = None + self.layers = nn.ModuleList( + [self.build_encoder_layer(args, i) for i in range(args.encoder_layers)] + ) + + def set_task_ids(self, task_ids): + self.task_ids = task_ids + + def build_encoder_layer(self, args, layer_idx=None): + return HeadSelectionTransformerEncoderLayer( + args, + layer_idx, + attn_head_selector=self.attn_head_selector + ) + + def forward( + self, + src_tokens, + src_lengths: Optional[torch.Tensor] = None, + return_all_hiddens: bool = False, + token_embeddings: Optional[torch.Tensor] = None, + ): + self.attn_head_selector.head_select(self.task_ids) + return super().forward(src_tokens, src_lengths, return_all_hiddens, token_embeddings) + + +class HeadSelectionTransformerDecoder(TransformerDecoder): + + def __init__( + self, + args, + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=None, + ): + self.num_tasks = args.decoder_tasks + self.num_layers = args.decoder_layers + self.total_num_heads = args.total_decoder_attention_heads + self.num_heads = args.decoder_attention_heads + self.select_strategy = args.attn_head_select_strategy + super().__init__( + args, dictionary, embed_tokens, + no_encoder_attn=no_encoder_attn, + output_projection=output_projection + ) + self.self_attn_head_selector = None + self.enc_attn_head_selector = None + if safe_hasattr(args, "decoder_self_attn_head_select") and args.decoder_self_attn_head_select: + self.self_attn_head_selector = AttnHeadSelector( + self.num_tasks, + self.num_layers, + self.total_num_heads, + self.num_heads, + self.select_strategy + ) + if safe_hasattr(args, "dec_enc_attn_head_select") and args.dec_enc_attn_head_select: + self.enc_attn_head_selector = AttnHeadSelector( + self.num_tasks, + self.num_layers, + self.total_num_heads, + self.num_heads, + self.select_strategy + ) + self.task_ids = None + self.layers = nn.ModuleList( + [ + self.build_head_selection_decoder_layer(args, no_encoder_attn, idx) for idx in range(args.decoder_layers) + ] + ) + + def set_task_ids(self, task_ids): + self.task_ids = task_ids + + def build_head_selection_decoder_layer(self, args, no_encoder_attn=False, layer_idx=None): + return HeadSelectionTransformerDecoderLayer( + args, + layer_idx, + self.self_attn_head_selector, + self.enc_attn_head_selector, + no_encoder_attn=no_encoder_attn + ) + + def forward( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + features_only: bool = False, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + src_lengths: Optional[Any] = None, + return_all_hiddens: bool = False, + ): + if self.self_attn_head_selector is not None: + self.self_attn_head_selector.head_select(self.task_ids) + if self.enc_attn_head_selector is not None: + self.enc_attn_head_selector.head_select(self.task_ids) + return super().forward( + prev_output_tokens=prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + features_only=features_only, + full_context_alignment=full_context_alignment, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + src_lengths=src_lengths, + return_all_hiddens=return_all_hiddens + ) diff --git a/examples/attention_head_selection/src/modules/__init__.py b/examples/attention_head_selection/src/modules/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/attention_head_selection/src/modules/attn_head_selector.py b/examples/attention_head_selection/src/modules/attn_head_selector.py new file mode 100644 index 0000000000..346fc62308 --- /dev/null +++ b/examples/attention_head_selection/src/modules/attn_head_selector.py @@ -0,0 +1,81 @@ +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn as nn +import math + + +class AttnHeadSelector(nn.Module): + """ + Latent variable modeling of attention head selection + """ + def __init__( + self, num_tasks, num_layers, + total_num_heads, num_heads, + select_strategy="group", + head_select_temp=5.0 + ): + super(AttnHeadSelector, self).__init__() + self.num_tasks = num_tasks + self.num_layers = num_layers + self.total_num_heads = total_num_heads + self.num_heads = num_heads + self.select_strategy = select_strategy + self.temp = head_select_temp + + self.head_logits = torch.nn.Parameter( + torch.Tensor(self.num_tasks, self.num_layers, total_num_heads), + requires_grad=True + ) + nn.init.uniform_( + self.head_logits, a=math.log(0.01), + b=math.log(1.0) + ) + + def gumbel_sample(self, logits, tau=1.0): + gumbels1 = -torch.empty_like(logits, memory_format=torch.legacy_contiguous_format).exponential_().log() + gumbels2 = -torch.empty_like(logits, memory_format=torch.legacy_contiguous_format).exponential_().log() + gumbels1 = (logits + gumbels1 - gumbels2) / tau + y_soft = gumbels1.sigmoid() + return y_soft + + def subset_select(self, y_soft, topk, dim=-1): + top_values, top_inds = torch.topk(y_soft, k=topk, dim=dim) + top_ret = 1.0 - top_values.detach() + top_values + return top_inds.detach(), top_ret + + def group_selet(self, y_soft, topk, dim=-1): + # top_values: (num_tasks, num_layers, topk) + top_values, top_inds = torch.max( + y_soft.view(self.num_tasks, self.num_layers, -1, topk), dim=2 + ) + top_inds = top_inds * topk + torch.arange(topk, device=top_inds.device).unsqueeze(0).unsqueeze(1) + top_ret = 1.0 - top_values.detach() + top_values + return top_inds.detach(), top_ret + + def head_select(self, task_ids=None): + # gumbel_sample + self.head_samples = self.gumbel_sample(self.head_logits, tau=self.temp) + # head select + if self.select_strategy == "subset": + self.subset_heads, self.subset_weights = self.subset_select( + self.head_samples, + topk=self.num_heads, + ) + elif self.select_strategy == "group": + self.subset_heads, self.subset_weights = self.group_selet( + self.head_samples, + topk=self.num_heads, + ) + else: + raise ValueError("{} is not supported".format(self.select_strategy)) + + self.batch_subset = self.subset_heads[task_ids, :, :] + self.batch_weights = self.subset_weights[task_ids, :, :] + + def forward(self, layer_idx): + assert layer_idx is not None + batch_subset = self.batch_subset[:, layer_idx, :] + batch_weights = self.batch_weights[:, layer_idx, :] + return batch_subset, batch_weights diff --git a/examples/attention_head_selection/src/modules/head_selection_transformer_layer.py b/examples/attention_head_selection/src/modules/head_selection_transformer_layer.py new file mode 100644 index 0000000000..ea4030c761 --- /dev/null +++ b/examples/attention_head_selection/src/modules/head_selection_transformer_layer.py @@ -0,0 +1,93 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from fairseq.utils import safe_getattr + +from fairseq.modules import TransformerEncoderLayer, TransformerDecoderLayer +from ..modules.multihead_attention_selection import MultiheadAttentionSelection + + +class HeadSelectionTransformerEncoderLayer(TransformerEncoderLayer): + + def __init__(self, args, layer_idx, attn_head_selector=None): + super().__init__(args) + self.layer_idx = layer_idx + self.self_attn = self.build_self_attention_selection( + self.embed_dim, args, attn_head_selector + ) + + def build_self_attention_selection(self, embed_dim, args, attn_head_selector=None): + return MultiheadAttentionSelection( + embed_dim, + args.total_encoder_attention_heads, + args.encoder_attention_heads, + dropout=args.attention_dropout, + self_attention=True, + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + layer_idx=self.layer_idx, + attn_head_selector=attn_head_selector + ) + + +class HeadSelectionTransformerDecoderLayer(TransformerDecoderLayer): + + def __init__( + self, + args, + layer_idx, + self_attn_head_selector=None, + enc_attn_head_selector=None, + no_encoder_attn=False, + add_bias_kv=False, + add_zero_attn=False, + ): + self.layer_idx = layer_idx + super().__init__(args, no_encoder_attn, add_bias_kv, add_zero_attn) + if self_attn_head_selector is not None: + self.self_attn = self.build_self_attention_selection( + self.embed_dim, args, + self_attn_head_selector=self_attn_head_selector, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn + ) + if enc_attn_head_selector is not None: + self.encoder_attn = self.build_encoder_attention_selection( + self.embed_dim, args, + enc_attn_head_selector=enc_attn_head_selector + ) + + def build_self_attention_selection( + self, embed_dim, args, self_attn_head_selector=None, + add_bias_kv=False, add_zero_attn=False + ): + return MultiheadAttentionSelection( + embed_dim, + args.total_decoder_attention_heads, + args.decoder_attention_heads, + dropout=args.attention_dropout, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + self_attention=not safe_getattr(args, "cross_self_attention"), + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + layer_idx=self.layer_idx, + attn_head_selector=self_attn_head_selector, + ) + + def build_encoder_attention_selection(self, embed_dim, args, enc_attn_head_selector=None): + return MultiheadAttentionSelection( + embed_dim, + args.total_decoder_attention_heads, + args.decoder_attention_heads, + kdim=args.encoder_embed_dim, + vdim=args.encoder_embed_dim, + dropout=args.attention_dropout, + encoder_decoder_attention=True, + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + layer_idx=self.layer_idx, + attn_head_selector=enc_attn_head_selector, + ) diff --git a/examples/attention_head_selection/src/modules/multihead_attention_selection.py b/examples/attention_head_selection/src/modules/multihead_attention_selection.py new file mode 100644 index 0000000000..81fc54cae7 --- /dev/null +++ b/examples/attention_head_selection/src/modules/multihead_attention_selection.py @@ -0,0 +1,356 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, Optional, Tuple + +import torch +from fairseq import utils +from fairseq.modules.quant_noise import quant_noise +from torch import Tensor, nn +from torch.nn import Parameter + +from fairseq.modules.multihead_attention import MultiheadAttention +from ..modules.multihead_functional import multi_head_attention_forward + + +class MultiheadAttentionSelection(MultiheadAttention): + + def __init__( + self, + embed_dim, + total_num_heads, + num_heads, + kdim=None, + vdim=None, + dropout=0.0, + bias=True, + add_bias_kv=False, + add_zero_attn=False, + self_attention=False, + encoder_decoder_attention=False, + q_noise=0.0, + qn_block_size=8, + layer_idx=0, + attn_head_selector=None + ): + super().__init__( + embed_dim, + num_heads, + kdim=kdim, + vdim=vdim, + dropout=dropout, + bias=bias, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + self_attention=self_attention, + encoder_decoder_attention=encoder_decoder_attention, + q_noise=q_noise, + qn_block_size=qn_block_size, + ) + self.layer_idx = layer_idx + self.attn_head_selector = attn_head_selector + self.total_num_heads = total_num_heads + self.total_embed_dim = self.head_dim * total_num_heads + self.k_proj = quant_noise( + nn.Linear(self.kdim, self.total_embed_dim, bias=bias), q_noise, qn_block_size + ) + self.v_proj = quant_noise( + nn.Linear(self.vdim, self.total_embed_dim, bias=bias), q_noise, qn_block_size + ) + self.q_proj = quant_noise( + nn.Linear(embed_dim, self.total_embed_dim, bias=bias), q_noise, qn_block_size + ) + if add_bias_kv: + self.bias_k = Parameter(torch.Tensor(1, 1, self.total_embed_dim)) + self.bias_v = Parameter(torch.Tensor(1, 1, self.total_embed_dim)) + else: + self.bias_k = self.bias_v = None + self.reset_parameters() + + def forward( + self, + query, + key: Optional[Tensor], + value: Optional[Tensor], + key_padding_mask: Optional[Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + need_weights: bool = True, + static_kv: bool = False, + attn_mask: Optional[Tensor] = None, + before_softmax: bool = False, + need_head_weights: bool = False, + # subset_heads: Optional[Tensor] = None, + # subset_weights: Optional[Tensor] = None + ) -> Tuple[Tensor, Optional[Tensor]]: + if need_head_weights: + need_weights = True + + is_tpu = query.device.type == "xla" + + subset_heads, subset_weights = self.attn_head_selector(self.layer_idx) + + tgt_len, bsz, embed_dim = query.size() + src_len = tgt_len + assert list(query.size()) == [tgt_len, bsz, self.embed_dim] + if key is not None: + src_len, key_bsz, _ = key.size() + if not torch.jit.is_scripting(): + assert key_bsz == bsz + assert value is not None + assert src_len, bsz == value.shape[:2] + + if ( + not self.onnx_trace + and not is_tpu # don't use PyTorch version on TPUs + and incremental_state is None + and not static_kv + # A workaround for quantization to work. Otherwise JIT compilation + # treats bias in linear module as method. + and not torch.jit.is_scripting() + ): + assert key is not None and value is not None + return multi_head_attention_forward( + query, + key, + value, + self.embed_dim, + self.total_num_heads, + self.num_heads, + torch.empty([0]), + torch.cat((self.q_proj.bias, self.k_proj.bias, self.v_proj.bias)), + self.bias_k, + self.bias_v, + self.add_zero_attn, + self.dropout_module.p, + self.out_proj.weight, + self.out_proj.bias, + self.training or self.dropout_module.apply_during_inference, + key_padding_mask, + need_weights, + attn_mask, + use_separate_proj_weight=True, + q_proj_weight=self.q_proj.weight, + k_proj_weight=self.k_proj.weight, + v_proj_weight=self.v_proj.weight, + subset_heads=subset_heads, + subset_weights=subset_weights + ) + + if incremental_state is not None: + saved_state = self._get_input_buffer(incremental_state) + if saved_state is not None and "prev_key" in saved_state: + # previous time steps are cached - no need to recompute + # key and value if they are static + if static_kv: + assert self.encoder_decoder_attention and not self.self_attention + key = value = None + else: + saved_state = None + + if self.self_attention: + q = self.q_proj(query) + k = self.k_proj(query) + v = self.v_proj(query) + elif self.encoder_decoder_attention: + # encoder-decoder attention + q = self.q_proj(query) + if key is None: + assert value is None + k = v = None + else: + k = self.k_proj(key) + v = self.v_proj(key) + + else: + assert key is not None and value is not None + q = self.q_proj(query) + k = self.k_proj(key) + v = self.v_proj(value) + q *= self.scaling + + if self.bias_k is not None: + assert self.bias_v is not None + k = torch.cat([k, self.bias_k.repeat(1, bsz, 1)]) + v = torch.cat([v, self.bias_v.repeat(1, bsz, 1)]) + if attn_mask is not None: + attn_mask = torch.cat( + [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1 + ) + if key_padding_mask is not None: + key_padding_mask = torch.cat( + [ + key_padding_mask, + key_padding_mask.new_zeros(key_padding_mask.size(0), 1), + ], + dim=1, + ) + + q = ( + q.contiguous() + .view(tgt_len, bsz * self.total_num_heads, self.head_dim) + .transpose(0, 1) + ) + if k is not None: + k = ( + k.contiguous() + .view(-1, bsz * self.total_num_heads, self.head_dim) + .transpose(0, 1) + ) + if v is not None: + v = ( + v.contiguous() + .view(-1, bsz * self.total_num_heads, self.head_dim) + .transpose(0, 1) + ) + + if saved_state is not None: + # saved states are stored with shape (bsz, num_heads, seq_len, head_dim) + if "prev_key" in saved_state: + _prev_key = saved_state["prev_key"] + assert _prev_key is not None + prev_key = _prev_key.view(bsz * self.total_num_heads, -1, self.head_dim) + if static_kv: + k = prev_key + else: + assert k is not None + k = torch.cat([prev_key, k], dim=1) + src_len = k.size(1) + if "prev_value" in saved_state: + _prev_value = saved_state["prev_value"] + assert _prev_value is not None + prev_value = _prev_value.view(bsz * self.total_num_heads, -1, self.head_dim) + if static_kv: + v = prev_value + else: + assert v is not None + v = torch.cat([prev_value, v], dim=1) + prev_key_padding_mask: Optional[Tensor] = None + if "prev_key_padding_mask" in saved_state: + prev_key_padding_mask = saved_state["prev_key_padding_mask"] + assert k is not None and v is not None + key_padding_mask = MultiheadAttention._append_prev_key_padding_mask( + key_padding_mask=key_padding_mask, + prev_key_padding_mask=prev_key_padding_mask, + batch_size=bsz, + src_len=k.size(1), + static_kv=static_kv, + ) + + saved_state["prev_key"] = k.view(bsz, self.total_num_heads, -1, self.head_dim) + saved_state["prev_value"] = v.view(bsz, self.total_num_heads, -1, self.head_dim) + saved_state["prev_key_padding_mask"] = key_padding_mask + # In this branch incremental_state is never None + assert incremental_state is not None + incremental_state = self._set_input_buffer(incremental_state, saved_state) + assert k is not None + assert k.size(1) == src_len + + # This is part of a workaround to get around fork/join parallelism + # not supporting Optional types. + if key_padding_mask is not None and key_padding_mask.dim() == 0: + key_padding_mask = None + + if key_padding_mask is not None: + assert key_padding_mask.size(0) == bsz + assert key_padding_mask.size(1) == src_len + + if self.add_zero_attn: + assert v is not None + src_len += 1 + k = torch.cat([k, k.new_zeros((k.size(0), 1) + k.size()[2:])], dim=1) + v = torch.cat([v, v.new_zeros((v.size(0), 1) + v.size()[2:])], dim=1) + if attn_mask is not None: + attn_mask = torch.cat( + [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1 + ) + if key_padding_mask is not None: + key_padding_mask = torch.cat( + [ + key_padding_mask, + torch.zeros(key_padding_mask.size(0), 1).type_as( + key_padding_mask + ), + ], + dim=1, + ) + + attn_weights = torch.bmm(q, k.transpose(1, 2)) + attn_weights = self.apply_sparse_mask(attn_weights, tgt_len, src_len, bsz) + + assert list(attn_weights.size()) == [bsz * self.total_num_heads, tgt_len, src_len] + + if attn_mask is not None: + attn_mask = attn_mask.unsqueeze(0) + if self.onnx_trace: + attn_mask = attn_mask.repeat(attn_weights.size(0), 1, 1) + attn_weights += attn_mask + + if key_padding_mask is not None: + # don't attend to padding symbols + attn_weights = attn_weights.view(bsz, self.total_num_heads, tgt_len, src_len) + if not is_tpu: + attn_weights = attn_weights.masked_fill( + key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), + float("-inf"), + ) + else: + attn_weights = attn_weights.transpose(0, 2) + attn_weights = attn_weights.masked_fill(key_padding_mask, float("-inf")) + attn_weights = attn_weights.transpose(0, 2) + attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len) + + if before_softmax: + return attn_weights, v + + attn_weights_float = utils.softmax( + attn_weights, dim=-1, onnx_trace=self.onnx_trace + ) + attn_weights = attn_weights_float.type_as(attn_weights) + attn_probs = self.dropout_module(attn_weights) + + assert v is not None + + # evaluation + if subset_heads is not None and subset_heads.numel() == 1: + subset_heads = subset_heads.repeat(bsz) + subset_weights = subset_weights.repeat(bsz) + + if subset_heads is None: + attn = torch.bmm(attn_probs, v) + else: + # training with head selection + mixed_attn = torch.bmm(attn_probs, v).contiguous().view(bsz, self.total_num_heads, tgt_len, self.head_dim) + attn = torch.stack( + [mixed_attn[torch.arange(bsz), subset_heads[:, col], :, :] for col in range(subset_heads.size(1))], dim=1 + ) + attn = attn * subset_weights.unsqueeze(2).unsqueeze(3) + attn = attn.contiguous().view(bsz * self.num_heads, tgt_len, self.head_dim) + + assert list(attn.size()) == [bsz * self.num_heads, tgt_len, self.head_dim] + if self.onnx_trace and attn.size(1) == 1: + # when ONNX tracing a single decoder step (sequence length == 1) + # the transpose is a no-op copy before view, thus unnecessary + attn = attn.contiguous().view(tgt_len, bsz, embed_dim) + else: + attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) + attn = self.out_proj(attn) + attn_weights: Optional[Tensor] = None + if need_weights: + if subset_heads is None: + attn_weights = attn_weights_float.view( + bsz, self.num_heads, tgt_len, src_len + ).transpose(1, 0) + else: + mixed_attn_weights = attn_weights_float.view( + bsz, self.total_num_heads, tgt_len, src_len + ) + attn_weights = torch.stack( + [mixed_attn_weights[torch.arange(bsz), subset_heads[:, col], :, :] for col in range(subset_heads.size(1))], dim=1 + ).transpose(1, 0) + if not need_head_weights: + # average attention weights over heads + attn_weights = attn_weights.mean(dim=0) + + return attn, attn_weights diff --git a/examples/attention_head_selection/src/modules/multihead_functional.py b/examples/attention_head_selection/src/modules/multihead_functional.py new file mode 100644 index 0000000000..9fc85419d3 --- /dev/null +++ b/examples/attention_head_selection/src/modules/multihead_functional.py @@ -0,0 +1,279 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Optional, Tuple +import torch +from torch import Tensor +from torch.nn.functional import ( + linear, softmax, dropout, pad, + has_torch_function, + handle_torch_function, + _in_projection_packed, +) +import math +import warnings + + +def _scaled_dot_product_attention( + q: Tensor, + k: Tensor, + v: Tensor, + attn_mask: Optional[Tensor] = None, + dropout_p: float = 0.0, + bsz: int = 1, + subset_heads: Optional[Tensor] = None, + subset_weights: Optional[Tensor] = None, +) -> Tuple[Tensor, Tensor]: + B, Nt, E = q.shape + q = q / math.sqrt(E) + # B: bsz * total_num_heads + # (B, Nt, E) x (B, E, Ns) -> (B, Nt, Ns) + attn = torch.bmm(q, k.transpose(-2, -1)) + if attn_mask is not None: + attn += attn_mask + attn = softmax(attn, dim=-1) + if dropout_p > 0.0: + attn = dropout(attn, p=dropout_p) + if subset_heads is None: + # (B, Nt, Ns) x (B, Ns, E) -> (B, Nt, E) + output = torch.bmm(attn, v) + else: + mixed_output = torch.bmm(attn, v).contiguous().view(bsz, -1, Nt, E) + output = torch.stack( + [mixed_output[torch.arange(bsz), subset_heads[:, col], :, :] for col in range(subset_heads.size(1))], + dim=1 + ) + output = output * subset_weights.unsqueeze(2).unsqueeze(3) + output = output.contiguous().view(-1, Nt, E) + if subset_heads is not None: + _, Nt, Ns = attn.size() + mixed_attn = attn.view(bsz, -1, Nt, Ns) + attn = torch.stack( + [mixed_attn[torch.arange(bsz), subset_heads[:, col], :, :] for col in range(subset_heads.size(1))], dim=1 + ) + return output, attn + + +def _in_projection( + q: Tensor, + k: Tensor, + v: Tensor, + w_q: Tensor, + w_k: Tensor, + w_v: Tensor, + b_q: Optional[Tensor] = None, + b_k: Optional[Tensor] = None, + b_v: Optional[Tensor] = None, +) -> Tuple[Tensor, Tensor, Tensor]: + return linear(q, w_q, b_q), linear(k, w_k, b_k), linear(v, w_v, b_v) + + +def multi_head_attention_forward( + query: Tensor, + key: Tensor, + value: Tensor, + embed_dim_to_check: int, + total_num_heads: int, + num_heads: int, + in_proj_weight: Tensor, + in_proj_bias: Optional[Tensor], + bias_k: Optional[Tensor], + bias_v: Optional[Tensor], + add_zero_attn: bool, + dropout_p: float, + out_proj_weight: Tensor, + out_proj_bias: Optional[Tensor], + training: bool = True, + key_padding_mask: Optional[Tensor] = None, + need_weights: bool = True, + attn_mask: Optional[Tensor] = None, + use_separate_proj_weight: bool = False, + q_proj_weight: Optional[Tensor] = None, + k_proj_weight: Optional[Tensor] = None, + v_proj_weight: Optional[Tensor] = None, + static_k: Optional[Tensor] = None, + static_v: Optional[Tensor] = None, + subset_heads: Optional[Tensor] = None, + subset_weights: Optional[Tensor] = None, +): + tens_ops = (query, key, value, in_proj_weight, in_proj_bias, bias_k, bias_v, out_proj_weight, out_proj_bias) + if has_torch_function(tens_ops): + return handle_torch_function( + multi_head_attention_forward, + tens_ops, + query, + key, + value, + embed_dim_to_check, + total_num_heads, + num_heads, + in_proj_weight, + in_proj_bias, + bias_k, + bias_v, + add_zero_attn, + dropout_p, + out_proj_weight, + out_proj_bias, + training=training, + key_padding_mask=key_padding_mask, + need_weights=need_weights, + attn_mask=attn_mask, + use_separate_proj_weight=use_separate_proj_weight, + q_proj_weight=q_proj_weight, + k_proj_weight=k_proj_weight, + v_proj_weight=v_proj_weight, + static_k=static_k, + static_v=static_v, + subset_heads=subset_heads, + subset_weights=subset_weights + ) + + # set up shape vars + tgt_len, bsz, embed_dim = query.shape + src_len, _, _ = key.shape + assert embed_dim == embed_dim_to_check, \ + f"was expecting embedding dimension of {embed_dim_to_check}, but got {embed_dim}" + if isinstance(embed_dim, torch.Tensor): + # embed_dim can be a tensor when JIT tracing + head_dim = embed_dim.div(num_heads, rounding_mode='trunc') + else: + head_dim = embed_dim // num_heads + assert head_dim * num_heads == embed_dim, f"embed_dim {embed_dim} not divisible by num_heads {num_heads}" + + if use_separate_proj_weight: + # allow MHA to have different embedding dimensions when separate projection weights are used + assert key.shape[:2] == value.shape[:2], \ + f"key's sequence and batch dims {key.shape[:2]} do not match value's {value.shape[:2]}" + else: + assert key.shape == value.shape, f"key shape {key.shape} does not match value shape {value.shape}" + + # + # compute in-projection + # + if not use_separate_proj_weight: + q, k, v = _in_projection_packed(query, key, value, in_proj_weight, in_proj_bias) + else: + assert q_proj_weight is not None, "use_separate_proj_weight is True but q_proj_weight is None" + assert k_proj_weight is not None, "use_separate_proj_weight is True but k_proj_weight is None" + assert v_proj_weight is not None, "use_separate_proj_weight is True but v_proj_weight is None" + if in_proj_bias is None: + b_q = b_k = b_v = None + else: + b_q, b_k, b_v = in_proj_bias.chunk(3) + q, k, v = _in_projection(query, key, value, q_proj_weight, k_proj_weight, v_proj_weight, b_q, b_k, b_v) + + # prep attention mask + if attn_mask is not None: + if attn_mask.dtype == torch.uint8: + warnings.warn("Byte tensor for attn_mask in nn.MultiheadAttention is deprecated. Use bool tensor instead.") + attn_mask = attn_mask.to(torch.bool) + else: + assert attn_mask.is_floating_point() or attn_mask.dtype == torch.bool, \ + f"Only float, byte, and bool types are supported for attn_mask, not {attn_mask.dtype}" + # ensure attn_mask's dim is 3 + if attn_mask.dim() == 2: + correct_2d_size = (tgt_len, src_len) + if attn_mask.shape != correct_2d_size: + raise RuntimeError(f"The shape of the 2D attn_mask is {attn_mask.shape}, but should be {correct_2d_size}.") + attn_mask = attn_mask.unsqueeze(0) + elif attn_mask.dim() == 3: + correct_3d_size = (bsz * total_num_heads, tgt_len, src_len) + if attn_mask.shape != correct_3d_size: + raise RuntimeError(f"The shape of the 3D attn_mask is {attn_mask.shape}, but should be {correct_3d_size}.") + else: + raise RuntimeError(f"attn_mask's dimension {attn_mask.dim()} is not supported") + + # prep key padding mask + if key_padding_mask is not None and key_padding_mask.dtype == torch.uint8: + warnings.warn("Byte tensor for key_padding_mask in nn.MultiheadAttention is deprecated. Use bool tensor instead.") + key_padding_mask = key_padding_mask.to(torch.bool) + + # add bias along batch dimension (currently second) + if bias_k is not None and bias_v is not None: + assert static_k is None, "bias cannot be added to static key." + assert static_v is None, "bias cannot be added to static value." + k = torch.cat([k, bias_k.repeat(1, bsz, 1)]) + v = torch.cat([v, bias_v.repeat(1, bsz, 1)]) + if attn_mask is not None: + attn_mask = pad(attn_mask, (0, 1)) + if key_padding_mask is not None: + key_padding_mask = pad(key_padding_mask, (0, 1)) + else: + assert bias_k is None + assert bias_v is None + + # + # reshape q, k, v for multihead attention and make em batch first + # + q = q.contiguous().view(tgt_len, bsz * total_num_heads, head_dim).transpose(0, 1) + if static_k is None: + k = k.contiguous().view(k.shape[0], bsz * total_num_heads, head_dim).transpose(0, 1) + else: + # TODO finish disentangling control flow so we don't do in-projections when statics are passed + assert static_k.size(0) == bsz * total_num_heads, \ + f"expecting static_k.size(0) of {bsz * total_num_heads}, but got {static_k.size(0)}" + assert static_k.size(2) == head_dim, \ + f"expecting static_k.size(2) of {head_dim}, but got {static_k.size(2)}" + k = static_k + if static_v is None: + v = v.contiguous().view(v.shape[0], bsz * total_num_heads, head_dim).transpose(0, 1) + else: + # TODO finish disentangling control flow so we don't do in-projections when statics are passed + assert static_v.size(0) == bsz * total_num_heads, \ + f"expecting static_v.size(0) of {bsz * total_num_heads}, but got {static_v.size(0)}" + assert static_v.size(2) == head_dim, \ + f"expecting static_v.size(2) of {head_dim}, but got {static_v.size(2)}" + v = static_v + + # add zero attention along batch dimension (now first) + if add_zero_attn: + zero_attn_shape = (bsz * total_num_heads, 1, head_dim) + k = torch.cat([k, torch.zeros(zero_attn_shape, dtype=k.dtype, device=k.device)], dim=1) + v = torch.cat([v, torch.zeros(zero_attn_shape, dtype=v.dtype, device=v.device)], dim=1) + if attn_mask is not None: + attn_mask = pad(attn_mask, (0, 1)) + if key_padding_mask is not None: + key_padding_mask = pad(key_padding_mask, (0, 1)) + + # update source sequence length after adjustments + src_len = k.size(1) + + # merge key padding and attention masks + if key_padding_mask is not None: + assert key_padding_mask.shape == (bsz, src_len), \ + f"expecting key_padding_mask shape of {(bsz, src_len)}, but got {key_padding_mask.shape}" + key_padding_mask = key_padding_mask.view(bsz, 1, 1, src_len). \ + expand(-1, total_num_heads, -1, -1).reshape(bsz * total_num_heads, 1, src_len) + if attn_mask is None: + attn_mask = key_padding_mask + elif attn_mask.dtype == torch.bool: + attn_mask = attn_mask.logical_or(key_padding_mask) + else: + attn_mask = attn_mask.masked_fill(key_padding_mask, float("-inf")) + + # convert mask to float + if attn_mask is not None and attn_mask.dtype == torch.bool: + new_attn_mask = torch.zeros_like(attn_mask, dtype=torch.float) + new_attn_mask.masked_fill_(attn_mask, float("-inf")) + attn_mask = new_attn_mask + + # adjust dropout probability + if not training: + dropout_p = 0.0 + + # + # (deep breath) calculate attention and out projection + # + attn_output, attn_output_weights = _scaled_dot_product_attention(q, k, v, attn_mask, dropout_p, bsz, subset_heads, subset_weights) + attn_output = attn_output.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim) + attn_output = linear(attn_output, out_proj_weight, out_proj_bias) + + if need_weights: + # average attention weights over heads + attn_output_weights = attn_output_weights.view(bsz, num_heads, tgt_len, src_len) + return attn_output, attn_output_weights.sum(dim=1) / num_heads + else: + return attn_output, None diff --git a/examples/attention_head_selection/src/speech_to_text_head_selection.py b/examples/attention_head_selection/src/speech_to_text_head_selection.py new file mode 100644 index 0000000000..f9dc68f85e --- /dev/null +++ b/examples/attention_head_selection/src/speech_to_text_head_selection.py @@ -0,0 +1,180 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from fairseq.optim.amp_optimizer import AMPOptimizer +from fairseq.tasks import register_task +from fairseq.tasks.speech_to_text import SpeechToTextTask + +from .data.speech_to_text_dataset_with_domain import SpeechToTextDatasetCreatorWithDomain +from .loss.attention_head_selection import HeadSelectionLoss + + +@register_task("speech_to_text_head_selection") +class SpeechToTextHeadSelectionTask(SpeechToTextTask): + + @classmethod + def add_args(cls, parser): + SpeechToTextTask.add_args(parser) + parser.add_argument( + "--task-type", + type=str, + default="lang", + help="task type for head selection, lang or domain" + ) + parser.add_argument( + "--kl-weight", + type=float, + default=0.0, + help="the weight of KL loss" + ) + + def __init__(self, args, tgt_dict): + super().__init__(args, tgt_dict) + self.task_type = args.task_type + assert self.task_type in ["lang", "domain"], "invalid task_type: {}, should be either lang or domain".format(self.task_type) + self.map_task_to_id(args.train_subset) + self.encoder_head_prior = float(args.decoder_attention_heads) / args.total_decoder_attention_heads + self.decoder_head_prior = float(args.encoder_attention_heads) / args.total_encoder_attention_heads + self.kl_loss = HeadSelectionLoss(args) + + def map_task_to_id(self, train_subset): + src_lang_set, tgt_lang_set, domain_set = set(), set(), set() + for split in train_subset.split(","): + seq = split.split("_") + assert len(seq) == 4, "subset {} should be in the format of train_src_tgt_domain".format(split) + _, src_lang, tgt_lang, domain = seq + src_lang_set.add(src_lang) + tgt_lang_set.add(tgt_lang) + domain_set.add(domain) + src_langs = sorted(src_lang_set) + tgt_langs = sorted(tgt_lang_set) + domains = sorted(domain_set) + self.src_lang_map = {src_lang: i for (i, src_lang) in enumerate(src_langs)} + self.tgt_lang_map = {tgt_lang: i for (i, tgt_lang) in enumerate(tgt_langs)} + self.domain_map = {domain: i for (i, domain) in enumerate(domains)} + if self.task_type == "lang": + self.encoder_tasks = len(self.src_lang_map) + self.decoder_tasks = len(self.tgt_lang_map) + elif self.task_type == "domain": + self.encoder_tasks = len(self.domain_map) + self.decoder_tasks = len(self.domain_map) + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + is_train_split = split.startswith("train") + pre_tokenizer = self.build_tokenizer(self.args) + bpe_tokenizer = self.build_bpe(self.args) + self.datasets[split] = SpeechToTextDatasetCreatorWithDomain.from_tsv( + self.args.data, + self.data_cfg, + split, + self.tgt_dict, + pre_tokenizer, + bpe_tokenizer, + is_train_split=is_train_split, + epoch=epoch, + seed=self.args.seed, + speaker_to_id=self.speaker_to_id, + src_lang_map=self.src_lang_map, + tgt_lang_map=self.tgt_lang_map, + domain_map=self.domain_map + ) + + def build_model(self, args): + args.encoder_tasks = self.encoder_tasks + args.decoder_tasks = self.decoder_tasks + return super(SpeechToTextHeadSelectionTask, self).build_model(args) + + def get_sample_sizes(self, sample, task_ids, num_tasks): + """ + task_ids: (bsz,) + get sample sizes for each task + """ + bsz = task_ids.size(0) + mat = torch.zeros((num_tasks, bsz), device=task_ids.device) + mat[task_ids, torch.arange(bsz)] = 1.0 + ntokens = torch.sum(sample['target'] != 1, dim=-1) + sample_sizes = torch.matmul(mat, ntokens.float()) + return sample_sizes + + def train_step( + self, sample, model, criterion, optimizer, update_num, ignore_grad=False + ): + model.train() + model.set_num_updates(update_num) + # task ids + if self.task_type == "lang": + encoder_task_ids = sample["src_lang_ids"] + decoder_task_ids = sample["tgt_lang_ids"] + elif self.task_type == "domain": + encoder_task_ids = sample["domain_ids"] + decoder_task_ids = sample["domain_ids"] + model.encoder.set_task_ids(encoder_task_ids) + model.decoder.set_task_ids(decoder_task_ids) + + with torch.autograd.profiler.record_function("forward"): + with torch.cuda.amp.autocast(enabled=(isinstance(optimizer, AMPOptimizer))): + loss, sample_size, logging_output = criterion(model, sample) + # KL loss + if self.args.encoder_attn_head_select: + sample_sizes = self.get_sample_sizes(sample, encoder_task_ids, self.encoder_tasks) + loss += self.kl_loss( + model.encoder.attn_head_selector.head_samples, + sample_sizes, + self.encoder_head_prior + ) + if self.args.decoder_self_attn_head_select: + sample_sizes = self.get_sample_sizes(sample, decoder_task_ids, self.decoder_tasks) + loss += self.kl_loss( + model.decoder.self_attn_head_selector.head_samples, + sample_sizes, + self.decoder_head_prior + ) + if self.args.dec_enc_attn_head_select: + sample_sizes = self.get_sample_sizes(sample, decoder_task_ids, self.decoder_tasks) + loss += self.kl_loss( + model.decoder.enc_attn_head_selector.head_sampes, + sample_sizes, + self.decoder_head_prior + ) + + if ignore_grad: + loss *= 0 + with torch.autograd.profiler.record_function("backward"): + optimizer.backward(loss) + return loss, sample_size, logging_output + + def valid_step(self, sample, model, criterion): + model.eval() + # task ids + if self.task_type == "lang": + encoder_task_ids = sample["src_lang_ids"] + decoder_task_ids = sample["tgt_lang_ids"] + elif self.task_type == "domain": + encoder_task_ids = sample["domain_ids"] + decoder_task_ids = sample["domain_ids"] + model.encoder.set_task_ids(encoder_task_ids) + model.decoder.set_task_ids(decoder_task_ids) + with torch.no_grad(): + loss, sample_size, logging_output = criterion(model, sample) + return loss, sample_size, logging_output + + def inference_step( + self, generator, models, sample, prefix_tokens=None, constraints=None + ): + with torch.no_grad(): + # task ids + if self.task_type == "lang": + encoder_task_ids = sample["src_lang_ids"][:1] + decoder_task_ids = sample["tgt_lang_ids"][:1] + elif self.task_type == "domain": + encoder_task_ids = sample["domain_ids"][:1] + decoder_task_ids = sample["domain_ids"][:1] + for model in models: + model.encoder.set_task_ids(encoder_task_ids) + model.decoder.set_task_ids(decoder_task_ids) + return generator.generate( + models, sample, prefix_tokens=prefix_tokens, constraints=constraints + ) From a075481d0de112aee2d79f40ac3ab0eca37214d8 Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Tue, 18 Jan 2022 19:28:52 -0800 Subject: [PATCH 548/774] Decode using EMA model in IPL recipe Summary: Add option to use the EMA model for decoding in transducer IPL recipe by passing --ipl-decode-ema. Note EMA should be enabled as in the diff D24238379 (https://github.com/pytorch/fairseq/commit/8feccf94412424a4683b01090de36fa77cb4951d) using options --store-ema --ema-start-update and --ema-decay. Reviewed By: cruvadom Differential Revision: D31983366 fbshipit-source-id: 2bf63b3f7d1b5fa8804b3a7e9bfab71a463ca957 --- fairseq/checkpoint_utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index a5ef37d435..851aa0a7aa 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -842,6 +842,11 @@ def verify_checkpoint_directory(save_dir: str) -> None: os.remove(temp_file_path) +def save_ema_as_checkpoint(src_path, dst_path): + state = load_ema_from_checkpoint(src_path) + torch_persistent_save(state, dst_path) + + def load_ema_from_checkpoint(fpath): """Loads exponential moving averaged (EMA) checkpoint from input and returns a model with ema weights. From a59cea594491a636e53dc0ac2fa8ee950a5442ab Mon Sep 17 00:00:00 2001 From: Hongyu Gong <hygong@fb.com> Date: Tue, 18 Jan 2022 21:14:14 -0800 Subject: [PATCH 549/774] attn head selection Summary: Add scripts for multihead attention selection in multilingual and multil-domain training from the following paper: "Pay Better Attention to Attention: Head Selection in Multilingual and Multi-Domain Sequence Modeling", NeurIPS 2021. Reviewed By: yuntang Differential Revision: D31802221 fbshipit-source-id: 8c69b89bda29e6857bd3af02979c07e1b5cf49f1 --- examples/attention_head_selection/README.md | 13 +++++-------- .../src/data/speech_to_text_dataset_with_domain.py | 13 +++++++------ .../src/loss/attention_head_selection.py | 2 -- .../src/models/head_selection_s2t_transformer.py | 14 ++------------ .../modules/head_selection_transformer_layer.py | 1 - .../src/modules/multihead_attention_selection.py | 1 - .../src/modules/multihead_functional.py | 1 - .../src/speech_to_text_head_selection.py | 4 ++-- 8 files changed, 16 insertions(+), 33 deletions(-) diff --git a/examples/attention_head_selection/README.md b/examples/attention_head_selection/README.md index d55b82b07b..2434f1fb21 100644 --- a/examples/attention_head_selection/README.md +++ b/examples/attention_head_selection/README.md @@ -152,13 +152,10 @@ fairseq-generate ${data_dir} \ ## Citation ```bibtex -@article{gong2021attn, - title={Pay Better Attention to Attention: Head Selection in Multilingual and Multi-Domain Sequence Modeling}, - author={Hongyu Gong and - Yun Tang and - Juan Miguel Pino and - Xian Li}, - journal={arXiv preprint arXiv:2106.10840}, - year={2021} +@article{gong2021pay, + title={Pay Better Attention to Attention: Head Selection in Multilingual and Multi-Domain Sequence Modeling}, + author={Gong, Hongyu and Tang, Yun and Pino, Juan and Li, Xian}, + journal={arXiv preprint arXiv:2106.10840}, + year={2021} } ''' diff --git a/examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py b/examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py index e80915e60c..1f1823a7ac 100644 --- a/examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py +++ b/examples/attention_head_selection/src/data/speech_to_text_dataset_with_domain.py @@ -12,6 +12,7 @@ from fairseq.data import ( ConcatDataset, Dictionary, + FairseqDataset, ResamplingDataset ) from fairseq.data.audio.data_cfg import S2TDataConfig @@ -190,9 +191,9 @@ def _from_tsv( bpe_tokenizer, n_frames_per_step, speaker_to_id, - src_lang_map, - tgt_lang_map, - domain_map + src_lang_map: Dict[str, int], + tgt_lang_map: Dict[str, int], + domain_map: Dict[str, int] ) -> SpeechToTextDatasetItemWithDomain: samples = cls._load_samples_from_tsv( root, split, src_lang_map, @@ -215,11 +216,11 @@ def from_tsv( is_train_split: bool, epoch: int, seed: int, - n_frames_per_step: int, - speaker_to_id, src_lang_map: Dict[str, int], tgt_lang_map: Dict[str, int], - domain_map: Dict[str, int] + domain_map: Dict[str, int], + n_frames_per_step: int = 1, + speaker_to_id=None ) -> SpeechToTextDatasetWithDomain: datasets = [ cls._from_tsv( diff --git a/examples/attention_head_selection/src/loss/attention_head_selection.py b/examples/attention_head_selection/src/loss/attention_head_selection.py index 296441b0a3..4ba33954d0 100644 --- a/examples/attention_head_selection/src/loss/attention_head_selection.py +++ b/examples/attention_head_selection/src/loss/attention_head_selection.py @@ -1,5 +1,3 @@ - - # Copyright (c) Facebook, Inc. and its affiliates. # # This source code is licensed under the MIT license found in the diff --git a/examples/attention_head_selection/src/models/head_selection_s2t_transformer.py b/examples/attention_head_selection/src/models/head_selection_s2t_transformer.py index 8938fffd82..2c7ed89e89 100644 --- a/examples/attention_head_selection/src/models/head_selection_s2t_transformer.py +++ b/examples/attention_head_selection/src/models/head_selection_s2t_transformer.py @@ -50,19 +50,14 @@ def add_args(parser): type=int, help="total number of encoder attention heads" ) - # parser.add_argument( - # "--encoder-tasks", - # type=int, - # help="the number of encoder tasks (input languages or input domains)" - # ) - # decoder self attention + # decoder self attention selection parser.add_argument( "--decoder-self-attn-head-select", action="store_true", default=False, help="decoder self-attention head selection" ) - # decoder-encoder attention + # decoder-encoder attention selection parser.add_argument( "--dec-enc-attn-head-select", action="store_true", @@ -74,11 +69,6 @@ def add_args(parser): type=int, help="total number of decoder attention heads" ) - # parser.add_argument( - # "--decoder-tasks", - # type=int, - # help="the number of decoder tasks (output languages or output domains)" - # ) # selection strategy parser.add_argument( "--attn-head-select-strategy", diff --git a/examples/attention_head_selection/src/modules/head_selection_transformer_layer.py b/examples/attention_head_selection/src/modules/head_selection_transformer_layer.py index ea4030c761..c792143503 100644 --- a/examples/attention_head_selection/src/modules/head_selection_transformer_layer.py +++ b/examples/attention_head_selection/src/modules/head_selection_transformer_layer.py @@ -4,7 +4,6 @@ # LICENSE file in the root directory of this source tree. from fairseq.utils import safe_getattr - from fairseq.modules import TransformerEncoderLayer, TransformerDecoderLayer from ..modules.multihead_attention_selection import MultiheadAttentionSelection diff --git a/examples/attention_head_selection/src/modules/multihead_attention_selection.py b/examples/attention_head_selection/src/modules/multihead_attention_selection.py index 81fc54cae7..566ad822ac 100644 --- a/examples/attention_head_selection/src/modules/multihead_attention_selection.py +++ b/examples/attention_head_selection/src/modules/multihead_attention_selection.py @@ -4,7 +4,6 @@ # LICENSE file in the root directory of this source tree. from typing import Dict, Optional, Tuple - import torch from fairseq import utils from fairseq.modules.quant_noise import quant_noise diff --git a/examples/attention_head_selection/src/modules/multihead_functional.py b/examples/attention_head_selection/src/modules/multihead_functional.py index 9fc85419d3..d5edc777e3 100644 --- a/examples/attention_head_selection/src/modules/multihead_functional.py +++ b/examples/attention_head_selection/src/modules/multihead_functional.py @@ -142,7 +142,6 @@ def multi_head_attention_forward( else: head_dim = embed_dim // num_heads assert head_dim * num_heads == embed_dim, f"embed_dim {embed_dim} not divisible by num_heads {num_heads}" - if use_separate_proj_weight: # allow MHA to have different embedding dimensions when separate projection weights are used assert key.shape[:2] == value.shape[:2], \ diff --git a/examples/attention_head_selection/src/speech_to_text_head_selection.py b/examples/attention_head_selection/src/speech_to_text_head_selection.py index f9dc68f85e..6e0ce11d63 100644 --- a/examples/attention_head_selection/src/speech_to_text_head_selection.py +++ b/examples/attention_head_selection/src/speech_to_text_head_selection.py @@ -76,10 +76,10 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): is_train_split=is_train_split, epoch=epoch, seed=self.args.seed, - speaker_to_id=self.speaker_to_id, src_lang_map=self.src_lang_map, tgt_lang_map=self.tgt_lang_map, - domain_map=self.domain_map + domain_map=self.domain_map, + speaker_to_id=self.speaker_to_id ) def build_model(self, args): From 995c204337d16a6146a433cee360e5a5bfbc9a6f Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 20 Jan 2022 00:01:14 -0800 Subject: [PATCH 550/774] Data2vec prelim (#2929) Summary: Preliminaries for data2vec release, include some minor improvements and bug fixes Most important change is that we now default to raising an exception when fields in config do not have a corresponding field in the model dataclass Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2929 Reviewed By: wnhsu Differential Revision: D33649708 Pulled By: alexeib fbshipit-source-id: 629bdb4c361550740b451c570c2005bb956c6fcb --- .gitignore | 5 ++ .../tasks/discriminative_reranking_task.py | 35 ++++++++++---- examples/laser/laser_src/laser_task.py | 2 +- .../commonsense_qa/commonsense_qa_task.py | 2 +- .../new/conf/hydra/sweeper/ax.yaml | 7 ++- .../speech_recognition/new/conf/infer.yaml | 4 +- examples/speech_recognition/new/infer.py | 2 + .../translation_moe_src/translation_moe.py | 2 +- .../unsupervised/tasks/unpaired_audio_text.py | 2 +- .../wav2vec/unsupervised/w2vu_generate.py | 2 +- fairseq/checkpoint_utils.py | 17 +++++-- fairseq/criterions/ctc.py | 2 +- fairseq/criterions/model_criterion.py | 21 ++++++++- fairseq/data/data_utils.py | 10 +++- fairseq/dataclass/configs.py | 6 +++ fairseq/dataclass/utils.py | 2 +- fairseq/models/__init__.py | 5 +- fairseq/models/ema/ema.py | 39 +++++++++------ fairseq/models/hubert/hubert_asr.py | 2 +- fairseq/models/wav2vec/wav2vec2_asr.py | 2 +- fairseq/modules/__init__.py | 4 ++ fairseq/modules/fp32_batch_norm.py | 44 +++++++++++++++++ fairseq/modules/fp32_instance_norm.py | 35 ++++++++++++++ fairseq/modules/transformer_layer.py | 10 +++- fairseq/nan_detector.py | 2 +- fairseq/tasks/audio_finetuning.py | 4 +- fairseq/tasks/audio_pretraining.py | 4 +- fairseq/tasks/fairseq_task.py | 8 ++-- fairseq/tasks/language_modeling.py | 4 +- .../tasks/multilingual_language_modeling.py | 4 +- fairseq/tasks/multilingual_translation.py | 4 +- fairseq/tasks/online_backtranslation.py | 4 +- fairseq/tasks/semisupervised_translation.py | 4 +- fairseq/tasks/sentence_prediction.py | 4 +- fairseq/tasks/sentence_ranking.py | 4 +- fairseq/tasks/speech_to_speech.py | 4 +- fairseq/tasks/speech_to_text.py | 4 +- fairseq/tasks/text_to_speech.py | 4 +- fairseq/tasks/translation.py | 4 +- .../tasks/translation_multi_simple_epoch.py | 4 +- fairseq/trainer.py | 47 ++++++++++++++++--- tests/test_checkpoint_utils.py | 9 ++-- tests/test_multihead_attention.py | 7 ++- tests/utils.py | 2 +- 44 files changed, 296 insertions(+), 97 deletions(-) create mode 100644 fairseq/modules/fp32_batch_norm.py create mode 100644 fairseq/modules/fp32_instance_norm.py diff --git a/.gitignore b/.gitignore index 4112804793..4be13638de 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,8 @@ experimental/* # Weights and Biases logs wandb/ + +# Hydra artifacts +nohup.out +multirun +outputs diff --git a/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py b/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py index 0e7fbba888..223f8d4294 100644 --- a/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py +++ b/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py @@ -161,7 +161,9 @@ def make_dataset(type, dictionary, data_split, combine): split_path = get_path(type, data_split) dataset = data_utils.load_indexed_dataset( - split_path, dictionary, combine=combine, + split_path, + dictionary, + combine=combine, ) return dataset @@ -241,7 +243,8 @@ def load_split(data_split, metric): "id": IdDataset(), "net_input": { "src_tokens": RightPadDataset( - src_tokens, pad_idx=self.source_dictionary.pad(), + src_tokens, + pad_idx=self.source_dictionary.pad(), ), "src_lengths": src_lengths, }, @@ -250,11 +253,16 @@ def load_split(data_split, metric): "target": label, } - dataset = NestedDictionaryDataset(dataset, sizes=[src_tokens.sizes],) + dataset = NestedDictionaryDataset( + dataset, + sizes=[src_tokens.sizes], + ) - assert len(dataset) % self.cfg.mt_beam == 0, ( - "dataset size (%d) is not a multiple of beam size (%d)" - % (len(dataset), self.cfg.mt_beam) + assert ( + len(dataset) % self.cfg.mt_beam == 0 + ), "dataset size (%d) is not a multiple of beam size (%d)" % ( + len(dataset), + self.cfg.mt_beam, ) # no need to shuffle valid/test sets @@ -270,7 +278,10 @@ def load_split(data_split, metric): start_idx, (self.cfg.mt_beam, 1) ).transpose().reshape(-1) - dataset = SortDataset(dataset, sort_order=[shuffle],) + dataset = SortDataset( + dataset, + sort_order=[shuffle], + ) logger.info(f"Loaded {split} with #samples: {len(dataset)}") @@ -313,7 +324,8 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): "id": IdDataset(), "net_input": { "src_tokens": RightPadDataset( - src_tokens, pad_idx=self.source_dictionary.pad(), + src_tokens, + pad_idx=self.source_dictionary.pad(), ), "src_lengths": src_lengths, }, @@ -321,9 +333,12 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): "ntokens": NumelDataset(src_tokens, reduce=True), } - return NestedDictionaryDataset(dataset, sizes=[src_tokens.sizes],) + return NestedDictionaryDataset( + dataset, + sizes=[src_tokens.sizes], + ) - def build_model(self, cfg: FairseqDataclass): + def build_model(self, cfg: FairseqDataclass, from_checkpoint: bool = False): return super().build_model(cfg) def build_generator(self, args): diff --git a/examples/laser/laser_src/laser_task.py b/examples/laser/laser_src/laser_task.py index 72d069fe8e..9bf2d7ad81 100644 --- a/examples/laser/laser_src/laser_task.py +++ b/examples/laser/laser_src/laser_task.py @@ -112,7 +112,7 @@ def setup_task(cls, args, **kwargs): return cls(args, config, src_dictionary, tgt_dictionary, num_tasks) # Experimental overriding for backtranslation - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): model = models.build_model(args, self) return model diff --git a/examples/roberta/commonsense_qa/commonsense_qa_task.py b/examples/roberta/commonsense_qa/commonsense_qa_task.py index 216093f708..7d8f8131b3 100644 --- a/examples/roberta/commonsense_qa/commonsense_qa_task.py +++ b/examples/roberta/commonsense_qa/commonsense_qa_task.py @@ -169,7 +169,7 @@ def binarize(s, append_bos=False): self.datasets[split] = dataset return self.datasets[split] - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): from fairseq import models model = models.build_model(args, self) diff --git a/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml b/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml index fbeff17ca6..9a6935b93e 100644 --- a/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml +++ b/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml @@ -5,8 +5,8 @@ ax_config: max_trials: 128 early_stop: minimize: true - max_epochs_without_improvement: 32 - epsilon: 1.0e-05 + max_epochs_without_improvement: 10 + epsilon: 0.025 experiment: name: ${dataset.gen_subset} objective_name: wer @@ -24,3 +24,6 @@ ax_config: decoding.wordscore: type: range bounds: [-5.0, 5.0] + decoding.silweight: + type: range + bounds: [ -8.0, 0.0 ] diff --git a/examples/speech_recognition/new/conf/infer.yaml b/examples/speech_recognition/new/conf/infer.yaml index f176228082..21dd19fadd 100644 --- a/examples/speech_recognition/new/conf/infer.yaml +++ b/examples/speech_recognition/new/conf/infer.yaml @@ -8,7 +8,7 @@ hydra: run: dir: ${common_eval.results_path}/${dataset.gen_subset} sweep: - dir: ${common_eval.results_path} + dir: /checkpoint/${env:USER}/${env:PREFIX}/${common_eval.results_path} subdir: ${dataset.gen_subset} common_eval: results_path: null @@ -16,7 +16,7 @@ common_eval: post_process: letter quiet: true dataset: - max_tokens: 1000000 + max_tokens: 3000000 gen_subset: test distributed_training: distributed_world_size: 1 diff --git a/examples/speech_recognition/new/infer.py b/examples/speech_recognition/new/infer.py index 3fb67151e0..d8d87f20bb 100644 --- a/examples/speech_recognition/new/infer.py +++ b/examples/speech_recognition/new/infer.py @@ -378,6 +378,8 @@ def main(cfg: InferConfig) -> float: if not cfg.common.cpu and not torch.cuda.is_available(): raise ValueError("CUDA not found; set `cpu=True` to run without CUDA") + logger.info(cfg.common_eval.path) + with InferenceProcessor(cfg) as processor: for sample in processor: processor.process_sample(sample) diff --git a/examples/translation_moe/translation_moe_src/translation_moe.py b/examples/translation_moe/translation_moe_src/translation_moe.py index 7f28c32dd6..1ee9d1b727 100644 --- a/examples/translation_moe/translation_moe_src/translation_moe.py +++ b/examples/translation_moe/translation_moe_src/translation_moe.py @@ -101,7 +101,7 @@ def __init__(self, cfg: TranslationMoEConfig, src_dict, tgt_dict): super().__init__(cfg, src_dict, tgt_dict) - def build_model(self, cfg): + def build_model(self, cfg, from_checkpoint=False): from fairseq import models model = models.build_model(cfg, self) diff --git a/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py index 5f292528f8..1e2dc55c23 100644 --- a/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py +++ b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py @@ -441,7 +441,7 @@ def reduce_metrics(self, logging_outputs, criterion): / meters["nsentences"].sum, ) - def build_model(self, cfg: FairseqDataclass): + def build_model(self, cfg: FairseqDataclass, from_checkpoint=False): model = super().build_model(cfg) return model diff --git a/examples/wav2vec/unsupervised/w2vu_generate.py b/examples/wav2vec/unsupervised/w2vu_generate.py index 6177239dc7..fca0c96f32 100644 --- a/examples/wav2vec/unsupervised/w2vu_generate.py +++ b/examples/wav2vec/unsupervised/w2vu_generate.py @@ -645,7 +645,7 @@ def main(cfg: UnsupGenerateConfig, model=None): lm_ppl = max(cfg.min_lm_ppl, lm_ppl) - if not cfg.unsupervised_tuning == 0: + if not cfg.unsupervised_tuning: weighted_score = wer else: weighted_score = math.log(lm_ppl) * (vt_diff or 1.0) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 851aa0a7aa..f93bf6622e 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -6,6 +6,7 @@ import ast import collections import contextlib +import inspect import logging import os import re @@ -111,7 +112,7 @@ def is_better(a, b): checkpoints = [ os.path.join(cfg.save_dir, fn) for fn, cond in checkpoint_conds.items() if cond ] - if len(checkpoints) > 0: + if len(checkpoints) > 0 and trainer.should_save_checkpoint_on_current_rank: trainer.save_checkpoint(checkpoints[0], extra_state) for cp in checkpoints[1:]: if cfg.write_checkpoints_asynchronously: @@ -215,7 +216,9 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): cfg.save_dir, "checkpoint_last{}.pt".format(suffix) ) first_launch = not PathManager.exists(checkpoint_path) - if cfg.finetune_from_model is not None and first_launch: + if first_launch and cfg.get("continue_once", None) is not None: + checkpoint_path = cfg.continue_once + elif cfg.finetune_from_model is not None and first_launch: # if there is no last checkpoint to restore, start the finetune from pretrained model # else just use usual logic to load checkpoint, e.g. restart from last checkpoint and etc. if PathManager.exists(cfg.finetune_from_model): @@ -460,7 +463,13 @@ def load_model_ensemble_and_task( ) else: # model parallel checkpoint or unsharded checkpoint - model = task.build_model(cfg.model) + # support old external tasks + + argspec = inspect.getfullargspec(task.build_model) + if "from_checkpoint" in argspec.args: + model = task.build_model(cfg.model, from_checkpoint=True) + else: + model = task.build_model(cfg.model) if ( "optimizer_history" in state and len(state["optimizer_history"]) > 0 @@ -605,7 +614,7 @@ def _upgrade_state_dict(state): # use stateful training data iterator if "train_iterator" not in state["extra_state"]: state["extra_state"]["train_iterator"] = { - "epoch": state["extra_state"]["epoch"], + "epoch": state["extra_state"].get("epoch", 0), "iterations_in_epoch": state["extra_state"].get("batch_offset", 0), } diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index 10e3618382..e966e47cf2 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -83,7 +83,7 @@ def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): cfg.wer_word_score, ) = eval(cfg.wer_args) - if cfg.wer_kenlm_model is not None: + if cfg.wer_kenlm_model is not None and cfg.wer_kenlm_model != "": from examples.speech_recognition.w2l_decoder import W2lKenLMDecoder dec_args = Namespace() diff --git a/fairseq/criterions/model_criterion.py b/fairseq/criterions/model_criterion.py index 30350f13b1..f9a810d835 100644 --- a/fairseq/criterions/model_criterion.py +++ b/fairseq/criterions/model_criterion.py @@ -7,6 +7,8 @@ from dataclasses import dataclass, field from typing import Dict, List +import torch + from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass @@ -49,7 +51,6 @@ def __init__(self, task, loss_weights=None, log_keys=None): def forward(self, model, sample, reduce=True): net_output = model(**sample["net_input"]) - sample_size = net_output["sample_size"] scaled_losses = {} if hasattr(model, "get_losses"): @@ -71,6 +72,12 @@ def forward(self, model, sample, reduce=True): scaled_losses[lk] = coef * p.float() loss = sum(scaled_losses.values()) + + if "sample_size" in net_output: + sample_size = net_output["sample_size"] + else: + sample_size = loss.numel() + if reduce and loss.numel() > 1: loss = loss.sum() @@ -84,12 +91,22 @@ def forward(self, model, sample, reduce=True): for lk in self.log_keys: if lk in net_output and net_output[lk] is not None: - logging_output[lk] = float(net_output[lk]) + if not torch.is_tensor(net_output[lk]) or net_output[lk].numel() == 1: + logging_output[lk] = float(net_output[lk]) + else: + for i, v in enumerate(net_output[lk]): + logging_output[f"{lk}_{i}"] = float(v) if len(scaled_losses) > 1: for lk, l in scaled_losses.items(): + if l.numel() > 1: + l = l.sum() logging_output[f"loss_{lk}"] = l.item() + if "logs" in net_output: + for lgw in net_output["logs"]: + logging_output[lgw] = net_output["logs"][lgw] + return loss, sample_size, logging_output @staticmethod diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 7914e6055b..9433e56d08 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -400,6 +400,8 @@ def compute_mask_indices( min_masks: int = 0, no_overlap: bool = False, min_space: int = 0, + require_same_masks: bool = True, + pct_holes: float = 0.0, ) -> np.ndarray: """ Computes random mask spans for a given shape @@ -510,8 +512,14 @@ def arrange(s, e, length, keep_length): min_len = min([len(m) for m in mask_idcs]) for i, mask_idc in enumerate(mask_idcs): - if len(mask_idc) > min_len: + if len(mask_idc) > min_len and require_same_masks: mask_idc = np.random.choice(mask_idc, min_len, replace=False) + if pct_holes > 0: + num_holes = np.rint(len(mask_idc) * pct_holes).astype(int) + mask_idc = np.random.choice( + mask_idc, len(mask_idc) - num_holes, replace=False + ) + mask[i, mask_idc] = True return mask diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index b6150ea3f7..b03e8386ed 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -639,6 +639,12 @@ class CheckpointConfig(FairseqDataclass): "(default: <save-dir>/checkpoint_last.pt" }, ) + continue_once: Optional[str] = field( + default=None, + metadata={ + "help": "continues from this checkpoint, unless a checkpoint indicated in 'restore_file' option is present" + }, + ) finetune_from_model: Optional[str] = field( default=None, metadata={ diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index b80315ddc9..f307fe6e5e 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -474,7 +474,7 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): cfg[k] = overrides[k] -def merge_with_parent(dc: FairseqDataclass, cfg: DictConfig, remove_missing=True): +def merge_with_parent(dc: FairseqDataclass, cfg: DictConfig, remove_missing=False): if remove_missing: if is_dataclass(dc): diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 320f5e1725..616e3051e9 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -7,6 +7,7 @@ import argparse import importlib import os + from contextlib import ExitStack from fairseq.dataclass import FairseqDataclass @@ -52,7 +53,7 @@ ] -def build_model(cfg: FairseqDataclass, task): +def build_model(cfg: FairseqDataclass, task, from_checkpoint=False): model = None model_type = getattr(cfg, "_name", None) or getattr(cfg, "arch", None) @@ -86,7 +87,7 @@ def build_model(cfg: FairseqDataclass, task): if isinstance(cfg, argparse.Namespace): cfg = dc.from_namespace(cfg) else: - cfg = merge_with_parent(dc(), cfg) + cfg = merge_with_parent(dc(), cfg, from_checkpoint) else: if model_type in ARCH_CONFIG_REGISTRY: with open_dict(cfg) if OmegaConf.is_config(cfg) else ExitStack(): diff --git a/fairseq/models/ema/ema.py b/fairseq/models/ema/ema.py index c43d9693a4..bc966a9aed 100644 --- a/fairseq/models/ema/ema.py +++ b/fairseq/models/ema/ema.py @@ -63,7 +63,7 @@ class EMA(object): Note this is enabled only when ema_fp32=True """ - def __init__(self, model, config, device=None): + def __init__(self, model, config, device=None, skip_keys=None): """ @param model model to initialize the EMA with @param config EMAConfig object with configuration like @@ -76,6 +76,7 @@ def __init__(self, model, config, device=None): self.model = copy.deepcopy(model) self.model.requires_grad_(False) self.config = config + self.skip_keys = skip_keys or set() self.fp32_params = {} if self.config.ema_seed_model is not None: @@ -142,6 +143,8 @@ def _step_internal(self, new_model, updates=None): self.fp32_params if self.config.ema_fp32 else self.model.state_dict() ) for key, param in new_model.state_dict().items(): + if isinstance(param, dict): + continue try: ema_param = ema_params[key] except KeyError: @@ -154,11 +157,16 @@ def _step_internal(self, new_model, updates=None): "incompatible tensor shapes between model param and ema param" + "{} vs. {}".format(param.shape, ema_param.shape) ) + if "version" in key: # Do not decay a model.version pytorch param continue - ema_param.mul_(decay) - ema_param.add_(param.to(dtype=ema_param.dtype), alpha=1 - decay) + + if key in self.skip_keys: + ema_param = param.to(dtype=ema_param.dtype).clone() + else: + ema_param.mul_(decay) + ema_param.add_(param.to(dtype=ema_param.dtype), alpha=1 - decay) ema_state_dict[key] = ema_param self.restore(ema_state_dict, build_fp32_params=False) @@ -173,16 +181,15 @@ def step(self, new_model, updates=None): When model updates >= ema_start_updates, then EMA is updated with a decay of self.config.ema_decay. """ - self._set_decay( - 0 - if updates is not None and updates < self.config.ema_start_update - else self.config.ema_decay - ) - if updates is not None and self.config.ema_update_freq > 1: - self.update_freq_counter += 1 - if self.update_freq_counter >= self.config.ema_update_freq: - self._step_internal(new_model, updates) - self.update_freq_counter = 0 + if updates is not None: + self._set_decay( + 0 if updates < self.config.ema_start_update else self.config.ema_decay + ) + if updates is not None and self.config.ema_update_freq > 1: + self.update_freq_counter += 1 + if self.update_freq_counter >= self.config.ema_update_freq: + self._step_internal(new_model, updates) + self.update_freq_counter = 0 else: self._step_internal(new_model, updates) @@ -191,5 +198,9 @@ def reverse(self, model): Load the model parameters from EMA model. Useful for inference or fine-tuning from the EMA model. """ - model.load_state_dict(self.model.state_dict(), strict=False) + d = self.model.state_dict() + if "_ema" in d: + del d["_ema"] + + model.load_state_dict(d, strict=False) return model diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index e336370b3e..b1d0a89b44 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -269,7 +269,7 @@ def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): if state is not None and "task_state" in state: # This will load the stored "dictionaries" object task.load_state_dict(state["task_state"]) - model = task.build_model(w2v_args.model) + model = task.build_model(w2v_args.model, from_checkpoint=True) if state is not None and not cfg.no_pretrained_weights: # set strict=False because we omit some modules diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 26d589e5bb..d2a039d2b8 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -385,7 +385,7 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): w2v_args.task.data = cfg.data task = tasks.setup_task(w2v_args.task) - model = task.build_model(w2v_args.model) + model = task.build_model(w2v_args.model, from_checkpoint=True) if state is not None and not cfg.no_pretrained_weights: self.load_model_weights(state, model, cfg) diff --git a/fairseq/modules/__init__.py b/fairseq/modules/__init__.py index 9db8dea598..085769c4fd 100644 --- a/fairseq/modules/__init__.py +++ b/fairseq/modules/__init__.py @@ -15,7 +15,9 @@ from .dynamic_convolution import DynamicConv, DynamicConv1dTBC from .dynamic_crf_layer import DynamicCRF from .fairseq_dropout import FairseqDropout +from .fp32_batch_norm import Fp32BatchNorm from .fp32_group_norm import Fp32GroupNorm +from .fp32_instance_norm import Fp32InstanceNorm from .gelu import gelu, gelu_accurate from .grad_multiply import GradMultiply from .gumbel_vector_quantizer import GumbelVectorQuantizer @@ -61,8 +63,10 @@ "DynamicConv", "DynamicCRF", "FairseqDropout", + "Fp32BatchNorm", "Fp32GroupNorm", "Fp32LayerNorm", + "Fp32InstanceNorm", "gelu", "gelu_accurate", "GradMultiply", diff --git a/fairseq/modules/fp32_batch_norm.py b/fairseq/modules/fp32_batch_norm.py new file mode 100644 index 0000000000..c560f338fd --- /dev/null +++ b/fairseq/modules/fp32_batch_norm.py @@ -0,0 +1,44 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +""" +batch norm done in fp32 (for fp16 training) +""" +import torch +import torch.nn as nn + + +class Fp32BatchNorm(nn.Module): + def __init__(self, sync=False, *args, **kwargs): + super().__init__() + + if sync: + from fairseq.distributed import utils + + if utils.get_global_world_size() == 1: + sync = False + + if sync: + self.bn = nn.SyncBatchNorm(*args, **kwargs) + else: + self.bn = nn.BatchNorm1d(*args, **kwargs) + + self.sync = sync + + def forward(self, input): + if self.bn.running_mean.dtype != torch.float: + if self.sync: + self.bn.running_mean = self.bn.running_mean.float() + self.bn.running_var = self.bn.running_var.float() + if self.bn.affine: + try: + self.bn.weight = self.bn.weight.float() + self.bn.bias = self.bn.bias.float() + except: + self.bn.float() + else: + self.bn.float() + + output = self.bn(input.float()) + return output.type_as(input) diff --git a/fairseq/modules/fp32_instance_norm.py b/fairseq/modules/fp32_instance_norm.py new file mode 100644 index 0000000000..30a54496de --- /dev/null +++ b/fairseq/modules/fp32_instance_norm.py @@ -0,0 +1,35 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +""" +Layer norm done in fp32 (for fp16 training) +""" + +import torch.nn as nn +import torch.nn.functional as F + + +class Fp32InstanceNorm(nn.InstanceNorm1d): + def __init__(self, *args, **kwargs): + self.transpose_last = "transpose_last" in kwargs and kwargs["transpose_last"] + if "transpose_last" in kwargs: + del kwargs["transpose_last"] + super().__init__(*args, **kwargs) + + def forward(self, input): + if self.transpose_last: + input = input.transpose(1, 2) + output = F.instance_norm( + input.float(), + running_mean=self.running_mean, + running_var=self.running_var, + weight=self.weight.float() if self.weight is not None else None, + bias=self.bias.float() if self.bias is not None else None, + use_input_stats=self.training or not self.track_running_stats, + momentum=self.momentum, + eps=self.eps, + ) + if self.transpose_last: + output = output.transpose(1, 2) + return output.type_as(input) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 638fef0f62..4a17d7180b 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -80,8 +80,14 @@ def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size): def _get_fc_rank(self, remove_num: int) -> List[int]: f1_filter_param = [] for i in range(self.fc1.out_features): - f1_filter_param.append(torch.sum(torch.abs(self.fc1.weight[i])) + torch.sum(torch.abs(self.fc2.weight[:, i])) + torch.abs(self.fc1.bias[i])) - return sorted(range(len(f1_filter_param)), key=lambda k: f1_filter_param[k], reverse=False)[0:remove_num] + f1_filter_param.append( + torch.sum(torch.abs(self.fc1.weight[i])) + + torch.sum(torch.abs(self.fc2.weight[:, i])) + + torch.abs(self.fc1.bias[i]) + ) + return sorted( + range(len(f1_filter_param)), key=lambda k: f1_filter_param[k], reverse=False + )[0:remove_num] def _prune_fc_layer(self, remove_index: List[int]): new_fc1_weight = [] diff --git a/fairseq/nan_detector.py b/fairseq/nan_detector.py index faa8031d46..7d46d766d2 100644 --- a/fairseq/nan_detector.py +++ b/fairseq/nan_detector.py @@ -37,7 +37,7 @@ def __exit__(self, exc_type, exc_value, exc_traceback): gradients = {} for name, param in self.named_parameters: if param.grad is not None: - grad_norm = torch.norm(param.grad.data, p=2, dtype=torch.float32) + grad_norm = torch.norm(param.grad.data.float(), p=2) norm[name] = grad_norm.item() if torch.isnan(grad_norm).any() or torch.isinf(grad_norm).any(): gradients[name] = param.grad.data diff --git a/fairseq/tasks/audio_finetuning.py b/fairseq/tasks/audio_finetuning.py index 70aa6a8da8..5e04a1b796 100644 --- a/fairseq/tasks/audio_finetuning.py +++ b/fairseq/tasks/audio_finetuning.py @@ -189,8 +189,8 @@ def valid_step(self, sample, model, criterion): logging_output[f"_bleu_totals_{i}"] = metrics.totals[i] return loss, sample_size, logging_output - def build_model(self, model_cfg: FairseqDataclass): - model = super().build_model(model_cfg) + def build_model(self, model_cfg: FairseqDataclass, from_checkpoint=False): + model = super().build_model(model_cfg, from_checkpoint) if self.cfg.eval_wer and self.cfg.autoregressive: self.sequence_generator = self.build_generator( diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index debb269ddd..a55c704006 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -193,8 +193,8 @@ def max_positions(self): """Maximum input length supported by the encoder.""" return sys.maxsize, sys.maxsize - def build_model(self, model_cfg: FairseqDataclass): - model = super().build_model(model_cfg) + def build_model(self, model_cfg: FairseqDataclass, from_checkpoint=False): + model = super().build_model(model_cfg, from_checkpoint) actualized_cfg = getattr(model, "cfg", None) if actualized_cfg is not None: diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 9cbdf89e6f..273dbddaa3 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -319,7 +319,7 @@ def get_batch_iterator( return epoch_iter - def build_model(self, cfg: FairseqDataclass): + def build_model(self, cfg: FairseqDataclass, from_checkpoint=False): """ Build the :class:`~fairseq.models.BaseFairseqModel` instance for this task. @@ -332,7 +332,7 @@ def build_model(self, cfg: FairseqDataclass): """ from fairseq import models, quantization_utils - model = models.build_model(cfg, self) + model = models.build_model(cfg, self, from_checkpoint) model = quantization_utils.quantize_model_scalar(model, cfg) return model @@ -655,7 +655,7 @@ def setup_task(cls, args: Namespace, **kwargs): def has_sharded_data(self, split): return os.pathsep in getattr(self.args, "data", "") - def build_model(self, args: Namespace): + def build_model(self, args: Namespace, from_checkpoint=False): """ Build the :class:`~fairseq.models.BaseFairseqModel` instance for this task. @@ -668,7 +668,7 @@ def build_model(self, args: Namespace): """ from fairseq import models, quantization_utils - model = models.build_model(args, self) + model = models.build_model(args, self, from_checkpoint) model = quantization_utils.quantize_model_scalar(model, args) return model diff --git a/fairseq/tasks/language_modeling.py b/fairseq/tasks/language_modeling.py index aa397de950..44d5324b3d 100644 --- a/fairseq/tasks/language_modeling.py +++ b/fairseq/tasks/language_modeling.py @@ -187,8 +187,8 @@ def setup_task(cls, args, **kwargs): return cls(args, dictionary, output_dictionary, targets=targets) - def build_model(self, args): - model = super().build_model(args) + def build_model(self, args, from_checkpoint=False): + model = super().build_model(args, from_checkpoint) for target in self.targets: if target not in model.supported_targets: raise ValueError( diff --git a/fairseq/tasks/multilingual_language_modeling.py b/fairseq/tasks/multilingual_language_modeling.py index f9e8d91c5f..673f563bed 100644 --- a/fairseq/tasks/multilingual_language_modeling.py +++ b/fairseq/tasks/multilingual_language_modeling.py @@ -256,8 +256,8 @@ def setup_task(cls, args, **kwargs): return cls(args, dictionary, output_dictionary, targets=targets) - def build_model(self, args): - model = super().build_model(args) + def build_model(self, args, from_checkpoint=False): + model = super().build_model(args, from_checkpoint) for target in self.targets: if target not in model.supported_targets: raise ValueError( diff --git a/fairseq/tasks/multilingual_translation.py b/fairseq/tasks/multilingual_translation.py index 4f85ab4832..e692b66690 100644 --- a/fairseq/tasks/multilingual_translation.py +++ b/fairseq/tasks/multilingual_translation.py @@ -281,7 +281,7 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None) eval_key=lang_pair, ) - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): def check_args(): messages = [] if ( @@ -316,7 +316,7 @@ def check_args(): from fairseq import models - model = models.build_model(args, self) + model = models.build_model(args, self, from_checkpoint) if not isinstance(model, FairseqMultiModel): raise ValueError( "MultilingualTranslationTask requires a FairseqMultiModel architecture" diff --git a/fairseq/tasks/online_backtranslation.py b/fairseq/tasks/online_backtranslation.py index 2e27ca237c..52ce58ced7 100644 --- a/fairseq/tasks/online_backtranslation.py +++ b/fairseq/tasks/online_backtranslation.py @@ -354,9 +354,9 @@ def load_translation_dataset( def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None): raise NotImplementedError - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): # torch.autograd.set_detect_anomaly(True) - model = super().build_model(args) + model = super().build_model(args, from_checkpoint) add_secial_tokens_to_dict_and_model(self.common_dict, model, self.mono_langs) diff --git a/fairseq/tasks/semisupervised_translation.py b/fairseq/tasks/semisupervised_translation.py index b2f9bf9a73..432b8a52ca 100644 --- a/fairseq/tasks/semisupervised_translation.py +++ b/fairseq/tasks/semisupervised_translation.py @@ -353,10 +353,10 @@ def language_pair_dataset(lang_pair): else "%s-%s" % (self.args.source_lang, self.args.target_lang), ) - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): from fairseq import models - model = models.build_model(args, self) + model = models.build_model(args, self, from_checkpoint) if not isinstance(model, FairseqMultiModel): raise ValueError( "SemisupervisedTranslationTask requires a FairseqMultiModel architecture" diff --git a/fairseq/tasks/sentence_prediction.py b/fairseq/tasks/sentence_prediction.py index d5f9302c10..52532ff61b 100644 --- a/fairseq/tasks/sentence_prediction.py +++ b/fairseq/tasks/sentence_prediction.py @@ -255,13 +255,13 @@ def parse_regression_target(i, line): self.datasets[split] = dataset return self.datasets[split] - def build_model(self, cfg): + def build_model(self, cfg, from_checkpoint=False): from fairseq import models with open_dict(cfg) if OmegaConf.is_config(cfg) else contextlib.ExitStack(): cfg.max_positions = self.cfg.max_positions - model = models.build_model(cfg, self) + model = models.build_model(cfg, self, from_checkpoint) model.register_classification_head( self.cfg.classification_head_name, diff --git a/fairseq/tasks/sentence_ranking.py b/fairseq/tasks/sentence_ranking.py index bed44f34e5..57f63aab67 100644 --- a/fairseq/tasks/sentence_ranking.py +++ b/fairseq/tasks/sentence_ranking.py @@ -195,10 +195,10 @@ def make_dataset(type, dictionary): self.datasets[split] = dataset return self.datasets[split] - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): from fairseq import models - model = models.build_model(args, self) + model = models.build_model(args, self, from_checkpoint) model.register_classification_head( getattr(args, "ranking_head_name", "sentence_classification_head"), diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index c2667d9d00..ed3a7ccd7d 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -275,13 +275,13 @@ def source_dictionary(self): def max_positions(self): return self.args.max_source_positions, self.args.max_target_positions - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): args.input_feat_per_channel = self.data_cfg.input_feat_per_channel args.input_channels = self.data_cfg.input_transformed_channels args.target_speaker_embed = self.data_cfg.target_speaker_embed is not None args.n_frames_per_step = self.args.n_frames_per_step - model = super().build_model(args) + model = super().build_model(args, from_checkpoint) if len(self.multitask_tasks) > 0: from fairseq.models.speech_to_speech.s2s_transformer import ( diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 3e568052cb..55ba284f8d 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -115,11 +115,11 @@ def source_dictionary(self): def max_positions(self): return self.args.max_source_positions, self.args.max_target_positions - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): args.input_feat_per_channel = self.data_cfg.input_feat_per_channel args.input_channels = self.data_cfg.input_channels args.speaker_to_id = self.speaker_to_id - return super(SpeechToTextTask, self).build_model(args) + return super(SpeechToTextTask, self).build_model(args, from_checkpoint) def build_generator( self, diff --git a/fairseq/tasks/text_to_speech.py b/fairseq/tasks/text_to_speech.py index bdbf87f6e9..82e7e6643a 100644 --- a/fairseq/tasks/text_to_speech.py +++ b/fairseq/tasks/text_to_speech.py @@ -133,13 +133,13 @@ def get_speaker_embeddings(cls, args): ) return embed_speaker - def build_model(self, cfg): + def build_model(self, cfg, from_checkpoint=False): cfg.pitch_min = self.data_cfg.config["features"].get("pitch_min", None) cfg.pitch_max = self.data_cfg.config["features"].get("pitch_max", None) cfg.energy_min = self.data_cfg.config["features"].get("energy_min", None) cfg.energy_max = self.data_cfg.config["features"].get("energy_max", None) cfg.speaker_emb_path = self.get_speaker_embeddings_path() - model = super().build_model(cfg) + model = super().build_model(cfg, from_checkpoint) self.generator = None if getattr(cfg, "eval_inference", False): self.generator = self.build_generator([model], cfg) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index f5a3cf6667..73b3d7c7be 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -365,8 +365,8 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, constraints=None) constraints=constraints, ) - def build_model(self, cfg): - model = super().build_model(cfg) + def build_model(self, cfg, from_checkpoint=False): + model = super().build_model(cfg, from_checkpoint) if self.cfg.eval_bleu: detok_args = json.loads(self.cfg.eval_bleu_detok_args) self.tokenizer = encoders.build_tokenizer( diff --git a/fairseq/tasks/translation_multi_simple_epoch.py b/fairseq/tasks/translation_multi_simple_epoch.py index 2ba012e88a..5db36a7c79 100644 --- a/fairseq/tasks/translation_multi_simple_epoch.py +++ b/fairseq/tasks/translation_multi_simple_epoch.py @@ -216,8 +216,8 @@ def build_generator( models, args, seq_gen_cls=None, extra_gen_cls_kwargs=extra_gen_cls_kwargs ) - def build_model(self, args): - return super().build_model(args) + def build_model(self, args, from_checkpoint=False): + return super().build_model(args, from_checkpoint) def valid_step(self, sample, model, criterion): loss, sample_size, logging_output = super().valid_step(sample, model, criterion) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index dd341f9c87..6b37caa8dd 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -9,6 +9,7 @@ import contextlib import logging +import os import sys import time from argparse import Namespace @@ -429,7 +430,8 @@ def state_dict(self): def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" - logger.info(f"Saving checkpoint to {filename}") + + logger.info(f"Saving checkpoint to {os.path.abspath(filename)}") # call state_dict on all ranks in case it needs internal communication state_dict = utils.move_to_cpu(self.state_dict()) state_dict["extra_state"].update(extra_state) @@ -439,7 +441,7 @@ def save_checkpoint(self, filename, extra_state): filename, async_write=self.cfg.checkpoint.write_checkpoints_asynchronously, ) - logger.info(f"Finished saving checkpoint to {filename}") + logger.info(f"Finished saving checkpoint to {os.path.abspath(filename)}") def load_checkpoint( self, @@ -502,6 +504,15 @@ def load_checkpoint( # load model parameters try: + if ( + "optimizer_history" in state + and len(state["optimizer_history"]) > 0 + and "num_updates" in state["optimizer_history"][-1] + ): + self.model.set_num_updates( + state["optimizer_history"][-1]["num_updates"] + ) + # this is the code related to AdaPrune # In short, it removes redundant heads in multi-head attention module based on heads importance provided # For more info, please refer to the paper: https://openreview.net/forum?id=_CMSV7FTzGI @@ -516,10 +527,16 @@ def load_checkpoint( and safe_hasattr(self.model.args, "mha_heads_to_keep") and self.model.args.mha_heads_to_keep != -1 ): - logger.info(f"Prune model: keep {self.model.args.mha_heads_to_keep} heads for each multihead attention module") + logger.info( + f"Prune model: keep {self.model.args.mha_heads_to_keep} heads for each multihead attention module" + ) for layer in self.model.encoder.sentence_encoder.layers: - reserve_head_index = layer.self_attn._get_reserve_head_index(num_heads_to_keep=self.model.args.mha_heads_to_keep) - layer.self_attn._adaptive_prune_heads(reserve_head_index=reserve_head_index) + reserve_head_index = layer.self_attn._get_reserve_head_index( + num_heads_to_keep=self.model.args.mha_heads_to_keep + ) + layer.self_attn._adaptive_prune_heads( + reserve_head_index=reserve_head_index + ) layer.self_attn._set_skip_embed_dim_check() logger.info(self.model) # this is the code related to AdaPrune @@ -536,9 +553,13 @@ def load_checkpoint( and safe_hasattr(self.model.args, "ffn_blocks_to_remove") and self.model.args.ffn_blocks_to_remove != -1 ): - logger.info(f"Prune model: remove {self.model.args.ffn_blocks_to_remove} ffn blocks for each transformer layer") + logger.info( + f"Prune model: remove {self.model.args.ffn_blocks_to_remove} ffn blocks for each transformer layer" + ) for layer in self.model.encoder.sentence_encoder.layers: - remove_index = layer._get_fc_rank(remove_num=self.model.args.ffn_blocks_to_remove) + remove_index = layer._get_fc_rank( + remove_num=self.model.args.ffn_blocks_to_remove + ) layer._prune_fc_layer(remove_index=remove_index) logger.info(self.model) @@ -832,6 +853,12 @@ def maybe_no_sync(): return None else: raise e + except Exception: + self.consolidate_optimizer() + self.save_checkpoint( + os.path.join(self.cfg.checkpoint.save_dir, "crash.pt"), {} + ) + raise if self.tpu and i < len(samples) - 1: # tpu-comment: every XLA operation before marking step is @@ -933,6 +960,12 @@ def maybe_no_sync(): ) # recursion to feed in same batch except FloatingPointError: + + self.consolidate_optimizer() + self.save_checkpoint( + os.path.join(self.cfg.checkpoint.save_dir, "crash.pt"), {} + ) + # re-run the forward and backward pass with hooks attached to print # out where it fails self.zero_grad() diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py index 1e58ddb112..0bc85562c7 100644 --- a/tests/test_checkpoint_utils.py +++ b/tests/test_checkpoint_utils.py @@ -107,13 +107,10 @@ def test_torch_persistent_save_async(self): def test_load_ema_from_checkpoint(self): dummy_state = {"a": torch.tensor([1]), "b": torch.tensor([0.1])} with patch(f"{checkpoint_utils.__name__}.PathManager.open") as mock_open, patch( - f"{checkpoint_utils.__name__}.torch.load") as mock_load: + f"{checkpoint_utils.__name__}.torch.load" + ) as mock_load: - mock_load.return_value = { - "extra_state": { - "ema": dummy_state - } - } + mock_load.return_value = {"extra_state": {"ema": dummy_state}} filename = "ema_checkpoint.pt" state = checkpoint_utils.load_ema_from_checkpoint(filename) diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index 786357dbcd..59864f9685 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -74,12 +74,15 @@ def test_pruning_heads(self): num_heads_to_keep = 8 dummy_input = torch.randn(32, 2, embed_dim) mha = MultiheadAttention(embed_dim=embed_dim, num_heads=num_heads) - reserve_head_index = mha._get_reserve_head_index(num_heads_to_keep=num_heads_to_keep) + reserve_head_index = mha._get_reserve_head_index( + num_heads_to_keep=num_heads_to_keep + ) mha._adaptive_prune_heads(reserve_head_index=reserve_head_index) mha._set_skip_embed_dim_check() mha(query=dummy_input, key=dummy_input, value=dummy_input) - self.assertEqual(mha.head_dim, embed_dim/num_heads) + self.assertEqual(mha.head_dim, embed_dim / num_heads) self.assertEqual(mha.num_heads, num_heads_to_keep) + if __name__ == "__main__": unittest.main() diff --git a/tests/utils.py b/tests/utils.py index e3fa98ac25..c14029e599 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -494,7 +494,7 @@ def __init__(self, args, src_dict, tgt_dict, model): def setup_task(cls, args, src_dict=None, tgt_dict=None, model=None): return cls(args, src_dict, tgt_dict, model) - def build_model(self, args): + def build_model(self, args, from_checkpoint=False): return TestModel.build_model(args, self) @property From c71870f370455e6154c730e8822ea323b5f266f6 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 20 Jan 2022 08:21:46 -0800 Subject: [PATCH 551/774] Data2vec (#2936) Summary: new data2vec models Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2936 Reviewed By: jacobkahn Differential Revision: D33674643 Pulled By: alexeib fbshipit-source-id: 2c2b4fae541974587b50a78a44d34033e9b5192d --- examples/data2vec/README.md | 136 +++++ .../audio/pretraining/base_librispeech.yaml | 83 +++ .../config/text/pretraining/base.yaml | 77 +++ examples/data2vec/models/data2vec_audio.py | 538 ++++++++++++++++++ examples/data2vec/models/data2vec_text.py | 518 +++++++++++++++++ examples/speech_recognition/new/infer.py | 2 + .../wav2vec/config/finetuning/base_1h.yaml | 4 +- fairseq/data/data_utils.py | 8 +- fairseq/models/roberta/model.py | 10 + .../models/transformer/transformer_encoder.py | 24 +- fairseq/models/wav2vec/wav2vec2.py | 189 ++++-- fairseq/models/wav2vec/wav2vec2_asr.py | 31 +- fairseq/modules/conformer_layer.py | 5 +- fairseq/modules/transformer_layer.py | 9 +- fairseq/tasks/masked_lm.py | 35 +- 15 files changed, 1590 insertions(+), 79 deletions(-) create mode 100644 examples/data2vec/README.md create mode 100644 examples/data2vec/config/audio/pretraining/base_librispeech.yaml create mode 100644 examples/data2vec/config/text/pretraining/base.yaml create mode 100644 examples/data2vec/models/data2vec_audio.py create mode 100644 examples/data2vec/models/data2vec_text.py diff --git a/examples/data2vec/README.md b/examples/data2vec/README.md new file mode 100644 index 0000000000..59cc888450 --- /dev/null +++ b/examples/data2vec/README.md @@ -0,0 +1,136 @@ + +# data2vec + +data2vec is a framework for self-supervised representation learning for images, speech, and text as described in [data2vec: A General Framework for Self-supervised Learning in Speech, Vision and Language (Baevski et al., 2022)](https://ai.facebook.com/research/data2vec-a-general-framework-for-self-supervised-learning-in-speech-vision-and-language). The algorithm uses the same learning mechanism for different modalities. + + +## Pre-trained models + +### Vision + +Coming soon! + +### Speech + +| Model | Finetuning split | Dataset | Link +|---|---|---|--- +data2vec Base | No fine-tuning | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/audio_base_ls.pt) +data2vec Base | 10 minutes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/audio_base_ls_10m.pt) +data2vec Base | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/audio_base_ls_100h.pt) +data2vec Base | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/audio_base_ls_960h.pt) + +### NLP + +Model | Fine-tuning data | Dataset | Link +|---|---|---|---| +data2vec Base | No fine-tuning | Books + Wiki | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/nlp_base.pt) + +## Training a new speech model with the CLI tools + +Below is copied from thw wav2vec README - needs adapting + +Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) + +### Prepare training data manifest: + +First, install the `soundfile` library: +```shell script +pip install soundfile +``` + +Next, run: + +```shell script +$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext $ext --valid-percent $valid +``` + +$ext should be set to flac, wav, or whatever format your dataset happens to use that soundfile can read. + +$valid should be set to some reasonable percentage (like 0.01) of training data to use for validation. +To use a pre-defined validation set (like dev-other from librispeech), set to it 0 and then overwrite valid.tsv with a +separately pre-processed manifest file. + +### Train a data2vec Base model: + +This configuration was used for the base model trained on the Librispeech dataset in the data2vec paper + +Note that the input is expected to be single channel, sampled at 16 kHz + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/audio/pretraining \ +--config-name base_librispeech task.data=/path/to/manifests common.user_dir=examples/data2vec +``` + +Note: you can simulate 16 GPUs by using k GPUs and adding command line parameters +`distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 16/k + +### Fine-tune a pre-trained model with CTC: + +Fine-tuning a model requires parallel audio and labels file, as well as a vocabulary file in fairseq format. +A letter vocabulary can be downloaded [here](https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt). +An example [script](../wav2vec/libri_labels.py) that generates labels for the Librispeech dataset from the tsv file produced by wav2vec_manifest.py can be used as follows: + +```shell script +split=train +$ python libri_labels.py /path/to/tsv --output-dir /output/dir --output-name $split +``` + +Fine-tuning on 100h of Librispeech with letter targets: +```shell script +$ fairseq-hydra-train \ + distributed_training.distributed_port=$PORT \ + task.data=/path/to/data \ + model.w2v_path=/path/to/model.pt \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/finetuning \ + --config-name base_100h common.user_dir=examples/data2vec +``` + +There are other config files in the config/finetuning directory that can be used to fine-tune on other splits. +You can specify the right config via the `--config-name` parameter. + +Decoding with a language model during training requires flashlight [python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter). +If you want to use a language model, add `+criterion.wer_args='[/path/to/kenlm, /path/to/lexicon, 2, -1]'` to the command line. + +### Evaluating a CTC model: + +Evaluating a CTC model with a language model requires [flashlight python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter) to be installed. + +Fairseq transformer language model used in the wav2vec 2.0 paper can be obtained from the [wav2letter model repository](https://github.com/facebookresearch/wav2letter/tree/master/recipes/sota/2019). +Be sure to upper-case the language model vocab after downloading it. + +Letter dictionary for pre-trained models can be found [here](https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt). + +Next, run the evaluation command: + +```shell script +python examples/speech_recognition/new/infer.py --config-dir examples/speech_recognition/new/conf \ +--config-name infer task=audio_finetuning task.data=/path/to/manifests common.user_dir=examples/data2vec \ +task.labels=ltr decoding.type=kenlm \ +decoding.lmweight=${lmweight} decoding.wordscore=${wordscore} decoding.silweight=${silscore} \ +decoding.lexicon=/path/to/lexicon \ +decoding.lmpath=/path/to/lm decoding.unique_wer_file=True \ +dataset.gen_subset=dev_clean,dev_other,test_clean,test_other \ +common_eval.path=/path/to/checkpoint.pt decoding.beam=1500 distributed_training.distributed_world_size=${num_gpus} +``` + +To get raw numbers, use decoding.type=viterbi and omit the lexicon. To use the transformer language model, use decoding.type=fairseqlm. + +## Training a new NLP model with the CLI tools + +Please follow the [RoBERTa](../roberta/README.md) instructions to preprocess your data. To train a data2vec model on run: + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/text/pretraining \ +--config-name base task.data=/path/to/data common.user_dir=examples/data2vec +``` + +As for speech models, you can simulate 16 gpus by using the update_freq parameter. + +### Finetuning data2vec-text on GLUE + +Please use a command similar to this: + +```shell +$ python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task task.data=$data_path checkpoint.restore_file="${/path/to/pretrained/model.pt}" +``` diff --git a/examples/data2vec/config/audio/pretraining/base_librispeech.yaml b/examples/data2vec/config/audio/pretraining/base_librispeech.yaml new file mode 100644 index 0000000000..c332c5a3f8 --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/base_librispeech.yaml @@ -0,0 +1,83 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: ??? + max_sample_size: 320000 + min_sample_size: 32000 + normalize: true + +dataset: + num_workers: 6 + max_tokens: 3800000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 16 + ddp_backend: legacy_ddp + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + +optimization: + max_update: 400000 + lr: [0.0005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.03,0.9,0.07] + +model: + _name: data2vec_audio + extractor_mode: layer_norm + encoder_layerdrop: 0.05 + dropout_input: 0.0 + dropout_features: 0.0 + feature_grad_mult: 1.0 + encoder_embed_dim: 768 + + mask_prob: 0.65 + mask_length: 10 + + loss_beta: 0 + loss_scale: null + + instance_norm_target_layer: true + average_top_k_layers: 8 + + pos_conv_depth: 5 + conv_pos: 95 + + ema_decay: 0.999 + ema_end_decay: 0.9999 + ema_anneal_end_step: 30000 + ema_transformer_only: true + ema_layers_only: true + + require_same_masks: true + mask_dropout: 0 diff --git a/examples/data2vec/config/text/pretraining/base.yaml b/examples/data2vec/config/text/pretraining/base.yaml new file mode 100644 index 0000000000..c6b07c4052 --- /dev/null +++ b/examples/data2vec/config/text/pretraining/base.yaml @@ -0,0 +1,77 @@ +# @package _group_ +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + +checkpoint: + no_epoch_checkpoints: true + save_interval_updates: 50000 + keep_interval_updates: 1 + +distributed_training: + distributed_world_size: 16 + ddp_backend: legacy_ddp + +task: + _name: masked_lm + data: ??? + sample_break_mode: complete_doc + tokens_per_sample: 512 + include_target_tokens: true + random_token_prob: 0 + leave_unmasked_prob: 0 + mask_prob: 0.35 + mask_multiple_length: 4 + +criterion: model + +dataset: + max_tokens: 8192 + ignore_unused_valid_subsets: true + skip_invalid_size_inputs_valid_test: true + +optimizer: + _name: adam + weight_decay: 0.01 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: cosine + warmup_updates: 10000 + +optimization: + clip_norm: 5 + lr: [0.0002] + max_update: 1000000 + update_freq: [1] + +model: + _name: data2vec_text + head_layers: 2 + average_top_k_layers: 10 + layer_norm_target_layer: true + loss_scale: 1 + ema_decay: 0.999 + ema_end_decay: 0.9999 + ema_anneal_end_step: 300000 + loss_beta: 4 + ema_transformer_layers_only: true + + transformer: + dropout: 0.1 + attention_dropout: 0.1 + layernorm_embedding: true + activation_fn: gelu + no_scale_embedding: true + max_source_positions: 512 + encoder: + embed_dim: 768 + ffn_embed_dim: 3072 + layers: 12 + attention_heads: 12 + normalize_before: false + learned_pos: true + layerdrop: 0 diff --git a/examples/data2vec/models/data2vec_audio.py b/examples/data2vec/models/data2vec_audio.py new file mode 100644 index 0000000000..43e2f07e63 --- /dev/null +++ b/examples/data2vec/models/data2vec_audio.py @@ -0,0 +1,538 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import math +from dataclasses import dataclass, field +from typing import Optional + +from omegaconf import II + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.distributed as dist + +from fairseq.dataclass.configs import EMAConfig +from fairseq.models.ema import EMA +from fairseq.data.data_utils import compute_mask_indices +from fairseq.models import BaseFairseqModel, register_model +from fairseq.models.wav2vec import ( + ConvFeatureExtractionModel, + Wav2Vec2Config, + TransformerEncoder, +) +from fairseq.modules import ( + GradMultiply, + LayerNorm, +) +from fairseq.utils import index_put + + +logger = logging.getLogger(__name__) + + +@dataclass +class Data2VecAudioConfig(Wav2Vec2Config): + + loss_beta: float = field( + default=0, metadata={"help": "beta for smooth l1 loss. 0 means use l2 loss"} + ) + loss_scale: Optional[float] = field( + default=None, + metadata={ + "help": "scale the reconstruction loss by this constant. if None then scales by 1/sqrt(dim)" + }, + ) + average_top_k_layers: int = field( + default=8, metadata={"help": "how many layers to average"} + ) + + layer_norm_target_layer: bool = False + instance_norm_target_layer: bool = False + instance_norm_targets: bool = False + layer_norm_targets: bool = False + batch_norm_target_layer: bool = False + group_norm_target_layer: bool = False + + ema_decay: float = field(default=0.999, metadata={"help": "initial ema decay rate"}) + ema_end_decay: float = field( + default=0.9999, metadata={"help": "final ema decay rate"} + ) + + # when to finish annealing ema decay rate + ema_anneal_end_step: int = II("optimization.max_update") + + ema_transformer_only: bool = field( + default=True, + metadata={"help": "whether to momentum update only the transformer"}, + ) + ema_layers_only: bool = field( + default=True, + metadata={"help": "whether to momentum update only the transformer layers"}, + ) + + max_update: int = II("optimization.max_update") + + min_target_var: float = field( + default=0.1, metadata={"help": "stop training if target var falls below this"} + ) + min_pred_var: float = field( + default=0.01, + metadata={"help": "stop training if prediction var falls below this"}, + ) + + +def get_annealed_rate(start, end, curr_step, total_steps): + r = end - start + pct_remaining = 1 - curr_step / total_steps + return end - r * pct_remaining + + +@register_model("data2vec_audio", dataclass=Data2VecAudioConfig) +class Data2VecAudioModel(BaseFairseqModel): + def __init__(self, cfg: Data2VecAudioConfig): + super().__init__() + self.cfg = cfg + + feature_enc_layers = eval(cfg.conv_feature_layers) + self.extractor_embed = feature_enc_layers[-1][0] + + self.ema = None + self.embed = cfg.encoder_embed_dim + + self.average_top_k_layers = cfg.average_top_k_layers + self.loss_beta = cfg.loss_beta + self.loss_scale = cfg.loss_scale + + self.feature_extractor = ConvFeatureExtractionModel( + conv_layers=feature_enc_layers, + dropout=0.0, + mode=cfg.extractor_mode, + conv_bias=cfg.conv_bias, + ) + + self.post_extract_proj = nn.Linear(self.extractor_embed, cfg.encoder_embed_dim) + + self.mask_prob = cfg.mask_prob + self.mask_selection = cfg.mask_selection + self.mask_other = cfg.mask_other + self.mask_length = cfg.mask_length + self.no_mask_overlap = cfg.no_mask_overlap + self.mask_min_space = cfg.mask_min_space + + self.mask_channel_prob = cfg.mask_channel_prob + self.mask_channel_before = cfg.mask_channel_before + self.mask_channel_selection = cfg.mask_channel_selection + self.mask_channel_other = cfg.mask_channel_other + self.mask_channel_length = cfg.mask_channel_length + self.no_mask_channel_overlap = cfg.no_mask_channel_overlap + self.mask_channel_min_space = cfg.mask_channel_min_space + + self.dropout_input = nn.Dropout(cfg.dropout_input) + self.dropout_features = nn.Dropout(cfg.dropout_features) + + self.feature_grad_mult = cfg.feature_grad_mult + + self.mask_emb = nn.Parameter( + torch.FloatTensor(cfg.encoder_embed_dim).uniform_() + ) + + self.encoder = TransformerEncoder(cfg) + self.layer_norm = LayerNorm(self.extractor_embed) + + self.final_proj = nn.Linear(self.embed, self.embed) + + self.num_updates = 0 + + def make_ema_teacher(self): + ema_config = EMAConfig( + ema_decay=self.cfg.ema_decay, + ema_fp32=True, + ) + skip_keys = set() + if self.cfg.ema_layers_only: + self.cfg.ema_transformer_only = True + for k, _ in self.encoder.pos_conv.named_parameters(): + skip_keys.add(f"pos_conv.{k}") + + self.ema = EMA( + self.encoder if self.cfg.ema_transformer_only else self, + ema_config, + skip_keys=skip_keys, + ) + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + + if self.ema is None and self.final_proj is not None: + logger.info(f"making ema teacher") + self.make_ema_teacher() + elif self.training and self.ema is not None: + if self.cfg.ema_decay != self.cfg.ema_end_decay: + if num_updates >= self.cfg.ema_anneal_end_step: + decay = self.cfg.ema_end_decay + else: + decay = get_annealed_rate( + self.cfg.ema_decay, + self.cfg.ema_end_decay, + num_updates, + self.cfg.ema_anneal_end_step, + ) + self.ema._set_decay(decay) + if self.ema.get_decay() < 1: + self.ema.step(self.encoder if self.cfg.ema_transformer_only else self) + + self.num_updates = num_updates + + def state_dict(self, destination=None, prefix="", keep_vars=False): + state = super().state_dict(destination, prefix, keep_vars) + + if self.ema is not None: + state[prefix + "_ema"] = self.ema.fp32_params + + return state + + def _load_from_state_dict(self, state_dict, prefix, *args, **kwargs): + if self.ema is not None: + k = prefix + "_ema" + assert k in state_dict + self.ema.restore(state_dict[k], True) + del state_dict[k] + return super()._load_from_state_dict(state_dict, prefix, *args, **kwargs) + + @classmethod + def build_model(cls, cfg: Data2VecAudioConfig, task=None): + """Build a new model instance.""" + + return cls(cfg) + + def apply_mask( + self, + x, + padding_mask, + mask_indices=None, + mask_channel_indices=None, + ): + B, T, C = x.shape + + if self.mask_channel_prob > 0 and self.mask_channel_before: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_channel_prob, + self.mask_channel_length, + self.mask_channel_selection, + self.mask_channel_other, + no_overlap=self.no_mask_channel_overlap, + min_space=self.mask_channel_min_space, + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x[mask_channel_indices] = 0 + + if self.mask_prob > 0: + if mask_indices is None: + mask_indices = compute_mask_indices( + (B, T), + padding_mask, + self.mask_prob, + self.mask_length, + self.mask_selection, + self.mask_other, + min_masks=1, + no_overlap=self.no_mask_overlap, + min_space=self.mask_min_space, + require_same_masks=self.cfg.require_same_masks, + mask_dropout=self.cfg.mask_dropout, + ) + mask_indices = torch.from_numpy(mask_indices).to(x.device) + x = index_put(x, mask_indices, self.mask_emb) + else: + mask_indices = None + + if self.mask_channel_prob > 0 and not self.mask_channel_before: + if mask_channel_indices is None: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_channel_prob, + self.mask_channel_length, + self.mask_channel_selection, + self.mask_channel_other, + no_overlap=self.no_mask_channel_overlap, + min_space=self.mask_channel_min_space, + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x = index_put(x, mask_channel_indices, 0) + + return x, mask_indices + + def _get_feat_extract_output_lengths(self, input_lengths: torch.LongTensor): + """ + Computes the output length of the convolutional layers + """ + + def _conv_out_length(input_length, kernel_size, stride): + return torch.floor((input_length - kernel_size) / stride + 1) + + conv_cfg_list = eval(self.cfg.conv_feature_layers) + + for i in range(len(conv_cfg_list)): + input_lengths = _conv_out_length( + input_lengths, conv_cfg_list[i][1], conv_cfg_list[i][2] + ) + + return input_lengths.to(torch.long) + + def forward( + self, + source, + padding_mask=None, + mask=True, + features_only=False, + layer=None, + mask_indices=None, + mask_channel_indices=None, + padding_count=None, + ): + features = source + + if self.feature_grad_mult > 0: + features = self.feature_extractor(features) + if self.feature_grad_mult != 1.0: + features = GradMultiply.apply(features, self.feature_grad_mult) + else: + with torch.no_grad(): + features = self.feature_extractor(features) + + features = features.transpose(1, 2) + + features = self.layer_norm(features) + + orig_padding_mask = padding_mask + + if padding_mask is not None and padding_mask.any(): + input_lengths = (1 - padding_mask.long()).sum(-1) + # apply conv formula to get real output_lengths + output_lengths = self._get_feat_extract_output_lengths(input_lengths) + + padding_mask = torch.zeros( + features.shape[:2], dtype=features.dtype, device=features.device + ) + + # these two operations makes sure that all values + # before the output lengths indices are attended to + padding_mask[ + ( + torch.arange(padding_mask.shape[0], device=padding_mask.device), + output_lengths - 1, + ) + ] = 1 + padding_mask = (1 - padding_mask.flip([-1]).cumsum(-1).flip([-1])).bool() + else: + padding_mask = None + + if self.post_extract_proj is not None: + features = self.post_extract_proj(features) + + pre_encoder_features = None + if self.cfg.ema_transformer_only: + pre_encoder_features = features.clone() + + features = self.dropout_input(features) + + if mask: + x, mask_indices = self.apply_mask( + features, + padding_mask, + mask_indices=mask_indices, + mask_channel_indices=mask_channel_indices, + ) + else: + x = features + mask_indices = None + + x, layer_results = self.encoder( + x, + padding_mask=padding_mask, + layer=layer, + ) + + if features_only: + return { + "x": x, + "padding_mask": padding_mask, + "layer_results": layer_results, + } + + result = { + "losses": {}, + } + + with torch.no_grad(): + self.ema.model.eval() + + if self.cfg.ema_transformer_only: + y, layer_results = self.ema.model.extract_features( + pre_encoder_features, + padding_mask=padding_mask, + min_layer=self.cfg.encoder_layers - self.average_top_k_layers, + ) + y = { + "x": y, + "padding_mask": padding_mask, + "layer_results": layer_results, + } + else: + y = self.ema.model.extract_features( + source=source, + padding_mask=orig_padding_mask, + mask=False, + ) + + target_layer_results = [l[2] for l in y["layer_results"]] + + permuted = False + if self.cfg.instance_norm_target_layer or self.cfg.batch_norm_target_layer: + target_layer_results = [ + tl.permute(1, 2, 0) for tl in target_layer_results # TBC -> BCT + ] + permuted = True + + if self.cfg.batch_norm_target_layer: + target_layer_results = [ + F.batch_norm( + tl.float(), running_mean=None, running_var=None, training=True + ) + for tl in target_layer_results + ] + + if self.cfg.instance_norm_target_layer: + target_layer_results = [ + F.instance_norm(tl.float()) for tl in target_layer_results + ] + + if permuted: + target_layer_results = [ + tl.transpose(1, 2) for tl in target_layer_results # BCT -> BTC + ] + + if self.cfg.group_norm_target_layer: + target_layer_results = [ + F.layer_norm(tl.float(), tl.shape[-2:]) + for tl in target_layer_results + ] + + if self.cfg.layer_norm_target_layer: + target_layer_results = [ + F.layer_norm(tl.float(), tl.shape[-1:]) + for tl in target_layer_results + ] + + y = sum(target_layer_results) / len(target_layer_results) + + if self.cfg.layer_norm_targets: + y = F.layer_norm(y.float(), y.shape[-1:]) + + if self.cfg.instance_norm_targets: + y = F.instance_norm(y.float().transpose(1, 2)).transpose(1, 2) + + if not permuted: + y = y.transpose(0, 1) + + y = y[mask_indices] + + x = x[mask_indices] + x = self.final_proj(x) + + sz = x.size(-1) + + if self.loss_beta == 0: + loss = F.mse_loss(x.float(), y.float(), reduction="none").sum(dim=-1) + else: + loss = F.smooth_l1_loss( + x.float(), y.float(), reduction="none", beta=self.loss_beta + ).sum(dim=-1) + + if self.loss_scale is not None: + scale = self.loss_scale + else: + scale = 1 / math.sqrt(sz) + + result["losses"]["regression"] = loss.sum() * scale + + if "sample_size" not in result: + result["sample_size"] = loss.numel() + + with torch.no_grad(): + result["target_var"] = self.compute_var(y) + result["pred_var"] = self.compute_var(x.float()) + + if self.num_updates > 5000 and result["target_var"] < self.cfg.min_target_var: + logger.error( + f"target var is {result['target_var'].item()} < {self.cfg.min_target_var}, exiting" + ) + raise Exception( + f"target var is {result['target_var'].item()} < {self.cfg.min_target_var}, exiting" + ) + if self.num_updates > 5000 and result["pred_var"] < self.cfg.min_pred_var: + logger.error( + f"pred var is {result['pred_var'].item()} < {self.cfg.min_pred_var}, exiting" + ) + raise Exception( + f"pred var is {result['pred_var'].item()} < {self.cfg.min_pred_var}, exiting" + ) + + if self.ema is not None: + result["ema_decay"] = self.ema.get_decay() * 1000 + + return result + + @staticmethod + def compute_var(y): + y = y.view(-1, y.size(-1)) + if dist.is_initialized(): + zc = torch.tensor(y.size(0)).cuda() + zs = y.sum(dim=0) + zss = (y ** 2).sum(dim=0) + + dist.all_reduce(zc) + dist.all_reduce(zs) + dist.all_reduce(zss) + + var = zss / (zc - 1) - (zs ** 2) / (zc * (zc - 1)) + return torch.sqrt(var + 1e-6).mean() + else: + return torch.sqrt(y.var(dim=0) + 1e-6).mean() + + def extract_features( + self, source, padding_mask, mask=False, layer=None + ): + res = self.forward( + source, + padding_mask, + mask=mask, + features_only=True, + layer=layer, + ) + return res + + def remove_pretraining_modules(self, last_layer=None): + self.final_proj = None + self.ema = None + if last_layer is not None: + self.encoder.layers = nn.ModuleList( + l for i, l in enumerate(self.encoder.layers) if i <= last_layer + ) diff --git a/examples/data2vec/models/data2vec_text.py b/examples/data2vec/models/data2vec_text.py new file mode 100644 index 0000000000..a69311cee6 --- /dev/null +++ b/examples/data2vec/models/data2vec_text.py @@ -0,0 +1,518 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass, field +from typing import Optional +import logging +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from omegaconf import II + +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.configs import EMAConfig +from fairseq.models.ema import EMA +from fairseq.models import ( + FairseqEncoder, + FairseqEncoderModel, + register_model, +) +from fairseq.models.roberta.model import RobertaLMHead, RobertaClassificationHead +from fairseq.models.transformer import TransformerEncoder, TransformerConfig +from fairseq.modules.transformer_sentence_encoder import init_bert_params + +logger = logging.getLogger(__name__) + + +@dataclass +class Data2VecTextConfig(FairseqDataclass): + max_positions: int = II("task.tokens_per_sample") + + head_layers: int = 1 + + transformer: TransformerConfig = TransformerConfig() + + load_checkpoint_heads: bool = field( + default=False, + metadata={"help": "(re-)register and load heads when loading checkpoints"}, + ) + + loss_beta: float = field( + default=0, metadata={"help": "beta for smooth l1 loss. 0 means use l2 loss"} + ) + loss_scale: Optional[float] = field( + default=None, + metadata={ + "help": "scale the reconstruction loss by this constant. if None then scales by 1/sqrt(dim)" + }, + ) + average_top_k_layers: int = field( + default=8, metadata={"help": "how many layers to average"} + ) + + layer_norm_target_layer: bool = False + instance_norm_target_layer: bool = False + batch_norm_target_layer: bool = False + instance_norm_targets: bool = False + layer_norm_targets: bool = False + + ema_decay: float = field(default=0.999, metadata={"help": "initial ema decay rate"}) + ema_end_decay: float = field( + default=0.9999, metadata={"help": "final ema decay rate"} + ) + + # when to finish annealing ema decay rate + ema_anneal_end_step: int = II("optimization.max_update") + + ema_transformer_layers_only: bool = field( + default=True, + metadata={"help": "whether to momentum update only the transformer layers"}, + ) + + +def get_annealed_rate(start, end, curr_step, total_steps): + r = end - start + pct_remaining = 1 - curr_step / total_steps + return end - r * pct_remaining + + +@register_model("data2vec_text", dataclass=Data2VecTextConfig) +class Data2VecTextModel(FairseqEncoderModel): + def __init__(self, cfg: Data2VecTextConfig, encoder): + super().__init__(encoder) + self.cfg = cfg + + # We follow BERT's random weight initialization + self.apply(init_bert_params) + + self.classification_heads = nn.ModuleDict() + + @classmethod + def build_model(cls, cfg, task): + """Build a new model instance.""" + + encoder = Data2VecTextEncoder(cfg, task.source_dictionary, task.cfg.data) + + return cls(cfg, encoder) + + def forward( + self, + src_tokens, + target_tokens=None, + features_only=False, + return_all_hiddens=False, + classification_head_name=None, + **kwargs, + ): + if classification_head_name is not None: + features_only = True + + res = self.encoder( + src_tokens, target_tokens, features_only, return_all_hiddens, **kwargs + ) + + if isinstance(res, tuple): + x, extra = res + else: + return res + + if classification_head_name is not None: + x = self.classification_heads[classification_head_name](x) + return x, extra + + def get_normalized_probs(self, net_output, log_probs, sample=None): + """Get normalized probabilities (or log probs) from a net's output.""" + logits = net_output[0].float() + if log_probs: + return F.log_softmax(logits, dim=-1) + else: + return F.softmax(logits, dim=-1) + + def register_classification_head( + self, name, num_classes=None, inner_dim=None, **kwargs + ): + """Register a classification head.""" + if name in self.classification_heads: + prev_num_classes = self.classification_heads[name].out_proj.out_features + prev_inner_dim = self.classification_heads[name].dense.out_features + if num_classes != prev_num_classes or inner_dim != prev_inner_dim: + logger.warning( + 're-registering head "{}" with num_classes {} (prev: {}) ' + "and inner_dim {} (prev: {})".format( + name, num_classes, prev_num_classes, inner_dim, prev_inner_dim + ) + ) + self.classification_heads[name] = RobertaClassificationHead( + input_dim=self.cfg.transformer.encoder.embed_dim, + inner_dim=inner_dim or self.cfg.transformer.encoder.embed_dim, + num_classes=num_classes, + activation_fn="tanh", + pooler_dropout=0, + ) + + @property + def supported_targets(self): + return {"self"} + + def upgrade_state_dict_named(self, state_dict, name): + prefix = name + "." if name != "" else "" + + # rename decoder -> encoder before upgrading children modules + for k in list(state_dict.keys()): + if k.startswith(prefix + "decoder"): + new_k = prefix + "encoder" + k[len(prefix + "decoder") :] + state_dict[new_k] = state_dict[k] + del state_dict[k] + + # rename emb_layer_norm -> layernorm_embedding + for k in list(state_dict.keys()): + if ".emb_layer_norm." in k: + new_k = k.replace(".emb_layer_norm.", ".layernorm_embedding.") + state_dict[new_k] = state_dict[k] + del state_dict[k] + + if self.encoder.regression_head is not None: + if ".lm_head." in k: + new_k = k.replace(".lm_head.", ".regression_head.") + state_dict[new_k] = state_dict[k] + del state_dict[k] + else: + if ".regression_head." in k: + del state_dict[k] + + # upgrade children modules + super().upgrade_state_dict_named(state_dict, name) + + # Handle new classification heads present in the state dict. + current_head_names = ( + [] + if not hasattr(self, "classification_heads") + or self.classification_heads is None + else self.classification_heads.keys() + ) + keys_to_delete = [] + for k in state_dict.keys(): + if not k.startswith(prefix + "classification_heads."): + continue + + head_name = k[len(prefix + "classification_heads.") :].split(".")[0] + num_classes = state_dict[ + prefix + "classification_heads." + head_name + ".out_proj.weight" + ].size(0) + inner_dim = state_dict[ + prefix + "classification_heads." + head_name + ".dense.weight" + ].size(0) + + if self.cfg.load_checkpoint_heads: + if head_name not in current_head_names: + self.register_classification_head(head_name, num_classes, inner_dim) + else: + if head_name not in current_head_names: + logger.warning( + "deleting classification head ({}) from checkpoint " + "not present in current model: {}".format(head_name, k) + ) + keys_to_delete.append(k) + elif ( + num_classes + != self.classification_heads[head_name].out_proj.out_features + or inner_dim + != self.classification_heads[head_name].dense.out_features + ): + logger.warning( + "deleting classification head ({}) from checkpoint " + "with different dimensions than current model: {}".format( + head_name, k + ) + ) + keys_to_delete.append(k) + for k in keys_to_delete: + del state_dict[k] + + # Copy any newly-added classification heads into the state dict + # with their current weights. + if ( + hasattr(self, "classification_heads") + and self.classification_heads is not None + and len(self.classification_heads) > 0 + ): + cur_state = self.classification_heads.state_dict() + for k, v in cur_state.items(): + if prefix + "classification_heads." + k not in state_dict: + logger.info("Overwriting " + prefix + "classification_heads." + k) + state_dict[prefix + "classification_heads." + k] = v + + for k in list(state_dict.keys()): + if k.startswith(prefix + "encoder.lm_head.") or k.startswith( + prefix + "encoder.emb_head." + ): + del state_dict[k] + + self.encoder.lm_head = None + + if self.encoder.target_model is None: + for k in list(state_dict.keys()): + if k.startswith(prefix + "encoder.target_model."): + del state_dict[k] + + if (self.encoder.ema is None) and (prefix + "encoder._ema" in state_dict): + del state_dict[prefix + "encoder._ema"] + + def remove_pretraining_modules(self, last_layer=None): + self.encoder.lm_head = None + self.encoder.regression_head = None + self.encoder.ema = None + self.classification_heads = None + + if last_layer is not None: + self.encoder.sentence_encoder.layers = nn.ModuleList( + l + for i, l in enumerate(self.encoder.sentence_encoder.layers) + if i <= last_layer + ) + self.encoder.sentence_encoder.layer_norm = None + + +class Data2VecTextEncoder(FairseqEncoder): + def __init__(self, cfg: Data2VecTextConfig, dictionary, task_data): + super().__init__(dictionary) + + self.cfg = cfg + + embed_tokens = self.build_embedding( + len(dictionary), cfg.transformer.encoder.embed_dim, dictionary.pad() + ) + + self.sentence_encoder = self.build_encoder(cfg, dictionary, embed_tokens) + self.mask_idx = dictionary.index("<mask>") + assert self.mask_idx != dictionary.unk(), dictionary.symbols + + self.ema = None + self.average_top_k_layers = cfg.average_top_k_layers + self.loss_scale = cfg.loss_scale + + assert self.cfg.head_layers >= 1 + + embed_dim = cfg.transformer.encoder.embed_dim + curr_dim = embed_dim + projs = [] + for i in range(self.cfg.head_layers - 1): + next_dim = embed_dim * 2 if i == 0 else curr_dim + projs.append(nn.Linear(curr_dim, next_dim)) + projs.append(nn.GELU()) + curr_dim = next_dim + + projs.append(nn.Linear(curr_dim, embed_dim)) + self.regression_head = nn.Sequential(*projs) + + self.num_updates = 0 + + def build_embedding(self, vocab_size, embedding_dim, padding_idx): + return nn.Embedding(vocab_size, embedding_dim, padding_idx) + + def build_encoder(self, cfg, dictionary, embed_tokens): + encoder = TransformerEncoder(cfg.transformer, dictionary, embed_tokens, return_fc=True) + encoder.apply(init_bert_params) + return encoder + + def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): + return RobertaLMHead(embed_dim, output_dim, activation_fn, weight) + + def make_ema_teacher(self): + ema_config = EMAConfig( + ema_decay=self.cfg.ema_decay, + ema_fp32=True, + ) + skip_keys = set() + if self.cfg.ema_transformer_layers_only: + for k, _ in self.sentence_encoder.embed_positions.named_parameters(): + skip_keys.add(f"embed_tokens.{k}") + for k, _ in self.sentence_encoder.embed_positions.named_parameters(): + skip_keys.add(f"embed_positions.{k}") + if self.sentence_encoder.layernorm_embedding is not None: + for ( + k, + _, + ) in self.sentence_encoder.layernorm_embedding.named_parameters(): + skip_keys.add(f"layernorm_embedding.{k}") + if self.sentence_encoder.layer_norm is not None: + for k, _ in self.sentence_encoder.layer_norm.named_parameters(): + skip_keys.add(f"layernorm_embedding.{k}") + + self.ema = EMA( + self.sentence_encoder, + ema_config, + skip_keys=skip_keys, + ) + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + + if self.ema is None and self.regression_head is not None: + logger.info(f"making ema teacher") + self.make_ema_teacher() + elif self.training and self.ema is not None: + if self.cfg.ema_decay != self.cfg.ema_end_decay: + if num_updates >= self.cfg.ema_anneal_end_step: + decay = self.cfg.ema_end_decay + else: + decay = get_annealed_rate( + self.cfg.ema_decay, + self.cfg.ema_end_decay, + num_updates, + self.cfg.ema_anneal_end_step, + ) + self.ema._set_decay(decay) + if self.ema.get_decay() < 1: + self.ema.step(self.sentence_encoder) + + def state_dict(self, destination=None, prefix="", keep_vars=False): + state = super().state_dict(destination, prefix, keep_vars) + if self.ema is not None: + state[prefix + "_ema"] = self.ema.fp32_params + return state + + def _load_from_state_dict(self, state_dict, prefix, *args, **kwargs): + if self.ema is not None: + k = prefix + "_ema" + assert k in state_dict + self.ema.restore(state_dict[k], True) + del state_dict[k] + return super()._load_from_state_dict(state_dict, prefix, *args, **kwargs) + + def forward( + self, + src_tokens, + target_tokens=None, + features_only=False, + return_all_hiddens=False, + masked_tokens=None, + **unused, + ): + """ + Args: + src_tokens (LongTensor): input tokens of shape `(batch, src_len)` + features_only (bool, optional): skip LM head and just return + features. If True, the output will be of shape + `(batch, src_len, embed_dim)`. + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + + Returns: + tuple: + - the LM output of shape `(batch, src_len, vocab)` + - a dictionary of additional data, where 'inner_states' + is a list of hidden states. Note that the hidden + states have shape `(src_len, batch, vocab)`. + """ + + x, extra = self.extract_features( + src_tokens, return_all_hiddens=return_all_hiddens + ) + + if features_only: + return x, extra + + assert target_tokens is not None + + with torch.no_grad(): + # use EMA parameter as the teacher + self.ema.model.eval() + + encoder_out = self.ema.model( + target_tokens, + return_all_hiddens=True, + ) + y = encoder_out["fc_results"] + + y = y[-self.average_top_k_layers :] + + permuted = False + if self.cfg.instance_norm_target_layer or self.cfg.batch_norm_target_layer: + y = [tl.permute(1, 2, 0) for tl in y] # TBC -> BCT + permuted = True + + if self.cfg.batch_norm_target_layer: + y = [ + F.batch_norm( + tl.float(), running_mean=None, running_var=None, training=True + ) + for tl in y + ] + + if self.cfg.instance_norm_target_layer: + y = [F.instance_norm(tl.float()) for tl in y] + + if permuted: + y = [tl.transpose(1, 2) for tl in y] # BCT -> BTC + + if self.cfg.layer_norm_target_layer: + y = [F.layer_norm(tl.float(), tl.shape[-1:]) for tl in y] + + y = sum(y) / len(y) + + if not permuted: + y = y.transpose(0, 1) + + if self.cfg.layer_norm_targets: + y = F.layer_norm(y.float(), y.shape[-1:]) + + if self.cfg.instance_norm_targets: + y = F.instance_norm(y.transpose(1, 2)).transpose(1, 2) + + masked_indices = src_tokens.eq(self.mask_idx) + + x = x[masked_indices] + y = y[masked_indices] + + x = self.regression_head(x) + + sz = x.size(-1) + if self.cfg.loss_beta == 0: + loss = F.mse_loss(x.float(), y.float(), reduction="none").sum(dim=-1) + else: + loss = F.smooth_l1_loss( + x.float(), y.float(), reduction="none", beta=self.cfg.loss_beta + ).sum(dim=-1) + + result = { + "losses": { + "main": loss.sum() / math.sqrt(sz) + if self.loss_scale <= 0 + else loss.sum() * self.loss_scale, + }, + "sample_size": loss.numel(), + } + + # logging other values + other_logs = { + "ema_decay": self.ema.get_decay() * 1000 + } + result["logs"] = other_logs + return result + + def extract_features(self, src_tokens, return_all_hiddens=False, **kwargs): + encoder_out = self.sentence_encoder( + src_tokens, + return_all_hiddens=return_all_hiddens, + token_embeddings=kwargs.get("token_embeddings", None), + ) + # T x B x C -> B x T x C + features = encoder_out["encoder_out"][0].transpose(0, 1) + inner_states = encoder_out["encoder_states"] if return_all_hiddens else None + return features, { + "inner_states": inner_states, + "encoder_embedding": encoder_out["encoder_embedding"][0], + } + + def output_layer(self, features, masked_tokens=None, **unused): + return self.lm_head(features, masked_tokens) + + def max_positions(self): + """Maximum output length supported by the encoder.""" + return self.cfg.max_positions diff --git a/examples/speech_recognition/new/infer.py b/examples/speech_recognition/new/infer.py index d8d87f20bb..f56e820ffa 100644 --- a/examples/speech_recognition/new/infer.py +++ b/examples/speech_recognition/new/infer.py @@ -422,6 +422,8 @@ def hydra_main(cfg: InferConfig) -> Union[float, Tuple[float, Optional[float]]]: if cfg.common.reset_logging: reset_logging() + utils.import_user_module(cfg.common) + # logger.info("Config:\n%s", OmegaConf.to_yaml(cfg)) wer = float("inf") diff --git a/examples/wav2vec/config/finetuning/base_1h.yaml b/examples/wav2vec/config/finetuning/base_1h.yaml index 14abc013bd..a0af1cfad7 100644 --- a/examples/wav2vec/config/finetuning/base_1h.yaml +++ b/examples/wav2vec/config/finetuning/base_1h.yaml @@ -6,8 +6,8 @@ common: log_interval: 200 checkpoint: - save_interval: 1000 - save_interval_updates: 50 + save_interval: 50 + save_interval_updates: 1000 keep_interval_updates: 1 no_epoch_checkpoints: true best_checkpoint_metric: wer diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 9433e56d08..9cd88ca76e 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -401,7 +401,7 @@ def compute_mask_indices( no_overlap: bool = False, min_space: int = 0, require_same_masks: bool = True, - pct_holes: float = 0.0, + mask_dropout: float = 0.0, ) -> np.ndarray: """ Computes random mask spans for a given shape @@ -421,6 +421,8 @@ def compute_mask_indices( min_masks: minimum number of masked spans no_overlap: if false, will switch to an alternative recursive algorithm that prevents spans from overlapping min_space: only used if no_overlap is True, this is how many elements to keep unmasked between spans + require_same_masks: if true, will randomly drop out masks until same amount of masks remains in each sample + mask_dropout: randomly dropout this percentage of masks in each example """ bsz, all_sz = shape @@ -514,8 +516,8 @@ def arrange(s, e, length, keep_length): for i, mask_idc in enumerate(mask_idcs): if len(mask_idc) > min_len and require_same_masks: mask_idc = np.random.choice(mask_idc, min_len, replace=False) - if pct_holes > 0: - num_holes = np.rint(len(mask_idc) * pct_holes).astype(int) + if mask_dropout > 0: + num_holes = np.rint(len(mask_idc) * mask_dropout).astype(int) mask_idc = np.random.choice( mask_idc, len(mask_idc) - num_holes, replace=False ) diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index d27e05cf1b..6d068d0dba 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -453,6 +453,16 @@ def upgrade_state_dict_named(self, state_dict, name): logger.info("Overwriting " + prefix + "classification_heads." + k) state_dict[prefix + "classification_heads." + k] = v + # adapt data2vec models + if "encoder._ema" in state_dict and "encoder.lm_head.weight" not in state_dict: + lm_state = self.encoder.lm_head.state_dict() + for k, v in lm_state.items(): + state_dict["encoder.lm_head." + k] = v + + for k in list(state_dict.keys()): + if k.startswith("encoder.regression_head") or k == "encoder._ema": + del state_dict[k] + class RobertaLMHead(nn.Module): """Head for masked language modeling.""" diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index 578f03d9de..739eb9df2c 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -46,7 +46,7 @@ class TransformerEncoderBase(FairseqEncoder): embed_tokens (torch.nn.Embedding): input embedding """ - def __init__(self, cfg, dictionary, embed_tokens): + def __init__(self, cfg, dictionary, embed_tokens, return_fc=False): self.cfg = cfg super().__init__(dictionary) self.register_buffer("version", torch.Tensor([3])) @@ -55,6 +55,7 @@ def __init__(self, cfg, dictionary, embed_tokens): cfg.dropout, module_name=module_name_fordropout(self.__class__.__name__) ) self.encoder_layerdrop = cfg.encoder.layerdrop + self.return_fc = return_fc embed_dim = embed_tokens.embedding_dim self.padding_idx = embed_tokens.padding_idx @@ -103,7 +104,9 @@ def __init__(self, cfg, dictionary, embed_tokens): self.layer_norm = None def build_encoder_layer(self, cfg): - layer = transformer_layer.TransformerEncoderLayerBase(cfg) + layer = transformer_layer.TransformerEncoderLayerBase( + cfg, return_fc=self.return_fc + ) checkpoint = cfg.checkpoint_activations if checkpoint: offload_to_cpu = cfg.offload_activations @@ -212,18 +215,27 @@ def forward_scriptable( x = x.transpose(0, 1) encoder_states = [] + fc_results = [] if return_all_hiddens: encoder_states.append(x) # encoder layers for layer in self.layers: - x = layer( + lr = layer( x, encoder_padding_mask=encoder_padding_mask if has_pads else None ) - if return_all_hiddens: + + if isinstance(lr, tuple) and len(lr) == 2: + x, fc_result = lr + else: + x = lr + fc_result = None + + if return_all_hiddens and not torch.jit.is_scripting(): assert encoder_states is not None encoder_states.append(x) + fc_results.append(fc_result) if self.layer_norm is not None: x = self.layer_norm(x) @@ -243,6 +255,7 @@ def forward_scriptable( "encoder_padding_mask": [encoder_padding_mask], # B x T "encoder_embedding": [encoder_embedding], # B x T x C "encoder_states": encoder_states, # List[T x B x C] + "fc_results": fc_results, # List[T x B x C] "src_tokens": [], "src_lengths": [src_lengths], } @@ -332,12 +345,13 @@ def upgrade_state_dict_named(self, state_dict, name): class TransformerEncoder(TransformerEncoderBase): - def __init__(self, args, dictionary, embed_tokens): + def __init__(self, args, dictionary, embed_tokens, return_fc=False): self.args = args super().__init__( TransformerConfig.from_namespace(args), dictionary, embed_tokens, + return_fc=return_fc, ) def build_encoder_layer(self, args): diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 8f41b60e0e..23c5ae2d91 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -174,6 +174,17 @@ class Wav2Vec2Config(FairseqDataclass): default=1, metadata={"help": "min space between spans (if no overlap is enabled)"}, ) + require_same_masks: bool = field( + default=True, + metadata={ + "help": "whether to number of masked timesteps must be the same across all " + "examples in a batch" + }, + ) + mask_dropout: float = field( + default=0.0, + metadata={"help": "percent of masks to unmask for each sample"}, + ) # channel masking mask_channel_length: int = field( @@ -227,6 +238,10 @@ class Wav2Vec2Config(FairseqDataclass): default=16, metadata={"help": "number of groups for convolutional positional embedding"}, ) + pos_conv_depth: int = field( + default=1, + metadata={"help": "depth of positional encoder network"}, + ) latent_temp: Tuple[float, float, float] = field( default=(2, 0.5, 0.999995), @@ -243,7 +258,7 @@ class Wav2Vec2Config(FairseqDataclass): # FP16 optimization required_seq_len_multiple: int = field( - default=1, + default=2, metadata={ "help": "pad the input to encoder such that the sequence length is divisible by multiple" }, @@ -434,6 +449,8 @@ def apply_mask( min_masks=2, no_overlap=self.no_mask_overlap, min_space=self.mask_min_space, + require_same_masks=self.cfg.require_same_masks, + mask_dropout=self.cfg.mask_dropout, ) mask_indices = torch.from_numpy(mask_indices).to(x.device) x = index_put(x, mask_indices, self.mask_emb) @@ -526,13 +543,13 @@ def compute_preds(self, x, y, negatives): y = y.unsqueeze(0) targets = torch.cat([y, negatives], dim=0) - logits = torch.cosine_similarity(x.float(), targets.float(), dim=-1).type_as(x) - + logits = torch.cosine_similarity(x.float(), targets.float(), dim=-1) logits = logits / self.logit_temp + logits = logits.type_as(x) if is_xla_tensor(logits) or neg_is_pos.any(): - fillval = -float(2 ** 30) if not hasattr(self, "_inftensor"): + fillval = -float(2 ** 30) self._inftensor = ( torch.tensor(fillval).to(x.device) if is_xla_tensor(logits) @@ -664,27 +681,32 @@ def forward( } if self.quantizer: - q = self.quantizer(y, produce_targets=False) - y = q["x"] - num_vars = q["num_vars"] - code_ppl = q["code_perplexity"] - prob_ppl = q["prob_perplexity"] - curr_temp = q["temp"] - - y = self.project_q(y) - if self.negatives_from_everywhere: - neg_cands = self.quantizer(unmasked_features, produce_targets=False)[ - "x" - ] + q = self.quantizer(unmasked_features, produce_targets=False) + y = q["x"] + num_vars = q["num_vars"] + code_ppl = q["code_perplexity"] + prob_ppl = q["prob_perplexity"] + curr_temp = q["temp"] + y = self.project_q(y) + negs, _ = self.sample_negatives( - neg_cands, - y.size(1), + y, + mask_indices[0].sum(), padding_count=padding_count, ) - negs = self.project_q(negs) + y = y[mask_indices].view(y.size(0), -1, y.size(-1)) else: + q = self.quantizer(y, produce_targets=False) + y = q["x"] + num_vars = q["num_vars"] + code_ppl = q["code_perplexity"] + prob_ppl = q["prob_perplexity"] + curr_temp = q["temp"] + + y = self.project_q(y) + negs, _ = self.sample_negatives( y, y.size(1), @@ -780,12 +802,17 @@ def get_extra_losses(self, net_output): return pen - def remove_pretraining_modules(self): + def remove_pretraining_modules(self, last_layer=None): self.quantizer = None self.project_q = None self.target_glu = None self.final_proj = None + if last_layer is not None: + self.encoder.layers = nn.ModuleList( + l for i, l in enumerate(self.encoder.layers) if i <= last_layer + ) + class ConvFeatureExtractionModel(nn.Module): def __init__( @@ -868,8 +895,27 @@ def forward(self, x): return x +def make_conv_pos(e, k, g): + pos_conv = nn.Conv1d( + e, + e, + kernel_size=k, + padding=k // 2, + groups=g, + ) + dropout = 0 + std = math.sqrt((4 * (1.0 - dropout)) / (k * e)) + nn.init.normal_(pos_conv.weight, mean=0, std=std) + nn.init.constant_(pos_conv.bias, 0) + + pos_conv = nn.utils.weight_norm(pos_conv, name="weight", dim=2) + pos_conv = nn.Sequential(pos_conv, SamePad(k), nn.GELU()) + + return pos_conv + + class TransformerEncoder(nn.Module): - def build_encoder_layer(self, args): + def build_encoder_layer(self, args: Wav2Vec2Config): if args.layer_type == "transformer": layer = TransformerSentenceEncoderLayer( embedding_dim=self.embedding_dim, @@ -898,27 +944,49 @@ def build_encoder_layer(self, args): layer = checkpoint_wrapper(layer) return layer - def __init__(self, args): + def __init__(self, args: Wav2Vec2Config): super().__init__() self.dropout = args.dropout self.embedding_dim = args.encoder_embed_dim self.required_seq_len_multiple = args.required_seq_len_multiple - self.pos_conv = nn.Conv1d( - self.embedding_dim, - self.embedding_dim, - kernel_size=args.conv_pos, - padding=args.conv_pos // 2, - groups=args.conv_pos_groups, - ) - dropout = 0 - std = math.sqrt((4 * (1.0 - dropout)) / (args.conv_pos * self.embedding_dim)) - nn.init.normal_(self.pos_conv.weight, mean=0, std=std) - nn.init.constant_(self.pos_conv.bias, 0) + pos_conv_depth = getattr(args, "pos_conv_depth", 1) + if pos_conv_depth > 1: + num_layers = args.pos_conv_depth + k = max(3, args.conv_pos // num_layers) - self.pos_conv = nn.utils.weight_norm(self.pos_conv, name="weight", dim=2) - self.pos_conv = nn.Sequential(self.pos_conv, SamePad(args.conv_pos), nn.GELU()) + def make_conv_block(e, k, g, l): + return nn.Sequential( + *[ + nn.Sequential( + nn.Conv1d( + e, + e, + kernel_size=k, + padding=k // 2, + groups=g, + ), + SamePad(k), + TransposeLast(), + LayerNorm(e, elementwise_affine=False), + TransposeLast(), + nn.GELU(), + ) + for _ in range(l) + ] + ) + + self.pos_conv = make_conv_block( + self.embedding_dim, k, args.conv_pos_groups, num_layers + ) + + else: + self.pos_conv = make_conv_pos( + self.embedding_dim, + args.conv_pos, + args.conv_pos_groups, + ) self.layers = nn.ModuleList( [self.build_encoder_layer(args) for _ in range(args.encoder_layers)] @@ -937,7 +1005,13 @@ def forward(self, x, padding_mask=None, layer=None): return x, layer_results - def extract_features(self, x, padding_mask=None, tgt_layer=None): + def extract_features( + self, + x, + padding_mask=None, + tgt_layer=None, + min_layer=0, + ): if padding_mask is not None: x = index_put(x, padding_mask, 0) @@ -968,22 +1042,13 @@ def extract_features(self, x, padding_mask=None, tgt_layer=None): layer_results = [] r = None for i, layer in enumerate(self.layers): - dropout_probability = np.random.random() + dropout_probability = np.random.random() if self.layerdrop > 0 else 1 if not self.training or (dropout_probability > self.layerdrop): - x, z = layer(x, self_attn_padding_mask=padding_mask, need_weights=False) - if tgt_layer is not None: - # unpad if needed - if pad_length > 0: - layer_results.append( - ( - x[:-pad_length], - z[:, :-pad_length, :-pad_length] - if z is not None - else z, - ) - ) - else: - layer_results.append((x, z)) + x, (z, lr) = layer( + x, self_attn_padding_mask=padding_mask, need_weights=False + ) + if i >= min_layer: + layer_results.append((x, z, lr)) if i == tgt_layer: r = x break @@ -993,10 +1058,20 @@ def extract_features(self, x, padding_mask=None, tgt_layer=None): # T x B x C -> B x T x C x = x.transpose(0, 1) + # undo paddding if pad_length > 0: x = x[:, :-pad_length] + def undo_pad(a, b, c): + return ( + a[:-pad_length], + b[:-pad_length] if b is not None else b, + c[:-pad_length], + ) + + layer_results = [undo_pad(*u) for u in layer_results] + return x, layer_results def max_positions(self): @@ -1105,7 +1180,7 @@ def __init__( self, embedding_dim: float = 768, ffn_embedding_dim: float = 3072, - num_attention_heads: float = 8, + num_attention_heads: int = 8, dropout: float = 0.1, attention_dropout: float = 0.1, activation_dropout: float = 0.1, @@ -1164,6 +1239,7 @@ def forward( value=x, key_padding_mask=self_attn_padding_mask, attn_mask=self_attn_mask, + need_weights=False, ) x = self.dropout1(x) x = residual + x @@ -1173,6 +1249,9 @@ def forward( x = self.activation_fn(self.fc1(x)) x = self.dropout2(x) x = self.fc2(x) + + layer_result = x + x = self.dropout3(x) x = residual + x else: @@ -1181,6 +1260,7 @@ def forward( key=x, value=x, key_padding_mask=self_attn_padding_mask, + need_weights=False, ) x = self.dropout1(x) @@ -1192,8 +1272,11 @@ def forward( x = self.activation_fn(self.fc1(x)) x = self.dropout2(x) x = self.fc2(x) + + layer_result = x + x = self.dropout3(x) x = residual + x x = self.final_layer_norm(x) - return x, attn + return x, (attn, layer_result) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index d2a039d2b8..3612609418 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -6,6 +6,7 @@ import contextlib import copy import math +import logging import re from argparse import Namespace from dataclasses import dataclass, field @@ -32,6 +33,9 @@ from fairseq.tasks import FairseqTask +logger = logging.getLogger(__name__) + + @dataclass class Wav2Vec2AsrConfig(FairseqDataclass): w2v_path: str = field( @@ -107,6 +111,17 @@ class Wav2Vec2AsrConfig(FairseqDataclass): default=1, metadata={"help": "min space between spans (if no overlap is enabled)"}, ) + require_same_masks: bool = field( + default=True, + metadata={ + "help": "whether to number of masked timesteps must be the same across all " + "examples in a batch" + }, + ) + mask_dropout: float = field( + default=0.0, + metadata={"help": "percent of masks to unmask for each sample"}, + ) # channel masking mask_channel_length: int = field( @@ -344,6 +359,8 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): "attention_dropout": cfg.attention_dropout, "mask_length": cfg.mask_length, "mask_prob": cfg.mask_prob, + "require_same_masks": getattr(cfg, "require_same_masks", True), + "pct_holes": getattr(cfg, "mask_dropout", 0), "mask_selection": cfg.mask_selection, "mask_other": cfg.mask_other, "no_mask_overlap": cfg.no_mask_overlap, @@ -368,13 +385,19 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): w2v_args.criterion = None w2v_args.lr_scheduler = None cfg.w2v_args = w2v_args + + logger.info(w2v_args) + else: state = None w2v_args = cfg.w2v_args if isinstance(w2v_args, Namespace): cfg.w2v_args = w2v_args = convert_namespace_to_omegaconf(w2v_args) - assert cfg.normalize == w2v_args.task.normalize, ( + model_normalized = w2v_args.task.get( + "normalize", w2v_args.model.get("normalize", False) + ) + assert cfg.normalize == model_normalized, ( "Fine-tuning works best when data normalization is the same. " "Please check that --normalize is set or unset for both pre-training and here" ) @@ -387,11 +410,11 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): task = tasks.setup_task(w2v_args.task) model = task.build_model(w2v_args.model, from_checkpoint=True) + model.remove_pretraining_modules() + if state is not None and not cfg.no_pretrained_weights: self.load_model_weights(state, model, cfg) - model.remove_pretraining_modules() - super().__init__(task.source_dictionary) d = w2v_args.model.encoder_embed_dim @@ -442,6 +465,8 @@ def load_model_weights(self, state, model, cfg): model.load_state_dict(new_big_dict, strict=False) else: + if "_ema" in state["model"]: + del state["model"]["_ema"] model.load_state_dict(state["model"], strict=True) def set_num_updates(self, num_updates): diff --git a/fairseq/modules/conformer_layer.py b/fairseq/modules/conformer_layer.py index f749eb4ff0..4e29b0d88f 100644 --- a/fairseq/modules/conformer_layer.py +++ b/fairseq/modules/conformer_layer.py @@ -275,10 +275,13 @@ def forward( residual = x x = self.ffn2(x) + + layer_result = x + x = x * 0.5 + residual x = self.final_layer_norm(x) - return x, attn + return x, (attn, layer_result) class ConformerWav2Vec2EncoderLayer(ConformerEncoderLayer): diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 4a17d7180b..50025e0454 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -32,9 +32,10 @@ class TransformerEncoderLayerBase(nn.Module): args (argparse.Namespace): parsed command-line arguments """ - def __init__(self, cfg): + def __init__(self, cfg, return_fc=False): super().__init__() self.cfg = cfg + self.return_fc = return_fc self.embed_dim = cfg.encoder.embed_dim self.quant_noise = cfg.quant_noise.pq self.quant_noise_block_size = cfg.quant_noise.pq_block_size @@ -212,10 +213,16 @@ def forward( x = self.activation_fn(self.fc1(x)) x = self.activation_dropout_module(x) x = self.fc2(x) + + fc_result = x + x = self.dropout_module(x) x = self.residual_connection(x, residual) if not self.normalize_before: x = self.final_layer_norm(x) + + if self.return_fc and not torch.jit.is_scripting(): + return x, fc_result return x diff --git a/fairseq/tasks/masked_lm.py b/fairseq/tasks/masked_lm.py index 0c08132fb7..d83dca6c1f 100644 --- a/fairseq/tasks/masked_lm.py +++ b/fairseq/tasks/masked_lm.py @@ -101,6 +101,13 @@ class MaskedLMConfig(FairseqDataclass): ) seed: int = II("common.seed") + include_target_tokens: bool = field( + default=False, + metadata={ + "help": "include target tokens in model input. this is used for data2vec" + }, + ) + @register_task("masked_lm", dataclass=MaskedLMConfig) class MaskedLMTask(FairseqTask): @@ -193,21 +200,27 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): with data_utils.numpy_seed(self.cfg.seed): shuffle = np.random.permutation(len(src_dataset)) + target_dataset = RightPadDataset( + tgt_dataset, + pad_idx=self.source_dictionary.pad(), + ) + + input_dict = { + "src_tokens": RightPadDataset( + src_dataset, + pad_idx=self.source_dictionary.pad(), + ), + "src_lengths": NumelDataset(src_dataset, reduce=False), + } + if self.cfg.include_target_tokens: + input_dict["target_tokens"] = target_dataset + self.datasets[split] = SortDataset( NestedDictionaryDataset( { "id": IdDataset(), - "net_input": { - "src_tokens": RightPadDataset( - src_dataset, - pad_idx=self.source_dictionary.pad(), - ), - "src_lengths": NumelDataset(src_dataset, reduce=False), - }, - "target": RightPadDataset( - tgt_dataset, - pad_idx=self.source_dictionary.pad(), - ), + "net_input": input_dict, + "target": target_dataset, "nsentences": NumSamplesDataset(), "ntokens": NumelDataset(src_dataset, reduce=True), }, From fc758bbf79ed7c79cfa8c1dbc4ffba0820123339 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 20 Jan 2022 08:47:44 -0800 Subject: [PATCH 552/774] fix readme (#2939) Summary: minor fix Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2939 Reviewed By: michaelauli Differential Revision: D33685330 Pulled By: alexeib fbshipit-source-id: 4d6c6edb1fab9d0d56a6e03c0a2b43a864f1d07a --- examples/data2vec/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/data2vec/README.md b/examples/data2vec/README.md index 59cc888450..a0aab16fa2 100644 --- a/examples/data2vec/README.md +++ b/examples/data2vec/README.md @@ -27,8 +27,6 @@ data2vec Base | No fine-tuning | Books + Wiki | [download](https://dl.fbaipublic ## Training a new speech model with the CLI tools -Below is copied from thw wav2vec README - needs adapting - Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) ### Prepare training data manifest: From 5fd38e3d5b1e5163aeace2a43d4a481fbbf1d83e Mon Sep 17 00:00:00 2001 From: Tony Bruguier <tonybruguier@fb.com> Date: Fri, 21 Jan 2022 09:26:50 -0800 Subject: [PATCH 553/774] Fix breakage from D33649708 Summary: https://www.internalfb.com/diff/D33649708 (https://github.com/pytorch/fairseq/commit/995c204337d16a6146a433cee360e5a5bfbc9a6f)?src_version_fbid=1030479880843010&dst_version_fbid=247617347518523&transaction_fbid=1601081576900014 Reviewed By: alexeib Differential Revision: D33696937 fbshipit-source-id: 9a17610e3f4eb3dd2b2131a3f9fb42732a31b47f --- fairseq/checkpoint_utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index f93bf6622e..73374bedf1 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -18,8 +18,6 @@ import numpy as np import torch -from omegaconf import DictConfig, OmegaConf, open_dict - from fairseq.data import data_utils from fairseq.dataclass.configs import CheckpointConfig from fairseq.dataclass.utils import ( @@ -29,6 +27,7 @@ from fairseq.distributed.fully_sharded_data_parallel import FSDP, has_FSDP from fairseq.file_io import PathManager from fairseq.models import FairseqDecoder, FairseqEncoder +from omegaconf import DictConfig, OmegaConf, open_dict logger = logging.getLogger(__name__) @@ -216,7 +215,7 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): cfg.save_dir, "checkpoint_last{}.pt".format(suffix) ) first_launch = not PathManager.exists(checkpoint_path) - if first_launch and cfg.get("continue_once", None) is not None: + if first_launch and getattr(cfg, "continue_once", None) is not None: checkpoint_path = cfg.continue_once elif cfg.finetune_from_model is not None and first_launch: # if there is no last checkpoint to restore, start the finetune from pretrained model From 509e83e4324110ffcca491460b2feb3169c628d0 Mon Sep 17 00:00:00 2001 From: Victoria X Lin <xilin@cs.washington.edu> Date: Mon, 24 Jan 2022 15:50:42 -0800 Subject: [PATCH 554/774] Add XGLM downstream task evaluation examples (#4154) Summary: 1. Add XGLM downstream task evaluation examples 2. Add bibtex citation of XGLM arXiv paper Pull Request resolved: https://github.com/pytorch/fairseq/pull/4154 Reviewed By: xianxl Differential Revision: D33748846 Pulled By: todpole3 fbshipit-source-id: ce4dfce2fccf92742f124f12a0d9a388280320fa --- examples/xglm/README.md | 131 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/examples/xglm/README.md b/examples/xglm/README.md index a4fc755d0f..8e65053174 100644 --- a/examples/xglm/README.md +++ b/examples/xglm/README.md @@ -2,7 +2,7 @@ ## Introduction -In this work, we train multilingual generative language models, dubbed XGLM, on a balanced corpus covering a diverse set of languages, and study their few- and zero-shot learning capabilities in a wide range of tasks. Our largest model with 7.5 billion parameters sets new state of the art in few-shot learning on more than 20 representative languages, outperforming GPT-3 of comparable size in multilingual commonsense reasoning (+7.4 accuracy points for 0-shot, +9.4 for 4-shot) and natural language inference (+5.4 for 0-shot, +5.4 for 4-shot). We have included a [model card](model_card.md) of XGLM for transparency and accountability. +In this work, we train a family of multilingual generative language models, dubbed XGLM, on a balanced corpus covering a diverse set of languages, and study their few- and zero-shot learning capabilities in a wide range of tasks. Our largest model with 7.5 billion parameters sets new state of the art in few-shot learning on more than 20 representative languages, outperforming GPT-3 of comparable size in multilingual commonsense reasoning (+7.4 accuracy points for 0-shot, +9.4 for 4-shot) and natural language inference (+5.4 for 0-shot, +5.4 for 4-shot). We have included a [model card](model_card.md) of XGLM for transparency and accountability. ## Data and Languages XGLM models are trained on a new multilingual corpus extracted from CommonCrawl (CC100-XL), a significantly larger multilingual dataset covering 68 Common Crawl (CC) snapshots (from [Summer 2013](http://commoncrawl.org/2013/11/new-crawl-data-available/) to [March/April 2020](https://commoncrawl.org/2020/04/march-april-2020-crawl-archive-now-available/) consisting of 134 languages. The detailed languages and data statistics are reported in the paper (Table A.1). @@ -18,7 +18,132 @@ Model | Layers | Model Dim | Languages | Download `XGLM 4.5B` | 48 | 2048 | trained on 134 languages| [xglm.4.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.4.5B.tar.gz) ## Evaluation -Coming soon. + +### Example (COPA) + +The following snippet show how to evaluate our models on the Choice of Plausible Alternatives (COPA) task, using examples in English, Chinese and Hindi. + +```python +data_samples = { + 'en': [ + { + "premise": "I wanted to conserve energy.", + "choice1": "I swept the floor in the unoccupied room.", + "choice2": "I shut off the light in the unoccupied room.", + "question": "effect", + "label": "1" + }, + { + "premise": "The flame on the candle went out.", + "choice1": "I blew on the wick.", + "choice2": "I put a match to the wick.", + "question": "cause", + "label": "0" + } + ], + 'zh': [ + { + "premise": "我想节约能源。", + "choice1": "我在空着的房间里扫了地板。", + "choice2": "我把空房间里的灯关了。", + "question": "effect", + "label": "1" + }, + { + "premise": "蜡烛上的火焰熄灭了。", + "choice1": "我吹灭了灯芯。", + "choice2": "我把一根火柴放在灯芯上。", + "question": "cause", + "label": "0" + } + ], + 'hi': [ + { + "premise": "M te vle konsève enèji.", + "choice1": "Mwen te fin baleye chanm lib la.", + "choice2": "Mwen te femen limyè nan chanm lib la.", + "question": "effect", + "label": "1" + }, + { + "premise": "Flam bouji a te etenn.", + "choice1": "Mwen te soufle bouji a.", + "choice2": "Mwen te limen mèch bouji a.", + "question": "cause", + "label": "0" + } + ] +} +``` +In this example, we format the examples use the non-verbal prompts `{premise}\n{choice1}` and `{premise}\n{choice2}`, which are shared by all three languages. +```python +from fairseq.models.transformer_lm import TransformerLanguageModel + +model_dir = 'path_to_decompressed_tar_gz_dir' +lm = TransformerLanguageModel.from_pretrained(model_dir, bpe='sentencepiece') +lm = lm.eval() +lm = lm.half() +lm = lm.cuda() + +def get_logprobs(prompt): + import re + prompt = re.sub('\n+' , '\n', prompt) # collapse repeated newlines, which indicate separate documents + return lm.score(prompt, replace_newlines_with_eos=True)['positional_scores'] + +# Zero-shot evaluation for the Choice of Plausible Alternatives (COPA) task. +# A return value of 0 indicates that the first alternative is more plausible, +# while 1 indicates that the second alternative is more plausible. +def COPA_eval(prompt, alternative1, alternative2): + lprob1 = get_logprobs(prompt + "\n" + alternative1).sum() + lprob2 = get_logprobs(prompt + "\n" + alternative2).sum() + return 0 if lprob1 > lprob2 else 1 + +for lang in ['en', 'zh', 'hi']: + for idx, example in enumerate(data_samples[lang]): + predict = COPA_eval(example["premise"], example["choice1"], example["choice2"]) + print(f'{lang}-{idx}', predict, example['label']) + +# en-0 1 1 +# en-1 0 0 +# zh-0 1 1 +# zh-1 0 0 +# hi-0 1 1 +# hi-1 0 0 +``` ## Citation -Coming soon. +``` +@article{DBLP:journals/corr/abs-2112-10668, + author = {Xi Victoria Lin and + Todor Mihaylov and + Mikel Artetxe and + Tianlu Wang and + Shuohui Chen and + Daniel Simig and + Myle Ott and + Naman Goyal and + Shruti Bhosale and + Jingfei Du and + Ramakanth Pasunuru and + Sam Shleifer and + Punit Singh Koura and + Vishrav Chaudhary and + Brian O'Horo and + Jeff Wang and + Luke Zettlemoyer and + Zornitsa Kozareva and + Mona T. Diab and + Veselin Stoyanov and + Xian Li}, + title = {Few-shot Learning with Multilingual Language Models}, + journal = {CoRR}, + volume = {abs/2112.10668}, + year = {2021}, + url = {https://arxiv.org/abs/2112.10668}, + eprinttype = {arXiv}, + eprint = {2112.10668}, + timestamp = {Tue, 04 Jan 2022 15:59:27 +0100}, + biburl = {https://dblp.org/rec/journals/corr/abs-2112-10668.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +``` From 4a7835b79423b152938e90b88224dac499560d11 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Mon, 24 Jan 2022 16:20:35 -0800 Subject: [PATCH 555/774] Hubert unit test (#2766) Summary: ## What does this PR do? - Add unit test for HuBERT - update model arg to comply with wav2vec to TranformerEncoder Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/2766 Reviewed By: Abdel-rahmanMohamed Differential Revision: D32965218 Pulled By: wnhsu fbshipit-source-id: 036a1644179c35b875c9ba30d75b4ef039fb328f --- examples/hubert/README.md | 6 +- examples/hubert/tests/6313-76958-0021.flac | Bin 0 -> 223912 bytes examples/hubert/tests/sample.base.L9.km500.km | 1 + examples/hubert/tests/sample.base.L9.len | 1 + examples/hubert/tests/sample.base.L9.npy | Bin 0 -> 1831104 bytes examples/hubert/tests/sample.large.L20.len | 1 + examples/hubert/tests/sample.large.L20.npy | Bin 0 -> 2441408 bytes examples/hubert/tests/sample.tsv | 2 + examples/hubert/tests/sample.xlarge.L30.len | 1 + examples/hubert/tests/sample.xlarge.L30.npy | Bin 0 -> 3051712 bytes .../hubert/tests/test_feature_and_unit.sh | 91 ++++++++++++++++++ 11 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 examples/hubert/tests/6313-76958-0021.flac create mode 100644 examples/hubert/tests/sample.base.L9.km500.km create mode 100644 examples/hubert/tests/sample.base.L9.len create mode 100644 examples/hubert/tests/sample.base.L9.npy create mode 100644 examples/hubert/tests/sample.large.L20.len create mode 100644 examples/hubert/tests/sample.large.L20.npy create mode 100644 examples/hubert/tests/sample.tsv create mode 100644 examples/hubert/tests/sample.xlarge.L30.len create mode 100644 examples/hubert/tests/sample.xlarge.L30.npy create mode 100644 examples/hubert/tests/test_feature_and_unit.sh diff --git a/examples/hubert/README.md b/examples/hubert/README.md index f88a34dc3c..6695d81971 100644 --- a/examples/hubert/README.md +++ b/examples/hubert/README.md @@ -1,9 +1,9 @@ # HuBERT ## Pre-trained and fine-tuned (ASR) models -Model | Pretraining Data | Finetuning Dataset | Model -|---|---|---|--- -HuBERT Base (~95M params) | [Librispeech](http://www.openslr.org/12) 960 hr | No finetuning (Pretrained Model) | [download](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) +Model | Pretraining Data | Finetuning Dataset | Model | Quantizer +|---|---|---|---|--- +HuBERT Base (~95M params) | [Librispeech](http://www.openslr.org/12) 960 hr | No finetuning (Pretrained Model) | [download](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) | [L9 km500](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960_L9_km500.bin) HuBERT Large (~316M params) | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning (Pretrained Model) | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k.pt) HuBERT Extra Large (~1B params) | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | No finetuning (Pretrained Model) | [download](https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k.pt) HuBERT Large | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k_finetune_ls960.pt) diff --git a/examples/hubert/tests/6313-76958-0021.flac b/examples/hubert/tests/6313-76958-0021.flac new file mode 100644 index 0000000000000000000000000000000000000000..e644b19871f16c12a29de08d95081e7ca53067e7 GIT binary patch literal 223912 zcmeF%^-o;g7btw(-JwusV1U7;xD^>>26uP2;!Xu0+y-}diaQi2ZpFQ{xI>{hE!^ju zym^!RC)}j#my?sMo$T|;PWC!$Z(C&xStKMR1|lRPBqU5qB=S(yL!@6wC`amQ{POAz zc~tt!#p@~${VZ9iNJyanGXJmmZ_NJ!#qIxl4muMdp&=oG0sp;w*x1^5*u1l{0XREY z$}3CD0(iOjxOf44JUl`?BD_NX8xoB4zs!H}PvD=xKY@P&{{;RC{1f;m@K4~Mz(0Y1 z0{;a53H%fIC-6_;pTIwXe**sm{t5gO_$TmB;Ge)hfqw%31pW#9zb^1{KZJ$ks*Z&D z@`8klgp7pp^73-~^7!)H!n{lxWOj+9u!a2P^r;>L!Ox<h79|g>cE~6q#>QS8e44LZ z{t1xz1&@>J0iLlsm@QqZs9IITDPcUt_>&ln06CX!yG0!qLg|O8IV8uZV%@#xUjpCu z=z9KM6tuOXr~&jFq8q-MK>w5~Qks9HBdZ-uJxRb|qP?^+#Tf}!eM{a6%Q2O!-<}Df zjOK5~aUCWD19}S?2bWQ_62`+ZKn<xA1Qz|qs#8p+4!v=Ic22XOO`?ewL^V!i2N|CM zf|`J&-Y9OFaH2q#=)f^Raz&LE>a>=4yjYa>z;){2V4^!Z+ykz)8Q=<@``~3kRnr%5 zrM3Isi?vRF!h|o>+9EJV*j7?OuVfH`wUr@2q5}N*x(a7&096&J8PyiMqoPzO1My5j zOzk?CGkjn%SIhK4lMT}K=&FN~BNo4_tdvk!YUC!TxPRV+PP)yLgIBlrqI5MisN3Xp z3;73EM?hCajnoS@i{#bv=%1&0WWR)j)HD(hPs&A-igZoS;)lFJVNZpk$M6Kww<GpN z{AGy4c4xjv!7%vQI4W7y8xn>b3kezT2MZ>yywx*0_De#97X4F_UPWzYN0Z~k4g+%E zB~39n_$*BJNT}I>4oJx8Lh!9w_RN&Nv&xm!oiE0kSZ4r0R6GdHrL|cUtJixuO0001 zTZ~L7uz67h$Yj-`Cd4wBA+0#Y<S4g>BB!1R9*)=NO%l#y=Yu*jx#dLmSNaUYGL9?@ zVS;N<OC(f<@-KXJdWoYA6OJ8{kO71|>%1+w^VQ<@F#w^=EnXL0%gZknQ5JEI^}2@V zOD;$SRICV9-7Xz*TIIR2?kR6rs*4cWD83uW;<(?>-8&KMDhz)Jk(959O#guab`!zm zj-cwB#~xvl+;z)<W?RD8O+OfO_G6O;kf(r4C_1b)y$N|BtneJK#B^nLxT@jN1iM<@ z?vW}@ja0E+#_#}>e!KR&xfLcG-cuQ5RNcK!-Q=u17)rHCDSLt?35)O^FA>xHAume2 z8zcUhKmYr43LP>97L79M=>fqef%M2It&VuIure&Yt%WudozvR(xXh@S?;pj^=q@Kz zO|wH6KaLufzT5Ye1A6~iVHtHc>C(2Nk@jlrX#ci4Pqqp8#_P_F%k#GV764GJp$T@t zky_uM?$HU;)?zd6)HF<nMXJjM@Zwlu1_<90>+s#}Ii@z`KF!z`#JjS!-Q+e9MUq9E z&80@L%|(A6>%I(QaL9!yU0Nh}ei>V5(^V+K!5J)wV|2@s^I_#L{!75D0OComkd`$@ z55??EJ(0Q&3uPViywguc_ykgKfhdMbAxk(7!*_69K;~Yvi>kO~fxwtYNgbQtXNGf1 zWXFrepBW{8MjHHO_~-n_-`(g8P*`P^ow4*5gyUJ7A98H`PByvFBmlU;R9AJE-YnSc zd#mM?4oEIiwQHrwl~<!Ma-m>C0s9(LHo^QR034L$!h$%Cih8AfZ3Xa^G-i%lu|AR# z2UTEjgxhz_5MJaQq<%{&KN5U5B6}$x^8Liom*BL!&n~$eO^7m{Np|8`!<_8fjO@oj ziySkL_JI#Mnry<+d~VzoM{Pm-ovxs<?UC8-pb#hBXaha_=S5cZQN@CnW=8_;&T+W} zEo=8T?e{7wziIq24Whi{34^U_aykt}Oxy&uAfkm+Lx3n-lf$=gw1@{>UOb~wsA!uL zMV)SXQg`x}2Ci&Dst;V1GOR&fF@i`%9!nX$v2wxJP@8865&8kb!t#7`DX*t8xnsgg ze>~@kH|#eInX6YgPQ7E2kXUdRfe?#UDF{Rxl9G)~pT&U6G!Z3lW+1<LzV8n845Q4{ z(DCMqud%aO_d#%nDF6aukippzWXSz^`DCv1x^&q7q^6Cprskxq65h(B2z_>$DQtAT zh27KVR>=bx5<3qOHsUD#C^yvBq-mTv&XDmpj7V>rd{*fdZmYAJIYY;vKl<&;*0WnQ zL#M|Blw4}IkG(FXB7UKjenY&JdlTy6!d$Vbv=pzYs4X+$GNRgeDnzn{?4f7ng2F06 zlk9__Drp&Y^%UidSnQ4EH0KU@1pxTF{LZ-A*opV^!LRaR`LVgO77&psM^*W;qJ{zw z8;PA6dP{}#VQ}Ya*f`z_982?hyyl6wcsz$|Pnk%1mjN{6tp_=Xg8mBs%*5Aq(xO$l z8VIwhJpgu*Rjwj5cjpMc`o!KVR{|SZQNaR}9Sr+>8;PM6P>9&OG`}C?HSXzNnr*_# zqg=TyW`jP^#eK5yybhZ*jo5(MA(OHY`feb*uIFbcS4Z)*qK;Mcv|=k2JpYQMmS$95 zLoGZDiiXAB`TqJ%aTi>n=@s6&tda?}(9P@~Ufdo#lYgzJc%*e5T}6G9e#|}<FJpJI zb4ve=-o%;9sx~z;N~3dx!>yGHV(OJAdoI8tR8#!7$hAe=Ai9`O6o$?md9rFs(zw5R zu2AaBU#HmOXdW^d_1~r-eY#&L{5i~{GSLhZvK!{NX#ta4XnB@A!3su<C;|Zf`Jd87 z2uVOlVh}#ot&^u=sAh~FVIlQex)-=kHUga!p`U^k{;k%0u30PZN}`+`U3OsZS7{EB zVcH-pzVVI0d-~nW1XTu(an=wsZQdt3+zg^f(juykJ^Y}nh0g5*1td%43gH{Zxzcyh z>QCHlqjD#^;VA~_jC+bqH6pX3)5d%B;g)WmityCL3Is%1dbrBbU{n-OnTA_aN&Yo! zEs?^E28d?FFp=j%g>2|G$2YP|rrVDp%|8Upt6T^)MG5)}#R;YVNF^@ekV$6f3m|Ej z>x&1ofo)7268A_KtSeLHe{qn{lw<^xs4<8=XHpnx9gW~YyO-Z=U-==heshE+MknAm z)ZHYNrdt~`%zs700U2UhG;403DcIjc&Q3w?zd(_(18_J5Xish`@XQ_Q$2AM_Sl_o_ zY%?;u*uW#p$rT1Vz;Fi5<!zFj5z9udvl8ki0lnw2s3od_A53<}1+zQ%B@KP8D*I~e z3#)L694RuE=6zLO<Nm#^-BqwOMg|~Kulm)}pUpxkMrP*^NfYgkv;GeHmNbL;&YgE; zx4>o@Qwt@z<0=hLMEHmNNNyi}A;pZI0CEfsLYpfxNS&q}o;-t2Sh|~DD|zLV4AVB5 zc4el!o6KEODh$vEcXVNj6E*Lu|B8XTYw+O~=Z;l?<wz?JH>p6R2yT-h>*iO+KxR2> z9*T02;cYne-3A<=6)nEtfW__O5{wRzBP-N3AV&svaBqd<NFVy5v$l;g!~=M3ByRN# zh(~2Hn%b-lNXK?+71o*rX?Eo{n6qNNMAN5uF?kxn^+l4Fsy(JRSz1h#bCpeEge1q! z6x!SqZUvEhN=62whA8B}@`&{}?=B30^0+uFBR~rBkpC5l$o7zzqnC}Bkrr@xQffx! z1zf;}G#Z`lw!te9ed9xmi@ms#KBzAC@2Y9%MCs9P7#?oGXYzFG?sse3CpVO2MCLOC z-&mu6P7X9+|Gj}eetwNdK{dQZ?J83`XqGAy7AG+_4gd2)uZ;$Z3nZja7@Ek|@pleS zG|DP-YIbXojuhcc`pEcY%2-^{sadyaxLQCnDnf}ZuDZe?dsADgHC}#E_a;=a@_Ulm z`N?v?<9@g0q}GG4*M>XI@uYPrsZk}6%S0nZ(Y}RN0n6>v6gnm5Gn1-aCHE>KQ}84U zY8nOO5_Ly-Uqx${7JoyZwg~0QbtW$ovmH*G>CE5(uwxk-@>}c(%h0KT>PaHuWYnkn zrqe&%K>!@02)1QcG_#D(xWsBLB5@LFWc3VfIWU<_d!<U+S$gR~)v{Ltuy&lJr6P*d zexn~qD4}BLoJ-C=g^<;DU@#rII$dWGuxy37F6`j)SYmJP&D8yEuHT0m@iN48sX>d> zVYjC5w?rAfGbceGCCV~}?B&AsVSm{*=$K@dcGMTg!iVpC(3{murggo!O!CLS87QzP zys>Ag8{o;gtTABIIeThk*+Nhbk@#<K*!P-<wL3ZmjtYRno(x&|Z(}rAU)xnZ8yJ~7 zzA8CyZV(tYV9cR#D~SRrmM)RLB9`mXtduGYr7N~R2#b@JFLk!jove#S0Io;XAT00t zdTdNQs%}T|cuEX>4>e+CJyg|wF0LPOgt1U?&@qz5m7I>S3SovqGh<0YK2lXSS)mUZ zCucnU=paQ3Kc@GS!a5;1SY%#lAoS3iz2I*=jFs7G;cRtbBS+cm+<<5PloP*Vgw%Fu zY&u#AX?+T{NWC;Nh6zX@fuoS)m>7-Sic)(c2ImaO8s3^!!spwg8cs6jqRMAlz8&$} z!tz%Z13DRCvX>KA0NY|hc3?@mRH0r&R+!H>A`KPF@u>h{uAaqALOr9WcsM&!csHIR zBk4CQiv#`+EBBgjX=e&qZ}j^sG`c2v9_ANca>Jb3Jm(ZXI3HBM9VgP39MSsad&<S; zqW;$*Y{N@$%~GwHaWWW`YuIn-{Kp+Tui2bOk${V3YKX{(s6sn7D;Sl^!BnPqM-L|1 zabi5NUgcdB2S0~>_^frMpi$0Jv^sw%feg|2-`>lT(`<#fYY8BdMjg2>8^bA4P;t~l zgUH1kZ>2nJDOx|7?3TsKKHA$bZv*Qa5q})~8BP+Qar!ydyH%yga=4~coCnrOinaU9 zI0sU9;~}99QLvixRjU9%ZAG%ovYVX*xBoJ}3kcK<Lz)|+q@!niOH|BdtQA)Bpv87v zB_nBGT8ZYv(|c?hwlecIoFh$io(X#Ax!f5UFM%PHI|<Ro+0v9^4X#lMtCZaVtcq<k zvIXe_Kw5ZR-nhb_MkR5gsw_fu_6&JoVSq`i=f>PO!OXAiBWe|^m>HYhh6SRma6yYC z@DysF7LrBMEOv3nXB&TegYiM)@m{N$TmpA?W)~67Z!84k_6qsU;b^Ev>c-A7=X>lW zTZQ}8vyYwS;5mBWgQ<~sgf0`Z;u_^Ce(T{QJW*<3N$YZa$^?D3Ho2lmO~Nm@DB+EU z*>H>lp=zg^PBW2(F!dkjrBb%><j@kGOTbJzPClCQ5i*daWU1K0TwCWa4<WemsN4f- ziBPH?UK7ZWQdgolp!mV%t9n>1UzCESb1^2CZq&;NE-+l39RVlWh!}K(Ck0DSNb?2| zYrfUUEEF}6fTD}VK9AM4$BX;9Lqdulj1|F}3${d#;@a%ByNG>EYbw-qTE7p=`aQoW z+bVFSG4y)>S~s0&($?(DK^CPYq1ZCZO{%FO%HKs@XLB`|rqs7BBICWV5TzqYBm&W7 zzwBxg#K%5tDTYdDI7T>S-mT3~3BX3|+2$8c47-w$8C<;ltZ#9^Q9WdHseeDr6%xFR zgCwYD{NF0ef10<8d5it1)2^>RSZi0eL`7K&%PMOOsVYIb|6f0YtPcrE>;G?T)G{GF z+$PC<8XqiJ$mQ3lir#En8NLogRAlYRlNHbsSYjqEh`$y69dMnJhei9k0_~nENwz-F zzxTWKU(wV@NB>cwmag4Y)_k2mDrU5knsNBevr!D9$M%Me_c2GTbt+-TA0B;_l_=re zf2I{629rOoSxYTLFLL6ZQuVfi_g)W;JBjnkIOI6ZgGfSTmDUatSSKhKZ(V!F*epz| z-ls8&H6cQFGf|t?oWYgp!!jQtMoSx`Y2z2`?}XY{Nn_YD?1gx(N?Ly<4x5;m1Iamq zWY!&92l%n}U1K`FpHA|*HTRVtaRo$fy*^9S-|At}pd#)Y&-YzC-j9-U=)vkB^q&+l zb&6<hb>q}Wn1$3fMvaa}s&f_|mgnHIw`>)Zd@kcT*$(<Jo+LN)4r@ZY?P!D~yG<D| z%-I}6{3$&IPo!qm^sp)%L<w8=NtboYpP>4$q=z_moQ{tynmF04b-l^KW($XUisn_2 zmUC1yByNUqV>4$@;O((_*i?aClYHawFz3TyoT(T7KQn*TdT5={QZQez^2ZQwPuCK3 zDkxqi@}w@#(4yVGKf2DQAgk7P-{ki=B9W7!!F_v}!vt=g)W4q!%%h<W^sg>;LO2<* zqdhzCQQexXLib7I;`iwFN8~v!)AX%=lIrBAQ$IPwdfBFNwu$ko*m)qqdUK(%pwmN~ zE7)80MZBE+u?j@=K0iwl`uv~x8~KX_9P9n}BwVsDgl8Yeeif!G^k#AAeEHhtk*`<4 z<hhm}TPnv;Os+Q<G`bXqTL&BnCQC7xM7-zGS$JV|0ZA)-+0%P@ma~=$v=w8JZYbm? zhbi|Rub@yx&hv`*SG$YO$J5NwjLCy=N>_)<?dPwriJH~XON}R=BYLW{JWy!jO9Z8A z13aF8y!^Q0wdlC{D^)l;?P#O0RWv}CUa91qp-F)U5e~tg;5Cq?uV#G6{b*;xIpuF2 z{q?FbmFw3tK<;4}U~qRe%G-gKG-aq`VaH#!g=cBmaOs-n-;1u)Ol%n=>E4tsV{?of z@#Mg72uHZwC<w8z%N%yjFs%3ER-$S>jT0!THMWJcMad)^q_Z41n=U;)ep{*1Nz!b! zyOuh(b9VZXnpFX?BS!!={Jy>3N}~iPsQS7`UL1l7n5tQ=&#EAtatti}XmXK#yAM)7 z8N(dNmN>WeUoq#jkb0<t%_6v%y!g&-{<N2I1Q_H)$@z=y<cU>+#j0L)VhgF_XUNPp zMf`~EHn*SG&%|`(EP)afV9W2iH5IQ8iiB-1D2uA;9wVCA?Si+MzfYqyB$t}%Rz#M> zyfPalYx#^JP2+|J!aXx}rNPP|dQ<kqKbWtrqlJ?AKKDZ1C5>l<pf5tr0Bu((5ndzu z1uN&#q08=zWB$Mo*(GuRS{)s<Kpc@b^W$|MAn+v;oO=&J-HXBPo1N~z(pXx?fbe?} zm6r%sRYht~yiQ3qj9o!gP>ZEjaoVI_pSvwc*lo}KCFE!xzm#E?$RSUda>p7o4wh}> zzjX_L8<e*aZM6HLHUErIs$k0kK&}&Y7yio>hqtb>T0J8tT_N?XZC}5Q&2(7dcL8j! zx9Qh6+?n+LJNTq}iFfF0p5AYCh7(6F6B7^ujgCjLwETQEd=6OX^1&C@*xI)0zW|c5 zUn7abI4~uvK+n+>qXQ8|jJmdFe&M1@yON$S_m@tQoiO!&15{Ruc0AheVnt`{L<fIF z^*gb0p}*t8l%Q-s>!?u@qk=CqpV2=J;_`g!3GZr?Qx8$M025LwgllP9NYE8G>o-z_ zlbnXt2NYU%jK%(qD+wOdOek-3l2`apVBjH-cz*)_6!OEHnj_m%BL13J&PV(L+&%_X z`Nn=^G9HYY6NVXBoPsTfO%|0FcR=C+bn=g6x?PdmS|spDc@X#}qGQ~0czS1IXJP%h zJ6$zZzbN1{(D~zJdqe#iX=pQ1;|E!?o(4`5lELY!*qwm%S+asET`YC;Stb!8pCUR& zjPO_3<bop4QXpoGcEl?T!-2<-x&^%mV;<QFrwJ}{T&!#5<~Ih)N7l<$D5*|L`9dT; zf(vg#{aDB8{S+m~OY?})HD?ZL+ERz98YS1t-EU5HknU$4XYE+AMbBUIyx@jfs^hUR z$YWeRB5X_x98InfxOU=1>XQ1F(<gw*Yi>(>P47PN>dP48=KfLe?jK~S59Gr=K|KS) zPepVSVV|lL3G#2|gU$$uNRQs#cn>8j!9`Rnhqp#4TMe*S8LzF)h7=ur<yJj%s?hyU z@A@Qtb)747!Q1m>xn}5hgYbdt<R0=%dG60zm~Ayoa^EWOCNv&eG6<F!WsyTU@NAS| z&c3G3#0nsl&A>ho2B?%O?91TSM`k@RzCi5`t7_ld77C{I{mT)rB+v-SY4}Hj4&5cC zTp6$KO8$Z@1jRr@yUWX;dk;JvZ=MIXL9-Jh;xI>TbWc?#mv7y+oFfv*Tn-iQ?Anu= z_#}Kjzi#aecS#-_`~GXvcRKAn(pl|yj(IiHwG3Lr{e}T0%H)4l5SdR}1K!0%{NaQX zl$GLbGa&-ycL<{bnGl68*c12XF4cCTw~Z;rx*?&z!3SvU<a;$RC;LekvzD}2j66^P zi_ADQ4Wq-@py%V3IL)9}rm#_t*KxlAnBa4B8m*7!Sv<?0Sn3g@Za9)pbbTC(MT)>N zxDe|K1H}-lCPVG6UmCal!v}#04PL@HlV2;_g1<s~!7})VvAobZ)YQW^>#1OD;&&%F z{hE^usDdg_^kK1ot>3=d+y((c&|I>%#K(9~Pw`~g0k`o`(sy3cyfpQvF9s4x8u%(E zRmpC96eWYMqOo4S=~CEQ5~~Z~xfelMw}L;Zgt*9U6J0aSHK*XP((y*6Z_-4ADB8%1 zDB}z9habX%6Od%3m1az?_7~8@49qPnB0?yvtakZ^L_Z1e=<%3}hnF>e43oviX%-A; zvm~FK<xVZ#z@p5h7=C^$mwk7n$+!)vWEpNJ0nVW51XCtTj3$E39VafH2lB&>2@F}P z$wP{Wmifouu}NYFQbh7V=8J6=<Olwiu}lH!3UVP;6UdA;+esul6{<NPy{<MIZS)Y@ z$ZBycz&iQn`uPI7Y#nk8cK1){?+`)UcDH-to;5>qT0p9d#*YwMW4VevLHngZ@h265 zZ9FYp(*d%>G_9fK$C`}kZ=;b*FacueB<9!B&$QLSKYavo1a&iKb&%o`-dp?o?B|@v z;G#Z(F4Wg2mnztCxim<%D^-owG5qsXagw+_!@pYT-uvuBs(Tf5M?XN#RW_EN5aV^k zxU7=_w6XvL$`RZ_*j?<kFv(@QzR7QfoQNqUvghv#cwE)hyg|Cl_~g@N{SHbVE+YKn zLUr-fuqyOPkB=IgEBl+6OF^T;;B!$Z$&T_4;Xy?^olFm%&;a?lj{nQ^<sHv%j|+iW z(Co{Igtv`PIJ#ZELr#mo{f&Xa>AL!=EnV2r*W!ecEt)T#0oxL$R@)P?AV^MQLT#A} zJ(g(WISYg+C~ASVmwTw7guHb~rI}>$d)MpB*_*b%8WX}ybn+hO;+#%`3!=G4D9(wU z2_a|QFkG$zXUemi_RLQWME~nfpjbeV&{679T3f_}8pwrbq^ImK-m5VN&62gYIzUj! z?o~R=44PN|0`Sxe0=|YCFzGUQZ1y&z7_nv!$S4qN@`sm6!5M$N5<(tSJE`+T*HSe8 zto_P}%>$&G%L--sb32o+`<ZTP5t{6c73!_q?j#Y*F-43&qsg0P6gfLi#<b3=+9IOV z06SwnYf*i;5j6O0$|XpLrLSErT!Rb#8V-7t(fne-p$wz%Zsj8I(%m#-3Y^VXFpd9G z91mfMDItb72)DC~)a;iR;ZhpNgv+<jRi-c-Sx&tb>zLw5SF_QcD$8DU2Xo7-yT__~ z$gxbBcsETc#O0~5U0~v`zmP;>E-;`-V~#k?ED`0G2f&g(4$L26G>c*1YxH<4d`r_? zYUHr&-h<LR%ApvKla>WEMPn~vfq>1?joH4SH!E7L*gabD^W-gwiXRqv;0mvR4f6W2 zF`trT8Vi^$N$S-vAtg47uI%fty#=D>a@I5k7`%AVDf6lTO|dri3^?D=C6Y^N3qSsF zU6kcla?2WSa7m^}Q98g+P4Ri<lUu}@9z$h4sINMo3_8xl2Co*Cny#I+eq0sHZyY_p zCT%I=y2#5ZzOqlf3I9-2<+X4b@W~Fyn<VtZBEI7?oc293L<d~|OAilMAek_nl4*;` zh>PC5{Lq3j+c0@uGky$ZqFCPrng4ev*wQC-A?qtAJPDQxhF9M35PSQ+##+*aTJ>P6 z;zaFgcn%|%$L5u5>4ekBFojj9-w&v!wd@Z2XJbTl7Z`+iqL7jQjfr0^h*nQQ+t)x4 zOHESAMNcL_w&w}PxR%1vWYFwrbl7O$69#2XW~@^+4YuboPh(ew%I+9-nuTD{%Gp-L z2Ul=u3$NL%NaGaUMpK6|gx*L3`f?MMPB+RfoEqB)T-)b-1{v9Y#u+IQlvzccPz2Xy z5@~B)hZu*7HFp>FIy|afmq3XWtwk7IIzaxpD(LR3B2HNM()kZK-gL2eE$>)CAI_Ai zV5-Sz1-?P7S*3Sq$Ni}0wR@Rtv_nt8tC>%*{?OU^@6lcJghC_?(&$;3wC&dQOo=Po zPWT#Swu4k2D1C#Hx%^H`=9kh8>90<xp!xbW4jIw@BZT4!2Kr?77Ca5e+pGt;b(Is0 zJwZHHFs0rUYu`d~SM}B~^w#NG_x|vVQlVI@!ASnxqX0v@mht4$BG&FD8gNsD3lI-l z&fNSn)smD}@4NS(lJ)Yn)rgKZnz&ideP|_0i&gja7%sU|cKjJcySr#f;=Zoj>;&Sq zdMJPkO8QaS&rA^uNbcAc9;8`8zs9Cp4yWL?;}|AlG4B`K4sZ0Jj&7l77^zIMJ)!>! z0VQbSSf7;MF^UrK2A|Tb(@+^AwEVSL8$AsF+sCcDgKIbqhY*gTidnNLlPUTsX;_5B zGP7|&q4-v;hqKpmI{i~njM$Zn;Y1L50*-x2UOa;aB8ZPjGF3NTV_e(DZrn&M6syHS zRk4g6p`%qNwIr_fPDAwjTm1IR2Jm-#8{tAdv9>UG^tMwCw0spD?hh`Ul~YV6rG93y ziyHMQZaY-4>IQ2Sa+!s-(l*fD!^B_5xlz*Ig!UlwF*_{9tGgNuujts3(aI15@hJ(~ zi)^#0EjevXa&Y$%A{w_Ph?A}R$t2dA8Bti1VKfY{)%=1sPlQw76i!c|fdAf$T1Zj{ z&4uv4s(T;QFjg~(WzB45;>94-5!Gm{0fd@fmcTLtv9?p`$>!pZ5O0YXHF)3mBX#$g z8Y9~y&7hYs5>BJ0hs&v9`dg`pr+lBMLNU8~6r`~oCt!~*bb9|vUOwM<%OLvGyOgnu zJ?eNh=$CZsz$Ba!>3jI^Zj_1^UIpaue^?*N&ulD|N>w1QFg;d`^RE7;px_Pon`8nx zak?8y(y$|_4$d&_sP-k+5S}W^vI=dPb|C_u0$i+~a|p)<G64JS^%pODke`@~e+|F( zX%|c|bV%;AnQCLWMroII64}WH`%R<o_9IrD;g9a~VPWSMNHGI*|EVm9bB-LtO@?e- znRI%IZ6WjWRCN%p@y7TeH)lv%vae--WoL&7OLdaY|NFgmvjr%bcw%>BUoXYq3^x~J zy_f{lo!u72RVh7_dvFwDmLcOW)@Kuz50CzgmdJ=~Or@!Guc3~08LtZx^X?w+0gvB_ ztXc9#EEXHT>vGY{d_C*T^qNY+y~u*38qe}KR|P*&o@Gz4VZiRRTy$rF36BQMb>-`; zzC4NnP<#B7H6w>tYOn-B+KbwKSrEw>#rJod0-YFI(41}EO0xd+5@dfowjOpi<}*Ws z^~|msU)xC@&l67mNS%fCr-Xj9vkb$;`r~<f>4=i)!e09;jDG8Hlm}_b${qPBQ*7@@ zV>})#-8mU{mOK<7idwBA`xFTon<h`S?nm#HOY%(CKK(L)34s~c3V9(5(mtZ#9dnw6 zT8>}ABQ(UpKFOvT6JA1xu;bu^CF_ww9;1#_0&C63kF6YYANn42P;=Q+EKz!K2TrA` zQ0h2u(HN9H`DvLIi4{4C<G++k>y~Ao2r-ZgcDN^Vy!~o>ONr~`Nq|ZfE?J0co)R!s zeDP<|5n2Y@Se$78rI049d*}U?Z*VOe=BPN+n3T}#hV%tPWcPY`;$C|q?)w~{*911D z-;(AT%UjY)y>@;&ow!mLN(<$80@z*T{D74Kep?mxzQOgsKnoU8p!fdekc>f@nvo4| zAjZr~nDo01wed!DzTWIC+~dHHA;RH9KZCk9*`iEWy~$|U#<13;#V5PV4B#kaBD+8< zYi76KFNuIRO(C#csr%^Xu~WV>VQ|w1R)VAMMiJzih8pgh?M+rJnumWc-|5C#v^!7@ zXik~5nOrw?wZ|s4C!|&Gec*$eil~mqs6r3&7Ph&}yW)c*8Afr(<-<|W;p$upAr`DO zeo?B!xWBW;eUk-$y6%N85QTbTwe`{Sl9Of1wgZAA&E?&&cX4CNK5_8aWyt5>3+ILY z$hRlvA!-_S3Y+0Jr|kNf#G+{?$i^eEblOP7($C{vVu||a+iv3iU#3$Q1`3COFF$0u zfmEeuVO*Qv#;yHBu)BP2QlqQ+VK%xqN&9Hu*8}EBZe;L=gomj<)o-kA2BeDa;Pj<r z)O_*?%~`E!4ha~@5lu=Svpfw1^(wxNrFqXOZ}gxXG=odE62yn)H~KpxE^1}&O=lsa z!Mv|V;o}V%I$eXbn5EE}bh;=uuWR;b38<bvSm!4iF_xQcxj_b_eiI{z0etC6C1Js@ z+jsvM8zu1HPr%)RL4K~)e_I~fl=3hUaWEaQh}U+_g272lRb@h%;o@z|=zR*c<1?VT zwUeBKHN8E=P$r&l4AcM3^l9*8mdSb<@{OVITQBy^#%<0005<NHfIZ-;5N~czJ4T^X z`15Gf@YE^555<xAU|4Ywa2cJs%Ndu9t;h<NJ4`vM!_u!wvX%>ycJ^@3p<qIZ;w2HF zaqg4fd>#5cr6j?0e8t50wuNo>>zV%mUu2rL!Z?FVv}_bux%xa6Fi8(=t-yU9WblO| zj!5mRi*42rI`V9*FI}h{A1+E|hfg}m&e;4^b!Dch2$<Td$BwFpN~vG%vkt!p#aL$f zjt5(ar|glzEbj4SmtyUbG2Zg+`JenkAn_sG32Z`D{H5@^g4abv5}#&<kBoo1-@X~W zqEonsf=Y?ifpfA&`jQnXzQjIs^@6S5Df!6h+bogoKt||&fZQq}ysX;h;$cVGTBsZQ z6(xV}VAv4rcA16F4nf#+F$sU-OMg-yhP?sPm)3km80C(K8e1%_nT-DWl|MiaI<Xw2 zEhe^D%vj4$l`+@cFDFLS(&OPMp(p;_Lld>kl7@q(a3AN=BpmOwr+(r*ao70uxIGZW zshF$esHbBnKi9_nE~R%fTLS2Td4Wkl&MhJ$NH>LSK$qazR>ZGU9AaHk8OW5O?`_=y zd{}Gxtw;YeOtV2&JCICjUMAFEpKg1sziLP<T8$RB?SQRsIyP2@n<~)Gt3++kNIueE zOpP%s&anY_`*sL3!L)1Q3+kZbOSRHaUBFEv0n+q%3>NLg1g3`f1~~~<z+lNf&n2&1 zvk(w-MJe4^h~99AaQL~1B8!TiQvaJw0~WXmtOHklqB7jo$jd}Y_LQ{;C&ke_F;)91 z`HUVmHN};D!I>xCV({GVn<g9a+Fspwg6sneYNxLY-O71i1r&#RI%+1ruhyrA3$ATj zEOZ^eeSNzWs-+0(2dSX!;XtzM4yj*}!3p4ksw8v*4(8!<%Jj54O~~?L@xijo0y3$; z4%^LQP?BlgOs!(Malc8`<bK(nQ5Y%`ogh^%?^9*sPR3;R?T*jKZERxY?H!2;ZHCnZ zRA|4scP8zkats(lj*m2DZ92!q82VX{#REf@zTHDnh%T7XF$*7jWhH=T#kl-KBePXK z4&s&boT$6_Hf{)b)Tt{}3M~B0;Mt@T_H(e*@Rat+Hat(IYihr8a#bZJ;IniRgT9tg zkWx$vUrkbjY@x*tCO#L5s30j3B_F_iGHYR6HF+=U*AV|-<8z0}KfX-Gq-DT0QK7dY zKCn9pv((kjH@>yXH>?6nIGrk)UWaW%HOxE>ti7ciUX9PMoHm_u-n2wuASc3S>?^8Y zS9SVBWVVQrwccI55w^E>o`F=+Dzp23F)3<NCIY(_c_fonebDuotVwNWO)ERsNNe$V zYlpJtz%nw@(5SP9Ms#OJXfouLytkh$i+GwEA7|;9^;S;j0x;_-f?r|hC1U3=lLK(5 zBo)8XQ43Wnv=;Cf8ssZ__QbCo4i`}%exQBKEZ2O#w&Xbz-bE}7`;D(xdx+oes(v0Y zTP%Ynvonkw7E6EEng|ouL9{~|zV4hQ<7RjSll@?`4zZEf-k@-~W~ekVgnXtqS0S;c z>LjPy(c5!8zr|%t${(XHhno&^0z-aEuo4XR<7tF9TCh4~@!Ho)Y#E-)Epw`(_tkKy zMgU<Ikj<a@ctd4{L&>jh!n1hwGniA?!Ig{)zuo*_xR1AkvE-z3+7MLSE?DkgV6`j; z*#q~KX!TFOi=V=53MNfvGrlLEg`S%6`ASqXbJ;%Y7M-7KcB_Lvhu4?yPTB8wVtx2B zGu`B@<gLuKH7H~C<E%!x)xNQYz4a9#JkuvN#c>xK?SpvSIjG%nAG0hY<)8}CQ0IKk zT1I7Xs?3^gdqwZzi-#_3L?Oi-0vQyM*7wb{`AMlP76Q_a(=u}RN3guZonxvYK=<5d z{_2t^9|rU$pu0byW&Go=**%c!T9#w}9Dq;uSL-qWk-op?upmL2p&J8X3#jPTG5-7; zfkQ4(v=?xs)CcXg*|zwyx0Wdx{Z5&Gv2YL=HVTr$hJ*4soiAkPUA2LR&E@<yoE_X8 zKU+M)v|A3Y>7l&G5nXk57h{Lg-0K4#uu;BTw6i~z+aChmhN6tYhcN`9HP6lnjLp{P zUn$rDrF3mbtik_l9H822K9@W<yo4g7pqQazq0}I2BJsbhHCI9&f!~CX>7x>vPh-E; z;-amqymEif(~K2jS{+jzNDwA5aix%?>CZ2aMIJ0Oh17IP*&y>?79@Fonf>P-wol@E z{C^WR?{P>;^s{b6jz{D5e_50-3EK{dh0si_^kx#jwFsG{0@(w1@&t=w^}`S4KLP7j z;=>NZ$*pvW$rf!W4zMkhl;X&dGJa#Nt=5+SYhV(@B+hsf9~@MM{Gy=qU#94Ijy(?D zT@^Drm3`<5V{B47*X-KeC2*#e^aOSA7}D`Kg0#xDT(6g4Ev^F>PG0TFY_E0jGoH#s ziu{}c0!8=}b2UZJ%=b#}bZS2+1gByAl|a`cC`KJyGga1Kd{`_#Q?;SVhdl*le~c;# z{3JJLmTCL|T;NBfZ-Br)$+n-GJ?cJN{tEZ<^;)o-(JuA&xgVIwv8l>l`E=xLVl6sL zIo-hiUc6OV?=gMxO1S4l6#I>Are8R>b#AVMLpt{Wg@>>0dM^p;6+aI!xH_W31SRc; zh^S~Kp-C!AL}@(BZgCG<X3}_>x{*6fasra5VK|R|gB!U|b-=6*bEvdtRBv~TP7sX` zXOAv1^){)hG=ip|0M8OwOcB8pp%MWqgb$|kmReLZpW-z5^ycK4MDguMNYoL60H}`W z15p-qi90cTU>Rh2^%xen77Nks)&BEpkZ$B%%&v6HeLC0^EJNpZtrPE&o9@9pP2-da zFoH2FldsWAIh=Lh=z1&b>znaKc%0!i)#JpFSa}NO23b;(4HXWySRWBAn#wQxew&jp zAU{eQ+K)YYrx|xy4DnJBACUEZ9fU?49a6N%QxGc=7rl^j^vfo%dCM7H6_lEKiGTTB zwOtx3EjkyQ?SfJuHJlLte)7-PW*Jgp`@H~*LnHcDs{MzT%~}_-C!>Bkr&O56mlIR! zW;b<XPV}N@4};kj`)%V2SEjP~>f`0tJr;=mqosLrDtX(f{7EJ^xi=DeT}>sUL(;c- z$d4gp)ora5<n1<FyoA-!)-YOUc3ajz!E%y(od!{ZpddtkanYklEXclQ$bTEU{#-B2 zFlECx%l~XZ94cKue<t06@AX1{{oZbU%vbA50P8fk@u9K$(o<rbe$ZGKs5Hgg823#@ zYf6n9Ie0}nDM`_t<txs+P*VrIyjo$T{OI{Qe2e^6WLy-%Up7+6GFQC?MF*krvPdqh zXr4);gc2Fy#nNCBXKsE0OM2u<UOZb)YIu^)qMUTPg))r%$5H7I7^WfRO0`~+Xs_v- zN8{AZVMBFi5b3TbD9}GyEcec#aSWB(t~;NY3+iy<S(6>syEGsEam@ggsAK^N*6&); zpN2#$!?22sE@Rw=#Xm`<Nt43Q_}goeaYu?5Ps7e$MU*AvlZu~az9)z0*mxBaQLs9M zlqBUn%cvM{mvqL2W_mo}t`wdQtC?Dp|8L<AA6$N8q%gx-$!#N}FhD&$-p3)$-s50u z$5Q2Ks?(K*lm$mhb|8Jm2+e&v7uE5AVxKsSi5<AdaE3MbRa>e}3w9i$=(XvU)h0VZ zGWC_j@r49E$}fx>JEqu%;n;6^&|yXgETDm$RyHUGyl=Zd<)<GBf|it6%^fT(wG~R5 zj4i)6qYLOl7R4w}QvzFE=3upxWfj|_2C1@t8#4j#dnACw)z9ssJTWIPO8SF1V%X># zNN({$fJ4R%Ys{k=$rL>#Ds%^MD_K0?%XNtGL|tSu%sza?zZ%#sWn7_od~yNj+ExEV zbcAEf{@Ya&lpf`wt~6E2#?kaCA|;w4x%b_&;@I`ZMlD)*{S}|#^Y0-o_v4sae*u@7 zzgnh_Ln5o}Ci`L_nKC#&`eGQhj@Rf9(%R~pP2GHp+gini)CTfpcu}h~>Bos7XvW|P zjkG`)#nSG&QiJ{CMs)nVf+xi(`8X-(k_+gKJj|_2qS<{R1fTV4(4J|bBKpUlz;c^8 z7PIHhatCq;64tq>KqIp8YB&Cyt|E4`$kN--b36x@_pPh3Tc{l*d`YKwADjp#{F@mJ z2JhTkSGid2QoWX31skSvfMo~RFTC6>GNF2Qq6Td<iNUqN!sHij^FGCAe;d1x{A&FG z(DXDsv%+#t8u#bYc#c&!!|sbGa3S&F4R9-2?^W(L<<bF{PP>Lmn+knocY|``SSJ&$ zi<YgWVXP}$aRJRYmKCM=2JO)6VuQdxn*&Mp2hlc;J<Hc*9XfaSP|NFt87vDzoNKIC z?Ohl)ET+s+QWuzI>zG)M3$}vJ-h|t8tfhL4$kuoQSKH<EA~atD>I;8Z&F;K+MnJfE z{CaFPn|fJcgmU;p?#b$ElyeNPq^1j6ewK!7y(WBtOLMYptl|ajVu87TA}^50?Q}R& zxd%V8OlXDAn7lH7Q}tt!F}<FuSN3P$H<F)YeIy_rXF3Ce2n2QRTVKcE2o22&8z|0} zz<|>suxID0hqLk=xb1f;&wI((LYy~A=a^rS`lwc0jcECy2Ui}D%7y?Wto_ak@RoKO zJ$qnE$7Zt|6umDrU3pGG)c`b3ycU&?vO58e?zV>fv-ga#lq6>_Px3#<TkXHeJyA8b z6qdyJzzs9A#7k|ULU^0U0#WKeY4N$yt!vGk`Zyuqj6G?D*>uZL)q%uVZ%o;BA<t^Y z7x6j}vQz*At%XBMGgeeop+`6CEQRU06&o<R(VBjCP?>ouH$dTN1u))+_>sD`VHg-4 z4F%*>&K<dEd}v!r`?y`9x=SHWP5I{3vg>Dfbz~3{&73)s@VH-u02gsHwxc9f9T6Fy zABy^~_%U~`&|RF2&n2S+RvyfW$xcn<k#MLYjucn^0OpaNnjD6no8!;eWPzVI{(tms zjLOS?Z^@KQG*xMB#6A(kXG74s6XT1MIRCpp090rA_=i@&JU=G}%!px{qyNU|t&x3V zHGglSekhXb#dA^Q!DHzMz<q#1#%9RW%1797bHn?f`RQ=RjfU|4GtyA0877f57t-2; zD0R>5W=n78;J|9GwD$?*56b;&87p%KRxY^8d(y7j*2217M2L*fUsp*-uB!AE6mPU@ zI@$NCwzm~gb9~<)ysgl0KXL506Q!q>&iVE=QVFhQS6h~`^Xt?N{8x3%hfRe(WaLSy z=>nc$9sw9BuD+Bb>DCzP36NKaeh;O>(c@^AcE;rWs)U%yz$W-5pC$<#{=pi1h!}F2 zqtJ7XFI?1{ys{4D6@pErD7zl;$!A}*B)NnVEDFv!p<<`5TM*?_SOmjF45sH;3Z2le z)Ap0}y20D>@*$Gkka0zSs!RFJuCKOcIU}6>F*8CM&m~XMe{P;+HdiQ@-{ArCR|{zj zb*gp+IuAxUk8Vn|*nWGDGA1QnZ@U+AR4VgbHO^o%DT9}TDcfaAkeUe6WG98BIb{fn zoWlI^cc~)LWz!B*WywbwH?AZ<zyC`2+h-569nqpY&rfbZe1l&8;53kI57FqsR%0Tm z3@4g?*0w#kpn_dDLmj?fbIo;_v-D#iFRRv3n9t(=eEf!k_sN{KXz3^hbu;V^%Y!3- zl%$Ak;qQ$fMYxvr4Hn_&scx-w?UbB&?rtws%-+2sEfzkJUq(eKCj#4liIZLme^WE| zkAc-hh-Wdq(<y0Kl{VUTEdnlm2`HmpcU`Uy?{kXqDJD3OowGn=)0}n~!I=`X!Y#rc z60elm6e*-#(qU{lG;*1Wn;Oj%e5@#AR_q878#bR*)rKPb>??~S7Mo^yb&WU4Y0FuE zO1*P2A24RwJnAso7`LlisfvQ3hQN;ZVz(D5<ZW!}L*~j0bo&WjLK=7yJ|_aD^_q81 z{DquRpeB4ksoL8hZe2RRL=pr(FU@~vDnvQQU4FUXL@Tc=1>%^~AFI{+>sSg<H1z@| znMl>%YG>SOi+86{xEFS{W;ScDRf{^PKsy)8nW|z?U)F^Mk;BA6X*>I%rosmdDzMoW zPGAT}V3l&7O-B6wYc)%&XqYVFe^*;b)UA#(l^O6Me;Rkcla;hHFIozq)PGv=lpsdI z8R6c+Bxfa&hrBWzDD)E-!{!>IkYFg7!0=ykil|Tu$>r0Yl^N)bMftii`uW6*ZQGwi zE!zDEhlqw?>Mrh+Vvj2CzI~#1L(F)odPZcBmONyQn=<9NMXzMXEr)S@o(S$-(q`XU z^OPu{Jd=CnkyFWf_g(+10JhwGl3K`+kk|t%T>@w{O(e`7pyAJ!)lkW#^G4^vjY`gm zqs2y&+!!(Nc5FbJ^ZVq<UrpaHXbnjEpS7kI1Zvs$YG%{j-ydaa2P7;&#L(H$^xJu- zHY7qPhc*wX`C5IVEo(_mHqj){891H-)#TjMv9^HYe5r?dlYViNA#Gv#i6#7Sk+p-P zXC;1P2Z{TY3=a$i$b#wYl7Qf^DSYqxAqb5N-4S*4x+WbOFNheF6KoY7;^_xGdVQ+C z(MB<o^Eq1(**>5n2M3a7Quwm&X6C#Lv~|rd{aIp7>D*@AmeW`V1jP#5JG6+wX-1n! z7|*yglK-Z167F2QH%8BlZ4z3#syqYuYm~NTB5pCfcfYHfa5dWd^`!aRCaoWFwY)FG z9;o3;Xdv*X;VK#Op>$_88xZ^vUOL9lZQZI5B$XbGe={2s#Mh*vr)@3T&8+BvvFsY8 z@E4Vo0#x*<tA~(nB-S8-lWnsm>1sN>$=W03e@LuyrjN8J;L~;)*d31X2jZQJb2F9& zPTF*F{gMji`Kr#cF<yIabnu(Rfv816DCKk(RTE}!Wh3iLPopeTKSh1SI?&Rd0zoHj zmUT~euyA%SDjDm1;GKyQBUAj^iiqW|F;EEW4TWpXsXz^h;#+T&K;yUtZA<wmihb0B zdU1kbA;r`9isdVq%#8Tv>|X)h3Q^3OoWJcHGFp;8{-KsdbUQ~R5!e^^+&?`Nh-Hxp z7x<{u;k~xQd^iNlJecse`t*y%+iGn?q-as02W&LN-ohM;8Y<B^;IoCkRXyWcvZ12% zS`PW17Q2;oDHv<;91Ip(XOrzc6*_<1E&rQcNSpn7(aQZr=(}u?5e_!<>zrSki2T9W z<9$#g01}-1cM%yqW6DoM_`RiquPjO|kk35n8a*oG=NpQANkii2wI3-gHXR?s_Fyt_ zdT9ZHr3F*`0c~!CdCn3=F7Gy4DH|y&a5O?F>?AE|_hY)Z+AF!ghmCeNX-Svi6LR(N zwNWcW{%c2AM>Stixlb}L$G)<?YI1CU%%j-&n=9x$a0_i4dE=9={!r%z%^Us6ZTn$8 zD1nNTl~$pl_hOGM&a_co(!JdCUSLo|kxq3YDVV|Iyken4ibnz`a<GCzLaWqApps*d z>B`lx`QFLNW$}`CETe334yLl+R#6#(_idjN7M59Rll`uyAKx^^@~Ow?M~)Pa5Yesb zeUz1JV7*;QlC+4sF*r~R9IJ)bJH^D<hVA)I6l|FWurXC|A<MVF_miz^wFbu<ipg=g zb6G!rUQ5aLcECBKgGklVKaaz&yq+1akCF@bHX7VCoQSL5u$8^6&|Fe%GX42I+wlGs zH<pvhm?=OlSI4fu>hEWKs%tE=vUd#EUs~+1bEh6qsyfm{J`Cbl0OxGus%flSH6_&- z2UB7Mhm$2j&61bU`(`1?0pf{m)LH4W6Sr+_`>2y)E*jiL8@8QcD>l(2CY{q(&h}e& zp;a15kj*KrVfCGT-^>8)HH%wye$%F{5kmzBcXouqYdyh}M#k6q);m5H5~gpPcyu52 ze6E7f4Zfu8JWj<p&S(czvW7>e9i6LkEI42gSq<eAxHOfZVjeJ~$toS|cl`OnljM|4 zzRDnn@*V}>KRn-|P|W0Go%D*%LE+d4eW7~tsohW8;Xb&S^dPLwGnh4TQ75ae<6V^W z;O~KgSB5{b;{Di;=W_*vMc%<(rTI324BMSJ@zNLeDX2^g$YMhjo&MH^aipbyd%Vqz zTTFVC31z8Xw7%@`z*I^9pq!C-4q_8QZGC5DG!H=7=XytWgYX>p4SB~w6UgYP1{C;} zGcj*{`$8-A>K?nd!r!_vF#2MaP;AC@5!t^$oA&$NEwNh|np@OGqwD;O)oO$w=S)~! z+aHqI!#LXC)at~em+-LOU^b?!RI8zTb)Hw$?<^QZ(x`NrT&3Z^c2_oVl!}X79njuP zDF+wa5lktsMlIPU+U<C;?Wb%IU4OwIH6NY|^Om{eL0e$cV2fd}$IB6u7LEA{-2d;x znpGp%lC!zC0Ym8)oxhRfJUjP-?EOJ^a2a+lB4aTxnbRSJ1)Ot0*KMpyyA7x$jUyk8 z&Y*l?9BMasPoBB;sT4ITZD`cKXppY2Um5WV8T$RKz`T-L(RZ(n1w6PP729jy<qkQ` zg<$2}jm^bc95U$LE$OZXu<*jGY;9A%nB`)o*|Ic`Y0VMQV(FUu$UWA``0*i#u&GK0 zKBDO`P*ikAM?L@@C(j&j+Vw=r97k`#f%9e<4vQ6NcJ2XrakMvF*rbl?)lg&~b{O8x zuq$-)5E2#@k&6qG+-s`Oyh49MFU^fbGat8yZi66obWq4(f>lGI<@2(buNKa7HxO-% zcRBj5&Unc15zdHfo)pEBjd35f%<Kiw?5`Sg@%6y%Rhr6<0E2%s7qXJ~`N)~h%fv&D zl<#5}Q5zK<suyN{WvfTz!9D&uxNFMsz;9{&<(Yf15{pJ$n8YQe2OQsC3A$QFj;+O; zEol7lYnznyVbYKUu666sOJz<G#i2(SPyt$W7?;#fTu!j}xQFEOhO0Dvwk{kixt6i9 z&%EtcEd&HImiLl-oiw&N^pN&`h|`!bS6=Y)48O=q5^TJW-e(j*7NEo1rv#*(GBS|o zBJ?v-`Oe8EUC#@mzc2=b6xlsKD4YFtsole~j>*;Ha2fI>*H>^QiqRN&>M-K`sh`@= zO7Tgo3On)s3Y-Doh`fG9JTxahpvoStZ1VfQgNLi%*PLmTG`A1<TFLyKU#~b<@BaZc zK+3;2$~-j26i&*CCR^Ta$bKANi`CGsFTXIGC-3MMo6LbD1=(6u8Y)}cEHz<72Ph$V z09d;)%#nh)K6_nhK72WKtBKOs$Sk7hy&j2+&sJm6uHkV$|5BIi&Y9r0YXA7f2n2If z3UvgI18N5K3EBy<1}gst@$lo1+#|IxC4!7-b$XBH3Fj&dZ-DxUv=?lrvsRiSAK1i* zyI|Hu)A|E`WG#J&8Ra0<1G)agB`;JT_FME<m7Sq5y(y(aq0Ik~ko!o~O!Qc0VCt=h zI8$b9k;tirK0D;=EGzVjf^3-N;0rR^G96uX{2EvKMqo~Dz2kQoa`p^J>KNXP%&xmf z0Uc$SSd;87LiI9x0Qqgxyx+M{l3_ifYD&_qF&W7;WF|^XY1UkG7LaA(YN>S+3_>06 z%g_Z4DzvY#k_Zsq+Uki5?wTE@oKS<XPp{;ZgeoeNBqMIIp%&<yT;{bsi{MY%7u`R$ z+_7$QLhK80rITiI7g*&)%0l)CSKP1=nDR?ZlW2tu&)U&t5$hfC89F-=;#iBylQ9;Y z$-BREf*An>C8RPen7atD-VwYfZ(~%#?JwKtFQHO549Z74v1FDDiGso!e?f18#}?b` zLO8T{FC)wCMbi>G9cfR(G~6v0=iK(IH>eUIs0jllmg7(RQ{o(PlVlA&OL2li>JCWv z39A&$lxUDkUDB&n_%?1FBM`t_ng^ujeh$3jcRMaB(tKB7^(rc%qotYtb!7IjQWr-3 zrNJnH$z062Ia}&Z2cxuW%f41mBZh}AZW)NT70*uk4;$Dekruf&vOsKB_*?R$$lyKC zSJCr3s3{Z2p3gtIrnDZL2#NMAZ*q^(FRPM}ulQ9Plcd^ix=G5>xhD@hhR7mYgDEDo zp7Gs|LAZ^kL_{fLVn%Lx<KV3%n-1$&=Rx(nBx9I^y`X@<xgrF33$;SRL)!S3ix`_x zWF!S^(b0JYK>7(I!8I@B#Gc%=<l{W8WuaE+w4NQ>h(M%xd3=`d3%gRTa5QdOrz(HN zCqiHT?j80sJeu#YIhn4X!#}#um*rV}$a(oh&)*7LTMkLCM2uHM-9ScV+*eI3jiPu+ zcoI@J%#yT^Qo==`n5gm`<5`k>q-^@nY`NDTY;d1es?|lHQ58bN1MwD@9=j`YgWw4! zfKd`gr!v!?!q4d1B80WG3bXxaQ{BJq=%px}B?(IJxy8L-Z}Pd%@%}MMdme&7Dw{&n zbeIjC(bnxJSee0WIfwy?)A+^BmZKU>z_>;}6E)92glwjsjsxQJNzZX6+4lGR>06RL z0$|FKH8wXyf?Mn0zhQ~?TOCPY5EBEba+dvZtY<4ToJEqDBNT*p^9>r`bk5fIr50re zIyxW5x@{G4sXQoBB+JErSe0^5AQcG<ztmX@a?7T4Sq$xlC)b}MW+(OW;(ux{7BmDe z6lb!-5`SNItu5oReMOo9b@SEGXX2)LM@-0dsW<U=(omv^Pm6|v@G1V$Dq!>wdS zswh2vqg7o^XyVuKF-ibXg|lo>EVhsfT`@}PGD~WcyY;lUwri@Krqe{OLG)n7Rr<}9 z?kD;&#mwkXVih_7iJ49CBZL8&Fmo69Zg%RA8kUs8jbmscscvI2=a;VKD$-S*XQ59O zAqhOdwYB?7ldQm=S`H4^4jD=9BDnjB{BBSiFbq*3M{^rSy8hI^0<tK<ory1y()b{? z6U+^0it}8UD4ZtxD!M<s3x1pQDx8>GAgA!HhUOCUt5sAU<kY2FMFOKZjN_PBiS}IN zs)?7;qW6+RxaW#(3#G|juWwE?oE*zYX^Xd7XUj(;KZ}g6R&lJ0X>SIkxKiWZiy<=Y zb|!wGA)-RrC$2qr?>(0h>|xbFp~SrBkdmYPs@zLAQhK_*{pic_4tE+zYy~o6s(~$w ztMY5q4L(2EVM1d&KaSs3rO9jB&~+y*&BB9gb6l=TIi~kVduOF;SV*mqti=bs<7zw1 z?JWe=$Y7E{Px^x;g+ZrN!>Y3X%l9ozw1~sm{eYgFyK|hLdlVFQTa|8Fg9Yjgp6UCv zS7Q2Nn7Lw79X)t$UznX)LOYcacs|A#PXUiTCkr_Z9JvoA;?E%FLV5k&12u(8%uF{j z$(MEv)UV_#btA4Orzhw~Qg>E;Zf3GW37P$I&ITL_DOEP;t!8bjQtBXGsXju^MLr8S zW+kj3ice>QPvk#pFuP+ZV<Aw-i(KL_r*tEa>g|<8g!JZiV(YN7HXF*)dRMQ~inCeJ zkB-Syq!z*;g3MJWcTn}IlEgLTR3bVe$})AF+u+%dy|(6=vH!tO=>En+I`XWK>8OjZ zOQc4Ug6aF8s0q0+(4t_@C3Hl|Zjaj&*%f0-|H%4O6Ig~4fNPf0qblQuH7)6y;E*c1 zL`cD60?}fCX3|{ulYS<Yfn@X~vsbM;^%QjxUkP<q2?paW*hC##9+m}a%hl*rB4{pd zEE5$GH7;isxtAKyn2t<1yBY8ZXhoWJbLE7>Q%yRM;_J2I439Ao>w0K>D?TJPdi`P3 zc@b2JB(*)`cKmo0RGCGAEJAm_Pa=pl+4G}LUAm^`zA&>cu@kg6SbSv(OQ&qdFGIH^ zrEF8)A>B~#4I}BeSAG~sfmP^NcnaxGddxF#l=5SkhQvj5Dz=U2Qx*-2#_z(_HU%~* z_Z^UpgmK{Bz^9~~bvGGFf?mVVbNR*4uVPdv5N*RlV|Q*VuUk1&KUg6Yt&J4~>n;;) z{ktmQ6SDzar7)ZY5Kh*r2xVTvI88N*Ni7^nffrG%Mi5eobUObM2*Qw92t<gMHJcB7 z3vZlN7eOOxXGXU%6^|~4JmA2Nb5;6ln;Kh6KWlASToMr;0|1OGA!q1;9JC#L*bt~& z)A-XIl2jXc8YP@cxS-=1@8v}m3mOuz3y8Oz=&Y1^#(mK*zrXHHpV!d5<5p_v(4;GP z>`+jJQ)NPw1kE&4xdl+pyJb}Wr!*^qWteSgA4#w1%9!X7o~kkf^Qs=WvJCfeNip+Q zthFYjsdErDrziwR;OJ(E5J+JNfYJiX%|(H25#@;5J4obb6Od1^DTv<)xl{FW8L2$v z&v-}PpAd`JUdr4P+1KVPEl`SJ&47tN)?cYL;&f``f-LCj>O9qP(SuPUS8H4QSgQh! z4}4<8#R3WoBl3!YP*on^9xOqtB;GX$pyLd9BST~@2`Zx{$qujA<%`GND5Z@yT3=(9 zpOb7r`rd`KOzD@%&q73uAS~}%3bZS_PfT&;HPvQUBy^g@*jl2<OSnZSl;Ms}`)p+e z@_dxm^lc^Wan%aDtgz>-NbY>w@Us%sQaco}E%~XEk#1e3biM7h5PDESnf2f6>m@@* zarVVhb;=;}2x`W7>$`-eqs6XjYnE?h3-4j|Cn_3hh)-|*o_|N~eF)Kl5D;E*yQSFr zgN7+ZeulZ~P{(V-U<o5ajyjBBqpb%2mWgRf2&QnwGu$k03F>izs9{1vnzEj?PcZFf zmI*eWpu`9iLI@_%X&WRQNl<9Thk=BmT;es|JH4+tbdn1YLL4husz&#`>QGczpvVTO zMZsW2Nt2x2z*1Z=lqKj#_(rD=`D3(WZn#boHD{gG)z%Li3oEC|*SL7Xgs)4cPCe~0 zBb~Cv>6BRVOF$j~17H9Y00%@7aZ=TR?oSm6U?wDI^<I2;%piu8Azn#17e}{x?<nCR z2e)Ap<2#WwoEAteKBixEX8!aFdQ{%6>!RuLlXk_=92jfgxGF@B*D0q2uqD$3=Z1gh z%oi;i-Q6b-K@KX+>><jP0ld|Le<T``nahYI##KnQF5-~9Lt1fQ*IOqP-I->3i9-Bd z_a@4%5*(G7JAKrfV-(I6CnD>Y9^6{m@mIB4Buvs{N6q#;x%p~I-3wI;7;r~}0*<b` zDpHXSteiC9Cj3)UqUjxT*hv5as0czp033k!Fr>PKgu7He5F&VmT}44NJ>7%|m}G7M z0m2p_0LT<)&;}?Lg^&v{pc3Fz2pup*0csz{31SQ4l`dR@qojvaFnOIY@8#)gMq>TZ zK{~K`Y&k71R9tGiO&a~&<OR*7m)s2`qPBD>K*;YG0S_EBls0oagwy?Si^gjdtf`(C z?$cqX9mJ@u`y?4{LhV(}Hrr56U&BwtDiCoA^I~S*T1Dk@Sn}B!=LYSEO{*3KrCK3m zku6CT82vp!pTKv1ge~-V$<cc)Ma)T!*#<BpM08AW%87Apb&0z<tFc*hSORALKBuso z@hZ7wP4`@`wOp0Su&ydJ7ELCQ!K27*>UPh2?scj81R|uvn@~aZNQ*7eGRph$+dxai zIWFYpu@qc+EnC_(&yj4mUAHr6{4PGJZ!qzcz~ke$mPIzG*rU~S4o?>N$tIW&MKyWV zRBe(aqM;1OOd?z<${7&pN1#{91uES)TR53)K6t+u0hU?RpbeM+W5pZl69P(3CUOla z^BxNnh(CdwK^sH&Y-ghZEj<_VR>?SNIbh7PXA7RPx0Oe2Ue!gsT(epNqka+~LWyd& zZzt_K%2>V;wm}&~)r57r*G1%*^jko<XuO}xv=VaeT3l38QsUSd$3L&bVTywdh<_}J zd8th6y!B|7{VmfEL8r~HfzYTD7PL%NX;e?fz?l|m?vqh($e5oFkkOj`F218XXR!(t z(X0;4kv>weaP~uQCyk~JC1$I$mGQf=Yr_#jzeH1Z?9h`;=&=_0D{aY9T3SUopz00k zcXNr@1SS9^(^~cjFtz?dT*j9gqkRy*6fvc<zo_P88eAOkN$A<yKH2`?WGTY_mhVM5 zq=QJ85|MRe$aG<}glLiqalq!haz<Re8Szmh4nPD~s}P}mtxPhl@l|${)^FcVi0~~g zk<(!olK$)yGRsk@**#75cKoV99f;cLQ;bzYKQC+f;2Zi3a~jLi%NP%xm-2VoFhVZv zyF-@g0OK=^A+Vt|!DV$Zf~;A3tBB(-d{!{2<r+6iswz3F6q4mTo3_-aX*NW}u7u6% zQ3^BisZ)bKTbtgGKaB<VDhgv+_Xnl}#TyE$5vOfliSCd8A!da}CdKg=I9aP=B7CuB zJry_PQQXX(-_@_mE=6+<VE<Ag2yXIPP{Z@tCi%&2s2hm1r5$T>x^Dd{1eL3ZDx`W1 zN#S<e+zG}?%E1^T1Q8r4E|7x}>T6>*xGu04n;jrUEkOzetC$85ioG)q*UJ;DO6b!i zwADoxU;jRhzo5NY=*J40<x#w~X|ALV3(u)whIDf(&ySh9fkcpKbiwl7I)y0L9<7ap z^dLy)2Re#HSIx7;D*vLfN*9Zhqj;|~xf8M!kOO*LNy%iymDN#DV7@kkWc?!3tC?Pw z?W8fL?L9vk(W4L8%(?glE}7@?S=5gv-j+|V%Y44QDa_7YbtC4eag^)x_*{e`5;_~k zF-H9`QoOtTTpGtPr94~Y(ZXsD`kvalLuORK8?XQ&e`ylJO#*{y#qo+7J@{wVqn9m& zU`OlZL0gFKRFVo#YfQwtv@<m$WYsp>Hl5tndDInQDApxeZ)hcuXj`@p_?)GKNEL(` z%&zHsas1+0(puA0Be3JE^>KQ2jB-O|6FP*B+jX})6;2$PEpXz)^BCNymnX6z2yJs( z3$at=2~h=VD7FUinA#T5gbJMA^>`!FaG40jDl{#2n~Wxi+OEcH!~wg)mvrCnt_|{h z>&fGMO^UqR2s+ucv&jM!-dPd^fh4U3r%x<mVdb#w!KA7r&NlF5-~s{z%mHYC0V0YF zDgr`O)UQY)Q8oSykS23h3o4)iJ+29)b3fqCii8yjQy*kb!qd06kJ+x;Z_pvX)1_&- z8ZvrPIs)$U$$4}r<w%a1H_6h%E0Eu|B~i>QNdAYsJZ>L~cHPVIVn;DM6&qEzRW*hL zP6Wb<Ftx<DaOi}CyVYMgTB<G@+TR@5SOhR3)il4{A7&?vRGrdW9M#qu@K}?x6;;&Y z<;BgD5FkE3{GY15u*N*<44w+3=$?zvmZ0S)Un>lHk@vAELujU3QLJ4VH2A7<$2~Ds zwn)`?POJb#;4iVE1#F&MPi1&7mzJ)DtXb+YxHS<Cr)30gsGPLB(V*7Cn&m<Rw-Lgx z=h+sboz`-+r&HTh*B}x_mH29tB|#je`P(8yJfN9lpeQ5}20(}cM&ZEB%m4Vr2nBRh z07nCV1v&&E0O9>E`qlik0<s0%1A?@k9sLmyP4f7Y2EO(V2cLc5v!_N%+Fi4C5+_d8 zDqjHkOe}=Fi7dg4IhsdHw?W4V5=VByee|ryi4V5rW{7*)K(J(&=}!r=(QZomk5u}H z)!I;9I|GmM;$P|Ptx}nSE=n=gZjAbpLRhmNgJYBhCc_d{Ils#??6qNIS!Ven$o@B7 zh+^2ydoIrClplCret}#}G&r3cVv01=KZ{#4b#~1@q;D{=%}8~)LeNl!FM$=5f5qym zO}n1}M@b8bGYcmmv~bwQl!3A-b9L#POVbO>r7}{5VmOdxdfCEdYqVDKXio=Zj1bR6 zz5%iR&y(eWmg9C+n!&|8;&zdIroZiJuuAL(CW_|Mb8;Gr!lN5?m1)#7Yr;ux;^-IO z9S(^R%}?l7`mF9TCXuIBKSbJ}BE@Ji*$NKo$u6Te6945RN!?o>jDqm18e8S`O=l?? ziu&3UnWsn1jG}gZqbLYdJD&nWoAU767G&vaR;Owwd;ZCh&Z>61mcEuCqrMM37X4L* z^4;7(reWN#LKK8Y3(3W&MdZ3#z0}~ab!N(c6|JxygWLd;5*6lR8CSI~xn3;ai4f*D zLs4pN6bwoeFm{pL_U_=fNe2%QiT$Y+ZlS&{1{hibo)zLNP`r@TkY&=M=bn9X2H!b_ z)A=xHvb%IDKW1N9;-#ZsNnGct_ffEERe}pDz09aebvsr1)IrjTx=4UfQY+$Nh@oPp zHV7p31i2%a%yiifPDlcCjMP)-j{OLV*;ackT`goDu?iAV>>Co~Ft_CVo#xDZOth&5 zB%>7-*^8I|=~=5UQY(&dbk4quV{B*>_8KEe(NE^?qK6<IpGLGn0aZSTe|<3?6@F28 zNC&}~YjPyN60e9ZaK2}n5Nf15aT11IZ`us95CDY(007qk5CU8t!OjUGTahFPGPnk~ zzyPmn0S>+wHYmhR2^)er%7e^k5-n-wO7|`9gIX-fPRqvy|Ca|xq|1{5oW(k|caeyO zQc?9D!pu!K7>@$m<CE$aI<=)$EL&KUimwOcKAK`W#mlM^<;a)OLf#@^>ar7RB92^v zFH6yqM~c-B9bC`5=9N07<jAd1Jabho-L(4KskB8%=yI!j<KU1@#)Z=x0X+y_cQidA z^_c!xC9+_2CWtL>3CQ*42!ggbsm}#FX%65_m6sfv?K13B$`xe;&e|Ot6j#>;4#1~d zt;8>xj||B{bEHfc4BMTyS{qSy%bgc(%Z4o}oY=U$hr7uBuzG$XFfRO;E9$?8m6FmD z^NA6_D~*LfpqWH$&1tQx9$m?=Oy+j+S@cg|WO<A>*g&Gt{7I(?)Dt1V2DrEdx-fCA zQ(&D}1MDUP#B3a8pg+=qH>+;F6hho}1*tp~?86;_1WqiZ6a*e4JqWcRF_4MLrdIoc zsr{5dPQC_S3>R~7`f?ZzB&5P(A2Dq>sBKjFLM*Ne4<gdQ>KpRM`J$<EvmWvHEPX<c z;O}J#+2ie=6D-}+{FHRd1iFYU_8x2Nl995gJ>-m;1UVH@-iesOdh~gU?y=B;5Kqzo z@y14C8d^qo4$=pSGJ7Z*gu<)ZNhv}`U<e5Unr4%V&2fSBKznCH@{4_C90iyS+l^ut z-#VAzd&3a)sY}0DXUN-5hTeN72?1M=zJN{lNIeprFK-x{fg$oeBtZjDD2cU}nt?07 z?28n>+@(4yb(=+I*hQ_CycHfus&p+Lg-gOjsj%AGHF-%pt8|%q&ODLFTY2d0Bi63V zrV0vra$1L6!zW7tg`tt#9QvGln7Ck4`r*0Iqlx6TGFjYm4qZw&IlSFUQTMhN8j9&o zeIuAuTqvOgFYG{qOH~mb0yanKU@^__6k#WWj#QQ<v=}4^Ha%&(?+_KrAka3SOJdX3 z8G!-pJXu>#L6Xc1HY$}OV;gpLRSQ^Q(569g+i^6`Nj-nwhvhsp$om!&ws=|cAME-8 zQ%2qx{+Io%X`TJM-uP$o;vHF36+K}G#e8vF4&h(^S*mcVYe6?)I5oNlA-{!*gARj< z6lLP9L=aUo%7s(C6JH)JtPcSao9Lkq!4N2y@&r%auu?#ZlGzFRy~CsqTbnmhqn;Cu z`8X+EcHB|k4TB1e)l>zx$>;y176Kch?q4Eb$l7K_sEA29bDBOnl$aEBLd-#TU5?#& z|24JAqcFC%+fH2EO1tRM`pGK9iQ1u==xqiJt`eIobmcN#=MqnwI)QBf5Rg5s@%)F$ zXe#9n1U6xAPvt|vT0uu{7XyPuKf-b%;lx)1Lsullo_bjXzh-(mTv_{!G-d$Rc+706 zwjpw!^xn5Dx)>Oay4}cGRtXvSm{waY6OTwH%1an1$#&>Ol0|r6Bg7qWQd_rE#Z)H4 zl}{A{vI`hBU<2c@laxle(Jw=~yK;C0!1tV^W^u@;kLQ8e6gD;1;4`c`#V9c*D?rYk zVphA(YEz4^eN1J|#6soGLYE}>*NDwZ)5XwTV6^8e)kGv$mZMQ|`9}zXOw~0+`IOco zUuIJD<(H)JL2U#&U_dJ*yK(>~U<2AT-~=EJSaGLWYl$5S!n1@GQ-sli7AX!<1$yr4 z013EO39zcJoU(?I5U9$^G)qZOXtc|U!Y>2D{)wdBpg?0#SU)`$$;KsC7=I}RVu*8Q zlPrmBOrL(#L|Bq93Bept2HOCD>3q|2QW%EqDyYvrcshh)A+iA~F!}m1d~+Ya>l9?Q z#OB$*Bg->Lv_d2-oEQ5g^ty5<Ce9(x++9NVtPUvGdQzfNs4si}kxeW6PE!N7ZB>@% zK>in_n{L@#JM1qW7KvR+_wX`@>vbHX=e!6zL#+u~DVv%^-FLl95kj%4S1fc{VaUm) z{N_}}uM?)yO#tO?u-OTyYb)ifK5_pIM0v^eKuzjpj0lu`1*&hRk%-E>c||DTbvGy_ zR7_Zgf8f<MBT+7hW#Fu>k8_q0tYlOex-nN(4Xfu(KD<T$$X!f<g!WaXZ~9CKqRmoQ z(?rxO>!J$bqb(ZI%(5;y4Pw#7qiye174Vh*2GPc3=nMnx14$3);ENPMsw?~;!Frws z453Q8QZk+RlL$twO&b5ctfZJx8FD|~h~@~bKKBs^XXT-7M!Bd|hURwdq7sF3NY`~- zTm7|)TySM<o4}3I(}uxQ*`kRN8dZdAXu%Z4Dc;OZ9wJvF(kC8599EO5{s@*fJpz)P zc~1qCU;qYG009>;Knvg~01#0}W(%@=wkpvgP=~y6MpNUPR3Q^zM(k=QXv!v@qu2nm zprJ-Fc0@P4CZq|2Z~|r~Vc4L|nl{P`%`NssZJ$ROnBi5!E>dL{n4KX<N%$2G<1P3% z$g)%P(l0ea2{Jbu#u`L-Co-IEl%JdCm31iIhSD5J2@SLZ9DU|XMJEeJ0MJyYNrbMV zT|r2ZnyXE^q`zhxYT$$X-R5Cl8VaGTr|5$1=e$xU_M|N})#3gk*xY+`O<$}eD-hv0 zT(vRMb$mq^K#-0diD=&QQoJTh`<UAiMdc%*>z|6EC|rW2R2)WlwUJCd)OZD=wJYTO zcV}AJz}ek{iafzMt@a-0BCp9fb7uU{V7u)fNO`1UD%6{g%VD3`t^D=MGW6v;7r&Yx zlUe6+Zb>`2$#;`dsxj0I1vg7ewFo>}6ntnDL<)^?{VD~i>`pI?g($m6lH@8edWtX< zJhcKM>OKV7loT_<<u3&7j+?XqiGiUM5D1+^=r@}yxOjDJvuqgWlq5-SO1Gi2d?q>; z684fkwZ#FUSY%er+ft&V2(J%AZ&-gnJ~dfyORADcn_!rFeG^jz^4Mswje6O1Tb;z= zSlBL$VHlD$5i%J@oH9_#A14P}`aaDuQc$*cdpbjLp)LCd08z^r`j=2L@NMY9BRemN zN<gWi9f2=IFQK7^srUpsxaui9=4^!67#!F&0F3sf1HvW-WS*YsnGf(`NqX9yu#QJg z)P%7fJiUiZh{YtZ&M!$gR13#TB<c_?Gc7Jsq1Db83OVS^2B6(8Ujbe@TavdLP+M5G zWR@?IR_<0}&o~OG75&AyC`vi%K-?|*<fb%R8y+L`e`8cj(d3fHmlqDR?Wa;Qaa_ei zI;#3&vNXL1M(?Sb`_V(HD|O*6m0R_*S!JenmZi#@X;AzXC*jIrwb%|~WT0W-k|~0j z;%Jzzm+d>Q!F*FalMI5?anx2(Jh8NRI7l5Z2ec%9;E6zsP6>}fc>r_*m1@|yxSE*2 zk^Mkq1Y1Z`YJHN+a_jV^Nh=-hp}3^PlRj;ZyjS9}Z`~OnwbE0CdgTGt?)Ov<T-Rlm zqbdt>5Y&GXCu&vp^emMuA|1T3@o#ks9hXHmx@e>pNQVs_Q@B;=Dlk=@g;gt3>?S-7 zsD8p@Bh9Zt$PNKEf+jF^<$rW*FJd;L&haZW!<(Vk-XzZF6G`PwB_;l=_dWw;N{%r< zxAW0;M6j5)Hk?uranaVF^k}1?p1vp>5NX9CIjj>F?Pe4%x1<tFW8KoN5X~P0Fj)w) z`Nl2WjS1S|41gSEAY+{=#2_aH$Zc`~&eR1c11=c3HbOxORoU5>hhrTYSeITwR`tIG z7|NJl$|RoXbefpA6pV$9st{tgSBpAhgSe+gKM4~1Z)nN524R*BBKT;fiDSn&ayNHF z;T|AJVXOpba{*Wb)INmZKEsmb%FyA%t}RQfWBd}#KP5BIQhCO5dd`ts^qL3RY;v}i z$)8S}j{P<pDC;?_mn9N}TDOuf5@`~rMm$#XX!&{%<!{y?biavHbaNdwM-Y#$ejIN` z-6ABAEa-7#Pq)H1F$n~K=DLZmp<={^7-04nq%G*J&bpHtWR8nY%kH7jY&KS@Se&7W z!zR{BY86_H(&C*iClXwrk>m~`!d6lw7ZyQ|`}K%rTC9m58o@vKF$JaG<P}jkEcVC) zj<Q>pzeX_=%WZ#$bhKGq@eGG9Xe2Mf&aZ_X1oGq%Bu!BH=^=@Wh*HqWv)ZF>lv`FF z_06zf{25t_jhW7~ie17v`$RqesGp}K@<_4aKVLtUVP9jg>WbW+;=0xUTI~ZO=O}~X z$^!?y%6jMU3&KOT!F5&y0Lha~YR;!jJMUHfYe6&*nzakDOz;vVmWi-Cr&}XeZLhwz zd9Q1gJ1zP#$wV4<Y7W|!riC83pltG1fp+4Hb5p9fHszU>N4796q`n@>8S;sPSyd^X z-AcjZ(r%yr;hRek`3Wd+_8q8ecA9Mq%0Vq_`^<vNkqOVV;R#CdF#6LKMCVa*K<`v! z|Cx1LB8BwOB>cWYMBKWU!Yi&>4rwmR7P4Imf9)2<Z?Wvd=d_vmpK-M!&K<E2ak&2q z#6<ulXu^PCeTjmy)nVfC{LTYg7r{sQi93D&nqn>MYWdU1!wN8flge9eY!tezLuj+G z*nDjW!w}R1J>!(XE_40zw)e(!jGn+XMlk}lULy^2I$(E+40F`vcE1x3eZ4g?KQLk+ zA%K;8f*3-o(8~LZwrPyc7+|Vrlcj=xCM?FQskw(Dc6hY;49nK~Fro$MmQm3*j`m_6 zwwm;E8|&#hlfC_)_=_|TlLM1iWzE_p-49rJc2X253s(dywA2Bf0Tc-G3_gjLINI%s zvTpfo1^Bi`!x;xmax0u751ABWvoUrHE4YmbN#Kaek(W|#Oz{|pJtnc~I@c<bzQ0ok ztwJt>&cP;$UGXAaU1!zCS8V$3%JRcbcP|8De>qw%GnTb#_#Se2uEzM8QVutb-Q<%| z9}@xHF=oi*{jRkZx_3i-n;dF*-^-?{rSI*ZF@m$^?-W{uF0p4os!{17N(ia2_oH;K z<L2c-8N8CU(ibt}ZR7W9Jj41S)ICn-@K{kOTRG3fLifvCc0({8RYK{%ulWhh%#bZ* zDeEKDo!JvgH%+^>9@ny!ldiTm(^V$Ck|X;U$bhvA{j`xP`U%vzjWdL8G9*KbY$^or ze37!sFFFt7&K3a)N-Yy5Wa1u|f<%Y=ncF5_pHo<uMx^^FDEpFC75J(4ao3TG6jn50 z2tKWVEJvN3OmgxhJ9v@aqG3iyU-ii-fZ0|m7G7e PLVkfU&k-<#uQ+<Ee+h>il@ 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�X}i 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Μ2Rim7T-AatVQ*vt^b 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 literal 0 HcmV?d00001 diff --git a/examples/hubert/tests/sample.base.L9.km500.km b/examples/hubert/tests/sample.base.L9.km500.km new file mode 100644 index 0000000000..656eef96e5 --- /dev/null +++ b/examples/hubert/tests/sample.base.L9.km500.km @@ -0,0 +1 @@ +17 17 17 17 296 296 20 20 20 461 461 20 184 20 20 20 184 289 144 445 445 213 213 213 213 252 215 129 401 20 354 180 494 44 416 416 416 192 192 180 180 84 84 84 16 88 88 88 88 319 242 240 348 35 35 117 404 197 226 209 83 55 55 55 322 67 94 199 118 118 118 118 118 118 402 219 219 219 222 222 222 353 59 245 245 251 251 241 241 431 367 367 178 35 35 35 458 192 351 41 324 324 324 252 464 464 139 139 424 424 424 497 497 497 122 90 42 42 147 380 380 499 319 319 319 348 348 33 33 394 90 76 465 74 425 425 386 386 431 319 319 319 319 319 240 203 53 473 34 340 340 340 340 116 64 212 384 377 123 123 123 216 216 216 114 114 57 57 57 203 381 381 117 48 13 47 80 20 80 80 320 7 7 364 345 141 141 141 141 281 281 9 86 221 198 198 22 283 455 236 239 239 107 107 395 286 286 286 468 468 406 406 467 176 176 176 328 200 200 248 464 145 365 365 365 365 330 385 457 77 77 77 54 224 300 334 334 382 304 304 271 186 31 342 342 342 198 22 283 5 38 162 232 232 482 68 26 26 359 359 81 444 213 213 252 143 458 41 324 324 324 422 143 445 445 445 351 180 486 315 315 450 450 450 203 53 473 291 89 116 379 243 478 478 66 482 482 105 105 336 336 354 29 498 498 498 498 396 396 313 37 314 198 22 222 222 222 222 245 129 74 74 437 437 496 496 496 413 94 199 41 41 324 324 318 318 269 342 9 168 106 106 284 426 426 426 426 348 64 76 401 259 108 123 153 153 153 153 372 372 396 313 24 314 90 401 259 445 445 351 351 365 365 365 365 282 282 215 233 233 229 427 20 247 126 126 126 326 326 326 326 326 326 326 101 101 101 149 228 228 20 289 20 7 217 70 65 189 189 151 240 285 300 300 495 406 467 176 135 135 339 248 466 114 222 222 222 313 313 239 384 371 490 490 38 31 54 54 224 494 494 236 129 259 74 190 487 288 288 288 288 374 173 173 280 280 302 302 175 175 69 69 223 130 129 401 75 108 119 295 295 295 295 143 192 192 135 135 135 135 200 200 464 255 255 255 251 251 241 431 235 235 235 348 348 465 192 44 44 236 8 8 354 319 319 383 348 36 310 107 107 395 462 462 8 32 32 32 354 153 153 153 153 153 387 387 387 387 85 207 318 318 318 49 453 9 168 125 125 125 125 125 466 199 44 44 143 129 144 445 351 351 351 486 486 460 285 285 302 302 497 497 122 239 161 161 79 79 499 499 499 265 265 265 85 85 85 299 299 173 352 352 427 229 170 247 15 15 15 15 15 15 193 193 193 17 diff --git a/examples/hubert/tests/sample.base.L9.len b/examples/hubert/tests/sample.base.L9.len new file mode 100644 index 0000000000..7d3028fa24 --- /dev/null +++ b/examples/hubert/tests/sample.base.L9.len @@ -0,0 +1 @@ +596 diff --git a/examples/hubert/tests/sample.base.L9.npy b/examples/hubert/tests/sample.base.L9.npy new file mode 100644 index 0000000000000000000000000000000000000000..574bef9c7cb6881eeed0d5d0d077e249422e396e GIT binary patch literal 1831104 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�U9?h~g9lew_Sd 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�w!usk?6$_;){&66dzfzebsi>d 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 DATunC#iAXN1c$7hAzq^a=?ZNEJS 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%0AGa#ujl4X)qurJsU#G-Ri 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%0DfF~z;1F)VJ<1Y<`!&HhwlY`@N6u9CwzX2 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 hYHOTt3o# zKOg&o)HCp4<~yd_K0xw!zY!j(cn%(WkF)o#EwE=(Fm&M*CSz?S%*ywe*PRqn9$XAQ zKL_IP*fzdr-C)}Kqrar2q5zxjYvG5X=OM|dA1+a8VPnV2Q?q3Xq_l0Lw|mxMQ^q3x zVKLzWk2t!qunlI|{o^MJnWUc4#6leNP;H+j=9Dm2Yd?=_yw1{${rR|Z+j-P29V^+t ze=9WI`3I8%tN3fXE<vg1D^ZKaU<Xf)>F`oJo-OYgil2Mu!3pnG;y$kyUR8Q7uInhk z$St4YIz;1yvsakmm<wz{mJQL9H}D`xf$+mVde}Yy`fZzr%@KDv&a8&zKPqFr-Y@xp zhYDmp@)MgdOdm~G`cu-9|0rz!KGvh4i4EsYzyoI!d~~;+x&K#yVL97a&&zxCukH+Z zW(*-Cv*m19Uk}-(2^{@#KPhuc9e?2Z2zo2M4dKuMZgAgVH2qIt<+erPZuv2yF(H9; zx$r(4^DP~xoEwjO#qY^8{Tl4<als&(%VljIN0;{zhJ6~%T(_^Fn>N+d==z54%|6ET zW*nk~fEDy>KoA8@`Nsxs@Ml;W#a7Rl#R@_isc3W}UcUVjRx3H9c7Af*!j@Rlp0bsO z{2T}?BJZ=NA6HQ;J&QNIs*YRp4`RX4!SH;31hwsvm3-Iy3EeLjGAFGbD3LM2**$)6 zEy@7Ygmb>0S|Gl<H2v&9^-5YXhyxqrB1z`%3AA47B6t5`8Jua3r;{&MQd(jGHpZA^ z_Ua{gca*U>eV`FO7QbV1HvJ?CJ?o(4aXGv9L@3HOwAH)C#^cdLY209e(|Pp8HNhLa zh<TOUvUPLasDzWD3)>DLZ%_}P2Mqyv#dGZDmi4&k=v9`pQjZFf_S1hBmq96yXhfAi znx6EayoM)m<_FIP<Q?P8$KSx4x;9|0Z7JpsuEtHCeN5H!hREa2etNuRzvSW;4e{>N z-c<k77b?d@u;6p4h{IQ5_O6}S^WF$EW?bY>p6E{s*=~>;y$|!;^=L?qB?}pr2vY`W zVU}zx)(M^Q;EI`$cu)^RI*mYmpBK(NB|>>^6?pT@n(0hG0I@C%irosJ|Hc0(Wy2M& zR_8SFA7<MnRgWP}wV606a0W7|7`F7_K@#5<p@jEFzQRNj+$4p=tHLFJC!S$;r;f9Q z57j~SX_Dl^I629?pT9(c=mKZ?-K2BTr`W$8Y0%4g+Uq>~4kJ%pVDVB@nDf2YpfPj< zT)nS@yRUm;*{7kHy(0y`zbc~(FBR!WeF)Yph^8%XuV9bR%UCrblATyx0<*5|#+k<~ zV3^WYQTV#Aw0FpT)?M9#FLQtJX3MWbtqq4as|}dC^;u41$$astwr5b{T7oqxiLh*Z zG7Z`}hK(1zDdFo!VM5Die)IByIK7%Ec1R>&^;U)%E<a5@zUyhNN)*bbR<R1-T#B#@ zX3gGPu=;Qi{_z`wen;|PY)Uc|O^M(ZpV&?v`^EyBktzDIdnm5SsiI7eGqic6u#c#a zBGsHm&dk>bt&LWI=>tcBAz}jx7ox?kUPj;?eFCEAT^0Q9X5v+M)>3kxkkL+>j|n>> zV10ZY9G^J~8gz5eX4oYB`qYrDV)hBn!agQ>E6be!DNt!x2mda=A0(G=#BW<)V53hh zITg8y-L8#>ZaZK4Q}m9lxcGxrH52DjJc=eS6SDe?@?lVHVSP>8W$M<|kn9R<ftT-3 zGXFzFa@9xBYmP0u<rKq41f+<iZeGG)(?@`XZ3P+*)1e)I4RD=)3hn$t(DTNbWqm1z z@gvq!OT%HBZ*z=B{8$eKHDgI5P($n+zM4ia4&`p94HlRfaZIl?o?Z4{%c_q>z~(mx zVC~{+dj9Gp`<FV3Te-5BWxk&VH@8WXtwJ?(QzbU{Z6o>?CWFLG5k1Qb$@uJWvB^_8 zl#h`iE6V_J--0y3L#V-498KrO+--ucpX+HFn@)E7Wk|atNOUTA4wcQ&z^fA;uvxD> z*$(vwq@ZMuw)TZ|Wy@mt?3)h3BVIzQg&GcbYNX#4Ct+dH26`TpOf&W>Q$<t;r>kLu zU8R>r$4-yo@9&#KA>o_wdS)wkQg<Xd$IOSnQYGw$ni88}`-H>h3OFr}$2KWFw2u%8 zjHA+eZ_5edM_;VOhW=%eJDSf?+usgGmCc~^c@Fsa%y*V%oJad7deA2yM{F9hjr@-n zLHMyDxWl<W!*@;iac?bpio#%#jxD<n4rpKVg-za|N?n1S+@99GblBCM<#Kyy%%98H zEo5Fd2DqWK$^#tII*d$rrZD^WnsoKa3S6K067u>c*B6|B$S)bwkIm*n*lmqy!aoAL zQBI1&Qj>s5JXo2#XT9~*g=AMS6bme0^6Mai?$p|fx1Ul)&vjb`-p^O|xaJ6pz8l6( z|2KnXo--639h^bmRti4KAJWwQiLt6p?acdef7~@^3Cs>#!a^le>Mb_4lYdqQY#9H5 zUYFmauP2>JMm>gYbiIo1O~GWd)B{~#jYGNrY;kJaNQ(I>IJ<v+5cOLmEBRcxi<^H> z9s4hz4xzK=a=*t1)8sYInA|LlA=Yak-Cq-3woQX4LN|ZK#Znfdp3h7l|0Cngm#|Iu zFDnnrfLW`~AQ$NZ&xaIn1_~zyPO&Ks9F#yBYg6do1r@w~Y$AH7dZBsz9CBJe4AkO} zz|W)s)DgaghOJYirEY`i#Gy1;8hQpM#+-uVx@DYu<#u*!Yz)>LpRk|*){?U77onf} zdsv!(o(*62k6ZM9huFX*maGa~K_OuU+?|_E&3*xNq<k$qaIls$8$AjahgGwd;y0jp zppty@9pKEQQ@la08E%oj&EnNYNwP1U!4C(9P}8VZw$4bIzHS`L+X{COzc#I4fj!T# z^2a(1{r6W?;PaAyCAdb{gv*PZCZ(}K(~{X-w~17KXb26GoyLaT9$hOxD-m_d850FM zQDuAu4k(GF6T44}YoC;X$gWPZvb!I)8a80piVax%$c7ouJIfvG@xiEvTalbaboEjd z7djvm=b0Hpeo}S)le+cdgS$tt^S|ZsZ%qtp9B%==0SDO5lfi8GWNB<h362)Bl3Beg zNlhMD@?$Y=nsxy9<=%j<IfKEbCV;)85GHYnVSGn_veS%WK7Wq0s=ZyzH!+7F7Ltyd zt6Est!D!GHsWgli{2h06irKky14&xu7#rqkBia|dgA>hfLUwtrc)ih3DA@ELH2WrT z$uGZ1<dqlF3$Jdr<BJ*#^`0&mipp7*UIQ~wT!t^keqqnk2Vuy-k2K`48h`4?Vswd} zjeA^8C2q0Gbg^<g)%6>Ridk=AykoJ%v;Gmg6uBC=oI58vDsUCvG(JUBa~FEAv72q$ zQV%<G!l@|dEUU7*3uTvnNmhJo7r1IEIHT6t-Y@Dp-8fKBOZ9h<r^@EDZr`-%-hWeQ z@R<*6!}w5Y&q~9TYI)Hz-HXCpnhE!{x3DE!^r=YkF`t&#N~6!-VAEdOi$&jK=}Jio zeVip^+0QS==<r<B{Fp@1@57kxT?q`|EDhXv6L!i+jvsw03RD06VBLwbxNMst?u>AO zs4I<pOTuMNV^<~Xw|PA{U-$~;c^hcf#VDNo_^9v}il|B0^|!U`1BEAj^~1shPn2ta z`ed?9=rg>duUpM%#rT8Jwa%G#A9TeF{p}>mz4`QYW+V8!u0kW*r>r%>6D<eJL&}Ig zKITXt*F4jgCdMh^@y1J#+kJr9e24_K@uq?^_C5@|(ZMoj3SIMm|8a5nkma?#WzDfl zk~;rX_`ee`T5k-sS?WuE&YXd2PKh|JX$=K+KH&arO^4SP*YdVEZ3PDIc&47zLmwq4 zM1h97sJ5XW<tSH>{Vx^ChLU2u);JudjyenTXC$Hdk!7@W%MkiBdoD;_97TmunV8() zAI3a6h4=rS7jl@1Oe%Of2Fk5wXXDSX4}Bfjux%_>z10x4_6}ejPWQ+!L>hOUml9{6 zA?E)$kj_N*LxrSHcs;WMBFYq4Uy_W2a_ST?kaOm}i`S60mOJ)an<yUnK!diqeg#YX zg!9cq;Q3ZFyfX2LsMzr!UmNm(P2h}i#T^^k+3z-sjD62NSKg25^7^pdp^ANk8t(ln zPuyj`nqGgn$=zI>2eC8f)2}C|$x5z=)tJu1$bLeHKO_KVI-O^m#x*nj>anP}eK%Ff zIYXY`F#3@6m+>pTXlh0T?)oPyxi`*}Le~j<QO*Tp{ExAf3oKCQi5Y}%^1)TcSxh%& zB-OYC(FnC@Y?_%acrU_8Ix!dAeeCewpKkld&vtM-h8)IATb@Il>~!`ZB%Pl4I+D=k zVRr^u)ul~UBAIbH^jjr}PxTP9r$L@<MbQ>gkX)er{Cha>?p0BuLllDeA=@I~M8nit zsOXRaI7$^!*v}*Qar+WV;uhhFi6^;dUbmT{Z3b*rN}%JLe?e}kDu2CdthnUuDYyn_ znc0d-*m;`cT)AZITse|H$9<uTLa#NjI8stFbRNA7D<Wt8NKsLeEG-CWqBNlsQ**Ka z7leI*gNHhVtZo#GE<O%nTHQ4M&rv?|mp8ec$biSLoiOn531)v`6zx==AsXs_h{Y@Q z!5eoe$@xEK?DJ0ra(FZcho!EDyxuO>eCjr&{MN)7{<~S&%bD~kD2|M0D?w1@W^ui8 zDI6E(k-_7m;KcSK_A*o#S9G4l?|b%g&&D?5l2B>Pw|T_se~+PmM=VGs<fMda7%6_U z<2Wr(mw=m&;PzSBj4LdMi<f6-vo)u8vEMFMB>yu8{ucJf0e0;$yJG>W_%FqI7EV;t zbppiylyJ3iJeBXb&UJm+3;R#3#<h}h;?WtgXee|CR9<Gn;)hG1<aH_<teedYSHEY6 zXEd`}Q;vd)t{SQ+#|wP4I?VO_4JXD~Q9{^qPztu-l6RVd-_sU4drDE<+c8A4eohAZ zZfeC-C5n_ed5NU^WdeWdN-CNEn#n!+6iH8BSm8PQ{@g~J74UlY6|7K=WBoe(=&$rK zcvou#w*%@R@LN0<trKC!(geYSAS+oh?F`HAd5XDd`K<L#8J;ygO1df>Jkc`1@21V{ z?j<pQ>-2f3zq^F`9SbMF{ui({FBD_+1wZ@9xwLI#3LCTK9IHzU=5s6O31_sO*jaf9 zQjHAgm{u@ncTmEoe9dR8A5KKYAImAnM2U_TKNfO-581?rZmi?|5i)C-fcI6UsZhAr zcXT^QKZ6Z$HHPC}B{vB4x&i-fJOC|~xm>-mz~^%r!9HZE3Vw)EmTS7SK6bM+iteqV z^3y~MZ%K0#XAZ#)--ojco6MM|_!N9JA1cmYGY*Fy;J9<Tm(lm~VYbF~EXfAf3v6o- zbP&~G%|=`5zpoIMRxii9l2ULxb{&j!eb~Hz<JfhxQ8<00EXfX!0@=B0<lwzhRQUWh zez^4y4)3g?&x2HGYV|t?Il?{U_xZed*CN!YHNmPY3t7&_UN}<|$4s`aqJQsIY1r;D zXj;`uvov|qJ#ioRDP>~G)+E-iE>7&~7m7<xoxq@|T(r9*d|okrct__etJyXffA+Q4 zs|5&*{Nn8}*YPQRoIP4N=YNKYIuBX&zXurpaUlEG&XI}BZnkCFJodS=mBPO_GTYVD zF|51^=f~+u8m`NrmFzpVSlxmycO~LfqjqL_^8zeQ>tqvqGGNX0Y+n8pl1Z&H&AP85 zo+ug)JqOk3p}jc`c@RccUCMA}vplU7au~<URU~zd2hqk!hviR~My_)Mi8K9R?uRfM zoe&|hUK>VDHAisNoe?lvONMW%NJ6dE-|QxoY=cy@rSzN$UE4i}D5m&0W$7qUbN+MD zo#TeQ-^dr-xqQKKsqzV|cZEa7niM?pHi8Qs=YUBjF|^S4Kjs5U^mb{g;A7f?)9iK7 zwfYL!ZtI6vU;d<XZ>sUZXhX>@!{azZ3-RalZM>7Yi`dNbBGvu2C;x~2B|pL+;FRsF zDDZ{AJF^JJ^w`a;ZFjubahST;bh{sl?+wAW7m;j$XfNn#{a_z1Iy2pv7}nZ(j}CEx z^yJP}tP2-dWGIcrfdj<m>Uw0=dx5VgJWq!V&cN-m18A%|7e`w$<`^~wmK_xGa%)ag ze_d7buS#GCV{SvjkacX3zA83w?Oa!119}%N<|j28O1gjZV%J4upiyNqE}622eSDQm zpGJP;tl~yd{?QngroW!b*USf)@s(}eyo26t*2iypd8n6YSD)OVOOGd|lW|!$<9s}z zZ$JaR*po?B!kyPinKN`gHIMTvxI}~h9L1p9N$}r@TsXCVIm;P(pWPnq57m1QgXx{s zq8rz$Fv4pF_Foyy%x$ySlxJBG*|!&zHe2Im=e=xF@d%orww>lmr_#)3L*_l_7|q)K zjXU^j2ey?vQ|CP;qSOsAS#T*GYb&JGyi4?8#~UW&Uql6cdMs*@JbD`Lq}^F{toThb zHt)y*-Pvc^%9<r~xu%iro3@7r4?~;~9g0`?Wx(|xmtlQ@;L3iPgL$=G;20FaGzZPY z=`Z40@pWHvI;enet_6r~HlHVb;W^tU&gG)bzOzp|k3izXXT0@c7iyj`nsO-*Jj^0+ z^3n*(-G3BM7~HF$oYT%a^&45e>|V+HV{y2sXdLYq`1(f_t+~frjc~lz1g2V)2&=mf zqEVWLcuJw7Fn2tJQC>Fmuv8xhG)&}jvUh-9vI3(;T9l+b5=DW<Fm2CIOgYxhQZR~r zy?u+-)a6ic*<<nQO>42+B3V-FnN0fH!?Al%JjOZOQDglw`2INtZOZ3jRr(>OJIV&1 z%}>MW$K&C?+Z{O6UsHVaj6b?8M^q8=bS=|<zzX3^Iwh<If=}hZ*})9Yi2=M!e!)5q z3H<2QgOQW1QESCdc(Q0AF^47W=Wr1_7`>Q^C){TW7REGukp(RjcCnrRHBrzk!L?O& zgAV@k!F7MzB%4&U@yQ&)jl5_meLql5QkfUI(#RulQ#lVkWcm=A`q+qhm)Y4@+9>tr zw&Yu?CsbVmT6lgop7x(efBov~@kIu84A2#iwR;H(aYxX0v4pnY8%UG1vS|GtbB@!t zk-U!3fYCD+@`ZtJU~B1zExS!6{@43UbhP&1@OgWgmy8>#45;Qahu<O3`TO{<m!0v< z(pEZl&6@T;c>!%Yb&@ra9zy1QIh(4r8$Vd=qiLT<lWU}@B;%eX9P=XX@REP@{F$`m z%$sdO#$_Vb?2Hhcc9XI8i5acgD@E_#&1O@R7gCFfCOvZVW;&mx#QV=7$rzmFrr6$P z<yuH(bqV<V-nqJ$FGTctU_0x#=>dD-F@e=|^zkDMuEL*p)97P%G|t-p85(1+K}eL4 zK?t;@9Tn|#^TQrID7OW>0)pt5I2DesN})-z8kF(<FfCkZK~Xn_xm~p%ZV$0$+<!m7 zNoFs>Z!NMMFNT?UNfeP;B$BsOlWg+#q-*mQp-Y7c`<9`LlWP@)dx!>Z_=c0@KhKo2 zw9=xln*ZRpl`#$(FZc*`AF{#^JE7i3M4>}x&^_g0<oUc9FIHNy&r?I`ZJwK?QMLsY zD(ZOIcdAtDaEi4n)-fY9HF4Fs17vf32K%^vDV^2-!aHse?hhSvU`)3M>w9z-&zS0> zuc`u59w1FCZ6`_I`3kH>+(aLTOr$@L7K?=41~sev5zY%^Y5kQ7=2mf=o60Jn@vph~ z{Q_0Vss2uqgt|+3b5DQ1R-{U*t{tEjA&2u$J>VjxiXiE{6-D2;#x0D!h%5AB(Bn!A zto!^13i6UM<KkWzQ6s|E$u2nIy%IH;Wq`(<R?6}li)RB1P#?xp)ctf;8x)Od3Pmia ze>rZrQ^^I*&8q*qb|JPN+6B?qc9Zgza&Gl6ckK0Ch|hA~@x8-Z`Qo}c`0QUfIi+u7 ze>SQ!*sz+C=jP(I&o+|N?~SO_rxA87+b;BUJmDHQm{xgNNw(NV@{>Mm(fqi7@G2Ln z6CCO*-35nrKY2{K(aE|r>ZsT5vPiAtf#`MrSIl^m8ESCvz-3rI`c0Zd7lw=wcuRXh zTE!Lh(ocd$;#wS$I#(n~x&~T{RPl1LE?%*G0&24&P|o}l)9PJ7@vj%rr~U(Jj^qVg zol#TIS)Zb1d)3gZ<|wn5wZ!v<Su|i(1p8<`NzB~c*>|6AIA^ZP{0An{k0hcsvIclE zxtgkXE8^P|Vf1|8Vr--c{ydk=^v&jBXx|{#@ZanDU)@t#y5bn|;*3aGcs`62)1O0= z<6$U@eht6Cfi6}rqUTvUTwZ{Kr0Q@L^Yj)R77oYxv@P#ggnK2GS1c5~e236IXbw~< z>_Tu6xT=>XpaAF)yo3#G&^0Z1U~7h7qBlUNRVF!1(4swtwXl9<8CyGS4{rV=BXPCW zqP+#@g}kjHN^2BBNV^q1US)&F=BvTrS=*T8S1$c{a)M>w`3~dX^WqtAJ(%M&XZmE+ z4PkfG$+yr6uMAy@lSj(IyNu)5IK2)Ezs;gqy3RDuv)*n;e6%FZQbT-o@@e+Ute#ub zsR`e*FJr&iR^oSs5oGc^j)WB|Jsa~H-YSfPpzZN+Su+q7OsnwQ`;ByCnJoAie`2N^ z<H_G<8SMI;%Uxa*kN$(Eh$|%ZsB|z8MkVI*or@$eVO=Wj_nsth@ouy3jq+r^Y(Io~ z?L+&p1=QQM1C=+3SVfF4UC7;tj`yX(=Cmfxd$ot8KPiiUXC9$P9x1qN$pxG=elX>o z`X5DS;!joEg<(X72t^SxRSL<J%Gqlj&9lmsL}}0{rBp;Rgvc05GB;@uB_(G+>ma2$ zmC9R^6lv6~Qu_Ay9~|fB?EO4z-S>6<pyaBbEN4O${k|}Xg};AHy&p^Pux%TgSUv~> z&Fb*{m{K~_v6sA*a`@Xf|MJykj<6&tMgTyU!nQtz`0BizwCQ7C8b0DF4lg*yEL}T+ z`+kaM)|Ijg^PJFNek!%;&tiqv?NCz}BiiR1LpO5HW8t)=cwkNm_^p>v^=+ijHM2=U zE{7uh5mOVD;O-oEIIrYOVI8CST}?4C#yN|RD~!iQKTnWd-E7t>^aE}mN)%Ox9t7Gi zxNPn9aKof$Y~=}gw*6%wjrl$iE$gi@FxDHCH(rCU(+eQ_WB?p8k7Uc=-(ii}BIG6} zQ2sLqZsbKRRNlOWUO(7JW4d;8&l_j*ihki-Na+ALtYe3s+w;)pWMA|Pv}IMH2T*I- z66)&Hzz6HxA-$0+aK2YDZa!#6=4lF?S02E?p<7@;tut;qmciZh_{iDc61;u=-?GU{ zwrDs~k@}VmWAz`7;2_-txY|rY(#DarMX!LJk3Gz%S1LhnzM0rZ=n6bjP=S>NDwtgR zoUOWTN|k|v2mIf5Y_2;)r}&H1`)oZXt=RxdXU;G=&qd;|0SRcYd<HcP_G6DtJse+= ziSHIHVQVZ9W{njBNdf+>b1;Yc`(&gc?bqN*c_1tsI+TVi5qh&z2g8C2!H;G!h)h(@ zz@+W6(qT)_u+^*g<Lf(jaI(3k^o`bV+;7&y6&h>PIospt@Ms{rHsU0oT~o|rZ#@E? zy^r{?ycQO|S&@zgD2c7^>hby~4ztgHoumieOIcc{4*Hp_qeZXcp+?{=*6%37iOJKs zmK0&`?+`*W&R4=l&tzI194DPNF^cAF5&C&6R>Ag+o&38tKYVr0n+@MF3{h%I(z#ce zqP!aoyHQ35&7!$qbJjw`l|d|2^AOnWw!p)gE_iyD28~@9fxBK`gk=Nw;n{X?8e(T4 z>33N~W~rX^7BbOi&UCzTQ5zrFE&=;vanf6JY*FJ}4I7skhpSEd;O&JE06q*C&s-%Z z^_i|ng$LE8CKKM`g&0|~lkw!7g0$hNOC#Ukj}te_YKnhtsm5mwmZ&{sBT41j;8l!0 z4W9jk{Z{zH8Q#q!`I)BlzM}$9js66Wrqv2;rLQ=9<qR_2BxIb|7E{FZ=V0a(ghB6v zFeg8rWxRgC`>dMGlw1ob?v)HZEE`8F)O2v7U+aV=!4cq}7!OM=uj0h6Gu-Z1CQ`$O zCt{;T0-y5rP0mZLnyVX=OBV$X=85rrm_^%CsJL!N_e|$vsp(h>>sn2h6$Ngv31RCE zCul~V9ZNYVWQ3<O52XZ{bT*&Z&oD9<U0`1VFVXV|bz+N8lBVJYv{|1AH`+GAy3Hlf zb>}8iSU-c)bP`w$jfSj!B9A+Ed7#-IWk}+pB?dE7c+bE`+#n}KG<Dw1<PAF6ZOsKV z&m^4|_sa8Qr=?I@tTIHOh(V7ni|PBCY|`-4LuG@LxPw0}aNu8(p-eG*r&35PWCVn~ z)no&QNhs_<H&2g0;y#T?=<1isUPmvd{-b#o)D=Lk-=Z-_J03;XR8X~HE?e2&1-m^j z;5nrR*u!PAlm6>)!;n5q@3RxdIpl!^^u&36uaLEN4#PfCFt0Y3j*oAEnI5}9d14Sf z{9Z)AYR+()4);)8eTq%VxrK}8ltHRN9V?mrovm8FPx`1v1t;&E$l}$Xu$)E0?(}0a z>MO>wkz<-+?Aw0WIx-ej{~lz=-P}-fmNj+h?!>o$gpO(WN2us`o3pqpPvQ1U@#@>9 zaPQg|%q-EP^bPf*DT(Ivw`4IX8+D6wMIt=5%RuUHMYK}7o6quF#=IVGcN}Ez0BhQE zQFZHFEIF9P&veVgW$uTuC*?hypPb59)eCzw!Kb^XEFbP&o#yDg=ofsHO(nPI8A5-5 z9nY2yL4BnI4D+J!UcE3oG*HL0>Sg?^qAQ>`U>>~*eJVJ;Q`v;NxfJ(qAT@tiCk6f* zbMu`~Hs=+jmP;=|n&cMUUEqU(0!Lc^mo8QW#uC#z$n5u=B$_YGjYbGL0=coct1KN; z{rgalyex%m4Z{KQ_od};p203<NBXvH0fuioM6ab6SkA?xOuyY;+{@D8l;B%kU|dW0 zSDa*}!_JZO^nB(y5v5B^1a;h+FR&u09UP^@(d$3Kt9QG<bX83WKI;x(hjt`k^K}=x z|65i%WAHlgENlS#^ox{JeVD&Jx(`<Dbe1}{Wl%r1m8L!PL8T>DWH9h0`&_0g^>ixb zE|V%w4(KQCF|4Dd+ZxzAVWzph@d|n>Z9{+U^E9ABk-peX7xG^sO1u1)sU=0Qy=@Wb z^Vo#Er|rZ^50j{R)iLJe90wX2GWgvN=+G`*BCQnB{iSB~Y(OZ>9$<)}$+q<3gC5@3 zF5voPdUHbu3ryqnne^JalCEyIz}n}^=ql_M?#(P=;YHi2T`P{wZrMXK{N!og_z4s> zYA}|ZiIe<|<!~BT#H!`Hd2Z+^`1o-vbxyMr6{(k!`a(;Rsoa2R_lHoMqJnhsxnm&O zc7^vnP)`<KhH&}eRi>6X6tf;JLo-7)aq<2Bv|n2XwdTc;qQ_S9tNJ6k6q=9s9BM&z zw=ZQq8ZI@t`Uu6*8>vKTJG1mk<>W5EVFQJ}tX0xkI&r+1Em(e>?7V04_br=5^1h2< z+hQY77AcGOyQDz(<u=K?e}njWOH8FCbo$R|ETM46CG>K3A2KgYqSV5z?5ye=ru|ln z{RmW({7&)U7swlkr$(4cpWmDzeEu@@jP>DeD-59tZq1^*Z<Qe2$^=ZdYEpjI1`2(9 zkd+k`V5{C<d{`HcR^=~2%e4|+*Tk^9CO%jpFkEq%3oWc3h34NQ>Gza6xb*1_`J8TM zN3SP}6xQ#;yQd$pic>tkJ`xM9dxX2zu}J*d8_Gu~AEE|tdFZ|#hP|Ci$j|LdrDluR z%+5SKp|e!FxBna{7xotYqqouh&3|x)x{b7L*F@SQ%ywJ<+Q8t_18BP0ih9mBQC!&| z`r_Ecrd{>G0sn5ZIV#57&Nx$Cr<%fEMK!SbZ#I!~Xd!%>V$4Q5Zf3_`z6Iqy!}09& z%eb^HhPf`#M*T)V7+J4`uczq19^*^6uwW6>uA2d_Ycz4}-v^*HRU3xBn2A&RY^PQB zld1JrGEHfaC*$%ic=_cobd1X<h2t$SaaIfaGIIoWE{UcwEy18TVx(9tER;=~B+q_2 z*uuzAOS;<k8a=x@5*sTj$<b~O%!;UFac*k3(A)`zC{^>{w;sdHcoFoePG_6K_1KTf z0pf1|Qr5KNG3g!n%8lEujY{+7sBc6eD^5BC??$On-m4+fuTPy|Z_^!SwrLspHZ`)N z&Kcwv_!S0)PQlT7=ivFxvFK1Rjy^<0VB4z@st(O$Ytzf&*Y>eEVV*v>Wm5^&8k*9D z*)L(~#<wg)I}EQqt0&di2%7Db0P(ZyU?_8d*pmVD<4iFsKM!X<BTloH<wT2r44~uV z2BC`DVX=PbP|_cWbn1%%w=Ci!b54v9&XQZu<ZV3^2LHeZ=gPUf`9~;1m<wsT?HA6x zeWWESyU?gU6K&Tsk!H3BMzmhT-OrT8>l@<e=jJE$-xtBzFwqPpriE-)$2+ikQvgbn zkKnW+`c#&X#~-fBq~e0Z<a@3Xf;0b0&TiX-;X~EMFO_d#)3j^6^`a2wc|ZnTbK1a7 zUICLg|6?vO^T=7MCr+Ihh(8^s5+C*#c8{D(eU6`?nj53hI(-0^8I{3|Bg$m<SVru% zxEwhRN3@LMaMHo+EXAaVI!(2u-_0ti#)r5@3x8=M#G$w$m0Z5wVcuRP__^vEE&IBe zwk7`JCx3Bdwl~7@Y_z~Feyk1Uz5<W=`T?>j*-3xr&c*E10485h#Wc@F(y>Q}=}xX2 zRyuE@VSe3g-ozO2(b~Wcazn`O7Kc>=Ls{eB1Aa`_OEON=qcx48R6U}J9{675N-&-M zDB8t&q)(*<0afs0xGs(y+{s<C7=n5Z3FQ1O8lF2mW1H4!q3_{b;kKSbDsz<ZX-Ym^ z8@`7tDIP%!U6<m;AI<z9_fJrjc@c(B=wbykWMS#lUViH|G1X)wa3_`SQujPLn5(Nq z-plhSy)%NYMWyiX{|pzpFlU)wn+(fyQNZQrF5<I^1lv%BJkvAKMqm!PJIL@Y!%OMr z@f3VBP654zj?>cb2~3IG$VMzO#~7tdH2GS>_p>_yja_bdVC-LsNqsO_TE6E=+QLra zSbS$MFaENx3xidN&CYu#iZ%O>Z@Pbi?@&({U-XKGhV`M?=bJwG*YBc`$?1&5M?f~u z8IL*+r}3JF<jBX+LG=Z+KmRj>g;&scL^K{qG8Lab;EI<j@A8=gf^gKP8pj>~bohw( zo1oatflgoj3BwolmCpJu_`!?Xc{sX>{+^nPPOt94@2(scZ8?K&st6W1DGE}~V?TR# z^*?aBDEPxG(<#hU%Ka<a4c`uGQt#kuw3+%2VhrE0JHGO?s^T5zc0$+#99e@mV|2I( zd3h>HIPds6b~9V;Sxp({I=KDlUfjGsf<Eomrnk3d3$Eibtm@3={H;#Iv2(|nXM_jp z+*?RPRR&0vPpl=i%hR#WWk37XcAGyJBe0Ir9}BJ}VIq2{fvG*RAQRmM^g`aBu3s$R zI%1!TdJo^_#^)^q^{UY@<mo=ajp|PnsEdyNmZ<9!fS)#hXCJyBvqq^RO%>cn+lPB& zy)+Ir&)4C+dM94B;<i-t^ju6cN#V;^?8ag9&oI@yium+wDz;lb5qdTcB`raU(m8!E zW8<VsrgrfdtJh5B`o2C6dlT1SM{hHB*XH8XtTvw31k%Yg;l65MNS+a`+=#C^_-KR* zMJ}99l|RZ+e90HL9Gb%)e3F6-w-`~)=tA11G>cXV%+$JJ8$j-iI&PT#5H62Zr^K7> z+yDhR_S?jsUC!=LHm@Bq+GaA=s^&u4RVnlA$-u(qJ^b@vd8u_+w|JE(jXr@T40vb9 zUjJH0m$%4cX-ow6+*yiO{;EJtO**c%oJHlz7wFzl3!LR=iSM`bU?jVeE7~Wb))(!p z+S?f&f1MQ=sKFF)QJoBae5SN%y7aB#3i-cIf@|joVAYN&{@!fCZ<Aq4hs8Vj13sV7 zbc{VqHZl{hJ!_6KHy6W&{1#R=dm&tVd6|hdZb9Og;qbJxgY^rXLeio|)bEliE_TeN zpy8QZslOfiKs5hf`$ej-^TzMyS5UEV7HNAPrpKQqlbuj|aCa8ruX7sgY(Wey2>;7W z$9%%sN(xl{`8F?JolSE+%qbz*j_i+Hz>;59n5yoD^BgYnw@xj>(|a3nq2LRYNjb*f z?6$@E#;=)))_tyDhlI6OdgADzmuRNw9n&{f6Z+Z8QZ99l!16o|d&)Pn#p_PdsP+b~ z^vhv9?lv1fuT~YmwwQqOr(GmgV|6Iq-(I@+lLdBcvgQ9R+9-IC=HQI3wWz07%g%Ma zg*Fvyl&s3dLnBI9@G?i#I&p?AYub%=3MS0uo;Nm}G=>pBmebJ3-Z(2;onxy?k+Onm zQQ#Ifb<R<m*jY|14*d~t?(x8)zZ0oXdp3<bJ4o`5MY8+T*5Q+mE21aguHaC`Wq5r5 zGYO6f$10h4^z*KSo5}O3XyrJzSh*b1<3m`7-Uv3oBnh@ToMt<V-ob;VX>88nQJ~_e zPSbxYiuuZO;A>h7C$8y`OG7?bXN;l}pMG>nxNmCurBl|px2(0>o-$J|!z&#xuz%tv zy}ES*YiK=8uRArEg;kjJ){1So_OmU;-HhdPC#O@s$9u3z8w9oM=3?(!CGjQ2PG;3_ z885p{1G^NyNfqR~IM<h-SwNT>u8tTiz2$31xuqXrl;G8t6_0_X4!?1!vVwH|brUMp zEoZH5z5ITA2PwVP!pIU={Aq59dj`t#@n&Q2ar|G}bw*LV`CmV-{_t`%F^HnoeOhV! zR37{lZwPE>OKP&;2o^toaXFv*OaJE7P~B<^T9~pHKY8q7B$2X($14e1Cg1`iVa6f* zh`cjG>E-fR3NqTp;<wzz0AFFJtF(cNjU4&NUDG)8{teuYqpqx5V#Y=``9sFPC>FHU z3TGWXN-_pBne^uZE^>T0b}#(RE`Et%BD3AlccC9mjIm}JCzfFTT4U-HT@2%kgZW1q z=KRI&2Kac~WlCVJOv6={zwu-%lncziNjHP3#<Z2)h`i6XJWi&WOU|$jk389^J8BTv zyb?a@Y{4_5ufxqpd$=D3)_837a{3UM3o4)Y(ENQuFW4diC;r$&;l27&%X~dNbFNh~ z=*TJB5t<8;4^z3{n(9z3+{2H?HDJ%ibL^7ffSsOsl!f=MqR)R7S>L1)cs11kqu0i= zBKNQKCi)yU2)xNnK9O*@mr-)3HhIc1fu)&Cm-gwh_1khOAu><0;(Qp(=VyTDOh+MO z@dE8fBUpa4hq(_tScX|VNxt6)`=grB{-uCD2-!;G)=Z<?LRDBEvV<S5zltRZdClej z9x&0*F7y%imu4$FNDG%tL{8|&7T*q|+J@uI=jmtuirs&(!?l*C586OF4l*>@z8D7t z>WY6om!M^q4Z0lNiIrW8$#jex?g~GO3*tj)v27M?_L4`3_8|C^9458fw1yw9t&VnG zV*I<`lwMsD^0C%BXw%n){5@~N+~^sg_I?h9jkyI&5(Pec#61`{Ig=bJ%1AX#U@pu) zFCA#43PWxPIT{TMiZA|zb6%fk-%3W)_IsiD;K~88yq|{Ev*r+u&ZO$^ONdWXWhW2G zqKfReOL=$0SX7@;XlPl&Hl5cb!*c`aaOxM>oX|(`G8S=HN|Pb3ZxOaOJx4|5(b(!P zu%5L#z$qpHY(8qx_?JQsNazVI-JSrAkA(N(&y&pf;}|ej+JGAK9m#9KPTKV%fy$-{ z9Tk-mT*f+2eD+M6=DT-F#tgg4zAQ->Nw)Lkn34x#+pp+*)B_?l-67;u57b9y!u1K) zsRFlv%H>KjagU{$858iFgB3Q;9Sd<HJ-X(57<CK&BS~f|6EDnztBtba$X{y($7Ln$ zTfPEDLlidbyG|RvUxNc}CFm5HK?4ix$T;T*#7-hs6WKvEk5%xIUoBgE_%iew=E7Rv zS#Wleg5Z~#Pld%Vp>c^8Qxv<iOH+H`^?)9z6;I*g9K__fEl=pAD8XBn&HnzY=dvVO zH2b6x$@^HKbI~IvKjAL89rc18Pu}9Mf}`wnULAjCpDtww$WiJUXP7hI1gD-_!+hdj zf&S*cs1gErO<NAre<S|6WyHJ>If$pyJ3dO_pzYTd&c#m_(Yj&sSR+SdwO&QM>R}?c zLuVNdt+NvEmHh$!a-lSTSQzPTJwxqV&2iixIU0EX7dN&tg#C&2K+(f}Z0n8yHbTvV z?wv~^Hc$iRTz|wnn|feqhrn6gU50<^Z!?!8AuMRs2i~rH28K1}a`*d0lhxCm#GMZo z+pU{|<%hHB=ioU^U3`dc?LR^#r%mairVNf1oY5V6)4_7kW0d+jiF?DAO7?BK!QvN9 z<GiCB$t|+KbX4CN%yiB;z9IR7G;G#qXt0bW)r4iVeAjIFcz!o?QqQAD5#{V@Y&xu3 zeFYn$WAI_T6FVg9j_&*Skn)c}x*R+NuM}oN<cDAI)cX^AuNp!$NE=7G2C+#Y1<WV& z6?jgcMX8(5^CQ>ZhZ<=Bt1yWI+lx7Lsj8N_2gp(uE~jbZN3fim-e~$+jvg02;G&mK z5lzgV&SuSysM0jl#WOu0+0ot$0@LRycYl34sQeet-wsy7uCu-HP~wI^Uz~+yADTe3 zY&lMII!PZ5?ttiQ6&$YhqkU>aaAVnYdVXB+jEovcsW+d{*HeCyV==4g*TWP_3NWRB z+ow2j&=e{R9zY9>8o~au4yLbJ0;|tCGWXF}SibgH{(fFD_vXtTk;k@Mto2|OhS@a2 z3K>gwcW4p2w!BEvCu<LuUuy;X^|dgfA<D5H%27U`f#3M@31r&&K>gudIx$S(nXg_f z4s>l4{~nBdjHecKxOu^>Tkg{Cv~qErvnq};JB9Cyl$oXI02wY>$qrAP%0%n`33vLf zRFIxZUpG&aE)3X4<(*!Xw0SL=uQtSKa>ZgJcL^BIPG$?I?Zt3)JDPR-E5B;&YJAkS zkQOEFMNUCRdZW2SGTlgUQ4Bjq&GBO~XMn%JLJ5YLHJ9P*7r`C-rIJoL9D>*H%D^i1 zCJU@^<y?xR_?ykYxdv4kx@vO)X-O^%=zEn#=F8Cqi+D)g?m&}P2I8#ylkjoZH0dDG zC+1u|oePX!fqLCvp}<S%60Lm0xY;%Iv|>IUoLq*Q7lY7t@N(WReiAMg$K!dO@w9Vu z1X(;DBrRDc2hCR%*qudV_>E^v;8MgB{@D|6fooF3^meOJ=ED{mmhMHC4lP`;d!=OR z!;RRiS;(BX$<xOHQK-BZ1*W->`F(i_yM|d~O_GS6)EP=ur&Zyo(gk|@@i@eNGsdc+ zO=z^^J+t3^OZs)qG49JBC8@fyCZ_6TQ`_5HFw#_&L_c%LeO5cfKJ1}4r^n(f?F5#0 z<rh;}=f{osdl@9xZ_s~Q0$(}q9L`*s1na+8k<ZIqJkBZ7Tq9jrSv3pq^rl0x>?}G} z?~bxE#|2hVWL5a$DfnSPEcWKak&c!(P4Ifpf+X!=Sa((60EFR)UOh4_R)_0a0{`D~ zD7t25N(T2$=KYFXarhAxG&&v)-qylyU0WCaq=Zq&*$nZIZ{>m);w`hS-3J~;XIX7O z9auWJ7?*Y^qjdTr*jCn!#X?TA*Ww__ByJMPWSgT`$|V@+m&1Mk6~TA*tfjHFci?5Y zmbA7@o5FpysU|{0S}<TfJiN7+iE6_M|2S}}hc_`HIgJ$~Co`6!iyn?k#eKGPOB6x` zZu+Jj9Q!Szix-a4pht$dyH@auJ3NDl<D)?$wAQU!9N3Vj^JwQu6YN^(LfO)A;3v0( z{u+VLYF|h5y<G9^oz?hqk1;XzS^SGvp6q+B0l6Ql#mR>T(wV4adgf6@kEb6+h0}R- z-82o>?Qo#EqdzjMW^;15Y)VW=SEPNr5yq4Z=8sJhTpN#{;>Csuc<6PiWWL@wRPm^0 zHc|C3)u({pGkP`Ijl4msnOmv6&mz=aIZ$e?e*&kT{>sj%sBwie1IX`vU-~s`H{KsN zm#=)EjvqGUL7r*}`>h>L7M8W}xL4p$xm<$W>6^*=n==~S&&QN1fm`*wA2?cf!UX^Q zSom9mj@H}<+rkYHYAbM_uil0o`{Qwvwi8X*U(Oa<rJ>Q}vADNK4B^co<evQkqDEIx zpi4B39tmQj^dj)x7%n|~Xe>p1I|1jcui@#dVX$G`7P>z_9}^ZHg`$PqQ0%w>Z@l^n z|H^aO_|PTLwIYkVdu=6*NmQcp0jV_Fqm}z&^ptNCST#<Q)!E16If7@XL-b))Ke4y= zARP5&6l}Ch;`%*Z2pU;&l;i5f?0seM&Zj%{Nc3HjCNMo<*mBI!p8_@AuF}un2e6mH zmuX%`KF|M%mOd_gh6fUN(3a}{)GsWEw8qJ?=3^<mUz0N$U+O2e@9|~)&mr)U?S=8< ze@ZQ0`Lc1lb%flD;E=RvB-?Of+P1$Lw5B<se!c>pFDKmlA%%AJIC1w~HQC;fJ^WiP zQ+ii^558R(j?sMw<1v#P+|x}zLDnFFuBx_T$ETanZQvprj*0a7S2|59_k>;fgD_#o zB(^}c39Ow>!AZW8Iy!`T*-{(a6@3eyeR&G2A1AP#*~@tuZ!4^AtY&uG&r;dKXsPjv zB6{=FkFGXd!1&if2llWL)p5mar;`bH{(3W9soF{6W(_t$vzy!ccK{S>wXpor&uQf- zq^BA8K;8T@K8&%V?Nf_6pW2}mUa3q0C;LNUSq>+g=SAwA44HQffjf`gxgX18QO4jU z>7LTT0L8J6mP%O=eNmMjjP#?ie<Qiatwyx>va+-|>lS-GEt)N=F=wYo8)4?SRQzOn zgaxOzL)k9^$3#uKy+`Pqu1O_pY^9-hy-`y+f*k5^L29@&7&gSh_pHq{$;}WqjogBB z!=AFyMtS(^QUu9Q7)OPc&2Wy5gX==iNbO+{i?*`B7g-wU)pn63RGy-Dk;Cu>XF=^N zMhOlUPApzh$9M15#U{5$Y<j~TE-OTrDzma!tk6Zd9=#SULLEg5F36*tTwfgF84Dj; zRcU<PA?g=@5~UyHamKm{T#5QPnmcwTWQ|V(JKw2H!P$j2U&&(u#dWNG&QX@Up^N&Q z-AGk|fhcRXki7Jk(U;o?*)b(!a(*=xCajZ{PEGWpp{-Upe}9^IeV^;%|Ed;X<+5DN zf93@nWCTa8W*zsqy<J=%C(QIhG~r?DAN<vp$axO?MDG5nY}@72U~*Csi{12T-P{)# zdQ20;bc3m^&s4U(BprSpzshQU15Vnlg8nXPu=4w7a*IzO&lAgGy5?EwT~B!sB?-OH z03|+uZ-4BB8jPMh7Z$8|2=)To;ePpR;0urxhu6}Nw0Mfz{DI&6c^sUdnGM(E9Ys5G zE1++f5k9K;#dNC+`4+EN+{ZXIHs;=WuvAEfbNjXmv*rW%!_@*!$~DMGT7+JUOGHv< z##WBD#$V1Qy!BOekeu}5_cfSPS(*}N9LQjKx4k)yj0Ae^$&t0{XJ%>_fWQ27(eL3S zhKZVN`-gbY@^gdEuTSW8V;VEOaSfHWBIrEXi6h5Uf?JS0ZhZNZ%yu}EYEF`{9jlbO zz4^sOz9@x#>F42BFHd%XZfLnETe{9RUhs#8!HLuZXly$J%o0;r-J_#Ss-l8l|30RZ zu_es)@*Obw^o;F1SU^iUbZ}X*0c)%XBJN5Ey37!Gp%p8j>-t<gam`csy`H6@KgKlm z-+Eei<t=*_b(lGQ_{tgW=*zp=B{7{^D?H^li%#^p&RQ(YDRNi_tK7MeHP{RD<PUSv zD{?q}U;iIhV|5&xs;Y6)&biF#$`<x;b3a^i(L%D(VJ*bCY^K{w%R$EZDJO3@2A9;0 zV!9va;O3b5@bU8pmb)TaJk)hO&S_gm2Sy0Y_etSw%_~iD@{{*`pS*lrGwB3$L=Ob# z-7?~-KaRkNmVfNlY%%7hX0x<p4d~I&V!A(;@%gd`nR50|n37sX6Jp)KC@l(Z2IjKq zNAe-z-EZ*zkpx?5s5Eg<8SdWooL!h}!L)?_<1WY7sM=8v9{M3neYA+naPKcZtaTIe zL%P`NX~`5dG>W(Yb&4ACj0&!}!_o0YIN5Y1OH3M$?(T1K)WT(S&S{4@^2<EY<nxIf z)5@T$&V$hAaRaE%D3vDPBQ~vV8{XTni|(u+##!e_NuAAvysKp~uiErXG;Q@3j6AA_ z8wJ;sW3asVzWr=^d-o0dx&1Tz5?sl_89^-HJ`pDS_Qlln?@Vou8CGWM!{~rEkxTMH zmeTW>y?Oo#loj3R{*pl0x-x+o_FWE@w(TIu&~U9xWL0~$9~$<~VX4aov0m9cPV4>{ z-o!pq;xw@lthKhY8$wTnuYSQbhqgi8>i4iV?E=o@5h7-sgTfL==sWWVWD2|fH_wlg zctC_GbND?;zow5|NYQynNU3MXu!&u1O=RD?TxeT;9p8TU4%Era00otLc)V^A&U79@ zrg?ykYhCa}{5A*}Gg<2Q_A56aV?555Go&|T`{D0bmtaA`a44#pikbcrzG;jEekhuv zmfIRQv{e>UhAsuGP<612Rbx{=?8hTx`mkk%PFUmJ4IbiA^dnzjwUjxF|BbvSUOD*{ ztiF^hFfJvW7VjyY^7X9vbN@69{%D5gb2iW?SHX9f6T`+`vLbOy8GOq1p}B_>>3&+E z^uf;vs$0H=@SLLbzt{x)+CIQ(_ONh3nHTKOHXS%;uFAgMErXyJPhinS12*#C2{_~S zkzR~<r<57?G^OA(YYi_1<<XAhZD5S;^DR+sa1MCMxzpqkQ=p~Gj;|EoW5-V=fk$r{ zlnna8QZ)7P`-phv$uB4OKciT=NfGzLC54^!TT2Q`96HUehp*nrn7Ja4iT!LLdxRp+ zv{8paWhVHrI+xoYWFjpPzJ;vhRLA1IEAZfJHSX2QEHrDChs=o=xvud%B)W;DM@()o zo8WrKwdvC_?VZ4%JDvbxdT~rEdA8`O%WK}XR+Uzd)}ak|g}KV}D<V0&NvJ29%tlPK z<MXC93ZB~@wm)bxzjVe1c5LEr*7Dyx?A@{o?xz{!s_$)V?{OW>(^3}lX4CLuhZ(80 z%#()H>*520Q}nf?hRvR2PSUm6@X*Uinsr=_!V<S}ZIRg&P?*A^Ko7S^KW9a?3rX8# z8mv-`kOqy)U=I(B!BodgEO@8Q{g5}pbMe!#X6+ta)s(^dIxfb(mj=-<n*`{1Hx52+ zjhD<ievb7W9E9!up=@BqO7g2$p_=K5Xm3);t406i>@`xjl>Uv-`+h4r9=QpMIpZWx zc118B|0nS0LLE1E@MsDxU5>V;>ga!`nwi^FbM>?T@r9-fM5^(_=(wr@&iea`y}z<f z;`#42H{{D((2>tW#p4G^|JXV9alk>~Q$|W&_QWy8qNyxYRh`m~?Pfc-nlZIYmzeLy zJyp9od2}0EP17u^@N(Y^U^T~>yp^{yjT?q+<i1hD^TrlU!-aFPp%_!}BfPvcoBjz5 zvXj1s6nEZ_^iCZ@8I3D!|Natue<qdrzG~w2_vt_%D^L3R)`06-5zWGHEyXCyd8oOy z1Jt^<v*`DF*l*<#sOSyj7HhfV0`&)M&-kx=Mb%t<*ptMZ1{6WZy1Ar(`XLwIe34p( zvv7E$EK9gl%0B)W$ZXfzu)y*JT5h*b#7o>J)C^e-CuASsal;F6*yydK`Q|X3yJZN3 zzWOHeTxbeOn+B5R>Jzlx*MlV5#^~gEj0%EJ;IeKFdNle7H`ZJYXTLWk&FuNuGWsUI z-u{aY{#OIrAFhI)fx6VYGnsb3^Fzv1LjA3;nQ!_&tUmk*ZvB_b7TnRI+ZHOEug_8G z+!gy^&3{HTsUnj9C-P<Gh}`O*2f_N_Y#O>F7>hNYz~wpH`0)OBSb|z2gl}9#a=K^1 z<j50NFzz$+U$KY!6&;Ya9o`Rh{c^bJ>ayZ)ZA12Bn-bl(4@E1%v)~#Vk0zB;R(CX& zyME&*Qy!=S0n|dP@3cbExc=BtIFqn`IV*bqlnrTc<_FAK1f)<&!FhwR_e>2uPq+p- z1-Y#FCxPe0AXK=VPT9jUxq=6iNN`Zo=jNSkWZ6Czei9)~aS;oy7%SbRtc0pXjm)@r z0lJ(xCslv367R{`Q&RU5EIdMze{zBBsI3VLePe`txrIdS5-`o#e(-H_3LoXBQT@?9 zlJSqOgIUE9{=~&I)N<vL=+W&yZ0NvT==-J#itsi>IyAu7kx`)UX-=K1f*9|1RO--g zJe1F!itWKm_@Uxh9GbzC@ssa-if~6)Idqv*d74i9Cwa5Dpr>rW$@9=_@skUPIK>6n zH3IV;f(s@K+*&nPc>U%jjK8{p={Os*y`7)<n|(D<du=g$HZhp}-snWSTY{vkFN~&- zhi|j)Bu&gYoX(;&cCj<1jqKKnSazn|1M`BGN`v@kT(dz8yy~`vuC4mgt)fkI``#&* zoid)ZqNbp&I0LfYjpMuT+3+j>6WntF^HF=FF@1>JOY02xK~8)bjNIWVsef>g+ju5| zvSQ-l&&FF2(rSSH*UqF4pM$J>=s!_+!zo^|w1Wn2y39V`%wZlgJJ{d9%6QgLp6l{h z1|t^i=H3eoK*f?*lD~o@bmbyTHlpAnt)8L}!)msmdruSX-)BwbH{EfKM?daY-<_Os z4+?!p59aYG1LyS9l@^QlGqF?#nza>~?mQsdT6^kU-T;x`4cLY4+bJXN1ZS$Zk<w%a zvlq1%B)6|oyyJ8!J`#2tir1&Y_@5Tw`eh9%?R(B{{h5XjN3Y>6t^D|x$D-NHd~fQE zmtnnLLe`R-D9zYagb(H<KzRQ#sPiv^YdaVU-*{zMnP-Cb3wP4R<(}j<qYQU!k^vKa zIoh~*9$cJxgl!+Ah?73W(lv{bq~k25CpHVg&QV9|4+Ci7-B~!dkr!W!G!XZ{x108# z8IIrfcyV%WmQ+}Oop)(fa&mi@z<E9VCwM#*#Sbm3U~gWIup8dV>|-0aGMQ5tf9*du zaYhcdy>FCc+NLpMuT1QnGZ+8s7|Di=%7laR`<UclG?Oh@MfEo3q?>F^b#funrKkIV zuSyb*l1~HR8-*Nw9+k=d29;HjFzUc+x@{H<%Pwq_WIR4e!$0Mb-Em<?SNMj_77H2j z%U7VMLSUoavPEkjId)-X2)kl?mop!835=3v!Zt1r`4i72<+gcz?XgL0)SSOeyQLG3 zy!*x8|9j5MoF9m)*Eg{#UWshJzYDAP1bXU{f@#Mdus$y~;STvo;mlS-*&f+!)!0DR zM{^E*&T8j=NEMmIcV*PE`wz5)nQwTA59Rx=#?$;zO49BG|3N%_-GM?k@)13H;z^;J zJd1Yfmd>g(WBaZ8;s%oq;F%$za!Y$OGd?3-F)xb$S{liYoE(P(pB3<FlfQB!d?xYj z#y7A4eCW&AT>4L^hnF96SMoBrjf{PVf{KzedT~v#Kk5Wn^6Kzv$U4w{wv1D|mk$9# z_io<XGNu^&m`(85LYfoDvitK*xZJBhneY9f`1(=|xF4Uvj(*DKYyM=h`FpcD*7=S9 zXLFSGxnhrV5AUGqrje}0e=BNVNEaB`X5@G1IP3q#42|Bj0(CDyRnHfsJA04BpmH|N z9Qhbhm#dM5!yeonU=O=ownA22hWOg0E8KV05O)8Y2C7cc!uVl((05arkP~rX8tzA! zz2LW=axf7$)XFk1rcB;3Z!u6HYX!B%L#B!!XC$x`C5K*c3BUVb<g`pGIdTYI-Vr** zVaqsgopN}8?HmODTE>>hCQ!BCNYr|5#&OHyxXzb$XtN~;ZJiU)Iea=dFuek@7r(&1 zd*rcjqa}1E?4qAW5?b-jfK&$FqjRr5gQ))=T>d8#9Lmh`S#lwsn&(Cpt=VGNgWs4E z?V{|g{iJPr5W<cq<DU`b($h}5v>^B$m`?DZZ-d$)(<WCMm@NDz>IU-%V=|dM^hXbc zY;Y(ZN@p{a#3rjY(i;B~*0%RN^VG_K^uSO`lQlw4wFqzgxW}62^g***3pk5qrkH<b zJg)t#PuQ{x?XKt3s26Y8w}ZwMZsg4G6S9~V7Y)Q8x;5~>es$0tvz8rr)x}<B4Mb<3 zKKRye0lc%*gqD6{{)zKy%B&vFdiOu(f-lTLhZ~Xj>QfwC-gN@x4m}cC(R{{*p2LR% z+b`?OcTv9OCNSNw9UYFwat=!_k864>flcb}IQg(EJ9RsY4K#K}54mdg<;yTKxo!>n z&a9zQfe)^7><6SwJHq=wA+0{LQPRA78-C9b+%xwZ*vj>QCP_otPu0Ub3VlJZqU~I) zS_FET$FtxiS`=T>1)V*XqE>D@ySPFLUumBKw=4bNr{OP%4UZI>Odr8zTz_%Sv;*SG z_2=PvrV8$C_9xTF?`hMUYvPkuhu8wC4?GjHXn!saqv++4@HaS%f^B@kRdo{Y%30F9 zkYQ4T0ge<RuTL724v{o@8@?W-=#<?(7tWUlQC>+0f4R*a%J0TPxfjCw-@<c5t(!&s zxItSw{0R)K=w9wm5t*!mJJou0Q05>sY&C`BJ?-qc&oH{P;69t_9>HC&p3m!l6f!rv zb#aHYE1i`y$NWns+#&55l(620H3T|}VkYZilIKizeZW(2-7&OMtTIjfMBx;>|J@&4 zMk&+#1$MY>NGPTnY=CuTR?;X!ak{$)fMOoIWKan<gZ9DqN+mjbvJSo}sEY>$ZIde4 zPG+G(e)#Y7`RFcWq$0n#g8cL;)ZG{bYI7M|_~QZlVcpEUOY<q^&0NS@Bachww83QW z%dkRn6>O|$QC}rTR%t$l2Dgu)&Xsw1e{ccjJvjjhrDYPk1sn1FAYp}e{}~(F?<4c+ zutvE}b~t}vIUDwR4H#N<bM41p@XeEyrOliwZNx;0X`3<aa8<`*o1Kttw35BPoyhtX z9py9{mq`m=yyaF0?qoTf6PvnxDyteRgJm1*A#`ymK5RL_DUViX*8TE%Lq&Z&x=Vqp z(MS}z1<e-zuoF;U@6L^MK0w#E5V-aKinTLR`FmGIY^ApmTBbjM@;)&V(}Wj7Z)G2o zy6%Rj4*D?S?H8Ese~B(k2dsPa3HoMfK-Vr4>FwFa;6}wv#B0N-NInWjzpP|N*L#`c z@eiCw?N8_{QAPXY50ow|4+~NT;jGWc*qR|--0zAQcIDS&rjs;Tw7LBY9QA*XRkEEd z@Bz;~TUbpe!@t2b?gUJp+rY`n$ib62y-?IVlPrsJz_wy4cK;5<wY741b01HxI+obm zzKOl8m_iB0ql6i*klS87SuEc|EP1sXyY=D?%vjUF7Q`#CB?Hq5wkP4EMZI7eVh%b% zdm!I85)JEp(Zy#N>PuqTGPMzuGUgBO80w72yJm^J_c$QtTk(50>42<9DQ(m3;2V48 z=&)TFJ#st3b{uDLuvB=@4i}zHS0rpimp%0CNk^L}w)j(4o0h(oa996XOWGd9vziJi zv^Bk<-}A@Qnafoy#BeWM&evkC&&;q-q7@q!iO^L&4)@lZbN%{x;RZ<~M)+t*ZFPTx zxN{`5BwT>bn*V!SKf<6-Ef6|h#2vm=h#B%c`_HBULOd8-{o+a0heJ~7(!kdOkKX~j zeaEuLKVPt6-wQd{zs|To$YWkiT+gq)q{NlgoMs_qo+Q6V1FwapQmB%S_+e5k9ns%F zFJ`Qv_QhJ#>2eYn9x#MfZ8i{3S@8;XeV)!7D%auV(Qia?{q5P<F9J*Mb~UqqQOv3| z&EcWZ0BQE978ooZge}^A=*y1n?8lKlFkWji?VK%i9wyXMWYl!_;>i?py4uOiTg%zX zZN?aDwiEk$*{})l2};y5*`IJ8{ti4u^EG6F7tUBouUc4~r;GG2@o268id`LF4URE4 zq=u)2d#|4lg&%0Zg2knRW4IJ{H>=b2uJLTwlf&%Yb7Xt87Glh_2)4jMzq<HzC+ioI z3hz@pS>KKM6u9PssI&Mj=dC>l)o~tP{4FowuPiZejBqcdW-545E?WIZPntMm8u;Y( zK$e*sn{r_<9#(Xa`U(EKn@yuA<DWbXZ7QSYVTt@c4O3D}Pr-gqby@nT8n74scW0gu z9L(2tp~;)u@b~*f$!G;f5<ASJ-Y-kp+MoioHELy_YCYjiVmWiWD?`bTIo4eHflYa4 z#^gSXq>mPI+@INRSk;^c{#0!Y+FX>E{&}YZyLJ(?y2!H}xna_jT`MX6xgu$<v!)(x zJMdDn$JhBr>~r{CXi1&Sa^Dch8)UFeVV-p8^90cCW6M3)y)AMPa?Y<NtYQO)_wYHZ zIW9T7kB}iZqWHNZ!Tn1W(@Ojf-%fQiKQyDug5OnR;_s@I=qOmf;Uy$>YvO5v1HScp z0Tpc9Dp|AK17ph^u(sElG=1Zt=gk>R>lq|fI53Y}ekKI{qY)gt>qNyv-Ff}H<IrNz zbX=-`nXi(3V+t0ZIkQcBn9Jnr?B0i6lyLVsK*>f{9A`s&cPC<kZ3VrxThE^NC{XUL znPOk7LeyM%4Q!9Jg6C#uF6#6InyMPdGH0$~b@xWm`A5xQ;WkXNbmnt<`qdP-6gx2c zq6{*2QN@hOA0^oXh5q3DSUzU|74UX(!VUA@fzE*!tY;Eq{a0&Zk**mInzV>prGHWA zzI3zrZ71;WUPmfSn!_$>XVdpqV5QPhl8%m|ki!k|yitnFA8aPmRb$xHNL_ZdU@@Ei za;U&uT+C_<ipA$L73kA+b^3Nz7oXWJf|X4&Qkf1jHlZn)rCGb<gtRbrV0R=YF1*Yg ziQ2|K3oJ(6*z3?}6axtbpV*k2o&wV}9&VaEXKwPd=#OCtJ(+V*ntjg|=QpfE^GCuC ze9#gWmpWW(IlYN3J+cWMPH6EN)1QLv?~~B6@j2(P^Ey=xT}UlajLpnh&c~e|jDh2M zw&7_U#sv%B<gy+%VqpO@8oUEyj<xcw@g-1R77yWvb=mOtdS<LJm1g@#!Ee`j)HwPq zuM~L*1}zy#%eHJ}0l)mXiA|c+!P#Qr$~$aIkUkD}3Z@{_ezfB3WYAMPP8I{-@Y+A0 z!PF;mK;cOO<FE*3jPPfdtuxrurQLXAjjnJ`XyK0?J_37gnc(=H!L)GM09stp9}Ujk zl_q@N#XP)>Fflm-#8YF)XVepDo+y>>56lFIh+-DD&IPu$O{D{CZg9;P7r>=yR^rrQ zhQh9^o&K%%r>rU=^Q@{UjlA}P>lm^K-?qlU+1%^g^!`Ec<?j-%r|%-NiOk?<g<m0? z{AT`$TqrX&FQJb2znJx=Sg>&$M)lgeu+&Ty4w)!Zzy1L%KT87T8%lVorWzbup3NRD z6r3y5is`?hZ}=of8GPd{MxU+Stk>-W3lY7B%h~Sesd*4rj7pN)%1&VCB1coeo1-97 zn?(J5_h3q0u4Iry1?)C26np5MWsM<nU_OfAx@RP|Md`t5fjw>=TS;-1r`exTM<J5Q zh`lS5L^TI8`9Y7{g#D2kYP~%Nv%Y<S%HB9yCS3&A_nF~7l~VeYb_p!g3j_~>gzI{} zn%i_`6z}y^jW!#1k|qw}6pIF+hV_1tMfh+m{+x~8gV$iR^?2SzwF<0L-Qi7;8-560 z4)WL1DdfjHiqbJ>v^Ihk3@}E+-zyOvyM=7+4~Q`Zrn1Y8PWUeo?;NX5)g4Xr&H54L z%<kq?Mz+A7rUYrmAr*oZ*SI-iZ5kBh4@*DfN)JS@A!W<!{IZQ{f=j+X`Usp}{cHz% zX>|?_MhN$?^hDMiqD9<zDVM0wN@oHl;02*07~JuZ{p8wU-u+>$?&L1?7x;I_Rb@$T zss}#%oJqXQGnSq_moyhE!236rkbF>9+%eG$jmPzfj?KK!%eR-a%v=lMef=Ds|5d}q zs!w>&GtWgvCl4^U7p>gdl~dVtlPK)&S&2zM9!j<bo&=wyL#)cYf@wPz;O+G{`NZjY z5*vM0v<^CeYF|Uy)1v$E_+vIVg!jdt$A_^8#wLuG3tjLfjeOl|k<e9^rNHDMDk^ve zBLxti4ra37wb8h7iVAC0x4~`~b#dv*kwWfs2VRLtWNcm`-)~+kya^u#u6I`81Fd^( zx3qx#w!DLR>iOVoW5W0kyCvh-_d)hT#5%UW0UH$~_}Y|+pH+JC;Ed&BM|pKn5%S4; zc>*Vc$<l;b#bT4wt*m#E4(GGgm)X<|;-BvQ3N6JC>GNd+VW)eO-&wPPol|&4>ytL| zH^Wb}9JPa7Z2*HmJs-uL_Gw@fK82Q;g5+xYV>nc+$*&Fc;Ey$R^N;FeXzPJhRGzbv zsIMm({#Odqx(~qj(sZun(^GhOGoSx&=~TAV@htoPQkM41myQq26L_g3GpK2r2G;*+ zXCub`2la2wIZH1W`Zy(sr51;ZV$ZhVg{%t4=79N75SI=LGDF3;^oDR&TPr{=Et&@B zMx%UK6h^5wz}Ax=sj@c<*A3gmJMYz^eTJf{eLH*jX9Gu*%-78@?#poT^{&y<erK++ zB@qu;qstIX^|E76o*aPJYcJ6L><LgcyPeHXnMl6xq)he1W(qKQ2(uo@V4}eFZ^*j` z@cjdHW`wb+H~TVoO-+9PZlPD8upUp3I*i8_o~r7-(^B<qr_c*HH-;I`8_)h!__7n( zB5`ZkUc7bf4&>}(ocZgc5K*De_piH3fh~8~(M1-JFW1Q?_S=SG7ryfUZYsf$&~oT= zK8oqR8Y3Ni)c{w#=wW>~BnamoV^(Wkgw@|R^J8Q7V0?WiZ0#CCqraL<#vfI|6HRUW zrkf`uS5(YMJ$WH});OBk%da56kNq)XhPrs$D_O~ib){8lD=l%+;&0rI9RdSWVB)c6 zN2cHR2pm$=kf=BhMDMM~DeUiCE@);tJh$8@(fVy64S({7Yy0mVv}DCqJv-%%V`NI% z$XGS%%UQs@xD#;uzYJk}af|dM1~};FHwa2AW#tx8fJ>EVuTcrx_*=+jSPaCn980l9 z=NK|S-Jd-SyG|xma<EQSU?Sh>hke~5c*%;X_;vkEy71@)r#izKlg_o^uiD{ww7Ha4 zE<J-<qb1ycUI{CgoPwp1OW5A58REtJOZbn<+t>@0aTvK?o_$a)mY|-L6i&usV^205 zGnvbue{cr6c4p%Z<1nnAB8$lr^+^1DJgK#1Fq_I_xLT<U4*$OcJ!TJU5((_?-@&AF zZ4<M&<jUd`jOoJdN?v}HE>H6X-_f%Plx%;W{SG52mCVBiYYmKP(WjW)gOKtj8RlDu zu*pql!LqTJlovc_vi^TL*CWY%RM}Em6)+W-ol1m}mXb@YN!Q>t8cF2OEy4lA3$cCq zJCgXw;;%prFpu(vn^%-k_tFLU_kJ1N2>S&sEFSZIIkQ7;26$lc72aRnNtpe_NLS=f z!msKgl$qViZeFpamv-4OR5S~(t?l9me6^u53M#aJtKcwSEBG9fLvf_nO6napM=UvA zKuM9>f^Suu@}GPnE0;x_oqsZ4@t_OyOD#})uZV9A6xc?|Y4DbN$F`sT&YleLqUf<L ztRg>#+f&^`8@&@jZITK;`)Wc_(an5x;{-hVb|;O>ozDhMXA~S}Px@^k<S|l2G=o^q zlRI!~-)s!F)Pv-Gui(d>EUu{J184j{hR!<>t2Ye8GD4DUC8K0DD64SZ=OdJclo2VV zq+v8Pv?Gb^O;%)&jMCz~&u3H;sf5y`l2p>buT=V-KfnLach37h&wXE)VIhh=U`V*& zN_@M|2m^dP`P1FM!GQ<H=+wcG_JhOxc}0Wd%KhEgeDEt=yrBZKHCDjZ-*&jcR34*W zE`-%{r?KC!9)#l`Ke2L3>UG{~GcYFa12M?YqWns2ymqOA@s|HhS{fI_Iv*3Tu#RW$ zE}ID-4u;W9(;p$zZpyk0i}3s3=8^9kuCW{J@6y2cPSAJp5MOq`KXxa0<E+(F$rtr( z%>SCm=6~10;`2=~b&3oLxe!IvAJ2#RmSsd(Bbo^v`9}nCi0Qbcf_X2cacGMUV;j-} zA1bF%#gw0<Rj-jbT2Tnr3gN8DR0aIAWd*fxmBH=8H%OLp30<T$n_e8?I#b-UHmRzS zTn*SlPmOiZ|5pFTmW>3<Z;a823DH;*_JltA(nFqk)X*gF^NbZ6MFXD6vQMSsxEw|n zJz+ePdf^#*VPObeS3gDz9rBp}q~B0q!~3*-l?*IySH=h0H%Y~%47xlsiwxiNWmjzQ zMq$1OuGToldVVCtwQV{K?YH3kV{*8Fmg8N05oXu%Wgv0Q32YiQF)*luc<Y^mpcrlb zF6Ry=`brv9HjObi8%(MCtsuInej~K2uYkE0-eCWA7pwgK89TkFntI1c;lckZ@zM8b z#N>huyC;%If2`y(H77!_Y4vUTDseWAoo#z_hrK4W_Y)G@uo7_bpW2Cs^Xa^03AAU% zHMZg<m!Aur4ZlPrNNd$aJg{sJ1b7NCLl0xPto~w1caCOa0!K-AfIYLO=rEJhYXaRt z=NbI3oK2mdL>0faGM4lP><^A2pFB^~c8*u{9t&V$-bSjoX$Jk5R)YyHlh8|j6MejN z7rs9w407UUA>g4nf3oipvNolh>YnzXqt}bsWuG3iO)UvL7mpz-wRbs{UXe!UM6Dwo zUw`60pGi2UD!Dd6?kq^}k)oUbu-q=|N3G1gpX|ovW+*)`jYPyw1C_p&D4k=#9+p&r zUn=?3FZv9!Qv>kNzAXNW*XO`*V+#2`Nu6pv8DlSLeMIGCIjSL&1)eWC2%*9_DX-p5 zl7*kb7F|B_+b$usoI|JS)G&*G^%1|tfD^YAz_Gg(Xn58NH_8d)Z`{mGoi&%6KTV?h z9rYNmCuQVw*c9x4G#RCQN13P|D}2WFOQ(;tkpguYbe~jA*N-+b7Hf-X<M2~5QD1~( zNJ!9)`Ciz~tD%Jf`Q(mwD%NUJwphM}c<dc8`z5=B1vNo-dyg5p8$6vwi|bH?6L8#4 z9RKqYCsrnzaOmM{>hYgG*>$!a?CMJSg1?l|u)`9L?hqt(E{~|_ZEq4XSiw&<mLbFA z@^~gd5QTmj;N<q)+9#*1nPm;@c?C;vF^gilu-ib2<`!(IO=u9}yS_7^=`Y;im%~5i zz`!#0%=av!c}{}nYMsXnyWI@!mBj7jpLwwLEc)r>GkmvM5!>F_fTf-Y-dMI0!Y0d+ zM9q1)COv`j){PQ3y=QDlwLH1CM2Y)74N~^x;lp>5&>6#nuF-W6F#M3(?H;F#p7@iu ziDj@q*&0$Op5~hfucT{S74h-X-!*-A=Ajv^gCjPD^j-8gQI)9Yc{$3WU}*<4YgHyO zv3m(}iK6hOX%>0s9E(5AC$cZ&wz3^MHoO+wo#6LuCJ0?kgqc%*l39!nd9rYTcwY3w zBTqRtzf2&AS(Ktq&o<~7e@W)Lr<h8ek|T%2X0tC`o$#2DEZ<Rjm^S&(hV1)3=4Sh} z;Gl~S)Zqkp3ua_TTLB3$nuseUjDdImuUTSqGS(lvhyEk+MA)SsZ~82RHIu6#(bf=e zym(2J3M;U2(G1R|R|{qXowV+YCVxZ)vC3mJx$ylTS^l~Vr(1ub`Be;A&T(P>G+NWT zyGQtwGZavBX-)0Tw+C3u<Xj^8(*jNd!PVR@;6dg!)K+U|FPt8xuUx9B=h;5IJ92}J zrAz|{{fP*#?=X4w^Qq#zaM;$b3?Gy~u+pXs7+;9Ps_LCoK+YNO2ISHYYCdF2ayF<e zc7v0jtTEz%0`oU^15K{p2OT|^$ds>#VdGwDYI-`Dh^S~XO4Iwz%QZ%*aY!6&yYrTG z?{_xWUQtY@!F0^~9!&Y2UT`&Nvbm#gA1f5638QvJ;1}?ft_*Y|X6+Z4Jyk2g`A-xz zDAuaI%Q0Sz72cSi<rr*jN0*}HM|HIFG9`0@VrW>y66)^p9EN+0h(h2HQM44}HSI>+ zyfhM8-Zs&8V<eRaErEBry(TeYJ{Wi9(pjG~uym;n?HP5a)$b>>iM@f;)bua2Rjz@a zGT%qqD>nhN{45-s{us1QnDS=Y$})vhbwH`MlgmiorRu_oyt9ghwBTqoJHC1em7V{V zS=#7HO5b&2oY#FuQ1BKFl%K*1KRbz0-|T7V_A(aFo5N3sH_Xw|HeQ^MAlwdGg-wkI zX=PLo^K`Z}x*Kxm8vp6kw4;pnxXwrEz5ZD6{3L#@odutzdx)@ODv6A^Lc}({BTT+L zvuzA$ImaC8ZFVPVwl~=2)g{>X#2Wm9i|MOOW!moXjCoZymGguzp?9;>NpAK(C>JZH zGM#~R@B&l28nk(@hTby=eq3Z$E`LWYMy|t_!>7T(T9th)^BRwtYv923du-a*<yerl znZ2*$OAlEMQq_NA^l`QpZ(o5cU-Z%#MR@_-vXUjUql1a_wp}#R{1FN*X&`3|g6Mz8 z)lux69@Tzv3MCu5$m`J8<lJOsBHY+dbi6MUCBtQe<oZ&>i^i<`!C;JfY0dSVw?Q43 zeQ(UuCS;BS==U(Rdb%c^+>=F>*{!@|A8tb2$TIeGks{XL@FjPAD;QnwJ(XdY%i6t& zBL4q|sjQ7Q3^@JA&h?QcrpEf<ZaE391Z?=nPZhv`+-Z8_eG0z2<v{KH2Vv7U1_e1T z+n@PTuv0;delCqBce^N=96S{}+h?;uH?{C=+%%M@Ni<zr0XKcK1P?n^p4^<r?B@H5 zI9)J~T-X<Ep142>!}W6T+BOHOZJA2uM<h~*tT<AUeggY%@1xqYZkTQj_GK&my0Kk! z4fzuy0K1M#!1vk|xH3To|3)Qa((Ji3vonY`noNRBg#?_Ys|V?yvdPXV*(B(AEj=^q z3LSMDppvsn+2I-uM!9-5Z=!WP4c)YroG6RH>E&C<zsVkO>iZRv;a$b7;<BS{T?a8t zcmmzr-$$PRljkiuF94cFk?6EH8a#HqV46pZsMxCO<k!cYH2!5Z9C!00cjAL6ZFPeC zcS_j0PkyY`%(HlP-4593kw^}G6+-93??}YiOmNE80;}Q6jNViUG)R4ndQ&^8=(qQf z@F1J@&piqa`T6XjJU0@NWP&x4`t-t{r(|~Cd3uF-lJb-^n&zs5O~G%eL1`te4;!t0 zc>O&Q`MCfp{j5+_z>M<<KVtPim2jS;LZU93gUhZ5;Mc%WMm%C7BU<^MF6Z90?ABPK z+$2hexO2~Izf5}Y<8)XcR7&2>>cCB<nvm&xoBTcAK%}}hf^768B6n5|wcWH~(t_o% z#Cw?advP3Q841v;i?d0tu^0d8@n~??v4X(C3An=K1QzTqCKhi9c!)`orBklc4U$vw zyvq{0&yVvzHN61CjOXmgRS%xFNDkJFDDiV1Na1+-J{<g4N0S%sV60b8<i)BxL8$&= zN;iHYKLmdf<u_tXxVZ@aJSoAkV{%!&qbl?xHzQlr{+k?}-^^UL9-vMy8E9i9;4;T+ zsMl2|k(*U<?}TG$`e!e~xFN<5IFfQr8F*jgMT7zfseh&fagHs-*mWiBds>0B&BvHU z-4}4>%zbFCwwcdl+yilsG&G#D$Nb7g@w#=woFZ>a2-fZIhv%o|KqMp@ywVroIiY&` zC_4(CSt}69XCd%&V>#P<V_Myg1#jt5kp<+^Tru1`$T48TZjhU8v2fU85iArB;xH|N zbjyiWGqcTIG>u8X-DkszY{^1CUr*-7_X<IB(yN!I?EFYPLpJjVY#mVXO(2GbT{bsx zFGihLFSuPQ$0`-S4|jYN;gEl(xxbPUJYMTWtS@$Rz>X2p=<tQiZTv*tXI?kgE#Z1m zwJN-a??%~vu92SM(?+x_&qK(H$L7uVo9V^Bc{Iu74!!ki3dpG05bCLh<evr@C=}B( zbBuw;>d+f8!?n{y|KRlGpLEG3TUtI?j3WUrY3g2ON)G&_u3Dei=iIGBeA;fJF4M!j zbZRFTtqbUY?<(S`^q8KIc0%L4M@*&9YufTHw$>|zM;4x%fOB(iGhsVi=q76oA~##F zcK5J1{>(SP=>ZSv<*JL!?s<9S;z&N3z19HZc7@{Q2@%9JgqssSUk$As{~_gJ961+% z7p7S{@V8gYqHkvVfn(Q1C=*h^=+z0dvv($J*~Gb7kH#`le`XOmejpQJ(oUz8x#G9# z6kKa%X<qz=`&R6YB~m?`p(cL@=C2jP9OJ2s^qdO3c`231+69wye{PTs!`^I9-FoJr z@N23oDMvNe&p^Mw`(a()W>O-XivdB~A*?Qp_WV@kSDecLy^!go^L#NWEB;vX&~pXt z>e@}hTYiu(m_%b1?l!-E)R2sL3i7&Vq><NBGWg(h3SPCn1$i@D*o1RjH}PRAX1(p8 zSu&GJO{NC=U6X?NHB))_Jhl0Ag64wm&rCM%{sj7Zct8FAM}bu={K6|t6Gh>{r{)8- z=PB^65E<q>mc6t^`6&u46}kf+nZiufnR3vX?`i&Gx(L;1xrm2W<+9iA=aZ+$w&14l zKqmZ!KScK?(34B+us_EJPhR5l7rTXl_SrP{*Um{WcyBGua@XW9GxBE6-AaYL`61B$ zAQ-m(*T&vVnaL~EtHgeRKCG#XWUuYp!6*qS5m&Brvnwkc&R%(ij?Oyx*W^20(zJ%@ zx?@aDxOc==7ZGgZJS)0i2dL%C1=OcS9z5y@-uN*@=ZlSzRNXq-Vphjq%CjKPf__rz zSDK6lZKS`}{zp$}$e_(T9@WoTOfx3Erc<<Jh+j-O=~hpnWuu?zE4OkQy03#+Ifk-V zgjGnxntAlbcoEGbYQ%8Q8@L}NO4PQyk_X?r!RO%u{`eA8bfmjsa(Qd5hqej%Z)g_l zEK$W*)q7#S!Du>GsLJ5u$)Y%TmPdAV2ol}BUc8V~)wO?;c3>69H(t`tGHP>X^1JO{ zvO87!Scm0{!N2E=xwdZwA*J3_&7JEjY?({6%LGZ-)nc>53v-#nTkEmKdx-7r+5nz< zn%MhM4IbVOW~F35($Y;W^u-i_r~D^WJwKH+UyWuD^8>+%<J)^~Tn}Au^58)?*Zcb} zh%cTi;<uhNWZ*+5w6=aA3w~zvM~~&O{Q>7NBEypkaXnC@$%Y`Wwt@DGFs$*CR^AGZ zG51Kc%e-mV6>=F0pxf1%WBq+%1Dk)*11_!1y#-=4L&uV*t8EQic8bHt(6_`?V**pZ zhPww^)-lraLeXx?a@ZW10)3j<n9*1PBfn1pf4&K$mGp(t^7_Lb_!f@q-_NCUXEJzq zM-YT)OVSu8X%H^3CAW0i$p+V9(y7V0{J50dj}je-$~B~idnaO1%R4-G-2px=AHxEU zAM3QU32X}^vB1Wk_0Da@=<dnnTi_9}YYwLt9OGj9^($yObcb|*eM@|2Xz>kwF4CKu zSCNMXi&1&bdAfbdBK}b!t{+|gni}8OOO{9`ldfN`Fuq2b+S_Qrm19B3p3o%|&T61i zs4|Wp=|`&pm)h%}E|I=@+L$Cb(R|P1BzE|j4h%?Sk=XaDIQU=ztSt(_g?jU;fAl<b zT=SRKZL4R0zX*gw2D2fTV>`)5c$2V?KKOC13v|b}ldl6y;P<hq^udrUggISg!`{xJ z({K3UZtrTS+~G?rmgTYf)&Iyz-U{q)6C%3;bRpF^m|U`RGf#0=h4@b__y=%zSWj*q z|F(-rsSlG1e=|DgXenJh+CyAwS72b~Sxiv*NB@bd(2~NPM5kRFkK}jL+mrvo$X7p7 zGRqt?7d{2I3>$3O5eh9APUFld?*7SWk_5vD`u5mslD)O9b}fWqg4|<jmK}&nyTjNN zabLQrRffHFZXKT7^q&2%I1l1pO@`)sQ7|I+7gDq{h|z~f<mx+$>#dgHp%iuAl&Q_M z_mv)*Vt0%Qc$>l=54}LN%%||jZ`cw$Edgw)m%^>4zs#9KpIOa$rBwLN9xxxBNLsyO zc@{OQpfPBO;rdT#)kvn9_QdTN(YlPOS<Gc4pGjc#RsobNPR5klW2lws1T!YC1Ob<S zWQ+0`k+;c(xpxn;ZBz6J)2@rkf+CQ(hI>a0o<|ESO;}O$n^k<Z8CTe8Gkty+m^Mpq z8s}<5vLd-JrEMZTu*MjTj`Y%<Uyt#Ga#fk5mBQ3M*@YTSdj_XJY=Iqpvh+%CAYOYw zvDvnknd@SXZhKadd)~$<yL292d)LRg=EQi)bHeypL>g7Otmjw$BeMKW64`xH2v-Or zdf&ats#z6L+3;zo@m!cG-jj|tzPThv>M)thWi3~6j=)MRCK)HC7(eMU+BlfOu6Bz; zCs$3F$G#)R7r1#qZIHQ}7}q^+En?l;4iFcW1p2z=H1E9p2iWr?595R#(f?L2BXWBV zAqGA4$;X%G+LteqeLcVFiPSgj4DB3hooYc<3Z9aTeShiXuFd?@^8di(s0!?QWsdWm zi|IX510jVUFuCO`QG75RCN{ic?#dh?r}~{peRVQD5WIn$`6!8Mdz{d8yA0l`Jwqp5 zHh`HQAHnFYOEhq;Jo*IQqVaA=NbH3#^icjaT;StI{Z=}Y(3zL%+;4&8_2_IA5e`RT zseC&3lQ?$_`H3Ufg@{9x0h6~t8Dw+3V59*sTJaF3&S|EHeZSN6Eyi&5vOV%T?4f5? zJ~b47LlR`QsbA_8VkkdGhbva#JfBT;W}YE0_1ku)qW1*zo$KDZRZS!RnifK-!1>xu z|J^1&BC8=o%?<@uz2#WTl+JMW<rQ{5AYZ5DW3T6au%F`3EM9PjYIbYFxZf1=;z}SK z9DGcEtBz4erxI>oR!LsQAECB9f=*uvge<&7jN{+1PL=UwaxTD%hvj5!c7^#+3DO_@ zX?!blU3zlmYj`ixP3@+!FsE)g@&9cAtA9(P#gW-$;XYBY*eOCgn!0L-8pIKj9#Th( zpKRHS>2#xSH5>Hu2T8kn9)?zl)o$DE1a<pUsBl3w)%!4w?%%kQ-l(lYVQyAoWLa9{ zl)RNLTdfC)H8aS;7Hw8ve}t&HucIBek{RaHPWo(2gn#+uC^=mAj;!QdA`AXW@CJ4~ zsAX&};<Z*cc;+s~?61vWTOv75?tX7Fwx*X6zU0qWNna1=eQiKDHJ)y1bjN9h3eX}l z3yN-TB#norQhwu0%5yJgBOAZedPp?Eg;uWL6tan@KFG%+_7Zwp-==?9Z8X%)q~Clf z8H)J}&qmLJ>&RNXcTobI4uyid<1lflki&P5e7gUs37j#`pznUV!YQk9(z5V9-FCN> zt+q*q>076ho$2$)?9W!@`-ll$XjFl#54mGgj~<r#9w%$|jFTvh!?n}aWtbnx@`gPN z#UX869u`wq3|L#u%$}Ex$CS2Uk35f`zS5s_N++YWiYI+nFs;r<#D{uiW@FmtbolVb zgmZJnLV$w^t{1&+mYyud+pNBiG?i?H!UJ*C$b4!YeiT8;b7JP_dRF3yQ7}rCaPEwq z9niCLAsn4q0If=kXy@0vm}+;Pnt9D+pNL&2r^Yt%m!H^87Oht#1)sRiuCXLLOVNj) z>$MrR24<maoiLs0n#gf5v{1z&n<k7EfjP&X{!?a5-+Xf;HRAWle<{(JK0An9%~c1b zv;}yeU=L`WH>6&QYP?HXx-`5tlxn&N!-e2sm_2-*G|v&n#GWF$D>aB75p;#D&2q48 zbOU~o<d|!f?@8o|h2T*bMc<~>5Sf~ByyJ16cI=pdtuK?&p--0vx2035KS`{WGfUrt zEAHzppqu3m5dUB2!6t;`N32$Z@#jcS1uRGRAq`W}_&>EBGh@kdt}8Lp5l?$>S<#+z zm)TZ(t(rsTx7fF8x~TN*G?m^Zg-(;xiSQgt_U%Gd;_M%U&kx&Ui_{=<X=5n)Sz-&i ziMnVO)j;mhk5H1R#8;}ge>2=c9}MQNfIHD%c>mW!s&iD5G!+PO=Pgt0uG&sdME@q5 zVceYkvo2~DdZYH*B4#{uoD{$BA?}yCIr-mu+On&H79HWdVd6&oTXmn9y-%0HNgogD zb|8^mz4J2pyUc{^VJeZS?`%=D@hGf){*{<)OT?{l+rcDH6t6B_$DdY}2b=X{nfso3 z<c#PWrhYJv&5<}jB-c&=y(wmFaF-i6RtB)HXC-*o|7Mdj63+OvH5D(mI>7u-ZL~~F z0HUVIU@zasTw7&2{ju8xe_me(i!|(b#*%k%Mdd`;Ff@ZLO8jH~GSY#bv=*e}@<JAZ zNpI-PqakGSkqPX=wI!tW@^ox%cfxCr9jWXtQQipS%oNA8f?3ERICQ6<%@%LR+{@ie zdSy0izR(o=HYYHSqB|i@N(X6LHoh#WVz*R2<QL@xz{Ap9X64rnP#-x)7Yr}ryVsb* zvsahlty3s8m3x3;avsffj)5CrCi2rVg!zYdt~Nt=Te7)hm|R%cg!~Uha8fNC!+Q4P z&25!*ZtqfNJWC%cHfZAVaeH*UFAo<Lb!q3>tIRi#w?r@JGnS`Jp<Z(rgJGyM&8XhW zyvdF*6J9HgD~DIqmPY(%o=`u5>NVV@kq=6!r^r2OvZ;`{bATm{Z>GTVs|353aA$)O z1Kd;<P0ru`%Z^#5;i&Q{2=I?2S_&axu5lCYUl4@abMf%FnuUQ$T#hjC7{(;8g6Lb7 z%nto-^3zV8PMRsszvDAPX1=*erDBx9MQ1DP?$^Zl1a#2cW%j(obC1CO)H9?zb_MU- zJz4faaRYWjK5^?y$F2H0SZ5(dm&v!lGF<^&ppis}Epy<zbsm&2QKPpFS3r|hB#N#u zgZ|Iq__XB~7Rl6;g8l90%15P9`nwXUELZ~48)L}QB5PtCdYbHOI}M}p-^gXNesZnx z0n|+25BhgC=_!#u#-Qmxvg7J5_-i3fqqn&8A1nkY|IY$#ws$e!(OWS}sEOn$P5=j? zB77Me!}B}$l4-0<rA{&HP%x>HXvLr7FFIvI>)$6q@%RGVwx7}u7EhsimMKKqU#GEe zM~M2h1S(OjOzR+rv>E5)(<9-;DCjCUHgCXku2Vsb@4<)BD*O{x&3-J{N75G=p`gZP zoVNNN{daaD-06NtgdTHlj+O;@mbp!yTr8va1RCLaLp(M$=<}bZO(6PD1DIjAX8dQ+ zOcUbG`Cf~k)INPGz<a*=9rpauz_O$m?EAS4^8b9o<2KDS(@KwTH9i}^OJ9Vb$Z_H! zt<IM(KS5^ntzgzqyNj2)e5mxzB;Lz)rf6$>ocg`w(~6#0*l5RfD|9A8&^sRP8ZM!y z&6>@|KGd>neC8k<eG0?+C8)jADMGdP(Dkif=_#8x^u&!lv~%SfdLYXY`<IGRO=CAI z`8kQ1x>OopIjkb~zZ&RX%Nh&_9VeH{_L{fkyoQ~=Y505~f?dYVP@kS`Wq<zo$Jl(C z40)&D(T4o<w0zHFY`#_wMf(3}fMhT%{LxAZPAs6jX&1q$YA5`#RE5Jvk4S+)7xQ>x z25iwzV2Ms14n4dGaxXR5KZCodCrP3^*0q_r1jJ%<m^b~KD#(aR1;WX{I^g>2HI+^+ ztZljB!!y!rB%j12p>ks<tn;#fc4i%j*jZ7s;V(%%Y)<Lp?I=}mhDV!)K}jl`G(Bvk zX6m`LrpAYqX2!y9E5J|N-SLrL5N&n0gR#MHXt+re4h%AUK`mA2R5PVx^{x1))QwMS zE1>yQDh4eLqdPUO5MMTt+&&-+Qh^-9I?W09YN{eM^`qpUr%)8X8-!wZ;}eccx%jRM z^a&a8ZpeM2Z(@be?O-%nA+!glD<q-oyrtmOb(RGEvcs|9EA)1zH9B|SBGb7&iP)SL z2;DPijxU$cWq-wal6w~sEw|I;<`+B4o45wVV&@@WaS!SR@X6~t5oG8Ri)r8FKq5Yi zL?}nIi%ad<-LfMvE$<fVO@naTnu(aYe-rQ2zZ+!fD}C1Bf(q~Uk91ga(4Nj|Y+%A- zB608X1^k%W1lW<X2Q4{Y)xOw9M$|7E4{-mx$Ktzrg?Homub*tgWl;mPZYscKUMkfw zJx4n_uTtgIG8{YJ!8Qm@!ebhKP}ja5Z{6sjTg8vk?F_*@Q*Ef?oETP9l$q>J97j`l zGyT3{C2qn8%y5nX{)l`|?$$@*^@K?f9FYKrIEO~ipE!DET@J^@AiVdB3its#YOqJ} zD))^KgiT33Tu){Kwj7v)oi=sk>-*RA^NV=SpXY!cYdHqxe;=qz#T&$==iq0&5v;e? zK!Dd7v{x!6_v57b3JxP=L}&r4(>EP<|DH(0W+gz2Y&P39%?{3fSq&aO{*a;m9~Drz zL%udN({meIp`*eRjWo)M*86K%J!=xq)3hQ_LK2Zq-o_~Wnos{o^pVu3)#Q_jERpw8 z<`491qRelO&GgiT-*99GY`1A4&STHXiJ~3E;f*8npYR#n!K!1yG=dYk49cdrvY_=U zmSca`(UD8hQ2gW>v;W0vIA6jiQg5E)#l8}=vg%7X)rkA9ep-b&ty18+QJ*BZO{J=l z#i*rv8qyM7Ak=pkZrC`)=G@3ZDYYiFoxx|^Y%bCF+fKs7r*$+(hDE!tJ<Rr4Q;3~+ z0bM^Ck}TnisNwaO&YM=v7$`K-<gzh570H5bvo5TBYzfgxIb>4XQ_`AM3B1%anp+}9 z>)$NqZz_;LZ{uqKn^t1AY7&fWC-_WA6suqB!|R|i!aU~kI76SP^RK7u(+Npz@uO_& zJjSr&8Z5bxZOpmq<ssmA101VTB4wHj$@-b$7<K#w$w>;q=`ZYgd&ENV>Na(JRuoOP z&TOL>9n4t$*hXrVc8PZW@gb*c_cArHt<+%NH5wTD48KH`v2Bu{A=r9=Jc>8Mx<zHQ zTA&^eECG_`_=s(7J3*Q<Mj&ujD$Drykyh<Ae){?aFdktKYxjR=e;aWe{TH*rYriw~ zP<J8!;+L9_sE?7|-CoqTsE;-(6vLB-w>ZlG0+(NLeal)A-b9^bjGHRJ_tCS5*kyyP zg|t0S9U@@;!ei8K{0oWn?uQHG8YDw(E&P?3gnak&a7K-rg^ybBcH5jLTeQt-u(&Lk zv@5_b{cEWA(F=?VB`7^^47;*4v559CF-P~2Vj*=*3VBZs#14^b4xA6DbwBt#{|MHZ zisZryanSlvP9maa;N019^n;^0f7iEf*xx^h2CtgPgqON?4w~C(u3#O;M6AN7?XN*e z*%6XEM`*fc5OaKW5I-XSli3N)W^%2T!J(Zjzh9Z#<+(5zbon%{FmI+tjy{}I{w$o& z(Su@+A6Vo#4Pf#wob9Vqvs|p2FmdsqL>}Tv|0I&(CWog?#lU;gLn`pn4f_tep<#gv zG{4%9hAE!7?3Xnz{N@P<`=yBS{MXPc{mQJNVJ_tR?uG;ERoM8rn=!e)7!+qp^PlM^ zgO9r@I{bb?gm0^1Pk|XKx*UX|6NOZ^yo%JGY$pO=Gw1>{Bi!Kc3*qM$fT4T`-q{+- z-5*w<k)<vSt`5a(f67U9tSZ03u#Z%WietR;c9I}62ZZ``psrU8{08=+u*nen-{oJd zUd}w+DA@#0x>9k*4Iy&)VI+}I@Mp4TZN>Oi1t9<73rW4)#GX*+oIDw2=>NL_ZG#Tf zwq9zYz1;4}^P~zH%8kaFQ(MRtUOk5pWH3EN0`*3C813PS0q-Zlj+PX20gD4TuHZq{ z^8|Tcl2*fEbpx<j*iJI$%!kmp9Q-LZKu=T#lWL`#%#)mcHdTEwx_Zb#@YK6>U8YiP zn20zP>^e<q{VVB@^5>+j&69sE;stRoInAj2*TdL_NAUC0eaU|LX}q4YM6@(kAw?at zVU6}6F`O+z*8L4bewr_C%sW&oaNdcUz80mE*5+eC@JfDz+GdF59FirOZ-{Y;6kDv! zklo8y6E2!W+)w!9^&4+s%d%ZK?|cpfzL6vL1FATryM?NTT&5B!S1^C1pZwV04jDuo zf|l>YJ9m%btCw9&z^Q{gm4xZkUL~2!wjLu{YA2b}N&o1wR)+d@zvnIUxIvkP&&ZIU zE!ezpg-yF3!}CrNY&!Ij?)Q4a92*h`-BrKAw)P5~ezcaIv^xXyYk!l%><w6C-Nj;e zHd9x849;C0rV35m-DUGAO!ATCPwu89OlJj@rZm;6m@Y@T+I={0ng>)$h=73!4^}z_ zk;>8}j$;)FA%|7?%1_F$+1VJz5~e|0L<YQ27sn%Ah2XWq3BO0VV#4!!dLk!`zLjYP zt^V~)$C+~&8rn%5+=I#W>^UTSqYTz}=<ric{v+R4u7k|QcNoj$6>x@~j;kKYA={`& z?&)sCCpX(U-(DCRoJoQMpEw8b$x;XoyhC`;AEH3}0PX6XK)#<A<E!<ZreoT3=)OQ# zbhJAI3mVsxOq>ZbHOgUGMmp&gSpXw4|CssC&j?TA7@iamghTU_iSyYAC=NDY1^#|x zFO@zZ(N8O=LE$#IeyWs4M3$2oF~M}-UlZPz0SW?tZq%L<{SHw<3ux)FXw<Q4CGvHi zxN6~lC^hz(_H(THMRVUXE_4qy?79FOxqjZPS@JZ0#z7L1sm(9QvxVK8#Q74T4*15| zjbqsP!D^QT8uwx{4s`0k=57<Pf38U9x>U2HPwhF5{&7%$IFoL_oWjlcs=+N>nx>LD z5Z-)=kvi#1z5OO(R$CR{RJsVHg5uD!ZUG!wm5kZjJjhhVEOJQi2RcPx<n_f$k`EG1 z^xKap)Z=s9Mwx4Tfh#Gj9hX<#xg(p-6<>tc6C0t@W(QnYT|;Y+&jr^H0$?+El^*p? zX4g6|#1(33RMNc!rsxf_uTqAH@TdrH=I9#?o76!go=QSfuR8L(J>Z?$G;GvwCZAt$ zTThP%#5QILdHXns?CQ0l%Xf9a{xg&KyYub&BG(k@I_azIxu|2fs_hy%r$38-T~3A0 zUR44cw6>y;aUjMgnew+ehk{N0N`C2a9~_&vfd4C(PaB(Nfw$=%s6TQHR=>SUzW&u^ zFJ2Boq0n%4Ny<&0Ud{`ep`S-Pqod7!O*I6cMcFs+HA=%3;ZOAK(_MJcJB{4h69AT% zEpbh-BhE?}#2dTB(0^At^LKF-$0YW|PphSgzWq-+RAq?4i?uOM=O3HE3#ZQ|jc7<g z0TZ+H16`i0!TC%7k*)TQ;66u?XMFEAlYGw>ML6!+=J_G?snKpyV|9nLO*~CPC#)bD zo+T&|8V3X6nKZ*0fdp-0ukGJPhRd5Em34;)rqN`&UM)#@^p-upKOg#sUQvfm&ZokC z#|*?B$k;=FI;cLM?wBV}M^odNtMOBCLC#uYoBj}V7Zwu5jogmmi4t{aPvg~e8Nf)A zBYQOBCd8U5vqv(5NlZ=}`L}w^{IZ}k2zWZ<LyZtj$dw`23si}Bo-~yZOJVlvte|eI z)p^pF7vSu@#wgNLNVTHR!S9H8{Fy33gX7})dz*MLweB8mndOCE{5yQb>zsqw<|F62 z9HNI-T_Hug1mXSjO>kZ+2g`;laPdx2tQ<X!lY1Iqz0X}Zkj=x5LtFWeUUDAYi$)-J z)(0yGQ!&9X3+{{PVUU*umW!A`tw#xIXq<v;hHX)?Vl_tmeNO0-2vYX05u#pRqmI+2 zlko7z99v!<*58t(cQsy8cb6a#tBs(qxBo|Z+M-~(l0c`#OPp@Wb!JkUn0+#1G<Qsh zC~STPGfrmHBl_p4z>g~=bcHtW#A^B4s|ix1*F~Qvlw<&_MxyYpWG*8oSAi!K)%em| zSniqOy2jmC>EsulOnT8g^a|qgK*3WXtD}&gx|L&^PT#|>>`#Hu^>^u~kAIjNrNEjY z#ZufD!F9VX{H1dg*TYh836ytgt<|&4ruJ(UQ2f&*IK(yMZk!q=LV*{#=jlJP<>)E= zCECH94lAMj;v)8EeH)H6i{gpobm(I>q3O{XnydPfS!K7BXE;#Kw?D8OA4N?iRelm6 zpZf#n`DIh-Gr{=%Ee~ey;M3HV5oo%452`u~W8;QeDk;1f#G_rHLWTifVRfGT<7}MU z-oe26HsoDBPkvWFhLRvL<c9^LziA?rAGE`ROD}+u-~#A7Q3fIzJ&exOD(33fdAKAX z84}*;;=lHCay=*(->L{9J9jII>zj|tkxQ5}1zZl*?F4uo7Ncsw1Gh6Qh8o&qh?NC< z>(M#>vxF*=@bD_#lo-wYDhgxDK$E^vO+$k@i*VDFGODm)QO$VMBdB_;3Gc!s@KItC zR7)yC$I}4de_967ef@N{x-6tx{~{$PWJt5cIh^Bol|;6Q6V=P#YKIHA<J^DMP=B(A z===Pj13yb@yp$sF-8EtUB!QpARB9q-{@w&rT%E8+qZqet?O={Q&xR|jbeS0%>)6j* z5;6P;$3%P+W&XGP7<Lg!er3xfo>g@yd<)SbulHXhx(B~er=wS3kBkS}`F4?+ic|R( z0}HWWc@xPzVvA~qXJG4v_bC3k1INeINEs8)Y~NEw9v42OuRl+M|L&_{Y=s$h;d+8= z8^4gGld5>cOoS;e)d9nf+ib%@>6*W<a`D`?Flu-#2K%L*d4VQ3@$j_`__$5QT=sE# z?O}~f#=G!5anq@$n=V<B`(+o&{rdCf+rL*)vp#p!(|JknJzNL5Mjm9~=wmd6K+2mH zNAo&v)5sTP<kxa}7}qWZtzW^kpnWp*S=jN*+MkneF|)zHcPIUJuAgT8VIc5h3*DPO zi}|>76_MGp3BG(Zqwhpl!Gtwca4hBko(MVuA~&)yulpKrLNezrQ3&A&n%aWXuXj}b z>;m2n31zlZ@jE^IL6mfS`U-xT#^kpBITH6w6qhWS0*en+<A+DGyeAf!wDi#v&H=X- zn84>m!8aQnyx$Ufq>$ZPwj72#<<V5=C==Q52!ZLzwViI6Tu!W!%)XZZL%&Z$?pPSa zrB$O<u@dv-yee!<kEd5N)0vS33I1&+2_r3guq$XL$VI5t4O)rggp_0qzfnY$AJjwn z+5vK*|17RM_Lg>q*z=!1&?T?4ddcX64cNT!8o%N8Fb#eZgGH*#aoMtH^Yd?Q(3K|B z#rvni&s1q%u%i|v>$c*?gjQlYa}~ROu`P@oiXcAqPl;Y#1=YH}2jWudXyRo{B2#LM zM`nnVLlH;Oy~rOE{^_Hci5w^m8`7EcQXueNBt22Q8zv5#fMAX)->ou`+)OuyEyZg5 z)cyA0v;=VM5(8V}pU^W?)iA8&7z7sCLi?~NC>(f5#$$x&aLok#JDLZ_ZgH-m(PkWz zxDGy3Ic~oA9yn(mj@A~T=7wve`6=g8nT^?kSkB!G_W7-V-jpDiik0MZVm{73d6rZ} zd?DV=>oELv3?!r(;fVNFDyB3{CaeD=`2`LbHf8}=+J2D;){p+umS*PuIE_kS<>>pQ znGw8H%+_AZCmS?x(!vL8QSF-?y}W-njVrVucMrX$0kh{}jIarQZwUaAV|g@EH59EP z?y#T5Dj;c-8!v-9XZ+dcM}$*FKw!@joWHz^*7we5)Au<*Y%YN(oX_~ObqdK{JR7Sc zgQ>pSAl=im4A8os_H*au>^qVC<`5~ko-{}T!$t6oN*Mpj%w@3a_ypbogHXIEa+A2# zSi$g`!>}*t8wpEIK;M)jICLkJt=hnKx@JjZpLIC~zU{%}M{VRanTtFrDJZu>W?RcW zjwSPotq3Zn&Kn&uyx|6z_*kRShypwjt07Sr58>kS!{p`J_1Jc%41Is>f`W&-yd`Q6 znRor^_&G)!&y}yMEt?p{>ug+yS|pRq%+-PR-)m@+>>}K|g-5wE1yA773-YY0mI(Gp zgZ1%xl2$B5^B74ymRmy`mY!nmqSaw2)||H?h5`4EC9HPO8qEA}7pecoLy_ETbg1AK zt2ep=E?IW7Ow2Abg+3A9_GP<4_OK=OS`q>JipBKqw;$Bd{2hddw-NCf228rsWr%qs z1)K#1dwbW?8I{-Z%s~%K>>VNgxzlLQ4|DkQVHI&d_yi6pe8R$$0yufZ3@dW|86Deg zpm%)=D5-K;Cle#Gd1p59?yO;4t{kAZpS9tw;>!$-xsXa3S!VCnt+3^40JfHK-h#bF zWJt{vO-<ck+oD8VK2sWU0+*qp^dg9lf5X(wuET=!S>{t&UutwinEznE7^Vao;mZqM z;8W!S77M-+9V_A5gWG<CSKSO$c_)X)g$~%5Zw)_Qoy2U*LgspSFqrG@hT9FY^xnkt z<Vk`Wy{N9j&blSR=}1~ANUKA|@nllGupZ`?WPyp37riA~!c6DRscjRKi9%@%W54A- zo!~H$Z+2=kt_nQN1PY3S!^Q|YV|4<^R&FPa|Mig%K62!2+z$TzW&cR?q2D-vMJ+Lo zdI!TV?f^Z$h*)x&vUe{e;ngZjaQc22%N(R}Ak~#@IcyCi`UFmKjs|0ekMK3=G4sC1 z8s7JW(My&a(emDM?maTX_tz<d1lb&n{$vUtWJ~Gzvk@|cuh}iNu{eFvTORxMH6t9j z(tPI3EPU)~Ni=Ws`6{As$P$e>_{LY~d{^n1b!IM4?rJLhOPq@HmS}SPs52lTRYH5Q zpI-ORHGkIDO}F)0K<4BavSZmi5}y1PuAIGweMVDJLve^HPNr1<Xb`V>k~AL5mnFxK zYN7lj75G?n1>W3_X7>BNVOwrrhSB7`{FN;OIK?x7?ufrdv)Nt5XeZ~G?&!zOM-GyL zLS4A{Or5UC%t!jEjQ_z*7+fTF@-tTKK<Rrb{QKAEkbbvO^AD5bL12C*Pd!Kq&d(F0 z2U0)R_8K}fUJGk^pG%8qj6)=wD(Fn=G9Qzn_$eTG_W@Jf%6V|6h2plr?PS%9XwC_I zhdwa3;W9a~^y8mOOzED0P#y<^inGvWKom4fDbx8_6V+4e>G{KV82{lj<miua#=Sp< zo%s#u%g2xKs+KVk5-5Q6EAE5$r8H2P@rP=sh;jVOaH=`}p8V&tmBe!eqkOwwX4}VV zI#a?5q8F(V-<NzisL#XZx%s4wcN#3iUBK?{NoI<I8!URr%{AJU;P7hB&v+*gLzJ7r zT)UDqb_wG4->r0ciU116$w4PC92G^ck(G*X;8s*HcZPaK@4RWCYnPnj2|X0yydA03 z^Wu3J&(MXu!;Xx_=K$J!aXG!B@B-Ek1k<0?5-o!+(U=~NtC*&ZW`)JHWZMIpmGcA2 zPFQm8Ct)m^x0^QTr*U4ibtI|80iWz}=lA?r5C2R~vF|2v&hZBw{OaCtEambJbz?<T z`<5uVrfULaJFGw{d?Me)P!-EgbA1bG6^wjw8ho=mp~~tTdtf+#U*H`|TlJ=a?fhW0 z8BNFL&lND{7*D^sHqhsj<l$KQ61d;dN9&t&ag#y_-c(#glr41WQ0p^jf3uv%TowSc z;U;i$wxMF0ne2eHB3;>b9CRJB*xSFAh;G0na8>t!U3I0nI@^ixCu*~<B%U4(t0ZZz z<D^LFDeF=2gN#NJQ1zYx^9B;>3L6o!Sa}pYFH{j-i4&+Hd6_jndJC!BBL3l@oQKN$ zi1`XXIlSaL3lCo$txfAqMlEYYzPkM@zQLd=U74RiWCzm#G!$?`&^q#Y(nPeXDZqmU znxHhn0PoLgU`CH6;iDh2<o>BBHpV8J#%%K<{yXytDbOWi-@=H>rS-7?z<!kZDgvr~ z64>-nj3%`uqv95O{9vTZ%}YJuT8ulb*^@`}9?#`jhR5@5xVhiuoUi21#_yz_y^H@| z@27VAm*Bl^9Ot0+F<tN_j#}1m3}xcWi0|1&ju9{3+4YBs{&Pc!D0~i;6Ry&wksImx z*A-}TDu;X<`vrI`0ardbi+jB(S%2jsdN1eZJWU(8-o+PkG}wl|Rx;;?p<B=-DiTzq zxs2Jqk967zZij!=k){dcu^Vq1;p+#dYbCtSkjNK1VDWW3T$A{hjGwEZ`m5zQ<}bHP z;~Yurx8I@pH<NKAk7Lo{1yb$47(F_zab5c_+LeEdl(ycdGp~%n<{&=Vqr#xo6;qJ1 z?<ST{m%;>YhH^cSl5>}g;N@&NUiwyXvTR-+ZQhhdpV+KtEFxs_sr`4lXHpjIb1WfN z@9xtSaZB=iKocKSPC!i=V^YWG@<yH<1NK}ZZr-~J-L)cVfX8tVEfwRL#x}6GA6)0S z$uc;pa~p|Xvk!A;&&MF17VmRQ9fa6h(M|f}tl?Q#JU1mD_RZdjUF<GUom_$W#x2x; zP9xJZ$DKB4m;nDqJ;xqW;tO3#BW|URq(d@{u36YeTOWNTs(WNH)LWVutg~iriOZ9} z;x4G-*UA>wy*1b8yOHosb|fJ(6K$MdqKAYKeo>vnD|z?{^@t{}3_ML|eYC-SO0%ew zodp?Hw4tu2u{JBskXXcOKt<mJddJtp+}P(iHRf(FIw_0MCb1ePa?X;n!;9eLpC9yO z>KwRxWiCvf;sW+-G;q^(&L663N#Z!ZNmRjph>g-C9?osFyFv$^sgKsa$-71*&RqhT zfDfdmU5hD=C;_J<dGPQ?BC{vz44g8Yhxs9eJmcl@w8-)fzv#>_vSic|6SgejU6-)O zwz_>-!=5H$$0qVTzn)<`?@Qt85>;AwM*#wk_F~CHgdak-X!YkE`Et`2@KHuh)3*ft zq#Q+`CF_&HGY8>ei!l9oV-adM9fn$+I3l^I8|Fniuw(H_(4xpWH~%J>uQQs*|6(!$ zGc+EP_D#!~!@;M_l`o&glKf!yxa4`9^3xsGu`+ehn`Kb^n<G|_YY|0O9NHD0n!ojr z!Tra%xsY{-`PXPU&Ov{Lxl@#gS!sO!MzwBQv@Q`H;UV1_T}3`}-7JeXVSaHAcc-PD zp#O6|2#8PMtGrN$;Iq%M?wUT`q*_a2D??#|Y$EeyU^;kJ)=-0IEd9YbH;Xu@vzyuj zn(vs2vvZYc@e*}VJ06JV?t8)3rZ&3y`Y$rC^E)}UGoD|0K^EFy6)>NlO7neI-XLMq z@6lyN4!rq~s_DW9Tqk<B9Yokq;2Fg)f~m?2>Bql?<jcjm=yYKYe3PLpkNdB3T~K&> zDg!PGnn8U)CFRSjqUFB_IPu*eJ8s%VU%e;resBeu_GB(7j}SUpCjn)yu*5NP5qOQ} zQ1;Sla%f)`UFq?H>S`!~+8{UMDwV_Ycl*i7zwTtO%>z2JJAlSbTa4BBq%ib!30bv& zgl((}q%*z*qlMEHbpOv5vu4hNl8(D%P=?zFI(Jc*s!^J2yayoTBt5vo2X`y-N!H~~ zB9JwoceJjG+&Qw549y&4L~`Tkmsn*gTr7*JN3Ma_(L8P!XG&Y=q%u=am|{TN3MzQh z7rXAwhl#(D`Bl%cv96rquYP@&G70){t(ME|PV(V@`!56vf5m|5?FAS(C`~$wb)e*W zCM0uS(TO)xkrc$&rV3plswaC%;A@Tv{9+DzI(?zEb}3yiya&&TiG!H!4mg`0LOvAQ zu^Qh?sOYI3)Gp%~$p5v*4Zf1##n`g7&oeOAvVu9WCLJBRx1rt(A6RsCGS75|I^+G7 zMbkYW>A}bM7_Cn!yi0u(cvVja*#!o%;OiPkgF0<7&n%9%s@y=mR%h7#r-6u^T|yc- ze{XJMH-5ojn&YWYA6IXKB%PaNr{rRuPk$RJ=2+PwmGyL+r5#bZRZJ^I8fjwTUm9lQ z4o{DI)749UP;1Y2SeNU;(|xiP4c|@V-MJabY;US0Dq$YH$|*;v-|;f4q$kD`9N7o! z9E?%=$}E1^E-C7pP{nH2%w|MuV)3{ZcORK|om?;&hLkG~e20QrD1A%>7yT?G>u*no z2@kc1Wp*-7oZY}mEmVf3omH%w$5rAjVuee7f2V#z2dG?-34RVyhQ-B#bc3HBcC>yZ z>g&0k-~v<fBHjh#Pp+bIzWQ|QBOiSKVI4VjEs%38dk_QOYz%d6#IIkv=$09$Q9{6h zxAF9E;#+qY7WUPm+baQH#qs+%Qp>sUzI?@?gID3^+EUaL_|6J9egmVGlX!`P73T71 zyKwK$U+n91OUc|_0<4O<2;N)9`Czxo5$fIvGi(!UbfOgKG{JWm`BeejX8dK7%D%8Q zz1PW^;Bhp`*?}`3*y5sj>tR8kC3HC5f_q<#XlB0$+&cW7Xr+kr<!%KMN2y!bIe89V zbG{9eIz>QkQxv*b5r`Gxct<z)L)m}&Xt_LsUR7EOHpO8eyXd6(2g#e@<1&{q=`TT- zK3RA_rHh6wU5uj9H`$ZTMf}Y2?Xd888@=kDOJcTa!f%)B;Pz=JRG+YgFB__PKMUu8 zt?PZJdXWjf2reLpHdpg+8ff!GOD99Z>uhvYlty(E8J>N|bke$P2s0%mK<rT_lrFtw zzCtsc9$GJhM|MocIV+Xupph#1y5=@r-P#Sx+ru&4I06%GlBurNGP<{I5>Na6W~!zu z3R(V(ah_8m%(^+37c8`vjdMB)H`f%wHkV<vjXR3E5~=jqpGK-Hlg}9$a!8H!5EWFY zBT1>2D9_CbyW<Q{HPMW}>Sh)BZXv_h$<xK<Hxw}W_XCi=CC;1gdl#;lUE!%7dq=+S zaHESoCql!51d>@m=u`_W_T#TFWMDxW{^^i_+waa$5iU!$;h8A>&(L{?WBG+~+$f=t znL^S)%7~J@&$-_UN%^&t1`QgNw3KKVMU+ShWs8gmg?OKHKc$S)vPVNnq>PG&QvIHP z`=hH%uJfF8-{0@&6Z!lxu1NQwN@KoJqg7J4{l#k>)L(%)TXNA`(-D;px<iY13+;b2 z64Z5nvzuquu~M_f!H>=)ay@7T367S8fU9$<a>hICkNN_UlE%1d5$}q9I3CLA4~Dlu zQTMi!w2mpk&||@@f?PmpSKAgW<^89v+D_z<ivZ@w&ZYVzmJzp2rTDbU2Btm{!`4ry zY1C_J6bror%bs7M9{hRQr<5arZ9^<m7YrNkFC%e0ughnM-`#uZVav5Au*XV*o6XPl zJ>K7go9WhYJG77tj4or0eJq5}cJCxr<E;e~N<v_X=_#1kq|Q5g<`O(_3NJi6$$uUp zr08EM+8w`)LWyRo`*uE_GXI3<4{S!qgRXdS`5Ek02qN=hd8XX<i=Z^Dju-QrDYtqd zrxbJtG_!7yv4bI$x888U6`Gu~)n$wuyh@p>9RhRVLhL^>k9U5*!F@@81Pk}5f{x-N zY~93Lgny0{GFA;tQ-L%m-ViQ2AS)x3y>}1|7yrhV`}d(IUkrDYD1+?5D7t!w7|47H zWzWoQ!{0V{*rBD(qSg6T<gKL_I8VIH^fm^-_L3^t9P3L>L>tNWYdWI;>KDSMhbz#` zY&<v*Ux9R=Oo;Qpj2l)<5P8EUjC&hN4y)}zk#aiud~YVixJg2Ea~L%o6OJ`~>fli; zOMm+t;@EeS*@=Y{=+j9$F#CQK_WDob8fxlbt&bso+Sf@I&dR~X<E!|c!Vs!lIl^61 z&*My&ey5XvYQhhrI{2JBnROlao0*?|m}L9h!OeOOc)>P?#6^81tNOO#vV0eMrCJ_O zB+tc3<Mt81n{6Z^c`=q=l!K>>WZ{EiA@yx_rT<(q&~3vd8t@>7E{q+ANdX$*9`lah zLl~gtvoy31))rQU$8fG;6d!d?=kxPV;Y@iVe#FmsL3%rOCCM?T&ws}8c9QJN1G}li zTLxX0n~^0Wt_n@G8w98J?j)B?GhxD&IGC{a7}_c|<8(bCDSv;TY(97c*EH<M5V9F& z>nQRZtQ(~C&=RbC-^EI_k7SiZ;<!|DHvZigfFCCm;n)ky*#X|csb68mY)q~uN7ozU zoOLclTs4~Nlr4n%vtj(cDI1E`meO~ZUGd8_Yv$RsB|<AW$veC5q2`IrxQPE5dxsps z!;3~zZXn9izBvyLU-ZW-x35Alo+Iwgwx||2l?<kD5tZdMlIa=S=!uCw#O~+}i0jvZ zb2}!Xl=)rK<B>~0GbOC%b7Pz$m;&CFrF4B|ELp5Fi8fztWuAzcaJ3(zA^3>{d0CT# zQ}yeqS@8rk%2&aZ6fHayvXbm*ss>Z75SHmk#h~A6w9oDXY2iD%j`jSv!O2KiSNRyM zCM+a5lIz*^I`?SqopKm+b|vC!E8g8=Of8Zc=uP_=TEd?Zc~7oE$>Mn8BDa_;Td)r{ z>=J`h%TJQ-hb{E+PI=-{dkU{@83lEFZjh=P4|=;@7c4cin3x47u%*NS*6jU2+ZGE^ zR?`75he!}<d;_LGRk&c;<ydgQlNPnea?(4Vk|R=9B+XZe#LWnx@2}n<$+h#LXvbV~ zJ^C^0_;VfAy84>rEdNcT<xP>UPrx<*T*>tED(d@A6?LuhA^J=@9Gf!{w8oC-e~&*v zL8>Cy*77}w{(WRdQWl0feINzQ1^VpGK5!b;28GyufoOv(ecCiaSf|$jF`3Irm+@n0 zNtuItA7}|RuI(my_qK5-VFKG!<ixyvvr{PY;CD&`)>M(-gSowu7XBArLAT75!K+@u zlm_O*^yn`r@w*wWjETg7OApA?+IJBDe4A*K<5gT|T}J8Qcf@LX7E`?N6a<w_z$xo* zfW_N;v?@}HPOb@HT8st>olywS57^<Niy^pajUG|{_K!+FjAs_&KAhU;!EF%#OH}_{ z!%vg)VBz3DZj(h9v1}<2NsbD@O*3oAhMW1!#dooo^K&vyce529dN)L-Pmw^0%0$cx zz07Srdj&QBOd@&hbI7iV2JnkXz*|2A+@A-n^yb5xaB5U4<jZg3PF3@B({+yA#(N=@ zn{JQ&w=02}J&WE+ihv-^Dr#zB1#6-uaOso~p3Bikzk9{w(^YHfbir&0(z<}l)ZW5l z$GMcG8^G-J|L6u?Bl;$%kX_Y38lM|o#rFp^VA$d;?b{b7e6gJOL=7&*3+`Wu_OvCm zD@qK~X1U?Oj8zbAp}~ETyG!;R&!!h|`w~%R8g*Z-3Hu6l>4XFu(m3i4J7chh+I`ti zk1yVbn%hUv1)LTQICzL;-)W_a+Wt86?lEvXuFHGNCcy9_Lc?FSQR`#ssO=QQ+~_VR zt7eL!8r3B}X6YnIv<x+850+G&QKjZ%&(TXJ2L)YyW1*by=Blsn#~~9<C{ub(9S7Rr zO1L+Frum}7rcv<4s{vI<pMnwr&nyVw->I8;AJVqJWXuXZF8`J$OyK=@zs9{H;Z4UN zY+8}XpvV9(onHZu9R9%NU#0WVRf0wg^8L$m1~|KEH6}D@&{J6}VcQxVSk*4z$^=@> zhGq3+J2Aj1%jUzJE*+Q|HU%2(_u~xt-Bka@N(f$k5&r#k0;xhFIsfH7eYD97K3!Og zUsJL%yxf-Dlkme!eUs@WsVCSGvkoo~DiGa&d%$Fq9Nq00NP6PZ(f3a?^DHYHf8Wp` z)y;Zndp?J#cl46`$?llkGzXX99f+9{1v1v(S$92IT)R{muCE@ZW?g|o$H-$sj|3HX ztbGE+zs$#DzPCw_{S#u_VhySVx7hxnCeqiSO|owAJZ#NPxMWluy){1)TcmQK_>>=A zQafIFaC8gY?)<|Jtt&<8pHIjfdlkG`>&A1DoblTApP+bh3sj1wv8{L;0!oS?{#^vF z6K)nh={9HF&zymcf+bMqT~FD(Uo`IIE@=EcmK+#(N5NXim3b79ug{i{1HZEAiq;4; znApgCnaRHsQvSdK-lx@XehnWyoz0NNPsw8aXqbH<gFXvM$DFT*xc*PEz^g$D$KUWH zvuqvU>oj{b(GS6tg-!U;`zi^|tAdp~n%O1I$#5*~0Q5wP<GHq_7|}=QsTE&H+lCJ~ zvpj;#8$Lw;$nh-M6Uume)D+y(c7Uv3Uc$PaNr9(3u90U4^1#INFK%*fg&8&+T1~x= z8cP*8H}}irMpF&;+TUg-I(~sl`Uz%BX@jhq9{2k9BU&?YGBe@wb?`gkjP_llK}@Hb zA!S`)y<~v4yeXkdy8`&#+#>k&=N9$9qJ{}Vd-$|lftw%ggj(KlRG05b&i`=%t{tNQ z^&Czb)`eeLy0Ee-9=CRc(zJ^$the7<vh4CbSoCo_9d$bhzizn*vF5Dcz5NCFHU2#9 zov?x`N~y!-p2tLu<in_=*CAsr?_D03h2vi_<V?^JdboWI?7OiaYexUXKDWQ*uDSzV zF-ir_4BjSJ?nOY9Sst`M@q)*OCxm9lRYCo`7m=>5qZu=7KooO_+qGXH<m~R#O7jdf zm+}|PjZJ|mG8c(t{Qwq9j)wjlrm$e$F;X;bHjMQzpj*zD(b0XcX}94F*xS4aT}S7^ ziTfqgck(0@Z}~>+y7$oYXU;*x%O&)8_C&}?+<}cu1Qb{633tR*(rM4qAl9K2nnn!a zQH3cmGFeveRe@*f_#Oo5FkjX&?j@tNX9RivAD{2dT+H7WM~PnR4wCoRvdPEwl6*EO zoO)i}jALu$g&wVQh2Pr}q20L>LYB+J#!Inu%QG?hway4`6||G+$PvWXCz&|YQe3^s zh(!J}Ms?qM@;)G&<Vp|Y5V=j&->TybgX#2I*D2g4V}imKeOzsP6%CF41M7#+DgD87 z^Gr8VGlx9ldf_pM+c^;9n_C4oQxEZM&18D^&2+B$j+&5nQR3DEKZ$hKbK<FBK^5hC z=#kO<xf_>*>$hdIRv$V_&n`sVE0G1WPNtE!+t<R1^V^7d{vuksbSDPcP8V%Ct%?H= zj^XDl4?0(`A1-BFCI0#c_{{%F_H302Yh&}C_^r+$Cx;fJ^xr^OGk6Z)o7TdJ_cgfE zPlmQnUIZQ=uS4L~az^@)BDr^Ql&~=OI<u?0mo@qf@I9%SaaEZL3va(?yK1w*^_CkF zLn~sDasgAz9^#Rnb{hWU5ZUrB7#FX9N}I<kaRE=vFlcTegl#xX>&M8#ys$JH<TwiS zH+pgd7s{b9J(BLodB!}d2QIu=id%24fhYTw@luy7{dn>^GQm0+N?)VH<QYu%+o!~L ztSr}*ln<S=TOq;DlCen5XO%5`M3=+lg(q@OVNGWRPW!YG<kV&{Ow%FI?puu#I+_@_ zSQk!S*Ww=EDq{|;>9@=;Hios`8|k4(^GUB(3;8Ws4<XgY^xX2vU{p0oEo667CCvg9 zi_ajJ`F=}*`*S$Xza?K}Po$AEexYVpDl<Df6d%qpBNx)r$eNf9%uBy%bX(?nn9$)3 zH??<AagSHHEB!v%ZIMp3UkYGt_BxaiDRLVg@VS>JH+<MP4<^;S(j@t1OpEPkPGz`@ z&uGPR?e+68W5!WfYxfOo3}#UUUny+sT|>2gmSRN62i_l7OK?UEDd+nPPYWGLV(=t< zZEzf2(-wn2*-bW%D8o@#<j7l_33QEQG!s}g9k08}lMKs1_G-xoI?GoZYv0$Ch}<|B ze0?5MT;jM-qlqw1GJ@0QOL##8W8m_L*YLJkTPT$`fHge|sJ+yK3I@h<dD8uiv&MWf z*sX(y_PBumtR2GC&<*6I<$dNEpO?%J`wO0J*%-?Ar_?%iVX!F{bbqeFFRvqTjHxy7 z&ucs~@*Q#XNk%o3ttid=>YEIZuCCZdJ{>xQ!u)R-&Fz4QZV@v|V><P3<hg>H{=~=C zg@kL#;h72J;Zf-{q<<ene5@0jHdlc9j(^w`l_p_AL^t+l=;6|$892FCOt|0XEcU#Z zM&^VVkeO>f!Xd#{T&igSF8q6GsU4w{!?o$@0T)L1=O)aWT*ubD9Uu=UdWhy&w@_Iz z3;Y@=NnC$s;GbY6j64%V=Ng#8BZb@OBcn{*|BIrr&QHj}=d-!G#2~6KF>I-Bz|zZW z#?p{BBxGnh{Bk067X3^tHhy7N6i_1FO7K{OA<PKxp>nrJVsyeyeD~`uq!vcN@xTXU z$;o9Tg|THE=2k&>LL|Ljz-Q2{MhoMn8ll^>A9PBXKh}@^2pdixgHlgL?zw&%j9HUP z-tqijV{VoxH~k4YkuwuV@q77#hX>ie%fC?D7v->{DvQ3kbdAi~^^+KWS%E5hmC*XS z7wxN?0-@gGFmv}bPA$9wt;U8>Ma>dSIdK$BWqX;lRVM@=z0a{TuWY8^T}9T~oCl|G z$8omUDLUoD3=kAL3hGu#!-#V!c;``d>GcO!=pH8rbdv6YI4cn_8(c`G-CB4dwgW;H zWZ{!(J4qkAkEXUgL4}k5SVO)qGo#86N}fBh_k&|ub^9pR{_aTO^%{hUq5AY_ud$FH zbKv2aub@=uN`C#9f%C*WXstyBjQ6&LeaoXU_?#+^YhH*VzK<|v&<KmQRT;;eTf{xS z3_i(~;ezf;aCbX}xwabcFhWB3Y6_nz&<#Vs_ck<NgVMiqreXS#1b8FsgTFq^fu++| zW525_Qtkz@!#U)b0|lAzeDvO9gkE0dr0P3^7jGI6<+W>Y6L*q_tWSd1w=7YY-}m+` z?BjlB?1O_}d3VrbcQi1uh28N6pq`58ckBuia_t07=UpXnF$d}8i{}voj&XBIJN`Wp zM<zr?gG=v7;i+lSDA6j$t-7<3F>1d8vGv_#EPvk|Wy!H4U^=JdGl6W;c|*%Lx<i<L zIT0I<fd6E+WAlzPLeH2=cK6oTgx$0dKPnu<56vyivO5=<*Z3T@`Q2;Um7DBU)m2ci z>mK!6J_dRg$7AQfeA;ong&xCTViyrfHcAExM~J;aYq!&M^2AtjoQ~nxAG=Ah>wH}2 zbOj<~)wy8mLia43Ne^0C!iPiryizcqNX~ytOLt6yZ_fcFZNkX*J5spDeLeoS=rP@N z;5ebKkErhzQ%3sCMSju~3QGKJzpW$;w)%Hb@14B4CbpM0H0~8F+n|ZLbMghfJ45Jq zl1pwK45U9Chna;LVMJ`-OKRb&O->{lLi@lwH2!xBoi<3ou1(W$k9jYc_6y)i$sHPa zqn&Av`;Ot7XTbC6c3}IxardhlTIl;9Y_h+FO{sUuw7C=cJZm5XdPl;yq$)C^`ZR4{ z;6P0pq=e(Wn@E|N2|6m)W7CFLbat^ahL8P26XKnqug!&|tn4D2t!99W(k9kQeG-0{ zS|cp`JC6h<_mO?Sbnt865oWk*hzO?u%!?>z-rGE6wZF??=bmwJBxn^**&K`9W8R;6 zQH7K7e?>>-`{JH<15ljzmi16#;fnr8f#&o;(j>bTck_3N{T68$#ru$7hK|9M!ZHH; zUlQ|@x72Jt(9_y#(9)AcOmc_mwJ{fHN3=PZWhS$;y=Dt{bx#uhIBW{{4DOSt;{o_E zGm-4u%#Z;GJ6t%;5SJL7CF5;YVw2iYTvb>_mx(Ir;OOIc(lG%vSFgbqhwtDUav21Q z>xkPv{_Lq=4d)V6@t^(=W`^uJ+}Nxjv_EPAGc3|*WR;3gx!#{!GI}u<SAB*2Eq=7i z{vc?y_oDlq3v9ve|FG}ER~qs88MCh2ofIFL$tm=2r7zzVki`=<aR00nntbOWGu_1y z)Bgs+{Q_f@P13{G?PZKi`c$ga`y8e%d`w3#2}Q=1_cM5$qXTO<VGNlJBU{vk*Y90I zDUTlda7-p%T9V0(`79<3dWcM%%PrXPdm_9H*o#YVN};RjST^_MePa3d1eaa<O|WEO zBQj$%aK)b?+97|A>OB9<9GuU421G5ezI6||w9FEUJ*7G6QVQ$lM&gNQby(2TgS`&7 z>Gg;f+;68#a?VHywNH-_Mk;2Lvp46Up64)q@iom-GNT*j&$2+%k{$4%{616LQw#ey zgcHjXmGt9xH`+R+0j4vu1#8FG(MP`F@VZipTdB7ZrQ-+{sE>drp)HV`vmMl$9-`;m z8d5V!9A2F3#h@-vYVqha?fx?g))gLt=NA>QXF?V2>k9y9xqIx+LU+jdd!Eh2XsUZe z8B&((5!c*K$ggmPxb#k}P>;ohin*khRmCN0>tTyeJZ?D}!M)+?N$x{RKYttz$|GDz z>WT~CCixTu=5t|DyT0&*L^$+!OamLE6uN6vF?@QF!s(Vw63PwB@!y*a-aCh6GdT|y zwoT;Q?PnPI#E4WyItnzO#uM><h9Dj{pDM*j@jDJaFYRg#>w32!Y`*}nlGCZyu3$E2 ztuv|w)zR?kXW-=RDVhk@<VKk>UV9!3^PN?MH^SrT!O%3A+d<(#s~iU<XQAzJ6G>_F z!^&+-z;Q<}b9vJOnko662qsEntg#oE+(~9lb5yBfGbQh4-Ne%Og#teDMr-em5Zcbr z6P_A#9QNEagJ#>s@WIBB+MJD~XKi<oV{amvo8P-ggmNTV#&c??zcr$jM;vek&&>Sr zMvJWfI+q(+a)2IK@QPLp-=jwvO;RJBMGL(7Y?xpg3d?m#-<4YGsy-jmYtIO5C(nUQ z&jGNvl!eDh61*e+A_S~2r2WZ8+|l3;lK)Q{7aRW&+3Xz)f=&x2>ctqe%^?tQrU+l$ ziDn}c<H!f=a$N3Q4zn9$iE=zZ*Q$9`f4VuEjt#_^@2lxduVwV}j04ztx}0n^cm=8X zzeu%aC^)ZpLqf{<$<k<hCYIBOgmt`&I5q@ImN(&$Gs3)|IoLfx3)Ao&Lso5si7C0v z6zLkKvuTpBSviqdF97yMCnb3@t9Tdq5V`k28WYMZp*DU#?)Tk53@<w4a@#sIn-hW~ z)&~=<dRH_Yp~U;P_?^i80qQro9ahf0!E{bLL*{y<L(IQ(r0s?SS4t9~aMfHKZpmk= z9E`Z#9o;lZIf&NH_(&I&jAw$!u_)0cM1_D>M*mQoDC(asyonjW)i<k{B|(4TD3i;) z<9P%}p9$D!@f7~Z*`oM{LNu&+PmIG4v9$3BB&!CX+^t0XtE35&*P3(Pr`woRhe+Pp zJPO=1mt&j8SQ7mFKT?Nz@O1r8x;{w;I@L$;&esOo*ied>B;=svqBH!c>4s^FQ?cyQ z1$Ohwd)Pkq1?}{V!n7ktV3|=X5gECW3hTEdX_tlYc#$u>{uNJU_Sc}xfyGdrkSnTV zqe%WpHN5+N3eUabyPn4bF*@}$guR^tL9OC+(d^M&tKmjAw_z`*WF3eN@BAT+pV>{? ztcSOM57YL4Q|Liiz9+wS7)u2zJXdBGl&J75^(YyriZjGRmrXEH!4#6hddUjCB<zKW zr2AkyJv03;b3Xkg?Kc}Ht#5A7@SR>L+DoaLWiGL7SAri?Ddy-r<c?8Op+f9l?vG9m zx|aHq@$enAeJ?`qf+DQ=T}uBIPoQ__s&SddiqQPinka6w#@BL-q04p($cRrND_&2f zjOs}U>ih<hYV~+k)(@3jPQXyc3ZZkSfDS#rjLJo_K$TWwn6w+uOxljU>v`8kmM6|J zn~U>(9+M(|SIU_7qE$~Uz~^#y?KTUl@w0|hi+7Q$*QEuStG!XUZJ4A=>0;pF3&1En zXBtAS@z%HB6#u&@{CQJ?d$utOA9c%P!Eg&Ge%^~eRUa~ny+y>!>Nl+YwiL5^)!<l` zCaU&T&`;wQ(?8`LUC47dZ?vc|%9bOcBVZ#X)$7s!)(n0>kink2D?;VdKWXGOmQ@*Z zk0d;;z?doJOxU+h#(auAoV%;fEpJfb-W_S7w%?;ghaAg9KT6dhuW&X<nuoC`OU>Zu zCTsK@>L8O+^zqq$WBCsBZmbI*qz79yxzDjla8o7{NM;Q4^@<E(58IGnu>o*)SVYW> zQ^@uj1L4x>U6|uw#Cs_xV%^Lia9HF7x0by?;fTjjutbx-9GXPtbzdfDODJ*JJ_Gao zje%+AnI-`SSmTrkUpKG8sugp{Y(9(cQY4FA=JNPVYAkgc`b@UEgu|O#(>X<zE)1}1 zVeVd;hphW0xH@etMqbZi4y-C?`=k`md;AzspS%l-a(Z#gb_Hh9xXCbguz~2joldU# zWukpT7;Ulgq>DOl<4@~BXd7yU$6xMJ`#a;nI8Xxv<9`$B3@5nudYIm=F2+?_s`S+> zb3Wtm0|z>W$aR=NOgE*Gr^+|rmUK91|JcfCowOC|9%`W*-8F<2{H&+Pv=a+mo>LwF zfBZLDmRs3)1GB%6$Gw${@Iwcm2Tb3^bISrm)5~~&fVvy(DnEdt<5$RkFEr4+Pm%Bc zWx}|#M%dT85~KExN8ucKG?me(#r!?dar#xv&Z=hzs^+3tV**}2F9mDbr;#D0`_LX= ziCSB%@RhX$^ZeOkcHf(k#H`C6tuu@`$=UjFVFQ1E^^AsZF`v0vi?=|2UkcQSi%_w5 z3+x|qgYusr(48;yn*>yl(IdCPl$o38wS=|&pPl4Z**2k!iYxpbZihj>ui8<vA4?R5 z@JQ7IQkxtF@3vdOTg!QzY=Q<_u3tv-hP9yRMG!VFQ-QcgrjX?q27{IB@ck_(;X{vC zO#KT!bN^;9-E(pZb|^%VQVlC+fpQDhtk@5yG-c4sWjEwC-lcz-r9xv;gdwhPn6qus zRLPom!hG^1>jy3fkFHvaqL~*(KeZN;#lP)w!uvO@&gyftHY)_yn5c1M?z!N!e`TV` zLI$SRd!x;ZpO7cjL+kkuh2#VRI-VtjW2fP-&Oz$+o@X$%pJTp0Q^kn9mjvftKoXP& zCkt+ro(R+dUy(Gva$JQ6i+O)!>phZ`9gf4fJLtW(4~$Kf5|t@CP1Isi=;%N0#OC@W z+&C(ceE3;sxpjjE_gKLTbK@G=nT-~hwc!<f(sY7*CVaoVa}m+<dW1De$06M}3!L-$ zU5iN#?=G^3DayO(O_c{^?KdS@?axA5c@PA-@cHFvj`({Q@Lcp|@KD<bu1Va)>=9ph z7rZK_+A3nCjy`UeoB>g__Usb3Mws|88<uojr~c1Z<1hC*;o)5$h=Zko2o@>f$mo1B z+GG+;37P<l#@bUO-4hr$a}qP~_%*4P3B&ILV^Ejp#v~qkg00^tQYB|+Y}d6R%Rkt% zZ2_Z&4(3^8%mgz*)&0#l>NKM1jT_iF@Q?V+oP*~h9buAOEx9Rnf({#H(#j<YV4W-n z%$(0uX08rysMLmG(`cR{`Uv)U#If6y-9UAsJ8`}cjUj@g<j2J$^w54y?!rzRd~n!| zgu0EyVaq@)J6XXls8FM`-S^-+=OhS$4Y=<?9@J*XftOYvk=-MW4L&Deo3#<j@V)&I z6+iS`uPB^S@QJ+Ie;9+3#t5aK-sisFP{b9MXJNQhjx9E;B|C#}!3bA>+CS)vSB_6a z4HHfB{L>vW<@pHi(r;rtJEDaIE={NFMqQ!@6(3O}mw6y;PA3m<N8)gi29e_-X)iTP zm@U0sVE*4HYU?#jAMY8DW$!ZS8A7m6<2WoBaRoBI$DmW=Vk)D30sqcUCI4!Q;jHUd z+V-&o>aOS!HIMyx`dT=(R+K`C{7AC0b2oSHhy&B$VuLrEN-=WU73yexj5_Z)$w&n0 zlWm?)A%CwJySYjN{%e!xoEHrfeT$RW$v-OKP#GSK_7^$w9-{SeM;TLDRbjyVZ@`Sr zB9*h7pmSFSJ^yeGnas@<%Eif|Qpa9M|KZ5$WcfjAD1Sc8aKNrH5uo(pB6;Z`1tEib z>A9t$a93Q9^9thguktbU!RH=w`b;l8>UcoL$%kQb=UEb+o=HMv1~B_XtSDoGJ)V`F z1gni^!}>4N(PrxzGP3s*iL!ntP_dZ^lOLR69q0U{J|53WP`jjP;g4VNc5e)5D|MsZ zsU+;a(MRS-pT(yAc3|ouLW}L~T;V1q*lRiqi*1%dc;h}YF5xWH89ae+m-S(iwt|q6 zdjy=q65f4ti4N@j2s5NDxf7vE!taygA$gc*zfVXawU6#W*bQHh@qUD>992og87+GB z-)qvpTNkRHzhgaQuFy5fN7+BJRx~-=5E~?>LG$cUOx2z`{{K80OMcZ*rzU0Lo0m<j z!6-wLULuYeMSkEI&<B$`3+TzGw_$Qe20Rpxz}TzD;8v0?)SQUIL#yoIa1uk7r1a49 zo*DqBUedj<GokVCKf%3~Le4`mh-@Cu_j6ASvEey)q3S~tL`i-HZ9Prs77c;0F$~rn zyGT2tW*{?ZujSUGPf+^nM^dsqim}f2!h&x@)Q<H>_xx%S6C+L6-?ir+8`sl<(&M77 zMV&NY_H}qJ9Zx(D332@6CVEwv%3Qf~oyx9Lhtze4$@Wuv;4tAMj7yjTOH>@7Pdo-z zR_vxF@?*G)HTvAx1;%vTL|>*<pTHdH52Rt!1Wd{AA~nmO;?lYV+NoATobKl#7(4~t z8f&KZ*h~=lZ(+?p2BNKcD4yf*mSZB8i85t2;Ww{c@FJlNM)7&dW1ik%!b(7%c><H& zev%P4TM5e#yVK~#EikaJ5e>5QAUpjwc6sf_ToY@$JEM?T>o>58+s#Obl)iAaqd4@8 zokm`4ozJ5u6ovPltibeL7|IOfKt@tCjoGk=Nme<G!ps(2C6$P6CNV^3wJ}Pk#xPPt z1$a(X19ek|p!mBFX_SyAdh;ZNg82>PUV;LrEA)di`?sN`b3f~HUy9q;Azd8$ZwJjR z=;GaeM+n7Q)MM9T+MRz8V79(^*%V1o+*X6~`)|^n?<9racuv8YFFd~?qnPb@&wJv( zKc=ys95%QQ3Zf5*(N9WSV4>CloM!tGbEKESy*P6YDx~NXUvrq(6H83P_F~r%!<<te zW>=3(1YmVh{(%_ynJVI<2mc{6E*I_Iu7h3sl)$O;4fMy#V28gqRnII&qq)wQyZ9W> z?zjXKd1v>O>c3=zstmA8RD|*yj>9blYwG`g9(Pj7A9S&Ytjbj<i=WNJN!wFNsa`*+ zyb*(s!xuy6-0iT-re8FaIgI|+>afV_3>Q*;6dMj~0D;FV7+2}b=OWAL{O3wE;z$On z2bH6JUJ$WQWcVVf5h{8qLSXp}lp5ba_2Z?X!O<30ww}Rd!-4F!f5F)5A|#{L<5@+K z4&>#E;mWF9R2I#nd-eyDgU6$Y=5BtT-P+3ON^1ze6dQ4FmFLm*s1*t8>Vwm_Gnu}u zKrC-MO~q=>sq#%_F8zuDR7Wc?!9ITYOl1r#*?$YaRz56U=_x_QZ4E)iNlbWf^B}JF zbw!cr8aTf;6$;z;kjei3JTJ4F%pY4vvsOjGPcD+qRlLhu2p6E&@gTIh(?r&~H;|w+ zBHXD{3v%J<^ka=FW7(4_xW7mW!sWA=$m5GJbHh_|^ACU5>=1*q1>U6l{5l+Lbw$02 ze!}U~#5q;w0)BQBr-d^Tp=JJZ^p1QX5+5N6FW&qEnb*w}J%fo)XBJLqRK|;29*B1E zVAWE33RjUJBKcYjHhwCgDZBsRT0arhp81_!Y4aE}j3Vg9%H<?*#Y}QmGl|dO6;jSY zo5bKdaywX@lgfUE9cvd*oBA~JYFL8A%6l^{B_?p|NF)0%+z&YUEbMMQMAEdqsBdoy z(`bDOjotF8oRc-T(~oC2Jn{zFNZvc@n@3!3ClR|CY2o4FWb*ir75wxWCv070gHd8? zctMhPes%PMVN?%!pmHA<??m|YPXUiOOHr(u2=zP*Zg7?WgI5YcgU^${dnAk93%q!& z{Q(4HT_RJX1ToBL^#5r|yQiL`S6<1%WT(ya{$T-E{&f`Rcvl^=#f?ess&!B&+JGa| zw$tZof7rX{9MPkumjtXLaBj37C#5JPc1|bA?-y&p(C--WFyGCy*dNhm-sdp*;1Sl& zs)UnIDj{x{5sH5r1N$Xfh{cZ`<dM`>u$v=EpWo+m%GM*OUa2JNemw~P+<YMKhaZWY zUP#QxCxDpcRg!RYDO7S(g@Sp1>3?Nv!kf;<P$~Zq?|m;~&UX*-&2E<WOZDShA7k8K zMzB<)9c<67MtiAg)Z}CtnB~qU9ak%9$&L3k&~h8S7N1M3KU$E*srxYTLjm<fTa5J` zhoga?`|9yCkKggQM|~+qOU~l^DN$HRj38~FJUkGELB=N$7D@GB%%{2N_x1z1>&m;f z*(EqqS)LoH+eb#7?4qr23*a94%=K8<!_Kf|Xi!bXF~)tQ=CK33{r(eGYoeg?cQmvv zl;n9kb#&v@-6*Iz&P_k?2$PHbq2g-}Y<v0)7jQgt(s~%3{%OOCnf~zL(`Lvo)Zjkr z&%tTJO;A+f2U{iAV@i!Ai19o1@n-`eE9?x~L?n}oYoC%kQpYjnN`s(jzbOV(jw4oP z#mv>Eud(#*VK~2c8ESQhgGY85Ree+_eC&o8zEm81#--5OW--d0pU!mf`Jd35M6!5q zEn8k;M)ui71D*}1{fl-`lnsTz$v^OKR4fLTr7$lY+sRpL0h(^s5k3`9rRUlC@aFJn zSU>v|$veCh^<I|KsdHA6brW~cC2@;z<Zl7&i8+JmTT;L?b0Xc}Jw&u8IAcZL1QfgF zPfe^<Alv93KG!s7_DYY1Z^4pSXZDn+)+plI<8#>iyR~sVpUvI=<OiE(sLqW|vBu4g z74$^>e;8ku07rKYkO%Ssg5z~xNT%6kG%|F9Pwo=J;>$^B`csqIom~h;=mPm(r^y~E zRZ{)p0_<AdNn)~3z-R47a!7Lyo!9<~L@t{JSNm9$eIv=|&AKU{Ex;;o2UMxlfuZiH zjK=qO(2#To9`q#8%3tO<=;kU^Ju3zD@f5l&ES}a0)FIkuK1}V~2DK&X)Gmz0Z}SHk zi>>vH@zij1Us%FQl$ww`Z(rl0i3aSp0^Zq{e4A-Mx}Epl8ww{J5Qm(Nsiljan&Mii z5L~O2gznBAWMubh?Af>%q8*K(aoj$t)$Bq4+Kq;o!T^w17eozI#qf9dQg}Y4gC^K% z!o|rud0(y%Y*ctbzOF9B>L(d|e#aPh+4Jw8Hg(+jQ=1IsAdPqvixpi~P>>kUmh*4@ z@sA2%S<ObgI5CZ9WY@v<!2wb``XikjmkNi^RMQ1>Zc;Z{fAsMhA#7K^#U$JaM9qNj zpw#?`JN)S$_1f(UT`fLjzk&>1Ww%FY!k0yUgomJ!uLj<+*iX{#<ukh))VQ5x7I^x* z08TCY!iMV$ST2n35w(a5+keR6U-|?Oi4BsU$~mNX!zZ?sFG@Cl*TR&+zjSTPC_K1> zqo6q-<83maNR{VfPRzu?F9vMeQg>7@Xd>@E9|Yzy;9CBSd_JX&ypMOleg8_RW&Toh zshL91Ou)^s(4*<8&V2VY66gOrYAN{niE4~`&FEIA(6KS|;pv`xqVUbZWQX=_+!S++ z$`zi$g+6=m$entO>U#qgkHT?(y(x?v`4aqXf<RMMog9q~74~!o(Vs4LWPx%3e|FEI z(vSQ=;q-3$&b)-$FFOg@Uk_o_wZBl_Vo0BS>4D}@2^Q{Og+n8ZxD65CsMqX7ddbnB zGz=8MYuRhezsW<?D_NBUKHUbY!;R?lE}xmul}BB^TEnV;&E)(A3uc+vJs7GkqO!H> zRMOd=?B~5@7rY)(6;TLT<|B*2M`eXaw|#_P4F$N{V<hK!JBjg#4MMRS^C10iA-dat z<P<m|+zhk8Kz~y>-X;lVC!9#<+_Uh+<`MZF+z1tS-@*vZIWW#|KM@>N5DFm#6Y}Q> zH%7_|Eo*LKJl|ojFZ2fapp)=N^)3c@$v{ZQ9D4Pi5mB@=fyCTo%b4UxY<0~&fnanb zK36|ZW862<6bW%q9dQH#c0^&4!`3^8P1XqOM|M)J$1mxFw`<XU*HWkuR72hSQu^jv zHYiThgp8X4n7aA4pt6_$w@KHa_F0~_RC<*eH%1u?0{uZ%;EBIv`Tj!ZIWjHMflIzo z%Br6U#Vv`q=;V#_gf&ePMD>L_Y@hB!N8Z*F8h?EY*A!~#>2Kb6;Qnj!)!_~nPCLVA z3qxq7-&vw+r-SvgkKqjqK8sdu#%4Y|$nB}Hq8h~yVeR-ty3@Y|HZ|)&cZ?an`qjYR z^fa{83A{!ph`y0uhRw{@6Y_AuO-6X9@i7_KoB*<KMDQTGj_Kc>hwG*Xa8`vsncKVl z$>$^nLhn4`Gbv;7;h_s;V5pquVSS`HZWd|Zz7`Gp<H0Sfg8h+d4Yo;HOi}d=bSUu0 zb-p98KG&ZleOye{=XJxZj%RQHO<_#E7W~Y5LjLa8ArmwD*+^1HCY@fx{`#Q-V^-#( z+>OgnC;tJ1of7f$gJkA}hXmTK-bIgWmnYM<m%*J!CQu?7N#&gdtm-});rQvjq`#mV zt8W{?nu=W7_+J^F*5QkHp5DU^Gb{1%Af<wj{61E6jXcs_h3i+F;GM7<n4OzSl%8r3 zn?1_H(!aM!>oaA}YvK=P$AwUw*Oy1Hwyg(`xm|SUnWgmi=OaiK#gLuL`*CviB{a8K zBYdJ>&!(*W%{~muKtJU?#yHLe?)P42wuhhQmd{I}%U{LOw|qCycv~6jPu;@IUa5dN z-b%2cMnvm^exu7|U$8zqkE{NWLeqbwf!2XwvP8Op`b@jTYRe~6o6D|XkzmcZoiK*P z%@66fA3=CTbq9V7^MEaJo#gNZB{<}!h-2#3(Xw}CC?@j&$4!bty~wk$!BQF|!u(-h z$5oiVUl!D4W5IgI2u$r=&V@QgLhGxW@N}UGGtbR|HXhT3OG|A?>(fjemu}5G>2aU~ z>*Pe7Ts7`Vy9<@a&U5yRFO~fpOMdNd0i$2{QLWaV6ft&qkIzkP-!cj<-@IX;cQg^N zzXFsr*Z?CBjmEZ_%V~&$H0+$jXRgI3VKUDlTNHH{`~NbG`9LHY^-+<GeKmoua_Ped zYjx=*&lQllT@rc(=P~<tD|e%Grf{o>#TOIj<HxD1U_@*%4858Ji?q_{vfS4tdq13` z6_%yAWsd-A>hDs;1qrBGWCzamzp-QMe9@5y9NGGW<9FFILf;Y@PQy8m@w;{h*wPoY zpU>}Kzwd*2$%lw^b2Zsuz_Sy&kCQlRPX_;-!xvjj_)gXVW^UkN*!BJr{$O6ff|d}v zsAfDAeE$zuzH|iJr&T1hJc|lF63LC8LQ;IujV$ZEL9(3e(EB9MTc2emREZwMntU;8 z7<iBr9Bw07rLWkF_ukX*hg@Oui%OVqbRzL=;+?uGb2%$rV>ByR%1k_Fj`u_6VN~Wk zn7!2m-fZCWB~}WYb!R!<c~Y0=n>1tYMO&I(r~prHMKQ$L8mBaw;G`5ue4ElJxaR!; zwW?dl^=YHPI>{X3kIf<b8@3_6<p^?L&JnflHK2BFDOSFAr=p6VB>z@-Y5wx-xZJ{@ z<afWp`RsZ4k{Ja?O{dA`u5%>1<v*&=XW%F6jfc+{^WX=+gAE=nhC%DsQk9e-y1t?U zx}T`xS)*D^Ja-;m&9}wq@<iIG7YrXh@tu^T4b;~>7H*WcG3LTzI^}K=xpgZKE66u; z+1UYR^vuHwnO0hQG6;W6NMh5%Ixvng=YGBWjmyu-LbF^oZ2J0&-O=UCbC}2A4gNRJ zfPb$Xuc;@?y)|g%IB71_V-{O2t$>kTa&YUYJ&}yj!KAWK+NHG||9FJsk`-yN#x)Ek zvH~ox-@@1%oW|!LbE#vv7X%eAfZR2wQU6pHiSa9<9TRqf8!ZCY(e}i8(lPk?xf*(S zo`U{(DdA{m4m=k1(`!p9Y~;Dzll<CAsAL)0bVyN{cBsR$(x(sWV<qvTG^N$gf5EvN zU0l2J3JvgJVbkk%qMF<)T0d|W-5V_F@y{KWC+tJe`(GqI5D-$jx6vQ-qK@F3y|#SU z;UI}ya0x~IDtKj*0-o$(ah&XV@OUs6(k;bEz_%fu$5lq}pF4oIm;Z?xUulD_!V3ES zt1g=!_KsG}-$L)_ej;--UUP6?8`_*pLFr|$z&3FN%rcH9LC3!0t*&>lwPOIE{nUXg zKJm18Sp<?FM>w0{C3xPOLimwdlHs+JlYXT`*LeNK%b}ql&9n8B#}^9%TqL*+gX7TC zG91>;+y>J6{O-`81YQdGj`J!3yf6+x_uoO>-f}IlYcxlx<S*pp`Y;^%xtQJ%e@FuC zBJhBD2`u=UjvCVDaQf&-bar?yEV9hR^J-nN)1rdz6ZZsB*dS5=v`v`fa~ZyVX-8*Q z{++Pq8B{69Gw(y+(}28n;Pdkip0Qt#@6yf^NwxpjKi|A*gFpuY`m2};3d&&dq=H<V zCk5M26{7jwTGk_PKgf=HO_LqA;l%edL79IS<&Ito%2XF^Y`e(*ckvisa{{l}^wQJ( z*J<txbNr>*%`UxN1%BTyqJ~@;SsAmDtzPs=wBLLKYL@zlr28$H)oH)^oTof8w=?N< zsijoM$`e+b4N<MteBLN4914z?psIB^)K4=N*4^BPr^bFE$!jLSbsYg*n(07;FR%jl zZ5+8VTSVXf&>(;1SyH0+AF=+n4Q_uh1P#M{yw%@_tp-8{9!TLw{c|{GsF(@W{6NMm zKvMo>JH*5VQ*T=p8u_mp4I;;r+dI^VYho~w?=^wnZof#EGXMAFOY%9Ohj?&fA<a`8 z3r0tZQM6hc)^vTMdq@4psqPvU*_8(2vJ-=3Xa(O-$QcINGAH;lN`-kcT@lL~<k2|z z9A?=Ck)`T+_&v0hrntI+-L)Xv@F<LFd-9A)PNtBty^}aLQZnbVF<7~uL(z^uST)`e z{8jn+!X{~Q_FEFpe`W@9nf|yVF-|z3bApDP5hoK@PDYPOiKywV#8rBP3Ah?#`pmT$ z`d3-tvt7Sn@7il%|M@l1u^)+_Kiq~U`BXtR6VGncJH`JFWkHXl4(flg<p&Yvu=)Fa zZl>!9Je9bGIJ^0f9>?p<qUH#p#LWaKSg;7c`i(?S?RSDtt&-%FvlXWslWDozk-u|V zOkw`}wvaK3tPre;`3s`mmr*B+!!5kO?ZDT0pmZ&Zjx-d(_c1=y`bao+TbIW=9K1lZ zKdRw_#}~lQvKb7==i}rP7nr5@vZzOL6>VLTL!xZgV<OM*eW{TOiMRV`>o`Xo{TFzq zr~|$5C<9-Z+p#-pH)5c~GrD-}GSQdE2XL+6iGbX8!=$u6?6vVDJg^&2Ps<aeOghUZ zC;Q{26CQNfP@c0d?FFsx<FI|tQFsW~;l`F6=J`MoWBvK9Fm0a(Jm`Nzx&{^qm$r{0 zGq>2o!Q+0k_+A%X9xDeKJ73TzFGLX2k|+9o|1{s<j<XatBe)-VjG->NSnz!-eN)MI zS%YiH)8=<{?bHhx|6&d_Wgmc}AN*+ll5u!9ZwpjK{3hjtnjjM86S-WzBlXXWIsaQg z)%^A7h``JAp2Ryg`1g27sauBbsmemh())0*ypZSnt8i7G2B>vf8eREshK%|gj8LiJ zUj8{t>=JfT8=i66R6HI0=Qgs1KgYnQRRAN->kFUBR>JD(*<j|V3?=ch!otz@^xMZF zsBTV#`i=lBN;LrKsiEY?K5xOQp;UYlWKY_P!pW!^tC=>%+0dS+1WNfg*+AdFM2XM* z>v%n9zI#5TGsmqUBx)yky*EY4r%Rz=+B(`F6+tU@ufr!RZ{xtBnGhUM4K6A^RBTx= zv_6pma@bV3KIkB>;B%pAHi(ic+VJfjpS$7jKBW(=;NRv%-bpSY4Anf%{I*Vo8ogq= z!r?vYJ{g6f4hw~Eqz{u@$?arf(Q5o^ae<h<xDTn36*S3%pyz-DY`$qA-1{~c6h&e5 zYO^CO7<~{YN$kWgb&Kfb$CruNt}9%QdkZx=WGMU=vzeaEcZQypd365CEL?N8i*5U@ zho6l8(vE!^Bzy26d&T4uxCBoS3Y5bc-#vqH-0%u)_0%D4<6_bNVKlCek7ZjXk75%N zmV(2|Xj(iYj;!^dWRubl{M9c<z6T}KfXC7_NU>dzx<DLahuet3E>k+<uoh-}2clz; z8GUs~2{IS;lYcHx;aAOQP~^F9pNf8v`tDVr(9=YIpE`?q6*KVY>LM~}xRd1Ps-k18 zlyLE#YSb#*fJGPQ!AX@Pg0h>T<T%f8KQ=lL-kWZMZDVtJCchFtFUuj13{I01o1SAZ zhKsCb+M=e*YpRf7h4LD|cvf*6DhfjJ!!3U9Hv1eI89oXtM@>fVULuU`{?1%#v7sR{ zO97v%VUdq6ZVr@0Oo+!bQ*+3Mj8Vd}rlq8O>_67%Pz2Hfb(m>9iVJyv085@Yz@F4K zRJPQb;{Ga}F47}2J1(=cc1N*$;!krm(JyFu2jKeO`k>d@f`fY=6Wdf{oaHdc%nzGI z=$v}=>OKnz4tCtk-d3``=skFS@C3V{NCqQZX{N_WT$b8TD%OURb$JPp6Y<H?X$|0h zl|86gG84E*1|ZcK!tPMg!PiU*+t`+XNh{J(?QkJJN;eliwK^~I71qKjvm$<%@*NNM zB*N4m*HEG`6{Z@NfQ^$sm~X5hzv@1a8D}TaYrDOv;Ycss(>#Z2Up|06UV}`s;ccui z5eS3UGF;x#Vsd5TNGhY21W;Xx4bSC3ZDcskO}T@M68l+9Z6LAAqv7SLo9vA-g>X2+ znz8VI#Kt#u^7$hps#$ZE-CY<hP?xE|l+1(lS+YL4X6u9DFJ(&C?TbW{NkjB1pNH^P zI|C*~`>@gV4Oe^KN$BUjj?<88qJ@_(gFl~Lw!ZWS@(o^*f0IY>&bt3l!S682$Y+zU zvC~ms&I?~`dI8Gh8Vt<OW{%A*CC@C2@!Y#-kmGN~jrt)5e?Iubf8G<hp6%k?8@CO- z%kc~qU)M@xW=Bw8j{$0>S;-dumf|kB?1Zrv51EJjJ2Uk_Iu>ee1zZ0sO!i$B2+=r+ zV;)Y1@0=(3+INzMtXmG%8}dkUlNS7oGlqb)2A)4<f?MOtv0~pjEVO<_3RM(INAG85 z>Sh7aO`eR>?H_>U_>6tjYN9gM5FPa7xySXVux@8N&tHqcg8k-rtX>}m<{7~F74o=M zOPsr1EyQzH(R9JVji~uj2A=DmhL?RtB*V%A1Jb5pUVA1@=6x@cjT+o3F&$jP@_V(N zry#;fm41wI#8vV!@ThARfY@jlFiaF(XnjsyCNz@w7stT6ghG56b&a56ARYEA0~N^( z_%`D>2q%oiCoQ{hbkc87lQ9DKuW=CPwTR!h{Gqa^#<9}l5~;P*We}H>!)J}1_|Rzx zau_=r|BXLq)13Hj{SR`-D~`^383USb^2ANg7(TA~X_?ag4vq56$e#13;cf9sG>Y1a zOja*CmHeV+RcCO$|5Wa8M;spXS&rGak3p1zJ${K1qWIURf;}?QApSZR$D5rb3wsSQ za&jUqkr-etgBe_sV2<S@4uP1S6uQ_IQU%>)_6a}dE6GX+x1B1mK0*~U8cJ9#4<qh_ zb308vpT~S1Sw#*Q??AOLO7O+chaGyl2Ts0H0{xm#^nIrYLI=cz$6mdmFXBFdbgcx~ zJROBSbUDg=ailrB)xmB>B-8%oJ?}KxL3e-S`F8g&lWf<|v}33moL2p%+IcZ_bN)PN zoL9$o-PnzOdc920=J8na)}L)xl*civY#@a96AZ5Gp|ujF=*F|S>ouC__iqh&XHF`! zyy_-(ifhCf;W@CD|F-_KGoiDYNnFwO7U(-Kg%9i~W*-eC2iRyT6+H_A&rHQ46CwX5 z_Qi+wcR1V7S<oEY2AA@z$vSJE)t~c{q$F0MTswsZFKcdji#9CWA3*0coWg*wd%3&C z*|cd%4}|;Ji?Tt76Lo6+PtkeDbM>}y++NvRT1sgMP3zp(Hz|r#QfVlOhK8R)o9va0 zj1WpFgr*Vaz7A1IsI;U=q9ht3O6ob!fBwUZbH4X|U7yeUjcGIc(R#EL;vPGI+4Dr2 z!-{ey&(7gGlh>rn<`A1Iz5z2{UW1~v4kk>?AJP+fUViU<PF`ILy3;SybeS-?nKm9> zsS<xruz;}jNmRtX5KMDpF#N`BIBQ=;HwJDHT=toU-)4;yc(40Gw}`jG(Y+y%uyl?f zZ+JDxWY=KOt$ld=(ROt5T47E@w6NdG18(kmgxjyy(y=>+$=1aC>|4{lJmc#jEAz%5 zrtz#J?fE~Mk2TTIA6<re1F2+bfH{=;h0@vn_E`E@4}yKJ<F_O8VB`8h3d{GwuAKc? z`eP6c#Qf3k-*wg|l_gKu_q6*G<r%Wicz;tpoATNmerIP>v7*D+X*!2i^*><`Itz2X zVzY6;s@YtA>^<|}?_Bw_suT4;asp$oKY^?7ggD2|-mrMqFti<Srjqtn#G`ozneP7; zf`%_sA2Jt48VAYh>w37t;56RZXGcyHdlByo-E{MXOpvcj!{n8j`1sa;^uneGWW$qj zcsp?q`>p6WG^D=7#wtJZEh?N*yJH59rX#o{?jflj4u!#RY35khZdd_oWS7H9qGW7J z3`Z|uM350~ntT_suGpbs%~p^-FOI4*vD~zsSJ?CuA-LXfChQap6Z1v0;NZ=jFf&sa zs^#v`*vP($8OJ8zo$FEXb35O$T$X@-54uQJ8vmZ^k0S?X>?Pe@@0oxDI{b6EmkBTm zfeS~@;R-P0p7DHR)z{m>%IgH5O$xz{cU?g`KLtZI!vt6E|D)?arICyXWg;IFh^>cx zxv;z|#7By<0a_=Z=+$ppYQI7-CR+yLJ}iQvbKzKhGZ>_n^4Ww{Qh0o<E!OUw&U+uV z@GH+;^N5duOp_q)z|1^cU;md%`()5(-CLo=ZG&L8^Z<nal7KyL{fPS-G4x)|KLa-B zxUXtTxJNsSB(36E9SQHL|M~igYjYmM+ISOsQg9Zx-;sf<yHg;h(SkXkkq%4Gy`?8t zSWu-at>*s(2}B|LM#Y=@K+t|)3EH=l@z23k)M@@R+Taw5^J>SzO+I%x9Q~F(H7gWi zKl9EMhG$<lU!*@DK4e!#%b?opog_7@hJL*Ig&uu#h$>6}qfJ9P5Sg-v_e##?uv45E zn|(u@c;3xgwhZKItg+g26_NgO5&wPpNtEJM&{gIJYd?1lWPI8|qdFp);I(3lG!MH% zw(Eb4pi~)r%p~CAa3)l4ScW~;tI+<s26(2W(mkzR_-c(TUfB4I`S-PnRC~XJ5Zxx~ z6nYfz{T$C&eVhQxu0-L~KQl1<*dVU?r2&nxr-<;#XM9{Gjl<$1f*G0C{9MwQ=c_uw z9DeTh@QDVx-qFHDr@gc`=?+Qbd%h+vhr#$vHSN-Q2T=zV$f{!AGdO6Bmd1zpnZGR? zxVDwtTl>hoxArerp&3gLbvwcsE+1B~LAQ_J)T{V<oX@7EogflVa|OlaXW(VhSE6)2 zfJiEiGPfm7@abOy?u$~0cb^?~KR6SQxpl)tp1tMhCP9OmT<N>eUu0pHD4IC(^Zg)c zn0;v`^XSrf;Qf_IJ7mpX&Qpcs1-wu6_9e;)wa`sN4d&sEySO7W$I{reow#Y*4ZN|B z5`*cd;rrbr`npkr>G+dK)}?f^wR<8kV&QJ`c#0azOwy&VB(CAEH4E@r;2PL@ObqMF zBEie0m?2BfRLmWjMn#QYQ>Bb0)O_Yx!S~0}<i@Z0aCqV^(rsD*4^n){zICy1K-r&~ z?rCI>`Hy8gC#At0Ss|QPa~h1EA4dDe7W!lTIId*#WN<j4%E^7^{mY|I;Zk8dqmUm2 zmaZNs!82NVj9$=(k1o)AA+|VudVIwgy)Wd?dU<BTRsI~_5sm(13n6;fc*y7&CI61{ zd`t%+?y;~wbzGHic6PJ8pgJ^}@JtUdo%z&!>z(g7@MJB#-lBtQ^9)eo>R00bNf!iC zNl+-+OQg2nU|%Y2<J}_T@z~#8Fj@KtN!?}xZ+os#t&V3*!Cw>jZ|OLaY%D=SHr~Xm z`ZIBj%ujO9z>mF=zli>LG*R%>I|Ik8*hnm8GvL42KuG*J6#}H55nty7$WaT2lBE?? z*svNsA_rlyV-I=Ju?R0~0x~#?*H*6~N`5|&@9KoJi2`>n+YDtILh#dVc~C!c1c$b3 z&|CaDW$$ZC_TbBYy60R3tk*tI3uaV6o{9uLFx*Q+pZmjsly>lS>%zbpllTtFbM}^$ zE>O?!)LhFAKXh!Pcxf&^*`x~v5fgE_0pK@&|9*DtA#;g;@!XJxB<mRQffn<AtCsp# zct-sVqn%ufxu=nR5Y<l{^!srkQw)(p<GDh|LDKj)6(T~XLP{Io8F3n9=Q*y!y>u29 zC3KR7j^-qMqdysJ_oZ^SvN$3V4F;*fpq{uESCxxnv~L@o_UsQfMaE-mqavy}8wxUP ztuQ?37O4{}BsOZl@lyRPzOQ0}$4piUd~B1MO?H=<XFqeHG3gt5{`ph6+Sfbuy=?}a z_p*j+%u2!6Cs!jkVLp}jYk+0;AsjFppyTi{bhS?7dnulD(^gsdXjP1t5^C5h8yCRU zn;%GVKc8RD<=Lwp(y*d_A)T?mp1J%W0{&LD)9>5Qn@4QVHdo2tj&Zvb(A-=Ix1RFA zy(*UI<0-%mlhd&*jUleTH^YzyzY)q|Ia9}j0=2RY+|;zS`0~RN(&=49gZd(|OIQR7 z{?91+B7+tG@l2Z|*Uh^gOu~ZuS?sMv41|THf!O``RQz5!uz7uSh3s|E-=@rM__6@T zu02T1BR}Di`yEv8b2Qre&PVIpO86#jHd*I90SB`5iNn>g-1n-}@WR~`wz&p_*f(kX zrOY#$EY!e|lZS8Ff%ryK3F=cfQS%o_lC*C?X6h{xFhLJgy{q8mVsUUxRmYi~H#sY- z9^Szd0NSsWp<Cci#^3EAC6zYx7#j`&BmQKB@4K2+M4|dQ7q;(C3|3vw0PBaj828?@ zV*1Ho(#LzEGCm5yXAO$+y}s!3*&Y>fEj+jB0@cwepeNQ!6h|h3^<7E>u70COckH2E zO0Q8#aVsYTZREtu?Qp~T7L`>SkCXdrX+&8kk<<H4PmL~vvUzXWm^5J!UVENwOn1Wu zQF*)`(+Hx2|6oD*b@FikMHsh!9LA`}qKwo7FsfM0`;?v#H=BPXLurKCSUJE*)+zex zP#0XuWa$jmpJZpzE^s^emf7gF7s!q2r2PG4Fj~?_#Z1%5Utu8#E6;*X_ble5Aer>) z=t9WhTTp(;io6c7!aKjR=+1Cy`s(^j&RI`}BNy~(;EN)9Xu>60P&|#TkpIB$E|#Uf z=L%t5-eUYT@i*DAx{eA4kAYg9omrsZ0sdUM6i;njhGGwW=-wkyRQ1s?oq6L7s(<TX za^e*5PRV9QX*u6DdORK8Z%U^%tyXAUItF7KcMxl-9@==fgh??|1$UiDy7?BrBS@@; z=M$2Mu0%0boG>=MG0z=)r7~%@6>z?{BB*}rSZ-PGI2>8f0UN}k%*WF(IIOc5#<k4H z!?v9uqqm-IC}S&R{I0=GHF;cqSqwjV4p7O%Qy?~3l)Qa#98Qe$gty)6c^^|6d3*RA zDx)zgw<C_0&3J<Gh8aXn)*T<WRpZ*gOJx0robviP<=AX7p0ia?gNEfp<i_`<=sToK zA_gvz?@u!X@ycQJ<d$dT$&3uV^e>pZs(puqJlzR5;yLnu?^TdLU=45Gs&I+WRLGxw zkxM5fW)J&$r{A0)wD?}d?OKqCTO~6<9LB(KoECTPfH1l>yr&JhC9KWG0I*)2LoS7{ z$2o3C+4<WuXwA81*7U$_RJZ})WXIn#YomeDcVM0Vd%-G*ePj}%rE$=$k9fab0$D?A zP+HcX?x@X%yYFpa&GS$cn>dz?IbO~l$aLlA=_P>ug8SeZupR1o=JXr=k7R2X@96xM zK{I9Lh_w0`OjoYQ-;<WY(EBa8`|B)lciw}-GHGmo$6~nh;tVQY9A%=EYS6qS9AITT z?d>S0-!k6OxgSMQKB^7;?5~mbYf;p{WExiAO(WtD^6+T!L1v2iN4ju#G@Ow6$s}zX zz-_HT7#yiao`~j<t4A`)i<m3S*){f9czPPb`3o>qJw$!N_&t<n9<wlcBGLD##+zq& z?p~1(5753q()Zm%jYm2}{@G2M5b9l#E6lTpth!*zX1-f0f1S>YYNo4PkD}g%-GbJc zo2ckJB_b2Eowz&i#No^#Oi7!7T6_Dc(@p_Lw|s=V!V7V!rwF>8QKBpTR2iq&W#oYW zWwJfaj4YNk=I1auv>mcRWQ-3nXz&yix`;w0-?6?pm3I&D{E}O3OTf>1BFtUhMGTHT zzzJvkadwcTpgcI7TtZc_+WMM?cU|LJcb)@<-MRSu+H=-nX9bz-kW9Zh&H$!!E&M!~ zPd;4V2g(MyWY?V+5ax3cHCRO)O0gqfw)@l0>BFQ&(}ZZb#o@VEyodR9xA|m4YuN4V z00!s81P8VULQv*kwz4#ZS*)iD;zz2<TMM3jsJRqujbrJLwVBjng%V2S>*A}C4cu7Y zP4H&>A@~^c0B#?;OuW)I2o`R?OE<sGBl}nAL9$&QQxf0>Ij&oIJ~+>H-`HhpB`JcJ zZa3obAYT|U)fG%uOv2vFPB_bBKdoJ^1~<i>(65SvV|th1;|4$IbL=NFkB-v(-)A}5 zB@s9hoB`*Gf15X{Z$TxtoH0E*49g0N$iv)~?3xAHY))_hd8wBKF{jo*XHE!ewhQA{ z30?l2rA(Cgxpi*OB65C{wtxt}va52(;K#?}I4w{Dzr6oRIxn21;mQ@%li&FTty_mB zwmB#>p`KP+>!OT>5?2y3gYKO-8{|ILQF%i#-ZP$0bw164gq1#c#P$U19D<~3?O7Do zd&{)$yTUVk)Y-^%ADC(K2sK?-z=ENh_+TiEzh5096;6a%y&|zfaNw!H?UW37>1-w^ zJ-*@v#Sn6ciG^N2NnA1_it}eLfvD_c+&61AXLlx>F}d4Ht3~u^vsVyU*maO62fUGS zu%Pc89N=@22{v?|#w6Zp^lFCzu)`tbsfaxO6G+j=f;9MMFb?Y$Rgptu!eIAeB{-*& zPM#Xh$NY#*Xt_LxPCZwSLWVBpPya5%xl)plI1tBltBc_HUn8v0scG1dVL+<R1exz0 z`9=<je&L=b$%8?K1RR{mcWh@%p;f*G>=@XIqmmU&hH;R<YR-HZ{!GZQ(_iMNWi-jY zJ)0X`!0!Q;io*}rMq<--3z^z=f;}J!-C-86Y_%@!G~NtXBHyxGUYL;aha53wixctC zQzY{$G;vr(nQq&C4Y&jukld<5&sB93oc5R|eL2m|vPP;(98qV}UVOCcA2EJAfw(G8 zW~UYfqH=K%o0?$9{hb?w5|N5Xd*exae;6{K8&UN1MRZHJ4g2%_iQkoVkR#~|b<Vzc zH})qT7P$rS(WfBtPd<FNxr@L4D1wYzH>166o*;1I6(T)J6EYoEkfgQ)%$k3D7^7q3 zVG8$|?NDam>#Y6cWStWZOHSoZJmH;ryS(wH`znygzd>Kx<x(lH9`I3=#<J`#D)jgW zxv_RST6xKl0JG^NZp|ceC`|<?XNQup`!3P_D~`~Bq(#K}eFT-iGZz2EiVDs)@^j|w zIug|x1^3Pdz}}c}$aeZdmiJ`fqhI=Dd!i`KlF+7|g$$|Q8bxW!M#`KoBs|drYAh&* zx@wW(Kz*1lDh!IshiKZDb0}Y`S)n^U8N`V&QRrjwMSC#szAD5Ei%*jz2YJw1@4$rr z4kyzC7om$u6ZsOB1h221g}7N-<XUktH8cAQUPDzhDb|68+vPLro+^Sf>RWNGy#+Mg z6GGd0Vw|gT7_l5W4Q)x*nCVi5&zk%2=yVrUuuCQ$M-w<_1OETTq6!+!dZ|I&Irdb} zWhmJ*3;yK<GeXzjQr+0ER4%E8eYgLNU>eGD@fN#j?WX1A-lQw^S?zzsLUxqe47ZXF zr*tODAqY0TcPC}8g)r7UfOXpaotg2@o$GI$2m`t)<d~HZeCm?qh9`EDkPZcIsg@(A zi>?JT{VzE0`7n|0T*H|izfU!fDZ;4MXF9Ofi|ihDrkT@Rsrm{R>iyz7Ni$G4zq-Sa zNGKo2iE&0GE}?>~e;Ns+>Z?)hXgNAtAH~RR19aK-%X|-1qGFSSrNCd#4Af?f<1@eW z*qP?LaH;P_>R{-Mxk=h^GwKWTdEOWp>t6sm7U$S$-S^l(0xS5Gbe46!mrf6NCSrk* z2>#sF!Y-4PfSW=~xY;Q=z-}$VKkqFe(7~N((E_;iB@SIbFMyf+d-=ePBD4IYy>x$r zIQ?oOZw|QysQg}<s4q?f)yw?*Jg6Ec*@(lu=|$*xHH_xOn&ULRb!hp`mgm;wlP&7{ zIQ#BdQnBDRyw~g{huy`w+{=t$Zo@t<Z{8UEo<0rj{baGQOo8*dt&UEM!_bKE+5NqW zK>S`Z+F42{v*#=A8z0Hf$K?g`m-&0z-7MIBdN)*vjF304GVq(HEN%~#Ls!w~$kr~x z28jc>Gi!i)Xr$2oeGh1HfdMYN)(e9dU*W|aPsl2xy=2RQ6XfaV1ia{_0qOVmgWjvf z6>Y1OF<E#vT)1P$>?;ugvzT%4g=d4G=CgYvGgHW+zNu&(6hvi@9OA+wonT~gB;8dL zjdgFou&vMS;YIUyl=<ZeS$yy4^ZP_<I(!km6pq2d)^56{Srs~6Mey<&U0g3_MQ!9v z(J$^YRhtut5|@*3RPJttpI-<VMe_TQBPTI>rWG#OvYXG-hnW9c8%>OUU!{|?QZeIl zJU6;a7@p<^@>#XN%+_hau;uF^RM89|>tmm@Q@_;0Q#TvPFp&biExNd+x|D8-IfV<q zW-)t99)nOiLzW*>fjx2h==kCn&2O=SztfwUp{6)cco~cnJvZXj%0+Nx?=UG5WP+WK z8k(5-;jBg_flJ6W`bNHstUeY;n!gz^Y-$)*4Ud7+-v?pJ;*<1+?N_Ge$QkD4`k!o5 zvk8>@Dbn~iWlX<KDycuY3^H!n(|+Y%6u13J!o$DNkjY>9+1@4I{V~cow@B0Zy<5OJ zP!BgO*+oJuQfbYCCD<6hl$91L#$QT3G|yL=8~qZ-JLW%C>^zP1H<LyF@VPwMKNoN? zV-;O$9)cg32!WsF8FHtN&oR#R!m+cjL&yEoC_3>o=@O{J+|OYUU#G<_D3gZoo^@Ei zFB!L$IYQeBo&(k{4;5z7n0&v1C>YP@Ubl_G19H;^m$KhMyx=IL^czF>tU|I|z8z-V zk6~<t&cF%rL|E^0m$@IX11&BVvt9<4u;J1&@=rSq&Iv8y*}FzK{-!?heJ)GqPaR^` zF1dh#2U~Gq@GSV54$<Hfb75>i4jUY0LQZs=@%@{4oVI=qEDP-?kD?tw{jLn^%)3Rt zVX45oMiqAMnhMcDlBl>apX(|PB$JolCwd_h@XEF_SXNyCgHyJlh|Ov9s(rsOcX%q_ zQEq4dvkRabr{ClB(;G42Yyp-1V}&jJUU8Na!+TKAqRK;6l-aU`l-~=5O$WZy<2{k& zl<^ME!f!GfKK93%-)6w3tN&rhk6c)B#Gf46JW+6R$2t<3_Y5l~3rJ|N0L~h$Ajhrj zNXAt+m~J(Oo;b!Z%axof)+y>BDGuZe%!?sJej`k)N+GW_&VodD9&|P=<R&$lkOQqe z*X&3E4ZrBX9HYJDd7=n@-p=Qda+;{rkxv-V;t4wg>QQ#T8GA+Y5Z+CT;X8U&#QBCe zp0V<yNi9F<Q}?@2w9|}k4=H3ybw80A3Wd}o+!g!gM#6>v2I%?av!R+iBVG}Q$q&_2 zC~Yo=|Hkfyf$n=`l}8~tQ8OD~o2c-4>u#_Mj;EEJBi3$FfWdzU!F0$4>k>S1t#=_| zizebtrwTN;If<SYw!D~N5}j#SM&0)JgYRQiw4T5)C#|Q_mHpl1ZvF&3-5)`B<{99I zP4(#R`;!{yi{sIY&ZO2zjkR*Vg%Q`?!AhivW}JOTN2cn*_PRE@Y(N5((st9MH%u{p zVKQl1s>PZmr9+hY5Y4@HNKk6k#7>Kk1jo@;C~l$zW6H0<)y<Dt6RX2?lD#T@bWsvB zMEzikQ8JXock}1GY&<@53-@AR3nbC8>@z)cyk2%5PKxnfs`2Vz`aF%9uNDWDav|V7 z$iK_CUItI&>-bJM6gp<9LibPzDPJ=Sp7D(3$Vzqmv%(UL-c0B2juntY&mBN$g+Hdv z7ZS*xZ)49VdEl|%^+XWH(bxHjw0w99DEOz6&$HDkRK{r`-yY%pHeI+rF%H~{UxU7g zjNrwhjj;RkOu@XA)A()8R9tyj9Yw4i!F^an@Sr?{X?}GLGHZX3g{qR|pZ72hdGLSh z%awxkuZ<{P@SSIXkH??m(iy+&lAPzoMX<q0T(G((7*d*6!te7d*x|FKTvSdE@sMtU zJ13lJL23~_S7b-C`JBl*!})MtoTFj9KdW!%cCvUW@B7?XK*A5`l>ew4M+J+%&<YP1 zS{if^W%DxW8#jM}>LZQ}7+yuC;Q91Igc*Hq=FR%tdrsrCy>NMMKizhx9`DP^bL4jv zG%UG?4w^kE^87YYs`?2%A?q-uIF?MG!~23qJgL|Po|gH=n?x5zK&9k<Vki`i`+Tmz z&Uq(Dy<`r&<F24U@+;lmTaKy`YJw{he6YXt8T<b1LcVigDEKR7PyY;!L$}LkF|TnC z2~~eXKgI)bavP7^joV0>eIj)%3C7iVp>$36O`bQ*;K3~#5cTZ=5e*T7dAEA$y2}9& z)b)@=B_d84GYtph72xo=SLB*b5Yv7#g1COTM1|$5$d9NzR{yzZMGD`elz4TQoY=2i z-qvh}=I8zKWz<W0yXZmr;n8;dC~8Rp->cJ>+bnJ{vc`kt4LzWmPO_(Z;q=#4Y`f4& zuJETPRBFet(aKL?!jExyJt+cmZ;eAq6(fw^Y)BHNav)#kEzu9LfK~Jf$hO6BsdAbE z{~ZHl?zK&@&4T55YdV7R+j}7Fs29!KHAs7AXPZ67STfFBg}ss_$DPx6CpiU^@wsCR zj(^}tm&9F!+>c_A`H{~B@Lb~5h}+DB<Q)7lf|QvnjpH@O(u?}z$?Aehz)Wc){sq^l z<SR3n**b^&u_m7xY}kN%9Glopg*>3<=M5|kxQGKr{?N838GM*l5DMYD<fD|Bu9C%_ zGgx>+;=$*iKE9gxj1FY%MaR`!(I~={+FTq@wbI8?>ksiJnk&;O<E<qanI8nn8r6`v zbs_6^suqfejPdd6CQQFM6MSVUj{W=(7HjUolX)>jORN$aEmxuSA%LANXGzeP&3LIz zos7S@f^=F(Kt@nCSzav6XDS4+`$H+l+>9dn3;M8mf;-lG$q2rRCV|6cSLk!_r+bZ3 zz*$L_{#%p|2OfH(amNE%C>xFU8AtdyUI9;kj-~oj!tr&~V%VW6MC}@%qPX>WkhcF# zPU0W(rd)*)-!Y8~@O6O5Nu^|lbR5aIY(%GUQFvw4gH!k&)`Z13={>a#;HkzkD|v<x zjqN3yewxBQ{tPW&<B5K6#c1b&$?#fu0q$>|g4KM6rRmT_=oNpCpEe8-NrxBA8X0l) zt2{zx204+YORvyo^I0-?t`sMi`GV{@!oN4ig>(CNsbaPF9mo_m!L_82tgzI@t?rM2 z)zjm`XVu_j4Qa0Kr4SAd9~VSSOXa(yyUg3({O0HW4mj|thS1mz)M1YW<ehoL=Zu@d zc->7how)$}TB!N&Se^}is*z-rKV_<K27qBi4OP07j`nHq$jZE1_-dO7H#s4bEPgwT z3O}>REF}l7UxUvf*IXi>mWtu$gjLjGiXm+6w5Kk-`(@r&-m&8{k8zqLi*-^7Sfby_ zzTjB{lO|qgh2FN)3FG_me8X9?=#v!;9qFUGU+pWpJ~x7Db1JAFzfEEu?!~?Djo|rl z-a&KW8hvpq7eBv=fg|?oKzzQ6K<!2&Ce6P<J}7>NNQ(`S8!QV)@j7)-siGR<32bBg ze4IOX7#){B1H0lnG(6eIPQlZ-^H3!`chkTp$3sBeNQuaKh~u-HH%QDe0hFZg<=N78 z7#VBJOp-bZgQu+_VyZeP^CY=E_}yu&k~&MKuqL>1l`Za8oeGa+BVgv@HWIqf8b$Z@ zz~q+O^huf>C*9KyMd5awu+c~MmsTS6Q<7puUPi!{@D(V1CJK+a@b}VAYc}S}Z*qC} zdi<rZ87o)vGcWmI(8~>_R^gg(RmlSO1TtuNW(Pi0k>fv4?$DVlo>A_aC|A6DJarc8 zp~?~M=E{G*V$$kvyuNk>-0XjmH=4#I)JF$a+swvWFOH+bk4Bi&ln2kxE}$3sreSw= zEi>TD_d%ufp)7k6@zHroU{(e@YjzwhT|9vk(TF74%@#P2%%AT{f6|-wN|>L2pS(Na z4=0y<<C3d9(<V)art~@Dkpwj&Z1#dA>@Ot8?+jBBn>18Y&%~U$Gr_xZI?9i*WU&>0 z#;yO%_Xq-bjh_odFZLvhk|NMCZ7$Y}l)-E%9b)Zd!gCJG>FvM^sJ`<SdL1f--Mni{ zygisYeE3Z!ByTs5I9<$pstHt2Fn}F<B4E(xG`X!Ege~5c<l6Tqm=x?mb5vqsb-XiM zBU{D>zfQ#bT@UHK%x0!%`c*v4-`%69MWgbQAIvHDXT)GM0v6Q;)1XCx^xiZ@?zpeA z;O@<2ES_XY>=ed;OUQL{^N9<lHYI?HZx?&JG84Dej6sQd6J%wJG5170v$*^LcICb1 z*&|ax=SLDzNiC!sKflF*r|CQ={Wxlu-o^D(%Sq~M9oDn49*p!#*(bKuG$ug~e7n@p zy+aL!>+P8As4hG^?TWdHtP+<hy9E}FT*SR;v)HjEH=tlcH%a8*#Rs*mA@Jlbx=C)c zVB72hEE}>zyO&zH^Na^{>}|q>6JkKB0N`I;6&T8P;8{MKxWUW@Q|uqn#>nZA)mqEW zHHwDc6@gU4c|1&i5Q0UPqSSk-uAn5u0Dkec=S10spq}vvlAAXY(<L)V#D~{>ACh;< z4y}Mfk*n0+Igadact^tWSu#J~6R!BohcPDn%lnTwlwSKn+O(HZ%k?X8Z{%*Oa2p|B z-4EU5{TZKJT{1528r(j212%<=v%8wZ!PVpsX<ya^<t|^*$EJ*l`%@18Ud!<}G9?J4 z`6SvonA7&RfhG3Aq`y*uo1}LD{@nNivL|`p3ZHj0;xi1}|JKpL$q(uDyGoFL)sbto zIEZ7X9LFLZf10z>k&Qi=LsFU#<H@7)@a$YLF8dP(2dB2s-|NGuo4qJ!G3zF_Z=FPU z%+dy*3}<|^EDk(wPvv_`vjxJv|3S>VYiLyUMwpkw26vulNAWMowi?!JEo`)%h# z>X#^j>WEUO+L<&ZQNCC21;-R~ARL95=1CN2=SQ?Wa}RTu*pW{C7Fwn=h?Y(oxZ!{n zZQof1qp?!hrf$joJDCYvCZ9y<q3d+@uLW%6ohXouoJV7x2H?l&HTZB%Aa<-c0zW>E zCzEZF6dVcVpBpWvdiF|G7CjH&l830Yhcf7@){&JR9&m4?0d9OOkIh4Iuz{aBS*?7; z+!E};-H$BMU1zf(H9fN8Kztl(C6thBO@9akEW%9Tx7hvSKe~9p6g56*(*N=+Fn9Sq z`eyh)nB2GueRXr8UNjm%enr-xl3ybvq{B8xerJ`%@cjK?S}$+T)dWn(zWa+|T&p2i zr)-6K*<G-_X*u6Ve1y(xml3ahf60fQTg<oRiEv<-84N56!gV9<P}P~i<lAe&8>L80 z-MT@r<y|gaEqoEu-+aZ2spnypo&kSf--skHocI;rA`is0aU{c&9Bg|EF}tTy;jkPU z=JEk!CEY+Ob0!J%-Gwy?mhk0Q4p`~Gfl4@rAtT}BdVh7f%~sxh+q4kUth(qD+wagM z<pNWqd`Ru!Dti5LJ5?^*j75*uf?7>4k2eS<*7q_|jn@P=`-BTFznDZvx4g%T{Cw(y z@-57}JqNc(NT5w=H*@j7$z+F$084@&!|OTQKzUCcya>*P+xv&exz8y?N00?#3uE!v z^8(c0H<s&t{txzKx&m~^nRSW>g7o6WWSd(jeY8H4?Ax&!`g$e{3g?J$rnCD{{=#{( z8QQV)t}NFWYXBbg7ho1M8II?qz`~Og!KZ97XSZ%VJv;D%F6w?p<t_B^M*wC0qpbv9 zie2<ZMgSJumcY)X3t_hA07$%k!t6eI50(-&qSu~`<#7R+k>v_M42!ADZ%IL9+g^+c zt4E`i6Y(g|{0QSeH-7b<qGqk}xUKpxtq3f{^^gDJoZ{Uu?-YM0Q5C|JN;^<!m4lhH z=ir}3(r~}x2W>pl$KKG00)?j)P|vM_`RnB%`ul4<CijBWG_;X{&I(u(k%1KtM7XH( z9Gs@LNU+*749z<%X+-aJm@hn2P;tkS?k!Hh*(1C^LL;tXc|<(#itS-1EW1K|=ZHbM z#Y*N^&PLpup@_~hb5TNF3NL&pA<<g9sAZfvxX)UM)*TDLa?};hO*oByJGbM^{R^Sv zwHbJ<xIs0WMTzy>WNa<m4OR($<mkW&?5|veQ!{g^chi`P>dxo1TX_OjE|Q>WAGB#! z=`A!5+CduoD`?U8GTbRN12t5(QVEY_ru+739PWHee=G{-rm6WucUlt}$i4_Cw9nA3 zrO)_XPcNOcuLh3<9mb02JlJ-B6Zz#c2gU{V@L#)gueUsgA!`MgtG$mr8V$qi8dC%~ zHW_AhKB4Q+ti-v(5wx@|i*$8~;Cz7!7hiaYNi_aJPt@N-gD?B3TmEjIOT3v3O7p$; zDg(;SdBc9Yx|%p4kIqlMKr83F(Lcv0(aMnxM9+H`Nax0|%12N0Z0RUe`Vq^t4cw!l zCLy$SeFW=#e>v^>&mBuE_QDa<ec)nV2CGYBDCc$rAN`4?R>H1O;pGkZ<|H<)DW|)> zc46Hv2ANAQVA`E2*fM=H6>XkQX5cjXds7)nX*vrFQ-<M{l48ZOg|A@$Ob;3+c^Olk z$HK;YEFPQu0K9qvaanc*Ebq^T?;kyIws{NLu;;0H!h?9qRZb#S&BJtA=MczuAlV%} z1N!eo@;`bG?yJ-WXTvA>Bi;eWX+6g&t_cvjQVgPZ-=itF%EA8IDzx-#1=lmS*l(Ie z)B4__-n`G`=wt^x`qGM-@{P}rD%~XRMjiC-@CV#H`5b)n6#@6s1BC12J9f@fxvT}} z;k3mm>QhrdUi`j@j*K64*xka?m_SmHdW-5m@BraoT5wiF1Ka<Z@&0OCVz6ZweYzwA zs}IGH?od^5nW=}uIYubYXEg&MpUnQ4j3&;-WSqD^fp!sQ)p1++JCaW;+g_nwxhc7~ zi^bz|y5PR^1M$zd<rLRn#Yv_-@4+;es+c#D-}y&q(Q0du=s(Im`*Ra7OjG5ob&Roe z%4~tlCrz4O8^S0a(M12&Xu78EF)1n|Y)yk2%#(9q&CfMJ@)c#kZ70ZJW*e;tD8*#! zXE1K~6C)WS09GY~R$3U~dSFR-UL+chXmZyD`-x5DBYgiRj;vq5ne!G^rPDu|F`}MV z*weE|>8dgO9OUs7?CY$7SyO6A+<pFeiamyx)~&?EXGOfv=oifuQbJ#sJ?y)y$tV|K z52|fj;oA99I_%s<hK*l<-|sc>^k4|_88pE=wL}p4>=PAts%3<QWw{Sc*MYOV3ku`p z1WyM<xTE`4!pUy~px|l?=PwyRr@;~W_>&3tw)ip8Ix*;Aa}`IXRDp&PPd{?mK})hK zaPIlv5aa%vUNMY;*XG9vKYhc#g;OXiT|x?@PLrzzMQGL&#>5IwgI>G$aB_?k*YWKt zeR%c>o%2!&^jnZV4%fu+-gM%wD9`VNH-d0-0ROqlduN-@(JeQUI4P5tARBNQWnYPq zsrDDmeM`@hmb)jwDQpoAo%ch#i{YRYT1Q=HUM1eyQmDr>p3X%Kk@GUCnB;6t_B4!# zj$^`bu)+>2Uwx;04mx9=-(K=yXb7Uai}6@~0-0d^f|{(VW~GjN!=%7IY^g1UhI)P` zbo>A_O;!pV<AbQ*mL2Hom<7!{B|yYaykazc6F$9hnD=)G!E&XK<Vd{&u`n@#Iv0Js zvoMwp+8J^mQs%;y@d-F<Spq0VuEG4DRrL3%qeS6!8+b?%d^5n}fqRdc2jz+=uI0>k zzpj($a}wY_Aj_Xu;xSP@4AVT#Abjc;{AANi<m{GWuY3v>Ylz@|>C<7rPZY;F2ht}W z9Z|PD5wvw(skWy9{Cp5aZ{E^GI~l%*J?9HtUQmjCdWp1My^nsh%%zhWuYr%UC#;-m z$Bgp*g7ez)kn!#k&KW*Kf+YCA^O7V+#5n{~KSk4i;R41XD-uJ?4${(lM``AVdJG?w zg*@EMB)a@18b<xpOMWRl*l`r=4m2=9<1XWt$T%1$nv5#p7pQFVDbSjy3!c7f@s5)_ zJa-t6(WmcWWOF}FT=<(}rx&VRv80EMKA^DXM;P~$fi&@@B<V^k@1ae?@>!X%)ad|w z*UT5UED47}+q8;h#vkF+V_zJm%~bQG7g*=c!=E!fY1^^WWU*2!y4;-(R<E_ViT6w( zYg`(>s@K9);tvUton%(zebfz&h70rNQ0qir!CG$_ZfWg#`sIl%R&M2Y!t40&%P51P zdnoiCP69@94StUZMN`i}`sI}kni~Hl8wP}7e0VF#u81XB2TY(wPL`YCd4qiT+s!90 zj$mD+DCe(j2LGwa2xf|y(Mg9($<WI$;L&Cae<J6BgRwDtEV+<rkrV;f#YdP9J$=TF zzegl)69+NV0Fu%>2@X1_gO^n_zH)FPm&EI!|413C`+MU?o_o6HWf#!b??KBjfv6r( zrt>zhBIXO9!_qbVyen8h6{TchR@wx?dV@VM-tY$bvCoftJ-}xyez=->2HwSe*?i7Y z@Exv{c%k7r4J>Bfg6kz)D*Wmq&HLa1DT>Rv7Yo%e>Y@n_^h|)mJ!7$Ikp~S5DrP^8 zaRwj0!}f5`Abh*@h-{Y~VZ`i%sN1e~>`PxsY%7D|=a&xpM&AjBH{GHQW4=Ore+IY= zM`QLBUpVHsibPJgp*thqFoQ~kXcKx0EmK~R%@3tWiNaZ|ee5XM@!gqxOV@*=+P5LK zbSg19xEmA?wWDtDXZ*T4oN>1Dq_x$7^cC+}Qc=(&hLX~Pa5XL7`>~J<42}d-u`KGC zELP$3vk2Cnh=k?Z8}N#qDL!jAM^=sZdYIJ0?5w?{sVRc?Zw&#b*h6G!&;{dlkHMXn z^D%jLIeGT)C-JD!g0{g6v{j>qjz8uGJI0Q|=?_`PGF*!1<af{+Yj+7QIo~Hocofm= z3LEH&%3;s<B~h)-Pw--5E<I3Vi_XLRUfnGTl^VOLq2(#~{mzUYw|WMrAHTpA<G=A7 z$8K<!i-4_*g>bC<V$9AqqaEIhxDv@AD#oA56xvG39w%2QINd>aldojA<OdAxIZ0d> zvt;0>F=Y>yL7;jNRC_yN<@A>jdUqy19QjP1h%LpJ&&32Qni{CbgK047z6e)iUIA)a zqr|3n2F{afVfMMsVRxHb;G-W^REW<8$$ec-71UoaGV&~HMYY2t?-XLox#GMYJ`+6S zCY%iEhhCR)cx_`O6}_*511@o}&^?1}{(PTSoOl7*+AAUMOdWmpQ6IM~T#Pj<#$sfO zC28r%LNaFzc{2F{u0J!8EA041x(ypDnk`OaNV_O_?);6aE^n!r_kSoip68v5bTPH; zf9yO=gn@cjDBJK60(t(oo8uhXA{5GwHVa^xM<%}ay^L>H^rO(Y7O<UqiL{%k(kpit zLiE)nYM2s*RnFN^x8NfYi&%tiO^;AVt_>Fj50GsWlsMCw4fOhhNq`G>fM&2ZoVs}h zBCe@}c8VBgujBWfsgk()pB)jiUV*s<&J_iQs{}5mH(<~bA6(u482Xg-q4B|UNDaM6 zOj@ph<<1~7V%3B9f1k(edlKQeDxlNoGibk%fFTw4(KtvIA?qamRJ}%{qG!X7>OQ*m z_Xm2``4VpEAH&sM_(*OqlHiPcHegTEc39~wON1`oGrszFG8i8GP7BWzR7e+OLXpfz z*m<InjNzY4f#!ScqCISqkuLm6e+tUpc{o!d4}UJXh~9Ok0^zs&QM);nrpx{XrALke zOXV+SRUdM&wlEp#7i}tlWL#S@gIVtsh}zWz&R=`PoX`xw4Fl_N1MhzDwl1cN@+Xk7 z*XClH_!Q7@;<LZy+Ry<dAg3__j~N&syF>!QCVwS6dCtp1g$hO|vkcGtt^<eczr0ia zCZ4-B4QwqOP<DYPZBjl@N4}h=YKEI=Ud;yDEX(JBL?hVN%zt!W)?>UpwUxfS&+p`J zXVD;o^LQ%ZD!u67$<@7ZgsMS9u$T6Ok8?OWcQ(&(-ZuvI*XQ8Ux<}ahFbz5%ijc(v zh2*dGLs+9K;Lt`+P!xFp7PXX^A2lwZCR_9c$NDNkK1%^5r!K$=<R6tR{7d>D2%}_{ z43{LF#*E3)=Gg?<h;Q8Koc9|c$kyF#?s8w~`g+#P%6>fU`BV=FK#Xqrw3|k_te|N{ znpC3tAU!njh%6V;APaJ~LHN6S*jDo&Rb1vltu05`_aYbQ&ktcF&h``4Nzee}!D6y% z_XVi#SEpzp#*Jw)B~twPSa6a6PVQxE#1(OCP76-Un~6sCmV%*$MmW~el1{m8OC0ys zR@^F4=hROWLXhYvDBOEWO#E)b3lCvTerASqepo>3u5#35j`Q;iKfLhYEl^>rA>K6x z%hMK+Q!DeS>-3Gx*a(hQ?aISzcRus1O*PWU^Prs#BPpL$$F(=zL7|@Fm-?GD<B$s% zla~Pl9uG;;qeR;Ass=<tt?(u3f{i5xnCJ41$<qFg@0_MGo&Rk`@ggA-bR!f;r3cJC znmAe^Bg}noC<2)=b6~;vQZi2ZDyS?};+!9rz?2<*)TUU6n4C<+XOB|ANGu3lcK#&$ z3(cvp^fs7N*+*Olz3^+94k+07RXA^LqWRBwSFCv%N$=rz|G~1Dbf3??ORWK?StV?e z^EULmd7bQ+In6ZjyV#@LC3uo!fRZn&aPdDg+Uz?IMR!({Ubi43&lz*(w_EY?Dg!uw zJ&-CL6@tg>nuwoQH*p-D&P|(i4sV1>aX$l2pwZmLV3He$<H%j}OBLF9_{cZ1dVw)1 zteZhh>d!OI$0Mopao+wp5<@2X>eHOninwj=E4(b&2yK%Olf%FE!lc{HRJ->)t@R$N zh@7z(Jp(1Vk7rEyTtg8?dRUPBZ5z4zUE#!a<sF9nX=ldu2%)EO18x47gnvG8aHi=V zs~#3h4F3fqmH9zEB6x<+=p4)rJC1$-RhdtG?u(mE>|oOK*&x_aMZ4U@VD@QY!O1tq zkl~g^>*RFspRp<L!!W?=tw*W5ktO%A?L3GIp1>HtAMh-_8!cDfBPU#%!FtpW&X)Lt zPOm&pE?UO3*~Dr2XDQUT+JqBJ^Py(b11$0jqP;zLP++PexF9El3ofTYU_}lYd>f2W zk6qDfSq#}$Dg#yG?wD+HmiaUH6;V@s1$R}&xnS@@ul=$ZdN2^wm+SCe)#vooL07W$ z!zbp-B@4K*Is`puH9)rokfG2Lj@gt4b#oT7=N8Mr>WLCi7$pMT!H)dwMGmj%TH>2F zXNY-ohgs2_U!nJ;nR?&dhU+8zh**Xt=O!IVHe0R$Dxtu%-?qS?FRf7V^CrAwsmc7c zeFf*zdg(GlQ@-O{K=a18FkT0mF{`@}eKT&u2Fn1LsQH1t(R7;8Q&~fb&yK}3+vD)0 zLz|TC;D}Wh-!=2t1Cf{co%oY4WNDN%6S?{zd|iDULv{R^+6|iAV=a9+rI-p6RFh%d zT{AqMd7nldEoL@5wSZG5K`%=_YvU0`S0-Jdrj5Vpv$W+zXQvJ^3Rb7r?w>+s-a&E6 zyq9$NUB+2?4&av^PVQXesEgkYm}Fl@?D(D4kG(Q5nl}~AEyF=)pBN4lh=RWFF-FMa zZpFX-DRl7l8)zBM$8(QHY4k)j9NqAZO6hNb1H*B!yfB2WecjJ2NHzg0xi~Z}Y9JEP z<><q;u(4t1V1I!>b&ahee*@ysN_G}GeYSu}4k|^-ji*V<GD6lKRD=Yx?byk87*uEk z?y1*>|LjFE`0`jN`{9Qt>RmC+iT5F_Q3K)s6!2zH3@pIs^uKMqD{s)7I@fv8u$DVC z)$c0P%~IT?(guwmb)dk#j}dCBM~f$?aMQRv@YoqoEMhCs=ST!7+|Xg;)(=48+cdl# zgVc7+T3DCsiY}ECD5I-S4)e-|@kTpAFw=<38hu4-CP$&e>m8`2*hQ{OO$VX-Pw_<6 zI%xQs$NYR0CHSm5nOoemf{vsXnV0lu!nbw~O?tkNbygJ+bLRv6JtU7&BoMtun%Ps* zXYiWMdMM}5>c2Od(?^|tFnV+%;OSgM+e{L5;1gWl^_S|*>qkpMV5*;#U|-5BejlF7 zyx89Z=9`wmJ0~@;_c=u4zptTb3hM~(V`u%}h-0^g0a$lS@_VP}B<Q3qeEPi$Hu1kp z+hk?h^tBL9{5p=GNIG8rc8V&h{eZ&zpCDhwl}zH9Bo@DfNrG4#^p$s__^1SGn(=;& zR#8E8n*j97uhDHa2e`c7q7YXfM+>`j@#xt)W=ZLD*zpo^r_L#=u<#a4`r*&VRD0;X zxUFzle+Q?R&_nAkX3>RgFA1)a<Ln<8(25H&MD-d!BPY4IzE(tVG0~i!_@zeIN>2s* z&mvsY0V&Y3Ne9NPghr{yK-rSF^z{?I<3FYZQm&dH-$;O~=BLO;zdtl=nJ#S>+KWy1 zr7*PozWK4HPG&{%D(oH~CAcdQMKrC-iOsYgSR?d+sH@0=>ibHRh-kpFSD%>1FMVc> z+vmYh-bUQi_mm7q$O$Ao^wFEq;?!*dK-Ow|#nzlBtV+v6;;<nG0=**ey!~&w%6}<7 zc{u}t{S14njG*P{f0U=Lfay~YK7SsJY|=v5x6KJ#AC!@$4ThjPRviMaXp_;vE}CyR z4{S|^ae+fSss2_*4b(01^yMvrIuS7_j=f6H-wJ^%4Rh(epKj#Z*amcQ7Qvt=OHkQ` zP=$LN(K2~5w)V8ZoV|}oS#k%+=a1nA|JG9lzju)Kb}p>Sc}r!oZ`1XrI_4IA^SLp% z?3u3;2T6bNL6T9s6rL|?M_>6xq+g*M2c<SMem6LBXUjF}B3}by_FLedfidc?c?5^s z)o|@30l7Cr7-x-WQcQb5XEpz178QR$sS}y7t9~LlHb`N0aV9&JC}8k{U@UK$jZJ%P zK<TqDd-306bIGO8urQ_tTD1y@M4>d!_#p&+%V&a4{C8;mGXd8hnuZoz2dLPqOr8Uf zOtV&mQZxAoaEQ|dp|V(1{GE>ZZ)RbwiYz*=yw3#ijJ4Dmo>W044?R}a;Yt5i`Z@C= zQ~CE0>ZaO5AfL-oS@?=h-g^Qzo{s^0xg`}s&bLW)i9E<1T1hRS1ztKGgh`IPKUzf? zCq>+0MgouG#r}L;Om5)^ue;!-ewL_a9j6irbIHPZEj+#@4c}j_21#83@w`8u>k3T8 zYX0+9%+8%y{TAask4=MpV`PY7UNM}pnF<eTec+=C%QQCWfy>)Zw5&`L9~kHYwyngk z`Ff;(v4)^}t`d$!OhcI+_rW!HBlw5k2Il8eGVy6Gj2bnNaSh*ae@-U$)*gg3lkq5J z!F$U16w`~=5}b&i=?=F5{IuvE9sOVh1<PNM@y8=s<@-}m=z%m>vL>Ho@f_>R6K<f# zfH$oCQ%k(1<l)a$5vW*SLyJDlpmS6Gq0spr4BoiGtXZK8r7o%X`{E@=(S*S9zc*lW z2}Lu5v8X?JFFxkkw=X$m>>X1~XCG1(w7tD0Sa4g4MkhyO@5*d^_s@aO=K1VrFEo(; z&+RBRV-aX*jA!b!y)i2#1T(i7@?M0KRJtaxLM{3+{VQPvb5|u|YorLwsa*nnLXtGz zD2bZgJx3BW?vk)q59m9meA2M$K5ox@34z;7NlP|=Rwzy5bKWK>UG2|y#Ehlf>RwiZ z{$c$eAE$RJIc#0OgxP%gCe?gihpT=LvoFjoNMH8^REqS$&ci?GP-_bJOnWx4c9Y=P z5*v`ok;RNNm*CAFBNQEdNQd&oxWs`~p!<Fndw<DBsxF=lo_?C#=<<yM4d)=(@KTaS zuX#;&xPd^|<}Fk#>7}Fnx_E8DAkDwL0B&axn)k08g-!Iyt!TpU+%0jc@O^4GQNYiv z9qID>^I@mVG2*&(0c+bUEYK74WM>}=G}~5KR#6?ZoqcfaFI^C}l5qWMaDPM@A}b70 zTv{7H&JfU{sc#vjB7J0!Unfg!yJ=A3(TZC0Ic4>4(%|Fb^CY8Y99J*%oU}XEldYdL z!0AyV(cxWrDw)xk@Y4amZ8|K7&{f7$OZHJOD@t$iT%z{a)tr8P5mYIE0@s42kon>? zY?!<j^SB~5<qZclTos-QwT4;+OZ@O8ALcR-Aj&5me-6n4Eq+Xe=NME>nI+7-WGeBO zY$k-u_|pP2I|vL(r_a2<;}gD{qnuWb*B%*C;b%9v#E(JXJ2(~=cURF?lLm-uH$_eP zo1oU3!cN<0506%U!SN$`G$Yp*pL=;QDOKC>j;9aJIk%3!H|@aIt-TP~`JHTym<*n4 z8{xHa0gB`_0_8Js9bx;arBMbN`=&x@gAdjpw+CP8Ev&txBwP)CO*+mrV<1~bDqGId zf+wZ_qv*Wja(dr5u0<)@Mv;azRA_0O`+Aa<R75hOh=e4&GMluNc9fQ+j0U25&V8Lo zOH@WAkwi&Ie920`^ZToRd-dvh&ULQq^LfAN1+7i^Wmh3tH*pK~NqSCq-WsNk&Oga| zsb|zzNggfJ7*a7|1x<YA2IJi?!|`?ltZ2_ig)~=c{`VRCEu)0Y<*t&;KbCUaEnZ^$ z8$)ugAe&xm(FD23Cel8?kuWntP<d!CzSI4V5xwPjTJ1Q-ILzWobic9_pPi<E7idD$ zcuBHkrWyIKUl;klAv?O6_mAH-!)xx}g)M4UctY_tX5FmAgq=O4H^2s-D2t)axXWx! zP#3k!Ux!DY-^ANI_u<90P@MGOy7jj3wVcR(S^hI@&VO&a5x+;DsL!_v_^2fkOP4)> zXVV{0LytW2)@>ZBERv)io%NK=4#j;;FuI;OOXq*I!wMT?Fj(}N3}ifFXWj@T7H!G` z`#eKf_ihh9kX(YqUP5q(&r8o-D2fwLt>YHlJ_m0yZ^CK5pE!>14b@EL8TQFSh{!zv zTVvDUXNWs~%F^WdO~b-=wTbv5=q%rhNdfZ<LM&=hp(B6u(CxdTAU5+Hy<AidH(rh* z8^m;Q-`qPmGwBkky<-a5zIHfu<w|BN@|l*$r(lD#G#6S|j88>)X4Ro;XyNCdnyMK3 z+k6*uTx1^eI8p{YBl(--oBJ^H-&ZncY%ABAdJqCGRFX3&3Iz|QgMV5vd8ZfxYfP(X z^#=!Rsgr~X_7E&qE~nP6qfm^`MSqZ-N?eWNx$oavh%Vn#i`%b(eICs;peG39wDs|2 zUNIf~-bdbiJWtli9D_0Yo9KSmpX8iU4R)R7#dFSu@L5s;dhbS3E@K}ZoiG=i-A>W$ z7k)7Dvk&32mVr)A05u9N1W7*M8sy$i_I%D~doUB!_O8I1T~*{t$UF44G=>;=Rl%f% z6qL@7(A^8~Fyl9rvo-HeLdio9ESXeJf8G{D^`N<=zNDU>z1T}{C|{<!8j0+R+%@Pr zc^Z01ITQCg^*C|pC`eW;g?64z`D@B-2q|nND}L(Z{LQD}>P4PU@HK?*Z)x)k?Rkvz zvsThBHI}{cZZAk@-Qbyir*Yz*#W?<3Gj%i1r+dO`NO5!otd-=s;=^{dAJ&6dqX9BO zGeIowKCWKr$4H&Y1t%vNES`FXoT^F2j74=svbdW(2szF7zI=%2q*A(NFOs`cwxh|z zc=lYR8BWWOhP+P>WNGpka9p*7DxJx}wuC-1Yqt`)wCE@^UckcmM+x+cr3Tj{>OrIW zcTnF+21H-KS6IvUsn4Bh0f~S5V83z{DM&qtw_XvPZ59oCdhQdGw_=>X$|!IaTSS)) z3`4b2Jc=wPtdjD4*!*h~e!FplnERb%7>|{h`zRB}lm&4gXFD<%b`nf`t&3H0HNui6 zKj<OVIOFGcA|Zd59N8Ktm|LgIRW{o4`QAYiyE6^!W?e+`O%1}X@~q-0Nx{$9`Ih=$ z4X~;8kI+>-9-VDIfY-do?6Pry4$+2!XBwx7RPH=Bdbt|AG`b&ZGaMj&=0of{W(vQ? zR`Gl{C7gXOo}T0H(LzN{c;>erzR3z`f`=~oJtKv!JtRwKThGTs3O4X4T^4q&e?Y=U z+`-ad5A3q)$H8b#To!c%q!jPa$`&6~oS=!ikyS88@B~JZy2%Gpga-~g(#I~f@Jq20 zzYn@%r0GjgrKxbiyN`&NAH`S8g1Av5i$Q$00rF~O$m$lu+PpltG5iLThoac?O|H<I zkWHjl{h&L=>q!5o6wa!Gqi=M>*rPrx>2p<HuQN(RsJ<zQWPYOHC3+4QX1#z*Ma6h@ zRTtg-QwLlm+whoDD=dqOfSA^cG}8Jee~*}e3F)s<W<e6n{S`^yR{Mk1uVAwC{c@aD z_LshE6w)Sj3u>cG=%>;bjC|f@8Wy)np!;wEyC~3zG`lsy^dtPP^so=9^{mAC@nP6& zCQgg*Z6Z_KlZBJqz3`bvASvkh2=l=O%{`uBn8<Q?Bma#_Y({3jTmj0~M!>Q04*1{k z61LmSik}tZ>9N(l&{16lp7BA}1vTlw-Je9n)}FvT_Y&e4xCviu?cmoiy=1^Z2b{2n zEV?}wgO|AyZKKt6V(=_*wOoUf70#let)rkauaQi>Kf=0*9)zrPapA~Y0oZr&en@v6 zyyzy0<5iB(iEU9x9w}m@=`c)b_5z2)&mhoWhl`a|!NIC>c$wWrBHN;Yo}J1nvB`|J zz8aVKaU+?rJch`{9%I7AEQ$ALQEt)WRARv2*L0I#(8;8jjD3*K-W#|CL$(?)VM-UB zE))|SGoo~|`8f9Yf2DMkrvtZ39_bmYeRynFD)#){3mwS<u-asb`mg>_o9^}4aWfqq zH_S!sv4n!BG366JO(3b#6S!)RBJezxL)J2-^xEYR;`I79mFD}4&65_>Crf7IV%>K3 z*O`@|>vI?{TiDXv95w4A+a1I&;52TK=P)pKH9e3m6jt!gtB6VZ=rxwl+w%LoLxUG+ z`l{2UH~czr@o>UksR#(0T8vl!>!BCL<_nTt<3M|N8GEF*pC}nCF=FizXfW*rh~8KL zg5Y3OFY?6e`}KrdUK!x4|1O|kUmWk&E(2elbTI4N8QPI%iWf@4FhGO9CD@h1i%Zk# z`jH^+&4h4l#yHe|9!x~r?%)%TpCG<;D|L7<46grXLAR?Jc)7i#+os<qOU$e2>QN?m z$9ORez+Gw)Fb0Mjc;38)Bk_9uoNl!#fY-K1A#ze8NF0Ap4CG5;@yQV)!tdS<`C04M z4jq`WRf#61O%e>{p2J!Fe#n+}(cu#gIEfvhJNR4u=$sR9NP9jR8aPLexk+$&<`)=A z!%<xL_me2F4~IzEBC;}p0naz%!1#bSJ)3fcs_^mBgAcXgsVgDA8tH89RyFGBdx<F; zTmua$KA;uy4a>jiuyZaN5sjxgAmCl?#^?b$Ht8UD_>16a?jriEioc7T>Z8jR{I*t? zOvVTEw5W}m9QSYDWb*AcpJ88K!8+JSW61K~)Z4*Wc>4P=S@>oS*pIqEtfq_N@5jAN z%b_*s_Tnvxbl*U=o;%Y!$v4T721!!D)>6;={GKA$oNldJ%M4GSgAa35=yHo{@}hAX z_Qp%`nNwGyqa4k+m~ia0k*E0d1E0k+C?ap{%&<w}0$o~^f=&Jvc+oG1EgR55FO>&e zajqAg`qhZ+yR;6Ld#Yj1(SCBwY%)3=lz}_@m2jfk82Eep1kJVI#~k5Z)~_%0<7|mo zK~`2Wh-T{XJ4sb|vVM->^?tMe=L$&Rg%Zs9NEn%-<>c+zcZ8hL!O3?Mgj+h+(TxYk zk<dDQ>|Li0zqluK-qf*hr}HKmdD_h!m>&k;lw679xvRW?a20KNC<@`qk?hgc3Q(87 z8M1=P*<A)p!DM1I+D!k%JjhcdVTY73Tvdcyr+E|~Tz^isJy3wV*1F&`sh+4Gk;CKx zS?WK<gisR|bW~qJ%b%Yi>(WPr(}Hzj#Su|~jjS5hh)yLtOCxYgVl}yu<^+39?BH<I za*{j$0JI;k23w0!u;G*(EpmJh!4F>GzlOuae_sZB)bBcUC6~ax9A(syDS(oFJJ5Jk z23_@O92(B?qgyb7`EQOo&N<RT+>Rw;W_2CURpC3+oeo&ovj*=3HgnD<YLM$72}csW zG3<spNGBgb5tM*8yPlDyo2sFyF9W|+AEx#vym9sH&%$p}--)ryeXG%BE7)<y|Iwok z6)@BAG<kN~7c>U~q4c5_HO%6j1P>46Es>jSVe2j2IQWLYF-7A0al6O?`3~BW9BMsI z{u`9pNOEgD+Q@=<d3^qJ89o)HlYb3Kp!%c&pJ-neTHg*vtI||r-};c+inx%|TQAV2 zpDDP8ce=~X_(_)W-G)N(A9Qp}g>?s?L+QLfNQa}+Nk_N>XE*N-o^RX?Lq>{tKW#j$ z;Z2`sMH}J3=zMr7lE}1HH=t_AbM*N;iTisskdvP-0#O0mKzblUxY4wW%s!k++j_s^ zm5s*4#QH70XspRq|IXoi+o!Omu@wE!)^Ov#_=9su07OYEGfxaV>6S6gROIw*{F<=@ zu`QKkopZ!T50lBE`Y3MT5lbu>!n6EGh^o3SYo+#qzUo;?vtm+U+Lrfp{ikotiUJ8L zW1&NK95A8kRxhpBSslWL^k8DU;}Jd6I+`%Q3dumPES>8;%sTy^Bhc3KqM!3eGX;{( zY?Mx~^{6p=H1w_xoAF~Z#};Km{a!DKza%4Y?)$(xby{+J;Dq%>FHv^Grc;n|T_`l4 z-%9tCiDSphvA8pJ8y6pt4zpiKqV*JMY)aiv13lWoPp6FcKVFAF|D~~SHTRM8y;rby zeFJffP$y4at#H;}TXwKQ5sI`+$e4eRF=jz8TE2)y=36T4mAU}}3;x~K?kh2E@k2S{ zPLk{n5-G1Ir00PHeLYjLO8>`lxcndQsrs`BB5nWB^Jo0Xw(wIh*{zgp-p{*W#ciw< zF1~}4zb)Zn(H1l<`$f%E%Sidk8{C8)k<8T`IavF_5kr`JM5J^%>b<Zd#p})s75@t( z)<5RJvX6J6<zE7Bo*D-`whDw_MgeLEo}(RaM`LW;V$^K<$o6K&fTO0m@CJ>7kjW$D zE@>d!e9od^b_(px)c|g8BuN=4WJ|w$fk<&YUYz=p1p4fxpS$>Z9c1xJMh4iK8Cw~b ze<brJE~I7Ud8E*$3^T{fq9cZTNJvNpl!l*&R-Xja5Fdj)4hI4y?di#ro@n@L1*~qV z$Ks2hi2ox)Y+fshQy2~WkZJ<9rJ8h~LlMj=MBJyajBIR_qX~g>D4IA9+6~9UgZ1y> z^U-f)^1o3e`wXD9P=ft^u!&lz=2JI~V3;X;lbQIZoo4WNux$sHKwhml36M|3tQFL{ z>H8pDlj)?~iPQ8~v^w5DUPo;u1(2beOXofOLPPe%;v1u0nw82xtWP()=(7&gd51%s zum;j6hJ*S#8F-u~MSeXFr^mC@G5=>6tUCIR34A5M9bac7b~~YaxDwR4z9yk<cKltd zf~?q=3Js<qVE7>t4BpDY<R8f-U~neeySR_cu2JO5m*1q)JUb)lXc5e6c!^sIhJ;%E z@=#~In=b5bg~D&wL2!Kz-P<=0K72^xqN2p`--K~wb*2f9Y5PUDTk$h>O9M)^E`|He zLFBCMTtR3jpTFIrNA^342+gv^V9EPS=&rU0*vM|!^Irnw&pARr@W1~U4_UCYU4b+G zRRl5-N?g%oGrSn9DR8_JOvc)WVs^?aa;(Az)=yX<h!yq0zvbcNmq-!}kC}-vSz+X9 zS0db;Ee}em{JZO>C_0^!65OaOq8<}2(7cg$92mF;zXF`dnDw#3-CHh`mqLATm~tQg zuFS{Z(iYHARzbEeKZ6=mQgCL(O5&K<3=8M(2OQ95R{L$kovPmS(Y-nv8e)eE$Nqxr z^-wxDW*fb>Z5g_c+r@pIBL^+MN$8}uMBrE@k51PaNHdy_o(s|${pmJX9kda6b|77y ze2RqgYr5^rIePhS5Ith^UuA|>G1>=wXZOn(F&4%0P*5JmURO;aGjE-s<lZB;Q~4<~ z!M}m|W8p6N&o2N>&OW2lK3;*j-n}&ZzZJNc7Q(EpBXpU>0P`&SVx?2<9U3`3TNrXH zp03?1j>mG`D641$S9Qe6hrlb4yLX7jzu^6;>RsgKxlZuf=FR3?-@~=@&azN$!|Hf8 z3d3gla&ce3(~!cijM~mUu;uAmMt)!nI)#<8ucpXg$cbo(9|v6E;#{~?8jas$!pS?m zP|Q_*LZ{qrhBY?_pr)#aj9K6d<~KJGy&WHD`P621&FLt-c2E;S+2v>x-A-3t(}aCn ztf}66mc7?0jliXX&b1;mE|10g@1+FGPHtsF_4Z=m_ObL+$uV|Ynlz{$T+0MbkD+7U z9VPo+WzZl0;?M<A9F$RnG!0b<tvU}i&2RAOr3EOXuMeRX*T8j@1E|jUMdtM-(#?rh zxGFf5sFWQAiMMm;!<Xx6!i&Y6V|o#@s;Zn!lhefq`qIQ~$~34ENJGqdRVdgPN6bC{ z1GTt0_-4)+*m}Ge#GG=uy+S!!nIguSx)zf#Is=S?$J4vr!T1<<<I313w7J8gOKT*q z%vnp`8Qy1{H{Yh4*0^$&rw8Gm*>0H6v$Tqf6RdXJSc^B~!buhHm<T+y9t#!)5NG>! z?BNA*cqj4{{$6Ip&AK*B4=u?e=bO&r?9eK*`NR#Fba_5}e-wu<Z4Q_<_X-){8MTKt zOcBW5(?!f#M(*ucLoy6r&^O~BGK#6)f<+s*l5b%t^i#+TFf&+7NX1Xodo-Ht{xp+n z9}}Pv3BX;2_ZTII37F$@oBp@e9#bap-<MY;@$MvPYCr1+mQ8HILn<a%t5QhlA1gLO z*_3-LVS@Fw94c#1taR3N$3nqnD7-Vm!p=yT;A(-=%Yd=yXhP#1U#ZSuBl+^$jz&M< z1aFJx()&f%U|#O2%0qlcqj^gOPKii>wZUB^xAYz<JFyk)Cal13h6_pB!%?WeB#7#2 zxiS~yXM$`0M#0dTcI=POC!6xd<7y2Z)V?|mw<uUZR2t8YI=voMLNdwPj9Yk8gXc^> z2*7>!mr=j#p)lIEkS5$70|hz>utK4ltWxNrW$7m&;Cl+8!kuKt^j^Bgq?1SmdD9<0 zMzHk17`FLXEnaVYM6RrvOKNM+gZ>Qx9rbq&jGsVB%-yGg9p(A-RQ+buEz>~fCn-b; zPScHx?QlY{7`G+J1}s7^V(!(kTu}ZzEV#EB&&mY}2Z!xJNjsa-x*bGw?B~-71>ae> z6P0M1F9p7aUT6hsw5_z1T#T<{=JD@M3(_t!ik6@0*ppr~yHy9Scsek<J9m=a+g-Hh z=2WmUPh)C7nd4>cljL~!O4M583x(%*Ltofyns&z=x2tsG;+z{e&Fl=jcch&jnJ8AJ zbhwFe$Sq-=OP0Z+-AU9aUk28!=pd60%mgDvae=ty4RXFAhsxex27`<VhWbX~DRUnI zqq2>(P0~U(xz~KI%zD916$XYAr@^J)dT3_ym}%$Tpe>X1AYa3sj4ErSImaF8iO_rO z;Uk%>m6Sc{igKr0?!*vp8Q$A=yOJI~Hl9m#SWG{JP65&M77`xD^I}${lVN8?`0!;R zOsZk1@}gXnd!dgx@>13Z9y>yTWj)<dI+iPqQpa<ZIS^W2NB5-h4#GoeMACLL-1qs* z+~sqM*`s+E{N=|?+Ja3KP45ts#dW|%#FLg!?zm0!8<DG>fn`<}AQQe1T9R5wiOW@L z^|k~~?(~5;)hIa9oq$1KqQKaxg>ectpw)*vn54uY=()6v$Q4x4pJHoiys|pZ5S$X) zY1Gq8GXEIKMfp@vz6(`Si<pORMst@uedxWHqrkW`h*XCt(pr<ZoS(vGSbHj!j!pVa z6r$x|>4_K&H?<_I^iC1ur%9l3u$o?Tvce!cQ+m|P1V<fs24wCkI6`kT|4w-$tWP1+ z4C}}wu@B^Y!D4tPs!m_LD}m`_Ja9JioLOLh2J4UfWKZ09PcOKQrsZN&@N~*}+!y;E zLas-npkqFnI`%R1H&_AhW_W;)a0Q&T>&2mtyJVkeJW)P=owRhH0#BY3G*}Wr+qR_P zX5mJ>raVagyyQEsG1J*@<8<0GJ%crlcz|YM?!?nWf$P@=Y*=s|)@w%~#PVT1Grrp} z&<oNnS^|AB5%Q*MEGC+)z_FJ~@s&#kH{l@9Js;cv0Z$i_*RE3V@S6=D>k{GqDZb^i zqo!z{F@p;UY9&*)<YMfSxwzBeH5dBi0L)RE&d7OxAqTe4$M0ihaDJN##=ls=uImto zJ<^Y;&us(f42|Z7?cb3og=`oV{g5~t<S~^l;$+7tDJ;}(6l$*SV!bCxlh2QM_Pj>~ z{XN5;OnfH+hFaD1$7DA~=ae|=eWi3kpA4>-Sc=2Ci8L_XLlCEWor=6nrf8x>7d*Ek z>)v`<_m7A`lld@;i!3Bhy6^FRp~rAEjPDOEapV47E=R%8akM$P96Y5G0q-q9hq(%9 z)M$st_ww&S4qIT02ha4(JV4`}%;B_KBAgDsM<rDhz(`V`CJl<i((5zvjp`)SsMn_5 zCi>KAPg6xjpCiZ_7Epsa7Gsyk;?TI;cv7>KIM7WHpPWjI!m@-}am$fm9#}_jziBmL zzY4m<%T$Kkk*<>GPLgL@4ZN>S3_f_SL~#|~dw%N|=Ey3*&u2WlEbgM!mySHJiVlP; zj)in6M}qchJhyteCx}}RSi!2#Z6sl13{c`%Jj|%dqE0{LV8$#0{(mP57EH_n`~EH{ zd$u3NQ;&eozkR@(t)lJTb@<#c3vd0m13NafF+KI=U=|x?^;ypzVhUto;NW*c4G?8! z#zMn>1vuFOupzFHh>Vd3Zxds@mbuy5)5`)rWrh=tFF~CAf-q<^4X0rxSFP{99H!BI zNpx&_8sG8HqcT?m$bqcGaChQi;1>I1L8v#CwH*h(!I4xUn87AT9~hL*L5GK#<cEO> zw<pUJJA<a+y6|9_%ReJ~Quf15M_WAJ8!u!&<PeKaHJl%!1sQd2WH@aJ9oSY(6R+FB z?egpNXw3j!Q}>2{M(?6DhtDt#?17KAHSFZgV_>^XFnr&BoBD;W#I-VGv0g$_aQA8< zb+l?@ZWX%HhB@OfDt#4cg4Lua>7_7it~0f~e-1_J&%%NBAHs~03(y;&4Su5H0;LHj z;Km^fm}{H~1}pg+jD;%+Y?%W}4suwq#{>l%E)lsNb(CFolIS>1gs#%Dbh~RTEU}0t zrtB#&*Lw+js$~Ql->Z^_^F3@^RBNT9uoFMjx6>7oQ}KX?9`vu-iDBB&l#YuapZA?5 zQwtJ6|NI9SY3QVVlRlD*A<<mcXO{jg&nLe(y5opH!8yF!>q6?^UQLLwq*nR`FIr z&*by$*LCNqk@0REHDMZ@+Ori0ef7atBNfs*T*(aoNR&|8j$_9s5mE1D>~ihd@Gg51 zr+z~p=g2%EJ64yFn|xlv!YYTF{=UW5$3zRBYFUDQ#0TraW<}VXI?NPFE5gkurR35b zX>hP?B1@%~Q0J-5@bP2`TQI(ivCoahM7|U5;pRd$u4m9vi>s{OQU(nDcH*H$C3w{J z2WhTkiP^FQJX5d(ZC4!?u047N4$B-R9jm9or*?H*uwV~fUME7zx?fb%Rzrbl)<l~A zUKJILcGIt=)3{6-Q!<_B>!|422%2u4rOF<+NYkkCD4v{6Y!Z#Qubq~##P~TIEZale z3SM(l=RTsV+b>xaff4itSm6FRXEG{Li`-i+U^mo=L61osi9CD>9&}HI2VE|Bprn?R zgSz0Wxe$E!a@Hg-1LjWFB=+t$0DXr+;`voNnrEwuyR{PijbrfgnM5*_;SGPl8dtv$ zr}^LbTve4VbvwR-Yt%o>^j4L^(FbWlnDY(P3}lF2qa_zzQbJ1mgUJK`3v_hve6Fs* zf=s*mf~1y>hPNhqaMAP<Ic=m|nSVSD^|V!C<;I;{DgU#rgYR+ur%5?;D=f%T!uTT* zz({nF^pbtF*uIF=UTG(p-+9_i<`WutmG8~t5i(rs#@{%e<5=Yt@cG6`cIrS9{+3!x z%@+P5(&?t?&_6^MaMz(CHlIv=&ND<yx8cX6lg#1DiDdGUy^tmQnSB+t177(4r9Sf2 zI3;E)c0dRgu9k)9>Z>p=rx{K9cVmrU6Rm$)45c~W!COxTG*{?j=BsF8yCllGZo)e1 zA-aMTP2x==W{KS2ALBvot1)Of8c_Fb@<j1pu2p2#4R)Q*E;is$3<It~m}hnXBhoj* z0mU*13sK=l^E}@j-_D|2$9QOHoeU0=68O?&7Ea*OSUbzNXtZP+$~;+sNrQISvF|6l z-9!}&y`ngmosxp3f1OC@vkv;#{5-k6={%hwC5ApKiXf_%K&4zM`FZXZNt!pC9Wke< zxo<CL{x{irw(=Y1!8rqA<HysaWefvVmMh`LM;UIzEPb?GycYU9^BC&~0zvWmRp>08 zN-8EcGCes7jMva*a(DH8fk^i;##8Ag{nDmI<{oHeCuga0(fka5SW=D3&P*a6sY6t) z&W^l4@RKfVv}MZPza@RA!imTY4>ZXvVMUk?=onav|Li8xz6HZ%RD(Y$Up-Oq<^b=` z+@6g4c;3RU`;MqFunab5Ut^x-)mrbI6pLlL<<@FOjTn6HJc@oh$rd=R2U9I?NUU8! z6~1P{!qJb(3jafJc|i&ao97d83w>&>rvTAgw!oyo2dFLOND_v0FiuRDi0(X2g)hgz z15tN@%gF;6%rm5)Z0@5u1!Ga-V=QSj?<ZL`Nw7F;J6^3b1Do8FxV>dQV)+C-ILOcr zK@f=Cdcc~lTgv=tjD<IITFLOMI99UE7(Ca^WY4)|QJFC(&^|$xbab4?#IgW(mc9Th zr2?>F=Kr}ghso-t)v)UyzeBRsCf6N>L|IQ&@F6sZ%u>+7my~~&NKm5wX9j3_^Z$d} z7jqpR3h+iQ6U!fIaXZ%75PS8F=;7^2Nj=XZ=$k^j95>R@%`MdG!;?yT{=2*6!7Z|W zVleqi;z|EXTQV;&n50Aq>AT>CFuB#h>OOtN$i&2v)RtIK+i;FdZ}>%iYA=J2i7Ocw z`}>$YS{byg3&<hUT-eo~0(NIl(_6Fp=$)H<$5Y}3{#f~w=y+|TCbQJ521jOswMGNY z@9rXjf&dgTJIyY<mjV^JjYJ|TpUk}A!st{3{?|MPv`$o`^td7_Ulb;2PPL~}TXzvv z*@O7>><&R@l!(CgrVd%-pFoGyYN`CiE)q4{kdb%uhi|X!aP6yhsu6G&EI$e$=+Q*z zf1*JK(~Z%`YB@YRSAtrHH*u+zTErvW9EMBO!PhT=MEnY658jodxsT>Diu_DHX`?ka z_Q@#F=JOO$4Ph`pU?Ms{eSj~%+t4+EpJAIRpGW&X7L(p9(}wvc;C%gEQoQddOs!X^ zbwYP=%U0l?EZYF`ss*sxS&vkBE+7l8A0kf{J)`8CDYRDY1sP>297t~^PQr4ccES=I z&&~k5(EXU?;t3kRWCS}FXkldC4D?LjL3fY0rhQj>nF-&mF=X~vvgd6s|BUEn<m{uY z9%ynjKI}OC+qIj<Z12FEd*X>#J0aux)8VK1B{(qIi@Uq#5ZsPr>9m{6;jpO-JSt2_ z<9{1*e?ukjU{fP$SqE6*EeSMVWDK`DBaziChKk~FxQFWS)#xZTWj&`U1{;X#*;(YI zTM+Gi{FdaG%LC**w_2qdM>1^rJ!0q!JgWK5I(}UWHCL>q&INIp{-lFWD?f=6YZJ(Z zo3;EcsfDD^^d~*hU&yaFBj~loiR{-4fp_^cXpftyU~k|&X2rr5V(ICIKGqlUSBL{> z@p-vEVIr+bJH>N=*Pv&f1gG=w3_Tti${CEB%)FCZ4X*l%*!?Mv{L8rjuXc-qcxXBK z<#A2;^gkVPmpzQj?efs!+9~d-T`f(!=s<iAo5G-=fFZUC)PGYHT)zL6cx_WauYP}Q zZn{I=f81e@Z7yb>C<SvlJ~>c$<RM*G_k+|&FTxn>FKnNdDb7B*o#?2Ig6%H^urYfV zlPZ3a^YU><S3VbB&2#(y9xW#d%j7}qTL!LLGKXv*5U1Q58?tx#AkkCm!XeGK6l@fz z?dF3dV(2w_XtNowJsFG7f{tJob;e_}(&>Il4MEp<C5$mBqvF-=)cd@xAUm;H7?p2G zeAcIOK4U)9Td@zx(j)U>k4rr4@lxY*?0hlrr!&sW(1s25rtn^Q0`pAbI2}?o<17xS z!qhnt%%s;rbn4EFWM2Alvfm*Aq?Wtk{%9pOUXUX!4y&TsY0K#CqBOert`!NL9sq9l z!|8HEW$@d&A0H1Guw$H7((C$VXqdNz+6;JtROVSmQEd(AB`>7^T`3@=!=1?<wM+PJ z{!CaV;lh0c1AH1RjmEjWlkC|QTJ=R4xBNKEJ<i(8cWh$u)3hAx<ePl|z-u+!_utHv zxEjFoMs-YfZpV9VlJtjo5?tFaL7gwkgWEMHvOBqkTza^QXHW(Tg7gglugAgSl6Lm^ zdmrY-Qv>)UlR=awdtuRX8|?m?jr&)Bqo0RffPC#^q3YQ%;(vFD>}g0Lm4;GuUc*@k zC=6m|+mC{1J$~n2qC;|eKGE2JQTWl)34Arr)1`$a-0mG)Akfzy_r3GNm|aMn9xLLV zv;saYw252_`$gtk^6%U&dujXCyKMHSN7TWg&<b{M!A7ShJVQ3YtDE`QxWAkE-8+dZ z=fAgBeKLmo<qTxrzYV_+6_W(}S0rMh5?L_gHj(o)#5ZxLz;9q2x@@n5ilz-z{Ba;2 zdMAd9PUjQx9cyumvnRgBee`wI7tpLeN1X0XfwY6B(C-+?v)|=W@Z%A_l5hr0Z=xTZ zKav!U=j4pNC@epJkxXCPOrj4L6LPYG7H-&vzAFNtGIk1z<jw(&Sa+B-HWEgUTM4@@ z4w0`sgT6C(A{6@bdGs@JFng$z-o4gIn<dRy)}@h={Hg>q6~)MhX}P4ndIH>P=wahr zqv2VRBTVTu6^vN(Ud2D&)IoP9-j~0KR~9P>D-RLmI>SJwVmqnjS^B3$ve?p_x5zRY z0#gh^$hV<MR!i3}VD$4=b5ZHfh}pymP&2g=Z;hDZFk?yoMGW$+#8i6e%qwcKtqV@o zhZFhl*Qsb`DOPv!PS~pLbo6CPlU3}XF06#TX`6#vqK(kuZy#+P=%mRP5M+wwFk0CI zcNR6{#cp{RHKZ<Bb~OWY1_l_VeUSpKU0$$njs<<eRgu>ka`c(v7VK5;q8ob^NM3p_ z+rC8}y=+AVzW;I<tyX_wX-5>u3d-1sU<=I5y+dF8lK{ad6`rBE4)t$;!s^jW0Ch$1 z#kEG7zbO-ooeslQrybCE;}+?jnMcx>ETdiX`TSMDKQgC9780{}gZFq{c)4f=>Waot zmEUu@d)~^lY{Du!_(NQv`gIe`<#$hS{d4Kd$~;yf>@^Ng*MynY!(`Lcb42P<KWEQ7 z3T}_8A-fm(u|Imd(aXJ_I9`aL)5Q-^4V&$>CvGiFJNXzgmj4C8?_u=zGA42UqJk;U zqy>jQbX&VTv;p5u6R7u}n>5Y+5nGgMg>DKS_(JUwn^@UGw)kIRBrMy=I-RX-*Z3s% z#r3hkv^C(&gbSz_y?{QlK0&%>h~elDC1A~|0{iPSw{oHqNb~-Uh_~K2YDkJ0zxqVN z!o^|H?I0kw)4<@+FE&}@I2pU~FFU2gnikBf=ALeDp{~ht@N0e-n`Tjq<5Fkh^U1ET zHD*2jt9e3qdiIf_T|?yHl6G2=*2?zJzDJGJIp%7*H@2Nr!JW^?lB;{$Nb*!^PI0i1 zTrsgEnVTJ%S$@l`ULDMbNe@quaOH4j`>Iz|`)9H6{(rf|?~E9XUulbDkMfLtrB(P? zx&bf8Ji_aTld!li4ss(-L7GiDRZyq&eC`rd9Weuq>>b?Lo&u6^QQJy$Q5=0gzm87M zIgTkebl}ScDO^>W%LVxTVS7e<kuvqMaO=<x_!6Fpv6;85|F{NY#U~q@wYwXC)I6m% zrOV-vsUakUyd*enBeryRkfZi{$st)o@^<$QIGq$vPOOSxN=F~S19x}Oo_EpcH+MWP z+H64!B;L}8AqP37(mgO{>@+Y9+sf>?J{^|CU4l*GJP%-OJL#V8PDC%Sr>k8Tz;eAM zWPia0{FAHB4d3>G2?ym+);s~We|uZGeYrF)Udpm-74~zBlNqX)v=lBex7Z+`41vR? zceL$6FVo=8(#ZZqy54##WDdU*R6TE_eqKP^PKx3)=MMULr4qM1LWX>2bI1z22c#_8 zi0u*eq(&!>up>olc`<wh?08#6D^o8~LsLrh77Wo4?a5?Uj{`i)F(pc7p*)K)O3)y& zkGj}|F)DpaVcWd`=GL7nbouy&bj7<xtk|bc`c5bXY9$0Obj6{{2NCRh_KIwAkR>r| zW$403xsW9i2aYvD_|hedu42)|IAk4pk#-6$Yc7YRb-(D+SuD{olEeBATTuA*g}whp z3)_y35)1{e#BV3^87J<aH8~?iiiSkNdZ<PC$<PhXkIkfQBnp}jHL}{ZMdXm)Cfsvf z8vG?fLG7|GTkPphdq$rnPfuphtVsnzB|g`>uXHqLc})>5)PcUP$PuR0CRa>fz`OVe z|G;%t#47bpOwSx7AzGbqqF4<3EDzERPrS&#j%c#^gEYwQ>SF(EJO}oHOGuhgI9!^w z6bpT0xvXRJ$c}L<Xy?o>R4E+=d9$3cEkl|%OgT^Lb_w9#{Q%k{d_k37Dw8`&4a{=Q z6e77ykxFear2gmCg>Bgzp|mF!OJdhSqMbSK{aV7adS0=S9~2;TR3JD#C8TWjf23`b z0g1i!1fTwCB35DBiF?>-xc)I5wvEjpACE|4;m@hqzV0vPn_U6B*YbEvW_(p$iYO_X zYloxzl1NAYKKi$QI?k6AvIoykrMf)RDWD*airu<^FZjPgQ(it=HpQWL%|?OptSdy; zZ5OGKdcrex<_q=)8ww2VPSQ466MVOEA@+`|APZFHFhyQ@u&VDQR+e6-J7<dtmcH*L z)^|LK+0Gd>(eFGxtggvtFoy9(PYLcmQBQVF-UZn!rdyBH7BSyT-m%bPjf(#b3D0>( zQo6#0JFLk;+|6;A{dY9qftim{=F;5#*<yI4K~|u=Aqn=+>gU;zsm$WFnGioRhyNR> zpjAN|mD348i{F3nv9&x*wLJ}AJ?BI16h9a?j3GP9RY=6aZsNS;2VhYi2G*_>;y7hE zSGx<m`tN}M<0EwI?HS;IEDY+;HB%{xmFP1$4iC<r38sR(bYt!WV#eR@ZYoRCCi}_k zQ`n22mY1`C<=cp^hB{UapTYt@yLh?P2%Q&Of*zmS7hRl+5=Q6Aj-t_2=iD49UTOv{ z_TTC7vR&A3T+DNntw`>cKeQyt3Oeo9gTc$y*q<FwzJJI8DNS$KofJatXX~(&larVp z-d`YUt;GDeG#=zn{UKj16=4Wxl2NanC@e3+dg)g3y)}!3bVT5<)wl6AKilao6ya*B zH6U}9IqI2|Lcx-9D)u;%z4lU%b7($BHn?fQc;z#gGLl7B>~sd1s@Y_N>@<{{{{|(; zEdqJ7Pi!Th`;*%H9G?v>z!Ne*@pHf;OxD=IRn)tZ>KC7(TiS;aSeBCGqMkVYlPDgn zeZz)jO&}&ums0oCf9!@CUuc{da6Mu{?CHiWWaOYKSi6m*B>pg27(EGyLkRPza}x3O zmY_Ka^HJBbhTR&>(aOXMyfHf&-hN494&LYI!l(e8I6(=9zqB*b);Y|(@!@Pxa|FoE zS<lpLi{@-sWuf-GO8Aj>57wwr*!EBzPOG@!CdU^<RevWAP8bcB<>QFP&p|x4ioc7< zI?&kCX5#B|mlSI8oG`AGtyl7)-4Us@r1=$1&`pI%85>MJNcn8D08eE^2@X4p;hh=j zq;x2jyPG|ZZ1)o<R{|yJjlDUrM`;NLXs)7j9!Ma!tA)Hg^M%ZRC=b&ub@8^A8n<z~ zF7rdhm+o)o7~$bwa(2T7X8+$XaJ)SO_f%eBDknIQ@OCjQ;r(~dJElUcx-6)D)B)!A zeoSrMNT@!)PphdVR`2HG<bz_=*Qt%Ym2C>`t^!z?aTWYz6*1;~A~cq6g#55M`01z% z%zx#LX^~a<#YBRXKgc6Cfuf*4zY1RqGPs=hX;?1|!Ber@iDq&zT)sOK!gt<h2l&rG z;gUY8eMp2G(1{~gFV({$+jnH21HT9HF^8JK7NRW?#^}Yx3UVWS=qAHMkagh&)exLz zb2jY<udz;a-zFn`7wtp-sGP#Ql?!qI?mN5}JDg5>`iWeA$h#A!TG6g!6Jg6fe<t|8 zJx-s0ikT53N9yIJsQ9%q;(Kj~t~izto;Q4O)5a2R>rZ8H8J&#U%lm1^^q<6St|4yE z8p4H!7g+U_GbG7@_ZwNQx7P3*0~>yZq13<+vUep#)+Y*wjPhWfJfeKTZ}Qd0h0AXp zV7wljgz+JV0UYkY`$J{qap8Z=f-F0#@Jkyi#E#(-$14!xQGpIC&I+n853;sf#kkC& zR2twKMs|Fjh>{!XFjizMP4Lg=J0K3^@-Yp5*P#yUU#`Nxy*g+cvIU3l-=;QxO?2<a z2-3BufM^Y{V3T4CH7Sos$el^FJ9P|qR6T(<Ei#0Y#}{IX!xdt5y^>^ZbceU^M8Gj7 zm}a=$<6VDom0E>9<fYaPu#2s;YSZ#!t8He`lEO?9J~;x$?AQp2y&uV1DNS}mb|^me zeoRJhcY@A_U(~SF7Wb(9WkUC5qtTU2lzV)Gq+c1LTQ0AIZ$34=dqfxecD0jJ9>sL5 zWFIu%Tt;8NI>TIXX(qy7C8&J!B&|x)fS~(hx#ssyaAuYVHCxxp97sCHYBNum<2~{C zcg;1{w9f*5z6`^)db?n7L<`prs$kG0X_&gKg=S9OiAPUc^0UiHVYY%Qk|PTRUQ?<` z<z__x4@R7V;v;rUqntoHnV*qQeX&03x=HZ;RS&(U;l<ySgrsizJ-WT;DRmw#iu=60 zSeMuS<n`eRIM8Ax$o;sEjI`{>X@4XI+5YZy4$la99X3pd4kdx^c`az2$6-a(U0hPR z8ph80N#E@og%1N$5HbRx)%+ZEpLKy=EiG_VeJHdR*TLaGCrC8UzxUWoQG3%UlGRd; zm1k1v0pA(i$7MR?pVcY6czl9jO@o9$dutdR^^!&NrJFINFd5ZlHR+lM9%OA=C#&UE z&z-sbfL*jp9X{I&k$pCa6Bv&tHtz?C_WE9Wgx~!s{&$Don_NOZdyf`$Px*-rzL6xP z`XQ`$&WA;n<y7v@dh*TB2|HIl!?*R<=^o!=8h`CF!eJ*|ICutb+w$+x3SZbo!8Xub zEx_rWIwZNH70<P$f_Hp9zw7lxh5w|fvZWBheyjwIRp+^h7)(N3G^k3}XuQy?!TpF4 zl8&to@V@gZ%=)wx{JLyV5Ee`R@?6ib(i_68!U!&P(*br*+7tRZM8JGm$#9-LFI@IY zG&G((f-$2Xv01WxB>2}a;f1$Gxb=50Gj7&X=A7MC`gH#&3_YDey*)0HIs-ZIAW~fH zyGx|ot%b3eHbR+83G~9Gekd=qpd0PJvkw-zVA7JS#CW_RKtu>xSZ|I)vYV;>vu#-I z<b+iRyU@d#&lwlqfiJzE$@G0IEziFiW-q7L(?^%p$>P7poYCU}R_&ub*!Y@Yx`+i^ z!Mgy35;Ac2Ogg$axpA+8l+oGm49RKV2pM0LA;Iw)Hf6u0PhNeaUuGh!=(P+Ny*<H5 zT)It$b%jLqu?xKUXNXC@F<{oj`*iD0k(gf{FmA(F;i$YKDzp{i7voD*CdMCcCk5l7 z)ptnz>Taep-<><PUlHtPXTzx{NIFLNeD(9QVAjDhg{nsIaJqm^sW!sD+DII~M9}`e zvFw`m1iW?NDVaRjPkxNQ4M#)QF(;*sF#1j)U158WoAZ4sxmO_ri>xMb+cX;mXYW{0 zy<&dWU3QvY?3s`2o?iv2SK>B%<PXw0w}<J^WNq4Ur;p~%tHLFUX+&at0M$Qihi(&J z(G-#6$lf{u`T_fBK};vCPJKXsZ+lHWM#9L9ndkYMqX&6rG@X3BeTjAQ-2wlpDhl=s zOd(?Qe&Rh3L9=Zhv%_Tz*6a(TC+u&~{v#?_%ijYOCAINz@Kl)FUPrfHU&uH~xr0>N zLRxFk4<gdmFkBP~L2JSZQPLz+h&nhbo`WlXd=AECIaY3YZ(X%m66_9qCfl5hNvid1 z{9`Z*Y;~kjPxJ^KJ!czzd2KUnU7rD|du&iLi|6JW%E8JQRS0NoXX-R3!@nc4xadkA zly9tty2Iy~gu*u@c7_BhUo*yIA~R^^yB4DQf5y-uHFkD;7<sm656+&i0#l4VFzoAX zGG?wcu;;S4t7CeY@OhU(DIpa9zFSQ7A2+kcJu_e@t3bXEETwb1Gs(hx737!OIQYc- z9aiNSaz0s(v`ah1THf#vpE->s{g=eCVbp2zCZrU66O!TCxKKQo5QcgV<KW60RU#-W zC*@bKqks1gy6x-<R?cn&{xnD7jY@NP(JO$dp<Cf>Vg&hpF^=eOol7eIHPPFl)2O?D zHF*>rha1)3(1<nZ^kMxG$UnIRoMQLD(Q*SE+ABluod`fT*C1H7K@wYLjj1Xhc}$H> zuH)?WOQ7|66nH(qhEM$B(716meSW~3dn~5Q&qoxGEj0uYy9w;)zJ7G~QxM#ra*oOd z-=gBPd#!3e@Xie-IYCut990$VN4L#W@tbQRdC%XYcfZttkR&VYUU~{WkB0JoGk22z z*Ag}j&7wC;RcXVjA@-4q6gPfdJftLQ!S5-b2|MK`_3&V*EnN)qmWOf4#&W7YVu{k~ zHC%SlYk0_adyW{%bHR<9c($qrw`y=d>dh7>lWlJ?59S!a9)4G?J*5C{d4HzP&6}{T zo1@Ba9->ZO94342h2brmz~8!;2IijP*;ixW&xjZ~;d78YHqYg!pF*s*4xu}DUVs_n zS%?$q<{gRk^xudZjDmXhSL-lY>9~^d{XT$yURu!1D^0ZTUKO)>Fo;a1_gIa!v2<E> zBH9>c!t)j}vaDejIX7_{>3`crJd(sQ_P_;pes2>j*f*8tm<&?I&>=Ew7X#-8PVo1O zM3!2=q&g*YvD9cS`P^rTd)jZn-NuO!mM4neK3QS<w<<`SHx}M@cL;_1lc>xcIcDBV zKej+825x`(!v_8og>0VjWB5iM_1iPqbk}HFWSq~uHQ5B?`JJ0%-gf*{h1An<I``^} zI?UQ9iTXnqL2kurzLTs%eZ9j`hTnBcR4dS`^N9TX!b!g_ft9?2XQ8GkKDlPeDVXt} zi%H>l*UOR)E_{mnB=|kdx>N*y|G9YKWX@Gnl4v<U2Y8dscH2k62HB0=W%X3N`*;pl z+E~tJ#%bY_y*5x`AR(yjIf%FOs>mblZ7?lcl+S(f>@Uj-`ubW8`jySY(HsNw+(&~W z-v<tUXo`FIJJlwo*RbC91)tlSjQx0njSP>&?gs#W({16Y)Hv!fw4LheG_dam#^bT5 z)m(nyI<zS*A~m5$AZ8EGXS_TOj+9)Xzn_YO^1)&H=-pC?+B1eI8KvO<(dVgJoIY;j zcg$}BRH*+PG2%HqL@ovmuopA<-kj4a+82~e+*XB>)i<-LRk#IqE3XrX^)Dftv6lGW zQ|9FEKe8^}!ta?f-B=kDS@@P6jn8E?nZ$=#<VSfSNwzx;k18**Vf=f+{LS**!>l^A z-k8lw#|>KBO%vzmmu@CYc^p(Z2#L-$7aC<_!HT4&p<3%xy72c}dQbEWF&lM&yfZJv zbxU{_(2}jRdneD7+!=xw%VX)m(HV4it_v$o<OQ}HZ$ZC#1DS1K1k<_-;e-DOQPEfm ztDB<mwTULzkgo$bD)nGS%mQ$}TaLe!in$t5L(Ez@5zU&<kZr!_iR4C>$gj<#to1+g z%l{S?F<;6VC#QjZV++*3R|1!*e;KoB9`Ja;hW&T1jm@sTE-2))NYSO?Q1#D~<axeh zjr_+jXG-6Y-<h$z7np(XYaddF@_ZcHo&gmXkgl4iNzNTHz>mX@n3;M4PSo<Qu~rqF zvO128-yBQY^(Mi-_sOJWhA6r=%m&@`c-%U4feQ?1B#Lh{v9Dzce91iodOUO8a2G+5 zg+5g7$3r&nT8#CkzfnM2BdJME5N01q0IkpU^j_o&98(idMqhr7s?Ro}|I;hna<R=& z+r9)=9X<waGjBra-*nO~ufWV($MdRhIKp-jZS*|k2qUkGu+^zTpnrgnd6#E#UZ3|8 zcUfoLqVknoQoV#v%XX4aZXMuw=r3)a1)$sCK*EISL_=#mnf6Ty4z5Z8Ujsd?dR<M* z|3)&)7pBucuXn@ZoMYr=Q#LJg-^9t>-wLt*d63(ef@7{`36+}y=n<ZSc|*yYrfmzy z(!QtUbVwkzD~_@<YtVz(;cX<7-$nWw&L*L})5813R8rfK57%0z!Q{;^`3`UeYFYTA zqU#;d|D4LzZR^DECh^d9Ck8tgC~|Ipo5&mM<;=TmDZ;Hv=Vy<nR7U9;vHQB19r-3H zSUY7o%)D}jzeTTSFF0Q#<7H}?5T-;Z8YRzlE?FiRJRJ#Fc%Q<!IV&0K%uh^$bp>4j znQWV%3(Q$1g(DsjaDITrEHew7clj=<EBQme&5p)Lr=*07#>bO$iJL)A+EBnIT?F%S zH7Gk{IXCv^0aO_6gL)sm@%Q&E)_<!kg^w?>bMH;uHLw6e76lPK-Ap)ccArjPE{}bW zTUc$aE}CNR17l{@)9KADDk}Da>zE5fRrf5Zq8;oXR}U~+m;<6xS8yZpE<&$%Yr0UJ zv>k4sak-&rl5Pwct9?P@UJ9}HdrNn$-NJh7zM)s6vuN_nPw*{Ijbo(Zti9T<^ZbHl z`jM65BHBJ!J^xsMy+?0Da`;2AW4FNEt?SYKi~*+HD`Q;>9@8PSi)70mXH=^#=N#A( zG90iQdR*sm`w!~yOp`jcyqM1)e-5A^XHEtG)#E8=8Fc8C61-ThP}zCjn#RBMgoX-p z5dFB6ZaS~WT3LxxyZTL>MR*4J<(>hB7P*-J-U8hY^R5C@Bs2M5^+}$eRpr`DPpa-l z`E{3Z>eOWLJ|BY-Ma9&8UKx}5M;A`3wUK{WC%L^+&#hZ4PT(2ka#B_h%Q=-L!O(0m zP@HB68Bto$MyJsGbBajoN=G1<571S`kI;(UM1$+DW3$ywp-hZC_xOJlooPT$Ul+w2 zHBd?=REkEWLZ<4TeM2gu2%)Gbk|aY)GL`018dZ`sM@p1Z_v|Z~5~4_wIUy1LN(k?L zKRn-`5BJ=A_S$Rx*6swDAKFSBo1f!6=SF6^wK(`}n25Gv1N7GBM$)Y)2aCRn^2y`x zkrC;-B;qt<87}6;W!%)_yI;;Fme|1U*3F=II!D8gWg_g{C!3h`ePgL*cQidZ+LHP= zs1h5Gbf(#;f^=t&!4d2@rgBddw`kxwUG-x(Q<f(RsS;w)^;8k{b!OvI-9!v=KSLfH zXR_8kwz#Gs1cGlm;<rKvZnx}VY#*$l!98cFTy-Np>xr(rDxCzT%N|=UOu9#2>`K8e zq>bhX%!c;jJm#TFI2mgw2h$ICa&9KkwBWM_pMG%(Zk_xLIwO<l>nVH4W$6^CemO+- zY$sx|Wj>}_IO5STp6r<`foreX)9gk!;f&1ZkNozA*oxEe-f=R>eAj~{F_zfatKkI~ z1$Z^Qkz3p-f_hfzw5vf9Z)fcy??$ANpDY6fiwtS+>{oE6KoZUhyPFx!@2M9x<YV>U zQu`G(VD2yYXVgBizgMaO75Wnw44vUD9sRMa<f!1KzQ8WqX+|y!GHTRpk@^b>l2}={ z0)M=YAZ467+1zi4Bg7-==i{p(#XlTw&-1{f+v4npkxh(G=LF&VI+Kbdrf}xMPUwSF z1;h5Pg4U5IXtC;SA$Ow=Dzc6k$DRNkhtZhQ_=R}1*aI`Kmr1aaq*rC{GZVHe<GkN# zFm6jcxKt+5?hU6P^U5-YS8oN!OA}zv^ZhhIc@XL&<!JixBJw%G0>V{Rk=p)w7=Hae z6Pqv&lG)?rB{LR+K7J=TJ58}(<^~DgmW<avmQwN9GoUkQ2DMK_$+I(I5GYy%-ZL^S zCywkV(TD2EEvZf_R-a7n9k>KfZU}6L(t&zU@kuzwTf{sk*0TP%#8j-&GKL{8k<KqT zPrj$cVS;)E*YWNWelk}Bh8Os7TdVji2_^D3<~WqcSrCth%iy1x4&@J-;;xxTnK${$ z%*DMeXv#`JddE2uGp&FbwHL9$$pGSd#AwYDS-x;^8z-{l9x9lHGDY6EASJvKaucm_ zg>Nw?G^&F2pepmGX?mUOWNE&2?*<g%e-W-hiFIo_D6kgSz--I4pt!J)82|fFUpcac zu3Fnf=Y4g>vw>UD^W-FOnFI7}_!zt(GY5-5#=<|f!%)+f$s8AS`DwG1n4r4xNVpTs z?UEDJpz}Si`};X<zvzcf8Ec^SkOF(QS`YKgcjAl7Psp~|V1Bv8Y5FkmI{KuYCP(E~ zfnBXUhG+MJXFkPE(>!o}a29>Gv=XdxD?nDbHy9Q@$Fze7VZX{H!XL;Lx^iBUP#ssy z81;`{Ya65yUjL|ejF35xiNa+@7ii8}U(~-?jp>~-pvo+Tc-b}Nt(D-X5m*{IPa|Po z8RFrTqZl)HE`Bze!=F5R1$s98N6dFA^2rW8bTW?SKh^f*`89uN?chRzw|yQ)#Jwha z`m|Y<(W{v;Q+r`_xSNn0t-*?@H#C3o85o}bkCZot@-oSlWMI})va9+(=Ih^5I=-fv z)t<HmSN>KfcWzTSzaj|C3@1P=*yHS#k`OYX5G%rV!KAK-WX!E*+&1G5s<E4Ck-$+a zsPUs4ACJZ3oGdxU2zTm9A>e3YiP!DA8R!1xkR2KdIcZZ#*Iy4<`+YHR>qoPnk3Oa! zjuex$*3$ZD-wM*Oc{@JeP3Z=?v)EE5K_vvw)_}<iC|G)v#Csi~JDgjX2nWHBeZYrA zS8Sor7Zq{JM?0wP!&l^1SRkn14ZwRdei7?Uqsh6U^Q3y47M58>z%D06eC~G_R=Nnf zu~ZU1JCg-#ZjR%>YDbWe*be4%#9BDI^%<GZ>SOkudtBCvjiCDBB-%&p!Q7f<e9~(J z__;$9Bl_=BsU=eUwjwz=BRv(BG<4zKiv)y|%5+#?=qIkj`uAqhR88NDI(dq)t@d6t za^VC)e_p}k+f-(7?|DAhw1Wg))~6{s4UC?8D0})d#WQgp5O~TQlAl!2z5#uB5;_U3 zXX^5CyRP7}ra<s`F+iQgTbSA9>8Ld4B014DAavFpp+WcWk_V$C=-JUP1;(Q&{CXS? z)ptjuw&F@=*n2UR{j?ujM#b?*26XYGofJ38{tlVVABAzFj}c96Lp*sR7UaiF!DD^e z5ZTtvbSqz@_gCdJ7stHB!0#nswqPl44;m)N>N*H(+{WRrT5iJ3lU!@VS~?+TG5J_F zfsvd3jE+?=VuMq!ldonn5SmoU^iGJRt6j^eUhzc8*?AYe+dO!^xfx_%6$@ok@`>rA zE=asa>6xrxW@Nu8Ge<8UyBGLcnC>?x|7IoOs1??*^`^C@f$McTqiQ7fefvwhr=7vR z8JlR0PdJt}Sd*3{DZ(xh!_L7*CV93GH+ozUbo{$R=L<W&UEbE%8#tC~A2(pj>*HY7 ze-==D>^M1ZDgo2yEdtQ7!6_|A_$gb4@yY1@P&V|EjH?kmC>^0_-h7!K8X@pT^DmPF z!?&4dF`g*$*M?NqtRXu;5a@PNgw82|r<9h1F)oLfTMhv@=|PcHD0#PjB0aTHg5Dk1 z!j>o;#jO`rps4R2Y1#gR#;S`!aHBg!1Xt3tbJR$drY5d>n~v@eGr`Pqh*tkF#S~$O z&+iw<eZfzOYf1z&Qkee&Ds5nU%4ZTGqXlo9%gE|;^>oz0cINGmBGh|+pMO)7My@|U zhf?$MpyJnKruUVt#izUN^quZV9MX~pe#nG7Cz1*KdaUZ@6|T^MzUR=8Zc3SL!alUe zi`*N|#@%HpX!j$I=Z2)=`EpNi%!?tXS2)9KAqNqun?zFs#nCQr22@GSLpRHAX6uNb zc=G%-wx@oOSzS7gKYi&9u~Rg}MDGJ&)%KVc750#OHZiRIg)l6*ECYEVcR9LaJ$F`Y zIj6uy(Nk~*e3M4ulcfP<r22VsD)IyVdL{`f9>=K66-NyCrN@8yRYC&Re1+Y~MY#RF z0zI6}!M6Zap^sJ>@7;Yy_iiQtU*qWRIX;%c{t)MHH6mpuC8T+=8Ni_mGNr~CI^LNA zot(hEUB{r5pD1ssd>S<du7F;m3E#9O4R7V=l1#xL?^kk{PI7(4JU>-J|JLNuo=j0_ z^|()CS~STgjUP;)(rmW7KMRuO_s~~P0wc5U3bdcT!IYUglP6p1aMD!=_O#k=!4t3^ zG&VHSvLo-9p6LtN5w$$s(;N><0?#GoW)d8q7l>Z%4wyGe3!ePANNYNq@wr(t#fh=x zw3<A7JRpmNk1T*&5ts4Jf+Czzr-AOj4f#<kb*XeYOTP>6|JA>z(`{38sFq3?B!+xq zDu1ZJnyaHp+|Vw{w@t+6ThC~(pE3<h|3t6UoEG-b-Ed&+AoJvcJem4I1+7|}$OyGV zRQ!7={-_*FW8WuWTc0WVe2c?{p9DXW&PL0O>^YEb^Rd2W|3<QQzAfFj%oqRD%cSZ5 zKEuPRWZpPH6iN$@Bk#@89GRK?pJijYz%C!`)w@P^%v=UrUSxxq*9~MnL~+p=b2j%| zCSzM_3^OA3F-ncdcZbMB#ml9zxqJn$T``Xh-GDTA$Q{<~{KTy~lSe(g7Eo$`4$Bs1 z!}y4qY=hD`)R)wO2Pb5Rw0RqO8898Y1a|Ca+b5W|FO<q%+YgEv#%S*Umi8;f!mAZG zxfi?vuFuJ)Y^4#MU3|GNQEeN_t>}Y3*K_prm?`jPp(glr$-xE(mSoF~;~Ol8$l#$? zd^XjTJlyaL9sU+DVd8H%gS<HMdQ3YBPH5%S-j3mHoC%z$ap9V`j$$p!tRerx7=GM? za-ti26rWC*48_`|BqcS8{%yZWe5C8iP+?~Mc2Onfh0#=U|HD^eUZKV(gsh=%Qz;Yg z@`~B%X%6oF(tNg&F`08rhZ>&vMovDfhb5a4R^1r~<363EZEv&bpovYr@ey<EY4s4g zMa)U!@&dXoayxv?zsbobHWMi!t1<6)EO%~9GiBemqt>iJ+R+k6Kj#=R*UX-=UFY?1 zR^L+iTvI|<Zy$pbo?DR(h4q$NTsn8&p#+PTIT7#nD2U&>m)Lw)0+rh`xK@3brn~kN z+sg)UBGUxwZY0AO!~0Bz8)rEbWy+7(^MUH9BRo5&h(}uMm``?=#MM3m#YDc+qlRtF z(OwnY?Yk9zn|Xl^osQi10n&PDCa(c=A+k9a=5M)4v%)lB%)lus8MB?{9D7BkKAa}x zf&L>~=Uk@=os(%G)gd-D>3HC4G5Ig@AvOF`ObTbYf&ISu>@RIiJj2=3!stM}d%YPB zZZzfQ-ao@KiDv{K{A*%8?K`94wv-&usUTT@zTu7i`NUnyhwG1eZRr=KMEpiy$IDJf zi2AHewDG(%mcLZPq@?T6_2wY32Nh9$*<MHsY$dS^kE5YIgL|zxdZt2ylt;cNnV!2L ze(YmnC9(@*jb-6@)&%r@HWiMvo#dS7#IZ)}FOpB@qriXRDa)$+EU~=56D7WtV_AGZ z$d#oDe!6(@|JueF2hN9Ud$M4;*DD&aWj1@ibOS2)MRLxy73AOsF+6M{=wZE{u&*MP z+IT)CH7Awe-(5GT{3*|eov5InvdfX!#Zj9*k>sYu251}zgv10hShu<X#{QX!)!On9 zmH3aQ=FY_{Y03D*>!`5Tn}CsfD!HRY-?&}Qhsj>&Vj4e`N4Iak2H#ST(28}}Nz&V6 zD5oY(GMWp}O>-=`+}=Qqf=}?cYdKxHB^dhb4B*BqJBU%zp<>K9G;kVAzq)IapP4M5 zu6&o6O?vo$UOP#g5`~XS*TbHW<*4&ZllPDxppBnr@yTN|$atwbD9SK}`-x?={8cnA z&N2q~59;Kqxg4ry$nf`!4q(wHC8#erLx#=9V@dpEC|q6z!Am5Ff#g}*C1V3EuOft9 z@MXGL*#^agJq(+eLi^WRpjFux?0C8!^c!;E@FjhEJ?<E4WISdDv!rm-<qp~(`I^RR z9O1J^uH-H~IEjnI#*m8%M(jT4i`=ho`uKwx4JLcT`G6B&xOLWH2qM0g5t)LnY_@@I zpCrl#{p!Q?9D!?N=Z?QDvS3-WGwk}Nh4#ZwQQl)Guxi?np0j`?4p@Tm7B5_P;s|%} zq9&>jw$sBsQt;!xupcf7q(_f>qG7KNe%I{65e4sv&0SNR|2Z53qx7kQ;agJpxC-T7 zMBqmud%4WpgU`1Z1h;H6XcX7vA3bZOhi}QCq(Lcuz4w8REI133w%>)!->Psid<FaQ zGqLo#XTYZ3&cNT_SE0Xg1QOFo0QW+R>t$7Zo3k@nV5tR3DHj>%*B=?pyu<A3Yg%Z~ zB?~`JUV<;8@x;?NkO{pRPG1=r64tLk$Zzg}tB^>tE~er+!9(Dqs7qF5P8LFn=c$P> z_kS7G0h!izI{a}Be8<;xT9^ynyCW0Mx$J}E!&Ri@>3n!p*~XNf;^C>+ce*OfkBb}% zW3EJqqT!Nw{4Pd`wNbjjBdVvNkDgOUw;Eu4DcN!L4VC#K@D1{i+*A5V9tIxdvYduE z3B5VAfsurmH(Nnk@ThB!8BaExJ;Ws>|0Bt%^>liF33wcPOUuTd0iUlUp)LCm`c(*B z>(GlDL-BM?;5EyC9XZ5)#&~#It&Pc|8(>HBFH*kr4tAxTqQB0$^U3M$q`JWgp?)hh zd1-^e%cg*XL<`M4zL<1IgrH5^3~tNrSZ2zXT4t^JXsG${ijKH^2VU&^MN4WNNzdwb z;;?reowm||*T}xcOg(;+S(2SaKd#YYJ52)le_y|n6xT~6#chal@Sg;}rl~Z+@HZ-M zF2}BUrm*LC20Felg<Cgn;n!wah*~g_wM}QK$$lAreC$r5y)Bu3bk=~~Ly3^&EcEBd zQ=+p`imsK3!a2($d70OP^o>U;SG2&E`JI0nG_|eC<@pP7aO-8zFhgo}!ygRVz7X5| zST5+wb|(JxY20X=0!u!opva_ba>w6~J1LeyZfj~Wp5gZN{JD?h#o`Gtv8kEd7uN%3 z<at)hLYq01+e(&JUj|u+=bYMr6c*jQMW#C_^6E0x{EBj+6Lnxc%r?=5Uov9sroni+ zVcTfvx+Kc3yrhNSFC8bl!#<G1i{epid?>8(Hl>m-+mW^O#-9(@pn2j^T%B^6d3Mki zYn~qArqMoTX;C?;F&tv#U;pCfjQ&gF!e*fEZE1A!55PkI0m}tEu%`Lrz;J>LDOfXy zIofumzPnTsv?U_2yCQ-A82S;jU;07wr#?n{w-QWmJR$I7AM-O!{2^j^83BG8)p}!! z?$$HOj?o<PjDJbG{^-DKq6+T@YRQozd2%wg7*=onLRu5FEIZq!gf8r{^z|AkE4|5$ z%=9REn)PfiBPm#A>)uxhJa*aoti|E@y73$BR<lR#4NuUoYaGa%j70IORp@gr0E5!A zXzT09`ai4n$xyby*S__N)CNz5t>0|G?U9_YS2dxkeNwRMR}an@jOF)NAAn8Sfmju% z1)kmvbM3z@ONA0gRQ$CXCw)^Cy659bPQY5&bw~%e594tEnwQX5Xh4>!=-|863Pem~ z8m@BF!Tj4rIJR~T;dL#*VQ>S;mU%LH_e|lQ;WF-zoe2%QVGb>ITDW%04DRfiV;Iwa zht}RM=i>N2yxe31)v7bO4#5kx*;a~i5?=|C*Yerk?Yr?mg=iA=C7u41pK7T%HI4d< zE28A%PtfVMg`+J&<V=7TxakjLllDL6V6PlqwZ<Hshr=;ptsKP1r9pn+S`<4pNPo$W zVZDrHV0fn@wZ0TicF9J-pU+4O#wwHgxBKy~T`5`ASxCP7)N{+SMPTZVPvo(80$qRN ztfiz+0X={92PTfr#QVVwFz=NgdGdt8I$LqNAYKW5Mg?QcX;m`TJDbk<po#;NH<0-j zJQuEYqyFD;I_Y{cmd!KtgZ~a>QNKiveshy$Z7Qlc@fRn^%9Lz;p*oM1FxUhJ^Hibs zU<tjxrkU7=ZDxm`$8$sBu28)F7Ot;zhI+{j7#ARhj}+H}R*v8ad7h3ICjv-rOasa4 zzX4WR`dA@)2bAl0d~xt7HV%p~!4@LCeS{9o*%ZTtOG)s)*MxcS>>EKJ42L({K5$We zJyi4jJ(3idO0Jo_r|@v5z_)HEy)%>O@EccblJf_T6fL|l*^*4XQ-b-OIYjA29Og^M z;c%5HwQvnXk&NBA|Ed%}b50IsFVex=0w3<)-7*^B_1U88pg8FBg0^NZ<h3);fqZEc zpP#D?b8qj$I4O0U_}+n6x_qk6iiqIt15)^0&=Qi)*@4KiN9dRGj(d{2hrJ?^&;9yk z3(cxkM3lSEYdDKTZ1iVhu5HVQk8x(3qAzj3{2SndsW=__x{fMj=|ko-89qD568<XR zWi`SdQ0wq5kRB~Cx^^YQN5Mz9tuBeUuXKdbTE}qt{25^E?L+=4&!sE(`4GS4N0!nH zjPWMDLN_-@(b0bssqC%EII2vKonui>cWa7+)u$rpT&Pv=ar!Xn-j|0noXS9JYY)Ci z*CcfjbL&RTau-<gS(F=yWd??S5m}8aYISoq$7#MLQzUJ<Be|+<@HAIAv!ew&G{%Bg zl@8XLj-$87Oaw#Q2jux>5n%LNh`Qjl(u+|eYXm=Ke|JAw(EAOIC9G&%-VLhqr;x(} zVgGn~5Wm<xCod|M>GOdlWZmNi`1{8mz8qQwZH{sDJ)WVrRK9Z$en#L$HX25yD{`Ys zGU}x-rhxZ|i%jO}#i063i$oW6SSpbeeDM4%zMm$GK~~A+u;VCnj!0n5R5p^s|2aT^ zVh0oTvX{Cjy1+ywNy}o-nbcyuByToa4$6B1fT<bDB`uo^w_3#U`qCzP;dCg7>uv^@ z$VoW$a}jj^HfM}~k0sp({`CrqcHAU)p*L!yG_GhRRD0?|8gCnjq3A34DO%~;&2EUc z%i*|P0h9~pO|(yfxNNoH4_;jeTaJx`^0W0cyJMBbJo|0b<6afbvDJXKu29;+U4SNY zC+hsW0`EA8<3SfG-o0UnDcZLkyZ_F?FBwI!THc#&5wiXB>J_+ypW`ri(^a@yJb_(e zCBv>)Glrdy3(1X99Pts0qJ>Q^bn~-RzG$&LEcknj*sLE3C5Mqz_y+OlAHXGDOd&S) z->JrIAz3QZF3fa$Kw5#PO<q&LRc#}@H|@o?Wyf)-;~ST9Ycai1K%m^&4-7sJlLhuJ zoYkzyL_zKX?K8K8fA+m}X<|0pc77`NX15F63V6ru>3q%TcL$;E&ck>xsSnzMBXOVn zPLj1^m|S@q!-Q$2LxQ(4+P+d_&08z!O`GXxd44&#%-et=ZVGs1zd6{Y_tTC~FA05n zfs|Vikk66f<G)&B+`a-d3B5_TIK8Ch_BTky#iL+6xB%Lt^C9Ix4ay9@AsX*;QBE!t z2VF98v#1$7@_J4+t{S2>7eIEIs(@CP3Kkx$rpank;b?O$GyBR+=DgYkeE)boneZzZ zm1pJ<qpl-NR8T74x_BgxukwN^Ya*dUPUxgrVn}ID3O8o+SgQOzgp{VQ<Dcn-ll42i zAT8$}lXtuXq5l@S8gdVn?Zj~3#YEaC^BVu{`^H?%KMsv;2k1Zf`_w?$1a0cG$kure ziC3TuhIlk$+oaj(pCm^Xrs+_NG5s_-Y$7ylc?o`7Z_~KLar8l38=TpnNNaZafx<~0 z{Cyr^!0$S<`;P~j;11kxH3q&yIz&M#HS|uy!@YSlUtJV)3`TPsSF`x&uNXD$&?F_B zPU6E64NPIs7Z@?vN-7R1qCbCvCLdbCZ~U;G3A*@|x*yt4U-T)!-6j9nZwZ>Lk>+ch z+U$dM-$L>Fp-7N5mV*&%+vpCPC`|ISgXMjd;M8CUk90+#&L$JZpB|$ByafK_wmceW zDFJ^AqtR;1ep>bN3N@V|aPuytBlqMRvECYt(+(t{yLk!KZI*|6$9!BU5s7o6Z*h)q zrTCtU4126b1FDv&@@ZRE;>tfVL}lVVoP72Z&6BwdFMYni!~=`TgPR55e9WIpN64_d zm9o*iOo0m2D%_nW0XMoE85fBf{!`C!qP>H_x|C<k(upcCkYvx^JvEZ9daw>c-0C4| zegXAq4J3L^_oz?gD{^joHGY{H2a8ViFz*W;a5Zrx%OQ_+4^SvyF+^uHXVLV_B@pX7 zK+~7U3B0f?+`J#(X#Mh77^&zB?><_?hG|BeN#9C3;5v>?zwb+*<sQfD|5?$jjq_1A zO#@dMD?_uuG8oQM#L$UyI7>YWKF95XPO})?^Cpw2+?UV1E>whjJyqn!_#W!1dXn6} zGZkiU)`M=H6}aBf0An8sJweV(;cB?9z)x@n9}p$hSsGybv6$R2dq?+e6s^zOd<7>I z9YIkkA@}RlSf{;91CrBZFtvXsyX@^hPQ3g9uJwP!ENFG*ZA(fSr_s@9J4=-dUNS%* z+_i-KI3Mn4Q#xmu>V$)tn`z{(JH&947Q__&syE-;O?%y^kk;FV*f2?&h}%T5C;V>G z|MDwgvD8uK!aJZRw~WG%dXn_NDcAU3_0>e|buKw@Rhy1`Ivv7&Qn`1p!*GR98_wG! z4uy^sJLQ0Va<Uaq{WlpbtM%acfG@o$zedQ@-yzGbo0vXZQ|Q~I0sa2nXt_}oE)`|d z^TiohsT{;RxvApYF}dVU$V9qGHW5<I_L1ZVQ5dh<0VOJXxiXL0;C|pAH@i`Xge;Av zUe~IzFKa8@iA}@-%`rqZA(BQ${voQ%Kap48ztT<<K_5CY0Tj+268Kh5P-Bt9rVBQL z!)r6i?mr<Aa(64U;g1IL&kDKVifm-PI{2l}XJgNk7<l-46ZyiwgPcM;y2v4yxDKyl zo4Tg(AInC9l%Xp0*{{OgdU7Bt%wkt{<MH{n{g`IxiK##AaL4x``p@$*Jy58@%?c<b zW=`^;^rV|Aj+jdel99aqy%O*Fn$Q{7N29Xv?bA)PU^^e^!Gjgo$$Wo3GOkA#7q2se zjeItC8LINlAFEJg^&IY{yg&4Rw*-sdh>v7ic%|MLn7(WWIi0CQowAX>T;WT$Onpcq zdp3dR<bKB2V*#wy`a#;$%b1IO%5e3s4)@e;1O_=Zab72mb1kZJRx3j`!j=O97juWu zU)>mibGLSqYb&=2tc816{5u}^xv1f5hhI3>^B+0>c_B)wm7&!ND_mpIO@%NyE!{rA zz1nuja;i!qSNBGfcwI<^$9cJyFCNrVCs2mo0#W`;whH=i!aPzPiN@pONa^9<MD6|+ zQoHUP=Ej}JtXeBFXcfqf%ZY__l{&Z=mr3WYxd1Z+UujwMAxs)hpw73h(e+~zX+vTa zee<n^lq^~XY-AmT2@LPGLNC{y#wpPDcVqpb<{(fRYlREqV+gT!#v{HayoYBMwYlho zfi68n`@AJAObaFZsvC)DsT_RiJkC}stw8Td^T0PMnI2D)zz;QoCwyux#_B!<+;)eW z`kx~kYr=?jt_Xkm&;;@%Kp*!kI7O>IZpY2Ho5@RV8a)1Q4TjvU<e1BPtZT;|=JwA_ zM&52NXbwAr`?VHgn<qwVi%mHNpOFyODh1zW-Jloe+cKjcSdo9Xwdw1pey|}yp2(UF zVC4N&w3!wKfsSKAQC=K3Xx-<ohcCeR<zx7_PaZPIKiJS+VKVqxzK*U~%yX*2XGyYx zHF@G$4I8&K5bw=0;PPkzmfMYCQzS;x2WKXe6t85|n_|kYjE#c(2mI-RrxS2{+9pV8 z%4JXc=~HQE1DKbPhJMnkNu1<ZfyGx!<#ZF^<xw+Ky0A`QP%nhEorfX(;8K{P_=ql# z%7^pk^6*=-9-m!$gJc;g^X9gP;d9*#Fq-|G6M|gObaw)ju2>C4&)aCooJaJ(p=L78 zZ5w0Q+d{wecw_6oCax^4ir&vzg@FrCaZA&epy&fBa^Q0nCf*AqN~%rRZ5fX<jowk- z88FI88NUfR1_=kjIAi{nHVt->A8!8C!KjCBd*sUKOn*(k`#-;YD|Rf%ZuZ8s$ZfRT zNE<izJfhas8~LksNJ8hH7rN$75v%9DWRAjIFcz&v?WvyBSgQlx`pD4fTDEX9<Ph_9 zRV{D$MUGS$MbHzQ6nK$_T)1&+Bs_Tb6s|4Fpmo=;ax8BP^DCzFhxQ8m;^e<<7tNy4 z%U)9jtt3pI*#PZqC$s+hezLlEGVb|&7{g{c(o=<hgv`b%>NGcmJ9GC6nV-sW$u2=u z>8>n|ylg;ErfcK&)m2dR(4Uz2XEF||i4gsD6w0-SG6C~*@S%DexE++?18iNW;@_8` z^?4T>iHpOUv;i`Tydv=f->KYGEyjH45fdkwOkMBiz^f0kfa+UuiL?TQ8c)J;OQ#Yx zNguS8PQuGKW{{c@Q&-^hg`|j-l1=G0kf*+u6mEHrc4>OlC3-*6U$KlNno7fyQ)77b zSz^FwjYR7bWx8Z*DtMHsLwaW{IM^jJF8F|cHY{f1?iOLciyFL*2_avvXVO696;QmZ zmSzMy0&gLWdW;xYG#25frhfdQ$0D44&(+O4jka+k*yZIPiF~Zk^`$-nGJ{W3>7DT~ zKF^OkvT`IH_LJl%MTtW090!=4=tyn7{K>$A!x(r!h%OPSfRJlGAiY-b?5CWCz9)-G z|NBB>-|x#tUm6JoW?P{;qnVC;+fVGjy{9kZ#-VqI6@ETB0Tpj+VX=ZZc!jtL%n@z; zZ_jA#(e>fSSJlvm)lWGOpC&5hx~DEx`UKf~rk4sF4+ztJPW_IwfK7WH^QYhh9u2NV zzyH+uucIOeb@8Y6F5##qeI7Cm7O~2nhv?d(NF00`iLY8d!IF2*toL<eR^K%MUd|r2 zJUaU|r@2QKePg6?aPvsM;j^~D;A`S+Z;!^pL{;)s@Yp5p8^g6_?gX)AQ}I8yljLY- z9NhNnBR(7DQN}WrEG`Owv*yomxc4w-XYHqw8?!CKTUSHY_E<={_?T?HnTki+iU{Xy zjjR7U!4a+LxZz9_EBfaieR??;oHeF$8*_rFnEwH6sXBr`l!jqVp&Is#Qn%c?_ZbQK zc-|szH-(?BqBwAT1{;0Aoj9J|gx|x@!pbE(uy0czr+LzmZhLT(PHA<7qV7ecaOX%E z?>h^BRS9<l-xxF~SHT=bL7(jXz<7CmA`4!)!my)1qz1mlVvm31<E?#oEp#<LI@W<R zGMdT!@hP-5KnJ_S-8jz#YbckJ#)q$OQSI*acqCC2biJN37ynjZNbv&V;kgn=Ra8-> zFHPi3d@x^G?Tb<C-JxRSB^Z!910wg->B87>`0W)(tIv0nQFqqyAMq+lhXQ!@emup? zW!NNN!##6qL(N-GjQ&UkZiS$A=j0x(_kDj9t`&=*ulr=Yyy`u@I))(^oK<1`<Q` zT@kjgn~Q&z3H`IdlR@9(8+~4C4L$p=z<LK?>^$&+nQ}7|KG?a@YbiC*y+{$|M)^Q$ z?^w98B^{H#E<ibFH?VtT04qjM!oxyOt?_z)4Basv7w&enEPd&SHJ9AkYaJ}tJ1qmH zpO)8uH#`LilRJslcU?TXED&$hiu3EHoFo}G228ZT%yVnfgBfFIS=kDtOMe$-{{0Uf z^t~f|M;(NBHaP+vp10_w3F>GfF&`cbRtw*vDR5<R9@7_9gkjG2sGk36D)V>~T{Yt; z>3X{!{r2hL;Un#wq;UxK{}T(Ovy+@Suor8CkKrxy9}S3I3fFIzV(fia{F8B;c|1Lz zy6-e)PZ`f6*`ktsZf7(uU))pwpz$517Qd!DcGtq*p7)T#{^16dyU=dp3wmII5^K?Q z43GQUQ1hWmJQQP1M(ZdrclU(yHqZ0Pkhc?<1~t%%xm&<8xehR|l>E*Phw*0%;rv7) z_j3L>aUM4Xm34%B>HB+F=9dhQ-kMQ|O=_6C$pchZOn@<~e!-TmJZhb*MC>*#2iMa} zu{r)GaJM#*@t+>jyrcc(NtYAE{#pa(`xjxy1_S0&zBhYEREMfg4nUXcWV(*=!W+h8 zFzDf2$PSOjB&VeUH(d`q(^Wvj`w4hAt;dEX7wPKZ7o7d)1psdSBuHQt&UKmunR6F` zS;jVEIKEBjPmaL{F&>Bu+euTSH0-4sP`hX|+17H4xE@<cw*7a5^Vi8B{==6sEU64{ z2ILSo<8#!dRv)Nu1%3V8m{l>Gf*DCI7#=W}$ktl$Gym<h%-NBF5dtsCvAcs#L@}7M zE{1GzA4}Iyw8Uvy(^2_=BBY&J2I9AF(3CkV=;Wn!v|4T~zG5qh&u}6uUiXdrx#c_P z?`>k<trx{Vt*7V(rxXmm{)YeQE6Feq3k9E;5{(aeLzZRu(9$!vY4E06oP4gI9NT>v zv#;!BuiU?l)1+1di4%dc*j%cqsK@`~Uy-ld9ul9mi{Zl5WU?13&`!O9OlPjrLGM}k z+$xEm65ne%Cg~2N7nMl&Pf~#E2X{cpwn((=IRn=%#NdQ`D``8cjx+Ag;ld(>49lle zI5~I^eAp0#&K{JkRd{Nd<@l44^Lj+KEB>R?1}fo|i!sri6c4<O1!!a)Wq*kv*SFJ> z(a?Sc;_n;jEiVb2`O|}DW+o#Ie#8^0C3saN1xj+NEDJ8y!t4198Gn&|wAL`1%`BSF zo1V%cPTMu%T*VaRB6zyZX%$xQbwJa0S-fWxfbSj@(>c68nj9&kmN=CRe^7>QJ2Bvf zO;G)&FU`v~1l_SL&iigaAJ!eA?t}TnqTYlptc(Q3EAFr`=?#(Cu?6=yxWE;;o4EO^ zDmH#th|Z^Zbm$9%D8C38oaBMWgQ^9!b1A&?p9SMylycG#$jpqBA<O?uA~r9g;bEXL zt!%sn`kfz0_Mdws-e?sa?;T8(_8Fn%A`94ksgEn`_{^59_km-VkD*x3XxLG{6TOYc z!?w_3;yLLW8kS!`9BQT`U=**mOBxpTy5hZA$!IXWnL3w`#BIrE=*Q4RI?eeYdHY}^ zjqMAd<u?LhslYK-oU;M%Y)Gq@e)}KV2tG9TH{FbdVmY2ye$0hmn*i1`7&tuQ1umKw ziARds>-}U$Q<K^($T`>qUD<+$A!Nkv=q?8D<`Za?CX1hJ|JJ+c*3mpQf9$ARL@Gxd zg@-Z-F&TSsjjt%(Y3BgzU>C)@Joxxb94lmRk>9@z&}`8hen8d`-+qiEv46J^8Q2WD zneAkAV;;G<ESea(r?B^4C*YIT8=y4Th>LPqj{#N-aN<@meqrGS=n%B-1J^H+n)e-a z;H?DTQ<YA(&-cS%&GR&GY&@RaT}Ql{6v1+NIA*n*5Ov!hQ1sG?Q~J8x0)uA4fQ|~B zf0+U2>`b_8W{IRZiziA$$C%DfQ}N4=6sqzpio`lkCesCG<gB|Bp>p6p`d;wCLp2g` z|6(OG{!cp{5IFN6d*|UeoXeBB#`W`0mD9BcZ&Ib7=joy~NY@o?g{)IT2B5J39(^$< zuWRDK@ZBNoH<-lwynn|W9($2F-~a;uRg5i9Z3TzywWyi55bxB#AoWKg*`M<_k_lRR zM15NX){9@GlesK9XWbQgQ$9{$3QOY%ISGualmQF9TQF5uo8&RC=*-70kRq3ddh;dt z78fKFGGuwK5a7X0QFgJq;4g8T2A>-Y;QW{|usO4nUMM<1=T^TUwlB|dmYRh6X8}$q zIE<ryx6ptuqw(L?A(~h?1x?iUlI{`hn6+R6Nl}pEH9x0fNQo)3>vVC@xrU~mT!%x( zia4ivCAa3lHReMULnqH%%VbXxyr=;)=z)ZFM8z(Rq&=yFm1}=e$vGwT$(;?Daygpc z;q!tlimc>X%d5%l^;00ko`sf{a{Qy2OD`&AbKOr5bN|xALFR}IZJ2bLf8D1|N7i4W zJr?DdX1p8K7b`&8jR@#%2&IMV7jcJI5C|93;9JL75?cI*-IMWxYTmg=yL4-Xep-QN zdAWnUIQEpW(Np0S{{&;KeH;czN<+-m=d`Qy6DOMSkr-M>gZ4skYWG`$R?RGAMzYJ% zs+z(^l!l)J_VrGS!yu<2OPJ-(Q~qZG9;vzm^JHf5YVS(ul|+4Z9=n^~pLiN{1g1*y zB%x1zeLhtiS3uVLj$@Lmx~W2AknkLc5Q{oBOnbYWXpWP|(ilTHB>R!vo_!l?zb%1V z7p8C@_6?H~$=hVRnlr!`Awzwj8h09IF@gI%q4H81$r=hJuG-do=*=;(J3;VZOYSFT z<(|+Y=urj2ouX;g1?EOX7PVaPfLVAc8<+Cx1U;4DO5AU{?|cfg#p5|$XX^-)6Aqzy z!U-~WPXS7)4dLQwV;m)hw4N=*+`1S@f9y|Iwyc2V^Nc`$M>K8yt^@hw@=3i^KT+r9 z`K;-h@brrT3_J>;`!D8@uMQircyJH5$&d=n7!~jyvSNcr6oPwiG1G0Y0IOZMuvd-3 zz^!K?yiyv2<J-bOb`a3<-5`~iI}%&EuW$!hN~KLA$yaAnc=3}#`}V`Ay!8m*+nj{G z&-5_$@po#jk;KT92EwQLl!mI_B-d*U(EU{gXl;B!daqSt`pk<Mh!gpH(dWqIEjf&S ze=2@dt$^qa<Jo^xOz4K~@>o(4hObYJVAWc8u^t9<*`>XcVc!IG#-{ZF)u<bTH`8=* zU!WxxrraSt;YN6MR3%Q;TgRnOmglF85X0rG;^En9LzF0647caj)|(voLyRUY#Z~vt za%)59z}7LfsAzz6+GO2&FGm&TR>Lo{d7~kuUKWRvFh9aqC6aCS+Ywj$LOJJ#X6hyE z(UouMuHpiyc2A~pJC;+|JL%{eKb>E!I|vPOON0)wC{DI<lAueJQlqa|p!4`W%C23& z8uuI|_tP)a<d__RBO8QI`rFClR)V>+8>yEtD?81SqUVi1)-Be`q4{f<V*62L+}0I> zr&MfFSxrvZv7|8yPeUMMo(dc?=kczbJq+$}#-A74=xh-~{y*Lm7N3Y_{slEs$0=** z>2r!;|H6c}4ga7f-<t6+dk7My>kv>2$8j6u=#ZD7$;uPFt+x%jZVGG^rzli8FbM`$ zl)&Yf6R<<K-NOG;BBYH%x=ngL2zV}j4r;(N{X(c6{et#AEyYibtz=i282`X62Q;r% zGBz_$<91KsN-&fTY8r{?m8ybMH@DEwx22hDPOYS<b2q^(b4(dwiMH2PV$PZZ*!5WO zW-U1c<5Ql&%Si=-c3Hv=wZxOLmlWy8kr!da^iq1_YBY@7>j&C%I2_(M17+*_$+TA; z%#2}UoG6QU-8chN^j^?)uj1$j(}lP!{VZFeeTsW`a~C>V-Qd#2!T`A$aNvLq8X8z( z>B2CqynTl}EIdo-gqiiPO0;3)Q8%m8q3^-$<#>MnMorwbbv@=hDTDr_HLy2fJjxoF z<2B*}o_3iKs<$1sH{GkR39CSFfiokvWGtgx7)3*-zab_Q{W1Rf4!kEnmf3S;1h-Ex zD{N~SOPbeO<4)fUG)dKDzKi6*<{#T}lkr|^y|R~B?dt~PQ7c%Fo38ZH^0#QUxeon4 zRM9y@JkmT#j1}gP^ro}$vd5Yplv%^?QdL2xd?i-e;|RV;bi@sAW<sCieeQzMdXgw) zvDVo?s2};%7`AxI;vS<!aF0kMA3`LdGk*iTxxW);7G0nV4}K)WvjH_5=YhNT4a^sK zXipX-((hX%sf|e(q+Buv*Q>XH|9FJ%e_BRPiuRBjo&;xoJ`H^*Bgxf9aoph;!--y8 z1y@GxhM0X}_;Rwq=uSQeVnzB)LjP>xoi~@Z<nF=RDXO?Paw{kf?ZB?zhUlOrh6??w zAmHvWG#%f7bDeKc(-H3UALlRpml$HHJRY^$g5jm8(5Vu4!Sc|&yIe6wV)pJ7Y=0C+ z-i36KeUI0{--=C)-ajA-<&&8H4U*iNlhs6VQ5)VnR)<%tmM|43)X|{-8abOK$$U$Y zWUIX6g?r6?T>AD0nK4e6caEM+zFj$u2Fp!hsgX7fTJ(mj|LaWZlV{g$<B!wsH}0sZ zYXrGwJ0PZ1jaFHU(C^n0XiAU>=W}fxakNfi*Cs5X*<H(FsA$kqIc_4p+@*^8FK3~_ zi0`~bn<|wW7QA20X7vG9O7(r;CeVS@)cS4GC$P812y{8bk~=Z%f3JG6-1r#WK0Ae8 z3*{*D@+mq>3yeksFL3JDfq$3MiE6-1{Bb~&1iSRn<g6=n(!Uhmd;Cb6oco>|(o3O< zlim`EcUNKfoHJU|Xz15m0^eoFTJCBK#l0Tp#4-9PjdYH|fM{QV{~n8vvU7>s>u{#l zR`3C5Um>}z52^UUV7TfV#XPkS0HYZX$VaJ}?Dfh$ME})TdOau>-VBUIRnZTeO6(uX zKd`{jmy-CA7dHy|m24O$W9WF_SXg;x4!JYwFrEK7h>glS%sW1L$r$wdL%_kqv^b7O zqda%~vAlsc{di0RWTvCch!py1<1W<B|G<QvxJE{wSOICZOUW{U8?Z>RobD9(GfpFd zF(DC|^5<9StM(6Myq*<Xvmyp|b|Fms^@;>U$Kd+LrO<u;Eph=bh{eNXeD=eDAJth5 z`-NHPfxIFv56|b{Pt7OXq$OZ9RgFq_ETMWyPskoSC1%4H;f&-qQ~RG;z+A{9izmjD zw6sY2t+tg+I}?L9vkF1BI*O6Vs$qXR`a*(BsE~nsM=ac;QMFzVb`(|+ZRJEfqP`ys z*2K~Y{4=y_$ss2*_T#aLWDNhp(oMV;rVi}KzNH5AnEE?1=x9vVw<=(V)m}I_berz{ z>xk2D)l&!d33_Jev4;+Ry?p;g3C3r3aC_YiA+mb`C@hfR>nDcbsv?f&@0CNp_I5Cv z+XzcGZKkX24#KOyAIVJlI((HdNK5ywBx<$|w5(enkGwxd-*5B~V8=h<>DX)x{VI*k zpG?5&*M2I!Js!HkmZIy{Uu0?s6*AUh{Mq+5SXrq6d*}Qi3a^*JpLk$Wm(`NNCz`}N zL(o?C*I;h0EIZw7I;lCkS@1UHqFKycjNx6O#Wn(6GN-}sVLANtPlPw|?Ib@puEnma zf9d^c7J~jAK_-iZa6L-X(cR-GaY;P`EAuq)>fin3hKCaTxi}s^d*1-<$*Q#IhXFb9 zsEEu;6M9%H6R?V=adI>FkvT0X#K`F$v~TMp|2-GuQ@{A3Rmuf2a^pBW#e|dVMo}b0 zW*O>v&*q(0M$ji)rqP^_Z!JbAy{8*iTOhu#f}OUqa8BVYWCi;Xzm0Ja*5`^pZq)&I z=rgBWHIMllC6ARy@}Z}N0{^)XBi>lzl9fhWLH1g<cA*+PKao!LrFWtkY{goSVrG0w z5FPpy4{y0j>OzL;1?ol)lu5EV_6O*gxD_-}(gS=V&Z2v<60e?nmhA5e#-b-OkTf8{ zUZU-gK7R$ch?;}{-=pO1@=2IxqKm=l>hO)9$yIxtW2}-!;D(dOF~smBH|d}a_dZ$h zV9gq$ak4JVl>ByFSL`J)<_B=f$wMe|wggL4yXcP*x0$Bq=X8m{?hhyl6T0u-&{K-n zX>vjpw3Vb`R{9&Vz4;8ee>Is2viS_!CTo$K=Ria}LvgogGGAcyk5s!RlFN5Z>zB@$ z3+E)|AZT_jX1&X!lk@(=g@I6S{`)Z0qCRuNJC%3c`IbAb(n<UEdT3eRZQOk7E!j0m z8%j>U;x7Gd;V%3)KqS6u^G`#ZNmqRpJ1^G+&!?E6-SBOEx4TN{CRqr}9PZYC3$W)a zo~Yr7uRl;_{{Q#C?$malG<`L2haCQL3moLnk(N)nMCwE`IsV8BpG2(yRkLaE%T$lJ zI)_5(`D3_4`!8)CF^#{q*%kb@YYC@M8K0fF3O~O05U=E?(71gHI95%eq;Uc!9x5hF zUS`l$T~BG*=kfgexngw=HKBOiawBKBvYBc)_`{;<zR<izl2sG@asejtw4vu0iHw;| z)FbYb&ZcLi)9w&@e$672)}8|5IR*?@g)#d^Z{tm)FOd?N@whW_1i0yr1DzmByfw^# z!YZPZ@|a%j4Ipk;s&GwHvZcW%eNg``iPF=8m^iO5^lY#%Ox%4ASG4pIC*!l2Y$VN( zWqUXYu@RU)q7rYvt0%wB`WZYr4J4Nf`_DNI+-X~B@<_XtJX{<I2Ohk|YN`K7e1|3+ zlBuB+=>wu=*+Zv(*+ldW@59ZcIHI4sl-*xg483zDiCFpsc)es5+Yyxxi_hO8R`1rK ziYtZgUPkaK{HfoG$LQncxiInCl=@YhPLl<ZUj?p^BpzEf56|aE@;ii{xq~zdzh0Os z@W4)4%6;#E*Au@oc@FtPXPQ1POYnsW>wb`}OX}!QR4yJ)R^<<R>Jf=J;T`^aI?hYY zhe918G(5wYoK=5M?X`s7(09FXA<2UM*&N8e+^<EJbey26g72q2qmHV{?ZozPU%+2o zlGFUN9__}RMTc*4mVPTgprY3p)HXj3>}(cStX6?L!zpyjyaMv`f-A;MoQ{!34+v<N zp<_WYGdH@6WNuC+E9xp3-@_~5V)h2utk?|?zE%?Py#zl?IzeFkejLuTXBGE#(y^|m z;fuU77Ox(Si?IZwo9FT`Hs6G#^|AO_Bc0ClQ=?~GOK40(Bs|QUj(18Iu`91waNpX( zY0BLbFxPP<7TasW@$V@(#$O3@J#T<WKrJ28-GnpFmqOFXxtN}+ic3nfaEglxUc2p! zsWm6KeZqe6_SH}l-BgV4FP#NDOLM$@bUhuEUe9lQ>Ht;q`#I4W&p3nSv#9+LPx#DG zi$kS9>9rXO{GRRE@UhbxTI=`Yb(xzu>s%r=%3F-v4(7nAE(w16>mU@l|CqSTTZ8Rg zTTngRRo~lr8rJyUpcb~L;MuwveEH&jqIYB`oH~A!9#eUbZqrL4=!pWaBk++H3*3(R zU!{0hngV5p>mYDREV`_4Mvb>^^!MWm%TxiktGrm~Cp;~SvZm&^Ju?WWZ8-?K5gTxI zx6qN`@DSn!?$`9j9o(-q*7bV^pD?Xen$Yg{lv8Ng2wUxK;lP~%oVa-bZdI#c-fc6% z!9!+vX~QLqJ{^N!+$8aWk0pA2{z?Z8(pc@-%k*1&5|*A&pnr~Qg8l7DP!@L-AIuWL z*HM}{dt5XTnIm+-6hx4KXNnL#$Jgpu+AzGf*5IcuZ>6Q0>+ybEDZH9_3jQ@u!mqC_ zaO#u=Fa&EM$aexbsN^tnX57R<*ASHXqrg~;jKT>=uaG^A7K%SyhbOs(#D3Cr(%XIm z+(veD{U=A^?%-^+6Ig)#C+~pXzsb14B8u!1^nlAJb=U;+W$di4U#ZmWhiExef%?)s zJrjQbd&14BcM*d3=u?pP={091qQ>9b7=fNMWY}vpv(fJPY<_8wK0VqZ<S_O(FndFy zSg}rbdgRC@a(ae2K5dYPU-Cj$p=~NLm7f7icg%+&MG>s@kpz5HjCR7aes@<b1}#$s z(T_JMx}{L9Mk%m1*9OZ1PdHMX#fkpBO61Ibb9*(n;2TaBbl5|rc=l9$xls7MpG^{) zykWRB4AXynBKB#EQ2z2CZqM{;nmss~x|>X(2Rej8@hznwzCl*#7$~6cm$cHl?|I;` zrWdUK>!k;q?ouVK<J_z54sg&)nym5`$JYEXC^_H7B{EI4Twa=3e;AF2wYKA%`_rh* zvx}s^IsqPbeysCXkY!+3H?eEzAdzB1znV`9Dx}2VZj9yH7sukLrN21I+zb+ya0?_3 z)}ilQ5&prK9dI`o_%z)_vS|M$d@)M_W-$rOr6)p9YxN@1xU8D%c`r`Q2M*%@C^`>+ zD&IGb%U)S!q^U&9N)qR}uSY5omC-;$d!bU_l7?gxqRcYWAe2#r=e~|aMJN%<Oj{Z> zq*A}<_aB^dUgw<WzOU=^dB2x6%q5z8-jR796-fBEJ|-bn6f4)XkQoCFq+)kCJI6>s z>F_M_tu0hwv|kg+ZYP|2{1|MoX%b#De9BRN=jeR4n~0km&>Jpcv|Ri(@h>}!0f#rk z&WX1%Z@e4Z|5{mCpIijd7f!);$<Ord;W{Ez6(u{A0^r)sbi&+RO&)wrAoKD<=p{ZM z7k|;7+H0N{I>j)Yc+(YH(DstM_0EcCb36rqcP0EaEC+{E&wv^4^L%<I2T#ojCIN?v zIO{!gv2x~m2#w+M@s_`dLv93pxLS=-SF$FTjCyFOM>rUN_8=mwB0=-0JROzN4=#FR z;C0O<YW;pJRvkWrQqj*y8k0dAnRr^bd9$!v7>EO}?!qyNbb7{i87%p&O+Fkr%Xjac z+0LV~!s=sN==|~&sFe7|O|~4yC+YX;L#0(*bIvy0WOj!x`1qH4^=v}J86(UGRtC~u zmBI?;T!B@(4X#-iLVZR)bDuZY;h$SBG{Q>+SC<5n*xO6kg-5GlYu|nF{qGq`^cjWY zmj}Vvm|IA++94|K6h4Y_6Fv_;!sq%fLI(robGK{}>SlcqED2r)GWsWJ>2d?iVl1FH z`84e|WZ=!*a2n!iL^c!|18Zgg*BSzt1FfE5UYdYr^Ri)z?hm3j-HYvt4Ta+_n)rK9 z2K`tii`+yL7+hvXvuh>r>sbjroDe{Zl`C+$NiuVyi^Z#tc^**IbFO;5IRDyi;Nydi zWSP=klJ;sZ{H<ZIGd==r<;1CBuLL@qEuuaOLiCmQW&e(@rz-PjqEY2r?#~wmAamql zW00)SBQS@`JZ+$bJ7kfkg|le~`PQweD&9#L2h!T=cw*I6+}_wpbBgsrjqfDY4WtN! z5vLK1MBoWKiftMffe%#FQBr<AU2x?;dNw2$l5(e@6Yq;WxuA%w*l&SbOtkRJiv93K z>O9Hbvy{x~xk`&aXoAe=@6676cXnS7hyJ2-SR*BGG88YsKBHo6Y=4R2pPNX`-(-B9 zTtrOy-)n5p3tV!qobk1pghBhfa7n!~dfcoc3FU|IfTb92u$T_XGC4$c-3zM2v;Eh+ zyTSy7#ld8z6)Fz2aC?@>qK>9L`K9xR8*;gi+rk)Tj9&`#Z)h|uI&l*uKA&MCZU5jw z)8p8k+DGG-B+}ho{lwS7NT6>eiZ<mS)YEgs`(Z!1Er}~h%#|lhP3>+}Q>CDim{sn) z=?*w276`V~WI^1jK`Q!_cit<T&{0tnq1i);#uWzgzOQgt7{EK|iuLHGuCKJ_rU@I_ zWdMJ4Sxn^rWqvF<kB<Ud$b{2ZNRR0h(0IF*tce+qErOf0ey$k1d_9X6+z)Qq#{bCV zwi?V;m&cq}f0>KdmqYYpZziK~68m>*G2BnGhL7vUgJ*^<HMl<xGxfx=;Q4Oont6}( zzLX}i=)=A9If8TfUFr1EF3ge~Pb}4b%gl5#Bvohl-uA3XOvL>pe9QRLz|eSfjHmSJ z)mf0?-b8duvgyspUS_3<A6^*kkI{0?kY|4m_l`LYTK=P9uT2TFc(oB*QEGyLK?7vF zSvEE=xg?zJDGQ}Kh7jHpj?NX55Ia+e_lBKD)oKN1o~Mn_u(qQ7aGDde9=bu^)~5&^ zvz<tm*iYJYxSqQ=E*V`LB<T!I2gtS-2UjC;GIVY#otZpYc=?7njGQ)Pf6=$p+usCt z1)RsMn#T|?yB2onTqjz;rVC}o-cw88(L$$EJ2){$1iEsgsZ@#-d2;t2Tv~jU998)b zQoN1H2L4>H`(rshQ+o#Tj?80Xx5q)OYA7C>?u54coP>_^GD(HzZ_Ej}P45}KV}7sI zfSg&)AiUuSD*J>qGVeU~$}1!DH_35J%&n+mh>cKs;~*`|h{L5Y3hC&{SWzDb61q!Z zWcV{oPsk?rh6S8eL;-pAB$!Md>rXbHUj{Sz``nO45BdEz3!cutPQpGWF=a=+gg@0B z$h6fL=p5k(a@brRUM#mE@_g=8>4h{5%zsPY1t*ZY8EI&Jsg-DSh{4^iqvamks_B8% z%jq6D9dOI;#AN=i5T%uj{}x~2`_Yxe`K3DE&&$KD`FUWbE=GO6d>}K%or6{3`^@(= zd1GeJ2oX+8ff#|guyxuy-WO6v2J0qc>R~m=-6SA=H{!|uHVJn7o+o6V#zJ<oLo|f{ zSV%hdx0A~$0=7Rb9p<WBU@}`zW8n9jaC7W7eC?D?X#Hts^xSnIzx*OGT|XLXhuuiD zbQ-mvDo%CecMC^M%&@}aGA7K|Mft)+MuJmdr3~9h)s1IF!^0e%0(XFWpE%g`In&%H z{uuanp-@h}wfw)1A4~~3LsvEi!Kds#FqPU(a;)EyU8mh~{ohDv`+W<_1b%FL+8ge@ zx+xm)nb3DSQ<=QiTQMo(8~BLWAlo?;B@eEk?13VImeOb1AG;g9qmD!R@p|s|;4b3+ zw2X<-Jwxn2Y2jt%QoJ9sk+BnJa0`r(@$Ob2T4_kU3~w-{m;+zB-9UTKJl1aKAPF>? zK}BtU5#V-Xr%^Px-aAb@F5Ce5z&Ut8H5Ch-FXHlZ_QJ@~H$ZtIqDhDvnw_qpmzQ1S z{594>S>Z-ZJ+y$0JRpbP2cB{Z?z)jT>x|J^*%Q8R2*G~43HbiqU8sMv7T*tCMaxJ7 z_QB96`dxJu%KDe%)W<y6NOA?9>liej-f;n(<C{sKuP2TaH$Y)&2D-^iz}WU}!jCNh zP-xoC+}06cdh*(6i?1xVQ2<1Kh7^u>lNTBerh?b}GMK%!3Z-Nx3Y8{E;8@)lnzHH= zjI=nT_t#K5_|cryyf@=LbQ$Dm)J%Hz?jw*lzt5Phtb!F<3c`;$G3C8q6u}T<h*`db zaDP%g<jwt#4Q2@Eg{|ba?@VElfe?cCWRe3*ep1ulnYiMb9JS6{OT};6aU=Yy%vFvf z*79oT@Kgf_7c^1pqEYDMvj;|=CWG_GcGOuu9~L$r<YugTL9|aDrj>qcaKG(lQdt{i zKHK##-d>+i<J3OUYh?x49M^<Tth{l8{sNRV$;1UEPFOY#xi_h!*<~84D851;Uvx!K z{|a%aQt)07H;0$rfB9ryrnLfpKZs>kcN7vkZ&B!9kwp$hY_QPda|{iJ-|)lk8}zk@ z1s3gbgS4whK&o6DLyQ%<2rqfK-;w}YNj=2y<9KKni^5kufb);P<6=%6z^;g|%+igc zsOvc1)$*!{EH(CosFDfj)^o9p=_uk}PhN<9AKc*G+7M7&zZqv4hLC$3#>0dQZmgBE zI=lAjX9}A#`L5PMRBxza6kPVB_nlJm!=x8{ceO%F(4*32qVmF`hzr=?d>^(-Dq``i zAmPF#Pw3OzDR@wPKm9gd)<UT_nUngYK^mVf!&Gx83S(T^{f@r0FutE$IJ_MK*Y4#r z5@(o%3MpapuMF6+JA%)QIg<BtHlPpx+kH?ok1Kg~hrHR-OWd7ylF7y{;GkN|Jhv`J zf$2ZyxB3N=f8qmu?|2&TU!QBfXuT%%NU37?5;JU!e~IOLLYaz@ZRC-hfcZLuclXM5 z(1}X%AgZl`pMI1xi&jjeBW4+(JJJkvmo5oU?4ZNlWrC~=-f+rYfj&9!hdoz<p&;)V zzF1<9SDyG0g`!H%<C`Kqm~o4$JW68DKK6m|@I~Z5&+F7JB#$)pz9s=>R<MBIwKiW1 z;MyB{$;6N*1fLlCsrMM?ZeRq356aQPp#+uqZsnJ62Zh6N*T}C)fw<jB9>Uk_k-a>l zbE5r0@_OG>TEEE&3zl%S;OZbvlu+Y5@A{Dyr&M8U4nq~sXhCDd3sUDF$d+v9?+x!R z;?fQ7oTbDOoLZ-g6F<qa|AvEvo#%S#v5M#1?|-5oyjx6<t+B+CWGmP;v7QbEMZ>bg ziP-HS%Z_BUpoZ>hIDfANe$MZv=Ttw#p}Q)W@?jUe_+5S5(jk@B^qz;jQ+z&So*MZV zH-}c;i50SA)M0zYCJff_CZ88v0+$C-AY8E;GZ}Hn3SSGepM0S7zhAU&+79xK&q{k- z8REJkipcMZDMDU`2F2meX!0W+xZ$70c?Ha(d#6zFXo?m*pYj&|MU>Mi5x>AdP8;(2 zgPGd{@mN#y8WWX9h-A|^lC-Fgn<KqPxYjQO*VgvHk6Fv{y`~HpzAL6GNlo0+P-F1u ztR$H!SDE}sOPFKyg|5qL#*I^Zne{WGXw9)?JUOa>R67#f@BW2Gtp1PKepd$#o#&vm z+Z=U7y67QwY1|^SmfnedgF|gwsH#X5ZN9ga5$!Z!zpQ8gr77olUhxmIwf{UdiH-x` z+<5G&oz5y6`k{e}wQ#goFnL*a3XTf=$)e_5WdA!)j~nEXGdg4ORJtSHez*{3>3MKV zH$0#h^?RA#Y!z%sJq%r<aZvodjcj_60TWttP~S5QRK=>`@0M;z9TyAEQeE`&s$aC} z<OE{+$ryZswxfffhSC1JmX`TWCG<@x${O#6qqSqOD}6C2w<w{reF~@Fw+7#xeb3xE z0nB5y5K#7dNA-&D01e0{2HvK0cE1{#5Za5km%6d`6?}gx|2<b#phtu?(!5XO6}c2q zij%rOkOb>iMxJj3?zfj?LnSjH*u)(#=NrOXp0CeS3NWWz7K?qZK$_<;b!x9I4YJC{ z8Df#;%6GrO^$jO5E%rXyWTcA?Guvr)_g&ce(Vdwwek>S$ih$dW2H>dCL0>jphMtv+ zX^~emb3I8E`&RScliT6kh6jsTu{V4MTzVS2=|MF$D4T@#VK;HjfgUUnJ5Q#M55~dg z#q@y39lFf@A%0v~ML%yUqJBDh80GAOm)*yaX~zmN%fpnWh<qaFMHOg6`ehRKXNara z%<tABC0UEZZ(+D2raVE<AAd&PBjP=_<f7?6ta4t+d^|A<BcBvP$qrXId-@)=GmF6o z0sQmyt_dFD_c+f+w{y2m0%=#cHr+MdNw{-{CVFa*<6UNo5b=2}OptG;-@g|^-Iq03 zGp`iB%=<@oy*>v~7othDk~yk374nSsVv_l47ajd07j5Ggg6zyfeAG0W_|{rtMT7-7 z>x~jr7rEoK!OM8ycpMHYYr-REKgg+APeIKMjJhw-pnnVvi1ve``;I6t^N!?12QdjX zsdz{G3Cx!#RC{m~`(V>bI^~ZAyYAc@-VxYC`d{RdT^kNz)gf=1ZNCLwRANE$%rUrm zSqgXDOClAA5-{fbRO(;Y&Ak=WF_A%XVCK4#NOwsHD_=+O{R4SW*s_ATk-iM4z2~#R zk`W*yYD+A={h5S>QRtL&5Tz{ZFnYmz_~OCmqr?}2__~=ee0+#YjCW$)KXuYqJJjKF zbT~?$e;~|TxsFNW8Hkr_WQ1S+?~)z=9R{g-H`F@TO)MT*3k5u5UG5Pw$v(#+jpPd} z-?+gkbv0c5w1)R2mXN0oK3Lcu3x++;5F4%m+k9m(W3GzuxbsHnaC}94?XPh~_r&SB zKa25<paKMqO7Pji3s%i<MQ<e$w9Wd4Ssmt33KB3TqlcRA&F8q1+tA#SPBg~~p;s@8 z^C*8zlSww3c_)LOYY1(1%LI?OV$44@9?OcHggQ62kqf?WaAsZw8JoHar``=<_U^w4 z1N`_`{_Pg@Y}`Tqx!vGiRr*27j}A`bx1CVJHW)u!-^S-+V{r7q9{i;h1p$k~NM8JG z@aQw9FLsqN#;Yxuf`#s6-A;43bz2W+Hjc$r|H;C%Mdf5khXGe4!@CZ0Rtu}=MiB!y zJzOFkM<4H<Mm~(4M5dR=kjhj$7_~_p4|Sg=TtqG2S~&;04oE^?{8G@go`;nc3+anf zab%goB{U(g7!5yVJbz;}^P$Xv$hrq{e_J2ZkZ}|Of2m*u?_6<RodRXbMO>=(7yS7o ziNuu>m@wT)I3el<A<S*g)NlrxEcr>kM^}+n)k{QTuQDq>Pnzr>Y6owf2J-&FLFRSw zF`~Gw5;8U8;p%b?JRvp~FKkbNjT;hhkA^KA6*)}yTB#HBo!um^Mvt80`xke_YdIf1 z8(3>OR`}09gqmRiPCXDxt8}YKOr!`q^VVguCsPyF9bb!wje<b=WjJY`oPe@YBXpM5 zD&fqg2D)#o1ST!i!<Pza#Nc@gELZg;#v&!K*e@N0&5K~0!FmX}HHF=(&`8Tx1)}?q zKS=(b4(7)VY3%QhWb^1?oal0jI+rYkWv_0KO^<D9G{f`NrL;)OR0B|r?xaulg@MBE zEnsl&0kzZ1#I>ylnUU=~8M!Tw$n)?uu=$w>Ra`Sjg02jJ-*hc_;W?3gGy54~qnE;w z*d_FRiaK8NIZa;s8WL5$8~wvr9*?-iph%E8R+Ix4lP<EwMn>qcQx;cGc}f$?b(kt! zE0Av6h&PvvV&janumi%lDAzLDq?kt4v~A$6lQ9|?RnqZi^T3~<<v%|<4(F*`v40I0 z)72?gu_pI1-e#WDb)Uvy>y&uzB+tlkc(4ElPOL%i%rY?l^#}jXP(}CaKk;IaKUC&Q z!&m1%T6bkF`tMW5mS?`?{^xGG@XL8Lu8)TC4&TXPtzcZYPfQ56s~L^+^YK3uRdQ?D zKVtoOG#G~dBBe|H;kVB-1_C8W<<mXv`_m#g=1?hEb>!pZb#8d7lFy9}k0$M!P1tq2 z6g;-|@iUNWsJga_Bv+dWla7SLt41lRJ7Eg(6%k^@CMAp;*uwqdxdhi2o&uXiV?gE~ z&yrUhp&wI53HyQ?=oq0Zl-3;r=e^cA-{&A?=GsH5e*#STH$=nE#&Cz+yveCUm*~a5 zMzs2oM8CYw!sT*>m}D+5-1)+g<QO*4?=v#c|Bf;)-@cKEJP5*<!;^8=#UBDDXBuu% zCVcj3C6#xo#U(-6bU&Z}DRsQTc;$N#kHDE=_PdEN%N#B0&GjL_avNUzaG&HV{iM;- zykkr+QjqP{RPI<dLTw%%#RDU=;c`Se`8Z}g)I738js9tv8yo>Oma!Oqa2mM~XG|w1 z<r2Z4m&EpFB={uCp_KY*`nBBv`sS~t63cm(;{gc>s^-XL)z_r?tQjcvhp`)#ZovDc zYiOJO4XP?O6SoboB|kM&Flzxvs;;kwlv}~DK4=^cNKAs?&#JHxtLc`|U);3JLZNtd zI_5QB!=ctpdZM1Oc;2axDx-JP`30w`>)j``Sx3xbs(d;6<jp3nLo$%HEda-FF`#;9 zZlOtu2|Fcn2hZc@v#7Z<Ij(yLDogirEk3!VK4L#q**DR_{|3lxx(J*?i&5=`58b!S zoAyq&KsG!BHCJEcvxZVMM@b&92UX&lG4;4?tqeV_vlVh150LoTpYYYz^UT-7yWx1- zMxOn(6trYNG8VPx;GcgEv<vj$o*my$OLo8uAFqL{awXx^Z&TH02jH%G5?WL}p!xc8 z&=D&~)>NgF9ar8`k@17HpwksxCQ1Vac{48}$H0$96JlPa47B?o8NV`v>b+ElCpxWo z<e)w}A1&e52IVuIl76V$RfZxnjbKfSpK#f7Ip*`k5ZtC#&HVGbPWy`;K>X<`dh(GZ zb8avYeXRp%>&6r+`eGD)HR%K0y4sep9Hm5MTU*GT{1o1|F@s%^Z3CtI`q1#f4{}I; zF&-|QPW=P!L#1ng;L+#xm}bD=@gE&0zdw}Gnw1~uXz$UWyCIoQemE0myy0_L_y3Ts z1#g*xWGUiY^BQ)1J4J2!Za}IV&$aC|gwqw@Y3!0ZdgQe@eB+-BnZ~WmhE1MytiFx# zQ++aN8sksL+jo;Q>%>9tXfOy$67k5ISzJ?$E2P*yrt=E==~SNe;n<^!-(uppoeD~z zFz^;PF31C^H+(Pe@((7?*N?mRX(E|kDb8-IbH=m#+Mw~RJaYajtXhx<jJJBhO(7C& zpXP03O5ZVQypJxUP7`oflu*HA72Yhk3|n=ha3aU|rPe*8wf;`rr-?858Ol|-AO5d= zuhC!5QRXaK@oYx>06ls@m!H#4JcPBHlOW;F78J>EVD3Gz#G$Z>P|WuvyDhY^&1WvY zO3y79-xov<JsB;`XpSo%#Yn^HYySieo>J`63l(r>d>C{)EQfUM7`o_kE7a<^;M-*l zpv9SBd+svfdd`!I_L@R^{EX7agQ9S1zJM%PA4}d(`a@;6dt<|YwM5sXhkS$0_?XWX zAK8<Duf1Q93(ht$+u<>Z<ol@Ud9!i(kOaG6R2zIOO&9E&84d&CbI>u>hIU?)C8q7^ z5aDKvHf{SbW8*Y<B_~EQ^CPe>ry34>j>nyi0g$ouB`wwvg+!mXw8#7=O<)(HiDx97 zZFHhCj2}p(6*2pG_ukD_he_V3ZnVDj8j6Z7so?c#s%LhZp7B0NMlExK!(+wisH&;p zDfA;NXH*e=hjHx30(~&(5#U{J7~W5uB-~j2oVJ>r=5(F}!ou(W%3pK4z(J<~_wN(M zBNzR7=IA>7aV`$l*ZiiljMihRg)79)R)jSr*NFCr5tNO~hQOe&+yj>ZvZ8}hIf*<{ zn)`}!9}PfPBbuDIkz#ej4AInOHY>k(E&2tj;koiY%sa6iUGJHK|F=}EJC=ufi#E{( zuE{7eUjz54&%pKGx|sX;Inn;4gIj+W;B?({Wc9*>Wa2ah`gtY4Pi^{Fu77y~hD;P; z&o<2^;aJL;*@*~m8QMV4uqXt(cj0kE7OKvir`a|G@ZgpT2<|k}-oLSQ`f?>StsUW6 z`3s;y-x=Mv$zx^aXjD!&5`M_nL#vhYq(9ac=JVNBf4c+Z#)K<SvGFz9cqp?S7R@v= zQwo+?nUVL_Q{jAKJY766hkTo~5%1-c;5qX^ko<KBhnJnCPcB6ASyo2a<h_W7T;x4P z({^C#w29QN;Sk-ly&T@Z9D}F$+0TQ&adgA35i;E*kXf(22oE)N3NDNC-pCR~%y$ff z{~A=dE~5rucK@QPpY+)|vvMJDe+ivEIa<&WdJPZ1-2<P?bT}g`CpfO+1ZR|;(Xd(< zRLU0<Pl@@k`gJPRjyyx}@9d=YE6m~em^=7PCX9YGxdy*tu9XiD+hW4QpVZoecL|gY zpzY#1dZjjinmAm<;<3#*Q@jH-dM?n@JY{_*&yvc?F5tutS+lECU(!)Fk4WB*Ss2mq zM)<K)3FNlS2eGU9_~erf&{PH<hw?MtWy6Awy$6L6^4FM<gZcDhF8`h;-4PnQc0>O3 zt$0XEig&PyvMufx5&9EhYe6#k{n#EtX8DkJ2ULY8<!Z^}syV_r#|5<c(lAjPFhq9< zhaw`5!KxczXV`me8<fVT-bB1U$_We>eloXRB0_`_YvAj+Y6wphl5Yodz*gAI?OMK% zi0=7{rGK828TU0%^GpiVt47lNxjl3h92Gv9s0yhKZ*f9OFZmbBp|hZt=K0tXt!hoM z(e=Yd)8ky<Lx#3E7lTQYK9^dSMej<F!6zZB@#_&6x^DLa)Lm~uIx?)ezGaul`VxJV zzbguF{8P!#eYxaoSQY8a^dtXv`eFIDT2e1lL;H8NleQT*=mNiDT(kN+m&E9!B%j$H z_L@LvT-(Zo>`Ng-`TOCfmodx^)Fn}W{c$DhMIKs==W0Se6TRqkZd!H*BYXBJz4AAS zRu+hW_M~v;ycyq9`m9Grd|r~Q-9NeB2`==Kf(br!G=iq<hrs-5ta&>32@5hO3kLf& ziTAr)Jo#z~1YDYe(qk0x+T<)QXh$!ZoH+{Jlr`C=_wLYceiZ7XOz_gP6U_B2H^%j^ zG3J;i!z8;P<nHaEotgnq;4lH#-nl~Po~eQZmCkfqh%a|xaW`!f<T1(3ix{_gArR{0 zhf@MK(xr|aG`~k21rLS=P2&{djA9|(b5#Wvl&J7|s<W_U?L|teKA}#LBGuF1B^+Ad zfwC?U*f8G^$2-VC#nR=VeUk6%*#^VV%L_b%?<~KQ9l^#I0&3!3Kz%l^#yHU&m^sk~ zeB^h*ylxLrwmX8a`rFAR)p$_V<+~D#jD=;ov+;TBG3K^b5Y)`PN0SvRU~kV<a2|V) zzPLCaQ{oxAH!_FL7mK7dU`mW$2AlUDTSh#)`ykqOAw7Bc27R@uj4qn30CkcY_~51% zeOC|<n$y0Q&r;O|8}SzUtKJsH1k;eFU4=<6Uhu-t0ZdsUOV#ps;nS8LZrg<Eu*&ZY zPORAu$phK+weBOv<a=7Ve|8@=%(+O#_mq*uEL(14e=C&#l|kP{;Y90RJ&26*r2A$a zLGoxWo=LLA*=n_9+f`-qSqed|)1DNqTEnf{a~AAQP8Uvh>7hL?LRuM|20I6q!jG~e zSbB9IzB#Z0tv5dA*dX~btHeBPJnjbRTiY3BH-D7=$e)|FF9IiF%%le?kfsm6iH6B+ zut>||9whKxKI>lk!|W~Dav+ZFmV8A6!xoXX=2F6LeLq}a)l3{D73s-0vS<@@53+-L zaQ%dIo*Te%WoHb8?s_f6+h7v2@OM95tGu7zX-M$BS4n|G;uX});B&%jEpa$(H`yMN zK`Qd+3e#s@;Ray?skvUyMECBdjCCxehc1SF`=5Y|y+8iVQpd<&`*5(Ms4PkDEXMK9 zMXC3F^ks)9wbuqLS>H>_K5yhcpN_|$iaYVWg*cslIY~HTXIws}b}tF{Pvg!>O@l7X z;2WbC@wcfK@8ylgOSUr55@AO?eua|wstV@O4h0K;XL&Tc7m0at#xS<|99|=#pdx({ zgFcOe31%X~+*_VFrP3bOXdEfiKQ#tk9`WRvhGiI|QUY2x`{|(QX1ZhE8l1v&kX<wO za(6@WxEUdyFvmOwO@2kdz4bNJ){&oyDrS<-)ZOImn6Yr}#bW01v}!i#ViMQ~%YaMW z-}1|O72G2K8j>!z48KN;LG!MqxQ`R#T~)Poa^*qx-RE6scR*5j|8X`g*qA7+pLv@6 zo*9d-T9>Gnp{WJub&Fd476B=T<M3;46n(u$#zH^pCGUfJMx1Lyz)tV2Ab0vadPj1Q zj(lIrp4jY8w^$aEy6Goq`KL@28+7Jf5@W!-P?oYUjtk}rwU}zBR&rvDKAx+LqE;2z z*g3a}R%vd*xBR&ZFZR*gj9h+4au0tdZ3W9^GZ8-p!$8XnXo5lf?#X~v=n9y0ppoud zd7UgCs3beY6JVF)FgbqD4&IvS2!<!d6L#naSFZeqcwgsdNWF2Sw%-p^H-^$(b~V&u ztUhp|d&s0?BUEx`clrBOE^xS76~2T}^Vr=_AmQ928o+x-mY$8FKb-8aMNto8RT}8w zs0Fy>!3EN{Q;f}LSJ0gKGQ!_Z8ZdP?BQ#%BNoR&7^BMF);(kNF{HMz?_<m4|yxYEz znk$~By--V)pNZi|^>o@ebOrD7teQl*)!-g#M7m;gp<t{lJ@d*27RaZ-)jl^k!DnTk z$W_yZyp1rA=Uq4+nvD}@7ov{VX=3=Qof&cnr5C=xCiy`taD3=6k^6ZOj~1_kiIaO_ zaaaZYc1w;8^zWdh{PWq}njz21Z$X0hWK0t?!Xx3X+}80NwNhS1<Nh4R#EGkf{p&x_ z_V<VQF5YSy8I?{i?Z3se@_Ch=(dTedSqyBMA<h_VwPJc#^pZUdJMs4+-V2g92R?_C zp!hry_%6Q^&2A<OoPxhF-rRYzddC!2QM(AoxfOuA;#7LPw-7h4zX_GMjG;U%jV(65 zgqoGU<l7ffm~JEkQ#Q5Y4YLHS`(y~Np4)KU>Q`Ltc6n^e0kr)X#uh4EgUD5f$jRh$ zc;$l`cK5W<zchx9T<)hf|79}!pV=~x{>{N9|D9oEJET$K%VmyDsD$f3hly%>6t+DK zW4g_f=q8s0+|Fmyc5dHGoQ^1hChrg3oFc*|Jd=arkOgEc_k+x}3V_$wB<TZ{AF#h- zCk&)r5*B~Wr*$pY%gdr8==QiiI5ulCiI?dilN|eqyNfCPaO78c?2I0g@lFy&<=o+m zX&X7_T}{62F~b8Z9AK}rJZL&oI{C&Dw(`kT$p3EvCZ>Of@tRZ6f08Xq++Z=q%n91{ zg9JwUCowj+9kx!^gbck)XzcnCE_i96y60Ugx#%f<u}}d<4&0>4+pWoh4@QU{P4L0% zBD3q52TZ=D10}?#e3VEC+`jvVRz4gHB{MVVs=GFL@{u@R$k2hOeCEX?*N@5H?E~BP z=g}k8Yrv#Snhn0J4DSzx(=9H)!Hes})gkI+k7YL#wLFj5W1_j^>A7sh${u_>?-^%! zcn0W5cng02bBC7~Uo#sa8gu+aK&*ZvNh?3jO}pbqn%_P#Q_3kJbyrrvQiWhzB(jp+ z9O|XscZ<l>mIt6zufeX}R4mvq@ElGR^N!6@1^m4w3EiZvu%FL?7F%Z0sO)wWJ7R$O zFF(?-)I_YDxC<wLnTfioLXvqXm8|%91)tmpC^tOA9hcQcyXVzJV)+AZ!F^{u`QJ_8 zG7NbJ`ekm8{RVUylz=IUcL*byf+gGiVBp3oI1yM0XXScmR{LdQ-o<yiCD&1Z;~XY1 zE&vlMp5dAkj=1(i5uD#CA$%4!0pq@m$7!XR;IPFDWIqjYLo)5q8u*iU5!$d1GoFx* zGY}4{Cewe5fxQs^l*)elA_$!RgnpZuhllu#n9s#9%q`?IlotuDoA3}{R8B3uF*%bS zKas@!>iENFBTbpB;Zkg*NC+0?J;FuD<9G<XIjoaT;F;Pg7&f&Axn?Kkx`7WZ>C=JC zXS3;1gH1x+uY{C8<KUB8E9m*vQR%fo-1|v4aQw>}(%!rttZRcv(k(lXpUUS1i(1Gw zNdbH|j0TGz_qdq%Y8d@F4Xd8*0OR06+H^gG+`RUTl=7TKnJtp|y_08bPRJrp<syV} zx^m@k(2lOkK8tUH3ed&M0+g@G;>jcTk?XUD4p&_&vb`CW&s~ALUI=ha+Z5c<-6H&} z7D)f{-izL}TKa0c2<WcNCt{}G=(ruNWXsZU6rGgH4R$Z24-0vB&(eFsXue0CEN_M0 z$EMPd<BDw3kOlt3ouKye5Vdqa2zPZ%VCTUITzPIAGbQmM_6|&CmfJrC$%;EPXi$#q znso;6Jlp_k5r$ZNQk9CXx5BzRpULL6Pifp%f4V4O9PB<&09P8uVPU@o3>+?@M}u#Z zN6jmR4%7LlrBfoFwUh+kBHrhr>|HJ`>MMMa&`4$rB!o*}t!IY%02Sa6nRj3+uCxn= z^m!Yw$8b7rxhIKFj`WfeO9AJ;tqmTg7}AE?1bWv-3RS#igxBN_5>~a1sIQ*GwLKBT z@E8vo6tn|AdM^geu?3`_USh62&?5=lO8gcqigj9g@U>bDnJZ(k`N3mON#YIFwU!V* zZO!85KD<_5|LsiKg`;{<p6^9IHp!8V`~A%ySAQnw=FUY0t3TA;#Q^R-k%bn8VY+!# zGT)UBArsDjV;r7OXY*=RFrIlrh?OkfTV}#;S8t_nG#r`gY6Nr1A`-tWf*$x0%V-iI z*EaM9bsfcF#`U{&`_@(Tsj@ig#O{G(3qx@8*CA+|%(D!qKEz{UM|gg@G_icK0Be(6 zgxl2=pikx-eRemA&c3>lR3D6@eY>wR{WAmc=;R8janKQ?%=zA<S{L<j?x()8&Tyjl zJZet}2T%8()X2>Pl^nh?E3PMD$tNdFs?R6lThDX9=VXD7|6Zo<5QoQ?1u_Z~-r?Q3 z(=j&cD(#!Fiw4gg1A_1xI_cF)6#o!UOaFz@W3nNb3b*jawz;e=!#g#9Z>C`r8X;pr z83EZ^x?=iRwo2_ajgh)Q#RMs!_WcyhsIS9flgqSgMk<*<{OtCHP3thGqZ8C0l~N6l zSnfvSGW-c&Y1s=qytaeEh8-%j&)Sr#4<!hMtOEoPIrOac2koO)7`5>fSv2=Mov*nL zpF0nM=l&k1B|eUk=653hd5*>|v+bCmbIsf_AO$kbqp<6PH5N`Eq*gwEsg0K=1Z2nK z@<)Y)bC?ZR{%Aw%yOl)XZipS}zIddugE_UzmpOMc7>*kee0OV`z^x^f7`)NM`RD)9 ze4l3SkfsxE-Ka&%#L}3jU*<tTe*xneR6yPgy()LQb%l4q>0zSrI{HR22&TK8gdZyV zF!h@Q#@(?-kBh%(PLdyq^(a8iud_iTR~yfn24nE^$9VkFKQb=(6!}-$#z-5jVvcV% z1+pm|8{YBV71fCtktYd{;zHT7buJ*e`ZnEc{0Dz}oukut@H~!r*;J5rl=>J-v65NO z@!kAY!WwlaoG{`hJos}u)HrM+Rbx)0i{1*fJ?BBx3Xr)Y$Kl%3Ct=N4L~FZ1sChO9 zmNh@c_^`d)VE;HwkZwUEn{(7lEC=p<oB-cGUxyan_1d^j9X|^BeVjDUPyLdNEqCgu zy<i@Br<B4y^;?dLJWppb&vTkJb3C4uSx(RG7>~OQtA#6bKahI{0;bI>npwOzkxq*$ zC^M`H!V94%K*;A2{$998rlbq7bBQ)BQ|rLBV_VpSnlw1E;0~2f5|WA){N6)WoHahN zmuEA+B;U443;!ywz&+D;VR_+He3v>vhW7W<N$b<``g$YieZP&glw{+(2W`~Y(t_;$ zDUZ?KNAcf0L%2V<Suj~I5MrmQW2>?Qxic~a-YPFbxm$^3O8!z(vAL9WhO>~-?nJf6 zgwd;xlj-<YA(^hy%<1VB&~n!+IOlpRHCa|mOvCfo>Qf6)<3=%xTX>WY&ZgK>6GubM zOmT`%35^M0EbQe2kv_46V^>Qd_UlhNyhel#*kxLNc2qOH%;&^YHtwX!?H6hH%|a5p z=^S`1OCryl!pL!NQ~dgL5BjXDhw|S-Zf=USV7=5_*gY|j+3G96lGagtMtKae;JILX zpQVzD(F^JB>g(i9fGpPYOccxh1fI_r!4BTKMgOe01=a@6(6Cfo=yh-v+-`1SWRJ%( zdWj1l`eHHBb{Pw=ZwCUqDV}_<+)3ht|IZoFA<?VG;Y*2?%!yq;xK5d9Y;yJ>i$!WU z$IsUAFEjy4ErQYQsSMQVE7MwA31~U730-*>cUxf^W*N_8wLT<KA)gz6X0aXe<SIG4 zkudVlWhwg9hqCwkku&IwMdjlJi;jDN%wQ-Zzd#4e?iDcUp4Ob~20z~MZc1h}%*8vO zPSHzkqfuTr4C60cqnZ0Q;pQbln8Ypz_k2R5{FXrat2x55v0l*gNQI3u|4cf<U5J<7 z6M9g*3MS}#38zijj=Oo6Nw)lGa(RhASG(L8*SkpIXxRvCn@^zJz7ii@N&@Y{(d>U4 zd=Spqvq!JA5UW`nlvM5oZ@Wgas(ul+`^eI58;!7P+YS0;nme~b+Ylox1BLw)J7{~e zFE^x7Piu-ZVGr+KeY-3U&jcfyjr=7SmgF&Kd+#$n<4!Y9`;~Ex)+pg4z9X&OISbeC z{l;_ZoYC>rHJWy6G=|ETawN|Yq!PYj=g|YqjTcgwR4y%?t`H242N%Plx-)F2>tZ@u zJ&`{5o<MKf@hqa4Ea*v2qC21pFUdYOPuvp5tlLyd95ieM8B8HW=a{fRE3VKr8)I?f z>>L_7!wTlqwov_qtr+UK4Gz0)E<0QFOYrN8CM_fB)c$@j_qJ>lJTj3d^}cc_Gfz{X zFxH;vyk==m!Fm$p6TsDM`VZWOZ$idUCubHQMqWlJ;h4Yr<Wip_8IDG3^dp4r{wdG; zy37*RcAmwrOH#?Fsezc)H3Zd5gUO;7qw)QZ_l!_s0lB)}5M8aufqA6{POBV+-scvu zdN0$cddg$!J9aI|IaR_Xhd82gS%E#0bphCcYTO)>3QKb~F$4M$Tu_r1K9DEy@|8C2 zVt1j;<5_&3JcyYy^&-xyS;Km=eOz-v8ND#Ql6u>Rk#ElPxa&zg&&rU}kE+8&`0F`w zUb-7-<S_A0Yvs@=f@GiCj^lG<dEbeUtJB$rKT|ZQ-j;kKUF}6|T{?-QdNy&o^n_NL zsgoOLW9h)xvG~LH3cWR7iOnqQ#K(_zk;6G9)O3s?e%L&rY;a;S+gR$3Y2vM9;iD7K z@zfHc7yV*%=0wBP_eE4%`ed1SQUs^)t&Z$4_r|kS2lDofLW`4LWMLf((~eFeL0NiO zIvBu2rhS8bNn&jJDiu<)(+Jpe=Rr6|8}BbIpv&Vw;kdRUD0depCT<U@wEP&%B(Y@O zkT!jDUz?l}9Yq3aC(seDnEYMPK>tirhkZ3!+?p*P=@d;HdVTMD9J;55{{;IX$KVc4 zP5(&V{TM}c#mB<Uj?Yv(WH!&84ToR7d_Kj4&jV{%;dPA;a#Yp;zEfv<K`e**ZmL4_ zYo@rx<}~+s>|40)J5E?6A_GHu>C{K-Hn@4la;x7r(wSyk$?(!FEcrm#Z~f||!MqXP zZ*igivsbg-^DL-dY&?Cu*#^b;%pv>hN4T52V(3HHFmTR#O=mZWK%@44^6|Gkb-T6& z#K$avYwsRW^PDB{Pj4n>Dj&jKhi$QdpCPCp$iUWoC){`T9<4R9qxRzyL8?`YeP=F> zVRzz%T3LZ$F(5%-r#vRre+=R8j^{M#@L4o#SAwTYBFRO%jJo_c9`=Zqq2}Fk5=kg^ z7!bgx$O~j-iX%2<kI={~TBI%A4wv6OPa4-wpv}(`@T7tPzH_r8r+?(pVD6^y?j<2{ zZ&sxJvs>t}!zre-Ihn3#j7LFgC{`S}OC|*=)7_86$?J$0T)xNw47sETHnoAmYcrqY zj;>D5v^#?+PW-}ceLWr$2m9!z8Ab4_`W8E-(2tJq%_gOTU#WR}s}Mey&`aI`J5;-g zt?UBU?r{)#KKcg@n595vg6>h%bD_}p)Bqi{C*UpFYz(R!&A5z7;^&_!WKGm4-Vg49 zH^sH!zpanZ(lC;EM9<`wW@*Ed4+gkZWG^+>RmP9IUy?avv+>iEU1W8P1fC;<oapYK zxJlX?54J|2yLvRNP|7C5&*tO32N#5!kKH4#j*sawVIJK!foJP(7lSX(dztS~kHRlA z8(hEqC*40!L_jU=vFa1g(l!=lnd1xK&a-iFDLfTrZ#=+^bdD58nS)oe9xC&D=FYcs zG5W_W`e0l<h}gM-gXouXVU;n4IR>Jo)l;%6r;?min~O0O0p$MXSzyc}?TTHFjoUKF z^OO#1rDDMJzw09R2SQ=*D-*OoA4i^s6%#=R-$7Y&nL14jL`A+M7eChuJ?thj{k)oZ zV}mU$h^YXz=XMz4o5i)6YfyWg+3>k&E>(KYXUE?<lKu=gh@Kb16<jJIfibt3b4JsI zq4`R1HPV(Af8%@5(~hHE{|!*5w|Vxl5!Fmv1S69&NaDK~%IQ#Il`VrOX1;~+b6yZI z<^Xi~%)+_foiVLe0!~NmhWu**xJb#E{NQ5(>mEy^+pP$2A8&yh_}%$8>o{R}=^5}I zy%QgXNa1FSrS!CV10MH$g#D9EDcc|h-+5<KebIgTFXT1a?mdBHpN+u4PD{`eJr6e; zVwnb$g-qu09t=BwmnOcn#Go-jd}q!ErJr}hmj-k8OHvfxc@suv^`-Ev!YyRra|Y@f z2e4t2B*=G%e)>H12X3mK4_lir<2U2UP|+}%JeHP%8I#7-hi`I0wSoVSmRAQo;a#G` z3xl^#*~R#qJ|@@p6w_T&mN@onhxyaB!^o{l!^|~X*-=4vX<Rbj56uaos}5S@o;iUa zcT0lK*pftk<xMB_x)-N7K7)>Pn~hfDdrA4PZ8*m`0wu^C%$ggC`Nmh_Z|p>(b@C$I zeEJd|Hr)c*-45jP#>KQa@Bs~7%+LJ$_%lX>CjNCV;qMX!cr^Go)sNmzZ=ZDI89$53 z2QN|BRDGZLR~_S$l0zVFx;iKgb`ZT$+t6;ZE?G7^gt|8Avx$Zl%&xu&82`78s!Lrj zcXD|`AI@>b4S!up^xDy&aW0K(W)G03me1(H1BGZf#{nQ!4I{FH7>!j*?5A;wobF`} z`dDB?TpK%?lZr>-+q^<}=(!sPYEzhC1^(>pCdmaXIs!W{y`o<?@56<)MP#E$KK>Ye z0be^W=G{E|ghgg=c~9aU{HCBvW+aHCO653gKdeNjo;c4bNtKl8?K(`o1|!J0wT56m zw}w2;w<3Arx%9`l%XoK@38ejf0!t4inGXepLR%*b@eBD5+zdU;bvT7~-*2I~eJNS@ z*$$L!B-r-4Bxq~-L$bp+(8~+$;HP>monsO~zEn42S#3HA3wwbVbl#C5TnH*(MnPH2 zLozGc4MsXc!25_3XTQk=GpFpwA=VkoFI{K59xh_d)vBRh<uv_J+(nZ!yZPPzE!y%x z3bI_^V5I(9S|`RcXX_hjLFgt}{Mn5=BwmZ>mz_Zs*UxmWN)G<;n9nme$3Xst22MI% zsr>S(*F2Ls2^6ckz^<?eZ3Qx%*6fSeBBxt!_1|>(V69B*)vmH>of)8S^@@8LWdRz8 z_TU`tE%euq>qz{3QPR1XY}(X?)7mm2#cK-Na`+)NF_44>m%os#lsuwzl#(U0LNM5O zAN91l$j%EsgN;fiH1MG%u{|xuEj6COX0Dk<=blT%GEI4iEO4Zw&4U<oGYxoQ_XqY0 z!r;XFc0r7dDZUVUhnxGJaXT}g(QgwHLC*O+c>b~j2R^giqvV3$S~hX6qy4DjUM~;~ zucJcc1SWJ_F;(Nao|6+I$=#w)tS0YF{WP^1Zb&Qyu`a}-^f@rDXc1*y-_a{7KRJ;f z-Vn3mB8)6s2u!Ua7JT?Y*x9;pDoUR|{Wk+u=N-hKM8G>CqOdz^h}KOOM^HLP+LdQO zNkR=CujSbZ(}rpO5^wt4b1!b$H<2jDrg9%j99aKPyyNQEWw^N28D3R!WGKZIB#v$r zgbc;gqv4myxmPPNWr)uLdl<6;`_^K2yFSmI*P{LV^cl<3<G?PW5Y}g(C)N{eNci); zT<6=-7$hq|9%qW1E4G!N->Lu-4<uk9?>D*X^9#rORs$LpkuL+i<h||{^Y$WnY8|4$ zu3(o6U(Jhxt&M6J`s+KVGgA%HTk5#0Zli?9UOz&!@SE^>ZxdBGa2nQXYk>Yu1DtP~ z#12%RBcqo(v8ydiL9~2?-=m$zk-fH9<k&{H@2D)dsgTC)N(Q)sOA}faCSjPtDzdxd zJL9V#1^Hs4MBP3DqYjT?>B(e}b|@2!Su6od9`DASi?8W&6*at5avImGo+qsyH>iI~ zBX&M%h527M^Y@gc+$E3qn5GwsA53cLLz8DzPFV*PbNwLoyEJVzBkXlAAr^l=OFBB& z6Qj=pM0+QwGtGvQdOy7E7(@<~s^W@5L-1D0BZ{lj@yJJK*8IK^dg`$FoE?K!97hhX z0G#@H8@3-~@#57S@*;Z{a@hi^Ic^4u)f(d6@y0YoVixYIJ&IQ?KhUzs@o;gPHpW$L zhC@0E%ml0UvOaeS(6g8VAu?YDI=#K*9iNRo@-LX^>~6-pUf!$-*AJu9EAZhdU67u8 z0YsDI@S}bz8**zpl;5f$5eXV}evYhQcqoJDJ@=y;FVEvG<2*FEIgec?_L}>vZU|%B znz$k7Ptg6)9wxgPU~%*;a2(%@v!u>**iOi~hKVpy;-<i4C*Nrsp2elF^dgD*eh_O> zz<9khLf!w~fnc8rN#qitNjaB`NtcD^1!K|b$RUA>VJF=aYE7J8Jug3^tI2;>tz<*E zE*=ZIN&0@>MQ=4%Hr4tNU6`N*WZ^?{!e0l?dcShTYh#FMybI%KsDXFx+@$TdZ&1mO zSQK5ANR%t2c(&mc+@Ror?KaCXDrFD-^Hl-slHy^Zu#(nkj)6lqtGN+>E9_Feic;&9 zsg~st+MM{CwDO(N1&?BAqq(GT{;E#ka4JsqO@wh%?8!WzAk;6l0N07L@Tjdc`=g~B zCRHbr(m>mCnZYXBlXetMh9j6Wk59p4@k`M9y^H3q6@&8&mZQvpEp#|boO&IxquN)y zn1|cDu~G1k{?wZ(h<v(=T))2(eJ=66ITd*fT_Xqg+V~!^Xd~PUFb9vjGkI6Vbz0HP zkt<8T(zC6>xU|WJ3vURfGNo_Jm5<%S?0aWO_2CYtX}%w(%;WDo%X0CNi!$AddhqY+ zN$}$J#2wce2>;`WHQi<qEoq4UZG7*+b~Uxm)#v$8>MUH^kDsmHgIU}`IOrwL+9;87 zt7LDI-_gX;{Ha8+ppP6JMX}~gHTWoI(2#B!_RYVC<V}$air1_H>$rc6wNnUw8jPT} zS<3WsxTJ75@1<HeVSv2OxP=u=FkF9B4d*(PFtAaf^y}Mb_W3p;ow7O*Z<~knUd|`z z{cRz9^qc{5sb?{__Z?p0vWQX26KZ{-oov1pMD`A86LUisFwPjHHGB9mo%ly;bI%EL zUrfgSVJZ43cpm)O#xciL^zi$NNZhvkFn(>(CF);p^8EHa!nYFkJV$gigx2|yq*;rg zJpR2vtttf%@ppwrCx0g3+ZPhKTMJv4c9EqD0T_EAn`|8)B1~7CjG^Io$@F)@@aO#~ z;z+gNzTYLXAv6b$e28bw;#+8w>_;x<w;TSO|4=wt)D5q`yi06~lVRYO4SVv(HP9Md zgo<k>V(`ZV;(cc;N$}+}ts5TWt=D2g{o9Sq@!J8=^~ey?eCOlk*<(mctp|*npoOM6 zyWrwmap+lHO2#<w?(A$yigU|pPUL*DBz_j}pU?)|d_OuZ=O+z#BM^Fj|4BJ-MIoo^ z16@l;!Q?M>c=+Z8;rUerueN5R%S%bF?sl5c+BBXNq%WlGc{vb@DO2GjMVRmVln)52 z;X3WFR9*{+LH2u+RDPTMIyj3KIF#d;w>yY*+dFEx<qR|p_mGFb+ejyo$FxFiE-x$t zL>{II{zuVy$K~|Caa@a*qN#-jT1JTUocnqj3dx8_8Z?otgp?7LB<%>LRMODWpnA@I zJ$*|N6-rhVGDDFhB){|fvwwQ^yy~3p`?@}#_dDrSE{>LD6D7|3pl~3FOljXuB^-=l zaOe{e8PLan-OlK0<IhG+m&DiSW+3f2P8|<MLiw3<c=-4QLHTcvg~&*d`nf@5{S_8{ zCzRu^y_PsD`x;uw#*z!I56RHixgdMQ6O-;_QRf<thq&w<K8+B=Gd7o)S6(4F{Ol6R zOF51S|B2$;08NM=?501Rq{*KHYv^}HH^{&JiFaN8CuHhJaz2dZD4KDRguhhgyIhzD z%ZA(N1~C&DKPiqcvh^>MnX{ei7jb*ktC#WpybUzr=Ny>E|H1rMuE@mkePFadjJ%#G z$?tLF;n1FXy!j$eC^_29ZgcFU@9Vtq#fq&gbNVRhQ&14f>`=l{J2g_(uo$k0{i01* ztx)b#A5Ah0ArB6uf{U{he`NeYD$Cs)!n=Ra1e=%i^S7;7v)u<h<Yr-&sHkuZZwg=K zzb7>D?^@7s>?A=A)#T}|$8=nXF21-{M$)%*Q%`?iq3w_%*p^;ENfJwbe|$vZ`n{R% zgWY78ogtUM&&8yvbKzC<SYms16WMfB$XHA|4KJUJ&_yZIp!6{d&iRfNPCgcenz6oo z<Fr_oug+jod_1#exQLFn9TRp%pCrE={OS6vyJV%c0dD)PRP|@u5@AT>Bor1#V6rC1 zH}mntmFL$XPiG>(W93-L2$teM;hwvNpJqc!+zMQftxUZw+&TVR4bRtlEa+Wcjc2;< zQN`7hso9}Xy2)A@Ck|Z4CUNc@GMr5fwZ<@pH;sW=_#VEL_Y>_%56sx6E%Y5@5A#0s zlPgh;P`P(Cqq-^(%ul?cAMP$^%aT{a{0ZWmV=)Tk-`E1*_!7<2+XGyEgIHP}LdD(J zVcXplkaCSCxp$X9)1DmOLfA`Irf~NvUt9R(9to`*4f)o78Dy8c5(zjVi<K`Ak>svo z=>Hr;o4M!F?AIXYCeFb6ReiAeuR6{bvl3R+Jf`~|K1Cc~PtS6nNjX&?JzFLq4Smmi zPPqi;Q@!!BXgJ){3MW<8Gue=F%i%FzWafVyWLmRQiOAr5Xbzc57*{c}^r<!cwAzLL z9h-nMUk0hVUp<!@R)i~sW8n0b3h0Zl0YB?gVCT$|TV3lZRp2sdomx~yyOEn|ZxSSy zNeCBI-6oY%<}^r|yDQ8OAyN}s$z(43BPEefTfZpKot#5=?HV)2`sh>s<frm{)weVG zu?C(fG`)^8^>L)nZ7P)S5hdM559lH@Mf_CJM6D;JliimqA!7FrI_F~+t_kYJzL!sF zs--@L2s-Jb_5mVj%cNJE-01J+GAO$%4QAZrF7e@F!k3Q*=n=&a_*QE-Ibq=o_g-kz zhIwD%%YAu%?Q0$ybtaMiW!Ko9tS8+6osPdfWpL|*PDUxOAKwegh`N?IzxziiYIxjd z+*2ozf)X9bdRc>fjWhUKay{AeY?L)MHOC@fRoasJhMBPO6Hi2j@<lrpV52`bZ;tL^ zU#tHiw>K&9zFq%A5+$EP!}`q}Ph%#@sXt7|%u^EbmZj4b%jNN~dI~$c!v{{+#)24^ zL$Pd?!{Y_+Jl!?6(2=$ewD1NUA5==lG-#qq=`-eCk~@1;={o=5y&iISWE<EXISyAU zl5l~P6cuR`FmH4Nu<f}sZkibh8UIeh_cwaX>w%@bg|qfhrGc4(sSh|7dmo^R*k_#G zH;;@@ufXz2-neJ(82l%8Rq$%h6;?!TCHl@2rJvA*<4aA!hQ#Z%uTK;1d}$@`9c1}? ztg~sw(>iGRWebhLD6l^_3(6WMK+KC6G#WI9b9?rojnop@Z_)zGO)iqwN2=hVtcrWe zgHWn+Cw!kG340tUnVn;bT4yC`&Rc)deS+eT3k%Wc-2gHCdIHuhe^2@%)G;_anOeHV z!3uFv;ku0~#5~NGY+Lt>>DaRi*T3R=M<<?gj1pHgJu!oJy6$9~7VRRxIH$w*<^vex zZUnbQS8^U}DRQl`i)rQQL16V~{!ec9IW&1S+;_RhKGIC1<@5eSPzuF?(MV=|yNMuv zX(cV`P(%BT`NDaMMksx#m>4U{gZ$n;rc6Z%z8~Q_DVKGH!M9#QVQ3}!Ue-hO$`<27 zC63GfY#ueJXvgN&#$@~|U0T<77WZtF<GUW7g8Row!*Vw(<jvfKv)>Xp6}AtJqL%YN zj_wEEzydPK*Mh%?b0`0I!JHXvJWbPfE<r7~zie|oL(U{RkPHPyvf$1e^84!|Cbqho z_aWE}i#8;{-dhXt^S%jKmcyg9q6{isnSr`?BlJ!3NnAfzOr~GnfY)S4*yG&%Jf?6h zetocxc&?d(8eUb%iyTi2wOqh)XADa3<$A%FP7@+F0V_(PX(H!}<}C=}1<V>Ii++u# znalP-rr~0|J0iu;?0o{{g9W+BQuv;O#68smJ8O#hsoqz}b8%;wVls{HbH4)-TlGP4 z>lO4nxE6aXU2y;B9`?uHTEc$!0oq51xY9<LCMF4DH=kj@rUd-7oXEepCysi0uVv>; zCNMh-E7%6I1(x(hlhu>A!mRcJ(A<5W`TKe*O<WmSJ-_B8F*tP>9xQAi*#}IpBg+A; zWX1`GdgQpj-53&Lpb4|0g0L;d3x9uzqv89f3DOq)N0oy1@E?wz$4>{7pf9VRX?=c= zbqG32O1hQNb?Hg^jeMp73avyse=hshE`@n-ss$f7{==B|5?m7_iIqQeF!A+eI<5X9 zjY=s5-SzV@Tkk7THz>!F%M^>kTj?^Zbee4Dj!wV#(Tm{+*~hVZq;F*=1{J75m9iC{ zOyWF$3tic9ucu<dl!s*R{r}L^xg6r0BDp=HDv_vV1adbgW7<9w&X2~4yx&$pM&Vgl zPHWg7)eDK!)CwAyIFo4Wa?TUpLb`49Doiy0$}wviXwt0<<nk^N(vlI4>XzDknMV@% ztW_MMSFFGT_s8=WT#tePwPxDW!1c0LnbJv<-wRy*hG>?TKkAey;cd?6;m-e#WzP9z zUAYq}G>O8LSJ%n7i*to*jN_?DUOu@k;AWevYuHRr2_o+hLS4TOkl~3pndaFd%wO?A zvU+_9di=+|!@eFwpB8nvdG-k`e~UCuxS!3{bD*p9D`~z|2fNTl2Ew#1(pPzfpy%RC z)9!eKf7vNUE>n$otr^2PGRj$7&m$=8Fh--7yJ^8_6MhW2ODvfUWZLYFIOp*V7?Aga z(RZBlxho8f<Z}2=XMUqMt5=fZI|o6ryb{}e1JP7sEmZ$Hjf;Ia|3k?kL77;~qO!D$ zjCeke9Qz>4IXPCswY5#GvT6Zju0D%liPh-DW&So>E75DiDIkc^2HjLuw02xbCj<<! z4)T}a)`U+rw&nAM2h+J3NLV{9-G7QK%05A!Y+H_hGh)%~H-mKnc~r8lm?*!#&O5%j z3Jydc;&z@B;P~+b;qWSb676&oPA{JiTXh0ZX6PMRV>C$O9=-#s6``P}8ivu|HG#2T zk2h4?gk`q|Y46>)G+54vpEUO={9KtvOm3wR)2{QhC%TZ-31o57>tJ*@4Mtcx5#{Hv zVl;I_VSZjFyfsgzp%#{q9<&{5RlMkzRZ<{WbCsn3%!0A~`q<6Qw-R1Xr>mPyxQ_iG zO=ypVO6fi#b-)HI+$Dv(<BO@=AARA7Sp%7JSQc200l#4PaiPW6FLd+DQrxon0?k{v zUwFu9A9=?0O3foLu}519=;<yI@@0WBOh2-OFtzpgl?UKqU<zO9Triu;btq;lqWSNB z+MK6A3@u{-`*y+8zcXR-&=y?2(#b5vR{+}we~{s32b$+ANk(lGAz+&tnRoUJx!B_g zyLSrMz-TudfBrbi+%+MWyq?mD*#~gkVGruf@#dU&IiuHWEi{?-0^U5_4mX^<N!Px3 zwD@R%HR6BSx@S>nr;tnjwm+oI;uke4lRBx+e>rq(Wgx_FP!bNt4bv8>GRUlOpeL3j zGHdoSxI-)x&z)TZKe|@pyA~r1CQ1-BkjjjFx<@XYu7*cm6HyTz(fR!t`0FmuUp9FY zxcG!)>yQfgwl(o%3skT?sgh|6>;m&A$LYk}B&z4FKo1wsLmw$MEOot3n>TM_)V0f? z-{=t6lRkk-Cv1gc$=|8vkK?Es--w-@N1VB*1UfFpLW74(m`Ua?g8kp4NWADfR)k|a z)owgZoxKjRSM<-pB(2YI#jTyjzfR`7Nt}ygNjp6=@B*J~$ivoE@9DSRV&Rpga>7eX zVjyDh3eeYqu+cu3%+-2J-s2SE^F^AldwmIeO6D7Pe)0jA9#5)$#vYpUY~axXBWA|D zgCHLG5^ZXwaCher!)h(%t-WZ5pXW$o_;4CriLRyVXI8__o997)`Y0oj=E)4$M`CqP z1v5~Ygd<U%)auhaR&Q&FaJ1b9{6Cy!iUNm;Q-CM(WwL06GE2s<KTl0ppTy@+Px2-{ z`9bB1Uvtc?UO1Xw2@lq`fW?j|dedeB_3}Q4tN%Ko^xLIW|7aHJJo<)QXy7u2NmrP! zUr$5Nw}tqId=eBrDZ!Jqsr2)p64o!_=7_p7P^bAEig!!UZ+Sy_#px?9?7vBVo2>w& zp%U`h!<MdH<tzyQSWV~pX413<FK$m*OH9%?lb!z(!L58L#`t)EW?MW_$;_h1_KgsS z&7%A}mKO-wJb^FhOdz@9i^&yk7xhxk5GG8~0G&3LA2alp=fB}T!~d`p7Z+u-TG`y3 z=du>b;qDfb_GN>VMhdP7*5xl`E^vQ)6!lI2KilZWs5=|cMK_8bFfm2d%?ve2;c|&# zouK@u9sk&Hvox1!@L|ky^zqpbL){5ftXdmZB+5ZVa5lTQWhK4P$oV(kcarmIHpr}& zqth0Bpbh`k;$o#iBBxbNr+Vs<q$kp(SuqH{Z`TI<iF5GVgJIUVV<9azZUfWj$Jtx{ z2l2y{RvN#2D$1xdLDo)Vl$@so&z%fN!k0N*5UG{@TNsIJCV9{$4v+a3W&+UQK1-2! zFcz13;0CT^`X+7}oTwYiai06wIa%7cRkD?0v?W-s%ZA5WRj_AtIx3AeqgZ$|UG_H@ zJ8y5srO&0|!VghgSfNXQ{bJ#X<$hQavW$!gZbL!%d-k-|6Ws4KhDv0Hg7e);wEmtB zelC3q!)od{FHIcn3STiRq^IyL(#}!$Lhk-K{SkhGb@=h=d9Ev71_rmA@JT@>B)L7K zFZtW~US`vUcU(TxypO?DCCfyZGh;RGdo~3-{EO+y=pxc`>k+?STmed-hzK)3ykSRl z{}7#>!!$E#0eri44J;$hk-P_lC^U&syXdh(p=&8oJvj^OE&Av>?^%T8MnTS$47|gt zV1LGZD!da0&N~xe{f;Fx-%AhA8S=5-Pm7Fy)kAA`M)GGr{4AI%rAiY@<Y7uEAH#3O z(}qlQxZA%EXFRt;ttBNezSAFimma|w@A2f<hC6JO_%(7ZE`izCpNA1H3c{+=CepX? z5jGsQMkNOY8mVXv;(xDEvvJupcXbMl5mCY-ZZ0G<<`C0EPmuWY?Tmt{8MGNV(+@}U zp!LEJB9U%Q?)}z*?c9Cyqv1&~ka$Iw+~x8o1A5@DXT)E3Gy=v&w~%WCGw}K1tC;7v z0NQ@-Bbi}qfn62F<z&y$8`G+oDgWxQ{qHtB#`$<=_Ev)7b`$ue_>G-;Xcri@IDpD5 ze|m6Q25ZcoX2RNxq4r=Zb~btQ|4Jvq+a<Xenv}y1Y~PD(3a5av{BsmxByixxZm`>) z08>2r*u|yq1xNbz;dw?IKi=gFtyGqyu5ZWC>cW%sT5Aoy-aickG$QHWJ<C8M;sUML z--#>Ijtbph|6^s($-+pmGnsrofmU>GhlQb9xLy1{j{NllUp;m5C8I)+V)L7>*pY?D zWsVcq0D0kuy+h=X=RWdBX$6`k_QT!zWAO596L{!X2C=vE=$FxtAk!U)hq*4@pPW=O zdZ?2PmU7^~$UKMHy%)*S#(6Zjw~y|6dKP~zvcZ1eUnGC*G+G>?2xmP1!_De}RMugH zjh%EI&R%Jxb+3O@nY&-v<c(Qa<7tDoPJV2Zt0<k4Cki6x^l)lSDxJ6>5@kapX|ugJ zvF;sDu2gavQsHvC%R8C``8~j-;nN%g@Cp<7Q3ExFmCV~+7NDQEnwINP68m%v4N*D) zwQ=U;>)CJQ%Cu+DE_E2B$H~EgJ9=cke*-m8-^)M0a5cQKJ_qxpb7|`RDp(g`LwX;s z#mySVSdp<GpXz<UWwnlAIxQ63^Usps&NGPMMFR6B<`@=kS^^HZng40}ZL&9RkmlSN zhccoUi0HO3xa6{pp8b~vh9{1}!>b<ThhHKs(UHVqlWWYZnJv)h{*er4#$)4(L>jL( zkLt{jz{ww#;q(RpnSCY+(^ik*0*Od^a$V@6Da-Wf+vHNdK<5vh&{{*T-pHkF_i~Uo zHiqic@95syK+?xIGP{j8l0TbM=y{Eew77N}ydq*y?7J2%uQ>5yG}mKqx;IS=_(mGu zo`K@7^LS|82UaJQqM^kZRB))K;tN~p$_s6DG-@8{UTg}p<lNy6*EMMWO0jxY5j|6R zm5k<`XYQU^f~V_Opk>Ef%=)$w67nMPXYea}I!v6EPd|Yn)DlbVaye(zUidC$2M4-p zh*{PN8n;rwUV6uaM|smRw@;QjZVp3--0xU2hS2N22k6P&5p>y?B`E&(H#qcdK^^K1 z#h2I7^8aTR-!20tn$Rh(O~l_s1V@^p7@1KSI@b0VU36$Z+SW(0-drd5r&2Ye^V5jV ze|{1NC;npmBXVg{<3BoXX|~|=n%!`tqy;0@3pp1>E#1+(k>qE{z^P11a%;Ci&dw*a zvRs4XYE49uFgsY~_Yk0a1T$QJ(`7^TEPt^v-gj^2Rl0m-FP_sNyPUJ&{`cGD)0z)Z zA8SFMy_SYm+s4Cxmv)gkF^;&vLzhl3x<!TWGBG4gAC@sIdH43;CUseQARZY3-R0)+ zW^NL;D75kCPCiFxg&;NkZw6GH+Jr;0S4n-2FLwscN6Rck<CT&m>Zm`ilD1|QyTj?& z2NpEBo$Iaqdd5no+=mF)v*;)C9&Iw}i1GRbbf<b6N!ap^Fzt5uNoYV63eJ+=s})ck zaf-3A^A&D;;sla^0`SLQB|Nn>kzSIp!L3uKqMoNHnevM3Am0mS`jqFec`hem59ioC zn^IcSI+!kO{4|CY$-NBLk#6)s^#zozyGvTQZi8<o=jC*tOoFyn;V+SKkR=yQReyB} z2fUK$^_pC|wQ(~4@q-j<pQcRyKH!7HtXO*S<uxWNw~{WOH%w)mWic>k4TMflU`o9$ zp~7hxc6giM!SHx!7x#ulJvUVN`JIGqS0VBSm*JkD1Re^`LyP`<ylcrDaiYdK#vnBu zg2lUuhO`yhPLjfloV)hdgR#P3yIRtz;>X@O$oc55ISF6YYcOi>IFGnl9Ilpmj6IWD z+0MD<=<Ba&{<G>nqoilXBq)i&gW*`-hHLp)mUw|QL~n-V&7Vk|)nz*W!7qW|Lqq)f zW;LYfpCdjC6@c>ukWFRA7~c?0+_o9OA>J7BPi#CXTM~~RTaw^*D#vz_${>I9Bf(M7 z!iFS!;P@BOIQcM3Cd%tzy_FU2z50}>-TFq*>@?0S=A+R25<LE-3iHy6+3Wc!boP^7 zq;J7&O#Y;ac*hxZ4<2PRo^PiswloPerW|7n<!=MsH%ZtgaSFG0or3ez9KmShBpLNI z!tL!@cwn0nB$X9nz|bPx&)k6p>3r;cIR_R8*g>Y;c0A3^kt#wR;GElc^5@|#CQL}t zEpY<~WPx)-Tw&eDuZOpr#rXE)U4V74z_FuswEbQ#2Fre=*OD&b8<Qf!LEc~j=VUzb zNEEMZQNz3rHC7{WCYpr}U<B7W`0c1lPTl>CpTlH8DSZ}w_}Yl)d*U&@QaV72r3}eP zyetH-=7DW}A#8d5p0vn1<Kla1P*tT5QI2bc9pQ;s7s#>KAD<N7XtEP_+$aQ}upQ8n zz8m<hY2<vDH5}K75+(&-CVzAlv3Tnm;-7JWIR6#{RXYV36h_0;seR=3hU1|4Z-nbj z%!aciQS|hf#U#Np2!Ge8VbsbU;57RK)%np0N4xJ5&Gy-}z|smd-Y`P%J(4hEC&!m; zLpmX-lFH0{LAGbaaeN?#Ts*|%U7Bl#!zX{R8@dnkZH|<3uAdsF+c<`FZjwa-bfZjJ zGsr0dR5HK7?7bz|<9fhbH+~0(XdC0zW6ETL_gau{8)dINxDIolGqhf84z!Q6!Ku+7 z*tz?o(0%?%%rHr#tJDv`u7^5s)A>5g=pG=+JuO(v<^09%hnbO)<;1|b6}(=bVpbo0 z&(zv)M_<`Wn!7WF*yt|f30LSbyQi*1yF@kI`d1kiRs1BIt_IV-%`&k16~Y={5iAH8 z!#`1?4I3vHl3dkpUeKC8=66{&aa^cqVKr_K=Y8bviF*&y3to1(>~;pcKlz7@q!4WI zihy@Mi*cQ!9N*JfNU-Gtoh+WjzHmrGucRCJ?aCS689kOBJzPoNQU+y`uD~(dWb{~b ziYBa?L0a9evq3NRz^kvlbouckP;_Jx+}hefjk&CX>LNo_yy{NkjMs4I^FWUMCqnj5 zOvDhIWTw)uiJn{f>W1UYwI~|XMoiDG0vF$S=G=mEI^9_u>mw=9fdlMH%{^4iK8m(B zTw|w~J_nIq<|wvF6e_P8U~9`I%vGvq4vYyzw`ba{-2Nth*2F=G_Lbp_z8Ih?+$>1z z`#p%!VPO77H_XrcM9;UWVR?50oe+PDbf+rApi4h}{ZSvQ<5!?=auogc>n8p<5{G{V zkAb0IGP6_=PRjlA_%Bw<kX2iqInG=(E?DnER>s6(df3-Rvd1TJtfV7YXIcd#tGPXt zs5DVfo{akQW0)7)r}9g*8Ax=~5?)r96NcUwr+@YLQIW!<;2o`kK~X}O`c(wyI_}|L z*PMU~p$`QCMOK(A87g$!@d2Zh!%*i|3r$}W2ct8S_<HWPq>#Ixl`rn2_b!{0xug48 zS>0uDEndjY+Ip$UPJcGIjgs(*?KoMtmmIV@il47H(h!Al93gi%yrq}XKCFPa=S;?x z6SP6^LN;%IuMfS}rG=v|GPtBeK#$L6>F<5w{3~4@T)t>AJ+*R}NOPQcH75xwE3OF< zD;-e0_Yh7#atz{^@}TxZI}Yqb=H<~fWcS5|NOYCKedZ-3RV*&^Od;o<rQ)3mQ#2nx z6*rom2j-AGvCyz&itl7Gtz8aOa@_<xoH@X-F9!wRzhzSC9gU=G;dk5^kqZ4o(QNi- zF&JuDPTG`HVCfbHiWh{C31S=<;<g4kI6DiLar+maO*uqzc_y>Ou^uf}ion-NLgK>s za~>mYT&h<}UH{Idhc+C-H12=Mh5~Ws_^w-|?dc+-WU_)7-G7BSb`$Y{-det(RTSmB zX4Bi-mw^6;X8c$g#?SqoO14>;qG|M7(mLH5E!F)Y?=XuWj~UX>PfFmv!Bi-U6XM<b z=P7Al04?3I{I5v`^xL6f@SS^|&aAvh*6dx4u`{fh=xtx<AkPOJ&M30@SPDBHh6)#_ zh_c7T|1uvFPS7^-yL3`jD*T)thc~i~@XALi=yG4hBpw`Lo@=RN>&x4C)72DA)L&qA z;5-sxID_6__<-sdHE_)n8FUT1O+IG~K*oN~7h3cP>O5>PN7_kvV&e@~$tRLZY_;Hf zX+LLX7Hp+ayklhjwBPjpv4uo_b~{zp>L$w9CUCRq7DoU3Pn<mbj7$hhg6ecFzW&V# z*t5fvT8_=2_92h($37lfjn^ZiM@HD$zh{#tdAjs!c@p(By-wY}rSe)=_L8W*KBRYW zH>2n;MHk<UqCMJ`7+qHeR{Dj4<RD#qlM?{fwu!*%d>!1Tb&zbAGQh}kGpMiehx)xU z0XiRo!7U#6l}{jlrc@H;hyaY+_7j@#E`z#qX~-YrhUOZ*@S)R-tSHgORq9`<?7vvF zO6o)3pyjZd7YG7tCEQ@Hg_eK!qS?zx9J8v9^Gt`s<>l%$r;_0ITXEPM#*%un0xECr zp_$WtpwdGXUKJFRJy&Ou-^YSTfZ-()tGolIPU|GrVae#FdxT^%C#cyA6<*fMV^I0b zRgm)d5dJ%M3rq4R;`g6J%#ze(w!l%`B08@EgO2W?nRC@JX{Qw|Za*e?ES4)+S)WF{ zy)_wua{)20eJ1emx58`Tv&g$K;l%L3WR!0F%{(6(i=JxZ(Y(HfOpW0BlDkt;aqL&> zFh3m~Cv8S{g%nCX;-i6IIa~a5A(!iDB+Ug@kiEkZGi^16ijOX^A*=VH<<)p1m1Bl^ zk85ymkO6ksejxwk^sq$E5?9UDfqyA^sDJA|wJHRvH(E+aW+_ohlZKB&|B<`?+C=86 z71tx2Pq%hy)1q`ee9*(4jf;|K<5LL?oOg*v?q7nwT2DYho%7Ot7v=lS)F&EsQ(%b~ zkZYaq$y=Ls&|{~Lv)ljgo2g?rEe>bQmmWhWp(CBam~c#0Io$H;2J4c*%~O+ZQ{w|V zP<>Ot)@2pag9lw;ZGHm|e+!^(GoDeyk`eaJ@ibB!(9R^JO$9Gk13XncmWm8;d25}^ z;C1i?46_eNH^<WGA1{vj>B{)o>^qef7-D`$82e{~4NThji5wO>@W&joqbJ9<fcQFB z80&hCGEUj}cyB)wUjC5&+**Vm{&MVMqjI((AOZs3<+F|}x`}HGcW(5z!}2%f{F>`y zaZ{?1aCWgSST@?=t5gFpQ&4217uDl2JWi)^ETft4WpM6?D3VbWj9bKvAU;7zL^p65 zz@rzTO>7ljuzZbovX(<@^;H@c!m@TlS9l^_iv%-;%h=tG#cbrWP#9i(i{5ul5<W39 zfeoxBW@bduP5lORmP9xGvEVc{+3ZTplI3xa|2p>hl3E&{umD1BZeqPa3ya3_gu<1b zEMpY`bGomSrw`om@_{%(p;58mzX}4;zhYtRkK0&hqyY8qs%%x{u+ZmA9dBNV8VXf^ zb6jT)IQ!`@>GgZdXfCowZ{t(!&h-mORhkFhx-*_9HL)J#Rg45yn|PF-DT0FsUSVro z7L1o~X12eQ6Ske33G2@Yh(UP*oINs3Z~cluVm}V9*?3@k^jAjH<p;T0WJvv`)?w)k zC)&P10mh{k<MdN6$Qi3{>V~(lf7~3QaO_oBGPs;RvtNRXgc`#9tG5LY7cWK6h+Q<( zp_JafArD0+v!Ka;41TsnTvxsiYrp3}w6-~gf<a;(^`71Kd@~cr@k#?0e<9M1Q-IxV z%^p%1rCWBn(iJm*lR1;7g68WTbYt*OoYfjlk`;=`oNv<vv2*so$bw|*<Y|jXSG}T> z4>;1{6=J9s%=u53oF*Q<ERpzk67LSlqh-ceke5Rm-0ec<t~d$R|E`i4_h@W8S47`r zDnp)UHoco8j(=4ykcG39L2aBkKV_FUf5y2qEKb}EpAUZ}f8K_%evTtFXYFZJ@Uezi z%{0s#o+Ws?bP&jQbsRjT0L8WWu>55>em*uza|+5~-vce-#!${*oqHCG8q#3@bw9jx zMjWT+{UT$0@4#K>8}J}l7TuJxsqWxG8f}!xCi1LFx5YYUf5H~<RS9Q@&Px&7!WCQ} zN1e5Nl0#?9f5b^{5|kh6N(n2#M(c0HU%8!{#N?1$N<(xN$DXmWiX>;e?!f!syWmQ; zBP`I#g#4<1<bt^;qk<=(`f-r(L60t8i^;-{2{!mKKMEE%a15V6RiwhBkLVtwWW|4q zSad*E$oF4_Eo&;c`cxp8TpA_6-l*_bXV%acC9Y8QeKDpV^M=eD%{0cm2u{gdpwAZG z0F}w5v~PfOz~ufTv!dE-lJ=ECV@5CelBk3mHT_Ai*IWD?>kk*-=P-wydIf6Xinuv@ z0G_?{h4GE^8LiE~YQ{gl!`#!%C-K&feAA_OX<${3`TgsDq<FX*{a%#feBmm1cvze2 zFD`){YeaD1!*}LN@p=09TOaj(H3zn8mXRfw<cVedbVyFuCVR{H<b!e^nQ%o3dsj5j z9i<s4BUQqd4D*Q;_b!FbBv6&h0(IMCSkiO^bMr*W+UDb|!%`W3)6UamL6Id+yI_p9 z(=^d@sW{lI6zB4k-?(gyxKOCKj3zOYF(xpH5sc%0$G(1~d`~`n36Q7FVMWY!Uk%v$ zMHzazuJ*qy4Q%7`6qk2Rw767ylElIi-e;L2s+E~YUfU-@#0w>&xbhPEMAd=1w<F%P z4MfpeH!_2$lZw0%2K1{DBw1YehI3tJw^7-69*BY=s_snz$*oSfc1$?4cT-Hw3o$)h zDmxA?KDGd*)iJPX!UV8sxI;Ut-EdfWBQ~1eXODL;M3uk;sAcCsJkD;xfHjfy{9OmK zsqP<{DLt3V7HYum6h#mlKaT6n`r(tc*=*U*H>l@UN=#pj&{2LBBW+=aH{-5>D7W|e z?SEXbdZiS|rKWR^t$wy)WdRKvjAZ)U4)KKthd|<d4<z1`z^IDV94lrfC^y-G@iz^; zIrj)X?s*g2{&OTPiQ=^M^lg&VWl5CV%IML5YD7kMZ<U+lOw<gv#_HWZ@cP*<@@1M7 zc(Wz^BZZPgVyg*?kIcXmraH_lU3HXl4TYe0hhe5=Eyv!<<In$n3(P#kXb(5rKX&N= zv-#q4=vco7Ha2JrMee@EOWraljN&Sqj@P+veGHkB*a$MiX{b$Y`Qq_f^x^$b`eXhM zYPzY1Cfa<)TT;fD{OBU@%qKngH0CiDa;(L#8{JXQ?h{SV{3ocI=R-E=a_`dtE7<!( z8Q0aUC8PH|V6paYH2YgdA|><C?@<OB_K<=tn~Gt=yA;&-7v&fQp=g^gjSDB)V|dUC zJlgw|-pb!WZbsJ7{liOf-Ijl(c~u|H_!y4|x;RF!Gq)Q&A4u%CEF?2K4`6a#5GIYc zfMKqOv1INu+$EPows^&m=D}$^n|X1tHB?;Ke@ha_1ihit;=Pfo>9W0J-02M$gjdfm zlY{?Ma8=7vVt;23>G~XmAKb@d*ds;snDdRTVO(gBPd~axael?zF=#dKK6f^JMJ!bS z?4EQoV}mx++`%x^9+bmnA0E(>g~~8h&KQn+>qFz6ZVYbL0Ua|bP+Rhv%*!vO1+C6B zxoaD?y`DiIKevN`wOlqYRgUp$IY=|TU$Rr;Zev-&3S8J_3s;XC;fJ-d$Zyy}@+bLX z$ESV3dKJNF#yWg^=oGtV-0A8)UcQj$y9M3;7O;KkS;X&9EE_oH9LK}rGD4fx;6%+R zRO!j#ROt}@2^AMiIkkj1tT;n^rhlRKe`Zhv8!ZqmG^3_Nu|zsKRal;8gv+X@P^)+o z*6q$jSoFgaetSgYP*D^8J9#F&JNKQ{opys9?>>wZj4t4v{fFSdRB_=a$5e9Xk0uit zx*KEeI&oR|T&DK58faAWi0Za27&lIxkZ+gJY4D)%tIG?T|M)pIlIOC4v-^o%SS&Uc zIq+I#^HADQ20Mm?%!v3UIMC;ZH8!f4c<CsP8{-8P+UJo(T!g)fEAZt$3sg8(MEzcg z;_NquIN^66dA>B32CqFvo&G!~(dSN)kt<UL+U;NHFNrB+L`oE+%Z$u-uKdpB0iEfO zC%aJOkQzUw>^B+xGY7{9aoI&}Q_N48fi|ntNQ8wu9v^atB^NS4BlJJ$Ih+RmBb)in z3)-2Uy&~jP-2moFSi(F_BXWpbBTZM*QEgHhoY_}GwL?x}y52N==d}#4|BJ!)fVHIU zhA#Z%Z>6(+rPwL6w$h}&PUdQH53xKuh}M%OvG}|kN)+YL!NIG<AaM>n(fP&N+Fc@! zf_eDlG1uexE=rb1?0|Dz|IbPMBWvx@F3>-nf%kmnL0bDIeRks*`z&0Xlm~Hs-M~wz zRg*4wKX(V-jq7D2BW2n8r9FJB!l$@w&<4*uxWdh?Eum3agYFKw!+R`skG`4tS#Ym+ z3_Ys99>$7~lJ5q+f<5ErkTdN=G|$wY)M%few?{0P7YRwsg1ZB-Bj5pctdXJ3@A;S@ zp3dqwuE6(3iFCfwR+1e|sQ%DY+VVjWI%8&Fz4%^S=oUgZc{@XLlmq;^Zw-k%rlO^D z4bJ#r4k>oqNz>72j1`Q9?C|Fp=dp%7*}I6I9Nk8z*}rD%6w^WbhBLEabtqGp5DIRG z=it^Yx%AkoGJ3LaAMP2NiCcmtnTTr&R5{@SI&!&{$QTL4s62S(EDf~}N=QPtJeYRm zgI%RH1SIrOwU3-%*<cKQ%923sZ5gOD)N7vmSf7?H+>Fy&EHQAc6!O#b(dKX>dugnY zoE`gv{ByWMPT23KqlsxmO(dAk^;4vcky4bE|41b6`jRoK9{5N8GGq;_!xP1mP<OHx z4ySHmY=TeF+`23p5~+*rN`4?VG?RWhd4ib7iomedIdY=GfbVoeno%k=h42PrST5E| zLwOXHZYom?cXO_rQ;yO4<*c8y6ten<3A3d_kgc_zh`+0ZV;x74^?ky>;c)?*%ngOk zu?8RrufzB0PQ03-R{HZ}5`O+#!8!Rp(NDFrU{9(jsMhk)y+}aTiX8a=-BxI`@EF)# zbV1|Y=J+E}6pVz*m~1tMY&z~lRDJ}Lx-Z*_z3Vad{ASMQtn-MT*^w;-z2_wM_<Wqz zy@x#LGKAXqo{X_3u#@<l=XzHg<Lxwoj1@D5gWIa9@Zd0B*_uVO(%&Fo5Ji?ZaXmM? zN8GbjMTOHZlcv)lbik^Sm@C-uJ#1E^`C~4#JCo(Pe-W+K-q*({?Ni6K3ksq3zXx#S zY7a@@`IDz&$MI7)p5X5P1`zio5jV>}qY{df`5Vs#v$a{}5V=o{DORmTfzbmvy!AHu zYr+USo5jiVo1*x+&J&zNh6I1@@6ib!tKj#LJeB!TO5bUyz?i{scIugJIOUeS@X!QB zOyi~FmWoE+o~hy(KYIXw7MKakQleqQd+xqBUJW&in$S7n85=4&hP#K}WZz$WOgE?c zz@Wxg(mQt}iZ&fWAGP(=Zx=#;kQunUrjiDM8GesSWbT*p;Wu=UA=?FTp{#=Ws^(9l zlyqprnLeKW5ij`0ar^h@T*m`(XPC1xm)Kt$Hd80D?L@X}H8yg+@V$>8GPBcG(f~UV z+{Zl+j~pJDN2^DZ@WN%3zj_XxyFZACcjRKk@Dy<MPKJU3Zr*coKgY?{r=jb|)8=Ip z@ULMF9b4zZ?c_KvF;f6Oj^+Ftnq_!x?N#F2Wy<9mYe-*+GP&eG2j3o_4hoM8LG~Br z9q>B?RRtCpkh_v~@c9Un7C)g6YXa$`yDiWGmvF83a(aI{$EKL23MUKnarZ1^8vS7v zB+n2ByV==LDf@su>2`z^kBq0@bF5+JhiTmY+m-H;3IYGU$Zl$qgJp|6g|j@qk^8yJ z@v1@rN*|tu?DX|`(J_bXazqlNd+(`v!8Otv-bl{{i-Nu1I7q+V2d0<akYpwe>{)AY zDOv)LO^@Ka3N09N2o%O2BD~~i&Qa^&z`uU_DLj$<K=_iL?6wjy&dC%75gc>TXiFfD zD{G>wcWlCx$X!qv8AyWP9pSSgCz-i(s^QC_c8sd}NhB<qph>VDnnkZL*Uq<*oR@a& zNn;6Abm<~-F|v5bs~Obd?YVA@D)4H)5RI1wFm<dp%(yVbh{c+M&d)?<m%}fxjoJX; zK1`<Hy|U@jPCl%NSxIJIs(|@{K9Jhm!#0|Y$I+h&ID1S4W`t>>$e$dXQ7XsZL~`g} zzhYYTFq-!<=RP&``9mJ1a5+=yd|2jEM|MlifJ$Bgp=me3C|L&e>Jq5r`3#KsVgi#@ z8|bv?bHw}W83+(P2t^v&X#1OB=)@FS*{;jV$!_Fp?0!jJUbMrW=Y6dIb`=!+>;)Rq zMwpo$1vi9Bf(k=_y6Sfydurw?vhRpD9vkeVa~j6OE;f?h^`j_O`<SRq?jYk*&XUgf zWoR}36VYsuv5@j#4}Z#E(cX*KFw(W0eBPM{Rk5}>@@N(+_r3-4N)~CA1LoSrkcp}9 z=;RC|+$ymbC$4$JwyA2PeNPr+dYYsATE1rA25Umi4_(YnjV70k?dilFNi?2wEX*fG zaHn6H<I8J9^^72zkr0k*Gy%PK#gTm;lc=%dE!=7KmMB{MU{^SQVdmZc#JqgXv0s-j zf*l6gB=+Sya`41@%I~~OSqo)+Wf+ChJ8dB7jVuy{cFJsb!7HajL52JB6xXFI$&}>V z$eJTN8bf(;qfE2ZNxCEVCOr4_;}^F-C61$R)N6VbNs%|jf&OK1JWLS>0@kA8guN)0 zqelGuMX^>ilFXQ%#o8|JCST4UhvuW3$jU{lv0Gs>iV5w>AziMw@zjJ-9X93v^^hca zbu;i(pbUnr4;2_cosG8|HNY}$J&6;P<D8WL_-;LpU~{;ZEWW!87rbg^Uy6j&`Lnop z!5sxI4}A~+gdf2hN`HuYNgg@4BwMijuBy<qe-*CTc$^N5-+(*a#IelvJh`ehigbX* zK3Or$iIXKSx&}$@iWexhrICuP&|!0Y-qEAmyvcX_SX$`rN%n3^peH4`nS0n<@={Bj zoKb0{Nm4p^JT?SXxZl^86O_n{e1OiAH)zr%6I@-zVEIc!9Q<|)>n1rfCyQICs-Fj3 z?=NDWW-vJQ;5EFj>BpK(%47Gttp}PjR%lf|8}ywQ!oNB9(4S*qcmBOYm`BG!H|_?` zu}Nb&AP4j{ufVU?MqpN+fKFGk=#M!*q)T@*ngnY=N%?CgP&gk>y}wB3emzFjTlUi$ zW-84Y6N`7{mtbu~7W>@Y5^vfaLm$^ESi*6HU0i<BW!{&lsP%YwRj37J9l)`IW2nUD zA5`ncJ@&7n8>+}gu`Yv~;FjNX2=uSVvdA`~rmz=Aaw18>qcu1=HJna1n}|jG4l@hC zT!H#Iw`q?UgR$x7Y4X$SjL(a+#6;y1nm(67=d)t?Vb4XDJ$M1tn;+p8rE9QiX(IR( zoWbJygLF;tL^3ts8@T;4j_<OfyOaD`>*?n)CjT^hqHPF!>s8o)Mrjc7el0IMPm3RZ zFdD0ZgDJmQNJ?tCbNZrH<i>#%a^sFX?08;5j|QXA;_Y-?b~%=o3wl_Q1I7?q70BG1 zrhzv^p3%S)%i!^yd*tGS`HZKwFD|J2K?}Hd;I(rl=w?0>|5bh@S=C|qvdsii4#|SC zoCYXNGhsFyd_qR|%z)R^9$=zJv#`$91pof!T=36s)6q*S=xiNx*6x8K5zLOlvc`{S zdqNflPZyJP!vj3WLo;#T&k#Iv%oViG`U<U$B8X({0rZ#~i25lk`<YdS{z<bj__!L` zbmurbwlkV!wi-a8iW2ctSW3^cW08GX!7H5PfEJG%1>*e=$;0Tm__Sjx=d&n+xl8rn zT7@I(@`_;LuZg%c>;vZlk*0;irSxOqC2~fo06NC%2zzX<LffuVzUod_cs$mY7v$1` zdk(q6p7eOS*>e`L2$+chO-K^#n&_TTKlCnsNP~}7lccvc{5+Q^&RgwBtVVmNlq3(H zP7fo`WK<z^z9x8#=AmKXNmOpViu<-DFxzYn5G_F)`Ny9`WQ@!q;kPV(&|XAkPn{(` zM+#xk_6^yb<wksNDAMj=b^I8f#uR<O%zD`>QkO2I`(Lxn?c6~cKU0C7_B?>NJ>N-E z7JVT<LyP$e2{~A&e3m@=%JmvjcS5Z2A3O9foQaor!(E1};8?dRXl_{pO&>$xO}9M_ z=PBUaac^0<lE37W$4*RXyH6jFdqVWaoANtCZs5(0Bdnv$7gROdL>Bw0(}KhhLH?(E z45)e1{)aqX`_+8v5O^L97fE5{4->5YcNv^oxSaquN1Xk6KlJHl<Je6rp>RqASrWr} zY6f&+-u7ZVWgAX5-F?plrk%szUEFS+>xzaAPa@89ztYRs>R=X?#@|s1WT!PtePTSx z3%eA&`Q92|9JB?^9AnN8ZvpBT-?Q%hs_5r-8AQ6&h}_N)80n9L)Q~EsZpel{eV9X> zwbLkn&LhU}bS(DMSStBr1zog@>#e|HH2PRa7ygT+^J98pmy-@Vyx|_3xsRba*%TxX z9^h3Qt--V!8`2@DBzJB4Sfj5E%z7h^k-um<-!*gt?5t=drM?#MCM$!=<j=x}eh0yU z+6by}E*10#Uo#tQ(rTXbQwbJLgqxBR`Nkt+5W@eD^ew+e;_s*M1}{fr>c}W{qQB{0 zPXXquiPL}L<H@79Ldw?+VCwQ>are_Y5-OWcFWGkU>!0bM%U=t)*q%=oX}v~|Pj{$c zm@)mv{lHG<Tz;c|m_BZ)A>Uq3r0<SQLAw?WvP0j5xa#*~;raPwN=_4|M%<$!c86)( z+G4!$ErIt|TZ70}D?`9fTXOto4793lXQq8or8AX!k$scKG;h+tN%lv`%^5OmfwT{N zUw9tF;(eGurRMaE+*j6VatTpoYN)*9W1PK6NVT@l5PErflFK<E<mhdrJ;SPa?QS4> zQgok!SvX1ICGp2)oTE*3H`&k!&Vr5#xmt@&3GBe-ZIn*5g&&=+{B*Z&vdU~77+4vg z?Q<>%rEmkD+&PPRCvW1XE$X24oFy))Wgz<MJ%tH;><YRAJ<TT2T`+>_A`R5fP!|tJ z?S;b+rC>POpFEkygMGQ_(3>uetNxorRPN-k|A{7$f13-1buH)dt<-Cbb?hcyU%7|d zunn!D7jJfPJ;+7NV13hFs#oJjYvoqZw(Gly$c$;kzSRKjwY{K9u$T0z2Z3RL8G2m) z0RmI5Yau6!Hd8sB`~59ccC#^+G|vaPn9BSb)qwT)03zpIAe-FtIqsGc{*jXemlt}> z{J<1U>3PStG#b!bEs{7;p^CSw($QKvfnB@v6b&4^k5sF3F7<txr1hH~y*|~P2LIT} zj5z+I{gydw`8ye$xP1W`d-*uE^|wUEB%W$iaf}!r1^i68y~@#i__sKRzMLoy{5*en z9=nnsWNyb!4_Ydyso6p@bvwwM?OeY@d^=WVhrnz@9)E|u1U<Ch1XPYMLiaU$*yj>X zur%O0`)T78NS<E-cMJ)Zs#@@5coVToC!8$k*5hADa0ah{Y_Pg(4&nFHVQ~6Xlv?(W zX}Pa}6^nPmpxRE-Uh<YS{8oXCp<&kMlR0^GU0aw?84T`oH(_T{59`tN67AG>;6^@! zm7Kr1!9EUS*PUbe<4Q=>g<jfuwS(QH>H{a$J=nABcEWBgM_k>f1JXZQ$mP%=`bXv( zPVQ0^wA?kuWBKVc@vH%a<z!Ny3`g4K9SM&z@&TuDZY0^Y=zrB7Ev;*)+zA7|PEjw} z===f3gFLAakAzFNq=ij$>e#Q`eYE*Z9dVE}hKs*<&^JO2^wOS6xpgqt8#;lZQum<x zi#vH+JDopSf%BDxH^585M@C^oKKbutJrSwpc3u;$U}C5|?CH2gnBG13`hh6KYs-++ zO*+C4t0eh3U1QN+Clt%w60or6Bt`EtI7?MVc&_ppIQ#kHbF&w8t(A~<NQtHQyk3#} zH)NrNR|sh@3mDfcc2F9;7>1|H@LyD}WNY0IkQCiGlqvm4{F*&+wc~fjE!hkH>+pd& zoffp->@&Ojs*nl>SfXh^fp1^nPh<Nh;jB8&6*iDX73&T{S)j6c^H)D;ohQQYys-{{ zow26NJr*J35rdf}F_<Ww#Cf~i!2O98K2?-}uDku_6SDJ3vlG{svp)!P+5-6|N8gfK zsq^&ZZ;Cnx#7V^Z^TfR1EdEH|2`iFK_~5Td_IjH0^{()sO@5p(Tz)MEh{VyOiUL;p zk0|zY!qkuxo5@+%2`D@EDx0Hzk|~?*Nw$8xL5-V-aJ5?+`>2->$0Qi8+Z+kO`$ceb zfI7aYpNI11W*}kwitHFCEqoesg(-|a&ar+Lpe&c6o$Gj!^i|5!TVI~h8^(I@^z|~b zN4km;lUYkv;d<eQr`O55z>BQunYUaPN`dpU)<N@)5D2&P#i+p#bcB01zKXPgrrT3^ zb7d3ZQGOE9ogKjU*unL3r!lCoO%A5<25`yK8SK|zM^SbnMN{uG8licC440S@&+G_Z z({^W4YW0&n(K<nJnmpkd6?kJ^niT52N2<Am>qj0?2Dh!tg^%P{;jNwWP;ReCQ`b*o z{s_*~QvVU6zj6{-E?I_!A2=7fRVbajMh8UAywSCn``Kq0lhRK$?ARI#=@yU4Io=L@ zdhUA-=KX->1$WqvC=p>~mL8tJcNF)h-WKe2{>C0wn-6EtBnY1udE!Z}AEeiH8a)*@ z4HnEf%>UCq6@R7q!Lkia^vgufe|S2NMxMAsY!Wlcn3oH<?|qH8`fMY6a7{mL>9~RE z;$um}iUUwxq6)k1JBUt>3KTfpp}F70@vTt~4gFM$GVXVX2j@;1+V+aIU9NyubsO=a zTAc8_>vMLwuQsSPghTqIk7zK>m}A2ngSc>S)T??yql&)>zBwC$VB=ME<3$V1o=t*p z7o+JE!G1WWla0oAY;fWg14t<hr8xnw$-e3O@a)|wTG%lc#cpfB##b{id5RMz1&g8h z6c4=gQIYwmosF;Gwd3OH@v#3i(Ch0{Q6h8(%}fa;UQ7z<lAcI^7MWuCw?Ou=!GCxn zo+Z1Q^JwXEb=c9k2r3uX(aVc|km<u_uzsT+jlAzqHoLxHJtteEV&4V2#ZQFaSQCx) zE92Spt_zIDvWc)(F_eR*O@zu5%@B0jzv{8fNhtYy0l(Ot7KZ<+fVQx$;J(a(y#MNo zyLwbOAE!My`A>pKyG>+#++3bdz7R{<OWX`P8}}Z{M1>$zzV8z~XwaU^@A~<Z#%N?< zL9PmsVA810J6||u7EOG2MgNbYGYzNe?c%UGq>L$ZQHfHLh_jz{B&C5Ur9uCwh*D{u z$(W20QY1rE6iI_Pd#$61CZ#!Jq@;OPX?pkj(HGab4%gn#v)1o--%!yuRx&E~npD{$ zmMninGOeHn$5BpCAk^$KKk$YhC#7IGwJ8o2-)RcZlSZs@(jkunJo7CGgt?#A(3idG zH2L~37NqRKy3-1Aofa_z2W@<@{1#j@Okph}^tk<3a=CbuPqg*82b>E2A$;D~@LRJ6 z-^Q7Nv0ftV_^_8xdpD4Lg#CGpnm_Gx$q)_h5xAqmIrnqy4W_)<T>31(nU}q!K$WXg z@N(BOMlz3u{IoiVXO-fHyK_au6s92M&!D%(5Ao@uKzKQRFn-rK$E@m!KBTK+Ve%e4 ze<=$almxdx!D;UGNm-N;e9cBn9mLz`{zdP26L6Wf5|r+@@b~*@!n%JanfJ?TX~B;O zIPs1b|6ZslJ|8d3XXzcFMB_>raCj_c$=Sl0;92apTL7DpEpUhaw&Gb02hK2LJ|wBk z6Q662r$2tTaM7p#==LWy81i^NOnrC&rg)XJX(@pe@je~TExAB@wG1&c`4?N|uM5|& zq=>do?dE+}C%~F5g}h(uZXD`z9$3w4#!W3iP0cK}{qSBkG5V3HZjvFauo(e?Q)biY zhHVVzB;i=IBKkXu0WV|%KFrwwrHjkp{!GD}xWOFy^sB~v!x&g)eG#wp>XD~{C!OjP z`dn2HS$*VwW;s3r%3>xlYa_u2s9lIb#)DBex{}7<e@RD{q+{P<6U2cRgx<VN7n>5Y zkj`5KgX5Y7Ot+y$@LRiz3M0zVv~M=_pB;&7W*;Ws4{FkTD+bV<&Uw(A+Xrgq?E+)t zqo}y{1l^0s0rP$7uwzy()+|}T2H0oeg>+kb_}hwwcgjf%ZpN^;MrmMjB#aFUxr)c` zz5=run!-#j0RvQn1m>*)*ya~gTh<0#v2Hk<`uh*(de##x8a1F^Qv~NPodn0n(QIGM z54OgP*vgMbS!?=k9xJSH<w*nDSvLx&krh5IU(U4@#lrjqBib@pheo-YVdUa3s1>wT z+}MxjvxPo&`19`=mR}B=I%>Gushg=eB%gWDkLNe<yp0Bb1Mw*w6h-~cg3B+p!MN-e zG`>(0ytgvamnO?O>E>C`v0e@gCp7~)pJ8flp)~Kh;6r#{$~K%$7JL3}U^fJ(%k``B zY<)+PB;l?p9gIJZ#S^}A2TdkOeI6#^o}-gt#gxJHq-!bn=(;8i|6~lS#CFtesU+4t z9D#Qa2rPxa1E}<}7aefTBD*zy<Pg^v)?Ic3=e3CK+g`G(*Anrd)mVBvN7zeFdWo+# zDAR&*88o|b870WRqT{h6IhvM8KT?Dq^`m&GU6ug47lYW}<n3U7--DQy9(8?AgM;r{ z@n7Cp%68M?UET6nwEG=c<lBK8j%L%epXwCedKizcISB?j2brrVkhBX9vym4hQZGeA z`qXfor~busey1jl+-gmQ`3l(8wjLgQ>JaDMR)mEKs_=5@Z>}=*m(+UOAN*Uof@_dn z!mNEp!H%kXEF}CoyYfRHhZ!HogeP5~yjw>)JAWoQ>P0}#(paI--^=Z3xq!j{#tM$N zLiiMUgR}grBF?BleqiY}7WJr|EjJc+4<}vV%;!C9=DGxsp}VA6lueDU8Ms&)0iz;| zq!&-e)2Zb>xX0);n;w`*V7Qzfy%<c77L0_mZ#KYsnZ0;Nr;B{;a@nxw3&C${F7MFt zi=S8(DN*`1l~NA{!NCTB(fP+gTD!v+-w%q!E2hKI->4gpJ?P?-^0Q%1avZlcsvNwZ z%m7YjFMnvlZpzpF#D=6_W{o*VVVb~Wd)1snN)|(T%dIYCK4&8t76j3j^-VZG@}h7@ zZ<d^P?SoGm#z5IoS@_*&0#T$l4wxrP@OK>yTU5s{Fn^8}?Ot@XE0S^wtx5KRp~NI% zEtP#egx|NAiPO$0(A-V+OwMp144bGe-8Lu|mVZ0Vhd1TXu1q0|^fVjRx(=oupD`?L z%n-3(|0Zm>ewjP^s13E+&vN=R7h=aYYdZUNAXXgP1D}=tldfH;FIwZVfo4=_^HWj} zic{6aP_gJWOj7^FX59#dEs+yQ`P*eoyOTn*ZH~f*1QR;^IEI_PastV>jl*p_@8gS+ z<7q^Z9|WFpp^Rm#VOnJ_Y4+=4^rwJACkT7POkGy=ERGuQE@f}+Z_?#kTC|owMaLW` zpt{|Us=Sj#Q@*Uj4#h}_D2ih@Ty0q0nM_VwGLy~v*<Tu`X(TS1`h+}H2BZ3@d9bU9 zgM**%bBoQ2#r6wMW8Ysk^tW=lSduTtwJhrZR_%@(xhxEe>Z14wUR=+k5YU}{^Fs6f zFKmIpG%a|PMWQ(q*telW$baobIvifXgcTDzGT<!C`H=@*BTU7;`wms-^}UG_)dE~& zb(t+nTt)ruuL+*Op{&w>ApPi>2$=)l^A(@I(Y_%cA!xyIbV$r%Q$CF26D;P!i51$? zagldvlTidKn>~)g!UFljiVuX2QY!k-(}xqcN-%+xq1=BM&Q@8#-Cy(@vS}H(-r5A` zy*{!dr4FPWlF78GkJR|Fn4R)Y<t!#=vz5)0Y5CC~c*IL^&ul*dFO(8sphp}x%S?q< zDEvW_ZMAHt1%Y<U0nA@F43aDlKxwSdkGK)aHa2O{R5NFU(H>Mft`E4bTLarq4wqIR zKgQN=P=H~_RABM5iIg`{3`sWE>GKXFD1Ee@yXX0krVIJ%e?o@q>f1y*q8ko}XIhDe z4%DE`+;}moOolzqGSb|is+cltDD`PjU=F90Sx3t)UV=K@-^|6NUuMMyUq`xf@*O)M zD^G!XdeVT~DY$g_0jM$4fPbOJ(EC81^WQ(0B5t?yjz#;R$Ss_W9&%4O%PG;0rT19% zgb2K>Q-dn@QuZs_KyZpyV%=C5Xj>9Mvv>=*F0iRSD#b}7EdGOyTQdYUqAZ<u%g3v0 za>01!2>5h)Iyo;6r-Z_FaIYo>{QL#>bhr*^4(r1yT&We`$Z2MFragE{B+T><4wr7w zT#jTANhu>cv7%1}V$&MjdgwMYaAlais!O!8DGz%cMv&==zqoeB4zk~uhtq<!ar#hu z{Ji@%cYF2+8djcz^Nx8k$BoY9Ke(DH^rnEtwrhOqztQk&>^@X$&7xkbyUh9C8P=Nc zoZcBR@Y|@#@3YXR_wG@k(ryg0cMej(E*ol9Ho!qbIZkWcQ1O{7rF2@e1w~moa6ITB z`lw1+T8ou5U7|o&PuW8MjV+u`c>*g4^<+Q2I+6ES1>I5g_~7hH@DG_q@jCs5{-ZK@ zr5t9@UR$uzp+`|qYXar>wI+=R4|yG<$?!|Vo;@y6C;K818{c0IXT(M_@dZO%_B#Rp zI!n3fW2b<_nON-UGaU6>&B<F}Ff1rj<}^nmOC6#KlkOj;*d+rvGvno8@=T0pzAD4y zLsG1+uweGRC(+hr7B{x$pTu<kTG;)5J{UG9QA~ex`qTF(YjxBV@=<Oq{heb~+~M!S z`!yI{b95na<9Q5BNx*JBMO+^?T<GzfK&$7a!pvB3?VgpwY)v0Bdz(V4!aUF6?QV9* zOO_t?zr|_%?oTe83t690Q|ZQ>0(ShuM{e%IYxun95ctjEz{9qK`@*ThWl^)pK<GeU zJY2weEm9zFzgPU`OWNWuzf@^*{c`B<X@cej!$4_MKehlHAojyWvC6|dw3%iN`d{)% zrQcYo#fyQoH2(%l55Ht@Mnuumw}KOV-%Zw&bCCHv=Cf|YsjO(WB^f@+CCBw=`Ewzj zw9+9;oOD?h45K2%19s_h5B|DP%&Yr+l5`?iB&~)ylWsGecUzz)B^e)QWk_oer_=Xi z!JGlU<n&KohGm_Z*soH9d@e=v*)4<Us!A2x?3{yFG>Sxp`tv|8p`9DLCk}VbJA+)i z4&;>2=5y@xkvrW7;vS5`+0(CrX3rW5+OEyu=tfq+O%@vr@`PsVMeyZXDl`6T38`MO zT;@T2=(cNRaYGJ(tBC{cUwfC-8*eflff2b`W&-{>F_w*0)Q3+u-C%o16w7=T!fN&P zVawfvtgF@qbX{C&Wz9Aw7cZPS4~?apUv3Bv*k9b##wyn5%XAj)+k#qe`;olPBOG${ zKF)YKn^d=n@ps8yrUoN1&e&Z%GhjUP{pADuwr4=>gBzk;eJiG7b4|3TZm{&mg7r{t zA1n6!a|Ry0ZRc-Ys-*j~ZNy75y0OH%m0R&{AFH@$hVQ<VNQSgb$LzvBOyk9OcFNt7 zj-Se=-j|1Q!DByqVc*5xbEjG5=@XFMvIqz1_A--K*QyVyY@r3dzwwNsBHGV*zz6mY zVeP^W-T9gq{E8Yw*Ejl+W^*oF`0$1oZH$*F1V_WYEIoXb@q~NaDq%Z)?U_%nDqU{N z5=A79qLnVsS!aVUoR~M0Y2S=T-GC@KGqZ$e%J-N`o(+Zk-YIY-ym&1gAChgip{-61 z5bAq~wFq}%8Kwts?Btodfeo~%ZNNnZ%@T2G5*3$P(~k!RIC<(wv7eV6<C22d@IHAs zKdS}?1xE305Kob@<^0a@A~s>|d&%Q}-<j-7e{{LoMbFn3vL9NHFyZ4+nA5lhK3ohS z)6X7!RGv0;DR+X#0VllaYsf#bKEd6cqE2b6&$7VkAX>I43icgKhk)~waEjzFo|~Kp z15;N(n(KaEWArAHxAQ{1Xd@CE&IYCK;h3_d6^(8?!Pojy{#*4kuH?{kcyZ$;uGlh~ z)7Y-X*S$7??FS-Jp3`UV_f&8bCQYFY9~m50dc%xn-C)Cx1fw{k6)zMk@IPeK@#q;v z@!^CGSSzPQGaU`7@8KW(BIzgolHF`No*i91c$Z+jRT9%QbxW}AJk1BuA$HYH4$h~= z!K~S)ta8wPsdAE(+cW<*?0&ZryxI?eYSdCTOIMZZ%$@j2(kI-^1q;Lr52?Vnl7qCt zL`<uP4Z_}yx#;CSg<bs|$koP5X{T`<-{v6CmQIgHmZpUJMhmP7nW=DlMJmltumSB5 z1<FY(md1YFj<BN%&qZlUkGTw_*9N<pM@t0^UvEw?7A8RF{JSVRyNpaDOlcf9nyvkB zxO7MLG7>wjVyC{BQa=MHs8>8j3nM~FVUr?sZ(a@Y>AP8h;S6rXrVx^JjiH+x%3%MX z>8x1zjK(rX{LS|#nQ2KRdWEg01Dcn}=bQ>1J<x?E_ERb3upL;rkEhuRaWJPgTiSGa zEOm}}$p_LzdTF$lU-Et~b_YlBAuWBubs{g0?Rd}TxQ&6ICF;l)tJjoH+QDbPo{oo> ziXgAr8DB+?W#`n6u<i%y5D<Kjvt-v{K;jLu*}jMK$Xdb4h&_3`0T1ZE+Y0>CA`e)T zzLgD_Er*3hF5+D`=b>1CHaCUZSafb0?GpPy`@a-^&wy00TX>ONv+q;kr%3edzY$(6 z5a$066G&;W6SYriVP3%xaOoKj-e8~$jIi9x6214swb}((*5E0Mwn}0lg41Y>Yd$wG zxSOf1@ug0QB0W{-AYV-#lOCE&C)W;SySv`th$`W|H!GgTuZ_TmWtDKlXAWIVFNV;A zZ<)!=m)K8XAmxTGfcy<xSwdVnJ97Ux&0W}tX(CRN*iV)=|5`vd{+`3fGM}-1o`@-3 zuEVhPt1!c|gk638ip93oqp%jDG<c2uXIlZ&P35!Fd`aSekfImNAm@)2eA!_kYbc*X z+nm3%eKUVSyzye{SapM4FkTA9)8|QL4b3EPl#gOl%?2|3GKme3-vw2L@i=<Ub&eKZ zaIpWv$kwoot2K>aQoZ3g;Y%<T<^0AljYRr9#hSh9RFf+2(8P%BbXqgWl8i4Tiw(?l zfq$F?>Zf(FCm|5VZ79R>-)3>npLWsnC9k+GJ`7x6)v~aj{bbcIlUXmz6m{DgN}H#K z30>~hbnJ64+n(5pqF+Z@o$!v^RUq(qbw%)5;z`$%c;+>~f)+Tnpwg03`Y3x3&5PGS zD*uqOw@UEECqI@J)y94~_u%N#l^D3iMDRcr(BplNSor-?+CHvQ6mjk*lia<_hAVaP zKPHQuE@zjsNu#&Ybn6}n$tdF$DqY0opM-3A<p=zh971t@Crid^>9Hq6B)D5Wo8|0@ zKz{rII_G(kDL-|fZ@)FEG9e$m2iW3s2NyUdlf;D?tOE0XdH7^XG#>6smn_v@3X_ib zO7*+ui%#3^7CE2PCCv&A(0T7fah_uMeJ~A-w#4#xhsr?Q?<Q<h*voRvbfqDE&B;bX z$O`WNi%V9h(fw7UVb#;)_}`$@Y`)1(T4Okr59pi2ZGLoxPc3bOo~U@(Jg%HIx#Y7G z9-}F&tc3OX_L-!1!h$2^BUf1e8{hGRXh(_`1!?WWfAb0jKR_fIr}bq?TZ-9^zIyoa zbU1T3;SC*yJJCK)ldTheZ<bs>*KThNRi0zWb(sfiDRiW$v8Ir++yQKadVrm{iLJIO zX7a(?*xHyP`q6fu-7hVW?)py|KDOuK;_$<C+Ae_`-ltaR0N9d&ZwU-i>LZqdob-$K zO!3#}?(kTYDtMALq3`SyD7S1cgJL5%tmTUTqLyP!#~$*iPyvnbc4}VR!0ZlhAa43! z+O2Cqn-&{ERqG7!ksAwbTruDMS&pCmrv{HzIm6ia<=p6s7;5M}zz(gS$U1KNaScC` zxi&3F*tki~A<e3hlL-`<>_b{`)2M^&){1D5x%7@kabk9M=s0wWFBbOfb7*|bTsHjL z4bDKT1LItTJG%8Vc5LcMIH-1<R~Qitrsa2-(acJ*$(se$msM=IOtTiQ#`7wvX3TNy zuH8<t(TQ+)&sa80XQrsX%WT1oa1`U-bg)0)$FmQXud$=khTeIW@b>v?DC=d(y;Tjs z?3__}sZ&BbeYY{!Xn}j5^8?M+4g#GqgW<%-!+g|PIXLuFj&1liP`Y%>Q1}#amQxBB zoM@S!xYe)gv2U~B@PQ`QwBLgHXAGu@kM`Jkf~Oho1M$oQ4Y8VAJr0ZB&dFxH;5K$F zAa=^NT6V%+7P!cXc5YN+i)^Pdsi>CUmnxQ)OtzF{d>92Gc6r$Ry&s4aP3XAcO*Tv5 zm(cf2=0ErjZ<e0LK716DXYgO{6W78|6RSgG^CfhA@TJ=8Ltj)LrUO?Mzq7Bc1L*5X zhF6Mmuv|A3Hl2~BqG<w$IeG;RoVAl$EmyG4`F~hd>?FMT-wKpY|HG!8bp@3HHtfqi z9ayMU$KN&=cq%<|w92B9I~t$Q+*l$wE|P_zKdxYR)mW6DDaETY9$;kZ&hPQ;<Q84b z6rHeG!cwj%fm6Q&T+h;LeCLKg9E8mf_)wNC+HnY_o{Xo`A8}wV-23NcY$Cr=Zgeo_ z1v_Ovl#kE@*js2o;u8a5goP!)MQlrf-s6~9=sI@DkAoL4_Q3Ps)uM*FWvuk{O<dyJ zhfm`k@K*!dBxlkrnTGNx@dEj2G^EM_)){y5!IeMQ&400^Y|#zlD{hEyx-G}PYR4tF zkJV7aiJJnuZML{YekEn;9AUeJZglU1BN*hP1-_MCc(Q&o8#-txTxp+-Z7L;nYnl=s zYZyt(lj6lEc2#m3|J93WM-bBy3(R86e#}$ok(mk^5Rr`)(~}W_`toIz+_GJ&*)fU2 zTB}g>$qZG-MZ>fw={Q^9M^4v0!RrXUW#`on=y2YR{+l{MWHf0i%&&ipi)wCF4IQvt z5|ZZz4{B2|bOX=V3M}?YpYhz48yOHXD4v$R+Yi~Df$T_sPqCkpIn$C%huLRW(}T+! zVS7a%jQAo&HPtc-b<`JU_Vgh$lLyqMW(ZTN8qsa3D!n{qz$Txpf>5`$prPr;bW6h} z`-jN@Q4yZD?+aDp^JG}OgcYCrhRV<0pw{CgwA(R=BJ4GwL14M*Um3%!W+wBllSZ=* zDc^8fs12?5o{!}<`z0RDrzLpqAzaOU#s)qtfV!hcfFD!Cg|!+o&&NaISAZqF8YUxF z%Q6$M$;o187Y@WNA4R01?+2b*nYgi&V*^Gn<ui5qg5C;EHsVeQQe7qI7%IZCx3);% zwI`zSwgAFW^>qH5a5gsAgW#$SaAx^FZcMNdtlN1L9dc{%?$__Udh9m-h<$%DYFfut zuMXn(+beTNybNiK?h?wM`2{Xi6rp`lB=3DBgU$FSID^&)UMSF1!eEO~<oh1SlVPiH zy-XJ8GshXPp3DVlg%K)y+L8FLIvAUok=(KZZ1?qK$4brNr{J628`Fn;GPNnD)KJLw zcCmMT1*b(;BUhyNjlH?44pl4t_-}_U@cB1f=)~6={<ZpZzRPB+_?r6@)XNyaGLyV% ztp6g2(o$rL1YY8*fH>ArlFv#+{cx3e0q0VjhQ6^P9QpVI3+g#V;w(iNzPc|=IHX0( z%5>qPyBYgytSt^4k%&g3i~Q{MC)vKfa{QGs-E3D<EIrrS3CUgenM0%scciL_+gLRb z+TRN^-XDd`{P-kVzAzd6%yV(?#aJki&&7V}j5Z1Ab^USbWK(KRD|h&^a=j>g|KS<0 zy5tEf`1;D>P|alC!(opkeY+0Y^iRYMH`YRTo&jW*E0X-2Tf9%V3X>hENR3ISn4kSq z_J}$1ce09kZ8V|IdjYi5Wd&<%EW#PND@E@FUig%*gVp1GO4-I^o8gXdH+J)FVzN*S zVpTclGz^pm3mnp48`UA*BNXy7w!w;H6VPs{2^XvQ5nE@CVRfH>!HFM%?BXS1zffsG zDmP__eY(lr_X-1@WCvcd=?INfUPL~9)%mn<^Vo;~j<PoE^JK9P!64)on#Y+?p63cG zJDw~(%vUlu!_D-zbvWcWU0}&oyZHMu0Wjn57;3wi$Be@dWBHkAx-{R0win5;f9jUf zpa6aRW!B6Nth*r!oI9Asr@7E9=M<XS_L*J!Wy18b9^v0NfAGKCCUib5l4c$mAyyII zk9P0Q;^OgEc#rYS=Aj$OtXxllnYuJMZ8=3+*-`j1d+F296`*%LoOW4kgtmnx(&AaM zSQ}$Pe6luH-;-gM%f92qWAW^hG?9x@Un~CY8O7$Fw}l}>{_N!NAvF$bblAJ^doX$0 zQ}mmx2vYYn7S-7YbgfLmN}-H(YAgbiAH%3wO9ir(H_-LhdNgU)7)(l11E&RdnB%Vu zbU1L4HM=Z<iN+e3{rwPo-cc^}8e{4A8+~}UG#>Zfp9|khdNC^E3+|43fl})wuz&bc zY24KZ^dS2-=YRe<TUXr8_YP{6$hzl)Qc5Ua`OF3ES5)H{=S_^c)G#eC;q$l$vMW;r zcSlhz4x4FAdAqY9K`PG%EiI<M#&Y0pG>+;XWjMS%dyGn-O~GkjG+~ARH{p5i0LyfO z*+2JK8Z@<*|KsBgzT1*n=Y+L1w5>lmceSz)EyF3+&Wz4~SV+g384hi#z&wX;uIk=K z?sZEm?pgO7H$RGJE8VLZxx130tKfb;;ednIec(L)WMYl8FykK`!aj8O;1{kE!?z8m z{Xql3(>slMmkUiAZwx3(}XZ@0AmzJlOhu4G%Ly~JflZ}FMWud>JQRtg>AV1fT) z#^v1{DNL9X@p@e}xAEF<^s(`wYjqq;SnEVz8hSa4C-qdgQHrTq4pi}a0*%ae6`OXI zL0865HvREUerSj))crk73U7-gkMtC2c5^BoKRy@=d}Em5H5YPsJjcGeuVzo450=J+ zzh;RSCg3yS-d_8y5*uTLbG7b#O3hJ)`Ue9L3RCFK^C;LId5g4G4yTMDBm8`E6z%u8 z1{tiDc2~Am_4oLS(G%|DezzR%n~5pe{#AmLL$cT}Z##j#Xv+JTU*n#{M@W|Tm@*~S z#aVlaoZ`n;Z~<vR3rF3Aq_wTw`%C&T?8z-u-xw#l==B{R8bz}=J~>n$SdNq4juF_C z4{>sY98K{)<DjkIf{VYM##gp#Z1!g_w&7+CE3&;o2`w7Z3YGJ$?D<L7UZ#iL6%G)f zCYGLwF=s)CqS^ASOm0{2AozX6f_}D+5&JyU6!;QbsiTBg+1^52Kg^s;roN_iUyN|R zH3w7wGr@5Re>tZ+HK^ZD$l$1ILO`Vrh1T}4|6=>&obij%A%8h+9jYR39x;gh%J|J9 zJ~`9#+&L3oh38U@e;n6Rn;~?SHA(lkh-$*i=%v;Ua=8@_HHNoojo&bOa;raAy3GYo zTfgHb&pyfua{Sn1$p<boYovIUYCUH$N0m))|B3}CkK#tzX;gY|2}}_S{!#9|RH)H2 zmA-=OQB4l69jhWsl}Z*rzd~C6;WryK&V&}(ET?&^GSMZvo|QElll$Wvu&=WfCY-X8 z?q2Z%ZVfkpfT4=ym34>F{r@<n#31H*If9K(?3H{pEk~JUr)W!&8JLzTORZz4v!nMD zDBpeyrCnT1T2#qyC(A&4w9seUEu5oPoneRNZRwT0Dhw6of%VrWlTCC98=@A44`1e? zq3Ru8-+u+P#(m?q_B3&0cD!bBrK_+V?yx*z-}&TkI+{1-pn<;`mG^DJJPM?96ZN=7 zay!u_pp)OEIge(Xn$7P$dW|`5%jdMxmcoCW7HBVx6Q91}O1Xpl*s4K&Mc0nUldAF* zh}t%W-Xut%q~o{1cKX0B9LR+5<%6h%oZ;}-Uu;bLJlv%!PlvAi@?{1Sk&`duT|OJr z#yyD5Vf#tOy->)|cj431ak!{sGT3?<ftI2Xx9;5n$o^Q*&MfAn1BI?p@Clw@XZMa? z#g3&SJ0Ul4(~oMDdf9)yS&Yjc#Z35I$+`w9jsLp@_j3oJ>Dea?{1c0-v^A(^w<GDy z+|GM$7iQV}r_r{vEAW9^9DDNS9ADG5L;6o%TVQ1kf%)FX*!cJv^ETarsrfykrw7#` zyH5>QcRHEfP`88RSYMj^(Uzh<T@-cuZGks(&(ZRmDU9m(7S~pdgV?Q4*@NpPSX|-9 zRgbf#D`~;-O7Nf_$s9!nk2xB>{6FZF8w{O^3XoH`7W*X)le~*r3n!hEAUt1q_vloz z>bfgz=>Ef?;9^PP71rE$9Zg6u5kW?1ChJ)Gkq<p0{GUz!j~4jYz}DzfEIHvATdVqm z{ns4FY!5DAOWx$Ot!i?jKZRFVkghzfe69&2`gd@rm+I0oM;nM;sz$DM!|BmzZ@RWY zhjr%eVR0J9;)}x(hmYtFHwJwdyt)T*On?m7UdUmSkNL56>&w9S%uPv_G>>)j0;fIb zHqNbxLQ;OpCj7URW$O(V`xo@5D|v$<e$EPR!Y)Ci(Q$~{ixc7gg%{%RQ|?%O_aV2f zZ!O(2eoxyEXN!aDrqR((l9=h$@N-w(=9UfCf;`i66xUQJI`zr`4z2mZk-e|LevQEB zLN8iUw_bd<{yZ)$ZxxSB+sI0m+fmQ_m#oQ0V1N0{htL)U++OvQ1&)lSV>Sz=B}#KC zva$gCJ>G}k=S+ut1G=$iS0et{V#Ai@50RYb4q$X`IDIQW!nF#|@$1>~wDiYQPI*!s zfBmQn<S5C|rAgO#leA@cWVIqArDRC$uA%|o@4zp!?;_X#^u=0JF7vyl2zQ>XcPUdh z27U`!?^!=T;llRY)Zg|Qr08X!wP7)-*xY3SJLReWOAR^{-N|IM(&54RByda~#$UMo z6<sDgWD45nu&1|(oqzk9Mvd6y$m0$C7GNRtOy*(St~pc}TFRmugc+o37qgMcVaGg@ z*oKk@oX|LyrZ?TMj&jXIyGPCZIO#`rc-9Q&`mqXF-(=V*u!6Yp4zSO{6H3Eg!u(zk z2h=)=XYJBM<!ZrGq9n$7BXn>ZYO&popV`YB(@`mF9>fHT*nG7aTweQCcIcHbpSiSG zy865iF71~?pA3J}gnL~=M>_@Fs-^%tFo)Hc6a(k?6SZIW$B&zm@${pEymNvK?LS|H z*SGiZ>i@cVew;jwy6Qy}!p+1(FD=10Z_-e*<P4XbY(}{wvJm?Gz@hgNFzdZ0-tYGg zHx3&P{t;bxUXls3g)E_>?gU|GSjUW2Txf%;zy;i<0*@xXV{2A%G<l^gwM=oM@%F83 zUEx{wG3qz&upa?3TeTs3%6X<5Z6$EoqR`wu8|Tj)g_~weMYph@_^9~++7T?nB*Xlu zR&6Z&7bCa~$dwZnmI?g0d2HL73;fs`4}7ts1j~M|hN9YSOea_9IJ_AS^&_5g8SZgd zDdhih-BY-V6$8Xy{ZsL4kHAlFzQQh)JrZ3Eea<q@RnfS4iy<R*ANRb+;X+BrT#&Rn zfXNPZc4Mj$JUg|5#^pHEH0~iDd9()%7p}mt)JE*}+QoGiSds!A{6C{vasiRMdQ_K9 z&245Sm*(Mb>wc&&*MalwQ?bayj-4Mm5dO}2!b(P`(;f3P-r9T<yX88X`uAG^JsYxV z*1duJu*?43&a>u}%Ei&^`e>ooG?MwJSWA8mT7=z)dbpfaZRV`C9|mM*;=`apu%(~` z?*E@@GxHPqm-YeY^?MzRAMFE~d;Q^<{C!lLag)8eBSYN5DsDV}Vs{p3Fs+@rC>vRV zHBa2A_xWj7-n<`nt~$<b8<I=Y9}4sG8HYs;5y}EnTwR!9H4wi?R=lgDnrqq-Lr&M+ zsHu68bi~Oh7Lam=6#v!>oC#l0*)&{W`(`q$$WqiUpM_t`q?n?RM2}7lBexa1xv(vk z(vFOAZ1j>Wq1SPXkAWFDKJJ>tb$1!vd8ZC+%@*!^fh&dg7w*eWvVsd>2K`t#Qaq!o zA29VOK4{2gZff^ruKnR6!5g@V?sV(no6rcV8(=}N?nFz=9=wO5*X8u+KmZ#Lr=^E> z{z5ntPNU`+K=iK~zQ2zYGu8|ISs{0OW}Jaoq@gG}GG!7}B}Z^Y&3ZN2wpZD>svPtw zi>IE=096<J!S1JzSgVo|d^nxX9{kbZe)xXkGKwSu=Omd$nzo^hp*`HTnFMN@wm3cY z54veqv9({lsr*tj#{0hDMrE95A8pr>|C1iJ2Ge-&+^Mk3PUvR%T5>7LdbqnyMR2St zN}o8zQ9;5DRyN0*tqJhNOv?@)m)(V)=OyU5eK73Z`;@En%7Cw<Dj6;51CO2-vv*p8 z$FciAZsYPkwCu!jnB-~A3VIUATV)Cioc{oo7DaQ%guQaiJrj(y?`0!`-_o2oCFZkH z0Yj!F(x1iy+@(Anm|y#u?Oj?%#b#Ua!x$GfUN{@H+Ha*#c!+ZD-Qk|b_MwgU>i9I{ ze(Z<e1N=SYHZDJUfE%$dfn`KYroabP_-|(ucJ`NW$A#z5u6U{B!L3K^-*^W){?QjT z`sZTPEP+EftOK5p(ZG=Si)@~TDX6_LmENv+%XC_UpwFr@?rhB$6gO3{Qo(a`-Nc%$ zd-DK;O@3hB+V7YgybL==w_<-KA)mim*nhTuMW4a-Y~lXLj-!*5=ux&YExS7qgN}8A zw@oh8z01Lct{H5Wt0{;(t7%mKKur9kjCbYhQQ2)bCq8th+DypbIgDv%!R|Y`7uqAG zGyN4{*7S*jSIH5o<PM=7OQv0E!WHLJD;xT&4uk&7rC-$tLBrxK{aNw~6aRZD*|xx! zRNr0^xR&LVG`W{mDDR=5#$1|jtO%ag8g%@1BvTF75I?v7L1&IW=CU62XHHS}Y@*Y8 z?(xh;tVZhK^zLFhTI7DjsKy+yJU393=(~}UgtNfi<8@5arGw3!?8Hizex`}D^YEnc z80eRxN2w2mopY)_YijMlPy3^=ZSs4T_jmzJdMQG)CMBu7&2DLm(|4v|?9C#lo)9{g z0;9{tNO~x6ljwT&1dwVC2I)Qy8W)|w(!ayR88OdTNmxE{w<0-gP{#Vcv2=R-9+ERo z!25F=*$L4mycQ%lud;^HmG5!nB%EjEw9KjM<}6s?oz7biO~Xa&X2B^r3-JPXV<!Fr z@MOLp?JrP7?SV__RFgV;J}i+PQ@(?B3LKTX-=K<z`>8oC1VocnrL|vX(1YYfZ0duz zjw3aWaUS~}xS$XA@aK&O%j~Bnu3EGT6}`@j{)PNOJaQW?6L+GGpDI{3Wr5Gjd(vrN zL-|o`4-2+`%dTuJqxbcRqMU*z>CXC7?8vids*A~_kpr&d-`m?IlC)oVR3j0>mOqDd zwn3`zWl9Rw@ysjZ6^nAtmR!&43zvK5K*dyBX8kQ2^#&@D$l(CJKA{P7Ev^yAU*w<G zrqI^CS?JKPnj&Xsu_1X!SY%s*Fb{9yH_d;|8Qc$}oS5;LZ-1N}Y2>K!@dg-I(u@cH zXj78aHukG-FN|+ehoGpa>hvEKOs3x#QS)LS7XErH?5sSBCB-`Q^4(r4eE1k^yv%6G zh&8D2YXoJ_%@Z}Zdr;X_cd7{;09I>znf|8Ta62p&j$7=5U&{9=JB)E<JH}yKZ+}Uy z-xDDxkzM_-JrHV4r@^<q-&oSjB=9bsMHc>hV9ejqaDv(4pVKedfao(U=9B@dSVfD{ zodf8D>{b5m_YSVKYAJ?jbfHtze$lyuZr~~Vn<)u*bi*(4@O*|EL>;|^I=d9%X^}0J zCdx>~H+5)8Y8jg{&ypGjw6OjBF7{U52sTbw!S1<NQ>V{jt|U2&bDz_Wv&YK<?d-r8 z!6x|Q&jBV5{mT-=+^E2#9?vQ(!RdVlxO((lso%^oFl@C9Y;25Ta6X*<PQ1e!r+njM zVm^zaynXTFe-5z0Zyx9+FQ(J4d?|Hb1GbnZf%dT^E>|y7a3ben(SvR#Q++{HCpZ=M z$M`V!k{BAv_k)0bGW5(hoo0l2qDbg*J6d^w@kTS|8s)|UO(NN7)e;DkKMlwCn1Gpu zKX=?;9pvkeL(NQOay@+!cU9TIwDbxVKQV;2JM+)+tm!{|Bfphee|duH^MNqC;Ry2( zZv>Ul5+)meTeNVTCv$Vy#x><kfrFFGFkjUgmTw*oJCaW_jY4%OP8O5h>O_1KRY+6L z+(fgV#vrXz5^s;V%yQGUAaY`gs82ewhWXl1F{_(R&(OuXRVnar%@59K*=$g*x222} zSz$jip3j-p!|vR?%gU67i{k{3;ZWO4%piQX#4t9Meb02m6>WB)df<ZC#K9Hwg8pNN zzQoY|Q`4o>4&D%Zr>l~)lLcQe;U$;yB$b&A-pv;NG$GYGZMLP)ICf5<FBBd*APLc% zhKu|{X!{@!an$wa=sl=ReADG2t7zFut3^&+zp0(PYUc?Szd)95WTi9n%TW|~YM%6b z#$kFcuZo}Lb$P{20&9J>7WEcn^7l&_OmDNq7<XmLN)~vac7^QOy>!0qeFXhnE(7W4 z#lM|dEICs&fVR9J!J6JEQ$n>CbNv|xlg`A^YP;2tJXnmb>sN{w`!B&4?P~b@ElAf1 z&!>gAV;I{iN2YD3=*0ZNV#|^aHvVNXeJ;L;3%!?9wuL?=YpJr2U!6gt>N8utpfAm9 z9!fiR%fMQRlnWXWEb``WP@+N~w!^WNf1B?}_mvbxm22N)K<i0PBQ%F?PP@u({{G8& zbHE&PF|F<GOLA3n_%*9m((%Ln*d8CD3vl2LzIVC<Mmn*OJfoJq8tMVNE*G&ip~~WK zs><RU=ckA##_q#T=f_OhR|c-sv|~Pd!fcnB!&0%3)m!8OGw;T;TUVO7uL~cuFwp?& z`L{}X?L<0jl3hX8I~wTg?k2vE<SERWRmXN$_ko%5zu`iN2cb*_d;K{cTUMrUmm4i` zXQMJTZVjNO&q9{(_<T(8Pea?!mg3^W3%NJSLn&rdA3lEVUDUl3iE6l%E@)Td&f7~Q zDq)TIqu~Xcvvdya9hC^7sb}~DGRh>j&>_cbN71d^hHkxa0W~#Y4zHp`tNSjaXSW14 zLhNiTacpEwbFHfPE!KszDlJU6@gtvG&sh4ru~c^MAFtxK1TTf};U~(E5To-Nl)b4B z*DpxuXuBnp$0WkVEM?}Y--QNswQS$eD!e&$A$i9A#g0v~;y=ryIn57MbZ=7@+qCy3 z9-k__&z{_5N+!{4r2i<f{-aDh-hF`!-)7EkNWvw(n;Rt6xqE4}<#o1a?hdxq^c%vm zNO(4F2CQ?P!G5nL<|FeH^Ms5>d!Mo7^S%VcNyjj8#25A|>j(QTd|%gGWTnM3|Khqr ze~@J8KumZpdoS66Rw3hY_mj!w-2I(DGW9dN@2Cgy{+C#DbQ)duRKkNcdN_8gE!o7E zfsvdwT;DItVphe90>ZB1^kyIO9Nfk(&zAxB&@g`eB;*rht}vO#7E#BfM3_454%&=e z4mIyW*!3Y1puAW|?3`%83TMVqnU_EOiPeI7lSZ6ZTgBGb=~EC9dURf5E}}LzeO3am zXYI*7I3mpQ-<v_T;F^2EHFEXduj%Q*%Xs?Q4(^7VIvk5y3@1<LQsyibaZu@HZkCO} z19Sh2wkw~b(X11=?Wy2Ol1>z#dzs9pg=^#JO2pg-DPME?D=IcPQl$GN;zo{g5bt}< z^r!wICs&R=9bkbzTLzNrSH>G$>dWG5$|xq*5x#$HX6r@=(D#eSa9r<D@?5r+oByw$ zc)MRaiwyO}N8J_NfJk47o4l|$C@!V~m%%W6YO3JxoIx9w9FUI4tp~jEjnq7PQ07^= z^pXAsihDtn+;>0x%lpcAFG}Itt-3jOd?2n)n8%cFyRoV7)gjG626mecsEPg89}@a) zK;Af(W-UzNy<ZN8kt4(4{c>%%T=$ke>O6!;-`UZSWq<hOz<l^zKLW{7U@jb92{XJd zqx_IM{4iG$T--pa|Iv){uh|lK3fa{SHuTt9sME}8;>-8A!_JCYewI}k`=+p-Ew7AW z<CSO950ej=GF|Y6ZnY8S%zOFk3%YpCc(M5N-M!osXAKC(f#9HWmC06{Ky1}giOCvW zyyqXyygtl?cd?U^`z-W?w^fKXRfo{-5r^T;n$MVWz>)2BJ4g2J^_-Kr0?SjrL|K}* zMEp%#!8aE~GycxT<?RiubJ}odetwT~&1AS~6@U50+)a`&>rG_le2e<7X<-9OBj}y0 z;JCa!2c<u3aR0D!UM?&T3s#sr47%+^jkB#p%jX-=f*)c${_iJdiAKP1fxR(cNHH0! z`CxhaO7?VoUpNz_FYbM?hn;Az7uowc!(XwZ)b-XvUO{^@OkcH$^EFVU_uoR;wtn*= ze@O}EtvX0SKi=Rb#eA;hpf0~wr3p7ZJ;*;>ewC>il;UPnA+xeeQ9R!FJ<9n$Lz{K2 z%vMhVnQ^P2^GFz<Fz*KYz*YS}H$#n2my?Ik!M569&rKIcaz^+A9fvHS{oC`H^Lk+( z!fQ)SCk|o<#%{*JK`+?Y1xxYly-bqF$N1K-ugI{hgDb4wL$T^tpz1;pxlOc{j4voh zN#aRTZ@mZ8&4b9%#~0LT7x`#krCn{VZ1Jf9+!Y;t*xEWpd^tXx*3%TWGk7oC^ST@p z+}`4-4^P<RHd80JYI*AAMZ$Ydm?`eM#Dk)`bf$g=S$d5J*^fP}d+cGZIAo~w)Qfa( zU8sl!kNSbEz=0+Sj+A*;>LhLX%Bq?+!o=8G$P>E2#(AAovE+)>e2)Tbo+!b}U&nCw zhQn;Ce6n=F#46k$5f3M??S{#xC&MOz<G=;f!|A9(Hlz3qeO$Mgxn({O^@~oXD=PXV zO{zlEe-b{zITmG>?&inF-o<<&_Y?gx6Q@%fq7E;(5YBLl2Tx(vrQ2|2guU2kuRqgR za)2FGjv%YR7<Syyhz9!Rh|IXms@l#ooSi~0RcW53E0%efct4Ao6(&+>g98~avw{&` zagK+!)M3_}H7suW8d%h6<2Xk~@Mca6L$y>V)YnR)Q}(h{8#w}wNbKQkrlEMxtMSt3 zpL=oh3vJk$-48mqTG29oAI?wTEbaa=1J24f(<6b*I&`597!6P*quu9d?AR>m=&gp; zinh|tWnGeh#B=QS;wNxVc#rB#e$9@iJcT(=`fwAT)k>5Ci|EOmGwAK?%@)S#k@wlB z7$AH%qaqpU4p>N=cRb=$J}GcTSt+pPLMlGoZwYSemea2naqL&;H@08#G6k8|Lh#U; zSlBofQn&7AJ0`V2sc{|Ksq&D!67m(xBm<x`&J+$MCBS3OpUlR_psm=Me2h!5G;uF} z($q(D>p}GURRvBfTq%8Ta21!y#>2T^q3p%je=w-$62uf$L7Qg-ex4z8;&guDu+5hR z_uvIs5&oVzn}{7!IwRP!QBK_X(ck#~OEO7!Y#qExEMl(V4^h9p5`G7?^MN^8T#Dus z+%7YPDsOi4mZy5zz{5t&<Lc|`8`nQGi#P79$mgge*x4LS#h2O1&xe?LUs*C-7RdA} z=b~-#2<eMhIWB$BAw1{t7Jr(^K@*n_PdDnqrp;rhb)A7!&Hoxx@^z3}WtnoizqR42 z;2LVK@Bq!$W6ZtZ6kK|66fL;Yz<gbknDksJ_O=y(wP_OjxHOxcEe^xXQ6*?*st1<Y zcet5`L9{zghRzM#%Kkij%d~ZcJNy2fxZy<$EjfP^_D;XX&I@~@{7a==Y506Pl|2LU zBJybShXNeE`5$)wtLGMNYZW?6Edo=fmi-pE`Nu?3ynfP^skVB<ONUi#k8?A8_O660 z0UR`)yNqXlm9oKyQ{bm=CJj@)ht+9D!tOvHWu$%Z`tMD6b50G3&tKr5eiXsh11UIW zw*&0&X9F)i4ubiTeD0meGc1gs&IQj*V56RFqwuw2-hE^(jvs%QE-#FR@J2OOzU~p4 zbfyaZ;1#q_$W}dB*9gv!FR}7V%HVeAHfj8x0fLx>)rAWEfwfoAUwJpP6o0^BBcouV zz8N)$Gx-j~Y(DH|I(om4;rFhbE&i8SL!Bq9;Utx?qGj^%y2}SDW4>X4PZ9hc<BFo< zQB=Av3rz=npr^if#9OX>K=X-*n5Rz&zD|{8x33<Au5B~8tBa4|ZJXWf-ugnWH?RN( z1jsP+L^nF&w^Drd+-VrxvPImm*#OixO`+zhlT2=rCbw_v1%6eU3Jr`KE#wi#k;*SC zY4!rai!OB7FQrU^V!c>6->%BP6x)Jqa4*y~2n@fugUGk!B#HN*fE(Mh(R<@2T;?|d z%$pa`im7+l-d)MGy<{N!wxR$BeYFDd+i$Gx=p8(%o`JQ7K&d@`;?S}Fs3$ng-U~T| z*it{Xv8{}$w2y|-=RCNVTdLV@Z6BEA#nY}uhw-{o8C6Nok#c&GC^yJV{LLr;j4w^1 zfS_sgdGvIcksk{Z+p}!zt~#`M+=LpvYdLk{E@*kb8|AopVA)cF;)|DXo5m|P)%+vV z%yXq%7EfuGG!#1r^^x{m%%yfw9xk)+BKa04{+{6cdhz%doU#_2fw}J`?xB{XshAHo z6Rv{exHV9``Z#I5TgNLMQx`8v74if_|A;DPs6%0r^g`Y2J)o6g%j8E}GV5u^bk^E{ zEDdy|gBC4>6Elx-#{$I6Vpb$wY-)to+4>-J`v{wDy^?hM+(zFQ>TGV8E^M=Y$PV%I z*|#&1<S~V(<<Bx`pF=$}Kl+<>1?h?v-&wKy%S3#iaxJ=SwO2Cza|`Np%i;YKM`=QC z0ZYASOdWe?VD{TNH22P9)=f)r(2yYdZ`WSIX=(wXPD5#vcPW!@5Zq8-g}K{&R|-~N zK+^_v(4a~Q%>2@T!A1&jYN!spdSwZ!mg8BUekt_#>QQv*SxLt(yhD}Gy$~?o1mxt? z;htN#u;e`gXCKZ5pPuvB_f$Ow_Swfyyoh0%b@oJp7xnY4apL<%^;|;qO?2;wp>KA& zblKg4CNL2c3HRt#$ziM_N)fDYFGtRA42dVJ@D4u<IU9`txH|tUp1gAcx1YU=zgkwJ z{&5rW5#M2OFW8(E?woMc@Jgl3-WbvgcmQq7ooPmNKEyt2hpht~*w-_c$-iG;e*C9q z(6tr%{z4Z+E@KY!m_MG>uD{~<SPHz??X}!sJqO_GHp8Td3<~K`p>?k&(f2$nG&54h z5$==44|cgQ<>39m1$<|b;!)D1pA4=K9|p=D7jc-yYQDVY9oJ$a1Jge*fiST<EapG4 zwWY(EVQ38O(@zn{J?X$P&W^Ou+ZL;H%GrXoD&(tH%Z;{P%crMmk#>ozv}9KhG!`Dg zBkx{GR7_==SIrJi!}>T>`t4=|9(d4%HSXjUQqPw^t><94GAZ_5gEy*W#L=h2SYYo} zN><uTKhqYAmrTtUy0o6s6KW=6d;K%GJ$o`3`uCuAlsxF`3V;91cG31p#&lQy3Y`12 znk_!&&3<nyBE>QLsSs<ZakD>M2rH$_KYnBIh8yhQD<OC0Bc?bzXQ7K(PTyJ*z;?k` zDC&{r8jT<E&w2zN_@lw_zBmW;`$W)}adB+$V@+Ckw3<ZA%B8nP6yTZHwPdiSmA{gZ zCH-KxnRb44B3ZAq+?6hEP$mb)Egj8|owfw39!{mU$&Z=1^d=sIjhuR1r&RvT0rv0v z6E4IomL#K2v3x5zn9?hO!@{0?+CpKD=5v`-|CvS;=E{M1V<EJ1>)AcwXZyQ{z{=Pc zSB<hH3ww8P;zFf=w;iJpZ^5H(G?va9o}!t?c@rA6w=$)*t~B;vh2y|Up3LlsKTQlv z;SKs<z*qg|QSUy%{VEqio?gn(xpzA|)GI4a86ij4`({g4|NIXsQ(~ouR4n1{#jWV! zS&7@$je>W>(;@lDH?Fg32u$+GAWzY2+9v4&^O#FG=}v!0{T4t&=8UKLJM`>_x}@>z zrCsb!;~Uhx^A_{w?j-*;Lm;wB2UY}sr(NS?VW2Q46Nf88!4ZA(O|>Wc$*-7qU>)D~ zDT_5b&ZDr^$9aP&fs@z26N44B(dqa}a`JtIj|4{8&j>X*XGi#?X&$W3h~~y5#E?K3 zphK79;Ql#vn6do_?C2i_vo1Q&4$G0?F{TZ5{mq4*rzhI<S-~gc3Z~IG9Nw2M;6gUv zrP9jf^rpm=<eR*Cdx0}CKVJifga(4f&WkW#)XDZtDuiKsFM!P{9rn|=o7>*>g&iI1 z1^UXP;os@@|50=vZauwk9B)Z!YDrR>Mn;sP&w1_>iKvi>>=lYA63S>ud#I>XXh)Q! zG|qE>L|fL^D2j+EDpE+I-}(Iob)D<_Jm)<3{eHh*#OsO^{Vo<wzSo)II|DVGIX|4C z^Y!VxfL0Qeokv}F$K#x%Z|F96S)46zB&_S-gmZuR!F&FGJbCFEvU=-Wy8rbhsxxUD z9V=l5g{AHE#nEXH^4JlT<$h9)y$i5(nhQqn3I_3m2^iZdM@N5J04I5efU$82QGfH8 z+||AhCfy&QKJyNIShkO@mw(T^-ja#?8qcC>(i0+IFvT+7U>El0yAYqkFQ9F<geE+6 z7H(7s#s=FbjIY-_X3j4qx}kO$AD!F+HG8ToUSF6C;qaO>`W=MFzH6b*gIF?__s$qZ z89?lKAr81DV5jcrI{{OonWcphs0yP{Eu#QSbmE0BeI_t<<2!QmSTT$pj)H*C<GFXc z3$cRV4E~++7maIEz+8QV>AAw7LU0zQHz#p<qiP^ey@{-SVuksMn%FW;1=<WPU`g(E z8gJB296sh$tpD_hR<&rcc3ubB=?e&?imnEy!Q-6dgaYW{?^%soYpGv0Kx9Z7&RtQ0 z#U9e+-kI~TeRYALcg9uhPu4@J+}Ut$N)eNIx`(E#@X=@^Eoiy*iptM472dz02Kv7h zv0y?n>b?Jk4O-c-{A4QWxog9U%{q(61{82#$y{(TTLX8OXVC~jG_6zW2bUiJ+Vmy5 zE<Zr#{agc<YpijU_gCE8lLO~w-GYQ4Js51b5qiyc(Hqs-e22w=mK&WX^CmXHEKU=r z6_0{L({k{u%W1mT_Z?BNk3!>sKE`%lN`+NP6pnMt!rNZ8wBfunlQi!PZ2VwLTH@r{ zS!&Dh<Dfjzols0JDXqZ)+YqR_ZOA=w3WwG=VZ4Xs4!rPxA~3Wy0<`m^b0yQ^o#aDe z@VXe@8+l_@?@JOq_YhUPIgMNT#tO63t`Y-<c>*=pG)(#)AxzSK&A5$fBicjtwDQC^ z_~$W9YeZyN4avLQuC7ETfdBgkN)5^F-S5eDKi(&`!hrYp%&~Y><isd^b;1RcgYoav z)sU||NJ=_xfF%EIb8UkehOa88_SP!c-MI;U<ffqS%Rtmq+zA%1gQ<RVJbCVVhBlp_ zN8ZeGpnrOe;kV{Wm|kUy0=Z6__M@1XC(RYsm}@}C-!wdQa|Zr*DVBTMY7dv6nbRly zowjI`IP9LV5XNXv5WeVtAh6<REk<)1fxF=ak?K1juW1`RuH(CV@(wVmD4F=`Pp7#j zuCvchE+jIxE9v@A6QJZyKE0IkgmY<*Ch7IvG%s#3)SQ+BkL=eB^}LMRi(}}6O^U)< zwI<M}qyWu5w_%~|5VJQq1qZ4(z^;FdICf7PZ96#;w>Pb!TV8#m@!@gQJ}86qj2$D) zbM?U-&(mP7UkEB`WB88E8?e;i{Y3f#xEJ)Ak$LSv<~q)R^qfKT;-=H1Yi6Q%S_CIM zouB&)Sl;)25BX65%$B!+kW?GoynHmsk741?w<73Taf3`u&!q7`?{lMC4l(0Ol`wGg zQX=}o7w3PyjSs6PfX<S!phxBLn2H*W8QzH%EWcx}kzz;1DuHvhI#_D$NAU@BSz|t{ zT9D(6N=16~rG^#vXK6OK!=Vwj3ia?v$so}^x0*gZu$0_eszg#%J=ok35q{=g3Ox$L zBxb7{Em|{=Ms+#jlVcxf^Y~za=GO%58{EqUce28=#4tA9&K4uR`K-XnZ}ifqdC=@9 z%1R%+jJ+b>=pQu}9_sz1N$!1o4k#V=7ipu{_dRfHOeOr+$dL0z*Guc=tdQKkLKR>C zA>D?OXsvpdI!{)mWxNx0B!8YT+EqljY)K+0PwyfAS`ARj%)wP<zR=TV3a@vJ!7w~R z_w#I_)iwc;toxO=TF)R010x9Mu@&#drIUSQBd~)|Ixu%K?L8d^F1aaWX?;1)UYx{i z{}RM=d0g4&5^>b-S0S25UjmO-c^s&>;ckWoLX*EK?EJM0AIG19BU;up!{R=ddwCd} zpZ>%?xyQ`O)0wRQrau*z(%f)l(j|O1YZdtytI6kqZd8=mX%TZZW3<aCV>DuOz+{OU zcQj@boJ=+(I*sw@ws|p3lKaDb$#us2vo2r~zqgtM`oi=6Ep(dmFM8NO3%^Op5W1Ts zL**rqYv)OP!VZwi%qvuO`xmSz<3RbPDAnB_j9v<V==NVytbyA%viXA=F3k=kN^M)p zb;@tS(t8i7Lx4H&$l~uGx!QO=){mNmNI|?uIgk^|&~c^;t30yEkqc>1*13kf%8kUP zt-<JeFROyl%z&fq2IOs94apmtj1PX8pzpJI)O)%QK25koB-c!0WyHonLH21l_4pj_ z36G+yzh1^8ro4~+Wh}n+83h<DfiF(-OJs{_pmNcP^NUd?9en1mFDgQKU&9Fe+P9Lj z@1syo#0pHVZKPz(RGwesPhF-bqlxkjNSn0}uV$2!#Y^{)z`PbJ6E?uilc}T~QVAA6 z=ri=GzD@UTaEA>8j^xYrc$j1&MF!4)gZe}%;_RD%tzIfbsWOOcEqqV@<&VO?-6q0` zuQs8z#2aF~unq2XKSu3yx}dzW7#}M1kmdU2FzeL=db?2_4q2VTWkV~m0Vh)*<8+$O zHo%@GPv{|X2h*&-3SzoC=(=gL?BCD?_%mCNSy)EswJSN8=hKCWFGX3^unidKVaQI^ zoXA$`ZzrZ})3G<og691<f&FtYlk^_kiYF6q)9vOv`FvO?->=rf%(z7IN689Q?o@-s z-eb7ga3yXz{1DF`Or!d<#^W5GRn;$%LTGyty!17NiHD~PPc77dLz7zx_72lDt9;t# zX9iu7pUB2f+o53r!w!k+lB0Lzp;velJ`7A}ulVfe*-e4;<GE9~H==<4-0_}1a+Cqf z*CF(|yAfHjbCJ-&>>TX+yBvp2hbg`|0cY=Op~O}R7=LOs)GW=wOR9-@W}`7Vv`-h? z^9nG<_!8zv7J*PZ0G-SFaFi#5TRsJlcEj6Lt;booyT%%RKWS$|_Gps2Ayw3u%7qKJ z^T@G%&gAi0BbtA?5o%xZ*`3*X?1Yr%JeM~B*S*L?%kSxgGikyK?bM3GjopmeKSu=b zIXL~m41DUk3a3Qye(8X4JiRN7tkNkb@-o-auW2WUt(ivlO`L&wf6t)O!(*K8k_5c( z;4k#aKaUn?2%ZwTFEAQ7Ck(r>k486J@jFxxDwV@KS|^)OWowSsoXm$3$;HC50ZlSS z#}@T@CS~W$JYjF;E3&D2GrY$$=(A!B`kVfvd%`MVp-mJdJj;do4`)K6Vk!n7d_<xK zuaUo7(n;&{aa^L^K?t}Ij)&jt(tkPJ{~hJ{Q|%Fb*QJXu^Ty+`EfuKt?<<Y(drD-3 z128irm3J!1gZp{j4KJleoe~8?-&i|r@T!2^8|QFY=4_a@wTS%Om5Yx`9^k-^_uTLv z6?pv2TA24ali4OZ7uze%xzh<5L{k4eOtH!%E+!Em{kt3|oGpXikq|hjMv1k^d$Ohd z1(|6&33Hcc)2>`AI7Wh?x5|rL{_IYg^lEU%bOLp*1;kCO3?28SfRu|K&0JE=T#L)6 zHr`5jB}{`+Gd6`o3u0mTfDDG@<x=<O#_0Id3KgPGQ{(#+g$h-CCvS8S8A-_`R};Q* z8o}$JtB+O`&hy6)Znik)-a*(fVJ!sqghGhYb0QlUN+;jXut;_YV%N?sgN2_a(3=xx z661*HjN_5JOo!ACKKsGH8)8n=^S1-2=#dF@u0#>@@rxa~Tz(kN_YHx~k1bplIKjsN zcMJ&^gHFfEu+97+Bo5jOAH52ImGgRuh5a(L5)0vqj*P*#{4VRwDJ61kP9taPZb{44 zZqck0186&UFCKa+j<3rrvHp4q&zvZLbVox-(G>-MZ3Wu&9<W#1mM&0z$Q2zgCjH&F zxe47@h{ZO79tq!3=~z5DTy%t#{K`U=kdJirg--Z%=`?DUe1aQkQy}T^AQbGDVP)q= zK#ATBnlP$@J~NWWtJ%viL(zoV&hBJWuDaswO*0|GON*7^^ib=^Xnw#G#x<Xo!os^c zn3bbJ52h}q&2Jka?tCYy$jE}t2hK967KRIa<VcQe44o3`Ps0D@(j}r2Lha~<xVyJq zIPJ|U`uWN}JQ*B?ua+na-=2&XDs7I1^yE8&h?qX`a0!Jkf%}>GIWvXt#zo`CGmmh_ zi+UKUE#Q16y{BE`9&}CdNiycK8avzg6RFpb!-YoU(PzINNauTz;iLyt5U2pRqA8_H zJ2B?l1Xgj>1xSyd0sA$>L5a%4!~C%<mvIz7WSqtzqhDl5sTZ@&V$ncx1Kl*g6jn55 zk~5BqLa!Gq(3`)D8cg8#oj+ZucDDqnc{d4WBnW9p$RH~Iup<*9TB-G~nYeJjs8Dcr z5)@^0(JMO^vTHjHh3|$%amtvx<dTR#^!~G;1$S3d7sq|<4H;Efd#DsUGZ(=X6C?1o z?4!k!S5cxOnY8F#04({1iOHry9gR`gy+{awo9~gWUGba~wTFS9{Mr3j1>8zjV#?uY zp6O@-9<M_&pktVPTh+~#^Lga<*?UnoWG19f>LjM0mw}zQHM9mzXANB{Q6O@ThD$#q zp3bKHnIZ}9bwk{j@Nsa5xk1c3Cc^8s$>eLrL9+GLc4FRC2_3(!NbTM6aCcy~aLMQ} zP>Gc!Jtyi(#}sRH&TpX)CcNe9IveoktcAjgN5;TKE<nGtTe0zjBNWxgVdNeY{(kiz zlhPq1x58p@xF(4DSqIUt;$v7B`#I#jV+%EjI7l3JiQ&McAkOllIyA51d5u<|VE#r0 zNL{E*i?`=+;^(!g70;#*9_xW`zh#1gmN7YMnu6D^6*9>M5j1bXPMX&fCs;o#k1X&k zgGf&un00$4z5VVNW9BwV=;}O7I=ymnc-cexR$LvQt4xQa8ddJz#6=h;2&7MS;t4tX znkeUw<=>|_=(c5zpr}*^dh?3lABwSki&o&*z(80!Wi4}Rp^$6}G-GE=l+xbx=XBdC zNoK$I4BSA&Fe<-R@Tz7Z+JAooPD8##M%9cvdu%s;%o|}$E{F&_m-BulcUL0OjIcB4 z4bxw75Kp8!!ivCb42i0vS#I-jQN9w9no>fl+myk2sWiE-=q5C6`9O=w187{L#ooAf z9}>b-K;eW89$l^k@*}3id^^uqFia=EHhiLON=dY1eh4EpyF`z9&!F>)6f2@)V$tJA zJ{SZ$QgE3_J9H(XH(e91)L($^-APon`6<=qp3*Zql!!D1(-oUzxCMM}b;Rf$J@DWa zNi{kJ%jTq!e4dp(Q}rw^Zqx#&l@9Dc@_CT>=nF9`Yv~l<!|cxsvRIdCj)%9e#g0X} z#DAtPy6f$L?QZhu?Xkh4IN}KTn4N|@9Gi%V(MFbT(n7s52?(6FpA2!fH1NDAsLvUp z56^F9zS^XdD=j}TT~ijK6HW?~{LiohZX2-rKpb@(7=x?NseyQQ8YHUg2s^%5;;(QD zp7l>LXL&sDZa)tFvAgI@2T3|ml?#n`f1~Cr1>AGy1TGvX;LjBSljrxB4&FRN&pmLZ zMjs3LIq71dgK|99mL7$Gr{VOx&r$dh7l*@f6X87H(XDQh#8qq$x6N=ehThA8>eK)l zwILcRAO7Zy4lTmHV!E7@nE|S}<x;0qJ?iEb30=84XlV2WWgBc@@7=LDSP{;S1obkV z23Bb4yo)RzJWTSBJChiZA7tC5Z6yDw1p6&w70lf$4%2#Tsr2Z6T>MB}IOK7GOUlS* zyX-5_rRN3hR4ztu<1ftBpV{<~0`D$p^QS+~1z=c!0(_7)fH{)l^nqqB<0|hDhfKWj z-KKdkZj}i6E*DLczPV!Xjy;Tz)k_S>n};`c@|nRU6(pj;ki4A}RWUbZB^XJiaQXk7 zNzNO}>9^Sk?H~C;cSZ+<F=tV1p)nQT{195>bcAz`U!aD32dCZQCf#Ok1A+T4(DpAg z>0kbPEZ;kljxn0fTFcu&{|PfzZ_XFyK*BVf%<uUsLw3TB1=V~`p&fU<KaFBD*HdHb zJy4YsLQZKHkx{;rD@NBWLj`|1^tOutpM@es<JEn5l#x#bvwp*j0R~4aXkt*34sMk? z4cj}^aD?Y`Dg5O-^JjX<oVjb@uqwZ=TieFGklv0i1-?Qz?-1t5Q(J;!7jR$yb+T|B zP$zB%GiAR6GK&VN#x@TaykUYrTO&!a@k+WvZU&!$|Bp<4vYWh&Qvfk8foFELaNp!) zSiesS7(qorg0qEnYbrrAHH!?rq}1r}MmYCF6IycBKyqj|ec2-_bS_^gytpoynRWCt ztQoxxy+$X1tn?TmYeix6%=Mu4Xbw2uP=cCF4s#X)E^YtHY&f(G^B*^W-Bn9ae8-=g z>n_5oRUD?f?S#7*)8N3PN#HN?jSljiak?}W<2UNF%{}rJPgZHO2j*P?Ya<4J%-)Bm zpWUHF<9<M^u`k_SA%gu$+W7lcB+tiuO=~a7VDdMH6f%Bf{i7<d*R;Xd@$q<(e!|z^ z7vPRS322$GM~zl!!uOnAplUKmzFpH2ZrPMUc7BN^`b{?UiugOO?ac-9!n2<o+<y!* zH_u>0dh^STMAws7>*M%bxj9>_#rHu&Rv;?fod3#(V^)?LVU>F<V3ZtAc3A{oiIu4P zXCn-_T;S)sSs3cK1_WYd^uHZy(3@cjAMLN8|Kw;~&3C5O1Zv{M6SZiXm4MCrRpIC~ zMQnd%EnE^=NQdNfglE3R(~pLKu^_$;SHx|B^%=|P(Pz3$qxL7T+IEpKQdg%7xA=3L z73JXiha=>{wQ3$>P)%&e8~P}(2p#5+$L@qbxNCe9>0YNUaI0Z(?63(fyX}DSX^Sza zqLBulP!xWtKMU-AIS{qzz>07_+rC+g<o~7QxcbA26}c8f<$yHzzPJE`5_ksWba8A{ z*#fiNjfM69T_=o(Hm))<#sk&w!2HsCqW^j&wkzC#Z=n^!9hbE6M}RUaJ?6QWuJuB> zd&OkMg$P(OB!|Ba#|S#ePON*b3G=)8*+OeJM72I6vn=@Mb|#FJ91SH-?+b~}s__^) z^)j7tCkf?^oXN30W0}Lxl;OVl9(vt;ENWCwVw8lAT*9h!T3WzTKbt@tZrF(+=}q$M zAJfVS*@BMjI^l`rIn>Lq1+Gl)pocU6lF)3PffsErjIOoBk}*l7p|F<te(j?l%8Nlo z`5d`(S%Xx*nm}1IN2tF1kO>`ki{w2_$4o^B_Wi03@_Fuh@O&x_lOCOcyV@TqJrltU zL`%T>HPPVuS_K+@Js~y!qA^V=o80-8Oaz|1mqaWH%u1hd->%!yEZ6U}{_I<fJW{}= zUD{6Om7NFB3?(~$?xvb2{?Xf?lku&iK5m?!hc<qm)a2b65?(Nto|aO?!C$7Rro0m5 zJWpX}aVh<&y@F`0u7nXENtCyqO7pJSQpeIH^3$n|wLNwPlCH(VlHqbDVE0_~uAEQx zmmenTUCqd>-GJe%Z(1bYQpM5jXGq-_ZJJ$>PaD@&fn9QeKzjOAqVZ3UB#FonKR#f! zb*CYmY+EUey)q6yTD5X*ML`%Pt;_BAd_rx0q=DRVa}dq^M<0var(L><G^MfvYuY!^ z^V7m<Th9*O1(%I!`oW;Qql$c1(T0SaVjR0w7d6iKbDlh-#%=i-*mdMQ<EwHAKJ^*V z*01@v&MOEk*Po_(=hM+4nRlfAh=HA%es~~y1U3jQK+d8Ce16|#9p*{1W_gdf>a;D~ zhkJHJ#+Ajxda|e?zn-1<cL_$B&jB;`1Gu)tW5}p_+&pV5XR%!g4^*k5f6qxeuFah$ zH|l^wY$&7u^E;G9bTF@+&f?(=H(H8PbPmtltsN<)vSy=%Ri4LCpT8^CZx=%+y;z*_ z)Eg_*8?kY>g>XnVk*p}KCX=3&z)h!OXy1E;xqo1kaPf^n^mJH*_BLto*X1Oc3bFM1 z?P(BLQV&Z<uJXM(brA3#plh>cQQ03l<n_PnbaH(mU8XD!L$(}lzE+1}Zcky{1bMK~ zJpr942KlAg#9*5t+sFG*n{yNSPK^<@?d(8D+g+G$Tgy1fCBX-#o~V!chewmH)5x}7 zX5v~uYT@EaBYxhZ8986M{&ik>DSaYa9yp0US@NDPNLUK5EkB{u%9DamR<rPgk}PXy zq%ZW(SxC1871E#wws5UMgdF{yMy)2UXLq0KBwWH&WWCeKD7|YWvg8?Qo;-`P3yV;H zq>CEL-@+ubi^6Nn0IeD~f!$Le1xfyD=)F-6+Q!-;%g?TZ>1wjn><K=*vJ!^BMbQg} zQqWruR4GaWAK`kM@%%OT?fXJ9-sr>m#TUz8jC8={*>yN^-A9_BJry>}n!>)$M|_U^ zI#K#Nn&xV?3*t}4a*};MWPbN2MtA2#a&`1`_~|~5H1w_{%(`7d)#Yw5ev1^8t4)9l z5}IU&swuiw-D5`cGo$yhv+3@^0B9Ad#!UX*oXvORGs60DRo-=s2>wOdR~eJoDYiJL z%NlC$G>}`9Z$SO~@em$%2^M*JkPxkNocf|*i-WCWAUt>~+~R%GSmOlG9TLId;8`Zf zH<6q^xf92hT4TnaY;fFs22*#m;q7a@8?kl^{=9nym9@`tDl)6F=xidKQw+hq!hWLK zoXD-6dkMAX7E_4{QP4X}4ZdaX;kxI~Ab&EClRb%Xq-6RD;n_QL=u6lE%NOoMJNqVL zFgl$ZFFgWxTIPdjR2*w|$P$H}(IB__P<eSk4%Jd!hLtI+(8t{ZH(oEGo2|oeoqi|= zXT;KsgWK_&K?>OX`BQ$3M>4G%GQsl>qcF;6DtZoO;$9OOy2y+L+pqVCi_T-Z)GHXc zxD@&_VH8%_eW7BS03S4Kp|Wf?C`Zrbf6FSuE;;^xzUK|zy^Gjq)4xK42%lm8z6dKD zjhI_aS!6&iyyAiSNv^sx13nmjrF`2NoI0oC+V;JmaMzo=qq7&kFG%Fy7X?%%<pFW- z(*jf7#dL%3R4^DeM$?n0xCiSKP|r#axFS_<$c4|^8Rnv*{}I9X$WtKgpaN%17lM}S zf5iRQDLmRP2J24lWR+HiKz09O$fzu*CufJU&-^B0bn#XCclQwtoV=IXm6zbO`c~$L zX&Zetc97p`B#}4iJ($&c3RLf$0q0S25Id!p+;0TB+aj4{_DO^E>NISUm_{Z&e@IS# zw?hq{W2;ryg&)1X!pT-MT(VypLpe3(#K90E7-}Y`jphm8hbPelzH_K4^%6Zx9+Ht} zeWJL$h4^>;hijT&lU;32LX$Lg44PC-J+@ck=&W!Y>`TU<_4>re;T=hP(OI$dzKU@C z;9t-`Gf3>hOSn~`qj2gc33Qvp&r*#H>9O$97#qX;skLs9NoE_Mk-z`Woq8Fn>)I;L zyE;+H@p<&({Vl}7Y!iR(&&1cNiRATQGd7ACW6#ku@I<$U+_-U^?YZ}qICy)IiNE^r zujP2S;b#al<&v4<#WRSMwHEvJXg`^=y96FQoPjC&YPd7L89n(7?w&Pz?3Bc2)EbjV z`m+w9`|ru{eb-n#YEw%ggWnbQ&&S9idq_Kcfo56+V_5kJ9bP*T{Fr-;b-6CFI`o7r zSQk!O2is_{TtGz!_Rw~_)2QCr#%GgV=-gTd*n9skP5XC)7OarKjY-eRy}G5$+DdcG zY^W0y1|4HtmLJDYZv|vdgb_S1C=_1as*YJ1+B6H~sM;-WPXEw$;yD~jP4{2N9httQ z^xacd-^~PC99OYhqLhWgDuA7de=*l%ka=)+fQV;^37s3x(!4zrxrgts3q1baBTuYm zz(vM~GfTRH2d-?wyxCUZgr=DEW;W!wYhuJlPk1;i3t?kEbA#s#$yeL0fHw<yelS39 zod=`$HjpUKi^A+NUd*)hrsP#*0&bhFE(~_QQ?4!|pt5rc>0o9%nbIPQab*G2Dds=C zcHDumOE@M`>l*&<mEsv|&D7Ir1x5vA(zrJdNN~6Znd?)|b=uaGf*e!!Qf~t739Y3z z_b!2f(ke(dbb%)qyvcW`t)OZs0-H_kVIuE9@*6I}LzCAET|>hKn`WDWu}V7qeRCge zxZH@b8~x$m1t+G2pZSiIH4!5zThw$vM}Ig;GX`gjact^kICMA@)Q6%-U9br}fBYDi zE)v12R0;>j-6Q`@N8zt9D?B7F%QG6K*Z{4maHOyTKHnT>0_Aj|-mioT{nk?}_dtF} zmy9!;9LUB^H>k$-0G_8i54TK>MAyD4u(h~=6Z#X7J(yz=p8uB45893Os)+ga$KmDm zHqe-?O}o0blYwyl_P6H^rY)E(FniKXN12bOzI^X#_mC;7b_X$GdtHgTE5ds5*|@qg zjcO<aQRVmztg!qgt!#=$<3+)cw3&gz+VwQS&H-Y4Qt;e3UEW#v46j7lfZ%%;x?6eT zf-pip2vX?lIb$f%aV56%voPMShz?Hqk9^<XIe*jm?^JnnvLIdIHNE#!j6D6fOW5pH zDv)V9Alx!j63wT6q8qc~z&u2moqB5)IoLP{W{ya(p_dAIFRC4FHn_k%IeLethR4v< zhtAmBmH^dGr<e!t)UeFu1Fuf3M1>u@1f6?a$;w(Qx~I>HJDFWZD=Xb-Ndd1QQc)B- z<X!^(+im66S=VrRy(pFUkYpYn_64~iaeTDfmU&fo0*s=AXkxKGDl$i@%EqVUkZz#x z^I{ERv^JX#e_bN{+kY7nY{TI2f7<vsU?=>XdroM(bTgvVGdj^H9gWn#2z6~YF(c<a zh;o30;AnXmO`T{&J9P$`Q=1-<A|5&Z=e`!%S`~&S$E(W!%PuAc+-4fGL6toG5K4F4 z2tsyXHW(>e;Zg%D@~XQ~kfR+=A8J0Mi&JGF?tVtaO?`EgdAStVOzEXNVG_!g5X{%} zqxTn0xpPZW4}Sbkhnr=W=*E4`OiNQb{=3tK3Z{Xu+I~8m9t|`s?Keogn8D8b9tM}f zl;Hagd6XUq6nwXCAlC+EsDI~vv^c(sUD5NN)Al{i_i8Ljfz){@>$u1m-V{K)=_|~- zU;}ZDp9E#C&4lnA3YUdf=?t;{ipKC-s>$DbbDsNCiDdH%k}OKApNtg_3!fAHJ{8>O z{*K#r!5BiDX2R{v0V=b>4;Ocy=j6LWNtaj+bHnfn@y?lottTGQ{AG1~&NK!_`LCnh zzpKf)-fTwrd>ix}Ovl#K@3}hDbrt=;?~!QFKFAW@BEz;Xp)61b9am0As}MgT`DF=} z{PLT8*d>m#na-p)M<2JFiZj0-Oyx2)_<huHNX42H5_p$qr4BcZ0W<TtD3+2yYzfc_ zFMGHz@AuM}hstDopfOHS3#9Jpn;2)KR$@NM62{-Q!E38_QKxyag3rg)=&DUXr4>DB zgUJO<?pscRb2}OQrvdjTXTYfPUX0c$qeFRbNS9A8&#^V4+yveM8L!N~T^LCx#QDRD z&57XYwT2rrVLGBv6O(6#ke#0CWOv17NZjiW^&i9F{>-23gD>Gw?spU)dTt{iszZKX zG{$8C>bPBW4zV^;qAH7S(m?ejc=hil9-nd*za1E1UQR6Gif`Yh`7$|le4Y#%shp)o z1E1)oW2W%sR1oR8)k?pHUZwa-62tFJz`rLH=pV<=i2fBsTfzp~btY0L?{7HX>o*Cj z6=AyTU!b-23f$Q_14d0XfzQh{*k}50In5u<X!kr71&^oje1a=v?5U@m*h&R5FE$bK z-&DesOInbsqXKL6fSR03C6CfVncZyz6<2>9<wUkcGCxQ&o}6(51q)?iey1dB^>`Wd z8cEZHyVGG{?>op_nu0Jb0F@1maHpLMI_^4&{~QzrJMv2C^U&)wblg+Qq&t&X-HW_G zu!PFCU!(n6Iyk%GDc9Y39qIX-?2_+Q^p3+=%s+aF90+Zw_$0d(Tkn_B7Edu&OZ_jj zm+t^S2S03S=0NLrFW2$+h2Tt{DoM3|2GgD9qrf8(Ui`=3;U5Xf@r-(U-~Ja#>yCoP zS+auUjf%pYwiNQ;K3mqQFN4XpnoE4{eJ0w`J5a(oiC!={Kz~cCqq3+L^e=u3%jC|| zDc>%Ta+PW9n31J)!rkMzOE?<O9p?7~A-<$fb%2ZeSBs;^^531mkJFlIzGzcChTM(5 zNzMBgb7Mj(@z>bLkd*pCP`Jbd*RP5qefuh)>Ax+waM&I)Iv0Wg%Rojn|2@9dlwO+r zi*EdH3Xz$n%Ef4Iq5T;V{4?PVvQKy5;KOHBug9O*%$qCp+I#>c%v?YZ-VoL;h!$Qf zfIU7U><*s&zvpKq9>1l?_Lwf9S0C*}#|=yQedQ-^>atC=;!6iPx9Jwd?oh+{T4VUE zw2QoMyv3yDY@qAIf8imYqu7+5fi<a7RBNRjcF8BBqWKs4>OWW1KC`SMGjlnf-o2d` z&IqIbYQNBjbwct+SB&+P*^ll;vgFl*W3W*{lRIWR9TGcKh0Q!u@7k<r_-*irPLChW z*7oUOT<k7LjjZMR1zGIpu4h=JDMn6(&Lu9|qPW=Y2<zf?2B#M6;!>=?(zjcixw?ZY z)WTc}Ue_hjeRf|t#ZNc5xuG(+ac&BVGz^fvp@-??v;de+RzjP|S0Zme7ZTfePs^|o zvvRnM?w&CjZx!b<6Z$kjNp%&*kN!ppmkD+k|AE}S&A7Vz4P<IOhL7J3S&PvZz<uC2 z*dCDu#|QZ|9mYe}H!~*VxD2Oydoyi#$^(U^?$P(HXNl3gaoGOJ7c&nQ5%1XBByZ*y z;!~gk-Ihj->4PWSWM@$nd{Zo&vR;zYy{J%bx@Q*5k-3X&E``wU39-1=dOm;Vwa^<A zi{OgnK3K6(9-F88k-*wq_Q{78#M;II+`WtFl$vv_epMS%ZB?%G=sGmkeSz2KXyLil z$1UnB1GwYP8QdIY1~sxQNJQZ>@^GxUu)8=M&FU5r$4dgb_0~CX>TaP`AKUpm`gii3 z|8AKOeuVs)8-#bv2x4po&072)<~=)0Y$x#SJdM-va`ad7n}5G8S#QG6VNS#GweRuk zp3`j7&lK<tcO}BhwPgR>tq{|hgq8WW<U;IoI%<*!-rFXDy?hq#z3ei|x|{_W%_Mvr z9w#(T+zV~bbWv}EKb@=54&w9W&}Fs+)sFiB<^1m1ZHo@xO46XSW|feF3Gz60Nd?II zOkq}OC}L_&JT4f~MeF-E0$Z;-EO1+i!7JY3)_~1$<j@>8@Ng`iV|T&&Nuw|<-jm3m z?ZLC-XY%y@za&HAF1f2RK&^@l*krexAZn?`#3)~;XP;MLwxt~wzp=)yA^}bd^cK48 zT@L$w&tsom2s852gmH9!YM~*^_h5t7aB80nD0yeW9Mc@MFJ6Kl-uYv;qypnVEu4|9 zW?}jKsc86pKXRVa7_F%jXa(<}I%z43BL?5lHLM@BA1uSRJX?;Bqe9)O%TO-XPHeT+ z*wptc;B*6@XY*4PW)y!RZteDPPW!rW$4Q249~(=LIlUw4zaNoEQbJzM5#{}C9rTi~ z5`ym+)~P-OX8gVl+Na|=cZE?PQ@ss6BgJuXMjbhIC|+oAIsyA_HzI3d#@tK`B`Z$+ z;4U^uVcIKyzJvRo?)s$8MDzuq;e&2y7vD=t9siLf<^^PS@H(P-6>#mt?SkA<A8E6Z zB_4j|k0*2)(h|;<5shKuT%m{4lh5IR(o7+)i6MMS3jaH)hV~*X%rO)tEp0BG*<UrB zZ!UwL3Oi9|dmpZJPa&_(pJH0@DIAyYNq;fpQCX#l8hPx-^`iE0FJBB*_}tOB6Klw4 zn<hxRSxjOd9EU28eRS2tsZ2twke}I(Atg1Z(Xq7~MOICKK>nVaEf<MK%kE+6$P{Ar z+!9A#i@~@-Pwu9-JIvsDzrX5DNg(&0zG&GGeTHg8>#G(u-&f0=4Ap?K0p1{UW-HTi zax%`&<Q>98cZl9Zaqj!lc6?Gi7hmjI!?Gx#^8aeVaFaUw^1w0Tr@Me^-V311Y9b&a zR)yPkvX-XZ83!G+mFP65kHp620y<oLPtqfvLu_{yAas)TWmkCba4)l5DH_c+--1ov z4%U3zVY2oVlGJ^7sO64@Lg7yVIj?0&59j4oSo^HPE&pvJ$M+l|$&p8J)4?Cy?YI0M z{%ssiakxO1Zko$_+O;sP%e?8;)?ZXnaXC4&CYSDR2%vcXDZRV;K6&wHA)Ec^0{NaE zj-j6yV{(@?YTq#@`_IS18*5o`>5szaJ!i2rBZ92US%5R5a;R0A9h-V8hRTeK0_XNM zLU+C!@pFbM>mb^K&cY{Xxo011Ur~mqWyXW9$V3>9@rTv>(y^gcgGy?PgZ<iC`ogdf zw;iq}lO~SPy44+A)~g0S>u(LxnS-eMq@J66JPvLpjulG!4ABKW4HX%iITBQLk(v#5 z!?IU*$%9l!tW3O5YwWG@{2W&>_Yp(=Up`pPnvtLxN@N)qhEqSrVRywjT;ZONi!Xl= z9{u+p^`3kc?Ynje9o^TGcggXjk!Ra3a~sV@ZaNP;1U1xfaXdDh8Hcyb&I{jZtI+qo z59q1QC20JT_f=hAEvQXU#}!;E99?x9dh||{Wu@=1NA@?hKk|ht$c0mRV<jxoZ{n8L znK4_p&1P<Ozr$6%*Wu&DgVcNfCn~m`p_>jU<NMNPQadP$UrTyWaBn>PO^L;LzNekM zY77j{Y!lAPe@QO;8AEB5IR?$oAX8=K@w&%o;a2bcfN>Gr+!ZsaSIR`;$@qS__(p<W zOjrzg=lF}`{ZR6E_Xp~wQc90kY2dp5jzQ^Gakk{|2V&`>OBV%;f$!oda!^A6&h?j3 zQGP0n6a>+GCGKR)`6;v`cL^wa`(kv5J6Slkgk0Vc!@P-%fy?pw7|5Szf#WVi#mqr+ z^QaPCY4fi9{Hl8LZJQr=`^`lvv^+u=X^esDhY=ugavJ7}4pN`I8a%Y743$3)kmH@Z z@ZGoruy=b0Nn87idz%)4mP-!`{;0cPbK5>>d_7(GL1GO|8S;ap(ic$1?^A_l$34hs z6Gz+a+v%<dp7wg=D+bL;r6WsQnJ0x-T#{uZk(_juN-oS}WEST@nZ!)tV*fyVR8dDu zOU0Nmb=Is&@g9h?dkwoajuERR<1sM%J#F5|vj*D+Nb_8A*g3@!PEFQ@A<02H>!~!? zwI&_oUq#VfHkzpYI2j&}+6k?VqHu20YkbhYh^oc-&}Uw=X~$p&ow7y+6qoY9@yXxl zUwfW+e?S3bdyeogOb@CO`2s48)&gre8<QsUo-Bz9a`KH9Tq=Iejx>o|{{0t=d0&Q^ z^u$Xzzqge#jRO^r-%ezoUAaUS?`k5#1+PKd+m;&9gYfpqCAgBGNuzNzzHRnI@lnA5 zk6*yzrf4SaYc2W2hiuoRgiyI<2k~`9Y=uvnD%q;(4ux*M!uZG1a4tlNB>}vLyKNMD z{cEMRx$)pN_L#8dsSC~v`A)7Fyn!{&itN^(Gbj=B7m6xvL=j7EBBp(Us6U#8QaX9~ zTz4!UxN!{h?nM&4_H(pv^H%UGs%J!r0*`@nA>KNP^uO2bByImujIOfBA|oX@r@Wr^ z*w_cHk9cSMkq!Z4<psC*&J}(fyh`_7cfmy-aYVgSfzJ%{S<_3AG@|L$yr$T>peJ{g zBzCU@AJql)aDo=?dMbmT^p7#4>noYEFj>}0WH}X`e2sJ5%(GB=AE0{34q7nvDYSd9 zgelrtkg>!7M2p7b+x5$NU&tXC?7mArzBLhE^Os~JquuF%>Pr|eoeszIDwx4F&E#=G z8-&!agj*h?**>>fXeH{)Y<MZgUT&C4>kaFmPr?DSwtW_SmDYyqQm@FZN%r`@>;Swq zzfBF+Tn35Bc2KfsEW0Jx3o9kQ;*4G2=&LFdGQQuB`tQDkP1;RV@7H}O7=4GdH=E(` zgIXB#EgElhM9@V;VR*|q3M?Otrj7e9V8ydGVt7E6?eXr%iH2Q7V@(npwR#nHa?)%~ zT{fyodtvAXC$w#t3W<Iaa8*wNr<PlC=lTy3Z?CmvS#=d0N!uh8t{%(oyj%|&dy{zw z!Z3|`6~y<WD`3p8Xns&MOQ;^R1g05P(IciO@y#ioWyrh7R42#KV|zvk)!dSZvQ#!b zVCE#y;b-JIb~goFwWT0#eH>o@k%KQb&A`;Uao}@r5p*^0!Re>nu=6vZXyqJEU2hg! z52xW~yA`x_KjQ8b#nUBs#Mt<vn}n_MC$WvQnZsX~K@pb%#rPejTg&16_ovB`hFDtL zZUf$S^(1xT8}9Il5Y%-_X1g}^VAxD0wB@tT@-~OCXWlqAZ$>!Hn|2HCUo;dtK3EEW z4t^rSKTDy)Oc~>*3;5^yi<8yLCwy}r>v*>t;j`u*{vsf6>j6uv3hDX29b{|3BO<d( zPnfNqM&A#tz{^GRslgvr7<)b#4c!-!x;<y%w*MZszgiKWL_5Mj<~4FQDh3YsY^C<2 z{lVpO4xDmdg)V-f@VG&gdG~Myr}8j{%zHY>h0ICC)u+GGy7Bh-=20+7zv_XGLoMXE z>shj|%8cY1>jHfcimJMiw3P2(DV@t89)oV^{<)1Q{@R0PZkM6hL681X|BVHyhSYUW z3-L4CW6{3v8rR$Xf_avf1a{J&>C-6-Xti$_RTKuWx>ks%%OhaRvS}pc_*V?5v7w7S zoTz$?1TFonQ_-{~lx|t+1Q!L@i0Wr|d{X!n4}H)?^T^$_PD~e8T>1}%{5|6{8-&px zO3CzTh14x26vuv7h2C4zm@Ib%M^0Iy^58<KTB8Vk@d8wjNFu*AHE~tDkh%S4DviE7 zo!wB-0>{SW@>%k!tX%4ErmU<5oXR#r?ea%t*UeD+@~k1WDKvuR)l+n6QyQu9I)dUi zGKJq)%J7`khd91(1HY#iW7k?(;tQh;Sh?d0d@fDlcBEC|&lBg!bLGqEe7KQI*X;t> zmdZpV{-DQILvWJbb<D9Fq#sXI(Y-^xINo)puzIf}DQx@%8*858i_f}jt)U-rN{S_3 zRlF}<bvHB&YT#u3J>chip8LLfG&nNLL1d{stY}*VJ`Z^JN&iJse_#){|K(lWd{#~< zBGL}4^1oD+DxRT}bq8tm?MUiO2bi}Doah2|F%n%H3I?-O;CZbi9pgFy;|C<5s%!zY zHfz&q+lOdN!aDxd5Jr2BNx(PH7%b79hsQ^9>B{!aFx`~*N;mGW==hjP;O#ls8N3_r zN1F3J)txZ?*CP<m`-w#-YUzO`t)$3ORajN%K^IxN@~#wlnw9mLd7zR_FBbwTi9ds> z($|Pfb}GATB#&ErP=;svYp~B-oat|oNX+gzi4Kt)V60*jp0yUx^?RF9PWvQ%M>(#( zB^>{p-p}9Zt!U}8XVhTFX}%|H3wgz}S-liKn^Se1uGs&ZEc<Ua#Kj)O&ruriJ|Uj& z*fUxvb$K_Msx_1MaGbd`QI}l0(M97*J@IX&h;a4b2FNM$6V&4rly9940dL1LqiaIp z$B%hrut$^#%-iwW$wzqK(UVR&VhF28akO%y8lJH~htj*`@#;h^ysEVlwL1pr?}>5P zbxI2Vo=b!cZIP&TQxywz-SEZNrQFV4`<Qu)98u|n9{!PjgW*e5*ee4kVD|`r{w_<$ zZOXE=rF{|fjxDF5>CqO474Aa@pH-b<6i7|XEy?|`XvnsTfm3^{$+C4#bm^v}u>EW# z_whm+5wpCDzwEmz%<~8i7UyDE>S<CfrNb?{Ojy7DUDUaI6KNe?0;Wtmipd`3!f&3% zkk?OP6yKY8Ai0<cPfKA8o{j_Q^YZW`CzD?OVh&R!99h{&S+?(T1F_@hX)#?FVd)P| zI#1{WqITCv{{DHO72`{I=P(|YO2X&Y?@?dLC)|9V+m)*Pi{{v<fb~Bu_#iAT7qqOT zp)PWe{38`Rb;`k@EeKXCY2r-DXXMmwC;aB*PBO0#ky~{SsE(vKE|XVbt__Zcyp8Ya zznKM8s%|V2g&354BoFToG=arGpnCrP=+_<3#hONf=AY}Rt|h>4!7i*vpB|XzUN0M0 z(T=OPYU6~cGN>77K&@vp(LP!YdITvr{_+kOo?OS7&X32W!TTtY&ER2ahJ1b#NyL_) zrAx0?Q}^EAbj8#^<fUaXy1$PmQ@1*xUrw>$9LM(;3*X?L`Wf(2LJR+%Sq)vkJgDbw zZK$^N7I=oO!+8Hds7!0+`L;In*7_d2V?7mTmMQZ6+zBxMI4iUjXAu5YqF3WG;epTH z!f9Eubd=6hDyVQ2+AudTr9}x2d`f4c;}v0Ox(`^SuHhv13=zY^v&4|kecB78S((Qv z_}wCa7%gSk9s@7t;U{yjsa*oOfi<x4q%oFPET&On`qZy106y){=N@X#!$Vir!VMws zTQ2{_q-iGNzWtHx+c~)woN@&Eo*d8YZDz3bx-}LRPa=Dd6rgxc4rAF+j6sKLiT~(6 zBK!52aK*z3^o-|L3{!hYtH)0y3R(AQZA2bKtolbC7Um*1VvcPY+k}4t?!Y3iD|lgN znqYfmIKEd<g##x7NhsgLnJ&D5Pwp>dy&S?I=w%{NP_rXHPN&mfJ7WbYc_V@>-Ul@A zz9=j$tEbTm{E6%pey=;Wl%Ja4r@w5q@zUq*upo36Y3hq6b9E%~c`~27Io`{hIPQsi z2E^f_-#t9(+X@E<3aGKeQR?q^6_?mK;ox90xO#apM9~tjFtG^2S2){m6ka?SkKezS zfct_%=7Yg{JbOA8n@VNDBjOj%u}FqXdU6;udLyBq3ZUBTDLUHcQ)ij2ux8`}UA;Ys zJPZqjCpvP%z?-j#bB;5v&f1JycF$+m7?{v!@A$dMgSU`ZwN6;i?~N|Xx8P5asq~P8 z4!h}M2ATLU7T#GLCy8s?soy3Mp{r1X>WxUl48y;~r}#I}PH7l3;{oi?RT4Z2h(kkz z0H#S)2UV=>sc{8m{`fhfYo#vO^>3h6DL|(#ilmpM&Y&Fcs*StW4<T<vD4MlE^YS_L z$o31UdLoGP_g@YZZ|SqMZi@&HPtqW(ygSK8?@%Piomp`?Nz1(r;UG{gf~j(?Sl8K3 zgBQ*uFC<kNl?N*DEGvd9n|=bSKVBrwUYaZ%w1Tz2N@>ZfyIA)&23I`W!A|vbfsrjU zs4?Gnk{TsRtMqlzrY43n=}N@QI@4hNr=7t065)&4Ybz$XKE<W{EYD%ydR!ax6wSB4 zAP+i|(JY@Zi|pI!%V$B5RwK%~?>+_cQyEP8peFq4tPOtyqaa>35o@*&Vs&#RDjIpw zxJ_fQWxfTscFrnj@Snqsw>O5TBO+j<r;N%M&w|NgJ#=wZ!93|my5&GE=<o4>m9IYF zJ^AN?^h;yGC*&R)mTI8Psaxn7aE)vYD}-fQl0tThgiy!gGD#X8iN9W3;ei?r(7x8s zRkO;1^#2x9T=0Wz=MuT0Ki#nZV=Fx#GLB~*xiUS!lF+xXoCIW!W+xpIhq-!#jH^!v ziLr2}2CpPxXebJ9_Rj+|g$cso58|xvG8w8}8Uc!NA<)~LN(Ua9fw1}ud|vUFd^VJ3 zzw`6TGTAi7!AuC#Bo<JQ%%{+*Qim^lQ@CsQd_iqTAk3WBN3U#5fNjTXaIHrP*t#DE zt|O6AbG?Yg{$2QErx<+OM@j7MGVbT_2JFgtPUjhag38)BQt;S=n`ih5DmvY9v}<xj z*3CG4xqlJaVPQ^&Zu8lV>AaJ~<TcE)?8ilqw8<0YTJ~M{9L&&`W<{(zFxqW4p8n;8 zMRCcnsdy5^1$uM&O#(7>hyl;>StM>_HMr+X2}iSH?0juqws~hH8I@(tcYIrUSIP~@ zkt)F8KT^W5%(G-`tR&+${W>0*`-b~0n!r@%*x-)$Q-qh+Um&-g<k9%JA{m=`0mK*a z9-{t9)T6<UepAdse>xGBq<@fp1qZmDGaH|**pHRNW>~E>pMIadku9E)1=DBkhdsuR z=oiq#`Ahm?^CMA6o^B4KOk(KwLK!$X<jn6fRaxU077bs8<MYQG=r+MokPmvo|GwT( zIFg96>f71k>`!>$;32w~ej)eMM(DaP_PBn-BeIcxh2z1qg`qJq;5#x292_S>ZMQ0} zR-8sfub!ilPYt*k-^|f($z5pClEhq%=ge&tZ?GptG=5?fS-7E`nQtTzE}URNJJ?{n zw(%^z9yy;`DK3Q@M(rd4O$3Jer?E%PQmM*;)u43rC6R2BfET4QRR6FsjDA!EH8w2X z4i1I^Cn;{sVOe;@^B6_mY18^6xA3)s9sSU=3q7_hCSMnA!v2gxBDY1H&xD*K6<a33 z)6F-r$)cLBC{Cxd9TKRdgbzNE?czRtZ^6FCdKhL`(`4y(R9icqY2SF4jN_mA_Qn!= zeq1-Rq$dmFUYOyu5#EzBe+sJHcVvfm+Te5j%fOxAPi%J=qFMhDdh_K9W}ZzF4bxao z@*Aep7~^iDmCO=1TRFU~^8r1-THyWFHe_y)4e#%8r`G(=G4+BT?+HyLN!l8i5f*_* zT*Dx+<|ngT^aA$8MB&*}r6AmWizzwkg>^PJp>EeS)K#>hv!BHfgT4mHE=~uZ)!!M> z*ZV<K&k)4rUc*hxX^@oe&v`Faq-)K_!o;xWpb;C#JlgP&xqEaLj?xViX7Kxzd)snx zFg1*4Sr3Dc^m3eGT?O>&4QRqbdi}#+EU)(>zULp{<P0f%@r6GJmR%*8lbWd8^n+Nv z6*1-B64V`1vKYtD<qpT02>UJmQl)_Nu;s&DERG3hS6m(>zXK1E#_KJ7ewu&x@GOXj zU8f;zi6!w@yUrZDIh(9l96=t;N`z#$AaMI1MduyQ)!W8#SrL(_kjN^esI)lub(G3# z?^Gm0KV-C*mAz*~5+OxKMdIAoQAC9#m5R`!t-XZjJb(Dx%lGwl&V66k=ktDtEFn*K zw~<Xg*Qiv^J&Y=S2jN9sjI;DSVivm*C&|T8_0Vkc=%hKV;hr)PDhpt;;C+6-`WdP5 zA{Zm|H}d}r0@0!fny~U=b>moXJT!QZ2Dv{W7rhxg8M6h&w&jxBZHua2jXp#Sj-51n z>d-)D$t1vpi^|~QIv-Q4{)3<emTY~;11zkVPtPR#kujOqu((KI+^ls+M>SU(Z1{!7 zOKYHx-$HyW*8{bRkua55vsMmyw9WZ04eQZn4}5c@VRQSr%s(&D@n;PDG20J|P3Ob8 zygK~YFNg8{0d%rwHQo?1ANMtM@FSUk>rdGdEz1OuvQT3ix3$kdKc|$=x|v7j%+7!{ zd&P0-)>ZKN!F4M0MTuXT*-S@1+DRsRJfjz8)o`;*4slj9La=$<5=NKX4|~Qhq34<1 z_;H>)`CE6Mbf?6@xXOj_K{AQ?VbhLEJMZI<yJ_^}*dl0&h@$uHM$wbcPvTbo6SXr* z<gN((B2E8ZBJ)8wKiS4(zy;x%>w>~v-y54Q-NJjS$Tf_;$>rr~;0Ki<`hNHhhPTau zzu^TS(N#xB9zH6twE}4ScOQ^DG!F+7k_7(y2v)Cb94?LfK%=5_$mK7u$WQb05VpRa zc(si}mxM@gZx}_tubIMR3EirqH#?ZmSLdL@$};?TCl^9KoFsa0C0UW3MfB!HB)7Z` z;K#{NxZ~43rut4KPOiTOuX9}m$7(#eAbyS8Jy{Dx4i}MCnKD(Zz6sneW?8xIJOrK- z_Ct@3FuT2rfe$NXI$E`0OhrC1I+F))R3gdq(mV{J>#$mWDqY2i(UA|m$Zq{;s+T1T zsmVLw;RG{Sqj8%$3wbHY%oAvmQ~`P|WsHNa1NMJg2iCIoD7D)IoI<{l4}we7Wa}HV zvEyw>_SAe#ek@9B)h80en&<SlTL<lb;SJ%5SK!NrTAKN6B1VN85SzL)u)I@`-&N#` zkFRfL@7L@BpEN^!_wOi*?7v7CRmH;Rj267m;Y&JqmtjLyFg7op17G%1dP*`9pB}q~ zAGF2rrl=ek7Xn%T;3aqZem43X<LS)7Rzj{;<Cf=b)pFMQxN4g*bKraj=_(G#i=pbU zcP?U#RUQlwL;R7U0VUzJoP^;?ddp`KEO~t#OFb&EJw$|m^1g$6H!X?$dcPY&2Icw2 zi{)n8iCs7&Vm1FFr;Be?9z!PP8Ia@xYksD%qnoR{5cX|YKo%=kk+r|a^5;Z@smd6C zVkPB6EIt0?r`e8UkH`mL-hU!ccyc0}sHsd_eRw!9<|=tt7zNj-I^sdIEvT=VPu`A@ zVVx#QAa{9?-g}b>!7G1|mfaIzWVtggTARY!T#RGf96E68%GG8oH#T$YlBZ(m@Lv*I z8;q$fk7?hVGq`KjGonzGLH;;R;lnmc(1t@!`1w>mJ@8+tnO$Nu{o*{0ouZ|LJvz5= zp=~U_@eRhDF>$c^-Z@;OcZu4|oyN%}0xzd(Ke@6ppWYo4fUc+Ju%C3KpfPR*gw%2* zpd?V>Kh39M`O0)p#05MeI0`p+-=a$=Dw1QzOR8-eBg{6FOzzZ`Fnp?T9h|QA5jJ5r zF)+MI55~>J@^fEI?|3y~^oL;BQdx=*zWs&3kazUO!9{435hiqC2a&iQg=e$9$@(!R zbo#(TT;nRow~joIQ;M!)_=<~gWW5?VHihH!CE6IR?LiV_#`AL=7^oa<girN<32$=| z^2BoRL{luC^XVTsZzX~@qV{B7-8bss(~DJFx{&O(8|!C<;kMiJ*-Z@(86Wx2q)F=z z=(g+f>;A2!zAx@#tMv~?!Ep@xwkVsn%y9wTwEaxMAu-Av=)%O054dyoHwEwZIl^`{ zft&SX(lhQB+#bDvPVA0Ahu^Yre_u8|y!kr)>k?1=jg;_<>K%yK{D5w3TurB>QaYqT zap|^XC^%RI%g4^71$-tP5V&2+$B$xbdJNs|A>^<Y%w&C0IRE>1lA))*<gD~7RBI7q z^<?u|pL;JL?!aG2@py$1`||1hx2LI!q%!X%>=#W685(Wb3V&;pi2u8-u)R!R{RH{b z(v8(PIK>qwRUKfR5*EVViJn}$?`Rm7m_rlS9ma%xa-{lU4tgH{Lzewm3Xi)N@=Tiq z2^i<XAN;fuRsBz5c0)IA9N|ez-kG3c))(&iBPsM*6%A|BMzS*Ixv(&?6!vFp^OYtO zVfvf~Fjv2dj!W9HJH8d?J&8oCwoG)oH6D78+mYTcqsUs^4EG;B<19nAVR6$HVE-(` z4`M=J*s6d!oht*qt(oAz{~@X$X(Z1=0vU&ERhV~Z29_5DqpL^*@#>2L=hQ!FJhuiP zYziUHb&`D2CgHo?=O}cJGRUeIl=)(4#|2JLCnH>qQ2F2wSoiP~jceS3ch-p0AN_5p zz1?2$Lx{5NPxXm!{!IA&D~p_MkKvYIlY-*5<8a397>qRAh3#2ga8=roVeL1--H8XG zGF0g6#LffLWnEwp|C5*o{f61+^3hqdglzDygU2l?)N4r+5E~_a^6O5{Ld^xH8HdBZ zSyz}Vmrp|O^iSxU$U$LN3T*$f3*SpL;7rkXIQnTcNFG-Lze5sal7lt2HppY}vggqG z_W?<;Eg<`kyo4j$d~w(MA!g2#AbdYIiFB`*2hBUSSmtHLSY)0C$$*#W-ju^#?d@c* zs7}Q%pL?PGWD|<Zo~2cs40_#(hmhMZN#|Z?(s-C715*T7aiJCYV{r$z>A29K>7&@N zL110-!%63C54^~yk}~VNpsCb~8g}1Nd)mV4AomjHziy!?u-lX-ImQubxijdbF3$%Q zWDwoteduWZh4@{Mgx<r4LAh!Uy)#%v78D=G4f^@CSNM$NkEw&$&L8w?=4PBNJ|2^f zU7*MB?_}GBd69jT4rB=P@BEd3(%Ns}<qU6f)W=D1g)PLl&-a4JyjMhunZi!wSv-3F z1@^^iFh4>>*kd~iaraF{jGJ%<jk8TyUA_jb=l0SqE*wc23ZtXWE#$9-YQwaDe<0(Y zBJUMY1#;<gVM%ojQO<r&#Y;~T=VcSAWA1voNnqAwUJ_@k=F4G%`5EHja|D(ze$S<B z%_o1N+~_(xmS1_GcY(Tm5Z)IRr^>H_>64!d)GjxX9#O6*li%C2k|Epa?v1hF9AE;$ zdke|6#Z#E64gyQt&JVbpkr>ps2@>`zK+%*f(6hn|?C0e(hwh)mJ*`(c<;h!cC{2_K zsA??nl>>jlmF#)FffUH737t-X&vt4d4SN_w_uG7-9sVx(Q0l!|*Y<8qNUH%R%^5>U z3-ZPqWWk^k#0cm7^QeH{Ns8Qgm6ssywFftO{iChn1ypXQ8M~{vfJ&`Nfx)|ZjLGY8 zT<?91rae^PHvcT5cFt?bvGsqr7WFH{{r3p^wqJ19-g}5^=SSgqseGdGSPRy@UjbW( zjzY4#5Bso3mShT<FdOF*Ji7BZ6yIBd2H%9<-@oIyB<(F+c3eu^g+BZYH3{}Wyc-Sw z)JF?rt%=pQSSZO*fzUJk<Z<aqI=0Cl7KoL@^#4u~T_Z8-6&A_u3HwT7lWs#v*BtVH z_o$V`6s*1G!@u{O2Fo9A5j<z>NPp2&7<AV`6_aG()GFcK5o5H|{D_&3cT8VQxQnZU zH1N{1c6jqca6fzgrE7+a@!_BIShgex&v@)0%RaW?ue;w+b(|#j!%RqGZsXBu;cV`| zUUIrriWC`-hmLR0$r{s{_)N%xJ7)d|s{b}{lP*<q8ahAB4l<eWQU3%ej{RKS-&{@} z^&W!)_7TqdQUK3-|1hr2LnL!s2>N}$LBkVo63+tx^m#)A6ZcgOZfWU3iI8b4i2>Xp zQA?uQc7T8GG0sEs7*YEfi&AszXkm-+^XD$LZFfTX>m8(_`aGTf`2)#*jzm$XkNgnH zgoMH#^2ckCe%F`<o)6sF1jAS8d+s_jYxXrVcAD@EUt)nh=^mKFcU9YmdD6)1x+s<* zg8?&YA!gk<=rH>N%Kt^ujEh1BEp7t)WPLq#6D=b~nPYjs-G|}%w->PVOftZEA3QgC zFaDlgK&N|h*w>kd(+8~3U-uXF_&ZAQS{(+roRMtb(jKm~XAMU~>WJE$D2S7k#zP;L zfZpUm`f}M=-o-qKYnfh0rW82iHfIG|;eCKOHF)E!ZY6g8%|uWxX{Gr`HlxgDmaY@| zO^zO334Ucl#^H0CY09q_{3_Rk4mZRwTjdhaj&ZmwSCN=pO2&hqvuNyU39d=a32#qT z7xIXr*ea2VVXgvCndw9oix~9tZpO{6NzCyps<bTdCjGDP4IQt26BTkN<K9V4@MU!Z zU0EP-CsYFH#sPsBniPSp;&14$#FsEBLl3cV45pNiA@=1Dn59DYzawcBbS@&u<eY}0 zTMZ<`&YKbaIScbsQ;3w)85;Mr7<Xxw!sUCR#Nx^wnDn!pR?a<6q&7?=@3Wqv?3yel z=bSBiig|<641saTE+#V<?ITz9onXOAHR99!z_e0*7TC{LW%~n4VZvd5*z9$X%zhjI z^2~Izn``RHZ|SWt&9nf#yUmERWh82k{e_Ccv&g#QotfNF3psdDf;kYZ2<O%Y!pCY$ zaO}&YTf=`;mxkuz9;}4kW2bQA(0IHmc)MI5+2i6%C&22#N+N6*QEN*GQO`P0gx|<p zJpRU1>`o&`oxWBZ)udAXUkGTVBmg;bgx-IfM<-UzWfTn0!jEV3cuNISd?z=bUA%QI zm^_$*@~M3^&p;B(Zuda1*)9CqJ{v}DsztdEtMJhwDKPIYp$pL+CHI^Y`cjGX_o6@; zwu>Rx3>ujIbCdD3(236b5kMv$dxj^3`P0?_Wt1HdG0VO5l4MjQp-hn>nLF|(9{H3B z-K8G*!*2pS$7NNE;(wW@J$*=qvNG|9t{Q*-NI!nmXd<?{mc-m~J`_#;h%ffHkiLzt zvD4q0596QmPp?lW-J8=$km71ysy!TcR4stjUgL?Q%@?xiL_Ghkte2}AKbjnTy_(Cv z6vhu2jbJw}GsV%<ewb}b&IHpR{j_Vkkjve_my}hmguqF{8D-5atZ>wW6rV-xHFtt{ zw7uyf4&m|4hs1Q>GomeTj{Sx!Sa(BFa!_LcFTdPFj5!HX7~4W;4z!YWr!w$!hY9NS z9mn+o<8xY_32}OtiW)5{wDIpG9G$j^4ou%l11s**e&Jo@QIkpgHTzKSMhI$5C8Vig zGjK0MaeHzJeSG%>I@zoQ*9~%}TRw{5=<x#2)3gZ&7EFSV)(H@)=|~JBJ8@cUBi)}D zOpP{P$A90O$f(tGaMkw|5}|dOTDr&5y?N@~&XTJ*fA|(CG7|8)+JwAP9)<mT!cf=c z4I`)a7<;XvgxPF7npkn5zg=DU4E)hy;uaxSC&}wfT>z_={6~(o$x_|%%dw$Ylixf2 zF<Mkr;k%3+@ZPQosZwExJMVHQ{#Y<YyfptQUIconGMlz+BCK9>0q$7r#r9{Obnday z<W5gNU37FVZM~3>7oZa(eFQ&XnJ$i=cO1{lYOwCF>KUcSHZafXIy}m}fqin*=?S-T zy!CYrSdSEETW+ktUV#HspWIfJU!h71cT>EqnaKs(=@aFGev)cd0NLq($bQ>cINg4p z`uzyPgsI|iRAwesT7HPuTo?Y=%uMOu;rnn-{UW_1=SQ<f7SIWf#kh4@7z_<>hcUu_ zM%BO)K4%@QHZVCy{bY2J9e7N}&16{@)wk&9dYp{>6-g53e84w$;%u43S@y!bC(!Hp z33mH;;I>I8>DBH8S~dSW?)&LXnx0fr3kf}TasLIP-CYF#<kMlV!&FA$P%~Oo&c#Uc zwd~ttxunw9ov1c`V$k(^bupWWGP4~Rxw=$bt^1Cgej>czUb*tkwJLD`a5VpWloAf9 zMPh#S157*WU%kmmUzp#e(pDjlm*gtkXEU4NQd2l+%~--xb2DCYt^^!=&<;K?x-m54 zGDi61q3Q4wbc`K99n}p`w@;2U>pDk9-C7D_y6u!dA&b+n1eBv@;5VyNLcjed9T4VF z*A^tggXR+4t~-f1Zx5xxTnA2h=SjCD&&Kcx8=>HbJ2c9EM493=eD9+K?nlS+s;!nd zDl#41lKzs-nsT%wJesW2XUO&EyD=$WTgby0;hjA@P+C^-0!e>EBf+z^{+4imvy!H3 zv#cT0Xe#-3@egO5qYpRQSAfj#Xm~e$DjZb04gPv}nVf}jkT>WGslB#%gP1~tTQ=DJ zl!m2AcOhT<Ar{+=gU4gESoPWr?$~P?SoCx}uco_#TE5-}gJM2V+bqm;enmlq%vY=u z<KVt{9()kxP_(}ftqmTd<c%B%2v&!-?~4Q{uO*(co{r;ep2F{u@5uhtX3{gz4Kq#! zp~LFWOj_17ymzXToE;DV6x)_#uWtxF(C-1py<O-b5<=~Z8(1ZEBYe2z7F?g3g*z7y znFfY(biYhG{F>@OMg;yO?<YJXy2Ascd+#|$a+$z%kLZLwE40|tr&h7EdtaMQTOWZj zU*~g)H~zx1qYuzV`5_Kf1kmG73mEa=r%~oD6`TX@<ov91j5;LCk9c{RsJt)4LuxkA zQWFDjHfF+}*mImc$HSj?6D%r@r;$?iGt$nRAFRJ=<CN8RLT*|%YuRXLZvr+1gw zOg~Oe{IkNzlEOVdya#%+L>XCoZ#Xh71^<}tf~B)680P~L?5;EJXf;ohKQ~&AM2^>B zEi*-V$!(MHR#geA${Vr%ImzhvZaVT2K;DVXqB;2y{H~xS5GC9dE(^Q7=O-S5x5ifZ zV8oNub6QmFtsFUTAwnH?InpvuZ(J;;%DxR`QNQsQajNzO-Ibe7?<V?@0<EvqCwMkr z5jKu?*>A&0c@uhMav$CQTc5<F{H4c2Cv%$>SFu_rPSUMLhhgd^dGOg+Lgsr-A#XjA zESTp752`}w_iOSnEaC|x)-D1Y;ruU~YDqpUU5`h%>e2MyJ8+vx1U<Q51!eQ>pf+he zc<$&U)9YryJXc#hesF={qB0ajK6mJ~fQ`7_M3c1t>BLdzE<lB83Kmq9;Og4B<e0B4 z)U~PL6D>W|otH;_9`r(6StKefw#M!LTe)Fn6Sm}h22<s{8NP0xK^4aTrNjA=G`%vK z&L6CyU;ic%Uq?Gy7*NR!34Vs)fKJYSp|GPkkb^l1(x7#RCl4-O0ok5oaB+MYTXMRb zaU0x<kJtnp`&$LpeteH(9i!1`)=sR2LHP5K&^09vc(*{6^=fTpJ`ImR^IRR%dBQ$u z;?ym~$50a%O}K%fx8q^H)(MEdyqsKED#|VW^Nri6K1e?Ny9@FWGt3rzY9_mGNMKCy zD*j>fVleD6#g?P57?B?}!uLZJV;YV_=Fbvf-p|9Xh9)d~9zbfmOVQ@|Y<%Zh1C#Df zh0NX#nmDbV)&|GptQBE6ZkOQVT+xK8eYeoYV>~LIxj`=c_YO<P>}NyOdPsJl8Idup zBwr?}!J_OM>hjSO9PP@XrqBqUPs``}axc*L*Y`uayf;`*O{C@iRYY_0LolzL#LqU{ z05dN|b0S;kfvUzC+;-(QB`3y#)`Dny?T;3>_Vyp*^l1zj-I~GBLyK{2NFiwrUJT0T z-!U_`iosFUFg$g(h1yT~4^?~usjKgLY^qX#7bCt?op)1Vg8Fzce%(u6N2bEaI8jJi z9864$bzn(h6#Jw5BdWiRVoX{FNdDs)ID2>@ZkV?hClr3EuDB#{Yi~*7{J~mbpL7mn zA6<l+`%!RP#)`hvwZhdx&iv<*8&rSvUs4b{k?#)N0iU1fvipilK)!S$t~nfxwhL;g zb#E;`m59U5>87}I(N#LhtAgsUSqWu@-(cv+cxrq)qRO&M2HJ#7@Yc&J7~p0KuAAP| z&l4qh<5AYMP+Q>E2|kUW#S^Gk=o@lQax0#Rjbb%VoP{dg<Mi5La}2pGgZ&z7K&xE` zycAc$S;b_|d1o`WNHyW5&I!nzEdl2Nb@VZIA|SUDdpw^}=J8Ul@6cr2W4{$<Sg7D~ zi*#I8Ur4t-7{L!o6`|wzTX?BPlsr+KLC@GkQCW@4)aT80bpI=G6#d#Dl$WAagN`WD zd5vZZoTi&56&T?0f{rl^2OdrF?hiS9WUoLBt%s`1o%11dTRhpUwE*Lla=}O41{RnW zlMfAwczfan677~mWoDei^!!v9Jo1DX=-0x;`VyKKc!pWNUxjArW}`}YB;93eiOuK6 zLgi$CFb}sRStZi2xJ%%#sM|A@9+|}Qjxe*(`V6+bz)b54hv=7iOp3nHVYUh-`^_Jc z49l}Hwf{Uct<NI1GU2FRH=e(4e4chKj3$?#3Gb>tUy_?93G2rvLU#iTGH?8-M%-1p zDDoVR{aFN`#8r6xq|0>Y*U_Z!_jWw<CIdE&ldW!%9)Za{1tik2m5AR8<1?neA@U~w z2%j4$xLbVbigs^kSB->CLA9LeVF|MY%PPiNGY7Jwr|{1_OmWP6eKuf~E)>h~^g@3k zsn0RO)!p|YXH^~g#QQ+Nwg9?KbuM<fibKKPHoD`98nzYe$As^qRAy!=eD4-mGtvW0 zxQ-`o>(j*)jU&XNOM<s}FoN?|7DdO756pi1ZX)-(8fWjHK>hzU;~dS+@Qpc$H7{oX z_0g)%DVAbtJC`t@cHhFAv3;ndC&F`zj!<-p5bs1uNH|)Fogvb&a_)D`zhJ}5-f8FI zr6F1CcaxdE8~Ea<2hgOz5ULKJBt6B(Fst+ipEcObB$n<V_9pweUmCIe26jkbQvIaw zt~68W%MDDC(nRFHmO^~sOfo`W$Uk<4p!=BDSakR;G260^O;gmson6*+-Y^dv^cR!- ze;Q=e$X*%}5&*xG9&lC0l6<-7dm{NcnC#YFP9JI+kz$ckf|I}w`*sCk`O{)XEK`j1 zYQJXEr_UxKq2H;2c{a7Y@}2sTZ*-s8Mz+;yK9`p*!8_d#!>ajZ<lLGS(0_0%T8ddv z)+G=t%XR|ojb$1trSV*3G8%7Q22)~f!7ly+1f4KqrUwt>NBB$QA0DFg?nV667eq$0 zOR=Rtk36`ihF+UhaZbTV^6~LQEcsReP8t*8d0`AWdTb=>+i_^&^ohwFuEe*qwt;zB z3=Z8s2};fCD0RmJy&jw6r6h6wgmV{>Gx(4B8F;_iKyWv_M-BeRs&^=^O|g1i1W5j# z47XqT;*`*HL_c*86IRoYBXW_vcU#A94V(;Jr_VrH%v^kRWU`Q#yu!`6Tu0mgrBJyr zA9T!ZM}-JkICt(GUHUx@OSg-#-hF}#+&CJXmtBDyW-B>OF|%sB^~KmE9|qH}s<Q2K z58;MrH@H?cvYH6p(ve-4QBfbcHi6w8HcJ&Ovv+~Y^ll=N<O4ahg3e!X1ig}~$qOn7 z)$1<NC7O-Ibae-F^DzanO$%s-e+Z5394DOFj$!qk2w3^q6n5vD;-9*W@GilG8C7_} z?9OU8+;?6aw&kp3-%O#XDX@tfs^Um`=mYFz0>DcAHd}4h3P(rW5WFsTu>9u{>K$%R z?ccG;JdPxFD-7{-l`gx<t%w|R>4ZbI86cr(N5r4>VtADnX31!=_Wkyzb+5-m=7L|` zoXi|%RDC%12H0@<!i?XWJS0m-n2;{-gM6dQ7O0SS=Vu4prXK#Qah!4^ep9$gVpL{f z<iDkYqq~Ccnwti_iQ$kEzaKtk*s)VXP5I6q1=#9%4;*qoVL?wZMt}bg#VfiouWuZ0 za$uF<A}gi`g?--DZb?|{Dv#zi�_kISiX=;gL1TbU=DOsvLF(-M)BuGbaHzCyt^e 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%0D{g9q~8bgMU0~>3y%)RApZc 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 T}Wj0@PEc?>{@T6)x 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%0D<rx((#U;IMA1-qebMvz<P=}a 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�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Ξ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ŝ$t1ni&5E8nA?|%m-Q3i(z&tJ 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 JqxBLOgYYup2ho`I|C9dMN#)Z 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 TC@lZAEJ;Y}c->6da`8*#+zLIBsOhTvJ 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 UrT-s2zIj;e=`<3<Ud`bD0i275hX4Qo literal 0 HcmV?d00001 diff --git a/examples/hubert/tests/sample.large.L20.len b/examples/hubert/tests/sample.large.L20.len new file mode 100644 index 0000000000..7d3028fa24 --- /dev/null +++ b/examples/hubert/tests/sample.large.L20.len @@ -0,0 +1 @@ +596 diff --git a/examples/hubert/tests/sample.large.L20.npy b/examples/hubert/tests/sample.large.L20.npy new file mode 100644 index 0000000000000000000000000000000000000000..c58d221e3c4b1d16381397c5dffcc981b7cbce2a GIT binary patch literal 2441408 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͈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%0AW54AU4eaP^bAPda#4bv|ac^d--5SC}pJ&2+*K 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ǃk{LhqVn4)jlD)$UJ(S-+VRo|kZ-+h4dm%9YKJEym88&Jem~28|i;l;#Y~ zCf&@tpz5xJR+3xh=@1JzIc^Hs?|w<!2L@2PvOfneP2qNj1R?NzAK`*-yLdc$J(&(N z<%1)Y;mxqs|D)(k<7#@lFdPjkr9qM;Nt94Zl+@X4r3gtvh?0;wnL|jDD3wYBAxV;u zBvYNeR?3+4SI7_|$&}0?y!-v?Lq83BpXXWYzORcDZrF=!cWo9{yDgEwvs}j+7G>BP zoW({`x6o}`I%k|prs0-DaoY1!817*S-;H~4hG{%DZd{I;7q1JJ(U-w}@GkVXlYCqC z!`XNLS-j(Fjl+9P2CJ<yc3L!oSN}D~;y(SPzUx7-oimGv-;)0AgC8{d48+k_;-${_ za`wtwE<XJbz@o$&$!txatZkM^Bh$qXuz+&!I59kYTIw<>6t{O+jt<iTBxV)LHiuRV z*{^rgy#2kva;9e4dh^FnciSFKukUBGv2o(<MT79`FB7zxuEoM`Ip~kwiWNl@acHv0 zMZL12#Ml(`N{ZRw(F8GDwFkD==3$F^8H5}7vu@Egi6uLiKMv}^C!dti^wt($`|Sz^ z`p(8Ri{@~6r)W?c<IX0A%jBo8X<~EB5lXn<oek43P{?U#&No%1(8Ozke{366s{{$k z6`Sz=AS3x_VGucaq?4l4XFR=sH=Bj^z=#XG@S@*wEWThN=&Gvnpauon^%l@`=p^)f zpH7KqJIOQcmkB>Ed@DON=^DPTTY^V!-lbf}>A3saR=)Io6a+kMmt|lWHY<ffqsL_M zo2lk9KH&;vq=w@~bzh2jR)VGz8px^NBk&2_MwR_f0gRX`m;@=ZLsx0P^(Gg8MXB+g zft@&G^M91!qr#2-WYoc}g>>iLgA1=tLO?_(neGD>F0Y-0asBtg^==#ak487n)K`|% z;dbZt&IXXCdsVEpJ%K4l^LbuL7!AFC3`gBD#?jBtp;MA291KnZivI~SE**kL`#bVm zl~~&CDC5YFyF}~3rg%%Q1oYjfP;|>I)LK_46iOL4)lE6nsZH_@w>|=^`<F3)bPE(5 zTYy)4-6O%c4D{X#g30|zeBAVa=H@)1{ttIR?VaVIJ#7MdwC$%~8<bp@Jq*CJs_K}v zX8>l|&*g$^$7G{F9mMX5tN2N~1MEw3AaA=|vaHp`AbWEhUKx%S;nICSCK95YJ$TfP zi5xBFa{riY3{wci;elEhG^UONCIVF_UB~BHdZh4Y9AAAN!Rh<1U}Mlf2pFP<_g&=t z+o~C^-)Nz-36IIUu9<Y7+~Oc17&g1iqu2$fC}8MA`H>}i=yrlL>U##@_nG(bzxfvQ z;JgnH=$Q_uyN@TmA=kx7rT1c{LA~gtqD)&ZhLUP|tmu*4jsL#9L)yJ+#1JtJ)$J=F z{>ce?D)uE~MN>SY9}NNF3$V=XEtVXeFD$M0rSWNt;mUwqY5uE@mtGr7bJhRzoTuTz zt`o`Yzz+0L{3R|_zKB})Mq`b!2L6fo%s<zi6=qbY^6{chWiYT-d}~;To1&+IX8Bc? zDcG_5ujN$#PGX9UJ1!J|`V5T{$KX7ubNTuVn&rPmER$){sH|gL-6s!g!<2dD<5G-y zT`hfvZx?KKne#>2YD^lf<DxX&6CS=T#?5X@sO|kv95TigCkAXny$O-zi3Ngw%T)Y$ z#+FUh<M6{yd-(8g5N`O_Al6(q#n@MYlt0EtTxuurOv)z9{w_PoUWzJw`d>O^OtOO| z^}4*{-+!P!e>Y{-Ycs5^U^~OJVzllU4Daqn!yZgR-BmiU`RV|yEcE8C->0xzVFsG* zS;tG4W>8*W3<a%9r$B}8aHvw-rE17~>g6~Ru67;BCY=j}8!z^v_8n`9>pzQ6tQ^9{ zd<xgK_QyXnHsGAm)i9*ui0pvzH}p+>C49{Y5I%c&vj3(?Oey*T?c*MS(d9Rwe(gO) z39dZVZ#+BXDDr5x?VvGi5}N$(z{|Is0e@3p{;j6q@?@?wTUNgf^L&oMnN4c^L!$xK z<hY@;RxD)2r9;}hT1<|VgVXjoWLPv9cS_H{w%#6G96bj8+e(B|nI44A3`D2AyJGE# z8F+f|5p3+)k2MyIW^G6lvLV2whtoG4Ewf`X_CoE5JEHL{4U8yqVTD`CbYo9Bf_J;{ zZ}wTTsn^3ciQA<Yc7ct&?~%gkI_C>_hM|9uDZT$5$5}~-*n8g^G+XzN()9ZC(~h$_ zTl23hueq2P_P&8r3d^Z~(?g*?HU+i2cjcu6*6{NZSNYYxcBuVEy6@??3JyXye$>?p z4Kr1xxyE!1netW$F<L1qyb3_Sz>Rpn=YH<CJPhpSltHmq78~cyMTPZtrJ+sv+^~KT z+g0?%DF?6NvNt`Mc6O94vkB*bG$S$zS;T9Dqeai8vn<m+3y<PsK|50y_U|&q_SV-@ zK4wqp$2?zb+P$28t@>h2ixIiI`jPMIW6)3fdF?;5kDg!oSUTpkj!WhE26}cU33F}B zg}MY~ylTo+E%w8LBkJ<*%H>daz>%6hN})s7Z5V1i6CGEy!KnM;MAm^a?TNlP&Kl8m z!y%VdKAL6A?=Rr@KW0Mc##X4czAOG)=7QSeYN+eJ4_x+46YB$Yu%>MWk8Q|@ifk!= z*l8XVgxQMu;x{4J{IsaKEKcG%SVO^<CJJ?Qga)gnkkmaM+hGQ4yqk=xD^&6A6GJ+$ ze3R?^TZAsgg>a!{7bXPh<HqSas32b^uk+fC30FLY+SSIGGiM}MdxWFH$Hk&;qAphF z+K4M1mcof;R&03aF1eSF<jqzmsLVP9zxLM={IfcM_Uhg^xmRcS+xah7ubIld)(qrJ z1FnOwbuQI)XRIE+PJTfy2;8Zb*It-KNqsDNjg0{w9&b?=AmuDp>-b>$D}CH~Y$)1H z)p1eSewHo6hLUzxfT&(UIQ>_+kn>LfxkohX&5cLDHU^E~>rrjM4*ZpCg3sQ?k>Y}1 zWMXN~e@~ysUmXk~Gblhd;dnY+O?*fJXVq}}dT)+$Ead7F$ru%2!I4w9aFh8U((TtB zJtVHme-Tee+jblqlo)Z@xkl;|cY^9O%z5Fb=de4c1nffwxI9=T2al!xLg11!RDOF3 z#@|yy`PK_~%k>P;vbjZ<52>-Wn~C(bJ?Q3^e*Ee;ux;}t&XM;9xT40tAJnj;tpg02 zHkhU_IxKFl{6_vmx5K4Qx-dn32rspXr-Rc>Iay*4Cu?`d8pTmeZ|dcm-FskKu^k<) zma>S+9k946OS;#nu>mN<hV#-~LwZM!Z?oY4VpCap%>|fk4CKA02%|KYP?AwDM;iP9 z_bL`nZMVgrLk^(Ja1Xd<HisLRTq2#@yZNTWUI^^=RD!3>!8sCp*DX=8Ot<JIF3xnq z#4np+X8)_$Cx0?-m=MJ~N_ye+gAZg=v!q<?!l4+JGZ&&K{t;@behc|R7$m<j<Wm<G zptoKIzjf{?y-)OAx+Q#cDZRIiPGxom+eB^D_#VZJdwS!@T~TGjH6k$oat>c#9wjlW z9qB;MEFQ0Zi$3l@0%J>&HyzVOC!=XZ7k-xNnD6A_XFfr0{b@)&@{$@qtYVuK6LffR zkVdbuh3voY1cUkzdXS=6R{OWJIDLsRRd<)z6Y)_TU>PHi>g&Kp=Nz$Yj|!PPEtBpj zspK`#AAh{f759(!fN}X>M30p*VCKG^>-T-3!&(PX;nZ-az-)V$;*Jtyd_qt5`8*ds zkI=>tWe;8=^_OhNWuT@?7Ef6`4X>qsqk!a4L1o7QjQr`$Q;Po(nJZCzdJ|miSPE^y z>MRe@z(JSKarmpQpkNRL)&Ux*H}Ec$PTqqhwH3I3{tVEsN`>e<KA2lLl{>yNgVTFQ z^7=(x*knx<6)2eT=YyJ*vGcxo-Q*(O{2c}VD#G#9J*fvD>;REhdx%Oijo2i8CGRk| zB}LzTxKit-5K+~c>wmOTx0GO9mfb+IBMuDVZ=AubP)vJp441cRVfL~bq4)6tymiog zT3U0AYn_&%`ha&7mvTpFUhgUN`Y@WEs_%fj-#|VUGL02rk<-&CeQs6E!^G5U5}V*A zWOfafDb;PF9M520`1Ks0zflHf$GBkT19L%D$P$iR?~X$*PexHGk!FvV_+YA9IQ-Cg z^4(zqMi5P^smEmH=?=IzUg{{0Y=V9*2RL!=3RoH;%B(`9%-y<3oUf3;DkI`y$YLO; zs7@T#Ah|YFS(=-Bu~~3}py%^MT+n$StDM-zXZGAC<3~~W!D%0?k!Fm)TE^o1#(Y>m z^cl3Ly@s}JN4UrRALQ42EkBQ2D?U+<6jvYoA;MNCd3eY;$ZmTh-0rfS|7-2S>(q7F zV)j}Nmom_^Bxl%2i8~#Vw^>M;H-o*+N8rP*j-;Bn1Sj8hMbp)KXkfHcx-%$ncKbNY zyX?bZin-X~DWaFsSB`Moik&6a=IrW0*kwZuC!_`oL(D-spG&h_A8Sml=*aLaOjfBi z3l^#j5JwkyV#LQJN)vlR*gtc8+VwJbn)U^HpPh<BWIbeR_FGWy<cv!wjz<=jfZ3R# zE(T{L-)pxH=wLLB_sZ^|>54?iYpz6>zysj=eWt|BU4TX-v*^?&C0@3#E8qPQ$zd(F zxNuAl-emEX_OIW9Bb2U_dD&M=OWDUkI-cB0_VT~d?8f4l8V$AoiQhXnQa`aPzMC@? z(<&wkO;e|G*4MSHaQhgP|2-r=KO9Eo*H5y+7DZH8Yc43YOFImyM;!O(IPKl%%L)!F zOX{>0c#Lc-x7y7W$Cb;_*Pux__G2jR@LWSfR%+2|-42{w)|+r^D;zl0jeX}AK!JY% zmlaFT#GN8x(!P#l@Tn8%du^fYKYclQ{8w?7{(OcRx8-{mOys6TfML(4ia&nr<+kAI z^6Z6jGI3IZdgX8Q$FBj3O8pUT$zcB$Q`~su2PjOtP<q627tY)si}}vo*+RZS2<!5N z2kq^^x@iyS+sR8Xpe6%%b&?nqU00!Eb^+QAZ4$SYz9RKqTIe>QJKXrAhtrBoAn@~X z{O`g>9F>qoPJyST9HJNeG|7U^XSQ<SnQaV#?@J46h}A|-<Yk9i;ar9VAIzD6u4ZGv zwpwy{KbyiP4>V{{zZ`IXw-DuXmO@9R1~A=FC{DL{PG?RG=7NSmE+2K68;7hEv(68O zcE1;5iu(;Z-tPy6Z(So;&6b|k(hy;O@4?V#f1WU@Z8fWp60z%{S^TNXNjf=X9-o-? znxcn!VeHS{Se2IuSN)DtqSJ7k-Ba2HY|0mJ%*m3R3OmuLj~sQUX>g%#B~~c`&hsyY zlVx4``C)xFyVwr760fVHe->yoM6ijbGatBD2Q{(%uzc47c;*$st;crAt#AP6Ug<>T z@PQr<u)^{?*<#MTU39{31~0tQ9ptvtai!B51UK!HwbDJPrE&}SNuN)($|^9&_8CV> zHkcRcTIe0Ih80G4a5B5T9ltM|h|krfyxhFQFz(KF?7h(j=QQl%jlEYx`l5mOR!7c| zIZJl!(h!NO5{ueNPh@+hDD&6isl3E{4!`_ZPB$0aCdZ{^Jb1z&>ONXJ*A@ox+c(y5 z!FwG4{TU7l^CZ8te=6P8k+JWnyHY;B7w>d0qV?Wc;4$A83$%;m-5h`8BGLw&22^F^ zNO!{@qd~8!eAR6yyplMmtD7=#__ts1GS6B1yq00+W@}XPn}Gc#=2eN*CtP$4Vg6K| zD;q9e!Z<BY)Oz}oe4hS<m%8B`OZCuxas^qYdgB#0Rh0Kx0BcO!aK`%gu=GR>>N%&- z;zRq8+KMQ>N*UcTnKBPYLf~^Z(bxMEUF&ocmhIe$BhMMJ>g9JNQ~pA2n*I2u`2`Ac z(dOo1Jz&s^n_zghP&ED4k7GQx;gnv9(9#&hDVGLw?io3>d6o&$7gB}VG3r!wfpFoE z0>0W1O~Dms@vr0#*f8oK7JfMfX?8bd&wEJ>b?ec%O7AbZ_mWsQ`?UFJmo?ybaV);j zS_Nd|OD$(ju*=$?qGxAYzPPsstLmQs<Arvh0+Qe7qLgcXJ`UIXy+#|J=)(o8DCo0y z0v_6%Mi*5g=<&YeFvMsZINX=c8QzcRVfS{tnll>Z3X}1xad(tw8gY%;eX;JvVYCch z&yJNv5WDu7=;C^uj`+D^=(Mib=VChMJEZY@tE=#5fj19cYRtBtIXq`}F20iP)qPg< z!<6hgj$hD)kL;|)Or2G7%V)ma+$)Cnb{6qX*D7!c8I0!7i+SD<N7(IMM=2|$yGM2b z4L<&aotl+FyLmP3czKEx9(*d%HGVB+1G?aV-b*mtvk1G?b|m?HCr($bgK)=5vh^xD z6h3%~yv}kC+3mb7zU+LDQoBB;iqNBU<LNe9_)nCXsm9{i&1RAlHIGI|Orj}^d@%X! zK6unM5dSW!LF0^AA!T|dCEA`Aa-DMV&TnOWal0pmJm}5E)0SYSw<&#onJ=9w^U2Oo z+Ebs@!~XrhK>s=SSV3p#NcWRl*(tq4nXP@PI8^g7Cih@S)@<T%oylDHHd4$HlsT+O zCKelaM84G(*4iGSH0z7vh8$N~KI^yOwCn)S9*~bMOI6smZ!Y>k5i6|vE9@$;=e&8z zm~>akrS(d!<VZS=a$9%Q`FM<;g>=Qr9h=bMj@0p}JPyjomtg9Gca&Sc8-r|K!lzYk z_;t%n7`&?|wqM*uPlHAJ9<Y?B=QxPX$M>=0>7SG^q`x>##}s~h<nZ_CGtk3!HhsSN zlI|?J%?39j#I^d<@yCiVT3GCWq0u6QHrQi_5&b!;)`{yDC*Y*M>$p?>KZ?uVM<u5_ zb5z%z;I!!vR!+P|r`-3z_h9Kfegfp5pX^5yryk_F=rmU*NIg7C!H)iJ_#<v5dT2$! z(%n4)k~+COzhW=sHcPt=zffNC$Op-x2D~!cA$!|Fxb?IrH{LYh4Rd9@a)dq`t-LG9 zrC#md^~wA-^AW5{_vOkJJzR$DiNgC=Hp2a%ec^qx#6o>0xw^uWQD66t&}4cabRU-C zfVCf?<ytzuY&ix!=j7tovhC>WVuyBai^Wu_8&IO>gYPFt(36NTOgp_EYrT50@oXvc z5LYU8|1!@-xuqTpD+PW#Q$TvPU6}H{3=TFK^YH8?V3BkZ8zo;r<Edg=I#dfIm9@FR z>k`*)H0CZ^J;|&8SnPL1>SDc{!5fBVaHUlS-hVuZpNQ)z{ZJIEHf)pUHl^^y4utzd zH97c85V+1dEb&E#Qd-h>$u(<E7T4U-u6`$dozN`&RK7)t7y6*)x?Wfv>V;2^^?~sE zb+Tn$rEbrE0l3TfFs~dP4jTPCpug)rHm>o&g&wU!MN|csADqaevwy(6upG>cZ6l4$ z5j5h}dhT89L$1bB$ENnA;OJ7w*9M;im0D@msagRUA0~jcP9?a{s1>h{TY%f&g>v~b zdkozEL9Bi0PTr1cxU*4*o9(WOb+cOp4+A}ycK<}NZ*7Y7E{KsCxs`#Z(F^*%QvvUK zeiUNE?m@uSF5;wzJ^B0F6ik|Din9kkg8Mhy#j3so$TCvmsyR#VooTHuP5xSCCpQ&K z-U^1G26MErQs*DjJ7VyqSKQ~<Rc>>A0H20G1#?j3TH9+f@OViEDQ@UFGmT>A%BA;( z7i1jXBcD(=8otlj3!`7`2eP#n*X2f|ckc=8qU+2LHwI#4RsucO+9A!b1LSROsZjWL zGOqj^f=gB~m>fAIPHv3C4R6Eg#+PR>B7Qonugk==uM!_S=`w`sS_&bnu8aO_e$d@5 zd+GY7bZM_xNROp6s9kD}08=BKb>B|H>57jbbo*&mDCu0faNK7alB9_y3I}Ch=0xK6 z^;5v<*bU)=)Xy;Sx+w;{e?Sr{8}{x}ESu+cPw?>Ti>d)#(7mJ+dRx@NL}>?nrC$fB z<5djyqf-zzo`z!G4RBU<4eOg)p@om3xYT<jwkhq#CMADNUbUNQ{H5&f{AMb8nuIDL zHKM_8iIp&MBy5vEqvu!6Fn?_dP49c28yBaeg2`{$5wA)7zUM;mpL9;QxH<?Muk4i- zPnp18W0z66?F6b@x?Ln8Uo21D11?vWfO4_A%f4Uc7?7nT_t}w6V^*u-xmY#)I;t6d z{7B?sgWdQ}?<9H=<1ckJ9tfdld-2~}%h}?YR@vCNc+mJaf``PEvVz@td9FzVIUcKn z5o3Kh$PfWEH_D$GNUq)$E2wRU0(S@rf)j<V=+zic3F~Hv?q{<F|E~J<Ut$Ry>a-tl z=TW}z+(_XgT;<-y3)y+yCKP-t=*G;xyyueSsk!l6?EfnPr*zWd#0nb@f4x{36B<h$ zC04?z&0FyMD>ZCe+)mrq=2CgTaGvT^15T0`VPyZaxNpG+@>#1;7P03Rx>(J?(mMyB zK`9-t8gD?I{^qRIb`{1Pk<M6jgf<>9#(+oXA$IFdag4hf%yHZeD>r+Q7aL${R3_`| zyP}niipz_YdZR-0u8OYi67z7!9{6}OnJouzho^T#%O+f!f<|)_xOH9!9vLFToq_Q* zt=*1)OMM#E#K#nJw-;u<y&=AT+Z}Auym`<pPoa9oH|YPiA7z$?@%m^-j2vqPru&*8 z%^*Uo-Vh>t?fIPdY1Tl9NdjD-cvSp)RH^LIj-L2zBh#?4-Z<sROo-00Vy`Ao(JZqA z&ImQ9oGYWn=AIoOEZ+&LJgivHpdX)nb^t5xcZLg2CN91=I&op44exf%f`UIY#fsos zau2*IZa!U%3!|5D^8^___f_Y7z9nuBI*Kik4s7E4NVL;ENO5Kl#M_gqV5f~UeI4nK zX>${~J#0AWKRXB~U(LavJ1)TO30?77TpF&N`c{<1{1fK)`~oWdJM$IyAZq>CPGKtM z>?NJU;{wdseQhry#j~YPgRW8Thn=#5lZkj~Ks+m4Tu|Cw>Iho+wNU<KKc>_Sv1L>S z?im>X-vey;S>_2EB+C(+?H^I-{n`99)&pWDO@+qv$v9j29mvxUh!aO{VAm6m1eJ~p zxF+!==qXmy*B{b+(Paj-_tK}hOSVYb(>S=^lWXTE(ny02Y;toC+VxE3jhX2%vwaJF zx~j!HJ{;hz7yH<3S-dc(vjMiv9zw^Iev`X_5#Igy58D3v30(s2LznxpkUukw_P$7l zH*<+DeUm!xUWlq$pQ+>J5Y+S0;q*cFu-@qunEXtDA@Re|Xi5ru293jnfh%Z;teG-p zbD?tPY6x1lj7y$}fc>ImDgi@ibQ;XDeN1`!1~v5P`5ux_sbcWG7Es6_$GJI&z^7Ol zr#)QF{Sp#s#@OzxZI>mmb1PNpKBT8t6uB)%MR>o-8C=yyv*WN<vb~c+pC>F~l{aA$ zi|4Yu=IbMvCAnMj#tZz?V+QI5NawTE;rMZl0p4AvBKC-KfwjUy%CV64mEqc4F)tQF zTyh~MymQ&6EdurzKSS=!e%Lc=8;5&UJF6O6gZIs?IAQ8baMxH*LnZE~#r7q_n<G(h z>&Zz_c<t<Tck3(YxYi!eAIN8{ZHI}|Pl2|#E%l0U#IJAD5M!jfiq=6$S*Px@sEZ?- zvI|7t_%258kH;@YX|VO{YdqRg1d4B>_~rbgI7!bM`i(qB3VZWul#&nsc@ZTjG^=oS zgg)h+48)jc+I(6bN$O9}uys`k8}0imPf2=2kIIgV>6tl5iaROS<QXLT{e@BmS2%J& zo26c$a63E+96hDnj`MH1_w#dH<Rv-Ji^FAklO3pF@@SBzzp`_$%-O7>5so}QOuN+b z`1It{Fmp~e1Sd-Qz7Ix_q&b32Zs&_8zZ_+@Pt|$r>8YUowN^BA3<FHr!Ul7_Saw44 zzN?z?i_SHmJ1q`sTfWlOCFh0vR~=cQveJ3c?;$+?h9Q1llR=vX%;#kLVwv5lJruSt z9kyJmA&q=j=o_#Ujh!!uak|m?YwdTqp*xjyv`?V>#%!!=x8e30MLK%=9QSzCmkNeh z2)pVo2;mVWFum*q!0X=lBrFLx9dV$v9|L){XIBgf*e_~C-G<=@9|(yO=V`iLXIwhv zuYA{~^ZX@N2Xs5_2FLx$-1I(<=jt60>?%dRe{T{;eprO3i|*6Xjmr4Bvjf~5sR;|s zw{reELsIBcCHwVq8-~BWU#ha?BFOWv!XdYvV#JN!Y&vN%f9^bo=T7QHN?wV=b<4*> zTh0nvyrYgHdfCC~Jb~wV=)giHebTh)jLq$1IcUZ`eE&i6Qt!Jjdil6Y9k8O(+uj>7 zbEpzNT6YqLpSU9|&U+&Ev~)s;jFn(3F%V?4!*R>dWSlxviH<J)4;}NDV0+6y(Qv3G zwZ(5D)r*>V+3UQZ5O*C+pWLCDGrO>sMjv!39)$ycZih@M$3&Lhom*D>aq_?`v~{%_ z>&#_{%QFC<yUOIdZ930*lLT%KT9|2l1~U(cPQz@o1k@gg+n#pf%%(^3rWb9rak1o) zf8H7UcQD|uKl~uS@d_qO|F`WyYAjct3|`?=vEWNz%(E=wl{L!n+;1-4oppdsHqMsb zv%g@mnIXR2y&sCF-=&!9U@l-^&bWG7R8Q=}E283gwtYI)=XS!8Pt^E&V3Evm)@(LP zDTDcrN(hZ%!a~23^w(z%g?5wXmREc6+`Eckv|tQ|PplxTcn6o=hCe_!U_`BNohbZZ zA?j<7;}xY5wDk85+&AkGp3@$TB}vg-7_aW)^k)Qak+OA8op*^j#SbX(*=9I3WXzQc zjh$F>=OUFnll=12#(<yyZdMX1;7su=`gs;HqtXt4g=Pry!YV8r`y0aB&GEXzSSsqU z0MpwvsIQMY`mVZ5+UL%QUfVn%*mslE2@}QV6<u-Ie=jMb=YLd{Xv+6>$FtGF8nPNW zox(Q0fh#%D;N&Qo+a(vCbFe$E-`5ov8n0!O&=d51nhgeQk;ambqRB<+gP0p%j^Spf zxIlXhy@}j_Rns)V^-315`{4;$_*~*x+Tgn}4tTc1eG2fgX1g7o#i9y5th}p-X2;gT zJe5Nvo2rbzuRaj=SxEW%q^0D(ELCz2t`}?@;xJG5hF~4N9j!Y~Vq<in-&sT9`_J1z zU7F=??Hg!i!6R@BS3!l4dotx}Z7v^QiJrq0@b9ij{MY+9MD{pNThq1K%W)5WFO+JN zZ|X|PW4nC#Vn?!D5r&z{dN|8wIaXcxLNoMDa6pda0+({ly*r-cYbmklHRU5jnWm%n z#2dWlql`7KA4b(L*94_+5j^v6IA>=?Aw^D?>5q`Um#mvy9eR*z><*C16y%Jhr|ElZ zAqQPr1KY-(A=SuNqV|wV*te{R%2LL`f5W!oRrA@{sBsWd59D(2fK%|~>IPxU3?JHa z)RpG9Y49VmhpHJGl+fFfhQ97VgEG}1BW5<Ozq}OR{%Z%Tw=<~ZLMin$&%rTX2SD~B z3={vAqASM<j(w((?etUtlX$%9{|^qk%dn-(R94>OjDD!fUB4Bh>9XG3f5i@zqN#9G z>J!_Y6*%6&kj+=BaX;k>Hn`JKHtgYc+*j-gRm)%SL5d*<y9;9NEfBxoxkBOcyH3q( zszquQNcqt%xHpR^Tz3;_orq!E35W33FGc?AatPIC&gHGDdiXZFlBQ0YfqlH*qh8W) z`1}4OD%igUl{s$QML!E{qlaSb%Kkj%=P{w`Oe`8KZxdG!cnnT9=ip%{Ck#`ZiPi=) zvD-CE?&zh@i=^)A+CAyy>L11Z?~LPQkAuR}+ykKFm&gjAHaf3<Gf=otkw+CVXV|t) z3w}v#!0Y3#h@1Vs!R3Lyusl5;oAOM_W3mDt`s#xDPkZqFJ5}^Gy(`scx=_T_dtzvD zB_@pgCo0}nKpoGS6vkJD*E{#(1%)LrEW3*R|5b`Nw%B3fS7mJKFcPcJMN-|RBSPwm z2Ha;8166~&uzR32@7mrGosEWo(g~S3qEQuAtLbptE1B5i%m_X;xrIvRKNafr*W=XN zx@Be-(_qrIX*`Y8T-J6h$E%yvC{O=24L>JA<)od%y2tq_Us?^hG1Jki|9?0x{1hBh z8qSF)6wyX26}?w2#8sEQq~4J<tmR_(^{yBqr0(kDkN~_Zos0^rQmNv>5S|!^bm~u- zOXvaxm#ZUVxl5}%e(w<j6Ry05IyE(xb#lklU(&AQ&QHNz(^Y&c&3fN`?Zy|bp63JR zKdII;jtZ1Upi%onax9AAje|F_fp<C<_}a5!{Sc1mxQC(IAO4&l%N@_wq1mBGDzuas z55bqPwa+N1E?dVYGHbd!UIVY!N6X4@?-N(FIq_mHgYsv2Fev^6=#9~ZkS=k;;xY5! z(!k$v>&04$lXDo}J<-J%<HESopet6NJ}L{WtmZ<$Z5)3-RhnU5kp9N5QU8hWNaH`r zMRR*04Y@sEE|IGw#=vo&UcMOW$C}~f-EUzZN<PTBwy<LF9?};TG0R~l>yFpLSu3Q! z>kMzXg8C_#VWi1bkCPzJLfTt&{3gx6w}N}n2{fy@EN=L705ra~(CPzE!2V7$*w@QJ zRc0x?lV;IJ%uBGYlL}gVYk~+ZW9oeP6NUfWgRid)hO-^jMy>wS%tP$-c*y-$kjrPI z)d)i_Tw{(ZZW?7TRUffg`fA$q<`vxAhI~3AQ_A@5qC;-`AX>Fr=6B5)*YExfp;=Zi zZILz>Jy{Ev!Y%Rc7!RDBB%ns`FqquIp{%@N6s~;dE3uDrXw%8-;*G4YfUbWqD1QbD zl4IAj_8h1WD8||2=kln}Gtljn0ehs!p=^3A`WNZ3(`t1wS8blS(fk~FwN?n)-pGk} zt_e3Iu7H*FPSQ2GCYJAH7@a;GqmKj$RcjwX7cFZto;)2bbS%VR-*2$!U@W;mkyu{6 zws1pwFs+($k&<3b;|Yo)`(?bO1jjSbxT*u1uj_~AZhB>n^UlEQ=nrDy?8hLBvcL`9 z3*Zk}ppD*Gw%XE*hrI7i(`o=8tyqjl<z<k3;x>i#IU_6;GGL-rBHp{K0btNxT2Yz@ zbSs?QZA#!yj~K~2QO&wtbMaFDFQUe$RUDPn8~Xk@4u{741ykLje7#_uIB&=*%H6R> zkVlN6n1=aySofpEk-rUvA8%r<Ov++R8A{?i2kLNfqBOs4k~J+XrQ745QMcETTso`^ zC&VYPey}G6M_!~3h8Dbil7HEP7*$NwXd>C12-bM~Np?TwG*ymz4!MJd@}&m?HET!m zPt!;aZn;5L^?hiw(-O$qzXEgXibb!(-9+*>7X9!0phNP1RP=ip`o2)+g>Mph<M09K zH|HA9yX%gwp%cLIydn4Np9671vN&qZVqC8m&(+TBWhafEf?rY-o!qa)&AW!+;_k)5 z-x323H%$_BgWAZp<rd7#)RXv6^D%0)Em~?<^S9-PaamFr*ly6m-gf6OSv-s8rZV0* zO>%II?d%-YTPC*I^+Wn#2JR`j(0-)@nz=MUl+?i-GIgUkFJ&wH8>Zuzjg?rFYcT4< zK||6e4{_=BpW+$4t^DQU5Z?Ce8@v3q7c&-^3#qw(==-1na9o=A_6?D;_9JVc!S^Y> zR?LTT*dx-*7>O}!PU+ppBfYnQqxI^j@L~e@GxWrbwF3HfQ^oL@sFFIRrRdcE3cEk) zhtr48#E|zca)pWQ9Idhp9}e9^Aq{_E;de#OtacGXOikso&Bx&Db1M+Wyr=waC8Fbv zExge22<gp9;;}08ar~<H(EFhqHcP%r^}}mvZ?iqjo_mwV8AbE=E8%ckaStxHE2Xd6 zmUy#^0xmi5R8aqzjfIv)q%ut6y!lRp^lz4wImt?FeRT(>CU(Ftu_uXMPn2IT{R18Q z^+T<LBD|1T;KT0DMw3Nr<o!4AgWNMpc;>ewbkcrB#rfUHG&F~AU6X^YZvxHwwGtHW zdx2lWUY@tXn1`+zfaT>?^!l+5+_icR2X4esY`H3%3_s|6>G%OO`(TLI_t%ql{fpAZ zZ+qBr$qV89-zXkX;U%d5SdI_JHiKE7fnam8fquOzW!J|2kaDONwi-Pb)Gasjq^6C+ zo3(||S}5&-&q`kG^-JlN|5%<QaRocy+7FJ=iuiZfMJlU*5AMDDvYJmfK4<UFH%E@< zg27$r)Aqd>I^w(dyQc*!b@G9m{yO+>L>bI-&=hFiMLHV1Lnt3!Dc-Wp5<51Wr_E=k zgXz=F)Z@@e+}IijDHs2Uj!~yzar<{lzR&^-yUb@_8i&E-lVM8xR(Q1MmY{o74muHT zY%wPi)GO5aW<WJv*Evds*5zW`gaK&zE0U5|jKw(Z?qY^hj>JdO!MvT5Kmtzjdz06q z>*(Fo)I;hLB|N20hXS}@!ft2Ph7el(eV3Tf-&68VG>SvZCa|Wb8y|Xh11^Qxu+^R# zcsqHkFf_I^YN<_>GQ~Dzc1@Mu1SSj5G*@xfJRhq3Zv>?Lb;8A?^e95z0u3MD67?p3 z;k1+b!n)Ubxc}*9iCd$^(?2O<cu0oR;O0A+Jyac35=Qab@i}}x^Bvru^9PbQPJv}D zj^djtJ#>jQhZ{5cF<5Bgy%AONI{W=X)!RzQSpO6wKNiq$d&%v7{U$aGny8bdisSaC zP_FbmJPI34{m!4ow`b;KR=1<9U^thS#@54`HSYKhAJW8M!#VX!8i!4l*k?xDM70gQ zuv>92YMy5es>}Wpy<Z&QgHxsae$WPKu0uk?x|>j4_eQ8x4}jRNo)F%#8{D$4fmqK; zxaRFHGTyWk);B!j=IAxjTxJsZIv#-4ZOKv=N|%?sx&^xrO{1oz@pxwZC($rt2lqNy z1^;H<A(xcp=szlxrhob;wwxV6pG%anV*VKZ+_6mvf1&{vigxgGRyx~^y2aIB?>YO{ z12i8nLkG~s@Dw*LzNLuMUu|T)37T+f(^k^&UI+m_wQ!5oK<+o|J`GJjDYibTm6!Zl z#)r=6(?-dmcBT0XmHQadhFy|JGEHI+D7=E<QN9?u>Y!Njd$9DolkxU^7gVq40If53 z$o{of(U{p|;q!wo7|_00${?xYspL5J3oU_s_h{~PI2?=giX?9mf^Bv-)Me@kCXepZ z)2nwN_xd$aYl$@{|I=ZO)rWyT#Bju#1HAN~5{|wj6LRad<Tj6$F;+MUx|cL5OwAYe zTQm}FwZ@wd{?gOd7;)PYH~jplD{pw%8`Gk{lh+#*BdRKe@Rf_{RCFG^GTH%VJst?Z z`b<HMj|S}15h$-FUh<zw`$5NAieHw9e!3R~`>+!bJn|Q9eVK-X>Wu{3Up>(Hzay}H z_h9V(c|2KWnxNU!PoU6m76u1($Ao1aa9P25iT!&5-%I<yw+9!2KfBProg(zQA4-u; zS7GOg5Xt8;1ul6M3jJqkVR1+X-1xf$8|fM;8SNxhOHIDDb|w9;84rpBrF_>UTbvxE zM>j|B5npUQ0^VOGMwR1jJUViZSZ@49n5Q~Z7#?UR-81(IH*OobtR2u74SJg57()kw z!^#vpV>OH}--Kb=4y<0kRLs${!<wa|kr$=1-QOGZEL0DE1^9A*PlhG$tKfh|iLiXG z75-PHLNC4J_{7vyG7gkc?zu!+ZSy`c?Xb7RP3(-+=`yuzT!d`DHoEs%Vuz$<famtj zVB*k+W_}(^yM|vBUR3Dw7%7)^P}-{~c;q?Xj(UKm7FT8C(szR0gk0)>d<W|GcAzP) z=@i=eKS)_CbxbV%QNw5oM>GvVqn*aMa?@VCxxPV|>wivs{d_)MbXaudy*x*X?Q8SQ z<Cg`)L1V<UgQ4_cr62l{2L;7-!-+pNFkzE24cj^gA>S5fN%Q5nqx0eUfN#*VO&^4{ z9dUTac|5kTfqr@>(Iu-VH1FjO`R#%R=swXLOw%0UbHF~Xv;HJIue6fCv^&v`025L@ zZ_Nv59uP~mtfZ>L5^H$TRXlgxnZr-^XN^%|_;z%YupvU5>42Z?<mX20q@KvL6y!AL zd_J`7X%(9eyF&Hf9JtchCWef3kvUvE#T6^GVT6Bg{yJ0QA{%&N(XFGxkD`zC)ag3J zcAAJ69EZv++fzAySG3^rDUcFY+6jfLKU4I?$Fj4w^*DaX72Z5}JKtOEj&m0HQ~6vS zyzU+=OL2Y$izSXw*qR6k?x2p9!85SZFCFDa)p5f&iD6cBK#bmXTj+3oEBshoO{v5C zv%~5rF#9<io=Lf7FMW0VVOI+;9;v~+$rB;!<zCK{=H!n1!@2UTH4dv!h8=!cxZQje z&$pUQ%4Ngwn^%F<nP1D(2mTYMD0gCGi&QFK<_lxf3;9jwMqa$FjWWM$^GVGC{4P>p zxr#Zq_mo3x)>i8F@`U8AFN9LJFtj3ld@yDMZd`JXR&|TvK}Bs4U0o?&2*2-qN$N58 zPFLid=XrwNNNvvSSS^grj6-pMXKef$$i<^qU`44X*j)<*t<sgC{BJQPuY4#>>DLCE zz8=Hur+QfYTZb1ke-o-6>_tb@7MNu=R^n&vqm|Q&U~;nsPYB4tSCw*z_OZe0jrrn> zHN{x2V<*DD6gKO-Q;e(G&voWK$o<7&v~8~ywABW4|N3x@kCFUwe~!u%Dlf{yH<?46 zZxg`fRQYP_r4XjEgB|urjGL#YxXdUOVs|$S{zp$jx|YBRhpq{Ek#?N$;E;TDPanM7 zR3+9+b1(ll<M5i>PHH*$05*(20!MpU@!BueWO}MMW>;B2_0LN3w7x})DFjV+F2U=w zmSfZ2Iov{P=)e4#G<onjxc54rcK?^jQLS;HraPAQPCUSl_7bbO_b-^TqmeAmhp?wt zoV+l=PMC7GR;b?J5gjoCW8Bu@tWiD5*kc_x8V$n~qf^j$#{n*?sl(=$FgP~YSL#Sd zq3^UEf{Oh}sQd5_a-A)NTUsm7u=gDJ?`Je?PanwI5A`scpMbyGeb`<Y$<s##3T|Dc z`{lqSc(A@J8H}}Hf456QY{>|U{nwRC-ku^$xA)?wq87+Kn@YEby@EfsQsuYTckucC zjo0k4qm-5iQe7_fZeM@KN;ISUcl_Ap&T_tcJQac-@58@4Y;m2j2R@E%#4P<?veWuf z?ru^TUi=~PX^p&u1s%3wfL0>VbSYQe77p$cExBEg-ihv#??!qbE?9J*JR<hexpVO@ zM*=lmir1ayHOf2D`qn_q6Ad|ftpiUE{Dqw4j?NQw(e<~bIJoar(A(OJDQq@ZwD|Gp z%0g<pm4qEfl<?Nl?R=slhzo*hrMZ@jpLwa39XlJ(YafgUl`ZvT((HzA6JNkiC1*5+ z8vOSCB5d)=Wwog}P%Zlo_N}h`_<=RwxQ3`*Rwq9%d4Dw4ofiAOKP!r-$I_FKPEb>q zNx`W|>h{C%=hw~><IaiBNIQ_XxlwGOJ(T+nJI(d&5?^&+8urmhrmH)K^Qdl(q}w%_ zRt>a9kK(1mAd^%cw>k+74R+y|>jQaBzZ7!#p^D0*`*X4LLUMilRScH;G8z7NCC6%& zP<&-RHdy4*l!gwxVW&Rc9V=y5pZ3H2_6+<zbOIDb4-jAV-9fVAHsRu~MYyiq3h!$9 z(DSGRbg|+RI$F5lg_+vm6`e+DM-P)--$YEaj1e8X8H^gfV-8!MF%z7EJHyBkN6<xC zlhk9>;E?5aj`^~HPhPjB*CkD&OT!Fa-Qy><z7K);?Stuo<ir@|QVAnYdg6i4_S7qL zEygMZ@wO+`pugh+>YvdRs`~c8d7eYdH1+hr-Oh>~bmoe$9t6WF?F^XiB5~lpb$~;M z&f~f$4OAaI4QE}-5WjVla;2R{!_AJ}G3oIM%nhE)wC`a_X1OAE>T`@PIIj{aZ~9R% ztpN>-bo#UA8U-D7rt-$cf<lLXas#b<pqG4~rpRL@-)j$ecJ>oJQ?3FF56QzkI~&h8 zj^hA_?U2>Hk&Nmixkt!v4$KXwVXKY_b06#w4;GyU$2)z?+`b-!7MT%6{PhMEYa1LH zl_Y)~-wz7LR?9Dp*)LDHw1{@!{0+q^UgC;LwN!oc3jI1!3_U`;QAb4^A!9kZA9tlG z($4VZ#p~3o&mMYh9ZiMvI<e!=;ixg$kca|#`J`^t<@_3`*xHl4Jy-GWi)z%O{Fa*S zeZ^J20sNv@G`e3Ji>(=tAz@~3jLNKpEUg)odpm`O9j$_Qqwk128@uz6@s{#&gM!I* z`yy7kF^J6`j$r%Cs<?LI1X{8=sBBx8!w_{-0hOlO2xZf<NNJTJ2K&sU4Yzub&iyRf z>3)_K|9J42`47otskL~zRboyI(#KIT@iZQ8iQ((di|en1<H7oEytZKn3Xdbi*_9zo zHg4Eu{|>&a(*wU7n2`5GBdIT?j6Kxi!J>2^)_qdsfC6Jw?tL2;u56HxjPJ#Fd!B#{ z+a~$luQTYb)?u7(oB)*`qv+YPzcAx^DAYy+?ylI+4<duau%xXd(=kKEW!3mWr4d>k zyy@(riKOyOgVP5m!_p{er{np$)XYv32a8rXrq!ON@3myZ{H|2cP$zL}wqfx8xwxrx z(x?T`i1eO@h{KMVvN=U@@rPs%Z1m-*UsK4dPnuxa(TrZ!M`J(l_c-a(Y1sW+9X9w@ zQ|OGtqD(WFUI%&dV6{G&*jNpfzi&w%fg;cyJ`rBFT$6fG*Wl3>$-RAc3;oLq!ozMm zSnXgfxJw<PmI51jhq33``g0r(PZ%uBF71WKCxlA8>g7OR)a15HqQo&5Bk`2^Cvlop zA!V$J;R{mErIXYHTAk;BmQtUWB6?7g+Hl;xas(V3xDM+sD^rgdk+e-K2J&P5u)u$% z@U@SLV5MAuzDJ_y`=nNw&=ABUrYrNq&nA?%{s{%`aUx#(76$V+c<?$6s+CMZW5zOZ z`D_6K8-GH*xe9mwdPdsm)X~D**TJq)dKUCIV!y;c6!*;?16LfOiC^5|bEv%#wZRJK zpDTjXmuxsV<RtxZY=rxJyVLupMe=t?v?<(bKN(@RJf!T8pecEX{(g?26{pV8W9R2| zYFa7pt;~jS(*(+s&NN#C2sJxpK*CoaSzE<8v0vXLcA6gy4JBPLu0xXeFSStWGj@{P zfpZ{g-B$K(7=(vY*Hit1PJA(RCqJ|E#TCxS!FRg`98tL`49@9AQ=1bganw{Sj<Mv} zls$A!R)9ghZ;OE&rH+?Pq@Z;Rv75#P(B)YaZQqF>byvcc{7G!z;fJ7bYJq&rrL(fr z;vlg47lDs@Zo*-?cg0yX9uV02L#&@J{cPgCh#ki}fM5D2;g5Mw-tej~b-gwKm23(G zr7i=>@YX7(y>0wLBMlarO@)l;&ye6H$i25C`ev8IFY^r2w|ozIW{H%0IG&FFR^Shj z^T6oANc#P2C4H!O=l$+`!Lq|V+Tr$2)cKnzvE#FZnP(?(w#0R)RUHoR7Wd@q7LAbg zT^XMbNW>+c(Rfr-a`?LGF{F)Ro%je|<LO6t%MS|4+3NVpbScDj83_Ta4uSpoH1_dH zq_)vjvXPUIfroj#_-{ryroHf|PnYvibxAA)rd^=Z|DEKlb#+j+ZUCl9d%RzTt0-*H z7L3kbBN|;F%dW|@Vat_EV3NF+qQ*9X<G4UPc+d+hrezCVb<Tjnf<s_?FdmI;fEHbB z7c}f0S#CKU4IlNxDL&6=TkSY1F4Dl7s;(}!_T^$i$T3Ph|B=#^yo8wfgK*327P#ft z5pJ0s65ifB23-#sb1$4HZ4i`spzcE2sF*}Tm?}>El}#QV^Ta9RdkP+XI^g4sN0Nr4 zv(#x&#OiH5%hKw;idio|6Y8CUj#Ct<ZflavsP8+_)_+}U(FWLmejP-A^QZgwehRr? zbm{P~L0B4KLyHvW@^d=}@ukF>FLGbV*%gzZcfoPddh>4S`Mb>@E=RBtcV*|sEm)>i z18~*>EE^ut!sR)_CAAvCVCEkD)Hzbz@J>eI(i5R-)K4^s7$|v&B84339lc-bd*8g- zM6n;{;PjyrNE-i0Go2T3f1oZ$Xb%L9_a%Z~@M&oNuOH`CJ)?b@vvGX+X-GHUNLeMu zysUCR7^*8^+so77pp^>U2JPkn+f&7C>mjVVcp7fXvqTS@0y^o_3j@YmV`$!1`p~)x zrrqlRsV^(3Tc2?95{n^WO8_sfwc+SZ6Uk!kewo42?n37LXhC;je+)=EC998H1f7$9 ziqGeE!cG6}q2lD(^s|2wYKHV?x5tK(8}S&aG?zouHb1!39?11mY|yOpC2+4#!BLC0 z<GYC@=J_e{rpk@1DF?jmbX*v2C5Mgs|4NRs#qjBq2JO$>h~tl5qP7;9tYfhk-0Uz@ zQ2ucMBApt+WT74=%|8OILvzKUQQG)Zy0_YS9>hVK_vp=m?hvw+NK5^JFgxcE<s4~+ z=Zyhk(fhrSGDT5x#jVDF7v@mAc^nFpM#B9VQ)o%M2HBvGHB#p)V8S`M%ew)1v+kcz zoN!uLF!vbL`y}Hjot0?g`cGK7<B;6G$`bTdJ9F@NYuI*Ts7vkc5{T*D25Kv<rCfJ8 zEgr9g&&MX>gS^gMsd0ePyDH=2IxkR>`t7wUhU~t)FMmH2Mr|f{;KPEuFhx&6OqLu0 z=}TOBP|Ff_HCM%gz=4?Yd;%;|3`U*E1H9@>6QpEI`KpnDIQ7wg)FAce&c2C(tuJ0e zb(j&AYhH$vD+}r5TYHK9(~~s)wV-|QE*cp#46mmLkmWlKTxl+4<hO0X?w=Q+@sO25 z)R&85X4j|k!F4ZTY~ND2QQA!BA5=*!(k1xjmpYED>PBU*MxxHLyerQQ(`C5yKl1ui z0qqV<LkiuT9p1f$n#bK)t(yiOI$a89dR4;bLLaFgGz1%0cfq3H2GsbU4sI=!JXxn! z2>O5QXl>C9S`oAb=9Rpl1G*CXxyK)9us6jhhbEylXCzms{DKL6KT`G9I3c(~%Hc(J zWD{EgpC5C<_TnqLc>5w|&iY4=yT_3ExO>oFdoYAP+(Wmz>e9!Jhta+CvZ#^wQCwua zfyy4V(upn_u=0EX3|q08qRo!c3CC6r@y~>u)WdZ3<_+puz7^}8{({+od$eqP1#IYd z77jli$-i1dIe%|GT<CU@e6|_F5R2Iy@;{2sG?1#Vi^E7Vlu*i?A_)npjQ6ZXgGy2f zsU*$P>`#LvQ%I(eN-`x$Qb~w=))t~PNh+z(q>|>+r1!kv?}z*0oU_+n>$je#t3o_~ zeIx2Gzrn5tO0)C#<k0G(;BY!ngR}RIgu#It_(jMM<}R5C7l!OZAOFAA_di|3u%TLl zTlyrdlo5PM$#2Bn2FbK=_Xo;3X3Cb?Dd4#I|KW`5BJ}yu3=_QGaO*U#hz#eAqG@uT zY>r0&J6Bjrr>4~MkCYq1Ch7q0`@Ni2pS?(dCr-j=DdEoi=mt5&tFRGnLZ;5pj6IrT zN+Ip{S*6kqc6;GjnxWak2RU_;ucs0-d;FQ36&ix+5{Jq6KphT_yGQSDUdDpEZ+T4v z1#EZAr)xQ#)O6VkTE6vA{sK?VQdf<g80!uRp06lAbr8GvF%VQ1OvC1GHApl(M-L4r zqJ5k{ghdU&(Gl{<W^9Mj>8X_KI*cXEXati{HPHSqoY#H)oNMx3gu%BB@c8KhI9^o^ z-fN1$!8C^dr6`Z8i5(E~-zqwwyN&!5098Ni1f$}0?24x_Bk`EXToaY(otp-j2$`id z_1}pU?C^<c70kaKPERe3FrnEB{|<3N2kB6*c76^;%v;R-Arxc07O_98BtUKW7Vf&) zc-B`qnVns9lO`Y1WEHdISkK~A@M->J&nDMF*{s2k5s}B~+S-BA?nB&s`>o9D#%Z|4 zCQ{vVMc8jI%PNCbQ`5z0*erh+aw1pa`wjBke-;CAY^E66W<C*IT4S;PgTRfGvV+oh z&2-~iG8<Q^L<#fng2GD^wp_Sl$L<Rz;Lh3?OuGfSr55OS?mld2TLj(NMq;CzNlaF0 z1$|qufwQ&raHg#`)vFJ|>05<ez5xN~{PU_vJZ%oKGsSS`O(&O=vJA>vEooZ16ld|W znevZ%fyJLOs1tObda};4vX-a(idU($+&vuR(|>?e`8XEWw1K|P5;Ea^16cB>L_Y1I zH2(kWU76Rzm;MNaf(MeY+u<5mUy5QozhzQT>JPqETVMEw{Km7NN+7Awk$pZN!qW48 ziAUVh#bw$&L<>H5xxGCYVzHFQzRjeRfvOnae^o5A<Q-v*@NU>G#)e%>(K%BcZq)5( zTi<uWhTbuFZ(tF)jY{B?M_aOv;Bbe!$Z`yulf)z%O(6F8VHo#*H#1qAO!vBy@R-Fh zP<$8;gYGY)slpsd(Lj;DxSb%2sthK2s>}6NM`Lm47n(dGk>xx}qkCslFww1#9K=_d zPyYdyaWesjNLJF<pJyqcH35dF4-smEW9axFqSh=+rrY(HA9wTz=O>&U$46?ie2W_F z$S<e;-z(Xw8TEXX&0+D;SKnws)>&xCS;f^h?ql384*OlB@q2nKWQQ2Q{d?K$XS%JB z@yX)i8x#12&x`TbnqhD^&y8(&jH8kPlKgs)ZSYWd_P0#CMi28d?9a)+#qtH0*p_Wa z>2FXDD!T1r3o?cG%~l#tzY%hTu`W0wrJe!=U(k#W;r|S9;lE9gMfX*S>~S5S@q|&R zBMcrM{?>+V_Et19_78<Bhu{M1F(|$C2x-0(-oF>t$S%GB>1kcixww!V3kR_M_f})Z zfM&WC`^Z7g;6Em}`2f|G3G=%V1vvN6A1c_A4g<c-uDLcz;K}DTLBPIy;`ERI#9wA< zu^l^GDb>0eUQWCP@`sDa7iu76|2F1jnT8{DUXo$XclcE}8ud3e@nHh@<G`LIChh6T z$uu(h<?)O=<GYT;Dh1r$0D)h8!Uvj%6ryZ=B6e5*w%;_q6rL4pVEL!9yrSkr^fP~g z^KZ;xa^3g2!PW(oGF_70yPgIPL(fy!xKS8CvPkfsKci<}^I>wAJhW^Xf?Y8ce9v!2 zPsTZr&pQYEt_mR&!TI5YR(ZDc`2p;=^J2<6jyU&xK6G_{rzImfHh9l7ephlA2<n1r znIB!SL_@vi<2Zj3ZL?(VYvSQiRvNgTDWnyLpTIS@%iNTYJ)*x8_A^f54@9ecg`Nl- z2pXl&l;`c^41ag>@2-bo%%*VAh@H+{7PoRY3UtV`B%Q+IPEfj392>9L2B{vx-nK<F zD@&UIC5abA2X<ML*&@lBg55{?^GPqcqn@&u^XMt#KgOec_yUxl+XY#AcQ7=ioO7Q& zn*Wycj!J?xX{gsoR&d;yO*?AD`|dMhQP+kOwLRmC>z31Ad%<ODGl%9oJJ)>usKnR) zJ0?0Pr-ZWoe&RHN4Q`sRf;*0GqUBqQI4hwpY;nE<^!X%h;RG(&wq&~BeFO66>rvdE z!2&;UD8DdW4;!}{GOZ*V^c|qa8pc=C#q(3Kuj>UH(-aPOMywET$`4^-(qga_I8hGS z2DnSkpKUvRi6(1ULserfjq&TF*+YUser-0SOfzL`$2Z`h25s>9__JCrJc48oIN-^Y za0=)=$oyTm<E!?~G;nebFTIlRXRa~I=1$~i3w@LghOg;Hq$EXb>*k-Q^zeTcaTvn2 zLu)|+?9_|pPN;^!O67q}pYjD()McpuG2XE_yqtzL*-}wZJzsG?gT3z?%HA%ru1PIQ zrU2K4T!4-;d-CWN9{U%LT0a)ksH9EMbNv|m$_u`#MXqees~Ebw9&upW5y5HU#p&+V z6cyf+VV23`LF-jNUsq{~hNp(`mW}=Ju3x&w*}5B&_pRp+Evw{?t375eFS;>RcMJwE zQpHP|LJvdjCj_~7(&J%ba?i5F_AN3HGD?~K_wYE~@(Q6dQ|GgHS_-)4krx;GUYei1 zS9r$bzr!A3|6Fb7B5X^PW=>O%P=T~J&I}h=s)x72j`dN%?>$QImJY}FZT4*K<OsHY zTodW%*TH{>jM<*d2wbW08a^KCw-4Rv&kKAL@|4o1TMI_w7^yi_dhs@%TXK_D^rwN5 z(;8vVLId+Yw@`hZKdLRdO`q^S&Cfnh(z~8>XM?4oY2H-2^HT7YTCD{o$97?d;T~u6 zIUk1avSpq@8KObehQhAr2{61LMGisR*b9GocGbI`O&j3|&aXA_p5WB`p_(r2gM{-L znqCmJql{mB+ncQlxd_{0w?HZ?kQbjp!xZJ%)4l4z3D4J^xtoO?Tqmf#Sj}3K)-d@? z-@tmkFdIAfj5Er6%`I0vPBx~K`P6&i@bm99c3f~@>3i8=pHng28n%b)c=8@{I~?)s z0&V=w6j}R(pM2rt>)_@vn4i@-fau*sPU65u9A5nco;}FJIWNL+dfy8Oa<oLv(Zj&+ z_#gz;qoStWb8#n^4${Z8Yku|5W=(a6VX)b08uLC0YC0|1ACW|j&L%ltEy;)OJnshW zz&g+nvVnJ&PQ;9ZKj=1hjnCcinWohx(%v*jW>z-|3>PY*M1TalDS4F^TnNIy=O+>S zV?fKZ7?n=F1)fRTZ2O}mmMB#~dj{*V-IvE;v5qX7->${ES6ASCm2a@=!aw@ex}SN^ z7{_Up>Cnk$Lv$>*gRTFK0}IWYoU(8)n$qxwbZkFR!vYRI>c&u$)(vX*Fvj|kq0C>Z z0<YNV;~E<s_UO6_o3OGRUR|7ky{n>m{5b&LP8o#K8TxSi)gtCPNR>CRBXIk$4}yxG zLFo@?4E+!!nysD)<@HPXi>F?}ekDWPZf^nV+n<BVke}q}6^%=M3&Ehvko9<EL8aF~ z)EG9=VeN{?^gv-63l5ZJD;j(G{OwYxcKjY3?%P4-`=+46zoFP{EP!r2t#L)i4N9xK zOfMc^AlZ#`@Y;b)(X?1SCaEfi*EbA8Q}>0~85c*tJM|&g-KJ*q`f$q3Dy6%j##lZl z8Q}g%48FS+J02gY{xw1!Uqwhm#E*Y8FSd)mzG{Z;X4A0OQbWj2r*fS`7tnj1?P$Zt zGnK#vv}2DgDP^DHD?XJopPoZ3&f*o+Y`6}y5AVY6Rlm7c<<H3|Q6E;ei7*f|@obzg zy-h#J8g5L%i+Y-5c4R)jxnBX~Z_S@i@u!#CI`}oW6OR?7GTd0hrrTO#yxt|MsalQF zbDxk`+GuV<^c3b9K9vnVa04QagkiVQPRhBV$f9d%xjP3Z;-8!Pxc!S4%AYf2|9U1t znw1J1?Hz?-d-@>x=nb-&RspRmb1*{Ef&LDij8BVVL>=ArqR;ZTNNSf4n3e2dwK*f$ zs3<9>7URZ+#w@B*T=ocNq=(|N@Nw*O?gcO_G~??kOmWI0ThRA7%zqEvkFGv5S=#*~ zR=#uqGcmmcx)tv5W5grM>O2e!JB6BK<S{(!eHPvAB(O?en|Vnjv+r+=v3f)-9UJzY zQz~zVZOsBRWpXY}(YM17P7?4o`vR4>d4fcqB{<JM08x2PG;a~2xKf&iDyXm;udlG< zRx+}p75LQRH$;p&jO}U`aQTJ~`VBW@?axG*E$nqVh|5S~O9GtNTMIiiW<$dcHSCJ` zNeS7yT)n|TXw4LMrQOS5!Fd;!eDf2WTD6QN<#>|r$xt*gKaSN;XQT7|EHYYmpFdpM z1=m7lS-5#P|7FA*R4Nz=R{t1hxBE61UHF8?7A+Ib2PaItKa=f~xj>=*o!o>*D^9j( zBoUWF;?vhCO<s+eZ5@P@jE92pEDJE*$b-@|FCd9iRCz=drA1=}Ci4aU)(AJOj!|cR zO95^_kb^;NF19ZAp{GtQ6hBlOWy5zuOxq_Ri!t3k*u<7CxjGlL<f~!HwE%2#ZlDY2 z)ljmb8n!Dvp#B@haJn)O&EJl}=<FWSx@eB>DSGVfeFZdAlM;HATdFF$|3QQ8Ow<-; zF3Ga#;y()nw}$e{tK%%IxX-f{S$e{B4Ca24PLVvdxF$o*k}@u6K{!0M*+NRuW{_GN zhzqUMP^9-C>W-I$M(u+*>)1EWfTU32;vQ<=BhSvsNV2#9Wm+CDxEcc%a6PugpuhYg z*iHFHg+3)vH}VoKwX5J#M=WH6@~5M_{%Z(U%oSNx<=Pi7--Mfz-;#eGf|6pReb$K( z`}EFv__1{(H@4LSpS28PRxQOMo$+%Z-r_h_?jD5S<qpG!I1|{jH4fs#lUc~ifr1Mv zfqL$bVbW(?fJ><3Bri{8?)86p>Gzt<<)t6<6PydfFK42Qqrf+D9tZ}TJ=py&2R8m_ zH!NxV$(G7`vyzo*6ucyf1>UMbi+Pc}(xpJW^~?javQ;oKY(Dy1Zv?y7?dYa=1Y&m9 zaZ+#Q;-=>k*wF9I&G^*{F_~kSkAfT|U;hZ}Zzteqr9NoM-_D<VSkFuPwekIP)v4v+ zb^6!pKo&QavF4V)u;IcpJXNKOc6<Gqa;`cC#yMcHsEp1|auD)wAE@W`bXM!PfcC*n zW-rWsUj<jt?1l(x7w&1$K8g&5cOxmI8=l5$!-)sN3_-S=ItG+unbBFX#IQ10DwhZa zo~e9gKp*Iw{Y&#>%<#~_CuF$vIV{qD2CGNMlEKrrH1>Br+#PF(Nis87k?RD!dA=0} z58cAK7FAXE87kxIx@G)il{egAw-6Nh%fW$z1}viEn<%2A0tJ63e3Ki2r|+)9dSw-? zN?yiPRdrD!Ck1SDo`P9tHZ31#ii<0jLW9R9mK7Pvza3=DI_kdB&6sSs-s8<T3E!BD z0Yh+S?oqhoZwod@Y;fqQEPN7RjQx_2L1W;3P)ZCE7;x$s`qq)@e!R>(N3CI}!;D#@ znktj2kYm@~gpBx`#iUiiVd#q;)ptGK!@_9|WT@OMG7OQTHE+Me7jXlBe*GaXWAsYs zlWeE=7LRC(k_~AdmZ8q#Gf;Q82vzQ-a8Lc)1P+!e9lWFskERVl(Qz&28sW!zj*W*^ z4=%G#fn-Z&hwY~vxlCmi0=swgGuklNoHsOX=kmhzVd&li>^{FA=*J!Yuf{@luX`w7 z*?SK{2Pb1k&1U*q`Vg+_RKT+Z5qL!@7&87yz;wlHP`{4g(Dfqj>BchpPx2AP72l%R zcLJMdUjrx^CG%2^iHy9yP;%vJO5D{&@u3n}=Izc!8V^Nz)1?%0QI|Pxx=h-lJaiuN z6Po8n!<j`zw8Wr_-h_@r>A_y?X!8t;>m9(vcX*h+WvIiv<H{(%;0(<eH;mrOcSG;$ zi}34EFG*P(63)$BY;h3!KZ`C=bk{?0+xiaN+PulxelQLyPr$OLhT{M1!>MwxH8YK^ z<aVt-1G{_$$8G^v-K#GYHiHg0Y~Iv@<E_-$3!B6AV&8wT#C|9n+9OS;mlcxsw|=f< z{5yNKs&B-v8bCi>Bk4)B6RY4avQdVf%(?C~F8q6d)hye|6pGICiyVH!3Vk1X602LY zsKA(6e)Gna$gzr&$(XghzuM?X7u@X{joaUE#8;6n{MUCKRO+gQUzY^2z;*NK)w8!; z{Hz|3rfT+L*jvc6XoncNMovqzh%0~A39_1k-}~<Y$R9czCp>y0>~|l7VY&G%us$4X zePnr4ePjAueh>>wM$n|KwhZQ87x`~vl%2g1)&-6vM|%a<zwQJ-;qgtp%q$t|o}!PI zg}k3s8Iy0Y=DP11!dT<K+|^Y-VAElHR2u6{OAoDK$yd^-$9fUb&xN$s$p#;V`C`ov z2ROQI6KEDnvsuoSB(vxa1di+D;{px~ZrT`ok)98R=|*ASu~4zn`SGmf=53mJ+XQ{D z{iKHh4;=ixcd-8VhuF<x9h@q7?J!~r(>z?kJ&e<?@$6M$2M0WXqTOe}?&fibmO8+k z>p${F39_inz2I2XP<oxv2b;1tvv*JBg}j{=*VEk#s@p%oqz{eUu>EOhHLe#A57eOB znN?ir^#Z;&Ck7g(R&iU0ye7S{3UJ0BU~(^!H`_CbnieUtfOT6yw~(iU%W7fCu`>dH zW<9xnxekWPXGG7+XVau%r=WL-39VT!39K&@g8oXw8nwePN#sF&e-*HJ!Y00diZe@d z9S_CPZgA~~JgWbQ#_i(aEa=x5fZh6RY)1ol&d-G#i_d|1vk_+6Mw7~#3F!CVRt)l6 zg>!Ws*{4j7Mfx5h<HRs9{*Wv%&2y+mU_47~+jpgIn-`R1rLcW5Zou7?M%fn&q0Svx z<j?6`zNmqQUXMqi2x9+c`?IVh75u(y4vYKrfr92f<PG9H*qCS?C<zjAWqV4f{@q}D zzrdCrXAHr46O?NzgL7b<xeT}S$~X+z|A1W#dJhr{hM~o?nY1t>2_LEN01aW~Q%Bi= zDRLaMICq^uaWuECQJ!{a%d$rSJHYvK7<Bn<!rM~^qTGkGv`C~-V-*@H4ph#kx%*6U z)W!8=zDW@;#mvU&qY~7l*u}~167s>Fi0y{qe51rG$nVXesLVN#*7}Opw(TdC8bhjk z6a{}D^@I4zKkldWc&6)kP-K_yfrqyzuvnu3Fx>b)clBiftGtm4`Txl?qu-mc{;1$2 zkU)M-c>(OcEyD5L@1ggc0%k_qgN)(;rg~3c+<qR6`iCCy@_REVckz8Z_*-yF{#nLe zmY3pO>6vs<*8tATpGGrVArHCqFCRCxm7mUUWl9xcyocb5(;Z+;qbBf>n?DayvcHSp z&iu)B^Gm5)E{IJw)W-!u<KS7dlH&=xOXN7zfxux7J)Cu&4g4p^7g)sBWJpEQ9;l$& zH{;pa%1?O9DG{VUw2Ov|FT&ML)7dU9EsW4HX0ArR`0`()G4<Fcv|48aj$1##{!f#b zQKvhtQm*0$>`OzJUM*}q{D^BPJ;|I^Rq_5bJKFMnp@<y~W4oreV%*^baPYqlKix*+ z4*OKFs|cjs8%w}p&mwTxtj_13S|RL<exVVDCuy5PEX@-3Vd5GDrs3|PsEV(ttzQMd zE_OnVH^)$9Hkk!TEMvR<RPezk1u`;~BBdEN%=fH2H0Ar^E6sy!jG{H`nHNuT6Pmy? zPm&sKlkw0zV{mda1-;i-0p0~uv)Vc?JK-6O2!2lQ3tUiTsD$txD&TfKJi*`G-w4m& zsk8K~?{IwhZ1$;iKW$5TMN;{~_i^}bdi6+PN=berl{;Ff!KIV$u3FksEihunNeJ)T zIVzoZ0e&~S@S-iZ`OH4X>ZS5%@HJuXdFLi~I>H)d&>k|?gYn><deBu}BJTbAi(hpI zXxwijXesugzegT`=u;)%_az&=^Hp)_(;wudRW4Qv9f=8poY+zwZ925IlKf1qF<zK= zscT;ZZ|_+G3)7bmX<SCZ{RzynEf~(dY=R%t#B{wkg^wFJlN;mJ2BkL9Ty|m?*~M0a z=E0k=)Z!=55P#9&rn_A1pl2Z3ju84g0b2(?0XKs!5O&9mqVo^JFLiTr&DaA^XEU@^ zm`C@=J!gh@HVVDcXO!eHmiZ`+qez3}^xG?y$~tnvZ)7~Feo26mNs_|v?}E+^3viBz zq1y^qY3r@sO!7n|^t*bo*7TR$+eudd&WsdEpV$ZK`sXl1W<QKj{>`6UBSS4)k&f=z z$a3|1Y1e1LcVy$hl)9%tsiq!EJkW)O%pDh*sbHm_1G^JHn$E|bg5RbmNHS|AP8mFx z%(Mnj^5m)9(xCGo+b;(-T59AHR4&?+e4W;mxpLEz-a+)&M0WJ{R`h!C94^QYCHpoj zuvNMX*WRU)_pJ!AQg#>xd#LdXvRZk!=R5dgH@nDI+Xpt)wZWr}&$#!U0yAQLGr5ZT z#Bsj^#0?R(5cOmomYi(i`sC&VgmKkZmjz(kOH-WDw37Xrn1+oLw}9824vcah#N>^a zu&Gwt+35Q*tXI{Z48rtLSLGEaZL$y@W|*+-mtl10tS4$$PXbr_Q&7HYB263OjQ$3B zP<I_*Xsjtp+s~uh=MvD`_6sB=Sx}v}VNFWw8~#M83v=4_P^46QjZ~$)@z1?eU_bdU zZxDI{W*?KowX@QwLC8<(j{9lfblVhvZS~*}9-IR)^1tD~#yNO*(K6;Fr$gqlQ`ubl zLzQ|PSzsi`dalgj)<lG}XE$X~<^5W4PrE`}rWC;!jo~Pvo`f<XCg?FYf`#fi;w-af z-sJaG41VB+y#rM+{lHqXsu_UFHwHQU5qiTpw+h(EJy&2^W(;Yy&H^_-N4k;skA5F5 zhZhaXg3Gl5He9pDSP2y_L@tC@omq{or(AKm?Ho*=DMM`7Kk6Pc2!G3d=2yN>1gl@~ zL|#4~<T|lTtZ^s}`uv|z;P+IFOVfbp9RsP#Ltrl7pM`u|2iw#dLmoYO^zp?(QOGB4 zppr2Amcl>?d6hxGhI9)%l%ugF#}WG-vcb^&0WJOVoO{1hl9k=AWXn|Q=+$dAo-Jkk zv6G>Ex0;H$;M@xcHrb4_ZeO{F^L4qbsXy!u`3fo@=ZG>YmuP+qlJxFgNMHJyQ(RC6 z>89tQ%|Rc1FTSAmz#2MWJd@j8Z-|l)&QQADKi)H98XLOJm0fk)39=_QVr%>X(5o1O z^OH_v&~z0Xq&yzw|2eSlUOREqA9pryM-H8ND?Dd~9Ji=GhZpU2f>}b(Cd>PzI4A2U zU$54{$40oJi@-mgu^DlyXeHZn@T~Z~^ekaVKow&&SL1?z@95HR6)14&hG2(5P?<W4 zxvkkxCU;NpRZGv)vxB?X!wN&1JKzZ$n(Ko8lXW=#p!3xIcL!V?<^%Ut#zFtUYPg=^ zOJ3UAOn4PhqWpffg6JX)DKQ7toAL-V=86+f=W*JWwa{REf}gT)9C%-PLM{zIIEPgQ zAU#Y0bMCz2-n2dEZN3WMrN#mfOKl@h?;GOlMaZscEXLf@bUOAy;A*ZgW5@P%iuy0_ z!fgxNXzY$fsP?)E4v9F}ZT^Zzlv`kQqp{#k4F})RKX?_11Nc#~PPAY{4UAne1{ziy zf_sq)UvtOvs<VL)Nvpo6l}0)kr!P%qw+FLzJ};`L#=Ed*DYBSRx*S^PmP1@(A|CS= z;f6~BccR%9mfM^`=Y{^H)sP1D?d33hf)PKp>^^x{odeU@0sMtOuldlPtteJ%g7%q* zz-?p$1>AhWf3VHr%|Gyz>S~APh8EzKvk!cPGq%L(BKe!^qsq4_*n6vo5BS(B>UKXW zw(`9pHa`}IhVMqurriplz04Zk$`%l)j1a{Nx$D=DKfnwj+aumLoZjxKq>%fL%t$Sl zwv1K6=&cj@7lMz8IXJLLA=mf4)RNsZeM_1LlpWMYhvS$}<5*v8tH|9Um&{rvaG~x& zw)K=B%aKo|RhMV5y`FxURj(~RmoC&$6INq|MI>HM?}B7|RUAF~DXRAx!H<4lFj-g3 z{rxr??bZrCRC#H<d+jkz?K=fGZPwF;&9T@&QV$1vn=xhmZS?0|BdH61b}N@sI__RZ z`!4>Y91Ryxnzb4pofDYAn}V6C<x;%-MVMutIwoYx-Pp1t18`x=FLJdjsx~Q)U?5Ur zxy!QYm#-2%Z`=i&{#nsHh@s_eMey*_c=7AWCn4rhC++)i0^6#@F#XsD3O=Zb=Qm!4 zA;0=z!j)0%;TuCd5n&CoV>glRzqO=P;mqe9N+Qcc4ZQDBeF5(x_?arrDafBgr$xP_ z)>=(v$ELy`nF^lQiG}KwBe7<C6*n<>Hj7!`A>1D~VeRLWqI>@=aZ1J&Xdbpz<diam z6<HR6<+60BH3#vw`|Y4~vlG^-6w(0o?d<Eo9dN|-JCz&}yxONZQRDXQ;A$-9?`R+A z?;h>p?H}9XiVLMMu;UKS8|;o@e*IuSQ4X)}`j18JvZA)T`q*{jFX*jY!G<kOqdawG zCcc$QI;)kL%i*&yiXV?}E3Z)Vy5%@`mK%fhTK2UIQu)vf2Y8yWikV-%&&@F0f*+5( z<0XDN@FwH-u<nWsen-kKp)NRu#zR8s=ZWXov?QEfEE$jb6LUnqt<ALR)KA{c%>eZ# znBmI1q3qTWOZI%$Pk!I)5H{_AE42Ie^VaQO$fVv6W?VeRU~?NkCix6)n-fLa=IStT zRXq22HIMEa<4B@L1HXBlrEynH95zJSp?}o~Ue?N0)bsibv~o+xH?@m`EF)RgfQ=Bd z7_s<5HPs9cpg8|NO0fxKR>7L$6T*42Eo~~ceHe_pGv?#*Iknt3$tH4q(n<HDgy-+X zd9FM57QbfnboSb11pBEz3WMjxVB)&*5E84&m9^gh$yxsJ`a~SKGztE<n-OgA$s^d5 z?TN<?6`9P-La@jce*a`J$eKMT*E$3K;3H%3ke?2NLwxXaurRyda93QPV89Ch$aA07 z(&5EHb$)5fXdy!%NA9fxo_b=GL;uS4=)ItZvJy{F!=bU<-`p^gaf~8!r!3|?OkgmC zHo||FT68pb8Fbv8%$~;hL5|6OW_LV>9ln=<HsSl&w^)B>Ugtpm%`({juM2e3zOjy< zwshmF5xQ+fw$D2T*Ju?}*C$oXQV$pRe|5$WRfs9(`}k(d*I?3Z&hp$-d5KYrMGNbM zdP3;{yQb!k&S_V;bUjNfNdL&S=bFHz5$UYmXAaW~Ishso9WeIAPA<S8fF;!~!#@%) zX!iYEbSmEkUB0C9x6f>3c3)e#)Wmiwdia(a7jP^k^(htaE&}*sfDd}IxcjF=X-WPK zTB~TqLU*g!kGVUKd`7GhNy9nV|Jnsj1}JhDH(9eQS<6W3MLbDW_X&BEQ{*!+n=82% z!^P^P&}CdihYVLk6g>iqpV{1&Vh@~Ztt%9aKe(Q>v#6U@R;^Yzi(lJ35@H7}XA+Z- zh%>fabJ%5jg&ll(jco}%h`+sk&?aLx+jP~9qJ}lH{8JxksfQkx=X)XF8wtY(m$09O z4>|Ke({Ql+2ku8i3!L>dK<)OQl$SM{iwgFoCr+n8wonotdW}J=p7F?rn>g$^5KCj! z!XSOd6fQ6%AL>h`aJFtD-*zAn{z~Xm{~rbBx^n@4vbu|0H>wI;Nja)MFZi6r>oMcy zESPvl5_Oy>;p<N(%rx>SKYhqRD2uPA6VI<hYsLaBeX*DJ3AMe;j|u3Ruz)>$v7ecb z@1rFGGc<44M)ar~j8+OG*(!A{dfPUIm0z91qRLi4;M7UzdU+8p&2%7&JPz3{S1`8n zD1J}vh0+}+tfXKaSCX|7ii34%$3PbrS~G}`zM_Dux0_?`Tou+dK9jc=^?{Z4ZT`d{ zSytTr64neE!~Ewh!Nd0XOtStAOBycZ#V*7$zw1$~{ZuPBX-KjTt#e$pnKG&>b#h&~ z_H5fBXEwcDAD0gqP*aenz^P9>%^5fA<B#M=EOTfGw^^8xK=X7_{H++Qoi~xY>*NS7 zNe{`Zn`7&y7SJ-84fxQ*h!x&AK%UYaFn`u|nv9DOUMZ4F{~hvmJ;{739*eSaE5zqC z2jDH;U&MXrfxv?q&>-ZUznbXtHP1Cs=fMop7joII)5q{5ze=&L{|4aO-36@8ri{OO z_%JcqiReAT9Oq|8P~4jR%wb9@s27gGAM*R@*sM%wTKk-yPO4}A))zUC?fNWW#1ecR z;zno6Yv4uh3vSnkCFm0$h)+L;;hN4}wD<OD(ogi_jOtY}MbjDv)s>TlI0s$&Zc|Ce zGIr2&6SgUb&<o2meDz{6u9G-Ka|BoFC{HO2KCH~{%-bz;`)?#`P(L8vD>DxKS2y!r zP6`6gA_{!|6Vc4!t69}BOYnD-WHZ*wIDTxsN(H|QIGxEdO!u%S^Cm@-SBR*o`^&Mu z<qMcZ`6M=Q*bI!@R1JflJqG{l&S*GKk=-~MjEjyNL(^bsCNujkbY7{#%&+;7AWWyv zWJIwzpQqeOlM&2i_C6dm;5rmdVBFO4M_BvUiFh>12#Q|)rF+5KSoO04w0UqCH<U}` znQMzNZTW0GzTOQURqn%YxBt<UiPltA@5<8u{G+$-e*{Ox0KqAF3?8g{$CdI07?)zj zmZKfg%?X%Xy$?H^;@F5Crh?<aoOty#ntd#mx(?1_8b9`fX6;d&?|F#HYoB0y$4&tm zxy`U;g&r?#JmH-`aiY?Tk2%{SY0Nsb4cNh@wDfs1zsk#u+p)_DtVWo!>^Y|?c9}Gz z;#!g42OCy)OB$#6iCDFv4jzx2#&m!GfigJ{;<O*Y!u~9(m=cb=N|iX1Ta26(1YW%S zC9)cy%29)nNULWbwMo3@H!mGn^XkoTCOb+SLcMKyg9pFB%t{e*BvWxwK{BSq?4Zq# zx<I|w;*f8%$SUg;T``%8(Q+^N&}H*+d+1@%cAv#gbreuh)kw5UAv*FPg)_LI#|(dX zW8T1gkp8?Cjj!HiyM;SSc6cdm_7mn#PYU3bVJ$pJ)n#$Ng#AX#ZkQ9C2eSmeQRzfm z$_P=wU(W=`=DyKr@SzK?yctV1Q}05gcNEa_u}Gu6#S2FTfNfSY?HKZuTV));nK!)Q zRvfLz%>|b1+nQDE;+G&My*Qk=%v59#%ce4=x?-_ceJ_=a@Z}O;`tv#8hv2NOneb-d zR*Y^oV-n{tSH-KOQu6j$^vHWKj-4OL;t!g@g<d)4BS3Il!cTKiu|>FhwJUb~JVG6A zAMF=t|KUTdlbF1rBs0#-pci8l$?Rf27`kr4%3*3OQ1vKkn!kh=vp6<8tCG7ZzYQny z!Ysuv4u6s-wJR;>ls4yr{$eX!_%M!AE_@Wldou3Z3<*r?za(US_k*_9K9;vP6h8>{ zcjAIXKI8Cv2o&~loRUIV#+gWPYyUwWUplD6OpWSY?F9zsRQ6}z3I4hHCXmn;GVZI- zRu}9^XWo+$*2U?GDudK;m#H868pwlN<|%;@ZXv3xDMZbUj=1WSEK_>88kdef1_55h zSovF)P39IbZNU+ho?gV>f11xUlmTmBETN+2dTzb52Xocdhwk6!xYFdqP}5|JPoG|f zR;^(e_{tYPW{<>{Fhzd&!~o{HsZgxxI1{6P<<c^KL=DA%=D*n(v9Fh!LGjL5wpifH zsD}*16FFw=byqw@t(<{<bux6QHkCQYwDZz0%b@X%F`KI;&F)4H#E^|KaHv^QU_6<# zDn6C%QLtpUlFV6<*+kZT={`+TdC$Vib>X$L8FsB{BOm`Vk`j8!4GU{gDPt&hnF_p5 z%@owNtQPrScEo0Z^(1aJ#M0`^G`Pl_v#EWH-V#UH+ckmAjCbb>Q)WW=+f@|uVJ8+0 zSj$?ZBr)1WkNKUH!q0bgFuEpLY&zKpdhhMRaiU0Jy72)*O-72XcIA-O^=(+Hegopp zzkv8(-IOuTkhd!N1TKqaaPRjHVbqq75rfu1>9oUeRKcBDOBmv{p^5C$dM)Ou)x$s2 zxCtwsOvKBh1vh%}UTU+wKq^bLIB#7c7j;q^NBxrIqNMf^%&4O$8(o=nLNQaD{Dgvw zJ_}w!Yd-T!7q>Fv0VVoZa0zV<Fy(I*xgLxVQSJ&-skjPZ^*!)qincJryCClBmB8qQ zCt+H6FiNhe0e5x{GL24<`HnFx@A7xjIh2GsW8CQd*dfgJ%_^qxPLf12(NH?~GkhF< z01BUXK-<*$cxA|Ry!3kr{@Nw*Ze`-}itZ5htx-bYt$X0Fv^e@co$<`h1c#k%V{;u< zS+n(e@YD?EL-yQ-J!>bi_XpFlcw;^_r^bWpI$36<JqedY2z=u01K>y5HON{o1-+kJ zz-@IpGfItS9q-R^dYTj9->wk0${>XOTyd10S}_9GoKeB}?r1)-Pnq^+H$l}y3pnf$ z3*EM-`N7v)>EpRGQ1Zo|N~jucMNbFc0r&ZqUm7gXdns+3QVcbA((Gk*4X-l1p1afF zi0?kfLz6fXdNOmNNk)Sd*B^&#Nx86Q)h+VcDv4iR4A}0AL-GH;hrN$};^X#<?3?Kb zHt3Jwa-08+{5*aGNLXX<Lp^r9F^zk7^**GOoFeZvw%G0^?0URChQUocAaj{4M7(^& zm1bp9R*b)pvvIpRbygFZT7RRc6Gph^qb_!<521&XYG`>;8I#Qm!Xv!E!0K1U4W{GJ z&A=Qa%=B&FYU^RtksOqmugaRN|8Ql;H-U7&CsbGD)8Yp!@lBcvIuEpirNT@q-9VBz zGiv4!-8(Prk4d4Tq5(6VF@(hiUk6jY<De9o43`W4LbkwKpQ5)NKVF`Q%Nlu3?dLJz zDwNpB#|89h_XTu*(@DB_8fZ#`Chb4<gL`lDnB?ZogHvAdc;Js6HrzA8;d5+gv12By zXc*7b2K|HBoK$Ff&y#KbRMw!;NK145nbQY>7r3ent34_(wq+>$e76e@e~cD(?I**X zN4{*nzA>9#B{(5>$}+9o4=^rp0M@Wn2p_MC#djhx`l<v)cW>aDGFs6@`aBrxE1}eh z?M!>Q7`!IwV98B0YWd*FX*5T}?)j1QcHKgpXSp8>$8TWXN0w3FIb}X$&SC5;6gU$@ zd&DK_KSjrMrSbE?1WxN;3IE48gUKZ1;G%dl_GU;0HR!j|f2X5y@X49Xq1X-m?!_^c z9m*^q5NX*!Rj4^^MU$ha)82DqDWGvRcq;4Q{O*tN^7$_k$2no~kT&jBq8}|hc?`?0 zq|np!iD)VC3Kb2<(aurXz=?m**xmbR(u6T|Oquu)BV)E@o+a!HPo!y=W1t5wz_^r$ zv`lg|OPsio#*EaVqf3i`ixjvzu8(-BUuyJucqpzp=YnTjB4E*kB>bBESeQ!|(%6JT zqN5+GO(SoT>C`;#ec(M9<aP&)-l{Q~F~&?|`yk%gVmz6=zssjCKL_Q4v*@qr9JfSP zsBb1MWS`EBz&jn$s5Pe=7gz=0!ftt7H#R}M_xKF<R_QXGEmFeP-(TS0KEW*!mc%zt zs3$Gaa$e?U6Ftbe1}pC8!mHgUx#_P{(cwiGEqs_q3Ck~0Q*9$mwFqT)jk@ge+%5Pj z>=+1Vhd4%IBa5v{fb{}X9M;{!>ndhcGT|b|?GK^$uUoL~oGd#Tsm`K%_KV#2+=q|r zvoU*ODbpG$^sHCxfJ6E`3+hb+>Hma$%=Y_SSL_b_BQuH>N6V9ISQ^z%lcnK0nh?7o zoBuVn5MNw7OUe2p@LPonJDH~Ipx`_W$NsiNvoA(mZ0KTYJA90+7A>dAzRGN-vL+1r zXoBoTBk6jqBIo4uG`8XkP1JHmm!~1@%xeXldG92s>xH4+^Lz@-c>*QUnPi#p5TfjW zwKs<IgSS~QanDL-b$dA~cmKeE<^;~C$_{@NM#IvPD(t&$73hZgi*)RoS>35B%(02W zJhM?OTHBM4pF9Z@YqoIr4j3@0_r9F>L@gHleLD7a7vs-=_n`mPEX>d|WG-Qr__S{~ zbgntW*I2r-Roc#c>uh7#U=;6AVl0ILg2&e-I+-(E(ZX+gYYj5q4P5Q^ZS0*e&skfR z2&G58`5Ev5biVCovQpKs=!hH>xNvm;?hLfpc#wYP?PtY}2ib%wz-V28;d(cQ$ycwZ z)r$9^C+-U<>7T-9|4dkscnKy>Q6ZxZW~i1Mi4Q@CwO3?uB?bPhZ`m5o`{QHIbC?WN zT5B`M8NyIuxd+H8?8ZAors1i)FI<ja0^9C=fc?5M0j+|%;8w+K*!5kJ0`NEJ%@S%1 z%Zcoxsc?_Vy$NY6@3MyF-?^Y1Ss|Bmnz<BuFwl6w@!$1v&yaMe>pexoEs|h;#UR*n z)rQ--eHU%g(`6+(AE;Q)lvYV>#4{;FaEiY%*&pNB^$mhA=9ekDe!IqJd7KlkiM|F~ z>lag^`4w6g=7;_thv1mYx8R89evHWY2qwd_xMP-aD0TY-m#QU#>oeprI&cMZUAJGP zb}8M#&wl}%8+DllP&m%33dNfzm$O+C-$?SnT^2O)EX?I>aP6jb=yqj2*`GMVw7(t% z`F4G*%&H~-KoxXXw8m3=dnv3;gZ(i0L<)Yw9MAoVD0!y9(pOiYZ${s+<KP6AZIR6> zdHO=2q6Rv}gyIAB1h}L1m5Z5NPZHZQ?XS0OC;9bFB)T~a4a}_ImhUwDx92*1*G@+9 zn?_I#Hbm<If{QIWmsYsXfjc`TSk#}t(7iYd8v;7XtMeCkW6gBjT$Rj{@~zn(DMj|o z(*do=jYOY?8@biPFOlwlm${tHQtb2cqpVz*n=QB(f^VuMuyxuO@X0$No)a34y_LfK zQ~ENte0{>toMiyNZmohTabozSxRLSUZLqLwBfhm9D0rkiMQsOFSk8b=5co@;Ir*F? zZ?=<DbehgeCf$I{OOKfH*Er^Mx&#W7vzTKQvaP-*_|)nrNt}5tIz4kYo)h}j@O2}L zvJzaFLN?*4%1`#VU@}T{oT!REbr~iP>0q5*`^oC`WylN4q>fKf*q~*|LJKB|pUMjU z(J#@=^Ggk{buS3lyvbl0GcvgZpJyOd8O1{C4&Z#D?wOr;l0Htc!)@gUKy#BEG`T<F z{T6re>gw`f7rUFcRBYp3KQE&FZ#rOZqzm&88;UW@BPs0NX;Nybg=JfBvYF2$Ny({% zA}YPG=juKjwKpDCI&Wk5&aMQXD-DoQl0_!ft0DeX4aGUevWI$CpeWRxK0e-!@lR)y zlKEoJH`x{B9V9V8t`a{*72<^(V@bM8pNf_mviAP@=+`}m-e12(cjgIh=i|@FBi@iT zJa`5Up<&P>^srU0KESdc3e3S~KU0ewgYw!b)X}ztPrCMw4_HyaD~hjk>2Cxv&8<3G zqu|Ar3`yZ6VnSHM4mYZva+`)vkaD~zr%64-WianXDcRC&W;o_J#1BoXaXj&kUL_XO zj5D*C?B3O2b|nuM<R_rchf(<PrUo+_?uQMt(%{6mF*GSs;G!Rm#$oD`_~%$L9&(Xq z_1dHPsN??3IZqE4X%)bo%lA0vTp#vlwH>zi=fj_jfvoRIEE~Nm1>NS?q4`Z4be~lT zDdzEbNY4c08l&*zQ)woyYa!QfdaT!I0Q21xOIv!6+uMa(aa|FO{L$gY4!bQlwry}f zC?4~Lfd$XeqdSHr$c2)2t3Jz@;_0_Avrwr?C02D5Bsp)~=$g%@7bLPjqa(S*P!ssd zKjf9a2jb&@6_hhqIR8vW!<%dKacT5^nrGfXUoM-2U4a#CRb9<O7vCj^oGCPSNC`QY zuVMv_8A4W5ok=ed;h>^K8dkFyrNTA}cNZ~dB%V(3GD%o8s*)>gdPyDXk$i3K0Jhqt z6sndCCfZSM?_d2KR;9_*WL&+(M$Z|Cu*SW*^|2c+wf)W?a7{+{%g1o$l{d6S90N*c zyhIAuRLQ5$fKMOqiDdIu@F)F0uQ!IK*z9ByN3GcUbZ@j3nX;^=<JI@NHCV7i9`2i) z0RG`=8247LCar1)lzmJh8>NNx@MomxiGUT-3$$cqh61;8W(-(Ow8hx`RCeHRE+vi- zasx-w@T-j)-W?>&`gaco;|E)y`Qd%8Jzz8{@l&b8DMqZe;uNo&aIg9$6Wp(vYoOKW z94;;WNirLxSZJWY#uoOPy1<S(Ubkf9<rzu-sv-Zk>h$o#JkBI#Bu)!d=LYx$q5jD8 zWT`oje{X9=wJArr!X4`P%&3Odxya*$r+IA0@paHH%y?p+>;o@84pk0lGS4#LRiYzE z+q;vthq;h$S~#aQC>_?#UIuB0BJg;pAA2yj4#%!F!K{PZglvwZ=!vQ~hR9Yk{=q!d zT_wxPqf0^exNui~u^ekCkNqCMf+K@T{O1e8vu-c=A-pbvTS+$mt~d!|j>nMz>#mye zX%5EN%cIlpASN;33m5Jn?97~x;6HsZX7gQ3VIG^qN)~I-kIq8+Za<K$HjDtLowaPZ zP7b_{NQN5&HBrUI9=p`rq37&jPWF#TbV21cntkxXAytAit~Ujp>OO)+h$E&rDe%{# z63JhogD-ko&oVFN(qG-LFnz5TeRj8{sVh`js0mLN{f8;^$4MA|?FiVt&xVVIXSfre z30|8jVuQ6Wr9ZvQF7*1aD9#am>qDv1TB2s~lIdjd?;QQAF+`Qgsx0Km7_`%{hTQ=T z0_WOGaGoY%+?vZ=Z0#IYzr>B|hp*tEMUQP-m&QU9r{OM#@ld<BlPuSnvoO&?7SOtj zipPhNe6<IY|E0^q)E=^YtBW9Sza8Bo2C+AzbV+qXg5Z!S!1aFLpmD4Tj#%4-d31~S zluyO{&_1XiJPIXdpRhAL(k*fpRpFEmX3V(3g-IFw<Kv$O!L2@ZcCPz8az$%ckcU5p zy;Wjg71zS!E(83O7)Ze_JGfQan&??|6isO$nk@?D!`wYcCS)Cso~(x3Y9?Sn{d3~8 zqd~H?9jGsco1dV<QdA$HuB#$!^c{dMo*gv$N-x;eWV64o6Ihj5Ew6lg9%lZUidH*Z z+48dwsLgGc;QzkCPanM-M?~xf<;wG9Bz{dUl8?#ik{t{4^I>6GtLOvjqF+iTrS4H< zmNt`^Y}YgjHur<F_ADx$=_D|^qD9}Yy@Wd#o#<c7b8g3$)1WnUGYsp{f?Y3?(0}+C zj2Qclr;CDyPJcP$myTmIeN)iZfw=k%3w9`f4ck9v1=uBB<6LX6ab8F4p?fUB2Z_;w z2YCaxrF%49P>W_-uUDXsQxq*vsil>NwxFZ3BRf?vn`y3Ehsp_+EH_A-W&B;j$xIaP znos_LR(T||kll-;&p+o2R)}H8Gkumg&Iv;<o1uhWC`bhfe2t^$L1(8KZh2h9erhPz z*!}y$#Yr-*bW|3L)GB3T1b4iXts&-1zK1E(b9mR~nj|CMj0JN%*zJzdxXWGv0=6Z= zS>u0@*&)lE1U`UW+*OVq_mSc|fxrFb38{ew?{{f6^X{F*mXD2rn@6VOM{QyM`&bd* zyoQ4*;#Asp-wY~+-G!oriEQP!<5;yahN*2Dgd@A+aOxyUhau<cS^4%%)=Pnu)7D4R zrda}YK7xf0ESP-gEpYlKf(0ceI4&;%twhnBlXVvMU;95d_8hpBs^jS0bJ)k%u^3Tr zb9L2?GrYApg4M?K!iF#*o831VcKDW(_piIm;En^nI4~5<KTN_M6J~Q$+6o}PX&7s{ zG!i9-EWnOK?@55AaP9@?K#WDux8eeyIX4QXU3m!Y1);FnWB|J6KHv`84Q08l*|gVo z0tOWc-<BdXa`89>w)WQ{{?J4;*wzK_^cyICf;zs)ss)UD0W&sfVzb6UW>S8Smx{~A z??T40_kaq^b4}r+T8!Y|L}91pb`Lyi$;EjlV^Kf51PhLraW!u<SjZ$HyF0E3_H7so zgNK_??9?M<F1MNXB&M<M)8Q0ZcN=$I%fx<5ZC3egF+9(D!8_@hiuO)g!kkJRsqbVx z%Dxp-qSIV7GgHOqz1v{kh+$whZ8$2A8_!G!%VTovNBq82U2x-#!X)P$c7Jj*Y@H#C zZMl-dT>CbsTiGf&h`M-t^S!wCmk67dNARAsUPQy!ai`Qyp~y~;bu4<wSqM(%>#D;A zKcnEKC@rSsH~X37{Nv~x63)WT|0M6;dK#^C8n=fWVCMUc1i#dG(mm)%*Zz}bf2L<} z!xX18wftq^GtYu^9t*sgxzMNC{1}`!RY9r8Supk+B=F|LN$*@X22bdr0o)3_SN)t? zQ>U@MPHS3uWCzg|Z|<Y^aqidVTIv&cY{l{#u-CDl;vZH+?A{#m48F^MwfIi>Z!I(X zdq>>5uLTZIP$8YJBh-_;4AoO-;J%&|?AjwiN8}RFRauhaEB^4i<{zel)I18(nZfFW zz3vIILouiEJ7+OUniXrVWlFcA#MZx!*`Km)V5E+iHXHHuBTKjft(0Nq&eVjM+_9&Y zxZqPUhDzFDY+*he8akMj3oNg?+2hF#+Q6HX&@0%AWoaD~^}|~-SpJQBqm@9RCJO|9 zY8&SsCuF$C3iXd`7C%Pz1`SWJA+B?`@J?-Gd)v)f%&FsO>O2r5uUJyT9&J|V8wCDV zQK&ku9e>NEQuluzLLXgl#Yr(-6)VNuvklp$#iqD>eH?^+$ilea4XkH>3ytwG=6+~Y zu~#R;V9Ln(r2Os@934@Ot36FfNx4R}sX39XRcFx9TlMf_@+S@lC1duKtK@Ou6a0^& zGx4jb?ZR-9REkQ4^pZ-*l%xn}ua!`SB&iURDG6mvNRvu~LQ+YRqzIWRsk7HgLP8QU zRYF3@ocY_|pV05L_kNzW?)$nDx6UGiRDD~w|Hk8<S#vSx*hC7wZAO-c2WVw&0mRNd zL-p1!px!|X2Z@jAOTSd|nxMu}H&uj->m=t$k~#PJcwV@*G67<;g0Zf;r<iud2sM9w zl537EmTlN(#eJ46gf_1Rf`Ij0^Jg+%>HY-&q6(Cq48cIhTDYaMiYN5Ugr#@;!NFA3 zvX+&1@lm534Tp@B*n1PiCKnYfOzV#4jeNLB_k+ZaBl@|$66&-PaC7)}FffzO7n7#* zWy>ghGDV*UhNZ%|rURVR^(?4`I78H$1lz*tUxmNEdsrdTWxUh0&!q5aU#a=b39_~Y zOF1JcoXh@3kkb4KG;6*ywtdauwj3X--0)TSR2T^`E<hOSw^h{Azs>(974R#gBs8tb zfm?M?+2!I6NZo6Jze}y~`;VRIv*HY0-uWL2<HtczP#{jqPC$*v`n<&JyP)%V8wu~b z<6r;3V&kq0rOz6JNWzxVyxIET;8KVaj+S7Jy%8KLPv!qw7P1rBU{SFP>G5J1bIlIV zb?z^5Dy_M0q7G?%`wKHOd*e!>hSzng7pBfp;KinOoY^3`7^K*EdF*P8b+{s^EnGwI zH8<juF^SM~lpAF<D|3#25Er~s=F8>UJjvHynj89J!o`R3>gD0QG2$`ljrs%T<G+gK z!*2^4CFYX%T4P>Y`dM^X<%`Kxj;PsD+F!b-VD)RsYxOje)JM8VZkN8|{qvoK^%CRW zaU9cXJ&9-Z!_W59<;|SE?mC}eWrMAs3~=ppX@=7NnvR*4@r!K+V)3&i?6)oyE%zKG znWA*xY`hAS_HV?y^3G&1Z4B0}HbZL@D_T2<CB|VfyL{8eH(NVXgnv0GN$#`(2DPZ5 z(~Bp}h!jf_tA$mYe?Y?L5R6I#gbSur0PD!IY9-K%7c}Bb3EAxW0`;GYDBfT)Zq@IH zi~l8H-vUkSaBK@+IEVaeMqf5zC0yH4;`dwrg^R%vICklKdg0_O-VBjkCW$Xt#d$kx z>~Ubv(j0UV$4gzbbo#Pm0B5+R!0n4xoZj~_Pq6+1;sYZzJaikn9_fzFA7e=Pvl|aT zKa45QuHpiSgf|9t!Y*}l3FUWFEYaP}2laGO-**vOsvm}o<I}~ivpaD0s*_MZ(v_EN zG!j=YkqaX~`O+2lYDjH($m3jBvFF)3S>~)Pp8D!LS<P0%e~uMY{wR%F+z#M=DF-y} zlPcdg9?R!$8N<u@Pk4;O5)6G22;p1Wg@|+KS!FTGt0fL~<IL+~^!VLa7~sfJ;$$)5 z?qKn9KnR;Z?>)Y0@GiUnSEM~(o-8!<1lT7W;|?E_@zCDI^bGgX`joRczP}<~_E{l% zPEM06M$QnE>JJGju^zPRNHDw|wwDU5i(&84NFJG<4n`jaNUrSza-&an@T_+|Zwv|$ z>%#xgl==ne{bxSrsc53}_Wj&6{hUzL%NsPoM96J#1H%>t{^+uR6`xDFR{s|w|CP?z zn!!|>(hoFyU6$J^CBX3`g*d$SB%ak$CC581^z{B#Ua`Rw+hjAv;&-|nJ}v{jmE2eu zGngwJ9)iz)Gl>JUkz7|i#z_W~dGq}UZZ(;NE;|ZDvkks5^pz8BJ$gXgpJYJESz#nM z?@Uu>Rzco{B++hmPtLzMld|6o;O09mwi6ykg6`ci=reaX<*hHLppA7BJJYMo+<yS) zu1z4TKPnuQs|OL6PC~<)1nmD<8wV{l;`iGme$v<)@Q@Co70Zsmw64Ke;8qPwzE<Oz zu2Z?)V!1rg_an7sYhlr|y=2fwhCPg@^Ag2nSf^Ye_nqB^=QfwnhMv1|=ZE{4l(-O+ zSI&aQkVLdjlvoMp)?wv2eO_6t$kp-@tam(vHf(uEVKWqANs|MF*R_lNF8kS@P6^^0 zmK|{AeN9NT{e<e<a{1~X6`FcHjDNo0P4Bi1W|hIt!U>OCuv{O}LGm^0RA+N-KxZMO z_#${|B~elQ05q?Yiw0{eA$8{mapW;$G+LTM2i{6O_z*9cGq5+8_YLOMPEnM8&ji#% z9?*)AEqt}p3Hb8tBh8q47&~3)&iPip=u{CS>bG_TS&%i9DDJ`5YwJP%Krgx$+bBMm z*i5N+JEFZ-3Dx$jfy~w{NX-1fDpbLl_4Cm|ISiireS#(K>nSTGR>}jP#j>xG8~Am9 z44v@<Y!59ZMdJce{w7g!cLss`t#}+V^Z|MHapUsr4t#n|e~ew@%oWWJFd|%!+fSdt zIfr(E<*D7c$D~KuL+jDtT=It!8nk5Z0>+T@n2TWexeL3Lza*W_W_Ypd71%s>6Zedc z5hv{)hK*m2VnX?Rc($9saEpYTbX3G5-z330Z9Et(w54E+O;9#Bl@#3cOVcl$0}gvF z>{^wKDtb@JblnxGJfF!K758Kp3KO{Z`(A83)R(uda^uS6B)V6n4|9trVr!MFC|f%l zTjC8UXlMw%u{4K19-6SxxFfFDuHg(X0mJ6z@V!^nFlR{)Wej;QZ#=vcTRf~K*I~Oj zY(gG+TS*zee|zbDWt=d$e>oUc4~4l+{^(sK^^}Ly<K{exS*$UZvv2E=+bDbVK2y#{ z{}RzcXC|*5nFU3!RZ;EmLVPHB=v6!l;rGQDn59vQqoR#qSwJ@&oiSbba_R`&y7^f& zw@Md-zK5dC(m1T^>&|t$GHN|Gmd=OHBRI5#3tpBBx2~;W9oj@)Esv7HtR%|Tn+GX} zE^_K=V{HA}6`XHRmEM{CAtB2L!;=;YDVp`-{25BN;RgDc_Tezk`<{wFC6>Fo&t|OF zX%;gpr<1SQd8*1d!tV<-NauYe7|x6p*MBwPe}^Vea(FO}etnM0KOGZ>7bif_fq$@e zNJlalBAuOv|Al9Fx^T8?C4*BDpI4oa!^#>-6r`R069v{PzE4iNlX1%5LF`c49Zhsz z3a{ga@Tw9k((IFt^#dM5-l;L%J#r;k)_760#&UM~62m7azk!Tfp>mUyYC85|Ir|Ph z#!04Tl#zLr_6!}%FFz{rp%ER+uGM$If+TlbuxdPi@>F4Zy$`3U6yRp>JeX{mi|f}t z!WV}J(uSwUQT}iq2uc?4-fab>Ie0+$om_mjZX4I<YjCzn25CB^$dVj7@Y&aAa1$@$ zptm+?`LB(P#I7Q(RzYeWLTRI{;K_v5QttC2`mR>MU>IFGZe$uMU+aWjw|s=v@rf9c z*GS6^17M<32$aYRgpeUyc-J~5+l8JQ`2DO34v`(8-@!GoNU@k}zK3yR)mC}5(HOM8 zrh~ujX7f+QBNT8ro*phM5V!AUZ0m9m{wfGu&_|Ou4#=j}_h<9Rh8;BT_F-zTt$>sA zOVscCT&mQz=h%23+WSZioC-Sg?jx0;vu_3YyWWA&BMuN6E9Ii}IzyBF4j8y7PjsCU zfOc^+k?@kt{$Gi3a`8~M`!j@{%l2WF(ju7uQHxhj_TbP0hWZYZ;A}=WywgJ$eTJ=p zUf24dPN6FWBpd*5-)OF0KNh9SxBTF*({yi~89IHR!U{J=@oEe}KkE#RteVF59=(MZ zFobPvcfn{Ccb@q$2+#Z76fNz;z)rJ{Qid4ft{GckT26P|AoRp?bLqEz>x<^Aqj<2l zep!`v7DPC=K}JeA4-szhlB>$J%w8SOh>dW4_)t*rI4CX~zXSF2Y<ZmI67f_u77jF& zl6BPp%&s-#Cv&vX+;at-%K`R%7s1KZYW(+zpBQ+<g>#Q+bF-A;>R&n>-#X5QYOfAL zY`;<=>E2Iju>60XCI%b|1-?ByUV66n^ZmfxkR6eL`%+bH4LV=peKY5>r{{0_xv4kz z8ZnqKZ5FQBXwDd+hVSo4d4!CvI5W}{drloA-ZDRkw`XZ!?UiDfc<BllbPwYDmv-Xf z$^9<3S+5rl4UJ}#1?5mMQy<R;T^9mchVhh=B3>lKp`oXjj04_4yJ?zm|F|&@`Hsvx zdSlkmaX5)ObDLVEd{|N}G+A~-Z?TUsDd`d93l9W^55Caso&`PJZOFKX0f&!qrbn-r zqUZWn(p-6h8cX|1oxMW9<py{yM+rBskvb+<A|#&t7byDEBC$IZ<wZ+ecwmp-!h!2C zIO*_P3i+zZ)lFvPR}u(Oe`-XX(yNf2aunmGeb|-L*;qaNC@e9G;~tHw+`MHl7>?U4 z8zPj`@L4g!+|Uo=&fC%4daMH{>u<;Iy$|5?kGgzq?mNi%H$*=FNe56~Xw7ZI_Xr_> zui)0E`K0C^itELZxZ_1MbkR_R@BjWo%f7LEwVOI_o%{}GsCL5cZCY58bcKC?H9~Ox z20XZVB%ABAOz%@2Eb9^@<mg!AM)yQ~z3+q+$&uXkE_JX~b{7-BL~`7#3DojH4a!a3 zv2NHfdgFM3#*I(oDZh82{*&DttESC6e+}fo+phTT_5nV1%mMc=8_q*ME*JB@&*jh4 zp9qct8+c)NM<}a34Sp+bNFO#649%7Hf7e5yp)3KO)Gq|56lHOw!cm;%slma^LvfDT zb=v7Mivv7Ngx{<0i3U%-pf>XqB_&DO<zX{;;Mp6({a@z%Hn=+$e^O+4dw+bD{2?`b zjN)d!I=Zi^hy%Z$5_-1Zqxv949J|dFh4V@H!t|ohyet*z_yC#xxa%@=D?|Ad`B!p1 zGK~k0^ASyM9fee@e3*B97<UMoCUpmix<`K}$F5^2A=d%3jCWvhW17_YS0d$IVZ2t^ z6xv_|?zRrbJ_8hR-_K}BQJ=*=ledYZP0msKj49MOF$jhfbZ6hAx|DvRfvVHZg&h`M zNpamyFwgi;uuXjm_dHecEww@S@3o}xct2VG@W;XpQdev1O*WfqhvVZuLg3F1w0Z*5 z7k>q`)!2_}*VJrdTasw`s#$pKWFM~V{0d(=ofPBLjCtYq<9PUG1*j)x3VAUiw`4yR zbN;F0;}>Vxkxju_SWl;l?eP;<qDoQ^G`L|a{O-_|_Zs-IP1I><ieC*M2ZW%)Hv@V8 z9Uo9giI;^u>Tj#`Vg^{6Ps03OdfYSa8W~IMj+1NDF-kXv@}6cv@>UIe99KjxO=m^_ zk?GQ|GZB)558z_e7|QTFIliej7A$_Qz-j$<h?bYbaM_j_@OXX`U6&ZaW-Vp#Tj>j( z)bn5rOOejHiMXU~lNhTIi$kOwWlMW+w)0jLl<sDd!sa5@etQPLKad#m@(@AOE>(uz z_X(3)&%(f_UEKEK1Snn5=G&vPA^F`wOgkDYDl9sPjY{@xeKY`LbcS-DmJ{HqSInO; zsN$`4Ip800!1mALg-~W4&Xbgi#6@2vFIasKS@;Z1toc_+JECLx^NmJown!5$57fr6 zRr{H&14)0!JxICp0velh#giAVlJ=tOoP0{;+mjEY!W$o1;`R*gS+fk@JP!fc@N-yp zJpmUbX~F$0eGJ}NA;AknadLw#K296P-klo-ivtcET5pF12Dwl@4rD+414(&o9z|W$ zgJW-R<LIj*Zf(yH_3m%sJ{7}Rt$s7gy8aN`*bPRB4w!k-5GIdpplQ_|c)R>9oaqg? zV|p8#s@MxR?v>K*Iq!IfQ#n03C*9q<M<ckJ%jQbC;qd2qn6y6!5<N`$TEl%>yj7ZE zCx4(bYx{Hdli5-p-T^a0_2k;s`E2H`&RI>;S=RQtY*Ifd%d@Utm~ZOK9#d4vY3gT4 zIW|~w>h1$SY5zOEJXdV5%M){ESYxgBA+fl2pBP)03<IWi0nK&RIPhSQZN;W;d>|r( z-}`O{^Bi?dHs8sy+YgBT-|E?_YBXu>i^i)`zVPj!Q0kcD#vR5#5*GIfz-;Am+Wle} zYOkt>jJje$vtkn6ZdNK&{pN<w@_Jf!a2ninTgP1W3a99)^U%)yg;%n4P-*xp`217E zx^>zZ5mH7|mL!PVJZ{3=%woFsQkp4TkAq6-f25>ue+>S;6xSDdp+pkK=AH={X|b2a zpWeVnoE>oH=-za@y%w6iT=Dn33_7A?N^=}%qwuhqw><2?(FG1{qjCu&+%!@1+A})5 zY!rKW&jQy60;hXavXOMRt8y8NXP>5n&7uLQFe8GZrzPMhqZrgR_>On523po0hbb>& zpjUc0ZEc8^488L)S#vo??ot&Lx+Dl$@`L0uCKx8YkUZvf1<;8%h>7Fcg`eMd!Hec* zmglRpf&G7yOME{+TiPI~^^Arii~mt@2VF9>Pe;3vQ~2JJV-#d&#tK7DiTiy^c>Vil zSS7K0CM-Bb=RZaBrd6U4I&dOurtcTEW~bw`YrDC4P90?pHHOOvma@^`G-1trU2Kp1 z%Yn3w6vD@jzayW+ii*2%d&qCm?`pNY>~0s^503`n+HR`cv&fh-=Eunm=f03rd3SEf zSp-wIXi9h7Y*=97&H6JZgVFmkD!G#)ICT$`SwAl1@~iG3yOv9)W&?2ir=M^t?iS<> z&gIt0Ofh3SK=8gNvaBluFm3U6il?jeX@v!vKb<X@FS{+M<<!u_QN_aO_g$!Mj;T0U za>0krWQ;aU5sT)opsJg$>@8*2Y8GY+rZfJ~hMRj(<7y9Hc}0ikTb4q`1W(z!3TNst z{u549bm!R_Blv;iSX|yP8SwlfoH`_myiKN4TI)KxzrT$9dgjWn{?I^zd~mx`N39Y^ z&*kqJ-oNdEZMyPoOr3cY((f9O#`~TSwp9+b&rQlqUXA8A)BPv|l)>d~9yqp4fCGxh zF|M;79?1Mia{?x#)y7qzSf&VYFkAL^=>rgh9>7A2R~UU|D0@b&Ba_$C4DeHTsQL4k zY&HC`epD}ZE}w`??;jIa&l$kerVd8g1j)luQ-L}C<M2#bv|zG-9qx>s2R(DN(4<di zQdu%x>f%PQ;f1~O`s#cN{?Z+EZ7xEk+y~y8M%wP#w~hNBlzM!-r9P-nGbVjL%%5ty zQt_TV{%v@X`sq1I|1Y(WWG8j3+9gK*rgeOK&@T4x?@yo`E2deS^7Ec5=)2nst}TBH z>Td?noo9<6vFHc6uG8l~HoKrgZ7vr$EMOXB0v0zIPH8#u+w+GwP`?%e_h<=|x(47) zt0UxNau<e5E_C0)HngPoB|*(79c^M>3x>_dN*`&)NsQ@tqIaYzX!l=5=Noom*}E^$ z7+A*<uFqM&MG^aJ<`U(<F1?V{k7AVFF!NU`Zv5UvZEKxy&pA*0=^|yYulHkp?u*(N zbaBt87^KK)^eAr!4YT==$858P5M!w$KG+2G(nql6jBFgN6b-Q<nW%B)8~6MjE_ZcP zWQ(d8xX`Z0y9V~eRl!GSN1?>qU*v|pYD(by^fV4M>xaLdTjTkE$FNO1T-LMsCOEw7 z%lD@ZN2jg65UcM2fr*y1K34(Z?RiqOeFC!veFSCs9`T*z%-Z~F0y|w@g!!Gac})<D zQ}HZ2{_MrG)*oS)<&msXQb#H^*@FLy5L~loIQ=Mz!Oa@;aEs(_SlyvNn%_Jn%e|z4 zv5NP3!`OYeC-^-NtLlt$vj%#)=q>5>vBmVoE7<d@5iJ|`fb5<8#aFs#C~vqGJvHc$ zYfQA^s%-`?C>{do*KcEVX*C$NTe5=TdAh275hiv!&7J2;Ec5w8*ly?`G?e)Yo()s6 z)h30FC8p22Qe#a2a{>1}cm!@H@4@rVMBz<DXL$N6M{KWf1Y^6cXkL8-AC=khw&9vw z^hrm^*}j2fni5}mYCd`0o6jRlYU!Rlnp~wEyn)2qkD9oSKTG*c#b3(-|C12n|CZ2J zrxHvH>;~3WGr?foUtE3l1YA}s<ovgX(Q)<)FxERD^|;r;lo$=#o4JYN=Zs^uPD{nj z#hZk+PX1(aY$3B?z!`<}Xode)`qi>W^f|T*+LXuQ9E}eAsgpkH_R+>rxiq7yxx%k@ z9Ol@*k~e4LL|&Gv!_T6C|HO9Xf0kPK>BLKVxb+&CRk^@Vi%>S&x0BSe87IX*28y<4 z&n0bggJ*py`KB`KRsP3WFSFo*wEwbS`ilnV>G6x)#jKNXKs;+1N`dP<xk=#(IXiSN zi#QR2T}Ny{2|mhi3Z=~am^ic;UX2RfbjPbdDwM8YkEQI#9dU-sVbmF*LOw3TVaBUK zIQ}9YVx;};fIchucA*z-?bnHiDRiPfE*%BiM#2p$Yk7V}8@MbwK~|%dQg6)(5M}E} zd6Oe)S=t<FE|!XR!gJVZph_~yMcp=|9vtHwP;2`J)Gnwd^~t}$?AHV+Ki~|L?=Rxq zTrFF#ryX#dXAewtZx^Xrl<gUx#bRMJr%kqmmsV3?ebhvdn@;4kMR|0qlP>QW6(<;r zg}B)1545j6Ao)phDQ)-<67Ku)`<Z`0&teamERKdpMhkf5kpS}3TELUe9HVB-72y5A zgJhA#5YR=+%yu3H-!l8cwHHOA>%xVgzak0_9qq{dA1%Uwp0ja=;&m9Lq6FraQier+ zAN{A6hApF3!nK8xt6;Gk|G4~2&?)SJOZ27ZdA1CxZLU1VI|Y(kI<ot-*U-~5g8dCu zG1#ZGJb0qAs91d+&VHN4frsaFl0!T$_1n%5yRYM_ExSdhg2g<BMu4W%OHz_{67Cxp zk?E0hLhshUWIyLSB=QK+@va(fk~~kNohGA2TQqLmZ_K6lyO$YD?7)`+((K8{TbhLw zNS%s)Xf?hgn(lffd3qEf@TC=4w%Ov(+g{wK*$%dNq=VjSDGOc{iN0k9{9jjf%+pDM zB`|^iQ(MJ<7nPFZm?k=^K9qyz`O}vJdmw9R4~+F_6HXmo0gailvYb12sAJneiA!k$ zy?Xhw&q`PPx8$tEe(M79D--bdk1DiOJI8(cqzfPGzL9#oCYxO9#JbWmvMniwR62FW zDDRG9tb;RZ4|2gX%k5~jmBfWt8HP#GvtWt*Fcd7x;-jtu@OriWWre{vg&{s7Yj58V z9<4th+b@p>pBl)T7wWjBLp+WhR3m1GU4|mb^D?bsCqA@3$eZQ=pgH*mRMh>TQ|%q; zQ@`V2)}=q@>phW$R}*AE?@PYdWT5>!S{S+N0}WCAN@jZo)0BS_J8}7OikkaVEIjXs z-AwX@-*pq=Wt0|XdM}}~qr*`3^n5HV=!S)hGssS^!3iUxgv4B3+|o6Pr+$m1jHa!n z?R%ffl$B2k$}hiyX7eP>G@gWi7jMF0Lw>+jwe@VM6Dr!7_=;<qgM|)C-)P;AWEg$a zh2FfG!lUl?=GYs1u+!09=%}mCzanR&nup{Osaiq(mI^$msu)6h=cB^j=Yr??1dQnK zjI;j5fWnjVl4;wz<JRvrZ25ks<e|NX=7CpX(4U$3Wo<scUezc@jM|6&EXFgf*)3=X zkHjTgs)RFh)v)A65Js77p`YVUQp!OM4C<PK+aw;Br|}b7uBrj)1Kn}Y6gA49Ig<~B zUSxNjbd)u$<#S8bdHRt_+!Z&$%eJGuw9N>EtZdj-I$O{GHk8i=Oaa4VyI4W(Y>BtC z5w3rHhuRgSjzx?jRu4ESOiJDX!BVENWOT5Q=KdMwLtNO57NF{|uk^-gD!Zhmis34! zVZvz@)c>r*CuI8EeQFzR`@g^Vf)Pj5O7qBf2JC3B0ogGfd25*`S9Cr~173GWP1C&s zMLnjuW^ZAgRW%%ca}4EsB`4G_H+22cje-Y#gW%wyf`8*^UVCRf-#*eA1}@JM5^C3p z`iYjToFn7ozL%+wRVRK>+L4C6^}#wd4^)V4A9p@;3N)}kJNZeYhe6Y@_1{X=5Bmq* zj;({)b9S))QDq3|?G46PHF;X@2xzKNWaR^@e5<b)DeS*rQgYXiZrJ-mI~^CVrrv{! zgTLTsq2$E9dyC9E-xhQ0L-FQ{bT;A&{%!sMn)aQ8fJ<e<VV7ts*aZ@s{08bRX~*^3 zx6#b@E@*2qou`GJ#%m9xU8H{kz4@bHdv{Dd47MQl5pM9f0cE6oW*KVuOYDYG%PCKC zrPZB_M(>#2*d*(QUc<C$$uKL<yKtQs?3e?M?rLbZe+??MWC{7b5h`sWz+%ZzTPb8L z&e=8_>rO~{eM4&==>H$=3t5Y=hWkK?^%Lm1=o}PIoGv78>nX;xkD>>wy5R8b$!M0N z3?~0pkWzOAuGr~;v&)@nevjGsz1I(z={=e`HIpG#3-dQ5Qtg61?9=rS7As$(e-G=0 zJthfQ|EmC8cCQfw&fgMl&hEvB4(z29kBab<w>3_<poj@=abz{KK@9Js41W(E<F)~A z;x`p#exh?wu&GZ$)g9kyy5&4nF_KtSMG5%++a@;JQ3~RhUmP)R4BEe+Dx8f-v$fIq z3Hu*K^3TE~I^6pvd8K90%-D`N*_`R`vt#U-uE^755peO?SvVOQ&IXCA=!vL+AA&}q z=I!J1^X0&~E3Y%w9p#~>d8i*OqpRog`MsktC`-I!!R#^Ww4T6{$Cn}Q$`I_M@=cs$ zxB}&wmm$2zS1PgB7u|GL^D)n0JZdfd&VN;e?3p_SgWK0cO{WW@gVSSFn4E-_cMbW} zp-p^px+cF(mFBPKEod=ZBa|(|xt}{w+UXObe876iyKDsFnPGVKN5`^P+8ap4Xq{Mj z>H|0A_aK?t7&=#HfomT$2!179SYJOE2gkO+sbg7O+j>gu=H<zb#Zqo0Xd-(W_Cm8Y z=2-Q#SiWdwG4E1|q{&L-@Pf%>>g;ELwi9oNgLx14d=Vml(zOpozp}vYhM6$;#BLnx z`GXoSY$79+903oQj8&sZ0jA3mf;)*B8zc|y^rN<4k{iggS%VjR_YrElErjQ*dhy>& zJ)nJSA!|+&XgL?dqSpeBp6^BlFE{d%W=k4e)fXS#tfYw`ah8+(!ERfUaD1F5H0%E2 zV%;e?E^j6Ic9(&#bXTwV*U@(5fy0#f%79?0p=`8ooiIQ9JSb0I2Y0DEpDAn+hLj%% zFI96IsL~5|T-zy%6VB0P+g7;$Q_AjTO_4m4B@lQe2rrNA4;xp9u)3Yp^}MYnUpq4q zsu$|u&bRsWTR1`{OZ#Bw=7U`IEriUL50`pBXHj483S{`U%74a`l9KINp=|R+{`e`1 zp9fY#O{aKRqZBDAp+@2Tf+%YBioi9;=HR}=>b71Mju`vu6~v3PVeX(c@Fz8mU!*Ta zt{sSq<MZV0VS5F08#`Hd91GpoexuaM1JQoPB{4s01IW#6p-A~97YJXd_(lR%;A(zT z6a}{w9znNi3vNAeRqXgP4)xk*vaq}dP5w568;df<Z*J%Kw8b!6&6qnvlWQ7nYH?<5 z2Wvsws6Vf^nnCBz?L^sXFE)QSpRe1#hT})gd6vOD(WP6h+~jrxN58*MjfbK|qlY@| zvfo|eX&t43eWS#^NyfGtg;r^{Z^rExpNaVcjKT1u0zF+bm__lZ7!!7tJY>TleeVFS z7JZ<{a|PC1kRe_>q9@$5wPX26f>UAFY5I#7kkJ?n2d?c9hK5zKg1k2exUUtK+z6*8 zH+|f^{GR9>s3<y)n1=4^=Y&Pq3aG=D@f^^nBY1utBY*MJo(8trpyJZAQn&P}5I%k@ z#ctQ)Bhl^%f0SfRF=~84%EZkzjU$iVc4YP9C(P9Mgg@nHX~3JW7~njZpG<m1Ul#v^ z$qP<GV*f)Z&ObzMZ`P1i;XTTi*izRVy9mh>dSkACZwP-?MLT*|)A9Uq-0u9<Hc)!D z*VYw5*_-oXpjo6?^HCXMURH9H#MP4Z-z$7M5drqw)$x_;ePQXoGw2!g8@`q*@;fDE z41an7oVxv$sjCNx9`5Ue5sP(kdOl-ohXk%0X)E5g?2h?`{RCqhRW@_niQVlwa=%r> z@biyx)a+r#p`EkwjbMfg8*(sw-f&!4yAdizj6xL+5GE$x0p+{|=(>F%FUuOv_P0~z z-ewlmTK80Jok9SD0p401X&X0V4uh;G#D4w<nQm`!+>K?tGTWQX$42w-u5!7ZE^_|9 z@38TlJ6QK0iW-sIxa)d#zE-xGX!lZTohsw@eN7PkQxhxJ-33cW8*r35g5H7ZBsEjT zAx|$0)AFYBy#5P0BlZIrOk4u%9RgT<p2}ZJd!e&Mf$(^>1$x(glV9831qyvE(O!N@ zd=u+PsU>^xTCB6!vU!0lyr~-~)<#gQX1!4B(OK*qd=mYoy`41qW}l4v>^(A8h`D3O z?#>3XxznEtcSb8=QeYTrpUI^eqdMT0AznCb>Q*6phXx<+o(_9Gbuci^ANM#b(u;U~ zSX%7CS3BIKTec3IbJ`bl<~^fE*TwkXQ!DsTrG(+e#MXV&#MF*nRP-+dlE%)V)e>Jj ztM5JfnjK1^CjxPKua}U};KNF%M&hhbpW$5bF`Si`C90__U|5$~ye!!OH6@<i@8EJs zk8y<Vvxj5%)X`*EKO9vSDxnc}V#+&(u6@+`)YuJpe`pk&e~2IdMdJ?ptnI_f+Ya(Z zhcO(`VoK3*=CoUPJ+_CUxPEd9x-0HSqnpWex#Apn9z7^deU<?A8Wp_YT`(FO)bd}M z7d(0&Ppj4XvY&G<ymuYJMt6QuvrSi4o45g@<Id5<zJJK^$TS>NItw&gL-CCEbEq+{ zMDr!1VCb_=yk-A5c3BZ3yz3Ick4>DhAh(vHt_ryOpBm*1ACF5-cJN+f1$<v`f?Yc8 zM5W-zpkk?pi=NMh=r>k0b4H06ZCnjj!#3f!Ef+Ax`!AV!J|xZUiQ?$B+etgflh>Fj zaKQ0yJgnJ-F6Zwf9btqZ=clmkt`kr7e+jB%<xq8^H(t|tL$23fpyBM|(k3a_+%mrf zC;OK`+oelf{8K<vl?TwiI~#2;kHXeod&IttGCKD@pUktTKuhd+3RvHb*R8T(nVlOq zS4WV&-$PmBByXX?s~bhRJcR0DL4wazHC#N;3RT8j6h{~C;JzJ0xqkxU<0ctHohOYP zF_OJzOWjbHZE)<$J|SFc{n@J@fOCEKu(z5wt^JXM78Xf@cBn0<DjkDmeL6tPOR0-G z@By_vnE;`+Q^nqOQf|B@lA3c4k%5K-9o_$k(gRQO&&zT2Y*jPAwcUrIN)iw3LOv~X z?#fHD)o{ey%lK%FE9HK&M6(GevCh{{csV>o@(#t4YKVZzGY&%j@pypZO&Ad6$tt~O zi4nUi=$lU}jm`Q3_bLu!<%&oapDqJ>ewN;L@5XA&Ho)r2dsH$<n~SC@VzH(_etVn) ziVueJ;FZ6r_ky9|GRGNBUxnhmju%Kz^AR}TR}?$NWWv*R!+F)mRxHm{fRZC)G1&bO zg@@gxc@_n{WkeWfCo}-z2T@_JwNP~Y4>cZ-6E*s^Q|18;P!L>jaPmNWQ?QF04yMtF zXG>_yJuhybVT%`j7K@Ov9Xx8RxcJBkDvL1UyxDsxFk2N=%{o%FtW-!?kShB0_Z5Pc zdI$qs4%4qqJ)y1WC}?_X^PT%sv2jBiWOq0P$F~*;{xb$k!k|QXyk7v;e|sV-udSpZ zL1Q?1shRjlV*0Hvx(_oz8?y>EAlzq<5Ni@j1DEwgn|I#qqtgiTkpG}@-5{as#S6kb z{TNd99?CM;WDLqR=R`wGwi@9>bM7zagpYG1UhZ!iH8K?=hG)<gD?zYowB(@T8}Pee z11<ZJ3zK?CyXw0hIOTj0j(R42D?2~uM#pf$bXqLLb(+dGG97L(ID!UQFQ8TG*aYqb zQTTiZ>W7R%p>r&Int@=yZU|g;n#6tkmg1lC(==Kw4SYUmp`Xx)T@FdCoYz}~+`Lo{ zGE61s1!n}!AS0-1=z#f2qh)^GJ_zQ?hedgqKb`7jfouA$g7VNH9&I}uEo_>3UWq*| ztzM5dr=-8(SrRLy2jh&-`E<^-jAVCr)81uwVVd1^DCsZ{UYM20T>V1uMPGjm`Er9) zq;HX#^qmdPY!IEZ9>T-piEQ$&5|TcSx!nFQ6NXn_=lsN@uz6t%nEj_E{U%4nGmZ~f zZMh@*WrhjP;Z2ZpQA7Mvn~V)j_xSI7O;k%d1;zQZXwJW2LAJCCI(|P7Ti1t(?(Ts? zd!VkEXc#VzyEzQ(=M3gvJBCn&G{>sj@(Jp5dXWCkL*lPCcicKJU07c^M~sV@gNwpq zDXpm=20W3W`7TQ=b=^<Fmg{(+X0Cjox0Vop>pYuR?2#ScI7$pG%%BHr?#t{_DxlSM z7c6i;hy}@0QK{!M`1V7Wm)y|Bq^237VZgTWak61_ylW^Vj8lbqAGeW{wI8pxOGMW@ zb8$iVAnw#2hUeSIq00m-x_WUImz+)j^U75itZFJA|DK4JuhwH-mpoWtoFTYKxfT_t z2W+1{A7i&vVXNLJA+*U!@@?*AJByo?m*R=D``o3G4pPTaV-fbuT`0I;ABl^30d5&v zBfeiYLu{9F>>ITWaoxu-?!DtPY1PLGu5Y!m&Fq}e!)-fn{dtsYZ--;Yv4i-RlLdRf z^y2#RZsb{$#96wg*dj5>K9B2z8Asxz0Cu|kX3cbt)jBHcbZ-r=a=b@T2XDipN4uf* zuo}78xPVt5J-9Hs9I~!-v@M#E&(WLo&~edAns+&wHrfB7tbG!DQrgM;7?`tWq?0&v z{Tot94Jf^3*P9dHK7gNlEZI>EhA#K6)0;DQsJy~PtV|k$=l5QKjf1|E`+FPEbR7dL zBM;(q<-Pc2Qdc}{98QnUjz&DDA`ZDWUYhaw@hP9rf~H=JSYQxKMbdZXRJ|T=|MQ5l z{mzqpKRsHnn~fgTLvh&H6Ex&f51eam!SkOO!oq(e@r0K<svAjcjN1!fw3-ojtSFQm zk`lLHp_abns-yh!IeI_cnau}ETgg3<5Yebgw@`9!^m7&}7cx9i+6?Qg6|nwFM~*G3 zm5)`Nhfo*6kEZQoyQxRu=zB%1Ty{}V@v5XLpLDQoYYi^ydJ~uY)g(<@KX6<(hOd`y zM@K2!^4L04Og~nS`L!pZ*Oe}1_0CniQS$5@O_MTb8eMtP<0s<TbBBov*I@TY7C6EF zo^ZHyAZWWhpwC;*FxmYnZH{rn!ZrHRoW3(mx)BUjQ&z)bFALj(mW}k^tbS-D<%0rd zS@IEeT|8^D8SVSz!G{kgA@pZ4By`9XHvBwEt27PB>{?G8;=3O6rQNv0))T_Ke>>PM zY!E6Oaw;9tF<$gv{~1n{CDQMW;k<dc1zJ7aLh3W`(P+ox80?qN^RM583)-I8l&FB` zPk*5kJNyN$S&Mkv`yyETI}`(R9>M{OR@kcXnhx4|z<C#4$ka~ez@tW-^JqVXHU`q( zgECC$6v}=!S#a>xKkD;rIsW(-$4RwULHp@7eir)&&bEyg28Zpnjn-F2&G~+uT@y_0 z-}J@t&U>kHTZS-UfRxuPEoEP|e$>7z4#qmafKHp|aYBz%bof>+ESqD6z8?YV*R0^t zha33Pt!NJ2x*r!D=}D)3kF%1ZF-`BKk80&Nacz4ZE_=}hKN#6yztzFwuk91ieAXdZ z>Xw({<xnXf_pX_?@AblsbJt>q*0$207M&p@wN3t`+aJNb_yi6P*^K%}9l68BBA&2C zDt#31$7}aTk%gryYuSY3d1W1%ergw#d|JiR@~(-tdRd?_t(5JoK9XUtpR)HOcC+V* z_R^7)@6&77Gcf6%mN4v16%A-iK_%%-S<-xlHSLc<yxM0vGS!)WxBsLM0SxCQXUveJ z_M&&uX7)RzNB#PEp?$YmT=%UT&d8c8y^=Foa|+9%>jsm#`!GztzEiMyz5+EpR5^Lg zYnj>4SWuYKn^%VR=OxRAl1k1!S^7s24t6ZGy&T<xd+V&{TRoLAX-A5Xyx^Ric3BI` zT~2cs2L;ZYvx{7YAA$MfB@|YC0PDR86O-!<X!MaVkz4}6eBK;bG%1$svhE3wj^uFl zL2qGswlN)Ox(5EAKa<}8BipZof`yC?Gf7mfr9mCyq2=jzQ1h)N<-^{*eEM44y1Wxd zUGNY$icQeHq>uQ^&4HRmw}8UyDHzki6tm7>h3NlG@N&EsDi@96z!TY`UC%{AcIRi1 zIw(<M^tY1g+GYw|Um@J;*pbb@YSB5*{=Dyv)PbnmFZ;Q*H`czX60>af!Hkvj*k<=7 z^3)F*Uu5VmQZEJDjxq;S{!elrDGkA>4xQ0kw*sASNV$utiK550UE+&e>7Dj%J}d3F z#@)uJ1o&br1bgTSmQuDLRdONR_)lNd-98SDpX?WwyxuLep6(ADmM-J(-tkh$UDA6z zGvGnPp3#VYGx70kR}LDtm}b5W#YtZmu|n)mn=G%bY=0KzdBd->PxMIJhNv>3Xwz|- zm!=Dk_BkwsM_m-P(}%&%6$9{FrZbg3*~2Hd#UedkDVzNCBiZPEqX_3?oVq@SD1H-N zQX9x!Pjtbkby1|h^^h>|p`vY0Z$oGft)Q9q74Ueg9!RZ!njN7ej#uj?KIx@PYPp9% z^Mx8N9jGhyH1E(_$#;47XgAQe?hRJ^KLA!eC-W*TSd*|{cyTwB)Ymq$+JQ8RGTTd@ zV`p+z<ts?7i4%N{J5!&?w{Z98Y?`cQz&#Yhc(-{2xGs1l7Cn9h%@5p!gFYwWT@PpY zmOqgcv|Ht7B{~S1UZrn(%;&_*Um$tsv+>DWs^qHvH=yN;p2Xv`;!eviqW_$i)KRX< zlQh@C-^M&pS8GO9D+BJCl_*w5S#yJ%0qhz&4HORS2hZ9$a(APl+})5#O|gJ>N8hv6 z4)a8vXU&44`VHamuEk_z`A}Z9$w@SuIuHu39)UYP&!G3CU{u>V3yQ)*(5d|zWLXd5 z2@_SpyyG63W>$A;Uj10eulh}KYCGVu^uHp%eUx`^2!pHcQs-#;WbpdeU96F^0|kS2 zQp-Lg^nI<xmeYrF{xLP%Z(0I6UAPGeibo+XVJY@a>WG>?2k2C160hAgK(%-s_S+Ur zTj!h+BZfW{ZZr(!LaP=?G6}@*Zkuf1TN-iNS939|i@JP5WefiL(23Q?3?Nh2x3qrD z7NIaMRq~s5#L@{BaBH7Ap1R#anV`d8vS(0QN~)MRHI5A0dqS5r()_HZ3N8+h5!z}( zxH0VHIC{|;T~yV%^utv0`fkme%$`Wk)?*sgI*SwQ!g$RS74+LSMR4x6Pu9U~x2We( zM;{)az}7$ZwB>`e5B?sBE0(8HdDu|8^|2oE=YJAxD=mdg<36DHdlI&mToA8*knT4h zwz0Eim>84Po7H=%vRvx0H+AiVe=JQTzxqv4=b<ZwFAu@JZN+f(b_JbM3Za>E!!do= zP&Dl8KYp5GA<WPZkvgMBZ0MLL-&>smx>wD`^@SR^X?b_}z3>Ye?h5BH2S=f=?_cr_ z(WNKZH{gfDB{=)piypdeqAz9NVA6YCx;3$ohSp?&dvgJ-h;&0cFHt6I*TCI}bvQ!G zdOq6M8Cq7n6{LtROq{HaZ3X+pf_NqDW_|z;yj;#L3li|f<zA%zs#vUA=F9G?C#ZSK z2DWv(CAw8aNj%VA9N1A2r!PN8QEeTub?G+9x#NYG9d_bKeoOT?9tpk!>M42PA9>{U zEes`7A?@5XY7t6=+0*)SLbu=abz>@dxZb1G*;-sN!IkCvPQvRNi8X0@kmdUoA+pmQ zF{OMqzMV7}?ML23^L+`hR&6>LFSg^68_Wbf>8!Z=T$bbovX&1tw8zHHe_@#15R;6x zdDlEwcrmL8POn}IOD^7q5jSR{pI)lG=CKzY8|p~QhcOJ&-H$Dw*Wix&JEUplD}HF` z%)fh0Wc5}zPFR{xr*|4q!km53Ip-&pw_0Jso_c6|kjRlmVXz>g8QPuxLKkyIp8d5F zuY`|<^ShO4+k|rTezzGiribvn{mBq?C>M5l$Ka-q4~2s@LFAO;OOM=Z$v)m4jSlYv zi+6XarN?V}A+gOa$((7}TowE`z7e+8pQS5W1L0QeGU#J|QK0|2;IL**oO0p2G|T-( zlY1(ne935PAG?S{ABuFsQ1W|U?S)r{UWCDWFM+A$5wIQ^%pPZ&M9%cajNy{&{a7Z2 z$2pMw2o-F*9n8Tghf6ZH*q1K)6^f3^W|Xhgjohp1W&TC3WVq0S+ide#A^ft9kNyEZ z9~qB_Py<)!g@Q?n2cK69roEq%(9=jsbT%A@0ik~Qd5AKkJ4x@E+VzxnSP^SyOC5~2 zxx&&FOHp38l0A<5NFL4C)Yvn7{N<P^yftMuDE3>=-F$b5{%>zdPqPN6I~)+EH1wn& zy+&}p>j)@0dJT@bbivt{ah&pYDnG1A5j*)h!wjo<OxUZ+0izV@s-Pv%>no*^UbETt z+XbvXd0MPho`SB6YN#mW3K@($%hOto_`>cASa4_n&5u|KnL#&b=wXC2Z_TN~xhq!x zYXTlB`MXw{^3FMy+#%FK=;wHfMqIiNK9wP2l=V2VF~>?YbW0Gbr29t6$zAjWRParW z8-3klLuVsPMceoQ2zV4K1fIS{FS-pN{UI9Ya!QjuX5WB&!E2~Zdbe*o`3jo%TZ?L! z0wHPj94s5)L%Rx<c+aOrl)hbqYMQmM>5VDWmm8tCdl;<l(+%nCOtH7w95`z_LUQ=^ z#pK`<ax<MsQt>I4-THPNG;_Oiw@D3<qwd0T&n#*g;LC@plJ?YP38TXt*wDrYztx|o zf2M;V_xpQtR~Uv0$NGU*!WZ~a{7n37)Bu~f3cSDV1`TO>QsOZhIy_wp$#KXQjxw;@ zbRFw7?m_5eJ)t^nCPhfhsrYph@xQnjZr?SCeAlK>kKd*oZ5)rcW_2QY%U4L4riy+l zSv0eg9$%4i{m+&tlqvig3QxErd{L1+ejC4o-@*xCGq+t(Our)<WfjsfxPr3_PQv*J zA8rygvB~W_w<UMue8pN=|3|>(t||QOl#%U%L0{ln+a}@TPD8Mmd=L~S)<ZfqfzHnX z=&1^LW!^3LW_ymtOzw-G+D5|GaiyeZ-wB<xZMZJQ4Ehdoyu3I#2clNnbNsZ~wDh{< zytVbF==#r)Hz%BrozlW@mYSd*>xgQ1bik(88I{)^;euYyXmK?jK6SVYqjN!swe17v zRno*)9Y^t5w`4Nhb9ub3!&BO<+6_yWXtUXaCddlagvK8S<Z~bGpasXjP(h#${<mfn z*~sK%H*+jz9DYrqonygzdK_d=9)l$l-2|mI5j@}TjaXIkSlGN~H&3zs2x%A23pb8T z<i;uKLSuNXIPSJwT<~KG8bo~%E_M^aM<XAe#!bP5+NqQ}YBAXdO8kTD6Y|cLN;pt0 z19m3w;NppwFx<@)mHSB^IqAGP`imx-tu(?M$DJJaP#uD=T^2m==E}NoC60Kt5|5lX z0)5RBz&$ES$g$7n&VdH_xqK&{GBM=2D}Tds!}sEq=9{$f_YT||e?_i$W*)D)HU@`$ zv!pY1R=Dg`Ai@$|l3!1U<v-?Nk9+N+=6}1T_rL)DeryI^j6W@ehF^jU=T&*>wCUW_ z%MrFOK1tuSm-Fk*4(#WCZv6fyCfrn^hH|e_e6>e8OnCW@mW>P(;<5_plwFzNb#)nL z?CVWE*QG;Py|Q3p70%{o?!mwf!%1U(Gc;Z8X1ngvd+wxu9rTs+XyL1qP<GmoADu0v zEYBtK$|Z|=%PV6Hh*(UYwjPDyMmeN#D??~3oIHM*Rwvq_bDHc|js&xy9EeXDg4<n< z@pyzLkKX-GIA1UAW^(4E?eGY6SCH5jj@l5k@Tk;FY8F4=ct;1#BIuE^<V#NK#x0XF zh5i-sRJZ*knN*}umE?K0@$W}>l2bA7P$Zh&(c_diIe2JyE4lbuK%0|47JUnbZZG9f z_HZ}cP7D+KR`*3qg#sEIZa~q$cA{nYF3Np0kaJ82%G{J6fqkKtY>v}qSYDhA>Ceg` zukR(%=S5%iBRdW|96^5mTjaB5u4O+1$%FQ<KRl6GU#~_+lSkHF3L6^?W8E#WV)IVy z*`rkOPV9tJI{X#e)+B>x%Pr_w_e4DSX*V`{*n-a5o@Hx4oaMDCrtH+SAG*8}>A#is zP?45QlL|-Up9=~Y?{`k@oDe0RI-mgCwyvid#Y7=Tw7|*<w_#z(bFr>EQP$!Z16EpH zZSlk|ioV_r4=%Ii3kP4*vH=zFpv(>XOW!b~1D$cHW^Z`kUt(kW2pm?HM?XiH;F%Ni z(DL|ZGN*^a;<`*O?kV-d51NUezDBZscLyOeuM#{a8?pb!4iGRWnr?NwL~30xqP;;I zN3HHG=nkHMcYC_y+awKM)u)u!7(A!EfpRRi9)Y|xT}&7lCL2BL2Hg}QG5(JYg!@n7 zw$(}ew!xAn^)3<@pFITh`2bI<tr3Hz&O*!g6T<b*dc4Z;4unaZhPTI*DEO+g{PD(k z+o4TnXxgeM@wtD=PV)lTuhJjqd2Jxa8T0s}-&>~BwKARIpM|6mk*IB(NNOLt^HbF! zbiU*{nEv_>(YTFkXZZ8APks4)l0BA{lUOw>gqycNA-%2L@b>Ub49!l$Z(S!zu3-b5 zQ|(2uW_CC@`;=&u^8rRn=j^$G6FD+&1a@8W7EIG}Y1{6ukfFOn`0*zkd|FNLc)@LG z+&P#tW%ca-x}5(07mC`2adb@LlRD0KK`3>TjXabFO}B5+zLKe&bs|Qr-?5Ojq8n(B zN)U`xt)^9GhrsHgltIn^Emp~kXzeE*ex!U5_KC_UCE0kwx5*fg(JCfHWe96djTXi_ z4+BN7w*W=o$9FS&N<BvI6H6ks(DUg?w)ox=x9^IE?e50h{=!S<GI6)~-#r-&HqeF9 zCvEWkXbp;LhzGlif8~aL|513u9^SS4xo~#nOe$ABF4U-Bw^e#_gV&FA=T==`NL;Lq zrmJJc_Wx0ICVn+`T^LRinxsN=nJQ^gAw%a`>y#lXAqh!H5|VhSgrZ48l0>9Qktj*h zaGtd*gd}4mghV9C9PvHhU!b2(XYak%eP5UD0M2`<gt>m0z#7J7a$gtQRZVg|$}1ZX zB$o>JY?}hQpjbi4^UT3<#xBk%>k<|7Um#=94=$6v0KXW48T5Atzk9kSSjnr2fB(MA z$DKP&b{B;Gben=`x%m^o$bD?Py$O@@y(73{KJ%{IS5bLh1UwgYKwzjZ)dUL88Lt3L zsNIHv;%nfWFia#rHvpRrB52x(iTwE9Oi)n!z{j~wWwu-Tvx{qcg};eL;0@AvqeGSO z+*Fljt}{mKN6muo${IhkM$@SUMmTF+9IHGtkfj$Vkmzk09M%W%`onE-<61kVP&`Pv z4zfS`?J4X|F~spdZ`0i<BS`c&!}@ZLJslc{p)ni_+&l!oNqR`h`4=oac8!;Eng*|Y z$Kcey8FYMKHVv|o7Bb4(%&;Q{x{dU?vP6GQ!|D;`cxYfl!UBeqg|mIw5iq&9l}(u& z3G_yWZ8jlTzZ$Afo>(l-pR7jTLoW!N96t&iWQ_AeVqw7iztFh576xox3bCFptmj=6 z7JZxu$+Jr-XxT7!?aOGEW2VHC(*E%&vhj2z)`SjSm&YZVRgnCP;iGNONm|a6VinFp z<0LssswSw*cp;LC$^^-3Vb}GoU2u>c#L(G|aF`h~wHvw&lHxd08I4<CjK({=JZRv> zr+gyUpSL?8BAvFktnS@#uI85|*Xt!>v0{-hbG4^<8bpnC-y!hN8Sctb8`?B3nx$GC zMXM7GTI(I?S?CjfQe+{y>&6mA+~-%^vcv4o=iJmniEx{l#P04@#Gwx}LDwvXegv!} zQ|n}qSz1GX2d_Y_V;WFev79WXeG+x#eCOmBU&Qbs#;l>IovJ$I*`(Aa7#sN><QGlG zAdMbwlkzF@elUYJzljv}3%e-pzex!f_WF>{s1G0s@nKnKILhvb$25r@_+6C4^yP-| zH#Z9nh3se?-U1cDo89}SoGXnIoZh?DsAPv689YsfGj$zgsM7;;brZSuZA9{K{AkOh zqtMS}0GOFZf$g>g!3&*9@<uCBR%1FdwNqf;;iJX(L(S3Ud>r5V)(%CJrSRWhA?qc3 zm#Dgp?~T942ftXzX3jW7vpfcKo&zF9HaaH+j!PL#9=aSN-n)uDeOqX6$`yiOc_v-; z>i^k9zEZ!MCKi}LdD<sFImn;eyQ`TdMBOA$Ia^VTj}jRS4`*uU-B_!Jz?D&63J;n> zA+~-SoKyG(9cFXrXxMCKsiZ;YPbcDohcnrA;Y`S^&|vLtT~K(-j5kW2&U9;C*p?0h zY?SksgvpI%2U@FWMolvn$k(ED*jxUDe;OQHc~(@meV-_;;|9h4Q^sLUsSsnbfm9Y8 z2JdiFj5>c2TmtIo)2=a0S~rq(Hmzf~{tjj;g1fW7$z+_oX)cuJ%@T6FakMzd9ux~? z@UoLR$#40|9Za8%eXYm9y=*a=SN;~=TAM|RCS%#@>w{@Ttgw^V-wS6ArP2RXDM)Ks zvTv=ESiWg9j6O4nO^-N8-)xQX?#g3OY5kH~L}i@q{o8bP-bfm+`c2rYMUjt;5vLR} z0Jmxf!|wYt(RGxNm33p3vgsZt{hu^N9C$4$y`YTmWMm=5Y!vowP3I>#*|P203s6Wn zb45Et7<l#4@aDbzk!2HT)zX!`nZVez{4f;~;+i46x0L4D8pDwz8aN}d7DnZt!IS^q z(Z^CXl0;fC6aNev;}O83P2O<+DX+PKJ*VN>B42iFR3JSr@L=k*W^!J`eOPS2cf<*I z<wxJnQ^%Y$OfsyTt}iQsD>X?ldhco6cw-~($O^{z3N6-Svz*mCcf#4c1x#OH+DsIg zP^HFiXiL}RcinglD7It59gb|LeBoYY%CJeFieO^>K0Kck2SY9?vfj}a;M4QAs_o@5 ztoeKuEZ)?>@!7NC@15~%XhVpw`;ce!;s@`VH;(dF4?>glXi<Dk9?S$Kcr$A_bN{D? zQ!Xur@X&Hf?jdTwT8dAniLmt35wdgJgrT~1kiA5keOVokDLrAp=}7q3-{qN|?L>Mq zxrD-81n-n20k^QNSfdpK?!tcg$ACkuJN~XPQ{E2eEq}v<D<7z#>p9gf(&sd`6mosD z)A*eY33%jOENqflfFX+;MW;1xi<C<Tv1H+MZ|s`LeD`=mYko6%?Dz`hOY|^7cP;BY z9nI&xehVQ(#=`fy9MU<L#~GBT3Gdx$EMeRfNlHSy=&fZmDjad4kwHCFqU{U@15DYi zQ5^f#5XBbG2nQw3j+N<6!M*Vur0?dT&~yr`y(`VuU7U?dqwh(Qs+GAUi+*@e?+_mp zUJYl2Zio8eOVGASxO-T%lFXg07?x|pl<zCCNoRe942Uy*=u1SigW4?aV;CFqx|=Vs z-2+nD$SvyyuHm#4d-i803phUyHcZZ>aDgxQJxPNtU#-Ee+&M~0sqv!l7GWnCAQAix z|4~?E4YWMl3swO(<h9Bjb@v(YaS>ziT75E6+BkBY7tQ8go(<=QigCjCV?=^XF-LzA zcXQ!O*e-A?l2pIKw>5G&p*;m-a6eZTJ)KocEK%ftj%Ioe;oJO<a#2bz>Ep*&kUHZt zm<6ihvum;RaC<C%wbP~V=8k+rS2hi{2;$eY6~f6icC7QQEPvjk2|5Cg@XzFA2tGb0 zZ<RD!<TeU}H*ciVGoC~6LQM>b-%39|2@a62@l)4jEuk~zwIr4OL}H_U3^$+XhU+SQ zFw<!SRrUna4W)zZSB?>C!(QR{`GEJ+x=wqSC1IP{FJAel5vHEp!%jVNgq$%`*pKzK zbjoTX=VCsGxxYIBi#vVTJ9*(Qr=|i=f|Bv>-geObPz7$ecgf=0cs^lI5FgO|0{*!R zy!Iz~bZxFWNIQf|%7?APsps<X=(2G_AJmfFe{w|7hM3}oOfh=-E3(S*9_--$U^*}C zY}fA}g$tyfakAHS@tR>6_p56abSYe<$Nf_zd*|k}xFsc^Dj7gSYX-70!CztD@})vw zCKAW*lBE|N^_04=7!RaN;jMcES$ywa2<%j<HeIMKussTS!x?d)f1!$nZEzI_6knqF zkXpWe&ri76V~juN=1YEV8UXr_7vapG$Ei^^M&z3Qgg!ov#{EhqH2v`|I<(UU!>w0x zG79_o(IzWvUO!6U-R7O74MSDf;MaY;_~0A5cFYv=rY&P3SJy$CD21kPFu|O83fM6v z8>VH8nOpM#+_z#BidEFn(PszDo4Ev(Cpbatei3_gYz`Z!X9+?@fqEuBgWKxLm|muX zP=3okDO;GW-IasTHVfA4GZ{VaBCR!&VmTA+`PFw`(6xz+`4!VAKz;CF_&eemr>&7s ze^UNQeEL7MzZGM`N_&>zxt=VTEVrA9t{;Il>o#)z)l{g(P6ZXdOR?6yLD28B2;VJD zfWp}#XibXewPO20^dDWCdf_bmSU&~DJ{PDpARB$Mw}6ax7kyuG8O~pt#Z?5(MZe?| zjDLH8#O;E6V(ksO>U;!ec6NbnfHRKzenph!mq8NC5W0U!U<Mz^2B|q4Y22{uAXslD z8av;^0>kxqJE;hAukT`q%M5Xa;G~gH_rqql)p%Y?oxk(B4hsAF;Rugw6gd7d<vYw~ zU9E@7P;ldo7@!ZvD%0utf~oA<&@PUgbLimHVs^PnlO4NCVBT<>UVd4?UHqd23gc8E z|8gb06`a&tUA>`q#W|WCp^r*Mk&tM212$ZnO*QpfnO~7Hnq;@}uhYEofW|IdI`kd8 zDf^YnK6z9)7v->8A&+0`W6qo-+o~D|8nDiDEpRc!8k2d!k^6KsZNOv-@oN*!EI&hg zq_gNhA!A+s-w0eG>?D166~oD=4lG4fz}ZfTrniesaNYd}&~vXAHVbpHJE}?eZlyk( zKK~!L?cogeR;-D#e-)VWIVJR#-^ayt?dP)kp7C4ef1t>z9bD#X37}IJ=9X8{yJeQB zEZj3UXIgP0u?JSih``6qLt>G1ffB>@aQ3bt=&vbaM{loUG<qbmK~?16<3JhvO_`$Q zGAijkLZv?<IIEB%&~*3?OU;hciJOB^I`k9Sn+q&`&!Lp!Gld04hp^9{N-XgDZRj=Z zB!wT-xl1o>dD&=ZvUco&cB@=aaN2+mUX_Ax$rR8t8i|RESMt%9??Bb5F7WzT%D%LF zGIy63lpnSdHk(WZvo{{xVXm29tvnhl<Wl(5^f-Dv)>ah6ra^+U4L4_zD<0T$4jM-a zc^M&V`Fu$jjR;-~@9(|9&=u=xtEVgm4vyzk-}i%*$P=J_xE1~m6(Tu94)BY127^MW zC61r#$sAtqX3M5c!$TUi@GP^KetmxoRb!5`JrnJ4-RUjV?X{Fm{<NEt1BJ}c#6MhZ zu^~Hb*G$9X4${|Gn{iBj2a{T|7jQC%I>H@d%=KY3dqyVT6chxf;_l-k)(MJt3~<tu zbKELPC&eBuz$?lxV8VVgcH-n|wrtjW2xtHJ;0J;e(7}cIcOIs2<p6R$Ex7MuQ|a{T z5fU?*4mw*dMHOp#x;*ZHxIU;FK6yvbs+;{eqYHcB{V^-dx4usK1?6mC{u6dkCYq0U zB%(hf_Mp+m3qUHnSy*Bmy<d{XmCv<C4+U-J`FSzBR=0y@WijsD>lLtT&_SA2<jh6e zsNnB=`-B-(Bd(a1&b{<C#q(x1kbib04l;43kiIgwT$acMY9C`O2F=5wzG0YjAd^=p zJ4L(V6NKHwP;4)p$|Y!qQ`TlRs{Gr{y!U_P$}h~s?0si>=NNZxv6LS7@xnl12V=&o z2tS{RmJ?ff<re2Pa6I3*^$u^)V-2#$8YQrAG3S{k%ihPY<38g|Hlk@8yVw=N5ABfy zi`QpZL&Y}iOMONg?;2v)d_`;uwIi2GBTSZB0frh$5Ue&6x)&beJ`e99c1iGxOlSwI z8-FDVqsl4i&pdjyy9``Mz2W1v;-GMikd-uC!adow3@*M;qweQ^Y{t_|AYS@|R_F*` z8Jo{y-9sOlevLEh4(<~<U9rZKR@W)*Vkiw=@Qayg3}@#Xbx<L_fWQB^17gk0uxIB! zFdZz#%v`S0X|+a4_s1(V;|@<d&P>J{NeXiM@1bgUm%xLXMz>PB`Jc;@vCn84FMA!h zLp?>n`dNdz>t}9WmKG}?`h-@`eTH?h{qb~rCW&`Whp_NrsNp)0`3f1n>xyg8TxlL= z)O_P6R*0z1DjX&MCeqT-JG9}VJU&dGL>Gi^lB`TQ-@SDf`BwMApB`sk;wyM%r`zy% zgePot%of^zX%pu4meDJ--58OT!9=@8vGV1r?Eb|G_&RclxGwz+<(wHvOM}OPVt5qn z?^(+9O6Fk7K^y8#s)nb-FTv`}S?q_>A?!N4i7h-i6ONBvNB0GPnbcRq3KdPEg(bKW zrjJtwT|SygPsrvxgzWX3LofJMI*nlXCSAm4rcuQ1EI91!$KL6Fl_Yn3p!|&oS*4Ki zdwqNga};v!d&c`$r}?>x-CX5F5#!3H$ZxLXH+4_IB=z0&?6Dr~OnDF5v$SAXsx=$d zIS)m{&e0!RWqw0b0Bej&Wd+}j*`ty$YFHjmss6E0dS2Kmd>D?Um(HP@*H3a=m0opA z;Q>frk)dvlmoW6)L+<AElQ1b}C)j^G09;`Xc0_#QLMHs9(&t{x%i<k)wmlVnlNNq& zPfh5(tO17n-UWa1zi}h$ZZO&YQ~4tI2(U_8&T2o0fK<gFe%$4El#rngTcWq}{|vWs zcdn$e$G!<T;(9#Ty;wn`+Gf*SrAlhie@*2ZM)G?9rs1aq5g0mpaK()m>Cb~1I8!|b zj-GnMm&EGwK|T*e(n;3jKH35`9J65hpLbMr=`Bq2+z!4QQ!y}KlPNMwR>QZ_l{fnM zRedyu_B4aoZwX-9DoReyq_7x8&iqTNxYqa&Y-)bb#lJiR@$Pe3o%vJA%T6irfwLE2 zt%EY=XV}B=GlE0IKby3Kx0&^!PU1Sfx!do|G41L==Fu4nQt3}BNADN271JW&*~Bf} z@VNPG`I|m!P&&rnzV85KV?IFLkUC0#DIvqfmoRbEb|!aW68p4ISG+W(5j5VZ(Uvzm zgnq<d`z3dtL&NY3w0LbZ=ubRP;*Q<SX2?KxeAQQIUEeFZd0`cMZ=S~={_+CK>n+8h z>cuqo{4(a;{heHDq{JROi?}t8Dh!);fW@O&8vQexzoDl|s@4Np<FI53KmL&hvLL49 zzJVP)S;+17o)2y1Dv-7#3N|uX%sLTG-@XK}342~~AOHB^r0JgQ`q)VBlz0aF^&}iB z3j5LTaegdj{C4(zqbB~0L>9F;jybC;F+;CEWG~0#bmvL*r#T&V+|A?VY7fJ4`)H=y zAuuA94#Oh53YzkvAAS<&;k{^qmw0Owz1#DU*po-JcY-6kB;=WM2Pk5~(sImg5^|K3 z#7Q|Dl3Oc*ICwE`i7BD|hdX(N+tO$`X)q?t*J2G1qhQhMr<B`b%zQ8ORn-N*lzgon zi%FYrLbzr$c$#{$bNjY23$s+%G*8T?_<FDg_kZyFhCc7QLkNRJ*}~P4cI=f|A8%Ur zh+BTClU}Jlfl~2(nCiV4_1=15bLV-Auh>p|9i;gYS8^e^#tE{f)Ida@1|R5H2HL|a zcvxb>zUh15H#Pvi3^HK%-wk8j-&ly~n`(da)O%6UGO^^2p}=2TqKtM6`pCIf9egGS zW2v<w-WXJZMe|>g<$a*lE_vir-4Dz=JXzB`f!EHgK|{#cUC%nsDo@@Z{ehNj!Lvow z7?sH2YJXAt(>mU8^%3%Qj%N^|$O4Nqp`TSGq>u8!ke!RL^MDgpxXxpB#(J#H<B>2I zn!=WA_s16%yGUwkCbayRDw6YxgcC(ERH1*DJ8QWT)c&@R!nHa`aIwc1zS2T|SB=-Y z&<*8p`uH#FS7OsiX&k!s9yjgHT#(FEXCnvevrjsPOv-M#$l+@jg`F32Lz^$rD}O1> zyH`Q4Hmk7ylS6TbwlWP9T<Dv%_tEm7;pl&PJ32Mhlk7z+G^(ox_Z9W@)<RxfAE!y7 zSt;y#Kql2&@8MT42a**!I;|g%W5vTHlpUmjcOUuDh1uJg;ny>KPDueAo81OOWAvFe zUZmZ!C!lextjNr#i|?qmLx<Z2czDWToOjs{+_f^`d0T%rb@xS>QB}(-EW9`eorz5L zuL^jSs^isXLz&U&8s2BEG&(<T<G7-J>|sDI=O-h<Uyf^8lkpy|C)%E$D({KY>*L7V z`i!vq+95jr>nIJ3GG^zr{Mh)#x4}`oi6sfnxaMcYklgzPr1mal|IO86GBN_&<byxG zI;G8C4b6sQS3-H|d)l~u&mZ!_bzHxTp`i8kBJCU<g&QOT*^`&kSf1K;7O}sMOB3eR z13c8Je8Dny{EP-K9$g4-Z%ZKHO&ch0ujW(7hOz@iNzhi^ObLP0vGGX-zax>T;f@~5 zPm`j6*><3P?i|dk%H<>a1!3-qGazbg<>Cj5QEVRpEf3^zgGh$8hJ<s|qC(h?ZDz2w zOxVvGkK|9uwZpD=<+Rv3iyN4`1J-}v1-1G@hF5bx&U2B6tH%wQPU1N1Q9VUN8@Dl6 zl_&hrq55o9=OOO=_dhUN#|0~r{AkLz9oT}+G_P0Sbc~Lr?bim7)|vaDo$tmv4tofU zgly1V{)P|H%;dLJc~I)60n9&93RT-?QH0V%xV~f(>bA;KyTUns^-SUa!gUbaqprqO z&lghokh3`3R|{qG_QCD3#>{8Q8_DR=$?TrB9F*)4d~1^hZqL#ZI=uQkzPwsRrq?E5 z)a)m0`_NcWE9j=gzH=mNS1DpmV%E_m2DNR;tkr(Ay`PdcY&D#X%W`C}sCf@GPaDOy zTrz-!at(^B=>%6#!Kpa3ky^q%xvnFw+}87}@Y#$aoM@_v^IxoFMz53kd6h!0zIY)9 zf3y?)+_LPaT{<^qUm;6*;fwBX>?ol4DKvhes*&w`!0U(%Q!5(C0?MKpru4_085)$7 zwvGL67Ne%}Pq-;EL7UIIV5rzf^}<_iOx9tL*d<X>(hwZ_@jdhYRziWhgzx_`rSSRu zBR0BVvRK<Qh0d>Y;cWLFg2XCM95u0;{#-VNs6oq7zxowD+pJCR6Nj*buydF^UEtx^ z-XfeGimLN|i;VvbrXdFw)V%91mvkjsv&o}`9!F3B{c>xgTE2_hCd|b@Hg1Q<PcBi3 zf*UHvyJ1jvB2*P^q6W7#Jdx{!(p%~z<TVHv-4teHp|9a+qAGi{Q--ZsnMe<w8!$F& z6zaX-hZC>GV9TyZQeC{9)PJdR7J@r9xp_RQLnQfr8qBr}-I0gif0I<+Jdu9Veco`Y z25+dO2gBQ<X`Ajsurl~8c`R^yPj6Jj*d-U>FN<I|mDj*qx!;^zp#^EGYT^WI1LoB< z6*kxKpt7$G{KxD9)h27ubhC#W^R`p#k|0sEixZyycZ4pSEXR&B@&YVGkrlcWa*{Mx zk>BB+DE&Q3=zDqE2mTm@gY7if!<E}{v6nvPIIhC)-Xi#N94Jw6kN!>;yqT>|P&a=H zr+23xPEy@ZowgHD?qWX-9K9a(HVJR<Uz73fB5!C}*dPC0cfsbDjH}Z=3>6zsgVcjW z@_sg!aeGGz9H7ChWZ7DQ4H(G<+`2$pL^o)vjwKw*Tg-Pm9cJsrKgja3DgMlxPbo7W zk$LY6h|SM|{UN0^r(Yy=E?LE$TIIkRPX2|Nt_JXZg#j9Phf;Xx45sHW5@oMG=AJJY zg;(z{g@3ac8=&vcB`=Mq>kExhB;^m{B@5U-|1YrY-YIHHJ_?IvJ+NTo0PIpf#n&aw z<<GB=<r|x$BwGU&Sz>e?OtYGb-<Mls!*&Tw7Kbs}_F<qItRO&yMq=yVw5bzrWW$#K z+~E5^fp_$K3QK7`%x!myWK)Y4;Np4_TR&$G&J`HWGb`qC(SGkJV~06Eb*(?Q?&n}A z{K%t^T{;DudtvrvX}B$IjtTwOqQ^%ESaU0atWF&y#q~qcEB7AE*f*6eUg6CW&3oa% zKYey$>v4X%)^jS}w~(4`t=X~ncJTe74#>8Dft<^=v|Z60A9kOkt;6hCLx&WxERJ0n z<HYXXYaofsao*>@g(SW97;hf#PaZ)ZNp_9}hPICaY*>LYDV1Ej(rMT>Z!kWK&7u<1 zpK$K@7%2F$o3G8iO7WA4>UBQA-^f**``WeSp`b@!Z_mYhgP!pXvzsXBdK}0;SVUzW zBSd9q*P@DtG?obH%L;#?pEmLqSKZSM)22VbUcW?=o}`I4uL*nPZWYXatB5Ld`lCya zIvW-?4*uRV!lO2GFh6cKOWB&v{AxyFyl`i85B))JM4d3p=`^$WEMy*%zVVCmzf+2% zJh@%^4i0(Y+!mc-%&PbiZO$4&G5Z%|<JmXt*q=?{*f|m{ja|UAJOTDLHc;*ZHQ+xA zuA$B|5S+Rj16mI7OE0RkK%qlTQs(%5*%J0!vw#&ih|qes7TFX%fs6hNm|5Hv%2>Fc z9HoY_YTvPZR-PQ^Yd?YAEzjcX-{g_w=L2HdeNy<d<RHDx9{~yO{jt2{3_MdfNIK7| zSjLo{?D4{zBFiPQVDUH@L+%`g0mpLK^Vin2=GIv<85n@YDsvg1;m#8KW=Y;3`Nppk zzUxXK+ETud*LsyU5UYi`snT6pan6<!2(D8=1<#W(ZO-!l&(rB@*dvgdt3wKgn^}dq z75Y7xggqsHh4<Rtil#;tyqfEWTXsF-g2v^LUwaI2KdPDSNjb0yQ^3*te8}uY1=K%U zKmi9m(WQAi1v-C%OX~-*w&)Cz+pib)_3su?_3tsD8+Hm@AMN54{V$MqS}?cLJ%Vu; zk1~(h8(_I_3wLVLHKseE0jEwM$|BS!p;qM-9B+Jpe%1`c12vVx8GMz0+m{VRuMIhe z-FNwDn?RW1^$qH#04&_Ro_%*bK~r4zL+%$jrfS(==){;(ZvW%dHS#8S7WYUjoSm6l z&s)$&eSwjG8nP0GIH>dtseZb=f;PR&<U7iZu~gtL{G4%#X5>p(-z#6p6>i&$>0S|% z>I2T`;Af6A4hlPkq)I*{uaFMUu7&eQZqczH<A}wLz(XndxFz5YxK@t@E1P)~*Yk|u zljnrG9m#y!#07LL?lO#dcmR?<KjrF0jTAL&B}LW~hO4aOrq-#FpK!k{|Br{FUz%*- zjpv}@W{r+1Quv-3f=7lA;bwcB<aL=JV^Bj@^KG!Vb`jIHpU+CYf*{;Vk$Rg1-cF}3 zHR(8lltq7b@8x;04qeFK%k~!D4k~Q%doh;l5UUIR!Yvi%@-C%wu`XhP_)4hIr#d2Z z?UYACap-X_ZP;CQtjPs;345)gl(T%MgEY!SO=aE}Lh$dVDa=qUN0hL4AAMnK;d_LH zF5l2ZskMJ0xh;-cbJ`WmbQkj(d^K%;HJ&ttS(2u&0WTF4&B;MFw?$;buB+|@@rG<# z5qyz(wG84%N?)hB+UG#c(6(A}$sBRnK_@<BU<e&H@PrRiE79=HGA>T9PPBDN9v{_v zg&xW1u^!3)JL%78j88sYOEh68-bOKxsg}&@>K{_9y~!Iy|KonEzlR+AjToi30^~<D z^9#%7z_ax>uwZ>F|DB(P`ai}%-9Jy<)&)=-R3!<sO+u#$TD-358_Bx$O6=oB1QWl9 zqQ04PAo$r0z9OARx%92@{gw{IwKp)s8FT63$k|waw1i$weGZZj=RjR^GuvP04X>N~ zQ(T=MecKkz^o8D%vRWw^ZtW-R&&}wMLIZ8=aG}z~OLVeZ1KTn!@%g4$fZ#=<*1?5P zVKx%&hFuZvjvC--^@*F8IfxcqiNizQ25|7?TsC9pcGOrsgbQn0ge~)f=wp5Y(@E(e z`;td6p#2&2Fg-}Lw!<$1#x9NjLU~?BoQym#etf-^@4TQv5fMIcyQYx&_cU?2s!rlr z^YghwTOH8ZQw@gegyO`!SbAq<%j_DJ*?@9Sm?ZfQx;pK&tK};cmq+lQH1t_c1J4)z zZiWogSxkMJ84H#xqIDhpz-CM_WX+XjkI&AgJn?1Z7C5qwn8_kb*}teMJs-Y_<(T`u z4Op5P4~~hgoZB5!mTvV0Zpw9&|MyueVvho|y;8tw>p$W@_)laZ3rE1({WrkYUsgP2 zK_OjPw}Q!hU(H>*9fM(#(ew>m**33<<UbFo^u=B365M`WuLSpUHc^<ZEDKbqpo{iO zthi+j$o9+S6nZ~^`}KWT@wN}*vNuy;({grp@NsZ>DUIpZG+0T(tE!}L%@nd>5rjS` z+Ol;hYw4K6r0Qtu4vpV5``s<ptha`yZ_#H}qATe3Dvw*;HUjgWNYRRQuAtrP%=)Gq z;^p*72>sMq;`RIRMG}qcZe4@Sz-zSl(i2hGbuH4HK8ppr+$8<asu;1Z8adCm+-uoj zp+okXTQpz}h~%xXOGky<>s-ngE;|bRVc{O`BxK+|Cqk#caE{cdv3Y-@A=}@HR;fGV z(dRee!kGwc)BaAr-MMt;q$P|>-7WYJPO)7#6!FR02yh-cm?hsm&B?~xAibj{P_liQ zWQWW{x}C0#ttZz2)kL9{feWtt;ml9*eMOF@1$=NwJ$zm14ps><WY0xY^SlZ;aI2jR zGc=e~*AK83_dt<vf02=Je%=;*(Nlknz&X*;pk1X%Bc8m+F41lbs@uh`9g-*GrbrA3 z6__?T@o46fPaktfQ~xUx^1S5@&Q<@B+ksg)Gucv-?zov`<Gt9CW2L;!2!R72UCRZS z&0tcOd}&kp9I_F7qgpPhth+pfO)YDMIc6hZ(zM@n+u8*aiuPjeRb)d$oB8~tBd~3q zIa@sa4k+B8O__sJAUv&|t1r^w)bH(rbs|~*c-TPBFm^GUHft<uMhgtrgbkoOF&|U{ znz(e6VoJ*J0Ef{|*eHGp8jAZxZD*5chxbQnT6LG6Cz|03!RIsTYc<4l^3;B*2W(`w z(|&1FmbFK4;|5kqq^i5AH~cn#c+xL$u2_!GMy1jor%VjxmqY1rKM<St7iT3N5i*}@ z)qcJ!*}9T%lCs`H^3(Xt-<6NVZM-8I_7gl$d;wMYo?thRXwk83Ymgadg(eBH)Ox3n z0@mk4NJuZ$$Lqm6$91TA;3Itfd=bm8jNwn1UWSN}VCFcfk4v#Q$*$Yq=dBcCm{;d@ zG8;1yj(i(W;hY11D_IR6k8Y3*yf&2PN#6vm1K)6L8L*S18{lj5X7D>;giZGQ$oZj& zB()D{_iA@K<S8(?Um7!$?z<2a;>jkakHif1gP^#~4m;PGvNJ#0sAEF`W^8u1|00^i zUUA!?c2EXgY>tEelQXDUZa=qp$X%|?dX(hatO(RB+(_#;xv(R<rmzc`1etF~@fOP~ zcuAY!SbR_h^imdwewvOAYn(XQm9yc9nh)#PCXfDg8T^;6E|_0jNZgn~?9;etepO@& zZ}oQowEVFItA&DJ?0Os;s`RsWw{GX!&DY?%mUmG6aVUE4`awkzJHXy%FRL8s#1;N` ziHfw<$-MI>ue10vDP-Ehwh=1A&N+{Ug%)Gxw~1JF>jD&YR8WEbX$Z14myGcDW8EoT zeDuqG%v$F(J^Zu>4i6fKM}>2tprZ>?tSs5_<HA{PVMW7M-Qjn>9D-Fp)S2qZCQAIK z%$qSI+N%5v);vDTAA4fXjElYDbZRSE{Qd?dsnw|QIhLyPm7odoz&53Y(uB`+(7+fz z>gQ;@I9ZIZ%1yv?xbQu@HitA0J25M}v2@`2KWJz>NV;;fIo;Kv7%s2CoUMLB+D@tJ zC!I?<&(2?be7F>Qzr&Z`e(wU=)iy&}dpN5tyAFm`E+UQ3)_Be%2R8WJg6QC03bI-% zbmS#uaa71={oBqdTo0oeZ|^|%$x+~W@h_;>m1B6W72X*AfNp;G<;nw=Vs7V5{Fmaw zs=ryWzY7nET8CRQrILPV{>PjR%s&e|r%UMA7Fjyma-8N}$>P7XOk{(VTOgyX%-*Xi zi9MY-8OQsjfNQEeqQ5z;%>6=>=I@8_8AIUs?=r6BiV~JglCbs#wVa#fMe=Jdf;$1# zOiuj`=3P9;S@=ufjdCz}Del0Ti30z%><zcdcsvd+oyC;fZ_v7c8Dv-S3wAj0q;0aB z9)((BgXwp^MSBIOK7V^n%iB`^_6>DrTI0db{NYbGleW|E=qPI47cBZ|)d|7<g$6~H z8EUyr#|)2CeD1Yo&Pg!=jW&4Ulx-(z@3FZ!uIU?hG`koYLSi}Xi__@!mJ<Xc-jm9t zJK!+$KitH`m{I7*50fsU;$KE=gwuXDu=F*sVFRdWp*<U0c%An3{KwvB-{2fq344Mv zdjh_Os)sJ6{HP}WxZt#NE&o9qrFuB$0maZR^rpO{)40sS&z$0J7xLCjp`O_>EJElv zIe*gNJ;$~}l*w}lb58=P=zP&v=%sB6*)-JhF0?}mX-8G!q{@6K2{K{Q%hPzf*D-Xa zRf3kEe+&2gpHM371C_G+GevcG>}nW@;|tR8+GutD>*Bk7U+iG8C|!dAWQvU}w@RdU z45YU#WJ#Y2z^mgb9V%2ujfET7+c`rpY{+-AoF;>*8fNH!a2qu3%!gHqzaVJl12We8 zNKZD$F_Zc`q^6}wjvv)o@1sD{FN~u+gZJF=6{BfO>K69lUkZiQIOBAaowUSTjrq=d z1Aj~QLC%2|(Ss)zaDBxPyx{N4>U9**M^-rB24}(U0Y>}>sYxvE)I7mYcmhlo+2K2n zYxZvo;u$Rlkx@hqd5LAQDYzGkq;vSlpNGNoln#A3lm@m<$1r8jCphD_jq1{zz;bGl zB){?^-3>NpcE{F=w3ex1aAFl~y0jar?<lgJUh=$xu>uR~=1{Ys4{8NzU%x+n;C|;P z=%*nA6&-Rs7{u1t_QNP|EA}Y45r*h!u;)&~<t1o7%O_h{Ab%N7PaZ*&?+T2Q^^bV< zDl3HAF_P)Ui73P>Fh))vx7>Wo%j(aB*rxk@mHHWO+?od39o<Q;`j;V1brBn;H;#H% zG|@<dX0j6pvW(sa=*A(C$~S`9fCf7EXewF>{Un9`FA35lRaTJ)n8KT-%<(~s<ZfsQ zopwtg1%>%^O!5j+KB+;-tEccKVLiD0JO;T_+h9exHxAHmgh|0KsMdK58VvphJ`rEB zx9b|kjg?_V7xF;<hB+mStfGj0GWNg6r{ZwcatePX@SeKcz;e-iT375VWHSVYWaV4% zOqa!5!W{62z;I4hISnpKkJ0b0uw>nr4u72Xb34jiaOmP|;QXtS^AfrW2cC=tua(v~ zqNyJaf27KC%F@^l^|^R^IpA3HUTSQ~hSYmeEadYbF6KxgxCRScA?X1y`;`=i$OnjG zdTS^yK#{r091tD+6^$?cOlEU*g|lJs9JDKbA-Q-r3TJM(NyBG3F!wYyG*@;bciU)O zofONd9UQ{D6#s`edJs3C@?hg^YT1w18*u#j1MuU6G4|_eAlowuY@Ndsh>J;}@O?q> zB2|j}InaigwK{_5oJ_uCWt3PeNDmv-Z_%_9m2mn%8CXBtKuUWV4SV#MeP3h9f-c|V zQ)YzmXXF~7%ls)!7%#;l-d%#uU-$WK#W&Dsg&|v-aG1^9@4_Vns<PysLV*jDDLGWN zikx9OoH`VN$!|LF#nNebeES_}tp5yun?^I!1O*u2_W?2vuMusrlVwu<qoH4Q6i%O# zO$#r{kb<l*&p}Q6{-VE-Ngd2Kb-aVnj2OWcx=W<$E}Tc$!nx1rghh9vSVgx7t`N@K zse@E-g!c?uXrBwsiw^K9v9mz(@FV0mJO<_8so?z9h0Hd3l9qKU8+ZRIOR3yR=kvy~ z-UkINU|S)63wCCjr!pYgdK6~JR+87OHSo*M82>wB$kzWDN#ESA(LmLMwB!94iE{Na zyqWtNqHDa^rnkvd**X$G+zn*kMRWOf<7(dfh8z2<QOdi23nFcOEfzgW8czv(s>GQN zu-nJXVcf<~tYink#K=qhLBS`XEzI-f4HVh(Tba!66+w5xUKFo8OUvFLgO}Nn_{Vq( zPW#Ue5<@rB{d=>}Y0U__{Piw5(0%y4{W5x~1%r~@RLmJSnqH(H=Dzow0M!Z*8HUfK zspm(+{dwsir5GiE?memV!E!oY7lV_xEeGdS=eeBuk71FpH=MqyKiQrghQ;%R9$EKv zu>0@`4)Mca=R|AFlAlV+!|nNZk__N)4q>BPX0i289VlY#32yqoD^P5;fJ8Dyq}S9) zkFGrtyf{PnaFZeEH1;+1&+LMX=N0VbvL6t9dmuB&65i16W5tyd{?N(OHt4cL0^B)Q zauU2L>AW3&$QXg23(840Rt3L0KB3^e3>ea~g1Nb_qvyJcEW>d%7=>w3Qc)*N(K7(= z7cHVs7rfD`_AVb3>_s0uYiLx<7+CMToNxTGROA`!Pi9?h^x%pon7#GmC(b#?uC{tm zfcH!O5~l&(aox;ftgSeCp*l->{eYhT+zy+!g=5lqLwJxb#Vh&fvD5o<$*aYTCC0RH z`)q&G_T00a{Ebv<elv!Zj{QvwcbKy3nfqbiiX3WYC*jR-S4>=H!&}y@;mfu1q5H;o za8Hzj;W=|r+^xjDy{U-H#>>-zWuJJr9j<7av7B)2Bu+Yjk;6R~sxVFB+2%!1`Zx^g zUtY(VPYXn_F@fLLw4bdw7D#`lrgHNZ2;SvMN|^uKLvWW|VO^pWP{~>=cu%%as%0G8 zGW{Kd$&H74|D&QM8w6JKxyfWgF_LA!9?`U4QK)frBE~)U;0ryCu%&+<WHkrjrtQO7 zf!RUOm92qUPp^ULMuuTWm%!2(Z5Hiu6lHXzDfUM^46OYQe_yR+1qbDs;eRqH<rHfl zF)CcLc2xidl|G;is>4|84JjP6K+3`W_DCk>`hk}>m*d{H9ATEfmO(;Hh?v^fR5>{b zZ>ap`)V<~a8h(+LgcRGcoeu}I6)&H0O5H}Z>5C?Nzq^9#R=mxt?5m(H+Ii$H(+Y=F zQtAKR?!W8G$WCB9LWT@VuUX5cCLf_^QX8<mayDP`UJ0WQJVf2xL-2LhM>5%u_;~RL zI2mrk-&-2V>ZT4r!%g`#p{PG=+P0fNnwn1vgWvOpJ+`c3q%0=){f7Sx3UGG&C*H;K zD{;23!LlWf+oLU__<>Gr*^U-oXL2u>ox7TK*;VsHm+G>=m7A$hbqF)7k0kdok4ZIn zI9-t#V@<p)QrI!n%N5*8LD7);YCVfOb(J3&e*~fn3uwfeT;9Zf5#<ikgjwNAtgB7P zD=gDzv~GrdTaG(vWgcb4hZj+~!7h5Jn})4Va=;{E1lErg{BxJz^Q#KQ?8p`;2yOlg zrt%|M`-e!lB7h0+H8qH4n>LcX_iC`av;juik7YKt^;8lt6k}do!hTy%aK7%|&=DmD z`Os3Xe3ldjq&YxKk_VVp9s{%27dh>kb}n7WwW@v+F>pF0_<Z(*eCmJHoUV_Hb+qtO zdLn-4>Y)8@X1rteS+4HlL}uo>lewm8q0LrXOfp_h585nf@Vy9fcCo|OgirRtniFXA z^l*5W=>!i7jWAG6278l+k-xZ_M)e8V!>wYNHAW6Doz!I0EIyOkjd`g3JC1zcDzn9N z1ny4iARHPL&YkbGW7St}N#lY)KJRZ0cNFS5X#RrJ1?R+J`6M<V<u!@gyfOCBHtyny zQ`lUwfHIRy>B#PnR66nwr*vz8WQ@G9zgn%s68}RwA3KUYD6QcW%?jZ*R}A`3UQ%~f z97V*Bklc2#WB*FTf_E;2Ma@148&&mb*nc5RHm?^je<v=iLsoUMKr~6n!6sZaV%2T; zIfrJ(tM!e95iZZk=W~-JLg2U?j`opU=^4tJhiqq$m>H_ntFdlr4uWQl#L8lUSF=pW zh}8y(3c}vOvMF=0IW!xF*({_U9~%}pc>voXQw%HK3mk!%!8p>*j4hAu15>|PeghLy zCr5R0X<8g#l<-s7DYU?^ce&gM<q&~eYfEc))S_o`C-*L9D;mG=C!Tpzg<JZ0P_>8K zVRkDtn7`rhh&TB+Q<&Y(#SOa~p=GiYZs~nUU;kFHwA>={?Q`J9W*VVyKJk;637^9{ zDXc$mpQ_YL;OLuRto@S?g_G~$NOKt$bs`sHcf4ZvPS4_ojuu>O`;_U;j|3K;rpyGH zHFawameiF#1ewpucxcRbT6xh8RCa%bP3Ppq4|MMH|83|La(Q1Me#cn+xM~u$xZdU} z+vHiaFi)9qXB2DSFXZYDX7D%E!r-*cV37NJ2>#vKjnS#)6lkr)=1)I|<nn@VS3X7; z!dHOSntkN<YLCb<r-$?2k`JBdPSYuYf2S?X&x7STI2>I~GCmv0$J!o#n(eE~^%}>$ zp6o;0I7>*asD}}21cr8BEp7GN0M;Ex$+b=ui*??LhHPm8PbVW5*wakMEq1{EEoD@D zK7{M7Jp(gm8u5|hc(nc&4N{+bM0ff+Ky?WZ37d<crAL!BpU(orr_n5E(+$zzSAsvl zv_RA|ZUxONh=Qb)$DD@P0^dJ2WK-<ouxr>-oIY_63@)e@`gS*9dT%7`3D9JwkykmD ztq0kM;4Dhk-w65X0vkH-vE*9(8Gc6XG<w>kgvr8pZ&BYbQudd_^6W%%R@Y+@`bIP} z-V09dOa|4%r6kfH!5q(xqzfZenfXu?EMG+!>GF>@XCy%MPE#~p#8a;0I99o|gi}+s z$G<P1LWxM|ZODG0jfb95m+@GLF!81=V|5Tn9i$=N#0Q)mk2`;fS=W@aqOb`??AwL; za9ikHlxN-~-$QPqvC1DfD^m|VC`iYS49f;V@h#jp2#)=-Cf>prYRwBN=Hhl(hyJ87 zDxS{yeFTLbSvIBV9E^V12gWz`@K<*#TI)OFvA0)v6YE&cNvw*2r+E-<G$;KB16ixy zD@pX-L*!HR3LahfLVs`n<vzLUvoXS;R_gf9ibPixaCcW^GYm?=aqLe}tXjmzzZr_B zLvv{LlYF@ADdI(chcKgKH~H>yF<_GNiwkyD#NiJsnQ`A~Q26Bwf0vD;+>1+@&(sKv znIi-BS|4Fp^-}<?Fx={B2})CvxwU~YaMfrzTOzy@zMA*&Eej@d6ZS?@qSARf^{WB) zmjzOQf)2QaoUGB~OsK_e9C<%F!5@0$#PPBRXz!NQWGK9A2McW6nRc0UZm}UcD#XHq zZ?0seDhGSMgrL8i4XT$P;x$t)fpu~u?;6z){Vrrf_sJ7gr;{c^)U=g+gzio7UFMBn z?Z>0^hT9~cdXuu}d$5ger&!;L3^-w|ND-Su*-^D!Y$fN%LTVOLgX=bM-)~Qj@zTt$ ze=dp2p7Zk$YT<LsZ&aG2Oi3>vL(yzmHbE|$?;W=pVuZZ)y8i@sozQPp^4<ZDt_xh~ zcj?^CIp*m7b1Z5^NReLk34XD~AU5-S5E!Ojp|LNLu}XO}S|3<N-;%Sru}9m;A+Q}2 zlYKZNvw4`f(TIy*zn?lTC}D8^SIEfA!i>}+iJP_sotKZ2sOe3_|MtY8IQ1O)a0?*n zw;7vTxD7ThjAq5>^+|tl8k_Lv9b_!gVj3=Txc<co+;Maqc*cH&b1|2oxjT~L7kcn? z$(uR&*^r8v7f5QgnV()CcXD$*txy<46+Q*fc2JACUO4~(%pKR;D6roK^I4a46s#F` zh?Gyu<4x-vaB(z6&$D{$Y~XcB9e=|<*XS%aq4h8XYB#X;ECONfB-n-hQEL5JSmd*e ztxjA>WB!YvVx<)B=Wi9LK7AF$73WB$cojc(sTPc1nvAzR<ne0kAm;mbBiO%A5DjXU zW*x?VX_b)<XFF~KSZ#|0t2GLIjDiu%wZ6ekeR7yCO*#P)ci+Mj@f%Jx@U?KKdjJ}H zd `G|AueVydIBaBiNBoZIO<`yYpuS;^oK$};&%QiCp39v|g~n$L%^7Y>e?l4wgG z#<ha(iddMjpa2JlX`<Q>Pc*aX;BNO?p@qOV_RP6K*<;T0DYeRM+OtvM;x>=PgwA1= z9m*`*HjOIGma&>Q2jS+Iq0k=I16KVe@KtstF!}m?c%D{DcN+w6Qv6BwU8ap%b`Hjd z-=Ar-fdTdZZxZZi8;4H!OtJl11O$`~#2ed<*mnbc!3l5%7i7vq-T7VAt9=?ef=1xU zYa;R2n~_v-N{<B$kfT-dv#C5if&O&G^2&vqkgIZ~H9jZUOEVn|*&)LZd-n#4_8b)b zmQ};fAB!Z??dM@is1=$Q4B@>7{=ivU_hIgEN4TA9!>{Zaf-xIi;MJHBG~w}PX0BsT zmevFDi0Bo!WMn%P967=qP9jz&1fcuKg)A&tiJw2om`P_R(IDdhu=4#!lY3jipwSNR z>HLA>f$8*qxdP*ZQ(*nNXw(uN!ajF>-0IQ_>n@awf@OAN!$YC>zJ3VfS8N4Ye@iy9 z&k&D4+s|J<qYG!BxMP`%EBc@QNZ<Y(VQi%y+9(!s-i2r2T45X?RbIqy3Z1hu(HC0w zteJCeJVawt)Tp5AH`wlp12hN}_dDJX4YeyN_uUl;vA-l5_jwkn2)ojT;r*)L?J#Bu zEEI|ku43P@3W|HbLGNB=(3g_M+EjOrd-4|jmz0vlf9F_GJmdQdZ>)LVy14n%OGx+C zXU507K<j7<WbR2vv7$e2czPR>a#Nvu@oY9uPq+_rQ}`o}i-h@9Bl-F7;>;)JV8+QQ z^xKY+){;za@lI2a)L){!nF1fZVLZzJEM~D+X22tzaOiyX15`t`;h|hAQ!KuOUM8k^ z?a4H(yy3xr690jHD+jO%F2e5K<}|2|{w12`RRXhY>L|6Ll%(S<*q@=fEb5CoJ8!GO zQZnM$<lkOc9;PHXx0dng?FM*!)i0{QIuL$nOvgns)ztJ=j@3scv&S_@x!SK!`H2H! zQ6(`7rCSWxlg+RA@tdSDYx^GdyJ`=o68V?6up7)qz0MZ3XV`M8Uv&g;_chSnriDKD zEa0cE*g@%80#mA1<n)EN$>+(Ms44s`XXg!I2Lp#O&l6gbMK3%sO71?rRjG#Ob57!Y z;k#x0QUlIxRU73f7NC`VwEdCs1KE&{IWS{n8ajQ{;D!a6VdeXB&=FW3u|tJ!!Gw=h zQlB4@+Uv)>=-qozD*G$(S8yTSPhTm1i{R%y4x*V4mw|2ANPINvCO2L65a@0<#QKzl zoR!gFoM84?;B;D2+(<n%dRb4_Uv7bMiWD4uzmQaRC=z$Kit>{-LHhQiyl(1k%4wLx zd_G0;b_I2u=NcJFw%=qtGEt5u{EUP910?Lx0%hE`Wi)H(+s#P^B;biD{&e|^2F`0a z2i-O!C5<nKu?&A><UTv$j^u9?<0<ThMBUUiOo3N5IKt{CUnKv-cFf5?0jy--@Z(+y zj*u6FC8|2FL|@YW!`(t2sjJ9<a_Y>PY3E+xAMzwt{KHp#HKE_1Jt^nES6p1>A-M4G z4znD;2hvVop)Bb~oNZGEHM9>9i<HN*S*<rI;r?eRa?(Ll$JbEz*OeBoO<*@u_K~!& z8OtfMhSMG=X&Wh`Ohd6GQs{czyDjXTmjjE+dIJk@8VUdA7w$FN317!HfmMBnq&Tw= z!e&fHUxOL&!rmO8Z5siXmd5h6TCXK(Q45GK-h;Zz6X<A)GFSv1AyLjITKgx4>hAZG zu!;g0{PQQyip>O>>z6t2%Mt8^RyIHN$!q@JbStcqnTB?<Q$^}3ADC0{2B_VB2viId zDK~31OBtNSW!P4dc}^6!SI-)|o?7r{rp@AiMc2_*E<<4Ld<EO0T)I}tp|xiVOq?|c zKOUXJUXOdktqJ}gMQ0vQ)!RjJQzcTGOd%wxkW`Ym=h?TC29i`7NhS4DNtz^?GLw*0 zlFWq2kPP?iEossup;;wqmNcv0^ZxDQez^CZbDq7|THke(9o8KM-}~Q(ZOa1Kbt8H5 zN-+g{w_%dsCtX;GtPEr?(<8eYBU-Mc1nz65@t6I^Ft1$}(6d;cZohww;r}vN%W<<= z17_)ycf&gN<Yp#L7fTB)%(Hyx4=-`Tjbp4XNtxQ`%FyN8XW+-!K*_=Fhqz?z3FxtA z6tXORIxci%^nD+}Pp;SJ$4!aAaITKO@Nt>YDWAkyxmi=2)@0%Lmx|(T;@OtWLUK?X zOy|>PgS)0Dv((iF!&kS3ZXJE-=VHu0^yq@>*4eNj!j$pvEAU>tDM;HdW>1$k;xKb5 z7!A^Nt40qGmb}C#nW`{V9bjY3B?yf8&h6GZ&6fV&3|oJ@qJ5b(r*(4zIi0yFI-!4F z@LCCc^M{Fy-)~6ro^g_h!PBUJe;X`$bqqCUhvS4JDd6z&GB+h<9ZVHiuxG6d!Ej<S z-EBOEJ5JPzx<fAWMoO`KQ|NM>Io^(q48DY`PK;)k{rb?GKgb%2Oi{{bHN7wP!%eM) z7)+5+BCt7~I(G<Frl+xYe-2;Ka2d}Dvrz~qbaP%eqE>fR{<WsC|6U|w@9Hk__L6bz zPH6<nb!_Gw20W0&4EfE%Wlf=d#!!^sCHRG#N3)lLhp9(A7W$WsK*KW^nEqD=aSMrS zFEwI0Q)ZHKwk>VzmBEyC*SQU4iFi%e!-h`i2Z>wP!n^5j_>MvIai4btZx>pQ=K@EQ zW3PxML@ouh50|*Mz^$m3<i%&roC*0sLPz(maRLv&iI=}2&(yXa5S1OtV^c3Z;;UC3 z#hNjGEM}PrYibB*i_)S{V|xeMH0^}=7IjuK|06aW%wS)_#q4q84AggYpv+COWaHok zYrkqB%FmJ<9Q_n>|JuNs?PB^m=PQ1HKNBox8}pkFPlxz*UD$tUCGOw$PsnU#a#t4Q zNbWce;1eh9rwNV5=pLSj{Zr<$rO(Ql-jK`8EwP%<50Ai*Co^$mls8%L(4@L3Rl4JU zkMn%IhEq7_PsfKwu=j_@fn_Np=K*2-Y7J%RQ!K}`fu;QQNWeswKyIAyH%2)Ju(W(t z_APZM3rlvRoQyastA5C0y_b`r;(O-1p@2Q?$z&&XSb~w$r`ooUIgE>30_RR2VG2X$ zvDn}J$=<08*HmV+>_=y?bKD2^KueX9G6R{~ltt*Y?*e{4yMRsKpM>=(*{H10#@39Q z!McZ8LOw<Ezt$ZAor1iYs(~Ls>R}*6hR9-XOc#y4zLqpQ`#7nD(CR@uZi~uJ9fF-j z(adX46B~4LCYEhN+Lka;=%bT@uU2<iOqT{fY10y}Ce{H`qI0k#bSr$jG!gv9FXLq# z|G`p$yYVbamR+eHR=2F%2dxw|$z41NWqTuNghf1es##z<tunwKIl=!qERET6IoPHy z$dlvyL#UL3*fHju$S`3oyUXG@X1f*^v?icIW;Fkxq#NV^i8%K!0hBWOIzLH9nL1wn zWk=LUvF_Oup$tyK_rqB@(|IEu?~Q|oqp3LJV=(`GVGV!x+kCEI*l9HJKEQ5x{ARS_ z7W!sIkmF)02<cSeeGlH`(I6Ddw#~v#iX6Mrlf`UJ61eRy#-L)7!|Z2`fN(8G(uf-X z?i(lKT4!7Mw)-3R(3aTpC@b3d@-Vt9s&e<)d5q2LNBPU6+4U1z2*>w9$nAXQ8xSZO z`%aUy9%avh25MpD@YR&NKZ74|A%blDl2A!3i}>y{=M$(TFg-T1T7myO|17|Ppj_Oy zQVG1R7J$66nC0KE!)H44*_1ie+>_2|WOk9(E6>g)hXuEAPJ0kL_W37sUg5#7m;J<> zdz?h;F~?a}Z#W)1bqdXcbz#Edr`YrTGit58hE)Uau{r6dSkKCSG|)F0*HnaHK+ZmV zqgc<B6T`rG_(aNku%C6V+W`(j|6Jm>C6re=9MuJV%FgyEpDE~w4=vI$DIo|o5-zi@ zLS0(Y(ZCr)2EHh_=L(iDgpom0sRMGE$)@AvdF&hK_d<j2d>(@BZRhzh_hew3-fmF% z+`*-4F5qkzOGEkhAoj20D}QHQ1t&LK1vljMvKwpkkQ2O8Cr&otgV8gob3!*O3)?32 z1kHh>aqHOZA;HjUIEh;weI5h$^|8l?gwFLeP4@B2I}FcOz}<G0{3ORdw&3+Qyfc;9 z4Azg%UU-R_Zd;h^MNf&j%?R|#xz1ib(13V7Yf|pt$!w2nk(-(ZqoXs>G)9&bilxXz zSDj5b7l_ew=7H|HLehzQ%CGYjECL@&@qBg@@4~NT0rFdgxxbB5vN_0-$0<VK&sVIu zHkFGEzRzTCo0FUWE!_4=mF*eul{Xf&8aW|@QX()l)t;7fmRrQEPxacR&O6~4saMQX z(R{jAlfVytHj-3QBC%G@pFKV$54QEi825P~d|KGfHO{yqdE{QsDQp}AkL4e-nB+EI zX7Etf*w2`+c`^jN2HLS-`QbQB6vp<;ALI;f+p!+`Znj@~IGDVVqYqEU<E<7gikv%( zDq1E1CwSVtzQs|!Y83tM^`!G-rRhjb0c%R?k_4*dW97&U{Bf&Q5<X!AOnB6Z<9EM9 zbD93&9l4oIv_9}R^iDIE^P@1_?>Z{0eZd9Ny_{L=VDj2ElJaL8L(z>fpxrW<YqKrq zWB2!A!<<xJZG$G7+&uv`0dbJ$QNu0j=m(8^f1r|69=Mtsiyj(yLVD_Tyj%JeSH0TF z?CQIicT5Sy)eHakf5q4~MGG~Zonc|cU0}rq^mxS@=Bji@6p+52MVybN)|u_tFCv6o z3}=JJqC`BOx{8f4u>t2fmHgC$YdN=bD_Ej?5c_s<Jf^9ONN4eH(La?YCf)oCcl>vR zeY8=gq)GmmeRw=X9@vkYggnqi7h!L9-JXtAnNeDI7GsBWNc)x|j1$=A@!MvDn|=;& z;PZf!f0rprT`iBdYjwbV-bd<^L_&7rD{fI-D301a4PM?0riz(C>{ja&?gW!Yhh`rx zSFwqiwJ70<_FR6-r&UZeLlHJq>qDdKHT?Zs3w+OQW#jC!@a}{RZ0cLYHVnyOR)rm` zXnhFkY}BWXkw(n;OE%we?LQW@bv7p)g*mtCC)^#)680pm2)%r2@ZiI_G%=P~@*gMm z{rDX2z2!qR>3;<+$N8f3)Y<%1ell2esnL>>g`jtQAbu}42Kq4+w&mr)TR)*kU~wUc z=iX%oTWsL<@%cjc$7M7U-{vjGyufc4ySPJzZ}7i!8MN`V2|e7Kg~}Ial0jV`f6ads zBrKf)$}h5+uIw?+*|Lt6mSo|j<3m8F>m0S89*)fyG@w&GgwyB*_T6U*^ERCWmUVC0 z<g!ZED0D-2EQzC;aogd?uO5&<36nXH!M`5%gL`!JI%`qgDE=_c0`FXZf?9JY;FW)y zxxpQaMJp#+;gWYFV9e1F9Q)rZ+BIJnW=}3<Ll@SwzP6Q|;m(E7854#X+lyHP?+mx2 zu5%^YTH+Kxfs0lY!Jd2M;Hw0o_rzr;U$gI4?VTahDE!k{st&JW3%vAr$0R9Yr9osk z?ISaHJp!+->?vzNqp&os!}e==X#Qmwzw})Pr#Q8m^`9HX9iM!j#a;>G5B!}%xb7|6 z<?IOVJMV&NQXc5vyvwfc`^jB@>&SeSCevJ%-Kadw1bV|ZQf5k<<c*p%sr9dC8D*cD z{I3^G`_XIe{ryyOXw6}nLlv2COFX;N^ni=6$fx-&{lU{fi;S!hMF+*aUFI;RIi`YX zZQ2O(=I-K-=Q+$@)FF8M+)?jv9fltNA}aeV_#^cHP+rnIJh|P1&HIu}Oz6DZI_ncV zcR!hxcn^Zd-(TW*#~+|we3hGGok!+-60t~jiNHfQg)Mid!luVgwD0V7Hd*mE4q09R zvRT$Fhi<V<VTY8uH3cu;9SLFM>hRP^DK=Qjkdn`A;1{GGf?nk}eEpM+*ga~FNL%2* z?wI!--Q5S$;03CXlG8y8W5$BorEDfOQpi_Vj>Ip@K)B=tWEd+#aKEW=Ex(*)y}Qgt z1Ut~qFZs;#Nh5csX#i#GE@Vqq9KdkpF|={pW7Ilxm>$=eQn%edKF!#N3gS}O_pkFv zMe8;iRyaVJ@<3{H$l-4MoB>VA63H<bPEFfSlDf1!JW`cnAAiI^RC6K73~9ogo?D`n z7gg-Z)E#8|`yCf+=7J|)C*xneG_1FpBk~@iLd{Qom?TkKxP}IS`hoA_s!Bs@U!_F- zQ}e-Qfh!AspisB8_z~SNjN}c@6j8Tj3v=DeAn0T=?ua`EAxjM*K$0m+E=xh@RdP(W z=?E2v+mKm^Go)^-hjXVg@qn)`Rk@o&?ra_v11bn`INX}yKyO2uvEgY2`s!8SU$g#n zIBFb|y8Vb#JFu94KQo%$_<jY`8>PVNmMhi^K39_ohe1*p0UzHY8+zJ{9%pO<>r2PT z_wOLE(7KHCj$Y*l3%t!0{v&8yXA+ha60^w25IuLWr?*EhQnA-`P%eJSD@-eZbzy;+ z%^on1{x-B}#8kRFz8__)tCHYN;U#9@c#ZzSLU*$!d~}^ps?~t4n`cnUhh1QNrC#uu z?&Ida8$my;*TJizArvAjqN}SXvfh<}g165bJ};F5<MM%EG`yN`0CVaJvq!UsCD`(Q z7OA_OhW8%k^k(E_fcQ+PO^+pI@~JhNH-)@eA&H)B2m5ye@sjZKK5rdz8T$stISah( zJ7(Z`^($&jy~u`V$%!WwZzE6XKw6@7fi*vjq1T_~A@^tpijogu`C$|Ec=Zt%+0`<u zq;U2yM2$x5-2lEXHLz%3A!?0$1uCNvH~4q51t&6~GWQ*yLcQGb3yWd=k+(uVNeTD? zN8q^bA^4^{1Yezb#5T1=U|&cfs%uUpv2dOGKbA13E`PZGy%;XHt|8OphvYE6liQIp zj_GL6;G0@Ef|(A0s*W!mPY`;r4fj!ZldxlRb0;5Pd0O~T1EpM-%@m#Z!SYN`)64n# zg4P+zx7Jm$+evv$v-20e?_7rplQuv%Hv*=%#^Ik*ODY+(3EO>kvZpzApepPN<Xmr} zzGne*nEIEq`nQf<aBD|7eM^krISg(-PGe5;623$2Hy>R2ni-#F6#si68Tu;HS_KlD ztju8Tve6>9vCG)I%hPF5gdV<IZzUEl_F_A0Qz*X5l_WZXE9{sNi&3}W%U(=oYjVet zQ>!!f&r8BR*T%w&>UsS5Voj)7HI&~de~z3t9YrUz?a-KGgdI{tp)M(#^K%_iXCJeV zT32X;`0-qR?yXe3{&FE4`XmJ=x>o_3w}H-zQ`T34j$?IV9sX*Hf?o=NS~pASh=(=w z&KN^yCkq+n=F7}MY{>;yr-Do0K=F7%$9|aq4a&A?pqGgOvo(k%*G8ZbOH$zXzGhbQ zSC8N0G6gdKDdAV&Qm{RghuV|Au)04kLSL#QWS!p+6UrAuT2BTZnkqwH6|*Gu?+VdP z`!veT-9>|s#WF9?!@Sq+g>0C*G2~jA@;x8!bMF2F>4|DM{P1_i=7mcs^xb~+l9W;W zHC3oD-yqyh7I9Ctq`_y0447Eju%#n?A<=IfM8_uzGjcE`wPmx^1!F*P)Z&D<KiIwd zYw3YoA-iWT0;RrkxTw1k4%SYD{M;L)*JqC!FVonh!d%#1(jPu<@q}(IFH!gB5|*mE z3g1f%>DS1+DD`O;$X^v26<rf>RmC*Oq@|d*Uk&^-55oO|bF`sn1Bu_7!QZ+Yc<X2? zZ!_Trx}K|M`nB8Hen}qN?=CR0ruV1bvx{j%7|-4=J%LRrL&)&kGC0u}0I!|X1g^Xq zJHKcFQ+Qv(;>r$kf%A@_$>cPq`b3NRe5Gm73oG8@(0QCY?-}Jx4`Zi`hEjN-9A>L1 zQFG8WJTN#Ad=}<P1{o_;`09I-f`9#BbEiGTDyfp$S|$2c@EEh9lNoNz<~kL>;Mt*v zQ0Dm&YFifsx3r?!z3K$^Bjmp1+RbLRR`4X<`Eg0)X&HfA4-Fxs!f^8O-iW<VG;nSE z99S59fF$b=!o#5fxc+N5);mvudr>c7^z>UeW5ZnN3+$7mXS<TeRwdNYo(Re-^yz)= zEvCDEAC1;?ptu$Pf$Fd6V18~Do7Xg+aNJ#d^g+m%y3OD(==*@_u>_XHoY~y?LR2;^ zqNZ8#WO-)}GyUlY6TYhp{<~6)OOEB-=nR<!1HEu@foTG}z%MQcrGhrjoaM8hd7j}Q zv$_dqXj}!&QZJTppb~N}l;NHJ*SMwUK9NJ6keSLVLM%VXJocX<55I0U=AH<gUd-e~ zF2_MCx3pSbH;{b_I|=U3ezA6^0n~Lr0OE&zXM_I+Q%1chMBkI<kLMcWvL_#5qUU^) zWVB2EN}Zt5@;>ZV!)mhf8_)Je29fvcOL(uC#~)LyQKkGh8*1dkUWeSlu#_RVx^)cR zC<F1Ge@S$rWi5z%^6{&1KP?ZLg8^>cwQe?x$kR*;db?aG#7X@BURm^+xs$$I)njjw z9Zcz23m-$BXlzzAJzCZPcvi?R4)0?=i=Xllg+Ez^^hIp;Z^Wkl)^z&SX__#il1@%G zhTZD_(I+{HpuaE1uj7KT_E{A)=cK{KY=MP*ww^_HRN}{1vCQUy2<zGvu~+RRN@+JR zg`0Dk?W|?6?#*lxc~6wg4+m!CFdC8$6iJRQ)1j`Fv1Fj)N4{T{GyBQ+u%YBTevg<3 z*9&$L4qU-y#s;JPoI#W=E6=W8yun9A9D*$$Ua_4&ZKypuU+8uXf-x4p?4pJNOcc&F zIvu(E$19FZsIX)0ON-HPm~EZ6o(lOG^LUQr;B;0COYIWQ`JDq$w^M<7?p5NX`Wj3d zVZ~V+`ct;x`1d^Ni&BI1MP{H2pM<VWhn{LK`FuD9DGgyyfA3?9N-c0zl8{l#7kb=x zIdS;*S8cP`W_GCa3x=33qo|BLNQoT7t>FK|@Sk_sqQ&>wbJY-B@NPT)x*32Cx3VFl z?-pMYv=G{*#q5!{gjd-j1-LJQf0&s=J0gNev(TB7x)D?J)%GoO_;(bXYEQEb>El>W zxxhfwafS8iry#{71U8KP#TH(Ph8t#&aJbfAuH{9U;KezO5gUFn8MU+M5x*FJC&bah z<R;kWVa~<w?@xaeBrN~sVP<$vlRW#aW}`}`fK<94``aDHVqQ+9{dR|-W~dfuo*BWM z9|Rz)7)8%+l#=ogFG(bu%*Pj<qmCC7@#aT$7P%vy)*JN)gK>IvMRJ);&4!ciWNq53 zwh-687*F%YEuxJ#gro8Mv0U7Tlk`i~gBG^rvEud#Wa6C<mBBesGjIoU-lPI)2dZF$ z!8ajKwH*S5eo^WB`t0!c<t#-ilohFmaldR7XuZuh23OrK<(+zfnva?}l(iv+XHHaD z6$MK!%%=L*L)h!*4Sj3G*#5l8`mI7D_x{FexW(L9W_ub;RhrIr4-go5;*H?D;TDtf zStvsJC+vuCCjFYEMK>}enEm@S7W*xOxr3LHj=^%i5iG&l-xyi&dtAHz9Bj3brC%~u zwD?ssvs$0S2m17&*DV_s%M36_V9Xg!jKT`d6bupRFb~5ASR?FsMO_=vQsx<T<O<h` zlqSi&45R8n^H}(LcWPU)8?4S4QJ{GVWuLVm^CzlIYJr)=B{-YTSfrui3|*LJ^PEm) z+Q8qrrL1f8UB35>EsNW8MWh!thUrgmf<dzhRBF31WI-j)>vf}$iudU8YaiQE8wmab z!dTxuJ$jh$00DRMtetwkh>ZK&g0zw}nVL6?-uT9m`0v>NtM2p<Kf<pihRo`K@cFL~ zgyNB5qQzM=NXo$9%Jc4FnAXyZ%bRZzQ<%m0J5O2I#&M7oC3OAzc#w0s(8uPNj_*3` z(foiXnkX6JwQH96a7#Ix7PbgN4fdn2X&S2>V9jD)EP)@Bm$2<-YhanyNJy|R!-q#t z!LRMz=$}0b{tg~a1ImlY<NFs-_ufR;$|9N9sXFG`sw<I>m;n{rrC`WYMd)jv#46S` zuxUS^;OYfG@lRO+2Hmd)x1zB${p(5Q+pvkPlwW~mqO+iGnFJY9r7X%VgN~=Y<q||I z$!ui}+P+gKnZbrISqfQ=lEBw*(5L_82C*rUVB8?{RN%S&<#uk5hQaQ7q+~w;r`1`Z z?b2=xdNl}LO?=UAU<CAhZeuHh9f4)%aba6_fZFS;EMo0!IBTX%vsgR&j*CXy(P_-N z{u)<2x<NAazz+Cw`UL9W5&rK8o+@-ibZ6@k&bZ%O=D6rGEZ8(0ynEcpCH)W^(ti}} zdhClQ<qyNL-eiG?C(N+6d%^EdBwEh8g7ucuA=GRu3V>Yjvvg%^ei&l7Y#gt3`xWzY zRumh(7>?3LJ*X2gimNHBXDLHw3j_o;8XI~9-o}oHgwrdi;jBGBaJdTJTe=F&le*Zy zv4iV$Zk)C@Se}Kih7=0taw!;WcbM6jm!qS;3jMX+0iW%Rz<#Bfm=&&ofZlD^YL!J8 zMUT0MSsOuR;Xu?Zvu6TLlET+X^CQ-cpv|#&sVX@MPfvNyKAf?E<k)^#YamZ%gX5S_ zv?W;NR)QQfv#vR5tkh@)R0jC)?GF}#@vvyD9lrw&CRxD7$pfHzLKRe+<guiCS}@{z zKg=;ZLt#T6qseszbZM}FNhklIW61)3;f$FmqjVJGHs!L;OR1<CZ-lqfb*agfG1FlW zps&9g?aM8t35k6;EZh)!*WD!7C|mAqgc~j&9fO^VcEK@^c=524+VEkW6<+I-;OTLK zr()VnP_VztwOu?+o*gS_h_Ksp8t#nxCtBFt25B08_7f(~`VX3w#-VrA9QYk|oE@3% zOgfc}KXULPvvgI0r#t$QZPsszg|i%b-%}$4yOHAWK|1uK>^VL!odbsXnsjS_JzJZ4 z4?CrYz_E98>XhA2vA~IwsUS}eIt+?fih~9B`KaKZ`EY|}P1Gd&A@kXXFdeF~;vwq$ z7#JvP1nucF!B1f&c^Cg+@9rs+;wTxAGZ9!FZ4>z!Q?KA=heX=1Lrm+<YwZ8AA7pCz zP}!h)bV^`Y%<n&*hPmuzBjo1746}MN`q;z#bp+1Ur13Z;U?AjXEtRA%HKvZjg~04O zS=t>%rr{V&J=3o<oj08#*SP~=eL))xQ9grqH`U0iRR!8U^<%lvDRD}hk3$U>Q{1!F ze9N9%k)+`V<=!2Pxv?X~8LNU}b9kJX@BNB%1Ri_lmV*#yS1TGY%dGBh&pjH%YS7{A zLmK>4;5<YKy@}I?QA4O0+Bf#+?Jq^Jij>(bq0bhlg|*Pu2b(BZF$Q{#=Q8uTJ$%iV z<G5#o84TY%iN;$N(Qq$2xako^Q8VSJCs&cqu4=-Cn)mn{GzD^h4yL6t(lA>ll;!<U zq3(T?5mSLZ{-8{in=&BjToD*rjo_ZuETl0X;@IOO6|~JZ3|!04i(ZUWXU;N5piRh^ z45d~aoqG_H0)MbWk1vqNzAp0Y6S9Gy6shuF82lZ-mpz-D!eo-dG2Xof<qPFVI#reS z%eK?_nVL{!{Q-)nr^8NJdy;Bbw+wl{meSG&iUU^V@qS4=@u6-2^?ptR2jf)Uqp=b1 zb|ru!+@bbrEttLH9=k$QVV-OuiuNt0ksd1K=)tIR(N@w9O@N|3CrRsB8*5Ve3iXXm zLdTmN=ecP#Wzk`p*_jV@pPu6C^E+U3j!a!la1-p9sYdnJx|rjQ&uAaE7B(pNz~7jB zdTq0gs_JjE#5JYVeOFr&6QD(!M|DU~Z5U*$JCUuMF$A`(hIb#zs5r(9`o&&k0VCFN zd&?}vk3BchlHa*F;e7>k%-@g7diDI5e%s*MT?fQnGEC~zBG5RO0U9NOuTJG4(=YtM z{Z$@7tHc^q@lNPfyCDUUV|76zF$H3u?4(OpXKA6Po#2!5gb7dD*u&gH=A-fxwkQfd z@SmBGwY8nbSPT&~Ctd2k5Q+Wcx3PeP<DvkWEXnMgV(PeYnQO{3#Vz8~Y}&aeEY4h* z#k96?^Lv+pzS~6Ts2@e)kM9!`*j>$^tzgx^Fxda$Dr`G%$)03gL8rT8px*u?x*qQ* zQgb>giX6}cD_x_R-Eb2e`~4_qI_?s)ZGDN8XX=rfaf`rO@DpeAdtiyAUg*O<1-B+< zQlI5w44VHH9yTQN$;vsj_;LX4%^pTl3pzxufo=TNkOHo0^J`q^r9%D3G@?Wh!V2ae zWg4do!S8i2R`_?*La!LS{V)$MS|l*<8OBiYGL`8*`$L}tHsG)gQ{b;k5sS|7m-L?T zg=2e!97FeS7`*d1+}>YK;_)0^ewa=@Z4W_8%TXjd=mS-5-voB%PV`IQ;tuqSfp0Ij z;(!r}a5?c6*g39(x!+a9OZ8=_amIGoJE4%ug=_C=**9?AZZEKng&ow45Eud{nf9RJ z;;#ACBHz66pwhIJGIr&H^AHIe<!J`W39>Z5P?5T_`|!w=E6n@MM7nhK3>_5Pv%UF2 zY(Vd8T=1(OoHnmUjkN(7|L6yQOvowfnC)k~s}9kxDO$95ZZfrwJk4%+r=a#t4s(z0 zhc}5j%%=Sc+|E1+3PzjY@F;oEd%~0X!-256DvBu!j63#SN$7EoqrHD!xsI;&FhWLF z{Bmd@xCBp!^(+3+Y?(|pWuFGPt-T3liz_)Pg-8gx7*1WyKe@^c4R~L98HqC{(XYdK zz{Y6ugT8Aso7Hacwa10b0~W!uAtj(Z>MW_}-N8XkMbHwef;B1&_}>GU(CXR6lI4<Y zG_Vfh;&TK~jqhDv-R?AXSckFq*1EXN(uVwJ?S<q65*YRJ9eZc)jTW^<xOYtwzenKv z8C0bR`){FZWt=tn49~{rb`IpaP>&)z88w>-y)8Anc$;n4@OZ1hBD*f|QCi$seb!Z6 zDrCXmw=ZUwlh(sq$t8HPxDyA}^rNB~UetMc1q|4+i}@V&C)6UGY+OUf^(R5xXbWu5 z*^P~TVbFFaMYMwT;hJ1IxU=FLudJLadQ|61ZU4<j%ZCXVXEsQfb${T!_H4*rlZHBl zO_C6~RQA}a1A@%f(M-_?Cc6BG9UkdI2U>TsZ}|~$&)JZUMfQgWiRF|K+K)bNJqsr) z_QA7P$~5+F92$tkv~Pnd1xc-;>5JW=`a=LX4Hbi~sS=r3i)i=E)g&~}qw}uYAoVs9 zT)JOlTSXgh<B~&$Pyg|LmAj#0)(-MtTY?J{AF+2nh3rH~I-ty8Zn1hjq}?{)*qU;9 zdQ?oI@1-bl%tLxA@F(=#Ptu_2y_^bPN)=lUpkb>T{Jp0D-CkQ@>q<2U=riPs^tVDm zS1}tdobj{j++f(!9+qn+p@4C#YNd*NtcyE_qQ${t7@v9>^TL<G!3CKVu8_o6yT_B+ zKy4<uEIjXwL#RW+10CY-bJ}(Sd+0$MH!iv!CoOHl-61bHrF2d4m8S=2SikLXYD_8y zE?0uSw^z~h<Zt%4{5&d^3<jGZO)`8ifHOV*2ZMHp;<ucWbiIBCixIdGP5M#vZL84z zcD_|$Bj0CM6UTwoMHRI3DPy<hs?$)1JY3zIO0)8gl1kzedMli{M4wV<+FnbNO0Yn~ z)Of^r74bx2qx{}g(A{1RW-6IdbYG!`Ies5O;-WpM7B`*r-7A^o>Nb{=lnlev8d1FF zD3&BG0Mpf$Fs~*8yxQ;c^%okc??)T8te6ZA6MQLU)Kt>0E`-D1HqyH@2LRet34K?S z>zhu=upP&-_`m~jsF#7FI1|z`7v}n5d*S23L+tiB1sE!~1WNL1S-ay5Zn==Dxh0b3 zbJk3%3)(Z9LWW1t^aJamX5V%8!|E#2{whZnN5`_X{Z)L8aTbkf9Sl?FB+-}YpK$Fb zOV;zIfR+3ax{m{*SXqJ;mG3H|m(%qb7HPvzW=g7SZZpM(P?j>|BxmKF#0Qv^@FOJA ztg2Ot`1KE=_tg}>VA?y(y+0n>MMEI^a4kxXcVTnM6AX#i2J>&l^PWY)9J@LTFU^_& z1IG`C|2)63jm0DDrhJ$|9S_VQV11Qj{-hQ@xgi16v}0gK({r{--2;A>-i7$o0?^u) z18!#<nftR%AhG{~op~B`QHp23s?)g08KLlL(qwXX4x;4|2PiI`7x=<{oTA8_O6`BK z$A8zt=<mlVq`83KyRIApk4^!@GhbQrSiw&aW(va;f}q)7%o2+<C@$s{ZQb-(&{FP* zGJhY!xSB#rlK;lepfVmhae~Y&wLnk99W7?`(p<{`+H(6KCY?Eo#o_YoqRCQ<j__dG z7dzPo9p$?H5f4ab<X*}BG14@+`Ur?;N5itzPPS0362AQ@5%vLNA#YF}<o3^`w)iZO z-dIbRE$jlbR;$5$f$e#_W($+{|5LY2@KIK^2<$N7Tsi((HKo7(4SzoDq}=cBC~o@* zwv~sN7psw23jDsSjR<G%er8uk3k;RzcI<J#Fy1du2d;)!VPl;H6;2d^j9e~7yHBU7 z6)ULB*Mv@=8Vm-@PLiglKJ9<8g&7J|5YzsbBzl++_1;Ih5mFo3^7lEAX+_*r=7Y)= z^~~bL67)WA0+p@d*!N&Dt+!UApBe*LLx~nNrF+oUa@D%*F&o%#*%V5){Ey<SXY!#p zTIt2*{g4)F$Sbaq&?D6%vW_F1`E4kDJYP#IH=jqh54TzUn89_XmOfB*w-X~~>Y~p% zD=c^viZ3)OF!s#@IAvb|YI7&>Mi(nlC-fkd^3F7MS~p)aa0Og7H00)4?;)*=N5I{V zk$>d^_UPbnI5+nn-m2B2l|zqXzVMtJb0LO;me#`|+23rnu)F;DIvw0EiNNB1Cpo=R zBjZ1E;G7r0V_6k7+X#%Blmr$lIs>X@S12;YnY8TA!1<4p=*OcBZe{*53b$y)=+3Eh zt7;ZFtq5dO1IN>Q+fb%sa)H-<z6Kn?gBztd1HSq00>k>ncydMxj9*j4?qqs!`RA0W zp<*;8jDH5(7bsBod40ZlmB0gVv7<c0rSMAr2n&4c1I~B_vn{U({=`)zlAI#yI>Ah& z@4?KPEV5dh#HtT;vF3`&<QUrt<%4!Yw$NFzd3-JD2Moj!Pp{HPV@1;M9*s}$tY^WV zLf%yOCRsKOA}Q$^)`r&%SWVwC=5aviIpmXJgW+0Alo`$GA6bsdXHs#DwJOPt-wYem zh5p|c-P~5caM<ozfyq@b*@ye9@Yuyd_E^y22dLyzE{9z9|G$5m!@zm!3(n|BF*s}- z%Wh1yhO*C9Bp#(mi}Dttf<rp2tbGf6ziUJ3=~Hyl|0ZktvI$seE^nX|2W~S@kWsNR znQSxxk5f6!Rr@vDaq}V=y>X%2mpj1ScP7)$Y31|EW#OvUb*AWh0Rl=tNNx&DI?t6+ z%(2BEO0U;JYV|@o>l6VNLMP32-5T<Ec1Y6xsz-DMgF%Cf26e+Ma&5PlgeV4*mO}{) z-lqu7MK4fI-jp`_f5icXabOmj4_95sh+kBngnJ*v<a$gA8-9ify5}S23$4tc=qwAn zZ%TUQNw`EL%rq`CbyBzQqP1B$E6KM7hXyg9t)xbGvLCT;s?l)dlA<_7c?J}7)7U0M z4(`+(<kDsDLENe9yk|~7aveR1y|`#Y@!J-FKcCLVn+}1;k*mR|?=4N4eh>9*uG5H; z%h0v6hu`~b2Fy0d$D*U=)F!=+ZIWb?x%)=6usuO07fv$e;sIhQ3xDgPCqxeKwa~35 z3^G=&ryCC4?4&4?g_r~*w|6*<Zip6}3VGBr2Q7@NPs2E2M?QG80`#6Xhc|s%)ay2d zj%zjwKDH(nvfvt5rM{L9#+%~Dr3x^2q#T`}mWpu+;jFabIu&t4;o~kdFbN7`se;D* zcCI2XTD6uHMe5?2U+Uu8@NraU6GQt>2|k$94&<k|o!@)l2yeJP64u!+sf%7efpd15 zM^1Y^zzK!Om2eLYH~h?7u1sf{j|@;M-H7Qqg|Hlvy7>5%2F`u4Cb*a#g)7;ibZnl` zb-6@%eSd9uC1kne<-3?)v=jO*lc}?PxC#>9hfs{PKAc#`(=UPhRhOOy>z;(+R6CAr zoYz8~%Xc#KlVQqdN3i^>3T&HAC>OHwheT;;F)i&s1*D^1v$Xj!0`B`BZ+@@~1J*3G zHm(nZ6#f&aRdl2B*|p@D|Al=lRECVzW60Tc9^1f|k!Oz;-*3b~(3>Dtr>i-Oh9)f* zk9hbWxT<d!2W^$7O4SrhdNCDLzKvlvO}cf~SMHOMN+Sxzxs>MS4UJdoz-*#1-7^bi zh3gs0?dW4SHd?Ww2h({OY$V@BAvD#^77Q+p5V*zDx%<1_QRiMJ^IaN8JAWUfz9N6P zI68oQN2}A-siP_T-b@;nI2|Wd%EJep5ZY-m6*Lo-L0?nY6%Kfc7WY5#ai^68GE6?$ zPArAw_7HB>J4LGdBVvaS6p{b7<#5#I8v8Ohjm;i#7+m`fQRkl^v}o7_dc%`oi&iTw zp3+0lx(0*g`fU{B9snty(wVp0XBKdE3@3kIf!7f7$KlV`^HEdA)vXp7cBu`r;*LFc z;daYF^4>fK{cj(j;<h2;gCA~i>f27>I_)efsc(RQsQIGSTdU~lmrNMqd5hF0m_lWt zz+ld@Wu*%?^K*=sQ1{l+c<)do?Mm56eh>CT@%0SSw%LYNMRMZD10Rrm<SeY-C@|xO zXVCKbm*LsSXV@LHAHsd5>Rv~@fV5{bXv4lKs1Z|wRn;osUX=xnB~o=ScNPe&@IRcA z<{PRO*hb1OW@PAQLTzjh`0ZIrn$l~9{oVrb8B<PEOI_f+F#|`1Om^nWa<QZPI<oq( z7M~7o1kvLfymOA{vyHaHtVgGL+jK*QVV+<<GzF$5KgX80$=rt-E7;2F-xzdj5;>g9 z<?<W<veKx@P&#fpjC5{7-I8qjn|Oo@xy>M2>kn3@`&i@s=a6qVMbLmEK)Xq{PQLdI zx9#UqZtby6*eEB%ZjFk;wojWd*EN=UG=q4ZMnC>|)=%a>QDBPbJ;RIVOxf;^IJj0m z5n$n5TG}mJx68tka<zpXu#gfslT`rC*M>v+g#auVy++_l52n>GFEFQLS$v|7oVc-k zG3Tk&iXwSID_J^>T?`Dyo=~9ZSN80Q>K<{+pfCvUD8p5cufo({mjt~F(SPOx`2O%V zj!=lAl1(vWS-+gN<Ru`xa)SS&@=Rdq^P=}F#*@=%jzW%xLFuS%&^IX`9JXGSXiWJa z2m%4zg^VWnFw2}xIARS>4@;P-#W6}1KA$6!2Q1^$Ah_dpiI=l}!8`*luuq?)#lB&_ zkZSmzvQie1g2z_U$?E}~RnA!Rm1y1GgHUIDh@5KmNyA9!Q~&uH<sJrrVbE_F>v#<u zE40L0EKgHwUNO9~OCTq!c+%J^BesoAfusmwB6F{TKPOz-g~T7Q?pGp49gu;e`N7nF z>=E35=FUvFC4>FX9NY<SaO2&RSS9#ZMpjwVq_^obKX^KmeI5j^ZDzFPxg6-*xZ>1Y z3*OZ}kQetWVN%>xb|(D@dH*({c3TlO$2RfmrBUc{rVaB7t3m%s2b(8J6`0hUz-Vm{ z<o*)01FZv;)R@J}_Gz-WUxVoS^;IlZr%B)f%92RvqP!Z=1sA5~f}GzEHmK(@wFDY5 zTxr65mX?9eYfZil7eGi^6IE_L$qA||uE;JR-AT3h*RL9qhCXMByFYSGXFOp^<4Nj0 zDa^kex8Rwn6Ll|pj*`My5KTFczYObe(4|q7ynX{WrNEfF&v<b4nT9~S>R6pyDuo=D z0kw_*eA~5xo~>U7Ev+e#I%qz-t}qr8hiXuKqbe4A6_M(XQ&>JMiugBKsI8MG?5d~I zgpEU}=6N0)Fjf}6)+?}E3Fc^Ha2~@Ww=>T*0sNqg8}a(ku~e0l#4a!22`k>8hofiH zahk3aR%r=7n6EQozU_B*GD_%J+#^Fq7q8Oe;2jV*u@9Z%ma?Ru7Xd#^V&;F1N%x*3 zm~5VdTY9c?*L_BjPQpeme!@YPV|0v#8rb4BwR7Mn7sgV)3K<deQkLJ+056)8sCjk? zm%p@*8TW=#oMkm9tse!4eJ^qWt7owOA#dna@I#F6N(E6rU&t?Zq2Bq6@U6^Z+P~M9 z_7qo<TB|B#E>DGjo995%`?WM-Lq9UU0;Db6-*ifQV2P_A+<Y~Sq{a^5ecy(VO>sMW zD0sg7TSCdyZ8(+M9)yq^QoPQN{m_!G2#$Ncfb+AD+{43V(BAZ>cKaO_YPxchTBMRO z_QnZnce#t{-s|YW;z2adu$viP3u1~Eo^Z%;GVDJ+fOI@pLU{8|<}>OnTDynB9EV<3 zBlr%MYHY!ZqyYX-Yb4*DFdCNN1kz6kfl#$XvUp;LE6XZrVZdmJjhTh34P7V~{c*@| z!85i^2j0djfcnHv)E(G^vEj$q%>G*9K6EAbBk$PD(f_coK9JipF_@P$PKEXieNJ+5 z5$Nd5CQSuzw!xwY?L6->&12QHyDf$V&YjD42cD(z!g~>V_a^)hvJ5h7uCU0;i~M1M z{lB<w4x!pOt~2{EZTn$M4X0j_l-wE^{PYt>dn}~K*N(AorygU@M0N2zgAAw@b|C3V zr6}c$)p>(ovY;ScDn8|jja7<d5T40a4c)<F53Ph^p2It(Kd{a+1gxY5EvY*Ww)sip z=DteW^0|QOgk92+Yko9EeJ_<9y8?3?!YS26=+INuq|KumDUC&o6b7dWO!qEuv+;oR z5KHm}C3;@847PvYk6r!-oSV)xxF+Z`6XYVe?%SozrArxyzm~6?t*MVH$;o7I91UvC z!#QO=Lr}}|z^?y182j*8qI~id#XksxO4WQS3!h3=FSFTMTndK9h0s%4#gbmgQG|9S zS(~k9F{%KqGc0L!VlC&rVkoLP2Z{_V9toaF0~S!YMAA1*69<2bhdUEWM4_LoaMZH# zAU8Xlb@!yBo}V3^&=vA0_7R{}Tg>asp2k(2i%0pWc~B5v%~CF#L5tbQx^W9Mh3v*o znA-A+g*W+Q)t)op;CdTcKIO348$%%`zZd3@3WGik4o+@)#JQS#u%<)@8f<?F->a^J zt7gkt!+{F82&$xZFO5bGT}|zsf#75!i!0APz)ShF;k=-?6*<<BJer|pLms5}FsSls zU~Nw)Fxz3(T<OfkFrr(RIgBnxpG^UD^-&|W99V<Pzy+JP1yfs%41^xO$~C)2QS1gO zkiWl`FEf2hejbse+G~tne>d?eow6|Ymm2Mj^<~3cbTMfC@H+N7g2oA%q0YRCv~7PF zjJ}ltpN<cO(I*oi`p;RIbHf%YWV;}q3EvCB$K1{YK5uavJFk8O95zLBNsY>EiDprq z)7`tMeIp2d&%ce8Rkh^Z_!9a)YS4xb16F~G;t5s*LHUXoJMbrfqRh@f2(5v_7i~;) z@p_2fIG^)P9R#Uc$I#He5#*bC8D3i?(8udp6u)6PO->IY;Rp%&{n9B<Y6>-prJ28U zG9R$^lO(+*8NLauiv5$WG6$z*@J%acUt0q(bHsX<V-SlO;0iuBWa)&o9C=kK)9>v0 zX#P+EN(VX8i(?b(KAmo0cj`~kX(vs}NDgPgj!0Hx+(5oY1N4KhlJ;Ys+OJmOk8nW` zesY8MOgErcFRn13l5utU0+`NOB-ES#9gAL9r{RkkfAB<&9Azw&5=UG}181EM?oeP7 z8b}vY=;ck6X)5rH-pmH=zmHhZ-%xTDSa4T1hfp{R;r}H+;!JD$;g_vL$+P4#SMM0Z zX~*s%jYBn{pJNFb+55p}ZX9%f<Y3SK0d=ciZJ>qIOSwwfJ^1Eh0Xb`q1=FM7YhBLz zfy3oI3OZ^<+Dgg7dul{ixxr+uzKbRuZ^EG((L(px3<yYUVbiAw`PclPB6;t3TuE~f zG)2x~UU4I!#JUw69R;nvpbFj#ya@TGA6Ri^04fI#qzo4+adOj9e($8myj*}8y!Or} z!;=ED_k{-=_;(pJ3>iuhf9&Ax@pP(>dPRx-D}<fULr^-FNjHjzFr9y&C5_8$D0b9W za2l2YdtYwEmfQ+j+cFXR*}bIGF|)C3`B-K%$_NTBP6r77NGf-pVW>hU8az(me$1C= zKlSFaRi~0cdB+wirU2IaIFkKp?!<+mU(h_r7M>oy%L0zfl7xH_`mCK+;AK|NM$VC< zU%_XY<d77pFM39ar=vKlv##LvGzv!c1+p!-&p}1qD%K^x6~tam)L5e^IKR~?q^KC4 zB|Lx~iyT0ImJwY(l*BYyB*+^W;j8Gi&}2T7?myc_US6XiSVIj~2ZlhQV-+x$btF1M zFydnrzcB7NYe}|(88g$_)O$7XtJVfv##d6`l5-3%yMyyMj?<rGEj%AKLX>Je{I^V) zftUR!az0(fmkslUg{}62*I_cH4_9IlN^5B2&)Z<--VY8{xRS5+5PBVEM1zF$%fpx^ zSY7rCJg#g7L!C%^5mw7r*qq{a%vKOs7YCU9sH4nK=xsWCst)5udh&tS?~~UxX_{=& z#D?6R01{zWnKE(^MM>MS^(+DIv<(n{y)zCT57T4cjh``j&Xdp7`U^(dt5N^dbn=-K zg!8-~(eChhtkOG2<fE>_l#4EcjE8bvzmy1^Z$wmmbf9?of1%80vNbsRzeJyZQ>ia( zGT2c#tq&+--Cs}9x9Gb}Q}-{#xenw@SF};tNp*C4ei|Cq`qFIcwL&+`BEDN-Iu~Z2 z=g%nwizj$Tz@P=o$Vp)jqSJg)*z6*faA7VefBYlye)9*HH%^As-X>;x|Ay#HfhxIv z|5V$ZbVyV;tp^QDw$fl(KUnQ2=;zf(nCvwR=*WN1DpnfM)t{B<$VNa{<zKG$-$?Px z12L4oqJ(xQrm^3vrjzpP1rnq1T*d_bX>aECy78x!QBg^O3I?46gFo5a`@&gdGEa%5 zepl4C&zdL+I~RwKb!wRR<uT%(&q3VS3jp74?t+n{FVIGzb8^`77pQ+`6%-vR$6Jdh zK-7&jXuoSf-L3vxVM9s~-B9Ue|735{h>k~SGMzvpW)M{x=1{}&uk2LyYqDLO&%0$S z!qi;_tiG&}U6$RAp+fM#*~JRB)?a6$JrywD`~o|8%z!$6hVs_2r(ndfSCAA`iCdN> z5|p>GGRMOpdrX%s_UZE(|E1EtnQNKq;sx+*)mK`$WhfO5uo7S0ln1{S#fVoM&ZGUG zm(l)bo`91NvNk)pI@2FF$YkFHY8@q0XL1D~FeCvg_otz`=~5Od?0UAu%>t{x=B#aB zHv3-KA?%p*$>QT?7UHdkwqadtRkR2{-4Z%{DidkfoF{a9`F5!3A3`gGH&JZF1Zq3C zhAiwYxq>BAnYF=as&&<cV*+p2%;^+8ZK=iZ-Y!1qoGP6+Y=vF<t)P>w$I=~sV|MXd z7J2&&#hyP7FHR4F&VDsaUw02g9SWtahaCN@nh2GpAz<Aiq2dJTx_L3a!v4;K3WLoA z?dBO%ACd>}YJ_}&6rzWJF7;aMM7GYVPSJZlglu{Z+PVdBbGQQ4j4h%W`{z(_nwHoz zbv-M(Jq07@2T`bJ82kvmhd*{6q*RRt=r%e}Z3kspZuTcp+_oaNPi-NKyLJ^1*Sny{ z-6d4n%aMJ?F>o~6LP<XY*i*UduxMVi@ciV_KI0VTM%GbZeHBETUB%UXCNMrnVC+te zg5vrocpi44O=~8a8cRdt$T$dfX`x{uPM90lpRKU1qB%8$*KJ%dQRq9{emfa1`#Vup zLOm<Vii7KE%g8y_fU*025D*$rn<8y1b{f@>+^cl)vT_0Fyi}2d)cN7EkxCG2-^u6p zedi`s27p~k1(>9sMTdDCx%2&k*vx0E+59$bn)Y89d+<uo-loq2hZEyqPozJ3?klFV zF^kD$gA)w@Xb4aH)iIUW!(e&55*383X<v(6UGyY3EGT-({+nlvBYMxV?gOW|)wiZ& z_Msj0V`-kmH6cyn9B2cg+M`S_<Op8&nusfO;-KR0D3&C=w%2FnI*H0WTILi8r&pB2 zUE8zJ*tQ$w|9N06>cG1>M-VT)VmdoUN_t(i#g1<agv3-PdbW>*8k6y?u=+52m8nA- zmtJ!Z*a7kJk(uCpc|HH%$eZxB?+z7YcJn@J_8?`hM-4iMs9a#^w51;)Q=2!a{P>Qj z`{Eb==8YWocjJ2c_(O}HD0_m@vwmRm=?hf64aQa5``7i>HsS`uESNvojTKjXVkf<R zvYe4=6nk3<m2IQ=ZRbBTxoL<t0)=#U`E@p7#ZYmJ<udTu+)M!~Mr1X48lBnE3L)2h z@W?m`v1x^DPE$C2*P2J~LmZ*#f+=br7lTd2BCx?ccrffeXn(Mxrlcd_c{qX6KkL!V zJ(s{pm~&*i3RsLq1B|t^VqLEk#oARK7%+G)=VZK`JXI<LKMpZgkpT8H@3C6t`)H^m z@VF&o;CihbnSR+so{w}{?ywV3a@>jLj_72r`FFUXGloEOsx^ibtO6C=NH%Ka7BV?l zkNr|@sQX3&w^zH8w-x82iEI;$o_w8!s8_*V{qx}1bP{BGdfD0+0VG#97@z%`!t|D$ zq^9e~_!0H#^tf{`c_~@&-Zu+i(yLM^*sBA#+If0WB+Gi2<?tQ#Q{d5IIqJM%3OTc* z$zfCr=PPGP^IQ_hA!Ic!)(HmlL`5jxr^T)MZ41xJ{-a6diEu}+7iP*%q2J!iXl#oO zOb_rRg<zp?njNOvCLfHGV)VkQg1u>b!yf20u=^KdsQqy#r+nlqc1#7DouL7RHAbNJ z{TTN@iq0$^tG5folBA-9WJ)T8CP|Wb_gX4Sk|s%#X3dj|Mso;BNHidoN|GeRyVuer zNlK$i8viO$DQW)pci_M&zrFYKtaablbv!+WG_Ogl<oOc>uU5&;I$$CwYdG`LCJXZ2 zU?gbypCEl#kzNMBhI_Tyk{9}_<cmrYe}1>7qN+tOH?#*Qsr;iFtv+0(XbM+DEm13L z4~}hf;4VpNlz+2;<M*{egN@YjckjeHJAR2@_nhD<4c2%n>p89bcv9Yd=0O~F?-lfs zdP`x;ZPDs|tK?mkiMRGRaM8SZG~v-6i2NA=3wFDa-?l?|H2*0q7_tmDKGMhhTE<HM z#ax(YN<rl><nnu?IJ$c(SZ!X6yYARS%9J=ECh8>@>`kHvCz7x+N+0*P4q&@i`b2i- zeCpaRew_b|9Y$K<@lL5Ya;xM76ejT<>8`dTKAYlle7M^97dqF>#FN{4vVz|R2gjZ( zIDPJCDAQF#3y)lmICz=r)286sZ)!Mbff?p)R)J;vzG6c|t>Cp>+NT*V!^h`)a_r?j ztp4dg+3~*lY;q}`jH}+$kZVsV$Dt!OT}c&Oq*<k-dAf8k-@tmg`k3W6SZG(D1D_&d za7oot^gVc*<0m~7EY!b<MKSkiQAh?1e0z=F58R4Iy3V47g8`f5CGnDT9(Xn37TvON zWY5Q0bh_3T?&hupjZ}Au|E9zJ|EcgqEl=EU+uc#Q^GniPqYbFJhx4UA;T-SIFfC&? zsxLYv433g|{Zgn;<ye96<&_V0uv6yOJBm0tX1&<Dbtl#6pXG`TugE9iD)#TB0*;e= z<FvR`^52NqdZG)rYwQ(E4KH)6^xjT=m(8EL_Q&tf%V^FWcMggshr;0+oN{rf<Mf#s z*yni%$#1VB`K%cH#(svCMp5)Y>k=6iJ)wR1cR+cmA==vQz!$3`K_PIDxOICZR;^D1 zpSToM{?Zw4U5wyAU(Rt&PB3nIIDv~y>{&JIA?7<pvSF`4T-4&gRmp99)A|UccRnsx zd(w=SF2%6D_XHl6`i@@21)|cwT2frs0c*^Z&_ia6E9FLFgX=Ld%d~(3PTuAJI<<-h z&oA?=3zM-iXrAy^aTw}M8%_=FkD-JAQ;I)P&-DY&VTsK$t~VG;|1AiE1zw>z{`xK~ zPuUI?mrF#2j};uU&J_n)*y1lYM}Be8oJ^O6g2Kd};(ufBllrNF<az3`*v%t{zLrMd z-8HVbUVj*^2_B8UKh6q`FAl?%QJXp8We`1&c1Fd}ZDOI;K^px1n|Rbhz@p{9V5q(o z?x^Tio_p*sWqvlo&I__2WbY+fn>Yna^6N3HY$2IN9m1{OpX2DPr8sAOA`Zx?6m2yJ zinDGl;LBNa$Yb43r0})E@X6J9uQZBkGD3LDadUnp*FvK`m&E?FUXyRa5Nt`d!niTl z*|K>CwOAzM%8qA+hi1Acp}`<aCyVA^8H7grb;W~u>Ew6HmF0(<rOaC+y*~3zh-%x+ z{Z2~xsj4tIKiY;LOzj3sKCdL7AIjy6!<O>d3qv7qb_G~(cgB4OM)86f`2b_D%cg%& zDBs~<1#S)iN9M#*qg5pw_;(hUe7C`$;Yn!F@d@(n9k|u2r(=onc{XWI#uurU_&qBc zvJX$k9j~fEuVDq5FG(uzo}|mCqcm}l;TvjS@PswW(r|OXQLJ_Sf(WlWIjZ&@jK}R1 zv29=`-??}cr{9u1g8|QkdyYNP*HukcJo+r`aaQ3~2lZG-?F{zcx1E=^EaWq@{aBRV zEz86EN!{)(+_FTSXS`e`kV`kpREia@FH6C^yEdq(e+>ScvKRH<oP=V7K0Nm4WZ18z zK<nR5$1@XVabDUI`f4|Va_4JO<4JeCYt)lpmZ_Bo%yJd)hEHLQ`A6xXcarcFc5-N| zB{pfUMw!}HDOZ1tUAw#`rO?B?rKE)8y=L*^abvN%RIA+m@M+jq=f{yYv#IflB_!*P z;mk*e$>#e9wAp+EzxF&U-0bm<Rt^s4H0{~kutVa(dW}KZ*K~;Pxr6OTyW^*{P;P81 z78-{BDpPr%B=o*?o4iJi#D}E^;ZD5|*Lm;7wUK?W*?Bjfa!$geN8>O-MX9_bZ4*!U zepSqC>_AF4o-_QD$RjO|bkEBSi#KiOob|^jza<;Tm^yOG<1HNUHkdmeSVQYv6QudL zB~J6`f_`T*#fc5UFzZ(zaMX%G|4o<0)O}}#I?q%rP;iFAuyh<WHXZf_O5YpF|NP)m z3wgHvz*jNh^q}f0y-nAWx<<)doRo(Z{hta+rAb&h@-flh7`*K|jsrbZ%l)Qa6qjU3 zeAN-b?9{Or9@z1eQvTCt>+A2(xULd^4gE&zpQo|*)~{mH_paqLHccmeCpnxPbqWh6 z^}#XqN2FQCE~<*jrGq<;0DM0Mjf(~GmcbY-o}$OQ{)~o#F?U6;%3pNxeK%IU9*RvV zU%>BmFNmy@3woapi+kqfz~^p{BsO6`0L?WJaYE!ZcTU0QId+(CaS)9bE*9<L&ZGD3 zY~gCph4^+#DQ5-A_+`5ezZ-E3hjf2}<<hz8pRyWfZ8k^at^@G6!*x;^I0G%0=korn zt(=~qh8v7kKx0NI3a8>xS#>5KU6Y1i6Yq*`7jvL+O(yDD?Vxj}>3FTyfFA8*PVc0F zD?R-1^Uu$m^RN&5-B}3+Ph+t5+eub95>dM4sy!UakHGS8r4ah@66E#&0)Nc=aID0{ z_2@ng>`0r{onDAKpf7ohC*$L?O}On_2gjq`V^DouDmxvGrSa3|Nu7hnveNUNM9V@w zaoNB`PB$OSzK0G7{T&Z*kM|Qe`&Oo~q*mf02c<(;ttf`xP{Q0<GbH}-Lo{?Q1xtgQ zpw=)Me6;UC$lSjOd;iEXiq}#3$P(IUZBRbU-Wo1H*$!=ms+6L88mHY*E-&4s%=0&< zae-wEcCWqyTD=Ej%!MAJafv6#75m`nzysWIKxarFvy!9UYM_?GXH*Cug#%{n<q1C} zw%#gTR0;(Co9u!OY8_>Mv-*lu)+9g2!H%B$rOxozIlT6zA}e^_wLcU%6nzHHMCX*Q zpk=h0uDw#m;05ntg?F0}A?v_7|Bee^r;Vq3>Q89Tscc^8x&ytv?{JWN2k<pU)IXbw zv!&VH^0|@+xz}DuydH+xb*hegm(SxR6GJ)s%5Xt*wg+En&lED6f}yHcZ>;>~^&a zR(zUplzN(+z>UlIg9ERnzta6cDI-VNbngu`WOkq@_s+nL3tw=;11V#WzZX)EEX4_N z{;YaFhu0cZ%i7x`@Kc5Xd9SiWui;1Ot<!g=uO=vqn8{aCQ-v%3C;61*r?iVXi!1Za zbGyk!uC#O!5(kuX{7Va%t=$0YZxihPrHd}<a^ZL7WBz3^0k5vJ#j>lBs4wyBE-2Oz zfTC>QopSX2+uPA&&pEofE{+qr-iCmfa4hs5O=0<VwAy7af7Ln+S=|?7?X)WXeDOar zd*$F5H%=9Ao_*$MzW*#cZqg(e7=fpxYVy0iYUK@9C0wb|t6YDaW_g$<gX$#*jOeb& z!*-vftYTl$OJxPN%o+yqwkHL*i?4aPgFg!nj`(d6W6RoO!a1E1v0{?5IQaVvX}$vG zYRfWV=+7-2fAl_)YadQB?9Pcw3xxv15Lh>;l0x4|49YRP;MLC*cKNJF1oLG1kxDFv zir8(^eq0f}0DS(eWUVcqK+k6f!yXk>Ib#nB(<jN~Q3o;a@pIba_=H?FI-@Rq#?SSe z`C+U|`7OO|IQuj5(AZ^IGrcqIm|}`c)F<GW+P_i`pdVX%myk(U*Ye0tCa`10A+(&~ zip7c2jL%Qxna8%Xa>FxJ9XJZDGwQ@mPJ{T+fit*c<XcE>FXgzGVfZ9ny8k=(LCXi< z;mUZ)-EzMQaw^t=p1U5qj5Ox@50m*z7m39?QkAE^j>6?<Utw<X5_YN(>36J$Z1)N& zBc&CB`qDn9=FUk;L>UbOZU&)6?PxZbnJbpNc+=nHQF!B5l;lfIV6XA|d_6df^qwX2 z-8LO=bTAa>e{tbs?-t_T6%kze#s!x7j>e6Lhw~7V*)TP1A5}EDz_nwY9e2;Gr%A{4 zdC=G#>^}bpeA$>Q44?8F`c(VzCwvX*nvOVi)GhS%e<>`zCOKaIn+5H!+Jq+$d$2Dp zK#y-DaD-|S+Tv_sbSGCbw)(^OM(^g8wLMYm^iJ{Zr_YjW${V{>%c<~+l%b0H$kVd& zXyEzRg4^I@FxatF9A9veo*sQeL9VIX=sN|(v|O+|Go4-zJp`5;_R#vRYq{*2KUO$S zmvZ6SJpE5Sht5!CFLM{nd4C<dFI<ng!@fXwi)qv?aD+6kQ)Ig(AH}LdQ?Wwl3bx<a zB?ji~0Ds?sc>KmkF~QytH)i~y@;R3%>{X*<ip1sVR5cQo>$qb|??Y@N@#s%^HNzxb zE55nXh7X&bqi!ynIVW%^UlGip#%d;9S270DKOl=X8_9`R%AkKu8lJ7#hf}69{qXi= z#TD<U{^uIBNcbb3cMZm;XU{-*)NUU7%z%xO9c6`wOeI!~0w)(P=e2V-;56-KTwL1) zOI#&SW7j!6)UpfjJza*rQAcEYlMnDHt1+nl?<>9UJ&K2WDq^Fo3;&V2{P|s)DZup< z^te)nHLgckZ_8W!RCkP*jsHx1^e|d4n1x!4pTf(ZqwtIAF}iM*j)RX+=2aV2(Q)Ek z>SPjvw$q%!C}s~Pur9cr87(f_k}4W4NsyW8ju29P{8{}_0Q_w>fY}?2rSr>Y!3Ay5 zL>@2peRYi1MywZ#6c&Q7ZxaP2B*XXAVvZa(05z-vK}p;qo46nspSd){gbgx`ca!GD zQto>1SraU9-Ng-i<K>BM{qb-YPd1BPDnIJDiz_&h-tBi}>kg;T6eP|^cpo}!6vaPB z4Tl*g4$;#?vG~Qvg;XvY!i4c7`0u14*swo^>gzJ;#(w15RC_6(9PocPDcy-~g+pEu zoVs^Cy4JqJ>S;Up#;Iub8b(m|y^idxx=WtbFm~xb8!jJGU|Wl)Q2u^6nrkWJ;rJK4 zV67%9>CY1k|9eTUw{5_@mm5OYRZt=yL9Xqi=zCQ!yjIYg<$>oweWAbj_l~g`)_jqI zRJX|LFC<dGtnS#gn=<~<3FV-46S936A--+t!4{JLVr)||N9NnHd&5X!n}0kg7Rqo9 zuBLgNn}vnnBlzKlLLqlW4#fD{!J@q}^vU=NkJgm(pmP;@QN6Pep%II#8ujpjrW3cE z9*PZb-pQA|OcxY>`ty!S88rBy23F}9Fz7jOro=%=`g#U4eG=(qLr0wAbqG}hR<Y@7 z4@!9Rfu>!aL7y|mLyE*`STLc1wwev(#R+Hm+z#NTE@RNUx)SC|x%1`H{UW*L08e&s zWg{=u^29?6P|w&AeVr2I|2bW!!zNpKbjKe2)owe_pi*pK>rOJou3#IsLRi(P%f6ZC zg-#!%u>RFv{xVpkB*|lTaq@7qykiNka*j~{Gw(3P@dLOFXcR{4X*ib5kE1<TrHpge z)50go32M|)MZDX;iW=1iaFL-MdRdPW&+ae6PA%OXml(+D{?g@m?~FA@eyJqCl#Muf zz;aYnb>m6qm4eQvj+|S4hn}lsV}$uG>e@jEQ|?~^7q4gF{$d9QEIAMMhg?bh)@ZVw zQz#A|qKc+Jy&?GcT>PzhQ}iKg%Ik3uJEV?utoR`@s@B8^yM`FB`<4TkZU!>_bz{(^ zYaOh9W{Gx6OW7cAu;@R(lnUm>@~fCoj%z)Q-DUYO{%i!lf1O4NDr>MjSdZI+yYuXe z<JoQVLR9ceyriD3EOaYc&rY33@!{fNe*C^3s-CTde0MiaJpD$Hcl|_j<+pHudNjTd zF~lBe8zEzY1;G6MGV7i`(05fCRe1E}2CqZnP*+u2WN`w_0;JqbUX?iJj4zg*>cone z3}3EIrJr#DyybQQM{je*){SPI<}r`EdS&2?mGNxz$N~$JLO3V0Q~8;-UtrL~f3W1b z9810W;<K|F{Mlj^+jfzjuN(_1(s(ZS9(fa%8}5T^7dOE2rO(KC;CedsBA33kEAY1x zRn8qd4(Gp;x==<UXt$q$RBtu1n9>;+jl0L2tIxsHyJhV0RF`bTVe~_A#&X|5Xxlvl z6g-y*LzhVX=qO#RoYob$X=}4jpI_uAF`8sUVnCMH8C#AWgipR_9pVEwOFN6Dm}0jM zXM)5TIv0sa^#DN%%4K=eJh&#kBe!k5j*$~rLeAw^GMjGUV5*Y`%c6%#IqTjy&|abZ zTF`yb<E0gLP^yI-uO33nTf~p&voOq5M?AZA5!PL~h&CxPQr061pAUU5O6@-=sf*$- zR+q$29TXjp{GCZtSB0bAhTW96?g4unbYO94CMMKdbH1)KU#PIgGlO$s=U<T@$Hjt? zn1&7y&GGGUM^t#61uM38!1X)(qtSYMH0h?!_0y*EoZ^n<eRw4WeH{YX&EeeNXalS> z2!O%wqN&(&FZ@iAd=Uz&<*A+>IOV~2(P$n)z`g0XMdn7QhIc}8nk{UtkQkZwGN8g& z0nKzLi#y^{VD;4`9GWZb8|%U_7tUkczTVilz7Wsq6mzM&;CSaoFHkRHsB!-ysxPRQ zMNNK4#b!Usi<<k$1BzdOg*4~<9{!58|7769ABV_)^Dgn<F%?I<1)o4?P8aO-`3*I- z24ise8VrJ2B6JudyEXMPL?7>kSa|^`YBL8teu#|+_j6p~VpiU{nV0puL$Nc{aQ@>; z4s)4E*{xlL{OJmKM7s;Ty?q{c85(2q!0W;pIEano)(CTUz9D_(7;N=Yk!BZTaA)ra zWNl?FblrWBMs$iHuRrQ|eMlj#F>Pi3<_a0VPjC=_w2zwn7=HdhHmF>IMa!OnZuKEv zEwQaTZtli!BqnaN)>0n&^&Wi~*&QM(fAEHbbMZ}&ZcI{++4{wJeA@rI@cQmRVaMe> z-2A);w#(b#aA+w1nG?o;$82Tw<|24f>5R@-)xkrsWaBq0@p0`P3YifiTz@8IG<_Te zAL}<1BK_r;hi|6EcYlcoQ;$e@?0I;1YboUIvp|ozx)?E_khF$LRHheZkbdBqeBzUP zY%rsm8oH;-<#*~~^O97q`2Ad_yx|y{+^i<wz6qSaD44ct=TOwKe%!cXD4x2PfN>>P zg+T4KXsKEWc6HgPQq>2empp@{hBO?Xb&SkTF^0IhVW#bN@Ht=(M@9!y&7oS%?(<eO zIy+T1<Lx`4J<pzxc?ZG!uFvR^XF9eA*zoNdOPqN`q!UYDv%w8RVRzyeG{16{E?zt> z`n1lXr4x<FA)*++A7k8b*n~z*4Cd6~))MEkhJPr&gkx@YxYRxeQ@>QeZ>znW*?AS) z%zH_hYlo7`%O(h$m_ZLTC*h#sYxtM#W3U}RK(w11BSz1iMJrT3g3<>i`gQmZL~Yyv zi8jeXfV0%|Hz*<Fy{fo+L^Mt45X-B}9+85zVcC-TlH1|xQCf7=8*g6sq5#d==s8Y$ zH)|!Z+T$sZ8nXz`t}a29dK-jPd(L<<2N$$g3)dRQu&~7sOL8*V%EX5M=-vVa_f?nb zhy4@Q9~gn<shS*W@DL)t-lD-8X_WOYNzjS<2oplnQS0><vWq&*S@RI%4L%BZ7|RRp z4I&}60hZKy;K>W|JgZ9wtatS$QtOQAuSUz=ee|Fye}hoKaym529iuy4hf~pq$ui>- z`OlrgzC(0y;bae7F}?(kJUN7CXE|}*ubYB<vIZ(7-!6Sx=fw(UTBRKqM)8y8DuSX2 z2T#M3+|tmUW1p+xj64+>)>U#^c9vMfo)*I5tU4I;;33{~(H32P*TI+N|K!y>$3k-d z2dKZcmCRn)lC0-z@%OZEyfe2ACb$g7xGAThvyXJXje5Xw(|d5@Tx0wcxfd1s$H}fm z&c|&Q^C`lxO$eH?9t*X+`Ag&w+&0;mv**l*t+q8dEB_I6=@ZFG()}#Kst3A^ujQ&N zsnb_qAr@3U6uOTM#}$=J9PeM;gOhI<vrqIky6mV1ixQM^XyS7?opK#~m%k7c9w^9v z-`B!<0R>`x?Kpmv(}Tv0(Sfe*DReNgD>tOs3$oI5Hu$6i_9Guc(P3%Nb^0Hx=q`}X z%{}<I$_{+guHjf*TFrJEt{k<>9&@@n^SC4D#Fg_)phU?EzpUz69(_BWwAy;{2di+L z@%sin$b2evI&8qpgS=>EfIf#Dm9c64O}MYG=s4)9Ixc!P6NbK+gn6fR$;+*kdw-A| z=YGTR@7se^v$q2(_;!-lR6OAs2KS))VkIf{vV!|raU2x0fD8IZ;;bZX9;uYTSq(cy zGrhB%yI~6Wwu}{j>nw!nmLja}+>b}d;<=)6C9c%i12;BFJ;>-((vR6s@ZJKwPG{qv zIY05eks424B)#XP=e<h$nZbSNcMo@1)M*|OHiL3SSB&;L!#6KlbL~te$B3P3G~hz_ zv6>n-<#BuB(fZdeVYSC1Y;T%Gvwp_#zrL>J3fmhvOzJGgjopCHyB+70MSZ#ORR{Fk z;)`?eJ%l|m0X?0K6w_-k>zx}#>!ohdvY;54pt(?N9c@Y1VoTBVzGZpKi^JTY|C?xJ zO4;7nS}I(!Nu2DZjYpi!@q3=+kqM8&OKaMo<cbsJJ>M@cpEZ>V4Af!Kmn$%I@Lj35 z{808(Tk>!Y%Rz$?Dx_ui6Rh=4iN3A-N$s5@={?#**9I{8c6OClOzz@n_$FTnb13J` z)eYFxQI)T~4aAg9FND>b-0<pIz!Tvj&bf3CP6_>JOoKvsvUM`G&E8EmZ!Bom5F^f% zX4*a}H|Xd73W)x;0n*<rqs?ExNIPmz47tXj+q!~#c6|&r`wYlP8no{V*T$1qC-SFH z2ZV?ve{fNc4)kGLC;mixY16S=u&n7GwX|Qrlj<qhJj9S=D=J{_m!lB#TF&`@dt<!J zTo$03h#k{3rSp2A)B*AXxv_Mz{<aqjPTRmlzKv~@O)$JDn@wJ(2(hYuJYn8G*tX-Y z(B0pJzTj|rm}$gkl0C)Ds@cQ_4WyQF6q{O?aj&HVNIy)AeT32ARBXr#7ykxD<3hj> zWx~M=&nf=?c=8(?3VL;x5TxD)^X?A7j;$f+`E{AlW5GLGmFP<@_w7(qCPVxAQFtmL zK{&bQDE%&;&jt?{%j*Xz!amIm-lp~kLbM{$>0J~3PHKTH`EqtQ8ZOQpJC7m`xq<hR zbHeI`02G#V!IkAJDRbK&!L8PVxBX4$K@FyOZQV(E$teT6)%6HQ?mUA|=QVhQ)Tvii zx<J#9hT)x1O~?Dy{ZY1O1qZKDfr&|4cu#X4P|9qX+mLhQX_za&s1qmD*&WBPweM-n zi;hTZtxzv!0W2&(0lIH`k5#Ij3DLnr@Jh$^bYaYD?l(S(FC?X6_R4O8(FP-`uYM|O zN%!AO)3H=J1EhVR4+;kUkom0{6xug)|5=0hdQ3d1_xLMscyB4Ya!Q)V57Op~mnYz~ zGjqZ8ejd#C_$yu*5Jcfl|6omhp73A%P$*G2B~Fm-<}HT`A+f6|Y9!A`q2?iOz7Rw< z4Kui?-2(Fll|p-L1~`9oqKXA!Y<eVy!*&&t(>!Ga6Y1{zbZWWZVkLTiVIxkQTLSaX z$K$YL-aNOL)akP@!-#+@P>nw!qT(jK^+~3^_v2xl+?FH8MZxf_4!CmhDY|y319PSk zmg>78Y!9`Mqe3ZX`W05JvqF5)lLsoiqo*mQly0zsy>H$W21UeUn0~rkedl|cds^~{ zSPWy!*r{lzHUyU@?dH~@U%>WRv5>a*IN6;OX@l!=%C>kRytI7<{_}@pNlTV2V%RFK za4i&dx70z1%5Z+?+f}HL|B+XuCDZZf&gH|(U&F~bb+kXY1{{3asV(sqDebTpCubgp zul92xXo!26ug6tE^S2HAYPitcXU4QycMlznx8vr4{-78x;}aKUaPPw&v7;;qi(<#h zAEhm%Z%@s6+5i{a`O}e2ze{JvfB9lnKLzpBUQ^5vA3^Dq6N1^-J>ut_EFK|sy&n8g z5&e7r1tq<a;-|B9!piJS`ZQltsEAG#7j6CzoC2N6G~E<;xclIvb^0)S+X31%xHDE- z_Xhd%mvH*~KpY<Iz*{R8imCbz@NvONo>J=x2WK|Of8YHf%or`*0rqsJbG;OKd3CC& zr4u7$E4`4-kN-wnqt$ut&OI1^B%AD>RkO0;1EH_U4VEnlLIwYhSXDU;J^ga1I%_Hp z`nZ}FF6~WAXG~yczr&n<xd+6=SJ3gnN;FbW@`cZPf$k}i+dlXq%#ik!gQY(7uS=uI z?&W&QTkQ=_J9`O>g1XVU_mg<WD0^NzDVe?T9I5HVkrGLHvA#)?UnrEEejMfPGD9A) z*`0fYwu9Z+BT!x4g(D_;QQ5-FTwG?x?b7+ne|=9hSm4D4qhcgaK^l0SQ3mCksif{T z0R6ri@Zj<lls$O?xY?LvV?rOCI_MTXJ~kbTR+~tf?VGG%Zt0kvkO=O}lO2-3oCLkr ziPU6dEcW{HN6ejW!S~(Mu-;-4+-q2g`)=wx9(cKd1KLB-X_hVyig-Z_y7k2SNq0c| z#{k}zz5{;Lhf|SuPfiX>kmg_M)I&EIYJcYnc0oVI;~q`I-D$(v_wQJ_k<wIn;5-bv zO5dObo3-h=VjAW)gu$X+YvosaUPg_SE{=BZ@6kbLiQRwLRh)A#5iMhb=-lm@c*Hvr zLgrtGvNem@b5cL}l=t0Xbif%ljI4$kVUO^gnlZW^p34LLB~RVI2q|Bk2nu6S@Y^+x z&dzRz%DvAiF{cM;ou9=;$#(28HdS<aGa2Zx4l6iK=6hd8aizVASoG*RRK7m~nYOKP z$0`+n>g~eo>isb%Rzo;G|DE_xwFiN*AZE!VN6vR^$rt!s&@u7gR9Plu`=(1f(J6xc z!zJK1u$!>W!cQz1G!GLiualc%Ump2D4`+k~$xgpmLki2zlaclb{#0^Acq~_eEv=4l zD0wQR*VoDBKDMT<qe|gF7>(s?6*>B)<S8-h489LSAysFYP^0Z6raP!QUiUQQGdY8} zeDGT`+UpA@(?Y0|wHyBHK3(iJDTPv<V_Bv)MTo86z!qQk!hMwhaop|sc<j^}8u5dm z@!dBeU+F!ltM(R7ujoQ|%NNt}UW?iM_acB}O6Yg=xac)z5YGFaOYu8))1`nu*mdGH z92%F5_rE-ajmu_1^RHTAQOr_m*fB?5wJ8CAdb&#c=}2M9)dP^&{kM?!V;`nfPQ_DZ z!+2lXBDm(X863MefbD_qxOV*wxSw>GR!;9B^si5*QlE*qTTK<MLhZ5P<uRJMSAg<Y z+I%yqKUW8gb8P=>NO$AkL%zB*1YUI}U%f$aC$0r@>eBg_`bMgn*D9Ede<FtdN#RBP z!k}gGE%9zJi-UU}#V)seSr*=m_Cup6y@w_}C_T=RahGJU=_7wxCG~GlltJG`Zmd4x zIZW0aOv&rr@b+fu#5LO()7HjvQN%Xk=~DxGZ%_}aRng)>y-s35d$w%Y+Yc0fwN<8G zkRdGbZ35K<O>CI+Pd=?n3<f2cqouE&#EzXVWvwQmY?&&m&6M`MKWb4g;}=`P1_+v> z$vLq(@N|6%EzWYetTp+fSb3;GG#YJ*K8ndK?{I)hmA$F?QW^~Twht{v9-u`9*}}7J zFJMbv1$7X6aq;&*02bQZ{J{aNy>^rO0wcD&^pl+S8RE+hHXL0&oWK5!W>tM>*!ZQB zW7P05{J4D>h~Lgorh);<TC+%bV;ug}jKYA4TS5KW4NR|l;9%X}O8VROpo!{5XjPjc zvA`<DWzBA&c)T;b_kKeC#;m~LP#3by+r_<NF3_V1l2c%Tp>)>Eh6|O><@#NN&|}y> zI5x2-cU^V@+LC@y+L<ZfCO!n;{eOi{4=<92;&C24bcM|O`3*|!_MVKpjldb!Q}FSt z&Y<vc7$299$9ESEP&>exx0aZ&hS3~ymwwMI7huM{r;xqYTXHFxW5Vr9ta$7N`!0N> zEAQXHlZo3g|ELlremc+3Hs6P$rVz<3J(X<K^l1L7Sgfv*3*?`Hq4!qtqo6}Hp{oPS zI#sZ{%LXxj;VZGBzn;9-z>hD-n~`PURy12TlXJJmNjXx9uh2V?@+S0VWrHYEy`%x= zZe7uC*F2cs+!gg^#^HT&4@jm;Q2h{v{Zq7=CuHF^mnp*W+P&E0&qfF@@THnBdE%aF zHgwiuDSd5P!fCO!qU{1Hb8=!dXFdzYT_K~n_NXCz_wvILx9$iH7qTg<>;$SwXpQQ< zCxpMMN#MS9mu%n@1(f;Tf=2l?v3pxTu88c3rHdwW@y16mqr(khK>Ql6`1TppxBjMo zlP2;|gO8+O_7L9Bn}mzrO=Oim?SgiG8YS&~FN7@*r;q)Pv-7^Aus?Pwm403W6j%qo z&jQ6VMJ?V}WsI(s6NJdy(U^654Vd1(DE|F;hwFE}ms|M%qCL&JQpakiY<gY{D7d!D zyAPa20l%iRm)k=a)ie-$iM`QCF<0yxewgrIBwfE1L2lcSZjV||gQAGn)`fGwpRQcD zbrHXubC?9r;gqv3AB<N8a<{1=q&aU5yJ>FWqw)kYf0hJ67As-UXk|fR;7Qyu{k3>^ z_>6L=x^P;YnhV=3l`(gy7Zn|pyr<SumgQAAoIj#SHQ&16g!DimXgrc>wK^VK&*0$M z1Z1KML;Jhawqw0e(4LMDN9^K*gK|;X`6;}vD~3!57i_c47bh+JPn@b*E9Rcd<>j*- z$Z~|l&T5{*SDpPqCuJU4ZV!;%8$SoC%IslYj<k=u6C%5|ZUi}RkzjOV(qPf#ZY+Pi zK<2ta7c<UPi%V_IVY$mAup73CyB^<*a~5>Lgh4aVIl&5pD(03dFR|yglwnvUieh}> zWWheMFMhdRDVm*%!R%GidAs#!nT|L>{?key<aQq+Kz9sok@y`GrR;3|VpW>mx($O` zj`CsIE({R+3zoBvh&H!VQC>aXF(hIqj_h;;UTFLy>n7=)aIl%$3fFLr#Gv@mYcaI_ z-7e)+roq)C9l7<<b=G@!lNzQ^g9l%VrJbK1?wq-V7nf(UaCQastiCU<Q*g#n*6Dnu za6UiXevl?FoPam-&fv|qU$lAeI_MHn2}OU3IJ{&#l#c5~7q<;U`Q9)LnrJFS<PW1q zzs8aA#aw>&(umsJ+(aL#kNbUa7GHTajTMqpgx9(Ap`_9T!;0UDb8g1M7ta{s=#LXz zUviXQ4N8T+O}$`-FQR4Z0%7*p{i5kc4{_Y40I*ieqOp>r<k&l@$M|XhI(<t7$2$@O zFme)`wWf=6c3<U!H)|m4?<K)DeE@{rae|>KapKQ!mAL51G#Zl*yw-FIhg)tDetb$o z4~a#VIQ}$t3~Zw9L!>_In@KpmSP8?7^{FW86%-{N6O1P(gZINeaI4Up-)<eqAs6<6 z-sfmAYET%v{f1fjn{~Uf?al+y!Lc_L7~K(HefvfK&MTI8Sa_S0de4F8r|U5N#1&e< zcNV`_j)u8ImZ7ClCFne>r3VlG!lP(4?o#N&cb6?CZN)}VZyX>qPBIqXeaezJC*`c1 zHi!ep_{ujAOC&gaO}d-vvZ=Eic1N6o4aer<<ckHU+b0|%R*oS57m_r$v_d}k#%|&G zvkv%X*<&mpVF&)<5__s97;jxWE-qhh#lL2&P_#)S?Kf{1uk>l5WR~``@g?&3z#x1O zZ7F4z<$PKDDkcT0aYvOSSmr2Y(-%+1raAuf^I8p>)(^xFJ+i>B-zvV*@`zgIgz~17 z??sz{Ja8TA0{spyg^ZQ}a0su0UD9qiuSs2Q`tcsreftOL8q+0rxQ=YenC`SKzlQ80 z`{Bp&K|C$+l2|ovt7H4uEV8$E=Cnh91lu}O6fG5KBgCNjfmt}blMhFq?F*{EyJE3^ z9LpO&2u^3JAmQ^)$!A?g&XWAw>3k8{*d>aW?kD1Dzgak8jgI42d4Fu$?!_;H`#^1_ zG>>h63w0L7P@uMvI(nQJR%9oU@~T3iv74@}bxe+UOke679yI4G-8aD9*Uwok)Bs*T zXqO-O_!0~sKB75eji`<e(9ZHdpf^bYZJQG0ehPEteXc8DWN{`ql@w61wD<V%JP&@p z7z>^`hahZ^G_%ovPYOfx%j|E|h(-q<%EBGaP*v4)o>7n|v-&PEm;9bnsp%oC%BiI# zpAtpYBSXO@aEW+B!HH+jx`JH~cgJxj?o#QHiO@sX!%1{k@E_6yZ&zeMz#lEyyE}n6 z>W~H=-s#5WYo7~M1=`?Kz6Cq{e2w2H%|_W+6aLgb8OO+zv2?N-#%zxiRA)UV+fnCb z{eG9h)w@=BK4~{;y_7U4l@a(T_8jE2UVx)<*Bsl&Wz(ZEURdPWQ*N4C#qRS)vQ2^< zx4nG`cfaou-`orlw)ROtpUZP_#-VL6KIAH-_bVf>PIXW(<^3E*UEUSY7xoW{r?&}r z=&(muFg2S*bFbT=nf698y59zfiH>3aXH_z#OJUgP_78GB8)&S~265pV=^HGuWFFlr zlD+)kh>^ck94*U6h@*B}aP*nu!Xzn^e57{|$tg3OzeVliiQZo9U1CkDt`bvJa_994 zoL%l`t;uogEHM0GKU6&W1|D2Vg119YlCVbsxBpGVs_A{vvrnW@|F;wlzPv7YFAL>` zU8a)30Raw|j-<NG8{(AETd?8IU#L21jMR`r>qbX_N<o#Vy>2J@`7{X)cl&}{lO8YM zUL|Zh9ti=Dj*H{Z&4O{BUrEVOft521Fe~#oJn1P4Zuhr9&|T@faGR*EcL9CzJxGzm zhhmD=6teRxrSJ0H)V(B)A7qzNVwN5HEKFs$YYIZq9&d~}vY7W>dBHL%S4&Qcu*Q5d z6j|S=n_I)l;_*Il*Mx^~<-#nO_rw-dg(INQZ4)<|_h6@gTc}gzdcrDwZmh}#%Xgn> zWqTDUw?BfiM}{~!q9@761=87W<{W2n9mMbsH0SChwA<~DEqUwU@7N}Y?5r!?l6#W2 zNq?~aHkpIoT*kA<Dxlk-X;6JH6^bMN6TVtc<aDJ!V$7dglpdlcl#cGi{dYcvt@|b3 zP)wk#X^#SH`#c0ygMCo=ONIO^?Q!I3bKYTW4UKO#prTTnRT9lOUkYtU1;)^Lvn`~M zHR;lo)&A6A+6n<KbA|WAwutdN3^+I=gq}VfgkM#<@rY#-!$#t(g32aN?K~Nko=D71 zn^dIi(K2)SXXx>5GmYt{Kna%v`TpN$Jp9~uFfq@8_QquBlH!05_lwwEI8k^s-UcgP z1!LVq9lkMlDA+!nC<_XB2%(8mkN8%jY|qr4TwU6kj5?S~j>f&B-<=LT-!c`Jy<Nl4 z?X*$jqa8;qSLfpM*J<?fMq%9^6KS^RLr4C4^2m!Cd|%=aR7}_Bs>~5kt<xJ0KU2ZV zw@FZWpf}v@{YkteWhvhMc7#QCj-ssek&wIpEQ%5f)%~6YPI3~k=YbM9d@6y1(o`KY zI`=^T(k$F`B9GjYEg|xJkUUwXfXqg(<oTx;;?IU*_+p(g{VVM5xTfcFZhIF28Jkz& z%D4w)R(k~6SIt7Zk|v5QR05BGd+E&(lCt6^g25$CZZ>-?DqiZ#k>3wd^NJX{79Gb! zeh!vqmlMP#%7@^bkr_O1(uK!UkDyMj<WJ7|C(Kfg$8)34U_rYsLBm9NzxE_q%=id( zxyG#Fdrc@;42G4#e(13H3R#AoD68-~AzX8o+@e*|9P?%@j@xhrJl`}?_LF3uTM&ab zU)}JNYQC&sbux_a(FZo&+s&&+cEve9UTo8tMjG>b)2p}l;LDz=G;4GuSIp0*iXBC8 z%+wtHD$MBh&>Hbfa1i$2ZzoBe^)aK=nEn2B;bBX=V1V%o$?+r2MK@Q9hl`Bp#%DFQ zk=zfBhVQ}hxf?XJhr`MicX4xiEKEBW239W9XhM07XmKeMV(b*bdj4lxUHFaWh-0~B z@lpzGSxdRn-M&277S($kgx4poiFq}5WUH#f;go>~Bz1cSwsGfV=NBteWSiv0RS5-g z;ta=Y`@CVVd^Rs%qRbAl6FIU^0acq9LSD@m*$!$TQ;%U%e`OQJZ<!2pmoMj{>RmFu z$`qXNrA4@?w1pa-R8VhgBZS1)QGeeA_^4^euJ2<Bw|2#v*j6y$L^56yj;#i_Dc$U} z?7hxTRN9vZeP;XNxF7X2HA;yO(J!c<xKG^Fb_M=y=!l~ae*yQ`?PY1<7P#WF4E^&a zQ>S%>IBTv2AB}av*rp5c9F}50xjn>KWr~qDAL*#+S#qD@LrR}R@WydXxHA13czg_^ zFNP<@<}^iabDho$>vlW-{c|49R;hvKv)|ym@1w)tKv(R0x&}_7)ED|!BQ9LHTg-L| zkzaOL#dEv(a@a{5-l%hjEW?+f_Cg0P+!!i7o0lkHt1&NHbe(Vd+p>e&TUNi=0d@Kr z0oj`HVK)QVoM25LjKV+BLAZZ?Cv-d4LUWEQv%OQBXxerhjf(SS+fj?3_Z=zLjwlph zri*BMv>z*8ya2;Gbq9-WeMmu`iB(%eK$zMGmA~%76P-=*#M5Fy;oCZh@p}o=wwaXM zmOqlG>h|Q!6=C49P%f^yY<1Z_r-%y5XVT?eeNZVRTkJbLhH~CrmH&M@3btoYK)3%? zd2@fs4<8~!*GpOStIG!dwroCnmyKkt8*hcz`|gTMVqfsK6<y?wBf4Q>-yF7^UO~yP z&U4?ZA>er?8g1?$l4f)zQsz*b6%?w9%;ZrN^WiT1(%ym|$E@J<EJuky?~TEKrgG2S zV{ymIc&I54M!T<$(*J3>*to(UCmz!0^V*5nS79XF*J&fUN~!20^|PGcFTtqVFj&24 zZaGL!KlS+$@XBU9-t51YuI(^ot;?y9Ww8R1Kg*!u>jaLm?8gx+oWZ{}hO&JW*vvDF zHU!qd(GGVZ<Cp@Oj=urZA1i^L^=s)}v`Y-IlL^yDO~4~w`plJI;nS0CVtlIyc2T^7 z-Hew)euXJ->URbbe??=VV*={#l-y57hEVb;0H4$y7r*rn5J2(=wmnh99TN2+bnI}> z${he9pS-y8i7UGlsM8hq>B2ZWe^Gtnat`sg64wvX#Hag$`E>Cr_8T4~ue2`{EZlv_ zzBHIB$H&oup9_Qu%QJ<PSA~#VAj1-!4fJ?_nDG6rCiL2oz`N}yqDR9ce%kyRj_ke< zHGQAc7K5|mWd|$pdN~B$6Kr_X5Mxrk@5>*JJ9CJ3D1LvuLGlqXoGF%^RC)bG-G94i zZ_hmXYoQ^uy{Q$Vzo!TaBhJZ&H+MtdmG5OKQ<&y=Nuy8RKcR!UuV|LlBG`To6Qf<8 zQ^(6)uzrOXe#?79Z))~a{M%9Be&LPq^vG@kt)Hb@_t%nFcWs(r=F0O<?&qst&w|Q- zJ;dR<MliHZAp3^xq-h;RaVhh$Y=pgN7VM2LP6pwE|NhbigK8e<c@7NLY75#*d%%09 zD$3fPLd3N;ae?_H7{6{PXCF?5u~8<doOB8Ng3DwEcGj@=ggHb^Q|0yUy(z?S4H=9` z<XVp~9vxJ~-M*~iVad1YzeP3Tx?0IqrO}z4=5^y2MQYq2vDDu5@rFpNle|D#nqg*E z(*w6v=$UB<y=OX<?<#mi-mAAz%gD3h#^Q;*{k<YuP4ABb0%r-nOKgRYug>G^!Oe0F zz57C#?H^b!WP;)=SD19M5ERzU7?b?x5Uf)_37b2%bDOs(W*0>Ze-(QQn+#h(HT)@6 zXsFToj_Y`=R}ia4nuE;P7PBt+kbIRVG<xRK%DbQCPn~@rVNSewb5TEfc5^t*`Eg(P z?_Lvaezl&aFH_{iRZ~U7D;;r(Sw4*HI|KZW8o)}OKq16E8mE2Bg~FX3AphAFs63(v zwgHPNIU<;rg$zckr=Ou^cOBfg7)w(FUgLwQ3-Fe@lqr~Xnf_K9V0!mSvY?(D9D*Dh z(R$o<j-9?sbR0Yi#q~ewXWdo|GOjMum$EL2k2LT<cSFZV|8ApE->a~?XCx&Z*-V+| zvgw}Ye7^9~lB1*<fN`Z7>+2k%qry2s_4ykze{v5@2OcGr9ed;>W=+M6w=$mVoW>q& z4JmB)2=KCO7Hnc7dCmSYyr=yGJg>Dt_pnge!qjCj*}@QAj@+cNWd`Nx<7_d-CI*7+ z!$5hLg=5W^C9>?D1LaHKxRQoZ8pri9qeZ<p!Na6HDjKQ68(XX7Q;;a{$#&AozbBZU zxi4i>I^y6<CrI<SGDP|fg9*=bY5D3oc(LvnPUxi0zt8WIW_mkG<&}&|_aU`xc4N=o z>EyIH9cy-Ufq4I0bSxr;R}3G7E4LQ#;BU9#tu)_^aZ{!19})o?3S}X0Ytbp)1YIv2 z;c*%ctbJ9HS4y0-w@;>E#(h!Z{|{zS$^buUsRdQ93W+^+OZ3wpFBFuS(jST2H22OQ zap^f54rxCHO2(P6E6iN5c-Q9mExMLe`*p%kHE|BBIy|75p|P^<2BGwAry)1~7smw& zKH&9fuCQfYsW`~OT#!AU05gx=5_|Z(fj);)WsN`P3I9xVpbG_&ztt}}n(Y)Ue`-2Z zV5<Do(r7U{e-G=}W;)p12o~0FRS}yOzZ6cnrbEsA8Djd$K4h16j(QGpK(9H?qNTbM z3~%X%4!NUgP?sbyjOvM|nZ}sa8ZWvG*Tm6(OF)E`qHm_NxOjh|sPMT)bd@?!oyYg) zZYCKL{~%3PtUD9#*7cyG0#7kNV+*Fc-=#ebXJOm68^Y?HTIg#xS1@xLi_Pw4JinuZ zkUsJ_>zD50AF>*{>19CYaR3}L%cCb#&j}Wz!ojFxg5Y;z3cYh$M~$0yK$GP{DEL|h ze@u$SE2^z!3quVkbNF7!F~1<D-_nuk_IizN*A`Lw?6Ew!&qHy`pec|N@>BfqY6bkK zokWgiqo{fO916%G`4zoE+`+p^?kk<M?0PPSC9%OgcFb(ry(t-b#wkl30}E1kX9lkR z_V8{0TVYv;b1*9QD;WOJffB_Z;;BC`;6gVu7?#$Dnxzi#@!f-js}1MqQJjt#GSLZM zR;{Jo>juH=9p5Ftz-*W)^|$TWiQZ<EgF%9}ysID=fA5?Ls$YxbtBP9W4YPv5bZVm5 zv^xquCCsPLYu{mhDhm}U=fTyqH|_9R0gu;P3HzOj#U6_a!RC!2e5}@zav{^j2KOq5 z8Gm)DcF_r%@cf?eBk+|lc};ihB6Vm=_q`KpBo5UJiI#M#;{dS9aE3qITEyAjH)-Z- z7r`k$PFVReP+abCT<pF3q&VNWFF8z!qTIe8VP%;iG)?;q18M|(ux~jzZZ8$jc8G>k zzxC<0b}0<<R1iKIU#3a%Lq#9U7s8F%7wF@s4!q#(ZE^54TkL0|h2?jm1+{~39Iu@T zrI$60(E2BowjVhop8nIBO5a9fZs-%pE>UAk)uWX7XAzv~b_0}U*JbV5)iA$0mhLET zfjip4G`!bnc+q1eth#DRy&l$(r9voF#(aVxpWgE1S^a3SU;tL_?lgJST1Yw6QEbTl zA_RBOr`@ODiwSj?>B-1B@ZQ-0p3FNYdDF*Y$8Dt~&%G@3=@$<@dj`<3Lrvmj%~HW5 zsaYJ_`6Y$SSx3>@&xIaCB~DVaN%^bO2k7c+1w7Tg6J<^9jRQOyr0!8MZMAs|Uk!7F zSL3y5_k$rQE^VY|*1v`KZm;NRR0q(#sU{}0dDF6%@8CH6jF>g<8>nVvz=#%IGP-b! z2F31Xp>H?*bh^51xxq6?d}2(e+hz#AswEEQnJvPn*h6Aeu_u|lJSdjzOq3OSr%8;P zEhx(}6uK;I6*JNch0F{qY5#3Wr?m%?)3{W~%@{1Xx<3ld){jYkKOO!x2((&5;$pAr z!uq3zqu~ihem?CAO?zk!Gxv@c8}ICaWj{M`;fvWcXib`6KKwhZAMY(_+intThnT@A z$wmE(Pm66l4$fFeo@<R1VTy8|*zjSlP<{Whc)`OJX1^W>HO|ovS;BVus(+1S6aItm z&ATXYcQ}}yS|fh4NERmj9!A4otOI=^Kz?G>K-%;^Qk*$88=RJ}gEb9ZA?$t;IG>qH z8Poq#%D6!2Im(STzCfC+wwKg+D?BYW!WY-dL|=y(YJG7Aia)**^L3KNc@jVR&6#uJ z)c$=i?r)rEcziEugujt}@}0xgDwRah7wvaDBGk?AN_ltQl@%@8FCM(0Cl>dV9I5Nl zV6V2sC0V>nXj1OWK>>qh*BWorxUbIG-03US|2Y6Xiwfk~R`D|Z*KV|>>tOhxA5RHE zZak#(R4CC}Dc0NHBVT7X$(7d$-Twv4Q;N4@&uv<mF(#R8jvc4Q^BEMkwHpptohL7< ze?rTDYO!VFOi`;TNmP&DMf&Ml!l=q_m>>9v8uac$p6Wi~`>IKxxb-dBR*ZyuK38O| z<~Km!!wBB`-xd@lc4z;m=Sh9rFTu-d73^sLEsOr}4;1pM;Ci?2Q1(HEy&o=z9m^`9 zYwK$0XxbNlr4kJ4{zeQfyaOhsCm?X{0LU=41FLSoM1$}acyRNc%)Q?uxbmYAI^4fU zllZ4dk0;~5ZoZgZ;3Ym7SPkV48Wbn578K7|K>w*>bh@LA`iegx=iDK=(uWrK`Y0Ui z{&|qU>lQFdek5C#l?3fobrQEgfwzU5@Q;t(xM7PvDd{|e0i6xN_q;i^jg6NpE>=T> zfVa@pycAa1ou`C?K6p%{Bb0hvfY42fXciv=euHk)liq`A|AJ5oyA~%*o7{=->T6O; z=wh}Vmrw2&;$@y8#@M{#Cd4QRw4(Jtn)=lhTeK(P;G?t9V7dV~Y&ECFfqh81zl|_; zaS9b*`yWN;;n&mu#qpMuhQ0}vq`j0vq}1o0lS-1T>?A~)Q6#e=l!lg6l7xgbsF3>H z^KJ=A%E*dHA|opz{O<2R=uzE!-|ur?ujkX29u)~Qul0VIuul_yHplXM8}vadzlBrw z|H$>(JHfuuCagF;0yf;&gwoxKpyb#p{$=nB#$XvN)V{>E1iS&WPYED#ZWW1Z9Ys37 zOS!*Se^A~MS9~xaf_rbhhClh#g5RP33C2}D1$Tqxa7*Ynm1HWwM9I@IP(7FeM*OCQ z3Xybr#4kQE`92KVoDLF8Q=s0Wf!~oaiY^xh0d20~rh1JN9J~eKarhFqz*8UJY|7yt z4==}O=QB79>m8)~D;vxnz2}=M2k_rNoQI<$&T>zZ9U;t0rE-z?9bQ8xh;<(HA(;vj z&iY9KXuW8Gl`{^*fnpo{sniK?LcY;~Qy#=(UQyB4=@8da$lq&!&AkeL3jQMw5O#-C zxoSJT=$?Y;`<1Ig6{tNnlVV&0=*{j+Fu`dREaq=eT0;lCI4X~uoVGitEepc(uSuM< zf-}e~2<JfSSKLqii%@gt2l!TJg6owIQCY7tS-nUCp=HBY*qnrGzN5IF*=`WLyqenK zw^;3WD@?jIi`zeN7yr&i$FU*rJzsO_D0q2yK<Usr@K1OvYO*)MPQ59j*hi_NGTQ{P zRqj$4{ZWr})HE2JG2<V#Phq}!38F2FlIilz$J~|W2e`5*59XNjp3a!)!MuHHti@#~ zw`27oh}fk>nqnz_|Dqbsvdjx#ZF~*G?^OVspbJjI_oq|u1AMKK!Fem&Ikf>t_@*~% ztabil`1B}&+V77*X&n*%yPgdDRw%K@-()eYbtOEgzXBy~G0@^To-W=v%6s@Pfl(nA zkT9c~7X6GNqldTo=SSS&6PFKTK3}T7yKy<Wt`htX^Zr5k*#BT`vJ!hY!U!Vjn)uU& zQ}D6w5c0I2%_;85hG$cJdAc^3^X#91gT7wlBb435evU(#UhOYhVfPWTMjGPszNeHq z?}I2)rHgF-7D0-s7M2!Xr^g$OM5nsX(Fm@CD~|-s&M)NtR@DPn#yAs`O`OG((WJRb zpB)P<g?5+@>-)3dy7M>A^(9pL=j?z7o1G{yatS0HJ;ck7t%XU}pZV6OHBj?Rk9T~l zPZ^(6nUu>8@H{7UHE+EawSEoZH?_El9=uheoWA|sN^OEskDk+)urXv-WQUHqDX`lq zj~}yFj`ZXVVZ6eAbUdaHg^T1cwx5SF6@8q+w`F)JsT|DpcR>BcHZh1CD`sZC6N`lI z?=+uLnD}cq`ACj*NEgl{6K_lLRc8#)HRuz~a#81cHB;c{sM*lT61f@0r{UX`KzLoN z2D|DMC}CN=L&#=fCx4-drafq&6`+8#_78+TqXQ^)@_!KO6GR&xc5?l<61eJx2CP<3 z$S?f2*Z!0!6ddO8wDkKkF1q>*|5w_Mvl{yymdUT+wu`m-TWQl-QjHu%UAh3R1M}F~ z9|9lm;XiK7xL2H+ISE|Gp}2INp}^eH;+*|$$uaaZiTMZADP6#I4)&nIcVBV`r;da* zx{D!Zuo3y*G9v4X(Qtayd+xq(1sS_0!J3{}7(eqISG`1sZ#z{*8(YdCLo=V#H4?lH z+7m0C=O=IysyR^Rh-fN%lFoj40Aa?%>0+JWoC(S!pPf;pWDyR{%P#QK9x1}El?SP0 zO$)q}QG@5sdC<4BfjYJ*KxVfu-3vVhD=wS>6(P^Ev>*(Qy)y^i;RltqW{P`T8LUve z25;;W0bLJ(%3?`YWEU<<-?)l~2k(Wg|1E>ZBbD&WpD^xa-b*NmX#rmHIGtW+&u3_~ zaz7F>n1;(sn&(@>+Z`<7`%6Pb)zL@!j-G8~6)beR-cBQb^Kaa@GU4aB)ypl}U&FRc z^59o@L~%;vTH&bvEGk*Ng-vr2SX5^eNhe#DE$QXyT$l^I=^cz~n~%ewzAv!TZz3)Y z@&HY#Zo#d3R5aOEh4y5c;n33>P=0wK#Z7evuZsnoN!Dnxl&*t0+dsiGUuCwBYCvVk zHh%StM<VgPeO&j$d9Wbt1l?-C54KaI>6yiCeoFOhuCB~Pq;7jl;GXw$t#L`zv-lE! z|E(2gYgqyfQ!43WSvoykvzUtZALP{Xj3Bn}H|!}W;0%19z`V2O_}3$iQ@)S_Cv83H z&eJ$@a&rTfpvByi(bqvII6+jiEsh)G=mH9fr6_6{2G@;_kmy?~e_vAxH+Bbu{HYf1 zmU9fc{~F13<#gfVOC^{k+&^4|-LJ~F4<eWNN05D?n=`NN#j{5Hv19pMkjW1N*9ZlA ze?f+P+6-vRNkwjhWWL~slwcu}LA+|g7l(%aBb=k^qsntf7oh6aR?hdM3cmU8KG#@b zBIFuI)2(Vrnyf#TA3F6g?Yt$&G^WRKZ-?K9=^s03N4PS^KGCAK`P12Vh-Q61UqZ;K z6cBEca4aVkGcIL_qIHI&HCeOUELT7gMuOS29GK-5Yp<W>kH*F)xn|yuEgxMB9>%Uv zDdeSBNDRZ5^S+T^daKB@D+Elt2CzToQ?Yf|Rq#=q4uOd_)Eqhr{?v_uBT~^|*L#Ia z&QM_4>L&2!S2j0E<stbE8H1MF<ni;19y0hdmy*L{N$r!0I6QAQ-(Vtzp+Ea!K(>XD zackoKE=gwIhh3;T=rwddUPK%HmgC4=8OlFy3%BoS3;c5zcr|q`pIh|+dVkL*d?Sa8 zc_XkKKAtId$+7UYbHULhiJbjarj+kH&NeM9fRUf~L*r{t`n9-+hF+V)x{hYEk-rm| z_Y^Je>&?j|KYRqc6KTUXdV7KF*bR7SSpbElc5)u8p2620q2w-WPcKxX#a|72Vb4_u zK!<QRWx4^@oXBR|#(pK-#^6Pdut(X@0801e*w+W)ko&ZWnvYqccTEcBr_H6bC`}yY zYRb0!oWSQ~z6SI72T;A>D8`=97SX<^u=%kPW@gQU+QN%8smco~{5pk9jXgPvtyxc& z1k=o0O_A+-nCf0i?Ftqwsc|1>ZVhI?6$W90$W-{d2VhoN7^Pn+gynm5>59u}@rgA< z*#<706<HXuOFlQ?q_#Jn-SL3eoZAh4&koWqTPa+lA43Hz8|m|9eR%YHBK+|mh6c_P zDd|HMUALFzG}oA7v*1k8NSH|@ytEygn|$caooUS8(vhl148ateiTtUKG0fx4ZV0@o z$~xZYvL)q-6hFC>&YTQ|$abDTJi!^a-xPR>LSEIt_A}SK;}ribvj*}X`l6!eb}W5Y z1s$68@V$5lX8&8utozN_te?(YroKPu`YB`M_#vcMGm6_7`4sF-`?xvR&O)O^H!WRu z6F!U?T-7N!=s{-&bv+1$rb(l@U6%*q?B<d1;tq3=G;u&pr9S@bT3?uOe<Y5x@h8X2 z29#1BEqZ??2@*tu=yKd#x+V00Q`tN?@>mD5ABd<(+8rkqNr~pAI5Oj=Gf>_=j4XFr zvoq7yVWhVNZ~c1$$aW3k`SYKtKtqYGlD>}t-*v#*;W2F*vXoP4x=UNb<4{%iHfUW{ zgWW;9;N|X#c<}WhSQ*euiaUq09$i;7e-(oLNwK&wuouFr6q(Z%cftR=0v(NhL#w=w zNWynvWv`bW_aXZUXvuhSa+6Z|7P~PN=(T`%sk{btH3vm|sx_u`HUvZF@nF<DahLvG z7|k+$E!fBrXQ*!Yc`&><hiOGb@rw@cLd{`=k<$#Ip?go#NgsQr@b(U8ZnT_j?|4Qs zy8fb=&ErVhc08|Q{EiE%8;swh%|Tya@=XuXg`w^9*ksv<<k@_-a_FQ+s16tA%faWk zpA%*A-QV3Pcf$zp2^_#x9ufF`U<veme#W<%)$%X$vbg?mDc=30Aqy<aVna=e$-G8_ z4Y*pyt$!@=T9c<&MFxN2{T{AIwd6FATv3BFuMER)@wMD!Q%{_tZ-f#54aA=&3ovf< ze{`bfwZP5d*(<xNL<ac|b3z``iv2&Jby2#*fL@{VYh4S<1Lr_>n=I45o5pVaE`;Zq z2OxXKeHgrGDupgR!zrY<axXqBa9a$g;FZcp+|kobTwlcwkm)}Uhs^Sjm9`71U@!Rg z<Nz6X&8D!Q*E!#>vEVuNHoaSYh;yzDVjHY}Q-0ijnz+TC-yxsI^kyW`T%*f84I9V4 zRxDu33;bxEM>K7nBMbgzowRVFHkDQVBRXn_#UE-x+wVHO-%tRPZKp8tz<B<tOax0^ z(N104{kbo=0*<dsf?4x};6u4H)~@ow<H^PXZ%g1ZIC)dI;El_<q{~Hg*1^pxN4z=R z0c-Z}qo7O8Ak|#V_g$Jn>%J(^%qMcVYqufVi8ILV#tA-pSrWvN8oO<J2DVjo^NJG{ z05(K$0n2|=Th0wQtFwU0-){x!{26Ffnd4x(&6N%6nF*(jiy-lxF1nXngP!(gdTB9; zY6cb2p7%ew#xfoDbfhj^+5I2(6r6x9^FP6P^JL<)HnXlz67-;P5s=y<l9bxWep(Jd zFFu>MPESSk%p5rGV1_%_7_fwVXV~JhlB8$3@{{T_NNdkQ)*yC;hR4Y;q9+dYW=_S7 zb;Ds6NK?&Lb=2rxgsv?|>Gi6e^rB>M<@RS%IOt(Kr1fcurp%M3v`@(}?f68Z@aaq< zG>cQVDdzO8zEg3z5_WvtFUp9J1huq_loEfAj_Ln{lm>m8E`CS2=Owx1c|xbKH<gL) zhD6&b=$!QkI(}rp!w>hU_+L0@(=>tVdQO1L^{3EvTM>Q!MBvOp4ydA=>u`Vn7nt`- z9-nH5(Qxk*n3wc}v)5L1RE@bz-b;I7e)JPCx)MmP_=G-LY{Dpccaer^61VKfdEBUe zhQ@uK2v0To;eF6`+Ok86Kd-5S9X4{@%=I<UKG2+2x9PHFLHB73wNaB@2ei1ZVq|`f zE*`r})ix>A@LJ%;F6e{Iz{&V8Zxvsmr41Xsx8sw+w&bz>CeJUm$BN~t*yvXxnswj> zG-#)h?bE5aT<GlCy}BznUaR?yw`}oqpB?KxI}+Vpyt(j|0kE%M0VnC{@=05>sWP#Z z8jIsetZ9mI9+U8ezczQJdJn|joDF-YX|Y_TBCy=_j3k5IVClFW%=p_NG_x27x8?lk zs-Xo$tzFA$zikK8OWO3<<voRrU5X*Co}z%zLsa#<h$`o1kgeSYc#|GR_s{JDlP%Zi zZ&V9yEUps#jy_z_-EuI>k;Hcsnm}iGtV7R=lMaplMS)t63fonj&6%C=;eWkWq%Yk@ zWIQN=7T3O`iSY|SqWT?GFHr>>sZ!W1dw_fJP>qSRl_71+1zx{Q7WV6}LW^ICFe3d3 zKQllJ@4INRWe0@}{yPs!eN#szt;W3TtLeh|#FxT;$AXQ;c!9}VO*C_>Lq=d4*P2+! z7vG)86om}J<Qwr=m#T@QPu}ACcK(3>_B)X0ym=gnk{!O?I3e!;w-J7fRc3E8L%=P2 zE-b6l!S6jIDQuPl7d+68e;+X({mb(zXRD28I*+WFpMfdXJ6Ul}k<D=6<wTrUd6IVy zJ`Blqv4S&wA@6Ic17>Dpuv6BB&Yio+t?)bpb!ponMP&+k%-9L`@03I>Gv82Y!7Ofz z5(BZ&t4|U<WqNEor9Aq|YjX$qs%@^Mx;@76)!uUM)Olr$a;?WyJxwx_Fo&7Pb@Akl zF#0$)oEjgGr=Dq!tS@*1)B9z?dIxB;=B6~ZUqc(U;~L3r&kziWzD^lWlBs9xTS}Vq zfesqWvz52iQF)zko}96i*~UkJSkja{9h^Cd12f@~%RR_AtitkdRSS0m8?YO*4j*RD zWoC!e*gr!_Jn~u=<wjNUx#v@85A#67eSi2#`EH!*!A+>`JQPQbzYC8>W`X*`T)4Wp zh>o2!#xOt5!DU1e8#uh09*n(ByCx^Vl<#->XE(B{BS)z+UpmQ>vMczoh!~;Is>f;$ zmv93o3<CT2TVPjxFYVlLftNA84RssaxySOtE_dTiu<?J*J1wc;uIFZv+2}O(#CH-7 zd2WiU<Q|Z?tW%^Cm?(H2d!TXQBplo+<d_3GITzb-`ulM&_jTfNsA`&q?jO!VQ2$JD zm72*qOy*JHgr}sv^b@2l)Zuap_3=Q6wD1hg=1(X2qTll}@>rvfGWT@2DiP05eR7ft zwi!c2Kr!Daxrlr9bU@YSpDjRvZz`va^oG?cW2tGw7g6m&fA0I-SRn@;3nd|q{IaBG zs`n2N-7xZ}G=&|Uj#pykj_Zf%{8e9mnX4Lt$_QMuRFXCMtfP}3|H4(s7kCs4u`cTx zFRNbxK1ueXSowXZ@i+(NRytDuEJjTaB+z~NaEyGa;W+%EBby%f7?cxZK&Nc3c-Wn< zqTR!+@m-54mK~JDD<WAiR<Ogt`}-(-NGNSwXHBx!)8Wms1{$9&+-(ol^A!=MIDMNH zHGNhUO9uYOA|DLG$Uq}DvAdYob%e19Vdwvk3c!E+UDzNRgU<8K@Y?NdFs(a)G=p52 z?U*4b+kchy?~%ofd-kCDM#Mt;W9ezeM9`S5i_2>c@cY$ExG7RAnL4yM%vHM%U)|=i zc{avac%%;sE~P-z2u@VI(u*11`2<%UPv+kChI0}{YV@o{3WwC(f@A#$VNRWxuRddm zLDzC2@5)wA%Vq$ocAST{6Q0CYgn{34Z%9nY6d1TOA?a;7ud>aaHXR>ETSm>`>n1-S zMQsr*T)CWO9uae<N2=hQ%3#nxSVE)In`m<OX6im*A^5frLZz%an%*x)=j3xF_fLZz zRJg&p*9&ZX?`$yCT!U%z8)3}A`RvZsCcblLDE|_2_>*si8T{IQxVP;VToekyV)wxU zTR)$Mrj~FS#a>`qTEJ$?C5V?_TE~uWNuUY|16XD^AG#!UVQSJ4*4kD<W(`lcXyqW5 z8gLLke7MLa-j;=fL4EY|Nfa2&uBB_2_AwVzq0?gbhr%0@$Ti{y$%TA`oI-bW`|ySA zhmWJ@t?Oumr449WmO{_J=??CuvHYix>PQ>)@o{A-zey&dQvTiuEI&Sx{R+RtUwM6= zRHm<I-S3o9bMJiCF=GKa9e+ZnZQUuPLmBEF`a}=bH}b0;gqfVCI+O~TpZSL`z^JkD zG^x*@>fE9!EjW&rU*5(oZOWy|J1d#@a9vz`S{A)coxpd(DwrkN%;oFlpl50nM&_7s zpTCFDtY>i)>b;!mvx>O+mNW464Luy?H4RB-k*M#h0~&-!p>feqc;(Rmv}Vh-`t?${ z__;4=%P-(c)qml_KnE7}?L23zeuT>9mNK<Xa+tl#gFeVb!JW6JIO?3b<LInwa8Oy1 zL|dfUjB*>AV<-jwGjv&cdK{(7%Hh4LY<l}hi!J>+9MwZJXj0A@PD=2Ue%Wx0S97?D zj)G@Y)5>1>&YQ8~{b5j}UI%r39|V_V1W64(3~T8XeH8vL-NI&oS64JQswa{qxkj>i zN~a-yOAz1MlFB9CIE0%2a$qk;U{9tcMRo_Xe(4nWI#2^z2W0bI134&kQ3p_~VxrAC z@cZ&$^pxm<&QG6UTe%~1ySp4~{;Ki^F0H4UNC}krJOMMO+Ciem2a33F#>!8J(v_lM zaCzNGCYIGSz~~m{&v0cI<{X1xTVBwL_+AJUchJXr3rhNU5>BPP5eea=%1q@j7<?fR z9|~OzlQ(17gQ_(4ZdepNn{W(#3iaXYz^mx9?>lLgdBEh6?!009S@D$cFb+GTp}B1p z*t<lcQ%n@^^T?9vS+63ks0?m_^c83f{^uzB@Ei-g3#h&iAouc2GBX*){?0O{xD3-O zhsF=Ise1q`c3jNLmu+T!W3MsoC0F6g^8IL8SVYkmg}r*(6gocpJYV!PLCpO+hZ%Kk z@OQBb$yB;w)oUjlvAl_C8C|8lp{ev~-*IY;?d2Dq(q~^CCsX>?WQy7ujW4<c?@Ws( z+uSJ+Pw%W`B@3SN67S?t^5i1C8d`xP9KZ5KQ62mn*KjP|8A<-HC$gUjlOf`GIu~A` z$h<!NrEA^e*t6~tV2~bw!y>=%t4z|Ex%*i(T$jwwpUQ{XW5aOj!!tNl*@79R%tfC| z{*ZXz7@M|vvGSX4Y;KMz<anL}?d8rW0hP96#u?(8yd~sfE`hv>Ep>U`rXo9Ow6wED zxxhBj+&l6hWw983`v2p@g>2b1?LemUawK!@j=^z*jM+8ed+s_QfyDV2A#46FE}qX7 z&iJG7MX-=J{&Prl&Y_a;P`)FuXY1hld>h(6e=!a`yNm5Ac*6A#z6aJqM%&py*b_*~ zph?s+Jb&5@pC`SCdX2H1;<h#H`xjOAQd<EtDlM4AP=ktj<9Y-Z?hSI=b_VIDHifFT z;pFo?b5prbs~a9LiHKF#JbY%cNlX92(Z{2amU0ef7u0eQ<uzR6v3$Jd?1>WNM#AW> z!#L&GJF1v81E!}`^5cdnl6%7~dOw3`yJ7&EZ?I&sOYd+78w1$#RKUXF)5yL*n;B1i z1Wu~05D^l^Ry{7pHP=b-2rMD(?o8Sk7|mpRzR>#WF<6uqjGY@svehe|a;x}B^tkIR zK5Tcxq1gi<&{GR#|AwNI#9z8M%9WMO2KIS?7wFF^#pGEr*l3`PN(-`CLqQUF9$JJx zOWP}7MvjBh@xvjkBv7~mK8N@vYf=4EBL{VsBDH`Zm=e5}3{z(EGbfu(SuHDYUo+C7 ztsxVN#wM_T)2!H-N2*n$3$^*@CIYkR<ydNe*n%s|T)^w=W%0v>11MsFKeLbOg5OJj zuwD;S7OR?1g@SXm=u<2m-ID|PF@mF`_%hvIkxlP=9)V9-ltcfBm2B>BVV+QPiPsRG zV{6On4(GN#6!KlM_#!?Tt^b=yk2jnJE!C-5BD}Y@jHnQgOfkn+6*Vd@NMmXS^(;f- z36&{VQoD*B*6*%@z+A<uF-C4sR3dnJl!v2R|3Jr*b0>tp>t`w%{0_$Ll))rk9!~{c z<`ezLkdo{hm^js+ZE`%vPR)KmTu%<&lXrop&x#Ow$OY#N7>OIYjhL3^d#e3m!CV6x zM90GQ@YViED0l0i13kttq}LhOCYJLJ#^W(1&YDbiPGG6-dZ;*MzZfr`g=2j#F!ZS^ zD|{`%OlO}Zsk(z;m-7_NF21EJ|5R9`b{AD>s*v}HYI=3Y7cZojGKuxIVhcRZx}I3F zGWmGAA)ijMm(^%*>}jI2o0wKoIoY<JW(ltILI2NP`ZGC-tNghY>c`5n+ucK$wdql6 z4|&8l92m-uD7z!H)^fpZSHVHe4>c<|3`!9)32mk9v>rnF@3GkbE0fEPRS}i;9)?d> zk6={MRqCqFgVUEbvw4@a*!;4ql&z<ZE3(w^y7wiLYn#JfzD|KD(l5AiU;!5#^PrVb z)Oyf?B4)|6cF8o@_DNuA&TWA+hjw5Q_`m|4?X0%D6v}qBz)hp;Q1$W*7cUn_|H|8- zcwQ>WZ9PU^;uZ8)SB6fGGseIL7qD!RKhGTz-1DoRQBvGx^5f=#Ow2!Vjei=;jMhVm z?8OdlpDHnP{$BB>?b}hTxn6MTO~&(852&fUpImPYXS3{Iv7qBTByDb@OE(wbs?j~* z_vtt|uk$DEnKJ02<brD>+}Pr8-LU4yVd^d)hzqkUG5FdFsN3O6MMEm7PWnG)QZ-fZ zv0Z_jAV0SEm^AwsSVph;X5PD2lKP{b^V!D>?H5Yxq1rwdreckx_vHpf8@`1Xu1cKp zfQ6WN{jA`BjzdE~J(TUPrChBG@bmI3&PaLyi_){_&RtESY6lU<iUe1vNd|a^SfEwD zE5>ac$ME(eOsUpEsn#}3yY`YZvfV?mqU-#efLJ~|ehuyH8i57!CuyvDGG6P^ca%|> z4JxjO;ra*z^c&kxcIR_BZ?E~nT(=YCez}3F^At)J9PK53>%<+ljU@8ZgPPhC%=}~% z-Rn|;{M=i#@A5m&swWK2448lyly#VPpTLjZycZ9~MbKOaAIf>1fptcQA<t1n0|YN| zc2pMIb2A@x+6OYl(bA-%SPx6KIibmd=k!|s7<_9O3kf4m@E6Q?;OgBK@O`}^#Kp{J zMayMHHx<`nYFiIjtx3kMU-fa2gBsSv=&@IyA5xRRyjoknkRC_t!>kDv@M6y)+MXOG zKy(#p-<vT&Arg4aJC@&RI+P7qC{QDx1G{G-&;Gu#fL{ZJob%mtoX&^6mB!14;DVDc zL3HH`1eT7WJ*z+Q>kqELax*CmD~;o3xfhC5qMIwN{yPerln&5cwLT8|tT?%;=V;Ow zu~^S$CX0&Br6i4G5F#DIPcsQ7?b5|qAl^W~YY&rzgq!V#gA?)o!wQ%d84ZKWD`{WE zEJ&RsDY&UVle$?rYm-%^9j-Q%H&BMRo>@mabE)!$aS8;qPs743H%Lm`pWjsSTdcKf zHmOTGQ}5R$Br#P9yYUvx8LkF8fk6(jUgm6JnIW{w=%9aigm~lP(bO$4d1Aypfa7;_ z)z5X&K1q*>6rWPA{xXnU<%Zd9-$CBy0nNB5jeq~lgpu32X-w93ObO58n=+)BSj7gD z1;$?GU_J17!h=qS1<v36Nt}i&IlVF75IE@q7}%>&ov%3rZd7FAQVk|i+s^k@Mxf3= zH&!tukN*@byhkqt(1PkVlCvdn{ubsaF?FiAs&h4&Y^%b{>qleZ&eweJNe&8Z4lvqV zPi6WFP_Xe3ZS$<BWBEz6WKR!`h%jQy?Bem3QUJ3XF$@!3hX{VYQdnH#NN)xnrMHg5 zSzcx&n2fW;vfq!W_}~w!&J=d=9p?DitDk>I;qdp-boRb0fhNh9a%}i1ypdi=Zuy4H za#=7|6+VGEpEQ~3_)pxaPm9qfbsjS}R3iC>DOjWRgUjAD2lS&9(4uNBx<q&g@57Jq zqID}Z1{E{1T;iZ}ZV#t7TLhO419_>=fa-J^S30j+!nB_wH)MJeySG-FeG%sAFXEPQ zA{AE}YmrW}E1yxowY?A>=|R`*Z0Oe71UPl_E!8%TVtQ5YC}gS;v-k9*xR5XyyRDF- zbtKvC+vnJ<o%iAXyOp?C`WyB9+(f5xU8w2yWEv8e3kH{caYd8REgv_A`}X5INjJ6f zE?0xttBmy+U113FxB5XQ@-<oN3?ucWj$F9-4jnryiNf&?)86WH5y8mr9WfQ=-<j9G zS)1U%-$z*M?hgKOiv*kbNtu1S=M35gXCWl{11Vf}rDh2;Fq10=b?%2)#dI#{Dp<lW zg_ZDzAIK!mt3XD>LS`^S9(R!<HojcVx^9hP55@#RonZ~%y|)cyo(fs>!e-9aaTw}6 zw4#nb*?4i^G12v}`^kAmDJr;IVev2<$5Zk>l*0rM<)HOk*SSRa>}}5n=(=Ib%sJ?O zRttY>T@`J(l#TJTi6Um~=d42f_-3^nK32kpv9~UCu;4AXc*s07+EGUP^H$N1BNN!_ zsU@6ga0bbKiKGu%hV19X_b~oRDI_coz-(75v>0iDZdU?m?!yZd|H+Nn|GW+v!SyV9 z?_o4wl_#DT>dm}cy{Sjjlf}4O;48K7lzlLoKYzHAEnD&)?ksS}fNDE7<Af2Kd!FRN zhUu{_A1{zqv@bhcn1jz|{o$7lJO>hsB!v#H5$@9r$E%AiVB@WeFmA;wesJ%0idnUR zUll$NM@lh)g=J3vk{jXDm;bmyc0$Ja;v-m)?T$trFTq=CE$+Q;z=Y2>|Lt=judjN6 zg*})hTA@1!G?ffk$c*tKr*$$+ZRK8C;jVzHFV1pSBh}GweJ4)XZNPL257O%9I0}xl zq^eDesb(sN$$3K|<edaLhMO>6*gtkE-Gxlcef-X=2T)Se31e?c<KQ+se&%gsruxC1 z%KmwP%(wCE-;_}>|KwnnHA%$$>%90!CF+p>O$D2r4$-V7MwAwP9!%yMQ-{M%dU|Fy zOCOv9Dd$G9`ohVmNXw}6d=B$hddkKAH&AeA{)Oy7O*V7jKFUqWBH8NG{Na`qIyC=1 zi+=V5`ZN_$t9lyd2yVol%Fo=oZG|vcR-5bdXy&7&MxpxLi%=F60kgI>k;1=hCOCd^ z^|8Uss?38XDSx1WW@g;0U`O;V{wNL`^RjaNswW_CW(LnBPvDOWa@cO7%LbKS0n?I1 z($U;X(=O<dZO3KMdQ{7d2W-al3}IK~8AS%4$8uql&)9EVlaHa#zJY~{8tYSg#fe({ z$@l9~J|pie`EEHNF#O_Z{eWup@t;Z!Ydc|A?O@C+O@!Z_mN?|tUcO_!FM58hhEVZd zh;g@doZj!i3i1ZghnDMf`O{Vgyx{zaDC28li=g=9Zgd_$#L@bv;Ck#dK#f*g;hfnG z9hRkBwriDWu`qu<6l94JF%#JACUw4P=o0ayJDb@tO$5J7vzd&iC6mz{?zs8e4mNC{ z6MvZ3qSqzw`NdV`P!rV8URyb^qW)ew7;FXa5(eXiT|C@yQbH?@u`E)ti1Kpcu;gk! ztTa7NtCp=o86o2}s(c(oUdRQNv{`gf;4fJX)S#|fd9rLXV2$(taKSH&*psVyprs#% z2A&?IC*&F9w=E=@=jmvAaXa(ba0g!Wy@gWkL>%@ghmJgH=I3c^vTC&=GPrVsR{ATm z>4kgP@#{0O(b$$X37z2X*Mr#mbqX*t#g|D;pM(bw)KHvl0ex`Y$2&x9#Ca)uQS*tw zMcbsw0wX#pUNZ`1Z+cS6*rB*6dlUx#+An@N>lFF?erx}-rk&h>4-!qfs*C@wIl{6( zdr@uzPo1BCQM1W3ZlbX&f<kj;-~3!hQ&m%@`D+zcdB)LnNP?+H&oG(vUvOM@SXE-v zaWY&d4R^*%GBZU9w#6}tr8>WZxNUPWY)c9lExidzYs6gg`Akq~D<iE*?N}HZMnCuE z^PB%9;U&A%pd4gGJ;}xt^DvNUm*}&MCHnN!$Bq6o%HhKc$FkmEHk|kBP1G~8oOVAQ z$#!-fW(mfT;&a@5-rp+%kIb5j9ieWJAu|e+B#)uw6InLnPa&mwn_}{YESRr6md*_d zq8>XPdXnV{4HC04w@!i?yv?HTpEu*r71_+ZD4FJs3d8!jCo%FyAj@!*#cNwP;puL5 z9DTc#Db*jL85^3p-e6xUI4}zbu04p^19XVl<-^QF{@A)>A?M<j!+h4w!Ffuim{O8M zRZSwAWM+o`vj?J2cn}_5qsFGLlN8*9i@A&TYHYyh95T5Y3_tu5D9rvp%AUMLyms6t zh!k-0n*}#o!sFE>9Yt*P<2Y{Nt$*B(8x!%6SvNDhbPzO3h4<-?+R8xX`>@M#Jcx6n zvHph@CvsbhxuxR;Cz=x5Av2Qs?H967g$LNx>(S8YC`mrsU(;ICsVEoyuTs6|5MI4z zOS=O<P=TvA`!TZzE))UlT_ukNgJ)s4u%nsQUC7maE+Q9!-;t~I4?3KD`KMcBamLOx z+VWY4*7j+@_~4;zaqR(^bi<BrzZ{OY*Q{dVv|RpU^Ba2pxdt=~kHNwZmaI<t9>nW^ zf$W0GEK2zhI-L7WsWAtrdP5>Js1)vTOVa7oAAPJiG6%a%mvX;%{(^$fCt#MXp(y3$ zV)TA}mQqihhJ=Ybaf<48!Oz1)IVT;dd5*wdjta$z?x|?mWq?wC0_U}zhqWQu_(92w zHAXxHe;OuEUJ{0{*SVnY@rC%qVJ@gy^zbET1K{wRMAB?Tbm&%`Qs6fgey=nYIz!1A zIDa4Pu#D!!r?*%6EL_dhxR3O5oDF$xR>w^!&ju=M;`)evocle2Q9sa?3<YrR;-f!F zIlhuEKEFkSgAJH=f;}$Ts=_u^-=#)_laz6yk#jL}<7=FGcIdB&rB+R5im^|~Y4SNP zr!GM>%;gT;d()4*HmI><2d4;K+A3JQO^!WpvBcbyHKcTJ2aC<y!hY>@WjcuteEiFC zY+Gs}KHayOA6;{Ye*Q5g<%i>NW3M(`ndglXBX!ul#I@|XzyN6SO@}$!gUNV`6wAE% zoa#$AV84bhwf)=4%!6YgD@Di$`wkYrJok&tgNI^vgA-P+Il-Ej&SBbnHo#b01$IE@ zAk;sdi48mc@Z%iTqEo9s>{!2qdgR9OR<$DB6cWxv&(olU-GW7z|H75{r%<rTkLC#e z@bsn{i1~1d)P4;@DP?mgchzQ!o0Tzc!T`4Ru^ziteE}v~Br_S=i8yV~ZMLD<8D1C0 z!0>&kq&RjNJ}}PX1G>XmcE}m-n&xaaL~|<S7WpyJ=TdNXJqq=C5?J*{l8s8R;LeZK zVw(;g6I~km1thJC;V<sT1&wDg=sy#tC_Nb^63ba*oC~dAv|rc_n2|@sN2>2T0%r9K zF?{nWy0|Qc6Yq6r3lxml!Ryj2?2|11sLTeB35U4t-J6*9-0>u5GZ^Q`ICHJ(D|nH_ zDSB4?hMIpSlCPBpn}1$|ZJh9pQ<V^MgF5>$VdE`2+GB=~_8-R(Qv`0WCi71h^Krko z<NTWAG-loq;oSd{8>V8!H|)2-+O1wRtmGwgo^C@iVg2ycxe1)c>T@1KKGj_2HzoYB zMIR}lds_Gze~T~ii<_fRUG5OG`FajF4Q+=Np_c43oFI1O25SiFpck7if=<qPe$KQi zOnBQb_PR8P<t=i;Z3$axQ;r_f5;}e6d3NX?JQ{W0=U_s>QE}7rQVO5bMs<HG>9_4Z z<}0^PeCPKq`j!5P0?r&`O(m*a)8!00?{CDcqLszNQolffz$Cb^M43HXHU!)cYNKS^ z5vY2rj2Gg~u-{@Ku9x$}rUhb=!SH<`v2sJDUh{NzLuoGVG*Y6mgMZO3{uE4g>LhXE zI=odO+%KQ-%%#{CPgIS>d*fcB#LB8`O~z*I%Gg!RUqN8+%hhul)5ep@vt+80Sc_L8 zzvEh%j(ful@Tr3azRxY^Xx<SKOlx=eXmgO~7|+Y!Z>J2~L2O<82fAV94pG+QA#iOk zTmR<>)YT7U?)CXR<`^^WtSBz^u?x&OJBsC5r?NG^tMJNCY0!Ue0<J3)@YIAMtS+F3 ztKVqGjabDqov0LCePR%cSuzx@o=JmVffkOMW&)9;OqkQrQ@r}SWz-s$i&p(-!ScBw zXZQO9?Xc1#(V_s<K3d3s5X(8fTe($umQ}Gb=o@&>w_zV-tyoF*UA}s$4K@Tf!hH4l zr23|XX+A#6|5j?Fc58uOSN#PX!i2n%LX^P3^I)rWWJ$-+96N&ZS@(W<TtnA6lZ-3~ zdo_WRHlHN;S&mUYRKo{3cT`jh<OE6yEj<00kJRvjj#E+m3@qS_?mmQXM#@+b*~>RP zIt1SG!<e?=5h~d7fSWq~0ZiRwic*i>Ls6Tj_}l!OY?vp9?<3r>r<lXC`ZieTG?jIP z=fMhp2duqXL!qHERdOya6t$?C+%huYtdcM@Rj}cfY_BBi=me4*dXwTe+p{qq-}y<w zE&So-fL}JB<Ltk0<u|n_ioTp#%FWo)EbP{fFinpISRwef{3BfHi}gS%{oT#KKAg(= z>`}tO&C2Y?)jRB-Sm*}$d4qYf6*k_s$FkRp8EGvSby;YV>q!%uD$MsYq@-AZ^gOzE zEEHWwacHKHg1$BPLDB3mAAT&CGD8-?`W?UN_6}K;X))$1+OwdgHb=PJ-yn~`@f1*z zg;6G#z|uqw-Q8;`WKIkpIAu4>%{s#Qb|1(6PUpzmNX%6)uf+QbmUw8W7GqW0V0ceI z4YHPHCwB_J$N61+`7}KizWA(2Vbp1=8W})|X%Db`%PpGZewQZIUZsf7M<~KDojVuP z2+re<GoAW_{N2?N*p#WtrK~<oWyLqiBcv4H+VoSrf-ddn$Fsz6cUWt9nw|}*#;)y( z&^JyMw;z8@&+mlct@QQ(_lAi1Lw=y5^^LadDd4B|jX|%DO3o@HgnPR6KisqJ8J=A; z8R=Ix)bt4ak*sRwZ~C5e{;G-YIyumk-doJ-rG0gWe+IwKDv6n>J>f5Dgs|1`AJMGz z#SnBdl7<)LQjF*(sm33s{G-)W^2Z$uZvd-Em`vAR9%P390$GaRLY6d{=&)X@z}H$2 zFY3hfHt`AFdoYKE{ZvAaq!oDObfkFVthZdrqBkTna|<oBSV|_b8W3_`j(^efi%O;$ zz`6KNS{Kw#s}x$XYFIP)%a~!!JY8nJZ8S4WuNL{VWQcdnpMhg;+F+(^7WCc=XFK$A z`K!A}p!d%{_!61K3Ko3j6b_xDoVyZivz8|Q>e&UiFS=7s`3XupI+{CRcN_Fm^ze-0 zZa8PT2r8#O1L=;V>}7u!ovi!Cbbl_#&`+P?sCP9424z#H<^%8!uBQFF4|8%FYfxA3 zF~2S538#_=Ao4XpzWO9i{j9_C{o_$WLy`{(Jc?moMuA=8Mf5aOWiKxG!LBFc`T5VT zz@JJftm3|cxqAh>KIQ;MDZb*=ZL9f_ts}v3dpPL}-HtD-FO$chX!ug^ftpL=SXSy} zHZ853y+1AkLK#tHe`q;mE-9l2_veGsr!(Ll^pW1T{l|MQd&94p{GIl0O`*iF!7S}b zws_iWWD&kQ@v)K*XCnAO-snx??hJ8b*G_7JyY?`uxV?aXx7v~I|0vu?zyE>zD_Us5 zvLmRn=8`x}DxN7T9H!_87wN#9c5d*S!8o-jiQ9JN5byuy0x0kC#}Lsw(Z&OHeB$V1 z6q&Q0O+P*q-|q^-%X`LS|Al-wlePf@eP)sBry4kDa}^KYio*5vX7G1F9Nx-QWj~(i zlb5O|w2Exm(-+~SI>!a4&fCQ5GXFs5y$1N(F2m}ggnL=Q1@11~flnvPaD($o3W*DX zn)xfxYe+gTr}d9({L%{itYla#^d~;9cVzEvE{cXVSwn063Cw-!Cd{Ml@Y&KGP$HcH zPmUd+qKDQj`IjVonEaS6o-TAK))jMChI1@rV7=(wmBVm(i59NC;ETg&?gx+aKjEEA z6R2#h5F1!Uk#<)G>~cOq&8uFZjoxkkW~&Q)-%IdET9eQFu@yGH$f7%=cTvr&I2vI& z9F@cOK#totHYQX9l)ei+=OYhMWB+D>`=$?Rf8x2owmRyvJIjy1AWPdGsXLDCoQA#O znjqR&#^M*>MBQY4(7huKk_~U@O8*0Knc$QBWxb7lcFkkuDI4*d)ob2OUeVFdCLR)J zZXyl&5O|usi#FwdCAs=x)cj*01`fZ=W&2p-I5{<nDo&!GTci1k=P3{;t%a_V3cPiT z4)@DyG?o`}Ozv0%Jc{B;YJw$5%g!V9H6D27<yL;s$MJYLC7OmSwDVsw>cDMy5~**A zz*OC3m}hH)*EfuJbkF)l#zNlyQ+yv72b8govm&v7XgXX1S$sd=n=f5w=Xi1K5ANR@ z3tV+h@Go|4=fWmMP|vVV*sI>ca^J>7*2@Ui8aoSupGcF(?l%<s*nn+($!O5f4zAhn z9v;&6W_!H<^8GENV5DUN*Stv?O<aSR)>vTi|8E^ccawaOHJ(U4fp2vN<0c^|uv%&$ zD*w8HE-%+%<GNAc^Sqx6b<}}9H|Jr^?+yI<uA{KFstHo7rI?0f4$P>z1~(E6;pVeK zW)`#o9nWw=_k0b_9le&u{rF8qM@j_7oF6+QFf%vJRUkKeZ**wuBb|~aIvTCU7O%NR zJI8g<#GF~|@&3Im*;y4%O4;*ab4*~(hr8Ua&;GP}NiDA`t&QJ9yU0hWPh|C6u2Lm) zw`k7AX7~}9iIENw{M-de5G*^C4U&ILscQz|VY~+y6`sTNx>%+u6AW}+Pn5b~7Q~ol zqD;OETQBUsT}~S@uW76KqIxGBqA>_2oA2RwEtuwLT(y~nY?%mQBP=SrhFuXqF34mu zDs^xr`2ssv=1&ogBam)&iYqp~p+!;QEdSd-7<od-PHwLTDf4u6o4AF-&R&7<1Ju~l z?sRlN^^$h{4FFBMA-Foifo3Q=;kxVku+n-4>$3QdY2E)Js?QtF4sEWY#~+T7x@Z{W zUb;@TXSc8rd%=}>Wh{Gl`Vfe^PDAEY4ODTw4!yS@z-enkh<_-sQYD0(z?OHkaz!)r z&B`F^iU0|Tn5*`cU+AE&z<KvB2Jz(^^r;|*v`z`k%qQW3>(P&YF=#rfnQTBd`7nDn zr-k+(_C>i5Q8e+wC1&er0e`E@`1Ma;ah5}N!oTL>0xNDjtiQ2{dsFR$-_G6RmYykR zPHn|-RiyxW+8x=IQMr`6+Zay|+kzv%jmFd~a%|h5d|Fd5hD>rsvg=ZpX~J6t@cb3X zkA0^>J5E*7Lbo{ZmE6g>&x^npj|c*<i<!2UJ>=+`;+j4q<f;o<#;qApJ~I)l=Q==1 z)MTtO8o;ca?nCM{BXTOT!4rWk)Vh5M^Xn`oYvIhY=+8=K`62)$qLdxdcbD<uBQiir zxfXJ{<2Wa4D;U2PyfP}rEHG#YzOemPdH8%U*v%DTSWy<ywDpxvQLE{l*C2#5ja(n@ zCuu`{9QogED6$#O@Fc>ngz;RJu`*f;x$O^c=Af?5G4^fpLt0q1hgD4;g$11jkn1bW z?zRCge{F*%YR%%L4<WeG$%vhn2#3o9tl4?t{<L|44P22wjC(E|fV!gJWOU3Bi*1f^ zL;6-y#cK@|-Kn6S7!}d(_-Nex><GPgUqGvV4`<$<GAQ>b89Tp3;J4H{c#-8Z@xI4m zKj*7h)?Gy=|J-?>ds3CYemk(=QyI@r&_=7<4Ek4xQkcyiam_g=CdxPtwc~mmSI6Gv zJaR(er)>hR-_Q%XC(O9wT`Q`-vWcwe^mNv{YcF|*eHFQ$e<98<9nEg3)xf<Y6PZ=) zO*(F5#h`H@``P6sHt+Z-+H@wFiQJQMZrcPl|Ia-N&u}6y*{xh!%p{VnPh!_X9@2#Y zp0HRqMJygO90uK*&GiWGtg{araFA&h4e%d?9nme2mpF;cZ7X5eC~LN};so<wX-|7s zTC?NU$rS$Z5j_i&LyMvTls9D`MD^YfFH6~h3dap;MzjGQ{*%iU?h<y^%H7miJP4k) zNWgzdKWJHSJtrHig=Vw2)7z!W?BzcjSmdb0xX?kUmQY5%?O(to#tIjBJYto@9GT}L zW2`rFq{ZH$H0*{Ms)(8?=ctg?KGDW!$KB%ASdAdN+CMPbJdUvghSVxO8*k}$!e)mr za51I|Dm>p)Zs>FjE6Agf!Wk(xDwex=Vhw$0sDde~u1rc&j#a%G$BSet$m?Gd4DGF9 zsoPJ0PWo3)K3g7qx&%(0kn7VtUCIWYJ<YY<Y~eZ{41p<COWEh?lBg~59o94z!4Ah@ zeuu!h`_{FKPd|5r)S?}EWp*D17VX1He=G6J@g(u}Lp1>UquHh2l^}a09i115AXdb2 z@3sni%dQnzaWtNyX2giPjHWa7^@cF)PBQ;mILj@+5eg0O;wj}^Ciz?q6AiE233c05 zq0)09se9%^_HGyQ()~pr!Iz!5l*HCFMN{`65q>LPf>O_?;jZ&p;P%Q4FX#)q%u5X- z>n(Sv=yWcGz3~Ch<uUYfK{3B&XD)x%DhM=}j)M+ij@5x;Fqxu^mrXCgp8YpP1GcDP zrEx7;_;vHWjjeo)RRccTd5=!HIpE<-X>3xv3|`E&5%!n;^iXReZI8Unu3pQh*j2qy z7-)!2hCBxRw-N0|>}4&PI$(8e7VWIwM=Q3eqW_+!&~*M6$aJKlNq(qkLctxbN%00< zpP@&;cb{d`Qs$81g88shvX82q3Yfj(0a*PooxFD2v9Z%*xC<t}v~J>T+MaQe)SPm_ zDO%7Cjk*Z^ca-qC$ttv8xE=FD)p4f!JAU9{8_sFzLTGjx%PdV(a86ki1-IWOmkPm| zH&}|LY5s<C{}Fg+#|)O1+63F?E<xdBhEBR$$hJv|NtWKFsfWAxuTSJy%vb{`^85>d zI2Yd@X~T%(UI=}h1LB(i%M*qQUcy*fSvm<i-Aut!Xm79i-b>H-EMQVft(2tmL=;;o z0a4}JRd3a-p%djv!sMo1_PvGdxVAm04NVrMY7vc&a%0tZ#|ioRWGb(^#?{L{gD>N& zNaD7@hr4(H^hQRo+T{vpa?+HwO>{x;#6aGq<sw+S>2gU{Q&^CMI!${aoX6)5!1qy# z=&G!M3Kl)&<=P}(`ez}YnmLKTeMibs&BFqh4le_R!584&iYZJgW&^8LIRyR#QsMG^ zIn0q<PZz%(V{67V(bJzdX{IpcNq^D|7Rwaio2fJYYMRTM(q{|K1662x<;?1u-^1U- z%lK)V7g1U7bj%Z6<jR`=__Co2c;{~bdanKsdPa}PSVEXJp8iI&j=kh#<!{k{><o;J z^8@v(on+<t0H$Y%`5Qkj(xzNpW*6KF333x~sn=jETPLCed%rVjft9y-l{79)7=&Yf z3hpUsW0p8MAKt$T!o}?ZcTDh+>D>Fm=Y6jrlQmztf7xp6tkZ3{^WS2jMKg}6?nAb! z;W^d(zD96hHYF>VqvOxhl=t>3Kj-orsu(H5FUV0s`N6Nq&^`_a+1-Wv#hLU@)C_9V zKRYCR_U89Je+*|L`$%eA23sJ*fzAFN2+14>3$M0--oG|l=XV)umLKD`OwFQk)lRtB z$AmJhw{hlv40g2{3jMJe!hK8;qq>&Dd40iezeA7oX@+pd$$>Mo2h%q>V;m9HO_PLY zJ>>TsS~Tn$^nRX>_)G;2Rb0v7Z7?S%+~wbNyJ6SX|G-P*AZZQQ2mQ-7<AWyxmru){ zNz{cy*4rO6jZJ1tYz#rIa2P)=aTU|~ZcL7|SF%v{AA6ruglacGaBI)`@o}PE^y#QB z1s{pvw5<TYj>}+XCEYN0)Fy1l|0u@1;eQmJ`9n=#7l)Hnk|Z=wnx#_4r0!WOR6-Ie zNkXQOka;SSM1xd9DTz{4=o?M<tlcCEA<3MCBuS`*yyyJ`?hoDW+54>F^E|Y>nWru1 zi-pg4k$*!vD2@0CMV93dlpVvpJQ|DcH<iJ3hXQ^sx<?O2tKu?8Eq2#q5G(5bz|Y8v zqV!V_XyqnnEYCbZde+N0nbQ(@!XX7KJ)$5W?JoD?$7%Lv>lJokLkiXJ63&;qtN5bm zSIl7sSKigThjQc(vro$}Lt{o5`>ZX&{xm3qna2d0zuuK1gt?A&pad&O*5jrBTZCV` z=CBiMN20`zn{>RfkuD1k`qsvDx+R>USvxwxpx%Kim3_v0uL-7{l$9XcJQME@7JApM zC%`#dhHTe`Q24xu)O^zi`(;H4y;98Aw43Cve4@C4{j~eWdbIe8Fzd2DUY-7!Qj!<2 z{b{$wQemh0wD+>OY0dzQ)$8DPjW4B-FNQFSTpbLn%7)s=zqEQoG~f2HSM+@IOPbD( zLd4ERFqDm;kwyb4A%8ApZQ0L#omB}}6mCIa>R0jUv-e=_qs`2F<t-AAPiK)s^f1x) zys&@w9&T60bBE{kfJ<2v6@}int8W~R3mZ~6k=|K;|AuNfbm@{X`#yv=TQ;)2&s4DF zuql^S<%~nO>Coa+swnkw8QV8Phqi=e)0#*_43W{nl8JYrZ|Y_C)L9$d)B8x={|z#q z|Ar5XiR^}(v9dH_N2IC(ULQ)p;SYV-R-L14@{{9io?<chUP&+Qxbp#KZG6L9kFpch zCNoHXHi@OB1anTpcWT#{20dYk{1x48v~Yh2b>$b+r-J#oy-=8UE02Zf2kFp$Er1<M zQ$WSZg4c6T7d6_KQkwrwND_929zH;3EqJ5%dKq%=H;1q}K_@6_i6rd2t;RkGmSAtA z`OqBQ3_*V8A~fB?WzIPW^OyahYiB*cCPRY7bZ!uPdU~OJ@ltx;6#;8wzwuYWjtzAw zpq0h?xIIenQ`9Duw79sSTa@4yI5SDeP3Z8w`xxmadXt;<HMsvOie{t0%n7>A-L3B; zIr*o2bih7HePtvLE4zVKn>)zs!Ffn}BZKwTXGOhx3&mG9>!3&{8h%|KK~=&WKW?Z8 zQC}7eDfU7I*IV%Dhy^McXu;9EERa)pN;{q!v&3tUMJ-+**{2#UW-`=GoD@HjoaS8= zoW6Itf^pWE_Gmfw)b{}O>2tOxB0#>?l-`fHMJ2nOFl=8DZTCNinm#(5^_#K6^C(AI zlLtYqFk4G^9Lm<Y3mmaMKlqo=C24g10tkz}!0z;200-S-2=97|CISMn*?2Pi@HFJE z-#kR-r<}=jr=pN6oNB-8*jB{1qwuthD+``;6N`T9L!*+gk0YHxaYv@Y`Z!DMHSniv zN*?4Ny#aEQ?~=&lHM%(m(AU%p-1ebS#LN|0?uSvV<JWV}=HLr(>C}V?F*l*^r!|;q zd2w)QE1eSjrPk9VG06`2`ig#T|0;Qe;{sEB!56MDYc53TjzD2l!7R1jfUBG_Rh>}9 zS`Q_R<HA6);v#455GmGtat@wER&v?Ge&m@|eOPzFNGvJ5KTS*#OgN#8Eti^#t3K!P zZ3Y?OvfUkCXim02)^Hn4eQeNUv>N`pQb^hBrocIyP4HPop-drQK1)*Sp|VCpCi{-( z_DXxO+rk_sa*!!sE^{BYJdwnQVH4P7V;6GRERUPQ$Kims;b?DGC_JMbq^0^qU@;{! zZ|a5tdmAzT!fW`NeU4r6Sb|$M4q@24t%4);G^hJ>9B1aR3l<9gGpWK0T!Tw2H+^Xh zl+-^HTu>$4jEdh}-&r+!InSEyI5h)n&RU?8uc^R4DB)vlGAZg>I;5;N1eIHtp>Jh7 zS*;Dh&Ff`Y=G7tW`4?4|sdS88nd>5OJMYl8+m39&)=Y3+XC}J$Z5sVrVMvRYMUr*l ze<U%SL0*OtbNX;z<eRidtUC^A{sVU?zhQ%UZ)fopTLP(iLo6u{RHo3P6VMvsf>sT( z=zDA?Gbnxp4eS<NTKyV21g3n@^Wmguu7{&moa3X}VhBjgfv7EI5Hudpt9`M3?d?!1 zy7pHjJM1tQ8g+oy_nc*E&yPS?VIs>JozJm(D=}v8Vo_A41xwo)$vQsWg4QZItR5-C zv+fu0PxxBCrr|p*%)Q8-EI*04yB4yjF@gi|`fThx^N4Q@s>F#^dtr9=OtzTKWo8GC z!wUbG(6Q(#sq4MuFWG(vtxp%&_yeXCraXxL9$L=tPMgbH`sZ+IA%>9Zoh357GaXG^ zHOWpwggsM}1y{x(7UnPjJ%%l3VGTy0_v1NKwLRuT{^n7rg9?eCs&biv$7_bo39JeC zVRGgJ(5){SoY-Ofc<Tf+ayDd5b0?za?KQmnlv4I3b}W3k*THFarGo3nUc2SHME2#E z#$%aT2D!Y@!R|UeQg!FqikhP^>YX1nnbec`n*!?(S&LDt$Drv<OPn!oB2(Wc$s`7x z<lWYtB~>RgraCPdjQL?8V^u>==TGvI2S0PG^THVC9*f;x=ehMWs@SwCDtK;pIF@WM z!&Zj{Y`}sBur!esUAuT%$g4GRGfS+Q{PT<8KcN9`zO=+GYcEsPn7!;|=U*zkr%81a z#<Jj1pNgN1ErMzJUxahx5d_I73GbYFctAQ2=Kj7wLxb~K_9b21CgTk=>lt70<O4kV zSV6=6FHz#GR9at{1TKRmsHHW8))<XMm4jgvQK`q8B;xIC{_f<Yj-P=)7N=q1{YhB# zsgglpnRvQoI-5Ey4XU0^f)j;FbaJn7FFuvTh4*H_xy9j-a=VZ&x1ZnwkE@Y>_D4wF zAR};Dgm>88>h!^M9R2rsC5pzkQKH0i-r$=BT$K~@kwX4D|6&P7J&y+g@<4uHHqegv z`8dbh3XOsnp|SfLIGh;7yz|G?wcu=Ay33NvclgnlQa!r+n84gk@b$bm#Ixp;aqpoN z>Tz;oGSZ=}S!96u_x{-bsBMMF<jGhk`4}2@4ukzyuFxfmfHI{uee`v(3Ok$OCpd!@ z?P%#-@vR3ZXja?=*t9~Mt$meBol{nWx6D&|IoFZfF@6x6CK1ibUIn4-M=#M?$tN^E z2U*+CL~i9BDVmqDi>Y7HV?X6A@ZI<*=y=-7_1Wt4cOD8oZ_{-cVEUYl%8y{_e+>|4 z>dgDvelB&cy~YalT$yimF5h;pmAD}sJ<&YRYTq8E%h@MEOVtZiC56e}Hfd~5@DY6P z<I&-E4ZQu}NHd<l<qPy|$+j?$9tMvFgL#GGKD!KFHu)DN#RQXr$x!lCxl1uw8?aOV zmuP;~d=xD;$Fe(@nDeeMiaK^0edA`r?v1g$+h21GdHjvO?{Njg=wOKG`c8L)N6@pK zIk0kc1T&G5W(rfz;n+k6aIQQLl>Z!BFAZd7FXv<GmM(F>^$7|qI7h*MQ$g|1T22V5 zu&Xz|2##!CJUM6y=|1bV6MwB`O;?7B)MXxUf70_rgNKA+>9aYkQ7fLEd6-5kLX?=| zgO8y1w4IOtC9pB~+VS?4U%BDaFHwR2J&?Vy8g?%f>J>#F(dEEUEcFe*q#t>>j=#bG zTepC_KHZWw4!r~t6{~QA_k9RY%YixdgTdfo9K;-Z%F$+j(a1$I?B$G$AfMn1^PF~I z!_-M=>laFm3IXK1W*Qw!{Ra;-VxY5V9G+8t2AM8)e6PAY8#{C#tM9u@7o{}VBTp-A z=tze<Es<E_|ByzmcEP<X;~_m{E=s#EWh2HN2Tf^tp)S79&()G4KmFTW<2Vyo#S|d6 zxrqLq(-!t_^l4#c4E!D=FbQg&f#JO{dT?Pf840=5<!=kH{`3XTQ2qg2OZH()9rnUR z6M-eK8_J4aETPPpj}+v0U3C54OyaEb@y(nQc+>X==IgF!O7_ig=%)%iHwg#&QEI0V zn#0vwEW^8Pt6}O*P3jxAl?+tB@sr=45qZt9V?{!L(mLi5r?<m_N$fWw-R>2jkfFnF zUlkY*qy6c<u{2#@zZ((;o~2Qv)u3rcE*!c&2J}`7XX1hg7+07EPqVgwUgZf;p`~!Z zp_iX`j!}e5GG1CEIC_(3GW`QuSakd;S(skM6D~{eSa%<Lmo^3Kl@Fu#g~K4sg2nc| zcX+8M#a#Z_beeHPim9Fs7v7yDuy<nu%9ZgLWmQNzZ-tzNVg`3*V~4P#mroHIWqjJ( zi|`><nGL=Emclkv(em$J%>A-4yc}^9PEO&<q+GhefBJV$TImuu<E95YlX4E`+LpsH z;~biJ_ZqdDt$|JBC$Rgk;z{|72Hu#J57osL+|K4jqPU;y1h&lqyt7~E`<fbH!>*-Z z(0pB(^G#w3IU3~juZ_AwLs*ujCPuW+#`cj>`1po4TmQ}-O0BX5CiWsG5!HxAj)pMy zzs=y=ectZ-k@-ySm;-z0AiO)tRS31*aa3v3rM3`Tmif?;S2LRl|9yW2YxiE}etgV= zolA#7T!1;dzV|cb9g3tW`#ssM1@0($Z6is%y+H$G-SC`xI!^rH#^3yT8$9aI<5Gd~ z@3(ugz};90jpLDRt5`%&+J>{&Z^T^3_22w$y~`ARHyO(PPf}Xq8L~f>#YWcMq@B|T zin7~<dS~lX&TwNnOaIado5k~Sw9zt3?_YtAhpd^epC;JOS%hw5OUUtII{Jt&fr(^F z>B+5PuA=7)C5<uS*OzF*v;$h~``BU3Jmd~^&yZwOhRKrK_%EEXuRL?oHs!MG3i<mJ z;$T)3hkG1z0H1Y0R7yHk)DC2>;X}o>JIlq1<>Q%MSTK4IwgKxULRMwVcepvR9+LY$ z(O;c0sA~C(emIsxOVl{Zss6?-laa&zOCem$9%s1k-NLEJTH*EKqcQvMKaic60t+o= zSd{EQuK2-Wdbpq%cK9d5qsw6!x>|=>gl0g(pIpAjG=m=gJ%Y{WDxq{mC7g~_#Os~A zsCZ*4ruH2Z*MI8g<;N?c$A~#t7aPv$X8hrO)aRo3M<y+MH<#(zX;Di3R_<r)RkpJ6 zF6hn)WqUB5J@E2Er<cueeZ>`8Wi*ndCR@P!Mgws7c?~T|w(QkE7u<Ph3u^YhB7+He zLJxBXHQo~T4L-EN)Fyoh+~|a9A**PU=`rXr@x`ieD>_`GgaM}qF-7lr{Ok<_ndiJr z+9b>>ynbA#!MUnzfbKc0bTWf{cMaxVE-1-$W}_^#<Ru>`!<453*~QK)>{87wiu_Y6 zI6F-Fs=Xy_;VJ)eZ)tZr;^WDr-X_8EKML%;b_S*U&gFlo=`$nsi?Hm`P53Zd*hMp5 z%QXdTK=~&J+2~+5^t(G+_<zo(UPlMm@Od16fAL!wZ>|lazfNE=Lq9=9-U&Yc^KyLl z<rBP)H)2D6DDflR0{C#97k2KOITl(o86~Ao;#&D~NS``^h2cr^FIN)wQ^%tHcM1GZ z9fdJrt(?5V391+PZSwP)X?D;yP*|dbWi^-JagN}iyZw-ir>db(ixVp5XwioFWYCZr zj7qacGb`U*?#ZDUv^Q6qzI2SirU$m%@yk5Cd|4)ze_x7@r{ej?d3rdmaU%;oe30&1 z<g+{9%u#*S6);-W$=}cbIHfWK)XHVpcGZ($qc{|Uq7&g;ttmF~VFJ_58aLb%_#h+H z*oIy+7}acqyQeB(ebH(bbgzg@S@4e@H;?7bwtgX{e^J;vTOHLC7K7rZ%}laN7n>%W zWd7gpi+djhVteLsFg~)3-Rn5Qi96z`?c+iGt5rc;Ot&)0F)g${UU1(QpXW?PrnLW{ zgurs^7A5}O2X>d{Gg-caS}nedD&oJvn^sA|%RY;@zTVD7mmQ+ViXAZfofIAJ{>14n z_d%xy4Jyo@1Wv14D1Yc0UP5>Cv;@&<u0>#<8)j@{E}120v}Tjwqnbi$KOa-@hE=8R z(@(H`ZGQ|dIu8<IYj9<o4f!u$%;3LGqLz<VeBEnnOr<V9A;%TkeDzUe>LGYptuT1R zFmagdBvz|*k3aQxK4{zvK+~5ez%8U2TD6{V`^L!Ax<AqMI<SKNPFhbl6vwl%4x{k> z2*I5-XfvFYtR`org9LT<c8OEY(#(+(_G8`{u&-^|Q2%cY_1|#ilq<Ht-ehgKQew(a zd*eoT|C!O1OZRz+=ba$+z!+oi48;$Vci{Swk6^`Wf$>whh+Z#DWWx*A(boU6Sn=!G ztm@-iSUJIqYDR0ZV8_QW%#Vj1$;#NIb^@$dEao~xGdPJ>J+4Y!Of{x<sBLqTg4CSQ zr>KheJ+xQ+dWJ0fa;KO|xBG&@kiDeq_DOvA@HF-y)1OQYjzU>%8P#j~LaW7LTpZ|) zeaelX?79hBYqGc#YF;#+KSx?KTOjuQ6#FFO9GEFL3OAgnCn#Kti{9k$S(EdqS!EAM z-O}TVZb;&=1twI2Y5dV*p>~)(*sf)Z9Ok9UP<_Ex&gZ8bEp(c|CcbPU)yrk#*CpF1 zXV_GPf9AMDrJ9P)AE#PAgOVa1P>uUd&}qtmB;|Kp(OU+i%<ZYsLXN%6DF9cKU~Iqs zo4RG=Ihz>=LFTI_?hL$&a$k+`RY5EN*i_h|Z;{0Gzv-Z;n1BV_mF)XlGf4fi474;| z6wMSeggF_{LHa`w`OQV#n;cC~Z58Y-?>vIOc5mW0XTqtXDQu2f2Aq3-ik~#Gkp;RP zV+$IyDXD!63-lgCt&==irKu~MzR8*P4p;(^Qf(&{Z6W3jLny0y1xW6c#q^qk&^rhC z$1g0{$B(u|T{dMov<p{w16pf(aeFmuSl0DrxNO}hG?NhKjY{K4YOpI-R!3mn;Yh3# z_8OON)rQpRyC9}qmg=<sa^VWE;79jHex*tltBM#2UBWXxewW~(bZVtPN`L9b*L+g% zlRzKGxqxeb)66R}sAF!$BGx6dbJrx;jiXuY+MPW5cyB2c2uSGivmMZUT@DrVG~t1S z0UO(8#iXxBP|K`gByVfWdYT6^iLb@npsWa(9w3i-AKH2K4Uc)*k6j|!xHa6P%VQx^ zX&mo9ZxwF8X9Lxn3Td0}S7@_k&}{+OzEBZsr`m{$w#Z{av<j%3X)wv&gPhxQBV6Pz zkAcQV?f0$WNpq4pQ+o4-y5gKDO1P^vKSfhqD`Rip?}7u#p4b_+00wq!q4i0h$h9K@ z;xAM|-W6xmuP?>M(R$3;;U74-&twfb<<L|aDBfwM4W3R%Mbc{N+%VZJ1iQ<kvlssp zT5oaWWHAn}b!GF9MJK4cC6YcXuELX!foy3;B6*Dor##gnKCoE0Pc<s}Il+hEq@jRg zve=5b@v+p0Q}FJb4*J|W7!G_Hh5O3F*s9}Mw9GLAe4MPAr&KQAZ|u%$PpRRpKq)T6 zY7<V&O`_aE2DrfX6!^SO!?dQgO!3$%_Wq_3Y7`dI?|%vG$E^2oOUUbn4Jv@J*7a;_ zs+@i8V{e>?BZa-wFEF}2fqu#7vhK5+$dzBhb@wi3z9plXrTJKVsWJ?s1ZLld^Z7Jx z@)O>m)12K(j-qotv)K8y{b1lN$GMB=^NoAs;EZdc=(<NIRsOgG-ipKU=_$!Fd-EWu z_&p4Z{Yt@qo+U~RYl1gpu5!k6rh`Il7{S*#rkp8o+Xh@01x&C8_y7OipO%sB^kRNl ze3ZDp`77x!e$A~{Fheg-KmN?~Iw%+|g^Dp+sMw?fEisR&N0{@9(hA}9zpq?pQNNv& zwK~^ue<n*9HWpm9-ivOzgz*u=dDOJcj@!6u5?E|K3j<U9nd9McxZC_b<h*<j7n;U^ ze#Zc;>d9bf6$&IVv6mg+rG{Y_MnPTtHc|7f9@xHd9G*!z!ATe<L7`L!xku09O^&VM zS|((1KbsLgxGcgg@|ysknBW0{*XB^Nj6Oe`$+!1@<;{c{j(>wb+jcn<Ep5ucL+I@X zH!kDdc2-09*b}hzhcnLJ=nuPOBU$jHa;mr(i#J0?LfjDpzH^-p^LbVbOJZKbusAhb zxZet^$DO1h8())|?`#(Rz7Z<ngMI4sG%zdE#*d%AL7k6>7*5sj@j9E!9Clc;1<r?= z(r_(yYn;G(beMo%1DCNyMJa--=PK1bokshFKK|XxV3Pj)h5L4@4l1*+vD%TAIA>)6 z*LC_GHJ!aEPMKQ6H4Ym|A>~3BA$0|xUu=(g{hLem|FwYp$5HH_Rg92{n1p&uPV&l& zJ&-qF$FKeTn_ey)!LpQ(u>|Wrq2F|zE^p}Px1=LW`WD7WYZlkO+#0KwnuGqz9@sYd z8CP-Dnzg@JjU|G&dhh)RZba*2`lT=2jcp^?oOuOwz+{S0pOo@XL)2)&F9m2W?x9al z{uBBc!RR8@z@;Z0LVw30*mG<FJG`u%q$>|$x7sMIs~g4oUN6Vho<Hen&1J~uM?=H_ zCFblhkN#vIMu!@G_OsNU#m3x){Q1-Q0D~W3)xI7tZH;4IA^R{$$U1<KyPzR;H0I%9 zJTtw6Zuyz9*J6P!zG|8{cuSJVS86_Ol&@j4OrMg;nF{W#_<-QT499sc>TIb0W;Q%= z51o5ZM3;}Jk^GhxUiHQz@un-+#n)!lz`bw!%>PI(<orDjH*9U#EsH5^*^3aA=#)dt zK{<Ht64JJ%+i`M&9eG$N(VmudD6XG@&mPUj_sMbG=j3|Wxqkwz+Z+$0<}G8sGUwsZ zlQ*CwBae@A4#LR5ncVT_J}yhm7H)o#!S5|YVX}G%RpdFKnk5hWFTJ5Z&sEr-HEyJm z>cal*io}g&pJ7<b1kBghX4CG!fq=XJphF@VS68?&_lJdW>Owta?vdi=2z(gLz7%*J z(Ie6m{}Oh^28bfg*T7~Eo`-sUyMJecNcY$;5mgjW(~~5UpVrFlh6Mr}#gIQ&YXLhv zf`#mNnOJ+L25Kb?W2pwt)HckE#Ywwx5=93}?kYXO6(xR{JSz`BFAQX!gEon-%)173 zXfjHBdE&%>H-&wAbFA9&20W*oq!R8Jd~;d=UzOf*d4G?x#?$Xf*?S2cvFM>)C0Aju zZv(H{A!HU!M8bZ1I6>`{($}uU4chyXf0ykE+lC1qZkcXytVxGV1uyjW>;Q9V4catQ z2Ioz&ru!=IA!TADJzg!s7!@l@o2Nk16K3G1&l2qX_2U>LT#*S+a+y-ZZQP%J01dWk zf|LJfA*-Oyn^n5;>n9yxf7bMpoWNKQdmIeQC&%NMWy9^0{<e{Xb4<x&Wk;BvYJx+G zlR49c4)C|m5o3dFn0SXWGq@tf3>H-JKHL6s_WC<v`!rEmt)svzTARfM{`xN3A8N*& zwn=h(m6gc{WN3rw8P0Flbl8;eks`7f$*7%zP#;D7uwWK#@~VR%a|7O}(hWBp-^F$< zu7<j$_e8}ChUo6E%`B74xx7_3Nd5SGrs!n~lEO<({kAaV1(%x6?q+VX+<&;+eJ2y$ z>BAqDhIDt;0vMNM&FlF}QvaD{tn=f4A~zhtHd#hvTiPV3__2=d(()l1SO^gr5nyTk z2F^c;f}9jZIQX@Mx*nHO|L_ysJA?Ps*t;341vb6%HC?K(y$vtKV{l^iLGD~pI!w8L z8aHbf!0~nW`8-K)@(JI`JoT&iUxBM=_t{x=@~9*);s2GMh$^7w@LHA>o5ELi{>RQQ zF=cc2=TiL%5BQ;ShfDQe!Ll#sa@WxdmD{aR_3c4?Eii~?WpqNn%^EznmM8g3L+lU9 z@?i2{CbN0!1CtLc(~rw)oF~?T-xnj&SuDw{17>1@@g$aA6H2=4{NSRUIkN~W;JwS; z$*ouwQ@09Cg3m*-FIOIHdXTAZ=@(DY)`A~tXShbchurgnv+-<C4R!C9VSk1nhL9L% z+>)O_!Ask@yW>9z4($UX@_lF*cwzx(K4U6oRc-~(XVx@am@VI({|wAOpBCI&E3n?z zny#d|i^MAXX|CH~=CLLmM5}LuVNsI6K0Cy`N4|sos@)L#U^9Jn^Fxn|*Fe#1JU{G8 zHZ*Jf<&PZRi5kVv!NX}YEtvTZ+5*17M5$!@@!}ix25rSl!XDL&;xTNPtPJ@$^?=-; zCk!6ObEQ|DS)R{7);C}ZX12YBTGRQoH((_HeEnq*IxEarM;8A|En^Zx_M^=oV|;gM zE>-WH0jIAI#!nHE_%F{KZ~fT8zqk~M%gas3Z`pBC!JoPK<9!3&u~UX08&c`q?iqNs z(Uqku6Tf|M6Qr9<3$Ev{l+^tgVcc6@YwZJyNpcod`wYUFf(vp%EP#ss9@3MKWR*V? zNjpP@b&A@#!Leed8L+Cn?3I`jV}$$uq8;ZZ%!E6KrBbiJZ5#DkgMpd?e$U+pPJ1_U zvl_$@E9AlaA~c!PuXXshFCBg=-vO6%Z=gMM5heQyo`p44yzYc@8vA}2)L9LM55mmE zbxD%=XSXAhyLk*w@?JD>;4)G#+`{IkS0lT`W2Rj$^o7^aiCtrvbHES~yKke`F*oeO zPhH2M?NT^$i6)CQ6n4YyY*=S$95><=gUC(VWGJP9-=}v{_ni@FtvUzWW(nMw!dYN^ zM+8~&#w;#vCwE6-7TFJpBgz-<&<l#Vu~ruoO<sr%<h)TgM1_wt8i2!sWf>W5V5UkN znTxj@9(eAICzBS_OJO(cdS)hgCOEMHV}{^b?ain;XBN7;o#afVEYPs{6wa!Z!O?r? zv0(KMJ7wi;@R_;*r=E#m6J0LyN4oWB($ILw+4_!ur#b+kV?Ou=cZr_QNTxR78M|Iv z%z`%T;rb27;!v-5@W=QQjr#G9i{7fjWVkp?nqtmAuHP!;)<(0nYB5mR*2jA+lgBQ8 zJq^)UVVZ}V_-8EwvmkK{`8iIdQAfkjYGD+#U3G-X!Jf2g<40O?Y(H9RYx7a}Bf!W_ znA^SZAgiAWJmtmlxBe`nCb=(M-JDRqd72!Wb>_1=(HjgNvlpeutE0?|B}_v8ipa21 zn>FZ6#|7`_bIRjVv7dV`iVzqUn+NB@3(M1-lTcd@F<(!6gPKI{W24Y{ybZftY=-%h z5ZX1|nS|=0l8e8-fxN<bym8H#Y7-Y?)t0vqvwbcl4O3tiFNd;s&ZTs8$$j#XyNv6` zouYZ;?U}j2f~(jv9flf9;PGo4Vd{7ZdrezQHeJY*#~7_*hrN=aB-c>L{-gp)*7F|S z=SgnqBxc(5mUgZ^B+BwJ#K>5|$uim;MV+cBW)C5w;5hx)5XRKA6G@@Gh<WPTvHtrh zU}O7$oDMys_y;2BKCcI5d#{33x+L~K)ZnBwp21p)VVuSPvz5}<(KC+m`=zu6Uil)f zyJS9v=s7TVSvgiEnaKT$Qz!om!F1)|N^&2VPVTz}&*{pku*)YD?ku~7y;GEN>!_31 zI;szDSquHxzaRLw!-P4AQ8;X$KE{4WaSap(OJRAyMUsfs;eTYV=7$Mv!Sw6*_>I#u z!0z@Ip+0OAE%RuE_8$u5az#vG88_h8!WZPRAP=55s<M*TE5R)27Uj+Fq^i9Kxigm} zP)Vi%QZ-x1uzfhRjxl2g2I;ZMKU3iAr4Eo>X+`Vr55N&STY+y=01eZt+{b6_c>U!+ z+IVd+Nh@81LyFosu3{lZsLV#Uw|l8~KjLz5fmdqFAm&sg9*um0XM%j`huKbUW@878 zD$-(_G4Em94<{DpITsej3}Kx{CiWY`a-e0*ZN6FH$WK@tMoKZNcsq3f%Rbe{*1x~R zk|tEpeU~b>LSPN;Z4G9tqHeIp6Pd)clc4O)HFAI?N^Lz`x+E@^t{nBpF{NW+;=3j| znPATbR1mjeyJp#wt!Hpnc`}s!nnD@xU$Tg>Jz$945Ga*KZmYeavGWdW`*;Fhxot+H zH$&iI_f%*f84HD*Lb*+ev4Zmy!Q8f!?j5?wZj4?C6=NSj&>2tcl|C#UoOptGcuhqC z=kRQ~1$$KTm%Oa!p|HzIN0U!5=ejfGuX>g7T6?(0jYmj&s4>lm;vw%x2Bezbpop4o z{`#na?2+sZk~pa$?&2(%gZ4m@XwZR^b7sOyxr=D~Cxwf)olPEv8T3Pb4tKC#MmX;U z?#@+0_cL#KBeRzf_ag>hc3g(=X#>$ZdpE}xN#oxG*TH?^AdJzT%w|vmDV*7cpD&Nc z3v0{m$A{$dr;XI<ipC^1p;HUf`t(`P#24gKVp#U)Ho};cGq`!R4k>qRWP>|~F#og% z;Ie!$4!QSB*k5tN(cx+&e{mu<>_5WVqdP%)TY-=>)@9ur?uwh_KJ#7TH`tupOHCL3 zOYbyDv7#w8;5A{X(6hbE@BDm=W-1w@sbUP9vFaw@u`P@_={VAlJqx+#7LRB;wt$!M zb7<j4V9Y2Hv-+-x?kmg4hjhW`=3t;gXO@-OOSy#+bSVBD#W?Mz;%m*kn|}cIbYCIu z;b$OhMi`%&*9+!W0$=rFJf4_zo7~1#f@a8Ioc2Q!Grx{vPGf_(J>`1Xxv`b2emG8) z7W@WnGhHxmX%DaP?k$|z{RG_J-e6-t#=-mb3&GtrpE8CxGXH{b6mPV_=CS6O`*jV= zZ;@q3`nu?KzBga4u$0(UFBlX)gJQ36n7>7inT6{@@NglUeI)`q|K!o2KiAoif>Pdj zTR5D#@fB2$z7-gcFF<KpBaOd%g_9dyOEc4tv3)n2sJd?sPM93b?P+*JYqwT#c6Wt6 zwp<O+RS#zFQ{Hn5VItCgs?72x?t{iXD@6N?W6@v8WQB&iG3nvDWlvLMpmz2auskQj zEtxtSUI;GlW{qf)@Msj7o}P$apM3D+qa_s8FbR*!MbJiWJ=53_18b}MMLFD8h`FQ) znvT*;`RP{{rZt{DI3L4$gDZdzl#63+*Rz~uM@g|q1A|XWa_@Btp|QMOoS5@hY!;eJ z9XnO9aQAh3W;+=b^9%R|fv&i;AX?!0DY2CDcnC8Yf;SuWS?+~<aHdb&-ei6a?DcM@ z1Bc_uw>d~`5bzdKl`OIC%{TbvW6A1P{>LrOK8Q0_2Qex658NJ!W>8Nr1M{9FxLBZ# zeUBI7pR>MXYbFgveXnTMnF8>tePeI))eJv>yZ}mHBEc}rKyZZyQpL$bWpW#XpyyE* zm-|nhl@2_LBV`-8Dcv81ox!=Z?ZiALVIZ(oDwpsJH+q1p{wnyCWyZdZUC-k7N#X6O zw$P#aiy~|8k*iD-bUxWb1BOSkS0mGy>&^=lrNh(hTj%&~)0$b*+6H(VpoZe@A3-tX zINBK+LJp0lYFRb$-Q!0Y33G}>&v>!Ps%l<#>?`t0QD#nq9&uV;-(XOa1M}7N7k}5- zMTH~2l3c0`j_Y(loAi@>sK5^J_&tKjcSW)jX$zT6djVCyP(TBjm9Rf`9*tYMpMpPZ z6eZ5R3sr^MxaG({s7ZbaE(?~iGG$k$XzGp|MCNc!b}^(@>vD4I*N}CRD)zgoV8ZVx zX6V7u<mkuHh(lT5u+w~5h_FLWo?z3)VcKB_u+4I$Q^M{=p-LE;e(|ST#h271xM_TU z-nA=}KSJWF9_n)b!CALm=Va40xl5BjvcC7y@MA~{{dKM4b`@Q~xO-M?RQ4`Xj(AOl z(<d<7;^Ra)k^FE4TcQ7?0TGL@@TVJvdQIF4tLu*OZ?C?ml7e5*aB>68u^)`OE8Fl! z<8yw2q#a7QuZK2$P3$iA!(QhX+-aFUu)n0iO2ZDqwpJ0UJ9P?d!IA8+Lmux}lgE>j z3;vK9g9*ZCUMI9s&%977Ia&dM4|Bl6buqf=J%A)3GgLBeF-s8KxgYk9p*5d|Lfg?% zn2{m$a94)$`(ra<L(y-(=*2@wEe(dE;Mq+3cmVcax5n*$y`(L8^}M%+QBbwuYE%do zg)2^D$v6aGuf9Y5w<h7ULSy8`Q_*Ph3p&dEM@C6Pp7>!b8od9&=^6`6tf+zP=nWsZ zwLMbYx@s|-|7|X_-+YJ8T`;86B?6aE#RjF+rGz>^3-@`2GkRFeJ&CyvVfi<~vQP<& z?wZg$`H>j%(FDvM4`$W>v?%Ge1pUj{Nw2VirEW4}w`2S%P2hd+j40xtk2p!wj@nVY z@pLx6_$Zm~8Yy@t4)Z}bf~f0^7;F+=g1p>#&d)dx-1qGUiPyrOBW<MbHyxoSK$Ggb z4so8JHqw;gW6-s9I2-RGoGt1jXi&xi*6fym2|Ko<&&qr3$IV{U_|^(0Z9;Fi{ToGg z8&Id?2D&CN7A>begRNhm!)Na-G!-%)`ZFc$!*f3HPaW=2%TOac_bQ%iT`-z^Gr>d1 zf9Am%PLZ}8Q-wbpCemh=fdbRo3bnXX;O*^RCfRV6i%gzHc?P*uwS6LkC2b{>+FihD z>1Fc2Gzo6UjmBGp55w!J%9wX$IajsyC+MslO#1qdz-+JqRM>{0{;3OW(aai{nOOrV z&n0okL`HF;D=1&Z9o*gTGV!SloM>;4i*y~)&@Gy!KRL}s-bofR`o1*Bz8#-*ro!ne zH*gxY5$?8Xv()qPqKL>?XjT17Z4<|$E1SwUW#tR!tMD5?+Rsf>YXaqWk73T~UV*ti z5{n|#m~ziia*pJ1c&`;}|0Z~j7k%XqIjVqzV-3WJQ_+ytVwjx_nvFS&ec4CB*Rq%o z-nCV%d-@4&{y3iYsgGwF&-`)qvdes%<^f2Yw1NhVJ<PnGJF|C2XW8+Qan!qgF03eh z2i`XCgqd*^Yc{Lnlonk;lP(L^^k)Dz`4-dbT3J3rOB>}Q?cv5aZTpjl;=sx3BsA_2 z;p1b+`1J4ZDP}+~WlEn0iKqo7Wosl*Wye#RQMCmW1!mYz>oqj@!hUMIV$N#SPs5Mn z&ggPh6|G(rLS^(kw)W->HnJs;|8easNrt|rz6?pBf1*umqZYE)>Nk1Ed;MHxz9NG< zA(#4UA>01p9vob<0*V(5W!@95L4N5_P%_LQaiA4j;kOc{$4P_lkUEit%RL$`VaRs4 zPU90BGwHLp0*cb!kk$8<829-I>oJa|hvHXc<Cj7)Zqrfr{BN%JyE?}wAI59l!fvL( z#a?4N2mOUg>`=NC@oC3!KTapJd$&p5_AG8N9>X#`TBt14l#TW32d*cbz0eN8M_0<o zD)}%w^?4#LTwlSp&eGyvZWcU{x^if{r;19)w8O#eTUmRZI_LDC4|Z)Qss}~XK7Nqb zHZ{gaQ#3J1*O$Be?E&QV%8EW*b%smZ!m-F*hQ5cH^E)e-(ZA$h&|Wx`1?D8f!k#%8 zG^(2px5v{{#d&x&WC=`O{g`i>;RTkisbH<=$X)!f3Ux2-#Yc3C%{+aUjQr%7#goA- zd43){rnsm)aMLGhjqqWkQW798UX2Zw8HJyfo#5;D5dwp3l;Fvf$KDJjv|r{3W|uTD zbY!)d-#3ys@Ek+YgJ#f<d81)Te+_BYltTK%N8)dzjxv+56fhs+&GPnn<LniGLA@B5 zx^oG4NiLMNEg8cmzuLxr%SB^l!)6@sy&7U7{ot%wJyjcT2L+cQD7nK7tc?X8%1wE2 zlvH6`7EM7v|LN>Ol|Hnb8HK$iv7B6G3@;t4#yU?e#mDV8QPN`=O&$|WvmPE|^|n?l zF3}HjcR0h?kZ{iC$52eDybk`#Q&3&ta_Gz$V4rU1N0+^>!RO_`Haxk-Z_<unOTE;v z_vc0M-SoM%DTueL%TlDSZ_8Ls)hs;jJPGG6wZ=Sm#^>#xgny(@;OM|=xPI{@UwPmZ zrdm~ser-QV*(H;N9`GA*FiD__kE^&*2VCjTKWUJ4lM;HQ_3+&5AX{3014h5;qJVaN zQr`Ux>}3yv-iR=^xM4W@c*V29!RIk_;bNG#@hAC)$FfZc91FI($t(R;qUs(E`jIt- z@3^K4owLqU#zKLy*;#L+7UBXM7JdTVPtD>F3rFyOj@%L0ujTk^qu?KP8OR);yrXkX zIs$`tFnEu=z?!_y(9rYyseh0oJ?$Hf3sz(^%nQfAe-;TlPziAEr~!-JI~g_)x=h7^ zH-s7C5i&_Rg*0{?TiDP>mOJe@r?gh^_8TbpMpfDC8>yh75`~lEHnB%e1zdvH4mc9t z#Mc){V{4`}N~~FmY9&dO*e%IB`NVV35k+|u<}u%?&qc>wrJ32311ySv0aq0UvMXuM z6k{jNNe6j?$V;Ef>|H^!=?!}J>C*9yH{kviGx|`mS;!~X)Aqp|`06-;X=B<-bA&8w z>z8uMP*#EA)q3b=QxAD-a=15Bi(rR#9p`*V#LWLLVe`C+mOZ@5sQ)CL|6B^bW3~8R zu7)mn?}0g`+PGu;0<aT#;EY9gISqduoN6D*{g+)z@gvVb;;Qkyu*!={CG)^`f)?KV z`Gx}B-&6QeHLU6HA=e2CFjP&Ny&mDj#-CY&kA>apoICX(;jV}EI+M^max>`Zn_ytc zb+K&9Dbjs)QfwRkoG-DPWpC;+951{R;dv`pw$$1VM_m6&e=i$jvr`XM=lP<`SX)$B zRswrR5MQ;?p0;hDk0;*_!{Ga|oa&h=5H)f=YwS|t4Lv84MS3`8{s|<BmlN?z{!(1) zRYq=F3M^@2EsQtmfC8=4+>*khyzj+&ZtdbWPCZ%~H-~)Tmm5!m_T`55LHsl7dbb?W z-5wQ9?!xj>C-BDLQFx-2D0#mo4wDi<wL&$#cFb`!fBhbntX0|mKULs6p{~?VK$Bd# z;|cEX<7oxR;qSO3Ofg&DzWT^-h}rK85!(gF%ZWJJoH7(%<SwMulhavu|7NE9pCe@( z|0AWcne^`Aawbx)WLcZqsp4@A581PM`?E&mzW+Xd&G;SHY2(9rI|f1Ro3&iIu_U{y zBf*M_N0j+^)S{!{b$jXB%hf&&VNIf35KW4}#HR_IX8B`r;<%@{c#%IomcNY7`c>TY zy{4#h`4yKMp~x*8p@C*ghJ$Q-GMT9<mECm~=As{XFqm={?gVY2eTqfoEN_afYt*rQ ztU1`|?PnFa%W=lm!!$hJk4YN@G9$waoallqacia7_<VtJVWf(0ekOy$A}zM+j{{lk z@?^TwjU-)noWHv`n{L)9um`EHDDRxWQ<i-U&lfC&#Nn1yb$%{df1ZFHS2+xHohADF z<_TJ7Hi(@9g*?HeThRRS9LTM^PTf-mVDs=gsI64O{1gq`-Y?IjNrFO`N5KXcW4t`4 z!M>;H2s2+Wl38aMu<;s-=<1`%#rqv+l}9AY>XuI=*T0v5{`!a;4@<DMt>bymS7lIa za39iq)UaadNX*k7K<>Fiaj1eM``Qo8vSJOSHa3*n&Hq4E*XqC^FdMrM&!U~$ufXYE z6txX#he?C)lar7gf$5%h`ww5mi0V<Sb-+q6^mk!eF&C-snJ2&V@kX*N4}rch)vzLa zCo1b%(-Ohw@&4I0+BEDsi2ugHpsj^u{_+&HI9Red3%0Y>$w&Eei5*Nl`wM5O9WPoM zXN@10^Kdas9nXYcfM<&@<F7AM*rS3Sba6pCujs9b)6@k=VDV)dSTz$yP0`2cKU;X$ zyQ4Tf;D@?_x)eQI*ryxWQW_Nen3;W7<85mG^2au4FxkU9*yq-1C^4qWu4}~`m^SAa zStj0r8){`Vl{NAb-)zL2mjPBk+6$ZBuYv?UHJ15K8%^ZuD1FKZ?t=O~NC-?}MgkP| zLv9`THO=6vo=vcy5IYFFUDuL?z8dMR|3dmIPVCr@aZL5qFTVGgh3NjJGcd6xi(<rU zxZpz@xGl<^yrfM4mvc4<EdQj?1v6caPdvhVcZ+dncpKk`gGjlWD+|=~<D>n*Kv~C6 z(EWpyHshPH3oD$r*-5;=O`pJ0(!-Ol%OS~IaQQr54KgLpRQ7xX`t7;}r!72j@0M0k zVObZ6Th_CK6MvHZ`gAsbYdAV|7(hvb8FSxn2DxXg@%N2bYFcvxHkxb_xP&3#_Oy^6 zIr@v(^=y>*!+~e;C|0OPES=Hab3XP+-xO-R5bRePiFPIutoq$RR+rU}+OMrByvK!2 zU0OrGJyPJEvLv3?yM(>R3%J%9%h<eIrPQoth5yxzpfDc`a1!pX*{=E+v@-xSG*{sI z>ya4n^9J?aJ3@ErH?Vm+hC-#4Y2Q*82d(SFLBd`Ia&(m0;Y7imm9f5TgLE4|;88L0 zeo|nq7=y!?q~NQuQf%MdWV)QQQRqD{K$#1l`SEe{s5NUmS1@Zdta!YOY0Fj$`LkrS z2{&e1r;1=u-)~T@-$DVJQ&`YwKhnOL!;dJ|hUz;#@alai<J1y_d(VZIWX=N<5_WW7 zKjeq*2xF6*kMZYnby<L>3yK@0NT$?;l?bi73!%p;Z$=$g7#oMfOWT;akq*w(_9p)c zf^Y8g7sw9Khkd=#kac$&3$)N-iU<11D0KyEX=~>t0(7|5y=Uml@^m`$<^h3vk=W(U zP$9c&iIVSB&@8VNx@;ooV*d!{t-Y2`oYch6D+;Mv>_!7dpP`1ulTp=q2+G+ulioB1 z?2ZC><Ss=&yG+@3-%p&uTvL|z$pQ_GZSm${U6zn~31rgd3mM;+M6Z^JPAZItjlJ14 z*?%gl0t>c(_iV`hEU<>e1FWS6N2+ZsxW40yJ56!m=a!Xe{(5UzTQ2flMClvwKQ2 zw~l5~c8B2f*wGOB;x{)SG?vCKJx@XNUh)lw5;VIajve_Wrt0X`P--uY-TO}=XSNa# z3M@5=M-RnW-R~fxJ_rj{2jbgHLvWJdI_ujI&&^Fwg|fm;K#fj}j(!wN+bhEj{~;({ z*$#>Ua`<G5(4&5r0nTB+`4zhdlfUKy%uR{{$+kYaKQ4ro_06Sw+w<Y0%?P31+liT_ z2Swkvy(GOtfupu13|75Jz*loju;b1WW^ra3x>#{IKxHENztmwZBL-pSd`D5RPj*S~ zsJC|fv=Tn(?h(O>*a{LRQv92i?V#J^z`mF2vbA?_@p;1B;VMgoNo#+@=Pz?uR!$o4 z^Yb$W-&3(OF?V7g7EfT3U;W{<&SF+|Umw?nxue#<2AG==%iE;PBqib9{PJ}%gx=9Z z<KGpuX8TaYoJgoq9LZFM&W1-@gN5()G*{Z1%3i2Hr6k7{Y|ff3Eaqq~nC-qIvQzrV z=c!q+$+J93=|wOZJ3OF4^Ou9s*AsNQ`55dx&?wAJSE8lLWgKErEtc)w%?IB&X&WAL znzI=4i?b`(&-aIV!GMIJ`1CP@h1^se9H7B0cgCXh{C7~F{fr;XrQ_UmPfU#3h1uIO z*kkwa6umE%t5z5({7orzOK>yg6)#5<uO6sUe}pH??@^O5JNh%{E_7Xe$&c39LfPkE za802JVB=5;hE|KwEFzvL@PXa>#fQP<PZ+8`U0<d&EfmU}#<H@Kam@H%B2!E+5&8QR z@?Jq6G)OWSo%|=^lFh`q8jd5QifM4WZ~-<fFu>eCS3I$~79JKh!=~MPSk&ju@b9uL zOB`U18(XxPnjngsn`S2DYM-$DmGT%})CIP?#-V>cu?9rso+jZv;|X-B?lUf3pa-s} z8pTq&zWB)VKZ^8-gT!I|A~|UVcr^L|##GmEN6sX$GvA29B}Rw_{w#)H4nr|G#=qpx z>p*xkNcjFAheBM86E<$KVbUs#Nakx4)CX1a@3r*#V|hNfJ#zv^cI`p${sc^QFh$XD zD{$>U%D-Iyk@B;KLuf-MEfz8<wfDq)pVcVVB3a8v>zgr2i6|PvMzhJ9mMr&%20LOQ z3m?KhaB?4pqm<7vn5G+r^7DEHHewD)#hdf95=2zx<BMg_3OUJ}2KKfFN#yD-qJktH zT$q%?DPG%3sk-At6Xpo4KaEr<iI{+%2X4TVspe?bC5@F_5xq=$O2d4=k?)f{XgZX| z`To<w8H-bdyzLzdS~QM5aFqc!Aw#EoJb=4Z`CL4FmmIeJJi;W;-r;H!)iLh<GK!Nb zprmnftZ~Fu-o!NqMwdsj)+8}k_Gkod8|c7GnW{q9XJMy*%Tc;IO@)P?@&)a!`E*J} zht=AZ(EdANyszNx3aBI4*XYMit;;9Rf-ur>x=otJd7xdaLxC#$d8-G@aHi-l-*sU( z)W5$auv<nmiG}k^T@U9#eb*6MH+?5dj9v=50ppmTW-d30UrCuN?&#H7z}CNz$Al!L z5ZMftFB1Wi|6HfcXZqN5HC?n;{VC+_In83C14R+P3)m>xa`K0D&^d86dwMhy)~5Xh z?UIui9jT5pHYd}R=mYRLT7!4^*~iU`(8T=DZ)vr{WL6SA1`Zy-!d(msVOITHvGmtG zbhBH-<P{^po}QrcWlOpgAH#oJ*aagc5;&vfALx>BzMnFR#k60mh2G*>GU$3u5<Na# z`}Z`KZ7`)=eo`14mp_4dSj0ia8UuD`paYt$kruz*c8>H<ZN&X=^FhM<i74~RRusfx zEcDSY=zh@)x#D%OY<EBRbjSeG-B-<9D=f!6D+e&y;mrR2nSrS>$#kPz7d2CU!_5&F zXuU@<tc?y}p)JO&ZL2Q(5po-k%)5vVa!+B<B*6vH5<{uQHT<FJNid;6ICp2KV%xY- z{<Os+)*<wbMtq28x9S_AR<ac&KeSTTZWY|(Qo!4v*@3DB`*8aNdFG(Tb2>M?SlRJ% zmXR?Z7X?qofOT`J*83UPy2}K;mPey^$Z7aIV4{7?!0(*JDKWn~<dCo{b5*Qhra>#K z4pGAr9x8k{utHgFiugSMI)ytV?kwW%51Y|zRt^?S&Z5gl++li1IhF(q-0qu?c=epw zczp0!4CxENmOCq$tL_kHcCk<VOUR@s?RiGGZiQ0aL^+f``HhSCJsO6a2@IOowygKb zA^z3WiJbKxp^j7#YDQBn2(I^IEnny0w$gFT(=n2MEsAEE6L(Sm?^U#A@o8S|(Gj-E z$%ux!E@pA$!T)PY0jU0u_dF5^2{zgSzq49wYv)GYS&w+7W$$smq%Y--kK@(voe+A| zVRX{bip`xdkA1aKfv8UgtnWb&^)&fn!LA4vu|o?}7VgB3S-bJSeLrc`vr$}sOB0t6 zJb`-_P)`M`kKpbl!|8t<orzygkJE-zX|*IIi9#g_*^;O;lOzcVNs=TaA%yHnn@XEX zWve8WEhI@jXC`~7Bzp)+68aKC^q$}QC)D$No^xjAzOPH|cbcfQr4mXuoP?gbEy8-Y zuB0tx!$$AQ#Lvp=T>4karb;u!vD~9Hp!p=MGWWvIGghKn|9<S6egWDlyNhl2_mSsq zOEGwEKFw4f%qc&d*~2Og_g9xf#)uf6s%iss9_%2M3MZ(vRK+T-eduEGSU5MPK+ruh zhF2vVfN?s`oR;%Pur;cqwEho>nofwV`qF)|QcIZhR3AfLCE}lQIcoeH3HcN5h+Wm2 zDO%+a?GTR<-w)wBg*Xnant~-0RH^uIEooF-kQjN{;2*fpTJSi9k#$;3uOiX*!4+ss zZKr=>i06Y=z~ruxke(MRB>y)7r`%e}H-1ErrT;l7JD?70uSuOU|J|fEdl#2x-4%2_ z_u{`!`-F<8Vc4YbN!*z^3QN|Gms~hQ=;Nz8DC(I2zRrK(O7k9@CMip5Hcl0jdWCSx z+kT?K4WbikoFwPXciOU`5Pi*kaeinYEWEiEng&XJ!2eXJe5E1{8e~e1{#{YdHGxg~ zwn0|$4w8q@v@frUl&>5Bmmxzj>hU8=KQY0&jPF6n^g(#ev^Q$|AA?bDDm*93i4Ldy zgs+EPz`1u7Y<)MtW=6<xw)?aMUo4vl*Z(fZC4=^1(ETnrc4`n^OIO4<T^iwA_62&c zu?GVlr=#=cPxSAoEtGe(TOS{Jg+7Nq1+OKGs9WeUy3;p|9iOV%#IK!)zv_)}%-)IQ zS!yNDnCw7abA5PPPYupemlkUV!IU>3hG)`ZEUehdCigG1j%+t=TAxp|J2k;4zy5r& z=oEMl8_LCQ9WbXR6Mm1AK8ssht(Q(z;K<l7{A63Q<UaXLjhek_wNo;8(W;?A6$+Te zUJx;PAJ}b3!sx@J(QB+S{!o8LlS5X~sWC?Qw`dErTv(5<&l*G6s#HojYE_mWS0{Kj z9V^|jY$b|88^KaLoHR~cgx=-RSfx3P1|03d+3(}<^5EfgFd>0b9+lDAf?Jfl@fInV zNEtir4yd#}2g~m+#_S&@)F{jsTvE%Z<kThbuDD?xqInw<)?B5B6_un?BD4MwmIY;b zH=z9EC((6Uxahfg5ymzIqh+@&$oSd`Q*I>DarD6*Y9C?N=n$&B*@uE$8EV3oV&JX^ z)(Pr%IQphPx9(ai6w6scMZCoSlCQT}6mp8k=scnHo@3e0&=ofq^knoo!Z%G6%ZzoR zt<}~gP*ZsU4b(qH8J3rX?nm!}*ZWkE+0UjT))Gz($`EKwU%}((2>z$}jy`7|5d>RB zat)5Rj!u@xb$Qe9-PpInpQELM+_kV$S$C;p-&d0dD1N7UgS|r6Jt6pENf*v~Sq@KU zo~8P|J@{Tvb<p@5L+j(5aLoLh;P-e8*w>sSzgPk77S;<tRR_a0i~WMT`XRw}-7w+V z)+|;VIhEyx+_3W7R!0-dvxN$UCt^+U3GvCJNoams4JX&8!+)1ja7WM*iOCuZN6d!6 z*sC+p=bMI2N}ql_;?_l2yipyuX!S?MOAmO#-ypo7d_&qryp%eHHz5983@fWfQ@>AB z1l|3|#RlW`{G+@Q?r-fYu@BPV=*ZD*@g$b$%SY;(zJcEMh=Pv^_Mqw*1UaK;()707 ztmC{DALNI!;qPiHT)zcU%+lC3Q=OvbHbTppgRo<Vg3XA@W>B}lo4WrHX=Ri){~COf zK6?EkJ^3`MUX&{w&e#b%k4BKu6iX_*{a)O@;vEI`ULyD$tq_-J6;ru&2KX2Eq^+rU zvEP;`qU;+G{?($a;dKxN{?^4>!(uSqxt=ngwn#no|HOwX3M@?5!_0k);cs>s2sh$k zi2NFQa^sbd6ZI10I7sOBW+<xUbcdXC`a*tMt(Eatb4pHK$xo}t<8M_D7&~(<{Zcsu z-V;r+JkFerulvFuN0gp*%J}=X1(kT$TKkmAQToLh!cYGS!Pa#b`fb_(1=F=zuJb{B zEoX?+ny0|!aVt1`NDbbtm@M47&`O$luPA+CGWdnxgIsB+-mU5nJUcXmk8GX~E;_pq z=4;TJ+f(808B^YQuMc{@>1uscts5>iKaIh0eaQTh9M{&Xvr^k=Y&x21<FrBvwHj=Y zRL97!o!?2yX1&QWeqouMx=gfgeoj7S)97%`I<(w670df7bNXN#3Otldww)IOW=)_$ zhsLv3t#tp`G>cM>BvRzqY;Z{Q!+f);>?5yA8XAM~{)l5#F5PAi%!(%C^$W$S<sP_w z%039u`D48|Sz_wBU!<zzf1um%1+Ym!S9F*4<Tzz{VeZ1?FsRNOU34E&eN$KJ^tp=W zRwjwLN@+A;`YJp&{0=!*1Ph9<eha6jb>{khpRJ94$f51!D}vT*ecpNO4EbdDl9;Wh zftDPeWSV&wl2^}TrKSKjm@Lh^ewN}d(@`jIoC+S@Glfwu{V{FONjj5qmFBKF#zP-i z<0SEkuwi2cceH(%?!q=`3Ho?{=yB@R-5UBW4yB-&NfH?_i2^>}gUmibEH)XU-PaY^ zZJ7Zl&p1dhC<SJ&4&W(S`@yI}M)2|>&D2(<>ZM!x&=x_sVdu$quSW6cIc5CF(U8CS z>=$|}+M|w{H>~<wO!DdHt;eb8@$OvdWqfHt>FbF*;GN22P;N~lQ&nBw@<og5C*_LA zi^oa*_LF2fC=q7)FM<UQ`(f?#i?}g)6Aqb}B)rU3V#(}?ixlK=`S*ijjK*nd>>(4} zE~JWW>py{u`w&`dIDo6(oVD_K<Slr`+hTFD1<C@lAm~K}G|mr|U5if={Z|dArtR)H zWY8y3?$9Q|{K8(Iw={>w8s8LRPMgu9Q?oEE<~TXLyGQaR``~mz1k^4+gsrXL;d`fY z={|H3=f?SB<&O@!uwolEMcCtj$Ya8_YELoGP#4xXqzLs3?YK^D5qe)}r#nZk!kf@2 zuFH<G&ioV#>xvSnoi%XK4plUd8Ox^N27cOONzJJZOpj*MPYR*>sS6<byeT(&`(wL` zI>w|wpka_e^A^m3At&W<tX72>`>F#9t@^UB?^dw>co#C~h48G`Rj_=)2zo#JlyKza zJsut7U~Qwjf|ozf<zhW8DI=02-Wuo%jT*YVs#Jpm$eOl))8Y3G*C1!wV0Il5C;Odr zP#AV~5_<oXv)Pd{kTTz25GPF1<jAhuLFwfLp}^y}F!@Ihoc?}4Qe27ExE5dRVe*zr zuS8%~_AIcTw2n?MaKM~X!{KQ6$N1x`7k9V_j31-K`di(2xy=_Ud_4^xuG@oyKb3%T z&SN~S*@FXa{U@sEcR(V)rlRX@lrlREs>X~!Ie7~bW*ej8sAyUo(LtlT#)$UYg3xA{ zQ0954T6Xu614oWbV55X|KKVx4bzfXc_S3uYwD@(BQ^OhqA6|e(f02E@Iz!x9#HULJ zqpGoV<7iBi@-&IEcV8oU<I+sncGHP}*fNaSev=BzOt|*(659FrG-vEr#)RrOP<ulY zmp(kj+HQw&)3SK1_3lC!qeWcZ5)JOA>0onmwRFF<V;y--TsQig5M<j4Zr+-Me{3X9 zk<)qBUj0?D=&3BOQJDaV+69tlI2Q{3roxHpKQyB(7>3P~X7X}xvOcK=^$P>QbNvZ2 zavwt*OY%@OJA}8tM*Q!080`j!VE3_&Lcx4>>h>TV>b+NsH<H!q#OqL;k~$iEyQopb z@h{f?0S{ykHHWZDPY;^u{e`?wc42b(Ztb(<0a-R~#`^TmsBPZ~-D8WvdiVq=R6Qz; z2)II%0~PT8F%=<im4=ObpQYT;Z#2bs?nURL3@B*NMX};<G^rR#ouiN_(V=1qX2-sT zHP>cJ{n$a+>2@wDDbAyHE3VUh*L@K8U^^Xr-4)|r|Fcf_3n%w^i9BI!cd%={Cs=P& z6hGHDk<Zdopfuf#V^)=sW}+5uQhN%x%$Fv3-R1K8Q>ZTT5B$U^{<m@+{V6xau>P6i zIgbMPniC;g*Zm{;c>bVC9v_5B8>`6kjxQ(ckA)?F4B+F5B(4pPflZ->;_YvmupwE> z$^RY)W}hreO$v>;ljmJfbZ-~TS4N9*$8*Wp<R0pHyR&OXr0_^V3*+W25XbZvct+4r zc&NIU@_Ma>Tas(Lr-BXkk;aLtqq`-RP=K`R9>e`Cmci)UUu5K|is^E5WDWkJ=vF(2 z*R7jE``Xf2shY|2MS!3p{l+y<jS=;q*9%h=*P!FzSCA`hXx#hlmw79@iQ0qK3eLap zfaAk_Nt^nQdhCman3WI37Q1H@A7v=Y9-R?JxcIVh_&^-^-z`+Sqs?&TqRiCHP{`Z2 zRq&Kup)(7w!?>xR@J7Z^hJll~{Symot__0`&!udVj@i{XgJpc7t0|WcH^d2sbu{V7 z7jXC*2WELoWIa{m(LH<#9eSTEln#!?<^F**)uk6Ymucg~oGhr9@_YsU$7H@Ht~7eR zKOTGKimMBgxjcG2?p@l4hZd$|d;33VxiUj+nmn2A_mn)-eb!UO$w0DCO-A!87tvtX zDVRQCBDM;tWVZZUY4XUPI73mS!j;+hXqP%~{#r$;7i@5D*dpH4c{Z;3n**fRMK*V* zg1CS8dI<BjMdwE&B=+fjvGCn*!DGn|9)CWUS2-NR>^8}zT;fT)wmzbsS4N|Kg&m&w za8xj_on+Hz$Pk=bTL7L8zOqfHas}JJAB5;%7Q8-WF$BsD=aQw<Bo0t_9BF09DZ|f0 zR6#$<#~Cd#$PBsv5D%~(UyOTS$+6C?Ja7!T4!`|ZV&UZ^yn25jhisWj4~Hxkx|@B4 z4gDnN_gki+zhXdZO{MjlM+0Ggxe<FQ@1i=}Wmfx!RSK1BBEj_Y0?v1ErRUzAxM1sc z>~%qhMkrfANct$Yk6KI<52OkTkB0IJ$8dJ&dsrx1c~u<LPYs9OZ4@RMPls)HYQ>j7 zL<m|P4#Bo>Y0Q_IuxkBN3|lxtC>St<H;-;Yv#Md7(yvYQnO{fy6xV^`pD@1SUM*f! zjl;sS&TRQ>D2_Ye12F{!=>GK_xkMRo-z_>|*ZzyNyQYC(^-7Ejl(HGF$@IIf4II-J z!W6mJ;)v7;5meSe(W+2%++xbphxMoM=ve5Xt;>_6&O^sX$=i8q7X-(>pfOLnpoPTM zs_8mVdd@4-_UT!0P|DJ%R2p*E$5&C~h@SW(=rAj4Z2^;7ZCt%LQh2;I2iq2G#6j<u z6BVg~i>)Qc`CqoyS}>DaD^HWZOpE_GtR^zn5nUUn@e?U$8?<7P)jy~Ekafw6kFC25 zC4sRNIc)`Omp>%bS)PNtgAP$eogsJD^*|@{lakXQ4o2rJ;pKO<@XU{8aL6DM6+^>C zuj8(m?vo@7%;?R_-OONO(HV$tXc4@lQsLCw6O!9aVy`<(T#nHLphbBC`MQ0C*h%d~ z`!%@qy2Nw(ej1ef$Yb6m1@tW&C>Cl<eRu^!>~=B~rd0ler{2FoHMcju8MoIa$14=F z4;6x)$qa73{8^}(Qb!T;MR57z4{A_ZgspxG_@r1xl<f!u$(tkFnxP225(?;zk}o;0 zI|ggym$AR`3eh{lSn}@$iL$@C<P()@J$Fm4<c_Hzc(s?x?1IsK&K@+jmF9PyW+5=} zuXywFJ)%rS4p)$FIor=b--rL<qgiuA?HAJXcDXZb?>+;2=6Aux@9s%1zy4xSilGoZ z<dt-8Dx<5v=HeaWi+F2Xk+5|wz}IE7DZ|r&bB+%c4R<Qh;A;=5=Z<HTc(;?y^yyX@ z5Oq>mWtc+2y8FnvTRpk`_)LfPjHQ62og{z!k(hbjh;u0t$L*iTGw&|rw2gg0dua%_ z3>l0t^C9({@J(WLeHJvDM<MSSfTk&WqKBcB-G1-GgAVLt_e*c_{)OlC!~VJ$r=G}h z3BjcfPMHwbvI*2KIf|X@;;}TZC!SvxjrRRj*y+0t2Y5T-nnR<gQDF%V-{y@TvCC;) zf?wIjv-0ToMGNlPHo@%Z?wB^blD;-yMn$jjcrJerWS*J98PTB_+*OCRWN)RODZ6;{ z-37F|=Ste~(4MOUABvAdJD^#0DUJ^4iQ61E(mBOFbooUs^mZ96yt&^WBd*(#<3@=e zA@?3e$Mk|;tNq~W*mdwq<%6(wWh%BG8;fu1--CYfNz#h>PABJCWBSJu>yt_{+FDU4 z4tRD7thf9F<2_qZ*1Q2f_{s5Hp+C$sy$0p2gHbSPvFT}ipX0py!?X?dtT@a9SBF@# z*?bRvIQa`V?eT&%<K+?;JDKEkr0?W4JFr-_RF-e!Ei3wUp1NgpgG8G`f}NkJMd2%r z*sX=?Vg_mVuqS^5V+<c>j%DxEgrE`q1ll2G*8V8as?6_@lBPl`ie+>t`2rY;DHvg{ z%GzNbSd}NSOq&B}<y2GLwSFqbJ%0tiCS*dr&qh*|KTrG5nqhx`Tby;rovusnIkT#N z(8X#Rv~3*CE|+HUp^gzkW0)#e8L9}+k9J}e?_sdrs0SWbHH2EPbTKDzF1i^6b49}? zh}o-%`_=~G#l{=xRTe-uau;IS%oyA@e+b&AoZ!#-VHkLMkYKGlN-RA+faE4F6g3~O zCB?#zV*2hhG`_itbYm^?$xo?UcA=KkTvl+(&@udd-fudv(T3(O86miy3=}#)cmyi? zD|qPN0i+au5J!G6r9k5o*1eCq3SLqt=SU~u35Pa<ZFB<aX?+BD)WC@?g&^Y=GD#f8 z$9OL_`+JFgZq~5Q?IAen8xsa+(x$^%^l175>J&4EUv+VU8h26bTbsgen{PvPeZBC< zhtcEbbb{t8*z2cP_VJ%Qo7Fc$OvgoG`m34z?^H6cFY)A>y5Yhy$q(^&*lD56#TT#s zc?$K){!&M&8(+j$=xABRJ9gfOnZ5_0Kwf&5-HU^;!<k}pk|A3knL?#Lny7EKbW+-& z2ym1KVaY>vPVTlE<-ZN)`s)37Xq7%yOz(@Qq;BWM>C#MnJOHi_KZ+Ww3m~<;H@zR5 zh(oU~gedI{Y4+;E&y=%pzySk{YdAn@8w}~CO+0CDtq@JzQZUlDvsnCCV$OCOhPfM~ zFd(vBw0>3xwn^$#UY?Kj`H{kUM{m?Pxf{1h-Rcu_{kU7d7K(HC1n(E8Y#e28#oNyY zqP)rip|w1g?3TYEg~x--UOckoRfF!+4od~@xafpKvk#-f=&{1jZM{MEM4xNA_z3<V z`g5-fd)VOFccE>M5(nfDpg$_HQ1L()?s#kRzm9tHOJ9V#I}eC^f;D*4stI`Nz$)74 zb_56fSPT_c?o;>4$1rA|5!UXX0&!vTTzg4Q%rzPXUhcb~^CLOzI$#C1e>~1_D<di2 zwN*SNF{WnPxWVA#-=NgG0bg|bLD^wH;Qr}Kx?Ubm^Txdvj`@G3pUD|~dq*V|cT=aY zts|gC$6k18HUT{*l=2a&J5^k?4LeQA;O+62n6WUP>_RR=(~K23y*`8vF8WD}=6vL+ zJH7FbQL?pGT{eHTyGzS;7K6%U7aaOkq=13lVV}f7-XGJGjq{Gc+3@-F^56tE(^12g z^aU8QMw`2K3?}_74=a-^YdHDGF#2b7PxQ}fBYCA5@;&a)ZBp*}TU`p<ng5_c*5^6m z&w6e%y$A&*EAiO8PvBhZ5ABy;TYo(r&)@nu@cSG)Gzwgb8gg;iD$VboT^^AYToxUC zr_lBt2{6BHDSP@Sh{Kkdqj|m|ZQXDIGw;^pp_`-O+O%`jpdJH%|J#k9O7bM8=nr~% z;}Xez^|mhTHxB3B+70JTk4X$kE2$T;MiAEYz<1-u;Wxb?+_ZZj*qp7R@~`@IJmEg{ zewqfhxl<|GtrT2uNefl##5-st__kh#?A=+A@@xXvOYfqM_E)KE`(#|GV1++MPX*2S zePC(52ibhPZap$ziIr~H<H3>&C@d@#uF(-nkflJ|pb%L^k}lPSb-@=Q)40dT-(q;g zKi;(IB>Wt%gBIt#WyJ%Ap`Uy_>=+WkU!;6jMEU^=$-NKu&xk(g#zRrdT=aY@FPdb1 z5a)dwh<=q?Fv7%>ZM#W3m^YWfr2i{Q?1;s)!}{_Bxvn_rM=({sv*Ax3`{B<sTl{ft zH~y`NmiRBngq1Jy`QM+-+%!eXqKKsw=s%G>-kb8)3@;(<$zF24_LoYhnPBIQDqNz} z9}?T5sN(t_*~RxaF+|y#??^X;<n7(aeb*yV!|W%l8!;AJ7LOC|KJ>)2`myj?MZ~cN z6|!)xcqDD9?xLH;T|Nikw~g5}IlmIi-&9j|?pQu%)<#?Vn6m7t6+ajli^1|I@LlS1 zd@?#6tE`VxO^XWeYMh6DJ3f=%#8u>V{yHolRRONs!ex`%vT5$*t!(RIBoszO31;@% zLQ%`;vI@g*5NV{&79j_?EGdbtY!dN_tuAHGK2C{?x4|eHji&Sa(2p@yJa76XaB@B= zE_`?q65Miye<M;TZQ2z&?=+uvYYZV`)o31HFdx5OKOwrOAK=`q@$9;C58H1$NQdSx z!aS8^xUegY>w+tB?`^5<y1XmjPt`=t5!c}J_B`6AI2>avrCv+tm%`prwPg3%kcxBl z&}s1|{?jv?Q@2kMlLR}`3D{2q4?cr1y+pBmaUDE!@5YmsXu=Jvxk!DiteqD|!*($m z@()T($pT-=2eb#Teo)4kh;ZC2g%4h3u;leTL4Bqx!>c2^(R5#v*k!&vSL^J-H3~`4 z>hnMxJ)j68C(VSHJJ+&Sr+qX{*_7SNXK?!c9PppDK=MFH?=<s=Vws*c+AKODyv(<O zy4l@W`*VYEc84M#X&y@xd*tKf69F`L-W#jgK0UbWu3*^dV-2-cN64*bJ%nA$fOm@x z&^3J@?D;Pb>tEKx*9{{eym=8B&QzwcpZ*EH1qWfC%YL{eb46$A*<e#&$!)0sYIX`Z zLI@H2CO6adNw%m`rpH~kJ*LK36*2v1AIupVEDmWZ;zmbpVd<^SSb0B-uQ$wrQ@ed2 zBOw-!wlm!1b7IaoK`?hUr}GOggVFts9CIO@wn$u)bmz(7eJ++WmP=Wk4`GsfGY4*1 z9;DIXQeHl4DYkVxMA5MtV!i8E3d;+m^o;R5@n!~;J9OfryKxk2u^q;&*a<q77g#rS zBH8<%AoT`QjChty7mB3!^2!7JP`VMd?<7I(MFMS&`Y9IPJ4-J2+r$jXl{?8J33k<u z=k_lytn<Ny*KFQP^E4EBbFeXgj@SlivnHdpRwOuF)qzW^w5X+hnE2`SP7#_4MY}x{ zxkX!x<aZVeAJrtrM{Z|vo=X;8A2Ws>J~U8L#du1bI}ne5I*pHHLpbt}3f62$lO?z3 zNZza$f|qZ1v7em>y5H``S<~lIjoWo`p2P+58|gr88}RCQ_wV%Kb0`h^GXuS)UtfbS zn%I)@U6557u_|0g4NFD#efUF^^|QvZvk#?Ps?54RG7#H0Nw>o@QpP`|7ZiK9gQ9^q zN)1wYrd-K-%agHb_;D`obXjtdjzq7CW*jg=owYifux;K%p<qG`<$Mc4SeJns>vhre z?=Yf~a-0`dFZLdM7;KwW#T6g2v8cEQ=dGSbAuD3=+`lbcozw@zCMaRnzj%rNsL7tA z6vWNpxoC4I76xSg5fpu$#bSxSZMoqhmz<i4n#&ZZ(ZF3u37N@rFKD9TP7CbOO^|qi z%WO)TvoWu=6r8n-A;9_&Wc~R=hT)RGWV{@jZ<NP~{M)27wE^gEQ;CW}qfGyr7a7+3 zp-k%%f4!7O^R~Rj{_Qs?@n$UE%2p-eeIh3I(6wp$wT>S-A+}!d<h1fYbe*tL{QY`9 zwXSxjq*Kxz(z%vAy_zSrYs?3E!=-THgbE(&qy$T3X&kAeMe}aj@YWum&@$79Jmee2 zo2%V9GJ7*UFdr(0T+ruBvpjgW?<I&bS_h``uc#{4n@r*tlT1mQ|J@yqPHw$1b4w@} zpDl+GH!om2o)8=4GdSX2e;e=rF7r|MAfa07fy)hC!IRIGuxnnl^`o)~oLIa718Vky zOW#Dw=v;>Pr>T;E@AGtZ<6QWCJcQ(r)C-TwzJqO?4hCQ7f-afMK-XzD-`g~sLi%42 z)PuX@p{Qe!@+OYOJxaK<rIhY&NMd{AI#ApGPqYg^4%<g-@l8<+vrl~&zwCKVeone< zwnMr(J3kj|9L`hOzEIqm8UWEvRlI4!0M5Flg!Wxu2t95-lK72NQRZhwt@Uogf>)0G zbwmi%eO|=fcPxW5&I>rJ&n0WGCKVd6ZxVO(zD65@j*(yKDQF3t$<8(dF~U2QZr?41 zHF9B4vb+nHUHk+(do$ok#0?C1F@xmxnPbR|E?lbs*xoP=J1o}W^ch+37)E3A>#4lA z&m^9?&5bwN3Rpepp{Q{_4`Lg7+srnM;FZ}|$mxQ*SbjkA2m8pQi_vyo^bP1xN-Cay zkjpjC7|i$n2c`|@$;@0C^zQ6NjpH&Xmi4B!-tXyF%pCleyVj=Z$5hGdQw?o3(k|xn z1aP^p!)x|Fhn&xysU`E7b$MEm*w`>#OrtFEg!)pL^*x#*mPot)3?1Gw*@L$BROE;S z7sN)r7c}-_KXi&wCN<Y|2zh#vYWyv!&hwH?#i;;1E?A)9+94SIcB<qnR-hhV)5&4w zPx?INIMpjR!AIqA++C}LwwKDJ&cQ&+-ywPCekfzxl*MH9!Cct6<pjJrt-}c~E<<yt zi5QjE%cf2>uXLV+1{mKtEv7cl<eJ!NLT2Vt9ys2Nx3B36vX}BUSCpgh^@)=t795~| zKX=n`GUt?c!}(QzLw?kzOttc(#X6mvRC`+)n^q0sqLu!1&aD+RE#o;yZY=u$uo2Er z^Th~-{jwk3j^M-7@4@rsIoZoz13|Oek+<xgMR%UuM>{(cHnyBhGgn9OkTzvpKl%nN z3o4Xyt^GMf(Ew5c`eMJBVW?kGLZXz_`MkCf#-2MZt_h67kE51j+`8p(@6hD3r-=;E zzYe~=b^v49YNU!|H2h;T?&`Q9<VPrDujk4X*yX6?&Am_VH8p~1!zC`t?9FWrH>}rp zvf|-qbor&!gK=(KhA}Bon3U3)O(UJz>QMqTb>6@#u0Enkav;cmci?$X7Gh#X6E!T8 z$NKlPL1}>;+ng@M5545j`kod@);9hv-F%KFnqvCDN~^>1>g+XiBQ|#3F4Rg4y3L-u zQOL=_=r3DnlPn7s`9;CY!g4|9Y=(_--+ioQ7Yrx8rM$J(8CcoFkGFQ+!*lGU{q56% zpipoWzgC2SM|!%@=6;1<=Y61QdQ}h-tjl-T%F`f619126$2E@s#OiZ)Sa&pA=6+i0 z7>Kn%Q~aSrPmZE(2UC}!!=c_{3gt(S!r+H3u={xgIlqpB!AVmvuY3o0PV9r>E(x&H zcc!RU8HEYKdvVXzo@DgoKIj!%u{Jjg?A8_I_o<@R^anyg|7BQUJQK~O9H#cUFrE;< zjAFf}LyO`MS<$Gj;whuKEO;k_qw!M+TYpQev9BQg|E6Nz+M#TBsT1Gs;fPUIhozan zh%5?r$*Q|w1nqOfph3tM4D5nvMf)%5uAC*vY@<PAubvneW+k*#h0>W<Sya8}I*v+; zh3on8=y~E6Jz@*K?sS}z9=q_e+*87~6Hg%b2h*UAuKX<YHLU%6jXlo{l>N-Oj#EO; zihAL?nDVV$Tv66cXRW76?&a=$(Ks8mQungT+G9f8t1|1m@9kM@%>*{sdq~V(okc;d z_r%FZDumm;o>B1`7x?hEl=A&&aCMt8uM)@MILA4h1jo5;s7%l|n<MD!-oumc%&@vP z1hdzL@Z#Kl?7jGu_0a%nE-#DVlIDFpI53a*s=O3+EMn2Vx>y`;I-9k07fE}qX>2^* zfHihXzjv=QxP8-e>E`<lOdL$nNkKZM_3Z+;s8U=!T;N+zPJ!IH2LfD1vRzjuMtkii z+m9QtT>B=ybS^<9DaVt1bv$lL(nI(i%Zbx3K=bb3XnfBMQ#5RaN%r^P@$19V9J5(C zd1xTt9u<c!L+gaL<%VKhJj1r_-zgw>BriP{jN_ZXlf!*4?l}SRT8uH?N;HSy?MgVa zcrhfDC84fbf0+7lF<R$^Le1{In6OUDWHb!r&mDW9i)E6{m(PaiGfuiihW)l)Vr0r1 ziYhEK4d%+w<?QuyFukcaWk2b&JMw!8W_9U@U;1u=5vRwp(_bse1=Mb>`(_WXidTY0 z7c;?1uP2xN*+ct=Wr~3-PSCMaCRAcJ8vlHbBSViq)I&}Iz5Jw`sp=8bROv51+nP?| zt$18$WsYDm86B6Y^Y8v;68qq;U_99#{GUvthkv9#SIB=nBcBC}LGjQfXg&m~`-9%a z{bGsfVjKJNwY)d}BrHjp!mdl7!>>SHoS*2->DB4nZ|DipvSSDhKI6=eWkoRVSP<$g zE#<q;N?bLDaaegUXD^u#G;0Nad_ENvUSy)itiRN)&4QL0JmURVZ$fCoZ1`mVh?5+9 zQopP&6sz_P@&>wa$<H3(^v9F_ZRpP0;uyT27)C?NO?XyyBKS6)g^eLYxjOX|>3jbb z^<6e|`N0sHg&LeQRY#~>a8uA1W^nZ0D)IZc5<ZkafIa8EBfqt$IjnmHY!Cbj>CYEK z&LD|--8YQRPd>>`wm@dnPT-@+A$agf398f&X2<>!0x45zz=0=}A9+&t%w`qUTga2) zQWXhOqA4qo%f#&m4AJesSg_sEiw)gIVf?2J*nh4!eEmC<|1_)c_9dF6{jUf9U8RK2 z{CqigQ<hBQbRQvWt1d=tU4)wx712IFpKe*Kr&L3Gm|9_kw#Rk|Dmzb8x&J%3apNd& zDj&dG`+kE@cdkHj$uC%uwV19f9z%a`8?s)wEl!Yb2_OA?a=38<)Gy7W{SVZ+m%Jc& z$Hk*o$3f6Oav2OBZReUlDm>OYiq?cCids8Q0i5;XjWx02#OMF9%b0OkcJd*NXm`Vw zoU>@@`wI?_J<5R|iGtrp6G1k47(mrRx*HOOampG}#-J-LF<XgGk_Y0!@TK_DFp!%~ zjtJ>vT#*OrvX0zoT>GwF?3E8fnMXFXLLeExilIRcYw)b$63kh7mYR$5!SSEK);eSO z$&4UM->569?|wl2yG`Zp3ztE`=Q_ym$RG##Eiknpgyf`|@~pE!KgTZQOoeNh938{~ zQvOZNa|nj1y`eRKVsP_qMKoCZU3_C@iJza;!Phux=9cz+bB5UB=)-Qb^N>Q>+=At} zY{C=rD?WuEyCzY2z!nZTvxKZO9QnaT>4x*^04_Xv2P-;fVzJ3KaNDHFBcGVD-IXwD z-gzm=yt+~lZ?rBNPz#=hTlt-t3rFvd=G#-<dGW>sFm_cIb=8#0?rRJLLpfhMn5N5~ zGaRTr>^N%csne4VL(%A|I`?ZuJlIhua#|Bd-AIPUfPLg`yaQazvV~EDa$xqEFq&o1 zLAqu(WY*h|L32&1Q+%zUXdBOGd@b31@nLSBuvp3&`br$^-SB;-jE66OfW}h>;;W|> zl%shPIt^%mVbLRb^&>y@AHEwWN-o=)e0eT9uuu$oxPk1=CD!I{2cFm#2t8*$qP6OB z9KrLEww7Bf*kpi*t1+ce6us}NigG?NaLFPE51pI>cUKso(!`@=wL%}S?N$}G8ie9H z*N>o_RswN@qhzBGP6F={GqCRGCTpGf2Wk0jRV@Eyfa@)Dgy!EG;Pc!c25f%Lt2d0~ z#>8tBx?nT69PWaUq{ACtPQdDY&%xhz5?UOT=CL$+Xz%xwdVe?urRMQ0H+%l1^=}`; z(wux@sa6Ul?^j?=9X*PAdJxP_g4x66jJWuH6SN<_O=q@9p6kUA@cfrE@V0**OxN#1 zM!Nk(!DTkomwO1&UgOZHY!?2#*8!2mZLE1g4bSf}!R>xW#bsxHkdgdXSgs*)52RW7 z*|XO)^;9G(rA|h3>&|7H!;gUd8+UAomKX)2uY$eLergX15u99$t@<eq<YvbKP}B1h zbnYoRO-{{a-8ZS^^Y(>xNL45lRxji}mj3wh$9%HgeOZWc9Lv}H_QC0YFQKN!ThV1k zhM;jihvM#x5r2hj<PDCgJa&~fo&6rojay9Mz|S%<y;X}Iy`L*I+l>`9zV^YhiyxDn z52B9%ys+UkZu=XCL87uKI%~r8i!xElB+w+6Pqf4^8yxct`TUDcJSlhxXSbV>x$<a= zympm#W@}>Q?%`-QFkV<1G6!n?6UilEICXpfSdeSUmhC7AX4`%bsYW>-8&DG@NrZ5# zYzSGN|BuS2o}|ln+u`-=CP;M7L|-@n`*SK$Ek~6-dz6R+=XJ;Gh(hs$l@sRudQGjH zLq&0xJokF3M+Ga62<w`=UR@vcl$w8~iCsHVr9H0#hR^fC-!30S(})^g<Jy39CC2Kg z$8+dXe+RmS+p+{tqgMSgIIu_ZqNz&#zZ<t`Z>kE~bPvLK<qz=RSUq+ze~JsA9%m(^ z1NhTm3NG(_iRa%n<JldPS*2^fc>0PQZ~62T=C()UCgst1T)$Czf9S+c;a8zAErh9_ zFJOVa3>A9(qqs^pvH9UiJat`#br%43o+OVAy)1FkVh?V#RpM~JQ@H8u1@PFJiVdMp z#Kd`P`M*7hJZtk(%zQb92OPAA_wk4Mf$<WYQy2|xy>3%{=6D;MV}Lbyf>zf`T-nR} z;82&TqIt9i-MM&LwCXk$!<J5_2(Ni~V)9u!^WQ*lx;{zDqWhuSwrf)M#DMnq5pl>} z6`bpP0%Pj$u*rzKpuDq}joOSTemgiAgWA=2Zgi}~qMn2qS7RtWL}Ki}utvSKC{F9} z!HU1GXffp?6t%12a_2<hP0np@sqM#si`VkR{3>i;8BD!O>&WeLJ{!b1&^D9*C?@MQ zWzT6L&3TJ3wEsf*aFyusyxyEJLWSSFK1+kt5eBH+V3+R&oHM}>HpE4s>w-eM(m0*_ z+4iyl*J*4k?XTM;zMZ;!CBKL|#&)6G!69ZVT2!CGUOr>k&7ddmOxTBkj$RPw^MqvQ z7m|~~a9R7C^HB6*s>DyL7AlraL4B<R@xZ_cc2zhddw%JUwBOu~TQ-{VvHQC@=kh)b z$sI>MEAFyRU;&WARoT?FoxpEfU(Oyn1++fNgU9<0y1TN4J}$_EscTCi>0f8w(dR#m z3hyAfp(j}X#wE_5HwNwPE`WaTci7M=0UP2*(wfqnv@K1_Oy^d^rVdBY+pLOj_8j0U zI%?f`#0zeHY#`tDwo?9ZnNT+^)mpgvjPmOok%~Tw21(L)>7zQ{nCFRMFa<Xo?ZK~d z9dIqUSn!$)Se(+8E2RC&@rGQ?I_iRZ2Jhj32T_7=d4F~)e@UgCBUvugQY=vlgI?D= zqiVOwHeWkpc~Wa%zTsF&%C8bQ&Fc>I?@8?UZ8;eXjYQv&D9(ci;F&^VW$=3PXza<I z5`1vh^+`DB{yp$5TF9L&3_z)iyG_8#rIN2n4TCyO7lLMj)e_HC(puz?`Z{ScP1T)} z+fR;_F1!&N46f1(mpTgi^x67>-%8XQ*pJt&$fccHM>zKQVJLomo-W*6j?aQ$QvS$R zLHGS^7M3@V{}Cn72@HXm%4?+iYA7c9yZ}>^CJ6Y{8RmW5&4p_lAa0x@>euvO)wV;Z zeKrj}-qngQd6~fVSwt~6#1Sd`Y1_#G_(;xy&Fh?@y66(T{Gw;0F?<Xed|D?w8n*}M z3|`C|hb@IUQU`R(fKmKy!BaTes%7IbZxq(ot>g2%<f&qKcW&A^h_kmprjtF+^P0Lj zbmru2zR~&;^3~1>mW!s)biE~DvBUxXx9e*>upTTN&cWsn^0+$iE-lp9hgm{Dp{^ka z0!OV9syz$H(R~YayY>z%8fNnrg@0sn=N+}Cjl$@>4`9)0F)iqB&6EFy!i7=(_$0sz z-Z)p&=$cR}#CF)B5G3r>cEJfB3Q+g3#0<UAv#jvjD2~{@2#=oa%RS?xaCG1u+VbiH z26nW-O^FkctmliHH$>sZF-h$6(i_@(oME}gGpRtDnLV$@u})4Nng7Wb_oeN|U1>7> zGI2PMToKDwyT?n<N@v!$@5Mpaf69_pjpb?MvaxGgB)MJ>6Q#xs_&AM%^=Zek)$)&M zAG=??)%1(fZ5Ij7d;O#wOo`B*qQP+%shIzFD(9Of3y=QG#q)gy45G49|KO#vE19u4 zzUvqW(c5QZQ<lOiF(G1oTqvugb-|p_Z!~Jj53+sWEAek+;`P`#T$zuk`Y%s-JQMih zdS^0q)W;7;P58>vc1WE*4T_IBk?fl*4l_C?n57&P%HNzNF}evZjWfa5=O*Ek^vV4G zTRODZEP<q5lKVmX4J?1LfXG?OIpk&G?b8k{KhPUm-EIM`&ZMei{h^?D3%H*%h5pNY zplN6}gxT3(fkCA#ttpJ24U2;N&X>?VcsPEZB9F~#UD<kL0y`Lwz&xXuV*Yy&mgg4H z$np|2jXeXJ@6<?cw*{klG-f7$q^Nd({<~DVr=*5T85YTv+d~6-TXe<k6B=N{G+lo8 zb~W<JUTA#MRd`k@$0-J}l7}aNQlxIslaYPMd8I%4o7)3trQn-HL$Pk^Q!<!W3Qy!- zlV4Z_x&Ehw3N4rE)QM2Y3Y0vN@u%4=))h{g@4(LX9=OA*Fa9_+4m{iRIC#(t;d8}0 zx|_TYqeqtTo<5Jk=HeRIJF0;~|MR6<EqjiZ*pOxGpHXvGo|x!(1Gby_k=%iJ4mDQd z#}k~mUt}y;O$_B_@g=<RcoywYoI))ZvoY3xCYGq5N2i88<Q8_D;_MUztxMy%i%9@o z*wdXiC&uuX$`f$o)kaJn=1<S$*YaP%4nJCSNbI~V^h^4?XSqrH)1XN#r?E~9dNmDO zFL&pEXZC;?Zq44Wt7ylqZBQ{`0aUD<2vsZ8$XPQT2FNF2cApl(=*VES)UTqd=^<Eg zXcX#9dd(BUbW#8NBivdOhT8_6fc4+f#SwSq@v*@|cw+Zh)cRzBm-e^7hx~GK(nyD< zU;}o|4&~k(*Q3>pPQ2}PBnK&Pz-{9WNO|F-Ah#O8$KM}}k7dHOH|Zpok$}RPsn{4C zja~-=xNWyLzx;8DuH6i=F<sji_E>MgxVOsmz0(aa3F$>m^%9?L%q=#bc?}GP4yS^S zMA?Hg;i!`4iN%s@`DOG@4onQgQ_5Np=;*`lS>I{j&BLHGZ7S5abVfPF8zoO3_|TeO z8G^^AB#Dvt7$Vd<!(lZ&{2lTXW^C&M%MXp@SyiU!KgAjY{0qf^q^m$5y9nm`pTyg} zUO~m@ascn;LNtegL2?Ku4v|cyRte&p8-Kucp*{AEFMt)B*V&xbkKy%uXW_mcL%B{% z8IMT*g&g0NJUns~XDy7SbrmyNBfk$<cn=|~Ggt8M<ZK?%;{~mI7$NQN&(QHCe<(32 zCL_Bk7(G|Yt<Fdii;n)0-LQ-1_~x;2aP=RmX;3S(-@lBTYBcal=U~|XeIM^XkN|zV z_raUX_R*Yw#o&+`Nku<Tk=Mm)sA?CiORj42M2Sb4*tdub#1OLm_EglkdqR-w7>bp> ze$$5Ny^vpH!0D^1d7$Qgj@T8=rGKLMtn(v)SqsE&fv?CY*BQxorMQ09RhB)LNBP5v zSTe^6bcTnaywMWQd9W1y*Bi_FOzOhgQCgyZ(@g&OU?9t_xI@NeL3Ha{I$EX6q5sRz zGPB{&sO_U4w6872><=Nhx3!YAD^xk(MNX*M`BZp#rw6tUh~hSH$!m4#A?PcVz+&@z z5Y(>*o;*E4ao6|59PcJ@DytXXKT~0ivGQVl*G|}YS@N}gu$EZ)Yd|*elTd9^hUO82 z$#mBZQR&qcPG0#FJ{wJ-M{@53lh4YKcew$EKIzULmm=v*LLsV3??L)nNtB=Zk*qcq z(XmG-;Mp>Lo^t$*aQ*Wfb{v4@VE&mi8lOYZm&fpQy#|(=^|6r!T>{mhOx|nLpQ_@& zi0(QKV!C>s_0#Hds6UeenWkq13)=&zWwaMVx&`6FWo~S&E@h&e7Ngh5dAuUi8db-S z=O+tNNm2czbxrCQD$XB*6T?U195)xNY>$VRUe6&z>V2zyJ1=>VI+4b0X+OPj4}UC) z<cgxrsC=grJQ+BPbsuZfup$c%Dmz`OKjDU0BxS{!W3Xm^5B_v;9LD>O#9b|?XrkJF zlxzJZoVYNbF8uC{v85Zq^;jdueV8p<Q<i~Y&rvjdStogYrCZ-sC#rLbD@mMtkiuqq zL%(P0Y%cAs<BVqT_Z5e6O~3&>@>34SuaAU+d*|u%u>{`UbQM<I^~1TF3@NkUL0q-3 z5aIP`DshVDch#fV(*VU+uUg1Ic^-d_Y?T<7Il`lS1rE@^PruxLk&agmCTD8$h{|y! zuY8P}?IW>e>|~+Ywt!kTri*fmyNSBq#`wfnUD~C{;98Gv>>7DO47SLSWe*P!gTI|4 zqjS5-y*QoC)MNN|(gR-N_JR|$3gCs-GORuB!;3B7N;k|HbnbG6rahUCQ)_x-$0i5v z{5K7AYA)fJt0UP?bp_k~-3uib){$F#9?2&Au}V%aYD@MP-G(V(<brtE`bvif%wJEn zeY#M67cHJHSffEr9u(X^i&sx5qRI++44S1|YWhMRyQs^9-cdJ9c)J3t#;g{czq}%q zGhx`P*Aqzo)g}&b)#R=%0&bsYhTcQ<*#2@C@LxVz9H6_G!)>zZl(IJQ*ZG|H${J^z zHIR1O5<&a?K1#c;%D<zA;`y2#!qaC`-td<>$|>!a*fkGCg`Y`c)24&eF1H6F6Y~U) z9t4d+UuouXf&Vl~@5vf2!n3OX1dk7)AT+JS`Xg}|Wbl~4S@OyMIW99u2q&k>2{?M; zDySM^VGSo0(aAo6gMSv#Tl>vWwbMcHo}x$#Hg}hty<f?E;#`vR>>}EFo<S$A7{RP9 zm$zhuLybaLTr+&CP&8r_P5e<PG+jyspIJvm?_Y1k?<@na_(aIGw8puqv22+u-TqyF z(lMI~aEMCdq0gKUR=gnpmLuYfl+nCXx;50KoW=R~#-NF=F160oqey2xJUGOX!V@n@ z9ArC^TdTkZ?I!HuGm%>Vo`9n6Ghz8kBX-a~DvS+khnzz%pndXjHv3cy_22hkp|nRd zYIVa-vVXMu*)y<PoiFxF=|eZ28;Jh(l+ANso+0&mc1bP(jSe+yKd&`V^dJ!F?M~WT zDUU~{Yf87;K+IbDSmMmQAyuhM+Viy>R}Pqoo~P!@f;JY5Q|&{kW8xH;HLovQo_3?g z__$KJ%tlz<)P>A{9Kdd&^4z}Vv(T`r2%0T=^UOE8+#|q@gWM-kX1E&<+3rQ|RljIu zm%dle^Ll<6rNY+bHaK;r8L8dz7RsKgz@eaO)}Q+bRh*gyqkXMlw$%*QU#g^ajRQHr zd=yyBXc1KmoCHssV%pI*6@G^-Lr<m4m_IIF9HM*)A5S{Z4ymzlu{sUP2Uha=4Sk_} z^HE;W*&Paz$k8(#ZAyypnPV$hNG=LJSrlJ;Wsdhc<w2cCiD10;HJCYE5zI?xz>R%9 zv2DOAu8Wbpj-lTnr|c(u3(A76!=92xkpsSR8w|y(H{eEi0*=2-L1*`VUV~R4)bKTF z1iX>`@EXr46M}^AcXwm=wHvtYK@-}|aK@dwuV_yvbNo6;8E0(lhrZ38bZg*iusWxL zS`l(Q;=n{Sd8W*<K2z~V?nM5b&>K&U3Fq~#wKRL<0c_hm1QG|jqi&YuUb5VQBl>l- z35$>6#QOQ@^mPn`$FIeOTRqV<qE&3^ddu3h*+lBFPG>3`hWqN&&{6go_=^cTYV;Md z?_J=7m+X1%y&~RxT-9d9d3{P;a+&rQUS=PsJ!0#_REZ6vj@8<|`0jvjg64ui3Y5H? zHI>pGP~n{9boeYh?L7)_+!=!tjE1w^tk}}>sss4u`#NFJwR8L^Q`5$6KtAt$JVpH8 zXoPd59gN3{R4(s0j|Vjh@tjXG2Cc3Wn$~`#<~V<x>^2&Lgnkm|<EN<kIbVF1)*0_z z?1`!??o&>>F=pmU4BvsT!~r}6AYEc*eY=PcEd=UtyTo?S`eF95zTk8_hpBWn<ZK$j zZ8m8_!J;9cR3Uk^^UsM1Jt8?&;`d$X>A*D805^522d$k=cx2K8s*ca#%Jre#7;TI% z!zN<FetDbr0h=-C+9<fI_k_av1@!vU4ZX)L;r4)R==;`^Ek1mN%7H!ki0@3!v|7oe zRtDn6NI2K|DHzlmgZ?5{Y*_d}ER=Sv-K3n}xo(j({L+2OR~U{xPngi=5fRw)%tc;t zxesO?c!>4YYp`Z*C~vxQTzGlMh&OoGQ^kx;e8v1Pc$@6S;UV2|6^yfS^G@UDy)VTL zCI)0<6vAqsM?*(y5?@Q|1S5S@VBJfJ<D@$u<I9<fzs(jruQUpJeMX`7vscz(`{mek zyf#ldsEJlLbZkZsSI3f96)-c9V9DDIT2m~Cqb$5IZIKTBhR(dHGDG}m90-j+8mP^z z8?SPak*%C74qmUsmw)JE_LtX8%fiGKjpwq*t2<+z&jYGUI#zna$el-;4Ma!H^N=9R z6g9S03C;!*FYdUtctpDes-ri-o2p|pZp%lweWO+Eb>fMvHe(2yZI2KK=&dEknTw&< zz}d9FZ74qJWFa}6!Z2}bGB?y(vdIDgyCoLl**}8-Y<^gM@za+6&k-EF+Y$Foc*FJw z8tB6d8Pvq<*o<mDhHklQSpR?>ZFJS=#0|Fp-$_@xd7d?wZ>QyL`RvkBN^0&yp*FaQ z68jDKKZ?%$uco&P!<8gSk|dduq*7@hMV-CY5t0z1q)0MP$&@+GsHBo4l_Vi#4t4fg zQ8I^AA~KT@;v127zyE-bA3FPap0)1#y6D-QNDL^IczmvsE6IHl{u}Z`xOKmsp!CH7 z0}pK!V%8=~8G3v6w(rjx6@!sSUq-c0b{uaTPfF`o%918L$3kOmnUB;(dsrdywTsQz zRC_ztwAKiR^}@MbeG|#U?tpxWI`}H~VO__asJ!f+P&;G^{~B|bavD<6y|=SaHO~yg zM)l*-Bh^v&lEfAna0E(JK7pQr3@c56UFxl&)0jk_mU@eP)ZWm_CHbt~<&<p0I)6|< zuS4%uXW>qZ|7e=WO}?g-0}}=@N0g4|MG0YosY5K?)mVsp{SCdntIX3BBgwvQB&Bv) ziAps-pdMwxMqj(Y>j7o(?Os<**?xu+E<TY(PF#jg^Cz)ksk5wY*+T4nem-cnKTAnQ zj-({Z!BB%U;<ltbxs!hy*M_!-f?rd)c|bN;k4h)UJ&ycq<P2!=@gmJ1Qg896fTn{- z3ax&J*}&Qw8owL?ZRftM=vWN7&W(UNzP$RBC2qMECs+uL0?g1A*WUUjs4mKefxhXO z|G|dp%<jYMg7fe!T?H*ubKqRvb1|!f8^~0Gu+K<M4wUlcSMo>UnbYGbrb-PpjQ&8x znx5pF>J7&0bHphz0y>xu5$56vI+!EXvG47{MPoOj-obWgQsBYQ)AYE<G9!Ew8V{>K z3=sNey`-S>d4LIjV7GZVxlglU)&HU}r9&p+{zSI7lsHB{=kda#tE_)>wQxu`9Ibu+ z2+y{T<L)7b^3|OS;E?iPIC>ShoBtOm3+Ti7Lz6(`|BlY$QgFF37mpU7MVoZ#O+4}s z!P(9j9G5|%Y0ry?gtx=Dojkd3v>A;tA0c(n-f`iT>!f743!fZF#HB~}p!()@Vw-(7 z)z6KjEh=>+e{ukI9m_c4+*!d)`yq6#JI-O!z9+_ciNuzZ+=Lr$llm)(*CE|qt%GD_ zo}b6xK91+uKHIoLyAUoY@8uPfUU1X>)f}wzi0pk&;Nn4}vG=_D=ySDHsFE@b8rzqE z%l5f^axl}ch#sWBJ&UWv9w=L<jB{qE(dVLN9N5+wO^ZTV-losW%d=q7k9}+tl);4o zo5kBk(YSu~ZrWei9~G08sjaV!t@QQ4WUS<^nx!wQ1TKZ$#RuVg$RRYkcNHFJ$Kdq! z_PlAE6_%gU#JKM#c*^q$7!&y!>)Kt$p{3Vg>8Lt5b1D;c-|ZCC%zshC)nGicFAf%s z8b%FiZ{WL=DNERA{;g(?e@B*5NJ|z!Q$B^Rt>>WkrV^0$D;OhJ70RDnkUiQzn(daS z<BreWz`DK^dz_fW{d;6_$?VH?=fM(r(Y?NyWP28^H0tP=MHF2SwQ1^x&T{9<22O7_ z!0qi#>GF~bqDJ5OFuy0^j;Lcot$Ht>aA=>D!Tu<I7*fmyi`|3^$%rAwSA@ak{^0+h zqhjW9seh|G17JyD@g`LiH+<ZQJDj~>Z}MfTvFV1tE5`A3ya20qZbsuJ7pas6V&7&d zALBG$u+Y5;-Os60(se2KsId{sj-KX<#J<9z^j)w^u*Lw(572FBf)MDpQC>T56DM|c z#)r8}xP1CjR9_;Ujm_uT(=>!Dm}RtGlmB)P<%z{_>Dz{Q-0fe(H%fjA8;xVJ{?#@x zUvDA>3l^}^uf7PyQV+MC3#VCz!zq)CRP|^Lz3kqXWa&C3=`OK6dfpfe8f-w7YfkVE z>G1ab>m~Ve<3&fkD$rB05*L=m$$sC}q%-TxsK`r~PAt2`Md>Q6T0Vyt_-2#&`O&oO zP8uxl8AloYj=&B}$!VNZ#2yky<FA$>`w!0LHv_hT;WcMj{pImsb%AiJ{dRItO6SQ- zlTqi#I=q>)1@5=czy{lk{PUsYFWG;Merva9A-4y$?`+1$7N$_nj$5?owhLAL*^lzQ zK16e~o!dspC2#yyD97zsDRltqdk3)Ep<GhB<_88d*Mri$BlyK<0)^G5z>kv-kUlgT zl%|<te4rYbFX_hLUY(>VFHF#;zX4E11TB|eg!z*TVb1#FJjZScD@nY5*Fm=wPxs`Y zEX)Y&ryds;CLLnWoMLd2m@zX}Kc{=TaWo^Z3fxwwk^a^P<fyK|j|~#nI>s8;1gpaN zl!-hrvK-!&^yLx0dN8UfmX%(}o#(z&Dsd{_g~mBc!12T&TslWjE}LbKBiHR=P0w=j z*9|YWI@E&>XjtKZ?~ziDXepe#o<lqS+l3w9@5Z4@XQaO1Htu1zgH=myG4bCZt~Q>6 z8?)5e%jqVS{D`8QCKsOBP964^-Ur<&*Fd;G8-I0=!)WfrlOhh1@04um+Ylhm{1waA z7mjhIS15i9@RR1^n!KXRWhxBt<f5mo!X}v(SN+Z7qg`CF(lL^^Ot(W{?YUs$G?{(( zG1h%F#30>F@EGNeDbn}-FjQh~FC}anQj2-N$HKP7SGnOxF1qiRgR`)fvwDZh3O_ZA zL8UKb-i~LWIl2QsPd|=A&RlGZ?1uHVmON$BTz<4DnmZr+1?itAVD0H@vFH397~!)D zjS}8a(xNKP`)?_Glti%c;<I$bwV1-sXqL#d8tLojGP->BIYre6)8Y;Vs6V132Ts<a zyD#6+`|oqGY5Yiv`RT(d$45cl?^McqRR!Zi_Hn=Vqww~D|7cl890fltgYQF?XiJ2g zZ+*EfM2(B#*w>akjzzxx?irWdI0O$@e}$^t!(83%6lMkP#`&wyNuHHhp+?GuhiOQi zhmMjHaCRvc=&5jq+7h<DVd3oF@R54l9!1gjR`R$(ZNmOPp7i}q53HE>79wyWk9la$ zo2D9xzBe*iu{9XqdtQQp>z|;@UL|}ny*t)-3xb-bzlG$hSwhYYiS^ZV1XY!MDLSY( zytbK%*3aZZx#dH_!t*e_3+as8*LKC2W%Xon+=XfydQfNY3tTnVlrKMYrGls4d|Y!C z7IvRb5AVDrgS#s1K4Bi8xHA#2F3_P!o$X}!Jr@<{R&e;KJTU1<q%*|;D;#Xa@(U)E zzNia#*(c`{b$j^l+coU8;skWp)@0X=NSs)|4_yOdu<E`!ZMEA)8;mBS&f0Ve`OpJ( zlr(VXW5n)*lELCt78_ou6N1Bjf_{5Vc<@kzzN*IKb^92aHRTiyx^;t0dn`ev^4VaO z@_-Y5JIfZg_C)_uWh^*XDr&_H<)O8aLetbwl<N~kbmB1m)LDbt?>ghK$)UXMv;liw zyDDs%w*&NA_jBE|a8z@9O#V948MN(q!Gq^8VDUYC?Q<KNmQDbr9tVX=&yEm0B8&dZ zQ7SpO;hQ))Tb(P5tSL1%pH^;kKy#OLaqT~2o{$hBd6E@S(61L7Tx(`ygITEb<08hu zU{E@K5S?4Qvu=lQ7&T6ZHjV8IgI9X+Wy9x!s@)BqvptKp`j5j~@0-CtE*GvTBxh$% z`~S16An=qa*MBU+i8oF{)QeDhAN@%Y+TM~`%8$kzQlY{cRj8a&NHWWA^z-jEDyeux zi~l9ipNdc+#A6$b2{?;cSIqh3--~cyV+mCDEu&F!+0>$QmuR$x!k~5=hY3y$KL=5$ zQM;=@wo3bn6dg+LVTu{j{b7FXAUvm6Ein;)^Dl=&oZ90r^wV5{>UN{y?raC5qA>RM z(dNWnoxn}{H{`mDM8gITET}$<&!jUn@cU947ykigsodca$-VgTp&qzyvB*}+j$9X) z!ur?!Ab)qJkTva{5a@FeEgIzLWtK_GrxLkH!v>Y2wimrz{tn(|O76f@KgD+s3GQY% z;_Bn~Xy9R~*YULmLgZ3kNGpdfg;{g9`%VmMPJ~|fMKpXo8uCYl!@XUuoY~h0v-$<` z%io1U&hvTvt#Uc}Oxc4rlD8)%rwlCz&Or06nfy%h!OU~?#k7kt*qGLZe>>`fbNivF zJ!BLg3d+NxUl#n%H35BB`g4QNUaVTwz@grcrLT85Rt<N>`v*<%<=rkNFZOET!5#V7 z^lK;2E}M_xFR#G6bLkl2>xZ(;vAjlEgfD};(}8xY`Lx+844z|ypEdep`TY5~)Xzwf zSay<c9J|fSem3!@E&B4j9upu{_KenUs^rkNu3}4h4Qn4<0M}hNQt()U1*H?Hc1Q>Q zmE^~Uvu|=*-|L`0l)%epDxPi}!VlHMS?7c?>IAo=mr-ZAp{}pI?Dje?SR==wWm0#; zFPt~^$d~ropYW$V8hvgxqLSZczWZkZZI}G-%at@Syw?qAS@(o2-cRBMMk_E}%GJ1U zxgmNh*`utV0f$=NlAYhIiqqphQ|zJ^qz}`C*MD<(ic?>#cfU-|n8@Edwd1$j_pr9# zO)<7-5V$%-3C$XlX-i+}d@<IOepjk=*6f+&jQS>2U24N0nUi>z<Zk&k#*K?Ue+RKu zj(1)Rlz)DejV<cEsYj#}uTC(+#$oC3Gwm2XFdL8h18=aQ?m9)@q+_I88p^eHd$~o` z2(1Io!OFHz@cLe|@P3n&$?$$m<#iRXKR*=BceIBs5<3Q_t%5Uq<S^gK8-tx|c=sHA zd|jp`A6=J+Q+h;kjOak0rJP!f+ZH;Pe313Sdr{*3|8Rwu4JIbL$!(YK=Ly@G{y2t0 z)4My|f6!ehoI8n621{?pr`2FMWDa%Cx{jys>hh=ix%5f1fLzPZL-MqG!EE+83JcQW zA6f#uwCE)-^!Otfb;uF|5;mZGQZwC3DTDZesaR8XM7G>ki*1kXqq6!WxSiBUUcEf| za)E|)W(DGFiI>ja7s1QEPs!V<M~Ff#oNbQ`Amhwe60`O-8FvlkPi6_Ia-<`ATpbAW zKN7@UMl`p-2va=0Fm=fbA*${pU5mX8zb9)+d8R;4+IIkdd%PA>gOg!ZW+6;?7eTsI z1v@2{#GIl~?CZ3fvnScG)5ly`_0<h6#@~ec7dHfl!7DNMzpK1VQ*zzdN`JF@(TajB z1DxzUOuokM2)><gmkYY2Kv4J`uDIPw4M9>zq2&U*tXAXizfzc5raQ}eOa7{^i>Rjk zLKq#q92eNdlKj&n+W2QauDx%~PLHY~HqAup{iM>tH)+^nxQ^CHJd<*@xw!UdJ9&h? z#6i%tgPLE5#8Z}ysNMdlICDTZywKQ20mq*RhEkTwZEa`#SUq0a!AsnqydScA&8H-O zMHn{Q24mIYQ{u~9JC12^<d=b`v1M1Hj5>USWy2P6{<_X+HzErsdd-2v^LCiF<1?Im zm&6upY{6hkELTPKr<GO1xb}G(U;fyYO7!nT#p5LLrgV2bW-0LkJx;T3ib7OUcI9iu zTR9};r&tl$LhpkE@Us6D4u8FhV~uAE=^dN_T*l(tTgkBYlLg##w?&W5RWKlbGs@P# zB1<6#_U0eM#12{f=ldtIyYU*dYdix=liOt1kB{PpMbTKkxdV3Gd_q1xBb;ZgQ=<BU zPF&rzpJsVFbKx~@T9FxoV~-5vX*W0Eh3r+3QmMqHK3&-D?@B!R*_lr2ZG(WLEs)qM z2V0$OlreS?&hn3;6)P`OmmVEB`*$~xeO(TAua)G5=TgPHnd*>rd=8&XO2I=NB;K6! zE|gXT#U(0bxO{wHF8pH1!tO;dBW4bC^C$uP58XxUZ!>BB+Am<Lt%nz^kHW@$M_433 zNaMVYVUTG$nnHImVonoOUYQ4b{FQn8wZlTTrUKku$Ma9mXTsaaj;KF=kx+9#f&Blf zu|tZIJbHlCHS2Pe`)jnr)uUt3^imYxA8*G=N5au0%nSZFp5lMu{pI`1eo^oBuIMv( zH@hr9PVQ|}`OB(mD!0uASMT?vFLfpkUn|9+k>}9RQiQ7?k7MQVLBhUU)5&`A8@Mfu z<+Urj<Akww5OXPmU+^2zv`Z-%s71mapDlPrasaE(xXsNoJZb20JJwMAfQPNkM4eC3 z?1mQMn#6liD4xKS^=r8B?rj?DAI<^G`#|Lj3$gy@UFv2MNiiJ^;B(|hQct`Jn=E>9 zZPY#<()p>x`Bl)hAKP(h*eE<3J`Y!}jpgW@#<aCh52`+2EOZN2qp~d*g?oX)T=BIM z6#dlj!THzXM#;}wQky1TGV<k3rBi9evI=-RFbn2}NxQ_3DuVZEFT4apIOeJk#&_Js z(VsW4cgS{7eIHEj!=-QaYZ;|~e*n3;@u(ClQ~dm-4T`u)6tm?hYCO6G@2n+uNrX8L z$5edbdmj~_`oZ#d*}`w-cqn+$Mou^VY08G%kk~F#Yz_ZPboHRj{MUGP@l)e_^Aah* ztc^VUC$Zblvl1I(G{BB5#nWxe#0f)6B+s8C=iIY`MO*jb&wFoSi<IFrHr&RM)&1Gx zi94tlo65tEnNY=^9avudfX@BUfDy?vz;L0ZJfdqpx4gawEB+l28rK$)>wx28+TxuM z^eIL7UHyZ6yC-6v@<<`9v@6}*rN#0;PXyN=cWH~n(A%DD3!7in(9rQ8DdxBdYKk`O z@gxN1_4z=}xyGmxXbEkXRH!L<n(!t-3x5w&<zczkMK|RH)O*#5XLjESRVsdTqs5m( zdvz*Ser(8hzPu!L`)1jqr7iG&<2p>}v>)F_d&%?vSO_y;CPSLVVJQQB4z%?(aJr9z zl^x@u>F;y0d?u2P%^li#D35JwuR)0YF0Sx3!%a_hVQ&9kxbXa8(ZXOQ&0i_GuGgF3 zy??{tkA?%!^)|&UnYkirur9Qmi{N4C$;)G>U~8<7)bCiqdk?tai!5UdvC9&YKW-5R zEzY6qlk`z(#2kv9`<nbe=!y|z@<oTZ`GRGoKko_I4MqG)2$0^t>W*XBy<Hi6J}S*3 z2OnaqH>ddX`rqW;*@(xahEhW46j@U5A7nYJ9X{VO61wlL<I5U7aIVBJT9?|M{!Sl{ zm;YGvhB$p(^hJj+pBTapZdT;)9?Od~rOey99NKVx0U!N66O~Rkg8E}!;n-C<w|5ia z(GXYk+pdS#tSrg*)L=5Uv_Mx4RT$`Y19eIeYzBN1Z@=9k%o!6eZ2I0u?AyZw4L?M{ zAr~h)`NRwM2L?jm#C=r$&=P|JUFkm^OK!a0k&WHg;Q5z}c*_Spd=@qZQ&%;>p^v-y zx2g_i7cGSzwt?`yB8oRmm9pEvrx$Dd&Z20kt6X(45tHM}!Lvji_Xlq$ld+Sru=68& zU38x|yy?$rCr*%I#C|>?by?_Qi(=H-S=f2R9=yG;E558=%@$ww0U54WtloGZ)NUq2 zeY3w%wN7HWfA*p?rQ`ARbO#)KFAZUwDR0;^g=3vkalZF>NV1-dnzo_5KsOl-#vh`Y zS0&Cy)g@T5<1mc95CLCoJ+Ry-85Vj=3_|-}ICka<avZG8Pa}~%6`y(5fNXsI#04uZ z=x|z)B`+}B&I)UZ1=wGkTW2KlxdIz}rlZYj6HY_I`5g*R-#X!@MgnSVy#iW#?Qz5K z22dJY3m@9TaQ>Hn!uW)8)Uz3f6Xr(on8p{_^GYdnvytAIXBSY7L!02H@>Bd=z6C?I zEfsrStDs%Sfw*Xr34C6%pKcWn;ND+Ha!|@fm}sqm{ykq7=TxMl|GsgUMS=X&E|Qge z_c@pRv*oFgkIBGv9@&R=EK$r}#w3_gQ?6K?Z{3xOZIkhW=U3`jbCJp{736cW7XEJa zV4qR9#F(RJp~_YU1B?&Q;+8|iXO2Ln`7gnCWeG)1&&OF~$Km}M?P*4n8e86KCci#u zbk3%8Np?yR-}vtz)b$yR<%M4;`&bm_Nx8Ki7JGQef71NIvn$pW?cyb!iqUC^#OZ%H zj0ado(l-Y+n6^a;-N%1c1U=l&#-ZtA?~+|YV`>yG4th-?`{L<a?L<(vY@-m>f1-Tu zRP>nkRBYUxfVz3Ng{F|H0u3&eMK>)XJ1284K2ivpXQce9{|T|%xA&6k!c4Km_Ny4% zNuTX!nzGWWH%{6)M%Xbhf!1LsRyneRW;M>^E=S|I@bWxygiTj|_j5lae)JG$t-K}_ z&fLy_he%%e>wV!y+YW#YSH-ff0?yfQ&WR50q$>5+YZ|i1zN;1{H@p&r<T!qtIDju_ z+HlDINPfOb6$?HnNb$xDWA^Cdohm7FdstO=Y}GcJF>0L<xDM%t*8}i>eNr&pGEv+# ze=xn8DPzOdOA2MjwIn=WN~`R2@JXIC-W-rbv1(6+?8JUx@9mDx3*ul&?ps=V=s9^l zNrA%s25{kM7rb1PLlqjf;JNV}JzbkYuMLLr#}^$iMlVPa{AdH~y)57nK}|&aUB&!& zV>rR<0Csfg%1{3!ag@qpI(U}_w{0IWbkS3|of8aMqx5A(lS<*+B8ILy&v}D)nGkDs z2?|!#z~V4-s(3dTH##U|hh*m8A;24}_kwx(WNh7>!&&-%uzvY8%%5XTw)6U6Q@dUS zLmkEDqgjIKnGCV&%M^Co*aE*l@8PV78xXYZH5j$GfHJ>bVBT{v*551>=*Lj%9A(XV zjYrU_VG}qwG*i{nyTUf;!5%t=aHjRFV4bvz63evsqW3MZRdt2>q*C&cJU87J=0Wb` z-Z;r-H<mOO(!?%?s8utVjH1hh7MGr4UUaT7BH9HP22>K;cVYG8!&tFP_iACW4j<Vz zn5NFY2_sKU<DUz9;<mXRaawu?zx{5D{NV_wf7Za?(tSC|HXR}+m=NqfL*quogM-0% z$j;hEe-_S^b-KPC6>dZErs*(>S3Qhg76-}lj0YF!F2=3-i}-EdR%m|g#jn9z2z|Lp zQCltbOWP-5cfT$eQ*Q}Tb8<Mn#u+Ww7gFJy&A2YyoNl5ruI=oL-*>yC+OTkroIi-d zR5dX<s~*n0m)K3U+I)ugf?HEG$ilj!gRYKf_jn>7yWq)x`i@7#uZ0qGqXWB@Sn$OW z&g}GTKW+%0$a8mBpx^X(9RD+%bz6I&`haz^ldVy3V%>14G4#gh>cwDx!kW8k`=HUE zCQ44<iPo_z#LmNp;=jcayl;sKUXOnR`qPd=$Ho%4`pccq#;V~go`M!jT12_lL0HoH zC|c%LfoZJ`=C%X+!M)KxeW>E`)o<ioXpT7@%!K4moyEphM{F7+^{N-_6<&UnvPKhY zx&H4i6e152eCkel`UxER=bdxL&HG#&*8rFMR#WIRH~tYZ06qMo$?b7ASB<#K8`Qes z>3K~c!3-2GjjO0WG?{<Q*@u-DKjD3~3C}jQmA^BH=Bn!>XjAz;A^61@nEdS+HSF98 zGX{iW;vpl1?uGE=1i{ZtJDisMnq<?u!kONFw6vuGX6_h|O0ubf@AV^4Q1jMVZ$^J| z7Oz2y{u{9F(kSNrRh5rv>xARy%UElp6T+JL#l4Sq<%)w3WNW+jlDuelY1YVh6r?-^ zO|4>S!^_Fs$ceac=6+sna{yJ>JL8gR2{>qq5!tVvM5a2<!lfhc!L=a}x+Xuz-0NS^ zd!>Vz=lg+9&C|#2p=l6y`z&oQpM()zOjzsU8);9mjomaB@|{ttRGmB$-;WU?=FvH^ zFrt-QcWgo}$3%W`vIb7J?tzlm6S$@G01g;G5<OC9L9a_yuw<bY7rxI^L}ylF0U4n7 zelMBojZyq^({AyZ`(45F-wjGkP~p4nwdAMgT!+5lrt;4^X1rVNo)EFxn}W~m<6)`p z@ZjkW%J)A_Y5k+YVATr>D|1FyD+f3g8^fWQFP#138fAe4DyhkSyCSP;75^Er1(GJ| z$q(*-25yhcaZ#7qm|+)AbK`sApGSj5%|$x}xBVOWem|KsC+vrlrettCrD`chrUR+1 z3$eKH5y_^`fQ!B_*!#1)Sa53#&1sR`Crv%rc(aaZJ3E2QrTbvQ$qv}*$1un&k3uWi zWiat^#Cc;n;=F%WsJkwLGAG7U|A`tn>$W;~d1Zq0|0N4vYFlaCr((#vl1LSiz463Y zHQt(g3jM}6(iB@GmfbN&gMVod(O3%?7JP@hC$zE8vk2ZXv=|=D3}u&ZsxU3o6P+f@ z<aqr)e#+a$FFSNVrLgP#Gr6xcho4Om*Di2Dj0W%4T*3V(E~1Gy{h+F-3uN|Aq^ql5 zL4=JGM_ri5c4Y&xFk=L#uG}Yfn)MO#LR}!_{BFG4CkhNqj<S<RG5nnN9`i!eg_@O_ zg7<n&^7vPQAA8PZRVsjc8WH>@Ae;@B^v8ua9zf3*>)5?~C9mmZNwE*^f=Z($E*{xO zoId|KI0lALiYn2nt^;tcP9`c9pDUW$Z3UYbb>w)BNW9`;0Eh3X<IqbI)9}G!ZhLZ) z)~ZPi&*uXvD{?Q#b1zOGV@LV6LD<p0gp@v}fPTbMG3mzyR<(>obB#Uh@AQEB1WNvq z`t#5^x)KaxUQt6elRR($6d!&I4(3BK^o}ErSmy}m%A;{`=`0L(3diQ0k92-k4=noW z311i8BUe3Dc&8^h?baCyhptAlj<OajZD}obnihx`cixiEE_32r=R329#(PS2Hx+75 z4-x*vnQ-|-AAFMflWOB)amrv@oPYc^)h?aHTdvA*#OnsAk9aP2@=?Jt6Hi0Mp@($- zwKe8dG|^Bx33`14NvS>!T&F)1t{520V}g$giQ`ra31e4t<bpUXpWYz8{Q4i%uHH%N zPflS*!2%BLe1#@fycK$?6jH|plC!YJ5g%{rA++nz3J(G#@5D=6%)9ajCP&|=GTMW+ zBL`!0<poglZxIvy;=pA>0qtCB3xx_1+BvClOrV{_2r89LHu(j2qbg~>ek@Je_Z)S$ zcZc$aD>#4A2N<HY3b#ujhnxOy=yv~T9Mq6abCZ);ZQ@{g`a>U~=yn3!nY4{(B&5Ok z+%fES!W`@>B#))(m*U>Grg(APQQR`~1U^5JBIUOuvHs)@(tBbLjX{n$U||(`T5kil z375d%{V>1FiKiLvE_m<96L8BYz_1Z}L9KZ&7tU9c&RR<z_|gHtb+N(v&7tB`r()W0 zUAj+yhyk^VMeLvS5OUL(@FwGjV(X<?3Qp@!o&&nE#g_Y&n}}@PKLQp+ZR3e=k8y6v zLT(pmz~RHZFnNo_&V98X&CcK9nyyFa#JOHH)IFC%)E-goO1Thx&4z_@I+(u35TlxP zN#lklH@zGtDlMDMt>Yu<kKY>zNgDxSt0r;K{9s|!Xfs@~b{u!<>V(yY^EiI{G&ZyD zhW0aoVqWj1!U6x_M9)@8)0VQdd|NPADFegVLBd+|wYab+(S$Mf>{8Pcjb|Rg0E-4} z)Km!F&f0^|uf^yw+8lbME~DJdyHQ_hr=oa>jJ59%;<F>9eS~Em&(ybp;x)7A+VPD% zm`l-6=b5vX#Yo(+BS};$|2HyfuXMHy4JNDbFm%z+lr7zfxcbg{a$WI~PW5G4rHk_X zPFFxY9)U~klzHtYU5NQ~N#SvNl3eB$$*t)xp*1}c++R(_w;w&BA;}P%HQG_mF=YQ^ z-e_QWjAEs^t&-CH;@?x|LTbA^vL9Yyv~A8qapk;H;a=87A@j^Va1pCz<DL{sS+tQf z@zy@cncyc*VKb?FZi_GUL^ypSkw$pf!}J+9acW!}y|~u}gHj});jFcACov67SNpK5 zjkREMaVXr{s)f5Yj>8N6Bd|ryOs-H)A<ZPoQIuuIR-Pl#anCqBs`r5X<Ber>;5+4| zuHlf|wW6+$<ls%S!-3UNT;UZD^#c}>agqhjYL@Pb2mA3o<B7PVNfXnANz}9>g1iF9 zqGktwaq@-1Wcd34M;wmfM#Bg+On67bCamL{pFMGg9-zw=P1>~auHu+OwZy>~i1SQW zl6tpyr1ame;<`<JB;J{i?AXMiY;{rzZ_PXd6(`LEFdE2K`&6(k^&q#DS8@D=NR|&j zM~UBM{4+C|Lg#FN81pV-kl{WId#4IxrWCOMGjA!Er7O;h3ZaI5ZrIn+pS^2Ofzk*w zHmur9@~P_lJ}Ht*Mm&*rmuE!v+%l?Z)5YN2ja1XFP8_c?m$uCK2Te~p;G)!xxWVcZ zz0qe_9PEHp|H=8x##{JkRd4EQ+$vNq?I^~yn2HI9;)DxFJ7D>1eOkTy1NpqOf`z|* z#ML;JI(qwIuX*kHcBH^>XPa^4*%SE8Lh}1<vq9B8x~QkA#y_T;aLrUd@n?GtSly&f zz1OC3`l{VRs>vWxXP+`_);Z(Z(*IyZK@2p8499V1_vqojm3Ss6ke|P*rg?eOxaGdC zklT40zfAJSgx_bu-7gDb)*MAmyLo7LWEqE?(;|msX@X&kwk&MK7|`xjCd_Io5LIR? z@$V05km#?Aw!336C}ttQtaj$E`$nUMmgHm%w!x(b$ML|ydjVFgrZB~Dj(0bMn@i4v zQ-~$KT<C^;;xS|?It#16=RlIqN9q;PlZ$&=^Gx9!NA#Y9-nH{F{||7#SM~IGwiWlu z-%F<7RXOo@G+V8_0_!unbK&wqV)M57^f%Or2A<i3PtP5L&UIUG^}vHd?@dGSLV?8n zzq>>B(WDr!-WiU0X}a9D@H4JIs*BBoBiJCfjm|8Rf%))4(%I*Th9Rx8sYBMH(v;Z> zn;91%;6ymLJWHf=D<v1=KqKt`Yb3fW&w!TRrP46R3hnv~;_rty^6S^%X-N5UE<6+o zCT2Uy<Dq)V$HhB&W<MidR``Stj!K2Hu?bjXF8MEvzfs>e@iZq>2|xKXka3r@3jG~} z1$%oB*ww)vg7g~6!O;ef<XFQRO(ojYYc0<5Rlwp68XO?y6FRuZaFr}o6r9g--&@hF zIYkA<6}HklGlqY)%ft&mx8hM}d;Wg*55z2v#;S*>cyVF`{)=3V(}zcJ#PfcfHgdTb zCS_6AIy|KrD`)VQmyUE}@@%l_laFKm_=&v>&0+e7ViCfADGE~hNvzL#7(4nHnLn9| z(ck(&eVH<<M~4XU9}UT6V;i;q=?y`)NobO5NSkJ#20CP*5XTPW&|kyF1zkt;{;j<c zuPR|oNHE;?$r4UW{$0-5%sLnR_(jJ!3aI}~vvj4;?tjlk^G$Z-Yn#G@_NcOF?PM_B zB2xr9PNUKZi!t|v9=m3JfZ|`)JpSWCy1RHCc%5zsDKFi4cl}6~T^=R%8<w)GMV6Go zE1~#<65s1fZ&cge4-3zJ6AV+7pihw=CjaoJ&wg5{`F0c;K3)#lW6z70haA{@c~{Vy z^i1@9-%fCyF-~StGX`7J+Eb0&Nq~ekGMjO(pwgTJ<}ipC1@vRPw}?vBy#&AI?eJQe zz_nJj;<;DDSikx`Y24|{A-D(vX5E6h6Wpo9ek!;1XwSKwAH$rD)A>={4fMI=z#lJX z@M@Dj{QcBrcy3vZM{W<r)6366)6*V`l>aKgaL{3}3i`y}%6e3Id#l*_j+9^h8z@`3 zOxkZRdnwx9+Q%xR4LP9p2y`B=j7f*@a*OjD*#5}_eX~aM_JcC~psdV4+<ai!cX#-6 zHJn_`fz`ix$ZlKRW~GQGSx{yfz|uY#`Og`2%gwO)X*TTZDTh#towPVN4j<QPLtoi- zF>Gon<c-f`KR;<cQPfG1J!c%5zq~-z)EEBjJw*Zk>=>@exGd>|pe;(X!>}AY0`tkW z&k~H7IF7!xOc3h#Y!wO;ufwxGfzWeTAXn{L%eVano}FrVRdd5|ejE0J9A<41T~3aW z{CuYPH1aaY#k+i9x(Wu#-$Fn|5T+ikg)@K6aO0jWtUacR9;_b$l{;FcS#TOn^pSR+ zjs+MyxKJ>dqsm`n&!g|~UEFt94jUdt3|lvwU32EaoXLxM#Ct99T|HQEI;)KhKi%<C zepl?YbOeR#?dNWBKS8e6DD*CfhaU^uVL|P6;m6RG*y-U5XqOqnVP*+nalrwr3Qob! z6v_W}WD4g-)`Pj)M+qX?4cijcP}ka()%}h6dS#gO|M4gFh|M(ao&lej@5mMQ37E1Z zkP}r8;S1YQIA;F=-lQFjhr{+mD3+s9x4!&vNEmv|4OJ}FHD+`1Fh=R?u!sEx^!;;% zj=Y_SLvyQHZ7*P~<qvRgUklXxBgk)h@UpB9*k$f#(W=>(Dq>`kvSJ$^cSwZvq8T{u z)<E(!-i-G&I>Lm*61zH1`aMY=ETvcL6?Y!DM~9qHVW;a(3fef7t7d*@+ac%BG_yfw z@cff_<VzW=-pLYn+g0<4*e|dyLx&|{y)dZV6VSExC(j<oIa29Ajvb4bdgL=uFBMt4 zmE*|AO1)(8^yyeTAPwRc{vzeVDe||YLpV9e2uwy72=U(*QI%#GTb&z;Rz4H3=+kfv z+T5OWOkN6QQ)UCSY!`p(1V}!C&fIcMM{(to9vZ6}L)K+Im?&jtH*~o|0mp`8tGhGF zJYSR7sRmT;)DaD=y71)V+rh=F9Iiau#PyS(D2&fU@h<6J8d5xmZYs3UzhkaqN}Cs7 z4Ua^lo!*?ZaX%V3Pr#bBDQH^uN|Zh84WTD9747~?zmbY?DE##ri?&_C;mhYr?;tJM zHEkni80CWD@4qyqU>B~=_Tr)hQ8uk)lEhw!<)*v_u`OT)23ZG!s=+;YqP2*p4d0C! zy(Vx_RwgVxuZ=C+r-|_Qpy)kXTQv8$EU2fcV)+6~e*dafkY6iD`-5GvY^fHf#;LGv zPLlA`aVW}Pcyh}?FY25A7X!m>G2*+m{Dz+&o7>K!f{(*sy<#(0x=a*QdxVftS2?R+ z3x%>1e@M#hVoT{s7?T-6c~0FRqK}LCFRDBDEzl)X!{@Z`?HA~EQeB?2`-f0A#2V#K z=HqmgBjj1r9c#BOz(*C{?EcZ1tNUGq#<|M4tXCp$mpo+`p1R|p&yz66O+ilixv=1s za*5KZr$u$y+bQ?VDxR$3MvAjBg8uyWEK_9Q{O(SuxPFmB^(Ug`igp;N<%5Hc>S0#0 zv_A>RCiUW;;*$X@A@q{EOj&ybep4@{waqP}(3TIK;>}3izXY1f%(<XA0(~lHviZQD z6kRv~XJk)@Cl!V`>##Jh-!uw0cF$!cca!4!90N8z*Cva8y$qkO66D`MoWkiz;jDg7 zU#9zFIahv45<K=LE9xc2%8T&xH1ByBr*G4vTh4djLUtZiN?oFOnFo4Ud{wwuhDo!1 zH*{GX$aaolV&RoFaIdfnkGgvVmCrcwz>5c1FMc4N*H@O`zUBpIA9=yjxle_PS@*GM zj+|HaLey}u=584;>G!-I_{?A|F8%w8t~GxpHN|D|{;0dqT5<??WDKOqA5T+eWCH7j z9~P8iqjC0FBmDEUBMw~P$q_@WgqxW+&_7ZX){fW><ttL*r}H{?eKVR09gVozd@5W0 z{YKGAllf=MR1U6pz=Q|AILK2=IQGDR?i=f{#jYW!PEW}s(U#u-_($142EwzA9%x$q zT^y%*fczg1A#10e5c}*mxEOn(+kOq$Iq@lOkxPyzD_@j#9!~KV+rZZ3733<7VVz7h zR1L}iA8B9I>CZ`4yDl+)q9euTs7jdh_JurqgB>@-r}Bp$&uENE9T=CVKuFXWt{?Lb zygkm7&G;dxaB7BcKF#E<ah1+pb;ae?JHYdv9nIdE1)Xj*LX*lj8YoJx+fnyu%(`Qc zF!8C_W*GzBcJ-tZO*?tA{Wih#SuY-TYZC{!DPfnkN^!|jRm_U6r#H6WF=5Ik)_2QS zI2iVYoF4r--6|PqNI2GP+A3ySsA9mVOXAB0UCd}}fT#D<$>NR~>dHmoQNlCO=s1Xv z)WwNf?{dfxlyUCuYOv7Or_d5D=Pa*u#rYK$cq_RhS5EFvhc-81M4a^Z(_MovKVL3f z9xxn_cF$ld$)S;ZJP37SR!FSNJ-pV#LhkycAD)?C2-g0ydGCxSn00FatD2B7X2eYx z9B~yc4w9qpi0#;%a1g~_`Jg!Hj<XtDNNw#Hw7St9gR;+(MV*sadg=if3l^N`WCZ@N zMxg9bmN01dRovk%amdtCSc&X-&BG#c{u6*#6OwSyW=niJxG(3msqyhg+aPzrS9;t% z3A26$^Y5O!sr`~c)ca=_TJ^`7KI~KBx*A=s8_-iI@!ZP$Uq|uQ)?hB0wwHHJ-ix{3 zD(H401M?1lVgu2Hr_Ve^2~+!X$+S>XivFy4*J~Kxz4!@2#Id+T$_3IkKXH|pEr=E- z{9;2bz4hDx4O5>($GII?-*Fo?ZOVte7S`PSYCI135yC6W9VG^Y2=!t8c>a*bbmQ_V zcv7<$I&R5FCq3yb+Gh=wA9CTHbQb*bPotMkKS=9x18BYQ#*LpCb!Ts+iUBWVBVy*G z!P^w5FwZ8d<lFdrccQq+PL&@>9^zaV9sV7e!nyDnH0@i(B_Z4RV{|bVO5aMoYva(c zXEd!2x-SlD@#dOS&BC?Q2hnhhy0g8K)az`VOmmKCuuI)3>gg6LhkadSlXpzOoC|V( zplwXP2Cu}WL$=AEWNzYPC38^kQ;m>vb2knid0(Ko-l*79LuISSu#1~7njQK^3+KG0 zBF{tOrWiNE^5bAAPNRrJ$Ki8m21IO*0=4Z&!RL0om}eUeDPb98C}kxxT#g9N@$YF( zcr<z&oEB)nXGQwYdqT$W``CSbGzBkql(Nfx_}k-2q+9+JCV1QOrL<!Z<a-RpUDd<~ z%ZFm(uWk6bV+Gm|EtIt8-(?BQ40&=dsn7aY@^yU8=KrG33h8-$N%#FoKB1~0?@fIu z(>?_?CM2=npuw0gu|!P$+92$%Dj&P7&VM=?V9m@ln102SY@MR$Q`}cr{MQ2d)uoU} zRWiS^-797DdZ2rezv%gPy2Mgn25;(Y@#d(Fw7PO9U7vlA?7}7f{ojR@I&wE1lGsvL zREF}Kx*x)!MIG3BZy+uVl00$4hLd2`o<Dm^9QeyAd@;R-KYx;Vrj_@|D&~uLtz#>B zoO6)&^P54Zcss_-9wD4rAIJqJZJ<8B4oX{cg{H4PP;uIpJ6y|#6vxrL`erxS%gX$q zZ4np#dqnycD`i<01Dvxv4TZ3@&y=htd12<Sq}W<bY@1sEKikG&`QW{Dduw~>bGZ|g zOg%+&GY;ZyeRpbiV!u$a?~$03J%IlDOJ}dD2@HSWPt8Mq(NNb@@U{0?(tEw18s9F) zzEbAvuGdeBcQod(*_Y6M$|Ro9Ed(D<Qb&y#KOR(EOuEi`;`4D=MCvn}G+av<$Ik)n zbw6OZ$vskhS%!bkX9%l*|9~YoaxwnANd68JaF^Fc9@;B{mX+@22@4O=r_mDg(_jh~ zzB~=b*Z&nvzK3F#Mv!zLUBu7-7AaOgJSpU>rHE{}8DtMc=>KoF7#Ly3*2x)Ee%%-| z_GDw)u)CypU_Sf$1fuJ>$>jIR4}1!D@!&lVz(_uebP@)#v2HMZIJXtng}tXSO(Rje zs{j)f3E*t?27KIH`CF$5&e!}dwo32j+$JZSo!<>}gUtEmv|`Cm_KvPC4x@<Eo%zkX z9-Jmsgb#eyW23GL${%z}xXh`Pzh}MVx|G~)NBq$tdLJ|$h{QRIcj6e=HqlY70@DtU zz#o1u;ej(_^~awuCMA-4>c&u=${OfD?*oNZ=%P)LGWOrx5o=xsi+dA}g7^B19C|R0 z&e-0jRZ(-W?e}Rode9zLy*h?^^Ge{`$y(C>s?M+W6p&@lm7INP8O+aFAmzTlu>JB~ z998_2BA;ro<QTvJ+i=V)>P?lkYpHgg)T>wTfa7nf!1<EJ!s^n8P+`~}57=B1wp3lA z$IoqWd31#Ea(uDip@_w)?F%3`u@j$^awsEKr*ggLam9rYJ8nDhi@bFXfXez*nEi1H zi*q+(--!$Gv$ZnouWyrS21R3|Q2{Uf;)xq8gYe<1K=y60XM=;9;6M5yxYYC$0*6T) zv;`(`Y`?@84mgbMk9?+Uat|<N4RTD-g>3!hyxztZa}4`%Sl2P=;_z7DlR8i|u0R-c zU!+SVZz;Mm7lNd&NyX-)f<^T=2(mI&Y!hSI%4|IZEHL8Z2ijxPvNqX!MUfc4Gz{#o zR?vSJPO?+MM2^!KM0I~;Jny&`>c4RpEiPG7sl@FnS!T^TPaEl^bFNTpy@!5JT`uv< z18M$)GmwxroFzjGRd_#v8FsB=ytNBk>I~$JG98XwA?>2pmOw|_Z{m~Uc9>n=7jp(Z zg#qi_;F$4gNZQd0$G`8uMV*g>X_qr%VN#uf+6@vS69U-qSg<0>HjO;9Pbkv26hK%X z8?-+(lyb_7Abx9SP%q4+db$c;2UbYC=?nB*+9hcxpe!}=F|^r)a+7-=MM!;*uy6C| zP^k(p&ie=tQeMK^tg#U7V8-5Y|LCGL7>@CZ=RfCf;ffz!I6P)QJNQ{~SCu`G(*F!@ z^I8e8dm1!5#)<wzC*bM{TR_jZb4g;{ObYE$AUszaNQyPBk~5?Lht2vWxSZR_3p4Y` z-)~&;-tAQ|<(^WB=I3ts>7hCXI(B83X)mB=pb|eDZY!*I)`if88;XVuHRD~1_u|s; zZ}{@=cI=p(3$g7Fg1w;&)DCNeHKqN~=8QF*zn@CydM%TBP-+TQtL5}#Wf=5m_mutP z)SZ<QI?E26pA7?_7E){7bEuv+h#mHv5#1&Zk{k|EV72B2M6_!Kn%7?TNM$dU1WToj z8OF~3)m5@9w{jut<Wt!TOLwOKhOnD~CpUD)tII2=@iF6zWVWQ3CVBVc_Y*6nz4jhB zn{bnVkLUw+YNwzee>4s~{Q%r1+F*+I9{v+}lr+K&;isaTl(RZ4j*j+%1mjA~`=>5C zNxXy=9aAvkQx@BP7|*sQKVjyjZXCKK*?E7H4;w1qhYgaq<*9WSG?Dn#jaHrUv%-Ot zzn<WwC$)veA5Xw7|4m@*+Y4XE9wNVx-Kg|PgWPo6bJnSgpz}!$FW-rQ8xnWO_KOb} zjy)%IDEb5YmqtSKI3skH+3-rAe(ZTS6Z5(+rT)^)bZMM2r?ofZon!aovVkLb%hVH? z?PiBocd~eK^&DKIcUC%wy2}6Sxs&Zf{jtVcSqRyEmKIi?#gm@x+08u;Gwx)I4(kF? zTgrtTdbv(|_u9d}!}FjP?!px3?(BDOFj}6Pz^PRvd><EzZ!QMn=O;$={LNoTU&>;q z^=oj?nNRRXenNCQau&|TMo=%Q!*6vx6(+rFPpMb*WV5eJ>|`k$R@N;L%O`)3jcMmi zGXpZ%w51vrAKby+Dtkger*ZtYp$?3!%prANnz-pxEDwEA&6`6%z{OEVz~OgKYPLEn zYQ9n_S^2LkUUt?-ujbxT*WFv*HTNi=lin=ZU)0zm_pBJu9Lv62rHseH0jM?51?fOn zg}?e~NZGIz?DMzLF@rM@z4kWE7_lGH^X~}l9(F{}+k)h>alp8icxriPj`6P~uUC(C zG{Uk8;pr`K>Nt+C)GUIXZ6D$I*!{fC)(bLb&1a9MV#PxD58{}1!=Tdog5dRfCHa?^ zW4p`i*st{)7+t*#UA~S)rE!fy-}G#-RK5ofe2p>iW{kMy^JPqRj>VMaKZHGZ&2VDD zVkzs<R6H+7a@O|Thy6-&xGm!WY>=sN+be-RjCaFhZ$mU*-cIm8(gmmQp2Pn4CgQw7 zj(l?bc=#{%2FMHgg3mN_vVEONMJeuLv)mSf-gV?q`v`^M*LbwrJ_2edc=GSze<{&& zDQvncV6!-yn=joJQ*S8CKMW7RtevLvUCy&vys=-P>Ep!U(;B>~%nAacm(km=(w%DN zGkA2Np03GOW3EYO+<5tbm~W~?wduD+*DH;bD=(#?r{{rDlNF8-yU7i6?kZlk{{l__ zMPv4Wz4U!yPk@uLxaI8t>3#W%Y|cr%`7agFb8;-}9jX)E{Fma?aEVE=$3loGjD<i? z^^(x-`<!<qHH(vGo#8Pdx-eyc8En_rCzrq#n5ON7+Pe<ZnBYoC4e>y&mEJi2^*SgR z?S(Ufrn2S)2dJ;}SEzTF&ZT8C{Fn(GKl_jnbL^jxZ*mD5?zP7W*MHE^r?as8o=keO zeG5%C(#2WRb_-|A2yS+tBNpL#`2D(&rB^D|^;l1pGgO3G+R+kc#$0~yzomG*yBco@ zQRNm5OAcg-RhV-E8Z|<=+SQEPWh~<Q0hyFOvMX*_@RsJ?c_b{Bc%(|JV`ax}!@2bI zZ}2(2nCBjg5m!}YizZ8lvzBfmZZa`sx5JzH@;?_aEW3{r9em;Q$EQ%xUQKAJNyEc& z)7a>rI&MijPXiK*V0Ej+Jg*#rMc1Y7_MQqFktcZ}ue-vMWnpOZcZk$0G~uy(Ql$*? zGAJFDib12g;ZMo4{NmtP4z$`u7iL^T1K+8T;1w@3U1+Fi{_~7db50XB&!eP*60#0F zNv-GiaInTe)|i$Eid)WbJ+YNS#EG=|T_a_D8jBfEr;DC<28;C`w<#;_p!gwv0M_k$ zB&5v`rh^}H$Xz`I{!O$19f_+J(C|U*oOcexecGW`>@vI{y^&OlH%soGju>#$g?}IH zgSoFCfmZN$$lUOZZ^sz2{<l%2DY<rXf~w_Sg>!hx=-ZsXAa#)4D24q3R3VND@c z@nX+$+LC96TZc$~ETIE0Zd(a%5P${I^WkFo2YRq141yfJp|8dv8gct7C^|^{|Lh*1 zSCCB!-}k|ewz1UU?JJ)kiv!tTBd*e1%XgFPFtFvm%&NZ`ysQ!_`mD0tD03SJeCP?v zD-9_-Whw6sd?;j3FTkjW>JS?1gYTnnipL$C(b{|lmd@zSrZ;k7&$Tl`r%Y)tV=Ct> zD=o0mZv{1E&4=7`(_mOE(hi#jp(sBEhR&S_Z_j?FUt>4Wlmj;~zO*BFY>E`8yilXL zj}L;Ct}5GI(xG7&ry`s=r&v)sn`6Ab;jt)9w02x4+%+7<ow5pG@0e?J<LM9KO`iv1 zuixSDKZ?#YkgB!|!!l<mNs%N|$W*-2fV0<9Bne59B+b%<G*3cEDpQd(QVB^CCC*+C zC261usidM5l_X8lx4+-|p>v$GpJ%Q6zOLzfCDb%*$KT2Vx1W0hHJO8vURblKYZ9?V zm=~y8J>X(fi6m5xaVpLIBzl|1=WYX>Y#9rKb}YdJOEVnNo599PeI_NRW-@%X1h1GR zK*W8)1zD)iE_tbw-qlo2)gg(SH02g9yf%vkuDnn6=VKu9m@>O&=+3Xv8N}8Jd7Nlr z=JIf?GYeh2jHx}cVC`QovynIQu;%Im(6fuj-5SOfkt64^-Hn$hptqAg<^@t?UKXT; z5H&#!@J7yPC44_7Y&tAT>iaC@b);G2GecT`{TU1>I|un6hB5KiMFJcA9RFA<jWn(; z!iot(*3Gwz7C)(jroCw_(Ch@sNqEq>c?Iw}AQB&MJ;JK24bdgA3w*;(G0^2TKcHkJ z%Nn2u3l7#m$l~)@J8}eDb^jlXtf>dR1s|a(r=1G(j^SqIbW&Dw7WM))Om;#d-IP&e z<I5MKi%CBBz&eD9^%5|lu^sF(cj4;Nt0cGI1XQYov+M1haE)1EoJ;|~_KF^48pqKN z-BaZ197YGsLmW&lOr+-6g{V5tg@u+(Vuqt;vgDo74oV_5Hn&&_2W^Pt)|EI5IpP<h z;-Ai-UYf^`$X&(8=sV##&2;LsRbasvRB3C^a8~qL6{kNvM9rPjSZ|#PJ-dtGtz{7W zdw-dOiPK48UOqV;(?%PKXZ)lm8%Qmp05?w%_OBZ@aA_YLc#p;HC?PhoH!*QV={3Pr z(Q$z^&X>TnDHT+<LSRUCH^GGT+n{V<h&EZmH)cJL2d(QVu31E3c`MktWp5#OYA}vJ z8pi_m%Yv&g-}-!DI<?N<PWc}Spu+tTrc9YC<cxA)Vyr1MnEe0>_sUU>!%Wg?)<frE ziC}O5NuuqL==RfR{I)EiSFl4$@CuJ)Wupbw-0T+4YgrW>ZzQ_aA}~3Q_(5O&1e*6H ziRKh3GS8^r+}Un7@R6Rw@A7TnzAEk^5bqRtS55q^e^&UjS_AE(u2T4DX%-+8fdwP- zsqknHoA!Pl+dl0M?V6$rzEbOG>va+OTZTblP&g{w3!)vT*RU-r!nDU%VCnt*0}*$P zQ1a7JvJn-*zA!IlxVn(Hh#totb*Qm5x?9L;f(0jew-$O2ZlZT5x6{g{=UC29eKJX% zg_+`Ncz9ih6N!PhEE<a8s>1WHG=)BP`s2%Oj!es}jEmFHBa6EGG<5huC{ifpy3QTp zhj~aany4k3Whbz-fA&$@BrzPE=fkWWzfy8iC!O4Q0F&0frIwDVxcQ$E`W9s}-^*9X z@zY%5*S+U82cDwty_=ZysaCRXkpaj42`u!-5VY#H1e&}M&+I;edq%3$_3%l!x;>fI z=S%^|a|hVRt-pB<x7`$#Es4|oGC(}{Bp0B%3_T_cN7Y6froE4c<)ek?(e=aJpsQn` zHNum7d|)nbwKR)r-Lptj<bv}wmZ0MXDQ3N6CA(Pch@#Xgp6eYZ^unT9{=IJy-dn^w z9UaBg#kZ*^yn{2VyiE!1$*|#z3Rno)(<#C^(dWiJsywB}loFPZVptUO+~|m(XFlVW zDJ^ANbZ+x|Z@r?{sjAe{vYd@d64UA`eV94Zk{%or_F+9aq8Y_%tS^2Hnm6Qu%lCyi zu1k|thkXNaSOuDR`?I2DnOME|2OR4O#0x<i(W6!uUp!4?k1YD>W6eZ}Us_LsyNBn4 zL-28*;6L2t$D2J1g3!G;SiZ_&XxX}ue;=2KN-Z4q)Mjx<dJg0HKVQI0>H(=H-{p4M z3$9IF9R`y+xct3BZ+~<+i<Y%wF~y^qYuiRDOcVON4(d4Rp%?Fe<Tz#LZ0DP_|HEB} zo`S~058{OpMp#&L8#EqX;49h=Q*Yugc&JgzuRAT`&X1pl1xA%zUla1|*KJy``V5O$ zF7#bGv`BAvE8jA0A~(zFf-s+dL;u38@yh7!7^mS!#$((_qb&-%wU4l8S4U#<SYI?- z@4&jW#<I?@uCUHV4c9t^ky@8F8-M*w`Q#zSSm=L7;PzILP1Ywa`JX$zKlqw6PxNDx zFOEaK=RFjhGXvC3&%=;t8BU_%n0QzGKbn2zA&vMk06q_&gsL6O;7Z^C)G=Bmo?e*4 z{=E7GvKcDu@An|o+I^XmsUHPW0%v5spDa_9y1)!bi%H)#=Bs0xsVaIZo|@QapBC64 z%JDR2X}9*$wlEWc%eVxVx&I@lTunTedkTW)Dc~a2Qr7-&GyUXxVdC&4>O7*%K64E; zN$m(-tBB-j(Fbt&caGm1S^^J)EzreQc%2(8;Dyz72%6XdYu=rvlsCc|`$Gb?Y;~rs z4(Gt4c@hiAd;ptX$WcVB8OeVi2gzYOK=-&dWf$*(q{d>{`p}fF?f(GzA+y+%>O<82 z!x=l9C)3={R#4Ryc*gGqzsrt%3K*KtEwjBspK>#V*;TYytSiigI>xYUeH(Uan>?Om z$5`Rk{iytRDDyd($lhN2M!Dj_XcBrHtvd#y*_}wP;PS2VK8<;J`-eQPHdCrNkyR$J zfZfDf{+uC~T)}o?QHXUPqo_^Yf@wBwrhuvQL~p!1cy-GP_ItZ3ezqPD9=Mt{l_i12 z^QT;Fx-=9lIl#FdCr<C+PwLQXp~+3h*!(IB=KsqTp6E1+-^(R~_np<SZG;-`_*Bj7 z3_3^yce>!mvl@K8vAmE+dM$EsY-CeToTvXn6XD9KvtZj`Ms))$VTW%hs~#|&zCHL( zMh|AA`0pQBbub3(e(r_tS#kKxFOdrLheLMJ1@VsMeL}87iGJ^#%nFBprXdd+$h%}p zWlgmu8=Iv~4(}GRIpfyTb6;DaloRD4OLJLjS1mk9y$qk-O<+svN-$g~JO@J;FwZ%Y z!24M~M5V<GJJ{3W^!^>-wTAG?P9KU@)n%{t9>S*MJDHZ_Z2t0{nf$5GJ|Z3U7W>~t zV_5PPdF-72oBJUOM3trUa7N8im}^za?|d4`(j%u+9Iu4S4sI2RuIz$pKA0RcR$y72 zJlAEjiGmz5ASg%~cj*}sCp!lF1)jD-#9B%gy7hCtjVUTD4YPhm&@WR3ws%SxF57T{ z3vtMVx4o@YRICDxju&uvuOaJ}%*KM^ZK$EWo^>p<LJg-b@vuD#4w*40*@kbkas2#4 z<*~wd>i5}s=x6YVQ#&*R$Dbd|%@W5z$sj@IHheIu9a{jBnR98z8+CLZXh6%$qOj`L z0ap0986F>t!l}l}==ekUUg_zDn4s_6;7}K|Qt5~2M0+?otCrjGdMt~ZxRn;|mf>g5 zA4VtpwPEnKT=qi!2(#Nr@ble7-e=HUKFB1TotWPt^iWfoMe8Y!tqNoD)&sHP!!b&0 zsTCiKl4pT0uQ7*rXTkZwK2i36ecY2M4fyI%!+x$XLA5Kgc+~bZU8$Jj@V%vk-Medr z8Ah7y@!V91X^dbpO~USX?+E;xvKo}0TcO?7!;m0X0HY)lX@YQ1%s2(4By{ad>W<UA ze^Y^cZ;Jjd{R+(`gUHKuB~<N>V?#>6@Oo9pP*l7X4q8lQ2HgSN`mMzfcgdQq8Szon zx=ESEm_CJ@KF|5bV|RhG{z6VgcZOKva0*`Awo+iM*ihHS3NYIs^cS2imB)(Lh;Zst zNM9(zE#JR#QCk+HU#pN$`=<#9Rtxj=P*3b0XbYJtgW2fTBgk#uz>>xt0Ev17))O&= z8J^X{WpxAL?Q<z=jk(T&{C?Il;yG*%He#iovxsDWme)k?0KLP}^u#NkrcIc~{eGOq zYwQ`w<U1^=L2yIWd{ctWZZa$gZ}3sST|ohlV;mEhS)0=NM~ZjRW#xGMSJ{d_4O7`P z-3D><yFa|>mnx&ZvCvZVqr4~Ai$#lSVUOi=UjIcm<hh@M-zSSf<Yhq>-A2?qTX2`V zTp&N&V^AQtDz4ug>mZTw)%ML~WgK*8HO3u0&b^3lgp8IoXz3V3)q9&LJtv0Wd9MXt z2^^xqtsXQsYaGVP849~(C4R}P-Jo9B#cF@-<ISo!i1WP;vZ$aU@HEpU&(S0Kh&6&o zeqb1e2zTIu8_S`@mBR=NCCoRCqZ;{9*b%AB{;A31s^__M=)otLEio94a|W_$cglHj zO9WUOWkKtuSJ0=d#GdczfL_m6+`}3*CO>Qn+IF4*x_S~0p75X#S9I{%Vxh;VTf|G8 zO1)tnqC&eCtwP_EdJa1)1^&9YiZlNc%PtnpqmpiEY%j=#<$YmnsLx~}udUA_6gXN_ z_Y)?dBwHonO^eJ;aqaMPT*ApR@|ZarIxcuI`0)IO_q=D^59N;}Q5233Gsd%~f2-Nc zR|jFIZz;|+7di~vk3(JJ6n>IY3VK>L(wyNVK-$%bY|2b=-<st(bi-DRSN+RZC5~s) z4b;(mVlQ`Z#xqEtw2WD=@8r3wSJ?JVNl@5#07GVtMsxQGf&={vtvq1LQoJvq3h&0X zPyftI7tDmfJITD}d4VZ?dlJp|AISpJ+w6l?&a#fL7byFem}^K=gp<-LY<$v2u1wdL zlFC*i4w=Lk2^@@@S3i(qUjqf13H=+B2Vml<0Lx@nQG8+%Ut{A<sV8DEdv_V#aE!sz z;SZt9>K7<2&!G0F(O_416Z8Z&<z9bXgyroZojn6p!oIM{!$#8wO;0+OmB$AuymT-N z7{PX}CuVv&l#(=-z?~ey2|v@Dttm33C3b%(zh@9`&HDx`6>m|zu=g#xCW9s$k$<AG zkQ$Gyg7(g@Vj6jwF1<eh$<q2vd#MSOMO>rqjSo2q-DFD9-R=;0b}bah{h?dI3s|>t zAPyS$9?}GFD*yO5-Sn4o7;KQuq}N4I_%S7RCD@w%o<D)R@ai!B{5t?QY>&iq{nc>u z^<=bI6NS5BA?wk)2>s5Cq?FU~)zrgGXXF&r8<hmP0h6HawH<u^WKH4YVqvWRHK@Lj z!Z+@2r^b`t#IqNC$AGpe_7QCaaXX?&apFlDJ@OP}N!5aLehb*$kLL{>Em+Lsd>mTW z3wJkG5axX+&A+`+Hd$alwN0gcb8RVLLlxI!@5smg7laOWi%`<I6Ld2)`5R*-*_b(m zyW%E6%?CyF{41u^Q+GM<^V&>e*f4mZY>YF14Fl_0Zn)uI8@O$#V%DjHxUrXGnQrAU zOnT~08n4$vUDOVW^jip(PY%MCvBO2tV?N<NB^~zTw-p=rS`v#ce5B@IdGy}w7@0|Q zlDumN_fO>~ozs+Ku6I@0$G_q1MOp^FwNS%H?W1tVgryb#4Krp5Hg;ruY8p4@xPUeD zp2&krp4e9MHB7mzg)MHntngI^{182Zv;~gh()$)PWU~Zbt{s36`)t`C+`x3#j$mOy zeq?RG46Q<9Sb;*9*h6WdsOiKFHZRnHY2G`}KX5$(W0uGwC%(?ArAFiKujXJs#ux*S zbWlLcFlKikhRcZ*7@na!(Eq^@cJ+%6*37xfN6!cWw~D>+#y=C|RkEnVX#?AA)ga`c z;z+Z>oA#~_#p#QyxWoQY%r@R0Q-yrSE-nUD%1uNc@2vw>t*I>Gr?3|i`X?{{6Zl7; z{Q1hl=d|tET=F}Dbm{9Jhr>15r1D&FMrXCs%xPPh@@HQbs}}1pEz6O-ZUbcRis$q; zS>lv0BFH!v4Rl45H<pcMt(iw4r285v{gtMQf<fezw~u|hV1|xn8Kfd>h3`{!;a;RI zb$dRAW<P)K+J)_Obnti<RBMdkYhH?Dv`gvpHh~E!_(DXYO`!2ESLEgT4d)zJr-)Ih zU{>eN*$t_pjwl|+ts6x)mt3gi&o?+SVHjMyDzMp%M`E~VJGQib;U{<tJ)OZCEK$f* zOlZo$bt=vDE?EMCHfeAc{#Qk_>a)T7)MEhUDuE3!l%+M#=ae(;*+@?<jJllyjSY+W z_d*}_rr}gx!)gOLz3bqHnTyz&;H6wv@_A6WQAk#cj|rX8n_Q0bGx(I~LvNl{^Qs5p zLE>8~KX9!a%U(2sX$1m>+1(OdtBv4S7+vH~PgWznJQFTRErEu)EyKtL7c`9>&4%X; zB<VIGTVoA0M{q5=Ne>nFQbI?-JryK!3hj&B&G7z=^YFDy5obuW^LopoS#7og?)4vn zC&oU54Z9W5NByQKSPuBHS<{*1#b}C<@L&rUAEB}xmub*}-SBm5FI2>(Qr=BXk=E=J z?5po!IvWmXF<J+#YkpAV%2;6szZ=E=>D-Ij63X5ph0*R-Y;o^O*gy0R#XVGDDX56& zH~GV#NHzG=x|3uzUeS|RB~+?4jCmNJ<aH{B2~KoLHfz*bS{FML9X1Sy*1OJl)Hfd% zhaP1v(+05EGka-s@ltNVw@wm;)>5g@2{zSaD{eGNVT$I9;Av7LsD2oO4!2ihR)#zu zxO+5?X3^|xv@T8^5X-zqtb*!$MPhTyX;61KqP%FzSuWJqAG?mV!IwQt*bJL07!tM} z!mrtiuT0IQGJT;7y<V7^rU|Zt-e68;YdDCdqVZR)J=@Xb&Bn`*L0OZf!m%S?;2Var zfTZDgqD%0`c|4;ZU2!yAeJ3379?B9rlm*^eCd74(!|<aO_NftpG?;rwVIxk^($fnC z=H(OaS^aQ&QTreB3~`2H>7Vp`$R{%B)?$8z_c-lU^0@THVD5yf91FIc23M~)l4?v9 zRNQ|JL7;?^Z%&YEOAM#1Pxv8yH_Lzs+#P%s4*Xt<eSv#%c))c0e6x~0kvCwmPfH=M zUzs_rKTNX!($IK>K90blgazT?W1P=)-pnaqCp>@7<|N>y%s2`;v6sGo@<+FAHekEJ zkZQgH{D?211-eI=`2Gp{xKEO~RO*n4n>{J~8Nqg(zfK`XL(nQ+aEu*P<C6zJ;xqr0 zz?73hZ$f$zM$lmT^4bMsCH?Tpo1>I-Yb|&@MwE{nNDGssXjQuz>byvX(cg2yHFXr* zxiOv1e6$|M8<=qaUNuAFP&s(=;xpVY7{RXaGPqbi43+cyVVg`eO;L=&%LjI`T^DnK z8{>lgUq-Meoo7fVtP4K58)4X?VzU0|!ITUak@;vld}bbl4_;iQrf?7N+Mo!%mXBbX zRxn+$k-~Q4CG^vD1w{$&012Zd<u`BHaJ$>(NMpM2*`$~BDp?)fr>=kz16=UMrBZU* zvX{YCU93})VwtsTu<4o+y%=?qcdqP*pNSXf8C_?8ICU0$txc@;$e!kYAB+JvD(oMu ziU)^QJ=W&@n}?L4tWdQC6tA@sohydI>R~u9@h~X2ykIsSddy?iQLxg<<5X@vqutIc zc!N6|`I9k!xLcBwVaC)+B=0r|zDYV`byNy$xid_((z6y$^jw8sLOx`3$_yGOdzl<s zx6{RmCNRKVUC8Sy2~4PP;n_c*4(g5qyG!BxlBqMOYm}b2cahLHAM;$ayW0!*PngHD z#znHi>PAR&lx7Z$aXKrL*d`gl=YDXXutz-uO)G=RLb!j{j2+8dtyaLe)L(Swo=^;1 zQ3TBo^H@%rGqz7OVN=9G!o2bWUt%SJ#SQToT(A?I)(g2AKZLwSB~;0jz)bTj=05)x zX+P7Xt}iWg-E<gca)`P9vb@Ysc^2;Uw|txY2^cz}j6%zfGhcND97oEOq;o^a(OK~p z;{!n@=?MSKO89Q93FZoB%@(N&*|)#P<yrpPJyd$^J@4hRjyqi+3_qW*r;@QEEWdq< zoS!$7bkIX6=(tp#CFCl$ZyhZ%Zmwr#ca)hQZ;Pb?hS--V$M1|#!?3Fx1V_v~zH0gn zn)NIWt2TUwNhemp6UQ!4`{9oNwH_iiZ3LuQ|A6Qfe<5vt9o@)PX02L&^e}EC>Bl%! zMhRTYZW}k+)VhRG)n@Ve({d<v><ENjiC}UAf5PdPf)idZo;zc@nA1vm3Tv(>QT*IK z?&0mBSS48@++BJ^`}-~FdE<6`zj=?4?^k3uKQ2etXZ3V(*cCYFeu7*syx?fmNBdEU zkEmsXJ=}Yv2Dz#UI7yhlq%4{VWsf|lNMj{CFy#V$I;t+XV9I!pr*d##U5Xvt&<{g0 zx6`xtO6<#sSg4*mgZuqJn?057htlfD<Q3IQrylr;ygv<RJwwi;Q<yyKP$(d?`I%V2 zc5}b2?{jwl-ckJPZh^JC8+UAcMJcLfI6*QJ^R5fLh;O4&Nf^-F&3lKtO4Hc>o%+~J z|HOVbg?p6bHvFu708E<xL)Wk6(5a%yJBx*9&)(6Pp4tXV(Hd;Jk`z`%JD}8*O{gz- zfbltlaJI$_41BGG(_Ht93_5N=fqop6OFo0~XZOIG*yY@^+Dg7Xb2FRl63b0$9}apU z*Qg~&%r9<R%p5+SXBMvacv+1fe52(9Zi|FFbFPx&PClE<*4p0^n|FSt=QStc$eaLz zM-xRV`8u>_*IA}F`zXjhS;<S3ghE4kDL5ASvBcqr@Xa`Z+0U=1srSts&aO{pHA4nq zCwG}n4|ol;mI|*+={;EZ!5iQ8o}rfiQiWdSC8%H12nUNs2n@aL5F9^Kq+n78En)?B zXjug87#+v081olQXU5Tr3trIbvy&N5G#39I8ifmIpM|Se=CUo9&1o-}13!k;k;FMW zSfTn)to&d!g2ql!*w<~4oqvMQKez&_^!MZN)Dg_{*=nZrEtG3Hz89QiXF|vRL3ANO z45MB};k}T_@Jdx1S1fWt_4dPDxwQ`t8DfT4Eu~58zBda#FYrd(rm}z@4{m>o4cjOu z%K}1w!Te4yg6uisz=?^1PiqdFaepn0em;iPY`jhVp*tx^<0M^9{7XeA`*=_D$Nba; zeX<HFCoS)XoaT(p!hPfucYLEESq&|L@G*wm&b^0GWW9?G+Oe8a8vIf7mIY?^#iK)| zGuy$Rr!*m3U8?tveAY#ReDNRN2GrS=qzABUz7EEw^uxu}yTWrj8C-s3a|3@)Aa$~1 zVjEdH5!DD*KPTd#bzTlS$?rs=s*}*1t--;=17P{Fr4YZ%0F#yPkcwJ7o$}crzPH^2 z-p@b9I$K)BZxc1KcQ1!w<4gFJ)!9%m>pQD*+C}lH^Xc8;6->)p$ON^xQ?vdM%KFm* zD<o&)n@o8cv`&?_O_Bqd*#f)YS(Y7or-A$XifQ4isVE~M$<lj1!kd-nKx*S+zPR=@ z*{%60?Ct{bOocX@?$4(&P6EGv<p3Nk+}G#W+Tqc~%9wGd7>-Qi$)nj8vt33popup# z<rT$+R12)-pf})^VC3**tO|nUYp(m}QFiUgS_m5R2z*!hLi(KZtoY!2x~>10CXN3h zaB<A>-0=If{)!oEUSW<}lYWbbKYUH$+xCggOkG*jv|%*I!wPmqz2p^sgyR`S;mo34 zL=)R=A?<k)9$c^-lZIMz;hwglGf##8<DR>m^rfx5gp7=6KxR6~>qX+P{L{E>)?seJ z7DE<o?SdhZgW&HXC)m7g8r#tEkuo>sFb(e;;HI<=mwdkjG64eXKkqS(KRA)iI_HJc zUJj<+_gneX!pz*ddKtXfJAfkA4+F_(L)e?p<NVIrM0Sq%B98$joH;3D=i|vN_;xzi zmA1qF$u~8uYF|KGHuZ~xlpgXc=YJ(%q0>Gu{2xTkt%t~l|M<xA1k$_smY-T_h$;sC zR6BMOrnR?;dk%l)c8Q`XOzcVq%$R~cUM7#E72@{il|n~uJHD)V$P{K5gR<mxa_Rby z!XCCb++I3^EfIDv?b8L<T+vumJ#?SB^&7J9`ognN$Z*#VorZ~B&v`kyXH@9nh@DRi zKrK)OEWK>WJvkYsrTpOy4Q!af!+3ac%#@ut90KzHaw%)$VTyBoPmkobIB31}<!XY3 zpVbS_k_m@!zN$O=Y0Rh1zYJJ^_y?>%(a9Vyda~&^oatWw2DYnZ9KY~u7|vQ5gD*p} za7CFjY6VK;FuoAOgx+o5&K2B<o%XC!@(_OZ+{HT7E$N+GEvL}`1xg;qQ@Ptd%DpCq z;}7eje^C_YIesMRC251oNePE4uTiY}kRqS0wVdW=9;ef*|Kgf)W#WNVsvzpxPF}13 zk)pE|oB#D8r2e#L#$(1%In)b`w;}90H<9@nMN@*raeCLcfHrKC#KjFMuuZlCR!cbw zj*1crNWK9IO#^Alp9s8WI)YLL7lY51NO5*~B<E8r!eMS*G%Uvl4Sv~UwnH&Xa1Vga zJ2#kV%XBcU+rV~Te??n{C6MbwRkVqkP1j0>vg(>v^rbuWDRu-4(p`*0atFf8WDAyM z(ah%`GiLZ@8Y!rJrhkRo=!B5l-(q3Hu4X0RSun(|%1kI~-BzLP=0~v>Lm<Ax40@M1 zF!@o}IfGY!A#qG1IJ^x3yA)qeZ<!sIY?=j0veqD9Gk}_&`C|Q4b&#^$$V~Y(T7D*x z<~APS49lbOOoBNZu9yuE#?|tdJR@0vLJ(7lEhO7xI`B%#1}eu)W6#&m!vk+B>Deb6 ztab@xHQgtvC(r=SwLOAE&hzoHi7vZZEQbmUdr0eBB3S)92g==fm_BbV$8C#Z)pt`F zZLTDV-_b(5BnGtnt0C(9dR7!O4?pWX;p{@D;IsdVAoTiaa#|+KUUzLkiMj4}wfr`U zn{UGn-7|$Los^<&377dUA&+I@w~wv`3w&t4RlLv0hPf_MVkb^`J4oo4ahs@z_d8O? z&o({{PHl5BNo@rDF%PHG5<hk^XEFb|+>}j9Ujy!6XVLzUB6jwV8J>I~;*Vt~!_8bN zD9bQoP}o*}5`Mz&CNbYf-)a5Il{h{qnm5&%O_kF67*<(`3k4>yVV5Nh_OHcV6*uWf zWG|O=#sTa!e5v=xK{&7Wmrw9WB&z}W5ayKxPPVggX!1(L{80{Zv**E#^HwZ!xjZXc zo`(a^9K}o0li9!lBXP%^M-=9_oqKJ`VaCBSIN|A!di6pt<Ih+)aqJNpnfwFk+y+R@ z90|Yg>r%$zGTyrd*};2VT*apV_I%@g%5j&1vnIBn9`qk;67Pqr5hAd&{m1tjnlq2> zBk;GTEjbKP6__;g?DGga*0T69gx|bXu5EuB1`IjEZ|OV>UTHGSD&ZLFQ5@QvyrdS4 zwSOn!gsrw)C_}}G71r#f+Jv+0h*cw>{$>uySV&-e?_rp|>lp01e*mPKmauPW>jbv= zOjN&O1(Su>4YXc@)2>jiEP6Hz@E^qQdcByn_DS(=6W>!;X#o1E3A5u-ntWX;g63B% z7Wg%jU!MIKCj5)0$%?*A*PxgCdLtIAV{Y;9Ll08_4GmQ6`b(=uNpLmIV(!{oA-AP+ z9lD%1<Cgo4@P_%qV>f^5di#>Bx`whBv&<=0>K1?IpEYN{Rf&bv{fA|3^I^2j0^IiS zEvInbnek^Pu-{SpX{w|mx?g-mo7WCzFW!G<L$l=ZUYid)av`5@eq@P>B0J3d@(5yQ z1#xLYroE>zlqE>yLXpuac3Gngo&=8Jx@0elPKLG7cprI?yDyw0=In;j{=qEasSfx4 z)M>szW*yaB8%yV<?@|yKPHwBcQ2z8~&Lj7z$lhls#JR??)G@h~qaJ|oK54LCH7{to zcZ@=3y@p`J`B?EoifI(ci?VuOK!vmflY6BPg{zb?wliAv+;2BIxNfIZ*NJSLQZofl z6I_3lj_|U^6S5=hNolPn^aLHH<^djLl01Mds7vJYH0Ge?%4>Y7+-T+&jJRfWrZ_vX z3mWT(VWW;QKStIOMB+mtjuB39pTREnPe$plhhbx|F{HB_xTeGqB`5Z==bQ(N8-IZo zjDAcLGJGjqG7*(`3uou*8d5y-0ghaL$p!?7sP4yPN~?*-#Se4n;)O+gVViIcDEyDU z|5g#6G3wChyo8>N%VIs#>-lj*p3}S8DxBz7D}P8qkrk{|WKF%67`SyJc9pb=gs_bG zYT`2x{R+TWgN$&>tAAwwBLolLv=n;kF06mTOzb)O8OE9&f%{KFXp+ehC_O1ljqiH7 z!M?FH+*^UIGtK<}>m>5lF~xX37N)D71OLPJY{R}8I86B{UY*_p_wtrfLby9Fv^>Iw zm1x5k1z&tx-$!;w&Tx)%CS!S_J8qaek_~+s&PM3|q9=jdV9O2*9OL+#f0L+zh7$*1 znOF=xY2nbDp^fVj$CE^LmOU-p2fce2b6GPsL(0Gkc=7r?J+zua3(8mGGM||gR686a zOzfGo?0nWR#seoc<npZ}qjAZWPI?~qhKkxwz?YA5aB^8PdsR7-{cg0SmYRX$6?4Ym zmb71ddP5Ktr-zY*o(cCcql$9<uR!|-Mdp%F!dV1oL&MR{@Zz)<yZuXv9sTuyZ=WuU zDpSKLd3rc(x-SFP{=q~G-<MZ}sj%}}k<fMS9!UH)D!1Y<@j4M>dHYa*I8plvAZ1GV zlD{Gv`)D?mCr*GL{=?XjK6O0PqlKH#I+4$Ua}cqjiAJ0n!Unx|B;jERExy0FD#>-Y z>d^>RHc-g(Smuk*3{+;WH5{#QU&vY&cxbPP5}OT-5^{zYz^mDwX{DWK8X8CWwB(EA zSsBh$3UaxNSF4zt`b3<yCV}a%|3L{UQJla2Hb@(>5cLx`aofwMq2H?OyjJ*c$WII= z8~s`eynBWuvl{pnm;O=cTX%R?aSh=4Oo&dM%Qk<Mh9gpaprAPfR%>Rk7Qv58`kD5I z)>qk^k^tJ6n?uv*4<X~;Xo~mJB)bi~_;8!x8C{UiRgH?JK`U?2#a2VwWc-%j-dsZi zUN1x5GlweA=`o+3Nf5t8_<QOz;^T5cVg8h@OnY<%-R#!Jx_j1m`ne7L73OQNBBNN= z@G8<?aFHJSZ$_`~*HGvj0fzSmK>F(6aP~_Kf5q<xJV@}v;+RI^Z(524|NJ2G%k1OQ zggxGW=kzNJ)@9Rz{2TNlcpRHj^`0AXeFCbcMMBS@aOU!~5MnzAfU~3$zu=ONz}3AA z!-hZN-bz`6!rNO=_v8&g{6H>clRwRTsEu~<i<$nUDE2wt0T-Y6L;JV6<M6$eB)1@i z+5@&io%T(!@40&FuiOu~QV*?1_d?Q^3!q{mu$FIYu(>-=aCprdb;2f+>+wSFM)D!H zD`<{z9?hT+8-%{l-)<=XlFxaqF(xx5flpcMO9K@37$r-VHzz+O^R(TV(56A#*2yvj z(@Jc4*vpCA&8T{E9zFej53KUvf=1I;{!LOk7MBL2+fY50bJ7-fY#GfYg-+n3sXN%6 zI{~;O_AzwHzZ8GHERBb*$_P#rT`aoGLHfy){I2On%u3*-M5NTiy3$e9Jlzl4Gpk@| z>VEV+|Asv6R^WkOngYA{Cv;lKfL*~oxOwj%zzSnBF?Hp2L<_(!A(s@I{aEm-LDaSU zG-p$hL)Fc8B>OIp+&7+P+1>G=R%ybuCDee(N1pLFo=~{uT56L)PV!VGXhhnBt-?5} zPN)Ebz$b#Y){niXVHp0+j8{w5gMHJofSiUvTVpBy2wMYRoJH*Z4Oxe7iMedk_OamL zrw(2(weXE!6?rB3aT2$upv~z!l>apY!@UmKsgC##5iXXjt9ZRAukA5>zT*sYU$l~r zdl_VnehMG&1b~M^F+Y8W3Y1q(V#dQ?@(&bdq0WiL;C;`Zt=p+dv4aT4sXDT?3on5M z6hKVcVw|))LDX#a9CW@V(W`}Lxq&i5-aqdgzXENU_<`W*i9Q1Fj?2Lk)m3Djp8$?A z8!>8;2gJR955_4DSUJ`NCffz!L;tssF(I8Y^4!=+(=yUB^I`>??uyQ=+|8~FOuwcr zceueaQ4~?|i2H4|fzMHy%8pNSq|fQrjHW8vw;Z3zpWk_%>Qrsm9>>w>6}yLP{kToY zI;)WJEf07Rv>an^gmHE+L+H~sp^I^Q3<bO&;PB*5Jq1q~VjnPjJZeN6;W_Wkbg$?U z4ZAX*zG|nFZ1HTG7wkq+*>7ma(oFK{*ux$F5r;d@E8)_4!oR<s!8>1n$>r$z(k!t* zi#1N7;J3TrqpSiRdu8L0b?GdZZtw+ebsoXr30jz3+XO``-*Hi?v)S6{JQ~qo3DN$E z(DE^woio}^JyWB(_UAr$G`F6gnQOycKh?`5b2f2)8f9EX@pM)yH-YOF`cdy*N7LbD zxu9$L6DEZpB4N4?x=;OC!j!rACv^cE*m(%nExJI#_zun#_mQ8GJ335SK&zq^p-TP@ zEuOU>Ur(_>i*?)a;g}qX;JYEn;~lJ?uF7)sjBw``Ap`3;6taYzZp6qK?DKy}opXI) z`p$Lysk%kNG$U2C;+B!aLd%=bGlBTu3;$!5o*^J-?hdEi8_I_q+r>0G(*;lCKI-W@ z!be8vquwA*${ViDO5X3l0LjquvZH%hd{!JCp5@L8ryig;jh3{eqmu$tufojBt7uTr zXA*6)<SUF{3H(G&^sCpR`KxY%-Q<n9u5Tg+HXh-%CZzFZy^s0Qs%Y$vAzT)>hwsmE zXYP}du+*~*Je@3X)qsAo7f)bOhxEt+JmI>(kOj=YAWj_F3sdv;*-AM#COT&UF1uH7 z+GaJ}fQ~Elp(;iEW{@uHdoi4s^!8<b4<g}5X9(rXG*H63H!!K%7i!<!;Fq0DrY`5b z&^mhwSlG$2Zc_(%7HtZ38k$^b`~+}4_y`=r>R@}TJziHoNtSh6VT(>A7wD2pt=S3u z^@@R%m65~+)(+*y2)`$-+-pDBK!OdLuFhU8(7}*(T9~=_HtRI*1GhVB?5+7n8usdk z!?0&3*|o37Xqmw1cYddjk1RU`{=d2~55K{BAJqyOg9UU!CXSLfn6MVl7Cip_JJh{+ zUpD7j3>O}X<)8OH081w~wm4@Xsst<2!_<BlHC~ea?du?xr2*7D(V=yb4lPNtCd0qS zL4H(>=#?SE<g3Hj>X2jfU3gEX{Vrnqb(U;-_))lt5v&!z!lfv4yds<n@3r`$(?=JS zGky)tN`**K|H#Yf7iFD};49=MFk`at_rco5!*2`S8jqcjFmyk+^xOc@yz(Dv6+Hrd zp~pB*$X^a0E6XlLb>aF<VOILSn6fY4qpJ2Zpcu5$Vd{rF#70(d%YN+v2ZMKHrarl% zK}zT-6|7_9-pf*rq7^2Xe5B#Y2gvnZHocUX$wH5NQhxSq{(<>9ZjJe1kX_PAqXggE zbzOl0_3$F!v{hhx%WA{$(E<xM&Vg5xxyvU6T@i2V-oqNMPk@^?+PHs9gOIU3#~G0t zJ0LKUQl~3aNEEh-qV@a1W%YcVck?lI8kz7;+wWk@isiIj=>i3ucfsw#XDjZLC$mXv z;~)N$V?QJBQg+A}lCaUh2VOd?>)lH-`L;;lRTOj19Xr6`@3x94nO;uQe=v^sR7bZS zHFoCJ9q1SMxfU<?@uyylg;Prk_!kq(F{<D>eCdthYc4+K&uvTql?HjNGX2asZ+cHg zMh)V*+!MOF#}1S0wE-S$i9&=dj)nJqDs#7B6V>h5Mg4u`@%jMowD}Unq%Xms3-&O+ z_zXtOSjIYA?I2;I8b-9v0j;s-DBF6II%$A#zd6o_ud)@Dz72)G7$IA&coY?*%mvp) z0a%A-!LC<vkaT$l4o{cGq`Ohf+nkYcK(#nIR36vg8i=Ot8th(Z3qR!K1kAL~hF1ks zY1tlc-lR;6`I}FrM(YlEwm;3mM&T@VVm#H^So1$sCb1iylPU1@YwVhG+g|7NZ8AJC zpW1X9s8;VQjH@3971|a2$t#bjbnZW{|H22F^Rt7>zl;a9>wlSOj0Yt7?SoT$?+YAS zP0|}L#muTM^M4-hgP9IvSc1n}sH^)2$$fH+PCN1!hjhZf2POFFcOtxA^8<2rt;MJ( z2gOh;xU^iez~H=a57zP^RQ*XCg;~dpC;nL9QA1sZVf-b_g}D0hbO$r>FIo}WNNH>3 z87{epGTM(}`|js7F3%NPlJm+e9&~`KhA=M<apYR<%tXHDjM%~P+qtaM|M)k9Ho&~G z%GkBJ8SL&lz~6&$Fm0w-$P!!?KZ@{YkBq&!AG#d78Q(-RM)|Po0;?s%?HPQSQAfT) zK4rzF1WJY?8tkOVh7}B9qwZ$2o+y8Tl~ciIj2w<Kw|~=|>idxJ%7=}79fqBIRnYE| zJyoqY#f&AE*tx%-JO_A^+pNiK=#Xr-LeZN<(X#C0x0}#-%K@5;{%|ki3L){I3p-=G z0IhQ6(e2MpSTaiR{C>B<z!+(<baV>c_$Wua-)vzoKD^|X-gacW+?t?LPYUjxO@|H{ zBQ(thMt?Taf)NR5R=k=09DRz#&l*SC<(B9%Q25;ReB?*T_Hf&6mDo5T*Vxzf1jgz% zz{sIRkX~Yp)7&<JOo`weS*kAVsuWpru_5%Y6Fi0*J4tEPAIM&?j@=aI?uWcw1uxKf z7%6p@JOt-?_=VMM&3wTxSzw7p_g-=Xtz=lZ$#;s~Z-jjUr=!K!je)8sHaclx$zf~U zq;{HnFTDLePbRS!%WA<=<uUW?m4u?gLDVYjeco<W6L{<Tcww<5>ab%p*V=^TL=?lO z6gQS8JSejlJ`%A=HRiwWC3N_kp;#*y`<<=f;JD@VBqyBoRy^dKcg;lG<Rk3q9vxP3 zcOy4E1o5z49-J~TXBju{fs@dEHF`CO**FqkG4&Lz{#j3M8!~CY)<}{_S!?@XrYt&F z{^oW>oQBGa+o0E>3Y`Bw7JYNSL~mQhkb8h38><{grnAmtgGK>)|MBDMe=bB{?RW6B zV3y#Rj3Bx9zO+F40{_N$8;`YtnASImy%Ids8Q;yY=>BJVR?vxF{Rma9ui4zuDs0W@ z5Yl+@6LJ?DqO@8T`pr%Om%|4Ds={IJg+6LbmlN*qqey>>56+X1Vg+TR?8l@<fX*p( zu5g1MotdSBUE}A7Dlb<v$J-aFX=WauS`h-{wNu2S<cA8Zoe{MD%T6xYIujj^8sfHZ zT2MBq9vpT~LFa;lP}joq1(StY^Uytbvq6G=jWNPGJyCFRy&h_^D%$^LBfrRP5BY!b zqF{sdwCsQyW`tDJXH8=WxD|=VFSUZpp=|hD+Cy8Kd{Ih}g~qmy!T4`KC`0Wc*q85M z;59{X8Qh=-hu5_5ZUMYHZjWRA1mDI=C-(U98e#q}%L?Q=`12oIIkhj6Ttap;>}%oS zQ_4}nWht<>TIEpIY!{dbzei4?DGXK;cBCh@@%Pi!IB@D8>JPZWg`SE+XF|#n&hNjw zf6$S4w(Rr8fmjyC^ELM^(098zx3qc>Wu%Xy0)7yN2xmUorAC6&^gh8oOR@Wy26(Q; zxayy0_*J&OJg+2!RhfdHbM`;D+3m^iIq`;m&dPyLO&wh6^|Rc?fG>Q;4j(dV*1+h` z&0t`lK+lDeXm;g!Sasn%6`CbM&f)94l+Y`y6moUWdNzD%b2+D-ZAPZk)o^@n9hX^L zNtFX@XocD<vg7k9c#bB5?q2YAILZymZGoFH$0>E}FKVfF=ffUrVt=9<rf3Wi=AfZ; zHzkTmY+49!1on-q(r+5PY!5UvT!xvP66-U{7t?h`I%&3u(L7@2lZE%KVJLsTpqi?^ z&v1onZ!i@&&8^rqjHL}0?hMMQFe*q6*2dOCQ`t>%i>*CLds*@kdwy}df6O4q%lYuB z@F?jfW`e7!D(f_zj!QF)@wH|<oPA);)E4~(tsg?h`9B|Am5|A<KNCDKABKaiZX4-M zyv17?7V@{n=@3{Y+@l=T=t*Nfe{`ZV7r++tF#*S@y6~^)=$sVxQvN-ZADqWxb>^bh zufvqqT`sO)P{MzyQ=)5H!Q6}vD@<Y6xa_UU5HIbHbxtqgr;ZA5bukU!MMqM(iWaRH z^prR4EyO-oV+eXUfuHb07yr|n&HF?&axLO<xaav6l!JF%di!{`_MJU`TKSnP_2}l8 zxp-D4R8C=L$%C0m)Isv=E+-qkZE$J#IZ)VrgcPU!1wH*ta8Wa*fT$VvKGDZSYcm%> z`_v*>#V+B0<<j)WU6DlNzKIN9?ZFRuqnVTGO7{6p7bo_rq)p!0xGg1v@=CQ>yi^^S z<<8)glu~Gc{CIfyppnYj`(f9VUl8N<f_i89u;21I@a`x=pt?}1tg+xdEibbhM<;`t z>_0v~<Gm=j_%TSXbR*v4B^6til8Zqi-{ZTA?nZi{rd2yx2#nE=_p89d)ri%XoWY54 zr{TG^IVGt~rs<ayV2*DhtkH~y{UQkmn>If@HC)Um?H&X2mcU|K1zv!O1FPQ~fi==O z;I&1LbzaoL^MzL+r9lE)%!12T3m)(B&kupY@O&`zp20~zRH7-BpZV&@YcPEADU_M} zOmGCr<IwxUeNIo2UQ3ojit!|_n_GyI=0bK-LLNEA8n||-mn@!(m_+Ufd(r87KH%09 z`{f=-__Dp<MCpU<SY^5ahF(}rbsfvO1)ef&S!)zsd~uv47KL+OE64D9H<rSdN==q< zP6G<xNuffR0=BJ7f?umn@(%TGT-}tRxbof^R8jwe>0fNgdg~~*_`ow<)fPzB(K{*Y z#8OIH(*+r#Zqc<<li7TmU>sxlgDOlS5F#&@dE^a1xBVvUn%_+_)jkLj3thNtTRr*o zW9Q-KTW3^p(iRmaU4^rvjdWH#idml%93kcd@zJ>i&iukkwkDyRmuPeqIkcyehElCa zr`=yv`t1}xP`$w2d07khd&;2RJ`*lmnXtl<=eeRZ1$OYzC|I!RD|AO5CZ~Hj<b7fa z)=Jo;Z+i~ZQ5RobBa5Q=k-YZfRLC}R=i2l*Vb*k;eSYwnlm$n^{MxPL<uZabZ4Kf_ z?U80_Cy!FN^*?(p&x5ovhl8g1f<EO-6`4Ai5u5!VYMPE`o1Y4PzY~KoYT_(T?KALx zg1ccj2sxsfXwGqyB+j<I25;w;Vcv#wRB}VYVVc%bUSBnqGYlJm;fDl1Y}-aQ_m&om z871sXddJfGkuTxpBp<l*T83SzX@U5@qoj6U5j}*R&mxb<;C*~33l#1%f#ze#5j5Dh z=zWxT{xRU+={R`F6o-s2X9Uk_GyP1<7q(Zzd{6lr6-r0IonQ^-x;Tl7CnQ7Z>pgVk zQZ1PcY9nR$!Gu?=(P>yZ6y-e?{NVpslkhy0IMD%5{}7FDxGxH?JZ`t{{zh0XGm7A4 z9X%ELW6mM*kk$R1ZSvlLCc@5Z>Z#|n5B+KM0CSRx;P}v?iMXX&a5u;r2s7v)lA5y~ zzq$BeWYQK)cz=RFcQufr21h{9^Ij@Qe8N2*TY-vMYQT;LQL)T(*nY}@rHCfM`Qp2D ze4hbZ_3ApE$sX;{|KDUB7bwXJbieWwl&^qEmMr{SyPxwe9LG|WmqLrj4NAH#3kFp> zLYDM1A2G9sZ<pADch(DM?~)w0HocIYx%H1?o24MI<0b$6-XeODu!hwSLfo}>4=<C+ z=s`~zZrNx@(#p&EfVT1c!q6}b=ou&KlOBPaWLr2lYhCstZ#>3E*r3fbS(+%HLnmg> z#>qZ|aKQ^-I5@+H@B2|nhB@A>+h_(oo$7?^j{KqrG2>{3?Kc{;Jc{`XyIW7gIv6_Z z1E>1=0BMX(1JCjUTvJmhyqYA*LYrJEAYYd>lBTdVuJhn#{A2KP^P#iF-pp28kv&k_ zN3Od=*iS19ZpGnBFt%WDF46%Wn)mS;`*nHWdl%qMeiLjGK97}Vo@n{a7%z`&V=sjc z!Ho&0_`Fg(`<KDl6f(?$84tcDPFpsR4){cZdh1{C-kiW9FGoR1v?{AH$^+5Weuv4m zQOsJ~oYWsoB)hs>(DGN{M;!i0QflKW;-WN}OWy@_8CpQ=TBXo)V+1yI>r;-2Io?~W zOamP~skC@Lyj(q#J?1^JIp36`y*#mE_6Rnx+KOH1zYMo7FLH>uQo;qaKIRmxe!;S; zO}M-2GD>WfW!HssYJ|JA!wSU^R^;HrtY#fz2Dx{s#YB>;?b(3b=qN$7ehTHjC34qJ zIC5HN6HsdGMD{*@I{bcI3HM4;q4-Auv(7FOiK?E`#|5&a#Vb<t5WyV^m&vnB51H*- zA*Xwc-oRFVY`qySb<bz1!m}=G^jR^jm<u{M&%tnpz}_BGO@+dIxK8GlnBTIeqWeu8 zCo%C784R0AHl0riu5Mz&&uDPla#sDVgZ693(%$##=;iem!Y?m_?lf7DS-p%jE!MF@ zjY`U@Ji>b=9pMTT{=p6xA&0(eHuQ}A%pcB?XGa>Mp=Ev)YD_!IRMs4XL6S+#?$iV* zw`yWjS0;n6>Mih=A1U~uq?qTH_x!J`PqAx)B%6~qnWgF{Vqo75VkzNlR7WvTt_iC? zn@$6CQka6Skk{#)#R|S&<ZG7K!ci%qd#^GI2exTeq(<C<YZu;&a@T3|nFse$nEFM& zE4~|~qGd^P>q&TF#zRkt7TQi52XY;uG=(prMVsbf!r&eJ=8B=r<M%KOiuwaf=s#Xs zV?6ps@1TOD%iNpGGpR*ak2lvkL@T`>Qo8Rl-d0%`PuvNHdK({12<s9b{vD30XS!*# zl`-qOCJAmwr$Oq}J!tSfj~c&^#Ni7y*+M%pH&fA$8l9|=8yN-pJN7YqCka&inoGs= z&O-R;WA^=b3^8=I;4y3QgT-0CY_sM-{PN^4#10K*!LJv=yEmTr!ecrv(Hg|^9GCJ& zQZj6ye===xG#8jNUJlu7Z%~&<9!PwjS-#n!j>Rjf@Iw>cqTkn9;M$Z<v57O_Ylb_H z=(>jz@7(Q;y?=tov!{Ib?=lj}ts_}qC({4!2LG)a!s_Sx)2_Gcz-M1HD=Rt6cdxy{ zN!ZJ=e7`!_J!cer!cthX#)?x4-$SDR_R^Ec2hb{$feudp!H&1~^uk_X*iitR_S>0^ zlMRpt%_t94bb#I5OByusCe){_rwJc4G2B2N4;Bl%bVW4>*SmTwAtloOXZIm8I+cvt z^Jefi74z9KVSiSzzJW`+w2}4+JHwIP@zAfta|@b((7D?_pyxCRzM>ZP=V^g<1p}YF zoxJ}Qp<mUc#N1{cCHWdPh#S3@DD!^|o#{VSZ4`!OPAHO4gd{R1sl?gqK`NCZp^~JM zBng!!5y=!Pb1G8`MT3Mmdp%O7LXwn7@=B5>qEfy44>(`W-oO0}>%On+FYl{IHr@>P zqSepjNRI-tW-sE|u|3OZ+NcoNHgfyp@n(!DE~Vej8_*RgAtcJ_4=!J@2dw-jp^w8~ z*!y0cYGWF4DRw8bcne5I&L!sV6)Cc9)Rg9@uAo~yVsJ41Dh>NOn_m4Ig}<ft!O8u% z$en9FFvjIDd-5D<1;;(h>k1@FBNstHzX;;Y{D_81AKL8UxGEAEJZb&;)W75}-rd%L zmkog|%9SGxpC^-vzAwS7Qxp2jSxkD{ffFZE+BT~bZ^@S84|@js=IzIoHFGhG^N+Sn zi-UG;OTOomCg%98FHG8fcMuFnA{k2Cm|3n{$kVV&#<<rWZu$h_!Zca(CCUK*HLk$) z=o)tRD-*IQ<`%Q#pcJV3Edu?7iDW=Rjcz$T3a;_%$-<p|Ov{rR%n696CLf|$5wX40 zbw)E51agj%J>sN&<0ts7lguV6Zb$3-?bIhkh@?$3qrPW~c{x{Y*qC$SST~|dvo=&i z%(+A05;7YcT6F0r!8EuQFpHj8E=3z6=VMsWIvlf|NhAjD!iTOfvd!rk2uvO__bODT zdn%O3<mIQx+?}bYtH*U79_TTDGp6F>(P2ngtiXXkzGF#(EV*;U2m+TLV|a64z?5nK zF%k|p@M>ujd}N$x@v?F5E?Ji>zGp*DnnjVE_apqAfdqEl{;Rz1Kto=wN+y55Xb`@w zRU*DAzL>T-09(0!Yw6dmkTBsD@ZPA9P03f_@WphTJAMp)ZwMoef4K9~JAa}w%aJB~ zD1c9j2k}c=i3tZ%>2{lQRO9k6g7k&T8*BE!`FazwZorZBzSo9a_i|7+nMEZXWat#v zPBy}sM<jJ6q3x+0(NfKWwL(*9&Wk3VqQh#k$V7{*4m6>ezkQ*7S|*;K^_KQ%Jjao@ z8<=yIk~rpahfV6SBTrmR!NS`E%4?R9`9A9it>HRg@73ssYyUxN|0<#r$z{!SYN1)Y zkk9Mlp85ATNUwyT+2P-8?|D^FDmVf4EZ51Axj^@P{eo{^OeNCz3-)s?o9p{>QCM<2 z8C!6QtUi|lzIt7dZKg=3EexcFo0^%c8$(I*jgu((UV>5md4VTPw-G-#9s02*j{P@b z6}@$~8nP-h$@WDD*&W&atlQWg&Lxme(p49d`gbGju?fbs*?Sss?hqykU%rCNq+Ygq zk2=x+%zbaNy-=3>UxQDC@MkI>z?eZ@DrP7~9pwR1(gqm6Q`<<xURCV*Gz0seXyKau zGBjAH8Oi=eEUR;*x$^}{d7~D|3brP$t?!xo7kL<KU<>o_^Dvk{pNYS8feGkvU`of8 zSuO6&;<r+mb_OJ)cS!@gZqy5|SBqg!p8&}THiWE$hw!j)DrU!|FkE<qZ*(LXtTiTq zPbdqylO8f#*7?Ar?>kxP;agy+u$Z+ywH8;9WN4nW9al~lC#SNn5tqV$3~x#_K*%q4 z`Q7C-VqFfa5g|uj4A_GF0u6G(RfX&@6Qtq4x!h;vCQK2QL2gC_AHPU}rdSW;Xdg$* zFn#pjb(*To=%kK0g;=uWId-8gZSj`F_Q)E#Qc8n!;yt8Rfzs5W^Drar?nO`cPb6I@ z<`G|M8M0~I1<K67gOtr=>b5oo3Jq?8nW#DV9m$}>qor_jS^|U`I5MwX4QcSyJt(w2 z3!*J2kY{-*R3%T0j3`~jk&EZ)^YubB;Dr^vc0U6qpPz(^sT8yP7EpcvQ`kS}C1ZgZ zjKH!BaAEE<Tq-<`^8q}m3`jC1*Wy<}zGgY5#iYXW{vK9PD2fU955~mXTX3tf6gQug zB5mjG$ZpRan3nZ{SdTJLG+Ue$x1_K<e_Jx<P|p)c_hvFSEy1hW0-)#m8OVSjiPd0< zKw&)A``CcIdo`-(JcZW8PTYTR{sV`rg4nKqg%==y6{lIpz@6`tz}iNU=ucjcE5(*U zx1Is?q>FH#jh{F_APk)4Ic~3(8rf@CNLE~o;ko>gBQaAAU}j_sR4<)M>rTC;gULD| zu;MiJRA>gqq!#i6d)O1+r4U~B6y2uf)9U66U|1l_MrQwDZc4_mmdbBorl=2Fzxol} zp6dpmdt2E7Q;J`z;;5hRQwUx>mDmQqV481ekopa$iP^a#yuNJ$Ex!1Vmw(Y0f<Imd z7mo2_RP`4+xifeC$P4z8N+i+sjf61im#p90+syCTuUMS)j^k{5kc>6|k<Hg4;MzfX zTH$2^#-W{TXH+Oz`8yI{<!F<XR7qHu@QZ&*YZX+PYhu+!C(?IdB3hj`q`T%OK>qC$ zq^j&Wbf5ap2<LgRuiI{6p>rr1aJPXr8wvci{V2#gl!J7Y7fv6VL>g6W$;u5IA@NQr zs2JadYpT;A_|tk?-}@fp<AzY_em~=OJ(UTnQh>~|v-EC7KHPRU;%1lgz`S3M4oOQ; z-k-&&cI_*xu_l>Vk6c5EIaYMY!;2hyFo7h<>CpH9F_K%QfEiOBz_ojh%(o50;Iy-p zOgPkm^$$|1;+G<B*5n2uc~{W$UJ7fmFcMum9%HfI3)GA?;qF4B_}xu|;9TRz)OW_P zj{mf2>-n`1zwr{=a5xhSrfZ}5#Z+c#!#J#Sxrpk<{oIG<0`FXAIGUXs#}AcLNJEh@ zOj!^Jcgky_sO14n&T2)N(a+F)GxXs}lXL7GO!5G@yTO-8>`X_8dC^qknK&6=WXyWa zH3H9s6c$61m~Y#PF=++MF)aGYDmOFYIaCU3pM8W_|Bp}=b_p^^1qgqiH;89FXH9<3 zgTud<(j3LlxYAdhmY#UaS{TisrMpM**fwX#%*_Ee|6MdGLzkx2G4zN@3>PO8fT zF|zU)&g|Mxx+3~;f?^LkE<M8*FW(83r+YXzw<sAO@nY8|hLiVu$5B|mk}$h|K%=ca z1`n1n$IKZLZ_)#wFRY`V8;@YW>KL0;YKhgwb5ZlJ3C1|b!Jn6^;CQB*<F_}mqQ#cP zE#xT}+oxg6_Xt=qVK;r&Edv4*<N2{QVN6nLCOKlgn!NKh2ZPV@WP4`<iC+{-)}LMm zd0%$W<<o7!TxbTFQvQH{1Rh{!jWX?+FGyX--8r_ZFa&G<LUTJFRk_~<uF9HZwVx%& zrg?)y+B=CHxeh4N$urzH9RmJ5M#+jT<SlqoyB<lR*%r!ZJljf4P7lNRh9PV(dcm~p z%>yO%4OH>98tD&7$GpAz<kf*f6189(DJZ-|lRAE*S3wM$a#n~*9|?iD*?WnBfd>7e zqR*`zx1jU1EzbS^73NtLuzQ_P(S07%>1_)Mi^OtWQae2k+R7u?uO9PY+7XU{<s(IA zeHo(Lmk&XmVH8B{QKj|jmZW-i3R`(&5EJ^&f@QQRHXl&KmqoRB7lUcUm_L?C-@_Xt z+i78rGF90-3!VRT;=`qrXi)1QIg+kPjHe6Jo25g{!t5_xSN;euBXgMFwKx<POUYv7 ziM8bViBpjE`U`8VElG8Dn~}C)gb%w{607JI#yW}5wk8i@e~l93#${y1{g<Nqhf0_w z7f7?j?$Y)PVUQ}H4QI<zq0wy@crtP5|D+ck=4-;-U}Jh}_h;Da`;Cc8yn~Om%h9-f z2guI9N%iu%T>4NPy?jBO9yq2=V+23q;9FN19CE_G-Nld*od!G8SK*Yy^9fkgK|+uk zaW0!oAA7z6xqX4Oy?Bh-wY!6rkBEYnefD&4jt$#ZP>NO6()5Q>1&n7X(3>5$G|#pU zmW%{ZzK#T}*`{Gx_^gm___3HAiT!|KYB^m0`w4C?a75#`&Gg7`7aFzsIgIX+V@36@ zvQ?V0<kFT0@Or@vT;R}xrMt|~ZDu=fP^Af1yDnjVU6ke=jJ|Bc+j->Fb}OnsDGKhc z*<k_C#Q3VQW#IEppY%DqLqHr$@;x|C-GM8tME5J=tMP_Ow&pT7IK+8>1?WJS2vn@t zO{5G78RK$(bN3D~lco|l{OUMS5!a-TDzm`&TLre}^|Ho^3DoT54O|}1a2)2oO6SdI zi0_ZLOvFk7X4~He@H3rGMD7nkie(?$^l2^$D=VXVLz`*-10%Q@eF^Bf)fOR|l=|nV z@Qi+5B)X0E^k@C{suE3Gh`oM;;|D9lLjRr6k|#%b!#!*+vw$whOko|D_hB@*hPFMi zB<S-MQf3vP{p22ueB6rTzDE(YzTw1o3ZSsvm^lBeXV<P+M>P|t(1Y1iY0hOe_C>~R z7@s_g9($SyYE+F~^?EhqEf7rSzqkSlDv$W91nhC(44-}Ez6p;jYLdCVdH71_J>GRV zO4g2OQ&Wcw)QHi<f0Gwc-?f9hGC>)-sMG_GURpzECxo)Dk%@R}Wjre#_Y=m(Z&J<Y z*Z5(@`|yXNFS9xO8(V9xNnY=J&5k^^Kz-pr@DJ92t(t}y@pm(H-f9HnljUq-nKm@O zsA0d)Ph|AQ74X}#_wdJEh#^-zAz1b$YzxR{+3csxlM*F(p!F1Y1SH}&ITu>H=rE}M zYp;;Z3?YqLf7yzlo8+QX2yT|`!|G&F^7^p@_`kfxF|SgQZ?}asP2R)C`HR4{6YWqv z!<1C$u|)Hg2g;q=06OmR?4mOph!F2ANebQw&E7xp#cXR_Dfb5*wXcCkR5&xgh3oim z|NAP{CSZ67S?ed@J*zloYN90$2BhGM>yt@T-g65Lu_dT6bQhLR`G#Tl1n6puG;9qp zws5$z9;_WhI5!Pts*kmDe383kZb?0gM?QeX!lq1&M?1=$)4*1<F%&<hNw~#}jUVY@ zEEK1azJOLN{k)V$t8?y|(@W{4ty08v+ApT<-X(N>RL|S6L=Q*%)#9C_^*OvJKY z;oi9h@OKg)b#8Xyf%{_g(TZbabXoyO-H*n`H~z4{tBk#7+QK|uA;M~Y{RCp%H)xW6 z0@-xs9>-?i0!lh3nAo|t#BKK;D*N7%%~ex_9>0a`BKutSJLeo-aAOiv4>z%9k1uty zjfK4lW8f+%O;WS;z(L8BSA0B}=V~TPZr0~ll!&aLT3jD7ezi81sCJpBU*|YEIhj;^ zUl$YPF9cU(#HmE5H64e$th0O<`}5x*TK%)4+O~OIbb2+B-(x_#-zqZ0&0Wm?plsOD z5<rbKW|NwM|KQK6Q8>KFhV&H<L9fte8auNd*BU=W$*XGAA!`z@Pr5{Z=w!l&^lY;F z!*3?nzz`%h%F`$04|7j=4yjQQWp0<qK+EV2IN)wZAFr86=Dl{u+Z|T4kNFE<{5P>e zmouQ_;0M_7!I@k-6G#M|l`&Y_f)}`FJD*LyM>P{7+3b^}%vV`sR_Pg!owZb$st<c| z`?XJuW|k`6|13iMsuFk&jSbLjoeV*=20}JQaqPWBRCJ5NIEN@+$Q%P~uic14O&?J4 z;yIpu)DXmX-NU@6UQDyQKJ(}PNwQ5an*OS+hV}6=q}6!@HXYZ6-6b5u)<}+QiZ-Tx zRW0afl}PgQ2BFuD4;LCHq4uLZ=Cpu24M^sg;CdD4*0dHj`pD7rxHqiZM{SC2mgHRD zS@wC^0;o8ZjZw=sV#g&Jn)|&E!6TVTw7ks-hs`BZFT_B#>?#tq-;%sGU4q!_$BVBR zWgSK4kj)VpxQuhzrcE1Sl=r2;vZ{sfS2Z6d_?QsAqX0&iIL?spSzetl$J|a_O?<Hr zXT&IxsV`@c{;^p^=)4eNoC+Wz(21mz56m&QcWCY9iK|{^;pA>d_;uzkuF>K4NkSZ7 zc~FL&9y&yLc8MS^bC&63m5E!w3Gc7+JhHdd9ov4I5nJVKFqnQ47T0Jq4aYB#HYrmO z37$Y#*c3x+bqj8G8p6KpWw5uum+{@jIeWo~h%1eOgs%$QGSY=<Cv|CX>RLAcs4eMD zIR|zRm5IG!Dl@oP29w@A00%8YveoAn<IuVrbFXms(XVRRkW!bb8=J=1VwG>Gcq|hG z4P*E=hs#){k$yJqR5g<*@)m}!9R}Zb=^&7HmNnYH3ntSu<XA`z8}^Ljz&+XySU1j2 zi(LrMPt0VlSV?lshF92j<R%-R5ekArUr<uy6SQ3Lg@V{<_E<(6tP706$LbA?6PHgv z=K!Rn;SPAdmEy<FwWRCkH^58KM6HGk>;mueSUt0c715O?(OZ6k^I|coDyTz!=eOgN z>(xx1egQ1LehS9S*26=uwPZ%;2)Ay0MP9N7E4f|;m+TpY^q&h^OQ~FDe#1A|H(Lg- ztcYM3bI!eGE{3CfA3((1kEkakO@1t2##*fC<sbERAiE<)=;(xY3{O(0VoIUddTJAW zQ#6jF3f#Tsr40C-t4KD-iIJXF<&4YmY2?mYMIuX&Kv`c7DXtj-Wvv{Hs4T-MnI!z1 z%yHYeeo4pm)pSkMC3gC)sbJ8P$_UO{4ABG8xYMW=r{!FPn#Xo%t@;wf*Peqgdt1=< z&SfS~&B8wOc_`W7z&JUCbNfsK?u=N-^!mnPXyX8^ma`&R#e*PuARp`<w!*C!@3Aae z4pbq8s0}ERoVHYC`nD3^+n*|x!a8`}eQMz5QNXiP6eT~_NO7IMTDWv=F*e`ZPfzyF zqDtTI(4hbqXq{q0WqghS`4Y#pcg>|O?{0$0-UJ$9RE1w&_VU>GGStnH^0z<f23k6R zFMF?p%5y)sKI;ft<Y`)@y!p&Or!5FRFDh7<$Vh%Wmw&(G>J53XZlm{L2=8}a3k(nb zfalL=@)nzo!H;)77_dQ$ZaXf5-|j?%aO)RXoZie2coffX@BM)(_liN+V?8^wS{|mZ z+DzKE>CwD}?GXIa2Ftr#2=nY7+rX1$R2eUDWH&*shX{oDt^mm~2UwU;#ePaHfap(h z<g2s_uKN^Bs*Oa*0Urs{@S>l0$-0sGad;>5>)$i>SKDW3UiOcfn0giTJfujE#1;}e zyANN9@vw`J{PmAlk|zHGcFWoL2a*aqQA0u(pX)`TRnbZ~=64V6>gJHRb+h4+&S|jg z=>#Q>pE&11K91O20rmV|w#U1ixwhpDDfu!H4{lCnhN8uY{8|;5ZlF)+e2As`XY=9n zWJBDg!FhN_n?US)F!(+iVzS#0p-H?wy?G%UWWU(KzG>Bv%Q1s(=Z3Imw&}3FRf+0U zG_rF_4A?hoo3Krp>-4*egWgps;<#TI%zBTo2ksZZy1T!TvAU0y-g8Ow;Xmf`^?y0u z!FE^>+XO1H3S?1YDr#!2f&AyeAmXe7SEonARb3Stb^bfF)?`BXuM+b7Y&1C?$MIF? zoaeuk$%7>)6p7J9dFmcn1=dZ-h)JlUq<tXv{3>PCTh|f+qs{Eua7p?tYzs-%D}&do zw~?hv@6hVR0dN;gVLZ2|fb@c$yzsZ4w5WOqwpE=6`<HQya#jl~$YpZE@E8>^-&WaI z{Tdc7y2}iRe!!Rlii2uXsl-NSi1*FoPsyK+4}E4*y@(Fp>Is$@P=1X`u~Vmy>gup| zl?q+${2e8|BXQ@V9xVUj%8JV?kZU_l$;1Ofs4!y&czr#`Ui5gv9_x4wTLnKs!L(um zXPWR_<4?Trc#Av>nnA{H?8k=nk5F8(3OCHygZ-}qP~~_PKgc1Mxv;(i{3@Nu&+K0e zS?53#IDVe4%`@imjTls(!lKtxP4pjHLIQrv(GOjmLsq8~^(SXD$sWsS#&&(k$rU9Y zi8b&-aFCT78iubm+gRsw)x5U}obDq-lx#LB1grnvGyd;ANud3E)E!i&kJ6lAy{a4> z-aLs|#L9pvBr~4cw{SHPf}yMevS3jaC=Tp|8`HRKnCk+fa<vE@BV0i4YY0f&Eax(c zjo9+W7`y7MsmtDbXx4d$r7<TMlTc%9+53XcpKJ`GgO_1Xq$lT!pp0I48x!Br$7g?J z(k5*y+PY>A>5(l$hc#DOIpN3nN3Dt<&&^h%HhL2nt$_4KDUxWv5@p}qBd59q$>C4` z;o=%Y{93C<JnZ7g(U&(+zJ4aYb-%^5+uTI~YY#9o@L-;8ie)8rR<Nelf))Ys#mw`n zpG;lGW4L=%33G!)!6l{%jVifpgP{U>H@gv#>#UXtsFRKi9riXW1G+7O#Qsb#^iAq# zuaA9W1DD-oji(+Xxw9J3u}_o^j<_=!%nZ!k&+(>=;-Pe7llkMhi>XZU6ZS>l8Mt=z zJUfr6K`Yk~P)!|ykeCeIahp3w|2x9ou4{y&iaMP2crGc{y9N+B2U5&+aGuXRyxwL& z_Lyhl@UDwgI!&5v%KM4xjSl2=&K<JX`8({sMd*e22<lvO4PqOn!{M@(Sf!RsPB$v! zmE4Ko+Fy<9ulVDfhO1Eg{VlVrJ`!In{EiO~OtiRm!j>p3yoE2$JpwNmC5%5VjzWV5 z^pK1ym8jUo+dW>)7LqRPF0Y0|@x?eM_>X-myB{JN_Ool)5W>v;gn5qXwB4l@e#v&i z6?rKX-ZF>s{R=?nuqZeNzr;Ur!eoVlHaX&Z8NVJjqk;U7_zR_(_8)}3u(6am80QG1 zPn<yPMLdZWc!F0#-(ZRI8|YqphrjOW2gWp=W7p^UGtcxwsElD0O}sM%D^7gn{cUn& zOa2H`yDNLC)}wsjmp=g8q)}Asy~OeISu7VXV6I1f#BDz&)6#FUY`KRDtqkS3O}CEF z<}HGxvn-S9sc;<(sR}yyQx&z|-@-*XIT#ka8)lpy#)uSsvL@vzR?FVNn9+m4Q#YdH ziTmK!u58vuWCeLWdKW!Sx$MXBS5TulABxJJ<C(oysNVdQZGAa~dd7xBdDU{}p&TDK zeNTkRGwkT9(C3i#*UB=+^cZbX{m$G;<Ytm%hu}bfGOY?4L*3ptwB&;ry{KBuUKXlE z|5F#R{d*9RPkGPOzMVv~tQXMBl?7m3af3A}nn1gA{ZK5*np8-80#Grs;<PJWcRUN; zZJ%M$cBzJaQ47#LTvoaLXdL7e`jgun-znkN9oD{biiPzPuJ>)~h~j52L(>*RsJ&>w zc(@%R$GCm%$69e>KW#BA;O<?MzP^B)dJ!1<D+88Z$we)ajn=KUG`>impZ8CePFp>N zYLi7ok~aag9;Puql@5$T$ySh3up*YzJ0K=7k?Rd*(YvNDVCpPHb}iq4Ukv71<gZDl zCwW0|z$J%xDOF&-o@JGj?lNK<n#D6V3S;jd=K2@?bGUr(eRwkS9Lmc)fq5@g=|J)u zShio5Jl|+QuB@!WgY{?db+RzW#jnOc+dty4Qy$;lZ7=!ztraXrfo@;_2Q9dM^zBE} zY1YPOcx*X=@+U51v&2qt&Yp5830{S`XAPrda0BO^T8h06_3Vr6>lk&yn{@d{!i$Eb zbl>Gt#%+QNEt^!teowr?G}nvJwS7rUdDv-uRj)wr3~JKSCy!t_C=}<eeTQR8d^j)I z45w<j@ow5q2$Nicdt&dR<ra>mQ&+$fn5azE9Qr}RxQ6YO*Mrs#KiP`>BxaqJCr|yk z8k`?#Lc6u^*gmC4?9XGaWR}bZ;xDTPg}(|wQfdMFOSTqPhbzKR=xK<$7Di)s2GFKi zC&>|=YX19I86<u}7n@|t{cb}aj^2=@w}d`}{GD*HNFWet+`ukM2qr;g9k{ni4ZqDU zfTOY#A^nLKG2Roy?r7S;#u|sij`k=byv&S5gjw=aq`h$Ln*}f4Nq~NvbCO7(-OX;g zB1Mf~YSVl&0D@D@VC!<037+6n;qYn$*01Zvv^|Gl_mWwb`BOTW;5oA7-mooAaLR?- z?<Z03$jKHNa2Y=CXrijwUXU4~N)C`*qS;Z;ztqvo5cv;mmAVSOF<+SOEYzX0*~__1 zf)ttzt8hF~VeY%%f>rlgX`_r3(OLKxb#{D&Lb0>>(@~$kW=t4;VoyG^ZMgKm`6Ojd z0=X746FmbyfO|&;#-$}7OrDBK4+F@zAD=*BQ!&TP&>%Bz&Zm_&XYsE|FeAWa9DHX@ zB5yq-$j!U{Wap3q`J<2sfn8@w^c^LdSKGpV+^34!lT6`}qAQ**@g|Q0Pcgf?#p(5D zI-IllI`2>=fV1@yzIW9}m?|5JOV;+nqwXeHc|wd#;n-0rM^_TJ7ee^6?h8|-bcJ?S z2GMx`-*9ePEzDo4jsIOxqkGR;lgSqO%$Zl4;qxmVt#3SllQxgRY_U>=<~r`Y5d--z zPQh1oC#o*!iwdC2&C-j^e<^f=_w~)_yY?n3n%%_P-s@mPb_7i-isaWHcA|pr>mVWW z5t;9-h^)*8blsy(on}hm9NRY#n!kuuRw;z?GDR}odjW0va1}g_2)kypJ$<uf3i(p{ z6l}RZax0e=UH`8MB%jSEGrR7v`(KW-0n;0p=hsrG$rT3_2p(O$k-r!6eD&br3NOS? ziur@@_@>Z{Ff)lQ+c%HC8GjC!&rQZ-^0VM669R_#h2N)F%uHP1%Jt3*nRZQKBKF9c z9@7^gTRV+O)v8k{VEMM9-<hJf)K2pI5liQPeGU~#=Si^jYxbN=5PT^<2Etj=<U&Fd zdWWh*#o#pZGDw0H_k6;(`G(MCJP&po9;Cl#hQNP|dRPH}QM0g@3+X1iCG1iIF<P3X zM7BT7WMY#GVE2`1{G}$1rd>y<f2uy+|Ag~CEmb1JGDYUkZ+MfP*R9B=74P7DYa9F0 za3Y;A<Up@hs*<*lE#Mlsmg}tfLis`|NU6SJt}px;7B0+zt&!27JCKR<k3^!qq71Ql zy9vrHPoh9nJ>05uCUWt5WbVo<_(n1Ty4pAg9{mVDc9c0^brx4Si&2k3FR1)J%ARY{ zASn`7)OFAdpKm(_sxPOTzmB(LkDl#>(2Gw&!$gfV3T#F};m>fy_8z#n)<E3lYs^hq zN>=<n13pd<@ngAwg=6J+JluQ}tF=Plp1Lx=IJ1UCF5gZ<vwm<s8wq&5eI}ku*^Fz_ z9)L>bC-DAL&kS%c#9v``G9>d56r8zP?N3dz)AI)kM+~!_2RYuC-7XAT?pl@JsL59L zRN~7uN|g7=1+=VU;F&@!7Te0RnZG6yTkcG_EL{QW#HZrvr*TALMjScS=#2JLCqVkE zC=`$#D7XJ;iWirCLIoLJ&Lz)+y608at~8zl4yw~#)><TZ;ku=!inVaW#)*W5%d(%J zN3puEG{}n-1iS7uQrGhn<?qE~o{<<?(lU-}B^*0x+FDln_XE7yCJB8vb71+=srXH_ z4)<K{Wp7_tjDNm;23ev+OuO$x)O>Yfrm+t~W^TkyO%7;Ns|uA3Vlce56$6CacuAtA zApPSaE4!@&%>I67Qqrq<S3}akZul3@uW2TqE}DUopaR~NJPTKSC(s_=QrgyPL>Fa0 z#8X|z=^D{hbWA9cJtP|qO(T<ur1&o$o?pSLO0Fj2%Dtd7B0w(x-b>o2$Pt)+3s;=^ z!M|9dOkEpR!4~%{6yEKPP9a$=KS&MZ-7=Zme~v)@nK$g>s9Y@gJB=(2P=oOU7O=6~ zfe1$yg2c>N=D)Q|u=(U|ruVoQ+x|x$O%_Muw?}vQBVMV{HB<yoJzv9BBRAsnr;k-H zGv|fsH{t8PL(F^4Mqpjj$i9MJ{84R81lIpBi}ev_-6x)8LO;esS>p$GXLtisKW!qJ zY2}WtUslti^-bva&yX&8lnH4?@6nyRlexK3fsM>`rFD08iLLoZoMR+SQ)h1nGbt_3 z<=%s_2Z~_hdQaR?bDrG2tjQdn-v-`GW>`%9B}avaG)T3~LXt5Q2dd_3%+rY-(0$|r z|Bs6dUAJ8iZ~oIZ?+=fG#iFCYSlM!!UQt?$u_!<BF(mzc#JQnM*;{s@pns9Day9@# zXEe}P=?#nuY$J1xH&esDr?CFkW2Us6klEfnOb?@l@mBwkKcvR|Nx8%N8k`1&&0Ea_ z{0-O#>|`RaW&tFWWbtDS3^6T~V_cZAjM(UD#(JL}xMoje(+9qzX75C(KC%(o1%HFY zG43wDM~(Q|jAGhwJ6_U0he=E<sdz5P)H+o?xT$l1(Z2i@Gp7{by|UGe%GWp8pXmw` zkHt9F#v)dH(mA;QZWa42?GHv3XhQOnPIh2VEMDAZNCG==Gle5dVO<wDe-RsnM)~6y z`7DM`GS(x)(ec>yXeY`0R|IFocC!7dPq6T3BQ6aZ!pa<utC1E!re8v6IHO24#yIEE z;7Rt&{ut`xJ&$z?<`|#OrnElu23uM*Sh?%?N-`=_$F!Nx!UT)YV7APRGXK3`<tjvo z$%ITynOTH_HFt@eoHZ=hR)XpOMCt6=pV_6u1+ZgVF31-}RW^9@@pnKYz@~eQpXFY% zj645}Zz*GD+)QTY&mMz{`NcfR<cAo?>>v%2y66r$I97Ydyd^r2gv^>q*7}}f`CN|v z*#m8Ib}*W8cRE25xi#GL`7hQaC=9&RV^~`%3PT*LVZ-7e+@apYc$~e#_DdG>R=muC zET`!-NU4Ag`$mY@3|r7z`~+R!3(z-X%Cx!9g@;ZZkhIGW8=H>P&QG(TXJj55WH%R% z4?MxK>tZ~ur_ES8s!2E7@2A_W|6y5C3=9_XNMTbJd2^Nf?q+X*#9v%7PJS6ad?`Xo zmUQEgO(ALCDoy8zxL|GSOY)zmD=Tbh0y&dQan<q_H0*p8mJ7XM{mnG6GUy^++$TcX z6k^!mi>Gl#r3>{r%Y)ikr*QaQJ)>2_M`o@$%;K0x6I6=$ChhkiN^d*;yj_?i?Ny;J z-G<D@ffXds?FERsd7+Wv18}T92<ImlpnRwSo-SNUjHk?C0>AuYTuPlti|S@9b()Ta z@0Tzhqj7M+aT>9Ce*%_F6kwZu&+s#+E`lLm8kwDJK*~?Zl01Gn@Xv`5hosY(+^0ro zMBj$bLrZXahy=AiRnBXY*+)G^zGCs8K@|0L#D~^e)M1-Cs{Q^2K_MO_@Ypt5b>|9i zyK4^es1#0JDM@oznbTr36|#7&1%H_)KsfgvbyQBqH&@;<RXY}u-91x@-w?N^w|!>j zJH?Z+QqDsvo`~)V3-I5^Rj^ZBz~Yuq9;W4|p@?M`PHU2<0`1$Na6via=+KQP9rs|x z`B!jLxtEpobphwBFU-sr!>sPvFrG`mR2;OECjlPEnen@|Alo4XZ>B$l#2M0H8NxAL zDvpA{R2gDILfBADgCDPS*^-e!vhL4!Ocm)z?-!hRSyBUKG_R9i>kOEe&sQ?##gl16 zfgU~%IgY`XPqU6o)gj?wDn8jV2K$eMV8K~c`tRI9@E)H{Cg?YliX%28lc<s@*RsHJ z4@E1VQk2)bOC)NqV(7qWdS60{tXnmS-gOTq!}Jm{|13)G1zF<4_(HDJX~fLQ_kgoU z2iVqxQ1T$Gk*!wmV;ckxa%aj}RMho5d_K2|8ECGA{r|1RlOqZiQ*JAh#$_rr$89DZ z+b2Rdt-b*pq9kzB)OMKJ^9U23cA`b5Fx8qijm*5W5uHBO;E0DY>eQ8?s7?iGUW2eS z-GxdC6~mHdFK`OK#AL1*!oR=8!1ZPd<Xl|NpM1Rp-o?a0l-fMBQIw|(^H0Ifh?i)Q zJAq!?Ce1S(HLQ%<Aw(jB?h$$CYV-{ir+y(%;PT=;%)LI!YF(N|{^s6?Qfr;6&R8Y7 z>5vimboDxua;lWIP?MqjX`k`jXFKw!%Ny&tZljFMM<&5w22MU9M2G)YV!g#4nz8P` z%Cu@Nd>k>Io@$Puo;yYH?%P{5{CPg)`cAL9HGGe4-}Dxl{ROy0e<8f;SEB9bHxLP@ zcyo~wZnpoCVtd9(I#|A*RGn;wc;iSi5d4;%lgDwdPA*`Q%x>ZFqzYVSV*nNW47}|# z7q=Kig3mrLqCG){26$5Z*Cs>t**e%QCt=Cw8PNN7`OLtd**GmBgpufpqB+arFlJ~@ zm0FY|)hsv*k`ew$ciKbn;7Rf$L>5Ez`><eQBz-@0308lLVuzeWsn*R7{^osQBuvkh z+{hcjfnA!^s^Sjc)PW_>lm>8mxIS@l+=%1TRiV>AhA7P7^3sQ%RqhR6VqtssB{qIO ziSdr#`9_9&$YZx(teL@5Vv>*pl0y>Y@77Atj@Sz6(J5r3%_N#2bB<q@qz%q+f*l+= zOD{zkbN!^_RHNey-Vrb*B7RH2N_`Sd=bo1v*VC_`oC!bbmNEx&b%<nl6@65ufUAoQ z$eQpv486a|V%?cvxHd)#gWD_kweqTT*8U50pOY~8dZGiiuDrp@b;Lor2gjRz8_PWA zJb6ZS@?__a>vU?V5y>Y4BxCDuUj2p3I3BFcbvYvF3djHWPlXA+KI()^cN`^IyXKJc zU@@8&lz<m!TT>-254$^eIj0*`rdQWjgJ!Ki%ZV^}x5AfEMdRrtaBe%BxN<64(>WWj z9^XPY9<C?jG4;$LJ6Ae2P=q8EMxmk+#ff*FVPMi1d?^1HgYy2NXYfVZuXPQ7oOun) z)WgWkRh+BREfwMKQVY?Sdi2=98>Zx}H+1VW=yuP5uYS7`6367}>5M&O;h+D&?U4@N zdr<|vtC`Fqv_?^7AJ}Z!%cj^=pwm}BICi%S^4H%c74@Nbe())(-wZ>MOY5=luL!kr z55%tibWGZ)N%fkRl8??>*m`F<amXIV;Pc%1^8P8v-IYz(H>SgdwFjBjJJKX8&j^># z4<_Db*V#h~Mkvx7#;m7ZV6*K8rYP5=)}QrIby*QE4jU2U%ye>fOBj>L*QXL<vT#iE z9RBboWHqx9-6tv2(v=nL2MufDyM78;{HhylUU5}VS5ds*I+c>)IA+1!hZY*8;m~WY z#QGi8rT>|10YSkRpziRJxGlX5{x_1TDVM%{bT@|7f3qR$?Pt@Wzi!Msvtq1Dt$+)6 zj!=bY8{BX&mx;I%!2kGl1$a8S!t`Z4+I;sBdUb6iZFj>^d}ceOURXx=h|Z?I&(+w< zm8H-fuR%kma(=O@G;%Gb9yEF*m^Vs-;P@bz%a+HJlbelUa@PrH{My96`jN$S1>InN z+8x72i6xk^{|j>xg<-q6mBqeS>k0Gn5VzOmn2>$?gkNMxn{}d4cjagHhxA-1^OT?+ zmlwcHuW)!R9EzraoENFN42`1+&Dm279+5Th(`yohYl;)l{|dPsw(#ZjY^uKH4145r z1N-<`GM=th=Qtn5-2M1n#>@98d9^ly^_~z&!#pFPJ7yv6(c8p1brtB`-Q(=0PqO4) z+Imd&Er;O9dldrP?!yE>5gItXf<MJBnjKoyff>Q)na3TjG@w|Oes5Ev-R-*UV6rET zdLTn}gjML^*(UH8G$AdQ^YPlV^^C=~b}W5W!EUi!PWlua$WF}$82G}%j`~S7`ST6d z?ROn&sO)Bbeop|yWNu&Z`4Gp?%?BIq*`^KYlf;P=plVhd+I^Zz4R<}quT@D9Toz|O zePS`rT%QFi3>Lv#GkJPbcMU&0>?OOp@j5cP|KY7?k6@EVEc@@wC@ULj1gA8bpz=~B zbj=FKW;qv_^jD5Nd~g*%?N9~N2p6*M-)iRk(+yxM(Fj9Rt#MoXR$8dVIXDhGkz}Pa ztnj4gF#Ow>q`a%dDp@lsp`gHox0J(NA$2qgI!xC+PKUe@z?%;9X_{>{7;&{$D?4Di zzBXX@BP+0Ru!1z@^BBC=uF_-^H=9``O`UZX@m?)Rr>`@g;Q33waIkkR2#5qMrMFUv zen>Z*7?_Heu5gSsN$wmsUz;Z|r;^yX-+{#kuHt>?T%2<}5QUcxGQD?1V9-JV<@6OX zHTNv&9?_ugDl;LqXAb!|qC(l@MjTV~5xP}wgy20B%&2uUj6bshaxeu#x%;a@KVSUl z1-P`~9m9#)VdZyOa{FjB`W%^pMs|zg<6sfgK48#ODG}<rL`id`7B-1bB)^`9lh#*f znCt$Dq_65XTWmg&RQ~?WEHAmrG@X~UFtE<V*>yGea>h3{K=K)8Sr`$!mP8U>G?Cmc zR3`X!FVpmOE_J+ol2lz(C;9F+%$4`gL0vtL>{cf1qn^vqJ$8jvJ(!Exf?g0Lv5y{n z_z^4iuC8)_`50E097S7uMLJnqnPQ*|DR9aG{R{6gPuG$-xnDzpZjSS;Wly_j`Vdo< z1TuHRO3Xg+6pS3s<0TJGa%;>Q>x|am>k&<A-#-qct>ZZ1LK%!pOs8(aA!IwpK#t9I zCC;aU$&#iJ7E_nQqojD!H-8?~iL{VL&S9XeS%D%}uBg8C7JT6D$#3ooL;KJsTq|;l zneJJJy<6`y=^KXe;7?PwEmV}4NfyDVm<X(8eMxVZ8FMN02Cs3r7}vUFp@s1mChM&> zY@d1`!A6z$O}-AktgQz3>S9>k+z1&5CeZTGOZeCRH~#*&ovhXnCc$R9jPf^b9bEQ| zJ@7CL!>V@BiqoQ$gA`K<vlTS(urb!^$ze)rH|!|Ai?`Qog4rk43IF*m*xGT9Ss5uy zu9O0amyqU_-pPi@uRqxL)s|GKWes?a1%u<1dc2)2O^VO#f#Mgr;MrnEmszM$(M@{9 zw@45irv8D-pVCC(s5kH5kGXI-<|W(xP7gf0PBN>TjOl{;a&&J`6+2yzVWK{|5|grf z2zmW*x$`cbH7EtI8cRBmo`POK>tQI<3<dH}!|S?YaxR<G6YR7_v!yYpI&umcb}lBX z9{z(PM}g=H>fy6p9nkZK#}>7OP^Hp;D8E{Y9t-beOMeMMxcMCVby6j>udR{h{YjuX z9d(RhYA+KSb{y|G&mphGt)Ss(GI_i%86>u+LF?&E$T9wa>OX*JOm0NK`wehk+>;s$ zy@6nlKX|pW4xjlP#W1N!B>C(&w&M8(Sk!EV>q;ik*P0u_GqVVb4ef~I<VtjMEFvU$ z0XjXLP8L3yOqIr^Q0h6y+o;Z@%~FZD?sWxB2^)bMk2`UrPaS6b7NX}GozR{Yrzb)= zu7&(pCNp&wEjhUjwEmreS_^r4G;IUeZr@5SPVr(-*2RPE;!@@>*F_fmK84zUT8=lj z3c~(X>&cXt5m11##GR&Mf{G#Yci=5*XKp6tABE{Z?YIZ4KM2Aa^|>^6??=9XMsMYv zSMg{a_L=|vc^&rtoQA%4ZdJAx??8p^?#%F~g?RDEejH0`0hzt?LEV?nh~9_;70#<L zGw>VscaG9;Bc;@SY&KY%Z(*+ud$9sT+eng17}I7mjq0A>%-HPb*eVxo&?%^Z)N}X8 zxp#KZ)W|V*;+0+KS{hERwoZq}P1muP%kYeQ&IMDqPw2kz6!BTIiB2&&!u(29BwZF} zR3K?JR&va2FMT_DR<s!6EON;BpVQ1jxdXUyWCeDw&fsnDi2)^5TQHvIiiHBt@&2D= zVlOHQK2JT!)*D}-$Rq*!&o}Wr4vjGpwQZ=GVoq<iorOQ#*<Z$7gg!BzL<=0Yl85Kk z6H_sFqQC4RJI?LLe{g&*1#v5)vThmUHqdLH<fuiu4OL0L^cqr|8B6)xnxgYc8ZT;3 z;O=|AL4$cRxE;I*-g?}O>9{{ry6z9-%zJ}hhokV9)Cwv!Qw7qpcx(m7Y@ArFN<XcZ zAi4dC?53S^Xxf{LwF~d?YlXz<-7zV8^|~BEBV*>YmL96z$s%9Mt`o-)Zf3UR6G&%8 zf~wV;O1s`7IKKQZ2FFy88G-(o6&;It#{?{_UytC(g*_N}wwG^qaRDvr*QatWfmqwO z1dd-qHdbXJIkIB`6<B&74N7`(qN^=2_+ba@$8y<y-a=frTZK(-Si&)hCX!CSoscro zfsQk}Bs$X{PfFf`)d_DQ$YzjSQd^6It(VB}m22tDpm3}$>1W>?tS8GeHgJNU2zXMo znKWKqPa{sNQ9q#*C~#yAQ61#w6~kM|_*NY#IT#FbV|9#_KpDyRUqWv4Q=mFEnU_3o zDarZViSMJ2(8<$2v8qY_U@EhSRhp^9)?R;td&QPf>5n-W@6b>g<JHbCb~PqyK0Ap0 zg>bmA_zGQTUWDRxepJcm0JJ<`hEIH_(t<ocIGWv#ohNcx%^?+9TC<2A#HZl4#GJG~ z-^W-qajt16ZD_U}AW9xhOv#CROwhL^Hq3khhWBb%6w0rlXRe$9tuZMkz$p!%b_(IP zDtjuhT@k~N*5knM0=h!^EE9bHtXYFy24fUk#?<a+dA(*DG;JyikE0u*;hG~hK2f3r zCDG7TV?&-T5+_}wqD0I|h13Xdg}t9|<KMf5xaLU|@f)5GKhT%+5Y%8&V+ZRh5JaS_ z=TI@xCFI-NLKdPtQT5?u8Xj7X-wG1Y=;{_Ie)WWrl(`I6-cH!x_?f*dRz#%AO~@O; z0n#gL3bJpe5Jf)|>h67potpiS<Qg1gTXYzDd&g8RTO@^AN;`@7nIs}PqZg*X2*AH0 zi>YLlA=7fV6a<v*K>Jb!@!_&g?Lm*x=1(PVP)wvjK@-TZ)=}0@LK-e_F2TvFVirH& zR6@JX6uRT;O*A@Qh{MZrVewZk^Ec{A9Ry=h{rwYG&anfB1ue+00W-`vxsmphFDSol z7UbmYC7a#`fe4rLfP-5Z8-6dF5oeA6t#_i~8FOG}K|Yuy55RFjO~QP(BF6+|_zr~! zp}P4K>@o5}x2g!f#NsYc?UtY>?oMDQa~mY*r0{=s|3YEDHu<t34;Qyp!6}akm|OH3 zF5PdV>P7ZopJ+g;cHe@{SB9Z_>I}L!|2TQ(n2!HgSFG9_#v5NQ&H4$avguL>=!y|J z*6pAlrmdWfCl(su@+2iXXw%2mz72)(-b~sdr$hR*-_XtVC(w82ENZ80Nss%4kX;Xz z@Y?NmSoGTsJnnZf15-qp55mW(#S0UX<@}cEiJMOPcZt$yn@IZTMlcvnjm1no2ikJB zn)zKbiEiT<=jYc1fWvYNvf6-is?WU1f45;5{;{1wzE62#q4`*vzIq}>*8DM|Cl7AJ zEn}Bx$RlN<DVIkFf9ygtAFgBP7Y3|QA@IDfK!(+6TKg%GS(MX8FZ-<}g35-_-qa1E ziNDcpmIFWHRwaoN<h+SHI4|aSJavy-Pi|MK5`mtNd`po!I`gs^@##NAB>#JlJ=@mN zw_S~-X75S*d*Luz{?n!R$1alB3;%I^Hc9Tx6#`~g4Z+hxjP4z{K>j)jS_Eln;5EZ> z?3lTVj9>T-{6crywy+FSwpLIN`-$Xc#YKo(`2)3NuTtl2W#se;hE5^rw4xYj<)Kuf zmG*$9tnI^68A0aJ$Boo+OAC?Hw1L;T0-XEjCXM*&O2>}O1J~Cf5Ck_scbL1|I6zUL zfMe{Y4CA<57P~}7kL)NAs9F@A1^@OXk^V`hxI{&iE{<?zEVM0Yvx^(KbSfBq>)vDY zDPcA(xf+89RLq7G7SP;B_Vk!pEchzU;D0%v$!|M2pMK+*f+<rxNwm^ydcEx->!`UL zKCBCd*4<Z_^0rXA`k=VQl4A$Zb!a-d`{OL>(>+d(rM^SI(I7aI?@2Guv!+2UOQ_zD zXe#G$6KyUF(2T2;)COha^h4G3tHC*o8KnoPP2@8i<2ZNLQ>x&Fp&1REb)IA?7}1@H z*5stK89ixzhK{AYz!JwB?5qJ_NGCd2BGrr;Hm`6(T@x(rup=2|FBt(j`N}wzY?^EP zoZi@#j_J8QIM1^K8>a3iDIQ0#H945Lz1qzRbUxvQ)@8z%dP8y{=MVH`htbt#?kGA- zfaoX0lZJF1x;c1&Ij6Fl7(1>aVOfTx?>^@uzc8Dw(GS4{&Vi+-x0h6Wzkt4tPoUH2 zKgKTOBE2-qdFCr_ak<iVz;9zblYUuh{AoY@^Y<fhA_Aag<4-hO^{DKeyUgr60W>2` zpWkx+n#JvanZ#tL7BM;1$AsrRgOiswli3rukzMr~WOr#H4G@r_B~^Z;ROk+@yj)NF zjINS3p8w%OWi6;uY(|M|MR5L)1;#BYL>Hk?OuMZs<FT@y&RAwkUU`+k-dlonfrBEQ zzu+aE$MuwBgt%NRuN#FHKg4B@D@nPqJ*hn`%(wqxLd<<kX=(ovdU&ZfS@7;Do>(J7 zD|YIEuW};YzM+C#yHm!@)0C!1iZ!Ucnml>7&)>q2b4seKj}W;%VRXG{EzGd*#DE2Z z{GQKysQ70ME^8J}&uzCPn^h@<_soYv*UJc-1TiOQ3q5|OkF<2p!;}TP$d6f%fZSe0 zoc$^Dy7V)D_>&ji>-z(`OSwMO1Wh>iz6qt0mvS?_0&*hb5mqjpMjc*wpx*OL+_|ub z1RwY2<(1fycXg+kP>wGYog7bszpmhw3)f*l_B7(Ef0x906(g>3seHG~hrYH9rA20* z)QejK{U!dvhoS~p<Qq%_rq9H)zeK2R%~UF~^*l*ESOy734?yUx02Mh9M+O##5nPsS z9@6>-@40m2iN;PGdmlw-Ugi1(O#|#q8)NdD^9)9bv7i-bPK~y=!HJ2wOx?FHklM&_ zu2Y8o`fo1zvBRFWgDbVU7e_yM$FU2vJ!q%Pd)OhAir!PIaD0U&z2-HQG_NY*H<}oc zzOz#-w%p!FaHN_yeqa(^=X;tBITD8%ZRVt<Qk=L52@*%=LnQ3KOW5{Yid^_-0U2=% zXioAv+IrCwM5L4;qT7`b-|>me%TJ{{f_~%M4_(;QC5YL6iI{$yM=e@naI%#*{a77@ zQ8kW4S0ES1XIfxyb_^ADQ6zz*lI(sDXH@pfAp!;zhW|{YCE`zT+~q5N+uRQ>GNEA7 z9F8jj)Q~<+B&CWjtnjwW#4x>xt@6mn!66+o<f2ameu|Q$5@R}P&m3w>*V90+^Xv?1 zE%J9nhc+7vvI%-su&$lu4NqUp*st{>^PRNl>^%?RPfHxFc^X2^KKJ5Sv^LQ^R{-+= zQ*<WoRJ~momXIPONfJVmBuSDu`&}m?N|H*FBuVomKdEHS98yV&N=T9<O|sXLBvcv* zO^PIyB+aF7fB%4UxvsO%e&4m8=e~DGLQ!iKUmd2%ewHkPtoRw6+lY0rb=5YMQ~1Dc zjhsubw>vO-gFpD@nhws@*J2&(3*ke?T&nhd$p@^s0{34<QekF1q*ooIEx&!4ESi>k z+!NdkM>@GMDH}?Xt-^)29$4x88RvSX^JdFUVd5Z3h)BExKi<2uW%FI>{qz{vb*BhY z`ycVAdX2zqxF%OQP?4ooi*WJ{Z_2rCg@JPCc%6VFG<?nq+FGGip)=$Vck!ALef}0o z>B|f-$1D%F*-Qe}6G3D&U5hmzZDM`?6A2x>Xi=^XYdv`t4(|6y^$US)WT-bB+W(Td zX$XF&@<cxH{Q<Q8`WOFg&Bk-Zk@R{^40UvwuzK?ekayr11g{tP1J4V}?S-AUwL%{J zTXGwV2iC!=ekVAhdX=d=*`eQqP2g;=!yAkq&Aa;q&^n#NtZD2&PBCL9_!<}E&{^~7 zfVCxLrCkyQZ4Rd^jyaIMYy_WLZVYON>Ui@bUxa?JHeI^0mtA_41QPeuZWz~jf;i+S ztEv0Sb<Y&C+2$+%?-edDU+usgA|qgNP%|DkNn<TDbU}K@4qz2lqQv-PXtJlQ-0`0+ z)jpM>dD0Q&@LG|~*Y<I5Kd+?q`6Xz$R)QaP^$n|;8vrdL6}Bo*@NGLs!=oi@SmL`_ z;ePUzj_<c(QVAiv{{?Nlu=E71z4Mf19a>zz?v)RnJ!eS?BW+Q8h9t`l+z+>D1e1!j zhm+T)(+5QrrX*L(TB3sl?%O#UJLDm1MC|2NQJbZ{NrBRXQ#t1Y$y}}MXi7|!ftG45 zVypdFlc_y3o9$00M{&3{yMsx{7S6PCQot3eRwSAD29vIxgJ&7$z|4FFhRrN;HOhs3 z5uce^<!Jg>{S3E_vO|BjO;jy(Ju3>7(P^CqyVs^&;XnQ?h5F_T{55@%No6uxz4*g= zrh0Qz(uRt?7KorLayfiqndFf_4qHB)VxEisAZ4|}d%<Lp|I!48=uV*-;i>EwD-&Fv zeXRDT3^l(9q>27Uz)sJ)5i)p`XvU!7w7G5zDDGc@=Z9;68rk4&yQARHF2{2FYlO^- zGPVx7M(vITOd+>{J+60WO@HT;MWPU08aEIfR8HW-Nmd{h*bUxxN-Vlfk3Lil1Cgx^ z_zSbBkbPq6YK&oCT^0Otsp+8dav;&wO#1aH8&$TOP*sOM>zU{dzPbz9xC_77*@~es zRy7TLH%pPv_7B{r-Z9kKviYW_r3ZDiFDKtDWPdivP}t%a+;DR(%C<})^)-j#MtKHZ zxIF-7EE)zGmx!5fQ3r|l4q%)@xV}yoJuXU7*@tkZeO`++_o`H^wM?Y>Kik;uFW)(d zC%yuHY8<>eWsNHz-o!?8E0z|pfW&j_Ff(PO*ltKZ42iTSmAj^BbmAX=zS)ZLQFoy= ze-0{X{lgho1P5!EAB|u1N}#2+aUCNU!_McuETii$isqW*vj>mZ(5K2YZ_ZxWxcUc| zqI#DX6~1GpYSO}9)fBRv|ASU7bI$U$9M(PS=bm{+vLPcf*zytgL9+4+JGC;8dDxC; zi_W^!hG#dJ#wRISv-&gFq?AGj^()a{$X>bdLs`|8Txi<f1!D>l&`2@6+}H67oZK}H zoO{hVZT+b7#fu)X$NMw!moQ5YdiNeZ7udk>#fjVv$wa7J5eu)RwV_bvG5EZ4VqNE_ zV&{K8OlF5W_$ZBoq@Mz}WmXusTQ8M~;wQty%ahS<pB!J3*NDL{M?rsTJ$GT6GR)sG zj$D;}Y3}A?$Z?ONkjH|b<!m0rK2d-v%F(PQN67pyv8ET5)x3TEdI)K5W`lN=F`aYu z{I-r%9No`})jfytR>!1i>f#)XKDw9mlg%lrC=8u6P3Y#a=ge$aEYt*ECQHq^v`_FY zSo&teSN4(3H#*D-8c;MJtOYvV0r2mP7PHaYfl<oB>tFniZA@rjmnPMN`?Te-U891T zl(h0Idy`>GWGrP>l?WNgZ@kZXPmnnN-8#x(F?ciqIIK8Ifho(FT4gB~oRoy>O{2*} z*gM_(?IiFXvaA=Lw1=ObYH)T<I3&Ikb6VaiP<e4Wth?w!QLi5G4@+0E#`8{aRk{{z z@;sOjT41uZpJ~I8OZ<3c1L`=V0YdWuc3yqSDuzrV;~FXYFUE)#th<20@Q(djJDaZm zH<m(-o|ILoreST(0d_=p2w7&!k^MUc1(#02C{t6G)inW9E|^33wE^OgLwhl7*L+xs z(V&(VO}7SViC^qpMcrGsvE$a4!1;bE-BJu?MM|qkLUkm}YWyuQHBu=`&Qf6b-r|*y zmZDom6kn8W1RHl|(&$a=!RehkdpMz&>&fZiBu>9CGb)OLf`%7d@1qg$Z=K+RnSGNh zb>E4%OV0Cjem|4d>gSFpy(5p;Wh7e|h!d?ZgXx|WidJYBa&14^>m+qjnvsFpBYu#^ z{t_xZZ;I=dR^i$6v9M0y4ePsG(7d4+AbUt0n5s6w^}+_`AeRXWLPsXvR09^cJpjC( zNoS8thK?9tczOLO#+a|;G`5K#<CGQ)8t?-%?MkTc=SP&2y2(066O6363S+XoVDX?N zrqbyEfi(x{kNg;Lus%j1gBNo4RiF8ZRSIGy1p`sCV>0a>ATYJeQ?cjKSopfA2D?4N zseRZ047qvuMug%m%K07x&Y#|tZ)mzo9p^l$ikeZaVg>EVm4dpl7wP$m=j1QHluwoV zj7+Ok;B%Oe#OPn>KjSOthhAYS<G!&MO>Z!H!&X=qIRb)rh{(7!8<bscvk<rG7*#Cf zm_|gAlV}*dfB1%=D+yvJ_OlPOi0Q{FL-Q+Nru|b!n8v5V9)Ure+CL0}UJ2)ocX=4A zN#I&zL3@I1>GqU)=ydZedR-61l$+U<_fW`2K3tE-1_#43q4T%+W+JV*k`B(#-wE8s zOb&~Fv&ySEG<_|PL-Ui-xnnwo{W}9A7slcG@2z<7N(*n}olU!s#l!fsv#9;1KMQM{ z3aJzQ*!p8~;5syl{^f~CLShoTds9qRv41f{y{mk1>lWH6QfBYx%YbC|8+7?Ni*9Si zvqBve_VL^~amLA7-c7?4rdLT(waa-Fn*`IIo(F8Pw(u^vpUe8aW1u=3SwQ3`ob=}w znm$z_^Gq!=pRkX#7b!tW?o0OdoHQ5+evLlyAl6g017t*<n3dPbGOVAH>#!c~b=4}k zrazNSe3MVkx;D(H@ga!C+Jbj;4vk*i2w^UDxbtNm^X%84s8Q45%6&P`rdN}V*_SHJ z)^4zMXBf?uTLW8nN{E-Ah{SD+EQl}XpzDn?{M1#ZwD=1*9$j2UPTw~`hkYfxxxkKO zI*2B`c>uD0t-N7o8ufqKP2N#uz-_uhYj>Sso90ThO()M{wT~xva0#-31}`u}^B6t$ zT1pcpRzcnG7)V{y!XkVWsMqu>)@_z$uP^8D1Dc({TSXNXzI;qUun;t_UI6FDB9=ex zFLv#$U^ZHItmT9gl$Jf`M@d*<-|8sVI8cnK*?u&z(TvWgMpORBkx+i(1NN!*piR3O zoe56D0DUb;NvNXgkp_^jxt-sC{{bF8)5vCvFOqTbE!bi)n8J3(z-#UZDD2t>70Z0E z-C7rSPcA}7^VxJtBZ9;gQz$?(8m$|WN%QIl=&-h-@J;85j%A8%CM}}vzC1qCn@QD| zK9pZc?zUEyN`_~rEXk=@9$b^o(#H)Vs+hGAb52ZW#fSTtl#L5bNNvF$t-IwiQyy_9 z+mm3~b!p~*djihU*h#0eUr=9wG`W71r7JI8NadIh7|k?bRm%s!?(xgnUFA{qJZd3J zd~=BnhGEb;PLEn6qeL~;cbJV&DRi#v#QG8gW~Fx<Rz9-<3%@G%$a)+IY%Kh^I)fdU za-C^b3LeEAIsQq!4_wkX$y+sCBQ;+Di3e?HpJvK^3)F(OMsd{NWhOA1G~o6<ee}-q zfv4Yx67yXxvYZ%5QZ=$LGxC}^=!XVK-WUM7t{*u!wRUd%$qdNZbp(E-#W3~cWi<MM z8l`tD0xXH+LN`C9F2y8xziKf_?9;PON*hGoHGV9{eiZpDETT!eYT##V%mw@9)6#kq zFduxMe<7F2C*2%N=PsWig}7xjV#pD8{K<1XuuhnLzS>1?Clz5?|8}enm<2cOkCM(H zvEX(b3HBu><Pd%gm9C9}MRSs<*1uBd(T!pu1;THD;HdT=q6x=OuNC(j0wl~n4=paW zlo))L%QRm@J}{O4y>OCnKW`RA6wjx_LE}InA%w|(V{GoFqvTaHl%-qdQMdgo_$c0w z#<S1Bht^*9<X0F(dfXHE4u`QRVGF&jSirjDOzDHI3FJ2$QJv0NY?8SP1|zNU{PRK# zvw4AO<4<6L=6iOicL>DJkq~!}7=yIXg=srRfmN~v3JW_d8Keu-wNJv&;$3vk^*Ao^ zO{Ujfrj!-yMLVB5u(ps@u(+_4MbxIzubffn+f<BkD)m@-e<vKcdXMRKykHR)?(}7R zC~UlY5Ry8g%O}Kq#zcQlv`UZ^dOG^#q2bBHvZLsH?kLC(lZLaB<KeO2Vsd!35N<fU z<Sq9Og7(=Wbg)pOEw=`Nq5KrG3i^o8Bj!+gZa>1BGc<li7#Cu82b&b@_}IyDG+>G~ zlnm;{E~8#yFQg+LU7rhSUaFkyugO$U-B(^eC>zK1h*`!QSxCOt%xZ+*b>hj%%&q(# z)3&<+V{NTy+2!dJp&iV8+~%?$!y5RwYm>!(S*xjJy*tVLOW>2e<b@q`(#$@cZgd*g zi|vl;^s7LL+&Aro==EbL`jU{H_!&W`%UfAiMA{AASBG)L`zY8lQ^fZVNXAnM<B53; zpuLS^Sbb|4+_Z>5bHTy6?o~LnJM6#-!aJ_RXEn=P9)X$9{<18G=lr*UIm~E&7b;s8 zq0NMal&EwAV`qs#2xXJz;3V9xrcGYAfAA}H4xyQx7FcN-(6)~f;MBU56ok1*zhNqM zhbn{N&UwuDz+td>CdsROB{t^8LD25M!AqRdv{qcyg+0q6`GgZgXu<j^0uPoKdW?6l z=fGQ0PW4By-=;(Zf*zqtS`IYD9w3P$Ca~+iHKj|Qz#xYcoRsc4=zJuiAt|Fs;@(zX zB5EZsZ7)ZD-g9{iemZ7M3M&uw9wZ+BLl#UwZlo9TA+V$_3H)U2X-?`;@Q54A)ilI1 zwH#?~cEUk=Jg$JhA>=7UPol|o>1?!FQBPe#(vTNEk~~JFlAWhFPWhM#Qq6}!z1Nxo z_6D<SF8jHZnpRxA)0<vJ9Ah%YF9qPtA8W&C5eqt$2Cd&ei(+aoV9+ihYdUi%QyuL| z6Ea-M`Rab!dMAx4g)El8#zqKxZ~!*wj)q~jGjLo;6FVGq0)p$UDRN~LyzZO?t$MRK z|5@6s-609K%-O^hr5<M!6=bQe#e&5IJY|NDra^p<h&fG^q`1uuEN#p^{_DI6WEK$( z|FsD@?DnaUF7Jh{ulJ%;M;IlJo67c@2uaPMrW}s82C?w2)(g_)onA)Z@OCG9{pcaX zf=X+>-UrO0=_$Gy35<sPlWcFGJ~(U*N6nH*+8}t<K72Yvto13n8hu8;5ze$&U_47i zOs6@s;wgWzG1qiwICt&jGj{ggIJR4EGW^_;1cSvou&Lt$i+XUEY6I24zkrpSf0m`3 z6-nT`!-mzz9YD`YM^aiIB7BdgkfqCb=8_W$*QU*2zDEs&-t<A#7`G2sZ~i0jb3e1H zOJ^x0Skqc!`t&k~={NZFwn%t*_%U-I*orA1dvWo}EGWFYoc0$JQ(thB`y_XPI<p?~ z9}_=gWqS#J`S=$l-Yg@DHP5+?_wvEY#{kOx=0mZK8<j7QhvXHD!RF^SJQO^iuI-wK zpS8bYi|iM^^Scb$kM~3K(?csdC*;y7=L}L_xEBrnS(5Y8<xFS82~3Gn7O&5(W?kup z5PY|Sh7L#;DiB6&)1-l9u67f&FPoG4kJGH{=N#-hpve4<`dCEIK~~|omkiY<i1~eI zo4_8fq;KKnjD2t$o@Nc^614DbC{wG^V@WoR;9<KI6wZF4tuA%kmUCVdyFv%%IXE$P z_cGUW(v&i`*YHz(-f>^}TR1^vA~0%^O__R!H{LZBB}Tkp@(PY%EPPgqUJ02T8N_D! z9A)hXV<5hzm?U&^i92%?t?b0K;m~qa?=b_(U2oZEGr>h?rvulFV?ow*D=v7MkB_=E z$h>OJ&6CTcDB^}O+4&Cy_bE!`QFNF8(viWAO?ZdFBS%9^p(iy2*?`QYL*V+&8P;Fe zB9uJsz-yR&`Ms3==rQa$evmlDetC=0%<UW5Mut-BM0J#voXVek8irfCZZOSVA8_s@ zBP@vPX3s)m$+}RJ4D6r7)CNa*um2qTAcFMO-=SQ`QS2Ch5q=+5#-5ZI&i>&95bcYh zvhV*fuRv4bZ@y!>m(AJu6YHqmeINHpTN-XQj1sslanS3kL^*|K!VK&l%QHI4b|vY9 z|JrF#Hcsf&d|!jpt{r3&f3&SGY{|x2byKmoiX`*49Scp{ZZNN{!$>ybf=Hi}CjZ&5 z`Mef;y6dG%l{rVjZ$KL>=ba$D`7N}TG~I9>^;O_K%ZoGm;^4^GaBP}4mpgh*1D2-m z!C_wEV3sI!4=kqwUV6awIC+Ep1_@Bo{>=4$Er1X1JuK+V3;gqUJcj*rgbbBLQ2cNn z$Lw8$mxSKt_q}24%0dY){8|G_IqH!8VM%CHodx@Lma(QlMUot~pN^*<2H$CU=;`&i zJfI^MS~(f;m=y^fOSiF>5sVxKHbU&H1W@BdaLDx`n^ZKCO>>mRpYDcYNBwAQUv&lF zUfzvIE5x)j@Hbj?)N<UQ6(pH=oo&Aq3Z1L|BVR=z1?|shvp5q14h1sNv152~;4h33 zKW24hM?g~g6VIfB`0YE(c=7rO&hWS|3^|ty%Pyuu$JuCXja<h~gn_WoWCt~_=14g* zmUGYF2y^CGutxi4PL3M`1=V75y?vLfPJV)s5o^Im$YLs9e*jxj8u(z>m2}$38dkRj zv(=JjP-OI!8+G<4yL4v-yJobPB4%G^H>N4z!w09Jb9XURsTDGpvudzH^E2(f)yXW6 z{KL&kAuu=18h(Z;L)OPJlo~ab)EX`_qy7{eKjQ~mYY|EkAKb~%{tjQiU=(I6-)9*P zztBZB3Fo`<tX#O4^^y<E`)kj~-`0a`?KeRqx|fUpV+S)Gli;RPE)Bl=5rVYl(FW&p z?7;Plu=s!>z1RXQ$~zd9{|H=L<K_Gxg}0b?ZY(us4q;mAx6yyfde$ao0@u<E$+asE zJZrSU;^bB?_FpA*UA>Rq1NH&8Xe0Y<Y6IV%WHE!&R($HTv8*Uc0tUX^hyh2B;h3}K zwEasADa;N-m(NMyX_YE)gzht~BkfGR%9dWoTTx-ifQl5mbL5nkiSbi|ab3Vks5%i& zRtdw%QKcAKK4h_Ng*C9r`wKJLRsyNshU{W(3`ZJOpl0`i=E%;1S>XUPFBr4nhzs1* z2}|Ka!7f&+q>3&l_S4Kq!r9x~gzs4S2vp~8fV~I3;I*?9d~Nu^I(i<G?@0|v(W@Zw zPX|cP{EIq|Mu@WmWLSMpEhSAC7(_?+VyXXTw&n9Lyz4WOsv;UNa8?E$agCy(+HSCz zzsdeBsU%08Ai)K81<fxWqS))HOg8T+UBA;p^>?O=r1uV`75+mgPpb*F;}dR(mS=+D z>}$-)cp<y8WFfEjwwvX@ngmtHLb0ZE3k169!Go0p*#;9s?tH;IGOOD{W3E1;z1uxu zv3oJ|8{vY=%^tv7diiUuxtQU%8-8s$2>Q)4!R^6l{>-x_%<||g5ai#OlIlQN2S0I_ zM>^45p<91%=SfmZ@8O%5s0w$U)gX$B$H%kwQ}WiskfoT8>t?tB&iRjjqu@b<77E?) z`m0PrcM}%BIt452eq+|eblMhi9IevZh!gnAYFEl|m*g<oQp+H(Ba0srcbO%BD#iXf z13ECefsNeShEXHU$m3cxE~?3-48hYW7IO5i_4(Z6%fVDXd@Cr-3WZmz6U3b+u9!A6 z0u~7j|E6{IxO<%nt=ypxeA7CxEGcD&RK`JDnZQ|B<Z*oa0p^gNLgh(@R1#fC_D1U9 zx!@IxFm;0ajU%W}znYxkIJms7#t6+U_U-lPiUrDta9Dc=^sI^ET6R34s97W6RY?~# zKQy5a$5v68(+e;^H;SxkJ+OWcpm?kze0X(%9XTyHj^3|ix2|*WaqK)Y61wEGt4E6$ zdz@$a-D}Y3*fv;2Mj*0SPGbTL*tfC*a;Ruy2^}+8S9c28UwB8|e~yBJaw;kwB<jeD zqlZ5bVpOxJbx#-9?(T_|z8rm9F_JPSYq0KJvq?w#A_Ww;<MkOi5H=<j6wcpdv!CC? z?hyr8>XFO0JCC6$v%fQ|KaAl&>56hQGx#$@aDd2-W_M&h;E%5YD|)>Nlm9XeLJp4+ z%}EPH{;w%+_`HJBRxqkspG237cGA7W>5wJ3O+8}gqF6nOTrM}D@dgd}alQ!kO2!Ct zsK4x&eE>b2@PPFm2&GL=ufjT+Ui3MA2hJ+Qz-E_o&_7a+vU*~8rETkk4EZRUF?b>6 zYyQK=8~d66%uMRHI0Uc0Zl>dfH58t_N8HUZijFyhuG2!Oq|lr#zLbpvZ3UK-k~6i& z?qwX7k=*Ds+VHKM*O!dKmfSI*6tIpwJiBo>)u6}rBKD%X1au_FP)CU@Sj?D?7l%ny z7_U{Qb^c3O=kTNC-Btn;jxub}8i7^)K7u{?n2$#*!$Ge(g{2=m%M4AHlZN+1w6HYd zIvXM&h`)wnw_-MRS0}9cnFtAT+re(oDApgHOy-mCFn#Ztc+)NgLZ0lf4llpQ0^15i z(mj_*EZxVNXQ<Kk!vc%=eF?j5HGv8<#)DVe6c}#s8P!bYgFJr2`hW`lL0m4mPW;G@ zWJQR}GfmiLTL~!WP-THZRjlI8C*Y5)f^~+2VY};Qx;NkuxmHbJ%E#)tN9SZK^jFn` zWs@6C^6x_fr&t_&br{4}jHjSGW)x;(0xg&KGbxESay8WlRemtb8Qp`I(_-jRWEFKK z@1*#r9sGW^QS>K#FgnZ?QD%*h6<!pM+hkNBaKdSN9I+iYT~>nc9`niJ^c3p))W;kr zoglftg%EN%^hR&cSXvo<mCFC>K-UHkU*2{UR3?3ZnP2lLQNbF!euk4xayr{^-I;9a z{84{*HU;RmK-%YcE_-(|(=WV%vbl{|5xtoV)YQZ+L&i~mVGPtxlY(QLHi6aIH=I~$ zn{Wr)M?-Jz<0`-TQD2556cyM}(D*g1{6YmJZobDyjFTkoWEZkinv4H^oeJ06#)F@% zjQI1$7R(PyWA@>pkmVvvY+ng>$uEQMy@k*%@ZGoTW-{@T6dIdhK_;DXl)vmFYd>5H zkH5@;fz=;L!{j<XY`cov6nzEuV!XgPIKVqE@L`Vk{Apce9{g@N24Bw9umHzqywjME z$|1inuHYE?&edjY+E+Xp8v{8%4uFHsMle`;fiAf?0)A7suHGl?b*ChtjC%m7M-2qm zXEF3*lsviJ7)y^wO`#X(Zcy8tFxD74p42MaMGG%XBUkC8Fs|_x|3cax3U_FWx0Y1^ z`b@zt-7MODc|WFIk)oXYHN2zsVrVsU<nrugK>Oox(X_sJnC~Si*6o-~Ew}W@AZrAS zivG)54(H>;djrKQCx%h7FrU&%O~Mz??6JCiAg7lH6k=Oien=cil65P{q1zSeudF7l zK3y)us_9DLP)Lg0S8m>J!t5XJ2bQ~;lSo;JY-tZ4GcOtE)*KXk5XtZ=au&Nabsuxs zE)6;9d8~cXATevd$d>(WV80q{VDY~&et5|v=5odXPiv}RN90CI`nCjjP2CJ8e*-DL zR*T6L6{5wvZTuGNCFM)<cY@ZmCbW?EfEw*?-243~_0Bs^u3=(uzjK$Xc*R5ACna{F zb|yc^`4kuo>cjEEe95>of_L7HqWQBMQHmm&&L<0!3(LZ?x&z#~{r%9b!qLn+AJPaf zf%l%Z<f9q}#aFUu^OqUqvn!K5J$f7z@-C8Rcog|}6{6cweSxo+O!bDoeC67a?9b34 zoN-wT_{*<=)O}0o<A5l5IQtHiT^&zjh2XzXFv8X^UVPB;Jy_a&oC>zq@D<zU(_ObZ zin^wWiyDjQ%JVihdDB>`7xDvswNBiRAz2Xf`vSC&?GYH;6G1;$9j@0)Q%c)$3Q>8@ z+P*yn=UMmoj1^ybiBbt6&!op!%XW)`-Bls)bP20h^r4~wjwB5ADQJd}Wl$>=J^MNq z5(gx~*BOH#B<wzV8M=VE`&IZ}5<y;73*oX~1jtq8vdO=uz{1h9VeFsfIBmTWq^E|W z-Lzn~%p)AEV>bxr_KhOr^dZEWkFduBwejg`6;jv~34G)}*lD#08W$AdLB&CoWfVe= zsrjrxCm#&$bFpk+F!UIdiWaOSG`kRtsJVzDx<^BiOEy;*xC5g12=4R2f7qH`d!Xn} zCUl;8&9jivq?<Pdj1FujEYw0P3tMvWNucC2nv@y7hyGicLsiC7oW_P0?wr|N$a_^U zuuDbYtbYRX0{#R4HVH^t7(&CIhq6Vw)2VT+;K#jh2IE(xv+i-NIDL33l^c(ul{L;( zf5DG47WR@E#%7SUFB}A>7B5>=z$t#Y%bqzTb1j9>NyYvL)=xdoISISlosO5GX;%*X zobE!^g`@EzcND^G_Yn%2fgzuq(EWTV6;Jdhx3Xh=<_+Py{qP-*f9OYfmutD*=Yt^4 zR30q6_2JN&3|esNDx`aOL7KLXz$LS#-`SNI>LT3xxfAHT^AI0Ax`=;>W)-2k)9AHZ zBv~D3<~OPcjKD>@u+)7vy_xwO9&0tREZb;k6!H$qv712uzsD?Pt`>DY8X%4xU_s@3 z_9K43dP71<i&-674_h31%TN3lOuCK7=)iIdczp9Lo3L{an%#@WXOqse`=$=W?B;OB z=~eu{aq&=1W$fL-kCZ)@6S!HCWT&YFA)~%<?)%Ev(y0a{Z(xQV7e+FbtwV`#vjOkM zT`XH;3BGKq!5AmOw~)ROu8jYRl81V+HG42$uwQ|_j-Ly6G6QIn;B_i{x*OXDCDXHC zbMTkZVdmg*9<`5lh>S|yK;HQpe7jwZRx^I1o~$Ij{i1twgYP^Vc&9>eI-g`M3v|i% zk{XL1n#T6Gzvgu|?SQ}E>*#<@9@rSg!7AfG*pTT9uIp?eEh~wet(Jg0j*X%S$sy=A zL5sZN233?D*-AJys@&egLdZ~i<K&`etoqI=^m#V{KTey;R)60|lh%!*-Miah*#QKJ zk^_{k6G2$qERxjE5f}s2@TX!4ZL(Eo3ZD)@zD_HpTpx?8q$h*(*DX*nOaZ($tRPw4 zTJBWk76|S+%YU^h14$!KdJ&``@L^`c)+tX|#O_g$H6s>!PGwj-mX@O0Iup$PBPnE- zR7gWtMI1Fr5?gOCfpQ}g@JvpjUtvnD`n@8TGJOb|dj3R>x2`nZDhDe49<ksxp<pa| z9eUQ@=KJET@aO$MFsY#iwp_O5{q9cWevO|6SJNJ2K~g-JJQaz~74C&mn|oPUT?SZw z2!N&=dF+?k2S~gV$69?pp-II#(FpZmXf!JYukRQ6zM_YiZhDNhWTmj#m!)`zR-idU zJZKu8hxwgS&~7>$o>e%Jw#j+Q`nds&UYb&CA`@9|jt65$5sN!1xO5XD*-bxFTI?ja zT|5NWs9ZX88a@l&KRm*A1oWbsqODlwSO)KZ;|KZ|KEZ99wxVjCD{~e(;^h4X)N-kx z$sWvuy|J6=d+kp8-Tw?_J_#N{1xa`vGY~gA^Vm8~4l3;v!Q+}DCu+@SdzNVlS)*#y znrsK|>Js9kO@UCoUQBu`6d_=%6+C+DLA}rB(us$&*~rhS@U`t7$}HE0fKV@h83m-A z9?c$S3}#JpR>9asYe{FvEAaXj%PFg@q&j;GND>W%2AfB$Xy!{yJN=fW50C<V<9IS! zWeN4CR)}1j10dop!ummW(08esDJhJoFy1*CZbfe-36*51d-j2a^dR$z3nSxEA25FT zc-Fh47_;vlWW5skRPSa>Bd^4v|H^lG{-F&>sMTTH)eGpnI*GfWl??4BnXJp@AWO|z z1V`0hz!j4sZbx(kocQ_(77n;ZV~V%Kfb1~xi{VAqNq1n=%xSdhwJS)3>X!c!_?$m( zDP#0KN9a4#hz05|x&Qpqu>J53X7hI_i~C%HXFQVO_?TSw(RVhRVBZeT@uLNP&KU^& zRmF`v8^j*{6_$CABe-?C(HK}c2O3`8LnX5@BtNr-7S=}72+a(fQI!u7AMI$9Wdg)| zn?vAyFN(V8K|V)1NqhQZx`koPE&VLFIBK9+RYmZkes&}?$vP-2Tm)ZAFT&&y8JMNA z4~&clfbr(hu>biRXrK6wCP>%7k)8l(c6-Fw)l0nImn!CXJd&y1m&c62RI1j9#~t7A zvC_ZIV7O^NtVlHxyg$}p)S3*M3F*Y&91rgkTIrLkI~cqy;fH@!5eHvV;EGn<CjHg> zVaz#I8XtX%#ZMlGbEba5$7Q8xzP$*mUE|1Dawhz&oh)<{231TMvyhZivvIe(d<ARl z=084@t{C#{F|}(ca)!>r*-s*q*ZG`Jn~QxZ{>O6=--%%xT+`W-jW@AWNgiHDABIm? zdvIfYCFGdSfdKWRc=2Bud-BGIN{`#or$;^XEkOqUdn@c=_e&8gx)1LSywE4Sf@8nq z1jj=V1kIcS%l<89Y1fOfqRvuq1PvnR5w66RWR|yW)*w}i6Q$2MOd;Bb%H!oVVVuii zsOif?<z?q6P9gzDUa_VLZ-tJ~ybtAXLWYyd@ik=o%N9b?@A6g8(!k<&0am0Pq+3xn z_`KyAt>W%M$FMp);BH9wpPquA<+r$jXI6k|LlhN3Bt2X2#m{XRMK3=uqtxfx<W#tk zs&72!3Wv&qWa)4ix2Bj5)jeYtcH6lbbWUua@sb}XuMg`t45PyxD%`syVej(M4eEva z?}6XOY}BRzIGZOtU#|6N`Cj0XuGgg5Pb8^k_#*lpnJTbRU$EFsk*wkN26{a8G7VHZ z4SP-2qn>XWTcLNKjEBZ!Nk=$n+s9jbuPP&nr<)k}{yK!oZ=lN1X%sf*5sZ@9i)Kyx znBLL?%o4I$KH`h4Sav8}Q5^*#3ej9pf)3rAw-~%eHG|_KftTX36{Fq%uvh!_VA<i@ zI6QGUbGn*OHUE8Mc3Ui2?VZJxF!&}Vt_lUi!rQ1ZIF{a@k)$~?MQ}<cm<-I7v08H! zzaXR=B`gn9+qoy~d}<@!Qwt)|<y`!cT?7Bg=z&CU1^0ep8XjGI4y*2Kv3-gDm{ubv zyx#;afqpYNT$P5M{deKo00q{$=Pt@#OlOv_8rkm;a=^Zx<_7y%u$r<eUiVxk?pW(W zrs_LM*~*g21_i>=h2{LL+R3=>^$sdqERAZPJ;C2Tf|dAehoqQvHqC1cU26Wsci&t{ zb|&`VwpfB(rW8Tmn5A%6Qv{3k?5Ia0iw`@~%SNA(rePT>BzbHo1+MYnjbu+y@r)zj zvO9#9PAVlI9e=Tf=@fb-PDSs{0c6(jgx6}jfC(PL8KrF^1=kG($%Nyy^lU0w8XQ5} z4+8g9rJbeyXHJ%}r!ncRn3rYIOx-sLB+GcjU4yu=MM~7=+eE%=mGJJA4*u_s81nVn z3U#Xs*kFNCFr(@SYrKC0e=pF3<uC&Zuaq*~^+h<tYz1B${D%4Krht62z$%!m$E`3t z1Ha{+A-~cVcGYUYp_+EIcW>v?Wt$L-)1mC8I%*tS4d*6|WkW2s3%_j>;D(_B$-EZ$ z>T6`!o&7WE*>FSn>i&+Eg}9+xK@_O1)S+mtI)0ny3X=a8!1ftl6hGP%&u~f>>%V@L zW!)}h3GYwBp0;*o66nQ_{O}^voBPQxuZQ2{r@>w+m6PwrTyW|dNB+m%@sRvuwDibi zi4zqm=AfPM%qqhc{n6Z;ttAxl(Gq?N{m0%3!)dYI6I@uEOKLZVPz5c6!9PS~kUj*R z`s4)$&2{#?B7>7zIuL%i1rvUfB&81)AlEa70vE+#)S@X6RUb!<@y$^1x|>_O@*gJW zZ=?MDIWS<Ymw1<IHT(5D2MU(FpoV33%<=s=njj~Il6NOiNYNp*nCMB8^2eb!_8R(K zeZr0#3B6uVBhjEpC%UjpT6`#SBl`Yb4sAg)U^?3fbn*tnt~uBF?g!3P<>1OX{j6xz zKNncGUU0G$C!u%fMR1-ZSMJsjitToPuv^F_x5lpKTIU~Of#pK>u0aMbKYzfKTuwup zcQ}qV97HJ}OW2@Q@gNpDVkTat{EyzvBpN)Fl6Ga$1TLJDqEJ|=Aq`E3Gbt_kCT}0o z!kcF7#lYsdaNp97DLlz#>uh7`P<}Be_V|GBnkx3=c?;@p*TKb#x6$XC6S=oP=kFy6 zXV}(QsJb`|>V@8+r*$axXY0UaXFC?`;|&G@h?KXCetfK8Y3GHU@QYixB}<<i_<xvX zo<K=0J)*Op`|)hh5Z2!9M%``_@ODxPx-J!iobDL0wL=(azxH9N*JsntYjwQk%PKtn z9}0UaVdgjT6)S2t;be^>x%ZLk@DRH|cZWG`KiP&Us;cZMU&GigDO!@EBfe`dIGUe& z(UqRU^4!#|SQKuDxj{o{!n7(J7cBHa9VbzZ(I&8cTZbM3_f`6LCi#Dg7nmUG_~~K@ z`z$>kLRuR|fB(KjogEL+`<52YwK9fXst#~8Zxug$fh@ePoCaOS18Lu^w@@6h64X9j z;CA|K0|Sl893Odu9au4%^515m)2gxbwzw9DJBP79aY;04{V|N{eS_IXjl6}+Mto5k z0)niH>mKU_OBWu;87+>aJn{f#nG6^9O0i6)Ck$>4i@__BquGk`V2BX9N<T`hxs(7& zD&M>tQ+he-R(;8Q#NY7QqJO;nTHp!~Gy+-O!e7NBD1KiQ<R^$JV(@?9motkJUpkYI znLLEQ4~K7cYbYy9hf?#6`HgoKP|2_sJ3T-1MF-Yk$j0Y4EYyEOkEAwm&UN^^WEm6< z&4ByM29t{ELSa92n|~ZNmRUK+V)2Z{RQW}g<$YO6BmTIPq%c|!xjvO%+uvaWC%BQq z0U(_<(p;!cAtXJwgNTENuxavHmVZ=BI3L_Z@o_O7D;xktUeBOu?-r)j=FA$GlmV_O zwq7HO=HgX$vzPke%;c9MJ$Sf@9_J9Xy4%wBp@wAU^n<lK2|dg+iqQA=A+E}^hx+fQ z;p-AB3W~QDya;w+uYQyB$+7{3TQi`4l?)%T@)c8hIuR>x3j6X?Q{d+tSI|_R&R#mS z3eQ9+SCo8(FL^M9PN{^$>UqXc>}LZ3Pi4u@R)W@N&84~>>+xb_8iYJsQf}$x3NO<P zSzv)AUdvn~?1UfU+Lf1Bd;BFHSKMRywJY)D;BICreVM6DuVLC>u9OE$NfNys0MRU( z+yxG8u=`syu#ch&^?lg5!I4z%WzZVAt=Qslf|WPEW@DRbIK2s)Fktg3c+{Z-+UeWb z&r83!Ka-EM4a@BD<ohTr*ct^9xlYV+AfeSwS&B87Lv?o!pviM{PVAWsNrTR?<*F0G zxN;gkPRilKu4+Ja*AXVKbc|GX1T#h0hX#|^qp?Z?6m%bl&q6QLtGba_ZAgQf8Lm`r zI*5g*>_g8XMI`Lv(cGq)-*s#`)&Ks9sC!CaqnPu(Hl;AN_7FR}<^|hxWd_|n7Y#4R zPluB)k7M-9KyrT2SN>S&PgFj*%>_<z#gnI<n2elGg?#jGk`uCRZ`Ns1qu>M%9}vNu zb&p{{_5;Y)I?HS>oPqa`x=1Owmu*o##Vpzx{n5V+N$K7EE1e`(uO>^L!xl25E7PFl zvfyr<U`Liql<3qhX?RfmnY9~7aHZ>mF<Rz3@A`BFX@)v5^Zrq6^n+~hjd{*~EW1sk z4TmDTx{mT4w4kY~h`Idy!#%DMk=Nzc8}_d+iV}1BFyEw$*+#8m6SFK)!{a9YzUjxz zhc5-u-a6#7A`wkDTL)fV%66A*1C6$8G`sdFU8`D*{r&<ss5b!@cLp$r(*xO)c_TqI z@(nw-@gV5-NYYOW!O1)DE(Z86zj-od5BZGxh*5X1vOW`KLaBKorBA)w?hZwo_jx7g zWh79p<6$tolK@@uiBP&>Bed;x0_(TWIOBp)EZHy~*~x0_>;b(vFuam7S{9JsP<1~4 znlfv@Btqwto0!ueMG9FzL3DrDLw4XvJoVq1N{h#T0mB#3@KGm<er8UljJ70!X@3}f z76d}vbzz4rFq6HEC19>h3>h4#7o{vb$Q~}}WC69qK)ZY|ea}ec&zUNKVW2f;s0lj` zc^i~46tP09oy_L*VDM5DLFLAwp!e?)S8VBvKeTn(3+>Z*Ej1H;^@fT|hg@PZ-U_gJ zw=%r9)1-R6qipihU|jh81?zt%qNZ){@xkhBaC%tHoNabOv1$ca)I_53k_UYL<1QHb z{0OwnQ^GQhT)`1G6BLHTVZO2t=sUNdktZiOgRV2<fumu2_GWmMS;j&-i(te0>ChMa z4r8?{xNB=I;Yq(e991=EX~n1T%Hi4kfsRD>WM>pgtO??WOl-y=qX_7q{+b1NUS~Z| z)Jaj;`D$(v!D~-*(jBMG98LE@-pIkQGGPpa9C>e@CpVGg`4haMzAwxwE5b*ieQe~& z2G+SEU8MJ9nz(gCae2n&R^A{cm*23>9NCq<=s!%KDLpxhV;eTHtYIl2`V~&ru>o`@ zunjM}MM9i=Av0Uu%&$9Viyqr*ndseqkm)>t1@Vf^BYizvJKGT7o_7Z?JPy_KMhSc1 zDO8nY3FG&_W7(PEWPH|`o|~nxCsXG@$%qGNa_ZcTi@GZz=S(O)yqn9JzFLYY*-N4D zwISJzuY-k?V=$tj1D)k3f!C)Hc2C$H%{ASLIS2Y!)xnRfh4ZIri5YCm_{pLNGi>40 z&4a)=MQEmK*1YNu)eEjztN)B?%;a#$n{EV8Lj||&gdaG98$lr@KCGz67G?V<gIrCl zzyO;}-si(mZEQauo%=#yC+)!M&~yy>?}N4GyCbkSvqgB;FLU|B2E(Ka=}@H5!@2ic zf<k>2u=G@V_ICk`(s3sv*OyFE>;PHTuH=;WlnrT9#NOE3O!28T);lReF?>YjfwH`m zz-8XD@io^hxaPOb8cM<E{h@2~X(sygi)-~Pf`X!6Ua+yj6=hYBs{F;)c%EdPo%*Px zxt3Ya9149BQgmot58ijbP0Q62=<V)$?EB9dHtBlNhs6uv%5?+ywtpP;uH8*NJ~cEq zJ(!l{s58BaMt;xsTd*l@75&^dob=i+fo)$If2_R<8q$UVB<=_8>>u3hxs%zt_B6<J z3MHTSiBMIf3tQ}mFz?(@l;oN@^^*%(kkJCcJ+hLNh6tRYjr+M}b54NhaTrTjBe1*u zw4lm<KE%uA(!mR>pjepk)K_@HL&XV9p;$$1wX%~(g?eg@v4J0t_Tl${anLW8p$&y& zaq!9iFqDtP8qaV_u>Z$WU5|6QFDfamN}o(NWMQH5Bl?>+25RIQ=!j)E{ik}1f4N~0 z%?&BQ-`m0{zsL`7?T?3BC(Pi~A~h&kwHf2vfF1ZK%p@j^5YFr&;A|evUVM-yi#y6} zws4oNxGF)F-cM-Z{x-Jf(|9m2c+4xUo&r;f6S3P!o;3echV4FfV7cEBBy|?yo<WA3 z)gL()yIBsa+;pjWW+$ib=ue{^Bw0XcES=g~imfY$LyLixkP#5Lx9y2^UivhYbY-Dg zjTuPGcHmRTHCU<RN-s3;v2VF0IBUfbD8A^0_d|qT$SHqO+MGh#H`5mGNEG1h5l>LN zViQCMJmU9Mg|m=HVp?<7gSOw2WbQYPVcPI<)bt{l*I2TScAXf^vUF;h<HF(Sz9WxX ztv54|y;nJUT`l&XI!JJ`H<v$ur%r9#4scT6pYVFJG4Q}uM*LTO9Nv2^@Ey#zac<=y ztY`T#yu$s%yvYUFdeNHZj-0|oW8_)q6D9VhxEU8jJf^RbMKJT;A*_D1jq6N`7aZY_ z@bFAi!3RHw*NZ76Pfp-CPmP2>{<COih&uTM9t4-(Ehu?$EPJ1zKo&y&$17(wOL<tq zw$;Uf#F6RDKlL@f_OyT&=^OA&7{ioCw(->l4b1r3P%t#g;(frDWiQGgn`g=F<keL6 zLpzC<tJagJ*FkujAx|MDn*>(leO|db7Utg@MeV1rpjYk)Hm!0U70lg4VL3vdTxBwj z`7Z3Ab|s>MNe1Y7y<}-@Jom5k5(f9kk&EkQywTc+TV4yUS>euFdb*YrM3v0K=#p^2 zG%No)<USU?n^msdJs6sjf3c>468y`|gUtHrc^q7CPN}|!QD@LHda^;9?(KNZyw*gP zN0&V1XPH~l%-ykQ7ZVIBx1TekvUw2jcrM@R6ji>Qicr@+3ClyKgKE}#%o{C+{<F>O zMCNkHr`hCl*b0^Y4&;{q^F#8yi~&*-<Tq*wZ@Bs>sW${d$QB{PqM1X+;<;iyfhln> zE*Jflx={8XQ<RvaNWbDt!S=8-&95B+r%O39m)0ON-7@q#wI5}MUSdTbJ@Cv2UG%zg z!8+dK9XIH}U?}}^LijFq@xPrz=|wY9K&7x-*BwZW!j7wQ{Z5e7?q((P)j+38hCM7T z#+C?AkgQOLQLcq7cWEI$)@8`MN`X|%KA60II9-@B0nJQBAiZWAm>LX+3#aEn{iHYO zw8R8Y6pRp@!OI~3@jKjgg99OFfU&E8VCeIoEYS4{TFR=!t^u#G?tTr5{_bG%BP&>5 z%mvOdPdMil37#KSdFFO*29>FP<{$2_68Eu|@=w;Xpiv{mw9UL2Ryjl9$Rn(@Oq12F zn?tV#?592_0~~Qo9=6vUro#i`K+WhQUfDZ|i@2YQs^1mhQN#%}O;V;!`|X(Q+oQ}Z zB$pOY1yjj9$v@kgjt1w2vw>D7sXC9Pzg&*6C!0h&Zo6Xs_M5ChJO<|ePz5vTS#0zB zb@c0}I;~nV1uVq<82#Ta-t*8nP<@|9E?b+xZ`nCsZr23t@EI+*cJ$$y-3;;S)O%>@ zYAkd=?o<64H+Ex~2ma90!qxdB=-T;v=$}1_uJ^garWJj-abyikE8NQ7j`YQy*$Nc$ z=mA*x6ruR~OC~eS1p2<3vIYwY=<Ybj_ZaF^`pYA%-$9DHjB1#E&m^)}$;U3*0?*Dw zqiw$mYCnC0c87CNR_ZwO<Ezn6>ngt%x3LG|kJ%MtHyFPw1J^V+;K;z?-0v?zpnArb z$^}ot10nYk)E9(mj}Hnt<67=>s62d`Hv+oX?4hQPI8>VUN|bmz7E=;^p{^{Q{nnQU z*=PIczEL@JkDLTU24`{a<6^MzYXO&f@iWd`@eK#K^ztL?wFRfx78rYbBxEkohP}J@ z(Vo^<Ov>&byDYIC^vZRpTf&gK$CyK_(0zI0Y)6+8USj(~H|(4uM~6yhpl#zzJlik~ zl{Ds1%at?CM7fo(Xj6pU;$h-*85~IF7O^GeLrB|eg-EKYhz~R}L*t)r(DF(HJZ>7X z<{PJ2fLsJyQgs?G+Ud}MGFd8=e#@(F9>gxM7Jg6V6~xL0wshgLz!Z@)L@Dc?_(P`_ z&#P!seE53w?!Qdp5m)iT$a&y#qZlo1gnn-JGD;qIls(IG;eCIOWGChifXZ!>to)=o zwO-0X)3|lmbta#E$UDfi$^=iX$ywGc;SCxO7E}M2B5?Ih1Ao~|cvx>Iv@d&Fo^a?X zi&Gm+E;5an`X&+CoNViYp1Vx7><YC`e#mS0?HAR&&%lV~hWH>N41VsJ3_C*FnA*`Q zKH1Hfl7$`39<BS#=HE@0;yoVbXs6+l*CCv%!)S1OX2U{i1qbArFtqUzy!E!nscrX6 zI1{xL(>f=LG#s;d^B*PPHm(+x#w0PZ)+RWYt3iRzA+T=8bgFF~L2hR+fPBj`=pB;4 z?rk3{{O_OmFUyx>(5&ld67`vv5S3VOh?&aN4XZ$QoDNf-*3GFotq}Gahd|<6I7%AF zgPo@wQ<5CPN{>&#l_Lg{<x5>Avtm4%c?_b>gKr@=rNNN%EyB!FgZ@2^#fvA$!T_5B z$ga`=(T4#f+xmqS87%>+?BVET%Tc_{5bzy$1|qi2XD7!@V`-@fXPr6lYV~K{p6Yyj zjyo6jQ-OR<;%Ew%klfUdC|SFJG%gshe@y|P*EACLJeQ}x1*y<JG!W*@6qu!xC%_^r zZ&2X>apDFu2%7Uw@Q=SNKk?B|;1fv`zA<NBZ)4bp`1|aEcsEPjp+#pC!<ka%S?0KY z0QooQ!?vUrHnqVLPAnWj9W#t+zWz5XHmg9t8c$G~eVs27T+DyGTbR4%7W~mCxLM4m z;4=9qY||aV0km%*Tv3Wd>8)~5mKDH)-wF51T?d&m7l`_A1pevUSPBVWhE11e(26%* zXlQ<x>pVG|GSwr5zUDw0u)_qRuFqy2UDH^>*q`iU>sA=%bDDi9=Ge=Ev7D_!44Qa1 z@;xonkli}~BmWL$Lz86i&eps9-s5uQI{RI@#FvSvpKT+|R(!c(qpZP7xehaebg^pU z2)NPR%f6eRq^8bRu2bNB)NlXF7yrtDb7O-3$IzJu)YL^`xLK$aNm5iwB&3q0?pdpR zO+qM%5JD0Xk`!r{G)a*pAqh#PN!_z{LJ^Xbu|hJFp-jnle)YHEcFx{wz3=m&)4cnn zlV3~!G^gY7jRwrY*pr6*ea(xWA7&2CQ=#+DH&N9zM`pWX3Bkq-EMWB*Dp4uHjSc%@ z(~I#S4xPjjhUlV`;xxpzHYz<3$^5!yxOJ4sG*7ic?-of)Fcfk$-4kk3pV~9!1@oBS zzhUgn@vr2z<`1kGqeI)`#puot!qLZ1;%i}-?YZ<F_*ZO#VF}0#zg<N6!a)KXWDI5{ zI53%Y@_eOhD%AN{aJw{m=}F!=vMKupvJVWoA|WSXbE|=O@j1bpx?Q0m8Q-Af$6-?6 zG9PtjwZgdgA|@_*L^I>ln1sX#@vPECkd)yBmJOcl-THh|OON80dCg!qq_d#-urlPv zN6_q8Ga4)@$vs&+3&Y)dC`?iX(@YPLxoHNp7+c`zxutA{tuK=&Ly%teiC4Sv6Lx?9 z!ab>f!7X%iNAITVTu#3S_OJ3_v-g)!!}RSm>*m_40Z)<5FPX|ZJ_^s7^l>a{$9g_r z@PNgSb!C^s*I}KPh&?w+#hYig;LY-_IPp<DhQD5m3o4HAo9u3o_Ji59JnthdD~#e| zwNqH@KsUCnBMja=&E&J!i};%0$Kd_>9~IqLOyB-Jg|DZ^u~VEjdp>HojYOG076?7Y z`1@Ay?a(Vyv?j_hazW$cjJFKRri?M_m{Pr-<@`633TE!7jH~-$UH>pNpL3qo<*AE* zm*s)+$OyVUE(n!f{&B8z3`NHcUs1w$XY3SukB?XDp}di!IDg$GasR(;fe$vC)yfQp ziQ5F(Lc0-KgxbP=3q`z=c8Fm1Nc1$wrH323;ildawryP!u>&zUx-u3d-krs;o(K5m zX#q{0^p2OBaszwJz45`;W%Q-d39hVD$AZ5VbS5GO>qhCaiSK9OlOZ$lv+!Kks}Z>I z&jpu#Mlzm`3CBX4Zn~a$39{Oj;W9Htm}B%n<hW@a)!hsO>k7dOy*!r|^aa85ka8M( zaRHw5Rt6i-TM+oilqvYmVDIb}V!`3f%+>8Pr~Lgl$jyqtI~((%#9bCvU7yXIv@SsG zU?VKFzD=Kg7Qx`5A3;271gI$p4y-2;a4*S~&b+PQZ^@er++HQNF}Db`uWFH3ay<;T z$VcB@D~0{YV5Vl+M}=>AoE@<rGGCqM=DL{DA1eo8R~L-gwg>s1j&kr0+yWiV&Rn;? zC0<Y3g;nDF(C}#oEy!PriOS{RC>731_e7I*;}tHlcpctaGlj)HK2E&R0W7S}WIwTk zI^{;P4GIp}dL@y<H=M>ihk+EGp-B(@ehKW<KM?p!9S|onNd{Oo>K#a2E2nThdor7P zhEsT+%r#pkVbytUEcsf+C43Y!?HqlsYS1bc=NyerQ6tbj^%zRQcY0oI$YTD}Vv<6p z)R}X_sAIF)>9~RHN=PCZRd?`mYs0x;-Ag&Yk1}jDKN7rRFX8XrH~h{YIbd%w5J#>o z!7EQCXx6gNAbac*p0paw^f!mn*SVvZ<H=|6cB?a%4%p3(kSFMkQ=>*r!O2uOl-;XO zz@b78H!!G0)Ya(Bn<pg+9nytpw|Xl(^~n!oQ$(D6)Dup-VGE8vx&Zq7&tR_56@2KO z0tH!R;4-~~kF=P>buVv*L(`v9)df#(nb42jFyaX7O@2ji!W~88G0ZTq00QJB(B{{B z>gcjyay_X`G<_y>RzF9XO#-vik?{PX>jE3(FWq^Vg3>}J-C=PN+S%m51Fu~emUWkF z+Af79xAm|wX$cf;(!$RNmgCoD`*>C1eO>!yK0SX_1ola3<gS#?ws|&_-?MNU^*9_G zrM<-GtbT!N%>h{2w+Bb;31_PWzENS%J|-hEAH5=~;o_wMHY=w+;I$*d*_E_x$d)P> zXD|5<`c+3L_~u}yd{&zp>^6}5^hox|^bMG;8_fRnonuD6zp2*9nYP;3FoPWvamCt7 zmht2Z8$EI)=}o^V#5aHPAAT=nAEW2d=(se5z7*7Mc?b)xzoE!+<xpL#h^FPQ>B56> zwAdWa)y*#D5@MyvJJ6QRFF#7bziQc!HW@U!@d~DXs|5#M2jZf0DSO8WW~gk8?}A6+ zsTYb^rZb%~oa$g(rXG{&^X7t_6j(%%Hkdt<rR4(SD&K4?YdI>-y4D;4r>k+G5E>!A z=p4otwx!}l)%P@A=Q?yBx8#!~_JRIy71pgBCHk~ga0Pl?K$YwQGIf<>5sf#X%Xc0# zX|EUj14F^fyF+Xd=#DnYK6JfcG=9oo!frHurzeB%b2sA!)~o+Hx)a<6<%-jp`~BxI zdE^eLUNDM@WskDvVWzNFU@V>;|HUR%>kV6A+D5rL^ZBcbAA|q2Mp(1|E?jH5jCH@P zm`!pdz88Eylha1w%+tc2WP;$Fds59g8q`t8{Zm}h&f_AZ(rvt#iiJo#(4F}udqECJ zGnYlW?DmdTpdEaXvu6dOZq?@MW4#xtbovRtcaiW+e?Eelyi{S9!_ML$8=iCM=i&0} z*=&=q87y3rOUA3EM0G2C(9HE67(a_9+E*!dx_JP-xy^i#*%<z1*(F$XZ>M;LK@nL< zM8LJb&P+aW9bY@j6_!PPpyA`ku&78Ln=&8MqKT&{BQPAo4-G>*DI}@>AnM<Fi`P#X z!3xJ|Vrsl3H^y}#jUM<PQ$Ais?spSGZ&C^rg^pr<<2Q2C?|V>eryT2kd_;6CUxKSo z9Y>tT5w>#aC=9Ip1C90{VCATvH2a1c>sTd%ZqIs70Jn&<9@K+EiV=v0acr%=0^4F~ z$b|?y$d@;^u+HxZoX(s?mT9ET*YzyrGH%a<9ed+34bGxz&rs@(I)W{vP5~R!Xp^u9 z_mq1Il`l(36x{}Mi=J_JT+dO$LJ2VL`6qTlfcGV@>4dxlv->W|#(O%k^*6HNqQ)<p zBsYakQ`>_6=KJ`dt<Nd!(;qJ3VjMsFsVnQBBacp3vuJ5%G-|G>5zkX!gdg7vj3f63 zF#Br8rM8rT{}djIzIAXNffC%2<#)L*v2Y$4X3y^%X~mi*zN0y1t5CIL3ghcN*%Lk+ zK-rHgIUvj<0|#+04~QtEu#wAAEP>M7y7>HQ52$Vn0YlS8Fl7F4Ts%~ol^4dt+vqK@ z=#}8*yt0&%+Ge1|kbHu=V)EqjNWXLiQuoH{=GJ{!KKC(&E;3@PHyi>j={ice6$QcP zK;Q?+Q?zs!pYT2vUL8uo+)3BruVNe*)i4`8;s?;vvK#ycU1qbbk>^#OM)B9(WN6Rw z|JdQ98_COQ0l(7F5bPzw>2B^|_PSCF1}Ugw*o9cS<8&9)H&3Rj<ii*@t((k!?FHt4 z0et)1N-hJWVf)hU@Fn*NCGL1c9e$6+`nl1xG<q;pmS^%$rk$baH8XMf94Q7Li>$9X zMc^03A!rpd5f?}<Ld(~aVas|`x;^w8r~YaTm&YgYW*Pp1<98Pusu7P1Hoqm8>=WXD z?>#ANS~q+cFv6y0w*nhKc{wl9slyhYSOez=Xi(<7VzQ7^0g1W`qJI5{bUrR!WK?TG zW-<3T?wb}x(+W}*jfQq1x8E|t26o*|BN@l_Xwu*ef4yb#)VCT@_y=EN*Oq~d*n#E! zctBYbecAkPiSYEm3=Dmw!2;hm6YLkf8)c_Rthg64+nm^m$Y6HvTLennkE(vUW;&%7 zjbLM3l$n~aFM7if*EVG*)fr2(_PHu7)Jd2ZbgtzrrZ49YsoCMO!-iy&GLjDt_h3EK zPD9MXF;r193}@{SbGvs><?gAA7>yl;`td5zt=K1${;4OhKi$BdL$=K<n7`ny%tVPv zB*o;hsC_cbkdp(a9gFFJ(AAP1SHV?hYoX_HEmAZX!R|Q4qU~ozGCbx-VLtWMf1W4M zGl!d8&Jz`;w%`i)?yfBPX{6C&{XP(_G6(Imk3i>OI1Xv5<tHCEg1Wiax#&;(MH@iq zu1U?|?aoR<vyu;bc{x-ENNz)ClSlC3#aAeB(FW_KQmjtkTEFg;V($C@P=8a1O|5V^ z(dXKEsp&U_yIeMZWv?omtbdqFibwKy{N}L}?h}~t*-d!*!U(qKSPBI0F{PYE_2l|P zm~#f2(Awj-A!W>AaB*j}jnm~1C*+Ce?tH>`oESrY%L*W2%p)+FH4d|4vsn2_HC`h^ z*lkFtalRwXP-NW6<t(s*`o-^P%r7}+7Jq|NYfA))o!fai|4_Ew%ZeG-%L|NW;W_wS zoeTzsWAXe|So!NGzk1<bQfQn&RgV&xL)>`ya6XN6HM}_2<}X}*?_5ZJV8(_POaje& z+hO!^U63){1KU4@v8aKjIAP5ap*ysPe-fk4-rBg~s%gVvzd<@q+OQSxbbh4p<>A;g z^eEJR&SIJ+cd;ha489#m!^HtVplS0PDmZS+`tFSdQCuRw`{X_@?%-hv(-ZjDd<9of zszT<Oc^H+l7PD4q)3A_eJS04W7ZeR3Z>9*!!wp2al0{JY(F1aB=W(`D9(2A>+a|Na z57fr%v%11u>fgVYa!;*6n+GdVwe$;Rww%FFzXS1z>UJ10{{g9)?FX-GS5U9>KaeVl zg4+`kaL>IxD1D$2H0$q(2UXfat9dlMx4p+yPsCFlW>Z(>YR)fd5|{9A3ubu>u8o6A z?91W15I#r9dYTPmzC#N6OIvzCDl;C!Vtzqyf&%Ncz057oEaF<`Mv&V=cj$cAPTlr) z@F&KYB)TGCOOFOBNu~?#b2+wiLIs4yR#UsMw=_&aIu<aKraT%?#cV7udNi6eu9-mI zUMVbIaSB4u93^2V4ZFX1QfjL=PCDgIMW%Y-Fmwd;zt=&#Ed=W6jxgTdRy1$R4EC=z zn)LJs)r_}$Ci*)56W6or1~tyxM>iu5LCc>(O!I*xIlFDdjtk+{i-(*7vll|{G4BA~ zb)E=s+DF35Ga>k7uoX+)HHM^qq>$YAKagr?!tbaQc-^tL;kmCb>$_^t?>?bV{sWcy z#TO^xo~QR9@X}zMoLNRY7goTg=VNil^;o7Y{C+Pbtz=@;c4`?9*kC^e3+><2r9W3` z$KC}H)n>}(>e|pP%jszHW(705mxE6~O2E5&8(C;?DHTr^I0k1W#LL$t<E*bH+*-YC zl2q!0GR<aaiMYsp4ACL0v9sCi@7p2d_fR%^l?Q$;y2S@>T?OAQAF!oDA22jDl5{Kv zvVmJ~l8=`?J{+XSjs6r4mzQ+G55<o#rCq7!N#P=L$h%0rzB+WD7x)`5qH(CaG<NOQ zWow_0VOPAX!Q_V#hIMUV2`{E$jf4|=uii$^Cph$1h!-VI953!%F^6n!dEg*lC5nG@ z3CPWyx2Rvo4y6w!wX6&_wdyQwn!`AUVJD&ctpZy#>NIU=@1SO%7!pYSq|&8?4<0=i zdV&3-53jG#!tO6zU-=!HfAtqE5)0megGWIp)&ece?Ah+46PX|Oa$m<d;hGZ%vBF_G zgp4f*mHV<b%eJ-A&tEO#eXk_Rb<an><a04et`EHG91zJa?nq`gZRD{|aU6S)Voer{ z=TOq^k0d^~70%{7Azv>&yz;ylwdF(6{_S*dS^XMpiqoMc!k&|`nrVGUS)Da!EuzJt z7nr<h06|Ix^%?yn{cn|U{Ovm2|MdX7x=5NCE*vHFw<W;4e=HY$MA0Vgf*wAM(qNBw z-va;R0Te#=A8p^f7iRT3!`bj?h`fFi40`og$5~}j%fd|7C7w;qLNhqBvx$wfKUw`` zSp$rJyB73MZb#|$0rcl!Dxm!sCgnH^OXU(UaMU#J@6SIF{6(JPb!))QWj)KQJ;41w zy$uUr=;0;t6I#931S=EuY5YA6jGUFvD)@Q0YOEZ4npa0|PXwmD%uC+MJ`-nn7og9_ zYH&Mm$+{imaZ7;)8hKu(gc-2{cRw2U?2QGN{!m;Jv5&r+M_`4Iz*6hKO%Ja~Vcg?d z@KlfBTgGMMBa?X$dG8)M4UPwcFNfIaL`#Zl9nON~m6?0z2&hlHLxr`bcqjiHjr%;D zt_?6I*E%CUc<N&cZZPL^Lv+wg*u|L0E{1%|EJ{e$#rltixUD*c`>CuZDv!U+b)y!( z>s`Q-oCI&B<uGKO7Whqm4~{N*N;UQqguPXpuuHM!wx3L3l{-ID%Fb$T)K;QEgC6wI z9mcvs4p5bcH`6wV!!LcG!FKsxdYP&Zu{x?){wsyzc6^8ai&sGYK^}e3I!8bJ6Clp_ z87W$If=@#svB`a~)X)<wu17GnxL0&XR0P)B8Du65VPA|b*hCj=Z0rwaJqbtHJYhFE z`g05%=AVgw7avBsV1Zla-vBDs#V|-;guXU%<ect8JAy25$=(L|?OX*D3{FvAoCcd{ zJb^ntSO&?~2ig`YQ-a(q)@GChC3DV`oUIEMq#uE_zO6Wrw!zm2f)7ydCetkPV9vE; z;Zo;s(zg1KS^gZvlvcz-ys8#k9CDtv2g<RzpR}+kA{JkryF{@z3&HcLDxQA%1uaT- zn1Nv!Utqsm$TlmG>*`ckp619FN0y2;ugv6{%qt;RQvxjPhVh+#x47FYC0X2v?Oe^i zr7+-=&{14<64YJ>LDC!voHzUjof6)6TXauB{M1+AE58b7TJ=EGr!X9QdM}<1z6`<5 zS`@PS4e!5bF$9%pbKR#Dcy+6Gh)maJ4=4Vl!N!Ta%xeYI9DI=*a#rwyY^o!@TY_Ib zsexv6IkG!8d#O#>Exxo(qsB%b1Q`SVyWKfbT{BI{8f39}6$_k_Jeb)<2jFi5V`$12 z&eY>;V27fdjkd~Bv3$Ov*k_L?<VGm~_(Za_KjqNUc8JfgNMiGffjyimVx7ebX!$D_ z4xcXP?xfc76>cLjqu!fcGarfFUw6^rfz!cff;CoJ4YJWaC^*?v!zu6HaJuJqmPUk) z1n-aLkXJAC(Zg&Z$Xbb|xX7|!1);!gkgQP`yfTB_)`7+wbvza0#k`s{sV>Bfh25IU zdgP=qQM#GCeyoAM8mqBI=fsdN=ZbQ1Rj8Dv%EIy@t^XS`39B7naC0UJmC@}HnC<EZ z%g?<7kF(P#H0K8Gzbea;8&0y;%IUOe_#DX6-VDCurh-G^UY4yss3v2<VXztOh!PVv zS7(1|606Tt$4OISnUdEfXj*xOtakiIPXs5>>2t+2sAvNlv0RbfKi!Xp(+AMdzz%xT zIE4i{yobO~#{{mw9rL$OgCP6om>sIc%Nh=0c}JotBy}yWy$qx(+eK&nRPp=R3@~y2 zP7*d!cw0{JRNmN#c6gu6ytd+4>6NVXO)*%?_Hx&*9;d1KhbZO5ELanFkA^#OxOB}0 zNOy^6F>Ct-7jHJFlVDDFuMM&NsWPA@GQXTmR;SQ_X@yYncMsM`wbP!RYBq~x>S*Z3 zZrXYDBglQJ1dDOW+?anKx&FJ66t>9BTHbd(FV&m_0k=j_%*1GcxgEeP9ki&h;J)>G zk9?|V5gY}(?;s1f$vcRW_;eL18kjtkenzR`C8K&8y-IM(Z#$3q9{SY#?k;GrcVlx` zU8mB8vds6eA%-pfDrCEjP-~YQG~7b+e3gw49r}2SY{ADkIhb4&Pg8EAH=F+ZxZtV! zMu(*YCWh%ZI8ZvCKm0+&Ek1G-rQ>EY$<SGl+Oh&WCXYmeJS{fgXB1j#>CsYQj@y>~ z6x#>Pf)*=vuJm#uXMFQCzq;x<Nx2?{np4%ZCukR>=_hjyo7MR9U9NoA9t98&_Jj<j zGAcPg9+P*R;0v}^@b8Kzvb$gRQBbNjuK6uEb*5U8y5}>|tk!2x8sx{$4TuAI-N~qQ z$cD{5HI!|wk$~t=k~L(c!%yhQCExyi{1yX&Ep$`L#zD^&-r4}FO@0l}ub+p?@fkEL z_W;;8lrjn1Bcge|{v`kBA+Mk!rkg@W?AF{7FeOxvmAS`L<bMm<;u1|3=5-pj**4Ha z;b+_Qetb=WFndWFtjikqtfdm)P5kexY0PfJ7(DKA3X0dsqm1t&>U~^>7lQ9W-h}=9 z%+G(w(y;|Xt}TEX-)7jWIuz8OEujBu$1?YjcF;U_lL8Ljr9-=FaZ?7z<c3Mml0;8D zbG3-~lXk^9ePy(%Wfh!};o(!}H1?p~7Q0twqe)&j{HxqR>hn%QrL+h8G$4=9njK5< z$p?HR4B)TbA{-`LPRE8!U<*49*|e1|825Y$zWlTrt9GQ(=oV)NTQ5Oq>KT}Kn7Ad1 z*I)_Uf{{;t(!sSeaEikYY&v(DpBd5z4jqA1xUyaB(y|6<b*fE@-bFe){40E^xkx&H z{aJFA4H!R_hoD_k`5WhUqHFAY?s0txE0Z`6>5{`STS|}bRGq@)s)nMXWD*P3dB*LY zeTlPsf1G&;{3!ploN8@%AJM4Hqx9gjAw!=T<ofM2<!>;hG}$4{eNqxURyfPAa1}WI zcK5Jf;GP!QzJP^?Dg}3EAo_ob7q2_Mh1YX0;^yZCa;dYglZkc~d$&1{&olc+BQyqs z_l*Hu31-2K*ys4+m;}GKcp3~dOM-x@W6>_{9cMA&7-uEqGP)^A%-z`!9`}F1&k|`c zJ|V!kdWVvF%xca_$or4yD`4034_x>}33hh!81!Q1<Q$?&C6ZUc_=N>?>@5Z}`a(;h z%Be0df>}NpgB__c7|Xd)&48N}A#sc*+f-0nVje6`naoz**ueZ%74dpOgOK0<LBH=B z^5g!zq7Wg|;cc^m90r<F(awo1*9)n`B3e{g{8Z@AaFiRHBCy8?u$VnjWH!Bsd3ohl ztCr`|kg395l9LeJo+CLaflp=l>?Z71aDvf#dK8>(4mVZ}A@O(<CQ%R$^<}Coz_W|G zkKD1&99_dt9@7H94F+KE`bN}{9s?~2{haa2IKkUo$S)r^9{jx0VV%x*paKslKX4HW zkIRtP`HR%Kalg2{MTbNh4>@IbOB@$wgXNAUSf{&-%P<LID}B>R?PmihEwluymIvIn zgHkZhSfABCT8Q5k{o?a}sG#3VSG=>fklW$C2uhusc?m0DlDT6KanGVTyNymZa4ZvG z=U(VsG?&WzhTz8C;q;?y2FdQ#qzl6bvL?xOY}JVM&@$JOd7k~rfpA~-T<1md!*}x8 z!a2gc@gNLpl*5K+&*)LR4vda2=5$|4g8J+de)7#aSlN;X5esEdVzUMNaB?O0dXkVu zoFoORE2jycoj8)(9Z1912>@@E)3iTA2_IH%g#D9mlT%h3O^>=v{=ecmb#qI+pYOr# z^fN*63}LQn6$yhyf}iHtVEAjYjvaU2O4(h>)W7B+7kqa(mg_A7i5<eTXmBI9Y#Tsf zfExV1vkkIb{K;9JxVrYM5M(-x_nfXqM?KQOy(1q#96f+RLmuFrdIgG;i@}!Xw%BrU zAM1H|5-k=j;ik-8iy;v?Fh4ShA5*Qu>?RK57o;h3V|%Az-f?YIl7A1Xx8h-&K|Gxk z`eYA-r{RB@7pUr_4MrO@!FiA4T=&uyTu}9BV3qf{Nte|~Kq1n^1BYn4(j*(}b$ayE z^b~nG`q4m%_q6Qzepr?WXlT2i_g)!>PMLer`fC%+u`7WFdt)%}&A_Ci8rZpJpGfwR zIxbsVfN$Wh_(s`N7+K~EYfDc<!gpWhy<LNRcSKXBz^zr7)(OKNq{EVb;oRbyhw!*a zgZ7Lz!U5+tvHlH4?Dm``IQ;Al@Yi`MuJu%9`s2%J4xc7)AJf1~BO0y*ZedC`VZ7m; z+1zTI7#O9efDiw+a{hvAWR~h~7=7kCSMzWmnk9#E=|AIWR%|*6nHk>HA&QLW>OhBs z3od=Ngf4ca(Vcz~|8{^Cj4@r0*_F2956&5&`K1A_=H7>$?So)QsW8jcuw?h9rjd!n zB&xG)V;TQ|4(CZ=;<q~#B&7k1H!z5NW=o=83)m`T5q~L5u$V}5-2Ybs>)tkyNTFF^ zbXQPL<7FJIUC6wz<qBu(Bb;vNQEF$C=;p4|@cZK|Oj$pS4cm2uD;)lqCdaHHGhIvk z9DNE*pJkyZOQ)I6!Z~^l@Y^zE*oW^oDf@)A=;yrWyy%%U*8V+-$xBlCvTF;ePOlk~ z?5DEsBSIg~!x#rUnzI|@58(139X5LVe6~qo1cbc}V{YEc0&l2;A6t75l$4**))imj z`~?YkoVAQU&=m^Tk~>J!#1C8lo5WoY*^U-dr?JuV$G{uXVz(!#;99M6>J9iouI47N zywd}B)~qF~xrXf7*&2E}{wPhVIK=L(Um^4Y+qlC<mJqbw2wM{mpj+x>ObO4XlrAZV zOts>!WG=${-BGMq-WVm-hT)+zRUlK>13i}q5I<o!4*FKiCCw4?1?y~SIYn|(fljQ* zK$F>}OW?c9cFazFB2(3=qltk5_<ZyOZiTujG^`xTzU@Qm?9e6Y5`pb6<kmGRN70Xi z38XxuTWo&J9R^;tW+MF|;Jfk`Sm<e?cj#UU5g2;L$Bek{TglkwriQnD1~cvL!yqlX z3w31IvajjwBx`kp%iA5x`{qT^+|aF8&&YW*-%CRoOt8Xrp;1)2I)@x$rZE3J5H~&Q zhbw{y;L?cUm^B)(!%+tBXokVHV<kc!*$~wShLO~=M*fCEBGWq=NY6sk*^kfD$RJ`A zWna~0YRz*{G{^`?=$Nww_m!Bh#yDPOY!F<x*Fwo<H}JduEv`>04&3}-L*ghk3NLnH z1>G|I&6&E8WZDN>jq~YcFi-a8gZRZ89oWb4`SdAg91Zx;!nVr9@+~JyAtZb>Szpjc zv)rxhJMP8xit||0=5R24U5bxG?t;s@TQFk7S;%@(&#mu8*7(GVydpz!yvIG!#sm+R zFCm5NTn~Y-us0ep|1A4_>NLs+8?b=e4ZNB45_Hhp2Yncbf6fiT{;*D{c%nedcPrp2 z%V3Unte|b3!}+SPY<PI$FIPT7SMZ4K;AE!TqnzI;eD7b%Hz+=ak^zDE(|tm9TkQ<A z{K%jt(TF*Y+e2|3d)Z43C2-mnN@_F1>0rcBvioC3LlVd0Yefse2Qr_jUs^^ztzXIJ zej2$by{4+nSDf7XBszLvG~Nt+LoOhLeT~0i;jTEY=;%H$5YEkhf8EhGeK>o+eLZT* znd9cqT9~O`PJ=VHvi_Z2usz;|O^7RmRNV+xckcmdU;f9(&oibb<#%{B!h-AESI#Z& z|HT`B`Nd)N1bW<8Ep**V!E<{O*H)iK9e>wx<9lxK@_P$Na=#S2^hbC<-~UH{hMa@K zL(6Dqnkvr9Isy886f=)iBkPx~^f^xt<KA}B_xTnyA!Vp=f2yQTA?LX{{R36_UZt)X zUhL6%!S|~43npZ0;j8$1QXfzR%CC5Fn6r)5w6PhOQ~LmNBo@%zwKL(yzAda|WG;Oz zy$5;`E}*<2g7RE>a({CG0$z<~GJ(&zwzv-d-`o($zrUV)RaHeoeu*uMac5xliJz&Y zK|>7+XozDFvt0jy-~T|BDU8!(vdS4W)NwyV<7UWB$pX`mBVaPX4E8_xfC{aP*p9&_ zti^sA+K#;nZ~bjR@RiVbB~|!v;tqGNvKBi2mBXOu`4IZz1lNCV1l#L=kflYO=B_#4 z1f^jw`PHq`I5cn|^nD-CHE)o>paBDgjE5d3&x^-`^-550xEhn2gpS8}7l>OtpEV@a zgJD@ayx7}8rnlz9DZhbm>dij!yp@Y-$$@=*PU=K#-MIn0EI)}BYz!miJ$<5@T}SBt z=Y4G3fMZ-wz78F897QV49<X&~HErveO~%VEf}xwB6dJGv`&BCV#X7@q`;1(=?XCq@ zsry0ZKNTBSgF1NcT1;^PC%BJ~wcvnlEK?JWBk7=5Ab&xb$<9q9r$Qwv{WO&5Z4Npw zKEx&uw}cp1f`;?fEK=?<bk3OxI(j$A2)E&D7j2s$?Rsv?n<A<zx=QZ@QfPNuDm;x- zL`w&0QkBSrkn=e-%uJoVd9x0Z2R>q@kA!pfu`+0Vn+<_^6?CV)g_7@mqT$2Okygl2 zjGa1w>dwEWce*24*V3gJr!yA3eD<P6R=DWjlZTvn0N|#^6I7He!=8FBMYn53kmcn^ zDqE9iLPQ{{{S9DyE+?>ocFL?SGa5YpUgJCVDZ`)YP3-VutD5WUJHho*G&X7;upSpV zjO=z~@RbRh*%=27Xf}u>Z<*V?gMTHSvX*Bve|rdSssX4mYO0W1d{0U3fyCE_QIlJT z=#ZBRbG&hsHM$=q^tz5STa?+g3N@1XJ(B&N%3<^HC`fAj%+LNSbUE6BV7F-{g>3o- zuD$bE{C9i2xpgk|zgP&)5i^;Fq&nxl=>n*`hQV9A3{u`K2k&wM*!TnQp+b2WrVf%~ ze@bNOGDcE`WfPas(qpq({tG)YU<Ok>)j}ha8epPJDX1C@XAYT4Hnk=H__cO}sr{)O z<p}4h#;lX%H(#DxToTBn6|2bLYb`}+jK*!te~Kra_TV?wO<?gU-t=^t1PedH(aICf z*i^XMX36|iPQqwBXIXKAR4uwiAG8L+`D5xV&V!@gD}*-=hLMHET=4B$z{2Zds9DLA z@?3;Y>(v0XF||eCIbI+aC{2@ZZ^p2D!>iR!o3iAS-Ly^V3`N))vikb3z<s+wjg?{{ z1Nl(Aq{@l*xgDX<@EhnYYb@~UlIg6+8jRMMk4`#f?32t)Y>`XjJ%sb4{{nX#2?<Ad z_hACN_r???eqDvSmm65t{S~O5^dDI1oB)OVg(P)uBJ($tB-y4wS~}%Ac)t0{4-;$Q zf)o1OdF4pH?%@C?zF8~WD;V6<3dPiWQR2CWrI?2NKK^v+Z1!W~O*o`H12b|yQh&j9 ze)2zQ`t#u{OAEZf&6=vu{Kv)6q80V5tm!RQuDZdqO_MRV>oIh#T*VoGQ4x7sO5n?l znT*rF$!&jtl-n^u;4@yNF7@LA>nnycv7O4sh7Uu{zE=7kd4^61{qEqSp48FaDmK9# zHLyisr{|ln%f&JD^N1}$^ekZy8II%jj=`4RwdgNlBc2}p3|}{oL+_10=-27X<OnHH zvLli!tTv`iNi#rVNhEt2WWgSb%`xw8IBAwda~GHIz>H>rp{Tx(I{c5pTaP60bm@hs zF*gJz%zD)RejoPu^AvtTNpOFk!G(5G_~AnU6^BQGUy?D?bJ7*&-yK}t@pfKy!9Cb5 z^eeL-nzAze)2zYw7L!$1M%lJq_&e1P!-E<`dw-5)&0X18>L?awqG9l<NDMOCvv5Y> zAlAHhj*w$$1&5KU+=7};kSVPq)%Z@aM05Mhr8(X<n|g}4rQfCTNk|G^9de3&4LAgr zbtCAF>=EnUF9vvcdJ)`H3}-oo1>D8^CaBzkT(Y7qQ}R0mno3s8Z{1)zm2sJ?(Y(u& zVh)ksuSD_9MjiTohf(PI3^ry_0VTK(r`_{b(haA%?8k%I(4%&ZJO*jAyvT1TcTP&M zh79F*yc9TQPtV}IPgV3f<uRY|#R1HXT47e_0`Ax4Jm$7q3l(<Gq4P^F^MQw4AwBUd ze0X~o^UiPJT;dD3!mUSO@>?PQS2dbjZa13Jdrk04*l&1!%80IgONXC6gGEgX6Y0d- zpVTuh5^UxDVO2*1_-BeB*D#b+M_0kkk>^13D5LJXi(q6!2lGk)1RL8NxaM|8Iy}#b zrLUfV^ION_l;|e@_rWw8*q6qag9#_TDs--sftiK=q5>7+e??;sn0x3_p4$}e>w10C zwj0hQzGPON)4#;~ZdpL<FDSAc4NDjm`5g8<)MpFMr$f?_xis;b6+8Z;hTUF1hl0yB zsHFKb)OrT+4nLc@#BG&y+_4YdU%kcu*m9J6qSp$cv48kbGYckfyHeygZ$GPyQl+LT zC#ucNVrcO~eUvYmgvqDY;#IAUB=>kWZEnBL8JcgT5TW;@G=m@}NYHH8uHy<rkn>WT z4+p<zLU{@=a-KGiB)qnP0OQ0{0cXKws1K_D@}W4-JQnc%3>h4cg7#Tuu<A-N4RH&F zTy<%da0u~o^I+6`e+^tEwDG>=EP8G!?A3dt`Q{;k6j<O654D28>e^-WZ&?Ao`>&C) zpAyqMXND+bXcyk^guGZU(X5T5D16RF7F<|CdAH@6p=m4cj3zY9y#x9Ua)ex_Hrumv zGQVi^5iqrrW;$Dgpljd@YNdSe8;XK5CX}z8u@Wsc>;(VYZEJ<r_rSl<#;4}PDcCd^ z=K5Wy5NUI<fu%Q;$$p_Pc4P5y)<f<qM3d)3MuFSxY3UX{l2IOo0)ABJaqY*WJ8j_g z+1n7HSwww3P0+DTk=J&gE3#S~$9a1@QO`MB(A7FBuy)f~$hOxcUUVDYpY=zdhx<A0 zX}hb-M<w%{4vwdJ-N&f^VKy}kC<kzzj-$$#;K9aL^t^DB&I~WY%xT0uP%0ICe;e>o zr3O0K`eB&>seWCxnZmT~`THO9D5X!xyYklfLs1MT_l5$EnkC*}F`5cLd*Cy9Jxt&P z&Yf{J@I~_I{wxn3yxt6RUj2e?ab4U>t>>g$dYbg_&891oQ*3T>-86b=8+T@#F~74Z zk>*~CgwR?4;gh^{YTX=xui9^7PxN^({eBhfyU&Bu#AbN^!35L$Lg7En^U$!f2E+L0 zqM?~7XjOKI8~OSrlv<}T#|i71>!~PlYRCaJQ`mx4J}cl$umaxdiUBoQ;Y^{Ij(6Tq zV!m$M*)@p)cy!HY`1#IJy!c={xrPg8viOr^Q6O}6TdUyS?@Zbk;6n=>QiY!HQ}H_g z!|)A;Qkd=x?(~NPRKIE<oBhETFRDkvm`#J(zbjX$7qa=h9jffBVj)E3T!gw<YbIfq z2tm)w#O^i9Sg9_FJ2QgWrXVTuj@<(jgq+>@JPyoc#MCNV2!#dP=~dDn?(wQCOnZ$w z8|*1~-0UZE)7~tHwn=ND>aZifzQ0Sjw=O_=_JrKq!|=`)X|&%_$$v_}4%z}UJ2}Z5 zUq!rS!@aM;<>!a^u`46#PT59s_|Y#KID7;8wiuA_rvdQw@hv*MLya?ecoH58tj)e5 z7MNFO%KNyx^IrKwMCbAaX7kDs?5Df}c=lf7F10SjTSdh<bWJKGiJ$S?mhS}hG3Lyt zazDN6a6>9tN!JaM(KdTF%Qw)3JOyu2dx<&|>bMxZ>87w3@8QnZ@8@B-Joeb{g`JMZ zY<aQ=T+i#Kx{)K$N9O{4xh`<b_1u`VVEet7`HGs&C2@gqGu0*T;yMRs(VyF9s3tjs zR-N(XQN~9&&nmF9N>`b2@No`mg|k7DBAfNd1ZNy^!jaPJu;`8+o4QyABQoUZZk;85 z@-bnf$8P{jP6JO(k`%s=&FEyS4Nq<MV$_lv?rxd^)?{cg<0WT7L^8ClL<#S#NaWfQ z0$6IJGP52g4=0ntvE_p{9nF`f%vZNb|Av;pR~9-^PXpj<o4^7Tyyr{zSkwB-4G=Qq zGsheanEA{}{A98N|CuWIpW{YY6g!1P1yNkLXeusx8v_H~rm^C;C!wiL;P+YFCJUi{ z+xX@xzw1y07;O}jQ-{md#<erZ!EYreR^5k@%N7eho?3d9f0f!x%qUjtF32WIvcOee zAgNp(>1k4Rc62Pg`_vBRFT?QgqC9G}{mISUl*IykF2XY@CnocJCNsP2!2Q%zU~dec zfR)-C=m_f|Ux`)BB=`!1XqHgFTNY%+9LEv<HIU={PnhhVhVV#NNb&_%nCrrCswm|$ z-JgMsl`C~i{i4U)_tWZSZp?`}^0D^@Va$-r?CqKN5c}{A#2%DjzY^X<H&??{xirDi z(g;JB9i@;juGnus9yR?Oz^Tv(8y+ozm@i(eRr@J4wQj-?w-WeZZpJ)jq!Wxi3EM&s zz&MASEa&QT%$mK6g%nnE$uE*Hdc8fmY+8+bTE?PR;}FiF>NaHy9bu^>f~$B)Jh?b; z73od&qTIQzkheKal;Gk7{V)9lKf*zg5_*tw#$EXD%N+bE%xXMMUO?6J0XS5ASUh*y zJ-Q(~gPjdq31;u@scYN`dio-tZ2J{h@S`Z0f4GQ#Xc({sBZJ7b+FRI5<Z-)i8I$8k zX*S4PgC!FWPo#&iV9h1CZ)-T%8Quho-EQ!6S1l>@I-&8=nJhkR3$AJ&fiV}u;hPYS zymNICOI=}xH8I-k$_EX|-F%tNl~03mk6KZVWH=X@wHqx%mr&-VK@_5NmMUy=D7X1I zt?ZwHe%9L9xR|rP5gtWN^W`bk=r}2sXt0(grQ})mnl4sOXB`7w#1|yvNvti4Ixjq+ zTHlDBkA4b<9&=g5F%4WS>_E$}4Q5-u`qE*SPJVM+Exn0}WWG;7^W&#EFxz+|TxcEz z1L_;V$Zr=d-}?xLmn%Zj)H;z|_!-=C;W;czUrx7+hhRn9H1>7qO}=HeHhyY&NmfTA zxRhTjY2~JGoMwk1-|?xGt2=W+)c6C)q-+!XXXq!)$4*k$#MR6~<Ai9f(PI2pY|kp^ z{Kpa;H`9&OeDWzH+HEDt`lN@z9p7RYX6uiuT`e(a_B&oZFcSmvU08;04+%qW4C;6X zPiLv1$q5P8@!+z^IAXpyT!Mp2uPKl|V;XdfXop24@RBROSHHP4h;6D>!hPyWlz2D; zTu0BPkn|)tEaMH@Xa0#o;w;f~=T}_S_6CmlT!OH^2`I0-ij1e9Bz5U_z^-BnzO|ps zEe^x?kU``#;}Cyw>vH;gA&%7ThM`aSLvd#aa68AHrCF}>pgz7>w5&8v=#T#4qsAPk zaT#AoKK%}FWu?U4RL>>3xW6#2{Rhixo{w**j%KGrXH!JoV%DP64dvF`Ve9QC9G^Cj z`#N(9oVGc{Wj`MV?dzS`NE4!Or9*J_oI%W|zf3&;z67g#txjc^>hL$KW`-xH!kLfH z;Let*EJu1E>YOiw#2FKqsn;~TFm<TSt?5-@Rr8MvyfU91r#F0Jqzw)ntBCCIY^L2) zC{h|Y60V(&V;?idVQlR*b~-bkMy(q`g<j7fJhh5%p8W_8{kTLgdZK87^m%O8y3L!% zKjkNDYp{Y*7T9pHgBFiW$KPvKLy%j2b&}pSPIka}Cc!0J9s4DL=Bwi2m!1c{oMA!t z-n@k6dG>7SNqhF++k+tbtB;^7begVSq}$~&^zWEiO^xM5Sj@#@{9Olxv4PdUCaeLu z8QGkjD3hc;<eBvW9aK}fh})VLF(36FYLS(~|GG!;cV9_So~e-OHeF2pAAiI8o+WH@ zaSZ#QV#l(TopH*RL$o{WEt%$-(xxE?FxF1!w4cnUzcCr$;1vSSKF?{3sV|r=s9+sl z`EX>v5t>aEJQAXL?0TO8{i*!~j_aq<C*d>XzkfLAY_85antk|;-~#yMKAzoCox#y& z6E3!`l@hF^Z6C~uXD&7}ENop0Wp8y9Z(VR1hLpQ7?Hyxnyu%LBlDEsj_dmhAEkb<u zWGeG_R}qg9y3u~t3)%DZaGFyY24<O0xI-bcL0W4K3*Rlc)x^VSTFw&w!*oN~GkK4V z)RxtdG-w{bR{Jaca0{jI`BuOpj9FooiuDrtZfyJQOJ(7OT;!g37FaJyUG59Hb^8M` zeBA-uS+WehKGi}<+z_ZuY67o$BX}#fQ#4)bC9REoz=y0mONY<z;Nl<5V86Y8@LxAv zCF6iM+`Gw@TvYmF3|3KKx3hoIw}S?l?$-(1GL|xlrv_Hn)dd$~^mnRGPq*1TS_OAs z7no<^;b6J@I^@OVv6t%*KbxKBM<4qMxj$XF5T7lKYZEvFJ<-6D6L5pR1p9nUa42uS zWNkQS8r^w$8`e%fOAAvCsj~Pp?AcUJbpjLZM6@j3{B6a``u@TXfkm?3-j1an^XKb^ z>agnco9w4^IW04ZW|_mx`MOIln5%L*?qJ1m&Bp+Bwfy+>34(LiISgihz0W;5qR6U> z)<fU9oxIt_Bv9`8$C;R0gZAESA{D8x6lz-vonzke!&gjX8NZFde621$T$m|ZFBM(W zFz^5^nG?-A{vM;&KL<&7>SAVLS%B|kG_c|OcI=JWE0(1**nkCKek_tGvw&tkSPC7> zawzSBJX1g311a@h?1{%E_{(j_j$2|{@WL3hBbJfE@if+vs>^be?4VU?IXtgG?7wsX zd_5jRex)&z<wzLeHI83m9))U8{_w_j_14$NETOZvUX#YHx4ewrNm|tPS(p<G8F0lg zq(djFcRm?Vqn=gCPJS7Nrn#pu_53AqiB~wS@(rgE!G36MxE6=35S;D78~E?rs-VUz zhfEhMqLPvl_C5%w+s048H6@glDCEGroX?cKbg0eb1CL0gGLAhw6%HAm_h?s3A5<F3 zV_GH$1u;6fT=_n?HLZdr+-rj=dBxme+fa&CF=5Z$=0bC6Jxwg#&Zp{1f$ppetkyk> zJ|~A$_gRkRwLYMz(W}^n^B?Hal=oz@--@l7y^8(TGly8+f$Y@E&veFK*+y09iqHRG z$m!`P;fBu<_*Y;le$D;H)fI<{LynHa+zBh-&xl%9*H?^p2jAlw)TP+ors?n@aUPf0 ze-Kx8RKebZ^C9zQ1m{;Ch%?U#vpxquuI8c%^d=wUZxk(LXH2wkf@}#{OXNVj;b&5M zbx_!|S%8gP4ji1>2MgZ}q=sWtp<Lh>OzO&|=n8)>^^M@5-JA$v3nJi#XAGp#8^N_F zk73r2tM3-rQ(VY0(fL`meCGBPZnb6t6E#j}KMty~t(K|u;&cyhIrJE;I@!#BAD77I z?%K<=;|FoAd)`rB!+N-`^McOGC&K+_hv4+Na7MG^#5H>kaQmj$vWC8=Y}GMySmGH6 zhKgUIUuOW0xBS6%$c&<+Em_zfx(VDgS8%3(6jAd^EALydf<5=G<UDhhvC4h_c=vs3 z)cooq{D`^^w>Lb2l3R#p6du6E)w5_+cLL4oJkMW{97S8VMuBT&0xDm;z!k`5QKj<* zYAN^vmp5loX6`6BT(2!Ioih(DF6F{^^)q-RzXoh7=Cbk)=JaKA0!f(cxe~u4i(0!5 z!Qq*+=&Nl2CiF(3T$wIv^~}K(S7UZ5TyQOK(7?vXI8t3)%N=u&Aq7|gUQg$Wm3M8S zZN;X{`{!Pq9<-Od>`eqW*KDeHd`DwlswwHFD%HJT!^HLL>3MD&UEkCP{_@WueM1vn ziylGt@{VZedX_qRlHhfK3Y+!P8@lZWkp1CVq~|!CLlp<KSG+}5kNQ9+_br4EcVM%p z??c6GMn>kgV7FQff%}`dpDH(?>UTakBnmyDpQos>r%hBaW)}?l=!%a`XX1x7dGK~c z7o-h8B6`5jhEsKgT%qtas6+zR_C&zoeT%61=Wj51ElVj$OPN>eL#xD60~~iG70l-E zfyehtc$tPMSYw*QS?n3ZKT<wRMWe%E$>l?!lkJCjRblvKX*c;=*WkX?JeX3snjO*o z3*YwZ<I!qO{O;%jy-QA0)SEbxS$K<F+wO8-omBB>Pd;7$odm8iw_$#4DLq;~4J&G$ zLGpr#E*ngSAv07kEW}mZS&<9JzW;@}U0c9Q*jx4~CzD)<1~ZxX9MQIe!p7g_>PK`7 z^LH}{&2SKSM9pB<zKE&&&BeHiN-TEROA}6>g@tFwptxQMH~fhOurb5ligVys=YknA z=`iJi4XSB&bJD%>;C{iIQQjuelI_K08+IFX*DpiU5qG$+3fh>rA)K1Zc(^wv8pRW2 z*zjXT5LG$?o4H?NRoxNfwXu=Auuka7VJkO!!~yVd6ndA7Bq2mc=pK$8$5wIvwC*NB z_Q=(IY4aco+h)&i4)&p@3pXJ8Wij~wxkfodtpwMQ63Gkq9MPkvAfaJa<*D366?Jo{ zbZ#wgWa@;W2Q{!;Gmd$gEfnYY2=6HKG}tih5=4wyNiENu(Iq6hnlVMv03UX$Q<ie~ zJmTV+5(YC1T=di#WS^;Eq5B-s?_Lc&VOUQp7k8l4iZh@&NAQJ}S;O&&e^geii5Dkr zVQGd@@LBk~bRJqvJ@+q>t4<t+yKTa-`Rde{e^4A$xPmE<DHkd9U#HtYlwiEx4$dLe z7+n=kasfN*Ir*!@MYhMsvDeooVW8Xzs^8lV_pQ3HTR|B+S{H%Zmpjm=e307qRZ*s& z;0sxOj~Xr|;>Fh!A!*BOP~G^2rpUUpTGbQ?NtR$A<_^QK#8u+Ormw5D$K;6|iuO@r z;AEz*7%TE~7>wgzoQ9}rwwUr|DC^qynv>gph$h}&hu-e?T(+UW8ZDeaVedY`TmunX zw^fnptEjPOs=4ewAIrSQEam@6G(pyXO3X<i5EG7sk+g!)hZ1@j0VNNhJ!(JHZcW3a zDWO!kHwTpCm*M_f-(Z~Vc_{KZNlw@9LsF~-KSO^M>ee6QjkcYISpyQ`=KFRixcWt8 z8|23fd0_|pU>fIt-U<WavS^siS~7AJ@^i%#_>q>osdC*aS{>obcKW1|R#6J&`zC?* z%NNyVs)e*#yq-0>8A5M$Kd6U9)2CA|P{MSudzuy=uG-7z_Xs~vMICf+zJXp&g711Q z2NPHJL1$GlXC};@)q`BFHf>b}-R^ZzEV~0G>=snzB{JSqr;&?P>g7Ef)o{MI0^6q> zkFP)llLL^;%ec#ri!s2*zgMBaU#3yY=P2oDCA%o!3m@y#*`$s=Y^DD(&PXbk#+h2< z$U`&Ha`ZcXY@aS`%{>p+QVwkBxqV#N!9<K1W`S~&W`d_$kILlIIi=0Ptj|~IRc}ZF zyMlU<bZMf2LbuVdU=Zyn9L`j?d;#@~2e6_ej%76<h4*BDvDz}0x$hXQeRGWQuSx`d zh#O8xJ;l$F)x?}P_n_}+E687(h%+`Hq&sP*Y{|{{FwoY6{ZG-ExYhJ_VYpIhQfZb- z^CW}{$=Pd#3Q<ThMEZpyge0WWBn?WEkQ7RhBq7w<>rF_KkR)V?5}8A$eEa(cx=z=1 z&ff34*7Mx=FQJR*CCriP6^(fH`{&{Cs5_kbf>t)WC>95P9><glOQ_Ttap5Irl>1PC z@6}hLXY)a_iB=bNUM@#9I7^cZqABT`CT$A5#UGu27aF$JauLxAFuvp$d<~Kna-ikV z=zAAFUCO}+UGmV7mj+Vz&vA2m{y?7Vd{OhI4|L(?c5ZQ$3Yki%z=9X`R5zf6vcK>k zv8Y!piv7;#F3_Xndp9uAUoqE^tj3DIucxLJD*RR(7qlEVNSxiPg0esMaT6@e@#Cg7 z&@)8n4=lL~O<LoDE`Nh#vO0L!w1WFpHJf(tmt?EoEW@F{KT&IoEk$;Um`}4D2D=r* z=8BK7!@~^k=gQ*6b3Z8CaGEe1&LvBmFs|u{E6)6JQ+QtvC1Wsw$q~)4YhfF-ZgFPj zk3#8WtqD{6l0-j(MAYbVl+GPkjP?Qp<oNO()NR-dM?YlI`}^Ox`wrun*QN!m%)U;f z-Z_8`-)zVZOwVHhzEdF3@E0lkYJiW~jqoy5A4mS}qrumb$@z;h)>R!Q&42rFcX2oP zTR!6M75swI!LO+%-2_YCoad^oLn!wBBVO{}A?i-E0C(LONbWvPE&lr<>t_S_E7gLW z#0Rn8gLHuMy=>jXPztZ{!Fc&N)|>Cg_L<0&jkPJa<oFdnd{il&+G~kp<qwlzdk(&Q z@dcMlYcbPQZHx&$K~FClu~l`?!0m4Xv>HkCUUQ|OJY_#^JQ2@_o4ggdz3$|*H$4Z- zH5Pblju!jjI0>sXgwLvX0-`tEs}4BW%x7$xBkUko(7m41{BF$~+?<oYU~9eLu8&&; zP9x2^1M2eV)TcnZM(lu?8&h$Qq5+HUnk~NnV?CWTx=dH=&r$X=XWqJBj<wG1g5$%@ zgzr-TNqd!u>r>x@#MI~F;T@A%Q~nLwBl!PX?pN`P2Wg4Z-HoVVW-pCS^u}M;nwgZc zBywXPQQpsi&{!wOcKiMY<@YtPXYdr<7BUoOO*=y`ZHH6c$u20alxAn8j)Q%s1$K=2 z!T&cT1R}oOq3K`Mgq+D${8xI6`CPjwmes6>kg^F(`t4av&3OeI<^EB`<O#Upp^md$ z%XBR08AS>%dsyW+1@7g<Q1mhAuWlLR&#sJoPUl{K2DiH$3uqmJrraV>to}hk(r4&x zS1$BB6w+63AKceHi>a^er1#U0<AO^o==>mA+O|lQ8ICc7pTUpmQQ|qg88r;kYo2kv zibr`>t!=FR)DY4Sih=QO2Xof@cSAr}78h5zi?_)<&3-=GLp80-FiftDuP~~hPuflp zb8ietmbbDs6aC@(vN+*g=#2+9iK%FT8ZQ|e#71WgV~O`oXr|jJbnFmV|8`qh;Q4mG zsr)fKC{3l3)5e@au?1_meu(V;ZbSGT!b(nUWqtd0vY%7;L&!{hrn+%Blj@Tttt(>m zJmZY!D{J_cg1cO!Nh}3DT}n=g?;zOm8hbBru>^@b4)XuWA15m|CEAI-iynp>%c`j9 zZUc~fI%g##&pxF;glkdH`2Ky4EVwX<##_yz0cTpNBL1(lch7QWUY<-NCH!bkof=4( z?SbVRD(GV3M_eCfz)q(6VDIUn{PI*W*0i6cLw8$v_jwCguAvEg-N$oHdsp$E2Bo~x zvsiwVbP6et+=NGu=+WqqUdr3+DBkxx$~iAEQRI6lpFrvz4ZkO*KP&V=tvHBkujN8p zWfvY?AWzcGB5vg6eeB8p46xp3fjgD=;EWZ?n3WoVCmW_BE!V5|=-tH?Mkn&bW{V{x zoOxY~rQBY5fy=(bN?=LJvZrNAtjKQ~^>pa+l@}L@dd5gO-|QbnJ#*BVy~PxCc7G~( zwO6xQlhs(EZ#pG-ou}(7a-8o?J;q1HEM;Zxa?q5r8TywGt=X!Z3Krq%WbB>~N0l$Z z7`b>BFl8#(zK(^2bJsBFV=tXNmVgHy?V{CppVHgz+u%Fci|uYzrQ;WNLT$-+ik2S6 zt(YAQYD-5mrM0FQBXCj3^B{{ge@K?`ous^JJyUaQrxPXFEaRsNP2Xlz^D93Xs{(BC z^`s2&=2cnQVSmz9-p5sq9!QIYJ(z#8IS#$;4_a^Z$kFjPgx`1J0_>3#ww|NDq`%yT z+|zWcz@K8SI)jJ1K9dW#!+$r@YmQf*qOFA-Tb5Ttai#i9S|y%s{qr4b(}hlsmmNm- zw18}67S=`O^EGobX|G`(SznXE7Ikg*R&o{7)SQCRCEApA?*Tj&_N+xgnpCHB3Kmbu z;b+af#wI<uD0Hj^NKb1N*XEUs2Bp@x`|fs{a$q|;{=N#eS7XV2;u)B8;19Vk9g6RL z&yrqd5QPm}O1AUHGN;ckI8j;}Ox<u8GhLs+^5fDqHV1Do<rgo(V9tK@a`Pe61M|7h zv*)n-0pX}rtqQe194co%=OZdOZja9($p55*iR~@iyn`3%bFe4&X?ijF-9nGU)Q7nV z&U%&eF>I@_D^iLci08`f*|r;5aIb$4PB&BKJjV{fhKelSxn&Dm`^OZvUNd6L1?R)h zG6}Z$+ZO)t>pc{_`~;;b7LZ2m8n&+SAf?1Sq^*)6tXi><maE&a`w!=^coRqV^x72m zy=N5rJhue=E0-|lCHU)YEuB|5O#$U%1=y95fn~wV(biaCO>P+m=Jz$R_Q5V(k)n$~ zpoQ7Y{E9EFh28QJ8P;}8iGwwcoL%@ev1-^NQG~}!F{v+t%bQPQX47~0bH0%ORq&2` z=<LYq9~@zOR2*^L%bjGpcRh>>8%s5V^>KK*DMstA5=CeGz=Veh6r*w&0_MfRoGw=g zFt*~RbZnxW?2Ft2<$>6BW(bB$I+4;L8_arTPPw(QG<|4>!19d%zs<?8{nuHx^P#{% zzWAEvcfBBm8YRZ|4ZylmFHYjwe(`{)y=;YYB+RzGDR2hVQCi^_&HwBQ(_Ol_hGlik zFf)(88?+uo&)%|k19;{c;eZ;yH8IO`CrXalhKU2DvCwfi{b_!V#SOOb`C>OH3cT1- zVdp$J#fpveIL;LW4`U&c(bdtu=c)sD0BYQN1Z`<LsGhHc3$q+>dzC$ne=OwFyIsgp zJB<puXM)PP-B@S31X9ms&;<QERF|xPb`rgm^>{dVrYhl!?_Q`TBmAv%63&UoJ+SS$ zB6Bx7Oxve8vu{J9$!*Y3YTu)SYVAkF;+X<dz&aI+{QrZ4TfNZYb|M>Py9fUJy%_iT zCP0sO9l4EuOxL~VGvjqaZuw+6$s0Pd>Go@Is5QquK0JpKFG+D7=f6;PAo60DMX+CB zI7RLIL~;+$(%lP6SQ^+5=^4NI%A}jzI>|(Qe#L{+mE6lsP?BfgkA^|tB`4lzbt5U| z$cdJ!?8EE#C7F`KTI>t4fl+@Cv%I1f{5CR;^1=^`KC9g1f_oBS)#p?y{H2e{1LrZh zM}PQ~jCtrgZ4mDItcla5Q!qGjENwLmgodwOBGb0VTx(Cac≥T-&RS`@R>#e=nzz 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%0AD>R&6e4hE<Rz?oG{7^(M<Do%Xh)l*Aa16r;9z7d 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�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�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勬=Fl3h# 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%0DBI%mf7 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�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੎$T# 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%0D1=Rg`$ox<Y(z$)I1!Tw=H& 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�Tf8Ci#Zg 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%0Asci<C~(A}t>talA<za!Y3z3Oay@9uXv= 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�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 (wf)XwK^k0TS$QFeVxn<;UxD?Z%3 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%0D=rB4 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%0A$6Sa<U;^-eEsV2CW|8Jf&)9rJ`+W{Oi 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 Ut2W5Z zb;3WZOmM16BTN6&2Kwr0$X~C(M$6I6Q{Z)c`u-kj`@Gqie~VGy<uN$DL~*p@d{l8W zK@%A%P%#*W{h#;8c46Jg7dUcix0_*!#XQoTuY&n=h~Kzj6@I$ggmQKA0$W=e$CwE{ z5Q7nDS<oLx<zAo}RWsRi3kMihU=J(zZ(<|2DB?Urgz|jh+|+f7JH2;4Q>fd=b?VeZ z&z)hcpmihj@Q;9(YhTc6&KS4dJ<qp*8G3GyAh*mx{5n0rjRA5PyXzIK7`c#zoEgnJ zefH3Wk#WL%(N7#V<QJ{`9tvU8rP<Ata2A#4fZHOpu>Nr=_|JOJQ*TlE*@VUDH>;cX z&J<I>+gGuzU=w^fGmp*vuFdSUN3x4SVVE`QJS`pT&uW^iS=*a^Y{}9}_Ge!d#NJD1 zHggBE=W+J9Cc=@uU0NtEP#i!OuYS{r{AP;1HwAm#qfuG#c`nNQ&Xn?Qg3{_|WdBeI z3VTmrGhbbxpwqK4M3jcXbt_nfT?~Uo<58<92W{WlA~Wp9xY|T?%J*dt?r4ekr`(3M z&+cHxYB>y3J_75{Dlh{TDZF@lC3XzzhgQq?!0C;dxX<f5oLr8$Yi>D9Gd~22uc_i3 z&7~Bx$_U2JoXwW}x&Ra2oPZ@K98om&2|c{s3Q03<*vuv~ygcVGEZh*y%#}@{grebY zkQrRJ7BQvL)zCUDh<1+~P2XmRQa|g<f{&qu#+@%=P5MsQo3W8KJuYKcht3q2xtY*C zhsV^IFac7|FTlAMFQdv`f4X<F9hz7O#|_u5aFtmmuvqkA-MWRCdVej3mQ94Qjt|jz zX)C<;GH0}P3d>s)4Ju*HtkU`lUveUhRCen^4?W<sPYmR8tz{svY%HdnOyRHO^swT4 zvf@RCi&)W(GCCh7&qQJkroJ$h4O&F#{lgA3{w_d6<8De!kgM2#E)#PHPvS3n{-A3E z=c4|cLsYGqMGu#D!GR=qE;A~bt-5!Jo4NEBH}PCID|_?`e7u6OK42o39X*>)g%pe3 zC!eS1?iOrozsKaB>4ZI7_A}2VbC~rFGpfHO%{D()VZKw%*q;y`sw|XZ`bPS=-Ax_^ zqY}Lzp^fgVOxS6CcQ(>f=svy~@IQ*qJgmmA3&TmJl9UETlY~kLNmA$C>y%28kR&0M zBqXF?NSZWj(43?Rse}fSI`3YmBq5n9QxZ}MA%yU~-~U}*4evQ;@3o%izA?mBfqber z$LhYvv~E!Vs6GqBihol{ch@MAt9{UPsFE~Xz62q%nF2NYJ@7Yh42pI$<h>i$iFhy( zmxZZ=O(w%`X{x6UHx^Q<tU~%MD-InNyD)VwC4xP{)?{L-0$46<f{NiEB<1!ve)g*K z)UoUkS)`FnLS`>v-jD=j$$erl?;CZVR}FN&6wl~tG7TR3!Ljg_>c3kDL9EP14D6_4 zM_<+Qmrjv~p%WGKfX)Q?Xm<#LQg&05Sw|u1p*xgmjT2m-QwUc#Zl|8NI;eYJ5pS0i z*Jq1X#0qj6793B&XEt9+kjiV)9hXb1sVJoAJ);(nTyQ~y8?CJs0dpA*FzT~m8jhIY zrfK)kB<Vh#>$(}=TmPj$4I`1c;0fo(&xa`$&G5#$gY7<HOG`B)frM{khHBQK$d>T> z)TQ(AzZYxKZCn&HRdGD3Kifjfl3lUsNGa?qvWGp#9pU-EFC<|6PS|!`K=FGn-Bww` zsDLfy!024Z<^b=D@^?n9kfN1#KcZhLNPa7&uV*{3Ask=HW~D0ixpjc#a{N(Gkr0dv z-Ue|=eH=qu4jMn4AkWl|LGzF%%ASrTj`nwm=$$&c_QP3-P4dH_S6+Bx-+n9?c0<le z6HIda0cStCkU2pj{7c*461gw01b#c_k~QCVgQvy?j-M3_u$MbG=!rA>^gX>lQ<6^n zJ{<?AHj~ZL$tb5I&fZ`X(P`i<NqR7q>04M&%D-P^+9kfA@sEG>n3)PXad(;Tk5i!{ zLV;`!;r0j{XJhK$Q|R-fiMqQ~l1F*<(0AI0>9*(>Ec&TM1M-V$YM?Fz>vPVC>4{YN zF#|pti_t{-4O3zx!;%(jp18UV%$DI$DTRJycg1#OIxeGT^+qBs{hl7m2m?*o59E4p z3^dN4M1xZ6NNYU@`qG?*V~1Zct3~R-Y|>gTTQnU-?z`}wo{)km;j@U-`(+So@R7Z< zGlkJ|SVr4!H`6x{>><~47K(7^{aYCcbkm08uywN~ByElZG4~ec<6G{zwYyI;?*tOx z<KuC$QUb=9{)g%xyfAH!2ySpcN!;Ftk@Aj4j)8ape<{6T=3m%}vI_zrh>DUN?pb#` zDMbxbyP$W?c!*z~O#cpW+4+BwWR7ei-IZ+s7nb)^$%QM(zBQ|fhR+5v;j1F{PYXqn zPu_4KsE+2P3F*l93bsvrGV5I0#S}~SW815zSaV&QU9dMAL}C|$rkXV!+98QK*DL6% z?jmfjIZbq@>T!M+?hG8}FG%9@Rej>VFmK*?=)V4iiBWw?-|1a~6*Zxtym>2h&u?KR zy6;d~ZjQZU<q)mQkpjE5e3CV_2tzaSn6taqP_<tcL}xgixZK+Z2kdK5d+B1z9*)Dh zt`vw;8i(D=UCc-Eqr~H<JXR@qf=J{vbKm*vxo*!VGG|j1Xsj8gtA>*CPm~L&nOtUT z<@0g1tpV;HT7|ytbA^@{<l(et27bDk0y+<rL85v*+*$LCy3}P5(~cN!R}@Mo8one( z4yD9zMieY;^a1IvNhtDq4b3!rMZParfK2Uo5FIW8sZ$fd+N=icmz84HzZ~5CoyGH7 zuc1nOBb}p`0VD2HXjP64PBY&Q30%jpZB`u5_~0L^>luj2l@aLKI+5yMJ%!RSve-2B zE$v(BN0h=P$RX8wq9T+-)o0acHRBMy70dMo4NsFc&w9KQ`;3jh8c82sYvj0&CAhgc z2%en3NH*(L(w{Cq^uUu0;{CRTHh<8<6Zcn<la1b>>6M8zK^ENH%c)XV37cS=44bD* z^7&f_n2?>hJp1m~sKpP&1BniBdiqn69}$f49Ddc5L$0TqY{jhQ<H4j<oxDl%h3)q? zKygPuqvL-W@-J;7`R_iGn{Oh}RMVZ@d)k9`=i}*E{p;}NwIlkS`ADAKO(lX&n_<_f zOK3QAke6$3hzV_t)Nx!C@ceU7v8j{YplQbO({55bRYRh3(uk-Yp9n4s2dL96UHUzw zh$ikohreDp;OFlgyWvYNuF+XR{8A@C3)i>xtDQmRzB;hZL89!q1v=QRp9Z5vfvl4* z_c}T+!<TBXry*-|1S5Cc=!G>y9Pj5NudVMpGwR#{hA#?mPVhLquv8nfN4Ar&6k{~q z?@1$$A7es#!dS9;5}R4v&rVA?OYX0C#oUeMv@f-sjOM>3+0RBv`(e%n{rCiI4OO7N zLFcLTB{7^_dygKyvIp9?>;W3cFp7&d!uL!~Ontc?UC-?z>M^gV?WP?1r0g8+yAews zJ^xAc(_YZtokrklSI6G?ClA$U*JI|K>-ccOY<QVl$=yA7L1udzvvhYJ27Ev!Nq-6~ z=)O*6{!`|<(+bdKGoCg*-h|_<I?1TPQM%eT8l5*O;=!YV7!<9<f6Utpa>qY0<_izO z`8+)usCS9A7Rw}~+EPNXYqJRQ;^5WmRZz?IFKce)lNr<6h@x5`bq{dDV#_HFk<ID! z-ikD8LcbGNj-Qpv&8GYt+sVIui|99BMbMfz0p)&Lk`QY@lBQ%pg^|g0%kty!z_5rm zL~P?ap66-gs#s=PpfN`8yazEuH!w%A0m&+NfuHLdRwhw`e`VcVn8tOQd${wtjobm! zAyC93(_gf(d>K@9?%=+*8jBxN^gkcOIi{;&_(T8+Q(~Y;BpgjNPqAf34v;@3Q!(v0 zz~Gk-Htee;tQP%5)KYHJMq`%9h4_PAy{^z-xC4#`uY@Veopk-xC-mhSZCpEH0*&xl zOs{-a!O?%(*yMPQ?P-sOt0o+${FDXx^s|y~9hO9!#H)0r{6P$Sx{G!CQO?ZwnuCIb zm5lTCdBjh#hRKr{;EAN{;dO4lLXA?|pjYEAlj|A_s|B;*jn*lgu%Q%!JAM%BiTyO> zzerkL)d9nq(@5l!Ibic8lvx)SMO2RV3jRKJ1LZ?VKXRQb-GL}xmD5tp$q;2#Oy9C6 zZZ(nbYRBQ}4pWdZIzgyi4@tA)SbxcJWI_El>c6po&f;cKgZndR)<QWf*?$u!X1^eL z@?$wqdL-G#eXba{X+qJ5v8*mH4CXCfiK?Os&_COjwDj*L6<<BTZPO&iw8xk94*sFW zc$|uO`qsUF7KCz>yX(o-J!l=KgPw~U$TML#u2xT`8v14=`uQ4Mcr=W-OpbztHy=n) zLkw2jDIimiab1ucZU*tTl-h0Xgn=?Yvh>ete9k=s(t8?7*MK6rJ=SJL-UVaQ*iZDq z{5jwg&5|Rl2o=56OgG$`0S9Glas4K4Zgeq}$sX<|l8Nak$;}}&P8NdO-s|Q*62Dl* zkT0-4$sLL56M8`V7SUJT0jjId(FBgK&^Khv*0}XE$0Y5k!Cx&>ZN=dcHthzLT^=0w z{ype%IsWGxHbQauZ<6)60uAiz$xnN6zOq6cesS1}?b@1nz?93ym~!rNmD}vyN?Dqu zzL5=AD}g*CTQ)Vw9$Mu$VLJ0mu=A(_$j!ZtyL^r4^hc`L;U&v=E0V?>ZeE)H?k|-& z`H5~`F^N=Jmyno)uQ{jBDwIw+hTaCJ*hwwv5VCd(owBNq%}jVm&(c-2T4)K5JqKxm z-c=NIl*19bHK4y_E%fA#5vEW5NeV{BP~8JnY#`?fg>&M<lJHCP@v+lH^mG@ESUQ`W z9WJ3|XBAOvz=K2v^+4_6pOl?<m3eUEEIqM%1<aA3j$dLJs9ml|l@@T$&2NTOVay;I z&{HEhMz=7?(u_KJs!?6ue8yJh9?jbOj#Q4nM|T=)bBwlWFlJf-ikW5LrAu|7LW-GO zauT#}o*+{sP57Of72uw?9!5PbvumD2;YjZyGJRAMt)EKpf4s0FB3NM_HcK2@gUn&y z#Z7ojVVZEp@_0yGb(d+^IuC)ji|MYWwM5wQg)A!w11HA;JZPUw7VG7J-K`h!D>MQ3 z8mBOe;?{BO?f~oz?IE@ii@5uZ0bkr@F`Nw3g5u0&>{Dt1FZ;EjH>(71pLxs-RxE`p z(=XEo)j?*a@EO^WHU%ntCHX_WZ<v*9r$MVt1Wb{WgPhqRKrb2c3Y{louiOMsud*Z3 z_ndM1zDQEJ@&Xg!6NEiSqL_i4O&Bw{j~H;=@p)OF*`Yi8Q2O!^aaMC7i(Vyx_(K8J zu6F^8J&82o3zB3e4Z>XdNT)A>s<V;!z%Pn+uC1n5!pGwi#eC3g=kgxQPp}_igJ^%# zUOd04k{td$5vIs!;orl@>0kt<T}uk#%RM8KcUzT_kgo#L)<9nSAa<KBrs3PZ(fG^^ z@cwp-^`D@D6$1}x<B3FUak_ysE2fe+JDTyo$I6%(dkkvbJE?(u20z54hb5;A1x?pD zb&sJev`)!}yp}W+ik`*pow-ay?+5yBSrN8rPNQj`?h!KuMX*0(1L*;q@XJ#nE-1Z3 zD%PC?Go39EdR-4@#a{x=Zi-H)=kgWz_>+Yv&qJ4FEZDegWnT8bq?0>5;OzBxB>vS{ zXct70+xwh=no2<Q&;;E5Ck3xtB`^xrQt-4nf*gZJvT{oXX6|u=XhxO!wdXSD+{vbD zz6s#<#1?B0J_CML0O^@}7}INKz>$|4aB1+OAbZFi@9g)Y&tDv+D-Io^QWFTuvc>53 z*Mr@Wk%yCu(%|w>imqd>vSb@Hb~llRx?!vH9Uew((ggr0N!e%hU1r>7*-I{o|7i z)oDW8p<OuK^@Gl}2m*a=7pU<MrlUvOIsZg3?cBT_8~XzBzq&wJP+E$`7)T9cBiVNE z1XA{`ir$Kl!OCl@)bLI_voFn&NPhW_osJ`r{P_{KHGgDn1O)HxDyPkZf0*Tyl8K3M z9{fC>3pG6|)T%&2sJ+~mn=|+ko918|J?<zt1Z2}Go2{|dTm<wS57S85By^6OMAVMA zkuOWcg%$-pL`3=@*X3VFvmEY{&kAMy&IMg`VN4pwm*QbyNFj4%ejxVzQp5$?E;L(1 z2}?aZ@J-?>9Q$)Db;|ioQ(ErAq^}xK6`exkx?I4rhx6gR<&&-xhM>}}#R~q+hQ#HI z(7*RL`{DpX_mLyG-=vV3DoF{=KFaa0dkl~-e-R#Ci(<NRbD%Nw9G9b1g0X8$@lf^| zZ0b7*h7~b_;pBfz#oJ?y>`ir))^|t6)}^@Mb`y<_yGIPOCE<<2CFt&-NKPg%;``m+ zOD}y4AQkhuz1YPVlJ=|s-+68Yl?k)4wQ?I&4@%(pC6V;4{s}0vwIy@%vmwda8+$A! zVf&lq{Kv`WQ1U>X?&3U?sRx6=BCCabe=!a!?bBgOQV|(HTmo+_Qc2{P_jFsLD6uN{ zfK8zn&^gl;>P!M~q%sl8{Od^Bgo})4@i5sj@SNI5TA=aG$8^m}LQbVD1JBYty5Q|h zI{$>S@QZ3Bo_KKy6+ew*pOwVor!9GaaeA=(M=H3=#!wN}V*=;BiQv8EIPIRnLtf5B z$~TU{@C|>s+?EcJ{Vk8K4^rsYZ&_%3XeVjnT?MPnzA*F65;(PS7W8jWr1mQb+Gy`# z$=(27aY6;TxI2V;+f8NMKV8Fx0d3fOF&M<w?IAUr#6af-K}XqHICa&0ZhxsjXC8Zk zejkp(a9bYi%XNh{_uiADkOT1NU>=@#E+;Cx|FNQnE9v}6`B3#u3pZ!|paHwNZp^}3 zh|P|t)_*4RWo|l947vhaYG09*?ZG5M(~nGCq6@}Htgu#P8$7*o1uyvp(J9*&VzdG> zy<7L;ksHs5ruub!{`Ednq3DAl4c7Hy^1&qh5y!9ede8iom@e!y&c(vg4Y+^$31WFh z9z?APgmW2fr9Trf_vc)$7n;fCQey>Y2MqWkm%^`;ZKJI1b3^n#bBapLz6s8!0UwO7 zqh@2pVf8c49q{%(@f%EJ0>?HpK7L8yoA3zirAJ9H)xv{p0lM+VFcp`kqOJ95?*8_f zF^Z}Lo2?a8aep4u6ru<E**2J3q(z0LmGE?*Jd9Q(q1L55&O3Ju#`(KJl3g<t6@(Ev zl^V9K(~uljJC7O?oP%LODfN~PB#jR&n2@<#Zb*D3)R&)!O9`)eB6U--wpI(adiT+4 z=h+xjydHy8xt&9i1zy?wfXe+EV4j96LFK_57;gT@+FrOve(m3f29s;RQeKukXdxV9 zcP=VMyoDH@1#oMd0_CMiVObO(O5|m!Q*R+t<0guY{tN{9USa$V0?35d;%MD;fOEJX z16vPE43w{Be>V28u3jlj>aHCyYw<qR6C1+$)2&EYP8g^*bde>ymeI{gBG@)N7biX1 ziQg+cNh{~K9l5ZMdI%GU;E+5xHa0;^M?A@Mn@2|_ccG4R0%Y`EfTz)ZpgqkN`|@AX zs&NfqmOdL#=-nnCIezhC4_91R=}F?VV%YJO`b3|bEn4k90<F)g&`iFW2BjUq(Iruk zJjEOhb=I*D6*Qqu;Q*?<>4uT|wHP=Qfm)lU3hKw3!@QRL81OY4e_Y)F=MGM!9*H8t zeVc62AWIA*$4nJAJ$pjTtrD@*$PCJjj=-;1a^TQcz_h=ePP@AXcp=+3Cec=TQ0cnB zh#5CSUiT6h%8Eppzio8T+nZc$4g?#f0<xzs2a)<(kam28d0Nd_CFO;~!q0g7tN~vu zJA@}Pju9Mc*n~f`EAd=V1O%C!CNn39Vz0a}$^=iwsjd~+%=ts)xLvB}ybS!f{w%dz zF&~;TGnlD=<RSXYR`ltqLu2(YQmZBhLo4(c-s478($1pYslKqHNDB&ITt<bhO|Wj8 z0kl|1(b0%Kbl58da{Z&|_5Nxadc%@>&klkTuW#tuwwnxS_@a@JV~)CHK>6r=esRY~ z_7cyPb$7pwQa{XTYIP$h+^!|HdZ$q3^#q*M%{^aSw|}TV3szolB3<Kdk&gRkpm?;6 zIRLW!!lG5Q$>SqgdC?Oud*7tFYglBy0%m;=1?F!U+D+~tI&m7%)RO@=yRTr7_&9ca zMjXy;{6Y`yxd=&fjv)E798FdogNmw~>~|>z{9WBjEx&&z`YSh4?N$-uc)}VhU){wc zAMaAvg?sR(+7RZPk^$YgX{6r!Dm+yzr|%!s)5ZUS=<UdS+POamM7rM9S)O=DbM{E_ z*Dz;s$Rddt*+nx+3;2vETSit|{AQlCzJ(q|Nnxb7E{c5)!;qXJp2S@v?Aff0iUoIQ z?rIOB=4b;}KTU8bK8IuqH{jjFi*ed%CHi)yHt3(84co^S6Q9HR;IR808F?B>{omYX z4tJ*0Lz0eA^Ctw_k}Q~~bUNIcas<~{W};DU8i`yagSxO9i$1<&@A;a;#|hR%rLBY3 ze2k;1qM3Bt`spBj_cZ2x`++HY;vjyq7*#O{1h?%9G(aI0yVs8Jx~C)jV#Lt&RtrfR zzZcHhC)1Y`?J#(YJrsnFqlpzkct<K3f2F*pHujSI*YBM`w4sQ8eCq-O|7ns-hdr4C zs^3ZGpQmUnrG=4G(%?hYTv}ql-Q9+7kkl|GvQ0x3ZzXqOBuNt{Ow6ZKfAHxrEd-}u zBUDjfiZ#mrNR4JZQHUtu^6lO@O{a|L?BmY#(;SKRMRA<tdk}8OnZf1~InduOg2kh= zn1eN1=$~87`R{sh_kb#Dcdw(}W{-I<5`F?N!We4X;}OeJpxbaR^E)CGZ_HkT#$OWQ z@cAdG5wR9`4Ygw6fn3n{?}xUk&*aU7N5ll<F=?xSec=0=a$#WlW>zU|OIE=CSq+S0 ziUVBwR70&S36xjaLYt<$@W{soD0$8?<9|M<=MFui)I|wTae3H8b5|_w564{f0DNb- zjry)WMC2ZRV`X<eCeejnr21t9O;oO>V&S2<GG+owyqicC{#k?Hp_fkJc2bg0{m7re ziTLaAC*r7f1v_3Ihh5HxSy&VW&o?@Q;rLMus@o4ayEs2^R1&ZFALp>xAi~$nsU^Id zyScsd1Zq2f9PRA>z&>(q1ChbsR4A(szb@B;<yS3KD?G}~Q<MYa^F{O(w|DCu8Aoii zjMz!+P7rzR%M5vykcoW~`0<)M-gvMLy<P6m6>|#dpOSC5U(1-A8+)L<*fAn$at(d! zBB4ds8gCpPC1Um2ytEMjq5c|@XOv}*;@mDPsh)fZ)@EDPUa|jNXA=!9qto8Fqvf5e z#P6{o<~7ftI)kg=tgWQbsZ<&*$!DhLKn!mG{f9hHJPcxlW12X;#LGw5!g2pu;Fnf_ z+9v_uXUXx`pE^c-PKKhaWDY)^^piwxd_hHyw6bcf3m%%nqk)aPVZR%fu_**<5EzXT z5qn_m(|5EtPyhvLr-}CPd7|k11ihllFmG!KoIesmo}JF2<JW(HNNzV{H~R;TDAT6= zfh?%?+Cx7Fs$pwz0_RV1Bi?0mk)3p&`m3iC`*UxJAFF`(jaB&#M$d@YXLayvQ-Nmh zHe7N`iDPza@sD>WW9z|md@qrW%k<CFDfh?W=-f|SZg&>b)?!BMTFOD>UO$tw{4}>y zF2~@*LFBT<4A^<;3tsu%OkL;i$JU+A5LfNZbwiKCF)dHrdSwO{Z+b&SXYjzASI%s6 zv%$pG2}I_S3Ov}r&1%~>;-lVU^iItz+%-9wh#Ff%gvoPytLz7c1x(~SC}cpQ)?JXF z`VI5v&g7UvKWTP}8z~SQ2ZFR2LPheE-YAiyLukpdK@^#gd6xyOyc#N2g_4BH3;DG% z<=jqU6Y&$ZrIB{kaB65V9$h{MzH^R6DgQ(GXUiDuR+~qj&+j3V*gcqdK@(5-hmea8 zxVg;w7cBOj1RbvrG*+~MwD$i8Dykj$y7mVC$LR=7ZdjnZW;1k-{lFBp&Eh|dJrA$k zi=ityl4@1d;?OS#Hv89WI&;hnKL6|~HhO0;rML2d28@SIJGWxd*Tq6B;TBl-d@<Sn zwFU$sJ8`Vu8d~s59As^U@Y7U6*!5Ntu3fW+D;vupQ)3kO{52;n>z>0!TXS@e*-ed| zBxt+lLcW<bH@E-h0l&Cx_1Z1{AlG_B(75?1ezUIz?NTcc+N{J_lQv>r8xD6qo&~i= zIld*ASsih;gis#_KCDZIdruaDZ4uDmo4Po2y&~9^7qEex|HHr|AMzVx7_0Cow2@lC z3`fRd-r<=r#YY8l462!ZwlczJ(qrJ>;35#uiUaLnQ@TihE`a$e@XGi~mb}x4A(t|8 zDM5iekDtjdls<;}&wtQvwf|7IvKeB=7~`Bry4WYF1?gX7Q8M=y8F+LAPHWWR;QF!n zMvBmDYfi)8&R1Nf)W=-Myc-@yZ2-?-Cs5MLkx7otMU_9NVe-X4Bt3Q>?JN}G7%YS6 zV)_@e>!Qi<{wy45`%SNGs3hs4o?Lc0moN3Zk}7_7pe{!pXx+_8F!fI^Sa~O*$^HwN zaqtW|@9jc6$JArgh&^^6ZD9ZI{7F{73Wf3uoH&Fh#ITw+Vzl-cbT17jW`f=D$SDCB zj`^r}Wh#G<Q7q}@cmZuA3qfR9-CWDU2A8i6hfq6nSb2Oih(1z>C6W=aV$pjNV)Uv0 zSHgMx_c?}a_FoF&jtxZ8<F(*PD}&pvPle+4Wh6gG1ALQv=-!<iSAG_Qo#EMFDk%nT zJ2#-)<p)H5s}VT-7Vrw~7NO+50oFZSA8QvWp`!OInjLow$<|={V)sJ)$8}64Qcq&V zvfG&U>?=%)PiK5yjnWaF?`+Zhy^x=D2ikHhsq_6X5NVI0+onwynuv#^h*gNd@S#3D z?wkqqP?F$mQ4fSHp2?G*uo)YL1{kQc8Rl<`MZ-yxXqCzhdfU*G=o^{SUZ+-SsN}{J z51%15*0F+<T*r0^E5moTtHNmKW*Yw38g&B3pheg?7_7ZPoZd`>9`$SB<2x2frKB)) z<SfwYUCboe2okb!1C%(0(MiVcXcw@W{C>Ebn)U5Oqt;Shqv|~}dPh{KX>y4?l2rk@ z4;$zll@oMT<7NIlu`@L3rYok}uEHq~!->7<5p;F4!|R=CG)Z+TI%-B?j~{n`J}`;4 zH_zvI*J;r5Nd=}IRKYDeCLp%i97R%oQNIe#kvvg?wH%oU1p(Vo&R&f*U6%zi|Lw$; zucOGCXCvI1N|7($A`e-1n>i*C=h;q<hc9<mqsqOV;AG*9y<;?R!D~mL(;o6fvTK*x z-F?6wE>S>zOhuFJpV`*C+BCa4mUJjRB-gBtgVy6hB7JK%Kj=mbRYxfpX!(y=t|(?6 ze&GJrc}TK+^suHZ33T-=+1QWw=t-%QP^%qB)@hf*<}qvWNvRv1aHNd?;iEMOIlqeA z@9p6C#~5@?N11h}lVQvY7x?nNm<&uzh2b1SddN7Jo_lCXr^FON!EgjBZV7|>H7Tgu z84YG>zsa&+gS2v^1E{31bWzn<l<>Mq2W6s|v&&q-rQC;(u1%uB<?Z-rj~li)CZXGX zU1}Wp4%g?|gZ8c;#OPrTBs`0!-4Mddj!Op>F-=;kwgsIG(&?v#A^2xSGxgfHl*F@} zQ6ypl?G-v;&5LLfzcdwArP~2NZx#q1NJH=5I(l(055umXB63onnJa(wVepnCJ9I6D z_w;o%E>V4hi*-t1YuZa{dOV)+j8*XQ=~k-qSqYY8oTU{q<><IMg6r~k!dCtY$eyeT zU$Y7H3RBQ4pq}WgRwedfo%D2IF%<tgjGw+ZqS^aGEP?khH^K_<49W7_H*i_R8BO5r zB|(n)ULnPn_KarBERcw@<QSux@cvvZdUu2h4owQhwHc|T-0uJ?Pn`~dUga3sIEOsD z6^G+vC82fi5z^?o9z+!7>N<8#5Gwu(LCbT~(5GCKeD#<Qjmo#l!1Ft#;xWglKOBO; z&zaBz_9;ZQUW8A?-wA%*s;2MfjL<;u^K^JZ8d%DX((K_{I{Vv97=L#QHV&4P7a9|Z z{`jY4?aE|W;#>nZ2SSPR%Pr{BejSsJYtfmvCg4Z;d`Q7ru;@`T)CFr$krOV2mF4n2 z>~pHUet=!>cLmN&T>-~`9>7i7N!(|*A{gaX!QZfW5Rr6c)^Y#CFZ1H4;_xZVi&_nr z9!x_y&XY70{(|w_!@`@#LD1491ev%RlHxlB7yO+8ZVij6=S>Sd?&O0@T)ptY&TwqH zP)r>pGz9vwnsDx2Df}mrPA&RwkOgzB@qT$G?0is6EbD&L>#5slME@{|gv4AIlj))^ z!-v_%a%*l^t4o~%#(-|N6V))dLM)0?$U$F@(Ry_X_V@>)%RN7c$#6&2x6#zmG>uK) z^pv%)oD6H9MWf-gUi4zB$k){rW_d_L8jhpp+v@0krE+8fgSiY>IeC*=N%yRI#`TH? z#6W90oLHC+<K!DjTdWpc7o>z6)q-GR<1ubuaTN6TB+%TWPpQzb6!Pb)<3Cw_D4V#3 zam)+FODQMGl__Cth}>-O-Y@}zeNS?JnJm<*=5}uSC1`m&1M+;rDczN2KIIF?)|N6t zX-J2cbLyzT#|8@nhDb}0CYU=(;4Z}+Y}sqa*<H5NFFF&1|DV}EDqWAKmUW=6ZV~zV zF%oUKS@gq)n_$Nqj!AX)EgcDwBaKET)Hr7nmc257o}I=-GUx$_J@f#{o=EHq4WSvT zvhenfDr~fV0xp-g!^pr{_%?C|AO02K#kw$@&?O>NU82d)w3^2fA=ksYZipwibI+ZQ zI7oV8#N3y;Pvbd8_<KKR)YmD;sh@|LqLM3EYT}1Sh2v?-wO7Q5Kc4OHm<k+>8jBtl zV&0B%#K?t`KRV@P6R#58{(a{;X}u<gPW~i!o|K|b@_sOmJVL@A575A}4mRG@7$g@x zry))@=;PVS`hHM_|H>NB)NlekpxpOt*g;C=&O&tPcz&^6gTPzGlJai6#Fa~D;aA@* zNI4@;x<lizZNe{lY`Fl|PK(BDa|eiDaDezf`$tY>W&s^PRS;Y81xhw=qcdK16VW-+ zTwm)v6(kC<I#C5pUKT)_;R$q}A4ReswUa4a&+a?_B)X5!p;JGs$AQrC=;HVYM5Xs* z5APqHW4|7p)c4bm8@lKtSqZ9G-~^g)pVEC__7dGAPpH~-ijVw#m<Kcjw@H?x;ph8A zOMVIIu)POKa=EP0R6nZX_<<H#E<ud}YwisFnCZ>YMrU1Fer`-0igcW*yOe*NO>7a8 z9m{%%v3@Y~Z1NzqzW#=XUM#~Wr)Hv@w+ESc@&+x{sORSRRn#YKBFVQO2Q!-{;L#(s zL};asAyKYW<a=QKz=Rt_yKy>*Jl#o#S4P2}*&Rgg-B=>x%s1c1|3%&>?FAphGhlgY zJ}oP=f~{tbc;#0%COIzv@va3(3#;kAXU0@I<3A8_aN;d&T#wGLDv4y+1xhX`0oCK< zxq~k-=c_HK1tc+B<<3FK5e@1-HW<qj+nC0w^^nzilR6~SlMnZk$bbRoo(<lM0R`c3 z_6SRr&vRL;$(ymNPY-3kP2f*|$~kFQ7O^nh3wq5C64_w~8atdts`x^@f7XTW3-$sy zxRw~MSp{XhW)jA1AzgbWp@3B2WZMy;``vJA^m;CPZ@>~%mLA5&FJ`!r%Q%dF$Yj3M zMZl8J*0}FaE-~HYPUdDik*wrX)P3<9NWUNjF&ntKe5(hIPkzNQ+b_|l^%o%}@eTfw zio?YIc)El0PRuTU1)ZlQVM}Zto={E(({pj;$z40t$-YPny7VBlzXWd_IgTB+mr*q? z0fdX&AU(+*oDxou3$HG6JFf^HDLlsRl9`Rw|8l@BriHp~e9N@^s6$PKI2y0!vM+oy zsNK0qn6vH_Y*G$^VM!(2vhOf8S=&QR^siCBV0rXC?vI0WmY~s_k90MEJw!WxWnMbA zlhGNM*a(iTuCd@fvstMEvs;H~S=0lj@WxuK-5`%=CP{*bffcVMN(0@lSTpIe`*HjI zTkxn@gsAG9gK5wV$ocO%%6rCw^S9|B6<<X&#ja7SN*TVE`X}=#^OitJ12R@?{7GlU zZpO?x3bHjAv^Q`f12Tr-?7?L#4@_o1Djg=>sVPjvw+uMbn@i-P*Yg@P7J%?c23zMC zPm<!)arCn-`imOilh?=S+qguUx4H#|>jb1z&K4aF-jV{|A(W2X3{>d{Z69nP1^wal z%=}?;ss9Qy@;r;psm_MByt~}qXl{LMLp8nh%7)EL9LxOoZ6|svo3o8m<Zz0gGDGK! z!bFAfLb2t2bboRXxsVl#b+c25>3R<^zo-Yw)`_Smr3P}_#o@ru0^G7g9`EH&;v0xc z5)bzfG+uKYBkP`%z7$GpluMX@zCk#?#Ffqx$bg@a<08+9qJgT4SZEpv+4;}t%k={2 za+m^&QrpQBgKBJgm4PQeoB<z?HB@jrfTsHQ!oO>}m{K|p#Z>Z`CtB_>Q@fvY41A-X zD=TR0S4*NiV+Km-$Iyj~Ldl);1ZpSG!o3^%!G66JxK)^d(7J-y6kotYpYD^!PxAb% z#7NZsd;l$i4RCTl=Pqn$;^wJ8Xv+^J(lYi8O}^FuZ5<m)Li=7&mpqFh4sUq_Pew`4 z-A8!9dnWGsxE@1yJcj<G-c)YMSva_TDysZvg3T^p7&m!ssB5kz^Gy9wv?`i7E6?Q4 zF)pBcZYp};T}eZR25D{I1ggiKN!KRaq+0YRO1l1o>AzRPs(^IZr}rNJb>Am{-Irr| zmk%SGZvdUc3PP`ZNz6NtPke6~V^ZmIhI)-LpIY5REhkoy`Nhh7<z!E47+lTF*rkjz z_E+IRfdyusSAit)<HW@32#STBrxjMWN%515B>RdTp1c!69ro;H8Wz4F0T1%&@^$MW z{f8*#wTlbF_C<iW^(Fj%;2M4tDTJ+~l=8!BAvf_AiCC$_H@s5`fgjJo$X7Wk;{6<Z z=J=4z;lET&W*mPRvy--o$I`~?rBIYH17;{S;>w_z!fS#&Xm#7pb^6XhNslyMhEwdm ziqGT)35VV^3E}i)uA8^a0xX9sVeMa0q1kCg#@Mt3mYz9?-GlMw^B+~yRj<_f8uD}D z$D+mHb^S7}Y;T86wrfbDUouK4=#Y<T32>SFz0c*{BoB4dV5CwTZ2w8~TO^(`&DC4r zM(YLWTImb_-JK0$GYq(W-VhxlY6o^9GVC)?4{ZF#gW!danH}Fh;pIRf85~N(CXTJp zw!(t=#pMdNDM<*&_xMBN77w`lXD?Xh_tI;5RuHs|V+BZ86R|Zh@Z?AlkyV-iOD13A zT%cBHc|;le&Ga!%C4zf@n~V-8I%rvm2GnIbVhfu?5-!+5{;_O4pss{L&875%Tqx*1 zlcc`NkJuC+7PM2gLeS2BOmeCwlX~~zl7@6RI7S8>62qvUA+T0SCCJzQiZ3JdiTXe( z?o(QXk;}44LY^3o)Ftyxo&-^cHGXW}q_LRv>=(J|mj-jIxx23WBJ{gwPL4h=pbh_G z@kl}*&7ZAKLk81{^R#|0n=u<54hqmi_aQ0S9ty*q4@vs7XyRK?0Q+x8qw69yevZm~ zBI{}ek|F^>v{ePK&q(0F#KrLCpAK}bmjPeTJH%Sb2n?1=!JREr@b&Q`d>hn6de5x} zMUhKH%k&I$c+4iW5Q&02xsTYwRXfOr@3EA>E(a|CEx@j>cF3+gPuzVyu}&<L30uH` z+f*rfvZ;+0Ul~KSB!1B6lcr<5k|7p5C!yTnHKuN?GHy9lLB{g94%2}_T-fy)cD<fY zy503q(ws+nw(o+!r$S&<OBQ?Bbr2*s%%1g<657@8MgD&SbYQJCu%UVo=<<MdS@;^} zeqBOmg@vI}y94H}$bx_MJJD&6G0iNgU=JN*$+dfxbiCygn)W1>h!lxZ&!aW0>9%wD zc<vYO_3;D)2R&%Nx-OQvsG>9X{9UQLK&_qTKwotYNEP3rq4hVg-!2l`lJkkm=`iNk znH})vwm%Ivj>IVegJfJ=2n{^1iFrQ?$Qz?iWVuZ@617O;qc=)E_THh74yH5VDrfn3 zQ#xqgvj4Dc+(B$xzmtjIn~oJqpSgM7DE)M2BEC`2!JY-tlrD0m6~lcrQ&0?RjwwKr z&H`+HydM%yEkP(VA-6Y+fknJMiS}6uGo?LoP)>sGo>~X3zq!u|Z|-MoypPHQa(tEc zi6GN)0_ygOLD?T4m~TD<EpAFeSY#T8Tf3kzJ{0mAqs(h;N{Gph1tc^1GYwebgQxlw zaZ>v!+S_-PH2xKXX|IpMkXs6~bD9A^B<TcwZm9^BG2<X4O~%}Q*J;$cs{q?BYGR^v z7|09`vR7{$q_^y=fX1(_pSh+IQY`jh$HKX|^iBzXuE#5~ud|J|&Pd`q6iyI2FOGc4 zc}ZH9mw-gJ0g;~+4|8VakcjpQYRGX4Te9q7+lQNI@hb+{&Nz%y%LBhS5h$Lxm>1OZ zk;ETUL#ywn>6-}dtmyrOe0?wrUhhyu3$}=k{qGMJF6L&jPb+Xh^EmrkIS$qL?SLEV z7O=757#wbVN!wD^v9b@3L&&deTG-S|BlZg@uQe2FZ!e{Ri?zw7;6>;xmPq@P_F!Js z2f^@v`4Aht3X&YWVEny!ayRohb%ZD!eR`4YerHbNUsjVco<Dv6Y$6@>-+*B`XRzm9 zC`23QF&-&$AgGI^$G49|-&Kpju<AH#lFZ_lT3yh%o(7=53i6iDghM_qU}ct#3wn!5 zo{(Wqj}ya#I-W3wzY0wrD5I%CKC%i;AT>7vXXdE#MFK9@HF0O&FVCY%<kBc2l4@$! z+n@uRPA|t@h8%NAtpJ+?_1Mt3DC|6FM$WE}L@hHL*mnOs%AUy}r75e>;co?N^jm@q zeV+rD-mPcmwkrsWmW1N->s;3VQ4!OYYXqBb*ue6a8#(XfRJ^f58U50?3!YSa5vz%s z{FzHTSs|Qfd(Lrv-h)w8_U?7qsV|OZ93x7$;SPZZ2T^8>6ysXiP0CbDiS4;O7#Vv7 zf)21`rjHyFDa4}eS#;WTRV-01gO@WWf~fIf=<A<Ii4EsVeLfa8d=bOl6Qb$B$8?TU z>I@U@Qm|I@ENr-=2VpBJVCJdou>89h8M4{Py1l%~d%yKM%IGa1>hqCavdZANuX1GQ zzeK1eYoVK)mx-5~kSp)&Xqkrz$8(#HjvVWL_kaXGF?T|l-Ai#aIE(6U*CD?fxI1re zHU!=K%^YjYCr=km!5o)*82Z}CI7f)0S!n^aA8G;Ttv{IBdoHxOP?<_BvIo*K%sV_~ zCpl|VNNYC8adX)M^0-PFUc1TTV#P?*owWlJMhSZVTuMV;fWUk8aT@g35ZZ$qIH%r2 zJo3nq9Fi@E^+r<gE!Trim-40K)>4cc{YEXnRx)$1b<mLX5?<GPCGdYb3y#ldhF4uG z#4w>&kiBpgnt!*4qJznxov|BaS6ZOaIwkC^sDqlB;;22`K|IodKL4nXGCfzx;|3FY zRqGJs8K}X|sx;^eO2LnXU6jA!2p&Bb3T_)t@gkJt*pr9!p!b*^&UteIGD7Te^w27l zY|kMR&RT%=)v0LoG#k^;FXm>&)pXGmNnuWsF>d#shTCSpLgP*wvQ9DpXBw@71uyNu zH$o3gnyOf>AS!sOev>_|CQnNieIU{<%0zGQ28eAm1C=pes8jQb`kj18>bqm$yW9&1 zuUZH5WUh1li)f5iy})&0R^Z6y?<m=*&No~6lrhfw%kZL{@or)*+Oxjkcv^&f6`6rf zA~$FkaC`rc4OpD~Mc}!JJCCo;z|ia7G&F!ahn5``6nyU{M#g;X(agc58CRL&cUtf? z$DQm6WwCg{2-|9~4qU_D6R&UFj`U9we7Y7*+!eBEUY80R6zTw1IZoOlt63;FluY-A zjD=Rm%V<w862Evylp8-5_=|FZC#S|Y<5(1aA1&yPKNa}k@k1u)&{@#^r%Sd=#AEuW zhjb2{gTQgeal;39NHEcbVW=YG);2;�~R9+eG-OhQsvfloXQvQUcFJzM=(t?x3-? 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 _WJ)?`8IXMWHi$kIB$|uOZvy_X_ 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 aTniJj#gi2LbtLNinZb1P9BE=n4ErBDLX6V@ literal 0 HcmV?d00001 diff --git a/examples/hubert/tests/sample.tsv b/examples/hubert/tests/sample.tsv new file mode 100644 index 0000000000..6f163c70be --- /dev/null +++ b/examples/hubert/tests/sample.tsv @@ -0,0 +1,2 @@ +./examples/hubert/tests +6313-76958-0021.flac 190800 diff --git a/examples/hubert/tests/sample.xlarge.L30.len b/examples/hubert/tests/sample.xlarge.L30.len new file mode 100644 index 0000000000..7d3028fa24 --- /dev/null +++ b/examples/hubert/tests/sample.xlarge.L30.len @@ -0,0 +1 @@ +596 diff --git a/examples/hubert/tests/sample.xlarge.L30.npy b/examples/hubert/tests/sample.xlarge.L30.npy new file mode 100644 index 0000000000000000000000000000000000000000..29d8c0dabde961dba15f55f2ff37ecb56117792f GIT binary patch literal 3051712 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≦8St}2$Ou9nOCqik%eOsKGqyw{E zd{HH!5(*=RP|%_<+G5U$)ov}tyK}yB+rDbyjk0idhmM&)oPU**UoXuT2>Fvm?QW(v z(~&Y3pM%7?A=sulklgYtAlt<hXGFT;hiMU<uHhhyn(%z=7`BnVnfCCxOvq4o^|HG; zQ+SWTFL`^>F@Ayuhdciyga2?t=5i(xKN-lPTjp#`uv26=|LW1bo_eT=-oXX^%3yD6 z9r<flWy$B@C&*TfV;^n~LC@eIn3eIKB}Q07xwj0-C5<7kxwDv&=|l=mZesqA=c9t( z5z?^pAegq%d|sXhT^lasMX9dXdPDFvthU1=JNEFqUMb>OgFxQ!R3avfUq%_b4Pf#X z5v8SX<Q>b`3i;7{O#kmS7iaSkjDr*@a%u)@hFoUzvw|t2^#s0ZN`+X3U4lbgnjYKQ z@`Luf(0R3&@NS|JeXq`C_nqqTbN?OAx_UNwFKy%>ZVHFNRKphU$;Iv3X4JPpa1mTE zh3Y*qP;2~_A2Vh;csIWl`FV<odtk}_dy&O@LfhbU$s?BJ>P8u_tDsr+4U5*@%%p6R zF*N!!bh(ca-M^zk5f!bhZ|r^c@Zn|j*$^h4zakh%tbWb@B@Uw&LypGDo+e)dBfR}E zlSNm&<g1EKutWKcWFqYYI<9-U6Z@*zcIo5r`ow+^P1c2W4Hd>Vod(VAGOX9YgQkXr za288ban#GXOzOKOi;y+p<y0Cl+4V2CdvqZt9UP2TPUmyY-!wVB?G|jpzDsPtrd0Hw zs!nmsi@-|ZC~Ewb#)CVPaPt@gy5SwerK#m$*4{pN!}T)%0Vl~M{W5!SZV+VNnk(+y z_k`)n%Aiq@I%fAo!GeWrX}@$8Q%`*;&XT^!Y}Wa*_i{@}swI~$*SEo-T`$2`aWxk; z{TN#upaPD&&ynv28(J%Dqc!SMDe1KZi|RJwx2XklD}*lPw(x(P$>KB$^`1d@MmD4M z0x$mWiRlzwoDEe2hM-5I6F%<{xXuk*NY8pebzZyROlt|Cv4#)D!)7j~kmTX`D{TV! znjhthDt(}A>v#6hG6IgI3j7Nl6Bu!@mkag!$oWnC4qK&W(q}x3{|(K8?BS=yQF1dd z(&imYR{qW&|LOpFm)mGJN(HW&%w?7fh0XhkavadLpLVv#v40zmK)Oa9>NJPr>orf{ zsa6c?-&A8smja>iw-24vQ^MJ2n_$e+;c)*(7ynfBgZp|=4i}m&!vWjdLFva>dOlqb zSK7Ff|Gc3TD}9ZLIyPW?>^)As`zOR25t|a)$2_hrK>3!}FnNYAH5v=O{`JSjzJHW) zSwR(uSEu04$!(B(Uz&ofi(t>^0IoI98fPEgg*AnJxLs}-C5mS7P6s^M#7iy|@@O&U znD_7lwluKAN3+o3)JuA1W{1gvvtZ~)Cp5Tpk2ZxnlIytB;$4-8*;zX~I5l6J8TQ^~ zwhMAm(s>JYHa38i)E+G0)3^ag_d>GmIiasAT`f^B2Zz5rVH$NkoRm!hD{XkmmT&UJ z*<(sDum3o!hz}KZtUUkNLvVX7n}ZUY4kNq@<SQoDidQamua>$L3x5Bj=sX;;`oB1i zq)4_(Mk+~?kW|uh&v}HFQ7NTJ+CqvZC7IbogpiOVElTLQpYtSbX-QftecNeBD%J1) z{srUSbI*CdUoXCq&zZiFdAB*^xH}zu+W-@Ish^MOzKgI(F_OMaO2+8!Dw_X&GgKxW zf%|iH(OF%NT{(G(EIu3KJ;i&FKUMI6y-~yNE&~jnUBPdWvqZNOfs#cJz2MW3zpz9j zg~k0k&Xuin71{RMv%~KX(5SjOsPc6&hIeV=OzYjua^QY=zpn`n+lffJQlC}^=u_Gx z71H=^#G($KgGaqX=~iNy<ga)m%eZj`P8=^`;}6*5qR*qyH#CHsw_+7Fn{mu%;tW(= zwhPlkEYZ5$hIXuTU_LE7L@Sm1P(<E0cqUb)GqQWAS)xzfa^GR%5Ct+gUdvV+o`DT% z>ew{)8B2V8g@t{*A~JL>fcEiT{I(gEsFie->q$tU{hr>SRnf!UE-@yJr4eAaU;uUZ z*5QuD9h`b=8s&LeQbCmh6-vrrO|w02dG&xh`}hvX@UjAXBNyEJ`J>4D4y2Y`f{x{g zGh`mXEdQw(r1XhfY}=PMH>gm1_iVO*OBFY%QUS%sqQE@wIr|sW0j+NL*p=>h7%hO2 z-?W~>-QTKsk1hMbyz)3}(G6o+XI3zuLJi4*X?yUf%Wx*Y;v;+)9B*#@mWc|My@nZ2 z&q~x%s`%m+reqhs06y2v6oK&kUbJQrDNK6~<=5lceVJlvOpBslhlg>tfiu~E!_2Al zQaB$p(-21O9xpB*)5J!unZdM|M)OOC?*|$8{dSET=kboef@t@N1XAcpWTNpg(zCa3 zGcLs+PrNutH=5(<SNRTV$p6NB4ciGP&P_p;AU&J|ru+v3BmDKoiT;-SVmk)=(u>E{ z%<V~t=)I@_imgrf1Cei7PS+w<))FOFyd-p#mnYEEt!t^}z-T;d6eYOCr_sW@Um>*O z9Sm7275WS7aMsgcko@vv>S-&{@PsgboVRB~9?at9tBs{2eTszKH)Gc#{V_ZAiDY|d z2g~`-4k0B&GP${0ayzDp&kS{gcTY2!LVY=xQxl0_9<_3D$0zYtH9{8uTr~W7m%-9_ zC2_S*BPP4-pvu0ocyzEcZW(FG$<8*D##PCo_TpPK!FoB(+}TIEtYanHF!dUI=Qy-- zG2#k-Po$0u$>{RM5+5e@;N(;}?%clDEKX+<*wrUsmr5Sn^&|<mzWo9xd%D=|cL(uK z?Ib+)?g2^V*VD9dO4N8-;9U%7aI8j2>?c;h|9<>~RDtblmEXhUJBvjsCW`pFu8x^h zo`s#0wZ)B}JRygT2j55k;OSgrsu?NIKBqr~6CY*KUziQQz2A#wE+cUIxo*D3K_5Rn zdI+y2d)dX*F7{^F7r64*gWD#}kj&e8jyDnK@SobOsA6CknuWPT__i_Vzw$4oJE$>- zZ6mP1uO~Zwdp%9I%faJ$N+d+vaJX=Lnyt~7KE02G7U##Pv9ArIhQz_G#KT~qzLYuo zZGeH^J^b)PvZ(E@3(W^Uz*`S<Qus(LyVjMNy^wO&7DxHsJ&Dvm-vrt6T9hc*^AlF@ zWKv;<9w)lNYE5)d8tlg3xl;f$1SiR;Df2Mvm<GIBb`zp~4-y$KAn%tdWDzBzX@ZkY z(IyB6W;v2~{sR{EG@8G<NRNWn=dgE1YcP;z(rWio)>hX<_7|sO>2xhvS*pNZzr0W8 z;=j;Z*DMij8%kj#>@nS6j}ABbvLx|>iwlM~!Vc_$(U(*4%Q-O?DcMo{b`i+kh(z;4 zRcvp|11c>Gr_hpQcJ<0~xUx%|z~B%D%BHX@e<LwswXL*qw=-Y4E1#V%`_5Uv7dRQm zqeVx4q|#R3XdJmj6%}5dWY$-Z;wx@3H-UY+aN{esCGI*rkfh*G1$puE-`gRr<P>PM z88WlbbVjT9z}TXZSo&6mcT8G`(nX~ZQ~pkJB+4ESyO?6{heEbH>DGl$hIW)!n#Wt- zKhBN0YR|NW2gB#+Z?N&=FdAG|gSFWXlE!1v@HXNwUJKkO+@6<nw|+G-tA;x?@?8$3 zT)7Q@zNphlfseG!$ey-17So)YO0?4G2*|ui5Zyd_2A}LxVtceqKz5BXYW;o#lRpc& zvzIy8|9~P5O;SKvp(gS=KaVS@A@ukV%ifs^&h@EU1Tyv95YLPJQMIp7+<g#-%>Bfd zr5T9iYtO=iKFgtUYz{Xg@dUT}NQm$|&%}>mW;o^40D9f2hW8VlaDn4Ter;Jk?bck0 zNjvvp`sqoOA9;%{JG6xH{qmsU*l)JR*98Z@Im9fEPQ%WrciEni-Qe3_1<#l!)19@^ zEKK-2Qf<v9*?(2&)q9Mj+J<yGNQJ#=kAt<@L%D{WXUy->70%_52AZ#_hR2D6vHvM^ z@qzpHbU$YuxK#`L=$0awcc+A=+1)3NE)LUl!)S4`EGm2Qkn$uHj(Zv5)czG<yZAc! zs1$N%MGLXKL`&e?dr<VBNLrSD7ES-#&Yi4U#IM}=kNHIWgvVvwP_v^(@SGmtnpH|M zf8%_Xsqu~3=?Gp#frs>F(>Q)}ff8P^RiLGH7s+>&AL|S}fopeugH07zF|a3^b295o zLGj-t0eW{~sqHa#|LOvqaCalCq9fc;hnuW7vw(gzcydf4<lXfR@rsT<eP8f{*8iSE zS=S5U?cZti{K0s(>iuLic#}l`6l|z!i4W!upF`cU-Y9<|96kgm(2&CC@a=9Y+w?w~ z-b$Wg`@w^BaM)aaWTGCqWY|)_7qR$pULhHNX@i?5&r&P*gbNE(5yxE*=ey$Mne@aS zW^V9=naiAGr}zA2Pg?fk5BVVR)s+>P3y;{5&|GrxdCrF1dJ9TF{P?r(LEK~a;ba|@ z0{(CBgW`<}zH|C5mfgD<@~Z_-M^Y*mQ-74b5sgRR6Rs#@c6^$PbqpNRJ;T=WZQRQ7 zui@l~Tn2|_F-Lg+JRGP(_mux}GV`DF^CF!=BXch~8@b~C;8=Dz>m-}j#L-IL6l+Ci z=-%Ca<YA?Tn}$ia)H|wl<&ePei;Te9gR7ZZqcE@4Z09=0j}u(4C%7F!J3&TKQLK7@ zFV0!=Qc}zv!B3fkaql7ytFEpl<1L2x^~HaXDEMRBw$I>JNsowCb{)o*VF8?U`D-|{ zL|%NbAe0{a^yk_q^=B1}_K-rLHu(0{N0%8ISURj2rN<31u=OB?RKF0u7b<w4DuI*r z{Wv%+&8J@HM`+k}n2jv?i}fRjR;~zTY;C<nKI1U3KDumllGNVsr#H*F1sKqNLhSz_ zn7341OiimaQP2Au1a3&CluK){LZ+3I5$~TC=6nFnessWp6TC2Uo;i&TF63MUX4Xbw zes;4=z~^C~peHC1*9<IYdBL(=x7T&dxHkw}jxEE$8$sl|KuO3RhQLX8CpMf!*x5dx zlovnbdrYoF(yhJt=72T7r$Q<z+wzB<HJinTm=>YS?pgTa)>IOi<>F`AFy51!L=CSs z#45a)FI8Jgdb4MPUX=#=EN<b_edprG$MeX?#ug=6z-qKe5|#Xl3*Nem?f-NElrHY& z?+Ck{S1VK5j~s1~6zwI|Zh3k=cq$ldKPI;R(~o++g?@>>9KG5aMqQT+S?gm7XY6QA z(}kPHqyxz$ShG+A_pvXF6=?gPM0(s23mJj4m}syJS?w?Yo!Lk6-I2khEaZ-Ne(c2J zj*-}#VNEi2d3IYyeuVNzJ<N2>3M`79!Y*lyr4@5)_&Z<5qq)sB)=yiOO8k_m*j3>B zTsX{}X6Z1$cXy#O#FnWJlx0KjoFKD=BlO$Q0RwV{oafKAVB8}-monQV8TA)%vT+2; zjHYRw)+ID=iVE}bYG98Q57G$zzL@!H8UC{KhM_{A?#Fd`dRFiXF1a6rhg<|6Iu%E6 z#Nm`w^pQ)ciebySepu^R1TqurB=QB<Vd!y9nq7H;yK8tC3~rCWz#=93^zkEk%Vr5o zBTc?VQE(IeXUR%)K7jHlfiX_6*v;)?Fg#q#HD~3pXwy>IGFBEdziyy<FAsbZdr%}5 zo`;_M8z`yb4ok`<79#vF?rIN&8_#k{Dew!IuQ?rdx7`K5h0z$aZaS(x98MoDrZ69s zA(9#+O-V)9Fsgs6L;V$gQtF{c0y9z;lcIL>L$}t$^UcRl-l!Dn-#K&sQ+M;fhNi)* z5mV@AqXJ%$o(3E3M=b5fa{AyIK-&wH#6DTFpklm_?GV1#r8Ddx<>p+P_HP@0n>$W$ zXMTa+?o{@3_;`#PCj5L&@7eAjI!EXu_%N9LSaif+7b{|wIWKF0E%!`?WNv9<FOB7A z${I3R%LICB^bSq?T}2tyLc0}yd+}l67J70^i4q6o&?uXwuwvON^gSwzo>v!;(ZpOj zF@7kXeiH<qX6@MU$QbV|l$FXyyk|R}zC`iiMQBsNc%Rrvp`W~wwaKnyyS@Ek_RSTT z+#8RZwwK|8%qi?nV=9?FJHQ_A9*v1zIZ$xHibAZs;dky|3`!1%?=vg;(*a^?Q(p*C zcQ?X2{c%{b#Dm5(UWBzLZh(pEG)zfsVowVfu)m~1mBQX>&Vq%Q6Sj!XK8WPv*8wFK zw1N5Q?VMSg4yZM~!o^x!q*^J%x%H*8)URJH?L6dx<?@s9K>r9dpPz=7B~tdtH5%_9 zKMlz~lS%usGV=YUpjW$y?1rghabGvws$xhomNP_d13!zt>8nep8z->w8~V{Ei6v~f ze~Nk6s?gdH12PRa5d22{*sh^VK)hd<u_^i3qLxjrHVO3kZ5nz;6v60>P3V4H2mH6T zFfF?SwBz<{mNp;(8{T(;a8|;Gt7W|6xDu|hYXc<8$>Q#d*V&=3Vrp1sL3IxOKvqo| z*N*Za%WYQd^pS6Hy7wTy+hoONd;SpDHxj1l3w){#)*wxH#lU;!)cK{9{kJH9dB>b( zmtqu!T*hm7oIafFg}d6AaA!0*X^Kz9uDsrmQ8aPv6FB*4IiKA;98OQ-`RIUOEatZr z&g#@<ne01c8fc-?Aw{xwYY}2<{mIXICX2hh0Zx?zb#8mg?$0<2-W3U?kz_*Kt=-^N z-(RfDYbodR>IB5My<?5l)1m){J0iyk_9(w~34cGf7GHX$k%`Jvk&;J0avv+p9`A4> z=NsnYtQ9LDdGl^i4sKxo+2^9@lrH;vz>h}R?!|_E!n@gc5$x-5qz?~nuoG7@sGnUw ze0{EjnR_=et+Tf<|I>74WNkunNxdvz;|6q|^<dlI6=0d?L#7cI2^Ml|p!c>s%bvpX z-G&_c&wMGq-FuNT_WN-=Kber^0%Du_QWmVSUhvJ7LZFg5d#~ifWKTMwH1-Vakn~{F zFLf5>afwd}QKS(oA0RxrJ?+Ek1RRoRMCu|FYQ6k~JsuKIJF-Wio9b*5&)h=)yhT(w z^t6z{0<PBMD4ZQMfW6-p32Gi+I4!}$IVw++so2g0<1r@mE2M<Hv-Fv@Y94;r8o_sU z*l?@wSg=_$x1*m<C|v93j`RNLqTw1fQGoOwTd3{^YV~qlKMx7c6lGEW^cFBycgOvf zOSrB&7u3`eQJAef&QDm6FRz@1W>J*Hx4xAf(NL%1nU}yv=8UM#{}M}{?Tp%^04tp4 zaM$u1Sc7CS>C8C*hNHvTdoRZRo~f3+K9@qv=gF{I;R~eVW&ywA*l5mEb2T%%c9M3L z?WRF#!#KCT*0k}0B})z$b6>5j>Atl;dQQB`{^}2+{_@e(J){A%Z6<MGtxdL~iBOyn z3BT7A!QzgCIP`2QYkK&Ixa8G1qa~9*z8J*Pf`e&z@fP8ZLEP8I80gk+=CTLbO^cPw z=PM@%;*G3!NEta0b5ius%ybwoJvg3Z`^e$P3;Dn$r!#5y4p_f)1cRyjxS!=uVad%n z?8zwM#KKNn?&=A4$-@S_jY>$eVkg_YyH!#>=PLdl=ZP1tZDm_G97WTw>evux1Vbhr zqu|{G@PoT0&K{fs*?5ZIdVM^q{{fts8;!2R;?NSjnS#3~$~Zfd$E!Scj#Fi$E-ypP z>x1E3oE{o~{K@+3Oc1qnm}1WLJ0QQ=g@$fkOonj_AbpZ1#%Nq)cayf_#6>Bb{C1AU z?D`8OW#gH@ss+wnoP|q1|HIYq;&~OHll%`2KXz@&I96{n5yR3AXaO$^)_>CQM(=j| z#%p2GnpC#WL>D&|wa^B^Uo^$En(YtgnQ!)Uuy6PRV|H#~F@rfw92CT~auh(Pas>`* z(t`aDqM7xjHp<TUK{G6kp)#eOz4e>|Gw#2ZEbxELFW*^@R}`vHer+-fv7e0B-sEzF zzm=0_&m`=XdShH36DjaQC;V!RG_W`l6`sbz@T7B)AY>>TqEzARc3~&*Ee2;<B;(%g z1#IyDS<2l>v^#A%j5O88B{K#?<$ZlV`_>t%yQ_^mmJC9Eh^pY3`UD$BmcaQxas18p zHQ3lk79ID00CwCDw~c<uriEO9fj)W|RPlf{e?3F91&8pK>I$r%mc_iEl}i397PC|T zM!}~ys+40jiVhddrY|njiL<q!K5c4vqQi*>>qp>&h>x6QNEO#@b%urMo`*fns`%3N z4C`!KNnai_HvO(Au9};M+bp*WjFWaYRoL^c)!xGtKPl1Yx!>TFFwd0USVxv&J1A&D zJZtTUWVYQN{Q933?8<-s_$T`UoAG`vh>zBDe)%t8(9CAm_Lf6~0*+6Oy~YBp2b0mu z&s@hGEB?5vHa>Dlq_eXV@mkmcI9Aug1sKG!l1sy=*;NdZ<IiDtm(T~Z4Mny!k@<Q0 zg2tS97}s+F)~e3K>EnKblg&X+XV5roYEJ+m>`iCpO{U}#1NpwG|DYks2I`)waoL#$ z<bGr!`tNLK7uvj`^>>PBV{0Grdm(!@^Xylc>HLZ<H2uZ?oztd2yAmP!@mQRDy^58! z&*bhY*kFO~bJ$kWBjL<7(Xh`bzIj#@>x}sZH;x;ysJj!WJo`8==c<nxIZL>hn+XD2 zIfFv9)yVK!mE`mA#iTU#CHDl^gZ?5t@x#plv{S~J&DpnAbYSienE3n$XBIdT^x}PK zZrwgw=BiG1F7eVbB@LD}s{-x%x>IT2EDBf}PBWUf@*T#b@T`g>nx9OE^?MX?{;t>H zutkL;z8Ud1g&F9|=6Lp>$Pi$9g5;&#KJLrYJ4~Ez$lr)tFRs|-gEz)jvhhNur1^TK zr1zj3+ox|tcBOu}uEhag^y}t>GY=xDcH3R@cVjd4{P1ed7|8T}#46*8nX{#ybboav z25Pmlm1F1NBwpC5P8!S3ui1v%9OMA>j&W)WN+p*CuFKE2=V93QYSzDZ8|F8<vgi>L z*?>)B(P!pWn7%tuvNL^>xW2LjzxQk=yARL6v2rEuT4m2F?}kc8BwmK3lTS(Wj3a+~ zRs&_N_hTC_sH5MGP>}arB07Kk4?C|=iLt}R;iH$AF=L5{MO4bOP0ua^s-HyvwIA8; z_`5jVHw8>*ykax<6k?3tSlr%zn{*Y#WbL<<E(^|%t`b-L<nR|yWZmPAYa61ByBD(? z^A~ofMR6*H!6<1kq5jTF*ziw5-2P)es7y#@?*Bc7j$6a2zx4r%^i)QV4L_l0LkR2G z5s#gx65-M7DeTl}XRsIEWA9Dvh*o#<(+VQNW3xOI^*zZNf)vmqd6(U!BgWLX*A1<s z@4(zaBD74FP=lc&%kf-?dK#PAy1sGb66}Y2nkQ1o{be{ew~D<v!n4s`L$P)92Ye+e z#GKL^K0I?0%Csg!<F1FGbT5W=Ol=3j+JIjN$fMPg#bjnOl@0&!oG(>R;hrDTpoqSa z)YexWpH4_a?Sp^8;>CKBoasZSFQ*FZSzkP^a1nNoZk={gMFST(OvO=jk<;F=0V29Q z=|*BF(~Ztyf?1C}`yPq?Gt|)UV=lAn5PXCSwPDrN1a_T&30m<RaD3)&s&HFD-!n!_ zlUB{fp;rA+!>XMBc>X_HH%|#C-M+)0ylY6E9$7f_geiHv&_pA9r;DB&)$y^LC1!p2 z2D&wgP<|+wiZ=7y;+vspU8T<~`X<uhURyGBN@A+lM&k0Lg4@wzuV}Z`W`@I4ux8vQ z=?zy4YW{PR_fzH|JL(;)^7n!8!e|O{G)DhT-?)OpEN0<kMMJKsa6iPmsY-Z9y);mx z4&BY@d%GGdGTivg`4ibnxk|Q6c?WaJtb&7HOW`B<vdX82uxrLEm|PggSg#ru<?n@6 z8H1_+Kof4J)+BO+F?9duFdUZ^0d2xwSkrkiEVGy*<mU;?ir-1TURsKNDTOGru5;S9 zoE9($aHUDPrv$!9A{^<zlr1lsPoMqrge)r(S7%PSdbMn`Ujpp963tzFo{y7%D@hD) zd2mMIar}naOEBcUJV~dhphDX@w!-lYc-ZUFukr3M%(e|}(!{WCb0|J>`^pX+l!K~y zF?{{dSKNO`63|*{DJ>Rwu}6OikV*M!!N-ycPm8mero}VR@C?D)kwWJ2jSe--^g*MK zNm!k_9p)M>rcs+(;ahPrRxPxm`$5mype!*9w6un{$aa>|90M{AkGaQBC*zNpcos5h z87x_7$<|G;q14}JSnjJ3NUzW&57$%pZoa%!Y3>4gY-<69+!nApIgd~L8^W+~CAK{P zR5G83gJ-Iv!xCrl&Ll&M_rAgFZQ{9#4zb8yTTYr8c!KVR>R{%^Ni@u-Kb1_%guR;u z9>aGR)PFe=x2R;0l4c3?iwQ(y^B3IBLTz@`>>yPLodHEU#Hzc0LKVBowrmdqsqH*y zc(M+gHr|8i`MLNaqF9&<cCi~X#&D@W1-9&6;bs*n#{Lt2F#C7M$!@a0B<}5cp?7gt zqVL#%+x~s!YhqvW3$J9cy;2R_{AoO?OsRzZbx{;nc7+$`hO!ZHvnc)hOkU~q9@;ix zCK`_&BjgtU(N~306sDZXzU(U@H=P9b^T82NNIOo3qa10oPCjT}yU*U$eTVQv2{6jc zkt$xi2fA<x(t;0CSonXKe5Jp1{}I83b=Zh@h;;>~@HjMXdC3xFg*-}3CV7j6TT9*# ze7rDS@G}o#tDOfyOYk$cMtwI~eBDfHF_TfUv%ffX`6-Nfah<t-A5HgmDpHN-K&Wx( zhyJ%qAlgyrrW*LbCpibm3vT7N_O4-1<3Gci5p!ruz&!3z@D!T$-Ue^AMPb_t1r~dE z7&B;YVngQZqsrPC&UBh89o#2y^d{A#M0`o`dkZt&w}qsg_8p9V=h8;Ka;|>dMux`q ztW?Nc{)x;0Q_CV+75a<K{V)Kl9S6aLo2I09LIqgAt!Ox~gatU)v6*x9@arob+_PPc zsy@zQ=RZHd;TFqq%jff=L6TIA9@_{{mY0A%Skn1{^7wSh3$8Hr1@sQ^MvH#?#O-G< z<C@o-p<Yl#2#Iujbz!Z*5{hKbee&6+k%{bP^c&WYaR^<N9WlPK85_Q<<LnAua?c3o zK1o`kpMi_;?*7arUs_5hjkLutg#Bsc<j1HqIGu7nd|`Sj-`O0W8SuGnGykvrlfCP? zS1jOaEhN9m5EuD=f(rwu)5rotFnTI5lA7023QobJR_5ThaR=0_C+rSeiEn=xqE2)% zG!2YprAtj|^7}-A)0m4>%{M~jtvZyCozKc9mP&L=Q_wH=1{~Ki!JDp|Npv1*<xP98 z@JtHZvV0mY{xgn@H>AVeO|RkRQsJ9%jvt(|T~FrW>SQo~4jC1DBYbnf^)&<O#R(C* zc^6$MZ!_nzb)R9}<FVAbVIS?f)B`i0&O@V-g?!cIKah19NvgXWCxs?5nTtoD;btW4 z$n#-ire9*`&N)B}cYykactKErx+LfIKFYR}qjA?|;pvov;*B3OnW}OGRRjt<u+dRu z?=+COJ093yV7JSMDZurdT{JiD2%7uv;{PPQ=I*a+q&F$sS<ZtTb}Z^ND{Ps;J-MeU z-2YwaWrYt|r3+ckJw^gkYdftK*m<#+G(mcD5LKxU#MGGR`ZxR&c7OjQ_Fvmr+_m5Y zn>B4Sdm(h1%SC#y@0K~Wrk;X{Jx%bt>>~H?a56WdLs@$D(0S_q?F^yEV@Q-|!|dif zf`*@dY<2c++!R)X?nO~--q_=`L*RP!HycJ@et#pMRjD{+XDIhw$gOe<uA#So7K?jv z8rmP&V%`lcG=pPwu1^@fQxAb9iZPr<Z9X^(4udtL&O&~Xf#5H#X0|K@{B%1ZqPZ5z zBY?u9kCM4}Ao5!KX+_Uq43<}6>B4@#Buo>-n%D6W>$b7nWdz}K`;knpA`24u8o8?% zQ{`!aC1pAo0^gWpO6OPF?9~Tto|%w!_j1(wlEFk<yLoxt_aF@)h<D}J!c�IBdN+ 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�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⪚^1ViqrWHOTSzTI?w@3;L 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�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Ⓢ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 JME9OBt; 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%0D7J`@cW_-L~tpD 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%0Dod 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‰u%8DSjaI-S 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%0DlNE@qKepHl!1LKE<I<6W_UsKZJ`ve}KFQRj!e! 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�E-PXfWvWRKr`>II(3CZ|ow6 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�N67(7>#Y(!?oT);|*_|44B5*z4jN6MdesdI-rjM&;_^lHyf;@gFWn ztz(UB7HwhUG`jGnj5500docBR$uyzE4H^ZHS;P1*6!@rA@^YmMUD&XKty?mP$`AIV zl~4Lov8020nJ%f?_#uat%4jf`mIF|kdK^4v&8wOyoFNDO5K|9*;g+v(B3=7~WEs7P zf9aaa5?zEm{;i>;JJ^jHTH?@hjnI4fGLdHX>ksc{52FB`EZF9Bmu-H(lgi4U!8jXt zEICzzh3&RbYiq&M>z2@k;FWB?cO1$T8sR~|SbTY14W&Q3V3=PNr_i9t$y+|+k66l) zXMm9Xt&1V0PlXup8Mp(}7vU(k!Q$$5qp^J2EQ&}pz^fO=L2~m}ntC=)$Z&n;o3pL4 zKJ+wbk6bLU?3Br&{3wPmFvGr?xp0*CWYYtU*lE2Fcwk8fJZY`O;T#V)Z@*ynU5c<{ z#3eQ+S{B#a{s%TKqXpmmewcen4YF$ovO5dTQd071{%v6m4E?LgntWr(F#S2xpVq*9 zAM9ceQUYkGTN;<%OM*9b6ce&x=-<x--ntgyhkbiVRYeDEyav&gcNw_r`BiR1t|?33 z@sGQk<VZ6d^x2x>JU#wzIY08NHgU;e_<HI_;Erjr#eHnCbFHd0WTzH>eHTF1m-3)# zxxP3pK@XR_$%4Ey-`NIx7wBKBCvBK96U$<j(YL@xAv2ZE`veHHr8WuoK=3J4o;e3$ z*0u;8<%r2q(&Jl?(ZiX8iCvt+%0DCRmg~>d9U3^V2bR#TTxECr^%2VNDuP{4E=U)~ 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≈5)tNsKh^`R}YG^gT(ezB$d0_3C+vq!0st^+~+=_ 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 (Jca(Pcmj6K>a1?}IkxVP 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�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 h|b9 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≷~}f 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 z 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≪Gl<G0*>pm{U^QdgToux2m) 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"kHit`t1)q^ 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 literal 0 HcmV?d00001 diff --git a/examples/hubert/tests/test_feature_and_unit.sh b/examples/hubert/tests/test_feature_and_unit.sh new file mode 100644 index 0000000000..c89bd60672 --- /dev/null +++ b/examples/hubert/tests/test_feature_and_unit.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +set -e + +sizes="base large xlarge" + +declare -A ckpt_urls +ckpt_urls[base]="https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt" +ckpt_urls[large]="https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k.pt" +ckpt_urls[xlarge]="https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k.pt" + +declare -A km_layers +km_layers[base]=9 +km_layers[large]=20 +km_layers[xlarge]=30 + +declare -A km_urls +km_urls[base]="https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960_L9_km500.bin" + +declare -A km_nunits +km_nunits[base]=500 + +test_dir=./examples/hubert/tests +split=sample + + +check_feature () { + echo "checking features..." + + size=$1 + ckpt_url=$2 + km_layer=$3 + ckpt_path="$test_dir/$(basename "$ckpt_url")" + + if [ ! -f "$ckpt_path" ]; then + echo "downloading $ckpt_url to $ckpt_path" + wget "$ckpt_url" -O "$ckpt_path" + fi + + python ./examples/hubert/simple_kmeans/dump_hubert_feature.py \ + "${test_dir}" "${split}" "${ckpt_path}" "${km_layer}" 1 0 "${test_dir}" + + if diff -q "${test_dir}/${split}.${size}.L${km_layer}.npy" "${test_dir}/${split}_0_1.npy" &>/dev/null; then + echo "...passed npy check" + else + echo "...failed npy check" + fi + + if diff -q "${test_dir}/${split}.${size}.L${km_layer}.len" "${test_dir}/${split}_0_1.len" &>/dev/null; then + echo "...passed len check" + else + echo "...failed len check" + fi +} + + +check_unit () { + echo "checking units..." + + size=$1 + km_url=$2 + km_layer=$3 + km_nunit=$4 + km_path="$test_dir/$(basename "$km_url")" + + if [ ! -f "$km_path" ]; then + echo "downloading $km_url to $km_path" + wget "$km_url" -O "$km_path" + fi + + python ./examples/hubert/simple_kmeans/dump_km_label.py \ + "${test_dir}" "${split}" "${km_path}" 1 0 "${test_dir}" + + if diff -q "${test_dir}/${split}.${size}.L${km_layer}.km${km_nunit}.km" "${test_dir}/${split}_0_1.km" &>/dev/null; then + echo "...passed unit check" + else + echo "...failed unit check" + fi +} + + +for size in $sizes; do + echo "=== Running unit test for HuBERT $size ===" + check_feature "$size" "${ckpt_urls[$size]}" "${km_layers[$size]}" + + if [ -n "${km_urls[$size]}" ]; then + check_unit "$size" "${km_urls[$size]}" "${km_layers[$size]}" "${km_nunits[$size]}" + fi + + rm -f $test_dir/${split}_0_1.* +done From 1b61bbad327d2bf32502b3b9a770b57714cc43dc Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Thu, 27 Jan 2022 13:01:49 -0800 Subject: [PATCH 556/774] Fix broken EMA in fairseq Summary: EMA broken since D33649708 (https://github.com/pytorch/fairseq/commit/995c204337d16a6146a433cee360e5a5bfbc9a6f) due to indentation error. Reviewed By: cruvadom Differential Revision: D33809223 fbshipit-source-id: c6c4d0d327443bfea787817040e1832eef0f50e4 --- fairseq/models/ema/ema.py | 10 +++---- tests/test_ema.py | 61 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/fairseq/models/ema/ema.py b/fairseq/models/ema/ema.py index bc966a9aed..dcc19d85cf 100644 --- a/fairseq/models/ema/ema.py +++ b/fairseq/models/ema/ema.py @@ -185,11 +185,11 @@ def step(self, new_model, updates=None): self._set_decay( 0 if updates < self.config.ema_start_update else self.config.ema_decay ) - if updates is not None and self.config.ema_update_freq > 1: - self.update_freq_counter += 1 - if self.update_freq_counter >= self.config.ema_update_freq: - self._step_internal(new_model, updates) - self.update_freq_counter = 0 + if self.config.ema_update_freq > 1: + self.update_freq_counter += 1 + if self.update_freq_counter >= self.config.ema_update_freq: + self._step_internal(new_model, updates) + self.update_freq_counter = 0 else: self._step_internal(new_model, updates) diff --git a/tests/test_ema.py b/tests/test_ema.py index e6f10ce9c2..1f8f71b9b6 100644 --- a/tests/test_ema.py +++ b/tests/test_ema.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import unittest +from unittest.mock import patch from copy import deepcopy from dataclasses import dataclass from typing import Optional @@ -36,9 +37,10 @@ class EMAConfig(object): ema_start_update: int = 0 ema_fp32: bool = False ema_seed_model: Optional[str] = None + ema_update_freq: int = 1 -class TestEMAGPU(unittest.TestCase): +class TestEMA(unittest.TestCase): def assertTorchAllClose(self, x, y, atol=1e-8, rtol=1e-5, msg=None): diff = x.float() - y.float() diff_norm = torch.norm(diff) @@ -104,6 +106,63 @@ def test_ema(self): ema_param = ema_state_dict[key] self.assertTrue(torch.allclose(ema_param, param)) + # Check that step_internal is called once + with patch.object( + ema, "_step_internal", return_value=None + ) as mock_method: + ema.step(model) + mock_method.assert_called_once_with(model, None) + + def _test_ema_start_update(self, updates): + model = DummyModule() + optimizer = torch.optim.SGD(model.parameters(), lr=0.01) + state = deepcopy(model.state_dict()) + config = EMAConfig(ema_start_update=1) + ema = EMA(model, config) + + # EMA step + x = torch.randn(32) + y = model(x) + loss = y.sum() + loss.backward() + optimizer.step() + + ema.step(model, updates=updates) + ema_state_dict = ema.get_model().state_dict() + + self.assertEqual(ema.get_decay(), 0 if updates == 0 else config.ema_decay) + + for key, param in model.state_dict().items(): + ema_param = ema_state_dict[key] + prev_param = state[key] + + if "version" in key: + # Do not decay a model.version pytorch param + continue + if updates == 0: + self.assertTorchAllClose( + ema_param, + param, + ) + else: + self.assertTorchAllClose( + ema_param, + config.ema_decay * prev_param + (1 - config.ema_decay) * param, + ) + + # Check that step_internal is called once + with patch.object( + ema, "_step_internal", return_value=None + ) as mock_method: + ema.step(model, updates=updates) + mock_method.assert_called_once_with(model, updates) + + def test_ema_before_start_update(self): + self._test_ema_start_update(updates=0) + + def test_ema_after_start_update(self): + self._test_ema_start_update(updates=1) + def test_ema_fp32(self): model = DummyModule().half() optimizer = torch.optim.SGD(model.parameters(), lr=0.01) From d839d84f1e936372b7fb768f27925858091c2914 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Mon, 31 Jan 2022 20:43:18 -0800 Subject: [PATCH 557/774] Miscellaneous S2T & S2 bug fixes Summary: Miscellaneous S2T & S2 bug fixes Reviewed By: yuntang Differential Revision: D33469556 fbshipit-source-id: 430c2cad01dd7ea862a6c1564ad609887d66b788 --- examples/speech_synthesis/docs/ljspeech_example.md | 3 +-- .../speech_text_joint_to_text/docs/ende-mustc.md | 4 ++-- examples/speech_to_text/data_utils.py | 2 +- fairseq/data/audio/data_cfg.py | 3 +++ fairseq/data/audio/speech_to_text_dataset.py | 14 ++++++++++---- fairseq/models/text_to_speech/hub_interface.py | 2 +- fairseq/models/wav2vec/wav2vec2_asr.py | 3 --- 7 files changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/speech_synthesis/docs/ljspeech_example.md b/examples/speech_synthesis/docs/ljspeech_example.md index 90c524fac8..836c30d6d5 100644 --- a/examples/speech_synthesis/docs/ljspeech_example.md +++ b/examples/speech_synthesis/docs/ljspeech_example.md @@ -65,8 +65,7 @@ fairseq-train ${FEATURE_MANIFEST_ROOT} --save-dir ${SAVE_DIR} \ --num-workers 4 --max-sentences 6 --max-update 200000 \ --task text_to_speech --criterion fastspeech2 --arch fastspeech2 \ --clip-norm 5.0 --n-frames-per-step 1 \ - --dropout 0.1 --attention-dropout 0.1 --activation-dropout 0.1 \ - --encoder-normalize-before --decoder-normalize-before \ + --dropout 0.1 --attention-dropout 0.1 \ --optimizer adam --lr 5e-4 --lr-scheduler inverse_sqrt --warmup-updates 4000 \ --seed 1 --update-freq 8 --eval-inference --best-checkpoint-metric mcd_loss ``` diff --git a/examples/speech_text_joint_to_text/docs/ende-mustc.md b/examples/speech_text_joint_to_text/docs/ende-mustc.md index 86b8fa91fe..ad9e222cef 100644 --- a/examples/speech_text_joint_to_text/docs/ende-mustc.md +++ b/examples/speech_text_joint_to_text/docs/ende-mustc.md @@ -21,7 +21,7 @@ Enhanced Joint Training: the joint training is enhanced with pre-trained models, --data-path ${must_c_en_de_src_text} \ --out-path ${must_c_en_de_src_text_pho} ``` -- Replace the source text under the "src_text" column in the tsv file with the corresponding phoneme reprentation generated in the step above. +- Replace the source text under the "src_text" column in the tsv file with the corresponding phoneme reprentation generated in the step above. - Prepare phoneme dictionary and save to $MANIFEST_ROOT as [src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/src_dict.txt) #### Prepare WMT text data - [Download wmt data](https://github.com/pytorch/fairseq/blob/main/examples/translation/prepare-wmt14en2de.sh) @@ -32,7 +32,7 @@ Enhanced Joint Training: the joint training is enhanced with pre-trained models, The model is trained with 8 v100 GPUs. #### Download pretrained models -- [pretrain_encoder](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_multilingual_asr_transformer_m.pt) +- [pretrain_encoder](https://dl.fbaipublicfiles.com/fairseq/s2t/mustc_joint_asr_transformer_m.pt) - [pretrain_nmt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/checkpoint_mt.pt) #### Training scripts diff --git a/examples/speech_to_text/data_utils.py b/examples/speech_to_text/data_utils.py index c9c69e2b46..b8648cb2a0 100644 --- a/examples/speech_to_text/data_utils.py +++ b/examples/speech_to_text/data_utils.py @@ -83,7 +83,7 @@ def extract_fbank_features( _waveform, _ = convert_waveform(waveform, sample_rate, to_mono=True) # Kaldi compliance: 16-bit signed integers _waveform = _waveform * (2 ** 15) - _waveform = _waveform[0].numpy() + _waveform = _waveform.numpy() features = _get_kaldi_fbank(_waveform, sample_rate, n_mel_bins) if features is None: diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 18fcf416f7..0396e6a346 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -108,6 +108,9 @@ def use_audio_input(self): raw audio as inputs.""" return self.config.get("use_audio_input", False) + def standardize_audio(self) -> bool: + return self.use_audio_input and self.config.get("standardize_audio", False) + @property def use_sample_rate(self): """Needed by the dataset loader to see if the model requires diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index 7bcc88b6bb..42f92186e7 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -14,6 +14,7 @@ import numpy as np import torch +import torch.nn.functional as F from fairseq.data import ( ConcatDataset, Dictionary, @@ -258,10 +259,15 @@ def _get_source_audio(self, index: int) -> torch.Tensor: need_waveform=self.cfg.use_audio_input, use_sample_rate=self.cfg.use_sample_rate, ) - if self.feature_transforms is not None: - assert not self.cfg.use_audio_input - source = self.feature_transforms(source) - source = torch.from_numpy(source).float() + if self.cfg.use_audio_input: + source = torch.from_numpy(source).float() + if self.cfg.standardize_audio: + with torch.no_grad(): + source = F.layer_norm(source, source.shape) + else: + if self.feature_transforms is not None: + source = self.feature_transforms(source) + source = torch.from_numpy(source).float() return source def __getitem__(self, index: int) -> SpeechToTextDatasetItem: diff --git a/fairseq/models/text_to_speech/hub_interface.py b/fairseq/models/text_to_speech/hub_interface.py index 8e367665da..c79e76b619 100644 --- a/fairseq/models/text_to_speech/hub_interface.py +++ b/fairseq/models/text_to_speech/hub_interface.py @@ -113,7 +113,7 @@ def get_model_input( logger.info(f"speaker: {spk}") spk = None if spk is None else torch.Tensor([[spk]]).long() - src_tokens = task.src_dict.encode_line(tokenized).view(1, -1) + src_tokens = task.src_dict.encode_line(tokenized, add_if_not_exist=False).view(1, -1) src_lengths = torch.Tensor([len(tokenized.split())]).long() return { "net_input": { diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 3612609418..0e35a87beb 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -162,9 +162,6 @@ class Wav2Vec2AsrConfig(FairseqDataclass): data: str = II("task.data") # this holds the loaded wav2vec args w2v_args: Any = None - checkpoint_activations: bool = field( - default=False, metadata={"help": "checkpoint_activations"} - ) offload_activations: bool = field( default=False, metadata={"help": "offload_activations"} ) From 790f3be15ac0781d02f3048d7d3d9279f4e5a91e Mon Sep 17 00:00:00 2001 From: Victoria X Lin <xilin@cs.washington.edu> Date: Tue, 1 Feb 2022 10:25:58 -0800 Subject: [PATCH 558/774] Add XGLM pre-training data format explaination (#4158) Summary: 1. Add XGLM pre-training data format explanation 2. Add back pointer to pre-print Pull Request resolved: https://github.com/pytorch/fairseq/pull/4158 Reviewed By: xianxl Differential Revision: D33825440 Pulled By: todpole3 fbshipit-source-id: 379aa55d55ef3c9016987d1f05de023b7a7aee04 --- examples/xglm/README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/examples/xglm/README.md b/examples/xglm/README.md index 8e65053174..0d9da32530 100644 --- a/examples/xglm/README.md +++ b/examples/xglm/README.md @@ -17,6 +17,33 @@ Model | Layers | Model Dim | Languages | Download `XGLM 7.5B` | 32 | 4096 | trained on 30 languages| [xglm.7.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.7.5B.tar.gz) `XGLM 4.5B` | 48 | 2048 | trained on 134 languages| [xglm.4.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.4.5B.tar.gz) +## Pre-training Data Format +Our models were pre-trained with data in the following format (i.e. paragraphs are separated with new lines and documents were separated with double new lines). +``` +<doc0,para0,tok0> ... <doc0,para0,tokX0> # X0: number of tokens in para0 of doc0 +<doc0,para1,tok0> ... <doc0,para1,tokY0> # Y0: number of tokens in para1 of doc0 + +<doc1,para0,tok0> ... <doc1,para0,tokX1> # X1: number of tokens in para0 of doc1 +<doc1,para1,tok0> ... <doc1,para1,tokY1> # Y1: number of tokens in para1 of doc1 + +... +``` +Fairseq's preprocessing replaces newlines with the end-of-sentence symbol (`</s>`). As a result, the models never saw newline characters during pretraining and the same preprocessing should be run prior to few-shot inference to maximize performance. For example, our language model scoring function has `replace_newlines_with_eos` argument to trigger this preprocessing: +```python +from fairseq.models.transformer_lm import TransformerLanguageModel + +model_dir = 'path_to_decompressed_tar_gz_dir' +lm = TransformerLanguageModel.from_pretrained(model_dir, bpe='sentencepiece') + +text = """First paragraph of the first document. +Second paragraph of the first document. + +First paragraph of the second document. +""" +tokens = lm.score(text, replace_newlines_with_eos=True)['tokens'] +assert '\n' not in lm.decode(tokens) # no newlines were encoded +``` + ## Evaluation ### Example (COPA) @@ -111,6 +138,11 @@ for lang in ['en', 'zh', 'hi']: # hi-1 0 0 ``` +## Preprint +[Few-shot Learning with Multilingual Language Models](https://arxiv.org/abs/2112.10668). +Xi Victoria Lin*, Todor Mihaylov, Mikel Artetxe, Tianlu Wang, Shuohui Chen, Daniel Simig, Myle Ott, Naman Goyal, Shruti Bhosale, Jingfei Du, Ramakanth Pasunuru, Sam Shleifer, Punit Singh Koura, Vishrav Chaudhary, Brian O'Horo, Jeff Wang, Luke Zettlemoyer, Zornitsa Kozareva, Mona Diab, Veselin Stoyanov, Xian Li* (* Equal Contribution). +ArXiv 2021. + ## Citation ``` @article{DBLP:journals/corr/abs-2112-10668, From 6b770134a2f4474e0a4ddf6c1085c0e06f292cab Mon Sep 17 00:00:00 2001 From: Victoria X Lin <xilin@cs.washington.edu> Date: Tue, 1 Feb 2022 10:56:27 -0800 Subject: [PATCH 559/774] Add citation details and other wording fixes to model card (#4172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4172 Reviewed By: punitkoura Differential Revision: D33911169 Pulled By: todpole3 fbshipit-source-id: d3e111ab4b9a646e1799ad9335c70ec1ee8d25a4 --- examples/xglm/model_card.md | 53 +++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/examples/xglm/model_card.md b/examples/xglm/model_card.md index 75ddb1708a..0cdd20fbe0 100644 --- a/examples/xglm/model_card.md +++ b/examples/xglm/model_card.md @@ -5,13 +5,7 @@ Meta AI ### Model type -A multilingual autoregressive language model trained on a balanced corpus of a diverse set of languages. The largest trained model has 7.5 billion parameters. The language model can learn tasks from natural language descriptions and a few examples. - -### References -Coming soon. - -### Citation details -Coming soon. +A family of multilingual autoregressive language models (ranging from 564 million to 7.5 billion parameters) trained on a balanced corpus of a diverse set of languages. The language model can learn tasks from natural language descriptions and a few examples. ### Model Feedback Channel https://github.com/pytorch/fairseq @@ -71,11 +65,11 @@ XWinograd is a multilingual collection of Winograd Schemas in six languages that PAWS-X contains 23,659 human translated PAWS evaluation pairs and 296,406 machine translated training pairs in six typologically distinct languages: French, Spanish, German, Chinese, Japanese, and Korean. All translated pairs are sourced from examples in PAWS-Wiki. ## Responsible AI (RAI) evaluation -### Hate speech -Hate speech datasets introduced by Huang et al. (2020). This dataset is a multilingual Twitter corpus for the task of hate speech detection with inferred four author demographic factors: age, country, gender and race/ethnicity. The corpus covers five languages: English, Italian, Polish, Portuguese and Spanish. +### Hate speech (Huang et al. 2020) +This is a multilingual Twitter corpus for the task of hate speech detection with inferred four author demographic factors: age, country, gender and race/ethnicity. The corpus covers five languages: English, Italian, Polish, Portuguese and Spanish. -### Bias dataset -This dataset by De-Arteaga et al. 2019 is a bias detection dataset, where the aim is to study gender bias based on identifying a person’s occupation from their bios. +### Bias dataset (De-Arteaga et al. 2019) +The aim of this dataset is to study the gender bias of models that identify a person’s occupation from their bios. ---- @@ -119,3 +113,40 @@ Maria De-Arteaga, Alexey Romanov, Hanna Wallach, Jennifer Chayes, Christian Borg Nasrin Mostafazadeh, Nathanael Chambers, Xiaodong He, Devi Parikh, Dhruv Batra, Lucy Vanderwende, Pushmeet Kohli, James F. Allen. A Corpus and Evaluation Framework for Deeper Understanding of Commonsense Stories. CoRR abs/1604.01696. Jieyu Zhao, Subhabrata Mukherjee, Saghar Hosseini, Kai-Wei Chang, and Ahmed Hassan Awadallah. 2020. Gender bias in multilingual embeddings and crosslingual transfer. In Proceedings of the 58th Annual Meeting of the Association for Computational Linguistics, pages 2896–2907. + +## Citation details +``` +@article{DBLP:journals/corr/abs-2112-10668, + author = {Xi Victoria Lin and + Todor Mihaylov and + Mikel Artetxe and + Tianlu Wang and + Shuohui Chen and + Daniel Simig and + Myle Ott and + Naman Goyal and + Shruti Bhosale and + Jingfei Du and + Ramakanth Pasunuru and + Sam Shleifer and + Punit Singh Koura and + Vishrav Chaudhary and + Brian O'Horo and + Jeff Wang and + Luke Zettlemoyer and + Zornitsa Kozareva and + Mona T. Diab and + Veselin Stoyanov and + Xian Li}, + title = {Few-shot Learning with Multilingual Language Models}, + journal = {CoRR}, + volume = {abs/2112.10668}, + year = {2021}, + url = {https://arxiv.org/abs/2112.10668}, + eprinttype = {arXiv}, + eprint = {2112.10668}, + timestamp = {Tue, 04 Jan 2022 15:59:27 +0100}, + biburl = {https://dblp.org/rec/journals/corr/abs-2112-10668.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +``` From 5d2be954bb7531bff92c195e61aa50a8ddd0baab Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Tue, 1 Feb 2022 21:41:20 -0800 Subject: [PATCH 560/774] add defaults again after importing user_module (#3007) Summary: ## What does this PR do? Default values for the configs imported from `user_dir` was not added properly. Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3007 Reviewed By: alexeib Differential Revision: D33926315 Pulled By: wnhsu fbshipit-source-id: 914eecec769964686342d66c96d6ba76f12e1277 --- fairseq_cli/train.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index a707add735..980e217147 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -31,6 +31,7 @@ from fairseq.data import data_utils, iterators from fairseq.data.plasma_utils import PlasmaStore from fairseq.dataclass.configs import FairseqConfig +from fairseq.dataclass.initialize import add_defaults from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.distributed import fsdp_enable_wrap, fsdp_wrap from fairseq.distributed import utils as distributed_utils @@ -45,6 +46,7 @@ def main(cfg: FairseqConfig) -> None: cfg = convert_namespace_to_omegaconf(cfg) utils.import_user_module(cfg.common) + add_defaults(cfg) if ( distributed_utils.is_master(cfg.distributed_training) From f591cc94caa85098ccf125a4782f91125b6a086d Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Wed, 2 Feb 2022 04:30:05 -0800 Subject: [PATCH 561/774] upgrade black for lints (#3004) Summary: This is the same as https://github.com/fairinternal/fairseq-py/issues/3003 but for main instead of gshard. the lint test will run the latest version of black, which is 22.1.0 right now and seems to be incompatible with the 21.12b0 version that is setup in pre-commit. This means that some files were with valid format in the past, but are not anymore... This PR formats these files with 22.1.0 and autoupdates pre-commit config to use that black version too. (note: this is the second time it happens. a solution would be to pin the lint test to the same version as the one in the pre-commit hook and that was used to format everything clean so that we have a stable formating) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3004 Reviewed By: dianaml0 Differential Revision: D33917490 Pulled By: Mortimerp9 fbshipit-source-id: d55e800b976f94545cdab4132daa7c45cbd0e34c --- .pre-commit-config.yaml | 4 ++-- fairseq/criterions/tacotron2_loss.py | 11 +++++----- fairseq/data/audio/audio_utils.py | 11 +++++----- .../feature_transforms/utterance_cmvn.py | 5 +++-- fairseq/data/audio/speech_to_text_dataset.py | 21 +++++++------------ fairseq/data/encoders/gpt2_bpe_utils.py | 4 ++-- .../multilingual/sampled_multi_dataset.py | 5 +++-- .../sampled_multi_epoch_dataset.py | 6 +++--- fairseq/data/plasma_utils.py | 6 +++--- fairseq/data/resampling_dataset.py | 4 ++-- fairseq/data/text_compressor.py | 2 +- fairseq/dataclass/configs.py | 7 +++---- .../legacy_distributed_data_parallel.py | 2 +- fairseq/file_chunker_utils.py | 2 +- .../pipeline_parallel_transformer/layers.py | 4 ++-- fairseq/model_parallel/models/transformer.py | 6 +++--- .../model_parallel/models/transformer_lm.py | 2 +- .../modules/multihead_attention.py | 10 ++++----- fairseq/models/bart/model.py | 7 +++---- fairseq/models/distributed_fairseq_model.py | 5 ++--- fairseq/models/hubert/hubert_asr.py | 7 ++++--- fairseq/models/lightconv.py | 5 +++-- fairseq/models/roberta/model.py | 5 ++++- fairseq/models/speech_to_speech/modules.py | 2 +- .../models/speech_to_text/modules/emformer.py | 2 +- fairseq/models/text_to_speech/fastspeech2.py | 2 +- fairseq/models/text_to_speech/hifigan.py | 4 ++-- .../models/text_to_speech/hub_interface.py | 8 ++++--- .../models/text_to_speech/tts_transformer.py | 2 +- .../models/transformer/transformer_base.py | 9 ++++---- .../models/transformer/transformer_decoder.py | 7 ++++--- fairseq/models/wav2vec/wav2vec2.py | 10 +++++---- fairseq/models/wav2vec/wav2vec2_asr.py | 7 +++---- fairseq/modules/adaptive_input.py | 5 +++-- .../downsampled_multihead_attention.py | 3 ++- fairseq/modules/gumbel_vector_quantizer.py | 8 +++---- fairseq/modules/kmeans_attention.py | 10 ++++----- fairseq/modules/multihead_attention.py | 7 ++++--- fairseq/modules/positional_embedding.py | 2 +- .../quantization/scalar/modules/qact.py | 2 +- .../quantization/scalar/modules/qconv.py | 2 +- .../quantization/scalar/modules/qemb.py | 2 +- .../quantization/scalar/modules/qlinear.py | 2 +- fairseq/modules/quantization/scalar/ops.py | 2 +- fairseq/optim/adafactor.py | 2 +- fairseq/optim/dynamic_loss_scaler.py | 2 +- fairseq/optim/fp16_optimizer.py | 7 ++++--- .../optim/lr_scheduler/cosine_lr_scheduler.py | 6 +++--- .../inverse_square_root_schedule.py | 4 ++-- .../lr_scheduler/triangular_lr_scheduler.py | 2 +- fairseq/tasks/multilingual_denoising.py | 4 ++-- .../tasks/multilingual_language_modeling.py | 2 +- fairseq/tasks/multilingual_masked_lm.py | 4 ++-- fairseq/trainer.py | 5 +++-- fairseq/utils.py | 7 ++++--- fairseq_cli/eval_lm.py | 6 +++--- tests/test_ema.py | 10 +++------ tests/test_plasma_utils.py | 7 ++++--- 58 files changed, 156 insertions(+), 151 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4817f6e876..e8f7a8bfc6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ default_language_version: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: trailing-whitespace - id: check-ast @@ -17,7 +17,7 @@ repos: - id: end-of-file-fixer - repo: https://github.com/ambv/black - rev: 21.12b0 + rev: 22.1.0 hooks: - id: black language_version: python3.8 diff --git a/fairseq/criterions/tacotron2_loss.py b/fairseq/criterions/tacotron2_loss.py index 04747bf1aa..d3af9762a7 100644 --- a/fairseq/criterions/tacotron2_loss.py +++ b/fairseq/criterions/tacotron2_loss.py @@ -6,19 +6,18 @@ # can be found in the PATENTS file in the same directory. import logging -from typing import Any, Dict, List -from functools import lru_cache from dataclasses import dataclass, field +from functools import lru_cache +from typing import Any, Dict, List import torch +import torch.nn.functional as F from omegaconf import II from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion -from fairseq.dataclass import FairseqDataclass from fairseq.data.data_utils import lengths_to_mask -import torch.nn.functional as F - +from fairseq.dataclass import FairseqDataclass logger = logging.getLogger(__name__) @@ -58,7 +57,7 @@ def _get_weight(s_len, t_len, sigma): grid_x = grid_x.to(s_len.device) grid_y = grid_y.to(s_len.device) w = (grid_y.float() / s_len - grid_x.float() / t_len) ** 2 - return 1.0 - torch.exp(-w / (2 * (sigma ** 2))) + return 1.0 - torch.exp(-w / (2 * (sigma**2))) def _get_weights(self, src_lens, tgt_lens): bsz, max_s_len, max_t_len = len(src_lens), max(src_lens), max(tgt_lens) diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index ac6b13d813..349b86c140 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -4,15 +4,14 @@ # LICENSE file in the root directory of this source tree. -from pathlib import Path -from typing import BinaryIO, Optional, Tuple, Union, List import mmap +from pathlib import Path +from typing import BinaryIO, List, Optional, Tuple, Union import numpy as np import torch import torch.nn.functional as F - SF_AUDIO_FILE_EXTENSIONS = {".wav", ".flac", ".ogg"} FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS = {".npy", ".wav", ".flac", ".ogg"} @@ -112,7 +111,7 @@ def get_waveform( ) if not normalization: - waveform *= 2 ** 15 # denormalized to 16-bit signed integers + waveform *= 2**15 # denormalized to 16-bit signed integers if not always_2d: waveform = waveform.squeeze(axis=0) return waveform, sample_rate @@ -123,7 +122,7 @@ def _get_kaldi_fbank( ) -> Optional[np.ndarray]: """Get mel-filter bank features via PyKaldi.""" try: - from kaldi.feat.fbank import FbankOptions, Fbank + from kaldi.feat.fbank import Fbank, FbankOptions from kaldi.feat.mel import MelBanksOptions from kaldi.feat.window import FrameExtractionOptions from kaldi.matrix import Vector @@ -275,7 +274,7 @@ def forward( x = F.conv1d(x, self.basis, stride=self.hop_length) real_part = x[:, : self.n_fft // 2 + 1, :] imag_part = x[:, self.n_fft // 2 + 1 :, :] - magnitude = torch.sqrt(real_part ** 2 + imag_part ** 2) + magnitude = torch.sqrt(real_part**2 + imag_part**2) if self.return_phase: phase = torch.atan2(imag_part, real_part) return magnitude, phase diff --git a/fairseq/data/audio/feature_transforms/utterance_cmvn.py b/fairseq/data/audio/feature_transforms/utterance_cmvn.py index 6bbd0ae821..37637bc09a 100644 --- a/fairseq/data/audio/feature_transforms/utterance_cmvn.py +++ b/fairseq/data/audio/feature_transforms/utterance_cmvn.py @@ -1,4 +1,5 @@ import numpy as np + from fairseq.data.audio.feature_transforms import ( AudioFeatureTransform, register_audio_feature_transform, @@ -28,12 +29,12 @@ def __repr__(self): def __call__(self, x): mean = x.mean(axis=0) - square_sums = (x ** 2).sum(axis=0) + square_sums = (x**2).sum(axis=0) if self.norm_means: x = np.subtract(x, mean) if self.norm_vars: - var = square_sums / x.shape[0] - mean ** 2 + var = square_sums / x.shape[0] - mean**2 std = np.sqrt(np.maximum(var, 1e-10)) x = np.divide(x, std) diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index 42f92186e7..2f1be34678 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -8,32 +8,27 @@ import logging import re from collections import defaultdict +from dataclasses import dataclass from pathlib import Path from typing import Dict, List, Optional -from dataclasses import dataclass import numpy as np import torch import torch.nn.functional as F -from fairseq.data import ( - ConcatDataset, - Dictionary, - FairseqDataset, - ResamplingDataset, - data_utils as fairseq_data_utils, -) + +from fairseq.data import ConcatDataset, Dictionary, FairseqDataset, ResamplingDataset +from fairseq.data import data_utils as fairseq_data_utils from fairseq.data.audio.audio_utils import ( + FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS, get_fbank, get_waveform, - read_from_stored_zip, is_npy_data, is_sf_audio_data, parse_path, - FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS, + read_from_stored_zip, ) -from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform from fairseq.data.audio.data_cfg import S2TDataConfig - +from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform logger = logging.getLogger(__name__) @@ -455,7 +450,7 @@ def get_size_ratios( sz_sum = sum(v for v in lp_to_sz.values()) lp_to_prob = {k: v / sz_sum for k, v in lp_to_sz.items()} - lp_to_tgt_prob = {k: v ** alpha for k, v in lp_to_prob.items()} + lp_to_tgt_prob = {k: v**alpha for k, v in lp_to_prob.items()} prob_sum = sum(v for v in lp_to_tgt_prob.values()) lp_to_tgt_prob = {k: v / prob_sum for k, v in lp_to_tgt_prob.items()} lp_to_sz_ratio = { diff --git a/fairseq/data/encoders/gpt2_bpe_utils.py b/fairseq/data/encoders/gpt2_bpe_utils.py index 688d4e36e3..996d3d4a11 100644 --- a/fairseq/data/encoders/gpt2_bpe_utils.py +++ b/fairseq/data/encoders/gpt2_bpe_utils.py @@ -27,10 +27,10 @@ def bytes_to_unicode(): ) cs = bs[:] n = 0 - for b in range(2 ** 8): + for b in range(2**8): if b not in bs: bs.append(b) - cs.append(2 ** 8 + n) + cs.append(2**8 + n) n += 1 cs = [chr(n) for n in cs] return dict(zip(bs, cs)) diff --git a/fairseq/data/multilingual/sampled_multi_dataset.py b/fairseq/data/multilingual/sampled_multi_dataset.py index b0a617424e..ece9a9721e 100644 --- a/fairseq/data/multilingual/sampled_multi_dataset.py +++ b/fairseq/data/multilingual/sampled_multi_dataset.py @@ -14,6 +14,7 @@ import numpy as np import torch + from fairseq.data import FairseqDataset, data_utils from fairseq.distributed import utils as distributed_utils @@ -406,8 +407,8 @@ def _establish_virtual_datasets(self): ).hexdigest(), 16, ) - % (2 ** 32), - self.seed % (2 ** 32), # global seed + % (2**32), + self.seed % (2**32), # global seed self._cur_epoch, # epoch index, ] ) diff --git a/fairseq/data/multilingual/sampled_multi_epoch_dataset.py b/fairseq/data/multilingual/sampled_multi_epoch_dataset.py index 17387b2f85..bb187a8dc2 100644 --- a/fairseq/data/multilingual/sampled_multi_epoch_dataset.py +++ b/fairseq/data/multilingual/sampled_multi_epoch_dataset.py @@ -8,11 +8,11 @@ import math import numpy as np + from fairseq.data import SampledMultiDataset from .sampled_multi_dataset import CollateFormat, default_virtual_size_func - logger = logging.getLogger(__name__) @@ -155,8 +155,8 @@ def _next_global_indices(self, epoch): ).hexdigest(), 16, ) - % (2 ** 32), - self.seed % (2 ** 32), # global seed + % (2**32), + self.seed % (2**32), # global seed epoch, # epoch index, ] ) diff --git a/fairseq/data/plasma_utils.py b/fairseq/data/plasma_utils.py index b9fab3b739..459fb8acd7 100644 --- a/fairseq/data/plasma_utils.py +++ b/fairseq/data/plasma_utils.py @@ -4,10 +4,10 @@ # LICENSE file in the root directory of this source tree. -import subprocess +import hashlib import json +import subprocess import tempfile -import hashlib from typing import Hashable try: @@ -176,7 +176,7 @@ def __len__(self): return self._n -GB100 = (1024 ** 3) * 100 +GB100 = (1024**3) * 100 class PlasmaStore: diff --git a/fairseq/data/resampling_dataset.py b/fairseq/data/resampling_dataset.py index 3d3b993164..2d77ed79d7 100644 --- a/fairseq/data/resampling_dataset.py +++ b/fairseq/data/resampling_dataset.py @@ -6,8 +6,8 @@ import logging import numpy as np -from fairseq.data import BaseWrapperDataset, plasma_utils +from fairseq.data import BaseWrapperDataset, plasma_utils logger = logging.getLogger(__name__) @@ -125,7 +125,7 @@ def set_epoch(self, epoch): rng = np.random.RandomState( [ 42, # magic number - self.seed % (2 ** 32), # global seed + self.seed % (2**32), # global seed self._cur_epoch, # epoch index ] ) diff --git a/fairseq/data/text_compressor.py b/fairseq/data/text_compressor.py index 8a4e8daa35..d699f2ea29 100644 --- a/fairseq/data/text_compressor.py +++ b/fairseq/data/text_compressor.py @@ -14,7 +14,7 @@ class TextCompressionLevel(Enum): class TextCompressor(object): def __init__( - self, level: TextCompressionLevel, max_input_byte_length: int = 2 ** 16 + self, level: TextCompressionLevel, max_input_byte_length: int = 2**16 ): self.level = level self.max_input_length = max_input_byte_length diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index b03e8386ed..7540738918 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -8,6 +8,7 @@ from typing import Any, List, Optional import torch +from omegaconf import II, MISSING from fairseq.dataclass.constants import ( DATASET_IMPL_CHOICES, @@ -21,8 +22,6 @@ ZERO_SHARDING_CHOICES, ) -from omegaconf import II, MISSING - @dataclass class FairseqDataclass: @@ -152,7 +151,7 @@ class CommonConfig(FairseqDataclass): default=False, metadata={"help": "don't flatten FP16 grads tensor"} ) fp16_init_scale: int = field( - default=2 ** 7, metadata={"help": "default FP16 loss scale"} + default=2**7, metadata={"help": "default FP16 loss scale"} ) fp16_scale_window: Optional[int] = field( default=None, @@ -188,7 +187,7 @@ class CommonConfig(FairseqDataclass): }, ) amp_init_scale: int = field( - default=2 ** 7, metadata={"help": "default AMP loss scale"} + default=2**7, metadata={"help": "default AMP loss scale"} ) amp_scale_window: Optional[int] = field( default=None, diff --git a/fairseq/distributed/legacy_distributed_data_parallel.py b/fairseq/distributed/legacy_distributed_data_parallel.py index 5f89e6c0ee..cd434c7372 100644 --- a/fairseq/distributed/legacy_distributed_data_parallel.py +++ b/fairseq/distributed/legacy_distributed_data_parallel.py @@ -38,7 +38,7 @@ class LegacyDistributedDataParallel(nn.Module): performing all-reduce (default: 256M). """ - def __init__(self, module, process_group, buffer_size=2 ** 28): + def __init__(self, module, process_group, buffer_size=2**28): super().__init__() self.module = module diff --git a/fairseq/file_chunker_utils.py b/fairseq/file_chunker_utils.py index 443100c61a..3f27549099 100644 --- a/fairseq/file_chunker_utils.py +++ b/fairseq/file_chunker_utils.py @@ -59,7 +59,7 @@ def __iter__(self) -> tp.Iterable[str]: if ( self._end_offset > 0 and pos > self._end_offset - and pos < self._end_offset + 2 ** 32 + and pos < self._end_offset + 2**32 ): break yield line diff --git a/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py b/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py index c07a027a31..85dbd44b3c 100644 --- a/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py +++ b/fairseq/model_parallel/models/pipeline_parallel_transformer/layers.py @@ -242,7 +242,7 @@ def __init__(self, args, embed_tokens, dictionary): torch.Tensor(len(dictionary), self.output_embed_dim) ) nn.init.normal_( - self.embed_tokens, mean=0, std=self.output_embed_dim ** -0.5 + self.embed_tokens, mean=0, std=self.output_embed_dim**-0.5 ) if args.decoder_normalize_before and not getattr( @@ -587,7 +587,7 @@ def make_generation_fast_(self, need_attn=False, **kwargs): def Embedding(num_embeddings, embedding_dim, padding_idx): m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) nn.init.constant_(m.weight[padding_idx], 0) return m diff --git a/fairseq/model_parallel/models/transformer.py b/fairseq/model_parallel/models/transformer.py index 6b330ef1b7..cf3b2e8baf 100644 --- a/fairseq/model_parallel/models/transformer.py +++ b/fairseq/model_parallel/models/transformer.py @@ -6,6 +6,7 @@ import logging import torch.nn as nn + from fairseq.model_parallel.modules import ( ModelParallelTransformerDecoderLayer, ModelParallelTransformerEncoderLayer, @@ -17,12 +18,11 @@ TransformerModel, ) - try: from fairseq.model_parallel.megatron.mpu import ( + VocabParallelEmbedding, copy_to_model_parallel_region, gather_from_model_parallel_region, - VocabParallelEmbedding, ) has_megatron_submodule = True @@ -52,7 +52,7 @@ def build_embedding(cls, args, dictionary, embed_dim, path=None): padding_idx = dictionary.pad() def _vocab_init(tensor, **kwargs): - nn.init.normal_(tensor, mean=0, std=num_embeddings ** -0.5) + nn.init.normal_(tensor, mean=0, std=num_embeddings**-0.5) nn.init.constant_(tensor[1], 0) emb = VocabParallelEmbedding( diff --git a/fairseq/model_parallel/models/transformer_lm.py b/fairseq/model_parallel/models/transformer_lm.py index a7ca5c9fe6..03e4dbe263 100644 --- a/fairseq/model_parallel/models/transformer_lm.py +++ b/fairseq/model_parallel/models/transformer_lm.py @@ -74,7 +74,7 @@ def build_model(cls, args, task): @classmethod def build_embedding(cls, args, dictionary, embed_dim, path=None): def _vocab_init(tensor, **kwargs): - nn.init.normal_(tensor, mean=0, std=embed_dim ** -0.5) + nn.init.normal_(tensor, mean=0, std=embed_dim**-0.5) nn.init.constant_(tensor[1], 0) embed_tokens = VocabParallelEmbedding( diff --git a/fairseq/model_parallel/modules/multihead_attention.py b/fairseq/model_parallel/modules/multihead_attention.py index 8eb9d09dad..bbea450950 100644 --- a/fairseq/model_parallel/modules/multihead_attention.py +++ b/fairseq/model_parallel/modules/multihead_attention.py @@ -7,18 +7,18 @@ import torch import torch.nn.functional as F +from torch import Tensor, nn + from fairseq import utils from fairseq.incremental_decoding_utils import with_incremental_state from fairseq.modules.fairseq_dropout import FairseqDropout -from torch import Tensor, nn - try: from fairseq.model_parallel.megatron.mpu import ( - get_cuda_rng_tracker, - get_model_parallel_world_size, ColumnParallelLinear, RowParallelLinear, + get_cuda_rng_tracker, + get_model_parallel_world_size, ) has_megatron_submodule = True @@ -71,7 +71,7 @@ def __init__( assert ( self.head_dim * num_heads == self.embed_dim ), "embed_dim must be divisible by num_heads" - self.scaling = self.head_dim ** -0.5 + self.scaling = self.head_dim**-0.5 self.self_attention = self_attention self.encoder_decoder_attention = encoder_decoder_attention diff --git a/fairseq/models/bart/model.py b/fairseq/models/bart/model.py index bdb12b02f7..ba30c1d742 100644 --- a/fairseq/models/bart/model.py +++ b/fairseq/models/bart/model.py @@ -6,12 +6,12 @@ BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension """ -from typing import Optional - import logging +from typing import Optional import torch import torch.nn as nn + from fairseq import utils from fairseq.models import register_model, register_model_architecture from fairseq.models.transformer import TransformerModel @@ -19,7 +19,6 @@ from .hub_interface import BARTHubInterface - logger = logging.getLogger(__name__) @@ -247,7 +246,7 @@ def truncate_emb(key): embed_dim = state_dict["encoder.embed_tokens.weight"].size(1) new_lang_embed_to_add = torch.zeros(num_langids_to_add, embed_dim) - nn.init.normal_(new_lang_embed_to_add, mean=0, std=embed_dim ** -0.5) + nn.init.normal_(new_lang_embed_to_add, mean=0, std=embed_dim**-0.5) new_lang_embed_to_add = new_lang_embed_to_add.to( dtype=state_dict["encoder.embed_tokens.weight"].dtype, ) diff --git a/fairseq/models/distributed_fairseq_model.py b/fairseq/models/distributed_fairseq_model.py index 7c4ab558c0..fd76bcd4bf 100644 --- a/fairseq/models/distributed_fairseq_model.py +++ b/fairseq/models/distributed_fairseq_model.py @@ -19,7 +19,6 @@ TPUDistributedDataParallel, ) - logger = logging.getLogger(__name__) @@ -72,8 +71,8 @@ def DistributedFairseqModel(args, model, process_group, device): logger.info("enable fp16 communication hook in DDP") try: from torch.distributed.algorithms.ddp_comm_hooks import ( - register_ddp_comm_hook, DDPCommHookType, + register_ddp_comm_hook, ) except: logger.error( @@ -87,7 +86,7 @@ def DistributedFairseqModel(args, model, process_group, device): elif args.ddp_backend in {"no_c10d", "legacy_ddp"}: wrapped_model = LegacyDistributedDataParallel( module=model.to(device), - buffer_size=2 ** 28, + buffer_size=2**28, process_group=process_group, ) # forward missing getattr and state_dict/load_state_dict to orig model diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index b1d0a89b44..a9ca7d1dc9 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -5,18 +5,19 @@ import contextlib from argparse import Namespace +from dataclasses import dataclass, field from typing import Any import torch import torch.nn as nn -from dataclasses import dataclass, field +from omegaconf import II, MISSING + from fairseq import checkpoint_utils, tasks, utils from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.models import BaseFairseqModel, FairseqEncoder, register_model from fairseq.models.hubert.hubert import MASKING_DISTRIBUTION_CHOICES from fairseq.tasks import FairseqTask -from omegaconf import II, MISSING @dataclass @@ -348,7 +349,7 @@ def upgrade_state_dict_named(self, state_dict, name): def Embedding(num_embeddings, embedding_dim, padding_idx): m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) nn.init.constant_(m.weight[padding_idx], 0) return m diff --git a/fairseq/models/lightconv.py b/fairseq/models/lightconv.py index 4edfe35937..5f4f6d47a4 100644 --- a/fairseq/models/lightconv.py +++ b/fairseq/models/lightconv.py @@ -8,6 +8,7 @@ import torch import torch.nn as nn import torch.nn.functional as F + from fairseq import utils from fairseq.models import ( FairseqEncoder, @@ -504,7 +505,7 @@ def __init__( self.embed_out = nn.Parameter( torch.Tensor(len(dictionary), output_embed_dim) ) - nn.init.normal_(self.embed_out, mean=0, std=output_embed_dim ** -0.5) + nn.init.normal_(self.embed_out, mean=0, std=output_embed_dim**-0.5) self.register_buffer("version", torch.Tensor([2])) self.normalize = args.decoder_normalize_before and final_norm if self.normalize: @@ -890,7 +891,7 @@ def extra_repr(self): def Embedding(num_embeddings, embedding_dim, padding_idx): m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) nn.init.constant_(m.weight[padding_idx], 0) return m diff --git a/fairseq/models/roberta/model.py b/fairseq/models/roberta/model.py index 6d068d0dba..d7ced9190c 100644 --- a/fairseq/models/roberta/model.py +++ b/fairseq/models/roberta/model.py @@ -454,7 +454,10 @@ def upgrade_state_dict_named(self, state_dict, name): state_dict[prefix + "classification_heads." + k] = v # adapt data2vec models - if "encoder._ema" in state_dict and "encoder.lm_head.weight" not in state_dict: + if ( + "encoder._ema" in state_dict + and "encoder.lm_head.weight" not in state_dict + ): lm_state = self.encoder.lm_head.state_dict() for k, v in lm_state.items(): state_dict["encoder.lm_head." + k] = v diff --git a/fairseq/models/speech_to_speech/modules.py b/fairseq/models/speech_to_speech/modules.py index d07994b90e..a2049816ab 100644 --- a/fairseq/models/speech_to_speech/modules.py +++ b/fairseq/models/speech_to_speech/modules.py @@ -26,7 +26,7 @@ class StackedEmbedding(nn.Embedding): def __init__(self, num_embeddings, embed_dim, padding_idx, num_stacked=1): super().__init__(num_embeddings, embed_dim, padding_idx) # follow transformer.Embedding - nn.init.normal_(self.weight, mean=0, std=embed_dim ** -0.5) + nn.init.normal_(self.weight, mean=0, std=embed_dim**-0.5) nn.init.constant_(self.weight[padding_idx], 0) self.offset = ( diff --git a/fairseq/models/speech_to_text/modules/emformer.py b/fairseq/models/speech_to_text/modules/emformer.py index 70339788f7..935d593078 100644 --- a/fairseq/models/speech_to_text/modules/emformer.py +++ b/fairseq/models/speech_to_text/modules/emformer.py @@ -348,7 +348,7 @@ def __init__( self.dropout = dropout self.head_dim = embed_dim // num_heads - self.scaling = self.head_dim ** -0.5 + self.scaling = self.head_dim**-0.5 self.std_scale = std_scale self.use_mem = use_mem diff --git a/fairseq/models/text_to_speech/fastspeech2.py b/fairseq/models/text_to_speech/fastspeech2.py index f6ccac5abf..fb2d0df37d 100644 --- a/fairseq/models/text_to_speech/fastspeech2.py +++ b/fairseq/models/text_to_speech/fastspeech2.py @@ -35,7 +35,7 @@ def model_init(m): def Embedding(num_embeddings, embedding_dim, padding_idx=None): m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) return m diff --git a/fairseq/models/text_to_speech/hifigan.py b/fairseq/models/text_to_speech/hifigan.py index a777af5167..a852beefec 100644 --- a/fairseq/models/text_to_speech/hifigan.py +++ b/fairseq/models/text_to_speech/hifigan.py @@ -2,7 +2,7 @@ import torch.nn as nn import torch.nn.functional as F from torch.nn import Conv1d, ConvTranspose1d -from torch.nn.utils import weight_norm, remove_weight_norm +from torch.nn.utils import remove_weight_norm, weight_norm LRELU_SLOPE = 0.1 @@ -130,7 +130,7 @@ def __init__(self, cfg): self.ups.append( weight_norm( ConvTranspose1d( - cfg["upsample_initial_channel"] // (2 ** i), + cfg["upsample_initial_channel"] // (2**i), cfg["upsample_initial_channel"] // (2 ** (i + 1)), k, u, diff --git a/fairseq/models/text_to_speech/hub_interface.py b/fairseq/models/text_to_speech/hub_interface.py index c79e76b619..26c7ccaca2 100644 --- a/fairseq/models/text_to_speech/hub_interface.py +++ b/fairseq/models/text_to_speech/hub_interface.py @@ -4,9 +4,9 @@ # LICENSE file in the root directory of this source tree. import logging -from pathlib import Path -from typing import Optional, Dict, Tuple import random +from pathlib import Path +from typing import Dict, Optional, Tuple import torch import torch.nn as nn @@ -113,7 +113,9 @@ def get_model_input( logger.info(f"speaker: {spk}") spk = None if spk is None else torch.Tensor([[spk]]).long() - src_tokens = task.src_dict.encode_line(tokenized, add_if_not_exist=False).view(1, -1) + src_tokens = task.src_dict.encode_line(tokenized, add_if_not_exist=False).view( + 1, -1 + ) src_lengths = torch.Tensor([len(tokenized.split())]).long() return { "net_input": { diff --git a/fairseq/models/text_to_speech/tts_transformer.py b/fairseq/models/text_to_speech/tts_transformer.py index 265d3998a2..19afc2b717 100644 --- a/fairseq/models/text_to_speech/tts_transformer.py +++ b/fairseq/models/text_to_speech/tts_transformer.py @@ -38,7 +38,7 @@ def encoder_init(m): def Embedding(num_embeddings, embedding_dim): m = nn.Embedding(num_embeddings, embedding_dim) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) return m diff --git a/fairseq/models/transformer/transformer_base.py b/fairseq/models/transformer/transformer_base.py index b4d5604dbb..0cbbccbc5a 100644 --- a/fairseq/models/transformer/transformer_base.py +++ b/fairseq/models/transformer/transformer_base.py @@ -7,16 +7,17 @@ import torch import torch.nn as nn +from torch import Tensor + from fairseq import utils from fairseq.dataclass.utils import gen_parser_from_dataclass from fairseq.distributed import fsdp_wrap from fairseq.models import FairseqEncoderDecoderModel from fairseq.models.transformer import ( - TransformerEncoderBase, - TransformerDecoderBase, TransformerConfig, + TransformerDecoderBase, + TransformerEncoderBase, ) -from torch import Tensor class TransformerModelBase(FairseqEncoderDecoderModel): @@ -174,6 +175,6 @@ def get_normalized_probs( def Embedding(num_embeddings, embedding_dim, padding_idx): m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) nn.init.constant_(m.weight[padding_idx], 0) return m diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py index 5046fa24fc..bc66949cf9 100644 --- a/fairseq/models/transformer/transformer_decoder.py +++ b/fairseq/models/transformer/transformer_decoder.py @@ -8,6 +8,8 @@ import torch import torch.nn as nn +from torch import Tensor + from fairseq import utils from fairseq.distributed import fsdp_wrap from fairseq.models import FairseqIncrementalDecoder @@ -20,11 +22,10 @@ LayerNorm, PositionalEmbedding, SinusoidalPositionalEmbedding, + transformer_layer, ) -from fairseq.modules import transformer_layer from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ -from torch import Tensor # rewrite name for backward compatibility in `make_generation_fast_` @@ -161,7 +162,7 @@ def build_output_projection(self, cfg, dictionary, embed_tokens): self.output_embed_dim, len(dictionary), bias=False ) nn.init.normal_( - self.output_projection.weight, mean=0, std=self.output_embed_dim ** -0.5 + self.output_projection.weight, mean=0, std=self.output_embed_dim**-0.5 ) num_base_layers = cfg.base_layers for i in range(num_base_layers): diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 23c5ae2d91..8214bc8e7a 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -11,9 +11,11 @@ import torch import torch.nn as nn import torch.nn.functional as F + from fairseq import utils from fairseq.data.data_utils import compute_mask_indices from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.distributed import fsdp_wrap from fairseq.models import BaseFairseqModel, register_model from fairseq.modules import ( Fp32GroupNorm, @@ -22,15 +24,15 @@ GumbelVectorQuantizer, LayerNorm, MultiheadAttention, + RelPositionalEncoding, SamePad, TransposeLast, ) from fairseq.modules.checkpoint_activations import checkpoint_wrapper +from fairseq.modules.conformer_layer import ConformerWav2Vec2EncoderLayer from fairseq.modules.transformer_sentence_encoder import init_bert_params from fairseq.utils import buffered_arange, index_put, is_xla_tensor -from fairseq.distributed import fsdp_wrap -from fairseq.modules.conformer_layer import ConformerWav2Vec2EncoderLayer -from fairseq.modules import RelPositionalEncoding + from .utils import pad_to_multiple EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) @@ -549,7 +551,7 @@ def compute_preds(self, x, y, negatives): if is_xla_tensor(logits) or neg_is_pos.any(): if not hasattr(self, "_inftensor"): - fillval = -float(2 ** 30) + fillval = -float(2**30) self._inftensor = ( torch.tensor(fillval).to(x.device) if is_xla_tensor(logits) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 0e35a87beb..08d875a01d 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -5,8 +5,8 @@ import contextlib import copy -import math import logging +import math import re from argparse import Namespace from dataclasses import dataclass, field @@ -32,7 +32,6 @@ from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerDecoderLayer from fairseq.tasks import FairseqTask - logger = logging.getLogger(__name__) @@ -603,7 +602,7 @@ def __init__( self.embed_out = nn.Parameter( torch.Tensor(len(dictionary), self.output_embed_dim) ) - nn.init.normal_(self.embed_out, mean=0, std=self.output_embed_dim ** -0.5) + nn.init.normal_(self.embed_out, mean=0, std=self.output_embed_dim**-0.5) if transformer_cfg.decoder_normalize_before: self.layer_norm = LayerNorm(embed_dim) @@ -736,7 +735,7 @@ def upgrade_state_dict_named(self, state_dict, name): def Embedding(num_embeddings, embedding_dim, padding_idx): m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) nn.init.constant_(m.weight[padding_idx], 0) return m diff --git a/fairseq/modules/adaptive_input.py b/fairseq/modules/adaptive_input.py index 446534a9f8..01ac4accac 100644 --- a/fairseq/modules/adaptive_input.py +++ b/fairseq/modules/adaptive_input.py @@ -7,9 +7,10 @@ from typing import List import torch -from fairseq.modules.quant_noise import quant_noise from torch import nn +from fairseq.modules.quant_noise import quant_noise + class AdaptiveInput(nn.Module): def __init__( @@ -40,7 +41,7 @@ def __init__( for i in range(len(self.cutoff)): prev = self.cutoff[i - 1] if i > 0 else 0 size = self.cutoff[i] - prev - dim = int(initial_dim // (factor ** i)) + dim = int(initial_dim // (factor**i)) seq = nn.Sequential( nn.Embedding(size, dim, self.padding_idx), quant_noise( diff --git a/fairseq/modules/downsampled_multihead_attention.py b/fairseq/modules/downsampled_multihead_attention.py index 2cdece3f7f..5e42942a9f 100644 --- a/fairseq/modules/downsampled_multihead_attention.py +++ b/fairseq/modules/downsampled_multihead_attention.py @@ -9,6 +9,7 @@ import torch import torch.nn as nn import torch.nn.functional as F + from fairseq.modules.fairseq_dropout import FairseqDropout from fairseq.modules.scalar_bias import scalar_bias @@ -69,7 +70,7 @@ def __init__( else: self.out_proj = Linear(out_proj_size, out_channels, bias=bias) - self.scaling = self.head_dim ** -0.5 + self.scaling = self.head_dim**-0.5 def forward( self, diff --git a/fairseq/modules/gumbel_vector_quantizer.py b/fairseq/modules/gumbel_vector_quantizer.py index a0e40c36dc..91655bc5e1 100644 --- a/fairseq/modules/gumbel_vector_quantizer.py +++ b/fairseq/modules/gumbel_vector_quantizer.py @@ -85,7 +85,7 @@ def block(input_dim, output_dim): def set_num_updates(self, num_updates): self.curr_temp = max( - self.max_temp * self.temp_decay ** num_updates, self.min_temp + self.max_temp * self.temp_decay**num_updates, self.min_temp ) def get_codebook_indices(self): @@ -100,7 +100,7 @@ def get_codebook_indices(self): if not self.combine_groups: self.codebook_indices = self.codebook_indices.view( - self.num_vars ** self.groups, -1 + self.num_vars**self.groups, -1 ) for b in range(1, self.groups): self.codebook_indices[:, b] += self.num_vars * b @@ -112,7 +112,7 @@ def codebook(self): return ( self.vars.squeeze(0) .index_select(0, indices) - .view(self.num_vars ** self.groups, -1) + .view(self.num_vars**self.groups, -1) ) def sample_from_codebook(self, b, n): @@ -132,7 +132,7 @@ def to_codebook_index(self, indices): res = indices.new_full(indices.shape[:-1], 0) for i in range(self.groups): exponent = self.groups - i - 1 - res += indices[..., i] * (self.num_vars ** exponent) + res += indices[..., i] * (self.num_vars**exponent) return res def forward_idx(self, x): diff --git a/fairseq/modules/kmeans_attention.py b/fairseq/modules/kmeans_attention.py index ca5063010a..0088d1ebdc 100644 --- a/fairseq/modules/kmeans_attention.py +++ b/fairseq/modules/kmeans_attention.py @@ -1,11 +1,11 @@ -import torch -import torch.nn as nn -import torch.nn.functional as F import math +from functools import reduce, wraps from inspect import isfunction from operator import mul -from functools import reduce, wraps +import torch +import torch.nn as nn +import torch.nn.functional as F from aml.multimodal_video.utils.einops.lib import rearrange, repeat from aml.multimodal_video.utils.einops.lib.layers.torch import Rearrange @@ -476,7 +476,7 @@ def forward(self, q, k, v, query_mask=None, key_mask=None, **kwargs): ) k, v = map(lambda x: torch.cat(x, dim=3), ((m_k, k), (m_v, v))) - dots = torch.einsum("bhnid,bhnjd->bhnij", q, k) * (d ** -0.5) + dots = torch.einsum("bhnid,bhnjd->bhnij", q, k) * (d**-0.5) mask_value = max_neg_value(dots) diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 8780a9b9fe..dd07cd9e45 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -8,12 +8,13 @@ import torch import torch.nn.functional as F +from torch import Tensor, nn +from torch.nn import Parameter + from fairseq import utils from fairseq.incremental_decoding_utils import with_incremental_state from fairseq.modules.fairseq_dropout import FairseqDropout from fairseq.modules.quant_noise import quant_noise -from torch import Tensor, nn -from torch.nn import Parameter @with_incremental_state @@ -53,7 +54,7 @@ def __init__( assert ( self.head_dim * num_heads == self.embed_dim ), "embed_dim must be divisible by num_heads" - self.scaling = self.head_dim ** -0.5 + self.scaling = self.head_dim**-0.5 self.self_attention = self_attention self.encoder_decoder_attention = encoder_decoder_attention diff --git a/fairseq/modules/positional_embedding.py b/fairseq/modules/positional_embedding.py index 8e94e35edb..97cd474b51 100644 --- a/fairseq/modules/positional_embedding.py +++ b/fairseq/modules/positional_embedding.py @@ -23,7 +23,7 @@ def PositionalEmbedding( if padding_idx is not None: num_embeddings = num_embeddings + padding_idx + 1 m = LearnedPositionalEmbedding(num_embeddings, embedding_dim, padding_idx) - nn.init.normal_(m.weight, mean=0, std=embedding_dim ** -0.5) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) if padding_idx is not None: nn.init.constant_(m.weight[padding_idx], 0) else: diff --git a/fairseq/modules/quantization/scalar/modules/qact.py b/fairseq/modules/quantization/scalar/modules/qact.py index c5dd1d6336..b362c30dc7 100644 --- a/fairseq/modules/quantization/scalar/modules/qact.py +++ b/fairseq/modules/quantization/scalar/modules/qact.py @@ -81,7 +81,7 @@ def quantize_hook(module, x, y): # using straight-through estimator (STE) clamp_low = -self.scale * self.zero_point - clamp_high = self.scale * (2 ** self.bits - 1 - self.zero_point) + clamp_high = self.scale * (2**self.bits - 1 - self.zero_point) return torch.clamp(y, clamp_low.item(), clamp_high.item()) + noise.detach() # register hook diff --git a/fairseq/modules/quantization/scalar/modules/qconv.py b/fairseq/modules/quantization/scalar/modules/qconv.py index 83788c6f71..29744744ec 100644 --- a/fairseq/modules/quantization/scalar/modules/qconv.py +++ b/fairseq/modules/quantization/scalar/modules/qconv.py @@ -119,7 +119,7 @@ def forward(self, input): # using straight-through estimator (STE) clamp_low = -self.scale * self.zero_point - clamp_high = self.scale * (2 ** self.bits - 1 - self.zero_point) + clamp_high = self.scale * (2**self.bits - 1 - self.zero_point) weight = ( torch.clamp(self.weight, clamp_low.item(), clamp_high.item()) + noise.detach() diff --git a/fairseq/modules/quantization/scalar/modules/qemb.py b/fairseq/modules/quantization/scalar/modules/qemb.py index d6cf06e587..3b293ac31e 100644 --- a/fairseq/modules/quantization/scalar/modules/qemb.py +++ b/fairseq/modules/quantization/scalar/modules/qemb.py @@ -113,7 +113,7 @@ def forward(self, input): # using straight-through estimator (STE) clamp_low = -self.scale * self.zero_point - clamp_high = self.scale * (2 ** self.bits - 1 - self.zero_point) + clamp_high = self.scale * (2**self.bits - 1 - self.zero_point) weight = ( torch.clamp(self.weight, clamp_low.item(), clamp_high.item()) + noise.detach() diff --git a/fairseq/modules/quantization/scalar/modules/qlinear.py b/fairseq/modules/quantization/scalar/modules/qlinear.py index 9db1559386..78606a25b9 100644 --- a/fairseq/modules/quantization/scalar/modules/qlinear.py +++ b/fairseq/modules/quantization/scalar/modules/qlinear.py @@ -92,7 +92,7 @@ def forward(self, input): # using straight-through estimator (STE) clamp_low = -self.scale * self.zero_point - clamp_high = self.scale * (2 ** self.bits - 1 - self.zero_point) + clamp_high = self.scale * (2**self.bits - 1 - self.zero_point) weight = ( torch.clamp(self.weight, clamp_low.item(), clamp_high.item()) + noise.detach() diff --git a/fairseq/modules/quantization/scalar/ops.py b/fairseq/modules/quantization/scalar/ops.py index ad1e14e051..e0f9a0c1f8 100644 --- a/fairseq/modules/quantization/scalar/ops.py +++ b/fairseq/modules/quantization/scalar/ops.py @@ -18,7 +18,7 @@ def emulate_int(w, bits, method, scale=None, zero_point=None): def quantize(w, scale, zero_point, bits=8): # In the default behavior, max_val = 255. - max_val = 2 ** bits - 1 + max_val = 2**bits - 1 return ( torch.clamp(torch.round(w / scale + zero_point), 0, max_val) - zero_point ) * scale diff --git a/fairseq/optim/adafactor.py b/fairseq/optim/adafactor.py index c969b9fbc0..042ae926b0 100644 --- a/fairseq/optim/adafactor.py +++ b/fairseq/optim/adafactor.py @@ -224,7 +224,7 @@ def step(self, closure=None): group["lr"] = self._get_lr(group, state) beta2t = 1.0 - math.pow(state["step"], group["decay_rate"]) - update = (grad ** 2) + group["eps"][0] + update = (grad**2) + group["eps"][0] if factored: exp_avg_sq_row = state["exp_avg_sq_row"] exp_avg_sq_col = state["exp_avg_sq_col"] diff --git a/fairseq/optim/dynamic_loss_scaler.py b/fairseq/optim/dynamic_loss_scaler.py index 43f9be37b9..60c47b8db0 100644 --- a/fairseq/optim/dynamic_loss_scaler.py +++ b/fairseq/optim/dynamic_loss_scaler.py @@ -7,7 +7,7 @@ class DynamicLossScaler(object): def __init__( self, - init_scale=2.0 ** 15, + init_scale=2.0**15, scale_factor=2.0, scale_window=2000, tolerance=0.0, diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index f8af2883a6..2c4ee326e9 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -7,9 +7,10 @@ from itertools import chain import torch -from fairseq import optim from omegaconf import DictConfig +from fairseq import optim + from .dynamic_loss_scaler import DynamicLossScaler @@ -265,7 +266,7 @@ def __init__(self, cfg: DictConfig, params, fp32_optimizer, fp32_params, **kwarg / cfg.common.model_parallel_size ) scale_window = int( - 2 ** 14 / data_parallel_size / cfg.optimization.update_freq[0] + 2**14 / data_parallel_size / cfg.optimization.update_freq[0] ) else: scale_window = cfg.common.fp16_scale_window @@ -499,7 +500,7 @@ def __init__( / cfg.common.model_parallel_size ) scale_window = int( - 2 ** 14 / data_parallel_size / cfg.optimization.update_freq[0] + 2**14 / data_parallel_size / cfg.optimization.update_freq[0] ) else: scale_window = cfg.common.fp16_scale_window diff --git a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py index 51f58359ed..d01143498f 100644 --- a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py @@ -125,17 +125,17 @@ def step_update(self, num_updates): 1 - curr_updates / self.period * (1 - self.t_mult), self.t_mult ) ) - t_i = self.t_mult ** i * self.period + t_i = self.t_mult**i * self.period t_curr = ( curr_updates - - (1 - self.t_mult ** i) / (1 - self.t_mult) * self.period + - (1 - self.t_mult**i) / (1 - self.t_mult) * self.period ) else: i = math.floor(curr_updates / self.period) t_i = self.period t_curr = curr_updates - (self.period * i) - lr_shrink = self.lr_shrink ** i + lr_shrink = self.lr_shrink**i min_lr = self.cfg.min_lr * lr_shrink max_lr = self.max_lr * lr_shrink diff --git a/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py b/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py index 0f87bb5d7e..987c905a23 100644 --- a/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py +++ b/fairseq/optim/lr_scheduler/inverse_square_root_schedule.py @@ -63,7 +63,7 @@ def __init__(self, cfg: InverseSquareRootLRScheduleConfig, optimizer): self.lr_step = (warmup_end_lr - cfg.warmup_init_lr) / cfg.warmup_updates # then, decay prop. to the inverse square root of the update number - self.decay_factor = warmup_end_lr * cfg.warmup_updates ** 0.5 + self.decay_factor = warmup_end_lr * cfg.warmup_updates**0.5 # initial learning rate self.lr = cfg.warmup_init_lr @@ -80,6 +80,6 @@ def step_update(self, num_updates): if num_updates < self.cfg.warmup_updates: self.lr = self.cfg.warmup_init_lr + num_updates * self.lr_step else: - self.lr = self.decay_factor * num_updates ** -0.5 + self.lr = self.decay_factor * num_updates**-0.5 self.optimizer.set_lr(self.lr) return self.lr diff --git a/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py b/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py index bfe2a0d381..2a32bd10f2 100644 --- a/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/triangular_lr_scheduler.py @@ -69,7 +69,7 @@ def step_update(self, num_updates): """Update the learning rate after each update.""" cycle = math.floor(num_updates / (2 * self.stepsize)) - lr_shrink = self.lr_shrink ** cycle + lr_shrink = self.lr_shrink**cycle max_lr = self.max_lr * lr_shrink if self.shrink_min: min_lr = self.min_lr * lr_shrink diff --git a/fairseq/tasks/multilingual_denoising.py b/fairseq/tasks/multilingual_denoising.py index d1c914917f..8226d95030 100644 --- a/fairseq/tasks/multilingual_denoising.py +++ b/fairseq/tasks/multilingual_denoising.py @@ -7,6 +7,7 @@ import os import numpy as np + from fairseq.data import ( AppendTokenDataset, ConcatDataset, @@ -23,7 +24,6 @@ from .denoising import DenoisingTask - logger = logging.getLogger(__name__) @@ -94,7 +94,7 @@ def _get_sample_prob(self, dataset_lens): languages by upsampling them. """ prob = dataset_lens / dataset_lens.sum() - smoothed_prob = prob ** self.args.multilang_sampling_alpha + smoothed_prob = prob**self.args.multilang_sampling_alpha smoothed_prob = smoothed_prob / smoothed_prob.sum() return smoothed_prob diff --git a/fairseq/tasks/multilingual_language_modeling.py b/fairseq/tasks/multilingual_language_modeling.py index 673f563bed..8fd5e5954d 100644 --- a/fairseq/tasks/multilingual_language_modeling.py +++ b/fairseq/tasks/multilingual_language_modeling.py @@ -272,7 +272,7 @@ def _get_sample_prob(self, dataset_lens): languages by upsampling them. """ prob = dataset_lens / dataset_lens.sum() - smoothed_prob = prob ** self.args.multilang_sampling_alpha + smoothed_prob = prob**self.args.multilang_sampling_alpha smoothed_prob = smoothed_prob / smoothed_prob.sum() return smoothed_prob diff --git a/fairseq/tasks/multilingual_masked_lm.py b/fairseq/tasks/multilingual_masked_lm.py index 9e6ce4b8a2..156d085aa4 100644 --- a/fairseq/tasks/multilingual_masked_lm.py +++ b/fairseq/tasks/multilingual_masked_lm.py @@ -8,6 +8,7 @@ import numpy as np import torch + from fairseq import utils from fairseq.data import ( ConcatDataset, @@ -28,7 +29,6 @@ ) from fairseq.tasks import LegacyFairseqTask, register_task - logger = logging.getLogger(__name__) @@ -144,7 +144,7 @@ def _get_sample_prob(self, dataset_lens): languages by upsampling them. """ prob = dataset_lens / dataset_lens.sum() - smoothed_prob = prob ** self.args.multilang_sampling_alpha + smoothed_prob = prob**self.args.multilang_sampling_alpha smoothed_prob = smoothed_prob / smoothed_prob.sum() return smoothed_prob diff --git a/fairseq/trainer.py b/fairseq/trainer.py index 6b37caa8dd..ee7d103316 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -17,6 +17,8 @@ from typing import Any, Dict, List import torch +from omegaconf import OmegaConf + from fairseq import checkpoint_utils, models, optim, utils from fairseq.dataclass.configs import FairseqConfig from fairseq.dataclass.utils import convert_namespace_to_omegaconf @@ -27,7 +29,6 @@ from fairseq.nan_detector import NanDetector from fairseq.optim import lr_scheduler from fairseq.utils import safe_hasattr -from omegaconf import OmegaConf logger = logging.getLogger(__name__) @@ -1253,7 +1254,7 @@ def agg_norm_fn(total_norm): total_norm = distributed_utils.all_reduce( total_norm, group=self.data_parallel_process_group ) - return total_norm ** 0.5 + return total_norm**0.5 should_agg_norm = self.is_fsdp and ( self.data_parallel_process_group is not None diff --git a/fairseq/utils.py b/fairseq/utils.py index c7161fa6d3..9dd9459507 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import argparse +import collections import contextlib import copy import importlib @@ -12,12 +13,11 @@ import sys import warnings from itertools import accumulate -from typing import Callable, Dict, List, Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, Callable, Dict, List, Optional import torch import torch.nn.functional as F from torch import Tensor -import collections if TYPE_CHECKING: from fairseq.modules.multihead_attention import MultiheadAttention @@ -529,7 +529,7 @@ def get_perplexity(loss, round=2, base=2): if loss is None: return 0.0 try: - return safe_round(base ** loss, round) + return safe_round(base**loss, round) except OverflowError: return float("inf") @@ -714,6 +714,7 @@ def get_tpu_device(): def tpu_data_loader(itr): import torch_xla.core.xla_model as xm import torch_xla.distributed.parallel_loader as pl + from fairseq.data import iterators xm.rendezvous("tpu_data_loader") # wait for all workers diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index ab6e77029e..250c766edd 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -16,14 +16,14 @@ from typing import Iterable, List, Optional import torch +from omegaconf import DictConfig + import fairseq from fairseq import checkpoint_utils, distributed_utils, options, tasks, utils from fairseq.dataclass.utils import convert_namespace_to_omegaconf from fairseq.logging import progress_bar from fairseq.logging.meters import StopwatchMeter from fairseq.sequence_scorer import SequenceScorer -from omegaconf import DictConfig - logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -197,7 +197,7 @@ def eval_lm( return { "loss": avg_nll_loss, - "perplexity": 2 ** avg_nll_loss, + "perplexity": 2**avg_nll_loss, } diff --git a/tests/test_ema.py b/tests/test_ema.py index 1f8f71b9b6..2c68185357 100644 --- a/tests/test_ema.py +++ b/tests/test_ema.py @@ -4,10 +4,10 @@ # LICENSE file in the root directory of this source tree. import unittest -from unittest.mock import patch from copy import deepcopy from dataclasses import dataclass from typing import Optional +from unittest.mock import patch import torch @@ -107,9 +107,7 @@ def test_ema(self): self.assertTrue(torch.allclose(ema_param, param)) # Check that step_internal is called once - with patch.object( - ema, "_step_internal", return_value=None - ) as mock_method: + with patch.object(ema, "_step_internal", return_value=None) as mock_method: ema.step(model) mock_method.assert_called_once_with(model, None) @@ -151,9 +149,7 @@ def _test_ema_start_update(self, updates): ) # Check that step_internal is called once - with patch.object( - ema, "_step_internal", return_value=None - ) as mock_method: + with patch.object(ema, "_step_internal", return_value=None) as mock_method: ema.step(model, updates=updates) mock_method.assert_called_once_with(model, updates) diff --git a/tests/test_plasma_utils.py b/tests/test_plasma_utils.py index e6344c2a5a..7286c6cd3a 100644 --- a/tests/test_plasma_utils.py +++ b/tests/test_plasma_utils.py @@ -1,6 +1,6 @@ import contextlib -import unittest import tempfile +import unittest from io import StringIO import numpy as np @@ -9,7 +9,8 @@ try: from pyarrow import plasma - from fairseq.data.plasma_utils import PlasmaView, PlasmaStore + + from fairseq.data.plasma_utils import PlasmaStore, PlasmaView PYARROW_AVAILABLE = True except ImportError: @@ -111,7 +112,7 @@ def test_plasma_store_full_raises(self): server.kill() def test_object_id_overflow(self): - PlasmaView.get_object_id("", 2 ** 21) + PlasmaView.get_object_id("", 2**21) def test_training_lm_plasma(self): with contextlib.redirect_stdout(StringIO()): From 272c4c5197250997148fb12c0db6306035f166a4 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Thu, 3 Feb 2022 10:15:44 -0800 Subject: [PATCH 562/774] Fix hubert (#3019) Summary: ## PR review 1. Update HuBERT to work with the TransformerEncoder wav2vec2.py 2. Remove dictionary loading issue when loading fine-tuned HuBERT checkpoints to make the checkpoints self-contained 3. Add unit-test for HuBERT fine-tuned checkpoints 4. Avoid divide-by-zero error in infer.py when inference time is zero (e.g., when inferring just one utterance) Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3019 Reviewed By: andrewyeh Differential Revision: D33970620 Pulled By: wnhsu fbshipit-source-id: c523dd6ddb0f6a496be8b0b4b56f0c32c1d3dbc5 --- examples/hubert/tests/sample.large.hypo.word | 1 + examples/hubert/tests/sample.tsv | 2 - examples/hubert/tests/sample.xlarge.hypo.word | 1 + .../hubert/tests/test_feature_and_unit.sh | 1 + examples/hubert/tests/test_finetuned_asr.sh | 46 +++++++++++++++++++ examples/speech_recognition/new/infer.py | 4 +- fairseq/models/hubert/hubert.py | 34 ++++++++++++-- fairseq/models/hubert/hubert_asr.py | 18 ++++---- 8 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 examples/hubert/tests/sample.large.hypo.word delete mode 100644 examples/hubert/tests/sample.tsv create mode 100644 examples/hubert/tests/sample.xlarge.hypo.word create mode 100644 examples/hubert/tests/test_finetuned_asr.sh diff --git a/examples/hubert/tests/sample.large.hypo.word b/examples/hubert/tests/sample.large.hypo.word new file mode 100644 index 0000000000..d77a4cfddc --- /dev/null +++ b/examples/hubert/tests/sample.large.hypo.word @@ -0,0 +1 @@ +KEEP A GOING AN IF YOU'RE LUCKY YOU'LL RUN PLUMB INTO THEM WAS THE JEERING ANSWER AS THE SLEEPY COWMEN SPURRED THEIR PONIES ON TOWARD CAMP MUTTERING THEIR DISAPPROVAL OF TAKING ALONG A BUNCH OF BOYS ON A CATTLE DRIVE (None-0) diff --git a/examples/hubert/tests/sample.tsv b/examples/hubert/tests/sample.tsv deleted file mode 100644 index 6f163c70be..0000000000 --- a/examples/hubert/tests/sample.tsv +++ /dev/null @@ -1,2 +0,0 @@ -./examples/hubert/tests -6313-76958-0021.flac 190800 diff --git a/examples/hubert/tests/sample.xlarge.hypo.word b/examples/hubert/tests/sample.xlarge.hypo.word new file mode 100644 index 0000000000..53e402d455 --- /dev/null +++ b/examples/hubert/tests/sample.xlarge.hypo.word @@ -0,0 +1 @@ +KEEP A GOIN AND IF YOU'RE LUCKY YOU'LL RUN PLUMB INTO THEM WAS THE JEERING ANSWER AS THE SLEEPY COWMEN SPURRED THEIR PONIES ON TOWARD CAMP MUTTERING THEIR DISAPPROVAL OF TAKING ALONG A BUNCH OF BOYS ON A CATTLE DRIVE (None-0) diff --git a/examples/hubert/tests/test_feature_and_unit.sh b/examples/hubert/tests/test_feature_and_unit.sh index c89bd60672..8cddb27758 100644 --- a/examples/hubert/tests/test_feature_and_unit.sh +++ b/examples/hubert/tests/test_feature_and_unit.sh @@ -23,6 +23,7 @@ km_nunits[base]=500 test_dir=./examples/hubert/tests split=sample +echo -e "${test_dir}\n6313-76958-0021.flac\t190800" > "${test_dir}/${split}.tsv" check_feature () { echo "checking features..." diff --git a/examples/hubert/tests/test_finetuned_asr.sh b/examples/hubert/tests/test_finetuned_asr.sh new file mode 100644 index 0000000000..3c0538b1f7 --- /dev/null +++ b/examples/hubert/tests/test_finetuned_asr.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +set -e + +sizes="large xlarge" + +declare -A ckpt_urls +ckpt_urls[large]="https://dl.fbaipublicfiles.com/hubert/hubert_large_ll60k_finetune_ls960.pt" +ckpt_urls[xlarge]="https://dl.fbaipublicfiles.com/hubert/hubert_xtralarge_ll60k_finetune_ls960.pt" + +test_dir=$(pwd)/examples/hubert/tests +split=sample + +echo -e "${test_dir}\n6313-76958-0021.flac\t190800" > "${test_dir}/${split}.tsv" +echo -e "K E E P | A | G O I N G | A N D | I F | Y O U ' R E | L U C K Y | Y O U ' L L | R U N | P L U M B | I N T O | T H E M | W A S | T H E | J E E R I N G | A N S W E R | A S | T H E | S L E E P Y | C O W M E N | S P U R R E D | T H E I R | P O N I E S | O N | T O W A R D | C A M P | M U T T E R I N G | T H E I R | D I S A P P R O V A L | O F | T A K I N G | A L O N G | A | B U N C H | O F | B O Y S | O N | A | C A T T L E | D R I V E |" > "${test_dir}/${split}.ltr" + +check_asr () { + echo "checking asr outputs..." + + size=$1 + ckpt_url=$2 + ckpt_path="$test_dir/$(basename "$ckpt_url")" + + if [ ! -f "$ckpt_path" ]; then + echo "downloading $ckpt_url to $ckpt_path" + wget "$ckpt_url" -O "$ckpt_path" + fi + + python examples/speech_recognition/new/infer.py \ + --config-dir examples/hubert/config/decode --config-name infer_viterbi \ + common_eval.path="${ckpt_path}" task.data="${test_dir}" task.normalize=true \ + decoding.results_path="${test_dir}/pred" \ + common_eval.results_path="${test_dir}/pred" \ + common_eval.quiet=false dataset.gen_subset="${split}" + + if diff -q "${test_dir}/pred/hypo.word" "${test_dir}/${split}.${size}.hypo.word" &>/dev/null; then + echo "...passed word check" + else + echo "...failed word check" + fi + rm -rf "${test_dir}/pred" +} + +for size in $sizes; do + check_asr "$size" "${ckpt_urls[$size]}" +done diff --git a/examples/speech_recognition/new/infer.py b/examples/speech_recognition/new/infer.py index f56e820ffa..e45e76870f 100644 --- a/examples/speech_recognition/new/infer.py +++ b/examples/speech_recognition/new/infer.py @@ -334,8 +334,8 @@ def log_generation_time(self) -> None: self.num_sentences, self.gen_timer.n, self.gen_timer.sum, - self.num_sentences / self.gen_timer.sum, - 1.0 / self.gen_timer.avg, + self.num_sentences / (self.gen_timer.sum + 1e-6), + 1.0 / (self.gen_timer.avg + 1e-6), ) diff --git a/fairseq/models/hubert/hubert.py b/fairseq/models/hubert/hubert.py index 40f35be688..d1e89dc9eb 100644 --- a/fairseq/models/hubert/hubert.py +++ b/fairseq/models/hubert/hubert.py @@ -18,6 +18,9 @@ from fairseq.dataclass import ChoiceEnum, FairseqDataclass from fairseq.models import BaseFairseqModel, register_model from fairseq.models.wav2vec.wav2vec2 import ( + EXTRACTOR_MODE_CHOICES, + MASKING_DISTRIBUTION_CHOICES, + LAYER_TYPE_CHOICES, ConvFeatureExtractionModel, TransformerEncoder, ) @@ -29,9 +32,6 @@ logger = logging.getLogger(__name__) -EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) -MASKING_DISTRIBUTION_CHOICES = ChoiceEnum(["static", "uniform", "normal", "poisson"]) - @dataclass class HubertConfig(FairseqDataclass): @@ -60,6 +60,9 @@ class HubertConfig(FairseqDataclass): activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( default="gelu", metadata={"help": "activation function to use"} ) + layer_type: LAYER_TYPE_CHOICES = field( + default="transformer", metadata={"help": "layer type in encoder"} + ) # dropouts dropout: float = field( @@ -209,6 +212,31 @@ class HubertConfig(FairseqDataclass): metadata={"help": "recompute activations and save memory for extra compute"}, ) + # FP16 optimization + required_seq_len_multiple: int = field( + default=2, + metadata={ + "help": "pad the input to encoder such that the sequence length is divisible by multiple" + }, + ) + + # Conformer + depthwise_conv_kernel_size: int = field( + default=31, + metadata={ + "help": "depthwise-conv-kernel-size for convolution in conformer layer" + }, + ) + attn_type: str = field( + default="", + metadata={"help": "if espnet use ESPNET MHA"}, + ) + pos_enc_type: str = field( + default="abs", + metadata={"help": "Positional encoding type to use in conformer"}, + ) + fp16: bool = field(default=False, metadata={"help": "If fp16 is being used"}) + @register_model("hubert", dataclass=HubertConfig) class HubertModel(BaseFairseqModel): diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index a9ca7d1dc9..8e06a2e675 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -144,7 +144,7 @@ def upgrade_state_dict_named(self, state_dict, name): @classmethod def build_model(cls, cfg: HubertCtcConfig, task: FairseqTask): """Build a new model instance.""" - w2v_encoder = HubertEncoder(cfg, task.target_dictionary) + w2v_encoder = HubertEncoder(cfg, task) return cls(cfg, w2v_encoder) def get_normalized_probs(self, net_output, log_probs): @@ -225,7 +225,7 @@ class HubertSeq2SeqConfig(HubertAsrConfig): class HubertEncoder(FairseqEncoder): - def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): + def __init__(self, cfg: HubertAsrConfig, task): self.apply_mask = cfg.apply_mask arg_overrides = { @@ -266,19 +266,21 @@ def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): ) w2v_args.task.data = cfg.data - task = tasks.setup_task(w2v_args.task) + pretrain_task = tasks.setup_task(w2v_args.task) if state is not None and "task_state" in state: # This will load the stored "dictionaries" object - task.load_state_dict(state["task_state"]) - model = task.build_model(w2v_args.model, from_checkpoint=True) + pretrain_task.load_state_dict(state["task_state"]) + else: + pretrain_task.load_state_dict(task.state_dict()) + model = pretrain_task.build_model(w2v_args.model, from_checkpoint=True) if state is not None and not cfg.no_pretrained_weights: # set strict=False because we omit some modules model.load_state_dict(state["model"], strict=False) model.remove_pretraining_modules() - super().__init__(task.source_dictionary) + super().__init__(pretrain_task.source_dictionary) d = w2v_args.model.encoder_embed_dim @@ -288,8 +290,8 @@ def __init__(self, cfg: HubertAsrConfig, tgt_dict=None): self.freeze_finetune_updates = cfg.freeze_finetune_updates self.num_updates = 0 - if tgt_dict is not None: - self.proj = Linear(d, len(tgt_dict)) + if task.target_dictionary is not None: + self.proj = Linear(d, len(task.target_dictionary)) elif getattr(cfg, "decoder_embed_dim", d) != d: self.proj = Linear(d, cfg.decoder_embed_dim) else: From 53cc55c9c8ce8277e3f65d442f848f76e593af74 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Thu, 3 Feb 2022 14:38:03 -0800 Subject: [PATCH 563/774] add BERTScore scorer Summary: add BERTScore scorer Reviewed By: yuntang Differential Revision: D33881724 fbshipit-source-id: 89f7f7b71a9def28cd8b0366f540e445e74efabb --- fairseq/scoring/bertscore.py | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 fairseq/scoring/bertscore.py diff --git a/fairseq/scoring/bertscore.py b/fairseq/scoring/bertscore.py new file mode 100644 index 0000000000..6d5a8450d3 --- /dev/null +++ b/fairseq/scoring/bertscore.py @@ -0,0 +1,44 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from dataclasses import dataclass, field + +import numpy as np + +from fairseq.dataclass import FairseqDataclass +from fairseq.scoring import BaseScorer, register_scorer + + +@dataclass +class BertScoreScorerConfig(FairseqDataclass): + bert_score_lang: str = field(default="en", metadata={"help": "BERTScore language"}) + + +@register_scorer("bert_score", dataclass=BertScoreScorerConfig) +class BertScoreScorer(BaseScorer): + def __init__(self, cfg): + super(BertScoreScorer, self).__init__(cfg) + try: + import bert_score as _bert_score + except ImportError: + raise ImportError("Please install BERTScore: pip install bert-score") + + self.cfg = cfg + self._bert_score = _bert_score + self.scores = None + + def add_string(self, ref, pred): + self.ref.append(ref) + self.pred.append(pred) + + def score(self, order=4): + _, _, self.scores = self._bert_score.score( + self.pred, self.ref, lang=self.cfg.bert_score_lang + ) + self.scores = self.scores.numpy() + return np.mean(self.scores) + + def result_string(self, order=4): + return f"BERTScore: {self.score():.4f}" From 6b7a7d64574da32c489f5dc3a22b9b8d31627390 Mon Sep 17 00:00:00 2001 From: Vimal Manohar <vimalmanohar@fb.com> Date: Fri, 4 Feb 2022 09:08:30 -0800 Subject: [PATCH 564/774] Fix EMA GPU test Summary: The GPU test was broken after D33809223 (https://github.com/pytorch/fairseq/commit/1b61bbad327d2bf32502b3b9a770b57714cc43dc) Reviewed By: cruvadom Differential Revision: D33931570 fbshipit-source-id: 37962a437d8e25b1dafc58db0efa55c1afa5f3ee --- tests/gpu/test_ema_gpu.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/gpu/test_ema_gpu.py b/tests/gpu/test_ema_gpu.py index 34d9ccb788..33fb5607b4 100644 --- a/tests/gpu/test_ema_gpu.py +++ b/tests/gpu/test_ema_gpu.py @@ -36,6 +36,7 @@ class EMAConfig(object): ema_start_update: int = 0 ema_fp32: bool = False ema_seed_model: Optional[str] = None + ema_update_freq: int = 1 @unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") From 11b2830d29aed8043e5011d64e14004347a08b50 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Fri, 4 Feb 2022 14:33:48 -0800 Subject: [PATCH 565/774] Refactor speech tests and add missing regression tests (#3001) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3001 Reviewed By: kahne Differential Revision: D33904550 Pulled By: sravyapopuri388 fbshipit-source-id: f55f8121d83e5abebdfcf7ac90dcba39f65cafaf --- tests/speech/__init__.py | 77 +++++++++++++++++------- tests/speech/test_s2s_transformer.py | 47 +++++++++++++++ tests/speech/test_s2t_conformer.py | 6 +- tests/speech/test_s2t_transformer.py | 6 +- tests/speech/test_wav2vec2.py | 90 ++++++++++++++++++++++++++++ tests/speech/test_xm_transformer.py | 44 +++----------- 6 files changed, 211 insertions(+), 59 deletions(-) create mode 100644 tests/speech/test_s2s_transformer.py create mode 100644 tests/speech/test_wav2vec2.py diff --git a/tests/speech/__init__.py b/tests/speech/__init__.py index 13b3ecf48c..dba99e4d93 100644 --- a/tests/speech/__init__.py +++ b/tests/speech/__init__.py @@ -15,7 +15,7 @@ from fairseq.scoring.wer import WerScorer from fairseq.scoring.bleu import SacrebleuScorer from fairseq import utils - +import zipfile S3_BASE_URL = "https://dl.fbaipublicfiles.com/fairseq" @@ -95,19 +95,30 @@ def set_up_mustc_de_fbank(self): ) def download_and_load_checkpoint( - self, checkpoint_filename: str, arg_overrides: Optional[Dict[str, str]] = None + self, + checkpoint_filename: str, + arg_overrides: Optional[Dict[str, str]] = None, + strict: bool = True, ): path = self.download(self.base_url, self.root, checkpoint_filename) _arg_overrides = arg_overrides or {} _arg_overrides["data"] = self.root.as_posix() models, cfg, task = load_model_ensemble_and_task( - [path.as_posix()], arg_overrides=_arg_overrides + [path.as_posix()], arg_overrides=_arg_overrides, strict=strict ) if self.use_cuda: for model in models: model.cuda() - generator = task.build_generator(models, cfg) - return models, cfg, task, generator + + return models, cfg, task, self.build_generator(task, models, cfg) + + def build_generator( + self, + task, + models, + cfg, + ): + return task.build_generator(models, cfg) @classmethod def get_batch_iterator(cls, task, test_split, max_tokens, max_positions): @@ -141,35 +152,59 @@ def get_bleu_scorer(cls, tokenizer="13a", lowercase=False, char_level=False): return SacrebleuScorer(Namespace(**scorer_args)) @torch.no_grad() - def librispeech_s2t_test_base(self, ckpt_name, reference_wer): - models, cfg, task, generator = self.download_and_load_checkpoint( - ckpt_name, - arg_overrides={"config_yaml": "cfg_librispeech.yaml"}, + def base_test( + self, + ckpt_name, + reference_score, + score_delta=0.3, + dataset="librispeech_test-other", + max_tokens=65_536, + max_positions=(4_096, 1_024), + arg_overrides=None, + strict=True, + score_type="wer", + ): + models, _, task, generator = self.download_and_load_checkpoint( + ckpt_name, arg_overrides=arg_overrides, strict=strict ) if not self.use_cuda: return batch_iterator = self.get_batch_iterator( - task, "librispeech_test-other", 65_536, (4_096, 1_024) + task, dataset, max_tokens, max_positions ) - scorer = self.get_wer_scorer() + if score_type == "bleu": + scorer = self.get_bleu_scorer() + elif score_type == "wer": + scorer = self.get_wer_scorer() + else: + raise Exception(f"Unsupported score type {score_type}") + progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) for batch_idx, sample in progress: sample = utils.move_to_cuda(sample) if self.use_cuda else sample hypo = task.inference_step(generator, models, sample) for i, sample_id in enumerate(sample["id"].tolist()): - tgt_tokens = ( - utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()) - .int() - .cpu() - ) - tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") - hypo_str = task.tgt_dict.string( - hypo[i][0]["tokens"].int().cpu(), "sentencepiece" + tgt_str, hypo_str = self.postprocess_tokens( + task, + sample["target"][i, :], + hypo[i][0]["tokens"].int().cpu(), ) if batch_idx == 0 and i < 3: print(f"T-{sample_id} {tgt_str}") print(f"H-{sample_id} {hypo_str}") scorer.add_string(tgt_str, hypo_str) - print(scorer.result_string() + f" (reference: {reference_wer})") - self.assertAlmostEqual(scorer.score(), reference_wer, delta=0.3) + + print(scorer.result_string() + f" (reference: {reference_score})") + self.assertAlmostEqual(scorer.score(), reference_score, delta=score_delta) + + def postprocess_tokens(self, task, target, hypo_tokens): + tgt_tokens = utils.strip_pad(target, task.tgt_dict.pad()).int().cpu() + tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") + hypo_str = task.tgt_dict.string(hypo_tokens, "sentencepiece") + return tgt_str, hypo_str + + def unzip_files(self, zip_file_name): + zip_file_path = self.root / zip_file_name + with zipfile.ZipFile(zip_file_path, "r") as zip_ref: + zip_ref.extractall(self.root / zip_file_name.strip(".zip")) diff --git a/tests/speech/test_s2s_transformer.py b/tests/speech/test_s2s_transformer.py new file mode 100644 index 0000000000..a4e71e246d --- /dev/null +++ b/tests/speech/test_s2s_transformer.py @@ -0,0 +1,47 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from tests.speech import TestFairseqSpeech +from fairseq import utils + +S3_BASE_URL = "https://dl.fbaipublicfiles.com/fairseq/" + + +class TestS2STransformer(TestFairseqSpeech): + def setUp(self): + self._set_up( + "s2s", + "speech_tests/s2s", + [ + "dev_shuf200.tsv", + "src_feat.zip", + "config_specaug_lb.yaml", + "config_letter_enc_unigram_dec.yaml", + ], + ) + + def test_s2s_transformer_checkpoint(self): + self.base_test( + ckpt_name="s2u_transformer_reduced_fisher.pt", + reference_score=38.3, + dataset="dev_shuf200", + arg_overrides={ + "config_yaml": "config_specaug_lb.yaml", + "target_is_code": True, + "target_code_size": 100, + }, + score_type="bleu", + ) + + def postprocess_tokens(self, task, target, hypo_tokens): + tgt_tokens = utils.strip_pad(target, task.tgt_dict.pad()).int().cpu() + tgt_str = task.tgt_dict.string(tgt_tokens) + hypo_str = task.tgt_dict.string(hypo_tokens) + return tgt_str, hypo_str + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/speech/test_s2t_conformer.py b/tests/speech/test_s2t_conformer.py index 2c7c57445a..5aaa4a0ed6 100644 --- a/tests/speech/test_s2t_conformer.py +++ b/tests/speech/test_s2t_conformer.py @@ -12,7 +12,11 @@ def setUp(self): self.set_up_librispeech() def test_librispeech_s2t_conformer_s_checkpoint(self): - self.librispeech_s2t_test_base("librispeech_conformer_rel_pos_s.pt", 12) + self.base_test( + ckpt_name="librispeech_conformer_rel_pos_s.pt", + reference_score=12, + arg_overrides={"config_yaml": "cfg_librispeech.yaml"}, + ) if __name__ == "__main__": diff --git a/tests/speech/test_s2t_transformer.py b/tests/speech/test_s2t_transformer.py index edf9f64c9e..172f5484a0 100644 --- a/tests/speech/test_s2t_transformer.py +++ b/tests/speech/test_s2t_transformer.py @@ -12,7 +12,11 @@ def setUp(self): self.set_up_librispeech() def test_librispeech_s2t_transformer_s_checkpoint(self): - self.librispeech_s2t_test_base("librispeech_transformer_s.pt", 9) + self.base_test( + ckpt_name="librispeech_transformer_s.pt", + reference_score=9, + arg_overrides={"config_yaml": "cfg_librispeech.yaml"}, + ) if __name__ == "__main__": diff --git a/tests/speech/test_wav2vec2.py b/tests/speech/test_wav2vec2.py new file mode 100644 index 0000000000..eff6114c8e --- /dev/null +++ b/tests/speech/test_wav2vec2.py @@ -0,0 +1,90 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +import torch +from tests.speech import TestFairseqSpeech +from fairseq.data.data_utils import post_process +from fairseq import utils +from omegaconf import open_dict + +S3_BASE_URL = "https://dl.fbaipublicfiles.com/fairseq" + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestWav2Vec2(TestFairseqSpeech): + def setUp(self): + self._set_up( + "librispeech_w2v2", + "conformer/wav2vec2/librispeech", + [ + "test_librispeech-other.ltr", + "test_librispeech-other.tsv", + "test_librispeech-other_small.ltr_100", + "test_librispeech-other_small.tsv", + "test-other.zip", + "dict.ltr.txt", + "dict.ltr_100.txt", + ], + ) + self.unzip_files( + "test-other.zip", + ) + + def test_transformer_w2v2(self): + self.base_test( + ckpt_name="transformer_oss_small_100h.pt", + reference_score=38, + score_delta=1, + dataset="test_librispeech-other", + max_tokens=1000000, + max_positions=(700000, 1000), + arg_overrides={ + "task": "audio_finetuning", + "labels": "ltr", + "nbest": 1, + "tpu": False, + }, + strict=False, + ) + + def test_conformer_w2v2(self): + self.base_test( + ckpt_name="conformer_LS_PT_LS_FT_rope.pt", + reference_score=4.5, + score_delta=1, + dataset="test_librispeech-other_small", + max_tokens=1000000, + max_positions=(700000, 1000), + arg_overrides={ + "task": "audio_finetuning", + "labels": "ltr_100", + "nbest": 1, + "tpu": False, + }, + strict=True, + ) + + def build_generator(self, task, models, cfg): + try: + from examples.speech_recognition.w2l_decoder import W2lViterbiDecoder + except Exception: + raise Exception("Cannot run this test without flashlight dependency") + with open_dict(cfg): + cfg.nbest = 1 + return W2lViterbiDecoder(cfg, task.target_dictionary) + + def postprocess_tokens(self, task, target, hypo_tokens): + tgt_tokens = utils.strip_pad(target, task.target_dictionary.pad()).int().cpu() + tgt_str = task.target_dictionary.string(tgt_tokens) + tgt_str = post_process(tgt_str, "letter") + + hypo_pieces = task.target_dictionary.string(hypo_tokens) + hypo_str = post_process(hypo_pieces, "letter") + return tgt_str, hypo_str + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/speech/test_xm_transformer.py b/tests/speech/test_xm_transformer.py index 60bb0dc6e1..43d321befd 100644 --- a/tests/speech/test_xm_transformer.py +++ b/tests/speech/test_xm_transformer.py @@ -4,11 +4,6 @@ # LICENSE file in the root directory of this source tree. import unittest - -import torch -from tqdm import tqdm - -from fairseq import utils from tests.speech import TestFairseqSpeech @@ -16,40 +11,17 @@ class TestXMTransformer(TestFairseqSpeech): def setUp(self): self.set_up_sotasty_es_en() - @torch.no_grad() def test_sotasty_es_en_600m_checkpoint(self): - models, cfg, task, generator = self.download_and_load_checkpoint( - "xm_transformer_600m_es_en_md.pt", + self.base_test( + ckpt_name="xm_transformer_600m_es_en_md.pt", + reference_score=30.42, + score_delta=0.2, + max_tokens=3_000_000, + max_positions=(1_000_000, 1_024), + dataset="sotasty_es_en_test_ted", arg_overrides={"config_yaml": "cfg_es_en.yaml"}, + score_type="bleu", ) - if not self.use_cuda: - return - - batch_iterator = self.get_batch_iterator( - task, "sotasty_es_en_test_ted", 3_000_000, (1_000_000, 1_024) - ) - scorer = self.get_bleu_scorer() - progress = tqdm(enumerate(batch_iterator), total=len(batch_iterator)) - for batch_idx, sample in progress: - sample = utils.move_to_cuda(sample) if self.use_cuda else sample - hypo = task.inference_step(generator, models, sample) - for i, sample_id in enumerate(sample["id"].tolist()): - tgt_tokens = ( - utils.strip_pad(sample["target"][i, :], task.tgt_dict.pad()) - .int() - .cpu() - ) - tgt_str = task.tgt_dict.string(tgt_tokens, "sentencepiece") - hypo_str = task.tgt_dict.string( - hypo[i][0]["tokens"].int().cpu(), "sentencepiece" - ) - if batch_idx == 0 and i < 3: - print(f"T-{sample_id} {tgt_str}") - print(f"H-{sample_id} {hypo_str}") - scorer.add_string(tgt_str, hypo_str) - reference_bleu = 31.7 - print(f"{scorer.result_string()} (reference: {reference_bleu})") - self.assertAlmostEqual(scorer.score(), reference_bleu, delta=0.2) if __name__ == "__main__": From 327cff24a57c2ae06657731bf3be86ee88fccfea Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Mon, 7 Feb 2022 15:37:59 -0800 Subject: [PATCH 566/774] Create a separate EMA implementation for in-model tracking (#3036) Summary: ema.py initially used by data2vec was actually created for trainer-level ema tracking since data2vec creates and uses ema tracking within the model, we will split ema into a different module-level implementation Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3036 Reviewed By: wnhsu Differential Revision: D34034479 Pulled By: alexeib fbshipit-source-id: f8c65552d446f1104c36380f5d1ff22a75e6e405 --- examples/data2vec/models/data2vec_audio.py | 9 +- examples/data2vec/models/data2vec_text.py | 9 +- fairseq/models/ema/ema.py | 3 + fairseq/modules/__init__.py | 3 + fairseq/modules/ema_module.py | 143 +++++++++++++++++++++ 5 files changed, 157 insertions(+), 10 deletions(-) create mode 100644 fairseq/modules/ema_module.py diff --git a/examples/data2vec/models/data2vec_audio.py b/examples/data2vec/models/data2vec_audio.py index 43e2f07e63..261c2f104c 100644 --- a/examples/data2vec/models/data2vec_audio.py +++ b/examples/data2vec/models/data2vec_audio.py @@ -15,8 +15,7 @@ import torch.nn.functional as F import torch.distributed as dist -from fairseq.dataclass.configs import EMAConfig -from fairseq.models.ema import EMA +from fairseq.modules import EMAModule, EMAModuleConfig from fairseq.data.data_utils import compute_mask_indices from fairseq.models import BaseFairseqModel, register_model from fairseq.models.wav2vec import ( @@ -148,7 +147,7 @@ def __init__(self, cfg: Data2VecAudioConfig): self.num_updates = 0 def make_ema_teacher(self): - ema_config = EMAConfig( + ema_config = EMAModuleConfig( ema_decay=self.cfg.ema_decay, ema_fp32=True, ) @@ -158,7 +157,7 @@ def make_ema_teacher(self): for k, _ in self.encoder.pos_conv.named_parameters(): skip_keys.add(f"pos_conv.{k}") - self.ema = EMA( + self.ema = EMAModule( self.encoder if self.cfg.ema_transformer_only else self, ema_config, skip_keys=skip_keys, @@ -181,7 +180,7 @@ def set_num_updates(self, num_updates): num_updates, self.cfg.ema_anneal_end_step, ) - self.ema._set_decay(decay) + self.ema.set_decay(decay) if self.ema.get_decay() < 1: self.ema.step(self.encoder if self.cfg.ema_transformer_only else self) diff --git a/examples/data2vec/models/data2vec_text.py b/examples/data2vec/models/data2vec_text.py index a69311cee6..cb3c8b383a 100644 --- a/examples/data2vec/models/data2vec_text.py +++ b/examples/data2vec/models/data2vec_text.py @@ -15,8 +15,7 @@ from omegaconf import II from fairseq.dataclass import FairseqDataclass -from fairseq.dataclass.configs import EMAConfig -from fairseq.models.ema import EMA +from fairseq.modules import EMAModule, EMAModuleConfig from fairseq.models import ( FairseqEncoder, FairseqEncoderModel, @@ -324,7 +323,7 @@ def build_lm_head(self, embed_dim, output_dim, activation_fn, weight): return RobertaLMHead(embed_dim, output_dim, activation_fn, weight) def make_ema_teacher(self): - ema_config = EMAConfig( + ema_config = EMAModuleConfig( ema_decay=self.cfg.ema_decay, ema_fp32=True, ) @@ -344,7 +343,7 @@ def make_ema_teacher(self): for k, _ in self.sentence_encoder.layer_norm.named_parameters(): skip_keys.add(f"layernorm_embedding.{k}") - self.ema = EMA( + self.ema = EMAModule( self.sentence_encoder, ema_config, skip_keys=skip_keys, @@ -367,7 +366,7 @@ def set_num_updates(self, num_updates): num_updates, self.cfg.ema_anneal_end_step, ) - self.ema._set_decay(decay) + self.ema.set_decay(decay) if self.ema.get_decay() < 1: self.ema.step(self.sentence_encoder) diff --git a/fairseq/models/ema/ema.py b/fairseq/models/ema/ema.py index dcc19d85cf..472d5d5f17 100644 --- a/fairseq/models/ema/ema.py +++ b/fairseq/models/ema/ema.py @@ -16,6 +16,9 @@ when used for inference or further fine-tuning. EMA class has a reverse function to load the EMA params into a model and use it like a regular model. + +This implementation is used for trainer-level ema tracking. For EMA tracking +inside the model, please use fairseq/modules/ema_module.py instead. """ import copy diff --git a/fairseq/modules/__init__.py b/fairseq/modules/__init__.py index 085769c4fd..8ad7f647d6 100644 --- a/fairseq/modules/__init__.py +++ b/fairseq/modules/__init__.py @@ -14,6 +14,7 @@ from .downsampled_multihead_attention import DownsampledMultiHeadAttention from .dynamic_convolution import DynamicConv, DynamicConv1dTBC from .dynamic_crf_layer import DynamicCRF +from .ema_module import EMAModuleConfig, EMAModule from .fairseq_dropout import FairseqDropout from .fp32_batch_norm import Fp32BatchNorm from .fp32_group_norm import Fp32GroupNorm @@ -62,6 +63,8 @@ "DynamicConv1dTBC", "DynamicConv", "DynamicCRF", + "EMAModule", + "EMAModuleConfig", "FairseqDropout", "Fp32BatchNorm", "Fp32GroupNorm", diff --git a/fairseq/modules/ema_module.py b/fairseq/modules/ema_module.py new file mode 100644 index 0000000000..77c21f0ab2 --- /dev/null +++ b/fairseq/modules/ema_module.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 + +""" +Used for EMA tracking a given pytorch module. The user is responsible for calling step() +and setting the appropriate decay +""" + +import copy +from dataclasses import dataclass, field +import logging + +import torch + +from fairseq.dataclass import FairseqDataclass + + +@dataclass +class EMAModuleConfig(FairseqDataclass): + ema_decay: float = field( + default=0.9999, metadata={"help": "decay for exponential moving average model"} + ) + ema_fp32: bool = field( + default=False, + metadata={"help": "If true, store EMA model in fp32 even if model is in fp16"}, + ) + + +class EMAModule: + """Exponential Moving Average of Fairseq Models""" + + def __init__(self, model, config: EMAModuleConfig, device=None, skip_keys=None): + """ + @param model model to initialize the EMA with + @param config EMAConfig object with configuration like + ema_decay, ema_update_freq, ema_fp32 + @param device If provided, copy EMA to this device (e.g. gpu). + Otherwise EMA is in the same device as the model. + """ + + self.decay = config.ema_decay + self.model = copy.deepcopy(model) + self.model.requires_grad_(False) + self.config = config + self.skip_keys = skip_keys or set() + self.fp32_params = {} + + if device is not None: + logging.info(f"Copying EMA model to device {device}") + self.model = self.model.to(device=device) + + if self.config.ema_fp32: + self.build_fp32_params() + + self.update_freq_counter = 0 + + def build_fp32_params(self, state_dict=None): + """ + Store a copy of the EMA params in fp32. + If state dict is passed, the EMA params is copied from + the provided state dict. Otherwise, it is copied from the + current EMA model parameters. + """ + if not self.config.ema_fp32: + raise RuntimeError( + "build_fp32_params should not be called if ema_fp32=False. " + "Use ema_fp32=True if this is really intended." + ) + + if state_dict is None: + state_dict = self.model.state_dict() + + def _to_float(t): + return t.float() if torch.is_floating_point(t) else t + + for param_key in state_dict: + if param_key in self.fp32_params: + self.fp32_params[param_key].copy_(state_dict[param_key]) + else: + self.fp32_params[param_key] = _to_float(state_dict[param_key]) + + def restore(self, state_dict, build_fp32_params=False): + """Load data from a model spec into EMA model""" + self.model.load_state_dict(state_dict, strict=False) + if build_fp32_params: + self.build_fp32_params(state_dict) + + def set_decay(self, decay): + self.decay = decay + + def get_decay(self): + return self.decay + + def _step_internal(self, new_model): + """One update of the EMA model based on new model weights""" + decay = self.decay + + ema_state_dict = {} + ema_params = ( + self.fp32_params if self.config.ema_fp32 else self.model.state_dict() + ) + for key, param in new_model.state_dict().items(): + if isinstance(param, dict): + continue + try: + ema_param = ema_params[key] + except KeyError: + ema_param = ( + param.float().clone() if param.ndim == 1 else copy.deepcopy(param) + ) + + if param.shape != ema_param.shape: + raise ValueError( + "incompatible tensor shapes between model param and ema param" + + "{} vs. {}".format(param.shape, ema_param.shape) + ) + + if "version" in key: + # Do not decay a model.version pytorch param + continue + + if key in self.skip_keys: + ema_param = param.to(dtype=ema_param.dtype).clone() + ema_params[key].copy_(ema_param) + else: + ema_param.mul_(decay) + ema_param.add_(param.to(dtype=ema_param.dtype), alpha=1 - decay) + ema_state_dict[key] = ema_param + self.restore(ema_state_dict, build_fp32_params=False) + + def step(self, new_model): + self._step_internal(new_model) + + def reverse(self, model): + """ + Load the model parameters from EMA model. + Useful for inference or fine-tuning from the EMA model. + """ + d = self.model.state_dict() + if "_ema" in d: + del d["_ema"] + + model.load_state_dict(d, strict=False) + return model From 8b02f00e8adaac5c86f0d333474e30cfd138ce2e Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Wed, 9 Feb 2022 10:04:23 -0800 Subject: [PATCH 567/774] fix s2s test - disable multitasking by setting multitask_config_yaml to None (#3059) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3059 Reviewed By: kahne Differential Revision: D34083178 Pulled By: sravyapopuri388 fbshipit-source-id: a33af1696570be4826973b19fe34177bcf851e06 --- tests/speech/test_s2s_transformer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/speech/test_s2s_transformer.py b/tests/speech/test_s2s_transformer.py index a4e71e246d..180f46307c 100644 --- a/tests/speech/test_s2s_transformer.py +++ b/tests/speech/test_s2s_transformer.py @@ -19,7 +19,8 @@ def setUp(self): "dev_shuf200.tsv", "src_feat.zip", "config_specaug_lb.yaml", - "config_letter_enc_unigram_dec.yaml", + "vocoder", + "vocoder_config.json", ], ) @@ -30,10 +31,13 @@ def test_s2s_transformer_checkpoint(self): dataset="dev_shuf200", arg_overrides={ "config_yaml": "config_specaug_lb.yaml", + "multitask_config_yaml": None, "target_is_code": True, "target_code_size": 100, + "eval_inference": False, }, score_type="bleu", + strict=False, ) def postprocess_tokens(self, task, target, hypo_tokens): From 5551a1995bea28e47b388dc21fe683efee2d53f6 Mon Sep 17 00:00:00 2001 From: Alban Desmaison <albandes@fb.com> Date: Wed, 9 Feb 2022 10:46:22 -0800 Subject: [PATCH 568/774] Change ParameterList and ParameterDict to be able to contain any kind of objects (#70499) Summary: The only difference with plain list/dict now is that nn.Parameters are handled specially and registered as parameters properly. test_nn and parametrization works locally. Will see in CI if DP is fixed as well. Tentative fix for https://github.com/pytorch/pytorch/issues/36035 Pull Request resolved: https://github.com/pytorch/pytorch/pull/70499 Reviewed By: jbschlosser, alexeib Differential Revision: D34005332 Pulled By: albanD fbshipit-source-id: 7e76b0873d0fec345cb537e2a6ecba0258e662b9 --- examples/truncated_bptt/transformer_xl_model.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/examples/truncated_bptt/transformer_xl_model.py b/examples/truncated_bptt/transformer_xl_model.py index a6c8b25a07..58c0f6ad8a 100644 --- a/examples/truncated_bptt/transformer_xl_model.py +++ b/examples/truncated_bptt/transformer_xl_model.py @@ -86,18 +86,6 @@ def __init__(self, cfg, task): logger.info(config) self.model = TransfoXLLMHeadModel(config) - # Workaround a bug in huggingface's ``ProjectedAdaptiveLogSoftmax`` - # which adds ``None`` values to an ``nn.ParameterList``, which is not - # supported in PyTorch. Instead we can replace this with an - # ``nn.ModuleList``, which does support ``None`` values. - try: - if all(p is None for p in self.model.crit.out_projs._parameters.values()): - self.model.crit.out_projs = torch.nn.ModuleList( - [None] * len(self.model.crit.out_projs._parameters) - ) - except Exception: - pass - if cfg.checkpoint_activations or cfg.offload_activations: for i in range(len(self.model.transformer.layers)): self.model.transformer.layers[i] = checkpoint_wrapper( From 5f2515e676985efd2944f6c87fe1b086cb94bdee Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 10 Feb 2022 12:17:00 -0800 Subject: [PATCH 569/774] Fix failing test (#3065) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3065 Reviewed By: Mortimerp9 Differential Revision: D34144674 Pulled By: dianaml0 fbshipit-source-id: 842b0d29c9c85d4b56b640f2823fcb4e3f912f98 --- tests/test_lm_context_window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_lm_context_window.py b/tests/test_lm_context_window.py index f8d7e7203c..165e04ac3a 100644 --- a/tests/test_lm_context_window.py +++ b/tests/test_lm_context_window.py @@ -34,6 +34,7 @@ def test_eval_dataloader(self): dataset=dataset, batch_size=1, context_window=2, + num_workers=0, ) batch = next(eval_dataloader) From cfc4d8475c04d8db74bb4a4e31c7342ba2c90522 Mon Sep 17 00:00:00 2001 From: Victoria Lin <victorialin@fb.com> Date: Tue, 15 Feb 2022 21:29:56 -0800 Subject: [PATCH 570/774] add missing transformer arch and update PadDataset (#4212) Summary: Fix issue https://github.com/pytorch/fairseq/issues/4209 #4210 Pull Request resolved: https://github.com/pytorch/fairseq/pull/4212 Reviewed By: sshleifer Differential Revision: D34208212 Pulled By: todpole3 fbshipit-source-id: 64a4777b8721b692ad339df0fc0495d823d58c07 --- fairseq/data/pad_dataset.py | 7 +++++-- fairseq/models/transformer_lm.py | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/fairseq/data/pad_dataset.py b/fairseq/data/pad_dataset.py index 8075bba6a9..b512d370f9 100644 --- a/fairseq/data/pad_dataset.py +++ b/fairseq/data/pad_dataset.py @@ -9,13 +9,16 @@ class PadDataset(BaseWrapperDataset): - def __init__(self, dataset, pad_idx, left_pad): + def __init__(self, dataset, pad_idx, left_pad, pad_length=None): super().__init__(dataset) self.pad_idx = pad_idx self.left_pad = left_pad + self.pad_length = pad_length def collater(self, samples): - return data_utils.collate_tokens(samples, self.pad_idx, left_pad=self.left_pad) + return data_utils.collate_tokens( + samples, self.pad_idx, left_pad=self.left_pad, pad_to_length=self.pad_length + ) class LeftPadDataset(PadDataset): diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index f029cf05de..5a23888b1e 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -487,6 +487,30 @@ def transformer_lm_gpt2_big(args): base_lm_architecture(args) +@register_model_architecture("transformer_lm", "transformer_lm_gpt2_big_wide") +def transformer_lm_gpt2_big_wide(args): + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 2048) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 8192) + args.decoder_layers = getattr(args, "decoder_layers", 24) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", 0.1) + args.activation_fn = getattr(args, "activation_fn", "gelu") + base_lm_architecture(args) + + +@register_model_architecture("transformer_lm", "transformer_lm_gpt2_bigger") +def transformer_lm_gpt2_bigger(args): + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 2048) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 8192) + args.decoder_layers = getattr(args, "decoder_layers", 48) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 32) + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", 0.1) + args.activation_fn = getattr(args, "activation_fn", "gelu") + base_lm_architecture(args) + + def base_gpt3_architecture(args): args.decoder_input_dim = args.decoder_embed_dim args.decoder_output_dim = args.decoder_embed_dim From 67eaecd2fc233eb9975ba6bd439cff75383fbd55 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Wed, 16 Feb 2022 09:31:33 -0800 Subject: [PATCH 571/774] Add regression test for SimulConvTransformerModel (#3031) Summary: Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3031 Reviewed By: kahne Differential Revision: D34018108 Pulled By: sravyapopuri388 fbshipit-source-id: 4db96653658a998b15c0cdbc2e588198d951a420 --- .../test_convtransformer_simul_trans.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/speech/test_convtransformer_simul_trans.py diff --git a/tests/speech/test_convtransformer_simul_trans.py b/tests/speech/test_convtransformer_simul_trans.py new file mode 100644 index 0000000000..6090f37f65 --- /dev/null +++ b/tests/speech/test_convtransformer_simul_trans.py @@ -0,0 +1,30 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from tests.speech import TestFairseqSpeech + +S3_BASE_URL = "https://dl.fbaipublicfiles.com/fairseq/" + + +class TestConvtransformerSimulTrans(TestFairseqSpeech): + def setUp(self): + self._set_up( + "simul", + "speech_tests/simul", + ["config_gcmvn_specaug.yaml", "dict.txt", "dev.tsv"], + ) + + def test_waitk_checkpoint(self): + """Only test model loading since fairseq currently doesn't support inference of simultaneous models""" + _, _, _, _ = self.download_and_load_checkpoint( + "checkpoint_best.pt", + arg_overrides={"config_yaml": "config_gcmvn_specaug.yaml"}, + ) + return + + +if __name__ == "__main__": + unittest.main() From 5b87224417553f411db51a908a664c1d861696fc Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Thu, 17 Feb 2022 10:33:35 -0800 Subject: [PATCH 572/774] Open source conformer models and update documentation Summary: TSIA Reviewed By: kahne Differential Revision: D34115270 fbshipit-source-id: aa5a226dae4539afc0aed9b7d43ba1fa2e40ae70 --- .../config/pretraining/wav2vec2_conformer_base_librispeech.yaml | 0 .../config/pretraining/wav2vec2_conformer_large_librivox.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/wav2vec/config/pretraining/wav2vec2_conformer_base_librispeech.yaml create mode 100644 examples/wav2vec/config/pretraining/wav2vec2_conformer_large_librivox.yaml diff --git a/examples/wav2vec/config/pretraining/wav2vec2_conformer_base_librispeech.yaml b/examples/wav2vec/config/pretraining/wav2vec2_conformer_base_librispeech.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/wav2vec/config/pretraining/wav2vec2_conformer_large_librivox.yaml b/examples/wav2vec/config/pretraining/wav2vec2_conformer_large_librivox.yaml new file mode 100644 index 0000000000..e69de29bb2 From 420136acd2a57de22e62f13930aa23e086bcbbf8 Mon Sep 17 00:00:00 2001 From: spopuri <fb_ust@ip-0A020404.jkgpqq2blx3ejatzdu0vkghyde.xx.internal.cloudapp.net> Date: Tue, 22 Feb 2022 11:17:26 -0800 Subject: [PATCH 573/774] fix failing convtransformer test (#3107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3107 Reviewed By: cndn Differential Revision: D34354339 Pulled By: sravyapopuri388 fbshipit-source-id: 50888706123d246c13d2cbb22d0e043740ff6bf5 --- tests/speech/test_convtransformer_simul_trans.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/speech/test_convtransformer_simul_trans.py b/tests/speech/test_convtransformer_simul_trans.py index 6090f37f65..0562404f52 100644 --- a/tests/speech/test_convtransformer_simul_trans.py +++ b/tests/speech/test_convtransformer_simul_trans.py @@ -21,7 +21,10 @@ def test_waitk_checkpoint(self): """Only test model loading since fairseq currently doesn't support inference of simultaneous models""" _, _, _, _ = self.download_and_load_checkpoint( "checkpoint_best.pt", - arg_overrides={"config_yaml": "config_gcmvn_specaug.yaml"}, + arg_overrides={ + "config_yaml": "config_gcmvn_specaug.yaml", + "load_pretrained_encoder_from": None, + }, ) return From 0c0ef06780b121b2b50b271852bde88fc998936e Mon Sep 17 00:00:00 2001 From: eugene-kharitonov <eugene.kharitonov@gmail.com> Date: Tue, 22 Feb 2022 23:47:19 -0800 Subject: [PATCH 574/774] Prosody-aware Generative Spoken Language Modelling (#3063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/fairinternal/fairseq-py/pull/3063 Reviewed By: eugene-kharitonov Differential Revision: D34323605 Pulled By: wnhsu fbshipit-source-id: 9dc779a6c399cda710863596e0880b9277ff2919 --- examples/textless_nlp/pgslm/README.md | 318 ++++++++ examples/textless_nlp/pgslm/data_utils.py | 107 +++ examples/textless_nlp/pgslm/eval/__init__.py | 4 + .../textless_nlp/pgslm/eval/cont_metrics.py | 730 ++++++++++++++++++ .../textless_nlp/pgslm/generate_waveform.py | 120 +++ .../textless_nlp/pgslm/inference_dataset.py | 103 +++ examples/textless_nlp/pgslm/naive_decoder.py | 40 + .../textless_nlp/pgslm/prepare_dataset.py | 143 ++++ examples/textless_nlp/pgslm/preprocess_f0.py | 65 ++ examples/textless_nlp/pgslm/quantize_f0.py | 94 +++ .../textless_nlp/pgslm/sample/__init__.py | 4 + examples/textless_nlp/pgslm/sample/sample.py | 612 +++++++++++++++ .../pgslm/scripts/join_units_manifest.py | 48 ++ .../pgslm/scripts/prepare_data.sh | 57 ++ .../pgslm/scripts/prepare_f0_quantization.sh | 27 + .../textless_nlp/pgslm/truncated_laplace.py | 29 + fairseq/criterions/speech_ulm_criterion.py | 126 +++ fairseq/data/codedataset.py | 576 ++++++++++++++ fairseq/models/text_to_speech/codehifigan.py | 20 +- fairseq/models/text_to_speech/vocoder.py | 8 +- fairseq/models/transformer_ulm.py | 408 ++++++++++ fairseq/tasks/speech_ulm_task.py | 224 ++++++ 22 files changed, 3861 insertions(+), 2 deletions(-) create mode 100644 examples/textless_nlp/pgslm/README.md create mode 100644 examples/textless_nlp/pgslm/data_utils.py create mode 100644 examples/textless_nlp/pgslm/eval/__init__.py create mode 100644 examples/textless_nlp/pgslm/eval/cont_metrics.py create mode 100644 examples/textless_nlp/pgslm/generate_waveform.py create mode 100644 examples/textless_nlp/pgslm/inference_dataset.py create mode 100644 examples/textless_nlp/pgslm/naive_decoder.py create mode 100644 examples/textless_nlp/pgslm/prepare_dataset.py create mode 100644 examples/textless_nlp/pgslm/preprocess_f0.py create mode 100644 examples/textless_nlp/pgslm/quantize_f0.py create mode 100644 examples/textless_nlp/pgslm/sample/__init__.py create mode 100644 examples/textless_nlp/pgslm/sample/sample.py create mode 100644 examples/textless_nlp/pgslm/scripts/join_units_manifest.py create mode 100644 examples/textless_nlp/pgslm/scripts/prepare_data.sh create mode 100644 examples/textless_nlp/pgslm/scripts/prepare_f0_quantization.sh create mode 100644 examples/textless_nlp/pgslm/truncated_laplace.py create mode 100644 fairseq/criterions/speech_ulm_criterion.py create mode 100644 fairseq/data/codedataset.py create mode 100644 fairseq/models/transformer_ulm.py create mode 100644 fairseq/tasks/speech_ulm_task.py diff --git a/examples/textless_nlp/pgslm/README.md b/examples/textless_nlp/pgslm/README.md new file mode 100644 index 0000000000..596467fe82 --- /dev/null +++ b/examples/textless_nlp/pgslm/README.md @@ -0,0 +1,318 @@ +# Text-Free Prosody-Aware Generative Spoken Language Modeling + +This folder contains code and recipes to reproduce results reported in a paper _Text-Free Prosody-Aware Generative Spoken Language Modeling_, +Eugene Kharitonov*, Ann Lee*, Adam Polyak, Yossi Adi, Jade Copet, Kushal Lakhotia, Tu-Anh Nguyen, Morgane Rivière, Abdelrahman Mohamed, Emmanuel Dupoux, Wei-Ning Hsu, 2021. arxiv/2109.03264 [[arxiv]](https://arxiv.org/abs/2109.03264). + +`*` denotes equal contribution. + +You can find demo samples [[here]](https://speechbot.github.io/pgslm/index.html). + +<details> + <summary>If you find this code useful, please consider citing our work using this bibtex </summary> + +``` + @misc{Kharitonov2021, + title={Text-Free Prosody-Aware Generative Spoken Language Modeling}, + author={Eugene Kharitonov and Ann Lee and Adam Polyak and Yossi Adi and Jade Copet and Kushal Lakhotia and Tu-Anh Nguyen and Morgane Rivière and Abdelrahman Mohamed and Emmanuel Dupoux and Wei-Ning Hsu}, + year={2021}, + eprint={2109.03264}, + archivePrefix={arXiv}, + primaryClass={cs.CL} +} +``` +</details> + + +## Additional requirements +Three packages are required in addition to fairseq, they are installable with pip: +```bash +pip install AMFM-decompy SoundFile scipy sklearn torchaudio npy-append-array +``` + +## Data preprocessing + +### Prepare unit pseudo-text transcriptions of the audio +To get unit trascripts of the speech data we rely on the preprocessing steps of [GSLM](https://github.com/pytorch/fairseq/tree/main/examples/textless_nlp/gslm/speech2unit/) work. + +Firstly, we will need to prepare manifest files for the dataset we want to preprocess +``` +mkdir manifests/ +python examples/wav2vec/wav2vec_manifest.py --valid-percent=0.0 $DATA_PATH --dest=manifests/train/ +``` +Next, we need a pre-trained HuBERT-base-ls960 model [[download]](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) and a corresponding kmeans-100 quantizer [[download]](https://dl.fbaipublicfiles.com/textless_nlp/gslm/hubert/km100/km.bin). Having those we can quantize the dataset: +``` +python examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py \ + --feature_type hubert \ + --kmeans_model_path km.bin \ + --acoustic_model_path hubert_base_ls960.pt \ + --layer 6 \ + --manifest_path manifests/train/train.tsv \ + --out_quantized_file_path manifests/train/units +``` + +Finally, by running +``` +python examples/textless_nlp/pgslm/scripts/join_units_manifest.py --manifest=manifests/train/train.tsv --units=manifests/train/units --output=train.txt +``` +We will get the training data description `train.txt` in the format that pGSLM expects. The above steps have to be repeated for +dev/test sets. Importantly, we rely on an assumption that the directories are structured as in LibriSpeech, i.e. the file paths follow the +`<spk_id>/<session_id>/<sample_id>.wav` format. + +### Preprocess data for pGSLM +The very first step is to obtain the F0 quantization bins. +Assume the vocoder training manifest is `vocoder_train.txt` (in pGSLM data format prepared with the same process above). +We prepare the quantized F0 from the vocoder training data by running +```sh +bash examples/textless_nlp/pgslm/scripts/prepare_f0_quantization.sh \ + vocoder_train.txt <sample_rate> 32 <preprocessed_dir> <output_prefix> # we use 32 bins in the paper +``` +- `<sample_rate>`: sampling rate of the audio files in the manifest +- `<preprocessed_dir>`: where to output the output files +- `<output_prefix>`: prefix of the output files + +The script will generate +- `<output_prefix>.f0_stat.pt`: the speaker-level F0 statistics, which can be used in vocoder training +- `<output_prefix>_mean_norm_log_f0_bin.th`: the quantized F0, which should be used in `prepare_data.sh` below + +**Note:** See "Pre-trained models" for the pre-computed speaker-level F0 statistics and quantized F0 bins. We suggest using the pre-computed statistics for the data preparation below in order to take advantage of the pre-trained vocoder for waveform generation. + +Next prepare the pGSLM data. +Assume train/valid/test manifests are `{train,valid,test}.txt`. +Here is an example of how to preprocess data: + +```sh +bash examples/textless_nlp/pgslm/scripts/prepare_data.sh \ + train.txt valid.txt test.txt <n_unit> <hop_size> <sample_rate> \ + <preprocessed_dir>/<output_prefix>_mean_norm_log_f0_bin.th <preprocessed_dir> +``` +- `<n_unit>`: discrete unit vocabulary size (we used a kmeans quantizer with the number of units equal to 100 in the example above) +- `<hop_size>`: downsampling rate relative to the waveform (e.g., 320 for HuBERT units) +- `<sample_rate>`: sampling rate of the audio files in the manifest +- `<preprocessed_dir>`: where to output the preprocessed files + +This will create the dataset json config used for the next section at +`<preprocessed_dir>/data_config.json`. + +Note that the example script uses only one thread to compute F0, which can take +_very long_ for preprocessing large datasets. It is suggested to distribute +jobs over multiple nodes/processes with `--nshards=x` and `--rank=z` (where z is +in [1, x]) in `preprocess_f0.py`, and set `--nshards_list=x` in +`prepare_data.py` correspondingly to collect sharded F0 data. + +Now, everything is ready for training a model. + +## Training Multi-Stream Transformer Unit Language Model (MS-TLM) + +Below is an example command that trains Multi-Stream Transformer Language Model (MS-TLM) on a prepared dataset: +```bash +DATASET=data_config.json + +fairseq-train $DATASET \ + --task=speech_unit_modeling \ + --arch="transformer_ulm_tiny" \ + --criterion=speech_unit_lm_criterion \ + --share-decoder-input-output-embed \ + --dropout=0.1 \ + --attention-dropout=0.1 \ + --optimizer="adam" \ + --adam-betas="(0.9, 0.98)" \ + --clip-norm=1.0 \ + --lr=0.0005 \ + --lr-scheduler="inverse_sqrt" \ + --warmup-updates=4000 \ + --warmup-init-lr=1e-07 \ + --tokens-per-sample=3072 \ + --max-tokens=3072 \ + --update-freq=4 \ + --max-epoch=70 \ + --num-workers=0 \ + --skip-invalid-size-inputs-valid-test \ + --loss-weights="1.0;0.5;0.0" \ + --ignore-f0-input \ + --checkpoint-activations \ + --fp16 \ + --max-target-positions=4096 \ + --stream-shifts="1,1" \ + --log-f0 --normalize-f0-mean --interpolate-f0 \ + --ignore-unused-valid-subsets \ + --discrete-duration --discrete-f0 +``` + +Some of the important parameters that are specific to MS-TLM: + * `arch`: specifies the Transformer architecture used. Supported options are: + * `transformer_ulm_tiny` - a tiny model that can be used for debugging; it has 2 layers, 1 attention head, FFN and embedding dimensions of 64, + * `transformer_ulm` - a base model with 6 layers, 8 heads, embedding dimension 512, and FFN dimensionality of 2048, + * `transformer_ulm_big` - the largest model we experiment with in the paper: 12-layer/16 heads, 1024/4096 embedding and FFN dimensions; + * `loss-weights`: this parameter sets importance weights (must be non-negative) for the components of the loss that correspond to unit, duration, and F0 streams. To turn off a component of the loss, its weight has to be set to 0. For instance, to predict only unit stream the parameter should be set to "1;0;0"; + * `stream-shifts`: specifies relative shifts of the two prosodic streams w.r.t. the unit stream (duration and F0, respectively). No shift corresponds to "0,0"; + * `ignore-duration-input`/`ignore-f0-input`: setting these flags would zero-out correpsonding input streams; + * `max-token-duration`: duration values would be max-capped by the specified value; + * `discrete-duration`/`discrete-f0`: whether duration and F0 streams should be quantized; + * `log_f0`, `normalize-f0-mean`, `normalize-f0-std`, `interpolate-f0`: configure how F0 stream is treated. `log_f0` sets up modelling in the log-space, `normalize-f0-mean`/`normalize-f0-std` control per-speaker normalization, and `interpolate-f0` enables F0 interpolation for unvoiced regions where F0 was set to 0, + * `mask-dur-prob`, `mask-f0-prob`, `mask-dur-seg-prob`, `mask-f0-seg-prob`, `mask-unit-seg-prob`, `mask-unit-seg-leng`: this family of parameters sets the probababilities of masking individual steps and spans on each stream as well as lengths of the maked spans. + + +## Pre-trained models +### MS-TLM +Below you can find checkpoints for four best-performing models from the paper (IDs 9..12 in Table 1). These models are trained on Hubert-100 transcripts of the LibriLight-6K dataset. They have the prosody streams shifted by 1 w.r.t. the unit stream. All models predict all three streams (units, duration, and F0), but two +of them only have unit steam in their input. + +| | Continuous prosody | Quantized prosody | +|-------------------|--------------------|-------------------| +| No prosody input | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/ulm_checkpoints/continuous_no_prosody_shift_1_1.pt) | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/ulm_checkpoints/discrete_no_prosody_shift_1_1.pt) | +| Has prosody input | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/ulm_checkpoints/continuous_prosody_shift_1_1.pt) | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/ulm_checkpoints/discrete_prosody_shift_1_1.pt)| + +The optimal per-stream sampling temperatures/scaling parameters that we have identified for these models, in the (`T-token, T-duration, T-f0`) format: + +| | Continuous prosody | Quantized prosody | +|-------------------|--------------------|-------------------| +| No prosody input | 0.7, 0.125, 0.0003125| 0.7, 0.25, 0.5 | +| Has prosody input | 0.7, 0.125, 0.00125 | 0.7, 0.25, 0.7 | + +## Vocoder +| Units | Prosody | F0 stats | Checkpoint | Config | +|-------------------|---------|--------------|------------|--------| +| HuBERT-base-ls960, kmeans-100 | [[Quantized 32 bins]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/mean_norm_log_f0_seg_bin.th) | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/f0_stats.pt) | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/naive_quant_32_norm_log_seg_hubert/checkpoint.pt) | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/naive_quant_32_norm_log_seg_hubert/config.json) | +| HuBERT-base-ls960, kmeans-100 | Continuous | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/f0_stats.pt) | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/mean_norm_log_f0_hubert/checkpoint.pt) | [[download]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/mean_norm_log_f0_hubert/config.json) | + + +## Evaluating a trained model +Evaluation is done with the `eval/cont_metrics.py` scripts. As described in the paper, there are several metrics used. + +**Teacher-forced metrics** +```bash +SET=valid +CHECKPOINT_PATH=discrete_prosody_shift_1_1.pt +DATA=data_config.json + +python examples/textless_nlp/pgslm/eval/cont_metrics.py $DATA \ + --metric=teacher_force_everything \ + --path=$CHECKPOINT_PATH \ + --batch-size=16 \ + --fp16 \ + --seed=111 \ + --eval-subset=$SET \ + --f0-discretization-bounds=mean_norm_log_f0_seg_bin.th --dequantize-prosody +``` +(Using this command, our provided `discrete_prosody_shift_1_1.pt` checkpoint should produce `{'token_loss': 1.408..., 'duration_loss': 0.5424..., 'f0_loss': 0.0474...}` on LibriSpeech dev-clean). + +The parameters `--f0-discretization-bounds=mean_norm_log_f0_seg_bin.th --dequantize-prosody` are specific for quantized-prosody models. They signal that the prosody streams must be decoded into the continuous domain before calculating correlation. It is the same `*_mean_norm_log_f0_bin.th` file as we prepared before. +The `mean_norm_log_f0_seg_bin.th` file we used with the pre-trained models can be downloaded [[here]](https://dl.fbaipublicfiles.com/textless_nlp/pgslm/vocoder/blizzard2013/mean_norm_log_f0_seg_bin.th). + + +**Consistency (aka Correlation) metrics** + +The following command estimates correlation between mean values of the F0 stream in the prompt and in the generated continuation (unit and duration steams are fixed). + +```bash +T_F0=0.7 +EXPLOSION=20 +SET=test +CHECKPOINT_PATH=discrete_prosody_shift_1_1.pt +DATA=data_config.json + +python examples/textless_nlp/pgslm/eval/cont_metrics.py $DATA \ + --prefix-length=150 \ + --metric=correlation \ + --path=$CHECKPOINT_PATH \ + --batch-size=16 \ + --fp16 \ + --seed=111 \ + --teacher-force-tokens \ + --teacher-force-duration \ + --min-length=300 \ + --batch-explosion-rate=$EXPLOSION \ + --T-f0=$T_F0 \ + --eval-subset=$SET \ + --f0-discretization-bounds=mean_norm_log_f0_seg_bin.th \ + --dequantize-prosody --n-workers=8 +``` +(Using this command, our provided `discrete_prosody_shift_1_1.pt` checkpoint should produce `{...'F0 corr': 0.315 ..}` on LibriSpeech test-clean). + + * By using flags `--teacher-force-tokens, --teacher-force-duration, --teacher-force-f0` one can calculate correlations along each stream while having other two streams fixed to ground-truth values (or freeze all three streams to get ground-truth correlation values); + * The parameters `T-f0`, `T-duration`, and `T-token` specify per-stream temperatures and, in the case of continuous-valued prosody, scaling parameter of the corresponding Laplace distribution (setting a temperature to 0 will enforce greedy sampling); + * `min-length` filters out sequences that are shorter then 300 duration units (i.e. 6s in the case of Hubert units); + * `prefix-length` specifies that we want to use first 150 duration units are prompt (i.e. 3s in the case of Hubert units) + + +**Correctness (aka Continuation) and Expressiveness (aka Std) metrics** + +By running the following command, we can get minMAE and Std for the log-F0 stream for the model with quantized prosody. +```bash +DATA=data_config.json +EXPLOSION=20 +SET=test +CHECKPOINT_PATH=discrete_prosody_shift_1_1.pt +T_F0=0.7 + +python examples/textless_nlp/pgslm/eval/cont_metrics.py $DATA \ + --prefix-length=150 \ + --metric=continuation \ + --path=$CHECKPOINT_PATH \ + --batch-size=16 \ + --fp16 \ + --seed=111 \ + --batch-explosion-rate=$EXPLOSION \ + --teacher-force-tokens \ + --teacher-force-duration \ + --T-f0=$T_F0 \ + --eval-subset=$SET \ + --f0-discretization-bounds=mean_norm_log_f0_seg_bin.th --dequantize-prosody +``` +(Using this command, our provided `discrete_prosody_shift_1_1.pt` checkpoint should produce `{...'F0 MAE': 0.0772, 'F0 Std': 0.1489...}` on LibriSpeech test-clean). + +Again, by setting `--teacher-force-tokens, --teacher-force-duration, --teacher-force-f0` we can calculate Token BLEU for the token stream (when `--teacher-force-duration` & `--teacher-force-f0` are on) and per-stream min MAE for each prosody stream individually. + +Finally, `cont_metrics.py` allows to specify the number of workers (e.g., `n-workers=8`) which allows to speed up the computation by spreading multiple worker processes +over the available GPUs. + +**Cont Word BLEU** + +We used the code and the evaluation protocol of [(Lakhotia et al., 2021)](https://arxiv.org/abs/2102.01192). + +## Sampling from a trained model + +To get (prompted or not) samples from a trained model it is enough to run `sample.py`: +```bash +CHECKPOINT_PATH=checkpoints/checkpoint_best.pt +DATASET=examples/textless_nlp/pgslm/repro/dataset/data_config.json +python examples/textless_nlp/pgslm/sample/sample.py $DATASET \ + --output=$SAMPLES \ + --path=$CHECKPOINT_PATH \ + --sampling \ + --T-token=0.7 \ + --T-duration=0.25 \ + --T-f0=0.7 \ + --max-length=500 \ + --prefix-length=150 \ + --subset=valid \ + --seed=1 \ + --match-duration \ + --code-type=hubert \ + --batch-explosion-rate=2 +``` + +Some useful parameters: + * `T-token`, `T-duration`, `T-f0` specify sampling temperature for the three streams. Setting a temperature to `0` switches sample to the greedy (argmax) one; + * `prefix-length`: length of the prompt, measured in timesteps (e.g. for Hubert (CPC) each timestep is 20 (10) ms); + * `subset`: which subset of the dataset to use as prompts (can be `train`, `valid`, `test`); + * `teacher-force-tokens`, `teacher-force-duration`, `teacher-force-f0`: if set, at each autoregressive step, ground-truth values replace the produced one; + * `short-curcuit`: replace sampling by ground-truth inputs; + * `match-duration`: forces the produced sample to have the same duration (in time), as the entire sequence (beyond the prompt if there is any); + * `batch-explosion-rate`: number of samples per prompt; + * `f0-discretization-bounds`: path to a file with quantization boundaries. If it is set, F0 values are de-quantized back to the continuous domain + (the model must be a quanized one); + * `max-length` sets the maximal number of segment steps to be produced. + +Note that `sample.py` automatically uses all available GPUs, to avoid that please use environment variable `CUDA_VISIBLE_DEVICES`. + +## Vocoding samples +To generate audios for output from `sample.py` (`$IN_FILE`): +```bash +python examples/textless_nlp/pgslm/generate_waveform.py \ + --in-file=$IN_FILE \ + --vocoder=$VODOER \ + --vocoder-cfg=$VOCODER_CFG \ + --results-path=$RESULTS_PATH +``` +See "Pre-trained model" for `$VOCODER` and `VOCODER_CFG`. diff --git a/examples/textless_nlp/pgslm/data_utils.py b/examples/textless_nlp/pgslm/data_utils.py new file mode 100644 index 0000000000..2033697b37 --- /dev/null +++ b/examples/textless_nlp/pgslm/data_utils.py @@ -0,0 +1,107 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import torch + +from tqdm import tqdm + + +class Stat: + def __init__(self, keep_raw=False): + self.x = 0.0 + self.x2 = 0.0 + self.z = 0.0 # z = logx + self.z2 = 0.0 + self.n = 0.0 + self.u = 0.0 + self.keep_raw = keep_raw + self.raw = [] + + def update(self, new_x): + new_z = new_x.log() + + self.x += new_x.sum() + self.x2 += (new_x**2).sum() + self.z += new_z.sum() + self.z2 += (new_z**2).sum() + self.n += len(new_x) + self.u += 1 + + if self.keep_raw: + self.raw.append(new_x) + + @property + def mean(self): + return self.x / self.n + + @property + def std(self): + return (self.x2 / self.n - self.mean**2) ** 0.5 + + @property + def mean_log(self): + return self.z / self.n + + @property + def std_log(self): + return (self.z2 / self.n - self.mean_log**2) ** 0.5 + + @property + def n_frms(self): + return self.n + + @property + def n_utts(self): + return self.u + + @property + def raw_data(self): + assert self.keep_raw, "does not support storing raw data!" + return torch.cat(self.raw) + + +class F0Stat(Stat): + def update(self, new_x): + # assume unvoiced frames are 0 and consider only voiced frames + if new_x is not None: + super().update(new_x[new_x != 0]) + + +def dump_speaker_f0_stat(speaker_to_f0_stat, out_prefix): + path = f"{out_prefix}.f0_stat.pt" + assert not os.path.exists(path) + + d = { + speaker: { + "f0_mean": speaker_to_f0_stat[speaker].mean, + "f0_std": speaker_to_f0_stat[speaker].std, + "logf0_mean": speaker_to_f0_stat[speaker].mean_log, + "logf0_std": speaker_to_f0_stat[speaker].std_log, + } + for speaker in speaker_to_f0_stat + } + torch.save(d, path) + + return d + + +def load_audio_path(path): + audio_paths = [] + with open(path) as f: + for line in f.readlines(): + sample = eval(line.strip()) + audio_paths.append(sample["audio"]) + + return audio_paths + + +def load_f0(f0_dir, nshards): + path_to_f0 = {} + for rank in tqdm(range(1, nshards + 1), desc=f"load f0"): + f0_shard_path = f"{f0_dir}/f0_{rank}_{nshards}.pt" + shard_path_to_f0 = torch.load(f0_shard_path) + path_to_f0.update(shard_path_to_f0) + return path_to_f0 diff --git a/examples/textless_nlp/pgslm/eval/__init__.py b/examples/textless_nlp/pgslm/eval/__init__.py new file mode 100644 index 0000000000..0e028c26b9 --- /dev/null +++ b/examples/textless_nlp/pgslm/eval/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/textless_nlp/pgslm/eval/cont_metrics.py b/examples/textless_nlp/pgslm/eval/cont_metrics.py new file mode 100644 index 0000000000..e98abadde3 --- /dev/null +++ b/examples/textless_nlp/pgslm/eval/cont_metrics.py @@ -0,0 +1,730 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import numpy as np +import scipy + +import torch +import torch.multiprocessing as mp +from fairseq import checkpoint_utils, options +from fairseq.data.codedataset import CodeDataset, ExpressiveCodeDataConfig +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from torch.utils.data import DataLoader, DistributedSampler +from fairseq.utils import move_to_cuda +from fairseq import utils +from fairseq.criterions.speech_ulm_criterion import nll_loss, mae_loss + +import time +from types import SimpleNamespace + +import sys, pathlib + +sys.path.append(str(pathlib.Path(__file__).parent.parent.resolve())) + +from naive_decoder import Naive_F0_Decoder +from inference_dataset import InferenceDataset, explode_batch +from sample.sample import do_sampling, TemperatureDecoder, FilterNamesDataset + +try: + from nltk.translate.bleu_score import sentence_bleu +except ImportError: + print("Please install nltk: `pip install --user -U nltk`") + raise + + +@torch.no_grad() +def teacher_force_everything( + args, dataset, model, criterion, tgt_dict, rank, world_size +): + prefix = args.prefix_length + + f0_decoder = None + if args.dequantize_prosody: + assert dataset.discrete_f0 + print("Reporting MAE for a discrete model") + f0_decoder = Naive_F0_Decoder( + args.f0_discretization_bounds, dataset.config.f0_vq_n_units + ).cuda() + + dataset = InferenceDataset( + dataset, + prefix=args.prefix_length, + only_prefix=False, + filter_short=True, + presort_by_length=True, + ) + sampler = ( + None + if world_size == 1 + else DistributedSampler( + dataset, num_replicas=world_size, rank=rank, shuffle=False + ) + ) + dataloader = DataLoader( + dataset, + args.batch_size, + shuffle=False, + collate_fn=dataset.collater, + sampler=sampler, + ) + + total_token_loss, total_duration_loss, total_f0_loss, total_tokens = ( + 0.0, + 0.0, + 0.0, + 0.0, + ) + + i = 0 + for batch in dataloader: + i += 1 + batch = move_to_cuda(batch) + output = model(**batch["net_input"]) + + tokens, durations, f0 = output["token"], output["duration"], output["f0"] + durations, f0 = durations.squeeze(), f0.squeeze() + + token_loss = nll_loss( + tokens[:, prefix - 1 :], + batch["target"][:, prefix - 1 :].contiguous(), + batch["mask"][:, prefix - 1 :].contiguous(), + reduce=True, + ) + + if args.dequantize_prosody: + durations = durations.argmax(dim=-1) + duration_loss = mae_loss( + durations[:, prefix - 1 :].contiguous().float(), + batch["dur_target"][:, prefix - 1 :].contiguous().float(), + batch["dur_mask"][:, prefix - 1 :].contiguous(), + reduce=True, + ) + else: + duration_loss = criterion.dur_loss_fn( + durations[:, prefix - 1 :].contiguous(), + batch["dur_target"][:, prefix - 1 :].contiguous(), + batch["dur_mask"][:, prefix - 1 :].contiguous(), + reduce=True, + ) + + if f0_decoder: + f0 = f0.argmax(dim=-1) + f0 = f0_decoder(f0).squeeze(-1) + + f0_target = batch["raw_f0"] + f0_loss = mae_loss( + f0[:, prefix - 1 :].contiguous(), + f0_target[:, prefix - 1 :].contiguous(), + batch["f0_mask"][:, prefix - 1 :].contiguous(), + reduce=True, + ) + else: + f0_loss = criterion.f0_loss_fn( + f0[:, prefix - 1 :].contiguous(), + batch["f0_target"][:, prefix - 1 :].contiguous(), + batch["f0_mask"][:, prefix - 1 :].contiguous(), + reduce=True, + ) + + n_tokens = (~batch["dur_mask"])[:, prefix - 1 :].sum() + + total_token_loss += token_loss.item() + total_duration_loss += duration_loss.item() + total_f0_loss += f0_loss.item() + + total_tokens += n_tokens.item() + if args.debug and i > 5: + break + + values = torch.tensor([total_token_loss, total_duration_loss, total_f0_loss]) + normalizers = torch.tensor([total_tokens for _ in range(3)]) + + return values, normalizers + + +def get_bleu(produced_tokens, target_tokens, tgt_dict): + assert target_tokens.ndim == 1 + assert produced_tokens.size(1) == target_tokens.size(0) + + # we can have padding due to shifted channels + shift = 0 + for token in reversed(target_tokens.cpu().tolist()): + if token in [tgt_dict.pad(), tgt_dict.eos()]: + shift += 1 + else: + break + target_tokens = target_tokens[:-shift] + produced_tokens = produced_tokens[:, :-shift] + + string_target = tgt_dict.string(target_tokens).split() + string_candidates = [ + tgt_dict.string(produced_tokens[i, :]).split() + for i in range(produced_tokens.size(0)) + ] + + bleu3 = sentence_bleu( + references=string_candidates, + hypothesis=string_target, + weights=(1.0 / 3, 1.0 / 3, 1.0 / 3), + ) + return bleu3 + + +@torch.no_grad() +def continuation(args, dataset, model, criterion, tgt_dict, rank, world_size): + is_discrete_duration = dataset.discrete_dur + is_discrete_f0 = dataset.discrete_f0 + + f0_decoder = None + if args.dequantize_prosody: + assert dataset.discrete_f0 + print("Reporting MAE F0 for a discrete model") + f0_decoder = Naive_F0_Decoder( + args.f0_discretization_bounds, dataset.config.f0_vq_n_units + ).cuda() + + dataset = InferenceDataset( + dataset, args.prefix_length, filter_short=True, presort_by_length=True + ) + sampler = ( + None + if world_size == 1 + else DistributedSampler( + dataset, num_replicas=world_size, rank=rank, shuffle=False + ) + ) + dataloader = DataLoader( + dataset, + batch_size=1, + shuffle=False, + collate_fn=dataset.collater, + sampler=sampler, + ) + + Ts = args.T_token, args.T_duration, args.T_f0 + decoder = TemperatureDecoder( + Ts, discrete_dur=is_discrete_duration, discrete_f0=is_discrete_f0 + ) + + running_stats = SimpleNamespace( + token_bleu=0.0, + duration_nll=0.0, + duration_mae=0.0, + f0_nll=0.0, + f0_mae=0.0, + n_tokens=0.0, + n_sentences=0.0, + f0_sum=0.0, + f0_sum_sq=0.0, + dur_sum=0.0, + dur_sum_sq=0.0, + ) + + for i, batch in enumerate(dataloader): + batch = explode_batch(batch, args.batch_explosion_rate) + bsz = batch["target"].size(0) + + batch = move_to_cuda(batch) + prefix = batch["prefix"][0] + + max_length_to_unroll = batch["target"].size(1) + prefix_length = batch["net_input"]["src_tokens"].size(1) + steps = max_length_to_unroll - prefix_length + 1 + + assert steps > 0 + produced_tokens, produced_durations, produced_f0, outputs = do_sampling( + model, + batch, + tgt_dict.eos(), + decoder, + autoregressive_steps=steps, + teacher_force_tokens=args.teacher_force_tokens, + teacher_force_duration=args.teacher_force_duration, + teacher_force_f0=args.teacher_force_f0, + ) + + if args.teacher_force_tokens: + assert (produced_tokens[:, 1:] == batch["target"]).all() + if args.teacher_force_duration: + assert (produced_durations[:, 1:] == batch["dur_target"]).all() + if args.teacher_force_f0: + assert (produced_f0[:, 1:] == batch["f0_target"]).all() + + dur_target = batch["dur_target"][:, prefix - 1 :].contiguous() + f0_target = batch["f0_target"][:, prefix - 1 :].contiguous() + + f0_mask = batch["f0_mask"][:, prefix - 1 :].contiguous() + dur_mask = batch["dur_mask"][:, prefix - 1 :].contiguous() + + duration_mae = mae_loss( + produced_durations[:, prefix:].float(), + dur_target.float(), + dur_mask, + reduce=False, + ) + min_duration_mae = duration_mae.view(bsz, -1).sum(dim=-1).min(dim=0)[0] + running_stats.duration_mae += min_duration_mae + + running_stats.dur_sum += ( + produced_durations[:, prefix:].float() * (~dur_mask) + ).sum() / args.batch_explosion_rate + running_stats.dur_sum_sq += ( + produced_durations[:, prefix:].float() * (~dur_mask) + ).pow(2.0).sum() / args.batch_explosion_rate + + if is_discrete_duration: + duration_loss = criterion.dur_loss_fn( + torch.stack([x[1] for x in outputs], dim=1), + dur_target, + dur_mask, + reduce=False, + ) + min_duration_loss = duration_loss.view(bsz, -1).sum(dim=-1).min(dim=0)[0] + running_stats.duration_nll += min_duration_loss + + if f0_decoder: # can only exist for discrete F0 models + decoded_produced_f0 = f0_decoder(produced_f0[:, prefix:]) + decoded_f0_target = batch["raw_f0"][:, prefix - 1 :].contiguous() + + if produced_f0.ndim == 3: + decoded_produced_f0 = decoded_produced_f0.squeeze(2) + decoded_f0_target = decoded_f0_target.squeeze(2) + + f0_mae = mae_loss( + decoded_produced_f0, decoded_f0_target, f0_mask, reduce=False + ) + f0_mae = f0_mae.view(bsz, -1).sum(dim=-1).min(dim=0)[0] + running_stats.f0_mae += f0_mae + + f0_loss = criterion.f0_loss_fn( + torch.stack([x[2] for x in outputs], dim=1), + f0_target.long(), + f0_mask, + reduce=False, + ) + f0_loss = f0_loss.view(bsz, -1).sum(dim=-1).min(dim=0)[0] + running_stats.f0_nll += f0_loss + + running_stats.f0_sum += ( + decoded_produced_f0 * (~f0_mask) + ).sum() / args.batch_explosion_rate + running_stats.f0_sum_sq += (decoded_produced_f0 * (~f0_mask)).pow( + 2.0 + ).sum() / args.batch_explosion_rate + + else: + assert not is_discrete_duration + + f0_loss = mae_loss( + produced_f0[:, prefix:], f0_target, f0_mask, reduce=False + ) + f0_loss = f0_loss.view(bsz, -1).sum(dim=-1).min(dim=0)[0] + running_stats.f0_mae += f0_loss + + running_stats.f0_sum += ( + produced_f0[:, prefix:].sum() / args.batch_explosion_rate + ) + running_stats.f0_sum_sq += ( + produced_f0[:, prefix:].pow(2.0).sum() / args.batch_explosion_rate + ) + + running_stats.n_tokens += (~dur_mask)[0, ...].sum() + + token_loss = get_bleu( + produced_tokens[:, prefix:], batch["target"][0, prefix - 1 :], tgt_dict + ) + running_stats.token_bleu += token_loss + running_stats.n_sentences += 1 + + if args.debug: + break + + values = torch.tensor( + [ + running_stats.token_bleu, + running_stats.duration_nll, + running_stats.duration_mae, + running_stats.f0_nll, + running_stats.f0_mae, + running_stats.f0_sum, + running_stats.f0_sum_sq, + running_stats.dur_sum, + running_stats.dur_sum_sq, + ] + ) + normalizers = torch.tensor( + [running_stats.n_sentences] + [running_stats.n_tokens] * 8 + ) + + return values, normalizers + + +@torch.no_grad() +def correlation(args, dataset, model, criterion, tgt_dict, rank, world_size): + is_discrete_duration = dataset.discrete_dur + is_discrete_f0 = dataset.discrete_f0 + + f0_decoder = None + if is_discrete_f0: + assert dataset.discrete_f0 + f0_decoder = Naive_F0_Decoder( + args.f0_discretization_bounds, dataset.config.f0_vq_n_units + ).cuda() + + if is_discrete_f0: + assert f0_decoder # correlation on tokens is meaningless + + dataset = InferenceDataset( + dataset, + args.prefix_length, + filter_short=True, + presort_by_length=True, + min_length=args.min_length, + ) + sampler = ( + None + if world_size == 1 + else DistributedSampler( + dataset, num_replicas=world_size, rank=rank, shuffle=False + ) + ) + dataloader = DataLoader( + dataset, + batch_size=1, + shuffle=False, + collate_fn=dataset.collater, + sampler=sampler, + ) + + Ts = args.T_token, args.T_duration, args.T_f0 + decoder = TemperatureDecoder( + Ts, discrete_dur=is_discrete_duration, discrete_f0=is_discrete_f0 + ) + + mean_dur_prefix, mean_dur_cont = [], [] + mean_f0_prefix, mean_f0_cont = [], [] + + for batch in dataloader: + batch = explode_batch(batch, args.batch_explosion_rate) + batch = move_to_cuda(batch) + + assert len(batch["prefix"]) == 1 + + if args.teacher_force_tokens: + autoregressive_steps = batch["target"].size(1) - args.prefix_length - 1 + else: + autoregressive_steps = args.max_length - args.prefix_length # + max_shift? + + if args.copy_target: + produced_durations, produced_f0 = batch["dur_target"], batch["f0_target"] + else: + _, produced_durations, produced_f0, outputs = do_sampling( + model, + batch, + tgt_dict.eos(), + decoder, + autoregressive_steps=autoregressive_steps, + teacher_force_tokens=args.teacher_force_tokens, + teacher_force_duration=args.teacher_force_duration, + teacher_force_f0=args.teacher_force_f0, + ) + + # first tokens actually correspond to BOS + produced_durations = produced_durations[:, 1:] + produced_f0 = produced_f0[:, 1:] + + dur_target = batch["dur_target"] + if is_discrete_duration: + produced_durations = produced_durations.float() + dur_target = dur_target.float() + + if is_discrete_f0: + produced_f0 = f0_decoder(produced_f0).squeeze(-1) + f0_target = batch["raw_f0"] + else: + f0_target = batch["f0_target"] + + # prefix values + prefix = batch["prefix"][0] + dur_prefix_mean = dur_target[:, :prefix].sum(dim=-1) / ( + (~batch["dur_mask"][:, :prefix]).sum(dim=-1) + ) + + non_voiced = f0_target[:, :prefix] == 0.0 + f0_mask = batch["f0_mask"][:, :prefix].logical_or(non_voiced) + f0_prefix_mean = f0_target[:, :prefix].sum(dim=-1) / ((~f0_mask).sum(dim=-1)) + + # continuation values + dur_cont_mean = produced_durations[:, prefix:].sum(dim=-1) / ( + (~batch["dur_mask"][:, prefix:]).sum(dim=-1) + ) + + non_voiced = produced_f0[:, prefix:] == 0.0 + f0_mask = non_voiced + f0_cont_mean = produced_f0[:, prefix:].sum(dim=-1) / ((~f0_mask).sum(dim=-1)) + + assert not f0_cont_mean.isnan().any() + + mean_dur_prefix.append(dur_prefix_mean.cpu()) + mean_dur_cont.append(dur_cont_mean.cpu()) + + mean_f0_prefix.append(f0_prefix_mean.cpu()) + mean_f0_cont.append(f0_cont_mean.cpu()) + + if args.debug and len(mean_dur_prefix) > 10: + break + + mean_dur_prefix, mean_dur_cont = torch.cat(mean_dur_prefix), torch.cat( + mean_dur_cont + ) + mean_f0_prefix, mean_f0_cont = torch.cat(mean_f0_prefix), torch.cat(mean_f0_cont) + + return mean_dur_prefix, mean_dur_cont, mean_f0_prefix, mean_f0_cont + + +def main(rank, world_size, args): + start = time.time() + + if world_size > 1: + torch.distributed.init_process_group( + backend="gloo", init_method="env://", world_size=world_size, rank=rank + ) + torch.cuda.set_device(rank % torch.cuda.device_count()) + + raw_args = args + + args = convert_namespace_to_omegaconf(args) + if args.common.seed is not None: + np.random.seed(args.common.seed) + utils.set_torch_seed(args.common.seed) + + models, model_args, task = checkpoint_utils.load_model_ensemble_and_task( + [raw_args.path], arg_overrides={"data": args.task.data} + ) + + tgt_dict = task.target_dictionary + + for model in models: + model.prepare_for_inference_(args) + model.cuda().eval() + if raw_args.fp16: + model = model.half() + model = models[0] + + config = ExpressiveCodeDataConfig(args.task.data) + + dataset = CodeDataset( + manifest=config.manifests[raw_args.eval_subset], + dictionary=task.source_dictionary, + dur_dictionary=task.source_duration_dictionary, + f0_dictionary=task.source_f0_dictionary, + config=config, + discrete_dur=task.cfg.discrete_duration, + discrete_f0=task.cfg.discrete_f0, + log_f0=task.cfg.log_f0, + normalize_f0_mean=task.cfg.normalize_f0_mean, + normalize_f0_std=task.cfg.normalize_f0_std, + interpolate_f0=task.cfg.interpolate_f0, + shifts=task.cfg.stream_shifts, + return_filename=True, + strip_filename=False, + return_continuous_f0=raw_args.dequantize_prosody, + ) + + if raw_args.filter_names: + dataset = FilterNamesDataset(dataset, raw_args.filter_names) + + criterion = task.build_criterion(model_args.criterion) + + name2metric = { + "continuation": continuation, + "teacher_force_everything": teacher_force_everything, + "correlation": correlation, + } + + name2keys = { + "continuation": ( + "Token BLEU3", + "Duration NLL", + "Duration MAE", + "F0 NLL", + "F0 MAE", + "F0 sum", + "F0 sum_sq", + "Dur sum", + "Dur sum_sq", + ), + "teacher_force_everything": ("token_loss", "duration_loss", "f0_loss"), + "correlation": ("Duration corr", "F0 corr"), + } + metric_name = raw_args.metric + + metric = name2metric[metric_name] + results = metric(raw_args, dataset, model, criterion, tgt_dict, rank, world_size) + + values = None + + if metric_name not in [ + "correlation", + ]: + values, normalizers = results + values = maybe_aggregate_normalize(values, normalizers, world_size) + elif metric_name == "correlation": + values = maybe_aggregate_correlations(results, world_size) + else: + assert False + + assert values is not None + summary = dict(zip(name2keys[raw_args.metric], values.tolist())) + if metric_name == "continuation": + summary["F0 Std"] = np.sqrt(-summary["F0 sum"] ** 2 + summary["F0 sum_sq"]) + summary["Dur Std"] = np.sqrt(-summary["Dur sum"] ** 2 + summary["Dur sum_sq"]) + del summary["F0 sum"] + del summary["F0 sum_sq"] + del summary["Dur sum"] + del summary["Dur sum_sq"] + + summary["metric"] = metric_name + + if rank == 0: + print(summary) + if raw_args.wandb: + wandb_results(summary, raw_args) + print("# finished in ", time.time() - start, "seconds") + + +def wandb_results(summary, raw_args): + import wandb + + run = wandb.init( + project=raw_args.wandb_project_name, tags=raw_args.wandb_tags.split(",") + ) + run.config.metric = raw_args.metric + run.config.model = raw_args.path + run.config.data = raw_args.data + + if raw_args.wandb_run_name: + run.name = raw_args.wandb_run_name + run.save() + + wandb.log(summary) + wandb.finish() + + +def maybe_aggregate_normalize(values, normalizers, world_size): + if world_size > 1: + torch.distributed.barrier() + + torch.distributed.all_reduce_multigpu([values]) + torch.distributed.all_reduce_multigpu([normalizers]) + + return values / normalizers + + +def maybe_aggregate_correlations(results, world_size): + if world_size > 1: + output = [None for _ in range(world_size)] + torch.distributed.all_gather_object(output, results) + mean_dur_prefix, mean_dur_cont, mean_f0_prefix, mean_f0_cont = [ + torch.cat([x[i] for x in output]) for i in range(4) + ] + else: + mean_dur_prefix, mean_dur_cont, mean_f0_prefix, mean_f0_cont = results + + corr_dur = scipy.stats.pearsonr(mean_dur_prefix.numpy(), mean_dur_cont.numpy())[0] + corr_f0 = scipy.stats.pearsonr(mean_f0_prefix.numpy(), mean_f0_cont.numpy())[0] + values = torch.tensor([corr_dur, corr_f0]) + + return values + + +def cli_main(): + parser = options.get_interactive_generation_parser() + parser.add_argument( + "--prefix-length", + type=int, + default=1, + help="Prompt prefix length (including <s>)", + ) + parser.add_argument( + "--duration-scale", + type=float, + default=1, + help="Multiply durations by the given scaler", + ) + parser.add_argument( + "--debug", action="store_true", help="Process only the first batch" + ) + parser.add_argument("--n_hypotheses", type=int, default=1) + parser.add_argument("--filter-names", type=str, default=None) + parser.add_argument( + "--max-length", type=int, default=200, help="Maximal produced length" + ) + + parser.add_argument("--teacher-force-tokens", action="store_true", default=False) + parser.add_argument("--teacher-force-duration", action="store_true", default=False) + parser.add_argument("--teacher-force-f0", action="store_true", default=False) + + parser.add_argument("--copy-target", action="store_true", default=False) + parser.add_argument("--min-length", type=int, default=None) + parser.add_argument("--f0-discretization-bounds", type=str, default=None) + parser.add_argument("--dequantize-prosody", action="store_true") + parser.add_argument("--batch-explosion-rate", type=int, default=1) + + parser.add_argument( + "--metric", + choices=["continuation", "teacher_force_everything", "correlation"], + required=True, + ) + + parser.add_argument("--wandb", action="store_true") + parser.add_argument("--wandb-project-name", type=str, default="eslm") + parser.add_argument("--wandb-tags", type=str, default="") + parser.add_argument("--wandb-run-name", type=str, default="") + + parser.add_argument("--T-token", type=float, default=1.0) + parser.add_argument("--T-duration", type=float, default=1.0) + parser.add_argument("--T-f0", type=float, default=1.0) + + parser.add_argument("--n-workers", type=int, default=1) + + parser.add_argument( + "--eval-subset", type=str, default="valid", choices=["valid", "test"] + ) + + args = options.parse_args_and_arch(parser) + + assert ( + args.prefix_length >= 1 + ), "Prefix length includes bos token <s>, hence the minimum is 1." + assert args.temperature >= 0.0, "T must be non-negative!" + + if args.dequantize_prosody: + assert args.f0_discretization_bounds + + world_size = args.n_workers or torch.cuda.device_count() + if world_size > 1: + import random + + mp.set_start_method("spawn", force=True) + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = str(random.randint(10_000, 50_000)) + + mp.spawn( + main, + nprocs=world_size, + args=( + world_size, + args, + ), + join=True, + ) + else: + main(rank=0, world_size=world_size, args=args) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/textless_nlp/pgslm/generate_waveform.py b/examples/textless_nlp/pgslm/generate_waveform.py new file mode 100644 index 0000000000..a6f348bb9b --- /dev/null +++ b/examples/textless_nlp/pgslm/generate_waveform.py @@ -0,0 +1,120 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import ast +import argparse +import json +import logging +from pathlib import Path +import soundfile as sf +import torch + +from tqdm import tqdm + +from fairseq import utils +from fairseq.models.text_to_speech.vocoder import CodeHiFiGANVocoder + + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def dump_result(args, data, sample_id, pred_wav): + assert "audio" in data or args.results_path is not None + if args.results_path: + fname = Path(data["audio"]).name if "audio" in data else f"{sample_id}_pred.wav" + out_file = Path(args.results_path) / fname + + sf.write( + out_file.as_posix(), + pred_wav.detach().cpu().numpy(), + args.sample_rate, + ) + + +def load_data(in_file): + with open(in_file) as f: + data = [ast.literal_eval(line.strip()) for line in f] + + return data + + +def get_f0_upsample_ratio(code_hop_size, f_hop_size): + ratio = (code_hop_size // 160) // (f_hop_size // 256) * 2 + return ratio + + +def main(args): + logger.info(args) + + use_cuda = torch.cuda.is_available() and not args.cpu + + with open(args.vocoder_cfg) as f: + vocoder_cfg = json.load(f) + vocoder = CodeHiFiGANVocoder(args.vocoder, vocoder_cfg) + if use_cuda: + vocoder = vocoder.cuda() + + data = load_data(args.in_file) + + if args.results_path: + Path(args.results_path).mkdir(exist_ok=True, parents=True) + + for i, d in tqdm(enumerate(data), total=len(data)): + code_key = "cpc_km100" if "cpc_km100" in d else "hubert" + code = list(map(int, d[code_key].split())) + + x = { + "code": torch.LongTensor(code).view(1, -1), + "f0": torch.Tensor(d["f0"]).view(1, -1), + } + + f0_up_ratio = get_f0_upsample_ratio( + vocoder_cfg["code_hop_size"], vocoder_cfg["hop_size"] + ) + if f0_up_ratio > 1: + bsz, cond_length = x["f0"].size() + x["f0"] = x["f0"].unsqueeze(2).repeat(1, 1, f0_up_ratio).view(bsz, -1) + + x = utils.move_to_cuda(x) if use_cuda else x + wav = vocoder(x) + dump_result(args, d, i, wav) + + +def cli_main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--in-file", + type=str, + required=True, + help="Input file following the same format of the output from sample.py ('f0' and 'cpc_km100/hubert' are required fields)", + ) + parser.add_argument( + "--vocoder", type=str, required=True, help="path to the vocoder" + ) + parser.add_argument( + "--vocoder-cfg", + type=str, + required=True, + help="path to the vocoder config", + ) + parser.add_argument("--sample-rate", type=int, default=16_000) + parser.add_argument( + "--results-path", + type=str, + default=None, + help="Output directory. If not set, the audios will be stored following the 'audio' field specified in the input file.", + ) + parser.add_argument("--cpu", action="store_true", help="run on CPU") + + args = parser.parse_args() + + main(args) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/textless_nlp/pgslm/inference_dataset.py b/examples/textless_nlp/pgslm/inference_dataset.py new file mode 100644 index 0000000000..9f7cfa5f54 --- /dev/null +++ b/examples/textless_nlp/pgslm/inference_dataset.py @@ -0,0 +1,103 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import torch + + +class InferenceDataset: + def __init__( + self, + dataset, + prefix, + only_prefix=True, + presort_by_length=True, + filter_short=False, + min_length=None, + ): + self.dataset = dataset + self.collater = self.dataset.collater + self.prefix = prefix + self.only_prefix = only_prefix + self.filter_short = filter_short + + self.remapping = list(range(len(self.dataset))) + if min_length: + assert min_length >= prefix + 1 + + length_thr = prefix + 1 if not min_length else min_length + + if filter_short: + self.remapping = list( + filter( + lambda i: self.dataset[i]["dur_source"].sum() > length_thr, + self.remapping, + ) + ) + print( + f"# the initial dataset of {len(self.dataset)} examples became {len(self.remapping)} after filtering" + f" examples shorter than {length_thr} (in duration units)" + ) + + if presort_by_length: + lengths = {index: dataset.size(index) for index in self.remapping} + self.remapping.sort(key=lambda i: lengths[i]) + + @property + def pads(self): + return self.dataset.pads + + def __len__(self): + return len(self.remapping) + + def original_size(self, k): + k = self.remapping[k] + return self.dataset.size(k) + + def __getitem__(self, k): + k = self.remapping[k] + channels = self.dataset[k] + + if self.prefix and self.only_prefix: + dur_channel = channels["dur_source"] + assert dur_channel.sum() >= self.prefix + + token_times = dur_channel.cumsum(dim=-1) + cut_after = torch.searchsorted(token_times, torch.tensor(self.prefix)) + + r = {} + for channel_name, value in channels.items(): + if isinstance(value, torch.Tensor) and "source" in channel_name: + # if self.filter_short: assert value.size(0) >= self.prefix + r[channel_name] = value[: cut_after + 1] + else: + r[channel_name] = value + + r["prefix"] = cut_after + 1 + else: + r = channels + + return r + + +def explode_batch(batch, times): + if times == 1: + return batch + + new_batch = {} + + for key, value in batch.items(): + if isinstance(value, torch.Tensor): + assert value.size(0) == 1 + new_batch[key] = torch.cat([value] * times) + elif key in ["ntokens", "nsentences"]: + new_batch[key] = value * times + elif key in ["prefix", "filename"]: + new_batch[key] = value + elif key == "net_input": + new_batch[key] = explode_batch(value, times) + else: + assert False, key + return new_batch diff --git a/examples/textless_nlp/pgslm/naive_decoder.py b/examples/textless_nlp/pgslm/naive_decoder.py new file mode 100644 index 0000000000..5132889792 --- /dev/null +++ b/examples/textless_nlp/pgslm/naive_decoder.py @@ -0,0 +1,40 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import warnings + + +class Naive_F0_Decoder(torch.nn.Module): + def __init__(self, bounds_path, n_units=32): + super().__init__() + + bounds = torch.load(bounds_path) + bounds = torch.from_numpy(bounds[n_units]) + assert bounds.ndim == 1 + + pad = torch.tensor([-5.0, -5.0]) # bos, eos, pad are in the dictionary + centers = torch.cat( + [bounds[0:1], 0.5 * (bounds[1:] + bounds[:-1]), bounds[-1:], pad[:]] + ) + + self.embedding = torch.nn.Embedding.from_pretrained( + centers.unsqueeze(-1), freeze=True + ) + self.max_n = self.embedding.weight.numel() + + def forward(self, discrete_f0: torch.Tensor): + in_bounds = (0 <= discrete_f0).all() and (discrete_f0 < self.max_n).all() + if not in_bounds: + warnings.warn( + f"F0 contains some weird outputs: discrete_f0.max().item()={discrete_f0.max().item()} discrete_f0.min().item()={discrete_f0.min().item()}; " + f"while we have embeddings for {self.max_n} values. " + "Assuming this is a no-prosody model -- but be careful!" + ) + + mask = discrete_f0 >= self.max_n + discrete_f0 = discrete_f0.masked_fill(mask, self.max_n - 1) + + return self.embedding(discrete_f0).squeeze(-1) diff --git a/examples/textless_nlp/pgslm/prepare_dataset.py b/examples/textless_nlp/pgslm/prepare_dataset.py new file mode 100644 index 0000000000..3d5edaa58f --- /dev/null +++ b/examples/textless_nlp/pgslm/prepare_dataset.py @@ -0,0 +1,143 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from multiprocessing import Pool + +import os +from collections import defaultdict +from itertools import starmap + +import torch +from npy_append_array import NpyAppendArray +from tqdm import tqdm + +from data_utils import dump_speaker_f0_stat, F0Stat, load_f0 +from fairseq.data.codedataset import ( + ExpressiveCodeDataConfig, + parse_manifest, + F0_FRAME_SPACE, + align_f0_to_durations, +) +from fairseq.tasks.speech_ulm_task import UnitDictionary + + +def load_meta(meta_path, split): + config = ExpressiveCodeDataConfig(meta_path) + manifest_path = config.manifests[split] + dictionary = UnitDictionary(n_units=config.n_units) + audio_paths, codes, durs, speakers = parse_manifest(manifest_path, dictionary) + return config, audio_paths, codes, durs, speakers + + +def _align_f0(f0, dur, ratio, frm_tol=5): + if f0 is None: + seg_f0 = torch.zeros_like(dur, dtype=torch.float) + else: + seg_f0 = align_f0_to_durations(f0, dur, ratio, tol=frm_tol * ratio) + return seg_f0.numpy() # try a hacky stuff + + +def align_f0(path_to_f0, audio_paths, durs, ratio, mp=False): + chunk_size = 2000 + num_procs = 40 + iterable = ((path_to_f0[p], d, ratio) for p, d in zip(audio_paths, durs)) + + seg_f0s = [] + if mp: + with Pool(num_procs) as pool: + iterator = tqdm( + pool.istarmap(_align_f0, iterable, chunk_size), + desc="align f0", + total=len(durs), + ) + for seg_f0 in iterator: + seg_f0s.append(torch.from_numpy(seg_f0).float()) + else: + iterator = tqdm(starmap(_align_f0, iterable), desc="align f0", total=len(durs)) + for seg_f0 in iterator: + seg_f0s.append(torch.from_numpy(seg_f0).float()) + + return seg_f0s + + +def prepare_seg_data(config, audio_paths, codes, durs, speakers, path_to_f0): + ratio = config.code_hop_size / (config.sampling_rate * F0_FRAME_SPACE) + seg_f0s = align_f0(path_to_f0, audio_paths, durs, ratio) + data = { + "codes": codes, + "duration": durs, + "f0": seg_f0s, + "speaker": speakers, + "path": audio_paths, + } + return data + + +def dump_seg_data(data, out_prefix): + key_targs = { + "codes": f"{out_prefix}.code.npy", + "duration": f"{out_prefix}.dur.npy", + "f0": f"{out_prefix}.f0.npy", + } + for key, targ in key_targs.items(): + assert not os.path.exists(targ) + npaa = NpyAppendArray(targ) + for utt_data in tqdm(data[key], desc=f"dumping {key}"): + npaa.append(utt_data.numpy()) + + assert not os.path.exists(f"{out_prefix}.path.txt") + with open(f"{out_prefix}.path.txt", "w") as f: + for x in data["path"]: + f.write(f"{str(x)}\n") + + assert not os.path.exists(f"{out_prefix}.leng.txt") + with open(f"{out_prefix}.leng.txt", "w") as f: + for x in data["codes"]: + f.write(f"{len(x)}\n") + + assert not os.path.exists(f"{out_prefix}.speaker.txt") + with open(f"{out_prefix}.speaker.txt", "w") as f: + for x in data["speaker"]: + f.write(f"{str(x)}\n") + + print(f"wrote to files with prefix {out_prefix}") + + +def main(meta_path, f0_dir, splits, nshards_list): + speaker_to_stat = defaultdict(F0Stat) + if len(nshards_list) == 1: + nshards_list = nshards_list * len(splits) + else: + assert len(nshards_list) == len(splits) + + for split, nshards in zip(splits, nshards_list): + config, audio_paths, codes, durs, speakers = load_meta(meta_path, split) + path_to_f0 = load_f0(f"{f0_dir}/{split}", nshards) + + # segment-level data + data = prepare_seg_data(config, audio_paths, codes, durs, speakers, path_to_f0) + dump_seg_data(data, config.manifests[split]) + + # speaker f0 + for audio_path, speaker in tqdm(zip(audio_paths, speakers)): + f0 = path_to_f0[audio_path] + speaker_to_stat[speaker].update(f0) + dump_speaker_f0_stat(speaker_to_stat, config.manifests[split]) + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("meta_path") + parser.add_argument("f0_dir", help="out_dir from preprocess_f0") + parser.add_argument("--splits", nargs="+", default=["train", "valid"]) + parser.add_argument( + "--nshards_list", type=int, nargs="+", default=[20], help="number of f0 shards" + ) + args = parser.parse_args() + print(args) + + main(**vars(args)) diff --git a/examples/textless_nlp/pgslm/preprocess_f0.py b/examples/textless_nlp/pgslm/preprocess_f0.py new file mode 100644 index 0000000000..afe899cb85 --- /dev/null +++ b/examples/textless_nlp/pgslm/preprocess_f0.py @@ -0,0 +1,65 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import torch +from tqdm import tqdm +from data_utils import load_audio_path +from fairseq.data.codedataset import get_f0_by_filename + + +def process_one(path, sr): + """ + Args: + path: audio file path + sr: sampling rate + """ + try: + # YAAPT throws errors in some rare cases + f0 = get_f0_by_filename(path, sr) + except Exception as e: + print( + f"WARNING: error when processing {path}. set f0 to zero. original error message:\n{e}" + ) + f0 = None + return f0 + + +def main(file_path, out_dir, nshards, rank, sampling_rate): + # load data + audio_paths = load_audio_path(file_path) + + # shard + assert nshards <= len(audio_paths) and nshards > 0 + shard_size = len(audio_paths) / nshards + s = int(round((rank - 1) * shard_size)) + e = int(round(rank * shard_size)) + audio_paths = audio_paths[s:e] + + # process + path_to_f0 = {} + for i, audio_path in enumerate(tqdm(audio_paths)): + f0 = process_one(audio_path, sampling_rate) + path_to_f0[audio_path] = f0 + print(f"finished processing {len(path_to_f0)} utterances ({s}-{e})") + + f0_path = f"{out_dir}/f0_{rank}_{nshards}.pt" + os.makedirs(out_dir, exist_ok=True) + torch.save(path_to_f0, f0_path) + print(f"saved to {f0_path}") + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("file_path") + parser.add_argument("out_dir") + parser.add_argument("--nshards", type=int, default=20) + parser.add_argument("--rank", type=int, default=1) + parser.add_argument("--sampling_rate", type=int, default=16000) + args = parser.parse_args() + + main(**vars(args)) diff --git a/examples/textless_nlp/pgslm/quantize_f0.py b/examples/textless_nlp/pgslm/quantize_f0.py new file mode 100644 index 0000000000..d9e3df2fe2 --- /dev/null +++ b/examples/textless_nlp/pgslm/quantize_f0.py @@ -0,0 +1,94 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from collections import defaultdict +from functools import partial + +import numpy as np +import torch +from tqdm import tqdm + +from data_utils import dump_speaker_f0_stat, F0Stat, load_audio_path, load_f0 + + +def load_speaker(path): + speakers = [] + with open(path) as f: + for line in f.readlines(): + sample = eval(line.strip()) + assert "speaker" in sample + speakers.append(sample["speaker"]) + return speakers + + +def quantize_f0(speaker_to_f0, f0_stats, nbins, normalize, log): + f0_all = [] + for speaker, f0 in speaker_to_f0.items(): + f0 = f0.raw_data + if log: + f0 = f0.log() + mean = f0_stats[speaker]["logf0_mean"] if log else f0_stats[speaker]["f0_mean"] + std = f0_stats[speaker]["logf0_std"] if log else f0_stats[speaker]["f0_std"] + if normalize == "mean": + f0 = f0 - mean + elif normalize == "meanstd": + f0 = (f0 - mean) / std + f0_all.extend(f0.tolist()) + + hist, bin_x = np.histogram(f0_all, 100000) + cum_hist = np.cumsum(hist) / len(f0_all) * 100 + + f0_bin = {} + for num_bin in nbins: + bin_offset = [] + bin_size = 100 / num_bin + threshold = bin_size + for i in range(num_bin - 1): + index = (np.abs(cum_hist - threshold)).argmin() + bin_offset.append(bin_x[index]) + threshold += bin_size + f0_bin[num_bin] = np.array(bin_offset) + + return f0_bin + + +def main(file_path, f0_dir, out_dir, out_prefix, nbins, nshards, normalize, log): + audio_paths = load_audio_path(file_path) + path_to_f0 = load_f0(f0_dir, nshards) + + speakers = load_speaker(file_path) + speaker_to_f0 = defaultdict(partial(F0Stat, True)) + + # speaker f0 stats + for audio_path, speaker in tqdm(zip(audio_paths, speakers)): + f0 = path_to_f0[audio_path] + speaker_to_f0[speaker].update(f0) + f0_stats = dump_speaker_f0_stat(speaker_to_f0, f"{out_dir}/{out_prefix}") + + # quantize + f0_bin = quantize_f0(speaker_to_f0, f0_stats, nbins, normalize, log) + log_suffix = "_log" if log else "" + f0_bin_out_file = f"{out_dir}/{out_prefix}_{normalize}_norm{log_suffix}_f0_bin.th" + torch.save(f0_bin, f0_bin_out_file) + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("file_path") + parser.add_argument("f0_dir", help="out_dir from preprocess_f0") + parser.add_argument("out_dir") + parser.add_argument("out_prefix") + parser.add_argument("--nbins", nargs="+", type=int, default=[32]) + parser.add_argument("--nshards", type=int, default=20, help="number of f0 shards") + parser.add_argument( + "--normalize", type=str, choices=["meanstd", "mean", "none"], default="mean" + ) + parser.add_argument("--log", action="store_true") + args = parser.parse_args() + print(args) + + main(**vars(args)) diff --git a/examples/textless_nlp/pgslm/sample/__init__.py b/examples/textless_nlp/pgslm/sample/__init__.py new file mode 100644 index 0000000000..0e028c26b9 --- /dev/null +++ b/examples/textless_nlp/pgslm/sample/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. diff --git a/examples/textless_nlp/pgslm/sample/sample.py b/examples/textless_nlp/pgslm/sample/sample.py new file mode 100644 index 0000000000..55ec7a955e --- /dev/null +++ b/examples/textless_nlp/pgslm/sample/sample.py @@ -0,0 +1,612 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import torch.multiprocessing as mp +import numpy as np +import json + +import torch +from torch.distributions.categorical import Categorical + +from fairseq import checkpoint_utils, options, utils +from fairseq.data.codedataset import CodeDataset, ExpressiveCodeDataConfig +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from torch.utils.data import DataLoader, DistributedSampler +from fairseq.utils import move_to_cuda + +import tqdm +import random +import pathlib + +import sys, pathlib + +sys.path.append(str(pathlib.Path(__file__).parent.parent)) +from inference_dataset import InferenceDataset, explode_batch +from naive_decoder import Naive_F0_Decoder +from truncated_laplace import truncated_laplace + +CODETYPE_TO_FRAMETIME = {"cpc_km100": 0.01, "hubert": 0.02} # 10ms # 20ms + + +class TemperatureDecoder: + def __init__(self, Ts, discrete_dur=False, discrete_f0=False): + self.T_token, self.T_dur, self.T_f0 = Ts + self.discrete_dur = discrete_dur + self.discrete_f0 = discrete_f0 + + def __call__(self, output): + def sample_multinomial(key, T): + logits = output[key][:, -1, :].float() + return Categorical(logits=logits / T).sample().unsqueeze(-1) + + def sample_laplace(key, T, truncate_at_zero): + mean = output[key][:, -1, :].float() + return truncated_laplace(mean=mean, T=T, truncate_by_zero=truncate_at_zero) + + if self.T_token > 0: + new_tokens = sample_multinomial("token", self.T_token) + else: + new_tokens = output["token"][:, -1, :].argmax(dim=-1, keepdim=True) + + if not self.discrete_dur and self.T_dur == 0: + new_durations = output["duration"][:, -1].round().int() + elif not self.discrete_dur and self.T_dur > 0: + new_durations = ( + sample_laplace("duration", self.T_dur, truncate_at_zero=True) + .round() + .int() + ) + elif self.discrete_dur and self.T_dur > 0: + new_durations = sample_multinomial("duration", self.T_dur) + elif self.discrete_dur and self.T_dur == 0: + new_durations = output["duration"][:, -1, :].argmax(dim=-1, keepdim=True) + else: + assert False + + if not self.discrete_f0 and self.T_f0 == 0: + new_f0 = output["f0"][:, -1] + elif not self.discrete_f0 and self.T_f0 > 0: + new_f0 = sample_laplace("f0", self.T_f0, truncate_at_zero=False) + elif self.discrete_f0 and self.T_f0 > 0: + new_f0 = sample_multinomial("f0", self.T_f0) + elif self.discrete_f0 and self.T_f0 == 0: + new_f0 = output["f0"][:, -1, :].argmax(dim=-1, keepdim=True) + else: + assert False + + return new_tokens, new_durations, new_f0 + + +class FilterNamesDataset: + def __init__(self, dataset, fnames_path): + self.dataset = dataset + + with open(fnames_path, "r") as fin: + fnames = set((eval(line)["audio"] for line in fin)) + print(f"# will retrict the dataset for {len(fnames)} files") + + self.indexes = [] + + for i, datapoint in enumerate(dataset): + if datapoint["filename"] in fnames: + self.indexes.append(i) + assert len(self.indexes) == len(fnames), f"{len(self.indexes)} {len(fnames)}" + + self.collater = self.dataset.collater + self.discrete_dur = self.dataset.discrete_dur + self.discrete_f0 = self.dataset.discrete_f0 + + def __len__(self): + return len(self.indexes) + + def __getitem__(self, k): + k = self.indexes[k] + return self.dataset[k] + + def size(self, k): + k = self.indexes[k] + return self.dataset.size(k) + + +@torch.no_grad() +def do_sampling( + model, + batch, + eos_token, + decoder, + autoregressive_steps=100, + teacher_force_tokens=False, + teacher_force_duration=False, + teacher_force_f0=False, + match_duration=False, +): + def autoregressive_step_(output, autoregressive_steps): + new_tokens, new_durations, new_f0 = decoder(output) + + n = output["token"].size(1) if output["token"].ndim == 3 else 1 + + if teacher_force_tokens: + new_tokens = batch["target"][:, n - 1].unsqueeze(-1) + if teacher_force_duration: + new_durations = batch["dur_target"][:, n - 1].unsqueeze(-1) + if teacher_force_f0: + new_f0 = batch["f0_target"][:, n - 1].unsqueeze(-1) + + batch["net_input"]["src_tokens"] = torch.cat( + [batch["net_input"]["src_tokens"], new_tokens], dim=1 + ) + batch["net_input"]["dur_src"] = torch.cat( + [batch["net_input"]["dur_src"], new_durations], dim=1 + ) + batch["net_input"]["f0_src"] = torch.cat( + [batch["net_input"]["f0_src"], new_f0], dim=1 + ) + + outputs = [] + + if teacher_force_tokens or teacher_force_duration or teacher_force_f0: + max_time = batch["target"].size(1) + prefix_time = batch["net_input"]["src_tokens"].size(1) + + autoregressive_steps = max_time - prefix_time + 1 # should be 0 + + for _ in range(autoregressive_steps): + output = model(**batch["net_input"]) + + last_steps = ( + output["token"][:, -1, ...], + output["duration"][:, -1, ...], + output["f0"][:, -1, ...], + ) + outputs.append(last_steps) + + autoregressive_step_(output, autoregressive_steps) + tokens, duration, f0 = ( + batch["net_input"]["src_tokens"], + batch["net_input"]["dur_src"], + batch["net_input"]["f0_src"], + ) + + if ( + match_duration + and (batch["dur_target"].sum(dim=-1) < duration.sum(dim=-1)).all() + ): + break + + return tokens, duration, f0, outputs + + +def unroll_duration(token_stream, duration_stream): + assert len(token_stream) == len( + duration_stream + ), f"{len(token_stream)} != {len(duration_stream)}" + non_positive_durations = sum(d <= 0 for d in duration_stream) + if non_positive_durations > 0: + print( + f"# {non_positive_durations} durations are non-positive, they will be capped to 1" + ) + + result = [] + + duration_stream_rounded_capped = [max(1, int(round(x))) for x in duration_stream] + for t, d in zip(token_stream, duration_stream_rounded_capped): + result.extend([t] * d) + + return result + + +def realign_shifted_streams(tokens, durations, F0s, shifts): + """ + Durations are shifted by 1, F0 by 2 + >>> tokens = ["<s>", "t1", "t2", "t3", "</s>", "x", "x"] + >>> durations = ["<0>", "<0>", "d1", "d2", "d3", "<0>", "x"] + >>> F0s = ["<0>", "<0>", "<0>", "f1", "f2", "f3", "<0>"] + >>> shifts = [1,2] + >>> realign_shifted_streams(tokens, durations, F0s, shifts) + (['<s>', 't1', 't2', 't3', '</s>'], ['<0>', 'd1', 'd2', 'd3', '<0>'], ['<0>', 'f1', 'f2', 'f3', '<0>']) + """ + max_shift = max(shifts) + if max_shift > 0: + shift_durations, shift_F0s = shifts + + tokens = tokens[:-max_shift] + durations = durations[shift_durations:] + if shift_durations < max_shift: + durations = durations[: -(max_shift - shift_durations)] + + if F0s is not None: + F0s = F0s[shift_F0s:] + if shift_F0s < max_shift: + F0s = F0s[: -(max_shift - shift_F0s)] + + assert len(tokens) == len(durations), f"{len(tokens)} =! {len(durations)}" + if F0s is not None: + assert len(tokens) == len(F0s), f"{len(tokens)} =! {len(F0s)}" + + return tokens, durations, F0s + + +def maybe_cut_eos(produced_tokens, produced_duration, produced_f0, eos_idx): + if eos_idx in produced_tokens: + eos_index = produced_tokens.index(eos_idx) + produced_tokens = produced_tokens[:eos_index] + produced_duration = produced_duration[:eos_index] + produced_f0 = produced_f0[:eos_index] + return produced_tokens, produced_duration, produced_f0 + + +def maybe_filter_pad(produced_tokens, produced_duration, produced_f0, pad_idx): + if pad_idx not in produced_tokens: + return produced_tokens, produced_duration, produced_f0 + + assert len(produced_tokens) == len(produced_duration) == len(produced_f0) + + print("<pad> is detected in the output!") + filtered_tokens, filtered_duration, filtered_f0 = [], [], [] + + for t, d, f in zip(produced_tokens, produced_duration, produced_f0): + if t != pad_idx: + filtered_tokens.append(t) + filtered_duration.append(d) + filtered_f0.append(f) + return filtered_tokens, filtered_duration, filtered_f0 + + +def match_duration(produced_tokens, produced_duration, produced_f0, target_duration): + """ + >>> tokens = ['t'] * 4 + >>> F0s = ['f0'] * 4 + >>> produced_duration = [1, 10, 10, 10] + >>> match_duration(tokens, produced_duration, F0s, target_duration=100) + (['t', 't', 't', 't'], [1, 10, 10, 10], ['f0', 'f0', 'f0', 'f0']) + >>> match_duration(tokens, produced_duration, F0s, target_duration=5) + (['t', 't'], [1, 4], ['f0', 'f0']) + """ + if sum(produced_duration) <= target_duration: + return produced_tokens, produced_duration, produced_f0 + + running_duration = 0 + filtered_duration = [] + + for next_tok_duration in produced_duration: + if running_duration + next_tok_duration < target_duration: + filtered_duration.append(next_tok_duration) + running_duration += next_tok_duration + else: + to_add = target_duration - running_duration + assert to_add <= next_tok_duration + filtered_duration.append(to_add) + break + + produced_duration = filtered_duration + assert sum(produced_duration) == target_duration + + n_tok = len(filtered_duration) + + return produced_tokens[:n_tok], produced_duration, produced_f0[:n_tok] + + +def main(rank, world_size, args): + if world_size > 1: + torch.distributed.init_process_group( + backend="gloo", init_method="env://", world_size=world_size, rank=rank + ) + torch.cuda.set_device(rank) + + raw_args = args + args = convert_namespace_to_omegaconf(args) + if args.common.seed is not None: + random.seed(args.common.seed) + np.random.seed(args.common.seed) + utils.set_torch_seed(args.common.seed) + + models, model_args, task = checkpoint_utils.load_model_ensemble_and_task( + [raw_args.path], arg_overrides={"data": args.task.data} + ) + tgt_dict = task.target_dictionary + + for model in models: + model.prepare_for_inference_(args) + model.cuda().eval() + if raw_args.fp16: + model = model.half() + model = models[0] + + config = ExpressiveCodeDataConfig(args.task.data) + + dataset = CodeDataset( + manifest=config.manifests[raw_args.subset], + dictionary=task.source_dictionary, + dur_dictionary=task.source_duration_dictionary, + f0_dictionary=task.source_f0_dictionary, + config=config, + discrete_dur=task.cfg.discrete_duration, + discrete_f0=task.cfg.discrete_f0, + log_f0=task.cfg.log_f0, + normalize_f0_mean=task.cfg.normalize_f0_mean, + normalize_f0_std=task.cfg.normalize_f0_std, + interpolate_f0=task.cfg.interpolate_f0, + shifts=task.cfg.stream_shifts, + return_filename=True, + strip_filename=False, + ) + tgt_dict = task.target_dictionary + shifts = dataset.shifts.dur, dataset.shifts.f0 + max_shift = max(shifts) + + fname = raw_args.output + if world_size > 1: + fname += f"_{rank}" + output_file = open(fname, "w") + + if raw_args.filter_names: + dataset = FilterNamesDataset(dataset, raw_args.filter_names) + + dataset = InferenceDataset(dataset, raw_args.prefix_length, filter_short=True) + print(f"Dataset size {len(dataset)}") + sampler = ( + None + if world_size == 1 + else DistributedSampler( + dataset, num_replicas=world_size, rank=rank, shuffle=False + ) + ) + dataloader = DataLoader( + dataset, + batch_size=1, + shuffle=False, + collate_fn=dataset.collater, + sampler=sampler, + ) + + Ts = raw_args.T_token, raw_args.T_duration, raw_args.T_f0 + decoder = TemperatureDecoder( + Ts, discrete_dur=task.cfg.discrete_duration, discrete_f0=task.cfg.discrete_f0 + ) + + dataset_size = len(dataset) + + f0_decoder = None + if raw_args.f0_discretization_bounds: + assert task.cfg.discrete_f0 + f0_decoder = Naive_F0_Decoder(raw_args.f0_discretization_bounds).cuda() + + pbar = ( + tqdm.tqdm( + total=dataset_size + if raw_args.max_samples is None + else min(raw_args.max_samples, dataset_size) + ) + if world_size == 1 + else None + ) + + samples_produced = 0 + + for batch in dataloader: + if ( + raw_args.max_samples is not None + and samples_produced >= raw_args.max_samples + ): + break + + prefix = batch["prefix"][0] + + batch = explode_batch(batch, raw_args.batch_explosion_rate) + batch = move_to_cuda(batch) + + if not raw_args.short_curcuit: + produced_tokens, produced_durations, produced_f0, _ = do_sampling( + models[0], + batch, + tgt_dict.eos(), + decoder, + autoregressive_steps=raw_args.max_length - prefix + max_shift, + teacher_force_tokens=raw_args.teacher_force_tokens, + match_duration=raw_args.match_duration, + teacher_force_duration=raw_args.teacher_force_duration, + teacher_force_f0=raw_args.teacher_force_f0, + ) + + # stip entries corresponding to <s> + produced_tokens = produced_tokens[:, 1:] + produced_durations = produced_durations[:, 1:] + produced_f0 = produced_f0[:, 1:] + + else: + max_length = raw_args.max_length + max_shift + produced_tokens, produced_durations, produced_f0 = ( + batch["target"][:, :max_length], + batch["dur_target"][:, :max_length], + batch["f0_target"][:, :max_length], + ) + + if f0_decoder is not None: + produced_f0 = f0_decoder(produced_f0) + + produced_tokens, produced_durations, produced_f0 = ( + produced_tokens.cpu().tolist(), + produced_durations.cpu().tolist(), + produced_f0.cpu().tolist(), + ) + + bsz = batch["target"].size(0) + assert bsz == raw_args.batch_explosion_rate + + for i in range(bsz): + if ( + raw_args.max_samples is not None + and samples_produced >= raw_args.max_samples + ): + break + + produced_tokens_i = produced_tokens[i] + produced_durations_i = produced_durations[i] + produced_f0_i = produced_f0[i] + + ( + produced_tokens_i, + produced_durations_i, + produced_f0_i, + ) = realign_shifted_streams( + produced_tokens_i, produced_durations_i, produced_f0_i, shifts + ) + + produced_tokens_i, produced_durations_i, produced_f0_i = maybe_cut_eos( + produced_tokens_i, produced_durations_i, produced_f0_i, tgt_dict.eos() + ) + + produced_tokens_i, produced_durations_i, produced_f0_i = maybe_filter_pad( + produced_tokens_i, produced_durations_i, produced_f0_i, tgt_dict.pad() + ) + + if raw_args.match_duration: + # NB: here we cheat a bit and use that padding has duration 0 + # so no need to re-align and remove padding + dur_target_i = batch["dur_target"][i, :].sum().item() + produced_tokens_i, produced_durations_i, produced_f0_i = match_duration( + produced_tokens_i, produced_durations_i, produced_f0_i, dur_target_i + ) + + if raw_args.cut_prompt: + produced_tokens_i, produced_durations_i, produced_f0_i = ( + produced_tokens_i[prefix:], + produced_durations_i[prefix:], + produced_f0_i[prefix:], + ) + + prompt_fname = batch["filename"][0] + fname = str(pathlib.Path(prompt_fname).with_suffix("")) + f"__{i}.wav" + + token_stream = unroll_duration(produced_tokens_i, produced_durations_i) + f0_stream = unroll_duration(produced_f0_i, produced_durations_i) + output_line = json.dumps( + { + "audio": fname, + "prompt": prompt_fname, + raw_args.code_type: " ".join(map(str, token_stream)), + "duration": round( + sum(produced_durations_i) + * CODETYPE_TO_FRAMETIME[raw_args.code_type], + 3, + ), + "raw_duration": produced_durations_i, + "raw_f0": produced_f0_i, + "f0": [round(f0, 3) for f0 in f0_stream], + } + ) + print(output_line, file=output_file) + + if pbar: + pbar.update(1) + samples_produced += 1 + + if raw_args.debug: + break + + output_file.close() + + if world_size > 1: + # important that everything is flushed before aggregating + torch.distributed.barrier() + + if world_size > 1 and rank == 0: + with open(raw_args.output, "w") as fout: + for i in range(world_size): + f = raw_args.output + f"_{i}" + with open(f, "r") as fin: + fout.write(fin.read()) + os.remove(f) + + +def cli_main(): + parser = options.get_interactive_generation_parser() + parser.add_argument( + "--prefix-length", + type=int, + default=1, + help="Prompt prefix length (including <s>)", + ) + parser.add_argument("--output", type=str, default=None, required=True) + parser.add_argument( + "--debug", action="store_true", help="Process only the first batch" + ) + parser.add_argument( + "--ignore-durations", + action="store_true", + help="If set, the duration stream is ignored", + ) + parser.add_argument( + "--max-length", type=int, default=200, help="Maximal produced length" + ) + parser.add_argument( + "--code-type", choices=["cpc_km100", "hubert"], default="cpc_km100" + ) + parser.add_argument("--max-samples", type=int, default=None) + parser.add_argument("--prompt-duration-scaler", type=float, default=1.0) + parser.add_argument("--teacher-force-tokens", action="store_true", default=False) + parser.add_argument("--teacher-force-duration", action="store_true", default=False) + parser.add_argument("--teacher-force-f0", action="store_true", default=False) + parser.add_argument("--filter-names", type=str, default=None) + parser.add_argument( + "--match-duration", + action="store_true", + help="Do not produce sequences longer that ground-truth", + ) + parser.add_argument( + "--cut-prompt", + action="store_true", + help="Remove prompt from the produced audio", + ) + parser.add_argument( + "--short-curcuit", action="store_true", help="Use 'target' as a sample" + ) + parser.add_argument("--f0-discretization-bounds", type=str, default=None) + + parser.add_argument("--batch-explosion-rate", type=int, default=1) + + parser.add_argument("--T-token", type=float, default=1.0) + parser.add_argument("--T-duration", type=float, default=1.0) + parser.add_argument("--T-f0", type=float, default=1.0) + + parser.add_argument( + "--subset", type=str, default="valid", choices=["test", "valid"] + ) + + args = options.parse_args_and_arch(parser) + + assert ( + args.prefix_length >= 1 + ), "Prefix length includes bos token <s>, hence the minimum is 1." + assert all( + t >= 0 for t in [args.T_token, args.T_f0, args.T_duration] + ), "T must be non-negative!" + + world_size = torch.cuda.device_count() + if world_size > 1: + import random + + mp.set_start_method("spawn", force=True) + os.environ["MASTER_ADDR"] = "localhost" + os.environ["MASTER_PORT"] = str(random.randint(10_000, 50_000)) + + print(f"Using {world_size} devices, master port {os.environ['MASTER_PORT']}") + + mp.spawn( + main, + nprocs=world_size, + args=( + world_size, + args, + ), + join=True, + ) + else: + main(rank=0, world_size=world_size, args=args) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/textless_nlp/pgslm/scripts/join_units_manifest.py b/examples/textless_nlp/pgslm/scripts/join_units_manifest.py new file mode 100644 index 0000000000..ed14fc5f59 --- /dev/null +++ b/examples/textless_nlp/pgslm/scripts/join_units_manifest.py @@ -0,0 +1,48 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import json +import argparse +import pathlib + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--manifest", required=True) + parser.add_argument("--units", required=True) + parser.add_argument("--output", required=True) + parser.add_argument("--sample_rate", type=int, default=16_000) + + args = parser.parse_args() + + with open(args.manifest, "r") as manifest, open(args.units, "r") as units, open( + args.output, "w" + ) as outp: + root = manifest.readline().strip() + root = pathlib.Path(root) + + for manifest_line, unit_line in zip(manifest.readlines(), units.readlines()): + path, frames = manifest_line.split() + duration = int(frames) / float(args.sample_rate) + fname = root / path + speaker = fname.parent.parent.name + + units = unit_line.split("|")[1] + + print( + json.dumps( + dict( + audio=str(root / path), + duration=duration, + hubert_km100=units.strip(), + speaker=speaker, + ) + ), + file=outp, + ) + + +if __name__ == "__main__": + main() diff --git a/examples/textless_nlp/pgslm/scripts/prepare_data.sh b/examples/textless_nlp/pgslm/scripts/prepare_data.sh new file mode 100644 index 0000000000..ec892e59a4 --- /dev/null +++ b/examples/textless_nlp/pgslm/scripts/prepare_data.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +train_json=$1 +valid_json=$2 +test_json=$3 +n_units=$4 +hop_size=$5 +sr=$6 +f0_quantizer=$7 +out_dir=$8 + +meta_path="$out_dir/data_config.json" +f0_dir="$out_dir/f0" + +mkdir -p $out_dir +ln -sf $train_json $out_dir/train.txt +ln -sf $valid_json $out_dir/valid.txt +ln -sf $test_json $out_dir/test.txt + +cat <<EOF >$meta_path +{ + "manifests": { + "train": "$out_dir/train.txt", + "valid": "$out_dir/valid.txt", + "test": "$out_dir/test.txt" + }, + "n_units": $n_units, + "code_hop_size": $hop_size, + "sampling_rate": $sr, + "multispkr": "parent_parent_name", + + "f0_vq_type": "naive", + "f0_vq_naive_quantizer": { + "log_mean_norm": "$f0_quantizer" + }, + "f0_vq_n_units": 32 +} +EOF + +for split in train valid test; do + python examples/textless_nlp/pgslm/preprocess_f0.py \ + $out_dir/$split.txt $f0_dir/$split --nshards=1 --rank=1 --sampling_rate=$sr + + #NSHARDS=16 + #seq 1 $NSHARDS | parallel -j $NSHARDS python examples/textless_nlp/pgslm/preprocess_f0.py \ + # $out_dir/$split.txt $f0_dir/$split --nshards=$NSHARDS --sampling_rate=$sr --rank +done + +# Please make sure that the number of shards (--nshards_list) is consistent across commands +python examples/textless_nlp/pgslm/prepare_dataset.py \ + $meta_path $f0_dir --splits test valid train --nshards_list 1 diff --git a/examples/textless_nlp/pgslm/scripts/prepare_f0_quantization.sh b/examples/textless_nlp/pgslm/scripts/prepare_f0_quantization.sh new file mode 100644 index 0000000000..3a285a39bc --- /dev/null +++ b/examples/textless_nlp/pgslm/scripts/prepare_f0_quantization.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +set -eu + +train_json=$1 +sr=$2 +nbins=$3 +out_dir=$4 +out_prefix=$5 + +f0_dir="$out_dir/f0" + +python examples/textless_nlp/pgslm/preprocess_f0.py \ + $train_json $f0_dir/${out_prefix}_f0_quant --nshards 1 --rank 1 --sampling_rate $sr + +# NB: one can use parallel here: +# NSHARDS=16 +# +#seq 1 $NSHARDS | parallel -j $NSHARDS python examples/textless_nlp/pgslm/preprocess_f0.py \ +# $train_json $f0_dir/${out_prefix}_f0_quant --nshards $NSHARDS --sampling_rate $sr --rank + +python examples/textless_nlp/pgslm/quantize_f0.py \ + $train_json $f0_dir/${out_prefix}_f0_quant $out_dir $out_prefix --nbins $nbins --nshards 1 --normalize mean --log diff --git a/examples/textless_nlp/pgslm/truncated_laplace.py b/examples/textless_nlp/pgslm/truncated_laplace.py new file mode 100644 index 0000000000..089f8a8cfc --- /dev/null +++ b/examples/textless_nlp/pgslm/truncated_laplace.py @@ -0,0 +1,29 @@ +# Copyright (c) Facebook, Inc. and its affiliates. + +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import warnings + + +def truncated_laplace(mean, T, truncate_by_zero=False): + """Generating a sample from a Laplace distribution, possible left-truncated at zero. + A bit of explanation here https://stats.stackexchange.com/a/357598 . + """ + assert isinstance(mean, torch.Tensor) + + if not truncate_by_zero: + percentile = 0.0 + else: + if not (mean >= 0.0).all(): + warnings.warn(f"means are supposed to be non-negative, but got {mean}") + mean = torch.clamp_min(mean, 0.0) + + lower_bound = mean.new_tensor([0.0]) + percentile = 0.5 + 0.5 * torch.sign(lower_bound - mean) * ( + 1.0 - torch.exp(-1.0 / T * torch.abs(mean - lower_bound)) + ) + + p = torch.empty_like(mean).uniform_() * (1.0 - percentile) + percentile + return mean - T * torch.sign(p - 0.5) * torch.log(1 - 2 * torch.abs(p - 0.5)) diff --git a/fairseq/criterions/speech_ulm_criterion.py b/fairseq/criterions/speech_ulm_criterion.py new file mode 100644 index 0000000000..eae6b62f76 --- /dev/null +++ b/fairseq/criterions/speech_ulm_criterion.py @@ -0,0 +1,126 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +from dataclasses import dataclass, field + +import torch.nn.functional as F +from fairseq import metrics +from fairseq.tasks import FairseqTask +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass +from omegaconf import II + + +@dataclass +class SpeechUnitLmCriterionConfig(FairseqDataclass): + sentence_avg: bool = II("optimization.sentence_avg") + loss_weights: str = field( + default="1.;0.0;0.0", + metadata={ + "help": "Weights of the losses that correspond to token, duration, and F0 streams" + }, + ) + discrete_duration: bool = II("task.discrete_duration") + discrete_f0: bool = II("task.discrete_f0") + + +def mae_loss(pred, targ, mask, reduce=True): + if pred.ndim == 3: + pred = pred.squeeze(2) + else: + assert pred.ndim == 2 + loss = (pred.float() - targ.float()).abs() * (~mask).float() + loss = loss.sum() if reduce else loss.view(-1) + return loss + + +def nll_loss(pred, targ, mask, reduce=True): + lprob = F.log_softmax(pred, dim=-1) + loss = F.nll_loss(lprob.view(-1, lprob.size(-1)), targ.view(-1), reduction="none") + loss = loss * (~mask).float().view(-1) + loss = loss.sum() if reduce else loss.view(-1) + return loss + + +@register_criterion("speech_unit_lm_criterion", dataclass=SpeechUnitLmCriterionConfig) +class SpeechUnitLmCriterion(FairseqCriterion): + def __init__(self, cfg: SpeechUnitLmCriterionConfig, task: FairseqTask): + super().__init__(task) + self.sentence_avg = cfg.sentence_avg + self.weights = torch.tensor([float(w) for w in cfg.loss_weights.split(";")]) + assert self.weights.size(0) == 3 + assert (self.weights >= 0.0).all() + + self.dur_loss_fn = nll_loss if cfg.discrete_duration else mae_loss + self.f0_loss_fn = nll_loss if cfg.discrete_f0 else mae_loss + + def forward(self, model, sample, reduce=True): + """Compute the loss for the given sample. + + Returns a tuple with three elements: + 1) the loss + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + net_output = model(**sample["net_input"]) + + token_loss = nll_loss( + net_output["token"], sample["target"], sample["mask"], reduce + ) + dur_loss = self.dur_loss_fn( + net_output["duration"], + sample["dur_target"], + sample["dur_mask"], + reduce, + ) + f0_loss = self.f0_loss_fn( + net_output["f0"], + sample["f0_target"], + sample["f0_mask"], + reduce, + ) + loss = self.weights.to(token_loss.device) * torch.stack( + [token_loss, dur_loss, f0_loss], dim=-1 + ) + loss = loss.sum() if reduce else loss.sum(-1) + + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + logging_output = { + "loss": loss.detach().sum().item(), + "token_loss": token_loss.detach().sum().item(), + "dur_loss": dur_loss.detach().sum().item(), + "f0_loss": f0_loss.detach().sum().item(), + "ntokens": sample["ntokens"], + "nsentences": sample["target"].size(0), + "sample_size": sample_size, + } + return loss, sample_size, logging_output + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + loss_sum = sum(log.get("loss", 0) for log in logging_outputs) + token_loss_sum = sum(log.get("token_loss", 0) for log in logging_outputs) + dur_loss_sum = sum(log.get("dur_loss", 0) for log in logging_outputs) + f0_loss_sum = sum(log.get("f0_loss", 0) for log in logging_outputs) + + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + + metrics.log_scalar("loss", loss_sum / sample_size, sample_size, round=3) + + metrics.log_scalar( + "token_loss", token_loss_sum / sample_size, sample_size, round=3 + ) + + metrics.log_scalar("dur_loss", dur_loss_sum / sample_size, sample_size, round=3) + + metrics.log_scalar("f0_loss", f0_loss_sum / sample_size, sample_size, round=3) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + return True diff --git a/fairseq/data/codedataset.py b/fairseq/data/codedataset.py new file mode 100644 index 0000000000..a433091956 --- /dev/null +++ b/fairseq/data/codedataset.py @@ -0,0 +1,576 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import json +import logging +import os +import random +from pathlib import Path + +import numpy as np +import torch +import torch.utils.data + +from . import data_utils +from fairseq.data.fairseq_dataset import FairseqDataset + +F0_FRAME_SPACE = 0.005 # sec + + +logger = logging.getLogger(__name__) + + +class ExpressiveCodeDataConfig(object): + def __init__(self, json_path): + with open(json_path, "r") as f: + self.config = json.load(f) + self._manifests = self.config["manifests"] + + @property + def manifests(self): + return self._manifests + + @property + def n_units(self): + return self.config["n_units"] + + @property + def sampling_rate(self): + return self.config["sampling_rate"] + + @property + def code_hop_size(self): + return self.config["code_hop_size"] + + @property + def f0_stats(self): + """pre-computed f0 statistics path""" + return self.config.get("f0_stats", None) + + @property + def f0_vq_type(self): + """naive or precomp""" + return self.config["f0_vq_type"] + + @property + def f0_vq_name(self): + return self.config["f0_vq_name"] + + def get_f0_vq_naive_quantizer(self, log, norm_mean, norm_std): + key = "log" if log else "linear" + if norm_mean and norm_std: + key += "_mean_std_norm" + elif norm_mean: + key += "_mean_norm" + else: + key += "_none_norm" + return self.config["f0_vq_naive_quantizer"][key] + + @property + def f0_vq_n_units(self): + return self.config["f0_vq_n_units"] + + @property + def multispkr(self): + """how to parse speaker label from audio path""" + return self.config.get("multispkr", None) + + +def get_f0(audio, rate=16000): + try: + import amfm_decompy.basic_tools as basic + import amfm_decompy.pYAAPT as pYAAPT + from librosa.util import normalize + except ImportError: + raise "Please install amfm_decompy (`pip install AMFM-decompy`) and librosa (`pip install librosa`)." + + assert audio.ndim == 1 + frame_length = 20.0 # ms + to_pad = int(frame_length / 1000 * rate) // 2 + + audio = normalize(audio) * 0.95 + audio = np.pad(audio, (to_pad, to_pad), "constant", constant_values=0) + audio = basic.SignalObj(audio, rate) + pitch = pYAAPT.yaapt( + audio, + frame_length=frame_length, + frame_space=F0_FRAME_SPACE * 1000, + nccf_thresh1=0.25, + tda_frame_length=25.0, + ) + f0 = pitch.samp_values + return f0 + + +def interpolate_f0(f0): + try: + from scipy.interpolate import interp1d + except ImportError: + raise "Please install scipy (`pip install scipy`)" + + orig_t = np.arange(f0.shape[0]) + f0_interp = f0[:] + ii = f0_interp != 0 + if ii.sum() > 1: + f0_interp = interp1d( + orig_t[ii], f0_interp[ii], bounds_error=False, kind="linear", fill_value=0 + )(orig_t) + f0_interp = torch.Tensor(f0_interp).type_as(f0).to(f0.device) + return f0_interp + + +def naive_quantize(x, edges): + bin_idx = (x.view(-1, 1) > edges.view(1, -1)).long().sum(dim=1) + return bin_idx + + +def load_wav(full_path): + try: + import soundfile as sf + except ImportError: + raise "Please install soundfile (`pip install SoundFile`)" + data, sampling_rate = sf.read(full_path) + return data, sampling_rate + + +def parse_code(code_str, dictionary, append_eos): + code, duration = torch.unique_consecutive( + torch.ShortTensor(list(map(int, code_str.split()))), return_counts=True + ) + code = " ".join(map(str, code.tolist())) + code = dictionary.encode_line(code, append_eos).short() + + if append_eos: + duration = torch.cat((duration, duration.new_zeros((1,))), dim=0) # eos + duration = duration.short() + return code, duration + + +def parse_manifest(manifest, dictionary): + audio_files = [] + codes = [] + durations = [] + speakers = [] + + with open(manifest) as info: + for line in info.readlines(): + sample = eval(line.strip()) + if "cpc_km100" in sample: + k = "cpc_km100" + elif "hubert_km100" in sample: + k = "hubert_km100" + elif "phone" in sample: + k = "phone" + else: + assert False, "unknown format" + code = sample[k] + code, duration = parse_code(code, dictionary, append_eos=True) + + codes.append(code) + durations.append(duration) + audio_files.append(sample["audio"]) + speakers.append(sample.get("speaker", None)) + + return audio_files, codes, durations, speakers + + +def parse_speaker(path, method): + if type(path) == str: + path = Path(path) + + if method == "parent_name": + return path.parent.name + elif method == "parent_parent_name": + return path.parent.parent.name + elif method == "_": + return path.name.split("_")[0] + elif method == "single": + return "A" + elif callable(method): + return method(path) + else: + raise NotImplementedError() + + +def get_f0_by_filename(filename, tgt_sampling_rate): + audio, sampling_rate = load_wav(filename) + if sampling_rate != tgt_sampling_rate: + raise ValueError( + "{} SR doesn't match target {} SR".format(sampling_rate, tgt_sampling_rate) + ) + + # compute un-interpolated f0, and use Ann's interp in __getitem__ if set + f0 = get_f0(audio, rate=tgt_sampling_rate) + f0 = torch.from_numpy(f0.astype(np.float32)) + return f0 + + +def align_f0_to_durations(f0, durations, f0_code_ratio, tol=1): + code_len = durations.sum() + targ_len = int(f0_code_ratio * code_len) + diff = f0.size(0) - targ_len + assert abs(diff) <= tol, ( + f"Cannot subsample F0: |{f0.size(0)} - {f0_code_ratio}*{code_len}|" + f" > {tol} (dur=\n{durations})" + ) + if diff > 0: + f0 = f0[:targ_len] + elif diff < 0: + f0 = torch.cat((f0, f0.new_full((-diff,), f0[-1])), 0) + + f0_offset = 0.0 + seg_f0s = [] + for dur in durations: + f0_dur = dur.item() * f0_code_ratio + seg_f0 = f0[int(f0_offset) : int(f0_offset + f0_dur)] + seg_f0 = seg_f0[seg_f0 != 0] + if len(seg_f0) == 0: + seg_f0 = torch.tensor(0).type(seg_f0.type()) + else: + seg_f0 = seg_f0.mean() + seg_f0s.append(seg_f0) + f0_offset += f0_dur + + assert int(f0_offset) == f0.size(0), f"{f0_offset} {f0.size()} {durations.sum()}" + return torch.tensor(seg_f0s) + + +class Paddings(object): + def __init__(self, code_val, dur_val=0, f0_val=-2.0): + self.code = code_val + self.dur = dur_val + self.f0 = f0_val + + +class Shifts(object): + def __init__(self, shifts_str, pads): + self._shifts = list(map(int, shifts_str.split(","))) + assert len(self._shifts) == 2, self._shifts + assert all(s >= 0 for s in self._shifts) + self.extra_length = max(s for s in self._shifts) + self.pads = pads + + @property + def dur(self): + return self._shifts[0] + + @property + def f0(self): + return self._shifts[1] + + @staticmethod + def shift_one(seq, left_pad_num, right_pad_num, pad): + assert seq.ndim == 1 + bos = seq.new_full((left_pad_num,), pad) + eos = seq.new_full((right_pad_num,), pad) + seq = torch.cat([bos, seq, eos]) + mask = torch.ones_like(seq).bool() + mask[left_pad_num : len(seq) - right_pad_num] = 0 + return seq, mask + + def __call__(self, code, dur, f0): + if self.extra_length == 0: + code_mask = torch.zeros_like(code).bool() + dur_mask = torch.zeros_like(dur).bool() + f0_mask = torch.zeros_like(f0).bool() + return code, code_mask, dur, dur_mask, f0, f0_mask + + code, code_mask = self.shift_one(code, 0, self.extra_length, self.pads.code) + dur, dur_mask = self.shift_one( + dur, self.dur, self.extra_length - self.dur, self.pads.dur + ) + f0, f0_mask = self.shift_one( + f0, self.f0, self.extra_length - self.f0, self.pads.f0 + ) + return code, code_mask, dur, dur_mask, f0, f0_mask + + +class CodeDataset(FairseqDataset): + def __init__( + self, + manifest, + dictionary, + dur_dictionary, + f0_dictionary, + config, + discrete_dur, + discrete_f0, + log_f0, + normalize_f0_mean, + normalize_f0_std, + interpolate_f0, + return_filename=False, + strip_filename=True, + shifts="0,0", + return_continuous_f0=False, + ): + random.seed(1234) + self.dictionary = dictionary + self.dur_dictionary = dur_dictionary + self.f0_dictionary = f0_dictionary + self.config = config + + # duration config + self.discrete_dur = discrete_dur + + # pitch config + self.discrete_f0 = discrete_f0 + self.log_f0 = log_f0 + self.normalize_f0_mean = normalize_f0_mean + self.normalize_f0_std = normalize_f0_std + self.interpolate_f0 = interpolate_f0 + + self.return_filename = return_filename + self.strip_filename = strip_filename + self.f0_code_ratio = config.code_hop_size / ( + config.sampling_rate * F0_FRAME_SPACE + ) + + # use lazy loading to avoid sharing file handlers across workers + self.manifest = manifest + self._codes = None + self._durs = None + self._f0s = None + with open(f"{manifest}.leng.txt", "r") as f: + lengs = [int(line.rstrip()) for line in f] + edges = np.cumsum([0] + lengs) + self.starts, self.ends = edges[:-1], edges[1:] + with open(f"{manifest}.path.txt", "r") as f: + self.file_names = [line.rstrip() for line in f] + logger.info(f"num entries: {len(self.starts)}") + + if os.path.exists(f"{manifest}.f0_stat.pt"): + self.f0_stats = torch.load(f"{manifest}.f0_stat.pt") + elif config.f0_stats: + self.f0_stats = torch.load(config.f0_stats) + + self.multispkr = config.multispkr + if config.multispkr: + with open(f"{manifest}.speaker.txt", "r") as f: + self.spkrs = [line.rstrip() for line in f] + self.id_to_spkr = sorted(self.spkrs) + self.spkr_to_id = {k: v for v, k in enumerate(self.id_to_spkr)} + + self.pads = Paddings( + dictionary.pad(), + 0, # use 0 for duration padding + f0_dictionary.pad() if discrete_f0 else -5.0, + ) + self.shifts = Shifts(shifts, pads=self.pads) + self.return_continuous_f0 = return_continuous_f0 + + def get_data_handlers(self): + logging.info(f"loading data for {self.manifest}") + self._codes = np.load(f"{self.manifest}.code.npy", mmap_mode="r") + self._durs = np.load(f"{self.manifest}.dur.npy", mmap_mode="r") + + if self.discrete_f0: + if self.config.f0_vq_type == "precomp": + self._f0s = np.load( + f"{self.manifest}.{self.config.f0_vq_name}.npy", mmap_mode="r" + ) + elif self.config.f0_vq_type == "naive": + self._f0s = np.load(f"{self.manifest}.f0.npy", mmap_mode="r") + quantizers_path = self.config.get_f0_vq_naive_quantizer( + self.log_f0, self.normalize_f0_mean, self.normalize_f0_std + ) + quantizers = torch.load(quantizers_path) + n_units = self.config.f0_vq_n_units + self._f0_quantizer = torch.from_numpy(quantizers[n_units]) + else: + raise ValueError(f"f0_vq_type {self.config.f0_vq_type} not supported") + else: + self._f0s = np.load(f"{self.manifest}.f0.npy", mmap_mode="r") + + def preprocess_f0(self, f0, stats): + """ + 1. interpolate + 2. log transform (keep unvoiced frame 0) + """ + # TODO: change this to be dependent on config for naive quantizer + f0 = f0.clone() + if self.interpolate_f0: + f0 = interpolate_f0(f0) + + mask = f0 != 0 # only process voiced frames + if self.log_f0: + f0[mask] = f0[mask].log() + if self.normalize_f0_mean: + mean = stats["logf0_mean"] if self.log_f0 else stats["f0_mean"] + f0[mask] = f0[mask] - mean + if self.normalize_f0_std: + std = stats["logf0_std"] if self.log_f0 else stats["f0_std"] + f0[mask] = f0[mask] / std + return f0 + + def _get_raw_item(self, index): + start, end = self.starts[index], self.ends[index] + if self._codes is None: + self.get_data_handlers() + code = torch.from_numpy(np.array(self._codes[start:end])).long() + dur = torch.from_numpy(np.array(self._durs[start:end])) + f0 = torch.from_numpy(np.array(self._f0s[start:end])) + return code, dur, f0 + + def __getitem__(self, index): + code, dur, f0 = self._get_raw_item(index) + code = torch.cat([code.new([self.dictionary.bos()]), code]) + + # use 0 for eos and bos + dur = torch.cat([dur.new([0]), dur]) + if self.discrete_dur: + dur = self.dur_dictionary.encode_line( + " ".join(map(str, dur.tolist())), append_eos=False + ).long() + else: + dur = dur.float() + + # TODO: find a more elegant approach + raw_f0 = None + if self.discrete_f0: + if self.config.f0_vq_type == "precomp": + f0 = self.f0_dictionary.encode_line( + " ".join(map(str, f0.tolist())), append_eos=False + ).long() + else: + f0 = f0.float() + f0 = self.preprocess_f0(f0, self.f0_stats[self.spkrs[index]]) + if self.return_continuous_f0: + raw_f0 = f0 + raw_f0 = torch.cat([raw_f0.new([self.f0_dictionary.bos()]), raw_f0]) + f0 = naive_quantize(f0, self._f0_quantizer) + f0 = torch.cat([f0.new([self.f0_dictionary.bos()]), f0]) + else: + f0 = f0.float() + if self.multispkr: + f0 = self.preprocess_f0(f0, self.f0_stats[self.spkrs[index]]) + else: + f0 = self.preprocess_f0(f0, self.f0_stats) + f0 = torch.cat([f0.new([0]), f0]) + + if raw_f0 is not None: + *_, raw_f0, raw_f0_mask = self.shifts(code, dur, raw_f0) + else: + raw_f0_mask = None + + code, code_mask, dur, dur_mask, f0, f0_mask = self.shifts(code, dur, f0) + if raw_f0_mask is not None: + assert (raw_f0_mask == f0_mask).all() + + # is a padded frame if either input or output is padded + feats = { + "source": code[:-1], + "target": code[1:], + "mask": code_mask[1:].logical_or(code_mask[:-1]), + "dur_source": dur[:-1], + "dur_target": dur[1:], + "dur_mask": dur_mask[1:].logical_or(dur_mask[:-1]), + "f0_source": f0[:-1], + "f0_target": f0[1:], + "f0_mask": f0_mask[1:].logical_or(f0_mask[:-1]), + } + + if raw_f0 is not None: + feats["raw_f0"] = raw_f0[1:] + + if self.return_filename: + fname = self.file_names[index] + feats["filename"] = ( + fname if not self.strip_filename else Path(fname).with_suffix("").name + ) + return feats + + def __len__(self): + return len(self.starts) + + def size(self, index): + return self.ends[index] - self.starts[index] + self.shifts.extra_length + + def num_tokens(self, index): + return self.size(index) + + def collater(self, samples): + pad_idx, eos_idx = self.dictionary.pad(), self.dictionary.eos() + if len(samples) == 0: + return {} + + src_tokens = data_utils.collate_tokens( + [s["source"] for s in samples], pad_idx, eos_idx, left_pad=False + ) + + tgt_tokens = data_utils.collate_tokens( + [s["target"] for s in samples], + pad_idx=pad_idx, + eos_idx=pad_idx, # appending padding, eos is there already + left_pad=False, + ) + + src_durs, tgt_durs = [ + data_utils.collate_tokens( + [s[k] for s in samples], + pad_idx=self.pads.dur, + eos_idx=self.pads.dur, + left_pad=False, + ) + for k in ["dur_source", "dur_target"] + ] + + src_f0s, tgt_f0s = [ + data_utils.collate_tokens( + [s[k] for s in samples], + pad_idx=self.pads.f0, + eos_idx=self.pads.f0, + left_pad=False, + ) + for k in ["f0_source", "f0_target"] + ] + + mask, dur_mask, f0_mask = [ + data_utils.collate_tokens( + [s[k] for s in samples], + pad_idx=1, + eos_idx=1, + left_pad=False, + ) + for k in ["mask", "dur_mask", "f0_mask"] + ] + + src_lengths = torch.LongTensor([s["source"].numel() for s in samples]) + n_tokens = sum(len(s["source"]) for s in samples) + + result = { + "nsentences": len(samples), + "ntokens": n_tokens, + "net_input": { + "src_tokens": src_tokens, + "src_lengths": src_lengths, + "dur_src": src_durs, + "f0_src": src_f0s, + }, + "target": tgt_tokens, + "dur_target": tgt_durs, + "f0_target": tgt_f0s, + "mask": mask, + "dur_mask": dur_mask, + "f0_mask": f0_mask, + } + + if "filename" in samples[0]: + result["filename"] = [s["filename"] for s in samples] + + # TODO: remove this hack into the inference dataset + if "prefix" in samples[0]: + result["prefix"] = [s["prefix"] for s in samples] + + if "raw_f0" in samples[0]: + raw_f0s = data_utils.collate_tokens( + [s["raw_f0"] for s in samples], + pad_idx=self.pads.f0, + eos_idx=self.pads.f0, + left_pad=False, + ) + result["raw_f0"] = raw_f0s + return result diff --git a/fairseq/models/text_to_speech/codehifigan.py b/fairseq/models/text_to_speech/codehifigan.py index ee4bb7d6f2..d1574dd63f 100644 --- a/fairseq/models/text_to_speech/codehifigan.py +++ b/fairseq/models/text_to_speech/codehifigan.py @@ -24,6 +24,12 @@ def __init__(self, cfg): Namespace(**cfg["dur_predictor_params"]) ) + self.f0 = cfg.get("f0", None) + n_f0_bin = cfg.get("f0_quant_num_bin", 0) + self.f0_quant_embed = ( + None if n_f0_bin <= 0 else nn.Embedding(n_f0_bin, cfg["embedding_dim"]) + ) + @staticmethod def _upsample(signal, max_frames): if signal.dim() == 3: @@ -59,6 +65,18 @@ def forward(self, **kwargs): # B x C x T x = torch.repeat_interleave(x, dur_out.view(-1), dim=2) + if self.f0: + if self.f0_quant_embed: + kwargs["f0"] = self.f0_quant_embed(kwargs["f0"].long()).transpose(1, 2) + else: + kwargs["f0"] = kwargs["f0"].unsqueeze(1) + + if x.shape[-1] < kwargs["f0"].shape[-1]: + x = self._upsample(x, kwargs["f0"].shape[-1]) + elif x.shape[-1] > kwargs["f0"].shape[-1]: + kwargs["f0"] = self._upsample(kwargs["f0"], x.shape[-1]) + x = torch.cat([x, kwargs["f0"]], dim=1) + if self.multispkr: assert ( "spkr" in kwargs @@ -68,7 +86,7 @@ def forward(self, **kwargs): x = torch.cat([x, spkr], dim=1) for k, feat in kwargs.items(): - if k in ["spkr", "code", "dur_prediction"]: + if k in ["spkr", "code", "f0", "dur_prediction"]: continue feat = self._upsample(feat, x.shape[-1]) diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index 69c9272063..c3d7134544 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -228,8 +228,14 @@ def __init__( def forward(self, x: Dict[str, torch.Tensor], dur_prediction=False) -> torch.Tensor: assert "code" in x x["dur_prediction"] = dur_prediction - mask = x["code"] >= 0 # remove invalid code + + # remove invalid code + mask = x["code"] >= 0 x["code"] = x["code"][mask].unsqueeze(dim=0) + if "f0" in x: + f0_up_ratio = x["f0"].size(1) // x["code"].size(1) + mask = mask.unsqueeze(2).repeat(1, 1, f0_up_ratio).view(-1, x["f0"].size(1)) + x["f0"] = x["f0"][mask].unsqueeze(dim=0) return self.model(**x).detach().squeeze() diff --git a/fairseq/models/transformer_ulm.py b/fairseq/models/transformer_ulm.py new file mode 100644 index 0000000000..0fc9ae4348 --- /dev/null +++ b/fairseq/models/transformer_ulm.py @@ -0,0 +1,408 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +from dataclasses import dataclass, field +from fairseq.models.fairseq_decoder import FairseqDecoder +import numpy as np +from typing import Optional, Dict, Any, List +import torch +from torch import nn +from fairseq.data.data_utils import compute_mask_indices +from fairseq.dataclass import ChoiceEnum +from fairseq.models import ( + FairseqLanguageModel, + register_model, + register_model_architecture, +) +from fairseq.tasks.speech_ulm_task import SpeechUnitLanguageModelingTask +from fairseq.models.transformer import Embedding, TransformerDecoder, Linear +from fairseq.models.transformer_lm import TransformerLanguageModelConfig +from torch import Tensor + + +DEFAULT_MAX_TARGET_POSITIONS = 1024 +MASKING_DISTRIBUTION_CHOICES = ChoiceEnum(["static", "uniform", "normal", "poisson"]) + + +@dataclass +class SpeechUnitLanguageModelConfig(TransformerLanguageModelConfig): + mask_unit_seg_prob: float = field( + default=0.0, metadata={"help": "probability to mask a segment of unit sequence"} + ) + mask_unit_seg_leng: int = field( + default=5, metadata={"help": "length of unit segment mask"} + ) + mask_unit_seg_type: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose unit mask length"} + ) + + mask_dur_prob: float = field( + default=0.0, metadata={"help": "probability to mask entire duration sequence"} + ) + mask_dur_seg_prob: float = field( + default=0.0, + metadata={"help": "probability to mask a segment of duration sequence"}, + ) + mask_dur_seg_leng: int = field( + default=5, metadata={"help": "length of duration segment mask"} + ) + mask_dur_seg_type: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose duration mask length"} + ) + + mask_f0_prob: float = field( + default=0.0, metadata={"help": "probability to mask entire duration sequence"} + ) + mask_f0_seg_prob: float = field( + default=0.0, metadata={"help": "probability to mask a segment of f0 sequence"} + ) + mask_f0_seg_leng: int = field( + default=5, metadata={"help": "length of f0 segment mask"} + ) + mask_f0_seg_type: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose f0 mask length"} + ) + + +@register_model("transformer_ulm", dataclass=SpeechUnitLanguageModelConfig) +class TransformerUnitLanguageModel(FairseqLanguageModel): + def __init__( + self, + cfg: SpeechUnitLanguageModelConfig, + task: SpeechUnitLanguageModelingTask, + decoder: FairseqDecoder, + ): + super().__init__(decoder) + self.cfg = cfg + + self.channel_names = task.channel_names + self.channel_sizes = task.channel_sizes + + self.unit_mask_val = task.source_dictionary.unk() + self.dur_mask_val = ( + task.source_duration_dictionary.unk() if task.cfg.discrete_duration else 0 + ) + self.f0_mask_val = ( + task.source_f0_dictionary.unk() if task.cfg.discrete_f0 else 0 + ) + + self.ignore_duration_input = task.cfg.ignore_duration_input + self.ignore_f0_input = task.cfg.ignore_f0_input + + @classmethod + def build_model(cls, args, task): + base_ulm_architecture(args) + + if getattr(args, "max_target_positions", None) is None: + args.max_target_positions = getattr( + args, "tokens_per_sample", DEFAULT_MAX_TARGET_POSITIONS + ) + + embed_tokens = Embedding( + len(task.source_dictionary), + args.decoder_input_dim, + padding_idx=task.source_dictionary.pad(), + ) + embed_duration = None + if task.cfg.discrete_duration: + embed_duration = Embedding( + len(task.source_duration_dictionary), + args.decoder_input_dim, + padding_idx=0, # duration uses 0 for padding + ) + embed_f0 = None + if task.cfg.discrete_f0: + embed_f0 = Embedding( + len(task.source_f0_dictionary), + args.decoder_input_dim, + padding_idx=task.source_f0_dictionary.pad(), + ) + + decoder = MultiStreamTransformerDecoder( + args, + task.target_dictionary, + embed_tokens, + [embed_duration, embed_f0], + no_encoder_attn=True, + channel_sizes=task.channel_sizes, + ) + + return cls(args, task, decoder) + + def apply_seg_dropout(self, inp, mask_prob, mask_leng, mask_type, mask_val): + B, T = inp.size() + if mask_prob > 0: + mask_indices = compute_mask_indices( + (B, T), None, mask_prob, mask_leng, mask_type # may mask padding + ) + mask_indices = torch.from_numpy(mask_indices).to(inp.device) + inp[mask_indices] = mask_val + else: + mask_indices = torch.zeros_like(inp).bool() + return inp, mask_indices + + def apply_seq_dropout(self, inp, mask_prob, mask_val): + B, T = inp.size() + if mask_prob > 0: + mask_indices = np.random.uniform(0, 1, (B,)) < mask_prob + mask_indices = ( + torch.from_numpy(mask_indices).to(inp.device).unsqueeze(1).expand(-1, T) + ) + inp[mask_indices] = mask_val + else: + mask_indices = torch.zeros_like(inp).bool() + return inp, mask_indices + + def apply_dropout(self, src_tokens, dur_src, f0_src): + src_tokens, unit_mask = self.apply_seg_dropout( + src_tokens, + self.cfg.mask_unit_seg_prob, + self.cfg.mask_unit_seg_leng, + self.cfg.mask_unit_seg_type, + self.unit_mask_val, + ) + + dur_src, dur_mask = self.apply_seq_dropout( + dur_src, self.cfg.mask_dur_prob, self.dur_mask_val + ) + dur_src, _dur_mask = self.apply_seg_dropout( + dur_src, + self.cfg.mask_dur_seg_prob, + self.cfg.mask_dur_seg_leng, + self.cfg.mask_dur_seg_type, + self.dur_mask_val, + ) + dur_mask = dur_mask.logical_or(_dur_mask) + + f0_src, f0_mask = self.apply_seq_dropout( + f0_src, self.cfg.mask_f0_prob, self.f0_mask_val + ) + f0_src, _f0_mask = self.apply_seg_dropout( + f0_src, + self.cfg.mask_f0_seg_prob, + self.cfg.mask_f0_seg_leng, + self.cfg.mask_f0_seg_type, + self.f0_mask_val, + ) + f0_mask = f0_mask.logical_or(_f0_mask) + + return src_tokens, unit_mask, dur_src, dur_mask, f0_src, f0_mask + + def forward( + self, + src_tokens: torch.Tensor, + dur_src: torch.Tensor, + f0_src: torch.Tensor, + src_lengths: Optional[Any] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + ): + if self.ignore_duration_input: + dur_src = torch.zeros_like(dur_src) + + if self.ignore_f0_input: + f0_src = torch.zeros_like(f0_src) + + if self.training: + ( + src_tokens, + unit_mask, + dur_src, + dur_mask, + f0_src, + f0_mask, + ) = self.apply_dropout(src_tokens, dur_src, f0_src) + else: + unit_masks = dur_mask = f0_mask = None + + prediction, _ = self.decoder( + prev_output_tokens=(src_tokens, dur_src, f0_src), + incremental_state=incremental_state, + src_lengths=src_lengths, + features_only=True, + ) + + result = dict(zip(self.channel_names, prediction)) + + return result + + +def base_ulm_architecture(args): + from .transformer_lm import base_lm_architecture + + base_lm_architecture(args) + + +@register_model_architecture("transformer_ulm", "transformer_ulm_big") +def transformer_ulm_big(args): + from .transformer_lm import transformer_lm_big + + transformer_lm_big(args) + base_ulm_architecture(args) + + +@register_model_architecture("transformer_ulm", "transformer_ulm_tiny") +def transformer_ulm_tiny(args): + from .transformer_lm import transformer_lm_gpt2_tiny + + transformer_lm_gpt2_tiny(args) + base_ulm_architecture(args) + + +class MultiStreamTransformerDecoder(TransformerDecoder): + def __init__( + self, + args, + dictionary, + embed_tokens, + embed_other_list, + no_encoder_attn, + channel_sizes, + ): + super().__init__( + args, dictionary, embed_tokens, no_encoder_attn=no_encoder_attn + ) + + # embed each channel and project if dimensions do not match + self.embed_other_list = torch.nn.ModuleList(embed_other_list) + self.proj_other_list = torch.nn.ModuleList() + dim = embed_tokens.embedding_dim + for embed_other in embed_other_list: + other_dim = 1 if embed_other is None else embed_other.embedding_dim + self.proj_other_list.append( + nn.Linear(other_dim, dim) if other_dim != dim else None + ) + + # tranformer output to prediction + self.channel_sizes = channel_sizes + self.project_out_dim = Linear( + embed_tokens.embedding_dim, sum(channel_sizes), bias=False + ) + + def extract_features_scriptable( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + if alignment_layer is None: + alignment_layer = self.num_layers - 1 + + # XXX: first multi-channel change start + prev_output_tokens, *other_channels = prev_output_tokens + # XXX: first multi-channel change end + + # embed positions + positions = None + if self.embed_positions is not None: + positions = self.embed_positions( + prev_output_tokens, incremental_state=incremental_state + ) + + if incremental_state is not None: + prev_output_tokens = prev_output_tokens[:, -1:] + other_channels = [o[:, -1:] for o in other_channels] + if positions is not None: + positions = positions[:, -1:] + + # embed tokens and positions + x = self.embed_scale * self.embed_tokens(prev_output_tokens) + + # XXX: second multi-channel change start + other_channels = [ + o.unsqueeze(-1).to(dtype=x.dtype) if emb is None else emb(o) + for o, emb in zip(other_channels, self.embed_other_list) + ] + other_channels = [ + o if proj_other is None else proj_other(o) + for o, proj_other in zip(other_channels, self.proj_other_list) + ] + for o in other_channels: + x = x + o + # XXX: second multi-channel change end + + if self.quant_noise is not None: + x = self.quant_noise(x) + + if self.project_in_dim is not None: + x = self.project_in_dim(x) + + if positions is not None: + x += positions + + if self.layernorm_embedding is not None: + x = self.layernorm_embedding(x) + + x = self.dropout_module(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + self_attn_padding_mask: Optional[Tensor] = None + if self.cross_self_attention or prev_output_tokens.eq(self.padding_idx).any(): + self_attn_padding_mask = prev_output_tokens.eq(self.padding_idx) + + # decoder layers + attn: Optional[Tensor] = None + inner_states: List[Optional[Tensor]] = [x] + for idx, layer in enumerate(self.layers): + if incremental_state is None and not full_context_alignment: + self_attn_mask = self.buffered_future_mask(x) + else: + self_attn_mask = None + + x, layer_attn, _ = layer( + x, + encoder_out["encoder_out"][0] + if (encoder_out is not None and len(encoder_out["encoder_out"]) > 0) + else None, + encoder_out["encoder_padding_mask"][0] + if ( + encoder_out is not None + and len(encoder_out["encoder_padding_mask"]) > 0 + ) + else None, + incremental_state, + self_attn_mask=self_attn_mask, + self_attn_padding_mask=self_attn_padding_mask, + need_attn=bool((idx == alignment_layer)), + need_head_weights=bool((idx == alignment_layer)), + ) + inner_states.append(x) + if layer_attn is not None and idx == alignment_layer: + attn = layer_attn.float().to(x) + + if attn is not None: + if alignment_heads is not None: + attn = attn[:alignment_heads] + + # average probabilities over heads + attn = attn.mean(dim=0) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + if self.project_out_dim is not None: + x = self.project_out_dim(x) + else: + assert False + + # XXX: the last change start + result = [] + start = 0 + for channel_size in self.channel_sizes: + end = start + channel_size + result.append(x[:, :, start:end]) + start = end + assert end == x.size(-1) + # XXX: the last change end + + return result, {"attn": [attn], "inner_states": inner_states} diff --git a/fairseq/tasks/speech_ulm_task.py b/fairseq/tasks/speech_ulm_task.py new file mode 100644 index 0000000000..b9d3019d50 --- /dev/null +++ b/fairseq/tasks/speech_ulm_task.py @@ -0,0 +1,224 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import sys +import torch +from dataclasses import dataclass, field +from typing import List, Optional, Tuple + +from fairseq.data import Dictionary +from fairseq.data.codedataset import ExpressiveCodeDataConfig, CodeDataset +from fairseq.dataclass.configs import FairseqDataclass +from fairseq.tasks import register_task +from fairseq.tasks.fairseq_task import FairseqTask +from omegaconf import MISSING, DictConfig + + +logger = logging.getLogger(__name__) + + +class UnitDictionary(Dictionary): + """ + A fixed-sized Dictionary that operates on integer-valued tokens + wth a trivial (identity) token <-> id mapping. + Special symbols (bos, eos, ...) have ids above n_units. + """ + + def __init__( + self, + *, # begin keyword-only arguments + n_units, + bos="<s>", + pad="<pad>", + eos="</s>", + unk="<unk>", + extra_special_symbols=None, + clip=False, + ): + self.n_units = n_units + self.bos_word, self.unk_word, self.pad_word, self.eos_word = bos, unk, pad, eos + self.clip = clip + + self.symbols = [] + self.count = [] + self.indices = {} + for i in range(n_units): + self.add_symbol(str(i)) + + self.bos_index = self.add_symbol(bos) + self.pad_index = self.add_symbol(pad) + self.eos_index = self.add_symbol(eos) + self.unk_index = self.add_symbol(unk) + + if extra_special_symbols: + for s in extra_special_symbols: + self.add_symbol(s) + self.nspecial = len(self.symbols) + + def encode_line(self, line, append_eos=True, prepend_bos=False) -> torch.IntTensor: + words = [int(x) for x in line.split()] + if self.clip: + words = [min(self.n_units - 1, word) for word in words] + if prepend_bos: + words = [self.bos_index] + words + if append_eos: + words.append(self.eos_index) + ids = torch.IntTensor(words) + return ids + + +@dataclass +class SpeechUnitModelingConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "Path to data config.json"}) + max_token_duration: int = field( + default=20, metadata={"help": "all token durations are capped to this value"} + ) + tokens_per_sample: int = field( + default=1024, metadata={"help": "tokens in a sample"} + ) + max_target_positions: int = field( + default=1024, metadata={"help": "max target positions"} + ) + + # duration modeling + ignore_duration_input: bool = field( + default=False, metadata={"help": "whether token durations should be zeroed out"} + ) + discrete_duration: bool = field( + default=False, metadata={"help": "treat duration as discrete variable"} + ) + # F0 modeling + ignore_f0_input: bool = field( + default=False, metadata={"help": "whether F0 should be zeroed out"} + ) + discrete_f0: bool = field( + default=False, metadata={"help": "load quantized f0. get bin from config"} + ) + log_f0: bool = field( + default=False, metadata={"help": "whether f0 should be modeled in log space"} + ) + normalize_f0_mean: bool = field( + default=False, metadata={"help": "whether normalize f0 by speaker mean"} + ) + normalize_f0_std: bool = field( + default=False, metadata={"help": "whether normalize f0 by speaker stddev"} + ) + interpolate_f0: bool = field( + default=False, + metadata={"help": "whether interpolate f0 for non-voiced segments"}, + ) + + # input/output streams + stream_shifts: str = field( + default="0,0", + metadata={ + "help": ( + "comma-separated integer list denoting right-shift for " + "duration and pitch streams" + ) + }, + ) + + +@register_task("speech_unit_modeling", dataclass=SpeechUnitModelingConfig) +class SpeechUnitLanguageModelingTask(FairseqTask): + def __init__(self, cfg: SpeechUnitModelingConfig) -> None: + super().__init__(cfg) + assert not self.cfg.normalize_f0_std or self.cfg.normalize_f0_mean + + self.data_config = ExpressiveCodeDataConfig(cfg.data) + self._source_dictionary = self._target_dictionary = UnitDictionary( + n_units=self.data_config.n_units + ) + self._source_duration_dictionary = self._target_duration_dictionary = ( + UnitDictionary(n_units=self.cfg.max_token_duration + 1, clip=True) + if self.cfg.discrete_duration + else None + ) + self._source_f0_dictionary = self._target_f0_dictionary = ( + UnitDictionary(n_units=self.data_config.f0_vq_n_units) + if self.cfg.discrete_f0 + else None + ) + + self._channel_names = ["token", "duration", "f0"] + self._channel_sizes = [ + len(self.target_dictionary), + len(self.target_duration_dictionary) if self.cfg.discrete_duration else 1, + len(self.target_f0_dictionary) if self.cfg.discrete_f0 else 1, + ] + + @property + def source_dictionary(self) -> Optional[Dictionary]: + return self._source_dictionary + + @property + def source_duration_dictionary(self) -> Optional[Dictionary]: + return self._source_duration_dictionary + + @property + def source_f0_dictionary(self) -> Optional[Dictionary]: + return self._source_f0_dictionary + + @property + def channel_names(self) -> List[str]: + return self._channel_names + + @property + def channel_sizes(self) -> List[int]: + return self._channel_sizes + + @property + def dictionary(self) -> Optional[Dictionary]: + return self._source_dictionary + + @property + def target_dictionary(self) -> Optional[Dictionary]: + return self._target_dictionary + + @property + def target_duration_dictionary(self) -> Optional[Dictionary]: + return self._target_duration_dictionary + + @property + def target_f0_dictionary(self) -> Optional[Dictionary]: + return self._target_f0_dictionary + + @property + def dictionaries(self) -> List[Dictionary]: + return [self._dictionaries[l] for l in self.cfg.labels] + + @classmethod + def setup_task( + cls, cfg: SpeechUnitModelingConfig, **kwargs + ) -> "SpeechUnitLanguageModelingTask": + return cls(cfg) + + def load_dataset(self, split: str, **kwargs) -> None: + self.datasets[split] = CodeDataset( + manifest=self.data_config.manifests[split], + dictionary=self.source_dictionary, + dur_dictionary=self.source_duration_dictionary, + f0_dictionary=self.source_f0_dictionary, + config=self.data_config, + discrete_dur=self.cfg.discrete_duration, + discrete_f0=self.cfg.discrete_f0, + log_f0=self.cfg.log_f0, + normalize_f0_mean=self.cfg.normalize_f0_mean, + normalize_f0_std=self.cfg.normalize_f0_std, + interpolate_f0=self.cfg.interpolate_f0, + shifts=self.cfg.stream_shifts, + ) + + def max_positions(self) -> Tuple[int, int]: + return (sys.maxsize, sys.maxsize) + + def build_criterion(self, cfg: DictConfig): + import fairseq.criterions + + return fairseq.criterions.build_criterion(cfg, self) From 5175fd5c267adceec9445bf067597686e159e7e7 Mon Sep 17 00:00:00 2001 From: spopuri <fb_ust@ip-0A020404.jkgpqq2blx3ejatzdu0vkghyde.xx.internal.cloudapp.net> Date: Wed, 23 Feb 2022 15:49:12 -0800 Subject: [PATCH 575/774] update readme for conformer based models (#3104) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3104 Reviewed By: kahne Differential Revision: D34323889 Pulled By: sravyapopuri388 fbshipit-source-id: da7216bc5918fd0e57e10395044088a555af2e07 --- .../speech_to_text/docs/covost_example.md | 60 +++++++++++--- examples/wav2vec/README.md | 83 ++++++++++++++----- .../wav2vec2_conformer_base_librispeech.yaml | 60 ++++++++++++++ .../wav2vec2_conformer_large_librivox.yaml | 72 ++++++++++++++++ 4 files changed, 241 insertions(+), 34 deletions(-) diff --git a/examples/speech_to_text/docs/covost_example.md b/examples/speech_to_text/docs/covost_example.md index 16447f041e..2dd41c3c55 100644 --- a/examples/speech_to_text/docs/covost_example.md +++ b/examples/speech_to_text/docs/covost_example.md @@ -1,12 +1,15 @@ [[Back]](..) # S2T Example: ST on CoVoST + We replicate the experiments in [CoVoST 2 and Massively Multilingual Speech-to-Text Translation (Wang et al., 2020)](https://arxiv.org/abs/2007.10310). ## Data Preparation + [Download](https://commonvoice.mozilla.org/en/datasets) and unpack Common Voice v4 to a path `${COVOST_ROOT}/${SOURCE_LANG_ID}`, then preprocess it with + ```bash # additional Python packages for S2T data processing/model training pip install pandas torchaudio sentencepiece @@ -19,28 +22,38 @@ python examples/speech_to_text/prep_covost_data.py \ --data-root ${COVOST_ROOT} --vocab-type char \ --src-lang fr --tgt-lang en ``` + The generated files (manifest, features, vocabulary and data configuration) will be added to `${COVOST_ROOT}/${SOURCE_LANG_ID}`. Download our vocabulary files if you want to use our pre-trained models: + - ASR: [En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_asr_vocab_char.zip) - ST: [Fr-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_vocab_char.zip), [De-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_vocab_char.zip), [Es-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_vocab_char.zip), [Ca-En](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_vocab_char.zip), [En-De](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_vocab_char.zip), [En-Ca](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_vocab_char.zip), [En-Fa](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_vocab_char.zip), [En-Et](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_vocab_char.zip) ## ASR + #### Training -We train an En ASR model for encoder pre-training of all ST models: + +We train an En ASR model for encoder pre-training some of the ST models. + ```bash fairseq-train ${COVOST_ROOT}/en \ --config-yaml config_asr_en.yaml --train-subset train_asr_en --valid-subset dev_asr_en \ --save-dir ${ASR_SAVE_DIR} --num-workers 4 --max-tokens 50000 --max-update 60000 \ --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --report-accuracy --arch s2t_transformer_s --dropout 0.15 --optimizer adam --lr 2e-3 \ - --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 + --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ + --attn-type None --pos-enc-type ${POS_ENC_TYPE} ``` -where `ASR_SAVE_DIR` is the checkpoint root path. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. -You may want to update it accordingly when using more than 1 GPU. + +where `ASR_SAVE_DIR` is the checkpoint root path and `POS_ENC_TYPE` refers to positional encoding to be used in the conformer encoder. +Set it to `abs`, `rope` or `rel_pos` to use the absolute positional encoding, rotary positional encoding or relative positional encoding in the conformer layer respectively. +Transformer encoder only supports absolute positional encoding and by default, the transformer encoder will be used. +To switch to conformer, set `--attn-type espnet` and `--POS_ENC_TYPE`. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly when using more than 1 GPU. #### Inference & Evaluation + ```bash CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt python scripts/average_checkpoints.py \ @@ -51,14 +64,22 @@ fairseq-generate ${COVOST_ROOT}/en \ --path ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} --max-tokens 50000 --beam 5 \ --scoring wer --wer-tokenizer 13a --wer-lowercase --wer-remove-punct ``` + #### Results -| --arch | Params | En | Model | -|---|---|---|---| -| s2t_transformer_s | 31M | 25.6 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_asr_transformer_s.pt) | + +| --arch | --pos-enc-type | Params | En | Model | +|---|---|---|---|---| +| s2t_transformer_s | - | 31M | 25.6 | [Download](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_asr_transformer_s.pt) | +| s2t_conformer | rel_pos | 42.9M | 23.18| [Download](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_asr/rel_pos_asr_checkpoint_best.pt) | +| s2t_conformer | rope | 42.1M | 23.8| [Download](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_asr/rope_pos_asr_checkpoint_best.pt) | +| s2t_conformer | abs | 42.1M | 23.8| [Download](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_asr/abs_asr_checkpoint_best.pt) | ## ST + #### Training + Fr-En as example: + ```bash fairseq-train ${COVOST_ROOT}/fr \ --config-yaml config_st_fr_en.yaml --train-subset train_st_fr_en --valid-subset dev_st_fr_en \ @@ -66,14 +87,21 @@ fairseq-train ${COVOST_ROOT}/fr \ --task speech_to_text --criterion label_smoothed_cross_entropy --label-smoothing 0.1 --report-accuracy \ --arch s2t_transformer_s --encoder-freezing-updates 1000 --optimizer adam --lr 2e-3 \ --lr-scheduler inverse_sqrt --warmup-updates 10000 --clip-norm 10.0 --seed 1 --update-freq 8 \ + --attn-type None --pos-enc-type ${POS_ENC_TYPE} \ --load-pretrained-encoder-from ${ASR_SAVE_DIR}/${CHECKPOINT_FILENAME} ``` -where `ST_SAVE_DIR` is the checkpoint root path. The ST encoder is pre-trained by En ASR for faster training and better + +where `ST_SAVE_DIR` is the checkpoint root path and `POS_ENC_TYPE` refers to positional encoding to be used in the conformer encoder. +Set it to `abs`, `rope` or `rel_pos` to use the absolute positional encoding, rotary positional encoding or relative positional encoding in the conformer layer respectively. +Transformer encoder only supports absolute positional encoding and by default, the transformer encoder will be used. +To switch to conformer, set `--attn-type espnet` and `--POS_ENC_TYPE`. Optionally load the pre-trained En ASR encoder for faster training and better performance: `--load-pretrained-encoder-from <ASR checkpoint path>`. We set `--update-freq 8` to simulate 8 GPUs with 1 GPU. You may want to update it accordingly when using more than 1 GPU. #### Inference & Evaluation + Average the last 10 checkpoints and evaluate on test split: + ```bash CHECKPOINT_FILENAME=avg_last_10_checkpoint.pt python scripts/average_checkpoints.py \ @@ -86,17 +114,27 @@ fairseq-generate ${COVOST_ROOT}/fr \ ``` ## Interactive Decoding + Launch the interactive console via + ```bash fairseq-interactive ${COVOST_ROOT}/fr --config-yaml config_st_fr_en.yaml \ --task speech_to_text --path ${SAVE_DIR}/${CHECKPOINT_FILENAME} \ --max-tokens 50000 --beam 5 ``` + Type in WAV/FLAC/OGG audio paths (one per line) after the prompt. #### Results -| --arch | Params | Fr-En | De-En | Es-En | Ca-En | En-De | En-Ca | En-Fa | En-Et | Model | -|---|---|---|---|---|---|---|---|---|---|---| -| s2t_transformer_s | 31M | [27.2](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_transformer_s.pt) | [17.7](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_transformer_s.pt) | [23.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_transformer_s.pt) | [19.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_transformer_s.pt) | [16.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_transformer_s.pt) | [21.6](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_transformer_s.pt) | [12.9](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_transformer_s.pt) | [12.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_transformer_s.pt) | (<-Download) | + +| --arch | --pos-enc-type | Params | ASR PT | Fr-En | De-En | Es-En | Ca-En | En-De | En-Ca | En-Fa | En-Et | Model | +|---|---|---|---|---|---|---|---|---|---|---|---|---| +| s2t_transformer | - | 31M | No | [27.2](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_transformer_s.pt) | [17.7](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_transformer_s.pt) | [23.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_transformer_s.pt) | [19.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_transformer_s.pt) | [16.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_transformer_s.pt) | [21.6](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_transformer_s.pt) | [12.9](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_transformer_s.pt) | [12.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_transformer_s.pt) | (<-Download) | +| s2t_conformer | rel_pos | 42.9M | No | [28.32](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [18.21](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [25.98](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [21.13](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [20.37](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [25.89](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [15.59](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [14.49](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | (<-Download) | +| s2t_conformer | rel_pos | 42.9M | Yes| [27.15](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [18.22](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [25.14](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [21.68](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [20.35](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [25.92](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [15.76](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [16.52](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | (<-Download) | +| s2t_conformer | rope | 42.1M | No | [27.61](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [17.6](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [24.91](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [20.78](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [19.7](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/rope_from_scratch_avg_last_10_checkpoint.pt) | [25.13](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/rope_from_scratch_avg_last_10_checkpoint.pt) | [15.22](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/rope_from_scratch_avg_last_10_checkpoint.pt) | [15.87](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/rope_from_scratch_avg_last_10_checkpoint.pt) | (<-Download) | +| s2t_conformer | rope | 42.1M | Yes | [26.99](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/rope_asr_pt_avg_last_10_checkpoint.pt) | [17.71](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/rope_asr_pt_avg_last_10_checkpoint.pt) | [24.24](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/rope_asr_pt_avg_last_10_checkpoint.pt) | [21.24](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/rope_asr_pt_avg_last_10_checkpoint.pt) | [19.9](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/rope_asr_pt_avg_last_10_checkpoint.pt) | [25.25](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/rope_asr_pt_avg_last_10_checkpoint.pt) | [15.58](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/rope_asr_pt_avg_last_10_checkpoint.pt) | [15.97](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/rope_asr_pt_avg_last_10_checkpoint.pt) | (<-Download) | +| s2t_conformer | abs | 42.1M | No | [27.45](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/abs_from_scratch_avg_last_10_checkpoint.pt) | [17.25](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/abs_from_scratch_avg_last_10_checkpoint.pt) | [25.01](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/abs_from_scratch_avg_last_10_checkpoint.pt) | [20.26](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/abs_from_scratch_avg_last_10_checkpoint.pt) | [19.86](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/abs_from_scratch_avg_last_10_checkpoint.pt) | [25.25](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/abs_from_scratch_avg_last_10_checkpoint.pt) | [15.46](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/abs_from_scratch_avg_last_10_checkpoint.pt) | [15.81](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/abs_from_scratch_avg_last_10_checkpoint.pt) | (<-Download) | +| s2t_conforme | abs | 42.1M | Yes| [26.52](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/abs_asr_pt_avg_last_10_checkpoint.pt) | [17.37](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/abs_asr_pt_avg_last_10_checkpoint.pt) | [25.40](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/abs_asr_pt_avg_last_10_checkpoint.pt) | [20.45](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/abs_asr_pt_avg_last_10_checkpoint.pt) | [19.57](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/abs_asr_pt_avg_last_10_checkpoint.pt) | [25.40](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/abs_asr_pt_avg_last_10_checkpoint.pt) | [15.17](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/abs_asr_pt_avg_last_10_checkpoint.pt) | [15.83](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/abs_asr_pt_avg_last_10_checkpoint.pt) | (<-Download) | [[Back]](..) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index db363f3f12..9cd2245381 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -10,7 +10,6 @@ We combined speech data from multiple domains in [Robust wav2vec 2.0: Analyzing We finetuned XLSR-53 on multiple languages to transcribe unseen languages in [Simple and Effective Zero-shot Cross-lingual Phoneme Recognition (Xu et al., 2021)](https://arxiv.org/abs/2109.11680). - ## Pre-trained models Model | Finetuning split | Dataset | Model @@ -24,9 +23,15 @@ Wav2Vec 2.0 Large | 10 minutes | [Librispeech](http://www.openslr.org/12) | [do Wav2Vec 2.0 Large | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_100h.pt) Wav2Vec 2.0 Large | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_960h.pt) Wav2Vec 2.0 Large (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_new.pt) +Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_no_FT ) +Wav2Vec 2.0 Large conformer - rope (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_no_FT ) Wav2Vec 2.0 Large (LV-60)* | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_new.pt) Wav2Vec 2.0 Large (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_new.pt) +Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_100h_FT.pt ) +Wav2Vec 2.0 Large conformer - rope (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_rope_PT_100h_FT.pt ) Wav2Vec 2.0 Large (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_new.pt) +Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_960h_FT.pt ) +Wav2Vec 2.0 Large conformer - rope (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_rope_PT_960h_FT.pt ) Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) @@ -66,9 +71,10 @@ We release 2 models that are finetuned on data from 2 different phonemizers. Alt Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) -### Prepare training data manifest: +### Prepare training data manifest First, install the `soundfile` library: + ```shell script pip install soundfile ``` @@ -76,7 +82,7 @@ pip install soundfile Next, run: ```shell script -$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext $ext --valid-percent $valid +python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext $ext --valid-percent $valid ``` $ext should be set to flac, wav, or whatever format your dataset happens to use that soundfile can read. @@ -85,7 +91,7 @@ $valid should be set to some reasonable percentage (like 0.01) of training data To use a pre-defined validation set (like dev-other from librispeech), set to it 0 and then overwrite valid.tsv with a separately pre-processed manifest file. -### Train a wav2vec 2.0 base model: +### Train a wav2vec 2.0 base model This configuration was used for the base model trained on the Librispeech dataset in the wav2vec 2.0 paper @@ -101,7 +107,7 @@ $ fairseq-hydra-train \ Note: you can simulate 64 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) `distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 64/k -### Train a wav2vec 2.0 large model: +### Train a wav2vec 2.0 large model This configuration was used for the large model trained on the Libri-light dataset in the wav2vec 2.0 paper @@ -115,7 +121,33 @@ $ fairseq-hydra-train \ Note: you can simulate 128 GPUs by using k GPUs and adding command line parameters (before `--config-dir`) `distributed_training.distributed_world_size=k` `+optimization.update_freq='[x]'` where x = 128/k -### Fine-tune a pre-trained model with CTC: +### Train a wav2vec 2.0 model with conformer backbone + +To replace the transformer layers in the encoder with the conformer layers, set `--layer-type conformer --attn-type espnet --pos-enc-type ${POS_ENC_TYPE}`. `POS_ENC_TYPE` refers to positional encoding to be used in the conformer encoder. +Set it to `abs`, `rope` or `rel_pos` to use the absolute positional encoding, rotary positional encoding or relative positional encoding in the conformer layer respectively. + +To train a base model with conformer: + +```shell script +$ fairseq-hydra-train \ + task.data=/path/to/data \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_conformer_base_librispeech \ + --attn-type espnet --pos-enc-type ${POS_ENC_TYPE} +``` + +To train a large model with conformer: + +```shell script +$ fairseq-hydra-train \ + task.data=/path/to/data \ + --config-dir /path/to/fairseq-py/examples/wav2vec/config/pretraining \ + --config-name wav2vec2_conformer_large_librivox + --attn-type espnet --pos-enc-type ${POS_ENC_TYPE} + +``` + +### Fine-tune a pre-trained model with CTC Fine-tuning a model requires parallel audio and labels file, as well as a vocabulary file in fairseq format. A letter vocabulary can be downloaded [here](https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt). @@ -127,6 +159,7 @@ $ python libri_labels.py /path/to/tsv --output-dir /output/dir --output-name $sp ``` Fine-tuning on 100h of Librispeech with letter targets: + ```shell script $ fairseq-hydra-train \ distributed_training.distributed_port=$PORT \ @@ -145,7 +178,7 @@ Note: you can simulate 24 GPUs by using k GPUs and adding command line parameter Decoding with a language model during training requires flashlight [python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter). If you want to use a language model, add `+criterion.wer_args='[/path/to/kenlm, /path/to/lexicon, 2, -1]'` to the command line. -### Evaluating a CTC model: +### Evaluating a CTC model Evaluating a CTC model with a language model requires [flashlight python bindings](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) (previously called [wav2letter](https://github.com/facebookresearch/wav2letter) to be installed. @@ -166,7 +199,7 @@ python examples/speech_recognition/infer.py /checkpoint/abaevski/data/speech/lib To get raw numbers, use --w2l-decoder viterbi and omit the lexicon. To use the transformer language model, use --w2l-decoder fairseqlm. -## Use wav2vec 2.0 with 🤗Transformers: +## Use wav2vec 2.0 with 🤗Transformers Wav2Vec2 is also available in the [🤗Transformers library](https://github.com/huggingface/transformers) since version 4.4. @@ -228,7 +261,8 @@ Description | Dataset | Model ---|---|--- Wav2Vec large | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_large.pt) -#### Example usage: +#### Example usage + ```python import torch import fairseq @@ -247,13 +281,13 @@ c = model.feature_aggregator(z) Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate files 10 to 30 seconds in length) -### Prepare training data manifest: +### Prepare training data manifest ``` -$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav +python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav ``` -### Train a wav2vec model: +### Train a wav2vec model ``` $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 --save-interval 1 --no-epoch-checkpoints \ @@ -264,11 +298,11 @@ $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 - --max-sample-size 150000 --max-tokens 1500000 --skip-invalid-size-inputs-valid-test ``` -### Run wav2vec2 pre-training on Google Cloud TPUs: +### Run wav2vec2 pre-training on Google Cloud TPUs Wav2Vec2 is now supported on TPUs! It's currently pre-training only. -#### Using hydra on a v3-8: +#### Using hydra on a v3-8 ``` $ OMP_NUM_THREADS=1 fairseq-hydra-train \ @@ -277,7 +311,8 @@ $ OMP_NUM_THREADS=1 fairseq-hydra-train \ --config-name wav2vec2_large_librivox_tpu.yaml ``` -#### Using command line arguments on a v3-8: +#### Using command line arguments on a v3-8 + Note: Commandline arguments way of execution has a [known-problem](https://github.com/pytorch/fairseq/issues/3741) currently. ``` @@ -291,7 +326,7 @@ $ OMP_NUM_THREADS=1 python train.py /manifest/path --save-dir /model/path --num- --encoder-layerdrop 0 --mask-channel-prob 0.1 ``` -#### Using hydra on a pod slice (v3-N with N > 8): +#### Using hydra on a pod slice (v3-N with N > 8) ``` $ OMP_NUM_THREADS=1 fairseq-hydra-train \ @@ -300,7 +335,8 @@ $ OMP_NUM_THREADS=1 fairseq-hydra-train \ --config-name wav2vec2_large_librivox_tpu-pod.yaml # edit distributed-world-size accordingly ``` -#### Using command line arguments on a pod slice (v3-N with N > 8): +#### Using command line arguments on a pod slice (v3-N with N > 8) + Note: Commandline arguments way of execution has a [known-problem](https://github.com/pytorch/fairseq/issues/3741) currently. ``` @@ -317,7 +353,7 @@ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --m --encoder-layerdrop 0 --mask-channel-prob 0.1 ``` -### Extract embeddings from the downstream task data: +### Extract embeddings from the downstream task data ``` $ PYTHONPATH=/path/to/fairseq python examples/wav2vec/wav2vec_featurize.py --input /path/to/task/waves --output /path/to/output \ @@ -338,7 +374,8 @@ vq-wav2vec Gumbel | [Librispeech](http://www.openslr.org/12) | [download](https: vq-wav2vec K-means | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/vq-wav2vec_kmeans.pt) Roberta on K-means codes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/bert_kmeans.tar) -#### Example usage: +#### Example usage + ```python import torch import fairseq @@ -358,13 +395,13 @@ print(idxs.shape) # output: torch.Size([1, 60, 2]), 60 timesteps with 2 indexes Given a directory containing wav files to be used for pretraining (we recommend splitting each file into separate file 10 to 30 seconds in length) -### Prepare training data manifest: +### Prepare training data manifest ``` -$ python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav +python examples/wav2vec/wav2vec_manifest.py /path/to/waves --dest /manifest/path --ext wav ``` -### Train a gumbel vq-wav2vec model: +### Train a gumbel vq-wav2vec model ``` $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 --max-update 400000 \ @@ -381,7 +418,7 @@ $ python train.py /manifest/path --save-dir /model/path --num-workers 6 --fp16 - for k-means training, set vq-type with "kmeans" and add --loss-weights [1] argument. Pre-trained models were trained on 16 GPUs. -### Tokenize audio data (e.g. for BERT training): +### Tokenize audio data (e.g. for BERT training) ``` $ PYTHONPATH=/path/to/fairseq python examples/wav2vec/vq-wav2vec_featurize.py --data-dir /manifest/path --output-dir /path/to/output \ diff --git a/examples/wav2vec/config/pretraining/wav2vec2_conformer_base_librispeech.yaml b/examples/wav2vec/config/pretraining/wav2vec2_conformer_base_librispeech.yaml index e69de29bb2..912ac152fd 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_conformer_base_librispeech.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_conformer_base_librispeech.yaml @@ -0,0 +1,60 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: ??? + max_sample_size: 250000 + min_sample_size: 32000 + normalize: false + +dataset: + num_workers: 6 + max_tokens: 1400000 + skip_invalid_size_inputs_valid_test: true + +distributed_training: + distributed_world_size: 64 + ddp_backend: legacy_ddp + +criterion: + _name: wav2vec + infonce: true + log_keys: ["prob_perplexity","code_perplexity","temp"] + loss_weights: [0.1, 10] + +optimization: + max_update: 400000 + lr: [0.0005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: wav2vec2 + quantize_targets: true + final_dim: 256 + encoder_layerdrop: 0.05 + dropout_input: 0.1 + dropout_features: 0.1 + feature_grad_mult: 0.1 + encoder_embed_dim: 768 + layer_type: conformer + attn_type: espnet + pos_enc_type: rel_pos diff --git a/examples/wav2vec/config/pretraining/wav2vec2_conformer_large_librivox.yaml b/examples/wav2vec/config/pretraining/wav2vec2_conformer_large_librivox.yaml index e69de29bb2..676166b6b7 100644 --- a/examples/wav2vec/config/pretraining/wav2vec2_conformer_large_librivox.yaml +++ b/examples/wav2vec/config/pretraining/wav2vec2_conformer_large_librivox.yaml @@ -0,0 +1,72 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: ??? + max_sample_size: 320000 + min_sample_size: 32000 + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1200000 + skip_invalid_size_inputs_valid_test: true + +distributed_training: + distributed_world_size: 128 + ddp_backend: legacy_ddp + +criterion: + _name: wav2vec + infonce: true + log_keys: ["prob_perplexity","code_perplexity","temp"] + loss_weights: [0.1, 0] + +optimization: + max_update: 1000000 + lr: [0.005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: wav2vec2 + quantize_targets: true + extractor_mode: layer_norm + layer_norm_first: true + final_dim: 768 + latent_temp: [2.0,0.1,0.999995] + encoder_layerdrop: 0.00 + dropout_input: 0.0 + dropout_features: 0.0 + dropout: 0.0 + attention_dropout: 0.0 + conv_bias: true + + encoder_layers: 24 + encoder_embed_dim: 1024 + encoder_ffn_embed_dim: 4096 + encoder_attention_heads: 16 + + feature_grad_mult: 1.0 + + layer_type: conformer + attn_type: espnet + pos_enc_type: rel_pos From 41847528fbcc13e901259207e3ca0ef8ddbb1573 Mon Sep 17 00:00:00 2001 From: Igor Shalyminov <shalymin@amazon.de> Date: Fri, 25 Feb 2022 14:29:43 -0800 Subject: [PATCH 576/774] Best metric is now only logged for the first of all the validation subsets (#4180) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Best metric is now only logged for the first of all the validation subsets # Before submitting - [x ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) https://groups.google.com/g/fairseq-users/c/7nk3rJmvlg8 - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/4162 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4180 Reviewed By: michaelauli Differential Revision: D34365416 Pulled By: alexeib fbshipit-source-id: 872f77da2cbf064ed838ebc7959365b0b33fe723 --- fairseq_cli/train.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 980e217147..0833f140ae 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -440,7 +440,7 @@ def validate( trainer.begin_valid_epoch(epoch_itr.epoch) valid_losses = [] - for subset in subsets: + for subset_idx, subset in enumerate(subsets): logger.info('begin validation on "{}" subset'.format(subset)) # Initialize data iterator @@ -483,7 +483,9 @@ def validate( trainer.valid_step(sample) # log validation stats - stats = get_valid_stats(cfg, trainer, agg.get_smoothed_values()) + # only tracking the best metric on the 1st validation subset + tracking_best = subset_idx == 0 + stats = get_valid_stats(cfg, trainer, agg.get_smoothed_values(), tracking_best) if hasattr(task, "post_validate"): task.post_validate(trainer.get_model(), stats, agg) @@ -495,10 +497,13 @@ def validate( def get_valid_stats( - cfg: DictConfig, trainer: Trainer, stats: Dict[str, Any] + cfg: DictConfig, + trainer: Trainer, + stats: Dict[str, Any], + tracking_best: bool, ) -> Dict[str, Any]: stats["num_updates"] = trainer.get_num_updates() - if hasattr(checkpoint_utils.save_checkpoint, "best"): + if tracking_best and hasattr(checkpoint_utils.save_checkpoint, "best"): key = "best_{0}".format(cfg.checkpoint.best_checkpoint_metric) best_function = max if cfg.checkpoint.maximize_best_checkpoint_metric else min stats[key] = best_function( From d421749323f466209d656536bb1f8963371ff29b Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Mon, 28 Feb 2022 09:49:11 -0800 Subject: [PATCH 577/774] Add s2s_conformer model to support conformer encoder in S2UT model (#3113) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3113 Reviewed By: an918tw, kahne Differential Revision: D34365606 Pulled By: sravyapopuri388 fbshipit-source-id: aa4f0ab24ca191101b9eca0f5e08dcbedf9fadbb --- fairseq/models/speech_to_speech/__init__.py | 1 + .../models/speech_to_speech/s2s_conformer.py | 111 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 fairseq/models/speech_to_speech/s2s_conformer.py diff --git a/fairseq/models/speech_to_speech/__init__.py b/fairseq/models/speech_to_speech/__init__.py index d348835525..41be5e75c6 100644 --- a/fairseq/models/speech_to_speech/__init__.py +++ b/fairseq/models/speech_to_speech/__init__.py @@ -5,3 +5,4 @@ from .modules import * # noqa from .s2s_transformer import * # noqa +from .s2s_conformer import * # noqa diff --git a/fairseq/models/speech_to_speech/s2s_conformer.py b/fairseq/models/speech_to_speech/s2s_conformer.py new file mode 100644 index 0000000000..a232412cc5 --- /dev/null +++ b/fairseq/models/speech_to_speech/s2s_conformer.py @@ -0,0 +1,111 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from pathlib import Path +import torch + +from fairseq import checkpoint_utils +from fairseq.models import ( + register_model, + register_model_architecture, +) +from fairseq.data.audio.data_cfg import S2SDataConfig +from fairseq.models.speech_to_text import S2TConformerEncoder +from fairseq.models.speech_to_speech import ( + S2UTTransformerModel, + s2ut_architecture_base as s2ut_transformer_architecture_base, +) +from fairseq.models.transformer import ( + Linear, +) + + +logger = logging.getLogger(__name__) + + +class S2SConformerEncoder(S2TConformerEncoder): + """Based on S2T transformer encoder, with support + to incorporate target speaker embedding.""" + + def __init__(self, args): + super().__init__(args) + + self.spk_emb_proj = None + if args.target_speaker_embed: + self.spk_emb_proj = Linear( + args.encoder_embed_dim + args.speaker_embed_dim, args.encoder_embed_dim + ) + + def forward( + self, src_tokens, src_lengths, tgt_speaker=None, return_all_hiddens=False + ): + out = super().forward(src_tokens, src_lengths, return_all_hiddens) + + if self.spk_emb_proj: + x = out["encoder_out"][0] + seq_len, bsz, _ = x.size() + tgt_speaker_emb = tgt_speaker.view(1, bsz, -1).expand(seq_len, bsz, -1) + x = self.spk_emb_proj(torch.cat([x, tgt_speaker_emb], dim=2)) + out["encoder_out"][0] = x + + return out + + +@register_model("s2ut_conformer") +class S2UTConformerModel(S2UTTransformerModel): + """ + Direct speech-to-speech translation model with S2T Conformer encoder + Transformer discrete unit decoder + """ + + @staticmethod + def add_args(parser): + S2UTTransformerModel.add_args(parser) + parser.add_argument("--depthwise-conv-kernel-size", default=31) + parser.add_argument( + "--attn-type", + default=None, + help="If not specified uses fairseq MHA. Other valid option is espnet for using conformer", + ) + parser.add_argument( + "--pos-enc-type", + default="abs", + help="Must be specified in addition to attn-type=espnet for rel_pos and rope", + ) + + @classmethod + def build_encoder(cls, args): + print(args) + data_cfg = S2SDataConfig(Path(args.data) / args.config_yaml) + args.input_feat_per_channel = data_cfg.input_feat_per_channel + args.input_channels = data_cfg.input_transformed_channels + + encoder = S2SConformerEncoder(args) + pretraining_path = getattr(args, "load_pretrained_encoder_from", None) + if pretraining_path is not None: + if not Path(pretraining_path).exists(): + logger.warning( + f"skipped pretraining because {pretraining_path} does not exist" + ) + else: + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=pretraining_path + ) + logger.info(f"loaded pretrained encoder from: {pretraining_path}") + return encoder + + +@register_model_architecture("s2ut_conformer", "s2ut_conformer") +def s2ut_base_architecture(args): + args.attn_type = getattr(args, "attn_type", None) + args.pos_enc_type = getattr(args, "pos_enc_type", "abs") + args.max_source_positions = getattr(args, "max_source_positions", 6000) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + args.encoder_layers = getattr(args, "encoder_layers", 16) + args.depthwise_conv_kernel_size = getattr(args, "depthwise_conv_kernel_size", 31) + s2ut_transformer_architecture_base(args) From a24fdf2d1b36e699d8f4e3efd33b7b78d6a02e7e Mon Sep 17 00:00:00 2001 From: Hetarth Chopra <34271010+choprahetarth@users.noreply.github.com> Date: Mon, 28 Feb 2022 20:21:53 -0800 Subject: [PATCH 578/774] Fixing and error related to Floor Division (#4221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/4058 While using the library the following warnings are shown which sometimes hinder the workflow. The warnings are `<USER_PATH>/fairseq/search.py:140: UserWarning: __floordiv__ is deprecated, and its behavior will change in a future version of pytorch. It currently rounds toward 0 (like the 'trunc' function NOT 'floor'). This results in incorrect rounding for negative values. To keep the current behavior, use torch.div(a, b, rounding_mode='trunc'), or for actual floor division, use torch.div(a, b, rounding_mode='floor'). beams_buf = indices_buf // vocab_size` `<USER_PATH>/fairseq/sequence_generator.py:666: UserWarning: __floordiv__ is deprecated, and its behavior will change in a future version of pytorch. It currently rounds toward 0 (like the 'trunc' function NOT 'floor'). This results in incorrect rounding for negative values. To keep the current behavior, use torch.div(a, b, rounding_mode='trunc'), or for actual floor division, use torch.div(a, b, rounding_mode='floor'). unfin_idx = bbsz_idx // beam_size` The methodology was simple, instead of using the `//`, it was replaced by `torch.div(arg1, arg2, rounding_mode='trunc')` and the variable alues do not change for both before and after, just the warning is resolved. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Yes, I did! Thanks! Pull Request resolved: https://github.com/pytorch/fairseq/pull/4221 Reviewed By: arbabu123 Differential Revision: D34538147 Pulled By: alexeib fbshipit-source-id: 143897a249129a163b6a30ba9b5cf5595ef42330 --- fairseq/data/indexed_dataset.py | 4 ++-- fairseq/search.py | 2 +- fairseq/sequence_generator.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index d0843926ae..81cba4af6b 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -120,7 +120,7 @@ def write_longs(f, a): 3: np.int16, 4: np.int32, 5: np.int64, - 6: np.float, + 6: np.float64, 7: np.double, 8: np.uint16, 9: np.uint32, @@ -327,7 +327,7 @@ class IndexedDatasetBuilder: np.int16: 2, np.int32: 4, np.int64: 8, - np.float: 4, + np.float64: 4, np.double: 8, } diff --git a/fairseq/search.py b/fairseq/search.py index d5ea68b4ce..226f08fe40 100644 --- a/fairseq/search.py +++ b/fairseq/search.py @@ -137,7 +137,7 @@ def step( scores_buf = top_prediction[0] indices_buf = top_prediction[1] # Project back into relative indices and beams - beams_buf = indices_buf // vocab_size + beams_buf = torch.div(indices_buf, vocab_size, rounding_mode='trunc') indices_buf = indices_buf.fmod(vocab_size) # At this point, beams_buf and indices_buf are single-dim and contain relative indices diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index db730c624a..4a441220e7 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -663,7 +663,7 @@ def finalize_hypos( cum_unfin.append(prev) cum_fin_tensor = torch.tensor(cum_unfin, dtype=torch.int).to(bbsz_idx) - unfin_idx = bbsz_idx // beam_size + unfin_idx = torch.div(bbsz_idx, beam_size, rounding_mode='trunc') sent = unfin_idx + torch.index_select(cum_fin_tensor, 0, unfin_idx) # Create a set of "{sent}{unfin_idx}", where From e55e094b969df89d43e68b797707ee8d3bac1c5a Mon Sep 17 00:00:00 2001 From: Igor Shalyminov <shalymin@amazon.de> Date: Mon, 28 Feb 2022 20:43:50 -0800 Subject: [PATCH 579/774] AddTargetDataset now first adds EOS then pads target sequences (#4243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) https://groups.google.com/g/fairseq-users/c/YoSm5J2To1A - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/4242 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4243 Reviewed By: arbabu123 Differential Revision: D34538164 Pulled By: alexeib fbshipit-source-id: cf2fdaa7663bee34571fb3d3bd9bdaf79d756206 --- fairseq/data/add_target_dataset.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fairseq/data/add_target_dataset.py b/fairseq/data/add_target_dataset.py index bf89f25656..1a9f80bc6a 100644 --- a/fairseq/data/add_target_dataset.py +++ b/fairseq/data/add_target_dataset.py @@ -54,22 +54,25 @@ def collater(self, samples): indices = set(collated["id"].tolist()) target = [s["label"] for s in samples if s["id"] in indices] + if self.add_to_input: + eos = torch.LongTensor([self.eos]) + prev_output_tokens = [torch.cat([eos, t], axis=-1) for t in target] + target = [torch.cat([t, eos], axis=-1) for t in target] + collated["net_input"]["prev_output_tokens"] = prev_output_tokens + if self.batch_targets: collated["target_lengths"] = torch.LongTensor([len(t) for t in target]) target = data_utils.collate_tokens(target, pad_idx=self.pad, left_pad=False) collated["ntokens"] = collated["target_lengths"].sum().item() + collated["net_input"]["prev_output_tokens"] = data_utils.collate_tokens( + collated["net_input"]["prev_output_tokens"], + pad_idx=self.pad, + left_pad=False + ) else: collated["ntokens"] = sum([len(t) for t in target]) collated["target"] = target - - if self.add_to_input: - eos = target.new_full((target.size(0), 1), self.eos) - collated["target"] = torch.cat([target, eos], dim=-1).long() - collated["net_input"]["prev_output_tokens"] = torch.cat( - [eos, target], dim=-1 - ).long() - collated["ntokens"] += target.size(0) return collated def filter_indices_by_size(self, indices, max_sizes): From 1479d311d54a4abb4db6fa7bfd14150789dbc7a6 Mon Sep 17 00:00:00 2001 From: Ann Lee <annl@fb.com> Date: Wed, 2 Mar 2022 12:19:20 -0800 Subject: [PATCH 580/774] update s2st vocoder training instructions (#3156) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? release training instructions for unit-based HiFi-GAN vocoder with duration prediction ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3156 Reviewed By: sravyapopuri388 Differential Revision: D34582951 Pulled By: an918tw fbshipit-source-id: 2e575fb15aa8cd5444272c3c31426ac64da84e97 --- examples/speech_to_speech/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_to_speech/README.md b/examples/speech_to_speech/README.md index 2a055a605b..b693c5f64b 100644 --- a/examples/speech_to_speech/README.md +++ b/examples/speech_to_speech/README.md @@ -119,7 +119,7 @@ fairseq-train $DATA_ROOT \ **Unit-based HiFi-GAN vocoder** -Coming soon. +The vocoder is trained with the [speech-resynthesis repo](https://github.com/facebookresearch/speech-resynthesis). See [here](https://github.com/facebookresearch/speech-resynthesis/tree/main/examples/speech_to_speech_translation) for instructions on how to train the unit-based HiFi-GAN vocoder with duration prediction. The same vocoder can support waveform generation for both _reduced_ unit sequences (with `--dur-prediction` set during inference) and original unit sequences. ## Inference From 2e0b961a0e3233eba39f9ea473cb4f56dcdf3bd8 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <wnhsu@csail.mit.edu> Date: Wed, 2 Mar 2022 23:58:52 -0800 Subject: [PATCH 581/774] fix import_user_module (#3144) Summary: ## What does this PR do? Avoid throwing ValueError when attempting to load a user defined module from common.user_dir that has the same module name and same module path as some loaded module. This occurs when a job is preempted and restarts using submitit_slurm X-link: https://github.com/fairinternal/fairseq-py/pull/3144 Reviewed By: Abdel-rahmanMohamed Differential Revision: D34521450 Pulled By: wnhsu fbshipit-source-id: eed00d4238a66dc524eee400a55ad2c011e1543c --- fairseq/data/add_target_dataset.py | 2 +- fairseq/search.py | 2 +- fairseq/sequence_generator.py | 2 +- fairseq/utils.py | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fairseq/data/add_target_dataset.py b/fairseq/data/add_target_dataset.py index 1a9f80bc6a..97ab9d32c2 100644 --- a/fairseq/data/add_target_dataset.py +++ b/fairseq/data/add_target_dataset.py @@ -67,7 +67,7 @@ def collater(self, samples): collated["net_input"]["prev_output_tokens"] = data_utils.collate_tokens( collated["net_input"]["prev_output_tokens"], pad_idx=self.pad, - left_pad=False + left_pad=False, ) else: collated["ntokens"] = sum([len(t) for t in target]) diff --git a/fairseq/search.py b/fairseq/search.py index 226f08fe40..a71e78019f 100644 --- a/fairseq/search.py +++ b/fairseq/search.py @@ -137,7 +137,7 @@ def step( scores_buf = top_prediction[0] indices_buf = top_prediction[1] # Project back into relative indices and beams - beams_buf = torch.div(indices_buf, vocab_size, rounding_mode='trunc') + beams_buf = torch.div(indices_buf, vocab_size, rounding_mode="trunc") indices_buf = indices_buf.fmod(vocab_size) # At this point, beams_buf and indices_buf are single-dim and contain relative indices diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 4a441220e7..e7e02d8285 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -663,7 +663,7 @@ def finalize_hypos( cum_unfin.append(prev) cum_fin_tensor = torch.tensor(cum_unfin, dtype=torch.int).to(bbsz_idx) - unfin_idx = torch.div(bbsz_idx, beam_size, rounding_mode='trunc') + unfin_idx = torch.div(bbsz_idx, beam_size, rounding_mode="trunc") sent = unfin_idx + torch.index_select(cum_fin_tensor, 0, unfin_idx) # Create a set of "{sent}{unfin_idx}", where diff --git a/fairseq/utils.py b/fairseq/utils.py index 9dd9459507..4852f48863 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -501,6 +501,8 @@ def import_user_module(args): from fairseq.models import import_models import_models(models_path, f"{module_name}.models") + elif module_path in sys.modules[module_name].__path__: + logger.info(f"--user-dir={module_path} has already been imported.") else: raise ImportError( "Failed to import --user-dir={} because the corresponding module name " From 592c1227f4f5c1d1e90fe8f436bef8cbfb52ed49 Mon Sep 17 00:00:00 2001 From: Dmitry Vinnik <dmitryvinn@users.noreply.github.com> Date: Fri, 4 Mar 2022 16:28:09 -0800 Subject: [PATCH 582/774] docs: add social button in support of Ukraine (#4249) Summary: Our mission at Meta Open Source is to empower communities through open source, and we believe that it means building a welcoming and safe environment for all. As a part of this work, we are adding this banner in support for Ukraine during this crisis. Pull Request resolved: https://github.com/pytorch/fairseq/pull/4249 Reviewed By: arbabu123 Differential Revision: D34635479 Pulled By: dmitryvinn-fb fbshipit-source-id: 488d30f0967ae9542ead968c5cb951ecf0e02a64 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f1db14a96e..b4a848ecf2 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ <img src="docs/fairseq_logo.png" width="150"> <br /> <br /> + <a href="https://opensource.fb.com/support-ukraine"><img alt="Support Ukraine" src="https://img.shields.io/badge/Support-Ukraine-FFD500?style=flat&labelColor=005BBB" /></a> <a href="https://github.com/pytorch/fairseq/blob/main/LICENSE"><img alt="MIT License" src="https://img.shields.io/badge/license-MIT-blue.svg" /></a> <a href="https://github.com/pytorch/fairseq/releases"><img alt="Latest Release" src="https://img.shields.io/github/release/pytorch/fairseq.svg" /></a> <a href="https://github.com/pytorch/fairseq/actions?query=workflow:build"><img alt="Build Status" src="https://github.com/pytorch/fairseq/workflows/build/badge.svg" /></a> From 0f078de343d985e0cba6a5c1dc8a6394698c95c7 Mon Sep 17 00:00:00 2001 From: Wei Ho <weiho@fb.com> Date: Mon, 7 Mar 2022 17:04:45 -0800 Subject: [PATCH 583/774] Re-land D34058196 [sacrebleu==2.0.0] buckification [Back out D34503161] Reviewed By: shreyanb98 Differential Revision: D34541824 fbshipit-source-id: 1dffc28bca971310920e1b1fdfe4016cc1aa1ceb --- examples/translation_moe/score.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/translation_moe/score.py b/examples/translation_moe/score.py index 9a529a9850..e45b2cb62e 100644 --- a/examples/translation_moe/score.py +++ b/examples/translation_moe/score.py @@ -17,8 +17,8 @@ from itertools import chain import numpy as np -from sacrebleu import compute_bleu, corpus_bleu as _corpus_bleu - +import sacrebleu +from sacrebleu import corpus_bleu as _corpus_bleu def main(): parser = argparse.ArgumentParser(sys.argv[0]) @@ -119,7 +119,7 @@ def sentence_bleu(hypothesis, reference): for i in range(1, 4): bleu.counts[i] += 1 bleu.totals[i] += 1 - bleu = compute_bleu( + bleu = sacrebleu.BLEU.compute_bleu( bleu.counts, bleu.totals, bleu.sys_len, From d03f4e771484a433f025f47744017c2eb6e9c6bc Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Fri, 11 Mar 2022 09:23:12 -0800 Subject: [PATCH 584/774] Minor fixes (#3198) Summary: - Fix error introduced in https://github.com/pytorch/fairseq/commit/e55e094b969df89d43e68b797707ee8d3bac1c5a in the case where net_input doesn't have prev_output_tokens key - Fix typo in covost README. X-link: https://github.com/fairinternal/fairseq-py/pull/3198 Reviewed By: cndn, kahne Differential Revision: D34810092 Pulled By: sravyapopuri388 fbshipit-source-id: 9be6e6f06586cd2a2d44415ebf7c3596a5334b81 --- examples/speech_to_text/docs/covost_example.md | 2 +- fairseq/data/add_target_dataset.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/speech_to_text/docs/covost_example.md b/examples/speech_to_text/docs/covost_example.md index 2dd41c3c55..6282428b16 100644 --- a/examples/speech_to_text/docs/covost_example.md +++ b/examples/speech_to_text/docs/covost_example.md @@ -129,7 +129,7 @@ Type in WAV/FLAC/OGG audio paths (one per line) after the prompt. | --arch | --pos-enc-type | Params | ASR PT | Fr-En | De-En | Es-En | Ca-En | En-De | En-Ca | En-Fa | En-Et | Model | |---|---|---|---|---|---|---|---|---|---|---|---|---| -| s2t_transformer | - | 31M | No | [27.2](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_transformer_s.pt) | [17.7](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_transformer_s.pt) | [23.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_transformer_s.pt) | [19.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_transformer_s.pt) | [16.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_transformer_s.pt) | [21.6](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_transformer_s.pt) | [12.9](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_transformer_s.pt) | [12.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_transformer_s.pt) | (<-Download) | +| s2t_transformer | - | 31M | Yes | [27.2](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_fr_en_st_transformer_s.pt) | [17.7](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_de_en_st_transformer_s.pt) | [23.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_es_en_st_transformer_s.pt) | [19.3](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_ca_en_st_transformer_s.pt) | [16.1](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_de_st_transformer_s.pt) | [21.6](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_ca_st_transformer_s.pt) | [12.9](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_fa_st_transformer_s.pt) | [12.8](https://dl.fbaipublicfiles.com/fairseq/s2t/covost2_en_et_st_transformer_s.pt) | (<-Download) | | s2t_conformer | rel_pos | 42.9M | No | [28.32](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [18.21](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [25.98](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [21.13](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [20.37](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [25.89](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [15.59](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | [14.49](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/rel_pos_from_scratch_avg_last_10_checkpoint.pt) | (<-Download) | | s2t_conformer | rel_pos | 42.9M | Yes| [27.15](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [18.22](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [25.14](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [21.68](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [20.35](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [25.92](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [15.76](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | [16.52](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/rel_pos_asr_pt_avg_last_10_checkpoint.pt) | (<-Download) | | s2t_conformer | rope | 42.1M | No | [27.61](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/fr_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [17.6](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/de_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [24.91](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/es_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [20.78](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/ca_en/rope_from_scratch_avg_last_10_checkpoint.pt) | [19.7](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_de/rope_from_scratch_avg_last_10_checkpoint.pt) | [25.13](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_ca/rope_from_scratch_avg_last_10_checkpoint.pt) | [15.22](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_fa/rope_from_scratch_avg_last_10_checkpoint.pt) | [15.87](https://dl.fbaipublicfiles.com/fairseq/conformer/covost2/en_et/rope_from_scratch_avg_last_10_checkpoint.pt) | (<-Download) | diff --git a/fairseq/data/add_target_dataset.py b/fairseq/data/add_target_dataset.py index 97ab9d32c2..978a5b1903 100644 --- a/fairseq/data/add_target_dataset.py +++ b/fairseq/data/add_target_dataset.py @@ -64,11 +64,12 @@ def collater(self, samples): collated["target_lengths"] = torch.LongTensor([len(t) for t in target]) target = data_utils.collate_tokens(target, pad_idx=self.pad, left_pad=False) collated["ntokens"] = collated["target_lengths"].sum().item() - collated["net_input"]["prev_output_tokens"] = data_utils.collate_tokens( - collated["net_input"]["prev_output_tokens"], - pad_idx=self.pad, - left_pad=False, - ) + if getattr(collated["net_input"], "prev_output_tokens", None): + collated["net_input"]["prev_output_tokens"] = data_utils.collate_tokens( + collated["net_input"]["prev_output_tokens"], + pad_idx=self.pad, + left_pad=False, + ) else: collated["ntokens"] = sum([len(t) for t in target]) From f9d07a920930a58d3177a201a26ff5392506f223 Mon Sep 17 00:00:00 2001 From: Hongyu Gong <51180284+hygong-fb@users.noreply.github.com> Date: Mon, 14 Mar 2022 09:06:49 -0700 Subject: [PATCH 585/774] support tgt_lang_tag in speech-to-speech (#3187) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Support tgt-lang-tag in speech-to-speech task. 1. If we set prepend_tgt_lang_tag: true, a dictionary with units and lang tags would be loaded from vocab_filename; otherwise, a dictionary is created with units only in setup_task. 2. prepend_tgt_lang_tag would add the target language token to the beginning of prev_output_tokens during data loading. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3187 Reviewed By: yuntang Differential Revision: D34768755 Pulled By: hygong-fb fbshipit-source-id: fa395c3319907221f95333283689671b194f3ccc --- fairseq/data/audio/data_cfg.py | 3 +- .../data/audio/speech_to_speech_dataset.py | 25 +++++++- fairseq/tasks/speech_to_speech.py | 57 +++++++++++++++++-- 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 0396e6a346..cc61e0fcdf 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -158,7 +158,8 @@ class S2SDataConfig(S2TDataConfig): @property def vocab_filename(self): - return None + """fairseq vocabulary file under data root""" + return self.config.get("vocab_filename", None) @property def pre_tokenizer(self) -> Dict: diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py index 3fed098375..74d778190b 100644 --- a/fairseq/data/audio/speech_to_speech_dataset.py +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -32,6 +32,7 @@ class SpeechToSpeechDatasetItem(object): source: torch.Tensor target: Optional[torch.Tensor] = None target_speaker: Optional[torch.Tensor] = None + tgt_lang_tag: Optional[int] = None class SpeechToSpeechDataset(SpeechToTextDataset): @@ -44,6 +45,8 @@ def __init__( src_n_frames: List[int], tgt_audio_paths: List[str], tgt_n_frames: List[int], + src_langs: Optional[List[str]] = None, + tgt_langs: Optional[List[str]] = None, ids: Optional[List[str]] = None, target_is_code: bool = False, tgt_dict: Dictionary = None, @@ -59,6 +62,8 @@ def __init__( ids=ids, tgt_dict=tgt_dict, tgt_texts=tgt_texts, + src_langs=src_langs, + tgt_langs=tgt_langs, n_frames_per_step=n_frames_per_step, ) @@ -108,6 +113,11 @@ def pack_units(self, input: torch.Tensor) -> torch.Tensor: def __getitem__(self, index: int) -> SpeechToSpeechDatasetItem: source = self._get_source_audio(index) + tgt_lang_tag = None + if self.cfg.prepend_tgt_lang_tag: + # prepend_tgt_lang_tag: modify prev_output_tokens instead of target + tgt_lang_tag = self.get_lang_tag_idx(self.tgt_langs[index], self.tgt_dict) + if not self.target_is_code: target = get_features_or_waveform(self.tgt_audio_paths[index]) target = torch.from_numpy(target).float() @@ -136,7 +146,9 @@ def __getitem__(self, index: int) -> SpeechToSpeechDatasetItem: tgt_spk = torch.FloatTensor([]) return SpeechToSpeechDatasetItem( - index=index, source=source, target=target, target_speaker=tgt_spk + index=index, source=source, target=target, + target_speaker=tgt_spk, + tgt_lang_tag=tgt_lang_tag ) def _collate_target(self, samples: List[SpeechToSpeechDatasetItem]) -> torch.Tensor: @@ -203,6 +215,9 @@ def collater( "prev_output_tokens": prev_output_tokens, "tgt_speaker": tgt_speakers, # TODO: unify "speaker" and "tgt_speaker" } + if self.tgt_texts is not None and samples[0].tgt_lang_tag is not None: + for i in range(len(samples)): + net_input["prev_output_tokens"][i][0] = samples[order[i]].tgt_lang_tag out = { "id": indices, "net_input": net_input, @@ -321,6 +336,10 @@ class SpeechToSpeechDatasetCreator(object): # mandatory columns KEY_ID, KEY_SRC_AUDIO, KEY_SRC_N_FRAMES = "id", "src_audio", "src_n_frames" KEY_TGT_AUDIO, KEY_TGT_N_FRAMES = "tgt_audio", "tgt_n_frames" + # optional columns + KEY_SRC_LANG, KEY_TGT_LANG = "src_lang", "tgt_lang" + # default values + DEFAULT_LANG = "" @classmethod def _from_list( @@ -347,6 +366,8 @@ def _from_list( ] src_n_frames = [int(s[cls.KEY_SRC_N_FRAMES]) for s in samples] tgt_n_frames = [int(s[cls.KEY_TGT_N_FRAMES]) for s in samples] + src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] + tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] has_multitask = len(multitask) > 0 dataset_cls = ( @@ -361,6 +382,8 @@ def _from_list( src_n_frames, tgt_audio_paths, tgt_n_frames, + src_langs, + tgt_langs, ids, target_is_code, target_dictionary, diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index ed3a7ccd7d..61c68b0c09 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -14,6 +14,7 @@ from fairseq import utils from fairseq.data import Dictionary from fairseq.data.audio.data_cfg import S2SDataConfig, MultitaskConfig +from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset from fairseq.data.audio.speech_to_speech_dataset import SpeechToSpeechDatasetCreator from fairseq.tasks import LegacyFairseqTask, register_task from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion @@ -196,8 +197,14 @@ def add_args(cls, parser): choices=["griffin_lim", "hifigan", "code_hifigan"], ) parser.add_argument("--spec-bwd-max-iter", type=int, default=8) + parser.add_argument( + "--infer-target-lang", + type=str, + default="", + help="target language for inference" + ) - def __init__(self, args, tgt_dict): + def __init__(self, args, tgt_dict, infer_tgt_lang_id=None): super().__init__(args) self.tgt_dict = tgt_dict self.data_cfg = S2SDataConfig(Path(args.data) / args.config_yaml) @@ -210,16 +217,34 @@ def __init__(self, args, tgt_dict): self.multitask_tasks[task_name] = DummyMultiTask( task_config, task_config.tgt_dict ) + self._infer_tgt_lang_id = infer_tgt_lang_id @classmethod def setup_task(cls, args, **kwargs): + data_cfg = data_cfg = S2SDataConfig(Path(args.data) / args.config_yaml) tgt_dict = None + infer_tgt_lang_id = None if args.target_is_code: - assert args.target_code_size is not None + if data_cfg.prepend_tgt_lang_tag: + # dictionary with language tags + dict_path = Path(args.data) / data_cfg.vocab_filename + if not dict_path.is_file(): + raise FileNotFoundError(f"Dict has to be provided when setting prepend_tgt_lang_tag: true, but dict not found: {dict_path}") + tgt_dict = Dictionary.load(dict_path.as_posix()) + + # target langauge for inference + if args.infer_target_lang != "": + tgt_lang_tag = SpeechToTextDataset.LANG_TAG_TEMPLATE.format( + args.infer_target_lang + ) + infer_tgt_lang_id = tgt_dict.index(tgt_lang_tag) + assert infer_tgt_lang_id != tgt_dict.unk() + else: + assert args.target_code_size is not None - tgt_dict = Dictionary() - for i in range(args.target_code_size): - tgt_dict.add_symbol(str(i)) + tgt_dict = Dictionary() + for i in range(args.target_code_size): + tgt_dict.add_symbol(str(i)) logger.info(f"dictionary size: " f"{len(tgt_dict):,}") if getattr(args, "train_subset", None) is not None: @@ -233,7 +258,7 @@ def setup_task(cls, args, **kwargs): or (not args.target_is_code and args.vocoder != "code_hifigan") ) - return cls(args, tgt_dict) + return cls(args, tgt_dict, infer_tgt_lang_id=infer_tgt_lang_id) def build_criterion(self, args): from fairseq import criterions @@ -433,6 +458,26 @@ def valid_step_with_inference(self, sample, model, generator): return hypos, losses + def inference_step( + self, generator, models, sample, prefix_tokens=None, constraints=None + ): + with torch.no_grad(): + if self._infer_tgt_lang_id is not None: + return generator.generate( + models, + sample, + prefix_tokens=prefix_tokens, + constraints=constraints, + bos_token=self._infer_tgt_lang_id + ) + else: + return super().inference_step( + generator, + models, + sample, + prefix_tokens=prefix_tokens, + constraints=constraints + ) class DummyMultiTask(LegacyFairseqTask): def __init__(self, args, tgt_dict): From b554f5ec9067c2f88bf17a736ddb57ea1cab14cc Mon Sep 17 00:00:00 2001 From: Hongyu Gong <hygong@fb.com> Date: Tue, 15 Mar 2022 22:55:21 -0700 Subject: [PATCH 586/774] replace "prepend-tgt-lang-tag" with "prepend-tgt-lang-tag-as-bos" to avoid confusion Summary: Replace "prepend-tgt-lang-tag" with "prepend-tgt-lang-tag-as-bos" in s2s data loading and s2s task. Reviewed By: yuntang Differential Revision: D34912239 fbshipit-source-id: 654d0eafafc275be6c2470b08a323f57a4f9b9cb --- fairseq/data/audio/data_cfg.py | 5 +++++ fairseq/data/audio/speech_to_speech_dataset.py | 4 ++-- fairseq/tasks/speech_to_speech.py | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index cc61e0fcdf..861fd767ff 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -192,6 +192,11 @@ def target_speaker_embed(self): """Target speaker embedding file (one line per target audio sample)""" return self.config.get("target_speaker_embed", None) + @property + def prepend_tgt_lang_tag_as_bos(self) -> bool: + """Prepend target lang ID token as the target BOS.""" + return self.config.get("prepend_tgt_lang_tag_as_bos", False) + class MultitaskConfig(object): """Wrapper class for data config YAML""" diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py index 74d778190b..04a36bea90 100644 --- a/fairseq/data/audio/speech_to_speech_dataset.py +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -114,8 +114,8 @@ def __getitem__(self, index: int) -> SpeechToSpeechDatasetItem: source = self._get_source_audio(index) tgt_lang_tag = None - if self.cfg.prepend_tgt_lang_tag: - # prepend_tgt_lang_tag: modify prev_output_tokens instead of target + if self.cfg.prepend_tgt_lang_tag_as_bos: + # prepend_tgt_lang_tag_as_bos: put tgt_lang_tag as bos of target tgt_lang_tag = self.get_lang_tag_idx(self.tgt_langs[index], self.tgt_dict) if not self.target_is_code: diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index 61c68b0c09..211bf1d4f1 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -225,11 +225,11 @@ def setup_task(cls, args, **kwargs): tgt_dict = None infer_tgt_lang_id = None if args.target_is_code: - if data_cfg.prepend_tgt_lang_tag: + if data_cfg.prepend_tgt_lang_tag_as_bos: # dictionary with language tags dict_path = Path(args.data) / data_cfg.vocab_filename if not dict_path.is_file(): - raise FileNotFoundError(f"Dict has to be provided when setting prepend_tgt_lang_tag: true, but dict not found: {dict_path}") + raise FileNotFoundError(f"Dict has to be provided when setting prepend_tgt_lang_tag_as_bos: true, but dict not found: {dict_path}") tgt_dict = Dictionary.load(dict_path.as_posix()) # target langauge for inference From f71c03fba8fd441198b1714e1d3d47bb89cdd888 Mon Sep 17 00:00:00 2001 From: Wei Ho <weiho@fb.com> Date: Thu, 24 Mar 2022 11:33:07 -0700 Subject: [PATCH 587/774] Don't fsdp_wrap transformer encoder & decoder Summary: Per anj-s 's suggestion - this seems to fix the ``` assert len(self.flat_params) == 1, "Incorrect access to flat_param" AssertionError: Incorrect access to flat_param ``` error when training transformer models w/ large number of params ~~(not sure why the number of params affect fairscale FSDP wrapping???)~~ Did this maybe only manifest when the encoder/decoder individually had > 1e8 params due to the default of `min_params_to_wrap`? Looking at D26771144 (https://github.com/pytorch/fairseq/commit/656d7e5779a9ec4ccf0ad45d86a4ce589c597588) & https://github.com/fairinternal/fairseq-py/pull/1667 where this code was added - it's unclear why wrapping was specifically necessary when share_all_embeddings=False? Is it OK to just delete this code? (And did the gshard model avoid this issue b/c it used share_all_embeddings=True?) Reviewed By: huihuifan Differential Revision: D35084649 fbshipit-source-id: ad5b394c9920e3bea2767a0771f6de36aecb3687 --- fairseq/models/transformer/transformer_base.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fairseq/models/transformer/transformer_base.py b/fairseq/models/transformer/transformer_base.py index 0cbbccbc5a..5e025c9058 100644 --- a/fairseq/models/transformer/transformer_base.py +++ b/fairseq/models/transformer/transformer_base.py @@ -96,10 +96,6 @@ def build_model(cls, cfg, task): cfg.checkpoint_activations = True # offloading implies checkpointing encoder = cls.build_encoder(cfg, src_dict, encoder_embed_tokens) decoder = cls.build_decoder(cfg, tgt_dict, decoder_embed_tokens) - if not cfg.share_all_embeddings: - # fsdp_wrap is a no-op when --ddp-backend != fully_sharded - encoder = fsdp_wrap(encoder, min_num_params=cfg.min_params_to_wrap) - decoder = fsdp_wrap(decoder, min_num_params=cfg.min_params_to_wrap) return cls(cfg, encoder, decoder) @classmethod From 7b9118bd93f0c80d9bc70133590ea867114e4549 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Fri, 25 Mar 2022 11:52:07 -0700 Subject: [PATCH 588/774] Open source code for "Enhanced Direct Speech-to-Speech Translation Using Self-supervised Pre-training and Data Augmentation" (#3233) Summary: OSS "Enhanced Direct Speech-to-Speech Translation Using Self-supervised Pre-training and Data Augmentation" paper code - Update xm_transformer to add a new arguments called encoder_proj (which ensures the encoder embedding dim and decoder embedding dim are matched) and max_positions (related to embedding size of conformer). - Add documentation and pretrained models related to the paper X-link: https://github.com/fairinternal/fairseq-py/pull/3233 Reviewed By: pipibjc Differential Revision: D35119604 Pulled By: sravyapopuri388 fbshipit-source-id: bbe517c4803c5808f8cce0e5d16cf5ffa96f425c --- .../enhanced_direct_s2st_discrete_units.md | 103 ++++++++++++++++++ .../models/speech_to_text/xm_transformer.py | 16 ++- 2 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md diff --git a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md new file mode 100644 index 0000000000..a0fc8180d6 --- /dev/null +++ b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md @@ -0,0 +1,103 @@ +# Speech to speech translation (S2ST) + +We provide the implementation for speech-to-unit translation (S2UT) proposed in [_Enhanced Direct Speech-to-Speech Translation Using Self-supervised Pre-training and Data Augmentation_](arxiv link) and the various pretrained models used. + +## Pretrained Models + +### Unit extraction +We used the multilingual HuBERT model open sourced in [Textless S2ST with Real Data](textless_s2st_real_data.md) + +### Wav2vec 2.0 +Language | Block type | Model size | Dataset | Model | +--- | --- | --- | --- | --- | +Es | Transformer | BASE | Voxpopuli | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/transformer_B.pt) | +Es | Transformer | LARGE | Voxpopuli | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/transformer_L.pt) | +Es | Conformer | LARGE | Voxpopuli | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/conformer_L.pt) | +En | Transformer | BASE | Librilight| [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/en/transformer_B.pt) | +En | Conformer | LARGE | Librilight | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/en/conformer_L.pt) | + +### Unit mBART +Unit size | Dataset | Unit config | Model | +--- | --- | --- | --- | +1000 | [Voxpopuli](https://aclanthology.org/2021.acl-long.80) En, Es unlabelled speech | [mbart_large](https://github.com/pytorch/fairseq/blob/f591cc94caa85098ccf125a4782f91125b6a086d/fairseq/models/bart/model.py#L368) |[ckpt](htpps://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/unit_mBART/checkpoint.pt) | + + +## Data preparation + +1. To prepare data for S2UT finetuning, follow the steps from [Direct S2ST with Discrete Units](./direct_s2st_discrete_units.md) and format the data in the _S2UT_ format. Note that we use 1000 units from the eleventh layer (`--layer 11`) of the multilingual hubert model linked above instead +2. Run +``` +var="id\taudio\tn_frames\ttgt_text\ttgt_n_frames" +sed -i "1s/.*/$var/" ${SPLIT}.tsv +``` + +## Training + +**Speech-to-unit translation (S2UT)** + +Here's an example for finetuning S2UT models with 1000 discrete units as target. You can download the config file and vocabulary from here[add links]: +``` +fairseq-train $DATA_ROOT \ + --config-yaml config.yaml \ + --task speech_to_text --arch xm_transformer\ + --criterion l --label-smoothing 0.2 \ + --share-decoder-input-output-embed --adaptor-n-layers 1 --normalize\ + --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.1 \ + --train-subset train --valid-subset dev \ + --load-pretrained-decoder-from ${unit_mBART} --w2v-path ${wav2vec2.0} \ + --mask-prob 0.3 --mask-channel-length 32 --mask-channel-prob 0.25\ + --save-dir ${MODEL_DIR} --checkpoint-activations --encoder-proj \ + --lr 0.0005 --dropout 0.1 --attention-dropout 0.1 --lr-scheduler inverse_sqrt\ + --warmup-init-lr 1e-7 --warmup-updates 10000 \ + --optimizer adam --adam-betas "(0.9,0.98)" --clip-norm 10.0 \ + --max-update 20000 --max-tokens 4000 --max-tokens-valid 4000 --max-source-positions 4000 \ + --max-target-positions 4000 --update-freq 120 \ + --seed 1 --fp16 --num-workers 1 +``` +* Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 15` to simulate training with 120 GPUs. +* In the above setting we finetune the model end to end, corresponding to the full setup in the paper. +* To apply LNA-E partial finetuning, add `--finetune-w2v-params layer_norm,self_attn` +* For LNA-D partial finetuning add `--finetune-decoder-params encoder_attn,layer_norm,self_attn`. To optionally freeze the encoder by k updates, use `--freeze-finetune-updates ${K}` +* For LNA-E,D partial finetuning add both the above options. + + +**Unit-based HiFi-GAN vocoder** + +We apply the open-sourced unit-based HiFi-GAN vocoders to convert the predicted unit sequences to waveform. They are open sourced in [Textless S2ST with Real Data](textless_s2st_real_data.md) + +## Inference + +**Speech-to-unit translation (S2UT)** + +1. Follow the same inference process as in [fairseq-S2T](https://github.com/pytorch/fairseq/tree/main/examples/speech_to_text) to generate unit sequences (`${RESULTS_PATH}/generate-${GEN_SUBSET}.txt`). +``` +fairseq-generate $DATA_ROOT \ + --config-yaml config.yaml \ + --task speech_to_text \ + --path $MODEL_DIR/checkpoint_best.pt --gen-subset $GEN_SUBSET \ + --max-tokens 10000 --max-source-positions 10000 --max-target-positions 10000\ + --beam 10 --max-len-a 1 --max-len-b 200 \ + --results-path ${RESULTS_PATH} +``` + +2. Convert unit sequences to waveform. +``` +grep "^D\-" ${RESULTS_PATH}/generate-${GEN_SUBSET}.txt | \ + sed 's/^D-//ig' | sort -nk1 | cut -f3 \ + > ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit + +python examples/speech_to_speech/generate_waveform_from_code.py \ + --in-code-file ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit \ + --vocoder $VOCODER_CKPT --vocoder-cfg $VOCODER_CFG \ + --results-path ${RESULTS_PATH} --dur-prediction +``` + + +## Evaluation + +To evaluate speech translation output, we first apply ASR on the speech output and then compute BLEU score betweent the ASR decoded text and the references using sacreBLEU. + +* Text normalization: We use the text cleaner at [https://github.com/keithito/tacotron](https://github.com/keithito/tacotron) for pre-processing reference English text for ASR BLEU evaluation. The text cleaner used for Spanish text normalization will be updated here shortly. +* En ASR: We use the "[Wav2Vec 2.0 Large (LV-60) + Self Training / 960 hours / Libri-Light + Librispeech](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt)" En ASR model open-sourced by the [wav2vec](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec) project. The model is also available on [Hugging Face](https://huggingface.co/facebook/wav2vec2-large-960h-lv60-self). +* Es ASR: We use the [Wav2Vec2-Large-XLSR-53-Spanish](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) finetuned on spanish Common Voice Es ASR model open-sourced by Jonatasgrosman(https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish) on [Hugging Face](https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish). +* See [instructions](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#evaluating-a-ctc-model) on how to run inference with a wav2vec-based ASR model. diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index 5d6f162d3e..afd8ead93b 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -229,6 +229,14 @@ def add_wav2vec_asr_args(parser): type=float, help="probability of dropping a layer in wav2vec 2.0", ) + parser.add_argument( + "--max-positions", + type=int, + help="Max input positions to be used in the conformer encoder in wav2vec 2.0", + ) + + parser.add_argument("--encoder-proj", action="store_true") + parser.add_argument("--w2v-args", default=None) @@ -507,7 +515,7 @@ def maybe_load_pretrained(cls, component, checkpoint: Optional[str] = None): @classmethod def build_encoder(cls, args): _args = copy.deepcopy(args) - if not args.adaptor_proj: # V0 arch + if not args.adaptor_proj and not args.encoder_proj: # V0 arch state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) if state.get("cfg") is not None: encoder_embed_dim = state["cfg"]._content["model"]["encoder_embed_dim"] @@ -526,12 +534,11 @@ def build_encoder(cls, args): @classmethod def build_decoder(cls, args, task, embed_tokens): _args = copy.deepcopy(args) - if args.adaptor_proj: # not V0 arch + if args.adaptor_proj or args.encoder_proj: # not V0 arch _args.encoder_embed_dim = _args.decoder_embed_dim _args.dropout = args.decoder_dropout _args.attention_dropout = args.decoder_attention_dropout _args.activation_dropout = args.decoder_activation_dropout - _args.max_target_positions = 1024 decoder = TransformerDecoder(_args, task.target_dictionary, embed_tokens) decoder = cls.maybe_load_pretrained( @@ -587,7 +594,6 @@ def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): def upgrade_state_dict(self, state_dict): for k, _ in state_dict.items(): if "adaptor.layers" in state_dict: - print(k) new = k.replace("adaptor.layers", "adaptor_layers") state_dict[new] = state_dict[k] del state_dict[k] @@ -601,6 +607,7 @@ def set_default_w2v_encoder_args(args): args.dropout = getattr(args, "dropout", 0) args.attention_dropout = getattr(args, "attention_dropout", 0) args.activation_dropout = getattr(args, "activation_dropout", 0) + args.encoder_proj = getattr(args, "encoder_proj", False) args.mask_length = getattr(args, "mask_length", 10) args.mask_prob = getattr(args, "mask_prob", 0.5) @@ -674,6 +681,7 @@ def set_default_general_args(args): args.checkpoint_activations = getattr(args, "checkpoint_activations", False) args.offload_activations = getattr(args, "offload_activations", False) args.min_params_to_wrap = getattr(args, "min_params_to_wrap", int(1e8)) + args.max_positions = getattr(args, "max_positions", 3000) @register_model_architecture(model_name="xm_transformer", arch_name="xm_transformer") From e9b89525b53cebdb38e5b009728f153e078a6dfd Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@fb.com> Date: Fri, 25 Mar 2022 16:18:47 -0700 Subject: [PATCH 589/774] Fix an indentation issue for decoder sweep config Summary: As per title Created from CodeHub with https://fburl.com/edit-in-codehub Reviewed By: arbabu123 Differential Revision: D35151134 fbshipit-source-id: bb97ae583542c8e7983b9d9042d8a3084b8fbef5 --- examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml b/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml index 9a6935b93e..38e9c221db 100644 --- a/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml +++ b/examples/speech_recognition/new/conf/hydra/sweeper/ax.yaml @@ -24,6 +24,6 @@ ax_config: decoding.wordscore: type: range bounds: [-5.0, 5.0] - decoding.silweight: - type: range - bounds: [ -8.0, 0.0 ] + decoding.silweight: + type: range + bounds: [ -8.0, 0.0 ] From 52658402c5f37ccc4c6b796c44c0115af3b6eca1 Mon Sep 17 00:00:00 2001 From: Changhan Wang <changhan@fb.com> Date: Fri, 25 Mar 2022 18:01:44 -0700 Subject: [PATCH 590/774] add CTC auxiliary loss to S2T Transformer Summary: Add CTC auxiliary loss to S2T Transformer Reviewed By: sravyapopuri388 Differential Revision: D33305481 fbshipit-source-id: d866a924e39beb03a2f8a59f7051b6c81980ad35 --- .../label_smoothed_cross_entropy_with_ctc.py | 82 +++++++++++++++++++ .../models/speech_to_text/s2t_transformer.py | 25 +++++- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py diff --git a/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py b/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py new file mode 100644 index 0000000000..01b040b29c --- /dev/null +++ b/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py @@ -0,0 +1,82 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from dataclasses import dataclass, field + +import torch +import torch.nn.functional as F + +from fairseq import metrics, utils +from fairseq.criterions import register_criterion +from fairseq.criterions.label_smoothed_cross_entropy import ( + LabelSmoothedCrossEntropyCriterion, LabelSmoothedCrossEntropyCriterionConfig +) +from fairseq.data.data_utils import lengths_to_mask + + +@dataclass +class LabelSmoothedCrossEntropyWithCtcCriterionConfig(LabelSmoothedCrossEntropyCriterionConfig): + ctc_weight: float = field(default=1.0, metadata={"help": "weight for CTC loss"}) + + +@register_criterion( + "label_smoothed_cross_entropy_with_ctc", + dataclass=LabelSmoothedCrossEntropyWithCtcCriterionConfig +) +class LabelSmoothedCrossEntropyWithCtcCriterion(LabelSmoothedCrossEntropyCriterion): + def __init__( + self, task, sentence_avg, label_smoothing, ignore_prefix_size, + report_accuracy, ctc_weight + ): + super().__init__( + task, sentence_avg, label_smoothing, ignore_prefix_size, + report_accuracy + ) + self.ctc_weight = ctc_weight + + def forward(self, model, sample, reduce=True): + net_output = model(**sample["net_input"]) + loss, nll_loss = self.compute_loss(model, net_output, sample, reduce=reduce) + + ctc_loss = torch.tensor(0.).type_as(loss) + if self.ctc_weight > 0.: + ctc_lprobs, ctc_lens = model.get_ctc_output(net_output, sample) + ctc_tgt, ctc_tgt_lens = model.get_ctc_target(sample) + ctc_tgt_mask = lengths_to_mask(ctc_tgt_lens) + ctc_tgt_flat = ctc_tgt.masked_select(ctc_tgt_mask) + reduction = "sum" if reduce else "none" + ctc_loss = F.ctc_loss( + ctc_lprobs, ctc_tgt_flat, ctc_lens, ctc_tgt_lens, + reduction=reduction, zero_infinity=True + ) * self.ctc_weight + loss += ctc_loss + + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + logging_output = { + "loss": utils.item(loss.data), + "nll_loss": utils.item(nll_loss.data), + "ctc_loss": utils.item(ctc_loss.data), + "ntokens": sample["ntokens"], + "nsentences": sample["target"].size(0), + "sample_size": sample_size, + } + if self.report_accuracy: + n_correct, total = self.compute_accuracy(model, net_output, sample) + logging_output["n_correct"] = utils.item(n_correct.data) + logging_output["total"] = utils.item(total.data) + return loss, sample_size, logging_output + + @classmethod + def reduce_metrics(cls, logging_outputs) -> None: + super().reduce_metrics(logging_outputs) + loss_sum = sum(log.get("ctc_loss", 0) for log in logging_outputs) + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + + metrics.log_scalar( + "ctc_loss", loss_sum / sample_size / math.log(2), sample_size, round=3 + ) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 33c30e1b0b..4ffbeaeecb 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -275,6 +275,7 @@ def build_embedding(dictionary, embed_dim): decoder_embed_tokens = build_embedding( task.target_dictionary, args.decoder_embed_dim ) + args.tgt_dict_size = len(task.target_dictionary) encoder = cls.build_encoder(args) decoder = cls.build_decoder(args, task, decoder_embed_tokens) return cls(encoder, decoder) @@ -290,6 +291,23 @@ def get_normalized_probs( lprobs.batch_first = True return lprobs + def get_ctc_target(self, sample: Optional[Dict[str, Tensor]]): + return sample["target"], sample["target_lengths"] + + def get_ctc_output( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + sample: Optional[Dict[str, Tensor]] + ): + encoder_out = net_output[1]["encoder_out"]["encoder_out"][0] + logits = self.encoder.ctc_proj(encoder_out) # T x B x C + out = utils.log_softmax(logits.float(), dim=-1) + padding_mask = net_output[1]["encoder_out"]["encoder_padding_mask"] + lens = out.new_full((out.shape[1], ), out.shape[0]).long() + if len(padding_mask) > 0: + lens -= padding_mask[0].sum(dim=-1) + return out, lens + def forward(self, src_tokens, src_lengths, prev_output_tokens): """ The forward method inherited from the base class has a **kwargs @@ -340,6 +358,10 @@ def __init__(self, args): else: self.layer_norm = None + self.ctc_proj = None + if getattr(args, "ctc_weight", 0.) > 0.: + self.ctc_proj = nn.Linear(args.encoder_embed_dim, args.tgt_dict_size) + def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): x, input_lengths = self.subsample(src_tokens, src_lengths) x = self.embed_scale * x @@ -444,7 +466,8 @@ def extract_features( alignment_layer, alignment_heads, ) - return x, None + extra = {"encoder_out": encoder_out} if incremental_state is None else None + return x, extra @register_model_architecture(model_name="s2t_transformer", arch_name="s2t_transformer") From c8a8e2c39204cffff082be508bbfd60254f5f1b7 Mon Sep 17 00:00:00 2001 From: Ann Lee <annl@fb.com> Date: Mon, 28 Mar 2022 13:26:07 -0700 Subject: [PATCH 591/774] release pre-trained models (#3245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Releasing pre-trained mHuBERT, vocoder, speech normalizer for the paper "Textless Speech-to-Speech Translation on Real Data" # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3245 Reviewed By: sravyapopuri388 Differential Revision: D35135891 Pulled By: an918tw fbshipit-source-id: 96e0a6354dc61d5cbfce9943893bebadfb21b642 --- examples/speech_to_speech/README.md | 182 +----------------- .../docs/direct_s2st_discrete_units.md | 181 +++++++++++++++++ .../docs/textless_s2st_real_data.md | 89 +++++++++ .../preprocessing/data_utils.py | 18 ++ .../preprocessing/prep_s2ut_data.py | 24 +-- .../preprocessing/prep_sn_data.py | 88 +++++++++ .../preprocessing/prep_sn_output_data.py | 58 ++++++ 7 files changed, 442 insertions(+), 198 deletions(-) create mode 100644 examples/speech_to_speech/docs/direct_s2st_discrete_units.md create mode 100644 examples/speech_to_speech/docs/textless_s2st_real_data.md create mode 100644 examples/speech_to_speech/preprocessing/prep_sn_data.py create mode 100644 examples/speech_to_speech/preprocessing/prep_sn_output_data.py diff --git a/examples/speech_to_speech/README.md b/examples/speech_to_speech/README.md index b693c5f64b..48cce071ad 100644 --- a/examples/speech_to_speech/README.md +++ b/examples/speech_to_speech/README.md @@ -1,181 +1,5 @@ # Speech to speech translation (S2ST) -We provide the implementation for speech-to-unit translation (S2UT) proposed in "[Direct speech-to-speech translation with discrete units (Lee et al. 2021)](https://arxiv.org/abs/2107.05604)" and also the transformer-based implementation of the speech-to-spectrogram translation (S2SPECT, or transformer-based [Translatotron](https://arxiv.org/abs/1904.06037)) baseline in the paper. - -## Pretrained Models - -### Unit-based HiFi-GAN Vocoder -Unit config | Unit size | Vocoder dataset | Model -|---|---|---|--- -[HuBERT Base, Librispeech](https://github.com/fairinternal/fairseq-py/tree/main/examples/hubert), layer 6 | 100 | [LJSpeech](https://keithito.com/LJ-Speech-Dataset/) | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/hubert_base_100_lj/g_00500000), [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/hubert_base_100_lj/config.json) - - -## Data preparation -### Target speech -0. (optional) To prepare S2S data from a speech-to-text translation (ST) dataset, see [fairseq-S^2](https://github.com/pytorch/fairseq/tree/main/examples/speech_synthesis) for pre-trained TTS models and instructions on how to train and decode TTS models. -1. Prepare two folders, `$SRC_AUDIO` and `$TGT_AUDIO`, with `${SPLIT}/${SAMPLE_ID}.wav` for source and target speech under each folder, separately. Note that for S2UT experiments, target audio sampling rate should be in 16,000 Hz, and for S2SPECT experiments, target audio sampling rate is recommended to be in 22,050 Hz. -2. To prepare target discrete units for S2UT model training, see [Generative Spoken Language Modeling (speech2unit)](https://github.com/pytorch/fairseq/tree/main/examples/textless_nlp/gslm/speech2unit) for pre-trained k-means models, checkpoints, and instructions on how to decode units from speech. Set the output target unit files (`--out_quantized_file_path`) as `${TGT_AUDIO}/${SPLIT}.txt`. In [Lee et al. 2021](https://arxiv.org/abs/2107.05604), we use 100 units from the sixth layer (`--layer 6`) of the HuBERT Base model. - -### Formatting data -**Speech-to-speech data** - -_S2UT_ - * Set `--reduce-unit` for training S2UT _reduced_ model - * Pre-trained vocoder and config (`$VOCODER_CKPT`, `$VOCODER_CFG`) can be downloaded from the **Pretrained Models** section. They are not required if `--eval-inference` is not going to be set during model training. -``` -# $SPLIT1, $SPLIT2, etc. are split names such as train, dev, test, etc. - -python examples/speech_to_speech/preprocessing/prep_s2ut_data.py \ - --source-dir $SRC_AUDIO --target-dir $TGT_AUDIO --data-split $SPLIT1 $SPLIT2 \ - --output-root $DATA_ROOT --reduce-unit \ - --vocoder-checkpoint $VOCODER_CKPT --vocoder-cfg $VOCODER_CFG -``` - -_S2SPECT_ -``` -# $SPLIT1, $SPLIT2, etc. are split names such as train, dev, test, etc. - -python examples/speech_to_speech/preprocessing/prep_s2spect_data.py \ - --source-dir $SRC_AUDIO --target-dir $TGT_AUDIO --data-split $SPLIT1 $SPLIT2 \ - --output-root $DATA_ROOT -``` - -**Multitask data** - * For each multitask `$TASK_NAME`, prepare `${DATA_ROOT}/${TASK_NAME}/${SPLIT}.tsv` files for each split following the format below: (Two tab separated columns. The sample_ids should match with the sample_ids for the speech-to-speech data in `${DATA_ROOT}/${SPLIT}.tsv`.) -``` -id tgt_text -sample_id_0 token1 token2 token3 ... -sample_id_1 token1 token2 token3 ... -... -``` - * For each multitask `$TASK_NAME`, prepare `${DATA_ROOT}/${TASK_NAME}/dict.txt`, a dictionary in fairseq format with all tokens for the targets for `$TASK_NAME`. - * Create `config_multitask.yaml`. Below is an example of the config used for S2UT _reduced_ with Fisher experiments including two encoder multitasks (`source_letter`, `target_letter`) and one decoder CTC task (`decoder_target_ctc`). -``` -source_letter: # $TASK_NAME - decoder_type: transformer - dict: ${DATA_ROOT}/source_letter/dict.txt - data: ${DATA_ROOT}/source_letter - encoder_layer: 6 - loss_weight: 8.0 -target_letter: - decoder_type: transformer - dict: ${DATA_ROOT}/target_letter/dict.txt - data: ${DATA_ROOT}/target_letter - encoder_layer: 8 - loss_weight: 8.0 -decoder_target_ctc: - decoder_type: ctc - dict: ${DATA_ROOT}/decoder_target_ctc/dict.txt - data: ${DATA_ROOT}/decoder_target_ctc - decoder_layer: 3 - loss_weight: 1.6 -``` - - -## Training - -**Speech-to-unit translation (S2UT)** - -Here's an example for training Fisher S2UT models with 100 discrete units as target: -``` -fairseq-train $DATA_ROOT \ - --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ - --task speech_to_speech --target-is-code --target-code-size 100 --vocoder code_hifigan \ - --criterion speech_to_unit --label-smoothing 0.2 \ - --arch s2ut_transformer_fisher --share-decoder-input-output-embed \ - --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.1 \ - --train-subset train --valid-subset dev \ - --save-dir ${MODEL_DIR} \ - --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-7 --warmup-updates 10000 \ - --optimizer adam --adam-betas "(0.9,0.98)" --clip-norm 10.0 \ - --max-update 400000 --max-tokens 20000 --max-target-positions 3000 --update-freq 4 \ - --seed 1 --fp16 --num-workers 8 -``` -* Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 4` to simulate training with 4 GPUs. -* Set `--n-frames-per-step 5` to train an S2UT _stacked_ system with reduction ratio r=5. (Use `$DATA_ROOT` prepared without `--reduce-unit`.) -* (optional) one can turn on tracking MCD loss during training for checkpoint selection by setting `--eval-inference --eval-args '{"beam": 1, "max_len_a": 1}' --best-checkpoint-metric mcd_loss`. It is recommended to sample a smaller subset as the validation set as MCD loss computation is time-consuming. - -**Speech-to-spectrogram translation (S2SPECT)** - -Here's an example for training Fisher S2SPECT models with reduction ratio r=5: -``` -fairseq-train $DATA_ROOT \ - --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ - --task speech_to_speech --n-frames-per-step 5 \ - --criterion speech_to_spectrogram \ - --arch s2spect_transformer_fisher --decoder-normalize-before \ - --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.1 \ - --train-subset train --valid-subset dev \ - --save-dir ${MODEL_DIR} \ - --eval-inference --best-checkpoint-metric mcd_loss \ - --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-7 --warmup-updates 10000 \ - --optimizer adam --adam-betas "(0.9,0.98)" --clip-norm 10.0 --weight-decay 1e-6 \ - --max-update 400000 --max-tokens 80000 --max-tokens-valid 30000 --required-batch-size-multiple 1 \ - --max-target-positions 3000 --update-freq 16 \ - --seed 1 --fp16 --num-workers 8 -``` -* Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 16` to simulate training with 16 GPUs. -* We recommend turning on MCD loss during training for the best checkpoint selection. - -**Unit-based HiFi-GAN vocoder** - -The vocoder is trained with the [speech-resynthesis repo](https://github.com/facebookresearch/speech-resynthesis). See [here](https://github.com/facebookresearch/speech-resynthesis/tree/main/examples/speech_to_speech_translation) for instructions on how to train the unit-based HiFi-GAN vocoder with duration prediction. The same vocoder can support waveform generation for both _reduced_ unit sequences (with `--dur-prediction` set during inference) and original unit sequences. - -## Inference - -**Speech-to-unit translation (S2UT)** - -1. Follow the same inference process as in [fairseq-S2T](https://github.com/pytorch/fairseq/tree/main/examples/speech_to_text) to generate unit sequences (`${RESULTS_PATH}/generate-${GEN_SUBSET}.txt`). -``` -fairseq-generate $DATA_ROOT \ - --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ - --task speech_to_speech --target-is-code --target-code-size 100 --vocoder code_hifigan \ - --path $MODEL_DIR/checkpoint_best.pt --gen-subset $GEN_SUBSET \ - --max-tokens 50000 \ - --beam 10 --max-len-a 1 \ - --results-path ${RESULTS_PATH} -``` - * Set `--beam 1 --n-frames-per-step $r` for decoding with S2UT _stacked_ models. - -2. Convert unit sequences to waveform. -``` -grep "^D\-" ${RESULTS_PATH}/generate-${GEN_SUBSET}.txt | \ - sed 's/^D-//ig' | sort -nk1 | cut -f3 \ - > ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit - -python examples/speech_to_speech/generate_waveform_from_code.py \ - --in-code-file ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit \ - --vocoder $VOCODER_CKPT --vocoder-cfg $VOCODER_CFG \ - --results-path ${RESULTS_PATH} --dur-prediction -``` - * Set `--dur-prediction` for generating audio for S2UT _reduced_ models. - - -**Speech-to-spectrogram translation (S2SPECT)** - -Follow the same inference process as in [fairseq-S^2](https://github.com/pytorch/fairseq/tree/main/examples/speech_synthesis) to generate waveform. - -``` -# assume using a default Griffin-Lim vocoder - -python examples/speech_synthesis/generate_waveform.py $DATA_ROOT \ - --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ - --task speech_to_speech --n-frames-per-step 5 \ - --path $MODEL_DIR/checkpoint_best.pt --gen-subset $GEN_SUBSET \ - --max-tokens 50000 \ - --results-path ${RESULTS_PATH} --dump-waveforms --output-sample-rate 16000 -``` - -In addition to using the default Griffin-Lim vocoder, one can also finetune a HiFi-GAN vocoder for the S2SPECT model by following the instructions in the [HiFi-GAN repo](https://github.com/jik876/hifi-gan). - -**Multitask decoding** - -Coming soon. - -## Evaluation - -To evaluate speech translation output, we first apply ASR on the speech output and then compute BLEU score betweent the ASR decoded text and the references using sacreBLEU. - -**En** -* ASR: We use the "[Wav2Vec 2.0 Large (LV-60) + Self Training / 960 hours / Libri-Light + Librispeech](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt)" En ASR model open-sourced by the [wav2vec](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec) project. See [instructions](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#evaluating-a-ctc-model) on how to run inference with a wav2vec-based ASR model. The model is also available on [Hugging Face](https://huggingface.co/facebook/wav2vec2-large-960h-lv60-self). -* Text normalization: We use the text cleaner at [https://github.com/keithito/tacotron](https://github.com/keithito/tacotron) for pre-processing reference English text for ASR BLEU evaluation. +We provide the implementation and resources for the following work on speech-to-speech translation (S2ST): + * [Direct speech-to-speech translation with discrete units (Lee et al. 2021)](docs/direct_s2st_discrete_units.md) + * [Textless Speech-to-Speech Translation on Real Data (Lee et al. 2021)](docs/textless_s2st_real_data.md) diff --git a/examples/speech_to_speech/docs/direct_s2st_discrete_units.md b/examples/speech_to_speech/docs/direct_s2st_discrete_units.md new file mode 100644 index 0000000000..0c63ffee1c --- /dev/null +++ b/examples/speech_to_speech/docs/direct_s2st_discrete_units.md @@ -0,0 +1,181 @@ +# Direct speech-to-speech translation with discrete units + +We provide the implementation for speech-to-unit translation (S2UT) proposed in "[Direct speech-to-speech translation with discrete units (Lee et al. 2021)](https://arxiv.org/abs/2107.05604)" and also the transformer-based implementation of the speech-to-spectrogram translation (S2SPECT, or transformer-based [Translatotron](https://arxiv.org/abs/1904.06037)) baseline in the paper. + +## Pretrained Models + +### Unit-based HiFi-GAN Vocoder +Unit config | Unit size | Vocoder dataset | Model +|---|---|---|--- +[HuBERT Base, Librispeech](https://github.com/fairinternal/fairseq-py/tree/main/examples/hubert), layer 6 | 100 | [LJSpeech](https://keithito.com/LJ-Speech-Dataset/) | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/hubert_base_100_lj/g_00500000), [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/hubert_base_100_lj/config.json) + + +## Data preparation +### Target speech +0. (optional) To prepare S2S data from a speech-to-text translation (ST) dataset, see [fairseq-S^2](https://github.com/pytorch/fairseq/tree/main/examples/speech_synthesis) for pre-trained TTS models and instructions on how to train and decode TTS models. +1. Prepare two folders, `$SRC_AUDIO` and `$TGT_AUDIO`, with `${SPLIT}/${SAMPLE_ID}.wav` for source and target speech under each folder, separately. Note that for S2UT experiments, target audio sampling rate should be in 16,000 Hz, and for S2SPECT experiments, target audio sampling rate is recommended to be in 22,050 Hz. +2. To prepare target discrete units for S2UT model training, see [Generative Spoken Language Modeling (speech2unit)](https://github.com/pytorch/fairseq/tree/main/examples/textless_nlp/gslm/speech2unit) for pre-trained k-means models, checkpoints, and instructions on how to decode units from speech. Set the output target unit files (`--out_quantized_file_path`) as `${TGT_AUDIO}/${SPLIT}.txt`. In [Lee et al. 2021](https://arxiv.org/abs/2107.05604), we use 100 units from the sixth layer (`--layer 6`) of the HuBERT Base model. + +### Formatting data +**Speech-to-speech data** + +_S2UT_ + * Set `--reduce-unit` for training S2UT _reduced_ model + * Pre-trained vocoder and config (`$VOCODER_CKPT`, `$VOCODER_CFG`) can be downloaded from the **Pretrained Models** section. They are not required if `--eval-inference` is not going to be set during model training. +``` +# $SPLIT1, $SPLIT2, etc. are split names such as train, dev, test, etc. + +python examples/speech_to_speech/preprocessing/prep_s2ut_data.py \ + --source-dir $SRC_AUDIO --target-dir $TGT_AUDIO --data-split $SPLIT1 $SPLIT2 \ + --output-root $DATA_ROOT --reduce-unit \ + --vocoder-checkpoint $VOCODER_CKPT --vocoder-cfg $VOCODER_CFG +``` + +_S2SPECT_ +``` +# $SPLIT1, $SPLIT2, etc. are split names such as train, dev, test, etc. + +python examples/speech_to_speech/preprocessing/prep_s2spect_data.py \ + --source-dir $SRC_AUDIO --target-dir $TGT_AUDIO --data-split $SPLIT1 $SPLIT2 \ + --output-root $DATA_ROOT +``` + +**Multitask data** + * For each multitask `$TASK_NAME`, prepare `${DATA_ROOT}/${TASK_NAME}/${SPLIT}.tsv` files for each split following the format below: (Two tab separated columns. The sample_ids should match with the sample_ids for the speech-to-speech data in `${DATA_ROOT}/${SPLIT}.tsv`.) +``` +id tgt_text +sample_id_0 token1 token2 token3 ... +sample_id_1 token1 token2 token3 ... +... +``` + * For each multitask `$TASK_NAME`, prepare `${DATA_ROOT}/${TASK_NAME}/dict.txt`, a dictionary in fairseq format with all tokens for the targets for `$TASK_NAME`. + * Create `config_multitask.yaml`. Below is an example of the config used for S2UT _reduced_ with Fisher experiments including two encoder multitasks (`source_letter`, `target_letter`) and one decoder CTC task (`decoder_target_ctc`). +``` +source_letter: # $TASK_NAME + decoder_type: transformer + dict: ${DATA_ROOT}/source_letter/dict.txt + data: ${DATA_ROOT}/source_letter + encoder_layer: 6 + loss_weight: 8.0 +target_letter: + decoder_type: transformer + dict: ${DATA_ROOT}/target_letter/dict.txt + data: ${DATA_ROOT}/target_letter + encoder_layer: 8 + loss_weight: 8.0 +decoder_target_ctc: + decoder_type: ctc + dict: ${DATA_ROOT}/decoder_target_ctc/dict.txt + data: ${DATA_ROOT}/decoder_target_ctc + decoder_layer: 3 + loss_weight: 1.6 +``` + + +## Training + +**Speech-to-unit translation (S2UT)** + +Here's an example for training Fisher S2UT models with 100 discrete units as target: +``` +fairseq-train $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --target-is-code --target-code-size 100 --vocoder code_hifigan \ + --criterion speech_to_unit --label-smoothing 0.2 \ + --arch s2ut_transformer_fisher --share-decoder-input-output-embed \ + --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.1 \ + --train-subset train --valid-subset dev \ + --save-dir ${MODEL_DIR} \ + --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-7 --warmup-updates 10000 \ + --optimizer adam --adam-betas "(0.9,0.98)" --clip-norm 10.0 \ + --max-update 400000 --max-tokens 20000 --max-target-positions 3000 --update-freq 4 \ + --seed 1 --fp16 --num-workers 8 +``` +* Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 4` to simulate training with 4 GPUs. +* Set `--n-frames-per-step 5` to train an S2UT _stacked_ system with reduction ratio r=5. (Use `$DATA_ROOT` prepared without `--reduce-unit`.) +* (optional) one can turn on tracking MCD loss during training for checkpoint selection by setting `--eval-inference --eval-args '{"beam": 1, "max_len_a": 1}' --best-checkpoint-metric mcd_loss`. It is recommended to sample a smaller subset as the validation set as MCD loss computation is time-consuming. + +**Speech-to-spectrogram translation (S2SPECT)** + +Here's an example for training Fisher S2SPECT models with reduction ratio r=5: +``` +fairseq-train $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --n-frames-per-step 5 \ + --criterion speech_to_spectrogram \ + --arch s2spect_transformer_fisher --decoder-normalize-before \ + --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.1 \ + --train-subset train --valid-subset dev \ + --save-dir ${MODEL_DIR} \ + --eval-inference --best-checkpoint-metric mcd_loss \ + --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-7 --warmup-updates 10000 \ + --optimizer adam --adam-betas "(0.9,0.98)" --clip-norm 10.0 --weight-decay 1e-6 \ + --max-update 400000 --max-tokens 80000 --max-tokens-valid 30000 --required-batch-size-multiple 1 \ + --max-target-positions 3000 --update-freq 16 \ + --seed 1 --fp16 --num-workers 8 +``` +* Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 16` to simulate training with 16 GPUs. +* We recommend turning on MCD loss during training for the best checkpoint selection. + +**Unit-based HiFi-GAN vocoder** + +The vocoder is trained with the [speech-resynthesis repo](https://github.com/facebookresearch/speech-resynthesis). See [here](https://github.com/facebookresearch/speech-resynthesis/tree/main/examples/speech_to_speech_translation) for instructions on how to train the unit-based HiFi-GAN vocoder with duration prediction. The same vocoder can support waveform generation for both _reduced_ unit sequences (with `--dur-prediction` set during inference) and original unit sequences. + +## Inference + +**Speech-to-unit translation (S2UT)** + +1. Follow the same inference process as in [fairseq-S2T](https://github.com/pytorch/fairseq/tree/main/examples/speech_to_text) to generate unit sequences (`${RESULTS_PATH}/generate-${GEN_SUBSET}.txt`). +``` +fairseq-generate $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --target-is-code --target-code-size 100 --vocoder code_hifigan \ + --path $MODEL_DIR/checkpoint_best.pt --gen-subset $GEN_SUBSET \ + --max-tokens 50000 \ + --beam 10 --max-len-a 1 \ + --results-path ${RESULTS_PATH} +``` + * Set `--beam 1 --n-frames-per-step $r` for decoding with S2UT _stacked_ models. + +2. Convert unit sequences to waveform. +``` +grep "^D\-" ${RESULTS_PATH}/generate-${GEN_SUBSET}.txt | \ + sed 's/^D-//ig' | sort -nk1 | cut -f3 \ + > ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit + +python examples/speech_to_speech/generate_waveform_from_code.py \ + --in-code-file ${RESULTS_PATH}/generate-${GEN_SUBSET}.unit \ + --vocoder $VOCODER_CKPT --vocoder-cfg $VOCODER_CFG \ + --results-path ${RESULTS_PATH} --dur-prediction +``` + * Set `--dur-prediction` for generating audio for S2UT _reduced_ models. + + +**Speech-to-spectrogram translation (S2SPECT)** + +Follow the same inference process as in [fairseq-S^2](https://github.com/pytorch/fairseq/tree/main/examples/speech_synthesis) to generate waveform. + +``` +# assume using a default Griffin-Lim vocoder + +python examples/speech_synthesis/generate_waveform.py $DATA_ROOT \ + --config-yaml config.yaml --multitask-config-yaml config_multitask.yaml \ + --task speech_to_speech --n-frames-per-step 5 \ + --path $MODEL_DIR/checkpoint_best.pt --gen-subset $GEN_SUBSET \ + --max-tokens 50000 \ + --results-path ${RESULTS_PATH} --dump-waveforms --output-sample-rate 16000 +``` + +In addition to using the default Griffin-Lim vocoder, one can also finetune a HiFi-GAN vocoder for the S2SPECT model by following the instructions in the [HiFi-GAN repo](https://github.com/jik876/hifi-gan). + +**Multitask decoding** + +Coming soon. + +## Evaluation + +To evaluate speech translation output, we first apply ASR on the speech output and then compute BLEU score betweent the ASR decoded text and the references using sacreBLEU. + +**En** +* ASR: We use the "[Wav2Vec 2.0 Large (LV-60) + Self Training / 960 hours / Libri-Light + Librispeech](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt)" En ASR model open-sourced by the [wav2vec](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec) project. See [instructions](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#evaluating-a-ctc-model) on how to run inference with a wav2vec-based ASR model. The model is also available on [Hugging Face](https://huggingface.co/facebook/wav2vec2-large-960h-lv60-self). +* Text normalization: We use the text cleaner at [https://github.com/keithito/tacotron](https://github.com/keithito/tacotron) for pre-processing reference English text for ASR BLEU evaluation. diff --git a/examples/speech_to_speech/docs/textless_s2st_real_data.md b/examples/speech_to_speech/docs/textless_s2st_real_data.md new file mode 100644 index 0000000000..ca6044be1a --- /dev/null +++ b/examples/speech_to_speech/docs/textless_s2st_real_data.md @@ -0,0 +1,89 @@ +# Textless Speech-to-Speech Translation (S2ST) on Real Data + +We provide instructions and pre-trained models for the work "[Textless Speech-to-Speech Translation on Real Data (Lee et al. 2021)](https://arxiv.org/abs/2112.08352)". + +## Pre-trained Models + +### HuBERT +Model | Pretraining Data | Model | Quantizer +|---|---|---|--- +mHuBERT Base | [VoxPopuli](https://github.com/facebookresearch/voxpopuli) En, Es, Fr speech from the 100k subset | [download](https://dl.fbaipublicfiles.com/hubert/mhubert_base_vp_en_es_fr_it3.pt) | [L11 km1000](https://dl.fbaipublicfiles.com/hubert/mhubert_base_vp_en_es_fr_it3_L11_km1000.bin) + + +### Unit-based HiFi-GAN vocoder +Unit config | Unit size | Vocoder language | Dataset | Model +|---|---|---|---|--- +mHuBERT, layer 11 | 1000 | En | [LJSpeech](https://keithito.com/LJ-Speech-Dataset/) | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/mhubert_vp_en_es_fr_it3_400k_layer11_km1000_lj/g_00500000), [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/mhubert_vp_en_es_fr_it3_400k_layer11_km1000_lj/config.json) +mHuBERT, layer 11 | 1000 | Es | [CSS10](https://github.com/Kyubyong/css10) | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/mhubert_vp_en_es_fr_it3_400k_layer11_km1000_es_css10/g_00500000), [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/mhubert_vp_en_es_fr_it3_400k_layer11_km1000_es_css10/config.json) +mHuBERT, layer 11 | 1000 | Fr | [CSS10](https://github.com/Kyubyong/css10) | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/mhubert_vp_en_es_fr_it3_400k_layer11_km1000_fr_css10/g_00500000), [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/vocoder/code_hifigan/mhubert_vp_en_es_fr_it3_400k_layer11_km1000_fr_css10/config.json) + + +### Speech normalizer +Language | Training data | Target unit config | Model +|---|---|---|--- +En | 10 mins | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/en/en_10min.tar.gz) +En | 1 hr | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/en/en_1h.tar.gz) +En | 10 hrs | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/en/en_10h.tar.gz) +Es | 10 mins | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/es/es_10min.tar.gz) +Es | 1 hr | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/es/es_1h.tar.gz) +Es | 10 hrs | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/es/es_10h.tar.gz) +Fr | 10 mins | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/fr/fr_10min.tar.gz) +Fr | 1 hr | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/fr/fr_1h.tar.gz) +Fr | 10 hrs | mHuBERT, layer 11, km1000 | [download](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/speech_normalizer/fr/fr_10h.tar.gz) + +* Refer to the paper for the details of the training data. + +## Inference with Pre-trained Models + +### Speech normalizer +1. Download the pre-trained models, including the dictionary, to `DATA_DIR`. +2. Format the audio data. +```bash +# AUDIO_EXT: audio extension, e.g. wav, flac, etc. +# Assume all audio files are at ${AUDIO_DIR}/*.${AUDIO_EXT} + +python examples/speech_to_speech/preprocessing/prep_sn_data.py \ + --audio-dir ${AUDIO_DIR} --ext ${AUIDO_EXT} \ + --data-name ${GEN_SUBSET} --output-dir ${DATA_DIR} \ + --for-inference +``` + +3. Run the speech normalizer and post-process the output. +```bash +mkdir -p ${RESULTS_PATH} + +python examples/speech_recognition/new/infer.py \ + --config-dir examples/hubert/config/decode/ \ + --config-name infer_viterbi \ + task.data=${DATA_DIR} \ + task.normalize=false \ + common_eval.results_path=${RESULTS_PATH}/log \ + common_eval.path=${DATA_DIR}/checkpoint_best.pt \ + dataset.gen_subset=${GEN_SUBSET} \ + '+task.labels=["unit"]' \ + +decoding.results_path=${RESULTS_PATH} \ + common_eval.post_process=none \ + +dataset.batch_size=1 \ + common_eval.quiet=True + +# Post-process and generate output at ${RESULTS_PATH}/${GEN_SUBSET}.txt +python examples/speech_to_speech/preprocessing/prep_sn_output_data.py \ + --in-unit ${RESULTS_PATH}/hypo.units \ + --in-audio ${DATA_DIR}/${GEN_SUBSET}.tsv \ + --output-root ${RESULTS_PATH} +``` + + +### Unit-to-waveform conversion with unit vocoder +The pre-trained vocoders can support generating audio for both full unit sequences and reduced unit sequences (i.e. duplicating consecutive units removed). Set `--dur-prediction` for generating audio with reduced unit sequences. +```bash +# IN_CODE_FILE contains one unit sequence per line. Units are separated by space. + +python examples/speech_to_speech/generate_waveform_from_code.py \ + --in-code-file ${IN_CODE_FILE} \ + --vocoder ${VOCODER_CKPT} --vocoder-cfg ${VOCODER_CFG} \ + --results-path ${RESULTS_PATH} --dur-prediction +``` + +## Training new models +To be updated. diff --git a/examples/speech_to_speech/preprocessing/data_utils.py b/examples/speech_to_speech/preprocessing/data_utils.py index 48fe57b742..a83a67f954 100644 --- a/examples/speech_to_speech/preprocessing/data_utils.py +++ b/examples/speech_to_speech/preprocessing/data_utils.py @@ -68,3 +68,21 @@ def gen_config_yaml( if extra is not None: writer.set_extra(extra) writer.flush() + + +def load_units(in_file): + out = {} + with open(in_file) as f: + for line in f: + sample_id, units = line.strip().split("|", 1) + out[sample_id] = units.split() + + return out + + +def process_units(units, reduce=False): + if not reduce: + return units + + out = [u for i, u in enumerate(units) if i == 0 or u != units[i - 1]] + return out diff --git a/examples/speech_to_speech/preprocessing/prep_s2ut_data.py b/examples/speech_to_speech/preprocessing/prep_s2ut_data.py index beeffaa0e4..c97c0fe9be 100644 --- a/examples/speech_to_speech/preprocessing/prep_s2ut_data.py +++ b/examples/speech_to_speech/preprocessing/prep_s2ut_data.py @@ -12,7 +12,11 @@ from tqdm import tqdm import pandas as pd -from examples.speech_to_speech.preprocessing.data_utils import gen_config_yaml +from examples.speech_to_speech.preprocessing.data_utils import ( + gen_config_yaml, + load_units, + process_units, +) from examples.speech_to_text.data_utils import save_df_to_tsv logger = logging.getLogger(__name__) @@ -20,24 +24,6 @@ MANIFEST_COLUMNS = ["id", "src_audio", "src_n_frames", "tgt_audio", "tgt_n_frames"] -def load_units(in_file): - out = {} - with open(in_file) as f: - for line in f: - sample_id, units = line.strip().split("|", 1) - out[sample_id] = units.split() - - return out - - -def process_units(units, reduce=False): - if not reduce: - return units - - out = [u for i, u in enumerate(units) if i == 0 or u != units[i - 1]] - return out - - def process(args): args.output_root.mkdir(exist_ok=True) diff --git a/examples/speech_to_speech/preprocessing/prep_sn_data.py b/examples/speech_to_speech/preprocessing/prep_sn_data.py new file mode 100644 index 0000000000..ea94175634 --- /dev/null +++ b/examples/speech_to_speech/preprocessing/prep_sn_data.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +# +# Adapted from examples/wav2vec/wav2vec_manifest.py +""" +Data preparation for the speech normalizer +""" + +import argparse +import glob +import os + +import soundfile + +from examples.speech_to_speech.preprocessing.data_utils import load_units, process_units + + +def process(args): + assert ( + args.for_inference or args.target_unit is not None + ), "missing --target-unit or --for-inference" + + if not os.path.exists(args.output_dir): + os.makedirs(args.output_dir) + + dir_path = os.path.realpath(args.audio_dir) + search_path = os.path.join(dir_path, "**/*." + args.ext) + + if args.target_unit: + unit_data = load_units(args.target_unit) + + with open(os.path.join(args.output_dir, f"{args.data_name}.tsv"), "w") as o_t, open( + os.path.join(args.output_dir, f"{args.data_name}.unit"), "w" + ) as o_u: + print(dir_path, file=o_t) + for fname in glob.iglob(search_path, recursive=True): + file_path = os.path.realpath(fname) + frames = soundfile.info(fname).frames + print( + "{}\t{}".format(os.path.relpath(file_path, dir_path), frames), file=o_t + ) + + if args.for_inference: + print("0", file=o_u) + else: + sample_id = os.path.basename(file_path)[: -len(args.ext) - 1] + assert ( + sample_id in unit_data + ), f'{fname} does not have unit data in {args.target_unit}. Expecting sample_id "{sample_id}".' + target_units = process_units(unit_data[sample_id], reduce=True) + print(" ".join(target_units), file=o_u) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--audio-dir", required=True, type=str, help="audio directory") + parser.add_argument("--ext", default="flac", type=str, help="audio extension") + parser.add_argument( + "--data-name", + required=True, + type=str, + help="dataset name", + ) + parser.add_argument( + "--output-dir", required=True, type=str, help="output directory" + ) + parser.add_argument( + "--for-inference", + action="store_true", + help="set this if preparing data for running inference with a speech normalizer", + ) + parser.add_argument( + "--target-unit", + default=None, + type=str, + help="a file containing unit sequences in the format: sample_id|u1 u2 ...", + ) + + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_to_speech/preprocessing/prep_sn_output_data.py b/examples/speech_to_speech/preprocessing/prep_sn_output_data.py new file mode 100644 index 0000000000..06991343bd --- /dev/null +++ b/examples/speech_to_speech/preprocessing/prep_sn_output_data.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +from pathlib import Path + +from tqdm import tqdm + + +def process(args): + args.output_root.mkdir(exist_ok=True) + + # load units + units = {} + with open(args.in_unit) as f: + for line in f: + unit_seq, utt_id = line.strip().rsplit(" ", 1) + utt_id = int(utt_id[6:-1]) # remove "(None-" + units[utt_id] = unit_seq + + with open(args.in_audio) as f, open( + args.output_root / f"{args.in_audio.stem}.txt", "w" + ) as o: + f.readline() + for i, line in enumerate(tqdm(f.readlines())): + audio, _ = line.strip().split("\t", 1) + sample_id = Path(audio).stem + o.write(f"{sample_id}|{units[i]}\n") + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--in-unit", + required=True, + type=Path, + help="unit file (output from the speech normalizer)", + ) + parser.add_argument( + "--in-audio", + required=True, + type=Path, + help="tsv file (input to the normalizer)", + ) + parser.add_argument( + "--output-root", required=True, type=Path, help="output directory" + ) + + args = parser.parse_args() + + process(args) + + +if __name__ == "__main__": + main() From fef5006caa1ec6c5b18bf0d01956434d6db4d719 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Mon, 28 Mar 2022 15:13:02 -0700 Subject: [PATCH 592/774] formatting fix (#4310) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fix issue with `black` causing build error. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4310 Reviewed By: shruti-bh Differential Revision: D35151101 Pulled By: dianaml0 fbshipit-source-id: 63d80b848fdd3c004d784add3bf74e4c5281e952 --- .../data/audio/speech_to_speech_dataset.py | 21 +++++++++---------- fairseq/tasks/speech_to_speech.py | 21 +++++++++++-------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py index 04a36bea90..c768dcfb0b 100644 --- a/fairseq/data/audio/speech_to_speech_dataset.py +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -3,26 +3,23 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from dataclasses import dataclass import logging +from dataclasses import dataclass from pathlib import Path from typing import Dict, List, Optional, Tuple import torch -from fairseq.data import ( - ConcatDataset, - data_utils as fairseq_data_utils, - Dictionary, -) + +from fairseq.data import ConcatDataset, Dictionary +from fairseq.data import data_utils as fairseq_data_utils from fairseq.data.audio.data_cfg import S2SDataConfig from fairseq.data.audio.speech_to_text_dataset import ( - _collate_frames, - get_features_or_waveform, SpeechToTextDataset, SpeechToTextDatasetCreator, + _collate_frames, + get_features_or_waveform, ) - logger = logging.getLogger(__name__) @@ -146,9 +143,11 @@ def __getitem__(self, index: int) -> SpeechToSpeechDatasetItem: tgt_spk = torch.FloatTensor([]) return SpeechToSpeechDatasetItem( - index=index, source=source, target=target, + index=index, + source=source, + target=target, target_speaker=tgt_spk, - tgt_lang_tag=tgt_lang_tag + tgt_lang_tag=tgt_lang_tag, ) def _collate_target(self, samples: List[SpeechToSpeechDatasetItem]) -> torch.Tensor: diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index 211bf1d4f1..d9e2325686 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -3,23 +3,23 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from argparse import Namespace import json import logging import math +from argparse import Namespace from pathlib import Path + import torch import torch.nn as nn from fairseq import utils from fairseq.data import Dictionary -from fairseq.data.audio.data_cfg import S2SDataConfig, MultitaskConfig -from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset +from fairseq.data.audio.data_cfg import MultitaskConfig, S2SDataConfig from fairseq.data.audio.speech_to_speech_dataset import SpeechToSpeechDatasetCreator +from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset from fairseq.tasks import LegacyFairseqTask, register_task from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion - logger = logging.getLogger(__name__) @@ -201,7 +201,7 @@ def add_args(cls, parser): "--infer-target-lang", type=str, default="", - help="target language for inference" + help="target language for inference", ) def __init__(self, args, tgt_dict, infer_tgt_lang_id=None): @@ -229,7 +229,9 @@ def setup_task(cls, args, **kwargs): # dictionary with language tags dict_path = Path(args.data) / data_cfg.vocab_filename if not dict_path.is_file(): - raise FileNotFoundError(f"Dict has to be provided when setting prepend_tgt_lang_tag_as_bos: true, but dict not found: {dict_path}") + raise FileNotFoundError( + f"Dict has to be provided when setting prepend_tgt_lang_tag_as_bos: true, but dict not found: {dict_path}" + ) tgt_dict = Dictionary.load(dict_path.as_posix()) # target langauge for inference @@ -468,17 +470,18 @@ def inference_step( sample, prefix_tokens=prefix_tokens, constraints=constraints, - bos_token=self._infer_tgt_lang_id + bos_token=self._infer_tgt_lang_id, ) else: - return super().inference_step( + return super().inference_step( generator, models, sample, prefix_tokens=prefix_tokens, - constraints=constraints + constraints=constraints, ) + class DummyMultiTask(LegacyFairseqTask): def __init__(self, args, tgt_dict): super().__init__(args) From 54ea689ac5b40b51ce82761caa3dc67445ec0fdf Mon Sep 17 00:00:00 2001 From: Angela Fan <angela.h.fan@gmail.com> Date: Tue, 29 Mar 2022 07:06:16 -0700 Subject: [PATCH 593/774] adding readme (#4314) Summary: adding for generating biographies paper Pull Request resolved: https://github.com/pytorch/fairseq/pull/4314 Reviewed By: edunov Differential Revision: D35205567 Pulled By: huihuifan fbshipit-source-id: 7698672dcffbdb8a10bfea4f72920e1f508a4104 --- examples/womens_bios/README.md | 81 +++++++++++++++++++ .../query_occupations_from_wikidata.py | 34 ++++++++ 2 files changed, 115 insertions(+) create mode 100644 examples/womens_bios/README.md create mode 100644 examples/womens_bios/query_occupations_from_wikidata.py diff --git a/examples/womens_bios/README.md b/examples/womens_bios/README.md new file mode 100644 index 0000000000..07d0646887 --- /dev/null +++ b/examples/womens_bios/README.md @@ -0,0 +1,81 @@ +# Wikipedia Biographies of Women + + +## Training: + +The training dataset is created based on WikiSum, a dataset created from the paper [Generating Wikipedia by Summarizing Long Sequences](https://arxiv.org/pdf/1801.10198.pdf). The dataset needs to be generated following the instructions in this [Github Repository](https://github.com/tensorflow/tensor2tensor/tree/master/tensor2tensor/data_generators/wikisum). + +### How is the WikiSum dataset structured? + +Overall, the task in WikiSum was to generate the entire Wikipedia article based on the contents of the top 10 Google Search Results. The authors provide a way for people to recreate their work. In the WikiSum Github, there are two options for the dataset recreation --- the first is to use CommonCrawl (a static, open source crawl of the web) and the second to do Live Web Fetches. The second has higher coverage, but the content is subject to change and difficult to fetch. We used the static, Commoncrawl version. This can be downloaded following the Github repo instructions, though note it will require usage of Google Cloud. + +Note: in our experience, it also requires requesting that the resource limit of the Google Cloud instance be raised, which requires emailing. + +Note: Having higher coverage in the training dataset would be expected to improve the model quality. There are many instances in the dataset where the training input (web evidence) does not contain sufficient content for producing the desired Wikipedia article. This may harm the model's ability to learn to retrieve, look at the input evidence, and overall could contribute to increased challenges in generating verifiable Wikipedia biographies. + +### How do you go from WikiSum dataset to Biography dataset? + +The WikiSum dataset is for Wikipedia in general, not just biographies. We do this by querying WikiData to see if the Wikipedia article has an occupation, with the thought that all articles with occupations are probably biographies. + + +## Evaluation: + +You can download the dataset and baseline model with the following command: + +``` +wget -N 'https://dl.fbaipublicfiles.com/fairseq/womenbios_dataset.zip' +wget -N 'https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/encoder.json' +wget -N 'https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/vocab.bpe' +wget -N 'https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/dict.txt' +``` + +We provide the full text Wikipedia articles split into four categories: +- Women in Africa +- Women in Asia +- Women in Science +- Women +We note that these are not exhaustive intersectional categories and mainly stem from personal interest. + +We also provide the URL of the Wikipedia article. Note that Wikipedia articles are constantly being improved, edited, and changed. Thus, it's completely possible that the Wikipedia article on Wikipedia has been lovingly improved by other Wikipedia editors. + +To get the occupations of each biographical subject, we use WikiData. We provide a sample script to do this. We also provide the raw output of this query. + +The final part of the evaluation dataset is to query web evidence for each of the biographical subjects. This is the part of the evaluation dataset that requires the most improvement. As we discuss in our paper, one of the major reasons why it is difficult to write biographies for sometimes very well qualified women is that there is not information online about them. Further, the search engine may not find it. We encourage others to improve upon this part of the data, as even re-querying again on the internet may find new, updated sources of information as the web is constantly evolving. + +We use the search engine from [Internet-Augmented Dialogue Generation](https://arxiv.org/abs/2107.07566), see [project URL](https://parl.ai/projects/sea/) to do the search queries. Note: we remove wikipedia site sources from our query (or we'd query the data itself). However, it's possible Wikipedia information can be copied around in multiple forms on the web, linked with edits, etc. + + +## Section by Section Generation: + +Wikipedia articles are split into sections, which are usually separated by headings. These headings can be separated in the article text by looking for these equal signs (==), where the number of equal signs usually signals if you are looking at a toplevel heading or a subheading, etc. An example regex that you can use is: + +` +section_header_re = re.compile(r"(?<!=)==([^=]+)==(?!=)") +` + + +## List of Notes: +- People can have multiple occupations, and we keep all occupations that we query from WikiData + + +## List of Possible Improvement Areas: +Using a larger generative pre-trained model, larger-scale retrieval, a retrieval encoder specialized to Wikipedia (or biographies), tuning all of the training & generation parameters exhaustively --- and the like --- would most likely be very useful. Overall, we hope that this is a starting point for others who might be interested in focusing on how we can help address the gender gap on Wikipedia. + + +## Interested in Wikipedia and Gender Gap? +You might want to check out: +- https://humaniki.wmcloud.org/ +- https://en.wikipedia.org/wiki/Wikipedia:WikiProject_Women_in_Red and https://wikimediafoundation.org/news/2018/10/18/women-in-red-wikiproject/ +- https://meta.wikimedia.org/wiki/Whose_Knowledge%3F/VisibleWikiWomen +- https://www.ted.com/talks/jess_wade_a_voice_for_diversity_in_science + +and thanks again to all of the Wikipedia editors and the entire community that is already working so hard to write amazing articles for diverse groups of people. + + +# LICENSE +This is licensed under CC-BY-NC, however portions of the dataset are available under separate license terms: text sourced from Wikipedia is licensed under CC-BY-SA. + + + + + diff --git a/examples/womens_bios/query_occupations_from_wikidata.py b/examples/womens_bios/query_occupations_from_wikidata.py new file mode 100644 index 0000000000..8028c6eece --- /dev/null +++ b/examples/womens_bios/query_occupations_from_wikidata.py @@ -0,0 +1,34 @@ +import sys +from SPARQLWrapper import SPARQLWrapper, JSON + +endpoint_url = "https://query.wikidata.org/sparql" + +with open("/your/urls/here") as f: + data = f.readlines() +urls = [i.strip() for i in data] + +def get_results(endpoint_url, URL): + query = f"""SELECT ?uriLabel ?occupation ?occupationLabel ?dob ?dobLabel WHERE {{ + <{URL}> schema:about ?uri . + ?uri wdt:P106 ?occupation . + SERVICE wikibase:label {{ bd:serviceParam wikibase:language "en" }} + }}""" + user_agent = "WDQS-example Python/%s.%s" % (sys.version_info[0], sys.version_info[1]) + sparql = SPARQLWrapper(endpoint_url, agent=user_agent) + sparql.setQuery(query) + sparql.setReturnFormat(JSON) + return sparql.query().convert() + +all_occupations = [] +for URL in urls: + results = get_results(endpoint_url, URL) + occupations = [] + for result in results["results"]["bindings"]: + occupations.append(result['occupationLabel']['value']) + all_occupations.append(result['uriLabel']['value'] + ", " + ", ".join(occupations)) + +assert(len(all_occupations) == len(urls)) + +with open("/your/file/output/here", "w") as o: + for line in all_occupations: + o.write(line.strip() + "\n") \ No newline at end of file From 7d72f28db5e4cb47a4ac5f5d37aeb159a5d48b4f Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Tue, 29 Mar 2022 07:20:46 -0700 Subject: [PATCH 594/774] formatting fix (#4313) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4313 Reviewed By: shruti-bh Differential Revision: D35200613 Pulled By: dianaml0 fbshipit-source-id: c011f89f4a7ee9404bec61728b52fcea8640d292 --- .../label_smoothed_cross_entropy_with_ctc.py | 40 +++++++++++++------ .../models/speech_to_text/s2t_transformer.py | 10 ++--- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py b/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py index 01b040b29c..e98e0f7da0 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py @@ -12,28 +12,35 @@ from fairseq import metrics, utils from fairseq.criterions import register_criterion from fairseq.criterions.label_smoothed_cross_entropy import ( - LabelSmoothedCrossEntropyCriterion, LabelSmoothedCrossEntropyCriterionConfig + LabelSmoothedCrossEntropyCriterion, + LabelSmoothedCrossEntropyCriterionConfig, ) from fairseq.data.data_utils import lengths_to_mask @dataclass -class LabelSmoothedCrossEntropyWithCtcCriterionConfig(LabelSmoothedCrossEntropyCriterionConfig): +class LabelSmoothedCrossEntropyWithCtcCriterionConfig( + LabelSmoothedCrossEntropyCriterionConfig +): ctc_weight: float = field(default=1.0, metadata={"help": "weight for CTC loss"}) @register_criterion( "label_smoothed_cross_entropy_with_ctc", - dataclass=LabelSmoothedCrossEntropyWithCtcCriterionConfig + dataclass=LabelSmoothedCrossEntropyWithCtcCriterionConfig, ) class LabelSmoothedCrossEntropyWithCtcCriterion(LabelSmoothedCrossEntropyCriterion): def __init__( - self, task, sentence_avg, label_smoothing, ignore_prefix_size, - report_accuracy, ctc_weight + self, + task, + sentence_avg, + label_smoothing, + ignore_prefix_size, + report_accuracy, + ctc_weight, ): super().__init__( - task, sentence_avg, label_smoothing, ignore_prefix_size, - report_accuracy + task, sentence_avg, label_smoothing, ignore_prefix_size, report_accuracy ) self.ctc_weight = ctc_weight @@ -41,17 +48,24 @@ def forward(self, model, sample, reduce=True): net_output = model(**sample["net_input"]) loss, nll_loss = self.compute_loss(model, net_output, sample, reduce=reduce) - ctc_loss = torch.tensor(0.).type_as(loss) - if self.ctc_weight > 0.: + ctc_loss = torch.tensor(0.0).type_as(loss) + if self.ctc_weight > 0.0: ctc_lprobs, ctc_lens = model.get_ctc_output(net_output, sample) ctc_tgt, ctc_tgt_lens = model.get_ctc_target(sample) ctc_tgt_mask = lengths_to_mask(ctc_tgt_lens) ctc_tgt_flat = ctc_tgt.masked_select(ctc_tgt_mask) reduction = "sum" if reduce else "none" - ctc_loss = F.ctc_loss( - ctc_lprobs, ctc_tgt_flat, ctc_lens, ctc_tgt_lens, - reduction=reduction, zero_infinity=True - ) * self.ctc_weight + ctc_loss = ( + F.ctc_loss( + ctc_lprobs, + ctc_tgt_flat, + ctc_lens, + ctc_tgt_lens, + reduction=reduction, + zero_infinity=True, + ) + * self.ctc_weight + ) loss += ctc_loss sample_size = ( diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 4ffbeaeecb..4b43e1acb5 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -295,15 +295,15 @@ def get_ctc_target(self, sample: Optional[Dict[str, Tensor]]): return sample["target"], sample["target_lengths"] def get_ctc_output( - self, - net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], - sample: Optional[Dict[str, Tensor]] + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + sample: Optional[Dict[str, Tensor]], ): encoder_out = net_output[1]["encoder_out"]["encoder_out"][0] logits = self.encoder.ctc_proj(encoder_out) # T x B x C out = utils.log_softmax(logits.float(), dim=-1) padding_mask = net_output[1]["encoder_out"]["encoder_padding_mask"] - lens = out.new_full((out.shape[1], ), out.shape[0]).long() + lens = out.new_full((out.shape[1],), out.shape[0]).long() if len(padding_mask) > 0: lens -= padding_mask[0].sum(dim=-1) return out, lens @@ -359,7 +359,7 @@ def __init__(self, args): self.layer_norm = None self.ctc_proj = None - if getattr(args, "ctc_weight", 0.) > 0.: + if getattr(args, "ctc_weight", 0.0) > 0.0: self.ctc_proj = nn.Linear(args.encoder_embed_dim, args.tgt_dict_size) def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): From 06c65c8297396959c025bf61aaeaa6f4ace9940e Mon Sep 17 00:00:00 2001 From: Gor Arakelyan <arakelyangor10@gmail.com> Date: Tue, 29 Mar 2022 10:38:10 -0700 Subject: [PATCH 595/774] Add Aim support for logging (#4311) Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Enables logging of params and metrics with Aim. Aim is an open-source experiment tracker - https://github.com/aimhubio/aim 1. Added two arguments to CommonConfig: - aim_repo: defines Aim repository location, can be set to remote URL as well(i.e. `aim://<ip>:<port>`) - aim_run_hash: defines run hash. If skipped, run will be created or continued based on `save_dir` argument. If there is an existing run which has the same `save_dir`, it will be reopened/continued, otherwise a new run will be created. 2. Implemented AimProgressBarWrapper class to handle logging Pull Request resolved: https://github.com/pytorch/fairseq/pull/4311 Reviewed By: ArmenAg Differential Revision: D35177412 Pulled By: dianaml0 fbshipit-source-id: 287afe3a77e1048e497a4e1bdc42efd46ec9c2fe --- fairseq/dataclass/configs.py | 11 ++++ fairseq/logging/progress_bar.py | 94 ++++++++++++++++++++++++++++++++- fairseq_cli/train.py | 22 ++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 7540738918..7e304f0ff4 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -113,6 +113,17 @@ class CommonConfig(FairseqDataclass): log_file: Optional[str] = field( default=None, metadata={"help": "log file to copy metrics to."} ) + aim_repo: Optional[str] = field( + default=None, + metadata={"help": "path to Aim repository"}, + ) + aim_run_hash: Optional[str] = field( + default=None, + metadata={ + "help": "Aim run hash. If skipped, creates or continues run " + "based on save_dir" + }, + ) tensorboard_logdir: Optional[str] = field( default=None, metadata={ diff --git a/fairseq/logging/progress_bar.py b/fairseq/logging/progress_bar.py index 061082caef..4c64b61bad 100644 --- a/fairseq/logging/progress_bar.py +++ b/fairseq/logging/progress_bar.py @@ -21,7 +21,6 @@ from .meters import AverageMeter, StopwatchMeter, TimeMeter - logger = logging.getLogger(__name__) @@ -32,6 +31,9 @@ def progress_bar( log_file: Optional[str] = None, epoch: Optional[int] = None, prefix: Optional[str] = None, + aim_repo: Optional[str] = None, + aim_run_hash: Optional[str] = None, + aim_param_checkpoint_dir: Optional[str] = None, tensorboard_logdir: Optional[str] = None, default_log_format: str = "tqdm", wandb_project: Optional[str] = None, @@ -58,10 +60,19 @@ def progress_bar( else: raise ValueError("Unknown log format: {}".format(log_format)) + if aim_repo: + bar = AimProgressBarWrapper( + bar, + aim_repo=aim_repo, + aim_run_hash=aim_run_hash, + aim_param_checkpoint_dir=aim_param_checkpoint_dir, + ) + if tensorboard_logdir: try: # [FB only] custom wrapper for TensorBoard import palaas # noqa + from .fb_tbmf_wrapper import FbTbmfWrapper bar = FbTbmfWrapper(bar, log_interval) @@ -310,6 +321,87 @@ def print(self, stats, tag=None, step=None): logger.info("{} | {}".format(self.prefix, postfix)) +try: + import functools + + from aim import Repo as AimRepo + + @functools.lru_cache() + def get_aim_run(repo, run_hash): + from aim import Run + + return Run(run_hash=run_hash, repo=repo) + +except ImportError: + get_aim_run = None + AimRepo = None + + +class AimProgressBarWrapper(BaseProgressBar): + """Log to Aim.""" + + def __init__(self, wrapped_bar, aim_repo, aim_run_hash, aim_param_checkpoint_dir): + self.wrapped_bar = wrapped_bar + + if get_aim_run is None: + self.run = None + logger.warning("Aim not found, please install with: pip install aim") + else: + logger.info(f"Storing logs at Aim repo: {aim_repo}") + + if not aim_run_hash: + # Find run based on save_dir parameter + query = f"run.checkpoint.save_dir == '{aim_param_checkpoint_dir}'" + try: + runs_generator = AimRepo(aim_repo).query_runs(query) + run = next(runs_generator.iter_runs()) + aim_run_hash = run.run.hash + except Exception: + pass + + if aim_run_hash: + logger.info(f"Appending to run: {aim_run_hash}") + + self.run = get_aim_run(aim_repo, aim_run_hash) + + def __iter__(self): + return iter(self.wrapped_bar) + + def log(self, stats, tag=None, step=None): + """Log intermediate stats to Aim.""" + self._log_to_aim(stats, tag, step) + self.wrapped_bar.log(stats, tag=tag, step=step) + + def print(self, stats, tag=None, step=None): + """Print end-of-epoch stats.""" + self._log_to_aim(stats, tag, step) + self.wrapped_bar.print(stats, tag=tag, step=step) + + def update_config(self, config): + """Log latest configuration.""" + if self.run is not None: + for key in config: + self.run.set(key, config[key], strict=False) + self.wrapped_bar.update_config(config) + + def _log_to_aim(self, stats, tag=None, step=None): + if self.run is None: + return + + if step is None: + step = stats["num_updates"] + + if "train" in tag: + context = {"tag": tag, "subset": "train"} + elif "val" in tag: + context = {"tag": tag, "subset": "val"} + else: + context = {"tag": tag} + + for key in stats.keys() - {"num_updates"}: + self.run.track(stats[key], name=key, step=step, context=context) + + try: _tensorboard_writers = {} from torch.utils.tensorboard import SummaryWriter diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 0833f140ae..376bd1d03a 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -270,6 +270,17 @@ def train( log_file=cfg.common.log_file, log_interval=cfg.common.log_interval, epoch=epoch_itr.epoch, + aim_repo=( + cfg.common.aim_repo + if distributed_utils.is_master(cfg.distributed_training) + else None + ), + aim_run_hash=( + cfg.common.aim_run_hash + if distributed_utils.is_master(cfg.distributed_training) + else None + ), + aim_param_checkpoint_dir=cfg.checkpoint.save_dir, tensorboard_logdir=( cfg.common.tensorboard_logdir if distributed_utils.is_master(cfg.distributed_training) @@ -455,6 +466,17 @@ def validate( log_interval=cfg.common.log_interval, epoch=epoch_itr.epoch, prefix=f"valid on '{subset}' subset", + aim_repo=( + cfg.common.aim_repo + if distributed_utils.is_master(cfg.distributed_training) + else None + ), + aim_run_hash=( + cfg.common.aim_run_hash + if distributed_utils.is_master(cfg.distributed_training) + else None + ), + aim_param_checkpoint_dir=cfg.checkpoint.save_dir, tensorboard_logdir=( cfg.common.tensorboard_logdir if distributed_utils.is_master(cfg.distributed_training) From 47e279842ac8776e3964b0e45c320ad1d2ea6096 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Fri, 1 Apr 2022 11:38:02 -0700 Subject: [PATCH 596/774] add large speech model and link to data2vec vision (#3264) Summary: adds data2vec large speech models + link to vision repo X-link: https://github.com/fairinternal/fairseq-py/pull/3264 Reviewed By: michaelauli Differential Revision: D35304818 Pulled By: alexeib fbshipit-source-id: 1068b40ea576471b265f40b2616b8b386b310efa --- examples/data2vec/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/data2vec/README.md b/examples/data2vec/README.md index a0aab16fa2..9fd05d8042 100644 --- a/examples/data2vec/README.md +++ b/examples/data2vec/README.md @@ -8,7 +8,7 @@ data2vec is a framework for self-supervised representation learning for images, ### Vision -Coming soon! +Code and pre-trained models for data2vec visions can be found [here](https://github.com/facebookresearch/data2vec_vision/tree/main/beit). ### Speech @@ -18,6 +18,11 @@ data2vec Base | No fine-tuning | [Librispeech](http://www.openslr.org/12) | [dow data2vec Base | 10 minutes | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/audio_base_ls_10m.pt) data2vec Base | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/audio_base_ls_100h.pt) data2vec Base | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/audio_base_ls_960h.pt) +data2vec Large | No fine-tuning | [Libri-light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/vox_pretrained.pt) +data2vec Large | 10 minutes | [Libri-light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/vox_10m.pt) +data2vec Large | 100 hours | [Libri-light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/vox_100h.pt) +data2vec Large | 960 hours | [Libri-light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec/vox_960h.pt) +--- ### NLP From 97076f9168158d3d8255e35c9746820b2ea4bf33 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Tue, 5 Apr 2022 09:15:26 -0700 Subject: [PATCH 597/774] Add codeowners file for UST related codebase (#3269) Summary: - Adding [CODEOWNERS](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners) for UST related codebase. The advantage is that all the owners will automatically be added as reviewers to PR's modifying the associated code. This is a good way to stay up-to-date with any changes to the code we are working on. - Tested the paths by copying into .gitignore as suggested in [here](http://www.benjaminoakes.com/git/2018/08/10/Testing-changes-to-GitHub-CODEOWNERS/) using `find . \( -path ./.git \) -prune -o -print | git check-ignore -v --stdin --no-index` X-link: https://github.com/fairinternal/fairseq-py/pull/3269 Reviewed By: kahne Differential Revision: D35368333 Pulled By: sravyapopuri388 fbshipit-source-id: 965496fd33977da4dd09e8df0c6bcea19c288bc9 --- .github/CODEOWNERS | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..4e818c6f99 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,18 @@ +# Setting up CODEOWNERS for UST related codebase +# Documentation for open sourced models relevant to UST +examples/speech_to_text @kahne @sravyapopuri388 @jmp84 +examples/speech_to_speech @an918tw @sravyapopuri388 @jmp84 +examples/speech_synthesis @kahne @jmp84 +examples/simultaneous_translation @kahne @jmp84 +examples/speech_text_joint_to_text @yuntang @jmp84 + +# Speech related models relevant to UST +fairseq/models/speech_to_speech @sravyapopuri388 @jmp84 +fairseq/models/speech_to_text @kahne @sravyapopuri388 @jmp84 +fairseq/models/text_to_speech @kahne @jmp84 + +# CONFORMER IMPLEMENTATION +fairseq/modules/conformer_layer.py @sravyapopuri388 @jmp84 +fairseq/modules/espnet_multihead_attention.py @sravyapopuri388 @jmp84 +fairseq/modules/rotary_positional_embedding.py @sravyapopuri388 @jmp84 +fairseq/modules/positional_encoding.py @sravyapopuri388 @jmp84 From 8fce12ddd4a0414de5a726af6193cee4893f0a13 Mon Sep 17 00:00:00 2001 From: freewym <freewym@gmail.com> Date: Tue, 5 Apr 2022 15:13:14 -0700 Subject: [PATCH 598/774] Support decimal label rate (#3937) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Make label_rate be of type float in Hubert pretraining to support decimal label rate (e.g. 33.3Hz, otherwise verify_label_lengths() will give warnings if the undelying label rate is 33.3Hz) # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3937 Reviewed By: zhengwy888 Differential Revision: D31489119 Pulled By: dianaml0 fbshipit-source-id: 3f9fa76b0fb07affbb947d5c7c09b6e48fbba231 --- fairseq/data/audio/hubert_dataset.py | 4 ++-- fairseq/models/hubert/hubert.py | 2 +- fairseq/tasks/hubert_pretraining.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/fairseq/data/audio/hubert_dataset.py b/fairseq/data/audio/hubert_dataset.py index 1c0267bbc0..a69b7dc9db 100644 --- a/fairseq/data/audio/hubert_dataset.py +++ b/fairseq/data/audio/hubert_dataset.py @@ -141,7 +141,7 @@ def __init__( self.single_target = single_target self.label_rates = ( [label_rates for _ in range(len(label_paths))] - if isinstance(label_rates, int) + if isinstance(label_rates, float) else label_rates ) self.store_labels = store_labels @@ -302,7 +302,7 @@ def collater_label(self, targets_by_label, audio_size, audio_starts): targets_list, lengths_list, ntokens_list = [], [], [] itr = zip(targets_by_label, self.label_rates, self.pad_list) for targets, label_rate, pad in itr: - if label_rate == -1: + if label_rate == -1.0: targets, lengths, ntokens = self.collater_seq_label(targets, pad) else: targets, lengths, ntokens = self.collater_frm_label( diff --git a/fairseq/models/hubert/hubert.py b/fairseq/models/hubert/hubert.py index d1e89dc9eb..0c0349eb2f 100644 --- a/fairseq/models/hubert/hubert.py +++ b/fairseq/models/hubert/hubert.py @@ -35,7 +35,7 @@ @dataclass class HubertConfig(FairseqDataclass): - label_rate: int = II("task.label_rate") + label_rate: float = II("task.label_rate") extractor_mode: EXTRACTOR_MODE_CHOICES = field( default="default", diff --git a/fairseq/tasks/hubert_pretraining.py b/fairseq/tasks/hubert_pretraining.py index b8667d42ac..1a3605f14d 100644 --- a/fairseq/tasks/hubert_pretraining.py +++ b/fairseq/tasks/hubert_pretraining.py @@ -55,9 +55,9 @@ class HubertPretrainingConfig(FairseqDataclass): "help": "if set, looks for labels in this directory instead", }, ) - label_rate: int = field( - default=-1, - metadata={"help": "label frame rate. -1 for sequence label"}, + label_rate: float = field( + default=-1.0, + metadata={"help": "label frame rate. -1.0 for sequence label"}, ) sample_rate: int = field( default=16_000, From 31d94f556bd49bc7e61511adbda482b2c54652b5 Mon Sep 17 00:00:00 2001 From: Victoria Lin <victorialin@fb.com> Date: Wed, 6 Apr 2022 09:56:02 -0700 Subject: [PATCH 599/774] Update XGLM README with model FFN dimension (#4331) Summary: Pull Request resolved: https://github.com/pytorch/fairseq/pull/4331 Reviewed By: ngoyal2707 Differential Revision: D35423131 Pulled By: todpole3 fbshipit-source-id: c91e590b30f7d90ffd3ac60d8cc2ef3031c0c039 --- examples/xglm/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/xglm/README.md b/examples/xglm/README.md index 0d9da32530..fb630f6f07 100644 --- a/examples/xglm/README.md +++ b/examples/xglm/README.md @@ -9,13 +9,13 @@ XGLM models are trained on a new multilingual corpus extracted from CommonCrawl ## Pre-trained models -Model | Layers | Model Dim | Languages | Download ----|---|---|---|--- -`XGLM 564M` | 24 | 1024 | trained on 30 languages| [xglm.564M.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.564M.tar.gz) -`XGLM 1.7B` | 24 | 2048 | trained on 30 languages| [xglm.1.7B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.1.7B.tar.gz) -`XGLM 2.9B` | 48 | 2048 | trained on 30 languages| [xglm.2.9B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.2.9B.tar.gz) -`XGLM 7.5B` | 32 | 4096 | trained on 30 languages| [xglm.7.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.7.5B.tar.gz) -`XGLM 4.5B` | 48 | 2048 | trained on 134 languages| [xglm.4.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.4.5B.tar.gz) +Model | Layers | Model Dim | FFN Dim | Languages | Download +---|---|---|---|---|--- +`XGLM 564M` | 24 | 1024 | 4096 | trained on 30 languages| [xglm.564M.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.564M.tar.gz) +`XGLM 1.7B` | 24 | 2048 | 8192 | trained on 30 languages| [xglm.1.7B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.1.7B.tar.gz) +`XGLM 2.9B` | 48 | 2048 | 8192 | trained on 30 languages| [xglm.2.9B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.2.9B.tar.gz) +`XGLM 7.5B` | 32 | 4096 | 16384 | trained on 30 languages| [xglm.7.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.7.5B.tar.gz) +`XGLM 4.5B` | 48 | 2048 | 16384 | trained on 134 languages| [xglm.4.5B.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xglm/xglm.4.5B.tar.gz) ## Pre-training Data Format Our models were pre-trained with data in the following format (i.e. paragraphs are separated with new lines and documents were separated with double new lines). From 8ca4813190f1e92b6fb734a0b8afa20ad231e289 Mon Sep 17 00:00:00 2001 From: Anchit Gupta <anchit@fb.com> Date: Mon, 11 Apr 2022 12:09:18 -0700 Subject: [PATCH 600/774] Optimize ngram blocking in SequenceGenerator Summary: Detecting repeated ngram is currently super slow in fairseq. I discovered this while reading the [fastseq paper](https://arxiv.org/abs/2106.04718) While this was partially solved in fairseq by borrowing their optimized cuda kernel in [PR](https://github.com/fairinternal/fairseq-py/pull/1509) there was no optimization made for the CPU case. Moreover most users (including me) don't know about this obscure ngram kernel and how to compile it. Also the kernel isn't torchscriptable Diving through the fastseq code i discovered this [PR](https://github.com/microsoft/fastseq/pull/18) and re-implemented the same optimization. This does away with slow dictionaries and relies on much faster lists as well as simplifies the code. # Performance Benchmarking We get **1.7X** improvement in E2E inference throughput without scripting and **3.2X** with scripting Data/Task: summarization task (BookSum) Hardware: A100 (I used batch size 5, expect much larger gains with larger batch sizes) Without torchscripting **Before: 15.7s/it** **After: 9.5s/it** **With kernel: 9.3s/it** With torchscripted NGramRepeatBlock **Before: 32.99s/it After: 10.1s/it** The dictionary handling in torchscript is especially slow hurting the existing implementation by 2 times! The new one doesn't suffer as much of a slowdown This new implementation comes very close to the optimized CUDA kernel but works on CPU and supports torchscripting. Reviewed By: xwhan Differential Revision: D35517508 fbshipit-source-id: 4fd9dcbc0076064601af0621b76113b70835fb02 --- fairseq/ngram_repeat_block.py | 64 ++++++++++------------------------- 1 file changed, 17 insertions(+), 47 deletions(-) diff --git a/fairseq/ngram_repeat_block.py b/fairseq/ngram_repeat_block.py index 98e707d1b8..4eb5030311 100644 --- a/fairseq/ngram_repeat_block.py +++ b/fairseq/ngram_repeat_block.py @@ -4,7 +4,7 @@ """ Wrapper for ngram_repeat_block cuda extension """ import math import warnings -from typing import Dict, List, Optional +from typing import List import torch from torch import nn @@ -95,56 +95,26 @@ def forward( def _no_repeat_ngram(self, tokens, lprobs, bsz: int, beam_size: int, step: int): """For each hypothesis generate a list of previous ngrams and set associated lprobs to -inf""" - gen_ngrams: List[Dict[str, List[int]]] = [ - torch.jit.annotate(Dict[str, List[int]], {}) - for bbsz_idx in range(bsz * beam_size) + banned_tokens = [ + torch.jit.annotate(List[int], []) for bbsz_idx in range(bsz * beam_size) ] - cpu_tokens = tokens.cpu() - for bbsz_idx in range(bsz * beam_size): - gen_tokens: List[int] = cpu_tokens[bbsz_idx].tolist() - for ngram in self.transpose_list( - [gen_tokens[i:] for i in range(self.no_repeat_ngram_size)] - ): - key = ",".join([str(x) for x in ngram[:-1]]) - gen_ngrams[bbsz_idx][key] = gen_ngrams[bbsz_idx].get( - key, torch.jit.annotate(List[int], []) - ) + [ngram[-1]] if step + 2 - self.no_repeat_ngram_size >= 0: - # no banned tokens if we haven't generated no_repeat_ngram_size tokens yet - banned_tokens = [ - self.calculate_banned_tokens( - tokens, step, gen_ngrams, self.no_repeat_ngram_size, bbsz_idx - ) - for bbsz_idx in range(bsz * beam_size) - ] - else: - banned_tokens = [ - torch.jit.annotate(List[int], []) for bbsz_idx in range(bsz * beam_size) - ] + cpu_tokens: List[List[int]] = tokens.cpu().tolist() + check_start_pos = step + 2 - self.no_repeat_ngram_size + for bbsz_idx in range(bsz * beam_size): + ngram_to_check = cpu_tokens[bbsz_idx][ + -(self.no_repeat_ngram_size - 1) : + ] + for i in range(check_start_pos): + if ( + ngram_to_check + == cpu_tokens[bbsz_idx][i : i + self.no_repeat_ngram_size - 1] + ): + banned_tokens[bbsz_idx].append( + cpu_tokens[bbsz_idx][i + self.no_repeat_ngram_size - 1] + ) for bbsz_idx in range(bsz * beam_size): lprobs[bbsz_idx][ torch.tensor(banned_tokens[bbsz_idx], dtype=torch.int64) ] = torch.tensor(-math.inf).to(lprobs) return lprobs - - @staticmethod - def calculate_banned_tokens( - tokens, - step: int, - gen_ngrams: List[Dict[str, List[int]]], - no_repeat_ngram_size: int, - bbsz_idx: int, - ): - tokens_list: List[int] = tokens[ - bbsz_idx, step + 2 - no_repeat_ngram_size : step + 1 - ].tolist() - # before decoding the next token, prevent decoding of ngrams that have already appeared - ngram_index = ",".join([str(x) for x in tokens_list]) - return gen_ngrams[bbsz_idx].get(ngram_index, torch.jit.annotate(List[int], [])) - - @staticmethod - def transpose_list(l: List[List[int]]): - # GeneratorExp aren't supported in TS so ignoring the lint - min_len = min([len(x) for x in l]) # noqa - l2 = [[row[i] for row in l] for i in range(min_len)] - return l2 From 7e758841da9e05cb21826a60d30a563a9e189d1d Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Mon, 11 Apr 2022 22:31:35 -0700 Subject: [PATCH 601/774] Fix documentation errors in Enhanced Direct Speech-to-Speech Translation Using Self-supervised Pre-training and Data Augmentation (#3280) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3280 Reviewed By: jmp84 Differential Revision: D35451365 Pulled By: sravyapopuri388 fbshipit-source-id: 691480e2f568922c1bf29f5d109dc042c0588a67 --- examples/speech_to_speech/README.md | 6 ++-- .../enhanced_direct_s2st_discrete_units.md | 35 +++++++++++-------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/examples/speech_to_speech/README.md b/examples/speech_to_speech/README.md index 48cce071ad..f03f6a32f8 100644 --- a/examples/speech_to_speech/README.md +++ b/examples/speech_to_speech/README.md @@ -1,5 +1,7 @@ # Speech to speech translation (S2ST) We provide the implementation and resources for the following work on speech-to-speech translation (S2ST): - * [Direct speech-to-speech translation with discrete units (Lee et al. 2021)](docs/direct_s2st_discrete_units.md) - * [Textless Speech-to-Speech Translation on Real Data (Lee et al. 2021)](docs/textless_s2st_real_data.md) + +* [Direct speech-to-speech translation with discrete units (Lee et al. 2021)](docs/direct_s2st_discrete_units.md) +* [Textless Speech-to-Speech Translation on Real Data (Lee et al. 2021)](docs/textless_s2st_real_data.md) +* [Enhanced Direct Speech-to-Speech Translation Using Self-supervised Pre-training and Data Augmentation](docs/enhanced_direct_s2st_discrete_units.md) diff --git a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md index a0fc8180d6..959de864d3 100644 --- a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md +++ b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md @@ -1,31 +1,34 @@ # Speech to speech translation (S2ST) -We provide the implementation for speech-to-unit translation (S2UT) proposed in [_Enhanced Direct Speech-to-Speech Translation Using Self-supervised Pre-training and Data Augmentation_](arxiv link) and the various pretrained models used. +We provide the implementation for speech-to-unit translation (S2UT) proposed in [Enhanced Direct Speech-to-Speech Translation Using Self-supervised Pre-training and Data Augmentation (Popuri et al. 2022)](https://arxiv.org/abs/2204.02967) and the various pretrained models used. ## Pretrained Models -### Unit extraction +### Unit extraction + We used the multilingual HuBERT model open sourced in [Textless S2ST with Real Data](textless_s2st_real_data.md) ### Wav2vec 2.0 + Language | Block type | Model size | Dataset | Model | --- | --- | --- | --- | --- | -Es | Transformer | BASE | Voxpopuli | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/transformer_B.pt) | -Es | Transformer | LARGE | Voxpopuli | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/transformer_L.pt) | -Es | Conformer | LARGE | Voxpopuli | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/conformer_L.pt) | -En | Transformer | BASE | Librilight| [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/en/transformer_B.pt) | -En | Conformer | LARGE | Librilight | [ckpt ](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/en/conformer_L.pt) | +Es | Transformer | BASE | Voxpopuli | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/transformer_B.pt) | +Es | Transformer | LARGE | Voxpopuli | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/transformer_L.pt) | +Es | Conformer | LARGE | Voxpopuli | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/es/conformer_L.pt) | +En | Transformer | BASE | Librilight| [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/en/transformer_B.pt) | +En | Conformer | LARGE | Librilight | [ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/w2v2/en/conformer_L.pt) | ### Unit mBART -Unit size | Dataset | Unit config | Model | ---- | --- | --- | --- | -1000 | [Voxpopuli](https://aclanthology.org/2021.acl-long.80) En, Es unlabelled speech | [mbart_large](https://github.com/pytorch/fairseq/blob/f591cc94caa85098ccf125a4782f91125b6a086d/fairseq/models/bart/model.py#L368) |[ckpt](htpps://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/unit_mBART/checkpoint.pt) | +Unit size | Dataset | Unit config | Model | +--- | --- | --- | --- | +1000 | [Voxpopuli](https://aclanthology.org/2021.acl-long.80) En, Es unlabelled speech | [mbart_large](https://github.com/pytorch/fairseq/blob/f591cc94caa85098ccf125a4782f91125b6a086d/fairseq/models/bart/model.py#L368) |[ckpt](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/unit_mBART/checkpoint.pt) | -## Data preparation +## Data preparation 1. To prepare data for S2UT finetuning, follow the steps from [Direct S2ST with Discrete Units](./direct_s2st_discrete_units.md) and format the data in the _S2UT_ format. Note that we use 1000 units from the eleventh layer (`--layer 11`) of the multilingual hubert model linked above instead 2. Run + ``` var="id\taudio\tn_frames\ttgt_text\ttgt_n_frames" sed -i "1s/.*/$var/" ${SPLIT}.tsv @@ -36,6 +39,7 @@ sed -i "1s/.*/$var/" ${SPLIT}.tsv **Speech-to-unit translation (S2UT)** Here's an example for finetuning S2UT models with 1000 discrete units as target. You can download the config file and vocabulary from here[add links]: + ``` fairseq-train $DATA_ROOT \ --config-yaml config.yaml \ @@ -54,14 +58,14 @@ fairseq-train $DATA_ROOT \ --max-target-positions 4000 --update-freq 120 \ --seed 1 --fp16 --num-workers 1 ``` + * Adjust `--update-freq` accordingly for different #GPUs. In the above we set `--update-freq 15` to simulate training with 120 GPUs. * In the above setting we finetune the model end to end, corresponding to the full setup in the paper. * To apply LNA-E partial finetuning, add `--finetune-w2v-params layer_norm,self_attn` * For LNA-D partial finetuning add `--finetune-decoder-params encoder_attn,layer_norm,self_attn`. To optionally freeze the encoder by k updates, use `--freeze-finetune-updates ${K}` * For LNA-E,D partial finetuning add both the above options. - -**Unit-based HiFi-GAN vocoder** +**Unit-based HiFi-GAN vocoder** We apply the open-sourced unit-based HiFi-GAN vocoders to convert the predicted unit sequences to waveform. They are open sourced in [Textless S2ST with Real Data](textless_s2st_real_data.md) @@ -70,6 +74,7 @@ We apply the open-sourced unit-based HiFi-GAN vocoders to convert the predicted **Speech-to-unit translation (S2UT)** 1. Follow the same inference process as in [fairseq-S2T](https://github.com/pytorch/fairseq/tree/main/examples/speech_to_text) to generate unit sequences (`${RESULTS_PATH}/generate-${GEN_SUBSET}.txt`). + ``` fairseq-generate $DATA_ROOT \ --config-yaml config.yaml \ @@ -81,6 +86,7 @@ fairseq-generate $DATA_ROOT \ ``` 2. Convert unit sequences to waveform. + ``` grep "^D\-" ${RESULTS_PATH}/generate-${GEN_SUBSET}.txt | \ sed 's/^D-//ig' | sort -nk1 | cut -f3 \ @@ -92,12 +98,11 @@ python examples/speech_to_speech/generate_waveform_from_code.py \ --results-path ${RESULTS_PATH} --dur-prediction ``` - ## Evaluation To evaluate speech translation output, we first apply ASR on the speech output and then compute BLEU score betweent the ASR decoded text and the references using sacreBLEU. * Text normalization: We use the text cleaner at [https://github.com/keithito/tacotron](https://github.com/keithito/tacotron) for pre-processing reference English text for ASR BLEU evaluation. The text cleaner used for Spanish text normalization will be updated here shortly. * En ASR: We use the "[Wav2Vec 2.0 Large (LV-60) + Self Training / 960 hours / Libri-Light + Librispeech](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt)" En ASR model open-sourced by the [wav2vec](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec) project. The model is also available on [Hugging Face](https://huggingface.co/facebook/wav2vec2-large-960h-lv60-self). -* Es ASR: We use the [Wav2Vec2-Large-XLSR-53-Spanish](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) finetuned on spanish Common Voice Es ASR model open-sourced by Jonatasgrosman(https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish) on [Hugging Face](https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish). +* Es ASR: We use the [Wav2Vec2-Large-XLSR-53-Spanish](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) finetuned on spanish Common Voice Es ASR model open-sourced by Jonatasgrosman(<https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish>) on [Hugging Face](https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish). * See [instructions](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#evaluating-a-ctc-model) on how to run inference with a wav2vec-based ASR model. From edb25c6b08c0631184b50f0c9cc7c5cb7ff01ef4 Mon Sep 17 00:00:00 2001 From: Patrick von Platen <patrick.v.platen@gmail.com> Date: Wed, 13 Apr 2022 20:15:48 +0200 Subject: [PATCH 602/774] Update README.md (#4349) --- examples/wav2vec/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/wav2vec/README.md b/examples/wav2vec/README.md index 9cd2245381..e979733075 100644 --- a/examples/wav2vec/README.md +++ b/examples/wav2vec/README.md @@ -23,15 +23,15 @@ Wav2Vec 2.0 Large | 10 minutes | [Librispeech](http://www.openslr.org/12) | [do Wav2Vec 2.0 Large | 100 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_100h.pt) Wav2Vec 2.0 Large | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_big_960h.pt) Wav2Vec 2.0 Large (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_new.pt) -Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_no_FT ) -Wav2Vec 2.0 Large conformer - rope (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_no_FT ) +Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_no_FT) +Wav2Vec 2.0 Large conformer - rope (LV-60)* | No finetuning | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_rope_PT_no_FT) Wav2Vec 2.0 Large (LV-60)* | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_new.pt) Wav2Vec 2.0 Large (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_new.pt) -Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_100h_FT.pt ) -Wav2Vec 2.0 Large conformer - rope (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_rope_PT_100h_FT.pt ) +Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_100h_FT.pt) +Wav2Vec 2.0 Large conformer - rope (LV-60)* | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_rope_PT_100h_FT.pt) Wav2Vec 2.0 Large (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec2_vox_960h_new.pt) -Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_960h_FT.pt ) -Wav2Vec 2.0 Large conformer - rope (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_rope_PT_960h_FT.pt ) +Wav2Vec 2.0 Large conformer - rel_pos (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_relpos_PT_960h_FT.pt) +Wav2Vec 2.0 Large conformer - rope (LV-60)* | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) | [download](s3://dl.fbaipublicfiles.com/fairseq/conformer/wav2vec2/librilight/LL_rope_PT_960h_FT.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 10 minutes | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_10m_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 100 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_100h_pl.pt) Wav2Vec 2.0 Large (LV-60) + Self Training * | 960 hours | [Libri-Light](https://github.com/facebookresearch/libri-light) + [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt) From 2e3c81034937bca63e45338bffc4f14b3267c15a Mon Sep 17 00:00:00 2001 From: Mateusz Klimaszewski <mk.klimaszewski@gmail.com> Date: Thu, 14 Apr 2022 15:39:36 -0700 Subject: [PATCH 603/774] Fix typo in exception value (#4334) Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes typo ## PR review ## Did you have fun? Pull Request resolved: https://github.com/pytorch/fairseq/pull/4334 Reviewed By: Mortimerp9 Differential Revision: D35503972 Pulled By: dianaml0 fbshipit-source-id: 09893de009d398e7a048ec89f757634ddc10139d --- fairseq/checkpoint_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 73374bedf1..aeb04f79be 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -232,7 +232,7 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): ) else: raise ValueError( - f"--funetune-from-model {cfg.finetune_from_model} does not exist" + f"--finetune-from-model {cfg.finetune_from_model} does not exist" ) elif suffix is not None: checkpoint_path = cfg.restore_file.replace(".pt", suffix + ".pt") From f862ff5137cf03ec8769b6e8f19c9dcdfe08ff91 Mon Sep 17 00:00:00 2001 From: freewym <freewym@gmail.com> Date: Sat, 16 Apr 2022 14:54:44 -0700 Subject: [PATCH 604/774] fix a bug in compute_mask_indices() for wav2vec (#3266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes a bug in the no_overlap case when computing mask indices for wav2vec ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/3266 Reviewed By: arbabu123 Differential Revision: D35704063 Pulled By: alexeib fbshipit-source-id: 3b77dc4cc50e539b57e6ad5f38f59eb975356adb --- fairseq/data/data_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 9cd88ca76e..0372d52b0f 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -476,7 +476,7 @@ def arrange(s, e, length, keep_length): new_parts = [] if span_start - s - min_space >= keep_length: new_parts.append((s, span_start - min_space + 1)) - if e - span_start - keep_length - min_space > keep_length: + if e - span_start - length - min_space > keep_length: new_parts.append((span_start + length + min_space, e)) return new_parts From 355ffbe4e2d0a8169287eb63a8218d2dea8be086 Mon Sep 17 00:00:00 2001 From: Alexander Jipa <azzhipa@amazon.com> Date: Mon, 18 Apr 2022 14:47:00 -0700 Subject: [PATCH 605/774] add masked_lm test (#4344) Summary: # Before submitting - [X] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [X] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [X] Did you make sure to update the docs? - [X] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/4300 ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Big time! Note: I had to update `black` because of [this known issue](https://github.com/psf/black/issues/2964): ``` black....................................................................Failed - hook id: black - exit code: 1 Traceback (most recent call last): File "/Users/azzhipa/.cache/pre-commit/repoxt83whf2/py_env-python3.8/bin/black", line 8, in <module> sys.exit(patched_main()) File "/Users/azzhipa/.cache/pre-commit/repoxt83whf2/py_env-python3.8/lib/python3.8/site-packages/black/__init__.py", line 1423, in patched_main patch_click() File "/Users/azzhipa/.cache/pre-commit/repoxt83whf2/py_env-python3.8/lib/python3.8/site-packages/black/__init__.py", line 1409, in patch_click from click import _unicodefun ImportError: cannot import name '_unicodefun' from 'click' (/Users/azzhipa/.cache/pre-commit/repoxt83whf2/py_env-python3.8/lib/python3.8/site-packages/click/__init__.py) ``` Pull Request resolved: https://github.com/pytorch/fairseq/pull/4344 Reviewed By: zhengwy888 Differential Revision: D35691648 Pulled By: dianaml0 fbshipit-source-id: 4bdf408bc9d9cca76c9c08e138cf85b1d00d14d4 --- .github/workflows/build.yml | 2 +- .pre-commit-config.yaml | 2 +- fairseq/tasks/masked_lm.py | 24 ++++++----- tests/tasks/test_masked_lm.py | 78 +++++++++++++++++++++++++++++++++++ tests/utils.py | 9 ++++ 5 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 tests/tasks/test_masked_lm.py diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a80e0f92c9..9abd0690fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,5 +56,5 @@ jobs: - name: Lint with black run: | - pip install black + pip install black==22.3.0 black --check . --extend-exclude 'examples|fairseq\/model_parallel\/megatron' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e8f7a8bfc6..6b1d6aed8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - id: end-of-file-fixer - repo: https://github.com/ambv/black - rev: 22.1.0 + rev: 22.3.0 hooks: - id: black language_version: python3.8 diff --git a/fairseq/tasks/masked_lm.py b/fairseq/tasks/masked_lm.py index d83dca6c1f..6393ee4800 100644 --- a/fairseq/tasks/masked_lm.py +++ b/fairseq/tasks/masked_lm.py @@ -3,13 +3,13 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from dataclasses import dataclass, field import logging import os - -from omegaconf import MISSING, II, OmegaConf +from dataclasses import dataclass, field import numpy as np +from omegaconf import II, MISSING, OmegaConf + from fairseq import utils from fairseq.data import ( Dictionary, @@ -31,7 +31,6 @@ from .language_modeling import SAMPLE_BREAK_MODE_CHOICES, SHORTEN_METHOD_CHOICES - logger = logging.getLogger(__name__) @@ -131,12 +130,7 @@ def setup_task(cls, cfg: MaskedLMConfig, **kwargs): logger.info("dictionary: {} types".format(len(dictionary))) return cls(cfg, dictionary) - def load_dataset(self, split, epoch=1, combine=False, **kwargs): - """Load a given dataset split. - - Args: - split (str): name of the split (e.g., train, valid, test) - """ + def _load_dataset_split(self, split, epoch, combine): paths = utils.split_paths(self.cfg.data) assert len(paths) > 0 data_path = paths[(epoch - 1) % len(paths)] @@ -173,7 +167,15 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): logger.info("loaded {} blocks from: {}".format(len(dataset), split_path)) # prepend beginning-of-sentence token (<s>, equiv. to [CLS] in BERT) - dataset = PrependTokenDataset(dataset, self.source_dictionary.bos()) + return PrependTokenDataset(dataset, self.source_dictionary.bos()) + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + """Load a given dataset split. + + Args: + split (str): name of the split (e.g., train, valid, test) + """ + dataset = self._load_dataset_split(split, epoch, combine) # create masked input and targets mask_whole_words = ( diff --git a/tests/tasks/test_masked_lm.py b/tests/tasks/test_masked_lm.py new file mode 100644 index 0000000000..215cd355b0 --- /dev/null +++ b/tests/tasks/test_masked_lm.py @@ -0,0 +1,78 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import unittest +from tempfile import TemporaryDirectory + +from fairseq.binarizer import FileBinarizer, VocabularyDatasetBinarizer +from fairseq.tasks.masked_lm import MaskedLMConfig, MaskedLMTask +from tests.utils import build_vocab, make_data + + +class TestMaskedLM(unittest.TestCase): + def test_masks_tokens(self): + with TemporaryDirectory() as dirname: + + # prep input file + raw_file = os.path.join(dirname, "raw") + data = make_data(out_file=raw_file) + vocab = build_vocab(data) + + # binarize + binarizer = VocabularyDatasetBinarizer(vocab, append_eos=False) + split = "train" + bin_file = os.path.join(dirname, split) + FileBinarizer.multiprocess_dataset( + input_file=raw_file, + binarizer=binarizer, + dataset_impl="mmap", + vocab_size=len(vocab), + output_prefix=bin_file, + ) + + # setup task + cfg = MaskedLMConfig( + data=dirname, + seed=42, + mask_prob=0.5, # increasing the odds of masking + random_token_prob=0, # avoiding random tokens for exact match + leave_unmasked_prob=0, # always masking for exact match + ) + task = MaskedLMTask(cfg, binarizer.dict) + + original_dataset = task._load_dataset_split(bin_file, 1, False) + + # load datasets + task.load_dataset(split) + masked_dataset = task.dataset(split) + + mask_index = task.source_dictionary.index("<mask>") + iterator = task.get_batch_iterator( + dataset=masked_dataset, + max_tokens=65_536, + max_positions=4_096, + ).next_epoch_itr(shuffle=False) + for batch in iterator: + for sample in range(len(batch)): + net_input = batch["net_input"] + masked_src_tokens = net_input["src_tokens"][sample] + masked_src_length = net_input["src_lengths"][sample] + masked_tgt_tokens = batch["target"][sample] + + sample_id = batch["id"][sample] + original_tokens = original_dataset[sample_id] + original_tokens = original_tokens.masked_select( + masked_src_tokens[:masked_src_length] == mask_index + ) + masked_tokens = masked_tgt_tokens.masked_select( + masked_tgt_tokens != task.source_dictionary.pad() + ) + + assert masked_tokens.equal(original_tokens) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/utils.py b/tests/utils.py index c14029e599..af3f714ed1 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -786,3 +786,12 @@ def make_data(length=1000, out_file=None) -> tp.List[tp.List[str]]: print(" ".join(s), file=out) return data + + +def build_vocab(data: tp.List[tp.List[str]]) -> Dictionary: + d = Dictionary() + for s in data: + for token in s: + d.add_symbol(token) + d.finalize() + return d From 7356784f01b94f1c3507a436d7e1412c5bd205e6 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Tue, 19 Apr 2022 16:04:09 -0700 Subject: [PATCH 606/774] fix missing links for vocabulary and config in the Enhanced direct S2ST documentation (#3320) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3320 Reviewed By: an918tw Differential Revision: D35752980 Pulled By: sravyapopuri388 fbshipit-source-id: da59d0621f6fa5d981701802f69a89495bcb9599 --- .../docs/enhanced_direct_s2st_discrete_units.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md index 959de864d3..55bf22100e 100644 --- a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md +++ b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md @@ -38,7 +38,7 @@ sed -i "1s/.*/$var/" ${SPLIT}.tsv **Speech-to-unit translation (S2UT)** -Here's an example for finetuning S2UT models with 1000 discrete units as target. You can download the config file and vocabulary from here[add links]: +Here's an example for finetuning S2UT models with 1000 discrete units as target. You can download the [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/config.yaml) file and [vocabulary](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/dict.txt) from here: ``` fairseq-train $DATA_ROOT \ From 806855bf660ea748ed7ffb42fe8dcc881ca3aca0 Mon Sep 17 00:00:00 2001 From: Anchit Gupta <anchit@fb.com> Date: Wed, 20 Apr 2022 11:21:46 -0700 Subject: [PATCH 607/774] Fast Beamable enc-dec attention Summary: Implements beamable encoder-decoder cross attention. This removes the need to duplicate the encoder states beam_size # of times during inference. Which gives both a big memory improvement enabling larger batch sizes while on GPU and also compute efficiency by greatly reducing time spent in reorder_encoder_out. This is inspired from work in [fastseq](https://arxiv.org/abs/2106.04718) which has more in-depth analysis. There was an old [PR](https://github.com/pytorch/fairseq/pull/1958) for fairseq as well to implement this feature but was not merged and eventually closed. I revive+refactor that PR and also add support for dynamically changing the beam_size while calling `hub_interface.generate()` ## Benchmarking **CPU Performance** (On-demand devserver) batch size: 1 | beam size: 4 50.4s/it -> 22.3s/it | **2.25X Speedup** batch size: 2 | beam size: 4 53.1s/it -> 25.8s/it | **2.06X Speedup** batch size: 1 | beam size: 8 65.8s/it -> 23.8s/it | **2.76X Speedup** **GPU Performance** Reported in detail [here](https://github.com/pytorch/fairseq/issues/1957) Currently this optimization is only enabled for our custom BART model used in the workplace summarization demo to unblock landing this fast. This should be up-streamed to TransformerModel after syncing with fairseq folk. Reviewed By: xwhan Differential Revision: D35722467 fbshipit-source-id: a420f73ff5b9ec0cdf40c59464b6ed1794114906 --- fairseq/models/bart/model.py | 11 +++ .../models/transformer/transformer_decoder.py | 3 - .../models/transformer/transformer_encoder.py | 5 ++ fairseq/modules/multihead_attention.py | 74 ++++++++++++++----- fairseq/sequence_generator.py | 8 ++ 5 files changed, 79 insertions(+), 22 deletions(-) diff --git a/fairseq/models/bart/model.py b/fairseq/models/bart/model.py index ba30c1d742..e3670c0a2c 100644 --- a/fairseq/models/bart/model.py +++ b/fairseq/models/bart/model.py @@ -279,6 +279,17 @@ def truncate_emb(key): logger.info("Overwriting " + prefix + "classification_heads." + k) state_dict[prefix + "classification_heads." + k] = v + def set_beam_size(self, beam): + """Set beam size for efficient beamable enc-dec attention.""" + beamable = False + for layer in self.decoder.layers: + if layer.encoder_attn is not None: + if hasattr(layer.encoder_attn, "set_beam_size"): + layer.encoder_attn.set_beam_size(beam) + beamable = True + if beamable: + self.encoder.reorder_encoder_out = self.encoder._reorder_encoder_out + class BARTClassificationHead(nn.Module): """Head for sentence-level classification tasks.""" diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py index bc66949cf9..61aaa098e9 100644 --- a/fairseq/models/transformer/transformer_decoder.py +++ b/fairseq/models/transformer/transformer_decoder.py @@ -287,9 +287,6 @@ def extract_features_scriptable( padding_mask: Optional[Tensor] = None if encoder_out is not None and len(encoder_out["encoder_out"]) > 0: enc = encoder_out["encoder_out"][0] - assert ( - enc.size()[1] == bs - ), f"Expected enc.shape == (t, {bs}, c) got {enc.shape}" if encoder_out is not None and len(encoder_out["encoder_padding_mask"]) > 0: padding_mask = encoder_out["encoder_padding_mask"][0] diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index 739eb9df2c..0b7e6d8379 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -313,6 +313,11 @@ def reorder_encoder_out(self, encoder_out: Dict[str, List[Tensor]], new_order): "src_lengths": src_lengths, # B x 1 } + @torch.jit.export + def _reorder_encoder_out(self, encoder_out: Dict[str, List[Tensor]], new_order): + """Dummy re-order function for beamable enc-dec attention""" + return encoder_out + def max_positions(self): """Maximum input length supported by the encoder.""" if self.embed_positions is None: diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index dd07cd9e45..7af8f65ce4 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -84,7 +84,7 @@ def __init__( self.bias_k = self.bias_v = None self.add_zero_attn = add_zero_attn - + self.beam_size = 1 self.reset_parameters() self.onnx_trace = False @@ -286,9 +286,8 @@ def forward( if key is not None: src_len, key_bsz, _ = key.size() if not torch.jit.is_scripting(): - assert key_bsz == bsz assert value is not None - assert src_len, bsz == value.shape[:2] + assert src_len, key_bsz == value.shape[:2] if ( not self.onnx_trace @@ -351,6 +350,11 @@ def forward( assert value is None k = v = None else: + if self.beam_size > 1 and bsz == key.size(1): + # key is [T, bsz*beam_size, C], reduce to [T, bsz, C] + key = key.view(key.size(0), -1, self.beam_size, key.size(2))[:, :, 0, :] + if key_padding_mask is not None: + key_padding_mask = key_padding_mask.view(-1, self.beam_size, key_padding_mask.size(1))[:, 0, :] k = self.k_proj(key) v = self.v_proj(key) @@ -383,16 +387,18 @@ def forward( .view(tgt_len, bsz * self.num_heads, self.head_dim) .transpose(0, 1) ) + kv_bsz = bsz # need default value for scripting if k is not None: + kv_bsz = k.size(1) k = ( k.contiguous() - .view(-1, bsz * self.num_heads, self.head_dim) + .view(-1, kv_bsz * self.num_heads, self.head_dim) .transpose(0, 1) ) if v is not None: v = ( v.contiguous() - .view(-1, bsz * self.num_heads, self.head_dim) + .view(-1, kv_bsz * self.num_heads, self.head_dim) .transpose(0, 1) ) @@ -401,7 +407,8 @@ def forward( if "prev_key" in saved_state: _prev_key = saved_state["prev_key"] assert _prev_key is not None - prev_key = _prev_key.view(bsz * self.num_heads, -1, self.head_dim) + kv_bsz = _prev_key.size(0) + prev_key = _prev_key.view(kv_bsz * self.num_heads, -1, self.head_dim) if static_kv: k = prev_key else: @@ -411,7 +418,8 @@ def forward( if "prev_value" in saved_state: _prev_value = saved_state["prev_value"] assert _prev_value is not None - prev_value = _prev_value.view(bsz * self.num_heads, -1, self.head_dim) + assert kv_bsz == _prev_value.size(0) + prev_value = _prev_value.view(kv_bsz * self.num_heads, -1, self.head_dim) if static_kv: v = prev_value else: @@ -424,13 +432,13 @@ def forward( key_padding_mask = MultiheadAttention._append_prev_key_padding_mask( key_padding_mask=key_padding_mask, prev_key_padding_mask=prev_key_padding_mask, - batch_size=bsz, + batch_size=kv_bsz, src_len=k.size(1), static_kv=static_kv, ) - saved_state["prev_key"] = k.view(bsz, self.num_heads, -1, self.head_dim) - saved_state["prev_value"] = v.view(bsz, self.num_heads, -1, self.head_dim) + saved_state["prev_key"] = k.view(kv_bsz, self.num_heads, -1, self.head_dim) + saved_state["prev_value"] = v.view(kv_bsz, self.num_heads, -1, self.head_dim) saved_state["prev_key_padding_mask"] = key_padding_mask # In this branch incremental_state is never None assert incremental_state is not None @@ -444,7 +452,7 @@ def forward( key_padding_mask = None if key_padding_mask is not None: - assert key_padding_mask.size(0) == bsz + assert key_padding_mask.size(0) == kv_bsz assert key_padding_mask.size(1) == src_len if self.add_zero_attn: @@ -467,7 +475,15 @@ def forward( dim=1, ) - attn_weights = torch.bmm(q, k.transpose(1, 2)) + if self.encoder_decoder_attention and bsz != kv_bsz: + attn_weights = torch.einsum( + "bxhtd,bhsd->bxhts", + q.view((kv_bsz, -1, self.num_heads) + q.size()[1:]), + k.view((kv_bsz, self.num_heads) + k.size()[1:]), + ) + attn_weights = attn_weights.reshape((-1,) + attn_weights.size()[-2:]) + else: + attn_weights = torch.bmm(q, k.transpose(1, 2)) attn_weights = self.apply_sparse_mask(attn_weights, tgt_len, src_len, bsz) assert list(attn_weights.size()) == [bsz * self.num_heads, tgt_len, src_len] @@ -482,8 +498,12 @@ def forward( # don't attend to padding symbols attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) if not is_tpu: + attn_weights = attn_weights.view(kv_bsz, -1, self.num_heads, tgt_len, src_len) attn_weights = attn_weights.masked_fill( - key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), + key_padding_mask.unsqueeze(1) + .unsqueeze(2) + .unsqueeze(3) + .to(torch.bool), float("-inf"), ) else: @@ -502,7 +522,15 @@ def forward( attn_probs = self.dropout_module(attn_weights) assert v is not None - attn = torch.bmm(attn_probs, v) + if self.encoder_decoder_attention and bsz != kv_bsz: + attn = torch.einsum( + "bxhts,bhsd->bxhtd", + attn_probs.view((kv_bsz, -1, self.num_heads,) + attn_probs.size()[1:]), + v.view((kv_bsz, self.num_heads,) + v.size()[1:]), + ) + attn = attn.reshape((-1,) + attn.size()[-2:]) + else: + attn = torch.bmm(attn_probs, v) assert list(attn.size()) == [bsz * self.num_heads, tgt_len, self.head_dim] if self.onnx_trace and attn.size(1) == 1: # when ONNX tracing a single decoder step (sequence length == 1) @@ -578,14 +606,22 @@ def reorder_incremental_state( for k in input_buffer.keys(): input_buffer_k = input_buffer[k] if input_buffer_k is not None: - if self.encoder_decoder_attention and input_buffer_k.size( - 0 - ) == new_order.size(0): - break - input_buffer[k] = input_buffer_k.index_select(0, new_order) + if self.encoder_decoder_attention: + if input_buffer_k.size(0) * self.beam_size == new_order.size(0): + return incremental_state + elif self.beam_size > 1: + input_buffer[k] = input_buffer_k.index_select(0, new_order.reshape(-1, self.beam_size)[:, 0] // self.beam_size) + else: + input_buffer[k] = input_buffer_k.index_select(0, new_order) + else: + input_buffer[k] = input_buffer_k.index_select(0, new_order) incremental_state = self._set_input_buffer(incremental_state, input_buffer) return incremental_state + def set_beam_size(self, beam_size): + """Used for effiecient beamable enc-dec attention""" + self.beam_size = beam_size + def _get_input_buffer( self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] ) -> Dict[str, Optional[Tensor]]: diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index e7e02d8285..976adbca00 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -80,6 +80,7 @@ def __init__( self.beam_size = beam_size # the max beam size is the dictionary size - 1, since we never select pad self.beam_size = min(beam_size, self.vocab_size - 1) + self.model.set_decoder_beam_size(self.beam_size) self.max_len_a = max_len_a self.max_len_b = max_len_b self.min_len = min_len @@ -768,6 +769,13 @@ def max_decoder_positions(self): + [sys.maxsize] ) + def set_decoder_beam_size(self, beam_size): + """Set beam size for efficient beamable enc-dec attention.""" + if beam_size > 1: + for model in self.models: + if hasattr(model, 'set_beam_size'): + model.set_beam_size(beam_size) + @torch.jit.export def forward_encoder(self, net_input: Dict[str, Tensor]): if not self.has_encoder(): From caac1873863cc9bf662afc5040a93682e2d4c158 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Wed, 27 Apr 2022 16:41:08 -0700 Subject: [PATCH 608/774] fix formatting (#3346) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Breaking build. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3346 Reviewed By: anchit Differential Revision: D35979333 Pulled By: dianaml0 fbshipit-source-id: 929e1d4a0b94d7f214646a5d5c226a790c563573 --- fairseq/modules/multihead_attention.py | 43 +++++++++++++++++++++----- fairseq/sequence_generator.py | 7 +++-- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 7af8f65ce4..4fcfaff92c 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -352,9 +352,13 @@ def forward( else: if self.beam_size > 1 and bsz == key.size(1): # key is [T, bsz*beam_size, C], reduce to [T, bsz, C] - key = key.view(key.size(0), -1, self.beam_size, key.size(2))[:, :, 0, :] + key = key.view(key.size(0), -1, self.beam_size, key.size(2))[ + :, :, 0, : + ] if key_padding_mask is not None: - key_padding_mask = key_padding_mask.view(-1, self.beam_size, key_padding_mask.size(1))[:, 0, :] + key_padding_mask = key_padding_mask.view( + -1, self.beam_size, key_padding_mask.size(1) + )[:, 0, :] k = self.k_proj(key) v = self.v_proj(key) @@ -419,7 +423,9 @@ def forward( _prev_value = saved_state["prev_value"] assert _prev_value is not None assert kv_bsz == _prev_value.size(0) - prev_value = _prev_value.view(kv_bsz * self.num_heads, -1, self.head_dim) + prev_value = _prev_value.view( + kv_bsz * self.num_heads, -1, self.head_dim + ) if static_kv: v = prev_value else: @@ -438,7 +444,9 @@ def forward( ) saved_state["prev_key"] = k.view(kv_bsz, self.num_heads, -1, self.head_dim) - saved_state["prev_value"] = v.view(kv_bsz, self.num_heads, -1, self.head_dim) + saved_state["prev_value"] = v.view( + kv_bsz, self.num_heads, -1, self.head_dim + ) saved_state["prev_key_padding_mask"] = key_padding_mask # In this branch incremental_state is never None assert incremental_state is not None @@ -498,7 +506,9 @@ def forward( # don't attend to padding symbols attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len) if not is_tpu: - attn_weights = attn_weights.view(kv_bsz, -1, self.num_heads, tgt_len, src_len) + attn_weights = attn_weights.view( + kv_bsz, -1, self.num_heads, tgt_len, src_len + ) attn_weights = attn_weights.masked_fill( key_padding_mask.unsqueeze(1) .unsqueeze(2) @@ -525,8 +535,21 @@ def forward( if self.encoder_decoder_attention and bsz != kv_bsz: attn = torch.einsum( "bxhts,bhsd->bxhtd", - attn_probs.view((kv_bsz, -1, self.num_heads,) + attn_probs.size()[1:]), - v.view((kv_bsz, self.num_heads,) + v.size()[1:]), + attn_probs.view( + ( + kv_bsz, + -1, + self.num_heads, + ) + + attn_probs.size()[1:] + ), + v.view( + ( + kv_bsz, + self.num_heads, + ) + + v.size()[1:] + ), ) attn = attn.reshape((-1,) + attn.size()[-2:]) else: @@ -610,7 +633,11 @@ def reorder_incremental_state( if input_buffer_k.size(0) * self.beam_size == new_order.size(0): return incremental_state elif self.beam_size > 1: - input_buffer[k] = input_buffer_k.index_select(0, new_order.reshape(-1, self.beam_size)[:, 0] // self.beam_size) + input_buffer[k] = input_buffer_k.index_select( + 0, + new_order.reshape(-1, self.beam_size)[:, 0] + // self.beam_size, + ) else: input_buffer[k] = input_buffer_k.index_select(0, new_order) else: diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 976adbca00..7d323d85e7 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -4,15 +4,16 @@ # LICENSE file in the root directory of this source tree. import math -from typing import Dict, List, Optional import sys +from typing import Dict, List, Optional import torch import torch.nn as nn +from torch import Tensor + from fairseq import search, utils from fairseq.data import data_utils from fairseq.models import FairseqIncrementalDecoder -from torch import Tensor from fairseq.ngram_repeat_block import NGramRepeatBlock @@ -773,7 +774,7 @@ def set_decoder_beam_size(self, beam_size): """Set beam size for efficient beamable enc-dec attention.""" if beam_size > 1: for model in self.models: - if hasattr(model, 'set_beam_size'): + if hasattr(model, "set_beam_size"): model.set_beam_size(beam_size) @torch.jit.export From 72d3408481c5a60c39cb12e1770774b88543c9ab Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Wed, 27 Apr 2022 16:54:02 -0700 Subject: [PATCH 609/774] Pull out some code into separate methods (#3068) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Pulling out some changes from https://github.com/fairinternal/fairseq-py/pull/2263 unrelated to xformers to make the PR cleaner ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3068 Reviewed By: blefaudeux Differential Revision: D34149016 Pulled By: dianaml0 fbshipit-source-id: 6442a5f451d56cc47106227298a624516b19a9ad --- fairseq/modules/multihead_attention.py | 87 +++++++++++++++++--------- tests/test_multihead_attention.py | 84 +++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 30 deletions(-) diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 4fcfaff92c..495a506ff6 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -241,6 +241,57 @@ def _adaptive_prune_heads(self, reserve_head_index: List[Tuple[int, int]]): def _set_skip_embed_dim_check(self): self.skip_embed_dim_check = True + def _pad_masks( + self, + key_padding_mask: Optional[Tensor], + attn_mask: Optional[Tensor], + ) -> Tuple[Optional[Tensor], Optional[Tensor]]: + if attn_mask is not None: + shape = attn_mask.size()[:-1] + torch.Size([1]) + attn_mask = torch.cat([attn_mask, attn_mask.new_zeros(shape)], dim=-1) + if key_padding_mask is not None: + shape = key_padding_mask.size()[:-1] + torch.Size([1]) + key_padding_mask = torch.cat( + [ + key_padding_mask, + key_padding_mask.new_zeros(shape), + ], + dim=-1, + ) + return key_padding_mask, attn_mask + + def _add_bias( + self, + k: Tensor, + v: Tensor, + key_padding_mask: Optional[Tensor], + attn_mask: Optional[Tensor], + bsz: int, + ) -> Tuple[Tensor, Tensor, Optional[Tensor], Optional[Tensor]]: + assert self.bias_k is not None + assert self.bias_v is not None + k = torch.cat([k, self.bias_k.repeat(1, bsz, 1)]) + v = torch.cat([v, self.bias_v.repeat(1, bsz, 1)]) + key_padding_mask, attn_mask = self._pad_masks(key_padding_mask=key_padding_mask, attn_mask=attn_mask) + return k, v, key_padding_mask, attn_mask + + def _append_zero_attn( + self, + k: Tensor, + v: Tensor, + key_padding_mask: Optional[Tensor], + attn_mask: Optional[Tensor], + ) -> Tuple[Tensor, Tensor, Optional[Tensor], Optional[Tensor]]: + zero_attn_shape = k.size()[:-2] + torch.Size([1]) + k.size()[-1:] + k = torch.cat( + [k, torch.zeros(zero_attn_shape, dtype=k.dtype, device=k.device)], dim=-2 + ) + v = torch.cat( + [v, torch.zeros(zero_attn_shape, dtype=v.dtype, device=v.device)], dim=-2 + ) + key_padding_mask, attn_mask = self._pad_masks(key_padding_mask=key_padding_mask, attn_mask=attn_mask) + return k, v, key_padding_mask, attn_mask + def forward( self, query, @@ -371,20 +422,9 @@ def forward( if self.bias_k is not None: assert self.bias_v is not None - k = torch.cat([k, self.bias_k.repeat(1, bsz, 1)]) - v = torch.cat([v, self.bias_v.repeat(1, bsz, 1)]) - if attn_mask is not None: - attn_mask = torch.cat( - [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1 - ) - if key_padding_mask is not None: - key_padding_mask = torch.cat( - [ - key_padding_mask, - key_padding_mask.new_zeros(key_padding_mask.size(0), 1), - ], - dim=1, - ) + k, v, attn_mask, key_padding_mask = self._add_bias( + k, v, attn_mask, key_padding_mask, bsz + ) q = ( q.contiguous() @@ -466,22 +506,9 @@ def forward( if self.add_zero_attn: assert v is not None src_len += 1 - k = torch.cat([k, k.new_zeros((k.size(0), 1) + k.size()[2:])], dim=1) - v = torch.cat([v, v.new_zeros((v.size(0), 1) + v.size()[2:])], dim=1) - if attn_mask is not None: - attn_mask = torch.cat( - [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1 - ) - if key_padding_mask is not None: - key_padding_mask = torch.cat( - [ - key_padding_mask, - torch.zeros(key_padding_mask.size(0), 1).type_as( - key_padding_mask - ), - ], - dim=1, - ) + k, v, key_padding_mask, attn_mask = self._append_zero_attn( + k=k, v=v, key_padding_mask=key_padding_mask, attn_mask=attn_mask + ) if self.encoder_decoder_attention and bsz != kv_bsz: attn_weights = torch.einsum( diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index 59864f9685..4e8f32c160 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -9,6 +9,90 @@ from fairseq.modules.multihead_attention import MultiheadAttention +def test_mask_padding_parity(): + + def old_padding_code(key_padding_mask, attn_mask): + if attn_mask is not None: + attn_mask = torch.cat( + [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1 + ) + if key_padding_mask is not None: + key_padding_mask = torch.cat( + [ + key_padding_mask, + torch.zeros(key_padding_mask.size(0), 1).type_as( + key_padding_mask + ), + ], + dim=1, + ) + return key_padding_mask, attn_mask + + # values don't matter for this test. + mha = MultiheadAttention( + embedding=8, + num_heads=2, + dropout=0.0, + add_bias_kv=True, + add_zero_attn=True, + ) + + key_padding_mask = torch.rand((8, 64)) + attn_mask = torch.rand((64, 64)) + + kp_mask_orig, a_mask_orig = old_padding_code(key_padding_mask, attn_mask) + kp_mask_new, a_mask_new = mha._pad_masks(key_padding_mask, attn_mask) + + assert kp_mask_orig.size() == kp_mask_new.size() + assert a_mask_orig.size() == a_mask_new.size() + assert torch.equal(kp_mask_orig, kp_mask_new) + assert torch.equal(a_mask_orig, a_mask_new) + + +def test_add_bias_parity(): + # values don't matter for this test. + mha = MultiheadAttention( + embedding=8, + num_heads=2, + dropout=0.0, + add_bias_kv=True, + add_zero_attn=True, + ) + + def old_bias_code(k, v, key_padding_mask, attn_mask, bsz): + k = torch.cat([k, mha.bias_k.repeat(1, bsz, 1)]) + v = torch.cat([v, mha.bias_v.repeat(1, bsz, 1)]) + if attn_mask is not None: + attn_mask = torch.cat( + [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1 + ) + if key_padding_mask is not None: + key_padding_mask = torch.cat( + [ + key_padding_mask, + key_padding_mask.new_zeros(key_padding_mask.size(0), 1), + ], + dim=1, + ) + return k, v, key_padding_mask, attn_mask + + seq_len = 64 + bsz = 8 + embedding = 8 + key_padding_mask = torch.rand((bsz, seq_len)) + attn_mask = torch.rand((seq_len, seq_len)) + k = torch.rand((seq_len, bsz, embedding)) + v = torch.rand((seq_len, bsz, embedding)) + + k_orig, v_orig, kp_mask_orig, a_mask_orig = old_bias_code(k, v, key_padding_mask, attn_mask, bsz) + k_new, v_new, kp_mask_new, a_mask_new = mha._add_bias(k, v, key_padding_mask, attn_mask, bsz) + + assert torch.equal(k_orig, k_new) + assert torch.equal(v_orig, v_new) + assert torch.equal(kp_mask_orig, kp_mask_new) + assert torch.equal(a_mask_orig, a_mask_new) + + class TestMultiheadAttention(unittest.TestCase): def test_append_prev_key_padding_mask(self): bsz = 1 From ab98e94046b451f0da0d3ee2dc4ad9f661018a24 Mon Sep 17 00:00:00 2001 From: Colin Clement <colin.clement@microsoft.com> Date: Thu, 28 Apr 2022 10:55:42 -0700 Subject: [PATCH 610/774] fairseq[-hydra]-train torchrun compatibility: default device_id set to LOCAL_RANK if exists (#4351) Summary: # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/pytorch/fairseq/issues/4302 (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? I had fun when I figured out why torchrun was failing :) Pull Request resolved: https://github.com/pytorch/fairseq/pull/4351 Reviewed By: shruti-bh Differential Revision: D35784181 Pulled By: dianaml0 fbshipit-source-id: 560c7af12b2f9278cba6c85711b98b9e043d0ec9 --- fairseq/dataclass/configs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 7e304f0ff4..43456d5b5f 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import os import sys from dataclasses import _MISSING_TYPE, dataclass, field from typing import Any, List, Optional @@ -285,9 +286,9 @@ class DistributedTrainingConfig(FairseqDataclass): }, ) device_id: int = field( - default=0, + default=os.getenv("LOCAL_RANK", 0), metadata={ - "help": "which GPU to use (usually configured automatically)", + "help": "which GPU to use (by default looks for $LOCAL_RANK, usually configured automatically)", "argparse_alias": "--local_rank", }, ) From 0b54d9fb2e42c2f40db3449ca34586952b8abe94 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Thu, 28 Apr 2022 14:17:09 -0700 Subject: [PATCH 611/774] fix formatting (#3350) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3350 Reviewed By: shruti-bh Differential Revision: D36009526 Pulled By: dianaml0 fbshipit-source-id: 9cdc3d53086b8d40a780bcb64cfe28108091ab98 --- fairseq/modules/multihead_attention.py | 8 ++++++-- tests/test_multihead_attention.py | 14 ++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 495a506ff6..fd33ba4462 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -272,7 +272,9 @@ def _add_bias( assert self.bias_v is not None k = torch.cat([k, self.bias_k.repeat(1, bsz, 1)]) v = torch.cat([v, self.bias_v.repeat(1, bsz, 1)]) - key_padding_mask, attn_mask = self._pad_masks(key_padding_mask=key_padding_mask, attn_mask=attn_mask) + key_padding_mask, attn_mask = self._pad_masks( + key_padding_mask=key_padding_mask, attn_mask=attn_mask + ) return k, v, key_padding_mask, attn_mask def _append_zero_attn( @@ -289,7 +291,9 @@ def _append_zero_attn( v = torch.cat( [v, torch.zeros(zero_attn_shape, dtype=v.dtype, device=v.device)], dim=-2 ) - key_padding_mask, attn_mask = self._pad_masks(key_padding_mask=key_padding_mask, attn_mask=attn_mask) + key_padding_mask, attn_mask = self._pad_masks( + key_padding_mask=key_padding_mask, attn_mask=attn_mask + ) return k, v, key_padding_mask, attn_mask def forward( diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index 4e8f32c160..ebed9c903f 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -6,11 +6,11 @@ import unittest import torch + from fairseq.modules.multihead_attention import MultiheadAttention def test_mask_padding_parity(): - def old_padding_code(key_padding_mask, attn_mask): if attn_mask is not None: attn_mask = torch.cat( @@ -20,9 +20,7 @@ def old_padding_code(key_padding_mask, attn_mask): key_padding_mask = torch.cat( [ key_padding_mask, - torch.zeros(key_padding_mask.size(0), 1).type_as( - key_padding_mask - ), + torch.zeros(key_padding_mask.size(0), 1).type_as(key_padding_mask), ], dim=1, ) @@ -84,8 +82,12 @@ def old_bias_code(k, v, key_padding_mask, attn_mask, bsz): k = torch.rand((seq_len, bsz, embedding)) v = torch.rand((seq_len, bsz, embedding)) - k_orig, v_orig, kp_mask_orig, a_mask_orig = old_bias_code(k, v, key_padding_mask, attn_mask, bsz) - k_new, v_new, kp_mask_new, a_mask_new = mha._add_bias(k, v, key_padding_mask, attn_mask, bsz) + k_orig, v_orig, kp_mask_orig, a_mask_orig = old_bias_code( + k, v, key_padding_mask, attn_mask, bsz + ) + k_new, v_new, kp_mask_new, a_mask_new = mha._add_bias( + k, v, key_padding_mask, attn_mask, bsz + ) assert torch.equal(k_orig, k_new) assert torch.equal(v_orig, v_new) From 51478ad3a19feed51d4bc4df5416870b7cee5347 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Wed, 4 May 2022 09:15:36 -0700 Subject: [PATCH 612/774] xformer integration (#2263) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/master/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? This PR is a cleaned up version of https://github.com/fairinternal/fairseq-py/issues/2138. It is based on the `main` branch instead of the `gshard` branch. Removed call to xFormers MultiHeadDispatch, only using xFormers Attention. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/2263 Reviewed By: blefaudeux Differential Revision: D33800377 Pulled By: dianaml0 fbshipit-source-id: 658d52214c782212b12881b30c4d908a763b4cf2 --- .circleci/config.yml | 13 + .github/workflows/build.yml | 2 + README.md | 1 + .../benchmark_multihead_attention.py | 172 +++++++++ .../models/transformer/transformer_config.py | 7 + fairseq/models/transformer_lm.py | 13 +- fairseq/modules/multihead_attention.py | 214 +++++++++-- fairseq/modules/transformer_layer.py | 3 + setup.py | 1 - tests/test_multihead_attention.py | 338 +++++++++++++++++- 10 files changed, 735 insertions(+), 29 deletions(-) create mode 100644 fairseq/benchmark/benchmark_multihead_attention.py diff --git a/.circleci/config.yml b/.circleci/config.yml index de40a6e9c5..c29b534ff9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,6 +45,17 @@ install_dep_fused_ops: &install_dep_fused_ops cd Megatron-LM pip install -e . +install_dep_xformers: &install_dep_xformers + - run: + name: Install xFormers Dependencies + working_directory: ~/ + command: | + source activate fairseq + git clone https://github.com/facebookresearch/xformers.git + cd xformers + pip install -r requirements.txt + pip install -e . + install_dep_pt19: &install_dep_pt19 - run: @@ -123,6 +134,7 @@ jobs: - <<: *install_dep_pt19 - <<: *install_dep_common - <<: *install_dep_fused_ops + - <<: *install_dep_xformers - save_cache: paths: - ~/miniconda/ @@ -144,6 +156,7 @@ jobs: - <<: *install_dep_pt18 - <<: *install_dep_common - <<: *install_dep_fused_ops + - <<: *install_dep_xformers - save_cache: paths: - ~/miniconda/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9abd0690fe..16b42974b0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,6 +41,8 @@ jobs: run: | python -m pip install iopath transformers pyarrow python -m pip install git+https://github.com/facebookresearch/fairscale.git@main + python -m pip install --progress-bar off git+https://github.com/facebookresearch/xformers.git@main + python -m pip install pytest - name: Lint with flake8 run: | diff --git a/README.md b/README.md index b4a848ecf2..a354e1b9ea 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ We provide reference implementations of various sequence modeling papers: </p></details> ### What's New: +* May 2022 [Integration with xFormers](https://github.com/facebookresearch/xformers) * December 2021 [Released Direct speech-to-speech translation code](examples/speech_to_speech/README.md) * October 2021 [Released VideoCLIP and VLM models](examples/MMPT/README.md) * October 2021 [Released multilingual finetuned XLSR-53 model](examples/wav2vec/README.md) diff --git a/fairseq/benchmark/benchmark_multihead_attention.py b/fairseq/benchmark/benchmark_multihead_attention.py new file mode 100644 index 0000000000..a44847f250 --- /dev/null +++ b/fairseq/benchmark/benchmark_multihead_attention.py @@ -0,0 +1,172 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import itertools +import random + +import torch +from torch.utils import benchmark + +from fairseq.modules.multihead_attention import MultiheadAttention + +BATCH = [20, 41, 97] +SEQ = 64 +EMB = 48 +HEADS = 4 +DROP = 0.1 +DEVICE = torch.device("cuda") +ATTN_MASK_DTYPE = [torch.uint8, torch.bool, torch.float] +KEY_PADDING_MASK_DTYPE = [torch.uint8, torch.bool] + + +def _reset_seeds(): + torch.manual_seed(0) + random.seed(0) + + +def _get_mask(to_dtype: torch.dtype, dim0: int, dim1: int): + if to_dtype == torch.float: + mask = torch.randint(0, 2, (dim0, dim1)).to(dtype=torch.bool) + return mask.to(dtype=to_dtype).masked_fill(mask, -float("inf")) + return torch.randint(0, 2, (dim0, dim1)).to(dtype=to_dtype) + + +def benchmark_multihead_attention( + label="", + attn_dtype=torch.uint8, + key_padding_dtype=torch.uint8, + add_bias_kv=False, + add_zero_attn=False, + static_kv=False, + batch_size=20, + embedding=EMB, + seq_len=SEQ, + num_heads=HEADS, +): + + results = [] + # device = torch.device("cuda") + + xformers_att_config = '{"name": "scaled_dot_product"}' + + attn_mask = _get_mask(to_dtype=attn_dtype, dim0=seq_len, dim1=seq_len) + key_padding_mask = _get_mask( + to_dtype=key_padding_dtype, dim0=batch_size, dim1=seq_len + ) + + q = torch.rand(seq_len, batch_size, embedding, requires_grad=True) + k = torch.rand(seq_len, batch_size, embedding, requires_grad=True) + v = torch.rand(seq_len, batch_size, embedding, requires_grad=True) + + _reset_seeds() + + original_mha = MultiheadAttention( + embedding, + num_heads, + dropout=0.0, + xformers_att_config=None, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + + xformers_mha = MultiheadAttention( + embedding, + num_heads, + dropout=0.0, + xformers_att_config=xformers_att_config, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + + def original_bench_fw(q, k, v, key_padding_mask, attn_mask, static_kv): + original_mha( + query=q, + key=k, + value=v, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + static_kv=static_kv, + ) + + def xformers_bench_fw(q, k, v, key_padding_mask, attn_mask, static_kv): + xformers_mha( + query=q, + key=k, + value=v, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + static_kv=static_kv, + ) + + def original_bench_fw_bw(q, k, v, key_padding_mask, attn_mask, static_kv): + output, _ = original_mha( + query=q, + key=k, + value=v, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + static_kv=static_kv, + ) + loss = torch.norm(output) + loss.backward() + + def xformers_bench_fw_bw(q, k, v, key_padding_mask, attn_mask, static_kv): + output, _ = xformers_mha( + query=q, + key=k, + value=v, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + static_kv=static_kv, + ) + loss = torch.norm(output) + loss.backward() + + fns = [ + original_bench_fw, + xformers_bench_fw, + original_bench_fw_bw, + xformers_bench_fw_bw, + ] + + for fn in fns: + results.append( + benchmark.Timer( + stmt="fn(q, k, v, key_padding_mask, attn_mask, static_kv)", + globals={ + "q": q, + "k": k, + "v": v, + "key_padding_mask": key_padding_mask, + "attn_mask": attn_mask, + "static_kv": static_kv, + "fn": fn, + }, + label="multihead fw + bw", + sub_label=f"{fn.__name__}", + description=label, + ).blocked_autorange(min_run_time=1) + ) + + compare = benchmark.Compare(results) + compare.print() + + +def run_benchmarks(): + for attn_dtype, key_padding_dtype, add_bias_kv, add_zero_attn in itertools.product( + ATTN_MASK_DTYPE, KEY_PADDING_MASK_DTYPE, [True, False], [True, False] + ): + label = f"attn_dtype {attn_dtype}, key_padding_dtype {key_padding_dtype}, \ + add_bias_kv {add_bias_kv}, add_zero_attn {add_zero_attn}" + benchmark_multihead_attention( + label=label, + attn_dtype=attn_dtype, + key_padding_dtype=key_padding_dtype, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + + +run_benchmarks() diff --git a/fairseq/models/transformer/transformer_config.py b/fairseq/models/transformer/transformer_config.py index 4ebd292b0d..119b030b04 100644 --- a/fairseq/models/transformer/transformer_config.py +++ b/fairseq/models/transformer/transformer_config.py @@ -49,6 +49,13 @@ class EncDecBaseConfig(FairseqDataclass): default=None, metadata={"help": "which layers to *keep* when pruning"} ) + xformers_att_config: Optional[str] = field( + default=None, + metadata={ + "help": "config for xFormers attention, defined in xformers.components.attention.AttentionConfig" + }, + ) + @dataclass class DecoderConfig(EncDecBaseConfig): diff --git a/fairseq/models/transformer_lm.py b/fairseq/models/transformer_lm.py index 5a23888b1e..1e3aa72d38 100644 --- a/fairseq/models/transformer_lm.py +++ b/fairseq/models/transformer_lm.py @@ -7,6 +7,8 @@ from dataclasses import dataclass, field from typing import Optional +from omegaconf import II + from fairseq import options, utils from fairseq.dataclass import ChoiceEnum, FairseqDataclass from fairseq.models import ( @@ -21,8 +23,6 @@ ) from fairseq.modules import AdaptiveInput, CharacterTokenEmbedder from fairseq.utils import safe_getattr, safe_hasattr -from omegaconf import II - DEFAULT_MAX_TARGET_POSITIONS = 1024 @@ -210,6 +210,15 @@ class TransformerLanguageModelConfig(FairseqDataclass): default=False, metadata={"help": "Learn a scale coefficient for each residual connection"}, ) + + # xFormers arguments + decoder_xformers_att_config: Optional[str] = field( + default=None, + metadata={ + "help": "config for xFormers library attention, defined in xformers.components.attention.AttentionConfig", + }, + ) + # options from other parts of the config add_bos_token: bool = II("task.add_bos_token") tokens_per_sample: int = II("task.tokens_per_sample") diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index fd33ba4462..8d08331e42 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -10,6 +10,8 @@ import torch.nn.functional as F from torch import Tensor, nn from torch.nn import Parameter +from xformers.components.attention import build_attention +from xformers.components.attention.utils import maybe_merge_masks from fairseq import utils from fairseq.incremental_decoding_utils import with_incremental_state @@ -17,6 +19,40 @@ from fairseq.modules.quant_noise import quant_noise +# TODO: move this into xformers? +# TODO: uint8 input type should just output a bool +def _mask_for_xformers(mask: Tensor, to_dtype: Optional[torch.dtype] = None): + """ + call to pytorch multihead accepts three mask types: + - ByteTensor where non-zero means to mask + - FloatTensor which is an additive mask + - BoolTensor where True means to mask + xFormers currently accepts boolean and additive maks. For boolean masks + the values have opposite meaning. For a BoolTensor True mean to keep the value. + """ + float_types = [torch.float, torch.float16] + # If an input mask is a float it is an additive mask. Otherwise it is either uint8 or bool. + additive = mask.dtype in float_types + # If to_dype is not specified, keep same dtype as mask. + to_dtype = mask.dtype if to_dtype is None else to_dtype + to_additive = to_dtype in float_types + + if additive: + if to_additive: + return mask.to(to_dtype) + mask = mask < 0 + + if to_additive: + # return additive mask + new_mask = torch.zeros_like(mask, dtype=to_dtype) + new_mask = new_mask.masked_fill_(mask, -float("inf")) + return new_mask + + # In xFormers True is value to keep rather than value to mask + mask = ~mask.to(torch.bool) + mask = mask.to(to_dtype) + return mask + @with_incremental_state class MultiheadAttention(nn.Module): """Multi-headed attention. @@ -38,8 +74,20 @@ def __init__( encoder_decoder_attention=False, q_noise=0.0, qn_block_size=8, + # TODO: pass in config rather than string. + # config defined in xformers.components.attention.AttentionConfig + xformers_att_config: Optional[str] = None, + xformers_blocksparse_layout: Optional[ + torch.Tensor + ] = None, # This should be part of the config + xformers_blocksparse_blocksize: Optional[ + int + ] = 16, # This should be part of the config ): super().__init__() + + xformers_att_config = utils.eval_str_dict(xformers_att_config) + self.use_xformers = xformers_att_config is not None self.embed_dim = embed_dim self.kdim = kdim if kdim is not None else embed_dim self.vdim = vdim if vdim is not None else embed_dim @@ -87,6 +135,23 @@ def __init__( self.beam_size = 1 self.reset_parameters() + self.fp16_mask = False + if self.use_xformers: + xformers_att_config["dropout"] = xformers_att_config.get("dropout", dropout) + xformers_att_config["num_heads"] = xformers_att_config.get( + "num_heads", num_heads + ) + + if xformers_blocksparse_layout is not None: + # Could be part of a single config passed only once + xformers_att_config["block_size"] = xformers_blocksparse_blocksize + xformers_att_config["layout"] = xformers_blocksparse_layout + xformers_att_config["name"] = "blocksparse" + # Mask required to be float16 + self.fp16_mask = True + + self.attention = build_attention(xformers_att_config) + self.onnx_trace = False self.skip_embed_dim_check = False @@ -296,6 +361,102 @@ def _append_zero_attn( ) return k, v, key_padding_mask, attn_mask + def _xformers_attn_forward( + self, + query, + key: Optional[Tensor], + value: Optional[Tensor], + key_padding_mask: Optional[Tensor] = None, + need_weights: bool = True, + attn_mask: Optional[Tensor] = None, + ) -> Tuple[Tensor, Optional[Tensor]]: + + tgt_len, bsz, embed_dim = query.size() + + if key_padding_mask is not None: + assert key_padding_mask.size(0) == bsz + assert key_padding_mask.size(1) == tgt_len + + if self.self_attention: + key = query + value = query + elif self.encoder_decoder_attention: + value = key + + q = self.q_proj(query) + k = self.k_proj(key) + v = self.v_proj(value) + + if self.bias_k is not None: + assert self.bias_v is not None + k, v, attn_mask, key_padding_mask = self._add_bias( + k, v, attn_mask, key_padding_mask, bsz + ) + + def fold_heads(x): + return ( + x.contiguous() + .view(-1, bsz * self.num_heads, self.head_dim) + .transpose(0, 1) + ) + + def split_heads(x): + return ( + x.contiguous() + .view(-1, bsz, self.num_heads, self.head_dim) + .transpose(0, 1) + .transpose(1, 2) + ) + + massage = split_heads if self.attention.requires_head_dimension else fold_heads + q = massage(q) + if k is not None: + k = massage(k) + if v is not None: + v = massage(v) + + if self.add_zero_attn: + k, v, key_padding_mask, attn_mask = self._append_zero_attn( + k=k, v=v, key_padding_mask=key_padding_mask, attn_mask=attn_mask + ) + + if attn_mask is not None: + to_dtype = torch.float16 if self.fp16_mask else q.dtype + attn_mask = _mask_for_xformers(attn_mask, to_dtype=to_dtype) + + if key_padding_mask is not None: + to_dtype = torch.float16 if self.fp16_mask else torch.bool + key_padding_mask = _mask_for_xformers(key_padding_mask, to_dtype=to_dtype) + if not self.attention.requires_separate_masks: + attn_mask = maybe_merge_masks( + attn_mask, + key_padding_mask, + batch_size=bsz, + src_len=k.size(-2), + tgt_len=q.size(-2), + num_heads=self.num_heads, + ) + key_padding_mask = None + + y = self.attention( + q, k, v, att_mask=attn_mask, key_padding_mask=key_padding_mask + ) + + y = ( + y.view(bsz, self.num_heads, tgt_len, self.head_dim) + .transpose(1, 2) + .flatten(start_dim=2, end_dim=3) + .transpose(0, 1) + ) + assert list(y.size()) == [tgt_len, bsz, embed_dim] + + # Dropout not needed because already applied in attention. + # It is applied to the attention weights before matmul with v. + y = self.out_proj(y) + + # TODO: support returning attention weights if needed. + return y, None + def forward( self, query, @@ -359,29 +520,36 @@ def forward( and not self.skip_embed_dim_check ): assert key is not None and value is not None - return F.multi_head_attention_forward( - query, - key, - value, - self.embed_dim, - self.num_heads, - torch.empty([0]), - torch.cat((self.q_proj.bias, self.k_proj.bias, self.v_proj.bias)), - self.bias_k, - self.bias_v, - self.add_zero_attn, - self.dropout_module.p, - self.out_proj.weight, - self.out_proj.bias, - self.training or self.dropout_module.apply_during_inference, - key_padding_mask, - need_weights, - attn_mask, - use_separate_proj_weight=True, - q_proj_weight=self.q_proj.weight, - k_proj_weight=self.k_proj.weight, - v_proj_weight=self.v_proj.weight, - ) + + if self.use_xformers: + return self._xformers_attn_forward( + query, key, value, key_padding_mask, need_weights, attn_mask + ) + + else: + return F.multi_head_attention_forward( + query, + key, + value, + self.embed_dim, + self.num_heads, + torch.empty([0]), + torch.cat((self.q_proj.bias, self.k_proj.bias, self.v_proj.bias)), + self.bias_k, + self.bias_v, + self.add_zero_attn, + self.dropout_module.p, + self.out_proj.weight, + self.out_proj.bias, + self.training or self.dropout_module.apply_during_inference, + key_padding_mask, + need_weights, + attn_mask, + use_separate_proj_weight=True, + q_proj_weight=self.q_proj.weight, + k_proj_weight=self.k_proj.weight, + v_proj_weight=self.v_proj.weight, + ) if incremental_state is not None: saved_state = self._get_input_buffer(incremental_state) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 50025e0454..2e687b94d0 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -141,6 +141,7 @@ def build_self_attention(self, embed_dim, cfg): self_attention=True, q_noise=self.quant_noise, qn_block_size=self.quant_noise_block_size, + xformers_att_config=cfg.encoder.xformers_att_config, ) def residual_connection(self, x, residual): @@ -359,6 +360,7 @@ def build_self_attention( self_attention=not cfg.cross_self_attention, q_noise=self.quant_noise, qn_block_size=self.quant_noise_block_size, + xformers_att_config=cfg.decoder.xformers_att_config, ) def build_encoder_attention(self, embed_dim, cfg): @@ -371,6 +373,7 @@ def build_encoder_attention(self, embed_dim, cfg): encoder_decoder_attention=True, q_noise=self.quant_noise, qn_block_size=self.quant_noise_block_size, + xformers_att_config=cfg.encoder.xformers_att_config, ) def prepare_for_onnx_export_(self): diff --git a/setup.py b/setup.py index c5591915fa..e2e44570c1 100644 --- a/setup.py +++ b/setup.py @@ -173,7 +173,6 @@ def include_dirs(self, dirs): if "clean" in sys.argv[1:]: # Source: https://bit.ly/2NLVsgE print("deleting Cython files...") - import subprocess subprocess.run( ["rm -f fairseq/*.so fairseq/**/*.so fairseq/*.pyd fairseq/**/*.pyd"], diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index ebed9c903f..dd075ea88c 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -3,11 +3,343 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import random import unittest +import pytest import torch +from fairseq.modules.multihead_attention import MultiheadAttention, _mask_for_xformers -from fairseq.modules.multihead_attention import MultiheadAttention +BATCH = [20, 41, 97] +SEQ = [64] +EMB = [48] +HEADS = [4] +DROP = 0.1 +DEVICE = ["cpu", "cuda"] if torch.cuda.is_available() else ["cpu"] +ATTN_MASK_DTYPE = [None, torch.uint8, torch.bool, torch.float] +KEY_PADDING_MASK_DTYPE = [None, torch.uint8, torch.bool] + + +# FIXME: some tests fail when decimal=2, fix this and set decimal to 2 +def assert_almost_equal(x, y, decimal=1, err_msg=""): + import numpy.testing as npt + + if isinstance(x, torch.Tensor): + x = x.cpu().detach().numpy() + if isinstance(y, torch.Tensor): + y = y.cpu().detach().numpy() + npt.assert_array_almost_equal(x, y, err_msg=err_msg, decimal=decimal) + + +def _reset_seeds(): + torch.manual_seed(0) + torch.random.manual_seed(0) + random.seed(0) + torch.cuda.manual_seed_all(0) + + +def _get_mask(to_dtype: torch.dtype, dim0: int, dim1: int): + if to_dtype == torch.float: + mask = torch.randint(0, 2, (dim0, dim1)).to(dtype=torch.bool) + return mask.to(dtype=to_dtype).masked_fill(mask, -float("inf")) + return torch.randint(0, 2, (dim0, dim1)).to(dtype=to_dtype) + + +def test_mask_for_xformers(): + # Additive Mask + m_float_add = torch.tensor([float("-inf"), 0]).to(torch.float) + m_float_add_flipped = torch.tensor([0, float("-inf")]).to(torch.float) + m_float16_add = torch.tensor([float("-inf"), 0]).to(torch.float16) + m_float16_add_flipped = torch.tensor([0, float("-inf")]).to(torch.float16) + m_uint = torch.tensor([1, 0]).to(torch.uint8) + m_uint_flipped = torch.tensor([0, 1]).to(torch.uint8) + m_bool = torch.tensor([False, True]) + + assert torch.equal(_mask_for_xformers(m_float_add), m_float_add) + assert torch.equal(_mask_for_xformers(m_float16_add), m_float16_add) + assert torch.equal(_mask_for_xformers(m_uint), m_uint_flipped) + assert torch.equal(_mask_for_xformers(m_bool), ~m_bool) + + assert torch.equal( + _mask_for_xformers(m_float_add, to_dtype=torch.float16), m_float16_add + ) + assert torch.equal( + _mask_for_xformers(m_float_add, to_dtype=torch.float), m_float_add + ) + assert torch.equal(_mask_for_xformers(m_float_add, to_dtype=torch.bool), m_bool) + assert torch.equal( + _mask_for_xformers(m_float_add, to_dtype=torch.uint8), m_uint_flipped + ) + + assert torch.equal( + _mask_for_xformers(m_float16_add, to_dtype=torch.float16), m_float16_add + ) + assert torch.equal( + _mask_for_xformers(m_float16_add, to_dtype=torch.float), m_float_add + ) + assert torch.equal(_mask_for_xformers(m_float16_add, to_dtype=torch.bool), m_bool) + assert torch.equal( + _mask_for_xformers(m_float16_add, to_dtype=torch.uint8), m_uint_flipped + ) + + assert torch.equal( + _mask_for_xformers(m_bool, to_dtype=torch.float16), m_float16_add_flipped + ) + assert torch.equal( + _mask_for_xformers(m_bool, to_dtype=torch.float), m_float_add_flipped + ) + assert torch.equal(_mask_for_xformers(m_bool, to_dtype=torch.bool), ~m_bool) + assert torch.equal(_mask_for_xformers(m_bool, to_dtype=torch.uint8), m_uint) + + assert torch.equal( + _mask_for_xformers(m_uint, to_dtype=torch.float16), m_float16_add + ) + assert torch.equal(_mask_for_xformers(m_uint, to_dtype=torch.float), m_float_add) + assert torch.equal(_mask_for_xformers(m_uint, to_dtype=torch.bool), m_bool) + assert torch.equal(_mask_for_xformers(m_uint, to_dtype=torch.uint8), m_uint_flipped) + + +@pytest.mark.parametrize("device", ["cuda"]) +@pytest.mark.parametrize("attn_dtype", ATTN_MASK_DTYPE) +@pytest.mark.parametrize("key_padding_dtype", KEY_PADDING_MASK_DTYPE) +@pytest.mark.parametrize("add_zero_attn", [False]) +@pytest.mark.parametrize("batch_size", [20]) +@pytest.mark.parametrize("embedding", [64]) +@pytest.mark.parametrize("seq_len", [64]) +@pytest.mark.parametrize("num_heads", [4]) +def test_xformers_blocksparse_parity( + device, + attn_dtype, + key_padding_dtype, + add_zero_attn, + batch_size, + embedding, + seq_len, + num_heads, +): + + xformers_att_config = '{"name": "scaled_dot_product"}' + xformers_blocksparse_blocksize = 16 + xformers_blocksparse_layout = torch.ones( + seq_len // xformers_blocksparse_blocksize, + seq_len // xformers_blocksparse_blocksize, + ) + + attn_mask = ( + None + if attn_dtype is None + else _get_mask(to_dtype=attn_dtype, dim0=seq_len, dim1=seq_len).to(device) + ) + + key_padding_mask = ( + None + if key_padding_dtype is None + else _get_mask(to_dtype=key_padding_dtype, dim0=batch_size, dim1=seq_len).to( + device + ) + ) + + q = torch.rand(seq_len, batch_size, embedding).to(device).half() + q.requires_grad = True + k = torch.rand(seq_len, batch_size, embedding).to(device).half() + k.requires_grad = True + v = torch.rand(seq_len, batch_size, embedding).to(device).half() + v.requires_grad = True + + q_ = q.detach().clone().half() + q_.requires_grad = True + k_ = k.detach().clone().half() + k_.requires_grad = True + v_ = v.detach().clone().half() + v_.requires_grad = True + + _reset_seeds() + xf_blocksparse_mha = ( + MultiheadAttention( + embedding, + num_heads, + dropout=0.0, + add_zero_attn=add_zero_attn, + xformers_att_config=xformers_att_config, + xformers_blocksparse_layout=xformers_blocksparse_layout, + xformers_blocksparse_blocksize=xformers_blocksparse_blocksize, + ) + .to(device) + .half() + ) + + xf_blocksparse_output, _ = xf_blocksparse_mha( + q, + k, + v, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + ) + + _reset_seeds() + xformers_mha = ( + MultiheadAttention( + embedding, + num_heads, + dropout=0.0, + add_zero_attn=add_zero_attn, + xformers_att_config=xformers_att_config, + xformers_blocksparse_layout=None, + ) + .to(device) + .half() + ) + + xformers_output, _ = xformers_mha( + q_, + k_, + v_, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + ) + + # # account for when nan != nan + rand = random.uniform(0, 1) + xformers_output = xformers_output.masked_fill(xformers_output.isnan(), rand) + xf_blocksparse_output = xf_blocksparse_output.masked_fill( + xf_blocksparse_output.isnan(), rand + ) + + assert_almost_equal(xformers_output, xf_blocksparse_output) + + loss_blocksparse = torch.norm(xformers_output) + loss_original = torch.norm(xf_blocksparse_output) + loss_blocksparse.backward() + loss_original.backward() + + q.masked_fill(q.isnan(), rand) + q_.masked_fill(q_.isnan(), rand) + k.masked_fill(k.isnan(), rand) + k_.masked_fill(k_.isnan(), rand) + v.masked_fill(v.isnan(), rand) + v_.masked_fill(v_.isnan(), rand) + + assert_almost_equal(q.grad, q_.grad) + assert_almost_equal(k.grad, k_.grad) + assert_almost_equal(v.grad, v_.grad) + + +@pytest.mark.parametrize("device", DEVICE) +@pytest.mark.parametrize("attn_dtype", ATTN_MASK_DTYPE) +@pytest.mark.parametrize("key_padding_dtype", KEY_PADDING_MASK_DTYPE) +@pytest.mark.parametrize("add_bias_kv", [True, False]) +@pytest.mark.parametrize("add_zero_attn", [True, False]) +# TODO: test with static_kv True +@pytest.mark.parametrize("static_kv", [False]) +@pytest.mark.parametrize("batch_size", BATCH) +@pytest.mark.parametrize("embedding", EMB) +@pytest.mark.parametrize("seq_len", SEQ) +@pytest.mark.parametrize("num_heads", HEADS) +def test_xformers_single_forward_parity( + device, + attn_dtype, + key_padding_dtype, + add_bias_kv, + add_zero_attn, + static_kv, + batch_size, + embedding, + seq_len, + num_heads, +): + + xformers_att_config = '{"name": "scaled_dot_product"}' + + attn_mask = ( + None + if attn_dtype is None + else _get_mask(to_dtype=attn_dtype, dim0=seq_len, dim1=seq_len).to(device) + ) + key_padding_mask = ( + None + if key_padding_dtype is None + else _get_mask(to_dtype=key_padding_dtype, dim0=batch_size, dim1=seq_len).to( + device + ) + ) + + q = torch.rand(seq_len, batch_size, embedding).to(device) + q.requires_grad = True + k = torch.rand(seq_len, batch_size, embedding).to(device) + k.requires_grad = True + v = torch.rand(seq_len, batch_size, embedding).to(device) + v.requires_grad = True + + q_ = q.detach().clone() + q_.requires_grad = True + k_ = k.detach().clone() + k_.requires_grad = True + v_ = v.detach().clone() + v_.requires_grad = True + + # TODO: dropouts in the two implementations lead to different entries dropped. + _reset_seeds() + xformers_mha = MultiheadAttention( + embedding, + num_heads, + dropout=0.0, + xformers_att_config=xformers_att_config, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ).to(device) + xformers_output, _ = xformers_mha( + q, + k, + v, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + static_kv=static_kv, + ) + + _reset_seeds() + original_mha = MultiheadAttention( + embedding, + num_heads, + dropout=0.0, + xformers_att_config=None, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ).to(device) + original_output, _ = original_mha( + q_, + k_, + v_, + key_padding_mask=key_padding_mask, + attn_mask=attn_mask, + static_kv=static_kv, + ) + + # account for when nan != nan + if xformers_output.isnan().any() or original_output.isnan().any(): + rand = random.uniform(0, 1) + xformers_output = xformers_output.masked_fill(xformers_output.isnan(), rand) + original_output = original_output.masked_fill(original_output.isnan(), rand) + + # torch.equal works for cpu, on cuda allclose is needed. + assert torch.allclose( + xformers_output, original_output, atol=1e-06 + ), f"max diff is {torch.max(torch.abs(xformers_output - original_output))}" + + loss_xformers = torch.norm(xformers_output) + loss_original = torch.norm(original_output) + loss_xformers.backward() + loss_original.backward() + + # torch.equal works for cpu, on cuda allclose is needed. + assert torch.allclose( + q.grad, q_.grad + ), f"max diff is {torch.max(torch.abs(q.grad - q_.grad))}" + assert torch.allclose( + k.grad, k_.grad + ), f"max diff is {torch.max(torch.abs(k.grad - k_.grad))}" + assert torch.allclose( + v.grad, v_.grad + ), f"max diff is {torch.max(torch.abs(v.grad - v_.grad))}" def test_mask_padding_parity(): @@ -28,7 +360,7 @@ def old_padding_code(key_padding_mask, attn_mask): # values don't matter for this test. mha = MultiheadAttention( - embedding=8, + embed_dim=8, num_heads=2, dropout=0.0, add_bias_kv=True, @@ -50,7 +382,7 @@ def old_padding_code(key_padding_mask, attn_mask): def test_add_bias_parity(): # values don't matter for this test. mha = MultiheadAttention( - embedding=8, + embed_dim=8, num_heads=2, dropout=0.0, add_bias_kv=True, From e71c4d04d717f6588641cd34632b22def4477abf Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 5 May 2022 15:18:53 -0700 Subject: [PATCH 613/774] fix broken build and docs (#3362) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? - [x] formatting fix - [x] optional import of xFormers - [x] enabled doc building as part of CI - [x] remove mask arguments for attentions that do not support them - [x] remove masks for blocksparse tests, no longer supported - [ ] use pytest instead of deprecated `setup.py test` - [ ] CircleCI xFormers tests Will submit without the last two done to unblock people using the repo ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � X-link: https://github.com/fairinternal/fairseq-py/pull/3362 Reviewed By: blefaudeux Differential Revision: D36169572 Pulled By: dianaml0 fbshipit-source-id: 3b20ae5f377144a0854e016771af703f0d0d694b --- .circleci/config.yml | 4 +--- .github/workflows/build.yml | 2 +- fairseq/modules/multihead_attention.py | 25 +++++++++++++++++++------ tests/test_multihead_attention.py | 25 +++---------------------- 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c29b534ff9..ff7237c441 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -56,7 +56,6 @@ install_dep_xformers: &install_dep_xformers pip install -r requirements.txt pip install -e . - install_dep_pt19: &install_dep_pt19 - run: name: Install Pytorch Dependencies @@ -120,6 +119,7 @@ create_conda_env: &create_conda_env # ------------------------------------------------------------------------------------- jobs: + gpu_tests_pt19: <<: *gpu @@ -134,7 +134,6 @@ jobs: - <<: *install_dep_pt19 - <<: *install_dep_common - <<: *install_dep_fused_ops - - <<: *install_dep_xformers - save_cache: paths: - ~/miniconda/ @@ -156,7 +155,6 @@ jobs: - <<: *install_dep_pt18 - <<: *install_dep_common - <<: *install_dep_fused_ops - - <<: *install_dep_xformers - save_cache: paths: - ~/miniconda/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 16b42974b0..a14365cd23 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,7 +54,7 @@ jobs: - name: Run tests run: | - python setup.py test + python setup.py test - name: Lint with black run: | diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 8d08331e42..6431b03344 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -10,8 +10,14 @@ import torch.nn.functional as F from torch import Tensor, nn from torch.nn import Parameter -from xformers.components.attention import build_attention -from xformers.components.attention.utils import maybe_merge_masks + +try: + from xformers.components.attention import build_attention + from xformers.components.attention.utils import maybe_merge_masks + + _xformers_available = True +except ImportError: + _xformers_available = False from fairseq import utils from fairseq.incremental_decoding_utils import with_incremental_state @@ -53,6 +59,7 @@ def _mask_for_xformers(mask: Tensor, to_dtype: Optional[torch.dtype] = None): mask = mask.to(to_dtype) return mask + @with_incremental_state class MultiheadAttention(nn.Module): """Multi-headed attention. @@ -88,6 +95,8 @@ def __init__( xformers_att_config = utils.eval_str_dict(xformers_att_config) self.use_xformers = xformers_att_config is not None + if self.use_xformers and not _xformers_available: + raise ImportError("\n\n Please install xFormers.") self.embed_dim = embed_dim self.kdim = kdim if kdim is not None else embed_dim self.vdim = vdim if vdim is not None else embed_dim @@ -420,9 +429,12 @@ def split_heads(x): k=k, v=v, key_padding_mask=key_padding_mask, attn_mask=attn_mask ) - if attn_mask is not None: + kwargs = {} + + if attn_mask is not None and self.attention.supports_attention_mask: to_dtype = torch.float16 if self.fp16_mask else q.dtype attn_mask = _mask_for_xformers(attn_mask, to_dtype=to_dtype) + kwargs["att_mask"] = attn_mask if key_padding_mask is not None: to_dtype = torch.float16 if self.fp16_mask else torch.bool @@ -437,10 +449,11 @@ def split_heads(x): num_heads=self.num_heads, ) key_padding_mask = None + kwargs["att_mask"] = attn_mask + if self.attention.supports_key_padding_mask: + kwargs["key_padding_mask"] = key_padding_mask - y = self.attention( - q, k, v, att_mask=attn_mask, key_padding_mask=key_padding_mask - ) + y = self.attention(q, k, v, **kwargs) y = ( y.view(bsz, self.num_heads, tgt_len, self.head_dim) diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index dd075ea88c..5301318c2c 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -8,6 +8,7 @@ import pytest import torch + from fairseq.modules.multihead_attention import MultiheadAttention, _mask_for_xformers BATCH = [20, 41, 97] @@ -99,9 +100,8 @@ def test_mask_for_xformers(): assert torch.equal(_mask_for_xformers(m_uint, to_dtype=torch.uint8), m_uint_flipped) +@pytest.mark.skipif(not torch.cuda.is_available(), reason="blocksparse requires gpu") @pytest.mark.parametrize("device", ["cuda"]) -@pytest.mark.parametrize("attn_dtype", ATTN_MASK_DTYPE) -@pytest.mark.parametrize("key_padding_dtype", KEY_PADDING_MASK_DTYPE) @pytest.mark.parametrize("add_zero_attn", [False]) @pytest.mark.parametrize("batch_size", [20]) @pytest.mark.parametrize("embedding", [64]) @@ -109,8 +109,6 @@ def test_mask_for_xformers(): @pytest.mark.parametrize("num_heads", [4]) def test_xformers_blocksparse_parity( device, - attn_dtype, - key_padding_dtype, add_zero_attn, batch_size, embedding, @@ -123,20 +121,7 @@ def test_xformers_blocksparse_parity( xformers_blocksparse_layout = torch.ones( seq_len // xformers_blocksparse_blocksize, seq_len // xformers_blocksparse_blocksize, - ) - - attn_mask = ( - None - if attn_dtype is None - else _get_mask(to_dtype=attn_dtype, dim0=seq_len, dim1=seq_len).to(device) - ) - - key_padding_mask = ( - None - if key_padding_dtype is None - else _get_mask(to_dtype=key_padding_dtype, dim0=batch_size, dim1=seq_len).to( - device - ) + dtype=torch.int32, ) q = torch.rand(seq_len, batch_size, embedding).to(device).half() @@ -172,8 +157,6 @@ def test_xformers_blocksparse_parity( q, k, v, - key_padding_mask=key_padding_mask, - attn_mask=attn_mask, ) _reset_seeds() @@ -194,8 +177,6 @@ def test_xformers_blocksparse_parity( q_, k_, v_, - key_padding_mask=key_padding_mask, - attn_mask=attn_mask, ) # # account for when nan != nan From c8d6fb198cd58d433cadf178b22afdba40401f13 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 6 May 2022 15:03:03 -0700 Subject: [PATCH 614/774] README for using xFormers in FairSeq (#4402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4402 Reviewed By: xwhan Differential Revision: D36208103 Pulled By: dianaml0 fbshipit-source-id: 1600356d20dc32340935c0c88c1f700a1cdefa14 --- examples/xformers/README.md | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 examples/xformers/README.md diff --git a/examples/xformers/README.md b/examples/xformers/README.md new file mode 100644 index 0000000000..400a74d536 --- /dev/null +++ b/examples/xformers/README.md @@ -0,0 +1,43 @@ +# Using xFormers with FairSeq + +[xFormers](https://github.com/facebookresearch/xformers) is a xFormers is a modular library for flexibly generating transformer architectures with interoperable and optimized building blocks. +The current integration allows for FairSeq users to use an attention variant available in the xFormers repository. + +In order to enable xFormers, all that needs to be passed in is a string representing an [xFormers attention config](https://github.com/facebookresearch/xformers/blob/5f754129bfb1ea53747b1ab2077261ea762faa47/xformers/components/attention/base.py#L18). + +The various attention variants can be found [here](https://github.com/facebookresearch/xformers/tree/main/xformers/components/attention). +These include sparse attention and blocksparse attention. + +For example, you could pass in the following args: + ```python +decoder_xformers_att_config = '{"name": "scaled_dot_product"}' + +encoder_xformers_att_config = '{"name": "linformer", "seq_len": "256"}' + ``` + +In order to use blocksparse attention you would have to additionally pass in a blocksparse layout and blocksize. For example: + + ```python + + xformers_att_config = '{"name": "scaled_dot_product"}' + xformers_blocksparse_blocksize = 16 + xformers_blocksparse_layout = torch.ones( + seq_len // xformers_blocksparse_blocksize, + seq_len // xformers_blocksparse_blocksize, + ) + + xf_blocksparse_mha = ( + MultiheadAttention( + embedding, + num_heads, + dropout=0.0, + add_zero_attn=add_zero_attn, + xformers_att_config=xformers_att_config, + xformers_blocksparse_layout=xformers_blocksparse_layout, + xformers_blocksparse_blocksize=xformers_blocksparse_blocksize, + ) + + ``` + +The xFormers repository currenlty has benchmarks on the [runtime](https://github.com/facebookresearch/xformers/blob/main/docs/plots/runtime_vs_attention.png) +and [memory usage](https://github.com/facebookresearch/xformers/blob/main/docs/plots/memory_vs_attention.png) of the various attentions. From 4368ede817856da288d2044bf8fc2bab4353919c Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Tue, 10 May 2022 12:58:44 -0700 Subject: [PATCH 615/774] Remove code used for blocksparse masking (#4401) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Blocksparse attention no longer accepts masks. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4401 Reviewed By: blefaudeux Differential Revision: D36208195 Pulled By: dianaml0 fbshipit-source-id: 0d0c57533cb9346724e8e8b0b9c28a2e57759135 --- fairseq/modules/multihead_attention.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 6431b03344..4314806010 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -144,7 +144,6 @@ def __init__( self.beam_size = 1 self.reset_parameters() - self.fp16_mask = False if self.use_xformers: xformers_att_config["dropout"] = xformers_att_config.get("dropout", dropout) xformers_att_config["num_heads"] = xformers_att_config.get( @@ -156,8 +155,6 @@ def __init__( xformers_att_config["block_size"] = xformers_blocksparse_blocksize xformers_att_config["layout"] = xformers_blocksparse_layout xformers_att_config["name"] = "blocksparse" - # Mask required to be float16 - self.fp16_mask = True self.attention = build_attention(xformers_att_config) @@ -432,13 +429,11 @@ def split_heads(x): kwargs = {} if attn_mask is not None and self.attention.supports_attention_mask: - to_dtype = torch.float16 if self.fp16_mask else q.dtype - attn_mask = _mask_for_xformers(attn_mask, to_dtype=to_dtype) + attn_mask = _mask_for_xformers(attn_mask, to_dtype=q.dtype) kwargs["att_mask"] = attn_mask if key_padding_mask is not None: - to_dtype = torch.float16 if self.fp16_mask else torch.bool - key_padding_mask = _mask_for_xformers(key_padding_mask, to_dtype=to_dtype) + key_padding_mask = _mask_for_xformers(key_padding_mask, to_dtype=torch.bool) if not self.attention.requires_separate_masks: attn_mask = maybe_merge_masks( attn_mask, From 993129dae4fab651524a8976db9486448e752d21 Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Tue, 10 May 2022 19:44:00 -0700 Subject: [PATCH 616/774] Merge STPT: Step 3 Summary: 1. Add joint pre-training scripts 2. Replace prepend_tgt_lang_tag_no_change with prepend_tgt_lang_tag_as_bos 3. Add readme for the joint pre-training 4. Add test case for the Librispeech model Reviewed By: hygong-fb Differential Revision: D36300953 fbshipit-source-id: cb749689787ed97c1250d122bdefb7f7a2252292 --- examples/speech_text_joint_to_text/README.md | 19 +- .../criterions/multi_modality_compound.py | 180 +++++ .../multi_modality_cross_entropy.py | 101 +++ .../data/pair_denoising_dataset.py | 318 ++++++++ .../docs/ende-mustc.md | 8 +- .../docs/pre-training.md | 188 +++++ .../joint_speech_text_pretrain_transformer.py | 698 ++++++++++++++++++ .../models/s2t_dualinputwavtransformer.py | 526 +++++++++++++ .../scripts/convert_model.py | 71 ++ .../tasks/pair_denoising.py | 447 +++++++++++ .../tasks/speech_text_denoise_pretrain.py | 654 ++++++++++++++++ fairseq/data/audio/multi_modality_dataset.py | 2 + .../audio/speech_to_text_joint_dataset.py | 20 +- fairseq/models/speech_to_text/__init__.py | 2 + .../speech_to_text/multi_modality_model.py | 49 ++ .../models/speech_to_text/s2t_transformer.py | 10 +- .../speech_to_text/s2t_wav_transformer.py | 485 ++++++++++++ .../speech/test_dual_input_wav_transformer.py | 76 ++ 18 files changed, 3831 insertions(+), 23 deletions(-) create mode 100644 examples/speech_text_joint_to_text/criterions/multi_modality_compound.py create mode 100644 examples/speech_text_joint_to_text/criterions/multi_modality_cross_entropy.py create mode 100644 examples/speech_text_joint_to_text/data/pair_denoising_dataset.py create mode 100644 examples/speech_text_joint_to_text/docs/pre-training.md create mode 100644 examples/speech_text_joint_to_text/models/joint_speech_text_pretrain_transformer.py create mode 100644 examples/speech_text_joint_to_text/models/s2t_dualinputwavtransformer.py create mode 100644 examples/speech_text_joint_to_text/scripts/convert_model.py create mode 100644 examples/speech_text_joint_to_text/tasks/pair_denoising.py create mode 100644 examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py create mode 100644 fairseq/models/speech_to_text/multi_modality_model.py create mode 100644 fairseq/models/speech_to_text/s2t_wav_transformer.py create mode 100644 tests/speech/test_dual_input_wav_transformer.py diff --git a/examples/speech_text_joint_to_text/README.md b/examples/speech_text_joint_to_text/README.md index e071d241e0..c1aa11929a 100644 --- a/examples/speech_text_joint_to_text/README.md +++ b/examples/speech_text_joint_to_text/README.md @@ -5,17 +5,16 @@ An extension of Fairseq s2t project with the speech to text task enhanced by the Examples of speech text joint training in fairseq - [English-to-German MuST-C model](docs/ende-mustc.md) - [IWSLT 2021 Multilingual Speech Translation](docs/iwslt2021.md) - +- [Speech Text Joint Pre-training ](docs/pre-training.md) ## Citation Please cite as: ``` -@inproceedings{Tang2021AGM, - title={A General Multi-Task Learning Framework to Leverage Text Data for Speech to Text Tasks}, - author={Yun Tang and J. Pino and Changhan Wang and Xutai Ma and Dmitriy Genzel}, - booktitle={ICASSP}, - year={2021} +@inproceedings{Tang2022UnifiedSP, + title={Unified Speech-Text Pre-training for Speech Translation and Recognition}, + author={Yun Tang and Hongyu Gong and Ning Dong and Changhan Wang and Wei-Ning Hsu and Jiatao Gu and Alexei Baevski and Xian Li and Abdelrahman Mohamed and Michael Auli and Juan Miguel Pino}, + booktitle={ACL}, + year={2022} } - @inproceedings{Tang2021IST, title = {Improving Speech Translation by Understanding and Learning from the Auxiliary Text Translation Task}, author = {Yun Tang and Juan Pino and Xian Li and Changhan Wang and Dmitriy Genzel}, @@ -29,6 +28,12 @@ Please cite as: booktitle = {IWSLT}, year = {2021}, } +@inproceedings{Tang2021AGM, + title={A General Multi-Task Learning Framework to Leverage Text Data for Speech to Text Tasks}, + author={Yun Tang and J. Pino and Changhan Wang and Xutai Ma and Dmitriy Genzel}, + booktitle={ICASSP}, + year={2021} +} @inproceedings{wang2020fairseqs2t, title = {fairseq S2T: Fast Speech-to-Text Modeling with fairseq}, diff --git a/examples/speech_text_joint_to_text/criterions/multi_modality_compound.py b/examples/speech_text_joint_to_text/criterions/multi_modality_compound.py new file mode 100644 index 0000000000..292f6fdf48 --- /dev/null +++ b/examples/speech_text_joint_to_text/criterions/multi_modality_compound.py @@ -0,0 +1,180 @@ +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import logging +import math +from dataclasses import dataclass, field + +from fairseq import metrics, utils +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.criterions.ctc import CtcCriterion, CtcCriterionConfig +from fairseq.criterions.label_smoothed_cross_entropy import ( + LabelSmoothedCrossEntropyCriterionConfig, +) +from fairseq.logging.meters import safe_round + +from .multi_modality_cross_entropy import SpeechTextPreTrainCrossEntCriterion + +logger = logging.getLogger(__name__) + + +@dataclass +class SpeechTextPreTrainCompoundCriterionConfig( + LabelSmoothedCrossEntropyCriterionConfig +): + zero_infinity: bool = field( + default=False, + metadata={"help": "zero inf loss when source length <= target length"}, + ) + post_process: str = field( + default="none", + metadata={ + "help": "how to post process predictions into words. can be letter, " + "wordpiece, BPE symbols, etc. " + "See fairseq.data.data_utils.post_process() for full list of options" + }, + ) + + +@register_criterion( + "speech_text_pretrain_compound", dataclass=SpeechTextPreTrainCompoundCriterionConfig +) +class SpeechTextPreTrainCompoundCriterion(FairseqCriterion): + def __init__( + self, + task, + sentence_avg, + label_smoothing, + report_accuracy=False, + zero_infinity=False, + post_process=None, + ): + super().__init__(task) + self.xent = SpeechTextPreTrainCrossEntCriterion( + task, sentence_avg, label_smoothing, report_accuracy + ) + cfg_dict = { + "zero_infinity": zero_infinity, + "sentence_avg": sentence_avg, + "post_process": post_process, + } + cfg_ctc = CtcCriterionConfig(**cfg_dict) + self.ctc = CtcCriterion(cfg_ctc, task) + + def forward(self, model, sample, reduce=True): + mode = sample["net_input"]["mode"] + if mode == "sup_speech_ctc": # CTC + sample["net_input"][ + "src_lengths" + ] = None # get downsampled src_lengths from padding_mask + loss, sample_size, logging_output = self.ctc(model, sample, reduce) + logging_output["mode"] = SpeechTextPreTrainCompoundCriterion.mode2value( + "CTC" + ) + else: + loss, sample_size, logging_output = self.xent(model, sample, reduce) + logging_output["mode"] = SpeechTextPreTrainCompoundCriterion.mode2value( + "xent" + ) + + return loss, sample_size, logging_output + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return True + + @staticmethod + def mode2value(mode): # make the logging_outputs_can_be_summed = True + if mode == "CTC": + return 907 # prime number + if mode == "xent": + return 887 # prime number + return 0 + + @staticmethod + def value2mode(value): + if value % 907 == 0: + return "CTC" + if value % 887 == 0: + return "xent" + raise ValueError("Unknow mode") + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + + def _get_mode(logging_outputs): + mds = [ + SpeechTextPreTrainCompoundCriterion.value2mode(log["mode"]) + for log in logging_outputs + ] + if sum([1 if l != mds[0] else 0 for l in mds]) > 0: + raise ValueError("mode in one mini-batch is expected to be the same!") + return mds[0] + + log_mode = _get_mode(logging_outputs) + if log_mode == "xent": + return SpeechTextPreTrainCrossEntCriterion.reduce_metrics(logging_outputs) + + # ctc loss + loss_sum = utils.item(sum(log.get("loss", 0) for log in logging_outputs)) + ntokens = utils.item(sum(log.get("ntokens", 0) for log in logging_outputs)) + nsentences = utils.item( + sum(log.get("nsentences", 0) for log in logging_outputs) + ) + sample_size = utils.item( + sum(log.get("sample_size", 0) for log in logging_outputs) + ) + + metrics.log_scalar( + "ctc_loss", loss_sum / sample_size / math.log(2), sample_size, round=3 + ) + metrics.log_scalar("ctc_ntokens", ntokens) + metrics.log_scalar("ctc_nsentences", nsentences) + if sample_size != ntokens: + metrics.log_scalar( + "ctc_nll_loss", loss_sum / ntokens / math.log(2), ntokens, round=3 + ) + + c_errors = sum(log.get("c_errors", 0) for log in logging_outputs) + metrics.log_scalar("_c_errors", c_errors) + c_total = sum(log.get("c_total", 0) for log in logging_outputs) + metrics.log_scalar("_c_total", c_total) + w_errors = sum(log.get("w_errors", 0) for log in logging_outputs) + metrics.log_scalar("_w_errors", w_errors) + wv_errors = sum(log.get("wv_errors", 0) for log in logging_outputs) + metrics.log_scalar("_wv_errors", wv_errors) + w_total = sum(log.get("w_total", 0) for log in logging_outputs) + metrics.log_scalar("_w_total", w_total) + + if c_total > 0: + metrics.log_derived( + "uer", + lambda meters: safe_round( + meters["_c_errors"].sum * 100.0 / meters["_c_total"].sum, 3 + ) + if meters["_c_total"].sum > 0 + else float("nan"), + ) + if w_total > 0: + metrics.log_derived( + "wer", + lambda meters: safe_round( + meters["_w_errors"].sum * 100.0 / meters["_w_total"].sum, 3 + ) + if meters["_w_total"].sum > 0 + else float("nan"), + ) + metrics.log_derived( + "raw_wer", + lambda meters: safe_round( + meters["_wv_errors"].sum * 100.0 / meters["_w_total"].sum, 3 + ) + if meters["_w_total"].sum > 0 + else float("nan"), + ) diff --git a/examples/speech_text_joint_to_text/criterions/multi_modality_cross_entropy.py b/examples/speech_text_joint_to_text/criterions/multi_modality_cross_entropy.py new file mode 100644 index 0000000000..6c9cb0f20d --- /dev/null +++ b/examples/speech_text_joint_to_text/criterions/multi_modality_cross_entropy.py @@ -0,0 +1,101 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import torch + +from fairseq import utils +from fairseq.criterions import register_criterion +from fairseq.criterions.label_smoothed_cross_entropy import ( + LabelSmoothedCrossEntropyCriterion, + LabelSmoothedCrossEntropyCriterionConfig, + label_smoothed_nll_loss, +) + + +@register_criterion( + "speech_text_pretrain_cross_entropy", + dataclass=LabelSmoothedCrossEntropyCriterionConfig, +) +class SpeechTextPreTrainCrossEntCriterion(LabelSmoothedCrossEntropyCriterion): + def __init__(self, task, sentence_avg, label_smoothing, report_accuracy=False): + super().__init__( + task, sentence_avg, label_smoothing, report_accuracy=report_accuracy + ) + + def forward(self, model, sample, reduce=True): + net_output = model(**sample["net_input"]) + loss, nll_loss, nsentences, ntokens, n_correct = self.compute_loss( + model, net_output, sample, reduce=reduce + ) + sample_size = nsentences if self.sentence_avg else ntokens + logging_output = { + "loss": loss.data, + "nll_loss": nll_loss.data, + "ntokens": ntokens, + "nsentences": nsentences, + "sample_size": sample_size, + } + if self.report_accuracy: + logging_output["n_correct"] = utils.item(n_correct) + logging_output["total"] = utils.item(ntokens) + return loss, sample_size, logging_output + + def get_lprobs_and_target(self, model, net_output, sample): + lprobs = model.get_normalized_probs(net_output, log_probs=True) + target = model.get_targets(sample, net_output) + assert self.ignore_prefix_size == 0 + if self.ignore_prefix_size > 0: + if getattr(lprobs, "batch_first", False): + lprobs = lprobs[:, self.ignore_prefix_size :, :].contiguous() + target = target[:, self.ignore_prefix_size :].contiguous() + else: + lprobs = lprobs[self.ignore_prefix_size :, :, :].contiguous() + target = target[self.ignore_prefix_size :, :].contiguous() + return lprobs, target + + def compute_loss(self, model, net_output, sample, reduce=True): + lprobs, target = self.get_lprobs_and_target(model, net_output, sample) + n_correct = 0 + if isinstance(target, dict): + t_lprobs = target["target_logprobs"] + + if not lprobs.batch_first: + lprobs = lprobs.transpose(0, 1) + t_lprobs = t_lprobs.transpose(0, 1) + nsentences, seq_len = lprobs.size()[:2] + ntokens = nsentences * seq_len + t_probs = t_lprobs.exp() + mask_indices = ( + net_output[1]["mask_indices"][0] + if len(net_output[1]["mask_indices"]) > 0 + else None + ) + + # mask_indices is True for those masking frames + if mask_indices is not None: # B X T + t_probs = t_probs.masked_fill(mask_indices.eq(False).unsqueeze(-1), 0) + ntokens = mask_indices.int().sum() + t_probs = t_probs.detach() + t_lprobs = t_lprobs.detach() + loss = ( + -(t_probs * (lprobs - t_lprobs)).sum() + if reduce + else -(t_probs * (lprobs - t_lprobs)).sum(-1, keepdim=True) + ) + nll_loss = loss + else: + nsentences = target.size(0) + mask = target.ne(self.padding_idx) + loss, nll_loss = label_smoothed_nll_loss( + lprobs.view(-1, lprobs.size(-1)), + target.view(-1), + self.eps, + ignore_index=self.padding_idx, + reduce=reduce, + ) + n_correct = torch.sum( + lprobs.argmax(-1).masked_select(mask).eq(target.masked_select(mask)) + ) + ntokens = torch.sum(mask) + return loss, nll_loss, nsentences, ntokens, n_correct diff --git a/examples/speech_text_joint_to_text/data/pair_denoising_dataset.py b/examples/speech_text_joint_to_text/data/pair_denoising_dataset.py new file mode 100644 index 0000000000..fc94fbaf11 --- /dev/null +++ b/examples/speech_text_joint_to_text/data/pair_denoising_dataset.py @@ -0,0 +1,318 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import copy +import math +import re + +import torch + +from fairseq.data import data_utils +from fairseq.data.language_pair_dataset import LanguagePairDataset + + +# Part of the code is modified from DenoisingDataset +# compared with DenoisingDataset, no permute_sentences or documents (rotate_ratio, permute_sentence_ratio) +class LanguagePairDenoisingDataset(LanguagePairDataset): + def __init__( + self, + src, + src_sizes, + src_dict, + tgt, + tgt_sizes, + tgt_dict, + mask_idx, + mask_whole_words, + seed, + args, + left_pad_source=True, + left_pad_target=False, + shuffle=True, + input_feeding=True, + remove_eos_from_source=False, + append_eos_to_target=False, + align_dataset=None, + constraints=None, + append_bos=False, + eos=None, + num_buckets=0, + src_lang_id=None, + tgt_lang_id=None, + pad_to_multiple=1, + ): + super().__init__( + src, + src_sizes, + src_dict, + tgt, + tgt_sizes, + tgt_dict, + left_pad_source, + left_pad_target, + shuffle, + input_feeding, + remove_eos_from_source, + append_eos_to_target, + align_dataset, + constraints, + append_bos, + eos, + num_buckets, + src_lang_id, + tgt_lang_id, + pad_to_multiple, + ) + + self.mask_idx = mask_idx + self.mask_whole_word = mask_whole_words + self.mask_ratio = args.mask + self.random_ratio = args.mask_random + self.insert_ratio = args.insert + + self.replace_length = args.replace_length + + if self.replace_length not in [-1, 0, 1]: + raise ValueError(f"invalid arg: replace_length={self.replace_length}") + if args.mask_length not in ["subword", "word", "span-poisson"]: + raise ValueError(f"invalid arg: mask-length={args.mask_length}") + if args.mask_length == "subword" and args.replace_length not in [0, 1]: + raise ValueError("if using subwords, use replace-length=1 or 0") + + self.mask_span_distribution = None + if args.mask_length == "span-poisson": + # Text infilling: "A number of text spans are sampled, with span lengths drawn from a Poisson distribution (λ = 3). Each span is replaced with a single [MASK] token. 0-length spans correspond to the insertion of [MASK] tokens." + _lambda = args.poisson_lambda + + lambda_to_the_k = 1 + e_to_the_minus_lambda = math.exp(-_lambda) + k_factorial = 1 + ps = [] + for k in range(0, 128): + ps.append(e_to_the_minus_lambda * lambda_to_the_k / k_factorial) + lambda_to_the_k *= _lambda + k_factorial *= k + 1 + if ps[-1] < 0.0000001: + break + ps = torch.FloatTensor(ps) + self.mask_span_distribution = torch.distributions.Categorical(ps) + + self.epoch = 0 + self.seed = seed + + def _is_phoneme(x): + if re.search("<lang:", x) or x in ( + "<mask>", + "<sil>", + "<pad>", + "<s>", + "</s>", + "<unk>", + ): + return False + return True + + self.voc_valid_ids = torch.LongTensor( + [i for i, x in enumerate(self.src_dict.symbols) if _is_phoneme(x)] + ) + self.voc_valid_size = self.voc_valid_ids.size(0) + + @property + def can_reuse_epoch_itr_across_epochs(self): + return False + + def set_epoch(self, epoch, **unused): + self.epoch = epoch + + def __getitem__(self, index): + tgt_item = self.tgt[index] if self.tgt is not None else None + src_item = copy.deepcopy(self.src[index]) + with data_utils.numpy_seed(self.seed, self.epoch, index): + source = src_item + assert source[-1] == self.eos + if self.mask_ratio > 0: + source = self.add_whole_word_mask(source, self.mask_ratio) + + if self.insert_ratio > 0: + source = self.add_insertion_noise(source, self.insert_ratio) + src_item = source + + if self.append_eos_to_target: + eos = self.tgt_dict.eos() if self.tgt_dict else self.src_dict.eos() + if self.tgt and self.tgt[index][-1] != eos: + tgt_item = torch.cat([self.tgt[index], torch.LongTensor([eos])]) + + if self.append_bos: + bos = self.tgt_dict.bos() if self.tgt_dict else self.src_dict.bos() + if self.tgt and self.tgt[index][0] != bos: + tgt_item = torch.cat([torch.LongTensor([bos]), self.tgt[index]]) + + bos = self.src_dict.bos() + if src_item[0] != bos: + src_item = torch.cat([torch.LongTensor([bos]), src_item]) + + if self.remove_eos_from_source: + eos = self.src_dict.eos() + if src_item[-1] == eos: + src_item = src_item[:-1] + + example = { + "id": index, + "source": src_item, + "target": tgt_item, + } + if self.align_dataset is not None: + example["alignment"] = self.align_dataset[index] + if self.constraints is not None: + example["constraints"] = self.constraints[index] + if self.src_lang_id is not None: + example["src_lang_id"] = self.src_lang_id + if self.tgt_lang_id is not None: + example["tgt_lang_id"] = self.tgt_lang_id + return example + + # following functions are borrowed from denoising_dataset + def word_starts(self, source): + if self.mask_whole_word is not None: + is_word_start = self.mask_whole_word.gather(0, source) + else: + is_word_start = torch.ones(source.size()) + is_word_start[0] = 0 + is_word_start[-1] = 0 + return is_word_start + + def add_whole_word_mask(self, source, p): + is_word_start = self.word_starts(source) + num_to_mask = int(math.ceil(is_word_start.float().sum() * p)) + num_inserts = 0 + if num_to_mask == 0: + return source + + if self.mask_span_distribution is not None: + lengths = self.mask_span_distribution.sample(sample_shape=(num_to_mask,)) + + # Make sure we have enough to mask + cum_length = torch.cumsum(lengths, 0) + while cum_length[-1] < num_to_mask: + lengths = torch.cat( + [ + lengths, + self.mask_span_distribution.sample(sample_shape=(num_to_mask,)), + ], + dim=0, + ) + cum_length = torch.cumsum(lengths, 0) + + # Trim to masking budget + i = 0 + while cum_length[i] < num_to_mask: + i += 1 + lengths[i] = num_to_mask - (0 if i == 0 else cum_length[i - 1]) + num_to_mask = i + 1 + lengths = lengths[:num_to_mask] + + # Handle 0-length mask (inserts) separately + lengths = lengths[lengths > 0] + num_inserts = num_to_mask - lengths.size(0) + num_to_mask -= num_inserts + if num_to_mask == 0: + return self.add_insertion_noise(source, num_inserts / source.size(0)) + + assert (lengths > 0).all() + else: + lengths = torch.ones((num_to_mask,)).long() + assert is_word_start[-1] == 0 + word_starts = is_word_start.nonzero(as_tuple=False) + indices = word_starts[ + torch.randperm(word_starts.size(0))[:num_to_mask] + ].squeeze(1) + mask_random = torch.FloatTensor(num_to_mask).uniform_() < self.random_ratio + + source_length = source.size(0) + assert source_length - 1 not in indices + to_keep = torch.ones(source_length, dtype=torch.bool) + is_word_start[ + -1 + ] = 255 # acts as a long length, so spans don't go over the end of doc + if self.replace_length == 0: + to_keep[indices] = 0 + else: + # keep index, but replace it with [MASK] + source[indices] = self.mask_idx + source[indices[mask_random]] = self.voc_valid_ids[ + torch.randint(0, self.voc_valid_size - 1, size=(mask_random.sum(),)) + ] + + if self.mask_span_distribution is not None: + assert len(lengths.size()) == 1 + assert lengths.size() == indices.size() + lengths -= 1 + while indices.size(0) > 0: + assert lengths.size() == indices.size() + lengths -= is_word_start[indices + 1].long() + uncompleted = lengths >= 0 + indices = indices[uncompleted] + 1 + mask_random = mask_random[uncompleted] + lengths = lengths[uncompleted] + if self.replace_length != -1: + # delete token + to_keep[indices] = 0 + else: + # keep index, but replace it with [MASK] + source[indices] = self.mask_idx + source[indices[mask_random]] = self.voc_valid_ids[ + torch.randint( + 0, self.voc_valid_size - 1, size=(mask_random.sum(),) + ) + ] + else: + # A bit faster when all lengths are 1 + while indices.size(0) > 0: + uncompleted = is_word_start[indices + 1] == 0 + indices = indices[uncompleted] + 1 + mask_random = mask_random[uncompleted] + if self.replace_length != -1: + # delete token + to_keep[indices] = 0 + else: + # keep index, but replace it with [MASK] + source[indices] = self.mask_idx + source[indices[mask_random]] = self.voc_valid_ids[ + torch.randint( + 0, self.voc_valid_size - 1, size=(mask_random.sum(),) + ) + ] + + assert source_length - 1 not in indices + + source = source[to_keep] + + if num_inserts > 0: + source = self.add_insertion_noise(source, num_inserts / source.size(0)) + + return source + + def add_insertion_noise(self, tokens, p): + if p == 0.0: + return tokens + + num_tokens = len(tokens) + n = int(math.ceil(num_tokens * p)) + + noise_indices = torch.randperm(num_tokens + n - 2)[:n] + 1 + noise_mask = torch.zeros(size=(num_tokens + n,), dtype=torch.bool) + noise_mask[noise_indices] = 1 + result = torch.LongTensor(n + len(tokens)).fill_(-1) + + num_random = int(math.ceil(n * self.random_ratio)) + result[noise_indices[num_random:]] = self.mask_idx + result[noise_indices[:num_random]] = self.voc_valid_ids[ + torch.randint(0, self.voc_valid_size - 1, size=(num_random,)) + ] + + result[~noise_mask] = tokens + + assert (result >= 0).all() + return result diff --git a/examples/speech_text_joint_to_text/docs/ende-mustc.md b/examples/speech_text_joint_to_text/docs/ende-mustc.md index ad9e222cef..1acf6e001b 100644 --- a/examples/speech_text_joint_to_text/docs/ende-mustc.md +++ b/examples/speech_text_joint_to_text/docs/ende-mustc.md @@ -22,11 +22,17 @@ Enhanced Joint Training: the joint training is enhanced with pre-trained models, --out-path ${must_c_en_de_src_text_pho} ``` - Replace the source text under the "src_text" column in the tsv file with the corresponding phoneme reprentation generated in the step above. +Below is the snapshot for the MuST-C en-de dev tsv +``` +id audio n_frames tgt_text src_text speaker +ted_767_0 en-de/flac.zip:10071514743:48445 56160 Heute spreche ich zu Ihnen über Energie und Klima. ▁AY1 M ▁G OW1 IH0 NG ▁T UW1 ▁T AO1 K ▁T AH0 D EY1 ▁AH0 B AW1 T ▁EH1 N ER0 JH IY0 ▁AH0 N D ▁K L AY1 M AH0 T spk.767_ +ted_767_1 en-de/flac.zip:1214217978:205678 226080 Und das überrascht vielleicht etwas, weil sich meine Vollzeitbeschäftigung bei der Stiftung hauptsächlich um Impfstoffe und Saatgut dreht, um die Dinge, die wir erfinden und liefern müssen um den ärmsten 2 Milliarden ein besseres Leben zu ermöglichen. ▁AH0 N D ▁DH AE1 T ▁M AY1 T ▁S IY1 M ▁AH0 ▁B IH1 T ▁S ER0 P R AY1 Z IH0 NG ▁B IH0 K AO1 Z ▁M AY1 ▁F UH1 L ▁T AY1 M ▁W ER1 K ▁AE1 T ▁DH AH0 ▁F AW0 N D EY1 SH AH0 N ▁IH1 Z ▁M OW1 S T L IY0 ▁AH0 B AW1 T ▁V AE2 K S IY1 N Z ▁AH0 N D ▁S IY1 D Z ▁AH0 B AW1 T ▁DH AH0 ▁TH IH1 NG Z ▁DH AE1 T ▁W IY1 ▁N IY1 D ▁T UW1 ▁IH0 N V EH1 N T ▁AH0 N D ▁D IH0 L IH1 V ER0 ▁T UW1 ▁HH EH1 L P ▁DH AH0 ▁P UH1 R IH0 S T ▁T UW1 ▁B IH1 L Y AH0 N ▁L AY1 V ▁B EH1 T ER0 ▁L IH1 V Z spk.767_ +``` - Prepare phoneme dictionary and save to $MANIFEST_ROOT as [src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/must_c/en_de/src_dict.txt) #### Prepare WMT text data - [Download wmt data](https://github.com/pytorch/fairseq/blob/main/examples/translation/prepare-wmt14en2de.sh) - Convert source text (English) into phoneme representation as above -- Generate binary parallel file for training (as translation example) and save data in $parallel_text_data +- Generate binary parallel files with "fairseq-preprocess" from fairseq for training and validation. The source input is English phoneme representation and the target input is German sentencepiece token . The output is saved under $parallel_text_data ## Training The model is trained with 8 v100 GPUs. diff --git a/examples/speech_text_joint_to_text/docs/pre-training.md b/examples/speech_text_joint_to_text/docs/pre-training.md new file mode 100644 index 0000000000..20272e6165 --- /dev/null +++ b/examples/speech_text_joint_to_text/docs/pre-training.md @@ -0,0 +1,188 @@ +[[Back]](..) + +# Unified Speech-Text Pre-training for Speech Translation and Recognition + +This directory contains the pre-training recipes from paper ["Unified Speech-Text Pre-training for Speech Translation and Recognition"](https://arxiv.org/abs/2204.05409). + +## Librispeech ASR Pre-training +### Prepare Data +#### Download files +#### Prepare pre-training data +- Text to text task (T2T): prepare the binary data following the similar steps in [EN_DE Joint training](./ende-mustc.md). The source data is presented as phomeme token sequence and the target data is coded as subword tokens via SentencePiece. The text data is downloaded from [openslr](https://www.openslr.org/12) +- Self-supervised speech learning task (SSL): The data is prepared as [wav2vec 2.0](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec/README.md) +- Speech to phoneme classification task (S2P): The tsv file contains 5 fields: "id", "audio", "n_frames", "tgt_text", and "align". The tgt_text field is corresponding to the phoneme based representation of the speech data. "align" field contains the alignment information. The phoneme level forced alignment for the labelled speech data (i.e. Librispeech) can be obtained via [kaldi](http://kaldi-asr.org) or [MFA](https://montrealcorpustools.github.io/Montreal-Forced-Aligner/). The segmentation information is normalized to 0$\sim$1 for the whole utterance. The snapshot of the tsv file is below: +``` +id audio n_frames tgt_text align +116-288045-0000 /librispeech/dev-other/116/288045/116-288045-0000.flac 170400 <sil> ▁AE1 Z AY1 ▁AH0 P R OW1 CH T ▁DH AH1 ▁S IH1 T IY0 <sil> AY1 ▁HH ER1 D ▁B EH1 L Z ▁R IH1 NG IH0 NG <sil> ▁AE1 N D AH0 ▁L IH1 T AH0 L ▁L EY1 T ER0 AY1 ▁F AW1 N D ▁DH AH0 ▁S T R IY1 T S ▁AH0 S T IH1 R ▁W IH0 TH ▁TH R AO1 NG Z ▁AH0 V ▁W EH1 L ▁D R EH1 S T ▁P IY1 P AH0 L ▁IH1 N ▁F AE1 M L IY0 ▁G R UW1 P S <sil> ▁W EH1 N D IH0 NG ▁DH EH1 R ▁W EY1 <sil> ▁HH IH1 DH ER0 ▁AH0 N D ▁TH IH1 DH ER0 <sil> 0.047977 0.056444 0.064911 0.075259 0.081844 0.089370 0.095014 0.104421 0.109125 0.111947 0.115710 0.120414 0.134525 0.141110 0.143932 0.174036 0.176858 0.190028 0.199436 0.207902 0.218250 0.224835 0.231421 0.242709 0.251176 0.257761 0.263405 0.268109 0.270931 0.290687 0.342427 0.349953 0.353716 0.356538 0.360301 0.363123 0.365945 0.368768 0.371590 0.376294 0.384760 0.394167 0.401693 0.409219 0.419567 0.430856 0.441204 0.444026 0.446849 0.449671 0.456256 0.463782 0.471308 0.477893 0.486359 0.491063 0.494826 0.501411 0.512700 0.517404 0.520226 0.534337 0.540922 0.545626 0.550329 0.559737 0.568203 0.583255 0.592662 0.600188 0.603951 0.611477 0.619003 0.624647 0.634055 0.639699 0.646284 0.653810 0.659454 0.664158 0.670743 0.682032 0.687676 0.692380 0.708373 0.713076 0.719661 0.729069 0.740357 0.744120 0.748824 0.752587 0.761994 0.770461 0.781750 0.790216 0.805268 0.808090 0.823142 0.832549 0.836312 0.840075 0.843838 0.851364 0.854186 0.857008 0.862653 0.878645 0.898401 0.901223 0.906867 0.913452 0.920038 0.926623 0.934149 0.939793 0.942615 0.945437 0.952023 0.957667 0.977422 1.000000 + +``` +- Speech to text task (S2T): The data preparation follow the steps in [EN_DE Joint training](./ende-mustc.md). + +#### Prepare fine-tuning data: +We re-use the data from T2T and S2T tasks in the fine-tuning stage. + +### Model Build +#### Pre-training +``` +python train.py $T2T_DATA \ + --save-dir $SAVE_PRE_PATH --user-dir examples/speech_text_joint_to_text --task speech_text_joint_denoising \ + --criterion speech_text_pretrain_cross_entropy --optimizer adam --weight-decay 0.01 --config-yaml config_s2p.yaml --config-s2s-yaml config.yaml --ddp-backend no_c10d \ + --lang-pairs pho-wrd --num-workers 4 --log-interval 500 --save-interval-updates 5000 --keep-interval-updates 1 --no-emb-update-unsup --report-accuracy --lr 0.001 --end-learning-rate 1e-06 \ + --lr-scheduler polynomial_decay --warmup-updates 10000 --total-num-update 800000 --update-freq 6 --validate-interval-updates 10000 --train-subset train \ + --valid-subset valid,valid_sup_speech,valid_sup_speech_s2s,valid_unsup_speech --dataset-impl mmap \ + --sup-speech-data $S2P_DATA_PATH --sup-speech-train-subset train_960.ali --sup-speech-valid-subset dev-clean.ali --sup-speech-s2s-data $S2T_DATA_PATH \ + --sup-speech-s2s-train-subset train --sup-speech-s2s-valid-subset dev-clean --unsup-speech-train-data $SSL_DATA_PATH/train.tsv --unsup-speech-valid-data $SSL_DATA_PATH/valid.tsv \ + --batch-size 200 --batch-size-valid 150 --max-source-positions 1024 --max-target-positions 1024 --max-text-tokens 3072 --max-speech-positions 600000 \ + --max-sample-size 750000 --min-sample-size 64000 --max-speech-tokens 750000 --max-tokens-valid 750000 --skip-invalid-size-inputs-valid-test \ + --unsupervised-speech-sample-ratio 3.0 --supervised-speech-sample-ratio 5 --supervised-speech-s2s-sample-ratio 5 --text-sample-ratio 1.0 --mask 0.3 --mask-random 0.1 \ + --mask-length span-poisson --speech-sup-mask-prob 0.3 --speech-unsup-mask-prob 0.7 --use-mask-whole-words --arch speech_text_pretrain_bart_base_stack \ + --no-scale-feature --activation-fn gelu --speech-extractor-mode default --stacked-encoder all --encoder-normalize-before --decoder-normalize-before \ + --encoder-learned-pos --decoder-learned-pos --dropout 0.1 --load-pretrained-mbart-encoder-from $BART --load-pretrained-mbart-decoder-from $BART +``` +The current implementation also supports model pre-training without the forced alignment supervised data. In this case, CTC is used to optimize the S2P task. We need to do following changes for the setting: +1. options to be added +``` +--use-sup-speech-ctc --criterion speech_text_pretrain_compound +``` +2. options to be deleted +``` +--same-data-update --criterion speech_text_pretrain_cross_entropy +``` +However, we find the CTC based pre-training is still worse than the forced alignment based setting. It could be partially due to the inferior pre-training setting that we re-use the forced alignment based pre-training setting for the CTC based pre-training. + +#### Fine-tuning +``` +python train.py $S2T_DATA_PATH \ + --save-dir $SAVE_FT_PATH --num-workers 8 --task speech_text_joint_to_text --arch dualinputs2twavtransformer_base_stack \ + --user-dir examples/speech_text_joint_to_text --max-update 100000 --optimizer adam --lr-scheduler inverse_sqrt --lr 0.0003 --update-freq 3 --clip-norm 10.0 \ + --criterion guided_label_smoothed_cross_entropy_with_accuracy --guide-alpha 0.8 --label-smoothing 0.1 --warmup-updates 20000 --attentive-cost-regularization 0.02 \ + --enc-grad-mult 2.0 --max-tokens 800000 --max-source-positions 800000 --max-tokens-text 10000 --max-positions-text 1024 --max-target-positions 1024 --no-scale-feature \ + --activation-fn gelu --load-pretrained-speech-text-encoder $SAVE_PRE_PATH/checkpoint_last.pt --load-pretrained-speech-text-decoder $SAVE_PRE_PATH/checkpoint_last.pt \ + --encoder-normalize-before --decoder-normalize-before --speech-extractor-mode default --speech-mask-channel-length 64 --speech-mask-channel-prob 0.5 \ + --speech-mask-length 10 --speech-mask-prob 0.65 --text-sample-ratio 0.25 --mask-text-ratio 0.3 --mask-text-type random --parallel-text-data text_bin \ + --text-input-cost-ratio 0.5 --langpairs pho-wrd --update-mix-data --log-format json --max-tokens-valid 800000 --ddp-backend no_c10d --log-interval 500 \ + --config-yaml config.yaml --skip-invalid-size-inputs-valid-test --keep-last-epochs 50 --layernorm-embedding --encoder-learned-pos --decoder-learned-pos +``` + +### Evaluation +The last 10 epoch models from fine-tuning is conducted model average to get $FINAL_MODEL +``` +python ./fairseq_cli/generate.py \ + $S2T_DATA_PATH \ + --task speech_text_joint_to_text \ + --max-tokens 800000 \ + --max-source-positions 800000 \ + --nbest 1 \ + --results-path $RESULTS_LOG \ + --batch-size 512 \ + --path $FINAL_MODEL \ + --gen-subset $SUBSET \ + --config-yaml config.yaml \ + --scoring wer \ + --beam 10 --lenpen 1.0 examples/speech_text_joint_to_text +``` + +### Results and models +| | dev-clean | dev-other | test-clean | test-other | +|---|---|---|---|---| +| WER| 2.0 | 4.4 | 2.1 |4.6 | + +**Model Links**: +- [config_s2p.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/pretrain/config_s2p.yaml): Config for S2P +- [spm.model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/finetuned/spm.model): Sentence Piece model +- [src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/finetuned/src_dict.txt): Source Phoneme Dictionary +- [tgt_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/finetuned/tgt_dict.txt): Target Sentence Piece Dictionary +- [config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/finetuned/config.yaml): Config for S2T +- [BART](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/pretrain/bart.pt): trained from Librispeech text data +- [Joint Pre-trained model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/pretrain/checkpoint6.pt): model pre-trained with 960 hours Librispeech data (S2P, S2T) Librispeech text training data (T2T) and Librilight data (SSL) +- [Fine-tuned model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/finetuned/checkpoint_ave_10.pt): the pre-trained model is fined one 960 hours Librispeech speech and text data. (S2T + T2T) + +## MuST-C +### Prepare Data +Compared with the ASR Librispeech ASR recipe, the differences are below: +- Replace the speech data with corresponding MuST-C data +- Parallel text data from WMT is replaced the Librispeech text data + +### Model Build +#### Pre-training +EN-DE is used as an example +``` +python train.py $TXT_DATA \ + --save-dir $SAVE_PRE_PATH --user-dir examples/speech_text_joint_to_text --task speech_text_joint_denoising --criterion speech_text_pretrain_cross_entropy --optimizer adam --weight-decay 0.01 \ + --config-yaml config_s2p.yaml --config-s2s-yaml config.yaml --ddp-backend no_c10d --lang-pairs-bitext en-fr --num-workers 4 --log-interval 500 --save-interval-updates 5000 --keep-interval-updates 1 \ + --no-emb-update-unsup --use-decoder-output-proj --report-accuracy --lr 0.001 --end-learning-rate 1e-06 --lr-scheduler polynomial_decay --warmup-updates 10000 --total-num-update 800000 \ + --update-freq 8 --validate-interval-updates 10000 --train-subset train --valid-subset valid_sup_speech,valid_sup_speech_s2s,valid_unsup_speech --dataset-impl mmap \ + --sup-speech-data $S2P_DATA_PATH --sup-speech-train-subset train --sup-speech-valid-subset dev --sup-speech-s2s-data $S2T_DATA_PATH --sup-speech-s2s-train-subset train \ + --sup-speech-s2s-valid-subset dev --unsup-speech-train-data $SSL_DATA_PATH/train.tsv --unsup-speech-valid-data $SSL_DATA_PATH/valid.tsv --batch-size 200 --batch-size-valid 100 \ + --max-source-positions 1024 --max-target-positions 1024 --max-text-tokens 2048 --max-speech-positions 600000 --max-sample-size 600000 --min-sample-size 64000 \ + --max-speech-tokens 600000 --max-tokens-valid 600000 --skip-invalid-size-inputs-valid-test --unsupervised-speech-sample-ratio 1.2 --supervised-speech-sample-ratio 10 \ + --supervised-speech-s2s-sample-ratio 10 --bitext-sample-ratio 0.5 --mask 0.3 --mask-random 0.1 --mask-length span-poisson --speech-sup-mask-prob 0.3 \ + --speech-unsup-mask-prob 0.7 --use-mask-whole-words --arch speech_text_pretrain_bart_base_stack --no-scale-feature --activation-fn gelu --speech-extractor-mode default \ + --stacked-encoder s2s --encoder-normalize-before --decoder-normalize-before --encoder-learned-pos --decoder-learned-pos --dropout 0.1 \ + --load-pretrained-mbart-encoder-from $EN_FR_NMT --load-pretrained-mbart-decoder-from $EN_FR_NMT +``` +#### Fine-tuning +``` +python train.py $S2T_DATA_PATH \ + --save-dir $SAVE_FT_PATH --num-workers 8 --task speech_text_joint_to_text --arch dualinputs2twavtransformer_base_stack --user-dir examples/speech_text_joint_to_text \ + --max-epoch 25 --update-mix-data --optimizer adam --lr-scheduler inverse_sqrt --lr 0.0003 --update-freq 4 --clip-norm 10.0 --warmup-updates 20000 \ + --criterion guided_label_smoothed_cross_entropy_with_accuracy --guide-alpha 0.8 --attentive-cost-regularization 0.02 --enc-grad-mult 2.0 --label-smoothing 0.1 \ + --max-tokens 800000 --max-source-positions 800000 --max-tokens-text 10000 --max-positions-text 1024 --load-pretrained-speech-text-encoder $SAVE_PRE_PATH/checkpoint_last.pt \ + --load-pretrained-speech-text-decoder $SAVE_PRE_PATH/checkpoint_last.pt --speech-mask-channel-length 64 --speech-mask-channel-prob 0.5 --speech-mask-length 10 \ + --speech-mask-prob 0.65 --text-sample-ratio 0.05 --mask-text-ratio 0.3 --mask-text-type random --parallel-text-data data-bin-wt --text-input-cost-ratio 0.5 \ + --langpairs en-fr --log-format json --max-tokens-valid 800000 --ddp-backend no_c10d --log-interval 100 --config-yaml config.yaml --skip-invalid-size-inputs-valid-test \ + --noise-token '▁NOISE' --keep-last-epochs 40 --layernorm-embedding --encoder-learned-pos --decoder-learned-pos --activation-fn gelu \ + --speech-extractor-mode default --max-target-positions 1024 --encoder-normalize-before --decoder-normalize-before +``` + +### Evaluation +The last 10 epoch models from fine-tuning is conducted model average to get $FINAL_MODEL +``` +python fairseq_cli/generate.py \ + $S2T_DATA_PATH \ + --task speech_text_joint_to_text \ + --nbest 1 \ + --max-tokens 800000 \ + --max-source-positions 800000 \ + --results-path $RESULTS_LOG \ + --batch-size 512 \ + --path $FINAL_MODEL \ + --gen-subset $SUBSET \ + --config-yaml config.yaml \ + --scoring sacrebleu \ + --beam 10 --lenpen 1.0 examples/speech_text_joint_to_text +``` + + +### Results and models +| | en-fr | en-es | en-de | +|---|---|---|---| +| BLEU| 39.7 | 33.2 |29.2 | + + +**Model Links**: +1. DE + - [de config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/de/config.yaml) + - [de src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/de/src_dict.txt) + - [de tgt_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/de/tgt_dict.txt) + - [de spm.model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/de/spm.model) + - [de pre-trained nmt model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/de/nmt.pt) + - [de pre-trained model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/de/checkpoint_pretraing.pt) + - [de fine-tuned model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/de/checkpoint_finetune_ave10.pt) +2. ES + - [es config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/es/config.yaml) + - [es src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/es/src_dict.txt) + - [es tgt_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/es/tgt_dict.txt) + - [es spm.model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/es/spm.model) + - [es pre-trained nmt model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/es/nmt.pt) + - [es pre-trained model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/es/checkpoint_pretraing.pt) + - [es fine-tuned model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/es/checkpoint_finetune_ave10.pt) +3. FR + - [fr config.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/fr/config.yaml) + - [fr src_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/fr/src_dict.txt) + - [fr tgt_dict.txt](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/fr/tgt_dict.txt) + - [fr spm.model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/fr/spm.model) + - [fr pre-trained nmt model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/fr/nmt.pt) + - [fr pre-trained model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/fr/checkpoint_pretraing.pt) + - [fr fine-tuned model](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/fr/checkpoint_finetune_ave10.pt) +4. [config_s2p.yaml](https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/must_c/config_s2p.yaml) diff --git a/examples/speech_text_joint_to_text/models/joint_speech_text_pretrain_transformer.py b/examples/speech_text_joint_to_text/models/joint_speech_text_pretrain_transformer.py new file mode 100644 index 0000000000..6f917398a5 --- /dev/null +++ b/examples/speech_text_joint_to_text/models/joint_speech_text_pretrain_transformer.py @@ -0,0 +1,698 @@ +#!/usr/bin/env python3 + +import logging +from collections import OrderedDict, namedtuple +from typing import Dict, Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor + +from fairseq import checkpoint_utils, utils +from fairseq.file_io import PathManager +from fairseq.models import ( + FairseqDecoder, + FairseqEncoderDecoderModel, + register_model, + register_model_architecture, +) +from fairseq.models.speech_to_text import ( + MultiInputDecoder, + MultiModalityEncoder, + SpeechWavTransformerEncoder, + StackedSpeechWavTransformerEncoder, +) +from fairseq.models.transformer import ( + TransformerDecoder, + TransformerEncoder, + TransformerModel, +) + +logger = logging.getLogger(__name__) + + +class SpeechTextPreTrainEncoder(MultiModalityEncoder): + def __init__( + self, + dictionary, + sup_speech_encoder, + sup_s2s_speech_encoder, + unsup_speech_encoder, + text_encoder, + ): + super().__init__(dictionary) + self.sup_speech_encoder = sup_speech_encoder + self.sup_s2s_speech_encoder = sup_s2s_speech_encoder + self.unsup_speech_encoder = unsup_speech_encoder + self.text_encoder = text_encoder + + @classmethod + def update_transformer_encoder_cfg(cls, args, update_dict): + cfg = dict(args._get_kwargs()) + for fkey in update_dict.keys(): + cfg[fkey] = update_dict[fkey] + cfg.pop("_name", None) # remove keys start with _ + model_args = namedtuple("args", cfg.keys())(*cfg.values()) + return model_args + + @classmethod + def build_text_encoder(cls, args, src_dictionary): + enc_emb = nn.Embedding( + len(src_dictionary), args.encoder_embed_dim, src_dictionary.pad() + ) + model_args = cls.update_transformer_encoder_cfg( + args, {"encoder_layers": args.text_encoder_layers} + ) + text_encoder = TransformerEncoder(model_args, src_dictionary, enc_emb) + return text_encoder + + @classmethod + def build_speech_encoder(cls, args): + model_args = cls.update_transformer_encoder_cfg( + args, + { + "encoder_layers": args.speech_encoder_layers, + "speech_mask_prob": args.speech_sup_mask_prob, + }, + ) + speech_encoder = SpeechWavTransformerEncoder(model_args) + return speech_encoder + + @classmethod + def share_layers(cls, src_layers, tgt_layers): # share layer but not dropout + # share parameters in src_layers with tgt_layers + assert len(src_layers) == len(tgt_layers) + for i, ly in enumerate(src_layers): + tly = tgt_layers[i] + tly.self_attn = ly.self_attn + tly.self_attn_layer_norm = ly.self_attn_layer_norm + tly.activation_fn = ly.activation_fn + tly.normalize_before = ly.normalize_before + tly.fc1 = ly.fc1 + tly.fc2 = ly.fc2 + tly.final_layer_norm = ly.final_layer_norm + if hasattr(tly, "encoder_attn"): + tly.encoder_attn = ly.encoder_attn + tly.encoder_attn_layer_norm = ly.encoder_attn_layer_norm + return tgt_layers + + @classmethod + def build_unsup_speech_encoder(cls, args, sup_speech_encoder): + model_args = cls.update_transformer_encoder_cfg( + args, + { + "encoder_layers": args.speech_encoder_layers, + "speech_mask_prob": args.speech_unsup_mask_prob, + "encoder_layerdrop": 0.0, + "decoder_layerdrop": 0.0, + "dropout": args.speech_unsup_dropout, + "activation_dropout": args.speech_unsup_dropout, + "attention_dropout": 0.0, + "dropout_features": args.speech_unsup_feature_dropout, + "dropout_input": args.speech_unsup_feature_dropout, + }, + ) + + unsup_speech_encoder = SpeechWavTransformerEncoder(model_args, alway_mask=True) + unsup_speech_encoder.layer_norm = sup_speech_encoder.layer_norm + unsup_speech_encoder.layers = cls.share_layers( + sup_speech_encoder.layers, unsup_speech_encoder.layers + ) + unsup_speech_encoder.mask_emb = sup_speech_encoder.mask_emb + unsup_speech_encoder.embed_positions = sup_speech_encoder.embed_positions + unsup_speech_encoder.feat_layer_norm = sup_speech_encoder.feat_layer_norm + unsup_speech_encoder.feat_proj = sup_speech_encoder.feat_proj + unsup_speech_encoder.subsample = sup_speech_encoder.subsample + return unsup_speech_encoder + + @classmethod + def build_encoder(cls, args, dictionary): + text_encoder = cls.build_text_encoder(args, dictionary) + if getattr(args, "load_pretrained_mbart_encoder_from", None): + text_encoder = checkpoint_utils.load_pretrained_component_from_model( + component=text_encoder, + checkpoint=args.load_pretrained_mbart_encoder_from, + ) + speech_encoder = cls.build_speech_encoder(args) + if getattr(args, "load_pretrained_feature_extractor_from", None): + + def load_feature_extractor(component, checkpoint): + if not PathManager.exists(checkpoint): + raise IOError("Model file not found: {}".format(checkpoint)) + state = checkpoint_utils.load_checkpoint_to_cpu(checkpoint) + component_state_dict = OrderedDict() + + component_prefix = "feature_extractor" + for key in state["model"].keys(): + if key.startswith(component_prefix): + component_subkey = key[len(component_prefix) + 1 :] + component_state_dict[component_subkey] = state["model"][key] + component.load_state_dict(component_state_dict, strict=True) + return component + + speech_encoder.subsample = load_feature_extractor( + speech_encoder.subsample, args.load_pretrained_feature_extractor_from + ) + speech_s2s_encoder = speech_encoder + unsup_speech_encoder = cls.build_unsup_speech_encoder(args, speech_encoder) + if getattr(args, "stacked_encoder", "none") != "none": + if args.encoder_shared_text_layers_from_begin > 0: + raise ValueError( + "We can not stack encoders and share encoders at the same time!" + ) + speech_s2s_encoder = StackedSpeechWavTransformerEncoder( + speech_encoder, text_encoder.layers, text_encoder.layer_norm + ) + if args.stacked_encoder == "all": + speech_encoder = speech_s2s_encoder + unsup_speech_encoder = StackedSpeechWavTransformerEncoder( + unsup_speech_encoder, text_encoder.layers, text_encoder.layer_norm + ) + else: + cls.share_speech_text_encoder( + speech_encoder, text_encoder, args.encoder_shared_text_layers_from_begin + ) + return SpeechTextPreTrainEncoder( + dictionary, + speech_encoder, + speech_s2s_encoder, + unsup_speech_encoder, + text_encoder, + ) + + @classmethod + def share_speech_text_encoder( + cls, speech_encoder, text_encoder, shared_layers_from_begin + ): + if shared_layers_from_begin > 0: + num_text_encoder_layers = len(text_encoder.layers) + assert len(speech_encoder.layers) >= shared_layers_from_begin + assert num_text_encoder_layers >= shared_layers_from_begin + assert len(speech_encoder.layers) >= num_text_encoder_layers + for i, ly in enumerate( + speech_encoder.layers[ + -num_text_encoder_layers : -num_text_encoder_layers + + shared_layers_from_begin + ] + ): + assert isinstance(text_encoder.layers[i], type(ly)) + text_encoder.layers[i] = ly + + def select_encoder(self, mode, **kwargs): + if mode in ("speech", "sup_speech_ctc", "sup_speech_ali", "sup_speech_s2s"): + kwargs["features_only"] = True + if mode == "sup_speech_s2s": + return self.sup_s2s_speech_encoder, kwargs + return self.sup_speech_encoder, kwargs + elif mode == "unsup_speech": + kwargs["features_only"] = False + return self.unsup_speech_encoder, kwargs + elif mode in ("text", "bitext"): + return self.text_encoder, kwargs + else: + raise NotImplementedError(f"{mode} is not supported") + return None, kwargs + + def forward(self, src_tokens, src_lengths=None, mode="", alignment=None, **kwargs): + return super().forward(src_tokens, src_lengths, mode, **kwargs) + + +# SpeechDummyDecoder works as an extension of encoder, so we could fit encoder only training into seq2seq training +class SpeechDummyDecoder(FairseqDecoder): + def __init__( + self, + dictionary, + output_embedding, + no_emb_update_unsup=False, + use_output_proj=False, + ): + super().__init__(dictionary) + self.output_embedding = output_embedding + num_embedding, num_dim = self.output_embedding.weight.size() + self.out_proj = ( + None if use_output_proj is False else nn.Linear(num_dim, num_dim) + ) + self.no_emb_update_unsup = no_emb_update_unsup + + def extend_alignment(self, alignment, src_lengths, prev_output_tokens): + # alignment: B X N + # src_lengths: B X T + # prev_output_tokens: B X (N + 1) + tgt_tokens = prev_output_tokens[ + :, 1: + ] # remove the leading start of sentence token + ext_alignment = ( + torch.ones(len(src_lengths), src_lengths.max(), device=src_lengths.device) + .long() + .fill_(self.dictionary.pad()) + ) + for bs in range(src_lengths.size(0)): + tgt_length = tgt_tokens[bs].ne(self.dictionary.pad()).sum().item() + assert tgt_length == sum(alignment[bs].ne(1)) + 1 + src_st = 0 + for i in range(tgt_length): + tok = tgt_tokens[bs][i] + src_ed = (alignment[bs][i] * src_lengths[bs]).int().item() + ext_alignment[bs][src_st:src_ed].fill_(tok) + src_st = src_ed + return ext_alignment + + def forward( + self, + prev_output_tokens, + encoder_out, + incremental_state=None, + mode="speech", + alignment=None, + **kwargs, + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + encoder_out (optional): output from the encoder, used for + encoder-side attention + incremental_state (dict): dictionary used for storing state during + :ref:`Incremental decoding` + features_only (bool, optional): only return features without + applying output layer (default: False). + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + + Returns: + sup_speech_ctc: + dictionary{"logits": logits, "padding_mask": padding_mask} + sup_speech_ali and unsup_speech: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + emb_weight = self.output_embedding.weight + if ( + mode == "unsup_speech" and self.no_emb_update_unsup + ): # no gradient for embedding here + emb_weight = emb_weight.detach() + enc_out = ( + encoder_out["encoder_out"][0] + if self.out_proj is None + else self.out_proj(encoder_out["encoder_out"][0]) + ) + logits = F.linear(enc_out, emb_weight, None).transpose(0, 1) # B X T X C + others = None + if mode in ( + "speech", + "sup_speech_ctc", + ): # speech data with label, do forcealignment + if len(encoder_out["encoder_padding_mask"]) > 0: + padding_mask = encoder_out["encoder_padding_mask"][0] + logits = logits.masked_fill(padding_mask, float("-inf")) + else: + seq_len, bsz = encoder_out["encoder_out"][0].size()[:2] + padding_mask = torch.zeros( + bsz, seq_len, device=encoder_out["encoder_out"][0].device + ).bool() + return {"x": logits, "padding_mask": padding_mask} + elif mode == "sup_speech_ali": + src_lengths = None + if len(encoder_out["encoder_padding_mask"]) > 0: + src_lengths = (1 - encoder_out["encoder_padding_mask"][0].long()).sum( + -1 + ) + else: + seq_len, bsz = encoder_out["encoder_out"][0].size()[:2] + src_lengths = ( + torch.ones(bsz, device=encoder_out["encoder_out"][0].device).long() + * seq_len + ) + assert alignment is not None + alignment = self.extend_alignment( + alignment, src_lengths, prev_output_tokens + ) + others = {"pseudo_target_tokens": alignment} + elif mode == "unsup_speech": + enc_out_ori = ( + encoder_out["encoder_unmasked_out"][0] + if self.out_proj is None + else self.out_proj(encoder_out["encoder_unmasked_out"][0]) + ) + logits_ori = F.linear(enc_out_ori, emb_weight, None).transpose(0, 1) + if len(encoder_out["encoder_padding_mask"]) > 0: + encoder_padding_mask = encoder_out["encoder_padding_mask"][0] + logits_ori = logits_ori.masked_fill(encoder_padding_mask, float("-inf")) + pseudo_labels = utils.log_softmax(logits_ori, dim=-1) + others = { + "pseudo_target_logprobs": pseudo_labels, + "padding_mask": encoder_out["encoder_padding_mask"], # B X T + "mask_indices": encoder_out[ + "mask_indices" + ], # True for masked frames B X T + } + return logits, others + + def get_normalized_probs( + self, + net_output: Dict[str, Tensor], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): + return self.get_normalized_probs_scriptable( + (net_output["x"], None), log_probs, sample + ) + + +class SpeechTextPreTrainDecoder(MultiInputDecoder): + def __init__(self, dictionary, speech_decoder, text_decoder): + super().__init__(dictionary) + self.speech_decoder = speech_decoder + self.text_decoder = text_decoder + + def select_decoder(self, mode, **kwargs): + if mode == "unsup_speech": + kwargs["mode"] = mode + return self.speech_decoder, kwargs + if mode in ("text", "bitext"): + return self.text_decoder, kwargs + if mode in ("speech", "sup_speech_ctc", "sup_speech_ali"): + kwargs["mode"] = mode + return self.speech_decoder, kwargs + if mode in ("speech", "sup_speech_s2s"): + if "alignment" in kwargs: + del kwargs["alignment"] + return self.text_decoder, kwargs + + raise NotImplementedError(f"{mode} is not supported") + return None, kwargs + + def get_normalized_probs( + self, + net_output, + log_probs, + sample=None, + ): + """Get normalized probabilities (or log probs) from a net's output.""" + if isinstance(net_output, dict): + return self.speech_decoder.get_normalized_probs( + net_output, log_probs, sample + ) + return self.text_decoder.get_normalized_probs(net_output, log_probs, sample) + + @classmethod + def build_text_decoder(cls, args, tgt_dictionary, dec_emb_share=None): + dec_emb = ( + nn.Embedding( + len(tgt_dictionary), args.decoder_embed_dim, tgt_dictionary.pad() + ) + if dec_emb_share is None + else dec_emb_share + ) + text_decoder = TransformerDecoder(args, tgt_dictionary, dec_emb) + return text_decoder + + @classmethod + def build_dummy_speech_decoder(cls, args, dictionary, dec_emb_share=None): + dec_emb = ( + nn.Embedding(len(dictionary), args.decoder_embed_dim, dictionary.pad()) + if dec_emb_share is None + else dec_emb_share + ) + speech_decoder = SpeechDummyDecoder( + dictionary, + dec_emb, + no_emb_update_unsup=getattr(args, "no_emb_update_unsup", False), + use_output_proj=getattr(args, "use_decoder_output_proj", False), + ) + return speech_decoder + + @classmethod + def build_decoder( + cls, args, text_dictionary, speech_dictionary, speech_output_embedding + ): + text_decoder = cls.build_text_decoder(args, text_dictionary) + speech_decoder = cls.build_dummy_speech_decoder( + args, speech_dictionary, speech_output_embedding + ) + if getattr(args, "load_pretrained_mbart_decoder_from", None): + text_decoder = checkpoint_utils.load_pretrained_component_from_model( + component=text_decoder, + checkpoint=args.load_pretrained_mbart_decoder_from, + ) + return SpeechTextPreTrainDecoder(text_dictionary, speech_decoder, text_decoder) + + +@register_model("speech_text_pretrain_bart") +class SpeechTextPreTrainModel(FairseqEncoderDecoderModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + self.num_updates = 0 + + def forward( + self, src_tokens, src_lengths, prev_output_tokens, src_lang_ids=None, **kwargs + ): + if src_lang_ids is not None: + encoder_out = self.encoder( + src_tokens, src_lengths=src_lengths, src_lang_ids=src_lang_ids, **kwargs + ) + else: + encoder_out = self.encoder(src_tokens, src_lengths=src_lengths, **kwargs) + decoder_out = self.decoder( + prev_output_tokens, encoder_out=encoder_out, **kwargs + ) + return decoder_out + + def max_positions(self): + return None # it is provided in task + + def get_targets(self, sample, net_output): + mode = sample["net_input"]["mode"] + if mode == "unsup_speech": + return {"target_logprobs": net_output[1]["pseudo_target_logprobs"]} + if mode == "sup_speech_ali": + return net_output[1]["pseudo_target_tokens"] + return sample["target"] + + def get_normalized_probs( + self, + net_output, + log_probs, + sample=None, + ): + # net_output['encoder_out'] is a (B, T, D) tensor + lprobs = self.get_normalized_probs_scriptable(net_output, log_probs, sample) + lprobs.batch_first = True + return lprobs + + @staticmethod + def add_args(parser): + TransformerModel.add_args(parser) + SpeechWavTransformerEncoder.add_args(parser) + parser.add_argument( + "--speech-sup-mask-prob", + type=float, + help="probability of replacing a token with mask (sup-speech)", + ) + parser.add_argument( + "--speech-unsup-mask-prob", + type=float, + help="probability of replacing a token with mask (unsup-speech)", + ) + parser.add_argument( + "--load-pretrained-mbart-encoder-from", + type=str, + metavar="STR", + help="model to take text encoder weights from (for initialization)", + ) + + parser.add_argument( + "--load-pretrained-mbart-decoder-from", + type=str, + metavar="STR", + help="model to take text decoder weights from (for initialization)", + ) + + parser.add_argument( + "--load-pretrained-feature-extractor-from", + type=str, + metavar="STR", + help="model to take feature extractor weights from (for initialization)", + ) + + parser.add_argument( + "--speech-unsup-dropout", + type=float, + default=0, + help="dropout for unsupervised speech encoder", + ) + + parser.add_argument( + "--speech-unsup-feature-dropout", + type=float, + default=0, + help="dropout for unsupervised speech feature encoder", + ) + + parser.add_argument( + "--encoder-shared-text-layers-from-begin", + type=int, + help="number of text encoder layers shared with speech encoder (from first layer)", + ) + + parser.add_argument( + "--stacked-encoder", + default="none", + choices=["none", "s2s", "all"], + help="stack speech and text encoders", + ) + + parser.add_argument("--use-decoder-output-proj", action="store_true") + + @classmethod + def build_model(cls, args, task): + encoder = SpeechTextPreTrainEncoder.build_encoder(args, task.src_dict) + decoder = SpeechTextPreTrainDecoder.build_decoder( + args, task.tgt_dict, task.src_dict, encoder.text_encoder.embed_tokens + ) + model = SpeechTextPreTrainModel(encoder, decoder) + return model + + def upgrade_state_dict(self, state_dict): + """Upgrade old state dicts to work with newer code.""" + if "decoder.speech_decoder.output_projection.weight" in state_dict: + del state_dict["decoder.speech_decoder.output_projection.weight"] + self.upgrade_state_dict_named(state_dict, "") + + +@register_model_architecture( + "speech_text_pretrain_bart", "speech_text_pretrain_bart_base" +) +def speech_text_pretrain_bart_base(args): + # speech masking + args.dropout_input = getattr(args, "dropout_input", 0) + args.dropout_features = getattr(args, "dropout_features", 0) + args.speech_mask_length = getattr(args, "speech_mask_length", 10) + args.speech_mask_prob = getattr(args, "speech_mask_prob", 0.65) + args.speech_sup_mask_prob = getattr(args, "speech_sup_mask_prob", 0.3) + args.speech_unsup_mask_prob = getattr( + args, "speech_unsup_mask_prob", args.speech_mask_prob + ) + args.speech_mask_selection = getattr(args, "speech_mask_selection", "static") + args.speech_mask_other = getattr(args, "speech_mask_other", 0) + args.speech_mask_min_space = getattr(args, "speech_mask_min_space", 1) + args.speech_no_mask_overlap = getattr(args, "speech_no_mask_overlap", False) + + args.speech_mask_channel_length = getattr(args, "speech_mask_channel_length", 10) + args.speech_mask_channel_prob = getattr(args, "speech_mask_channel_prob", 0.0) + args.speech_mask_channel_selection = getattr( + args, "speech_mask_channel_selection", "static" + ) + args.speech_mask_channel_other = getattr(args, "speech_mask_channel_other", 0) + args.speech_mask_channel_min_space = getattr( + args, "speech_mask_channel_min_space", 1 + ) + args.speech_no_mask_channel_overlap = getattr( + args, "speech_no_mask_channel_overlap", False + ) + args.no_scale_feature = getattr(args, "", False) + args.feature_grad_mult = getattr(args, "feature_grad_mult", 1.0) # 0.1 + + # Transformer + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768) + args.encoder_ffn_embed_dim = getattr( + args, "encoder_ffn_embed_dim", args.encoder_embed_dim * 4 + ) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) + args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0) + args.encoder_learned_pos = getattr(args, "encoder_learned_pos", False) + args.speech_conv_bias = getattr(args, "speech_conv_bias", False) + + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim + ) + args.decoder_attention_heads = getattr( + args, "decoder_attention_heads", args.encoder_attention_heads + ) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", args.dropout) + args.activation_dropout = getattr(args, "activation_dropout", 0.0) + args.activation_fn = getattr(args, "activation_fn", "relu") # gelu? + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + + args.speech_unsup_dropout = getattr(args, "speech_unsup_dropout", 0) + args.speech_unsup_feature_dropout = getattr(args, "speech_unsup_feature_dropout", 0) + + args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + args.adaptive_input = getattr(args, "adaptive_input", False) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.layernorm_embedding = getattr(args, "layernorm_embedding", False) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 12) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.encoder_shared_text_layers_from_begin = getattr( + args, "encoder_shared_text_layers_from_begin", 6 + ) + args.decoder_layers = getattr(args, "decoder_layers", 6) + + args.no_emb_update_unsup = getattr(args, "no_emb_update_unsup", False) + + +@register_model_architecture( + "speech_text_pretrain_bart", "speech_text_pretrain_bart_base_stack" +) +def speech_text_pretrain_bart_base_stack(args): + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 6) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.encoder_shared_text_layers_from_begin = getattr( + args, "encoder_shared_text_layers_from_begin", 0 + ) + args.stacked_encoder = getattr(args, "stacked_encoder", "all") + args.layernorm_embedding = getattr(args, "layernorm_embedding", True) + speech_text_pretrain_bart_base(args) + + +@register_model_architecture( + "speech_text_pretrain_bart", "speech_text_pretrain_bart_large" +) +def speech_text_pretrain_bart_large(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 24) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 12) + args.encoder_shared_text_layers_from_begin = getattr( + args, "encoder_shared_text_layers_from_begin", 12 + ) + args.decoder_layers = getattr(args, "decoder_layers", 12) + args.dropout = getattr(args, "dropout", 0.3) + speech_text_pretrain_bart_base(args) + + +@register_model_architecture( + "speech_text_pretrain_bart", "speech_text_pretrain_bart_large_stack" +) +def speech_text_pretrain_bart_large_stack(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 6) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 12) + args.encoder_shared_text_layers_from_begin = getattr( + args, "encoder_shared_text_layers_from_begin", 0 + ) + args.decoder_layers = getattr(args, "decoder_layers", 12) + args.stacked_encoder = getattr(args, "stacked_encoder", "s2s") + args.layernorm_embedding = getattr(args, "layernorm_embedding", True) + speech_text_pretrain_bart_base(args) diff --git a/examples/speech_text_joint_to_text/models/s2t_dualinputwavtransformer.py b/examples/speech_text_joint_to_text/models/s2t_dualinputwavtransformer.py new file mode 100644 index 0000000000..66e4b3f1ec --- /dev/null +++ b/examples/speech_text_joint_to_text/models/s2t_dualinputwavtransformer.py @@ -0,0 +1,526 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from collections import OrderedDict, namedtuple + +import torch.nn as nn + +from fairseq import checkpoint_utils, utils +from fairseq.checkpoint_utils import load_checkpoint_to_cpu +from fairseq.file_io import PathManager +from fairseq.models import register_model, register_model_architecture +from fairseq.models.speech_to_text import ( + SpeechWavTransformerEncoder, + StackedSpeechWavTransformerEncoder, + TransformerDecoder, +) +from fairseq.models.transformer import TransformerEncoder + +from .s2t_dualinputtransformer import ( + DualInputEncoder, + DualInputS2TTransformerModel, + TransformerMultiInputDecoder, +) + +logger = logging.getLogger(__name__) + + +@register_model("dual_input_wav_transformer") +class DualInputWavTransformerModel(DualInputS2TTransformerModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @staticmethod + def add_args(parser): + def add_transformer_args(parser): + # We can't use TransformerModel.add_args(parser), since it defines max-source-positions which is duplicated with tasks/speech_to_text.py + # Transformer + parser.add_argument( + "--activation-fn", + type=str, + default="relu", + choices=utils.get_available_activation_fns(), + help="activation function to use", + ) + parser.add_argument( + "--dropout", type=float, metavar="D", help="dropout probability" + ) + parser.add_argument( + "--attention-dropout", + type=float, + metavar="D", + help="dropout probability for attention weights", + ) + parser.add_argument( + "--activation-dropout", + "--relu-dropout", + type=float, + metavar="D", + help="dropout probability after activation in FFN.", + ) + parser.add_argument( + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension", + ) + parser.add_argument( + "--encoder-ffn-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension for FFN", + ) + parser.add_argument( + "--encoder-layers", type=int, metavar="N", help="num encoder layers" + ) + parser.add_argument( + "--encoder-attention-heads", + type=int, + metavar="N", + help="num encoder attention heads", + ) + parser.add_argument( + "--encoder-normalize-before", + action="store_true", + help="apply layernorm before each encoder block", + ) + parser.add_argument( + "--decoder-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension", + ) + parser.add_argument( + "--decoder-ffn-embed-dim", + type=int, + metavar="N", + help="decoder embedding dimension for FFN", + ) + parser.add_argument( + "--decoder-layers", type=int, metavar="N", help="num decoder layers" + ) + parser.add_argument( + "--decoder-attention-heads", + type=int, + metavar="N", + help="num decoder attention heads", + ) + parser.add_argument( + "--decoder-normalize-before", + action="store_true", + help="apply layernorm before each decoder block", + ) + parser.add_argument( + "--share-decoder-input-output-embed", + action="store_true", + help="share decoder input and output embeddings", + ) + parser.add_argument( + "--layernorm-embedding", + action="store_true", + help="add layernorm to embedding", + ) + parser.add_argument( + "--no-scale-embedding", + action="store_true", + help="if True, dont scale embeddings", + ) + + parser.add_argument( + "--encoder-learned-pos", + action="store_true", + help="use learned positional embeddings", + ) + parser.add_argument( + "--decoder-learned-pos", + action="store_true", + help="use learned positional embeddings", + ) + + add_transformer_args(parser) + SpeechWavTransformerEncoder.add_args(parser) + parser.add_argument( + "--load-pretrained-speech-text-encoder", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained speech text encoder from SpeechTextPreTrainModel """, + ) + parser.add_argument( + "--load-pretrained-wav2vec-encoder", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained speech text encoder from wav2vec """, + ) + + parser.add_argument( + "--load-pretrained-speech-text-decoder", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained speech text decoder from SpeechTextPreTrainModel """, + ) + parser.add_argument( + "--load-pretrained-text-decoder", + type=str, + default="", + metavar="EXPR", + help=""" path to the pretrained text decoder """, + ) + parser.add_argument( + "--load-init-encoder", + type=str, + default="", + metavar="EXPR", + help=""" path to load seed encoder model """, + ) + parser.add_argument( + "--load-init-decoder", + type=str, + default="", + metavar="EXPR", + help=""" path to load seed decoder model """, + ) + + parser.add_argument( + "--text-input-cost-ratio", + type=float, + default=1.0, + metavar="V", + help="text input cost ratio relative to speech input cost", + ) + parser.add_argument( + "--enc-grad-mult", + type=float, + metavar="V", + default=1.0, + help="multiply enc1 and enc2 gradient by V", + ) + parser.add_argument( + "--enc2-along-grad-mult", + type=float, + metavar="V", + default=1.0, + help="multiply enc2 gradient by V if only enc2 is used", + ) + parser.add_argument( + "--no-strict-check-pretrain-model", + action="store_true", + help="Don't apply strict model check for the pretrained model", + ) + + parser.add_argument( + "--stacked-encoder", + action="store_true", + help="stack speech and text encoders", + ) + + @classmethod + def update_transformer_encoder_cfg(cls, args, update_dict): + cfg = dict(args._get_kwargs()) + for fkey in update_dict.keys(): + cfg[fkey] = update_dict[fkey] + cfg.pop("_name", None) # remove keys start with _ + model_args = namedtuple("args", cfg.keys())(*cfg.values()) + return model_args + + @classmethod + def build_text_encoder(cls, args, src_dictionary): + enc_emb = nn.Embedding( + len(src_dictionary), args.encoder_embed_dim, src_dictionary.pad() + ) + model_args = cls.update_transformer_encoder_cfg( + args, + { + "encoder_layers": args.text_encoder_layers, + "max_source_positions": args.max_positions_text, + }, + ) + text_encoder = TransformerEncoder(model_args, src_dictionary, enc_emb) + return text_encoder + + @classmethod + def build_speech_encoder(cls, args): + model_args = cls.update_transformer_encoder_cfg( + args, {"encoder_layers": args.speech_encoder_layers} + ) + speech_encoder = SpeechWavTransformerEncoder(model_args) + return speech_encoder + + @classmethod + def check_args(cls, condition, is_strict, msg): + if condition: + return + if is_strict: + raise ValueError(msg) + logger.warn(msg) + + @classmethod + def build_encoder(cls, args, task): + # text_encoder = cls.build_text_encoder(args, task.source_dictionary ) + text_encoder = cls.build_text_encoder(args, task.src_dict) + speech_encoder = cls.build_speech_encoder(args) + if args.load_pretrained_wav2vec_encoder: + component_pairs = ( + ("feature_extractor", speech_encoder.subsample), + ("post_extract_proj", speech_encoder.feat_proj), + ("layer_norm", speech_encoder.feat_layer_norm), + ("encoder.pos_conv", speech_encoder.embed_positions), + ("encoder.layers", speech_encoder.layers), + ("encoder.layer_norm", speech_encoder.layer_norm), + ("mask_emb", speech_encoder.mask_emb), + ) + state = cls.load_pretrained_speech_text_components( + args.load_pretrained_wav2vec_encoder, component_pairs + ) + cls.check_args( + args.encoder_normalize_before + == state["cfg"]["model"]["layer_norm_first"], + not args.no_strict_check_pretrain_model, + f"encoder_normalize_before {args.encoder_normalize_before} doesn't match with the pretrained model", + ) + cls.check_args( + args.activation_fn == state["cfg"]["model"]["activation_fn"], + not args.no_strict_check_pretrain_model, + f"activation_fn {args.activation_fn} doesn't match with the pretrained model", + ) + + if getattr(args, "stacked_encoder", False): + if args.encoder_shared_text_layers_from_begin > 0: + raise ValueError( + "We can not stack encoders and share encoders at the same time!" + ) + speech_encoder = StackedSpeechWavTransformerEncoder( + speech_encoder, text_encoder.layers, text_encoder.layer_norm + ) + else: + cls.share_speech_text_encoder( + speech_encoder, text_encoder, args.encoder_shared_text_layers_from_begin + ) + + cross_attentive_loss_before_last_layer = ( + 0 if getattr(args, "attentive_cost_regularization", 0.0) > 0.0 else -1 + ) + encoder = DualInputEncoder( + args, + speech_encoder, + text_encoder, + task.src_dict, + cross_attentive_loss_before_last_layer, + ) + if args.load_pretrained_speech_text_encoder: + component_pairs = ( + ("encoder.sup_s2s_speech_encoder", encoder.spch_encoder), + ("encoder.text_encoder", encoder.text_encoder), + ) + cls.load_pretrained_speech_text_components( + args.load_pretrained_speech_text_encoder, component_pairs + ) + if getattr(args, "load_init_encoder", "") != "": + checkpoint_utils.load_pretrained_component_from_model( + encoder, args.load_init_encoder + ) + return encoder + + @classmethod + def build_text_decoder(cls, args, tgt_dictionary, dec_emb_share=None): + dec_emb = ( + nn.Embedding( + len(tgt_dictionary), args.decoder_embed_dim, tgt_dictionary.pad() + ) + if dec_emb_share is None + else dec_emb_share + ) + text_decoder = TransformerDecoder(args, tgt_dictionary, dec_emb) + return text_decoder + + @classmethod + def build_decoder(cls, args, task): + text_decoder = cls.build_text_decoder(args, task.target_dictionary) + compute_cross_attentive_loss = ( + True if getattr(args, "attentive_cost_regularization", 0.0) > 0.0 else False + ) + cross_attentive_loss_without_norm = getattr( + args, "attentive_cost_without_normalize", False + ) + cross_attentive_loss_reverse = ( + False # getattr(args, "attentive_cost_reverse", False) + ) + if getattr(args, "load_pretrained_text_decoder", "") != "": + checkpoint_utils.load_pretrained_component_from_model( + text_decoder, args.load_pretrained_text_decoder + ) + + if args.load_pretrained_speech_text_decoder: + component_pairs = (("decoder.text_decoder", text_decoder),) + cls.load_pretrained_speech_text_components( + args.load_pretrained_speech_text_decoder, component_pairs + ) + + decoder = TransformerMultiInputDecoder( + dictionary=task.target_dictionary, + spch_decoder=text_decoder, + text_decoder=text_decoder, + compute_cross_attentive_loss=compute_cross_attentive_loss, + cross_attentive_loss_with_norm=True + if not cross_attentive_loss_without_norm + else False, + cross_attentive_loss_reverse=cross_attentive_loss_reverse, + ) + if getattr(args, "load_init_decoder", "") != "": + checkpoint_utils.load_pretrained_component_from_model( + decoder, args.load_init_decoder + ) + return decoder + + @classmethod + def load_pretrained_speech_text_components(cls, checkpoint, component_pairs): + if not PathManager.exists(checkpoint): + raise IOError("Model file not found: {}".format(checkpoint)) + state = load_checkpoint_to_cpu(checkpoint) + for component_type, component in component_pairs: + if isinstance(component, nn.parameter.Parameter): + component.data.copy_(state["model"][component_type]) + else: + component_state_dict = OrderedDict() + for key in state["model"].keys(): + if key.startswith(component_type): + component_subkey = key[len(component_type) + 1 :] + component_state_dict[component_subkey] = state["model"][key] + component.load_state_dict(component_state_dict, strict=True) + return state + + @classmethod + def share_speech_text_encoder( + cls, speech_encoder, text_encoder, shared_layers_from_begin + ): + if shared_layers_from_begin > 0: + num_text_encoder_layers = len(text_encoder.layers) + assert len(speech_encoder.layers) >= shared_layers_from_begin + assert num_text_encoder_layers >= shared_layers_from_begin + assert len(speech_encoder.layers) >= num_text_encoder_layers + for i, ly in enumerate( + speech_encoder.layers[ + -num_text_encoder_layers : -num_text_encoder_layers + + shared_layers_from_begin + ] + ): + assert isinstance(text_encoder.layers[i], type(ly)) + text_encoder.layers[i] = ly + + +@register_model_architecture( + "dual_input_wav_transformer", "dualinputs2twavtransformer_base" +) +def dualinputs2twavtransformer_base(args): + # speech masking + args.dropout_input = getattr(args, "dropout_input", 0) + args.dropout_features = getattr(args, "dropout_features", 0) + args.speech_mask_length = getattr(args, "speech_mask_length", 10) + args.speech_mask_prob = getattr(args, "speech_mask_prob", 0.65) + args.speech_mask_selection = getattr(args, "speech_mask_selection", "static") + args.speech_mask_other = getattr(args, "speech_mask_other", 0) + args.speech_mask_min_space = getattr(args, "speech_mask_min_space", 1) + args.speech_no_mask_overlap = getattr(args, "speech_no_mask_overlap", False) + args.speech_conv_bias = getattr(args, "speech_conv_bias", False) + args.speech_extractor_mode = getattr(args, "speech_extractor_mode", "default") + args.no_strict_check_pretrain_model = getattr( + args, "no_strict_check_pretrain_model", False + ) + + args.speech_mask_channel_length = getattr(args, "speech_mask_channel_length", 10) + args.speech_mask_channel_prob = getattr(args, "speech_mask_channel_prob", 0.0) + args.speech_mask_channel_selection = getattr( + args, "speech_mask_channel_selection", "static" + ) + args.speech_mask_channel_other = getattr(args, "speech_mask_channel_other", 0) + args.speech_mask_channel_min_space = getattr( + args, "speech_mask_channel_min_space", 1 + ) + args.speech_no_mask_channel_overlap = getattr( + args, "speech_no_mask_channel_overlap", False + ) + args.no_scale_feature = getattr(args, "", False) + args.feature_grad_mult = getattr(args, "feature_grad_mult", 0.0) # 0.1 + + # Transformer + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 768) + args.encoder_ffn_embed_dim = getattr( + args, "encoder_ffn_embed_dim", args.encoder_embed_dim * 4 + ) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 12) + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) + args.encoder_layerdrop = getattr(args, "encoder_layerdrop", 0.1) + args.encoder_learned_pos = getattr(args, "encoder_learned_pos", False) + + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) + args.decoder_ffn_embed_dim = getattr( + args, "decoder_ffn_embed_dim", args.encoder_ffn_embed_dim + ) + args.decoder_attention_heads = getattr( + args, "decoder_attention_heads", args.encoder_attention_heads + ) + args.decoder_normalize_before = getattr(args, "decoder_normalize_before", False) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", 0) + args.activation_dropout = getattr(args, "activation_dropout", args.dropout) + args.activation_fn = getattr(args, "activation_fn", "relu") # gelu? + args.adaptive_softmax_cutoff = getattr(args, "adaptive_softmax_cutoff", None) + args.adaptive_softmax_dropout = getattr(args, "adaptive_softmax_dropout", 0) + args.tie_adaptive_weights = getattr(args, "tie_adaptive_weights", False) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + args.adaptive_input = getattr(args, "adaptive_input", False) + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0.0) + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.layernorm_embedding = getattr(args, "layernorm_embedding", False) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 12) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.encoder_shared_text_layers_from_begin = getattr( + args, "encoder_shared_text_layers_from_begin", 6 + ) + args.decoder_layers = getattr(args, "decoder_layers", 6) + + +@register_model_architecture( + "dual_input_wav_transformer", "dualinputs2twavtransformer_base_stack" +) +def dualinputs2twavtransformer_base_stack(args): + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 6) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 6) + args.encoder_shared_text_layers_from_begin = getattr( + args, "encoder_shared_text_layers_from_begin", 0 + ) + args.decoder_layers = getattr(args, "decoder_layers", 6) + args.stacked_encoder = getattr(args, "stacked_encoder", True) + args.layernorm_embedding = getattr(args, "layernorm_embedding", True) + dualinputs2twavtransformer_base(args) + + +@register_model_architecture( + "dual_input_wav_transformer", "dualinputs2twavtransformer_large" +) +def dualinputs2twavtransformer_large(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + args.speech_encoder_layers = getattr(args, "speech_encoder_layers", 24) + args.text_encoder_layers = getattr(args, "text_encoder_layers", 12) + args.encoder_shared_text_layers_from_begin = getattr( + args, "encoder_shared_text_layers_from_begin", 12 + ) + args.decoder_layers = getattr(args, "decoder_layers", 12) + dualinputs2twavtransformer_base(args) diff --git a/examples/speech_text_joint_to_text/scripts/convert_model.py b/examples/speech_text_joint_to_text/scripts/convert_model.py new file mode 100644 index 0000000000..4923af1312 --- /dev/null +++ b/examples/speech_text_joint_to_text/scripts/convert_model.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import re +from collections import OrderedDict + +import torch + +from fairseq.file_io import PathManager + + +def is_update(param_name, module_name): + if module_name in param_name: + return True + return False + + +def load_checkpoint(src_cpt): + + with PathManager.open(src_cpt, "rb") as f: + state_src = torch.load( + f, + map_location=( + lambda s, _: torch.serialization.default_restore_location(s, "cpu") + ), + ) + + return state_src + + +def save_checkpoint(tgt_cpt, states): + + with PathManager.open(tgt_cpt, "wb") as f: + torch.save( + states, + f, + ) + + +# convert the pre-trained model into bart model +def main(): + parser = argparse.ArgumentParser() + # fmt: off + parser.add_argument('--input-model', required=True, + help='Input checkpoint file path.') + parser.add_argument('--output-model', required=True, + help='output checkpoint file path.') + # fmt: on + args = parser.parse_args() + print(args) + + states = load_checkpoint(args.input_model) + model = states["model"] + new_model = OrderedDict() + for key in model.keys(): + if re.search("^encoder.text_encoder", key): + new_key = re.sub("encoder.text_encoder", "encoder", key) + new_model[new_key] = model[key] + elif re.search("^decoder.text_decoder", key): + new_key = re.sub("decoder.text_decoder", "decoder", key) + new_model[new_key] = model[key] + states["model"] = new_model + save_checkpoint(args.output_model, states) + + +if __name__ == "__main__": + main() diff --git a/examples/speech_text_joint_to_text/tasks/pair_denoising.py b/examples/speech_text_joint_to_text/tasks/pair_denoising.py new file mode 100644 index 0000000000..b13b1e5ae3 --- /dev/null +++ b/examples/speech_text_joint_to_text/tasks/pair_denoising.py @@ -0,0 +1,447 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import itertools +import logging +import os +import re + +import numpy as np +import torch + +from examples.speech_text_joint_to_text.data.pair_denoising_dataset import ( + LanguagePairDenoisingDataset, +) +from fairseq import utils +from fairseq.data import ( + ConcatDataset, + Dictionary, + LanguagePairDataset, + ResamplingDataset, + TransformEosConcatLangPairDataset, + TransformEosLangPairDataset, + data_utils, + indexed_dataset, +) +from fairseq.data.encoders.utils import get_whole_word_mask +from fairseq.tasks import register_task +from fairseq.tasks.translation import TranslationTask + +logger = logging.getLogger(__name__) + + +def gen_whole_word_mask(args, dictionary): + def is_beginning_of_word(i): + if i < dictionary.nspecial: + # special elements are always considered beginnings + return True + tok = dictionary[i] + if tok.startswith("madeupword"): + return True + + if tok in ["<unk>", "<s>", "</s>", "<pad>"]: + return True + return tok.startswith("\u2581") + + if args.use_mask_whole_words: + mask_whole_words = torch.ByteTensor( + list(map(is_beginning_of_word, range(len(dictionary)))) + ) + else: + # it will mask every token as word leading token, since no bpe model is loaded for phoneme tokens + return get_whole_word_mask(args, dictionary) + return mask_whole_words + + +@register_task("paired_denoising") +class PairedDenoisingTask(TranslationTask): + + LANG_TAG_TEMPLATE = "<lang:{}>" # Tag for language (target) + + @staticmethod + def add_args(parser): + TranslationTask.add_args(parser) + # bart setting + parser.add_argument( + "--mask", + default=0.0, + type=float, + help="fraction of words/subwords that will be masked", + ) + parser.add_argument( + "--mask-random", + default=0.0, + type=float, + help="instead of using [MASK], use random token this often", + ) + parser.add_argument( + "--insert", + default=0.0, + type=float, + help="insert this percentage of additional random tokens", + ) + parser.add_argument( + "--poisson-lambda", + default=3.0, + type=float, + help="randomly shuffle sentences for this proportion of inputs", + ) + parser.add_argument( + "--mask-length", + default="span-poisson", + type=str, + choices=["subword", "word", "span-poisson"], + help="mask length to choose", + ) + parser.add_argument( + "--replace-length", + default=1, + type=int, + help="when masking N tokens, replace with 0, 1, or N tokens (use -1 for N)", + ) + + # multi-lingual + parser.add_argument( + "--multilang-sampling-alpha", + type=float, + default=1.0, + help="smoothing alpha for sample ratios across multiple datasets", + ) + parser.add_argument( + "--lang-pairs", + default="", + metavar="PAIRS", + help="comma-separated list of language pairs (in training order): phnen-en,phnfr-fr,phnit-it. Do masking", + ) + parser.add_argument( + "--lang-pairs-bitext", + default="", + metavar="PAIRS", + help="comma-separated list of language pairs (in training order): en-de,en-fr,de-fr. No masking", + ) + parser.add_argument("--add-src-lang-token", default=False, action="store_true") + parser.add_argument("--add-tgt-lang-token", default=False, action="store_true") + parser.add_argument( + "--no-whole-word-mask-langs", + type=str, + default="", + metavar="N", + help="languages without spacing between words dont support whole word masking", + ) + parser.add_argument( + "--use-mask-whole-words", default=False, action="store_true" + ) + + @classmethod + def setup_task(cls, args, **kwargs): + """Setup the task.""" + paths = args.data.split(":") + assert len(paths) > 0 + src_dict = Dictionary.load( + os.path.join(paths[0], "src_dict.txt") + ) # assume all languages share a source dictionary + tgt_dict = Dictionary.load( + os.path.join(paths[0], "tgt_dict.txt") + ) # assume all languages share a target dictionary + + lang_pairs = args.lang_pairs + "," + args.lang_pairs_bitext + lang_pairs = re.sub(",$", "", re.sub("^,", "", lang_pairs)) + src_langs = [lp.split("-")[0] for lp in lang_pairs.split(",")] + tgt_langs = [lp.split("-")[1] for lp in lang_pairs.split(",")] + + if args.add_src_lang_token: + for lang in src_langs: + assert ( + src_dict.index(PairedDenoisingTask.LANG_TAG_TEMPLATE.format(lang)) + != src_dict.unk() + ) + if args.add_tgt_lang_token: + for lang in tgt_langs: + assert ( + tgt_dict.index(PairedDenoisingTask.LANG_TAG_TEMPLATE.format(lang)) + != tgt_dict.unk() + ) + + logger.info("source dictionary: {} types".format(len(src_dict))) + logger.info("target dictionary: {} types".format(len(tgt_dict))) + if not hasattr(args, "shuffle_instance"): + args.shuffle_instance = False + return cls(args, src_dict, tgt_dict) + + def __init__(self, args, src_dict, tgt_dict): + super().__init__(args, src_dict, tgt_dict) + # check mask token + self.mask_idx = self.src_dict.index("<mask>") + assert self.mask_idx != self.src_dict.unk() + self.lang_pairs = args.lang_pairs + self.lang_pairs_bitext = args.lang_pairs_bitext + self.args = args + + @classmethod + def language_pair_denoising_dataset( + cls, + data_path, + do_mask, + split, + src, + src_dict, + tgt, + tgt_dict, + mask_idx, + mask_whole_words, + seed, + args, + dataset_impl, + combine=False, + left_pad_source=True, + left_pad_target=False, + max_source_positions=1024, + max_target_positions=1024, + shuffle=True, + src_lang_id=None, + tgt_lang_id=None, + ): + def split_exists(split, src, tgt, lang, data_path): + filename = os.path.join( + data_path, "{}.{}-{}.{}".format(split, src, tgt, lang) + ) + return indexed_dataset.dataset_exists(filename, impl=dataset_impl) + + src_datasets = [] + tgt_datasets = [] + + for k in itertools.count(): + split_k = split + (str(k) if k > 0 else "") + + # infer langcode + if split_exists(split_k, src, tgt, src, data_path): + prefix = os.path.join(data_path, "{}.{}-{}.".format(split_k, src, tgt)) + elif split_exists(split_k, tgt, src, src, data_path): + prefix = os.path.join(data_path, "{}.{}-{}.".format(split_k, tgt, src)) + else: + if k > 0: + break + else: + raise FileNotFoundError( + "Dataset not found: {} ({})".format(split, data_path) + ) + + src_dataset = data_utils.load_indexed_dataset( + prefix + src, src_dict, dataset_impl + ) + src_datasets.append(src_dataset) + + tgt_dataset = data_utils.load_indexed_dataset( + prefix + tgt, tgt_dict, dataset_impl + ) + if tgt_dataset is not None: + tgt_datasets.append(tgt_dataset) + + logger.info( + "{} {} {}-{} {} examples".format( + data_path, split_k, src, tgt, len(src_datasets[-1]) + ) + ) + + if not combine: + break + + assert len(src_datasets) == len(tgt_datasets) or len(tgt_datasets) == 0 + + if len(src_datasets) == 1: + src_dataset = src_datasets[0] + tgt_dataset = tgt_datasets[0] if len(tgt_datasets) > 0 else None + else: + sample_ratios = [1] * len(src_datasets) + src_dataset = ConcatDataset(src_datasets, sample_ratios) + if len(tgt_datasets) > 0: + tgt_dataset = ConcatDataset(tgt_datasets, sample_ratios) + else: + tgt_dataset = None + + eos = None + + tgt_dataset_sizes = tgt_dataset.sizes if tgt_dataset is not None else None + if not do_mask: + return LanguagePairDataset( + src_dataset, + src_dataset.sizes, + src_dict, + tgt_dataset, + tgt_dataset_sizes, + tgt_dict, + left_pad_source=left_pad_source, + left_pad_target=left_pad_target, + eos=eos, + shuffle=shuffle, + src_lang_id=src_lang_id, + tgt_lang_id=tgt_lang_id, + ) + + return LanguagePairDenoisingDataset( + src_dataset, + src_dataset.sizes, + src_dict, + tgt_dataset, + tgt_dataset_sizes, + tgt_dict, + mask_idx, + mask_whole_words, + seed, + args, + left_pad_source=left_pad_source, + left_pad_target=left_pad_target, + eos=eos, + shuffle=shuffle, + src_lang_id=src_lang_id, + tgt_lang_id=tgt_lang_id, + ) + + def _get_sample_prob(self, dataset_lens): + """ + Get smoothed sampling porbability by languages. This helps low resource + languages by upsampling them. + """ + prob = dataset_lens / dataset_lens.sum() + smoothed_prob = prob ** self.args.multilang_sampling_alpha + smoothed_prob = smoothed_prob / smoothed_prob.sum() + return smoothed_prob + + def resample_datasets(self, lang_datasets, lang_pairs_all, epoch): + # For train subset, additionally up or down sample languages. + if self.args.multilang_sampling_alpha == 1.0: + return lang_datasets + + dataset_lengths = np.array( + [len(d) for d in lang_datasets], + dtype=float, + ) + sample_probs = self._get_sample_prob(dataset_lengths) + logger.info( + "Sample probability by language pair: {}".format( + { + lp: "{0:.4f}".format(sample_probs[id]) + for id, lp in enumerate(lang_pairs_all) + } + ) + ) + size_ratio = (sample_probs * dataset_lengths.sum()) / dataset_lengths + logger.info( + "Up/Down Sampling ratio by language: {}".format( + { + lp: "{0:.2f}".format(size_ratio[id]) + for id, lp in enumerate(lang_pairs_all) + } + ) + ) + + resampled_lang_datasets = [ + ResamplingDataset( + lang_datasets[i], + size_ratio=size_ratio[i], + seed=self.args.seed, + epoch=epoch, + replace=size_ratio[i] >= 1.0, + ) + for i, d in enumerate(lang_datasets) + ] + return resampled_lang_datasets + + def load_dataset_only( + self, split, lang_pairs, do_mask=True, epoch=1, combine=False + ): + paths = utils.split_paths(self.args.data) + assert len(paths) > 0 + data_path = paths[(epoch - 1) % len(paths)] + + # TODO unk token will be considered as first word too, though it might be an unknown phoneme within a word + # get_whole_word_mask returns a tensor (size V by 1 ) to indicate if a token is a word start token + mask_whole_src_words = gen_whole_word_mask(self.args, self.src_dict) + language_without_segmentations = self.args.no_whole_word_mask_langs.split(",") + lang_datasets = [] + eos_bos = [] + lang_pairs = lang_pairs.split(",") if lang_pairs != "" else [] + assert len(lang_pairs) > 0 + for lp in lang_pairs: + src, tgt = lp.split("-") + lang_mask_whole_src_words = ( + mask_whole_src_words + if src not in language_without_segmentations + else None + ) + + end_token = ( + self.source_dictionary.index( + PairedDenoisingTask.LANG_TAG_TEMPLATE.format(src) + ) + if self.args.add_src_lang_token + else None + ) + bos_token = ( + self.target_dictionary.index( + PairedDenoisingTask.LANG_TAG_TEMPLATE.format(tgt) + ) + if self.args.add_tgt_lang_token + else None + ) + src_lang_id = None + + if self.args.add_src_lang_token or self.args.add_tgt_lang_token: + eos_bos.append((end_token, bos_token)) + + dataset = PairedDenoisingTask.language_pair_denoising_dataset( + data_path, + do_mask, + split, + src, + self.source_dictionary, + tgt, + self.target_dictionary, + self.mask_idx, + lang_mask_whole_src_words, + self.args.seed, + self.args, + self.args.dataset_impl, + combine=combine, + left_pad_source=utils.eval_bool(self.args.left_pad_source), + left_pad_target=utils.eval_bool(self.args.left_pad_target), + max_source_positions=self.args.max_source_positions, + max_target_positions=self.args.max_target_positions, + src_lang_id=src_lang_id, + ) + + lang_datasets.append(dataset) + + if len(lang_datasets) == 0: + return + elif len(lang_datasets) == 1: + dataset = lang_datasets[0] + if self.args.add_src_lang_token or self.args.add_tgt_lang_token: + end_token, bos_token = eos_bos[0] + dataset = TransformEosLangPairDataset( + dataset, + src_eos=self.source_dictionary.eos(), + new_src_eos=end_token, + tgt_bos=self.target_dictionary.eos(), + new_tgt_bos=bos_token, + ) + else: + end_tokens = [item[0] for item in eos_bos if item[0] is not None] + bos_tokens = [item[1] for item in eos_bos if item[1] is not None] + lang_datasets = self.resample_datasets(lang_datasets, lang_pairs, epoch) + dataset = TransformEosConcatLangPairDataset( + lang_datasets, + self.source_dictionary.eos(), + self.target_dictionary.eos(), + new_src_eos=end_tokens, + new_tgt_bos=bos_tokens, + ) + return dataset + + # split in (train, valid, test, ...) + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + self.datasets[split] = self.load_dataset_only( + split, self.lang_pairs, epoch=epoch, combine=combine + ) diff --git a/examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py b/examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py new file mode 100644 index 0000000000..f592633c08 --- /dev/null +++ b/examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py @@ -0,0 +1,654 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import logging +import os +import re +from argparse import Namespace +from pathlib import Path + +from fairseq.data import ConcatDataset, Dictionary, encoders +from fairseq.data.audio.multi_modality_dataset import ( + FileAudioDatasetWrapper, + ModalityDatasetItem, + MultiModalityDataset, +) +from fairseq.data.audio.speech_to_text_joint_dataset import ( + S2TJointDataConfig, + SpeechToTextJointDatasetCreator, +) +from fairseq.data.iterators import GroupedEpochBatchIterator +from fairseq.tasks import register_task + +from .pair_denoising import PairedDenoisingTask + +logger = logging.getLogger(__name__) + + +@register_task("speech_text_joint_denoising") +class SpeechTextJointDenoisingPreTask(PairedDenoisingTask): + """ + Joint denoising training task for speech and text. + """ + + SIL_TOKEN = "sil" + + @classmethod + def add_args(cls, parser): + PairedDenoisingTask.add_args(parser) + # set max tokens and position + parser.add_argument( + "--max-text-tokens", + type=int, + metavar="N", + default=1024, + help="maximum samples for encoder text input ", + ) + parser.add_argument( + "--max-speech-tokens", + type=int, + metavar="N", + default=50000, + help="maximum samples for encoder speech input ", + ) + parser.add_argument( + "--max-speech-positions", + type=int, + metavar="N", + default=400, + help="maximum tokens for per encoder text input ", + ) + + parser.add_argument( + "--max-sample-size", + type=int, + metavar="N", + default=32000, + help="max sample size to crop to for batching (unsupervised speech) ", + ) + parser.add_argument( + "--min-sample-size", + type=int, + metavar="N", + default=4000, + help="min sample size to crop to for batching (unsupervised speech) ", + ) + + # set mini-batch ratio for different modalities/subtasks + # s2p + parser.add_argument( + "--supervised-speech-sample-ratio", + default="1", + type=str, + metavar="N", + help="Multiple Ratio for speech dataset with transcripts ", + ) + # s2t + parser.add_argument( + "--supervised-speech-s2s-sample-ratio", + default="1", + type=str, + metavar="N", + help="Multiple Ratio for speech dataset with transcripts ", + ) + # ssl + parser.add_argument( + "--unsupervised-speech-sample-ratio", + default="1", + type=str, + metavar="N", + help="Multiple Ratio for speech dataset without transcripts ", + ) + # t2t with monolingual data (masking) + parser.add_argument( + "--text-sample-ratio", + default="1", + type=str, + metavar="N", + help="Multiple Ratio for text set ", + ) + # t2t with parallel data (no masking) + parser.add_argument( + "--bitext-sample-ratio", + default="1", + type=str, + metavar="N", + help="Multiple Ratio for text set (bitext) ", + ) + # train_subset = "train", 'valid' or so + # parallel data is loaded according to string lang_pairs and lang_pairs_no_mask from args.data + # (un)supervised speech is loaded from args.(un)sup_speech_{train,valid}_subset + parser.add_argument( + "--sup-speech-data", default="", help="path to supervised speech data" + ) + parser.add_argument( + "--sup-speech-train-subset", + default="", + help="supervised speech training subsets", + ) + parser.add_argument( + "--sup-speech-valid-subset", + default="", + help="supervised speech validation subsets", + ) + parser.add_argument( + "--config-yaml", + default="config.yaml", + help="supervised speech configuration yaml file", + ) + parser.add_argument( + "--sup-speech-s2s-data", default="", help="path to supervised speech data" + ) + parser.add_argument( + "--sup-speech-s2s-train-subset", + default="", + help="supervised speech training subsets", + ) + parser.add_argument( + "--sup-speech-s2s-valid-subset", + default="", + help="supervised speech validation subsets", + ) + parser.add_argument( + "--config-s2s-yaml", + default="config.yaml", + help="supervised speech configuration yaml file", + ) + parser.add_argument( + "--unsup-speech-train-data", + default="", + help="path to unsupervised speech training data (tsv)", + ) + parser.add_argument( + "--unsup-speech-valid-data", + default="", + help="path to unsupervised speech valid data (tsv)", + ) + parser.add_argument( + "--sample-rate", + type=int, + metavar="N", + default=16000, + help="input audio sampling rate", + ) + parser.add_argument( + "--no-emb-update-unsup", + default=False, + action="store_true", + help="no update for output embedding during unsupervised_speech mode", + ) + parser.add_argument("--same-data-update", default=False, action="store_true") + + # used for sup_speech_ali + parser.add_argument( + "--use-sup-speech-ctc", + default=False, + action="store_true", + help="use speech_sup_ctc instead of speech_sup_ali", + ) + + @classmethod + def setup_task(cls, args, **kwargs): + """Setup the task.""" + paths = args.data.split(":") + assert len(paths) > 0 + src_dict = Dictionary.load( + os.path.join(paths[0], "src_dict.txt") + ) # assume all languages share a source dictionary + tgt_dict = Dictionary.load( + os.path.join(paths[0], "tgt_dict.txt") + ) # assume all languages share a target dictionary + + lang_pairs = args.lang_pairs + "," + args.lang_pairs_bitext + lang_pairs = re.sub(",$", "", re.sub("^,", "", lang_pairs)) + if lang_pairs != "": + src_langs = [lp.split("-")[0] for lp in lang_pairs.split(",")] + tgt_langs = [lp.split("-")[1] for lp in lang_pairs.split(",")] + else: + src_langs = [] + tgt_langs = [] + + if args.add_src_lang_token: + for lang in src_langs: + assert ( + src_dict.index(PairedDenoisingTask.LANG_TAG_TEMPLATE.format(lang)) + != src_dict.unk() + ) + if args.add_tgt_lang_token: + for lang in tgt_langs: + assert ( + tgt_dict.index(PairedDenoisingTask.LANG_TAG_TEMPLATE.format(lang)) + != tgt_dict.unk() + ) + + logger.info("source dictionary: {} types".format(len(src_dict))) + logger.info("target dictionary: {} types".format(len(tgt_dict))) + if not hasattr(args, "shuffle_instance"): + args.shuffle_instance = False + return cls(args, src_dict, tgt_dict) + + def __init__(self, args, src_dict, tgt_dict): + super().__init__(args, src_dict, tgt_dict) + self.data_cfg = S2TJointDataConfig( + Path(args.sup_speech_data) / args.config_yaml + ) + logger.info( + f"load supervised speech data configure from {Path(args.sup_speech_data) / args.config_yaml}" + ) + self.data_s2s_cfg = ( + S2TJointDataConfig(Path(args.sup_speech_s2s_data) / args.config_s2s_yaml) + if args.sup_speech_s2s_train_subset != "" + else None + ) + if self.data_s2s_cfg is not None: + logger.info( + f"load supervised sequece to sequence speech data configure from {Path(args.sup_speech_s2s_data) / args.config_yaml}" + ) + + def parse_data_ratio(sample_ratio): + ratios = sample_ratio.split(",") + if len(ratios) == 1: + return [float(ratios[0])] + epoch_ratios = [] + for item in ratios: + ep, r = item.split(":") + ep = int(ep) + r = float(r) + assert ep > 0 # epoch is 1 based + assert ep >= len(epoch_ratios) + + if len(epoch_ratios) == 0: + epoch_ratios.append( + r + ) # epoch_ratios[0] is not used, but we still set it to the first value to make thing simple. + while len(epoch_ratios) < ep: + epoch_ratios.append(epoch_ratios[-1]) + epoch_ratios.append(r) + return epoch_ratios + + self.sup_ratio = parse_data_ratio(args.supervised_speech_sample_ratio) + self.sup_s2s_ratio = parse_data_ratio(args.supervised_speech_s2s_sample_ratio) + self.text_ratio = parse_data_ratio(args.text_sample_ratio) + self.bitext_ratio = parse_data_ratio(args.bitext_sample_ratio) + self.unsup_ratio = parse_data_ratio(args.unsupervised_speech_sample_ratio) + self.sample_mode = None + + def build_model(self, args): + args.input_feat_per_channel = self.data_cfg.input_feat_per_channel + args.input_channels = self.data_cfg.input_channels + return super().build_model(args) + + def build_tokenizer(self, data_cfg, msg=""): + logger.info(f"pre-tokenizer {msg}: {data_cfg.pre_tokenizer}") + return encoders.build_tokenizer(Namespace(**data_cfg.pre_tokenizer)) + + def build_bpe(self, data_cfg, msg=""): + logger.info(f"tokenizer {msg}: {data_cfg.bpe_tokenizer}") + return encoders.build_bpe(Namespace(**data_cfg.bpe_tokenizer)) + + @classmethod + def resolve_data_type(cls, split, use_sup_speech_ctc): + if len(split.split("_")) == 1: + # default case, train or valid + is_train = split + dtype = "text" + else: + is_train, dtype = split.split("_", 1) + is_train = True if is_train == "train" else False + if dtype == "sup_speech": + dtype = "sup_speech_ctc" if use_sup_speech_ctc else "sup_speech_ali" + assert dtype in ( + "text", + "bitext", + "sup_speech_ali", + "sup_speech_s2s", + "unsup_speech", + "sup_speech_ctc", + ) + return is_train, dtype + + def create_modalitydatasetitem(self, dtype, dataset): + dsitem = None + if dtype in ("text", "bitext"): + dsitem = ModalityDatasetItem( + dtype, + dataset, + (self.args.max_source_positions, self.args.max_target_positions), + self.args.max_text_tokens, + self.args.batch_size, + ) + elif dtype in ("sup_speech_ctc", "sup_speech_ali", "sup_speech_s2s"): + dsitem = ModalityDatasetItem( + dtype, + dataset, + (self.args.max_speech_positions, self.args.max_target_positions), + self.args.max_speech_tokens, + self.args.batch_size, + ) + elif dtype == "unsup_speech": + dsitem = ModalityDatasetItem( + dtype, dataset, 1e8, self.args.max_speech_tokens, self.args.batch_size + ) + else: + raise ValueError(f"{dtype} is not supported") + return dsitem + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + def _get_sup_src_tgt_dict(src_dict, tgt_dict, use_s2s_sup_decoder): + if use_s2s_sup_decoder: + return None, tgt_dict + # use src_dict as tgt_dict here, since we use source dictionary as target for forcealignment + return None, src_dict + + is_train, dtype = self.resolve_data_type(split, self.args.use_sup_speech_ctc) + + # Note we use --add-tgt-lang-token instead of data_cfg.prepend_tgt_lang_tag_no_change to set target language tag in the text dataset + # Verify add_tgt_lang_token and prepend_tgt_lang_tag_no_change are same + + # Note we use --multilang-sampling-alpha instead of data_cfg.sampling_text_alpha to set text data sampling + if is_train: + msets = [] + # train split, load everything into one + if self.lang_pairs != "": + text_dataset = self.load_dataset_only( + "train", self.lang_pairs, epoch=epoch, combine=combine + ) + dsitem = self.create_modalitydatasetitem("text", text_dataset) + msets.append(dsitem) + if self.lang_pairs_bitext != "": # load bitext + bitext_dataset = self.load_dataset_only( + "train_bitext", + self.lang_pairs_bitext, + do_mask=False, + epoch=epoch, + combine=combine, + ) + dsitem = self.create_modalitydatasetitem("bitext", bitext_dataset) + msets.append(dsitem) + if self.args.sup_speech_train_subset != "": + pre_tokenizer = self.build_tokenizer(self.data_cfg) + bpe_tokenizer = self.build_bpe(self.data_cfg) + + append_eos = True + sup_speech_type = "sup_speech_ali" + if self.args.use_sup_speech_ctc: + # CTC mode + sup_speech_type = "sup_speech_ctc" + append_eos = False # CTC doesn't need eos in the target + + src_dict, tgt_dict = _get_sup_src_tgt_dict( + self.src_dict, self.tgt_dict, False + ) + sup_speech_dataset = SpeechToTextJointDatasetCreator.from_tsv( + self.args.sup_speech_data, + self.data_cfg, + self.args.sup_speech_train_subset, + tgt_dict=tgt_dict, + src_dict=src_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + src_pre_tokenizer=None, + src_bpe_tokenizer=None, + is_train_split=is_train, + epoch=epoch, + seed=self.args.seed, + append_eos=append_eos, + ) + dsitem = self.create_modalitydatasetitem( + sup_speech_type, sup_speech_dataset + ) + msets.append(dsitem) + + if self.args.sup_speech_s2s_train_subset != "": + pre_tokenizer = self.build_tokenizer(self.data_s2s_cfg, msg="(s2s)") + bpe_tokenizer = self.build_bpe(self.data_s2s_cfg, msg="(s2s)") + + # make sure self.data_cfg.prepend_tgt_lang_tag_no_change == self.args.add_tgt_lang_token + src_dict, tgt_dict = _get_sup_src_tgt_dict( + self.src_dict, self.tgt_dict, True + ) + sup_speech_s2s_dataset = SpeechToTextJointDatasetCreator.from_tsv( + self.args.sup_speech_s2s_data, + self.data_s2s_cfg, + self.args.sup_speech_s2s_train_subset, + tgt_dict=tgt_dict, + src_dict=src_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + src_pre_tokenizer=None, + src_bpe_tokenizer=None, + is_train_split=is_train, + epoch=epoch, + seed=self.args.seed, + ) + dsitem = self.create_modalitydatasetitem( + "sup_speech_s2s", sup_speech_s2s_dataset + ) + msets.append(dsitem) + if self.args.unsup_speech_train_data != "": + unsup_speech_dataset = FileAudioDatasetWrapper( + self.args.unsup_speech_train_data, + self.args.sample_rate, + max_sample_size=self.args.max_sample_size, + min_sample_size=self.args.min_sample_size, + normalize=False, + ) + dsitem = self.create_modalitydatasetitem( + "unsup_speech", unsup_speech_dataset + ) + msets.append(dsitem) + + pre_train_dataset = MultiModalityDataset(msets) + self.datasets[split] = pre_train_dataset + else: # validation split, load them for each type of data + if dtype == "text": + text_dataset = self.load_dataset_only( + split, self.lang_pairs, epoch=epoch, combine=combine + ) + dsitem = self.create_modalitydatasetitem("text", text_dataset) + self.datasets[split] = MultiModalityDataset([dsitem]) + elif dtype == "bitext": + bitext_dataset = self.load_dataset_only( + split, + self.lang_pairs_bitext, + do_mask=False, + epoch=epoch, + combine=combine, + ) + dsitem = self.create_modalitydatasetitem("bitext", bitext_dataset) + self.datasets[split] = MultiModalityDataset([dsitem]) + + elif dtype in ("sup_speech_ctc", "sup_speech_ali"): + assert self.args.sup_speech_valid_subset != "" + pre_tokenizer = self.build_tokenizer(self.data_cfg) + bpe_tokenizer = self.build_bpe(self.data_cfg) + append_eos = True + if dtype == "sup_speech_ctc": + # CTC mode + append_eos = False # CTC doesn't need eos + assert self.args.use_sup_speech_ctc + + datasets = [] + for split_name in self.args.sup_speech_valid_subset.split(","): + src_dict, tgt_dict = _get_sup_src_tgt_dict( + self.src_dict, self.tgt_dict, False + ) + datasets.append( + SpeechToTextJointDatasetCreator.from_tsv( + self.args.sup_speech_data, + self.data_cfg, + split_name, + tgt_dict=tgt_dict, + src_dict=src_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + src_pre_tokenizer=None, + src_bpe_tokenizer=None, + is_train_split=is_train, + epoch=epoch, + seed=self.args.seed, + append_eos=append_eos, + ) + ) + + dset = datasets[0] if len(datasets) == 1 else ConcatDataset(datasets) + dsitem = self.create_modalitydatasetitem(dtype, dset) + self.datasets[split] = MultiModalityDataset([dsitem]) + + elif dtype == "sup_speech_s2s": + assert self.args.sup_speech_s2s_valid_subset != "" + pre_tokenizer = self.build_tokenizer(self.data_s2s_cfg) + bpe_tokenizer = self.build_bpe(self.data_s2s_cfg) + datasets = [] + for split_name in self.args.sup_speech_s2s_valid_subset.split(","): + src_dict, tgt_dict = _get_sup_src_tgt_dict( + self.src_dict, self.tgt_dict, True + ) + datasets.append( + SpeechToTextJointDatasetCreator.from_tsv( + self.args.sup_speech_s2s_data, + self.data_s2s_cfg, + split_name, + tgt_dict=tgt_dict, + src_dict=src_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + src_pre_tokenizer=None, + src_bpe_tokenizer=None, + is_train_split=is_train, + epoch=epoch, + seed=self.args.seed, + ) + ) + + dset = datasets[0] if len(datasets) == 1 else ConcatDataset(datasets) + dsitem = self.create_modalitydatasetitem("sup_speech_s2s", dset) + self.datasets[split] = MultiModalityDataset([dsitem]) + elif dtype == "unsup_speech": + assert self.args.unsup_speech_valid_data != "" + unsup_speech_dataset = FileAudioDatasetWrapper( + self.args.unsup_speech_valid_data, + self.args.sample_rate, + max_sample_size=self.args.max_sample_size, + min_sample_size=self.args.min_sample_size, + normalize=False, + ) + dsitem = self.create_modalitydatasetitem( + "unsup_speech", unsup_speech_dataset + ) + self.datasets[split] = MultiModalityDataset([dsitem]) + else: + raise ValueError(f"Unsupported type {dtype}") + + def get_sample_ratio(self, epoch): + sup_ratio = ( + self.sup_ratio[epoch] if len(self.sup_ratio) > epoch else self.sup_ratio[-1] + ) + sup_s2s_ratio = ( + self.sup_s2s_ratio[epoch] + if len(self.sup_s2s_ratio) > epoch + else self.sup_s2s_ratio[-1] + ) + unsup_ratio = ( + self.unsup_ratio[epoch] + if len(self.unsup_ratio) > epoch + else self.unsup_ratio[-1] + ) + text_ratio = ( + self.text_ratio[epoch] + if len(self.text_ratio) > epoch + else self.text_ratio[-1] + ) + bitext_ratio = ( + self.bitext_ratio[epoch] + if len(self.bitext_ratio) > epoch + else self.bitext_ratio[-1] + ) + return text_ratio, bitext_ratio, sup_ratio, sup_s2s_ratio, unsup_ratio + + def get_batch_iterator( + self, + dataset, + max_tokens=None, + max_sentences=None, + max_positions=None, + ignore_invalid_inputs=False, + required_batch_size_multiple=1, + seed=1, + num_shards=1, + shard_id=0, + num_workers=0, + epoch=0, + data_buffer_size=0, + disable_iterator_cache=False, + skip_remainder_batch=False, + grouped_shuffling=False, + update_epoch_batch_itr=False, + ): + + assert isinstance(dataset, MultiModalityDataset) + if len(dataset.id_to_mode) == 1: + max_positions = dataset.max_positions[0] + max_tokens = dataset.max_tokens[0] + max_sentences = dataset.max_sentences[0] + return super().get_batch_iterator( + dataset, + max_tokens, + max_sentences, + max_positions, + ignore_invalid_inputs, + required_batch_size_multiple, + seed, + num_shards, + shard_id, + num_workers, + epoch, + data_buffer_size, + disable_iterator_cache, + skip_remainder_batch=skip_remainder_batch, + ) + + mult_ratio = [] + ( + text_ratio, + bitext_ratio, + sup_ratio, + sup_s2s_ratio, + unsup_ratio, + ) = self.get_sample_ratio(epoch) + for mode in dataset.id_to_mode: + if mode in ("sup_speech_ctc", "sup_speech_ali"): + mult_ratio.append(sup_ratio) + elif mode == "sup_speech_s2s": + mult_ratio.append(sup_s2s_ratio) + elif mode == "text": + mult_ratio.append(text_ratio) + elif mode == "bitext": + mult_ratio.append(bitext_ratio) + elif mode == "unsup_speech": + mult_ratio.append(unsup_ratio) + + # initialize the dataset with the correct starting epoch + dataset.set_epoch(epoch) + + batch_samplers = dataset.get_batch_samplers( + mult_ratio, required_batch_size_multiple, seed + ) + + # return a reusable, sharded iterator + epoch_iter = GroupedEpochBatchIterator( + dataset=dataset, + collate_fn=dataset.collater, + batch_samplers=batch_samplers, + seed=seed, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + epoch=epoch, + mult_rate=max(self.args.update_freq) if self.args.same_data_update else 1, + buffer_size=data_buffer_size, + skip_remainder_batch=skip_remainder_batch, + ) + self.dataset_to_epoch_iter[dataset] = {} # refresh it every epoch + return epoch_iter diff --git a/fairseq/data/audio/multi_modality_dataset.py b/fairseq/data/audio/multi_modality_dataset.py index 625a16ec94..39551a613b 100644 --- a/fairseq/data/audio/multi_modality_dataset.py +++ b/fairseq/data/audio/multi_modality_dataset.py @@ -200,6 +200,8 @@ def sizes(self): return self.dataset.sizes def get_batch_shapes(self): + if hasattr(self.dataset, "get_batch_shapes"): + return self.dataset.get_batch_shapes() return self.dataset.buckets def num_tokens_vec(self, indices): diff --git a/fairseq/data/audio/speech_to_text_joint_dataset.py b/fairseq/data/audio/speech_to_text_joint_dataset.py index 505ee81f3b..06922ea083 100644 --- a/fairseq/data/audio/speech_to_text_joint_dataset.py +++ b/fairseq/data/audio/speech_to_text_joint_dataset.py @@ -5,22 +5,18 @@ import logging from pathlib import Path -from typing import Dict, List, Optional, NamedTuple +from typing import Dict, List, NamedTuple, Optional import torch -from fairseq.data import ( - ConcatDataset, - Dictionary, - ResamplingDataset, - data_utils as fairseq_data_utils, -) + +from fairseq.data import ConcatDataset, Dictionary, ResamplingDataset +from fairseq.data import data_utils as fairseq_data_utils from fairseq.data.audio.speech_to_text_dataset import ( - SpeechToTextDataset, S2TDataConfig, + SpeechToTextDataset, SpeechToTextDatasetCreator, ) - logger = logging.getLogger(__name__) @@ -52,8 +48,12 @@ def src_bpe_tokenizer(self) -> Dict: def prepend_tgt_lang_tag_no_change(self) -> bool: """Prepend target lang ID token as the prev_output_tokens BOS (e.g. for to-many multilingual setting). No change needed during inference. + This option is deprecated and replaced by prepend_tgt_lang_tag_as_bos. """ - return self.config.get("prepend_tgt_lang_tag_no_change", False) + value = self.config.get("prepend_tgt_lang_tag_no_change", None) + if value is None: + return self.config.get("prepend_tgt_lang_tag_as_bos", False) + return value @property def sampling_text_alpha(self): diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index e5d2ede313..f49c88e563 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -5,6 +5,8 @@ from .berard import * # noqa from .convtransformer import * # noqa +from .multi_modality_model import * # noqa from .s2t_transformer import * # noqa +from .s2t_wav_transformer import * # noqa from .xm_transformer import * # noqa from .s2t_conformer import * # noqa diff --git a/fairseq/models/speech_to_text/multi_modality_model.py b/fairseq/models/speech_to_text/multi_modality_model.py new file mode 100644 index 0000000000..046421620a --- /dev/null +++ b/fairseq/models/speech_to_text/multi_modality_model.py @@ -0,0 +1,49 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from fairseq.models import FairseqDecoder, FairseqEncoder + + +# a container for different encoders with training samples from different modality +# each time, only one encoder is selected +class MultiModalityEncoder(FairseqEncoder): + def __init__(self, dictionary): + super().__init__(dictionary) + + def select_encoder(self, mode, **kwargs): + raise NotImplementedError("Model must implement the select_encoder method") + return None, kwargs + + # def post_encoder(self, encoder_out, src_tokens, src_lengths, mode, **kwargs): + # # Default do nothing + # return encoder_out + + # get sample data from JointSpeechTextDataset + def forward(self, src_tokens, src_lengths=None, mode="", **kwargs): + encoder, kwargs = self.select_encoder(mode, **kwargs) + # return self.post_encoder(encoder(src_tokens, src_lengths, **kwargs), src_tokens, src_lengths, mode, **kwargs) + return encoder(src_tokens, src_lengths, **kwargs) + + +# a container for different decoders with training samples from different modality +# each time, only one decoder is selected +class MultiInputDecoder(FairseqDecoder): + def __init__(self, dictionary): + super().__init__(dictionary) + + def select_decoder(self, mode, **kwargs): + raise NotImplementedError("Model must implement the select_decoder method") + return None, kwargs + + def forward( + self, prev_output_tokens, encoder_out, incremental_state=None, mode="", **kwargs + ): + decoder, kwargs = self.select_decoder(mode, **kwargs) + return decoder( + prev_output_tokens, + encoder_out, + incremental_state=incremental_state, + **kwargs + ) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 4b43e1acb5..4ffbeaeecb 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -295,15 +295,15 @@ def get_ctc_target(self, sample: Optional[Dict[str, Tensor]]): return sample["target"], sample["target_lengths"] def get_ctc_output( - self, - net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], - sample: Optional[Dict[str, Tensor]], + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + sample: Optional[Dict[str, Tensor]] ): encoder_out = net_output[1]["encoder_out"]["encoder_out"][0] logits = self.encoder.ctc_proj(encoder_out) # T x B x C out = utils.log_softmax(logits.float(), dim=-1) padding_mask = net_output[1]["encoder_out"]["encoder_padding_mask"] - lens = out.new_full((out.shape[1],), out.shape[0]).long() + lens = out.new_full((out.shape[1], ), out.shape[0]).long() if len(padding_mask) > 0: lens -= padding_mask[0].sum(dim=-1) return out, lens @@ -359,7 +359,7 @@ def __init__(self, args): self.layer_norm = None self.ctc_proj = None - if getattr(args, "ctc_weight", 0.0) > 0.0: + if getattr(args, "ctc_weight", 0.) > 0.: self.ctc_proj = nn.Linear(args.encoder_embed_dim, args.tgt_dict_size) def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): diff --git a/fairseq/models/speech_to_text/s2t_wav_transformer.py b/fairseq/models/speech_to_text/s2t_wav_transformer.py new file mode 100644 index 0000000000..f11034818d --- /dev/null +++ b/fairseq/models/speech_to_text/s2t_wav_transformer.py @@ -0,0 +1,485 @@ +#!/usr/bin/env python3 + +import math + +import torch +import torch.nn as nn + +from fairseq.data.data_utils import compute_mask_indices +from fairseq.models import FairseqEncoder +from fairseq.models.wav2vec import ConvFeatureExtractionModel +from fairseq.modules import GradMultiply, LayerNorm, SamePad, TransformerEncoderLayer + + +# Transformer encoder with wave input, it is adopted from wav2vec 2.0 Encoder. +# use wav input +# use trained position embedding so it is easier to match with text input +class SpeechWavTransformerEncoder(FairseqEncoder): + + # extra parameters for speech encoder besides those defined in transformermodel + @staticmethod + def add_args(parser): + parser.add_argument( + "--dropout-input", + type=float, + metavar="D", + help="dropout to apply to the input (after feat extr)", + ) + parser.add_argument( + "--dropout-features", + type=float, + metavar="D", + help="dropout to apply to the unmasked features (after feat extr)", + ) + parser.add_argument( + "--speech-extractor-mode", + type=str, + default="layer_norm", + choices=["default", "layer_norm"], + help="feature extractor norm", + ) + + parser.add_argument( + "--speech-conv-bias", + action="store_true", + help="include bias in speech conv encoder", + ) + + parser.add_argument( + "--conv-feature-layers", + default="[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]", + help="string describing convolutional feature extraction layers in form of a python list that contains [(dim, kernel_size, stride), ...]", + ) + + parser.add_argument( + "--speech-mask-length", + type=int, + help="repeat the mask indices multiple times", + ) + + parser.add_argument( + "--speech-mask-prob", + type=float, + help="probability of replacing a token with mask", + ) + + parser.add_argument( + "--speech-mask-selection", + type=str, + choices=["static", "uniform", "normal", "poisson"], + help="how to choose masks", + ) + + parser.add_argument( + "--speech-mask-other", + type=float, + help="stdev of the mask length in case of 'normal' selection strategy", + ) + + parser.add_argument( + "--speech-no-mask-overlap", + action="store_true", + help="whether to allow masks to overlap", + ) + + parser.add_argument( + "--speech-mask-min-space", + type=int, + help="min space between spans (if no overlap is enabled)", + ) + + parser.add_argument( + "--speech-mask-channel-length", + type=int, + help="repeat the mask indices multiple times", + ) + + parser.add_argument( + "--speech-mask-channel-prob", + type=float, + help="probability of replacing a token with mask", + ) + + parser.add_argument( + "--speech-mask-channel-selection", + type=str, + choices=["static", "uniform", "normal", "poisson"], + help="how to choose masks", + ) + + parser.add_argument( + "--speech-mask-channel-other", + type=float, + help="stdev of the mask length in case of 'normal' selection strategy", + ) + + parser.add_argument( + "--speech-no-mask-channel-overlap", + action="store_true", + help="whether to allow masks to overlap", + ) + + parser.add_argument( + "--no-scale-feature", + action="store_true", + help="no scale for the calculated features", + ) + + parser.add_argument( + "--speech-mask-channel-min-space", + type=int, + help="min space between spans (if no overlap is enabled)", + ) + + parser.add_argument( + "--feature-grad-mult", + type=float, + help="reset feature grad mult in wav2vec 2.0 to this", + ) + + # positional embeddings + parser.add_argument( + "--conv-pos", + type=int, + default=128, + help="number of filters for convolutional positional embeddings", + ) + + parser.add_argument( + "--conv-pos-groups", + type=int, + default=16, + help="number of groups for convolutional positional embedding", + ) + # model configures + parser.add_argument( + "--speech-encoder-layers", + type=int, + help="number of speech encoder layers", + ) + parser.add_argument( + "--text-encoder-layers", + type=int, + help="number of text encoder layers", + ) + + def __init__(self, args, alway_mask=False): + super().__init__(args) + self.args = args + self.dropout = args.dropout + self.embedding_dim = args.encoder_embed_dim + self.feat_scale = math.sqrt(args.encoder_embed_dim) + if args.no_scale_feature: + self.feat_scale = 1.0 + + subsample = ConvFeatureExtractionModel( + conv_layers=eval(args.conv_feature_layers), + dropout=0.0, + mode=args.speech_extractor_mode, # default, layer_norm + conv_bias=args.speech_conv_bias, + ) + feature_enc_layers = eval(args.conv_feature_layers) + self.subsample = subsample + self.feat_proj = ( + nn.Linear(feature_enc_layers[-1][0], self.embedding_dim) + if feature_enc_layers[-1][0] != self.embedding_dim + else None + ) + + self.feat_layer_norm = LayerNorm(feature_enc_layers[-1][0]) + + self.embed_positions = nn.Conv1d( + self.embedding_dim, + self.embedding_dim, + kernel_size=args.conv_pos, + padding=args.conv_pos // 2, + groups=args.conv_pos_groups, + ) + std = math.sqrt(4 / (args.conv_pos * self.embedding_dim)) + nn.init.normal_(self.embed_positions.weight, mean=0, std=std) + nn.init.constant_(self.embed_positions.bias, 0) + + self.embed_positions = nn.utils.weight_norm( + self.embed_positions, name="weight", dim=2 + ) + self.embed_positions = nn.Sequential( + self.embed_positions, SamePad(args.conv_pos), nn.GELU() + ) + + self.mask_prob = args.speech_mask_prob + self.mask_selection = args.speech_mask_selection + self.mask_other = args.speech_mask_other + self.mask_length = args.speech_mask_length + self.no_mask_overlap = args.speech_no_mask_overlap + self.mask_min_space = args.speech_mask_min_space + + self.mask_channel_prob = args.speech_mask_channel_prob + self.mask_channel_selection = args.speech_mask_channel_selection + self.mask_channel_other = args.speech_mask_channel_other + self.mask_channel_length = args.speech_mask_channel_length + self.no_mask_channel_overlap = args.speech_no_mask_channel_overlap + self.mask_channel_min_space = args.speech_mask_channel_min_space + + self.dropout_input = nn.Dropout(args.dropout_input) + self.dropout_features = nn.Dropout(args.dropout_features) + + self.feature_grad_mult = args.feature_grad_mult + + self.mask_emb = nn.Parameter( + torch.FloatTensor(args.encoder_embed_dim).uniform_() + ) + + self.layers = nn.ModuleList( + [TransformerEncoderLayer(args) for _ in range(args.encoder_layers)] + ) + self.layer_norm = LayerNorm(args.encoder_embed_dim) + self.normalize_before = args.encoder_normalize_before + self.alway_mask = alway_mask + + def apply_mask(self, x, padding_mask): + B, T, C = x.shape + if self.mask_prob > 0: + mask_indices = compute_mask_indices( + (B, T), + padding_mask, + self.mask_prob, + self.mask_length, + self.mask_selection, + self.mask_other, + min_masks=2, + no_overlap=self.no_mask_overlap, + min_space=self.mask_min_space, + ) + mask_indices = torch.from_numpy(mask_indices).to(x.device) + x[mask_indices] = self.mask_emb + else: + mask_indices = None + + if self.mask_channel_prob > 0: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_channel_prob, + self.mask_channel_length, + self.mask_channel_selection, + self.mask_channel_other, + no_overlap=self.no_mask_channel_overlap, + min_space=self.mask_channel_min_space, + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x[mask_channel_indices] = 0 + + return x, mask_indices + + def forward( + self, + src_tokens, + src_lengths, + return_all_hiddens=False, + padding_mask=None, + features_only=True, + ): + mask = self.training or self.alway_mask + if self.feature_grad_mult > 0 and self.training: + features = self.subsample(src_tokens) + if self.feature_grad_mult != 1.0: + features = GradMultiply.apply(features, self.feature_grad_mult) + else: + with torch.no_grad(): + features = self.subsample(src_tokens) + features = features.transpose(1, 2) + features = self.feat_layer_norm(features) + if self.feat_proj is not None: + features = self.feat_proj(features) + + if padding_mask is not None: + input_lengths = (1 - padding_mask.long()).sum(-1) + # apply conv formula to get real output_lengths + output_lengths = self._get_feat_extract_output_lengths(input_lengths) + + padding_mask = torch.zeros( + features.shape[:2], dtype=features.dtype, device=features.device + ) + + # these two operations makes sure that all values + # before the output lengths indices are attended to + padding_mask[ + ( + torch.arange(padding_mask.shape[0], device=padding_mask.device), + output_lengths - 1, + ) + ] = 1 + padding_mask = (1 - padding_mask.flip([-1]).cumsum(-1).flip([-1])).bool() + + features = self.feat_scale * features if self.feat_scale != 1.0 else features + unmasked_features = features.clone() + + features = self.dropout_input(features) + unmasked_features = self.dropout_features(unmasked_features) + if mask: + x, mask_indices = self.apply_mask(features, padding_mask) + else: + x = features + mask_indices = None + + def cal_transformer_layers(x, encoder_padding_mask, return_all_hiddens=False): + # x: B x T x C + positions = self.embed_positions(x.transpose(1, 2)).transpose(1, 2) + x = x + positions + if not self.normalize_before: + x = self.layer_norm(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + encoder_states = [] + for layer in self.layers: + x = layer(x, encoder_padding_mask) + if return_all_hiddens: + encoder_states.append(x) + if self.normalize_before: + x = self.layer_norm(x) + return x, encoder_states + + x, encoder_states = cal_transformer_layers(x, padding_mask, return_all_hiddens) + if features_only: + return { + "encoder_out": [x], # [T x B x C] + "encoder_padding_mask": [padding_mask] + if padding_mask is not None + else [], # B x T + "encoder_embedding": [], # + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + "mask_indices": [mask_indices], + } + + x_unmasked = x + if self.mask_prob > 0 or self.mask_channel_prob > 0: + x_unmasked, _ = cal_transformer_layers(unmasked_features, padding_mask) + return { + "encoder_out": [x], # [T x B x C] + "encoder_unmasked_out": [x_unmasked], # [T x B x C] + "encoder_padding_mask": [padding_mask] + if padding_mask is not None + else [], # B x T + "encoder_embedding": [], # + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + "mask_indices": [mask_indices] if mask_indices is not None else [], # B X T + } + + def reorder_encoder_out(self, encoder_out, new_order): + new_encoder_out = ( + [] + if len(encoder_out["encoder_out"]) == 0 + else [x.index_select(1, new_order) for x in encoder_out["encoder_out"]] + ) + + new_encoder_padding_mask = ( + [] + if len(encoder_out["encoder_padding_mask"]) == 0 + else [ + x.index_select(0, new_order) + for x in encoder_out["encoder_padding_mask"] + ] + ) + + new_encoder_embedding = ( + [] + if len(encoder_out["encoder_embedding"]) == 0 + else [ + x.index_select(0, new_order) for x in encoder_out["encoder_embedding"] + ] + ) + + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: + for idx, state in enumerate(encoder_states): + encoder_states[idx] = state.index_select(1, new_order) + + return { + "encoder_out": new_encoder_out, # T x B x C + "encoder_padding_mask": new_encoder_padding_mask, # B x T + "encoder_embedding": new_encoder_embedding, # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], # B x T + "src_lengths": [], # B x 1 + } + + +class StackedSpeechWavTransformerEncoder(FairseqEncoder): + def __init__(self, speech_enc, text_enc_layers, text_layer_norm): + super().__init__(None) + self.speech_encoder = speech_enc + self.text_encoder_layers = text_enc_layers + self.final_layer_norm = text_layer_norm + + def forward( + self, + src_tokens, + src_lengths=None, + return_all_hiddens=False, + padding_mask=None, + features_only=True, + ): + + out = self.speech_encoder.forward( + src_tokens, + src_lengths, + return_all_hiddens, + padding_mask=padding_mask, + features_only=features_only, + ) + x = out["encoder_out"][0] + encoder_padding_mask = None + if len(out["encoder_padding_mask"]) > 0: + encoder_padding_mask = out["encoder_padding_mask"][0] + + def cal_text_layers(x, padding_mask, return_all_hiddens=False): + encoder_states = [] + for layer in self.text_encoder_layers: + x = layer(x, padding_mask) + if return_all_hiddens: + encoder_states.append(x) + if self.final_layer_norm is not None: + x = self.final_layer_norm(x) + return x, encoder_states + + x, encoder_states = cal_text_layers(x, encoder_padding_mask, return_all_hiddens) + if features_only: + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [encoder_padding_mask] + if encoder_padding_mask is not None + else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + + x_u = out["encoder_unmasked_out"][0] + x_u, _ = cal_text_layers(x_u, encoder_padding_mask) + + return { + "encoder_out": [x], # [T x B x C] + "encoder_unmasked_out": [x_u], # [T x B x C] + "encoder_padding_mask": [encoder_padding_mask] + if encoder_padding_mask is not None + else [], # B x T + "encoder_embedding": [], # + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + "mask_indices": out["mask_indices"], # B X T + } + + def reorder_encoder_out(self, encoder_out, new_order): + return self.speech_encoder.reorder_encoder_out(encoder_out, new_order) diff --git a/tests/speech/test_dual_input_wav_transformer.py b/tests/speech/test_dual_input_wav_transformer.py new file mode 100644 index 0000000000..3581bc1991 --- /dev/null +++ b/tests/speech/test_dual_input_wav_transformer.py @@ -0,0 +1,76 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import unittest +from collections import namedtuple +from pathlib import Path + +import torch +from tqdm import tqdm + +import fairseq +from fairseq import utils +from fairseq.checkpoint_utils import load_model_ensemble_and_task +from fairseq.scoring.bleu import SacrebleuScorer +from fairseq.tasks import import_tasks +from tests.speech import S3_BASE_URL, TestFairseqSpeech + + +@unittest.skipIf(not torch.cuda.is_available(), "test requires a GPU") +class TestLibrispeechDualInputWavTransformer(TestFairseqSpeech): + def setUp(self): + dataset_id = "librispeech_wvtrasnformer" + base_url = "https://dl.fbaipublicfiles.com/joint_speech_text_4_s2t/acl2022/librispeech/finetuned" + data_filenames = [ + "checkpoint_ave_10.pt", + "spm.model", + "src_dict.txt", + "tgt_dict.txt", + "config.yaml", + ] + self._set_up( + dataset_id, + "s2t", + [ + "librispeech_flac_test-other.tsv", + "librispeech_flac_test-other.zip", + ], + ) + for filename in data_filenames: + self.download(base_url, self.root, filename) + + def import_user_module(self): + user_dir = ( + Path(fairseq.__file__).parent.parent / "examples/speech_text_joint_to_text" + ) + Arg = namedtuple("Arg", ["user_dir"]) + arg = Arg(user_dir.__str__()) + utils.import_user_module(arg) + + @torch.no_grad() + def test_librispeech_dualinput_wav_transformer_checkpoint(self): + self.import_user_module() + checkpoint_filename = "checkpoint_ave_10.pt" + arg_overrides = { + "config_yaml": "config.yaml", + "load_pretrained_speech_text_encoder": "", + "load_pretrained_speech_text_decoder": "", + "beam": 10, + "nbest": 1, + "lenpen": 1.0, + "load_speech_only": True, + } + self.base_test( + checkpoint_filename, + 4.6, + dataset="librispeech_flac_test-other", + max_tokens=800000, + max_positions=(800000, 1024), + arg_overrides=arg_overrides, + ) + + +if __name__ == "__main__": + unittest.main() From 1ab7a751dae13cea108bebef6e7e65a258c39f73 Mon Sep 17 00:00:00 2001 From: Sravya Popuri <spopuri@fb.com> Date: Tue, 10 May 2022 22:21:21 -0700 Subject: [PATCH 617/774] support appending lang tags in S2T task (#3353) Summary: Follow up to diff D35864490 Currently speech_to_text task only supports prepending language tag but we append the language tag in unit mBART. To support that use case here, I add an option called 'prepend_bos_and_append_tgt_lang_tag' to S2TDataConfig to support the case where to want to prepend the BOS token and append the language tag. Update the sequence generator to read the tgt_lang tag from the data config and replace EOS token with it during inference. Example config file for S2UT pretraining with wav2vec 2.0 encoder and unit mBART looks like ``` audio_root: $AUDIO_ROOT standardize_audio: true use_audio_input: true vocab_filename: dict_1003_unitmbart.txt prepend_bos_and_append_tgt_lang_tag: true eos_token: <lang:en> ``` X-link: https://github.com/fairinternal/fairseq-py/pull/3353 Reviewed By: kahne Differential Revision: D36112014 Pulled By: sravyapopuri388 fbshipit-source-id: 56294d8fd6071ad6e95c797bd221467e4cf3d035 --- fairseq/data/audio/data_cfg.py | 5 +++++ fairseq/data/audio/speech_to_text_dataset.py | 9 +++++++- fairseq/dataclass/configs.py | 4 ++++ fairseq/tasks/speech_to_text.py | 22 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 861fd767ff..fba36dfcf0 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -82,6 +82,11 @@ def prepend_tgt_lang_tag(self) -> bool: to force BOS to be lang ID token.""" return self.config.get("prepend_tgt_lang_tag", False) + @property + def prepend_bos_and_append_tgt_lang_tag(self) -> bool: + """Prepend BOS and append target lang ID token to the target (e.g. mBART with language token pretraining).""" + return self.config.get("prepend_bos_and_append_tgt_lang_tag", False) + @property def input_feat_per_channel(self): """The dimension of input features (per audio channel)""" diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index 2f1be34678..bfd500395d 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -281,6 +281,13 @@ def __getitem__(self, index: int) -> SpeechToTextDatasetItem: ) target = torch.cat((torch.LongTensor([lang_tag_idx]), target), 0) + if self.cfg.prepend_bos_and_append_tgt_lang_tag: + bos = torch.LongTensor([self.tgt_dict.bos()]) + lang_tag_idx = self.get_lang_tag_idx(self.tgt_langs[index], self.tgt_dict) + assert lang_tag_idx != self.tgt_dict.unk() + lang_tag_idx = torch.LongTensor([lang_tag_idx]) + target = torch.cat((bos, target, lang_tag_idx), 0) + speaker_id = None if self.speaker_to_id is not None: speaker_id = self.speaker_to_id[self.speakers[index]] @@ -322,7 +329,7 @@ def collater( prev_output_tokens = fairseq_data_utils.collate_tokens( [x.target for x in samples], self.tgt_dict.pad(), - self.tgt_dict.eos(), + eos_idx=None, left_pad=False, move_eos_to_beginning=True, ) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 43456d5b5f..3079101db3 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -997,6 +997,10 @@ class GenerationConfig(FairseqDataclass): default=False, metadata={"help": "if set, dont use seed for initializing random generators"}, ) + eos_token: Optional[str] = field( + default=None, + metadata={"help": "EOS token"}, + ) @dataclass diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 55ba284f8d..5818fbe62c 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -51,6 +51,13 @@ def __init__(self, args, tgt_dict): self.tgt_dict = tgt_dict self.data_cfg = S2TDataConfig(Path(args.data) / args.config_yaml) self.speaker_to_id = self._get_speaker_to_id() + if ( + self.data_cfg.prepend_tgt_lang_tag + and self.data_cfg.prepend_bos_and_append_tgt_lang_tag + ): + raise ValueError( + "Please set only one of the two options to avoid adding target token multiple times" + ) def _get_speaker_to_id(self): speaker_to_id = None @@ -142,6 +149,21 @@ def build_generator( if extra_gen_cls_kwargs is None: extra_gen_cls_kwargs = {} extra_gen_cls_kwargs["symbols_to_strip_from_output"] = lang_token_ids + + eos_token = ( + args.eos_token + if "eos_token" in args and args.eos_token is not None + else self.data_cfg.config.get("eos_token", None) + ) + + if self.data_cfg.prepend_bos_and_append_tgt_lang_tag and not eos_token: + raise Warning( + "Please provide --eos_token to replace eos in sequence generator" + ) + + eos_id = self.tgt_dict.index(eos_token) if eos_token else None + extra_gen_cls_kwargs["eos"] = eos_id + return super().build_generator( models, args, seq_gen_cls=None, extra_gen_cls_kwargs=extra_gen_cls_kwargs ) From 17fc870b64aeb3a9d8c0ba24e32fb083a6b5da73 Mon Sep 17 00:00:00 2001 From: Mikel Artetxe <artetxe@fb.com> Date: Wed, 11 May 2022 18:33:28 -0700 Subject: [PATCH 618/774] Release code and models for X-MOD (#3333) Summary: Release code and models from the paper "Lifting the Curse of Multilinguality by Pre-training Modular Transformers". X-link: https://github.com/fairinternal/fairseq-py/pull/3333 Reviewed By: ngoyal2707 Differential Revision: D36319556 Pulled By: artetxem fbshipit-source-id: 9e373fa8811da28e78328102b8224f9e0d05ab9e --- examples/xmod/README.md | 133 ++++ examples/xmod/preprocess_nli.py | 168 ++++ .../sentence_prediction_adapters.py | 63 ++ fairseq/models/xmod/__init__.py | 7 + fairseq/models/xmod/hub_interface.py | 51 ++ fairseq/models/xmod/model.py | 742 ++++++++++++++++++ fairseq/models/xmod/transformer_layer_xmod.py | 179 +++++ fairseq/tasks/sentence_prediction_adapters.py | 56 ++ 8 files changed, 1399 insertions(+) create mode 100644 examples/xmod/README.md create mode 100644 examples/xmod/preprocess_nli.py create mode 100644 fairseq/criterions/sentence_prediction_adapters.py create mode 100644 fairseq/models/xmod/__init__.py create mode 100644 fairseq/models/xmod/hub_interface.py create mode 100644 fairseq/models/xmod/model.py create mode 100644 fairseq/models/xmod/transformer_layer_xmod.py create mode 100644 fairseq/tasks/sentence_prediction_adapters.py diff --git a/examples/xmod/README.md b/examples/xmod/README.md new file mode 100644 index 0000000000..62aa215efc --- /dev/null +++ b/examples/xmod/README.md @@ -0,0 +1,133 @@ +# X-MOD: Lifting the Curse of Multilinguality by Pre-training Modular Transformers + +X-MOD extends multilingual masked language models like XLM-R to include language-specific modular components, introduced at each transformer layer. Each module is only used by one language. For fine-tuning, the modular components are frozen, and replaced with the target language in cross-lingual transfer settings. + + +## Pre-trained models + +Model | Size | # train steps | # langs | Download +---|---|---|---|--- +`xmod.base.13.125k` | BERT-base | 125k | 13 | [xmod.base.13.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.13.125k.tar.gz) +`xmod.base.30.125k` | BERT-base | 125k | 30 | [xmod.base.30.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.30.125k.tar.gz) +`xmod.base.30.195k` | BERT-base | 195k | 30 | [xmod.base.30.195k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.30.195k.tar.gz) +`xmod.base.60.125k` | BERT-base | 125k | 60 | [xmod.base.60.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.60.125k.tar.gz) +`xmod.base.60.265k` | BERT-base | 265k | 60 | [xmod.base.60.265k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.60.265k.tar.gz) +`xmod.base.75.125k` | BERT-base | 125k | 75 | [xmod.base.75.125k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.75.125k.tar.gz) +`xmod.base.75.269k` | BERT-base | 269k | 75 | [xmod.base.75.269k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.75.269k.tar.gz) +`xmod.base` | BERT-base | 1M | 81 | [xmod.base.81.1M.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.81.1M.tar.gz) +`xmod.large.prenorm` | BERT-large | 500k | 81 | [xmod.large.prenorm.81.500k.tar.gz](https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.large.prenorm.81.500k.tar.gz) + + +## Fine-tuning on NLI + +We next provide an example of how to fine-tune the pre-trained models above on Natural Language Inference (NLI). We use MNLI for training in English, and show how to run inference in other languages. + +### 1) Download a pre-trained model + +```bash +MODEL=xmod.base.81.1M +wget https://dl.fbaipublicfiles.com/fairseq/models/xmod/$MODEL.tar.gz +tar -xzf $MODEL.tar.gz +``` + +### 2) Download and preprocess [MNLI](https://cims.nyu.edu/~sbowman/multinli/) +```bash +wget https://cims.nyu.edu/~sbowman/multinli/multinli_1.0.zip +unzip multinli_1.0.zip +python ./examples/xmod/preprocess_nli.py \ + --sentencepiece-model $MODEL/sentencepiece.bpe.model \ + --train multinli_1.0/multinli_1.0_train.jsonl \ + --valid multinli_1.0/multinli_1.0_dev_matched.jsonl \ + --destdir multinli_1.0/fairseq +``` + +### 3) Fine-tune on MNLI: + +```bash +MAX_EPOCH=5 +LR=1e-05 +BATCH_SIZE=32 +DATA_DIR=multinli_1.0/fairseq/bin + +CUDA_VISIBLE_DEVICES=0 fairseq-train $DATA_DIR \ + --restore-file $MODEL/model.pt \ + --save-dir $MODEL/nli \ + --reset-optimizer \ + --reset-dataloader \ + --reset-meters \ + --best-checkpoint-metric accuracy \ + --maximize-best-checkpoint-metric \ + --task sentence_prediction_adapters \ + --num-classes 3 \ + --init-token 0 \ + --separator-token 2 \ + --max-positions 512 \ + --shorten-method "truncate" \ + --arch xmod_base \ + --dropout 0.1 \ + --attention-dropout 0.1 \ + --weight-decay 0.01 \ + --criterion sentence_prediction_adapters \ + --optimizer adam \ + --adam-betas '(0.9, 0.98)' \ + --adam-eps 1e-06 \ + --clip-norm 0.0 \ + --lr-scheduler fixed \ + --lr $LR \ + --fp16 \ + --fp16-init-scale 4 \ + --threshold-loss-scale 1 \ + --fp16-scale-window 128 \ + --batch-size $BATCH_SIZE \ + --required-batch-size-multiple 1 \ + --update-freq 1 \ + --max-epoch $MAX_EPOCH +``` + +### 4) Run inference + +After training the model, we can load it and run inference in our target language. The default language is set to English, which is why we were not required to pass a language ID to the model during fine-tuning. To run inference in a non-English language, we need to tell the model that the module of the target language should be used instead: + +```python +from fairseq.models.xmod import XMODModel + +MODEL='xmod.base.81.1M/nli' +DATA='multinli_1.0/fairseq/bin' + +# Load model +model = XMODModel.from_pretrained( + model_name_or_path=MODEL, + checkpoint_file='checkpoint_best.pt', + data_name_or_path=DATA, + suffix='', + criterion='cross_entropy', + bpe='sentencepiece', + sentencepiece_model=DATA+'/input0/sentencepiece.bpe.model') +model = model.eval(); # disable dropout +model = model.half(); # use FP16 +model = model.cuda(); # move to GPU + +def predict(premise, hypothesis, lang): + tokens = model.encode(premise, hypothesis) + idx = model.predict('sentence_classification_head', tokens, lang_id=[lang]).argmax().item() + dictionary = model.task.label_dictionary + return dictionary[idx + dictionary.nspecial] + +predict( + premise='X-Mod hat spezifische Module die für jede Sprache existieren.', + hypothesis='X-Mod hat Module.', + lang='de_DE' +) # entailment + +predict( + premise='Londres es la capital del Reino Unido.', + hypothesis='Londres está en Francia.', + lang='es_XX', +) # contradiction + +predict( + premise='Patxik gogoko ditu babarrunak.', + hypothesis='Patxik babarrunak bazkaldu zituen.', + lang='eu_ES', +) # neutral +``` diff --git a/examples/xmod/preprocess_nli.py b/examples/xmod/preprocess_nli.py new file mode 100644 index 0000000000..e1fb91c5d3 --- /dev/null +++ b/examples/xmod/preprocess_nli.py @@ -0,0 +1,168 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import json +import collections +import argparse +import shutil +import subprocess +import sys +import tempfile +from multiprocessing import Pool +import sentencepiece as spm + + +def preprocess(spm_model_path, train_path, valid_path, test_path, dest_dir, remove_empty=False, output_format='piece', workers=20): + with tempfile.TemporaryDirectory() as tmp: + # Tokenize with SentencePiece + for split, path in ('train', train_path), ('valid', valid_path), ('test', test_path): + if path is None: + continue + if path == '-': + path = sys.stdin.fileno() + with open(path, encoding='utf-8', errors='surrogateescape') as fin: + with open(f'{tmp}/{split}', mode='w', encoding='utf-8', errors='surrogateescape') as fout: + encoder = MultiprocessingEncoder(model=spm_model_path, remove_empty=remove_empty, output_format=output_format) + pool = Pool(workers, initializer=encoder.initializer) + encoded_lines = pool.imap(encoder.encode, fin, 10000) + for i, line in enumerate(encoded_lines, start=1): + if line is not None: + print(line, file=fout) + if i % 10000 == 0: + print("tokenized {} lines".format(i), file=sys.stderr) + + # Generate dictionary + sp = spm.SentencePieceProcessor(model_file=spm_model_path) + if output_format == 'piece': + vocab = [sp.id_to_piece(i) for i in range(3, sp.vocab_size())] + else: + vocab = map(str, range(sp.vocab_size())) + with open(f'{tmp}/dict.txt', mode='w', encoding='utf-8', errors='surrogateescape') as f: + for word in vocab: + print(word, 1, file=f) + + # Binarize + command = [ + 'python3', '-m', 'fairseq_cli.preprocess', + '--only-source', + '--thresholdsrc', '0', + '--destdir', dest_dir, + '--srcdict', f'{tmp}/dict.txt', + '--workers', '20', + ] + for split, path in ('train', train_path), ('valid', valid_path), ('test', test_path): + if path is not None: + command += [f'--{split}pref', f'{tmp}/{split}'] + subprocess.run(command) + + # Copy SentencePiece model + shutil.copyfile(spm_model_path, f'{dest_dir}/sentencepiece.bpe.model') + + +class MultiprocessingEncoder(object): + def __init__(self, model, remove_empty, output_format): + self.model = model + self.remove_empty = remove_empty + self.output_format = output_format + + def initializer(self): + global sp + sp = spm.SentencePieceProcessor(model_file=self.model) + + def encode(self, line): + global sp + line = line.strip() + if len(line) == 0 and self.remove_empty: + return None + + if self.output_format == 'piece': + return ' '.join(sp.encode_as_pieces(line)) + else: + return ' '.join(map(str, sp.encode(line))) + + +def write_lines(lines, path): + with open(path, mode='x', encoding='utf-8') as f: + for line in lines: + print(line, file=f) + + +def read_jsonl(path): + with open(path, encoding='utf-8') as f: + return [json.loads(line) for line in f.read().splitlines()] + + +def read_nli(path, langs=None): + data = read_jsonl(path) + + if langs is not None: + data = [sample for sample in data if sample.get('language') in langs] + + lang2count = collections.defaultdict(int) + for sample in data: + lang2count[sample.get('language')] += 1 + + if langs: + assert set(lang2count.keys()) == set(langs) + + nlangs = len(lang2count) + assert nlangs > 0 + lens = list(lang2count.values()) + assert all([lens[0] == length for length in lens]) + + print(f'Loaded {lens[0]} samples in {nlangs} languages from {path}', file=sys.stderr) + return data + + +def main(): + parser = argparse.ArgumentParser(description='Tokenize and binarize NLI data') + parser.add_argument('--sentencepiece-model', required=True) + parser.add_argument('--train', required=True, help='Training data in jsonl format') + parser.add_argument('--valid', required=True, help='Validation data in jsonl format') + parser.add_argument('--destdir', required=True) + + args = parser.parse_args() + + os.makedirs(args.destdir + '/raw',) + os.makedirs(args.destdir + '/bin', ) + + # Extract input/labels + for split, path in ('train', args.train), ('valid', args.valid): + data = read_nli(path, langs=None) + original_size = len(data) + data = [sample for sample in data if sample['gold_label'] != '-'] + assert all(sample['gold_label'] in ('contradiction', 'entailment', 'neutral') for sample in data) + filtered_size = len(data) + if filtered_size != original_size: + print(f'Filtered {filtered_size}/{original_size} samples from {path}', file=sys.stderr) + for name, field in ('input0', 'sentence1'), ('input1', 'sentence2'), ('label', 'gold_label'): + write_lines([sample[field] for sample in data], f'{args.destdir}/raw/{split}.{name}.txt') + + # Tokenize and binarize input + for field in 'input0', 'input1': + preprocess( + spm_model_path=args.sentencepiece_model, + train_path=f'{args.destdir}/raw/train.{field}.txt', + valid_path=f'{args.destdir}/raw/valid.{field}.txt', + test_path=None, + dest_dir=f'{args.destdir}/bin/{field}', + workers=20, + ) + + # Binarize labels + subprocess.run([ + 'python3', '-m', 'fairseq_cli.preprocess', + '--trainpref', f'{args.destdir}/raw/train.label.txt', + '--validpref', f'{args.destdir}/raw/valid.label.txt', + '--only-source', + '--thresholdsrc', '0', + '--destdir', f'{args.destdir}/bin/label', + '--workers', '20', + ]) + + +if __name__ == '__main__': + main() diff --git a/fairseq/criterions/sentence_prediction_adapters.py b/fairseq/criterions/sentence_prediction_adapters.py new file mode 100644 index 0000000000..8a873a45b3 --- /dev/null +++ b/fairseq/criterions/sentence_prediction_adapters.py @@ -0,0 +1,63 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn.functional as F +from fairseq.criterions import register_criterion +from fairseq.criterions.sentence_prediction import ( + SentencePredictionCriterion, + SentencePredictionConfig, +) + + +@register_criterion("sentence_prediction_adapters", dataclass=SentencePredictionConfig) +class SentencePredictionCriterionAdapters(SentencePredictionCriterion): + def forward(self, model, sample, reduce=True): + """Compute the loss for the given sample. + + Returns a tuple with three elements: + 1) the loss + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + assert ( + hasattr(model, "classification_heads") + and self.classification_head_name in model.classification_heads + ), "model must provide sentence classification head for --criterion=sentence_prediction" + + if not hasattr(sample, "lang_id"): + # If no language ID is given, we fall back to English + lang_id = ["en_XX"] * sample["nsentences"] + else: + lang_id = sample["lang_id"] + + logits, _ = model( + **sample["net_input"], + features_only=True, + classification_head_name=self.classification_head_name, + lang_id=lang_id, + ) + targets = model.get_targets(sample, [logits]).view(-1) + sample_size = targets.numel() + + if not self.regression_target: + lprobs = F.log_softmax(logits, dim=-1, dtype=torch.float32) + loss = F.nll_loss(lprobs, targets, reduction="sum") + else: + logits = logits.view(-1).float() + targets = targets.float() + loss = F.mse_loss(logits, targets, reduction="sum") + + logging_output = { + "loss": loss.data, + "ntokens": sample["ntokens"], + "nsentences": sample_size, + "sample_size": sample_size, + } + if not self.regression_target: + preds = logits.argmax(dim=1) + logging_output["ncorrect"] = (preds == targets).sum() + + return loss, sample_size, logging_output diff --git a/fairseq/models/xmod/__init__.py b/fairseq/models/xmod/__init__.py new file mode 100644 index 0000000000..bbf7694920 --- /dev/null +++ b/fairseq/models/xmod/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .model import * # noqa +from .transformer_layer_xmod import * # noqa diff --git a/fairseq/models/xmod/hub_interface.py b/fairseq/models/xmod/hub_interface.py new file mode 100644 index 0000000000..909bb423ca --- /dev/null +++ b/fairseq/models/xmod/hub_interface.py @@ -0,0 +1,51 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +from fairseq.models.roberta.hub_interface import RobertaHubInterface +import torch +import torch.nn.functional as F + + +class XMODHubInterface(RobertaHubInterface): + def extract_features( + self, + tokens: torch.LongTensor, + return_all_hiddens: bool = False, + lang_id=None, + ) -> torch.Tensor: + if tokens.dim() == 1: + tokens = tokens.unsqueeze(0) + if tokens.size(-1) > self.model.max_positions(): + raise ValueError( + "tokens exceeds maximum length: {} > {}".format( + tokens.size(-1), self.model.max_positions() + ) + ) + features, extra = self.model( + tokens.to(device=self.device), + features_only=True, + return_all_hiddens=return_all_hiddens, + lang_id=lang_id, + ) + if return_all_hiddens: + # convert from T x B x C -> B x T x C + inner_states = extra["inner_states"] + return [inner_state.transpose(0, 1) for inner_state in inner_states] + else: + return features # just the last layer's features + + def predict( + self, + head: str, + tokens: torch.LongTensor, + return_logits: bool = False, + lang_id=None, + ): + features = self.extract_features(tokens.to(device=self.device), lang_id=lang_id) + logits = self.model.classification_heads[head](features) + if return_logits: + return logits + return F.log_softmax(logits, dim=-1) diff --git a/fairseq/models/xmod/model.py b/fairseq/models/xmod/model.py new file mode 100644 index 0000000000..fb6c7a8dea --- /dev/null +++ b/fairseq/models/xmod/model.py @@ -0,0 +1,742 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from ..roberta.model_xlmr import XLMRModel +from fairseq.models.xmod.transformer_layer_xmod import XMODTransformerEncoderLayerBase +from ..roberta.model import base_architecture, RobertaEncoder +from fairseq.models.transformer import TransformerEncoder +from fairseq.modules.transformer_sentence_encoder import init_bert_params +from typing import Optional +from fairseq.models.xmod.hub_interface import XMODHubInterface +import torch +from fairseq.distributed import fsdp_wrap +from fairseq.models import ( + register_model, + register_model_architecture, +) + +from fairseq.modules.checkpoint_activations import checkpoint_wrapper + +DEFAULT_MIN_PARAMS_TO_WRAP = int(1e8) + + +@register_model("xmod") +class XMODModel(XLMRModel): + @classmethod + def hub_models(cls): + return { + "xmod.base": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.81.1M.tar.gz", + "xmod.large.prenorm": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.large.prenorm.81.500k.tar.gz", + "xmod.base.13.125k": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.13.125k.tar.gz", + "xmod.base.30.125k": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.30.125k.tar.gz", + "xmod.base.30.195k": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.30.195k.tar.gz", + "xmod.base.60.125k": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.60.125k.tar.gz", + "xmod.base.60.265k": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.60.265k.tar.gz", + "xmod.base.75.125k": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.75.125k.tar.gz", + "xmod.base.75.269k": "https://dl.fbaipublicfiles.com/fairseq/models/xmod/xmod.base.75.269k.tar.gz", + } + + @classmethod + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + bpe="sentencepiece", + **kwargs, + ): + from fairseq import hub_utils + + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + bpe=bpe, + load_checkpoint_heads=True, + **kwargs, + ) + return XMODHubInterface(x["args"], x["task"], x["models"][0]) + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + + from omegaconf import OmegaConf + + if OmegaConf.is_config(args): + OmegaConf.set_struct(args, False) + + # make sure all arguments are present + base_architecture(args) + + if not hasattr(args, "max_positions"): + if not hasattr(args, "tokens_per_sample"): + args.tokens_per_sample = task.max_positions() + args.max_positions = args.tokens_per_sample + + encoder = XMODEncoder(args, task.source_dictionary) + + if OmegaConf.is_config(args): + OmegaConf.set_struct(args, True) + + return cls(args, encoder) + + def forward( + self, + src_tokens, + features_only=False, + return_all_hiddens=False, + classification_head_name=None, + lang_id=None, + **kwargs, + ): + if classification_head_name is not None: + features_only = True + x, extra = self.encoder( + src_tokens, features_only, return_all_hiddens, lang_id=lang_id, **kwargs + ) + + if classification_head_name is not None: + x = self.classification_heads[classification_head_name](x) + return x, extra + + +class XMODEncoder(RobertaEncoder): + """XMOD encoder.""" + + def build_encoder(self, args, dictionary, embed_tokens): + encoder = XMODTransformerEncoder(args, dictionary, embed_tokens) + encoder.apply(init_bert_params) + return encoder + + def forward( + self, + src_tokens, + features_only=False, + return_all_hiddens=False, + masked_tokens=None, + lang_id=None, + **unused, + ): + """ + Args: + src_tokens (LongTensor): input tokens of shape `(batch, src_len)` + features_only (bool, optional): skip LM head and just return + features. If True, the output will be of shape + `(batch, src_len, embed_dim)`. + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + + Returns: + tuple: + - the LM output of shape `(batch, src_len, vocab)` + - a dictionary of additional data, where 'inner_states' + is a list of hidden states. Note that the hidden + states have shape `(src_len, batch, vocab)`. + """ + x, extra = self.extract_features( + src_tokens, return_all_hiddens=return_all_hiddens, lang_id=lang_id + ) + if not features_only: + x = self.output_layer(x, masked_tokens=masked_tokens) + return x, extra + + def extract_features( + self, src_tokens, return_all_hiddens=False, lang_id=None, **kwargs + ): + encoder_out = self.sentence_encoder( + src_tokens, + return_all_hiddens=return_all_hiddens, + lang_id=lang_id, + token_embeddings=kwargs.get("token_embeddings", None), + ) + # T x B x C -> B x T x C + features = encoder_out["encoder_out"][0].transpose(0, 1) + inner_states = encoder_out["encoder_states"] if return_all_hiddens else None + return features, {"inner_states": inner_states} + + +class XMODTransformerEncoder(TransformerEncoder): + def build_encoder_layer(self, cfg): + layer = XMODTransformerEncoderLayerBase(cfg) + checkpoint = cfg.checkpoint_activations + if checkpoint: + offload_to_cpu = cfg.offload_activations + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + # if we are checkpointing, enforce that FSDP always wraps the + # checkpointed layer, regardless of layer size + min_params_to_wrap = cfg.min_params_to_wrap if not checkpoint else 0 + layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) + return layer + + def forward( + self, + src_tokens, + src_lengths: Optional[torch.Tensor] = None, + return_all_hiddens: bool = False, + token_embeddings: Optional[torch.Tensor] = None, + lang_id=None, + ): + """ + Args: + src_tokens (LongTensor): tokens in the source language of shape + `(batch, src_len)` + src_lengths (torch.LongTensor): lengths of each source sentence of + shape `(batch)` + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + token_embeddings (torch.Tensor, optional): precomputed embeddings + default `None` will recompute embeddings + + Returns: + dict: + - **encoder_out** (Tensor): the last encoder layer's output of + shape `(src_len, batch, embed_dim)` + - **encoder_padding_mask** (ByteTensor): the positions of + padding elements of shape `(batch, src_len)` + - **encoder_embedding** (Tensor): the (scaled) embedding lookup + of shape `(batch, src_len, embed_dim)` + - **encoder_states** (List[Tensor]): all intermediate + hidden states of shape `(src_len, batch, embed_dim)`. + Only populated if *return_all_hiddens* is True. + """ + return self.forward_scriptable( + src_tokens, + src_lengths, + return_all_hiddens, + token_embeddings, + lang_id=lang_id, + ) + # TorchScript doesn't support super() method so that the scriptable Subclass + # can't access the base class model in Torchscript. + # Current workaround is to add a helper function with different name and + # call the helper function from scriptable Subclass. + + def forward_scriptable( + self, + src_tokens, + src_lengths: Optional[torch.Tensor] = None, + return_all_hiddens: bool = False, + token_embeddings: Optional[torch.Tensor] = None, + lang_id=None, + ): + """ + Args: + src_tokens (LongTensor): tokens in the source language of shape + `(batch, src_len)` + src_lengths (torch.LongTensor): lengths of each source sentence of + shape `(batch)` + return_all_hiddens (bool, optional): also return all of the + intermediate hidden states (default: False). + token_embeddings (torch.Tensor, optional): precomputed embeddings + default `None` will recompute embeddings + + Returns: + dict: + - **encoder_out** (Tensor): the last encoder layer's output of + shape `(src_len, batch, embed_dim)` + - **encoder_padding_mask** (ByteTensor): the positions of + padding elements of shape `(batch, src_len)` + - **encoder_embedding** (Tensor): the (scaled) embedding lookup + of shape `(batch, src_len, embed_dim)` + - **encoder_states** (List[Tensor]): all intermediate + hidden states of shape `(src_len, batch, embed_dim)`. + Only populated if *return_all_hiddens* is True. + """ + # compute padding mask + encoder_padding_mask = src_tokens.eq(self.padding_idx) + has_pads = src_tokens.device.type == "xla" or encoder_padding_mask.any() + + x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) + + # account for padding while computing the representation + if has_pads: + x = x * (1 - encoder_padding_mask.unsqueeze(-1).type_as(x)) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + encoder_states = [] + + if return_all_hiddens: + encoder_states.append(x) + + # encoder layers + for layer in self.layers: + x = layer( + x, + encoder_padding_mask=encoder_padding_mask if has_pads else None, + lang_id=lang_id, + ) + if return_all_hiddens: + assert encoder_states is not None + encoder_states.append(x) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + # The Pytorch Mobile lite interpreter does not supports returning NamedTuple in + # `forward` so we use a dictionary instead. + # TorchScript does not support mixed values so the values are all lists. + # The empty list is equivalent to None. + src_lengths = ( + src_tokens.ne(self.padding_idx) + .sum(dim=1, dtype=torch.int32) + .reshape(-1, 1) + .contiguous() + ) + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [encoder_padding_mask], # B x T + "encoder_embedding": [encoder_embedding], # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [src_lengths], + } + + +@register_model_architecture("xmod", "xmod_base_13") +def roberta_base_architecture(args): + args.ffn_modules = getattr(args, "ffn_modules", False) + args.adapter_modules = getattr(args, "adapter_modules", True) + args.adapter_layer_norm = getattr(args, "adapter_layer_norm", False) + args.adapter_reuse_layer_norm = getattr(args, "adapter_reuse_layer_norm", True) + args.ln_before_adapter = getattr(args, "ln_before_adapter", True) + args.languages = getattr( + args, + "languages", + [ + "ar_AR", + "en_XX", + "fi_FI", + "fr_XX", + "hi_IN", + "id_ID", + "ka_GE", + "ko_KR", + "ru_RU", + "sw_KE", + "ta_IN", + "th_TH", + "vi_VN", + ], + ) + base_architecture(args) + + +@register_model_architecture("xmod", "xmod_base_30") +def roberta_base_architecture(args): + args.ffn_modules = getattr(args, "ffn_modules", False) + args.adapter_modules = getattr(args, "adapter_modules", True) + args.adapter_layer_norm = getattr(args, "adapter_layer_norm", False) + args.adapter_reuse_layer_norm = getattr(args, "adapter_reuse_layer_norm", True) + args.ln_before_adapter = getattr(args, "ln_before_adapter", True) + args.languages = getattr( + args, + "languages", + [ + "ar_AR", + "cs_CZ", + "en_XX", + "eu_ES", + "fi_FI", + "fr_XX", + "hi_IN", + "hr_HR", + "hu_HU", + "hy_AM", + "id_ID", + "it_IT", + "ka_GE", + "ko_KR", + "lt_LT", + "ml_IN", + "mn_MN", + "ms_MY", + "pl_PL", + "ro_RO", + "ru_RU", + "si_LK", + "sk_SK", + "sq_AL", + "sv_SE", + "sw_KE", + "ta_IN", + "th_TH", + "tl_XX", + "vi_VN", + ], + ) + base_architecture(args) + + +@register_model_architecture("xmod", "xmod_base_60") +def roberta_base_architecture(args): + args.ffn_modules = getattr(args, "ffn_modules", False) + args.adapter_modules = getattr(args, "adapter_modules", True) + args.adapter_layer_norm = getattr(args, "adapter_layer_norm", False) + args.adapter_reuse_layer_norm = getattr(args, "adapter_reuse_layer_norm", True) + args.ln_before_adapter = getattr(args, "ln_before_adapter", True) + args.languages = getattr( + args, + "languages", + [ + "af_ZA", + "am_ET", + "ar_AR", + "be_BY", + "bn_IN", + "ca_ES", + "cs_CZ", + "cy_GB", + "da_DK", + "en_XX", + "eo_EO", + "et_EE", + "eu_ES", + "fa_IR", + "fi_FI", + "fr_XX", + "ga_IE", + "gl_ES", + "gu_IN", + "ha_NG", + "hi_IN", + "hr_HR", + "hu_HU", + "hy_AM", + "id_ID", + "is_IS", + "it_IT", + "ka_GE", + "ko_KR", + "ku_TR", + "la_VA", + "lt_LT", + "lv_LV", + "mk_MK", + "ml_IN", + "mn_MN", + "ms_MY", + "ne_NP", + "nl_XX", + "no_XX", + "pl_PL", + "ps_AF", + "pt_XX", + "ro_RO", + "ru_RU", + "sa_IN", + "sd_PK", + "si_LK", + "sk_SK", + "sl_SI", + "so_SO", + "sq_AL", + "sr_RS", + "sv_SE", + "sw_KE", + "ta_IN", + "te_IN", + "th_TH", + "tl_XX", + "vi_VN", + ], + ) + base_architecture(args) + + +@register_model_architecture("xmod", "xmod_base_75") +def roberta_base_architecture(args): + args.ffn_modules = getattr(args, "ffn_modules", False) + args.adapter_modules = getattr(args, "adapter_modules", True) + args.adapter_layer_norm = getattr(args, "adapter_layer_norm", False) + args.adapter_reuse_layer_norm = getattr(args, "adapter_reuse_layer_norm", True) + args.ln_before_adapter = getattr(args, "ln_before_adapter", True) + args.languages = getattr( + args, + "languages", + [ + "af_ZA", + "am_ET", + "ar_AR", + "as_IN", + "be_BY", + "bn_IN", + "br_FR", + "bs_BA", + "ca_ES", + "cs_CZ", + "cy_GB", + "da_DK", + "en_XX", + "eo_EO", + "et_EE", + "eu_ES", + "fa_IR", + "fi_FI", + "fr_XX", + "fy_NL", + "ga_IE", + "gd_GB", + "gl_ES", + "gu_IN", + "ha_NG", + "hi_IN", + "hr_HR", + "hu_HU", + "hy_AM", + "id_ID", + "is_IS", + "it_IT", + "jv_ID", + "ka_GE", + "kn_IN", + "ko_KR", + "ku_TR", + "la_VA", + "lt_LT", + "lv_LV", + "mg_MG", + "mk_MK", + "ml_IN", + "mn_MN", + "mr_IN", + "ms_MY", + "ne_NP", + "nl_XX", + "no_XX", + "om_KE", + "or_IN", + "pa_IN", + "pl_PL", + "ps_AF", + "pt_XX", + "ro_RO", + "ru_RU", + "sa_IN", + "sd_PK", + "si_LK", + "sk_SK", + "sl_SI", + "so_SO", + "sq_AL", + "sr_RS", + "su_ID", + "sv_SE", + "sw_KE", + "ta_IN", + "te_IN", + "th_TH", + "tl_XX", + "vi_VN", + "xh_ZA", + "yi_DE", + ], + ) + base_architecture(args) + + +@register_model_architecture("xmod", "xmod_base") +def roberta_base_architecture(args): + args.ffn_modules = getattr(args, "ffn_modules", False) + args.adapter_modules = getattr(args, "adapter_modules", True) + args.adapter_layer_norm = getattr(args, "adapter_layer_norm", False) + args.adapter_reuse_layer_norm = getattr(args, "adapter_reuse_layer_norm", True) + args.ln_before_adapter = getattr(args, "ln_before_adapter", True) + args.languages = getattr( + args, + "languages", + [ + "en_XX", + "id_ID", + "vi_VN", + "ru_RU", + "fa_IR", + "sv_SE", + "ja_XX", + "fr_XX", + "de_DE", + "ro_RO", + "ko_KR", + "hu_HU", + "es_XX", + "fi_FI", + "uk_UA", + "da_DK", + "pt_XX", + "no_XX", + "th_TH", + "pl_PL", + "bg_BG", + "nl_XX", + "zh_CN", + "he_IL", + "el_GR", + "it_IT", + "sk_SK", + "hr_HR", + "tr_TR", + "ar_AR", + "cs_CZ", + "lt_LT", + "hi_IN", + "zh_TW", + "ca_ES", + "ms_MY", + "sl_SI", + "lv_LV", + "ta_IN", + "bn_IN", + "et_EE", + "az_AZ", + "sq_AL", + "sr_RS", + "kk_KZ", + "ka_GE", + "tl_XX", + "ur_PK", + "is_IS", + "hy_AM", + "ml_IN", + "mk_MK", + "be_BY", + "la_VA", + "te_IN", + "eu_ES", + "gl_ES", + "mn_MN", + "kn_IN", + "ne_NP", + "sw_KE", + "si_LK", + "mr_IN", + "af_ZA", + "gu_IN", + "cy_GB", + "eo_EO", + "km_KH", + "ky_KG", + "uz_UZ", + "ps_AF", + "pa_IN", + "ga_IE", + "ha_NG", + "am_ET", + "lo_LA", + "ku_TR", + "so_SO", + "my_MM", + "or_IN", + "sa_IN", + ], + ) + base_architecture(args) + + +@register_model_architecture("xmod", "xmod_large_prenorm") +def roberta_base_architecture(args): + args.ffn_modules = getattr(args, "ffn_modules", False) + args.adapter_modules = getattr(args, "adapter_modules", True) + args.adapter_layer_norm = getattr(args, "adapter_layer_norm", True) + args.adapter_reuse_layer_norm = getattr(args, "adapter_reuse_layer_norm", False) + args.ln_before_adapter = getattr(args, "ln_before_adapter", False) + # args.bottleneck = getattr(args, "bottleneck", 8) + args.bottleneck = getattr(args, "bottleneck", 4) + args.languages = getattr( + args, + "languages", + [ + "en_XX", + "id_ID", + "vi_VN", + "ru_RU", + "fa_IR", + "sv_SE", + "ja_XX", + "fr_XX", + "de_DE", + "ro_RO", + "ko_KR", + "hu_HU", + "es_XX", + "fi_FI", + "uk_UA", + "da_DK", + "pt_XX", + "no_XX", + "th_TH", + "pl_PL", + "bg_BG", + "nl_XX", + "zh_CN", + "he_IL", + "el_GR", + "it_IT", + "sk_SK", + "hr_HR", + "tr_TR", + "ar_AR", + "cs_CZ", + "lt_LT", + "hi_IN", + "zh_TW", + "ca_ES", + "ms_MY", + "sl_SI", + "lv_LV", + "ta_IN", + "bn_IN", + "et_EE", + "az_AZ", + "sq_AL", + "sr_RS", + "kk_KZ", + "ka_GE", + "tl_XX", + "ur_PK", + "is_IS", + "hy_AM", + "ml_IN", + "mk_MK", + "be_BY", + "la_VA", + "te_IN", + "eu_ES", + "gl_ES", + "mn_MN", + "kn_IN", + "ne_NP", + "sw_KE", + "si_LK", + "mr_IN", + "af_ZA", + "gu_IN", + "cy_GB", + "eo_EO", + "km_KH", + "ky_KG", + "uz_UZ", + "ps_AF", + "pa_IN", + "ga_IE", + "ha_NG", + "am_ET", + "lo_LA", + "ku_TR", + "so_SO", + "my_MM", + "or_IN", + "sa_IN", + ], + ) + + args.encoder_normalize_before = getattr(args, "encoder_normalize_before", True) + args.encoder_layers = getattr(args, "encoder_layers", 24) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) + base_architecture(args) diff --git a/fairseq/models/xmod/transformer_layer_xmod.py b/fairseq/models/xmod/transformer_layer_xmod.py new file mode 100644 index 0000000000..47a91cdc23 --- /dev/null +++ b/fairseq/models/xmod/transformer_layer_xmod.py @@ -0,0 +1,179 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from fairseq.modules.transformer_layer import TransformerEncoderLayer +from typing import Optional +import torch +import torch.nn as nn +from fairseq import utils +from fairseq.modules import LayerNorm +from fairseq.modules.fairseq_dropout import FairseqDropout +from fairseq.modules.quant_noise import quant_noise +from torch import Tensor + + +class Adapter(nn.Module): + def __init__(self, cfg, red_fac=2): + super(Adapter, self).__init__() + self.cfg = cfg + self.embed_dim = cfg.encoder_embed_dim + self.quant_noise = getattr(cfg, "quant_noise_pq", 0) + self.quant_noise_block_size = getattr(cfg, "quant_noise_pq_block_size", 8) or 8 + self.activation_fn = utils.get_activation_fn( + activation=getattr(cfg, "activation_fn", "relu") or "relu" + ) + self.fc1 = quant_noise( + nn.Linear(self.embed_dim, self.embed_dim // red_fac), + p=self.quant_noise, + block_size=self.quant_noise_block_size, + ) + self.fc2 = quant_noise( + nn.Linear(self.embed_dim // red_fac, self.embed_dim), + p=self.quant_noise, + block_size=self.quant_noise_block_size, + ) + activation_dropout_p = getattr(cfg, "activation_dropout", 0) or 0 + if activation_dropout_p == 0: + # for backwards compatibility with models that use cfg.relu_dropout + activation_dropout_p = getattr(cfg, "relu_dropout", 0) or 0 + self.activation_dropout_module = FairseqDropout( + float(activation_dropout_p), module_name=self.__class__.__name__ + ) + + def forward(self, x): + x = self.activation_fn(self.fc1(x)) + if not hasattr(self.cfg, "adapter_dropout") or self.cfg.adapter_dropout: + x = self.activation_dropout_module(x) + x = self.fc2(x) + return x + + +class XMODTransformerEncoderLayerBase(TransformerEncoderLayer): + """Encoder layer block. + + In the original paper each operation (multi-head attention or FFN) is + postprocessed with: `dropout -> add residual -> layernorm`. In the + tensor2tensor code they suggest that learning is more robust when + preprocessing each layer with layernorm and postprocessing with: + `dropout -> add residual`. We default to the approach in the paper, but the + tensor2tensor approach can be enabled by setting + *cfg.encoder.normalize_before* to ``True``. + + Args: + args (argparse.Namespace): parsed command-line arguments + """ + + def __init__(self, cfg): + super().__init__(cfg) + if hasattr(cfg, "adapter_modules") and cfg.adapter_modules: + export = getattr(cfg, "export", False) + if cfg.adapter_layer_norm: + self.adapter_layer_norm = LayerNorm(self.embed_dim, export=export) + self.adapter_modules = nn.ModuleDict(dict()) + if hasattr(self.cfg, "bottleneck"): + bottleneck = self.cfg.bottleneck + else: + bottleneck = 2 + for language in cfg.languages: + self.adapter_modules[str(language)] = Adapter(cfg, red_fac=bottleneck) + + def lang_adapter(self, lang_id, x): + # If language adapters exist pass throught them + if hasattr(self.cfg, "adapter_modules") and self.cfg.adapter_modules: + if lang_id is None: + lang_id = ["en_XX"] * x.shape[1] + d_langs = [lang_id[0]] + lang_lengths = [1] + for lang in lang_id[1:]: + if lang == d_langs[-1]: + lang_lengths[-1] += 1 + else: + d_langs.append(lang) + lang_lengths.append(1) + + if ( + not hasattr(self.cfg, "ln_before_adapter") + or not self.cfg.ln_before_adapter + ): + residual = x + if self.cfg.adapter_layer_norm: + x = self.adapter_layer_norm(x) + elif self.cfg.adapter_reuse_layer_norm: + x = self.final_layer_norm(x) + if hasattr(self.cfg, "ln_before_adapter") and self.cfg.ln_before_adapter: + residual = x + + split_x = torch.split(x, lang_lengths, 1) + x_ = [] + for i, (lang, s_x) in enumerate(zip(d_langs, split_x)): + lang = lang.replace("_rom", "").replace("_zaw", "") + x_.append(self.adapter_modules[str(lang)](s_x)) + x = torch.cat(x_, 1) + + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + + return x + + def forward( + self, + x, + encoder_padding_mask: Optional[Tensor], + attn_mask: Optional[Tensor] = None, + lang_id: Optional[list] = None, + ): + """ + Args: + x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)` + encoder_padding_mask (ByteTensor): binary ByteTensor of shape + `(batch, seq_len)` where padding elements are indicated by ``1``. + attn_mask (ByteTensor): binary tensor of shape `(tgt_len, src_len)`, + where `tgt_len` is the length of output and `src_len` is the + length of input, though here both are equal to `seq_len`. + `attn_mask[tgt_i, src_j] = 1` means that when calculating the + embedding for `tgt_i`, we exclude (mask out) `src_j`. This is + useful for strided self-attention. + + Returns: + encoded output of shape `(seq_len, batch, embed_dim)` + """ + # anything in original attn_mask = 1, becomes -1e8 + # anything in original attn_mask = 0, becomes 0 + # Note that we cannot use -inf here, because at some edge cases, + # the attention weight (before softmax) for some padded element in query + # will become -inf, which results in NaN in model parameters + if attn_mask is not None: + attn_mask = attn_mask.masked_fill(attn_mask.to(torch.bool), -1e8) + + residual = x + if self.normalize_before: + x = self.self_attn_layer_norm(x) + x, _ = self.self_attn( + query=x, + key=x, + value=x, + key_padding_mask=encoder_padding_mask, + need_weights=False, + attn_mask=attn_mask, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) + + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + + x = self.lang_adapter(lang_id, x) + + if not self.normalize_before: + x = self.final_layer_norm(x) + return x diff --git a/fairseq/tasks/sentence_prediction_adapters.py b/fairseq/tasks/sentence_prediction_adapters.py new file mode 100644 index 0000000000..afe5569626 --- /dev/null +++ b/fairseq/tasks/sentence_prediction_adapters.py @@ -0,0 +1,56 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging + +import contextlib +from omegaconf import open_dict, OmegaConf + +from fairseq.tasks import register_task +from fairseq.tasks.sentence_prediction import ( + SentencePredictionTask, + SentencePredictionConfig, +) + + +logger = logging.getLogger(__name__) + + +@register_task("sentence_prediction_adapters", dataclass=SentencePredictionConfig) +class SentencePredictionAdapterTask(SentencePredictionTask): + def build_model(self, cfg): + from fairseq import models + + with open_dict(cfg) if OmegaConf.is_config(cfg) else contextlib.ExitStack(): + cfg.max_positions = self.cfg.max_positions + + model = models.build_model(cfg, self) + + model.register_classification_head( + self.cfg.classification_head_name, + num_classes=self.cfg.num_classes, + ) + + logger.info("Freezing Embedding Parameters") + for parameter in model.encoder.sentence_encoder.embed_positions.parameters(): + parameter.requires_grad = False + for ( + parameter + ) in model.encoder.sentence_encoder.layernorm_embedding.parameters(): + parameter.requires_grad = False + for parameter in model.encoder.sentence_encoder.embed_tokens.parameters(): + parameter.requires_grad = False + + logger.info("Freezing Adapters") + for k, v in model.encoder.sentence_encoder.layers._modules.items(): + logger.info("Freezing Adapters in Layer " + str(k)) + if hasattr(v, "adapter_layer_norm"): + logger.info("Freezing Adapter LN") + for parameter in v.adapter_layer_norm.parameters(): + parameter.requires_grad = False + for parameter in v.adapter_modules.parameters(): + parameter.requires_grad = False + + return model From f7303c30297bae757ecb9247635636ccc3e99812 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Thu, 12 May 2022 16:54:07 -0700 Subject: [PATCH 619/774] format fix (#4418) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes failing build error. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/pytorch/fairseq/pull/4418 Reviewed By: yuntang Differential Revision: D36325742 Pulled By: dianaml0 fbshipit-source-id: d68d04dc01eac0f776ba06534cdf846d9d45fe0b --- fairseq/models/speech_to_text/s2t_transformer.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 4ffbeaeecb..4b43e1acb5 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -295,15 +295,15 @@ def get_ctc_target(self, sample: Optional[Dict[str, Tensor]]): return sample["target"], sample["target_lengths"] def get_ctc_output( - self, - net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], - sample: Optional[Dict[str, Tensor]] + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + sample: Optional[Dict[str, Tensor]], ): encoder_out = net_output[1]["encoder_out"]["encoder_out"][0] logits = self.encoder.ctc_proj(encoder_out) # T x B x C out = utils.log_softmax(logits.float(), dim=-1) padding_mask = net_output[1]["encoder_out"]["encoder_padding_mask"] - lens = out.new_full((out.shape[1], ), out.shape[0]).long() + lens = out.new_full((out.shape[1],), out.shape[0]).long() if len(padding_mask) > 0: lens -= padding_mask[0].sum(dim=-1) return out, lens @@ -359,7 +359,7 @@ def __init__(self, args): self.layer_norm = None self.ctc_proj = None - if getattr(args, "ctc_weight", 0.) > 0.: + if getattr(args, "ctc_weight", 0.0) > 0.0: self.ctc_proj = nn.Linear(args.encoder_embed_dim, args.tgt_dict_size) def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): From eb2d7862c29990e5be35ee227a6952ae21d621a1 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 12 May 2022 18:59:18 -0700 Subject: [PATCH 620/774] fix ema memory leak (#3384) Summary: fixes memory leak in ema module by making sure the update happens in no_grad regime X-link: https://github.com/fairinternal/fairseq-py/pull/3384 Reviewed By: arbabu123 Differential Revision: D36352890 Pulled By: alexeib fbshipit-source-id: 0f3575ac356a13483e00ed431375b2c798621a3a --- fairseq/modules/ema_module.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/fairseq/modules/ema_module.py b/fairseq/modules/ema_module.py index 77c21f0ab2..a5b98861d8 100644 --- a/fairseq/modules/ema_module.py +++ b/fairseq/modules/ema_module.py @@ -98,7 +98,7 @@ def _step_internal(self, new_model): ema_params = ( self.fp32_params if self.config.ema_fp32 else self.model.state_dict() ) - for key, param in new_model.state_dict().items(): + for key, param in new_model.named_parameters(): if isinstance(param, dict): continue try: @@ -107,6 +107,7 @@ def _step_internal(self, new_model): ema_param = ( param.float().clone() if param.ndim == 1 else copy.deepcopy(param) ) + ema_params[key] = ema_param if param.shape != ema_param.shape: raise ValueError( @@ -118,15 +119,21 @@ def _step_internal(self, new_model): # Do not decay a model.version pytorch param continue - if key in self.skip_keys: - ema_param = param.to(dtype=ema_param.dtype).clone() - ema_params[key].copy_(ema_param) + if key in self.skip_keys or not param.requires_grad: + ema_params[key].copy_(param.to(dtype=ema_param.dtype).data) + ema_param = ema_params[key] else: ema_param.mul_(decay) - ema_param.add_(param.to(dtype=ema_param.dtype), alpha=1 - decay) + ema_param.add_(param.data.to(dtype=ema_param.dtype), alpha=1 - decay) + ema_state_dict[key] = ema_param + + for key, param in new_model.named_buffers(): + ema_state_dict[key] = param + self.restore(ema_state_dict, build_fp32_params=False) + @torch.no_grad() def step(self, new_model): self._step_internal(new_model) From b5a039c292facba9c73f59ff34621ec131d82341 Mon Sep 17 00:00:00 2001 From: Mikel Artetxe <artetxe@fb.com> Date: Fri, 13 May 2022 09:29:21 -0700 Subject: [PATCH 621/774] Add X-MOD paper citation (#3386) Summary: Add a link and bibtex citation to the X-MOD paper X-link: https://github.com/fairinternal/fairseq-py/pull/3386 Reviewed By: ngoyal2707 Differential Revision: D36377376 Pulled By: artetxem fbshipit-source-id: 84540b90dbea8502ba5fecfcbdb60164e4fb801e --- examples/xmod/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/examples/xmod/README.md b/examples/xmod/README.md index 62aa215efc..46958b8141 100644 --- a/examples/xmod/README.md +++ b/examples/xmod/README.md @@ -1,5 +1,10 @@ # X-MOD: Lifting the Curse of Multilinguality by Pre-training Modular Transformers +https://arxiv.org/abs/2205.06266 + + +## Introduction + X-MOD extends multilingual masked language models like XLM-R to include language-specific modular components, introduced at each transformer layer. Each module is only used by one language. For fine-tuning, the modular components are frozen, and replaced with the target language in cross-lingual transfer settings. @@ -131,3 +136,16 @@ predict( lang='eu_ES', ) # neutral ``` + + +## Citation + +```bibtex +@misc{pfeiffer2022xmod, + doi = {10.48550/ARXIV.2205.06266}, + url = {https://arxiv.org/abs/2205.06266}, + title = {Lifting the Curse of Multilinguality by Pre-training Modular Transformers}, + publisher = {arXiv}, + year = {2022}, +} +``` From b5e7b250913120409b872a940fbafec4d43c7b13 Mon Sep 17 00:00:00 2001 From: code-review-doctor <contact+django-doctor-test@richardtier.co.uk> Date: Mon, 23 May 2022 16:26:35 -0700 Subject: [PATCH 622/774] Missing `f` prefix on f-strings fix (#4380) Summary: Fixes https://github.com/facebookresearch/fairseq/issues/4379 Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4380 Reviewed By: cbalioglu Differential Revision: D36454259 Pulled By: dianaml0 fbshipit-source-id: cf47b4d4c5e80e1f3bc5b400e40f1192dfa84933 --- fairseq/data/huffman/huffman_mmap_indexed_dataset.py | 2 +- fairseq/data/iterators.py | 2 +- fairseq/data/multilingual/multilingual_data_manager.py | 4 ++-- fairseq_cli/eval_lm.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fairseq/data/huffman/huffman_mmap_indexed_dataset.py b/fairseq/data/huffman/huffman_mmap_indexed_dataset.py index 3279dae89a..9b098f2c2b 100644 --- a/fairseq/data/huffman/huffman_mmap_indexed_dataset.py +++ b/fairseq/data/huffman/huffman_mmap_indexed_dataset.py @@ -70,7 +70,7 @@ def __init__(self, path): (version,) = struct.unpack("<Q", stream.read(8)) assert ( self._VERSION == version - ), "Unexpected file version f{version} != code version f{self._VERSION}" + ), f"Unexpected file version{version} != code version {self._VERSION}" # read length of data file (self._data_len,) = struct.unpack("<Q", stream.read(8)) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 1d8e179f8b..beb681fc70 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -57,7 +57,7 @@ def __next__(self): except StopIteration: raise IndexError( f"Iterator expected to have length {self.total}, " - "but exhausted at position {self.n}." + f"but exhausted at position {self.n}." ) self.n += 1 return x diff --git a/fairseq/data/multilingual/multilingual_data_manager.py b/fairseq/data/multilingual/multilingual_data_manager.py index 8dae99d99f..876dfcec36 100644 --- a/fairseq/data/multilingual/multilingual_data_manager.py +++ b/fairseq/data/multilingual/multilingual_data_manager.py @@ -919,7 +919,7 @@ def get_split_num_data_shards(self, split): # monolingual data requires tgt only assert src is None or src == tgt, ( f"error: src={src}, " - "tgt={tgt} for data_category={data_category}" + f"tgt={tgt} for data_category={data_category}" ) num_shards_dict[key] = shards_dict[tgt] else: @@ -972,7 +972,7 @@ def get_split_data_param_list(self, split, epoch, shard_epoch=None): lang_dirs = [x if len(x) > 1 else (x[0], x[0]) for x in lang_dirs] for src, tgt in lang_dirs: assert src is not None or data_category == "mono_dae", ( - f"error: src={src}, " "tgt={tgt} for data_category={data_category}" + f"error: src={src}, " f"tgt={tgt} for data_category={data_category}" ) # logger.info(f"preparing param for {data_category}: {src} - {tgt}") key = self.get_dataset_key(data_category, src, tgt) diff --git a/fairseq_cli/eval_lm.py b/fairseq_cli/eval_lm.py index 250c766edd..dbd1450a9e 100644 --- a/fairseq_cli/eval_lm.py +++ b/fairseq_cli/eval_lm.py @@ -95,7 +95,7 @@ def eval_lm( } else: raise NotImplementedError( - "--post-process={post_process} is not implemented" + f"--post-process={post_process} is not implemented" ) bpe_len = len(bpe_cont) else: From e0884db9a7ce83670e21af39bf785b616ce5e3e3 Mon Sep 17 00:00:00 2001 From: Jongsoo Park <jongsoo@fb.com> Date: Thu, 26 May 2022 21:14:17 -0700 Subject: [PATCH 623/774] don't use half precision in test_ema on CPU (#3408) Summary: X-link: https://github.com/fairinternal/fairseq-py/pull/3408 Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4443 To fix errors introduced in D35571505 Reviewed By: ngimel Differential Revision: D36726254 fbshipit-source-id: dde8964c47426839b03c842574669ae9428031c6 --- tests/test_ema.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/test_ema.py b/tests/test_ema.py index 2c68185357..847316ff48 100644 --- a/tests/test_ema.py +++ b/tests/test_ema.py @@ -160,14 +160,17 @@ def test_ema_after_start_update(self): self._test_ema_start_update(updates=1) def test_ema_fp32(self): - model = DummyModule().half() + # CPU no longer supports Linear in half precision + dtype = torch.half if torch.cuda.is_available() else torch.float + + model = DummyModule().to(dtype) optimizer = torch.optim.SGD(model.parameters(), lr=0.01) state = deepcopy(model.state_dict()) config = EMAConfig(ema_fp32=True) ema = EMA(model, config) x = torch.randn(32) - y = model(x.half()) + y = model(x.to(dtype)) loss = y.sum() loss.backward() optimizer.step() @@ -192,7 +195,7 @@ def test_ema_fp32(self): config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float() ) - .half() + .to(dtype) .float() ), torch.norm( @@ -207,10 +210,14 @@ def test_ema_fp32(self): ( config.ema_decay * prev_param.float() + (1 - config.ema_decay) * param.float() - ).half(), + ).to(dtype), ) def test_ema_fp16(self): + # CPU no longer supports Linear in half precision + if not torch.cuda.is_available(): + return + model = DummyModule().half() optimizer = torch.optim.SGD(model.parameters(), lr=0.01) state = deepcopy(model.state_dict()) From 86f706577d7b21377ff978d4761af50867213318 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Tue, 31 May 2022 08:52:43 -0700 Subject: [PATCH 624/774] CircleCI deprecating Ubuntu 16.04-based machine images (#4218) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4218 Reviewed By: cbalioglu Differential Revision: D36681610 Pulled By: dianaml0 fbshipit-source-id: fb47c1df91cf73eabe082783c852a6a66b8831e3 --- .circleci/config.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ff7237c441..59a244f346 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,9 +6,9 @@ version: 2.1 # ------------------------------------------------------------------------------------- gpu: &gpu environment: - CUDA_VERSION: "11.1" + CUDA_VERSION: "11.2" machine: - image: ubuntu-1604-cuda-11.1:202012-01 + image: ubuntu-2004-cuda-11.2:202103-01 resource_class: gpu.nvidia.medium.multi @@ -39,6 +39,7 @@ install_dep_fused_ops: &install_dep_fused_ops git clone https://github.com/NVIDIA/apex cd apex git checkout e2083df5eb96643c61613b9df48dd4eea6b07690 + sed -i '101,107 s/^/#/' setup.py pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" --global-option="--deprecated_fused_adam" --global-option="--xentropy" --global-option="--fast_multihead_attn" ./ cd ~/ git clone --depth=1 --branch v2.4 https://github.com/NVIDIA/Megatron-LM.git From e35c593c84bd84d5c7777ef7ace98dab508ff88e Mon Sep 17 00:00:00 2001 From: Ilia Kulikov <kulikov@fb.com> Date: Wed, 1 Jun 2022 20:31:50 -0700 Subject: [PATCH 625/774] xm transformer decoder arg loading & optional weight norm remove (#3400) Summary: First part of the diff is the copy of https://github.com/fairinternal/fairseq-py/pull/3308 with slight change: now check arg where 'decoder' appears anywhere in the arg in order to catch args like '--share-decoder-input-output-embed`. This is how it looks like in the log: ``` 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg decoder_normalize_before: from False to True 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg decoder_layers: from 12 to 6 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg decoder_attention_heads: from 16 to 12 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg decoder_embed_dim: from 1024 to 768 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg decoder_ffn_embed_dim: from 4096 to 3072 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg share_decoder_input_output_embed: from False to True 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg decoder_output_dim: from 1024 to 768 2022-05-20 16:19:52 | WARNING | fairseq.models.speech_to_text.xm_transformer | Overriding decoder arg decoder_input_dim: from 1024 to 768 ``` Second part of the diff is about `--remove-weight-norm` encoder argument. Weight norm happens only *once* in w2v. It breaks any code which tries to use deepcopy of the model such as stochastic weight averaging or exponential moving average (EMA) of the model. Removing weightnorm has no effect on the weights, so it does not corrupt model weights. Example log: ``` 2022-05-20 16:06:09 | WARNING | fairseq.models.speech_to_text.xm_transformer | Removing weight norm from wav2vec encoder 2022-05-20 16:06:09 | WARNING | fairseq.models.speech_to_text.xm_transformer | Weight norm removed from module with Conv1d(1024, 1024, kernel_size=(128,), stride=(1,), padding=(64,), groups=16) ``` Gpu tests are passed for this diff. X-link: https://github.com/fairinternal/fairseq-py/pull/3400 Reviewed By: kahne Differential Revision: D36785559 Pulled By: uralik fbshipit-source-id: 053a2f79549ceeb1357f09d1aefab77ac5581c20 --- .../models/speech_to_text/xm_transformer.py | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index afd8ead93b..b21ff823cf 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -239,6 +239,12 @@ def add_wav2vec_asr_args(parser): parser.add_argument("--w2v-args", default=None) + parser.add_argument( + "--remove-weight-norm", + action="store_true", + help="if set, then the weight-norm (in one pos_conv layer) is removed from the model", + ) + def need_finetuning(ft_params, param_name): if ft_params == "all": @@ -441,6 +447,23 @@ def add_decoder_args(parser): ) +def remove_weight_norm_from_model(model): + from functools import reduce + + layers_with_wn = [] + for param_name, _ in model.named_parameters(): + if param_name.endswith("_g"): + # retrieve the module with this param_name + module_names = param_name.split(".")[ + :-1 + ] # exclude the actual parameter name + wn_module = reduce(getattr, module_names, model) + layers_with_wn.append(wn_module) + for wn_module in layers_with_wn: + torch.nn.utils.remove_weight_norm(wn_module) + logger.warning(f"Weight norm removed from module with {wn_module}\n") + + @register_model("xm_transformer") class XMTransformerModel(FairseqEncoderDecoderModel): @classmethod @@ -527,9 +550,36 @@ def build_encoder(cls, args): del state encoder = Wav2VecEncoderWithAdaptor(_args) - return cls.maybe_load_pretrained( + encoder = cls.maybe_load_pretrained( encoder, getattr(args, "load_pretrained_encoder_from", None) ) + if args.remove_weight_norm: + # remove the wn for EMA usage + logger.warning("Removing weight norm from wav2vec encoder") + remove_weight_norm_from_model(encoder) + + return encoder + + @classmethod + def get_decoder_args_from_checkpoint(cls, ckpt_args): + assert "model" in ckpt_args, "Model args not found in checkpoint cfg!" + decoder_args = {} + for k, v in ckpt_args["model"].__dict__.items(): + if "decoder" in k: + decoder_args[k] = v + + return decoder_args + + @classmethod + def override_decoder_args(cls, cli_args, decoder_args_dict): + for k, v in decoder_args_dict.items(): + if v != getattr(cli_args, k, None): + logger.warning( + f"Overriding decoder arg {k}: from {getattr(cli_args, k, None)} to {v}" + ) + setattr(cli_args, k, v) + + return cli_args @classmethod def build_decoder(cls, args, task, embed_tokens): @@ -555,6 +605,10 @@ def build_model(cls, args, task): # make sure all arguments are present in older models base_architecture(args) + if getattr(args, "load_pretrained_decoder_from", None): + ckpt = torch.load(getattr(args, "load_pretrained_decoder_from", None)) + decoder_args_dict = cls.get_decoder_args_from_checkpoint(ckpt["cfg"]) + args = cls.override_decoder_args(args, decoder_args_dict) def build_embedding(dictionary, embed_dim): num_embeddings = len(dictionary) @@ -608,6 +662,7 @@ def set_default_w2v_encoder_args(args): args.attention_dropout = getattr(args, "attention_dropout", 0) args.activation_dropout = getattr(args, "activation_dropout", 0) args.encoder_proj = getattr(args, "encoder_proj", False) + args.remove_weight_norm = getattr(args, "remove_weight_norm", False) args.mask_length = getattr(args, "mask_length", 10) args.mask_prob = getattr(args, "mask_prob", 0.5) From f97cdf76d9cd20b16c3ff51f46382c2ed639bd17 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Fri, 3 Jun 2022 09:13:15 -0700 Subject: [PATCH 626/774] Working Build Wheels for Fairseq (#4206) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Build wheels was broken. - [x] get build wheels to work successfully - [x] update the fairseq version - [x] Bump up the python version - [x] skip musllinux builds followup improvements incoming in another PR ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4206 Reviewed By: cbalioglu Differential Revision: D36880560 Pulled By: dianaml0 fbshipit-source-id: 91c538e785c5ed107b17b8093afa1d3ce387f56a --- .github/workflows/build_wheels.yml | 14 +++++++++++--- fairseq/version.txt | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index 7261708596..acd828e809 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -21,19 +21,27 @@ jobs: - name: Install Python uses: actions/setup-python@v2 with: - python-version: '3.7' + python-version: '3.8' + + - name: Upgrade pip + run: | + python3 -m pip install --upgrade pip - name: Install cibuildwheel run: | - python -m pip install cibuildwheel + python3 -m pip install cibuildwheel - name: Build wheels for CPython run: | - python -m cibuildwheel --output-dir dist + python3 -m cibuildwheel --output-dir dist env: CIBW_BUILD: "cp36-*64 cp37-*64 cp38-*64" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . + # Install system library + CIBW_BEFORE_BUILD_LINUX: yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true + CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" + CIBW_SKIP: "*musllinux*" - uses: actions/upload-artifact@v2 with: diff --git a/fairseq/version.txt b/fairseq/version.txt index 41432f00d9..d9df1bbc0c 100644 --- a/fairseq/version.txt +++ b/fairseq/version.txt @@ -1 +1 @@ -1.0.0a0 +0.11.0 From 97b2d8153babe06d3580add6eb512c7e2fbc0fc6 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Wed, 8 Jun 2022 16:23:48 -0700 Subject: [PATCH 627/774] Auto release (#4455) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Automates release process and allows it to be triggered directly. Heavily inspired by fairscale's release setup. Few improvements in followup PR. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4455 Reviewed By: cbalioglu Differential Revision: D36993777 Pulled By: dianaml0 fbshipit-source-id: bfa9663c3a7d20dd7ebf690e182d7f8102328c08 --- .github/workflows/build_wheels.yml | 49 ------------ .github/workflows/release.yml | 119 +++++++++++++++++++++++++++++ release_utils.py | 72 +++++++++++++++++ 3 files changed, 191 insertions(+), 49 deletions(-) delete mode 100644 .github/workflows/build_wheels.yml create mode 100644 .github/workflows/release.yml create mode 100644 release_utils.py diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml deleted file mode 100644 index acd828e809..0000000000 --- a/.github/workflows/build_wheels.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: build_wheels - -on: - push: - branches: - - v[0-9]+.[0-9]+.[x0-9]+ - tags: - - v* - -jobs: - build_wheels: - name: Build wheels on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - - steps: - - uses: actions/checkout@v2 - - - name: Install Python - uses: actions/setup-python@v2 - with: - python-version: '3.8' - - - name: Upgrade pip - run: | - python3 -m pip install --upgrade pip - - - name: Install cibuildwheel - run: | - python3 -m pip install cibuildwheel - - - name: Build wheels for CPython - run: | - python3 -m cibuildwheel --output-dir dist - env: - CIBW_BUILD: "cp36-*64 cp37-*64 cp38-*64" - CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 - CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . - # Install system library - CIBW_BEFORE_BUILD_LINUX: yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true - CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" - CIBW_SKIP: "*musllinux*" - - - uses: actions/upload-artifact@v2 - with: - name: wheels - path: ./dist/*.whl diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..671f0c2819 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,119 @@ +name: Fairseq Release + +on: + workflow_dispatch: + inputs: + name: + description: 'Release Type' + default: 'patch' + required: true + +jobs: + + get_next_version: + runs-on: ubuntu-latest + steps: + - name: checkout-repo-content + uses: actions/checkout@v2 + + - name: setup-python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: get next version and tag + id: get-next-version-and-tag + run: | + output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }}) + echo $output + new_version=$(echo $output | awk '{print $1}') + new_tag=$(echo $output | awk '{print $2}') + echo "new version is $new_version" + echo "new tag is $new_tag" + echo ::set-output name=version::$new_version + echo ::set-output name=tag::$new_tag + outputs: + new_version: ${{ steps.get-next-version-and-tag.outputs.version }} + new_tag: ${{ steps.get-next-version-and-tag.outputs.tag }} + + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + needs: get_next_version + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + + steps: + - uses: actions/checkout@v2 + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + + # update the version number in version.txt + - name: update version + id: update-version + run : | + echo "current folder = $PWD" + echo "current branch = $(git branch --show-current)" + output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }}--update-version) + + - name: Upgrade pip + run: | + python3 -m pip install --upgrade pip + + - name: Create Source Distribution + run: | + pip install setuptools wheel twine + python3 setup.py sdist + + - name: Install cibuildwheel + run: | + python3 -m pip install cibuildwheel + + - name: Build wheels for CPython + run: | + python3 -m cibuildwheel --output-dir dist + env: + CIBW_BUILD: "cp36-*64 cp37-*64 cp38-*64" + CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 + CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . + # Install system library + CIBW_BEFORE_BUILD_LINUX: yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true + CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" + CIBW_SKIP: "*musllinux*" + + # build the PyPI package and upload it + - name: upload + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + run: | + python3 -m twine upload --repository pypi dist/* + + # add and commit the updated version.py to main + - name: add and commit + if: ${{ matrix.os=='ubuntu-latest' }} + uses: EndBug/add-and-commit@v9 + with: + author_name: ${{ secrets.AUTHOR_NAME }} + author_email: ${{ secrets.AUTHOR_EMAIL }} + + # TODO: change this to main once shipit is disabled. + new_branch: ${{ needs.get_next_version.outputs.new_version }} + default_author: github_actor + message: '${{ needs.get_next_version.outputs.new_version }} release' + pathspec_error_handling: exitAtEnd + + # Arguments for the git pull command. Use NO-PULL to avoid the action pulling at all. + # pull: 'NO-PULL' + tag: '${{ needs.get_next_version.outputs.new_tag }}' + + # create the release on github + - name: create release on github + if: ${{ matrix.os=='ubuntu-latest' }} + uses: ncipollo/release-action@v1 + with: + tag: '${{ needs.get_next_version.outputs.new_tag }}' diff --git a/release_utils.py b/release_utils.py new file mode 100644 index 0000000000..69a5e8dda3 --- /dev/null +++ b/release_utils.py @@ -0,0 +1,72 @@ +import argparse +from typing import Tuple + + +def get_next_version(release_type) -> Tuple[Tuple[int, int, int], str, str]: + current_ver = find_version("fairseq/version.txt") + version_list = [int(x) for x in current_ver.strip("'").split(".")] + major, minor, patch = version_list[0], version_list[1], version_list[2] + if release_type == "patch": + patch += 1 + elif release_type == "minor": + minor += 1 + patch = 0 + elif release_type == "major": + major += 1 + minor = patch = 0 + else: + raise ValueError( + "Incorrect release type specified. Acceptable types are major, minor and patch." + ) + + new_version_tuple = (major, minor, patch) + new_version_str = ".".join([str(x) for x in new_version_tuple]) + new_tag_str = "v" + new_version_str + return new_version_tuple, new_version_str, new_tag_str + + +def find_version(version_file_path) -> str: + with open(version_file_path) as f: + version = f.read().strip() + return version + + +def update_version(new_version_str) -> None: + """ + given the current version, update the version to the + next version depending on the type of release. + """ + + with open("fairseq/version.txt", "w") as writer: + writer.write(new_version_str) + + +def main(args): + if args.release_type in ["major", "minor", "patch"]: + new_version_tuple, new_version, new_tag = get_next_version(args.release_type) + else: + raise ValueError("Incorrect release type specified") + + if args.update_version: + update_version(new_version) + + print(new_version, new_tag) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Versioning utils") + parser.add_argument( + "--release-type", + type=str, + required=True, + help="type of release = major/minor/patch", + ) + parser.add_argument( + "--update-version", + action="store_true", + required=False, + help="updates the version in fairseq/version.txt", + ) + + args = parser.parse_args() + main(args) From 44a86604cedaab6b49fbf1ec26a8c5ec4658d916 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 9 Jun 2022 11:20:55 -0700 Subject: [PATCH 628/774] Fix typo in release.yml (#4471) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4471 Reviewed By: cbalioglu Differential Revision: D37040680 Pulled By: dianaml0 fbshipit-source-id: f2ab6ab4dd410ea7784fe94d1386bccfd1956909 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 671f0c2819..45034854af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,7 +58,7 @@ jobs: run : | echo "current folder = $PWD" echo "current branch = $(git branch --show-current)" - output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }}--update-version) + output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }} --update-version) - name: Upgrade pip run: | From 3864ffa1f35dccecb67921d711fd0592ede6d8c1 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 9 Jun 2022 11:59:49 -0700 Subject: [PATCH 629/774] Document Release Process (#4466) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4466 Reviewed By: cbalioglu Differential Revision: D37040595 Pulled By: dianaml0 fbshipit-source-id: b834594c047fa786111a0ade81a7c7e4e2909625 --- RELEASE.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 RELEASE.md diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000000..2b05ab0d4b --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,13 @@ +# Creating a New Release + +In order to create a new release: + +1. Navigate to the [Fairseq Workflows](https://github.com/facebookresearch/fairseq/actions) and find the one named _Fairseq Release_. + +2. Under _Run Workflow_ choose the branch `main` and for _Release Type_ enter either `major`, `minor`, or `patch`. + +3. A branch with the same name as the new version will be created where the `version.txt` file is updated. Merge those changes into `main`. + +4. Make sure that a [new PYPI package](https://pypi.org/project/fairseq/) has been uploaded. + +5. Make sure that a [new github release](https://github.com/facebookresearch/fairseq/releases) has been created. From 10b797a44f1d724465cd66ce1bb92d6b8fa052eb Mon Sep 17 00:00:00 2001 From: Dawei Liang <liangdw@fb.com> Date: Thu, 9 Jun 2022 15:59:11 -0700 Subject: [PATCH 630/774] =?UTF-8?q?=E2=80=9Cnew=5Fcriterions=5Ffor=5Fend-p?= =?UTF-8?q?oint=5Fdetection=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: New regression loss for end point detection study Differential Revision: D36887730 fbshipit-source-id: d76eec81f686ecb2630f3a8be3aafdc7d222af61 --- fairseq/trainer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fairseq/trainer.py b/fairseq/trainer.py index ee7d103316..da1f949107 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -30,6 +30,7 @@ from fairseq.optim import lr_scheduler from fairseq.utils import safe_hasattr + logger = logging.getLogger(__name__) From c39fefccb013bfb8b1dc6cbbfabe1fd7ad4344a7 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 9 Jun 2022 16:13:26 -0700 Subject: [PATCH 631/774] Do not append commit hash to version (#4472) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4472 Reviewed By: cbalioglu Differential Revision: D37047097 Pulled By: dianaml0 fbshipit-source-id: 7cc67bb6661a393d7e5d15f1be7d35646cef5181 --- setup.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/setup.py b/setup.py index e2e44570c1..a7ce61a896 100644 --- a/setup.py +++ b/setup.py @@ -18,17 +18,6 @@ def write_version_py(): with open(os.path.join("fairseq", "version.txt")) as f: version = f.read().strip() - # append latest commit hash to version string - try: - sha = ( - subprocess.check_output(["git", "rev-parse", "HEAD"]) - .decode("ascii") - .strip() - ) - version += "+" + sha[:7] - except Exception: - pass - # write version info to fairseq/version.py with open(os.path.join("fairseq", "version.py"), "w") as f: f.write('__version__ = "{}"\n'.format(version)) From 3a72168bd81e5d3470c089746f62e191a4ad6f93 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 10 Jun 2022 06:55:45 -0700 Subject: [PATCH 632/774] Add CircleCI status badge (#4473) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4473 Reviewed By: cbalioglu Differential Revision: D37052250 Pulled By: dianaml0 fbshipit-source-id: e5e4c38a9108c769953ef2202c7adb8aa335771a --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a354e1b9ea..f7acbd15c3 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ <a href="https://github.com/pytorch/fairseq/releases"><img alt="Latest Release" src="https://img.shields.io/github/release/pytorch/fairseq.svg" /></a> <a href="https://github.com/pytorch/fairseq/actions?query=workflow:build"><img alt="Build Status" src="https://github.com/pytorch/fairseq/workflows/build/badge.svg" /></a> <a href="https://fairseq.readthedocs.io/en/latest/?badge=latest"><img alt="Documentation Status" src="https://readthedocs.org/projects/fairseq/badge/?version=latest" /></a> + <a href="https://app.circleci.com/pipelines/github/facebookresearch/fairseq/"><img alt="CicleCI Status" src="https://circleci.com/gh/facebookresearch/fairseq.svg?style=shield" /></a> </p> -------------------------------------------------------------------------------- From c42d11ca3e44dbb385a8b00f2cb8772a6ff2970b Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@fb.com> Date: Fri, 10 Jun 2022 10:08:44 -0700 Subject: [PATCH 633/774] 0.12.0 release (#4476) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4476 Reviewed By: shruti-bh Differential Revision: D37072342 Pulled By: dianaml0 fbshipit-source-id: c5343a766641d3939e3af1b61b62d8a03f4dae28 --- fairseq/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/version.txt b/fairseq/version.txt index d9df1bbc0c..d33c3a2128 100644 --- a/fairseq/version.txt +++ b/fairseq/version.txt @@ -1 +1 @@ -0.11.0 +0.12.0 \ No newline at end of file From fea865c079251cb383f1a2e6778f14e22d19e5cc Mon Sep 17 00:00:00 2001 From: Yun Tang <yuntang@fb.com> Date: Fri, 10 Jun 2022 11:08:26 -0700 Subject: [PATCH 634/774] Update Inference example in speech text joint training Summary: One command line was missing and it broke the test. It will address issue reported in https://github.com/facebookresearch/fairseq/issues/4462 Reviewed By: kahne Differential Revision: D37043373 fbshipit-source-id: e3f14b6aa1cbb603e4b23dfbaf8f57564b73d470 --- examples/speech_text_joint_to_text/docs/pre-training.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/speech_text_joint_to_text/docs/pre-training.md b/examples/speech_text_joint_to_text/docs/pre-training.md index 20272e6165..6d9e2cb0bb 100644 --- a/examples/speech_text_joint_to_text/docs/pre-training.md +++ b/examples/speech_text_joint_to_text/docs/pre-training.md @@ -79,7 +79,9 @@ python ./fairseq_cli/generate.py \ --gen-subset $SUBSET \ --config-yaml config.yaml \ --scoring wer \ - --beam 10 --lenpen 1.0 examples/speech_text_joint_to_text + --beam 10 --lenpen 1.0 examples/speech_text_joint_to_text \ + --user-dir examples/speech_text_joint_to_text --load-speech-only \ + --model-overrides {'load_pretrained_speech_text_decoder':'','load_pretrained_speech_text_encoder':''} ``` ### Results and models @@ -150,7 +152,9 @@ python fairseq_cli/generate.py \ --gen-subset $SUBSET \ --config-yaml config.yaml \ --scoring sacrebleu \ - --beam 10 --lenpen 1.0 examples/speech_text_joint_to_text + --beam 10 --lenpen 1.0 examples/speech_text_joint_to_text \ + --user-dir examples/speech_text_joint_to_text --load-speech-only \ + --model-overrides {'load_pretrained_speech_text_decoder':'','load_pretrained_speech_text_encoder':''} ``` From 73b42f0f3e397d896ed42ef7b2aaac9e3ead3676 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@devfair0471.h2.fair> Date: Sat, 11 Jun 2022 11:49:18 -0700 Subject: [PATCH 635/774] Refactor release.yml (#4475) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4475 Reviewed By: anupambhatnagar Differential Revision: D37081823 Pulled By: dianaml0 fbshipit-source-id: b5167aa66e0b873c5f466e1b16a27ca779802780 --- .github/workflows/release.yml | 109 +++++++++++++++++++++++----------- RELEASE.md | 2 +- 2 files changed, 76 insertions(+), 35 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 45034854af..b3aed1f514 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: - name: get next version and tag id: get-next-version-and-tag run: | - output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }}) + output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }}) echo $output new_version=$(echo $output | awk '{print $1}') new_tag=$(echo $output | awk '{print $2}') @@ -32,9 +32,66 @@ jobs: echo "new tag is $new_tag" echo ::set-output name=version::$new_version echo ::set-output name=tag::$new_tag + echo ::set-output name=branch_name::$new_version-release + echo "NEW_TAG=$new_tag" >> $GITHUB_ENV + echo "NEW_BRANCH=$new_version-release" >> $GITHUB_ENV + + + # update the version number in version.txt + - name: update version + id: update-version + run : | + echo "current folder = $PWD" + echo "current branch = $(git branch --show-current)" + output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }} --update-version) + + - name: add and commit + uses: EndBug/add-and-commit@v9 + with: + author_name: ${{ secrets.AUTHOR_NAME }} + author_email: ${{ secrets.AUTHOR_EMAIL }} + + # TODO: change this to main once shipit is disabled. + new_branch: '${{ env.NEW_BRANCH }}' + default_author: github_actor + message: '${{ env.NEW_TAG }} release' + pathspec_error_handling: exitAtEnd + + # Arguments for the git pull command. Use NO-PULL to avoid the action pulling at all. + # pull: 'NO-PULL' + tag: '${{ env.NEW_TAG }}' + outputs: new_version: ${{ steps.get-next-version-and-tag.outputs.version }} new_tag: ${{ steps.get-next-version-and-tag.outputs.tag }} + branch_name: ${{ steps.get-next-version-and-tag.outputs.branch_name }} + + create_sdist: + runs-on: ubuntu-latest + name: Create Source Distribution + needs: get_next_version + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ needs.get_next_version.outputs.branch_name }} + + - name: Install Python + uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Upgrade pip + run: | + python3 -m pip install --upgrade pip + + - name: Create Source Distribution + run: | + pip install setuptools wheel twine + python3 setup.py sdist + + - uses: actions/upload-artifact@v2 + with: + path: dist/*.tar.gz build_wheels: name: Build wheels on ${{ matrix.os }} @@ -45,30 +102,19 @@ jobs: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + with: + ref: ${{ needs.get_next_version.outputs.branch_name }} - name: Install Python uses: actions/setup-python@v2 with: python-version: '3.8' - # update the version number in version.txt - - name: update version - id: update-version - run : | - echo "current folder = $PWD" - echo "current branch = $(git branch --show-current)" - output=$(python3 release_utils.py --release-type ${{ github.event.inputs.name }} --update-version) - - name: Upgrade pip run: | python3 -m pip install --upgrade pip - - name: Create Source Distribution - run: | - pip install setuptools wheel twine - python3 setup.py sdist - - name: Install cibuildwheel run: | python3 -m pip install cibuildwheel @@ -85,6 +131,20 @@ jobs: CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" CIBW_SKIP: "*musllinux*" + - uses: actions/upload-artifact@v2 + with: + path: dist + + upload: + name: Upload to PyPi and create release + runs-on: ubuntu-latest + needs: [build_wheels, create_sdist, get_next_version] + steps: + - uses: actions/download-artifact@v2 + with: + name: artifact + path: dist + # build the PyPI package and upload it - name: upload env: @@ -93,27 +153,8 @@ jobs: run: | python3 -m twine upload --repository pypi dist/* - # add and commit the updated version.py to main - - name: add and commit - if: ${{ matrix.os=='ubuntu-latest' }} - uses: EndBug/add-and-commit@v9 - with: - author_name: ${{ secrets.AUTHOR_NAME }} - author_email: ${{ secrets.AUTHOR_EMAIL }} - - # TODO: change this to main once shipit is disabled. - new_branch: ${{ needs.get_next_version.outputs.new_version }} - default_author: github_actor - message: '${{ needs.get_next_version.outputs.new_version }} release' - pathspec_error_handling: exitAtEnd - - # Arguments for the git pull command. Use NO-PULL to avoid the action pulling at all. - # pull: 'NO-PULL' - tag: '${{ needs.get_next_version.outputs.new_tag }}' - # create the release on github - name: create release on github - if: ${{ matrix.os=='ubuntu-latest' }} uses: ncipollo/release-action@v1 with: tag: '${{ needs.get_next_version.outputs.new_tag }}' diff --git a/RELEASE.md b/RELEASE.md index 2b05ab0d4b..79480a11c5 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -6,7 +6,7 @@ In order to create a new release: 2. Under _Run Workflow_ choose the branch `main` and for _Release Type_ enter either `major`, `minor`, or `patch`. -3. A branch with the same name as the new version will be created where the `version.txt` file is updated. Merge those changes into `main`. +3. A branch named `$new_version-release` will be created where the `version.txt` file is updated. Merge those changes into `main`. 4. Make sure that a [new PYPI package](https://pypi.org/project/fairseq/) has been uploaded. From 4bcab98b92027daf2632c76f9266f7bdefb040f5 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Mon, 13 Jun 2022 07:36:54 -0700 Subject: [PATCH 636/774] Add command to release workflow (#4483) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Fixes # (issue). ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4483 Reviewed By: cbalioglu Differential Revision: D37098170 Pulled By: dianaml0 fbshipit-source-id: 6413fe0d03586e8b8b81701284cc010eafce7e4a --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b3aed1f514..60934fcee7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -151,6 +151,7 @@ jobs: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | + pip install setuptools wheel twine python3 -m twine upload --repository pypi dist/* # create the release on github From 4b98d9393e4180c273e7876b4663d278f75958d0 Mon Sep 17 00:00:00 2001 From: Diana Liskovich <dianaml@fb.com> Date: Mon, 13 Jun 2022 10:19:46 -0700 Subject: [PATCH 637/774] v0.12.1 release (#4486) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ ] Did you make sure to update the docs? - [ ] Did you write any new necessary tests? ## What does this PR do? Had to rerun release, created new PR. ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4486 Reviewed By: cbalioglu Differential Revision: D37110232 Pulled By: dianaml0 fbshipit-source-id: e5ce9d8c4d37a27e256a17458808312ab3b02b53 --- fairseq/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/version.txt b/fairseq/version.txt index d33c3a2128..aac2dacab4 100644 --- a/fairseq/version.txt +++ b/fairseq/version.txt @@ -1 +1 @@ -0.12.0 \ No newline at end of file +0.12.1 \ No newline at end of file From a0ceabc287e26f64517fadb13a54c83b71e8e469 Mon Sep 17 00:00:00 2001 From: Alex Liu <alexliu36@gmail.com> Date: Tue, 14 Jun 2022 21:54:56 -0700 Subject: [PATCH 638/774] include wav2vec-u 2.0 (#2826) Summary: # Before submitting - [ ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [ x ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [ x ] Did you make sure to update the docs? - [ x ] Did you write any new necessary tests? ## What does this PR do? include wav2vec-u 2.0 !!! TODO !!! update title/link of paper in readme X-link: https://github.com/fairinternal/fairseq-py/pull/2826 Reviewed By: michaelauli Differential Revision: D37162174 Pulled By: alexeib fbshipit-source-id: b985ebb9bb94c25d30b6fc53d8c79088cb9798f9 --- README.md | 1 + examples/wav2vec/unsupervised/README.md | 28 +++- .../unsupervised/config/gan/w2vu2.yaml | 154 ++++++++++++++++++ .../data/extracted_features_dataset.py | 25 ++- .../wav2vec/unsupervised/models/wav2vec_u.py | 64 +++++++- .../unsupervised/scripts/prepare_audio_v2.sh | 68 ++++++++ .../unsupervised/scripts/prepare_text.sh | 3 +- .../unsupervised/tasks/unpaired_audio_text.py | 5 + .../wav2vec/unsupervised/w2vu_generate.py | 7 + 9 files changed, 340 insertions(+), 15 deletions(-) create mode 100644 examples/wav2vec/unsupervised/config/gan/w2vu2.yaml create mode 100644 examples/wav2vec/unsupervised/scripts/prepare_audio_v2.sh diff --git a/README.md b/README.md index f7acbd15c3..2dfd9e96fe 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ We provide reference implementations of various sequence modeling papers: </p></details> ### What's New: +* June 2022 [Released code for wav2vec-U 2.0 from Towards End-to-end Unsupervised Speech Recognition (Liu, et al., 2022)](examples/wav2vec/unsupervised/README.md) * May 2022 [Integration with xFormers](https://github.com/facebookresearch/xformers) * December 2021 [Released Direct speech-to-speech translation code](examples/speech_to_speech/README.md) * October 2021 [Released VideoCLIP and VLM models](examples/MMPT/README.md) diff --git a/examples/wav2vec/unsupervised/README.md b/examples/wav2vec/unsupervised/README.md index 0b213fd202..b9d6f6762c 100644 --- a/examples/wav2vec/unsupervised/README.md +++ b/examples/wav2vec/unsupervised/README.md @@ -1,8 +1,8 @@ # wav2vec Unsupervised (wav2vec-U) -Wav2vec Unsupervised (wav2vec-U) is a framework for building speech recognition systems without any labeled training data as described in [Unsupervised Speech Recognition (Baevski et al., 2021)](https://ai.facebook.com/research/publications/unsupervised-speech-recognition). The model takes as input wav2vec 2.0 or XLSR representations (see [pretrained models](https://github.com/pytorch/fairseq/blob/main/examples/wav2vec)) as well as unlabeled speech and text data. +Wav2vec Unsupervised (wav2vec-U) and the 2.0 version are frameworks for building speech recognition systems without any labeled training data as described in [Unsupervised Speech Recognition (Baevski et al., 2021)](https://ai.facebook.com/research/publications/unsupervised-speech-recognition) and [Towards End-to-end Unsupervised Speech Recognition (Liu, et al., 2022)](https://arxiv.org/abs/2204.02492). The model takes as input wav2vec 2.0 or XLSR representations (see [pretrained models](https://github.com/pytorch/fairseq/blob/main/examples/wav2vec)) as well as unlabeled speech and text data. - The wav2vec-U training procedure consists of three consecutive main steps: + The training procedure consists of three consecutive main steps: * Preparation of speech representations and text data * Generative adversarial training (GAN) * Iterative self-training + Kaldi LM-decoding @@ -33,13 +33,16 @@ python $FAIRSEQ_ROOT/examples/wav2vec/wav2vec_manifest.py /dir/to/save/audio/fil Next, we need to preprocess the audio data to better match phonemized text data: ```shell +# wav2vec-U zsh scripts/prepare_audio.sh /dir/with/{train,test,valid}.tsv /output/dir /path/to/wav2vec2/model.pt 512 14 +# wav2vec-U 2.0 +zsh scripts/prepare_audio_v2.sh /dir/with/{train,test,valid}.tsv /output/dir /path/to/wav2vec2/model.pt 64 14 ``` -Note that if you have splits different than train/valid/test, you will need to modify this script. The last two arguments are the PCA dimensionality and the 0-based index of the layer from which to extract representations. +Note that if you have splits different than train/valid/test, you will need to modify this script. The thrid argument is the PCA dimensionality for wav2vec-U and the number of MFCC clusters for wav2vec-U 2.0. The last argument is the 0-based index of the layer from which to extract representations. Now we need to prepare text data: ```shell -zsh scripts/prepare_text.sh language /path/to/text/file /output/dir 1000 espeak /path/to/fasttext/lid/model +zsh scripts/prepare_text.sh language /path/to/text/file /output/dir 1000 espeak /path/to/fasttext/lid/model sil_prob ``` The fourth argument is minimum number observations of phones to keep. If your text corpus is small, you might want to reduce this number. @@ -48,6 +51,8 @@ The fifth argument is which phonemizer to use. Supported values are [espeak](htt Pre-trained fasttext LID models can be downloaded [here](https://fasttext.cc/docs/en/language-identification.html). +The last argument is the probability to introduce silence (`<SIL>`) between the word boundaries. We found the value `0.25`/`0.5` works in general for wav2vec-U and the 2.0 version respectively, but you might want to vary for languages that are never tested. + ### Prepare TIMIT data TIMIT transcripts include silence. Therefore VAD is not used for audio preprocessing, and we do not wrap transcripts with silences or insert random silence in between words. @@ -66,13 +71,22 @@ Launching GAN training on top of preprocessed features, with default hyperparame ``` PREFIX=w2v_unsup_gan_xp -TASK_DATA=/path/to/features/precompute_unfiltered_pca512_cls128_mean_pooled + +# For wav2vec-U, audio features are pre-segmented +CONFIG_NAME=w2vu +TASK_DATA=/path/to/features/precompute_unfiltered_pca512_cls128_mean_pooled + +# For wav2vec-U 2.0, use raw audio features +CONFIG_NAME=w2vu2 +TASK_DATA=/path/to/features/ + +# Unpaired text input TEXT_DATA=/path/to/data/phones # path to fairseq-preprocessed GAN data (phones dir) KENLM_PATH=/path/to/data/phones/kenlm.phn.o4.bin # KenLM 4-gram phoneme language model (LM data = GAN data here) PYTHONPATH=$FAIRSEQ_ROOT PREFIX=$PREFIX fairseq-hydra-train \ -m --config-dir config/gan \ - --config-name w2vu \ + --config-name $CONFIG_NAME \ task.data=${TASK_DATA} \ task.text_data=${TEXT_DATA} \ task.kenlm_path=${KENLM_PATH} \ @@ -94,6 +108,8 @@ fairseq.dataset.gen_subset=valid results_path=/where/to/save/transcriptions The decoding without LM works best on the same adjacent-mean-pooled features that the gan was trained on, while decoding with LM works better on features before the adjacent timestep mean-pooling step (without the "_pooled" suffix). +While the generator of wav2vec-U 2.0 is trained with an output frequency of 16hz, we found decoding at a higher frequency produces better results. This can be done by adding `decode_stride=1` or `2` to the argument. + ## Iterative self-training + Kaldi LM-decoding After the GAN training provides a first unsupervised model, we can then progressively refine the quality of transcriptions using several iterations of semi-supervised learning. We perform two iterations: first, pseudo-label the training data with the unsupervised GAN model and train an HMM on the pseudo-labels. Second, we relabel the training data with the HMM and then fine-tune the original wav2vec 2.0 model using the HMM pseudo-labels with a CTC loss. Note that HMM models use phonemes as output, while wav2vec 2.0 use letter. Both are decoded using WFST decoders into words. diff --git a/examples/wav2vec/unsupervised/config/gan/w2vu2.yaml b/examples/wav2vec/unsupervised/config/gan/w2vu2.yaml new file mode 100644 index 0000000000..52014222b2 --- /dev/null +++ b/examples/wav2vec/unsupervised/config/gan/w2vu2.yaml @@ -0,0 +1,154 @@ +# @package _group_ + +common: + fp16: false + fp16_no_flatten_grads: true + log_format: json + log_interval: 100 + tensorboard_logdir: tb + reset_logging: false + suppress_crashes: false + +checkpoint: + save_interval: 1000 + save_interval_updates: 1000 + no_epoch_checkpoints: true + best_checkpoint_metric: weighted_lm_ppl + save_dir: . + +distributed_training: + distributed_world_size: 1 + +task: + _name: unpaired_audio_text + data: ??? + text_data: ??? + labels: phn + sort_by_length: false + unfiltered: false + max_length: null + append_eos: false + kenlm_path: ??? + aux_target_postfix: km + +dataset: + num_workers: 6 + batch_size: 160 + skip_invalid_size_inputs_valid_test: true + valid_subset: valid + validate_interval: 1000 + validate_interval_updates: 1000 + +criterion: + _name: model + log_keys: + - accuracy_dense + - accuracy_token + - temp + - code_ppl + +optimization: + max_update: 150000 + clip_norm: 5.0 + lr: [0] + +optimizer: + _name: composite + groups: + generator: + lr: [0.00005] + lr_float: null + optimizer: + _name: adam + adam_betas: [0.5,0.98] + adam_eps: 1e-06 + weight_decay: 0 + amsgrad: false + lr_scheduler: + _name: fixed + warmup_updates: 0 + discriminator: + lr: [ 0.0003 ] + lr_float: null + optimizer: + _name: adam + adam_betas: [0.5,0.98] + adam_eps: 1e-06 + weight_decay: 0.0001 + amsgrad: false + lr_scheduler: + _name: fixed + warmup_updates: 0 + +lr_scheduler: pass_through + +model: + _name: wav2vec_u + + discriminator_dim: 384 + discriminator_depth: 2 + discriminator_kernel: 8 + discriminator_linear_emb: false + discriminator_causal: true + discriminator_max_pool: false + discriminator_act_after_linear: false + discriminator_dropout: 0.0 + discriminator_weight_norm: false + + generator_stride: 3 + generator_kernel: 9 + generator_bias: false + generator_dropout: 0.1 + generator_batch_norm: 30 + generator_residual: true + + smoothness_weight: 1.5 + smoothing: 0 + smoothing_one_sided: false + gumbel: false + hard_gumbel: false + gradient_penalty: 1.0 + code_penalty: 3.0 + temp: [ 2,0.1,0.99995 ] + input_dim: 1024 + mmi_weight: 0.5 + target_dim: 64 + + segmentation: + type: JOIN + mean_pool_join: false + remove_zeros: false + + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + - common.user_dir + - task.data + - task.kenlm_path + - task.text_data + - model.generator_layers + - task.labels + - task.force_model_seed + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 1 + tasks_per_node: 1 + mem_gb: 120 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + comment: intern_endding_soon + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/unsupervised/data/extracted_features_dataset.py b/examples/wav2vec/unsupervised/data/extracted_features_dataset.py index d6ee9c4a36..7f7a58c0e5 100644 --- a/examples/wav2vec/unsupervised/data/extracted_features_dataset.py +++ b/examples/wav2vec/unsupervised/data/extracted_features_dataset.py @@ -28,6 +28,7 @@ def __init__( label_dict=None, shuffle=True, sort_by_length=True, + aux_target_postfix=None, ): super().__init__() @@ -43,6 +44,7 @@ def __init__( self.sizes = [] self.offsets = [] self.labels = [] + self.aux_tgt = None path = os.path.join(path, split) data_path = path @@ -71,7 +73,16 @@ def __init__( self.sizes = np.asarray(self.sizes) self.offsets = np.asarray(self.offsets) - + + if aux_target_postfix is not None: + if not os.path.exists(path+f".{aux_target_postfix}"): + logger.info(f"auxaliry target for {split} missing") + else: + with open(path+f".{aux_target_postfix}", "r") as t_f: + self.aux_tgt = [ + torch.LongTensor(list(map(int,seg.strip().split())))\ + for seg in t_f] + logger.info(f"loaded {len(self.offsets)}, skipped {skipped} samples") def __getitem__(self, index): @@ -86,6 +97,9 @@ def __getitem__(self, index): line_tokenizer=lambda x: x, append_eos=False, ) + + if self.aux_tgt: + res["aux_target"] = self.aux_tgt[index] return res @@ -121,6 +135,15 @@ def collater(self, samples): left_pad=False, ) res["target"] = target + + if self.aux_tgt: + idxs = torch.nn.utils.rnn.pad_sequence( + [s["aux_target"] for s in samples], + batch_first=True, + padding_value=-1, + ) + res["net_input"]["aux_target"] = idxs + return res def num_tokens(self, index): diff --git a/examples/wav2vec/unsupervised/models/wav2vec_u.py b/examples/wav2vec/unsupervised/models/wav2vec_u.py index 27792ebda8..8a1e9055e3 100644 --- a/examples/wav2vec/unsupervised/models/wav2vec_u.py +++ b/examples/wav2vec/unsupervised/models/wav2vec_u.py @@ -42,7 +42,6 @@ class SegmentationConfig(FairseqDataclass): @dataclass class Wav2vec_UConfig(FairseqDataclass): - discriminator_kernel: int = 3 discriminator_dilation: int = 1 discriminator_dim: int = 256 @@ -58,8 +57,11 @@ class Wav2vec_UConfig(FairseqDataclass): generator_kernel: int = 4 generator_dilation: int = 1 generator_stride: int = 1 + generator_pad: int = -1 generator_bias: bool = False generator_dropout: float = 0.0 + generator_batch_norm: int = 0 + generator_residual: bool = False blank_weight: float = 0 blank_mode: str = "add" @@ -72,6 +74,9 @@ class Wav2vec_UConfig(FairseqDataclass): gradient_penalty: float = 0.0 probabilistic_grad_penalty_slicing: bool = False code_penalty: float = 0.0 + mmi_weight: float = 0.0 + target_dim: int = 64 + target_downsample_rate: int = 2 gumbel: bool = False hard_gumbel: bool = True temp: Tuple[float, float, float] = (2, 0.1, 0.99995) @@ -288,8 +293,12 @@ def __init__(self, input_dim, output_dim, cfg: Wav2vec_UConfig): self.output_dim = output_dim self.stride = cfg.generator_stride self.dropout = nn.Dropout(cfg.generator_dropout) + self.batch_norm = cfg.generator_batch_norm != 0 + self.residual = cfg.generator_residual - padding = cfg.generator_kernel // 2 + padding = ( + cfg.generator_kernel // 2 if cfg.generator_pad < 0 else cfg.generator_pad + ) self.proj = nn.Sequential( TransposeLast(), nn.Conv1d( @@ -304,7 +313,22 @@ def __init__(self, input_dim, output_dim, cfg: Wav2vec_UConfig): TransposeLast(), ) + if self.batch_norm: + self.bn = nn.BatchNorm1d(input_dim) + self.bn.weight.data.fill_(cfg.generator_batch_norm) + if self.residual: + self.in_proj = nn.Linear(input_dim, input_dim) + def forward(self, dense_x, tokens, dense_padding_mask): + result = {} + + if self.batch_norm: + dense_x = self.bn_padded_data(dense_x, dense_padding_mask) + if self.residual: + inter_x = self.in_proj(self.dropout(dense_x)) + dense_x = dense_x + inter_x + result["inter_x"] = inter_x + dense_x = self.dropout(dense_x) dense_x = self.proj(dense_x) @@ -314,9 +338,7 @@ def forward(self, dense_x, tokens, dense_padding_mask): if dense_padding_mask.size(1) != dense_x.size(1): new_padding = dense_padding_mask.new_zeros(dense_x.shape[:-1]) diff = new_padding.size(1) - dense_padding_mask.size(1) - assert ( - diff > 0 - ), f"{new_padding.shape}, {dense_padding_mask.shape}, {dense_x.shape}, {diff}" + if diff > 0: new_padding[:, diff:] = dense_padding_mask else: @@ -325,8 +347,6 @@ def forward(self, dense_x, tokens, dense_padding_mask): dense_padding_mask = new_padding - result = {} - token_x = None if tokens is not None: token_x = dense_x.new_zeros(tokens.numel(), self.output_dim) @@ -339,6 +359,13 @@ def forward(self, dense_x, tokens, dense_padding_mask): return result + def bn_padded_data(self, feature, padding_mask): + normed_feature = feature.clone() + normed_feature[~padding_mask] = self.bn( + feature[~padding_mask].unsqueeze(-1) + ).squeeze(-1) + return normed_feature + @register_model("wav2vec_u", dataclass=Wav2vec_UConfig) class Wav2vec_U(BaseFairseqModel): @@ -420,6 +447,7 @@ def __init__(self, cfg: Wav2vec_UConfig, target_dict): self.gradient_penalty = cfg.gradient_penalty self.code_penalty = cfg.code_penalty + self.mmi_weight = cfg.mmi_weight self.blank_weight = cfg.blank_weight self.blank_mode = cfg.blank_mode self.blank_index = target_dict.index("<SIL>") if cfg.blank_is_sil else 0 @@ -446,6 +474,12 @@ def __init__(self, cfg: Wav2vec_UConfig, target_dict): self.curr_temp = self.max_temp self.update_num = 0 + if self.mmi_weight > 0: + self.target_downsample_rate = cfg.target_downsample_rate + self.decoder = nn.Linear(d, cfg.target_dim) + for p in self.decoder.parameters(): + p.param_group = "generator" + @classmethod def build_model(cls, cfg, task): return cls(cfg, task.target_dictionary) @@ -529,6 +563,7 @@ def forward( random_label=None, dense_x_only=False, segment=True, + aux_target=None, ): if segment: features, padding_mask = self.segmenter.pre_segment(features, padding_mask) @@ -578,6 +613,7 @@ def forward( zero_loss = None smoothness_loss = None code_pen = None + mmi_loss = None if d_step: loss_dense = F.binary_cross_entropy_with_logits( @@ -617,11 +653,25 @@ def forward( smoothness_loss.mean() * sample_size * self.smoothness_weight ) + if (self.mmi_weight > 0) and (aux_target is not None): + inter_x = self.decoder(gen_result["inter_x"]) + if self.target_downsample_rate > 1: + aux_target = aux_target[:, :: self.target_downsample_rate] + max_t_len = min(aux_target.shape[1], inter_x.shape[1]) + mmi_loss = F.cross_entropy( + inter_x[:, :max_t_len].transpose(1, 2), + aux_target[:, :max_t_len], + ignore_index=-1, + reduction="none", + ) + mmi_loss = mmi_loss.mean() * mmi_loss.shape[0] * self.mmi_weight + result = { "losses": { "grad_pen": grad_pen, "code_pen": code_pen, "smoothness": smoothness_loss, + "mmi": mmi_loss, }, "temp": self.curr_temp, "code_ppl": code_perplexity, diff --git a/examples/wav2vec/unsupervised/scripts/prepare_audio_v2.sh b/examples/wav2vec/unsupervised/scripts/prepare_audio_v2.sh new file mode 100644 index 0000000000..96a52c5c83 --- /dev/null +++ b/examples/wav2vec/unsupervised/scripts/prepare_audio_v2.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env zsh +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +source_dir=$1 +tgt_dir=$2 +model=$3 + +if [ -z "$4" ] + then + dim=64 + else + dim=$4 +fi + +echo "using $dim clusters for auxilary target" + +if [ -z "$5" ] + then + layer=14 + else + layer=$5 +fi + +echo "extracting from layer $layer" + +train_split=train +valid_split=valid +test_split=test + +all_splits=($train_split) + +if [[ -f "$source_dir/valid.tsv" ]]; then + all_splits+=('valid') +fi + +if [[ -f "$source_dir/test.tsv" ]]; then + all_splits+=('test') +fi + +echo "processing splits: $all_splits" + +mkdir -p $tgt_dir + +cp $source_dir/*.tsv $tgt_dir +cp $source_dir/*.wrd $tgt_dir +cp $source_dir/*.ltr $tgt_dir +cp $source_dir/*.phn $tgt_dir +cp $source_dir/dict* $tgt_dir + +setopt shwordsplit + +for split in $all_splits; do + python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/wav2vec_extract_features.py $source_dir --split $split \ + --save-dir $tgt_dir --checkpoint $model --layer $layer +done + + +mkdir -p $tgt_dir/mfcc + +# Consider spliting corpus into chuncks for large corpus, see HuBERT preprocessing for more details +python $FAIRSEQ_ROOT/examples/hubert/simple_kmeans/dump_mfcc_feature.py \ + $tgt_dir $train_split 1 0 $tgt_dir/mfcc +python $FAIRSEQ_ROOT/examples/hubert/simple_kmeans/dump_km_label.py \ + $tgt_dir/mfcc $train_split $tgt_dir/mfcc/cls$dim 1 0 $tgt_dir/mfcc/cls${dim}_idx +cp $tgt_dir/mfcc/cls${dim}_idx/${train_split}_0_1.km $tgt_dir/$train_split.km diff --git a/examples/wav2vec/unsupervised/scripts/prepare_text.sh b/examples/wav2vec/unsupervised/scripts/prepare_text.sh index 1caf13cb6a..dbd17a2472 100644 --- a/examples/wav2vec/unsupervised/scripts/prepare_text.sh +++ b/examples/wav2vec/unsupervised/scripts/prepare_text.sh @@ -10,6 +10,7 @@ target_dir=$3 min_phones=$4 phonemizer=$5 lid_path=$6 +sil_prob=$7 if [ -z "$lid_path" ]; then lid_path="lid.187.bin" @@ -63,7 +64,7 @@ paste $target_dir/words.txt $target_dir/phones.txt >! $target_dir/lexicon.lst python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones.txt --only-source --destdir $target_dir/phones --thresholdsrc $min_phones --padding-factor 1 --dict-only python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/filter_lexicon.py -d $target_dir/phones/dict.txt < $target_dir/lexicon.lst >! $target_dir/lexicon_filtered.lst -python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py -s 0.25 --surround --lexicon $target_dir/lexicon_filtered.lst < $target_dir/lm.upper.lid.txt >! $target_dir/phones/lm.phones.filtered.txt +python $FAIRSEQ_ROOT/examples/wav2vec/unsupervised/scripts/phonemize_with_sil.py -s $sil_prob --surround --lexicon $target_dir/lexicon_filtered.lst < $target_dir/lm.upper.lid.txt >! $target_dir/phones/lm.phones.filtered.txt cp $target_dir/phones/dict.txt $target_dir/phones/dict.phn.txt echo "<SIL> 0" >> $target_dir/phones/dict.phn.txt python $FAIRSEQ_ROOT/fairseq_cli/preprocess.py --dataset-impl mmap --trainpref $target_dir/phones/lm.phones.filtered.txt --workers 70 --only-source --destdir $target_dir/phones --srcdict $target_dir/phones/dict.phn.txt diff --git a/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py index 1e2dc55c23..b6b65d5c49 100644 --- a/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py +++ b/examples/wav2vec/unsupervised/tasks/unpaired_audio_text.py @@ -54,6 +54,10 @@ class UnpairedAudioTextConfig(FairseqDataclass): default=None, metadata={"help": "extension of the label file to load, used for fine-tuning"}, ) + aux_target_postfix: Optional[str] = field( + default=None, + metadata={"help": "auxaliry target filename extension"}, + ) unfiltered: bool = field( default=False, metadata={"help": "load data with _unfiltered suffix"} ) @@ -302,6 +306,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): label_dict=self.target_dictionary, shuffle=getattr(task_cfg, "shuffle", True), sort_by_length=task_cfg.sort_by_length, + aux_target_postfix=task_cfg.aux_target_postfix, ) logger.info(f"split {split} has unpaired text? {has_unpaired_text}") diff --git a/examples/wav2vec/unsupervised/w2vu_generate.py b/examples/wav2vec/unsupervised/w2vu_generate.py index fca0c96f32..0611297a4f 100644 --- a/examples/wav2vec/unsupervised/w2vu_generate.py +++ b/examples/wav2vec/unsupervised/w2vu_generate.py @@ -68,6 +68,10 @@ class UnsupGenerateConfig(FairseqDataclass): default=None, metadata={"help": "path to language model (kenlm or fairseq)"}, ) + decode_stride: Optional[float] = field( + default=None, + metadata={"help": "changing the decoding frequency of the generator"}, + ) unit_lm: bool = field( default=False, metadata={"help": "whether to use unit lm"}, @@ -590,6 +594,9 @@ def main(cfg: UnsupGenerateConfig, model=None): "blank_weight": cfg.blank_weight, "blank_mode": cfg.blank_mode, } + + if cfg.decode_stride: + overrides["model"]["generator_stride"] = cfg.decode_stride if model is None: # Load ensemble From d9c661bf4fad170a1c66a7abd9f433a848d0d26a Mon Sep 17 00:00:00 2001 From: James Cross <jcross@fb.com> Date: Wed, 15 Jun 2022 16:48:07 -0700 Subject: [PATCH 639/774] don't allow language tokens in output for 1:many decoding Summary: Because of the way language ID tokens were introduced for training 1:N MT models, we sometimes see the artifact of the model producing language tokens in the output (see T119348697 for details). This change prevents that by simply zeroing out their probabilities during beam search. Edit: it turns out that the majority of cases of target language token appearing in the output are due to UNK replacement, where the language ID in source prefix was the "most-attended-to" source token at the step where the UNK was produced. Thus, this change zeros out the attention weights for prefix tokens in the source sequence. Reviewed By: theweiho Differential Revision: D36282175 fbshipit-source-id: fb7b2bfd3a8c1c66563ea509e68ab742a831ba4a --- fairseq/sequence_generator.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 7d323d85e7..13f99078c7 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -38,6 +38,7 @@ def __init__( symbols_to_strip_from_output=None, lm_model=None, lm_weight=1.0, + tokens_to_suppress=(), ): """Generates translations of a given source sentence. @@ -77,6 +78,18 @@ def __init__( if symbols_to_strip_from_output is not None else {self.eos} ) + + self.token_indices_to_suppress: Optional[Tensor] = None + token_indices_to_suppress = [] + for token_string in tokens_to_suppress: + token_index = tgt_dict.index(token_string) + assert token_index != self.unk + token_indices_to_suppress.append(token_index) + if len(token_indices_to_suppress) > 0: + self.token_indices_to_suppress = torch.Tensor( + token_indices_to_suppress + ).long() + self.vocab_size = len(tgt_dict) self.beam_size = beam_size # the max beam size is the dictionary size - 1, since we never select pad @@ -372,9 +385,13 @@ def _generate( lprobs, tokens, scores = self._prefix_tokens( step, lprobs, scores, tokens, prefix_tokens, beam_size ) - elif step < self.min_len: - # minimum length constraint (does not apply if using prefix_tokens) - lprobs[:, self.eos] = -math.inf + else: + if step < self.min_len: + # minimum length constraint (does not apply if using prefix_tokens) + lprobs[:, self.eos] = -math.inf + + if self.token_indices_to_suppress is not None: + lprobs[:, self.token_indices_to_suppress] = -math.inf # Record attention scores, only support avg_attn_scores is a Tensor if avg_attn_scores is not None: From 3a757d7ab2de97c3da5efd05712f703c26abe8d2 Mon Sep 17 00:00:00 2001 From: Wei Wei <wwei6@fb.com> Date: Wed, 15 Jun 2022 21:48:41 -0700 Subject: [PATCH 640/774] BT enablement on fairseq - fairseq change (#4480) Summary: Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4480 as titled and depends on D36057338 Fork the inference path inside the forward function. If loaded the checkpoint file and perform the inference, we will deploy BT. Otherwise, fairseq take the position. In summary: Accuracy: accuracy loss due to the fp16, the maximum diff is around 0.009. If we set it to fp32, there is no accuracy loss Perf: the current fairseq has similar speed as vanilla version. After the enablement, the speedup is similar to standalone BT test. With batch size=64 For V100, the speedup reaches to 1.23x For A100, the speedup reaches to 1.38x After enable nested tensor, For V100, the speedup reaches to 2.46x Reviewed By: mikekgfb Differential Revision: D37082681 fbshipit-source-id: 984266f850fc30603e48be56e41ac2c67da080f5 --- .../models/transformer/transformer_encoder.py | 90 ++++- fairseq/modules/transformer_layer.py | 207 ++++++++-- scripts/better_transformer.py | 380 ++++++++++++++++++ tests/test_export.py | 32 +- tests/test_sequence_generator.py | 31 +- 5 files changed, 693 insertions(+), 47 deletions(-) create mode 100644 scripts/better_transformer.py diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index 0b7e6d8379..c887c5afe2 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -8,23 +8,22 @@ import torch import torch.nn as nn +from torch import Tensor + from fairseq import utils from fairseq.distributed import fsdp_wrap from fairseq.models import FairseqEncoder +from fairseq.models.transformer import TransformerConfig from fairseq.modules import ( FairseqDropout, LayerDropModuleList, LayerNorm, PositionalEmbedding, SinusoidalPositionalEmbedding, + transformer_layer, ) -from fairseq.modules import transformer_layer from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ -from torch import Tensor -from fairseq.models.transformer import ( - TransformerConfig, -) # rewrite name for backward compatibility in `make_generation_fast_` @@ -220,11 +219,79 @@ def forward_scriptable( if return_all_hiddens: encoder_states.append(x) + # nested tensor and BT enable + layer = self.layers[0] + BT_flag = False + NT_flag = False + # torch version check, BT>=1.12.0 and NT>=1.13.0.dev20220613 + # internal format is '1.13.0a0+fb' + # external format is '1.13.0.dev20220613'(cpu&gpu) for nightly or "1.11.0"(cpu) or '1.11.0+cu102'(gpu) for stable + BT_version = False + NT_version = False + if "fb" in torch.__version__: + BT_version = True + NT_version = True + else: + if "+" in torch.__version__: + torch_version = torch.__version__.split("+")[0] + else: + torch_version = torch.__version__ + + torch_version = torch_version.split(".") + int_version = ( + int(torch_version[0]) * 1000 + + int(torch_version[1]) * 10 + + int(torch_version[2]) + ) + if len(torch_version) == 3: + if int_version >= 1120: + BT_version = True + if int_version >= 1131: + NT_version = True + elif len(torch_version) == 4: + if int_version >= 1130: + BT_version = True + # Consider _nested_tensor_from_mask_left_aligned is landed after "20220613" + if int_version >= 1131 or ( + int_version == 1130 and torch_version[3][3:] >= "20220613" + ): + NT_version = True + + if ( + BT_version + and x.dim() == 3 + and layer.load_to_BT + and not layer.return_fc + and layer.can_use_fastpath + and not layer.training + and not layer.ever_training + and not layer.cfg_checkpoint_activations + ): + # Batch first can not be justified but needs user to make sure + x = x.transpose(0, 1) + # Check mask conditions for nested tensor + if NT_version: + if ( + encoder_padding_mask is not None + and torch._nested_tensor_from_mask_left_aligned( + x, encoder_padding_mask.logical_not() + ) + ): + if not torch.is_grad_enabled() or not x.requires_grad: + x = torch._nested_tensor_from_mask( + x, encoder_padding_mask.logical_not() + ) + NT_flag = True + BT_flag = True + # encoder layers + if NT_flag: + processing_mask = None + else: + processing_mask = encoder_padding_mask + encoder_padding_mask_out = processing_mask if has_pads else None for layer in self.layers: - lr = layer( - x, encoder_padding_mask=encoder_padding_mask if has_pads else None - ) + lr = layer(x, encoder_padding_mask=encoder_padding_mask_out) if isinstance(lr, tuple) and len(lr) == 2: x, fc_result = lr @@ -237,6 +304,13 @@ def forward_scriptable( encoder_states.append(x) fc_results.append(fc_result) + # change back to non-nested and Batch second + if NT_flag: + x = x.to_padded_tensor(0.0) + + if NT_flag or BT_flag: + x = x.transpose(0, 1) + if self.layer_norm is not None: x = self.layer_norm(x) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 2e687b94d0..6589a5075e 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -7,14 +7,13 @@ import torch import torch.nn as nn +from torch import Tensor + from fairseq import utils +from fairseq.models.transformer import TransformerConfig from fairseq.modules import LayerNorm, MultiheadAttention from fairseq.modules.fairseq_dropout import FairseqDropout from fairseq.modules.quant_noise import quant_noise -from torch import Tensor -from fairseq.models.transformer import ( - TransformerConfig, -) class TransformerEncoderLayerBase(nn.Module): @@ -68,6 +67,103 @@ def __init__(self, cfg, return_fc=False): self.final_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) + self.num_heads = cfg.encoder.attention_heads + self.load_to_BT = False + self.ever_training = False + # For BT, we need continuous mem + self.in_proj_weight = torch.nn.Parameter( + torch.zeros( + self.self_attn.q_proj.weight.shape[0] * 3, + self.self_attn.q_proj.weight.shape[1], + ) + ) + self.in_proj_bias = torch.nn.Parameter( + torch.zeros(self.self_attn.q_proj.bias.shape[0] * 3) + ) + + if ( + self.activation_fn is torch.nn.functional.relu + or isinstance(self.activation_fn, torch.nn.ReLU) + or self.activation_fn == "relu" + ): + self.activation_relu_or_gelu = 1 + elif ( + self.activation_fn is torch.nn.functional.gelu + or isinstance(self.activation_fn, torch.nn.GELU) + or self.activation_fn == "gelu" + ): + self.activation_relu_or_gelu = 2 + else: + self.activation_relu_or_gelu = 0 + # Batch first can not be justified but needs user to make sure + self.can_use_fastpath = ( + not self.normalize_before + and self.activation_relu_or_gelu + and (self.self_attn_layer_norm.eps == self.final_layer_norm.eps) + ) + self.cfg_checkpoint_activations = self.cfg.checkpoint_activations + # torch version check + # make sure BT version is >=1.12.0 + self.BT_version = False + if "fb" in torch.__version__: + self.BT_version = True + else: + if "+" in torch.__version__: + self.torch_version = torch.__version__.split("+")[0] + else: + self.torch_version = torch.__version__ + + self.torch_version = self.torch_version.split(".") + self.int_version = ( + int(self.torch_version[0]) * 1000 + + int(self.torch_version[1]) * 10 + + int(self.torch_version[2]) + ) + if len(self.torch_version) == 3: + if self.int_version >= 1120: + self.BT_version = True + elif len(self.torch_version) == 4: + if self.int_version >= 1130: + self.BT_version = True + + def _load_from_state_dict( + self, + state_dict, + prefix, + local_metadata, + strict, + missing_keys, + unexpected_keys, + error_msgs, + ): + self.load_to_BT = True + + old_name = prefix + "self_attn." + q_proj_weight = state_dict[old_name + "q_proj.weight"] + k_proj_weight = state_dict[old_name + "k_proj.weight"] + v_proj_weight = state_dict[old_name + "v_proj.weight"] + q_proj_bias = state_dict[old_name + "q_proj.bias"] + k_proj_bias = state_dict[old_name + "k_proj.bias"] + v_proj_bias = state_dict[old_name + "v_proj.bias"] + + new_name = prefix + state_dict[new_name + "in_proj_weight"] = torch.cat( + (q_proj_weight, k_proj_weight, v_proj_weight), dim=0 + ) + state_dict[new_name + "in_proj_bias"] = torch.cat( + (q_proj_bias, k_proj_bias, v_proj_bias), dim=0 + ) + + super(TransformerEncoderLayerBase, self)._load_from_state_dict( + state_dict, + prefix, + local_metadata, + strict, + missing_keys, + unexpected_keys, + error_msgs, + ) + def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): return quant_noise( nn.Linear(input_dim, output_dim), p=q_noise, block_size=qn_block_size @@ -187,44 +283,83 @@ def forward( # Note that we cannot use -inf here, because at some edge cases, # the attention weight (before softmax) for some padded element in query # will become -inf, which results in NaN in model parameters - if attn_mask is not None: - attn_mask = attn_mask.masked_fill( - attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 + + if self.training: + self.ever_training = True + + if ( + self.BT_version + and x.dim() == 3 + and self.load_to_BT + and not self.return_fc + and self.can_use_fastpath + and not self.training + and not self.ever_training + and not self.cfg_checkpoint_activations + ): + # assume is Batch first and nested tensor + output = torch._transformer_encoder_layer_fwd( + x, + self.embed_dim, + self.num_heads, + self.in_proj_weight, + self.in_proj_bias, + self.self_attn.out_proj.weight, + self.self_attn.out_proj.bias, + self.activation_relu_or_gelu == 2, + False, # norm_first, currently not supported + self.self_attn_layer_norm.eps, + self.self_attn_layer_norm.weight, + self.self_attn_layer_norm.bias, + self.final_layer_norm.weight, + self.final_layer_norm.bias, + self.fc1.weight, + self.fc1.bias, + self.fc2.weight, + self.fc2.bias, + encoder_padding_mask if encoder_padding_mask is not None else attn_mask, ) + return output - residual = x - if self.normalize_before: - x = self.self_attn_layer_norm(x) - x, _ = self.self_attn( - query=x, - key=x, - value=x, - key_padding_mask=encoder_padding_mask, - need_weights=False, - attn_mask=attn_mask, - ) - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.self_attn_layer_norm(x) + else: + if attn_mask is not None: + attn_mask = attn_mask.masked_fill( + attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 + ) - residual = x - if self.normalize_before: - x = self.final_layer_norm(x) - x = self.activation_fn(self.fc1(x)) - x = self.activation_dropout_module(x) - x = self.fc2(x) + residual = x + if self.normalize_before: + x = self.self_attn_layer_norm(x) + x, _ = self.self_attn( + query=x, + key=x, + value=x, + key_padding_mask=encoder_padding_mask, + need_weights=False, + attn_mask=attn_mask, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) - fc_result = x + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.final_layer_norm(x) + fc_result = x + + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) - if self.return_fc and not torch.jit.is_scripting(): - return x, fc_result - return x + if self.return_fc and not torch.jit.is_scripting(): + return x, fc_result + return x # backward compatible with the legacy argparse format diff --git a/scripts/better_transformer.py b/scripts/better_transformer.py new file mode 100644 index 0000000000..2bbf64c3c6 --- /dev/null +++ b/scripts/better_transformer.py @@ -0,0 +1,380 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import sys + +import click +import numpy as np +import torch +from fvcore.nn import FlopCountAnalysis + +from fairseq.models.transformer import TransformerConfig as FairseqTransformerConfig +from fairseq.models.transformer import TransformerEncoder as FairseqTransformerEncoder + +seed = 0 +torch.manual_seed(seed) +np.random.seed(seed) + + +def benchmark_torch_function(iters, f, *args, **kwargs): + f(*args, **kwargs) + torch.cuda.synchronize() + start_event = torch.cuda.Event(enable_timing=True) + end_event = torch.cuda.Event(enable_timing=True) + start_event.record() + for _ in range(iters): + f(*args, **kwargs) + end_event.record() + torch.cuda.synchronize() + return (start_event.elapsed_time(end_event) * 1.0e-3) / iters + + +def numerical_test(lengths, truth_tensors, test_list): + """ + truth_tensors is the source of truth. + test_dict looks like + [ + (name, out_tensors, atol, rtol), + ... + ] + """ + for name, out_tensors, rtol, atol in test_list: + n_failures = 0 + max_diff = 0 + for (length, truth, out) in zip(lengths, truth_tensors, out_tensors): + cut_truth = truth[:length] + cut_out = out[:length] + max_diff = max(max_diff, torch.max(torch.abs(cut_truth - cut_out))) + if not torch.allclose(cut_truth, cut_out, atol=atol, rtol=rtol): + n_failures += 1 + + if n_failures == 0: + print(f"{name} PASS") + else: + print(f"{name} FAIL {n_failures}/{len(lengths)}. Max diff is {max_diff}") + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.option("--save", is_flag=True, default=False) +@click.option("--load", is_flag=True, default=False) +@click.option("--half", is_flag=True, default=False) +@click.option("--bt2fairseq", is_flag=True, default=False) +def transformer( + save, + load, + half, + bt2fairseq, +): + xlarge = False + large = False + DEFAULT_PADDING_IDX = 1 + avg_sequence_length = 128 + max_sequence_length = 256 + batch_size = 64 + + class FairseqEncoder(torch.nn.Module): + def __init__( + self, + embed_dim, + attention_heads, + ffn_embed_dim, + num_layers, + embedding_layer, # torch.nn.Embedding. Must have a padding_idx field + dropout=0, + normalize_before=False, + torch_encoder=None, # torch encoder that you can map weights from + activation="relu", + ): + super().__init__() + + cfg = FairseqTransformerConfig() + cfg.encoder.embed_dim = embed_dim + cfg.encoder.attention_heads = attention_heads + cfg.encoder.ffn_embed_dim = ffn_embed_dim + cfg.dropout = dropout + cfg.encoder.normalize_before = normalize_before + cfg.encoder.layers = num_layers + # make embedding behavior same as other encoders + cfg.no_token_positional_embeddings = True + cfg.no_scale_embedding = True + cfg.activation_fn = activation + dictionary = {} # TODO: verify what this is + + self.encoder = FairseqTransformerEncoder( + cfg, dictionary, embedding_layer, return_fc=False + ) + + if torch_encoder is not None: + for src_layer, dst_layer in zip( + torch_encoder.layers, self.encoder.layers + ): + w_q, w_k, w_v = src_layer.self_attn.in_proj_weight.chunk(3, dim=0) + b_q, b_k, b_v = src_layer.self_attn.in_proj_bias.chunk(3, dim=0) + + dst_layer.self_attn.q_proj.weight = torch.nn.Parameter(w_q) + dst_layer.self_attn.q_proj.bias = torch.nn.Parameter(b_q) + dst_layer.self_attn.k_proj.weight = torch.nn.Parameter(w_k) + dst_layer.self_attn.k_proj.bias = torch.nn.Parameter(b_k) + dst_layer.self_attn.v_proj.weight = torch.nn.Parameter(w_v) + dst_layer.self_attn.v_proj.bias = torch.nn.Parameter(b_v) + + dst_layer.self_attn.out_proj.weight = ( + src_layer.self_attn.out_proj.weight + ) + dst_layer.self_attn.out_proj.bias = ( + src_layer.self_attn.out_proj.bias + ) + + dst_layer.fc1.weight = src_layer.linear1.weight + dst_layer.fc1.bias = src_layer.linear1.bias + + # fairseq may use fusedlayernorm from nvidia apex - diff properties + dst_layer.self_attn_layer_norm.load_state_dict( + src_layer.norm1.state_dict() + ) + + dst_layer.fc2.weight = src_layer.linear2.weight + dst_layer.fc2.bias = src_layer.linear2.bias + + dst_layer.final_layer_norm.load_state_dict( + src_layer.norm2.state_dict() + ) + + # self.encoder = self.encoder.eval().cuda().half() + + def forward(self, tokens, src_lengths=None): + return self.encoder( + tokens, + src_lengths=src_lengths, + return_all_hiddens=False, + token_embeddings=None, + ) + + def get_layers_embedding_dim_num_heads_for_configuration(xlarge, large): + if xlarge: + # XLM-R extra large (no BERT-XL exists) + L = 24 # Layers + D = 2560 # Embedding Dim + H = 32 # Number of Heads + FD = 10240 # Feed-forward network dim + V = 30000 # Vocab Size + elif large: + # BERT-large + L = 24 + D = 1024 + H = 16 + FD = 4096 + V = 30000 + else: + # BERT-base + L = 12 + D = 768 + H = 12 + FD = 3072 + V = 30000 + + return (L, D, H, FD, V) + + # Better transformer + class PTTransformer(torch.nn.Module): + def __init__(self, transformer, embedding): + super().__init__() + self.transformer = transformer + self.embedding = embedding + self.padding_idx = DEFAULT_PADDING_IDX + + def forward(self, x): + padding_mask = None + if not x.is_nested: + padding_mask = x.eq(self.padding_idx) + x = self.embedding(x) + return self.transformer(x, src_key_padding_mask=padding_mask) + + def make_transformer(): + return ( + PTTransformer( + torch.nn.TransformerEncoder( + torch.nn.TransformerEncoderLayer( + d_model=D, + nhead=H, + dim_feedforward=FD, + batch_first=True, + activation="relu", + ), + num_layers=L, + enable_nested_tensor=False, + ), + embedding_layer, + ) + .eval() + .cuda() + ) + + def copy_weights(layers_fairseq, layers_bt): + for src_layer, dst_layer in zip(layers_fairseq, layers_bt): + w_q = src_layer.self_attn.q_proj.weight + b_q = src_layer.self_attn.q_proj.bias + w_k = src_layer.self_attn.k_proj.weight + b_k = src_layer.self_attn.k_proj.bias + w_v = src_layer.self_attn.v_proj.weight + b_v = src_layer.self_attn.v_proj.bias + dst_layer.self_attn.in_proj_weight = torch.nn.Parameter( + torch.cat((w_q, w_k, w_v), dim=0) + ) + dst_layer.self_attn.in_proj_bias = torch.nn.Parameter( + torch.cat((b_q, b_k, b_v), dim=0) + ) + + dst_layer.self_attn.out_proj.weight = src_layer.self_attn.out_proj.weight + dst_layer.self_attn.out_proj.bias = src_layer.self_attn.out_proj.bias + + dst_layer.linear1.weight = src_layer.fc1.weight + dst_layer.linear1.bias = src_layer.fc1.bias + dst_layer.linear2.weight = src_layer.fc2.weight + dst_layer.linear2.bias = src_layer.fc2.bias + + dst_layer.norm1.weight = src_layer.self_attn_layer_norm.weight + dst_layer.norm1.bias = src_layer.self_attn_layer_norm.bias + dst_layer.norm2.weight = src_layer.final_layer_norm.weight + dst_layer.norm2.bias = src_layer.final_layer_norm.bias + + (L, D, H, FD, V) = get_layers_embedding_dim_num_heads_for_configuration( + xlarge, large + ) + embedding_layer = torch.nn.Embedding(V, D, DEFAULT_PADDING_IDX) + # True means BT as source and fairseq is target, False means the other way + # mode1 = False + if bt2fairseq: + # BT as source and fairseq is target, copy BT's weight to fairseq + transformer = make_transformer() + fairseq_transformer = ( + FairseqEncoder( + D, + H, + FD, + L, + embedding_layer, + dropout=0, + normalize_before=False, + torch_encoder=transformer.transformer, + activation="relu", + ) + .eval() + .cuda() + ) + if half: + transformer.half() + fairseq_transformer.half() + if not bt2fairseq: + # the other way around, fairseq is source and BT is target,copy fairseq's weight to BT + transformer = make_transformer() + fairseq_transformer = ( + FairseqEncoder( + D, + H, + FD, + L, + embedding_layer, + dropout=0, + normalize_before=False, + torch_encoder=None, + activation="relu", + ) + .eval() + .cuda() + ) + # for the test where we need to load existing ckpt. It is tested that after loading + # the ckpt, the results between fairseq_transformer(BT kernel) equals BT + if half: + transformer.half() + fairseq_transformer.half() + if save: + torch.save(fairseq_transformer.state_dict(), "./fairseq.pt") + sys.exit(0) + if load: + fairseq_transformer.load_state_dict(torch.load("./fairseq.pt")) + # copy + copy_weights(fairseq_transformer.encoder.layers, transformer.transformer.layers) + + device = "cuda" + lengths = (avg_sequence_length,) * batch_size + tokens = torch.full( + (batch_size, max_sequence_length), + DEFAULT_PADDING_IDX, + device=device, + dtype=torch.long, + ) + for i in range(batch_size): + tokens[i, : lengths[i]] = torch.randint( + DEFAULT_PADDING_IDX + 1, + V - 1, + size=(lengths[i],), + device=device, + dtype=torch.long, + ) + # mask + if half: + lengths_tensor = torch.Tensor(lengths).cuda().half() + else: + lengths_tensor = torch.Tensor(lengths).cuda() + + with torch.inference_mode(): + fs_output = fairseq_transformer(tokens, lengths_tensor)["encoder_out"][0] + fs_output = fs_output.transpose(0, 1) + with torch.inference_mode(): + t_output = transformer(tokens) + test_lst = [ + # (name, output, relative tolerance, absolute tolerance) + ("FS", fs_output, 1e-4, 9e-3), + ] + numerical_test(lengths, t_output, test_lst) + + iters = 100 + t = benchmark_torch_function(iters, transformer, tokens) + + def bert_flops(B, T, D, L): + mlp = 2 * (B * T * D * 4 * D) + 2 * (B * T * D * 4 * D) + qkv = 3 * 2 * B * T * D * D + attn = 2 * B * D * T * T + 2 * B * D * T * T + 2 * B * T * D * D + return L * (mlp + qkv + attn) + + flops = bert_flops(batch_size, avg_sequence_length, D, L) + flops_e = ( + FlopCountAnalysis(transformer, (tokens[:, :avg_sequence_length])).total() * 2 + ) + with torch.inference_mode(): + bt = benchmark_torch_function(iters, transformer, tokens) + fst = benchmark_torch_function( + iters, fairseq_transformer, tokens, lengths_tensor + ) + + def metrics(tt, baseline=None): + if baseline: + return metrics(tt) + f", Speedup: {baseline / tt:.2f}x" + return f"{tt * 1.0e3:.2f} ms/iter, {flops_e / tt / 1.0e12:.2f} TFLOP/s" + + results = [ + f"Seed: {seed}", + f"Padded tokens: {(1-sum(lengths)/(tokens.numel()))*100:.2f}%", + f"Batch shape: {tokens.shape}", + f"Analytical flops per batch: {flops/ batch_size / 1e9:.2f} GFLOPS", + f"Empirical flops per batch: {flops_e/ batch_size / 1e9:.2f} GFLOPS", + f"B: {batch_size}", + f"T: {avg_sequence_length}", + f"TMax: {max_sequence_length}", + f"Eager Time: {metrics(t)}", + f"BetterTransformer: {metrics(bt, t)}", + f"FST: {metrics(fst, t)}", + ] + print("===========Speedup Results") + print("; ".join(results)) + + +if __name__ == "__main__": + cli() diff --git a/tests/test_export.py b/tests/test_export.py index 3e9a48d187..36fcc44550 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -92,8 +92,35 @@ def test_positional_embedding(self): scripted = torch.jit.script(module) _test_save_and_load(scripted) + def version_check(): + # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' + if "fb" in torch.__version__: + return False + else: + if "+" in torch.__version__: + torch_version = torch.__version__.split("+")[0] + else: + torch_version = torch.__version__ + + torch_version = torch_version.split(".") + int_version = ( + int(torch_version[0]) * 1000 + + int(torch_version[1]) * 10 + + int(torch_version[2]) + ) + if len(torch_version) == 3: + if int_version >= 1131: + return False + elif len(torch_version) == 4: + if int_version >= 1131 or ( + int_version == 1130 and torch_version[3][3:] >= "20220613" + ): + return False + return True + @unittest.skipIf( - torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" + version_check(), + "Targeting OSS scriptability for the 1.13.0.dev20220613 release", ) def test_export_transformer(self): task, parser = get_dummy_task_and_parser() @@ -104,7 +131,8 @@ def test_export_transformer(self): _test_save_and_load(scripted) @unittest.skipIf( - torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" + version_check(), + "Targeting OSS scriptability for the 1.13.0.dev20220613 release", ) def test_export_transformer_no_token_pos_emb(self): task, parser = get_dummy_task_and_parser() diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index 2e42df0e56..a0b6e8934c 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -22,6 +22,33 @@ DEFAULT_TEST_VOCAB_SIZE = 100 +def version_check(): + # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' + if "fb" in torch.__version__: + return False + else: + if "+" in torch.__version__: + torch_version = torch.__version__.split("+")[0] + else: + torch_version = torch.__version__ + + torch_version = torch_version.split(".") + int_version = ( + int(torch_version[0]) * 1000 + + int(torch_version[1]) * 10 + + int(torch_version[2]) + ) + if len(torch_version) == 3: + if int_version >= 1131: + return False + elif len(torch_version) == 4: + if int_version >= 1131 or ( + int_version == 1130 and torch_version[3][3:] >= "20220613" + ): + return False + return True + + class DummyTask(LegacyFairseqTask): def __init__(self, args): super().__init__(args) @@ -113,7 +140,9 @@ def _test_save_and_load(self, scripted_module): JIT_MSG = "Targeting OSS scriptability for the 1.6 release" -@unittest.skipIf(torch.__version__ < "1.6.0", JIT_MSG) +@unittest.skipIf( + version_check(), "Targeting OSS scriptability for the 1.13.0.dev20220613 release" +) class TestJitSequenceGenerator(TestJitSequenceGeneratorBase): def test_export_transformer(self): model = self.transformer_model From 08fe88479f8dd1f53705e203474a031d14cc2d75 Mon Sep 17 00:00:00 2001 From: alexeib <alexei.b@gmail.com> Date: Thu, 16 Jun 2022 14:24:29 -0700 Subject: [PATCH 641/774] reuse dataloader and workers (#3442) Summary: this PR reuses a dataloader instead of recreating it for every epoch. Creating a dataloader is expensive, and also leads to crashes with latest pytorch when spawning 1 task per gpu (e.g. using slurm). Otherwise, the behavior should remain the same. X-link: https://github.com/fairinternal/fairseq-py/pull/3442 Reviewed By: arbabu123 Differential Revision: D37162558 Pulled By: alexeib fbshipit-source-id: ea4dd0955dbf01d74aebb067116d7e38b60a031b --- fairseq/data/iterators.py | 117 ++++++++++++++++++++++++---------- fairseq/tasks/fairseq_task.py | 3 + 2 files changed, 88 insertions(+), 32 deletions(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index beb681fc70..24e7475b3d 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -11,6 +11,7 @@ import queue import time from threading import Thread +from typing import Iterator, List import numpy as np import torch @@ -217,6 +218,7 @@ def _get_iterator_for_epoch(self, epoch, shuffle, offset=0): timeout=self.timeout, worker_init_fn=worker_init_fn, pin_memory=True, + persistent_workers=self.num_workers > 0, ) # Wrap with a BufferedIterator if needed @@ -229,6 +231,34 @@ def _get_iterator_for_epoch(self, epoch, shuffle, offset=0): return itr +class FrozenBatchSampler: + def __init__( + self, + ordered_batches, + epoch, + fix_batches_to_gpus, + shuffle, + initial_offset, + ): + self.ordered_batches = ordered_batches + self.fix_batches_to_gpus = fix_batches_to_gpus + self.shuffle = shuffle + self.make_batches_for_epoch(epoch, initial_offset) + + def make_batches_for_epoch(self, epoch, offset=0): + self.batches = self.ordered_batches( + epoch, self.fix_batches_to_gpus, self.shuffle + ) + if offset > 0: + self.batches = self.batches[offset:] + + def __iter__(self) -> Iterator[List[int]]: + return iter(self.batches) + + def __len__(self) -> int: + return len(self.batches) + + class EpochBatchIterator(EpochBatchIterating): """A multi-epoch iterator over a :class:`torch.utils.data.Dataset`. @@ -288,6 +318,7 @@ def __init__( disable_shuffling=False, skip_remainder_batch=False, grouped_shuffling=False, + reuse_dataloader=False, ): assert isinstance(dataset, torch.utils.data.Dataset) self.dataset = dataset @@ -314,6 +345,9 @@ def __init__( self._next_epoch_itr = None self._supports_prefetch = getattr(dataset, "supports_prefetch", False) + self.dataloader = None + self.reuse_dataloader = reuse_dataloader + @property def frozen_batches(self): if self._frozen_batches is None: @@ -443,6 +477,55 @@ def load_state_dict(self, state_dict): def _get_iterator_for_epoch( self, epoch, shuffle, fix_batches_to_gpus=False, offset=0 ): + if self.reuse_dataloader and self.dataloader is not None: + self.batch_sampler.make_batches_for_epoch(epoch, offset) + itr = self.dataloader + else: + self.batch_sampler = FrozenBatchSampler( + self.ordered_batches, + epoch, + fix_batches_to_gpus, + shuffle, + initial_offset=offset, + ) + + if offset > 0 and len(self.batch_sampler) == 0: + return None + + if self.num_workers > 0: + os.environ["PYTHONWARNINGS"] = "ignore:semaphore_tracker:UserWarning" + + # Create data loader + itr = torch.utils.data.DataLoader( + self.dataset, + collate_fn=self.collate_fn, + batch_sampler=self.batch_sampler, + num_workers=self.num_workers, + timeout=self.timeout, + pin_memory=True, + persistent_workers=self.num_workers > 0, + ) + + if self.reuse_dataloader: + self.dataloader = itr + + # Wrap with a BufferedIterator if needed + if self.buffer_size > 0: + itr = BufferedIterator(self.buffer_size, itr) + + # Wrap with CountingIterator + itr = CountingIterator(itr, start=offset) + + if self.skip_remainder_batch: + # TODO: Below is a lazy implementation which discard the final batch regardless + # of whether it is a full batch or not. + total_num_itrs = len(self.batch_sampler) - 1 + itr.take(total_num_itrs) + logger.info(f"skip final residual batch, total_num_itrs = {total_num_itrs}") + + return itr + + def ordered_batches(self, epoch, fix_batches_to_gpus, shuffle): def shuffle_batches(batches, seed): with data_utils.numpy_seed(seed): @@ -479,38 +562,7 @@ def shuffle_batches(batches, seed): batches = list( ShardedIterator(batches, self.num_shards, self.shard_id, fill_value=[]) ) - - if offset > 0 and offset >= len(batches): - return None - - if self.num_workers > 0: - os.environ["PYTHONWARNINGS"] = "ignore:semaphore_tracker:UserWarning" - - # Create data loader - itr = torch.utils.data.DataLoader( - self.dataset, - collate_fn=self.collate_fn, - batch_sampler=batches[offset:], - num_workers=self.num_workers, - timeout=self.timeout, - pin_memory=True, - ) - - # Wrap with a BufferedIterator if needed - if self.buffer_size > 0: - itr = BufferedIterator(self.buffer_size, itr) - - # Wrap with CountingIterator - itr = CountingIterator(itr, start=offset) - - if self.skip_remainder_batch: - # TODO: Below is a lazy implementation which discard the final batch regardless - # of whether it is a full batch or not. - total_num_itrs = len(batches) - 1 - itr.take(total_num_itrs) - logger.info(f"skip final residual batch, total_num_itrs = {total_num_itrs}") - - return itr + return batches class GroupedIterator(CountingIterator): @@ -814,6 +866,7 @@ def return_full_batches(batch_sets, seed, shuffle): collate_fn=self.collate_fn, batch_sampler=batches[offset:], num_workers=self.num_workers, + persistent_workers=self.num_workers > 0, ) if self.buffer_size > 0: itr = BufferedIterator(self.buffer_size, itr) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 273dbddaa3..0d1dcf6906 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -299,6 +299,8 @@ def get_batch_iterator( required_batch_size_multiple=required_batch_size_multiple, ) + reuse_dataloader = getattr(self.cfg, "reuse_dataloader", True) + # return a reusable, sharded iterator epoch_iter = iterators.EpochBatchIterator( dataset=dataset, @@ -312,6 +314,7 @@ def get_batch_iterator( buffer_size=data_buffer_size, skip_remainder_batch=skip_remainder_batch, grouped_shuffling=grouped_shuffling, + reuse_dataloader=reuse_dataloader, ) if can_reuse_epoch_itr: From 956fcf495b2d5d696ba114520363f82148a8a649 Mon Sep 17 00:00:00 2001 From: Wei Ho <weiho@fb.com> Date: Tue, 21 Jun 2022 17:27:50 -0700 Subject: [PATCH 642/774] Back out "BT enablement on fairseq - fairseq change" Summary: Context: https://fburl.com/7vdj7vhl Backing out due to breaking our TorchScript test: ``` RuntimeError: method cannot be used as a value: File "/dev/shm/uid-30041/54641b26-seed-nspid4026533396_cgpid7154327-ns-4026533393/fairseq/modules/transformer_layer.py", line 307 self.in_proj_weight, self.in_proj_bias, self.self_attn.out_proj.weight, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <--- HERE self.self_attn.out_proj.bias, self.activation_relu_or_gelu == 2, Stack trace: Exception type: torch::jit::ErrorReport ``` https://fburl.com/sandcastle/4pzqemf5 Original commit changeset: 984266f850fc Original Phabricator Diff: D37082681 (https://github.com/facebookresearch/fairseq/commit/3a757d7ab2de97c3da5efd05712f703c26abe8d2) Differential Revision: D37303846 fbshipit-source-id: 1757ea5dae98be5beb4d08f70b0c3001d6ea336f --- .../models/transformer/transformer_encoder.py | 90 +---- fairseq/modules/transformer_layer.py | 207 ++-------- scripts/better_transformer.py | 380 ------------------ tests/test_export.py | 32 +- tests/test_sequence_generator.py | 31 +- 5 files changed, 47 insertions(+), 693 deletions(-) delete mode 100644 scripts/better_transformer.py diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index c887c5afe2..0b7e6d8379 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -8,22 +8,23 @@ import torch import torch.nn as nn -from torch import Tensor - from fairseq import utils from fairseq.distributed import fsdp_wrap from fairseq.models import FairseqEncoder -from fairseq.models.transformer import TransformerConfig from fairseq.modules import ( FairseqDropout, LayerDropModuleList, LayerNorm, PositionalEmbedding, SinusoidalPositionalEmbedding, - transformer_layer, ) +from fairseq.modules import transformer_layer from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ +from torch import Tensor +from fairseq.models.transformer import ( + TransformerConfig, +) # rewrite name for backward compatibility in `make_generation_fast_` @@ -219,79 +220,11 @@ def forward_scriptable( if return_all_hiddens: encoder_states.append(x) - # nested tensor and BT enable - layer = self.layers[0] - BT_flag = False - NT_flag = False - # torch version check, BT>=1.12.0 and NT>=1.13.0.dev20220613 - # internal format is '1.13.0a0+fb' - # external format is '1.13.0.dev20220613'(cpu&gpu) for nightly or "1.11.0"(cpu) or '1.11.0+cu102'(gpu) for stable - BT_version = False - NT_version = False - if "fb" in torch.__version__: - BT_version = True - NT_version = True - else: - if "+" in torch.__version__: - torch_version = torch.__version__.split("+")[0] - else: - torch_version = torch.__version__ - - torch_version = torch_version.split(".") - int_version = ( - int(torch_version[0]) * 1000 - + int(torch_version[1]) * 10 - + int(torch_version[2]) - ) - if len(torch_version) == 3: - if int_version >= 1120: - BT_version = True - if int_version >= 1131: - NT_version = True - elif len(torch_version) == 4: - if int_version >= 1130: - BT_version = True - # Consider _nested_tensor_from_mask_left_aligned is landed after "20220613" - if int_version >= 1131 or ( - int_version == 1130 and torch_version[3][3:] >= "20220613" - ): - NT_version = True - - if ( - BT_version - and x.dim() == 3 - and layer.load_to_BT - and not layer.return_fc - and layer.can_use_fastpath - and not layer.training - and not layer.ever_training - and not layer.cfg_checkpoint_activations - ): - # Batch first can not be justified but needs user to make sure - x = x.transpose(0, 1) - # Check mask conditions for nested tensor - if NT_version: - if ( - encoder_padding_mask is not None - and torch._nested_tensor_from_mask_left_aligned( - x, encoder_padding_mask.logical_not() - ) - ): - if not torch.is_grad_enabled() or not x.requires_grad: - x = torch._nested_tensor_from_mask( - x, encoder_padding_mask.logical_not() - ) - NT_flag = True - BT_flag = True - # encoder layers - if NT_flag: - processing_mask = None - else: - processing_mask = encoder_padding_mask - encoder_padding_mask_out = processing_mask if has_pads else None for layer in self.layers: - lr = layer(x, encoder_padding_mask=encoder_padding_mask_out) + lr = layer( + x, encoder_padding_mask=encoder_padding_mask if has_pads else None + ) if isinstance(lr, tuple) and len(lr) == 2: x, fc_result = lr @@ -304,13 +237,6 @@ def forward_scriptable( encoder_states.append(x) fc_results.append(fc_result) - # change back to non-nested and Batch second - if NT_flag: - x = x.to_padded_tensor(0.0) - - if NT_flag or BT_flag: - x = x.transpose(0, 1) - if self.layer_norm is not None: x = self.layer_norm(x) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 6589a5075e..2e687b94d0 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -7,13 +7,14 @@ import torch import torch.nn as nn -from torch import Tensor - from fairseq import utils -from fairseq.models.transformer import TransformerConfig from fairseq.modules import LayerNorm, MultiheadAttention from fairseq.modules.fairseq_dropout import FairseqDropout from fairseq.modules.quant_noise import quant_noise +from torch import Tensor +from fairseq.models.transformer import ( + TransformerConfig, +) class TransformerEncoderLayerBase(nn.Module): @@ -67,103 +68,6 @@ def __init__(self, cfg, return_fc=False): self.final_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) - self.num_heads = cfg.encoder.attention_heads - self.load_to_BT = False - self.ever_training = False - # For BT, we need continuous mem - self.in_proj_weight = torch.nn.Parameter( - torch.zeros( - self.self_attn.q_proj.weight.shape[0] * 3, - self.self_attn.q_proj.weight.shape[1], - ) - ) - self.in_proj_bias = torch.nn.Parameter( - torch.zeros(self.self_attn.q_proj.bias.shape[0] * 3) - ) - - if ( - self.activation_fn is torch.nn.functional.relu - or isinstance(self.activation_fn, torch.nn.ReLU) - or self.activation_fn == "relu" - ): - self.activation_relu_or_gelu = 1 - elif ( - self.activation_fn is torch.nn.functional.gelu - or isinstance(self.activation_fn, torch.nn.GELU) - or self.activation_fn == "gelu" - ): - self.activation_relu_or_gelu = 2 - else: - self.activation_relu_or_gelu = 0 - # Batch first can not be justified but needs user to make sure - self.can_use_fastpath = ( - not self.normalize_before - and self.activation_relu_or_gelu - and (self.self_attn_layer_norm.eps == self.final_layer_norm.eps) - ) - self.cfg_checkpoint_activations = self.cfg.checkpoint_activations - # torch version check - # make sure BT version is >=1.12.0 - self.BT_version = False - if "fb" in torch.__version__: - self.BT_version = True - else: - if "+" in torch.__version__: - self.torch_version = torch.__version__.split("+")[0] - else: - self.torch_version = torch.__version__ - - self.torch_version = self.torch_version.split(".") - self.int_version = ( - int(self.torch_version[0]) * 1000 - + int(self.torch_version[1]) * 10 - + int(self.torch_version[2]) - ) - if len(self.torch_version) == 3: - if self.int_version >= 1120: - self.BT_version = True - elif len(self.torch_version) == 4: - if self.int_version >= 1130: - self.BT_version = True - - def _load_from_state_dict( - self, - state_dict, - prefix, - local_metadata, - strict, - missing_keys, - unexpected_keys, - error_msgs, - ): - self.load_to_BT = True - - old_name = prefix + "self_attn." - q_proj_weight = state_dict[old_name + "q_proj.weight"] - k_proj_weight = state_dict[old_name + "k_proj.weight"] - v_proj_weight = state_dict[old_name + "v_proj.weight"] - q_proj_bias = state_dict[old_name + "q_proj.bias"] - k_proj_bias = state_dict[old_name + "k_proj.bias"] - v_proj_bias = state_dict[old_name + "v_proj.bias"] - - new_name = prefix - state_dict[new_name + "in_proj_weight"] = torch.cat( - (q_proj_weight, k_proj_weight, v_proj_weight), dim=0 - ) - state_dict[new_name + "in_proj_bias"] = torch.cat( - (q_proj_bias, k_proj_bias, v_proj_bias), dim=0 - ) - - super(TransformerEncoderLayerBase, self)._load_from_state_dict( - state_dict, - prefix, - local_metadata, - strict, - missing_keys, - unexpected_keys, - error_msgs, - ) - def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): return quant_noise( nn.Linear(input_dim, output_dim), p=q_noise, block_size=qn_block_size @@ -283,83 +187,44 @@ def forward( # Note that we cannot use -inf here, because at some edge cases, # the attention weight (before softmax) for some padded element in query # will become -inf, which results in NaN in model parameters - - if self.training: - self.ever_training = True - - if ( - self.BT_version - and x.dim() == 3 - and self.load_to_BT - and not self.return_fc - and self.can_use_fastpath - and not self.training - and not self.ever_training - and not self.cfg_checkpoint_activations - ): - # assume is Batch first and nested tensor - output = torch._transformer_encoder_layer_fwd( - x, - self.embed_dim, - self.num_heads, - self.in_proj_weight, - self.in_proj_bias, - self.self_attn.out_proj.weight, - self.self_attn.out_proj.bias, - self.activation_relu_or_gelu == 2, - False, # norm_first, currently not supported - self.self_attn_layer_norm.eps, - self.self_attn_layer_norm.weight, - self.self_attn_layer_norm.bias, - self.final_layer_norm.weight, - self.final_layer_norm.bias, - self.fc1.weight, - self.fc1.bias, - self.fc2.weight, - self.fc2.bias, - encoder_padding_mask if encoder_padding_mask is not None else attn_mask, + if attn_mask is not None: + attn_mask = attn_mask.masked_fill( + attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 ) - return output - - else: - if attn_mask is not None: - attn_mask = attn_mask.masked_fill( - attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 - ) - residual = x - if self.normalize_before: - x = self.self_attn_layer_norm(x) - x, _ = self.self_attn( - query=x, - key=x, - value=x, - key_padding_mask=encoder_padding_mask, - need_weights=False, - attn_mask=attn_mask, - ) - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.self_attn_layer_norm(x) + residual = x + if self.normalize_before: + x = self.self_attn_layer_norm(x) + x, _ = self.self_attn( + query=x, + key=x, + value=x, + key_padding_mask=encoder_padding_mask, + need_weights=False, + attn_mask=attn_mask, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) - residual = x - if self.normalize_before: - x = self.final_layer_norm(x) - x = self.activation_fn(self.fc1(x)) - x = self.activation_dropout_module(x) - x = self.fc2(x) + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) - fc_result = x + fc_result = x - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.final_layer_norm(x) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) - if self.return_fc and not torch.jit.is_scripting(): - return x, fc_result - return x + if self.return_fc and not torch.jit.is_scripting(): + return x, fc_result + return x # backward compatible with the legacy argparse format diff --git a/scripts/better_transformer.py b/scripts/better_transformer.py deleted file mode 100644 index 2bbf64c3c6..0000000000 --- a/scripts/better_transformer.py +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. -import sys - -import click -import numpy as np -import torch -from fvcore.nn import FlopCountAnalysis - -from fairseq.models.transformer import TransformerConfig as FairseqTransformerConfig -from fairseq.models.transformer import TransformerEncoder as FairseqTransformerEncoder - -seed = 0 -torch.manual_seed(seed) -np.random.seed(seed) - - -def benchmark_torch_function(iters, f, *args, **kwargs): - f(*args, **kwargs) - torch.cuda.synchronize() - start_event = torch.cuda.Event(enable_timing=True) - end_event = torch.cuda.Event(enable_timing=True) - start_event.record() - for _ in range(iters): - f(*args, **kwargs) - end_event.record() - torch.cuda.synchronize() - return (start_event.elapsed_time(end_event) * 1.0e-3) / iters - - -def numerical_test(lengths, truth_tensors, test_list): - """ - truth_tensors is the source of truth. - test_dict looks like - [ - (name, out_tensors, atol, rtol), - ... - ] - """ - for name, out_tensors, rtol, atol in test_list: - n_failures = 0 - max_diff = 0 - for (length, truth, out) in zip(lengths, truth_tensors, out_tensors): - cut_truth = truth[:length] - cut_out = out[:length] - max_diff = max(max_diff, torch.max(torch.abs(cut_truth - cut_out))) - if not torch.allclose(cut_truth, cut_out, atol=atol, rtol=rtol): - n_failures += 1 - - if n_failures == 0: - print(f"{name} PASS") - else: - print(f"{name} FAIL {n_failures}/{len(lengths)}. Max diff is {max_diff}") - - -@click.group() -def cli(): - pass - - -@cli.command() -@click.option("--save", is_flag=True, default=False) -@click.option("--load", is_flag=True, default=False) -@click.option("--half", is_flag=True, default=False) -@click.option("--bt2fairseq", is_flag=True, default=False) -def transformer( - save, - load, - half, - bt2fairseq, -): - xlarge = False - large = False - DEFAULT_PADDING_IDX = 1 - avg_sequence_length = 128 - max_sequence_length = 256 - batch_size = 64 - - class FairseqEncoder(torch.nn.Module): - def __init__( - self, - embed_dim, - attention_heads, - ffn_embed_dim, - num_layers, - embedding_layer, # torch.nn.Embedding. Must have a padding_idx field - dropout=0, - normalize_before=False, - torch_encoder=None, # torch encoder that you can map weights from - activation="relu", - ): - super().__init__() - - cfg = FairseqTransformerConfig() - cfg.encoder.embed_dim = embed_dim - cfg.encoder.attention_heads = attention_heads - cfg.encoder.ffn_embed_dim = ffn_embed_dim - cfg.dropout = dropout - cfg.encoder.normalize_before = normalize_before - cfg.encoder.layers = num_layers - # make embedding behavior same as other encoders - cfg.no_token_positional_embeddings = True - cfg.no_scale_embedding = True - cfg.activation_fn = activation - dictionary = {} # TODO: verify what this is - - self.encoder = FairseqTransformerEncoder( - cfg, dictionary, embedding_layer, return_fc=False - ) - - if torch_encoder is not None: - for src_layer, dst_layer in zip( - torch_encoder.layers, self.encoder.layers - ): - w_q, w_k, w_v = src_layer.self_attn.in_proj_weight.chunk(3, dim=0) - b_q, b_k, b_v = src_layer.self_attn.in_proj_bias.chunk(3, dim=0) - - dst_layer.self_attn.q_proj.weight = torch.nn.Parameter(w_q) - dst_layer.self_attn.q_proj.bias = torch.nn.Parameter(b_q) - dst_layer.self_attn.k_proj.weight = torch.nn.Parameter(w_k) - dst_layer.self_attn.k_proj.bias = torch.nn.Parameter(b_k) - dst_layer.self_attn.v_proj.weight = torch.nn.Parameter(w_v) - dst_layer.self_attn.v_proj.bias = torch.nn.Parameter(b_v) - - dst_layer.self_attn.out_proj.weight = ( - src_layer.self_attn.out_proj.weight - ) - dst_layer.self_attn.out_proj.bias = ( - src_layer.self_attn.out_proj.bias - ) - - dst_layer.fc1.weight = src_layer.linear1.weight - dst_layer.fc1.bias = src_layer.linear1.bias - - # fairseq may use fusedlayernorm from nvidia apex - diff properties - dst_layer.self_attn_layer_norm.load_state_dict( - src_layer.norm1.state_dict() - ) - - dst_layer.fc2.weight = src_layer.linear2.weight - dst_layer.fc2.bias = src_layer.linear2.bias - - dst_layer.final_layer_norm.load_state_dict( - src_layer.norm2.state_dict() - ) - - # self.encoder = self.encoder.eval().cuda().half() - - def forward(self, tokens, src_lengths=None): - return self.encoder( - tokens, - src_lengths=src_lengths, - return_all_hiddens=False, - token_embeddings=None, - ) - - def get_layers_embedding_dim_num_heads_for_configuration(xlarge, large): - if xlarge: - # XLM-R extra large (no BERT-XL exists) - L = 24 # Layers - D = 2560 # Embedding Dim - H = 32 # Number of Heads - FD = 10240 # Feed-forward network dim - V = 30000 # Vocab Size - elif large: - # BERT-large - L = 24 - D = 1024 - H = 16 - FD = 4096 - V = 30000 - else: - # BERT-base - L = 12 - D = 768 - H = 12 - FD = 3072 - V = 30000 - - return (L, D, H, FD, V) - - # Better transformer - class PTTransformer(torch.nn.Module): - def __init__(self, transformer, embedding): - super().__init__() - self.transformer = transformer - self.embedding = embedding - self.padding_idx = DEFAULT_PADDING_IDX - - def forward(self, x): - padding_mask = None - if not x.is_nested: - padding_mask = x.eq(self.padding_idx) - x = self.embedding(x) - return self.transformer(x, src_key_padding_mask=padding_mask) - - def make_transformer(): - return ( - PTTransformer( - torch.nn.TransformerEncoder( - torch.nn.TransformerEncoderLayer( - d_model=D, - nhead=H, - dim_feedforward=FD, - batch_first=True, - activation="relu", - ), - num_layers=L, - enable_nested_tensor=False, - ), - embedding_layer, - ) - .eval() - .cuda() - ) - - def copy_weights(layers_fairseq, layers_bt): - for src_layer, dst_layer in zip(layers_fairseq, layers_bt): - w_q = src_layer.self_attn.q_proj.weight - b_q = src_layer.self_attn.q_proj.bias - w_k = src_layer.self_attn.k_proj.weight - b_k = src_layer.self_attn.k_proj.bias - w_v = src_layer.self_attn.v_proj.weight - b_v = src_layer.self_attn.v_proj.bias - dst_layer.self_attn.in_proj_weight = torch.nn.Parameter( - torch.cat((w_q, w_k, w_v), dim=0) - ) - dst_layer.self_attn.in_proj_bias = torch.nn.Parameter( - torch.cat((b_q, b_k, b_v), dim=0) - ) - - dst_layer.self_attn.out_proj.weight = src_layer.self_attn.out_proj.weight - dst_layer.self_attn.out_proj.bias = src_layer.self_attn.out_proj.bias - - dst_layer.linear1.weight = src_layer.fc1.weight - dst_layer.linear1.bias = src_layer.fc1.bias - dst_layer.linear2.weight = src_layer.fc2.weight - dst_layer.linear2.bias = src_layer.fc2.bias - - dst_layer.norm1.weight = src_layer.self_attn_layer_norm.weight - dst_layer.norm1.bias = src_layer.self_attn_layer_norm.bias - dst_layer.norm2.weight = src_layer.final_layer_norm.weight - dst_layer.norm2.bias = src_layer.final_layer_norm.bias - - (L, D, H, FD, V) = get_layers_embedding_dim_num_heads_for_configuration( - xlarge, large - ) - embedding_layer = torch.nn.Embedding(V, D, DEFAULT_PADDING_IDX) - # True means BT as source and fairseq is target, False means the other way - # mode1 = False - if bt2fairseq: - # BT as source and fairseq is target, copy BT's weight to fairseq - transformer = make_transformer() - fairseq_transformer = ( - FairseqEncoder( - D, - H, - FD, - L, - embedding_layer, - dropout=0, - normalize_before=False, - torch_encoder=transformer.transformer, - activation="relu", - ) - .eval() - .cuda() - ) - if half: - transformer.half() - fairseq_transformer.half() - if not bt2fairseq: - # the other way around, fairseq is source and BT is target,copy fairseq's weight to BT - transformer = make_transformer() - fairseq_transformer = ( - FairseqEncoder( - D, - H, - FD, - L, - embedding_layer, - dropout=0, - normalize_before=False, - torch_encoder=None, - activation="relu", - ) - .eval() - .cuda() - ) - # for the test where we need to load existing ckpt. It is tested that after loading - # the ckpt, the results between fairseq_transformer(BT kernel) equals BT - if half: - transformer.half() - fairseq_transformer.half() - if save: - torch.save(fairseq_transformer.state_dict(), "./fairseq.pt") - sys.exit(0) - if load: - fairseq_transformer.load_state_dict(torch.load("./fairseq.pt")) - # copy - copy_weights(fairseq_transformer.encoder.layers, transformer.transformer.layers) - - device = "cuda" - lengths = (avg_sequence_length,) * batch_size - tokens = torch.full( - (batch_size, max_sequence_length), - DEFAULT_PADDING_IDX, - device=device, - dtype=torch.long, - ) - for i in range(batch_size): - tokens[i, : lengths[i]] = torch.randint( - DEFAULT_PADDING_IDX + 1, - V - 1, - size=(lengths[i],), - device=device, - dtype=torch.long, - ) - # mask - if half: - lengths_tensor = torch.Tensor(lengths).cuda().half() - else: - lengths_tensor = torch.Tensor(lengths).cuda() - - with torch.inference_mode(): - fs_output = fairseq_transformer(tokens, lengths_tensor)["encoder_out"][0] - fs_output = fs_output.transpose(0, 1) - with torch.inference_mode(): - t_output = transformer(tokens) - test_lst = [ - # (name, output, relative tolerance, absolute tolerance) - ("FS", fs_output, 1e-4, 9e-3), - ] - numerical_test(lengths, t_output, test_lst) - - iters = 100 - t = benchmark_torch_function(iters, transformer, tokens) - - def bert_flops(B, T, D, L): - mlp = 2 * (B * T * D * 4 * D) + 2 * (B * T * D * 4 * D) - qkv = 3 * 2 * B * T * D * D - attn = 2 * B * D * T * T + 2 * B * D * T * T + 2 * B * T * D * D - return L * (mlp + qkv + attn) - - flops = bert_flops(batch_size, avg_sequence_length, D, L) - flops_e = ( - FlopCountAnalysis(transformer, (tokens[:, :avg_sequence_length])).total() * 2 - ) - with torch.inference_mode(): - bt = benchmark_torch_function(iters, transformer, tokens) - fst = benchmark_torch_function( - iters, fairseq_transformer, tokens, lengths_tensor - ) - - def metrics(tt, baseline=None): - if baseline: - return metrics(tt) + f", Speedup: {baseline / tt:.2f}x" - return f"{tt * 1.0e3:.2f} ms/iter, {flops_e / tt / 1.0e12:.2f} TFLOP/s" - - results = [ - f"Seed: {seed}", - f"Padded tokens: {(1-sum(lengths)/(tokens.numel()))*100:.2f}%", - f"Batch shape: {tokens.shape}", - f"Analytical flops per batch: {flops/ batch_size / 1e9:.2f} GFLOPS", - f"Empirical flops per batch: {flops_e/ batch_size / 1e9:.2f} GFLOPS", - f"B: {batch_size}", - f"T: {avg_sequence_length}", - f"TMax: {max_sequence_length}", - f"Eager Time: {metrics(t)}", - f"BetterTransformer: {metrics(bt, t)}", - f"FST: {metrics(fst, t)}", - ] - print("===========Speedup Results") - print("; ".join(results)) - - -if __name__ == "__main__": - cli() diff --git a/tests/test_export.py b/tests/test_export.py index 36fcc44550..3e9a48d187 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -92,35 +92,8 @@ def test_positional_embedding(self): scripted = torch.jit.script(module) _test_save_and_load(scripted) - def version_check(): - # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' - if "fb" in torch.__version__: - return False - else: - if "+" in torch.__version__: - torch_version = torch.__version__.split("+")[0] - else: - torch_version = torch.__version__ - - torch_version = torch_version.split(".") - int_version = ( - int(torch_version[0]) * 1000 - + int(torch_version[1]) * 10 - + int(torch_version[2]) - ) - if len(torch_version) == 3: - if int_version >= 1131: - return False - elif len(torch_version) == 4: - if int_version >= 1131 or ( - int_version == 1130 and torch_version[3][3:] >= "20220613" - ): - return False - return True - @unittest.skipIf( - version_check(), - "Targeting OSS scriptability for the 1.13.0.dev20220613 release", + torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" ) def test_export_transformer(self): task, parser = get_dummy_task_and_parser() @@ -131,8 +104,7 @@ def test_export_transformer(self): _test_save_and_load(scripted) @unittest.skipIf( - version_check(), - "Targeting OSS scriptability for the 1.13.0.dev20220613 release", + torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" ) def test_export_transformer_no_token_pos_emb(self): task, parser = get_dummy_task_and_parser() diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index a0b6e8934c..2e42df0e56 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -22,33 +22,6 @@ DEFAULT_TEST_VOCAB_SIZE = 100 -def version_check(): - # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' - if "fb" in torch.__version__: - return False - else: - if "+" in torch.__version__: - torch_version = torch.__version__.split("+")[0] - else: - torch_version = torch.__version__ - - torch_version = torch_version.split(".") - int_version = ( - int(torch_version[0]) * 1000 - + int(torch_version[1]) * 10 - + int(torch_version[2]) - ) - if len(torch_version) == 3: - if int_version >= 1131: - return False - elif len(torch_version) == 4: - if int_version >= 1131 or ( - int_version == 1130 and torch_version[3][3:] >= "20220613" - ): - return False - return True - - class DummyTask(LegacyFairseqTask): def __init__(self, args): super().__init__(args) @@ -140,9 +113,7 @@ def _test_save_and_load(self, scripted_module): JIT_MSG = "Targeting OSS scriptability for the 1.6 release" -@unittest.skipIf( - version_check(), "Targeting OSS scriptability for the 1.13.0.dev20220613 release" -) +@unittest.skipIf(torch.__version__ < "1.6.0", JIT_MSG) class TestJitSequenceGenerator(TestJitSequenceGeneratorBase): def test_export_transformer(self): model = self.transformer_model From ae9b76a7221de2504f6a98644f63cdf9dd05a104 Mon Sep 17 00:00:00 2001 From: Jieru Hu <jieru@fb.com> Date: Wed, 22 Jun 2022 14:03:17 -0700 Subject: [PATCH 643/774] add check for OC version in fairseq Summary: fairseq patches a omegaconf internal util function that no longer exists in OmegaConf 2.2. This is a fix to make it compatible with both versions. Reviewed By: dianaml0 Differential Revision: D37323720 fbshipit-source-id: 1b15b86decc70776303afe4a9a4c63acfef27ffc --- fairseq/checkpoint_utils.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index aeb04f79be..138b4d1eb2 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -323,15 +323,19 @@ def load_checkpoint_to_cpu(path, arg_overrides=None, load_on_all_ranks=False): # hack to be able to set Namespace in dict config. this should be removed when we update to newer # omegaconf version that supports object flags, or when we migrate all existing models + from omegaconf import __version__ as oc_version from omegaconf import _utils - old_primitive = _utils.is_primitive_type - _utils.is_primitive_type = lambda _: True + if oc_version < "2.2": + old_primitive = _utils.is_primitive_type + _utils.is_primitive_type = lambda _: True - state["cfg"] = OmegaConf.create(state["cfg"]) + state["cfg"] = OmegaConf.create(state["cfg"]) - _utils.is_primitive_type = old_primitive - OmegaConf.set_struct(state["cfg"], True) + _utils.is_primitive_type = old_primitive + OmegaConf.set_struct(state["cfg"], True) + else: + state["cfg"] = OmegaConf.create(state["cfg"], flags={"allow_objects": True}) if arg_overrides is not None: overwrite_args_by_name(state["cfg"], arg_overrides) From 5c8aaaf123c205a9dad86bae99f89b48788f7c38 Mon Sep 17 00:00:00 2001 From: Changsheng Zhao <cszhao@fb.com> Date: Thu, 23 Jun 2022 11:02:07 -0700 Subject: [PATCH 644/774] Fix for dynamic quant decoder embedding Summary: One line change at transformer decoder to enable jit script of 8 bit dynamic quantization of embedding for translation model. f351446639. Error replicated at Bento: N2127304 {F745783045} Add option for translation model to export model with/without embedding quantization. Reviewed By: theweiho Differential Revision: D37334811 fbshipit-source-id: a95bbe70f5eba6445c2e40751bdfac24396b710c --- fairseq/models/transformer/transformer_decoder.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py index 61aaa098e9..1a0f978b3b 100644 --- a/fairseq/models/transformer/transformer_decoder.py +++ b/fairseq/models/transformer/transformer_decoder.py @@ -8,7 +8,6 @@ import torch import torch.nn as nn -from torch import Tensor from fairseq import utils from fairseq.distributed import fsdp_wrap @@ -26,6 +25,7 @@ ) from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ +from torch import Tensor # rewrite name for backward compatibility in `make_generation_fast_` @@ -302,6 +302,8 @@ def extract_features_scriptable( if positions is not None: positions = positions[:, -1:] + # Prevent torchscript exporting issue for dynamic quant embedding + prev_output_tokens = prev_output_tokens.contiguous() # embed tokens and positions x = self.embed_scale * self.embed_tokens(prev_output_tokens) From fe06598cdba9ae51c96d6d1577be8777f2c1c249 Mon Sep 17 00:00:00 2001 From: Rastislav Rabatin <rasto2211@fb.com> Date: Fri, 24 Jun 2022 01:30:35 -0700 Subject: [PATCH 645/774] Explicitly convert sequence length to integer Summary: Explicitly convert sequence length to int. Sometimes the sequence length is float tensor. Here is the exception that I was getting: Traceback (most recent call last): File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/torch/multiprocessing/spawn.py", line 69, in _wrap fn(i, *args) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq/distributed/utils.py", line 328, in distributed_main main(cfg, **kwargs) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq_cli/train.py", line 190, in main valid_losses, should_stop = train(cfg, trainer, task, epoch_itr) File "/usr/local/fbcode/platform010/lib/python3.8/contextlib.py", line 75, in inner return func(*args, **kwds) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq_cli/train.py", line 330, in train valid_losses, should_stop = validate_and_save( File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq_cli/train.py", line 421, in validate_and_save valid_losses = validate(cfg, trainer, task, epoch_itr, valid_subsets) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq_cli/train.py", line 505, in validate trainer.valid_step(sample) File "/usr/local/fbcode/platform010/lib/python3.8/contextlib.py", line 75, in inner return func(*args, **kwds) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq/trainer.py", line 1157, in valid_step logging_output = self._reduce_and_log_stats(logging_outputs, sample_size) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq/trainer.py", line 1527, in _reduce_and_log_stats logging_output = agg.get_smoothed_values() File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq/logging/meters.py", line 300, in get_smoothed_values [ File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq/logging/meters.py", line 301, in <listcomp> (key, self.get_smoothed_value(key)) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq/logging/meters.py", line 293, in get_smoothed_value return meter.fn(self) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/fairseq/tasks/translation.py", line 438, in compute_bleu bleu = comp_bleu( File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/sacrebleu/metrics/bleu.py", line 282, in compute_bleu return BLEUScore(score, correct, total, precisions, bp, sys_len, ref_len) File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/sacrebleu/metrics/bleu.py", line 103, in _init_ self._verbose += f"ratio = {self.ratio:.3f} hyp_len = {self.sys_len:d} " File "/data/sandcastle/boxes/fbsource/fbcode/buck-out/dev/gen/aab7ed39/deeplearning/projects/fairseq-py/hydra_train#link-tree/torch/_tensor.py", line 664, in _format_ return self.item().__format__(format_spec) ValueError: Unknown format code 'd' for object of type 'float' Differential Revision: D37377076 fbshipit-source-id: 2e7bb22018a446fdc8d223d8c81bea742a249ec7 --- fairseq/tasks/translation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 73b3d7c7be..79752279a6 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -438,8 +438,8 @@ def compute_bleu(meters): bleu = comp_bleu( correct=meters["_bleu_counts"].sum, total=meters["_bleu_totals"].sum, - sys_len=meters["_bleu_sys_len"].sum, - ref_len=meters["_bleu_ref_len"].sum, + sys_len=int(meters["_bleu_sys_len"].sum), + ref_len=int(meters["_bleu_ref_len"].sum), **smooth, ) return round(bleu.score, 2) From de26c455430f29ffc8dc5923e52232078b884416 Mon Sep 17 00:00:00 2001 From: Michael Voznesensky <voznesenskym@gmail.com> Date: Fri, 24 Jun 2022 12:37:57 -0700 Subject: [PATCH 646/774] Add fix and back compat for changed private omegaconf api (#4440) Summary: Alternatively, we could pin a version of omegaconf # Before submitting - [X ] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) No - [X ] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? Yes - [X ] Did you make sure to update the docs? N/A - [ X] Did you write any new necessary tests? N/A ## What does this PR do? No issue opened, but noticed when running torchbenchmark ## PR review ## Did you have fun? The most fun you can have with your clothes on Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4440 Reviewed By: dianaml0 Differential Revision: D36694085 Pulled By: alexeib fbshipit-source-id: 1175a757868aa0495644e3c782a4321e4ac85169 --- fairseq/dataclass/utils.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index f307fe6e5e..69b77962e6 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -364,13 +364,23 @@ def override_module_args(args: Namespace) -> Tuple[List[str], List[str]]: class omegaconf_no_object_check: def __init__(self): - self.old_is_primitive = _utils.is_primitive_type + # Changed in https://github.com/omry/omegaconf/pull/911 - both are kept for back compat. + if hasattr(_utils, "is_primitive_type"): + self.old_is_primitive = _utils.is_primitive_type + else: + self.old_is_primitive = _utils.is_primitive_type_annotation def __enter__(self): - _utils.is_primitive_type = lambda _: True + if hasattr(_utils, "is_primitive_type"): + _utils.is_primitive_type = lambda _: True + else: + _utils.is_primitive_type_annotation = lambda _: True def __exit__(self, type, value, traceback): - _utils.is_primitive_type = self.old_is_primitive + if hasattr(_utils, "is_primitive_type"): + _utils.is_primitive_type = self.old_is_primitive + else: + _utils.is_primitive_type_annotation = self.old_is_primitive def convert_namespace_to_omegaconf(args: Namespace) -> DictConfig: From 5528b6a38224404d80b900609463fd6864fd115a Mon Sep 17 00:00:00 2001 From: Ilia Kulikov <kulikov@fb.com> Date: Fri, 24 Jun 2022 14:09:30 -0700 Subject: [PATCH 647/774] add reading from zip audio to hubert dataset and scripts (#3403) Summary: These are changes from: https://github.com/fairinternal/fairseq-py/pull/3310 https://github.com/fairinternal/fairseq-py/pull/3285 which were in ust team branch, now moving them to the main. the main goal is to provide hubert dataset and scripts to read audio from zipped audio storage with backward compatibility depending on the given path. X-link: https://github.com/fairinternal/fairseq-py/pull/3403 Reviewed By: kahne Differential Revision: D37150156 Pulled By: uralik fbshipit-source-id: 7f249b09d7e971c6c7f99114709c26e6a35805cf --- .../simple_kmeans/dump_hubert_feature.py | 8 +- .../simple_kmeans/dump_hubert_feature_s2t.py | 37 ++++----- .../hubert/simple_kmeans/dump_mfcc_feature.py | 10 +-- fairseq/data/audio/audio_utils.py | 66 ++++++++++++++++ fairseq/data/audio/hubert_dataset.py | 14 +++- .../data/audio/speech_to_speech_dataset.py | 2 +- fairseq/data/audio/speech_to_text_dataset.py | 75 +------------------ fairseq/data/audio/text_to_speech_dataset.py | 2 +- fairseq/tasks/speech_to_text.py | 2 +- tests/speech/test_xm_transformer.py | 3 +- 10 files changed, 112 insertions(+), 107 deletions(-) diff --git a/examples/hubert/simple_kmeans/dump_hubert_feature.py b/examples/hubert/simple_kmeans/dump_hubert_feature.py index 5c7b67f8b1..7ea4ea0aa9 100644 --- a/examples/hubert/simple_kmeans/dump_hubert_feature.py +++ b/examples/hubert/simple_kmeans/dump_hubert_feature.py @@ -13,6 +13,7 @@ import torch.nn.functional as F from feature_utils import get_path_iterator, dump_feature +from fairseq.data.audio.audio_utils import get_features_or_waveform logging.basicConfig( @@ -39,8 +40,7 @@ def __init__(self, ckpt_path, layer, max_chunk=1600000): logger.info(f" max_chunk = {self.max_chunk}") def read_audio(self, path, ref_len=None): - wav, sr = sf.read(path) - assert sr == self.task.cfg.sample_rate, sr + wav = get_features_or_waveform(path, need_waveform=True, use_sample_rate=self.task.cfg.sample_rate) if wav.ndim == 2: wav = wav.mean(-1) assert wav.ndim == 1, wav.ndim @@ -49,7 +49,7 @@ def read_audio(self, path, ref_len=None): return wav def get_feats(self, path, ref_len=None): - x = self.read_audio(path, ref_len) + x = self.read_audio(path, ref_len=ref_len) with torch.no_grad(): x = torch.from_numpy(x).float().cuda() if self.task.cfg.normalize: @@ -58,7 +58,7 @@ def get_feats(self, path, ref_len=None): feat = [] for start in range(0, x.size(1), self.max_chunk): - x_chunk = x[:, start: start + self.max_chunk] + x_chunk = x[:, start : start + self.max_chunk] feat_chunk, _ = self.model.extract_features( source=x_chunk, padding_mask=None, diff --git a/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py b/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py index 6fff4faf44..941bc1b675 100644 --- a/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py +++ b/examples/hubert/simple_kmeans/dump_hubert_feature_s2t.py @@ -12,10 +12,7 @@ from dump_hubert_feature import HubertFeatureReader from feature_utils import get_shard_range, dump_feature -from fairseq.data.audio.audio_utils import get_waveform -from fairseq.data.audio.speech_to_text_dataset import ( - read_from_uncompressed_zip, -) +from fairseq.data.audio.audio_utils import get_features_or_waveform logging.basicConfig( @@ -29,14 +26,9 @@ class HubertFeatureReaderS2T(HubertFeatureReader): def read_audio(self, path, ref_len=None): - path, *extra = path.split(":") - assert len(extra) == 2 - assert path.endswith(".zip") - - data = read_from_uncompressed_zip(path, int(extra[0]), int(extra[1])) - f = io.BytesIO(data) - wav, sr = get_waveform(f) - assert sr == self.task.cfg.sample_rate, sr + wav = get_features_or_waveform( + path, need_waveform=True, use_sample_rate=self.task.cfg.sample_rate + ) if wav.ndim == 2: wav = wav.mean(-1) assert wav.ndim == 1, wav.ndim @@ -45,7 +37,7 @@ def read_audio(self, path, ref_len=None): return wav -def get_path_iterator(root, tsv, nshard, rank): +def get_path_iterator(root, tsv, nshard, rank, audio_col_name): with open(tsv) as f: reader = csv.DictReader( f, @@ -55,24 +47,34 @@ def get_path_iterator(root, tsv, nshard, rank): lineterminator="\n", quoting=csv.QUOTE_NONE, ) - subpaths = [op.join(root, e["audio"]) for e in reader] + subpaths = [op.join(root, e[audio_col_name]) for e in reader] start, end = get_shard_range(len(subpaths), nshard, rank) subpaths = subpaths[start:end] + def iterate(): for subpath in subpaths: yield op.join(root, subpath), None + return iterate, len(subpaths) def main( - root, tsv_path, ckpt_path, layer, nshard, rank, feat_dir, split, max_chunk + root, + tsv_path, + ckpt_path, + layer, + nshard, + rank, + feat_dir, + split, + max_chunk, + audio_col_name, ): reader = HubertFeatureReaderS2T(ckpt_path, layer, max_chunk) - generator, num = get_path_iterator(root, tsv_path, nshard, rank) + generator, num = get_path_iterator(root, tsv_path, nshard, rank, audio_col_name) dump_feature(reader, generator, num, split, nshard, rank, feat_dir) - if __name__ == "__main__": import argparse @@ -85,6 +87,7 @@ def main( parser.add_argument("rank", type=int) parser.add_argument("feat_dir") parser.add_argument("split") + parser.add_argument("--audio_col_name", type=str, default="audio") parser.add_argument("--max_chunk", type=int, default=1600000) args = parser.parse_args() logger.info(args) diff --git a/examples/hubert/simple_kmeans/dump_mfcc_feature.py b/examples/hubert/simple_kmeans/dump_mfcc_feature.py index 70d0016663..c3537784d1 100644 --- a/examples/hubert/simple_kmeans/dump_mfcc_feature.py +++ b/examples/hubert/simple_kmeans/dump_mfcc_feature.py @@ -12,6 +12,7 @@ import torchaudio from feature_utils import get_path_iterator, dump_feature +from fairseq.data.audio.audio_utils import get_features_or_waveform logging.basicConfig( format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", @@ -27,17 +28,13 @@ def __init__(self, sample_rate): self.sample_rate = sample_rate def read_audio(self, path, ref_len=None): - wav, sr = sf.read(path) - assert sr == self.sample_rate, sr - if wav.ndim == 2: - wav = wav.mean(-1) - assert wav.ndim == 1, wav.ndim + wav = get_features_or_waveform(path, need_waveform=True, use_sample_rate=self.sample_rate) if ref_len is not None and abs(ref_len - len(wav)) > 160: logging.warning(f"ref {ref_len} != read {len(wav)} ({path})") return wav def get_feats(self, path, ref_len=None): - x = self.read_audio(path, ref_len) + x = self.read_audio(path, ref_len=ref_len) with torch.no_grad(): x = torch.from_numpy(x).float() x = x.view(1, -1) @@ -61,7 +58,6 @@ def main(tsv_dir, split, nshard, rank, feat_dir, sample_rate): dump_feature(reader, generator, num, split, nshard, rank, feat_dir) - if __name__ == "__main__": import argparse diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index 349b86c140..34b4d73fd2 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -6,6 +6,7 @@ import mmap from pathlib import Path +import io from typing import BinaryIO, List, Optional, Tuple, Union import numpy as np @@ -117,6 +118,71 @@ def get_waveform( return waveform, sample_rate +def get_features_from_npy_or_audio(path): + ext = Path(path).suffix + if ext not in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: + raise ValueError(f'Unsupported file format for "{path}"') + return np.load(path) if ext == ".npy" else get_fbank(path) + + +def get_features_or_waveform_from_stored_zip( + path, + byte_offset, + byte_size, + need_waveform=False, + use_sample_rate=None, +): + assert path.endswith(".zip") + data = read_from_stored_zip(path, byte_offset, byte_size) + f = io.BytesIO(data) + if is_npy_data(data): + features_or_waveform = np.load(f) + elif is_sf_audio_data(data): + features_or_waveform = ( + get_waveform(f, always_2d=False, output_sample_rate=use_sample_rate)[0] + if need_waveform + else get_fbank(f) + ) + else: + raise ValueError(f'Unknown file format for "{path}"') + return features_or_waveform + + +def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=None): + """Get speech features from .npy file or waveform from .wav/.flac file. + The file may be inside an uncompressed ZIP file and is accessed via byte + offset and length. + + Args: + path (str): File path in the format of "<.npy/.wav/.flac path>" or + "<zip path>:<byte offset>:<byte length>". + need_waveform (bool): return waveform instead of features. + use_sample_rate (int): change sample rate for the input wave file + + Returns: + features_or_waveform (numpy.ndarray): speech features or waveform. + """ + _path, slice_ptr = parse_path(path) + if len(slice_ptr) == 0: + if need_waveform: + return get_waveform( + _path, always_2d=False, output_sample_rate=use_sample_rate + )[0] + return get_features_from_npy_or_audio(_path) + elif len(slice_ptr) == 2: + features_or_waveform = get_features_or_waveform_from_stored_zip( + _path, + slice_ptr[0], + slice_ptr[1], + need_waveform=need_waveform, + use_sample_rate=use_sample_rate, + ) + else: + raise ValueError(f"Invalid path: {path}") + + return features_or_waveform + + def _get_kaldi_fbank( waveform: np.ndarray, sample_rate: int, n_bins=80 ) -> Optional[np.ndarray]: diff --git a/fairseq/data/audio/hubert_dataset.py b/fairseq/data/audio/hubert_dataset.py index a69b7dc9db..f09b065fdc 100644 --- a/fairseq/data/audio/hubert_dataset.py +++ b/fairseq/data/audio/hubert_dataset.py @@ -15,6 +15,11 @@ import torch.nn.functional as F from fairseq.data import data_utils from fairseq.data.fairseq_dataset import FairseqDataset +from fairseq.data.audio.audio_utils import ( + parse_path, + read_from_stored_zip, +) +import io logger = logging.getLogger(__name__) @@ -172,7 +177,14 @@ def get_audio(self, index): import soundfile as sf wav_path = os.path.join(self.audio_root, self.audio_names[index]) - wav, cur_sample_rate = sf.read(wav_path) + _path, slice_ptr = parse_path(wav_path) + if len(slice_ptr) == 0: + wav, cur_sample_rate = sf.read(_path) + else: + assert _path.endswith(".zip") + data = read_from_stored_zip(_path, slice_ptr[0], slice_ptr[1]) + f = io.BytesIO(data) + wav, cur_sample_rate = sf.read(f) wav = torch.from_numpy(wav).float() wav = self.postprocess(wav, cur_sample_rate) return wav diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py index c768dcfb0b..4b7f8b6824 100644 --- a/fairseq/data/audio/speech_to_speech_dataset.py +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -13,11 +13,11 @@ from fairseq.data import ConcatDataset, Dictionary from fairseq.data import data_utils as fairseq_data_utils from fairseq.data.audio.data_cfg import S2SDataConfig +from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.speech_to_text_dataset import ( SpeechToTextDataset, SpeechToTextDatasetCreator, _collate_frames, - get_features_or_waveform, ) logger = logging.getLogger(__name__) diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index bfd500395d..53fd2ea203 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -18,86 +18,13 @@ from fairseq.data import ConcatDataset, Dictionary, FairseqDataset, ResamplingDataset from fairseq.data import data_utils as fairseq_data_utils -from fairseq.data.audio.audio_utils import ( - FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS, - get_fbank, - get_waveform, - is_npy_data, - is_sf_audio_data, - parse_path, - read_from_stored_zip, -) +from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.data_cfg import S2TDataConfig from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform logger = logging.getLogger(__name__) -def get_features_from_npy_or_audio(path): - ext = Path(path).suffix - if ext not in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: - raise ValueError(f'Unsupported file format for "{path}"') - return np.load(path) if ext == ".npy" else get_fbank(path) - - -def get_features_or_waveform_from_stored_zip( - path, - byte_offset, - byte_size, - need_waveform=False, - use_sample_rate=None, -): - assert path.endswith(".zip") - data = read_from_stored_zip(path, byte_offset, byte_size) - f = io.BytesIO(data) - if is_npy_data(data): - features_or_waveform = np.load(f) - elif is_sf_audio_data(data): - features_or_waveform = ( - get_waveform(f, always_2d=False, output_sample_rate=use_sample_rate)[0] - if need_waveform - else get_fbank(f) - ) - else: - raise ValueError(f'Unknown file format for "{path}"') - return features_or_waveform - - -def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=None): - """Get speech features from .npy file or waveform from .wav/.flac file. - The file may be inside an uncompressed ZIP file and is accessed via byte - offset and length. - - Args: - path (str): File path in the format of "<.npy/.wav/.flac path>" or - "<zip path>:<byte offset>:<byte length>". - need_waveform (bool): return waveform instead of features. - use_sample_rate (int): change sample rate for the input wave file - - Returns: - features_or_waveform (numpy.ndarray): speech features or waveform. - """ - _path, slice_ptr = parse_path(path) - if len(slice_ptr) == 0: - if need_waveform: - return get_waveform( - _path, always_2d=False, output_sample_rate=use_sample_rate - )[0] - return get_features_from_npy_or_audio(_path) - elif len(slice_ptr) == 2: - features_or_waveform = get_features_or_waveform_from_stored_zip( - _path, - slice_ptr[0], - slice_ptr[1], - need_waveform=need_waveform, - use_sample_rate=use_sample_rate, - ) - else: - raise ValueError(f"Invalid path: {path}") - - return features_or_waveform - - def _collate_frames( frames: List[torch.Tensor], is_audio_input: bool = False ) -> torch.Tensor: diff --git a/fairseq/data/audio/text_to_speech_dataset.py b/fairseq/data/audio/text_to_speech_dataset.py index 0e1489ae83..27e52df1a3 100644 --- a/fairseq/data/audio/text_to_speech_dataset.py +++ b/fairseq/data/audio/text_to_speech_dataset.py @@ -12,12 +12,12 @@ import numpy as np import torch +from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.speech_to_text_dataset import ( SpeechToTextDataset, SpeechToTextDatasetCreator, S2TDataConfig, _collate_frames, - get_features_or_waveform, ) from fairseq.data import Dictionary, data_utils as fairseq_data_utils diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 5818fbe62c..80e18dc072 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -8,11 +8,11 @@ from argparse import Namespace from fairseq.data import Dictionary, encoders +from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.speech_to_text_dataset import ( S2TDataConfig, SpeechToTextDataset, SpeechToTextDatasetCreator, - get_features_or_waveform, ) from fairseq.tasks import LegacyFairseqTask, register_task diff --git a/tests/speech/test_xm_transformer.py b/tests/speech/test_xm_transformer.py index 43d321befd..0a55094151 100644 --- a/tests/speech/test_xm_transformer.py +++ b/tests/speech/test_xm_transformer.py @@ -11,10 +11,11 @@ class TestXMTransformer(TestFairseqSpeech): def setUp(self): self.set_up_sotasty_es_en() + # TODO: investigate increases BLEU score (30.42 -> 31.74) def test_sotasty_es_en_600m_checkpoint(self): self.base_test( ckpt_name="xm_transformer_600m_es_en_md.pt", - reference_score=30.42, + reference_score=31.74, score_delta=0.2, max_tokens=3_000_000, max_positions=(1_000_000, 1_024), From d364fdbb269891d4c81d94b37d130eab34dcc1eb Mon Sep 17 00:00:00 2001 From: Wei Wei <wwei6@fb.com> Date: Fri, 24 Jun 2022 19:03:29 -0700 Subject: [PATCH 648/774] Reland BT enablement on fairseq - fairseq change (#4513) Summary: Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4513 With some fixes to torchscript using dual copies. Reland this diff. Reviewed By: erichan1 Differential Revision: D37371293 fbshipit-source-id: 4fcfc4083955b6f5fc4ef8600f1b517b6ba69aae --- .../models/transformer/transformer_encoder.py | 90 ++++- fairseq/modules/transformer_layer.py | 237 +++++++++-- scripts/better_transformer.py | 380 ++++++++++++++++++ tests/test_export.py | 32 +- tests/test_sequence_generator.py | 31 +- 5 files changed, 723 insertions(+), 47 deletions(-) create mode 100644 scripts/better_transformer.py diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index 0b7e6d8379..c887c5afe2 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -8,23 +8,22 @@ import torch import torch.nn as nn +from torch import Tensor + from fairseq import utils from fairseq.distributed import fsdp_wrap from fairseq.models import FairseqEncoder +from fairseq.models.transformer import TransformerConfig from fairseq.modules import ( FairseqDropout, LayerDropModuleList, LayerNorm, PositionalEmbedding, SinusoidalPositionalEmbedding, + transformer_layer, ) -from fairseq.modules import transformer_layer from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ -from torch import Tensor -from fairseq.models.transformer import ( - TransformerConfig, -) # rewrite name for backward compatibility in `make_generation_fast_` @@ -220,11 +219,79 @@ def forward_scriptable( if return_all_hiddens: encoder_states.append(x) + # nested tensor and BT enable + layer = self.layers[0] + BT_flag = False + NT_flag = False + # torch version check, BT>=1.12.0 and NT>=1.13.0.dev20220613 + # internal format is '1.13.0a0+fb' + # external format is '1.13.0.dev20220613'(cpu&gpu) for nightly or "1.11.0"(cpu) or '1.11.0+cu102'(gpu) for stable + BT_version = False + NT_version = False + if "fb" in torch.__version__: + BT_version = True + NT_version = True + else: + if "+" in torch.__version__: + torch_version = torch.__version__.split("+")[0] + else: + torch_version = torch.__version__ + + torch_version = torch_version.split(".") + int_version = ( + int(torch_version[0]) * 1000 + + int(torch_version[1]) * 10 + + int(torch_version[2]) + ) + if len(torch_version) == 3: + if int_version >= 1120: + BT_version = True + if int_version >= 1131: + NT_version = True + elif len(torch_version) == 4: + if int_version >= 1130: + BT_version = True + # Consider _nested_tensor_from_mask_left_aligned is landed after "20220613" + if int_version >= 1131 or ( + int_version == 1130 and torch_version[3][3:] >= "20220613" + ): + NT_version = True + + if ( + BT_version + and x.dim() == 3 + and layer.load_to_BT + and not layer.return_fc + and layer.can_use_fastpath + and not layer.training + and not layer.ever_training + and not layer.cfg_checkpoint_activations + ): + # Batch first can not be justified but needs user to make sure + x = x.transpose(0, 1) + # Check mask conditions for nested tensor + if NT_version: + if ( + encoder_padding_mask is not None + and torch._nested_tensor_from_mask_left_aligned( + x, encoder_padding_mask.logical_not() + ) + ): + if not torch.is_grad_enabled() or not x.requires_grad: + x = torch._nested_tensor_from_mask( + x, encoder_padding_mask.logical_not() + ) + NT_flag = True + BT_flag = True + # encoder layers + if NT_flag: + processing_mask = None + else: + processing_mask = encoder_padding_mask + encoder_padding_mask_out = processing_mask if has_pads else None for layer in self.layers: - lr = layer( - x, encoder_padding_mask=encoder_padding_mask if has_pads else None - ) + lr = layer(x, encoder_padding_mask=encoder_padding_mask_out) if isinstance(lr, tuple) and len(lr) == 2: x, fc_result = lr @@ -237,6 +304,13 @@ def forward_scriptable( encoder_states.append(x) fc_results.append(fc_result) + # change back to non-nested and Batch second + if NT_flag: + x = x.to_padded_tensor(0.0) + + if NT_flag or BT_flag: + x = x.transpose(0, 1) + if self.layer_norm is not None: x = self.layer_norm(x) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 2e687b94d0..3b98bf3764 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -7,17 +7,17 @@ import torch import torch.nn as nn +from torch import Tensor + from fairseq import utils +from fairseq.models.transformer import TransformerConfig from fairseq.modules import LayerNorm, MultiheadAttention from fairseq.modules.fairseq_dropout import FairseqDropout from fairseq.modules.quant_noise import quant_noise -from torch import Tensor -from fairseq.models.transformer import ( - TransformerConfig, -) class TransformerEncoderLayerBase(nn.Module): + """Encoder layer block. In the original paper each operation (multi-head attention or FFN) is @@ -68,6 +68,132 @@ def __init__(self, cfg, return_fc=False): self.final_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) + self.num_heads = cfg.encoder.attention_heads + self.load_to_BT = False + self.ever_training = False + # For BT, we need continuous mem + self.in_proj_weight = torch.nn.Parameter( + torch.zeros( + self.self_attn.q_proj.weight.shape[0] * 3, + self.self_attn.q_proj.weight.shape[1], + ) + ) + self.in_proj_bias = torch.nn.Parameter( + torch.zeros(self.self_attn.q_proj.bias.shape[0] * 3) + ) + self.out_proj_weight = torch.nn.Parameter( + torch.zeros( + self.self_attn.out_proj.weight.shape + ) + ) + self.out_proj_bias = torch.nn.Parameter( + torch.zeros(self.self_attn.out_proj.bias.shape) + ) + self.fc1_weight = torch.nn.Parameter( + torch.zeros( + self.fc1.weight.shape + ) + ) + self.fc1_bias = torch.nn.Parameter( + torch.zeros(self.fc1.bias.shape) + ) + self.fc2_weight = torch.nn.Parameter( + torch.zeros( + self.fc2.weight.shape + ) + ) + self.fc2_bias = torch.nn.Parameter( + torch.zeros(self.fc2.bias.shape) + ) + + if ( + self.activation_fn is torch.nn.functional.relu + or isinstance(self.activation_fn, torch.nn.ReLU) + or self.activation_fn == "relu" + ): + self.activation_relu_or_gelu = 1 + elif ( + self.activation_fn is torch.nn.functional.gelu + or isinstance(self.activation_fn, torch.nn.GELU) + or self.activation_fn == "gelu" + ): + self.activation_relu_or_gelu = 2 + else: + self.activation_relu_or_gelu = 0 + # Batch first can not be justified but needs user to make sure + self.can_use_fastpath = ( + not self.normalize_before + and self.activation_relu_or_gelu + and (self.self_attn_layer_norm.eps == self.final_layer_norm.eps) + ) + self.cfg_checkpoint_activations = self.cfg.checkpoint_activations + # torch version check + # make sure BT version is >=1.12.0 + self.BT_version = False + if "fb" in torch.__version__: + self.BT_version = True + else: + if "+" in torch.__version__: + self.torch_version = torch.__version__.split("+")[0] + else: + self.torch_version = torch.__version__ + + self.torch_version = self.torch_version.split(".") + self.int_version = ( + int(self.torch_version[0]) * 1000 + + int(self.torch_version[1]) * 10 + + int(self.torch_version[2]) + ) + if len(self.torch_version) == 3: + if self.int_version >= 1120: + self.BT_version = True + elif len(self.torch_version) == 4: + if self.int_version >= 1130: + self.BT_version = True + + def _load_from_state_dict( + self, + state_dict, + prefix, + local_metadata, + strict, + missing_keys, + unexpected_keys, + error_msgs, + ): + self.load_to_BT = True + + old_name = prefix + "self_attn." + q_proj_weight = state_dict[old_name + "q_proj.weight"] + k_proj_weight = state_dict[old_name + "k_proj.weight"] + v_proj_weight = state_dict[old_name + "v_proj.weight"] + q_proj_bias = state_dict[old_name + "q_proj.bias"] + k_proj_bias = state_dict[old_name + "k_proj.bias"] + v_proj_bias = state_dict[old_name + "v_proj.bias"] + + new_name = prefix + state_dict[new_name + "in_proj_weight"] = torch.cat( + (q_proj_weight, k_proj_weight, v_proj_weight), dim=0 + ) + state_dict[new_name + "in_proj_bias"] = torch.cat( + (q_proj_bias, k_proj_bias, v_proj_bias), dim=0 + ) + state_dict[new_name + "out_proj_weight"] = state_dict[old_name + "out_proj.weight"] + state_dict[new_name + "out_proj_bias"] = state_dict[old_name + "out_proj.bias"] + state_dict[new_name + "fc1_weight"] = state_dict[prefix + "fc1.weight"] + state_dict[new_name + "fc1_bias"] = state_dict[prefix + "fc1.bias"] + state_dict[new_name + "fc2_weight"] = state_dict[prefix + "fc2.weight"] + state_dict[new_name + "fc2_bias"] = state_dict[prefix + "fc2.bias"] + super(TransformerEncoderLayerBase, self)._load_from_state_dict( + state_dict, + prefix, + local_metadata, + strict, + missing_keys, + unexpected_keys, + error_msgs, + ) + def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): return quant_noise( nn.Linear(input_dim, output_dim), p=q_noise, block_size=qn_block_size @@ -187,44 +313,83 @@ def forward( # Note that we cannot use -inf here, because at some edge cases, # the attention weight (before softmax) for some padded element in query # will become -inf, which results in NaN in model parameters - if attn_mask is not None: - attn_mask = attn_mask.masked_fill( - attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 + + if self.training: + self.ever_training = True + + if ( + self.BT_version + and x.dim() == 3 + and self.load_to_BT + and not self.return_fc + and self.can_use_fastpath + and not self.training + and not self.ever_training + and not self.cfg_checkpoint_activations + ): + # assume is Batch first and nested tensor + output = torch._transformer_encoder_layer_fwd( + x, + self.embed_dim, + self.num_heads, + self.in_proj_weight, + self.in_proj_bias, + self.out_proj_weight, + self.out_proj_bias, + self.activation_relu_or_gelu == 2, + False, # norm_first, currently not supported + self.self_attn_layer_norm.eps, + self.self_attn_layer_norm.weight, + self.self_attn_layer_norm.bias, + self.final_layer_norm.weight, + self.final_layer_norm.bias, + self.fc1_weight, + self.fc1_bias, + self.fc2_weight, + self.fc2_bias, + encoder_padding_mask if encoder_padding_mask is not None else attn_mask, ) + return output - residual = x - if self.normalize_before: - x = self.self_attn_layer_norm(x) - x, _ = self.self_attn( - query=x, - key=x, - value=x, - key_padding_mask=encoder_padding_mask, - need_weights=False, - attn_mask=attn_mask, - ) - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.self_attn_layer_norm(x) + else: + if attn_mask is not None: + attn_mask = attn_mask.masked_fill( + attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 + ) - residual = x - if self.normalize_before: - x = self.final_layer_norm(x) - x = self.activation_fn(self.fc1(x)) - x = self.activation_dropout_module(x) - x = self.fc2(x) + residual = x + if self.normalize_before: + x = self.self_attn_layer_norm(x) + x, _ = self.self_attn( + query=x, + key=x, + value=x, + key_padding_mask=encoder_padding_mask, + need_weights=False, + attn_mask=attn_mask, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) - fc_result = x + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.final_layer_norm(x) + fc_result = x + + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) - if self.return_fc and not torch.jit.is_scripting(): - return x, fc_result - return x + if self.return_fc and not torch.jit.is_scripting(): + return x, fc_result + return x # backward compatible with the legacy argparse format diff --git a/scripts/better_transformer.py b/scripts/better_transformer.py new file mode 100644 index 0000000000..2bbf64c3c6 --- /dev/null +++ b/scripts/better_transformer.py @@ -0,0 +1,380 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. +import sys + +import click +import numpy as np +import torch +from fvcore.nn import FlopCountAnalysis + +from fairseq.models.transformer import TransformerConfig as FairseqTransformerConfig +from fairseq.models.transformer import TransformerEncoder as FairseqTransformerEncoder + +seed = 0 +torch.manual_seed(seed) +np.random.seed(seed) + + +def benchmark_torch_function(iters, f, *args, **kwargs): + f(*args, **kwargs) + torch.cuda.synchronize() + start_event = torch.cuda.Event(enable_timing=True) + end_event = torch.cuda.Event(enable_timing=True) + start_event.record() + for _ in range(iters): + f(*args, **kwargs) + end_event.record() + torch.cuda.synchronize() + return (start_event.elapsed_time(end_event) * 1.0e-3) / iters + + +def numerical_test(lengths, truth_tensors, test_list): + """ + truth_tensors is the source of truth. + test_dict looks like + [ + (name, out_tensors, atol, rtol), + ... + ] + """ + for name, out_tensors, rtol, atol in test_list: + n_failures = 0 + max_diff = 0 + for (length, truth, out) in zip(lengths, truth_tensors, out_tensors): + cut_truth = truth[:length] + cut_out = out[:length] + max_diff = max(max_diff, torch.max(torch.abs(cut_truth - cut_out))) + if not torch.allclose(cut_truth, cut_out, atol=atol, rtol=rtol): + n_failures += 1 + + if n_failures == 0: + print(f"{name} PASS") + else: + print(f"{name} FAIL {n_failures}/{len(lengths)}. Max diff is {max_diff}") + + +@click.group() +def cli(): + pass + + +@cli.command() +@click.option("--save", is_flag=True, default=False) +@click.option("--load", is_flag=True, default=False) +@click.option("--half", is_flag=True, default=False) +@click.option("--bt2fairseq", is_flag=True, default=False) +def transformer( + save, + load, + half, + bt2fairseq, +): + xlarge = False + large = False + DEFAULT_PADDING_IDX = 1 + avg_sequence_length = 128 + max_sequence_length = 256 + batch_size = 64 + + class FairseqEncoder(torch.nn.Module): + def __init__( + self, + embed_dim, + attention_heads, + ffn_embed_dim, + num_layers, + embedding_layer, # torch.nn.Embedding. Must have a padding_idx field + dropout=0, + normalize_before=False, + torch_encoder=None, # torch encoder that you can map weights from + activation="relu", + ): + super().__init__() + + cfg = FairseqTransformerConfig() + cfg.encoder.embed_dim = embed_dim + cfg.encoder.attention_heads = attention_heads + cfg.encoder.ffn_embed_dim = ffn_embed_dim + cfg.dropout = dropout + cfg.encoder.normalize_before = normalize_before + cfg.encoder.layers = num_layers + # make embedding behavior same as other encoders + cfg.no_token_positional_embeddings = True + cfg.no_scale_embedding = True + cfg.activation_fn = activation + dictionary = {} # TODO: verify what this is + + self.encoder = FairseqTransformerEncoder( + cfg, dictionary, embedding_layer, return_fc=False + ) + + if torch_encoder is not None: + for src_layer, dst_layer in zip( + torch_encoder.layers, self.encoder.layers + ): + w_q, w_k, w_v = src_layer.self_attn.in_proj_weight.chunk(3, dim=0) + b_q, b_k, b_v = src_layer.self_attn.in_proj_bias.chunk(3, dim=0) + + dst_layer.self_attn.q_proj.weight = torch.nn.Parameter(w_q) + dst_layer.self_attn.q_proj.bias = torch.nn.Parameter(b_q) + dst_layer.self_attn.k_proj.weight = torch.nn.Parameter(w_k) + dst_layer.self_attn.k_proj.bias = torch.nn.Parameter(b_k) + dst_layer.self_attn.v_proj.weight = torch.nn.Parameter(w_v) + dst_layer.self_attn.v_proj.bias = torch.nn.Parameter(b_v) + + dst_layer.self_attn.out_proj.weight = ( + src_layer.self_attn.out_proj.weight + ) + dst_layer.self_attn.out_proj.bias = ( + src_layer.self_attn.out_proj.bias + ) + + dst_layer.fc1.weight = src_layer.linear1.weight + dst_layer.fc1.bias = src_layer.linear1.bias + + # fairseq may use fusedlayernorm from nvidia apex - diff properties + dst_layer.self_attn_layer_norm.load_state_dict( + src_layer.norm1.state_dict() + ) + + dst_layer.fc2.weight = src_layer.linear2.weight + dst_layer.fc2.bias = src_layer.linear2.bias + + dst_layer.final_layer_norm.load_state_dict( + src_layer.norm2.state_dict() + ) + + # self.encoder = self.encoder.eval().cuda().half() + + def forward(self, tokens, src_lengths=None): + return self.encoder( + tokens, + src_lengths=src_lengths, + return_all_hiddens=False, + token_embeddings=None, + ) + + def get_layers_embedding_dim_num_heads_for_configuration(xlarge, large): + if xlarge: + # XLM-R extra large (no BERT-XL exists) + L = 24 # Layers + D = 2560 # Embedding Dim + H = 32 # Number of Heads + FD = 10240 # Feed-forward network dim + V = 30000 # Vocab Size + elif large: + # BERT-large + L = 24 + D = 1024 + H = 16 + FD = 4096 + V = 30000 + else: + # BERT-base + L = 12 + D = 768 + H = 12 + FD = 3072 + V = 30000 + + return (L, D, H, FD, V) + + # Better transformer + class PTTransformer(torch.nn.Module): + def __init__(self, transformer, embedding): + super().__init__() + self.transformer = transformer + self.embedding = embedding + self.padding_idx = DEFAULT_PADDING_IDX + + def forward(self, x): + padding_mask = None + if not x.is_nested: + padding_mask = x.eq(self.padding_idx) + x = self.embedding(x) + return self.transformer(x, src_key_padding_mask=padding_mask) + + def make_transformer(): + return ( + PTTransformer( + torch.nn.TransformerEncoder( + torch.nn.TransformerEncoderLayer( + d_model=D, + nhead=H, + dim_feedforward=FD, + batch_first=True, + activation="relu", + ), + num_layers=L, + enable_nested_tensor=False, + ), + embedding_layer, + ) + .eval() + .cuda() + ) + + def copy_weights(layers_fairseq, layers_bt): + for src_layer, dst_layer in zip(layers_fairseq, layers_bt): + w_q = src_layer.self_attn.q_proj.weight + b_q = src_layer.self_attn.q_proj.bias + w_k = src_layer.self_attn.k_proj.weight + b_k = src_layer.self_attn.k_proj.bias + w_v = src_layer.self_attn.v_proj.weight + b_v = src_layer.self_attn.v_proj.bias + dst_layer.self_attn.in_proj_weight = torch.nn.Parameter( + torch.cat((w_q, w_k, w_v), dim=0) + ) + dst_layer.self_attn.in_proj_bias = torch.nn.Parameter( + torch.cat((b_q, b_k, b_v), dim=0) + ) + + dst_layer.self_attn.out_proj.weight = src_layer.self_attn.out_proj.weight + dst_layer.self_attn.out_proj.bias = src_layer.self_attn.out_proj.bias + + dst_layer.linear1.weight = src_layer.fc1.weight + dst_layer.linear1.bias = src_layer.fc1.bias + dst_layer.linear2.weight = src_layer.fc2.weight + dst_layer.linear2.bias = src_layer.fc2.bias + + dst_layer.norm1.weight = src_layer.self_attn_layer_norm.weight + dst_layer.norm1.bias = src_layer.self_attn_layer_norm.bias + dst_layer.norm2.weight = src_layer.final_layer_norm.weight + dst_layer.norm2.bias = src_layer.final_layer_norm.bias + + (L, D, H, FD, V) = get_layers_embedding_dim_num_heads_for_configuration( + xlarge, large + ) + embedding_layer = torch.nn.Embedding(V, D, DEFAULT_PADDING_IDX) + # True means BT as source and fairseq is target, False means the other way + # mode1 = False + if bt2fairseq: + # BT as source and fairseq is target, copy BT's weight to fairseq + transformer = make_transformer() + fairseq_transformer = ( + FairseqEncoder( + D, + H, + FD, + L, + embedding_layer, + dropout=0, + normalize_before=False, + torch_encoder=transformer.transformer, + activation="relu", + ) + .eval() + .cuda() + ) + if half: + transformer.half() + fairseq_transformer.half() + if not bt2fairseq: + # the other way around, fairseq is source and BT is target,copy fairseq's weight to BT + transformer = make_transformer() + fairseq_transformer = ( + FairseqEncoder( + D, + H, + FD, + L, + embedding_layer, + dropout=0, + normalize_before=False, + torch_encoder=None, + activation="relu", + ) + .eval() + .cuda() + ) + # for the test where we need to load existing ckpt. It is tested that after loading + # the ckpt, the results between fairseq_transformer(BT kernel) equals BT + if half: + transformer.half() + fairseq_transformer.half() + if save: + torch.save(fairseq_transformer.state_dict(), "./fairseq.pt") + sys.exit(0) + if load: + fairseq_transformer.load_state_dict(torch.load("./fairseq.pt")) + # copy + copy_weights(fairseq_transformer.encoder.layers, transformer.transformer.layers) + + device = "cuda" + lengths = (avg_sequence_length,) * batch_size + tokens = torch.full( + (batch_size, max_sequence_length), + DEFAULT_PADDING_IDX, + device=device, + dtype=torch.long, + ) + for i in range(batch_size): + tokens[i, : lengths[i]] = torch.randint( + DEFAULT_PADDING_IDX + 1, + V - 1, + size=(lengths[i],), + device=device, + dtype=torch.long, + ) + # mask + if half: + lengths_tensor = torch.Tensor(lengths).cuda().half() + else: + lengths_tensor = torch.Tensor(lengths).cuda() + + with torch.inference_mode(): + fs_output = fairseq_transformer(tokens, lengths_tensor)["encoder_out"][0] + fs_output = fs_output.transpose(0, 1) + with torch.inference_mode(): + t_output = transformer(tokens) + test_lst = [ + # (name, output, relative tolerance, absolute tolerance) + ("FS", fs_output, 1e-4, 9e-3), + ] + numerical_test(lengths, t_output, test_lst) + + iters = 100 + t = benchmark_torch_function(iters, transformer, tokens) + + def bert_flops(B, T, D, L): + mlp = 2 * (B * T * D * 4 * D) + 2 * (B * T * D * 4 * D) + qkv = 3 * 2 * B * T * D * D + attn = 2 * B * D * T * T + 2 * B * D * T * T + 2 * B * T * D * D + return L * (mlp + qkv + attn) + + flops = bert_flops(batch_size, avg_sequence_length, D, L) + flops_e = ( + FlopCountAnalysis(transformer, (tokens[:, :avg_sequence_length])).total() * 2 + ) + with torch.inference_mode(): + bt = benchmark_torch_function(iters, transformer, tokens) + fst = benchmark_torch_function( + iters, fairseq_transformer, tokens, lengths_tensor + ) + + def metrics(tt, baseline=None): + if baseline: + return metrics(tt) + f", Speedup: {baseline / tt:.2f}x" + return f"{tt * 1.0e3:.2f} ms/iter, {flops_e / tt / 1.0e12:.2f} TFLOP/s" + + results = [ + f"Seed: {seed}", + f"Padded tokens: {(1-sum(lengths)/(tokens.numel()))*100:.2f}%", + f"Batch shape: {tokens.shape}", + f"Analytical flops per batch: {flops/ batch_size / 1e9:.2f} GFLOPS", + f"Empirical flops per batch: {flops_e/ batch_size / 1e9:.2f} GFLOPS", + f"B: {batch_size}", + f"T: {avg_sequence_length}", + f"TMax: {max_sequence_length}", + f"Eager Time: {metrics(t)}", + f"BetterTransformer: {metrics(bt, t)}", + f"FST: {metrics(fst, t)}", + ] + print("===========Speedup Results") + print("; ".join(results)) + + +if __name__ == "__main__": + cli() diff --git a/tests/test_export.py b/tests/test_export.py index 3e9a48d187..36fcc44550 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -92,8 +92,35 @@ def test_positional_embedding(self): scripted = torch.jit.script(module) _test_save_and_load(scripted) + def version_check(): + # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' + if "fb" in torch.__version__: + return False + else: + if "+" in torch.__version__: + torch_version = torch.__version__.split("+")[0] + else: + torch_version = torch.__version__ + + torch_version = torch_version.split(".") + int_version = ( + int(torch_version[0]) * 1000 + + int(torch_version[1]) * 10 + + int(torch_version[2]) + ) + if len(torch_version) == 3: + if int_version >= 1131: + return False + elif len(torch_version) == 4: + if int_version >= 1131 or ( + int_version == 1130 and torch_version[3][3:] >= "20220613" + ): + return False + return True + @unittest.skipIf( - torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" + version_check(), + "Targeting OSS scriptability for the 1.13.0.dev20220613 release", ) def test_export_transformer(self): task, parser = get_dummy_task_and_parser() @@ -104,7 +131,8 @@ def test_export_transformer(self): _test_save_and_load(scripted) @unittest.skipIf( - torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" + version_check(), + "Targeting OSS scriptability for the 1.13.0.dev20220613 release", ) def test_export_transformer_no_token_pos_emb(self): task, parser = get_dummy_task_and_parser() diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index 2e42df0e56..a0b6e8934c 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -22,6 +22,33 @@ DEFAULT_TEST_VOCAB_SIZE = 100 +def version_check(): + # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' + if "fb" in torch.__version__: + return False + else: + if "+" in torch.__version__: + torch_version = torch.__version__.split("+")[0] + else: + torch_version = torch.__version__ + + torch_version = torch_version.split(".") + int_version = ( + int(torch_version[0]) * 1000 + + int(torch_version[1]) * 10 + + int(torch_version[2]) + ) + if len(torch_version) == 3: + if int_version >= 1131: + return False + elif len(torch_version) == 4: + if int_version >= 1131 or ( + int_version == 1130 and torch_version[3][3:] >= "20220613" + ): + return False + return True + + class DummyTask(LegacyFairseqTask): def __init__(self, args): super().__init__(args) @@ -113,7 +140,9 @@ def _test_save_and_load(self, scripted_module): JIT_MSG = "Targeting OSS scriptability for the 1.6 release" -@unittest.skipIf(torch.__version__ < "1.6.0", JIT_MSG) +@unittest.skipIf( + version_check(), "Targeting OSS scriptability for the 1.13.0.dev20220613 release" +) class TestJitSequenceGenerator(TestJitSequenceGeneratorBase): def test_export_transformer(self): model = self.transformer_model From d83f376b8991488219a606bf302e5b3310d4e850 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Mon, 27 Jun 2022 09:12:44 -0700 Subject: [PATCH 649/774] Fix sdist install error (#4511) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: https://github.com/facebookresearch/fairseq/issues/4501 # Before submitting - [x] Was this discussed/approved via a Github issue? (no need for typos, doc improvements) - [x] Did you read the [contributor guideline](https://github.com/pytorch/fairseq/blob/main/CONTRIBUTING.md)? - [x] Did you make sure to update the docs? - [x] Did you write any new necessary tests? ## What does this PR do? Fixes https://github.com/facebookresearch/fairseq/issues/4501 . ## PR review Anyone in the community is free to review the PR once the tests have passed. If we didn't discuss your PR in Github issues there's a high chance it will not be merged. ## Did you have fun? Make sure you had fun coding � Pull Request resolved: https://github.com/facebookresearch/fairseq/pull/4511 Reviewed By: cbalioglu Differential Revision: D37415937 Pulled By: dianaml0 fbshipit-source-id: bed8cd8e6db23f161fc96e32a0b14535b2373a43 --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000..4f719da85c --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include fairseq/version.txt From 4ee361cb45fdc5c914e4adb746d560a26cddbd40 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Mon, 27 Jun 2022 12:30:10 -0400 Subject: [PATCH 650/774] fix format (#4515) Co-authored-by: Diana Liskovich <dianaml@devfair0471.h2.fair> --- fairseq/modules/transformer_layer.py | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 3b98bf3764..1b6b713025 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -82,29 +82,15 @@ def __init__(self, cfg, return_fc=False): torch.zeros(self.self_attn.q_proj.bias.shape[0] * 3) ) self.out_proj_weight = torch.nn.Parameter( - torch.zeros( - self.self_attn.out_proj.weight.shape - ) + torch.zeros(self.self_attn.out_proj.weight.shape) ) self.out_proj_bias = torch.nn.Parameter( torch.zeros(self.self_attn.out_proj.bias.shape) ) - self.fc1_weight = torch.nn.Parameter( - torch.zeros( - self.fc1.weight.shape - ) - ) - self.fc1_bias = torch.nn.Parameter( - torch.zeros(self.fc1.bias.shape) - ) - self.fc2_weight = torch.nn.Parameter( - torch.zeros( - self.fc2.weight.shape - ) - ) - self.fc2_bias = torch.nn.Parameter( - torch.zeros(self.fc2.bias.shape) - ) + self.fc1_weight = torch.nn.Parameter(torch.zeros(self.fc1.weight.shape)) + self.fc1_bias = torch.nn.Parameter(torch.zeros(self.fc1.bias.shape)) + self.fc2_weight = torch.nn.Parameter(torch.zeros(self.fc2.weight.shape)) + self.fc2_bias = torch.nn.Parameter(torch.zeros(self.fc2.bias.shape)) if ( self.activation_fn is torch.nn.functional.relu @@ -178,7 +164,9 @@ def _load_from_state_dict( state_dict[new_name + "in_proj_bias"] = torch.cat( (q_proj_bias, k_proj_bias, v_proj_bias), dim=0 ) - state_dict[new_name + "out_proj_weight"] = state_dict[old_name + "out_proj.weight"] + state_dict[new_name + "out_proj_weight"] = state_dict[ + old_name + "out_proj.weight" + ] state_dict[new_name + "out_proj_bias"] = state_dict[old_name + "out_proj.bias"] state_dict[new_name + "fc1_weight"] = state_dict[prefix + "fc1.weight"] state_dict[new_name + "fc1_bias"] = state_dict[prefix + "fc1.bias"] From 58c8041c17446872bdf22aed8009b9f3d5fbf645 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Mon, 27 Jun 2022 15:34:49 -0400 Subject: [PATCH 651/774] v0.12.2 release (#4516) --- fairseq/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/version.txt b/fairseq/version.txt index aac2dacab4..e96a87111c 100644 --- a/fairseq/version.txt +++ b/fairseq/version.txt @@ -1 +1 @@ -0.12.1 \ No newline at end of file +0.12.2 \ No newline at end of file From fe56de410cefcccfd9ea49f96ed9a79271338018 Mon Sep 17 00:00:00 2001 From: Xuan-Phi Nguyen <nxphi47@gmail.com> Date: Tue, 28 Jun 2022 12:06:52 -0700 Subject: [PATCH 652/774] Hot_reload_debug (#4519) * Add hot reload function decorator, allow faster debugging without reloading models and data. --- fairseq/utils.py | 101 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/fairseq/utils.py b/fairseq/utils.py index 4852f48863..b6a7e2339b 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -840,3 +840,104 @@ def safe_getattr(obj, k, default=None): def safe_hasattr(obj, k): """Returns True if the given key exists and is not None.""" return getattr(obj, k, None) is not None + + +def hotreload_function(name=None): + """ + Decorator to function to enable hot-reload for debugging. + It allows you to debug a function without having reloading all heavy models, dataset loading and + preprocessing, allow faster debugging. + If you want to change model or dataset loading, consider relaunching your code + ----------------------------------- + This will run the decorated function func: + if func run successful: + It will pause, allow user to edit code, and prompt user to: + Press enter to re-run the function with updated code + Type "done" to finish the function, return output + Type "disable" to stop pausing this function and let code continue without pause + Ctril + C to terminal + if func raise error: + it will prompt user to + 1. Edit code, and press enter to retry + 2. Ctrl + C to terminate + 3. Type "raise" to raise that exception + * Requirements: + 0. Fairseq was installed with `pip install --editable .` + 1. pip install jurigged[develoop] + 2. set environment HOTRELOAD_PAUSE=1 CUDA_LAUNCH_BLOCKING=1 + 3. Run on only 1 GPU (no distributed) + * How to use: + 1. in python, import and decorate the top-level function to be re-run after code edits: + ```python + from fairseq.utils import hotreload_function + .... + @hotreload_function("train_step") + def train_step(self, sample ....): + .... + .... + ``` + 2. in bash run scripts: + ```bash + watch_dir=<home>/fairseq-py/fairseq/tasks # directory to watch for file changes + export CUDA_VISIBLE_DEVICES=0 # single-gpu + HOTRELOAD_PAUSE=1 CUDA_LAUNCH_BLOCKING=1 python -m jurigged -w ${watch_dir} --poll 2 -v train.py ...... + ``` + * NOTE: + 1. -w ${watch_dir} specify all the files to be watched for changes + once functions, class, ... code are changed, all instances in the process will get updated (hot-reload) + * Limitation: + * Currently distributed debugging not working + * Need to launch train.py locally (cannot submit jobs) + """ + try: + import jurigged + except ImportError as e: + logger.warning(f'Please install jurigged: pip install jurigged[develoop]') + raise e + from fairseq.distributed import utils as distributed_utils + import traceback + + def hotreload_decorator(func): + assert callable(func), f'not callable: {func}' + jname = name or func.__name__ + logger.info(f'jurigged-hotreload:Apply jurigged on {jname}:{func.__name__}') + HOTRELOAD_PAUSE = bool(os.environ.get("HOTRELOAD_PAUSE", 0)) + cublk = bool(os.environ.get("CUDA_LAUNCH_BLOCKING", 0)) + prefix = f"HOTRELOAD:{jname}:[cublk={cublk}]" + hot_reload_state = {"disable": False} + def func_wrapper(*args, **kwargs): + if not HOTRELOAD_PAUSE or hot_reload_state['disable']: + return func(*args, **kwargs) + world_size = distributed_utils.get_global_world_size() + assert world_size <= 1, f'HOTRELOAD_PAUSE:{jname} currently cannot do distributed training' + success = False + while not success: + try: + output = func(*args, **kwargs) + # success = True + end_action = input(f'{prefix}: PAUSE, you may edit code now. Enter to re-run, ctrl+C to terminate, ' + f'type "done" to continue (function still being watched), or type "disable" to stop pausing this function :') + if end_action.strip().lower() in ["disable", "done"]: + success = True + else: + logger.warning(f'{prefix}: action={end_action} function will re-run now.') + except Exception as e: + action = input( + f'{prefix}:ERROR: \n{traceback.format_exc()}\n' + f'Edit code to try again: enter to continue, ctrl+C to terminate, or type "raise" to raise the exception: ' + ) + if action.strip().lower() == "raise": + raise e + + if end_action.strip().lower() == "disable": + logger.warning( + f'{prefix}: Stop pausing {jname}. The function is still being watched and newly editted code will take effect ' + f'if the {jname} is called again later.' + f' "unset HOTRELOAD_PAUSE" before relaunch to disable hotreload and' + f' remove @hotreload_function decorator in the code.' + ) + hot_reload_state['disable'] = True + return output + return func_wrapper + return hotreload_decorator + From a6a63279422f846a3c2f6c45b9c96d6951cc4b82 Mon Sep 17 00:00:00 2001 From: Alexander Jipa <alexander.jipa@gmail.com> Date: Tue, 28 Jun 2022 15:44:18 -0400 Subject: [PATCH 653/774] switch denoising and multilingual_denoising tasks to OmegaConf (#4447) Co-authored-by: Alexander Jipa <azzhipa@amazon.com> --- fairseq/data/denoising_dataset.py | 37 +-- fairseq/tasks/denoising.py | 286 +++++++++++---------- fairseq/tasks/multilingual_denoising.py | 126 +++++---- tests/tasks/test_denoising.py | 96 +++++++ tests/tasks/test_multilingual_denoising.py | 98 +++++++ 5 files changed, 439 insertions(+), 204 deletions(-) create mode 100644 tests/tasks/test_denoising.py create mode 100644 tests/tasks/test_multilingual_denoising.py diff --git a/fairseq/data/denoising_dataset.py b/fairseq/data/denoising_dataset.py index bdb62c8d5d..a900fc6f96 100644 --- a/fairseq/data/denoising_dataset.py +++ b/fairseq/data/denoising_dataset.py @@ -107,7 +107,6 @@ class DenoisingDataset(FairseqDataset): shuffle (bool, optional): shuffle the elements before batching. Default: ``True`` seed: Seed for random number generator for reproducibility. - args: argparse arguments. """ def __init__( @@ -119,7 +118,15 @@ def __init__( mask_whole_words, shuffle, seed, - args, + mask, + mask_random, + insert, + rotate, + permute_sentences, + bpe, + replace_length, + mask_length, + poisson_lambda, eos=None, item_transform_func=None, ): @@ -132,31 +139,31 @@ def __init__( self.seed = seed self.mask_idx = mask_idx self.mask_whole_word = mask_whole_words - self.mask_ratio = args.mask - self.random_ratio = args.mask_random - self.insert_ratio = args.insert - self.rotate_ratio = args.rotate - self.permute_sentence_ratio = args.permute_sentences + self.mask_ratio = mask + self.random_ratio = mask_random + self.insert_ratio = insert + self.rotate_ratio = rotate + self.permute_sentence_ratio = permute_sentences self.eos = eos if eos is not None else vocab.eos() self.item_transform_func = item_transform_func - if args.bpe != "gpt2": + if bpe != "gpt2": self.full_stop_index = self.vocab.eos() else: - assert args.bpe == "gpt2" + assert bpe == "gpt2" self.full_stop_index = self.vocab.index("13") - self.replace_length = args.replace_length + self.replace_length = replace_length if self.replace_length not in [-1, 0, 1]: raise ValueError(f"invalid arg: replace_length={self.replace_length}") - if args.mask_length not in ["subword", "word", "span-poisson"]: - raise ValueError(f"invalid arg: mask-length={args.mask_length}") - if args.mask_length == "subword" and args.replace_length not in [0, 1]: + if mask_length not in ["subword", "word", "span-poisson"]: + raise ValueError(f"invalid arg: mask-length={mask_length}") + if mask_length == "subword" and replace_length not in [0, 1]: raise ValueError(f"if using subwords, use replace-length=1 or 0") self.mask_span_distribution = None - if args.mask_length == "span-poisson": - _lambda = args.poisson_lambda + if mask_length == "span-poisson": + _lambda = poisson_lambda lambda_to_the_k = 1 e_to_the_minus_lambda = math.exp(-_lambda) diff --git a/fairseq/tasks/denoising.py b/fairseq/tasks/denoising.py index 1d4f84c08b..57b824d581 100644 --- a/fairseq/tasks/denoising.py +++ b/fairseq/tasks/denoising.py @@ -5,6 +5,11 @@ import logging import os +from dataclasses import dataclass, field +from typing import Any, Optional + +import numpy as np +from omegaconf import II, MISSING from fairseq import utils from fairseq.data import ( @@ -22,145 +27,142 @@ ) from fairseq.data.encoders.utils import get_whole_word_mask from fairseq.data.shorten_dataset import maybe_shorten_dataset -from fairseq.tasks import LegacyFairseqTask, register_task -import numpy as np +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.tasks import FairseqTask, register_task +from ..data.indexed_dataset import get_available_dataset_impl logger = logging.getLogger(__name__) +SAMPLE_BREAK_MODE_CHOICES = ChoiceEnum(["none", "complete", "complete_doc", "eos"]) +SHORTEN_METHOD_CHOICES = ChoiceEnum(["none", "truncate", "random_crop"]) +MASK_LENGTH_CHOICES = ChoiceEnum(["subword", "word", "span-poisson"]) + + +@dataclass +class DenoisingConfig(FairseqDataclass): + data: str = field( + default=MISSING, + metadata={"help": "path to data directory"}, + ) + bpe: Optional[str] = field( + default=None, + metadata={"help": "TODO"}, + ) + tokens_per_sample: int = field( + default=512, + metadata={ + "help": "max number of total tokens over all segments " + "per sample for dataset" + }, + ) + sample_break_mode: SAMPLE_BREAK_MODE_CHOICES = field( + default="complete_doc", + metadata={ + "help": 'If omitted or "none", fills each sample with tokens-per-sample ' + 'tokens. If set to "complete", splits samples only at the end ' + "of sentence, but may include multiple sentences per sample. " + '"complete_doc" is similar but respects doc boundaries. ' + 'If set to "eos", includes only one sentence per sample.' + }, + ) + replace_length: int = field( + default=0, + metadata={"help": "TODO, should only allow -1, 0 and 1"}, + ) + mask: float = field( + default=0.0, + metadata={"help": "fraction of words/subwords that will be masked"}, + ) + mask_random: float = field( + default=0.0, + metadata={"help": "instead of using [MASK], use random token this often"}, + ) + insert: float = field( + default=0.0, + metadata={"help": "insert this percentage of additional random tokens"}, + ) + permute: float = field( + default=0.0, + metadata={"help": "take this proportion of subwords and permute them"}, + ) + rotate: float = field( + default=0.5, + metadata={"help": "rotate this proportion of inputs"}, + ) + poisson_lambda: float = field( + default=3.0, + metadata={"help": "randomly shuffle sentences for this proportion of inputs"}, + ) + shuffle_instance: float = field( + default=0.0, + metadata={"help": "shuffle this proportion of sentences in all inputs"}, + ) + mask_length: MASK_LENGTH_CHOICES = field( + default="subword", + metadata={"help": "mask length to choose"}, + ) + permute_sentences: int = field( + default=-1, + metadata={ + "help": "when masking N tokens, replace with 0, 1, or N tokens (use -1 for N)" + }, + ) + seed: int = II("common.seed") + shorten_method: SHORTEN_METHOD_CHOICES = field( + default="none", + metadata={ + "help": "if not none, shorten sequences that exceed --tokens-per-sample" + }, + ) + shorten_data_split_list: str = field( + default="", + metadata={ + "help": "comma-separated list of dataset splits to apply shortening to, " + 'e.g., "train,valid" (default: all dataset splits)' + }, + ) + max_source_positions: int = field( + default=1024, + metadata={"help": "max number of tokens in the source sequence"}, + ) + max_target_positions: int = field( + default=1024, + metadata={"help": "max number of tokens in the target sequence"}, + ) + dataset_impl: Optional[ChoiceEnum(get_available_dataset_impl())] = II( + "dataset.dataset_impl" + ) -@register_task("denoising") -class DenoisingTask(LegacyFairseqTask): + +@register_task("denoising", dataclass=DenoisingConfig) +class DenoisingTask(FairseqTask): """ Denoising task for applying sequence to sequence denoising. (ie. BART) """ - @staticmethod - def add_args(parser): - """Add task-specific arguments to the parser.""" - parser.add_argument("data", help="path to data directory") - parser.add_argument( - "--tokens-per-sample", - default=512, - type=int, - help="max number of total tokens over all segments" - " per sample for dataset", - ) - parser.add_argument( - "--sample-break-mode", - default="complete_doc", - type=str, - help="mode for breaking sentence", - ) - parser.add_argument( - "--mask", - default=0.0, - type=float, - help="fraction of words/subwords that will be masked", - ) - parser.add_argument( - "--mask-random", - default=0.0, - type=float, - help="instead of using [MASK], use random token this often", - ) - parser.add_argument( - "--insert", - default=0.0, - type=float, - help="insert this percentage of additional random tokens", - ) - parser.add_argument( - "--permute", - default=0.0, - type=float, - help="take this proportion of subwords and permute them", - ) - parser.add_argument( - "--rotate", - default=0.5, - type=float, - help="rotate this proportion of inputs", - ) - parser.add_argument( - "--poisson-lambda", - default=3.0, - type=float, - help="randomly shuffle sentences for this proportion of inputs", - ) - parser.add_argument( - "--permute-sentences", - default=0.0, - type=float, - help="shuffle this proportion of sentences in all inputs", - ) - parser.add_argument( - "--mask-length", - default="subword", - type=str, - choices=["subword", "word", "span-poisson"], - help="mask length to choose", - ) - parser.add_argument( - "--replace-length", - default=-1, - type=int, - help="when masking N tokens, replace with 0, 1, or N tokens (use -1 for N)", - ) - parser.add_argument( - "--max-source-positions", - default=1024, - type=int, - metavar="N", - help="max number of tokens in the source sequence", - ) - parser.add_argument( - "--max-target-positions", - default=1024, - type=int, - metavar="N", - help="max number of tokens in the target sequence", - ) + cfg: DenoisingConfig - parser.add_argument( - "--shorten-method", - default="none", - choices=["none", "truncate", "random_crop"], - help="if not none, shorten sequences that exceed --tokens-per-sample", - ) - parser.add_argument( - "--shorten-data-split-list", - default="", - help="comma-separated list of dataset splits to apply shortening to, " - 'e.g., "train,valid" (default: all dataset splits)', - ) - - def __init__(self, args, dictionary): - super().__init__(args) + def __init__(self, cfg, dictionary): + super().__init__(cfg) self.dictionary = dictionary - self.seed = args.seed # add mask token self.mask_idx = self.dictionary.add_symbol("<mask>") @classmethod - def setup_task(cls, args, **kwargs): + def setup_task(cls, cfg: DenoisingConfig, **kwargs): """Setup the task.""" - paths = utils.split_paths(args.data) + paths = utils.split_paths(cfg.data) assert len(paths) > 0 dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) logger.info("dictionary: {} types".format(len(dictionary))) - if not hasattr(args, "shuffle_instance"): - args.shuffle_instance = False - return cls(args, dictionary) + if not hasattr(cfg, "shuffle_instance"): + cfg.shuffle_instance = False + return cls(cfg, dictionary) - def load_dataset(self, split, epoch=1, combine=False, **kwargs): - """Load a given dataset split. - - Args: - split (str): name of the split (e.g., train, valid, test) - """ - paths = utils.split_paths(self.args.data) + def _load_dataset_split(self, split, epoch, combine): + paths = utils.split_paths(self.cfg.data) assert len(paths) > 0 data_path = paths[(epoch - 1) % len(paths)] split_path = os.path.join(data_path, split) @@ -168,7 +170,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): dataset = data_utils.load_indexed_dataset( split_path, self.dictionary, - self.args.dataset_impl, + self.cfg.dataset_impl, combine=combine, ) if dataset is None: @@ -181,20 +183,21 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): dataset = maybe_shorten_dataset( dataset, split, - self.args.shorten_data_split_list, - self.args.shorten_method, - self.args.tokens_per_sample, - self.args.seed, + self.cfg.shorten_data_split_list, + self.cfg.shorten_method, + self.cfg.tokens_per_sample, + self.cfg.seed, ) # create continuous blocks of tokens dataset = TokenBlockDataset( dataset, dataset.sizes, - self.args.tokens_per_sample - 2, # one less for <s> and one for </s> + self.cfg.tokens_per_sample - 2, + # one less for <s> and one for </s> pad=self.dictionary.pad(), eos=self.dictionary.eos(), - break_mode=self.args.sample_break_mode, + break_mode=self.cfg.sample_break_mode, document_sep_len=0, ) logger.info("loaded {} blocks from: {}".format(len(dataset), split_path)) @@ -202,10 +205,19 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): # prepend beginning-of-sentence token (<s>, equiv. to [CLS] in BERT) dataset = PrependTokenDataset(dataset, self.source_dictionary.bos()) dataset = AppendTokenDataset(dataset, self.source_dictionary.eos()) + return dataset + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + """Load a given dataset split. + + Args: + split (str): name of the split (e.g., train, valid, test) + """ + dataset = self._load_dataset_split(split, epoch, combine) mask_whole_words = ( - get_whole_word_mask(self.args, self.source_dictionary) - if self.args.mask_length != "subword" + get_whole_word_mask(self.cfg.bpe, self.source_dictionary) + if self.cfg.mask_length != "subword" else None ) @@ -215,9 +227,17 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): self.dictionary, self.mask_idx, mask_whole_words, - shuffle=self.args.shuffle_instance, - seed=self.seed, - args=self.args, + shuffle=self.cfg.shuffle_instance, + seed=self.cfg.seed, + mask=self.cfg.mask, + mask_random=self.cfg.mask_random, + insert=self.cfg.insert, + rotate=self.cfg.rotate, + permute_sentences=self.cfg.permute_sentences, + bpe=self.cfg.bpe, + replace_length=self.cfg.replace_length, + mask_length=self.cfg.mask_length, + poisson_lambda=self.cfg.poisson_lambda, ) logger.info( "Split: {0}, Loaded {1} samples of denoising_dataset".format( @@ -236,10 +256,10 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): src_dataset = TokenBlockDataset( src_tokens, src_lengths, - block_size=self.args.tokens_per_sample - 2, # for <s> and </s> + block_size=self.cfg.tokens_per_sample - 2, # for <s> and </s> pad=pad, eos=eos, - break_mode=self.args.sample_break_mode, + break_mode=self.cfg.sample_break_mode, document_sep_len=0, ) prev_output_tokens = PrependTokenDataset( @@ -263,7 +283,7 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): def max_positions(self): """Return the max sentence length allowed by the task.""" - return (self.args.max_source_positions, self.args.max_target_positions) + return (self.cfg.max_source_positions, self.cfg.max_target_positions) @property def source_dictionary(self): diff --git a/fairseq/tasks/multilingual_denoising.py b/fairseq/tasks/multilingual_denoising.py index 8226d95030..cb5ee34554 100644 --- a/fairseq/tasks/multilingual_denoising.py +++ b/fairseq/tasks/multilingual_denoising.py @@ -2,11 +2,13 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. - import logging import os +from dataclasses import dataclass, field +from typing import Optional import numpy as np +from omegaconf import II from fairseq.data import ( AppendTokenDataset, @@ -22,43 +24,49 @@ from fairseq.data.encoders.utils import get_whole_word_mask from fairseq.tasks import register_task -from .denoising import DenoisingTask +from .denoising import DenoisingConfig, DenoisingTask logger = logging.getLogger(__name__) -@register_task("multilingual_denoising") +@dataclass +class MultilingualDenoisingConfig(DenoisingConfig): + multilang_sampling_alpha: float = field( + default=1.0, + metadata={"help": "smoothing alpha for sample ratios across multiple datasets"}, + ) + add_lang_token: bool = field( + default=False, + metadata={"help": ""}, + ) + langs: Optional[str] = field( + default=None, + metadata={"help": "language ids we are considering"}, + ) + no_whole_word_mask_langs: str = field( + default="", + metadata={ + "help": "languages without spacing between words don't support whole word masking" + }, + ) + train_subset: str = II("common.train_subset") + valid_subset: str = II("common.valid_subset") + + +@register_task("multilingual_denoising", dataclass=MultilingualDenoisingConfig) class MultilingualDenoisingTask(DenoisingTask): - @staticmethod - def add_args(parser): - DenoisingTask.add_args(parser) - parser.add_argument( - "--multilang-sampling-alpha", - type=float, - default=1.0, - help="smoothing alpha for sample ratios across multiple datasets", - ) - parser.add_argument("--add-lang-token", default=False, action="store_true") - parser.add_argument( - "--langs", type=str, help="language ids we are considering", default=None - ) - parser.add_argument( - "--no-whole-word-mask-langs", - type=str, - default="", - metavar="N", - help="languages without spacing between words dont support whole word masking", - ) + + cfg: MultilingualDenoisingConfig @classmethod - def setup_task(cls, args, **kwargs): + def setup_task(cls, cfg: MultilingualDenoisingConfig, **kwargs): """Setup the task.""" - paths = args.data.split(":") + paths = cfg.data.split(":") assert len(paths) > 0 dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) data_path = paths[0] - if args.langs is None: + if cfg.langs is None: languages = sorted( [ name @@ -67,34 +75,32 @@ def setup_task(cls, args, **kwargs): ] ) else: - languages = args.langs.split(",") + languages = cfg.langs.split(",") - if args.add_lang_token: + if cfg.add_lang_token: for lang in languages: dictionary.add_symbol("[{}]".format(lang)) logger.info("dictionary: {} types".format(len(dictionary))) - if not hasattr(args, "shuffle_instance"): - args.shuffle_instance = False - return cls(args, dictionary) + if not hasattr(cfg, "shuffle_instance"): + cfg.shuffle_instance = False + return cls(cfg, dictionary) - def __init__(self, args, dictionary): - super().__init__(args, dictionary) + def __init__(self, cfg: MultilingualDenoisingConfig, dictionary): + super().__init__(cfg, dictionary) self.dictionary = dictionary - self.seed = args.seed # add mask token self.mask_idx = self.dictionary.add_symbol("<mask>") - self.langs = args.langs - self.args = args + self.cfg = cfg def _get_sample_prob(self, dataset_lens): """ - Get smoothed sampling porbability by languages. This helps low resource + Get smoothed sampling probability by languages. This helps low resource languages by upsampling them. """ prob = dataset_lens / dataset_lens.sum() - smoothed_prob = prob**self.args.multilang_sampling_alpha + smoothed_prob = prob**self.cfg.multilang_sampling_alpha smoothed_prob = smoothed_prob / smoothed_prob.sum() return smoothed_prob @@ -104,12 +110,12 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): Args: split (str): name of the split (e.g., train, valid, test) """ - paths = self.args.data.split(":") + paths = self.cfg.data.split(":") assert len(paths) > 0 data_path = paths[(epoch - 1) % len(paths)] split_path = os.path.join(data_path, split) - if self.langs is None: + if self.cfg.langs is None: languages = sorted( [ name @@ -118,7 +124,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): ] ) else: - languages = self.langs.split(",") + languages = self.cfg.langs.split(",") for name in languages: p = os.path.join(data_path, name) assert os.path.exists(p), "data not found: {}".format(p) @@ -128,8 +134,8 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): "Language to id mapping: ", {lang: id for id, lang in enumerate(languages)} ) - mask_whole_words = get_whole_word_mask(self.args, self.dictionary) - language_without_segmentations = self.args.no_whole_word_mask_langs.split(",") + mask_whole_words = get_whole_word_mask(self.cfg.bpe, self.dictionary) + language_without_segmentations = self.cfg.no_whole_word_mask_langs.split(",") lang_datasets = [] for language in languages: split_path = os.path.join(data_path, language, split) @@ -137,7 +143,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): dataset = data_utils.load_indexed_dataset( split_path, self.source_dictionary, - self.args.dataset_impl, + self.cfg.dataset_impl, combine=combine, ) if dataset is None: @@ -147,7 +153,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): end_token = ( self.source_dictionary.index("[{}]".format(language)) - if self.args.add_lang_token + if self.cfg.add_lang_token else self.source_dictionary.eos() ) @@ -155,10 +161,10 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): dataset = TokenBlockDataset( dataset, dataset.sizes, - self.args.tokens_per_sample - 2, # one less for <s> + self.cfg.tokens_per_sample - 2, # one less for <s> pad=self.source_dictionary.pad(), eos=end_token, - break_mode=self.args.sample_break_mode, + break_mode=self.cfg.sample_break_mode, ) logger.info("loaded {} blocks from: {}".format(len(dataset), split_path)) @@ -177,11 +183,19 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): self.dictionary, self.mask_idx, lang_mask_whole_words, - shuffle=self.args.shuffle_instance, - seed=self.seed, - args=self.args, + shuffle=self.cfg.shuffle_instance, + seed=self.cfg.seed, + mask=self.cfg.mask, + mask_random=self.cfg.mask_random, + insert=self.cfg.insert, + rotate=self.cfg.rotate, + permute_sentences=self.cfg.permute_sentences, + bpe=self.cfg.bpe, + replace_length=self.cfg.replace_length, + mask_length=self.cfg.mask_length, + poisson_lambda=self.cfg.poisson_lambda, eos=None - if not self.args.add_lang_token + if not self.cfg.add_lang_token else self.source_dictionary.index("[{}]".format(language)), ) lang_datasets.append(lang_dataset) @@ -195,7 +209,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): int(dataset_lengths.sum()), ) ) - if split == self.args.train_subset: + if split == self.cfg.train_subset: # For train subset, additionally up or down sample languages. sample_probs = self._get_sample_prob(dataset_lengths) logger.info( @@ -220,7 +234,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): ResamplingDataset( lang_datasets[i], size_ratio=size_ratio[i], - seed=self.args.seed, + seed=self.cfg.seed, epoch=epoch, replace=size_ratio[i] >= 1.0, ) @@ -237,12 +251,12 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): lang_splits.append(split_name) self.datasets[split_name] = lang_dataset - if split in self.args.valid_subset: - self.args.valid_subset = self.args.valid_subset.replace( + if split in self.cfg.valid_subset: + self.cfg.valid_subset = self.cfg.valid_subset.replace( split, ",".join(lang_splits) ) - with data_utils.numpy_seed(self.args.seed + epoch): + with data_utils.numpy_seed(self.cfg.seed + epoch): shuffle = np.random.permutation(len(dataset)) self.datasets[split] = SortDataset( diff --git a/tests/tasks/test_denoising.py b/tests/tasks/test_denoising.py new file mode 100644 index 0000000000..5c22168352 --- /dev/null +++ b/tests/tasks/test_denoising.py @@ -0,0 +1,96 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import unittest +from tempfile import TemporaryDirectory + +from fairseq import options +from fairseq.binarizer import FileBinarizer, VocabularyDatasetBinarizer +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.tasks.denoising import DenoisingTask +from tests.utils import build_vocab, make_data + + +class TestDenoising(unittest.TestCase): + def test_denoising(self): + with TemporaryDirectory() as dirname: + + # prep input file + raw_file = os.path.join(dirname, "raw") + data = make_data(out_file=raw_file) + vocab = build_vocab(data) + + # binarize + binarizer = VocabularyDatasetBinarizer(vocab, append_eos=False) + split = "train" + bin_file = os.path.join(dirname, split) + dataset_impl = "mmap" + FileBinarizer.multiprocess_dataset( + input_file=raw_file, + binarizer=binarizer, + dataset_impl=dataset_impl, + vocab_size=len(vocab), + output_prefix=bin_file, + ) + + # setup task + train_args = options.parse_args_and_arch( + options.get_training_parser(), + [ + "--task", + "denoising", + "--arch", + "bart_base", + "--seed", + "42", + "--mask-length", + "word", + "--permute-sentences", + "1", + "--rotate", + "0", + "--replace-length", + "-1", + "--mask", + "0.2", + dirname, + ], + ) + cfg = convert_namespace_to_omegaconf(train_args) + task = DenoisingTask(cfg.task, binarizer.dict) + + # load datasets + original_dataset = task._load_dataset_split(bin_file, 1, False) + task.load_dataset(split) + masked_dataset = task.dataset(split) + + iterator = task.get_batch_iterator( + dataset=masked_dataset, + max_tokens=65_536, + max_positions=4_096, + ).next_epoch_itr(shuffle=False) + mask_index = task.source_dictionary.index("<mask>") + for batch in iterator: + for sample in range(len(batch)): + net_input = batch["net_input"] + masked_src_tokens = net_input["src_tokens"][sample] + masked_src_length = net_input["src_lengths"][sample] + masked_tgt_tokens = batch["target"][sample] + + sample_id = batch["id"][sample] + original_tokens = original_dataset[sample_id] + original_tokens = original_tokens.masked_select( + masked_src_tokens[:masked_src_length] == mask_index + ) + masked_tokens = masked_tgt_tokens.masked_select( + masked_src_tokens == mask_index + ) + + assert masked_tokens.equal(original_tokens) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/tasks/test_multilingual_denoising.py b/tests/tasks/test_multilingual_denoising.py new file mode 100644 index 0000000000..a0227f69b5 --- /dev/null +++ b/tests/tasks/test_multilingual_denoising.py @@ -0,0 +1,98 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import unittest +from tempfile import TemporaryDirectory + +from fairseq import options +from fairseq.binarizer import FileBinarizer, VocabularyDatasetBinarizer +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.tasks.multilingual_denoising import MultilingualDenoisingTask +from tests.utils import build_vocab, make_data + + +class TestMultilingualDenoising(unittest.TestCase): + def test_multilingual_denoising(self): + with TemporaryDirectory() as dirname: + + # prep input file + lang_dir = os.path.join(dirname, "en") + os.mkdir(lang_dir) + raw_file = os.path.join(lang_dir, "raw") + data = make_data(out_file=raw_file) + vocab = build_vocab(data) + + # binarize + binarizer = VocabularyDatasetBinarizer(vocab, append_eos=False) + split = "train" + bin_file = os.path.join(lang_dir, split) + dataset_impl = "mmap" + FileBinarizer.multiprocess_dataset( + input_file=raw_file, + binarizer=binarizer, + dataset_impl=dataset_impl, + vocab_size=len(vocab), + output_prefix=bin_file, + ) + + # setup task + train_args = options.parse_args_and_arch( + options.get_training_parser(), + [ + "--task", + "multilingual_denoising", + "--arch", + "bart_base", + "--seed", + "42", + "--mask-length", + "word", + "--permute-sentences", + "1", + "--rotate", + "0", + "--replace-length", + "-1", + "--mask", + "0.2", + dirname, + ], + ) + cfg = convert_namespace_to_omegaconf(train_args) + task = MultilingualDenoisingTask(cfg.task, binarizer.dict) + + # load datasets + original_dataset = task._load_dataset_split(bin_file, 1, False) + task.load_dataset(split) + masked_dataset = task.dataset(split) + + iterator = task.get_batch_iterator( + dataset=masked_dataset, + max_tokens=65_536, + max_positions=4_096, + ).next_epoch_itr(shuffle=False) + mask_index = task.source_dictionary.index("<mask>") + for batch in iterator: + for sample in range(len(batch)): + net_input = batch["net_input"] + masked_src_tokens = net_input["src_tokens"][sample] + masked_src_length = net_input["src_lengths"][sample] + masked_tgt_tokens = batch["target"][sample] + + sample_id = batch["id"][sample] + original_tokens = original_dataset[sample_id] + original_tokens = original_tokens.masked_select( + masked_src_tokens[:masked_src_length] == mask_index + ) + masked_tokens = masked_tgt_tokens.masked_select( + masked_src_tokens == mask_index + ) + + assert masked_tokens.equal(original_tokens) + + +if __name__ == "__main__": + unittest.main() From 5d8d0674c141e2b503fd2108adf619115cd8c5e0 Mon Sep 17 00:00:00 2001 From: Jacob Kahn <jacobkahn1@gmail.com> Date: Tue, 28 Jun 2022 17:52:57 -0700 Subject: [PATCH 654/774] [docs] Update Flashlight Bindings Docs (#4522) * Update README.md * Update README.md --- examples/speech_recognition/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/speech_recognition/README.md b/examples/speech_recognition/README.md index 17030bf0fd..5f9b27880e 100644 --- a/examples/speech_recognition/README.md +++ b/examples/speech_recognition/README.md @@ -41,7 +41,11 @@ sclite -r ${RES_DIR}/ref.word-checkpoint_last.pt-${SET}.txt -h ${RES_DIR}/hypo.w * flashlight-style Conv/GLU model * flashlight's beam search decoder -To use these, follow the instructions on [this page](https://github.com/facebookresearch/flashlight/tree/master/bindings/python) to install python bindings. +To use these, follow the instructions on [this page](https://github.com/flashlight/flashlight/tree/e16682fa32df30cbf675c8fe010f929c61e3b833/bindings/python) to install python bindings. **Flashlight v0.3.2** must be used to install the bindings. Running: +``` +git clone --branch v0.3.2 https://github.com/flashlight/flashlight +``` +will properly clone and check out this version. ## Training librispeech data (flashlight style, Conv/GLU + ASG loss) Training command: From ba415c99ca89b212ce9c8b79c565d828b89a8761 Mon Sep 17 00:00:00 2001 From: Alexander Jipa <alexander.jipa@gmail.com> Date: Wed, 29 Jun 2022 10:04:00 -0400 Subject: [PATCH 655/774] add span_masked_lm task (#4366) Co-authored-by: Alexander Jipa <azzhipa@amazon.com> --- fairseq/data/span_mask_tokens_dataset.py | 293 +++++++++++++++++++++++ fairseq/tasks/span_masked_lm.py | 243 +++++++++++++++++++ tests/tasks/test_span_masked_lm.py | 106 ++++++++ 3 files changed, 642 insertions(+) create mode 100644 fairseq/data/span_mask_tokens_dataset.py create mode 100644 fairseq/tasks/span_masked_lm.py create mode 100644 tests/tasks/test_span_masked_lm.py diff --git a/fairseq/data/span_mask_tokens_dataset.py b/fairseq/data/span_mask_tokens_dataset.py new file mode 100644 index 0000000000..72189bd378 --- /dev/null +++ b/fairseq/data/span_mask_tokens_dataset.py @@ -0,0 +1,293 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +import torch + +from . import Dictionary, FairseqDataset, data_utils + + +def collate( + samples, + pad_idx, + eos_idx, + vocab, + left_pad_source=False, + left_pad_target=False, + input_feeding=True, + pad_to_length=None, +): + assert input_feeding + if len(samples) == 0: + return {} + + def merge(key, left_pad, move_eos_to_beginning=False, pad_to_length=None): + return data_utils.collate_tokens( + [s[key] for s in samples], + pad_idx, + eos_idx=None, # use eos_idx of each sample instead of vocab.eos() + left_pad=left_pad, + move_eos_to_beginning=move_eos_to_beginning, + pad_to_length=pad_to_length, + ) + + id = torch.LongTensor([s["id"] for s in samples]) + src_tokens = merge( + "source", + left_pad=left_pad_source, + pad_to_length=pad_to_length["source"] if pad_to_length is not None else None, + ) + # sort by descending source length + src_lengths = torch.LongTensor([s["source"].numel() for s in samples]) + src_lengths, sort_order = src_lengths.sort(descending=True) + id = id.index_select(0, sort_order) + src_tokens = src_tokens.index_select(0, sort_order) + + prev_output_tokens = None + target = None + if samples[0].get("target", None) is not None: + target = merge( + "target", + left_pad=left_pad_target, + pad_to_length=pad_to_length["target"] + if pad_to_length is not None + else None, + ) + target = target.index_select(0, sort_order) + ntokens = sum(len(s["target"]) for s in samples) + + if input_feeding: + # we create a shifted version of targets for feeding the + # previous output token(s) into the next decoder step + prev_output_tokens = merge( + "target", + left_pad=left_pad_target, + move_eos_to_beginning=True, + pad_to_length=pad_to_length["target"] + if pad_to_length is not None + else None, + ) + prev_output_tokens = prev_output_tokens.index_select(0, sort_order) + else: + ntokens = sum(len(s["source"]) for s in samples) + + batch = { + "id": id, + "ntokens": ntokens, + "net_input": { + "src_tokens": src_tokens, + "src_lengths": src_lengths, + }, + "target": target, + "target_lengths": torch.LongTensor([len(t) for t in target]), + "nsentences": samples[0]["source"].size(0), + "sort_order": sort_order, + } + if prev_output_tokens is not None: + batch["net_input"]["prev_output_tokens"] = prev_output_tokens + + return batch + + +class SpanMaskedTokensDataset(FairseqDataset): + """ + A wrapper around TokenBlockDataset for T5 dataset. + + Args: + dataset (~torch.utils.data.Dataset): dataset to wrap + vocab (~fairseq.data.Dictionary): vocabulary + noise_density (float): fraction of the tokens to select as noise. + mean_noise_span_length (float): mean noise span length. + shuffle (bool, optional): shuffle the elements before batching. + Default: ``True`` + seed: Seed for random number generator for reproducibility. + """ + + def __init__( + self, + dataset: torch.utils.data.Dataset, + vocab: Dictionary, + noise_density: float, + mean_noise_span_length: float, + shuffle: bool, + seed: int = 1, + ): + self.dataset = dataset + self.vocab = vocab + self.seed = seed + self.noise_density = noise_density + self.mean_noise_span_length = mean_noise_span_length + self.shuffle = shuffle + self.epoch = 0 + + @property + def can_reuse_epoch_itr_across_epochs(self): + return True # only the noise changes, not item sizes + + def set_epoch(self, epoch, **unused): + self.epoch = epoch + + def __getitem__(self, index): + with data_utils.numpy_seed(self.seed, self.epoch, index): + item = self.dataset[index] + assert item[-1] == self.vocab.eos() + + noise_mask = self.random_spans_noise_mask(len(item)) + + source_sentinel_ids = self.create_sentinel_ids(noise_mask.astype(np.int8)) + source = self.filter_input_ids(item, source_sentinel_ids) + + target_sentinel_ids = self.create_sentinel_ids( + (~noise_mask).astype(np.int8) + ) + target = self.filter_input_ids(item, target_sentinel_ids) + + return { + "id": index, + "source": torch.from_numpy(source), + "target": torch.from_numpy(target), + } + + def random_spans_noise_mask(self, length): + + """ + This function is copy of `random_spans_helper <https://github.com/google-research/text-to-text-transfer-transformer/blob/84f8bcc14b5f2c03de51bd3587609ba8f6bbd1cd/t5/data/preprocessors.py#L2682>`__ . + Noise mask consisting of random spans of noise tokens. + The number of noise tokens and the number of noise spans and non-noise spans + are determined deterministically as follows: + num_noise_tokens = round(length * noise_density) + num_nonnoise_spans = num_noise_spans = round(num_noise_tokens / mean_noise_span_length) + Spans alternate between non-noise and noise, beginning with non-noise. + Subject to the above restrictions, all masks are equally likely. + Args: + length: an int32 scalar (length of the incoming token sequence) + Returns: + a boolean tensor with shape [length] + """ + + orig_length = length + + num_noise_tokens = int(np.round(length * self.noise_density)) + # avoid degeneracy by ensuring positive numbers of noise and nonnoise tokens. + num_noise_tokens = min(max(num_noise_tokens, 1), length - 1) + num_noise_spans = int(np.round(num_noise_tokens / self.mean_noise_span_length)) + + # avoid degeneracy by ensuring positive number of noise spans + num_noise_spans = max(num_noise_spans, 1) + num_nonnoise_tokens = length - num_noise_tokens + + # pick the lengths of the noise spans and the non-noise spans + def _random_segmentation(num_items, num_segments): + """ + Partition a sequence of items randomly into non-empty segments. + Args: + num_items: an integer scalar > 0 + num_segments: an integer scalar in [1, num_items] + Returns: + a Tensor with shape [num_segments] containing positive integers that add up to num_items + """ + mask_indices = np.arange(num_items - 1) < (num_segments - 1) + np.random.shuffle(mask_indices) + first_in_segment = np.pad(mask_indices, [[1, 0]]) + segment_id = np.cumsum(first_in_segment) + # count length of subsegments assuming that list is sorted + _, segment_length = np.unique(segment_id, return_counts=True) + return segment_length + + noise_span_lengths = _random_segmentation(num_noise_tokens, num_noise_spans) + nonnoise_span_lengths = _random_segmentation( + num_nonnoise_tokens, num_noise_spans + ) + + interleaved_span_lengths = np.reshape( + np.stack([nonnoise_span_lengths, noise_span_lengths], axis=1), + [num_noise_spans * 2], + ) + span_starts = np.cumsum(interleaved_span_lengths)[:-1] + span_start_indicator = np.zeros((length,), dtype=np.int8) + span_start_indicator[span_starts] = True + span_num = np.cumsum(span_start_indicator) + is_noise = np.equal(span_num % 2, 1) + + return is_noise[:orig_length] + + def create_sentinel_ids(self, mask_indices): + """ + Sentinel ids creation given the indices that should be masked. + The start indices of each mask are replaced by the sentinel ids in increasing + order. Consecutive mask indices to be deleted are replaced with `-1`. + """ + start_indices = mask_indices - np.roll(mask_indices, 1, axis=-1) * mask_indices + + sentinel_ids = np.where( + start_indices != 0, np.cumsum(start_indices, axis=-1), start_indices + ) + # making sure all sentinel tokens are unique over the example + sentinel_ids = np.where(sentinel_ids != 0, len(self.vocab) - sentinel_ids, 0) + sentinel_ids -= mask_indices - start_indices + return sentinel_ids + + @staticmethod + def filter_input_ids(input_ids, sentinel_ids): + """ + Puts sentinel mask on `input_ids` and fuse consecutive mask tokens into a single mask token by deleting. + This will reduce the sequence length from `expanded_inputs_length` to `input_length`. + """ + input_ids_full = np.where(sentinel_ids != 0, sentinel_ids, input_ids) + + # input_ids tokens and sentinel tokens are >= 0, tokens < 0 are + # masked tokens coming after sentinel tokens and should be removed + return input_ids_full[input_ids_full >= 0] + + def __len__(self): + return len(self.dataset) + + def collater(self, samples, pad_to_length=None): + """ + Merge a list of samples to form a mini-batch. + Args: + samples (List[dict]): samples to collate + Returns: + dict: a mini-batch of data + """ + return collate( + samples, + self.vocab.pad(), + self.vocab.eos(), + self.vocab, + pad_to_length=pad_to_length, + ) + + def num_tokens(self, index): + """Return the number of tokens in a sample. This value is used to + enforce ``--max-tokens`` during batching.""" + return self.dataset.sizes[index] + + def size(self, index): + """Return an example's size as a float or tuple. This value is used when + filtering a dataset with ``--max-positions``.""" + return self.dataset.sizes[index] + + def ordered_indices(self): + """Return an ordered list of indices. Batches will be constructed based + on this order.""" + if self.shuffle: + indices = np.random.permutation(len(self)) + else: + indices = np.arange(len(self)) + return indices[np.argsort(self.dataset.sizes[indices], kind="mergesort")] + + def prefetch(self, indices): + self.src.prefetch(indices) + self.tgt.prefetch(indices) + + @property + def supports_prefetch(self): + return ( + hasattr(self.src, "supports_prefetch") + and self.src.supports_prefetch + and hasattr(self.tgt, "supports_prefetch") + and self.tgt.supports_prefetch + ) diff --git a/fairseq/tasks/span_masked_lm.py b/fairseq/tasks/span_masked_lm.py new file mode 100644 index 0000000000..d746aa154c --- /dev/null +++ b/fairseq/tasks/span_masked_lm.py @@ -0,0 +1,243 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from dataclasses import dataclass, field +from typing import Optional + +import numpy as np +from omegaconf import II, MISSING + +from fairseq import utils +from fairseq.data import ( + AppendTokenDataset, + Dictionary, + IdDataset, + NestedDictionaryDataset, + NumelDataset, + PadDataset, + PrependTokenDataset, + StripTokenDataset, + TokenBlockDataset, + data_utils, +) +from fairseq.data.shorten_dataset import maybe_shorten_dataset +from fairseq.data.span_mask_tokens_dataset import SpanMaskedTokensDataset +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.tasks import FairseqTask, register_task + +from ..data.indexed_dataset import get_available_dataset_impl + +logger = logging.getLogger(__name__) + +SAMPLE_BREAK_MODE_CHOICES = ChoiceEnum(["none", "complete", "complete_doc", "eos"]) +SHORTEN_METHOD_CHOICES = ChoiceEnum(["none", "truncate", "random_crop"]) + + +@dataclass +class SpanMaskedLMConfig(FairseqDataclass): + shuffle: bool = field( + default=False, + ) + noise_density: float = field( + default=0.15, + metadata={"help": "What fraction of the tokens to select as noise"}, + ) + mean_noise_span_length: float = field( + default=3, + metadata={"help": "Mean noise span length, must be >= 1"}, + ) + data: str = field( + default=MISSING, + metadata={ + "help": "colon separated path to data directories list, " + "will be iterated upon during epochs in round-robin manner" + }, + ) + sample_break_mode: SAMPLE_BREAK_MODE_CHOICES = field( + default="none", + metadata={ + "help": 'If omitted or "none", fills each sample with tokens-per-sample ' + 'tokens. If set to "complete", splits samples only at the end ' + "of sentence, but may include multiple sentences per sample. " + '"complete_doc" is similar but respects doc boundaries. ' + 'If set to "eos", includes only one sentence per sample.' + }, + ) + tokens_per_sample: int = field( + default=1024, + metadata={"help": "max number of tokens per sample for LM dataset"}, + ) + shorten_method: SHORTEN_METHOD_CHOICES = field( + default="none", + metadata={ + "help": "if not none, shorten sequences that exceed --tokens-per-sample" + }, + ) + shorten_data_split_list: str = field( + default="", + metadata={ + "help": "comma-separated list of dataset splits to apply shortening to, " + 'e.g., "train,valid" (default: all dataset splits)' + }, + ) + seed: int = II("common.seed") + dataset_impl: Optional[ChoiceEnum(get_available_dataset_impl())] = II( + "dataset.dataset_impl" + ) + max_source_positions: int = field( + default=1024, metadata={"help": "max number of tokens in the source sequence"} + ) + max_target_positions: int = field( + default=1024, metadata={"help": "max number of tokens in the target sequence"} + ) + include_target_tokens: bool = field( + default=False, + metadata={ + "help": "include target tokens in model input. this is used for data2vec" + }, + ) + + +@register_task("span_masked_lm", dataclass=SpanMaskedLMConfig) +class SpanMaskedLMTask(FairseqTask): + """ + Span masked language modeling task. (ie. T5) + """ + + cfg: SpanMaskedLMConfig + + def __init__(self, cfg, dictionary): + super().__init__(cfg) + self.dictionary = dictionary + + @classmethod + def setup_task(cls, cfg: SpanMaskedLMConfig, **kwargs): + """Setup the task.""" + paths = utils.split_paths(cfg.data) + assert len(paths) > 0 + dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) + logger.info("dictionary: {} types".format(len(dictionary))) + if not hasattr(cfg, "shuffle"): + cfg.shuffle = False + return cls(cfg, dictionary) + + def _load_dataset_split(self, split, epoch, combine): + paths = utils.split_paths(self.cfg.data) + assert len(paths) > 0 + data_path = paths[(epoch - 1) % len(paths)] + split_path = os.path.join(data_path, split) + + dataset = data_utils.load_indexed_dataset( + split_path, + self.dictionary, + self.cfg.dataset_impl, + combine=combine, + ) + if dataset is None: + raise FileNotFoundError( + "Dataset not found: {} ({})".format(split, split_path) + ) + + dataset = StripTokenDataset(dataset, self.dictionary.eos()) + + dataset = maybe_shorten_dataset( + dataset, + split, + self.cfg.shorten_data_split_list, + self.cfg.shorten_method, + self.cfg.tokens_per_sample, + self.cfg.seed, + ) + + # create continuous blocks of tokens + dataset = TokenBlockDataset( + dataset, + dataset.sizes, + self.cfg.tokens_per_sample - 2, # one less for <s> and one for </s> + pad=self.dictionary.pad(), + eos=self.dictionary.eos(), + break_mode=self.cfg.sample_break_mode, + document_sep_len=0, + ) + logger.info("loaded {} blocks from: {}".format(len(dataset), split_path)) + + # prepend beginning-of-sentence token (<s>, equiv. to [CLS] in BERT) + dataset = PrependTokenDataset(dataset, self.source_dictionary.bos()) + dataset = AppendTokenDataset(dataset, self.source_dictionary.eos()) + return dataset + + def load_dataset(self, split, epoch=1, combine=False, **kwargs): + """Load a given dataset split. + + Args: + split (str): name of the split (e.g., train, valid, test) + """ + dataset = self._load_dataset_split(split, epoch, combine) + + self.datasets[split] = SpanMaskedTokensDataset( + dataset, + self.dictionary, + noise_density=self.cfg.noise_density, + mean_noise_span_length=self.cfg.mean_noise_span_length, + shuffle=self.cfg.shuffle, + seed=self.cfg.seed, + ) + logger.info( + "Split: {0}, Loaded {1} samples of span_masked_tokens_dataset".format( + split, + len(self.datasets[split]), + ) + ) + + def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): + """ + Generate batches for inference. We assume that the input begins with a + bos symbol (`<s>`) and ends with an eos symbol (`</s>`). + """ + pad = self.source_dictionary.pad() + eos = self.source_dictionary.eos() + src_dataset = TokenBlockDataset( + src_tokens, + src_lengths, + block_size=self.cfg.tokens_per_sample - 2, # for <s> and </s> + pad=pad, + eos=eos, + break_mode=self.cfg.sample_break_mode, + document_sep_len=0, + ) + prev_output_tokens = PrependTokenDataset( + StripTokenDataset(src_dataset, eos), eos + ) + src_dataset = PadDataset(src_dataset, pad_idx=pad, left_pad=False) + return NestedDictionaryDataset( + { + "id": IdDataset(), + "net_input": { + "src_tokens": src_dataset, + "src_lengths": NumelDataset(src_dataset, reduce=False), + "prev_output_tokens": PadDataset( + prev_output_tokens, pad_idx=pad, left_pad=False + ), + }, + "target": src_dataset, + }, + sizes=[np.array(src_lengths)], + ) + + def max_positions(self): + """Return the max sentence length allowed by the task.""" + return (self.cfg.max_source_positions, self.cfg.max_target_positions) + + @property + def source_dictionary(self): + """Return the source :class:`~fairseq.data.Dictionary`.""" + return self.dictionary + + @property + def target_dictionary(self): + """Return the target :class:`~fairseq.data.Dictionary`.""" + return self.dictionary diff --git a/tests/tasks/test_span_masked_lm.py b/tests/tasks/test_span_masked_lm.py new file mode 100644 index 0000000000..d289cf843e --- /dev/null +++ b/tests/tasks/test_span_masked_lm.py @@ -0,0 +1,106 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import unittest +from tempfile import TemporaryDirectory + +from fairseq import options +from fairseq.binarizer import FileBinarizer, VocabularyDatasetBinarizer +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.tasks.span_masked_lm import SpanMaskedLMTask +from tests.utils import build_vocab, make_data + + +class TestSpanMaskedLM(unittest.TestCase): + def test_masks_token_spans(self): + with TemporaryDirectory() as dirname: + + # prep input file + raw_file = os.path.join(dirname, "raw") + data = make_data(out_file=raw_file) + vocab = build_vocab(data) + + # binarize + binarizer = VocabularyDatasetBinarizer(vocab, append_eos=False) + split = "train" + bin_file = os.path.join(dirname, split) + dataset_impl = "mmap" + + FileBinarizer.multiprocess_dataset( + input_file=raw_file, + binarizer=binarizer, + dataset_impl=dataset_impl, + vocab_size=len(vocab), + output_prefix=bin_file, + ) + + # adding sentinel tokens + for i in range(100): + vocab.add_symbol(f"<extra_id_{i}>") + + # setup task + train_args = options.parse_args_and_arch( + options.get_training_parser(), + [ + "--task", + "span_masked_lm", + "--arch", + "bart_base", + "--seed", + "42", + dirname, + ], + ) + cfg = convert_namespace_to_omegaconf(train_args) + task = SpanMaskedLMTask(cfg.task, binarizer.dict) + + # load datasets + original_dataset = task._load_dataset_split(bin_file, 1, False) + task.load_dataset(split) + masked_dataset = task.dataset(split) + + iterator = task.get_batch_iterator( + dataset=masked_dataset, + max_tokens=65_536, + max_positions=4_096, + ).next_epoch_itr(shuffle=False) + num_tokens = len(vocab) + for batch in iterator: + for sample in range(len(batch)): + sample_id = batch["id"][sample] + original_tokens = original_dataset[sample_id] + masked_src_tokens = batch["net_input"]["src_tokens"][sample] + masked_src_length = batch["net_input"]["src_lengths"][sample] + masked_tgt_tokens = batch["target"][sample] + + original_offset = 0 + masked_tgt_offset = 0 + extra_id_token = len(vocab) - 1 + for masked_src_token in masked_src_tokens[:masked_src_length]: + if masked_src_token == extra_id_token: + assert ( + masked_src_token == masked_tgt_tokens[masked_tgt_offset] + ) + extra_id_token -= 1 + masked_tgt_offset += 1 + while ( + original_offset < len(original_tokens) + and masked_tgt_tokens[masked_tgt_offset] + != extra_id_token + ): + assert ( + original_tokens[original_offset] + == masked_tgt_tokens[masked_tgt_offset] + ) + original_offset += 1 + masked_tgt_offset += 1 + else: + assert original_tokens[original_offset] == masked_src_token + original_offset += 1 + + +if __name__ == "__main__": + unittest.main() From 5307a0e078d7460003a86f4e2246d459d4706a1d Mon Sep 17 00:00:00 2001 From: Alexei Baevski <alexei.b@gmail.com> Date: Thu, 30 Jun 2022 11:48:49 -0700 Subject: [PATCH 656/774] turn persistent workers off by default (#4524) --- fairseq/data/iterators.py | 25 +++++++++++++++++-------- fairseq/tasks/fairseq_task.py | 2 ++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 24e7475b3d..45a8c65fa9 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -156,6 +156,7 @@ def __init__( num_workers=0, buffer_size=0, timeout=0, + persistent_workers=False, ): assert isinstance(dataset, torch.utils.data.IterableDataset) self.dataset = dataset @@ -167,6 +168,7 @@ def __init__( # in a shared computing environment. self.buffer_size = min(buffer_size, 20) self.timeout = timeout + self.persistent_workers = persistent_workers self._current_epoch_iterator = None @@ -218,7 +220,7 @@ def _get_iterator_for_epoch(self, epoch, shuffle, offset=0): timeout=self.timeout, worker_init_fn=worker_init_fn, pin_memory=True, - persistent_workers=self.num_workers > 0, + persistent_workers=self.persistent_workers, ) # Wrap with a BufferedIterator if needed @@ -319,6 +321,7 @@ def __init__( skip_remainder_batch=False, grouped_shuffling=False, reuse_dataloader=False, + persistent_workers=False, ): assert isinstance(dataset, torch.utils.data.Dataset) self.dataset = dataset @@ -347,6 +350,7 @@ def __init__( self.dataloader = None self.reuse_dataloader = reuse_dataloader + self.persistent_workers = persistent_workers @property def frozen_batches(self): @@ -478,10 +482,10 @@ def _get_iterator_for_epoch( self, epoch, shuffle, fix_batches_to_gpus=False, offset=0 ): if self.reuse_dataloader and self.dataloader is not None: - self.batch_sampler.make_batches_for_epoch(epoch, offset) + self.epoch_batch_sampler.make_batches_for_epoch(epoch, offset) itr = self.dataloader else: - self.batch_sampler = FrozenBatchSampler( + self.epoch_batch_sampler = FrozenBatchSampler( self.ordered_batches, epoch, fix_batches_to_gpus, @@ -489,7 +493,7 @@ def _get_iterator_for_epoch( initial_offset=offset, ) - if offset > 0 and len(self.batch_sampler) == 0: + if offset > 0 and len(self.epoch_batch_sampler) == 0: return None if self.num_workers > 0: @@ -499,11 +503,11 @@ def _get_iterator_for_epoch( itr = torch.utils.data.DataLoader( self.dataset, collate_fn=self.collate_fn, - batch_sampler=self.batch_sampler, + batch_sampler=self.epoch_batch_sampler, num_workers=self.num_workers, timeout=self.timeout, pin_memory=True, - persistent_workers=self.num_workers > 0, + persistent_workers=self.persistent_workers, ) if self.reuse_dataloader: @@ -519,7 +523,8 @@ def _get_iterator_for_epoch( if self.skip_remainder_batch: # TODO: Below is a lazy implementation which discard the final batch regardless # of whether it is a full batch or not. - total_num_itrs = len(self.batch_sampler) - 1 + + total_num_itrs = len(self.epoch_batch_sampler) - 1 itr.take(total_num_itrs) logger.info(f"skip final residual batch, total_num_itrs = {total_num_itrs}") @@ -772,6 +777,8 @@ def __init__( mult_rate=1, buffer_size=0, skip_remainder_batch=False, + reuse_dataloader=False, + persistent_workers=False, ): super().__init__( dataset, @@ -784,6 +791,8 @@ def __init__( epoch, buffer_size, skip_remainder_batch=skip_remainder_batch, + reuse_dataloader=reuse_dataloader, + persistent_workers=persistent_workers, ) # level 0: sub-samplers 1: batch_idx 2: batches self._frozen_batches = tuple([tuple(sub_batch) for sub_batch in batch_samplers]) @@ -866,7 +875,7 @@ def return_full_batches(batch_sets, seed, shuffle): collate_fn=self.collate_fn, batch_sampler=batches[offset:], num_workers=self.num_workers, - persistent_workers=self.num_workers > 0, + persistent_workers=self.persistent_workers, ) if self.buffer_size > 0: itr = BufferedIterator(self.buffer_size, itr) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 0d1dcf6906..3cba8f224a 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -300,6 +300,7 @@ def get_batch_iterator( ) reuse_dataloader = getattr(self.cfg, "reuse_dataloader", True) + persistent_workers = getattr(self.cfg, "persistent_workers", False) # return a reusable, sharded iterator epoch_iter = iterators.EpochBatchIterator( @@ -315,6 +316,7 @@ def get_batch_iterator( skip_remainder_batch=skip_remainder_batch, grouped_shuffling=grouped_shuffling, reuse_dataloader=reuse_dataloader, + persistent_workers=persistent_workers, ) if can_reuse_epoch_itr: From 71a21dfb6506341ecf998bf43f56ff937e219be2 Mon Sep 17 00:00:00 2001 From: Sebastian Vincent <19303946+st-vincent1@users.noreply.github.com> Date: Thu, 7 Jul 2022 12:38:48 +0100 Subject: [PATCH 657/774] closes #4549 (#4550) --- docs/tutorial_classifying_names.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial_classifying_names.rst b/docs/tutorial_classifying_names.rst index b02fec0489..de099f08f5 100644 --- a/docs/tutorial_classifying_names.rst +++ b/docs/tutorial_classifying_names.rst @@ -208,7 +208,7 @@ following contents:: import torch from fairseq.data import Dictionary, LanguagePairDataset - from fairseq.tasks import FairseqTask, register_task + from fairseq.tasks import LegacyFairseqTask, register_task @register_task('simple_classification') From 570c942dcc1b1467fa421aa445620305ad9b19ae Mon Sep 17 00:00:00 2001 From: Marco Gaido <mgaido@fb.com> Date: Thu, 7 Jul 2022 16:25:43 -0700 Subject: [PATCH 658/774] fix multilingual training with tags only on target side (#4543) --- fairseq/data/transform_eos_concat_langpair_dataset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/data/transform_eos_concat_langpair_dataset.py b/fairseq/data/transform_eos_concat_langpair_dataset.py index 638bd1a3d7..effa127d50 100644 --- a/fairseq/data/transform_eos_concat_langpair_dataset.py +++ b/fairseq/data/transform_eos_concat_langpair_dataset.py @@ -28,11 +28,11 @@ def __init__( new_tgt_bos=None, ): super().__init__(datasets) - if new_src_eos is not None: + if new_src_eos is not None and new_src_eos != []: assert len(new_src_eos) == len(datasets) else: new_src_eos = [] - if new_tgt_bos is not None: + if new_tgt_bos is not None and new_tgt_bos != []: assert len(new_tgt_bos) == len(datasets) else: new_tgt_bos = [] From cba35cdbca8385fe00045796ea731c0296f5434b Mon Sep 17 00:00:00 2001 From: Marco Gaido <mgaido@fb.com> Date: Thu, 7 Jul 2022 16:31:11 -0700 Subject: [PATCH 659/774] fix multi modality dataset error with resampling datasets after first epoch (#4544) --- .../tasks/speech_text_denoise_pretrain.py | 2 +- fairseq/data/audio/multi_modality_dataset.py | 26 +++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py b/examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py index f592633c08..3ad8e1c906 100644 --- a/examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py +++ b/examples/speech_text_joint_to_text/tasks/speech_text_denoise_pretrain.py @@ -305,7 +305,7 @@ def resolve_data_type(cls, split, use_sup_speech_ctc): "sup_speech_s2s", "unsup_speech", "sup_speech_ctc", - ) + ), f"failed resolving {split} (it resulted into: {dtype} ; is_train={is_train})" return is_train, dtype def create_modalitydatasetitem(self, dtype, dataset): diff --git a/fairseq/data/audio/multi_modality_dataset.py b/fairseq/data/audio/multi_modality_dataset.py index 39551a613b..ddc9eb63b5 100644 --- a/fairseq/data/audio/multi_modality_dataset.py +++ b/fairseq/data/audio/multi_modality_dataset.py @@ -10,6 +10,7 @@ from typing import List, Optional, NamedTuple import numpy as np +from fairseq.data.resampling_dataset import ResamplingDataset import torch from fairseq.data import ( ConcatDataset, @@ -30,6 +31,16 @@ class ModalityDatasetItem(NamedTuple): max_sentences: Optional[int] = None +def resampling_dataset_present(ds): + if isinstance(ds, ResamplingDataset): + return True + if isinstance(ds, ConcatDataset): + return any(resampling_dataset_present(d) for d in ds.datasets) + if hasattr(ds, "dataset"): + return resampling_dataset_present(ds.dataset) + return False + + # MultiModalityDataset: it concate multiple datasets with different modalities. # Compared with ConcatDataset it can 1) sample data given the ratios for different datasets # 2) it adds mode to indicate what type of the data samples come from. @@ -88,7 +99,7 @@ def size(self, index: int): def sizes(self): if len(self.datasets) == 1: return self.datasets[0].sizes - super().sizes + return super().sizes def ordered_indices(self): """ @@ -106,12 +117,14 @@ def ordered_indices(self): return indices_group def get_raw_batch_samplers(self, required_batch_size_multiple, seed): - if len(self.raw_sub_batch_samplers) > 0: - logger.info(" raw_sub_batch_samplers exists. No action is taken") - return with data_utils.numpy_seed(seed): indices = self.ordered_indices() for i, ds in enumerate(self.datasets): + # If we have ResamplingDataset, the same id can correpond to a different + # sample in the next epoch, so we need to rebuild this at every epoch + if i < len(self.raw_sub_batch_samplers) and not resampling_dataset_present(ds): + logger.info(f"dataset {i} is valid and it is not re-sampled") + continue indices[i] = ds.filter_indices_by_size( indices[i], self.max_positions[i], @@ -122,7 +135,10 @@ def get_raw_batch_samplers(self, required_batch_size_multiple, seed): max_sentences=self.max_sentences[i], required_batch_size_multiple=required_batch_size_multiple, ) - self.raw_sub_batch_samplers.append(sub_batch_sampler) + if i < len(self.raw_sub_batch_samplers): + self.raw_sub_batch_samplers[i] = sub_batch_sampler + else: + self.raw_sub_batch_samplers.append(sub_batch_sampler) def get_batch_samplers(self, mult_ratios, required_batch_size_multiple, seed): self.get_raw_batch_samplers(required_batch_size_multiple, seed) From c82b7c54df85b9df70fc66544326a4de96b61820 Mon Sep 17 00:00:00 2001 From: padentomasello <pdtomasello@gmail.com> Date: Mon, 18 Jul 2022 15:47:30 -0700 Subject: [PATCH 660/774] STOP Dataset Release and Experiment Reproduction (#4578) * STOP paper release Co-authored-by: Paden Tomasello <padentomasello@devfair0417.h2.fair> Co-authored-by: Paden Tomasello <padentomasello@learnfair5258.h2.fair> --- examples/audio_nlp/nlu/README.md | 51 ++ .../audio_nlp/nlu/configs/nlu_finetuning.yaml | 59 +++ examples/audio_nlp/nlu/create_dict_stop.sh | 38 ++ fairseq/models/hubert/hubert_asr.py | 330 +++++++++++- fairseq/models/wav2vec/wav2vec2_asr.py | 6 + fairseq/tasks/nlu_finetuning.py | 481 ++++++++++++++++++ 6 files changed, 954 insertions(+), 11 deletions(-) create mode 100644 examples/audio_nlp/nlu/README.md create mode 100644 examples/audio_nlp/nlu/configs/nlu_finetuning.yaml create mode 100755 examples/audio_nlp/nlu/create_dict_stop.sh create mode 100644 fairseq/tasks/nlu_finetuning.py diff --git a/examples/audio_nlp/nlu/README.md b/examples/audio_nlp/nlu/README.md new file mode 100644 index 0000000000..ec23934e6d --- /dev/null +++ b/examples/audio_nlp/nlu/README.md @@ -0,0 +1,51 @@ +# End-to-end NLU + +End-to-end spoken language understanding (SLU) predicts intent directly from audio using a single model. It promises to improve the performance of assistant systems by leveraging acoustic information lost in the intermediate textual representation and preventing cascading errors from Automatic Speech Recognition (ASR). Further, having one unified model has efficiency advantages when deploying assistant systems on-device. + +This page releases the code for reproducing the results in [STOP: A dataset for Spoken Task Oriented Semantic Parsing](TODO) + +The dataset can be downloaded here: [download link](https://dl.fbaipublicfiles.com/stop/stop.tar.gz) + +## Pretrained models end-to-end NLU Models + +| Speech Pretraining | ASR Pretraining | Test EM Accuracy | Tesst EM-Tree Accuracy | Link | +| ----------- | ----------- |----------|----------|----------| +| None | None | 36.54 | 57.01 | [link](https://dl.fbaipublicfiles.com/stop/end-to-end-nlu-none-none.pt) | +| Wav2Vec | None | 68.05 | 82.53 | [link](https://dl.fbaipublicfiles.com/stop/end-to-end-nlu-wav2vec-none.pt) | +| HuBERT | None | 68.40 | 82.85 | [link](https://dl.fbaipublicfiles.com/stop/end-to-end-nlu-hubert-none.pt) | +| Wav2Vec | STOP | 68.70 | 82.78 | [link](https://dl.fbaipublicfiles.com/stop/end-to-end-nlu-wav2vec-stop.pt) | +| HuBERT | STOP | 69.23 | 82.87 | [link](https://dl.fbaipublicfiles.com/stop/end-to-end-nlu-hubert-stop.pt) | +| Wav2Vec | Librispeech | 68.47 | 82.49 | [link](https://dl.fbaipublicfiles.com/stop/end-to-end-nlu-wav2vec-ls.pt) | +| HuBERT | Librispeech | 68.70 | 82.78 | [link](https://dl.fbaipublicfiles.com/stop/end-to-end-nlu-hubert-ls.pt) | + +## Pretrained models ASR Models +| Speech Pre-training | ASR Dataset | STOP Eval WER | STOP Test WER | dev\_other WER | dev\_clean WER | test\_clean WER | test\_other WER | Link | +| ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | ----------- | +| HuBERT | Librispeech | 8.47 | 2.99 | 3.25 | 8.06 | 25.68 | 26.19 | [link](https://dl.fbaipublicfiles.com/stop/ctc-asr-hubert-ls.pt) | +| Wav2Vec | Librispeech | 9.215 | 3.204 | 3.334 | 9.006 | 27.257 | 27.588 | [link](https://dl.fbaipublicfiles.com/stop/ctc-asr-wav2vec-ls.pt) | +| HuBERT | STOP | 46.31 | 31.30 | 31.52 | 47.16 | 4.29 | 4.26 | [link](https://dl.fbaipublicfiles.com/stop/ctc-asr-hubert-stop.pt) | +| Wav2Vec | STOP | 43.103 | 27.833 | 28.479 | 28.479 | 4.679 | 4.667 | [link](https://dl.fbaipublicfiles.com/stop/ctc-asr-wav2vec-stop.pt) | +| HuBERT | Librispeech + STOP | 9.015 | 3.211 | 3.372 | 8.635 | 5.133 | 5.056 | [link](https://dl.fbaipublicfiles.com/stop/ctc-asr-hubert-ls-stop.pt) | +| Wav2Vec | Librispeech + STOP | 9.549 | 3.537 | 3.625 | 9.514 | 5.59 | 5.562 | [link](https://dl.fbaipublicfiles.com/stop/ctc-asr-wav2vec-ls-stop.pt) | + +## Creating the fairseq datasets from STOP + +First, create the audio file manifests and label files: + +``` +python examples/audio_nlp/nlu/generate_manifests.py --stop_root $STOP_DOWNLOAD_DIR/stop --output $FAIRSEQ_DATASET_OUTPUT/ +``` + + +Run `./examples/audio_nlp/nlu/create_dict_stop.sh $FAIRSEQ_DATASET_OUTPUT` to generate the fairseq dictionaries. + + +## Training an End-to-end NLU Model + + +Download a wav2vec or hubert model from [link](https://github.com/facebookresearch/fairseq/tree/main/examples/hubert) or [link](https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec) + + +``` +python fairseq_cli/hydra-train --config-dir examples/audio_nlp/nlu/configs/ --config-name nlu_finetuning task.data=$FAIRSEQ_DATA_OUTPUT model.w2v_path=$PRETRAINED_MODEL_PATH +``` diff --git a/examples/audio_nlp/nlu/configs/nlu_finetuning.yaml b/examples/audio_nlp/nlu/configs/nlu_finetuning.yaml new file mode 100644 index 0000000000..bb90f45a30 --- /dev/null +++ b/examples/audio_nlp/nlu/configs/nlu_finetuning.yaml @@ -0,0 +1,59 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 10 + tensorboard_logdir: tb + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: em_error + save_interval: 10 + +task: + _name: nlu_finetuning + data: ??? + labels: parse + eval_wer_parse: true + autoregressive: true + +dataset: + num_workers: 6 + max_tokens: 1600000 + skip_invalid_size_inputs_valid_test: true + valid_subset: eval,test + train_subset: train + validate_interval: 10 + +criterion: + _name: label_smoothed_cross_entropy + +optimization: + max_update: 320000 + lr: [0.0001] + sentence_avg: true + update_freq: [1] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_seq2seq + w2v_path: ??? + autoregressive: true + apply_mask: true + mask_prob: 0.5 + mask_channel_prob: 0.5 + mask_channel_length: 64 + layerdrop: 0.1 + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 0 diff --git a/examples/audio_nlp/nlu/create_dict_stop.sh b/examples/audio_nlp/nlu/create_dict_stop.sh new file mode 100755 index 0000000000..c782035343 --- /dev/null +++ b/examples/audio_nlp/nlu/create_dict_stop.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +### Script handling creation of data binaries +### for model training within fairseq + + +fairseq_root="." + +data_root=$1 +train_prefix="${data_root}/train" +valid_prefix="${data_root}/eval" +test_prefix="${data_root}/test" + +dest_dir="$data_root/" + +#echo "src dict: $src_dict" > "$dest_dir/src_dict.txt" +#echo "trg dict: $tgt_dict" > "$dest_dir/tgt_dict.txt" + + #--tgtdict $tgt_dict \ +PYTHONPATH=$fairseq_root \ + python $fairseq_root/fairseq_cli/preprocess.py \ + --source-lang "parse" \ + --trainpref $train_prefix \ + --validpref $valid_prefix \ + --destdir $dest_dir \ + --only-source \ + --dict-only \ + --workers 60; + +PYTHONPATH=$fairseq_root \ + python $fairseq_root/fairseq_cli/preprocess.py \ + --source-lang "ltr" \ + --trainpref $train_prefix \ + --validpref $valid_prefix \ + --destdir $dest_dir \ + --only-source \ + --dict-only \ + --workers 60; diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index 8e06a2e675..6f5dc46f55 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -3,20 +3,31 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from typing import Any import contextlib +import copy +import math from argparse import Namespace from dataclasses import dataclass, field -from typing import Any - +from typing import Any, Optional +import numpy as np import torch import torch.nn as nn -from omegaconf import II, MISSING +import torch.nn.functional as F +from omegaconf import II, MISSING, open_dict from fairseq import checkpoint_utils, tasks, utils from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import convert_namespace_to_omegaconf -from fairseq.models import BaseFairseqModel, FairseqEncoder, register_model +from fairseq.models import ( + BaseFairseqModel, + FairseqEncoder, + FairseqEncoderDecoderModel, + FairseqIncrementalDecoder, + register_model, +) from fairseq.models.hubert.hubert import MASKING_DISTRIBUTION_CHOICES +from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerDecoderLayer from fairseq.tasks import FairseqTask @@ -51,6 +62,9 @@ class HubertAsrConfig(FairseqDataclass): "help": "dropout probability after activation in FFN " "inside hubert model" }, ) + encoder_embed_dim: Optional[int] = field( + default=768, metadata={"help": "encoder embedding dimension"} + ) # masking apply_mask: bool = field( @@ -191,13 +205,12 @@ class HubertSeq2SeqConfig(HubertAsrConfig): metadata={"help": "use learned positional embeddings in the decoder"}, ) decoder_normalize_before: bool = field( - default=False, - metadata={"help": "apply layernorm before each decoder block"}, + default=False, metadata={"help": "apply layernorm before each decoder block"} ) no_token_positional_embeddings: bool = field( default=False, metadata={ - "help": "if set, disables positional embeddings " "(outside self attention)" + "help": "if set, disables positional embeddings (outside self attention)" }, ) decoder_dropout: float = field( @@ -206,23 +219,101 @@ class HubertSeq2SeqConfig(HubertAsrConfig): decoder_attention_dropout: float = field( default=0.0, metadata={ - "help": "dropout probability for attention weights " "inside the decoder" + "help": "dropout probability for attention weights inside the decoder" }, ) decoder_activation_dropout: float = field( default=0.0, metadata={ - "help": "dropout probability after activation in FFN " "inside the decoder" + "help": "dropout probability after activation in FFN inside the decoder" }, ) max_target_positions: int = field( default=2048, metadata={"help": "max target positions"} ) share_decoder_input_output_embed: bool = field( + default=False, metadata={"help": "share decoder input and output embeddings"} + ) + autoregressive: bool = II("task.autoregressive") + seq2seq_path: str = field( + default='', + metadata={"help": "reset_dict"}, + ) + reset_dict: bool = field( default=False, - metadata={"help": "share decoder input and output embeddings"}, + metadata={"help": "reset_dict"}, ) +@register_model("hubert_seq2seq", dataclass=HubertSeq2SeqConfig) +class HubertSeq2SeqModel(FairseqEncoderDecoderModel): + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @classmethod + def build_model(cls, cfg: HubertSeq2SeqConfig, task: FairseqTask): + """Build a new model instance.""" + + assert ( + cfg.autoregressive + ), "Please set task.autoregressive=true for seq2seq asr models" + + src_dict, tgt_dict = task.source_dictionary, task.target_dictionary + + def build_embedding(dictionary, embed_dim): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + emb = Embedding(num_embeddings, embed_dim, padding_idx) + return emb + + decoder_embed_tokens = build_embedding(tgt_dict, cfg.decoder_embed_dim) + + encoder = cls.build_encoder(cfg, task) + decoder = cls.build_decoder(cfg, tgt_dict, decoder_embed_tokens) + + + model = HubertSeq2SeqModel(encoder, decoder) + + if cfg['seq2seq_path']: + state = checkpoint_utils.load_checkpoint_to_cpu( + cfg.seq2seq_path + ) + state = state['model'] + if cfg['reset_dict']: + del state['decoder.embed_out'] + del state['decoder.embed_tokens.weight'] + model.load_state_dict(state, strict=False) + return model + + @classmethod + def build_encoder(cls, cfg: HubertAsrConfig, task): + return HubertEncoder(cfg, task) + + @classmethod + def build_decoder(cls, cfg: HubertSeq2SeqConfig, tgt_dict, embed_tokens): + return TransformerDecoder(cfg, tgt_dict, embed_tokens) + + def forward(self, **kwargs): + encoder_out = self.encoder(**kwargs) + decoder_out = self.decoder(encoder_out=encoder_out, **kwargs) + return decoder_out + + def upgrade_state_dict_named(self, state_dict, name): + return state_dict + + def load_state_dict( + self, + state_dict, + strict=True, + model_cfg=None, + args: Optional[Namespace] = None, + ): + if(model_cfg.reset_dict): + logger.warn("Overriding loading strict state dict!") + del state_dict['decoder.embed_out'] + del state_dict['decoder.embed_tokens.weight'] + return super().load_state_dict(state_dict, False, model_cfg, args) + return super().load_state_dict(state_dict, strict, model_cfg, args) + class HubertEncoder(FairseqEncoder): def __init__(self, cfg: HubertAsrConfig, task): @@ -290,7 +381,7 @@ def __init__(self, cfg: HubertAsrConfig, task): self.freeze_finetune_updates = cfg.freeze_finetune_updates self.num_updates = 0 - if task.target_dictionary is not None: + if task.target_dictionary is not None and not cfg.autoregressive : self.proj = Linear(d, len(task.target_dictionary)) elif getattr(cfg, "decoder_embed_dim", d) != d: self.proj = Linear(d, cfg.decoder_embed_dim) @@ -339,6 +430,10 @@ def reorder_encoder_out(self, encoder_out, new_order): encoder_out["encoder_padding_mask"] = encoder_out[ "encoder_padding_mask" ].index_select(0, new_order) + if encoder_out["padding_mask"] is not None: + encoder_out["padding_mask"] = encoder_out[ + "padding_mask" + ].index_select(0, new_order) return encoder_out def max_positions(self): @@ -348,6 +443,219 @@ def max_positions(self): def upgrade_state_dict_named(self, state_dict, name): return state_dict +class TransformerDecoder(FairseqIncrementalDecoder): + """ + Transformer decoder consisting of *args.decoder_layers* layers. Each layer + is a :class:`TransformerDecoderLayer`. + + Args: + args (argparse.Namespace): parsed command-line arguments + dictionary (~fairseq.data.Dictionary): decoding dictionary + embed_tokens (torch.nn.Embedding): output embedding + no_encoder_attn (bool, optional): whether to attend to encoder outputs + (default: False). + """ + + def __init__( + self, + cfg: HubertSeq2SeqConfig, + dictionary, + embed_tokens, + no_encoder_attn=False, + ): + super().__init__(dictionary) + + self.dropout = cfg.decoder_dropout + self.share_input_output_embed = cfg.share_decoder_input_output_embed + + input_embed_dim = embed_tokens.embedding_dim + embed_dim = cfg.decoder_embed_dim + self.output_embed_dim = cfg.decoder_embed_dim + + self.layerdrop = cfg.decoder_layerdrop + + self.padding_idx = embed_tokens.padding_idx + self.max_target_positions = cfg.max_target_positions + + self.embed_tokens = embed_tokens + self.embed_scale = math.sqrt(embed_dim) # todo: try with input_embed_dim + + self.project_in_dim = ( + Linear(input_embed_dim, embed_dim, bias=False) + if embed_dim != input_embed_dim + else None + ) + + self.embed_positions = ( + PositionalEmbedding( + cfg.max_target_positions, + embed_dim, + self.padding_idx, + learned=cfg.decoder_learned_pos, + ) + if not cfg.no_token_positional_embeddings + else None + ) + + # TODO: update this when transformer gets converted to dataclass configs + transformer_cfg = copy.deepcopy(cfg) + with open_dict(transformer_cfg): + transformer_cfg.dropout = transformer_cfg.decoder_dropout + transformer_cfg.attention_dropout = ( + transformer_cfg.decoder_attention_dropout + ) + transformer_cfg.activation_dropout = ( + transformer_cfg.decoder_activation_dropout + ) + + self.layers = nn.ModuleList([]) + self.layers.extend( + [ + TransformerDecoderLayer(transformer_cfg, no_encoder_attn) + for _ in range(transformer_cfg.decoder_layers) + ] + ) + + if not self.share_input_output_embed: + self.embed_out = nn.Parameter( + torch.Tensor(len(dictionary), self.output_embed_dim) + ) + nn.init.normal_(self.embed_out, mean=0, std=self.output_embed_dim**-0.5) + + if transformer_cfg.decoder_normalize_before: + self.layer_norm = LayerNorm(embed_dim) + else: + self.layer_norm = None + + def forward( + self, prev_output_tokens, encoder_out=None, incremental_state=None, **unused + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + encoder_out (Tensor, optional): output from the encoder, used for + encoder-side attention + incremental_state (dict): dictionary used for storing state during + :ref:`Incremental decoding` + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + if (type(prev_output_tokens) == list): + max_len = max((len(x) for x in prev_output_tokens)) + tmp = torch.zeros([len(prev_output_tokens), max_len], device=prev_output_tokens[0].device) + for (i, p) in enumerate(prev_output_tokens): + tmp[i, :len(p)] = p + prev_output_tokens = tmp + prev_output_tokens = prev_output_tokens.long() + x, extra = self.extract_features( + prev_output_tokens, encoder_out, incremental_state + ) + x = self.output_layer(x) + return x, extra + + def extract_features( + self, prev_output_tokens, encoder_out=None, incremental_state=None, **unused + ): + """ + Similar to *forward* but only return features. + + Returns: + tuple: + - the decoder's features of shape `(batch, tgt_len, embed_dim)` + - a dictionary with any model-specific outputs + """ + + # embed positions + positions = ( + self.embed_positions( + prev_output_tokens, incremental_state=incremental_state + ) + if self.embed_positions is not None + else None + ) + + if incremental_state is not None: + prev_output_tokens = prev_output_tokens[:, -1:] + if positions is not None: + positions = positions[:, -1:] + + # embed tokens and positions + x = self.embed_scale * self.embed_tokens(prev_output_tokens) + + if self.project_in_dim is not None: + x = self.project_in_dim(x) + + if positions is not None: + x += positions + x = F.dropout(x, p=self.dropout, training=self.training) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + attn = None + + inner_states = [x] + + # decoder layers + self_attn_padding_mask = None + if prev_output_tokens.eq(self.padding_idx).any(): + self_attn_padding_mask = prev_output_tokens.eq(self.padding_idx) + for layer in self.layers: + dropout_probability = np.random.random() + if not self.training or (dropout_probability > self.layerdrop): + x, attn, _ = layer( + x, + encoder_out["encoder_out"] if encoder_out is not None else None, + encoder_out["padding_mask"] if encoder_out is not None else None, + incremental_state, + self_attn_mask=self.buffered_future_mask(x) + if incremental_state is None + else None, + self_attn_padding_mask=self_attn_padding_mask + ) + inner_states.append(x) + + if self.layer_norm: + x = self.layer_norm(x) + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + return x, {"attn": attn, "inner_states": inner_states} + + def output_layer(self, features, **kwargs): + """Project features to the vocabulary size.""" + # project back to size of vocabulary + if self.share_input_output_embed: + return F.linear(features, self.embed_tokens.weight) + else: + return F.linear(features, self.embed_out) + + def max_positions(self): + """Maximum output length supported by the decoder.""" + if self.embed_positions is None: + return self.max_target_positions + return min(self.max_target_positions, self.embed_positions.max_positions) + + def buffered_future_mask(self, tensor): + dim = tensor.size(0) + if ( + not hasattr(self, "_future_mask") + or self._future_mask is None + or self._future_mask.device != tensor.device + or self._future_mask.size(0) < dim + ): + self._future_mask = torch.triu( + utils.fill_with_neg_inf(tensor.new(dim, dim)), 1 + ) + return self._future_mask[:dim, :dim] + + def upgrade_state_dict_named(self, state_dict, name): + return state_dict + def Embedding(num_embeddings, embedding_dim, padding_idx): m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 08d875a01d..8854bda5ca 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -626,6 +626,12 @@ def forward( - the decoder's output of shape `(batch, tgt_len, vocab)` - a dictionary with any model-specific outputs """ + if (type(prev_output_tokens) == list): + max_len = max((len(x) for x in prev_output_tokens)) + tmp = torch.zeros([len(prev_output_tokens), max_len], device=prev_output_tokens[0].device) + for (i, p) in enumerate(prev_output_tokens): + tmp[i, :len(p)] = p + prev_output_tokens = tmp prev_output_tokens = prev_output_tokens.long() x, extra = self.extract_features( prev_output_tokens, encoder_out, incremental_state diff --git a/fairseq/tasks/nlu_finetuning.py b/fairseq/tasks/nlu_finetuning.py new file mode 100644 index 0000000000..2ea39cdb87 --- /dev/null +++ b/fairseq/tasks/nlu_finetuning.py @@ -0,0 +1,481 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import os +import torch +import json + +from argparse import Namespace +from dataclasses import dataclass, field +from typing import Optional, Any + +from fairseq.data import AddTargetDataset, Dictionary, encoders +from fairseq.tasks.audio_pretraining import AudioPretrainingTask, AudioPretrainingConfig +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.configs import GenerationConfig +from fairseq.data.text_compressor import TextCompressor, TextCompressionLevel + +from . import register_task +from .. import utils +from ..logging import metrics + + +logger = logging.getLogger(__name__) + + +class LabelEncoder(object): + def __init__(self, dictionary): + self.dictionary = dictionary + + def __call__(self, label): + return self.dictionary.encode_line( + label, append_eos=False, add_if_not_exist=False + ) + + +def label_len_fn(label): + return len(label.split(" ")) + + +@dataclass +class NLUFinetuningConfig(AudioPretrainingConfig): + # Options for reporting WER metrics during validation. Only applicable to + # Seq2Seq models during fine-tuning + eval_wer: bool = field( + default=False, metadata={"help": "compute WER for Seq2Seq models"} + ) + eval_wer_parse: bool = field( + default=False, metadata={"help": "compute WER for Seq2Seq models"} + ) + eval_wer_config: GenerationConfig = field( + default_factory=lambda: GenerationConfig(), + metadata={"help": "beam search config for evaluating wer during training"}, + ) + eval_wer_tokenizer: Any = field( + default=None, + metadata={"help": "tokenizer config for evaluating wer during training"}, + ) + eval_wer_post_process: str = field( + default="letter", + metadata={ + "help": "remove BPE tokens before scoring (can be sentencepiece, letter, and more)" + }, + ) + eval_bleu: bool = field( + default=False, metadata={"help": "evaluation with BLEU scores"} + ) + eval_bleu_detok: Optional[str] = field( + default=None, metadata={ + "help": "detokenize before computing BLEU (e.g., 'moses'); " + "required if using --eval-bleu; use 'space' to disable " + "detokenization; see fairseq.data.encoders for other options" + } + ) + eval_bleu_detok_args: str = field( + default="{}", + metadata={"help": "args for building the tokenizer, if needed"} + ) + eval_tokenized_bleu: bool = field( + default=False, + metadata={"help": "compute tokenized BLEU instead of sacrebleu"} + ) + eval_bleu_remove_bpe: Optional[str] = field( + default=None, metadata={"help": "remove BPE before computing BLEU"} + ) + eval_bleu_args: str = field( + default="{}", + metadata={"help": "generation args for BLUE scoring, e.g., " + "'{\"beam\": 4, \"lenpen\": 0.6}'"} + ) + eval_bleu_print_samples: bool = field( + default=False, + metadata={"help": "print sample generations during validation"} + ) + autoregressive: bool = field( + default=False, + metadata={ + "help": "required for autoregressive decoders (like seq2seq models); " + "adds 'prev_output_tokens' to input and appends eos to target" + }, + ) + + +@register_task("nlu_finetuning", dataclass=NLUFinetuningConfig) +class NLUFinetuningTask(AudioPretrainingTask): + """ """ + + cfg: NLUFinetuningConfig + + def __init__( + self, + cfg: NLUFinetuningConfig, + ): + super().__init__(cfg) + self.blank_symbol = "<s>" + + self.state.add_factory("target_dictionary", self.load_target_dictionary) + + def load_target_dictionary(self): + if self.cfg.labels: + dict_path = os.path.join(self.cfg.data, f"dict.{self.cfg.labels}.txt") + return Dictionary.load(dict_path) + return None + + def load_dataset(self, split: str, task_cfg: NLUFinetuningConfig = None, **kwargs): + super().load_dataset(split, task_cfg, **kwargs) + + task_cfg = task_cfg or self.cfg + assert task_cfg.labels is not None + text_compression_level = getattr( + TextCompressionLevel, str(self.cfg.text_compression_level) + ) + data_path = self.cfg.data + label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") + skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) + text_compressor = TextCompressor(level=text_compression_level) + with open(label_path, "r") as f: + labels = [ + text_compressor.compress(l) + for i, l in enumerate(f) if i not in skipped_indices + ] + + assert len(labels) == len(self.datasets[split]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.datasets[split])}) do not match" + ) + + process_label = LabelEncoder(self.target_dictionary) + + self.datasets[split] = AddTargetDataset( + self.datasets[split], + labels, + pad=self.target_dictionary.pad(), + eos=self.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + label_len_fn=label_len_fn, + add_to_input=task_cfg.get("autoregressive", False), + text_compression_level=text_compression_level + ) + + @property + def target_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.state.target_dictionary + + def valid_step(self, sample, model, criterion): + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + if self.cfg.eval_wer_parse and self.cfg.autoregressive: + metrics = self._inference_with_wer_parse(self.sequence_generator, sample, model) + logging_output["_num_char_errors"] = metrics["num_char_errors"] + logging_output["_num_chars"] = metrics["num_chars"] + logging_output["_num_word_errors"] = metrics["num_word_errors"] + logging_output["_num_words"] = metrics["num_words"] + logging_output["_num_em_errors"] = metrics["num_em_errors"] + logging_output["_num_ems"] = metrics["num_ems"] + logging_output["_num_tree_errors"] = metrics["num_tree_errors"] + logging_output["_num_trees"] = metrics["num_trees"] + if self.cfg.eval_wer and self.cfg.autoregressive: + metrics = self._inference_with_wer(self.sequence_generator, sample, model) + logging_output["_num_char_errors"] = metrics["num_char_errors"] + logging_output["_num_chars"] = metrics["num_chars"] + logging_output["_num_word_errors"] = metrics["num_word_errors"] + logging_output["_num_words"] = metrics["num_words"] + if self.cfg.eval_bleu and self.cfg.autoregressive: + metrics = self._inference_with_bleu(self.sequence_generator, sample, model) + logging_output['_bleu_sys_len'] = metrics.sys_len + logging_output['_bleu_ref_len'] = metrics.ref_len + # we split counts into separate entries so that they can be + # summed efficiently across workers using fast-stat-sync + assert len(metrics.counts) == 4 + for i in range(4): + logging_output[f"_bleu_counts_{i}"] = metrics.counts[i] + logging_output[f"_bleu_totals_{i}"] = metrics.totals[i] + return loss, sample_size, logging_output + + def build_model(self, model_cfg: FairseqDataclass): + model = super().build_model(model_cfg) + + if (self.cfg.eval_wer or self.cfg.eval_wer_parse) and self.cfg.autoregressive: + self.sequence_generator = self.build_generator( + [model], + self.cfg.eval_wer_config, + ) + if self.cfg.eval_wer_tokenizer: + self.tokenizer = encoders.build_tokenizer(self.cfg.eval_wer_tokenizer) + else: + self.tokenizer = None + if self.cfg.eval_bleu and self.cfg.autoregressive: + assert self.cfg.eval_bleu_detok is not None, ( + '--eval-bleu-detok is required if using --eval-bleu; ' + 'try --eval-bleu-detok=moses (or --eval-bleu-detok=space ' + 'to disable detokenization, e.g., when using sentencepiece)' + ) + detok_args = json.loads(self.cfg.eval_bleu_detok_args) + self.tokenizer = encoders.build_tokenizer( + Namespace(tokenizer=self.cfg.eval_bleu_detok, **detok_args) + ) + gen_args = json.loads(self.cfg.eval_bleu_args) + gen_args = Namespace(**gen_args) + self.sequence_generator = self.build_generator([model], gen_args) + + return model + + def _inference_with_wer_parse(self, generator, sample, model): + import editdistance + + def decode(toks): + s = self.target_dictionary.string( + toks.int().cpu(), + self.cfg.eval_wer_post_process, + escape_unk=True, + ) + if self.tokenizer: + s = self.tokenizer.decode(s) + return s + + def decode_to_list(toks): + def token_string(i): + if i == self.target_dictionary.unk(): + return self.target_dictionary.unk_string(False) + else: + return self.target_dictionary[i] + return [ token_string(i) for i in toks ] + + def is_ont_token(token): + return '[' in token or ']' in token + + def post_process(l): + o = [] + for w in l: + if(w == self.target_dictionary.eos_word or w == '|'): + continue + if(w == '_'): + o.append(' ') + else: + o.append(w) + if(is_ont_token(w)): + o.append(' ') + return o + + num_word_errors, num_char_errors = 0, 0 + num_chars, num_words = 0, 0 + num_em_errors, num_ems = 0, 0 + num_tree_errors, num_trees = 0, 0 + gen_out = self.inference_step(generator, [model], sample, None) + for i in range(len(gen_out)): + hyp_tokens = gen_out[i][0]["tokens"] + # hyp = decode(hyp_tokens) + ref_tokens = utils.strip_pad(sample["target"][i], self.target_dictionary.pad()) + # ref = decode(ref_tokens) + hyp_list = decode_to_list(hyp_tokens) + ref_list = decode_to_list(ref_tokens) + + hyp_list = post_process(hyp_list) + ref_list = post_process(ref_list) + + hyp = ''.join(hyp_list).strip() + ref = ''.join(ref_list).strip() + num_chars += len(ref) + num_char_errors += editdistance.eval(hyp, ref) + hyp_words = hyp.split() + ref_words = ref.split() + hyp_tree = [ word for word in hyp_list if ('[' in word or ']' in word) ] + ref_tree = [ word for word in ref_list if ('[' in word or ']' in word) ] + # num_word_errors += editdistance.eval(hyp_words, ref_words) + hyp_before = decode(hyp_tokens).split() + ref_before = decode(ref_tokens).split() + + num_word_errors += editdistance.eval(hyp_before, ref_before) + num_words += len(ref_before) + if(hyp != ref): + num_em_errors += 1 + if(hyp_tree != ref_tree): + num_tree_errors += 1 + num_ems += 1 + num_trees += 1 + + return { + "num_char_errors": num_char_errors, + "num_chars": num_chars, + "num_word_errors": num_word_errors, + "num_words": num_words, + "num_ems": num_ems, + "num_em_errors": num_em_errors, + "num_trees": num_trees, + "num_tree_errors": num_tree_errors + } + + def _inference_with_wer(self, generator, sample, model): + import editdistance + + def decode(toks): + s = self.target_dictionary.string( + toks.int().cpu(), + self.cfg.eval_wer_post_process, + escape_unk=True, + ) + if self.tokenizer: + s = self.tokenizer.decode(s) + return s + + num_word_errors, num_char_errors = 0, 0 + num_chars, num_words = 0, 0 + gen_out = self.inference_step(generator, [model], sample, None) + for i in range(len(gen_out)): + hyp = decode(gen_out[i][0]["tokens"]) + ref = decode( + utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), + ) + num_char_errors += editdistance.eval(hyp, ref) + num_chars += len(ref) + hyp_words = hyp.split() + ref_words = ref.split() + num_word_errors += editdistance.eval(hyp_words, ref_words) + num_words += len(ref_words) + + return { + "num_char_errors": num_char_errors, + "num_chars": num_chars, + "num_word_errors": num_word_errors, + "num_words": num_words, + } + + def _inference_with_bleu(self, generator, sample, model): + import sacrebleu + + def decode(toks, is_ref): + s = self.target_dictionary.string( + toks.int().cpu(), + self.cfg.eval_bleu_remove_bpe, + # The default unknown string in fairseq is `<unk>`, but + # this is tokenized by sacrebleu as `< unk >`, inflating + # BLEU scores. Instead, we use a somewhat more verbose + # alternative that is unlikely to appear in the real + # reference, but doesn't get split into multiple tokens. + unk_string=( + "UNKNOWNTOKENINREF" if is_ref else "UNKNOWNTOKENINHYP" + ), + ) + if self.tokenizer: + s = self.tokenizer.decode(s) + return s + + gen_out = self.inference_step(generator, [model], sample) + hyps, refs = [], [] + for i in range(len(gen_out)): + hyps.append(decode(gen_out[i][0]['tokens'], is_ref=False)) + refs.append( + decode( + utils.strip_pad( + sample['target'][i], + self.target_dictionary.pad() + ), + is_ref=True, # don't count <unk> as matches to the hypo + ) + ) + if self.cfg.eval_bleu_print_samples: + logger.info('H-{} {}'.format(sample["id"][0], hyps[0])) + logger.info('T-{} {}'.format(sample["id"][0], refs[0])) + + eval_tokenization = 'none' if self.cfg.eval_tokenized_bleu else '13a' + return sacrebleu.corpus_bleu(hyps, [refs], tokenize=eval_tokenization) + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + if self.cfg.eval_wer or self.cfg.eval_wer_parse: + zero = torch.scalar_tensor(0.0) + num_char_errors = sum( + log.get("_num_char_errors", zero) for log in logging_outputs + ) + num_chars = sum(log.get("_num_chars", zero) for log in logging_outputs) + num_word_errors = sum( + log.get("_num_word_errors", zero) for log in logging_outputs + ) + num_words = sum(log.get("_num_words", zero) for log in logging_outputs) + metrics.log_scalar("_num_char_errors", num_char_errors) + metrics.log_scalar("_num_chars", num_chars) + metrics.log_scalar("_num_word_errors", num_word_errors) + metrics.log_scalar("_num_words", num_words) + if num_chars > 0: + metrics.log_derived( + "uer", + lambda meters: meters["_num_char_errors"].sum + * 100.0 + / meters["_num_chars"].sum + if meters["_num_chars"].sum > 0 + else float("nan"), + ) + if num_words > 0: + metrics.log_derived( + "wer", + lambda meters: meters["_num_word_errors"].sum + * 100.0 + / meters["_num_words"].sum + if meters["_num_words"].sum > 0 + else float("nan"), + ) + if self.cfg.eval_wer_parse: + num_em_errors = sum( + log.get("_num_em_errors", zero) for log in logging_outputs + ) + num_ems = sum( + log.get("_num_ems", zero) for log in logging_outputs + ) + metrics.log_scalar("_num_em_errors", num_em_errors) + metrics.log_scalar("_num_ems", num_ems) + num_tree_errors = sum( + log.get("_num_tree_errors", zero) for log in logging_outputs + ) + num_trees = sum( + log.get("_num_trees", zero) for log in logging_outputs + ) + metrics.log_scalar("_num_tree_errors", num_tree_errors) + metrics.log_scalar("_num_trees", num_trees) + + if num_ems > 0: + metrics.log_derived( + "em_error", + lambda meters: meters["_num_em_errors"].sum + * 100.0 + / meters["_num_ems"].sum + if meters["_num_ems"].sum > 0 + else float("nan"), + ) + if num_trees > 0: + metrics.log_derived( + "tree_error", + lambda meters: meters["_num_tree_errors"].sum + * 100.0 + / meters["_num_trees"].sum + if meters["_num_trees"].sum > 0 + else float("nan"), + ) + + if self.cfg.eval_bleu: + len_keys = ["_bleu_sys_len", "_bleu_ref_len"] + count_keys = [f"_bleu_counts_{i}" for i in range(4)] + total_keys = [f"_bleu_totals_{i}" for i in range(4)] + for k in len_keys + count_keys + total_keys: + metrics.log_scalar( + k, sum(log.get(k, 0) for log in logging_outputs) + ) + + import sacrebleu + metrics.log_derived( + 'bleu', + lambda meters: sacrebleu.compute_bleu( + correct=[meters[k].sum for k in count_keys], + total=[meters[k].sum for k in total_keys], + sys_len=meters['_bleu_sys_len'].sum, + ref_len=meters['_bleu_ref_len'].sum, + smooth_method="exp" + ).score + ) From e83bd93cd32ec5d58a473ca9aac0585b135ae0fd Mon Sep 17 00:00:00 2001 From: sravyapopuri388 <51169165+sravyapopuri388@users.noreply.github.com> Date: Tue, 19 Jul 2022 12:50:17 -0700 Subject: [PATCH 661/774] OSS ckpts for Interspeech 2022 paper (#4588) --- .../enhanced_direct_s2st_discrete_units.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md index 55bf22100e..97c47795ba 100644 --- a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md +++ b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md @@ -38,7 +38,7 @@ sed -i "1s/.*/$var/" ${SPLIT}.tsv **Speech-to-unit translation (S2UT)** -Here's an example for finetuning S2UT models with 1000 discrete units as target. You can download the [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/config.yaml) file and [vocabulary](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/dict.txt) from here: +Here's an example for finetuning S2UT models with 1000 discrete units as target. You can download the sample [config](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/config.yaml) file and [vocabulary](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/dict.txt) for Es-En from here: ``` fairseq-train $DATA_ROOT \ @@ -106,3 +106,20 @@ To evaluate speech translation output, we first apply ASR on the speech output a * En ASR: We use the "[Wav2Vec 2.0 Large (LV-60) + Self Training / 960 hours / Libri-Light + Librispeech](https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt)" En ASR model open-sourced by the [wav2vec](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec) project. The model is also available on [Hugging Face](https://huggingface.co/facebook/wav2vec2-large-960h-lv60-self). * Es ASR: We use the [Wav2Vec2-Large-XLSR-53-Spanish](https://huggingface.co/facebook/wav2vec2-large-xlsr-53) finetuned on spanish Common Voice Es ASR model open-sourced by Jonatasgrosman(<https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish>) on [Hugging Face](https://huggingface.co/jonatasgrosman/wav2vec2-large-xlsr-53-spanish). * See [instructions](https://github.com/pytorch/fairseq/tree/main/examples/wav2vec#evaluating-a-ctc-model) on how to run inference with a wav2vec-based ASR model. + + +## Finetuned Model Checkpoints + +ID | En - Es | Es - En | +| --- | --- | --- | +**S2UT systems without pre-training** +S2UT with multitask | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//S2UT_w_multitask.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//S2UT_w_multitask.pt) | +**S2UT systems with model pre-training** +w2v2-L | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_only.pt ) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_only.pt) | +w2v2-L + mBART (LNA-E) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LNE.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LNE.pt) | +w2v2-L + mBART (LNA-D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LND.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LND.pt) | +w2v2-L + mBART (LNA-E,D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LNED.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LNED.pt) | +**S2UT systems with model pre-training and data augmentation** +w2v2-L + mBART (LNA-D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LND_w_ASR.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LND_w_ASR.pt) | + +Note: Some of the tasks use speech_to_text_sharded task which is yet to be open sourced. So make sure to override the task to speech_to_text to use those models. From 8097fbeb811843ff6b6361f51d4d4bdc30896a49 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Wed, 20 Jul 2022 17:20:14 -0400 Subject: [PATCH 662/774] Update xformers install, other small fixes (#4539) * Update build.yml fix logger error * formatting fix Co-authored-by: Diana Liskovich <dianaml@devfair0471.h2.fair> --- .github/workflows/build.yml | 13 +- fairseq/data/audio/multi_modality_dataset.py | 4 +- fairseq/models/hubert/hubert_asr.py | 46 +++---- fairseq/models/wav2vec/wav2vec2_asr.py | 8 +- fairseq/tasks/nlu_finetuning.py | 120 +++++++++---------- fairseq/utils.py | 46 ++++--- 6 files changed, 130 insertions(+), 107 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a14365cd23..6f8d90e0eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,8 +41,19 @@ jobs: run: | python -m pip install iopath transformers pyarrow python -m pip install git+https://github.com/facebookresearch/fairscale.git@main - python -m pip install --progress-bar off git+https://github.com/facebookresearch/xformers.git@main python -m pip install pytest + python -m pip install pygit2 pgzip + + - name: Install xformers for Macos + if: matrix.platform == 'macos-latest' + run: | + brew install llvm libomp + CC=/usr/local/opt/llvm/bin/clang CXX=clang++ pip install git+https://github.com/facebookresearch/xformers.git@main + + - name: Install xformers for non-MacOS + if: matrix.platform != 'macos-latest' + run: | + python -m pip install --progress-bar off git+https://github.com/facebookresearch/xformers.git@main - name: Lint with flake8 run: | diff --git a/fairseq/data/audio/multi_modality_dataset.py b/fairseq/data/audio/multi_modality_dataset.py index ddc9eb63b5..2db1637341 100644 --- a/fairseq/data/audio/multi_modality_dataset.py +++ b/fairseq/data/audio/multi_modality_dataset.py @@ -122,7 +122,9 @@ def get_raw_batch_samplers(self, required_batch_size_multiple, seed): for i, ds in enumerate(self.datasets): # If we have ResamplingDataset, the same id can correpond to a different # sample in the next epoch, so we need to rebuild this at every epoch - if i < len(self.raw_sub_batch_samplers) and not resampling_dataset_present(ds): + if i < len(self.raw_sub_batch_samplers) and not resampling_dataset_present( + ds + ): logger.info(f"dataset {i} is valid and it is not re-sampled") continue indices[i] = ds.filter_indices_by_size( diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index 6f5dc46f55..05ddedc74b 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -6,6 +6,7 @@ from typing import Any import contextlib import copy +import logging import math from argparse import Namespace from dataclasses import dataclass, field @@ -30,6 +31,8 @@ from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerDecoderLayer from fairseq.tasks import FairseqTask +logger = logging.getLogger(__name__) + @dataclass class HubertAsrConfig(FairseqDataclass): @@ -236,7 +239,7 @@ class HubertSeq2SeqConfig(HubertAsrConfig): ) autoregressive: bool = II("task.autoregressive") seq2seq_path: str = field( - default='', + default="", metadata={"help": "reset_dict"}, ) reset_dict: bool = field( @@ -244,6 +247,7 @@ class HubertSeq2SeqConfig(HubertAsrConfig): metadata={"help": "reset_dict"}, ) + @register_model("hubert_seq2seq", dataclass=HubertSeq2SeqConfig) class HubertSeq2SeqModel(FairseqEncoderDecoderModel): def __init__(self, encoder, decoder): @@ -270,17 +274,14 @@ def build_embedding(dictionary, embed_dim): encoder = cls.build_encoder(cfg, task) decoder = cls.build_decoder(cfg, tgt_dict, decoder_embed_tokens) - model = HubertSeq2SeqModel(encoder, decoder) - if cfg['seq2seq_path']: - state = checkpoint_utils.load_checkpoint_to_cpu( - cfg.seq2seq_path - ) - state = state['model'] - if cfg['reset_dict']: - del state['decoder.embed_out'] - del state['decoder.embed_tokens.weight'] + if cfg["seq2seq_path"]: + state = checkpoint_utils.load_checkpoint_to_cpu(cfg.seq2seq_path) + state = state["model"] + if cfg["reset_dict"]: + del state["decoder.embed_out"] + del state["decoder.embed_tokens.weight"] model.load_state_dict(state, strict=False) return model @@ -307,10 +308,10 @@ def load_state_dict( model_cfg=None, args: Optional[Namespace] = None, ): - if(model_cfg.reset_dict): + if model_cfg.reset_dict: logger.warn("Overriding loading strict state dict!") - del state_dict['decoder.embed_out'] - del state_dict['decoder.embed_tokens.weight'] + del state_dict["decoder.embed_out"] + del state_dict["decoder.embed_tokens.weight"] return super().load_state_dict(state_dict, False, model_cfg, args) return super().load_state_dict(state_dict, strict, model_cfg, args) @@ -381,7 +382,7 @@ def __init__(self, cfg: HubertAsrConfig, task): self.freeze_finetune_updates = cfg.freeze_finetune_updates self.num_updates = 0 - if task.target_dictionary is not None and not cfg.autoregressive : + if task.target_dictionary is not None and not cfg.autoregressive: self.proj = Linear(d, len(task.target_dictionary)) elif getattr(cfg, "decoder_embed_dim", d) != d: self.proj = Linear(d, cfg.decoder_embed_dim) @@ -431,9 +432,9 @@ def reorder_encoder_out(self, encoder_out, new_order): "encoder_padding_mask" ].index_select(0, new_order) if encoder_out["padding_mask"] is not None: - encoder_out["padding_mask"] = encoder_out[ - "padding_mask" - ].index_select(0, new_order) + encoder_out["padding_mask"] = encoder_out["padding_mask"].index_select( + 0, new_order + ) return encoder_out def max_positions(self): @@ -443,6 +444,7 @@ def max_positions(self): def upgrade_state_dict_named(self, state_dict, name): return state_dict + class TransformerDecoder(FairseqIncrementalDecoder): """ Transformer decoder consisting of *args.decoder_layers* layers. Each layer @@ -544,11 +546,13 @@ def forward( - the decoder's output of shape `(batch, tgt_len, vocab)` - a dictionary with any model-specific outputs """ - if (type(prev_output_tokens) == list): + if type(prev_output_tokens) == list: max_len = max((len(x) for x in prev_output_tokens)) - tmp = torch.zeros([len(prev_output_tokens), max_len], device=prev_output_tokens[0].device) + tmp = torch.zeros( + [len(prev_output_tokens), max_len], device=prev_output_tokens[0].device + ) for (i, p) in enumerate(prev_output_tokens): - tmp[i, :len(p)] = p + tmp[i, : len(p)] = p prev_output_tokens = tmp prev_output_tokens = prev_output_tokens.long() x, extra = self.extract_features( @@ -614,7 +618,7 @@ def extract_features( self_attn_mask=self.buffered_future_mask(x) if incremental_state is None else None, - self_attn_padding_mask=self_attn_padding_mask + self_attn_padding_mask=self_attn_padding_mask, ) inner_states.append(x) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 8854bda5ca..9d3ffa1544 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -626,11 +626,13 @@ def forward( - the decoder's output of shape `(batch, tgt_len, vocab)` - a dictionary with any model-specific outputs """ - if (type(prev_output_tokens) == list): + if type(prev_output_tokens) == list: max_len = max((len(x) for x in prev_output_tokens)) - tmp = torch.zeros([len(prev_output_tokens), max_len], device=prev_output_tokens[0].device) + tmp = torch.zeros( + [len(prev_output_tokens), max_len], device=prev_output_tokens[0].device + ) for (i, p) in enumerate(prev_output_tokens): - tmp[i, :len(p)] = p + tmp[i, : len(p)] = p prev_output_tokens = tmp prev_output_tokens = prev_output_tokens.long() x, extra = self.extract_features( diff --git a/fairseq/tasks/nlu_finetuning.py b/fairseq/tasks/nlu_finetuning.py index 2ea39cdb87..a335021335 100644 --- a/fairseq/tasks/nlu_finetuning.py +++ b/fairseq/tasks/nlu_finetuning.py @@ -70,31 +70,31 @@ class NLUFinetuningConfig(AudioPretrainingConfig): default=False, metadata={"help": "evaluation with BLEU scores"} ) eval_bleu_detok: Optional[str] = field( - default=None, metadata={ + default=None, + metadata={ "help": "detokenize before computing BLEU (e.g., 'moses'); " - "required if using --eval-bleu; use 'space' to disable " - "detokenization; see fairseq.data.encoders for other options" - } + "required if using --eval-bleu; use 'space' to disable " + "detokenization; see fairseq.data.encoders for other options" + }, ) eval_bleu_detok_args: str = field( - default="{}", - metadata={"help": "args for building the tokenizer, if needed"} + default="{}", metadata={"help": "args for building the tokenizer, if needed"} ) eval_tokenized_bleu: bool = field( - default=False, - metadata={"help": "compute tokenized BLEU instead of sacrebleu"} + default=False, metadata={"help": "compute tokenized BLEU instead of sacrebleu"} ) eval_bleu_remove_bpe: Optional[str] = field( default=None, metadata={"help": "remove BPE before computing BLEU"} ) eval_bleu_args: str = field( default="{}", - metadata={"help": "generation args for BLUE scoring, e.g., " - "'{\"beam\": 4, \"lenpen\": 0.6}'"} + metadata={ + "help": "generation args for BLUE scoring, e.g., " + '\'{"beam": 4, "lenpen": 0.6}\'' + }, ) eval_bleu_print_samples: bool = field( - default=False, - metadata={"help": "print sample generations during validation"} + default=False, metadata={"help": "print sample generations during validation"} ) autoregressive: bool = field( default=False, @@ -141,7 +141,8 @@ def load_dataset(self, split: str, task_cfg: NLUFinetuningConfig = None, **kwarg with open(label_path, "r") as f: labels = [ text_compressor.compress(l) - for i, l in enumerate(f) if i not in skipped_indices + for i, l in enumerate(f) + if i not in skipped_indices ] assert len(labels) == len(self.datasets[split]), ( @@ -160,7 +161,7 @@ def load_dataset(self, split: str, task_cfg: NLUFinetuningConfig = None, **kwarg process_label=process_label, label_len_fn=label_len_fn, add_to_input=task_cfg.get("autoregressive", False), - text_compression_level=text_compression_level + text_compression_level=text_compression_level, ) @property @@ -172,7 +173,9 @@ def target_dictionary(self): def valid_step(self, sample, model, criterion): loss, sample_size, logging_output = super().valid_step(sample, model, criterion) if self.cfg.eval_wer_parse and self.cfg.autoregressive: - metrics = self._inference_with_wer_parse(self.sequence_generator, sample, model) + metrics = self._inference_with_wer_parse( + self.sequence_generator, sample, model + ) logging_output["_num_char_errors"] = metrics["num_char_errors"] logging_output["_num_chars"] = metrics["num_chars"] logging_output["_num_word_errors"] = metrics["num_word_errors"] @@ -189,8 +192,8 @@ def valid_step(self, sample, model, criterion): logging_output["_num_words"] = metrics["num_words"] if self.cfg.eval_bleu and self.cfg.autoregressive: metrics = self._inference_with_bleu(self.sequence_generator, sample, model) - logging_output['_bleu_sys_len'] = metrics.sys_len - logging_output['_bleu_ref_len'] = metrics.ref_len + logging_output["_bleu_sys_len"] = metrics.sys_len + logging_output["_bleu_ref_len"] = metrics.ref_len # we split counts into separate entries so that they can be # summed efficiently across workers using fast-stat-sync assert len(metrics.counts) == 4 @@ -213,9 +216,9 @@ def build_model(self, model_cfg: FairseqDataclass): self.tokenizer = None if self.cfg.eval_bleu and self.cfg.autoregressive: assert self.cfg.eval_bleu_detok is not None, ( - '--eval-bleu-detok is required if using --eval-bleu; ' - 'try --eval-bleu-detok=moses (or --eval-bleu-detok=space ' - 'to disable detokenization, e.g., when using sentencepiece)' + "--eval-bleu-detok is required if using --eval-bleu; " + "try --eval-bleu-detok=moses (or --eval-bleu-detok=space " + "to disable detokenization, e.g., when using sentencepiece)" ) detok_args = json.loads(self.cfg.eval_bleu_detok_args) self.tokenizer = encoders.build_tokenizer( @@ -246,22 +249,23 @@ def token_string(i): return self.target_dictionary.unk_string(False) else: return self.target_dictionary[i] - return [ token_string(i) for i in toks ] + + return [token_string(i) for i in toks] def is_ont_token(token): - return '[' in token or ']' in token + return "[" in token or "]" in token def post_process(l): o = [] for w in l: - if(w == self.target_dictionary.eos_word or w == '|'): + if w == self.target_dictionary.eos_word or w == "|": continue - if(w == '_'): - o.append(' ') + if w == "_": + o.append(" ") else: o.append(w) - if(is_ont_token(w)): - o.append(' ') + if is_ont_token(w): + o.append(" ") return o num_word_errors, num_char_errors = 0, 0 @@ -272,7 +276,9 @@ def post_process(l): for i in range(len(gen_out)): hyp_tokens = gen_out[i][0]["tokens"] # hyp = decode(hyp_tokens) - ref_tokens = utils.strip_pad(sample["target"][i], self.target_dictionary.pad()) + ref_tokens = utils.strip_pad( + sample["target"][i], self.target_dictionary.pad() + ) # ref = decode(ref_tokens) hyp_list = decode_to_list(hyp_tokens) ref_list = decode_to_list(ref_tokens) @@ -280,23 +286,23 @@ def post_process(l): hyp_list = post_process(hyp_list) ref_list = post_process(ref_list) - hyp = ''.join(hyp_list).strip() - ref = ''.join(ref_list).strip() + hyp = "".join(hyp_list).strip() + ref = "".join(ref_list).strip() num_chars += len(ref) num_char_errors += editdistance.eval(hyp, ref) hyp_words = hyp.split() ref_words = ref.split() - hyp_tree = [ word for word in hyp_list if ('[' in word or ']' in word) ] - ref_tree = [ word for word in ref_list if ('[' in word or ']' in word) ] + hyp_tree = [word for word in hyp_list if ("[" in word or "]" in word)] + ref_tree = [word for word in ref_list if ("[" in word or "]" in word)] # num_word_errors += editdistance.eval(hyp_words, ref_words) hyp_before = decode(hyp_tokens).split() ref_before = decode(ref_tokens).split() num_word_errors += editdistance.eval(hyp_before, ref_before) num_words += len(ref_before) - if(hyp != ref): + if hyp != ref: num_em_errors += 1 - if(hyp_tree != ref_tree): + if hyp_tree != ref_tree: num_tree_errors += 1 num_ems += 1 num_trees += 1 @@ -309,7 +315,7 @@ def post_process(l): "num_ems": num_ems, "num_em_errors": num_em_errors, "num_trees": num_trees, - "num_tree_errors": num_tree_errors + "num_tree_errors": num_tree_errors, } def _inference_with_wer(self, generator, sample, model): @@ -359,9 +365,7 @@ def decode(toks, is_ref): # BLEU scores. Instead, we use a somewhat more verbose # alternative that is unlikely to appear in the real # reference, but doesn't get split into multiple tokens. - unk_string=( - "UNKNOWNTOKENINREF" if is_ref else "UNKNOWNTOKENINHYP" - ), + unk_string=("UNKNOWNTOKENINREF" if is_ref else "UNKNOWNTOKENINHYP"), ) if self.tokenizer: s = self.tokenizer.decode(s) @@ -370,21 +374,18 @@ def decode(toks, is_ref): gen_out = self.inference_step(generator, [model], sample) hyps, refs = [], [] for i in range(len(gen_out)): - hyps.append(decode(gen_out[i][0]['tokens'], is_ref=False)) + hyps.append(decode(gen_out[i][0]["tokens"], is_ref=False)) refs.append( decode( - utils.strip_pad( - sample['target'][i], - self.target_dictionary.pad() - ), + utils.strip_pad(sample["target"][i], self.target_dictionary.pad()), is_ref=True, # don't count <unk> as matches to the hypo ) ) if self.cfg.eval_bleu_print_samples: - logger.info('H-{} {}'.format(sample["id"][0], hyps[0])) - logger.info('T-{} {}'.format(sample["id"][0], refs[0])) + logger.info("H-{} {}".format(sample["id"][0], hyps[0])) + logger.info("T-{} {}".format(sample["id"][0], refs[0])) - eval_tokenization = 'none' if self.cfg.eval_tokenized_bleu else '13a' + eval_tokenization = "none" if self.cfg.eval_tokenized_bleu else "13a" return sacrebleu.corpus_bleu(hyps, [refs], tokenize=eval_tokenization) def reduce_metrics(self, logging_outputs, criterion): @@ -424,19 +425,15 @@ def reduce_metrics(self, logging_outputs, criterion): ) if self.cfg.eval_wer_parse: num_em_errors = sum( - log.get("_num_em_errors", zero) for log in logging_outputs - ) - num_ems = sum( - log.get("_num_ems", zero) for log in logging_outputs + log.get("_num_em_errors", zero) for log in logging_outputs ) + num_ems = sum(log.get("_num_ems", zero) for log in logging_outputs) metrics.log_scalar("_num_em_errors", num_em_errors) metrics.log_scalar("_num_ems", num_ems) num_tree_errors = sum( - log.get("_num_tree_errors", zero) for log in logging_outputs - ) - num_trees = sum( - log.get("_num_trees", zero) for log in logging_outputs + log.get("_num_tree_errors", zero) for log in logging_outputs ) + num_trees = sum(log.get("_num_trees", zero) for log in logging_outputs) metrics.log_scalar("_num_tree_errors", num_tree_errors) metrics.log_scalar("_num_trees", num_trees) @@ -464,18 +461,17 @@ def reduce_metrics(self, logging_outputs, criterion): count_keys = [f"_bleu_counts_{i}" for i in range(4)] total_keys = [f"_bleu_totals_{i}" for i in range(4)] for k in len_keys + count_keys + total_keys: - metrics.log_scalar( - k, sum(log.get(k, 0) for log in logging_outputs) - ) + metrics.log_scalar(k, sum(log.get(k, 0) for log in logging_outputs)) import sacrebleu + metrics.log_derived( - 'bleu', + "bleu", lambda meters: sacrebleu.compute_bleu( correct=[meters[k].sum for k in count_keys], total=[meters[k].sum for k in total_keys], - sys_len=meters['_bleu_sys_len'].sum, - ref_len=meters['_bleu_ref_len'].sum, - smooth_method="exp" - ).score + sys_len=meters["_bleu_sys_len"].sum, + ref_len=meters["_bleu_ref_len"].sum, + smooth_method="exp", + ).score, ) diff --git a/fairseq/utils.py b/fairseq/utils.py index b6a7e2339b..3669594fdd 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -844,8 +844,8 @@ def safe_hasattr(obj, k): def hotreload_function(name=None): """ - Decorator to function to enable hot-reload for debugging. - It allows you to debug a function without having reloading all heavy models, dataset loading and + Decorator to function to enable hot-reload for debugging. + It allows you to debug a function without having reloading all heavy models, dataset loading and preprocessing, allow faster debugging. If you want to change model or dataset loading, consider relaunching your code ----------------------------------- @@ -857,8 +857,8 @@ def hotreload_function(name=None): Type "disable" to stop pausing this function and let code continue without pause Ctril + C to terminal if func raise error: - it will prompt user to - 1. Edit code, and press enter to retry + it will prompt user to + 1. Edit code, and press enter to retry 2. Ctrl + C to terminate 3. Type "raise" to raise that exception * Requirements: @@ -892,38 +892,45 @@ def train_step(self, sample ....): try: import jurigged except ImportError as e: - logger.warning(f'Please install jurigged: pip install jurigged[develoop]') + logger.warning(f"Please install jurigged: pip install jurigged[develoop]") raise e from fairseq.distributed import utils as distributed_utils import traceback - + def hotreload_decorator(func): - assert callable(func), f'not callable: {func}' + assert callable(func), f"not callable: {func}" jname = name or func.__name__ - logger.info(f'jurigged-hotreload:Apply jurigged on {jname}:{func.__name__}') + logger.info(f"jurigged-hotreload:Apply jurigged on {jname}:{func.__name__}") HOTRELOAD_PAUSE = bool(os.environ.get("HOTRELOAD_PAUSE", 0)) cublk = bool(os.environ.get("CUDA_LAUNCH_BLOCKING", 0)) prefix = f"HOTRELOAD:{jname}:[cublk={cublk}]" hot_reload_state = {"disable": False} + def func_wrapper(*args, **kwargs): - if not HOTRELOAD_PAUSE or hot_reload_state['disable']: + if not HOTRELOAD_PAUSE or hot_reload_state["disable"]: return func(*args, **kwargs) world_size = distributed_utils.get_global_world_size() - assert world_size <= 1, f'HOTRELOAD_PAUSE:{jname} currently cannot do distributed training' + assert ( + world_size <= 1 + ), f"HOTRELOAD_PAUSE:{jname} currently cannot do distributed training" success = False while not success: try: output = func(*args, **kwargs) # success = True - end_action = input(f'{prefix}: PAUSE, you may edit code now. Enter to re-run, ctrl+C to terminate, ' - f'type "done" to continue (function still being watched), or type "disable" to stop pausing this function :') + end_action = input( + f"{prefix}: PAUSE, you may edit code now. Enter to re-run, ctrl+C to terminate, " + f'type "done" to continue (function still being watched), or type "disable" to stop pausing this function :' + ) if end_action.strip().lower() in ["disable", "done"]: success = True else: - logger.warning(f'{prefix}: action={end_action} function will re-run now.') + logger.warning( + f"{prefix}: action={end_action} function will re-run now." + ) except Exception as e: action = input( - f'{prefix}:ERROR: \n{traceback.format_exc()}\n' + f"{prefix}:ERROR: \n{traceback.format_exc()}\n" f'Edit code to try again: enter to continue, ctrl+C to terminate, or type "raise" to raise the exception: ' ) if action.strip().lower() == "raise": @@ -931,13 +938,14 @@ def func_wrapper(*args, **kwargs): if end_action.strip().lower() == "disable": logger.warning( - f'{prefix}: Stop pausing {jname}. The function is still being watched and newly editted code will take effect ' - f'if the {jname} is called again later.' + f"{prefix}: Stop pausing {jname}. The function is still being watched and newly editted code will take effect " + f"if the {jname} is called again later." f' "unset HOTRELOAD_PAUSE" before relaunch to disable hotreload and' - f' remove @hotreload_function decorator in the code.' + f" remove @hotreload_function decorator in the code." ) - hot_reload_state['disable'] = True + hot_reload_state["disable"] = True return output + return func_wrapper - return hotreload_decorator + return hotreload_decorator From 8e804cb38a1575c65a1fc981d75ae5a97c24dd5b Mon Sep 17 00:00:00 2001 From: sravyapopuri388 <51169165+sravyapopuri388@users.noreply.github.com> Date: Thu, 21 Jul 2022 15:04:23 -0700 Subject: [PATCH 663/774] Support direct S2ST models in HF demo (#4593) * OSS ckpts for Interspeech 2022 paper * HF interface update * local test * local test * revert local test * address comments --- fairseq/hub_utils.py | 17 +++++-- .../models/speech_to_text/hub_interface.py | 3 ++ .../models/speech_to_text/xm_transformer.py | 5 ++ fairseq/models/text_to_speech/__init__.py | 1 + .../models/text_to_speech/hub_interface.py | 47 ++++++++++++++++++ fairseq/models/text_to_speech/vocoder.py | 49 +++++++++++++++++-- 6 files changed, 113 insertions(+), 9 deletions(-) diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index b6fa2cb97d..d0f4d03139 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -70,10 +70,19 @@ def from_pretrained( if "user_dir" in kwargs: utils.import_user_module(argparse.Namespace(user_dir=kwargs["user_dir"])) - models, args, task = checkpoint_utils.load_model_ensemble_and_task( - [os.path.join(model_path, cpt) for cpt in checkpoint_file.split(os.pathsep)], - arg_overrides=kwargs, - ) + model_path = [ + os.path.join(model_path, cpt) for cpt in checkpoint_file.split(os.pathsep) + ] + + if "is_vocoder" in kwargs: + args = {"data": kwargs["data"], "model_path": model_path} + task = None + models = None + else: + models, args, task = checkpoint_utils.load_model_ensemble_and_task( + model_path, + arg_overrides=kwargs, + ) return { "args": args, diff --git a/fairseq/models/speech_to_text/hub_interface.py b/fairseq/models/speech_to_text/hub_interface.py index ff6fd638a7..8d6cefbf27 100644 --- a/fairseq/models/speech_to_text/hub_interface.py +++ b/fairseq/models/speech_to_text/hub_interface.py @@ -95,6 +95,9 @@ def get_prediction( prefix = cls.get_prefix_token(task, _tgt_lang) pred_tokens = generator.generate([model], sample, prefix_tokens=prefix) pred = cls.detokenize(task, pred_tokens[0][0]["tokens"]) + eos_token = task.data_cfg.config.get("eos_token", None) + if eos_token: + pred = ' '.join(pred.split(' ')[:-1]) if synthesize_speech: pfx = f"{_tgt_lang}_" if task.data_cfg.prepend_tgt_lang_tag else "" diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index b21ff823cf..ac5ae90c4b 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -487,6 +487,9 @@ def hub_models(cls): "xm_transformer-21_en-xls_r_2b", "xm_transformer-en_15-xls_r_2b", "xm_transformer-22_16-xls_r_2b", + "xm_transformer_s2ut_800m-es-en-st-asr-bt_h1_2022", + "xm_transformer_s2ut_800m-en-es-st_plus_asr", + "xm_transformer_s2ut_es_en_st_asr_test" ] return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} @@ -497,6 +500,7 @@ def from_pretrained( checkpoint_file="model.pt", data_name_or_path=".", config_yaml="config.yaml", + task="speech_to_text", **kwargs, ): from fairseq import hub_utils @@ -507,6 +511,7 @@ def from_pretrained( data_name_or_path, archive_map=cls.hub_models(), config_yaml=config_yaml, + task=task, **kwargs, ) return S2THubInterface(x["args"], x["task"], x["models"][0]) diff --git a/fairseq/models/text_to_speech/__init__.py b/fairseq/models/text_to_speech/__init__.py index 652fee0d68..c0dcd69b07 100644 --- a/fairseq/models/text_to_speech/__init__.py +++ b/fairseq/models/text_to_speech/__init__.py @@ -6,3 +6,4 @@ from .tacotron2 import * # noqa from .tts_transformer import * # noqa from .fastspeech2 import * # noqa +from .vocoder import * # noqa diff --git a/fairseq/models/text_to_speech/hub_interface.py b/fairseq/models/text_to_speech/hub_interface.py index 26c7ccaca2..a72b59d6c8 100644 --- a/fairseq/models/text_to_speech/hub_interface.py +++ b/fairseq/models/text_to_speech/hub_interface.py @@ -137,3 +137,50 @@ def predict( ) -> Tuple[torch.Tensor, int]: sample = self.get_model_input(self.task, text, speaker, verbose=verbose) return self.get_prediction(self.task, self.model, self.generator, sample) + + +class VocoderHubInterface(nn.Module): + """Vocoder interface to run vocoder models through hub. Currently we only support unit vocoder""" + def __init__(self, cfg, model): + super().__init__() + self.vocoder = model + self.vocoder.eval() + self.sr = 16000 + self.multispkr = self.vocoder.model.multispkr + if self.multispkr: + logger.info("multi-speaker vocoder") + self.num_speakers = cfg.get( + "num_speakers", + 200, + ) # following the default in codehifigan to set to 200 + + def get_model_inout( + self, + text: str, + speaker: Optional[int] = -1, + ): + units = list(map(int, text.strip().split())) + x = { + "code": torch.LongTensor(units).view(1, -1), + } + + if self.multispkr: + assert ( + speaker < self.num_speakers + ), f"invalid --speaker-id ({speaker}) with total #speakers = {self.num_speakers}" + spk = random.randint(0, self.num_speakers - 1) if speaker == -1 else speaker + x["spkr"] = torch.LongTensor([spk]).view(1, 1) + return x + + def get_prediction(self, sample, dur_prediction: Optional[bool] = True): + wav = self.vocoder(sample, dur_prediction) + return wav, self.sr + + def predict( + self, + text: str, + speaker: Optional[int] = None, + dur_prediction: Optional[bool] = True, + ): + sample = self.get_model_inout(text, speaker) + return self.get_prediction(sample, dur_prediction) diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index c3d7134544..6d70879a0c 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -11,7 +11,8 @@ import torch from torch import nn import torch.nn.functional as F - +from fairseq.models import BaseFairseqModel, register_model +from fairseq.models.text_to_speech.hub_interface import VocoderHubInterface from fairseq.data.audio.audio_utils import ( get_window, get_fourier_basis, @@ -83,7 +84,7 @@ def get_window_sum_square( x = torch.zeros(n, dtype=torch.float32) for i in range(n_frames): ofst = i * hop_length - x[ofst : min(n, ofst + n_fft)] += w_sq[: max(0, min(n_fft, n - ofst))] + x[ofst: min(n, ofst + n_fft)] += w_sq[: max(0, min(n_fft, n - ofst))] return x def inverse(self, magnitude: torch.Tensor, phase) -> torch.Tensor: @@ -101,8 +102,8 @@ def inverse(self, magnitude: torch.Tensor, phase) -> torch.Tensor: approx_nonzero_indices = win_sum_sq > self.tiny x[:, :, approx_nonzero_indices] /= win_sum_sq[approx_nonzero_indices] x *= self.n_fft / self.hop_length - x = x[:, :, self.n_fft // 2 :] - x = x[:, :, : -self.n_fft // 2 :] + x = x[:, :, self.n_fft // 2:] + x = x[:, :, : -self.n_fft // 2:] return x def forward(self, specgram: torch.Tensor) -> torch.Tensor: @@ -211,7 +212,8 @@ def from_data_cfg(cls, args, data_cfg: S2TDataConfig): return cls(vocoder_cfg["checkpoint"], model_cfg, fp16=args.fp16) -class CodeHiFiGANVocoder(nn.Module): +@register_model("CodeHiFiGANVocoder") +class CodeHiFiGANVocoder(BaseFairseqModel): def __init__( self, checkpoint_path: str, model_cfg: Dict[str, str], fp16: bool = False ) -> None: @@ -247,6 +249,43 @@ def from_data_cfg(cls, args, data_cfg): model_cfg = json.load(f) return cls(vocoder_cfg["checkpoint"], model_cfg, fp16=args.fp16) + @classmethod + def hub_models(cls): + base_url = "http://dl.fbaipublicfiles.com/fairseq/vocoder" + model_ids = ["unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_lj_dur", + "unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_es_css10_dur"] + return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} + + @classmethod + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + config="config.json", + fp16: bool = False, + **kwargs, + ): + from fairseq import hub_utils + + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + config_yaml=config, + fp16=fp16, + is_vocoder=True, + **kwargs, + ) + + with open(f"{x['args']['data']}/{config}") as f: + vocoder_cfg = json.load(f) + assert len(x["args"]["model_path"]) == 1, "Too many vocoder models in the input" + + vocoder = CodeHiFiGANVocoder(x["args"]["model_path"][0], vocoder_cfg) + return VocoderHubInterface(vocoder_cfg, vocoder) + def get_vocoder(args, data_cfg: S2TDataConfig): if args.vocoder == "griffin_lim": From a546702008f65deb5f26b0bb92410d679cd0e25d Mon Sep 17 00:00:00 2001 From: Rastislav Rabatin <rastislav.rabatin@gmail.com> Date: Tue, 26 Jul 2022 16:51:27 +0100 Subject: [PATCH 664/774] Merge source and target embedding tables into one table (#4594) Add support for merging source and target embedding table into one table. This feature might hurt performance, but it will decrease the size of the final model. --- fairseq/models/transformer/transformer_base.py | 17 +++++++++++++++++ .../models/transformer/transformer_config.py | 8 ++++++++ .../models/transformer/transformer_legacy.py | 2 ++ 3 files changed, 27 insertions(+) diff --git a/fairseq/models/transformer/transformer_base.py b/fairseq/models/transformer/transformer_base.py index 5e025c9058..f9f097f04b 100644 --- a/fairseq/models/transformer/transformer_base.py +++ b/fairseq/models/transformer/transformer_base.py @@ -9,6 +9,8 @@ import torch.nn as nn from torch import Tensor +import logging + from fairseq import utils from fairseq.dataclass.utils import gen_parser_from_dataclass from fairseq.distributed import fsdp_wrap @@ -20,6 +22,9 @@ ) +logger = logging.getLogger(__name__) + + class TransformerModelBase(FairseqEncoderDecoderModel): """ Transformer model from `"Attention Is All You Need" (Vaswani, et al, 2017) @@ -85,6 +90,18 @@ def build_model(cls, cfg, task): ) decoder_embed_tokens = encoder_embed_tokens cfg.share_decoder_input_output_embed = True + elif cfg.merge_src_tgt_embed: + logger.info(f"source dict size: {len(src_dict)}") + logger.info(f"target dict size: {len(tgt_dict)}") + src_dict.update(tgt_dict) + task.src_dict = src_dict + task.tgt_dict = src_dict + logger.info(f"merged dict size: {len(src_dict)}") + encoder_embed_tokens = cls.build_embedding( + cfg, src_dict, cfg.encoder.embed_dim + ) + decoder_embed_tokens = encoder_embed_tokens + cfg.share_decoder_input_output_embed = True else: encoder_embed_tokens = cls.build_embedding( cfg, src_dict, cfg.encoder.embed_dim, cfg.encoder.embed_path diff --git a/fairseq/models/transformer/transformer_config.py b/fairseq/models/transformer/transformer_config.py index 119b030b04..9c8f330f74 100644 --- a/fairseq/models/transformer/transformer_config.py +++ b/fairseq/models/transformer/transformer_config.py @@ -132,6 +132,14 @@ class TransformerConfig(FairseqDataclass): "help": "share encoder, decoder and output embeddings (requires shared dictionary and embed dim)" }, ) + merge_src_tgt_embed: bool = field( + default=False, + metadata={ + "help": "if true then the source and target embedding table is " + "merged into one table. This is going to make the model smaller but " + "it might hurt performance." + } + ) no_token_positional_embeddings: bool = field( default=False, metadata={ diff --git a/fairseq/models/transformer/transformer_legacy.py b/fairseq/models/transformer/transformer_legacy.py index af9646740a..00d14a7dde 100644 --- a/fairseq/models/transformer/transformer_legacy.py +++ b/fairseq/models/transformer/transformer_legacy.py @@ -174,6 +174,7 @@ def base_architecture(args): args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 8) args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) args.encoder_learned_pos = getattr(args, "encoder_learned_pos", False) + args.decoder_embed_path = getattr(args, "decoder_embed_path", None) args.decoder_embed_dim = getattr(args, "decoder_embed_dim", args.encoder_embed_dim) args.decoder_ffn_embed_dim = getattr( @@ -193,6 +194,7 @@ def base_architecture(args): args, "share_decoder_input_output_embed", False ) args.share_all_embeddings = getattr(args, "share_all_embeddings", False) + args.merge_src_tgt_embed = getattr(args, "merge_src_tgt_embed", False) args.no_token_positional_embeddings = getattr( args, "no_token_positional_embeddings", False ) From ad3bec5a07962a994ac25ad1609ab926b13e0c0f Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Tue, 26 Jul 2022 17:25:47 -0400 Subject: [PATCH 665/774] Fix Linting Errors (#4611) * Update version.txt * Update create_dict_stop.sh * Update enhanced_direct_s2st_discrete_units.md * Update hubert_asr.py * Update utils.py --- examples/audio_nlp/nlu/create_dict_stop.sh | 14 +++++++------- .../docs/enhanced_direct_s2st_discrete_units.md | 10 +++++----- fairseq/models/hubert/hubert_asr.py | 1 - fairseq/utils.py | 2 +- fairseq/version.txt | 2 +- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/examples/audio_nlp/nlu/create_dict_stop.sh b/examples/audio_nlp/nlu/create_dict_stop.sh index c782035343..753393284d 100755 --- a/examples/audio_nlp/nlu/create_dict_stop.sh +++ b/examples/audio_nlp/nlu/create_dict_stop.sh @@ -20,19 +20,19 @@ dest_dir="$data_root/" PYTHONPATH=$fairseq_root \ python $fairseq_root/fairseq_cli/preprocess.py \ --source-lang "parse" \ - --trainpref $train_prefix \ - --validpref $valid_prefix \ - --destdir $dest_dir \ + --trainpref "$train_prefix" \ + --validpref "$valid_prefix" \ + --destdir "$dest_dir" \ --only-source \ --dict-only \ --workers 60; PYTHONPATH=$fairseq_root \ python $fairseq_root/fairseq_cli/preprocess.py \ - --source-lang "ltr" \ - --trainpref $train_prefix \ - --validpref $valid_prefix \ - --destdir $dest_dir \ + --source-lang "ltr" \ + --trainpref "$train_prefix" \ + --validpref "$valid_prefix" \ + --destdir "$dest_dir" \ --only-source \ --dict-only \ --workers 60; diff --git a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md index 97c47795ba..fbfa5dd16a 100644 --- a/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md +++ b/examples/speech_to_speech/docs/enhanced_direct_s2st_discrete_units.md @@ -113,12 +113,12 @@ To evaluate speech translation output, we first apply ASR on the speech output a ID | En - Es | Es - En | | --- | --- | --- | **S2UT systems without pre-training** -S2UT with multitask | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//S2UT_w_multitask.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//S2UT_w_multitask.pt) | +S2UT with multitask | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//S2UT_w_multitask.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//S2UT_w_multitask.pt) | **S2UT systems with model pre-training** -w2v2-L | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_only.pt ) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_only.pt) | -w2v2-L + mBART (LNA-E) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LNE.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LNE.pt) | -w2v2-L + mBART (LNA-D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LND.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LND.pt) | -w2v2-L + mBART (LNA-E,D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LNED.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LNED.pt) | +w2v2-L | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_only.pt ) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_only.pt) | +w2v2-L + mBART (LNA-E) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LNE.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LNE.pt) | +w2v2-L + mBART (LNA-D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LND.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LND.pt) | +w2v2-L + mBART (LNA-E,D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LNED.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LNED.pt) | **S2UT systems with model pre-training and data augmentation** w2v2-L + mBART (LNA-D) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/en_es//w2v2_mbart_LND_w_ASR.pt) | [checkpoint](https://dl.fbaipublicfiles.com/fairseq/speech_to_speech/s2st_finetuning/es_en//w2v2_mbart_LND_w_ASR.pt) | diff --git a/fairseq/models/hubert/hubert_asr.py b/fairseq/models/hubert/hubert_asr.py index 05ddedc74b..11c85ce7d1 100644 --- a/fairseq/models/hubert/hubert_asr.py +++ b/fairseq/models/hubert/hubert_asr.py @@ -3,7 +3,6 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from typing import Any import contextlib import copy import logging diff --git a/fairseq/utils.py b/fairseq/utils.py index 3669594fdd..e6196863fa 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -892,7 +892,7 @@ def train_step(self, sample ....): try: import jurigged except ImportError as e: - logger.warning(f"Please install jurigged: pip install jurigged[develoop]") + logger.warning("Please install jurigged: pip install jurigged[develoop]") raise e from fairseq.distributed import utils as distributed_utils import traceback diff --git a/fairseq/version.txt b/fairseq/version.txt index e96a87111c..26acbf080b 100644 --- a/fairseq/version.txt +++ b/fairseq/version.txt @@ -1 +1 @@ -0.12.2 \ No newline at end of file +0.12.2 From 0c5731f92194a204427515e70854813b14701ed2 Mon Sep 17 00:00:00 2001 From: sravyapopuri388 <51169165+sravyapopuri388@users.noreply.github.com> Date: Wed, 27 Jul 2022 19:16:04 -0700 Subject: [PATCH 666/774] Support En->Hk model in fairseq hub. (#4614) * OSS ckpts for Interspeech 2022 paper * HF interface update * local test * local test * revert local test * address comments * add Hk<>En models * add Hk<>En models * add Hk<>En models * add hk->en * add hk->en * add hk->en * add hk->en * add hk->en --- .../models/speech_to_text/hub_interface.py | 3 ++- .../models/speech_to_text/xm_transformer.py | 27 ++++++++++++------- .../models/text_to_speech/hub_interface.py | 8 +++--- fairseq/models/text_to_speech/vocoder.py | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/fairseq/models/speech_to_text/hub_interface.py b/fairseq/models/speech_to_text/hub_interface.py index 8d6cefbf27..173bb73064 100644 --- a/fairseq/models/speech_to_text/hub_interface.py +++ b/fairseq/models/speech_to_text/hub_interface.py @@ -102,12 +102,13 @@ def get_prediction( if synthesize_speech: pfx = f"{_tgt_lang}_" if task.data_cfg.prepend_tgt_lang_tag else "" tts_model_id = task.data_cfg.hub.get(f"{pfx}tts_model_id", None) + speaker = task.data_cfg.hub.get(f"{pfx}speaker", None) if tts_model_id is None: logger.warning("TTS model configuration not found") else: _repo, _id = tts_model_id.split(":") tts_model = torch.hub.load(_repo, _id, verbose=False) - pred = (pred, tts_model.predict(pred)) + pred = (pred, tts_model.predict(pred, speaker=speaker)) return pred def predict( diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index ac5ae90c4b..e3deebe8bf 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -244,6 +244,9 @@ def add_wav2vec_asr_args(parser): action="store_true", help="if set, then the weight-norm (in one pos_conv layer) is removed from the model", ) + parser.add_argument( + "--encoder-embed-dim", type=int, metavar="N", help="encoder embedding dimension to be used when w2v_path is None and no encoder_proj is set" + ) def need_finetuning(ft_params, param_name): @@ -489,7 +492,9 @@ def hub_models(cls): "xm_transformer-22_16-xls_r_2b", "xm_transformer_s2ut_800m-es-en-st-asr-bt_h1_2022", "xm_transformer_s2ut_800m-en-es-st_plus_asr", - "xm_transformer_s2ut_es_en_st_asr_test" + "xm_transformer_s2ut_800m-hk-en-h1_2022", + "xm_transformer_s2ut_800m-en-hk-h1_2022" + ] return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} @@ -544,15 +549,18 @@ def maybe_load_pretrained(cls, component, checkpoint: Optional[str] = None): def build_encoder(cls, args): _args = copy.deepcopy(args) if not args.adaptor_proj and not args.encoder_proj: # V0 arch - state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) - if state.get("cfg") is not None: - encoder_embed_dim = state["cfg"]._content["model"]["encoder_embed_dim"] - elif state.get("args") is not None: - encoder_embed_dim = state["args"].encoder_embed_dim + if args.w2v_path: + state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) + if state.get("cfg") is not None: + encoder_embed_dim = state["cfg"]._content["model"]["encoder_embed_dim"] + elif state.get("args") is not None: + encoder_embed_dim = state["args"].encoder_embed_dim + else: + raise ValueError(f"Invalid config in {args.w2v_path}") + _args.decoder_embed_dim = encoder_embed_dim + del state else: - raise ValueError(f"Invalid config in {args.w2v_path}") - _args.decoder_embed_dim = encoder_embed_dim - del state + _args.decoder_embed_dim = args.encoder_embed_dim encoder = Wav2VecEncoderWithAdaptor(_args) encoder = cls.maybe_load_pretrained( @@ -688,6 +696,7 @@ def set_default_w2v_encoder_args(args): args.normalize = getattr(args, "normalize", False) args.finetune_w2v_params = getattr(args, "finetune_w2v_params", "all") args.w2v_freezing_updates = getattr(args, "w2v_freezing_updates", None) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) def set_default_adaptor_args(args): diff --git a/fairseq/models/text_to_speech/hub_interface.py b/fairseq/models/text_to_speech/hub_interface.py index a72b59d6c8..e251c65c1d 100644 --- a/fairseq/models/text_to_speech/hub_interface.py +++ b/fairseq/models/text_to_speech/hub_interface.py @@ -141,6 +141,7 @@ def predict( class VocoderHubInterface(nn.Module): """Vocoder interface to run vocoder models through hub. Currently we only support unit vocoder""" + def __init__(self, cfg, model): super().__init__() self.vocoder = model @@ -154,7 +155,7 @@ def __init__(self, cfg, model): 200, ) # following the default in codehifigan to set to 200 - def get_model_inout( + def get_model_input( self, text: str, speaker: Optional[int] = -1, @@ -163,7 +164,8 @@ def get_model_inout( x = { "code": torch.LongTensor(units).view(1, -1), } - + if not speaker: + speaker = -1 if self.multispkr: assert ( speaker < self.num_speakers @@ -182,5 +184,5 @@ def predict( speaker: Optional[int] = None, dur_prediction: Optional[bool] = True, ): - sample = self.get_model_inout(text, speaker) + sample = self.get_model_input(text, speaker) return self.get_prediction(sample, dur_prediction) diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index 6d70879a0c..0088daadcb 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -253,7 +253,7 @@ def from_data_cfg(cls, args, data_cfg): def hub_models(cls): base_url = "http://dl.fbaipublicfiles.com/fairseq/vocoder" model_ids = ["unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_lj_dur", - "unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_es_css10_dur"] + "unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_es_css10_dur", "unit_hifigan_HK_layer12.km2500_frame_TAT-TTS"] return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} @classmethod From 4fe8583396191c22011350248119db98ec1b5cb8 Mon Sep 17 00:00:00 2001 From: Ilia Kulikov <kulikov@cs.nyu.edu> Date: Fri, 29 Jul 2022 09:59:52 -0700 Subject: [PATCH 667/774] padding fix in the adaptor layer (#4613) --- fairseq/models/speech_to_text/xm_transformer.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index e3deebe8bf..e67b7c6715 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -86,6 +86,9 @@ def forward(self, x, padding_mask: Optional[torch.Tensor]): x = x + 0.5 * self.proj(x) x = self.proj_ln(x) + if padding_mask is not None: + x = utils.index_put(x, padding_mask.T, 0) + # T x B x C -> B x C x T x = x.transpose(0, 1).transpose(1, 2) out_lens = None @@ -108,6 +111,7 @@ def forward(self, x, padding_mask: Optional[torch.Tensor]): out_padding_mask = None if padding_mask is not None: out_padding_mask = lengths_to_padding_mask(out_lens.long()) + x = utils.index_put(x, out_padding_mask.T, 0) return x, out_padding_mask From 42360dbc065ff8ef13959f5e79a927368fc320fc Mon Sep 17 00:00:00 2001 From: Sanchit Gandhi <93869735+sanchit-gandhi@users.noreply.github.com> Date: Mon, 1 Aug 2022 18:08:28 +0100 Subject: [PATCH 668/774] Fix uninitialized bias parameters in RelPositionMultiHeadedAttention (#4623) --- fairseq/modules/espnet_multihead_attention.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fairseq/modules/espnet_multihead_attention.py b/fairseq/modules/espnet_multihead_attention.py index d319a168f4..f25acc3b66 100644 --- a/fairseq/modules/espnet_multihead_attention.py +++ b/fairseq/modules/espnet_multihead_attention.py @@ -124,8 +124,8 @@ def __init__(self, n_feat, n_head, dropout, zero_triu=False): self.linear_pos = nn.Linear(n_feat, n_feat, bias=False) # these two learnable bias are used in matrix c and matrix d # as described in https://arxiv.org/abs/1901.02860 Section 3.3 - self.pos_bias_u = nn.Parameter(torch.Tensor(self.h, self.d_k)) - self.pos_bias_v = nn.Parameter(torch.Tensor(self.h, self.d_k)) + self.pos_bias_u = nn.Parameter(torch.zeros(self.h, self.d_k)) + self.pos_bias_v = nn.Parameter(torch.zeros(self.h, self.d_k)) torch.nn.init.xavier_uniform_(self.pos_bias_u) torch.nn.init.xavier_uniform_(self.pos_bias_v) From acd9a53607d1e5c64604e88fc9601d0ee56fd6f1 Mon Sep 17 00:00:00 2001 From: Wei <wwei6@fb.com> Date: Mon, 1 Aug 2022 14:26:36 -0700 Subject: [PATCH 669/774] update isort (#4568) Co-authored-by: dianaml0 <82468439+dianaml0@users.noreply.github.com> --- .../models/transformer/transformer_encoder.py | 81 +--- fairseq/modules/transformer_layer.py | 218 ++-------- scripts/better_transformer.py | 380 ------------------ tests/test_export.py | 32 +- tests/test_sequence_generator.py | 31 +- 5 files changed, 38 insertions(+), 704 deletions(-) delete mode 100644 scripts/better_transformer.py diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index c887c5afe2..a5fbc6991d 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -219,79 +219,11 @@ def forward_scriptable( if return_all_hiddens: encoder_states.append(x) - # nested tensor and BT enable - layer = self.layers[0] - BT_flag = False - NT_flag = False - # torch version check, BT>=1.12.0 and NT>=1.13.0.dev20220613 - # internal format is '1.13.0a0+fb' - # external format is '1.13.0.dev20220613'(cpu&gpu) for nightly or "1.11.0"(cpu) or '1.11.0+cu102'(gpu) for stable - BT_version = False - NT_version = False - if "fb" in torch.__version__: - BT_version = True - NT_version = True - else: - if "+" in torch.__version__: - torch_version = torch.__version__.split("+")[0] - else: - torch_version = torch.__version__ - - torch_version = torch_version.split(".") - int_version = ( - int(torch_version[0]) * 1000 - + int(torch_version[1]) * 10 - + int(torch_version[2]) - ) - if len(torch_version) == 3: - if int_version >= 1120: - BT_version = True - if int_version >= 1131: - NT_version = True - elif len(torch_version) == 4: - if int_version >= 1130: - BT_version = True - # Consider _nested_tensor_from_mask_left_aligned is landed after "20220613" - if int_version >= 1131 or ( - int_version == 1130 and torch_version[3][3:] >= "20220613" - ): - NT_version = True - - if ( - BT_version - and x.dim() == 3 - and layer.load_to_BT - and not layer.return_fc - and layer.can_use_fastpath - and not layer.training - and not layer.ever_training - and not layer.cfg_checkpoint_activations - ): - # Batch first can not be justified but needs user to make sure - x = x.transpose(0, 1) - # Check mask conditions for nested tensor - if NT_version: - if ( - encoder_padding_mask is not None - and torch._nested_tensor_from_mask_left_aligned( - x, encoder_padding_mask.logical_not() - ) - ): - if not torch.is_grad_enabled() or not x.requires_grad: - x = torch._nested_tensor_from_mask( - x, encoder_padding_mask.logical_not() - ) - NT_flag = True - BT_flag = True - # encoder layers - if NT_flag: - processing_mask = None - else: - processing_mask = encoder_padding_mask - encoder_padding_mask_out = processing_mask if has_pads else None for layer in self.layers: - lr = layer(x, encoder_padding_mask=encoder_padding_mask_out) + lr = layer( + x, encoder_padding_mask=encoder_padding_mask if has_pads else None + ) if isinstance(lr, tuple) and len(lr) == 2: x, fc_result = lr @@ -304,13 +236,6 @@ def forward_scriptable( encoder_states.append(x) fc_results.append(fc_result) - # change back to non-nested and Batch second - if NT_flag: - x = x.to_padded_tensor(0.0) - - if NT_flag or BT_flag: - x = x.transpose(0, 1) - if self.layer_norm is not None: x = self.layer_norm(x) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 1b6b713025..4a283762b8 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -17,7 +17,6 @@ class TransformerEncoderLayerBase(nn.Module): - """Encoder layer block. In the original paper each operation (multi-head attention or FFN) is @@ -68,120 +67,6 @@ def __init__(self, cfg, return_fc=False): self.final_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) - self.num_heads = cfg.encoder.attention_heads - self.load_to_BT = False - self.ever_training = False - # For BT, we need continuous mem - self.in_proj_weight = torch.nn.Parameter( - torch.zeros( - self.self_attn.q_proj.weight.shape[0] * 3, - self.self_attn.q_proj.weight.shape[1], - ) - ) - self.in_proj_bias = torch.nn.Parameter( - torch.zeros(self.self_attn.q_proj.bias.shape[0] * 3) - ) - self.out_proj_weight = torch.nn.Parameter( - torch.zeros(self.self_attn.out_proj.weight.shape) - ) - self.out_proj_bias = torch.nn.Parameter( - torch.zeros(self.self_attn.out_proj.bias.shape) - ) - self.fc1_weight = torch.nn.Parameter(torch.zeros(self.fc1.weight.shape)) - self.fc1_bias = torch.nn.Parameter(torch.zeros(self.fc1.bias.shape)) - self.fc2_weight = torch.nn.Parameter(torch.zeros(self.fc2.weight.shape)) - self.fc2_bias = torch.nn.Parameter(torch.zeros(self.fc2.bias.shape)) - - if ( - self.activation_fn is torch.nn.functional.relu - or isinstance(self.activation_fn, torch.nn.ReLU) - or self.activation_fn == "relu" - ): - self.activation_relu_or_gelu = 1 - elif ( - self.activation_fn is torch.nn.functional.gelu - or isinstance(self.activation_fn, torch.nn.GELU) - or self.activation_fn == "gelu" - ): - self.activation_relu_or_gelu = 2 - else: - self.activation_relu_or_gelu = 0 - # Batch first can not be justified but needs user to make sure - self.can_use_fastpath = ( - not self.normalize_before - and self.activation_relu_or_gelu - and (self.self_attn_layer_norm.eps == self.final_layer_norm.eps) - ) - self.cfg_checkpoint_activations = self.cfg.checkpoint_activations - # torch version check - # make sure BT version is >=1.12.0 - self.BT_version = False - if "fb" in torch.__version__: - self.BT_version = True - else: - if "+" in torch.__version__: - self.torch_version = torch.__version__.split("+")[0] - else: - self.torch_version = torch.__version__ - - self.torch_version = self.torch_version.split(".") - self.int_version = ( - int(self.torch_version[0]) * 1000 - + int(self.torch_version[1]) * 10 - + int(self.torch_version[2]) - ) - if len(self.torch_version) == 3: - if self.int_version >= 1120: - self.BT_version = True - elif len(self.torch_version) == 4: - if self.int_version >= 1130: - self.BT_version = True - - def _load_from_state_dict( - self, - state_dict, - prefix, - local_metadata, - strict, - missing_keys, - unexpected_keys, - error_msgs, - ): - self.load_to_BT = True - - old_name = prefix + "self_attn." - q_proj_weight = state_dict[old_name + "q_proj.weight"] - k_proj_weight = state_dict[old_name + "k_proj.weight"] - v_proj_weight = state_dict[old_name + "v_proj.weight"] - q_proj_bias = state_dict[old_name + "q_proj.bias"] - k_proj_bias = state_dict[old_name + "k_proj.bias"] - v_proj_bias = state_dict[old_name + "v_proj.bias"] - - new_name = prefix - state_dict[new_name + "in_proj_weight"] = torch.cat( - (q_proj_weight, k_proj_weight, v_proj_weight), dim=0 - ) - state_dict[new_name + "in_proj_bias"] = torch.cat( - (q_proj_bias, k_proj_bias, v_proj_bias), dim=0 - ) - state_dict[new_name + "out_proj_weight"] = state_dict[ - old_name + "out_proj.weight" - ] - state_dict[new_name + "out_proj_bias"] = state_dict[old_name + "out_proj.bias"] - state_dict[new_name + "fc1_weight"] = state_dict[prefix + "fc1.weight"] - state_dict[new_name + "fc1_bias"] = state_dict[prefix + "fc1.bias"] - state_dict[new_name + "fc2_weight"] = state_dict[prefix + "fc2.weight"] - state_dict[new_name + "fc2_bias"] = state_dict[prefix + "fc2.bias"] - super(TransformerEncoderLayerBase, self)._load_from_state_dict( - state_dict, - prefix, - local_metadata, - strict, - missing_keys, - unexpected_keys, - error_msgs, - ) - def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): return quant_noise( nn.Linear(input_dim, output_dim), p=q_noise, block_size=qn_block_size @@ -301,83 +186,44 @@ def forward( # Note that we cannot use -inf here, because at some edge cases, # the attention weight (before softmax) for some padded element in query # will become -inf, which results in NaN in model parameters - - if self.training: - self.ever_training = True - - if ( - self.BT_version - and x.dim() == 3 - and self.load_to_BT - and not self.return_fc - and self.can_use_fastpath - and not self.training - and not self.ever_training - and not self.cfg_checkpoint_activations - ): - # assume is Batch first and nested tensor - output = torch._transformer_encoder_layer_fwd( - x, - self.embed_dim, - self.num_heads, - self.in_proj_weight, - self.in_proj_bias, - self.out_proj_weight, - self.out_proj_bias, - self.activation_relu_or_gelu == 2, - False, # norm_first, currently not supported - self.self_attn_layer_norm.eps, - self.self_attn_layer_norm.weight, - self.self_attn_layer_norm.bias, - self.final_layer_norm.weight, - self.final_layer_norm.bias, - self.fc1_weight, - self.fc1_bias, - self.fc2_weight, - self.fc2_bias, - encoder_padding_mask if encoder_padding_mask is not None else attn_mask, + if attn_mask is not None: + attn_mask = attn_mask.masked_fill( + attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 ) - return output - else: - if attn_mask is not None: - attn_mask = attn_mask.masked_fill( - attn_mask.to(torch.bool), -1e8 if x.dtype == torch.float32 else -1e4 - ) - - residual = x - if self.normalize_before: - x = self.self_attn_layer_norm(x) - x, _ = self.self_attn( - query=x, - key=x, - value=x, - key_padding_mask=encoder_padding_mask, - need_weights=False, - attn_mask=attn_mask, - ) - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.self_attn_layer_norm(x) + residual = x + if self.normalize_before: + x = self.self_attn_layer_norm(x) + x, _ = self.self_attn( + query=x, + key=x, + value=x, + key_padding_mask=encoder_padding_mask, + need_weights=False, + attn_mask=attn_mask, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) - residual = x - if self.normalize_before: - x = self.final_layer_norm(x) - x = self.activation_fn(self.fc1(x)) - x = self.activation_dropout_module(x) - x = self.fc2(x) + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) - fc_result = x + fc_result = x - x = self.dropout_module(x) - x = self.residual_connection(x, residual) - if not self.normalize_before: - x = self.final_layer_norm(x) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) - if self.return_fc and not torch.jit.is_scripting(): - return x, fc_result - return x + if self.return_fc and not torch.jit.is_scripting(): + return x, fc_result + return x # backward compatible with the legacy argparse format diff --git a/scripts/better_transformer.py b/scripts/better_transformer.py deleted file mode 100644 index 2bbf64c3c6..0000000000 --- a/scripts/better_transformer.py +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright (c) Facebook, Inc. and its affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. -import sys - -import click -import numpy as np -import torch -from fvcore.nn import FlopCountAnalysis - -from fairseq.models.transformer import TransformerConfig as FairseqTransformerConfig -from fairseq.models.transformer import TransformerEncoder as FairseqTransformerEncoder - -seed = 0 -torch.manual_seed(seed) -np.random.seed(seed) - - -def benchmark_torch_function(iters, f, *args, **kwargs): - f(*args, **kwargs) - torch.cuda.synchronize() - start_event = torch.cuda.Event(enable_timing=True) - end_event = torch.cuda.Event(enable_timing=True) - start_event.record() - for _ in range(iters): - f(*args, **kwargs) - end_event.record() - torch.cuda.synchronize() - return (start_event.elapsed_time(end_event) * 1.0e-3) / iters - - -def numerical_test(lengths, truth_tensors, test_list): - """ - truth_tensors is the source of truth. - test_dict looks like - [ - (name, out_tensors, atol, rtol), - ... - ] - """ - for name, out_tensors, rtol, atol in test_list: - n_failures = 0 - max_diff = 0 - for (length, truth, out) in zip(lengths, truth_tensors, out_tensors): - cut_truth = truth[:length] - cut_out = out[:length] - max_diff = max(max_diff, torch.max(torch.abs(cut_truth - cut_out))) - if not torch.allclose(cut_truth, cut_out, atol=atol, rtol=rtol): - n_failures += 1 - - if n_failures == 0: - print(f"{name} PASS") - else: - print(f"{name} FAIL {n_failures}/{len(lengths)}. Max diff is {max_diff}") - - -@click.group() -def cli(): - pass - - -@cli.command() -@click.option("--save", is_flag=True, default=False) -@click.option("--load", is_flag=True, default=False) -@click.option("--half", is_flag=True, default=False) -@click.option("--bt2fairseq", is_flag=True, default=False) -def transformer( - save, - load, - half, - bt2fairseq, -): - xlarge = False - large = False - DEFAULT_PADDING_IDX = 1 - avg_sequence_length = 128 - max_sequence_length = 256 - batch_size = 64 - - class FairseqEncoder(torch.nn.Module): - def __init__( - self, - embed_dim, - attention_heads, - ffn_embed_dim, - num_layers, - embedding_layer, # torch.nn.Embedding. Must have a padding_idx field - dropout=0, - normalize_before=False, - torch_encoder=None, # torch encoder that you can map weights from - activation="relu", - ): - super().__init__() - - cfg = FairseqTransformerConfig() - cfg.encoder.embed_dim = embed_dim - cfg.encoder.attention_heads = attention_heads - cfg.encoder.ffn_embed_dim = ffn_embed_dim - cfg.dropout = dropout - cfg.encoder.normalize_before = normalize_before - cfg.encoder.layers = num_layers - # make embedding behavior same as other encoders - cfg.no_token_positional_embeddings = True - cfg.no_scale_embedding = True - cfg.activation_fn = activation - dictionary = {} # TODO: verify what this is - - self.encoder = FairseqTransformerEncoder( - cfg, dictionary, embedding_layer, return_fc=False - ) - - if torch_encoder is not None: - for src_layer, dst_layer in zip( - torch_encoder.layers, self.encoder.layers - ): - w_q, w_k, w_v = src_layer.self_attn.in_proj_weight.chunk(3, dim=0) - b_q, b_k, b_v = src_layer.self_attn.in_proj_bias.chunk(3, dim=0) - - dst_layer.self_attn.q_proj.weight = torch.nn.Parameter(w_q) - dst_layer.self_attn.q_proj.bias = torch.nn.Parameter(b_q) - dst_layer.self_attn.k_proj.weight = torch.nn.Parameter(w_k) - dst_layer.self_attn.k_proj.bias = torch.nn.Parameter(b_k) - dst_layer.self_attn.v_proj.weight = torch.nn.Parameter(w_v) - dst_layer.self_attn.v_proj.bias = torch.nn.Parameter(b_v) - - dst_layer.self_attn.out_proj.weight = ( - src_layer.self_attn.out_proj.weight - ) - dst_layer.self_attn.out_proj.bias = ( - src_layer.self_attn.out_proj.bias - ) - - dst_layer.fc1.weight = src_layer.linear1.weight - dst_layer.fc1.bias = src_layer.linear1.bias - - # fairseq may use fusedlayernorm from nvidia apex - diff properties - dst_layer.self_attn_layer_norm.load_state_dict( - src_layer.norm1.state_dict() - ) - - dst_layer.fc2.weight = src_layer.linear2.weight - dst_layer.fc2.bias = src_layer.linear2.bias - - dst_layer.final_layer_norm.load_state_dict( - src_layer.norm2.state_dict() - ) - - # self.encoder = self.encoder.eval().cuda().half() - - def forward(self, tokens, src_lengths=None): - return self.encoder( - tokens, - src_lengths=src_lengths, - return_all_hiddens=False, - token_embeddings=None, - ) - - def get_layers_embedding_dim_num_heads_for_configuration(xlarge, large): - if xlarge: - # XLM-R extra large (no BERT-XL exists) - L = 24 # Layers - D = 2560 # Embedding Dim - H = 32 # Number of Heads - FD = 10240 # Feed-forward network dim - V = 30000 # Vocab Size - elif large: - # BERT-large - L = 24 - D = 1024 - H = 16 - FD = 4096 - V = 30000 - else: - # BERT-base - L = 12 - D = 768 - H = 12 - FD = 3072 - V = 30000 - - return (L, D, H, FD, V) - - # Better transformer - class PTTransformer(torch.nn.Module): - def __init__(self, transformer, embedding): - super().__init__() - self.transformer = transformer - self.embedding = embedding - self.padding_idx = DEFAULT_PADDING_IDX - - def forward(self, x): - padding_mask = None - if not x.is_nested: - padding_mask = x.eq(self.padding_idx) - x = self.embedding(x) - return self.transformer(x, src_key_padding_mask=padding_mask) - - def make_transformer(): - return ( - PTTransformer( - torch.nn.TransformerEncoder( - torch.nn.TransformerEncoderLayer( - d_model=D, - nhead=H, - dim_feedforward=FD, - batch_first=True, - activation="relu", - ), - num_layers=L, - enable_nested_tensor=False, - ), - embedding_layer, - ) - .eval() - .cuda() - ) - - def copy_weights(layers_fairseq, layers_bt): - for src_layer, dst_layer in zip(layers_fairseq, layers_bt): - w_q = src_layer.self_attn.q_proj.weight - b_q = src_layer.self_attn.q_proj.bias - w_k = src_layer.self_attn.k_proj.weight - b_k = src_layer.self_attn.k_proj.bias - w_v = src_layer.self_attn.v_proj.weight - b_v = src_layer.self_attn.v_proj.bias - dst_layer.self_attn.in_proj_weight = torch.nn.Parameter( - torch.cat((w_q, w_k, w_v), dim=0) - ) - dst_layer.self_attn.in_proj_bias = torch.nn.Parameter( - torch.cat((b_q, b_k, b_v), dim=0) - ) - - dst_layer.self_attn.out_proj.weight = src_layer.self_attn.out_proj.weight - dst_layer.self_attn.out_proj.bias = src_layer.self_attn.out_proj.bias - - dst_layer.linear1.weight = src_layer.fc1.weight - dst_layer.linear1.bias = src_layer.fc1.bias - dst_layer.linear2.weight = src_layer.fc2.weight - dst_layer.linear2.bias = src_layer.fc2.bias - - dst_layer.norm1.weight = src_layer.self_attn_layer_norm.weight - dst_layer.norm1.bias = src_layer.self_attn_layer_norm.bias - dst_layer.norm2.weight = src_layer.final_layer_norm.weight - dst_layer.norm2.bias = src_layer.final_layer_norm.bias - - (L, D, H, FD, V) = get_layers_embedding_dim_num_heads_for_configuration( - xlarge, large - ) - embedding_layer = torch.nn.Embedding(V, D, DEFAULT_PADDING_IDX) - # True means BT as source and fairseq is target, False means the other way - # mode1 = False - if bt2fairseq: - # BT as source and fairseq is target, copy BT's weight to fairseq - transformer = make_transformer() - fairseq_transformer = ( - FairseqEncoder( - D, - H, - FD, - L, - embedding_layer, - dropout=0, - normalize_before=False, - torch_encoder=transformer.transformer, - activation="relu", - ) - .eval() - .cuda() - ) - if half: - transformer.half() - fairseq_transformer.half() - if not bt2fairseq: - # the other way around, fairseq is source and BT is target,copy fairseq's weight to BT - transformer = make_transformer() - fairseq_transformer = ( - FairseqEncoder( - D, - H, - FD, - L, - embedding_layer, - dropout=0, - normalize_before=False, - torch_encoder=None, - activation="relu", - ) - .eval() - .cuda() - ) - # for the test where we need to load existing ckpt. It is tested that after loading - # the ckpt, the results between fairseq_transformer(BT kernel) equals BT - if half: - transformer.half() - fairseq_transformer.half() - if save: - torch.save(fairseq_transformer.state_dict(), "./fairseq.pt") - sys.exit(0) - if load: - fairseq_transformer.load_state_dict(torch.load("./fairseq.pt")) - # copy - copy_weights(fairseq_transformer.encoder.layers, transformer.transformer.layers) - - device = "cuda" - lengths = (avg_sequence_length,) * batch_size - tokens = torch.full( - (batch_size, max_sequence_length), - DEFAULT_PADDING_IDX, - device=device, - dtype=torch.long, - ) - for i in range(batch_size): - tokens[i, : lengths[i]] = torch.randint( - DEFAULT_PADDING_IDX + 1, - V - 1, - size=(lengths[i],), - device=device, - dtype=torch.long, - ) - # mask - if half: - lengths_tensor = torch.Tensor(lengths).cuda().half() - else: - lengths_tensor = torch.Tensor(lengths).cuda() - - with torch.inference_mode(): - fs_output = fairseq_transformer(tokens, lengths_tensor)["encoder_out"][0] - fs_output = fs_output.transpose(0, 1) - with torch.inference_mode(): - t_output = transformer(tokens) - test_lst = [ - # (name, output, relative tolerance, absolute tolerance) - ("FS", fs_output, 1e-4, 9e-3), - ] - numerical_test(lengths, t_output, test_lst) - - iters = 100 - t = benchmark_torch_function(iters, transformer, tokens) - - def bert_flops(B, T, D, L): - mlp = 2 * (B * T * D * 4 * D) + 2 * (B * T * D * 4 * D) - qkv = 3 * 2 * B * T * D * D - attn = 2 * B * D * T * T + 2 * B * D * T * T + 2 * B * T * D * D - return L * (mlp + qkv + attn) - - flops = bert_flops(batch_size, avg_sequence_length, D, L) - flops_e = ( - FlopCountAnalysis(transformer, (tokens[:, :avg_sequence_length])).total() * 2 - ) - with torch.inference_mode(): - bt = benchmark_torch_function(iters, transformer, tokens) - fst = benchmark_torch_function( - iters, fairseq_transformer, tokens, lengths_tensor - ) - - def metrics(tt, baseline=None): - if baseline: - return metrics(tt) + f", Speedup: {baseline / tt:.2f}x" - return f"{tt * 1.0e3:.2f} ms/iter, {flops_e / tt / 1.0e12:.2f} TFLOP/s" - - results = [ - f"Seed: {seed}", - f"Padded tokens: {(1-sum(lengths)/(tokens.numel()))*100:.2f}%", - f"Batch shape: {tokens.shape}", - f"Analytical flops per batch: {flops/ batch_size / 1e9:.2f} GFLOPS", - f"Empirical flops per batch: {flops_e/ batch_size / 1e9:.2f} GFLOPS", - f"B: {batch_size}", - f"T: {avg_sequence_length}", - f"TMax: {max_sequence_length}", - f"Eager Time: {metrics(t)}", - f"BetterTransformer: {metrics(bt, t)}", - f"FST: {metrics(fst, t)}", - ] - print("===========Speedup Results") - print("; ".join(results)) - - -if __name__ == "__main__": - cli() diff --git a/tests/test_export.py b/tests/test_export.py index 36fcc44550..3e9a48d187 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -92,35 +92,8 @@ def test_positional_embedding(self): scripted = torch.jit.script(module) _test_save_and_load(scripted) - def version_check(): - # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' - if "fb" in torch.__version__: - return False - else: - if "+" in torch.__version__: - torch_version = torch.__version__.split("+")[0] - else: - torch_version = torch.__version__ - - torch_version = torch_version.split(".") - int_version = ( - int(torch_version[0]) * 1000 - + int(torch_version[1]) * 10 - + int(torch_version[2]) - ) - if len(torch_version) == 3: - if int_version >= 1131: - return False - elif len(torch_version) == 4: - if int_version >= 1131 or ( - int_version == 1130 and torch_version[3][3:] >= "20220613" - ): - return False - return True - @unittest.skipIf( - version_check(), - "Targeting OSS scriptability for the 1.13.0.dev20220613 release", + torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" ) def test_export_transformer(self): task, parser = get_dummy_task_and_parser() @@ -131,8 +104,7 @@ def test_export_transformer(self): _test_save_and_load(scripted) @unittest.skipIf( - version_check(), - "Targeting OSS scriptability for the 1.13.0.dev20220613 release", + torch.__version__ < "1.6.0", "Targeting OSS scriptability for the 1.6 release" ) def test_export_transformer_no_token_pos_emb(self): task, parser = get_dummy_task_and_parser() diff --git a/tests/test_sequence_generator.py b/tests/test_sequence_generator.py index a0b6e8934c..2e42df0e56 100644 --- a/tests/test_sequence_generator.py +++ b/tests/test_sequence_generator.py @@ -22,33 +22,6 @@ DEFAULT_TEST_VOCAB_SIZE = 100 -def version_check(): - # check Nested Tensor available. Make sure version >= '1.13.0.dev20220613' - if "fb" in torch.__version__: - return False - else: - if "+" in torch.__version__: - torch_version = torch.__version__.split("+")[0] - else: - torch_version = torch.__version__ - - torch_version = torch_version.split(".") - int_version = ( - int(torch_version[0]) * 1000 - + int(torch_version[1]) * 10 - + int(torch_version[2]) - ) - if len(torch_version) == 3: - if int_version >= 1131: - return False - elif len(torch_version) == 4: - if int_version >= 1131 or ( - int_version == 1130 and torch_version[3][3:] >= "20220613" - ): - return False - return True - - class DummyTask(LegacyFairseqTask): def __init__(self, args): super().__init__(args) @@ -140,9 +113,7 @@ def _test_save_and_load(self, scripted_module): JIT_MSG = "Targeting OSS scriptability for the 1.6 release" -@unittest.skipIf( - version_check(), "Targeting OSS scriptability for the 1.13.0.dev20220613 release" -) +@unittest.skipIf(torch.__version__ < "1.6.0", JIT_MSG) class TestJitSequenceGenerator(TestJitSequenceGeneratorBase): def test_export_transformer(self): model = self.transformer_model From f82661594b4c2b712cb7ab19c58d4b30317972b9 Mon Sep 17 00:00:00 2001 From: Marco Gaido <mgaido@fb.com> Date: Wed, 24 Aug 2022 08:51:52 -0700 Subject: [PATCH 670/774] fix padding of s2t_wav_transformer (#4629) --- .../speech_to_text/s2t_wav_transformer.py | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/fairseq/models/speech_to_text/s2t_wav_transformer.py b/fairseq/models/speech_to_text/s2t_wav_transformer.py index f11034818d..e2d7b6b609 100644 --- a/fairseq/models/speech_to_text/s2t_wav_transformer.py +++ b/fairseq/models/speech_to_text/s2t_wav_transformer.py @@ -178,15 +178,15 @@ def __init__(self, args, alway_mask=False): mode=args.speech_extractor_mode, # default, layer_norm conv_bias=args.speech_conv_bias, ) - feature_enc_layers = eval(args.conv_feature_layers) + self.feature_enc_layers = eval(args.conv_feature_layers) self.subsample = subsample self.feat_proj = ( - nn.Linear(feature_enc_layers[-1][0], self.embedding_dim) - if feature_enc_layers[-1][0] != self.embedding_dim + nn.Linear(self.feature_enc_layers[-1][0], self.embedding_dim) + if self.feature_enc_layers[-1][0] != self.embedding_dim else None ) - self.feat_layer_norm = LayerNorm(feature_enc_layers[-1][0]) + self.feat_layer_norm = LayerNorm(self.feature_enc_layers[-1][0]) self.embed_positions = nn.Conv1d( self.embedding_dim, @@ -236,6 +236,21 @@ def __init__(self, args, alway_mask=False): self.normalize_before = args.encoder_normalize_before self.alway_mask = alway_mask + def _get_feat_extract_output_lengths(self, input_lengths: torch.LongTensor): + """ + Computes the output length of the convolutional layers + """ + + def _conv_out_length(input_length, kernel_size, stride): + return torch.floor((input_length - kernel_size) / stride + 1) + + for i in range(len(self.feature_enc_layers)): + input_lengths = _conv_out_length( + input_lengths, self.feature_enc_layers[i][1], self.feature_enc_layers[i][2] + ) + + return input_lengths.to(torch.long) + def apply_mask(self, x, padding_mask): B, T, C = x.shape if self.mask_prob > 0: @@ -299,22 +314,24 @@ def forward( if padding_mask is not None: input_lengths = (1 - padding_mask.long()).sum(-1) - # apply conv formula to get real output_lengths - output_lengths = self._get_feat_extract_output_lengths(input_lengths) + else: + input_lengths = src_lengths + # apply conv formula to get real output_lengths + output_lengths = self._get_feat_extract_output_lengths(input_lengths) - padding_mask = torch.zeros( - features.shape[:2], dtype=features.dtype, device=features.device - ) + padding_mask = torch.zeros( + features.shape[:2], dtype=features.dtype, device=features.device + ) - # these two operations makes sure that all values - # before the output lengths indices are attended to - padding_mask[ - ( - torch.arange(padding_mask.shape[0], device=padding_mask.device), - output_lengths - 1, - ) - ] = 1 - padding_mask = (1 - padding_mask.flip([-1]).cumsum(-1).flip([-1])).bool() + # these two operations makes sure that all values + # before the output lengths indices are attended to + padding_mask[ + ( + torch.arange(padding_mask.shape[0], device=padding_mask.device), + output_lengths - 1, + ) + ] = 1 + padding_mask = (1 - padding_mask.flip([-1]).cumsum(-1).flip([-1])).bool() features = self.feat_scale * features if self.feat_scale != 1.0 else features unmasked_features = features.clone() From eda703798dcfde11c1ee517805c27e8698285d71 Mon Sep 17 00:00:00 2001 From: sravyapopuri388 <51169165+sravyapopuri388@users.noreply.github.com> Date: Wed, 24 Aug 2022 11:06:45 -0700 Subject: [PATCH 671/774] Fix under generation issue for speech to speech translation models by adding optional generation args (#4662) * OSS ckpts for Interspeech 2022 paper * HF interface update * local test * local test * revert local test * address comments * add Hk<>En models * add Hk<>En models * add Hk<>En models * add hk->en * add hk->en * add hk->en * add hk->en * add hk->en * debug * debug * debub * fix undergeneration for S2UT * fix typo * fix typo * fix bug --- fairseq/hub_utils.py | 3 +++ fairseq/models/speech_to_text/hub_interface.py | 2 +- fairseq/models/speech_to_text/xm_transformer.py | 3 ++- fairseq/sequence_generator.py | 8 ++++---- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/fairseq/hub_utils.py b/fairseq/hub_utils.py index d0f4d03139..b0c2da15bf 100644 --- a/fairseq/hub_utils.py +++ b/fairseq/hub_utils.py @@ -83,6 +83,9 @@ def from_pretrained( model_path, arg_overrides=kwargs, ) + if "generation_args" in kwargs and kwargs["generation_args"]: + for key in kwargs["generation_args"]: + setattr(args["generation"], key, kwargs["generation_args"][key]) return { "args": args, diff --git a/fairseq/models/speech_to_text/hub_interface.py b/fairseq/models/speech_to_text/hub_interface.py index 173bb73064..c7e1f5ee06 100644 --- a/fairseq/models/speech_to_text/hub_interface.py +++ b/fairseq/models/speech_to_text/hub_interface.py @@ -30,7 +30,7 @@ def __init__(self, cfg, task, model): self.task = task self.model = model self.model.eval() - self.generator = self.task.build_generator([self.model], self.cfg) + self.generator = self.task.build_generator([self.model], self.cfg.generation) @classmethod def get_model_input(cls, task, audio: Union[str, torch.Tensor]): diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index e67b7c6715..c82dea9ba4 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -510,10 +510,10 @@ def from_pretrained( data_name_or_path=".", config_yaml="config.yaml", task="speech_to_text", + generation_args=None, **kwargs, ): from fairseq import hub_utils - x = hub_utils.from_pretrained( model_name_or_path, checkpoint_file, @@ -521,6 +521,7 @@ def from_pretrained( archive_map=cls.hub_models(), config_yaml=config_yaml, task=task, + generation_args=generation_args, **kwargs, ) return S2THubInterface(x["args"], x["task"], x["models"][0]) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 13f99078c7..5176f5d267 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -374,7 +374,7 @@ def _generate( # handle max length constraint if step >= max_len: lprobs[:, : self.eos] = -math.inf - lprobs[:, self.eos + 1 :] = -math.inf + lprobs[:, self.eos + 1:] = -math.inf # handle prefix tokens (possibly with different lengths) if ( @@ -604,7 +604,7 @@ def _prefix_tokens( if eos_mask.any(): # validate that the first beam matches the prefix first_beam = tokens[eos_mask].view(-1, beam_size, tokens.size(-1))[ - :, 0, 1 : step + 1 + :, 0, 1: step + 1 ] eos_mask_batch_dim = eos_mask.view(-1, beam_size)[:, 0] target_prefix = prefix_tokens[eos_mask_batch_dim][:, :step] @@ -649,12 +649,12 @@ def finalize_hypos( # tokens is (batch * beam, max_len). So the index_select # gets the newly EOS rows, then selects cols 1..{step + 2} tokens_clone = tokens.index_select(0, bbsz_idx)[ - :, 1 : step + 2 + :, 1: step + 2 ] # skip the first index, which is EOS tokens_clone[:, step] = self.eos attn_clone = ( - attn.index_select(0, bbsz_idx)[:, :, 1 : step + 2] + attn.index_select(0, bbsz_idx)[:, :, 1: step + 2] if attn is not None else None ) From d81fac8163364561fd6cd9d82b6ee1ba502c3526 Mon Sep 17 00:00:00 2001 From: Can Balioglu <cbalioglu@users.noreply.github.com> Date: Mon, 29 Aug 2022 16:35:08 +0300 Subject: [PATCH 672/774] Fix edit_dist.cu header file directives (#4667) --- fairseq/clib/libnat_cuda/edit_dist.cu | 2 +- fairseq/model_parallel/megatron_trainer.py | 4 ++-- fairseq/models/speech_to_text/hub_interface.py | 2 +- .../models/speech_to_text/s2t_wav_transformer.py | 4 +++- fairseq/models/speech_to_text/xm_transformer.py | 13 +++++++++---- fairseq/models/text_to_speech/vocoder.py | 13 ++++++++----- fairseq/models/transformer/transformer_config.py | 2 +- fairseq/sequence_generator.py | 8 ++++---- 8 files changed, 29 insertions(+), 19 deletions(-) diff --git a/fairseq/clib/libnat_cuda/edit_dist.cu b/fairseq/clib/libnat_cuda/edit_dist.cu index 96569d46c8..1ea5ec7e3c 100644 --- a/fairseq/clib/libnat_cuda/edit_dist.cu +++ b/fairseq/clib/libnat_cuda/edit_dist.cu @@ -8,7 +8,7 @@ #include "edit_dist.h" -#include <THC/THC.h> +#include <c10/cuda/CUDAStream.h> #include <cuda.h> #include <cuda_runtime.h> #include <device_launch_parameters.h> diff --git a/fairseq/model_parallel/megatron_trainer.py b/fairseq/model_parallel/megatron_trainer.py index ca42118648..aedf608bce 100644 --- a/fairseq/model_parallel/megatron_trainer.py +++ b/fairseq/model_parallel/megatron_trainer.py @@ -38,11 +38,11 @@ def __init__(self, cfg: FairseqConfig, task, model, criterion, **kwargs): def clip_grad_norm(self, clip_norm): def _aggregate_model_parallel_grad_norm(total_norm): - total_norm = total_norm ** 2 + total_norm = total_norm**2 distributed_utils.all_reduce( total_norm, group=distributed_utils.get_model_parallel_group() ) - total_norm = total_norm ** 0.5 + total_norm = total_norm**0.5 return total_norm return self.optimizer.clip_grad_norm( diff --git a/fairseq/models/speech_to_text/hub_interface.py b/fairseq/models/speech_to_text/hub_interface.py index c7e1f5ee06..49d5b6b03b 100644 --- a/fairseq/models/speech_to_text/hub_interface.py +++ b/fairseq/models/speech_to_text/hub_interface.py @@ -97,7 +97,7 @@ def get_prediction( pred = cls.detokenize(task, pred_tokens[0][0]["tokens"]) eos_token = task.data_cfg.config.get("eos_token", None) if eos_token: - pred = ' '.join(pred.split(' ')[:-1]) + pred = " ".join(pred.split(" ")[:-1]) if synthesize_speech: pfx = f"{_tgt_lang}_" if task.data_cfg.prepend_tgt_lang_tag else "" diff --git a/fairseq/models/speech_to_text/s2t_wav_transformer.py b/fairseq/models/speech_to_text/s2t_wav_transformer.py index e2d7b6b609..ad21aeeb1a 100644 --- a/fairseq/models/speech_to_text/s2t_wav_transformer.py +++ b/fairseq/models/speech_to_text/s2t_wav_transformer.py @@ -246,7 +246,9 @@ def _conv_out_length(input_length, kernel_size, stride): for i in range(len(self.feature_enc_layers)): input_lengths = _conv_out_length( - input_lengths, self.feature_enc_layers[i][1], self.feature_enc_layers[i][2] + input_lengths, + self.feature_enc_layers[i][1], + self.feature_enc_layers[i][2], ) return input_lengths.to(torch.long) diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index c82dea9ba4..ce855af76f 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -249,7 +249,10 @@ def add_wav2vec_asr_args(parser): help="if set, then the weight-norm (in one pos_conv layer) is removed from the model", ) parser.add_argument( - "--encoder-embed-dim", type=int, metavar="N", help="encoder embedding dimension to be used when w2v_path is None and no encoder_proj is set" + "--encoder-embed-dim", + type=int, + metavar="N", + help="encoder embedding dimension to be used when w2v_path is None and no encoder_proj is set", ) @@ -497,8 +500,7 @@ def hub_models(cls): "xm_transformer_s2ut_800m-es-en-st-asr-bt_h1_2022", "xm_transformer_s2ut_800m-en-es-st_plus_asr", "xm_transformer_s2ut_800m-hk-en-h1_2022", - "xm_transformer_s2ut_800m-en-hk-h1_2022" - + "xm_transformer_s2ut_800m-en-hk-h1_2022", ] return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} @@ -514,6 +516,7 @@ def from_pretrained( **kwargs, ): from fairseq import hub_utils + x = hub_utils.from_pretrained( model_name_or_path, checkpoint_file, @@ -557,7 +560,9 @@ def build_encoder(cls, args): if args.w2v_path: state = checkpoint_utils.load_checkpoint_to_cpu(args.w2v_path) if state.get("cfg") is not None: - encoder_embed_dim = state["cfg"]._content["model"]["encoder_embed_dim"] + encoder_embed_dim = state["cfg"]._content["model"][ + "encoder_embed_dim" + ] elif state.get("args") is not None: encoder_embed_dim = state["args"].encoder_embed_dim else: diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index 0088daadcb..34e7f498fb 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -84,7 +84,7 @@ def get_window_sum_square( x = torch.zeros(n, dtype=torch.float32) for i in range(n_frames): ofst = i * hop_length - x[ofst: min(n, ofst + n_fft)] += w_sq[: max(0, min(n_fft, n - ofst))] + x[ofst : min(n, ofst + n_fft)] += w_sq[: max(0, min(n_fft, n - ofst))] return x def inverse(self, magnitude: torch.Tensor, phase) -> torch.Tensor: @@ -102,8 +102,8 @@ def inverse(self, magnitude: torch.Tensor, phase) -> torch.Tensor: approx_nonzero_indices = win_sum_sq > self.tiny x[:, :, approx_nonzero_indices] /= win_sum_sq[approx_nonzero_indices] x *= self.n_fft / self.hop_length - x = x[:, :, self.n_fft // 2:] - x = x[:, :, : -self.n_fft // 2:] + x = x[:, :, self.n_fft // 2 :] + x = x[:, :, : -self.n_fft // 2 :] return x def forward(self, specgram: torch.Tensor) -> torch.Tensor: @@ -252,8 +252,11 @@ def from_data_cfg(cls, args, data_cfg): @classmethod def hub_models(cls): base_url = "http://dl.fbaipublicfiles.com/fairseq/vocoder" - model_ids = ["unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_lj_dur", - "unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_es_css10_dur", "unit_hifigan_HK_layer12.km2500_frame_TAT-TTS"] + model_ids = [ + "unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_lj_dur", + "unit_hifigan_mhubert_vp_en_es_fr_it3_400k_layer11_km1000_es_css10_dur", + "unit_hifigan_HK_layer12.km2500_frame_TAT-TTS", + ] return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} @classmethod diff --git a/fairseq/models/transformer/transformer_config.py b/fairseq/models/transformer/transformer_config.py index 9c8f330f74..4650de2e17 100644 --- a/fairseq/models/transformer/transformer_config.py +++ b/fairseq/models/transformer/transformer_config.py @@ -138,7 +138,7 @@ class TransformerConfig(FairseqDataclass): "help": "if true then the source and target embedding table is " "merged into one table. This is going to make the model smaller but " "it might hurt performance." - } + }, ) no_token_positional_embeddings: bool = field( default=False, diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 5176f5d267..13f99078c7 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -374,7 +374,7 @@ def _generate( # handle max length constraint if step >= max_len: lprobs[:, : self.eos] = -math.inf - lprobs[:, self.eos + 1:] = -math.inf + lprobs[:, self.eos + 1 :] = -math.inf # handle prefix tokens (possibly with different lengths) if ( @@ -604,7 +604,7 @@ def _prefix_tokens( if eos_mask.any(): # validate that the first beam matches the prefix first_beam = tokens[eos_mask].view(-1, beam_size, tokens.size(-1))[ - :, 0, 1: step + 1 + :, 0, 1 : step + 1 ] eos_mask_batch_dim = eos_mask.view(-1, beam_size)[:, 0] target_prefix = prefix_tokens[eos_mask_batch_dim][:, :step] @@ -649,12 +649,12 @@ def finalize_hypos( # tokens is (batch * beam, max_len). So the index_select # gets the newly EOS rows, then selects cols 1..{step + 2} tokens_clone = tokens.index_select(0, bbsz_idx)[ - :, 1: step + 2 + :, 1 : step + 2 ] # skip the first index, which is EOS tokens_clone[:, step] = self.eos attn_clone = ( - attn.index_select(0, bbsz_idx)[:, :, 1: step + 2] + attn.index_select(0, bbsz_idx)[:, :, 1 : step + 2] if attn is not None else None ) From c0c326cbf8c517a6f6d2e63747567a7f3b33a2b6 Mon Sep 17 00:00:00 2001 From: Bing Han <beatmight@gmail.com> Date: Fri, 2 Sep 2022 03:44:26 +0800 Subject: [PATCH 673/774] Fix for #4689. (#4690) --- fairseq/tasks/translation.py | 6 ++++-- setup.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 79752279a6..029ca2f551 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -492,6 +492,8 @@ def decode(toks, escape_unk=False): logger.info("example hypothesis: " + hyps[0]) logger.info("example reference: " + refs[0]) if self.cfg.eval_tokenized_bleu: - return sacrebleu.corpus_bleu(hyps, [refs], tokenize="none") + return sacrebleu.metrics.BLEU().corpus_score(hyps, [refs]) else: - return sacrebleu.corpus_bleu(hyps, [refs]) + return sacrebleu.metrics.BLEU(trg_lang=self.cfg.target_lang).corpus_score( + hyps, [refs] + ) diff --git a/setup.py b/setup.py index a7ce61a896..f103664c50 100644 --- a/setup.py +++ b/setup.py @@ -205,7 +205,7 @@ def do_setup(package_data): 'numpy<1.20.0; python_version<"3.7"', 'numpy; python_version>="3.7"', "regex", - "sacrebleu>=1.4.12", + "sacrebleu>=2.0.0", "torch", "tqdm", "bitarray", From 0bad0ce56a43bfd8251a8c773764a5884d4d21ee Mon Sep 17 00:00:00 2001 From: Can Balioglu <cbalioglu@users.noreply.github.com> Date: Thu, 8 Sep 2022 15:07:47 +0300 Subject: [PATCH 674/774] Revert "Fix for #4689. (#4690)" (#4698) This reverts commit c0c326cbf8c517a6f6d2e63747567a7f3b33a2b6. --- fairseq/tasks/translation.py | 6 ++---- setup.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 029ca2f551..79752279a6 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -492,8 +492,6 @@ def decode(toks, escape_unk=False): logger.info("example hypothesis: " + hyps[0]) logger.info("example reference: " + refs[0]) if self.cfg.eval_tokenized_bleu: - return sacrebleu.metrics.BLEU().corpus_score(hyps, [refs]) + return sacrebleu.corpus_bleu(hyps, [refs], tokenize="none") else: - return sacrebleu.metrics.BLEU(trg_lang=self.cfg.target_lang).corpus_score( - hyps, [refs] - ) + return sacrebleu.corpus_bleu(hyps, [refs]) diff --git a/setup.py b/setup.py index f103664c50..a7ce61a896 100644 --- a/setup.py +++ b/setup.py @@ -205,7 +205,7 @@ def do_setup(package_data): 'numpy<1.20.0; python_version<"3.7"', 'numpy; python_version>="3.7"', "regex", - "sacrebleu>=2.0.0", + "sacrebleu>=1.4.12", "torch", "tqdm", "bitarray", From 9a00e0336bda9fcf297541d2fbe5fc26f710e0fa Mon Sep 17 00:00:00 2001 From: Can Balioglu <cbalioglu@users.noreply.github.com> Date: Thu, 8 Sep 2022 15:09:39 +0300 Subject: [PATCH 675/774] Update CODEOWNERS (#4699) --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4e818c6f99..b79aa2ff06 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,3 +16,6 @@ fairseq/modules/conformer_layer.py @sravyapopuri388 @jmp84 fairseq/modules/espnet_multihead_attention.py @sravyapopuri388 @jmp84 fairseq/modules/rotary_positional_embedding.py @sravyapopuri388 @jmp84 fairseq/modules/positional_encoding.py @sravyapopuri388 @jmp84 + +# Machine Translation/NLLB +fairseq/tasks/translation.py @gwenzek From eba8a50d2b184a0eba8dbec8bada8a2129bbb77c Mon Sep 17 00:00:00 2001 From: Adishree Ghatare <adishree@fb.com> Date: Thu, 8 Sep 2022 14:14:02 -0700 Subject: [PATCH 676/774] [feat][ust] Noise and data augmentation suite (#4692) * Implemented data augmentation for concatenation (#3516) * Implemented ConcatAug as setting from config * Switched ConcatAug implementation to sweep script * Added rate and max tokens as ConcatAug params * Kept original fns, pulled concat_attempts as hyperparam * Fixed ConcatAug nits * ConcatAug typing recognizes int and np.int * Implemented waveform transforms and suite of noise augmentation techniques (#3517) * Implemented ConcatAug as setting from config * Switched ConcatAug implementation to sweep script * Kept original fns, pulled concat_attempts as hyperparam * Implemented WaveformTransforms, MusicAug * Removed leftovers from debugging * Separated out feature_ and waveform_transforms, updated constants, formatting cleanup * Added Babble and SporadicNoise augmentations * Fixed zero division error * Adding BackgroundNoiseAugment * Added warning for if using feature transforms with waveform input * warnings, SNR fix * fix for NoneType extension error * fix 2 for NoneType extension error * delete print * Dataset transform, NoisyOverlapAugment, reframe ConcatAugment (#3533) * Dataset transform, NoisyOverlapAugment, reframe ConcatAugment * using np.random instead of python random * fixed np random upper bound bug * cleanup * Changed args & return expressions for waveform transform * Documented new augmentation features * Create augmentation_example.md * Update augmentation_example.md * Update, benchmarking left to do * Move docs to speech_to_speech * Remove docs from speech_to_text * [docs] Updated clean benchmarks * [docs] Add benchmark data --- .../docs/data_augmentation.md | 435 ++++++++++++++++++ fairseq/data/audio/__init__.py | 93 ++++ fairseq/data/audio/audio_utils.py | 48 +- fairseq/data/audio/data_cfg.py | 44 +- .../data/audio/dataset_transforms/__init__.py | 53 +++ .../audio/dataset_transforms/concataugment.py | 61 +++ .../dataset_transforms/noisyoverlapaugment.py | 105 +++++ .../data/audio/feature_transforms/__init__.py | 89 +--- fairseq/data/audio/speech_to_text_dataset.py | 101 +++- .../audio/waveform_transforms/__init__.py | 48 ++ .../audio/waveform_transforms/noiseaugment.py | 201 ++++++++ 11 files changed, 1187 insertions(+), 91 deletions(-) create mode 100644 examples/speech_to_speech/docs/data_augmentation.md create mode 100644 fairseq/data/audio/dataset_transforms/__init__.py create mode 100644 fairseq/data/audio/dataset_transforms/concataugment.py create mode 100644 fairseq/data/audio/dataset_transforms/noisyoverlapaugment.py create mode 100644 fairseq/data/audio/waveform_transforms/__init__.py create mode 100644 fairseq/data/audio/waveform_transforms/noiseaugment.py diff --git a/examples/speech_to_speech/docs/data_augmentation.md b/examples/speech_to_speech/docs/data_augmentation.md new file mode 100644 index 0000000000..c0c17ff223 --- /dev/null +++ b/examples/speech_to_speech/docs/data_augmentation.md @@ -0,0 +1,435 @@ +# Noise and audio augmentation techniques + +The noise and data augmentation techniques were written in an effort to understand how augmenatation can affect model robustness and performance in both clean and noisy settings. + +All transforms discussed in this section are subclasses of `AudioFeatureTransform`, `AudioWaveformTransform`, or `AudioDatasetTransform`. Each `Audio*Transform` has unique interaction with the data. If interested in implemented one's own transforms, it is highly advisable to review the differences (see [Adding your own transforms](https://github.com/facebookresearch/fairseq/blob/main/examples/speech_to_speech/docs/data_augmentation.md#adding-your-own-transforms)). If only applying the in-built transforms, then one only needs to be mindful that the correct kind of transform is listed in the config (see [Using transforms](https://github.com/facebookresearch/fairseq/blob/main/examples/speech_to_speech/docs/data_augmentation.md#using-transforms)). These transforms can be applied to instances of `SpeechToTextDataset`. + +### Contents +[In-built transforms](https://github.com/facebookresearch/fairseq/blob/main/examples/speech_to_speech/docs/data_augmentation.md#in-built-transforms) + +[Benchmark studies](https://github.com/facebookresearch/fairseq/blob/main/examples/speech_to_speech/docs/data_augmentation.md#benchmark-studies) + +[Using transforms](https://github.com/facebookresearch/fairseq/blob/main/examples/speech_to_speech/docs/data_augmentation.md#using-transforms) + +[Adding your own transforms](https://github.com/facebookresearch/fairseq/blob/main/examples/speech_to_speech/docs/data_augmentation.md#adding-your-own-transforms) + + +## In-built transforms +### 1. Utterance concatenation +Utterance concatenation is a data augmenation technique introduced as ConcatAug in [Translatotron 2: High-quality direct speech-to-speech translation +with voice preservation](https://arxiv.org/pdf/2107.08661.pdf). +With some parameterized probability, samples are concatenated with one other randomly chosen sample from the whole dataset. In the positive (concatenation) case, accessing `dataset[i]` will return a `SpeechToTextDatasetItem` where `source=source[i]+source[j]` and `target=target[i]+target[j]`. In the negative (skip concatenation) case, accessing `dataset[i]` will return a `SpeechToTextDatasetItem` where `source=source[i]` and `target=target[i]` as usual. + +**Usage**: `concataugment` is an `AudioDatasetTransform` and has three configurable hyperparameters: +- `rate`: probability that any single access will result in the positive (concatenation) case. Defaults to 0.25. +- `max_tokens`: maximum number of tokens allowed for concatenated source sequences. This parameter is meant to limit the length of concatenated samples to avoid out-of-memory errors. Defaults to 300. +- `attempts`: maximum number of invalid concatenation attempts before defaulting to the negative (skip concatenation) case. This parameter aims to limit excessive time spent trying to find candidate samples that are short enough to concatenate with. Defaults to 5. + +Please be wary of OOMs while using this augmentation technique; we used smaller batch sizes as a workaround to avoid OOMs. Batch size is determined by update frequency, batch size hyperparameter, and the number of GPU, so you may want to alter these to this end. + +### 2. Noise augmentation suite + +The four noise augmentation methods in this suite adhere to the following principle: with some parameterized probability, samples are overlayed with a noise track. The content of the noise track is specific to the method. Signal-to-noise ratio with which the noise track is overlayed is determined by choosing a value from a random uniform distribution with parameterized endpoints. The first three methods are based off data augmentation methods suggested in Section 3.3 of [X-Vectors: Robust DNN Embeddings for Speaker Recognition](https://danielpovey.com/files/2018_icassp_xvectors.pdf). + +#### 2.1. Music augmentation +For music augmentation, the noise track consists of one file uniformly randomly selected from a corpus of music files. The music file is cut to size, including being repeated to fill the original sample length if necessary. + +**Usage**: `musicaugment` is an `AudioWaveformTransform` and has four configurable hyperparameters: +- `samples_path`: path where background music files are saved as audios (.wav files). No default. +- `rate`: probability that any single access will result in the positive (background music) case. Defaults to 0.25. +- `snr_min`: lower endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 5. +- `snr_max`: higher endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 15. + +#### 2.2. Babble augmentation +For babble augmentation, the noise track consists of multiple audios uniformly randomly selected from a corpus of speech files. The number of speech audios in the background track is chosen randomly with equal probability between 3 and 7 audios. + +**Usage**: `babbleaugment` is an `AudioWaveformTransform` and has four configurable hyperparameters: +- `samples_path`: path where background speech files are saved as audios (.wav files). No default. +- `rate`: probability that any single access will result in the positive (background speech) case. Defaults to 0.25. +- `snr_min`: lower endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 5. +- `snr_max`: higher endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 15. + +#### 2.3. Sporadic noise augmentation +For sporadic noise augmentation, the noise track is mostly silent except for intermittent short clips of noise which are added at roughly a parameterized frequency. These clips are randomly chosen and cut from a corpus of noise files to lengths according to a parameterized Gaussian distribution. + +**Usage**: `sporadicnoiseaugment` is an `AudioWaveformTransform` and has seven configurable hyperparameters: +- `samples_path`: path where background noise files are saved as audios (.wav files). No default. +- `rate`: probability that any single access will result in the positive (add a sporadic noise track) case. Defaults to 0.25. +- `snr_min`: lower endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 5. +- `snr_max`: higher endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 15. +- `noise_rate`: rate in noises per second at which noise clip will be added to the original sample +- `noise_len_mean`: mean of Gaussian normal distribution from which length of noise clip is chosen +- `noise_len_std`: standard deviation of Gaussian normal distribution from which length of noise clip is chosen + +#### 2.4. Background noise augmentation +For background noise augmentation, the noise track is a single track uniformly randomly selected from a corpus of noise files. The noise file is cut to size, including being repeated to fill the original sample length if necessary. + +**Usage**: `backgroundnoiseaugment` is an `AudioWaveformTransform` and has four configurable hyperparameters: +- `samples_path`: path where background noise files are saved as audios (.wav files). No default. +- `rate`: probability that any single access will result in the positive (background noise) case. Defaults to 0.25. +- `snr_min`: lower endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 5. +- `snr_max`: higher endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 15. + +### 3. Mixed babble and background noise augmentation with recognizable source speaker + +This augmentation technique is based on Algorithm 1 in [WavLM: Large-Scale Self-Supervised Pre-Training for Full Stack Speech Processing](https://arxiv.org/abs/2110.13900) and is similar to the noise augmentation suite techniques in that it has a background noise track. The noise track consists of either (1) another audio sample from the batch or (2) a background noise track. A key difference is the length of the noise track is chosen from a uniform random distribution between 0 and half of the original sample length. + +**Usage**: `noisyoverlapaugment` is an `AudioDatasetTransform` and has seven configurable hyperparameters: +- `noises_path`: path where background noise files are saved as audios (.wav files). No default. +- `rate`: probability that any single access will result in the positive (background noise) case. Defaults to 0.25. +- `mixing_noise_rate`: probability that in a positive (background noise) case, the noise track will consist of background noise (rather than babble from the batch). Defaults to 0.1. +- `noise_snr_min`: lower endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to -5. +- `noise_snr_max`: higher endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add background noise to the original source. Defaults to 5. +- `utterance_snr_min`: lower endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add **another audio from the batch** to the original source. Defaults to -5. +- `utterance_snr_max`: higher endpoint of the range from which a signal-to-noise ratio is uniformly randomly chosen with which to add **another audio from the batch** to the original source. Defaults to 5. + +## Benchmark studies +### Evaluation on clean data +Augmentation in training data|Hyperparameters|Training loss|BLEU (covost)|BLEU (epst)|BLEU (mtedx) +---|---|---|---|---|--- +None||3.954|24.984|23.962|24.448 +ConcatAugment|rate = 0.25, max_tokens = 3000, attempts = 5|3.940|25.322|26.124|26.19 +BabbleAugment|rate = 0.25, MUSAN speech, snr_min = (-5), snr_max = 5|3.957|24.226|23.186|22.368| +BackgroundNoiseAugment|rate = 0.1, MUSAN noises, snr_min = (-10), snr_max = 10|3.955|24.745|23.513|23.819 +MusicAugment|rate = 0.25, MUSAN music, snr_min = 0, snr_max = 20|3.954|25.096|24.301|23.341| +SporadicNoiseAugment|rate = 0.1, noise_rate = 0.25, MUSAN noises, snr_min = 10, snr_max = 35|3.954|24.924|23.951|23.484| +MusicAugment + BabbleAugment + BackgroundNoiseAugment + SporadicNoiseAugment|as above, except limited rates to sum to 0.25: music (0.074), background (0.029), babble (0.074), sporadic (0.029)|3.953|24.874|23.675|24.249| +NoisyOverlapAugment|rate = 0.25, mixing_noise_rate = 0.5, MUSAN noises, utterance_snr_min = (-10), utterance_snr_max = 0, noise_snr_min = (-5), noise_snr_max = 20|3.954|24.949|24.015|23.768| + +### Evaluation on data with music noise added at SNR = (-5) - 5 +Augmentation in training data|Training loss|BLEU (covost)|BLEU (epst)|BLEU (mtedx) +---|---|---|---|--- +None|3.954|15.785|21.105|16.944 +ConcatAugment|3.940|17.186|23.255|18.24 +BabbleAugment|3.957|19.158|22.064|17.116 +BackgroundNoiseAugment|3.955|17.777|22.0|17.535| +MusicAugment|3.954|20.345|23.126|19.433| +SporadicNoiseAugment|3.954|15.927|21.382|14.736| +MusicAugment + BabbleAugment + BackgroundNoiseAugment + SporadicNoiseAugment|3.953|19.724|22.659|17.852| +NoisyOverlapAugment|3.954|17.49|22.142|17.207| + +### Evaluation on data with babble noise added at SNR = (-5) - 5 +Augmentation in training data|Training loss|BLEU (covost)|BLEU (epst)|BLEU (mtedx) +---|---|---|---|--- +None|3.954|4.092|13.514|5.13 +ConcatAugment|3.940|5.493|15.835|6.893 +BabbleAugment|3.957|16.12|21.097|13.996 +BackgroundNoiseAugment|3.955|4.691|15.784|5.982 +MusicAugment|3.954|8.06|17.764|9.008 +SporadicNoiseAugment|3.954|4.009|13.935|4.814 +MusicAugment + BabbleAugment + BackgroundNoiseAugment + SporadicNoiseAugment|3.953|14.692|20.882|14.45 +NoisyOverlapAugment|3.954|4.032|16.434|7.284 + +### Evaluation on data with sporadic noise added at SNR = (-5) - 5 +Augmentation in training data|Training loss|BLEU (covost)|BLEU (epst)|BLEU (mtedx) +---|---|---|---|--- +None|3.954|23.778|23.745|22.748 +ConcatAugment|3.940|24.239|25.907|25.723 +BabbleAugment|3.957|23.42|23.048|21.076 +BackgroundNoiseAugment|3.955|23.998|23.467|22.494 +MusicAugment|3.954|24.142|24.181|19.143 +SporadicNoiseAugment|3.954|23.97|23.894|22.61 +MusicAugment + BabbleAugment + BackgroundNoiseAugment + SporadicNoiseAugment|3.953|24.118|23.59|23.717 +NoisyOverlapAugment|3.954|24.265|24.103|23.167 + +### Evaluation on data with background noise added at SNR = (-5) - 5 +Augmentation in training data|Training loss|BLEU (covost)|BLEU (epst)|BLEU (mtedx) +---|---|---|---|--- +None|3.954|20.201|22.525|19.66 +ConcatAugment|3.940|20.904|24.706|21.353 +BabbleAugment|3.957|20.687|22.374|18.907 +BackgroundNoiseAugment|3.955|21.574|22.998|20.043 +MusicAugment|3.954|21.65|23.529|19.87 +SporadicNoiseAugment|3.954|20.578|22.577|19.096 +MusicAugment + BabbleAugment + BackgroundNoiseAugment + SporadicNoiseAugment|3.953|21.811|23.144|20.986 +NoisyOverlapAugment|3.954|21.312|23.153|20.302 + +### Evaluation on data with all four types of noises added at SNR = (-5) - 5, each applied with prob 0.5 +Augmentation in training data|Training loss|BLEU (covost)|BLEU (epst)|BLEU (mtedx) +---|---|---|---|--- +None|3.954|10.895|19.319|12.748 +ConcatAugment|3.940|13.517|21.658|15.428 +BabbleAugment|3.957|18.09|21.384|16.018 +BackgroundNoiseAugment|3.955|12.837|20.719|13.933 +MusicAugment|3.954|16.589|21.823|15.927 +SporadicNoiseAugment|3.954|11.238|19.91|13.31 +MusicAugment + BabbleAugment + BackgroundNoiseAugment + SporadicNoiseAugment|3.953|18.636|21.935|17.845 +NoisyOverlapAugment|3.954|12.829|20.856|15.048 + +### Evaluation on data with noisy overlap augment +Augmentation in training data|Training loss|BLEU (covost)|BLEU (epst)|BLEU (mtedx) +---|---|---|---|--- +None|3.954|21.245|22.24|20.994 +ConcatAugment|3.940|21.611|24.247|23.068 +BabbleAugment|3.957|21.867|21.987|20.099| +BackgroundNoiseAugment|3.955|21.533|21.806|19.717| +MusicAugment|3.954|21.823|22.643|20.847| +SporadicNoiseAugment|3.954|21.373|22.381|20.672| +MusicAugment + BabbleAugment + BackgroundNoiseAugment + SporadicNoiseAugment|3.953|22.206|22.414|21.375| +NoisyOverlapAugment|3.954|23.371|23.396|22.627| + +## Using transforms +Transforms are configurable. + +1. Please pay careful attention to the type of transform you are applying. + - `concataugment` and `noisyoverlapaugment` are instances of `AudioDatasetTransform` and should be listed in the config under `dataset_transforms`. + - `musicaugment`, `babbleaugment`, `sporadicnoiseaugment`, and `backgroundnoiseaugment` are instances of `AudioWaveformTransform` and should be listed under `waveform_transforms`. + - Instances of `AudioFeatureTransform` should be listed under `feature_transforms`. +2. Feel free to apply these augmentations in different contexts, e.g., you may use a `_train` or `_eval` flag to specify when the transform will be applied. If the dataset at hand contains `train` in its name, those transforms under the `_train` flag will be applied; else, the remaining transforms will be applied. + +For example, you would add this to your config to apply the musicaugment transform to a training dataset: +```yaml +musicaugment: + samples_path: ${MUSIC_PATH} + snr_min: 10 + snr_max: 15 + rate: 0.25 +waveform_transforms: + _train: + - musicaugment +``` +or add this to apply the concataugment transform: +```yaml +concataugment: + rate: 0.25 + max_tokens: 3000 + attempts: 5 +dataset_transforms: + _train: + - concataugment + ``` +You may also want to add multiple of one type of transform; here, we add multiple `AudioWaveformTransform`s: +```yaml +musicaugment: + samples_path: ${MUSIC_PATH} + snr_min: 5 + snr_max: 20 + rate: 0.25 +backgroundnoiseaugment: + samples_path: ${NOISES_PATH} + snr_min: 10 + snr_max: 20 + rate: 0.1 +sporadicnoiseaugment: + samples_path: ${NOISES_PATH} + snr_min: 5 + snr_max: 15 + rate: 0.1 + noise_rate: 0.25 +waveform_transforms: + _train: + - musicaugment + - backgroundnoiseaugment + - sporadicnoiseaugment +``` + +## Adding your own transforms +Note: We store transform implementations in `fairseq/data/audio/*_transforms` directories. You may refer to these as examples while implementing your own transform. + +### Step 1. Picking the right class for your transform +The integration into SpeechToTextDataset is quite different for each kind of transform, so it is important to understand which one is best suited to your purposes. + +**Feature transforms** +`AudioFeatureTransform` is a base class which allows **some transform to be applied to audio spectrograms** in the data loading step. One thing to note is that the source data is either saved as `np.ndarrays` or as audio files, and is to be returned either as features (spectrogram) or waveform. If and only if the data is to be returned as a spectrogram, then `AudioFeatureTransform`s will be applied. + +**Waveform transforms** +`AudioWaveformTransform` is a base class which allows some **transform to be applied to waveforms** in the data loading step. As mentioned above, there are two source and return types to data loading for this dataset. If and only if the data is saved in audio file format, then `AudioWaveformTransform`s will be applied, whichever return type is used. + +**Dataset transforms** +`AudioDatasetTransform` is a base class for transforms **based on more than one item in a dataset**, ex. concatenation of two random samples in a dataset. Rather than being applied in a consistent way, i.e., to all features or to all waveforms, the integration of a dataset transform is entirely specific. Adding a dataset transform requires actually editing the `fairseq/data/audio/speech_to_text_dataset.py` file. + +### Step 2. Setting up your transform (generic to all types of transforms) +Now that you know which kind of transform you would like to use, we are ready to implement it. This step is generic for all transform types, i.e., `TRANSFORM_TYPE` may be any of `feature`, `waveform`, or `dataset`. We will show how to build utterance concatenation (an `AudioDatasetTransform`) as an example. + +Import the base class and registration function for your transform. +```python +from fairseq.data.audio.dataset_transforms import ( + AudioDatasetTransform, + register_audio_dataset_transform +) +``` + +Define the class and register the transform. The name passed into the registration function is how your transform should be named in the config. +```python +@register_audio_dataset_transform("concataugment") +class ConcatAugment(AudioDatasetTransform): +``` + +We are now ready to add the basic important functions to our new class. In this example, `_DEFAULTS` refers to a dictionary with the default hyperparameter values that we defined. `from_config_dict` is called to instantiate the transform given hyperparameters from the config. +```python + @classmethod + def from_config_dict(cls, config=None): + _config = {} if config is None else config + return ConcatAugment( + _config.get("rate", _DEFAULTS["rate"]), + _config.get("max_tokens", _DEFAULTS["max_tokens"]), + _config.get("attempts", _DEFAULTS["attempts"]), + ) +``` +We edit the instantiation function `__init__` to track hyperparameters and do any setup work. +```python + def __init__( + self, + rate=_DEFAULTS["rate"], + max_tokens=_DEFAULTS["max_tokens"], + attempts=_DEFAULTS["attempts"], + ): + self.rate, self.max_tokens, self.attempts = rate, max_tokens, attempts +``` +Lastly `__repr__` gives how the transform will be reported in an output log. +```python + def __repr__(self): + return ( + self.__class__.__name__ + + "(" + + ", ".join( + [ + f"rate={self.rate}", + f"max_tokens={self.max_tokens}", + f"attempts={self.attempts}", + ] + ) + + ")" + ) +``` + +### Step 3. Adding the transform logic +At this point, we are ready to implement the actual transform logic. The flow from here is different for each of the three transforms, so follow the path that is relevant to you. +### ...for feature transforms +The final step is implementing the `__call__` function, which applies the transform logic and **returns** the spectrogram with transform applied. This supports and should take exactly **two arguments**: +- `self` +- `x` (np.ndarray): the spectrogram for one source sample. (This is a positional argument, so you can use another parameter name like `spectrogram` instead of `x`.) + +For example, this is the `__call__` function for GlobalCMVN (cepstral mean and variance normalization). +```python + def __call__(self, x): + x = np.subtract(x, self.mean) + x = np.divide(x, self.std) + return x + +``` +### ...for waveform transforms +The final step is implementing the `__call__` function, which applies the transform logic. This supports and should take exactly **three arguments**: +- `self` +- `source` (numpy.ndarray or torch.Tensor): source audio 2d waveform (channels x length) +- `sample_rate` (optional, defaults to None): sample rate of `source` + +`__call__` **returns**: +- transformed audio waveform +- sample rate of transformed audio waveform + +For example, this is the `__call__` function for augmentations in the Noise Augmentation Suite. +```python + def __call__(self, source, sample_rate=None): + if np.random.random() > self.rate: + return source + + noise = self._get_noise( + source.shape, always_2d=True, use_sample_rate=sample_rate + ) + return self._mix(source, noise, rand_uniform(self.snr_min, self.snr_max)), sample_rate +``` + +### ...for dataset transforms +Dataset transforms are extremely flexible, and implementation involves directly integrating them into `fairseq/data/audio/speech_to_text_dataset.py` in transform-specific ways. +There are two basic components: (1) check whether or not this transform is part of this dataset instance using `self.dataset_transforms.has_transform(TRANSFORM_CLS)`, and (2) if so, get the transform using `self.dataset_transforms.get_transform(TRANSFORM_CLS)` & apply it. +Due to the case-by-case specificity, it is easier to demonstrate this by examples. + +#### Example: NoisyOverlapAugment +This transform requires access to multiple items within the same batch at once. + +**Logic**: We still use the transform classes to keep away the transform logic. For example, `__call__` of `NoisyOverlapAugment` class takes a list of source tokens for items in a mini-batch, applies noise/utterance as dictated by the transform, and returns the list of transformed source tokens for items in the mini-batch. + +```python + def __call__(self, sources): + for i, source in enumerate(sources): + if np.random.random() > self.rate: + continue + + pri = source.numpy() + + # ... some transform code omitted + + pri[s_source : s_source + l] = np.add( + pri[s_source : s_source + l], np.multiply(scl, sec[s_sec : s_sec + l]) + ) + sources[i] = torch.from_numpy(pri).float() + + return sources +``` + +**Integration**: The `collater` function for `SpeechToTextDataset` is responsible for preparing a mini-batch for training, so we integrate NOAug through adding a few lines to the top of this function: +```python +def collater( + self, samples: List[SpeechToTextDatasetItem], return_order: bool = False +) -> Dict: + if len(samples) == 0: + return {} + indices = torch.tensor([x.index for x in samples], dtype=torch.long) + + sources = [x.source for x in samples] + + # NOAUG INTEGRATION BLOCK + # (1) Check whether or not this transform is part of this dataset instance + has_NOAug = self.dataset_transforms.has_transform(NoisyOverlapAugment) + # (2) If so, get & apply the transform + if has_NOAug and self.cfg.use_audio_input: + NOAug = self.dataset_transforms.get_transform(NoisyOverlapAugment) + sources = NOAug(sources) + + frames = _collate_frames(sources, self.cfg.use_audio_input) + # sort samples by descending number of frames + n_frames = torch.tensor([x.size(0) for x in sources], dtype=torch.long) + n_frames, order = n_frames.sort(descending=True) + indices = indices.index_select(0, order) + frames = frames.index_select(0, order) + + # ... rest of function +``` + +#### Example: ConcatAugment +This transform requires access to another item within the dataset at once. + +**Logic**: We abstract the logic for picking indices to concatenate by adding a `find_indices` function to the `ConcatAugment` class, which takes one index in the dataset and finds a compatible second index to concatenate source and target tokens. +```python + def find_indices(self, index: int, n_frames: List[int], n_samples: int): + # skip conditions: application rate, max_tokens limit exceeded + if np.random.random() > self.rate: + return [index] + if self.max_tokens and n_frames[index] > self.max_tokens: + return [index] + + # pick second sample to concatenate + for _ in range(self.attempts): + index2 = np.random.randint(0, n_samples) + if index2 != index and ( + not self.max_tokens + or n_frames[index] + n_frames[index2] < self.max_tokens + ): + return [index, index2] + + return [index] +``` + +**Integration**: `SpeechToTextDataset` uses a custom `__getitem__(self, index)` function (called in the background when you write `dataset[i]`). We edited this function (as well as `_get_source_audio` and `get_tokenized_tgt_text`) to achieve the desired transform effect where accessing `dataset[i]` will return a `SpeechToTextDatasetItem` where `source=source[i]+source[j]` and `target=target[i]+target[j]`. +```python +def __getitem__(self, index: int) -> SpeechToTextDatasetItem: + + # CONCATAUGMENT INTEGRATION BLOCK + # (1) Check whether or not this transform is part of this dataset instance + has_concat = self.dataset_transforms.has_transform(ConcatAugment) + # (2) If so, get & apply the transform + if has_concat: + concat = self.dataset_transforms.get_transform(ConcatAugment) + indices = concat.find_indices(index, self.n_frames, self.n_samples) + + source = self._get_source_audio(indices if has_concat else index) + source = self.pack_frames(source) + + target = None + if self.tgt_texts is not None: + tokenized = self.get_tokenized_tgt_text(indices if has_concat else index) + target = self.tgt_dict.encode_line( + + # ... rest of function +``` diff --git a/fairseq/data/audio/__init__.py b/fairseq/data/audio/__init__.py index e69de29bb2..dff90fadfc 100644 --- a/fairseq/data/audio/__init__.py +++ b/fairseq/data/audio/__init__.py @@ -0,0 +1,93 @@ +from abc import ABC, abstractmethod +from typing import Dict, Optional +import importlib +import os +import numpy as np + + +class AudioTransform(ABC): + @classmethod + @abstractmethod + def from_config_dict(cls, config: Optional[Dict] = None): + pass + + +class CompositeAudioTransform(AudioTransform): + def _from_config_dict( + cls, + transform_type, + get_audio_transform, + composite_cls, + config=None, + return_empty=False, + ): + _config = {} if config is None else config + _transforms = _config.get(f"{transform_type}_transforms") + + if _transforms is None: + if return_empty: + _transforms = [] + else: + return None + + transforms = [ + get_audio_transform(_t).from_config_dict(_config.get(_t)) + for _t in _transforms + ] + return composite_cls(transforms) + + def __init__(self, transforms): + self.transforms = [t for t in transforms if t is not None] + + def __call__(self, x): + for t in self.transforms: + x = t(x) + return x + + def __repr__(self): + format_string = ( + [self.__class__.__name__ + "("] + + [f" {t.__repr__()}" for t in self.transforms] + + [")"] + ) + return "\n".join(format_string) + + +def register_audio_transform(name, cls_type, registry, class_names): + def register_audio_transform_cls(cls): + if name in registry: + raise ValueError(f"Cannot register duplicate transform ({name})") + if not issubclass(cls, cls_type): + raise ValueError( + f"Transform ({name}: {cls.__name__}) must extend " + f"{cls_type.__name__}" + ) + if cls.__name__ in class_names: + raise ValueError( + f"Cannot register audio transform with duplicate " + f"class name ({cls.__name__})" + ) + registry[name] = cls + class_names.add(cls.__name__) + return cls + + return register_audio_transform_cls + + +def import_transforms(transforms_dir, transform_type): + for file in os.listdir(transforms_dir): + path = os.path.join(transforms_dir, file) + if ( + not file.startswith("_") + and not file.startswith(".") + and (file.endswith(".py") or os.path.isdir(path)) + ): + name = file[: file.find(".py")] if file.endswith(".py") else file + importlib.import_module( + f"fairseq.data.audio.{transform_type}_transforms." + name + ) + + +# Utility fn for uniform numbers in transforms +def rand_uniform(a, b): + return np.random.uniform() * (b - a) + a diff --git a/fairseq/data/audio/audio_utils.py b/fairseq/data/audio/audio_utils.py index 34b4d73fd2..590a7493ae 100644 --- a/fairseq/data/audio/audio_utils.py +++ b/fairseq/data/audio/audio_utils.py @@ -13,6 +13,8 @@ import torch import torch.nn.functional as F +from fairseq.data.audio.waveform_transforms import CompositeAudioWaveformTransform + SF_AUDIO_FILE_EXTENSIONS = {".wav", ".flac", ".ogg"} FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS = {".npy", ".wav", ".flac", ".ogg"} @@ -73,6 +75,7 @@ def get_waveform( always_2d: bool = True, output_sample_rate: Optional[int] = None, normalize_volume: bool = False, + waveform_transforms: Optional[CompositeAudioWaveformTransform] = None, ) -> Tuple[np.ndarray, int]: """Get the waveform and sample rate of a 16-bit WAV/FLAC/OGG Vorbis audio. @@ -113,16 +116,25 @@ def get_waveform( if not normalization: waveform *= 2**15 # denormalized to 16-bit signed integers + + if waveform_transforms is not None: + waveform, sample_rate = waveform_transforms(waveform, sample_rate) + if not always_2d: waveform = waveform.squeeze(axis=0) + return waveform, sample_rate -def get_features_from_npy_or_audio(path): +def get_features_from_npy_or_audio(path, waveform_transforms=None): ext = Path(path).suffix if ext not in FEATURE_OR_SF_AUDIO_FILE_EXTENSIONS: raise ValueError(f'Unsupported file format for "{path}"') - return np.load(path) if ext == ".npy" else get_fbank(path) + return ( + np.load(path) + if ext == ".npy" + else get_fbank(path, waveform_transforms=waveform_transforms) + ) def get_features_or_waveform_from_stored_zip( @@ -131,6 +143,7 @@ def get_features_or_waveform_from_stored_zip( byte_size, need_waveform=False, use_sample_rate=None, + waveform_transforms=None, ): assert path.endswith(".zip") data = read_from_stored_zip(path, byte_offset, byte_size) @@ -139,16 +152,23 @@ def get_features_or_waveform_from_stored_zip( features_or_waveform = np.load(f) elif is_sf_audio_data(data): features_or_waveform = ( - get_waveform(f, always_2d=False, output_sample_rate=use_sample_rate)[0] + get_waveform( + f, + always_2d=False, + output_sample_rate=use_sample_rate, + waveform_transforms=waveform_transforms, + )[0] if need_waveform - else get_fbank(f) + else get_fbank(f, waveform_transforms=waveform_transforms) ) else: raise ValueError(f'Unknown file format for "{path}"') return features_or_waveform -def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=None): +def get_features_or_waveform( + path: str, need_waveform=False, use_sample_rate=None, waveform_transforms=None +): """Get speech features from .npy file or waveform from .wav/.flac file. The file may be inside an uncompressed ZIP file and is accessed via byte offset and length. @@ -166,9 +186,14 @@ def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=Non if len(slice_ptr) == 0: if need_waveform: return get_waveform( - _path, always_2d=False, output_sample_rate=use_sample_rate + _path, + always_2d=False, + output_sample_rate=use_sample_rate, + waveform_transforms=waveform_transforms, )[0] - return get_features_from_npy_or_audio(_path) + return get_features_from_npy_or_audio( + _path, waveform_transforms=waveform_transforms + ) elif len(slice_ptr) == 2: features_or_waveform = get_features_or_waveform_from_stored_zip( _path, @@ -176,6 +201,7 @@ def get_features_or_waveform(path: str, need_waveform=False, use_sample_rate=Non slice_ptr[1], need_waveform=need_waveform, use_sample_rate=use_sample_rate, + waveform_transforms=waveform_transforms, ) else: raise ValueError(f"Invalid path: {path}") @@ -223,12 +249,16 @@ def _get_torchaudio_fbank( return None -def get_fbank(path_or_fp: Union[str, BinaryIO], n_bins=80) -> np.ndarray: +def get_fbank( + path_or_fp: Union[str, BinaryIO], n_bins=80, waveform_transforms=None +) -> np.ndarray: """Get mel-filter bank features via PyKaldi or TorchAudio. Prefer PyKaldi (faster CPP implementation) to TorchAudio (Python implementation). Note that Kaldi/TorchAudio requires 16-bit signed integers as inputs and hence the waveform should not be normalized.""" - waveform, sample_rate = get_waveform(path_or_fp, normalization=False) + waveform, sample_rate = get_waveform( + path_or_fp, normalization=False, waveform_transforms=waveform_transforms + ) features = _get_kaldi_fbank(waveform, sample_rate, n_bins) if features is None: diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index fba36dfcf0..1fcf419d7a 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -3,12 +3,17 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. from argparse import Namespace +from copy import deepcopy from pathlib import Path +import logging from typing import Dict, Optional from fairseq.data import Dictionary +logger = logging.getLogger(__name__) + + def get_config_from_yaml(yaml_path: Path): try: import yaml @@ -128,19 +133,46 @@ def audio_root(self): the root path. Set this to empty string when using absolute paths.""" return self.config.get("audio_root", "") - def get_feature_transforms(self, split, is_train): + def get_transforms(self, transform_type, split, is_train): """Split-specific feature transforms. Allowing train set wildcard `_train`, evaluation set wildcard `_eval` and general wildcard `*` for matching.""" from copy import deepcopy cfg = deepcopy(self.config) - _cur = cfg.get("transforms", {}) + _cur = cfg.get(f"{transform_type}transforms", {}) cur = _cur.get(split) cur = _cur.get("_train") if cur is None and is_train else cur cur = _cur.get("_eval") if cur is None and not is_train else cur cur = _cur.get("*") if cur is None else cur - cfg["transforms"] = cur + return cur + + def get_feature_transforms(self, split, is_train): + cfg = deepcopy(self.config) + # TODO: deprecate transforms + cur = self.get_transforms("", split, is_train) + if cur is not None: + logger.warning( + "Auto converting transforms into feature_transforms, " + "but transforms will be deprecated in the future. Please " + "update this in the config." + ) + ft_transforms = self.get_transforms("feature_", split, is_train) + if ft_transforms: + cur.extend(ft_transforms) + else: + cur = self.get_transforms("feature_", split, is_train) + cfg["feature_transforms"] = cur + return cfg + + def get_waveform_transforms(self, split, is_train): + cfg = deepcopy(self.config) + cfg["waveform_transforms"] = self.get_transforms("waveform_", split, is_train) + return cfg + + def get_dataset_transforms(self, split, is_train): + cfg = deepcopy(self.config) + cfg["dataset_transforms"] = self.get_transforms("dataset_", split, is_train) return cfg @property @@ -178,7 +210,13 @@ def bpe_tokenizer(self) -> Dict: def input_transformed_channels(self): """The number of channels in the audio after feature transforms""" # TODO: move this into individual transforms + # TODO: deprecate transforms _cur = self.config.get("transforms", {}) + ft_transforms = self.config.get("feature_transforms", {}) + if _cur and ft_transforms: + _cur.update(ft_transforms) + else: + _cur = self.config.get("feature_transforms", {}) cur = _cur.get("_train", []) _channels = self.input_channels diff --git a/fairseq/data/audio/dataset_transforms/__init__.py b/fairseq/data/audio/dataset_transforms/__init__.py new file mode 100644 index 0000000000..b24c6f731f --- /dev/null +++ b/fairseq/data/audio/dataset_transforms/__init__.py @@ -0,0 +1,53 @@ +import os +from fairseq.data.audio import ( + AudioTransform, + CompositeAudioTransform, + import_transforms, + register_audio_transform, +) + + +class AudioDatasetTransform(AudioTransform): + pass + + +AUDIO_DATASET_TRANSFORM_REGISTRY = {} +AUDIO_DATASET_TRANSFORM_CLASS_NAMES = set() + + +def get_audio_dataset_transform(name): + return AUDIO_DATASET_TRANSFORM_REGISTRY[name] + + +def register_audio_dataset_transform(name): + return register_audio_transform( + name, + AudioDatasetTransform, + AUDIO_DATASET_TRANSFORM_REGISTRY, + AUDIO_DATASET_TRANSFORM_CLASS_NAMES, + ) + + +import_transforms(os.path.dirname(__file__), "dataset") + + +class CompositeAudioDatasetTransform(CompositeAudioTransform): + @classmethod + def from_config_dict(cls, config=None): + return super()._from_config_dict( + cls, + "dataset", + get_audio_dataset_transform, + CompositeAudioDatasetTransform, + config, + return_empty=True, + ) + + def get_transform(self, cls): + for t in self.transforms: + if isinstance(t, cls): + return t + return None + + def has_transform(self, cls): + return self.get_transform(cls) is not None diff --git a/fairseq/data/audio/dataset_transforms/concataugment.py b/fairseq/data/audio/dataset_transforms/concataugment.py new file mode 100644 index 0000000000..0b632ccf2b --- /dev/null +++ b/fairseq/data/audio/dataset_transforms/concataugment.py @@ -0,0 +1,61 @@ +from typing import List +import numpy as np + +from fairseq.data.audio.dataset_transforms import ( + AudioDatasetTransform, + register_audio_dataset_transform, +) + +_DEFAULTS = {"rate": 0.25, "max_tokens": 3000, "attempts": 5} + + +@register_audio_dataset_transform("concataugment") +class ConcatAugment(AudioDatasetTransform): + @classmethod + def from_config_dict(cls, config=None): + _config = {} if config is None else config + return ConcatAugment( + _config.get("rate", _DEFAULTS["rate"]), + _config.get("max_tokens", _DEFAULTS["max_tokens"]), + _config.get("attempts", _DEFAULTS["attempts"]), + ) + + def __init__( + self, + rate=_DEFAULTS["rate"], + max_tokens=_DEFAULTS["max_tokens"], + attempts=_DEFAULTS["attempts"], + ): + self.rate, self.max_tokens, self.attempts = rate, max_tokens, attempts + + def __repr__(self): + return ( + self.__class__.__name__ + + "(" + + ", ".join( + [ + f"rate={self.rate}", + f"max_tokens={self.max_tokens}", + f"attempts={self.attempts}", + ] + ) + + ")" + ) + + def find_indices(self, index: int, n_frames: List[int], n_samples: int): + # skip conditions: application rate, max_tokens limit exceeded + if np.random.random() > self.rate: + return [index] + if self.max_tokens and n_frames[index] > self.max_tokens: + return [index] + + # pick second sample to concatenate + for _ in range(self.attempts): + index2 = np.random.randint(0, n_samples) + if index2 != index and ( + not self.max_tokens + or n_frames[index] + n_frames[index2] < self.max_tokens + ): + return [index, index2] + + return [index] diff --git a/fairseq/data/audio/dataset_transforms/noisyoverlapaugment.py b/fairseq/data/audio/dataset_transforms/noisyoverlapaugment.py new file mode 100644 index 0000000000..e9ebec2388 --- /dev/null +++ b/fairseq/data/audio/dataset_transforms/noisyoverlapaugment.py @@ -0,0 +1,105 @@ +import numpy as np +import torch + +from fairseq.data.audio import rand_uniform +from fairseq.data.audio.dataset_transforms import ( + AudioDatasetTransform, + register_audio_dataset_transform, +) +from fairseq.data.audio.waveform_transforms.noiseaugment import ( + NoiseAugmentTransform, +) + +_DEFAULTS = { + "rate": 0.25, + "mixing_noise_rate": 0.1, + "noise_path": "", + "noise_snr_min": -5, + "noise_snr_max": 5, + "utterance_snr_min": -5, + "utterance_snr_max": 5, +} + + +@register_audio_dataset_transform("noisyoverlapaugment") +class NoisyOverlapAugment(AudioDatasetTransform): + @classmethod + def from_config_dict(cls, config=None): + _config = {} if config is None else config + return NoisyOverlapAugment( + _config.get("rate", _DEFAULTS["rate"]), + _config.get("mixing_noise_rate", _DEFAULTS["mixing_noise_rate"]), + _config.get("noise_path", _DEFAULTS["noise_path"]), + _config.get("noise_snr_min", _DEFAULTS["noise_snr_min"]), + _config.get("noise_snr_max", _DEFAULTS["noise_snr_max"]), + _config.get("utterance_snr_min", _DEFAULTS["utterance_snr_min"]), + _config.get("utterance_snr_max", _DEFAULTS["utterance_snr_max"]), + ) + + def __init__( + self, + rate=_DEFAULTS["rate"], + mixing_noise_rate=_DEFAULTS["mixing_noise_rate"], + noise_path=_DEFAULTS["noise_path"], + noise_snr_min=_DEFAULTS["noise_snr_min"], + noise_snr_max=_DEFAULTS["noise_snr_max"], + utterance_snr_min=_DEFAULTS["utterance_snr_min"], + utterance_snr_max=_DEFAULTS["utterance_snr_max"], + ): + self.rate = rate + self.mixing_noise_rate = mixing_noise_rate + self.noise_shaper = NoiseAugmentTransform(noise_path) + self.noise_snr_min = noise_snr_min + self.noise_snr_max = noise_snr_max + self.utterance_snr_min = utterance_snr_min + self.utterance_snr_max = utterance_snr_max + + def __repr__(self): + return ( + self.__class__.__name__ + + "(" + + ", ".join( + [ + f"rate={self.rate}", + f"mixing_noise_rate={self.mixing_noise_rate}", + f"noise_snr_min={self.noise_snr_min}", + f"noise_snr_max={self.noise_snr_max}", + f"utterance_snr_min={self.utterance_snr_min}", + f"utterance_snr_max={self.utterance_snr_max}", + ] + ) + + ")" + ) + + def __call__(self, sources): + for i, source in enumerate(sources): + if np.random.random() > self.rate: + continue + + pri = source.numpy() + + if np.random.random() > self.mixing_noise_rate: + sec = sources[np.random.randint(0, len(sources))].numpy() + snr = rand_uniform(self.utterance_snr_min, self.utterance_snr_max) + else: + sec = self.noise_shaper.pick_sample(source.shape) + snr = rand_uniform(self.noise_snr_min, self.noise_snr_max) + + L1 = pri.shape[-1] + L2 = sec.shape[-1] + l = np.random.randint(0, min(round(L1 / 2), L2)) # mix len + s_source = np.random.randint(0, L1 - l) + s_sec = np.random.randint(0, L2 - l) + + get_power = lambda x: np.mean(x**2) + if get_power(sec) == 0: + continue + + scl = np.sqrt(get_power(pri) / (np.power(10, snr / 10) * get_power(sec))) + + pri[s_source : s_source + l] = np.add( + pri[s_source : s_source + l], np.multiply(scl, sec[s_sec : s_sec + l]) + ) + sources[i] = torch.from_numpy(pri).float() + + return sources diff --git a/fairseq/data/audio/feature_transforms/__init__.py b/fairseq/data/audio/feature_transforms/__init__.py index 359fa06971..d295013b90 100644 --- a/fairseq/data/audio/feature_transforms/__init__.py +++ b/fairseq/data/audio/feature_transforms/__init__.py @@ -1,82 +1,43 @@ -import importlib import os -from abc import ABC, abstractmethod -from typing import Dict, Optional +from fairseq.data.audio import ( + AudioTransform, + CompositeAudioTransform, + import_transforms, + register_audio_transform, +) -class AudioFeatureTransform(ABC): - @classmethod - @abstractmethod - def from_config_dict(cls, config: Optional[Dict] = None): - pass +class AudioFeatureTransform(AudioTransform): + pass AUDIO_FEATURE_TRANSFORM_REGISTRY = {} AUDIO_FEATURE_TRANSFORM_CLASS_NAMES = set() -def register_audio_feature_transform(name): - def register_audio_feature_transform_cls(cls): - if name in AUDIO_FEATURE_TRANSFORM_REGISTRY: - raise ValueError(f"Cannot register duplicate transform ({name})") - if not issubclass(cls, AudioFeatureTransform): - raise ValueError( - f"Transform ({name}: {cls.__name__}) must extend " - "AudioFeatureTransform" - ) - if cls.__name__ in AUDIO_FEATURE_TRANSFORM_CLASS_NAMES: - raise ValueError( - f"Cannot register audio feature transform with duplicate " - f"class name ({cls.__name__})" - ) - AUDIO_FEATURE_TRANSFORM_REGISTRY[name] = cls - AUDIO_FEATURE_TRANSFORM_CLASS_NAMES.add(cls.__name__) - return cls - - return register_audio_feature_transform_cls - - def get_audio_feature_transform(name): return AUDIO_FEATURE_TRANSFORM_REGISTRY[name] -transforms_dir = os.path.dirname(__file__) -for file in os.listdir(transforms_dir): - path = os.path.join(transforms_dir, file) - if ( - not file.startswith("_") - and not file.startswith(".") - and (file.endswith(".py") or os.path.isdir(path)) - ): - name = file[: file.find(".py")] if file.endswith(".py") else file - importlib.import_module("fairseq.data.audio.feature_transforms." + name) - +def register_audio_feature_transform(name): + return register_audio_transform( + name, + AudioFeatureTransform, + AUDIO_FEATURE_TRANSFORM_REGISTRY, + AUDIO_FEATURE_TRANSFORM_CLASS_NAMES, + ) -class CompositeAudioFeatureTransform(AudioFeatureTransform): - @classmethod - def from_config_dict(cls, config=None): - _config = {} if config is None else config - _transforms = _config.get("transforms") - if _transforms is None: - return None - transforms = [ - get_audio_feature_transform(_t).from_config_dict(_config.get(_t)) - for _t in _transforms - ] - return CompositeAudioFeatureTransform(transforms) - def __init__(self, transforms): - self.transforms = [t for t in transforms if t is not None] +import_transforms(os.path.dirname(__file__), "feature") - def __call__(self, x): - for t in self.transforms: - x = t(x) - return x - def __repr__(self): - format_string = ( - [self.__class__.__name__ + "("] - + [f" {t.__repr__()}" for t in self.transforms] - + [")"] +class CompositeAudioFeatureTransform(CompositeAudioTransform): + @classmethod + def from_config_dict(cls, config=None): + return super()._from_config_dict( + cls, + "feature", + get_audio_feature_transform, + CompositeAudioFeatureTransform, + config, ) - return "\n".join(format_string) diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index 53fd2ea203..ce92750946 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -10,7 +10,7 @@ from collections import defaultdict from dataclasses import dataclass from pathlib import Path -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Union import numpy as np import torch @@ -21,6 +21,12 @@ from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.data_cfg import S2TDataConfig from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform +from fairseq.data.audio.waveform_transforms import CompositeAudioWaveformTransform +from fairseq.data.audio.dataset_transforms import CompositeAudioDatasetTransform +from fairseq.data.audio.dataset_transforms.concataugment import ConcatAugment +from fairseq.data.audio.dataset_transforms.noisyoverlapaugment import ( + NoisyOverlapAugment, +) logger = logging.getLogger(__name__) @@ -46,6 +52,12 @@ def _collate_frames( return out +def _is_int_or_np_int(n): + return isinstance(n, int) or ( + isinstance(n, np.generic) and isinstance(n.item(), int) + ) + + @dataclass class SpeechToTextDatasetItem(object): index: int @@ -102,6 +114,20 @@ def __init__( self.feature_transforms = CompositeAudioFeatureTransform.from_config_dict( self.cfg.get_feature_transforms(split, is_train_split) ) + self.waveform_transforms = CompositeAudioWaveformTransform.from_config_dict( + self.cfg.get_waveform_transforms(split, is_train_split) + ) + # TODO: add these to data_cfg.py + self.dataset_transforms = CompositeAudioDatasetTransform.from_config_dict( + self.cfg.get_dataset_transforms(split, is_train_split) + ) + + # check proper usage of transforms + if self.feature_transforms and self.cfg.use_audio_input: + logger.warning( + "Feature transforms will not be applied. To use feature transforms, " + "set use_audio_input as False in config." + ) self.pre_tokenizer = pre_tokenizer self.bpe_tokenizer = bpe_tokenizer @@ -136,8 +162,11 @@ def __repr__(self): self.__class__.__name__ + f'(split="{self.split}", n_samples={self.n_samples:_}, ' f"prepend_tgt_lang_tag={self.cfg.prepend_tgt_lang_tag}, " - f"shuffle={self.shuffle}, transforms={self.feature_transforms}, " - f"n_frames_per_step={self.n_frames_per_step}" + f"n_frames_per_step={self.n_frames_per_step}, " + f"shuffle={self.shuffle}, " + f"feature_transforms={self.feature_transforms}, " + f"waveform_transforms={self.waveform_transforms}, " + f"dataset_transforms={self.dataset_transforms})" ) @classmethod @@ -157,8 +186,13 @@ def check_tgt_lang_tag(self): def tokenize(cls, tokenizer, text: str): return text if tokenizer is None else tokenizer.encode(text) - def get_tokenized_tgt_text(self, index: int): - text = self.tokenize(self.pre_tokenizer, self.tgt_texts[index]) + def get_tokenized_tgt_text(self, index: Union[int, List[int]]): + if _is_int_or_np_int(index): + text = self.tgt_texts[index] + else: + text = " ".join([self.tgt_texts[i] for i in index]) + + text = self.tokenize(self.pre_tokenizer, text) text = self.tokenize(self.bpe_tokenizer, text) return text @@ -175,12 +209,37 @@ def get_lang_tag_idx(cls, lang: str, dictionary: Dictionary): assert lang_tag_idx != dictionary.unk() return lang_tag_idx - def _get_source_audio(self, index: int) -> torch.Tensor: - source = get_features_or_waveform( - self.audio_paths[index], - need_waveform=self.cfg.use_audio_input, - use_sample_rate=self.cfg.use_sample_rate, - ) + def _get_source_audio(self, index: Union[int, List[int]]) -> torch.Tensor: + """ + Gives source audio for given index with any relevant transforms + applied. For ConcatAug, source audios for given indices are + concatenated in given order. + Args: + index (int or List[int]): index—or in the case of ConcatAug, + indices—to pull the source audio for + Returns: + source audios concatenated for given indices with + relevant transforms appplied + """ + if _is_int_or_np_int(index): + source = get_features_or_waveform( + self.audio_paths[index], + need_waveform=self.cfg.use_audio_input, + use_sample_rate=self.cfg.use_sample_rate, + waveform_transforms=self.waveform_transforms, + ) + else: + source = np.concatenate( + [ + get_features_or_waveform( + self.audio_paths[i], + need_waveform=self.cfg.use_audio_input, + use_sample_rate=self.cfg.use_sample_rate, + waveform_transforms=self.waveform_transforms, + ) + for i in index + ] + ) if self.cfg.use_audio_input: source = torch.from_numpy(source).float() if self.cfg.standardize_audio: @@ -193,12 +252,17 @@ def _get_source_audio(self, index: int) -> torch.Tensor: return source def __getitem__(self, index: int) -> SpeechToTextDatasetItem: - source = self._get_source_audio(index) + has_concat = self.dataset_transforms.has_transform(ConcatAugment) + if has_concat: + concat = self.dataset_transforms.get_transform(ConcatAugment) + indices = concat.find_indices(index, self.n_frames, self.n_samples) + + source = self._get_source_audio(indices if has_concat else index) source = self.pack_frames(source) target = None if self.tgt_texts is not None: - tokenized = self.get_tokenized_tgt_text(index) + tokenized = self.get_tokenized_tgt_text(indices if has_concat else index) target = self.tgt_dict.encode_line( tokenized, add_if_not_exist=False, append_eos=self.append_eos ).long() @@ -231,9 +295,16 @@ def collater( if len(samples) == 0: return {} indices = torch.tensor([x.index for x in samples], dtype=torch.long) - frames = _collate_frames([x.source for x in samples], self.cfg.use_audio_input) + + sources = [x.source for x in samples] + has_NOAug = self.dataset_transforms.has_transform(NoisyOverlapAugment) + if has_NOAug and self.cfg.use_audio_input: + NOAug = self.dataset_transforms.get_transform(NoisyOverlapAugment) + sources = NOAug(sources) + + frames = _collate_frames(sources, self.cfg.use_audio_input) # sort samples by descending number of frames - n_frames = torch.tensor([x.source.size(0) for x in samples], dtype=torch.long) + n_frames = torch.tensor([x.size(0) for x in sources], dtype=torch.long) n_frames, order = n_frames.sort(descending=True) indices = indices.index_select(0, order) frames = frames.index_select(0, order) diff --git a/fairseq/data/audio/waveform_transforms/__init__.py b/fairseq/data/audio/waveform_transforms/__init__.py new file mode 100644 index 0000000000..57f8bb571b --- /dev/null +++ b/fairseq/data/audio/waveform_transforms/__init__.py @@ -0,0 +1,48 @@ +import os +from fairseq.data.audio import ( + AudioTransform, + CompositeAudioTransform, + import_transforms, + register_audio_transform, +) + + +class AudioWaveformTransform(AudioTransform): + pass + + +AUDIO_WAVEFORM_TRANSFORM_REGISTRY = {} +AUDIO_WAVEFORM_TRANSFORM_CLASS_NAMES = set() + + +def get_audio_waveform_transform(name): + return AUDIO_WAVEFORM_TRANSFORM_REGISTRY[name] + + +def register_audio_waveform_transform(name): + return register_audio_transform( + name, + AudioWaveformTransform, + AUDIO_WAVEFORM_TRANSFORM_REGISTRY, + AUDIO_WAVEFORM_TRANSFORM_CLASS_NAMES, + ) + + +import_transforms(os.path.dirname(__file__), "waveform") + + +class CompositeAudioWaveformTransform(CompositeAudioTransform): + @classmethod + def from_config_dict(cls, config=None): + return super()._from_config_dict( + cls, + "waveform", + get_audio_waveform_transform, + CompositeAudioWaveformTransform, + config, + ) + + def __call__(self, x, sample_rate): + for t in self.transforms: + x, sample_rate = t(x, sample_rate) + return x, sample_rate diff --git a/fairseq/data/audio/waveform_transforms/noiseaugment.py b/fairseq/data/audio/waveform_transforms/noiseaugment.py new file mode 100644 index 0000000000..401ce30943 --- /dev/null +++ b/fairseq/data/audio/waveform_transforms/noiseaugment.py @@ -0,0 +1,201 @@ +from pathlib import Path +import numpy as np +from math import ceil + +from fairseq.data.audio import rand_uniform +from fairseq.data.audio.waveform_transforms import ( + AudioWaveformTransform, + register_audio_waveform_transform, +) + +SNR_MIN = 5.0 +SNR_MAX = 15.0 +RATE = 0.25 + +NOISE_RATE = 1.0 +NOISE_LEN_MEAN = 0.2 +NOISE_LEN_STD = 0.05 + + +class NoiseAugmentTransform(AudioWaveformTransform): + @classmethod + def from_config_dict(cls, config=None): + _config = {} if config is None else config + return cls( + _config.get("samples_path", None), + _config.get("snr_min", SNR_MIN), + _config.get("snr_max", SNR_MAX), + _config.get("rate", RATE), + ) + + def __init__( + self, + samples_path: str, + snr_min: float = SNR_MIN, + snr_max: float = SNR_MAX, + rate: float = RATE, + ): + # Sanity checks + assert ( + samples_path + ), "need to provide path to audio samples for noise augmentation" + assert snr_max >= snr_min, f"empty signal-to-noise range ({snr_min}, {snr_max})" + assert rate >= 0 and rate <= 1, "rate should be a float between 0 to 1" + + self.paths = list(Path(samples_path).glob("**/*.wav")) # load music + self.n_samples = len(self.paths) + assert self.n_samples > 0, f"no audio files found in {samples_path}" + + self.snr_min = snr_min + self.snr_max = snr_max + self.rate = rate + + def __repr__(self): + return ( + self.__class__.__name__ + + "(" + + ", ".join( + [ + f"n_samples={self.n_samples}", + f"snr={self.snr_min}-{self.snr_max}dB", + f"rate={self.rate}", + ] + ) + + ")" + ) + + def pick_sample(self, goal_shape, always_2d=False, use_sample_rate=None): + from fairseq.data.audio.audio_utils import get_waveform + + path = self.paths[np.random.randint(0, self.n_samples)] + sample = get_waveform( + path, always_2d=always_2d, output_sample_rate=use_sample_rate + )[0] + + # Check dimensions match, else silently skip adding noise to sample + # NOTE: SHOULD THIS QUIT WITH AN ERROR? + is_2d = len(goal_shape) == 2 + if len(goal_shape) != sample.ndim or ( + is_2d and goal_shape[0] != sample.shape[0] + ): + return np.zeros(goal_shape) + + # Cut/repeat sample to size + len_dim = len(goal_shape) - 1 + n_repeat = ceil(goal_shape[len_dim] / sample.shape[len_dim]) + repeated = np.tile(sample, [1, n_repeat] if is_2d else n_repeat) + start = np.random.randint(0, repeated.shape[len_dim] - goal_shape[len_dim] + 1) + return ( + repeated[:, start : start + goal_shape[len_dim]] + if is_2d + else repeated[start : start + goal_shape[len_dim]] + ) + + def _mix(self, source, noise, snr): + get_power = lambda x: np.mean(x**2) + if get_power(noise): + scl = np.sqrt( + get_power(source) / (np.power(10, snr / 10) * get_power(noise)) + ) + else: + scl = 0 + return 1 * source + scl * noise + + def _get_noise(self, goal_shape, always_2d=False, use_sample_rate=None): + return self.pick_sample(goal_shape, always_2d, use_sample_rate) + + def __call__(self, source, sample_rate): + if np.random.random() > self.rate: + return source, sample_rate + + noise = self._get_noise( + source.shape, always_2d=True, use_sample_rate=sample_rate + ) + + return ( + self._mix(source, noise, rand_uniform(self.snr_min, self.snr_max)), + sample_rate, + ) + + +@register_audio_waveform_transform("musicaugment") +class MusicAugmentTransform(NoiseAugmentTransform): + pass + + +@register_audio_waveform_transform("backgroundnoiseaugment") +class BackgroundNoiseAugmentTransform(NoiseAugmentTransform): + pass + + +@register_audio_waveform_transform("babbleaugment") +class BabbleAugmentTransform(NoiseAugmentTransform): + def _get_noise(self, goal_shape, always_2d=False, use_sample_rate=None): + for i in range(np.random.randint(3, 8)): + speech = self.pick_sample(goal_shape, always_2d, use_sample_rate) + if i == 0: + agg_noise = speech + else: # SNR scaled by i (how many noise signals already in agg_noise) + agg_noise = self._mix(agg_noise, speech, i) + return agg_noise + + +@register_audio_waveform_transform("sporadicnoiseaugment") +class SporadicNoiseAugmentTransform(NoiseAugmentTransform): + @classmethod + def from_config_dict(cls, config=None): + _config = {} if config is None else config + return cls( + _config.get("samples_path", None), + _config.get("snr_min", SNR_MIN), + _config.get("snr_max", SNR_MAX), + _config.get("rate", RATE), + _config.get("noise_rate", NOISE_RATE), + _config.get("noise_len_mean", NOISE_LEN_MEAN), + _config.get("noise_len_std", NOISE_LEN_STD), + ) + + def __init__( + self, + samples_path: str, + snr_min: float = SNR_MIN, + snr_max: float = SNR_MAX, + rate: float = RATE, + noise_rate: float = NOISE_RATE, # noises per second + noise_len_mean: float = NOISE_LEN_MEAN, # length of noises in seconds + noise_len_std: float = NOISE_LEN_STD, + ): + super().__init__(samples_path, snr_min, snr_max, rate) + self.noise_rate = noise_rate + self.noise_len_mean = noise_len_mean + self.noise_len_std = noise_len_std + + def _get_noise(self, goal_shape, always_2d=False, use_sample_rate=None): + agg_noise = np.zeros(goal_shape) + len_dim = len(goal_shape) - 1 + is_2d = len(goal_shape) == 2 + + n_noises = round(self.noise_rate * goal_shape[len_dim] / use_sample_rate) + start_pointers = [ + round(rand_uniform(0, goal_shape[len_dim])) for _ in range(n_noises) + ] + + for start_pointer in start_pointers: + noise_shape = list(goal_shape) + len_seconds = np.random.normal(self.noise_len_mean, self.noise_len_std) + noise_shape[len_dim] = round(max(0, len_seconds) * use_sample_rate) + end_pointer = start_pointer + noise_shape[len_dim] + if end_pointer >= goal_shape[len_dim]: + continue + + noise = self.pick_sample(noise_shape, always_2d, use_sample_rate) + if is_2d: + agg_noise[:, start_pointer:end_pointer] = ( + agg_noise[:, start_pointer:end_pointer] + noise + ) + else: + agg_noise[start_pointer:end_pointer] = ( + agg_noise[start_pointer:end_pointer] + noise + ) + + return agg_noise From dec1e6b0447c1b7afda19ec330ed885b55f8a40a Mon Sep 17 00:00:00 2001 From: Michael Suo <darthsuo@gmail.com> Date: Fri, 9 Sep 2022 11:05:59 -0700 Subject: [PATCH 677/774] [fairseq] Guard call to `shape_as_tensor` with `is_in_onnx_export()` (#4708) This is a no-op in eager and in ONNX export, but it's better for other tracers if this is preserved as shapes directly instead of converted to a tensor. There is a little annoying code duplication with `torch.jit.is_scripting()`, which is unforunately necessary because we didn't implement compile-time short circuiting correctly in TorchScript lol. --- fairseq/modules/sinusoidal_positional_embedding.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fairseq/modules/sinusoidal_positional_embedding.py b/fairseq/modules/sinusoidal_positional_embedding.py index 4793ecfb52..5889e08d8b 100644 --- a/fairseq/modules/sinusoidal_positional_embedding.py +++ b/fairseq/modules/sinusoidal_positional_embedding.py @@ -65,7 +65,12 @@ def forward( positions: Optional[Any] = None, ): """Input is expected to be of size [bsz x seqlen].""" - bspair = torch.onnx.operators.shape_as_tensor(input) + if torch.jit.is_scripting(): + bspair = torch.onnx.operators.shape_as_tensor(input) + elif torch.onnx.is_in_onnx_export(): + bspair = torch.onnx.operators.shape_as_tensor(input) + else: + bspair = input.size() bsz, seq_len = bspair[0], bspair[1] max_pos = self.padding_idx + 1 + seq_len if self.weights is None or max_pos > self.weights.size(0): From 5ec3a27ea8dcd9fd11a6990dacd180e9ddd51f6c Mon Sep 17 00:00:00 2001 From: Junteng Jia <juntengjia@hotmail.com> Date: Fri, 9 Sep 2022 16:13:50 -0700 Subject: [PATCH 678/774] =?UTF-8?q?add=20an=20option=20to=20fetch=20datapo?= =?UTF-8?q?ints=20within=20a=20batch=20in=20an=20async=20manner,=20?= =?UTF-8?q?=E2=80=A6=20(#4710)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add an option to fetch datapoints within a batch in an async manner, which is helpful if the fetching is io bound * add an option to fetch datapoints within a batch in an async manner Co-authored-by: juntengjia <juntengjia@fb.com> --- fairseq/data/multi_corpus_dataset.py | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/fairseq/data/multi_corpus_dataset.py b/fairseq/data/multi_corpus_dataset.py index a3f47c720d..6f2fe074b2 100644 --- a/fairseq/data/multi_corpus_dataset.py +++ b/fairseq/data/multi_corpus_dataset.py @@ -3,12 +3,14 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import asyncio import logging import time from collections import OrderedDict from typing import Dict, List, Optional import numpy as np + from fairseq.data import data_utils from . import FairseqDataset @@ -161,16 +163,43 @@ def __len__(self): """ return self.total_num_instances - def __getitem__(self, index): + async def getitem(self, index): new_index, key = self._map_index(index) try: - item = self.datasets[key][new_index] + if hasattr(self.datasets[key], "getitem"): + item = await self.datasets[key].getitem(new_index) + else: + item = self.datasets[key][new_index] item["full_id"] = index return item except Exception as e: e.args = (f"Error from {key} dataset", *e.args) raise + def __getitem__(self, index): + return asyncio.run(self.getitem(index)) + + async def getitems(self, indices): + # initialize a bunch of everstore read operations + # wait in the end to reduce overhead + # very helpful if io is latency bounded + + max_concurrency = 32 + sem = asyncio.Semaphore(max_concurrency) + + async def controlled_getitem(index): + async with sem: + return await self.getitem(index) + + coroutines = [] + for index in indices: + coroutines.append(controlled_getitem(index)) + results = await asyncio.gather(*coroutines) + return results + + def __getitems__(self, indices): + return asyncio.run(self.getitems(indices)) + def collater(self, samples): """ If we are doing batch sampling, then pick the right collater to use. From 0cc475b9b4d2e491fcae8ca47c443f9a32976d97 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Thu, 15 Sep 2022 13:08:35 +0900 Subject: [PATCH 679/774] Reformat speech translation modules (#4707) * Reformat speech translation modules by black+isort * Fix argment parser for Conformer * Move convolution * Update XMTransformer * Remove unnecessary lines * Fix import --- fairseq/criterions/ctc.py | 7 +- .../label_smoothed_cross_entropy.py | 3 +- .../criterions/speech_to_speech_criterion.py | 1 + .../data/audio/speech_to_speech_dataset.py | 2 +- fairseq/data/audio/speech_to_text_dataset.py | 4 +- fairseq/models/speech_to_speech/__init__.py | 2 +- .../models/speech_to_speech/s2s_conformer.py | 36 +++++----- .../speech_to_speech/s2s_transformer.py | 11 +-- fairseq/models/speech_to_text/__init__.py | 2 +- fairseq/models/speech_to_text/berard.py | 1 + .../models/speech_to_text/convtransformer.py | 21 +++--- .../models/speech_to_text/hub_interface.py | 14 ++-- .../modules/augmented_memory_attention.py | 11 ++- .../speech_to_text/modules/convolution.py | 70 +++++++++++++++++++ .../models/speech_to_text/s2t_conformer.py | 41 ++++++++--- .../models/speech_to_text/s2t_transformer.py | 50 +------------ fairseq/models/speech_to_text/utils.py | 1 - .../models/speech_to_text/xm_transformer.py | 55 +++++++-------- fairseq/modules/conformer_layer.py | 6 +- fairseq/modules/espnet_multihead_attention.py | 2 + fairseq/speech_generator.py | 2 +- fairseq/tasks/speech_to_text.py | 3 +- 22 files changed, 188 insertions(+), 157 deletions(-) create mode 100644 fairseq/models/speech_to_text/modules/convolution.py diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index e966e47cf2..131d2f20c0 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -7,17 +7,18 @@ import math from argparse import Namespace from dataclasses import dataclass, field -from omegaconf import II from typing import Optional import torch import torch.nn.functional as F +from omegaconf import II + from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion -from fairseq.dataclass import FairseqDataclass from fairseq.data.data_utils import post_process -from fairseq.tasks import FairseqTask +from fairseq.dataclass import FairseqDataclass from fairseq.logging.meters import safe_round +from fairseq.tasks import FairseqTask @dataclass diff --git a/fairseq/criterions/label_smoothed_cross_entropy.py b/fairseq/criterions/label_smoothed_cross_entropy.py index cb43be0ca5..257466903f 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy.py +++ b/fairseq/criterions/label_smoothed_cross_entropy.py @@ -7,10 +7,11 @@ from dataclasses import dataclass, field import torch +from omegaconf import II + from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass -from omegaconf import II @dataclass diff --git a/fairseq/criterions/speech_to_speech_criterion.py b/fairseq/criterions/speech_to_speech_criterion.py index 7fba673d25..09bf745c19 100644 --- a/fairseq/criterions/speech_to_speech_criterion.py +++ b/fairseq/criterions/speech_to_speech_criterion.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import math + import torch from fairseq import metrics, utils diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py index 4b7f8b6824..fa31c3301f 100644 --- a/fairseq/data/audio/speech_to_speech_dataset.py +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -12,8 +12,8 @@ from fairseq.data import ConcatDataset, Dictionary from fairseq.data import data_utils as fairseq_data_utils -from fairseq.data.audio.data_cfg import S2SDataConfig from fairseq.data.audio.audio_utils import get_features_or_waveform +from fairseq.data.audio.data_cfg import S2SDataConfig from fairseq.data.audio.speech_to_text_dataset import ( SpeechToTextDataset, SpeechToTextDatasetCreator, diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index ce92750946..cc1221b132 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -20,13 +20,13 @@ from fairseq.data import data_utils as fairseq_data_utils from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.data_cfg import S2TDataConfig -from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform -from fairseq.data.audio.waveform_transforms import CompositeAudioWaveformTransform from fairseq.data.audio.dataset_transforms import CompositeAudioDatasetTransform from fairseq.data.audio.dataset_transforms.concataugment import ConcatAugment from fairseq.data.audio.dataset_transforms.noisyoverlapaugment import ( NoisyOverlapAugment, ) +from fairseq.data.audio.feature_transforms import CompositeAudioFeatureTransform +from fairseq.data.audio.waveform_transforms import CompositeAudioWaveformTransform logger = logging.getLogger(__name__) diff --git a/fairseq/models/speech_to_speech/__init__.py b/fairseq/models/speech_to_speech/__init__.py index 41be5e75c6..64ea7cda62 100644 --- a/fairseq/models/speech_to_speech/__init__.py +++ b/fairseq/models/speech_to_speech/__init__.py @@ -4,5 +4,5 @@ # LICENSE file in the root directory of this source tree. from .modules import * # noqa -from .s2s_transformer import * # noqa from .s2s_conformer import * # noqa +from .s2s_transformer import * # noqa diff --git a/fairseq/models/speech_to_speech/s2s_conformer.py b/fairseq/models/speech_to_speech/s2s_conformer.py index a232412cc5..ff890f4210 100644 --- a/fairseq/models/speech_to_speech/s2s_conformer.py +++ b/fairseq/models/speech_to_speech/s2s_conformer.py @@ -5,23 +5,17 @@ import logging from pathlib import Path + import torch from fairseq import checkpoint_utils -from fairseq.models import ( - register_model, - register_model_architecture, -) -from fairseq.data.audio.data_cfg import S2SDataConfig -from fairseq.models.speech_to_text import S2TConformerEncoder -from fairseq.models.speech_to_speech import ( - S2UTTransformerModel, +from fairseq.models import register_model, register_model_architecture +from fairseq.models.speech_to_speech.s2s_transformer import S2UTTransformerModel +from fairseq.models.speech_to_speech.s2s_transformer import ( s2ut_architecture_base as s2ut_transformer_architecture_base, ) -from fairseq.models.transformer import ( - Linear, -) - +from fairseq.models.speech_to_text import S2TConformerEncoder +from fairseq.models.transformer import Linear logger = logging.getLogger(__name__) @@ -63,25 +57,27 @@ class S2UTConformerModel(S2UTTransformerModel): @staticmethod def add_args(parser): S2UTTransformerModel.add_args(parser) - parser.add_argument("--depthwise-conv-kernel-size", default=31) + parser.add_argument( + "--depthwise-conv-kernel-size", + type=int, + metavar="N", + help="kernel size of depthwise convolution layers", + ) parser.add_argument( "--attn-type", - default=None, + type=str, + metavar="STR", help="If not specified uses fairseq MHA. Other valid option is espnet for using conformer", ) parser.add_argument( "--pos-enc-type", - default="abs", + type=str, + metavar="STR", help="Must be specified in addition to attn-type=espnet for rel_pos and rope", ) @classmethod def build_encoder(cls, args): - print(args) - data_cfg = S2SDataConfig(Path(args.data) / args.config_yaml) - args.input_feat_per_channel = data_cfg.input_feat_per_channel - args.input_channels = data_cfg.input_transformed_channels - encoder = S2SConformerEncoder(args) pretraining_path = getattr(args, "load_pretrained_encoder_from", None) if pretraining_path is not None: diff --git a/fairseq/models/speech_to_speech/s2s_transformer.py b/fairseq/models/speech_to_speech/s2s_transformer.py index a5954a83e5..dcc5173241 100644 --- a/fairseq/models/speech_to_speech/s2s_transformer.py +++ b/fairseq/models/speech_to_speech/s2s_transformer.py @@ -12,21 +12,16 @@ from fairseq import checkpoint_utils, utils from fairseq.models import ( - FairseqEncoderModel, FairseqEncoderDecoderModel, + FairseqEncoderModel, FairseqLanguageModel, register_model, register_model_architecture, ) -from fairseq.models.speech_to_text import S2TTransformerEncoder from fairseq.models.speech_to_speech.modules import CTCDecoder, StackedEmbedding +from fairseq.models.speech_to_text import S2TTransformerEncoder from fairseq.models.text_to_speech import TTSTransformerDecoder -from fairseq.models.transformer import ( - Linear, - TransformerDecoder, - TransformerModelBase, -) - +from fairseq.models.transformer import Linear, TransformerDecoder, TransformerModelBase logger = logging.getLogger(__name__) diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index f49c88e563..e3fadc8cdd 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -6,7 +6,7 @@ from .berard import * # noqa from .convtransformer import * # noqa from .multi_modality_model import * # noqa +from .s2t_conformer import * # noqa from .s2t_transformer import * # noqa from .s2t_wav_transformer import * # noqa from .xm_transformer import * # noqa -from .s2t_conformer import * # noqa diff --git a/fairseq/models/speech_to_text/berard.py b/fairseq/models/speech_to_text/berard.py index c505e3acaa..7babe7a230 100644 --- a/fairseq/models/speech_to_text/berard.py +++ b/fairseq/models/speech_to_text/berard.py @@ -6,6 +6,7 @@ import torch import torch.nn as nn import torch.nn.functional as F + from fairseq import checkpoint_utils, utils from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import ( diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py index eba000d7b0..29dd49cec0 100644 --- a/fairseq/models/speech_to_text/convtransformer.py +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -1,4 +1,7 @@ -#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. import logging import math @@ -7,6 +10,8 @@ import torch import torch.nn as nn import torch.nn.functional as F +from torch import Tensor + from fairseq import checkpoint_utils, utils from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import ( @@ -15,9 +20,9 @@ register_model, register_model_architecture, ) +from fairseq.models.speech_to_text.modules.convolution import infer_conv_output_dim from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerEncoderLayer -from torch import Tensor logger = logging.getLogger(__name__) @@ -251,7 +256,7 @@ def __init__(self, args): ), torch.nn.ReLU(), ) - transformer_input_dim = self.infer_conv_output_dim( + transformer_input_dim = infer_conv_output_dim( self.in_channels, self.input_dim, args.conv_out_channels ) self.out = torch.nn.Linear(transformer_input_dim, args.encoder_embed_dim) @@ -274,16 +279,6 @@ def __init__(self, args): def pooling_ratio(self): return 4 - def infer_conv_output_dim(self, in_channels, input_dim, out_channels): - sample_seq_len = 200 - sample_bsz = 10 - x = torch.randn(sample_bsz, in_channels, sample_seq_len, input_dim) - x = torch.nn.Conv2d(1, out_channels, 3, stride=2, padding=3 // 2)(x) - x = torch.nn.Conv2d(out_channels, out_channels, 3, stride=2, padding=3 // 2)(x) - x = x.transpose(1, 2) - mb, seq = x.size()[:2] - return x.contiguous().view(mb, seq, -1).size(-1) - def forward(self, src_tokens, src_lengths): """Encode input sequence. :param torch.Tensor xs: input tensor diff --git a/fairseq/models/speech_to_text/hub_interface.py b/fairseq/models/speech_to_text/hub_interface.py index 49d5b6b03b..d78427f687 100644 --- a/fairseq/models/speech_to_text/hub_interface.py +++ b/fairseq/models/speech_to_text/hub_interface.py @@ -3,21 +3,19 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from argparse import Namespace import logging -from typing import Union, Tuple, Optional +from argparse import Namespace +from typing import Optional, Tuple, Union import torch import torch.nn as nn import torch.nn.functional as F -from fairseq.data import encoders -from fairseq.data.audio.audio_utils import ( - get_waveform as get_wav, - convert_waveform as convert_wav, - get_fbank, -) import fairseq.data.audio.feature_transforms.utterance_cmvn as utt_cmvn +from fairseq.data import encoders +from fairseq.data.audio.audio_utils import convert_waveform as convert_wav +from fairseq.data.audio.audio_utils import get_fbank +from fairseq.data.audio.audio_utils import get_waveform as get_wav from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset logger = logging.getLogger(__name__) diff --git a/fairseq/models/speech_to_text/modules/augmented_memory_attention.py b/fairseq/models/speech_to_text/modules/augmented_memory_attention.py index e7465bc889..2d330f96f6 100644 --- a/fairseq/models/speech_to_text/modules/augmented_memory_attention.py +++ b/fairseq/models/speech_to_text/modules/augmented_memory_attention.py @@ -3,22 +3,21 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from typing import Tuple, List +from typing import List, Tuple import torch import torch.nn.functional as F +from torch import Tensor, nn + from fairseq.models import FairseqEncoder -from fairseq.models.speech_to_text import ( - ConvTransformerEncoder, -) -from fairseq.models.speech_to_text.utils import attention_suppression +from fairseq.models.speech_to_text import ConvTransformerEncoder from fairseq.models.speech_to_text.utils import ( + attention_suppression, lengths_to_encoder_padding_mask, segments_to_sequence, sequence_to_segments, ) from fairseq.modules import MultiheadAttention, TransformerEncoderLayer -from torch import nn, Tensor # ------------------------------------------------------------------------------ # AugmentedMemoryConvTransformerEncoder diff --git a/fairseq/models/speech_to_text/modules/convolution.py b/fairseq/models/speech_to_text/modules/convolution.py new file mode 100644 index 0000000000..a22f1c0d40 --- /dev/null +++ b/fairseq/models/speech_to_text/modules/convolution.py @@ -0,0 +1,70 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +from typing import List + +import torch +import torch.nn as nn + + +class Conv1dSubsampler(nn.Module): + """Convolutional subsampler: a stack of 1D convolution (along temporal + dimension) followed by non-linear activation via gated linear units + (https://arxiv.org/abs/1911.08460) + + Args: + in_channels (int): the number of input channels + mid_channels (int): the number of intermediate channels + out_channels (int): the number of output channels + kernel_sizes (List[int]): the kernel size for each convolutional layer + """ + + def __init__( + self, + in_channels: int, + mid_channels: int, + out_channels: int, + kernel_sizes: List[int] = (3, 3), + ): + super(Conv1dSubsampler, self).__init__() + self.n_layers = len(kernel_sizes) + self.conv_layers = nn.ModuleList( + nn.Conv1d( + in_channels if i == 0 else mid_channels // 2, + mid_channels if i < self.n_layers - 1 else out_channels * 2, + k, + stride=2, + padding=k // 2, + ) + for i, k in enumerate(kernel_sizes) + ) + + def get_out_seq_lens_tensor(self, in_seq_lens_tensor): + out = in_seq_lens_tensor.clone() + for _ in range(self.n_layers): + out = ((out.float() - 1) / 2 + 1).floor().long() + return out + + def forward(self, src_tokens, src_lengths): + bsz, in_seq_len, _ = src_tokens.size() # B x T x (C x D) + x = src_tokens.transpose(1, 2).contiguous() # -> B x (C x D) x T + for conv in self.conv_layers: + x = conv(x) + x = nn.functional.glu(x, dim=1) + _, _, out_seq_len = x.size() + x = x.transpose(1, 2).transpose(0, 1).contiguous() # -> T x B x (C x D) + return x, self.get_out_seq_lens_tensor(src_lengths) + + +def infer_conv_output_dim(in_channels, input_dim, out_channels): + sample_seq_len = 200 + sample_bsz = 10 + x = torch.randn(sample_bsz, in_channels, sample_seq_len, input_dim) + x = torch.nn.Conv2d(in_channels, out_channels, 3, stride=2, padding=3 // 2)(x) + x = torch.nn.Conv2d(out_channels, out_channels, 3, stride=2, padding=3 // 2)(x) + x = x.transpose(1, 2) + mb, seq = x.size()[:2] + return x.contiguous().view(mb, seq, -1).size(-1) diff --git a/fairseq/models/speech_to_text/s2t_conformer.py b/fairseq/models/speech_to_text/s2t_conformer.py index fbac61d5a7..0c3c54d111 100644 --- a/fairseq/models/speech_to_text/s2t_conformer.py +++ b/fairseq/models/speech_to_text/s2t_conformer.py @@ -1,16 +1,20 @@ import logging +import math + import torch + +from fairseq.data.data_utils import lengths_to_padding_mask +from fairseq.models import FairseqEncoder, register_model, register_model_architecture from fairseq.models.speech_to_text.s2t_transformer import ( + Conv1dSubsampler, S2TTransformerEncoder, S2TTransformerModel, - Conv1dSubsampler, +) +from fairseq.models.speech_to_text.s2t_transformer import ( base_architecture as transformer_base_architecture, ) -from fairseq.data.data_utils import lengths_to_padding_mask -from fairseq.modules.conformer_layer import ConformerEncoderLayer -from fairseq.models import FairseqEncoder, register_model_architecture, register_model from fairseq.modules import PositionalEmbedding, RelPositionalEncoding -import math +from fairseq.modules.conformer_layer import ConformerEncoderLayer logger = logging.getLogger(__name__) @@ -123,17 +127,34 @@ def __init__(self, encoder, decoder): @staticmethod def add_args(parser): S2TTransformerModel.add_args(parser) - parser.add_argument("--input-feat-per-channel", default=80) - parser.add_argument("--depthwise-conv-kernel-size", default=31) - parser.add_argument("--input-channels", default=1) + parser.add_argument( + "--input-feat-per-channel", + type=int, + metavar="N", + help="dimension of input features per channel", + ) + parser.add_argument( + "--input-channels", + type=int, + metavar="N", + help="number of chennels of input features", + ) + parser.add_argument( + "--depthwise-conv-kernel-size", + type=int, + metavar="N", + help="kernel size of depthwise convolution layers", + ) parser.add_argument( "--attn-type", - default=None, + type=str, + metavar="STR", help="If not specified uses fairseq MHA. Other valid option is espnet", ) parser.add_argument( "--pos-enc-type", - default="abs", + type=str, + metavar="STR", help="Must be specified in addition to attn-type=espnet for rel_pos and rope", ) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 4b43e1acb5..e6c351c4e3 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -18,6 +18,7 @@ register_model_architecture, ) from fairseq.models.speech_to_text.hub_interface import S2THubInterface +from fairseq.models.speech_to_text.modules.convolution import Conv1dSubsampler from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.modules import ( FairseqDropout, @@ -29,55 +30,6 @@ logger = logging.getLogger(__name__) -class Conv1dSubsampler(nn.Module): - """Convolutional subsampler: a stack of 1D convolution (along temporal - dimension) followed by non-linear activation via gated linear units - (https://arxiv.org/abs/1911.08460) - - Args: - in_channels (int): the number of input channels - mid_channels (int): the number of intermediate channels - out_channels (int): the number of output channels - kernel_sizes (List[int]): the kernel size for each convolutional layer - """ - - def __init__( - self, - in_channels: int, - mid_channels: int, - out_channels: int, - kernel_sizes: List[int] = (3, 3), - ): - super(Conv1dSubsampler, self).__init__() - self.n_layers = len(kernel_sizes) - self.conv_layers = nn.ModuleList( - nn.Conv1d( - in_channels if i == 0 else mid_channels // 2, - mid_channels if i < self.n_layers - 1 else out_channels * 2, - k, - stride=2, - padding=k // 2, - ) - for i, k in enumerate(kernel_sizes) - ) - - def get_out_seq_lens_tensor(self, in_seq_lens_tensor): - out = in_seq_lens_tensor.clone() - for _ in range(self.n_layers): - out = ((out.float() - 1) / 2 + 1).floor().long() - return out - - def forward(self, src_tokens, src_lengths): - bsz, in_seq_len, _ = src_tokens.size() # B x T x (C x D) - x = src_tokens.transpose(1, 2).contiguous() # -> B x (C x D) x T - for conv in self.conv_layers: - x = conv(x) - x = nn.functional.glu(x, dim=1) - _, _, out_seq_len = x.size() - x = x.transpose(1, 2).transpose(0, 1).contiguous() # -> T x B x (C x D) - return x, self.get_out_seq_lens_tensor(src_lengths) - - @register_model("s2t_transformer") class S2TTransformerModel(FairseqEncoderDecoderModel): """Adapted Transformer model (https://arxiv.org/abs/1706.03762) for diff --git a/fairseq/models/speech_to_text/utils.py b/fairseq/models/speech_to_text/utils.py index 168b8bf13b..33117446a5 100644 --- a/fairseq/models/speech_to_text/utils.py +++ b/fairseq/models/speech_to_text/utils.py @@ -14,7 +14,6 @@ import torch from torch import Tensor - # ------------------------------------------------------------------------------ # assert_equal() # ------------------------------------------------------------------------------ diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index ce855af76f..84d8186260 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -28,6 +28,12 @@ logger = logging.getLogger(__name__) +def build_embedding(dictionary, embed_dim): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + return Embedding(num_embeddings, embed_dim, padding_idx) + + class Conv1dAdaptor(nn.Module): def __init__( self, @@ -156,93 +162,78 @@ def add_wav2vec_asr_args(parser): metavar="D", help="dropout probability after activation in FFN inside wav2vec 2.0 model", ) - parser.add_argument( "--mask-length", type=int, help="repeat the mask indices multiple times" ) - parser.add_argument( "--mask-prob", type=float, help="probability of replacing a token with mask" ) - parser.add_argument( "--mask-selection", type=str, choices=["static", "uniform", "normal", "poisson"], help="how to choose masks", ) - parser.add_argument( "--mask-other", type=float, help="stdev of the mask length in case of 'normal' selection strategy", ) - parser.add_argument( "--no-mask-overlap", action="store_true", help="whether to allow masks to overlap", ) - parser.add_argument( "--mask-channel-length", type=int, help="repeat the mask indices multiple times" ) - parser.add_argument( "--mask-channel-prob", type=float, help="probability of replacing a token with mask", ) - parser.add_argument( "--mask-channel-selection", type=str, choices=["static", "uniform", "normal", "poisson"], help="how to choose masks", ) - parser.add_argument( "--mask-channel-other", type=float, help="stdev of the mask length in case of 'normal' selection strategy", ) - parser.add_argument( "--no-mask-channel-overlap", action="store_true", help="whether to allow masks to overlap", ) - parser.add_argument( "--freeze-finetune-updates", - default=0, type=int, + metavar="N", help="dont finetune wav2vec for this many updates", ) - parser.add_argument( "--feature-grad-mult", - default=None, type=float, + metavar="D", help="reset feature grad mult in wav2vec 2.0 to this", ) - parser.add_argument( "--layerdrop", - default=0.0, type=float, + metavar="D", help="probability of dropping a layer in wav2vec 2.0", ) parser.add_argument( "--max-positions", type=int, + metavar="N", help="Max input positions to be used in the conformer encoder in wav2vec 2.0", ) - parser.add_argument("--encoder-proj", action="store_true") - parser.add_argument("--w2v-args", default=None) - parser.add_argument( "--remove-weight-norm", action="store_true", @@ -435,9 +426,22 @@ def add_decoder_args(parser): parser.add_argument( "--layernorm-embedding", action="store_true", help="add layernorm to embedding" ) - parser.add_argument("--decoder-layerdrop", type=float, metavar="D") - parser.add_argument("--decoder-learned-pos", action="store_true") - parser.add_argument("--share-decoder-input-output-embed", action="store_true") + parser.add_argument( + "--decoder-layerdrop", + type=float, + metavar="D", + help="layerdrop probability for decoder", + ) + parser.add_argument( + "--decoder-learned-pos", + action="store_true", + help="learn positional embedding in decoder", + ) + parser.add_argument( + "--share-decoder-input-output-embed", + action="store_true", + help="share decoder input and output embeddings", + ) parser.add_argument( "--no-scale-embedding", action="store_true", @@ -539,7 +543,7 @@ def add_args(cls, parser): add_decoder_args(parser) parser.add_argument("--checkpoint-activations", action="store_true") parser.add_argument("--offload-activations", action="store_true") - parser.add_argument("--min-params-to-wrap", type=int) + parser.add_argument("--min-params-to-wrap", type=int, metavar="N") @classmethod def maybe_load_pretrained(cls, component, checkpoint: Optional[str] = None): @@ -633,11 +637,6 @@ def build_model(cls, args, task): decoder_args_dict = cls.get_decoder_args_from_checkpoint(ckpt["cfg"]) args = cls.override_decoder_args(args, decoder_args_dict) - def build_embedding(dictionary, embed_dim): - num_embeddings = len(dictionary) - padding_idx = dictionary.pad() - return Embedding(num_embeddings, embed_dim, padding_idx) - decoder_embed_tokens = build_embedding( task.target_dictionary, args.decoder_embed_dim ) diff --git a/fairseq/modules/conformer_layer.py b/fairseq/modules/conformer_layer.py index 4e29b0d88f..964af243ec 100644 --- a/fairseq/modules/conformer_layer.py +++ b/fairseq/modules/conformer_layer.py @@ -4,12 +4,14 @@ # LICENSE file in the root directory of this source tree. -import torch from typing import Optional + +import torch + from fairseq.modules import ( + ESPNETMultiHeadedAttention, LayerNorm, MultiheadAttention, - ESPNETMultiHeadedAttention, RelPositionMultiHeadedAttention, RotaryPositionMultiHeadedAttention, ) diff --git a/fairseq/modules/espnet_multihead_attention.py b/fairseq/modules/espnet_multihead_attention.py index f25acc3b66..82bc0d7b45 100644 --- a/fairseq/modules/espnet_multihead_attention.py +++ b/fairseq/modules/espnet_multihead_attention.py @@ -7,8 +7,10 @@ """Multi-Head Attention layer definition.""" import math + import torch from torch import nn + from fairseq.modules.rotary_positional_embedding import ( RotaryPositionalEmbedding, apply_rotary_pos_emb, diff --git a/fairseq/speech_generator.py b/fairseq/speech_generator.py index 90ec914e60..b6d5f5cc13 100644 --- a/fairseq/speech_generator.py +++ b/fairseq/speech_generator.py @@ -3,8 +3,8 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import torch import numpy as np +import torch from fairseq.data.audio.speech_to_text_dataset import S2TDataConfig diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 80e18dc072..fe847358d7 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -4,8 +4,8 @@ # LICENSE file in the root directory of this source tree. import logging -from pathlib import Path from argparse import Namespace +from pathlib import Path from fairseq.data import Dictionary, encoders from fairseq.data.audio.audio_utils import get_features_or_waveform @@ -16,7 +16,6 @@ ) from fairseq.tasks import LegacyFairseqTask, register_task - logger = logging.getLogger(__name__) From 34ac73292762441ca99a6ca28e0fe7e90b2347da Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Thu, 15 Sep 2022 15:54:19 +0900 Subject: [PATCH 680/774] Fix conformer encoder (#4721) --- .../models/speech_to_text/s2t_conformer.py | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/fairseq/models/speech_to_text/s2t_conformer.py b/fairseq/models/speech_to_text/s2t_conformer.py index 0c3c54d111..88dc380ed3 100644 --- a/fairseq/models/speech_to_text/s2t_conformer.py +++ b/fairseq/models/speech_to_text/s2t_conformer.py @@ -1,8 +1,15 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + import logging import math +from pathlib import Path import torch +from fairseq import checkpoint_utils from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import FairseqEncoder, register_model, register_model_architecture from fairseq.models.speech_to_text.s2t_transformer import ( @@ -24,6 +31,10 @@ class S2TConformerEncoder(FairseqEncoder): def __init__(self, args): super().__init__(None) + + self.encoder_freezing_updates = args.encoder_freezing_updates + self.num_updates = 0 + self.embed_scale = math.sqrt(args.encoder_embed_dim) if args.no_scale_embedding: self.embed_scale = 1.0 @@ -65,7 +76,7 @@ def __init__(self, args): ] ) - def forward(self, src_tokens, src_lengths, return_all_hiddens=False): + def _forward(self, src_tokens, src_lengths, return_all_hiddens=False): """ Args: src_tokens: Input source tokens Tensor of shape B X T X C @@ -114,10 +125,30 @@ def forward(self, src_tokens, src_lengths, return_all_hiddens=False): "src_lengths": [], } + def forward(self, src_tokens, src_lengths, return_all_hiddens=False): + if self.num_updates < self.encoder_freezing_updates: + with torch.no_grad(): + x = self._forward( + src_tokens, + src_lengths, + return_all_hiddens=return_all_hiddens, + ) + else: + x = self._forward( + src_tokens, + src_lengths, + return_all_hiddens=return_all_hiddens, + ) + return x + def reorder_encoder_out(self, encoder_out, new_order): """Required method for a FairseqEncoder. Calls the method from the parent class""" return S2TTransformerEncoder.reorder_encoder_out(self, encoder_out, new_order) + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + self.num_updates = num_updates + @register_model("s2t_conformer") class S2TConformerModel(S2TTransformerModel): @@ -161,11 +192,22 @@ def add_args(parser): @classmethod def build_encoder(cls, args): encoder = S2TConformerEncoder(args) + pretraining_path = getattr(args, "load_pretrained_encoder_from", None) + if pretraining_path is not None: + if not Path(pretraining_path).exists(): + logger.warning( + f"skipped pretraining because {pretraining_path} does not exist" + ) + else: + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=pretraining_path + ) + logger.info(f"loaded pretrained encoder from: {pretraining_path}") return encoder @register_model_architecture("s2t_conformer", "s2t_conformer") -def base_architecture(args): +def conformer_base_architecture(args): args.attn_type = getattr(args, "attn_type", None) args.pos_enc_type = getattr(args, "pos_enc_type", "abs") args.input_feat_per_channel = getattr(args, "input_feat_per_channel", 80) From 56e7fb4761456508a44277883d8f6d767151cbbb Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Fri, 16 Sep 2022 11:33:48 +0900 Subject: [PATCH 681/774] Fix eval mode for S2ST models during training (#4722) * Fix eval mode for S2ST models during training * Add getattr * Revert change --- fairseq/tasks/speech_to_speech.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index d9e2325686..08748c6d40 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -142,6 +142,12 @@ def add_args(cls, parser): default="config.yaml", help="Configuration YAML filename (under manifest root)", ) + parser.add_argument( + "--multitask-config-yaml", + type=str, + default=None, + help="Configuration YAML filename for the multitasks (under manifest root)", + ) parser.add_argument( "--max-source-positions", default=6000, @@ -170,12 +176,6 @@ def add_args(cls, parser): default=1, help="# stacked frames, use 0 for reduced discrete unit sequence", ) - parser.add_argument( - "--multitask-config-yaml", - type=str, - default=None, - help="Configuration YAML filename for the multitasks (under manifest root)", - ) parser.add_argument("--eval-inference", action="store_true") parser.add_argument( "--eval-args", @@ -388,6 +388,8 @@ def train_step( criterion.set_multitask_loss_weight( task_name, task_obj.args.get_loss_weight(update_num) ) + if task_name in model.multitask_decoders: + model.multitask_decoders[task_name].train() loss, sample_size, logging_output = super().train_step( sample, model, criterion, optimizer, update_num, ignore_grad @@ -395,6 +397,9 @@ def train_step( return loss, sample_size, logging_output def valid_step(self, sample, model, criterion): + for task_name in self.multitask_tasks.keys(): + if task_name in model.multitask_decoders: + model.multitask_decoders[task_name].eval() loss, sample_size, logging_output = super().valid_step(sample, model, criterion) if self.args.eval_inference: From 59e00272bca7130b73e71466e6d93fe61bea7121 Mon Sep 17 00:00:00 2001 From: Pengwei Li <84808064+lpw0@users.noreply.github.com> Date: Mon, 19 Sep 2022 10:01:38 -0700 Subject: [PATCH 682/774] update vocoder to support cpu (#4727) * update vocoder to support cpu * lint --- fairseq/models/text_to_speech/vocoder.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/fairseq/models/text_to_speech/vocoder.py b/fairseq/models/text_to_speech/vocoder.py index 34e7f498fb..dbc02da368 100644 --- a/fairseq/models/text_to_speech/vocoder.py +++ b/fairseq/models/text_to_speech/vocoder.py @@ -3,25 +3,26 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -import logging import json +import logging from typing import Dict import numpy as np import torch -from torch import nn import torch.nn.functional as F -from fairseq.models import BaseFairseqModel, register_model -from fairseq.models.text_to_speech.hub_interface import VocoderHubInterface +from torch import nn + from fairseq.data.audio.audio_utils import ( - get_window, + TTSSpectrogram, get_fourier_basis, get_mel_filters, - TTSSpectrogram, + get_window, ) from fairseq.data.audio.speech_to_text_dataset import S2TDataConfig +from fairseq.models import BaseFairseqModel, register_model from fairseq.models.text_to_speech.codehifigan import CodeGenerator as CodeHiFiGANModel from fairseq.models.text_to_speech.hifigan import Generator as HiFiGANModel +from fairseq.models.text_to_speech.hub_interface import VocoderHubInterface logger = logging.getLogger(__name__) @@ -219,7 +220,10 @@ def __init__( ) -> None: super().__init__() self.model = CodeHiFiGANModel(model_cfg) - state_dict = torch.load(checkpoint_path) + if torch.cuda.is_available(): + state_dict = torch.load(checkpoint_path) + else: + state_dict = torch.load(checkpoint_path, map_location=torch.device("cpu")) self.model.load_state_dict(state_dict["generator"]) self.model.eval() if fp16: From adebac6f4fc68c3419a092c18915a98b45420c89 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Tue, 20 Sep 2022 17:31:00 +0900 Subject: [PATCH 683/774] Add Conv2dSubsampler (#4724) * Add Conv2dSubsampler * Add conv_out_channels option --- .../speech_to_speech/s2s_transformer.py | 35 ++++++++++-- .../speech_to_text/modules/convolution.py | 56 +++++++++++++++++++ .../models/speech_to_text/s2t_conformer.py | 26 ++++++--- .../models/speech_to_text/s2t_transformer.py | 55 ++++++++++++++---- 4 files changed, 147 insertions(+), 25 deletions(-) diff --git a/fairseq/models/speech_to_speech/s2s_transformer.py b/fairseq/models/speech_to_speech/s2s_transformer.py index dcc5173241..7e1e9b72a5 100644 --- a/fairseq/models/speech_to_speech/s2s_transformer.py +++ b/fairseq/models/speech_to_speech/s2s_transformer.py @@ -247,13 +247,26 @@ def add_args(parser): "--conv-kernel-sizes", type=str, metavar="N", - help="kernel sizes of Conv1d subsampling layers", + help="kernel sizes of Conv1d (s2t_transformer) subsampling layers", ) parser.add_argument( "--conv-channels", type=int, metavar="N", - help="# of channels in Conv1d subsampling layers", + help="# of channels in Conv1d (s2t_transformer) subsampling layers", + ) + parser.add_argument( + "--conv-out-channels", + type=int, + metavar="N", + help="# of channels in Conv2d (convtransformer) subsampling layers", + ) + parser.add_argument( + "--conv-version", + type=str, + default="s2t_transformer", + choices=["s2t_transformer", "convtransformer"], + help="version of frontend convolutional layers", ) # Transformer parser.add_argument( @@ -422,13 +435,20 @@ def add_args(parser): "--conv-kernel-sizes", type=str, metavar="N", - help="kernel sizes of Conv1d subsampling layers", + help="kernel sizes of Conv1d (s2t_transformer) subsampling layers", ) parser.add_argument( "--conv-channels", type=int, metavar="N", - help="# of channels in Conv1d subsampling layers", + help="# of channels in Conv1d (s2t_transformer) subsampling layers", + ) + parser.add_argument( + "--conv-version", + type=str, + default="s2t_transformer", + choices=["s2t_transformer", "convtransformer"], + help="version of frontend convolutional layers", ) # Transformer parser.add_argument( @@ -599,8 +619,11 @@ def base_s2st_transformer_encoder_architecture(args): args.encoder_freezing_updates = getattr(args, "encoder_freezing_updates", 0) # Convolutional subsampler - args.conv_kernel_sizes = getattr(args, "conv_kernel_sizes", "5,5") - args.conv_channels = getattr(args, "conv_channels", 1024) + args.input_channels = getattr(args, "input_channels", 1) + args.conv_kernel_sizes = getattr(args, "conv_kernel_sizes", "5,5") # for Conv1d + args.conv_channels = getattr(args, "conv_channels", 1024) # for Conv1d + args.conv_out_channels = getattr(args, "conv_out_channels", 256) # for Conv2d + args.conv_version = getattr(args, "conv_version", "s2t_transformer") # Transformer args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) diff --git a/fairseq/models/speech_to_text/modules/convolution.py b/fairseq/models/speech_to_text/modules/convolution.py index a22f1c0d40..526d7540c5 100644 --- a/fairseq/models/speech_to_text/modules/convolution.py +++ b/fairseq/models/speech_to_text/modules/convolution.py @@ -68,3 +68,59 @@ def infer_conv_output_dim(in_channels, input_dim, out_channels): x = x.transpose(1, 2) mb, seq = x.size()[:2] return x.contiguous().view(mb, seq, -1).size(-1) + + +class Conv2dSubsampler(nn.Module): + """Convolutional subsampler: a stack of 2D convolution based on ESPnet implementation + (https://github.com/espnet/espnet) + + Args: + input_channels (int): the number of input channels + input_feat_per_channel (int): encoder input dimension per input channel + conv_out_channels (int): the number of output channels of conv layer + encoder_embed_dim (int): encoder dimentions + """ + + def __init__( + self, + input_channels: int, + input_feat_per_channel: int, + conv_out_channels: int, + encoder_embed_dim: int, + ): + super().__init__() + assert input_channels == 1, input_channels + self.conv = torch.nn.Sequential( + torch.nn.Conv2d( + input_channels, conv_out_channels, 3, stride=2, padding=3 // 2 + ), + torch.nn.ReLU(), + torch.nn.Conv2d( + conv_out_channels, + conv_out_channels, + 3, + stride=2, + padding=3 // 2, + ), + torch.nn.ReLU(), + ) + transformer_input_dim = infer_conv_output_dim( + input_channels, input_feat_per_channel, conv_out_channels + ) + self.out = torch.nn.Linear(transformer_input_dim, encoder_embed_dim) + + def forward(self, src_tokens, src_lengths): + B, T_i, C = src_tokens.size() + x = src_tokens.view(B, T_i, 1, C).transpose(1, 2).contiguous() + x = self.conv(x) + B, _, T_o, _ = x.size() + x = x.transpose(1, 2).transpose(0, 1).contiguous().view(T_o, B, -1) + x = self.out(x) + + subsampling_factor = int(T_i * 1.0 / T_o + 0.5) + input_len_0 = (src_lengths.float() / subsampling_factor).ceil().long() + input_len_1 = x.size(0) * torch.ones([src_lengths.size(0)]).long().to( + input_len_0.device + ) + input_lengths = torch.min(input_len_0, input_len_1) + return x, input_lengths diff --git a/fairseq/models/speech_to_text/s2t_conformer.py b/fairseq/models/speech_to_text/s2t_conformer.py index 88dc380ed3..79dbbec1b9 100644 --- a/fairseq/models/speech_to_text/s2t_conformer.py +++ b/fairseq/models/speech_to_text/s2t_conformer.py @@ -12,8 +12,11 @@ from fairseq import checkpoint_utils from fairseq.data.data_utils import lengths_to_padding_mask from fairseq.models import FairseqEncoder, register_model, register_model_architecture -from fairseq.models.speech_to_text.s2t_transformer import ( +from fairseq.models.speech_to_text.modules.convolution import ( Conv1dSubsampler, + Conv2dSubsampler, +) +from fairseq.models.speech_to_text.s2t_transformer import ( S2TTransformerEncoder, S2TTransformerModel, ) @@ -39,12 +42,21 @@ def __init__(self, args): if args.no_scale_embedding: self.embed_scale = 1.0 self.padding_idx = 1 - self.subsample = Conv1dSubsampler( - args.input_feat_per_channel * args.input_channels, - args.conv_channels, - args.encoder_embed_dim, - [int(k) for k in args.conv_kernel_sizes.split(",")], - ) + self.conv_version = args.conv_version + if self.conv_version == "s2t_transformer": + self.subsample = Conv1dSubsampler( + args.input_feat_per_channel * args.input_channels, + args.conv_channels, + args.encoder_embed_dim, + [int(k) for k in args.conv_kernel_sizes.split(",")], + ) + elif self.conv_version == "convtransformer": + self.subsample = Conv2dSubsampler( + args.input_channels, + args.input_feat_per_channel, + args.conv_out_channels, + args.encoder_embed_dim, + ) self.pos_enc_type = args.pos_enc_type if self.pos_enc_type == "rel_pos": self.embed_positions = RelPositionalEncoding( diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index e6c351c4e3..6adbd3c339 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -1,4 +1,7 @@ -#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. import logging import math @@ -18,7 +21,10 @@ register_model_architecture, ) from fairseq.models.speech_to_text.hub_interface import S2THubInterface -from fairseq.models.speech_to_text.modules.convolution import Conv1dSubsampler +from fairseq.models.speech_to_text.modules.convolution import ( + Conv1dSubsampler, + Conv2dSubsampler, +) from fairseq.models.transformer import Embedding, TransformerDecoder from fairseq.modules import ( FairseqDropout, @@ -80,13 +86,26 @@ def add_args(parser): "--conv-kernel-sizes", type=str, metavar="N", - help="kernel sizes of Conv1d subsampling layers", + help="kernel sizes of Conv1d (s2t_transformer) subsampling layers", ) parser.add_argument( "--conv-channels", type=int, metavar="N", - help="# of channels in Conv1d subsampling layers", + help="# of channels in Conv1d (s2t_transformer) subsampling layers", + ) + parser.add_argument( + "--conv-out-channels", + type=int, + metavar="N", + help="# of channels in Conv2d (convtransformer) subsampling layers", + ) + parser.add_argument( + "--conv-version", + type=str, + default="s2t_transformer", + choices=["s2t_transformer", "convtransformer"], + help="version of frontend convolutional layers", ) # Transformer parser.add_argument( @@ -291,12 +310,21 @@ def __init__(self, args): self.embed_scale = 1.0 self.padding_idx = 1 - self.subsample = Conv1dSubsampler( - args.input_feat_per_channel * args.input_channels, - args.conv_channels, - args.encoder_embed_dim, - [int(k) for k in args.conv_kernel_sizes.split(",")], - ) + self.conv_version = args.conv_version + if self.conv_version == "s2t_transformer": + self.subsample = Conv1dSubsampler( + args.input_feat_per_channel * args.input_channels, + args.conv_channels, + args.encoder_embed_dim, + [int(k) for k in args.conv_kernel_sizes.split(",")], + ) + elif self.conv_version == "convtransformer": + self.subsample = Conv2dSubsampler( + args.input_channels, + args.input_feat_per_channel, + args.conv_out_channels, + args.encoder_embed_dim, + ) self.embed_positions = PositionalEmbedding( args.max_source_positions, args.encoder_embed_dim, self.padding_idx @@ -426,8 +454,11 @@ def extract_features( def base_architecture(args): args.encoder_freezing_updates = getattr(args, "encoder_freezing_updates", 0) # Convolutional subsampler - args.conv_kernel_sizes = getattr(args, "conv_kernel_sizes", "5,5") - args.conv_channels = getattr(args, "conv_channels", 1024) + args.input_channels = getattr(args, "input_channels", 1) + args.conv_kernel_sizes = getattr(args, "conv_kernel_sizes", "5,5") # for Conv1d + args.conv_channels = getattr(args, "conv_channels", 1024) # for Conv1d + args.conv_out_channels = getattr(args, "conv_out_channels", 256) # for Conv2d + args.conv_version = getattr(args, "conv_version", "s2t_transformer") # Transformer args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) From 03f3a7304e8317a4e8861b8714633a88d8072156 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Wed, 21 Sep 2022 22:41:40 +0900 Subject: [PATCH 684/774] Support multi-task learning for speech-to-text task (#4732) * Move TextTargetMultitaskData * Support MTL for speech-to-text * Fix for black * Fix SpeechToTextDatasetCreator * Suport online text preprocessing * Add keyword to arguments --- .../data/audio/speech_to_speech_dataset.py | 112 +++-------- fairseq/data/audio/speech_to_text_dataset.py | 183 ++++++++++++++++-- fairseq/data/audio/text_to_speech_dataset.py | 10 +- fairseq/tasks/speech_to_speech.py | 47 +---- fairseq/tasks/speech_to_text.py | 89 ++++++++- 5 files changed, 291 insertions(+), 150 deletions(-) diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py index fa31c3301f..0d4151f587 100644 --- a/fairseq/data/audio/speech_to_speech_dataset.py +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -17,6 +17,7 @@ from fairseq.data.audio.speech_to_text_dataset import ( SpeechToTextDataset, SpeechToTextDatasetCreator, + TextTargetMultitaskData, _collate_frames, ) @@ -51,11 +52,11 @@ def __init__( ): tgt_texts = tgt_audio_paths if target_is_code else None super().__init__( - split, - is_train_split, - data_cfg, - src_audio_paths, - src_n_frames, + split=split, + is_train_split=is_train_split, + cfg=data_cfg, + audio_paths=src_audio_paths, + n_frames=src_n_frames, ids=ids, tgt_dict=tgt_dict, tgt_texts=tgt_texts, @@ -231,60 +232,9 @@ def collater( return out -class TextTargetMultitaskData(object): - # mandatory columns - KEY_ID, KEY_TEXT = "id", "tgt_text" - - def __init__(self, args, split, tgt_dict): - samples = SpeechToTextDatasetCreator._load_samples_from_tsv(args.data, split) - self.data = {s[self.KEY_ID]: s[self.KEY_TEXT] for s in samples} - self.dict = tgt_dict - self.append_eos = args.decoder_type != "ctc" - - def get(self, sample_id): - if sample_id in self.data: - return self.dict.encode_line( - self.data[sample_id], - add_if_not_exist=False, - append_eos=self.append_eos, - ) - else: - logger.warning(f"no target for {sample_id}") - return torch.IntTensor([]) - - def collater(self, samples: List[torch.Tensor]) -> torch.Tensor: - out = fairseq_data_utils.collate_tokens( - samples, - self.dict.pad(), - self.dict.eos(), - left_pad=False, - move_eos_to_beginning=False, - ).long() - - prev_out = fairseq_data_utils.collate_tokens( - samples, - self.dict.pad(), - self.dict.eos(), - left_pad=False, - move_eos_to_beginning=True, - ).long() - - target_lengths = torch.tensor([t.size(0) for t in samples], dtype=torch.long) - ntokens = sum(t.size(0) for t in samples) - - output = { - "prev_output_tokens": prev_out, - "target": out, - "target_lengths": target_lengths, - "ntokens": ntokens, - } - - return output - - class SpeechToSpeechMultitaskDataset(SpeechToSpeechDataset): - def __init__(self, *argv): - super().__init__(*argv) + def __init__(self, **kwargs): + super().__init__(**kwargs) self.multitask_data = {} def add_multitask_dataset(self, task_name, task_data): @@ -348,7 +298,7 @@ def _from_list( samples: List[Dict], data_cfg: S2SDataConfig, target_is_code: bool = False, - target_dictionary: Dictionary = None, + tgt_dict: Dictionary = None, n_frames_per_step: int = 1, multitask: Optional[Dict] = None, ) -> SpeechToSpeechDataset: @@ -374,19 +324,19 @@ def _from_list( ) ds = dataset_cls( - split_name, - is_train_split, - data_cfg, - src_audio_paths, - src_n_frames, - tgt_audio_paths, - tgt_n_frames, - src_langs, - tgt_langs, - ids, - target_is_code, - target_dictionary, - n_frames_per_step, + split=split_name, + is_train_split=is_train_split, + data_cfg=data_cfg, + src_audio_paths=src_audio_paths, + src_n_frames=src_n_frames, + tgt_audio_paths=tgt_audio_paths, + tgt_n_frames=tgt_n_frames, + src_langs=src_langs, + tgt_langs=tgt_langs, + ids=ids, + target_is_code=target_is_code, + tgt_dict=tgt_dict, + n_frames_per_step=n_frames_per_step, ) if has_multitask: @@ -407,7 +357,7 @@ def from_tsv( epoch: int, seed: int, target_is_code: bool = False, - target_dictionary: Dictionary = None, + tgt_dict: Dictionary = None, n_frames_per_step: int = 1, multitask: Optional[Dict] = None, ) -> SpeechToSpeechDataset: @@ -415,14 +365,14 @@ def from_tsv( for split in splits.split(","): samples = SpeechToTextDatasetCreator._load_samples_from_tsv(root, split) ds = cls._from_list( - split, - is_train_split, - samples, - data_cfg, - target_is_code, - target_dictionary, - n_frames_per_step, - multitask, + split_name=split, + is_train_split=is_train_split, + samples=samples, + data_cfg=data_cfg, + target_is_code=target_is_code, + tgt_dict=tgt_dict, + n_frames_per_step=n_frames_per_step, + multitask=multitask, ) datasets.append(ds) return ConcatDataset(datasets) if len(datasets) > 1 else datasets[0] diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index cc1221b132..500f4991db 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -4,13 +4,13 @@ # LICENSE file in the root directory of this source tree. import csv -import io import logging import re +from argparse import Namespace from collections import defaultdict from dataclasses import dataclass from pathlib import Path -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Tuple, Union import numpy as np import torch @@ -18,6 +18,7 @@ from fairseq.data import ConcatDataset, Dictionary, FairseqDataset, ResamplingDataset from fairseq.data import data_utils as fairseq_data_utils +from fairseq.data import encoders from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.data_cfg import S2TDataConfig from fairseq.data.audio.dataset_transforms import CompositeAudioDatasetTransform @@ -387,6 +388,135 @@ def prefetch(self, indices): raise False +class TextTargetMultitaskData(object): + # mandatory columns + KEY_ID, KEY_TEXT = "id", "tgt_text" + + def __init__(self, args, split, tgt_dict): + samples = SpeechToTextDatasetCreator._load_samples_from_tsv(args.data, split) + self.data = {s[self.KEY_ID]: s[self.KEY_TEXT] for s in samples} + self.dict = tgt_dict + self.append_eos = args.decoder_type != "ctc" + self.pre_tokenizer = self.build_tokenizer(args) + self.bpe_tokenizer = self.build_bpe(args) + + @classmethod + def tokenize(cls, tokenizer, text: str): + return text if tokenizer is None else tokenizer.encode(text) + + def get_tokenized_tgt_text(self, index: int): + text = self.tokenize(self.pre_tokenizer, self.data[index]) + text = self.tokenize(self.bpe_tokenizer, text) + return text + + def build_tokenizer(self, args): + pre_tokenizer = args.config.get("pre_tokenizer") + if pre_tokenizer is not None: + logger.info(f"pre-tokenizer: {pre_tokenizer}") + return encoders.build_tokenizer(Namespace(**pre_tokenizer)) + else: + return None + + def build_bpe(self, args): + bpe_tokenizer = args.config.get("bpe_tokenizer") + if bpe_tokenizer is not None: + logger.info(f"tokenizer: {bpe_tokenizer}") + return encoders.build_bpe(Namespace(**bpe_tokenizer)) + else: + return None + + def get(self, sample_id): + if sample_id in self.data: + tokenized = self.get_tokenized_tgt_text(sample_id) + return self.dict.encode_line( + tokenized, + add_if_not_exist=False, + append_eos=self.append_eos, + ) + else: + logger.warning(f"no target for {sample_id}") + return torch.IntTensor([]) + + def collater(self, samples: List[torch.Tensor]) -> torch.Tensor: + out = fairseq_data_utils.collate_tokens( + samples, + self.dict.pad(), + eos_idx=self.dict.eos(), + left_pad=False, + move_eos_to_beginning=False, + ).long() + + prev_out = fairseq_data_utils.collate_tokens( + samples, + self.dict.pad(), + eos_idx=self.dict.eos(), + left_pad=False, + move_eos_to_beginning=True, + ).long() + + target_lengths = torch.tensor([t.size(0) for t in samples], dtype=torch.long) + ntokens = sum(t.size(0) for t in samples) + + output = { + "prev_output_tokens": prev_out, + "target": out, + "target_lengths": target_lengths, + "ntokens": ntokens, + } + + return output + + +class SpeechToTextMultitaskDataset(SpeechToTextDataset): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.multitask_data = {} + + def add_multitask_dataset(self, task_name, task_data): + self.multitask_data[task_name] = task_data + + def __getitem__( + self, index: int + ) -> Tuple[SpeechToTextDatasetItem, Dict[str, torch.Tensor]]: + s2t_data = super().__getitem__(index) + + multitask_target = {} + sample_id = self.ids[index] + tgt_lang = self.tgt_langs[index] + for task_name, task_dataset in self.multitask_data.items(): + multitask_target[task_name] = task_dataset.get(sample_id, tgt_lang) + + return s2t_data, multitask_target + + def collater( + self, samples: List[Tuple[SpeechToTextDatasetItem, Dict[str, torch.Tensor]]] + ) -> Dict: + if len(samples) == 0: + return {} + + out = super().collater([s for s, _ in samples], return_order=True) + order = out["order"] + del out["order"] + + for task_name, task_dataset in self.multitask_data.items(): + if "multitask" not in out: + out["multitask"] = {} + d = [s[task_name] for _, s in samples] + task_target = task_dataset.collater(d) + out["multitask"][task_name] = { + "target": task_target["target"].index_select(0, order), + "target_lengths": task_target["target_lengths"].index_select(0, order), + "ntokens": task_target["ntokens"], + } + out["multitask"][task_name]["net_input"] = { + "prev_output_tokens": task_target["prev_output_tokens"].index_select( + 0, order + ), + } + + return out + + class SpeechToTextDatasetCreator(object): # mandatory columns KEY_ID, KEY_AUDIO, KEY_N_FRAMES = "id", "audio", "n_frames" @@ -409,6 +539,7 @@ def _from_list( bpe_tokenizer, n_frames_per_step, speaker_to_id, + multitask: Optional[Dict] = None, ) -> SpeechToTextDataset: audio_root = Path(cfg.audio_root) ids = [s[cls.KEY_ID] for s in samples] @@ -419,12 +550,18 @@ def _from_list( speakers = [s.get(cls.KEY_SPEAKER, cls.DEFAULT_SPEAKER) for s in samples] src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] - return SpeechToTextDataset( - split_name, - is_train_split, - cfg, - audio_paths, - n_frames, + + has_multitask = len(multitask) > 0 + dataset_cls = ( + SpeechToTextMultitaskDataset if has_multitask else SpeechToTextDataset + ) + + ds = dataset_cls( + split=split_name, + is_train_split=is_train_split, + cfg=cfg, + audio_paths=audio_paths, + n_frames=n_frames, src_texts=src_texts, tgt_texts=tgt_texts, speakers=speakers, @@ -438,6 +575,14 @@ def _from_list( speaker_to_id=speaker_to_id, ) + if has_multitask: + for task_name, task_obj in multitask.items(): + task_data = TextTargetMultitaskData( + task_obj.args, split_name, task_obj.target_dictionary + ) + ds.add_multitask_dataset(task_name, task_data) + return ds + @classmethod def get_size_ratios( cls, datasets: List[SpeechToTextDataset], alpha: float = 1.0 @@ -502,6 +647,7 @@ def _from_tsv( bpe_tokenizer, n_frames_per_step, speaker_to_id, + multitask: Optional[Dict] = None, ) -> SpeechToTextDataset: samples = cls._load_samples_from_tsv(root, split) return cls._from_list( @@ -514,6 +660,7 @@ def _from_tsv( bpe_tokenizer, n_frames_per_step, speaker_to_id, + multitask, ) @classmethod @@ -530,18 +677,20 @@ def from_tsv( seed: int, n_frames_per_step: int = 1, speaker_to_id=None, + multitask: Optional[Dict] = None, ) -> SpeechToTextDataset: datasets = [ cls._from_tsv( - root, - cfg, - split, - tgt_dict, - is_train_split, - pre_tokenizer, - bpe_tokenizer, - n_frames_per_step, - speaker_to_id, + root=root, + cfg=cfg, + split=split, + tgt_dict=tgt_dict, + is_train_split=is_train_split, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, + n_frames_per_step=n_frames_per_step, + speaker_to_id=speaker_to_id, + multitask=multitask, ) for split in splits.split(",") ] diff --git a/fairseq/data/audio/text_to_speech_dataset.py b/fairseq/data/audio/text_to_speech_dataset.py index 27e52df1a3..13612b458b 100644 --- a/fairseq/data/audio/text_to_speech_dataset.py +++ b/fairseq/data/audio/text_to_speech_dataset.py @@ -5,21 +5,22 @@ # the root directory of this source tree. An additional grant of patent rights # can be found in the PATENTS file in the same directory.abs -from pathlib import Path -from typing import List, Dict, Optional, Any from dataclasses import dataclass +from pathlib import Path +from typing import Any, Dict, List, Optional import numpy as np import torch +from fairseq.data import Dictionary +from fairseq.data import data_utils as fairseq_data_utils from fairseq.data.audio.audio_utils import get_features_or_waveform from fairseq.data.audio.speech_to_text_dataset import ( + S2TDataConfig, SpeechToTextDataset, SpeechToTextDatasetCreator, - S2TDataConfig, _collate_frames, ) -from fairseq.data import Dictionary, data_utils as fairseq_data_utils @dataclass @@ -196,6 +197,7 @@ def _from_list( bpe_tokenizer, n_frames_per_step, speaker_to_id, + multitask=None, ) -> TextToSpeechDataset: audio_root = Path(cfg.audio_root) ids = [s[cls.KEY_ID] for s in samples] diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index 08748c6d40..d41ce854d4 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -18,6 +18,7 @@ from fairseq.data.audio.speech_to_speech_dataset import SpeechToSpeechDatasetCreator from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset from fairseq.tasks import LegacyFairseqTask, register_task +from fairseq.tasks.speech_to_text import DummyMultiTask from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion logger = logging.getLogger(__name__) @@ -279,14 +280,14 @@ def build_criterion(self, args): def load_dataset(self, split, epoch=1, combine=False, **kwargs): self.datasets[split] = SpeechToSpeechDatasetCreator.from_tsv( - self.args.data, - self.data_cfg, - split, + root=self.args.data, + data_cfg=self.data_cfg, + splits=split, is_train_split=split.startswith("train"), epoch=epoch, seed=self.args.seed, target_is_code=self.args.target_is_code, - target_dictionary=self.target_dictionary, + tgt_dict=self.target_dictionary, n_frames_per_step=self.args.n_frames_per_step, multitask=self.multitask_tasks, ) @@ -485,41 +486,3 @@ def inference_step( prefix_tokens=prefix_tokens, constraints=constraints, ) - - -class DummyMultiTask(LegacyFairseqTask): - def __init__(self, args, tgt_dict): - super().__init__(args) - self.tgt_dict = tgt_dict - - @property - def target_dictionary(self): - return self.tgt_dict - - def inference_step( - self, generator, models, sample, prefix_tokens=None, constraints=None - ): - if self.args.decoder_type == "ctc": - model = models[0] # only support single model - encoder_out = model(**sample) - if hasattr(model, "get_logits"): - emissions = model.get_logits( - encoder_out - ) # no need to normalize emissions - else: - emissions = model.get_normalized_probs(encoder_out, log_probs=True) - return generator.decode( - emissions.transpose(0, 1).float().cpu().contiguous() - ) - else: - raise NotImplementedError("only ctc decoder is supported at the moment") - - def build_generator( - self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None - ): - if self.args.decoder_type == "ctc": - from examples.speech_recognition.w2l_decoder import W2lViterbiDecoder - - return W2lViterbiDecoder(args, self.tgt_dict) - else: - raise NotImplementedError("only ctc decoder is supported at the moment") diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index fe847358d7..3fd0402203 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -9,6 +9,7 @@ from fairseq.data import Dictionary, encoders from fairseq.data.audio.audio_utils import get_features_or_waveform +from fairseq.data.audio.data_cfg import MultitaskConfig from fairseq.data.audio.speech_to_text_dataset import ( S2TDataConfig, SpeechToTextDataset, @@ -30,6 +31,12 @@ def add_args(cls, parser): default="config.yaml", help="Configuration YAML filename (under manifest root)", ) + parser.add_argument( + "--multitask-config-yaml", + type=str, + default=None, + help="Configuration YAML filename for the multitasks (under manifest root)", + ) parser.add_argument( "--max-source-positions", default=6000, @@ -58,6 +65,15 @@ def __init__(self, args, tgt_dict): "Please set only one of the two options to avoid adding target token multiple times" ) + self.multitask_tasks = {} + if getattr(args, "multitask_config_yaml", None) is not None: + multitask_cfg = MultitaskConfig( + Path(args.data) / args.multitask_config_yaml + ) + for task_name, task_config in multitask_cfg.get_all_tasks().items(): + task_obj = DummyMultiTask(task_config, task_config.tgt_dict) + self.multitask_tasks[task_name] = task_obj + def _get_speaker_to_id(self): speaker_to_id = None speaker_set_filename = self.data_cfg.config.get("speaker_set_filename") @@ -98,12 +114,12 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): pre_tokenizer = self.build_tokenizer(self.args) bpe_tokenizer = self.build_bpe(self.args) self.datasets[split] = SpeechToTextDatasetCreator.from_tsv( - self.args.data, - self.data_cfg, - split, - self.tgt_dict, - pre_tokenizer, - bpe_tokenizer, + root=self.args.data, + cfg=self.data_cfg, + splits=split, + tgt_dict=self.tgt_dict, + pre_tokenizer=pre_tokenizer, + bpe_tokenizer=bpe_tokenizer, is_train_split=is_train_split, epoch=epoch, seed=self.args.seed, @@ -167,6 +183,29 @@ def build_generator( models, args, seq_gen_cls=None, extra_gen_cls_kwargs=extra_gen_cls_kwargs ) + def train_step( + self, sample, model, criterion, optimizer, update_num, ignore_grad=False + ): + for task_name, task_obj in self.multitask_tasks.items(): + criterion.set_multitask_loss_weight( + task_name, task_obj.args.get_loss_weight(update_num) + ) + if task_name in model.multitask_decoders: + model.multitask_decoders[task_name].train() + + loss, sample_size, logging_output = super().train_step( + sample, model, criterion, optimizer, update_num, ignore_grad + ) + return loss, sample_size, logging_output + + def valid_step(self, sample, model, criterion): + for task_name, task_obj in self.multitask_tasks.items(): + if task_name in model.multitask_decoders: + model.multitask_decoders[task_name].eval() + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + + return loss, sample_size, logging_output + def build_tokenizer(self, args): logger.info(f"pre-tokenizer: {self.data_cfg.pre_tokenizer}") return encoders.build_tokenizer(Namespace(**self.data_cfg.pre_tokenizer)) @@ -183,3 +222,41 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): return SpeechToTextDataset( "interactive", False, self.data_cfg, src_tokens, src_lengths ) + + +class DummyMultiTask(LegacyFairseqTask): + def __init__(self, args, tgt_dict): + super().__init__(args) + self.tgt_dict = tgt_dict + + @property + def target_dictionary(self): + return self.tgt_dict + + def inference_step( + self, generator, models, sample, prefix_tokens=None, constraints=None + ): + if self.args.decoder_type == "ctc": + model = models[0] # only support single model + encoder_out = model(**sample) + if hasattr(model, "get_logits"): + emissions = model.get_logits( + encoder_out + ) # no need to normalize emissions + else: + emissions = model.get_normalized_probs(encoder_out, log_probs=True) + return generator.decode( + emissions.transpose(0, 1).float().cpu().contiguous() + ) + else: + raise NotImplementedError("only ctc decoder is supported at the moment") + + def build_generator( + self, models, args, seq_gen_cls=None, extra_gen_cls_kwargs=None + ): + if self.args.decoder_type == "ctc": + from examples.speech_recognition.w2l_decoder import W2lViterbiDecoder + + return W2lViterbiDecoder(args, self.tgt_dict) + else: + raise NotImplementedError("only ctc decoder is supported at the moment") From 699ab190147e3afff0201c956d8145d158bc6f28 Mon Sep 17 00:00:00 2001 From: Guillaume Wenzek <gwenzek@users.noreply.github.com> Date: Fri, 23 Sep 2022 18:40:50 +0200 Subject: [PATCH 685/774] run all tests (#4733) * run all tests * make torch a build-time dependency * add 'dev' extra deps to install black, flake, pytest at once * Build docs in CI This should also help catch some import bugs, since sphinx inspect a lot of code * CI should do the real install not "--editable" * check installation succeeded * add missing __init__.py file * add check installation * move check_installation.py to its own script * fix pytest import mode, force recent numpy, torch * run black before flake and tests * torch >= 1.10.0 * use torch 1.10 for GPU tests --- .circleci/config.yml | 22 ++-- .github/workflows/build.yml | 32 +++--- .isort.cfg | 2 - README.md | 4 +- docs/_static/theme_overrides.css | 9 -- docs/conf.py | 38 +------ docs/requirements.txt | 2 - .../models/speech_to_text/modules/__init__.py | 0 pyproject.toml | 22 +++- scripts/check_installation.py | 36 +++++++ setup.py | 100 +++++++----------- 11 files changed, 133 insertions(+), 134 deletions(-) delete mode 100644 .isort.cfg delete mode 100644 docs/_static/theme_overrides.css delete mode 100644 docs/requirements.txt create mode 100644 fairseq/models/speech_to_text/modules/__init__.py create mode 100644 scripts/check_installation.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 59a244f346..6187ccc688 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -31,6 +31,7 @@ install_dep_common: &install_dep_common python -m torch.utils.collect_env install_dep_fused_ops: &install_dep_fused_ops + # this version of Apex is from Feb 2021 and doesn't work with torch>=1.12 - run: name: Install Megatron/Apex Dependencies working_directory: ~/ @@ -57,22 +58,22 @@ install_dep_xformers: &install_dep_xformers pip install -r requirements.txt pip install -e . -install_dep_pt19: &install_dep_pt19 +install_dep_pt1_10: &install_dep_pt1_10 - run: name: Install Pytorch Dependencies command: | source activate fairseq pip install --upgrade setuptools - pip install torch==1.9.1+cu111 torchvision==0.10.1+cu111 torchaudio==0.9.1 -f https://download.pytorch.org/whl/torch_stable.html + pip install torch==1.10.1+cu111 torchaudio==0.10.1+cu111 -f https://download.pytorch.org/whl/torch_stable.html python -c 'import torch; print("Torch version:", torch.__version__)' -install_dep_pt18: &install_dep_pt18 +install_dep_pt1_12: &install_dep_pt1_12 - run: name: Install Pytorch Dependencies command: | source activate fairseq pip install --upgrade setuptools - pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html + pip install torch==1.12.1+cu116 torchaudio==0.12.1+cu116 -f https://download.pytorch.org/whl/torch_stable.html python -c 'import torch; print("Torch version:", torch.__version__)' install_repo: &install_repo @@ -121,7 +122,7 @@ create_conda_env: &create_conda_env jobs: - gpu_tests_pt19: + gpu_tests_pt1_10: <<: *gpu working_directory: ~/fairseq-py @@ -132,7 +133,7 @@ jobs: - <<: *create_conda_env - restore_cache: key: *cache_key - - <<: *install_dep_pt19 + - <<: *install_dep_pt1_10 - <<: *install_dep_common - <<: *install_dep_fused_ops - save_cache: @@ -142,7 +143,7 @@ jobs: - <<: *install_repo - <<: *run_unittests - gpu_tests_pt18: + gpu_tests_pt1_12: <<: *gpu working_directory: ~/fairseq-py @@ -153,7 +154,7 @@ jobs: - <<: *create_conda_env - restore_cache: key: *cache_key - - <<: *install_dep_pt18 + - <<: *install_dep_pt1_12 - <<: *install_dep_common - <<: *install_dep_fused_ops - save_cache: @@ -167,5 +168,6 @@ workflows: version: 2 build: jobs: - - gpu_tests_pt18 - - gpu_tests_pt19 + # TODO: Figure out how to run APEX on torch 1.12 + # - gpu_tests_pt1_12 + - gpu_tests_pt1_10 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f8d90e0eb..036233d8cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,14 +34,17 @@ jobs: run: | python -m pip install --upgrade pip git submodule update --init --recursive - python setup.py build_ext --inplace - python -m pip install --editable . + python -m pip install . + + - name: Check installation + working-directory: /tmp + run: python $GITHUB_WORKSPACE/scripts/check_installation.py - name: Install optional test requirements run: | + python -m pip install '.[dev,docs]' python -m pip install iopath transformers pyarrow python -m pip install git+https://github.com/facebookresearch/fairscale.git@main - python -m pip install pytest python -m pip install pygit2 pgzip - name: Install xformers for Macos @@ -55,19 +58,24 @@ jobs: run: | python -m pip install --progress-bar off git+https://github.com/facebookresearch/xformers.git@main + - name: Lint with black + run: black --check --diff . + - name: Lint with flake8 run: | - pip install flake8 # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --extend-exclude fairseq/model_parallel/megatron + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics --extend-exclude fairseq/model_parallel/megatron + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + + - name: Build doc + run: make singlehtml + working-directory: docs/ - name: Run tests - run: | - python setup.py test + # When installing in non-editable mode, the .so files will be generated in 'site-packages/fairseq'. + # But by default, pytest import machinery will load local fairseq, and won't see the .so. + # Use --import-mode=append to favorize the 'site-packages/fairseq'. + # https://docs.pytest.org/en/7.1.x/explanation/pythonpath.html + run: pytest --import-mode=append -vvv tests/ - - name: Lint with black - run: | - pip install black==22.3.0 - black --check . --extend-exclude 'examples|fairseq\/model_parallel\/megatron' diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index aed482f47e..0000000000 --- a/.isort.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[settings] -known_third_party = _cffi_backend,agg_results,aml,bitarray,boto3,botocore,dump_hubert_feature,dynamicconv_cuda,editdistance,faiss,fasttext,feature_utils,ffmpeg,g2p_en,h5py,hydra,hypothesis,indicnlp,inflect,iopath,joblib,kaldi_io,kenlm,libfb,librosa,lightconv_cuda,matplotlib,misc,mmpt,mmpt_cli,model,nltk,npy_append_array,numpy,omegaconf,pandas,pathbuilder,preprocessing,progressbar,pythainlp,random_sequence_shuffler,regex,sacrebleu,sacremoses,scipy,sentencepiece,setuptools,six,sklearn,soundfile,sweep,sweep_wmt_en2de_transformer_big_common,tabulate,torch,torchaudio,tqdm,unidecode,utils,videoreader,wav2vec_cluster_faiss,wget,yaml diff --git a/README.md b/README.md index 2dfd9e96fe..047e1b7686 100644 --- a/README.md +++ b/README.md @@ -147,8 +147,8 @@ and [RoBERTa](https://pytorch.org/hub/pytorch_fairseq_roberta/) for more example # Requirements and Installation -* [PyTorch](http://pytorch.org/) version >= 1.5.0 -* Python version >= 3.6 +* [PyTorch](http://pytorch.org/) version >= 1.10.0 +* Python version >= 3.8 * For training new models, you'll also need an NVIDIA GPU and [NCCL](https://github.com/NVIDIA/nccl) * **To install fairseq** and develop locally: diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css deleted file mode 100644 index 2a07641936..0000000000 --- a/docs/_static/theme_overrides.css +++ /dev/null @@ -1,9 +0,0 @@ -.wy-table-responsive table td kbd { - white-space: nowrap; -} -.wy-table-responsive table td { - white-space: normal !important; -} -.wy-table-responsive { - overflow: visible !important; -} diff --git a/docs/conf.py b/docs/conf.py index 87b0db98c7..0bc049f802 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -88,43 +88,7 @@ # -- Options for HTML output ---------------------------------------------- -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "sphinx_rtd_theme" - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] - -html_context = { - "css_files": [ - "_static/theme_overrides.css", # override wide tables in RTD theme - ], -} - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# This is required for the alabaster theme -# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars -# html_sidebars = { -# '**': [ -# 'about.html', -# 'navigation.html', -# 'relations.html', # needs 'show_related': True theme option to display -# 'searchbox.html', -# 'donate.html', -# ] -# } - +html_theme = "classic" # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index c734a1f04f..0000000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -sphinx<2.0 -sphinx-argparse diff --git a/fairseq/models/speech_to_text/modules/__init__.py b/fairseq/models/speech_to_text/modules/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pyproject.toml b/pyproject.toml index 6d1b4c5b6f..f4cb74ba1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,23 @@ [build-system] -requires = ["setuptools", "wheel", "cython"] +requires = [ + "setuptools>=18.0", + "wheel", + "cython", + "numpy>=1.23.3", + "torch>=1.10", +] build-backend = "setuptools.build_meta" + +[tool.black] +extend-exclude = ''' +( +^/examples/| +^/fairseq/model_parallel/megatron| +^/build/ +) +''' + +[tool.isort] +profile = "black" +known_third_party = "_cffi_backend,agg_results,aml,bitarray,boto3,botocore,dump_hubert_feature,dynamicconv_cuda,editdistance,faiss,fasttext,feature_utils,ffmpeg,g2p_en,h5py,hydra,hypothesis,indicnlp,inflect,iopath,joblib,kaldi_io,kenlm,libfb,librosa,lightconv_cuda,matplotlib,misc,mmpt,mmpt_cli,model,nltk,npy_append_array,numpy,omegaconf,pandas,pathbuilder,preprocessing,progressbar,pythainlp,random_sequence_shuffler,regex,sacrebleu,sacremoses,scipy,sentencepiece,setuptools,six,sklearn,soundfile,sweep,sweep_wmt_en2de_transformer_big_common,tabulate,torch,torchaudio,tqdm,unidecode,utils,videoreader,wav2vec_cluster_faiss,wget,yaml" +skip_gitignore = true diff --git a/scripts/check_installation.py b/scripts/check_installation.py new file mode 100644 index 0000000000..e5a9d9dd46 --- /dev/null +++ b/scripts/check_installation.py @@ -0,0 +1,36 @@ +from pathlib import Path +import os + +cwd = Path(".").resolve() +print("running 'check_installation.py' from:", cwd) + +# Old versions of numpy/torch can prevent loading the .so files +import torch + +print("torch:", torch.__version__) +import numpy + +print("numpy:", numpy.__version__) + +import fairseq + +print("Fairseq installed at:", fairseq.__file__) +import fairseq.criterions +import fairseq.dataclass.configs + +import _imp + +print("Should load following .so suffixes:", _imp.extension_suffixes()) + +so_files = list(Path(fairseq.__file__).parent.glob("*.so")) +so_files.extend(Path(fairseq.__file__).parent.glob("data/*.so")) +print("Found following .so files:") +for so_file in so_files: + print(f"- {so_file}") + +from fairseq import libbleu + +print("Found libbleu at", libbleu.__file__) +from fairseq.data import data_utils_fast + +print("Found data_utils_fast at", data_utils_fast.__file__) diff --git a/setup.py b/setup.py index a7ce61a896..ace36e980a 100644 --- a/setup.py +++ b/setup.py @@ -9,6 +9,7 @@ import sys from setuptools import Extension, find_packages, setup +from torch.utils import cpp_extension if sys.version_info < (3, 6): sys.exit("Sorry, Python >= 3.6 is required for fairseq.") @@ -79,71 +80,56 @@ def include_dirs(self, dirs): ] -cmdclass = {} - - -try: - # torch is not available when generating docs - from torch.utils import cpp_extension - +extensions.extend( + [ + cpp_extension.CppExtension( + "fairseq.libbase", + sources=[ + "fairseq/clib/libbase/balanced_assignment.cpp", + ], + ), + cpp_extension.CppExtension( + "fairseq.libnat", + sources=[ + "fairseq/clib/libnat/edit_dist.cpp", + ], + ), + cpp_extension.CppExtension( + "alignment_train_cpu_binding", + sources=[ + "examples/operators/alignment_train_cpu.cpp", + ], + ), + ] +) +if "CUDA_HOME" in os.environ: extensions.extend( [ cpp_extension.CppExtension( - "fairseq.libbase", + "fairseq.libnat_cuda", sources=[ - "fairseq/clib/libbase/balanced_assignment.cpp", + "fairseq/clib/libnat_cuda/edit_dist.cu", + "fairseq/clib/libnat_cuda/binding.cpp", ], - ) - ] - ) - - extensions.extend( - [ + ), cpp_extension.CppExtension( - "fairseq.libnat", + "fairseq.ngram_repeat_block_cuda", sources=[ - "fairseq/clib/libnat/edit_dist.cpp", + "fairseq/clib/cuda/ngram_repeat_block_cuda.cpp", + "fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu", ], ), cpp_extension.CppExtension( - "alignment_train_cpu_binding", + "alignment_train_cuda_binding", sources=[ - "examples/operators/alignment_train_cpu.cpp", + "examples/operators/alignment_train_kernel.cu", + "examples/operators/alignment_train_cuda.cpp", ], ), ] ) - if "CUDA_HOME" in os.environ: - extensions.extend( - [ - cpp_extension.CppExtension( - "fairseq.libnat_cuda", - sources=[ - "fairseq/clib/libnat_cuda/edit_dist.cu", - "fairseq/clib/libnat_cuda/binding.cpp", - ], - ), - cpp_extension.CppExtension( - "fairseq.ngram_repeat_block_cuda", - sources=[ - "fairseq/clib/cuda/ngram_repeat_block_cuda.cpp", - "fairseq/clib/cuda/ngram_repeat_block_cuda_kernel.cu", - ], - ), - cpp_extension.CppExtension( - "alignment_train_cuda_binding", - sources=[ - "examples/operators/alignment_train_kernel.cu", - "examples/operators/alignment_train_cuda.cpp", - ], - ), - ] - ) - cmdclass["build_ext"] = cpp_extension.BuildExtension - -except ImportError: - pass +cmdclass = {"build_ext": cpp_extension.BuildExtension} if "READTHEDOCS" in os.environ: # don't build extensions when generating docs @@ -190,27 +176,23 @@ def do_setup(package_data): ], long_description=readme, long_description_content_type="text/markdown", - setup_requires=[ - "cython", - 'numpy<1.20.0; python_version<"3.7"', - 'numpy; python_version>="3.7"', - "setuptools>=18.0", - ], install_requires=[ "cffi", "cython", - 'dataclasses; python_version<"3.7"', "hydra-core>=1.0.7,<1.1", "omegaconf<2.1", - 'numpy<1.20.0; python_version<"3.7"', - 'numpy; python_version>="3.7"', + "numpy>=1.23.3", "regex", "sacrebleu>=1.4.12", - "torch", + "torch>=1.10", "tqdm", "bitarray", "torchaudio>=0.8.0", ], + extras_require={ + "dev": ["flake8", "pytest", "black==22.3.0"], + "docs": ["sphinx", "sphinx-argparse"], + }, dependency_links=dependency_links, packages=find_packages( exclude=[ From 25451b23a264beab423babc43d437ff1aafa85a9 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Wed, 28 Sep 2022 11:44:19 -0700 Subject: [PATCH 686/774] Add Rdrop (#4730) --- fairseq/criterions/ctc.py | 27 ++- ...label_smoothed_cross_entropy_with_rdrop.py | 176 ++++++++++++++++++ .../criterions/speech_to_speech_criterion.py | 82 +++++--- fairseq/data/audio/data_cfg.py | 8 +- 4 files changed, 267 insertions(+), 26 deletions(-) create mode 100644 fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index 131d2f20c0..6d53198b09 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -65,7 +65,9 @@ class CtcCriterionConfig(FairseqDataclass): @register_criterion("ctc", dataclass=CtcCriterionConfig) class CtcCriterion(FairseqCriterion): - def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): + def __init__( + self, cfg: CtcCriterionConfig, task: FairseqTask, rdrop_alpha: int = 0.0 + ): super().__init__(task) self.blank_idx = ( task.target_dictionary.index(task.blank_symbol) @@ -76,6 +78,8 @@ def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): self.eos_idx = task.target_dictionary.eos() self.post_process = cfg.post_process + self.rdrop_alpha = rdrop_alpha + if cfg.wer_args is not None: ( cfg.wer_kenlm_model, @@ -107,12 +111,31 @@ def __init__(self, cfg: CtcCriterionConfig, task: FairseqTask): self.zero_infinity = cfg.zero_infinity self.sentence_avg = cfg.sentence_avg - def forward(self, model, sample, reduce=True): + def forward(self, model, sample, reduce=True, **kwargs): net_output = model(**sample["net_input"]) lprobs = model.get_normalized_probs( net_output, log_probs=True ).contiguous() # (T, B, C) from the encoder + # CTC loss is calculated over duplicated inputs + # sample is already duplicated for R-Drop + if self.rdrop_alpha > 0: + for k, v in sample.items(): + if k in ["target", "target_lengths"]: + sample[k] = torch.cat([v, v.clone()], dim=0) + elif k == "net_input": + if sample[k]["src_tokens"].size(1) != sample[k]["src_lengths"].size( + 0 + ): + # for decoder CTC loss + sample[k]["src_lengths"] = torch.cat( + [ + sample[k]["src_lengths"], + sample[k]["src_lengths"].clone(), + ], + dim=0, + ) + if "src_lengths" in sample["net_input"]: input_lengths = sample["net_input"]["src_lengths"] else: diff --git a/fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py b/fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py new file mode 100644 index 0000000000..80b5ea0f73 --- /dev/null +++ b/fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py @@ -0,0 +1,176 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from dataclasses import dataclass, field + +import torch + +from fairseq import metrics, utils +from fairseq.criterions import register_criterion +from fairseq.criterions.label_smoothed_cross_entropy import ( + LabelSmoothedCrossEntropyCriterion, + LabelSmoothedCrossEntropyCriterionConfig, + label_smoothed_nll_loss, +) + + +@dataclass +class RdropLabelSmoothedCrossEntropyCriterionConfig( + LabelSmoothedCrossEntropyCriterionConfig +): + rdrop_alpha: float = field( + default=0.0, + metadata={"help": "alpha for r-drop, 0 means no r-drop"}, + ) + + +@register_criterion( + "label_smoothed_cross_entropy_with_rdrop", + dataclass=RdropLabelSmoothedCrossEntropyCriterionConfig, +) +class RdropLabelSmoothedCrossEntropyCriterion(LabelSmoothedCrossEntropyCriterion): + def __init__( + self, + task, + sentence_avg, + label_smoothing, + ignore_prefix_size=0, + report_accuracy=False, + rdrop_alpha=0.0, + ): + super().__init__( + task, + sentence_avg, + label_smoothing, + ignore_prefix_size=ignore_prefix_size, + report_accuracy=report_accuracy, + ) + self.sentence_avg = sentence_avg + self.eps = label_smoothing + self.ignore_prefix_size = ignore_prefix_size + self.report_accuracy = report_accuracy + self.rdrop_alpha = rdrop_alpha + + def forward(self, model, sample, reduce=True, net_output=None): + """Compute the loss for the given sample. + + Returns a tuple with three elements: + 1) the loss + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + if net_output is None: + if self.rdrop_alpha > 0 and sample["net_input"]["src_tokens"].size( + 0 + ) == sample["target"].size(0): + sample = duplicate_input(sample) + net_output = model(**sample["net_input"]) + loss, nll_loss, rdrop_kl_loss = self.compute_loss( + model, net_output, sample, reduce=reduce + ) + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + logging_output = { + "loss": loss.data, + "nll_loss": nll_loss.data, + "ntokens": sample["ntokens"], + "nsentences": sample["target"].size(0), + "sample_size": sample_size, + } + if self.report_accuracy: + n_correct, total = self.compute_accuracy(model, net_output, sample) + logging_output["n_correct"] = utils.item(n_correct.data) + logging_output["total"] = utils.item(total.data) + if self.rdrop_alpha > 0: + logging_output["rdrop_kl_loss"] = utils.item(rdrop_kl_loss.data) + return loss, sample_size, logging_output + + def get_lprobs_and_target(self, model, net_output, sample): + lprobs = model.get_normalized_probs(net_output, log_probs=True) + target = model.get_targets(sample, net_output) + if self.rdrop_alpha > 0 or target.size(0) != lprobs.size(0): + target = torch.cat([target, target.clone()], dim=0) + + if self.ignore_prefix_size > 0: + # lprobs: B x T x C + lprobs = lprobs[:, self.ignore_prefix_size :, :].contiguous() + target = target[:, self.ignore_prefix_size :].contiguous() + return lprobs.view(-1, lprobs.size(-1)), target.view(-1) + + def compute_loss(self, model, net_output, sample, reduce=True): + lprobs, target = self.get_lprobs_and_target(model, net_output, sample) + loss, nll_loss = label_smoothed_nll_loss( + lprobs, + target, + self.eps, + ignore_index=self.padding_idx, + reduce=reduce, + ) + + if self.rdrop_alpha > 0: + pad_mask = target[: target.size(0) // 2].unsqueeze(-1).eq(self.padding_idx) + rdrop_kl_loss = compute_kl_loss(model, net_output, pad_mask) + loss += self.rdrop_alpha * rdrop_kl_loss + else: + rdrop_kl_loss = loss.new_zeros(1) + return loss, nll_loss, rdrop_kl_loss + + @classmethod + def reduce_metrics(cls, logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + super().reduce_metrics(logging_outputs) + + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + + rdrop_kl_loss = utils.item( + sum(log.get("rdrop_kl_loss", 0) for log in logging_outputs) + / sample_size + / math.log(2) + ) + if rdrop_kl_loss > 0: + metrics.log_scalar("rdrop_kl_loss", rdrop_kl_loss) + + +def duplicate_input(sample): + if "net_input" in sample.keys(): + sample_input = sample["net_input"] + else: + sample_input = sample + + for k, v in sample_input.items(): + if isinstance(v, torch.Tensor): + sample_input[k] = torch.cat([v, v.clone()], dim=0) + if "net_input" in sample.keys(): + sample["net_input"] = sample_input + else: + sample = sample_input + return sample + + +def compute_kl_loss(model, net_output, pad_mask=None, reduce=True): + net_prob = model.get_normalized_probs(net_output, log_probs=True) + net_prob_tec = model.get_normalized_probs(net_output, log_probs=False) + + net_prob = net_prob.view(-1, net_prob.size(-1)) + net_prob_tec = net_prob_tec.view(-1, net_prob_tec.size(-1)) + + p, q = torch.split(net_prob, net_prob.size(0) // 2, dim=0) + p_tec, q_tec = torch.split(net_prob_tec, net_prob_tec.size(0) // 2, dim=0) + + p_loss = torch.nn.functional.kl_div(p, q_tec, reduction="none") + q_loss = torch.nn.functional.kl_div(q, p_tec, reduction="none") + + if pad_mask is not None: + p_loss.masked_fill_(pad_mask, 0.0) + q_loss.masked_fill_(pad_mask, 0.0) + + if reduce: + p_loss = p_loss.sum() + q_loss = q_loss.sum() + + loss = (p_loss + q_loss) / 2 + return loss diff --git a/fairseq/criterions/speech_to_speech_criterion.py b/fairseq/criterions/speech_to_speech_criterion.py index 09bf745c19..6212395e3c 100644 --- a/fairseq/criterions/speech_to_speech_criterion.py +++ b/fairseq/criterions/speech_to_speech_criterion.py @@ -3,39 +3,56 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import logging import math +from collections import OrderedDict import torch from fairseq import metrics, utils from fairseq.criterions import register_criterion from fairseq.criterions.ctc import CtcCriterion -from fairseq.criterions.label_smoothed_cross_entropy import ( - LabelSmoothedCrossEntropyCriterion, - LabelSmoothedCrossEntropyCriterionConfig, +from fairseq.criterions.label_smoothed_cross_entropy_with_rdrop import ( + RdropLabelSmoothedCrossEntropyCriterion, + RdropLabelSmoothedCrossEntropyCriterionConfig, + duplicate_input, ) from fairseq.criterions.tacotron2_loss import ( Tacotron2Criterion, Tacotron2CriterionConfig, ) +logger = logging.getLogger(__name__) + class MultitaskCriterion: - def __init__(self, multitask_tasks): - self.multitask_criterion = {} - self.multitask_loss_weight = {} + def __init__(self, multitask_tasks, rdrop_alpha=0.0): + self.rdrop_alpha = rdrop_alpha + self.rdrop_alpha_mtl = rdrop_alpha + + self.multitask_criterion = OrderedDict() + self.multitask_loss_weight = OrderedDict() for task_name, task_obj in multitask_tasks.items(): + rdrop_alpha_task = task_obj.args.rdrop_alpha + if rdrop_alpha_task is None: + rdrop_alpha_task = rdrop_alpha + self.rdrop_alpha_mtl = rdrop_alpha_task + logger.info(f"rdrop_alpha is set to {rdrop_alpha_task}") + if task_obj.args.decoder_type == "ctc": self.multitask_criterion[task_name] = CtcCriterion( - task_obj.args.criterion_cfg, task_obj + task_obj.args.criterion_cfg, + task_obj, + rdrop_alpha=rdrop_alpha_task, ) else: self.multitask_criterion[ task_name - ] = LabelSmoothedCrossEntropyCriterion( + ] = RdropLabelSmoothedCrossEntropyCriterion( task_obj, task_obj.args.criterion_cfg.sentence_avg, label_smoothing=task_obj.args.criterion_cfg.label_smoothing, + rdrop_alpha=rdrop_alpha_task, ) def set_multitask_loss_weight(self, task_name, weight=0.0): @@ -48,8 +65,15 @@ def get_multitask_loss(self, model, sample, model_out): layer_id = task_criterion.task.args.input_layer if isinstance(task_criterion, CtcCriterion): if task_criterion.task.args.input_from == "encoder": - non_padding_mask = ~model_out["encoder_padding_mask"][0] - input_lengths = non_padding_mask.long().sum(-1) + if len(model_out["encoder_padding_mask"]) > 0: + non_padding_mask = ~model_out["encoder_padding_mask"][0] + input_lengths = non_padding_mask.long().sum(-1) + else: + out = model_out["encoder_states"][layer_id] + input_lengths = out.new_full( + (out.shape[1],), out.shape[0] + ).long() + task_sample = { "net_input": { "src_tokens": model_out["encoder_states"][ @@ -125,10 +149,10 @@ def reduce_metrics(cls, logging_outputs) -> None: @register_criterion( - "speech_to_unit", dataclass=LabelSmoothedCrossEntropyCriterionConfig + "speech_to_unit", dataclass=RdropLabelSmoothedCrossEntropyCriterionConfig ) class SpeechToUnitMultitaskTaskCriterion( - LabelSmoothedCrossEntropyCriterion, MultitaskCriterion + RdropLabelSmoothedCrossEntropyCriterion, MultitaskCriterion ): def __init__( self, @@ -137,22 +161,34 @@ def __init__( label_smoothing, ignore_prefix_size=0, report_accuracy=False, + rdrop_alpha=0.0, ): super().__init__( - task, sentence_avg, label_smoothing, ignore_prefix_size, report_accuracy + task, + sentence_avg, + label_smoothing, + ignore_prefix_size, + report_accuracy, + rdrop_alpha, ) - MultitaskCriterion.__init__(self, task.multitask_tasks) + MultitaskCriterion.__init__(self, task.multitask_tasks, rdrop_alpha) def forward(self, model, sample, reduce=True): - net_output, extra = model( - src_tokens=sample["net_input"]["src_tokens"], - src_lengths=sample["net_input"]["src_lengths"], - prev_output_tokens=sample["net_input"]["prev_output_tokens"], - tgt_speaker=sample["net_input"]["tgt_speaker"], - return_all_hiddens=True, - ) + net_input_concat = { + "src_tokens": sample["net_input"]["src_tokens"], + "src_lengths": sample["net_input"]["src_lengths"], + "prev_output_tokens": sample["net_input"]["prev_output_tokens"], + "tgt_speaker": sample["net_input"].get("tgt_speaker", None), + "return_all_hiddens": True, + } - loss, nll_loss = self.compute_loss(model, [net_output], sample, reduce=reduce) + if self.rdrop_alpha > 0 or self.rdrop_alpha_mtl > 0: + net_input_concat = duplicate_input(net_input_concat) + + net_output, extra = model(**net_input_concat) + loss, nll_loss, rdrop_kl_loss = self.compute_loss( + model, [net_output], sample, reduce=reduce + ) sample_size = ( sample["target"].size(0) if self.sentence_avg else sample["ntokens"] ) @@ -167,6 +203,8 @@ def forward(self, model, sample, reduce=True): n_correct, total = self.compute_accuracy(model, [net_output], sample) logging_output["n_correct"] = utils.item(n_correct.data) logging_output["total"] = utils.item(total.data) + if self.rdrop_alpha > 0: + logging_output["rdrop_kl_loss"] = utils.item(rdrop_kl_loss.data) if len(self.multitask_criterion) == 0: return loss, sample_size, logging_output diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 1fcf419d7a..4475dbfc81 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -2,15 +2,15 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. + +import logging from argparse import Namespace from copy import deepcopy from pathlib import Path -import logging from typing import Dict, Optional from fairseq.data import Dictionary - logger = logging.getLogger(__name__) @@ -335,3 +335,7 @@ def get_loss_weight(self, num_updates): loss_weight_min, ) return weight + + @property + def rdrop_alpha(self): + return self.config.get("rdrop_alpha", None) From dd0079bde7f678b0cd0715cbd0ae68d661b7226d Mon Sep 17 00:00:00 2001 From: Ilia Kulikov <kulikov@cs.nyu.edu> Date: Fri, 30 Sep 2022 11:00:15 -0700 Subject: [PATCH 687/774] use src_lengths from net_input if possible if src_tokens in the input (#4751) * use src_lengths from net_input if possible * lint+black --- fairseq/sequence_generator.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fairseq/sequence_generator.py b/fairseq/sequence_generator.py index 13f99078c7..78db504e6c 100644 --- a/fairseq/sequence_generator.py +++ b/fairseq/sequence_generator.py @@ -222,9 +222,15 @@ def _generate( if "src_tokens" in net_input: src_tokens = net_input["src_tokens"] # length of the source text being the character length except EndOfSentence and pad - src_lengths = ( - (src_tokens.ne(self.eos) & src_tokens.ne(self.pad)).long().sum(dim=1) - ) + # if src_lengths exists in net_input (speech_to_text dataset case), then use it + if "src_lengths" in net_input: + src_lengths = net_input["src_lengths"] + else: + src_lengths = ( + (src_tokens.ne(self.eos) & src_tokens.ne(self.pad)) + .long() + .sum(dim=1) + ) elif "source" in net_input: src_tokens = net_input["source"] src_lengths = ( From 0e9a4250398c409a5fa765b5895e9bfc759c1871 Mon Sep 17 00:00:00 2001 From: Guillaume Wenzek <gwenzek@users.noreply.github.com> Date: Thu, 6 Oct 2022 11:18:47 +0200 Subject: [PATCH 688/774] drop apex/megatron in CI (not used) (#4757) --- .circleci/config.yml | 53 ++----------------- .../fully_sharded_data_parallel.py | 14 ++++- 2 files changed, 16 insertions(+), 51 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6187ccc688..7a2ab46797 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,47 +17,6 @@ gpu: &gpu # ------------------------------------------------------------------------------------- cache_key: &cache_key cache-key-{{ .Environment.CIRCLE_JOB }}-{{ checksum ".circleci/config.yml" }}-{{ checksum "setup.py"}} -install_dep_common: &install_dep_common - - run: - name: Install Common Dependencies - command: | - source activate fairseq - pip install --upgrade setuptools - pip install bitarray boto3 deepspeed editdistance fastBPE iopath ipdb ipython pyarrow pytest sacremoses sentencepiece subword-nmt hydra-core==1.0.7 omegaconf==2.0.6 - pip install --progress-bar off pytest - pip install --progress-bar off fairscale - pip install -i https://test.pypi.org/simple/ bitsandbytes-cuda111 -U - python -c 'import torch; print("Torch version:", torch.__version__)' - python -m torch.utils.collect_env - -install_dep_fused_ops: &install_dep_fused_ops - # this version of Apex is from Feb 2021 and doesn't work with torch>=1.12 - - run: - name: Install Megatron/Apex Dependencies - working_directory: ~/ - command: | - source activate fairseq - git clone https://github.com/NVIDIA/apex - cd apex - git checkout e2083df5eb96643c61613b9df48dd4eea6b07690 - sed -i '101,107 s/^/#/' setup.py - pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" --global-option="--deprecated_fused_adam" --global-option="--xentropy" --global-option="--fast_multihead_attn" ./ - cd ~/ - git clone --depth=1 --branch v2.4 https://github.com/NVIDIA/Megatron-LM.git - cd Megatron-LM - pip install -e . - -install_dep_xformers: &install_dep_xformers - - run: - name: Install xFormers Dependencies - working_directory: ~/ - command: | - source activate fairseq - git clone https://github.com/facebookresearch/xformers.git - cd xformers - pip install -r requirements.txt - pip install -e . - install_dep_pt1_10: &install_dep_pt1_10 - run: name: Install Pytorch Dependencies @@ -81,8 +40,9 @@ install_repo: &install_repo name: Install Repository command: | source activate fairseq - pip install . - python setup.py build_ext --inplace + python -m pip install fairscale + python -m pip install -e '.[dev,docs]' + python -c 'import torch; print("Torch version:", torch.__version__)' run_unittests: &run_unittests - run: @@ -134,8 +94,6 @@ jobs: - restore_cache: key: *cache_key - <<: *install_dep_pt1_10 - - <<: *install_dep_common - - <<: *install_dep_fused_ops - save_cache: paths: - ~/miniconda/ @@ -155,8 +113,6 @@ jobs: - restore_cache: key: *cache_key - <<: *install_dep_pt1_12 - - <<: *install_dep_common - - <<: *install_dep_fused_ops - save_cache: paths: - ~/miniconda/ @@ -168,6 +124,5 @@ workflows: version: 2 build: jobs: - # TODO: Figure out how to run APEX on torch 1.12 - # - gpu_tests_pt1_12 + - gpu_tests_pt1_12 - gpu_tests_pt1_10 diff --git a/fairseq/distributed/fully_sharded_data_parallel.py b/fairseq/distributed/fully_sharded_data_parallel.py index 88dc698b4d..1c508b05dd 100644 --- a/fairseq/distributed/fully_sharded_data_parallel.py +++ b/fairseq/distributed/fully_sharded_data_parallel.py @@ -76,6 +76,18 @@ def load_state_dict(self, state_dict, strict=True, model_cfg=None): return super().load_state_dict(state_dict, strict=strict) +class DummyProcessGroup: + def __init__(self, rank: int, size: int): + self._rank = rank + self._size = size + + def rank(self) -> int: + return self._rank + + def size(self) -> int: + return self._size + + @contextlib.contextmanager def fsdp_enable_wrap(cfg: DistributedTrainingConfig): try: @@ -89,8 +101,6 @@ def fsdp_enable_wrap(cfg: DistributedTrainingConfig): assert cfg.fp16 # memory_efficient_fp16 should imply fp16 group = dist_utils.get_data_parallel_group() if group is None and cfg.distributed_world_size == 1: - from fairscale.utils.testing import DummyProcessGroup - group = DummyProcessGroup(rank=0, size=1) fsdp_config = { "process_group": group, From 9273676f50e5ff93767e88c832bc2c96858ba04b Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Thu, 6 Oct 2022 12:43:30 -0700 Subject: [PATCH 689/774] Support multitask for XMTransformer (#4763) --- .../criterions/speech_to_speech_criterion.py | 6 ++- .../models/speech_to_text/xm_transformer.py | 41 ++++++++++++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/fairseq/criterions/speech_to_speech_criterion.py b/fairseq/criterions/speech_to_speech_criterion.py index 6212395e3c..0cc2c4870c 100644 --- a/fairseq/criterions/speech_to_speech_criterion.py +++ b/fairseq/criterions/speech_to_speech_criterion.py @@ -33,11 +33,15 @@ def __init__(self, multitask_tasks, rdrop_alpha=0.0): self.multitask_criterion = OrderedDict() self.multitask_loss_weight = OrderedDict() for task_name, task_obj in multitask_tasks.items(): + if task_obj.args.get_loss_weight(0) == 0: + logger.info(f"Skip {task_name} loss criterion") + continue + rdrop_alpha_task = task_obj.args.rdrop_alpha if rdrop_alpha_task is None: rdrop_alpha_task = rdrop_alpha self.rdrop_alpha_mtl = rdrop_alpha_task - logger.info(f"rdrop_alpha is set to {rdrop_alpha_task}") + logger.info(f"rdrop_alpha is set to {rdrop_alpha_task} for {task_name}") if task_obj.args.decoder_type == "ctc": self.multitask_criterion[task_name] = CtcCriterion( diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index 84d8186260..bb93448cfc 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -17,6 +17,8 @@ from fairseq.models import ( FairseqEncoder, FairseqEncoderDecoderModel, + FairseqEncoderModel, + FairseqLanguageModel, register_model, register_model_architecture, ) @@ -643,7 +645,29 @@ def build_model(cls, args, task): encoder = cls.build_encoder(args) decoder = cls.build_decoder(args, task, decoder_embed_tokens) - return cls(encoder, decoder) + base_model = cls(encoder, decoder) + + # set up multitask decoders + base_model.multitask_decoders = {} + for i, (task_name, task_obj) in enumerate(task.multitask_tasks.items()): + # dummy auxiliary decoder + if task_obj.args.get_loss_weight(0) == 0: + continue + + task_decoder = cls.build_multitask_decoder( + task_obj.args, task_obj.target_dictionary, args.decoder_embed_dim + ) + + setattr(base_model, f"{task_name}_decoder", task_decoder) + decoder_model_cls = ( + FairseqEncoderModel + if task_obj.args.decoder_type == "ctc" + else FairseqLanguageModel + ) + base_model.multitask_decoders[task_name] = decoder_model_cls( + getattr(base_model, f"{task_name}_decoder") + ) + return base_model def get_normalized_probs( self, @@ -653,7 +677,14 @@ def get_normalized_probs( ): return self.get_normalized_probs_scriptable(net_output, log_probs, sample) - def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + return_all_hiddens=False, + **kwargs, + ): """ The forward method inherited from the base class has a **kwargs argument in its input, which is not supported in torchscript. This @@ -665,6 +696,12 @@ def forward(self, src_tokens, src_lengths, prev_output_tokens, **kwargs): decoder_out = self.decoder( prev_output_tokens=prev_output_tokens, encoder_out=encoder_out ) + if return_all_hiddens: + decoder_out[-1]["encoder_states"] = encoder_out["encoder_out"] + # NOTE: from the top layer + decoder_out[-1]["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ] return decoder_out def upgrade_state_dict(self, state_dict): From 21865d58770e4019d8f61fa8e52f392fa15ce901 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Thu, 6 Oct 2022 16:36:49 -0700 Subject: [PATCH 690/774] Add a missing method to XMTransformer (#4764) * Add build_multitask_decoder() * Fix import --- .../models/speech_to_text/xm_transformer.py | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index bb93448cfc..303c27d43b 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -22,8 +22,13 @@ register_model, register_model_architecture, ) +from fairseq.models.speech_to_speech.modules import CTCDecoder from fairseq.models.speech_to_text.hub_interface import S2THubInterface -from fairseq.models.transformer import Embedding, TransformerDecoder +from fairseq.models.transformer import ( + Embedding, + TransformerDecoder, + TransformerModelBase, +) from fairseq.models.wav2vec import Wav2VecEncoder from fairseq.modules.layer_norm import LayerNorm @@ -669,6 +674,42 @@ def build_model(cls, args, task): ) return base_model + @classmethod + def build_multitask_decoder( + cls, args, mtl_args, tgt_dict, in_dim, is_first_pass_decoder + ): + decoder_args = mtl_args.decoder_args + decoder_args.encoder_embed_dim = in_dim + if mtl_args.decoder_type == "transformer": + if is_first_pass_decoder: + task_decoder = cls.build_text_decoder(args, tgt_dict) + else: + from fairseq.models.speech_to_speech import ( + base_multitask_text_transformer_decoder_arch, + ) + + base_multitask_text_transformer_decoder_arch(decoder_args) # 2L + task_decoder = TransformerDecoder( + decoder_args, + tgt_dict, + embed_tokens=TransformerModelBase.build_embedding( + decoder_args, + tgt_dict, + decoder_args.decoder_embed_dim, + ), + ) + elif args.decoder_type == "ctc": + task_decoder = CTCDecoder( + dictionary=tgt_dict, + in_dim=in_dim, + ) + else: + raise NotImplementedError( + "currently only support multitask decoder_type 'transformer', 'ctc'" + ) + + return task_decoder + def get_normalized_probs( self, net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], From 6d90f79883a53f0531e716d35cb17e9689e5a716 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Thu, 6 Oct 2022 17:38:12 -0700 Subject: [PATCH 691/774] Refactor S2ST (#4747) * Move S2ST submodules to separate files * Refactoring * Fix import --- fairseq/models/speech_to_speech/__init__.py | 1 - .../speech_to_speech/modules/__init__.py | 0 .../speech_to_speech/modules/ctc_decoder.py | 18 ++++++++ .../stacked_embedding.py} | 11 ----- .../models/speech_to_speech/s2s_conformer.py | 42 +++++++++++-------- .../speech_to_speech/s2s_transformer.py | 9 ++-- fairseq/models/speech_to_text/berard.py | 4 +- .../models/speech_to_text/convtransformer.py | 4 +- .../models/speech_to_text/s2t_transformer.py | 2 +- .../models/speech_to_text/xm_transformer.py | 4 +- 10 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 fairseq/models/speech_to_speech/modules/__init__.py create mode 100644 fairseq/models/speech_to_speech/modules/ctc_decoder.py rename fairseq/models/speech_to_speech/{modules.py => modules/stacked_embedding.py} (83%) diff --git a/fairseq/models/speech_to_speech/__init__.py b/fairseq/models/speech_to_speech/__init__.py index 64ea7cda62..3d9e4728df 100644 --- a/fairseq/models/speech_to_speech/__init__.py +++ b/fairseq/models/speech_to_speech/__init__.py @@ -3,6 +3,5 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. -from .modules import * # noqa from .s2s_conformer import * # noqa from .s2s_transformer import * # noqa diff --git a/fairseq/models/speech_to_speech/modules/__init__.py b/fairseq/models/speech_to_speech/modules/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/fairseq/models/speech_to_speech/modules/ctc_decoder.py b/fairseq/models/speech_to_speech/modules/ctc_decoder.py new file mode 100644 index 0000000000..721efbf61a --- /dev/null +++ b/fairseq/models/speech_to_speech/modules/ctc_decoder.py @@ -0,0 +1,18 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from torch import nn + +from fairseq.models import FairseqEncoder + + +class CTCDecoder(FairseqEncoder): + def __init__(self, dictionary, in_dim): + super().__init__(dictionary) + self.proj = nn.Linear(in_dim, len(dictionary)) + + def forward(self, src_tokens, src_lengths=None, **kwargs): + encoder_out = self.proj(src_tokens) + return {"encoder_out": encoder_out} diff --git a/fairseq/models/speech_to_speech/modules.py b/fairseq/models/speech_to_speech/modules/stacked_embedding.py similarity index 83% rename from fairseq/models/speech_to_speech/modules.py rename to fairseq/models/speech_to_speech/modules/stacked_embedding.py index a2049816ab..5955a08538 100644 --- a/fairseq/models/speech_to_speech/modules.py +++ b/fairseq/models/speech_to_speech/modules/stacked_embedding.py @@ -6,20 +6,9 @@ import torch from torch import nn -from fairseq.models import FairseqEncoder from fairseq.models.transformer import Linear -class CTCDecoder(FairseqEncoder): - def __init__(self, dictionary, in_dim): - super().__init__(dictionary) - self.proj = nn.Linear(in_dim, len(dictionary)) - - def forward(self, src_tokens, src_lengths=None, **kwargs): - encoder_out = self.proj(src_tokens) - return {"encoder_out": encoder_out} - - class StackedEmbedding(nn.Embedding): """Embedding module that supports stacked units -> single embedding""" diff --git a/fairseq/models/speech_to_speech/s2s_conformer.py b/fairseq/models/speech_to_speech/s2s_conformer.py index ff890f4210..50fb2c4b75 100644 --- a/fairseq/models/speech_to_speech/s2s_conformer.py +++ b/fairseq/models/speech_to_speech/s2s_conformer.py @@ -10,9 +10,9 @@ from fairseq import checkpoint_utils from fairseq.models import register_model, register_model_architecture -from fairseq.models.speech_to_speech.s2s_transformer import S2UTTransformerModel from fairseq.models.speech_to_speech.s2s_transformer import ( - s2ut_architecture_base as s2ut_transformer_architecture_base, + S2UTTransformerModel, + s2ut_architecture_base, ) from fairseq.models.speech_to_text import S2TConformerEncoder from fairseq.models.transformer import Linear @@ -20,6 +20,22 @@ logger = logging.getLogger(__name__) +def build_s2s_conformer_encoder(args): + encoder = S2SConformerEncoder(args) + pretraining_path = getattr(args, "load_pretrained_encoder_from", None) + if pretraining_path is not None: + if not Path(pretraining_path).exists(): + logger.warning( + f"skipped pretraining because {pretraining_path} does not exist" + ) + else: + encoder = checkpoint_utils.load_pretrained_component_from_model( + component=encoder, checkpoint=pretraining_path + ) + logger.info(f"loaded pretrained encoder from: {pretraining_path}") + return encoder + + class S2SConformerEncoder(S2TConformerEncoder): """Based on S2T transformer encoder, with support to incorporate target speaker embedding.""" @@ -51,7 +67,7 @@ def forward( @register_model("s2ut_conformer") class S2UTConformerModel(S2UTTransformerModel): """ - Direct speech-to-speech translation model with S2T Conformer encoder + Transformer discrete unit decoder + Direct speech-to-speech translation model with Conformer encoder + Transformer discrete unit decoder """ @staticmethod @@ -78,25 +94,15 @@ def add_args(parser): @classmethod def build_encoder(cls, args): - encoder = S2SConformerEncoder(args) - pretraining_path = getattr(args, "load_pretrained_encoder_from", None) - if pretraining_path is not None: - if not Path(pretraining_path).exists(): - logger.warning( - f"skipped pretraining because {pretraining_path} does not exist" - ) - else: - encoder = checkpoint_utils.load_pretrained_component_from_model( - component=encoder, checkpoint=pretraining_path - ) - logger.info(f"loaded pretrained encoder from: {pretraining_path}") - return encoder + return build_s2s_conformer_encoder(args) @register_model_architecture("s2ut_conformer", "s2ut_conformer") -def s2ut_base_architecture(args): +def s2ut_conformer_architecture_base(args): args.attn_type = getattr(args, "attn_type", None) args.pos_enc_type = getattr(args, "pos_enc_type", "abs") + args.input_feat_per_channel = getattr(args, "input_feat_per_channel", 80) + args.input_channels = getattr(args, "input_channels", 1) args.max_source_positions = getattr(args, "max_source_positions", 6000) args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) @@ -104,4 +110,4 @@ def s2ut_base_architecture(args): args.dropout = getattr(args, "dropout", 0.1) args.encoder_layers = getattr(args, "encoder_layers", 16) args.depthwise_conv_kernel_size = getattr(args, "depthwise_conv_kernel_size", 31) - s2ut_transformer_architecture_base(args) + s2ut_architecture_base(args) diff --git a/fairseq/models/speech_to_speech/s2s_transformer.py b/fairseq/models/speech_to_speech/s2s_transformer.py index 7e1e9b72a5..07393d2598 100644 --- a/fairseq/models/speech_to_speech/s2s_transformer.py +++ b/fairseq/models/speech_to_speech/s2s_transformer.py @@ -18,7 +18,8 @@ register_model, register_model_architecture, ) -from fairseq.models.speech_to_speech.modules import CTCDecoder, StackedEmbedding +from fairseq.models.speech_to_speech.modules.ctc_decoder import CTCDecoder +from fairseq.models.speech_to_speech.modules.stacked_embedding import StackedEmbedding from fairseq.models.speech_to_text import S2TTransformerEncoder from fairseq.models.text_to_speech import TTSTransformerDecoder from fairseq.models.transformer import Linear, TransformerDecoder, TransformerModelBase @@ -236,7 +237,7 @@ def forward_encoder(self, src_tokens, src_lengths, speaker=None, **kwargs): @register_model("s2ut_transformer") class S2UTTransformerModel(S2STransformerMultitaskModelBase): """ - Direct speech-to-speech translation model with S2T Transformer encoder + Transformer discrete unit decoder + Direct speech-to-speech translation model with Transformer encoder + Transformer discrete unit decoder https://arxiv.org/abs/2107.05604 """ @@ -246,7 +247,7 @@ def add_args(parser): parser.add_argument( "--conv-kernel-sizes", type=str, - metavar="N", + metavar="STR", help="kernel sizes of Conv1d (s2t_transformer) subsampling layers", ) parser.add_argument( @@ -434,7 +435,7 @@ def add_args(parser): parser.add_argument( "--conv-kernel-sizes", type=str, - metavar="N", + metavar="STR", help="kernel sizes of Conv1d (s2t_transformer) subsampling layers", ) parser.add_argument( diff --git a/fairseq/models/speech_to_text/berard.py b/fairseq/models/speech_to_text/berard.py index 7babe7a230..107ac983c6 100644 --- a/fairseq/models/speech_to_text/berard.py +++ b/fairseq/models/speech_to_text/berard.py @@ -132,7 +132,7 @@ def build_encoder(cls, args, task): lstm_size=args.lstm_size, dropout=args.dropout, ) - if getattr(args, "load_pretrained_encoder_from", None): + if getattr(args, "load_pretrained_encoder_from", None) is not None: encoder = checkpoint_utils.load_pretrained_component_from_model( component=encoder, checkpoint=args.load_pretrained_encoder_from ) @@ -150,7 +150,7 @@ def build_decoder(cls, args, task): attention_dim=args.attention_dim, output_layer_dim=args.output_layer_dim, ) - if getattr(args, "load_pretrained_decoder_from", None): + if getattr(args, "load_pretrained_decoder_from", None) is not None: decoder = checkpoint_utils.load_pretrained_component_from_model( component=decoder, checkpoint=args.load_pretrained_decoder_from ) diff --git a/fairseq/models/speech_to_text/convtransformer.py b/fairseq/models/speech_to_text/convtransformer.py index 29dd49cec0..4d0fc02aee 100644 --- a/fairseq/models/speech_to_text/convtransformer.py +++ b/fairseq/models/speech_to_text/convtransformer.py @@ -162,7 +162,7 @@ def add_args(parser): @classmethod def build_encoder(cls, args): encoder = ConvTransformerEncoder(args) - if getattr(args, "load_pretrained_encoder_from", None): + if getattr(args, "load_pretrained_encoder_from", None) is not None: encoder = checkpoint_utils.load_pretrained_component_from_model( component=encoder, checkpoint=args.load_pretrained_encoder_from ) @@ -171,7 +171,7 @@ def build_encoder(cls, args): @classmethod def build_decoder(cls, args, task, embed_tokens): decoder = TransformerDecoderNoExtra(args, task.target_dictionary, embed_tokens) - if getattr(args, "load_pretrained_decoder_from", None): + if getattr(args, "load_pretrained_decoder_from", None) is not None: decoder = checkpoint_utils.load_pretrained_component_from_model( component=decoder, checkpoint=args.load_pretrained_decoder_from ) diff --git a/fairseq/models/speech_to_text/s2t_transformer.py b/fairseq/models/speech_to_text/s2t_transformer.py index 6adbd3c339..50fae2ffa2 100644 --- a/fairseq/models/speech_to_text/s2t_transformer.py +++ b/fairseq/models/speech_to_text/s2t_transformer.py @@ -85,7 +85,7 @@ def add_args(parser): parser.add_argument( "--conv-kernel-sizes", type=str, - metavar="N", + metavar="STR", help="kernel sizes of Conv1d (s2t_transformer) subsampling layers", ) parser.add_argument( diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index 303c27d43b..f6aa590493 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -22,7 +22,7 @@ register_model, register_model_architecture, ) -from fairseq.models.speech_to_speech.modules import CTCDecoder +from fairseq.models.speech_to_speech.modules.ctc_decoder import CTCDecoder from fairseq.models.speech_to_text.hub_interface import S2THubInterface from fairseq.models.transformer import ( Embedding, @@ -639,7 +639,7 @@ def build_model(cls, args, task): # make sure all arguments are present in older models base_architecture(args) - if getattr(args, "load_pretrained_decoder_from", None): + if getattr(args, "load_pretrained_decoder_from", None) is not None: ckpt = torch.load(getattr(args, "load_pretrained_decoder_from", None)) decoder_args_dict = cls.get_decoder_args_from_checkpoint(ckpt["cfg"]) args = cls.override_decoder_args(args, decoder_args_dict) From b4001184f49ed0e20d619b54bb3d43088fabf990 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Thu, 6 Oct 2022 19:38:32 -0700 Subject: [PATCH 692/774] UnitY implementation (#4670) * Add UnitY implementation * Rename for consistency * Refactor conformer encoder construction * Change the order of arguments for rdrop_alpha * Add compute_loss_with_rdrop * Move build_multitask_decoder to xm_transformer_unity.py * Fix generator selection * Fix check in build_criterion * Modularize Rdrop * Minor fix * Refine class names * Refactor submodules * Fix CE * Fix import * Fix argments for datasets * Add description to AugTransformerDecoderBase * Fix SpeechToTextDatasetCreator * Fix metavar in arguments * Uncomment override_decoder_args * Fix comment in warning * Add is_fisrt_pass_decoder flag * Change Translatotron2SpeechGenerator to MultiDecoderSpeechGenerator * Move inference code to examples/speech_to_speech/unity * Fix rdrop default value in aux tasks * Add language tag mapping option to multitask-config-yaml * Rename encoder_out2 and encoder_outs2 * Rename UnitYXMTransformerModel to XMTransformerModelUnitY * Support num_best_checkpoints in average_checkpoints * Fix has_multitask * Inherit SequenceGenerator * Reflect recent updates * Minor fix in logging * Fix typo * Refactor SpeechToSpectrogram2passMultitaskTaskCriterion * Minor update for multitask --- examples/speech_to_speech/__init__.py | 2 + examples/speech_to_speech/unity/__init__.py | 7 + .../unity/sequence_generator.py | 626 ++++++++++++++++++ .../unity/sequence_generator_multi_decoder.py | 260 ++++++++ .../criterions/speech_to_speech_criterion.py | 165 ++++- fairseq/data/audio/data_cfg.py | 48 +- .../data/audio/speech_to_speech_dataset.py | 5 +- fairseq/data/audio/speech_to_text_dataset.py | 35 +- fairseq/dataclass/configs.py | 22 + fairseq/models/speech_to_speech/__init__.py | 2 + .../modules/transformer_decoder_aug.py | 108 +++ .../modules/transformer_encoder.py | 85 +++ .../models/speech_to_speech/s2s_conformer.py | 59 ++ .../s2s_conformer_translatotron2.py | 262 ++++++++ .../speech_to_speech/s2s_conformer_unity.py | 298 +++++++++ fairseq/models/speech_to_text/__init__.py | 1 + .../models/speech_to_text/xm_transformer.py | 1 + .../speech_to_text/xm_transformer_unity.py | 351 ++++++++++ .../models/transformer/transformer_decoder.py | 4 +- .../transformer/transformer_decoder_aug.py | 392 +++++++++++ fairseq/modules/transformer_layer.py | 2 +- fairseq/modules/transformer_layer_aug.py | 315 +++++++++ fairseq/speech_generator.py | 198 +++++- fairseq/tasks/speech_to_speech.py | 163 ++++- fairseq/tasks/speech_to_text.py | 100 ++- scripts/average_checkpoints.py | 16 + 26 files changed, 3481 insertions(+), 46 deletions(-) create mode 100644 examples/speech_to_speech/unity/__init__.py create mode 100644 examples/speech_to_speech/unity/sequence_generator.py create mode 100644 examples/speech_to_speech/unity/sequence_generator_multi_decoder.py create mode 100644 fairseq/models/speech_to_speech/modules/transformer_decoder_aug.py create mode 100644 fairseq/models/speech_to_speech/modules/transformer_encoder.py create mode 100644 fairseq/models/speech_to_speech/s2s_conformer_translatotron2.py create mode 100644 fairseq/models/speech_to_speech/s2s_conformer_unity.py create mode 100644 fairseq/models/speech_to_text/xm_transformer_unity.py create mode 100644 fairseq/models/transformer/transformer_decoder_aug.py create mode 100644 fairseq/modules/transformer_layer_aug.py diff --git a/examples/speech_to_speech/__init__.py b/examples/speech_to_speech/__init__.py index 6264236915..812b3c30b9 100644 --- a/examples/speech_to_speech/__init__.py +++ b/examples/speech_to_speech/__init__.py @@ -2,3 +2,5 @@ # # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. + +from . import unity # noqa diff --git a/examples/speech_to_speech/unity/__init__.py b/examples/speech_to_speech/unity/__init__.py new file mode 100644 index 0000000000..349db7c65e --- /dev/null +++ b/examples/speech_to_speech/unity/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from . import sequence_generator # noqa +from . import sequence_generator_multi_decoder # noqa diff --git a/examples/speech_to_speech/unity/sequence_generator.py b/examples/speech_to_speech/unity/sequence_generator.py new file mode 100644 index 0000000000..c482098feb --- /dev/null +++ b/examples/speech_to_speech/unity/sequence_generator.py @@ -0,0 +1,626 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +import sys +from typing import Dict, List, Optional + +import torch +from torch import Tensor + +from fairseq.sequence_generator import EnsembleModel as EnsembleModelBase +from fairseq.sequence_generator import SequenceGenerator as SequenceGeneratorBase + + +class SequenceGenerator(SequenceGeneratorBase): + def __init__( + self, + models, + tgt_dict, + beam_size=1, + max_len_a=0, + max_len_b=200, + max_len=0, + min_len=1, + normalize_scores=True, + len_penalty=1.0, + unk_penalty=0.0, + temperature=1.0, + match_source_len=False, + no_repeat_ngram_size=0, + search_strategy=None, + eos=None, + symbols_to_strip_from_output=None, + lm_model=None, + lm_weight=1.0, + tokens_to_suppress=(), + ): + """Generates translations of a given source sentence. + + Args: + models (List[~fairseq.models.FairseqModel]): ensemble of models, + currently support fairseq.models.TransformerModel for scripting + beam_size (int, optional): beam width (default: 1) + max_len_a/b (int, optional): generate sequences of maximum length + ax + b, where x is the source length + max_len (int, optional): the maximum length of the generated output + (not including end-of-sentence) + min_len (int, optional): the minimum length of the generated output + (not including end-of-sentence) + normalize_scores (bool, optional): normalize scores by the length + of the output (default: True) + len_penalty (float, optional): length penalty, where <1.0 favors + shorter, >1.0 favors longer sentences (default: 1.0) + unk_penalty (float, optional): unknown word penalty, where <0 + produces more unks, >0 produces fewer (default: 0.0) + temperature (float, optional): temperature, where values + >1.0 produce more uniform samples and values <1.0 produce + sharper samples (default: 1.0) + match_source_len (bool, optional): outputs should match the source + length (default: False) + """ + super().__init__( + models=models, + tgt_dict=tgt_dict, + beam_size=beam_size, + max_len_a=max_len_a, + max_len_b=max_len_b, + max_len=max_len, + min_len=min_len, + normalize_scores=normalize_scores, + len_penalty=len_penalty, + unk_penalty=unk_penalty, + temperature=temperature, + match_source_len=match_source_len, + no_repeat_ngram_size=no_repeat_ngram_size, + search_strategy=search_strategy, + eos=eos, + symbols_to_strip_from_output=symbols_to_strip_from_output, + lm_model=lm_model, + lm_weight=lm_weight, + tokens_to_suppress=tokens_to_suppress, + ) + + if isinstance(models, EnsembleModel): + self.model = models + else: + self.model = EnsembleModel(models) + + self.model.set_decoder_beam_size(self.beam_size) + self.model.eval() + + def _generate( + self, + sample: Dict[str, Dict[str, Tensor]], + prefix_tokens: Optional[Tensor] = None, + constraints: Optional[Tensor] = None, + bos_token: Optional[int] = None, + ): + net_input = sample["net_input"] + + if "src_tokens" in net_input: + src_tokens = net_input["src_tokens"] + # length of the source text being the character length except EndOfSentence and pad + # if src_lengths exists in net_input (speech_to_text dataset case), then use it + if "src_lengths" in net_input: + src_lengths = net_input["src_lengths"] + else: + src_lengths = ( + (src_tokens.ne(self.eos) & src_tokens.ne(self.pad)) + .long() + .sum(dim=1) + ) + elif "source" in net_input: + src_tokens = net_input["source"] + src_lengths = ( + net_input["padding_mask"].size(-1) - net_input["padding_mask"].sum(-1) + if net_input["padding_mask"] is not None + else torch.tensor(src_tokens.size(-1)).to(src_tokens) + ) + elif "features" in net_input: + src_tokens = net_input["features"] + src_lengths = ( + net_input["padding_mask"].size(-1) - net_input["padding_mask"].sum(-1) + if net_input["padding_mask"] is not None + else torch.tensor(src_tokens.size(-1)).to(src_tokens) + ) + else: + raise Exception( + "expected src_tokens or source in net input. input keys: " + + str(net_input.keys()) + ) + + if constraints is not None and not self.search.supports_constraints: + raise NotImplementedError( + "Target-side constraints were provided, but search method doesn't support them" + ) + + # Initialize constraints, when active + self.search.init_constraints(constraints, self.beam_size) + + # compute the encoder output for each beam + with torch.autograd.profiler.record_function("EnsembleModel: forward_encoder"): + encoder_outs = self.model.forward_encoder(net_input) + + finalized = self.generate_decoder( + encoder_outs, + src_tokens, + src_lengths, + sample, + prefix_tokens, + constraints, + bos_token, + ) + return finalized + + def generate_decoder( + self, + encoder_outs, + src_tokens, + src_lengths, + sample: Dict[str, Dict[str, Tensor]], + prefix_tokens: Optional[Tensor] = None, + constraints: Optional[Tensor] = None, + bos_token: Optional[int] = None, + aux_task_name="", + encoder_outs_aug: Optional[ + Tensor + ] = None, # an additional/augmented encoder_outs + ): + incremental_states = torch.jit.annotate( + List[Dict[str, Dict[str, Optional[Tensor]]]], + [ + torch.jit.annotate(Dict[str, Dict[str, Optional[Tensor]]], {}) + for i in range(self.model.models_size) + ], + ) + + # bsz: total number of sentences in beam + # Note that src_tokens may have more than 2 dimensions (i.e. audio features) + bsz, src_len = src_tokens.size()[:2] + beam_size = self.beam_size + + decoder_name = f"{aux_task_name}_decoder" if aux_task_name else "decoder" + + max_len: int = -1 + if self.match_source_len: + max_len = src_lengths.max().item() + else: + max_len = min( + int(self.max_len_a * src_len + self.max_len_b), + self.max_len - 1, + ) + assert ( + self.min_len <= max_len + ), "min_len cannot be larger than max_len, please adjust these!" + + # placeholder of indices for bsz * beam_size to hold tokens and accumulative scores + new_order = torch.arange(bsz).view(-1, 1).repeat(1, beam_size).view(-1) + new_order = new_order.to(src_tokens.device).long() + encoder_outs = self.model.reorder_encoder_out(encoder_outs, new_order) + # ensure encoder_outs is a List. + assert encoder_outs is not None + if encoder_outs_aug is not None: + encoder_outs_aug = self.model.reorder_encoder_out( + encoder_outs_aug, new_order + ) + + # initialize buffers + scores = ( + torch.zeros(bsz * beam_size, max_len + 1).to(src_tokens).float() + ) # +1 for eos; pad is never chosen for scoring + tokens = ( + torch.zeros(bsz * beam_size, max_len + 2) + .to(src_tokens) + .long() + .fill_(self.pad) + ) # +2 for eos and pad + tokens[:, 0] = self.eos if bos_token is None else bos_token + attn: Optional[Tensor] = None + + # A list that indicates candidates that should be ignored. + # For example, suppose we're sampling and have already finalized 2/5 + # samples. Then cands_to_ignore would mark 2 positions as being ignored, + # so that we only finalize the remaining 3 samples. + cands_to_ignore = ( + torch.zeros(bsz, beam_size).to(src_tokens).eq(-1) + ) # forward and backward-compatible False mask + + # list of completed sentences + finalized = torch.jit.annotate( + List[List[Dict[str, Tensor]]], + [torch.jit.annotate(List[Dict[str, Tensor]], []) for i in range(bsz)], + ) # contains lists of dictionaries of infomation about the hypothesis being finalized at each step + + # a boolean array indicating if the sentence at the index is finished or not + finished = [False for i in range(bsz)] + num_remaining_sent = bsz # number of sentences remaining + + # number of candidate hypos per step + cand_size = 2 * beam_size # 2 x beam size in case half are EOS + + # offset arrays for converting between different indexing schemes + bbsz_offsets = ( + (torch.arange(0, bsz) * beam_size) + .unsqueeze(1) + .type_as(tokens) + .to(src_tokens.device) + ) + cand_offsets = torch.arange(0, cand_size).type_as(tokens).to(src_tokens.device) + + reorder_state: Optional[Tensor] = None + batch_idxs: Optional[Tensor] = None + + original_batch_idxs: Optional[Tensor] = None + if "id" in sample and isinstance(sample["id"], Tensor): + original_batch_idxs = sample["id"] + else: + original_batch_idxs = torch.arange(0, bsz).type_as(tokens) + + for step in range(max_len + 1): # one extra step for EOS marker + # reorder decoder internal states based on the prev choice of beams + if reorder_state is not None: + if batch_idxs is not None: + # update beam indices to take into account removed sentences + corr = batch_idxs - torch.arange(batch_idxs.numel()).type_as( + batch_idxs + ) + reorder_state.view(-1, beam_size).add_( + corr.unsqueeze(-1) * beam_size + ) + original_batch_idxs = original_batch_idxs[batch_idxs] + self.model.reorder_incremental_state( + incremental_states, reorder_state, decoder_name + ) + encoder_outs = self.model.reorder_encoder_out( + encoder_outs, reorder_state + ) + if encoder_outs_aug is not None: + encoder_outs_aug = self.model.reorder_encoder_out( + encoder_outs_aug, reorder_state + ) + with torch.autograd.profiler.record_function( + "EnsembleModel: forward_decoder" + ): + lprobs, avg_attn_scores = self.model.forward_decoder( + tokens[:, : step + 1], + encoder_outs, + incremental_states, + self.temperature, + decoder_name=decoder_name, + encoder_outs_aug=encoder_outs_aug, + ) + + if self.lm_model is not None and not aux_task_name: + lm_out = self.lm_model(tokens[:, : step + 1]) + probs = self.lm_model.get_normalized_probs( + lm_out, log_probs=True, sample=None + ) + probs = probs[:, -1, :] * self.lm_weight + lprobs += probs + + lprobs[lprobs != lprobs] = torch.tensor(-math.inf).to(lprobs) + + lprobs[:, self.pad] = -math.inf # never select pad + lprobs[:, self.unk] -= self.unk_penalty # apply unk penalty + + # handle max length constraint + if step >= max_len: + lprobs[:, : self.eos] = -math.inf + lprobs[:, self.eos + 1 :] = -math.inf + + # handle prefix tokens (possibly with different lengths) + if ( + prefix_tokens is not None + and step < prefix_tokens.size(1) + and step < max_len + ): + lprobs, tokens, scores = self._prefix_tokens( + step, lprobs, scores, tokens, prefix_tokens, beam_size + ) + else: + if step < self.min_len: + # minimum length constraint (does not apply if using prefix_tokens) + lprobs[:, self.eos] = -math.inf + + if self.token_indices_to_suppress is not None: + lprobs[:, self.token_indices_to_suppress] = -math.inf + + # Record attention scores, only support avg_attn_scores is a Tensor + if avg_attn_scores is not None: + if attn is None: + attn = torch.empty( + bsz * beam_size, avg_attn_scores.size(1), max_len + 2 + ).to(scores) + attn[:, :, step + 1].copy_(avg_attn_scores) + + scores = scores.type_as(lprobs) + eos_bbsz_idx = torch.empty(0).to( + tokens + ) # indices of hypothesis ending with eos (finished sentences) + eos_scores = torch.empty(0).to( + scores + ) # scores of hypothesis ending with eos (finished sentences) + + if self.should_set_src_lengths: + self.search.set_src_lengths(src_lengths) + + if self.repeat_ngram_blocker is not None: + lprobs = self.repeat_ngram_blocker(tokens, lprobs, bsz, beam_size, step) + + # Shape: (batch, cand_size) + cand_scores, cand_indices, cand_beams = self.search.step( + step, + lprobs.view(bsz, -1, self.vocab_size), + scores.view(bsz, beam_size, -1)[:, :, :step], + tokens[:, : step + 1], + original_batch_idxs, + ) + + # cand_bbsz_idx contains beam indices for the top candidate + # hypotheses, with a range of values: [0, bsz*beam_size), + # and dimensions: [bsz, cand_size] + cand_bbsz_idx = cand_beams.add(bbsz_offsets) + + # finalize hypotheses that end in eos + # Shape of eos_mask: (batch size, beam size) + eos_mask = cand_indices.eq(self.eos) & cand_scores.ne(-math.inf) + eos_mask[:, :beam_size][cands_to_ignore] = torch.tensor(0).to(eos_mask) + + # only consider eos when it's among the top beam_size indices + # Now we know what beam item(s) to finish + # Shape: 1d list of absolute-numbered + eos_bbsz_idx = torch.masked_select( + cand_bbsz_idx[:, :beam_size], mask=eos_mask[:, :beam_size] + ) + + finalized_sents: List[int] = [] + if eos_bbsz_idx.numel() > 0: + eos_scores = torch.masked_select( + cand_scores[:, :beam_size], mask=eos_mask[:, :beam_size] + ) + + finalized_sents = self.finalize_hypos( + step, + eos_bbsz_idx, + eos_scores, + tokens, + scores, + finalized, + finished, + beam_size, + attn, + src_lengths, + max_len, + ) + num_remaining_sent -= len(finalized_sents) + + assert num_remaining_sent >= 0 + if num_remaining_sent == 0: + break + if self.search.stop_on_max_len and step >= max_len: + break + assert step < max_len, f"{step} < {max_len}" + + # Remove finalized sentences (ones for which {beam_size} + # finished hypotheses have been generated) from the batch. + if len(finalized_sents) > 0: + new_bsz = bsz - len(finalized_sents) + + # construct batch_idxs which holds indices of batches to keep for the next pass + batch_mask = torch.ones( + bsz, dtype=torch.bool, device=cand_indices.device + ) + batch_mask[finalized_sents] = False + # TODO replace `nonzero(as_tuple=False)` after TorchScript supports it + batch_idxs = torch.arange( + bsz, device=cand_indices.device + ).masked_select(batch_mask) + + # Choose the subset of the hypothesized constraints that will continue + self.search.prune_sentences(batch_idxs) + + eos_mask = eos_mask[batch_idxs] + cand_beams = cand_beams[batch_idxs] + bbsz_offsets.resize_(new_bsz, 1) + cand_bbsz_idx = cand_beams.add(bbsz_offsets) + cand_scores = cand_scores[batch_idxs] + cand_indices = cand_indices[batch_idxs] + + if prefix_tokens is not None: + prefix_tokens = prefix_tokens[batch_idxs] + src_lengths = src_lengths[batch_idxs] + cands_to_ignore = cands_to_ignore[batch_idxs] + + scores = scores.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, -1) + tokens = tokens.view(bsz, -1)[batch_idxs].view(new_bsz * beam_size, -1) + if attn is not None: + attn = attn.view(bsz, -1)[batch_idxs].view( + new_bsz * beam_size, attn.size(1), -1 + ) + bsz = new_bsz + else: + batch_idxs = None + + # Set active_mask so that values > cand_size indicate eos hypos + # and values < cand_size indicate candidate active hypos. + # After, the min values per row are the top candidate active hypos + + # Rewrite the operator since the element wise or is not supported in torchscript. + + eos_mask[:, :beam_size] = ~((~cands_to_ignore) & (~eos_mask[:, :beam_size])) + active_mask = torch.add( + eos_mask.type_as(cand_offsets) * cand_size, + cand_offsets[: eos_mask.size(1)], + ) + + # get the top beam_size active hypotheses, which are just + # the hypos with the smallest values in active_mask. + # {active_hypos} indicates which {beam_size} hypotheses + # from the list of {2 * beam_size} candidates were + # selected. Shapes: (batch size, beam size) + new_cands_to_ignore, active_hypos = torch.topk( + active_mask, k=beam_size, dim=1, largest=False + ) + + # update cands_to_ignore to ignore any finalized hypos. + cands_to_ignore = new_cands_to_ignore.ge(cand_size)[:, :beam_size] + # Make sure there is at least one active item for each sentence in the batch. + assert (~cands_to_ignore).any(dim=1).all() + + # update cands_to_ignore to ignore any finalized hypos + + # {active_bbsz_idx} denotes which beam number is continued for each new hypothesis (a beam + # can be selected more than once). + active_bbsz_idx = torch.gather(cand_bbsz_idx, dim=1, index=active_hypos) + active_scores = torch.gather(cand_scores, dim=1, index=active_hypos) + + active_bbsz_idx = active_bbsz_idx.view(-1) + active_scores = active_scores.view(-1) + + # copy tokens and scores for active hypotheses + + # Set the tokens for each beam (can select the same row more than once) + tokens[:, : step + 1] = torch.index_select( + tokens[:, : step + 1], dim=0, index=active_bbsz_idx + ) + # Select the next token for each of them + tokens.view(bsz, beam_size, -1)[:, :, step + 1] = torch.gather( + cand_indices, dim=1, index=active_hypos + ) + if step > 0: + scores[:, :step] = torch.index_select( + scores[:, :step], dim=0, index=active_bbsz_idx + ) + scores.view(bsz, beam_size, -1)[:, :, step] = torch.gather( + cand_scores, dim=1, index=active_hypos + ) + + # Update constraints based on which candidates were selected for the next beam + self.search.update_constraints(active_hypos) + + # copy attention for active hypotheses + if attn is not None: + attn[:, :, : step + 2] = torch.index_select( + attn[:, :, : step + 2], dim=0, index=active_bbsz_idx + ) + + # reorder incremental state in decoder + reorder_state = active_bbsz_idx + + # sort by score descending + for sent in range(len(finalized)): + scores = torch.tensor( + [float(elem["score"].item()) for elem in finalized[sent]] + ) + _, sorted_scores_indices = torch.sort(scores, descending=True) + finalized[sent] = [finalized[sent][ssi] for ssi in sorted_scores_indices] + finalized[sent] = torch.jit.annotate( + List[Dict[str, Tensor]], finalized[sent] + ) + return finalized + + +class EnsembleModel(EnsembleModelBase): + """A wrapper around an ensemble of models.""" + + def __init__(self, models): + super().__init__(models) + + @torch.jit.export + def forward_decoder( + self, + tokens, + encoder_outs: List[Dict[str, List[Tensor]]], + incremental_states: List[Dict[str, Dict[str, Optional[Tensor]]]], + temperature: float = 1.0, + decoder_name="decoder", + encoder_outs_aug: List[Dict[str, List[Tensor]]] = None, + ): + log_probs = [] + avg_attn: Optional[Tensor] = None + encoder_out: Optional[Dict[str, List[Tensor]]] = None + encoder_out_aug: Optional[Dict[str, List[Tensor]]] = None + for i, model in enumerate(self.models): + if self.has_encoder(): + encoder_out = encoder_outs[i] + if encoder_outs_aug is not None: + encoder_out_aug = encoder_outs_aug[i] + # decode each model + if self.has_incremental_states(): + if encoder_out_aug is not None: + decoder_out = getattr(model, decoder_name).forward( + tokens, + encoder_out=encoder_out, + encoder_out_aug=encoder_out_aug, + incremental_state=incremental_states[i], + ) + else: + decoder_out = getattr(model, decoder_name).forward( + tokens, + encoder_out=encoder_out, + incremental_state=incremental_states[i], + ) + else: + if hasattr(model, decoder_name): + decoder_out = getattr(model, decoder_name).forward( + tokens, encoder_out=encoder_out + ) + else: + decoder_out = model.forward(tokens) + + attn: Optional[Tensor] = None + decoder_len = len(decoder_out) + if decoder_len > 1 and decoder_out[1] is not None: + if isinstance(decoder_out[1], Tensor): + attn = decoder_out[1] + else: + attn_holder = decoder_out[1]["attn"] + if isinstance(attn_holder, Tensor): + attn = attn_holder + elif attn_holder is not None: + attn = attn_holder[0] + if attn is not None: + attn = attn[:, -1, :] + + decoder_out_tuple = ( + decoder_out[0][:, -1:, :].div_(temperature), + None if decoder_len <= 1 else decoder_out[1], + ) + probs = getattr(model, decoder_name).get_normalized_probs( + decoder_out_tuple, log_probs=True, sample=None + ) + probs = probs[:, -1, :] + if self.models_size == 1: + return probs, attn + + log_probs.append(probs) + if attn is not None: + if avg_attn is None: + avg_attn = attn + else: + avg_attn.add_(attn) + + avg_probs = torch.logsumexp(torch.stack(log_probs, dim=0), dim=0) - math.log( + self.models_size + ) + + if avg_attn is not None: + avg_attn.div_(self.models_size) + return avg_probs, avg_attn + + @torch.jit.export + def reorder_incremental_state( + self, + incremental_states: List[Dict[str, Dict[str, Optional[Tensor]]]], + new_order, + decoder_name="decoder", + ): + if not self.has_incremental_states(): + return + for i, model in enumerate(self.models): + getattr(model, decoder_name).reorder_incremental_state_scripting( + incremental_states[i], new_order + ) diff --git a/examples/speech_to_speech/unity/sequence_generator_multi_decoder.py b/examples/speech_to_speech/unity/sequence_generator_multi_decoder.py new file mode 100644 index 0000000000..49d127b34d --- /dev/null +++ b/examples/speech_to_speech/unity/sequence_generator_multi_decoder.py @@ -0,0 +1,260 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Optional + +import torch +import torch.nn as nn +from torch import Tensor + +from fairseq import search + + +class MultiDecoderSequenceGenerator(nn.Module): + def __init__( + self, + models, + tgt_dict, + tgt_dict_mt, + beam_size=1, + beam_size_mt=1, + max_len_a=0, + max_len_b=200, + max_len_a_mt=0, + max_len_b_mt=200, + max_len=0, + min_len=1, + normalize_scores=True, + len_penalty=1.0, + len_penalty_mt=1.0, + unk_penalty=0.0, + temperature=1.0, + match_source_len=False, + no_repeat_ngram_size=0, + eos=None, + eos_mt=None, + symbols_to_strip_from_output=None, + lm_model=None, + lm_weight=1.0, + ): + """Generates translations of a given source sentence. + + Args: + models (List[~fairseq.models.FairseqModel]): ensemble of models, + currently support fairseq.models.TransformerModel for scripting + beam_size (int, optional): beam width (default: 1) + max_len_a/b (int, optional): generate sequences of maximum length + ax + b, where x is the source length for the second pass + max_len_a_mt/b_mt (int, optional): generate sequences of maximum length + ax + b, where x is the source length for the first pass + max_len (int, optional): the maximum length of the generated output + (not including end-of-sentence) + min_len (int, optional): the minimum length of the generated output + (not including end-of-sentence) + normalize_scores (bool, optional): normalize scores by the length + of the output (default: True) + len_penalty (float, optional): length penalty in the second pass, where <1.0 favors + shorter, >1.0 favors longer sentences (default: 1.0) + len_penalty (float, optional): length penalty in the first pass, where <1.0 favors + shorter, >1.0 favors longer sentences (default: 1.0) + unk_penalty (float, optional): unknown word penalty, where <0 + produces more unks, >0 produces fewer (default: 0.0) + temperature (float, optional): temperature, where values + >1.0 produce more uniform samples and values <1.0 produce + sharper samples (default: 1.0) + match_source_len (bool, optional): outputs should match the source + length (default: False) + """ + super().__init__() + + from examples.speech_to_speech.unity.sequence_generator import SequenceGenerator + + self.generator = SequenceGenerator( + models, + tgt_dict, + beam_size=beam_size, + max_len_a=max_len_a, + max_len_b=max_len_b, + max_len=max_len, + min_len=min_len, + normalize_scores=normalize_scores, + len_penalty=len_penalty, + unk_penalty=unk_penalty, + temperature=temperature, + match_source_len=match_source_len, + no_repeat_ngram_size=no_repeat_ngram_size, + search_strategy=search.BeamSearch(tgt_dict), + eos=eos, + symbols_to_strip_from_output=symbols_to_strip_from_output, + lm_model=lm_model, + lm_weight=lm_weight, + ) + self.eos = self.generator.eos + + self.generator_mt = SequenceGenerator( + models, + tgt_dict_mt, + beam_size=beam_size_mt, + max_len_a=max_len_a_mt, + max_len_b=max_len_b_mt, + max_len=max_len, + min_len=min_len, + normalize_scores=normalize_scores, + len_penalty=len_penalty_mt, + unk_penalty=unk_penalty, + temperature=temperature, + match_source_len=match_source_len, + no_repeat_ngram_size=no_repeat_ngram_size, + search_strategy=search.BeamSearch(tgt_dict_mt), + eos=eos_mt, + symbols_to_strip_from_output=symbols_to_strip_from_output, + ) + + @torch.no_grad() + def generate( + self, models, sample: Dict[str, Dict[str, Tensor]], **kwargs + ) -> List[List[Dict[str, Tensor]]]: + """Generate translations. Match the api of other fairseq generators. + + Args: + models (List[~fairseq.models.FairseqModel]): ensemble of models + sample (dict): batch + prefix_tokens (torch.LongTensor, optional): force decoder to begin + with these tokens + constraints (torch.LongTensor, optional): force decoder to include + the list of constraints + bos_token (int, optional): beginning of sentence token + (default: self.eos) + """ + return self._generate(sample, **kwargs) + + def _generate( + self, + sample: Dict[str, Dict[str, Tensor]], + prefix_tokens: Optional[Tensor] = None, + constraints: Optional[Tensor] = None, + bos_token: Optional[int] = None, + ): + net_input = sample["net_input"] + + if "src_tokens" in net_input: + src_tokens = net_input["src_tokens"] + # length of the source text being the character length except EndOfSentence and pad + src_lengths = ( + (src_tokens.ne(self.generator.eos) & src_tokens.ne(self.generator.pad)) + .long() + .sum(dim=1) + ) + else: + raise Exception( + "expected src_tokens or source in net input. input keys: " + + str(net_input.keys()) + ) + + if constraints is not None and not self.generator.search.supports_constraints: + raise NotImplementedError( + "Target-side constraints were provided, but search method doesn't support them" + ) + + # Initialize constraints, when active + self.generator.search.init_constraints(constraints, self.generator.beam_size) + self.generator_mt.search.init_constraints( + constraints, self.generator_mt.beam_size + ) + + # compute the encoder output for each beam + with torch.autograd.profiler.record_function("EnsembleModel: forward_encoder"): + encoder_outs = self.generator.model.forward_encoder(net_input) + + single_model = self.generator.model.single_model + mt_decoder = getattr(single_model, f"{single_model.mt_task_name}_decoder") + + # 1. MT decoder + finalized_mt = self.generator_mt.generate_decoder( + encoder_outs, + src_tokens, + src_lengths, + sample, + prefix_tokens, + constraints, + bos_token, + aux_task_name=single_model.mt_task_name, + ) + + # extract decoder output corresponding to the best hypothesis + max_tgt_len = max([len(hypo[0]["tokens"]) for hypo in finalized_mt]) + prev_output_tokens_mt = ( + src_tokens.new_zeros(src_tokens.shape[0], max_tgt_len) + .fill_(mt_decoder.padding_idx) + .int() + ) # B x T + for i, hypo in enumerate(finalized_mt): + i_beam = 0 + tmp = hypo[i_beam]["tokens"].int() # hyp + eos + prev_output_tokens_mt[i, 0] = self.generator_mt.eos + if tmp[-1] == self.generator_mt.eos: + tmp = tmp[:-1] + prev_output_tokens_mt[i, 1 : len(tmp) + 1] = tmp + + text = "".join([self.generator_mt.tgt_dict[c] for c in tmp]) + text = text.replace("_", " ") + text = text.replace("▁", " ") + text = text.replace("<unk>", " ") + text = text.replace("<s>", "") + text = text.replace("</s>", "") + if len(text) > 0 and text[0] == " ": + text = text[1:] + sample_id = sample["id"].tolist()[i] + print("{} (None-{})".format(text, sample_id)) + + x = mt_decoder( + prev_output_tokens_mt, + encoder_out=encoder_outs[0], + features_only=True, + )[0].transpose(0, 1) + + if getattr(single_model, "proj", None) is not None: + x = single_model.proj(x) + + mt_decoder_padding_mask = None + if prev_output_tokens_mt.eq(mt_decoder.padding_idx).any(): + mt_decoder_padding_mask = prev_output_tokens_mt.eq(mt_decoder.padding_idx) + + # 2. T2U encoder + if getattr(single_model, "synthesizer_encoder", None) is not None: + t2u_encoder_out = single_model.synthesizer_encoder( + x, + mt_decoder_padding_mask, + ) + else: + t2u_encoder_out = { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [mt_decoder_padding_mask] + if mt_decoder_padding_mask is not None + else [], # B x T + "encoder_embedding": [], + "encoder_states": [], + "src_tokens": [], + "src_lengths": [], + } + + if getattr(single_model, "t2u_augmented_cross_attn", False): + encoder_outs_aug = [t2u_encoder_out] + else: + encoder_outs = [t2u_encoder_out] + encoder_outs_aug = None + + # 3. T2U decoder + finalized = self.generator.generate_decoder( + encoder_outs, + src_tokens, + src_lengths, + sample, + prefix_tokens, + constraints, + bos_token, + encoder_outs_aug=encoder_outs_aug, + ) + return finalized diff --git a/fairseq/criterions/speech_to_speech_criterion.py b/fairseq/criterions/speech_to_speech_criterion.py index 0cc2c4870c..6c663c7713 100644 --- a/fairseq/criterions/speech_to_speech_criterion.py +++ b/fairseq/criterions/speech_to_speech_criterion.py @@ -111,8 +111,12 @@ def get_multitask_loss(self, model, sample, model_out): for key in ["target", "target_lengths", "ntokens"]: task_sample[key] = sample["multitask"][task_name][key] + if task_name == getattr(model, "mt_task_name", None): + decoder_out = model_out["mt_decoder_out"] + else: + decoder_out = None task_loss, task_sample_size, task_logging_output = task_criterion( - model.multitask_decoders[task_name], task_sample + model.multitask_decoders[task_name], task_sample, net_output=decoder_out ) loss = loss + self.multitask_loss_weight[task_name] * task_loss @@ -251,6 +255,80 @@ def logging_outputs_can_be_summed() -> bool: return False +@register_criterion( + "speech_to_unit_2pass", dataclass=RdropLabelSmoothedCrossEntropyCriterionConfig +) +class SpeechToUnit2passMultitaskTaskCriterion(SpeechToUnitMultitaskTaskCriterion): + def __init__( + self, + task, + sentence_avg, + label_smoothing, + ignore_prefix_size=0, + report_accuracy=False, + rdrop_alpha=0.0, + ): + super().__init__( + task, + sentence_avg, + label_smoothing, + ignore_prefix_size, + report_accuracy, + rdrop_alpha, + ) + + def forward(self, model, sample, reduce=True): + net_input_concat = { + "src_tokens": sample["net_input"]["src_tokens"], + "src_lengths": sample["net_input"]["src_lengths"], + "prev_output_tokens": sample["net_input"]["prev_output_tokens"], + "prev_output_tokens_mt": sample["multitask"][model.mt_task_name][ + "net_input" + ]["prev_output_tokens"], + "tgt_speaker": sample["net_input"].get("tgt_speaker", None), + "return_all_hiddens": True, + } + if getattr(model, "asr_task_name", None) is not None: + net_input_concat["prev_output_tokens_asr"] = sample["multitask"][ + model.asr_task_name + ]["net_input"]["prev_output_tokens"] + + if self.rdrop_alpha > 0 or self.rdrop_alpha_mtl > 0: + net_input_concat = duplicate_input(net_input_concat) + + net_output, extra = model(**net_input_concat) + loss, nll_loss, rdrop_kl_loss = self.compute_loss( + model, [net_output], sample, reduce=reduce + ) + + sample_size = ( + sample["target"].size(0) if self.sentence_avg else sample["ntokens"] + ) + logging_output = { + "loss": loss.data, + "nll_loss": nll_loss.data, + "ntokens": sample["ntokens"], + "nsentences": sample["target"].size(0), + "sample_size": sample_size, + } + if self.report_accuracy: + n_correct, total = self.compute_accuracy(model, [net_output], sample) + logging_output["n_correct"] = utils.item(n_correct.data) + logging_output["total"] = utils.item(total.data) + if self.rdrop_alpha > 0: + logging_output["rdrop_kl_loss"] = utils.item(rdrop_kl_loss.data) + + if len(self.multitask_criterion) == 0: + return loss, sample_size, logging_output + + # multitask + multitask_loss, multitask_log = self.get_multitask_loss(model, sample, extra) + loss += multitask_loss + logging_output["multitask"] = multitask_log + + return loss, sample_size, logging_output + + @register_criterion("speech_to_spectrogram", dataclass=Tacotron2CriterionConfig) class SpeechToSpectrogramMultitaskTaskCriterion(Tacotron2Criterion, MultitaskCriterion): def __init__( @@ -351,3 +429,88 @@ def reduce_metrics(cls, logging_outputs) -> None: return MultitaskCriterion.reduce_metrics(logging_outputs) + + +@register_criterion("speech_to_spectrogram_2pass", dataclass=Tacotron2CriterionConfig) +class SpeechToSpectrogram2passMultitaskTaskCriterion( + SpeechToSpectrogramMultitaskTaskCriterion +): + def __init__( + self, + task, + sentence_avg, + use_guided_attention_loss, + guided_attention_loss_sigma, + bce_pos_weight, + ctc_weight, + ): + super().__init__( + task, + sentence_avg, + use_guided_attention_loss, + guided_attention_loss_sigma, + bce_pos_weight, + ctc_weight, + ) + + def forward(self, model, sample, reduction="mean"): + bsz, max_len, _ = sample["target"].size() + feat_tgt = sample["target"] + feat_len = sample["target_lengths"].view(bsz, 1).expand(-1, max_len) + eos_tgt = torch.arange(max_len).to(sample["target"].device) + eos_tgt = eos_tgt.view(1, max_len).expand(bsz, -1) + eos_tgt = (eos_tgt == (feat_len - 1)).float() + + feat_out, eos_out, extra = model( + src_tokens=sample["net_input"]["src_tokens"], + src_lengths=sample["net_input"]["src_lengths"], + prev_output_tokens=sample["net_input"]["prev_output_tokens"], + prev_output_tokens_mt=sample["multitask"][model.mt_task_name]["net_input"][ + "prev_output_tokens" + ], + tgt_speaker=sample["net_input"]["tgt_speaker"], + target_lengths=sample["target_lengths"], + return_all_hiddens=True, + ) + + l1_loss, mse_loss, eos_loss = self.compute_loss( + extra["feature_out"], + feat_out, + eos_out, + feat_tgt, + eos_tgt, + sample["target_lengths"], + reduction, + ) + attn_loss = torch.tensor(0.0).type_as(l1_loss) + if self.guided_attn is not None: + attn_loss = self.guided_attn( + extra["attn"], + sample["net_input"]["src_lengths"], + sample["target_lengths"], + reduction, + ) + loss = ( + l1_loss + mse_loss + eos_loss + attn_loss + ) # do not include ctc loss as there's no text target + + sample_size = sample["nsentences"] if self.sentence_avg else sample["ntokens"] + logging_output = { + "loss": utils.item(loss.data), + "ntokens": sample["ntokens"], + "nsentences": sample["nsentences"], + "sample_size": sample_size, + "l1_loss": utils.item(l1_loss.data), + "mse_loss": utils.item(mse_loss.data), + "eos_loss": utils.item(eos_loss.data), + "attn_loss": utils.item(attn_loss.data), + } + + if len(self.multitask_criterion) == 0: + return loss, sample_size, logging_output + + # multitask + multitask_loss, multitask_log = self.get_multitask_loss(model, sample, extra) + loss += multitask_loss + logging_output["multitask"] = multitask_log + return loss, sample_size, logging_output diff --git a/fairseq/data/audio/data_cfg.py b/fairseq/data/audio/data_cfg.py index 4475dbfc81..6be6f6521c 100644 --- a/fairseq/data/audio/data_cfg.py +++ b/fairseq/data/audio/data_cfg.py @@ -257,6 +257,24 @@ def get_single_task(self, name): assert name in self.config, f"multitask '{name}' does not exist!" return self.config[name] + @property + def first_pass_decoder_task_index(self): + """Return the task index of the first-pass text decoder. + If there are multiple 'is_first_pass_decoder: True' in the config file, + the last task is used for the first-pass decoder. + If there is no 'is_first_pass_decoder: True' in the config file, + the last task whose task_name includes 'target' and decoder_type is not ctc. + """ + idx = -1 + for i, (k, v) in enumerate(self.config.items()): + if v.is_first_pass_decoder: + idx = i + if idx < 0: + for i, (k, v) in enumerate(self.config.items()): + if k.startswith("target") and v.decoder_type == "transformer": + idx = i + return idx + class SingleTaskConfig(object): def __init__(self, name, config): @@ -336,6 +354,34 @@ def get_loss_weight(self, num_updates): ) return weight + @property + def prepend_bos_and_append_tgt_lang_tag(self) -> bool: + """Prepend BOS and append target lang ID token to the target (e.g. mBART with language token pretraining).""" + return self.config.get("prepend_bos_and_append_tgt_lang_tag", False) + + @property + def eos_token(self): + """EOS token during generation""" + return self.config.get("eos_token", "<eos>") + @property def rdrop_alpha(self): - return self.config.get("rdrop_alpha", None) + return self.config.get("rdrop_alpha", 0.0) + + @property + def is_first_pass_decoder(self): + flag = self.config.get("is_first_pass_decoder", False) + if flag: + if self.decoder_type == "ctc": + raise ValueError( + "First-pass decoder in the multi-decoder model must not be CTC." + ) + if "target" not in self.task_name: + raise Warning( + 'The name of the first-pass decoder does not include "target".' + ) + return flag + + @property + def get_lang_tag_mapping(self): + return self.config.get("lang_tag_mapping", {}) diff --git a/fairseq/data/audio/speech_to_speech_dataset.py b/fairseq/data/audio/speech_to_speech_dataset.py index 0d4151f587..fe4b61f831 100644 --- a/fairseq/data/audio/speech_to_speech_dataset.py +++ b/fairseq/data/audio/speech_to_speech_dataset.py @@ -247,8 +247,9 @@ def __getitem__( multitask_target = {} sample_id = self.ids[index] + tgt_lang = self.tgt_langs[index] for task_name, task_dataset in self.multitask_data.items(): - multitask_target[task_name] = task_dataset.get(sample_id) + multitask_target[task_name] = task_dataset.get(sample_id, tgt_lang) return s2s_data, multitask_target @@ -318,7 +319,7 @@ def _from_list( src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] - has_multitask = len(multitask) > 0 + has_multitask = multitask is not None and len(multitask.keys()) > 0 dataset_cls = ( SpeechToSpeechMultitaskDataset if has_multitask else SpeechToSpeechDataset ) diff --git a/fairseq/data/audio/speech_to_text_dataset.py b/fairseq/data/audio/speech_to_text_dataset.py index 500f4991db..cdf71558fd 100644 --- a/fairseq/data/audio/speech_to_text_dataset.py +++ b/fairseq/data/audio/speech_to_text_dataset.py @@ -391,6 +391,7 @@ def prefetch(self, indices): class TextTargetMultitaskData(object): # mandatory columns KEY_ID, KEY_TEXT = "id", "tgt_text" + LANG_TAG_TEMPLATE = "<lang:{}>" def __init__(self, args, split, tgt_dict): samples = SpeechToTextDatasetCreator._load_samples_from_tsv(args.data, split) @@ -399,6 +400,16 @@ def __init__(self, args, split, tgt_dict): self.append_eos = args.decoder_type != "ctc" self.pre_tokenizer = self.build_tokenizer(args) self.bpe_tokenizer = self.build_bpe(args) + self.prepend_bos_and_append_tgt_lang_tag = ( + args.prepend_bos_and_append_tgt_lang_tag + ) + self.eos_token = args.eos_token + self.lang_tag_mapping = args.get_lang_tag_mapping + + @classmethod + def is_lang_tag(cls, token): + pattern = cls.LANG_TAG_TEMPLATE.replace("{}", "(.*)") + return re.match(pattern, token) @classmethod def tokenize(cls, tokenizer, text: str): @@ -409,6 +420,13 @@ def get_tokenized_tgt_text(self, index: int): text = self.tokenize(self.bpe_tokenizer, text) return text + def get_lang_tag_idx(self, lang: str, dictionary: Dictionary): + lang_tag = self.LANG_TAG_TEMPLATE.format(lang) + lang_tag = self.lang_tag_mapping.get(lang_tag, lang_tag) + lang_tag_idx = dictionary.index(lang_tag) + assert lang_tag_idx != dictionary.unk(), (lang, lang_tag) + return lang_tag_idx + def build_tokenizer(self, args): pre_tokenizer = args.config.get("pre_tokenizer") if pre_tokenizer is not None: @@ -425,14 +443,21 @@ def build_bpe(self, args): else: return None - def get(self, sample_id): + def get(self, sample_id, tgt_lang=None): if sample_id in self.data: tokenized = self.get_tokenized_tgt_text(sample_id) - return self.dict.encode_line( + target = self.dict.encode_line( tokenized, add_if_not_exist=False, append_eos=self.append_eos, ) + if self.prepend_bos_and_append_tgt_lang_tag: + bos = torch.LongTensor([self.dict.bos()]) + lang_tag_idx = self.get_lang_tag_idx(tgt_lang, self.dict) + assert lang_tag_idx != self.dict.unk() + lang_tag_idx = torch.LongTensor([lang_tag_idx]) + target = torch.cat((bos, target, lang_tag_idx), 0) + return target else: logger.warning(f"no target for {sample_id}") return torch.IntTensor([]) @@ -441,7 +466,7 @@ def collater(self, samples: List[torch.Tensor]) -> torch.Tensor: out = fairseq_data_utils.collate_tokens( samples, self.dict.pad(), - eos_idx=self.dict.eos(), + eos_idx=None, left_pad=False, move_eos_to_beginning=False, ).long() @@ -449,7 +474,7 @@ def collater(self, samples: List[torch.Tensor]) -> torch.Tensor: prev_out = fairseq_data_utils.collate_tokens( samples, self.dict.pad(), - eos_idx=self.dict.eos(), + eos_idx=None, left_pad=False, move_eos_to_beginning=True, ).long() @@ -551,7 +576,7 @@ def _from_list( src_langs = [s.get(cls.KEY_SRC_LANG, cls.DEFAULT_LANG) for s in samples] tgt_langs = [s.get(cls.KEY_TGT_LANG, cls.DEFAULT_LANG) for s in samples] - has_multitask = len(multitask) > 0 + has_multitask = multitask is not None and len(multitask.keys()) > 0 dataset_cls = ( SpeechToTextMultitaskDataset if has_multitask else SpeechToTextDataset ) diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 3079101db3..5fdfab38d3 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -811,6 +811,10 @@ class GenerationConfig(FairseqDataclass): default=5, metadata={"help": "beam size"}, ) + beam_mt: int = field( + default=0, + metadata={"help": "beam size for the first-pass decoder"}, + ) nbest: int = field( default=1, metadata={"help": "number of hypotheses to output"}, @@ -827,6 +831,18 @@ class GenerationConfig(FairseqDataclass): "help": "generate sequences of maximum length ax + b, where x is the source length" }, ) + max_len_a_mt: float = field( + default=0, + metadata={ + "help": "generate sequences of maximum length ax + b, where x is the source length for the first-pass decoder" + }, + ) + max_len_b_mt: int = field( + default=200, + metadata={ + "help": "generate sequences of maximum length ax + b, where x is the source length for the first-pass decoder" + }, + ) min_len: int = field( default=1, metadata={"help": "minimum generation length"}, @@ -853,6 +869,12 @@ class GenerationConfig(FairseqDataclass): "help": "length penalty: <1.0 favors shorter, >1.0 favors longer sentences" }, ) + lenpen_mt: float = field( + default=1, + metadata={ + "help": "length penalty for the first-pass decoder: <1.0 favors shorter, >1.0 favors longer sentences" + }, + ) unkpen: float = field( default=0, metadata={ diff --git a/fairseq/models/speech_to_speech/__init__.py b/fairseq/models/speech_to_speech/__init__.py index 3d9e4728df..f29215c2fe 100644 --- a/fairseq/models/speech_to_speech/__init__.py +++ b/fairseq/models/speech_to_speech/__init__.py @@ -4,4 +4,6 @@ # LICENSE file in the root directory of this source tree. from .s2s_conformer import * # noqa +from .s2s_conformer_translatotron2 import * # noqa +from .s2s_conformer_unity import * # noqa from .s2s_transformer import * # noqa diff --git a/fairseq/models/speech_to_speech/modules/transformer_decoder_aug.py b/fairseq/models/speech_to_speech/modules/transformer_decoder_aug.py new file mode 100644 index 0000000000..68f42c2b36 --- /dev/null +++ b/fairseq/models/speech_to_speech/modules/transformer_decoder_aug.py @@ -0,0 +1,108 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, Dict, List, Optional + +from torch import Tensor + +from fairseq.models.transformer import Linear +from fairseq.models.transformer.transformer_decoder_aug import AugTransformerDecoder + + +class AugTransformerUnitDecoder(AugTransformerDecoder): + """Based on Transformer decoder, with support to decoding stacked units""" + + def __init__( + self, + args, + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=None, + ): + super().__init__( + args, dictionary, embed_tokens, no_encoder_attn, output_projection + ) + self.n_frames_per_step = args.n_frames_per_step + + self.out_proj_n_frames = ( + Linear( + self.output_embed_dim, + self.output_embed_dim * self.n_frames_per_step, + bias=False, + ) + if self.n_frames_per_step > 1 + else None + ) + + def forward( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + encoder_out_aug: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + features_only: bool = False, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + src_lengths: Optional[Any] = None, + return_all_hiddens: bool = False, + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + encoder_out (optional): output from the encoder, used for + encoder-side attention, should be of size T x B x C + incremental_state (dict): dictionary used for storing state during + :ref:`Incremental decoding` + features_only (bool, optional): only return features without + applying output layer (default: False). + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + + x, extra = self.extract_features( + prev_output_tokens, + encoder_out=encoder_out, + encoder_out_aug=encoder_out_aug, + incremental_state=incremental_state, + full_context_alignment=full_context_alignment, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + ) + + if not features_only: + bsz, seq_len, d = x.size() + if self.out_proj_n_frames: + x = self.out_proj_n_frames(x) + x = self.output_layer(x.view(bsz, seq_len, self.n_frames_per_step, d)) + x = x.view(bsz, seq_len * self.n_frames_per_step, -1) + if ( + incremental_state is None and self.n_frames_per_step > 1 + ): # teacher-forcing mode in training + x = x[ + :, : -(self.n_frames_per_step - 1), : + ] # remove extra frames after <eos> + + return x, extra + + def upgrade_state_dict_named(self, state_dict, name): + if self.n_frames_per_step > 1: + move_keys = [ + ( + f"{name}.project_in_dim.weight", + f"{name}.embed_tokens.project_in_dim.weight", + ) + ] + for from_k, to_k in move_keys: + if from_k in state_dict and to_k not in state_dict: + state_dict[to_k] = state_dict[from_k] + del state_dict[from_k] diff --git a/fairseq/models/speech_to_speech/modules/transformer_encoder.py b/fairseq/models/speech_to_speech/modules/transformer_encoder.py new file mode 100644 index 0000000000..fb1af433d8 --- /dev/null +++ b/fairseq/models/speech_to_speech/modules/transformer_encoder.py @@ -0,0 +1,85 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch.nn as nn + +from fairseq.models import FairseqEncoder +from fairseq.modules import LayerNorm, TransformerEncoderLayer + + +class TransformerEncoderNoEmb(FairseqEncoder): + """Transformer encoder without token embeddings.""" + + def __init__(self, args): + super().__init__(None) + + self.layers = nn.ModuleList( + [TransformerEncoderLayer(args) for _ in range(args.encoder_layers)] + ) + if args.encoder_normalize_before: + self.layer_norm = LayerNorm(args.encoder_embed_dim) + else: + self.layer_norm = None + + def forward(self, x, encoder_padding_mask, return_all_hiddens=False): + + encoder_states = [] + + for layer in self.layers: + x = layer(x, encoder_padding_mask) + if return_all_hiddens: + encoder_states.append(x) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + return { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [encoder_padding_mask] + if encoder_padding_mask is not None and encoder_padding_mask.any() + else [], # B x T + "encoder_embedding": [], # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], + "src_lengths": [], + } + + def reorder_encoder_out(self, encoder_out, new_order): + new_encoder_out = ( + [] + if len(encoder_out["encoder_out"]) == 0 + else [x.index_select(1, new_order) for x in encoder_out["encoder_out"]] + ) + + new_encoder_padding_mask = ( + [] + if len(encoder_out["encoder_padding_mask"]) == 0 + else [ + x.index_select(0, new_order) + for x in encoder_out["encoder_padding_mask"] + ] + ) + + new_encoder_embedding = ( + [] + if len(encoder_out["encoder_embedding"]) == 0 + else [ + x.index_select(0, new_order) for x in encoder_out["encoder_embedding"] + ] + ) + + encoder_states = encoder_out["encoder_states"] + if len(encoder_states) > 0: + for idx, state in enumerate(encoder_states): + encoder_states[idx] = state.index_select(1, new_order) + + return { + "encoder_out": new_encoder_out, # T x B x C + "encoder_padding_mask": new_encoder_padding_mask, # B x T + "encoder_embedding": new_encoder_embedding, # B x T x C + "encoder_states": encoder_states, # List[T x B x C] + "src_tokens": [], # B x T + "src_lengths": [], # B x 1 + } diff --git a/fairseq/models/speech_to_speech/s2s_conformer.py b/fairseq/models/speech_to_speech/s2s_conformer.py index 50fb2c4b75..636396d536 100644 --- a/fairseq/models/speech_to_speech/s2s_conformer.py +++ b/fairseq/models/speech_to_speech/s2s_conformer.py @@ -11,7 +11,9 @@ from fairseq import checkpoint_utils from fairseq.models import register_model, register_model_architecture from fairseq.models.speech_to_speech.s2s_transformer import ( + S2SpecTTransformerModel, S2UTTransformerModel, + s2spect_architecture_base, s2ut_architecture_base, ) from fairseq.models.speech_to_text import S2TConformerEncoder @@ -97,6 +99,34 @@ def build_encoder(cls, args): return build_s2s_conformer_encoder(args) +@register_model("s2spect_conformer") +class S2SpecTConformerModel(S2SpecTTransformerModel): + """ + Direct speech-to-speech translation model with Conformer encoder + TTS Transformer decoder + """ + + @staticmethod + def add_args(parser): + S2SpecTTransformerModel.add_args(parser) + parser.add_argument("--depthwise-conv-kernel-size", type=int, default=31) + parser.add_argument( + "--attn-type", + type=str, + default=None, + help="If not specified uses fairseq MHA. Other valid option is espnet for using conformer", + ) + parser.add_argument( + "--pos-enc-type", + type=str, + default="abs", + help="Must be specified in addition to attn-type=espnet for rel_pos and rope", + ) + + @classmethod + def build_encoder(cls, args): + return build_s2s_conformer_encoder(args) + + @register_model_architecture("s2ut_conformer", "s2ut_conformer") def s2ut_conformer_architecture_base(args): args.attn_type = getattr(args, "attn_type", None) @@ -111,3 +141,32 @@ def s2ut_conformer_architecture_base(args): args.encoder_layers = getattr(args, "encoder_layers", 16) args.depthwise_conv_kernel_size = getattr(args, "depthwise_conv_kernel_size", 31) s2ut_architecture_base(args) + + +@register_model_architecture("s2spect_conformer", "s2spect_conformer") +def s2spect_conformer_architecture_base(args): + args.attn_type = getattr(args, "attn_type", None) + args.pos_enc_type = getattr(args, "pos_enc_type", "abs") + args.input_feat_per_channel = getattr(args, "input_feat_per_channel", 80) + args.input_channels = getattr(args, "input_channels", 1) + args.max_source_positions = getattr(args, "max_source_positions", 6000) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + args.encoder_layers = getattr(args, "encoder_layers", 16) + args.depthwise_conv_kernel_size = getattr(args, "depthwise_conv_kernel_size", 31) + s2spect_architecture_base(args) + + +@register_model_architecture("s2spect_conformer", "s2spect_conformer_fisher") +def s2spect_architecture_fisher(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 256 * 8) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + + # decoder + args.prenet_dim = getattr(args, "prenet_dim", 32) + + s2spect_conformer_architecture_base(args) diff --git a/fairseq/models/speech_to_speech/s2s_conformer_translatotron2.py b/fairseq/models/speech_to_speech/s2s_conformer_translatotron2.py new file mode 100644 index 0000000000..8016daee8d --- /dev/null +++ b/fairseq/models/speech_to_speech/s2s_conformer_translatotron2.py @@ -0,0 +1,262 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import copy +import logging + +from fairseq.models import ( + FairseqEncoderModel, + FairseqLanguageModel, + register_model, + register_model_architecture, +) +from fairseq.models.speech_to_speech.modules.ctc_decoder import CTCDecoder +from fairseq.models.speech_to_speech.modules.transformer_encoder import ( + TransformerEncoderNoEmb, +) +from fairseq.models.speech_to_speech.s2s_conformer import S2SpecTConformerModel +from fairseq.models.speech_to_speech.s2s_conformer_unity import ( + multitask_text_transformer_decoder_arch, +) +from fairseq.models.speech_to_speech.s2s_transformer import ( + base_multitask_text_transformer_decoder_arch, + s2spect_architecture_base, +) +from fairseq.models.text_to_speech import TTSTransformerDecoder +from fairseq.models.transformer import TransformerDecoder, TransformerModelBase + +logger = logging.getLogger(__name__) + + +@register_model("s2spect2_conformer") +class S2SpecT2ConformerModel(S2SpecTConformerModel): + """ + Direct speech-to-speech translation model with Conformer encoder + MT Transformer decoder + TTS Transformer decoder + """ + + @staticmethod + def add_args(parser): + S2SpecTConformerModel.add_args(parser) + parser.add_argument( + "--translation-decoder-layers", + type=int, + default=4, + metavar="N", + help="num decoder layers in the first-pass translation module", + ) + parser.add_argument( + "--synthesizer", + default="transformer", + choices=["transformer"], + help="", + ) + parser.add_argument( + "--synthesizer-encoder-layers", + type=int, + default=0, + metavar="N", + help="num encoder layers in the second-pass synthesizer module", + ) + + @classmethod + def build_multitask_decoder( + cls, + args, + tgt_dict, + in_dim, + is_mt_decoder, + decoder_layers, + decoder_embed_dim, + decoder_attention_heads, + ): + decoder_args = args.decoder_args + decoder_args.encoder_embed_dim = in_dim + if args.decoder_type == "transformer": + if is_mt_decoder: + multitask_text_transformer_decoder_arch( + decoder_args, + decoder_layers, + decoder_embed_dim, + decoder_attention_heads, + ) # 4L + else: + base_multitask_text_transformer_decoder_arch(decoder_args) # 2L + task_decoder = TransformerDecoder( + decoder_args, + tgt_dict, + embed_tokens=TransformerModelBase.build_embedding( + decoder_args, + tgt_dict, + decoder_args.decoder_embed_dim, + ), + ) + elif args.decoder_type == "ctc": + task_decoder = CTCDecoder( + dictionary=tgt_dict, + in_dim=in_dim, + ) + else: + raise NotImplementedError( + "currently only support multitask decoder_type 'transformer', 'ctc'" + ) + + return task_decoder + + @classmethod + def build_decoder(cls, args): + _args = copy.deepcopy(args) + _args.encoder_embed_dim = args.decoder_embed_dim + + if args.synthesizer == "transformer": + return TTSTransformerDecoder(_args, None, padding_idx=1) + else: + raise NotImplementedError(args.synthesizer) + + @classmethod + def build_model(cls, args, task): + encoder = cls.build_encoder(args) + decoder = cls.build_decoder(args) + base_model = cls(encoder, decoder) + + # set up multitask decoders + base_model.mt_task_name = None + base_model.multitask_decoders = {} + has_first_pass_decoder = False + for task_name, task_obj in task.multitask_tasks.items(): + if task_obj.is_first_pass_decoder: + has_first_pass_decoder = True + base_model.mt_task_name = task_name + + in_dim = ( + args.encoder_embed_dim + if task_obj.args.input_from == "encoder" + else args.decoder_embed_dim + ) + task_decoder = cls.build_multitask_decoder( + task_obj.args, + task_obj.target_dictionary, + in_dim, + task_obj.is_first_pass_decoder, + getattr(args, "translation_decoder_layers", 4), + getattr(args, "decoder_embed_dim", 256), + getattr(args, "decoder_attention_heads", 4), + ) + + setattr(base_model, f"{task_name}_decoder", task_decoder) + decoder_model_cls = ( + FairseqEncoderModel + if task_obj.args.decoder_type == "ctc" + else FairseqLanguageModel + ) + base_model.multitask_decoders[task_name] = decoder_model_cls( + getattr(base_model, f"{task_name}_decoder") + ) + + assert has_first_pass_decoder, "set at least one intermediate non-CTC decoder" + + # set up encoder on top of the auxiliary MT decoder + if getattr(args, "synthesizer_encoder_layers", 0) > 0: + base_model.synthesizer_encoder = cls.build_text_encoder(args) + else: + base_model.synthesizer_encoder = None + + return base_model + + @classmethod + def build_text_encoder(cls, args): + _args = copy.deepcopy(args) + _args.encoder_layers = args.synthesizer_encoder_layers + _args.encoder_embed_dim = args.decoder_embed_dim + _args.encoder_ffn_embed_dim = args.decoder_ffn_embed_dim + _args.encoder_attention_heads = args.decoder_attention_heads + _args.encoder_normalize_before = True + return TransformerEncoderNoEmb(_args) + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + prev_output_tokens_mt, + tgt_speaker=None, + incremental_state=None, + target_lengths=None, + speaker=None, + return_all_hiddens=False, + ): + encoder_out = self.encoder( + src_tokens, + src_lengths=src_lengths, + tgt_speaker=tgt_speaker, + return_all_hiddens=return_all_hiddens, + ) + + # 1. MT decoder + mt_decoder = getattr(self, f"{self.mt_task_name}_decoder") + mt_decoder_out = mt_decoder( + prev_output_tokens_mt, + encoder_out=encoder_out, + ) + x = mt_decoder_out[1]["inner_states"][-1] + if mt_decoder.layer_norm is not None: + x = mt_decoder.layer_norm(x) + + mt_decoder_padding_mask = None + if prev_output_tokens_mt.eq(mt_decoder.padding_idx).any(): + mt_decoder_padding_mask = prev_output_tokens_mt.eq(mt_decoder.padding_idx) + + # 2. TTS encoder + if self.synthesizer_encoder is not None: + tts_encoder_out = self.synthesizer_encoder( + x, + mt_decoder_padding_mask, + return_all_hiddens=return_all_hiddens, + ) + else: + tts_encoder_out = { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [mt_decoder_padding_mask], # B x T + } + + # 3. TTS decoder + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=tts_encoder_out, + incremental_state=incremental_state, + target_lengths=target_lengths, + speaker=speaker, + ) + if return_all_hiddens: + decoder_out[-1]["encoder_states"] = encoder_out["encoder_states"] + decoder_out[-1]["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ] + decoder_out[-1]["mt_decoder_out"] = mt_decoder_out + return decoder_out + + +@register_model_architecture( + model_name="s2spect2_conformer", arch_name="s2spect2_conformer" +) +def s2spect2_conformer_architecture_base(args): + args.conv_version = getattr(args, "conv_version", "convtransformer") + args.attn_type = getattr(args, "attn_type", None) + args.pos_enc_type = getattr(args, "pos_enc_type", "abs") + args.max_source_positions = getattr(args, "max_source_positions", 6000) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + args.encoder_layers = getattr(args, "encoder_layers", 16) + args.depthwise_conv_kernel_size = getattr(args, "depthwise_conv_kernel_size", 31) + s2spect_architecture_base(args) + + +# for old naming +@register_model_architecture( + model_name="s2spect2_conformer", arch_name="s2spect_conformer_translatotron2" +) +def s2spect2_conformer_architecture_base_legacy(args): + s2spect2_conformer_architecture_base(args) diff --git a/fairseq/models/speech_to_speech/s2s_conformer_unity.py b/fairseq/models/speech_to_speech/s2s_conformer_unity.py new file mode 100644 index 0000000000..64388d6d16 --- /dev/null +++ b/fairseq/models/speech_to_speech/s2s_conformer_unity.py @@ -0,0 +1,298 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import copy +import logging + +from fairseq.models import ( + FairseqEncoder, + FairseqEncoderModel, + FairseqLanguageModel, + register_model, + register_model_architecture, +) +from fairseq.models.speech_to_speech.modules.ctc_decoder import CTCDecoder +from fairseq.models.speech_to_speech.modules.stacked_embedding import StackedEmbedding +from fairseq.models.speech_to_speech.modules.transformer_decoder_aug import ( + AugTransformerUnitDecoder, +) +from fairseq.models.speech_to_speech.modules.transformer_encoder import ( + TransformerEncoderNoEmb, +) +from fairseq.models.speech_to_speech.s2s_conformer import S2UTConformerModel +from fairseq.models.speech_to_speech.s2s_transformer import ( + TransformerUnitDecoder, + base_multitask_text_transformer_decoder_arch, + s2ut_architecture_base, +) +from fairseq.models.transformer import TransformerDecoder, TransformerModelBase + +logger = logging.getLogger(__name__) + + +def multitask_text_transformer_decoder_arch( + args, decoder_layers, decoder_embed_dim=256, decoder_attention_heads=4 +): + args.decoder_layers = decoder_layers + args.decoder_embed_dim = decoder_embed_dim + args.decoder_attention_heads = decoder_attention_heads + base_multitask_text_transformer_decoder_arch(args) + + +@register_model("unity_conformer") +class UnityConformerModel(S2UTConformerModel): + """ + Direct speech-to-speech translation model with Conformer encoder + MT Transformer decoder + Transformer discrete unit decoder + """ + + @staticmethod + def add_args(parser): + S2UTConformerModel.add_args(parser) + parser.add_argument( + "--translation-decoder-layers", + type=int, + default=4, + metavar="N", + help="num decoder layers in the first-pass translation module", + ) + parser.add_argument( + "--synthesizer", + default="transformer", + choices=["transformer"], + help="", + ) + parser.add_argument( + "--synthesizer-encoder-layers", + type=int, + default=0, + metavar="N", + help="num encoder layers in the second-pass synthesizer module", + ) + parser.add_argument( + "--synthesizer-augmented-cross-attention", + action="store_true", + default=False, + help="augmented cross-attention over speech encoder output", + ) + + @classmethod + def build_multitask_decoder( + cls, + args, + tgt_dict, + in_dim, + is_first_pass_decoder, + decoder_layers, + decoder_embed_dim, + decoder_attention_heads, + ): + decoder_args = args.decoder_args + decoder_args.encoder_embed_dim = in_dim + if args.decoder_type == "transformer": + if is_first_pass_decoder: + multitask_text_transformer_decoder_arch( + decoder_args, + decoder_layers, + decoder_embed_dim, + decoder_attention_heads, + ) # 4L + else: + base_multitask_text_transformer_decoder_arch(decoder_args) # 2L + task_decoder = TransformerDecoder( + decoder_args, + tgt_dict, + embed_tokens=TransformerModelBase.build_embedding( + decoder_args, + tgt_dict, + decoder_args.decoder_embed_dim, + ), + ) + elif args.decoder_type == "ctc": + task_decoder = CTCDecoder( + dictionary=tgt_dict, + in_dim=in_dim, + ) + else: + raise NotImplementedError( + "currently only support multitask decoder_type 'transformer', 'ctc'" + ) + + return task_decoder + + @classmethod + def build_decoder(cls, args, tgt_dict, aug_attn=False): + num_embeddings = len(tgt_dict) + padding_idx = tgt_dict.pad() + embed_tokens = StackedEmbedding( + num_embeddings, + args.decoder_embed_dim, + padding_idx, + num_stacked=args.n_frames_per_step, + ) + + _args = copy.deepcopy(args) + _args.encoder_embed_dim = args.decoder_embed_dim + + decoder_cls = AugTransformerUnitDecoder if aug_attn else TransformerUnitDecoder + return decoder_cls( + _args, + tgt_dict, + embed_tokens, + ) + + @classmethod + def build_model(cls, args, task): + encoder = cls.build_encoder(args) + decoder = cls.build_decoder( + args, + task.target_dictionary, + aug_attn=getattr(args, "synthesizer_augmented_cross_attention", False), + ) + base_model = cls(encoder, decoder) + + base_model.t2u_augmented_cross_attn = getattr( + args, "synthesizer_augmented_cross_attention", False + ) + + # set up multitask decoders + base_model.mt_task_name = None + base_model.multitask_decoders = {} + has_first_pass_decoder = False + for task_name, task_obj in task.multitask_tasks.items(): + if task_obj.is_first_pass_decoder: + has_first_pass_decoder = True + base_model.mt_task_name = task_name + + in_dim = ( + args.encoder_embed_dim + if task_obj.args.input_from == "encoder" + else args.decoder_embed_dim + ) + task_decoder = cls.build_multitask_decoder( + task_obj.args, + task_obj.target_dictionary, + in_dim, + task_obj.is_first_pass_decoder, + getattr(args, "translation_decoder_layers", 4), + getattr(args, "decoder_embed_dim", 256), + getattr(args, "decoder_attention_heads", 4), + ) + + setattr(base_model, f"{task_name}_decoder", task_decoder) + decoder_model_cls = ( + FairseqEncoderModel + if task_obj.args.decoder_type == "ctc" + else FairseqLanguageModel + ) + base_model.multitask_decoders[task_name] = decoder_model_cls( + getattr(base_model, f"{task_name}_decoder") + ) + + assert has_first_pass_decoder, "set at least one intermediate non-CTC decoder" + + # set up encoder on top of the auxiliary MT decoder + if getattr(args, "synthesizer_encoder_layers", 0) > 0: + base_model.synthesizer_encoder = cls.build_text_encoder(args) + else: + base_model.synthesizer_encoder = None + + return base_model + + @classmethod + def build_text_encoder(cls, args): + _args = copy.deepcopy(args) + _args.encoder_layers = args.synthesizer_encoder_layers + _args.encoder_embed_dim = args.decoder_embed_dim + _args.encoder_ffn_embed_dim = args.decoder_ffn_embed_dim + _args.encoder_attention_heads = args.decoder_attention_heads + _args.encoder_normalize_before = True + return TransformerEncoderNoEmb(_args) + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + prev_output_tokens_mt, + tgt_speaker=None, + return_all_hiddens=False, + ): + mt_decoder = getattr(self, f"{self.mt_task_name}_decoder") + + encoder_out = self.encoder( + src_tokens, + src_lengths=src_lengths, + tgt_speaker=tgt_speaker, + return_all_hiddens=return_all_hiddens, + ) + + # 1. MT decoder + mt_decoder_out = mt_decoder( + prev_output_tokens_mt, + encoder_out=encoder_out, + ) + x = mt_decoder_out[1]["inner_states"][-1] + if mt_decoder.layer_norm is not None: + x = mt_decoder.layer_norm(x) + + mt_decoder_padding_mask = None + if prev_output_tokens_mt.eq(mt_decoder.padding_idx).any(): + mt_decoder_padding_mask = prev_output_tokens_mt.eq(mt_decoder.padding_idx) + + # 2. T2U encoder + if self.synthesizer_encoder is not None: + t2u_encoder_out = self.synthesizer_encoder( + x, + mt_decoder_padding_mask, + return_all_hiddens=return_all_hiddens, + ) + else: + t2u_encoder_out = { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [mt_decoder_padding_mask], # B x T + } + + # 3. T2U decoder + if self.t2u_augmented_cross_attn: + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=encoder_out, + encoder_out_aug=t2u_encoder_out, + ) + else: + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=t2u_encoder_out, + ) + if return_all_hiddens: + decoder_out[-1]["encoder_states"] = encoder_out["encoder_states"] + decoder_out[-1]["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ] + decoder_out[-1]["mt_decoder_out"] = mt_decoder_out + return decoder_out + + +@register_model_architecture(model_name="unity_conformer", arch_name="unity_conformer") +def unity_conformer_architecture_base(args): + args.conv_version = getattr(args, "conv_version", "convtransformer") + args.attn_type = getattr(args, "attn_type", None) + args.pos_enc_type = getattr(args, "pos_enc_type", "abs") + args.max_source_positions = getattr(args, "max_source_positions", 6000) + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 256) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 2048) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.dropout = getattr(args, "dropout", 0.1) + args.encoder_layers = getattr(args, "encoder_layers", 16) + args.depthwise_conv_kernel_size = getattr(args, "depthwise_conv_kernel_size", 31) + s2ut_architecture_base(args) + + +# for old naming +@register_model_architecture( + model_name="unity_conformer", arch_name="s2ut_conformer_translatotron2" +) +def unity_conformer_architecture_base_legacy(args): + unity_conformer_architecture_base(args) diff --git a/fairseq/models/speech_to_text/__init__.py b/fairseq/models/speech_to_text/__init__.py index e3fadc8cdd..62ef663efb 100644 --- a/fairseq/models/speech_to_text/__init__.py +++ b/fairseq/models/speech_to_text/__init__.py @@ -10,3 +10,4 @@ from .s2t_transformer import * # noqa from .s2t_wav_transformer import * # noqa from .xm_transformer import * # noqa +from .xm_transformer_unity import * # noqa diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index f6aa590493..57edc1069d 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -623,6 +623,7 @@ def build_decoder(cls, args, task, embed_tokens): _args.dropout = args.decoder_dropout _args.attention_dropout = args.decoder_attention_dropout _args.activation_dropout = args.decoder_activation_dropout + _args.layerdrop = _args.decoder_layerdrop decoder = TransformerDecoder(_args, task.target_dictionary, embed_tokens) decoder = cls.maybe_load_pretrained( diff --git a/fairseq/models/speech_to_text/xm_transformer_unity.py b/fairseq/models/speech_to_text/xm_transformer_unity.py new file mode 100644 index 0000000000..450bf01efe --- /dev/null +++ b/fairseq/models/speech_to_text/xm_transformer_unity.py @@ -0,0 +1,351 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import copy +import logging + +from fairseq.models import ( + FairseqEncoderModel, + FairseqLanguageModel, + register_model, + register_model_architecture, +) +from fairseq.models.speech_to_speech.modules.ctc_decoder import CTCDecoder +from fairseq.models.speech_to_speech.modules.transformer_encoder import ( + TransformerEncoderNoEmb, +) +from fairseq.models.speech_to_text.xm_transformer import XMTransformerModel +from fairseq.models.speech_to_text.xm_transformer import ( + base_architecture as xm_t_base_architecture, +) +from fairseq.models.speech_to_text.xm_transformer import ( + build_embedding, + need_finetuning, + set_default_adaptor_args, + set_default_general_args, + set_default_transformer_decoder_args, + set_default_w2v_encoder_args, +) +from fairseq.models.transformer import Linear, TransformerDecoder, TransformerModelBase +from fairseq.models.transformer.transformer_decoder_aug import AugTransformerDecoder + +logger = logging.getLogger(__name__) + + +def unit_transformer_decoder_arch_base( + args, decoder_layers=6, decoder_embed_dim=768, decoder_attention_heads=12 +): + args.encoder_layers = decoder_layers + args.decoder_layers = decoder_layers + args.decoder_embed_dim = decoder_embed_dim + args.decoder_ffn_embed_dim = decoder_embed_dim * 4 + args.decoder_attention_heads = decoder_attention_heads + args.encoder_embed_dim = args.decoder_embed_dim + args.decoder_output_dim = decoder_embed_dim + args.decoder_input_dim = decoder_embed_dim + + +def unit_transformer_decoder_arch_large( + args, decoder_layers=12, decoder_embed_dim=1024, decoder_attention_heads=16 +): + args.encoder_layers = decoder_layers + args.decoder_layers = decoder_layers + args.decoder_embed_dim = decoder_embed_dim + args.decoder_ffn_embed_dim = decoder_embed_dim * 4 + args.decoder_attention_heads = decoder_attention_heads + args.encoder_embed_dim = args.decoder_embed_dim + args.decoder_output_dim = decoder_embed_dim + args.decoder_input_dim = decoder_embed_dim + + +@register_model("unity_xm_transformer") +class XMTransformerModelUnitY(XMTransformerModel): + @classmethod + def hub_models(cls): + base_url = "http://dl.fbaipublicfiles.com/fairseq/s2t" + model_ids = [] + return {i: f"{base_url}/{i}.tar.gz" for i in model_ids} + + def __init__(self, encoder, decoder): + super().__init__(encoder, decoder) + + @classmethod + def add_args(cls, parser): + """Add model-specific arguments to the parser.""" + XMTransformerModel.add_args(parser) + parser.add_argument( + "--translation-decoder-layers", + type=int, + default=4, + metavar="N", + help="num decoder layers in the first-pass translation module", + ) + parser.add_argument( + "--synthesizer-encoder-layers", + type=int, + default=0, + metavar="N", + help="num encoder layers in the second-pass synthesizer module", + ) + parser.add_argument( + "--synthesizer-augmented-cross-attention", + action="store_true", + default=False, + help="augmented cross-attention over speech encoder output", + ) + parser.add_argument( + "--load-pretrained-aux-decoder-from", + type=str, + metavar="STR", + help="model to take decoder weights from (for initialization)", + ) + + @classmethod + def build_text_decoder(cls, args, tgt_dict): + _args = copy.deepcopy(args) + + if args.adaptor_proj or args.encoder_proj: # not V0 arch + _args.encoder_embed_dim = _args.decoder_embed_dim + _args.dropout = args.decoder_dropout + _args.attention_dropout = args.decoder_attention_dropout + _args.activation_dropout = args.decoder_activation_dropout + _args.layerdrop = _args.decoder_layerdrop + _args.decoder_layers = _args.translation_decoder_layers + + embed_tokens = build_embedding(tgt_dict, _args.decoder_embed_dim) + decoder = TransformerDecoder(_args, tgt_dict, embed_tokens) + + if getattr(args, "load_pretrained_aux_decoder_from", None) is not None: + decoder = cls.maybe_load_pretrained( + decoder, getattr(args, "load_pretrained_aux_decoder_from", None) + ) + + for k, p in decoder.named_parameters(): + p.requires_grad = need_finetuning(args.finetune_decoder_params, k) + return decoder + + @classmethod + def build_decoder(cls, args, task, aug_attn=False): + _args = copy.deepcopy(args) + _args.layerdrop = 0.0 # turn off layerdrop for shallow layers + + _args.encoder_embed_dim = args.decoder_embed_dim + + proj = None + if args.decoder_embed_dim != _args.decoder_embed_dim: + proj = Linear(args.decoder_embed_dim, _args.decoder_embed_dim) + + embed_tokens = build_embedding(task.target_dictionary, _args.decoder_embed_dim) + decoder_cls = AugTransformerDecoder if aug_attn else TransformerDecoder + decoder = decoder_cls(_args, task.target_dictionary, embed_tokens) + + if getattr(args, "load_pretrained_decoder_from", None) is not None: + # load all layers first and then discard the bottom layers + embed_tokens = build_embedding( + task.target_dictionary, _args.decoder_embed_dim + ) + decoder_tmp = decoder_cls(_args, task.target_dictionary, embed_tokens) + decoder_tmp = cls.maybe_load_pretrained( + decoder_tmp, getattr(_args, "load_pretrained_decoder_from", None) + ) + state_dict = decoder_tmp.state_dict() + for k, p in decoder.named_parameters(): + p.data = state_dict[k].data + p.requires_grad = need_finetuning(_args.finetune_decoder_params, k) + decoder.layers = decoder.layers[-_args.decoder_layers :] + + return decoder, proj, _args + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + + # make sure all arguments are present in older models + xm_t_base_architecture(args) + + encoder = cls.build_encoder(args) + decoder, proj, unit_args = cls.build_decoder( + args, + task, + aug_attn=getattr(args, "synthesizer_augmented_cross_attention", False), + ) + base_model = cls(encoder, decoder) + setattr(base_model, "proj", proj) + + base_model.t2u_augmented_cross_attn = getattr( + args, "synthesizer_augmented_cross_attention", False + ) + + # set up multitask decoders + base_model.mt_task_name = None + base_model.multitask_decoders = {} + has_first_pass_decoder = False + for task_name, task_obj in task.multitask_tasks.items(): + if task_obj.is_first_pass_decoder: + has_first_pass_decoder = True + base_model.mt_task_name = task_name + + task_decoder = cls.build_multitask_decoder( + args, + task_obj.args, + task_obj.target_dictionary, + args.decoder_embed_dim, + task_obj.is_first_pass_decoder, + ) + + setattr(base_model, f"{task_name}_decoder", task_decoder) + decoder_model_cls = ( + FairseqEncoderModel + if task_obj.args.decoder_type == "ctc" + else FairseqLanguageModel + ) + base_model.multitask_decoders[task_name] = decoder_model_cls( + getattr(base_model, f"{task_name}_decoder") + ) + + assert has_first_pass_decoder, "set at least one intermediate non-CTC decoder" + + # set up encoder on top of the auxiliary MT decoder + if getattr(args, "synthesizer_encoder_layers", 0) > 0: + base_model.synthesizer_encoder = cls.build_t2u_encoder(unit_args) + else: + base_model.synthesizer_encoder = None + + return base_model + + @classmethod + def build_multitask_decoder( + cls, args, mtl_args, tgt_dict, in_dim, is_first_pass_decoder + ): + decoder_args = mtl_args.decoder_args + decoder_args.encoder_embed_dim = in_dim + if mtl_args.decoder_type == "transformer": + if is_first_pass_decoder: + task_decoder = cls.build_text_decoder(args, tgt_dict) + else: + from fairseq.models.speech_to_speech import ( + base_multitask_text_transformer_decoder_arch, + ) + + base_multitask_text_transformer_decoder_arch(decoder_args) # 2L + task_decoder = TransformerDecoder( + decoder_args, + tgt_dict, + embed_tokens=TransformerModelBase.build_embedding( + decoder_args, + tgt_dict, + decoder_args.decoder_embed_dim, + ), + ) + elif args.decoder_type == "ctc": + task_decoder = CTCDecoder( + dictionary=tgt_dict, + in_dim=in_dim, + ) + else: + raise NotImplementedError( + "currently only support multitask decoder_type 'transformer', 'ctc'" + ) + + return task_decoder + + @classmethod + def build_t2u_encoder(cls, args): + _args = copy.deepcopy(args) + _args.encoder_layers = _args.synthesizer_encoder_layers + _args.encoder_embed_dim = args.decoder_embed_dim + _args.encoder_ffn_embed_dim = args.decoder_ffn_embed_dim + _args.encoder_attention_heads = args.decoder_attention_heads + _args.encoder_normalize_before = True + return TransformerEncoderNoEmb(_args) + + def forward( + self, + src_tokens, + src_lengths, + prev_output_tokens, + prev_output_tokens_mt, + return_all_hiddens=False, + tgt_speaker=None, + **kwargs, + ): + """ + The forward method inherited from the base class has a **kwargs + argument in its input, which is not supported in torchscript. This + method overwrites the forward method definition without **kwargs. + """ + encoder_out = self.encoder( + src_tokens=src_tokens, src_lengths=src_lengths, **kwargs + ) + + # 1. MT decoder + mt_decoder = getattr(self, f"{self.mt_task_name}_decoder") + mt_decoder_out = mt_decoder( + prev_output_tokens_mt, + encoder_out=encoder_out, + ) + x = mt_decoder_out[1]["inner_states"][-1] + if mt_decoder.layer_norm is not None: + x = mt_decoder.layer_norm(x) + if self.proj is not None: + x = self.proj(x) + + mt_decoder_padding_mask = None + if prev_output_tokens_mt.eq(mt_decoder.padding_idx).any(): + mt_decoder_padding_mask = prev_output_tokens_mt.eq(mt_decoder.padding_idx) + + # 2. T2U encoder + if self.synthesizer_encoder is not None: + t2u_encoder_out = self.synthesizer_encoder( + x, + mt_decoder_padding_mask, + ) + else: + t2u_encoder_out = { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [mt_decoder_padding_mask], # B x T + } + + # 3. T2U decoder + if self.t2u_augmented_cross_attn: + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=encoder_out, + encoder_out_aug=t2u_encoder_out, + ) + else: + decoder_out = self.decoder( + prev_output_tokens, + encoder_out=t2u_encoder_out, + ) + if return_all_hiddens: + decoder_out[-1]["encoder_states"] = encoder_out["encoder_out"] + # NOTE: from the top layer + decoder_out[-1]["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ] + decoder_out[-1]["mt_decoder_out"] = mt_decoder_out + return decoder_out + + +@register_model_architecture( + model_name="unity_xm_transformer", arch_name="unity_xm_transformer" +) +def base_architecture_unity(args): + set_default_general_args(args) + set_default_w2v_encoder_args(args) + set_default_adaptor_args(args) + set_default_transformer_decoder_args(args) + + args.layernorm_embedding = False + args.decoder_learned_pos = False + + +# for old models +@register_model_architecture( + model_name="unity_xm_transformer", arch_name="xm_transformer_t2" +) +def base_architecture_unity_legacy(args): + base_architecture_unity(args) diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py index 1a0f978b3b..c22e5625d4 100644 --- a/fairseq/models/transformer/transformer_decoder.py +++ b/fairseq/models/transformer/transformer_decoder.py @@ -8,6 +8,7 @@ import torch import torch.nn as nn +from torch import Tensor from fairseq import utils from fairseq.distributed import fsdp_wrap @@ -25,7 +26,6 @@ ) from fairseq.modules.checkpoint_activations import checkpoint_wrapper from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ -from torch import Tensor # rewrite name for backward compatibility in `make_generation_fast_` @@ -42,7 +42,7 @@ class TransformerDecoderBase(FairseqIncrementalDecoder): is a :class:`TransformerDecoderLayer`. Args: - args (argparse.Namespace): parsed command-line arguments + cfg (argparse.Namespace): parsed command-line arguments dictionary (~fairseq.data.Dictionary): decoding dictionary embed_tokens (torch.nn.Embedding): output embedding no_encoder_attn (bool, optional): whether to attend to encoder outputs diff --git a/fairseq/models/transformer/transformer_decoder_aug.py b/fairseq/models/transformer/transformer_decoder_aug.py new file mode 100644 index 0000000000..c5e7101794 --- /dev/null +++ b/fairseq/models/transformer/transformer_decoder_aug.py @@ -0,0 +1,392 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Any, Dict, List, Optional + +import torch +import torch.nn as nn +from torch import Tensor + +from fairseq import utils +from fairseq.distributed import fsdp_wrap +from fairseq.models.transformer import TransformerConfig +from fairseq.models.transformer.transformer_decoder import TransformerDecoderBase +from fairseq.modules import ( + LayerDropModuleList, + SinusoidalPositionalEmbedding, + transformer_layer_aug, +) +from fairseq.modules.checkpoint_activations import checkpoint_wrapper + + +class AugTransformerDecoderBase(TransformerDecoderBase): + """ + Transformer decoder augmented with an additional cross-attention. Each layer + is a :class:`AugTransformerDecoderLayerBase`. + + Args: + cfg (argparse.Namespace): parsed command-line arguments + dictionary (~fairseq.data.Dictionary): decoding dictionary + embed_tokens (torch.nn.Embedding): output embedding + encoder_attn_merge_type (str, optional): the way to combine outputs from + two cross-attention modules. If "sequential" is set, two cross-attention + modules are stacked sequentially. If "parallel" is set, they are processed + in parallel and combined before feeding it to FFN (default: sequential). + dropnet_ratio (float, optional): a probability to drop each cross-attention + module during training (default: 0.0). + """ + + def __init__( + self, + cfg, + dictionary, + embed_tokens, + output_projection=None, + encoder_attn_merge_type="sequential", + dropnet_ratio=0.0, + ): + super().__init__( + cfg, + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=output_projection, + ) + # assert cfg.cross_self_attention + self.cross_self_attention = cfg.cross_self_attention + + if self.decoder_layerdrop > 0.0: + self.layers = LayerDropModuleList(p=self.decoder_layerdrop) + else: + self.layers = nn.ModuleList([]) + self.layers.extend( + [ + self.build_decoder_layer(cfg, encoder_attn_merge_type, dropnet_ratio) + for _ in range(cfg.decoder.layers) + ] + ) + + def build_decoder_layer( + self, + cfg, + encoder_attn_merge_type="sequential", + dropnet_ratio=0, + ): + layer = transformer_layer_aug.AugTransformerDecoderLayerBase( + cfg, + no_encoder_attn=False, + encoder_attn_merge_type=encoder_attn_merge_type, + dropnet_ratio=dropnet_ratio, + ) + checkpoint = cfg.checkpoint_activations + if checkpoint: + offload_to_cpu = cfg.offload_activations + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + # if we are checkpointing, enforce that FSDP always wraps the + # checkpointed layer, regardless of layer size + min_params_to_wrap = cfg.min_params_to_wrap if not checkpoint else 0 + layer = fsdp_wrap(layer, min_num_params=min_params_to_wrap) + return layer + + def forward( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + encoder_out_aug: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + features_only: bool = False, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + src_lengths: Optional[Any] = None, + return_all_hiddens: bool = False, + ): + """ + Args: + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + encoder_out (optional): output from the encoder, used for + encoder-side attention, should be of size T x B x C + incremental_state (dict): dictionary used for storing state during + :ref:`Incremental decoding` + features_only (bool, optional): only return features without + applying output layer (default: False). + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + + x, extra = self.extract_features( + prev_output_tokens, + encoder_out=encoder_out, + encoder_out_aug=encoder_out_aug, + incremental_state=incremental_state, + full_context_alignment=full_context_alignment, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + ) + + if not features_only: + x = self.output_layer(x) + return x, extra + + def extract_features( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + encoder_out_aug: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + return self.extract_features_scriptable( + prev_output_tokens, + encoder_out, + encoder_out_aug, + incremental_state, + full_context_alignment, + alignment_layer, + alignment_heads, + ) + + """ + A scriptable subclass of this class has an extract_features method and calls + super().extract_features, but super() is not supported in torchscript. A copy of + this function is made to be used in the subclass instead. + """ + + def extract_features_scriptable( + self, + prev_output_tokens, + encoder_out: Optional[Dict[str, List[Tensor]]], + encoder_out_aug: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + """ + Similar to *forward* but only return features. + + Includes several features from "Jointly Learning to Align and + Translate with Transformer Models" (Garg et al., EMNLP 2019). + + Args: + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + alignment_layer (int, optional): return mean alignment over + heads at this layer (default: last layer). + alignment_heads (int, optional): only average alignment over + this many heads (default: all heads). + + Returns: + tuple: + - the decoder's features of shape `(batch, tgt_len, embed_dim)` + - a dictionary with any model-specific outputs + """ + bs, slen = prev_output_tokens.size() + if alignment_layer is None: + alignment_layer = self.num_layers - 1 + + enc: Optional[Tensor] = None + padding_mask: Optional[Tensor] = None + if encoder_out is not None and len(encoder_out["encoder_out"]) > 0: + enc = encoder_out["encoder_out"][0] + if encoder_out is not None and len(encoder_out["encoder_padding_mask"]) > 0: + padding_mask = encoder_out["encoder_padding_mask"][0] + + enc_aug: Optional[Tensor] = None + padding_mask_aug: Optional[Tensor] = None + if encoder_out_aug is not None and len(encoder_out_aug["encoder_out"]) > 0: + enc_aug = encoder_out_aug["encoder_out"][0] + if ( + encoder_out_aug is not None + and len(encoder_out_aug["encoder_padding_mask"]) > 0 + ): + padding_mask_aug = encoder_out_aug["encoder_padding_mask"][0] + + # embed positions + positions = None + if self.embed_positions is not None: + positions = self.embed_positions( + prev_output_tokens, incremental_state=incremental_state + ) + + if incremental_state is not None: + prev_output_tokens = prev_output_tokens[:, -1:] + if positions is not None: + positions = positions[:, -1:] + + # Prevent torchscript exporting issue for dynamic quant embedding + prev_output_tokens = prev_output_tokens.contiguous() + # embed tokens and positions + x = self.embed_scale * self.embed_tokens(prev_output_tokens) + + if self.quant_noise is not None: + x = self.quant_noise(x) + + if self.project_in_dim is not None: + x = self.project_in_dim(x) + + if positions is not None: + x += positions + + if self.layernorm_embedding is not None: + x = self.layernorm_embedding(x) + + x = self.dropout_module(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + self_attn_padding_mask: Optional[Tensor] = None + if self.cross_self_attention or prev_output_tokens.eq(self.padding_idx).any(): + self_attn_padding_mask = prev_output_tokens.eq(self.padding_idx) + + # decoder layers + attn: Optional[Tensor] = None + attn_aug: Optional[Tensor] = None + inner_states: List[Optional[Tensor]] = [x] + for idx, layer in enumerate(self.layers): + if incremental_state is None and not full_context_alignment: + self_attn_mask = self.buffered_future_mask(x) + else: + self_attn_mask = None + + x, layer_attn, layer_attn_aug, _ = layer( + x, + enc, + padding_mask, + enc_aug, + padding_mask_aug, + incremental_state, + self_attn_mask=self_attn_mask, + self_attn_padding_mask=self_attn_padding_mask, + need_attn=bool((idx == alignment_layer)), + need_head_weights=bool((idx == alignment_layer)), + ) + inner_states.append(x) + if layer_attn is not None and idx == alignment_layer: + attn = layer_attn.float().to(x) + if layer_attn_aug is not None and idx == alignment_layer: + attn_aug = layer_attn_aug.float().to(x) + + if attn is not None: + if alignment_heads is not None: + attn = attn[:alignment_heads] + + # average probabilities over heads + attn = attn.mean(dim=0) + + if attn_aug is not None: + if alignment_heads is not None: + attn_aug = attn_aug[:alignment_heads] + + # average probabilities over heads + attn_aug = attn_aug.mean(dim=0) + + if self.layer_norm is not None: + x = self.layer_norm(x) + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + if self.project_out_dim is not None: + x = self.project_out_dim(x) + + return x, {"attn": [attn], "attn_aug": [attn_aug], "inner_states": inner_states} + + def upgrade_state_dict_named(self, state_dict, name): + """Upgrade a (possibly old) state dict for new versions of fairseq.""" + if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): + weights_key = "{}.embed_positions.weights".format(name) + if weights_key in state_dict: + del state_dict[weights_key] + state_dict[ + "{}.embed_positions._float_tensor".format(name) + ] = torch.FloatTensor(1) + + if f"{name}.output_projection.weight" not in state_dict: + if self.share_input_output_embed: + embed_out_key = f"{name}.embed_tokens.weight" + else: + embed_out_key = f"{name}.embed_out" + if embed_out_key in state_dict: + state_dict[f"{name}.output_projection.weight"] = state_dict[ + embed_out_key + ] + if not self.share_input_output_embed: + del state_dict[embed_out_key] + + for i in range(self.num_layers): + # update layer norms + layer_norm_map = { + "0": "self_attn_layer_norm", + "1": "encoder_attn_layer_norm", + "2": "encoder_attn_layer_norm2", + "3": "final_layer_norm", + } + for old, new in layer_norm_map.items(): + for m in ("weight", "bias"): + k = "{}.layers.{}.layer_norms.{}.{}".format(name, i, old, m) + if k in state_dict: + state_dict[ + "{}.layers.{}.{}.{}".format(name, i, new, m) + ] = state_dict[k] + del state_dict[k] + + version_key = "{}.version".format(name) + if utils.item(state_dict.get(version_key, torch.Tensor([1]))[0]) <= 2: + # earlier checkpoints did not normalize after the stack of layers + self.layer_norm = None + self.normalize = False + state_dict[version_key] = torch.Tensor([1]) + + return state_dict + + +class AugTransformerDecoder(AugTransformerDecoderBase): + def __init__( + self, + args, + dictionary, + embed_tokens, + output_projection=None, + ): + self.args = args + super().__init__( + TransformerConfig.from_namespace(args), + dictionary, + embed_tokens, + no_encoder_attn=False, + output_projection=output_projection, + encoder_attn_merge_type=getattr( + args, "synthesizer_augmented_cross_attention_merge_type", "sequential" + ), + dropnet_ratio=getattr(args, "dropnet_ratio", 0), + ) + + def build_output_projection(self, args, dictionary, embed_tokens): + super().build_output_projection( + TransformerConfig.from_namespace(args), dictionary, embed_tokens + ) + + def build_decoder_layer( + self, + args, + encoder_attn_merge_type="sequential", + dropnet_ratio=0, + ): + return super().build_decoder_layer( + TransformerConfig.from_namespace(args), + no_encoder_attn=False, + encoder_attn_merge_type=encoder_attn_merge_type, + dropnet_ratio=dropnet_ratio, + ) diff --git a/fairseq/modules/transformer_layer.py b/fairseq/modules/transformer_layer.py index 4a283762b8..19e035dec5 100644 --- a/fairseq/modules/transformer_layer.py +++ b/fairseq/modules/transformer_layer.py @@ -28,7 +28,7 @@ class TransformerEncoderLayerBase(nn.Module): *cfg.encoder.normalize_before* to ``True``. Args: - args (argparse.Namespace): parsed command-line arguments + cfg (argparse.Namespace): parsed command-line arguments """ def __init__(self, cfg, return_fc=False): diff --git a/fairseq/modules/transformer_layer_aug.py b/fairseq/modules/transformer_layer_aug.py new file mode 100644 index 0000000000..7eb816978a --- /dev/null +++ b/fairseq/modules/transformer_layer_aug.py @@ -0,0 +1,315 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Optional + +import torch +from numpy.random import uniform +from torch import Tensor + +from fairseq.modules import LayerNorm +from fairseq.modules.transformer_layer import TransformerDecoderLayerBase + + +class AugTransformerDecoderLayerBase(TransformerDecoderLayerBase): + """Decoder layer block augmented with an additional cross-attention. + + This decoder block is processed with the sequence of the following sub-modules. + self-attention -> cross-attention (first) -> cross-attention (second) -> FFN + + Args: + cfg (argparse.Namespace): parsed command-line arguments + encoder_attn_merge_type (str, optional): the way to combine outputs from + two cross-attention modules. If "sequential" is set, two cross-attention + modules are stacked sequentially. If "parallel" is set, they are processed + in parallel and combined before feeding it to FFN (default: sequential). + dropnet_ratio (float, optional): a probability to drop each cross-attention + module during training (default: 0.0). + """ + + def __init__( + self, + cfg, + add_bias_kv=False, + add_zero_attn=False, + encoder_attn_merge_type="sequential", + dropnet_ratio=0.0, + ): + super().__init__( + cfg, + no_encoder_attn=False, + add_bias_kv=add_bias_kv, + add_zero_attn=False, + ) + self.encoder_attn = self.build_encoder_attention(self.embed_dim, cfg) + self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=cfg.export) + self.encoder_attn2 = self.build_encoder_attention(self.embed_dim, cfg) + if encoder_attn_merge_type == "sequential": + self.encoder_attn_layer_norm2 = LayerNorm(self.embed_dim, export=cfg.export) + else: + self.encoder_attn_layer_norm2 = None + + self.encoder_attn_merge_type = encoder_attn_merge_type + self.dropnet_ratio = dropnet_ratio + + def forward( + self, + x, + encoder_out: Optional[torch.Tensor] = None, + encoder_padding_mask: Optional[torch.Tensor] = None, + encoder_out_aug: Optional[torch.Tensor] = None, + encoder_padding_mask2: Optional[torch.Tensor] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + prev_self_attn_state: Optional[List[torch.Tensor]] = None, + prev_attn_state: Optional[List[torch.Tensor]] = None, + self_attn_mask: Optional[torch.Tensor] = None, + self_attn_padding_mask: Optional[torch.Tensor] = None, + need_attn: bool = False, + need_head_weights: bool = False, + ): + """ + Args: + x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)` + encoder_padding_mask (ByteTensor, optional): binary + ByteTensor of shape `(batch, src_len)` where padding + elements are indicated by ``1``. + need_attn (bool, optional): return attention weights + need_head_weights (bool, optional): return attention weights + for each head (default: return average over heads). + + Returns: + encoded output of shape `(seq_len, batch, embed_dim)` + """ + if need_head_weights: + need_attn = True + + residual = x + if self.normalize_before: + x = self.self_attn_layer_norm(x) + if prev_self_attn_state is not None: + prev_key, prev_value = prev_self_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_self_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_self_attn_state[2] + assert incremental_state is not None + self.self_attn._set_input_buffer(incremental_state, saved_state) + _self_attn_input_buffer = self.self_attn._get_input_buffer(incremental_state) + if self.cross_self_attention and not ( + incremental_state is not None + and _self_attn_input_buffer is not None + and "prev_key" in _self_attn_input_buffer + ): + if self_attn_mask is not None: + assert encoder_out is not None + self_attn_mask = torch.cat( + (x.new_zeros(x.size(0), encoder_out.size(0)), self_attn_mask), dim=1 + ) + if self_attn_padding_mask is not None: + if encoder_padding_mask is None: + assert encoder_out is not None + encoder_padding_mask = self_attn_padding_mask.new_zeros( + encoder_out.size(1), encoder_out.size(0) + ) + self_attn_padding_mask = torch.cat( + (encoder_padding_mask, self_attn_padding_mask), dim=1 + ) + assert encoder_out is not None + y = torch.cat((encoder_out, x), dim=0) + else: + y = x + + x, attn = self.self_attn( + query=x, + key=y, + value=y, + key_padding_mask=self_attn_padding_mask, + incremental_state=incremental_state, + need_weights=False, + attn_mask=self_attn_mask, + ) + if self.c_attn is not None: + tgt_len, bsz = x.size(0), x.size(1) + x = x.view(tgt_len, bsz, self.nh, self.head_dim) + x = torch.einsum("tbhd,h->tbhd", x, self.c_attn) + x = x.reshape(tgt_len, bsz, self.embed_dim) + if self.attn_ln is not None: + x = self.attn_ln(x) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) + + assert encoder_out is not None + assert encoder_out_aug is not None + + if self.encoder_attn_merge_type == "sequential": + ratios = self.get_dropnet_ratio() + + # first encoder attention + if ratios[0] > 0: + residual = x + if self.normalize_before: + x = self.encoder_attn_layer_norm(x) + if prev_attn_state is not None: + prev_key, prev_value = prev_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_attn_state[2] + assert incremental_state is not None + self.encoder_attn._set_input_buffer(incremental_state, saved_state) + + x, attn = self.encoder_attn( + query=x, + key=encoder_out, + value=encoder_out, + key_padding_mask=encoder_padding_mask, + incremental_state=incremental_state, + static_kv=True, + need_weights=need_attn or (not self.training and self.need_attn), + need_head_weights=need_head_weights, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.encoder_attn_layer_norm(x) + x = ratios[0] * x + + # second encoder attention + if ratios[1] > 0: + residual = x + if self.normalize_before: + x = self.encoder_attn_layer_norm2(x) + if prev_attn_state is not None: + prev_key, prev_value = prev_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_attn_state[2] + assert incremental_state is not None + self.encoder_attn2._set_input_buffer(incremental_state, saved_state) + + x, attn2 = self.encoder_attn2( + query=x, + key=encoder_out_aug, + value=encoder_out_aug, + key_padding_mask=encoder_padding_mask2, + incremental_state=incremental_state, + static_kv=True, + need_weights=need_attn or (not self.training and self.need_attn), + need_head_weights=need_head_weights, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.encoder_attn_layer_norm2(x) + x = ratios[1] * x + + elif self.encoder_attn_merge_type == "parallel": + residual = x + if self.normalize_before: + x = self.encoder_attn_layer_norm(x) + if prev_attn_state is not None: + prev_key, prev_value = prev_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_attn_state[2] + assert incremental_state is not None + self.encoder_attn._set_input_buffer(incremental_state, saved_state) + + x1, attn = self.encoder_attn( + query=x, + key=encoder_out, + value=encoder_out, + key_padding_mask=encoder_padding_mask, + incremental_state=incremental_state, + static_kv=True, + need_weights=need_attn or (not self.training and self.need_attn), + need_head_weights=need_head_weights, + ) + x2, attn2 = self.encoder_attn2( + query=x, + key=encoder_out_aug, + value=encoder_out_aug, + key_padding_mask=encoder_padding_mask2, + incremental_state=incremental_state, + static_kv=True, + need_weights=need_attn or (not self.training and self.need_attn), + need_head_weights=need_head_weights, + ) + x1 = self.dropout_module(x1) + x2 = self.dropout_module(x2) + ratios = self.get_dropnet_ratio() + x = ratios[0] * x1 + ratios[1] * x2 + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.encoder_attn_layer_norm(x) + + else: + raise NotImplementedError(self.encoder_attn_merge_type) + + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + if self.ffn_layernorm is not None: + x = self.ffn_layernorm(x) + x = self.fc2(x) + x = self.dropout_module(x) + if self.w_resid is not None: + residual = torch.mul(self.w_resid, residual) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) + if self.onnx_trace and incremental_state is not None: + saved_state = self.self_attn._get_input_buffer(incremental_state) + assert saved_state is not None + if self_attn_padding_mask is not None: + self_attn_state = [ + saved_state["prev_key"], + saved_state["prev_value"], + saved_state["prev_key_padding_mask"], + ] + else: + self_attn_state = [saved_state["prev_key"], saved_state["prev_value"]] + return x, attn, attn2, self_attn_state + return x, attn, attn2, None + + def get_dropnet_ratio(self): + if self.encoder_attn_merge_type == "sequential": + if self.dropnet_ratio > 0: + frand = float(uniform(0, 1)) + if frand < self.dropnet_ratio and self.training: + return [2, 0] + elif frand > 1 - self.dropnet_ratio and self.training: + return [0, 2] + else: + return [1, 1] + else: + return [1, 1] + + elif self.encoder_attn_merge_type == "parallel": + if self.dropnet_ratio > 0: + frand = float(uniform(0, 1)) + if frand < self.dropnet_ratio and self.training: + return [1, 0] + elif frand > 1 - self.dropnet_ratio and self.training: + return [0, 1] + else: + return [0.5, 0.5] + else: + return [0.5, 0.5] diff --git a/fairseq/speech_generator.py b/fairseq/speech_generator.py index b6d5f5cc13..f2cc8b5e86 100644 --- a/fairseq/speech_generator.py +++ b/fairseq/speech_generator.py @@ -76,7 +76,203 @@ def generate(self, model, sample, has_targ=False, **kwargs): incremental_state=incremental_state, target_lengths=cur_out_lens, speaker=sample["speaker"], - **kwargs + **kwargs, + ) + cur_eos_prob = torch.sigmoid(cur_eos_out).squeeze(2) + feat.append(cur_extra["feature_out"]) + attn.append(cur_extra["attn"]) + eos_prob.append(cur_eos_prob) + + cur_finished = cur_eos_prob.squeeze(1) > self.eos_prob_threshold + out_lens.masked_fill_((~finished) & cur_finished, step + 1) + finished = finished | cur_finished + if finished.sum().item() == bsz: + break + prev_feat_out = cur_extra["feature_out"] + + feat = torch.cat(feat, dim=1) + feat = model.decoder.postnet(feat) + feat + eos_prob = torch.cat(eos_prob, dim=1) + attn = torch.cat(attn, dim=2) + alignment = attn.max(dim=1)[1] + + feat = feat.reshape(bsz, -1, raw_dim) + feat = self.gcmvn_denormalize(feat) + + eos_prob = eos_prob.repeat_interleave(n_frames_per_step, dim=1) + attn = attn.repeat_interleave(n_frames_per_step, dim=2) + alignment = alignment.repeat_interleave(n_frames_per_step, dim=1) + out_lens = out_lens * n_frames_per_step + + finalized = [ + { + "feature": feat[b, :out_len], + "eos_prob": eos_prob[b, :out_len], + "attn": attn[b, :, :out_len], + "alignment": alignment[b, :out_len], + "waveform": self.get_waveform(feat[b, :out_len]), + } + for b, out_len in zip(range(bsz), out_lens) + ] + + if has_targ: + assert sample["target"].size(-1) == out_dim + tgt_feats = sample["target"].view(bsz, -1, raw_dim) + tgt_feats = self.gcmvn_denormalize(tgt_feats) + tgt_lens = sample["target_lengths"] * n_frames_per_step + for b, (f, l) in enumerate(zip(tgt_feats, tgt_lens)): + finalized[b]["targ_feature"] = f[:l] + finalized[b]["targ_waveform"] = self.get_waveform(f[:l]) + return finalized + + +class MultiDecoderSpeechGenerator(SpeechGenerator): + def __init__( + self, + models, + args, + vocoder, + data_cfg, + tgt_dict_mt, + max_iter: int = 6000, + eos_prob_threshold: float = 0.5, + eos_mt=None, + symbols_to_strip_from_output=None, + ): + super().__init__(models[0], vocoder, data_cfg) + self.max_iter = max_iter + self.eos_prob_threshold = eos_prob_threshold + + self.tgt_dict_mt = tgt_dict_mt + self.eos_mt = eos_mt + + from examples.speech_to_speech.unity.sequence_generator import SequenceGenerator + from fairseq import search + + self.text_generator = SequenceGenerator( + models, + tgt_dict_mt, + beam_size=max(1, getattr(args, "beam", 5)), + max_len_a=getattr(args, "max_len_a", 0), + max_len_b=getattr(args, "max_len_b", 200), + min_len=getattr(args, "min_len", 1), + normalize_scores=(not getattr(args, "unnormalized", False)), + len_penalty=getattr(args, "lenpen", 1), + unk_penalty=getattr(args, "unkpen", 0), + temperature=getattr(args, "temperature", 1.0), + match_source_len=getattr(args, "match_source_len", False), + no_repeat_ngram_size=getattr(args, "no_repeat_ngram_size", 0), + search_strategy=search.BeamSearch(tgt_dict_mt), + eos=eos_mt, + symbols_to_strip_from_output=symbols_to_strip_from_output, + ) + + @torch.no_grad() + def generate(self, model, sample, has_targ=False, **kwargs): + model.eval() + + src_tokens = sample["net_input"]["src_tokens"] + src_lengths = sample["net_input"]["src_lengths"] + bsz, src_len = src_tokens.size()[:2] + n_frames_per_step = model.decoder.n_frames_per_step + out_dim = model.decoder.out_dim + raw_dim = out_dim // n_frames_per_step + + # initialize + encoder_out = model.forward_encoder( + src_tokens, src_lengths, speaker=sample["speaker"] + ) + + prefix_tokens = None + constraints = None + bos_token = None + + mt_decoder = getattr(model, f"{model.mt_task_name}_decoder") + + # 1. MT decoder + finalized_mt = self.text_generator.generate_decoder( + [encoder_out], + src_tokens, + src_lengths, + sample, + prefix_tokens, + constraints, + bos_token, + aux_task_name=model.mt_task_name, + ) + + # extract decoder output corresponding to the best hypothesis + max_tgt_len = max([len(hypo[0]["tokens"]) for hypo in finalized_mt]) + prev_output_tokens_mt = ( + src_tokens.new_zeros(src_tokens.shape[0], max_tgt_len) + .fill_(mt_decoder.padding_idx) + .int() + ) # B x T + for i, hypo in enumerate(finalized_mt): + i_beam = 0 + tmp = hypo[i_beam]["tokens"].int() # hyp + eos + prev_output_tokens_mt[i, 0] = self.text_generator.eos + if tmp[-1] == self.text_generator.eos: + tmp = tmp[:-1] + prev_output_tokens_mt[i, 1 : len(tmp) + 1] = tmp + + text = "".join([self.tgt_dict_mt[c] for c in tmp]) + text = text.replace("_", " ") + text = text.replace("▁", " ") + text = text.replace("<unk>", " ") + text = text.replace("<s>", "") + text = text.replace("</s>", "") + if len(text) > 0 and text[0] == " ": + text = text[1:] + sample_id = sample["id"].tolist()[i] + print("{} (None-{})".format(text, sample_id)) + + mt_decoder_out = mt_decoder( + prev_output_tokens_mt, + encoder_out=encoder_out, + features_only=True, + ) + x = mt_decoder_out[0].transpose(0, 1) + + mt_decoder_padding_mask = None + if prev_output_tokens_mt.eq(mt_decoder.padding_idx).any(): + mt_decoder_padding_mask = prev_output_tokens_mt.eq(mt_decoder.padding_idx) + + # 2. TTS encoder + if getattr(model, "synthesizer_encoder", None) is not None: + synthesizer_encoder_out = model.synthesizer_encoder( + x, + mt_decoder_padding_mask, + ) + else: + synthesizer_encoder_out = { + "encoder_out": [x], # T x B x C + "encoder_padding_mask": [mt_decoder_padding_mask] + if mt_decoder_padding_mask is not None + else [], # B x T + "encoder_embedding": [], + "encoder_states": [], + "src_tokens": [], + "src_lengths": [], + } + + # 3. TTS decoder + incremental_state = {} + feat, attn, eos_prob = [], [], [] + finished = src_tokens.new_zeros((bsz,)).bool() + out_lens = src_lengths.new_zeros((bsz,)).long().fill_(self.max_iter) + + prev_feat_out = encoder_out["encoder_out"][0].new_zeros(bsz, 1, out_dim) + for step in range(self.max_iter): + cur_out_lens = out_lens.clone() + cur_out_lens.masked_fill_(cur_out_lens.eq(self.max_iter), step + 1) + _, cur_eos_out, cur_extra = model.forward_decoder( + prev_feat_out, + encoder_out=synthesizer_encoder_out, + incremental_state=incremental_state, + target_lengths=cur_out_lens, + speaker=sample["speaker"], + **kwargs, ) cur_eos_prob = torch.sigmoid(cur_eos_out).squeeze(2) feat.append(cur_extra["feature_out"]) diff --git a/fairseq/tasks/speech_to_speech.py b/fairseq/tasks/speech_to_speech.py index d41ce854d4..5aaaa95a90 100644 --- a/fairseq/tasks/speech_to_speech.py +++ b/fairseq/tasks/speech_to_speech.py @@ -8,6 +8,7 @@ import math from argparse import Namespace from pathlib import Path +from typing import List import torch import torch.nn as nn @@ -16,7 +17,10 @@ from fairseq.data import Dictionary from fairseq.data.audio.data_cfg import MultitaskConfig, S2SDataConfig from fairseq.data.audio.speech_to_speech_dataset import SpeechToSpeechDatasetCreator -from fairseq.data.audio.speech_to_text_dataset import SpeechToTextDataset +from fairseq.data.audio.speech_to_text_dataset import ( + SpeechToTextDataset, + TextTargetMultitaskData, +) from fairseq.tasks import LegacyFairseqTask, register_task from fairseq.tasks.speech_to_text import DummyMultiTask from fairseq.tasks.text_to_speech import batch_mel_cepstral_distortion @@ -209,15 +213,35 @@ def __init__(self, args, tgt_dict, infer_tgt_lang_id=None): super().__init__(args) self.tgt_dict = tgt_dict self.data_cfg = S2SDataConfig(Path(args.data) / args.config_yaml) + self.multitask_tasks = {} + self.tgt_dict_mt = None + self.eos_token_mt = None if getattr(args, "multitask_config_yaml", None) is not None: multitask_cfg = MultitaskConfig( Path(args.data) / args.multitask_config_yaml ) - for task_name, task_config in multitask_cfg.get_all_tasks().items(): - self.multitask_tasks[task_name] = DummyMultiTask( - task_config, task_config.tgt_dict + first_pass_task_idx = multitask_cfg.first_pass_decoder_task_index + for i, (task_name, task_config) in enumerate( + multitask_cfg.get_all_tasks().items() + ): + task_obj = DummyMultiTask( + task_config, + task_config.tgt_dict, + first_pass=i == first_pass_task_idx, ) + self.multitask_tasks[task_name] = task_obj + if task_obj.is_first_pass_decoder: + self.tgt_dict_mt = task_obj.target_dictionary + if task_config.prepend_bos_and_append_tgt_lang_tag: + self.eos_token_mt = task_config.eos_token + assert not isinstance(self.eos_token_mt, List) + + if not self.eos_token_mt: + raise Warning( + "Please provide eos_token in --multitask-config-yaml to replace eos in sequence generator" + ) + self._infer_tgt_lang_id = infer_tgt_lang_id @classmethod @@ -267,11 +291,13 @@ def build_criterion(self, args): from fairseq import criterions if len(self.multitask_tasks) > 0: - if self.args.target_is_code and args._name != "speech_to_unit": + if self.args.target_is_code and not args._name.startswith("speech_to_unit"): raise ValueError( "set --criterion speech_to_unit for speech-to-unit loss with multitask" ) - elif not self.args.target_is_code and args._name != "speech_to_spectrogram": + elif not self.args.target_is_code and not args._name.startswith( + "speech_to_spectrogram" + ): raise ValueError( "set --criterion speech_to_spectrogram for speech-to-spectrogram loss with multitask" ) @@ -296,6 +322,10 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): def target_dictionary(self): return self.tgt_dict + @property + def target_dictionary_mt(self): + return self.tgt_dict_mt + @property def source_dictionary(self): return None @@ -326,6 +356,36 @@ def build_model(self, args, from_checkpoint=False): return model + def build_generator_dual_decoder( + self, + models, + args, + extra_gen_cls_kwargs=None, + ): + from examples.speech_to_speech.unity.sequence_generator_multi_decoder import ( + MultiDecoderSequenceGenerator, + ) + + return MultiDecoderSequenceGenerator( + models, + self.target_dictionary, + self.target_dictionary_mt, + beam_size=max(1, getattr(args, "beam", 1)), + beam_size_mt=max(1, getattr(args, "beam_mt", 1)), + max_len_a=getattr(args, "max_len_a", 0), + max_len_b=getattr(args, "max_len_b", 200), + max_len_a_mt=getattr(args, "max_len_a_mt", 0), + max_len_b_mt=getattr(args, "max_len_b_mt", 200), + min_len=getattr(args, "min_len", 1), + normalize_scores=(not getattr(args, "unnormalized", False)), + len_penalty=getattr(args, "lenpen", 1), + unk_penalty=getattr(args, "unkpen", 0), + temperature=getattr(args, "temperature", 1.0), + match_source_len=getattr(args, "match_source_len", False), + no_repeat_ngram_size=getattr(args, "no_repeat_ngram_size", 0), + **extra_gen_cls_kwargs, + ) + def build_generator( self, models, @@ -344,14 +404,23 @@ def build_generator( else self.vocoder.cpu() ) + has_dual_decoder = getattr(models[0], "mt_task_name", None) is not None + if self.args.target_is_code: if self.args.n_frames_per_step == 1: - seq_generator = super().build_generator( - models, - args, - seq_gen_cls=None, - extra_gen_cls_kwargs=extra_gen_cls_kwargs, - ) + if has_dual_decoder: + seq_generator = self.build_generator_dual_decoder( + models, + args, + extra_gen_cls_kwargs=extra_gen_cls_kwargs, + ) + else: + seq_generator = super().build_generator( + models, + args, + seq_gen_cls=None, + extra_gen_cls_kwargs=extra_gen_cls_kwargs, + ) else: assert ( getattr(args, "beam", 1) == 1 and getattr(args, "nbest", 1) == 1 @@ -361,24 +430,64 @@ def build_generator( self.args.target_code_size, ) else: - if getattr(args, "teacher_forcing", False): - from fairseq.speech_generator import ( - TeacherForcingAutoRegressiveSpeechGenerator, + if has_dual_decoder: + if getattr(args, "teacher_forcing", False): + raise NotImplementedError + else: + from fairseq.speech_generator import MultiDecoderSpeechGenerator + + generator = MultiDecoderSpeechGenerator + + lang_token_ids_aux = { + i + for s, i in self.tgt_dict_mt.indices.items() + if TextTargetMultitaskData.is_lang_tag(s) + } + + if extra_gen_cls_kwargs is None: + extra_gen_cls_kwargs = {} + extra_gen_cls_kwargs[ + "symbols_to_strip_from_output" + ] = lang_token_ids_aux + + eos_id_mt = ( + self.tgt_dict_mt.index(self.eos_token_mt) + if self.eos_token_mt + else None ) + assert eos_id_mt != self.tgt_dict_mt.unk() + extra_gen_cls_kwargs["eos_mt"] = eos_id_mt - generator = TeacherForcingAutoRegressiveSpeechGenerator - logger.info("Teacher forcing mode for generation") + seq_generator = generator( + models, + args, + self.vocoder, + self.data_cfg, + self.target_dictionary_mt, + max_iter=self.args.max_target_positions, + eos_prob_threshold=self.args.eos_prob_threshold, + **extra_gen_cls_kwargs, + ) else: - from fairseq.speech_generator import AutoRegressiveSpeechGenerator - - generator = AutoRegressiveSpeechGenerator - seq_generator = generator( - models[0], - self.vocoder, - self.data_cfg, - max_iter=self.args.max_target_positions, - eos_prob_threshold=self.args.eos_prob_threshold, - ) + if getattr(args, "teacher_forcing", False): + from fairseq.speech_generator import ( + TeacherForcingAutoRegressiveSpeechGenerator, + ) + + generator = TeacherForcingAutoRegressiveSpeechGenerator + logger.info("Teacher forcing mode for generation") + else: + from fairseq.speech_generator import AutoRegressiveSpeechGenerator + + generator = AutoRegressiveSpeechGenerator + + seq_generator = generator( + models[0], + self.vocoder, + self.data_cfg, + max_iter=self.args.max_target_positions, + eos_prob_threshold=self.args.eos_prob_threshold, + ) return seq_generator diff --git a/fairseq/tasks/speech_to_text.py b/fairseq/tasks/speech_to_text.py index 3fd0402203..884082112a 100644 --- a/fairseq/tasks/speech_to_text.py +++ b/fairseq/tasks/speech_to_text.py @@ -6,6 +6,7 @@ import logging from argparse import Namespace from pathlib import Path +from typing import List from fairseq.data import Dictionary, encoders from fairseq.data.audio.audio_utils import get_features_or_waveform @@ -14,6 +15,7 @@ S2TDataConfig, SpeechToTextDataset, SpeechToTextDatasetCreator, + TextTargetMultitaskData, ) from fairseq.tasks import LegacyFairseqTask, register_task @@ -66,13 +68,32 @@ def __init__(self, args, tgt_dict): ) self.multitask_tasks = {} + self.tgt_dict_mt = None + self.eos_token_mt = None if getattr(args, "multitask_config_yaml", None) is not None: multitask_cfg = MultitaskConfig( Path(args.data) / args.multitask_config_yaml ) - for task_name, task_config in multitask_cfg.get_all_tasks().items(): - task_obj = DummyMultiTask(task_config, task_config.tgt_dict) + first_pass_task_idx = multitask_cfg.first_pass_decoder_task_index + for i, (task_name, task_config) in enumerate( + multitask_cfg.get_all_tasks().items() + ): + task_obj = DummyMultiTask( + task_config, + task_config.tgt_dict, + first_pass=i == first_pass_task_idx, + ) self.multitask_tasks[task_name] = task_obj + if task_obj.is_first_pass_decoder: + self.tgt_dict_mt = task_obj.target_dictionary + if task_config.prepend_bos_and_append_tgt_lang_tag: + self.eos_token_mt = task_config.eos_token + assert not isinstance(self.eos_token_mt, List) + + if not self.eos_token_mt: + raise Warning( + "Please provide eos_token in --multitask-config-yaml to replace eos in sequence generator" + ) def _get_speaker_to_id(self): speaker_to_id = None @@ -124,12 +145,17 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): epoch=epoch, seed=self.args.seed, speaker_to_id=self.speaker_to_id, + multitask=self.multitask_tasks, ) @property def target_dictionary(self): return self.tgt_dict + @property + def target_dictionary_mt(self): + return self.tgt_dict_mt + @property def source_dictionary(self): return None @@ -143,6 +169,51 @@ def build_model(self, args, from_checkpoint=False): args.speaker_to_id = self.speaker_to_id return super(SpeechToTextTask, self).build_model(args, from_checkpoint) + def build_generator_dual_decoder( + self, + models, + args, + extra_gen_cls_kwargs, + ): + from examples.speech_to_speech.unity.sequence_generator_multi_decoder import ( + MultiDecoderSequenceGenerator, + ) + + lang_token_ids_aux = { + i + for s, i in self.tgt_dict_mt.indices.items() + if TextTargetMultitaskData.is_lang_tag(s) + } + + extra_gen_cls_kwargs["symbols_to_strip_from_output"].update(lang_token_ids_aux) + + eos_id_mt = ( + self.tgt_dict_mt.index(self.eos_token_mt) if self.eos_token_mt else None + ) + assert eos_id_mt != self.tgt_dict_mt.unk() + extra_gen_cls_kwargs["eos_mt"] = eos_id_mt + + return MultiDecoderSequenceGenerator( + models, + self.target_dictionary, + self.target_dictionary_mt, + beam_size=max(1, getattr(args, "beam", 1)), + beam_size_mt=max(1, getattr(args, "beam_mt", 1)), + max_len_a=getattr(args, "max_len_a", 0), + max_len_b=getattr(args, "max_len_b", 200), + max_len_a_mt=getattr(args, "max_len_a_mt", 0), + max_len_b_mt=getattr(args, "max_len_b_mt", 0), + min_len=getattr(args, "min_len", 1), + normalize_scores=(not getattr(args, "unnormalized", False)), + len_penalty=getattr(args, "lenpen", 1), + len_penalty_mt=getattr(args, "lenpen_mt", 1), + unk_penalty=getattr(args, "unkpen", 0), + temperature=getattr(args, "temperature", 1.0), + match_source_len=getattr(args, "match_source_len", False), + no_repeat_ngram_size=getattr(args, "no_repeat_ngram_size", 0), + **extra_gen_cls_kwargs, + ) + def build_generator( self, models, @@ -179,9 +250,21 @@ def build_generator( eos_id = self.tgt_dict.index(eos_token) if eos_token else None extra_gen_cls_kwargs["eos"] = eos_id - return super().build_generator( - models, args, seq_gen_cls=None, extra_gen_cls_kwargs=extra_gen_cls_kwargs - ) + has_dual_decoder = getattr(models[0], "mt_task_name", None) is not None + + if has_dual_decoder: + return self.build_generator_dual_decoder( + models, + args, + extra_gen_cls_kwargs=extra_gen_cls_kwargs, + ) + else: + return super().build_generator( + models, + args, + seq_gen_cls=None, + extra_gen_cls_kwargs=extra_gen_cls_kwargs, + ) def train_step( self, sample, model, criterion, optimizer, update_num, ignore_grad=False @@ -225,14 +308,19 @@ def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): class DummyMultiTask(LegacyFairseqTask): - def __init__(self, args, tgt_dict): + def __init__(self, args, tgt_dict, first_pass=False): super().__init__(args) self.tgt_dict = tgt_dict + self.first_pass = first_pass @property def target_dictionary(self): return self.tgt_dict + @property + def is_first_pass_decoder(self): + return self.first_pass + def inference_step( self, generator, models, sample, prefix_tokens=None, constraints=None ): diff --git a/scripts/average_checkpoints.py b/scripts/average_checkpoints.py index a4711e4840..49f4f9d912 100644 --- a/scripts/average_checkpoints.py +++ b/scripts/average_checkpoints.py @@ -10,6 +10,7 @@ import re import torch + from fairseq.file_io import PathManager @@ -113,6 +114,9 @@ def main(): num_group.add_argument('--num-update-checkpoints', type=int, help='if set, will try to find checkpoints with names checkpoint_ee_xx.pt in the path specified by' ' input, and average last this many of them.') + num_group.add_argument('--num-best-checkpoints', type=int, default=0, + help='if set, will try to find checkpoints with names checkpoint_best_ee_xx.pt in the path specified by' + ' input, and average last this many of them.') parser.add_argument('--checkpoint-upper-bound', type=int, help='when using --num-epoch-checkpoints, this will set an upper bound on which epoch to use, ' 'when using --num-update-checkpoints, this will set an upper bound on which update to use' @@ -150,6 +154,18 @@ def main(): ) print("averaging checkpoints: ", args.inputs) + if args.num_best_checkpoints > 0: + args.inputs = list( + sorted( + args.inputs, + key=lambda x: float( + os.path.basename(x).split("_")[-1].replace(".pt", "") + ), + ) + ) + args.inputs = args.inputs[: args.num_best_checkpoints] + for path in args.inputs: + print(os.path.basename(path)) new_state = average_checkpoints(args.inputs) with PathManager.open(args.output, "wb") as f: torch.save(new_state, f) From a3bd67231713d645c343e5e4b2f615e6699224c1 Mon Sep 17 00:00:00 2001 From: Mohsen <moslehpour@users.noreply.github.com> Date: Mon, 10 Oct 2022 16:38:20 -0700 Subject: [PATCH 693/774] make a scriptable dynamicconv (#4772) Make dynamicconv scriptable --- fairseq/modules/__init__.py | 3 +- fairseq/modules/dynamic_convolution.py | 215 ++++++++++++++++++++++++- fairseq/modules/unfold.py | 2 +- 3 files changed, 217 insertions(+), 3 deletions(-) diff --git a/fairseq/modules/__init__.py b/fairseq/modules/__init__.py index 8ad7f647d6..1df76ef24d 100644 --- a/fairseq/modules/__init__.py +++ b/fairseq/modules/__init__.py @@ -12,7 +12,7 @@ from .conv_tbc import ConvTBC from .cross_entropy import cross_entropy from .downsampled_multihead_attention import DownsampledMultiHeadAttention -from .dynamic_convolution import DynamicConv, DynamicConv1dTBC +from .dynamic_convolution import DynamicConv, DynamicConv1dTBC, DynamicConv_scripatable from .dynamic_crf_layer import DynamicCRF from .ema_module import EMAModuleConfig, EMAModule from .fairseq_dropout import FairseqDropout @@ -62,6 +62,7 @@ "DownsampledMultiHeadAttention", "DynamicConv1dTBC", "DynamicConv", + "DynamicConv_scripatable", "DynamicCRF", "EMAModule", "EMAModuleConfig", diff --git a/fairseq/modules/dynamic_convolution.py b/fairseq/modules/dynamic_convolution.py index 0121d453b9..49778a5b1b 100644 --- a/fairseq/modules/dynamic_convolution.py +++ b/fairseq/modules/dynamic_convolution.py @@ -3,12 +3,18 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +from typing import Dict, Optional + import torch import torch.nn as nn import torch.nn.functional as F from fairseq import utils -from fairseq.incremental_decoding_utils import with_incremental_state +from fairseq.incremental_decoding_utils import ( + FairseqIncrementalState, + with_incremental_state, +) from fairseq.modules.fairseq_dropout import FairseqDropout +from torch import Tensor from .unfold import unfold1d @@ -308,3 +314,210 @@ def extra_repr(self): if self.weight_dropout_module.p > 0.0: s += ", weight_dropout={}".format(self.weight_dropout_module.p) return s + + +class DynamicConv_scripatable(nn.Module, FairseqIncrementalState): + """Dynamic lightweight convolution taking T x B x C inputs + Args: + input_size: # of channels of the input + kernel_size: convolution channels + padding_l: padding to the left when using "same" padding + num_heads: number of heads used. The weight is of shape (num_heads, 1, kernel_size) + weight_dropout: the drop rate of the DropConnect to drop the weight + weight_softmax: normalize the weight with softmax before the convolution + renorm_padding: re-normalize the filters to ignore the padded part (only the non-padding parts sum up to 1) + bias: use bias + conv_bias: bias of the convolution + query_size: specified when feeding a different input as the query + in_proj: project the input and generate the filter together + + Shape: + Input: TxBxC, i.e. (timesteps, batch_size, input_size) + Output: TxBxC, i.e. (timesteps, batch_size, input_size) + + Attributes: + weight: the learnable weights of the module of shape + `(num_heads, 1, kernel_size)` + bias: the learnable bias of the module of shape `(input_size)` + """ + + def __init__( + self, + input_size, + kernel_size=1, + padding_l=None, + num_heads=1, + weight_dropout=0.0, + weight_softmax=False, + renorm_padding=False, + bias=False, + conv_bias=False, + query_size=None, + in_proj=False, + ): + super().__init__() + self.input_size = input_size + self.query_size = input_size if query_size is None else query_size + self.kernel_size = kernel_size + self.padding_l = padding_l + self.num_heads = num_heads + self.weight_dropout_module = FairseqDropout( + weight_dropout, module_name=self.__class__.__name__ + ) + self.weight_softmax = weight_softmax + self.renorm_padding = renorm_padding + + if in_proj: + self.weight_linear = Linear( + self.input_size, self.input_size + num_heads * kernel_size * 1 + ) + else: + self.weight_linear = Linear( + self.query_size, num_heads * kernel_size * 1, bias=bias + ) + self.in_proj = ( + self.weight_linear.out_features + == self.input_size + self.num_heads * self.kernel_size + ) + self.has_conv_bias = conv_bias + self.conv_bias = nn.Parameter(torch.Tensor(input_size).view(1, 1, -1)) + self.init_incremental_state() + + self.reset_parameters() + + def reset_parameters(self): + self.weight_linear.reset_parameters() + if self.has_conv_bias: + nn.init.constant_(self.conv_bias, 0.0) + + def forward( + self, + x, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + query: Optional[Tensor] = None, + ): + """Assuming the input, x, of the shape T x B x C and producing an output in the shape T x B x C + args: + x: Input of shape T x B x C, i.e. (timesteps, batch_size, input_size) + incremental_state: A dict to keep the state + unfold: unfold the input or not. If not, we use the matrix trick instead + query: use the specified query to predict the conv filters + """ + assert query is None or not self.in_proj + + if query is None: + query = x + + output = self._forward_unfolded(x, incremental_state, query) + + if self.has_conv_bias: + output = output + self.conv_bias + return output + + def _forward_unfolded( + self, + x, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + query, + ): + """The conventional implementation of convolutions. + Unfolding the input by having a window shifting to the right.""" + T, B, C = x.size() + K, H = self.kernel_size, self.num_heads + R = C // H + assert R * H == C == self.input_size + + TxBxH = T * B * H + + if self.in_proj: + proj = self.weight_linear(x) + x = proj.narrow(2, 0, self.input_size).contiguous() + weight = proj.narrow(2, self.input_size, H * K).contiguous().view(TxBxH, -1) + else: + weight = self.weight_linear(query).view(TxBxH, -1) + + # renorm_padding is only implemented in _forward_expanded + assert not self.renorm_padding or incremental_state is not None + + if incremental_state is not None: + input_buffer = self._get_input_buffer(incremental_state) + if input_buffer is not None: + x_unfold = torch.cat([input_buffer, x.unsqueeze(3)], dim=3) + else: + x_unfold = x.unsqueeze(3).clone() + if self.kernel_size > 1: + self._set_input_buffer( + incremental_state, x_unfold[:, :, :, -self.kernel_size + 1 :] + ) + x_unfold = x_unfold.view(TxBxH, R, -1) + else: + padding_l = self.padding_l + if K > T and padding_l == K - 1: + weight = weight.narrow(1, K - T, T) + K, padding_l = T, T - 1 + # unfold the input: T x B x C --> T' x B x C x K + x_unfold = unfold1d(x, K, padding_l, 0.0) + x_unfold = x_unfold.view(TxBxH, R, K) + + if self.weight_softmax and not self.renorm_padding: + weight = F.softmax(weight, dim=1) + weight = weight.narrow(1, 0, K) + + if incremental_state is not None: + weight = weight[:, -(x_unfold.size(2)) :] + K = weight.size(1) + + if self.weight_softmax and self.renorm_padding: + weight = F.softmax(weight, dim=1) + + weight = self.weight_dropout_module(weight, inplace=False) + + output = torch.bmm(x_unfold, weight.unsqueeze(2)) # T x B x H x R x 1 + output = output.view(T, B, C) + return output + + def reorder_incremental_state( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + new_order: Tensor, + ): + input_buffer = self._get_input_buffer(incremental_state) + if input_buffer is not None: + input_buffer = input_buffer.index_select(1, new_order) + self._set_input_buffer(incremental_state, input_buffer) + + def _get_input_buffer( + self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] + ): + result = self.get_incremental_state(incremental_state, "input_buffer") + if result is not None and "input_buffer" in result: + return result["input_buffer"] + else: + return None + + def _set_input_buffer( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + new_buffer: Optional[Tensor], + ): + return self.set_incremental_state( + incremental_state, "input_buffer", {"input_buffer": new_buffer} + ) + + def extra_repr(self): + s = "{}, kernel_size={}, padding_l={}, num_heads={}, weight_softmax={}, conv_bias={}, renorm_padding={}, in_proj={}".format( # noqa + self.input_size, + self.kernel_size, + self.padding_l, + self.num_heads, + self.weight_softmax, + self.conv_bias is not None, + self.renorm_padding, + self.in_proj, + ) + + if self.query_size != self.input_size: + s += ", query_size={}".format(self.query_size) + if self.weight_dropout_module.p > 0.0: + s += ", weight_dropout={}".format(self.weight_dropout_module.p) + return s diff --git a/fairseq/modules/unfold.py b/fairseq/modules/unfold.py index 138272f1ef..bbaafbd6bf 100644 --- a/fairseq/modules/unfold.py +++ b/fairseq/modules/unfold.py @@ -6,7 +6,7 @@ import torch.nn.functional as F -def unfold1d(x, kernel_size, padding_l, pad_value=0): +def unfold1d(x, kernel_size: int, padding_l: int, pad_value: float = 0): """unfold T x B x C to T x B x C x K""" if kernel_size > 1: T, B, C = x.size() From c20ba1fbe16568380e85fdeb69fd138ef22483e5 Mon Sep 17 00:00:00 2001 From: Mohsen <moslehpour@users.noreply.github.com> Date: Mon, 10 Oct 2022 18:47:43 -0700 Subject: [PATCH 694/774] make Multihead_attention scriptable (#4773) Co-authored-by: moslehpour <moslehpour@meta.com> --- fairseq/modules/multihead_attention.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 4314806010..1cf3abe945 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -20,9 +20,9 @@ _xformers_available = False from fairseq import utils -from fairseq.incremental_decoding_utils import with_incremental_state from fairseq.modules.fairseq_dropout import FairseqDropout from fairseq.modules.quant_noise import quant_noise +from fairseq.models.fairseq_incremental_decoder import FairseqIncrementalDecoder # TODO: move this into xformers? @@ -60,8 +60,7 @@ def _mask_for_xformers(mask: Tensor, to_dtype: Optional[torch.dtype] = None): return mask -@with_incremental_state -class MultiheadAttention(nn.Module): +class MultiheadAttention(FairseqIncrementalDecoder): """Multi-headed attention. See "Attention Is All You Need" for more details. @@ -79,6 +78,7 @@ def __init__( add_zero_attn=False, self_attention=False, encoder_decoder_attention=False, + dictionary=None, q_noise=0.0, qn_block_size=8, # TODO: pass in config rather than string. @@ -91,7 +91,7 @@ def __init__( int ] = 16, # This should be part of the config ): - super().__init__() + super().__init__(dictionary) xformers_att_config = utils.eval_str_dict(xformers_att_config) self.use_xformers = xformers_att_config is not None @@ -160,6 +160,7 @@ def __init__( self.onnx_trace = False self.skip_embed_dim_check = False + self.init_incremental_state() def prepare_for_onnx_export_(self): self.onnx_trace = True @@ -467,7 +468,7 @@ def split_heads(x): def forward( self, - query, + query: Tensor, key: Optional[Tensor], value: Optional[Tensor], key_padding_mask: Optional[Tensor] = None, @@ -739,6 +740,7 @@ def forward( attn_probs = self.dropout_module(attn_weights) assert v is not None + attn: Optional[Tensor] = None if self.encoder_decoder_attention and bsz != kv_bsz: attn = torch.einsum( "bxhts,bhsd->bxhtd", @@ -827,7 +829,7 @@ def _append_prev_key_padding_mask( @torch.jit.export def reorder_incremental_state( self, - incremental_state: Dict[str, Dict[str, Optional[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], new_order: Tensor, ): """Reorder buffered internal state (for incremental generation).""" @@ -868,7 +870,7 @@ def _get_input_buffer( def _set_input_buffer( self, - incremental_state: Dict[str, Dict[str, Optional[Tensor]]], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], buffer: Dict[str, Optional[Tensor]], ): return self.set_incremental_state(incremental_state, "attn_state", buffer) From 411d3650552f02a20c99d3101699f6aacc6e4d6f Mon Sep 17 00:00:00 2001 From: Mohsen <moslehpour@users.noreply.github.com> Date: Tue, 11 Oct 2022 14:44:20 -0700 Subject: [PATCH 695/774] make lightconv scriptable (#4775) make lightconv scriptable --- fairseq/models/lightconv.py | 272 +++++++++++++++++++++++++----------- 1 file changed, 193 insertions(+), 79 deletions(-) diff --git a/fairseq/models/lightconv.py b/fairseq/models/lightconv.py index 5f4f6d47a4..6dd99a860f 100644 --- a/fairseq/models/lightconv.py +++ b/fairseq/models/lightconv.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import math +from typing import Dict, List, Optional, Tuple import torch import torch.nn as nn @@ -19,7 +20,7 @@ ) from fairseq.modules import ( AdaptiveSoftmax, - DynamicConv, + DynamicConv_scripatable as DynamicConv, FairseqDropout, LayerNorm, LightweightConv, @@ -27,6 +28,7 @@ PositionalEmbedding, ) from fairseq.utils import safe_hasattr +from torch import Tensor @register_model("lightconv") @@ -308,6 +310,42 @@ def build_embedding(dictionary, embed_dim, path=None): decoder = LightConvDecoder(args, tgt_dict, decoder_embed_tokens) return LightConvModel(encoder, decoder) + def forward( + self, + src_tokens: Tensor, + prev_output_tokens: Tensor, + src_lengths: Optional[Tensor] = None, + ): + """ + (The forward method inherited from the base class has a **kwargs + argument in its input, which is not supported in torchscript. This + method overwrites the forward method definition without **kwargs.) + + Run the forward pass for an encoder-decoder model. + + First feed a batch of source tokens through the encoder. Then, feed the + encoder output and previous decoder outputs (i.e., teacher forcing) to + the decoder to produce the next outputs:: + + encoder_out = self.encoder(src_tokens, src_lengths) + return self.decoder(prev_output_tokens, encoder_out) + + Args: + src_tokens (LongTensor): tokens in the source language of shape + `(batch, src_len)` + src_lengths (LongTensor): source sentence lengths of shape `(batch)` + prev_output_tokens (LongTensor): previous decoder outputs of shape + `(batch, tgt_len)`, for teacher forcing + + Returns: + tuple: + - the decoder's output of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + encoder_out = self.encoder(src_tokens, src_lengths) + decoder_out = self.decoder(prev_output_tokens, encoder_out=encoder_out) + return decoder_out + class LightConvEncoder(FairseqEncoder): """ @@ -356,8 +394,12 @@ def __init__(self, args, dictionary, embed_tokens): self.normalize = args.encoder_normalize_before if self.normalize: self.layer_norm = LayerNorm(embed_dim) + else: + self.layer_norm = None - def forward(self, src_tokens, **unused): + def forward( + self, src_tokens: Tensor, src_lengths: Optional[Tensor] = None + ) -> Dict[str, List[Tensor]]: """ Args: src_tokens (LongTensor): tokens in the source language of shape @@ -380,23 +422,32 @@ def forward(self, src_tokens, **unused): x = x.transpose(0, 1) # compute padding mask - encoder_padding_mask = src_tokens.eq(self.padding_idx) + encoder_padding_mask = src_tokens.eq(self.padding_idx) # B x T if not encoder_padding_mask.any(): - encoder_padding_mask = None + encoder_mask = None + else: + encoder_mask = encoder_padding_mask # encoder layers for layer in self.layers: - x = layer(x, encoder_padding_mask) + x = layer(x, encoder_mask) - if self.normalize: + if self.layer_norm is not None: x = self.layer_norm(x) - return { - "encoder_out": x, # T x B x C - "encoder_padding_mask": encoder_padding_mask, # B x T - } + output_dict: Dict[str, List[Tensor]] = {} + if src_lengths is not None: + output_dict["src_lengths"] = [src_lengths] + output_dict["encoder_out"] = [x] # T x B x C + if encoder_mask is not None: + output_dict["encoder_padding_mask"] = [encoder_mask] # B x T + + return output_dict - def reorder_encoder_out(self, encoder_out, new_order): + @torch.jit.export + def reorder_encoder_out( + self, encoder_out: Dict[str, List[Tensor]], new_order: Tensor + ): """ Reorder encoder output according to *new_order*. @@ -407,15 +458,22 @@ def reorder_encoder_out(self, encoder_out, new_order): Returns: *encoder_out* rearranged according to *new_order* """ - if encoder_out["encoder_out"] is not None: - encoder_out["encoder_out"] = encoder_out["encoder_out"].index_select( - 1, new_order - ) - if encoder_out["encoder_padding_mask"] is not None: - encoder_out["encoder_padding_mask"] = encoder_out[ - "encoder_padding_mask" - ].index_select(0, new_order) - return encoder_out + if len(encoder_out["encoder_out"]) == 0: + encoder = [] + else: + encoder = [encoder_out["encoder_out"][0].index_select(1, new_order)] + output_dict = {"encoder_out": encoder} + + if ("encoder_padding_mask" not in encoder_out) or ( + len(encoder_out["encoder_padding_mask"]) == 0 + ): + encoder_padding_mask = [] + else: + encoder_padding_mask = [ + encoder_out["encoder_padding_mask"][0].index_select(0, new_order) + ] + output_dict["encoder_padding_mask"] = encoder_padding_mask + return output_dict def max_positions(self): """Maximum input length supported by the encoder.""" @@ -477,13 +535,17 @@ def __init__( self.layers.extend( [ LightConvDecoderLayer( - args, no_encoder_attn, kernel_size=args.decoder_kernel_size_list[i] + args, + no_encoder_attn, + kernel_size=args.decoder_kernel_size_list[i], + dictionary=dictionary, ) for i in range(args.decoder_layers) ] ) self.adaptive_softmax = None + self.output_projection = None self.project_out_dim = ( Linear(embed_dim, output_embed_dim, bias=False) @@ -501,18 +563,33 @@ def __init__( factor=args.adaptive_softmax_factor, tie_proj=args.tie_adaptive_proj, ) - elif not self.share_input_output_embed: - self.embed_out = nn.Parameter( - torch.Tensor(len(dictionary), output_embed_dim) + elif self.share_input_output_embed: + self.output_projection = nn.Linear( + self.embed_tokens.weight.shape[1], + self.embed_tokens.weight.shape[0], + bias=False, + ) + self.output_projection.weight = self.embed_tokens.weight + + else: + self.output_projection = nn.Linear( + output_embed_dim, len(dictionary), bias=False + ) + nn.init.normal_( + self.output_projection.weight, mean=0, std=output_embed_dim**-0.5 ) - nn.init.normal_(self.embed_out, mean=0, std=output_embed_dim**-0.5) self.register_buffer("version", torch.Tensor([2])) self.normalize = args.decoder_normalize_before and final_norm if self.normalize: self.layer_norm = LayerNorm(embed_dim) + else: + self.layer_norm = None def forward( - self, prev_output_tokens, encoder_out=None, incremental_state=None, **kwargs + self, + prev_output_tokens: Tensor, + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, ): """ Args: @@ -546,7 +623,7 @@ def forward( positions = positions[:, -1:] # embed tokens and positions - x = self.embed_scale * self.embed_tokens(prev_output_tokens) + x = self.embed_scale * self.embed_tokens(prev_output_tokens.contiguous()) if self.project_in_dim is not None: x = self.project_in_dim(x) @@ -559,21 +636,30 @@ def forward( x = x.transpose(0, 1) attn = None - inner_states = [x] + inner_states: List[Optional[Tensor]] = [x] # decoder layers + attn: Optional[Tensor] = None for layer in self.layers: + encoder: Optional[Tensor] = None + encoder_padding_mask: Optional[Tensor] = None + if encoder_out is not None: + if len(encoder_out["encoder_out"]) > 0: + encoder = encoder_out["encoder_out"][0] + if ( + "encoder_padding_mask" in encoder_out + and len(encoder_out["encoder_padding_mask"]) > 0 + ): + encoder_padding_mask = encoder_out["encoder_padding_mask"][0] x, attn = layer( x, - encoder_out["encoder_out"] if encoder_out is not None else None, - encoder_out["encoder_padding_mask"] - if encoder_out is not None - else None, + encoder, + encoder_padding_mask, incremental_state, ) inner_states.append(x) - if self.normalize: + if self.layer_norm is not None: x = self.layer_norm(x) # T x B x C -> B x T x C @@ -584,12 +670,9 @@ def forward( if self.adaptive_softmax is None: # project back to size of vocabulary - if self.share_input_output_embed: - x = F.linear(x, self.embed_tokens.weight) - else: - x = F.linear(x, self.embed_out) + x = self.output_projection(x) - return x, {"attn": attn, "inner_states": inner_states} + return x, {"attn": [attn], "inner_states": inner_states} def max_positions(self): """Maximum output length supported by the decoder.""" @@ -613,6 +696,14 @@ def buffered_future_mask(self, tensor): ) return self._future_mask[:dim, :dim] + def reorder_incremental_state( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + new_order: Tensor, + ): + for layer in self.layers: + layer.reorder_incremental_state(incremental_state, new_order) + class LightConvEncoderLayer(nn.Module): """Encoder layer block. @@ -672,9 +763,10 @@ def __init__(self, args, kernel_size=0): self.normalize_before = args.encoder_normalize_before self.fc1 = Linear(self.embed_dim, args.encoder_ffn_embed_dim) self.fc2 = Linear(args.encoder_ffn_embed_dim, self.embed_dim) - self.layer_norms = nn.ModuleList([LayerNorm(self.embed_dim) for _ in range(2)]) + self.layer_norm1 = LayerNorm(self.embed_dim) + self.layer_norm2 = LayerNorm(self.embed_dim) - def forward(self, x, encoder_padding_mask): + def forward(self, x, encoder_padding_mask: Optional[Tensor] = None) -> Tensor: """ Args: x (Tensor): input to the layer of shape `(seq_len, batch, embed_dim)` @@ -685,7 +777,9 @@ def forward(self, x, encoder_padding_mask): encoded output of shape `(batch, src_len, embed_dim)` """ residual = x - x = self.maybe_layer_norm(0, x, before=True) + normalize = self.maybe_layer_norm(before=True) + if normalize: + x = self.layer_norm1(x) x = self.input_dropout_module(x) x = self.linear1(x) if self.act is not None: @@ -696,24 +790,27 @@ def forward(self, x, encoder_padding_mask): x = self.linear2(x) x = self.dropout_module(x) x = residual + x - x = self.maybe_layer_norm(0, x, after=True) + normalize = self.maybe_layer_norm(after=True) + if normalize: + x = self.layer_norm1(x) residual = x - x = self.maybe_layer_norm(1, x, before=True) + normalize = self.maybe_layer_norm(before=True) + if normalize: + x = self.layer_norm2(x) x = F.relu(self.fc1(x)) x = self.relu_dropout_module(x) x = self.fc2(x) x = self.dropout_module(x) x = residual + x - x = self.maybe_layer_norm(1, x, after=True) + normalize = self.maybe_layer_norm(after=True) + if normalize: + x = self.layer_norm2(x) return x - def maybe_layer_norm(self, i, x, before=False, after=False): - assert before ^ after - if after ^ self.normalize_before: - return self.layer_norms[i](x) - else: - return x + def maybe_layer_norm(self, before: bool = False, after: bool = False): + assert before ^ after, "Incorrect arguments" + return after ^ self.normalize_before def extra_repr(self): return ( @@ -736,7 +833,7 @@ class LightConvDecoderLayer(nn.Module): kernel_size: kernel size of the convolution """ - def __init__(self, args, no_encoder_attn=False, kernel_size=0): + def __init__(self, args, no_encoder_attn=False, kernel_size=0, dictionary=None): super().__init__() self.embed_dim = args.decoder_embed_dim self.conv_dim = args.decoder_conv_dim @@ -790,6 +887,7 @@ def __init__(self, args, no_encoder_attn=False, kernel_size=0): args.decoder_attention_heads, dropout=args.attention_dropout, encoder_decoder_attention=True, + dictionary=dictionary, ) self.encoder_attn_layer_norm = LayerNorm(self.embed_dim) @@ -801,14 +899,14 @@ def __init__(self, args, no_encoder_attn=False, kernel_size=0): def forward( self, - x, - encoder_out, - encoder_padding_mask, - incremental_state, - prev_conv_state=None, - prev_attn_state=None, - conv_mask=None, - conv_padding_mask=None, + x: Tensor, + encoder_out: Optional[Tensor], + encoder_padding_mask: Optional[Tensor], + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + prev_conv_state: Optional[Tensor] = None, + prev_attn_state: Optional[Tuple[Tensor, Tensor]] = None, + conv_mask: Optional[Tensor] = None, + conv_padding_mask: Optional[Tensor] = None, ): """ Args: @@ -820,10 +918,10 @@ def forward( encoded output of shape `(batch, src_len, embed_dim)` """ residual = x - x = self.maybe_layer_norm(self.conv_layer_norm, x, before=True) + normalize = self.maybe_layer_norm(before=True) + if normalize: + x = self.conv_layer_norm(x) if prev_conv_state is not None: - if incremental_state is None: - incremental_state = {} self.conv._set_input_buffer(incremental_state, prev_conv_state) x = self.input_dropout_module(x) x = self.linear1(x) @@ -833,17 +931,22 @@ def forward( x = self.linear2(x) x = self.dropout_module(x) x = residual + x - x = self.maybe_layer_norm(self.conv_layer_norm, x, after=True) + normalize = self.maybe_layer_norm(after=True) + if normalize: + x = self.conv_layer_norm(x) - attn = None + attn: Optional[Tensor] = None if self.encoder_attn is not None: residual = x - x = self.maybe_layer_norm(self.encoder_attn_layer_norm, x, before=True) + normalize = self.maybe_layer_norm(before=True) + if normalize: + x = self.encoder_attn_layer_norm(x) + if prev_attn_state is not None: - if incremental_state is None: - incremental_state = {} - prev_key, prev_value = prev_attn_state - saved_state = {"prev_key": prev_key, "prev_value": prev_value} + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_attn_state[0], + "prev_value": prev_attn_state[1], + } self.encoder_attn._set_input_buffer(incremental_state, saved_state) x, attn = self.encoder_attn( query=x, @@ -856,28 +959,39 @@ def forward( ) x = self.dropout_module(x) x = residual + x - x = self.maybe_layer_norm(self.encoder_attn_layer_norm, x, after=True) + normalize = self.maybe_layer_norm(after=True) + if normalize: + x = self.encoder_attn_layer_norm(x) residual = x - x = self.maybe_layer_norm(self.final_layer_norm, x, before=True) + normalize = self.maybe_layer_norm(before=True) + if normalize: + x = self.final_layer_norm(x) x = F.relu(self.fc1(x)) x = self.relu_dropout_module(x) x = self.fc2(x) x = self.dropout_module(x) x = residual + x - x = self.maybe_layer_norm(self.final_layer_norm, x, after=True) + normalize = self.maybe_layer_norm(after=True) + if normalize: + x = self.final_layer_norm(x) return x, attn - def maybe_layer_norm(self, layer_norm, x, before=False, after=False): - assert before ^ after - if after ^ self.normalize_before: - return layer_norm(x) - else: - return x + def maybe_layer_norm(self, before: bool = False, after: bool = False): + assert before ^ after, "Incorrect usage" + return after ^ self.normalize_before - def make_generation_fast_(self, need_attn=False, **kwargs): + def make_generation_fast_(self, need_attn: bool = False, **kwargs): self.need_attn = need_attn + def reorder_incremental_state( + self, + incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], + new_order: Tensor, + ): + self.encoder_attn.reorder_incremental_state(incremental_state, new_order) + self.conv.reorder_incremental_state(incremental_state, new_order) + def extra_repr(self): return ( "dropout={}, relu_dropout={}, input_dropout={}, normalize_before={}".format( From 16538a0bff1b9f32e89aa915f2e8b57193f33109 Mon Sep 17 00:00:00 2001 From: Mohsen <moslehpour@users.noreply.github.com> Date: Tue, 11 Oct 2022 23:28:08 -0700 Subject: [PATCH 696/774] fix dynamicconv test (#4779) fix broken tests after merging #4775 --- fairseq/models/lightconv.py | 21 +++------------------ fairseq/modules/dynamic_convolution.py | 5 ++++- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/fairseq/models/lightconv.py b/fairseq/models/lightconv.py index 6dd99a860f..7950280e30 100644 --- a/fairseq/models/lightconv.py +++ b/fairseq/models/lightconv.py @@ -4,7 +4,7 @@ # LICENSE file in the root directory of this source tree. import math -from typing import Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple import torch import torch.nn as nn @@ -313,8 +313,8 @@ def build_embedding(dictionary, embed_dim, path=None): def forward( self, src_tokens: Tensor, + src_lengths: Tensor, prev_output_tokens: Tensor, - src_lengths: Optional[Tensor] = None, ): """ (The forward method inherited from the base class has a **kwargs @@ -590,6 +590,7 @@ def forward( prev_output_tokens: Tensor, encoder_out: Optional[Dict[str, List[Tensor]]] = None, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None, + src_lengths: Optional[Any] = None, ): """ Args: @@ -696,14 +697,6 @@ def buffered_future_mask(self, tensor): ) return self._future_mask[:dim, :dim] - def reorder_incremental_state( - self, - incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], - new_order: Tensor, - ): - for layer in self.layers: - layer.reorder_incremental_state(incremental_state, new_order) - class LightConvEncoderLayer(nn.Module): """Encoder layer block. @@ -984,14 +977,6 @@ def maybe_layer_norm(self, before: bool = False, after: bool = False): def make_generation_fast_(self, need_attn: bool = False, **kwargs): self.need_attn = need_attn - def reorder_incremental_state( - self, - incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], - new_order: Tensor, - ): - self.encoder_attn.reorder_incremental_state(incremental_state, new_order) - self.conv.reorder_incremental_state(incremental_state, new_order) - def extra_repr(self): return ( "dropout={}, relu_dropout={}, input_dropout={}, normalize_before={}".format( diff --git a/fairseq/modules/dynamic_convolution.py b/fairseq/modules/dynamic_convolution.py index 49778a5b1b..0ff02cd62a 100644 --- a/fairseq/modules/dynamic_convolution.py +++ b/fairseq/modules/dynamic_convolution.py @@ -500,9 +500,12 @@ def _set_input_buffer( incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]], new_buffer: Optional[Tensor], ): - return self.set_incremental_state( + result = self.set_incremental_state( incremental_state, "input_buffer", {"input_buffer": new_buffer} ) + if result is not None: + incremental_state = result + return incremental_state def extra_repr(self): s = "{}, kernel_size={}, padding_l={}, num_heads={}, weight_softmax={}, conv_bias={}, renorm_padding={}, in_proj={}".format( # noqa From 8df77ea9b8cd4c4fff987ddf4c365834d999ee1b Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 13:39:47 -0400 Subject: [PATCH 697/774] Fix error in workflow (#4790) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 60934fcee7..b0b2105361 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -86,7 +86,7 @@ jobs: - name: Create Source Distribution run: | - pip install setuptools wheel twine + python3 -m pip install setuptools wheel twine torch python3 setup.py sdist - uses: actions/upload-artifact@v2 From 2727d17affed128778ea66020c443557b0783380 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 13:56:58 -0400 Subject: [PATCH 698/774] Remove support for cpython 3.6 (#4791) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b0b2105361..61c22f8fec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -123,7 +123,7 @@ jobs: run: | python3 -m cibuildwheel --output-dir dist env: - CIBW_BUILD: "cp36-*64 cp37-*64 cp38-*64" + CIBW_BUILD: "cp37-*64 cp38-*64" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library From 144e7c5157f7d5f94340503525c6db01d12e0bf7 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 14:11:54 -0400 Subject: [PATCH 699/774] Remove cpython support as well (#4792) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 61c22f8fec..00a4ab9d9e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -123,7 +123,7 @@ jobs: run: | python3 -m cibuildwheel --output-dir dist env: - CIBW_BUILD: "cp37-*64 cp38-*64" + CIBW_BUILD: "cp38-*64" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library From 8adff217f0faa8b187cdef4e609e4fc05fb02cd5 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 17:24:56 -0400 Subject: [PATCH 700/774] Update release.yml (#4793) Add print statement, add cpython versions --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00a4ab9d9e..2aea1d3705 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -87,6 +87,7 @@ jobs: - name: Create Source Distribution run: | python3 -m pip install setuptools wheel twine torch + python3 -c "import torch; print(f'torch version: {torch.__version__}'): python3 setup.py sdist - uses: actions/upload-artifact@v2 @@ -123,7 +124,7 @@ jobs: run: | python3 -m cibuildwheel --output-dir dist env: - CIBW_BUILD: "cp38-*64" + CIBW_BUILD: "cp38-*64 cp39-*64 cp310-*64" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library From d55ac5d13a26eadaccf86c2553e1d7f7df1dd56e Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 17:25:28 -0400 Subject: [PATCH 701/774] Lower required numpy (#4794) --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ace36e980a..8a9b2f9770 100644 --- a/setup.py +++ b/setup.py @@ -181,7 +181,7 @@ def do_setup(package_data): "cython", "hydra-core>=1.0.7,<1.1", "omegaconf<2.1", - "numpy>=1.23.3", + "numpy>=1.21.3", "regex", "sacrebleu>=1.4.12", "torch>=1.10", From 4fa4e1f1184a59b1259840fc700e138844f61a33 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 20:55:06 -0400 Subject: [PATCH 702/774] Revert "Update release.yml (#4793)" (#4795) This reverts commit 8adff217f0faa8b187cdef4e609e4fc05fb02cd5. --- .github/workflows/release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2aea1d3705..00a4ab9d9e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -87,7 +87,6 @@ jobs: - name: Create Source Distribution run: | python3 -m pip install setuptools wheel twine torch - python3 -c "import torch; print(f'torch version: {torch.__version__}'): python3 setup.py sdist - uses: actions/upload-artifact@v2 @@ -124,7 +123,7 @@ jobs: run: | python3 -m cibuildwheel --output-dir dist env: - CIBW_BUILD: "cp38-*64 cp39-*64 cp310-*64" + CIBW_BUILD: "cp38-*64" CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library From e40c4352663ce040ecd980e7ca4912dc85cb1dce Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:27:22 -0400 Subject: [PATCH 703/774] Update release.yml (#4796) --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00a4ab9d9e..5f0b087d8f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,7 +128,6 @@ jobs: CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library CIBW_BEFORE_BUILD_LINUX: yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true - CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" CIBW_SKIP: "*musllinux*" - uses: actions/upload-artifact@v2 From fdcfd7914771cc48100d85bcd265b3540be518e7 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:37:53 -0400 Subject: [PATCH 704/774] Revert "Update release.yml (#4796)" (#4797) This reverts commit e40c4352663ce040ecd980e7ca4912dc85cb1dce. --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5f0b087d8f..00a4ab9d9e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,6 +128,7 @@ jobs: CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library CIBW_BEFORE_BUILD_LINUX: yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true + CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" CIBW_SKIP: "*musllinux*" - uses: actions/upload-artifact@v2 From b7b7928065ec90bef8f9a489b0128a4dce560d57 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Fri, 14 Oct 2022 21:40:11 -0400 Subject: [PATCH 705/774] Lower numpy version requirement (#4798) --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f4cb74ba1d..4d84c9bc36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = [ "setuptools>=18.0", "wheel", "cython", - "numpy>=1.23.3", + "numpy>=1.21.3", "torch>=1.10", ] build-backend = "setuptools.build_meta" From f3429391b188430e6e50c28c17cf60d4e32fdb0e Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Mon, 17 Oct 2022 11:59:36 -0400 Subject: [PATCH 706/774] Fix GLIBC 2.14 not found error (#4802) * Fix GLIBC 2.14 not found error * Update release.yml --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00a4ab9d9e..e30afc242b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -127,7 +127,7 @@ jobs: CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library - CIBW_BEFORE_BUILD_LINUX: yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true + CIBW_BEFORE_BUILD_LINUX: (yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true) && (apt-get update && apt-get install -y libc6) CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" CIBW_SKIP: "*musllinux*" From 66d713b4d07ef1bcf09d89329c314f6b6059254f Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:24:58 -0400 Subject: [PATCH 707/774] Update release.yml (#4804) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e30afc242b..241b74b32d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -127,7 +127,7 @@ jobs: CIBW_MANYLINUX_X86_64_IMAGE: manylinux1 CIBW_BEFORE_BUILD: git submodule update --init --recursive && pip install . # Install system library - CIBW_BEFORE_BUILD_LINUX: (yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true) && (apt-get update && apt-get install -y libc6) + CIBW_BEFORE_BUILD_LINUX: (yum install -y libffi-devel || apt-get install -y libffi-devel || apk add --update --no-cache libffi-devel || true) && (yum install -y libc6 || apt-get install -y libc6 || apk add --update --no-cache libc6 || true) CIBW_ENVIRONMENT: "PIP_ONLY_BINARY=numpy" CIBW_SKIP: "*musllinux*" From 05625e3e6e660909e4df833de1f7b49019496a68 Mon Sep 17 00:00:00 2001 From: Mohsen <moslehpour@users.noreply.github.com> Date: Mon, 17 Oct 2022 13:04:51 -0700 Subject: [PATCH 708/774] fix #4708 (#4805) Co-authored-by: moslehpour <moslehpour@meta.com> --- fairseq/modules/sinusoidal_positional_embedding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/modules/sinusoidal_positional_embedding.py b/fairseq/modules/sinusoidal_positional_embedding.py index 5889e08d8b..5f5c9859dc 100644 --- a/fairseq/modules/sinusoidal_positional_embedding.py +++ b/fairseq/modules/sinusoidal_positional_embedding.py @@ -97,7 +97,7 @@ def forward( if self.onnx_trace: flat_embeddings = self.weights.detach().index_select(0, positions.view(-1)) embedding_shape = torch.cat( - (bsz.view(1), seq_len.view(1), torch.tensor([-1], dtype=torch.long)) + (bsz, seq_len, torch.tensor([-1], dtype=torch.long)) ) embeddings = torch.onnx.operators.reshape_from_tensor_shape( flat_embeddings, embedding_shape From 7a71b8460a5cf5a8dc09f56867ac35984c799ed8 Mon Sep 17 00:00:00 2001 From: Mohsen <moslehpour@users.noreply.github.com> Date: Mon, 17 Oct 2022 17:45:58 -0700 Subject: [PATCH 709/774] Revert changes to sinusoidal_positional_embedding.py (#4808) * Revert #4805 and #4708 --- fairseq/modules/sinusoidal_positional_embedding.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fairseq/modules/sinusoidal_positional_embedding.py b/fairseq/modules/sinusoidal_positional_embedding.py index 5f5c9859dc..4793ecfb52 100644 --- a/fairseq/modules/sinusoidal_positional_embedding.py +++ b/fairseq/modules/sinusoidal_positional_embedding.py @@ -65,12 +65,7 @@ def forward( positions: Optional[Any] = None, ): """Input is expected to be of size [bsz x seqlen].""" - if torch.jit.is_scripting(): - bspair = torch.onnx.operators.shape_as_tensor(input) - elif torch.onnx.is_in_onnx_export(): - bspair = torch.onnx.operators.shape_as_tensor(input) - else: - bspair = input.size() + bspair = torch.onnx.operators.shape_as_tensor(input) bsz, seq_len = bspair[0], bspair[1] max_pos = self.padding_idx + 1 + seq_len if self.weights is None or max_pos > self.weights.size(0): @@ -97,7 +92,7 @@ def forward( if self.onnx_trace: flat_embeddings = self.weights.detach().index_select(0, positions.view(-1)) embedding_shape = torch.cat( - (bsz, seq_len, torch.tensor([-1], dtype=torch.long)) + (bsz.view(1), seq_len.view(1), torch.tensor([-1], dtype=torch.long)) ) embeddings = torch.onnx.operators.reshape_from_tensor_shape( flat_embeddings, embedding_shape From f2fefe457240dd1a78bc29e0be699890cea6aae4 Mon Sep 17 00:00:00 2001 From: Andros Tjandra <38714605+androstj@users.noreply.github.com> Date: Tue, 18 Oct 2022 13:54:23 -0400 Subject: [PATCH 710/774] Update README.md (#4809) Add LID inference documentation. --- examples/wav2vec/xlsr/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/examples/wav2vec/xlsr/README.md b/examples/wav2vec/xlsr/README.md index 84e9de36a6..e0a7c4ef3f 100644 --- a/examples/wav2vec/xlsr/README.md +++ b/examples/wav2vec/xlsr/README.md @@ -49,7 +49,34 @@ MLS 10h | 20000 For finetuning the 2B model, we make some additional changes for `finetune.yaml` . We use the fully_sharded `distributed_training.ddp_backend` provided by the [fairscale](https://github.com/facebookresearch/fairscale) library and and set `model.activation_checkpoint` to true. We also increase `dataset.max_tokens` to 2560000 and use a total effective batch size of 2560000*24. We sweep for the best `optimization.lr` within the interval [3e−6,3e−5] using dev error rate. For common voice dataset, we pick the `model.mask_prob` for different languages among {0.30, 0.40} based on best dev error rate. +## LID Inference +Model | Link +|------|------ +XLS-R 300M + ft Voxlingua107 | [download](https://dl.fbaipublicfiles.com/fairseq/wav2vec/xlsr_300m_voxlingua107_ft.pt) + +How to run inference & calculate accuracy (step-by-step): +1. Download the Voxlingua107 checkpoint from the table above. +1. Use this python script to extract logit/embedding from the XLSR model: https://github.com/fairinternal/fairseq-py/blob/xlsr2/examples/wav2vec/gen_audio_embedding.py +```shell command +CUDA_VISIBLE_DEVICES=0 PYTHONPATH=. python3 examples/wav2vec/gen_audio_embedding.py \ + /fsx/data/VoxLingua107/manifest --path "/path/to/checkpoint.pt" \ + --task audio_classification --batch-size 90 --gen-subset test \ + --infer-manifest /fsx/data/VoxLingua107/manifest/test.tsv \ + --infer-xtimes 10 --infer-max-sample-size 160000 --output-path /tmp/tmp_voxling_infer.npz +``` + +2. Calculate the overall accuracy, 0-5 seconds and 5-20 seconds: +```shell command +PYTHONPATH='.' python examples/wav2vec/eval_speaker_clf_task.py \ + --task cls --merge mean_logit --data /tmp/tmp_voxling_infer.npz + +Output: +| run classification evaluation +| acc = 94.34% -- err = 5.66% -- correct=1518 total=1609 +| acc 0to5 = 90.91% -- err = 9.09% -- c_5=230.0 t_5=253 +| acc 5to20 = 94.99% -- err = 5.01% -- c_20=1288.0 t_20=1356 +``` ## Citation From 0272196aa803ecc94a8bffa6132a8c64fd7de286 Mon Sep 17 00:00:00 2001 From: Andros Tjandra <38714605+androstj@users.noreply.github.com> Date: Tue, 18 Oct 2022 16:25:27 -0400 Subject: [PATCH 711/774] Add LID generate & eval script (#4810) Co-authored-by: Andros Tjandra <androstj@meta.com> --- .../xlsr/scripts/eval_speaker_clf_task.py | 173 ++++++++++++++ .../xlsr/scripts/gen_audio_embedding.py | 222 ++++++++++++++++++ 2 files changed, 395 insertions(+) create mode 100644 examples/wav2vec/xlsr/scripts/eval_speaker_clf_task.py create mode 100644 examples/wav2vec/xlsr/scripts/gen_audio_embedding.py diff --git a/examples/wav2vec/xlsr/scripts/eval_speaker_clf_task.py b/examples/wav2vec/xlsr/scripts/eval_speaker_clf_task.py new file mode 100644 index 0000000000..16d07516f8 --- /dev/null +++ b/examples/wav2vec/xlsr/scripts/eval_speaker_clf_task.py @@ -0,0 +1,173 @@ +""" +Usage: + This scripts it to evaluate the classification accuracy/error rate from the embedding extracted + by gen_audio_embedding.py + Example (LID classification) + + PYTHONPATH='.' python examples/wav2vec/eval_speaker_clf_task.py \ + --data /fsx/androstj/exps/lid_voxlingua/infer/atj_xlsr2_100pct_300M_mean_fast_upd_100k_new.npz \ + --task cls --merge mean_logit +""" +import numpy as np +import sklearn +from sklearn.metrics.pairwise import cosine_similarity +from sklearn.preprocessing import StandardScaler +from tqdm import tqdm +import ipdb +import logging +import argparse +from scipy.special import softmax + +log=logging.getLogger(__name__) +log.setLevel(logging.INFO) + +def calculate_eer(y_label, y_score): + # y denotes groundtruth scores, + # y_score denotes the prediction scores. + from scipy.optimize import brentq + from sklearn.metrics import roc_curve + from scipy.interpolate import interp1d + + fpr, tpr, thresholds = roc_curve(y_label, y_score, pos_label=1) + eer = brentq(lambda x : 1. - x - interp1d(fpr, tpr)(x), 0., 1.) + optimal_threshold = interp1d(fpr, thresholds)(eer) + return eer, optimal_threshold + +def calculate_minDCF(y_label, y_score, p_target=0.01, c_miss=1, c_fa=1): + # https://github.com/kaldi-asr/kaldi/blob/master/egs/sre08/v1/sid/compute_min_dcf.py + from sklearn.metrics import det_curve + fpr, fnr, thresholds = det_curve(y_label, y_score, pos_label=1) + min_c_det = float("inf") + min_c_det_threshold = thresholds[0] + for i in range(0, len(fpr)): + # See Equation (2). it is a weighted sum of false negative + # and false positive errors. + c_det = c_miss * fnr[i] * p_target + c_fa * fpr[i] * (1 - p_target) + if c_det < min_c_det: + min_c_det = c_det + min_c_det_threshold = thresholds[i] + # See Equations (3) and (4). Now we normalize the cost. + c_def = min(c_miss * p_target, c_fa * (1 - p_target)) + min_dcf = min_c_det / c_def + return min_dcf, min_c_det_threshold + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--data', help='npz contains name & latent file') + parser.add_argument('--task', choices=['cls', 'veri', 'cls_voxlingua']) + parser.add_argument('--merge', choices=['mean_logit', 'first_logit', 'mean_latent_sim', 'first_latent_sim', 'mean_logit_sim', 'first_logit_sim']) + parser.add_argument('--veri-pair', help='verification file contains 1/0 utt_x utt_y') + parser.add_argument('--scaler', type=str, choices=['mean_var']) + parser.add_argument('--compress-method', choices=['pca']) + parser.add_argument('--compress-dim', type=int) + args = parser.parse_args() + + if args.task in ['cls', 'cls_voxlingua']: + print('| run classification evaluation') + data = np.load(args.data) + data_logit = data['logit'] + data_target = data['target'] + data_src_len = data['src_len'] + assert data_logit.shape[0] == data_target.shape[0] + B = data_logit.shape[0] + correct = 0 + total = 0 + data_prob = softmax(data_logit, axis=2) + correct_vs_len = np.empty((B, 2)) + for ii in range(B): + _target = data_target[ii] + if args.merge == 'mean_logit': + _prob = np.mean(data_prob[ii], axis=0) + top_1 = np.argmax(_prob) + elif args.merge == 'first_logit': + _prob = data_prob[ii][0] + top_1 = np.argmax(_prob) + else : + raise ValueError() + is_top_1 = (1 if top_1 == _target else 0) + correct += is_top_1 + total += 1 + _src_len = data_src_len[ii] / 16000 + correct_vs_len[ii] = [is_top_1, _src_len] + + acc = correct / total * 100 + t_5 = correct_vs_len[:, 1] <= 5 + t_20 = correct_vs_len[:, 1] > 5 + c_5 = correct_vs_len[t_5, 0].sum() + c_20 = correct_vs_len[t_20, 0].sum() + t_5 = t_5.sum() + t_20 = t_20.sum() + acc_5 = c_5 / t_5 * 100 + acc_20 = c_20 / t_20 * 100 + print(f'| acc = {acc:.2f}% -- err = {100-acc:.2f}% -- {correct=} {total=}') + print(f'| acc 0to5 = {acc_5:.2f}% -- err = {100-acc_5:.2f}% -- {c_5=} {t_5=}') + print(f'| acc 5to20 = {acc_20:.2f}% -- err = {100-acc_20:.2f}% -- {c_20=} {t_20=}') + + + + if args.task == 'veri': + print('| run verification evaluation') + veri_pairs = [] + with open(args.veri_pair) as ff: + for fi in ff: + a,b,c = fi.split() + a = int(a) + veri_pairs.append([a,b,c]) + + data = np.load(args.data) + if 'logit' in args.merge: + data_latent = data['logit'] + elif 'latent' in args.merge: + data_latent = data['latent'] + else : + raise ValueError() + + data_name = data['name'] + assert len(data_name) == len(data_latent) + map_name_latent = {} + + from sklearn.pipeline import make_pipeline + pipe = [] + if args.scaler == 'mean_var': + print(f'| apply StandardScaler') + pipe.append(StandardScaler()) + + if args.compress_method == 'pca': + n_comp = args.compress_dim + print(f'| apply PCA with {n_comp=}') + from sklearn.decomposition import PCA + pipe.append(PCA(n_components=n_comp)) + if len(pipe) > 0 : + pipe = make_pipeline(*pipe) + data_latent_2d = data_latent.reshape(-1, data_latent.shape[-1]) + pipe.fit(data_latent_2d) + data_latent_2d = pipe.transform(data_latent_2d) + data_latent = data_latent_2d.reshape(data_latent.shape[0], data_latent.shape[1], -1) + + for ii in range(len(data_name)): + map_name_latent[data_name[ii]] = data_latent[ii] + labels = [] + scores = [] + for lbl, pair_a, pair_b in tqdm(veri_pairs): + labels.append(lbl) + pair_a = map_name_latent[pair_a] + pair_b = map_name_latent[pair_b] + assert pair_a.ndim == pair_b.ndim == 2 + score = cosine_similarity(pair_a, pair_b) + if args.merge.startswith('mean'): + score = np.mean(score) + elif args.merge.startswith('first'): + score = score[0, 0] + else : + raise ValueError() + scores.append(score) + labels = np.array(labels) + scores = np.array(scores) + eer, eer_threshold = calculate_eer(labels, scores) + minDCF, minDCF_threshold = calculate_minDCF(labels, scores) + print('='*40) + print(f'| EER = {eer*100:.2f}%\tthreshold = {eer_threshold:.2f}') + print(f'| minDCF = {minDCF:.2f}\tthreshold = {minDCF_threshold:.2f}') + + diff --git a/examples/wav2vec/xlsr/scripts/gen_audio_embedding.py b/examples/wav2vec/xlsr/scripts/gen_audio_embedding.py new file mode 100644 index 0000000000..e5de1d5efd --- /dev/null +++ b/examples/wav2vec/xlsr/scripts/gen_audio_embedding.py @@ -0,0 +1,222 @@ +""" +Usage: + This script is used to extract the embedding / logit for speech classification task. + 1. Set fdir into your model checkpoint directory + 2. Run the following command (preferrably on GPU machine to speed up the inference process) + + CUDA_VISIBLE_DEVICES=0 python3 examples/wav2vec/gen_audio_embedding.py /fsx/data/VoxLingua107/manifest --path ${fdir} \ + --task audio_classification --batch-size 90 --gen-subset test \ + --infer-manifest /fsx/data/VoxLingua107/manifest/test.tsv \ + --infer-xtimes 10 --infer-max-sample-size 160000 --output-path $odir + + Example: + Case: LID logit extraction + fdir='/fsx/androstj/exps/voxlingua_lid_train_all/ckpt_100pct_300m_voxling-act_linear-pool_mean_fast-lr_1e-4-phase_0.1_0.4_0.5-maxupd_100000-ufreq_1-mprob_0.5-fz_0-cr_softmax/0/checkpoints/checkpoint_best.pt' + python3 examples/wav2vec/gen_audio_embedding.py /fsx/data/VoxLingua107/manifest --path ${fdir} \ + --task audio_classification --batch-size 90 --gen-subset test \ + --infer-manifest /fsx/data/VoxLingua107/manifest/test.tsv \ + --infer-xtimes 10 --infer-max-sample-size 160000 --output-path $odir + +""" +import torch +from fairseq import checkpoint_utils, distributed_utils, options, utils +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.logging import metrics, progress_bar +from fairseq import checkpoint_utils, data, options, tasks +from fairseq.data import FileAudioDataset, AddTargetDataset, Dictionary +from fairseq.tasks.audio_classification import LabelEncoder +import ipdb +import copy +import sys +from tqdm import tqdm +import tempfile +import numpy as np +import sklearn + +def subset_manifest(infer_manifest, veri_pair): + with open(infer_manifest) as ff, open(veri_pair) as gg, \ + tempfile.NamedTemporaryFile('w', delete=False) as ww: + fnames = ff.read().strip().split("\n") + basedir = fnames[0] + needed_fname = [] + for gi in gg.read().strip().split('\n'): + _, x1, x2 = gi.split() + needed_fname.append(x1) + needed_fname.append(x2) + needed_fname = set(needed_fname) + + ww.write(basedir+'\n') + for ii in range(1, len(fnames)): + x1,x2 = fnames[ii].split() + if x1 in needed_fname: + ww.write(fnames[ii]+'\n') + print(f'| subset manifest for verification: {ww.name}') + return ww.name + +def wrap_target_dataset(infer_manifest, dataset, task): + label_path = infer_manifest.replace(".tsv", ".label") + with open(label_path, "r") as f: + labels = f.read().strip().split("\n") + assert len(labels) == len(dataset) + process_label = LabelEncoder(task.target_dictionary) + dataset = AddTargetDataset(dataset, labels, + pad=task.target_dictionary.pad(), + eos=task.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + add_to_input=False) + return dataset + +def resample_data(source, padding_mask, n_sample, max_sample_len): + # source: BxT + # padding_mask: BxT + B = source.shape[0] + T = source.shape[1] + sources = [] + padding_masks = [] + seq_len = (~padding_mask).sum(1) + for jj in range(n_sample): + new_source = source.new_zeros(B, max_sample_len) + new_padding_mask = padding_mask.new_zeros(B, max_sample_len) + for ii in range(B): + if seq_len[ii] > max_sample_len: + start = np.random.randint(0, seq_len[ii]-max_sample_len+1) + end = start + max_sample_len + else : + start = 0 + end = seq_len[ii] + new_source[ii, 0:end-start] = source[ii, start:end] + new_padding_mask[ii, end-start+1:] = True + sources.append(new_source) + padding_masks.append(new_padding_mask) + return sources, padding_masks + +def resample_sample(sample, n_sample, max_sample_len): + new_sources, new_padding_masks = resample_data(sample['net_input']['source'], sample['net_input']['padding_mask'], n_sample, max_sample_len) + new_samples = [] + for ii in range(n_sample): + new_sample = copy.deepcopy(sample) + new_sample['net_input']['source'] = new_sources[ii] + new_sample['net_input']['padding_mask'] = new_padding_masks[ii] + new_samples.append(new_sample) + return new_samples + +if __name__ == '__main__': + np.random.seed(123) + # Parse command-line arguments for generation + parser = options.get_generation_parser(default_task='audio_classification') + # parser.add_argument('--infer-merge', type=str, default='mean') + parser.add_argument('--infer-xtimes', type=int, default=1) + parser.add_argument('--infer-max-sample-size', type=int, default=5*16000) # 5 secs + parser.add_argument('--infer-manifest', type=str) + parser.add_argument('--verification-pair', type=str, required=False, + help=''' + a file that contains pairs of utts to evaluated if they are from same speaker or not + format: (following voxceleb) + 1/0 <wav_pair_a> <wav_pair_b> + ''') + parser.add_argument('--output-path', type=str) + # parser.add_argument('--infer-xtimes', type=int, default=1) + + args = options.parse_args_and_arch(parser) + # Setup task + # task = tasks.setup_task(args) + use_cuda = not args.cpu + + # Load model & task + print('| loading model from {}'.format(args.path)) + arg_overrides = { + 'data': args.data, + # 'mask_prob': 0 + #'max_sample_size': sys.maxsize, + #'min_sample_size': 0, + } + state = checkpoint_utils.load_checkpoint_to_cpu(args.path) + # move to AWS + state['cfg']['model']['w2v_path'] = state['cfg']['model']['w2v_path'].replace('/checkpoint/arbabu/XLSR2/model_versions/', '/fsx/data/model_versions/').replace('/checkpoint/kushall/final_model_checkpoints/wav2vec2/', '/fsx/data/wav2vec_ckpt/') + state['cfg']['task']['data'] = state['cfg']['task']['data'].replace('/checkpoint/kushall/data/', '/fsx/data/') + + models, _model_args, task = checkpoint_utils.load_model_ensemble_and_task([args.path], + arg_overrides=arg_overrides, + task=None, + state=state) + model = models[0] + model.eval() + if use_cuda: + model.cuda() + + + # Load dataset + task.load_dataset(args.gen_subset) + dataset = task.dataset(args.gen_subset) + infer_manifest = args.infer_manifest + # only decode needed utts + # infer_manifest = subset_manifest(infer_manifest, + # args.verification_pair) + infer_dataset = FileAudioDataset(infer_manifest, + sample_rate=task.cfg.sample_rate, + max_sample_size=10**10, #task.cfg.max_sample_size, + min_sample_size=1, #task.cfg.min_sample_size, + pad=True, + normalize=task.cfg.normalize) + # add target (if needed) + infer_dataset = wrap_target_dataset(infer_manifest, infer_dataset, task) + itr = task.get_batch_iterator( + dataset=infer_dataset, + max_sentences=args.batch_size, + ).next_epoch_itr(shuffle=False) + + + # correct = 0 + # total = 0 + list_uttname = [] + list_latent = [] + list_logit = [] + list_target = [] + list_src_len = [] + with torch.no_grad(): + for _, sample in tqdm(enumerate(itr)): + # resample if needed + samples = resample_sample(sample, args.infer_xtimes, args.infer_max_sample_size) + list_uttname.extend(sample['name']) + list_target.extend(sample['target'][:, 0].cpu().numpy()) + list_src_len.extend((~sample['net_input']['padding_mask']).sum(1).cpu().numpy()) + latents = [] + logits = [] + for sample in samples: + sample = utils.move_to_cuda(sample) if use_cuda else sample + try: + latent = model.forward_latent(**sample['net_input']) + latents.append(latent.detach().cpu().numpy()) + except: + latent = None + logit = model.forward(**sample['net_input']) + logits.append(logit.detach().cpu().numpy()) + + if len(latents) > 0: + latents = np.stack(latents, 1) # B,X,D + logits = np.stack(logits, 1) # B,X,Cls + list_latent.extend(latents) + list_logit.extend(logits) + + # create big npz + list_uttname = np.array(list_uttname) + list_latent = np.array(list_latent) + list_target = np.array(list_target) + list_logit = np.array(list_logit) + list_src_len = np.array(list_src_len) + # save to npz + output_path = args.output_path + if (output_path is None): + output_path = tempfile.NamedTemporaryFile('wb', delete=False).name + + with open(output_path, 'wb') as ww: + np.savez(ww, name=list_uttname, + latent=list_latent, + target=list_target, + logit=list_logit, + src_len=list_src_len) + + print("="*10 + " REPORT " + "="*10) + print(f'| latent saved in {output_path}') + print(f'| {list_uttname.shape=}, {list_latent.shape=}, {list_target.shape=}, {list_logit.shape=}, {list_src_len.shape=}') From c8e4ab71e43eb93012a0ab4dfc09910393686cb0 Mon Sep 17 00:00:00 2001 From: Hirofumi Inaguma <hirofumii@fb.com> Date: Wed, 26 Oct 2022 16:09:14 -0700 Subject: [PATCH 712/774] Fix UnitY (#4830) * Fix build_multitask_decoder * Fix src_lengths in UnitY decoding --- .../unity/sequence_generator_multi_decoder.py | 17 ++++++--- .../models/speech_to_text/xm_transformer.py | 12 +++++-- .../speech_to_text/xm_transformer_unity.py | 36 ------------------- 3 files changed, 21 insertions(+), 44 deletions(-) diff --git a/examples/speech_to_speech/unity/sequence_generator_multi_decoder.py b/examples/speech_to_speech/unity/sequence_generator_multi_decoder.py index 49d127b34d..af99a960b8 100644 --- a/examples/speech_to_speech/unity/sequence_generator_multi_decoder.py +++ b/examples/speech_to_speech/unity/sequence_generator_multi_decoder.py @@ -142,11 +142,18 @@ def _generate( if "src_tokens" in net_input: src_tokens = net_input["src_tokens"] # length of the source text being the character length except EndOfSentence and pad - src_lengths = ( - (src_tokens.ne(self.generator.eos) & src_tokens.ne(self.generator.pad)) - .long() - .sum(dim=1) - ) + # if src_lengths exists in net_input (speech_to_text dataset case), then use it + if "src_lengths" in net_input: + src_lengths = net_input["src_lengths"] + else: + src_lengths = ( + ( + src_tokens.ne(self.generator.eos) + & src_tokens.ne(self.generator.pad) + ) + .long() + .sum(dim=1) + ) else: raise Exception( "expected src_tokens or source in net input. input keys: " diff --git a/fairseq/models/speech_to_text/xm_transformer.py b/fairseq/models/speech_to_text/xm_transformer.py index 57edc1069d..7b4b234641 100644 --- a/fairseq/models/speech_to_text/xm_transformer.py +++ b/fairseq/models/speech_to_text/xm_transformer.py @@ -297,6 +297,7 @@ def __init__(self, args): @classmethod def add_args(cls, parser): + """Add model-specific arguments to the parser.""" add_wav2vec_asr_args(parser) parser.add_argument( "--normalize", @@ -661,7 +662,7 @@ def build_model(cls, args, task): continue task_decoder = cls.build_multitask_decoder( - task_obj.args, task_obj.target_dictionary, args.decoder_embed_dim + args, task_obj.args, task_obj.target_dictionary, args.decoder_embed_dim ) setattr(base_model, f"{task_name}_decoder", task_decoder) @@ -677,7 +678,12 @@ def build_model(cls, args, task): @classmethod def build_multitask_decoder( - cls, args, mtl_args, tgt_dict, in_dim, is_first_pass_decoder + cls, + args, + mtl_args, + tgt_dict, + in_dim, + is_first_pass_decoder=False, ): decoder_args = mtl_args.decoder_args decoder_args.encoder_embed_dim = in_dim @@ -699,7 +705,7 @@ def build_multitask_decoder( decoder_args.decoder_embed_dim, ), ) - elif args.decoder_type == "ctc": + elif mtl_args.decoder_type == "ctc": task_decoder = CTCDecoder( dictionary=tgt_dict, in_dim=in_dim, diff --git a/fairseq/models/speech_to_text/xm_transformer_unity.py b/fairseq/models/speech_to_text/xm_transformer_unity.py index 450bf01efe..f77ef4e570 100644 --- a/fairseq/models/speech_to_text/xm_transformer_unity.py +++ b/fairseq/models/speech_to_text/xm_transformer_unity.py @@ -215,42 +215,6 @@ def build_model(cls, args, task): return base_model - @classmethod - def build_multitask_decoder( - cls, args, mtl_args, tgt_dict, in_dim, is_first_pass_decoder - ): - decoder_args = mtl_args.decoder_args - decoder_args.encoder_embed_dim = in_dim - if mtl_args.decoder_type == "transformer": - if is_first_pass_decoder: - task_decoder = cls.build_text_decoder(args, tgt_dict) - else: - from fairseq.models.speech_to_speech import ( - base_multitask_text_transformer_decoder_arch, - ) - - base_multitask_text_transformer_decoder_arch(decoder_args) # 2L - task_decoder = TransformerDecoder( - decoder_args, - tgt_dict, - embed_tokens=TransformerModelBase.build_embedding( - decoder_args, - tgt_dict, - decoder_args.decoder_embed_dim, - ), - ) - elif args.decoder_type == "ctc": - task_decoder = CTCDecoder( - dictionary=tgt_dict, - in_dim=in_dim, - ) - else: - raise NotImplementedError( - "currently only support multitask decoder_type 'transformer', 'ctc'" - ) - - return task_decoder - @classmethod def build_t2u_encoder(cls, args): _args = copy.deepcopy(args) From 59d966a92aabc68b6e0fe1f7bc3eeccbbbe91413 Mon Sep 17 00:00:00 2001 From: zhxchen17 <zhxchen17@outlook.com> Date: Wed, 2 Nov 2022 15:03:14 -0700 Subject: [PATCH 713/774] Make representation computation branchless in TransformerEncoderBase (#4818) Summary: We want to make the computation branchless here because fairseq code may be exported and traced for deployment purposes, and tracing mechanisms can break the correctness for a captured program if it's dependent on input data. In this diff we try to rewrite the code to remove one branch so that tracer can proceed here and preserve the correct semantics of the model. Test Plan: CI Reviewers: Subscribers: Tasks: Tags: --- fairseq/models/transformer/transformer_encoder.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index a5fbc6991d..49c432804d 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -202,13 +202,16 @@ def forward_scriptable( """ # compute padding mask encoder_padding_mask = src_tokens.eq(self.padding_idx) - has_pads = src_tokens.device.type == "xla" or encoder_padding_mask.any() + has_pads: Tensor = ( + torch.tensor(src_tokens.device.type == "xla") or encoder_padding_mask.any() + ) x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) # account for padding while computing the representation - if has_pads: - x = x * (1 - encoder_padding_mask.unsqueeze(-1).type_as(x)) + x = x * ( + 1 - encoder_padding_mask.unsqueeze(-1).type_as(x) * has_pads.type_as(x) + ) # B x T x C -> T x B x C x = x.transpose(0, 1) From b8ac3fa6cc95f9dc97085232d4faf125e5bcd2e7 Mon Sep 17 00:00:00 2001 From: zhxchen17 <zhxchen17@fb.com> Date: Tue, 8 Nov 2022 11:03:01 -0800 Subject: [PATCH 714/774] Fix Torchscript typing in transformer_encoder.py (#4847) --- fairseq/models/transformer/transformer_encoder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index 49c432804d..17369ec8dc 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -202,9 +202,12 @@ def forward_scriptable( """ # compute padding mask encoder_padding_mask = src_tokens.eq(self.padding_idx) - has_pads: Tensor = ( + has_pads = ( torch.tensor(src_tokens.device.type == "xla") or encoder_padding_mask.any() ) + # Torchscript doesn't handle bool Tensor correctly, so we need to work around. + if torch.jit.is_scripting(): + has_pads = torch.tensor(1) if has_pads else torch.tensor(0) x, encoder_embedding = self.forward_embedding(src_tokens, token_embeddings) From f131336fc303992cf309be3953bf523e1654fa1f Mon Sep 17 00:00:00 2001 From: Nguyen Tu Anh <nguyentuanh208@gmail.com> Date: Tue, 29 Nov 2022 17:50:12 +0100 Subject: [PATCH 715/774] Add Generative Spoken Dialogue Language Modeling (#4879) --- examples/textless_nlp/dgslm/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 examples/textless_nlp/dgslm/README.md diff --git a/examples/textless_nlp/dgslm/README.md b/examples/textless_nlp/dgslm/README.md new file mode 100644 index 0000000000..7a9248666b --- /dev/null +++ b/examples/textless_nlp/dgslm/README.md @@ -0,0 +1,19 @@ +# Generative Spoken Dialogue Language Modeling +[[paper]](https://arxiv.org/abs/2203.16502) [[demo samples]](https://speechbot.github.io/dgslm/index.html) [[blog]](https://ai.facebook.com/blog/generating-chit-chat-including-laughs-yawns-ums-and-other-nonverbal-cues-from-raw-audio/) + +The code for the paper _Generative Spoken Dialogue Language Modeling_ will be released here very soon. + +## Reference + +If you find our work useful in your research, please consider citing our paper: + +```bibtex +@article{nguyen2022dgslm, + title = {Generative Spoken Dialogue Language Modeling}, + author = {Nguyen, Tu Anh and Kharitonov, Eugene and Copet, Jade and Adi, Yossi and Hsu, Wei-Ning and Elkahky, Ali and Tomasello, Paden and Algayres, Robin and Sagot, Benoit and Mohamed, Abdelrahman and Dupoux, Emmanuel}, + eprint={2203.16502}, + archivePrefix={arXiv}, + primaryClass={cs.CL}, + year={2022} +} +``` From 1f533150710a3b393650dc4e3998c3675e42e3c9 Mon Sep 17 00:00:00 2001 From: Sergii Dymchenko <kit1980@gmail.com> Date: Fri, 9 Dec 2022 16:03:01 -0800 Subject: [PATCH 716/774] Update deprecated torch.qr in glow.py example (#4685) torch.qr is deprecated for a long time and is being removed by https://github.com/pytorch/pytorch/pull/70989. This PR makes the example compatible with new and old PyTorch versions. --- examples/textless_nlp/gslm/unit2speech/glow.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/textless_nlp/gslm/unit2speech/glow.py b/examples/textless_nlp/gslm/unit2speech/glow.py index 7a7696403d..41fd437feb 100644 --- a/examples/textless_nlp/gslm/unit2speech/glow.py +++ b/examples/textless_nlp/gslm/unit2speech/glow.py @@ -71,7 +71,8 @@ def __init__(self, c): bias=False) # Sample a random orthonormal matrix to initialize weights - W = torch.qr(torch.FloatTensor(c, c).normal_())[0] + _qr = torch.linalg.qr if torch.__version__ >= "1.8" else torch.qr + W = _qr(torch.FloatTensor(c, c).normal_())[0] # Ensure determinant is 1.0 not -1.0 if torch.det(W) < 0: From 0f33ccf7cfae3fdc918d40a8c8388eea00f5ea2a Mon Sep 17 00:00:00 2001 From: Felix Kreuk <felixkreuk@gmail.com> Date: Mon, 12 Dec 2022 16:00:01 +0200 Subject: [PATCH 717/774] Emotion Conversion Paper Open Source (#4895) --- examples/emotion_conversion/README.md | 214 +++++++ .../emotion_models/__init__.py | 0 .../emotion_models/duration_predictor.py | 243 ++++++++ .../emotion_models/duration_predictor.yaml | 48 ++ .../emotion_models/pitch_predictor.py | 559 ++++++++++++++++++ .../emotion_models/pitch_predictor.yaml | 64 ++ .../emotion_models/utils.py | 78 +++ .../fairseq_models/__init__.py | 226 +++++++ .../emotion_conversion/preprocess/__init__.py | 0 .../preprocess/build_hifigan_manifest.py | 38 ++ .../preprocess/build_translation_manifests.py | 258 ++++++++ .../preprocess/create_core_manifest.py | 91 +++ .../preprocess/extract_f0.py | 57 ++ .../preprocess/process_km.py | 40 ++ .../preprocess/split_emov_km_tsv_by_uttid.py | 70 +++ .../emotion_conversion/preprocess/split_km.py | 50 ++ .../preprocess/split_km_tsv.py | 65 ++ examples/emotion_conversion/requirements.txt | 11 + examples/emotion_conversion/synthesize.py | 322 ++++++++++ 19 files changed, 2434 insertions(+) create mode 100644 examples/emotion_conversion/README.md create mode 100644 examples/emotion_conversion/emotion_models/__init__.py create mode 100644 examples/emotion_conversion/emotion_models/duration_predictor.py create mode 100644 examples/emotion_conversion/emotion_models/duration_predictor.yaml create mode 100644 examples/emotion_conversion/emotion_models/pitch_predictor.py create mode 100644 examples/emotion_conversion/emotion_models/pitch_predictor.yaml create mode 100644 examples/emotion_conversion/emotion_models/utils.py create mode 100644 examples/emotion_conversion/fairseq_models/__init__.py create mode 100644 examples/emotion_conversion/preprocess/__init__.py create mode 100644 examples/emotion_conversion/preprocess/build_hifigan_manifest.py create mode 100644 examples/emotion_conversion/preprocess/build_translation_manifests.py create mode 100644 examples/emotion_conversion/preprocess/create_core_manifest.py create mode 100644 examples/emotion_conversion/preprocess/extract_f0.py create mode 100644 examples/emotion_conversion/preprocess/process_km.py create mode 100644 examples/emotion_conversion/preprocess/split_emov_km_tsv_by_uttid.py create mode 100644 examples/emotion_conversion/preprocess/split_km.py create mode 100644 examples/emotion_conversion/preprocess/split_km_tsv.py create mode 100644 examples/emotion_conversion/requirements.txt create mode 100644 examples/emotion_conversion/synthesize.py diff --git a/examples/emotion_conversion/README.md b/examples/emotion_conversion/README.md new file mode 100644 index 0000000000..caf22befe4 --- /dev/null +++ b/examples/emotion_conversion/README.md @@ -0,0 +1,214 @@ +# Textless speech emotion conversion using decomposed and discrete representations +[Felix Kreuk](https://felixkreuk.github.io), Adam Polyak, Jade Copet, Eugene Kharitonov, Tu-Anh Nguyen, Morgane Rivière, Wei-Ning Hsu, Abdelrahman Mohamed, Emmanuel Dupoux, [Yossi Adi](https://adiyoss.github.io) + +_abstract_: Speech emotion conversion is the task of modifying the perceived emotion of a speech utterance while preserving the lexical content and speaker identity. In this study, we cast the problem of emotion conversion as a spoken language translation task. We decompose speech into discrete and disentangled learned representations, consisting of content units, F0, speaker, and emotion. First, we modify the speech content by translating the content units to a target emotion, and then predict the prosodic features based on these units. Finally, the speech waveform is generated by feeding the predicted representations into a neural vocoder. Such a paradigm allows us to go beyond spectral and parametric changes of the signal, and model non-verbal vocalizations, such as laughter insertion, yawning removal, etc. We demonstrate objectively and subjectively that the proposed method is superior to the baselines in terms of perceived emotion and audio quality. We rigorously evaluate all components of such a complex system and conclude with an extensive model analysis and ablation study to better emphasize the architectural choices, strengths and weaknesses of the proposed method. Samples and code will be publicly available under the following link: https://speechbot.github.io/emotion. + +## Installation +First, create a conda virtual environment and activate it: +``` +conda create -n emotion python=3.8 -y +conda activate emotion +``` + +Then, clone this repository: +``` +git clone https://github.com/facebookresearch/fairseq.git +cd fairseq/examples/emotion_conversion +git clone https://github.com/felixkreuk/speech-resynthesis +``` + +Next, download the EmoV discrete tokens: +``` +wget https://dl.fbaipublicfiles.com/textless_nlp/emotion_conversion/data.tar.gz # (still in fairseq/examples/emotion_conversion) +tar -xzvf data.tar.gz +``` + +Your `fairseq/examples/emotion_conversion` directory should like this: +``` +drwxrwxr-x 3 felixkreuk felixkreuk 0 Feb 6 2022 data +drwxrwxr-x 3 felixkreuk felixkreuk 0 Sep 28 10:41 emotion_models +drwxr-xr-x 3 felixkreuk felixkreuk 0 Jun 29 05:43 fairseq_models +drwxr-xr-x 3 felixkreuk felixkreuk 0 Sep 28 10:41 preprocess +-rw-rw-r-- 1 felixkreuk felixkreuk 11K Dec 5 09:00 README.md +-rw-rw-r-- 1 felixkreuk felixkreuk 88 Mar 6 2022 requirements.txt +-rw-rw-r-- 1 felixkreuk felixkreuk 13K Jun 29 06:26 synthesize.py +``` + +Lastly, install fairseq and the other packages: +``` +pip install --editable ./ +pip install -r examples/emotion_conversion/requirements.txt +``` + +## Data preprocessing + +### Convert your audio to discrete representations +Please follow the steps described [here](https://github.com/pytorch/fairseq/tree/main/examples/hubert/simple_kmeans). +To generate the same discrete representations please use the following: +1. [HuBERT checkpoint](https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt) +2. k-means model at `data/hubert_base_ls960_layer9_clusters200/data_hubert_base_ls960_layer9_clusters200.bin` + +### Construct data splits +This step will use the discrete representations from the previous step and split them to train/valid/test sets for 3 tasks: +1. Translation model pre-training (BART language denoising) +2. Translation model training (content units emotion translation mechanism) +3. HiFiGAN model training (for synthesizing audio from discrete representations) + +Your processed data should be at `data/`: +1. `hubert_base_ls960_layer9_clusters200` - discrete representations extracted using HuBERT layer 9, clustered into 200 clusters. +2. `data.tsv` - a tsv file pointing to the EmoV dataset in your environment (Please edit the first line of this file according to your path). + +The following command will create the above splits: +``` +python examples/emotion_conversion/preprocess/create_core_manifest.py \ + --tsv data/data.tsv \ + --emov-km data/hubert_base_ls960_layer9_clusters200/data.km \ + --km data/hubert_base_ls960_layer9_clusters200/vctk.km \ + --dict data/hubert_base_ls960_layer9_clusters200/dict.txt \ + --manifests-dir $DATA +``` +* Set `$DATA` as the directory that will contain the processed data. + +### Extract F0 +To train the HiFiGAN vocoder we need to first extract the F0 curves: +``` +python examples/emotion_conversion/preprocess/extract_f0.py \ + --tsv data/data.tsv \ + --extractor pyaapt \ +``` + +## HiFiGAN training +Now we are all set to train the HiFiGAN vocoder: +``` +python examples/emotion_conversion/speech-resynthesis/train.py + --checkpoint_path <hifigan-checkpoint-dir> \ + --config examples/emotion_conversion/speech-resynthesis/configs/EmoV/emov_hubert-layer9-cluster200_fixed-spkr-embedder_f0-raw_gst.json +``` + +## Translation Pre-training +Before translating emotions, we first need to pre-train the translation model as a denoising autoencoder (similarly to BART). +``` +python train.py \ + $DATA/fairseq-data/emov_multilingual_denoising_cross-speaker_dedup_nonzeroshot/tokenized \ + --save-dir <your-save-dir> \ + --tensorboard-logdir <your-tb-dir> \ + --langs neutral,amused,angry,sleepy,disgusted,vctk.km \ + --dataset-impl mmap \ + --task multilingual_denoising \ + --arch transformer_small --criterion cross_entropy \ + --multilang-sampling-alpha 1.0 --sample-break-mode eos --max-tokens 16384 \ + --update-freq 1 --max-update 3000000 \ + --dropout 0.1 --attention-dropout 0.1 --relu-dropout 0.0 \ + --optimizer adam --weight-decay 0.01 --adam-eps 1e-06 \ + --clip-norm 0.1 --lr-scheduler polynomial_decay --lr 0.0003 \ + --total-num-update 3000000 --warmup-updates 10000 --fp16 \ + --poisson-lambda 3.5 --mask 0.3 --mask-length span-poisson --replace-length 1 --rotate 0 --mask-random 0.1 --insert 0 --permute-sentences 1.0 \ + --skip-invalid-size-inputs-valid-test \ + --user-dir examples/emotion_conversion/fairseq_models +``` + +## Translation Training +Now we are ready to train our emotion translation model: +``` +python train.py \ + --distributed-world-size 1 \ + $DATA/fairseq-data/emov_multilingual_translation_cross-speaker_dedup/tokenized/ \ + --save-dir <your-save-dir> \ + --tensorboard-logdir <your-tb-dir> \ + --arch multilingual_small --task multilingual_translation \ + --criterion label_smoothed_cross_entropy --label-smoothing 0.2 \ + --lang-pairs neutral-amused,neutral-sleepy,neutral-disgusted,neutral-angry,amused-sleepy,amused-disgusted,amused-neutral,amused-angry,angry-amused,angry-sleepy,angry-disgusted,angry-neutral,disgusted-amused,disgusted-sleepy,disgusted-neutral,disgusted-angry,sleepy-amused,sleepy-neutral,sleepy-disgusted,sleepy-angry \ + --optimizer adam --adam-betas "(0.9, 0.98)" --adam-eps 1e-06 \ + --lr 1e-05 --clip-norm 0 --dropout 0.1 --attention-dropout 0.1 \ + --weight-decay 0.01 --warmup-updates 2000 --lr-scheduler inverse_sqrt \ + --max-tokens 4096 --update-freq 1 --max-update 100000 \ + --required-batch-size-multiple 8 --fp16 --num-workers 4 \ + --seed 2 --log-format json --log-interval 25 --save-interval-updates 1000 \ + --no-epoch-checkpoints --keep-best-checkpoints 1 --keep-interval-updates 1 \ + --finetune-from-model <path-to-model-from-previous-step> \ + --user-dir examples/emotion_conversion/fairseq_models +``` +* To share encoders/decoders use the `--share-encoders` and `--share-decoders` flags. +* To add source/target emotion tokens use the `--encoder-langtok {'src'|'tgt'}` and `--decoder-langtok` flags. + +## F0-predictor Training +The following command trains the F0 prediction module: +``` +cd examples/emotion_conversion +python -m emotion_models.pitch_predictor n_tokens=200 \ + train_tsv="$DATA/denoising/emov/train.tsv" \ + train_km="$DATA/denoising/emov/train.km" \ + valid_tsv="$DATA/denoising/emov/valid.tsv" \ + valid_km="$DATA/denoising/emov/valid.km" +``` +* See `hyra.run.dir` to configure directory for saving models. + +## Duration-predictor Training +The following command trains the duration prediction modules: +``` +cd examples/emotion_conversion +for emotion in "neutral" "amused" "angry" "disgusted" "sleepy"; do + python -m emotion_models.duration_predictor n_tokens=200 substring=$emotion \ + train_tsv="$DATA/denoising/emov/train.tsv" \ + train_km="$DATA/denoising/emov/train.km" \ + valid_tsv="$DATA/denoising/emov/valid.tsv" \ + valid_km="$DATA/denoising/emov/valid.km" +done +``` +* See `hyra.run.dir` to configure directory for saving models. +* After the above command you should have 5 duration models in your checkpoint directory: +``` +❯ ll duration_predictor/ +total 21M +-rw-rw-r-- 1 felixkreuk felixkreuk 4.1M Nov 15 2021 amused.ckpt +-rw-rw-r-- 1 felixkreuk felixkreuk 4.1M Nov 15 2021 angry.ckpt +-rw-rw-r-- 1 felixkreuk felixkreuk 4.1M Nov 15 2021 disgusted.ckpt +-rw-rw-r-- 1 felixkreuk felixkreuk 4.1M Nov 15 2021 neutral.ckpt +-rw-rw-r-- 1 felixkreuk felixkreuk 4.1M Nov 15 2021 sleepy.ckpt +``` + +## Token Generation +The following command uses `fairseq-generate` to generate the token sequences based on the source and target emotions. +``` +fairseq-generate \ + $DATA/fairseq-data/emov_multilingual_translation_cross-speaker_dedup/tokenized/ \ + --task multilingual_translation \ + --gen-subset test \ + --path <your-saved-translation-checkpoint> \ + --beam 5 \ + --batch-size 4 --max-len-a 1.8 --max-len-b 10 --lenpen 1 --min-len 1 \ + --skip-invalid-size-inputs-valid-test --distributed-world-size 1 \ + --source-lang neutral --target-lang amused \ + --lang-pairs neutral-amused,neutral-sleepy,neutral-disgusted,neutral-angry,amused-sleepy,amused-disgusted,amused-neutral,amused-angry,angry-amused,angry-sleepy,angry-disgusted,angry-neutral,disgusted-amused,disgusted-sleepy,disgusted-neutral,disgusted-angry,sleepy-amused,sleepy-neutral,sleepy-disgusted,sleepy-angry \ + --results-path <token-output-path> \ + --user-dir examples/emotion_conversion/fairseq_models +``` +* Modify `--source-lang` and `--target-lang` to control for the source and target emotions. +* See [fairseq documentation](https://fairseq.readthedocs.io/en/latest/command_line_tools.html#fairseq-generate) for a full overview of generation parameters (e.g., top-k/top-p sampling). + +## Waveform Synthesis +Using the output of the above command, the HiFiGAN vocoder, and the prosody prediction modules (F0 and duration) we can now generate the output waveforms: +``` +python examples/emotion_conversion/synthesize.py \ + --result-path <token-output-path>/generate-test.txt \ + --data $DATA/fairseq-data/emov_multilingual_translation_cross-speaker_dedup/neutral-amused \ + --orig-tsv examples/emotion_conversion/data/data.tsv \ + --orig-km examples/emotion_conversion/data/hubert_base_ls960_layer9_clusters200/data.km \ + --checkpoint-file <hifigan-checkpoint-dir>/g_00400000 \ + --dur-model duration_predictor/ \ + --f0-model pitch_predictor/pitch_predictor.ckpt \ + -s neutral -t amused \ + --outdir ~/tmp/emotion_results/wavs/neutral-amused +``` +* Please make sure the source and target emotions here match those of the previous command. + +# Citation +If you find this useful in your research, please use the following BibTeX entry for citation. +``` +@article{kreuk2021textless, + title={Textless speech emotion conversion using decomposed and discrete representations}, + author={Kreuk, Felix and Polyak, Adam and Copet, Jade and Kharitonov, Eugene and Nguyen, Tu-Anh and Rivi{\`e}re, Morgane and Hsu, Wei-Ning and Mohamed, Abdelrahman and Dupoux, Emmanuel and Adi, Yossi}, + journal={Conference on Empirical Methods in Natural Language Processing (EMNLP)}, + year={2022} +} +``` diff --git a/examples/emotion_conversion/emotion_models/__init__.py b/examples/emotion_conversion/emotion_models/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/emotion_conversion/emotion_models/duration_predictor.py b/examples/emotion_conversion/emotion_models/duration_predictor.py new file mode 100644 index 0000000000..eb47df0a21 --- /dev/null +++ b/examples/emotion_conversion/emotion_models/duration_predictor.py @@ -0,0 +1,243 @@ +import logging +import os + +import hydra +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops.layers.torch import Rearrange +from torch.utils.data import DataLoader, Dataset + +from .utils import Accuracy + +logger = logging.getLogger(__name__) + + +def save_ckpt(model, path, model_class): + ckpt = { + "state_dict": model.state_dict(), + "padding_token": model.padding_token, + "model_class": model_class, + } + torch.save(ckpt, path) + + +def load_ckpt(path): + ckpt = torch.load(path) + ckpt["model_class"]["_target_"] = "emotion_models.duration_predictor.CnnPredictor" + model = hydra.utils.instantiate(ckpt["model_class"]) + model.load_state_dict(ckpt["state_dict"]) + model.padding_token = ckpt["padding_token"] + model = model.cpu() + model.eval() + return model + + +class Collator: + def __init__(self, padding_idx): + self.padding_idx = padding_idx + + def __call__(self, batch): + x = [item[0] for item in batch] + lengths = [len(item) for item in x] + x = torch.nn.utils.rnn.pad_sequence(x, batch_first=True, padding_value=self.padding_idx) + y = [item[1] for item in batch] + y = torch.nn.utils.rnn.pad_sequence(y, batch_first=True, padding_value=self.padding_idx) + mask = (x != self.padding_idx) + return x, y, mask, lengths + + +class Predictor(nn.Module): + def __init__(self, n_tokens, emb_dim): + super(Predictor, self).__init__() + self.n_tokens = n_tokens + self.emb_dim = emb_dim + self.padding_token = n_tokens + # add 1 extra embedding for padding token, set the padding index to be the last token + # (tokens from the clustering start at index 0) + self.emb = nn.Embedding(n_tokens + 1, emb_dim, padding_idx=self.padding_token) + + def inflate_input(self, batch): + """ get a sequence of tokens, predict their durations + and inflate them accordingly """ + batch_durs = self.forward(batch) + batch_durs = torch.exp(batch_durs) - 1 + batch_durs = batch_durs.round() + output = [] + for seq, durs in zip(batch, batch_durs): + inflated_seq = [] + for token, n in zip(seq, durs): + if token == self.padding_token: + break + n = int(n.item()) + token = int(token.item()) + inflated_seq.extend([token for _ in range(n)]) + output.append(inflated_seq) + output = torch.LongTensor(output) + return output + + +class CnnPredictor(Predictor): + def __init__(self, n_tokens, emb_dim, channels, kernel, output_dim, dropout, n_layers): + super(CnnPredictor, self).__init__(n_tokens=n_tokens, emb_dim=emb_dim) + layers = [ + Rearrange("b t c -> b c t"), + nn.Conv1d(emb_dim, channels, kernel_size=kernel, padding=(kernel - 1) // 2), + Rearrange("b c t -> b t c"), + nn.ReLU(), + nn.LayerNorm(channels), + nn.Dropout(dropout), + ] + for _ in range(n_layers-1): + layers += [ + Rearrange("b t c -> b c t"), + nn.Conv1d(channels, channels, kernel_size=kernel, padding=(kernel - 1) // 2), + Rearrange("b c t -> b t c"), + nn.ReLU(), + nn.LayerNorm(channels), + nn.Dropout(dropout), + ] + self.conv_layer = nn.Sequential(*layers) + self.proj = nn.Linear(channels, output_dim) + + def forward(self, x): + x = self.emb(x) + x = self.conv_layer(x) + x = self.proj(x) + x = x.squeeze(-1) + return x + + +def l2_log_loss(input, target): + return F.mse_loss( + input=input.float(), + target=torch.log(target.float() + 1), + reduce=False + ) + + +class DurationDataset(Dataset): + def __init__(self, tsv_path, km_path, substring=""): + lines = open(tsv_path, "r").readlines() + self.root, self.tsv = lines[0], lines[1:] + self.km = open(km_path, "r").readlines() + logger.info(f"loaded {len(self.km)} files") + + if substring != "": + tsv, km = [], [] + for tsv_line, km_line in zip(self.tsv, self.km): + if substring.lower() in tsv_line.lower(): + tsv.append(tsv_line) + km.append(km_line) + self.tsv, self.km = tsv, km + logger.info(f"after filtering: {len(self.km)} files") + + def __len__(self): + return len(self.km) + + def __getitem__(self, i): + x = self.km[i] + x = x.split(" ") + x = list(map(int, x)) + + y = [] + xd = [] + count = 1 + for x1, x2 in zip(x[:-1], x[1:]): + if x1 == x2: + count += 1 + continue + else: + y.append(count) + xd.append(x1) + count = 1 + + xd = torch.LongTensor(xd) + y = torch.LongTensor(y) + return xd, y + + +def train(cfg): + device = "cuda:0" + model = hydra.utils.instantiate(cfg[cfg.model]).to(device) + optimizer = hydra.utils.instantiate(cfg.optimizer, model.parameters()) + # add 1 extra embedding for padding token, set the padding index to be the last token + # (tokens from the clustering start at index 0) + collate_fn = Collator(padding_idx=model.padding_token) + logger.info(f"data: {cfg.train_tsv}") + train_ds = DurationDataset(cfg.train_tsv, cfg.train_km, substring=cfg.substring) + valid_ds = DurationDataset(cfg.valid_tsv, cfg.valid_km, substring=cfg.substring) + train_dl = DataLoader(train_ds, batch_size=32, shuffle=True, collate_fn=collate_fn) + valid_dl = DataLoader(valid_ds, batch_size=32, shuffle=False, collate_fn=collate_fn) + + best_loss = float("inf") + for epoch in range(cfg.epochs): + train_loss, train_loss_scaled = train_epoch(model, train_dl, l2_log_loss, optimizer, device) + valid_loss, valid_loss_scaled, *acc = valid_epoch(model, valid_dl, l2_log_loss, device) + acc0, acc1, acc2, acc3 = acc + if valid_loss_scaled < best_loss: + path = f"{os.getcwd()}/{cfg.substring}.ckpt" + save_ckpt(model, path, cfg[cfg.model]) + best_loss = valid_loss_scaled + logger.info(f"saved checkpoint: {path}") + logger.info(f"[epoch {epoch}] train loss: {train_loss:.3f}, train scaled: {train_loss_scaled:.3f}") + logger.info(f"[epoch {epoch}] valid loss: {valid_loss:.3f}, valid scaled: {valid_loss_scaled:.3f}") + logger.info(f"acc: {acc0,acc1,acc2,acc3}") + + +def train_epoch(model, loader, criterion, optimizer, device): + model.train() + epoch_loss = 0 + epoch_loss_scaled = 0 + for x, y, mask, _ in loader: + x, y, mask = x.to(device), y.to(device), mask.to(device) + yhat = model(x) + loss = criterion(yhat, y) * mask + loss = torch.mean(loss) + loss.backward() + nn.utils.clip_grad_norm_(model.parameters(), 1.0) + optimizer.step() + epoch_loss += loss.item() + # get normal scale loss + yhat_scaled = torch.exp(yhat) - 1 + yhat_scaled = torch.round(yhat_scaled) + scaled_loss = torch.mean(torch.abs(yhat_scaled - y) * mask) + epoch_loss_scaled += scaled_loss.item() + return epoch_loss / len(loader), epoch_loss_scaled / len(loader) + + +def valid_epoch(model, loader, criterion, device): + model.eval() + epoch_loss = 0 + epoch_loss_scaled = 0 + acc = Accuracy() + for x, y, mask, _ in loader: + x, y, mask = x.to(device), y.to(device), mask.to(device) + yhat = model(x) + loss = criterion(yhat, y) * mask + loss = torch.mean(loss) + epoch_loss += loss.item() + # get normal scale loss + yhat_scaled = torch.exp(yhat) - 1 + yhat_scaled = torch.round(yhat_scaled) + scaled_loss = torch.sum(torch.abs(yhat_scaled - y) * mask) / mask.sum() + acc.update(yhat_scaled[mask].view(-1).float(), y[mask].view(-1).float()) + epoch_loss_scaled += scaled_loss.item() + logger.info(f"example y: {y[0, :10].tolist()}") + logger.info(f"example yhat: {yhat_scaled[0, :10].tolist()}") + acc0 = acc.acc(tol=0) + acc1 = acc.acc(tol=1) + acc2 = acc.acc(tol=2) + acc3 = acc.acc(tol=3) + logger.info(f"accs: {acc0,acc1,acc2,acc3}") + return epoch_loss / len(loader), epoch_loss_scaled / len(loader), acc0, acc1, acc2, acc3 + + +@hydra.main(config_path=".", config_name="duration_predictor.yaml") +def main(cfg): + logger.info(f"{cfg}") + train(cfg) + + +if __name__ == "__main__": + main() diff --git a/examples/emotion_conversion/emotion_models/duration_predictor.yaml b/examples/emotion_conversion/emotion_models/duration_predictor.yaml new file mode 100644 index 0000000000..0e976f4843 --- /dev/null +++ b/examples/emotion_conversion/emotion_models/duration_predictor.yaml @@ -0,0 +1,48 @@ +train_tsv: "<your-processed-data>/denoising/emov/train.tsv" +train_km: "<your-processed-data>/denoising/emov/train.km" +valid_tsv: "<your-processed-data>/denoising/emov/valid.tsv" +valid_km: "<your-processed-data>/denoising/emov/valid.km" + +n_tokens: 200 +batch_size: 32 +lr: 0.0001 +epochs: 300 +model: "cnn" +substring: "" + +rnn: + _target_: emotion_models.duration_predictor.RnnPredictor + n_tokens: ${n_tokens} + emb_dim: 128 + rnn_hidden: 128 + output_dim: 1 + dropout: 0 + n_layers: 1 + +optimizer: + _target_: torch.optim.Adam + lr: ${lr} + betas: [0.9, 0.98] + eps: 0.000000001 + weight_decay: 0 + +cnn: + _target_: emotion_models.duration_predictor.CnnPredictor + n_tokens: ${n_tokens} + emb_dim: 128 + channels: 256 + kernel: 3 + output_dim: 1 + dropout: 0.5 + n_layers: 1 + +hydra: + run: + dir: /checkpoint/felixkreuk/experiments/duration_predictor/${hydra.job.override_dirname} + job: + config: + # configuration for the ${hydra.job.override_dirname} runtime variable + override_dirname: + kv_sep: '=' + item_sep: ',' + exclude_keys: ['train_tsv', 'train_km', 'valid_tsv', 'valid_km'] diff --git a/examples/emotion_conversion/emotion_models/pitch_predictor.py b/examples/emotion_conversion/emotion_models/pitch_predictor.py new file mode 100644 index 0000000000..431446996c --- /dev/null +++ b/examples/emotion_conversion/emotion_models/pitch_predictor.py @@ -0,0 +1,559 @@ +import logging +import os +import random +import sys +from collections import defaultdict + +import hydra +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange +from einops.layers.torch import Rearrange +from scipy.io.wavfile import read +from scipy.ndimage import gaussian_filter1d +from torch.utils.data import DataLoader, Dataset +from tqdm import tqdm + +dir_path = os.path.dirname(__file__) +resynth_path = os.path.dirname(dir_path) + "/speech-resynthesis" +sys.path.append(resynth_path) +from dataset import parse_speaker, parse_style +from .utils import F0Stat + +MAX_WAV_VALUE = 32768.0 +logger = logging.getLogger(__name__) + + +def quantize_f0(speaker_to_f0, nbins, normalize, log): + f0_all = [] + for speaker, f0 in speaker_to_f0.items(): + f0 = f0.raw_data + if log: + f0 = f0.log() + mean = speaker_to_f0[speaker].mean_log if log else speaker_to_f0[speaker].mean + std = speaker_to_f0[speaker].std_log if log else speaker_to_f0[speaker].std + if normalize == "mean": + f0 = f0 - mean + elif normalize == "meanstd": + f0 = (f0 - mean) / std + f0_all.extend(f0.tolist()) + + hist, bin_x = np.histogram(f0_all, 100000) + cum_hist = np.cumsum(hist) / len(f0_all) * 100 + + bin_offset = [] + bin_size = 100 / nbins + threshold = bin_size + for i in range(nbins - 1): + index = (np.abs(cum_hist - threshold)).argmin() + bin_offset.append(bin_x[index]) + threshold += bin_size + bins = np.array(bin_offset) + bins = torch.FloatTensor(bins) + + return bins + + +def save_ckpt(model, path, model_class, f0_min, f0_max, f0_bins, speaker_stats): + ckpt = { + "state_dict": model.state_dict(), + "padding_token": model.padding_token, + "model_class": model_class, + "speaker_stats": speaker_stats, + "f0_min": f0_min, + "f0_max": f0_max, + "f0_bins": f0_bins, + } + torch.save(ckpt, path) + + +def load_ckpt(path): + ckpt = torch.load(path) + ckpt["model_class"]["_target_"] = "emotion_models.pitch_predictor.CnnPredictor" + model = hydra.utils.instantiate(ckpt["model_class"]) + model.load_state_dict(ckpt["state_dict"]) + model.setup_f0_stats( + ckpt["f0_min"], + ckpt["f0_max"], + ckpt["f0_bins"], + ckpt["speaker_stats"], + ) + return model + + +def freq2bin(f0, f0_min, f0_max, bins): + f0 = f0.clone() + f0[f0 < f0_min] = f0_min + f0[f0 > f0_max] = f0_max + f0 = torch.bucketize(f0, bins) + return f0 + + +def bin2freq(x, f0_min, f0_max, bins, mode): + n_bins = len(bins) + 1 + assert x.shape[-1] == n_bins + bins = torch.cat([torch.tensor([f0_min]), bins]).to(x.device) + if mode == "mean": + f0 = (x * bins).sum(-1, keepdims=True) / x.sum(-1, keepdims=True) + elif mode == "argmax": + idx = F.one_hot(x.argmax(-1), num_classes=n_bins) + f0 = (idx * bins).sum(-1, keepdims=True) + else: + raise NotImplementedError() + return f0[..., 0] + + +def load_wav(full_path): + sampling_rate, data = read(full_path) + return data, sampling_rate + + +def l1_loss(input, target): + return F.l1_loss(input=input.float(), target=target.float(), reduce=False) + + +def l2_loss(input, target): + return F.mse_loss(input=input.float(), target=target.float(), reduce=False) + + +class Collator: + def __init__(self, padding_idx): + self.padding_idx = padding_idx + + def __call__(self, batch): + tokens = [item[0] for item in batch] + lengths = [len(item) for item in tokens] + tokens = torch.nn.utils.rnn.pad_sequence( + tokens, batch_first=True, padding_value=self.padding_idx + ) + f0 = [item[1] for item in batch] + f0 = torch.nn.utils.rnn.pad_sequence( + f0, batch_first=True, padding_value=self.padding_idx + ) + f0_raw = [item[2] for item in batch] + f0_raw = torch.nn.utils.rnn.pad_sequence( + f0_raw, batch_first=True, padding_value=self.padding_idx + ) + spk = [item[3] for item in batch] + spk = torch.LongTensor(spk) + gst = [item[4] for item in batch] + gst = torch.LongTensor(gst) + mask = tokens != self.padding_idx + return tokens, f0, f0_raw, spk, gst, mask, lengths + + +class CnnPredictor(nn.Module): + def __init__( + self, + n_tokens, + emb_dim, + channels, + kernel, + dropout, + n_layers, + spk_emb, + gst_emb, + n_bins, + f0_pred, + f0_log, + f0_norm, + ): + super(CnnPredictor, self).__init__() + self.n_tokens = n_tokens + self.emb_dim = emb_dim + self.f0_log = f0_log + self.f0_pred = f0_pred + self.padding_token = n_tokens + self.f0_norm = f0_norm + # add 1 extra embedding for padding token, set the padding index to be the last token + # (tokens from the clustering start at index 0) + self.token_emb = nn.Embedding( + n_tokens + 1, emb_dim, padding_idx=self.padding_token + ) + + self.spk_emb = spk_emb + self.gst_emb = nn.Embedding(20, gst_emb) + self.setup = False + + feats = emb_dim + gst_emb + # feats = emb_dim + gst_emb + (256 if spk_emb else 0) + layers = [ + nn.Sequential( + Rearrange("b t c -> b c t"), + nn.Conv1d( + feats, channels, kernel_size=kernel, padding=(kernel - 1) // 2 + ), + Rearrange("b c t -> b t c"), + nn.ReLU(), + nn.LayerNorm(channels), + nn.Dropout(dropout), + ) + ] + for _ in range(n_layers - 1): + layers += [ + nn.Sequential( + Rearrange("b t c -> b c t"), + nn.Conv1d( + channels, + channels, + kernel_size=kernel, + padding=(kernel - 1) // 2, + ), + Rearrange("b c t -> b t c"), + nn.ReLU(), + nn.LayerNorm(channels), + nn.Dropout(dropout), + ) + ] + self.conv_layer = nn.ModuleList(layers) + self.proj = nn.Linear(channels, n_bins) + + def forward(self, x, gst=None): + x = self.token_emb(x) + feats = [x] + + if gst is not None: + gst = self.gst_emb(gst) + gst = rearrange(gst, "b c -> b c 1") + gst = F.interpolate(gst, x.shape[1]) + gst = rearrange(gst, "b c t -> b t c") + feats.append(gst) + + x = torch.cat(feats, dim=-1) + + for i, conv in enumerate(self.conv_layer): + if i != 0: + x = conv(x) + x + else: + x = conv(x) + + x = self.proj(x) + x = x.squeeze(-1) + + if self.f0_pred == "mean": + x = torch.sigmoid(x) + elif self.f0_pred == "argmax": + x = torch.softmax(x, dim=-1) + else: + raise NotImplementedError + return x + + def setup_f0_stats(self, f0_min, f0_max, f0_bins, speaker_stats): + self.f0_min = f0_min + self.f0_max = f0_max + self.f0_bins = f0_bins + self.speaker_stats = speaker_stats + self.setup = True + + def inference(self, x, spk_id=None, gst=None): + assert ( + self.setup == True + ), "make sure that `setup_f0_stats` was called before inference!" + probs = self(x, gst) + f0 = bin2freq(probs, self.f0_min, self.f0_max, self.f0_bins, self.f0_pred) + for i in range(f0.shape[0]): + mean = ( + self.speaker_stats[spk_id[i].item()].mean_log + if self.f0_log + else self.speaker_stats[spk_id[i].item()].mean + ) + std = ( + self.speaker_stats[spk_id[i].item()].std_log + if self.f0_log + else self.speaker_stats[spk_id[i].item()].std + ) + if self.f0_norm == "mean": + f0[i] = f0[i] + mean + if self.f0_norm == "meanstd": + f0[i] = (f0[i] * std) + mean + if self.f0_log: + f0 = f0.exp() + return f0 + + +class PitchDataset(Dataset): + def __init__( + self, + tsv_path, + km_path, + substring, + spk, + spk2id, + gst, + gst2id, + f0_bins, + f0_bin_type, + f0_smoothing, + f0_norm, + f0_log, + ): + lines = open(tsv_path, "r").readlines() + self.root, self.tsv = lines[0], lines[1:] + self.root = self.root.strip() + self.km = open(km_path, "r").readlines() + print(f"loaded {len(self.km)} files") + + self.spk = spk + self.spk2id = spk2id + self.gst = gst + self.gst2id = gst2id + + self.f0_bins = f0_bins + self.f0_smoothing = f0_smoothing + self.f0_norm = f0_norm + self.f0_log = f0_log + + if substring != "": + tsv, km = [], [] + for tsv_line, km_line in zip(self.tsv, self.km): + if substring.lower() in tsv_line.lower(): + tsv.append(tsv_line) + km.append(km_line) + self.tsv, self.km = tsv, km + print(f"after filtering: {len(self.km)} files") + + self.speaker_stats = self._compute_f0_stats() + self.f0_min, self.f0_max = self._compute_f0_minmax() + if f0_bin_type == "adaptive": + self.f0_bins = quantize_f0( + self.speaker_stats, self.f0_bins, self.f0_norm, self.f0_log + ) + elif f0_bin_type == "uniform": + self.f0_bins = torch.linspace(self.f0_min, self.f0_max, self.f0_bins + 1)[ + 1:-1 + ] + else: + raise NotImplementedError + print(f"f0 min: {self.f0_min}, f0 max: {self.f0_max}") + print(f"bins: {self.f0_bins} (shape: {self.f0_bins.shape})") + + def __len__(self): + return len(self.km) + + def _load_f0(self, tsv_line): + tsv_line = tsv_line.split("\t")[0] + f0 = self.root + "/" + tsv_line.replace(".wav", ".yaapt.f0.npy") + f0 = np.load(f0) + f0 = torch.FloatTensor(f0) + return f0 + + def _preprocess_f0(self, f0, spk): + mask = f0 != -999999 # process all frames + # mask = (f0 != 0) # only process voiced frames + mean = ( + self.speaker_stats[spk].mean_log + if self.f0_log + else self.speaker_stats[spk].mean + ) + std = ( + self.speaker_stats[spk].std_log + if self.f0_log + else self.speaker_stats[spk].std + ) + if self.f0_log: + f0[f0 == 0] = 1e-5 + f0[mask] = f0[mask].log() + if self.f0_norm == "mean": + f0[mask] = f0[mask] - mean + if self.f0_norm == "meanstd": + f0[mask] = (f0[mask] - mean) / std + return f0 + + def _compute_f0_minmax(self): + f0_min, f0_max = float("inf"), -float("inf") + for tsv_line in tqdm(self.tsv, desc="computing f0 minmax"): + spk = self.spk2id[parse_speaker(tsv_line, self.spk)] + f0 = self._load_f0(tsv_line) + f0 = self._preprocess_f0(f0, spk) + f0_min = min(f0_min, f0.min().item()) + f0_max = max(f0_max, f0.max().item()) + return f0_min, f0_max + + def _compute_f0_stats(self): + from functools import partial + + speaker_stats = defaultdict(partial(F0Stat, True)) + for tsv_line in tqdm(self.tsv, desc="computing speaker stats"): + spk = self.spk2id[parse_speaker(tsv_line, self.spk)] + f0 = self._load_f0(tsv_line) + mask = f0 != 0 + f0 = f0[mask] # compute stats only on voiced parts + speaker_stats[spk].update(f0) + return speaker_stats + + def __getitem__(self, i): + x = self.km[i] + x = x.split(" ") + x = list(map(int, x)) + x = torch.LongTensor(x) + + gst = parse_style(self.tsv[i], self.gst) + gst = self.gst2id[gst] + spk = parse_speaker(self.tsv[i], self.spk) + spk = self.spk2id[spk] + + f0_raw = self._load_f0(self.tsv[i]) + f0 = self._preprocess_f0(f0_raw.clone(), spk) + + f0 = F.interpolate(f0.unsqueeze(0).unsqueeze(0), x.shape[0])[0, 0] + f0_raw = F.interpolate(f0_raw.unsqueeze(0).unsqueeze(0), x.shape[0])[0, 0] + + f0 = freq2bin(f0, f0_min=self.f0_min, f0_max=self.f0_max, bins=self.f0_bins) + f0 = F.one_hot(f0.long(), num_classes=len(self.f0_bins) + 1).float() + if self.f0_smoothing > 0: + f0 = torch.tensor( + gaussian_filter1d(f0.float().numpy(), sigma=self.f0_smoothing) + ) + return x, f0, f0_raw, spk, gst + + +def train(cfg): + device = "cuda:0" + # add 1 extra embedding for padding token, set the padding index to be the last token + # (tokens from the clustering start at index 0) + padding_token = cfg.n_tokens + collate_fn = Collator(padding_idx=padding_token) + train_ds = PitchDataset( + cfg.train_tsv, + cfg.train_km, + substring=cfg.substring, + spk=cfg.spk, + spk2id=cfg.spk2id, + gst=cfg.gst, + gst2id=cfg.gst2id, + f0_bins=cfg.f0_bins, + f0_bin_type=cfg.f0_bin_type, + f0_smoothing=cfg.f0_smoothing, + f0_norm=cfg.f0_norm, + f0_log=cfg.f0_log, + ) + valid_ds = PitchDataset( + cfg.valid_tsv, + cfg.valid_km, + substring=cfg.substring, + spk=cfg.spk, + spk2id=cfg.spk2id, + gst=cfg.gst, + gst2id=cfg.gst2id, + f0_bins=cfg.f0_bins, + f0_bin_type=cfg.f0_bin_type, + f0_smoothing=cfg.f0_smoothing, + f0_norm=cfg.f0_norm, + f0_log=cfg.f0_log, + ) + train_dl = DataLoader( + train_ds, + num_workers=0, + batch_size=cfg.batch_size, + shuffle=True, + collate_fn=collate_fn, + ) + valid_dl = DataLoader( + valid_ds, num_workers=0, batch_size=16, shuffle=False, collate_fn=collate_fn + ) + + f0_min = train_ds.f0_min + f0_max = train_ds.f0_max + f0_bins = train_ds.f0_bins + speaker_stats = train_ds.speaker_stats + + model = hydra.utils.instantiate(cfg["model"]).to(device) + model.setup_f0_stats(f0_min, f0_max, f0_bins, speaker_stats) + + optimizer = hydra.utils.instantiate(cfg.optimizer, model.parameters()) + + best_loss = float("inf") + for epoch in range(cfg.epochs): + train_loss, train_l2_loss, train_l2_voiced_loss = run_epoch( + model, train_dl, optimizer, device, cfg, mode="train" + ) + valid_loss, valid_l2_loss, valid_l2_voiced_loss = run_epoch( + model, valid_dl, None, device, cfg, mode="valid" + ) + print( + f"[epoch {epoch}] train loss: {train_loss:.3f}, l2 loss: {train_l2_loss:.3f}, l2 voiced loss: {train_l2_voiced_loss:.3f}" + ) + print( + f"[epoch {epoch}] valid loss: {valid_loss:.3f}, l2 loss: {valid_l2_loss:.3f}, l2 voiced loss: {valid_l2_voiced_loss:.3f}" + ) + if valid_l2_voiced_loss < best_loss: + path = f"{os.getcwd()}/pitch_predictor.ckpt" + save_ckpt(model, path, cfg["model"], f0_min, f0_max, f0_bins, speaker_stats) + best_loss = valid_l2_voiced_loss + print(f"saved checkpoint: {path}") + print(f"[epoch {epoch}] best loss: {best_loss:.3f}") + + +def run_epoch(model, loader, optimizer, device, cfg, mode): + if mode == "train": + model.train() + else: + model.eval() + + epoch_loss = 0 + l1 = 0 + l1_voiced = 0 + for x, f0_bin, f0_raw, spk_id, gst, mask, _ in tqdm(loader): + x, f0_bin, f0_raw, spk_id, gst, mask = ( + x.to(device), + f0_bin.to(device), + f0_raw.to(device), + spk_id.to(device), + gst.to(device), + mask.to(device), + ) + b, t, n_bins = f0_bin.shape + yhat = model(x, gst) + nonzero_mask = (f0_raw != 0).logical_and(mask) + yhat_raw = model.inference(x, spk_id, gst) + expanded_mask = mask.unsqueeze(-1).expand(-1, -1, n_bins) + if cfg.f0_pred == "mean": + loss = F.binary_cross_entropy( + yhat[expanded_mask], f0_bin[expanded_mask] + ).mean() + elif cfg.f0_pred == "argmax": + loss = F.cross_entropy( + rearrange(yhat, "b t d -> (b t) d"), + rearrange(f0_bin.argmax(-1), "b t -> (b t)"), + reduce=False, + ) + loss = rearrange(loss, "(b t) -> b t", b=b, t=t) + loss = (loss * mask).sum() / mask.float().sum() + else: + raise NotImplementedError + l1 += F.l1_loss(yhat_raw[mask], f0_raw[mask]).item() + l1_voiced += F.l1_loss(yhat_raw[nonzero_mask], f0_raw[nonzero_mask]).item() + epoch_loss += loss.item() + + if mode == "train": + loss.backward() + nn.utils.clip_grad_norm_(model.parameters(), 1.0) + optimizer.step() + + print(f"{mode} example y: {f0_bin.argmax(-1)[0, 50:60].tolist()}") + print(f"{mode} example yhat: {yhat.argmax(-1)[0, 50:60].tolist()}") + print(f"{mode} example y: {f0_raw[0, 50:60].round().tolist()}") + print(f"{mode} example yhat: {yhat_raw[0, 50:60].round().tolist()}") + return epoch_loss / len(loader), l1 / len(loader), l1_voiced / len(loader) + + +@hydra.main(config_path=dir_path, config_name="pitch_predictor.yaml") +def main(cfg): + np.random.seed(1) + random.seed(1) + torch.manual_seed(1) + from hydra.core.hydra_config import HydraConfig + + overrides = { + x.split("=")[0]: x.split("=")[1] + for x in HydraConfig.get().overrides.task + if "/" not in x + } + print(f"{cfg}") + train(cfg) + + +if __name__ == "__main__": + main() diff --git a/examples/emotion_conversion/emotion_models/pitch_predictor.yaml b/examples/emotion_conversion/emotion_models/pitch_predictor.yaml new file mode 100644 index 0000000000..d2dbb862c3 --- /dev/null +++ b/examples/emotion_conversion/emotion_models/pitch_predictor.yaml @@ -0,0 +1,64 @@ +train_tsv: "<your-processed-data>/denoising/emov/train.tsv" +train_km: "<your-processed-data>/denoising/emov/train.km" +valid_tsv: "<your-processed-data>/denoising/emov/valid.tsv" +valid_km: "<your-processed-data>/denoising/emov/valid.km" + +n_tokens: 200 +batch_size: 64 +lr: 0.0001 +epochs: 1000 + +substring: "" +loss: "l2" +spk: "parent_parent_name" +gst: "emotion" + +f0_bins: 50 +f0_pred: "mean" # [argmax, mean] +f0_smoothing: 0.1 +f0_norm: "mean" +f0_log: false +f0_bin_type: "adaptive" # [uniform, adaptive] + +spk2id: + bea: 0 + jenie: 1 + josh: 2 + sam: 3 + +gst2id: + amused: 0 + angry: 1 + disgusted: 2 + neutral: 3 + sleepy: 4 + +optimizer: + _target_: torch.optim.Adam + lr: ${lr} + +model: + _target_: emotion_models.pitch_predictor.CnnPredictor + n_tokens: ${n_tokens} + emb_dim: 256 + channels: 256 + kernel: 5 + dropout: 0.1 + n_layers: 6 + spk_emb: true + gst_emb: 8 + n_bins: ${f0_bins} + f0_pred: ${f0_pred} + f0_log: ${f0_log} + f0_norm: ${f0_norm} + +hydra: + run: + dir: /checkpoint/felixkreuk/experiments/pitch_predictor/${hydra.job.override_dirname} + job: + config: + # configuration for the ${hydra.job.override_dirname} runtime variable + override_dirname: + kv_sep: '=' + item_sep: ',' + exclude_keys: ['train_tsv', 'train_km', 'valid_tsv', 'valid_km'] diff --git a/examples/emotion_conversion/emotion_models/utils.py b/examples/emotion_conversion/emotion_models/utils.py new file mode 100644 index 0000000000..4199c310f8 --- /dev/null +++ b/examples/emotion_conversion/emotion_models/utils.py @@ -0,0 +1,78 @@ +import torch + + +class Stat: + def __init__(self, keep_raw=False): + self.x = 0.0 + self.x2 = 0.0 + self.z = 0.0 # z = logx + self.z2 = 0.0 + self.n = 0.0 + self.u = 0.0 + self.keep_raw = keep_raw + self.raw = [] + + def update(self, new_x): + new_z = new_x.log() + + self.x += new_x.sum() + self.x2 += (new_x**2).sum() + self.z += new_z.sum() + self.z2 += (new_z**2).sum() + self.n += len(new_x) + self.u += 1 + + if self.keep_raw: + self.raw.append(new_x) + + @property + def mean(self): + return self.x / self.n + + @property + def std(self): + return (self.x2 / self.n - self.mean**2) ** 0.5 + + @property + def mean_log(self): + return self.z / self.n + + @property + def std_log(self): + return (self.z2 / self.n - self.mean_log**2) ** 0.5 + + @property + def n_frms(self): + return self.n + + @property + def n_utts(self): + return self.u + + @property + def raw_data(self): + assert self.keep_raw, "does not support storing raw data!" + return torch.cat(self.raw) + + +class F0Stat(Stat): + def update(self, new_x): + # assume unvoiced frames are 0 and consider only voiced frames + if new_x is not None: + super().update(new_x[new_x != 0]) + + +class Accuracy: + def __init__(self): + self.y, self.yhat = [], [] + + def update(self, yhat, y): + self.yhat.append(yhat) + self.y.append(y) + + def acc(self, tol): + yhat = torch.cat(self.yhat) + y = torch.cat(self.y) + acc = torch.abs(yhat - y) <= tol + acc = acc.float().mean().item() + return acc diff --git a/examples/emotion_conversion/fairseq_models/__init__.py b/examples/emotion_conversion/fairseq_models/__init__.py new file mode 100644 index 0000000000..441bc03db4 --- /dev/null +++ b/examples/emotion_conversion/fairseq_models/__init__.py @@ -0,0 +1,226 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from fairseq import utils +from fairseq.models import ( + FairseqMultiModel, + register_model, + register_model_architecture, +) +from fairseq.models.transformer import ( + Embedding, + base_architecture, +) +from fairseq.models.multilingual_transformer import ( + MultilingualTransformerModel, + base_multilingual_architecture, +) +from fairseq.utils import safe_hasattr +from collections import OrderedDict + + +@register_model("multilingual_transformer_from_mbart") +class MultilingualTransformerModelFromMbart(MultilingualTransformerModel): + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + from fairseq.tasks.multilingual_translation import MultilingualTranslationTask + + assert isinstance(task, MultilingualTranslationTask) + + # make sure all arguments are present in older models + base_multilingual_architecture(args) + + if not safe_hasattr(args, "max_source_positions"): + args.max_source_positions = 1024 + if not safe_hasattr(args, "max_target_positions"): + args.max_target_positions = 1024 + + src_langs = [lang_pair.split("-")[0] for lang_pair in task.model_lang_pairs] + tgt_langs = [lang_pair.split("-")[1] for lang_pair in task.model_lang_pairs] + + if args.share_encoders: + args.share_encoder_embeddings = True + if args.share_decoders: + args.share_decoder_embeddings = True + + def build_embedding(dictionary, embed_dim, path=None): + num_embeddings = len(dictionary) + padding_idx = dictionary.pad() + emb = Embedding(num_embeddings, embed_dim, padding_idx) + # if provided, load from preloaded dictionaries + if path: + embed_dict = utils.parse_embedding(path) + utils.load_embedding(embed_dict, dictionary, emb) + return emb + + # build shared embeddings (if applicable) + shared_encoder_embed_tokens, shared_decoder_embed_tokens = None, None + if args.share_all_embeddings: + if args.encoder_embed_dim != args.decoder_embed_dim: + raise ValueError( + "--share-all-embeddings requires --encoder-embed-dim to match --decoder-embed-dim" + ) + if args.decoder_embed_path and ( + args.decoder_embed_path != args.encoder_embed_path + ): + raise ValueError( + "--share-all-embeddings not compatible with --decoder-embed-path" + ) + shared_encoder_embed_tokens = FairseqMultiModel.build_shared_embeddings( + dicts=task.dicts, + langs=task.langs, + embed_dim=args.encoder_embed_dim, + build_embedding=build_embedding, + pretrained_embed_path=args.encoder_embed_path, + ) + shared_decoder_embed_tokens = shared_encoder_embed_tokens + args.share_decoder_input_output_embed = True + else: + if args.share_encoder_embeddings: + shared_encoder_embed_tokens = FairseqMultiModel.build_shared_embeddings( + dicts=task.dicts, + langs=src_langs, + embed_dim=args.encoder_embed_dim, + build_embedding=build_embedding, + pretrained_embed_path=args.encoder_embed_path, + ) + if args.share_decoder_embeddings: + shared_decoder_embed_tokens = FairseqMultiModel.build_shared_embeddings( + dicts=task.dicts, + langs=tgt_langs, + embed_dim=args.decoder_embed_dim, + build_embedding=build_embedding, + pretrained_embed_path=args.decoder_embed_path, + ) + + # encoders/decoders for each language + lang_encoders, lang_decoders = {}, {} + + def get_encoder(lang): + if lang not in lang_encoders: + if shared_encoder_embed_tokens is not None: + encoder_embed_tokens = shared_encoder_embed_tokens + else: + encoder_embed_tokens = build_embedding( + task.dicts[lang], + args.encoder_embed_dim, + args.encoder_embed_path, + ) + lang_encoders[lang] = MultilingualTransformerModel._get_module_class( + True, args, task.dicts[lang], encoder_embed_tokens, src_langs + ) + return lang_encoders[lang] + + def get_decoder(lang): + if lang not in lang_decoders: + if shared_decoder_embed_tokens is not None: + decoder_embed_tokens = shared_decoder_embed_tokens + else: + decoder_embed_tokens = build_embedding( + task.dicts[lang], + args.decoder_embed_dim, + args.decoder_embed_path, + ) + lang_decoders[lang] = MultilingualTransformerModel._get_module_class( + False, args, task.dicts[lang], decoder_embed_tokens, tgt_langs + ) + return lang_decoders[lang] + + # shared encoders/decoders (if applicable) + shared_encoder, shared_decoder = None, None + if args.share_encoders: + shared_encoder = get_encoder(src_langs[0]) + if args.share_decoders: + shared_decoder = get_decoder(tgt_langs[0]) + + encoders, decoders = OrderedDict(), OrderedDict() + for lang_pair, src, tgt in zip(task.model_lang_pairs, src_langs, tgt_langs): + encoders[lang_pair] = ( + shared_encoder if shared_encoder is not None else get_encoder(src) + ) + decoders[lang_pair] = ( + shared_decoder if shared_decoder is not None else get_decoder(tgt) + ) + + return MultilingualTransformerModelFromMbart(encoders, decoders) + + def load_state_dict(self, state_dict, strict=True, model_cfg=None): + state_dict_subset = state_dict.copy() + lang_pairs = set([x.split(".")[1] for x in state_dict.keys()]) + finetune_mode = not any("neutral" in lp for lp in lang_pairs) + + if finetune_mode: + # load a pre-trained mBART/BART model + # we need this code because mBART/BART are not of type FairseqMultiModel but FairseqModel + # so we hackishly load the weights by replicating them for all lang pairs + print("loading pre-trained BART") + self_state_dict = self.state_dict() + for k, v in state_dict.items(): + for lang_pair in self.models: + new_key = k if "models." in k else f"models.{lang_pair}.{k}" + # print(new_key) + if self_state_dict[new_key].shape == v.shape: + state_dict_subset[new_key] = v + elif any( + w in k + for w in [ + "encoder.embed_tokens.weight", + "decoder.embed_tokens.weight", + "decoder.output_projection.weight", + ] + ): + # why vocab_size - 5? because there are `vocab_size` tokens from the language + # and 5 additional tokens in the denoising task: eos,bos,pad,unk,mask. + # but in the translation task there are only `vocab_size` + 4 (no mask). + print( + f"{k}: {self_state_dict[new_key].shape} != {v.shape}", + end="", + flush=True, + ) + vocab_size = v.shape[0] - 5 + state_dict_subset[new_key] = self_state_dict[new_key] + state_dict_subset[new_key] = v[: vocab_size + 4] + print(f" => fixed by using first {vocab_size + 4} dims") + else: + raise ValueError("unable to load model due to mimatched dims!") + del state_dict_subset[k] + else: + print("loading pre-trained emotion translation model") + for k, _ in state_dict.items(): + assert k.startswith("models.") + lang_pair = k.split(".")[1] + if lang_pair not in self.models: + del state_dict_subset[k] + + super().load_state_dict(state_dict_subset, strict=strict, model_cfg=model_cfg) + + +@register_model_architecture("transformer", "transformer_small") +def transformer_small(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 512) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.encoder_layers = getattr(args, "encoder_layers", 3) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 512) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) + args.decoder_layers = getattr(args, "decoder_layers", 3) + base_architecture(args) + + +@register_model_architecture( + "multilingual_transformer_from_mbart", "multilingual_small" +) +def multilingual_small(args): + args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 512) + args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 512) + args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 4) + args.encoder_layers = getattr(args, "encoder_layers", 3) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 512) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 4) + args.decoder_layers = getattr(args, "decoder_layers", 3) + base_multilingual_architecture(args) diff --git a/examples/emotion_conversion/preprocess/__init__.py b/examples/emotion_conversion/preprocess/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/emotion_conversion/preprocess/build_hifigan_manifest.py b/examples/emotion_conversion/preprocess/build_hifigan_manifest.py new file mode 100644 index 0000000000..29c0d79cee --- /dev/null +++ b/examples/emotion_conversion/preprocess/build_hifigan_manifest.py @@ -0,0 +1,38 @@ +import torchaudio +import argparse +import json + +def main(): + parser = argparse.ArgumentParser(description="example: python create_hifigan_manifest.py --tsv /checkpoint/felixkreuk/datasets/vctk/splits/vctk_16khz/train.tsv --km /checkpoint/felixkreuk/experiments/hubert/hubert_feats/vctk_16khz_km_100/train.km --km_type hubert_100km > ~/tmp/tmp_mani.txt") + parser.add_argument("--tsv", required=True, help="path to fairseq tsv file") + parser.add_argument("--km", required=True, help="path to a km file generated by HuBERT clustering") + parser.add_argument("--km_type", required=True, help="name of the codes in the output json (for example: 'cpc_100km')") + args = parser.parse_args() + + km_lines = open(args.km, "r").readlines() + tsv_lines = open(args.tsv, "r").readlines() + assert len(km_lines) == len(tsv_lines) - 1, "tsv and km files are not of the same length!" + + wav_root = tsv_lines[0].strip() + tsv_lines = tsv_lines[1:] + + for tsv_line, km_line in zip(tsv_lines, km_lines): + tsv_line, km_line = tsv_line.strip(), km_line.strip() + wav_basename, wav_num_frames = tsv_line.split("\t") + wav_path = wav_root + "/" + wav_basename + wav_info = torchaudio.info(wav_path) + assert int(wav_num_frames) == wav_info.num_frames, "tsv duration and actual duration don't match!" + wav_duration = wav_info.num_frames / wav_info.sample_rate + manifest_line = {"audio": wav_path, "duration": wav_duration, args.km_type: km_line} + print(json.dumps(manifest_line)) + +if __name__ == "__main__": + """ + usage: + python create_hifigan_manifest.py \ + --tsv /checkpoint/felixkreuk/datasets/vctk/manifests/vctk_16khz/valid.tsv \ + --km /checkpoint/felixkreuk/datasets/vctk/manifests/vctk_16khz/hubert_km_100/valid.km \ + --km_type hubert \ + > /checkpoint/felixkreuk/datasets/vctk/manifests/vctk_16khz/hubert_km_100/hifigan_valid_manifest.txt + """ + main() diff --git a/examples/emotion_conversion/preprocess/build_translation_manifests.py b/examples/emotion_conversion/preprocess/build_translation_manifests.py new file mode 100644 index 0000000000..d38454a713 --- /dev/null +++ b/examples/emotion_conversion/preprocess/build_translation_manifests.py @@ -0,0 +1,258 @@ +from glob import glob +import argparse +from collections import defaultdict, Counter +from itertools import combinations, product, groupby +from pathlib import Path +import os +from sklearn.utils import shuffle +import numpy as np +import random +from shutil import copy +from subprocess import check_call + +np.random.seed(42) +random.seed(42) + + +def get_fname(s): + return s.split("\t")[0] + +def get_emotion(s): + return get_fname(s).split("_")[0].split("/")[1].lower() + +def get_utt_id(s): + return get_fname(s).split(".")[0].split("_")[-1] + +def dedup(seq): + """ >> remove_repetitions("1 2 2 3 100 2 2 1") + '1 2 3 100 2 1' """ + seq = seq.strip().split(" ") + result = seq[:1] + reps = [] + rep_counter = 1 + for k in seq[1:]: + if k != result[-1]: + result += [k] + reps += [rep_counter] + rep_counter = 1 + else: + rep_counter += 1 + reps += [rep_counter] + assert len(reps) == len(result) and sum(reps) == len(seq) + return " ".join(result) + "\n" #, reps + +def remove_under_k(seq, k): + """ remove tokens that repeat less then k times in a row + >> remove_under_k("a a a a b c c c", 1) ==> a a a a c c c """ + seq = seq.strip().split(" ") + result = [] + + freqs = [(k,len(list(g))) for k, g in groupby(seq)] + for c, f in freqs: + if f > k: + result += [c for _ in range(f)] + return " ".join(result) + "\n" #, reps + + +def call(cmd): + print(cmd) + check_call(cmd, shell=True) + + +def denoising_preprocess(path, lang, dict): + bin = 'fairseq-preprocess' + cmd = [ + bin, + f'--trainpref {path}/train.{lang} --validpref {path}/valid.{lang} --testpref {path}/test.{lang}', + f'--destdir {path}/tokenized/{lang}', + '--only-source', + '--task multilingual_denoising', + '--workers 40', + ] + if dict != "": + cmd += [f'--srcdict {dict}'] + cmd = " ".join(cmd) + call(cmd) + + +def translation_preprocess(path, src_lang, trg_lang, dict, only_train=False): + bin = 'fairseq-preprocess' + cmd = [ + bin, + f'--source-lang {src_lang} --target-lang {trg_lang}', + f'--trainpref {path}/train', + f'--destdir {path}/tokenized', + '--workers 40', + ] + if not only_train: + cmd += [f'--validpref {path}/valid --testpref {path}/test'] + if dict != "": + cmd += [ + f'--srcdict {dict}', + f'--tgtdict {dict}', + ] + cmd = " ".join(cmd) + call(cmd) + + +def load_tsv_km(tsv_path, km_path): + assert tsv_path.exists() and km_path.exists() + tsv_lines = open(tsv_path, "r").readlines() + root, tsv_lines = tsv_lines[0], tsv_lines[1:] + km_lines = open(km_path, "r").readlines() + assert len(tsv_lines) == len(km_lines), ".tsv and .km should be the same length!" + return root, tsv_lines, km_lines + + +def main(): + desc = """ + this script takes as input .tsv and .km files for EMOV dataset, and a pairs of emotions. + it generates parallel .tsv and .km files for these emotions. for exmaple: + ❯ python build_emov_translation_manifests.py \ + /checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz/train.tsv \ + /checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz/emov_16khz_km_100/train.km \ + ~/tmp/emov_pairs \ + --src-emotion amused --trg-emotion neutral \ + --dedup --shuffle --cross-speaker --dry-run + """ + parser = argparse.ArgumentParser(description=desc) + parser.add_argument("data", type=Path, help="path to a dir containing .tsv and .km files containing emov dataset") + parser.add_argument("output_path", type=Path, help="output directory with the manifests will be created") + parser.add_argument("-cs", "--cross-speaker", action='store_true', help="if set then translation will occur also between speakers, meaning the same sentence can be translated between different speakers (default: false)") + parser.add_argument("-dd", "--dedup", action='store_true', help="remove repeated tokens (example: 'aaabc=>abc')") + parser.add_argument("-sh", "--shuffle", action='store_true', help="shuffle the data") + parser.add_argument("-ae", "--autoencode", action='store_true', help="include training pairs from the same emotion (this includes examples of the same sentence uttered by different people and examples where the src and trg are the exact same seq)") + parser.add_argument("-dr", "--dry-run", action='store_true', help="don't write anything to disk") + parser.add_argument("-zs", "--zero-shot", action='store_true', help="if true, the denoising task will train on the same splits as the translation task (split by utterance id). if false, the denoising task will train on randomly sampled splits (not split by utterance id)") + parser.add_argument("--km-ext", default="km", help="") + parser.add_argument("--dict", default="/checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz/fairseq.dict.txt", help="") + args = parser.parse_args() + SPEAKERS = ["bea", "jenie", "josh", "sam", "SAME"] + EMOTIONS = ['neutral', 'amused', 'angry', 'disgusted', 'sleepy'] + + suffix = "" + if args.cross_speaker: suffix += "_cross-speaker" + if args.dedup: suffix += "_dedup" + translation_suffix = "" + if args.autoencode: translation_suffix += "_autoencode" + denoising_suffix = "" + denoising_suffix += "_zeroshot" if args.zero_shot else "_nonzeroshot" + + translation_dir = Path(args.output_path) / ("emov_multilingual_translation" + suffix + translation_suffix) + os.makedirs(translation_dir, exist_ok=True) + denoising_dir = Path(args.output_path) / ("emov_multilingual_denoising" + suffix + denoising_suffix) + os.makedirs(denoising_dir, exist_ok=True) + + denoising_data = [p.name for p in (args.data / "denoising").glob("*") if "emov" not in p.name] + + for split in ["train", "valid", "test"]: + root, tsv_lines, km_lines = load_tsv_km( + tsv_path = args.data / "denoising" / "emov" / f"{split}.tsv", + km_path = args.data / "denoising" / "emov" / f"{split}.{args.km_ext}" + ) + + # generate data for the multilingual denoising task + for EMOTION in EMOTIONS: + print("---") + print(split) + print(f"denoising: {EMOTION}") + emotion_tsv, emotion_km = [], [] + for tsv_line, km_line in zip(tsv_lines, km_lines): + if EMOTION.lower() in tsv_line.lower(): + km_line = km_line if not args.dedup else dedup(km_line) + emotion_tsv.append(tsv_line) + emotion_km.append(km_line) + print(f"{len(emotion_km)} samples") + open(denoising_dir / f"files.{split}.{EMOTION}", "w").writelines([root] + emotion_tsv) + open(denoising_dir / f"{split}.{EMOTION}", "w").writelines(emotion_km) + + for data in denoising_data: + with open(args.data / "denoising" / data / f"{split}.{args.km_ext}", "r") as f1: + with open(denoising_dir / f"{split}.{data}", "w") as f2: + f2.writelines([l if not args.dedup else dedup(l) for l in f1.readlines()]) + + # start of translation preprocessing + root, tsv_lines, km_lines = load_tsv_km( + tsv_path = args.data / "translation" / f"{split}.tsv", + km_path = args.data / "translation" / f"{split}.{args.km_ext}" + ) + + # generate data for the multilingual translation task + for SRC_EMOTION in EMOTIONS: + TRG_EMOTIONS = EMOTIONS if args.autoencode else set(EMOTIONS) - set([SRC_EMOTION]) + for TRG_EMOTION in TRG_EMOTIONS: + # when translating back to the same emotion - we dont want these emotion + # pairs to be part of the validation/test sets (because its not really emotion conversino) + # if SRC_EMOTION == TRG_EMOTION and split in ["valid", "test"]: continue + print("---") + print(split) + print(f"src emotions: {SRC_EMOTION}\ntrg emotions: {TRG_EMOTION}") + + # create a dictionary with the following structure: + # output[SPEAKER][UTT_ID] = list with indexes of line from the tsv file + # that match the speaker and utterance id. for exmaple: + # output = {'sam': {'0493': [875, 1608, 1822], ...}, ...} + # meaning, for speaker 'sam', utterance id '0493', the indexes in tsv_lines + # are 875, 1608, 1822 + spkr2utts = defaultdict(lambda: defaultdict(list)) + for i, tsv_line in enumerate(tsv_lines): + speaker = tsv_line.split("/")[0] + if args.cross_speaker: speaker = "SAME" + assert speaker in SPEAKERS, "unknown speaker! make sure the .tsv contains EMOV data" + utt_id = get_utt_id(tsv_line) + spkr2utts[speaker][utt_id].append(i) + + # create a tsv and km files with all the combinations for translation + src_tsv, trg_tsv, src_km, trg_km = [], [], [], [] + for speaker, utt_ids in spkr2utts.items(): + for utt_id, indices in utt_ids.items(): + # generate all pairs + pairs = [(x,y) for x in indices for y in indices] + # self-translation + if SRC_EMOTION == TRG_EMOTION: + pairs = [(x,y) for (x,y) in pairs if x == y] + # filter according to src and trg emotions + pairs = [(x,y) for (x,y) in pairs + if get_emotion(tsv_lines[x]) == SRC_EMOTION and get_emotion(tsv_lines[y]) == TRG_EMOTION] + + for idx1, idx2 in pairs: + assert get_utt_id(tsv_lines[idx1]) == get_utt_id(tsv_lines[idx2]) + src_tsv.append(tsv_lines[idx1]) + trg_tsv.append(tsv_lines[idx2]) + km_line_idx1 = km_lines[idx1] + km_line_idx2 = km_lines[idx2] + km_line_idx1 = km_line_idx1 if not args.dedup else dedup(km_line_idx1) + km_line_idx2 = km_line_idx2 if not args.dedup else dedup(km_line_idx2) + src_km.append(km_line_idx1) + trg_km.append(km_line_idx2) + assert len(src_tsv) == len(trg_tsv) == len(src_km) == len(trg_km) + print(f"{len(src_tsv)} pairs") + + if len(src_tsv) == 0: + raise Exception("ERROR: generated 0 pairs!") + + if args.dry_run: continue + + # create files + os.makedirs(translation_dir / f"{SRC_EMOTION}-{TRG_EMOTION}", exist_ok=True) + open(translation_dir / f"{SRC_EMOTION}-{TRG_EMOTION}" / f"files.{split}.{SRC_EMOTION}", "w").writelines([root] + src_tsv) + open(translation_dir / f"{SRC_EMOTION}-{TRG_EMOTION}" / f"files.{split}.{TRG_EMOTION}", "w").writelines([root] + trg_tsv) + open(translation_dir / f"{SRC_EMOTION}-{TRG_EMOTION}" / f"{split}.{SRC_EMOTION}", "w").writelines(src_km) + open(translation_dir / f"{SRC_EMOTION}-{TRG_EMOTION}" / f"{split}.{TRG_EMOTION}", "w").writelines(trg_km) + + + # fairseq-preprocess the denoising data + for EMOTION in EMOTIONS + denoising_data: + denoising_preprocess(denoising_dir, EMOTION, args.dict) + os.system(f"cp {args.dict} {denoising_dir}/tokenized/dict.txt") + + # fairseq-preprocess the translation data + os.makedirs(translation_dir / "tokenized", exist_ok=True) + for SRC_EMOTION in EMOTIONS: + TRG_EMOTIONS = EMOTIONS if args.autoencode else set(EMOTIONS) - set([SRC_EMOTION]) + for TRG_EMOTION in TRG_EMOTIONS: + translation_preprocess(translation_dir / f"{SRC_EMOTION}-{TRG_EMOTION}", SRC_EMOTION, TRG_EMOTION, args.dict)#, only_train=SRC_EMOTION==TRG_EMOTION) + os.system(f"cp -rf {translation_dir}/**/tokenized/* {translation_dir}/tokenized") + +if __name__ == "__main__": + main() diff --git a/examples/emotion_conversion/preprocess/create_core_manifest.py b/examples/emotion_conversion/preprocess/create_core_manifest.py new file mode 100644 index 0000000000..b55740e00b --- /dev/null +++ b/examples/emotion_conversion/preprocess/create_core_manifest.py @@ -0,0 +1,91 @@ +from pathlib import Path +import os +import sys +import subprocess +import argparse +from datetime import datetime +import logging + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [%(levelname)s] %(message)s', + handlers=[logging.FileHandler('debug.log'), logging.StreamHandler()] +) +logger = logging.getLogger(__name__) + + +def verify_dict_size(km, dict): + logger.info(f"verifying: {km}") + dict_size = len(open(dict, "r").readlines()) + km_vocab = set(open(km, "r").read().replace("\n", " ").split(" ")) + if "" in km_vocab: km_vocab.remove("") + km_vocab_size = len(km_vocab) + return dict_size == km_vocab_size + + +def verify_files_exist(l): + for f in l: + if not f.exists(): + logging.error(f"{f} doesn't exist!") + return False + return True + + +def run_cmd(cmd, print_output=True): + try: + out = subprocess.check_output(cmd, stderr=subprocess.STDOUT, universal_newlines=True, shell=True) + if print_output: + logger.info(f"command output:\n{out}") + return out + except subprocess.CalledProcessError as grepexc: + logger.info(f"error executing command!:\n{cmd}") + logger.info(grepexc.output) + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--tsv", default="/checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz/data.tsv", type=Path) + parser.add_argument("--emov-km", required=True, type=Path) + parser.add_argument("--km", nargs='+', required=True, type=Path) + parser.add_argument("--seed", type=int, default=1) + parser.add_argument("--dict", default="/checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz/fairseq.dict.txt") + parser.add_argument("--manifests-dir", type=Path, default="/checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz") + args = parser.parse_args() + + manifests_dir = args.manifests_dir + date = datetime.now().strftime('%d%m%y') + outdir = manifests_dir / f"{date}" + + # verify input and create folders + all_kms = args.km + [args.emov_km] + assert verify_files_exist(all_kms), "make sure the km dir contains: train-clean-all.km, blizzard2013.km, data.km" + for codes in all_kms: + assert verify_dict_size(codes, args.dict), "dict argument doesn't match the vocabulary of the km file!" + assert not outdir.exists(), "data dir already exists!" + outdir.mkdir(parents=True, exist_ok=True) + + logger.info("generating denoising split (emov)") + run_cmd(f"python preprocess/split_km_tsv.py {args.tsv} {args.emov_km} --destdir {outdir}/denoising/emov -sh --seed {args.seed}") + for codes in args.km: + codes_name = os.path.basename(codes) + run_cmd(f"python preprocess/split_km.py {codes} --destdir {outdir}/denoising/{codes_name} -sh --seed {args.seed}") + + logger.info("generating translation split") + run_cmd(f"python preprocess/split_emov_km_tsv_by_uttid.py {args.tsv} {args.emov_km} --destdir {outdir}/translation --seed {args.seed}") + + emov_code_name = os.path.basename(args.emov_km) + logger.info("generating hifigan split") + run_cmd( + f"mkdir -p {outdir}/hifigan &&" + f"python preprocess/build_hifigan_manifest.py --km_type hubert --tsv {outdir}/denoising/emov/train.tsv --km {outdir}/denoising/emov/train.km > {outdir}/hifigan/train.txt &&" + f"python preprocess/build_hifigan_manifest.py --km_type hubert --tsv {outdir}/denoising/emov/valid.tsv --km {outdir}/denoising/emov/valid.km > {outdir}/hifigan/valid.txt &&" + f"python preprocess/build_hifigan_manifest.py --km_type hubert --tsv {outdir}/denoising/emov/test.tsv --km {outdir}/denoising/emov/test.km > {outdir}/hifigan/test.txt" + ) + + logger.info("generating fairseq manifests") + run_cmd(f"python preprocess/build_translation_manifests.py {outdir} {outdir}/fairseq-data -dd -cs --dict {args.dict}") + + logger.info(f"finished processing data at:\n{outdir}") + + +if __name__ == "__main__": + main() diff --git a/examples/emotion_conversion/preprocess/extract_f0.py b/examples/emotion_conversion/preprocess/extract_f0.py new file mode 100644 index 0000000000..4204aa4db1 --- /dev/null +++ b/examples/emotion_conversion/preprocess/extract_f0.py @@ -0,0 +1,57 @@ +import argparse +from tqdm import tqdm +from multiprocessing import Manager, Pool + +from scipy.io.wavfile import read +from librosa.util import normalize +import numpy as np +import amfm_decompy.pYAAPT as pYAAPT +import amfm_decompy.basic_tools as basic + +MAX_WAV_VALUE = 32768.0 + +parser = argparse.ArgumentParser(description="") +parser.add_argument("tsv", help="") +parser.add_argument("--extractor", choices=["crepe", "pyaapt"], default="pyaapt", help="") +parser.add_argument("--interp", action="store_true", help="") +parser.add_argument("--n_workers", type=int, default=40, help="") +args = parser.parse_args() + +tsv_lines = open(args.tsv, "r").readlines() +root, tsv_lines = tsv_lines[0].strip(), tsv_lines[1:] + + +def extract_f0(tsv_line): + wav_path, _ = tsv_line.split("\t") + wav_path = root.strip() + "/" + wav_path + sr, wav = read(wav_path) + wav = wav / MAX_WAV_VALUE + wav = normalize(wav) * 0.95 + + if args.extractor == "pyaapt": + frame_length = 20.0 + pad = int(frame_length / 1000 * sr) // 2 + wav = np.pad(wav.squeeze(), (pad, pad), "constant", constant_values=0) + signal = basic.SignalObj(wav, sr) + pitch = pYAAPT.yaapt( + signal, + **{ + 'frame_length': frame_length, + 'frame_space': 5.0, + 'nccf_thresh1': 0.25, + 'tda_frame_length': 25.0 + }) + pitch = pitch.samp_interp[None, None, :] if args.interp else pitch.samp_values[None, None, :] + pitch = pitch[0, 0] + f0_path = wav_path.replace(".wav", ".yaapt") + f0_path += ".interp.f0" if args.interp else ".f0" + np.save(f0_path, pitch) + + +def main(): + with Pool(args.n_workers) as p: + r = list(tqdm(p.imap(extract_f0, tsv_lines), total=len(tsv_lines))) + + +if __name__ == "__main__": + main() diff --git a/examples/emotion_conversion/preprocess/process_km.py b/examples/emotion_conversion/preprocess/process_km.py new file mode 100644 index 0000000000..864a022105 --- /dev/null +++ b/examples/emotion_conversion/preprocess/process_km.py @@ -0,0 +1,40 @@ +import sys +import argparse +from tqdm import tqdm +from build_emov_translation_manifests import dedup, remove_under_k + + +if __name__ == "__main__": + """ + this is a standalone script to process a km file + specifically, to dedup or remove tokens that repeat less + than k times in a row + """ + parser = argparse.ArgumentParser(description="") + parser.add_argument("km", type=str, help="path to km file") + parser.add_argument("--dedup", action='store_true') + parser.add_argument("--remove-under-k", type=int, default=0) + parser.add_argument("--output", default=None) + args = parser.parse_args() + + if not args.dedup and args.remove_under_k == 0: + print("nothing to do! quitting...") + sys.exit(0) + + km = open(args.km, "r").readlines() + out = [] + for line in tqdm(km): + if args.remove_under_k > 0: + line = remove_under_k(line, args.remove_under_k) + if args.dedup: + line = dedup(line) + out.append(line) + + path = args.km if args.output is None else args.output + if args.remove_under_k > 0: + path = path.replace(".km", f"-k{args.remove_under_k}.km") + if args.dedup: + path = path.replace(".km", f"-deduped.km") + + open(path, "w").writelines(out) + print(f"written to {path}") diff --git a/examples/emotion_conversion/preprocess/split_emov_km_tsv_by_uttid.py b/examples/emotion_conversion/preprocess/split_emov_km_tsv_by_uttid.py new file mode 100644 index 0000000000..94221afba7 --- /dev/null +++ b/examples/emotion_conversion/preprocess/split_emov_km_tsv_by_uttid.py @@ -0,0 +1,70 @@ +from pathlib import Path +import os +import sys +import argparse +import random +import numpy as np +from tqdm import tqdm +from sklearn.model_selection import train_test_split +from build_translation_manifests import get_utt_id + + +def train_val_test_split(tsv_lines, km_lines, valid_percent, test_percent, seed=42): + utt_ids = list(sorted(set([get_utt_id(x) for x in tsv_lines]))) + utt_ids, valid_utt_ids, _, _ = train_test_split(utt_ids, utt_ids, test_size=valid_percent, shuffle=True, random_state=seed) + train_utt_ids, test_utt_ids, _, _ = train_test_split(utt_ids, utt_ids, test_size=test_percent, shuffle=True, random_state=seed) + + train_idx = [i for i, line in enumerate(tsv_lines) if get_utt_id(line) in train_utt_ids] + valid_idx = [i for i, line in enumerate(tsv_lines) if get_utt_id(line) in valid_utt_ids] + test_idx = [i for i, line in enumerate(tsv_lines) if get_utt_id(line) in test_utt_ids] + + train_tsv, train_km = [tsv_lines[i] for i in train_idx], [km_lines[i] for i in train_idx] + valid_tsv, valid_km = [tsv_lines[i] for i in valid_idx], [km_lines[i] for i in valid_idx] + test_tsv, test_km = [tsv_lines[i] for i in test_idx], [km_lines[i] for i in test_idx] + + print(f"train {len(train_km)}") + print(f"valid {len(valid_km)}") + print(f"test {len(test_km)}") + + return train_tsv, train_km, valid_tsv, valid_km, test_tsv, test_km + + +if __name__ == "__main__": + """ + this is a standalone script to process a km file + specifically, to dedup or remove tokens that repeat less + than k times in a row + """ + parser = argparse.ArgumentParser(description="") + parser.add_argument("tsv", type=str, help="path to tsv file") + parser.add_argument("km", type=str, help="path to km file") + parser.add_argument("--destdir", required=True, type=str) + parser.add_argument("--valid-percent", type=float, default=0.05, help="percent to allocate to validation set") + parser.add_argument("--test-percent", type=float, default=0.05, help="percent to allocate to test set") + parser.add_argument("--seed", type=int, default=42, help="") + args = parser.parse_args() + + np.random.seed(args.seed) + random.seed(args.seed) + + os.makedirs(args.destdir, exist_ok=True) + km = open(args.km, "r").readlines() + tsv = open(args.tsv, "r").readlines() + root, tsv = tsv[0], tsv[1:] + + assert args.tsv.endswith(".tsv") and args.km.endswith(".km") + assert len(tsv) == len(km) + + train_tsv, train_km, valid_tsv, valid_km, test_tsv, test_km = train_val_test_split(tsv, km, args.valid_percent, args.test_percent, args.seed) + + assert len(train_tsv) + len(valid_tsv) + len(test_tsv) == len(tsv) + assert len(train_tsv) == len(train_km) and len(valid_tsv) == len(valid_km) and len(test_tsv) == len(test_km) + + dir = Path(args.destdir) + open(dir / f"train.tsv", "w").writelines([root] + train_tsv) + open(dir / f"valid.tsv", "w").writelines([root] + valid_tsv) + open(dir / f"test.tsv", "w").writelines([root] + test_tsv) + open(dir / f"train.km", "w").writelines(train_km) + open(dir / f"valid.km", "w").writelines(valid_km) + open(dir / f"test.km", "w").writelines(test_km) + print("done") diff --git a/examples/emotion_conversion/preprocess/split_km.py b/examples/emotion_conversion/preprocess/split_km.py new file mode 100644 index 0000000000..d145fc2bde --- /dev/null +++ b/examples/emotion_conversion/preprocess/split_km.py @@ -0,0 +1,50 @@ +from pathlib import Path +import os +import argparse +import random +import numpy as np +from sklearn.utils import shuffle + + +if __name__ == "__main__": + """ + this is a standalone script to process a km file + specifically, to dedup or remove tokens that repeat less + than k times in a row + """ + parser = argparse.ArgumentParser(description="") + parser.add_argument("km", type=str, help="path to km file") + parser.add_argument("--destdir", required=True, type=str) + parser.add_argument("--valid-percent", type=float, default=0.05, help="percent to allocate to validation set") + parser.add_argument("--test-percent", type=float, default=0.05, help="percent to allocate to test set") + parser.add_argument("-sh", "--shuffle", action="store_true", help="path to km file") + parser.add_argument("--seed", type=int, default=42, help="") + args = parser.parse_args() + + np.random.seed(args.seed) + random.seed(args.seed) + + os.makedirs(args.destdir, exist_ok=True) + km = open(args.km, "r").readlines() + + if args.shuffle: + km = shuffle(km) + print(f"shuffled") + + N = len(km) + N_tt = int(N * args.test_percent) + N_cv = int(N * args.valid_percent) + N_tr = N - N_tt - N_cv + + train_km = km[:N_tr] + valid_km = km[N_tr:N_tr + N_cv] + test_km = km[N_tr + N_cv:] + + dir = Path(args.destdir) + open(dir / f"train.km", "w").writelines(train_km) + open(dir / f"valid.km", "w").writelines(valid_km) + open(dir / f"test.km", "w").writelines(test_km) + print(f"train: {len(train_km)}") + print(f"valid: {len(valid_km)}") + print(f"test: {len(test_km)}") + print("done") diff --git a/examples/emotion_conversion/preprocess/split_km_tsv.py b/examples/emotion_conversion/preprocess/split_km_tsv.py new file mode 100644 index 0000000000..2113aa718d --- /dev/null +++ b/examples/emotion_conversion/preprocess/split_km_tsv.py @@ -0,0 +1,65 @@ +from pathlib import Path +import os +import argparse +import random +import numpy as np +from sklearn.utils import shuffle + + +if __name__ == "__main__": + """ + this is a standalone script to process a km file + specifically, to dedup or remove tokens that repeat less + than k times in a row + """ + parser = argparse.ArgumentParser(description="") + parser.add_argument("tsv", type=str, help="path to tsv file") + parser.add_argument("km", type=str, help="path to km file") + parser.add_argument("--destdir", required=True, type=str) + parser.add_argument("--valid-percent", type=float, default=0.05, help="percent to allocate to validation set") + parser.add_argument("--test-percent", type=float, default=0.05, help="percent to allocate to test set") + parser.add_argument("-sh", "--shuffle", action="store_true", help="path to km file") + parser.add_argument("--seed", type=int, default=42, help="") + args = parser.parse_args() + + np.random.seed(args.seed) + random.seed(args.seed) + + os.makedirs(args.destdir, exist_ok=True) + km = open(args.km, "r").readlines() + tsv = open(args.tsv, "r").readlines() + root, tsv = tsv[0], tsv[1:] + + assert args.tsv.endswith(".tsv") and args.km.endswith(".km") + assert len(tsv) == len(km) + + if args.shuffle: + tsv, km = shuffle(tsv, km) + print(f"shuffled") + + N = len(tsv) + N_tt = int(N * args.test_percent) + N_cv = int(N * args.valid_percent) + N_tr = N - N_tt - N_cv + + train_tsv = tsv[:N_tr] + valid_tsv = tsv[N_tr:N_tr + N_cv] + test_tsv = tsv[N_tr + N_cv:] + train_km = km[:N_tr] + valid_km = km[N_tr:N_tr + N_cv] + test_km = km[N_tr + N_cv:] + + assert len(train_tsv) + len(valid_tsv) + len(test_tsv) == len(tsv) + assert len(train_tsv) == len(train_km) and len(valid_tsv) == len(valid_km) and len(test_tsv) == len(test_km) + + dir = Path(args.destdir) + open(dir / f"train.tsv", "w").writelines([root] + train_tsv) + open(dir / f"valid.tsv", "w").writelines([root] + valid_tsv) + open(dir / f"test.tsv", "w").writelines([root] + test_tsv) + open(dir / f"train.km", "w").writelines(train_km) + open(dir / f"valid.km", "w").writelines(valid_km) + open(dir / f"test.km", "w").writelines(test_km) + print(f"train: {len(train_km)}") + print(f"valid: {len(valid_km)}") + print(f"test: {len(test_km)}") + print("done") diff --git a/examples/emotion_conversion/requirements.txt b/examples/emotion_conversion/requirements.txt new file mode 100644 index 0000000000..fc94c5a547 --- /dev/null +++ b/examples/emotion_conversion/requirements.txt @@ -0,0 +1,11 @@ +scipy +einops +amfm_decompy +joblib +numba +decorator +requests +appdirs +packaging +six +sklearn diff --git a/examples/emotion_conversion/synthesize.py b/examples/emotion_conversion/synthesize.py new file mode 100644 index 0000000000..327fdaf4ea --- /dev/null +++ b/examples/emotion_conversion/synthesize.py @@ -0,0 +1,322 @@ +import logging +import argparse +import random +import sys +import os +import numpy as np +import torch +import soundfile as sf +import shutil +import librosa +import json +from pathlib import Path +from tqdm import tqdm +import amfm_decompy.basic_tools as basic +import amfm_decompy.pYAAPT as pYAAPT + +dir_path = os.path.dirname(__file__) +resynth_path = os.path.dirname(os.path.abspath(__file__)) + "/speech-resynthesis" +sys.path.append(resynth_path) + +from models import CodeGenerator +from inference import scan_checkpoint, load_checkpoint, generate +from emotion_models.pitch_predictor import load_ckpt as load_pitch_predictor +from emotion_models.duration_predictor import load_ckpt as load_duration_predictor +from dataset import load_audio, MAX_WAV_VALUE, parse_style, parse_speaker, EMOV_SPK2ID, EMOV_STYLE2ID + + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [%(levelname)s] %(message)s', + handlers=[logging.FileHandler('debug.log'), logging.StreamHandler()] +) +logger = logging.getLogger(__name__) + + +class AttrDict(dict): + def __init__(self, *args, **kwargs): + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self + + +def parse_generation_file(fname): + lines = open(fname).read() + lines = lines.split('\n') + + results = {} + for l in lines: + if len(l) == 0: + continue + + if l[0] == 'H': + parts = l[2:].split('\t') + if len(parts) == 2: + sid, utt = parts + else: + sid, _, utt = parts + sid = int(sid) + utt = [int(x) for x in utt.split()] + if sid in results: + results[sid]['H'] = utt + else: + results[sid] = {'H': utt} + elif l[0] == 'S': + sid, utt = l[2:].split('\t') + sid = int(sid) + utt = [x for x in utt.split()] + if sid in results: + results[sid]['S'] = utt + else: + results[sid] = {'S': utt} + elif l[0] == 'T': + sid, utt = l[2:].split('\t') + sid = int(sid) + utt = [int(x) for x in utt.split()] + if sid in results: + results[sid]['T'] = utt + else: + results[sid] = {'T': utt} + + for d, result in results.items(): + if 'H' not in result: + result['H'] = result['S'] + + return results + + +def get_code_to_fname(manifest, tokens): + if tokens is None: + code_to_fname = {} + with open(manifest) as f: + for line in f: + line = line.strip() + fname, code = line.split() + code = code.replace(',', ' ') + code_to_fname[code] = fname + + return code_to_fname + + with open(manifest) as f: + fnames = [l.strip() for l in f.readlines()] + root = Path(fnames[0]) + fnames = fnames[1:] + if '\t' in fnames[0]: + fnames = [x.split()[0] for x in fnames] + + with open(tokens) as f: + codes = [l.strip() for l in f.readlines()] + + code_to_fname = {} + for fname, code in zip(fnames, codes): + code = code.replace(',', ' ') + code_to_fname[code] = str(root / fname) + + return root, code_to_fname + + +def code_to_str(s): + k = ' '.join([str(x) for x in s]) + return k + + +def get_praat_f0(audio, rate=16000, interp=False): + frame_length = 20.0 + to_pad = int(frame_length / 1000 * rate) // 2 + + f0s = [] + for y in audio.astype(np.float64): + y_pad = np.pad(y.squeeze(), (to_pad, to_pad), "constant", constant_values=0) + signal = basic.SignalObj(y_pad, rate) + pitch = pYAAPT.yaapt(signal, **{'frame_length': frame_length, 'frame_space': 5.0, 'nccf_thresh1': 0.25, + 'tda_frame_length': 25.0}) + if interp: + f0s += [pitch.samp_interp[None, None, :]] + else: + f0s += [pitch.samp_values[None, None, :]] + + f0 = np.vstack(f0s) + return f0 + + +def generate_from_code(generator, h, code, spkr=None, f0=None, gst=None, device="cpu"): + batch = { + 'code': torch.LongTensor(code).to(device).view(1, -1), + } + if spkr is not None: + batch['spkr'] = spkr.to(device).unsqueeze(0) + if f0 is not None: + batch['f0'] = f0.to(device) + if gst is not None: + batch['style'] = gst.to(device) + + with torch.no_grad(): + audio, rtf = generate(h, generator, batch) + audio = librosa.util.normalize(audio / 2 ** 15) + + return audio + + +@torch.no_grad() +def synth(argv, interactive=False): + parser = argparse.ArgumentParser() + parser.add_argument('--result-path', type=Path, help='Translation Model Output', required=True) + parser.add_argument('--data', type=Path, help='a directory with the files: src.tsv, src.km, trg.tsv, trg.km, orig.tsv, orig.km') + parser.add_argument("--orig-tsv", default="/checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz/data.tsv") + parser.add_argument("--orig-km", default="/checkpoint/felixkreuk/datasets/emov/manifests/emov_16khz/core_manifests/emov_16khz_km_100/data.km") + + parser.add_argument('--checkpoint-file', type=Path, help='Generator Checkpoint', required=True) + parser.add_argument('--dur-model', type=Path, help='a token duration prediction model (if tokens were deduped)') + parser.add_argument('--f0-model', type=Path, help='a f0 prediction model') + + parser.add_argument('-s', '--src-emotion', default=None) + parser.add_argument('-t', '--trg-emotion', default=None) + parser.add_argument('-N', type=int, default=10) + parser.add_argument('--split', default="test") + + parser.add_argument('--outdir', type=Path, default=Path('results')) + parser.add_argument('--orig-filename', action='store_true') + + parser.add_argument('--device', type=int, default=0) + a = parser.parse_args(argv) + + seed = 52 + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + + if os.path.isdir(a.checkpoint_file): + config_file = os.path.join(a.checkpoint_file, 'config.json') + else: + config_file = os.path.join(os.path.split(a.checkpoint_file)[0], 'config.json') + with open(config_file) as f: + data = f.read() + json_config = json.loads(data) + h = AttrDict(json_config) + + generator = CodeGenerator(h).to(a.device) + if os.path.isdir(a.checkpoint_file): + cp_g = scan_checkpoint(a.checkpoint_file, 'g_') + else: + cp_g = a.checkpoint_file + state_dict_g = load_checkpoint(cp_g) + generator.load_state_dict(state_dict_g['generator']) + + generator.eval() + generator.remove_weight_norm() + + dur_models = { + "neutral": load_duration_predictor(f"{a.dur_model}/neutral.ckpt"), + "amused": load_duration_predictor(f"{a.dur_model}/amused.ckpt"), + "disgusted": load_duration_predictor(f"{a.dur_model}/disgusted.ckpt"), + "angry": load_duration_predictor(f"{a.dur_model}/angry.ckpt"), + "sleepy": load_duration_predictor(f"{a.dur_model}/sleepy.ckpt"), + } + logger.info(f"loaded duration prediction model from {a.dur_model}") + + f0_model = load_pitch_predictor(a.f0_model).to(a.device) + logger.info(f"loaded f0 prediction model from {a.f0_model}") + + # we need to know how to map code back to the filename + # (if we want the original files names as output) + results = parse_generation_file(a.result_path) + _, src_code_to_fname = get_code_to_fname(f'{a.data}/files.{a.split}.{a.src_emotion}', f'{a.data}/{a.split}.{a.src_emotion}') + _, tgt_code_to_fname = get_code_to_fname(f'{a.data}/files.{a.split}.{a.trg_emotion}', f'{a.data}/{a.split}.{a.trg_emotion}') + + # we need the originals (before dedup) to get the ground-truth durations + orig_tsv = open(a.orig_tsv, 'r').readlines() + orig_tsv_root, orig_tsv = orig_tsv[0].strip(), orig_tsv[1:] + orig_km = open(a.orig_km, 'r').readlines() + fname_to_idx = {orig_tsv_root + "/" + line.split("\t")[0]: i for i, line in enumerate(orig_tsv)} + + outdir = a.outdir + outdir.mkdir(parents=True, exist_ok=True) + (outdir / '0-source').mkdir(exist_ok=True) + (outdir / '1-src-tokens-src-style-src-f0').mkdir(exist_ok=True) + (outdir / '2-src-tokens-trg-style-src-f0').mkdir(exist_ok=True) + (outdir / '2.5-src-tokens-trg-style-src-f0').mkdir(exist_ok=True) + (outdir / '3-src-tokens-trg-style-pred-f0').mkdir(exist_ok=True) + (outdir / '4-gen-tokens-trg-style-pred-f0').mkdir(exist_ok=True) + (outdir / '5-target').mkdir(exist_ok=True) + + N = 0 + results = list(results.items()) + random.shuffle(results) + for i, (sid, result) in tqdm(enumerate(results)): + N += 1 + if N > a.N and a.N != -1: + break + + if '[' in result['S'][0]: + result['S'] = result['S'][1:] + if '_' in result['S'][-1]: + result['S'] = result['S'][:-1] + src_ref = src_code_to_fname[code_to_str(result['S'])] + trg_ref = tgt_code_to_fname[code_to_str(result['T'])] + + src_style, trg_style = None, None + src_spkr, trg_spkr = None, None + src_f0 = None + src_audio = (load_audio(src_ref)[0] / MAX_WAV_VALUE) * 0.95 + trg_audio = (load_audio(trg_ref)[0] / MAX_WAV_VALUE) * 0.95 + src_audio = torch.FloatTensor(src_audio).unsqueeze(0).cuda() + trg_audio = torch.FloatTensor(trg_audio).unsqueeze(0).cuda() + + src_spkr = parse_speaker(src_ref, h.multispkr) + src_spkr = src_spkr if src_spkr in EMOV_SPK2ID else random.choice(list(EMOV_SPK2ID.keys())) + src_spkr = EMOV_SPK2ID[src_spkr] + src_spkr = torch.LongTensor([src_spkr]) + trg_spkr = parse_speaker(trg_ref, h.multispkr) + trg_spkr = trg_spkr if trg_spkr in EMOV_SPK2ID else random.choice(list(EMOV_SPK2ID.keys())) + trg_spkr = EMOV_SPK2ID[trg_spkr] + trg_spkr = torch.LongTensor([trg_spkr]) + + src_style = EMOV_STYLE2ID[a.src_emotion] + src_style = torch.LongTensor([src_style]).cuda() + trg_style_str = a.trg_emotion + trg_style = EMOV_STYLE2ID[a.trg_emotion] + trg_style = torch.LongTensor([trg_style]).cuda() + + src_tokens = list(map(int, orig_km[fname_to_idx[src_ref]].strip().split(" "))) + src_tokens = torch.LongTensor(src_tokens).unsqueeze(0) + src_tokens_dur_pred = torch.LongTensor(list(map(int, result['S']))).unsqueeze(0) + src_tokens_dur_pred = dur_models[trg_style_str].inflate_input(src_tokens_dur_pred) + gen_tokens = torch.LongTensor(result['H']).unsqueeze(0) + gen_tokens = dur_models[trg_style_str].inflate_input(gen_tokens) + trg_tokens = torch.LongTensor(result['T']).unsqueeze(0) + trg_tokens = dur_models[trg_style_str].inflate_input(trg_tokens) + + src_f0 = get_praat_f0(src_audio.unsqueeze(0).cpu().numpy()) + src_f0 = torch.FloatTensor(src_f0).cuda() + + pred_src_f0 = f0_model.inference(torch.LongTensor(src_tokens).to(a.device), src_spkr, trg_style).unsqueeze(0) + pred_src_dur_pred_f0 = f0_model.inference(torch.LongTensor(src_tokens_dur_pred).to(a.device), src_spkr, trg_style).unsqueeze(0) + pred_gen_f0 = f0_model.inference(torch.LongTensor(gen_tokens).to(a.device), src_spkr, trg_style).unsqueeze(0) + pred_trg_f0 = f0_model.inference(torch.LongTensor(trg_tokens).to(a.device), src_spkr, trg_style).unsqueeze(0) + + if a.orig_filename: + path = src_code_to_fname[code_to_str(result['S'])] + sid = str(sid) + "__" + Path(path).stem + shutil.copy(src_code_to_fname[code_to_str(result['S'])], outdir / '0-source' / f'{sid}.wav') + + audio = generate_from_code(generator, h, src_tokens, spkr=src_spkr, f0=src_f0, gst=src_style, device=a.device) + sf.write(outdir / '1-src-tokens-src-style-src-f0' / f'{sid}.wav', audio, samplerate=h.sampling_rate) + + audio = generate_from_code(generator, h, src_tokens, spkr=src_spkr, f0=src_f0, gst=trg_style, device=a.device) + sf.write(outdir / '2-src-tokens-trg-style-src-f0' / f'{sid}.wav', audio, samplerate=h.sampling_rate) + + audio = generate_from_code(generator, h, src_tokens_dur_pred, spkr=src_spkr, f0=src_f0, gst=trg_style, device=a.device) + sf.write(outdir / '2.5-src-tokens-trg-style-src-f0' / f'{sid}.wav', audio, samplerate=h.sampling_rate) + + audio = generate_from_code(generator, h, src_tokens_dur_pred, spkr=src_spkr, f0=pred_src_dur_pred_f0, gst=trg_style, device=a.device) + sf.write(outdir / '3-src-tokens-trg-style-pred-f0' / f'{sid}.wav', audio, samplerate=h.sampling_rate) + + audio = generate_from_code(generator, h, gen_tokens, spkr=src_spkr, f0=pred_gen_f0, gst=trg_style, device=a.device) + sf.write(outdir / '4-gen-tokens-trg-style-pred-f0' / f'{sid}.wav', audio, samplerate=h.sampling_rate) + + shutil.copy(tgt_code_to_fname[code_to_str(result['T'])], outdir / '5-target' / f'{sid}.wav') + + logger.info("Done.") + + +if __name__ == '__main__': + synth(sys.argv[1:]) From d871f6169f8185837d1c11fb28da56abfd83841c Mon Sep 17 00:00:00 2001 From: Alexei Baevski <alexei.b@gmail.com> Date: Mon, 12 Dec 2022 08:53:56 -0800 Subject: [PATCH 718/774] data2vec v2.0 (#4903) data2v2c 2.0 Co-authored-by: Arun Babu <arbabu@fb.com> Co-authored-by: Wei-Ning Hsu <wnhsu@csail.mit.edu> --- examples/data2vec/README.md | 122 +++ examples/data2vec/__init__.py | 0 .../classification/base_classification.yaml | 70 ++ .../classification/run_config/slurm_1.yaml | 35 + .../classification/run_config/slurm_1g.yaml | 35 + .../classification/run_config/slurm_2.yaml | 35 + .../config/audio/pretraining/audioset.yaml | 91 ++ .../audio/pretraining/run_config/local.yaml | 15 + .../audio/pretraining/run_config/slurm_1.yaml | 37 + .../pretraining/run_config/slurm_1_aws.yaml | 36 + .../audio/pretraining/run_config/slurm_2.yaml | 37 + .../pretraining/run_config/slurm_2_aws.yaml | 37 + .../audio/pretraining/run_config/slurm_3.yaml | 36 + .../audio/pretraining/run_config/slurm_4.yaml | 36 + .../pretraining/run_config/slurm_4_aws.yaml | 37 + .../pretraining/run_config/slurm_6_aws.yaml | 36 + .../pretraining/run_config/slurm_8_aws.yaml | 36 + .../text/pretraining/run_config/local.yaml | 15 + .../pretraining/run_config/slurm_1_aws.yaml | 37 + .../text/pretraining/run_config/slurm_2.yaml | 37 + .../pretraining/run_config/slurm_2_aws.yaml | 37 + .../text/pretraining/run_config/slurm_3.yaml | 36 + .../text/pretraining/run_config/slurm_4.yaml | 36 + .../pretraining/run_config/slurm_4_aws.yaml | 41 + .../pretraining/run_config/slurm_8_aws.yaml | 41 + .../config/v2/base_audio_only_task.yaml | 113 +++ .../config/v2/base_images_only_task.yaml | 116 +++ .../config/v2/base_text_only_task.yaml | 112 +++ .../config/v2/huge_images14_only_task.yaml | 122 +++ .../config/v2/huge_images_only_task.yaml | 120 +++ .../config/v2/large_audio_only_task.yaml | 122 +++ .../config/v2/large_images_only_task.yaml | 120 +++ .../config/v2/large_text_only_task.yaml | 112 +++ .../v2/large_text_only_task_pgrp_1M.yaml | 123 +++ .../data2vec/config/v2/run_config/local.yaml | 15 + .../config/v2/run_config/slurm_1.yaml | 37 + .../config/v2/run_config/slurm_1_aws.yaml | 37 + .../config/v2/run_config/slurm_2.yaml | 37 + .../config/v2/run_config/slurm_2_aws.yaml | 39 + .../config/v2/run_config/slurm_3.yaml | 36 + .../config/v2/run_config/slurm_4.yaml | 36 + .../config/v2/run_config/slurm_4_aws.yaml | 37 + .../config/v2/run_config/slurm_6_aws.yaml | 36 + .../config/v2/run_config/slurm_8.yaml | 37 + .../config/v2/run_config/slurm_8_aws.yaml | 36 + .../config/v2/text_finetuning/cola.yaml | 60 ++ .../config/v2/text_finetuning/mnli.yaml | 60 ++ .../config/v2/text_finetuning/mrpc.yaml | 60 ++ .../config/v2/text_finetuning/qnli.yaml | 59 ++ .../config/v2/text_finetuning/qqp.yaml | 60 ++ .../config/v2/text_finetuning/rte.yaml | 59 ++ .../v2/text_finetuning/run_config/local.yaml | 15 + .../config/v2/text_finetuning/sst_2.yaml | 59 ++ .../config/v2/text_finetuning/sts_b.yaml | 61 ++ .../config/vision/finetuning/imagenet.yaml | 52 ++ .../vision/finetuning/mae_imagenet_clean.yaml | 65 ++ .../finetuning/mae_imagenet_huge_clean.yaml | 68 ++ .../finetuning/mae_imagenet_large_clean.yaml | 68 ++ .../vision/finetuning/run_config/local.yaml | 15 + .../vision/finetuning/run_config/slurm_1.yaml | 37 + .../finetuning/run_config/slurm_1_aws.yaml | 36 + .../vision/finetuning/run_config/slurm_2.yaml | 38 + .../finetuning/run_config/slurm_2_aws.yaml | 38 + .../vision/finetuning/run_config/slurm_3.yaml | 36 + .../vision/finetuning/run_config/slurm_4.yaml | 36 + .../finetuning/run_config/slurm_4_aws.yaml | 36 + .../finetuning/run_config/slurm_6_aws.yaml | 36 + .../finetuning/run_config/slurm_8_aws.yaml | 36 + .../vision/pretraining/base_imagenet.yaml | 52 ++ .../pretraining/base_imagenet_d2v1.yaml | 64 ++ .../vision/pretraining/base_mae_imagenet.yaml | 64 ++ .../vision/pretraining/run_config/local.yaml | 15 + .../pretraining/run_config/slurm_1.yaml | 37 + .../pretraining/run_config/slurm_1_aws.yaml | 36 + .../pretraining/run_config/slurm_2.yaml | 38 + .../pretraining/run_config/slurm_2_aws.yaml | 37 + .../pretraining/run_config/slurm_3.yaml | 36 + .../pretraining/run_config/slurm_4.yaml | 36 + .../pretraining/run_config/slurm_4_aws.yaml | 36 + .../pretraining/run_config/slurm_6_aws.yaml | 36 + .../pretraining/run_config/slurm_8_aws.yaml | 36 + examples/data2vec/data/__init__.py | 17 + .../data2vec/data/add_class_target_dataset.py | 63 ++ examples/data2vec/data/image_dataset.py | 127 +++ .../data/mae_finetuning_image_dataset.py | 135 +++ examples/data2vec/data/mae_image_dataset.py | 418 +++++++++ examples/data2vec/data/modality.py | 14 + examples/data2vec/data/path_dataset.py | 64 ++ examples/data2vec/fb_convert_beit_cp.py | 165 ++++ examples/data2vec/models/__init__.py | 0 .../data2vec/models/audio_classification.py | 614 +++++++++++++ examples/data2vec/models/data2vec2.py | 813 +++++++++++++++++ .../models/data2vec_image_classification.py | 143 +++ .../models/data2vec_text_classification.py | 141 +++ examples/data2vec/models/data2vec_vision.py | 727 +++++++++++++++ examples/data2vec/models/mae.py | 825 ++++++++++++++++++ .../models/mae_image_classification.py | 386 ++++++++ .../data2vec/models/modalities/__init__.py | 0 examples/data2vec/models/modalities/audio.py | 192 ++++ examples/data2vec/models/modalities/base.py | 684 +++++++++++++++ examples/data2vec/models/modalities/images.py | 256 ++++++ .../data2vec/models/modalities/modules.py | 589 +++++++++++++ examples/data2vec/models/modalities/text.py | 161 ++++ examples/data2vec/models/utils.py | 55 ++ .../scripts/convert_audioset_labels.py | 63 ++ .../multi/finetune_all_fair_aws_local_lr.sh | 18 + .../finetune_all_fair_aws_local_lr_nodep.sh | 16 + .../multi/finetune_all_fair_local_lr.sh | 28 + .../finetune_all_char_fair_aws_local_lr.sh | 17 + .../scripts/text/finetune_all_fair.sh | 21 + .../scripts/text/finetune_all_fair_aws.sh | 21 + .../text/finetune_all_fair_aws_local_lr.sh | 17 + .../scripts/text/finetune_all_fair_aws_lr.sh | 23 + .../text/finetune_all_fair_local_lr.sh | 25 + .../scripts/text/finetune_all_fair_nodep.sh | 19 + .../text/finetune_all_fair_nodep_aws.sh | 19 + .../finetune_all_fair_nodep_aws_local_lr.sh | 15 + .../text/finetune_all_fair_nodep_aws_lr.sh | 21 + .../finetune_all_fair_nodep_aws_lr_nopos.sh | 21 + .../finetune_all_large_fair_aws_local_lr.sh | 17 + .../text/finetune_all_large_fair_local_lr.sh | 26 + ...etune_all_large_fair_nodep_aws_local_lr.sh | 15 + .../finetune_sst2_qnli_sweep_fair_nodep.sh | 20 + examples/data2vec/scripts/text/glue.py | 34 + examples/data2vec/scripts/text/glue_lr.py | 143 +++ .../data2vec/scripts/text/unprocess_data.py | 188 ++++ examples/data2vec/scripts/text/valids.py | 301 +++++++ examples/data2vec/tasks/__init__.py | 18 + .../data2vec/tasks/audio_classification.py | 167 ++++ .../data2vec/tasks/image_classification.py | 129 +++ examples/data2vec/tasks/image_pretraining.py | 110 +++ .../tasks/mae_image_classification.py | 100 +++ .../data2vec/tasks/mae_image_pretraining.py | 119 +++ examples/data2vec/tasks/multimodal.py | 165 ++++ .../config/finetuning/run_config/local.yaml | 15 + .../finetuning/run_config/slurm_1g.yaml | 28 + .../finetuning/run_config/slurm_1g_aws.yaml | 25 + .../config/pretraining/run_config/local.yaml | 15 + .../pretraining/run_config/slurm_2.yaml | 37 + .../pretraining/run_config/slurm_2_aws.yaml | 39 + .../pretraining/run_config/slurm_3.yaml | 36 + .../pretraining/run_config/slurm_4.yaml | 36 + .../README.multilingual.pretraining.md | 26 + .../modules/monotonic_multihead_attention.py | 1 + .../tests/test_text_models.py | 2 +- .../new/conf/hydra/sweeper/ax_sil.yaml | 29 + .../speech_recognition/new/conf/infer.yaml | 2 + .../new/conf/run_config/fb_slurm_1.yaml | 28 + .../new/conf/run_config/fb_slurm_2g.yaml | 27 + .../config/finetuning/run_config/slurm_1.yaml | 26 + .../finetuning/run_config/slurm_16.yaml | 27 + .../finetuning/run_config/slurm_1_aws.yaml | 37 + .../finetuning/run_config/slurm_1_old.yaml | 27 + .../config/finetuning/run_config/slurm_2.yaml | 27 + .../finetuning/run_config/slurm_2_aws.yaml | 37 + .../finetuning/run_config/slurm_2g.yaml | 26 + .../config/finetuning/run_config/slurm_3.yaml | 27 + .../finetuning/run_config/slurm_4g.yaml | 26 + .../finetuning/run_config/slurm_4g_aws.yaml | 37 + .../config/finetuning/run_config/slurm_8.yaml | 26 + .../wav2vec/config/finetuning/vox_100h_2.yaml | 106 +++ .../config/finetuning/vox_100h_2_aws.yaml | 82 ++ .../wav2vec/config/finetuning/vox_100h_3.yaml | 101 +++ .../wav2vec/config/finetuning/vox_10h_2.yaml | 102 +++ .../config/finetuning/vox_10h_2_aws.yaml | 81 ++ .../config/finetuning/vox_10h_aws.yaml | 104 +++ .../config/finetuning/vox_10h_aws_v100.yaml | 102 +++ .../wav2vec/config/finetuning/vox_10m_2.yaml | 114 +++ .../config/finetuning/vox_10m_2_aws.yaml | 114 +++ .../wav2vec/config/finetuning/vox_10m_3.yaml | 105 +++ .../wav2vec/config/finetuning/vox_1h_2.yaml | 104 +++ .../config/finetuning/vox_1h_2_aws.yaml | 114 +++ .../wav2vec/config/finetuning/vox_1h_3.yaml | 104 +++ .../wav2vec/config/finetuning/vox_1h_4.yaml | 104 +++ .../wav2vec/config/finetuning/vox_1h_aws.yaml | 80 ++ .../wav2vec/config/finetuning/vox_960h_2.yaml | 105 +++ .../config/finetuning/vox_960h_2_aws.yaml | 82 ++ .../wav2vec/config/finetuning/vox_960h_3.yaml | 101 +++ fairseq/checkpoint_utils.py | 21 +- fairseq/config/fb_run_config/slurm.yaml | 29 + fairseq/criterions/__init__.py | 4 +- fairseq/criterions/ctc.py | 12 +- .../label_smoothed_cross_entropy.py | 3 +- fairseq/criterions/model_criterion.py | 33 +- fairseq/criterions/sentence_prediction.py | 151 +++- fairseq/data/__init__.py | 5 + fairseq/data/add_class_target_dataset.py | 79 ++ fairseq/data/audio/multi_modality_dataset.py | 29 +- fairseq/data/audio/raw_audio_dataset.py | 178 ++-- fairseq/data/data_utils.py | 604 ++++++++++++- fairseq/data/indexed_dataset.py | 5 + fairseq/data/iterators.py | 12 +- fairseq/data/mask_tokens_dataset.py | 202 ++--- fairseq/data/padding_mask_dataset.py | 38 + fairseq/data/subsample_dataset.py | 11 +- fairseq/dataclass/configs.py | 1 + fairseq/dataclass/utils.py | 21 +- fairseq/distributed/utils.py | 51 +- fairseq/iterative_refinement_generator.py | 4 +- fairseq/logging/meters.py | 30 + fairseq/logging/metrics.py | 20 + fairseq/models/__init__.py | 3 +- fairseq/models/fairseq_model.py | 5 + fairseq/models/wav2vec/wav2vec2_asr.py | 143 ++- fairseq/modules/__init__.py | 3 +- fairseq/modules/ema_module.py | 83 +- fairseq/modules/gumbel_vector_quantizer.py | 33 +- fairseq/modules/kmeans_vector_quantizer.py | 19 +- fairseq/modules/multihead_attention.py | 2 +- fairseq/modules/same_pad.py | 12 + fairseq/modules/transpose_last.py | 5 +- fairseq/nan_detector.py | 2 +- fairseq/optim/composite.py | 123 ++- fairseq/optim/fp16_optimizer.py | 5 + fairseq/optim/fused_adam.py | 3 + .../optim/lr_scheduler/cosine_lr_scheduler.py | 5 +- fairseq/registry.py | 6 +- fairseq/tasks/__init__.py | 6 +- fairseq/tasks/audio_finetuning.py | 1 + fairseq/tasks/audio_pretraining.py | 116 +-- fairseq/tasks/fairseq_task.py | 54 +- fairseq/tasks/masked_lm.py | 93 +- fairseq/tasks/sentence_prediction.py | 43 +- fairseq/trainer.py | 73 +- fairseq/utils.py | 4 +- fairseq_cli/hydra_validate.py | 188 ++++ fairseq_cli/train.py | 31 +- .../dependency_submitit_launcher/__init__.py | 3 + .../dependency_submitit_launcher/config.py | 23 + .../dependency_submitit_launcher/launcher.py | 121 +++ .../dependency_submitit_launcher/setup.py | 29 + setup.py | 4 +- tests/test_binaries.py | 7 + tests/test_ema.py | 16 +- tests/test_multihead_attention.py | 1 + tests/test_valid_subset_checks.py | 9 +- 236 files changed, 17324 insertions(+), 519 deletions(-) create mode 100644 examples/data2vec/__init__.py create mode 100644 examples/data2vec/config/audio/classification/base_classification.yaml create mode 100644 examples/data2vec/config/audio/classification/run_config/slurm_1.yaml create mode 100644 examples/data2vec/config/audio/classification/run_config/slurm_1g.yaml create mode 100644 examples/data2vec/config/audio/classification/run_config/slurm_2.yaml create mode 100644 examples/data2vec/config/audio/pretraining/audioset.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/local.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_1.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_1_aws.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_2.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_2_aws.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_3.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_4.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_4_aws.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_6_aws.yaml create mode 100644 examples/data2vec/config/audio/pretraining/run_config/slurm_8_aws.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/local.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/slurm_1_aws.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/slurm_2.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/slurm_2_aws.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/slurm_3.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/slurm_4.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/slurm_4_aws.yaml create mode 100644 examples/data2vec/config/text/pretraining/run_config/slurm_8_aws.yaml create mode 100644 examples/data2vec/config/v2/base_audio_only_task.yaml create mode 100644 examples/data2vec/config/v2/base_images_only_task.yaml create mode 100644 examples/data2vec/config/v2/base_text_only_task.yaml create mode 100644 examples/data2vec/config/v2/huge_images14_only_task.yaml create mode 100644 examples/data2vec/config/v2/huge_images_only_task.yaml create mode 100644 examples/data2vec/config/v2/large_audio_only_task.yaml create mode 100644 examples/data2vec/config/v2/large_images_only_task.yaml create mode 100644 examples/data2vec/config/v2/large_text_only_task.yaml create mode 100644 examples/data2vec/config/v2/large_text_only_task_pgrp_1M.yaml create mode 100644 examples/data2vec/config/v2/run_config/local.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_1.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_1_aws.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_2.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_2_aws.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_3.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_4.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_4_aws.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_6_aws.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_8.yaml create mode 100644 examples/data2vec/config/v2/run_config/slurm_8_aws.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/cola.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/mnli.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/mrpc.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/qnli.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/qqp.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/rte.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/run_config/local.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/sst_2.yaml create mode 100644 examples/data2vec/config/v2/text_finetuning/sts_b.yaml create mode 100644 examples/data2vec/config/vision/finetuning/imagenet.yaml create mode 100644 examples/data2vec/config/vision/finetuning/mae_imagenet_clean.yaml create mode 100644 examples/data2vec/config/vision/finetuning/mae_imagenet_huge_clean.yaml create mode 100644 examples/data2vec/config/vision/finetuning/mae_imagenet_large_clean.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/local.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_1.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_1_aws.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_2.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_2_aws.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_3.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_4.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_4_aws.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_6_aws.yaml create mode 100644 examples/data2vec/config/vision/finetuning/run_config/slurm_8_aws.yaml create mode 100644 examples/data2vec/config/vision/pretraining/base_imagenet.yaml create mode 100644 examples/data2vec/config/vision/pretraining/base_imagenet_d2v1.yaml create mode 100644 examples/data2vec/config/vision/pretraining/base_mae_imagenet.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/local.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_1.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_1_aws.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_2.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_2_aws.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_3.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_4.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_4_aws.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_6_aws.yaml create mode 100644 examples/data2vec/config/vision/pretraining/run_config/slurm_8_aws.yaml create mode 100644 examples/data2vec/data/__init__.py create mode 100644 examples/data2vec/data/add_class_target_dataset.py create mode 100644 examples/data2vec/data/image_dataset.py create mode 100644 examples/data2vec/data/mae_finetuning_image_dataset.py create mode 100644 examples/data2vec/data/mae_image_dataset.py create mode 100644 examples/data2vec/data/modality.py create mode 100644 examples/data2vec/data/path_dataset.py create mode 100644 examples/data2vec/fb_convert_beit_cp.py create mode 100644 examples/data2vec/models/__init__.py create mode 100644 examples/data2vec/models/audio_classification.py create mode 100644 examples/data2vec/models/data2vec2.py create mode 100644 examples/data2vec/models/data2vec_image_classification.py create mode 100644 examples/data2vec/models/data2vec_text_classification.py create mode 100644 examples/data2vec/models/data2vec_vision.py create mode 100644 examples/data2vec/models/mae.py create mode 100644 examples/data2vec/models/mae_image_classification.py create mode 100644 examples/data2vec/models/modalities/__init__.py create mode 100644 examples/data2vec/models/modalities/audio.py create mode 100644 examples/data2vec/models/modalities/base.py create mode 100644 examples/data2vec/models/modalities/images.py create mode 100644 examples/data2vec/models/modalities/modules.py create mode 100644 examples/data2vec/models/modalities/text.py create mode 100644 examples/data2vec/models/utils.py create mode 100644 examples/data2vec/scripts/convert_audioset_labels.py create mode 100755 examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr.sh create mode 100644 examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr_nodep.sh create mode 100755 examples/data2vec/scripts/multi/finetune_all_fair_local_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_char_fair_aws_local_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_aws.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_aws_local_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_aws_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_local_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_nodep.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_nodep_aws.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_local_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr_nopos.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_large_fair_aws_local_lr.sh create mode 100644 examples/data2vec/scripts/text/finetune_all_large_fair_local_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_all_large_fair_nodep_aws_local_lr.sh create mode 100755 examples/data2vec/scripts/text/finetune_sst2_qnli_sweep_fair_nodep.sh create mode 100644 examples/data2vec/scripts/text/glue.py create mode 100644 examples/data2vec/scripts/text/glue_lr.py create mode 100644 examples/data2vec/scripts/text/unprocess_data.py create mode 100644 examples/data2vec/scripts/text/valids.py create mode 100644 examples/data2vec/tasks/__init__.py create mode 100644 examples/data2vec/tasks/audio_classification.py create mode 100644 examples/data2vec/tasks/image_classification.py create mode 100644 examples/data2vec/tasks/image_pretraining.py create mode 100644 examples/data2vec/tasks/mae_image_classification.py create mode 100644 examples/data2vec/tasks/mae_image_pretraining.py create mode 100644 examples/data2vec/tasks/multimodal.py create mode 100644 examples/roberta/config/finetuning/run_config/local.yaml create mode 100644 examples/roberta/config/finetuning/run_config/slurm_1g.yaml create mode 100644 examples/roberta/config/finetuning/run_config/slurm_1g_aws.yaml create mode 100644 examples/roberta/config/pretraining/run_config/local.yaml create mode 100644 examples/roberta/config/pretraining/run_config/slurm_2.yaml create mode 100644 examples/roberta/config/pretraining/run_config/slurm_2_aws.yaml create mode 100644 examples/roberta/config/pretraining/run_config/slurm_3.yaml create mode 100644 examples/roberta/config/pretraining/run_config/slurm_4.yaml create mode 100644 examples/roberta/fb_multilingual/README.multilingual.pretraining.md create mode 100644 examples/speech_recognition/new/conf/hydra/sweeper/ax_sil.yaml create mode 100644 examples/speech_recognition/new/conf/run_config/fb_slurm_1.yaml create mode 100644 examples/speech_recognition/new/conf/run_config/fb_slurm_2g.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_1.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_16.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_1_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_1_old.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_2.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_2_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_2g.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_3.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_4g.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_4g_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/run_config/slurm_8.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_100h_2.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_100h_2_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_100h_3.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10h_2.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10h_2_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10h_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10h_aws_v100.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10m_2.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10m_2_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_10m_3.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_1h_2.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_1h_2_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_1h_3.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_1h_4.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_1h_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_960h_2.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_960h_2_aws.yaml create mode 100644 examples/wav2vec/config/finetuning/vox_960h_3.yaml create mode 100644 fairseq/config/fb_run_config/slurm.yaml create mode 100644 fairseq/data/add_class_target_dataset.py create mode 100644 fairseq/data/padding_mask_dataset.py create mode 100644 fairseq_cli/hydra_validate.py create mode 100644 hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/__init__.py create mode 100644 hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/config.py create mode 100644 hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/launcher.py create mode 100644 hydra_plugins/dependency_submitit_launcher/setup.py diff --git a/examples/data2vec/README.md b/examples/data2vec/README.md index 9fd05d8042..5b680ef8c0 100644 --- a/examples/data2vec/README.md +++ b/examples/data2vec/README.md @@ -1,3 +1,125 @@ +# data2vec 2.0 + +data2vec 2.0 improves the training efficiency of the original data2vec algorithm. We make the following improvements for efficiency considerations - we forward only the unmasked timesteps through the encoder, we use convolutional decoder and we use multimasking to amortize the compute overhead of the teacher model. You can find details in [Efficient Self-supervised Learning with Contextualized Target Representations for Vision, Speech and Language](https://ai.facebook.com/research/xyz) + +## Pretrained and finetuned models +### Vision +| Model | Finetuning split | Link +|---|---|--- +data2vec ViT-B | No fine-tuning | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/base_imagenet.pt) +data2vec ViT-B | Imagenet-1K | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/base_imagenet_ft.pt) +data2vec ViT-L | No fine-tuning | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/large_imagenet.pt) +data2vec ViT-L | Imagenet-1K | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/large_imagenet_ft.pt) +data2vec ViT-H | No fine-tuning | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/huge_imagenet.pt) +data2vec ViT-H | Imagenet-1K | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/huge_imagenet_ft.pt) + +Vision models only are license under CC-BY-NC. +### Speech + +| Model | Finetuning split | Dataset | Link +|---|---|---|--- +data2vec Base | No fine-tuning | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/base_libri.pt) +data2vec Base | 960 hours | [Librispeech](http://www.openslr.org/12) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/base_libri_960h.pt) +data2vec Large | No fine-tuning | [Libri-light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/large_vox.pt) +data2vec Large | 960 hours | [Libri-light](https://github.com/facebookresearch/libri-light) | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/large_vox_960h.pt) + +### NLP + +Model | Fine-tuning data | Dataset | Link +|---|---|---|---| +data2vec Base | No fine-tuning | Books + Wiki | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/nlp_base.pt) + +[//]: # (## Data Preparation) + +[//]: # () +[//]: # (### Vision) + +[//]: # (add details) + +[//]: # (### Speech) + +[//]: # (add details) + +[//]: # () +[//]: # (### NLP) + +[//]: # (add details) + + +## Commands to train different models using data2vec 2.0 + +### Vision + +Commands to pretrain different model configurations +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/v2 \ +--config-name base_images_only_task task.data=/path/to/dir +``` + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/v2 \ +--config-name large_images_only_task task.data=/path/to/dir +``` + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/v2 \ +--config-name huge_images14_only_task task.data=/path/to/dir +``` + +Commands to finetune different model configurations + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/vision/finetuning \ +--config-name mae_imagenet_clean task.data=/path/to/dir model.model_path=/path/to/pretrained/model +``` + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/vision/finetuning \ +--config-name mae_imagenet_large_clean task.data=/path/to/dir model.model_path=/path/to/pretrained/model +``` + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/vision/finetuning \ +--config-name mae_imagenet_huge_clean task.data=/path/to/dir model.model_path=/path/to/pretrained/model +``` + +### Speech + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/v2 \ +--config-name base_audio_only_task task.data=/path/to/manifests +``` + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/v2 \ +--config-name large_audio_only_task task.data=/path/to/manifests +``` + +Finetuning: + +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/wav2vec/config/finetuning --config-name vox_10h \ +task.data=/path/to/manifests model.w2v_path=/path/to/pretrained/model common.user_dir=examples/data2vec +``` + +Replace vox_10h with the right config depending on your model and fine-tuning split. +See examples/wav2vec/config/finetuning for all available configs. + +### NLP + +Commands to pretrain +```shell script +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/v2 \ +--config-name base_text_only_task task.data=/path/to/file +``` + +Commands to fine-tune all GLUE tasks +```shell script +$ task=cola # choose from [cola|qnli|mrpc|rte|sst_2|mnli|qqp|sts_b] +$ lr=1e-5 # sweep [1e-5|2e-5|4e-5|6e-5] for each task +$ python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/v2/text_finetuning \ +--config-name $task task.data=/path/to/file model.model_path=/path/to/pretrained/model "optimization.lr=[${lr}]" +``` # data2vec diff --git a/examples/data2vec/__init__.py b/examples/data2vec/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/data2vec/config/audio/classification/base_classification.yaml b/examples/data2vec/config/audio/classification/base_classification.yaml new file mode 100644 index 0000000000..fdb9c8d3d7 --- /dev/null +++ b/examples/data2vec/config/audio/classification/base_classification.yaml @@ -0,0 +1,70 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + all_gather_list_size: 70000 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + +checkpoint: + save_interval: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: mAP + maximize_best_checkpoint_metric: true + +task: + _name: audio_classification + data: ??? + normalize: true + labels: lbl + +dataset: + num_workers: 6 + max_tokens: 2560000 + skip_invalid_size_inputs_valid_test: true + valid_subset: eval + validate_interval: 5 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: model + can_sum: false + log_keys: + - _predictions + - _targets + +optimization: + max_update: 30000 + lr: [0.00006] # scratch 53-5 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: cosine + warmup_updates: 5000 + +model: + _name: audio_classification + model_path: ??? + apply_mask: true + mask_prob: 0.6 + mask_length: 5 # scratch 1 + mask_channel_prob: 0 + mask_channel_length: 64 + layerdrop: 0.1 + dropout: 0.1 + activation_dropout: 0.1 + attention_dropout: 0.2 + feature_grad_mult: 0 # scratch 1 + label_mixup: true + source_mixup: 0.5 + prediction_mode: lin_softmax # scratch average_sigmoid + diff --git a/examples/data2vec/config/audio/classification/run_config/slurm_1.yaml b/examples/data2vec/config/audio/classification/run_config/slurm_1.yaml new file mode 100644 index 0000000000..881a1583f8 --- /dev/null +++ b/examples/data2vec/config/audio/classification/run_config/slurm_1.yaml @@ -0,0 +1,35 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/classification/run_config/slurm_1g.yaml b/examples/data2vec/config/audio/classification/run_config/slurm_1g.yaml new file mode 100644 index 0000000000..de7894d9cf --- /dev/null +++ b/examples/data2vec/config/audio/classification/run_config/slurm_1g.yaml @@ -0,0 +1,35 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 1 + tasks_per_node: 1 + mem_gb: 100 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/classification/run_config/slurm_2.yaml b/examples/data2vec/config/audio/classification/run_config/slurm_2.yaml new file mode 100644 index 0000000000..b016cac9b5 --- /dev/null +++ b/examples/data2vec/config/audio/classification/run_config/slurm_2.yaml @@ -0,0 +1,35 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/audioset.yaml b/examples/data2vec/config/audio/pretraining/audioset.yaml new file mode 100644 index 0000000000..dd30fbedd5 --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/audioset.yaml @@ -0,0 +1,91 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec + +checkpoint: + save_interval: 1 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: /private/home/abaevski/data/audioset + max_sample_size: 320000 + min_sample_size: 32000 + normalize: true + +dataset: + num_workers: 6 + max_tokens: 3400000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 24 + ddp_backend: legacy_ddp + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var +# - avg_self_attn +# - weights + +optimization: + max_update: 200000 + lr: [0.0005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: cosine + warmup_updates: 10000 + +model: + _name: data2vec_audio + extractor_mode: layer_norm + encoder_layerdrop: 0.05 + dropout_input: 0.0 + dropout_features: 0.0 + feature_grad_mult: 1.0 + encoder_embed_dim: 768 + + mask_prob: 0.65 + mask_length: 10 + + loss_beta: 0 + loss_scale: null + + instance_norm_target_layer: true + layer_norm_targets: true + average_top_k_layers: 12 + + self_attn_norm_type: deepnorm + final_norm_type: deepnorm + + pos_conv_depth: 5 + conv_pos: 95 + + ema_decay: 0.999 + ema_end_decay: 0.9999 + ema_anneal_end_step: 30000 + ema_transformer_only: true + ema_layers_only: false + + require_same_masks: true + mask_dropout: 0 diff --git a/examples/data2vec/config/audio/pretraining/run_config/local.yaml b/examples/data2vec/config/audio/pretraining/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_1.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_1.yaml new file mode 100644 index 0000000000..732f018899 --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_1.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_1_aws.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_1_aws.yaml new file mode 100644 index 0000000000..e2bab5675a --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_1_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_2.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_2.yaml new file mode 100644 index 0000000000..ec53dc2a98 --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_2.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_2_aws.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_2_aws.yaml new file mode 100644 index 0000000000..70cc8cbb5b --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_2_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - task.post_save_script + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_3.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_3.yaml new file mode 100644 index 0000000000..14b47d14e6 --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_3.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 3 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_4.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_4.yaml new file mode 100644 index 0000000000..c54d735fb2 --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_4.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_4_aws.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_4_aws.yaml new file mode 100644 index 0000000000..0231b2690d --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_4_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - task.post_save_script + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_6_aws.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_6_aws.yaml new file mode 100644 index 0000000000..9a4e43a987 --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_6_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 6 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/audio/pretraining/run_config/slurm_8_aws.yaml b/examples/data2vec/config/audio/pretraining/run_config/slurm_8_aws.yaml new file mode 100644 index 0000000000..78c9f57aeb --- /dev/null +++ b/examples/data2vec/config/audio/pretraining/run_config/slurm_8_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 8 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/text/pretraining/run_config/local.yaml b/examples/data2vec/config/text/pretraining/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/data2vec/config/text/pretraining/run_config/slurm_1_aws.yaml b/examples/data2vec/config/text/pretraining/run_config/slurm_1_aws.yaml new file mode 100644 index 0000000000..4bac45a58d --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/slurm_1_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: '_' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir}/submitit + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec + max_num_timeout: 30 + exclude: a100-st-p4d24xlarge-471 diff --git a/examples/data2vec/config/text/pretraining/run_config/slurm_2.yaml b/examples/data2vec/config/text/pretraining/run_config/slurm_2.yaml new file mode 100644 index 0000000000..006a0f2116 --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/slurm_2.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/text/pretraining/run_config/slurm_2_aws.yaml b/examples/data2vec/config/text/pretraining/run_config/slurm_2_aws.yaml new file mode 100644 index 0000000000..4292198b4e --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/slurm_2_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: '_' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir}/submitit + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec + max_num_timeout: 30 + exclude: a100-st-p4d24xlarge-471 diff --git a/examples/data2vec/config/text/pretraining/run_config/slurm_3.yaml b/examples/data2vec/config/text/pretraining/run_config/slurm_3.yaml new file mode 100644 index 0000000000..0e1555d20f --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/slurm_3.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 3 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/text/pretraining/run_config/slurm_4.yaml b/examples/data2vec/config/text/pretraining/run_config/slurm_4.yaml new file mode 100644 index 0000000000..c54d735fb2 --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/slurm_4.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/text/pretraining/run_config/slurm_4_aws.yaml b/examples/data2vec/config/text/pretraining/run_config/slurm_4_aws.yaml new file mode 100644 index 0000000000..5df84cd6da --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/slurm_4_aws.yaml @@ -0,0 +1,41 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: '_' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir}/submitit + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec + max_num_timeout: 30 + exclude: a100-st-p4d24xlarge-471 + +distributed_training: + distributed_world_size: 32 + ddp_backend: legacy_ddp diff --git a/examples/data2vec/config/text/pretraining/run_config/slurm_8_aws.yaml b/examples/data2vec/config/text/pretraining/run_config/slurm_8_aws.yaml new file mode 100644 index 0000000000..5b32c23a66 --- /dev/null +++ b/examples/data2vec/config/text/pretraining/run_config/slurm_8_aws.yaml @@ -0,0 +1,41 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: '_' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir}/submitit + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 8 + name: pt + partition: wav2vec + max_num_timeout: 30 + exclude: a100-st-p4d24xlarge-471 + +distributed_training: + distributed_world_size: 64 + ddp_backend: legacy_ddp diff --git a/examples/data2vec/config/v2/base_audio_only_task.yaml b/examples/data2vec/config/v2/base_audio_only_task.yaml new file mode 100644 index 0000000000..65a9ab3e73 --- /dev/null +++ b/examples/data2vec/config/v2/base_audio_only_task.yaml @@ -0,0 +1,113 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + fp16_no_flatten_grads: false + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + save_interval: 1 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: /private/home/abaevski/data/librispeech/full + max_sample_size: 320000 + min_sample_size: 32000 + normalize: true + precompute_mask_config: {} + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 8 + ddp_backend: legacy_ddp + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +optimization: + max_update: 400000 + lr: [0.00075] + debug_param_names: true + +optimizer: + _name: adam + adam_betas: [ 0.9,0.98 ] + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: cosine + warmup_updates: 8000 + +model: + _name: data2vec_multi + + loss_beta: 0 + loss_scale: null + + depth: 12 + embed_dim: 768 + clone_batch: 8 + + ema_decay: 0.999 + ema_end_decay: 0.99999 + ema_anneal_end_step: 75000 + ema_encoder_only: false + + average_top_k_layers: 8 + instance_norm_target_layer: true + layer_norm_target_layer: false + layer_norm_targets: false + + layerdrop: 0.05 + norm_eps: 1e-5 + + supported_modality: AUDIO + + modalities: + audio: + feature_encoder_spec: '[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]' + conv_pos_depth: 5 + conv_pos_width: 95 + conv_pos_groups: 16 + prenet_depth: 0 + mask_prob: 0.5 + mask_prob_adjust: 0.05 + inverse_mask: false + mask_length: 5 + mask_noise_std: 0.01 + mask_dropout: 0 + add_masks: false + ema_local_encoder: false + use_alibi_encoder: true + prenet_layerdrop: 0.05 + prenet_dropout: 0.1 + learned_alibi_scale: true + learned_alibi_scale_per_head: true + decoder: + input_dropout: 0.1 + decoder_dim: 384 + decoder_groups: 16 + decoder_kernel: 7 + decoder_layers: 4 diff --git a/examples/data2vec/config/v2/base_images_only_task.yaml b/examples/data2vec/config/v2/base_images_only_task.yaml new file mode 100644 index 0000000000..ff0c247b13 --- /dev/null +++ b/examples/data2vec/config/v2/base_images_only_task.yaml @@ -0,0 +1,116 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: mae_image_pretraining + data: /datasets01/imagenet_full_size/061417/ + rebuild_batches: true + local_cache_path: /scratch/cache_abaevski/imagenet + key: source + precompute_mask_config: {} + +dataset: + num_workers: 10 + batch_size: 16 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +optimization: + max_update: 375300 + lr: [ 0.001 ] + debug_param_names: true + clip_norm: 4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 1e-3 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 50040 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + ema_decay: 0.9998 + ema_end_decay: 0.99999 + ema_anneal_end_step: 100000 + instance_norm_target_layer: true + layer_norm_target_layer: false + layer_norm_targets: true + end_of_block_targets: false + + depth: 10 + average_top_k_layers: 10 + clone_batch: 16 + + norm_eps: 1e-6 + + min_target_var: 0 + min_pred_var: 0 + + encoder_dropout: 0 + post_mlp_drop: 0 + attention_dropout: 0 + activation_dropout: 0 + + supported_modality: IMAGE + cls_loss: 0.01 + + ema_encoder_only: false + + modalities: + image: + inverse_mask: true + mask_prob: 0.8 + mask_prob_adjust: 0.07 + mask_length: 3 + mask_noise_std: 0.01 + prenet_depth: 2 + ema_local_encoder: true + num_extra_tokens: 1 + init_extra_token_zero: false + use_alibi_encoder: false + decoder: + decoder_dim: 768 + decoder_groups: 16 + decoder_kernel: 3 + decoder_layers: 6 + input_dropout: 0 \ No newline at end of file diff --git a/examples/data2vec/config/v2/base_text_only_task.yaml b/examples/data2vec/config/v2/base_text_only_task.yaml new file mode 100644 index 0000000000..62f22eb0fe --- /dev/null +++ b/examples/data2vec/config/v2/base_text_only_task.yaml @@ -0,0 +1,112 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + no_epoch_checkpoints: true + save_interval_updates: 50000 + keep_interval_updates: 1 + +distributed_training: + distributed_world_size: 16 + ddp_backend: legacy_ddp + +task: + _name: masked_lm + data: /fsx-wav2vec/abaevski/data/nlp/bookwiki_aml-full-mmap2-bin + sample_break_mode: none + tokens_per_sample: 512 + include_target_tokens: true + random_token_prob: 0 + leave_unmasked_prob: 0 + include_index: True + skip_masking: True + d2v2_multi: True + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +dataset: + batch_size: 4 + ignore_unused_valid_subsets: true + skip_invalid_size_inputs_valid_test: true + disable_validation: true + +optimization: + clip_norm: 1 + lr: [0.0002] + max_update: 1000000 + update_freq: [1] + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 0.0002 + optimizer: + _name: adam + adam_betas: [0.9,0.98] + adam_eps: 1e-06 + weight_decay: 0.01 + lr_scheduler: + _name: cosine + warmup_updates: 4000 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + loss_beta: 0 + loss_scale: 1 + + depth: 12 + embed_dim: 768 + clone_batch: 8 + + ema_decay: 0.9999 + ema_end_decay: 0.99999 + ema_anneal_end_step: 100000 + ema_encoder_only: true + + average_top_k_layers: 12 + layer_norm_target_layer: false + instance_norm_target_layer: true + batch_norm_target_layer: false + instance_norm_targets: false + layer_norm_targets: false + + layerdrop: 0 + norm_eps: 1e-5 + + supported_modality: TEXT + + modalities: + text: + mask_prob: 0.48 + mask_length: 1 + mask_noise_std: 0.01 + prenet_depth: 0 + decoder: + input_dropout: 0.1 + decoder_dim: 768 + decoder_groups: 1 + decoder_kernel: 9 + decoder_layers: 5 + decoder_residual: false + projection_layers: 2 + projection_ratio: 2.0 diff --git a/examples/data2vec/config/v2/huge_images14_only_task.yaml b/examples/data2vec/config/v2/huge_images14_only_task.yaml new file mode 100644 index 0000000000..a8a15253f2 --- /dev/null +++ b/examples/data2vec/config/v2/huge_images14_only_task.yaml @@ -0,0 +1,122 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: mae_image_pretraining + data: /datasets01/imagenet_full_size/061417/ + rebuild_batches: true + local_cache_path: /scratch/cache_abaevski/imagenet + key: source + precompute_mask_config: {} + +dataset: + num_workers: 10 + batch_size: 8 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 32 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +optimization: + max_update: 500000 + lr: [ 0.0004 ] + debug_param_names: true + clip_norm: 4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 4e-4 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 50040 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + ema_decay: 0.9998 + ema_end_decay: 1 + ema_anneal_end_step: 300000 + instance_norm_target_layer: true + layer_norm_target_layer: false + layer_norm_targets: true + end_of_block_targets: false + + depth: 32 + embed_dim: 1280 + num_heads: 16 + + average_top_k_layers: 24 + clone_batch: 16 + + norm_eps: 1e-6 + + min_target_var: 0 + min_pred_var: 0 + + encoder_dropout: 0 + post_mlp_drop: 0 + attention_dropout: 0 + activation_dropout: 0 + + supported_modality: IMAGE + cls_loss: 0.01 + + ema_encoder_only: false + + modalities: + image: + patch_size: 14 + inverse_mask: true + mask_prob: 0.75 + mask_prob_adjust: 0.1 + mask_length: 3 + mask_noise_std: 0.01 + prenet_depth: 0 + ema_local_encoder: true + num_extra_tokens: 1 + init_extra_token_zero: false + use_alibi_encoder: false + embed_dim: 1280 + decoder: + decoder_dim: 1024 + decoder_groups: 16 + decoder_kernel: 5 + decoder_layers: 3 + final_layer_norm: false + input_dropout: 0 \ No newline at end of file diff --git a/examples/data2vec/config/v2/huge_images_only_task.yaml b/examples/data2vec/config/v2/huge_images_only_task.yaml new file mode 100644 index 0000000000..7a352ac3c7 --- /dev/null +++ b/examples/data2vec/config/v2/huge_images_only_task.yaml @@ -0,0 +1,120 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: mae_image_pretraining + data: /datasets01/imagenet_full_size/061417/ + rebuild_batches: true + local_cache_path: /scratch/cache_abaevski/imagenet + key: source + precompute_mask_config: {} + +dataset: + num_workers: 10 + batch_size: 8 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +optimization: + max_update: 375300 + lr: [ 0.0004 ] + debug_param_names: true + clip_norm: 4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 4e-4 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 50040 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + ema_decay: 0.9998 + ema_end_decay: 0.99995 + ema_anneal_end_step: 150000 + instance_norm_target_layer: true + layer_norm_target_layer: false + layer_norm_targets: true + end_of_block_targets: false + + depth: 32 + embed_dim: 1280 + num_heads: 16 + + average_top_k_layers: 24 + clone_batch: 16 + + norm_eps: 1e-6 + + min_target_var: 0 + min_pred_var: 0 + + encoder_dropout: 0 + post_mlp_drop: 0 + attention_dropout: 0 + activation_dropout: 0 + + supported_modality: IMAGE + cls_loss: 0.01 + + ema_encoder_only: false + + modalities: + image: + inverse_mask: true + mask_prob: 0.75 + mask_prob_adjust: 0.1 + mask_length: 3 + mask_noise_std: 0.01 + prenet_depth: 0 + ema_local_encoder: true + num_extra_tokens: 1 + init_extra_token_zero: false + use_alibi_encoder: false + embed_dim: 1280 + decoder: + decoder_dim: 1024 + decoder_groups: 16 + decoder_kernel: 5 + decoder_layers: 3 + input_dropout: 0 \ No newline at end of file diff --git a/examples/data2vec/config/v2/large_audio_only_task.yaml b/examples/data2vec/config/v2/large_audio_only_task.yaml new file mode 100644 index 0000000000..3f61589721 --- /dev/null +++ b/examples/data2vec/config/v2/large_audio_only_task.yaml @@ -0,0 +1,122 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + save_interval: 1 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: audio_pretraining + data: /fsx-wav2vec/abaevski/data/librivox/no_silence + max_sample_size: 320000 + min_sample_size: 32000 + normalize: true + precompute_mask_config: {} + +dataset: + num_workers: 8 + max_tokens: 320000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 48 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +optimization: + max_update: 600000 + debug_param_names: true + clip_norm: 1 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 0.0004 + optimizer: + _name: adam + adam_betas: [0.9,0.98] + adam_eps: 1e-06 + weight_decay: 0.01 + lr_scheduler: + _name: cosine + warmup_updates: 10000 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + loss_beta: 0 + loss_scale: null + + depth: 16 + embed_dim: 1024 + num_heads: 16 + + clone_batch: 12 + + ema_decay: 0.9997 + ema_end_decay: 1 + ema_anneal_end_step: 300000 + ema_encoder_only: false + + average_top_k_layers: 16 + instance_norm_target_layer: true + layer_norm_target_layer: false + layer_norm_targets: false + + layerdrop: 0 + norm_eps: 1e-5 + + supported_modality: AUDIO + + modalities: + audio: + feature_encoder_spec: '[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]' + conv_pos_depth: 5 + conv_pos_width: 95 + conv_pos_groups: 16 + prenet_depth: 8 + mask_prob: 0.55 + mask_prob_adjust: 0.1 + inverse_mask: false + mask_length: 5 + mask_noise_std: 0.01 + mask_dropout: 0 + add_masks: false + ema_local_encoder: false + use_alibi_encoder: true + prenet_layerdrop: 0 + prenet_dropout: 0.1 + learned_alibi_scale: true + learned_alibi_scale_per_head: true + decoder: + input_dropout: 0.1 + decoder_dim: 768 + decoder_groups: 16 + decoder_kernel: 7 + decoder_layers: 4 diff --git a/examples/data2vec/config/v2/large_images_only_task.yaml b/examples/data2vec/config/v2/large_images_only_task.yaml new file mode 100644 index 0000000000..6b957fc129 --- /dev/null +++ b/examples/data2vec/config/v2/large_images_only_task.yaml @@ -0,0 +1,120 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: mae_image_pretraining + data: /datasets01/imagenet_full_size/061417/ + rebuild_batches: true + local_cache_path: /scratch/cache_abaevski/imagenet + key: source + precompute_mask_config: {} + +dataset: + num_workers: 10 + batch_size: 8 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +optimization: + max_update: 375300 + lr: [ 0.0004 ] + debug_param_names: true + clip_norm: 4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 4e-4 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 50040 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + ema_decay: 0.9998 + ema_end_decay: 0.99999 + ema_anneal_end_step: 150000 + instance_norm_target_layer: true + layer_norm_target_layer: false + layer_norm_targets: true + end_of_block_targets: false + + depth: 24 + embed_dim: 1024 + num_heads: 16 + + average_top_k_layers: 18 + clone_batch: 16 + + norm_eps: 1e-6 + + min_target_var: 0 + min_pred_var: 0 + + encoder_dropout: 0 + post_mlp_drop: 0 + attention_dropout: 0 + activation_dropout: 0 + + supported_modality: IMAGE + cls_loss: 0.01 + + ema_encoder_only: false + + modalities: + image: + inverse_mask: true + mask_prob: 0.75 + mask_prob_adjust: 0.1 + mask_length: 3 + mask_noise_std: 0.01 + prenet_depth: 0 + ema_local_encoder: true + num_extra_tokens: 1 + init_extra_token_zero: false + use_alibi_encoder: false + embed_dim: 1024 + decoder: + decoder_dim: 1024 + decoder_groups: 16 + decoder_kernel: 5 + decoder_layers: 3 + input_dropout: 0 \ No newline at end of file diff --git a/examples/data2vec/config/v2/large_text_only_task.yaml b/examples/data2vec/config/v2/large_text_only_task.yaml new file mode 100644 index 0000000000..fd69048e77 --- /dev/null +++ b/examples/data2vec/config/v2/large_text_only_task.yaml @@ -0,0 +1,112 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + min_loss_scale: 1e-6 + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + save_interval_updates: 50000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: masked_lm + data: /fsx-wav2vec/abaevski/data/nlp/bookwiki_aml-full-mmap2-bin + sample_break_mode: none + tokens_per_sample: 512 + include_target_tokens: true + random_token_prob: 0 + leave_unmasked_prob: 0 + include_index: True + skip_masking: True + d2v2_multi: True + +dataset: + batch_size: 2 + ignore_unused_valid_subsets: true + skip_invalid_size_inputs_valid_test: true + disable_validation: true + +distributed_training: + distributed_world_size: 32 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +optimization: + max_update: 600000 + clip_norm: 1 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 0.0001 + optimizer: + _name: adam + adam_betas: [0.9,0.98] + adam_eps: 1e-06 + weight_decay: 0.01 + lr_scheduler: + _name: cosine + warmup_updates: 4000 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + loss_beta: 0 + loss_scale: 1 + + depth: 24 + num_heads: 16 + embed_dim: 1024 + clone_batch: 8 + + ema_decay: 0.9999 + ema_end_decay: 0.99999 + ema_anneal_end_step: 100000 + ema_encoder_only: true + + average_top_k_layers: 24 + layer_norm_target_layer: true + instance_norm_target_layer: false + batch_norm_target_layer: false + instance_norm_targets: true + layer_norm_targets: false + + layerdrop: 0 + norm_eps: 1e-5 + + supported_modality: TEXT + + modalities: + text: + mask_prob: 0.5 + mask_length: 1 + mask_noise_std: 0.01 + prenet_depth: 0 + decoder: + input_dropout: 0.1 + decoder_dim: 768 + decoder_groups: 1 + decoder_kernel: 9 + decoder_layers: 5 + decoder_residual: false + projection_layers: 2 + projection_ratio: 2.0 diff --git a/examples/data2vec/config/v2/large_text_only_task_pgrp_1M.yaml b/examples/data2vec/config/v2/large_text_only_task_pgrp_1M.yaml new file mode 100644 index 0000000000..739e6f6724 --- /dev/null +++ b/examples/data2vec/config/v2/large_text_only_task_pgrp_1M.yaml @@ -0,0 +1,123 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + fp16_no_flatten_grads: true + user_dir: ${env:PWD}/examples/data2vec + +checkpoint: + no_epoch_checkpoints: true + save_interval_updates: 50000 + keep_interval_updates: 1 + +distributed_training: + distributed_world_size: 32 + ddp_backend: legacy_ddp + +task: + _name: masked_lm + data: /fsx-wav2vec/abaevski/data/nlp/bookwiki_aml-full-mmap2-bin + sample_break_mode: none + tokens_per_sample: 512 + include_target_tokens: true + random_token_prob: 0 + leave_unmasked_prob: 0 + include_index: True + skip_masking: True + d2v2_multi: True + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + - model_norm + - ema_norm + - masked_pct + +dataset: + batch_size: 2 + ignore_unused_valid_subsets: true + skip_invalid_size_inputs_valid_test: true + disable_validation: true + +optimization: + clip_norm: 1 + lr: [3e-4] + max_update: 1000000 + update_freq: [1] + +optimizer: + _name: composite + groups: + default: + lr_float: 1e-4 + optimizer: + _name: adam + adam_betas: [0.9,0.98] + adam_eps: 1e-06 + weight_decay: 0.01 + lr_scheduler: + _name: cosine + warmup_updates: 4000 + decoder: + lr_float: 1e-4 + optimizer: + _name: adam + adam_betas: [0.9,0.98] + adam_eps: 1e-06 + weight_decay: 0.01 + lr_scheduler: + _name: cosine + warmup_updates: 4000 + +lr_scheduler: pass_through + +model: + _name: data2vec_multi + + loss_beta: 4 + loss_scale: 1 + + depth: 24 + num_heads: 16 + embed_dim: 1024 + clone_batch: 8 + + ema_decay: 0.9999 + ema_end_decay: 0.99999 + ema_anneal_end_step: 100000 + ema_encoder_only: true + + average_top_k_layers: 24 + layer_norm_target_layer: true + instance_norm_target_layer: false + batch_norm_target_layer: false + instance_norm_targets: true + layer_norm_targets: false + + layerdrop: 0 + norm_eps: 1e-5 + + supported_modality: TEXT + decoder_group: true + + modalities: + text: + mask_prob: 0.5 + mask_length: 1 + mask_noise_std: 0.01 + prenet_depth: 0 + decoder: + input_dropout: 0.1 + decoder_dim: 768 + decoder_groups: 1 + decoder_kernel: 9 + decoder_layers: 5 + decoder_residual: false + projection_layers: 2 + projection_ratio: 2.0 diff --git a/examples/data2vec/config/v2/run_config/local.yaml b/examples/data2vec/config/v2/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/data2vec/config/v2/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/data2vec/config/v2/run_config/slurm_1.yaml b/examples/data2vec/config/v2/run_config/slurm_1.yaml new file mode 100644 index 0000000000..732f018899 --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_1.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_1_aws.yaml b/examples/data2vec/config/v2/run_config/slurm_1_aws.yaml new file mode 100644 index 0000000000..b2184f8cfa --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_1_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.local_cache_path + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_2.yaml b/examples/data2vec/config/v2/run_config/slurm_2.yaml new file mode 100644 index 0000000000..ec53dc2a98 --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_2.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_2_aws.yaml b/examples/data2vec/config/v2/run_config/slurm_2_aws.yaml new file mode 100644 index 0000000000..553765597f --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_2_aws.yaml @@ -0,0 +1,39 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.local_cache_path + - task.data + - task.post_save_script + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + - model.model_path + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 12 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_3.yaml b/examples/data2vec/config/v2/run_config/slurm_3.yaml new file mode 100644 index 0000000000..14b47d14e6 --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_3.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 3 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_4.yaml b/examples/data2vec/config/v2/run_config/slurm_4.yaml new file mode 100644 index 0000000000..c54d735fb2 --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_4.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_4_aws.yaml b/examples/data2vec/config/v2/run_config/slurm_4_aws.yaml new file mode 100644 index 0000000000..a77f62aece --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_4_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - task.post_save_script + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 12 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_6_aws.yaml b/examples/data2vec/config/v2/run_config/slurm_6_aws.yaml new file mode 100644 index 0000000000..20e06582be --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_6_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 12 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 6 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_8.yaml b/examples/data2vec/config/v2/run_config/slurm_8.yaml new file mode 100644 index 0000000000..e3ec2c2847 --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_8.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 8 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/run_config/slurm_8_aws.yaml b/examples/data2vec/config/v2/run_config/slurm_8_aws.yaml new file mode 100644 index 0000000000..a9dce876cc --- /dev/null +++ b/examples/data2vec/config/v2/run_config/slurm_8_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 12 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 8 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/v2/text_finetuning/cola.yaml b/examples/data2vec/config/v2/text_finetuning/cola.yaml new file mode 100644 index 0000000000..d4ac4ec8b8 --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/cola.yaml @@ -0,0 +1,60 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: mcc + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + report_mcc: True + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 320 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 5336 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/v2/text_finetuning/mnli.yaml b/examples/data2vec/config/v2/text_finetuning/mnli.yaml new file mode 100644 index 0000000000..1a9d6e52f0 --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/mnli.yaml @@ -0,0 +1,60 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 3 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + valid_subset: valid,valid1 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 7432 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 123873 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/v2/text_finetuning/mrpc.yaml b/examples/data2vec/config/v2/text_finetuning/mrpc.yaml new file mode 100644 index 0000000000..8f93d9d9ea --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/mrpc.yaml @@ -0,0 +1,60 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: acc_and_f1 + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + report_acc_and_f1: True + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 137 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 2296 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/v2/text_finetuning/qnli.yaml b/examples/data2vec/config/v2/text_finetuning/qnli.yaml new file mode 100644 index 0000000000..739fb53b69 --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/qnli.yaml @@ -0,0 +1,59 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 1986 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 33112 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/v2/text_finetuning/qqp.yaml b/examples/data2vec/config/v2/text_finetuning/qqp.yaml new file mode 100644 index 0000000000..9accbaa521 --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/qqp.yaml @@ -0,0 +1,60 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: acc_and_f1 + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + report_acc_and_f1: True + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 28318 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 113272 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/v2/text_finetuning/rte.yaml b/examples/data2vec/config/v2/text_finetuning/rte.yaml new file mode 100644 index 0000000000..ea07764d98 --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/rte.yaml @@ -0,0 +1,59 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 122 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 2036 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/v2/text_finetuning/run_config/local.yaml b/examples/data2vec/config/v2/text_finetuning/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/data2vec/config/v2/text_finetuning/sst_2.yaml b/examples/data2vec/config/v2/text_finetuning/sst_2.yaml new file mode 100644 index 0000000000..a273e5b943 --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/sst_2.yaml @@ -0,0 +1,59 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 2 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + +dataset: + batch_size: 32 + required_batch_size_multiple: 1 + max_tokens: 4400 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 1256 + +optimization: + clip_norm: 0.0 + lr: [2e-05] + max_update: 20935 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/v2/text_finetuning/sts_b.yaml b/examples/data2vec/config/v2/text_finetuning/sts_b.yaml new file mode 100644 index 0000000000..fb009ab95b --- /dev/null +++ b/examples/data2vec/config/v2/text_finetuning/sts_b.yaml @@ -0,0 +1,61 @@ +# @package _group_ + +common: + fp16: true + fp16_init_scale: 4 + threshold_loss_scale: 1 + fp16_scale_window: 128 + log_format: json + log_interval: 200 + user_dir: ${env:PWD}/examples/data2vec + +task: + _name: sentence_prediction + data: ??? + init_token: 0 + separator_token: 2 + num_classes: 1 + max_positions: 512 + d2v2_multi: True + +checkpoint: + best_checkpoint_metric: pearson_and_spearman + maximize_best_checkpoint_metric: true + no_epoch_checkpoints: true + +distributed_training: + find_unused_parameters: true + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +criterion: + _name: sentence_prediction + regression_target: true + report_pearson_and_spearman: True + +dataset: + batch_size: 16 + required_batch_size_multiple: 1 + max_tokens: 4400 + num_workers: 1 + +optimizer: + _name: adam + weight_decay: 0.1 + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 214 + +optimization: + clip_norm: 0.0 + lr: [4e-05] + max_update: 3598 + max_epoch: 10 + +model: + _name: data2vec_text_classification + model_path: ??? diff --git a/examples/data2vec/config/vision/finetuning/imagenet.yaml b/examples/data2vec/config/vision/finetuning/imagenet.yaml new file mode 100644 index 0000000000..d6d4864cca --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/imagenet.yaml @@ -0,0 +1,52 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + +checkpoint: + save_interval: 1 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: accuracy + +task: + _name: image_classification + data: /datasets01/imagenet_full_size/061417 + +dataset: + num_workers: 6 + batch_size: 64 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 1 + valid_subset: val + +distributed_training: + distributed_world_size: 8 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - correct + +optimization: + max_update: 100000 + lr: [0.0005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: cosine + warmup_updates: 10000 + +model: + _name: data2vec_image_classification + model_path: ??? diff --git a/examples/data2vec/config/vision/finetuning/mae_imagenet_clean.yaml b/examples/data2vec/config/vision/finetuning/mae_imagenet_clean.yaml new file mode 100644 index 0000000000..17d4c0a8f5 --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/mae_imagenet_clean.yaml @@ -0,0 +1,65 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + fp16_no_flatten_grads: true + +checkpoint: + save_interval: 1 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +task: + _name: mae_image_classification + data: /datasets01/imagenet_full_size/061417 + +dataset: + num_workers: 6 + batch_size: 32 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 2 + valid_subset: val + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - correct + +optimization: + max_update: 250200 + lr: [0.001] + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 0.001 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 16000 + min_lr: 1e-6 + + +lr_scheduler: pass_through + +model: + _name: mae_image_classification + mixup: 0.7 + mixup_prob: 0.9 + + model_path: ??? diff --git a/examples/data2vec/config/vision/finetuning/mae_imagenet_huge_clean.yaml b/examples/data2vec/config/vision/finetuning/mae_imagenet_huge_clean.yaml new file mode 100644 index 0000000000..2d2eb57bac --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/mae_imagenet_huge_clean.yaml @@ -0,0 +1,68 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + fp16_no_flatten_grads: true + +checkpoint: + save_interval: 1 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +task: + _name: mae_image_classification + data: /datasets01/imagenet_full_size/061417 + +dataset: + num_workers: 6 + batch_size: 32 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 2 + valid_subset: val + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - correct + +optimization: + max_update: 125200 + lr: [0.0005] + clip_norm: 4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 0.0005 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 16000 + min_lr: 1e-20 + + +lr_scheduler: pass_through + +model: + _name: mae_image_classification + mixup: 0.7 + mixup_prob: 0.9 + layer_decay: 0.75 + drop_path_rate: 0.2 + + model_path: ??? diff --git a/examples/data2vec/config/vision/finetuning/mae_imagenet_large_clean.yaml b/examples/data2vec/config/vision/finetuning/mae_imagenet_large_clean.yaml new file mode 100644 index 0000000000..3a9413cef6 --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/mae_imagenet_large_clean.yaml @@ -0,0 +1,68 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + fp16_no_flatten_grads: true + +checkpoint: + save_interval: 1 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: accuracy + maximize_best_checkpoint_metric: true + +task: + _name: mae_image_classification + data: /datasets01/imagenet_full_size/061417 + +dataset: + num_workers: 6 + batch_size: 32 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 2 + valid_subset: val + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - correct + +optimization: + max_update: 125200 + lr: [0.0005] + clip_norm: 4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 0.0005 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 16000 + min_lr: 1e-7 + + +lr_scheduler: pass_through + +model: + _name: mae_image_classification + mixup: 0.7 + mixup_prob: 0.9 + layer_decay: 0.75 + drop_path_rate: 0.2 + + model_path: ??? diff --git a/examples/data2vec/config/vision/finetuning/run_config/local.yaml b/examples/data2vec/config/vision/finetuning/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_1.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_1.yaml new file mode 100644 index 0000000000..732f018899 --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_1.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_1_aws.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_1_aws.yaml new file mode 100644 index 0000000000..e2bab5675a --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_1_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_2.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_2.yaml new file mode 100644 index 0000000000..c8b0f02a9b --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_2.yaml @@ -0,0 +1,38 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + - task.local_cache_path + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_2_aws.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_2_aws.yaml new file mode 100644 index 0000000000..93d0d9c20a --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_2_aws.yaml @@ -0,0 +1,38 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + - task.local_cache_path + - model.model_path + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_3.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_3.yaml new file mode 100644 index 0000000000..14b47d14e6 --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_3.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 3 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_4.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_4.yaml new file mode 100644 index 0000000000..c54d735fb2 --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_4.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_4_aws.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_4_aws.yaml new file mode 100644 index 0000000000..d5d11cb755 --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_4_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_6_aws.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_6_aws.yaml new file mode 100644 index 0000000000..906f08a602 --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_6_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 6 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/finetuning/run_config/slurm_8_aws.yaml b/examples/data2vec/config/vision/finetuning/run_config/slurm_8_aws.yaml new file mode 100644 index 0000000000..d60e13f8ba --- /dev/null +++ b/examples/data2vec/config/vision/finetuning/run_config/slurm_8_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 8 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/base_imagenet.yaml b/examples/data2vec/config/vision/pretraining/base_imagenet.yaml new file mode 100644 index 0000000000..9bfc0f32b6 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/base_imagenet.yaml @@ -0,0 +1,52 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: image_pretraining + data: /datasets01/imagenet_full_size/061417/ + +dataset: + num_workers: 6 + batch_size: 64 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + +optimization: + max_update: 400000 + lr: [0.0005] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: cosine + warmup_updates: 10000 + +model: + _name: data2vec_vision diff --git a/examples/data2vec/config/vision/pretraining/base_imagenet_d2v1.yaml b/examples/data2vec/config/vision/pretraining/base_imagenet_d2v1.yaml new file mode 100644 index 0000000000..5fd399b117 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/base_imagenet_d2v1.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: image_pretraining + data: /datasets01/imagenet_full_size/061417 + +dataset: + num_workers: 6 + batch_size: 128 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 2 + disable_validation: true + +distributed_training: + distributed_world_size: 16 + ddp_backend: legacy_ddp + +criterion: + _name: model + log_keys: + - ema_decay + - target_var + - pred_var + +optimization: + max_update: 375300 #300*1251 + lr: [0.0005] + clip_norm: 3.0 + +optimizer: + _name: adam + adam_betas: (0.9,0.999) + adam_eps: 1e-08 + weight_decay: 0.05 + +lr_scheduler: + _name: cosine + warmup_updates: 12510 # it should be 10 epochs + +model: + _name: data2vec_vision + + attention_dropout: 0.05 + + ema_decay: 0.999 + ema_end_decay: 0.9998 + layer_norm_targets: True + average_top_k_layers: 6 + + loss_beta: 2.0 + + drop_path: 0.25 diff --git a/examples/data2vec/config/vision/pretraining/base_mae_imagenet.yaml b/examples/data2vec/config/vision/pretraining/base_mae_imagenet.yaml new file mode 100644 index 0000000000..d7872b5e04 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/base_mae_imagenet.yaml @@ -0,0 +1,64 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tb + fp16_no_flatten_grads: true + +checkpoint: + save_interval: 5 + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +task: + _name: mae_image_pretraining + data: /datasets01/imagenet_full_size/061417/ + rebuild_batches: true + +dataset: + num_workers: 6 + batch_size: 64 + skip_invalid_size_inputs_valid_test: true + required_batch_size_multiple: 1 + disable_validation: true + +distributed_training: + distributed_world_size: 16 + ddp_backend: c10d + +criterion: + _name: model + +optimization: + max_update: 375300 + lr: [0.0006] + +optimizer: + _name: composite + groups: + with_decay: + lr_float: 6e-4 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0.05 + lr_scheduler: + _name: cosine + warmup_updates: 50040 + no_decay: + lr_float: 6e-4 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + weight_decay: 0 + lr_scheduler: + _name: cosine + warmup_updates: 50040 + +lr_scheduler: pass_through + +model: + _name: mae diff --git a/examples/data2vec/config/vision/pretraining/run_config/local.yaml b/examples/data2vec/config/vision/pretraining/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_1.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_1.yaml new file mode 100644 index 0000000000..732f018899 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_1.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_1_aws.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_1_aws.yaml new file mode 100644 index 0000000000..e2bab5675a --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_1_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_2.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_2.yaml new file mode 100644 index 0000000000..c8b0f02a9b --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_2.yaml @@ -0,0 +1,38 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + - task.local_cache_path + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_2_aws.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_2_aws.yaml new file mode 100644 index 0000000000..032e53a304 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_2_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + - task.local_cache_path + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_3.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_3.yaml new file mode 100644 index 0000000000..14b47d14e6 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_3.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 3 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_4.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_4.yaml new file mode 100644 index 0000000000..c54d735fb2 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_4.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_4_aws.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_4_aws.yaml new file mode 100644 index 0000000000..d5d11cb755 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_4_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_6_aws.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_6_aws.yaml new file mode 100644 index 0000000000..906f08a602 --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_6_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 6 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/config/vision/pretraining/run_config/slurm_8_aws.yaml b/examples/data2vec/config/vision/pretraining/run_config/slurm_8_aws.yaml new file mode 100644 index 0000000000..d60e13f8ba --- /dev/null +++ b/examples/data2vec/config/vision/pretraining/run_config/slurm_8_aws.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 8 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/data2vec/data/__init__.py b/examples/data2vec/data/__init__.py new file mode 100644 index 0000000000..d76112bfc2 --- /dev/null +++ b/examples/data2vec/data/__init__.py @@ -0,0 +1,17 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .image_dataset import ImageDataset +from .path_dataset import PathDataset +from .mae_image_dataset import MaeImageDataset +from .mae_finetuning_image_dataset import MaeFinetuningImageDataset + + +__all__ = [ + "ImageDataset", + "MaeImageDataset", + "MaeFinetuningImageDataset", + "PathDataset", +] \ No newline at end of file diff --git a/examples/data2vec/data/add_class_target_dataset.py b/examples/data2vec/data/add_class_target_dataset.py new file mode 100644 index 0000000000..c346c83e58 --- /dev/null +++ b/examples/data2vec/data/add_class_target_dataset.py @@ -0,0 +1,63 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + +from fairseq.data import BaseWrapperDataset, data_utils + + +class AddClassTargetDataset(BaseWrapperDataset): + def __init__( + self, + dataset, + labels, + multi_class, + num_classes=None, + label_indices=None, + add_to_input=True, + ): + super().__init__(dataset) + + self.label_indices = label_indices + self.labels = labels + self.multi_class = multi_class + self.add_to_input = add_to_input + if num_classes is None and multi_class: + assert self.label_indices is not None + num_classes = len(self.label_indices) + + self.num_classes = num_classes + + def __getitem__(self, index): + item = self.dataset[index] + item_labels = self.labels[index] + if self.multi_class: + item["label"] = torch.zeros(self.num_classes) + for il in item_labels: + if self.label_indices is not None: + il = self.label_indices[il] + item["label"][il] = 1.0 + else: + item["label"] = torch.tensor( + self.labels[index] + if self.label_indices is None + else self.label_indices[self.labels[index]] + ) + + return item + + def collater(self, samples): + collated = self.dataset.collater(samples) + if len(collated) == 0: + return collated + + indices = set(collated["id"].tolist()) + target = [s["label"] for s in samples if s["id"] in indices] + collated["label"] = torch.stack(target, dim=0) + + if self.add_to_input: + collated["net_input"]["label"] = collated["label"] + + return collated diff --git a/examples/data2vec/data/image_dataset.py b/examples/data2vec/data/image_dataset.py new file mode 100644 index 0000000000..7f551057e8 --- /dev/null +++ b/examples/data2vec/data/image_dataset.py @@ -0,0 +1,127 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import numpy as np +import os +from typing import Optional, Callable, Set + +import torch + +from torchvision.datasets.vision import VisionDataset +from torchvision.transforms import ToTensor + +from fairseq.data import FairseqDataset + + +logger = logging.getLogger(__name__) + + +class ImageDataset(FairseqDataset, VisionDataset): + def __init__( + self, + root: str, + extensions: Set[str], + load_classes: bool, + transform: Optional[Callable] = None, + shuffle=True, + ): + FairseqDataset.__init__(self) + VisionDataset.__init__(self, root=root, transform=transform) + + self.shuffle = shuffle + self.tensor_transform = ToTensor() + + self.classes = None + self.labels = None + if load_classes: + classes = [d.name for d in os.scandir(root) if d.is_dir()] + classes.sort() + self.classes = {cls_name: i for i, cls_name in enumerate(classes)} + logger.info(f"loaded {len(self.classes)} classes") + self.labels = [] + + def walk_path(root_path): + for root, _, fnames in sorted(os.walk(root_path, followlinks=True)): + for fname in sorted(fnames): + fname_ext = os.path.splitext(fname) + if fname_ext[-1].lower() not in extensions: + continue + + path = os.path.join(root, fname) + yield path + + logger.info(f"finding images in {root}") + if self.classes is not None: + self.files = [] + self.labels = [] + for c, i in self.classes.items(): + for f in walk_path(os.path.join(root, c)): + self.files.append(f) + self.labels.append(i) + else: + self.files = [f for f in walk_path(root)] + + logger.info(f"loaded {len(self.files)} examples") + + def __getitem__(self, index): + from PIL import Image + + fpath = self.files[index] + + with open(fpath, "rb") as f: + img = Image.open(f).convert("RGB") + + if self.transform is None: + img = self.tensor_transform(img) + else: + img = self.transform(img) + assert torch.is_tensor(img) + + res = {"id": index, "img": img} + + if self.labels is not None: + res["label"] = self.labels[index] + + return res + + def __len__(self): + return len(self.files) + + def collater(self, samples): + if len(samples) == 0: + return {} + + collated_img = torch.stack([s["img"] for s in samples], dim=0) + + res = { + "id": torch.LongTensor([s["id"] for s in samples]), + "net_input": { + "img": collated_img, + }, + } + + if "label" in samples[0]: + res["net_input"]["label"] = torch.LongTensor([s["label"] for s in samples]) + + return res + + def num_tokens(self, index): + return 1 + + def size(self, index): + return 1 + + def ordered_indices(self): + """Return an ordered list of indices. Batches will be constructed based + on this order.""" + if self.shuffle: + order = [np.random.permutation(len(self))] + else: + order = [np.arange(len(self))] + + return order[0] diff --git a/examples/data2vec/data/mae_finetuning_image_dataset.py b/examples/data2vec/data/mae_finetuning_image_dataset.py new file mode 100644 index 0000000000..28cbcb38ac --- /dev/null +++ b/examples/data2vec/data/mae_finetuning_image_dataset.py @@ -0,0 +1,135 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +import logging + +import numpy as np +import os + +import torch + +from torchvision import datasets, transforms + +from timm.data import create_transform +from timm.data.constants import IMAGENET_DEFAULT_MEAN, IMAGENET_DEFAULT_STD +import PIL + +from fairseq.data import FairseqDataset +from .mae_image_dataset import caching_loader + + +logger = logging.getLogger(__name__) + + +def build_transform(is_train, input_size, color_jitter, aa, reprob, remode, recount): + mean = IMAGENET_DEFAULT_MEAN + std = IMAGENET_DEFAULT_STD + # train transform + if is_train: + # this should always dispatch to transforms_imagenet_train + transform = create_transform( + input_size=input_size, + is_training=True, + color_jitter=color_jitter, + auto_augment=aa, + interpolation="bicubic", + re_prob=reprob, + re_mode=remode, + re_count=recount, + mean=mean, + std=std, + ) + return transform + + # eval transform + t = [] + if input_size <= 224: + crop_pct = 224 / 256 + else: + crop_pct = 1.0 + size = int(input_size / crop_pct) + t.append( + transforms.Resize( + size, interpolation=PIL.Image.BICUBIC + ), # to maintain same ratio w.r.t. 224 images + ) + t.append(transforms.CenterCrop(input_size)) + + t.append(transforms.ToTensor()) + t.append(transforms.Normalize(mean, std)) + return transforms.Compose(t) + + +class MaeFinetuningImageDataset(FairseqDataset): + def __init__( + self, + root: str, + split: str, + is_train: bool, + input_size, + color_jitter=None, + aa="rand-m9-mstd0.5-inc1", + reprob=0.25, + remode="pixel", + recount=1, + local_cache_path=None, + shuffle=True, + ): + FairseqDataset.__init__(self) + + self.shuffle = shuffle + + transform = build_transform( + is_train, input_size, color_jitter, aa, reprob, remode, recount + ) + + path = os.path.join(root, split) + loader = caching_loader(local_cache_path, datasets.folder.default_loader) + + self.dataset = datasets.ImageFolder(path, loader=loader, transform=transform) + + logger.info(f"loaded {len(self.dataset)} examples") + + def __getitem__(self, index): + img, label = self.dataset[index] + return {"id": index, "img": img, "label": label} + + def __len__(self): + return len(self.dataset) + + def collater(self, samples): + if len(samples) == 0: + return {} + + collated_img = torch.stack([s["img"] for s in samples], dim=0) + + res = { + "id": torch.LongTensor([s["id"] for s in samples]), + "net_input": { + "imgs": collated_img, + }, + } + + if "label" in samples[0]: + res["net_input"]["labels"] = torch.LongTensor([s["label"] for s in samples]) + + return res + + def num_tokens(self, index): + return 1 + + def size(self, index): + return 1 + + def ordered_indices(self): + """Return an ordered list of indices. Batches will be constructed based + on this order.""" + if self.shuffle: + order = [np.random.permutation(len(self))] + else: + order = [np.arange(len(self))] + + return order[0] diff --git a/examples/data2vec/data/mae_image_dataset.py b/examples/data2vec/data/mae_image_dataset.py new file mode 100644 index 0000000000..4aacb94895 --- /dev/null +++ b/examples/data2vec/data/mae_image_dataset.py @@ -0,0 +1,418 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +from functools import partial +import logging +import math +import random +import time + +import numpy as np +import os + +import torch + +from torchvision import datasets, transforms +from .path_dataset import PathDataset + +from fairseq.data import FairseqDataset +from fairseq.data.data_utils import compute_block_mask_1d, compute_block_mask_2d + +from shutil import copyfile + +logger = logging.getLogger(__name__) + + +def load(path, loader, cache): + if hasattr(caching_loader, "cache_root"): + cache = caching_loader.cache_root + + cached_path = cache + path + + num_tries = 3 + for curr_try in range(num_tries): + try: + if curr_try == 2: + return loader(path) + if not os.path.exists(cached_path) or curr_try > 0: + os.makedirs(os.path.dirname(cached_path), exist_ok=True) + copyfile(path, cached_path) + os.chmod(cached_path, 0o777) + return loader(cached_path) + except Exception as e: + logger.warning(str(e)) + if "Errno 13" in str(e): + caching_loader.cache_root = f"/scratch/{random.randint(0, 69420)}" + logger.warning(f"setting cache root to {caching_loader.cache_root}") + cached_path = caching_loader.cache_root + path + if curr_try == (num_tries - 1): + raise + time.sleep(2) + + +def caching_loader(cache_root: str, loader): + if cache_root is None: + return loader + + if cache_root == "slurm_tmpdir": + cache_root = os.environ["SLURM_TMPDIR"] + assert len(cache_root) > 0 + + if not cache_root.endswith("/"): + cache_root += "/" + + return partial(load, loader=loader, cache=cache_root) + + +class RandomResizedCropAndInterpolationWithTwoPic: + """Crop the given PIL Image to random size and aspect ratio with random interpolation. + + A crop of random size (default: of 0.08 to 1.0) of the original size and a random + aspect ratio (default: of 3/4 to 4/3) of the original aspect ratio is made. This crop + is finally resized to given size. + This is popularly used to train the Inception networks. + + Args: + size: expected output size of each edge + scale: range of size of the origin size cropped + ratio: range of aspect ratio of the origin aspect ratio cropped + interpolation: Default: PIL.Image.BILINEAR + """ + + def __init__( + self, + size, + second_size=None, + scale=(0.08, 1.0), + ratio=(3.0 / 4.0, 4.0 / 3.0), + interpolation="bilinear", + second_interpolation="lanczos", + ): + if isinstance(size, tuple): + self.size = size + else: + self.size = (size, size) + if second_size is not None: + if isinstance(second_size, tuple): + self.second_size = second_size + else: + self.second_size = (second_size, second_size) + else: + self.second_size = None + if (scale[0] > scale[1]) or (ratio[0] > ratio[1]): + logger.warning("range should be of kind (min, max)") + + if interpolation == "random": + from PIL import Image + + self.interpolation = (Image.BILINEAR, Image.BICUBIC) + else: + self.interpolation = self._pil_interp(interpolation) + + self.second_interpolation = ( + self._pil_interp(second_interpolation) + if second_interpolation is not None + else None + ) + self.scale = scale + self.ratio = ratio + + def _pil_interp(self, method): + from PIL import Image + + if method == "bicubic": + return Image.BICUBIC + elif method == "lanczos": + return Image.LANCZOS + elif method == "hamming": + return Image.HAMMING + else: + # default bilinear, do we want to allow nearest? + return Image.BILINEAR + + @staticmethod + def get_params(img, scale, ratio): + """Get parameters for ``crop`` for a random sized crop. + + Args: + img (PIL Image): Image to be cropped. + scale (tuple): range of size of the origin size cropped + ratio (tuple): range of aspect ratio of the origin aspect ratio cropped + + Returns: + tuple: params (i, j, h, w) to be passed to ``crop`` for a random + sized crop. + """ + area = img.size[0] * img.size[1] + + for attempt in range(10): + target_area = random.uniform(*scale) * area + log_ratio = (math.log(ratio[0]), math.log(ratio[1])) + aspect_ratio = math.exp(random.uniform(*log_ratio)) + + w = int(round(math.sqrt(target_area * aspect_ratio))) + h = int(round(math.sqrt(target_area / aspect_ratio))) + + if w <= img.size[0] and h <= img.size[1]: + i = random.randint(0, img.size[1] - h) + j = random.randint(0, img.size[0] - w) + return i, j, h, w + + # Fallback to central crop + in_ratio = img.size[0] / img.size[1] + if in_ratio < min(ratio): + w = img.size[0] + h = int(round(w / min(ratio))) + elif in_ratio > max(ratio): + h = img.size[1] + w = int(round(h * max(ratio))) + else: # whole image + w = img.size[0] + h = img.size[1] + i = (img.size[1] - h) // 2 + j = (img.size[0] - w) // 2 + return i, j, h, w + + def __call__(self, img): + import torchvision.transforms.functional as F + + """ + Args: + img (PIL Image): Image to be cropped and resized. + + Returns: + PIL Image: Randomly cropped and resized image. + """ + i, j, h, w = self.get_params(img, self.scale, self.ratio) + if isinstance(self.interpolation, (tuple, list)): + interpolation = random.choice(self.interpolation) + else: + interpolation = self.interpolation + if self.second_size is None: + return F.resized_crop(img, i, j, h, w, self.size, interpolation) + else: + return F.resized_crop( + img, i, j, h, w, self.size, interpolation + ), F.resized_crop( + img, i, j, h, w, self.second_size, self.second_interpolation + ) + + +class MaeImageDataset(FairseqDataset): + def __init__( + self, + root: str, + split: str, + input_size, + local_cache_path=None, + shuffle=True, + key="imgs", + beit_transforms=False, + target_transform=False, + no_transform=False, + compute_mask=False, + patch_size: int = 16, + mask_prob: float = 0.75, + mask_prob_adjust: float = 0, + mask_length: int = 1, + inverse_mask: bool = False, + expand_adjacent: bool = False, + mask_dropout: float = 0, + non_overlapping: bool = False, + require_same_masks: bool = True, + clone_batch: int = 1, + dataset_type: str = "imagefolder", + ): + FairseqDataset.__init__(self) + + self.shuffle = shuffle + self.key = key + + loader = caching_loader(local_cache_path, datasets.folder.default_loader) + + self.transform_source = None + self.transform_target = None + + if target_transform: + self.transform_source = transforms.ColorJitter(0.4, 0.4, 0.4) + self.transform_target = transforms.ColorJitter(0.4, 0.4, 0.4) + + if no_transform: + if input_size <= 224: + crop_pct = 224 / 256 + else: + crop_pct = 1.0 + size = int(input_size / crop_pct) + + self.transform_train = transforms.Compose( + [ + transforms.Resize(size, interpolation=3), + transforms.CenterCrop(input_size), + ] + ) + + self.transform_train = transforms.Resize((input_size, input_size)) + elif beit_transforms: + beit_transform_list = [] + if not target_transform: + beit_transform_list.append(transforms.ColorJitter(0.4, 0.4, 0.4)) + beit_transform_list.extend( + [ + transforms.RandomHorizontalFlip(p=0.5), + RandomResizedCropAndInterpolationWithTwoPic( + size=input_size, + second_size=None, + interpolation="bicubic", + second_interpolation=None, + ), + ] + ) + self.transform_train = transforms.Compose(beit_transform_list) + else: + self.transform_train = transforms.Compose( + [ + transforms.RandomResizedCrop( + input_size, scale=(0.2, 1.0), interpolation=3 + ), # 3 is bicubic + transforms.RandomHorizontalFlip(), + ] + ) + self.final_transform = transforms.Compose( + [ + transforms.ToTensor(), + transforms.Normalize( + mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] + ), + ] + ) + + if dataset_type == "imagefolder": + self.dataset = datasets.ImageFolder( + os.path.join(root, split), loader=loader + ) + elif dataset_type == "path": + self.dataset = PathDataset( + root, + loader, + None, + None, + mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225], + ) + else: + raise Exception(f"invalid dataset type {dataset_type}") + + logger.info( + f"initial transform: {self.transform_train}, " + f"source transform: {self.transform_source}, " + f"target transform: {self.transform_target}, " + f"final transform: {self.final_transform}" + ) + logger.info(f"loaded {len(self.dataset)} examples") + + self.is_compute_mask = compute_mask + self.patches = (input_size // patch_size) ** 2 + self.mask_prob = mask_prob + self.mask_prob_adjust = mask_prob_adjust + self.mask_length = mask_length + self.inverse_mask = inverse_mask + self.expand_adjacent = expand_adjacent + self.mask_dropout = mask_dropout + self.non_overlapping = non_overlapping + self.require_same_masks = require_same_masks + self.clone_batch = clone_batch + + def __getitem__(self, index): + img, _ = self.dataset[index] + + img = self.transform_train(img) + + source = None + target = None + if self.transform_source is not None: + source = self.final_transform(self.transform_source(img)) + if self.transform_target is not None: + target = self.final_transform(self.transform_target(img)) + + if source is None: + img = self.final_transform(img) + + v = {"id": index, self.key: source if source is not None else img} + if target is not None: + v["target"] = target + + if self.is_compute_mask: + if self.mask_length == 1: + mask = compute_block_mask_1d( + shape=(self.clone_batch, self.patches), + mask_prob=self.mask_prob, + mask_length=self.mask_length, + mask_prob_adjust=self.mask_prob_adjust, + inverse_mask=self.inverse_mask, + require_same_masks=True, + ) + else: + mask = compute_block_mask_2d( + shape=(self.clone_batch, self.patches), + mask_prob=self.mask_prob, + mask_length=self.mask_length, + mask_prob_adjust=self.mask_prob_adjust, + inverse_mask=self.inverse_mask, + require_same_masks=True, + expand_adjcent=self.expand_adjacent, + mask_dropout=self.mask_dropout, + non_overlapping=self.non_overlapping, + ) + + v["precomputed_mask"] = mask + + return v + + def __len__(self): + return len(self.dataset) + + def collater(self, samples): + if len(samples) == 0: + return {} + + collated_img = torch.stack([s[self.key] for s in samples], dim=0) + + res = { + "id": torch.LongTensor([s["id"] for s in samples]), + "net_input": { + self.key: collated_img, + }, + } + + if "target" in samples[0]: + collated_target = torch.stack([s["target"] for s in samples], dim=0) + res["net_input"]["target"] = collated_target + + if "precomputed_mask" in samples[0]: + collated_mask = torch.cat([s["precomputed_mask"] for s in samples], dim=0) + res["net_input"]["precomputed_mask"] = collated_mask + + return res + + def num_tokens(self, index): + return 1 + + def size(self, index): + return 1 + + @property + def sizes(self): + return np.full((len(self),), 1) + + def ordered_indices(self): + """Return an ordered list of indices. Batches will be constructed based + on this order.""" + if self.shuffle: + order = [np.random.permutation(len(self))] + else: + order = [np.arange(len(self))] + + return order[0] diff --git a/examples/data2vec/data/modality.py b/examples/data2vec/data/modality.py new file mode 100644 index 0000000000..aa23ac94f7 --- /dev/null +++ b/examples/data2vec/data/modality.py @@ -0,0 +1,14 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +from enum import Enum, auto + + +class Modality(Enum): + AUDIO = auto() + IMAGE = auto() + TEXT = auto() diff --git a/examples/data2vec/data/path_dataset.py b/examples/data2vec/data/path_dataset.py new file mode 100644 index 0000000000..02010058e6 --- /dev/null +++ b/examples/data2vec/data/path_dataset.py @@ -0,0 +1,64 @@ +import glob +import os +from typing import List, Optional, Tuple + +import logging +import numpy as np +import torchvision.transforms.functional as TF +import PIL +from PIL import Image +from torchvision.datasets import VisionDataset + +logger = logging.getLogger(__name__) + + +class PathDataset(VisionDataset): + def __init__( + self, + root: List[str], + loader: None = None, + transform: Optional[str] = None, + extra_transform: Optional[str] = None, + mean: Optional[List[float]] = None, + std: Optional[List[float]] = None, + ): + super().__init__(root=root) + + PIL.Image.MAX_IMAGE_PIXELS = 256000001 + + self.files = [] + for folder in self.root: + self.files.extend( + sorted(glob.glob(os.path.join(folder, "**", "*.jpg"), recursive=True)) + ) + self.files.extend( + sorted(glob.glob(os.path.join(folder, "**", "*.png"), recursive=True)) + ) + + self.transform = transform + self.extra_transform = extra_transform + self.mean = mean + self.std = std + + self.loader = loader + + logger.info(f"loaded {len(self.files)} samples from {root}") + + assert (mean is None) == (std is None) + + def __len__(self) -> int: + return len(self.files) + + def __getitem__(self, idx) -> Tuple[np.ndarray, np.ndarray]: + path = self.files[idx] + + if self.loader is not None: + return self.loader(path), None + + img = Image.open(path).convert("RGB") + if self.transform is not None: + img = self.transform(img) + img = TF.to_tensor(img) + if self.mean is not None and self.std is not None: + img = TF.normalize(img, self.mean, self.std) + return img, None diff --git a/examples/data2vec/fb_convert_beit_cp.py b/examples/data2vec/fb_convert_beit_cp.py new file mode 100644 index 0000000000..cf42ace762 --- /dev/null +++ b/examples/data2vec/fb_convert_beit_cp.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import torch + +from omegaconf import OmegaConf + +from fairseq.criterions.model_criterion import ModelCriterionConfig +from fairseq.dataclass.configs import FairseqConfig + +from tasks import ImageClassificationConfig, ImagePretrainingConfig +from models.data2vec_image_classification import ( + Data2VecImageClassificationConfig, + Data2VecImageClassificationModel, +) +from models.data2vec_vision import Data2VecVisionConfig, Data2VecVisionModel + + +def get_parser(): + parser = argparse.ArgumentParser( + description="convert beit checkpoint into data2vec - vision checkpoint" + ) + # fmt: off + parser.add_argument('checkpoint', help='checkpoint to convert') + parser.add_argument('--output', required=True, metavar='PATH', help='where to output converted checkpoint') + parser.add_argument('--type', type=str, choices=['vision', 'image_classification'], default='image_classification', help='type of model to upgrade') + parser.add_argument('--inception_norms', action='store_true', default=False) + # fmt: on + + return parser + + +def update_checkpoint(model_dict, prefix, is_nested): + + replace_paths = { + "cls_token": "model.cls_emb" if is_nested else "cls_emb", + "patch_embed": "model.patch_embed" if is_nested else "patch_embed", + "mask_token": "mask_emb", + } + + starts_with = { + "patch_embed.proj": "model.patch_embed.conv" + if is_nested + else "patch_embed.conv", + "lm_head": "final_proj", + "fc_norm": "fc_norm", + "head": "head", + } + + partial = { + "mlp.fc1": "mlp.0", + "mlp.fc2": "mlp.2", + } + + for k in list(model_dict.keys()): + for sw, r in starts_with.items(): + if k.startswith(sw): + replace_paths[k] = k.replace(sw, r) + for p, r in partial.items(): + if p in k: + replace_paths[k] = prefix + k.replace(p, r) + + if prefix != "": + for k in list(model_dict.keys()): + if k not in replace_paths: + replace_paths[k] = prefix + k + + for k in list(model_dict.keys()): + if k in replace_paths: + model_dict[replace_paths[k]] = model_dict[k] + if k != replace_paths[k]: + del model_dict[k] + + return model_dict + + +def main(): + parser = get_parser() + args = parser.parse_args() + + cp = torch.load(args.checkpoint, map_location="cpu") + + cfg = FairseqConfig( + criterion=ModelCriterionConfig(_name="model", log_keys=["correct"]), + ) + + if args.type == "image_classification": + + cfg.task = ImageClassificationConfig( + _name="image_classification", + data=".", + ) + + if args.inception_norms: + cfg.task.normalization_mean = [0.5, 0.5, 0.5] + cfg.task.normalization_std = [0.5, 0.5, 0.5] + + cfg.model = Data2VecImageClassificationConfig( + _name="data2vec_image_classification", + ) + cfg.model.pretrained_model_args = FairseqConfig( + model=Data2VecVisionConfig( + _name="data2vec_vision", shared_rel_pos_bias=False + ), + task=ImagePretrainingConfig( + _name="image_pretraining", + ), + ) + + cfg = OmegaConf.create(cfg) + + state = { + "cfg": OmegaConf.to_container(cfg, resolve=True, enum_to_str=True), + "model": cp["module"], + "best_loss": None, + "optimizer": None, + "extra_state": {}, + } + + model = Data2VecImageClassificationModel(cfg.model) + model.load_state_dict( + update_checkpoint(state["model"], prefix="model.encoder.", is_nested=True), + strict=True, + ) + elif args.type == "vision": + cfg.task = ImagePretrainingConfig( + _name="image_pretraining", + data=".", + ) + + if args.inception_norms: + cfg.task.normalization_mean = [0.5, 0.5, 0.5] + cfg.task.normalization_std = [0.5, 0.5, 0.5] + + cfg.model = Data2VecVisionConfig( + _name="data2vec_vision", + ) + cfg = OmegaConf.create(cfg) + + state = { + "cfg": OmegaConf.to_container(cfg, resolve=True, enum_to_str=True), + "model": cp["model"], + "best_loss": None, + "optimizer": None, + "extra_state": {}, + } + + model = Data2VecVisionModel(cfg.model) + model.load_state_dict( + update_checkpoint(state["model"], prefix="encoder.", is_nested=False), + strict=True, + ) + else: + raise Exception("unsupported type " + args.type) + + print(state["cfg"], state.keys()) + torch.save(state, args.output) + + +if __name__ == "__main__": + main() diff --git a/examples/data2vec/models/__init__.py b/examples/data2vec/models/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/data2vec/models/audio_classification.py b/examples/data2vec/models/audio_classification.py new file mode 100644 index 0000000000..06d2158267 --- /dev/null +++ b/examples/data2vec/models/audio_classification.py @@ -0,0 +1,614 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import contextlib +import logging +import re +from dataclasses import dataclass, field +from typing import Any, Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +from omegaconf import II, MISSING, open_dict + +from fairseq import checkpoint_utils, tasks +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.models import ( + BaseFairseqModel, + register_model, +) +from fairseq.models.wav2vec.wav2vec2 import MASKING_DISTRIBUTION_CHOICES +from fairseq.modules import TransposeLast +from fairseq.tasks import FairseqTask + +logger = logging.getLogger(__name__) + + +@dataclass +class AudioClassificationConfig(FairseqDataclass): + model_path: str = field( + default=MISSING, metadata={"help": "path to wav2vec 2.0 model"} + ) + no_pretrained_weights: bool = field( + default=False, metadata={"help": "if true, does not load pretrained weights"} + ) + dropout_input: float = field( + default=0.0, + metadata={"help": "dropout to apply to the input (after feat extr)"}, + ) + final_dropout: float = field( + default=0.0, + metadata={"help": "dropout after transformer and before final projection"}, + ) + dropout: float = field( + default=0.0, metadata={"help": "dropout probability inside wav2vec 2.0 model"} + ) + attention_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability for attention weights inside wav2vec 2.0 model" + }, + ) + activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN inside wav2vec 2.0 model" + }, + ) + + # masking + apply_mask: bool = field( + default=False, metadata={"help": "apply masking during fine-tuning"} + ) + mask_length: int = field( + default=10, metadata={"help": "repeat the mask indices multiple times"} + ) + mask_prob: float = field( + default=0.5, + metadata={ + "help": "probability of replacing a token with mask (normalized by length)" + }, + ) + mask_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose masks"} + ) + mask_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument (used for more complex distributions), " + "see help in compute_mask_indices" + }, + ) + no_mask_overlap: bool = field( + default=False, metadata={"help": "whether to allow masks to overlap"} + ) + mask_min_space: Optional[int] = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + require_same_masks: bool = field( + default=True, + metadata={ + "help": "whether to number of masked timesteps must be the same across all " + "examples in a batch" + }, + ) + mask_dropout: float = field( + default=0.0, + metadata={"help": "percent of masks to unmask for each sample"}, + ) + + # channel masking + mask_channel_length: int = field( + default=10, metadata={"help": "length of the mask for features (channels)"} + ) + mask_channel_prob: float = field( + default=0.0, metadata={"help": "probability of replacing a feature with 0"} + ) + mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", + metadata={"help": "how to choose mask length for channel masking"}, + ) + mask_channel_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument (used for more complex distributions), " + "see help in compute_mask_indicesh" + }, + ) + no_mask_channel_overlap: bool = field( + default=False, metadata={"help": "whether to allow channel masks to overlap"} + ) + freeze_finetune_updates: int = field( + default=0, metadata={"help": "dont finetune wav2vec for this many updates"} + ) + feature_grad_mult: float = field( + default=0.0, metadata={"help": "reset feature grad mult in wav2vec 2.0 to this"} + ) + layerdrop: float = field( + default=0.0, metadata={"help": "probability of dropping a layer in wav2vec 2.0"} + ) + mask_channel_min_space: Optional[int] = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + mask_channel_before: bool = False + normalize: bool = II("task.normalize") + data: str = II("task.data") + # this holds the loaded wav2vec args + d2v_args: Any = None + offload_activations: bool = field( + default=False, metadata={"help": "offload_activations"} + ) + min_params_to_wrap: int = field( + default=int(1e8), + metadata={ + "help": "minimum number of params for a layer to be wrapped with FSDP() when " + "training with --ddp-backend=fully_sharded. Smaller values will " + "improve memory efficiency, but may make torch.distributed " + "communication less efficient due to smaller input sizes. This option " + "is set to 0 (i.e., always wrap) when --checkpoint-activations or " + "--offload-activations are passed." + }, + ) + + checkpoint_activations: bool = field( + default=False, + metadata={"help": "recompute activations and save memory for extra compute"}, + ) + ddp_backend: str = II("distributed_training.ddp_backend") + + prediction_mode: str = "lin_softmax" + eval_prediction_mode: Optional[str] = None + conv_kernel: int = -1 + conv_stride: int = 1 + two_convs: bool = False + extreme_factor: float = 1.0 + + conv_feature_layers: Optional[str] = field( + default=None, + metadata={ + "help": "string describing convolutional feature extraction layers in form of a python list that contains " + "[(dim, kernel_size, stride), ...]" + }, + ) + + mixup_prob: float = 1.0 + source_mixup: float = -1 + same_mixup: bool = True + label_mixup: bool = False + + gain_mode: str = "none" + + +@register_model("audio_classification", dataclass=AudioClassificationConfig) +class AudioClassificationModel(BaseFairseqModel): + def __init__(self, cfg: AudioClassificationConfig, num_classes): + super().__init__() + + self.apply_mask = cfg.apply_mask + self.cfg = cfg + + arg_overrides = { + "dropout": cfg.dropout, + "activation_dropout": cfg.activation_dropout, + "dropout_input": cfg.dropout_input, + "attention_dropout": cfg.attention_dropout, + "mask_length": cfg.mask_length, + "mask_prob": cfg.mask_prob, + "require_same_masks": getattr(cfg, "require_same_masks", True), + "mask_dropout": getattr(cfg, "mask_dropout", 0), + "mask_selection": cfg.mask_selection, + "mask_other": cfg.mask_other, + "no_mask_overlap": cfg.no_mask_overlap, + "mask_channel_length": cfg.mask_channel_length, + "mask_channel_prob": cfg.mask_channel_prob, + "mask_channel_before": cfg.mask_channel_before, + "mask_channel_selection": cfg.mask_channel_selection, + "mask_channel_other": cfg.mask_channel_other, + "no_mask_channel_overlap": cfg.no_mask_channel_overlap, + "encoder_layerdrop": cfg.layerdrop, + "feature_grad_mult": cfg.feature_grad_mult, + "checkpoint_activations": cfg.checkpoint_activations, + "offload_activations": cfg.offload_activations, + "min_params_to_wrap": cfg.min_params_to_wrap, + "mixup": -1, + } + + if cfg.conv_feature_layers is not None: + arg_overrides["conv_feature_layers"] = cfg.conv_feature_layers + + if cfg.d2v_args is None: + state = checkpoint_utils.load_checkpoint_to_cpu( + cfg.model_path, arg_overrides + ) + d2v_args = state.get("cfg", None) + if d2v_args is None: + d2v_args = convert_namespace_to_omegaconf(state["args"]) + d2v_args.criterion = None + d2v_args.lr_scheduler = None + cfg.d2v_args = d2v_args + + logger.info(d2v_args) + + else: + state = None + d2v_args = cfg.d2v_args + + model_normalized = d2v_args.task.get( + "normalize", d2v_args.model.get("normalize", False) + ) + assert cfg.normalize == model_normalized, ( + "Fine-tuning works best when data normalization is the same. " + "Please check that --normalize is set or unset for both pre-training and here" + ) + + if hasattr(cfg, "checkpoint_activations") and cfg.checkpoint_activations: + with open_dict(d2v_args): + d2v_args.model.checkpoint_activations = cfg.checkpoint_activations + + d2v_args.task.data = cfg.data + task = tasks.setup_task(d2v_args.task) + model = task.build_model(d2v_args.model, from_checkpoint=True) + + model.remove_pretraining_modules() + + if state is not None and not cfg.no_pretrained_weights: + self.load_model_weights(state, model, cfg) + + d = d2v_args.model.encoder_embed_dim + + self.d2v_model = model + + self.final_dropout = nn.Dropout(cfg.final_dropout) + self.freeze_finetune_updates = cfg.freeze_finetune_updates + self.num_updates = 0 + + for p in self.parameters(): + p.param_group = "pretrained" + + if cfg.prediction_mode == "proj_avg_proj": + self.proj = nn.Linear(d, d * 2) + self.proj2 = nn.Linear(d * 2, num_classes) + + for p in self.proj.parameters(): + p.param_group = "projection" + for p in self.proj2.parameters(): + p.param_group = "projection" + elif self.cfg.prediction_mode == "summary_proj": + self.proj = nn.Linear(d // 3, num_classes) + for p in self.proj.parameters(): + p.param_group = "projection" + elif self.cfg.conv_kernel > 1 and not self.cfg.two_convs: + self.proj = nn.Sequential( + TransposeLast(), + nn.Conv1d(d, num_classes, kernel_size=self.cfg.conv_kernel, stride=self.cfg.conv_stride), + TransposeLast(), + ) + for p in self.proj.parameters(): + p.param_group = "projection" + elif self.cfg.conv_kernel > 0 and self.cfg.two_convs: + self.proj = nn.Sequential( + TransposeLast(), + nn.Conv1d(d, d, kernel_size=self.cfg.conv_kernel, stride=self.cfg.conv_stride), + TransposeLast(), + nn.GELU(), + nn.Linear(d, num_classes), + ) + for p in self.proj.parameters(): + p.param_group = "projection" + else: + self.proj = nn.Linear(d, num_classes) + for p in self.proj.parameters(): + p.param_group = "projection" + + def upgrade_state_dict_named(self, state_dict, name): + super().upgrade_state_dict_named(state_dict, name) + return state_dict + + @classmethod + def build_model(cls, cfg: AudioClassificationConfig, task: FairseqTask): + """Build a new model instance.""" + + assert hasattr(task, "labels"), f"Task {task} must have an attribute 'labels'" + + return cls(cfg, len(task.labels)) + + def load_model_weights(self, state, model, cfg): + if cfg.ddp_backend == "fully_sharded": + from fairseq.distributed import FullyShardedDataParallel + + for name, module in model.named_modules(): + if "encoder.layers" in name and len(name.split(".")) == 3: + # Only for layers, we do a special handling and load the weights one by one + # We dont load all weights together as that wont be memory efficient and may + # cause oom + new_dict = { + k.replace(name + ".", ""): v + for (k, v) in state["model"].items() + if name + "." in k + } + assert isinstance(module, FullyShardedDataParallel) + with module.summon_full_params(): + module.load_state_dict(new_dict, strict=True) + module._reset_lazy_init() + + # Once layers are loaded, filter them out and load everything else. + r = re.compile("encoder.layers.\d.") + filtered_list = list(filter(r.match, state["model"].keys())) + + new_big_dict = { + k: v for (k, v) in state["model"].items() if k not in filtered_list + } + + model.load_state_dict(new_big_dict, strict=False) + else: + if "_ema" in state["model"]: + del state["model"]["_ema"] + model.load_state_dict(state["model"], strict=False) + + def set_num_updates(self, num_updates): + """Set the number of parameters updates.""" + super().set_num_updates(num_updates) + self.num_updates = num_updates + + def compute_gain(self, sound, fs=16_000, min_db=-80.0, mode="A_weighting"): + if fs == 16000: + n_fft = 2048 + elif fs == 44100: + n_fft = 4096 + else: + raise Exception("Invalid fs {}".format(fs)) + stride = n_fft // 2 + + def a_weight(fs, n_fft, min_db=-80.0): + freq = np.linspace(0, fs // 2, n_fft // 2 + 1) + freq_sq = np.power(freq, 2) + freq_sq[0] = 1.0 + weight = 2.0 + 20.0 * ( + 2 * np.log10(12194) + + 2 * np.log10(freq_sq) + - np.log10(freq_sq + 12194 ** 2) + - np.log10(freq_sq + 20.6 ** 2) + - 0.5 * np.log10(freq_sq + 107.7 ** 2) + - 0.5 * np.log10(freq_sq + 737.9 ** 2) + ) + weight = np.maximum(weight, min_db) + + return weight + + gain = [] + for i in range(0, len(sound) - n_fft + 1, stride): + if mode == "RMSE": + g = np.mean(sound[i : i + n_fft] ** 2) + elif mode == "A_weighting": + spec = np.fft.rfft(np.hanning(n_fft + 1)[:-1] * sound[i : i + n_fft]) + power_spec = np.abs(spec) ** 2 + a_weighted_spec = power_spec * np.power(10, a_weight(fs, n_fft) / 10) + g = np.sum(a_weighted_spec) + else: + raise Exception("Invalid mode {}".format(mode)) + gain.append(g) + + gain = np.array(gain) + gain = np.maximum(gain, np.power(10, min_db / 10)) + gain_db = 10 * np.log10(gain) + + return gain_db + + # adapted from https://github.com/mil-tokyo/bc_learning_sound/blob/master/utils.py + def compute_gain_torch(self, sound, fs=16_000, min_db=-80.0, mode="A_weighting"): + if fs == 16000: + n_fft = 2048 + elif fs == 44100: + n_fft = 4096 + else: + raise Exception("Invalid fs {}".format(fs)) + + if mode == "A_weighting": + if not hasattr(self, f"a_weight"): + self.a_weight = {} + + if fs not in self.a_weight: + + def a_weight(fs, n_fft, min_db=-80.0): + freq = np.linspace(0, fs // 2, n_fft // 2 + 1) + freq_sq = freq ** 2 + freq_sq[0] = 1.0 + weight = 2.0 + 20.0 * ( + 2 * np.log10(12194) + + 2 * np.log10(freq_sq) + - np.log10(freq_sq + 12194 ** 2) + - np.log10(freq_sq + 20.6 ** 2) + - 0.5 * np.log10(freq_sq + 107.7 ** 2) + - 0.5 * np.log10(freq_sq + 737.9 ** 2) + ) + weight = np.maximum(weight, min_db) + + return weight + + self.a_weight[fs] = torch.from_numpy( + np.power(10, a_weight(fs, n_fft, min_db) / 10) + ).to(device=sound.device) + + sound = sound.unfold(-1, n_fft, n_fft // 2) + + if mode == "RMSE": + sound = sound ** 2 + g = sound.mean(-1) + elif mode == "A_weighting": + w = torch.hann_window(n_fft, device=sound.device) * sound + spec = torch.fft.rfft(w) + power_spec = spec.abs() ** 2 + a_weighted_spec = power_spec * self.a_weight[fs] + g = a_weighted_spec.sum(-1) + else: + raise Exception("Invalid mode {}".format(mode)) + + gain = torch.maximum(g, torch.tensor(10 ** (min_db / 10), device=g.device)) + gain_db = 10 * torch.log10(gain) + + return gain_db + + def forward(self, source, padding_mask, label=None, **kwargs): + + if self.cfg.source_mixup >= 0 and self.training and self.cfg.mixup_prob > 0: + with torch.no_grad(): + mixed_source = source + mix_mask = None + if self.cfg.mixup_prob < 1: + mix_mask = ( + torch.empty((source.size(0),), device=source.device) + .bernoulli_(self.cfg.mixup_prob) + .bool() + ) + mixed_source = source[mix_mask] + + r = ( + torch.FloatTensor( + 1 if self.cfg.same_mixup else mixed_source.size(0) + ) + .uniform_(max(1e-6, self.cfg.source_mixup), 1) + .to(dtype=source.dtype, device=source.device) + ) + + mixup_perm = torch.randperm(source.size(0)) + s2 = source[mixup_perm] + + if self.cfg.gain_mode == "none": + p = r.unsqueeze(-1) + if mix_mask is not None: + s2 = s2[mix_mask] + else: + if self.cfg.gain_mode == "naive_rms": + G1 = source.pow(2).mean(dim=-1).sqrt() + else: + G1, _ = self.compute_gain_torch( + source, mode=self.cfg.gain_mode + ).max(-1) + G1 = G1.to(dtype=source.dtype) + + G2 = G1[mixup_perm] + + if mix_mask is not None: + G1 = G1[mix_mask] + G2 = G2[mix_mask] + s2 = s2[mix_mask] + + p = 1 / (1 + 10 ** ((G1 - G2) / 20) * (1 - r) / r) + p = p.unsqueeze(-1) + + mixed = (p * mixed_source) + (1 - p) * s2 + + if mix_mask is None: + source = mixed / torch.sqrt(p ** 2 + (1 - p) ** 2) + else: + source[mix_mask] = mixed / torch.sqrt(p ** 2 + (1 - p) ** 2) + + if label is not None and self.cfg.label_mixup: + r = r.unsqueeze(-1) + if mix_mask is None: + label = label * r + (1 - r) * label[mixup_perm] + else: + label[mix_mask] = ( + label[mix_mask] * r + (1 - r) * label[mixup_perm][mix_mask] + ) + + d2v_args = { + "source": source, + "padding_mask": padding_mask, + "mask": self.apply_mask and self.training, + } + + ft = self.freeze_finetune_updates <= self.num_updates + + with torch.no_grad() if not ft else contextlib.ExitStack(): + res = self.d2v_model.extract_features(**d2v_args) + + x = res["x"] + padding_mask = res["padding_mask"] + if padding_mask is not None: + x[padding_mask] = 0 + + x = self.final_dropout(x) + + if self.training or ( + self.cfg.eval_prediction_mode is None or self.cfg.eval_prediction_mode == "" + ): + prediction_mode = self.cfg.prediction_mode + else: + prediction_mode = self.cfg.eval_prediction_mode + + if prediction_mode == "average_before": + x = x.mean(dim=1) + + if prediction_mode != "summary_mha" and prediction_mode != "summary_proj" and prediction_mode != "cls": + x = self.proj(x) + + logits = True + if prediction_mode == "lin_softmax": + x = F.logsigmoid(x.float()) + x = torch.logsumexp(x + x, dim=1) - torch.logsumexp(x, dim=1) + x = x.clamp(max=0) + x = x - torch.log(-(torch.expm1(x))) + elif prediction_mode == "extremized_odds": + x = x.float().sum(dim=1) + x = x * self.cfg.extreme_factor + elif prediction_mode == "average_before": + x = x.float() + elif prediction_mode == "average": + x = x.float().mean(dim=1) + elif prediction_mode == "average_sigmoid": + x = torch.sigmoid(x.float()) + x = x.mean(dim=1) + logits = False + elif prediction_mode == "max": + x, _ = x.float().max(dim=1) + elif prediction_mode == "max_sigmoid": + x = torch.sigmoid(x.float()) + x, _ = x.float().max(dim=1) + logits = False + elif prediction_mode == "proj_avg_proj": + x = x.mean(dim=1) + x = self.proj2(x) + elif prediction_mode == "summary_mha" or prediction_mode == "summary_proj": + x = self.d2v_model.summary( + x, padding_mask, proj=prediction_mode == "summary_proj" + ) + x = x.type_as(source) + x = self.proj(x) + elif prediction_mode == "cls": + x = x[:,0] + x = self.proj(x) + else: + raise Exception(f"unknown prediction mode {prediction_mode}") + + if label is None: + return torch.sigmoid(x) if logits else x + + x = torch.nan_to_num(x) + + if logits: + loss = F.binary_cross_entropy_with_logits( + x, label.float(), reduction="none" + ) + else: + loss = F.binary_cross_entropy(x, label.float(), reduction="none") + + result = { + "losses": { + "main": loss, + }, + "sample_size": label.sum(), + } + + if not self.training: + result["_predictions"] = torch.sigmoid(x) if logits else x + result["_targets"] = label + + return result diff --git a/examples/data2vec/models/data2vec2.py b/examples/data2vec/models/data2vec2.py new file mode 100644 index 0000000000..0c61b37081 --- /dev/null +++ b/examples/data2vec/models/data2vec2.py @@ -0,0 +1,813 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import math +from dataclasses import dataclass, field +from typing import Optional, Callable +from functools import partial +import numpy as np + +from omegaconf import II + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.distributed as dist + +from fairseq.modules import EMAModule, EMAModuleConfig + +from fairseq.dataclass import FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model + +from examples.data2vec.data.modality import Modality + +from examples.data2vec.models.modalities.base import ( + MaskSeed, + D2vModalityConfig, + ModalitySpecificEncoder, + get_annealed_rate, +) +from examples.data2vec.models.modalities.modules import ( + D2vDecoderConfig, + AltBlock, + Decoder1d, +) + +from examples.data2vec.models.modalities.audio import ( + D2vAudioConfig, + AudioEncoder, +) +from examples.data2vec.models.modalities.images import ( + D2vImageConfig, + ImageEncoder, +) +from examples.data2vec.models.modalities.text import ( + D2vTextConfig, + TextEncoder, +) + +logger = logging.getLogger(__name__) + + +@dataclass +class D2vModalitiesConfig(FairseqDataclass): + audio: D2vAudioConfig = D2vAudioConfig() + image: D2vImageConfig = D2vImageConfig() + text: D2vTextConfig = D2vTextConfig() + + +@dataclass +class Data2VecMultiConfig(FairseqDataclass): + + loss_beta: float = field( + default=0, metadata={"help": "beta for smooth l1 loss. 0 means use l2 loss"} + ) + loss_scale: Optional[float] = field( + default=None, + metadata={ + "help": "scale the reconstruction loss by this constant. if None then scales by 1/sqrt(dim)" + }, + ) + + depth: int = 8 + start_drop_path_rate: float = 0 + end_drop_path_rate: float = 0 + num_heads: int = 12 + norm_eps: float = 1e-6 + norm_affine: bool = True + encoder_dropout: float = 0.1 + post_mlp_drop: float = 0.1 + attention_dropout: float = 0.1 + activation_dropout: float = 0.0 + dropout_input: float = 0.0 + layerdrop: float = 0.0 + embed_dim: int = 768 + mlp_ratio: float = 4 + layer_norm_first: bool = False + + average_top_k_layers: int = field( + default=8, metadata={"help": "how many layers to average"} + ) + + end_of_block_targets: bool = False + + clone_batch: int = 1 + + layer_norm_target_layer: bool = False + batch_norm_target_layer: bool = False + instance_norm_target_layer: bool = False + instance_norm_targets: bool = False + layer_norm_targets: bool = False + + ema_decay: float = field(default=0.999, metadata={"help": "initial ema decay rate"}) + ema_same_dtype: bool = True + log_norms: bool = True + ema_end_decay: float = field( + default=0.9999, metadata={"help": "final ema decay rate"} + ) + + # when to finish annealing ema decay rate + ema_anneal_end_step: int = II("optimization.max_update") + + ema_encoder_only: bool = field( + default=True, + metadata={ + "help": "whether to momentum update only the shared transformer encoder" + }, + ) + + max_update: int = II("optimization.max_update") + + modalities: D2vModalitiesConfig = D2vModalitiesConfig() + + shared_decoder: Optional[D2vDecoderConfig] = None + + min_target_var: float = field( + default=0.1, metadata={"help": "stop training if target var falls below this"} + ) + min_pred_var: float = field( + default=0.01, + metadata={"help": "stop training if prediction var falls below this"}, + ) + + supported_modality: Optional[Modality] = None + mae_init: bool = False + + seed: int = II("common.seed") + + skip_ema: bool = False + + cls_loss: float = 0 + recon_loss: float = 0 + d2v_loss: float = 1 + + decoder_group: bool = False + + +@register_model("data2vec_multi", dataclass=Data2VecMultiConfig) +class Data2VecMultiModel(BaseFairseqModel): + def make_modality_encoder( + self, + cfg: D2vModalityConfig, + embed_dim: int, + make_block: Callable[[float], nn.ModuleList], + norm_layer: Callable[[int], nn.LayerNorm], + layer_norm_first: bool, + alibi_biases, + task, + ) -> ModalitySpecificEncoder: + if cfg.type == Modality.AUDIO: + enc_cls = AudioEncoder + elif cfg.type == Modality.IMAGE: + enc_cls = ImageEncoder + elif cfg.type == Modality.TEXT: + enc_cls = TextEncoder + if hasattr(task, "text_task"): + task = task.text_task + else: + raise Exception(f"unsupported modality {cfg.type}") + + return enc_cls( + cfg, + embed_dim, + make_block, + norm_layer, + layer_norm_first, + alibi_biases, + task, + ) + + def __init__(self, cfg: Data2VecMultiConfig, modalities, skip_ema=False, task=None): + super().__init__() + self.cfg = cfg + self.modalities = modalities + self.task = task + + make_layer_norm = partial( + nn.LayerNorm, eps=cfg.norm_eps, elementwise_affine=cfg.norm_affine + ) + + def make_block(drop_path, dim=None, heads=None): + return AltBlock( + cfg.embed_dim if dim is None else dim, + cfg.num_heads if heads is None else heads, + cfg.mlp_ratio, + qkv_bias=True, + drop=cfg.encoder_dropout, + attn_drop=cfg.attention_dropout, + mlp_drop=cfg.activation_dropout, + post_mlp_drop=cfg.post_mlp_drop, + drop_path=drop_path, + norm_layer=make_layer_norm, + layer_norm_first=cfg.layer_norm_first, + ffn_targets=not cfg.end_of_block_targets, + ) + + self.alibi_biases = {} + self.modality_encoders = nn.ModuleDict() + for mod in self.modalities: + mod_cfg = getattr(cfg.modalities, mod.name.lower()) + enc = self.make_modality_encoder( + mod_cfg, + cfg.embed_dim, + make_block, + make_layer_norm, + cfg.layer_norm_first, + self.alibi_biases, + task, + ) + self.modality_encoders[mod.name] = enc + + self.ema = None + + self.average_top_k_layers = cfg.average_top_k_layers + self.loss_beta = cfg.loss_beta + self.loss_scale = cfg.loss_scale + + self.dropout_input = nn.Dropout(cfg.dropout_input) + + dpr = np.linspace(cfg.start_drop_path_rate, cfg.end_drop_path_rate, cfg.depth) + + self.blocks = nn.ModuleList([make_block(dpr[i]) for i in range(cfg.depth)]) + + self.norm = None + if cfg.layer_norm_first: + self.norm = make_layer_norm(cfg.embed_dim) + + if self.cfg.mae_init: + self.apply(self._init_weights) + else: + from fairseq.modules.transformer_sentence_encoder import init_bert_params + + self.apply(init_bert_params) + + for mod_enc in self.modality_encoders.values(): + mod_enc.reset_parameters() + + if not skip_ema: + self.ema = self.make_ema_teacher(cfg.ema_decay) + self.shared_decoder = ( + Decoder1d(cfg.shared_decoder, cfg.embed_dim) + if self.cfg.shared_decoder is not None + else None + ) + if self.shared_decoder is not None: + self.shared_decoder.apply(self._init_weights) + + self.recon_proj = None + if cfg.recon_loss > 0: + self.recon_proj = nn.Linear(cfg.embed_dim, cfg.embed_dim) + + for pn, p in self.named_parameters(): + if len(p.shape) == 1 or pn.endswith(".bias") or "alibi_scale" in pn: + p.optim_overrides = {"optimizer": {"weight_decay_scale": 0}} + if cfg.decoder_group and "decoder" in pn: + p.param_group = "decoder" + + self.num_updates = 0 + + def _init_weights(self, m): + + try: + from apex.normalization import FusedLayerNorm + + fn = FusedLayerNorm + except: + fn = nn.LayerNorm + + if isinstance(m, nn.Linear): + torch.nn.init.xavier_uniform_(m.weight) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm) or isinstance(m, fn): + if m.bias is not None: + nn.init.constant_(m.bias, 0) + if m.weight is not None: + nn.init.constant_(m.weight, 1.0) + + @torch.no_grad() + def make_ema_teacher(self, ema_decay): + ema_config = EMAModuleConfig( + ema_decay=ema_decay, + ema_fp32=True, + log_norms=self.cfg.log_norms, + add_missing_params=False, + ) + + model_copy = self.make_target_model() + + return EMAModule( + model_copy, + ema_config, + copy_model=False, + ) + + def make_target_model(self): + logger.info("making target model") + + model_copy = Data2VecMultiModel( + self.cfg, self.modalities, skip_ema=True, task=self.task + ) + + if self.cfg.ema_encoder_only: + model_copy = model_copy.blocks + for p_s, p_t in zip(self.blocks.parameters(), model_copy.parameters()): + p_t.data.copy_(p_s.data) + else: + for p_s, p_t in zip(self.parameters(), model_copy.parameters()): + p_t.data.copy_(p_s.data) + + for mod_enc in model_copy.modality_encoders.values(): + mod_enc.decoder = None + if not mod_enc.modality_cfg.ema_local_encoder: + mod_enc.local_encoder = None + mod_enc.project_features = None + + model_copy.requires_grad_(False) + return model_copy + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + + if self.ema is not None and ( + (self.num_updates == 0 and num_updates > 1) + or self.num_updates >= num_updates + ): + pass + elif self.training and self.ema is not None: + ema_weight_decay = None + if self.cfg.ema_decay != self.cfg.ema_end_decay: + if num_updates >= self.cfg.ema_anneal_end_step: + decay = self.cfg.ema_end_decay + else: + decay = get_annealed_rate( + self.cfg.ema_decay, + self.cfg.ema_end_decay, + num_updates, + self.cfg.ema_anneal_end_step, + ) + self.ema.set_decay(decay, weight_decay=ema_weight_decay) + if self.ema.get_decay() < 1: + self.ema.step(self.blocks if self.cfg.ema_encoder_only else self) + + self.num_updates = num_updates + + def state_dict(self, destination=None, prefix="", keep_vars=False): + state = super().state_dict(destination, prefix, keep_vars) + + if self.ema is not None: + state[prefix + "_ema"] = self.ema.fp32_params + + return state + + def _load_from_state_dict(self, state_dict, prefix, *args, **kwargs): + k = prefix + "_ema" + if self.ema is not None: + assert k in state_dict + self.ema.restore(state_dict[k], True) + del state_dict[k] + elif k in state_dict: + del state_dict[k] + + return super()._load_from_state_dict(state_dict, prefix, *args, **kwargs) + + @classmethod + def build_model(cls, cfg: Data2VecMultiConfig, task=None): + """Build a new model instance.""" + if task is None or not hasattr(task, "supported_modalities"): + modalities = ( + [cfg.supported_modality] + if cfg.supported_modality is not None + else [ + Modality.AUDIO, + Modality.IMAGE, + Modality.TEXT, + ] + ) + else: + modalities = task.supported_modalities + return cls(cfg, modalities, task=task, skip_ema=cfg.skip_ema) + + def forward( + self, + source, + target=None, + id=None, + mode=None, + padding_mask=None, + mask=True, + features_only=False, + force_remove_masked=False, + remove_extra_tokens=True, + precomputed_mask=None, + ): + if mode is None: + assert self.cfg.supported_modality is not None + mode = self.cfg.supported_modality + + if isinstance(mode, Modality): + mode = mode.name + + feature_extractor = self.modality_encoders[mode] + + mask_seeds = None + if id is not None: + mask_seeds = MaskSeed(seed=self.cfg.seed, update=self.num_updates, ids=id) + + extractor_out = feature_extractor( + source, + padding_mask, + mask, + remove_masked=not features_only or force_remove_masked, + clone_batch=self.cfg.clone_batch if not features_only else 1, + mask_seeds=mask_seeds, + precomputed_mask=precomputed_mask, + ) + + x = extractor_out["x"] + encoder_mask = extractor_out["encoder_mask"] + masked_padding_mask = extractor_out["padding_mask"] + masked_alibi_bias = extractor_out.get("alibi_bias", None) + alibi_scale = extractor_out.get("alibi_scale", None) + + if self.dropout_input is not None: + x = self.dropout_input(x) + + layer_results = [] + for i, blk in enumerate(self.blocks): + if ( + not self.training + or self.cfg.layerdrop == 0 + or (np.random.random() > self.cfg.layerdrop) + ): + ab = masked_alibi_bias + if ab is not None and alibi_scale is not None: + scale = ( + alibi_scale[i] + if alibi_scale.size(0) > 1 + else alibi_scale.squeeze(0) + ) + ab = ab * scale.type_as(ab) + + x, lr = blk( + x, + padding_mask=masked_padding_mask, + alibi_bias=ab, + ) + if features_only: + layer_results.append(lr) + + if self.norm is not None: + x = self.norm(x) + + if features_only: + if remove_extra_tokens: + x = x[:, feature_extractor.modality_cfg.num_extra_tokens :] + if masked_padding_mask is not None: + masked_padding_mask = masked_padding_mask[ + :, feature_extractor.modality_cfg.num_extra_tokens : + ] + + return { + "x": x, + "padding_mask": masked_padding_mask, + "layer_results": layer_results, + "mask": encoder_mask, + } + + xs = [] + + if self.shared_decoder is not None: + dx = self.forward_decoder( + x, + feature_extractor, + self.shared_decoder, + encoder_mask, + ) + xs.append(dx) + if feature_extractor.decoder is not None: + dx = self.forward_decoder( + x, + feature_extractor, + feature_extractor.decoder, + encoder_mask, + ) + xs.append(dx) + orig_x = x + + assert len(xs) > 0 + + p = next(self.ema.model.parameters()) + device = x.device + dtype = x.dtype + ema_device = p.device + ema_dtype = p.dtype + + if not self.cfg.ema_same_dtype: + dtype = ema_dtype + + if ema_device != device or ema_dtype != dtype: + logger.info(f"adjusting ema dtype to {dtype} and device to {device}") + self.ema.model = self.ema.model.to(dtype=dtype, device=device) + ema_dtype = dtype + + def to_device(d): + for k, p in d.items(): + if isinstance(d[k], dict): + to_device(d[k]) + else: + d[k] = p.to(device=device) + + to_device(self.ema.fp32_params) + tm = self.ema.model + + with torch.no_grad(): + tm.eval() + + if self.cfg.ema_encoder_only: + assert target is None + ema_input = extractor_out["local_features"] + ema_input = feature_extractor.contextualized_features( + ema_input.to(dtype=ema_dtype), + padding_mask, + mask=False, + remove_masked=False, + ) + ema_blocks = tm + else: + ema_blocks = tm.blocks + if feature_extractor.modality_cfg.ema_local_encoder: + inp = ( + target.to(dtype=ema_dtype) + if target is not None + else source.to(dtype=ema_dtype) + ) + ema_input = tm.modality_encoders[mode]( + inp, + padding_mask, + mask=False, + remove_masked=False, + ) + else: + assert target is None + ema_input = extractor_out["local_features"] + ema_feature_enc = tm.modality_encoders[mode] + ema_input = ema_feature_enc.contextualized_features( + ema_input.to(dtype=ema_dtype), + padding_mask, + mask=False, + remove_masked=False, + ) + + ema_padding_mask = ema_input["padding_mask"] + ema_alibi_bias = ema_input.get("alibi_bias", None) + ema_alibi_scale = ema_input.get("alibi_scale", None) + ema_input = ema_input["x"] + + y = [] + ema_x = [] + extra_tokens = feature_extractor.modality_cfg.num_extra_tokens + for i, blk in enumerate(ema_blocks): + ab = ema_alibi_bias + if ab is not None and alibi_scale is not None: + scale = ( + ema_alibi_scale[i] + if ema_alibi_scale.size(0) > 1 + else ema_alibi_scale.squeeze(0) + ) + ab = ab * scale.type_as(ab) + + ema_input, lr = blk( + ema_input, + padding_mask=ema_padding_mask, + alibi_bias=ab, + ) + y.append(lr[:, extra_tokens:]) + ema_x.append(ema_input[:, extra_tokens:]) + + y = self.make_targets(y, self.average_top_k_layers) + orig_targets = y + + if self.cfg.clone_batch > 1: + y = y.repeat_interleave(self.cfg.clone_batch, 0) + + masked = encoder_mask.mask.unsqueeze(-1) + masked_b = encoder_mask.mask.bool() + y = y[masked_b] + + if xs[0].size(1) == masked_b.size(1): + xs = [x[masked_b] for x in xs] + else: + xs = [x.reshape(-1, x.size(-1)) for x in xs] + + sample_size = masked.sum().long() + + result = { + "losses": {}, + "sample_size": sample_size, + } + + sample_size = result["sample_size"] + + if self.cfg.cls_loss > 0: + assert extra_tokens > 0 + cls_target = orig_targets.mean(dim=1) + if self.cfg.clone_batch > 1: + cls_target = cls_target.repeat_interleave(self.cfg.clone_batch, 0) + cls_pred = x[:, extra_tokens - 1] + result["losses"]["cls"] = self.d2v_loss(cls_pred, cls_target) * ( + self.cfg.cls_loss * sample_size + ) + + if self.cfg.recon_loss > 0: + + with torch.no_grad(): + target = feature_extractor.patchify(source) + mean = target.mean(dim=-1, keepdim=True) + var = target.var(dim=-1, keepdim=True) + target = (target - mean) / (var + 1.0e-6) ** 0.5 + + if self.cfg.clone_batch > 1: + target = target.repeat_interleave(self.cfg.clone_batch, 0) + + if masked_b is not None: + target = target[masked_b] + + recon = xs[0] + if self.recon_proj is not None: + recon = self.recon_proj(recon) + + result["losses"]["recon"] = ( + self.d2v_loss(recon, target.float()) * self.cfg.recon_loss + ) + + if self.cfg.d2v_loss > 0: + for i, x in enumerate(xs): + reg_loss = self.d2v_loss(x, y) + n = f"{mode}_regression_{i}" if len(xs) > 1 else f"{mode}_regression" + result["losses"][n] = reg_loss * self.cfg.d2v_loss + + suffix = "" if len(self.modalities) == 1 else f"_{mode}" + with torch.no_grad(): + if encoder_mask is not None: + result["masked_pct"] = 1 - ( + encoder_mask.ids_keep.size(1) / encoder_mask.ids_restore.size(1) + ) + for i, x in enumerate(xs): + n = f"pred_var{suffix}_{i}" if len(xs) > 1 else f"pred_var{suffix}" + result[n] = self.compute_var(x.float()) + if self.ema is not None: + for k, v in self.ema.logs.items(): + result[k] = v + + y = y.float() + result[f"target_var{suffix}"] = self.compute_var(y) + + if self.num_updates > 5000: + if result[f"target_var{suffix}"] < self.cfg.min_target_var: + logger.error( + f"target var is {result[f'target_var{suffix}'].item()} < {self.cfg.min_target_var}, exiting ({mode})" + ) + raise Exception( + f"target var is {result[f'target_var{suffix}'].item()} < {self.cfg.min_target_var}, exiting ({mode})" + ) + + for k in result.keys(): + if k.startswith("pred_var") and result[k] < self.cfg.min_pred_var: + logger.error( + f"{k} is {result[k].item()} < {self.cfg.min_pred_var}, exiting ({mode})" + ) + raise Exception( + f"{k} is {result[k].item()} < {self.cfg.min_pred_var}, exiting ({mode})" + ) + + result["ema_decay"] = self.ema.get_decay() * 1000 + + return result + + def forward_decoder( + self, + x, + feature_extractor, + decoder, + mask_info, + ): + x = feature_extractor.decoder_input(x, mask_info) + x = decoder(*x) + + return x + + def d2v_loss(self, x, y): + x = x.view(-1, x.size(-1)).float() + y = y.view(-1, x.size(-1)) + + if self.loss_beta == 0: + loss = F.mse_loss(x, y, reduction="none") + else: + loss = F.smooth_l1_loss(x, y, reduction="none", beta=self.loss_beta) + + if self.loss_scale is not None: + scale = self.loss_scale + else: + scale = 1 / math.sqrt(x.size(-1)) + + reg_loss = loss * scale + + return reg_loss + + def make_targets(self, y, num_layers): + + with torch.no_grad(): + target_layer_results = y[-num_layers:] + + permuted = False + if self.cfg.instance_norm_target_layer or self.cfg.batch_norm_target_layer: + target_layer_results = [ + tl.transpose(1, 2) for tl in target_layer_results # BTC -> BCT + ] + permuted = True + if self.cfg.batch_norm_target_layer: + target_layer_results = [ + F.batch_norm( + tl.float(), running_mean=None, running_var=None, training=True + ) + for tl in target_layer_results + ] + if self.cfg.instance_norm_target_layer: + target_layer_results = [ + F.instance_norm(tl.float()) for tl in target_layer_results + ] + if permuted: + target_layer_results = [ + tl.transpose(1, 2) for tl in target_layer_results # BCT -> BTC + ] + if self.cfg.layer_norm_target_layer: + target_layer_results = [ + F.layer_norm(tl.float(), tl.shape[-1:]) + for tl in target_layer_results + ] + + y = target_layer_results[0].float() + for tl in target_layer_results[1:]: + y.add_(tl.float()) + y = y.div_(len(target_layer_results)) + + if self.cfg.layer_norm_targets: + y = F.layer_norm(y, y.shape[-1:]) + + if self.cfg.instance_norm_targets: + y = F.instance_norm(y.transpose(1, 2)).transpose(1, 2) + + return y + + @staticmethod + def compute_var(y): + y = y.view(-1, y.size(-1)) + if dist.is_initialized(): + zc = torch.tensor(y.size(0)).cuda() + zs = y.sum(dim=0) + zss = (y**2).sum(dim=0) + + dist.all_reduce(zc) + dist.all_reduce(zs) + dist.all_reduce(zss) + + var = zss / (zc - 1) - (zs**2) / (zc * (zc - 1)) + return torch.sqrt(var + 1e-6).mean() + else: + return torch.sqrt(y.var(dim=0) + 1e-6).mean() + + def extract_features( + self, source, mode=None, padding_mask=None, mask=False, remove_extra_tokens=True + ): + res = self.forward( + source, + mode=mode, + padding_mask=padding_mask, + mask=mask, + features_only=True, + remove_extra_tokens=remove_extra_tokens, + ) + return res + + def remove_pretraining_modules(self, modality=None, keep_decoder=False): + self.ema = None + self.cfg.clone_batch = 1 + self.recon_proj = None + + if not keep_decoder: + self.shared_decoder = None + + modality = modality.lower() if modality is not None else None + for k in list(self.modality_encoders.keys()): + if modality is not None and k.lower() != modality: + del self.modality_encoders[k] + else: + self.modality_encoders[k].remove_pretraining_modules( + keep_decoder=keep_decoder + ) + if not keep_decoder: + self.modality_encoders[k].decoder = None diff --git a/examples/data2vec/models/data2vec_image_classification.py b/examples/data2vec/models/data2vec_image_classification.py new file mode 100644 index 0000000000..851c9ce455 --- /dev/null +++ b/examples/data2vec/models/data2vec_image_classification.py @@ -0,0 +1,143 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# The code in this file is adapted from the BeiT implementation which can be found here: +# https://github.com/microsoft/unilm/tree/master/beit + +import logging + +from dataclasses import dataclass +from typing import Any + +from omegaconf import II, MISSING + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from fairseq import checkpoint_utils, tasks + +from fairseq.dataclass import FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model + + +logger = logging.getLogger(__name__) + + +@dataclass +class Data2VecImageClassificationConfig(FairseqDataclass): + model_path: str = MISSING + no_pretrained_weights: bool = False + num_classes: int = 1000 + mixup: float = 0.8 + cutmix: float = 1.0 + label_smoothing: float = 0.1 + + pretrained_model_args: Any = None + data: str = II("task.data") + + +@register_model( + "data2vec_image_classification", dataclass=Data2VecImageClassificationConfig +) +class Data2VecImageClassificationModel(BaseFairseqModel): + def __init__(self, cfg: Data2VecImageClassificationConfig): + super().__init__() + self.cfg = cfg + + if cfg.pretrained_model_args is None: + state = checkpoint_utils.load_checkpoint_to_cpu(cfg.model_path, {}) + pretrained_args = state.get("cfg", None) + pretrained_args.criterion = None + pretrained_args.lr_scheduler = None + cfg.pretrained_model_args = pretrained_args + + logger.info(pretrained_args) + else: + state = None + pretrained_args = cfg.pretrained_model_args + + pretrained_args.task.data = cfg.data + task = tasks.setup_task(pretrained_args.task) + model = task.build_model(pretrained_args.model, from_checkpoint=True) + + model.remove_pretraining_modules() + + self.model = model + + if state is not None and not cfg.no_pretrained_weights: + self.load_model_weights(state, model, cfg) + + self.fc_norm = nn.LayerNorm(pretrained_args.model.embed_dim) + self.head = nn.Linear(pretrained_args.model.embed_dim, cfg.num_classes) + + self.head.weight.data.mul_(1e-3) + self.head.bias.data.mul_(1e-3) + + self.mixup_fn = None + + if cfg.mixup > 0 or cfg.cutmix > 0: + from timm.data import Mixup + + self.mixup_fn = Mixup( + mixup_alpha=cfg.mixup, + cutmix_alpha=cfg.cutmix, + cutmix_minmax=None, + prob=1.0, + switch_prob=0.5, + mode="batch", + label_smoothing=cfg.label_smoothing, + num_classes=cfg.num_classes, + ) + + def load_model_weights(self, state, model, cfg): + if "_ema" in state["model"]: + del state["model"]["_ema"] + model.load_state_dict(state["model"], strict=True) + + @classmethod + def build_model(cls, cfg: Data2VecImageClassificationConfig, task=None): + """Build a new model instance.""" + + return cls(cfg) + + def forward( + self, + img, + label=None, + ): + if self.training and self.mixup_fn is not None and label is not None: + img, label = self.mixup_fn(img, label) + + x = self.model(img, mask=False) + x = x[:, 1:] + x = self.fc_norm(x.mean(1)) + x = self.head(x) + + if label is None: + return x + + if self.training and self.mixup_fn is not None: + loss = -label * F.log_softmax(x.float(), dim=-1) + else: + loss = F.cross_entropy( + x.float(), + label, + label_smoothing=self.cfg.label_smoothing if self.training else 0, + reduction="none", + ) + + result = { + "losses": {"regression": loss}, + "sample_size": img.size(0), + } + + if not self.training: + with torch.no_grad(): + pred = x.argmax(-1) + correct = (pred == label).sum() + result["correct"] = correct + + return result diff --git a/examples/data2vec/models/data2vec_text_classification.py b/examples/data2vec/models/data2vec_text_classification.py new file mode 100644 index 0000000000..e787b916dc --- /dev/null +++ b/examples/data2vec/models/data2vec_text_classification.py @@ -0,0 +1,141 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# The code in this file is adapted from the BeiT implementation which can be found here: +# https://github.com/microsoft/unilm/tree/master/beit + +import logging + +from dataclasses import dataclass +from typing import Any + +from omegaconf import II, MISSING + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from fairseq import checkpoint_utils, tasks + +from fairseq.dataclass import FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model +from fairseq.models.roberta.model import RobertaClassificationHead + +from examples.data2vec.data.modality import Modality + + +logger = logging.getLogger(__name__) + + +@dataclass +class Data2VecTextClassificationConfig(FairseqDataclass): + pooler_dropout: float = 0.0 + pooler_activation_fn: str = "tanh" + quant_noise_pq: int = 0 + quant_noise_pq_block_size: int = 8 + spectral_norm_classification_head: bool = False + + model_path: str = MISSING + no_pretrained_weights: bool = False + + pretrained_model_args: Any = None + + +@register_model( + "data2vec_text_classification", dataclass=Data2VecTextClassificationConfig +) +class Data2VecTextClassificationModel(BaseFairseqModel): + def __init__(self, cfg: Data2VecTextClassificationConfig): + super().__init__() + self.cfg = cfg + + if cfg.pretrained_model_args is None: + state = checkpoint_utils.load_checkpoint_to_cpu(cfg.model_path, {}) + pretrained_args = state.get("cfg", None) + pretrained_args.criterion = None + pretrained_args.lr_scheduler = None + cfg.pretrained_model_args = pretrained_args + + logger.info(pretrained_args) + else: + state = None + pretrained_args = cfg.pretrained_model_args + + task = tasks.setup_task(pretrained_args.task) + model = task.build_model(pretrained_args.model, from_checkpoint=True) + + model.remove_pretraining_modules() + + self.model = model + + if state is not None and not cfg.no_pretrained_weights: + self.load_model_weights(state, model, cfg) + + self.classification_heads = nn.ModuleDict() + + + def load_model_weights(self, state, model, cfg): + for k in list(state["model"].keys()): + if ( + k.startswith("shared_decoder") or + k.startswith("_ema") or + "decoder" in k + ): + logger.info(f"Deleting {k} from checkpoint") + del state["model"][k] + model.load_state_dict(state["model"], strict=True) + + @classmethod + def build_model(cls, cfg: Data2VecTextClassificationConfig, task=None): + """Build a new model instance.""" + + return cls(cfg) + + def register_classification_head( + self, name, num_classes=None, inner_dim=None, **kwargs + ): + """Register a classification head.""" + if name in self.classification_heads: + prev_num_classes = self.classification_heads[name].out_proj.out_features + prev_inner_dim = self.classification_heads[name].dense.out_features + if num_classes != prev_num_classes or inner_dim != prev_inner_dim: + logger.warning( + 're-registering head "{}" with num_classes {} (prev: {}) ' + "and inner_dim {} (prev: {})".format( + name, num_classes, prev_num_classes, inner_dim, prev_inner_dim + ) + ) + embed_dim = self.cfg.pretrained_model_args.model.embed_dim + self.classification_heads[name] = RobertaClassificationHead( + input_dim=embed_dim, + inner_dim=inner_dim or embed_dim, + num_classes=num_classes, + activation_fn=self.cfg.pooler_activation_fn, + pooler_dropout=self.cfg.pooler_dropout, + q_noise=self.cfg.quant_noise_pq, + qn_block_size=self.cfg.quant_noise_pq_block_size, + do_spectral_norm=self.cfg.spectral_norm_classification_head, + ) + + def forward( + self, + source, + id, + padding_mask, + features_only=True, + remove_extra_tokens=True, + classification_head_name=None, + ): + encoder_out = self.model( + source, + id=id, + mode=Modality.TEXT, + padding_mask=padding_mask, + mask=False, + features_only=features_only, + remove_extra_tokens=remove_extra_tokens + ) + logits = self.classification_heads[classification_head_name](encoder_out["x"]) + return logits, encoder_out diff --git a/examples/data2vec/models/data2vec_vision.py b/examples/data2vec/models/data2vec_vision.py new file mode 100644 index 0000000000..2f89894429 --- /dev/null +++ b/examples/data2vec/models/data2vec_vision.py @@ -0,0 +1,727 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# The code in this file is adapted from the BeiT implementation which can be found here: +# https://github.com/microsoft/unilm/tree/master/beit + +import logging +import math +import numpy as np +import random + +from dataclasses import dataclass, field +from typing import Optional + +from omegaconf import II + +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.distributed as dist + +from fairseq.modules import EMAModule, EMAModuleConfig +from fairseq.dataclass import FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model + + +logger = logging.getLogger(__name__) + + +@dataclass +class Data2VecVisionConfig(FairseqDataclass): + layer_scale_init_value: float = field( + default=1e-4, metadata={"help": "rescale layer outputs, 0 to disable"} + ) + num_mask_patches: int = field( + default=75, + metadata={"help": "number of the visual tokens/patches need be masked"}, + ) + min_mask_patches_per_block: int = 16 + max_mask_patches_per_block: int = 196 + image_size: int = 224 + patch_size: int = 16 + in_channels: int = 3 + + shared_rel_pos_bias: bool = True + + drop_path: float = 0.1 + attention_dropout: float = 0.0 + + depth: int = 12 + embed_dim: int = 768 + num_heads: int = 12 + mlp_ratio: int = 4 + + loss_beta: float = field( + default=0, metadata={"help": "beta for smooth l1 loss. 0 means use l2 loss"} + ) + loss_scale: Optional[float] = field( + default=None, + metadata={ + "help": "scale the reconstruction loss by this constant. if None then scales by 1/sqrt(dim)" + }, + ) + average_top_k_layers: int = field( + default=8, metadata={"help": "how many layers to average"} + ) + + end_of_block_targets: bool = True + layer_norm_target_layer: bool = False + instance_norm_target_layer: bool = False + batch_norm_target_layer: bool = False + instance_norm_targets: bool = False + layer_norm_targets: bool = False + + ema_decay: float = field(default=0.999, metadata={"help": "initial ema decay rate"}) + ema_end_decay: float = field( + default=0.9999, metadata={"help": "final ema decay rate"} + ) + + # when to finish annealing ema decay rate + ema_anneal_end_step: int = II("optimization.max_update") + + ema_transformer_only: bool = field( + default=True, + metadata={"help": "whether to momentum update only the transformer layers"}, + ) + + +def get_annealed_rate(start, end, curr_step, total_steps): + r = end - start + pct_remaining = 1 - curr_step / total_steps + return end - r * pct_remaining + + +@register_model("data2vec_vision", dataclass=Data2VecVisionConfig) +class Data2VecVisionModel(BaseFairseqModel): + def __init__(self, cfg: Data2VecVisionConfig): + super().__init__() + self.cfg = cfg + + self.ema = None + + self.average_top_k_layers = cfg.average_top_k_layers + self.loss_beta = cfg.loss_beta + self.loss_scale = ( + cfg.loss_scale + if cfg.loss_scale is not None + else 1 / math.sqrt(cfg.embed_dim) + ) + + self.patch_embed = PatchEmbed( + img_size=cfg.image_size, + patch_size=cfg.patch_size, + in_chans=cfg.in_channels, + embed_dim=cfg.embed_dim, + ) + + patch_size = self.patch_embed.patch_size + self.window_size = ( + cfg.image_size // patch_size[0], + cfg.image_size // patch_size[1], + ) + + self.cls_emb = nn.Parameter(torch.FloatTensor(1, 1, cfg.embed_dim)) + self.mask_emb = nn.Parameter(torch.FloatTensor(1, 1, cfg.embed_dim)) + + nn.init.trunc_normal_(self.cls_emb, 0.02) + nn.init.trunc_normal_(self.mask_emb, 0.02) + + self.encoder = TransformerEncoder(cfg, self.patch_embed.patch_shape) + + self.final_proj = nn.Linear(cfg.embed_dim, cfg.embed_dim) + self.num_updates = 0 + + def make_ema_teacher(self): + ema_config = EMAModuleConfig( + ema_decay=self.cfg.ema_decay, + ema_fp32=True, + ) + self.ema = EMAModule( + self.encoder if self.cfg.ema_transformer_only else self, + ema_config, + ) + + def set_num_updates(self, num_updates): + super().set_num_updates(num_updates) + + if self.ema is None and self.final_proj is not None: + logger.info(f"making ema teacher") + self.make_ema_teacher() + elif self.training and self.ema is not None: + if self.cfg.ema_decay != self.cfg.ema_end_decay: + if num_updates >= self.cfg.ema_anneal_end_step: + decay = self.cfg.ema_end_decay + else: + decay = get_annealed_rate( + self.cfg.ema_decay, + self.cfg.ema_end_decay, + num_updates, + self.cfg.ema_anneal_end_step, + ) + self.ema.set_decay(decay) + if self.ema.get_decay() < 1: + self.ema.step(self.encoder if self.cfg.ema_transformer_only else self) + + self.num_updates = num_updates + + def state_dict(self, destination=None, prefix="", keep_vars=False): + state = super().state_dict(destination, prefix, keep_vars) + + if self.ema is not None: + state[prefix + "_ema"] = self.ema.fp32_params + + return state + + def _load_from_state_dict(self, state_dict, prefix, *args, **kwargs): + if self.ema is not None: + k = prefix + "_ema" + assert k in state_dict + self.ema.restore(state_dict[k], True) + del state_dict[k] + return super()._load_from_state_dict(state_dict, prefix, *args, **kwargs) + + @classmethod + def build_model(cls, cfg: Data2VecVisionConfig, task=None): + """Build a new model instance.""" + + return cls(cfg) + + def make_mask(self, bsz, num_masks, min_masks, max_masks): + height, width = self.window_size + + masks = np.zeros(shape=(bsz, height, width), dtype=np.int) + + for i in range(bsz): + mask = masks[i] + mask_count = 0 + + min_aspect = 0.3 + max_aspect = 1 / min_aspect + log_aspect_ratio = (math.log(min_aspect), math.log(max_aspect)) + + def _mask(mask, max_mask_patches): + delta = 0 + for attempt in range(10): + target_area = random.uniform(min_masks, max_mask_patches) + aspect_ratio = math.exp(random.uniform(*log_aspect_ratio)) + h = int(round(math.sqrt(target_area * aspect_ratio))) + w = int(round(math.sqrt(target_area / aspect_ratio))) + if w < width and h < height: + top = random.randint(0, height - h) + left = random.randint(0, width - w) + + num_masked = mask[top : top + h, left : left + w].sum() + # Overlap + if 0 < h * w - num_masked <= max_mask_patches: + for i in range(top, top + h): + for j in range(left, left + w): + if mask[i, j] == 0: + mask[i, j] = 1 + delta += 1 + + if delta > 0: + break + return delta + + while mask_count < num_masks: + max_mask_patches = min(num_masks - mask_count, max_masks) + + delta = _mask(mask, max_mask_patches) + if delta == 0: + break + else: + mask_count += delta + + return torch.from_numpy(masks) + + def forward( + self, + img, + mask: bool = True, + layer_results: bool = False, + ): + x = self.patch_embed(img) + batch_size, seq_len, _ = x.size() + + if mask: + mask_indices = self.make_mask( + img.size(0), + self.cfg.num_mask_patches, + self.cfg.min_mask_patches_per_block, + self.cfg.max_mask_patches_per_block, + ) + bool_mask = mask_indices.view(mask_indices.size(0), -1).bool() + else: + mask_indices = bool_mask = None + + cls_tokens = self.cls_emb.expand(batch_size, -1, -1) + x = torch.cat((cls_tokens, x), dim=1) + + if self.ema is not None: + with torch.no_grad(): + self.ema.model.eval() + + if self.cfg.ema_transformer_only: + y = self.ema.model( + x, + layer_results="end" if self.cfg.end_of_block_targets else "fc", + ) + else: + y = self.ema.model( + img, + mask=False, + layer_results=True, + ) + + y = y[-self.cfg.average_top_k_layers :] + + permuted = False + if self.cfg.instance_norm_target_layer or self.cfg.batch_norm_target_layer: + y = [tl.transpose(1, 2) for tl in y] # BTC -> BCT + permuted = True + + if self.cfg.batch_norm_target_layer: + y = [ + F.batch_norm( + tl.float(), running_mean=None, running_var=None, training=True + ) + for tl in y + ] + + if self.cfg.instance_norm_target_layer: + y = [F.instance_norm(tl.float()) for tl in y] + + if permuted: + y = [tl.transpose(1, 2) for tl in y] # BCT -> BTC + + if self.cfg.layer_norm_target_layer: + y = [F.layer_norm(tl.float(), tl.shape[-1:]) for tl in y] + + y = sum(y) / len(y) + + if self.cfg.layer_norm_targets: + y = F.layer_norm(y.float(), y.shape[-1:]) + + if self.cfg.instance_norm_targets: + y = F.instance_norm(y.float().transpose(1, 2)).transpose(1, 2) + + y = y[bool_mask].float() + + if mask_indices is not None: + mask_token = self.mask_emb.expand(batch_size, seq_len, -1) + w = mask_indices.view(mask_indices.size(0), -1, 1).type_as(mask_token) + x[:, 1:] = x[:, 1:] * (1 - w) + mask_token * w + + if layer_results: + enc_layer_results = "end" if self.cfg.end_of_block_targets else "fc" + else: + enc_layer_results = None + + x = self.encoder(x, layer_results=enc_layer_results) + if layer_results or mask_indices is None: + return x + + x = x[bool_mask].float() + + if self.loss_beta == 0: + loss = F.mse_loss(x, y, reduction="none").sum(dim=-1) + else: + loss = F.smooth_l1_loss(x, y, reduction="none", beta=self.loss_beta).sum( + dim=-1 + ) + + if self.loss_scale > 0: + loss = loss * self.loss_scale + + result = { + "losses": {"regression": loss.sum()}, + "sample_size": loss.numel(), + "target_var": self.compute_var(y), + "pred_var": self.compute_var(x), + "ema_decay": self.ema.get_decay() * 1000, + } + return result + + @staticmethod + def compute_var(y): + y = y.view(-1, y.size(-1)) + if dist.is_initialized(): + zc = torch.tensor(y.size(0)).cuda() + zs = y.sum(dim=0) + zss = (y ** 2).sum(dim=0) + + dist.all_reduce(zc) + dist.all_reduce(zs) + dist.all_reduce(zss) + + var = zss / (zc - 1) - (zs ** 2) / (zc * (zc - 1)) + return torch.sqrt(var + 1e-6).mean() + else: + return torch.sqrt(y.var(dim=0) + 1e-6).mean() + + def remove_pretraining_modules(self, last_layer=None): + self.final_proj = None + self.ema = None + self.encoder.norm = nn.Identity() + self.mask_emb = None + if last_layer is not None: + self.encoder.layers = nn.ModuleList( + l for i, l in enumerate(self.encoder.layers) if i <= last_layer + ) + + +class PatchEmbed(nn.Module): + """Image to Patch Embedding""" + + def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768): + super().__init__() + if isinstance(img_size, int): + img_size = img_size, img_size + if isinstance(patch_size, int): + patch_size = patch_size, patch_size + num_patches = (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0]) + self.patch_shape = (img_size[0] // patch_size[0], img_size[1] // patch_size[1]) + self.img_size = img_size + self.patch_size = patch_size + self.num_patches = num_patches + + self.conv = nn.Conv2d( + in_chans, embed_dim, kernel_size=patch_size, stride=patch_size + ) + + def forward(self, x): + # BCHW -> BTC + x = self.conv(x).flatten(2).transpose(1, 2) + return x + + +class Attention(nn.Module): + def __init__( + self, + dim, + num_heads=8, + qkv_bias=True, + attn_drop=0.0, + proj_drop=0.0, + window_size=None, + attn_head_dim=None, + ): + super().__init__() + self.num_heads = num_heads + head_dim = dim // num_heads + if attn_head_dim is not None: + head_dim = attn_head_dim + all_head_dim = head_dim * self.num_heads + self.scale = head_dim ** -0.5 + + self.qkv = nn.Linear(dim, all_head_dim * 3, bias=False) + if qkv_bias: + self.q_bias = nn.Parameter(torch.zeros(all_head_dim)) + self.v_bias = nn.Parameter(torch.zeros(all_head_dim)) + else: + self.q_bias = None + self.v_bias = None + + if window_size: + self.window_size = window_size + self.num_relative_distance = (2 * window_size[0] - 1) * ( + 2 * window_size[1] - 1 + ) + 3 + self.relative_position_bias_table = nn.Parameter( + torch.zeros(self.num_relative_distance, num_heads) + ) # 2*Wh-1 * 2*Ww-1, nH + # cls to token & token 2 cls & cls to cls + + # get pair-wise relative position index for each token inside the window + coords_h = torch.arange(window_size[0]) + coords_w = torch.arange(window_size[1]) + coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww + coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww + relative_coords = ( + coords_flatten[:, :, None] - coords_flatten[:, None, :] + ) # 2, Wh*Ww, Wh*Ww + relative_coords = relative_coords.permute( + 1, 2, 0 + ).contiguous() # Wh*Ww, Wh*Ww, 2 + relative_coords[:, :, 0] += window_size[0] - 1 # shift to start from 0 + relative_coords[:, :, 1] += window_size[1] - 1 + relative_coords[:, :, 0] *= 2 * window_size[1] - 1 + relative_position_index = torch.zeros( + size=(window_size[0] * window_size[1] + 1,) * 2, + dtype=relative_coords.dtype, + ) + relative_position_index[1:, 1:] = relative_coords.sum(-1) # Wh*Ww, Wh*Ww + relative_position_index[0, 0:] = self.num_relative_distance - 3 + relative_position_index[0:, 0] = self.num_relative_distance - 2 + relative_position_index[0, 0] = self.num_relative_distance - 1 + + self.register_buffer("relative_position_index", relative_position_index) + else: + self.window_size = None + self.relative_position_bias_table = None + self.relative_position_index = None + + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(all_head_dim, dim) + self.proj_drop = nn.Dropout(proj_drop) + + def forward(self, x, rel_pos_bias=None): + B, N, C = x.shape + qkv_bias = None + if self.q_bias is not None: + qkv_bias = torch.cat( + ( + self.q_bias, + torch.zeros_like(self.v_bias, requires_grad=False), + self.v_bias, + ) + ) + # qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) + qkv = F.linear(input=x, weight=self.qkv.weight, bias=qkv_bias) + qkv = qkv.reshape(B, N, 3, self.num_heads, -1).permute(2, 0, 3, 1, 4) + q, k, v = ( + qkv[0], + qkv[1], + qkv[2], + ) # make torchscript happy (cannot use tensor as tuple) + + q = q * self.scale + attn = q @ k.transpose(-2, -1) + + if self.relative_position_bias_table is not None: + assert 1==2 + relative_position_bias = self.relative_position_bias_table[ + self.relative_position_index.view(-1) + ].view( + self.window_size[0] * self.window_size[1] + 1, + self.window_size[0] * self.window_size[1] + 1, + -1, + ) # Wh*Ww,Wh*Ww,nH + relative_position_bias = relative_position_bias.permute( + 2, 0, 1 + ).contiguous() # nH, Wh*Ww, Wh*Ww + attn = attn + relative_position_bias.unsqueeze(0) + print("attn.size() :", attn.size()) + print("rel_pos_bias.size() :", rel_pos_bias.size()) + if rel_pos_bias is not None: + attn = attn + rel_pos_bias + attn = attn.softmax(dim=-1) + attn = self.attn_drop(attn) + + x = (attn @ v).transpose(1, 2).reshape(B, N, -1) + x = self.proj(x) + x = self.proj_drop(x) + return x + + +class RelativePositionBias(nn.Module): + def __init__(self, window_size, num_heads): + super().__init__() + self.window_size = window_size + self.num_relative_distance = (2 * window_size[0] - 1) * ( + 2 * window_size[1] - 1 + ) + 3 + self.relative_position_bias_table = nn.Parameter( + torch.zeros(self.num_relative_distance, num_heads) + ) + + # get pair-wise relative position index for each token inside the window + coords_h = torch.arange(window_size[0]) + coords_w = torch.arange(window_size[1]) + coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww + coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww + relative_coords = ( + coords_flatten[:, :, None] - coords_flatten[:, None, :] + ) # 2, Wh*Ww, Wh*Ww + relative_coords = relative_coords.permute( + 1, 2, 0 + ).contiguous() # Wh*Ww, Wh*Ww, 2 + relative_coords[:, :, 0] += window_size[0] - 1 # shift to start from 0 + relative_coords[:, :, 1] += window_size[1] - 1 + relative_coords[:, :, 0] *= 2 * window_size[1] - 1 + relative_position_index = torch.zeros( + size=(window_size[0] * window_size[1] + 1,) * 2, dtype=relative_coords.dtype + ) + relative_position_index[1:, 1:] = relative_coords.sum(-1) # Wh*Ww, Wh*Ww + relative_position_index[0, 0:] = self.num_relative_distance - 3 + relative_position_index[0:, 0] = self.num_relative_distance - 2 + relative_position_index[0, 0] = self.num_relative_distance - 1 + + self.register_buffer("relative_position_index", relative_position_index) + + def forward(self): + relative_position_bias = self.relative_position_bias_table[ + self.relative_position_index.view(-1) + ].view( + self.window_size[0] * self.window_size[1] + 1, + self.window_size[0] * self.window_size[1] + 1, + -1, + ) # Wh*Ww,Wh*Ww,nH + print("self.window_size :", self.window_size) + print("self.num_relative_distance :", self.num_relative_distance) + print("self.relative_position_index :", self.relative_position_index.size(), self.relative_position_index) + print("relative_position_bias.size(), relative_position_bias :",relative_position_bias.size(), relative_position_bias) + print("self.relative_position_bias_table.size(), self.relative_position_bias_table :",self.relative_position_bias_table.size(), self.relative_position_bias_table) + return relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww + + +class DropPath(nn.Module): + """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).""" + + def __init__(self, drop_prob=None): + super(DropPath, self).__init__() + self.drop_prob = drop_prob + + def forward(self, x): + if self.drop_prob == 0.0 or not self.training: + return x + keep_prob = 1 - self.drop_prob + shape = (x.shape[0],) + (1,) * ( + x.ndim - 1 + ) # work with diff dim tensors, not just 2D ConvNets + random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device) + random_tensor.floor_() + output = x.div(keep_prob) * random_tensor + return output + + def extra_repr(self) -> str: + return "p={}".format(self.drop_prob) + + +class Block(nn.Module): + def __init__( + self, + dim, + num_heads, + mlp_ratio=4.0, + drop=0.0, + attn_drop=0.0, + drop_path=0.0, + init_values=None, + window_size=None, + ): + super().__init__() + + self.norm1 = nn.LayerNorm(dim) + self.attn = Attention( + dim, + num_heads=num_heads, + attn_drop=attn_drop, + proj_drop=drop, + window_size=window_size, + ) + + self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + self.norm2 = nn.LayerNorm(dim) + mlp_hidden_dim = int(dim * mlp_ratio) + + self.mlp = nn.Sequential( + nn.Linear(dim, mlp_hidden_dim), + nn.GELU(), + nn.Linear(mlp_hidden_dim, dim), + nn.Dropout(drop), + ) + + if init_values > 0: + self.gamma_1 = nn.Parameter( + init_values * torch.ones((dim)), requires_grad=True + ) + self.gamma_2 = nn.Parameter( + init_values * torch.ones((dim)), requires_grad=True + ) + else: + self.gamma_1, self.gamma_2 = None, None + + def forward(self, x, rel_pos_bias=None): + print("inside block :", x.size()) + if self.gamma_1 is None: + x = x + self.drop_path(self.attn(self.norm1(x), rel_pos_bias=rel_pos_bias)) + fc_feature = self.drop_path(self.mlp(self.norm2(x))) + x = x + fc_feature + else: + x = x + self.drop_path( + self.gamma_1 * self.attn(self.norm1(x), rel_pos_bias=rel_pos_bias) + ) + fc_feature = self.drop_path(self.gamma_2 * self.mlp(self.norm2(x))) + x = x + fc_feature + return x, fc_feature + + +class TransformerEncoder(nn.Module): + def __init__(self, cfg: Data2VecVisionConfig, patch_shape): + super().__init__() + + self.rel_pos_bias = None + if cfg.shared_rel_pos_bias: + self.rel_pos_bias = RelativePositionBias( + window_size=patch_shape, num_heads=cfg.num_heads + ) + + dpr = [ + x.item() for x in torch.linspace(0, cfg.drop_path, cfg.depth) + ] # stochastic depth decay rule + + print("TransformerEncoder > patch_shape :", patch_shape) + self.blocks = nn.ModuleList( + Block( + dim=cfg.embed_dim, + num_heads=cfg.num_heads, + attn_drop=cfg.attention_dropout, + drop_path=dpr[i], + init_values=cfg.layer_scale_init_value, + window_size=patch_shape if not cfg.shared_rel_pos_bias else None, + ) + for i in range(cfg.depth) + ) + + self.norm = nn.LayerNorm(cfg.embed_dim) + + self.apply(self.init_weights) + self.fix_init_weight() + + def init_weights(self, m): + std = 0.02 + if isinstance(m, nn.Linear): + nn.init.trunc_normal_(m.weight, std=std) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm): + nn.init.constant_(m.bias, 0) + nn.init.constant_(m.weight, 1.0) + elif isinstance(m, nn.Conv2d): + nn.init.trunc_normal_(m.weight, std=std) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def fix_init_weight(self): + def rescale(param, layer_id): + param.div_(math.sqrt(2.0 * layer_id)) + + for layer_id, layer in enumerate(self.blocks): + rescale(layer.attn.proj.weight.data, layer_id + 1) + rescale(layer.mlp[2].weight.data, layer_id + 1) + + def extract_features(self, x, layer_results): + + rel_pos_bias = self.rel_pos_bias() if self.rel_pos_bias is not None else None + + z = [] + for i, blk in enumerate(self.blocks): + x, fc_feature = blk(x, rel_pos_bias=rel_pos_bias) + if layer_results == "end": + z.append(x) + elif layer_results == "fc": + z.append(fc_feature) + + return z if layer_results else self.norm(x) + + def forward(self, x, layer_results=None): + x = self.extract_features(x, layer_results=layer_results) + if layer_results: + return [z[:, 1:] for z in x] + + x = x[:, 1:] + return x diff --git a/examples/data2vec/models/mae.py b/examples/data2vec/models/mae.py new file mode 100644 index 0000000000..5101e070e1 --- /dev/null +++ b/examples/data2vec/models/mae.py @@ -0,0 +1,825 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# The code in this file is adapted from the BeiT implementation which can be found here: +# https://github.com/microsoft/unilm/tree/master/beit + +import logging +from dataclasses import dataclass +from functools import partial + +from timm.models.vision_transformer import PatchEmbed, Block + +import torch +import torch.nn as nn + +import numpy as np + +from fairseq.dataclass import FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model +from fairseq.models.wav2vec.wav2vec2 import TransformerSentenceEncoderLayer + +from apex.normalization import FusedLayerNorm +import torch.nn.functional as F + + +logger = logging.getLogger(__name__) + + +@dataclass +class MaeConfig(FairseqDataclass): + input_size: int = 224 + in_chans: int = 3 + patch_size: int = 16 + embed_dim: int = 768 + depth: int = 12 + num_heads: int = 12 + decoder_embed_dim: int = 512 + decoder_depth: int = 8 + decoder_num_heads: int = 16 + mlp_ratio: int = 4 + norm_eps: float = 1e-6 + + drop_path_rate: float = 0.0 + + mask_ratio: float = 0.75 + norm_pix_loss: bool = True + + w2v_block: bool = False + alt_block: bool = False + alt_block2: bool = False + alt_attention: bool = False + block_dropout: float = 0 + attention_dropout: float = 0 + activation_dropout: float = 0 + layer_norm_first: bool = False + + fused_ln: bool = True + end_of_block_targets: bool = True + + no_decoder_embed: bool = False + no_decoder_pos_embed: bool = False + mask_noise_std: float = 0 + + single_qkv: bool = False + use_rel_pos_bias: bool = False + no_cls: bool = False + + +def modify_relative_position_bias(orig_bias, bsz, mask): + if mask is None: + return orig_bias.unsqueeze(0).repeat( + bsz, 1, 1, 1 + ) # heads x seq_len x seq_len => bsz x heads x seq_len x seq_len + heads, max_seq_len, max_seq_len = orig_bias.shape # includes CLS token + mask_for_rel_pos_bias = torch.cat( + (torch.zeros(bsz, 1, dtype=mask.dtype, device=mask.device), mask), dim=1 + ).bool() # bsz x seqlen (add CLS token) + unmasked_for_rel_pos_bias = ~mask_for_rel_pos_bias + unmasked_for_rel_pos_bias = unmasked_for_rel_pos_bias.unsqueeze(1).repeat( + 1, heads, 1 + ) # bsz x seq_len => bsz x heads x seq_len + b_t_t_rel_pos_bias = orig_bias.unsqueeze(0).repeat( + bsz, 1, 1, 1 + ) # heads x seq_len x seq_len => bsz x heads x seq_len x seq_len + b_t_t_rel_pos_bias = b_t_t_rel_pos_bias.masked_select( + unmasked_for_rel_pos_bias.unsqueeze(-1) + ) + b_t_t_rel_pos_bias = b_t_t_rel_pos_bias.view(bsz, heads, -1, max_seq_len) + new_len = b_t_t_rel_pos_bias.size(-2) + b_t_t_rel_pos_bias = b_t_t_rel_pos_bias.masked_select( + unmasked_for_rel_pos_bias.unsqueeze(-2) + ) + b_t_t_rel_pos_bias = b_t_t_rel_pos_bias.view(bsz, heads, new_len, new_len) + return b_t_t_rel_pos_bias + + +class AltBlock(nn.Module): + def __init__( + self, + dim, + num_heads, + mlp_ratio=4.0, + qkv_bias=False, + qk_scale=None, + drop=0.0, + attn_drop=0.0, + drop_path=0.0, + act_layer=nn.GELU, + norm_layer=nn.LayerNorm, + layer_norm_first=True, + ffn_targets=False, + use_rel_pos_bias=False, + window_size=None, + alt_attention=False, + ): + super().__init__() + + self.layer_norm_first = layer_norm_first + self.ffn_targets = ffn_targets + + from timm.models.vision_transformer import Attention, DropPath, Mlp + + self.norm1 = norm_layer(dim) + self.use_rel_pos_bias = use_rel_pos_bias + if use_rel_pos_bias: + self.attn = AltAttention( + dim, + num_heads=num_heads, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + attn_drop=attn_drop, + proj_drop=drop, + window_size=window_size, + ) + else: + if alt_attention: + from .multi.modules import AltAttention as AltAttention2 + self.attn = AltAttention2( + dim, + num_heads=num_heads, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + attn_drop=attn_drop, + proj_drop=drop, + ) + else: + self.attn = Attention( + dim, + num_heads=num_heads, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + attn_drop=attn_drop, + proj_drop=drop, + ) + # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here + self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + self.norm2 = norm_layer(dim) + mlp_hidden_dim = int(dim * mlp_ratio) + self.mlp = Mlp( + in_features=dim, + hidden_features=mlp_hidden_dim, + act_layer=act_layer, + drop=drop, + ) + + def forward(self, x, rel_pos_bias=None, pos_mask=None): + if self.layer_norm_first: + if self.use_rel_pos_bias: + x = x + self.drop_path( + self.attn( + self.norm1(x), rel_pos_bias=rel_pos_bias, pos_mask=pos_mask + ) + ) + else: + x = x + self.drop_path(self.attn(self.norm1(x))) + t = self.mlp(self.norm2(x)) + x = x + self.drop_path(t) + if not self.ffn_targets: + t = x + return x, t + else: + if self.use_rel_pos_bias: + x = x + self.drop_path( + self.attn(x, rel_pos_bias=rel_pos_bias, pos_mask=pos_mask) + ) + else: + x = x + self.drop_path(self.attn(x)) + r = x = self.norm1(x) + x = self.mlp(x) + t = x + x = self.norm2(r + self.drop_path(x)) + if not self.ffn_targets: + t = x + return x, t + + +class AltAttention(nn.Module): + def __init__( + self, + dim, + num_heads=8, + qkv_bias=True, + qk_scale=None, + attn_drop=0.0, + proj_drop=0.0, + window_size=None, + attn_head_dim=None, + ): + super().__init__() + self.num_heads = num_heads + head_dim = dim // num_heads + if attn_head_dim is not None: + head_dim = attn_head_dim + all_head_dim = head_dim * self.num_heads + self.scale = qk_scale or head_dim ** -0.5 + + self.qkv = nn.Linear(dim, all_head_dim * 3, bias=False) + if qkv_bias: + self.q_bias = nn.Parameter(torch.zeros(all_head_dim)) + self.v_bias = nn.Parameter(torch.zeros(all_head_dim)) + else: + self.q_bias = None + self.v_bias = None + + if window_size: + self.window_size = window_size + self.num_relative_distance = (2 * window_size[0] - 1) * ( + 2 * window_size[1] - 1 + ) + 3 + self.relative_position_bias_table = nn.Parameter( + torch.zeros(self.num_relative_distance, num_heads) + ) # 2*Wh-1 * 2*Ww-1, nH + # cls to token & token 2 cls & cls to cls + + # get pair-wise relative position index for each token inside the window + coords_h = torch.arange(window_size[0]) + coords_w = torch.arange(window_size[1]) + coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww + coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww + relative_coords = ( + coords_flatten[:, :, None] - coords_flatten[:, None, :] + ) # 2, Wh*Ww, Wh*Ww + relative_coords = relative_coords.permute( + 1, 2, 0 + ).contiguous() # Wh*Ww, Wh*Ww, 2 + relative_coords[:, :, 0] += window_size[0] - 1 # shift to start from 0 + relative_coords[:, :, 1] += window_size[1] - 1 + relative_coords[:, :, 0] *= 2 * window_size[1] - 1 + relative_position_index = torch.zeros( + size=(window_size[0] * window_size[1] + 1,) * 2, + dtype=relative_coords.dtype, + ) + relative_position_index[1:, 1:] = relative_coords.sum(-1) # Wh*Ww, Wh*Ww + relative_position_index[0, 0:] = self.num_relative_distance - 3 + relative_position_index[0:, 0] = self.num_relative_distance - 2 + relative_position_index[0, 0] = self.num_relative_distance - 1 + + self.register_buffer("relative_position_index", relative_position_index) + else: + self.window_size = None + self.relative_position_bias_table = None + self.relative_position_index = None + + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(all_head_dim, dim) + self.proj_drop = nn.Dropout(proj_drop) + + def forward(self, x, rel_pos_bias=None, pos_mask=None): + B, N, C = x.shape + qkv_bias = None + if self.q_bias is not None: + qkv_bias = torch.cat( + ( + self.q_bias, + torch.zeros_like(self.v_bias, requires_grad=False), + self.v_bias, + ) + ) + # qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4) + qkv = F.linear(input=x, weight=self.qkv.weight, bias=qkv_bias) + qkv = qkv.reshape(B, N, 3, self.num_heads, -1).permute(2, 0, 3, 1, 4) + q, k, v = ( + qkv[0], + qkv[1], + qkv[2], + ) # make torchscript happy (cannot use tensor as tuple) + + q = q * self.scale + attn = q @ k.transpose(-2, -1) + + if self.relative_position_bias_table is not None: + relative_position_bias = self.relative_position_bias_table[ + self.relative_position_index.view(-1) + ].view( + self.window_size[0] * self.window_size[1] + 1, + self.window_size[0] * self.window_size[1] + 1, + -1, + ) # Wh*Ww,Wh*Ww,nH + relative_position_bias = relative_position_bias.permute( + 2, 0, 1 + ).contiguous() # nH, Wh*Ww, Wh*Ww + attn = attn + modify_relative_position_bias( + relative_position_bias, x.size(0), pos_mask + ) + + if rel_pos_bias is not None: + attn = attn + rel_pos_bias + + attn = attn.softmax(dim=-1) + attn = self.attn_drop(attn) + + x = (attn @ v).transpose(1, 2).reshape(B, N, -1) + x = self.proj(x) + x = self.proj_drop(x) + return x + + +class RelativePositionBias(nn.Module): + def __init__(self, window_size, num_heads): + super().__init__() + self.window_size = window_size + self.num_relative_distance = (2 * window_size[0] - 1) * ( + 2 * window_size[1] - 1 + ) + 3 + self.relative_position_bias_table = nn.Parameter( + torch.zeros(self.num_relative_distance, num_heads) + ) + + # get pair-wise relative position index for each token inside the window + coords_h = torch.arange(window_size[0]) + coords_w = torch.arange(window_size[1]) + coords = torch.stack(torch.meshgrid([coords_h, coords_w])) # 2, Wh, Ww + coords_flatten = torch.flatten(coords, 1) # 2, Wh*Ww + relative_coords = ( + coords_flatten[:, :, None] - coords_flatten[:, None, :] + ) # 2, Wh*Ww, Wh*Ww + relative_coords = relative_coords.permute( + 1, 2, 0 + ).contiguous() # Wh*Ww, Wh*Ww, 2 + relative_coords[:, :, 0] += window_size[0] - 1 # shift to start from 0 + relative_coords[:, :, 1] += window_size[1] - 1 + relative_coords[:, :, 0] *= 2 * window_size[1] - 1 + relative_position_index = torch.zeros( + size=(window_size[0] * window_size[1] + 1,) * 2, dtype=relative_coords.dtype + ) + relative_position_index[1:, 1:] = relative_coords.sum(-1) # Wh*Ww, Wh*Ww + relative_position_index[0, 0:] = self.num_relative_distance - 3 + relative_position_index[0:, 0] = self.num_relative_distance - 2 + relative_position_index[0, 0] = self.num_relative_distance - 1 + + self.register_buffer("relative_position_index", relative_position_index) + + def forward(self): + relative_position_bias = self.relative_position_bias_table[ + self.relative_position_index.view(-1) + ].view( + self.window_size[0] * self.window_size[1] + 1, + self.window_size[0] * self.window_size[1] + 1, + -1, + ) # Wh*Ww,Wh*Ww,nH + return relative_position_bias.permute(2, 0, 1).contiguous() # nH, Wh*Ww, Wh*Ww + + +def get_2d_sincos_pos_embed(embed_dim, grid_size, cls_token=False): + """ + grid_size: int of the grid height and width + return: + pos_embed: [grid_size*grid_size, embed_dim] or [1+grid_size*grid_size, embed_dim] (w/ or w/o cls_token) + """ + grid_h = np.arange(grid_size, dtype=np.float32) + grid_w = np.arange(grid_size, dtype=np.float32) + grid = np.meshgrid(grid_w, grid_h) # here w goes first + grid = np.stack(grid, axis=0) + + grid = grid.reshape([2, 1, grid_size, grid_size]) + pos_embed = get_2d_sincos_pos_embed_from_grid(embed_dim, grid) + if cls_token: + pos_embed = np.concatenate([np.zeros([1, embed_dim]), pos_embed], axis=0) + return pos_embed + + +def get_2d_sincos_pos_embed_from_grid(embed_dim, grid): + assert embed_dim % 2 == 0 + + # use half of dimensions to encode grid_h + emb_h = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[0]) # (H*W, D/2) + emb_w = get_1d_sincos_pos_embed_from_grid(embed_dim // 2, grid[1]) # (H*W, D/2) + + emb = np.concatenate([emb_h, emb_w], axis=1) # (H*W, D) + return emb + + +def get_1d_sincos_pos_embed_from_grid(embed_dim, pos): + """ + embed_dim: output dimension for each position + pos: a list of positions to be encoded: size (M,) + out: (M, D) + """ + assert embed_dim % 2 == 0 + omega = np.arange(embed_dim // 2, dtype=np.float) + omega /= embed_dim / 2.0 + omega = 1.0 / 10000 ** omega # (D/2,) + + pos = pos.reshape(-1) # (M,) + out = np.einsum("m,d->md", pos, omega) # (M, D/2), outer product + + emb_sin = np.sin(out) # (M, D/2) + emb_cos = np.cos(out) # (M, D/2) + + emb = np.concatenate([emb_sin, emb_cos], axis=1) # (M, D) + return emb + + +def interpolate_pos_embed(model, checkpoint_model): + if "pos_embed" in checkpoint_model: + pos_embed_checkpoint = checkpoint_model["pos_embed"] + embedding_size = pos_embed_checkpoint.shape[-1] + num_patches = model.patch_embed.num_patches + num_extra_tokens = model.pos_embed.shape[-2] - num_patches + # height (== width) for the checkpoint position embedding + orig_size = int((pos_embed_checkpoint.shape[-2] - num_extra_tokens) ** 0.5) + # height (== width) for the new position embedding + new_size = int(num_patches ** 0.5) + # class_token and dist_token are kept unchanged + if orig_size != new_size: + print( + "Position interpolate from %dx%d to %dx%d" + % (orig_size, orig_size, new_size, new_size) + ) + extra_tokens = pos_embed_checkpoint[:, :num_extra_tokens] + # only the position tokens are interpolated + pos_tokens = pos_embed_checkpoint[:, num_extra_tokens:] + pos_tokens = pos_tokens.reshape( + -1, orig_size, orig_size, embedding_size + ).permute(0, 3, 1, 2) + pos_tokens = torch.nn.functional.interpolate( + pos_tokens, + size=(new_size, new_size), + mode="bicubic", + align_corners=False, + ) + pos_tokens = pos_tokens.permute(0, 2, 3, 1).flatten(1, 2) + new_pos_embed = torch.cat((extra_tokens, pos_tokens), dim=1) + checkpoint_model["pos_embed"] = new_pos_embed + + +@register_model("mae", dataclass=MaeConfig) +class MaeModel(BaseFairseqModel): + def __init__(self, cfg: MaeConfig): + super().__init__() + self.cfg = cfg + + self.mask_ratio = cfg.mask_ratio + + # -------------------------------------------------------------------------- + # MAE encoder specifics + self.patch_embed = PatchEmbed( + cfg.input_size, cfg.patch_size, cfg.in_chans, cfg.embed_dim + ) + num_patches = self.patch_embed.num_patches + + self.cls_token = nn.Parameter(torch.zeros(1, 1, cfg.embed_dim)) if not cfg.no_cls else None + self.pos_embed = nn.Parameter( + torch.zeros(1, num_patches + int(not cfg.no_cls), cfg.embed_dim), requires_grad=False + ) # fixed sin-cos embedding + + norm_layer = partial(nn.LayerNorm, eps=cfg.norm_eps) + + dpr = [ + x.item() for x in torch.linspace(0, cfg.drop_path_rate, cfg.depth) + ] # stochastic depth decay rule + + def make_block(drop_path): + if cfg.w2v_block: + return TransformerSentenceEncoderLayer( + embedding_dim=cfg.embed_dim, + ffn_embedding_dim=cfg.embed_dim * cfg.mlp_ratio, + num_attention_heads=cfg.num_heads, + dropout=cfg.block_dropout, + attention_dropout=cfg.attention_dropout, + activation_dropout=cfg.activation_dropout, + activation_fn="gelu", + layer_norm_first=cfg.layer_norm_first, + drop_path=drop_path, + norm_eps=1e-6, + single_qkv=cfg.single_qkv, + fused_ln=cfg.fused_ln, + ) + elif cfg.alt_block: + window_size = ( + cfg.input_size // self.patch_embed.patch_size[0], + cfg.input_size // self.patch_embed.patch_size[1], + ) + return AltBlock( + cfg.embed_dim, + cfg.num_heads, + cfg.mlp_ratio, + qkv_bias=True, + qk_scale=None, + norm_layer=norm_layer, + drop_path=drop_path, + layer_norm_first=cfg.layer_norm_first, + ffn_targets=not cfg.end_of_block_targets, + use_rel_pos_bias=cfg.use_rel_pos_bias, + window_size=window_size + if (self.cfg.use_rel_pos_bias and not self.cfg.shared_rel_pos_bias) + else None, + alt_attention=cfg.alt_attention, + ) + elif cfg.alt_block2: + from .multi.modules import AltBlock as AltBlock2 + return AltBlock2( + cfg.embed_dim, + cfg.num_heads, + cfg.mlp_ratio, + qkv_bias=True, + qk_scale=None, + norm_layer=norm_layer, + drop_path=drop_path, + layer_norm_first=cfg.layer_norm_first, + ffn_targets=not cfg.end_of_block_targets, + ) + else: + return Block( + cfg.embed_dim, + cfg.num_heads, + cfg.mlp_ratio, + qkv_bias=True, + qk_scale=None, + norm_layer=norm_layer, + drop_path=drop_path, + ) + + self.blocks = nn.ModuleList([make_block(dpr[i]) for i in range(cfg.depth)]) + self.norm = norm_layer(cfg.embed_dim) + # -------------------------------------------------------------------------- + + # -------------------------------------------------------------------------- + # MAE decoder specifics + self.decoder_embed = ( + nn.Linear(cfg.embed_dim, cfg.decoder_embed_dim, bias=True) + if not cfg.no_decoder_embed + else None + ) + + self.mask_token = ( + nn.Parameter( + torch.zeros( + 1, + 1, + cfg.decoder_embed_dim + if not cfg.no_decoder_embed + else cfg.embed_dim, + ) + ) + if cfg.mask_noise_std <= 0 + else None + ) + + self.decoder_pos_embed = ( + nn.Parameter( + torch.zeros( + 1, + num_patches + 1, + cfg.decoder_embed_dim + if not cfg.no_decoder_embed + else cfg.embed_dim, + ), + requires_grad=False, + ) + if not cfg.no_decoder_pos_embed + else None + ) + + self.decoder_blocks = nn.ModuleList( + [ + Block( + cfg.decoder_embed_dim, + cfg.decoder_num_heads, + cfg.mlp_ratio, + qkv_bias=True, + qk_scale=None, + norm_layer=norm_layer, + ) + for _ in range(cfg.decoder_depth) + ] + ) + + self.decoder_norm = norm_layer(cfg.decoder_embed_dim) + self.decoder_pred = nn.Linear( + cfg.decoder_embed_dim, cfg.patch_size ** 2 * cfg.in_chans, bias=True + ) # decoder to patch + # -------------------------------------------------------------------------- + + self.norm_pix_loss = cfg.norm_pix_loss + + self.initialize_weights() + + for pn, p in self.named_parameters(): + if len(p.shape) == 1 or pn.endswith(".bias"): + p.param_group = "no_decay" + else: + p.param_group = "with_decay" + + def initialize_weights(self): + # initialization + # initialize (and freeze) pos_embed by sin-cos embedding + pos_embed = get_2d_sincos_pos_embed( + self.pos_embed.shape[-1], + int(self.patch_embed.num_patches ** 0.5), + cls_token=not self.cfg.no_cls, + ) + self.pos_embed.data.copy_(torch.from_numpy(pos_embed).float().unsqueeze(0)) + + if self.decoder_pos_embed is not None: + decoder_pos_embed = get_2d_sincos_pos_embed( + self.decoder_pos_embed.shape[-1], + int(self.patch_embed.num_patches ** 0.5), + cls_token=not self.cfg.no_cls, + ) + self.decoder_pos_embed.data.copy_( + torch.from_numpy(decoder_pos_embed).float().unsqueeze(0) + ) + + # initialize patch_embed like nn.Linear (instead of nn.Conv2d) + w = self.patch_embed.proj.weight.data + torch.nn.init.xavier_uniform_(w.view([w.shape[0], -1])) + + # timm's trunc_normal_(std=.02) is effectively normal_(std=0.02) as cutoff is too big (2.) + if self.cls_token is not None: + torch.nn.init.normal_(self.cls_token, std=0.02) + + if self.mask_token is not None: + torch.nn.init.normal_(self.mask_token, std=0.02) + + # initialize nn.Linear and nn.LayerNorm + self.apply(self._init_weights) + + def _init_weights(self, m): + if isinstance(m, nn.Linear): + # we use xavier_uniform following official JAX ViT: + torch.nn.init.xavier_uniform_(m.weight) + if isinstance(m, nn.Linear) and m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.LayerNorm) or isinstance(m, FusedLayerNorm): + nn.init.constant_(m.bias, 0) + nn.init.constant_(m.weight, 1.0) + + def patchify(self, imgs): + """ + imgs: (N, 3, H, W) + x: (N, L, patch_size**2 *3) + """ + p = self.patch_embed.patch_size[0] + assert imgs.shape[2] == imgs.shape[3] and imgs.shape[2] % p == 0 + + h = w = imgs.shape[2] // p + x = imgs.reshape(shape=(imgs.shape[0], 3, h, p, w, p)) + x = torch.einsum("nchpwq->nhwpqc", x) + x = x.reshape(shape=(imgs.shape[0], h * w, p ** 2 * 3)) + return x + + def unpatchify(self, x): + """ + x: (N, L, patch_size**2 *3) + imgs: (N, 3, H, W) + """ + p = self.patch_embed.patch_size[0] + h = w = int(x.shape[1] ** 0.5) + assert h * w == x.shape[1] + + x = x.reshape(shape=(x.shape[0], h, w, p, p, 3)) + x = torch.einsum("nhwpqc->nchpwq", x) + imgs = x.reshape(shape=(x.shape[0], 3, h * p, h * p)) + return imgs + + def random_masking(self, x, mask_ratio): + """ + Perform per-sample random masking by per-sample shuffling. + Per-sample shuffling is done by argsort random noise. + x: [N, L, D], sequence + """ + N, L, D = x.shape # batch, length, dim + len_keep = int(L * (1 - mask_ratio)) + + noise = torch.rand(N, L, device=x.device) # noise in [0, 1] + + # sort noise for each sample + ids_shuffle = torch.argsort( + noise, dim=1 + ) # ascend: small is keep, large is remove + ids_restore = torch.argsort(ids_shuffle, dim=1) + + # keep the first subset + ids_keep = ids_shuffle[:, :len_keep] + x_masked = torch.gather(x, dim=1, index=ids_keep.unsqueeze(-1).repeat(1, 1, D)) + + # generate the binary mask: 0 is keep, 1 is remove + mask = torch.ones([N, L], device=x.device) + mask[:, :len_keep] = 0 + # unshuffle to get the binary mask + mask = torch.gather(mask, dim=1, index=ids_restore) + + return x_masked, mask, ids_restore # x_masked is actually unmasked x + + @classmethod + def build_model(cls, cfg: MaeConfig, task=None): + """Build a new model instance.""" + + return cls(cfg) + + def forward_encoder(self, x, mask_ratio): + # embed patches + x = self.patch_embed(x) + + # add pos embed w/o cls token + # if self.cls_token is not None: + # x = x + self.pos_embed + # else: + x = x + self.pos_embed[:, 1:, :] + + # masking: length -> length * mask_ratio + if mask_ratio > 0: + x, mask, ids_restore = self.random_masking(x, mask_ratio) + else: + mask = ids_restore = None + + # append cls token + if self.cls_token is not None: + cls_token = self.cls_token + self.pos_embed[:, :1, :] + cls_tokens = cls_token.expand(x.shape[0], -1, -1) + x = torch.cat((cls_tokens, x), dim=1) + + # apply Transformer blocks + for blk in self.blocks: + x = blk(x) + + if self.norm is not None: + x = self.norm(x) + + return x, mask, ids_restore + + def forward_decoder(self, x, ids_restore): + # embed tokens + x = self.decoder_embed(x) + + # append mask tokens to sequence + mask_tokens = self.mask_token.repeat( + x.shape[0], ids_restore.shape[1] + 1 - x.shape[1], 1 + ) + if self.cls_token is not None: + x_ = torch.cat([x[:, 1:, :], mask_tokens], dim=1) # no cls token + else: + x_ = torch.cat([x, mask_tokens], dim=1) # no cls token + + x_ = torch.gather( + x_, dim=1, index=ids_restore.unsqueeze(-1).repeat(1, 1, x.shape[2]) + ) # unshuffle + + if self.cls_token is not None: + x = torch.cat([x[:, :1, :], x_], dim=1) # append cls token + + # add pos embed + x = x + self.decoder_pos_embed + + # apply Transformer blocks + for blk in self.decoder_blocks: + x = blk(x) + x = self.decoder_norm(x) + + # predictor projection + x = self.decoder_pred(x) + + if self.cls_token is not None: + # remove cls token + x = x[:, 1:, :] + + return x + + def forward_loss(self, imgs, pred, mask): + """ + imgs: [N, 3, H, W] + pred: [N, L, p*p*3] + mask: [N, L], 0 is keep, 1 is remove, + """ + target = self.patchify(imgs) + if self.norm_pix_loss: + mean = target.mean(dim=-1, keepdim=True) + var = target.var(dim=-1, keepdim=True) + target = (target - mean) / (var + 1.0e-6) ** 0.5 + + loss = (pred - target) ** 2 + loss = loss.mean(dim=-1) # [N, L], mean loss per patch + + loss = (loss * mask).sum() + return loss, mask.sum() + + def forward(self, imgs, predictions_only=False): + latent, mask, ids_restore = self.forward_encoder( + imgs, self.mask_ratio if not predictions_only else 0 + ) + + if predictions_only: + return latent + + pred = self.forward_decoder(latent, ids_restore) # [N, L, p*p*3] + loss, sample_size = self.forward_loss(imgs, pred, mask) + + result = { + "losses": {"regression": loss}, + "sample_size": sample_size, + } + return result + + def remove_pretraining_modules(self): + self.decoder_embed = None + self.decoder_blocks = None + self.decoder_norm = None + self.decoder_pos_embed = None + self.decoder_pred = None + self.mask_token = None + if self.cfg.layer_norm_first: + self.norm = None diff --git a/examples/data2vec/models/mae_image_classification.py b/examples/data2vec/models/mae_image_classification.py new file mode 100644 index 0000000000..e304618dc5 --- /dev/null +++ b/examples/data2vec/models/mae_image_classification.py @@ -0,0 +1,386 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# The code in this file is adapted from the BeiT implementation which can be found here: +# https://github.com/microsoft/unilm/tree/master/beit + +import logging + +from dataclasses import dataclass +from enum import Enum, auto +from typing import Any, Optional + +import numpy as np +from omegaconf import II, MISSING + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from fairseq import checkpoint_utils, tasks +from omegaconf import open_dict + +from fairseq.dataclass import FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model +from .mae import interpolate_pos_embed + + +logger = logging.getLogger(__name__) + + +class PredictionMode(Enum): + MEAN_POOLING = auto() + CLS_TOKEN = auto() + LIN_SOFTMAX = auto() + + +@dataclass +class MaeImageClassificationConfig(FairseqDataclass): + model_path: str = MISSING + no_pretrained_weights: bool = False + linear_classifier: bool = False + num_classes: int = 1000 + mixup: float = 0.8 + cutmix: float = 1.0 + label_smoothing: float = 0.1 + + drop_path_rate: float = 0.1 + layer_decay: float = 0.65 + + mixup_prob: float = 1.0 + mixup_switch_prob: float = 0.5 + mixup_mode: str = "batch" + + pretrained_model_args: Any = None + data: str = II("task.data") + + norm_eps: Optional[float] = None + + remove_alibi: bool = False + + # regularization overwrites + encoder_dropout: float = 0 + post_mlp_drop: float = 0 + attention_dropout: float = 0 + activation_dropout: float = 0.0 + dropout_input: float = 0.0 + layerdrop: float = 0.0 + + prenet_layerdrop: float = 0 + prenet_dropout: float = 0 + + use_fc_norm: bool = True + prediction_mode: PredictionMode = PredictionMode.MEAN_POOLING + + no_decay_blocks: bool = True + + +def get_layer_id_for_vit(name, num_layers): + """ + Assign a parameter with its layer id + Following BEiT: https://github.com/microsoft/unilm/blob/master/beit/optim_factory.py#L33 + """ + if name in ["cls_token", "pos_embed"]: + return 0 + elif name.startswith("patch_embed"): + return 0 + elif name.startswith("rel_pos_bias"): + return num_layers - 1 + elif name.startswith("blocks"): + return int(name.split(".")[1]) + 1 + else: + return num_layers + + +@register_model("mae_image_classification", dataclass=MaeImageClassificationConfig) +class MaeImageClassificationModel(BaseFairseqModel): + def __init__(self, cfg: MaeImageClassificationConfig): + super().__init__() + self.cfg = cfg + + if cfg.pretrained_model_args is None: + state = checkpoint_utils.load_checkpoint_to_cpu(cfg.model_path, {}) + pretrained_args = state.get("cfg", None) + + pretrained_args.criterion = None + pretrained_args.lr_scheduler = None + + logger.info(pretrained_args.model) + + with open_dict(pretrained_args.model): + pretrained_args.model.drop_path_rate = cfg.drop_path_rate + if cfg.norm_eps is not None: + pretrained_args.model.norm_eps = cfg.norm_eps + + cfg.pretrained_model_args = pretrained_args + + logger.info(pretrained_args) + else: + state = None + pretrained_args = cfg.pretrained_model_args + + if "data" in pretrained_args.task: + pretrained_args.task.data = cfg.data + elif "image" in pretrained_args.task: + pretrained_args.task.image.data = cfg.data + + if "modalities" in pretrained_args.model: + prenet_blocks = pretrained_args.model["modalities"]["image"]["prenet_depth"] + model_blocks = pretrained_args.model["depth"] + with open_dict(pretrained_args): + dpr = np.linspace(0, cfg.drop_path_rate, model_blocks).tolist() + pretrained_args.model["modalities"]["image"][ + "start_drop_path_rate" + ] = dpr[0] + pretrained_args.model["modalities"]["image"][ + "end_drop_path_rate" + ] = max(0, dpr[prenet_blocks - 1]) + pretrained_args.model["start_drop_path_rate"] = dpr[prenet_blocks] + pretrained_args.model["end_drop_path_rate"] = dpr[-1] + + if "mae_masking" in pretrained_args.model["modalities"]["image"]: + del pretrained_args.model["modalities"]["image"]["mae_masking"] + + if cfg.remove_alibi: + pretrained_args.model["modalities"]["image"][ + "use_alibi_encoder" + ] = False + if ( + state is not None + and "modality_encoders.IMAGE.alibi_bias" in state["model"] + ): + del state["model"]["modality_encoders.IMAGE.alibi_bias"] + + pretrained_args.model["encoder_dropout"] = cfg.encoder_dropout + pretrained_args.model["post_mlp_drop"] = cfg.post_mlp_drop + pretrained_args.model["attention_dropout"] = cfg.attention_dropout + pretrained_args.model["activation_dropout"] = cfg.activation_dropout + pretrained_args.model["dropout_input"] = cfg.dropout_input + pretrained_args.model["layerdrop"] = cfg.layerdrop + + pretrained_args.model["modalities"]["image"][ + "prenet_layerdrop" + ] = cfg.prenet_layerdrop + pretrained_args.model["modalities"]["image"][ + "prenet_dropout" + ] = cfg.prenet_dropout + else: + # not d2v multi + with open_dict(pretrained_args): + pretrained_args.model["drop_path_rate"] = cfg.drop_path_rate + pretrained_args.model["block_dropout"] = cfg.encoder_dropout + pretrained_args.model["attention_dropout"] = cfg.attention_dropout + pretrained_args.model["activation_dropout"] = cfg.activation_dropout + + task = tasks.setup_task(pretrained_args.task) + model = task.build_model(pretrained_args.model, from_checkpoint=True) + + self.d2v_multi = "data2vec_multi" in pretrained_args.model._name + self.linear_classifier = cfg.linear_classifier + + self.model = model + + if state is not None and not cfg.no_pretrained_weights: + interpolate_pos_embed(model, state) + + if "modality_encoders.IMAGE.positional_encoder.pos_embed" in state["model"]: + state["model"][ + "modality_encoders.IMAGE.positional_encoder.positions" + ] = state["model"][ + "modality_encoders.IMAGE.positional_encoder.pos_embed" + ] + del state["model"][ + "modality_encoders.IMAGE.positional_encoder.pos_embed" + ] + if "modality_encoders.IMAGE.encoder_mask" in state["model"]: + del state["model"]["modality_encoders.IMAGE.encoder_mask"] + + model.load_state_dict(state["model"], strict=True) + + if self.d2v_multi: + model.remove_pretraining_modules(modality="image") + else: + model.remove_pretraining_modules() + + if self.linear_classifier: + model.requires_grad_(False) + + self.fc_norm = None + if self.cfg.use_fc_norm: + self.fc_norm = nn.LayerNorm(pretrained_args.model.embed_dim, eps=1e-6) + nn.init.constant_(self.fc_norm.bias, 0) + nn.init.constant_(self.fc_norm.weight, 1.0) + + self.head = nn.Linear(pretrained_args.model.embed_dim, cfg.num_classes) + + nn.init.trunc_normal_(self.head.weight, std=0.02) + nn.init.constant_(self.head.bias, 0) + + self.mixup_fn = None + + if cfg.mixup > 0 or cfg.cutmix > 0: + from timm.data import Mixup + + self.mixup_fn = Mixup( + mixup_alpha=cfg.mixup, + cutmix_alpha=cfg.cutmix, + cutmix_minmax=None, + prob=cfg.mixup_prob, + switch_prob=cfg.mixup_switch_prob, + mode=cfg.mixup_mode, + label_smoothing=cfg.label_smoothing, + num_classes=cfg.num_classes, + ) + + if self.model.norm is not None: + for pn, p in self.model.norm.named_parameters(): + if len(p.shape) == 1 or pn.endswith(".bias"): + p.optim_overrides = {"optimizer": {"weight_decay_scale": 0}} + + if self.fc_norm is not None: + for pn, p in self.fc_norm.named_parameters(): + if len(p.shape) == 1 or pn.endswith(".bias"): + p.optim_overrides = {"optimizer": {"weight_decay_scale": 0}} + + for pn, p in self.head.named_parameters(): + if len(p.shape) == 1 or pn.endswith(".bias"): + p.optim_overrides = {"optimizer": {"weight_decay_scale": 0}} + + if self.d2v_multi: + mod_encs = list(model.modality_encoders.values()) + assert len(mod_encs) == 1, len(mod_encs) + blocks = list(mod_encs[0].context_encoder.blocks) + list(model.blocks) + else: + blocks = model.blocks + + num_layers = len(blocks) + 1 + layer_scales = list( + cfg.layer_decay ** (num_layers - i) for i in range(num_layers + 1) + ) + + if self.d2v_multi: + for n, p in self.model.named_parameters(): + optimizer_override_dict = {} + + if len(p.shape) == 1 or n.endswith(".bias"): + optimizer_override_dict["weight_decay_scale"] = 0 + + p.optim_overrides = {"optimizer": optimizer_override_dict} + + if cfg.layer_decay > 0: + for i, b in enumerate(blocks): + lid = i + 1 + if layer_scales[lid] == 1.0: + continue + + for n, p in b.named_parameters(): + optim_override = getattr(p, "optim_overrides", {}) + if "optimizer" not in optim_override: + optim_override["optimizer"] = {} + + if cfg.no_decay_blocks: + optim_override["optimizer"]["lr_scale"] = layer_scales[lid] + p.optim_overrides = optim_override + else: + optim_override["optimizer"] = { + "lr_scale": layer_scales[lid] + } + p.optim_overrides = optim_override + + else: + for n, p in self.model.named_parameters(): + optimizer_override_dict = {} + layer_id = get_layer_id_for_vit(n, num_layers) + + if len(p.shape) == 1 or n.endswith(".bias"): + optimizer_override_dict["weight_decay_scale"] = 0 + + if cfg.layer_decay > 0: + optimizer_override_dict["lr_scale"] = layer_scales[layer_id] + p.optim_overrides = {"optimizer": optimizer_override_dict} + + @classmethod + def build_model(cls, cfg: MaeImageClassificationConfig, task=None): + """Build a new model instance.""" + + return cls(cfg) + + def forward( + self, + imgs, + labels=None, + ): + if self.training and self.mixup_fn is not None and labels is not None: + imgs, labels = self.mixup_fn(imgs, labels) + + if self.linear_classifier: + with torch.no_grad(): + x = self.model_forward(imgs) + else: + x = self.model_forward(imgs) + + if self.cfg.prediction_mode == PredictionMode.MEAN_POOLING: + x = x.mean(dim=1) + elif self.cfg.prediction_mode == PredictionMode.CLS_TOKEN: + x = x[:, 0] + elif self.cfg.prediction_mode == PredictionMode.LIN_SOFTMAX: + dtype = x.dtype + x = F.logsigmoid(x.float()) + x = torch.logsumexp(x + x, dim=1) - torch.logsumexp(x + 1e-6, dim=1) + x = x.clamp(max=0) + x = x - torch.log(-(torch.expm1(x))) + x = torch.nan_to_num(x, nan=0, posinf=0, neginf=0) + x = x.to(dtype=dtype) + else: + raise Exception(f"unknown prediction mode {self.cfg.prediction_mode.name}") + + if self.fc_norm is not None: + x = self.fc_norm(x) + + x = self.head(x) + + if labels is None: + return x + + if self.training and self.mixup_fn is not None: + loss = -labels * F.log_softmax(x.float(), dim=-1) + else: + loss = F.cross_entropy( + x.float(), + labels, + label_smoothing=self.cfg.label_smoothing if self.training else 0, + reduction="none", + ) + + result = { + "losses": {"regression": loss}, + "sample_size": imgs.size(0), + } + + if not self.training: + with torch.no_grad(): + pred = x.argmax(-1) + correct = (pred == labels).sum() + result["correct"] = correct + + return result + + def model_forward(self, imgs): + if self.d2v_multi: + x = self.model.extract_features( + imgs, + mode="IMAGE", + mask=False, + remove_extra_tokens=( + self.cfg.prediction_mode != PredictionMode.CLS_TOKEN + ), + )["x"] + else: + x = self.model(imgs, predictions_only=True) + if ( + "no_cls" not in self.model.cfg or not self.model.cfg.no_cls + ) and not self.cfg.prediction_mode == PredictionMode.CLS_TOKEN: + x = x[:, 1:] + return x diff --git a/examples/data2vec/models/modalities/__init__.py b/examples/data2vec/models/modalities/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/data2vec/models/modalities/audio.py b/examples/data2vec/models/modalities/audio.py new file mode 100644 index 0000000000..80d2857b24 --- /dev/null +++ b/examples/data2vec/models/modalities/audio.py @@ -0,0 +1,192 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from functools import partial +import torch +import torch.nn as nn +import numpy as np +from dataclasses import dataclass, field +from typing import Callable, Dict, Optional +from fairseq.models.wav2vec import ConvFeatureExtractionModel +from fairseq.modules import ( + LayerNorm, + SamePad, + TransposeLast, +) +from fairseq.tasks import FairseqTask +from .base import D2vModalityConfig, ModalitySpecificEncoder, get_alibi_bias +from .modules import BlockEncoder, Decoder1d +from examples.data2vec.data.modality import Modality + + +@dataclass +class D2vAudioConfig(D2vModalityConfig): + type: Modality = Modality.AUDIO + extractor_mode: str = "layer_norm" + feature_encoder_spec: str = field( + default="[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]", + metadata={ + "help": "string describing convolutional feature extraction layers in form of a python list that contains " + "[(dim, kernel_size, stride), ...]" + }, + ) + conv_pos_width: int = field( + default=95, + metadata={"help": "number of filters for convolutional positional embeddings"}, + ) + conv_pos_groups: int = field( + default=16, + metadata={"help": "number of groups for convolutional positional embedding"}, + ) + conv_pos_depth: int = field( + default=5, + metadata={"help": "depth of positional encoder network"}, + ) + conv_pos_pre_ln: bool = False + + +class AudioEncoder(ModalitySpecificEncoder): + + modality_cfg: D2vAudioConfig + + def __init__( + self, + modality_cfg: D2vAudioConfig, + embed_dim: int, + make_block: Callable[[float], nn.ModuleList], + norm_layer: Callable[[int], nn.LayerNorm], + layer_norm_first: bool, + alibi_biases: Dict, + task: Optional[FairseqTask], + ): + + self.feature_enc_layers = eval(modality_cfg.feature_encoder_spec) + feature_embed_dim = self.feature_enc_layers[-1][0] + + local_encoder = ConvFeatureExtractionModel( + conv_layers=self.feature_enc_layers, + dropout=0.0, + mode=modality_cfg.extractor_mode, + conv_bias=False, + ) + + project_features = nn.Sequential( + TransposeLast(), + nn.LayerNorm(feature_embed_dim), + nn.Linear(feature_embed_dim, embed_dim), + ) + + num_pos_layers = modality_cfg.conv_pos_depth + k = max(3, modality_cfg.conv_pos_width // num_pos_layers) + + positional_encoder = nn.Sequential( + TransposeLast(), + *[ + nn.Sequential( + nn.Conv1d( + embed_dim, + embed_dim, + kernel_size=k, + padding=k // 2, + groups=modality_cfg.conv_pos_groups, + ), + SamePad(k), + TransposeLast(), + LayerNorm(embed_dim, elementwise_affine=False), + TransposeLast(), + nn.GELU(), + ) + for _ in range(num_pos_layers) + ], + TransposeLast(), + ) + + if modality_cfg.conv_pos_pre_ln: + positional_encoder = nn.Sequential(LayerNorm(embed_dim), positional_encoder) + + dpr = np.linspace( + modality_cfg.start_drop_path_rate, + modality_cfg.end_drop_path_rate, + modality_cfg.prenet_depth, + ) + context_encoder = BlockEncoder( + nn.ModuleList(make_block(dpr[i]) for i in range(modality_cfg.prenet_depth)), + norm_layer(embed_dim) if not layer_norm_first else None, + layer_norm_first, + modality_cfg.prenet_layerdrop, + modality_cfg.prenet_dropout, + ) + + decoder = ( + Decoder1d(modality_cfg.decoder, embed_dim) + if modality_cfg.decoder is not None + else None + ) + + alibi_bias_fn = partial(get_alibi_bias, alibi_biases=alibi_biases) + + super().__init__( + modality_cfg=modality_cfg, + embed_dim=embed_dim, + local_encoder=local_encoder, + project_features=project_features, + fixed_positional_encoder=None, + relative_positional_encoder=positional_encoder, + context_encoder=context_encoder, + decoder=decoder, + get_alibi_bias=alibi_bias_fn, + ) + + def convert_padding_mask(self, x, padding_mask): + def get_feat_extract_output_lengths(input_lengths: torch.LongTensor): + """ + Computes the output length of the convolutional layers + """ + + def _conv_out_length(input_length, kernel_size, stride): + return torch.floor((input_length - kernel_size) / stride + 1) + + for i in range(len(self.feature_enc_layers)): + input_lengths = _conv_out_length( + input_lengths, + self.feature_enc_layers[i][1], + self.feature_enc_layers[i][2], + ) + + return input_lengths.to(torch.long) + + if padding_mask is not None: + input_lengths = (1 - padding_mask.long()).sum(-1) + # apply conv formula to get real output_lengths + output_lengths = get_feat_extract_output_lengths(input_lengths) + + if padding_mask.any(): + padding_mask = torch.zeros(x.shape[:2], dtype=x.dtype, device=x.device) + + # these two operations makes sure that all values + # before the output lengths indices are attended to + padding_mask[ + ( + torch.arange(padding_mask.shape[0], device=padding_mask.device), + output_lengths - 1, + ) + ] = 1 + padding_mask = ( + 1 - padding_mask.flip([-1]).cumsum(-1).flip([-1]) + ).bool() + else: + padding_mask = torch.zeros( + x.shape[:2], dtype=torch.bool, device=x.device + ) + + return padding_mask + + def reset_parameters(self): + super().reset_parameters() + for mod in self.project_features.children(): + if isinstance(mod, nn.Linear): + mod.reset_parameters() + if self.decoder is not None: + self.decoder.reset_parameters() diff --git a/examples/data2vec/models/modalities/base.py b/examples/data2vec/models/modalities/base.py new file mode 100644 index 0000000000..642cc84661 --- /dev/null +++ b/examples/data2vec/models/modalities/base.py @@ -0,0 +1,684 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import math +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +from collections import namedtuple +from dataclasses import dataclass +from functools import partial +from omegaconf import MISSING, II +from typing import Optional, Callable +from fairseq.data.data_utils import compute_mask_indices +from fairseq.modules import GradMultiply +from fairseq.utils import index_put +from examples.data2vec.data.modality import Modality +from .modules import D2vDecoderConfig + +logger = logging.getLogger(__name__) + + +@dataclass +class D2vModalityConfig: + type: Modality = MISSING + prenet_depth: int = 4 + prenet_layerdrop: float = 0 + prenet_dropout: float = 0 + start_drop_path_rate: float = 0 + end_drop_path_rate: float = 0 + + num_extra_tokens: int = 0 + init_extra_token_zero: bool = True + + mask_noise_std: float = 0.01 + mask_prob_min: Optional[float] = None + mask_prob: float = 0.7 + inverse_mask: bool = False + mask_prob_adjust: float = 0 + keep_masked_pct: float = 0 + + mask_length: int = 5 + add_masks: bool = False + remove_masks: bool = False + mask_dropout: float = 0.0 + encoder_zero_mask: bool = True + + mask_channel_prob: float = 0.0 + mask_channel_length: int = 64 + + ema_local_encoder: bool = False # used in data2vec_multi + local_grad_mult: float = 1.0 + + use_alibi_encoder: bool = False + alibi_scale: float = 1.0 + learned_alibi: bool = False + alibi_max_pos: Optional[int] = None + learned_alibi_scale: bool = False + learned_alibi_scale_per_head: bool = False + learned_alibi_scale_per_layer: bool = False + + num_alibi_heads: int = II("model.num_heads") + model_depth: int = II("model.depth") + + decoder: Optional[D2vDecoderConfig] = D2vDecoderConfig() + + +MaskSeed = namedtuple("MaskSeed", ["seed", "update", "ids"]) +MaskInfo = namedtuple("MaskInfo", ["x_unmasked", "mask", "ids_restore", "ids_keep"]) + + +class ModalitySpecificEncoder(nn.Module): + def __init__( + self, + modality_cfg: D2vModalityConfig, + embed_dim: int, + local_encoder: nn.Module, + project_features: nn.Module, + fixed_positional_encoder: Optional[nn.Module], + relative_positional_encoder: Optional[nn.Module], + context_encoder: nn.Module, + decoder: nn.Module, + get_alibi_bias: Optional[Callable[[int, int, str, str], torch.Tensor]], + ): + super().__init__() + + self.modality_cfg = modality_cfg + self.local_encoder = local_encoder + self.project_features = project_features + self.fixed_positional_encoder = fixed_positional_encoder + self.relative_positional_encoder = relative_positional_encoder + self.context_encoder = context_encoder + + self.decoder = decoder + self.get_alibi_bias = get_alibi_bias if modality_cfg.use_alibi_encoder else None + + self.local_grad_mult = self.modality_cfg.local_grad_mult + + self.extra_tokens = None + if modality_cfg.num_extra_tokens > 0: + self.extra_tokens = nn.Parameter( + torch.zeros(1, modality_cfg.num_extra_tokens, embed_dim) + ) + if not modality_cfg.init_extra_token_zero: + nn.init.normal_(self.extra_tokens) + elif self.extra_tokens.size(1) > 1: + nn.init.normal_(self.extra_tokens[:, 1:]) + + self.alibi_scale = None + if self.get_alibi_bias is not None: + self.alibi_scale = nn.Parameter( + torch.full( + ( + (modality_cfg.prenet_depth + modality_cfg.model_depth) + if modality_cfg.learned_alibi_scale_per_layer + else 1, + 1, + self.modality_cfg.num_alibi_heads + if modality_cfg.learned_alibi_scale_per_head + else 1, + 1, + 1, + ), + modality_cfg.alibi_scale, + dtype=torch.float, + ), + requires_grad=modality_cfg.learned_alibi_scale, + ) + + if modality_cfg.learned_alibi and self.get_alibi_bias is not None: + assert modality_cfg.alibi_max_pos is not None + alibi_bias = self.get_alibi_bias( + batch_size=1, + time_steps=modality_cfg.alibi_max_pos, + heads=modality_cfg.num_alibi_heads, + scale=1.0, + dtype=torch.float, + device="cpu", + ) + self.alibi_bias = nn.Parameter(alibi_bias) + self.get_alibi_bias = partial( + _learned_alibi_bias, alibi_bias=self.alibi_bias + ) + + def upgrade_state_dict_named(self, state_dict, name): + k = f"{name}.alibi_scale" + if k in state_dict and state_dict[k].dim() == 4: + state_dict[k] = state_dict[k].unsqueeze(0) + + return state_dict + + def convert_padding_mask(self, x, padding_mask): + return padding_mask + + def decoder_input(self, x, mask_info: MaskInfo): + inp_drop = self.modality_cfg.decoder.input_dropout + if inp_drop > 0: + x = F.dropout(x, inp_drop, training=self.training, inplace=True) + + num_extra = self.modality_cfg.num_extra_tokens + + if mask_info is not None: + num_masked = mask_info.ids_restore.shape[1] - x.shape[1] + num_extra + + mask_tokens = x.new_empty( + x.size(0), + num_masked, + x.size(-1), + ).normal_(0, self.modality_cfg.mask_noise_std) + + x_ = torch.cat([x[:, num_extra:], mask_tokens], dim=1) + x = torch.gather(x_, dim=1, index=mask_info.ids_restore) + + if self.modality_cfg.decoder.add_positions_masked: + assert self.fixed_positional_encoder is not None + pos = self.fixed_positional_encoder(x, None) + x = x + (pos * mask_info.mask.unsqueeze(-1)) + else: + x = x[:, num_extra:] + + if self.modality_cfg.decoder.add_positions_all: + assert self.fixed_positional_encoder is not None + x = x + self.fixed_positional_encoder(x, None) + + return x, mask_info + + def local_features(self, features): + if self.local_grad_mult > 0: + if self.local_grad_mult == 1.0: + x = self.local_encoder(features) + else: + x = GradMultiply.apply( + self.local_encoder(features), self.local_grad_mult + ) + else: + with torch.no_grad(): + x = self.local_encoder(features) + + x = self.project_features(x) + return x + + def contextualized_features( + self, + x, + padding_mask, + mask, + remove_masked, + clone_batch: int = 1, + mask_seeds: Optional[torch.Tensor] = None, + precomputed_mask=None, + ): + + if padding_mask is not None: + padding_mask = self.convert_padding_mask(x, padding_mask) + + local_features = x + if mask and clone_batch == 1: + local_features = local_features.clone() + + orig_B, orig_T, _ = x.shape + pre_mask_B = orig_B + mask_info = None + + x_pos = None + if self.fixed_positional_encoder is not None: + x = x + self.fixed_positional_encoder(x, padding_mask) + + if mask: + if clone_batch > 1: + x = x.repeat_interleave(clone_batch, 0) + if mask_seeds is not None: + clone_hash = [ + int(hash((mask_seeds.seed, ind)) % 1e10) + for ind in range(clone_batch - 1) + ] + clone_hash = torch.tensor([0] + clone_hash).long().view(1, -1) + + id = mask_seeds.ids + id = id.repeat_interleave(clone_batch, 0) + id = id.view(-1, clone_batch) + clone_hash.to(id) + id = id.view(-1) + mask_seeds = MaskSeed( + seed=mask_seeds.seed, update=mask_seeds.update, ids=id + ) + if padding_mask is not None: + padding_mask = padding_mask.repeat_interleave(clone_batch, 0) + + x, mask_info = self.compute_mask( + x, + padding_mask, + mask_seed=mask_seeds, + apply=self.relative_positional_encoder is not None or not remove_masked, + precomputed_mask=precomputed_mask, + ) + + if self.relative_positional_encoder is not None: + x_pos = self.relative_positional_encoder(x) + + masked_padding_mask = padding_mask + if mask and remove_masked: + x = mask_info.x_unmasked + if x_pos is not None: + x = x + gather_unmasked(x_pos, mask_info) + + if padding_mask is not None and padding_mask.any(): + masked_padding_mask = gather_unmasked_mask(padding_mask, mask_info) + if not masked_padding_mask.any(): + masked_padding_mask = None + else: + masked_padding_mask = None + + elif x_pos is not None: + x = x + x_pos + + alibi_bias = None + alibi_scale = self.alibi_scale + + if self.get_alibi_bias is not None: + alibi_bias = self.get_alibi_bias( + batch_size=pre_mask_B, + time_steps=orig_T, + heads=self.modality_cfg.num_alibi_heads, + dtype=torch.float32, + device=x.device, + ) + + if alibi_scale is not None: + alibi_scale = alibi_scale.clamp_min(0) + if alibi_scale.size(0) == 1: + alibi_bias = alibi_bias * alibi_scale.squeeze(0).type_as(alibi_bias) + alibi_scale = None + + if clone_batch > 1: + alibi_bias = alibi_bias.repeat_interleave(clone_batch, 0) + + if mask_info is not None and remove_masked: + alibi_bias = masked_alibi(alibi_bias, mask_info) + + if self.extra_tokens is not None: + num = self.extra_tokens.size(1) + x = torch.cat([self.extra_tokens.expand(x.size(0), -1, -1), x], dim=1) + if masked_padding_mask is not None: + # B x T + masked_padding_mask = F.pad(masked_padding_mask, (num, 0)) + if alibi_bias is not None: + # B x H x T x T + alibi_bias = F.pad(alibi_bias, (num, 0, num, 0)) + + x = self.context_encoder( + x, + masked_padding_mask, + alibi_bias, + alibi_scale[: self.modality_cfg.prenet_depth] + if alibi_scale is not None + else None, + ) + + return { + "x": x, + "local_features": local_features, + "padding_mask": masked_padding_mask, + "alibi_bias": alibi_bias, + "alibi_scale": alibi_scale[self.modality_cfg.prenet_depth :] + if alibi_scale is not None and alibi_scale.size(0) > 1 + else alibi_scale, + "encoder_mask": mask_info, + } + + def forward( + self, + features, + padding_mask, + mask: bool, + remove_masked: bool, + clone_batch: int = 1, + mask_seeds: Optional[torch.Tensor] = None, + precomputed_mask=None, + ): + x = self.local_features(features) + return self.contextualized_features( + x, + padding_mask, + mask, + remove_masked, + clone_batch, + mask_seeds, + precomputed_mask, + ) + + def reset_parameters(self): + pass + + def compute_mask( + self, + x, + padding_mask, + mask_seed: Optional[MaskSeed], + apply, + precomputed_mask, + ): + if precomputed_mask is not None: + mask = precomputed_mask + mask_info = self.make_maskinfo(x, mask) + else: + B, T, C = x.shape + cfg = self.modality_cfg + + mask_prob = cfg.mask_prob + + if ( + cfg.mask_prob_min is not None + and cfg.mask_prob_min >= 0 + and cfg.mask_prob_min < mask_prob + ): + mask_prob = np.random.uniform(cfg.mask_prob_min, mask_prob) + + if mask_prob > 0: + if cfg.mask_length == 1: + mask_info = random_masking(x, mask_prob, mask_seed) + else: + if self.modality_cfg.inverse_mask: + mask_prob = 1 - mask_prob + + mask = compute_mask_indices( + (B, T), + padding_mask, + mask_prob, + cfg.mask_length, + min_masks=1, + require_same_masks=True, + mask_dropout=cfg.mask_dropout, + add_masks=cfg.add_masks, + seed=mask_seed.seed if mask_seed is not None else None, + epoch=mask_seed.update if mask_seed is not None else None, + indices=mask_seed.ids if mask_seed is not None else None, + ) + + mask = torch.from_numpy(mask).to(device=x.device) + if self.modality_cfg.inverse_mask: + mask = 1 - mask + mask_info = self.make_maskinfo(x, mask) + else: + mask_info = None + + if apply: + x = self.apply_mask(x, mask_info) + + return x, mask_info + + def make_maskinfo(self, x, mask, shape=None): + if shape is None: + B, T, D = x.shape + else: + B, T, D = shape + + mask = mask.to(torch.uint8) + ids_shuffle = mask.argsort(dim=1) + ids_restore = ids_shuffle.argsort(dim=1).unsqueeze(-1).expand(-1, -1, D) + + len_keep = T - mask[0].sum() + if self.modality_cfg.keep_masked_pct > 0: + len_keep += round((T - int(len_keep)) * self.modality_cfg.keep_masked_pct) + + ids_keep = ids_shuffle[:, :len_keep] + + if shape is not None: + x_unmasked = None + else: + ids_keep = ids_keep.unsqueeze(-1).expand(-1, -1, D) + x_unmasked = torch.gather(x, dim=1, index=ids_keep) + + mask_info = MaskInfo( + x_unmasked=x_unmasked, + mask=mask, + ids_restore=ids_restore, + ids_keep=ids_keep, + ) + return mask_info + + def apply_mask(self, x, mask_info): + cfg = self.modality_cfg + B, T, C = x.shape + + if mask_info is not None: + mask = mask_info.mask + if cfg.encoder_zero_mask: + x = x * (1 - mask.type_as(x).unsqueeze(-1)) + else: + num_masks = mask.sum().item() + masks = x.new_empty(num_masks, x.size(-1)).normal_( + 0, cfg.mask_noise_std + ) + x = index_put(x, mask, masks) + if cfg.mask_channel_prob > 0: + mask_channel = compute_mask_indices( + (B, C), + None, + cfg.mask_channel_prob, + cfg.mask_channel_length, + ) + mask_channel = ( + torch.from_numpy(mask_channel) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x = index_put(x, mask_channel, 0) + return x + + def remove_pretraining_modules(self, keep_decoder=False): + if not keep_decoder: + self.decoder = None + + +def get_annealed_rate(start, end, curr_step, total_steps): + if curr_step >= total_steps: + return end + r = end - start + pct_remaining = 1 - curr_step / total_steps + return end - r * pct_remaining + + +# adapted from MAE +def random_masking(x, mask_ratio, mask_seed: Optional[MaskSeed]): + N, L, D = x.shape # batch, length, dim + len_keep = int(L * (1 - mask_ratio)) + + generator = None + if mask_seed is not None: + seed = int( + hash((mask_seed.seed, mask_seed.update, mask_seed.ids.sum().item())) % 1e6 + ) + generator = torch.Generator(device=x.device) + generator.manual_seed(seed) + + noise = torch.rand(N, L, generator=generator, device=x.device) # noise in [0, 1] + + # sort noise for each sample + ids_shuffle = noise.argsort(dim=1) # ascend: small is keep, large is remove + ids_restore = ids_shuffle.argsort(dim=1) + + # keep the first subset + ids_keep = ids_shuffle[:, :len_keep] + ids_keep = ids_keep.unsqueeze(-1).expand(-1, -1, D) + x_unmasked = torch.gather(x, dim=1, index=ids_keep) + + # generate the binary mask: 0 is keep, 1 is remove + mask = torch.ones([N, L], dtype=x.dtype, device=x.device) + mask[:, :len_keep] = 0 + # unshuffle to get the binary mask + mask = torch.gather(mask, dim=1, index=ids_restore) + + ids_restore = ids_restore.unsqueeze(-1).expand(-1, -1, D) + + return MaskInfo( + x_unmasked=x_unmasked, mask=mask, ids_restore=ids_restore, ids_keep=ids_keep + ) + + +def gather_unmasked(x: torch.Tensor, mask_info: MaskInfo) -> torch.Tensor: + return torch.gather( + x, + dim=1, + index=mask_info.ids_keep, + ) + + +def gather_unmasked_mask(x: torch.Tensor, mask_info: MaskInfo) -> torch.Tensor: + return torch.gather( + x, + dim=1, + index=mask_info.ids_keep[..., 0], # ignore the feature dimension + ) + + +def get_alibi( + max_positions: int, + attention_heads: int, + dims: int = 1, + distance: str = "manhattan", +): + def get_slopes(n): + def get_slopes_power_of_2(n): + start = 2 ** (-(2 ** -(math.log2(n) - 3))) + ratio = start + return [start * ratio**i for i in range(n)] + + # In the paper, we only train models that have 2^a heads for some + # a. This function has some good properties that only occur when + # the input is a power of 2. To maintain that even when the number + # of heads is not a power of 2, we use this workaround. + if math.log2(n).is_integer(): + return get_slopes_power_of_2(n) + else: + closest_power_of_2 = 2 ** math.floor(math.log2(n)) + return ( + get_slopes_power_of_2(closest_power_of_2) + + get_slopes(2 * closest_power_of_2)[0::2][: n - closest_power_of_2] + ) + + maxpos = max_positions + attn_heads = attention_heads + slopes = torch.Tensor(get_slopes(attn_heads)) + + if dims == 1: + # prepare alibi position linear bias. Note that wav2vec2 is non + # autoregressive model so we want a symmetric mask with 0 on the + # diagonal and other wise linear decreasing valuees + pos_bias = ( + torch.abs( + torch.arange(maxpos).unsqueeze(0) - torch.arange(maxpos).unsqueeze(1) + ) + * -1 + ) + elif dims == 2: + if distance == "manhattan": + df = lambda x1, y1, x2, y2: abs(x1 - x2) + abs(y1 - y2) + elif distance == "euclidean": + df = lambda x1, y1, x2, y2: math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) + + n = math.sqrt(max_positions) + assert n.is_integer(), n + n = int(n) + + pos_bias = torch.zeros((max_positions, max_positions)) + + for i in range(n): + for j in range(n): + for k in range(n): + for l in range(n): + new_x = i * n + j + new_y = k * n + l + pos_bias[new_x, new_y] = -df(i, j, k, l) + + else: + raise Exception(f"unsupported number of alibi dims: {dims}") + + alibi_bias = slopes.unsqueeze(1).unsqueeze(1) * pos_bias.unsqueeze(0).expand( + attn_heads, -1, -1 + ) + + return alibi_bias + + +def get_alibi_bias( + alibi_biases, + batch_size, + time_steps, + heads, + dtype, + device, + dims=1, + distance="manhattan", +): + cache_key = f"{dims}_{heads}_{distance}" + + buffered = alibi_biases.get(cache_key, None) + + target_size = heads * batch_size + if ( + buffered is None + or buffered.size(0) < target_size + or buffered.size(1) < time_steps + or buffered.dtype != dtype + or buffered.device != device + ): + bt = max(time_steps, buffered.size(1) if buffered is not None else 0) + bn = max(target_size, buffered.size(0) if buffered is not None else 0) // heads + + buffered = ( + get_alibi(bt, heads, dims=dims, distance=distance) + .to(dtype=dtype, device=device) + .repeat(bn, 1, 1) + ) + + alibi_biases[cache_key] = buffered + + b = buffered[:target_size, :time_steps, :time_steps] + b = b.view(batch_size, heads, time_steps, time_steps) + return b + + +def _learned_alibi_bias( + alibi_bias, + batch_size, + time_steps, + heads, + scale, + dtype, + device, +): + assert alibi_bias.size(1) == heads, alibi_bias.shape + assert alibi_bias.dtype == dtype, alibi_bias.dtype + assert alibi_bias.device == device, alibi_bias.device + + if alibi_bias.size(-1) < time_steps: + psz = math.ceil((time_steps - alibi_bias.size(-1)) / 2) + alibi_bias = F.pad(alibi_bias, (psz, psz, psz, psz), mode="replicate") + + alibi_bias = alibi_bias.expand(batch_size, -1, -1, -1) * scale + return alibi_bias[..., :time_steps, :time_steps] + + +def masked_alibi(alibi_bias, mask_info): + H = alibi_bias.size(1) + + orig_bias = alibi_bias + + index = mask_info.ids_keep.unsqueeze(1)[..., 0].unsqueeze(-1) + alibi_bias = torch.gather( + orig_bias, + dim=-2, + index=index.expand(-1, H, -1, mask_info.ids_restore.size(1)), + ) + alibi_bias = torch.gather( + alibi_bias, + dim=-1, + index=index.transpose(-1, -2).expand(-1, H, alibi_bias.size(-2), -1), + ) + + return alibi_bias diff --git a/examples/data2vec/models/modalities/images.py b/examples/data2vec/models/modalities/images.py new file mode 100644 index 0000000000..a6b738cb07 --- /dev/null +++ b/examples/data2vec/models/modalities/images.py @@ -0,0 +1,256 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +from functools import partial +from dataclasses import dataclass +from typing import Callable, Dict, Optional +from timm.models.layers import to_2tuple +from fairseq.tasks import FairseqTask +from examples.data2vec.models.mae import get_2d_sincos_pos_embed, PatchEmbed +from .base import ( + D2vModalityConfig, + ModalitySpecificEncoder, + get_alibi_bias, + MaskSeed, +) +from .modules import ( + BlockEncoder, + Decoder2d, + FixedPositionalEncoder, + TransformerDecoder, + EncDecTransformerDecoder, +) +from examples.data2vec.data.modality import Modality + + +@dataclass +class D2vImageConfig(D2vModalityConfig): + type: Modality = Modality.IMAGE + + input_size: int = 224 + in_chans: int = 3 + patch_size: int = 16 + embed_dim: int = 768 + + alibi_dims: int = 2 + alibi_distance: str = "manhattan" + + fixed_positions: bool = True + + transformer_decoder: bool = False + enc_dec_transformer: bool = False + + +class ImageEncoder(ModalitySpecificEncoder): + + modality_cfg: D2vImageConfig + + def __init__( + self, + modality_cfg: D2vImageConfig, + embed_dim: int, + make_block: Callable[[float, Optional[int], Optional[int]], nn.ModuleList], + norm_layer: Callable[[int], nn.LayerNorm], + layer_norm_first: bool, + alibi_biases: Dict, + task: Optional[FairseqTask], + ): + + img_size = to_2tuple(modality_cfg.input_size) + patch_size = to_2tuple(modality_cfg.patch_size) + num_patches = (img_size[1] // patch_size[1]) * (img_size[0] // patch_size[0]) + + local_encoder = PatchEmbed( + modality_cfg.input_size, + modality_cfg.patch_size, + modality_cfg.in_chans, + modality_cfg.embed_dim, + ) + + w = local_encoder.proj.weight.data + torch.nn.init.xavier_uniform_(w.view([w.shape[0], -1])) + + if modality_cfg.embed_dim != embed_dim: + local_encoder = nn.Sequential( + local_encoder, + nn.Linear(modality_cfg.embed_dim, embed_dim), + ) + + project_features = nn.Identity() + + pos_embed = nn.Parameter( + torch.zeros(1, num_patches, embed_dim), requires_grad=False + ) + + side_n = int(num_patches ** 0.5) + + emb = get_2d_sincos_pos_embed( + pos_embed.shape[-1], + side_n, + cls_token=False, + ) + pos_embed.data.copy_(torch.from_numpy(emb).float().unsqueeze(0)) + fixed_positional_encoder = ( + FixedPositionalEncoder(pos_embed) if modality_cfg.fixed_positions else None + ) + + dpr = np.linspace( + modality_cfg.start_drop_path_rate, + modality_cfg.end_drop_path_rate, + modality_cfg.prenet_depth, + ) + + context_encoder = BlockEncoder( + nn.ModuleList(make_block(dpr[i]) for i in range(modality_cfg.prenet_depth)), + norm_layer(embed_dim) if not layer_norm_first else None, + layer_norm_first, + modality_cfg.prenet_layerdrop, + modality_cfg.prenet_dropout, + ) + + if modality_cfg.transformer_decoder: + if modality_cfg.enc_dec_transformer: + decoder = EncDecTransformerDecoder(modality_cfg.decoder, embed_dim) + else: + dec_enc = BlockEncoder( + nn.ModuleList( + make_block(0, modality_cfg.decoder.decoder_dim, 8) + for _ in range(modality_cfg.decoder.decoder_layers) + ), + None, + layer_norm_first, + 0, + 0, + ) + decoder = TransformerDecoder(modality_cfg.decoder, embed_dim, dec_enc) + else: + decoder = ( + Decoder2d(modality_cfg.decoder, embed_dim, side_n, side_n) + if modality_cfg.decoder is not None + else None + ) + + alibi_bias_fn = partial( + get_alibi_bias, + alibi_biases=alibi_biases, + heads=modality_cfg.num_alibi_heads, + dims=modality_cfg.alibi_dims, + distance=modality_cfg.alibi_distance, + ) + + super().__init__( + modality_cfg=modality_cfg, + embed_dim=embed_dim, + local_encoder=local_encoder, + project_features=project_features, + fixed_positional_encoder=fixed_positional_encoder, + relative_positional_encoder=None, + context_encoder=context_encoder, + decoder=decoder, + get_alibi_bias=alibi_bias_fn, + ) + + def reset_parameters(self): + super().reset_parameters() + if self.decoder is not None: + self.decoder.reset_parameters() + + @torch.no_grad() + def patchify(self, imgs): + """ + imgs: (N, 3, H, W) + x: (N, L, patch_size**2 *3) + """ + p = self.modality_cfg.patch_size + h = w = imgs.shape[2] // p + x = imgs.reshape(shape=(imgs.shape[0], 3, h, p, w, p)) + x = torch.einsum("nchpwq->nhwpqc", x) + x = x.reshape(shape=(imgs.shape[0], h * w, p ** 2 * 3)) + + return x + + @torch.no_grad() + def unpatchify(self, x): + """ + x: (N, L, patch_size**2 *3) + imgs: (N, 3, H, W) + """ + p = self.modality_cfg.patch_size + h = w = int(x.shape[1] ** 0.5) + assert h * w == x.shape[1] + + x = x.reshape(shape=(x.shape[0], h, w, p, p, 3)) + x = torch.einsum("nhwpqc->nchpwq", x) + imgs = x.reshape(shape=(x.shape[0], 3, h * p, h * p)) + return imgs + + def compute_mask( + self, + x, + padding_mask, + mask_seed: Optional[MaskSeed], + apply, + shape=None, + precomputed_mask=None, + ): + mlen = self.modality_cfg.mask_length + if mlen <= 1: + return super().compute_mask( + x, padding_mask, mask_seed, apply, precomputed_mask + ) + + if precomputed_mask is not None: + mask = precomputed_mask + else: + from fairseq.data.data_utils import compute_block_mask_2d + + if shape is not None: + B, L, D = shape + else: + B, L, D = x.shape + + mask = compute_block_mask_2d( + shape=(B, L), + mask_prob=self.modality_cfg.mask_prob, + mask_length=self.modality_cfg.mask_length, + mask_prob_adjust=self.modality_cfg.mask_prob_adjust, + inverse_mask=self.modality_cfg.inverse_mask, + require_same_masks=True, + mask_dropout=self.modality_cfg.mask_dropout, + ) + + mask_info = self.make_maskinfo(x, mask, shape) + if apply: + x = self.apply_mask(x, mask_info) + + return x, mask_info + + def decoder_input(self, x, mask_info): + if ( + not self.modality_cfg.transformer_decoder + or not self.modality_cfg.enc_dec_transformer + ): + return super().decoder_input(x, mask_info) + + inp_drop = self.modality_cfg.decoder.input_dropout + if inp_drop > 0: + x = F.dropout(x, inp_drop, training=self.training, inplace=True) + + kv = x[:, self.modality_cfg.num_extra_tokens :] + + assert self.fixed_positional_encoder is not None + pos = self.fixed_positional_encoder(x, None).expand(x.size(0), -1, -1) + + mask = mask_info.mask.bool() + if self.modality_cfg.decoder.add_positions_all: + kv = kv + pos[~mask].view(kv.shape) + + q = pos[mask].view(x.size(0), -1, x.size(-1)) + + return q, kv diff --git a/examples/data2vec/models/modalities/modules.py b/examples/data2vec/models/modalities/modules.py new file mode 100644 index 0000000000..a4e1a4ea07 --- /dev/null +++ b/examples/data2vec/models/modalities/modules.py @@ -0,0 +1,589 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +from dataclasses import dataclass +from fairseq.modules import ( + LayerNorm, + SamePad, + SamePad2d, + TransposeLast, +) + + +@dataclass +class D2vDecoderConfig: + decoder_dim: int = 384 + decoder_groups: int = 16 + decoder_kernel: int = 5 + decoder_layers: int = 5 + input_dropout: float = 0.1 + + add_positions_masked: bool = False + add_positions_all: bool = False + + decoder_residual: bool = True + projection_layers: int = 1 + projection_ratio: float = 2.0 + + +class FixedPositionalEncoder(nn.Module): + def __init__(self, pos_embed): + super().__init__() + self.positions = pos_embed + + def forward(self, x, padding_mask): + return self.positions + + +class TextFeatPositionalEncoder(nn.Module): + """ + Original encoder expects (B, T) long input. This module wraps it to take + local_encoder output which are (B, T, D) float tensors + """ + + def __init__(self, pos_encoder): + super().__init__() + self.pos_encoder = pos_encoder + + def forward(self, x, padding_mask): + # assume padded token embeddings are 0s + # TODO: consider using padding_mask as input + return self.pos_encoder(x[..., 0]) + + +class BlockEncoder(nn.Module): + def __init__(self, blocks, norm_layer, layer_norm_first, layerdrop, dropout): + super().__init__() + self.blocks = blocks + self.norm = norm_layer + self.layer_norm_first = layer_norm_first + self.layerdrop = layerdrop + self.dropout = nn.Dropout(dropout, inplace=True) + + def forward(self, x, padding_mask, alibi_bias, alibi_scale): + if self.norm is not None and not self.layer_norm_first: + x = self.norm(x) + + x = self.dropout(x) + + for i, blk in enumerate(self.blocks): + if ( + not self.training + or self.layerdrop == 0 + or (np.random.random() > self.layerdrop) + ): + ab = alibi_bias + if ab is not None and alibi_scale is not None: + scale = ( + alibi_scale[i] + if alibi_scale.size(0) > 1 + else alibi_scale.squeeze(0) + ) + ab = ab * scale.type_as(ab) + x, _ = blk(x, padding_mask, ab) + + if self.norm is not None and self.layer_norm_first: + x = self.norm(x) + + return x + + +class DecoderBase(nn.Module): + decoder_cfg: D2vDecoderConfig + + def __init__(self, cfg: D2vDecoderConfig): + super().__init__() + + self.decoder_cfg = cfg + + def reset_parameters(self): + for mod in self.proj.modules(): + if isinstance(mod, nn.Linear): + mod.reset_parameters() + + def add_residual(self, x, residual, i, mask_info): + if ( + residual is None + or not self.decoder_cfg.decoder_residual + or residual.size(1) != x.size(1) + ): + return x + + ret = x + residual + + return ret + + +class Decoder1d(DecoderBase): + def __init__(self, cfg: D2vDecoderConfig, input_dim): + super().__init__(cfg) + + def make_block(in_dim): + block = [ + nn.Conv1d( + in_dim, + cfg.decoder_dim, + kernel_size=cfg.decoder_kernel, + padding=cfg.decoder_kernel // 2, + groups=cfg.decoder_groups, + ), + SamePad(cfg.decoder_kernel), + TransposeLast(), + LayerNorm(cfg.decoder_dim, elementwise_affine=False), + TransposeLast(), + nn.GELU(), + ] + + return nn.Sequential(*block) + + self.blocks = nn.Sequential( + *[ + make_block(input_dim if i == 0 else cfg.decoder_dim) + for i in range(cfg.decoder_layers) + ] + ) + + projs = [] + curr_dim = cfg.decoder_dim + for i in range(cfg.projection_layers - 1): + next_dim = int(curr_dim * cfg.projection_ratio) if i == 0 else curr_dim + projs.append(nn.Linear(curr_dim, next_dim)) + projs.append(nn.GELU()) + curr_dim = next_dim + projs.append(nn.Linear(curr_dim, input_dim)) + if len(projs) == 1: + self.proj = projs[0] + else: + self.proj = nn.Sequential(*projs) + + def forward(self, x, mask_info): + + x = x.transpose(1, 2) + + residual = x + + for i, layer in enumerate(self.blocks): + x = layer(x) + x = self.add_residual(x, residual, i, mask_info) + residual = x + + x = x.transpose(1, 2) + x = self.proj(x) + return x + + +class Decoder2d(DecoderBase): + def __init__(self, cfg: D2vDecoderConfig, input_dim, h_size, w_size): + super().__init__(cfg) + + self.h_size = h_size + self.w_size = w_size + + def make_block(in_dim): + block = [ + nn.Conv2d( + in_dim, + cfg.decoder_dim, + kernel_size=cfg.decoder_kernel, + padding=cfg.decoder_kernel // 2, + groups=cfg.decoder_groups, + ), + SamePad2d(cfg.decoder_kernel), + TransposeLast(tranpose_dim=-3), + LayerNorm(cfg.decoder_dim, elementwise_affine=False), + TransposeLast(tranpose_dim=-3), + nn.GELU(), + ] + + return nn.Sequential(*block) + + self.blocks = nn.Sequential( + *[ + make_block(input_dim if i == 0 else cfg.decoder_dim) + for i in range(cfg.decoder_layers) + ] + ) + + self.proj = nn.Linear(cfg.decoder_dim, input_dim) + + def forward(self, x, mask_info): + B, T, C = x.shape + + x = x.transpose(1, 2).reshape(B, C, self.h_size, self.w_size) + + residual = x + + for i, layer in enumerate(self.blocks): + x = layer(x) + x = self.add_residual(x, residual, i, mask_info) + residual = x + + x = x.reshape(B, -1, T).transpose(1, 2) + x = self.proj(x) + return x + + +class TransformerDecoder(nn.Module): + decoder_cfg: D2vDecoderConfig + + def __init__(self, cfg: D2vDecoderConfig, input_dim, encoder): + super().__init__() + + self.decoder_cfg = cfg + + self.input_proj = nn.Linear(input_dim, cfg.decoder_dim) + + self.encoder = encoder + + self.proj = nn.Linear(cfg.decoder_dim, input_dim) + + def reset_parameters(self): + from fairseq.modules.transformer_sentence_encoder import init_bert_params + + self.apply(init_bert_params) + + def forward(self, x, mask_info): + x = self.input_proj(x) + x = self.encoder(x, None, None, 1) + x = self.proj(x) + return x + + +class AltBlock(nn.Module): + def __init__( + self, + dim, + num_heads, + mlp_ratio=4.0, + qkv_bias=False, + qk_scale=None, + drop=0.0, + attn_drop=0.0, + mlp_drop=0.0, + post_mlp_drop=0.0, + drop_path=0.0, + act_layer=nn.GELU, + norm_layer=nn.LayerNorm, + layer_norm_first=True, + ffn_targets=False, + cosine_attention=False, + ): + super().__init__() + + self.layer_norm_first = layer_norm_first + self.ffn_targets = ffn_targets + + from timm.models.vision_transformer import DropPath, Mlp + + self.norm1 = norm_layer(dim) + self.attn = AltAttention( + dim, + num_heads=num_heads, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + attn_drop=attn_drop, + proj_drop=drop, + cosine_attention=cosine_attention, + ) + + self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + self.norm2 = norm_layer(dim) + mlp_hidden_dim = int(dim * mlp_ratio) + self.mlp = Mlp( + in_features=dim, + hidden_features=mlp_hidden_dim, + act_layer=act_layer, + drop=mlp_drop, + ) + self.post_mlp_dropout = nn.Dropout(post_mlp_drop, inplace=False) + + def forward(self, x, padding_mask=None, alibi_bias=None): + if self.layer_norm_first: + x = x + self.drop_path(self.attn(self.norm1(x), padding_mask, alibi_bias)) + r = x = self.mlp(self.norm2(x)) + t = x + x = r + self.drop_path(self.post_mlp_dropout(x)) + if not self.ffn_targets: + t = x + else: + x = x + self.drop_path(self.attn(x, padding_mask, alibi_bias)) + r = x = self.norm1(x) + x = self.mlp(x) + t = x + x = self.norm2(r + self.drop_path(self.post_mlp_dropout(x))) + if not self.ffn_targets: + t = x + + return x, t + + +class AltAttention(nn.Module): + def __init__( + self, + dim, + num_heads=8, + qkv_bias=False, + qk_scale=None, + attn_drop=0.0, + proj_drop=0.0, + cosine_attention=False, + ): + super().__init__() + self.num_heads = num_heads + head_dim = dim // num_heads + self.scale = qk_scale or head_dim ** -0.5 + + self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(dim, dim) + self.proj_drop = nn.Dropout(proj_drop) + + self.cosine_attention = cosine_attention + + if cosine_attention: + self.logit_scale = nn.Parameter( + torch.log(10 * torch.ones((num_heads, 1, 1))), requires_grad=True + ) + + def forward(self, x, padding_mask=None, alibi_bias=None): + B, N, C = x.shape + qkv = ( + self.qkv(x) + .reshape(B, N, 3, self.num_heads, C // self.num_heads) + .permute(2, 0, 3, 1, 4) # qkv x B x H x L x D + ) + q, k, v = ( + qkv[0], + qkv[1], + qkv[2], + ) # make torchscript happy (cannot use tensor as tuple) + + dtype = q.dtype + + if self.cosine_attention: + # cosine attention + attn = F.normalize(q, dim=-1) @ F.normalize(k, dim=-1).transpose(-2, -1) + logit_scale = torch.clamp( + self.logit_scale, max=torch.log(torch.tensor(1.0 / 0.01)) + ).exp() + attn = attn * logit_scale + else: + q = q * self.scale + attn = q @ k.transpose(-2, -1) + + if alibi_bias is not None: + attn = attn.type_as(alibi_bias) + attn[:, : alibi_bias.size(1)] += alibi_bias + + if padding_mask is not None and padding_mask.any(): + attn = attn.masked_fill( + padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), + float("-inf"), + ) + + attn = attn.softmax(dim=-1, dtype=torch.float32).to(dtype=dtype) + attn = self.attn_drop(attn) + x = (attn @ v).transpose(1, 2) # + x = x.reshape(B, N, C) + x = self.proj(x) + x = self.proj_drop(x) + return x + + +class EncDecAttention(nn.Module): + def __init__( + self, + q_dim, + kv_dim, + num_heads=8, + qkv_bias=False, + qk_scale=None, + attn_drop=0.0, + proj_drop=0.0, + cosine_attention=False, + ): + super().__init__() + self.num_heads = num_heads + head_dim = q_dim // num_heads + self.scale = qk_scale or head_dim ** -0.5 + + self.q_proj = nn.Linear(q_dim, q_dim, bias=qkv_bias) + self.kv_proj = nn.Linear(kv_dim, 2 * q_dim, bias=qkv_bias) + self.attn_drop = nn.Dropout(attn_drop) + self.proj = nn.Linear(q_dim, q_dim) + self.proj_drop = nn.Dropout(proj_drop) + + self.cosine_attention = cosine_attention + + if cosine_attention: + self.logit_scale = nn.Parameter( + torch.log(10 * torch.ones((num_heads, 1, 1))), requires_grad=True + ) + + def forward(self, q, kv, padding_mask=None, alibi_bias=None): + B, N, C = q.shape + + q = ( + self.q_proj(q) + .reshape(B, N, self.num_heads, C // self.num_heads) + .permute(0, 2, 1, 3) + ) # B x H x L x D + kv = ( + self.kv_proj(kv) + .reshape(B, -1, 2, self.num_heads, C // self.num_heads) + .permute(2, 0, 3, 1, 4) + ) # kv x B x H x L x D + k, v = ( + kv[0], + kv[1], + ) # make torchscript happy (cannot use tensor as tuple) + + dtype = q.dtype + + if self.cosine_attention: + # cosine attention + attn = F.normalize(q, dim=-1) @ F.normalize(k, dim=-1).transpose(-2, -1) + logit_scale = torch.clamp( + self.logit_scale, max=torch.log(torch.tensor(1.0 / 0.01)) + ).exp() + attn = attn * logit_scale + else: + q = q * self.scale + attn = q @ k.transpose(-2, -1) + + if alibi_bias is not None: + attn = attn.type_as(alibi_bias) + attn[:, : alibi_bias.size(1)] += alibi_bias + + if padding_mask is not None and padding_mask.any(): + attn = attn.masked_fill( + padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), + float("-inf"), + ) + + attn = attn.softmax(dim=-1, dtype=torch.float32).to(dtype=dtype) + attn = self.attn_drop(attn) + x = (attn @ v).transpose(1, 2) # + x = x.reshape(B, N, C) + x = self.proj(x) + x = self.proj_drop(x) + return x + + +class EncDecBlock(nn.Module): + def __init__( + self, + q_dim, + kv_dim, + num_heads, + mlp_ratio=4.0, + qkv_bias=False, + qk_scale=None, + drop=0.0, + attn_drop=0.0, + mlp_drop=0.0, + post_mlp_drop=0.0, + drop_path=0.0, + act_layer=nn.GELU, + norm_layer=nn.LayerNorm, + layer_norm_first=True, + cosine_attention=False, + first_residual=True, + ): + super().__init__() + + self.layer_norm_first = layer_norm_first + + from timm.models.vision_transformer import DropPath, Mlp + + self.norm1 = norm_layer(q_dim) + self.attn = EncDecAttention( + q_dim, + kv_dim, + num_heads=num_heads, + qkv_bias=qkv_bias, + qk_scale=qk_scale, + attn_drop=attn_drop, + proj_drop=drop, + cosine_attention=cosine_attention, + ) + + self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity() + self.norm2 = norm_layer(q_dim) + mlp_hidden_dim = int(q_dim * mlp_ratio) + self.mlp = Mlp( + in_features=q_dim, + hidden_features=mlp_hidden_dim, + act_layer=act_layer, + drop=mlp_drop, + ) + self.post_mlp_dropout = nn.Dropout(post_mlp_drop, inplace=False) + self.first_residual = first_residual + + def forward(self, q, kv, padding_mask=None, alibi_bias=None): + r = q if self.first_residual else 0 + if self.layer_norm_first: + x = r + self.drop_path( + self.attn(self.norm1(q), kv, padding_mask, alibi_bias) + ) + r = x = self.mlp(self.norm2(x)) + x = r + self.drop_path(self.post_mlp_dropout(x)) + else: + x = r + self.drop_path(self.attn(q, kv, padding_mask, alibi_bias)) + r = x = self.norm1(x) + x = self.mlp(x) + x = self.norm2(r + self.drop_path(self.post_mlp_dropout(x))) + + return x + + +class EncDecTransformerDecoder(nn.Module): + def __init__(self, cfg: D2vDecoderConfig, input_dim): + super().__init__() + + self.input_proj = nn.Linear(input_dim, cfg.decoder_dim) + + self.blocks = nn.Sequential( + *[ + EncDecBlock( + q_dim=cfg.decoder_dim, + kv_dim=input_dim, + num_heads=8, + mlp_ratio=4.0, + qkv_bias=True, + qk_scale=None, + drop=0.0, + attn_drop=0.0, + mlp_drop=0.0, + post_mlp_drop=0.0, + drop_path=0.0, + act_layer=nn.GELU, + norm_layer=nn.LayerNorm, + layer_norm_first=False, + cosine_attention=False, + first_residual=i > 0, + ) + for i in range(cfg.decoder_layers) + ] + ) + + self.proj = nn.Linear(cfg.decoder_dim, input_dim) + + def reset_parameters(self): + from fairseq.modules.transformer_sentence_encoder import init_bert_params + + self.apply(init_bert_params) + + def forward(self, x, kv): + x = self.input_proj(x) + for i, layer in enumerate(self.blocks): + x = layer(x, kv) + + x = self.proj(x) + return x diff --git a/examples/data2vec/models/modalities/text.py b/examples/data2vec/models/modalities/text.py new file mode 100644 index 0000000000..adfac1ca48 --- /dev/null +++ b/examples/data2vec/models/modalities/text.py @@ -0,0 +1,161 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from dataclasses import dataclass +from functools import partial +from typing import Callable, Dict, Optional + +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +from fairseq.modules import PositionalEmbedding, FairseqDropout, LayerNorm +from fairseq.tasks import FairseqTask +from .base import D2vModalityConfig, ModalitySpecificEncoder, get_alibi_bias +from .modules import BlockEncoder, Decoder1d +from examples.data2vec.data.modality import Modality + + +@dataclass +class D2vTextConfig(D2vModalityConfig): + type: Modality = Modality.TEXT + max_source_positions: int = 512 + learned_pos: bool = True + dropout: float = 0.1 # used for both local_encoder and contextualized encoder. tied with global transformer in data2vec_text + + no_scale_embedding: bool = True + layernorm_embedding: bool = True + no_token_positional_embeddings: bool = False + + +class TextEncoder(ModalitySpecificEncoder): + + modality_cfg: D2vTextConfig + + def __init__( + self, + modality_cfg: D2vTextConfig, + embed_dim: int, + make_block: Callable[[float], nn.ModuleList], + norm_layer: Callable[[int], nn.LayerNorm], + layer_norm_first: bool, + alibi_biases: Dict, + task: Optional[FairseqTask], + ): + self.pad_idx = task.source_dictionary.pad() + self.vocab_size = len(task.source_dictionary) + + local_encoder = TextLocalEncoder( + vocab_size=self.vocab_size, + embed_dim=embed_dim, + max_source_positions=modality_cfg.max_source_positions, + pad_idx=self.pad_idx, + no_scale_embedding=modality_cfg.no_scale_embedding, + layernorm_embedding=modality_cfg.layernorm_embedding, + dropout=modality_cfg.dropout, + no_token_positional_embeddings=modality_cfg.no_token_positional_embeddings, + learned_pos=modality_cfg.learned_pos, + ) + dpr = np.linspace( + modality_cfg.start_drop_path_rate, + modality_cfg.end_drop_path_rate, + modality_cfg.prenet_depth, + ) + context_encoder = BlockEncoder( + nn.ModuleList(make_block(dpr[i]) for i in range(modality_cfg.prenet_depth)), + norm_layer(embed_dim) + if not layer_norm_first and modality_cfg.prenet_depth > 0 + else None, + layer_norm_first, + modality_cfg.prenet_layerdrop, + modality_cfg.prenet_dropout if modality_cfg.prenet_depth > 0 else 0.0, + ) + decoder = ( + Decoder1d(modality_cfg.decoder, embed_dim) + if modality_cfg.decoder is not None + else None + ) + + alibi_bias_fn = partial(get_alibi_bias, alibi_biases=alibi_biases) + + super().__init__( + modality_cfg=modality_cfg, + embed_dim=embed_dim, + local_encoder=local_encoder, + project_features=nn.Identity(), + fixed_positional_encoder=None, + relative_positional_encoder=None, + context_encoder=context_encoder, + decoder=decoder, + get_alibi_bias=alibi_bias_fn, + ) + + def reset_parameters(self): + super().reset_parameters() + + def convert_padding_mask(self, x, padding_mask): + if padding_mask is None or padding_mask.size(1) == x.size(1): + return padding_mask + + diff = self.downsample - padding_mask.size(1) % self.downsample + if 0 < diff < self.downsample: + padding_mask = F.pad(padding_mask, (0, diff), value=True) + + padding_mask = padding_mask.view(padding_mask.size(0), -1, self.downsample) + padding_mask = padding_mask.all(-1) + if padding_mask.size(1) > x.size(1): + padding_mask = padding_mask[:, : x.size(1)] + + assert x.size(1) == padding_mask.size( + 1 + ), f"{x.size(1), padding_mask.size(1), diff, self.downsample}" + + return padding_mask + + +class TextLocalEncoder(nn.Module): + def __init__( + self, + vocab_size, + embed_dim, + max_source_positions, + pad_idx, + no_scale_embedding, + layernorm_embedding, + dropout, + no_token_positional_embeddings, + learned_pos, + ): + super().__init__() + self.pad_idx = pad_idx + self.dropout_module = FairseqDropout(dropout) + + self.embed_tokens = nn.Embedding(vocab_size, embed_dim, pad_idx) + self.embed_scale = 1.0 if no_scale_embedding else math.sqrt(embed_dim) + self.embed_positions = ( + PositionalEmbedding( + max_source_positions, + embed_dim, + pad_idx, + learned=learned_pos, + ) + if not no_token_positional_embeddings + else None + ) + self.embed_scale = 1.0 if no_scale_embedding else math.sqrt(embed_dim) + + self.layernorm_embedding = None + if layernorm_embedding: + self.layernorm_embedding = LayerNorm(embed_dim) + + def forward(self, src_tokens): + x = self.embed_scale * self.embed_tokens(src_tokens) + if self.embed_positions is not None: + x = x + self.embed_positions(src_tokens) + + if self.layernorm_embedding is not None: + x = self.layernorm_embedding(x) + x = self.dropout_module(x) + return x diff --git a/examples/data2vec/models/utils.py b/examples/data2vec/models/utils.py new file mode 100644 index 0000000000..0e2f240d4f --- /dev/null +++ b/examples/data2vec/models/utils.py @@ -0,0 +1,55 @@ +import math +import torch + +def get_alibi( + max_positions: int, + attention_heads: int, +): + def get_slopes(n): + def get_slopes_power_of_2(n): + start = 2 ** (-(2 ** -(math.log2(n) - 3))) + ratio = start + return [start * ratio ** i for i in range(n)] + + # In the paper, we only train models that have 2^a heads for some + # a. This function has some good properties that only occur when + # the input is a power of 2. To maintain that even when the number + # of heads is not a power of 2, we use this workaround. + if math.log2(n).is_integer(): + return get_slopes_power_of_2(n) + else: + closest_power_of_2 = 2 ** math.floor(math.log2(n)) + return ( + get_slopes_power_of_2(closest_power_of_2) + + get_slopes(2 * closest_power_of_2)[0::2][: n - closest_power_of_2] + ) + + maxpos = max_positions + attn_heads = attention_heads + slopes = torch.Tensor(get_slopes(attn_heads)) + # prepare alibi position linear bias. Note that wav2vec2 is non + # autoregressive model so we want a symmetric mask with 0 on the + # diagonal and other wise linear decreasing valuees + pos_bias = ( + torch.abs( + torch.arange(maxpos).unsqueeze(0) - torch.arange(maxpos).unsqueeze(1) + ) + * -1 + ) + alibi_bias = slopes.unsqueeze(1).unsqueeze(1) * pos_bias.unsqueeze(0).expand( + attn_heads, -1, -1 + ) + return alibi_bias + +def masked_alibi(alibi_bias, mask_indices, orig_B, orig_T): + alibi_bias = alibi_bias.view(orig_B, -1, orig_T, orig_T) + H = alibi_bias.size(1) + alibi_mask = mask_indices.unsqueeze(1) + alibi_bias = alibi_bias.masked_select(alibi_mask.unsqueeze(-1)) + alibi_bias = alibi_bias.view(orig_B, H, -1, orig_T) + M = alibi_bias.size(-2) + alibi_bias = alibi_bias.masked_select(alibi_mask.unsqueeze(-2)) + alibi_bias = alibi_bias.view(-1, M, M) + return alibi_bias + + diff --git a/examples/data2vec/scripts/convert_audioset_labels.py b/examples/data2vec/scripts/convert_audioset_labels.py new file mode 100644 index 0000000000..7d720e606a --- /dev/null +++ b/examples/data2vec/scripts/convert_audioset_labels.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import os + + +def get_parser(): + parser = argparse.ArgumentParser(description="convert audioset labels") + # fmt: off + parser.add_argument('in_file', help='audioset csv file to convert') + parser.add_argument('--manifest', required=True, metavar='PATH', help='wav2vec-like manifest') + parser.add_argument('--descriptors', required=True, metavar='PATH', help='path to label descriptor file') + parser.add_argument('--output', required=True, metavar='PATH', help='where to output converted labels') + # fmt: on + + return parser + + +def main(): + parser = get_parser() + args = parser.parse_args() + + label_descriptors = {} + with open(args.descriptors, "r") as ldf: + next(ldf) + for line in ldf: + if line.strip() == "": + continue + + items = line.split(",") + assert len(items) > 2, line + idx = items[0] + lbl = items[1] + assert lbl not in label_descriptors, lbl + label_descriptors[lbl] = idx + + labels = {} + with open(args.in_file, "r") as ifd: + for line in ifd: + if line.lstrip().startswith("#"): + continue + items = line.rstrip().split(",") + id = items[0].strip() + start = items[1].strip() + end = items[2].strip() + lbls = [label_descriptors[it.strip(' "')] for it in items[3:]] + labels[id] = [start, end, ",".join(lbls)] + + with open(args.manifest, "r") as mf, open(args.output, "w") as of: + next(mf) + for line in mf: + path, _ = line.split("\t") + id = os.path.splitext(os.path.basename(path))[0] + lbl = labels[id] + print("\t".join(lbl), file=of) + + +if __name__ == "__main__": + main() diff --git a/examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr.sh b/examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr.sh new file mode 100755 index 0000000000..41bcd31fc5 --- /dev/null +++ b/examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -eu + +job_id="$1" +task_id="$2" +dir="$3" + +echo "job_id: $job_id, task_id: $task_id, dir: $dir" + +mkdir -p "$dir/log" +sbatch_args="-p wav2vec --nodes=1 --ntasks-per-node=1" +sbatch_args="$sbatch_args --gpus-per-node=1 --cpus-per-task=8 --mem=0 --time=24:00:00" +sbatch_args="$sbatch_args -d afterok:$job_id -o $dir/log/decode_sweep_%A.out" +sbatch_args="$sbatch_args -e $dir/log/decode_sweep_%A.err" + +sbatch $sbatch_args examples/data2vec/scripts/multi/finetune_all_fair_local_lr.sh $dir + diff --git a/examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr_nodep.sh b/examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr_nodep.sh new file mode 100644 index 0000000000..fc85908b72 --- /dev/null +++ b/examples/data2vec/scripts/multi/finetune_all_fair_aws_local_lr_nodep.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -eu + +dir="$1" + +echo "dir: $dir" + +mkdir -p "$dir/log" +sbatch_args="-p wav2vec --nodes=1 --ntasks-per-node=1" +sbatch_args="$sbatch_args --gpus-per-node=1 --cpus-per-task=8 --mem=0 --time=24:00:00" +sbatch_args="$sbatch_args -o $dir/log/decode_sweep_%A.out" +sbatch_args="$sbatch_args -e $dir/log/decode_sweep_%A.err" + +sbatch $sbatch_args examples/data2vec/scripts/multi/finetune_all_fair_local_lr.sh $dir + diff --git a/examples/data2vec/scripts/multi/finetune_all_fair_local_lr.sh b/examples/data2vec/scripts/multi/finetune_all_fair_local_lr.sh new file mode 100755 index 0000000000..121226972b --- /dev/null +++ b/examples/data2vec/scripts/multi/finetune_all_fair_local_lr.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" +tasks[mnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MNLI-bin" +tasks[qqp]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QQP-bin" +tasks[sts_b]="/fsx-wav2vec/abaevski/data/nlp/GLUE/STS-B-bin" + +lrs=(5e-6 8e-6 1e-5 2e-5) + +for task data_path in ${(kv)tasks}; do + for lr in $lrs; do + echo $lr $task + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" \ + python fairseq_cli/hydra_train.py -m --config-dir examples/data2vec/config/multi/text_finetuning \ + --config-name $task +run_config=local task.data="$data_path" common.log_interval=200 dataset.num_workers=1 \ + model.model_path="$cp" hydra.sweep.dir="$dir/finetune_lr/$task/$lr" "optimization.lr=[${lr}]" +model=text_wrap + done +done diff --git a/examples/data2vec/scripts/text/finetune_all_char_fair_aws_local_lr.sh b/examples/data2vec/scripts/text/finetune_all_char_fair_aws_local_lr.sh new file mode 100755 index 0000000000..18b862c240 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_char_fair_aws_local_lr.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -eu + +job_id="$1" +task_id="$2" +dir="$3" + +echo "job_id: $job_id, task_id: $task_id, dir: $dir" + +mkdir -p "$dir/log" +sbatch_args="-p wav2vec --nodes=1 --ntasks-per-node=1" +sbatch_args="$sbatch_args --gpus-per-node=1 --cpus-per-task=8 --mem=0 --time=24:00:00" +sbatch_args="$sbatch_args -d afterok:$job_id -o $dir/log/ft_%A.out" +sbatch_args="$sbatch_args -e $dir/log/ft_%A.err" + +sbatch $sbatch_args examples/data2vec/scripts/text/finetune_all_char_fair_local_lr.sh $dir diff --git a/examples/data2vec/scripts/text/finetune_all_fair.sh b/examples/data2vec/scripts/text/finetune_all_fair.sh new file mode 100755 index 0000000000..34a2df3990 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env zsh + +job_id=$1 +task_id=$2 +dir="$3" +cp="$dir/$task_id/checkpoints/checkpoint_last.pt" + +echo "job_id: $job_id, task_id: $task_id, dir: $dir" + +declare -A tasks +tasks[cola]="/private/home/jgu/data/GLUE/CoLA-bin" +tasks[qnli]="/private/home/jgu/data/GLUE/QNLI-bin" +tasks[mrpc]="/private/home/jgu/data/GLUE/MRPC-bin" +tasks[rte]="/private/home/jgu/data/GLUE/RTE-bin" +tasks[sst_2]="/private/home/jgu/data/GLUE/SST-2-bin" + +for task data_path in ${(kv)tasks}; do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" +hydra.launcher.additional_parameters.dependency="afterok:$job_id" hydra.sweep.dir="$dir/finetune/$task" & +done diff --git a/examples/data2vec/scripts/text/finetune_all_fair_aws.sh b/examples/data2vec/scripts/text/finetune_all_fair_aws.sh new file mode 100755 index 0000000000..b417c20024 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_aws.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env zsh + +job_id=$1 +task_id=$2 +dir="$3" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "job_id: $job_id, task_id: $task_id, dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" + +for task data_path in ${(kv)tasks}; do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g_aws task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" +hydra.launcher.additional_parameters.dependency="afterok:$job_id" hydra.sweep.dir="$dir/finetune/$task" & +done diff --git a/examples/data2vec/scripts/text/finetune_all_fair_aws_local_lr.sh b/examples/data2vec/scripts/text/finetune_all_fair_aws_local_lr.sh new file mode 100755 index 0000000000..64dbcb111e --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_aws_local_lr.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -eu + +job_id="$1" +task_id="$2" +dir="$3" + +echo "job_id: $job_id, task_id: $task_id, dir: $dir" + +mkdir -p "$dir/log" +sbatch_args="-p wav2vec --nodes=1 --ntasks-per-node=1" +sbatch_args="$sbatch_args --gpus-per-node=1 --cpus-per-task=8 --mem=0 --time=24:00:00" +sbatch_args="$sbatch_args -d afterok:$job_id -o $dir/log/decode_sweep_%A.out" +sbatch_args="$sbatch_args -e $dir/log/decode_sweep_%A.err" + +sbatch $sbatch_args examples/data2vec/scripts/text/finetune_all_fair_local_lr.sh $dir diff --git a/examples/data2vec/scripts/text/finetune_all_fair_aws_lr.sh b/examples/data2vec/scripts/text/finetune_all_fair_aws_lr.sh new file mode 100755 index 0000000000..d75c549573 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_aws_lr.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env zsh + +job_id=$1 +task_id=$2 +dir="$3" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "job_id: $job_id, task_id: $task_id, dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" + +for task data_path in ${(kv)tasks}; do + for lr in 5e-6 8e-6 1e-5 2e-5 5e-5 8e-5 1e-4 2e-4; do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g_aws task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" +hydra.launcher.additional_parameters.dependency="afterok:$job_id" hydra.sweep.dir="$dir/finetune_lr/$task/$lr" "optimization.lr=[${lr}]" & + done +done diff --git a/examples/data2vec/scripts/text/finetune_all_fair_local_lr.sh b/examples/data2vec/scripts/text/finetune_all_fair_local_lr.sh new file mode 100755 index 0000000000..8be98c0847 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_local_lr.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" + +lrs=(5e-6 8e-6 1e-5 2e-5) + +for task data_path in ${(kv)tasks}; do + for lr in $lrs; do + echo $lr $task + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" \ + python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task +run_config=local task.data="$data_path" common.log_interval=200 dataset.num_workers=1 \ + checkpoint.restore_file="$cp" hydra.sweep.dir="$dir/finetune_lr/$task/$lr" "optimization.lr=[${lr}]" + done +done diff --git a/examples/data2vec/scripts/text/finetune_all_fair_nodep.sh b/examples/data2vec/scripts/text/finetune_all_fair_nodep.sh new file mode 100755 index 0000000000..d02bcc0f75 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_nodep.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[cola]="/private/home/jgu/data/GLUE/CoLA-bin" +tasks[qnli]="/private/home/jgu/data/GLUE/QNLI-bin" +tasks[mrpc]="/private/home/jgu/data/GLUE/MRPC-bin" +tasks[rte]="/private/home/jgu/data/GLUE/RTE-bin" +tasks[sst_2]="/private/home/jgu/data/GLUE/SST-2-bin" + +for task data_path in ${(kv)tasks}; do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" hydra.sweep.dir="$dir/finetune/$task" & +done diff --git a/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws.sh b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws.sh new file mode 100755 index 0000000000..75538354e1 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" + +for task data_path in ${(kv)tasks}; do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g_aws task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" hydra.sweep.dir="$dir/finetune/$task" & +done diff --git a/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_local_lr.sh b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_local_lr.sh new file mode 100755 index 0000000000..16c1358b2f --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_local_lr.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -eu + +dir="$1" + +echo "dir: $dir" + +mkdir -p "$dir/log" +sbatch_args="-p wav2vec --nodes=1 --ntasks-per-node=1" +sbatch_args="$sbatch_args --gpus-per-node=1 --cpus-per-task=8 --mem=0 --time=24:00:00" +sbatch_args="$sbatch_args -o $dir/log/decode_sweep_%A.out" +sbatch_args="$sbatch_args -e $dir/log/decode_sweep_%A.err" + +sbatch $sbatch_args examples/data2vec/scripts/text/finetune_all_fair_local_lr.sh $dir diff --git a/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr.sh b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr.sh new file mode 100755 index 0000000000..fb5ddbe22c --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" + +for task data_path in ${(kv)tasks}; do + for lr in 5e-6 8e-6 1e-5 2e-5 5e-5 8e-5 1e-4 2e-4; do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g_aws task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" hydra.sweep.dir="$dir/finetune_lr/$task/$lr" "optimization.lr=[${lr}]" & + done +done diff --git a/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr_nopos.sh b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr_nopos.sh new file mode 100755 index 0000000000..1ffab1c850 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_fair_nodep_aws_lr_nopos.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" + +for task data_path in ${(kv)tasks}; do + for lr in 5e-6 8e-6 1e-5 2e-5 5e-5 8e-5 1e-4 2e-4; do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g_aws task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" hydra.sweep.dir="$dir/finetune_lr/$task/$lr" "optimization.lr=[${lr}]" +model.encoder_learned_pos=False & + done +done diff --git a/examples/data2vec/scripts/text/finetune_all_large_fair_aws_local_lr.sh b/examples/data2vec/scripts/text/finetune_all_large_fair_aws_local_lr.sh new file mode 100755 index 0000000000..c3c58adcb8 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_large_fair_aws_local_lr.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -eu + +job_id="$1" +task_id="$2" +dir="$3" + +echo "job_id: $job_id, task_id: $task_id, dir: $dir" + +mkdir -p "$dir/log" +sbatch_args="-p wav2vec --nodes=1 --ntasks-per-node=1" +sbatch_args="$sbatch_args --gpus-per-node=1 --cpus-per-task=8 --mem=0 --time=24:00:00" +sbatch_args="$sbatch_args -d afterok:$job_id -o $dir/log/decode_sweep_%A.out" +sbatch_args="$sbatch_args -e $dir/log/decode_sweep_%A.err" + +sbatch $sbatch_args examples/data2vec/scripts/text/finetune_all_large_fair_local_lr.sh $dir diff --git a/examples/data2vec/scripts/text/finetune_all_large_fair_local_lr.sh b/examples/data2vec/scripts/text/finetune_all_large_fair_local_lr.sh new file mode 100644 index 0000000000..5efb00e0df --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_large_fair_local_lr.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[cola]="/fsx-wav2vec/abaevski/data/nlp/GLUE/CoLA-bin" +tasks[qnli]="/fsx-wav2vec/abaevski/data/nlp/GLUE/QNLI-bin" +tasks[mrpc]="/fsx-wav2vec/abaevski/data/nlp/GLUE/MRPC-bin" +tasks[rte]="/fsx-wav2vec/abaevski/data/nlp/GLUE/RTE-bin" +tasks[sst_2]="/fsx-wav2vec/abaevski/data/nlp/GLUE/SST-2-bin" + +lrs=(5e-6 8e-6 1e-5 2e-5) + +for task data_path in ${(kv)tasks}; do + for lr in $lrs; do + echo $lr $task + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" \ + python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task +run_config=local task.data="$data_path" common.log_interval=200 dataset.num_workers=1 \ + checkpoint.restore_file="$cp" hydra.sweep.dir="$dir/finetune_lr/$task/$lr" "optimization.lr=[${lr}]" \ + model._name=roberta_large + done +done diff --git a/examples/data2vec/scripts/text/finetune_all_large_fair_nodep_aws_local_lr.sh b/examples/data2vec/scripts/text/finetune_all_large_fair_nodep_aws_local_lr.sh new file mode 100755 index 0000000000..4fb21bce79 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_all_large_fair_nodep_aws_local_lr.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -eu + +dir="$1" + +echo "dir: $dir" + +mkdir -p "$dir/log" +sbatch_args="-p wav2vec --nodes=1 --ntasks-per-node=1" +sbatch_args="$sbatch_args --gpus-per-node=1 --cpus-per-task=8 --mem=0 --time=24:00:00" +sbatch_args="$sbatch_args -o $dir/log/decode_sweep_%A.out" +sbatch_args="$sbatch_args -e $dir/log/decode_sweep_%A.err" + +sbatch $sbatch_args examples/data2vec/scripts/text/finetune_all_large_fair_local_lr.sh $dir diff --git a/examples/data2vec/scripts/text/finetune_sst2_qnli_sweep_fair_nodep.sh b/examples/data2vec/scripts/text/finetune_sst2_qnli_sweep_fair_nodep.sh new file mode 100755 index 0000000000..d7b43bee80 --- /dev/null +++ b/examples/data2vec/scripts/text/finetune_sst2_qnli_sweep_fair_nodep.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env zsh + +dir="$1" +cp="$dir/checkpoints/checkpoint_last.pt" + +echo "dir: $dir" + +declare -A tasks +tasks[qnli]="/private/home/jgu/data/GLUE/QNLI-bin" +tasks[sst_2]="/private/home/jgu/data/GLUE/SST-2-bin" + +lrs="5e-6 1e-5 2e-5 5e-5 1e-4 2e-4 5e-4 1e-3" + +for task data_path in ${(kv)tasks}; do + for lr in $(echo "$lrs"); do + PYTHONPATH=. PREFIX="${PREFIX}" SUFFIX="" nohup python fairseq_cli/hydra_train.py -m --config-dir examples/roberta/config/finetuning \ + --config-name $task hydra/launcher=submitit_slurm +run_config=slurm_1g task.data="$data_path" hydra.launcher.name=finetune_${task}_${PREFIX} \ + checkpoint.restore_file="$cp" hydra.sweep.dir="$dir/finetune_sweep/$task/lr_$lr" "optimization.lr=[${lr}]" & + done +done diff --git a/examples/data2vec/scripts/text/glue.py b/examples/data2vec/scripts/text/glue.py new file mode 100644 index 0000000000..5382d31834 --- /dev/null +++ b/examples/data2vec/scripts/text/glue.py @@ -0,0 +1,34 @@ +from valids import parser, main as valids_main +import os.path as osp + + +args = parser.parse_args() +args.target = "valid_accuracy" +args.best_biggest = True +args.best = True +args.last = 0 +args.path_contains = None + +res = valids_main(args, print_output=False) + +grouped = {} +for k, v in res.items(): + k = osp.dirname(k) + run = osp.dirname(k) + task = osp.basename(k) + val = v["valid_accuracy"] + + if run not in grouped: + grouped[run] = {} + + grouped[run][task] = val + +for run, tasks in grouped.items(): + print(run) + avg = sum(float(v) for v in tasks.values()) / len(tasks) + avg_norte = sum(float(v) for k,v in tasks.items() if k != 'rte') / (len(tasks) -1) + try: + print(f"{tasks['cola']}\t{tasks['qnli']}\t{tasks['mrpc']}\t{tasks['rte']}\t{tasks['sst_2']}\t{avg:.2f}\t{avg_norte:.2f}") + except: + print(tasks) + print() diff --git a/examples/data2vec/scripts/text/glue_lr.py b/examples/data2vec/scripts/text/glue_lr.py new file mode 100644 index 0000000000..75bdfe0368 --- /dev/null +++ b/examples/data2vec/scripts/text/glue_lr.py @@ -0,0 +1,143 @@ +import os.path as osp +import re +from collections import defaultdict + +from valids import parser, main as valids_main + + +TASK_TO_METRIC = { + "cola": "mcc", + "qnli": "accuracy", + "mrpc": "acc_and_f1", + "rte": "accuracy", + "sst_2": "accuracy", + "mnli": "accuracy", + "qqp": "acc_and_f1", + "sts_b": "pearson_and_spearman", +} +TASKS = ["cola", "qnli", "mrpc", "rte", "sst_2", "mnli", "qqp", "sts_b"] + + +def get_best_stat_str(task_vals, show_subdir): + task_to_best_val = {} + task_to_best_dir = {} + for task, subdir_to_val in task_vals.items(): + task_to_best_val[task] = max(subdir_to_val.values()) + task_to_best_dir[task] = max(subdir_to_val.keys(), key=lambda x: subdir_to_val[x]) + + # import pdb; pdb.set_trace() + N1 = len(task_to_best_val) + N2 = len([k for k in task_to_best_val if k != "rte"]) + avg1 = sum(task_to_best_val.values()) / N1 + avg2 = sum(v for task, v in task_to_best_val.items() if task != "rte") / N2 + + try: + msg = "" + for task in TASKS: + dir = task_to_best_dir.get(task, 'null') + val = task_to_best_val.get(task, -100) + msg += f"({dir}, {val})\t" if show_subdir else f"{val}\t" + msg += f"{avg1:.2f}\t{avg2:.2f}" + except Exception as e: + msg = str(e) + msg += str(sorted(task_vals.items())) + return msg + +def get_all_stat_str(task_vals): + msg = "" + for task in [task for task in TASKS if task in task_vals]: + msg += f"=== {task}\n" + for subdir in sorted(task_vals[task].keys()): + msg += f"\t{subdir}\t{task_vals[task][subdir]}\n" + return msg + +def get_tabular_stat_str(task_vals): + """assume subdir is <param>/run_*/0""" + msg = "" + for task in [task for task in TASKS if task in task_vals]: + msg += f"=== {task}\n" + param_to_runs = defaultdict(dict) + for subdir in task_vals[task]: + match = re.match("(.*)/(run_.*)/0", subdir) + assert match, "subdir" + param, run = match.groups() + param_to_runs[param][run] = task_vals[task][subdir] + params = sorted(param_to_runs, key=lambda x: float(x)) + runs = sorted(set(run for runs in param_to_runs.values() for run in runs)) + msg += ("runs:" + "\t".join(runs) + "\n") + msg += ("params:" + "\t".join(params) + "\n") + for param in params: + msg += "\t".join([str(param_to_runs[param].get(run, None)) for run in runs]) + msg += "\n" + # for subdir in sorted(task_vals[task].keys()): + # msg += f"\t{subdir}\t{task_vals[task][subdir]}\n" + return msg + + + +def main(): + parser.add_argument("--show_glue", action="store_true", help="show glue metric for each task instead of accuracy") + parser.add_argument("--print_mode", default="best", help="best|all|tabular") + parser.add_argument("--show_subdir", action="store_true", help="print the subdir that has the best results for each run") + parser.add_argument("--override_target", default="valid_accuracy", help="override target") + + args = parser.parse_args() + args.target = args.override_target + args.best_biggest = True + args.best = True + args.last = 0 + args.path_contains = None + + res = valids_main(args, print_output=False) + grouped_acc = {} + grouped_met = {} # use official metric for each task + for path, v in res.items(): + path = "/".join([args.base, path]) + path = re.sub("//*", "/", path) + match = re.match("(.*)finetune[^/]*/([^/]*)/(.*)", path) + if not match: + continue + run, task, subdir = match.groups() + + if run not in grouped_acc: + grouped_acc[run] = {} + grouped_met[run] = {} + if task not in grouped_acc[run]: + grouped_acc[run][task] = {} + grouped_met[run][task] = {} + + if v is not None: + grouped_acc[run][task][subdir] = float(v.get("valid_accuracy", -100)) + grouped_met[run][task][subdir] = float(v.get(f"valid_{TASK_TO_METRIC[task]}", -100)) + else: + print(f"{path} has None return") + + header = "\t".join(TASKS) + for run in sorted(grouped_acc): + print(run) + if args.print_mode == "all": + if args.show_glue: + print("===== GLUE =====") + print(get_all_stat_str(grouped_met[run])) + else: + print("===== ACC =====") + print(get_all_stat_str(grouped_acc[run])) + elif args.print_mode == "best": + print(f" {header}") + if args.show_glue: + print(f"GLEU: {get_best_stat_str(grouped_met[run], args.show_subdir)}") + else: + print(f"ACC: {get_best_stat_str(grouped_acc[run], args.show_subdir)}") + elif args.print_mode == "tabular": + if args.show_glue: + print("===== GLUE =====") + print(get_tabular_stat_str(grouped_met[run])) + else: + print("===== ACC =====") + print(get_tabular_stat_str(grouped_acc[run])) + else: + raise ValueError(args.print_mode) + print() + +if __name__ == "__main__": + main() diff --git a/examples/data2vec/scripts/text/unprocess_data.py b/examples/data2vec/scripts/text/unprocess_data.py new file mode 100644 index 0000000000..f1acb624b8 --- /dev/null +++ b/examples/data2vec/scripts/text/unprocess_data.py @@ -0,0 +1,188 @@ +import json +import os +import tqdm +from fairseq.data import Dictionary, data_utils + + +def load_dictionary(dict_path): + return Dictionary.load(dict_path) + +def load_dataset(split_path, src_dict): + dataset = data_utils.load_indexed_dataset( + split_path, + src_dict, + combine=False, # set to true for loading `train*` + ) + if dataset is None: + raise FileNotFoundError(f"Dataset not found: {split_path}") + return dataset + +def load_bpe(enc_path): + with open(enc_path) as f: + bpe2idx = json.load(f) + idx2bpe = {v: k for k, v in bpe2idx.items()} + return bpe2idx, idx2bpe + +def detokenize(tokens, src_dict, idx2bpe): + raw_inds = map(int, src_dict.string(tokens).split()) + raw_chrs = "".join([idx2bpe[raw_ind] for raw_ind in raw_inds]) + raw_chrs = raw_chrs.replace("\u0120", " ") + return raw_chrs + +def _main(src_root, src_dict_path, src_bpe_path, src_splits, tgt_root, tgt_splits): + src_dict = load_dictionary(src_dict_path) + bpe2idx, idx2bpe = load_bpe(src_bpe_path) + + assert len(src_splits) == len(tgt_splits) + for src_split, tgt_split in zip(src_splits, tgt_splits): + src_dataset = load_dataset(f"{src_root}/{src_split}", src_dict) + tgt_path = f"{tgt_root}/{tgt_split}.txt" + print(f"processing {src_split} (dump to {tgt_path})...") + os.makedirs(os.path.dirname(tgt_path), exist_ok=True) + with open(tgt_path, "w") as f: + for tokens in tqdm.tqdm(src_dataset): + raw_str = detokenize(tokens, src_dict, idx2bpe) + f.write(raw_str + "\n") + +def main_pt(): + src_root = "/datasets01/bookwiki_CC-NEWS_openwebtext_stories-mmap2-bin/121219/bookwiki_CC-NEWS_openwebtext_stories-mmap2-bin" + src_dict_path = f"{src_root}/dict.txt" + src_bpe_path = f"{src_root}/encoder.json" + src_splits = [ + "bookwiki_aml-mmap2-bin/shard0/train", + "bookwiki_aml-mmap2-bin/shard1/train", + "bookwiki_aml-mmap2-bin/shard2/train", + "bookwiki_aml-mmap2-bin/shard3/train", + "bookwiki_aml-mmap2-bin/shard4/train", + "bookwiki_aml-mmap2-bin/valid/valid", + ] + + tgt_root = "/checkpoint/wnhsu/data/data2vec2/data/text/bookwiki_aml-full-mmap2-txt" + tgt_splits = [ + "train0", + "train1", + "train2", + "train3", + "train4", + "valid", + ] + _main(src_root, src_dict_path, src_bpe_path, src_splits, tgt_root, tgt_splits) + +def main_ft(): + src_root = "/fsx-wav2vec/wnhsu/data/data2vec2/data/text/GLUE" + src_dict_path = f"{src_root}/dict.txt" + src_bpe_path = f"{src_root}/encoder.json" + src_splits = [ + "CoLA-bin/input0/train", + "CoLA-bin/input0/valid", + "CoLA-bin/input0/test", + + "MNLI-bin/input0/train", + "MNLI-bin/input0/valid", + "MNLI-bin/input0/test", + "MNLI-bin/input0/test1", + "MNLI-bin/input1/train", + "MNLI-bin/input1/valid", + "MNLI-bin/input1/test", + "MNLI-bin/input1/test1", + + "MRPC-bin/input0/train", + "MRPC-bin/input0/valid", + "MRPC-bin/input0/test", + "MRPC-bin/input1/train", + "MRPC-bin/input1/valid", + "MRPC-bin/input1/test", + + "QNLI-bin/input0/train", + "QNLI-bin/input0/valid", + "QNLI-bin/input0/test", + "QNLI-bin/input1/train", + "QNLI-bin/input1/valid", + "QNLI-bin/input1/test", + + "QQP-bin/input0/train", + "QQP-bin/input0/valid", + "QQP-bin/input0/test", + "QQP-bin/input1/train", + "QQP-bin/input1/valid", + "QQP-bin/input1/test", + + "RTE-bin/input0/train", + "RTE-bin/input0/valid", + "RTE-bin/input0/test", + "RTE-bin/input1/train", + "RTE-bin/input1/valid", + "RTE-bin/input1/test", + + "SST-2-bin/input0/train", + "SST-2-bin/input0/valid", + "SST-2-bin/input0/test", + + "STS-B-bin/input0/train", + "STS-B-bin/input0/valid", + "STS-B-bin/input0/test", + "STS-B-bin/input1/train", + "STS-B-bin/input1/valid", + "STS-B-bin/input1/test", + ] + + tgt_root = "/fsx-wav2vec/wnhsu/data/data2vec2/data/text/GLUE_chr" + tgt_splits = [ + "CoLA-bin/input0/train", + "CoLA-bin/input0/valid", + "CoLA-bin/input0/test", + + "MNLI-bin/input0/train", + "MNLI-bin/input0/valid", + "MNLI-bin/input0/test", + "MNLI-bin/input0/test1", + "MNLI-bin/input1/train", + "MNLI-bin/input1/valid", + "MNLI-bin/input1/test", + "MNLI-bin/input1/test1", + + "MRPC-bin/input0/train", + "MRPC-bin/input0/valid", + "MRPC-bin/input0/test", + "MRPC-bin/input1/train", + "MRPC-bin/input1/valid", + "MRPC-bin/input1/test", + + "QNLI-bin/input0/train", + "QNLI-bin/input0/valid", + "QNLI-bin/input0/test", + "QNLI-bin/input1/train", + "QNLI-bin/input1/valid", + "QNLI-bin/input1/test", + + "QQP-bin/input0/train", + "QQP-bin/input0/valid", + "QQP-bin/input0/test", + "QQP-bin/input1/train", + "QQP-bin/input1/valid", + "QQP-bin/input1/test", + + "RTE-bin/input0/train", + "RTE-bin/input0/valid", + "RTE-bin/input0/test", + "RTE-bin/input1/train", + "RTE-bin/input1/valid", + "RTE-bin/input1/test", + + "SST-2-bin/input0/train", + "SST-2-bin/input0/valid", + "SST-2-bin/input0/test", + + "STS-B-bin/input0/train", + "STS-B-bin/input0/valid", + "STS-B-bin/input0/test", + "STS-B-bin/input1/train", + "STS-B-bin/input1/valid", + "STS-B-bin/input1/test", + ] + _main(src_root, src_dict_path, src_bpe_path, src_splits, tgt_root, tgt_splits) + + +if __name__ == "__main__": + main_pt() + main_ft() diff --git a/examples/data2vec/scripts/text/valids.py b/examples/data2vec/scripts/text/valids.py new file mode 100644 index 0000000000..b2e5cfb25d --- /dev/null +++ b/examples/data2vec/scripts/text/valids.py @@ -0,0 +1,301 @@ +import os, argparse, re, json, copy, math +from collections import OrderedDict +import numpy as np + +parser = argparse.ArgumentParser(description='Process some integers.') +parser.add_argument('base', help='base log path') +parser.add_argument('--file_name', default='train.log', help='the log file name') +parser.add_argument('--target', default='valid_loss', help='target metric') +parser.add_argument('--last', type=int, default=999999999, help='print last n matches') +parser.add_argument('--last_files', type=int, default=None, help='print last x files') +parser.add_argument('--everything', action='store_true', help='print everything instead of only last match') +parser.add_argument('--path_contains', help='only consider matching file pattern') +parser.add_argument('--group_on', help='if set, groups by this metric and shows table of differences') +parser.add_argument('--epoch', help='epoch for comparison', type=int) +parser.add_argument('--skip_empty', action='store_true', help='skip empty results') +parser.add_argument('--skip_containing', help='skips entries containing this attribute') +parser.add_argument('--unique_epochs', action='store_true', help='only consider the last line fore each epoch') +parser.add_argument('--best', action='store_true', help='print the last best result') +parser.add_argument('--avg_params', help='average these params through entire log') +parser.add_argument('--extract_prev', help='extracts this metric from previous line') + +parser.add_argument('--remove_metric', help='extracts this metric from previous line') + +parser.add_argument('--compact', action='store_true', help='if true, just prints checkpoint <tab> best val') +parser.add_argument('--hydra', action='store_true', help='if true, uses hydra param conventions') + +parser.add_argument('--best_biggest', action='store_true', help='if true, best is the biggest number, not smallest') +parser.add_argument('--key_len', type=int, default=10, help='max length of key') + +parser.add_argument('--best_only', action='store_true', help='if set, only prints the best value') +parser.add_argument('--flat', action='store_true', help='just print the best results') + + +def main(args, print_output): + ret = {} + + entries = [] + + def extract_metric(s, metric): + try: + j = json.loads(s) + except: + return None + if args.epoch is not None and ('epoch' not in j or j['epoch'] != args.epoch): + return None + return j[metric] if metric in j else None + + + def extract_params(s): + s = s.replace(args.base, '', 1) + if args.path_contains is not None: + s = s.replace(args.path_contains, '', 1) + + if args.hydra: + num_matches = re.findall(r'(?:/|__)([^/:]+):(\d+\.?\d*)', s) + # str_matches = re.findall(r'(?:/|__)([^/:]+):([^\.]*[^\d\.]+)(?:/|__)', s) + str_matches = re.findall(r'(?:/|__)?((?:(?!(?:\:|__)).)+):([^\.]*[^\d\.]+\d*)(?:/|__)', s) + lr_matches = re.findall(r'optimization.(lr):\[([\d\.,]+)\]', s) + task_matches = re.findall(r'.*/(\d+)$', s) + else: + num_matches = re.findall(r'\.?([^\.]+?)(\d+(e\-\d+)?(?:\.\d+)?)(\.|$)', s) + str_matches = re.findall(r'[/\.]([^\.]*[^\d\.]+\d*)(?=\.)', s) + lr_matches = [] + task_matches = [] + + cp_matches = re.findall(r'checkpoint(?:_\d+)?_(\d+).pt', s) + + items = OrderedDict() + for m in str_matches: + if isinstance(m, tuple): + if 'checkpoint' not in m[0]: + items[m[0]] = m[1] + else: + items[m] = '' + + for m in num_matches: + items[m[0]] = m[1] + + for m in lr_matches: + items[m[0]] = m[1] + + for m in task_matches: + items["hydra_task"] = m + + for m in cp_matches: + items['checkpoint'] = m + + return items + + abs_best = None + + sources = [] + for root, _, files in os.walk(args.base): + if args.path_contains is not None and not args.path_contains in root: + continue + for f in files: + if f.endswith(args.file_name): + sources.append((root, f)) + + if args.last_files is not None: + sources = sources[-args.last_files:] + + for root, file in sources: + with open(os.path.join(root, file), 'r') as fin: + found = [] + avg = {} + prev = None + for line in fin: + line = line.rstrip() + if line.find(args.target) != -1 and ( + args.skip_containing is None or line.find(args.skip_containing) == -1): + try: + idx = line.index("{") + line = line[idx:] + line_json = json.loads(line) + except: + continue + if prev is not None: + try: + prev.update(line_json) + line_json = prev + except: + pass + if args.target in line_json: + found.append(line_json) + if args.avg_params: + avg_params = args.avg_params.split(',') + for p in avg_params: + m = extract_metric(line, p) + if m is not None: + prev_v, prev_c = avg.get(p, (0, 0)) + avg[p] = prev_v + float(m), prev_c + 1 + if args.extract_prev: + try: + prev = json.loads(line) + except: + pass + best = None + if args.best: + curr_best = None + for i in range(len(found)): + cand_best = found[i][args.target] if args.target in found[i] else None + + def cmp(a, b): + a = float(a) + b = float(b) + if args.best_biggest: + return a > b + return a < b + + if cand_best is not None and not math.isnan(float(cand_best)) and ( + curr_best is None or cmp(cand_best, curr_best)): + curr_best = cand_best + if abs_best is None or cmp(curr_best, abs_best): + abs_best = curr_best + best = found[i] + if args.unique_epochs or args.epoch: + last_found = [] + last_epoch = None + for i in reversed(range(len(found))): + epoch = found[i]['epoch'] + if args.epoch and args.epoch != epoch: + continue + if epoch != last_epoch: + last_epoch = epoch + last_found.append(found[i]) + found = list(reversed(last_found)) + + if len(found) == 0: + if print_output and (args.last_files is not None or not args.skip_empty): + # print(root.split('/')[-1]) + print(root[len(args.base):]) + print('Nothing') + else: + if not print_output: + ret[root[len(args.base):]] = best + continue + + if args.compact: + # print('{}\t{}'.format(root.split('/')[-1], curr_best)) + print('{}\t{}'.format(root[len(args.base)+1:], curr_best)) + continue + + if args.group_on is None and not args.best_only: + # print(root.split('/')[-1]) + print(root[len(args.base):]) + if not args.everything: + if best is not None and args.group_on is None and not args.best_only and not args.flat: + print(best, '(best)') + if args.group_on is None and args.last and not args.best_only and not args.flat: + for f in found[-args.last:]: + if args.extract_prev is not None: + try: + print('{}\t{}'.format(f[args.extract_prev], f[args.target])) + except Exception as e: + print('Exception!', e) + else: + print(f) + try: + metric = found[-1][args.target] if not args.best or best is None else best[args.target] + except: + print(found[-1]) + raise + if metric is not None: + entries.append((extract_params(root), metric)) + else: + for f in found: + print(f) + if not args.group_on and print_output: + print() + + if len(avg) > 0: + for k, (v, c) in avg.items(): + print(f'{k}: {v/c}') + + if args.best_only: + print(abs_best) + + if args.flat: + print("\t".join(m for _, m in entries)) + + if args.group_on is not None: + by_val = OrderedDict() + for e, m in entries: + k = args.group_on + if k not in e: + m_keys = [x for x in e.keys() if x.startswith(k)] + if len(m_keys) == 0: + val = "False" + else: + assert len(m_keys) == 1 + k = m_keys[0] + val = m_keys[0] + else: + val = e[args.group_on] + if val == "": + val = "True" + scrubbed_entry = copy.deepcopy(e) + if k in scrubbed_entry: + del scrubbed_entry[k] + if args.remove_metric and args.remove_metric in scrubbed_entry: + val += '_' + scrubbed_entry[args.remove_metric] + del scrubbed_entry[args.remove_metric] + by_val.setdefault(tuple(scrubbed_entry.items()), dict())[val] = m + distinct_vals = set() + for v in by_val.values(): + distinct_vals.update(v.keys()) + try: + distinct_vals = {int(d) for d in distinct_vals} + except: + print(distinct_vals) + print() + print("by_val", len(by_val)) + for k,v in by_val.items(): + print(k, '=>', v) + print() + + # , by_val, entries) + raise + from natsort import natsorted + svals = list(map(str, natsorted(distinct_vals))) + print('{}\t{}'.format(args.group_on, '\t'.join(svals))) + sums = OrderedDict({n:[] for n in svals}) + for k, v in by_val.items(): + kstr = '.'.join(':'.join(x) for x in k) + vstr = '' + for mv in svals: + x = v[mv] if mv in v else '' + vstr += '\t{}'.format(round(x, 5) if isinstance(x, float) else x) + try: + sums[mv].append(float(x)) + except: + pass + print('{}{}'.format(kstr[:args.key_len], vstr)) + if any(len(x) > 0 for x in sums.values()): + print('min:', end='') + for v in sums.values(): + min = np.min(v) + print(f'\t{round(min, 5)}', end='') + print() + print('max:', end='') + for v in sums.values(): + max = np.max(v) + print(f'\t{round(max, 5)}', end='') + print() + print('avg:', end='') + for v in sums.values(): + mean = np.mean(v) + print(f'\t{round(mean, 5)}', end='') + print() + print('median:', end='') + for v in sums.values(): + median = np.median(v) + print(f'\t{round(median, 5)}', end='') + print() + + return ret + +if __name__ == "__main__": + args = parser.parse_args() + main(args, print_output=True) \ No newline at end of file diff --git a/examples/data2vec/tasks/__init__.py b/examples/data2vec/tasks/__init__.py new file mode 100644 index 0000000000..a7422e4b30 --- /dev/null +++ b/examples/data2vec/tasks/__init__.py @@ -0,0 +1,18 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .image_pretraining import ImagePretrainingTask, ImagePretrainingConfig +from .image_classification import ImageClassificationTask, ImageClassificationConfig +from .mae_image_pretraining import MaeImagePretrainingTask, MaeImagePretrainingConfig + + +__all__ = [ + "ImageClassificationTask", + "ImageClassificationConfig", + "ImagePretrainingTask", + "ImagePretrainingConfig", + "MaeImagePretrainingTask", + "MaeImagePretrainingConfig", +] \ No newline at end of file diff --git a/examples/data2vec/tasks/audio_classification.py b/examples/data2vec/tasks/audio_classification.py new file mode 100644 index 0000000000..2925a04cf9 --- /dev/null +++ b/examples/data2vec/tasks/audio_classification.py @@ -0,0 +1,167 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import os +import numpy as np +import math +import torch + +from sklearn import metrics as sklearn_metrics +from dataclasses import dataclass + +from fairseq.tasks.audio_pretraining import AudioPretrainingTask, AudioPretrainingConfig +from fairseq.tasks import register_task +from fairseq.logging import metrics + +from ..data.add_class_target_dataset import AddClassTargetDataset + + +logger = logging.getLogger(__name__) + + +@dataclass +class AudioClassificationConfig(AudioPretrainingConfig): + label_descriptors: str = "label_descriptors.csv" + labels: str = "lbl" + + +@register_task("audio_classification", dataclass=AudioClassificationConfig) +class AudioClassificationTask(AudioPretrainingTask): + """ """ + + cfg: AudioClassificationConfig + + def __init__( + self, + cfg: AudioClassificationConfig, + ): + super().__init__(cfg) + + self.state.add_factory("labels", self.load_labels) + + def load_labels(self): + labels = {} + path = os.path.join(self.cfg.data, self.cfg.label_descriptors) + with open(path, "r") as ldf: + for line in ldf: + if line.strip() == "": + continue + items = line.split(",") + idx = items[0] + lbl = items[1] + assert lbl not in labels, lbl + labels[lbl] = idx + return labels + + @property + def labels(self): + return self.state.labels + + def load_dataset( + self, split: str, task_cfg: AudioClassificationConfig = None, **kwargs + ): + super().load_dataset(split, task_cfg, **kwargs) + + task_cfg = task_cfg or self.cfg + + data_path = self.cfg.data + label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") + skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) + labels = [] + with open(label_path, "r") as f: + for i, line in enumerate(f): + if i not in skipped_indices: + lbl_items = line.rstrip().split("\t") + labels.append([int(x) for x in lbl_items[2].split(",")]) + + assert len(labels) == len(self.datasets[split]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.datasets[split])}) do not match" + ) + + self.datasets[split] = AddClassTargetDataset( + self.datasets[split], + labels, + multi_class=True, + add_to_input=True, + num_classes=len(self.labels), + ) + + def calculate_stats(self, output, target): + + classes_num = target.shape[-1] + stats = [] + + # Accuracy, only used for single-label classification such as esc-50, not for multiple label one such as AudioSet + # acc = sklearn_metrics.accuracy_score(np.argmax(target, 1), np.argmax(output, 1)) + + # Class-wise statistics + for k in range(classes_num): + # Average precision + avg_precision = sklearn_metrics.average_precision_score( + target[:, k], output[:, k], average=None + ) + + dict = { + "AP": avg_precision, + } + + # # AUC + # try: + # auc = sklearn_metrics.roc_auc_score(target[:, k], output[:, k], average=None) + # except: + # auc = 0 + # + # # Precisions, recalls + # (precisions, recalls, thresholds) = sklearn_metrics.precision_recall_curve( + # target[:, k], output[:, k] + # ) + # + # # FPR, TPR + # (fpr, tpr, thresholds) = sklearn_metrics.roc_curve(target[:, k], output[:, k]) + # + # save_every_steps = 1000 # Sample statistics to reduce size + # dict = { + # "precisions": precisions[0::save_every_steps], + # "recalls": recalls[0::save_every_steps], + # "AP": avg_precision, + # "fpr": fpr[0::save_every_steps], + # "fnr": 1.0 - tpr[0::save_every_steps], + # "auc": auc, + # # note acc is not class-wise, this is just to keep consistent with other metrics + # "acc": acc, + # } + stats.append(dict) + + return stats + + def valid_step(self, sample, model, criterion): + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + return loss, sample_size, logging_output + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + if "_predictions" in logging_outputs[0]: + metrics.log_concat_tensor( + "_predictions", + torch.cat([l["_predictions"].cpu() for l in logging_outputs], dim=0), + ) + metrics.log_concat_tensor( + "_targets", + torch.cat([l["_targets"].cpu() for l in logging_outputs], dim=0), + ) + + def compute_stats(meters): + if meters["_predictions"].tensor.shape[0] < 100: + return 0 + stats = self.calculate_stats( + meters["_predictions"].tensor, meters["_targets"].tensor + ) + return np.nanmean([stat["AP"] for stat in stats]) + + metrics.log_derived("mAP", compute_stats) diff --git a/examples/data2vec/tasks/image_classification.py b/examples/data2vec/tasks/image_classification.py new file mode 100644 index 0000000000..1ea4c2afee --- /dev/null +++ b/examples/data2vec/tasks/image_classification.py @@ -0,0 +1,129 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import os.path as osp +import logging + +from dataclasses import dataclass +import torch +from torchvision import transforms + +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import register_task +from fairseq.logging import metrics + +try: + from ..data import ImageDataset +except: + import sys + + sys.path.append("..") + from data import ImageDataset + +from .image_pretraining import ( + ImagePretrainingConfig, + ImagePretrainingTask, + IMG_EXTENSIONS, +) + +logger = logging.getLogger(__name__) + + +@dataclass +class ImageClassificationConfig(ImagePretrainingConfig): + pass + + +@register_task("image_classification", dataclass=ImageClassificationConfig) +class ImageClassificationTask(ImagePretrainingTask): + + cfg: ImageClassificationConfig + + @classmethod + def setup_task(cls, cfg: ImageClassificationConfig, **kwargs): + return cls(cfg) + + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + data_path = self.cfg.data + cfg = task_cfg or self.cfg + + path_with_split = osp.join(data_path, split) + if osp.exists(path_with_split): + data_path = path_with_split + + from timm.data import create_transform + + if split == "train": + # this should always dispatch to transforms_imagenet_train + transform = create_transform( + input_size=cfg.input_size, + is_training=True, + auto_augment="rand-m9-mstd0.5-inc1", + interpolation="bicubic", + re_prob=0.25, + re_mode="pixel", + re_count=1, + mean=cfg.normalization_mean, + std=cfg.normalization_std, + ) + if not cfg.input_size > 32: + transform.transforms[0] = transforms.RandomCrop( + cfg.input_size, padding=4 + ) + else: + t = [] + if cfg.input_size > 32: + crop_pct = 1 + if cfg.input_size < 384: + crop_pct = 224 / 256 + size = int(cfg.input_size / crop_pct) + t.append( + transforms.Resize( + size, interpolation=3 + ), # to maintain same ratio w.r.t. 224 images + ) + t.append(transforms.CenterCrop(cfg.input_size)) + + t.append(transforms.ToTensor()) + t.append( + transforms.Normalize(cfg.normalization_mean, cfg.normalization_std) + ) + transform = transforms.Compose(t) + logger.info(transform) + + self.datasets[split] = ImageDataset( + root=data_path, + extensions=IMG_EXTENSIONS, + load_classes=True, + transform=transform, + ) + for k in self.datasets.keys(): + if k != split: + assert self.datasets[k].classes == self.datasets[split].classes + + def build_model(self, model_cfg: FairseqDataclass, from_checkpoint=False): + model = super().build_model(model_cfg, from_checkpoint) + + actualized_cfg = getattr(model, "cfg", None) + if actualized_cfg is not None: + if hasattr(actualized_cfg, "pretrained_model_args"): + model_cfg.pretrained_model_args = actualized_cfg.pretrained_model_args + + return model + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + if "correct" in logging_outputs[0]: + zero = torch.scalar_tensor(0.0) + correct = sum(log.get("correct", zero) for log in logging_outputs) + metrics.log_scalar_sum("_correct", correct) + + metrics.log_derived( + "accuracy", + lambda meters: 100 * meters["_correct"].sum / meters["sample_size"].sum, + ) diff --git a/examples/data2vec/tasks/image_pretraining.py b/examples/data2vec/tasks/image_pretraining.py new file mode 100644 index 0000000000..cd688fd136 --- /dev/null +++ b/examples/data2vec/tasks/image_pretraining.py @@ -0,0 +1,110 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import sys +import os.path as osp + +from dataclasses import dataclass, field +from typing import List +from omegaconf import MISSING + +import torch +from torchvision import transforms + +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task + +try: + from ..data import ImageDataset +except: + sys.path.append("..") + from data import ImageDataset + +logger = logging.getLogger(__name__) + +IMG_EXTENSIONS = { + ".jpg", + ".jpeg", + ".png", + ".ppm", + ".bmp", + ".pgm", + ".tif", + ".tiff", + ".webp", +} + + +@dataclass +class ImagePretrainingConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) + input_size: int = 224 + normalization_mean: List[float] = (0.485, 0.456, 0.406) + normalization_std: List[float] = (0.229, 0.224, 0.225) + + +@register_task("image_pretraining", dataclass=ImagePretrainingConfig) +class ImagePretrainingTask(FairseqTask): + """ """ + + cfg: ImagePretrainingConfig + + @classmethod + def setup_task(cls, cfg: ImagePretrainingConfig, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + cfg (AudioPretrainingConfig): configuration of this task + """ + + return cls(cfg) + + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + data_path = self.cfg.data + cfg = task_cfg or self.cfg + + path_with_split = osp.join(data_path, split) + if osp.exists(path_with_split): + data_path = path_with_split + + transform = transforms.Compose( + [ + transforms.ColorJitter(0.4, 0.4, 0.4), + transforms.RandomHorizontalFlip(p=0.5), + transforms.RandomResizedCrop( + size=cfg.input_size, + interpolation=transforms.InterpolationMode.BICUBIC, + ), + transforms.ToTensor(), + transforms.Normalize( + mean=torch.tensor(cfg.normalization_mean), + std=torch.tensor(cfg.normalization_std), + ), + ] + ) + + logger.info(transform) + + self.datasets[split] = ImageDataset( + root=data_path, + extensions=IMG_EXTENSIONS, + load_classes=False, + transform=transform, + ) + + @property + def source_dictionary(self): + return None + + @property + def target_dictionary(self): + return None + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return sys.maxsize, sys.maxsize diff --git a/examples/data2vec/tasks/mae_image_classification.py b/examples/data2vec/tasks/mae_image_classification.py new file mode 100644 index 0000000000..1bf935879f --- /dev/null +++ b/examples/data2vec/tasks/mae_image_classification.py @@ -0,0 +1,100 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import sys +import torch + +from typing import Optional +from dataclasses import dataclass, field +from omegaconf import MISSING + +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task +from fairseq.logging import metrics + +try: + from ..data import MaeFinetuningImageDataset +except: + sys.path.append("..") + from data import MaeFinetuningImageDataset + +logger = logging.getLogger(__name__) + + +@dataclass +class MaeImageClassificationConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) + input_size: int = 224 + local_cache_path: Optional[str] = None + + rebuild_batches: bool = True + + +@register_task("mae_image_classification", dataclass=MaeImageClassificationConfig) +class MaeImageClassificationTask(FairseqTask): + """ """ + + cfg: MaeImageClassificationConfig + + @classmethod + def setup_task(cls, cfg: MaeImageClassificationConfig, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + cfg (AudioPretrainingConfig): configuration of this task + """ + + return cls(cfg) + + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + data_path = self.cfg.data + cfg = task_cfg or self.cfg + + self.datasets[split] = MaeFinetuningImageDataset( + root=data_path, + split=split, + is_train=split == "train", + input_size=cfg.input_size, + local_cache_path=cfg.local_cache_path, + shuffle=split == "train", + ) + + def build_model(self, model_cfg: FairseqDataclass, from_checkpoint=False): + model = super().build_model(model_cfg, from_checkpoint) + + actualized_cfg = getattr(model, "cfg", None) + if actualized_cfg is not None: + if hasattr(actualized_cfg, "pretrained_model_args"): + model_cfg.pretrained_model_args = actualized_cfg.pretrained_model_args + + return model + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + if "correct" in logging_outputs[0]: + zero = torch.scalar_tensor(0.0) + correct = sum(log.get("correct", zero) for log in logging_outputs) + metrics.log_scalar_sum("_correct", correct) + + metrics.log_derived( + "accuracy", + lambda meters: 100 * meters["_correct"].sum / meters["sample_size"].sum, + ) + + @property + def source_dictionary(self): + return None + + @property + def target_dictionary(self): + return None + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return sys.maxsize, sys.maxsize diff --git a/examples/data2vec/tasks/mae_image_pretraining.py b/examples/data2vec/tasks/mae_image_pretraining.py new file mode 100644 index 0000000000..35a14891ca --- /dev/null +++ b/examples/data2vec/tasks/mae_image_pretraining.py @@ -0,0 +1,119 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import sys + +from typing import Optional, List +from dataclasses import dataclass, field +from omegaconf import MISSING, II + +from fairseq.data import SubsampleDataset +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task + +try: + from ..data import MaeImageDataset +except: + sys.path.append("..") + from data import MaeImageDataset + +logger = logging.getLogger(__name__) + + +@dataclass +class ImageMaskingConfig: + patch_size: int = II("model.modalities.image.patch_size") + mask_prob: float = II("model.modalities.image.mask_prob") + mask_prob_adjust: float = II("model.modalities.image.mask_prob_adjust") + mask_length: int = II("model.modalities.image.mask_length") + inverse_mask: bool = II("model.modalities.image.inverse_mask") + mask_dropout: float = II("model.modalities.image.mask_dropout") + clone_batch: int = II("model.clone_batch") + expand_adjacent: bool = False + non_overlapping: bool = False + + +@dataclass +class MaeImagePretrainingConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) + multi_data: Optional[List[str]] = None + input_size: int = 224 + local_cache_path: Optional[str] = None + key: str = "imgs" + + beit_transforms: bool = False + target_transform: bool = False + no_transform: bool = False + + rebuild_batches: bool = True + + precompute_mask_config: Optional[ImageMaskingConfig] = None + + subsample: float = 1 + seed: int = II("common.seed") + dataset_type: str = "imagefolder" + + +@register_task("mae_image_pretraining", dataclass=MaeImagePretrainingConfig) +class MaeImagePretrainingTask(FairseqTask): + """ """ + + cfg: MaeImagePretrainingConfig + + @classmethod + def setup_task(cls, cfg: MaeImagePretrainingConfig, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + cfg (AudioPretrainingConfig): configuration of this task + """ + + return cls(cfg) + + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + data_path = self.cfg.data + cfg = task_cfg or self.cfg + + compute_mask = cfg.precompute_mask_config is not None + mask_args = {} + if compute_mask: + mask_args = cfg.precompute_mask_config + + self.datasets[split] = MaeImageDataset( + root=data_path if cfg.multi_data is None else cfg.multi_data, + split=split, + input_size=cfg.input_size, + local_cache_path=cfg.local_cache_path, + key=cfg.key, + beit_transforms=cfg.beit_transforms, + target_transform=cfg.target_transform, + no_transform=cfg.no_transform, + compute_mask=compute_mask, + dataset_type=cfg.dataset_type, + **mask_args, + ) + + if cfg.subsample < 1: + self.datasets[split] = SubsampleDataset( + self.datasets[split], + cfg.subsample, + shuffle=True, + seed=cfg.seed, + ) + + @property + def source_dictionary(self): + return None + + @property + def target_dictionary(self): + return None + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return sys.maxsize, sys.maxsize diff --git a/examples/data2vec/tasks/multimodal.py b/examples/data2vec/tasks/multimodal.py new file mode 100644 index 0000000000..74648e918f --- /dev/null +++ b/examples/data2vec/tasks/multimodal.py @@ -0,0 +1,165 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import sys + +from dataclasses import dataclass +from typing import Optional, List +from omegaconf import II + +from fairseq.data.iterators import GroupedEpochBatchIterator + +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks import FairseqTask, register_task +from fairseq.tasks.audio_pretraining import AudioPretrainingConfig, AudioPretrainingTask +from fairseq.tasks.masked_lm import MaskedLMConfig, MaskedLMTask +from .mae_image_pretraining import MaeImagePretrainingConfig, MaeImagePretrainingTask +from examples.data2vec.data.modality import Modality + +from fairseq.data.audio.multi_modality_dataset import ( + MultiModalityDataset, + ModalityDatasetItem, +) + + +@dataclass +class MultimodalPretrainingConfig(FairseqDataclass): + audio: Optional[AudioPretrainingConfig] = None + image: Optional[MaeImagePretrainingConfig] = None + text: Optional[MaskedLMConfig] = None + + audio_ratio: float = 1 + image_ratio: float = 1 + text_ratio: float = 1 + + max_tokens: Optional[int] = II("dataset.max_tokens") + batch_size: Optional[int] = II("dataset.batch_size") + update_freq: List[int] = II("optimization.update_freq") + + rebuild_batches: bool = True + + +@register_task("multimodal_pretraining", dataclass=MultimodalPretrainingConfig) +class MultimodalPretrainingTask(FairseqTask): + """ """ + + cfg: MultimodalPretrainingConfig + + def __init__(self, cfg: MultimodalPretrainingConfig): + super().__init__(cfg) + self.audio_task = ( + AudioPretrainingTask(cfg.audio) if cfg.audio is not None else None + ) + self.image_task = ( + MaeImagePretrainingTask(cfg.image) if cfg.image is not None else None + ) + self.text_task = MaskedLMTask(cfg.text) if cfg.text is not None else None + + self.mult_ratios = [] + + @classmethod + def setup_task(cls, cfg: MultimodalPretrainingConfig, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + cfg (AudioPretrainingConfig): configuration of this task + """ + + return cls(cfg) + + def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): + datasets = [] + self.mult_ratios = [] + + def load_ds(task, name, ratio): + if task is not None: + task.load_dataset(split) + ds = ModalityDatasetItem( + datasetname=name, + dataset=task.dataset(split), + max_positions=task.max_positions(), + max_tokens=self.cfg.max_tokens, + max_sentences=self.cfg.batch_size, + ) + datasets.append(ds) + self.mult_ratios.append(ratio) + + load_ds(self.audio_task, Modality.AUDIO, self.cfg.audio_ratio) + load_ds(self.image_task, Modality.IMAGE, self.cfg.image_ratio) + load_ds(self.text_task, Modality.TEXT, self.cfg.text_ratio) + + assert len(datasets) > 0 + + self.datasets[split] = MultiModalityDataset(datasets) + + @property + def supported_modalities(self): + modalities = [] + if self.cfg.text is not None: + modalities.append(Modality.TEXT) + if self.cfg.audio is not None: + modalities.append(Modality.AUDIO) + if self.cfg.image is not None: + modalities.append(Modality.IMAGE) + + return modalities + + def get_batch_iterator( + self, + dataset, + max_tokens=None, + max_sentences=None, + max_positions=None, + ignore_invalid_inputs=False, + required_batch_size_multiple=1, + seed=1, + num_shards=1, + shard_id=0, + num_workers=0, + epoch=0, + data_buffer_size=0, + disable_iterator_cache=False, + skip_remainder_batch=False, + grouped_shuffling=False, + update_epoch_batch_itr=False, + ): + + # initialize the dataset with the correct starting epoch + dataset.set_epoch(epoch) + + batch_samplers = dataset.get_batch_samplers( + self.mult_ratios, required_batch_size_multiple, seed + ) + + # return a reusable, sharded iterator + epoch_iter = GroupedEpochBatchIterator( + dataset=dataset, + collate_fn=dataset.collater, + batch_samplers=batch_samplers, + seed=seed, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + epoch=epoch, + mult_rate=max(self.cfg.update_freq), + buffer_size=data_buffer_size, + skip_remainder_batch=skip_remainder_batch, + ) + self.dataset_to_epoch_iter[dataset] = {} # refresh it every epoch + return epoch_iter + + @property + def source_dictionary(self): + return None + + @property + def target_dictionary(self): + return None + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return sys.maxsize, sys.maxsize diff --git a/examples/roberta/config/finetuning/run_config/local.yaml b/examples/roberta/config/finetuning/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/roberta/config/finetuning/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/roberta/config/finetuning/run_config/slurm_1g.yaml b/examples/roberta/config/finetuning/run_config/slurm_1g.yaml new file mode 100644 index 0000000000..8bc21854d4 --- /dev/null +++ b/examples/roberta/config/finetuning/run_config/slurm_1g.yaml @@ -0,0 +1,28 @@ + +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: '_' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/roberta_ft/${env:PREFIX}/${hydra.job.config_name}/${env:SUFFIX} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir}/submitit + timeout_min: 1000 + cpus_per_task: 8 + gpus_per_node: 1 + tasks_per_node: 1 + mem_gb: 60 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 + exclude: learnfair1381,learnfair5192,learnfair2304 diff --git a/examples/roberta/config/finetuning/run_config/slurm_1g_aws.yaml b/examples/roberta/config/finetuning/run_config/slurm_1g_aws.yaml new file mode 100644 index 0000000000..085391cffa --- /dev/null +++ b/examples/roberta/config/finetuning/run_config/slurm_1g_aws.yaml @@ -0,0 +1,25 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: '_' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /fsx-wav2vec/${env:USER}/roberta_ft/${env:PREFIX}/${hydra.job.config_name}/${env:SUFFIX} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir}/submitit + timeout_min: 1000 + cpus_per_task: 8 + gpus_per_node: 1 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: learnfair,wav2vec + max_num_timeout: 30 diff --git a/examples/roberta/config/pretraining/run_config/local.yaml b/examples/roberta/config/pretraining/run_config/local.yaml new file mode 100644 index 0000000000..45595f9eea --- /dev/null +++ b/examples/roberta/config/pretraining/run_config/local.yaml @@ -0,0 +1,15 @@ +# @package _global_ +hydra: + sweep: + dir: ${env:PWD}/tmp_dbg/${now:%H-%M-%S} + +distributed_training: + distributed_world_size: 1 + nprocs_per_node: 1 + distributed_port: -1 + +common: + log_interval: 1 + +dataset: + num_workers: 0 diff --git a/examples/roberta/config/pretraining/run_config/slurm_2.yaml b/examples/roberta/config/pretraining/run_config/slurm_2.yaml new file mode 100644 index 0000000000..006a0f2116 --- /dev/null +++ b/examples/roberta/config/pretraining/run_config/slurm_2.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/roberta/config/pretraining/run_config/slurm_2_aws.yaml b/examples/roberta/config/pretraining/run_config/slurm_2_aws.yaml new file mode 100644 index 0000000000..a5937ea5a8 --- /dev/null +++ b/examples/roberta/config/pretraining/run_config/slurm_2_aws.yaml @@ -0,0 +1,39 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.local_cache_path + - task.data + - task.post_save_script + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + - model.model_path + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 0 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec + max_num_timeout: 30 diff --git a/examples/roberta/config/pretraining/run_config/slurm_3.yaml b/examples/roberta/config/pretraining/run_config/slurm_3.yaml new file mode 100644 index 0000000000..0e1555d20f --- /dev/null +++ b/examples/roberta/config/pretraining/run_config/slurm_3.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 3 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/roberta/config/pretraining/run_config/slurm_4.yaml b/examples/roberta/config/pretraining/run_config/slurm_4.yaml new file mode 100644 index 0000000000..c54d735fb2 --- /dev/null +++ b/examples/roberta/config/pretraining/run_config/slurm_4.yaml @@ -0,0 +1,36 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 4 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb,ib4 + max_num_timeout: 30 diff --git a/examples/roberta/fb_multilingual/README.multilingual.pretraining.md b/examples/roberta/fb_multilingual/README.multilingual.pretraining.md new file mode 100644 index 0000000000..234fd74708 --- /dev/null +++ b/examples/roberta/fb_multilingual/README.multilingual.pretraining.md @@ -0,0 +1,26 @@ +# Multilingual pretraining RoBERTa + +This tutorial will walk you through pretraining multilingual RoBERTa. + +### 1) Preprocess the data + +```bash +DICTIONARY="/private/home/namangoyal/dataset/XLM/wiki/17/175k/vocab" +DATA_LOCATION="/private/home/namangoyal/dataset/XLM/wiki/17/175k" + +for LANG in en es it +do + fairseq-preprocess \ + --only-source \ + --srcdict $DICTIONARY \ + --trainpref "$DATA_LOCATION/train.$LANG" \ + --validpref "$DATA_LOCATION/valid.$LANG" \ + --testpref "$DATA_LOCATION/test.$LANG" \ + --destdir "wiki_17-bin/$LANG" \ + --workers 60; +done +``` + +### 2) Train RoBERTa base + +[COMING UP...] diff --git a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py index 11ef60c945..06d20d8d4a 100644 --- a/examples/simultaneous_translation/modules/monotonic_multihead_attention.py +++ b/examples/simultaneous_translation/modules/monotonic_multihead_attention.py @@ -396,6 +396,7 @@ def forward( "p_choose": p_choose, "alpha": alpha, "beta": beta, + "soft_energy": soft_energy, } def _get_monotonic_buffer(self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]): diff --git a/examples/simultaneous_translation/tests/test_text_models.py b/examples/simultaneous_translation/tests/test_text_models.py index 127adfa633..19d6356304 100644 --- a/examples/simultaneous_translation/tests/test_text_models.py +++ b/examples/simultaneous_translation/tests/test_text_models.py @@ -334,7 +334,7 @@ def test_expected_attention(self): self.model.decoder.layers[0].encoder_attn, "chunk_size", int(1e10) - ) + ) or int(1e10) ) self.assertTrue( diff --git a/examples/speech_recognition/new/conf/hydra/sweeper/ax_sil.yaml b/examples/speech_recognition/new/conf/hydra/sweeper/ax_sil.yaml new file mode 100644 index 0000000000..eaaebcf5f6 --- /dev/null +++ b/examples/speech_recognition/new/conf/hydra/sweeper/ax_sil.yaml @@ -0,0 +1,29 @@ +# @package hydra.sweeper +_target_: hydra_plugins.hydra_ax_sweeper.ax_sweeper.AxSweeper +max_batch_size: null +ax_config: + max_trials: 64 + early_stop: + minimize: true + max_epochs_without_improvement: 10 + epsilon: 0.025 + experiment: + name: ${dataset.gen_subset} + objective_name: wer + minimize: true + parameter_constraints: null + outcome_constraints: null + status_quo: null + client: + verbose_logging: false + random_seed: null + params: + decoding.lmweight: + type: range + bounds: [0.0, 10.0] + decoding.wordscore: + type: range + bounds: [-10.0, 10.0] + decoding.silweight: + type: range + bounds: [ -10.0, 0.0 ] diff --git a/examples/speech_recognition/new/conf/infer.yaml b/examples/speech_recognition/new/conf/infer.yaml index 21dd19fadd..2d168d06af 100644 --- a/examples/speech_recognition/new/conf/infer.yaml +++ b/examples/speech_recognition/new/conf/infer.yaml @@ -10,6 +10,8 @@ hydra: sweep: dir: /checkpoint/${env:USER}/${env:PREFIX}/${common_eval.results_path} subdir: ${dataset.gen_subset} +common: + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec common_eval: results_path: null path: null diff --git a/examples/speech_recognition/new/conf/run_config/fb_slurm_1.yaml b/examples/speech_recognition/new/conf/run_config/fb_slurm_1.yaml new file mode 100644 index 0000000000..d0a9b0e586 --- /dev/null +++ b/examples/speech_recognition/new/conf/run_config/fb_slurm_1.yaml @@ -0,0 +1,28 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - common_eval.path + sweep: + dir: /checkpoint/abaevski/asr/d2v2/decoding/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} +# subdir: ${hydra.job.override_dirname} + launcher: + cpus_per_task: 16 + gpus_per_node: 1 + tasks_per_node: 1 + nodes: 1 + partition: devlab,learnlab + mem_gb: 100 + timeout_min: 2000 + max_num_timeout: 10 + name: ${env:PREFIX}_${hydra.job.config_name} + submitit_folder: ${hydra.sweep.dir}/%j + constraint: volta32gb + exclude: learnfair7598 \ No newline at end of file diff --git a/examples/speech_recognition/new/conf/run_config/fb_slurm_2g.yaml b/examples/speech_recognition/new/conf/run_config/fb_slurm_2g.yaml new file mode 100644 index 0000000000..c0c442f76d --- /dev/null +++ b/examples/speech_recognition/new/conf/run_config/fb_slurm_2g.yaml @@ -0,0 +1,27 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - common_eval.path + sweep: + dir: /checkpoint/abaevski/asr/d2v2/decoding/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} +# subdir: ${hydra.job.override_dirname} + launcher: + cpus_per_task: 16 + gpus_per_node: 2 + tasks_per_node: 2 + nodes: 1 + partition: devlab,learnlab + mem_gb: 100 + timeout_min: 2000 + max_num_timeout: 10 + name: ${env:PREFIX}_${hydra.job.config_name} + submitit_folder: ${hydra.sweep.dir}/%j + constraint: volta32gb \ No newline at end of file diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_1.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_1.yaml new file mode 100644 index 0000000000..4a848435c1 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_1.yaml @@ -0,0 +1,26 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 \ No newline at end of file diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_16.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_16.yaml new file mode 100644 index 0000000000..041843a9b9 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_16.yaml @@ -0,0 +1,27 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 16 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 + exclude: learnfair1381,learnfair5192,learnfair2304 \ No newline at end of file diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_1_aws.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_1_aws.yaml new file mode 100644 index 0000000000..b9335df782 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_1_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.local_cache_path + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_1_old.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_1_old.yaml new file mode 100644 index 0000000000..a8d2363dc5 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_1_old.yaml @@ -0,0 +1,27 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 450 + nodes: 1 + name: ${env:PREFIX}_wav2vec3_small_librispeech + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 + exclude: learnfair1381 \ No newline at end of file diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_2.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_2.yaml new file mode 100644 index 0000000000..65ec48920d --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_2.yaml @@ -0,0 +1,27 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 + exclude: learnfair7491,learnfair7477,learnfair7487 \ No newline at end of file diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_2_aws.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_2_aws.yaml new file mode 100644 index 0000000000..e7590efc0a --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_2_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.local_cache_path + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 8 + tasks_per_node: 1 + mem_gb: 0 + nodes: 2 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_2g.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_2g.yaml new file mode 100644 index 0000000000..aaa20ebd03 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_2g.yaml @@ -0,0 +1,26 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 2 + tasks_per_node: 2 + mem_gb: 200 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_3.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_3.yaml new file mode 100644 index 0000000000..9614ececae --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_3.yaml @@ -0,0 +1,27 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 450 + nodes: 3 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 + exclude: learnfair7491,learnfair7477,learnfair7487 \ No newline at end of file diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_4g.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_4g.yaml new file mode 100644 index 0000000000..c0c9f60436 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_4g.yaml @@ -0,0 +1,26 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 200 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_4g_aws.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_4g_aws.yaml new file mode 100644 index 0000000000..6bbbf3b646 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_4g_aws.yaml @@ -0,0 +1,37 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '/' + exclude_keys: + - run_config + - distributed_training.distributed_port + - distributed_training.distributed_world_size + - model.pretrained_model_path + - model.target_network_path + - next_script + - task.cache_in_scratch + - task.local_cache_path + - task.data + - checkpoint.save_interval_updates + - checkpoint.keep_interval_updates + - checkpoint.save_on_overflow + - common.log_interval + - common.user_dir + sweep: + dir: /fsx-wav2vec/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: '' + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 80 + gpus_per_node: 4 + tasks_per_node: 1 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab,learnfair + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/run_config/slurm_8.yaml b/examples/wav2vec/config/finetuning/run_config/slurm_8.yaml new file mode 100644 index 0000000000..984f218885 --- /dev/null +++ b/examples/wav2vec/config/finetuning/run_config/slurm_8.yaml @@ -0,0 +1,26 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 4320 + cpus_per_task: 10 + gpus_per_node: 8 + tasks_per_node: 8 + mem_gb: 400 + nodes: 8 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_100h_2.yaml b/examples/wav2vec/config/finetuning/vox_100h_2.yaml new file mode 100644 index 0000000000..9bf588f587 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_100h_2.yaml @@ -0,0 +1,106 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/1h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 1 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: 0 + wer_sil_weight: -2 + +optimization: + max_update: 100000 + lr: [1e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: null + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 72000 + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_100h_2_aws.yaml b/examples/wav2vec/config/finetuning/vox_100h_2_aws.yaml new file mode 100644 index 0000000000..3a0d517ebb --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_100h_2_aws.yaml @@ -0,0 +1,82 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /data/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx-wav2vec/abaevski/data/libri/100h/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 1 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /fsx-wav2vec/abaevski/data/libri/4-gram.bin + wer_lexicon: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: 0 + wer_sil_weight: -2 + +optimization: + max_update: 100000 + lr: [1e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: null + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 82000 + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 7 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + diff --git a/examples/wav2vec/config/finetuning/vox_100h_3.yaml b/examples/wav2vec/config/finetuning/vox_100h_3.yaml new file mode 100644 index 0000000000..46778666f6 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_100h_3.yaml @@ -0,0 +1,101 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/1h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 1 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: -1.0 + +optimization: + max_update: 100000 + lr: [1e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: cosine + warmup_updates: 8000 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_10h_2.yaml b/examples/wav2vec/config/finetuning/vox_10h_2.yaml new file mode 100644 index 0000000000..05ee76f147 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10h_2.yaml @@ -0,0 +1,102 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 10 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + keep_interval_updates: 1 + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 10 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: -1.0 + +optimization: + max_update: 60000 + lr: [2e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: cosine + warmup_updates: 8000 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.5 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_10h_2_aws.yaml b/examples/wav2vec/config/finetuning/vox_10h_2_aws.yaml new file mode 100644 index 0000000000..a0afc9c5d5 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10h_2_aws.yaml @@ -0,0 +1,81 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /data/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 10 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 10 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /fsx-wav2vec/abaevski/data/libri/4-gram.bin + wer_lexicon: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: 4 + wer_sil_weight: -5 + +optimization: + max_update: 60000 + lr: [1e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: null + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 72000 + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.75 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 diff --git a/examples/wav2vec/config/finetuning/vox_10h_aws.yaml b/examples/wav2vec/config/finetuning/vox_10h_aws.yaml new file mode 100644 index 0000000000..c754373657 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10h_aws.yaml @@ -0,0 +1,104 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /data/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 10 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 10 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter +# wer_kenlm_model: /fsx-wav2vec/abaevski/data/libri/4-gram.bin +# wer_lexicon: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst +# wer_lm_weight: 2.0 +# wer_word_score: -1.0 + +optimization: + max_update: 60000 + lr: [2e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: null + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 72000 + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: wav2vec,learnlab + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_10h_aws_v100.yaml b/examples/wav2vec/config/finetuning/vox_10h_aws_v100.yaml new file mode 100644 index 0000000000..58ad2acf71 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10h_aws_v100.yaml @@ -0,0 +1,102 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 +# tensorboard_logdir: tb + +checkpoint: + save_interval: 10 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx/abaevski/data/libri/10h/wav2vec/raw + labels: ltr + cache_in_scratch: true + + +dataset: + num_workers: 10 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 10 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_lexicon: /fsx/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: -1.0 + +optimization: + max_update: 60000 + lr: [2e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: null + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 72000 + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.6 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /fsx/${env:USER}/w2v_ft/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 0 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: learnfair + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_10m_2.yaml b/examples/wav2vec/config/finetuning/vox_10m_2.yaml new file mode 100644 index 0000000000..1ac7c1217f --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10m_2.yaml @@ -0,0 +1,114 @@ +# @package _group_ + +common: + fp16: true + fp16_no_flatten_grads: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 500 + save_interval_updates: 500 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/10m/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 500 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 5 + wer_word_score: 2 + wer_sil_weight: -2 + +optimization: + max_update: 10000 + lr: [2e-6] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [4] # base 10h we -> 2/4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 2e-6 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + lr_scheduler: + _name: cosine + warmup_updates: 1000 + +lr_scheduler: pass_through + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 3 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + freeze_finetune_updates: 100 + + zero_mask: true + feature_grad_mult: 0.0 + activation_dropout: 0.1 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + update_alibi: false + +#hydra: +# job: +# config: +# override_dirname: +# kv_sep: ':' +# item_sep: '__' +# exclude_keys: +# - run_config +# - distributed_training.distributed_port +# sweep: +# dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} +# subdir: ${hydra.job.num} +# launcher: +# submitit_folder: ${hydra.sweep.dir} +# timeout_min: 3000 +# cpus_per_task: 10 +# gpus_per_node: 4 +# tasks_per_node: 4 +# mem_gb: 250 +# nodes: 1 +# name: ${env:PREFIX}_${hydra.job.config_name} +# partition: devlab,learnlab,learnfair,scavenge +# constraint: volta32gb +# max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_10m_2_aws.yaml b/examples/wav2vec/config/finetuning/vox_10m_2_aws.yaml new file mode 100644 index 0000000000..a9c270855b --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10m_2_aws.yaml @@ -0,0 +1,114 @@ +# @package _group_ + +common: + fp16: true + fp16_no_flatten_grads: true + log_format: json + log_interval: 200 + user_dir: /data/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 500 + save_interval_updates: 500 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx-wav2vec/abaevski/data/libri/10m/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 500 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /fsx-wav2vec/abaevski/data/libri/4-gram.bin + wer_lexicon: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 5 + wer_word_score: 2 + wer_sil_weight: -2 + +optimization: + max_update: 10000 + lr: [2e-6] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [4] # base 10h we -> 2/4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 2e-6 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + lr_scheduler: + _name: cosine + warmup_updates: 1000 + +lr_scheduler: pass_through + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 3 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + freeze_finetune_updates: 100 + + zero_mask: true + feature_grad_mult: 0.0 + activation_dropout: 0.1 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + update_alibi: false + +#hydra: +# job: +# config: +# override_dirname: +# kv_sep: ':' +# item_sep: '__' +# exclude_keys: +# - run_config +# - distributed_training.distributed_port +# sweep: +# dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} +# subdir: ${hydra.job.num} +# launcher: +# submitit_folder: ${hydra.sweep.dir} +# timeout_min: 3000 +# cpus_per_task: 10 +# gpus_per_node: 4 +# tasks_per_node: 4 +# mem_gb: 250 +# nodes: 1 +# name: ${env:PREFIX}_${hydra.job.config_name} +# partition: devlab,learnlab,learnfair,scavenge +# constraint: volta32gb +# max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_10m_3.yaml b/examples/wav2vec/config/finetuning/vox_10m_3.yaml new file mode 100644 index 0000000000..b6804126cf --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_10m_3.yaml @@ -0,0 +1,105 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 1000 + save_interval_updates: 100 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/10m/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 500 + valid_subset: dev_other + required_batch_size_multiple: 8 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 8 + wer_word_score: 5.8 + wer_sil_weight: -8 + +optimization: + max_update: 13000 + lr: [2e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [5] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_length: 10 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_1h_2.yaml b/examples/wav2vec/config/finetuning/vox_1h_2.yaml new file mode 100644 index 0000000000..75f4aafd71 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_1h_2.yaml @@ -0,0 +1,104 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 100 + save_interval_updates: 500 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/1h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 100 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 6 + wer_word_score: -0.1 + wer_sil_weight: -4.7 + +optimization: + max_update: 60000 + lr: [1e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: cosine + warmup_updates: 4000 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_1h_2_aws.yaml b/examples/wav2vec/config/finetuning/vox_1h_2_aws.yaml new file mode 100644 index 0000000000..cc4d511d14 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_1h_2_aws.yaml @@ -0,0 +1,114 @@ +# @package _group_ + +common: + fp16: true + fp16_no_flatten_grads: true + log_format: json + log_interval: 200 + user_dir: /data/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 100 + save_interval_updates: 500 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx-wav2vec/abaevski/data/libri/1h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 500 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 4 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /fsx-wav2vec/abaevski/data/libri/4-gram.bin + wer_lexicon: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 5 + wer_word_score: 0 + wer_sil_weight: -4 + +optimization: + max_update: 10000 + lr: [2e-6] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [4] # base 10h we -> 2/4 + +optimizer: + _name: composite + dynamic_groups: true + groups: + default: + lr_float: 2e-6 + optimizer: + _name: adam + adam_betas: [0.9,0.95] + lr_scheduler: + _name: cosine + warmup_updates: 1000 + +lr_scheduler: pass_through + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 3 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + freeze_finetune_updates: 100 + + zero_mask: true + feature_grad_mult: 0.0 + activation_dropout: 0.1 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + update_alibi: false + +#hydra: +# job: +# config: +# override_dirname: +# kv_sep: ':' +# item_sep: '__' +# exclude_keys: +# - run_config +# - distributed_training.distributed_port +# sweep: +# dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} +# subdir: ${hydra.job.num} +# launcher: +# submitit_folder: ${hydra.sweep.dir} +# timeout_min: 3000 +# cpus_per_task: 10 +# gpus_per_node: 4 +# tasks_per_node: 4 +# mem_gb: 250 +# nodes: 1 +# name: ${env:PREFIX}_${hydra.job.config_name} +# partition: devlab,learnlab,learnfair,scavenge +# constraint: volta32gb +# max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_1h_3.yaml b/examples/wav2vec/config/finetuning/vox_1h_3.yaml new file mode 100644 index 0000000000..842c89717e --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_1h_3.yaml @@ -0,0 +1,104 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 100 + save_interval_updates: 500 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/1h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 640000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 100 + valid_subset: dev_other + required_batch_size_multiple: 8 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 6 + wer_word_score: -0.1 + wer_sil_weight: -4.7 + +optimization: + max_update: 13000 + lr: [6e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [5] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: cosine + warmup_updates: 4000 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.3 + mask_length: 3 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_1h_4.yaml b/examples/wav2vec/config/finetuning/vox_1h_4.yaml new file mode 100644 index 0000000000..698ed8c4da --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_1h_4.yaml @@ -0,0 +1,104 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 100 + save_interval_updates: 1000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/1h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 640000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 100 + valid_subset: dev_other + required_batch_size_multiple: 8 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: -1.0 + +optimization: + max_update: 13000 + lr: [6e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [5] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.65 + mask_length: 10 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_1h_aws.yaml b/examples/wav2vec/config/finetuning/vox_1h_aws.yaml new file mode 100644 index 0000000000..aa6700415b --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_1h_aws.yaml @@ -0,0 +1,80 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /data/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 100 + save_interval_updates: 500 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx-wav2vec/abaevski/data/libri/10m/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 10000 + validate_interval: 100 + valid_subset: dev_other + required_batch_size_multiple: 8 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 8 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /fsx-wav2vec/abaevski/data/libri/4-gram.bin + wer_lexicon: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 5 + wer_word_score: -0.1 + wer_sil_weight: -4.7 + +optimization: + max_update: 13000 + lr: [6e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [5] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: cosine + warmup_updates: 4000 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.3 + mask_length: 3 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.25 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + update_alibi: false diff --git a/examples/wav2vec/config/finetuning/vox_960h_2.yaml b/examples/wav2vec/config/finetuning/vox_960h_2.yaml new file mode 100644 index 0000000000..d96e2325be --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_960h_2.yaml @@ -0,0 +1,105 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/960h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 1 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 16 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: -1.0 + +optimization: + max_update: 200000 + lr: [1e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: null + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 200000 + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/examples/wav2vec/config/finetuning/vox_960h_2_aws.yaml b/examples/wav2vec/config/finetuning/vox_960h_2_aws.yaml new file mode 100644 index 0000000000..41d2b38f85 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_960h_2_aws.yaml @@ -0,0 +1,82 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /data/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /fsx-wav2vec/abaevski/data/librispeech + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1280000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 1 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 16 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /fsx-wav2vec/abaevski/data/libri/4-gram.bin + wer_lexicon: /fsx-wav2vec/abaevski/data/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 1.5 + wer_word_score: 0 + wer_sil_weight: -1 + +optimization: + max_update: 200000 + lr: [2e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: null + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 192000 + final_lr_scale: 0.05 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.3 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + diff --git a/examples/wav2vec/config/finetuning/vox_960h_3.yaml b/examples/wav2vec/config/finetuning/vox_960h_3.yaml new file mode 100644 index 0000000000..ef6597aa67 --- /dev/null +++ b/examples/wav2vec/config/finetuning/vox_960h_3.yaml @@ -0,0 +1,101 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + user_dir: /private/home/abaevski/fairseq-py/examples/data2vec +# tensorboard_logdir: tb + +checkpoint: + save_interval: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +task: + _name: audio_finetuning + data: /checkpoint/abaevski/data/speech/libri/1h/wav2vec/raw + labels: ltr + normalize: true + +dataset: + num_workers: 6 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_after_updates: 100 + validate_interval: 1 + valid_subset: dev_other + required_batch_size_multiple: 1 + +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 16 + +criterion: + _name: ctc + zero_infinity: true + post_process: letter + wer_kenlm_model: /checkpoint/abaevski/data/speech/libri/4-gram.bin + wer_lexicon: /checkpoint/abaevski/data/speech/libri/10h/wav2vec/raw/lexicon_ltr2.lst + wer_lm_weight: 2.0 + wer_word_score: -1.0 + +optimization: + max_update: 200000 + lr: [1e-5] +# lr: [1e-5] # base 10h wer + sentence_avg: true + update_freq: [1] # base 10h we -> 2/4 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: cosine + warmup_updates: 8000 + +model: + _name: wav2vec_ctc + w2v_path: ??? + apply_mask: true + mask_prob: 0.4 + mask_length: 5 +# mask_prob: 0.65 # base 10h wer + mask_channel_prob: 0.1 +# mask_channel_prob: 0.6 # base 10h wer + mask_channel_length: 64 + layerdrop: 0.1 +# layerdrop: 0.05 # base 10h wer + activation_dropout: 0.1 + feature_grad_mult: 0.0 + freeze_finetune_updates: 100 + dropout: 0 + final_dropout: 0 + attention_dropout: 0 + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}/${hydra.job.override_dirname} + subdir: ${hydra.job.num} + launcher: + submitit_folder: ${hydra.sweep.dir} + timeout_min: 3000 + cpus_per_task: 10 + gpus_per_node: 4 + tasks_per_node: 4 + mem_gb: 250 + nodes: 1 + name: ${env:PREFIX}_${hydra.job.config_name} + partition: devlab,learnlab,learnfair,scavenge + constraint: volta32gb + max_num_timeout: 30 diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 138b4d1eb2..ff1da2553c 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -45,14 +45,14 @@ def save_checkpoint(cfg: CheckpointConfig, trainer, epoch_itr, val_loss): save_checkpoint.best = best_function(val_loss, prev_best) if cfg.no_save: - return + return None trainer.consolidate_optimizer() # TODO(SS): do we need this if no_save_optimizer_state if not trainer.should_save_checkpoint_on_current_rank: if trainer.always_call_state_dict_during_save_checkpoint: trainer.state_dict() - return + return None write_timer = meters.StopwatchMeter() write_timer.start() @@ -111,8 +111,9 @@ def is_better(a, b): checkpoints = [ os.path.join(cfg.save_dir, fn) for fn, cond in checkpoint_conds.items() if cond ] + saved_cp = None if len(checkpoints) > 0 and trainer.should_save_checkpoint_on_current_rank: - trainer.save_checkpoint(checkpoints[0], extra_state) + saved_cp = trainer.save_checkpoint(checkpoints[0], extra_state) for cp in checkpoints[1:]: if cfg.write_checkpoints_asynchronously: # TODO[ioPath]: Need to implement a delayed asynchronous @@ -133,7 +134,11 @@ def is_better(a, b): ) ) - if not end_of_epoch and cfg.keep_interval_updates > 0: + if ( + not end_of_epoch + and cfg.keep_interval_updates > 0 + and trainer.should_save_checkpoint_on_current_rank + ): # remove old checkpoints; checkpoints are sorted in descending order if cfg.keep_interval_updates_pattern == -1: checkpoints = checkpoint_paths( @@ -157,7 +162,7 @@ def is_better(a, b): elif PathManager.exists(old_chk): PathManager.rm(old_chk) - if cfg.keep_last_epochs > 0: + if cfg.keep_last_epochs > 0 and trainer.should_save_checkpoint_on_current_rank: # remove old epoch checkpoints; checkpoints are sorted in descending order checkpoints = checkpoint_paths( cfg.save_dir, pattern=r"checkpoint(\d+){}\.pt".format(suffix) @@ -168,7 +173,7 @@ def is_better(a, b): elif PathManager.exists(old_chk): PathManager.rm(old_chk) - if cfg.keep_best_checkpoints > 0: + if cfg.keep_best_checkpoints > 0 and trainer.should_save_checkpoint_on_current_rank: # only keep the best N checkpoints according to validation metric checkpoints = checkpoint_paths( cfg.save_dir, @@ -184,6 +189,8 @@ def is_better(a, b): elif PathManager.exists(old_chk): PathManager.rm(old_chk) + return saved_cp + def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): """ @@ -574,6 +581,8 @@ def _torch_persistent_save(obj, f): if i == 2: logger.error(traceback.format_exc()) raise + else: + time.sleep(2.5) def _upgrade_state_dict(state): diff --git a/fairseq/config/fb_run_config/slurm.yaml b/fairseq/config/fb_run_config/slurm.yaml new file mode 100644 index 0000000000..20cf8f5201 --- /dev/null +++ b/fairseq/config/fb_run_config/slurm.yaml @@ -0,0 +1,29 @@ +# @package _global_ + +hydra: + job: + config: + override_dirname: + kv_sep: ':' + item_sep: '__' + exclude_keys: + - fb_run_config + - distributed_training.distributed_port + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${hydra.job.config_name}_${hydra.launcher.gpus_per_node}/${hydra.job.override_dirname} + launcher: + cpus_per_task: 60 + gpus_per_node: ??? + tasks_per_node: 1 + nodes: 1 + partition: learnfair + mem_gb: 400 + timeout_min: 4320 + max_num_timeout: 10 + name: ${env:PREFIX}_${hydra.job.config_name} + submitit_folder: ${hydra.sweep.dir} + +distributed_training: + ddp_backend: c10d + distributed_world_size: ??? + distributed_port: ??? diff --git a/fairseq/criterions/__init__.py b/fairseq/criterions/__init__.py index 4dbf46a1cb..ecd65d34ad 100644 --- a/fairseq/criterions/__init__.py +++ b/fairseq/criterions/__init__.py @@ -25,8 +25,8 @@ ) -def build_criterion(cfg: DictConfig, task): - return build_criterion_(cfg, task) +def build_criterion(cfg: DictConfig, task, from_checkpoint=False): + return build_criterion_(cfg, task, from_checkpoint=from_checkpoint) # automatically import any Python files in the criterions/ directory diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index 6d53198b09..e55e928b4f 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -7,18 +7,17 @@ import math from argparse import Namespace from dataclasses import dataclass, field +from omegaconf import II from typing import Optional import torch import torch.nn.functional as F -from omegaconf import II - from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion -from fairseq.data.data_utils import post_process from fairseq.dataclass import FairseqDataclass -from fairseq.logging.meters import safe_round +from fairseq.data.data_utils import post_process from fairseq.tasks import FairseqTask +from fairseq.logging.meters import safe_round @dataclass @@ -54,6 +53,10 @@ class CtcCriterionConfig(FairseqDataclass): default=-1.0, metadata={"help": "lm word score to use with wer_kenlm_model"}, ) + wer_sil_weight: float = field( + default=0, + metadata={"help": "lm word score to use with wer_kenlm_model"}, + ) wer_args: Optional[str] = field( default=None, @@ -101,6 +104,7 @@ def __init__( dec_args.beam_threshold = min(50, len(task.target_dictionary)) dec_args.lm_weight = cfg.wer_lm_weight dec_args.word_score = cfg.wer_word_score + dec_args.sil_weight = cfg.wer_sil_weight dec_args.unk_weight = -math.inf dec_args.sil_weight = 0 diff --git a/fairseq/criterions/label_smoothed_cross_entropy.py b/fairseq/criterions/label_smoothed_cross_entropy.py index 257466903f..cb43be0ca5 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy.py +++ b/fairseq/criterions/label_smoothed_cross_entropy.py @@ -7,11 +7,10 @@ from dataclasses import dataclass, field import torch -from omegaconf import II - from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass +from omegaconf import II @dataclass diff --git a/fairseq/criterions/model_criterion.py b/fairseq/criterions/model_criterion.py index f9a810d835..2c9fbb2553 100644 --- a/fairseq/criterions/model_criterion.py +++ b/fairseq/criterions/model_criterion.py @@ -12,6 +12,7 @@ from fairseq import metrics, utils from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass +from fairseq.logging.meters import safe_round logger = logging.getLogger(__name__) @@ -27,6 +28,7 @@ class ModelCriterionConfig(FairseqDataclass): default_factory=list, metadata={"help": "additional output keys to log"}, ) + can_sum: bool = True @register_criterion("model", dataclass=ModelCriterionConfig) @@ -43,10 +45,11 @@ class ModelCriterion(FairseqCriterion): net_output dict can be logged via the log_keys parameter. """ - def __init__(self, task, loss_weights=None, log_keys=None): + def __init__(self, task, loss_weights=None, log_keys=None, can_sum=True): super().__init__(task) self.loss_weights = loss_weights self.log_keys = log_keys + self.can_sum = can_sum def forward(self, model, sample, reduce=True): net_output = model(**sample["net_input"]) @@ -69,7 +72,7 @@ def forward(self, model, sample, reduce=True): ) raise if coef != 0 and p is not None: - scaled_losses[lk] = coef * p.float() + scaled_losses[lk] = coef * p.float().sum() loss = sum(scaled_losses.values()) @@ -93,6 +96,8 @@ def forward(self, model, sample, reduce=True): if lk in net_output and net_output[lk] is not None: if not torch.is_tensor(net_output[lk]) or net_output[lk].numel() == 1: logging_output[lk] = float(net_output[lk]) + elif lk.startswith("_"): + logging_output[lk] = net_output[lk] else: for i, v in enumerate(net_output[lk]): logging_output[f"{lk}_{i}"] = float(v) @@ -124,6 +129,7 @@ def reduce_metrics(logging_outputs) -> None: metrics.log_scalar("loss", loss_sum / sample_size, sample_size, round=3) metrics.log_scalar("ntokens", ntokens) metrics.log_scalar("nsentences", nsentences) + metrics.log_scalar("sample_size", sample_size) builtin_keys = { "loss", @@ -138,18 +144,33 @@ def reduce_metrics(logging_outputs) -> None: ) for k in logging_outputs[0]: - if k not in builtin_keys: + if k not in builtin_keys and not k.startswith("_"): val = sum(log.get(k, 0) for log in logging_outputs) if k.startswith("loss_"): metrics.log_scalar(k, val / sample_size, sample_size, round=3) else: metrics.log_scalar(k, val / world_size, round=3) - @staticmethod - def logging_outputs_can_be_summed() -> bool: + correct = sum(log.get("correct", 0) for log in logging_outputs) + total = sum(log.get("count", 0) for log in logging_outputs) + + if total > 0: + metrics.log_scalar("_correct", correct) + metrics.log_scalar("_total", total) + + metrics.log_derived( + "accuracy", + lambda meters: safe_round( + meters["_correct"].sum / meters["_total"].sum, 5 + ) + if meters["_total"].sum > 0 + else float("nan"), + ) + + def logging_outputs_can_be_summed(self) -> bool: """ Whether the logging outputs returned by `forward` can be summed across workers prior to calling `reduce_metrics`. Setting this to True will improves distributed training speed. """ - return True + return self.can_sum diff --git a/fairseq/criterions/sentence_prediction.py b/fairseq/criterions/sentence_prediction.py index b402d76039..01c2a2ba6d 100644 --- a/fairseq/criterions/sentence_prediction.py +++ b/fairseq/criterions/sentence_prediction.py @@ -5,13 +5,49 @@ import math from dataclasses import dataclass, field +from itertools import chain +import numpy as np import torch import torch.nn.functional as F +from sklearn.metrics import f1_score +from sklearn.metrics import matthews_corrcoef as _matthews_corrcoef +from scipy.stats import pearsonr, spearmanr from fairseq import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass +from fairseq.logging.meters import safe_round + + +def simple_accuracy(preds, labels): + return (preds == labels).mean() + + +def acc_and_f1(preds, labels): + acc = simple_accuracy(preds, labels) + f1 = f1_score(y_true=labels, y_pred=preds) + return { + "acc": acc, + "f1": f1, + "acc_and_f1": (acc + f1) / 2, + } + + +def pearson_and_spearman(preds, labels): + pearson_corr = pearsonr(preds, labels)[0] + spearman_corr = spearmanr(preds, labels)[0] + return { + "pearson": pearson_corr, + "spearmanr": spearman_corr, + "corr": (pearson_corr + spearman_corr) / 2, + } + + +def matthews_corrcoef(preds, labels): + # make it consistent with other metrics taking (preds, labels) as input + mcc = _matthews_corrcoef(labels, preds) + return mcc @dataclass @@ -23,6 +59,9 @@ class SentencePredictionConfig(FairseqDataclass): regression_target: bool = field( default=False, ) + report_mcc: bool = False + report_acc_and_f1: bool = False + report_pearson_and_spearman: bool = False @register_criterion("sentence_prediction", dataclass=SentencePredictionConfig) @@ -31,6 +70,13 @@ def __init__(self, cfg: SentencePredictionConfig, task): super().__init__(task) self.classification_head_name = cfg.classification_head_name self.regression_target = cfg.regression_target + self.keep_pred_and_targ = ( + cfg.report_mcc or cfg.report_acc_and_f1 or cfg.report_pearson_and_spearman + ) + self.report_mcc = cfg.report_mcc + self.report_acc_and_f1 = cfg.report_acc_and_f1 + self.report_pearson_and_spearman = cfg.report_pearson_and_spearman + self.label_dict = task.label_dictionary def forward(self, model, sample, reduce=True): """Compute the loss for the given sample. @@ -65,14 +111,16 @@ def forward(self, model, sample, reduce=True): loss = task_loss # mha & ffn regularization update if ( - hasattr(model.args, "mha_reg_scale_factor") + hasattr(model, "args") + and hasattr(model.args, "mha_reg_scale_factor") and model.args.mha_reg_scale_factor != 0.0 ): mha_reg_loss = model._get_adaptive_head_loss() loss += mha_reg_loss logging_output.update({"mha_reg_loss": mha_reg_loss}) if ( - hasattr(model.args, "ffn_reg_scale_factor") + hasattr(model, "args") + and hasattr(model.args, "ffn_reg_scale_factor") and model.args.ffn_reg_scale_factor != 0.0 ): ffn_reg_loss = model._get_adaptive_ffn_loss() @@ -90,6 +138,25 @@ def forward(self, model, sample, reduce=True): if not self.regression_target: preds = logits.argmax(dim=1) logging_output["ncorrect"] = (preds == targets).sum() + if self.keep_pred_and_targ and not model.training: + if self.regression_target: + logging_output["pred"] = logits.detach().cpu().tolist() + logging_output["targ"] = targets.detach().cpu().tolist() + else: + # remove offset `self.label_dict.nspecial` from OffsetTokensDataset + preds = self.label_dict.string(preds + self.label_dict.nspecial).split() + targets = self.label_dict.string( + targets + self.label_dict.nspecial + ).split() + logging_output["pred"] = list(map(int, preds)) + logging_output["targ"] = list(map(int, targets)) + + if self.report_mcc: + logging_output["report_mcc"] = True + if self.report_acc_and_f1: + logging_output["report_acc_and_f1"] = True + if self.report_pearson_and_spearman: + logging_output["report_pearson_and_spearman"] = True return loss, sample_size, logging_output @@ -131,6 +198,86 @@ def reduce_metrics(logging_outputs) -> None: "accuracy", 100.0 * ncorrect / nsentences, nsentences, round=1 ) + # Metrics used by GLUE + pred = np.array( + list(chain.from_iterable(log.get("pred", []) for log in logging_outputs)) + ) + targ = np.array( + list(chain.from_iterable(log.get("targ", []) for log in logging_outputs)) + ) + if len(pred): + metrics.log_concat_tensor("pred", torch.from_numpy(pred), dim=0) + metrics.log_concat_tensor("targ", torch.from_numpy(targ), dim=0) + if any("report_mcc" in log for log in logging_outputs): + metrics.log_derived( + "mcc", + lambda meters: safe_round( + matthews_corrcoef( + meters["pred"].tensor.numpy(), + meters["targ"].tensor.numpy(), + ) + * 100, + 1, + ), + ) + if any("report_acc_and_f1" in log for log in logging_outputs): + metrics.log_derived( + "acc_and_f1", + lambda meters: safe_round( + acc_and_f1( + meters["pred"].tensor.numpy(), + meters["targ"].tensor.numpy(), + )["acc_and_f1"] + * 100, + 1, + ), + ) + metrics.log_derived( + "f1", + lambda meters: safe_round( + acc_and_f1( + meters["pred"].tensor.numpy(), + meters["targ"].tensor.numpy(), + )["f1"] + * 100, + 1, + ), + ) + if any("report_pearson_and_spearman" in log for log in logging_outputs): + metrics.log_derived( + "pearson_and_spearman", + lambda meters: safe_round( + pearson_and_spearman( + meters["pred"].tensor.numpy(), + meters["targ"].tensor.numpy(), + )["corr"] + * 100, + 1, + ), + ) + metrics.log_derived( + "pearson", + lambda meters: safe_round( + pearson_and_spearman( + meters["pred"].tensor.numpy(), + meters["targ"].tensor.numpy(), + )["pearson"] + * 100, + 1, + ), + ) + metrics.log_derived( + "spearman", + lambda meters: safe_round( + pearson_and_spearman( + meters["pred"].tensor.numpy(), + meters["targ"].tensor.numpy(), + )["spearmanr"] + * 100, + 1, + ), + ) + @staticmethod def logging_outputs_can_be_summed() -> bool: """ diff --git a/fairseq/data/__init__.py b/fairseq/data/__init__.py index 8acf2ca173..a27e3184aa 100644 --- a/fairseq/data/__init__.py +++ b/fairseq/data/__init__.py @@ -39,6 +39,11 @@ from .numel_dataset import NumelDataset from .num_samples_dataset import NumSamplesDataset from .offset_tokens_dataset import OffsetTokensDataset +from .padding_mask_dataset import ( + LeftPaddingMaskDataset, + PaddingMaskDataset, + RightPaddingMaskDataset, +) from .pad_dataset import LeftPadDataset, PadDataset, RightPadDataset from .prepend_dataset import PrependDataset from .prepend_token_dataset import PrependTokenDataset diff --git a/fairseq/data/add_class_target_dataset.py b/fairseq/data/add_class_target_dataset.py new file mode 100644 index 0000000000..bf89f25656 --- /dev/null +++ b/fairseq/data/add_class_target_dataset.py @@ -0,0 +1,79 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + +from . import BaseWrapperDataset, data_utils +from fairseq.data.text_compressor import TextCompressor, TextCompressionLevel + + +class AddTargetDataset(BaseWrapperDataset): + def __init__( + self, + dataset, + labels, + pad, + eos, + batch_targets, + process_label=None, + label_len_fn=None, + add_to_input=False, + text_compression_level=TextCompressionLevel.none, + ): + super().__init__(dataset) + self.labels = labels + self.batch_targets = batch_targets + self.pad = pad + self.eos = eos + self.process_label = process_label + self.label_len_fn = label_len_fn + self.add_to_input = add_to_input + self.text_compressor = TextCompressor(level=text_compression_level) + + def get_label(self, index, process_fn=None): + lbl = self.labels[index] + lbl = self.text_compressor.decompress(lbl) + return lbl if process_fn is None else process_fn(lbl) + + def __getitem__(self, index): + item = self.dataset[index] + item["label"] = self.get_label(index, process_fn=self.process_label) + return item + + def size(self, index): + sz = self.dataset.size(index) + own_sz = self.label_len_fn(self.get_label(index)) + return sz, own_sz + + def collater(self, samples): + collated = self.dataset.collater(samples) + if len(collated) == 0: + return collated + indices = set(collated["id"].tolist()) + target = [s["label"] for s in samples if s["id"] in indices] + + if self.batch_targets: + collated["target_lengths"] = torch.LongTensor([len(t) for t in target]) + target = data_utils.collate_tokens(target, pad_idx=self.pad, left_pad=False) + collated["ntokens"] = collated["target_lengths"].sum().item() + else: + collated["ntokens"] = sum([len(t) for t in target]) + + collated["target"] = target + + if self.add_to_input: + eos = target.new_full((target.size(0), 1), self.eos) + collated["target"] = torch.cat([target, eos], dim=-1).long() + collated["net_input"]["prev_output_tokens"] = torch.cat( + [eos, target], dim=-1 + ).long() + collated["ntokens"] += target.size(0) + return collated + + def filter_indices_by_size(self, indices, max_sizes): + indices, ignored = data_utils._filter_by_size_dynamic( + indices, self.size, max_sizes + ) + return indices, ignored diff --git a/fairseq/data/audio/multi_modality_dataset.py b/fairseq/data/audio/multi_modality_dataset.py index 2db1637341..0a42c10611 100644 --- a/fairseq/data/audio/multi_modality_dataset.py +++ b/fairseq/data/audio/multi_modality_dataset.py @@ -10,7 +10,6 @@ from typing import List, Optional, NamedTuple import numpy as np -from fairseq.data.resampling_dataset import ResamplingDataset import torch from fairseq.data import ( ConcatDataset, @@ -31,16 +30,6 @@ class ModalityDatasetItem(NamedTuple): max_sentences: Optional[int] = None -def resampling_dataset_present(ds): - if isinstance(ds, ResamplingDataset): - return True - if isinstance(ds, ConcatDataset): - return any(resampling_dataset_present(d) for d in ds.datasets) - if hasattr(ds, "dataset"): - return resampling_dataset_present(ds.dataset) - return False - - # MultiModalityDataset: it concate multiple datasets with different modalities. # Compared with ConcatDataset it can 1) sample data given the ratios for different datasets # 2) it adds mode to indicate what type of the data samples come from. @@ -106,7 +95,7 @@ def ordered_indices(self): Returns indices sorted by length. So less padding is needed. """ if len(self.datasets) == 1: - return self.datasets[0].ordered_indices() + return [self.datasets[0].ordered_indices()] indices_group = [] for d_idx, ds in enumerate(self.datasets): sample_num = self.cumulative_sizes[d_idx] @@ -117,16 +106,13 @@ def ordered_indices(self): return indices_group def get_raw_batch_samplers(self, required_batch_size_multiple, seed): + if len(self.raw_sub_batch_samplers) > 0: + logger.info(" raw_sub_batch_samplers exists. No action is taken") + return with data_utils.numpy_seed(seed): indices = self.ordered_indices() + for i, ds in enumerate(self.datasets): - # If we have ResamplingDataset, the same id can correpond to a different - # sample in the next epoch, so we need to rebuild this at every epoch - if i < len(self.raw_sub_batch_samplers) and not resampling_dataset_present( - ds - ): - logger.info(f"dataset {i} is valid and it is not re-sampled") - continue indices[i] = ds.filter_indices_by_size( indices[i], self.max_positions[i], @@ -137,10 +123,7 @@ def get_raw_batch_samplers(self, required_batch_size_multiple, seed): max_sentences=self.max_sentences[i], required_batch_size_multiple=required_batch_size_multiple, ) - if i < len(self.raw_sub_batch_samplers): - self.raw_sub_batch_samplers[i] = sub_batch_sampler - else: - self.raw_sub_batch_samplers.append(sub_batch_sampler) + self.raw_sub_batch_samplers.append(sub_batch_sampler) def get_batch_samplers(self, mult_ratios, required_batch_size_multiple, seed): self.get_raw_batch_samplers(required_batch_size_multiple, seed) diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index 181e2bbc9a..edb307e68f 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -7,6 +7,7 @@ import logging import os import sys +import time import io import numpy as np @@ -14,7 +15,7 @@ import torch.nn.functional as F from .. import FairseqDataset -from ..data_utils import compute_mask_indices, get_buckets, get_bucketed_sizes +from ..data_utils import compute_block_mask_1d, get_buckets, get_bucketed_sizes from fairseq.data.audio.audio_utils import ( parse_path, read_from_stored_zip, @@ -35,8 +36,17 @@ def __init__( shuffle=True, pad=False, normalize=False, - compute_mask_indices=False, - **mask_compute_kwargs, + compute_mask=False, + feature_encoder_spec: str = "None", + mask_prob: float = 0.75, + mask_prob_adjust: float = 0, + mask_length: int = 1, + inverse_mask: bool = False, + require_same_masks: bool = True, + clone_batch: int = 1, + expand_adjacent: bool = False, + mask_dropout: float = 0, + non_overlapping: bool = False, ): super().__init__() @@ -49,12 +59,19 @@ def __init__( self.pad = pad self.shuffle = shuffle self.normalize = normalize - self.compute_mask_indices = compute_mask_indices - if self.compute_mask_indices: - self.mask_compute_kwargs = mask_compute_kwargs - self._features_size_map = {} - self._C = mask_compute_kwargs["encoder_embed_dim"] - self._conv_feature_layers = eval(mask_compute_kwargs["conv_feature_layers"]) + + self.is_compute_mask = compute_mask + self.feature_encoder_spec = eval(feature_encoder_spec) + self._features_size_map = {} + self.mask_prob = mask_prob + self.mask_prob_adjust = mask_prob_adjust + self.mask_length = mask_length + self.inverse_mask = inverse_mask + self.require_same_masks = require_same_masks + self.clone_batch = clone_batch + self.expand_adjacent = expand_adjacent + self.mask_dropout = mask_dropout + self.non_overlapping = non_overlapping def __getitem__(self, index): raise NotImplementedError() @@ -76,48 +93,21 @@ def postprocess(self, feats, curr_sample_rate): feats = F.layer_norm(feats, feats.shape) return feats - def crop_to_max_size(self, wav, target_size): - size = len(wav) + def crop_to_max_size(self, t, target_size, dim=0): + size = t.size(dim) diff = size - target_size if diff <= 0: - return wav + return t start = np.random.randint(0, diff + 1) end = size - diff + start - return wav[start:end] - - def _compute_mask_indices(self, dims, padding_mask): - B, T, C = dims - mask_indices, mask_channel_indices = None, None - if self.mask_compute_kwargs["mask_prob"] > 0: - mask_indices = compute_mask_indices( - (B, T), - padding_mask, - self.mask_compute_kwargs["mask_prob"], - self.mask_compute_kwargs["mask_length"], - self.mask_compute_kwargs["mask_selection"], - self.mask_compute_kwargs["mask_other"], - min_masks=2, - no_overlap=self.mask_compute_kwargs["no_mask_overlap"], - min_space=self.mask_compute_kwargs["mask_min_space"], - ) - mask_indices = torch.from_numpy(mask_indices) - if self.mask_compute_kwargs["mask_channel_prob"] > 0: - mask_channel_indices = compute_mask_indices( - (B, C), - None, - self.mask_compute_kwargs["mask_channel_prob"], - self.mask_compute_kwargs["mask_channel_length"], - self.mask_compute_kwargs["mask_channel_selection"], - self.mask_compute_kwargs["mask_channel_other"], - no_overlap=self.mask_compute_kwargs["no_mask_channel_overlap"], - min_space=self.mask_compute_kwargs["mask_channel_min_space"], - ) - mask_channel_indices = ( - torch.from_numpy(mask_channel_indices).unsqueeze(1).expand(-1, T, -1) - ) - return mask_indices, mask_channel_indices + slices = [] + for d in range(dim): + slices.append(slice(None)) + slices.append(slice(start, end)) + + return t[slices] @staticmethod def _bucket_tensor(tensor, num_pad, value): @@ -166,33 +156,24 @@ def collater(self, samples): input["source"] = self._bucket_tensor(collated_sources, num_pad, 0) input["padding_mask"] = self._bucket_tensor(padding_mask, num_pad, True) - if self.compute_mask_indices: - B = input["source"].size(0) - T = self._get_mask_indices_dims(input["source"].size(-1)) - padding_mask_reshaped = input["padding_mask"].clone() - extra = padding_mask_reshaped.size(1) % T - if extra > 0: - padding_mask_reshaped = padding_mask_reshaped[:, :-extra] - padding_mask_reshaped = padding_mask_reshaped.view( - padding_mask_reshaped.size(0), T, -1 - ) - padding_mask_reshaped = padding_mask_reshaped.all(-1) - input["padding_count"] = padding_mask_reshaped.sum(-1).max().item() - mask_indices, mask_channel_indices = self._compute_mask_indices( - (B, T, self._C), - padding_mask_reshaped, + if "precomputed_mask" in samples[0]: + target_size = self._get_mask_indices_dims(target_size) + collated_mask = torch.cat( + [ + self.crop_to_max_size(s["precomputed_mask"], target_size, dim=1) + for s in samples + ], + dim=0, ) - input["mask_indices"] = mask_indices - input["mask_channel_indices"] = mask_channel_indices - out["sample_size"] = mask_indices.sum().item() + input["precomputed_mask"] = collated_mask out["net_input"] = input return out def _get_mask_indices_dims(self, size, padding=0, dilation=1): - if size not in self._features_size_map: + if size not in self.feature_encoder_spec: L_in = size - for (_, kernel_size, stride) in self._conv_feature_layers: + for (_, kernel_size, stride) in self.feature_encoder_spec: L_out = L_in + 2 * padding - dilation * (kernel_size - 1) - 1 L_out = 1 + L_out // stride L_in = L_out @@ -244,6 +225,9 @@ def set_bucket_info(self, num_buckets): f"{self.buckets}" ) + def filter_indices_by_size(self, indices, max_sizes): + return indices, [] + class FileAudioDataset(RawAudioDataset): def __init__( @@ -256,7 +240,7 @@ def __init__( pad=False, normalize=False, num_buckets=0, - compute_mask_indices=False, + compute_mask=False, text_compression_level=TextCompressionLevel.none, **mask_compute_kwargs, ): @@ -267,7 +251,7 @@ def __init__( shuffle=shuffle, pad=pad, normalize=normalize, - compute_mask_indices=compute_mask_indices, + compute_mask=compute_mask, **mask_compute_kwargs, ) @@ -319,11 +303,43 @@ def __getitem__(self, index): assert is_sf_audio_data(byte_data) path_or_fp = io.BytesIO(byte_data) - wav, curr_sample_rate = sf.read(path_or_fp, dtype="float32") + retry = 3 + wav = None + for i in range(retry): + try: + wav, curr_sample_rate = sf.read(path_or_fp, dtype="float32") + break + except Exception as e: + logger.warning( + f"Failed to read {path_or_fp}: {e}. Sleeping for {1 * i}" + ) + time.sleep(1 * i) + + if wav is None: + raise Exception(f"Failed to load {path_or_fp}") feats = torch.from_numpy(wav).float() feats = self.postprocess(feats, curr_sample_rate) - return {"id": index, "source": feats} + + v = {"id": index, "source": feats} + + if self.is_compute_mask: + T = self._get_mask_indices_dims(feats.size(-1)) + mask = compute_block_mask_1d( + shape=(self.clone_batch, T), + mask_prob=self.mask_prob, + mask_length=self.mask_length, + mask_prob_adjust=self.mask_prob_adjust, + inverse_mask=self.inverse_mask, + require_same_masks=True, + expand_adjcent=self.expand_adjacent, + mask_dropout=self.mask_dropout, + non_overlapping=self.non_overlapping, + ) + + v["precomputed_mask"] = mask + + return v class BinarizedAudioDataset(RawAudioDataset): @@ -338,7 +354,7 @@ def __init__( pad=False, normalize=False, num_buckets=0, - compute_mask_indices=False, + compute_mask=False, **mask_compute_kwargs, ): super().__init__( @@ -348,7 +364,7 @@ def __init__( shuffle=shuffle, pad=pad, normalize=normalize, - compute_mask_indices=compute_mask_indices, + compute_mask=compute_mask, **mask_compute_kwargs, ) @@ -390,4 +406,22 @@ def __getitem__(self, index): wav, curr_sample_rate = sf.read(fname) feats = torch.from_numpy(wav).float() feats = self.postprocess(feats, curr_sample_rate) - return {"id": index, "source": feats} + v = {"id": index, "source": feats} + + if self.is_compute_mask: + T = self._get_mask_indices_dims(feats.size(-1)) + mask = compute_block_mask_1d( + shape=(self.clone_batch, T), + mask_prob=self.mask_prob, + mask_length=self.mask_length, + mask_prob_adjust=self.mask_prob_adjust, + inverse_mask=self.inverse_mask, + require_same_masks=True, + expand_adjcent=self.expand_adjacent, + mask_dropout=self.mask_dropout, + non_overlapping=self.non_overlapping, + ) + + v["precomputed_mask"] = mask + + return v diff --git a/fairseq/data/data_utils.py b/fairseq/data/data_utils.py index 0372d52b0f..9a19cc3c18 100644 --- a/fairseq/data/data_utils.py +++ b/fairseq/data/data_utils.py @@ -14,6 +14,7 @@ import warnings from typing import Optional, Tuple +import math import numpy as np import torch @@ -337,7 +338,7 @@ def batch_by_size( if fixed_shapes is None: if num_tokens_vec is None: - return batch_by_size_fn( + b = batch_by_size_fn( indices, num_tokens_fn, max_tokens, @@ -345,7 +346,7 @@ def batch_by_size( bsz_mult, ) else: - return batch_by_size_vec( + b = batch_by_size_vec( indices, num_tokens_vec, max_tokens, @@ -353,6 +354,11 @@ def batch_by_size( bsz_mult, ) + if bsz_mult > 1 and len(b[-1]) % bsz_mult != 0: + b = b[:-1] + + return b + else: fixed_shapes = np.array(fixed_shapes, dtype=np.int64) sort_order = np.lexsort( @@ -402,6 +408,12 @@ def compute_mask_indices( min_space: int = 0, require_same_masks: bool = True, mask_dropout: float = 0.0, + add_masks: bool = False, + seed: Optional[int] = None, + epoch: Optional[int] = None, + indices: Optional[torch.Tensor] = None, + idc_select_ver: int = 1, # 2 to reproduce mask_tokens_dataset + num_mask_ver: int = 2, # 2 to reproduce mask_tokens_dataset ) -> np.ndarray: """ Computes random mask spans for a given shape @@ -428,49 +440,73 @@ def compute_mask_indices( bsz, all_sz = shape mask = np.full((bsz, all_sz), False) - all_num_mask = int( - # add a random number for probabilistic rounding - mask_prob * all_sz / float(mask_length) - + np.random.rand() - ) - - all_num_mask = max(min_masks, all_num_mask) + if num_mask_ver == 1: + all_num_mask = int( + # add a random number for probabilistic rounding + mask_prob * all_sz / float(mask_length) + + np.random.rand() + ) + all_num_mask = max(min_masks, all_num_mask) mask_idcs = [] for i in range(bsz): + if seed is not None and epoch is not None and indices is not None: + seed_i = int(hash((seed, epoch, indices[i].item())) % 1e6) + else: + seed_i = None + + rng = np.random.default_rng(seed_i) + if padding_mask is not None: sz = all_sz - padding_mask[i].long().sum().item() + assert sz >= 0, sz + else: + sz = all_sz + + if num_mask_ver == 1: + if padding_mask is not None: + num_mask = int( + # add a random number for probabilistic rounding + mask_prob * sz / float(mask_length) + + np.random.rand() + ) + num_mask = max(min_masks, num_mask) + else: + num_mask = all_num_mask + elif num_mask_ver == 2: num_mask = int( # add a random number for probabilistic rounding mask_prob * sz / float(mask_length) - + np.random.rand() + + rng.random() ) num_mask = max(min_masks, num_mask) else: - sz = all_sz - num_mask = all_num_mask + raise ValueError() if mask_type == "static": lengths = np.full(num_mask, mask_length) elif mask_type == "uniform": - lengths = np.random.randint(mask_other, mask_length * 2 + 1, size=num_mask) + lengths = rng.randint(mask_other, mask_length * 2 + 1, size=num_mask) elif mask_type == "normal": - lengths = np.random.normal(mask_length, mask_other, size=num_mask) + lengths = rng.normal(mask_length, mask_other, size=num_mask) lengths = [max(1, int(round(x))) for x in lengths] elif mask_type == "poisson": - lengths = np.random.poisson(mask_length, size=num_mask) + lengths = rng.poisson(mask_length, size=num_mask) lengths = [int(round(x)) for x in lengths] else: raise Exception("unknown mask selection " + mask_type) if sum(lengths) == 0: - lengths[0] = min(mask_length, sz - 1) + if mask_type == "static": + raise ValueError(f"this should never happens") + else: + lengths = [min(mask_length, sz - 1)] if no_overlap: mask_idc = [] def arrange(s, e, length, keep_length): - span_start = np.random.randint(s, e - length) + span_start = rng.randint(s, e - length) mask_idc.extend(span_start + i for i in range(length)) new_parts = [] @@ -491,16 +527,20 @@ def arrange(s, e, length, keep_length): if l_sum == 0: break probs = lens / np.sum(lens) - c = np.random.choice(len(parts), p=probs) + c = rng.choice(len(parts), p=probs) s, e = parts.pop(c) parts.extend(arrange(s, e, length, min_length)) mask_idc = np.asarray(mask_idc) else: - min_len = min(lengths) - if sz - min_len <= num_mask: - min_len = sz - num_mask - 1 - - mask_idc = np.random.choice(sz - min_len, num_mask, replace=False) + if idc_select_ver == 1: + min_len = min(lengths) + if sz - min_len <= num_mask: + min_len = sz - num_mask - 1 + mask_idc = rng.choice(sz - min_len, num_mask, replace=False) + elif idc_select_ver == 2: + mask_idc = rng.choice(sz, num_mask, replace=False) + else: + raise ValueError() mask_idc = np.asarray( [ @@ -510,20 +550,300 @@ def arrange(s, e, length, keep_length): ] ) - mask_idcs.append(np.unique(mask_idc[mask_idc < sz])) + mask_idc = np.unique(mask_idc[mask_idc < sz]) + if len(mask_idc) >= sz: + raise ValueError( + ( + f"the entire sequence is masked. " + f"sz={sz}; mask_idc[mask_idc]; " + f"index={indices[i] if indices is not None else None}" + ) + ) + mask_idcs.append(mask_idc) + + target_len = None + if require_same_masks: + if add_masks: + target_len = max([len(m) for m in mask_idcs]) + else: + target_len = min([len(m) for m in mask_idcs]) - min_len = min([len(m) for m in mask_idcs]) for i, mask_idc in enumerate(mask_idcs): - if len(mask_idc) > min_len and require_same_masks: - mask_idc = np.random.choice(mask_idc, min_len, replace=False) - if mask_dropout > 0: - num_holes = np.rint(len(mask_idc) * mask_dropout).astype(int) - mask_idc = np.random.choice( - mask_idc, len(mask_idc) - num_holes, replace=False - ) + if target_len is not None and len(mask_idc) > target_len: + mask_idc = rng.choice(mask_idc, target_len, replace=False) mask[i, mask_idc] = True + if target_len is not None and len(mask_idc) < target_len: + unmasked = np.flatnonzero(~mask[i]) + to_mask = rng.choice(unmasked, target_len - len(mask_idc), replace=False) + mask[i, to_mask] = True + + if mask_dropout > 0: + masked = np.flatnonzero(mask[i]) + num_holes = np.rint(len(masked) * mask_dropout).astype(int) + to_drop = rng.choice(masked, num_holes, replace=False) + mask[i, to_drop] = False + + return mask + + +def compute_block_mask_2d( + shape: Tuple[int, int], + mask_prob: float, + mask_length: int, + mask_prob_adjust: float = 0, + inverse_mask: bool = False, + require_same_masks: bool = True, + expand_adjcent: bool = False, + mask_dropout: float = 0, + non_overlapping: bool = False, +) -> torch.Tensor: + + assert mask_length > 1 + + B, L = shape + + d = int(L**0.5) + + if inverse_mask: + mask_prob = 1 - mask_prob + + if non_overlapping: + sz = math.ceil(d / mask_length) + inp_len = sz * sz + + inp = torch.zeros((B, 1, sz, sz)) + w = torch.ones((1, 1, mask_length, mask_length)) + + mask_inds = torch.multinomial( + 1 - inp.view(B, -1), + int(inp_len * (mask_prob + mask_prob_adjust) * (1 + mask_dropout)), + replacement=False, + ) + inp.view(B, -1).scatter_(1, mask_inds, 1) + + mask = torch.nn.functional.conv_transpose2d(inp, w, stride=mask_length).squeeze( + 1 + ) + if mask.size(-1) > d: + mask = mask[..., :d, :d] + else: + mask = torch.zeros((B, d, d)) + mask_inds = torch.randint( + 0, + L, + size=( + B, + int( + L + * ((mask_prob + mask_prob_adjust) / mask_length**2) + * (1 + mask_dropout) + ), + ), + ) + mask.view(B, -1).scatter_(1, mask_inds, 1) + centers = mask.nonzero(as_tuple=True) + + inds = ([], [], []) + + offset = mask_length // 2 + for i in range(mask_length): + for j in range(mask_length): + k1 = i - offset + k2 = j - offset + inds[0].append(centers[0]) + inds[1].append(centers[1] + k1) + inds[2].append(centers[2] + k2) + + i0 = torch.cat(inds[0]) + i1 = torch.cat(inds[1]).clamp_(min=0, max=d - 1) + i2 = torch.cat(inds[2]).clamp_(min=0, max=d - 1) + + mask[(i0, i1, i2)] = 1 + + def get_nbs(b, m, w): + all_nbs = torch.nn.functional.conv2d(m.unsqueeze(1), w, padding="same") + all_nbs = all_nbs.clamp_max_(1).view(b, -1) + return all_nbs + + if require_same_masks and expand_adjcent: + w = torch.zeros((1, 1, 3, 3)) + w[..., 0, 1] = 1 + w[..., 2, 1] = 1 + w[..., 1, 0] = 1 + w[..., 1, 2] = 1 + + all_nbs = get_nbs(B, mask, w) + + mask = mask.reshape(B, -1) + + if require_same_masks: + n_masks = mask.sum(dim=-1) + final_target_len = int(L * (mask_prob)) + target_len = int(final_target_len * (1 + mask_dropout)) + + for i in range(len(mask)): + n = n_masks[i] + m = mask[i] + r = 0 + while expand_adjcent and n < target_len: + if r == 0: + nbs = all_nbs[i] + else: + nbs = get_nbs(1, m.view(1, d, d), w).flatten() + + cands = (1 - m + nbs) > 1 + cand_sz = int(cands.sum().item()) + + assert cand_sz > 0, f"{nbs} {cand_sz}" + + to_mask = torch.multinomial( + cands.float(), min(cand_sz, int(target_len - n)), replacement=False + ) + m[to_mask] = 1 + assert to_mask.numel() > 0 + n += to_mask.numel() + r += 1 + + if n > final_target_len: + to_unmask = torch.multinomial( + m, int(n - final_target_len), replacement=False + ) + m[to_unmask] = 0 + elif n < final_target_len: + to_mask = torch.multinomial( + (1 - m), int(final_target_len - n), replacement=False + ) + m[to_mask] = 1 + + if inverse_mask: + mask = 1 - mask + + return mask + + +def compute_block_mask_1d( + shape: Tuple[int, int], + mask_prob: float, + mask_length: int, + mask_prob_adjust: float = 0, + inverse_mask: bool = False, + require_same_masks: bool = True, + expand_adjcent: bool = False, + mask_dropout: float = 0, + non_overlapping: bool = False, +) -> torch.Tensor: + + B, L = shape + + if inverse_mask: + mask_prob = 1 - mask_prob + + if non_overlapping: + sz = math.ceil(L / mask_length) + + inp = torch.zeros((B, 1, sz)) + w = torch.ones((1, 1, mask_length)) + + mask_inds = torch.multinomial( + 1 - inp.view(B, -1), + int(sz * (mask_prob + mask_prob_adjust) * (1 + mask_dropout)), + replacement=False, + ) + inp.view(B, -1).scatter_(1, mask_inds, 1) + + mask = torch.nn.functional.conv_transpose1d(inp, w, stride=mask_length).squeeze( + 1 + ) + if mask.size(-1) > L: + mask = mask[..., :L] + + else: + mask = torch.zeros((B, L)) + mask_inds = torch.randint( + 0, + L, + size=( + B, + int( + L + * ((mask_prob + mask_prob_adjust) / mask_length) + * (1 + mask_dropout) + ), + ), + ) + + mask.view(B, -1).scatter_(1, mask_inds, 1) + centers = mask.nonzero(as_tuple=True) + + inds = ([], []) + + offset = mask_length // 2 + for i in range(mask_length): + k1 = i - offset + inds[0].append(centers[0]) + inds[1].append(centers[1] + k1) + + i0 = torch.cat(inds[0]) + i1 = torch.cat(inds[1]).clamp_(min=0, max=L - 1) + + mask[(i0, i1)] = 1 + + def get_nbs(b, m, w): + all_nbs = torch.nn.functional.conv1d(m.unsqueeze(1), w, padding="same") + all_nbs = all_nbs.clamp_max_(1).view(b, -1) + return all_nbs + + if require_same_masks and expand_adjcent: + w = torch.ones((1, 1, 3)) + w[..., 1] = 0 + all_nbs = get_nbs(B, mask, w) + + mask = mask.view(B, -1) + + if require_same_masks: + n_masks = mask.sum(dim=-1) + final_target_len = int(L * (mask_prob)) + target_len = int(final_target_len * (1 + mask_dropout)) + + for i in range(len(mask)): + n = n_masks[i] + m = mask[i] + r = 0 + while expand_adjcent and n < target_len: + if r == 0: + nbs = all_nbs[i] + else: + nbs = get_nbs(1, m.unsqueeze(0), w).squeeze(0) + + cands = (1 - m + nbs) > 1 + cand_sz = int(cands.sum().item()) + + assert cand_sz > 0, f"{nbs} {cand_sz}" + + to_mask = torch.multinomial( + cands.float(), min(cand_sz, int(target_len - n)), replacement=False + ) + m[to_mask] = 1 + assert to_mask.numel() > 0 + n += to_mask.numel() + r += 1 + + if n > final_target_len: + to_unmask = torch.multinomial( + m, int(n - final_target_len), replacement=False + ) + m[to_unmask] = 0 + elif n < final_target_len: + to_mask = torch.multinomial( + (1 - m), int(final_target_len - n), replacement=False + ) + m[to_mask] = 1 + + if inverse_mask: + mask = 1 - mask + return mask @@ -602,3 +922,223 @@ def raise_if_valid_subsets_unintentionally_ignored(train_cfg) -> None: advice = "Set --combine-val to combine them or --ignore-unused-valid-subsets to ignore them." msg = f"Valid paths {ignored_paths} will be ignored. {advice}" raise ValueError(msg) + + +def compute_mask_indices_for_one( + sz, + mask_prob: float, + mask_length: int, + seed=None, + epoch=None, + index=None, + min_masks=0, +): + """ + set seed, epoch, index for deterministic masking + """ + seed = int(hash((seed, epoch, index)) % 1e6) if seed else None + rng = np.random.default_rng(seed) + + # decide elements to mask + mask = np.full(sz, False) + num_mask = int( + # add a random number for probabilistic rounding + mask_prob * sz / float(mask_length) + + rng.random() + ) + num_mask = max(min_masks, num_mask) + + # multiple masking as described in the vq-wav2vec paper (https://arxiv.org/abs/1910.05453) + mask_idc = rng.choice(sz, num_mask, replace=False) + mask_idc = np.concatenate([mask_idc + i for i in range(mask_length)]) + mask_idc = mask_idc[mask_idc < len(mask)] + try: + mask[mask_idc] = True + except: # something wrong + print(f"Assigning mask indexes {mask_idc} to mask {mask} failed!") + raise + + return mask + + +def compute_mask_indices_v2( + shape: Tuple[int, int], + padding_mask: Optional[torch.Tensor], + mask_prob: float, + mask_length: int, + min_masks: int = 0, + require_same_masks: bool = True, + seed: Optional[int] = None, + epoch: Optional[int] = None, + indices: Optional[torch.Tensor] = None, +) -> np.ndarray: + bsz, all_sz = shape + mask = np.full((bsz, all_sz), False) + for i in range(bsz): + if padding_mask is not None: + sz = all_sz - padding_mask[i].long().sum().item() + else: + sz = all_sz + index = indices[i].item() if indices is not None else None + mask_for_one = compute_mask_indices_for_one( + sz, mask_prob, mask_length, seed, epoch, index, min_masks + ) + mask[i, :sz] = mask_for_one + + if require_same_masks: + index_sum = indices.sum().item() if indices is not None else None + seed = int(hash((seed, epoch, index_sum)) % 1e6) if seed else None + rng = np.random.default_rng(seed) + + num_mask = mask.sum(-1).min() + for i in range(bsz): + extra = mask[i].sum() - num_mask + if extra > 0: + to_unmask = rng.choice(np.nonzero(mask[i])[0], extra, replace=False) + mask[i, to_unmask] = False + + return mask + + +# TODO: a copy of the original compute_mask_indices +def compute_mask_indices_v3( + shape: Tuple[int, int], + padding_mask: Optional[torch.Tensor], + mask_prob: float, + mask_length: int, + mask_type: str = "static", + mask_other: float = 0.0, + min_masks: int = 0, + no_overlap: bool = False, + min_space: int = 0, + require_same_masks: bool = True, + mask_dropout: float = 0.0, + seed: Optional[int] = None, + epoch: Optional[int] = None, + indices: Optional[torch.Tensor] = None, +) -> np.ndarray: + """ + Computes random mask spans for a given shape + + Args: + shape: the the shape for which to compute masks. + should be of size 2 where first element is batch size and 2nd is timesteps + padding_mask: optional padding mask of the same size as shape, which will prevent masking padded elements + mask_prob: probability for each token to be chosen as start of the span to be masked. this will be multiplied by + number of timesteps divided by length of mask span to mask approximately this percentage of all elements. + however due to overlaps, the actual number will be smaller (unless no_overlap is True) + mask_type: how to compute mask lengths + static = fixed size + uniform = sample from uniform distribution [mask_other, mask_length*2] + normal = sample from normal distribution with mean mask_length and stdev mask_other. mask is min 1 element + poisson = sample from possion distribution with lambda = mask length + min_masks: minimum number of masked spans + no_overlap: if false, will switch to an alternative recursive algorithm that prevents spans from overlapping + min_space: only used if no_overlap is True, this is how many elements to keep unmasked between spans + require_same_masks: if true, will randomly drop out masks until same amount of masks remains in each sample + mask_dropout: randomly dropout this percentage of masks in each example + """ + bsz, all_sz = shape + mask = np.full((bsz, all_sz), False) + + all_num_mask = int( + # add a random number for probabilistic rounding + mask_prob * all_sz / float(mask_length) + + np.random.rand() + ) + + all_num_mask = max(min_masks, all_num_mask) + + mask_idcs = [] + for i in range(bsz): + if seed is not None and epoch is not None and indices is not None: + seed_i = int(hash((seed, epoch, indices[i].item())) % 1e6) + else: + seed_i = None + rng = np.random.default_rng(seed_i) + + if padding_mask is not None: + sz = all_sz - padding_mask[i].long().sum().item() + num_mask = int( + # add a random number for probabilistic rounding + mask_prob * sz / float(mask_length) + + rng.random() + ) + num_mask = max(min_masks, num_mask) + else: + sz = all_sz + num_mask = all_num_mask + + if mask_type == "static": + lengths = np.full(num_mask, mask_length) + elif mask_type == "uniform": + lengths = rng.randint(mask_other, mask_length * 2 + 1, size=num_mask) + elif mask_type == "normal": + lengths = rng.normal(mask_length, mask_other, size=num_mask) + lengths = [max(1, int(round(x))) for x in lengths] + elif mask_type == "poisson": + lengths = rng.poisson(mask_length, size=num_mask) + lengths = [int(round(x)) for x in lengths] + else: + raise Exception("unknown mask selection " + mask_type) + + if sum(lengths) == 0: + lengths[0] = min(mask_length, sz - 1) + + if no_overlap: + mask_idc = [] + + def arrange(s, e, length, keep_length): + span_start = rng.randint(s, e - length) + mask_idc.extend(span_start + i for i in range(length)) + + new_parts = [] + if span_start - s - min_space >= keep_length: + new_parts.append((s, span_start - min_space + 1)) + if e - span_start - length - min_space > keep_length: + new_parts.append((span_start + length + min_space, e)) + return new_parts + + parts = [(0, sz)] + min_length = min(lengths) + for length in sorted(lengths, reverse=True): + lens = np.fromiter( + (e - s if e - s >= length + min_space else 0 for s, e in parts), + np.int, + ) + l_sum = np.sum(lens) + if l_sum == 0: + break + probs = lens / np.sum(lens) + c = rng.choice(len(parts), p=probs) + s, e = parts.pop(c) + parts.extend(arrange(s, e, length, min_length)) + mask_idc = np.asarray(mask_idc) + else: + min_len = min(lengths) + if sz - min_len <= num_mask: + min_len = sz - num_mask - 1 + + mask_idc = rng.choice(sz - min_len, num_mask, replace=False) + + mask_idc = np.asarray( + [ + mask_idc[j] + offset + for j in range(len(mask_idc)) + for offset in range(lengths[j]) + ] + ) + + mask_idcs.append(np.unique(mask_idc[mask_idc < sz])) + + min_len = min([len(m) for m in mask_idcs]) + for i, mask_idc in enumerate(mask_idcs): + if len(mask_idc) > min_len and require_same_masks: + mask_idc = rng.choice(mask_idc, min_len, replace=False) + if mask_dropout > 0: + num_holes = np.rint(len(mask_idc) * mask_dropout).astype(int) + mask_idc = rng.choice(mask_idc, len(mask_idc) - num_holes, replace=False) + + mask[i, mask_idc] = True + + return mask diff --git a/fairseq/data/indexed_dataset.py b/fairseq/data/indexed_dataset.py index 81cba4af6b..1947d99408 100644 --- a/fairseq/data/indexed_dataset.py +++ b/fairseq/data/indexed_dataset.py @@ -542,6 +542,11 @@ def exists(path): data_file_path(path) ) + @property + def can_reuse_epoch_itr_across_epochs(self): + # TODO: a quick fix. make it a child class of FairseqDataset instead? + return True + def get_indexed_dataset_to_local(path) -> str: local_index_path = PathManager.get_local_path(index_file_path(path)) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index 45a8c65fa9..a488265137 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -156,7 +156,7 @@ def __init__( num_workers=0, buffer_size=0, timeout=0, - persistent_workers=False, + persistent_workers=True, ): assert isinstance(dataset, torch.utils.data.IterableDataset) self.dataset = dataset @@ -164,11 +164,11 @@ def __init__( self.collate_fn = collate_fn self.epoch = max(epoch, 1) # we use 1-based indexing for epochs self.num_workers = num_workers + self.persistent_workers = persistent_workers and num_workers > 0 # This upper limit here is to prevent people from abusing this feature # in a shared computing environment. self.buffer_size = min(buffer_size, 20) self.timeout = timeout - self.persistent_workers = persistent_workers self._current_epoch_iterator = None @@ -321,7 +321,7 @@ def __init__( skip_remainder_batch=False, grouped_shuffling=False, reuse_dataloader=False, - persistent_workers=False, + persistent_workers=True, ): assert isinstance(dataset, torch.utils.data.Dataset) self.dataset = dataset @@ -334,6 +334,7 @@ def __init__( self.num_shards = num_shards self.shard_id = shard_id self.num_workers = num_workers + self.persistent_workers = persistent_workers and num_workers > 0 # This upper limit here is to prevent people from abusing this feature # in a shared computing environment. self.buffer_size = min(buffer_size, 20) @@ -350,7 +351,6 @@ def __init__( self.dataloader = None self.reuse_dataloader = reuse_dataloader - self.persistent_workers = persistent_workers @property def frozen_batches(self): @@ -777,8 +777,6 @@ def __init__( mult_rate=1, buffer_size=0, skip_remainder_batch=False, - reuse_dataloader=False, - persistent_workers=False, ): super().__init__( dataset, @@ -791,8 +789,6 @@ def __init__( epoch, buffer_size, skip_remainder_batch=skip_remainder_batch, - reuse_dataloader=reuse_dataloader, - persistent_workers=persistent_workers, ) # level 0: sub-samplers 1: batch_idx 2: batches self._frozen_batches = tuple([tuple(sub_batch) for sub_batch in batch_samplers]) diff --git a/fairseq/data/mask_tokens_dataset.py b/fairseq/data/mask_tokens_dataset.py index 9123235594..0ca9051c9a 100644 --- a/fairseq/data/mask_tokens_dataset.py +++ b/fairseq/data/mask_tokens_dataset.py @@ -69,6 +69,7 @@ def __init__( mask_whole_words: torch.Tensor = None, mask_multiple_length: int = 1, mask_stdev: float = 0.0, + skip_masking: bool = False, ): assert 0.0 < mask_prob < 1.0 assert 0.0 <= random_token_prob <= 1.0 @@ -89,6 +90,7 @@ def __init__( self.mask_whole_words = mask_whole_words self.mask_multiple_length = mask_multiple_length self.mask_stdev = mask_stdev + self.skip_masking = skip_masking if random_token_prob > 0.0: if freq_weighted_replacement: @@ -113,108 +115,112 @@ def __getitem__(self, index: int): @lru_cache(maxsize=8) def __getitem_cached__(self, seed: int, epoch: int, index: int): - with data_utils.numpy_seed(self.seed, self.epoch, index): - item = self.dataset[index] - sz = len(item) - - assert ( - self.mask_idx not in item - ), "Dataset contains mask_idx (={}), this is not expected!".format( - self.mask_idx, - ) + seed = int(hash((seed, epoch, index)) % 1e6) + rng = np.random.default_rng(seed) + item = self.dataset[index] + sz = len(item) + + assert ( + self.mask_idx not in item + ), "Dataset contains mask_idx (={}), this is not expected!".format( + self.mask_idx, + ) + if self.skip_masking: + return torch.from_numpy(np.copy(item)) + + if self.mask_whole_words is not None: + word_begins_mask = self.mask_whole_words.gather(0, item) + word_begins_idx = word_begins_mask.nonzero().view(-1) + sz = len(word_begins_idx) + words = np.split(word_begins_mask, word_begins_idx)[1:] + assert len(words) == sz + word_lens = list(map(len, words)) + + # decide elements to mask + mask = np.full(sz, False) + num_mask = int( + # add a random number for probabilistic rounding + self.mask_prob * sz / float(self.mask_multiple_length) + + rng.random() + ) - if self.mask_whole_words is not None: - word_begins_mask = self.mask_whole_words.gather(0, item) - word_begins_idx = word_begins_mask.nonzero().view(-1) - sz = len(word_begins_idx) - words = np.split(word_begins_mask, word_begins_idx)[1:] - assert len(words) == sz - word_lens = list(map(len, words)) - - # decide elements to mask - mask = np.full(sz, False) - num_mask = int( - # add a random number for probabilistic rounding - self.mask_prob * sz / float(self.mask_multiple_length) - + np.random.rand() + # multiple masking as described in the vq-wav2vec paper (https://arxiv.org/abs/1910.05453) + mask_idc = rng.choice(sz, num_mask, replace=False) + if self.mask_stdev > 0.0: + lengths = rng.normal( + self.mask_multiple_length, self.mask_stdev, size=num_mask + ) + lengths = [max(0, int(round(x))) for x in lengths] + mask_idc = np.asarray( + [ + mask_idc[j] + offset + for j in range(len(mask_idc)) + for offset in range(lengths[j]) + ], + dtype=np.int64, + ) + else: + mask_idc = np.concatenate( + [mask_idc + i for i in range(self.mask_multiple_length)] ) + mask_idc = mask_idc[mask_idc < len(mask)] + try: + mask[mask_idc] = True + except: # something wrong + print("Assigning mask indexes {} to mask {} failed!".format(mask_idc, mask)) + raise + + # if self.return_masked_tokens: + # print(( + # f"IDX={index}; seed={seed}; epoch={epoch}; is_tgt={self.return_masked_tokens}: " + # f"{np.nonzero(mask)[0].sum()}" + # )) + if self.return_masked_tokens: + # exit early if we're just returning the masked tokens + # (i.e., the targets for masked LM training) + if self.mask_whole_words is not None: + mask = np.repeat(mask, word_lens) + new_item = np.full(len(mask), self.pad_idx) + new_item[mask] = item[torch.from_numpy(mask.astype(np.uint8)) == 1] + return torch.from_numpy(new_item) - # multiple masking as described in the vq-wav2vec paper (https://arxiv.org/abs/1910.05453) - mask_idc = np.random.choice(sz, num_mask, replace=False) - if self.mask_stdev > 0.0: - lengths = np.random.normal( - self.mask_multiple_length, self.mask_stdev, size=num_mask - ) - lengths = [max(0, int(round(x))) for x in lengths] - mask_idc = np.asarray( - [ - mask_idc[j] + offset - for j in range(len(mask_idc)) - for offset in range(lengths[j]) - ], - dtype=np.int64, - ) + # decide unmasking and random replacement + rand_or_unmask_prob = self.random_token_prob + self.leave_unmasked_prob + if rand_or_unmask_prob > 0.0: + rand_or_unmask = mask & (rng.random(sz) < rand_or_unmask_prob) + if self.random_token_prob == 0.0: + unmask = rand_or_unmask + rand_mask = None + elif self.leave_unmasked_prob == 0.0: + unmask = None + rand_mask = rand_or_unmask else: - mask_idc = np.concatenate( - [mask_idc + i for i in range(self.mask_multiple_length)] - ) - mask_idc = mask_idc[mask_idc < len(mask)] - try: - mask[mask_idc] = True - except: # something wrong - print( - "Assigning mask indexes {} to mask {} failed!".format( - mask_idc, mask - ) - ) - raise - - if self.return_masked_tokens: - # exit early if we're just returning the masked tokens - # (i.e., the targets for masked LM training) + unmask_prob = self.leave_unmasked_prob / rand_or_unmask_prob + decision = rng.random(sz) < unmask_prob + unmask = rand_or_unmask & decision + rand_mask = rand_or_unmask & (~decision) + else: + unmask = rand_mask = None + + if unmask is not None: + mask = mask ^ unmask + + if self.mask_whole_words is not None: + mask = np.repeat(mask, word_lens) + + new_item = np.copy(item) + new_item[mask] = self.mask_idx + if rand_mask is not None: + num_rand = rand_mask.sum() + if num_rand > 0: if self.mask_whole_words is not None: - mask = np.repeat(mask, word_lens) - new_item = np.full(len(mask), self.pad_idx) - new_item[mask] = item[torch.from_numpy(mask.astype(np.uint8)) == 1] - return torch.from_numpy(new_item) - - # decide unmasking and random replacement - rand_or_unmask_prob = self.random_token_prob + self.leave_unmasked_prob - if rand_or_unmask_prob > 0.0: - rand_or_unmask = mask & (np.random.rand(sz) < rand_or_unmask_prob) - if self.random_token_prob == 0.0: - unmask = rand_or_unmask - rand_mask = None - elif self.leave_unmasked_prob == 0.0: - unmask = None - rand_mask = rand_or_unmask - else: - unmask_prob = self.leave_unmasked_prob / rand_or_unmask_prob - decision = np.random.rand(sz) < unmask_prob - unmask = rand_or_unmask & decision - rand_mask = rand_or_unmask & (~decision) - else: - unmask = rand_mask = None - - if unmask is not None: - mask = mask ^ unmask + rand_mask = np.repeat(rand_mask, word_lens) + num_rand = rand_mask.sum() - if self.mask_whole_words is not None: - mask = np.repeat(mask, word_lens) - - new_item = np.copy(item) - new_item[mask] = self.mask_idx - if rand_mask is not None: - num_rand = rand_mask.sum() - if num_rand > 0: - if self.mask_whole_words is not None: - rand_mask = np.repeat(rand_mask, word_lens) - num_rand = rand_mask.sum() - - new_item[rand_mask] = np.random.choice( - len(self.vocab), - num_rand, - p=self.weights, - ) + new_item[rand_mask] = rng.choice( + len(self.vocab), + num_rand, + p=self.weights, + ) - return torch.from_numpy(new_item) + return torch.from_numpy(new_item) diff --git a/fairseq/data/padding_mask_dataset.py b/fairseq/data/padding_mask_dataset.py new file mode 100644 index 0000000000..d7f7b88dbb --- /dev/null +++ b/fairseq/data/padding_mask_dataset.py @@ -0,0 +1,38 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import torch + +from fairseq.data import data_utils +from . import BaseWrapperDataset + + +class PaddingMaskDataset(BaseWrapperDataset): + def __init__(self, dataset, left_pad, pad_length=None): + super().__init__(dataset) + self.left_pad = left_pad + self.pad_length = pad_length + + def __getitem__(self, index): + item = self.dataset[index] + return torch.zeros_like(item).bool() + + def __len__(self): + return len(self.dataset) + + def collater(self, samples): + return data_utils.collate_tokens( + samples, True, left_pad=self.left_pad, pad_to_length=self.pad_length + ) + + +class LeftPaddingMaskDataset(PaddingMaskDataset): + def __init__(self, dataset): + super().__init__(dataset, left_pad=True) + + +class RightPaddingMaskDataset(PaddingMaskDataset): + def __init__(self, dataset): + super().__init__(dataset, left_pad=False) diff --git a/fairseq/data/subsample_dataset.py b/fairseq/data/subsample_dataset.py index 48feaf883f..fe5c7e2ac8 100644 --- a/fairseq/data/subsample_dataset.py +++ b/fairseq/data/subsample_dataset.py @@ -3,9 +3,11 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import contextlib import logging import numpy as np +from fairseq.data.data_utils import numpy_seed from . import BaseWrapperDataset @@ -21,13 +23,14 @@ class SubsampleDataset(BaseWrapperDataset): size_ratio(float): the ratio to subsample to. must be between 0 and 1 (exclusive) """ - def __init__(self, dataset, size_ratio, shuffle=False): + def __init__(self, dataset, size_ratio, shuffle=False, seed=None): super().__init__(dataset) assert size_ratio < 1 self.actual_size = np.ceil(len(dataset) * size_ratio).astype(int) - self.indices = np.random.choice( - list(range(len(self.dataset))), self.actual_size, replace=False - ) + with numpy_seed(seed) if seed is not None else contextlib.ExitStack(): + self.indices = np.random.choice( + list(range(len(self.dataset))), self.actual_size, replace=False + ) self.shuffle = shuffle logger.info( "subsampled dataset from {} to {} (ratio={})".format( diff --git a/fairseq/dataclass/configs.py b/fairseq/dataclass/configs.py index 5fdfab38d3..af957fec64 100644 --- a/fairseq/dataclass/configs.py +++ b/fairseq/dataclass/configs.py @@ -636,6 +636,7 @@ class OptimizationConfig(FairseqDataclass): " (default is to skip it)." }, ) + debug_param_names: bool = False @dataclass diff --git a/fairseq/dataclass/utils.py b/fairseq/dataclass/utils.py index 69b77962e6..f6467d5f40 100644 --- a/fairseq/dataclass/utils.py +++ b/fairseq/dataclass/utils.py @@ -487,15 +487,22 @@ def overwrite_args_by_name(cfg: DictConfig, overrides: Dict[str, any]): def merge_with_parent(dc: FairseqDataclass, cfg: DictConfig, remove_missing=False): if remove_missing: - if is_dataclass(dc): - target_keys = set(dc.__dataclass_fields__.keys()) - else: - target_keys = set(dc.keys()) + def remove_missing_rec(src_keys, target_cfg): + if is_dataclass(target_cfg): + target_keys = set(target_cfg.__dataclass_fields__.keys()) + else: + target_keys = set(target_cfg.keys()) - with open_dict(cfg): - for k in list(cfg.keys()): + for k in list(src_keys.keys()): if k not in target_keys: - del cfg[k] + del src_keys[k] + elif OmegaConf.is_config(src_keys[k]): + tgt = getattr(target_cfg, k) + if tgt is not None and (is_dataclass(tgt) or hasattr(tgt, "keys")): + remove_missing_rec(src_keys[k], tgt) + + with open_dict(cfg): + remove_missing_rec(cfg, dc) merged_cfg = OmegaConf.merge(dc, cfg) merged_cfg.__dict__["_parent"] = cfg.__dict__["_parent"] diff --git a/fairseq/distributed/utils.py b/fairseq/distributed/utils.py index 2c52f76aa7..968830d585 100644 --- a/fairseq/distributed/utils.py +++ b/fairseq/distributed/utils.py @@ -51,18 +51,21 @@ def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False): if cfg.pipeline_model_parallel: num_pipeline_devices, num_pipelines_per_node = _pipeline_parallel_pre_init(cfg) + if cfg.distributed_world_size == 1: + return if all( key in os.environ for key in ["MASTER_ADDR", "MASTER_PORT", "WORLD_SIZE", "RANK"] ): # support torch.distributed.launch _infer_torch_distributed_launch_init(cfg) - elif cfg.distributed_port > 0: + else: # we can determine the init method automatically for Slurm - _infer_slurm_init(cfg, num_pipelines_per_node) - elif cfg.distributed_world_size > 1 or force_distributed: - # fallback for single node with multiple GPUs - _infer_single_node_init(cfg) + if not _infer_slurm_init(cfg, num_pipelines_per_node): + if cfg.distributed_port <= 0 or force_distributed: + _infer_single_node_init(cfg) + elif cfg.distributed_port <= 0: + _infer_single_node_init(cfg) if cfg.pipeline_model_parallel: _pipeline_parallel_post_init(cfg, num_pipeline_devices, num_pipelines_per_node) @@ -71,12 +74,21 @@ def infer_init_method(cfg: DistributedTrainingConfig, force_distributed=False): cfg.distributed_num_procs = min( torch.cuda.device_count(), cfg.distributed_world_size ) + else: + if cfg.device_id > 0: + logger.info( + "setting CUDA device={} on rank {}".format( + cfg.device_id, cfg.distributed_rank + ) + ) + torch.cuda.set_device(cfg.device_id) def _infer_torch_distributed_launch_init(cfg: DistributedTrainingConfig): cfg.distributed_init_method = "env://" cfg.distributed_world_size = int(os.environ["WORLD_SIZE"]) cfg.distributed_rank = int(os.environ["RANK"]) + cfg.device_id = cfg.distributed_rank % torch.cuda.device_count() # processes are created by torch.distributed.launch cfg.distributed_no_spawn = True @@ -127,22 +139,44 @@ def _infer_slurm_init(cfg: DistributedTrainingConfig, num_pipelines_per_node): # number of pipelines across all nodes. cfg.distributed_world_size = nnodes * num_pipelines_per_node else: - assert ntasks_per_node == cfg.distributed_world_size // nnodes + assert ( + ntasks_per_node == cfg.distributed_world_size // nnodes + ), f"{ntasks_per_node}, {cfg.distributed_world_size}, {nnodes}" cfg.distributed_no_spawn = True cfg.distributed_rank = int(os.environ.get("SLURM_PROCID")) cfg.device_id = int(os.environ.get("SLURM_LOCALID")) + logger.info(f"Rank {cfg.distributed_rank}, device_id: {cfg.device_id}") + return True except subprocess.CalledProcessError as e: # scontrol failed raise e except FileNotFoundError: # Slurm is not installed pass + return False + def _infer_single_node_init(cfg: DistributedTrainingConfig): assert ( cfg.distributed_world_size <= torch.cuda.device_count() ), f"world size is {cfg.distributed_world_size} but have {torch.cuda.device_count()} available devices" - port = random.randint(10000, 20000) - cfg.distributed_init_method = "tcp://localhost:{port}".format(port=port) + + if cfg.distributed_port <= 0: + jobid = os.environ.get("SLURM_JOB_ID") + task_id = os.environ.get("SLURM_ARRAY_TASK_ID") + + if jobid is not None: + if task_id is not None: + jobid += str(task_id) + jobid = int(jobid) + rng = random.Random(jobid) + port = rng.randint(10000, 60000) + else: + port = random.randint(10000, 60000) + + cfg.distributed_port = port + cfg.distributed_init_method = "tcp://localhost:{port}".format( + port=cfg.distributed_port + ) def _pipeline_parallel_pre_init(cfg: DistributedTrainingConfig): @@ -341,6 +375,7 @@ def call_main(cfg: FairseqConfig, main, **kwargs): start_rank = cfg.distributed_training.distributed_rank cfg.distributed_training.distributed_rank = None # assign automatically kwargs["start_rank"] = start_rank + torch.multiprocessing.spawn( fn=distributed_main, args=(main, cfg, kwargs), diff --git a/fairseq/iterative_refinement_generator.py b/fairseq/iterative_refinement_generator.py index 4fb0946f49..3d32c6bf4d 100644 --- a/fairseq/iterative_refinement_generator.py +++ b/fairseq/iterative_refinement_generator.py @@ -235,7 +235,7 @@ def finalized_hypos(step, prev_out_token, prev_out_score, prev_out_attn): terminated.fill_(1) # collect finalized sentences - finalized_idxs = sent_idxs[terminated] + finalized_idxs = sent_idxs[terminated.to(sent_idxs.device)] finalized_tokens = decoder_out.output_tokens[terminated] finalized_scores = decoder_out.output_scores[terminated] finalized_attn = ( @@ -285,7 +285,7 @@ def finalized_hypos(step, prev_out_token, prev_out_score, prev_out_attn): encoder_out = model.encoder.reorder_encoder_out( encoder_out, not_terminated.nonzero(as_tuple=False).squeeze() ) - sent_idxs = sent_idxs[not_terminated] + sent_idxs = sent_idxs[not_terminated.to(sent_idxs.device)] prev_output_tokens = prev_decoder_out.output_tokens.clone() if self.beam_size > 1: diff --git a/fairseq/logging/meters.py b/fairseq/logging/meters.py index d5f7c775d9..495bd08300 100644 --- a/fairseq/logging/meters.py +++ b/fairseq/logging/meters.py @@ -139,6 +139,36 @@ def smoothed_value(self) -> float: return val +class ConcatTensorMeter(Meter): + """Concatenates tensors""" + + def __init__(self, dim=0): + super().__init__() + self.reset() + self.dim = dim + + def reset(self): + self.tensor = None + + def update(self, val): + if self.tensor is None: + self.tensor = val + else: + self.tensor = torch.cat([self.tensor, val], dim=self.dim) + + def state_dict(self): + return { + "tensor": self.tensor, + } + + def load_state_dict(self, state_dict): + self.tensor = state_dict["tensor"] + + @property + def smoothed_value(self) -> float: + return [] # return a dummy value + + class TimeMeter(Meter): """Computes the average occurrence of some event per second""" diff --git a/fairseq/logging/metrics.py b/fairseq/logging/metrics.py index 892b0ea4dd..49301f27f8 100644 --- a/fairseq/logging/metrics.py +++ b/fairseq/logging/metrics.py @@ -151,6 +151,26 @@ def log_scalar_sum( agg[key].update(value) +def log_concat_tensor( + key: str, + value: torch.Tensor, + priority: int = 10, + dim: int = 0, +): + """Log a scalar value that is summed for reporting. + + Args: + key (str): name of the field to log + value (float): value to log + priority (int): smaller values are logged earlier in the output + round (Optional[int]): number of digits to round to when displaying + """ + for agg in get_active_aggregators(): + if key not in agg: + agg.add_meter(key, ConcatTensorMeter(dim=dim), priority) + agg[key].update(value) + + def log_derived(key: str, fn: Callable[[MetersDict], float], priority: int = 20): """Log a scalar value derived from other meters. diff --git a/fairseq/models/__init__.py b/fairseq/models/__init__.py index 616e3051e9..11cf6ee530 100644 --- a/fairseq/models/__init__.py +++ b/fairseq/models/__init__.py @@ -128,7 +128,8 @@ class LSTM(FairseqEncoderDecoderModel): def register_model_cls(cls): if name in MODEL_REGISTRY: - raise ValueError("Cannot register duplicate model ({})".format(name)) + return MODEL_REGISTRY[name] + if not issubclass(cls, BaseFairseqModel): raise ValueError( "Model ({}: {}) must extend BaseFairseqModel".format(name, cls.__name__) diff --git a/fairseq/models/fairseq_model.py b/fairseq/models/fairseq_model.py index 42f9134a3e..65ead9dcf2 100644 --- a/fairseq/models/fairseq_model.py +++ b/fairseq/models/fairseq_model.py @@ -160,6 +160,11 @@ def set_num_updates(self, num_updates): if hasattr(m, "set_num_updates") and m != self: m.set_num_updates(num_updates) + def set_epoch(self, epoch): + for m in self.modules(): + if hasattr(m, "set_epoch") and m != self: + m.set_epoch(epoch) + def prepare_for_inference_(self, cfg: DictConfig): """Prepare model for inference.""" kwargs = {} diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index 9d3ffa1544..bf261624e6 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -47,6 +47,7 @@ class Wav2Vec2AsrConfig(FairseqDataclass): default=0.0, metadata={"help": "dropout to apply to the input (after feat extr)"}, ) + final_dropout: float = field( default=0.0, metadata={"help": "dropout after transformer and before final projection"}, @@ -66,19 +67,6 @@ class Wav2Vec2AsrConfig(FairseqDataclass): "help": "dropout probability after activation in FFN inside wav2vec 2.0 model" }, ) - conv_feature_layers: Optional[str] = field( - default="[(512, 10, 5)] + [(512, 3, 2)] * 4 + [(512,2,2)] + [(512,2,2)]", - metadata={ - "help": ( - "string describing convolutional feature extraction " - "layers in form of a python list that contains " - "[(dim, kernel_size, stride), ...]" - ), - }, - ) - encoder_embed_dim: Optional[int] = field( - default=768, metadata={"help": "encoder embedding dimension"} - ) # masking apply_mask: bool = field( @@ -152,12 +140,14 @@ class Wav2Vec2AsrConfig(FairseqDataclass): layerdrop: float = field( default=0.0, metadata={"help": "probability of dropping a layer in wav2vec 2.0"} ) + drop_path: float = 0 mask_channel_min_space: Optional[int] = field( default=1, metadata={"help": "min space between spans (if no overlap is enabled)"}, ) mask_channel_before: bool = False normalize: bool = II("task.normalize") + update_alibi: bool = True data: str = II("task.data") # this holds the loaded wav2vec args w2v_args: Any = None @@ -182,6 +172,11 @@ class Wav2Vec2AsrConfig(FairseqDataclass): ) ddp_backend: str = II("distributed_training.ddp_backend") + zero_mask: bool = False + load_ema: bool = False + + layer_decay: float = 1 + @dataclass class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): @@ -224,6 +219,12 @@ def get_logits(self, net_output, normalize=False): number_of_classes, device=logits.device ) * float("-inf") masking_tensor[0] = 0 + + if logits.size(0) > net_output["padding_mask"].size(1): + net_output["padding_mask"] = F.pad( + net_output["padding_mask"], (1, 0), value=False + ) + logits[net_output["padding_mask"].T] = masking_tensor.type_as(logits) if normalize: @@ -371,6 +372,19 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): "checkpoint_activations": cfg.checkpoint_activations, "offload_activations": cfg.offload_activations, "min_params_to_wrap": cfg.min_params_to_wrap, + # d2v multi args + "encoder_dropout": cfg.dropout, + "drop_path": getattr(cfg, "drop_path", 0), + "mask_dropout": getattr(cfg, "mask_dropout", 0), + "zero_mask": getattr(cfg, "zero_mask", False), + "local_grad_mult": cfg.feature_grad_mult, + "layerdrop": cfg.layerdrop, + "prenet_layerdrop": cfg.layerdrop, + "prenet_dropout": cfg.dropout, + "post_mlp_drop": cfg.dropout, + "encoder_zero_mask": getattr(cfg, "zero_mask", False), + "inverse_mask": False, + "learned_alibi_scale": getattr(cfg, "update_alibi", True), } if cfg.w2v_args is None: @@ -380,6 +394,7 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): w2v_args = convert_namespace_to_omegaconf(state["args"]) w2v_args.criterion = None w2v_args.lr_scheduler = None + cfg.w2v_args = w2v_args logger.info(w2v_args) @@ -390,31 +405,52 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): if isinstance(w2v_args, Namespace): cfg.w2v_args = w2v_args = convert_namespace_to_omegaconf(w2v_args) - model_normalized = w2v_args.task.get( - "normalize", w2v_args.model.get("normalize", False) - ) - assert cfg.normalize == model_normalized, ( - "Fine-tuning works best when data normalization is the same. " - "Please check that --normalize is set or unset for both pre-training and here" - ) + self.is_d2v_multi = "data2vec_multi" in w2v_args.model.get("_name", None) + + if not self.is_d2v_multi: + model_normalized = w2v_args.task.get( + "normalize", w2v_args.model.get("normalize", False) + ) + assert cfg.normalize == model_normalized, ( + "Fine-tuning works best when data normalization is the same. " + "Please check that --normalize is set or unset for both pre-training and here" + ) + + if hasattr(cfg, "checkpoint_activations") and cfg.checkpoint_activations: + with open_dict(w2v_args): + w2v_args.model.checkpoint_activations = cfg.checkpoint_activations + + w2v_args.task.data = cfg.data + task = tasks.setup_task(w2v_args.task, from_checkpoint=True) + model = task.build_model(w2v_args.model, from_checkpoint=True) + + model.remove_pretraining_modules() + d = w2v_args.model.encoder_embed_dim + else: + assert cfg.normalize - if hasattr(cfg, "checkpoint_activations") and cfg.checkpoint_activations: - with open_dict(w2v_args): - w2v_args.model.checkpoint_activations = cfg.checkpoint_activations + if hasattr(w2v_args.task, "audio"): + w2v_args.task.audio.data = cfg.data + else: + w2v_args.task.data = cfg.data + task = tasks.setup_task(w2v_args.task, from_checkpoint=True) - w2v_args.task.data = cfg.data - task = tasks.setup_task(w2v_args.task) - model = task.build_model(w2v_args.model, from_checkpoint=True) + model = task.build_model(w2v_args.model, from_checkpoint=True) - model.remove_pretraining_modules() + model.remove_pretraining_modules(modality="audio") + d = w2v_args.model.embed_dim if state is not None and not cfg.no_pretrained_weights: + if cfg.load_ema: + assert "_ema" in state["model"] + for k in state["model"]["_ema"]: + mk = "encoder." + k + assert mk in state["model"], mk + state["model"][mk] = state["model"]["_ema"][k] self.load_model_weights(state, model, cfg) super().__init__(task.source_dictionary) - d = w2v_args.model.encoder_embed_dim - self.w2v_model = model self.final_dropout = nn.Dropout(cfg.final_dropout) @@ -432,6 +468,29 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): if targ_d is not None: self.proj = Linear(d, targ_d) + layer_decay = getattr(cfg, "layer_decay", 1) + if layer_decay < 1: + mod_encs = list(model.modality_encoders.values()) + assert len(mod_encs) == 1, len(mod_encs) + blocks = list(mod_encs[0].context_encoder.blocks) + list(model.blocks) + num_layers = len(blocks) + 1 + layer_scales = list( + layer_decay ** (num_layers - i) for i in range(num_layers + 1) + ) + + for i, b in enumerate(blocks): + lid = i + 1 + if layer_scales[lid] == 1.0: + continue + + for n, p in b.named_parameters(): + optim_override = getattr(p, "optim_overrides", {}) + if "optimizer" not in optim_override: + optim_override["optimizer"] = {} + + optim_override["optimizer"]["lr_scale"] = layer_scales[lid] + p.optim_overrides = optim_override + def load_model_weights(self, state, model, cfg): if cfg.ddp_backend == "fully_sharded": from fairseq.distributed import FullyShardedDataParallel @@ -461,8 +520,25 @@ def load_model_weights(self, state, model, cfg): model.load_state_dict(new_big_dict, strict=False) else: - if "_ema" in state["model"]: - del state["model"]["_ema"] + to_delete = {"_ema", "target_proj", "decoder"} + for k in to_delete: + if k in state["model"]: + del state["model"][k] + + if hasattr(model, "modality_encoders"): + if "modality_encoders.AUDIO.encoder_mask" not in state["model"]: + model.modality_encoders["AUDIO"].encoder_mask = None + elif not cfg.zero_mask: + model.modality_encoders["AUDIO"].encoder_mask = None + del state["model"]["modality_encoders.AUDIO.encoder_mask"] + + for k in list(state["model"].keys()): + if k.startswith("modality_encoders.") and not k.startswith( + "modality_encoders.AUDIO" + ): + del state["model"][k] + + print(model) model.load_state_dict(state["model"], strict=True) def set_num_updates(self, num_updates): @@ -478,6 +554,9 @@ def forward(self, source, padding_mask, **kwargs): "mask": self.apply_mask and self.training, } + if self.is_d2v_multi: + w2v_args["mode"] = "AUDIO" + ft = self.freeze_finetune_updates <= self.num_updates with torch.no_grad() if not ft else contextlib.ExitStack(): @@ -626,6 +705,7 @@ def forward( - the decoder's output of shape `(batch, tgt_len, vocab)` - a dictionary with any model-specific outputs """ + if type(prev_output_tokens) == list: max_len = max((len(x) for x in prev_output_tokens)) tmp = torch.zeros( @@ -634,6 +714,7 @@ def forward( for (i, p) in enumerate(prev_output_tokens): tmp[i, : len(p)] = p prev_output_tokens = tmp + prev_output_tokens = prev_output_tokens.long() x, extra = self.extract_features( prev_output_tokens, encoder_out, incremental_state diff --git a/fairseq/modules/__init__.py b/fairseq/modules/__init__.py index 1df76ef24d..dcfda9b82a 100644 --- a/fairseq/modules/__init__.py +++ b/fairseq/modules/__init__.py @@ -32,7 +32,7 @@ from .lstm_cell_with_zoneout import LSTMCellWithZoneOut from .multihead_attention import MultiheadAttention from .positional_embedding import PositionalEmbedding -from .same_pad import SamePad +from .same_pad import SamePad, SamePad2d from .scalar_bias import ScalarBias from .sinusoidal_positional_embedding import SinusoidalPositionalEmbedding from .transformer_sentence_encoder_layer import TransformerSentenceEncoderLayer @@ -87,6 +87,7 @@ "MultiheadAttention", "PositionalEmbedding", "SamePad", + "SamePad2d", "ScalarBias", "SinusoidalPositionalEmbedding", "TransformerSentenceEncoderLayer", diff --git a/fairseq/modules/ema_module.py b/fairseq/modules/ema_module.py index a5b98861d8..f0ece842d4 100644 --- a/fairseq/modules/ema_module.py +++ b/fairseq/modules/ema_module.py @@ -11,8 +11,18 @@ import torch +from omegaconf import II from fairseq.dataclass import FairseqDataclass +try: + from amp_C import multi_tensor_l2norm + + multi_tensor_l2norm_available = True +except ImportError: + multi_tensor_l2norm_available = False + +logger = logging.getLogger(__name__) + @dataclass class EMAModuleConfig(FairseqDataclass): @@ -23,12 +33,21 @@ class EMAModuleConfig(FairseqDataclass): default=False, metadata={"help": "If true, store EMA model in fp32 even if model is in fp16"}, ) + add_missing_params: bool = True + log_norms: bool = False class EMAModule: """Exponential Moving Average of Fairseq Models""" - def __init__(self, model, config: EMAModuleConfig, device=None, skip_keys=None): + def __init__( + self, + model, + config: EMAModuleConfig, + copy_model=True, + device=None, + skip_keys=None, + ): """ @param model model to initialize the EMA with @param config EMAConfig object with configuration like @@ -37,11 +56,18 @@ def __init__(self, model, config: EMAModuleConfig, device=None, skip_keys=None): Otherwise EMA is in the same device as the model. """ - self.decay = config.ema_decay - self.model = copy.deepcopy(model) - self.model.requires_grad_(False) self.config = config + + if copy_model: + self.model = copy.deepcopy(model) + self.model.requires_grad_(False) + else: + self.model = model + + self.config = config + self.decay = config.ema_decay self.skip_keys = skip_keys or set() + self.add_missing_params = config.add_missing_params self.fp32_params = {} if device is not None: @@ -51,7 +77,8 @@ def __init__(self, model, config: EMAModuleConfig, device=None, skip_keys=None): if self.config.ema_fp32: self.build_fp32_params() - self.update_freq_counter = 0 + self.log_norms = config.log_norms and multi_tensor_l2norm_available + self.logs = {} def build_fp32_params(self, state_dict=None): """ @@ -74,9 +101,16 @@ def _to_float(t): for param_key in state_dict: if param_key in self.fp32_params: - self.fp32_params[param_key].copy_(state_dict[param_key]) + if param_key == "__sq_mom": + self.fp32_params[param_key] = state_dict[param_key] + else: + self.fp32_params[param_key].copy_(state_dict[param_key]) else: self.fp32_params[param_key] = _to_float(state_dict[param_key]) + if "__sq_mom" in self.fp32_params: + self.fp32_params["__sq_mom"][param_key] = torch.zeros_like( + self.fp32_params[param_key] + ) def restore(self, state_dict, build_fp32_params=False): """Load data from a model spec into EMA model""" @@ -84,8 +118,10 @@ def restore(self, state_dict, build_fp32_params=False): if build_fp32_params: self.build_fp32_params(state_dict) - def set_decay(self, decay): + def set_decay(self, decay, weight_decay=None): self.decay = decay + if weight_decay is not None: + self.weight_decay = weight_decay def get_decay(self): return self.decay @@ -98,9 +134,17 @@ def _step_internal(self, new_model): ema_params = ( self.fp32_params if self.config.ema_fp32 else self.model.state_dict() ) + + new_p = [] + ema_p = [] + for key, param in new_model.named_parameters(): if isinstance(param, dict): continue + + if not self.add_missing_params and key not in ema_params: + continue + try: ema_param = ema_params[key] except KeyError: @@ -119,18 +163,39 @@ def _step_internal(self, new_model): # Do not decay a model.version pytorch param continue + lr = 1 - decay + if key in self.skip_keys or not param.requires_grad: ema_params[key].copy_(param.to(dtype=ema_param.dtype).data) ema_param = ema_params[key] else: - ema_param.mul_(decay) - ema_param.add_(param.data.to(dtype=ema_param.dtype), alpha=1 - decay) + if self.log_norms: + new_p.append(param) + ema_p.append(ema_param) + + ema_param.mul_(1 - lr) + ema_param.add_(param.data.to(dtype=ema_param.dtype), alpha=lr) ema_state_dict[key] = ema_param for key, param in new_model.named_buffers(): ema_state_dict[key] = param + if self.log_norms: + if "model_norm" in self.logs: + self.prev_model_norm = self.logs["model_norm"] + + chunk_size = 2048 * 32 + has_inf = torch.zeros( + (1, 1), dtype=torch.int, device=next(new_model.parameters()).device + ) + + new_norm = multi_tensor_l2norm(chunk_size, has_inf, [new_p], False) + old_norm = multi_tensor_l2norm(chunk_size, has_inf, [ema_p], False) + + self.logs["model_norm"] = new_norm[0] + self.logs["ema_norm"] = old_norm[0] + self.restore(ema_state_dict, build_fp32_params=False) @torch.no_grad() diff --git a/fairseq/modules/gumbel_vector_quantizer.py b/fairseq/modules/gumbel_vector_quantizer.py index 91655bc5e1..867b019f67 100644 --- a/fairseq/modules/gumbel_vector_quantizer.py +++ b/fairseq/modules/gumbel_vector_quantizer.py @@ -21,6 +21,8 @@ def __init__( activation=nn.GELU(), weight_proj_depth=1, weight_proj_factor=1, + hard=True, + std=0, ): """Vector quantization using gumbel softmax @@ -44,6 +46,7 @@ def __init__( self.input_dim = dim self.num_vars = num_vars self.time_first = time_first + self.hard = hard assert ( vq_dim % groups == 0 @@ -53,7 +56,10 @@ def __init__( num_groups = groups if not combine_groups else 1 self.vars = nn.Parameter(torch.FloatTensor(1, num_groups * num_vars, var_dim)) - nn.init.uniform_(self.vars) + if std == 0: + nn.init.uniform_(self.vars) + else: + nn.init.normal_(self.vars, mean=0, std=std) if weight_proj_depth > 1: @@ -151,16 +157,17 @@ def forward(self, x, produce_targets=False): x = self.weight_proj(x) x = x.view(bsz * tsz * self.groups, -1) - _, k = x.max(-1) - hard_x = ( - x.new_zeros(*x.shape) - .scatter_(-1, k.view(-1, 1), 1.0) - .view(bsz * tsz, self.groups, -1) - ) - hard_probs = torch.mean(hard_x.float(), dim=0) - result["code_perplexity"] = torch.exp( - -torch.sum(hard_probs * torch.log(hard_probs + 1e-7), dim=-1) - ).sum() + with torch.no_grad(): + _, k = x.max(-1) + hard_x = ( + x.new_zeros(*x.shape) + .scatter_(-1, k.view(-1, 1), 1.0) + .view(bsz * tsz, self.groups, -1) + ) + hard_probs = torch.mean(hard_x.float(), dim=0) + result["code_perplexity"] = torch.exp( + -torch.sum(hard_probs * torch.log(hard_probs + 1e-7), dim=-1) + ).sum() avg_probs = torch.softmax( x.view(bsz * tsz, self.groups, -1).float(), dim=-1 @@ -172,7 +179,9 @@ def forward(self, x, produce_targets=False): result["temp"] = self.curr_temp if self.training: - x = F.gumbel_softmax(x.float(), tau=self.curr_temp, hard=True).type_as(x) + x = F.gumbel_softmax(x.float(), tau=self.curr_temp, hard=self.hard).type_as( + x + ) else: x = hard_x diff --git a/fairseq/modules/kmeans_vector_quantizer.py b/fairseq/modules/kmeans_vector_quantizer.py index 040db1e83e..1015c38999 100644 --- a/fairseq/modules/kmeans_vector_quantizer.py +++ b/fairseq/modules/kmeans_vector_quantizer.py @@ -100,15 +100,16 @@ def forward(self, x, produce_targets=False): assert ze.shape == zq.shape, (ze.shape, zq.shape) x = self._pass_grad(ze, zq) - hard_x = ( - idx.new_zeros(bsz * tsz * self.groups, self.num_vars) - .scatter_(-1, idx.view(-1, 1), 1.0) - .view(bsz * tsz, self.groups, -1) - ) - hard_probs = torch.mean(hard_x.float(), dim=0) - result["code_perplexity"] = torch.exp( - -torch.sum(hard_probs * torch.log(hard_probs + 1e-7), dim=-1) - ).sum() + with torch.no_grad(): + hard_x = ( + idx.new_zeros(bsz * tsz * self.groups, self.num_vars) + .scatter_(-1, idx.view(-1, 1), 1.0) + .view(bsz * tsz, self.groups, -1) + ) + hard_probs = torch.mean(hard_x.float(), dim=0) + result["code_perplexity"] = torch.exp( + -torch.sum(hard_probs * torch.log(hard_probs + 1e-7), dim=-1) + ).sum() if produce_targets: result["targets"] = idx diff --git a/fairseq/modules/multihead_attention.py b/fairseq/modules/multihead_attention.py index 1cf3abe945..262132dfe7 100644 --- a/fairseq/modules/multihead_attention.py +++ b/fairseq/modules/multihead_attention.py @@ -551,7 +551,7 @@ def forward( self.out_proj.weight, self.out_proj.bias, self.training or self.dropout_module.apply_during_inference, - key_padding_mask, + key_padding_mask.bool() if key_padding_mask is not None else None, need_weights, attn_mask, use_separate_proj_weight=True, diff --git a/fairseq/modules/same_pad.py b/fairseq/modules/same_pad.py index 4c04990ea6..a3ce4131c6 100644 --- a/fairseq/modules/same_pad.py +++ b/fairseq/modules/same_pad.py @@ -19,3 +19,15 @@ def forward(self, x): if self.remove > 0: x = x[:, :, : -self.remove] return x + + +class SamePad2d(nn.Module): + def __init__(self, kernel_size): + super().__init__() + self.remove = 1 if kernel_size % 2 == 0 else 0 + + def forward(self, x): + assert len(x.size()) == 4 + if self.remove > 0: + x = x[:, :, : -self.remove, : -self.remove] + return x diff --git a/fairseq/modules/transpose_last.py b/fairseq/modules/transpose_last.py index e578b3ec50..d7cca9a4bb 100644 --- a/fairseq/modules/transpose_last.py +++ b/fairseq/modules/transpose_last.py @@ -10,11 +10,12 @@ class TransposeLast(nn.Module): - def __init__(self, deconstruct_idx=None): + def __init__(self, deconstruct_idx=None, tranpose_dim=-2): super().__init__() self.deconstruct_idx = deconstruct_idx + self.tranpose_dim = tranpose_dim def forward(self, x): if self.deconstruct_idx is not None: x = x[self.deconstruct_idx] - return x.transpose(-2, -1) + return x.transpose(self.tranpose_dim, -1) diff --git a/fairseq/nan_detector.py b/fairseq/nan_detector.py index 7d46d766d2..bd0f911073 100644 --- a/fairseq/nan_detector.py +++ b/fairseq/nan_detector.py @@ -38,7 +38,7 @@ def __exit__(self, exc_type, exc_value, exc_traceback): for name, param in self.named_parameters: if param.grad is not None: grad_norm = torch.norm(param.grad.data.float(), p=2) - norm[name] = grad_norm.item() + norm[name] = param.norm().item() if torch.isnan(grad_norm).any() or torch.isinf(grad_norm).any(): gradients[name] = param.grad.data if len(gradients) > 0: diff --git a/fairseq/optim/composite.py b/fairseq/optim/composite.py index 63701ee8b1..1ef0114ed6 100644 --- a/fairseq/optim/composite.py +++ b/fairseq/optim/composite.py @@ -13,6 +13,7 @@ from fairseq.optim import FairseqOptimizer, register_optimizer, _build_optimizer from fairseq.optim.lr_scheduler import FairseqLRScheduler, build_lr_scheduler from omegaconf import II, open_dict +import copy logger = logging.getLogger(__name__) @@ -37,6 +38,12 @@ class CompositeOptimizerConfig(FairseqDataclass): "Configures a different optimizer and (optionally) lr scheduler for each parameter group" }, ) + dynamic_groups: bool = field( + default=False, + metadata={ + "help": "create groups dynamically based on parameters, if set to False, all parameters needs to have group_names" + }, + ) @register_optimizer("composite", dataclass=CompositeOptimizerConfig) @@ -54,31 +61,107 @@ def __init__(self, cfg: CompositeOptimizerConfig, params): len(params) > 1 ), "Composite optimizer only works when there are multiple parameter groups (try fp16_no_flatten_grads: true)" - groupped_params = defaultdict(list) - for p in params: - group = getattr(p, "param_group", "default") - groupped_params[group].append(p) + def dict_hash(dictionary: Dict[str, Any]) -> str: + import hashlib + import json - assert groupped_params.keys() == cfg.groups.keys(), ( - f"Parameter groups {groupped_params.keys()} and optimizer groups {cfg.groups.keys()} are not the same! " - "Try setting 'param_group' on your parameters in the model." - ) + dhash = hashlib.md5() + encoded = json.dumps(dictionary, sort_keys=True).encode() + dhash.update(encoded) + return dhash.hexdigest() - for group, group_params in groupped_params.items(): - group_cfg = cfg.groups[group] - with open_dict(group_cfg): - if group_cfg.lr_float is not None: - group_cfg.optimizer.lr = [group_cfg.lr_float] - group_cfg.lr_scheduler.lr = [group_cfg.lr_float] + groupped_params = defaultdict(list) + overrides = defaultdict(dict) + if not cfg.dynamic_groups: + for p in params: + group = getattr(p, "param_group", "default") + override_config = getattr(p, "optim_overrides", None) + if override_config is not None and bool(override_config): + overrides[group] = override_config + else: + assert ( + override_config == None or override_config == overrides[group] + ), f"For group {group}, different overrides found {override_config} v/s {overrides[group]}" + groupped_params[group].append(p) + + for p, params in groupped_params.items(): + override_config = getattr(params[0], "optim_overrides", None) + if override_config is not None: + for pp in params[1:]: + assert override_config == getattr( + pp, "optim_overrides", None + ), f" {str(override_config)} != {str(getattr(pp, 'optim_overrides', None))}" + else: + for p in params: + group = getattr(p, "param_group", "default") + override_config = getattr(p, "optim_overrides", None) + if override_config is not None: + override_config["group_name"] = group + group_name = dict_hash(override_config) + overrides[group_name] = override_config else: - group_cfg.optimizer.lr = group_cfg.lr - group_cfg.lr_scheduler.lr = group_cfg.lr - self.optimizers[group] = _build_optimizer(group_cfg.optimizer, group_params) - if group_cfg.lr_scheduler is not None: + group_name = group + groupped_params[group_name].append(p) + + self.optimizers_config = {} + for group, group_params in groupped_params.items(): + p_group = group + if group in overrides and "group_name" in overrides[group]: + p_group = overrides[group]["group_name"] + if group in cfg.groups: + group_cfg = cfg.groups[group] + optimizer_config = copy.deepcopy(group_cfg.optimizer) + scheduler_config = copy.deepcopy(group_cfg.lr_scheduler) + explicit_group_present = True + else: + group_cfg = cfg.groups[p_group] + optimizer_config = copy.deepcopy(group_cfg.optimizer) + scheduler_config = copy.deepcopy(group_cfg.lr_scheduler) + explicit_group_present = False + + if getattr(group_cfg, "lr_float", None) is not None: + with open_dict(optimizer_config): + optimizer_config.lr = [group_cfg.lr_float] + + if group in overrides and "optimizer" in overrides[group]: + with open_dict(optimizer_config): + if "lr_scale" in overrides[group]["optimizer"]: + lr_scale = overrides[group]["optimizer"]["lr_scale"] + optimizer_config.lr = [ + lr * lr_scale for lr in optimizer_config.lr + ] + + if explicit_group_present: + logger.info( + f"For group:{group}, config as well as override present for lr" + ) + + if ( + "weight_decay_scale" in overrides[group]["optimizer"] + and "optimizer_config" in optimizer_config + ): + weight_decay_scale = overrides[group]["optimizer"][ + "weight_decay_scale" + ] + optimizer_config.weight_decay = ( + optimizer_config.weight_decay * weight_decay_scale + ) + if explicit_group_present: + logger.info( + f"For group:{group}, config as well as override present for weight_decay" + ) + + with open_dict(scheduler_config): + scheduler_config.lr = optimizer_config.lr + self.optimizers[group] = _build_optimizer(optimizer_config, group_params) + self.optimizers_config[group] = optimizer_config + if scheduler_config is not None: self.lr_schedulers[group] = build_lr_scheduler( - group_cfg.lr_scheduler, self.optimizers[group] + scheduler_config, self.optimizers[group] ) - + logger.info("Optimizers for different groups are as below") + for group in self.optimizers_config.keys(): + logger.info(f"Group : {group}:{self.optimizers_config[group]}") if len(self.lr_schedulers) > 0: assert len(self.lr_schedulers) == len(self.optimizers), ( f"Please provide an lr scheduler for each optimizer to use pass_through scheduler. " diff --git a/fairseq/optim/fp16_optimizer.py b/fairseq/optim/fp16_optimizer.py index 2c4ee326e9..6a4da342ca 100644 --- a/fairseq/optim/fp16_optimizer.py +++ b/fairseq/optim/fp16_optimizer.py @@ -72,6 +72,8 @@ def build_fp32_params(cls, args, params, flatten=True): p32.grad = torch.zeros_like(p32.data) if hasattr(p, "param_group"): p32.param_group = p.param_group + if hasattr(p, "optim_overrides"): + p32.optim_overrides = p.optim_overrides fp32_params.append(p32) return fp32_params @@ -194,6 +196,9 @@ def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): 0, aggregate_norm_fn ) + if torch.is_tensor(self._multiply_factor): + self._multiply_factor = self._multiply_factor.to(grad_norm.device) + if self.scaler is not None: if grad_norm > max_norm > 0.0: self._multiply_factor *= max_norm / grad_norm diff --git a/fairseq/optim/fused_adam.py b/fairseq/optim/fused_adam.py index 1290ecfdbf..39a2a83694 100644 --- a/fairseq/optim/fused_adam.py +++ b/fairseq/optim/fused_adam.py @@ -210,6 +210,9 @@ def step(self, closure=None, grads=None, scale=1.0, grad_norms=None): exp_avg_sq = exp_avg_sq.float() * state["exp_avg_sq_scale"] beta1, beta2 = group["betas"] + if "step" not in state: + state["step"] = group["step"] + state["step"] += 1 with torch.cuda.device(p_data_fp32.device): diff --git a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py index d01143498f..5fcaea25d4 100644 --- a/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py +++ b/fairseq/optim/lr_scheduler/cosine_lr_scheduler.py @@ -77,9 +77,8 @@ def __init__(self, cfg: CosineLRScheduleConfig, fairseq_optimizer): ) self.max_lr = cfg.lr[0] if isinstance(cfg.lr, Collection) else cfg.lr - assert ( - self.max_lr > cfg.min_lr - ), f"max_lr (={cfg.lr}) must be more than min_lr (={cfg.min_lr})" + if self.max_lr < cfg.min_lr: + cfg.min_lr = self.max_lr warmup_end_lr = self.max_lr if cfg.warmup_init_lr < 0: diff --git a/fairseq/registry.py b/fairseq/registry.py index f3b9406043..904ffcd602 100644 --- a/fairseq/registry.py +++ b/fairseq/registry.py @@ -36,8 +36,9 @@ def build_x(cfg: Union[DictConfig, str, Namespace], *extra_args, **extra_kwargs) choice = cfg._name if choice and choice in DATACLASS_REGISTRY: + from_checkpoint = extra_kwargs.get("from_checkpoint", False) dc = DATACLASS_REGISTRY[choice] - cfg = merge_with_parent(dc(), cfg) + cfg = merge_with_parent(dc(), cfg, remove_missing=from_checkpoint) elif isinstance(cfg, str): choice = cfg if choice in DATACLASS_REGISTRY: @@ -58,6 +59,9 @@ def build_x(cfg: Union[DictConfig, str, Namespace], *extra_args, **extra_kwargs) else: builder = cls + if "from_checkpoint" in extra_kwargs: + del extra_kwargs["from_checkpoint"] + return builder(cfg, *extra_args, **extra_kwargs) def register_x(name, dataclass=None): diff --git a/fairseq/tasks/__init__.py b/fairseq/tasks/__init__.py index 9a46b012c5..6da1f001f0 100644 --- a/fairseq/tasks/__init__.py +++ b/fairseq/tasks/__init__.py @@ -35,8 +35,9 @@ def setup_task(cfg: FairseqDataclass, **kwargs): task_name = getattr(cfg, "_name", None) if task_name and task_name in TASK_DATACLASS_REGISTRY: + remove_missing = "from_checkpoint" in kwargs and kwargs["from_checkpoint"] dc = TASK_DATACLASS_REGISTRY[task_name] - cfg = merge_with_parent(dc(), cfg) + cfg = merge_with_parent(dc(), cfg, remove_missing=remove_missing) task = TASK_REGISTRY[task_name] assert ( @@ -68,7 +69,8 @@ class ClassificationTask(FairseqTask): def register_task_cls(cls): if name in TASK_REGISTRY: - raise ValueError("Cannot register duplicate task ({})".format(name)) + return TASK_REGISTRY[name] + if not issubclass(cls, FairseqTask): raise ValueError( "Task ({}: {}) must extend FairseqTask".format(name, cls.__name__) diff --git a/fairseq/tasks/audio_finetuning.py b/fairseq/tasks/audio_finetuning.py index 5e04a1b796..77634f1bae 100644 --- a/fairseq/tasks/audio_finetuning.py +++ b/fairseq/tasks/audio_finetuning.py @@ -100,6 +100,7 @@ class AudioFinetuningConfig(AudioPretrainingConfig): "adds 'prev_output_tokens' to input and appends eos to target" }, ) + rebuild_batches: bool = True @register_task("audio_finetuning", dataclass=AudioFinetuningConfig) diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index a55c704006..e6de0666ad 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -12,9 +12,9 @@ from argparse import Namespace from dataclasses import dataclass, field from typing import Optional -from omegaconf import MISSING, II, OmegaConf +from omegaconf import MISSING, II -from fairseq.data import BinarizedAudioDataset, FileAudioDataset +from fairseq.data import BinarizedAudioDataset, FileAudioDataset, SubsampleDataset from fairseq.dataclass import FairseqDataclass, ChoiceEnum from fairseq.data.text_compressor import TextCompressionLevel @@ -25,24 +25,16 @@ @dataclass -class InferredW2vConfig: - # The following are needed to precompute mask and mask channel indices - # before model's forward. - mask_length: Optional[int] = II("model.mask_length") - mask_prob: Optional[float] = II("model.mask_prob") - mask_selection: Optional[str] = II("model.mask_selection") - mask_other: Optional[float] = II("model.mask_other") - no_mask_overlap: Optional[bool] = II("model.no_mask_overlap") - mask_min_space: Optional[int] = II("model.mask_min_space") - mask_channel_length: Optional[int] = II("model.mask_channel_length") - mask_channel_prob: Optional[float] = II("model.mask_channel_prob") - mask_channel_selection: Optional[str] = II("model.mask_channel_selection") - mask_channel_other: Optional[float] = II("model.mask_channel_other") - no_mask_channel_overlap: Optional[bool] = II("model.no_mask_channel_overlap") - mask_channel_min_space: Optional[int] = II("model.mask_channel_min_space") - - conv_feature_layers: Optional[str] = II("model.conv_feature_layers") - encoder_embed_dim: Optional[int] = II("model.encoder_embed_dim") +class AudioMaskingConfig: + feature_encoder_spec: str = II("model.modalities.audio.feature_encoder_spec") + mask_prob: float = II("model.modalities.audio.mask_prob") + mask_prob_adjust: float = II("model.modalities.audio.mask_prob_adjust") + mask_length: int = II("model.modalities.audio.mask_length") + inverse_mask: bool = II("model.modalities.audio.inverse_mask") + mask_dropout: float = II("model.modalities.audio.mask_dropout") + clone_batch: int = II("model.clone_batch") + expand_adjacent: bool = False + non_overlapping: bool = False @dataclass @@ -82,20 +74,6 @@ class AudioPretrainingConfig(FairseqDataclass): default=0, metadata={"help": "number of buckets"}, ) - precompute_mask_indices: bool = field( - default=False, - metadata={ - "help": "flag to compute mask indices in data preparation.", - }, - ) - - inferred_w2v_config: Optional[InferredW2vConfig] = field( - default=None, - metadata={ - "help": "wav2vec 2.0 masking arguments used to pre-compute masks (required for TPU)", - }, - ) - tpu: bool = II("common.tpu") text_compression_level: ChoiceEnum([x.name for x in TextCompressionLevel]) = field( default="none", @@ -105,6 +83,14 @@ class AudioPretrainingConfig(FairseqDataclass): }, ) + rebuild_batches: bool = True + precompute_mask_config: Optional[AudioMaskingConfig] = None + + post_save_script: Optional[str] = None + + subsample: float = 1 + seed: int = II("common.seed") + @register_task("audio_pretraining", dataclass=AudioPretrainingConfig) class AudioPretrainingTask(FairseqTask): @@ -122,17 +108,6 @@ def setup_task(cls, cfg: AudioPretrainingConfig, **kwargs): return cls(cfg) - def _get_mask_precompute_kwargs(self, cfg): - if self.cfg.precompute_mask_indices or self.cfg.tpu: - assert ( - cfg.inferred_w2v_config is not None - ), "inferred_w2v_config must be set" - return OmegaConf.to_container( - cfg.inferred_w2v_config, resolve=True, enum_to_str=True - ) - else: - return {} - def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): data_path = self.cfg.data task_cfg = task_cfg or self.cfg @@ -145,6 +120,12 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): text_compression_level = getattr( TextCompressionLevel, str(self.cfg.text_compression_level) ) + + compute_mask = task_cfg.precompute_mask_config is not None + mask_args = {} + if compute_mask: + mask_args = task_cfg.precompute_mask_config + if getattr(task_cfg, "binarized_dataset", False): self.datasets[split] = BinarizedAudioDataset( data_path, @@ -155,8 +136,8 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): pad=task_cfg.labels is not None or task_cfg.enable_padding, normalize=task_cfg.normalize, num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), - compute_mask_indices=(self.cfg.precompute_mask_indices or self.cfg.tpu), - **self._get_mask_precompute_kwargs(task_cfg), + compute_mask=compute_mask, + **mask_args, ) else: manifest_path = os.path.join(data_path, "{}.tsv".format(split)) @@ -169,9 +150,17 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): pad=task_cfg.labels is not None or task_cfg.enable_padding, normalize=task_cfg.normalize, num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), - compute_mask_indices=(self.cfg.precompute_mask_indices or self.cfg.tpu), text_compression_level=text_compression_level, - **self._get_mask_precompute_kwargs(task_cfg), + compute_mask=compute_mask, + **mask_args, + ) + + if getattr(task_cfg, "subsample", 1) < 1: + self.datasets[split] = SubsampleDataset( + self.datasets[split], + task_cfg.subsample, + shuffle=True, + seed=task_cfg.seed, ) if self.cfg.tpu and task_cfg.inferred_w2v_config.mask_channel_prob == 0.0: @@ -181,14 +170,6 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): "0. You may want to set this to a low value close to 0." ) - @property - def source_dictionary(self): - return None - - @property - def target_dictionary(self): - return None - def max_positions(self): """Maximum input length supported by the encoder.""" return sys.maxsize, sys.maxsize @@ -203,3 +184,24 @@ def build_model(self, model_cfg: FairseqDataclass, from_checkpoint=False): model_cfg.w2v_args = actualized_cfg.w2v_args return model + + def post_save(self, cp_path, num_updates): + if self.cfg.post_save_script is not None: + logger.info(f"launching {self.cfg.post_save_script}") + import os.path as osp + from fairseq.file_io import PathManager + + eval_cp_path = osp.join( + osp.dirname(cp_path), f"checkpoint_eval_{num_updates}.pt" + ) + + print(cp_path, eval_cp_path, osp.dirname(cp_path)) + + assert PathManager.copy( + cp_path, eval_cp_path, overwrite=True + ), f"Failed to copy {cp_path} to {eval_cp_path}" + + import subprocess + import shlex + + subprocess.call(shlex.split(f"{self.cfg.post_save_script} {eval_cp_path}")) diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 3cba8f224a..7481e0f4bf 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -272,6 +272,7 @@ def get_batch_iterator( and not update_epoch_batch_itr and self.can_reuse_epoch_itr(dataset) ) + logger.info(f"can_reuse_epoch_itr = {can_reuse_epoch_itr}") if can_reuse_epoch_itr and dataset in self.dataset_to_epoch_iter: logger.debug("reusing EpochBatchIterator for epoch {}".format(epoch)) return self.dataset_to_epoch_iter[dataset] @@ -281,26 +282,39 @@ def get_batch_iterator( # initialize the dataset with the correct starting epoch dataset.set_epoch(epoch) - # get indices ordered by example size - with data_utils.numpy_seed(seed): - indices = dataset.ordered_indices() + def make_batches(dataset, epoch): + logger.info(f"creating new batches for epoch {epoch}") - # filter examples that are too large - if max_positions is not None: - indices = self.filter_indices_by_size( - indices, dataset, max_positions, ignore_invalid_inputs - ) + # get indices ordered by example size + with data_utils.numpy_seed(seed + epoch): + indices = dataset.ordered_indices() - # create mini-batches with given size constraints - batch_sampler = dataset.batch_by_size( - indices, - max_tokens=max_tokens, - max_sentences=max_sentences, - required_batch_size_multiple=required_batch_size_multiple, - ) + # filter examples that are too large + if max_positions is not None: + indices = self.filter_indices_by_size( + indices, dataset, max_positions, ignore_invalid_inputs + ) + + # create mini-batches with given size constraints + batches = dataset.batch_by_size( + indices, + max_tokens=max_tokens, + max_sentences=max_sentences, + required_batch_size_multiple=required_batch_size_multiple, + ) + return batches reuse_dataloader = getattr(self.cfg, "reuse_dataloader", True) - persistent_workers = getattr(self.cfg, "persistent_workers", False) + persistent_workers = getattr(self.cfg, "persistent_workers", True) + rebuild_batches = getattr(self.cfg, "rebuild_batches", False) + logger.info(f"reuse_dataloader = {reuse_dataloader}") + logger.info(f"rebuild_batches = {rebuild_batches}") + + if rebuild_batches: + logger.info("batches will be rebuilt for each epoch") + batch_sampler = make_batches + else: + batch_sampler = make_batches(dataset, epoch) # return a reusable, sharded iterator epoch_iter = iterators.EpochBatchIterator( @@ -341,7 +355,7 @@ def build_model(self, cfg: FairseqDataclass, from_checkpoint=False): model = quantization_utils.quantize_model_scalar(model, cfg) return model - def build_criterion(self, cfg: DictConfig): + def build_criterion(self, cfg: DictConfig, from_checkpoint=False): """ Build the :class:`~fairseq.criterions.FairseqCriterion` instance for this task. @@ -354,7 +368,7 @@ def build_criterion(self, cfg: DictConfig): """ from fairseq import criterions - return criterions.build_criterion(cfg, self) + return criterions.build_criterion(cfg, self, from_checkpoint=from_checkpoint) def build_generator( self, @@ -614,13 +628,13 @@ def max_positions(self): def source_dictionary(self): """Return the source :class:`~fairseq.data.Dictionary` (if applicable for this task).""" - raise NotImplementedError + return None @property def target_dictionary(self): """Return the target :class:`~fairseq.data.Dictionary` (if applicable for this task).""" - raise NotImplementedError + return None def build_tokenizer(self, args): """Build the pre-tokenizer for this task.""" diff --git a/fairseq/tasks/masked_lm.py b/fairseq/tasks/masked_lm.py index 6393ee4800..b064907a50 100644 --- a/fairseq/tasks/masked_lm.py +++ b/fairseq/tasks/masked_lm.py @@ -20,6 +20,7 @@ NumSamplesDataset, PrependTokenDataset, RightPadDataset, + RightPaddingMaskDataset, SortDataset, TokenBlockDataset, data_utils, @@ -106,6 +107,22 @@ class MaskedLMConfig(FairseqDataclass): "help": "include target tokens in model input. this is used for data2vec" }, ) + include_index: bool = field( + default=True, + metadata={"help": "include index in model input. this is used for data2vec"}, + ) + skip_masking: bool = field( + default=False, + metadata={"help": "skip masking at dataset"}, + ) + # subsample_train: float = field( + # default=1, + # metadata={"help": "shorten training set for debugging"}, + # ) + d2v2_multi: bool = field( + default=False, + metadata={"help": "prepare dataset for data2vec_multi"}, + ) @register_task("masked_lm", dataclass=MaskedLMConfig) @@ -115,20 +132,25 @@ class MaskedLMTask(FairseqTask): """Task for training masked language models (e.g., BERT, RoBERTa).""" - def __init__(self, cfg: MaskedLMConfig, dictionary): + def __init__(self, cfg: MaskedLMConfig, dictionary=None): super().__init__(cfg) - self.dictionary = dictionary + self.dictionary = dictionary or self.load_dict(cfg) # add mask token - self.mask_idx = dictionary.add_symbol("<mask>") + self.mask_idx = self.dictionary.add_symbol("<mask>") @classmethod def setup_task(cls, cfg: MaskedLMConfig, **kwargs): + dictionary = cls.load_dict(cfg) + return cls(cfg, dictionary) + + @classmethod + def load_dict(cls, cfg): paths = utils.split_paths(cfg.data) assert len(paths) > 0 dictionary = Dictionary.load(os.path.join(paths[0], "dict.txt")) logger.info("dictionary: {} types".format(len(dictionary))) - return cls(cfg, dictionary) + return dictionary def _load_dataset_split(self, split, epoch, combine): paths = utils.split_paths(self.cfg.data) @@ -197,6 +219,7 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): mask_whole_words=mask_whole_words, mask_multiple_length=self.cfg.mask_multiple_length, mask_stdev=self.cfg.mask_stdev, + skip_masking=self.cfg.skip_masking, ) with data_utils.numpy_seed(self.cfg.seed): @@ -207,6 +230,16 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): pad_idx=self.source_dictionary.pad(), ) + if self.cfg.d2v2_multi: + dataset = self._d2v2_multi_dataset(src_dataset) + else: + dataset = self._regular_dataset(src_dataset, target_dataset) + + self.datasets[split] = SortDataset( + dataset, sort_order=[shuffle, src_dataset.sizes] + ) + + def _regular_dataset(self, src_dataset, target_dataset): input_dict = { "src_tokens": RightPadDataset( src_dataset, @@ -216,23 +249,41 @@ def load_dataset(self, split, epoch=1, combine=False, **kwargs): } if self.cfg.include_target_tokens: input_dict["target_tokens"] = target_dataset + if self.cfg.include_index: + input_dict["src_id"] = IdDataset() - self.datasets[split] = SortDataset( - NestedDictionaryDataset( - { - "id": IdDataset(), - "net_input": input_dict, - "target": target_dataset, - "nsentences": NumSamplesDataset(), - "ntokens": NumelDataset(src_dataset, reduce=True), - }, - sizes=[src_dataset.sizes], + dataset = NestedDictionaryDataset( + { + "id": IdDataset(), + "net_input": input_dict, + "target": target_dataset, + "nsentences": NumSamplesDataset(), + "ntokens": NumelDataset(src_dataset, reduce=True), + }, + sizes=[src_dataset.sizes], + ) + return dataset + + def _d2v2_multi_dataset(self, src_dataset): + input_dict = { + "source": RightPadDataset( + src_dataset, + pad_idx=self.source_dictionary.pad(), ), - sort_order=[ - shuffle, - src_dataset.sizes, - ], + "id": IdDataset(), + "padding_mask": RightPaddingMaskDataset(src_dataset), + } + + dataset = NestedDictionaryDataset( + { + "id": IdDataset(), + "net_input": input_dict, + "nsentences": NumSamplesDataset(), + "ntokens": NumelDataset(src_dataset, reduce=True), + }, + sizes=[src_dataset.sizes], ) + return dataset def build_dataset_for_inference(self, src_tokens, src_lengths, sort=True): src_dataset = RightPadDataset( @@ -268,3 +319,9 @@ def source_dictionary(self): @property def target_dictionary(self): return self.dictionary + + def begin_epoch(self, epoch, model): + model.set_epoch(epoch) + + def max_positions(self): + return self.cfg.tokens_per_sample diff --git a/fairseq/tasks/sentence_prediction.py b/fairseq/tasks/sentence_prediction.py index 52532ff61b..de80addaf2 100644 --- a/fairseq/tasks/sentence_prediction.py +++ b/fairseq/tasks/sentence_prediction.py @@ -23,6 +23,7 @@ PrependTokenDataset, RawLabelDataset, RightPadDataset, + RightPaddingMaskDataset, RollDataset, SortDataset, StripTokenDataset, @@ -83,6 +84,11 @@ class SentencePredictionConfig(FairseqDataclass): classification_head_name: str = II("criterion.classification_head_name") seed: int = II("common.seed") + d2v2_multi: bool = field( + default=False, + metadata={"help": "prepare dataset for data2vec_multi"}, + ) + @register_task("sentence_prediction", dataclass=SentencePredictionConfig) class SentencePredictionTask(FairseqTask): @@ -181,28 +187,39 @@ def make_dataset(key, dictionary): self.cfg.seed, ) - dataset = { - "id": IdDataset(), - "net_input": { + if self.cfg.d2v2_multi: + net_input = { + "source": RightPadDataset( + src_tokens, + pad_idx=self.source_dictionary.pad(), + ), + "id": IdDataset(), + "padding_mask": RightPaddingMaskDataset(src_tokens), + } + else: + net_input = { "src_tokens": RightPadDataset( src_tokens, pad_idx=self.source_dictionary.pad(), ), "src_lengths": NumelDataset(src_tokens, reduce=False), - }, + } + if self.cfg.add_prev_output_tokens: + prev_tokens_dataset = RightPadDataset( + RollDataset(src_tokens, 1), + pad_idx=self.dictionary.pad(), + ) + net_input.update( + prev_output_tokens=prev_tokens_dataset, + ) + + dataset = { + "id": IdDataset(), + "net_input": net_input, "nsentences": NumSamplesDataset(), "ntokens": NumelDataset(src_tokens, reduce=True), } - if self.cfg.add_prev_output_tokens: - prev_tokens_dataset = RightPadDataset( - RollDataset(src_tokens, 1), - pad_idx=self.dictionary.pad(), - ) - dataset["net_input"].update( - prev_output_tokens=prev_tokens_dataset, - ) - if not self.cfg.regression_target: label_dataset = make_dataset("label", self.label_dictionary) if label_dataset is not None: diff --git a/fairseq/trainer.py b/fairseq/trainer.py index da1f949107..16b1b91697 100644 --- a/fairseq/trainer.py +++ b/fairseq/trainer.py @@ -30,7 +30,6 @@ from fairseq.optim import lr_scheduler from fairseq.utils import safe_hasattr - logger = logging.getLogger(__name__) @@ -288,12 +287,27 @@ def lr_scheduler(self): return self._lr_scheduler def _build_optimizer(self): - params = list( - filter( - lambda p: p.requires_grad, - chain(self.model.parameters(), self.criterion.parameters()), + + if ( + self.cfg.optimization.debug_param_names + and self.cfg.common.fp16_no_flatten_grads + ): + params = [] + self.param_names = [] + + for n, p in chain( + self.model.named_parameters(), self.criterion.named_parameters() + ): + if p.requires_grad: + params.append(p) + self.param_names.append(n) + else: + params = list( + filter( + lambda p: p.requires_grad, + chain(self.model.parameters(), self.criterion.parameters()), + ) ) - ) if self.is_fsdp and self.cfg.common.fp16: # FullyShardedDataParallel always uses MemoryEfficientFP16 wrapper, @@ -432,18 +446,21 @@ def state_dict(self): def save_checkpoint(self, filename, extra_state): """Save all training state in a checkpoint file.""" - - logger.info(f"Saving checkpoint to {os.path.abspath(filename)}") - # call state_dict on all ranks in case it needs internal communication - state_dict = utils.move_to_cpu(self.state_dict()) - state_dict["extra_state"].update(extra_state) if self.should_save_checkpoint_on_current_rank: + + logger.info(f"Saving checkpoint to {os.path.abspath(filename)}") + # call state_dict on all ranks in case it needs internal communication + state_dict = utils.move_to_cpu(self.state_dict()) + state_dict["extra_state"].update(extra_state) + checkpoint_utils.torch_persistent_save( state_dict, filename, async_write=self.cfg.checkpoint.write_checkpoints_asynchronously, ) - logger.info(f"Finished saving checkpoint to {os.path.abspath(filename)}") + logger.info(f"Finished saving checkpoint to {os.path.abspath(filename)}") + return os.path.abspath(filename) + return None def load_checkpoint( self, @@ -793,6 +810,8 @@ def train_step(self, samples, raise_oom=False): if self.cfg.ema.store_ema and getattr(self.task, "uses_ema", False): extra_kwargs["ema_model"] = self.ema.get_model() + has_oom = False + # forward and backward pass logging_outputs, sample_size, ooms = [], 0, 0 for i, sample in enumerate(samples): # delayed update loop @@ -842,17 +861,9 @@ def maybe_no_sync(): except RuntimeError as e: if "out of memory" in str(e): self._log_oom(e) + has_oom = True if raise_oom: raise e - logger.warning( - "attempting to recover from OOM in forward/backward pass" - ) - ooms += 1 - self.zero_grad() - if self.cuda: - torch.cuda.empty_cache() - if self.cfg.distributed_training.distributed_world_size == 1: - return None else: raise e except Exception: @@ -862,6 +873,18 @@ def maybe_no_sync(): ) raise + if has_oom: + logger.warning( + "attempting to recover from OOM in forward/backward pass" + ) + ooms += 1 + self.zero_grad() + if self.cuda: + torch.cuda.empty_cache() + + if self.cfg.distributed_training.distributed_world_size == 1: + return None + if self.tpu and i < len(samples) - 1: # tpu-comment: every XLA operation before marking step is # appended to the IR graph, and processing too many batches @@ -989,6 +1012,14 @@ def maybe_no_sync(): logger.info( f"NOTE: gradient overflow detected, ignoring gradient, {str(e)}" ) + + if hasattr(self, "param_names") and hasattr( + self.optimizer, "fp32_optimizer" + ): + for p, n in zip(self.optimizer.fp32_optimizer.params, self.param_names): + if torch.isinf(p.grad).any() or torch.isnan(p.grad).any(): + logger.info(f"overflow in param {n}") + grad_norm = torch.tensor(0.0).cuda() self.zero_grad() except RuntimeError as e: diff --git a/fairseq/utils.py b/fairseq/utils.py index e6196863fa..e5c77e4b9e 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -270,9 +270,9 @@ def strip_pad(tensor, pad): return tensor[tensor.ne(pad)] -def buffered_arange(max): +def buffered_arange(max, device="cpu"): if not hasattr(buffered_arange, "buf"): - buffered_arange.buf = torch.LongTensor() + buffered_arange.buf = torch.LongTensor().to(device) if max > buffered_arange.buf.numel(): buffered_arange.buf.resize_(max) torch.arange(max, out=buffered_arange.buf) diff --git a/fairseq_cli/hydra_validate.py b/fairseq_cli/hydra_validate.py new file mode 100644 index 0000000000..cb6f7612d0 --- /dev/null +++ b/fairseq_cli/hydra_validate.py @@ -0,0 +1,188 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +import sys +from itertools import chain + +import torch +from hydra.core.hydra_config import HydraConfig +from omegaconf import OmegaConf, open_dict +import hydra + +from fairseq import checkpoint_utils, distributed_utils, utils +from fairseq.dataclass.configs import FairseqConfig +from fairseq.dataclass.initialize import add_defaults, hydra_init +from fairseq.dataclass.utils import omegaconf_no_object_check +from fairseq.distributed import utils as distributed_utils +from fairseq.logging import metrics, progress_bar +from fairseq.utils import reset_logging + +logging.basicConfig( + format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + level=os.environ.get("LOGLEVEL", "INFO").upper(), + stream=sys.stdout, +) +logger = logging.getLogger("fairseq_cli.validate") + + +@hydra.main(config_path=os.path.join("..", "fairseq", "config"), config_name="config") +def hydra_main(cfg: FairseqConfig) -> float: + return _hydra_main(cfg) + + +def _hydra_main(cfg: FairseqConfig, **kwargs) -> float: + add_defaults(cfg) + + if cfg.common.reset_logging: + reset_logging() # Hydra hijacks logging, fix that + else: + # check if directly called or called through hydra_main + if HydraConfig.initialized(): + with open_dict(cfg): + # make hydra logging work with ddp (see # see https://github.com/facebookresearch/hydra/issues/1126) + cfg.job_logging_cfg = OmegaConf.to_container( + HydraConfig.get().job_logging, resolve=True + ) + + with omegaconf_no_object_check(): + cfg = OmegaConf.create( + OmegaConf.to_container(cfg, resolve=True, enum_to_str=True) + ) + OmegaConf.set_struct(cfg, True) + + assert ( + cfg.dataset.max_tokens is not None or cfg.dataset.batch_size is not None + ), "Must specify batch size either with --max-tokens or --batch-size" + + distributed_utils.call_main(cfg, validate, **kwargs) + + +def validate(cfg): + utils.import_user_module(cfg.common) + + use_fp16 = cfg.common.fp16 + use_cuda = torch.cuda.is_available() and not cfg.common.cpu + + if use_cuda: + torch.cuda.set_device(cfg.distributed_training.device_id) + + if cfg.distributed_training.distributed_world_size > 1: + data_parallel_world_size = distributed_utils.get_data_parallel_world_size() + data_parallel_rank = distributed_utils.get_data_parallel_rank() + else: + data_parallel_world_size = 1 + data_parallel_rank = 0 + + overrides = {"task": {"data": cfg.task.data}} + + # Load ensemble + logger.info("loading model(s) from {}".format(cfg.common_eval.path)) + models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task( + [cfg.common_eval.path], + arg_overrides=overrides, + suffix=cfg.checkpoint.checkpoint_suffix, + ) + model = models[0] + + # Move models to GPU + for model in models: + model.eval() + if use_fp16: + model.half() + if use_cuda: + model.cuda() + + # Print args + logger.info(saved_cfg) + + # Build criterion + criterion = task.build_criterion(saved_cfg.criterion, from_checkpoint=True) + criterion.eval() + + for subset in cfg.dataset.valid_subset.split(","): + try: + task.load_dataset(subset, combine=False, epoch=1, task_cfg=saved_cfg.task) + dataset = task.dataset(subset) + except KeyError: + raise Exception("Cannot find dataset: " + subset) + + # Initialize data iterator + itr = task.get_batch_iterator( + dataset=dataset, + max_tokens=cfg.dataset.max_tokens, + max_sentences=cfg.dataset.batch_size, + max_positions=utils.resolve_max_positions( + task.max_positions(), + *[m.max_positions() for m in models], + ), + ignore_invalid_inputs=cfg.dataset.skip_invalid_size_inputs_valid_test, + required_batch_size_multiple=cfg.dataset.required_batch_size_multiple, + seed=cfg.common.seed, + num_shards=data_parallel_world_size, + shard_id=data_parallel_rank, + num_workers=cfg.dataset.num_workers, + data_buffer_size=cfg.dataset.data_buffer_size, + ).next_epoch_itr(shuffle=False) + progress = progress_bar.progress_bar( + itr, + log_format=cfg.common.log_format, + log_interval=cfg.common.log_interval, + prefix=f"valid on '{subset}' subset", + default_log_format=("tqdm" if not cfg.common.no_progress_bar else "simple"), + ) + + def apply_half(t): + if t.dtype is torch.float32: + return t.to(dtype=torch.half) + return t + + log_outputs = [] + for i, sample in enumerate(progress): + sample = utils.move_to_cuda(sample) if use_cuda else sample + + if use_fp16: + sample = utils.apply_to_sample(apply_half, sample) + + _loss, _sample_size, log_output = task.valid_step(sample, model, criterion) + with metrics.aggregate() as agg: + task.reduce_metrics([log_output], criterion) + progress.log(agg.get_smoothed_values(), step=i) + # progress.log(log_output, step=i) from vision + log_outputs.append(log_output) + + if data_parallel_world_size > 1: + log_outputs = distributed_utils.all_gather_list( + log_outputs, + max_size=cfg.common.all_gather_list_size, + group=distributed_utils.get_data_parallel_group(), + ) + log_outputs = list(chain.from_iterable(log_outputs)) + + with metrics.aggregate() as agg: + task.reduce_metrics(log_outputs, criterion) + log_output = agg.get_smoothed_values() + + progress.print(log_output, tag=subset, step=i) + + +def cli_main(): + try: + from hydra._internal.utils import get_args + + cfg_name = get_args().config_name or "config" + except: + logger.warning("Failed to get config name from hydra args") + cfg_name = "config" + + hydra_init(cfg_name) + hydra_main() + + +if __name__ == "__main__": + cli_main() diff --git a/fairseq_cli/train.py b/fairseq_cli/train.py index 376bd1d03a..f771bff654 100644 --- a/fairseq_cli/train.py +++ b/fairseq_cli/train.py @@ -125,12 +125,13 @@ def main(cfg: FairseqConfig) -> None: # Load valid dataset (we load training data below, based on the latest checkpoint) # We load the valid dataset AFTER building the model - data_utils.raise_if_valid_subsets_unintentionally_ignored(cfg) - if cfg.dataset.combine_valid_subsets: - task.load_dataset("valid", combine=True, epoch=1) - else: - for valid_sub_split in cfg.dataset.valid_subset.split(","): - task.load_dataset(valid_sub_split, combine=False, epoch=1) + if not cfg.dataset.disable_validation: + data_utils.raise_if_valid_subsets_unintentionally_ignored(cfg) + if cfg.dataset.combine_valid_subsets: + task.load_dataset("valid", combine=True, epoch=1) + else: + for valid_sub_split in cfg.dataset.valid_subset.split(","): + task.load_dataset(valid_sub_split, combine=False, epoch=1) # (optionally) Configure quantization if cfg.common.quantization_config_path is not None: @@ -175,6 +176,20 @@ def main(cfg: FairseqConfig) -> None: max_epoch = cfg.optimization.max_epoch or math.inf lr = trainer.get_lr() + # TODO: a dry run on validation set to pin the memory + valid_subsets = cfg.dataset.valid_subset.split(",") + if not cfg.dataset.disable_validation: + for subset in valid_subsets: + logger.info('begin dry-run validation on "{}" subset'.format(subset)) + itr = trainer.get_valid_iterator(subset).next_epoch_itr( + shuffle=False, set_dataset_epoch=False # use a fixed valid set + ) + if cfg.common.tpu: + itr = utils.tpu_data_loader(itr) + for _ in itr: + pass + # TODO: end of dry run section + train_meter = meters.StopwatchMeter() train_meter.start() while epoch_itr.next_epoch_idx <= max_epoch: @@ -424,9 +439,11 @@ def validate_and_save( # Save checkpoint if do_save or should_stop: - checkpoint_utils.save_checkpoint( + cp_path = checkpoint_utils.save_checkpoint( cfg.checkpoint, trainer, epoch_itr, valid_losses[0] ) + if cp_path is not None and hasattr(task, "post_save"): + task.post_save(cp_path, num_updates) return valid_losses, should_stop diff --git a/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/__init__.py b/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/__init__.py new file mode 100644 index 0000000000..4884f5bdcb --- /dev/null +++ b/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/__init__.py @@ -0,0 +1,3 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved + +__version__ = "0.1" diff --git a/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/config.py b/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/config.py new file mode 100644 index 0000000000..91926c4abc --- /dev/null +++ b/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/config.py @@ -0,0 +1,23 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +from dataclasses import dataclass, field + +from hydra.core.config_store import ConfigStore + +from hydra_plugins.hydra_submitit_launcher.config import SlurmQueueConf + + +@dataclass +class DependencySubmititConf(SlurmQueueConf): + """Slurm configuration overrides and specific parameters""" + + _target_: str = ( + "hydra_plugins.dependency_submitit_launcher.launcher.DependencySubmititLauncher" + ) + + +ConfigStore.instance().store( + group="hydra/launcher", + name="dependency_submitit_slurm", + node=DependencySubmititConf(), + provider="dependency_submitit_slurm", +) diff --git a/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/launcher.py b/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/launcher.py new file mode 100644 index 0000000000..b3fcf79e17 --- /dev/null +++ b/hydra_plugins/dependency_submitit_launcher/hydra_plugins/dependency_submitit_launcher/launcher.py @@ -0,0 +1,121 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +import logging +import os +import subprocess +from pathlib import Path +from typing import Any, List, Sequence + +from hydra.core.singleton import Singleton +from hydra.core.utils import JobReturn, filter_overrides +from omegaconf import OmegaConf + +log = logging.getLogger(__name__) + +from .config import DependencySubmititConf +from hydra_plugins.hydra_submitit_launcher.submitit_launcher import BaseSubmititLauncher + + +class DependencySubmititLauncher(BaseSubmititLauncher): + _EXECUTOR = "slurm" + + def launch( + self, job_overrides: Sequence[Sequence[str]], initial_job_idx: int + ) -> Sequence[JobReturn]: + + # lazy import to ensure plugin discovery remains fast + import submitit + + assert self.config is not None + + num_jobs = len(job_overrides) + assert num_jobs > 0 + + next_script = None + + for jo in job_overrides: + if next_script is None: + for item in jo: + if "next_script=" in item: + next_script = item + break + assert ( + next_script is not None + ), "job overrides must contain +next_script=path/to/next/script" + jo.remove(next_script) + + idx = next_script.find("=") + next_script = next_script[idx + 1 :] + + params = self.params + # build executor + init_params = {"folder": self.params["submitit_folder"]} + specific_init_keys = {"max_num_timeout"} + + init_params.update( + **{ + f"{self._EXECUTOR}_{x}": y + for x, y in params.items() + if x in specific_init_keys + } + ) + init_keys = specific_init_keys | {"submitit_folder"} + executor = submitit.AutoExecutor(cluster=self._EXECUTOR, **init_params) + + # specify resources/parameters + baseparams = set(OmegaConf.structured(DependencySubmititConf).keys()) + params = { + x if x in baseparams else f"{self._EXECUTOR}_{x}": y + for x, y in params.items() + if x not in init_keys + } + executor.update_parameters(**params) + + log.info( + f"Submitit '{self._EXECUTOR}' sweep output dir : " + f"{self.config.hydra.sweep.dir}" + ) + sweep_dir = Path(str(self.config.hydra.sweep.dir)) + sweep_dir.mkdir(parents=True, exist_ok=True) + if "mode" in self.config.hydra.sweep: + mode = int(str(self.config.hydra.sweep.mode), 8) + os.chmod(sweep_dir, mode=mode) + + job_params: List[Any] = [] + for idx, overrides in enumerate(job_overrides): + idx = initial_job_idx + idx + lst = " ".join(filter_overrides(overrides)) + log.info(f"\t#{idx} : {lst}") + job_params.append( + ( + list(overrides), + "hydra.sweep.dir", + idx, + f"job_id_for_{idx}", + Singleton.get_state(), + ) + ) + + jobs = executor.map_array(self, *zip(*job_params)) + + for j, jp in zip(jobs, job_params): + job_id = str(j.job_id) + task_id = "0" if "_" not in job_id else job_id.split("_")[1] + sweep_config = self.config_loader.load_sweep_config(self.config, jp[0]) + dir = sweep_config.hydra.sweep.dir + + dir = ( + dir.replace("[", "") + .replace("]", "") + .replace("{", "") + .replace("}", "") + .replace(",", "_") + .replace("'", "") + .replace('"', "") + ) + + subprocess.call( + [next_script, job_id, task_id, dir], + shell=False, + ) + + return [j.results()[0] for j in jobs] diff --git a/hydra_plugins/dependency_submitit_launcher/setup.py b/hydra_plugins/dependency_submitit_launcher/setup.py new file mode 100644 index 0000000000..bf795462bd --- /dev/null +++ b/hydra_plugins/dependency_submitit_launcher/setup.py @@ -0,0 +1,29 @@ +# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved +# type: ignore +from pathlib import Path + +from read_version import read_version +from setuptools import find_namespace_packages, setup + +setup( + name="dependency-submitit-launcher", + version=read_version("hydra_plugins/dependency_submitit_launcher", "__init__.py"), + author="Alexei Baevski", + author_email="abaevski@fb.com", + description="Dependency-supporting Submitit Launcher for Hydra apps", + packages=find_namespace_packages(include=["hydra_plugins.*"]), + classifiers=[ + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Operating System :: MacOS", + "Operating System :: POSIX :: Linux", + "Development Status :: 4 - Beta", + ], + install_requires=[ + "hydra-core>=1.0.4", + "submitit>=1.0.0", + ], + include_package_data=True, +) diff --git a/setup.py b/setup.py index 8a9b2f9770..dae06080c5 100644 --- a/setup.py +++ b/setup.py @@ -184,10 +184,12 @@ def do_setup(package_data): "numpy>=1.21.3", "regex", "sacrebleu>=1.4.12", - "torch>=1.10", + "torch>=1.13", "tqdm", "bitarray", "torchaudio>=0.8.0", + "scikit-learn", + "packaging", ], extras_require={ "dev": ["flake8", "pytest", "black==22.3.0"], diff --git a/tests/test_binaries.py b/tests/test_binaries.py index 1ab92f5f7e..41d9210e7c 100644 --- a/tests/test_binaries.py +++ b/tests/test_binaries.py @@ -11,6 +11,7 @@ import sys import tempfile import unittest +from packaging import version from io import StringIO from typing import Dict, List @@ -625,6 +626,10 @@ def test_transformer_cross_self_attention(self): ) generate_main(data_dir, extra_flags=[]) + @unittest.skipIf( + version.parse(torch.__version__) > version.parse("1.8"), + "skip for latest torch versions", + ) def test_transformer_pointer_generator(self): with contextlib.redirect_stdout(StringIO()): with tempfile.TemporaryDirectory( @@ -1827,6 +1832,8 @@ def train_masked_lm(data_dir, arch, extra_flags=None): "masked_lm", "--batch-size", "500", + "--required-batch-size-multiple", + "1", "--save-dir", data_dir, "--max-epoch", diff --git a/tests/test_ema.py b/tests/test_ema.py index 847316ff48..bd2cf2c78c 100644 --- a/tests/test_ema.py +++ b/tests/test_ema.py @@ -6,6 +6,7 @@ import unittest from copy import deepcopy from dataclasses import dataclass +import pytest from typing import Optional from unittest.mock import patch @@ -160,8 +161,7 @@ def test_ema_after_start_update(self): self._test_ema_start_update(updates=1) def test_ema_fp32(self): - # CPU no longer supports Linear in half precision - dtype = torch.half if torch.cuda.is_available() else torch.float + dtype = torch.float model = DummyModule().to(dtype) optimizer = torch.optim.SGD(model.parameters(), lr=0.01) @@ -213,12 +213,12 @@ def test_ema_fp32(self): ).to(dtype), ) + @pytest.mark.skipif( + not torch.cuda.is_available(), + reason="CPU no longer supports Linear in half precision", + ) def test_ema_fp16(self): - # CPU no longer supports Linear in half precision - if not torch.cuda.is_available(): - return - - model = DummyModule().half() + model = DummyModule().cuda().half() optimizer = torch.optim.SGD(model.parameters(), lr=0.01) state = deepcopy(model.state_dict()) config = EMAConfig(ema_fp32=False) @@ -227,7 +227,7 @@ def test_ema_fp16(self): # Since fp32 params is not used, it should be of size 0 self.assertEqual(len(ema.fp32_params), 0) - x = torch.randn(32) + x = torch.randn(32).cuda() y = model(x.half()) loss = y.sum() loss.backward() diff --git a/tests/test_multihead_attention.py b/tests/test_multihead_attention.py index 5301318c2c..4a0b430b6f 100644 --- a/tests/test_multihead_attention.py +++ b/tests/test_multihead_attention.py @@ -101,6 +101,7 @@ def test_mask_for_xformers(): @pytest.mark.skipif(not torch.cuda.is_available(), reason="blocksparse requires gpu") +@pytest.mark.skip(reason="not part of latest xformers") @pytest.mark.parametrize("device", ["cuda"]) @pytest.mark.parametrize("add_zero_attn", [False]) @pytest.mark.parametrize("batch_size", [20]) diff --git a/tests/test_valid_subset_checks.py b/tests/test_valid_subset_checks.py index 3e9191bda6..c39fb89823 100644 --- a/tests/test_valid_subset_checks.py +++ b/tests/test_valid_subset_checks.py @@ -126,13 +126,18 @@ def _train(self, extra_flags): return [x.message for x in logs.records] def test_combined(self): - flags = ["--combine-valid-subsets"] + flags = ["--combine-valid-subsets", "--required-batch-size-multiple", "1"] logs = self._train(flags) assert any(["valid1" in x for x in logs]) # loaded 100 examples from valid1 assert not any(["valid1_ppl" in x for x in logs]) # metrics are combined def test_subsets(self): - flags = ["--valid-subset", "valid,valid1"] + flags = [ + "--valid-subset", + "valid,valid1", + "--required-batch-size-multiple", + "1", + ] logs = self._train(flags) assert any(["valid_ppl" in x for x in logs]) # loaded 100 examples from valid1 assert any(["valid1_ppl" in x for x in logs]) # metrics are combined From 902f4aa5e82d40a78e81e49b3b2f3cc434539e23 Mon Sep 17 00:00:00 2001 From: Alexei Baevski <alexei.b@gmail.com> Date: Mon, 12 Dec 2022 23:36:17 -0800 Subject: [PATCH 719/774] remove missing config entries when loading task from checkpoint (#4905) --- fairseq/checkpoint_utils.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index ff1da2553c..fb9a6679ba 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -440,11 +440,13 @@ def load_model_ensemble_and_task( ) if task is None: - task = tasks.setup_task(cfg.task) + task = tasks.setup_task(cfg.task, from_checkpoint=True) if "task_state" in state: task.load_state_dict(state["task_state"]) + argspec = inspect.getfullargspec(task.build_model) + if "fsdp_metadata" in state and num_shards > 1: model_shard_state["shard_weights"].append(state["model"]) model_shard_state["shard_metadata"].append(state["fsdp_metadata"]) @@ -459,7 +461,10 @@ def load_model_ensemble_and_task( shard_weights=model_shard_state["shard_weights"], shard_metadata=model_shard_state["shard_metadata"], ) - model = task.build_model(cfg.model) + if "from_checkpoint" in argspec.args: + model = task.build_model(cfg.model, from_checkpoint=True) + else: + model = task.build_model(cfg.model) if ( "optimizer_history" in state and len(state["optimizer_history"]) > 0 @@ -475,7 +480,6 @@ def load_model_ensemble_and_task( # model parallel checkpoint or unsharded checkpoint # support old external tasks - argspec = inspect.getfullargspec(task.build_model) if "from_checkpoint" in argspec.args: model = task.build_model(cfg.model, from_checkpoint=True) else: From c19aed8ef59acafc8c146b50aed0ff3275ffcf01 Mon Sep 17 00:00:00 2001 From: Alexei Baevski <alexei.b@gmail.com> Date: Tue, 13 Dec 2022 00:50:53 -0800 Subject: [PATCH 720/774] make apex optional (#4906) --- examples/data2vec/models/mae.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/data2vec/models/mae.py b/examples/data2vec/models/mae.py index 5101e070e1..a3b5f72a4a 100644 --- a/examples/data2vec/models/mae.py +++ b/examples/data2vec/models/mae.py @@ -21,7 +21,11 @@ from fairseq.models import BaseFairseqModel, register_model from fairseq.models.wav2vec.wav2vec2 import TransformerSentenceEncoderLayer -from apex.normalization import FusedLayerNorm +try: + from apex.normalization import FusedLayerNorm +except: + FusedLayerNorm = nn.LayerNorm + import torch.nn.functional as F From 6c57de3c0aac2423ab58c7ed4d67fbed39fb641c Mon Sep 17 00:00:00 2001 From: padentomasello <pdtomasello@gmail.com> Date: Wed, 14 Dec 2022 09:53:29 -0800 Subject: [PATCH 721/774] Add file to generate manifests for stop dataset. (#4891) --- examples/audio_nlp/nlu/generate_manifests.py | 83 ++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 examples/audio_nlp/nlu/generate_manifests.py diff --git a/examples/audio_nlp/nlu/generate_manifests.py b/examples/audio_nlp/nlu/generate_manifests.py new file mode 100644 index 0000000000..e2176099cb --- /dev/null +++ b/examples/audio_nlp/nlu/generate_manifests.py @@ -0,0 +1,83 @@ +import argparse +from pathlib import Path +import soundfile + +def get_insl_frame(parse): + out = [] + def is_ont_token(tok): + return tok[0] in ["[", "]"]; + + res = [] + x = [] + for tok in parse.split(): + if is_ont_token(tok): + res.extend('_'.join(x)) + x = [] + res.append(tok.upper()) + else: + x.append(tok.upper()) + + return " ".join(res) + ' | ' + +def sequencify_utterance(utterance): + utterance = utterance.upper() + utterance = utterance.replace(' ', '|') + '|' + utterance = list(utterance) + utterance = ' '.join(utterance) + return utterance + + +def generate_fairseq_manifests(manifest, output_path, audio_root=None): + + with open(manifest, 'r') as i: + parses = [] + utterances = [] + filepaths = [] + keys = None + for (idx, line) in enumerate(i): + if idx == 0: keys = line.strip().split('\t') + else: + data = { k: v for (k, v) in zip(keys, line.split('\t'))} + parses.append(get_insl_frame(data['decoupled_normalized_seqlogical'])) + utterances.append(sequencify_utterance(data['normalized_utterance'])) + filepaths.append(data['file_id']) + + parses_fp = output_path.with_suffix('.parse') + with open(str(parses_fp), 'w') as o: + for p in parses: + o.write(p + '\n') + + utterances_fp = output_path.with_suffix('.ltr') + with open(str(utterances_fp), 'w') as o: + for u in utterances: + o.write(u + '\n') + + filepaths_fp = output_path.with_suffix('.tsv') + with open(str(filepaths_fp), 'w') as o: + o.write(str(audio_root) + '\n') + for f in filepaths: + fullpath = audio_root / f + assert fullpath.exists(), f'{fullpath}' + frames = soundfile.info(fullpath).frames + o.write(f'{f}\t{frames}\n') + +def main(args): + + splits = ['train', 'eval', 'test'] + root = Path(args.stop_root) + output_root = Path(args.output) + + for split in splits: + stop_manifest_path = root / 'manifests' / (split + '.tsv') + output_path = output_root / (split) + + generate_fairseq_manifests(stop_manifest_path, output_path, root) + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Process some integers.') + parser.add_argument('--stop_root', type=str, + help='path to stop root directory') + parser.add_argument('--output', type=str, + help='output directory') + args = parser.parse_args() + main(args) From 61883423056f3a9d1a4450174ae2f30a5a254716 Mon Sep 17 00:00:00 2001 From: padentomasello <pdtomasello@gmail.com> Date: Wed, 14 Dec 2022 09:53:54 -0800 Subject: [PATCH 722/774] Update STOP dataset README to include proper link. (#4892) --- examples/audio_nlp/nlu/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/audio_nlp/nlu/README.md b/examples/audio_nlp/nlu/README.md index ec23934e6d..aa22504e69 100644 --- a/examples/audio_nlp/nlu/README.md +++ b/examples/audio_nlp/nlu/README.md @@ -2,7 +2,7 @@ End-to-end spoken language understanding (SLU) predicts intent directly from audio using a single model. It promises to improve the performance of assistant systems by leveraging acoustic information lost in the intermediate textual representation and preventing cascading errors from Automatic Speech Recognition (ASR). Further, having one unified model has efficiency advantages when deploying assistant systems on-device. -This page releases the code for reproducing the results in [STOP: A dataset for Spoken Task Oriented Semantic Parsing](TODO) +This page releases the code for reproducing the results in [STOP: A dataset for Spoken Task Oriented Semantic Parsing](https://arxiv.org/abs/2207.10643) The dataset can be downloaded here: [download link](https://dl.fbaipublicfiles.com/stop/stop.tar.gz) From 9ab5f32fb3a5dfe5247587b80a144bb5563fcd2d Mon Sep 17 00:00:00 2001 From: padentomasello <pdtomasello@gmail.com> Date: Wed, 14 Dec 2022 09:54:14 -0800 Subject: [PATCH 723/774] Update README.md (#4893) --- examples/audio_nlp/nlu/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/audio_nlp/nlu/README.md b/examples/audio_nlp/nlu/README.md index aa22504e69..a11b3f3065 100644 --- a/examples/audio_nlp/nlu/README.md +++ b/examples/audio_nlp/nlu/README.md @@ -6,6 +6,8 @@ This page releases the code for reproducing the results in [STOP: A dataset for The dataset can be downloaded here: [download link](https://dl.fbaipublicfiles.com/stop/stop.tar.gz) +The low-resource splits can be downloaded here: [download link](http://dl.fbaipublicfiles.com/stop/low_resource_splits.tar.gz) + ## Pretrained models end-to-end NLU Models | Speech Pretraining | ASR Pretraining | Test EM Accuracy | Tesst EM-Tree Accuracy | Link | From 3c1abb59f581bfce68822b6179d1c1b37b304259 Mon Sep 17 00:00:00 2001 From: Junteng Jia <juntengjia@hotmail.com> Date: Fri, 16 Dec 2022 17:06:21 -0800 Subject: [PATCH 724/774] using foreach to reduce kernel (#4904) * using foreach to reduce kernel * set reproducibility to looser threshold * revert optimzer * update * update * update * update * update * update * update Co-authored-by: juntengjia <juntengjia@fb.com> --- fairseq/optim/fairseq_optimizer.py | 14 +++++++++++--- fairseq/utils.py | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/fairseq/optim/fairseq_optimizer.py b/fairseq/optim/fairseq_optimizer.py index 7e5411753a..73c7c695ee 100644 --- a/fairseq/optim/fairseq_optimizer.py +++ b/fairseq/optim/fairseq_optimizer.py @@ -6,6 +6,7 @@ import torch from fairseq import utils from fairseq.dataclass.utils import gen_parser_from_dataclass +from collections import defaultdict class FairseqOptimizer(object): @@ -101,11 +102,18 @@ def all_reduce_grads(self, module): def multiply_grads(self, c): """Multiplies grads by a constant *c*.""" + per_device_and_dtype_grads = defaultdict(lambda: defaultdict(list)) for p in self.params: if p.grad is not None: - if torch.is_tensor(c): - c = c.to(p.grad.device) - p.grad.data.mul_(c) + if p.grad.is_sparse: + p.grad.data.mul_(c.to(p.grad.device) if torch.is_tensor(c) else c) + else: + per_device_and_dtype_grads[p.grad.device][p.grad.dtype].append( + p.grad.data + ) + for device, per_dtype_grads in per_device_and_dtype_grads.items(): + for grads in per_dtype_grads.values(): + torch._foreach_mul_(grads, c.to(device) if torch.is_tensor(c) else c) def clip_grad_norm(self, max_norm, aggregate_norm_fn=None): """Clips gradient norm.""" diff --git a/fairseq/utils.py b/fairseq/utils.py index e5c77e4b9e..4d4b350523 100644 --- a/fairseq/utils.py +++ b/fairseq/utils.py @@ -392,8 +392,8 @@ def grad_exists(p): if max_norm > 0: max_norm = float(max_norm) clip_coef = (max_norm / (total_norm + 1e-6)).clamp_(max=1) - for g in grads + expert_grads: - g.mul_(clip_coef) + torch._foreach_mul_(grads + expert_grads, clip_coef) + return total_norm From 58cc6cca18f15e6d56e3f60c959fe4f878960a60 Mon Sep 17 00:00:00 2001 From: arbabu123 <arbabu@fb.com> Date: Tue, 20 Dec 2022 10:34:07 -0800 Subject: [PATCH 725/774] Update README.md to add data2vec blog post (#4913) * Update README.md --- examples/data2vec/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/data2vec/README.md b/examples/data2vec/README.md index 5b680ef8c0..99d56cf06d 100644 --- a/examples/data2vec/README.md +++ b/examples/data2vec/README.md @@ -1,6 +1,6 @@ # data2vec 2.0 -data2vec 2.0 improves the training efficiency of the original data2vec algorithm. We make the following improvements for efficiency considerations - we forward only the unmasked timesteps through the encoder, we use convolutional decoder and we use multimasking to amortize the compute overhead of the teacher model. You can find details in [Efficient Self-supervised Learning with Contextualized Target Representations for Vision, Speech and Language](https://ai.facebook.com/research/xyz) +data2vec 2.0 improves the training efficiency of the original data2vec algorithm. We make the following improvements for efficiency considerations - we forward only the unmasked timesteps through the encoder, we use convolutional decoder and we use multimasking to amortize the compute overhead of the teacher model. You can find details in the paper [Efficient Self-supervised Learning with Contextualized Target Representations for Vision, Speech and Language](https://arxiv.org/abs/2212.07525) and our [blog post](https://ai.facebook.com/blog/ai-self-supervised-learning-data2vec/). ## Pretrained and finetuned models ### Vision From 7d050ada7d365b535bf7c634ed3bcaf1cc2930b1 Mon Sep 17 00:00:00 2001 From: dianaml0 <82468439+dianaml0@users.noreply.github.com> Date: Thu, 19 Jan 2023 10:43:10 -0500 Subject: [PATCH 726/774] Update config to fix circleci failure (#4949) https://app.circleci.com/pipelines/github/fairinternal/fairseq-py/12635/workflows/3befbae2-79c4-458d-9fc4-aad4484183b4/jobs/26767 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7a2ab46797..7710c78c2f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -65,7 +65,7 @@ create_conda_env: &create_conda_env command: | curl -o ~/miniconda.sh -O https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh chmod +x ~/miniconda.sh - ~/miniconda.sh -b -p $HOME/miniconda + bash ~/miniconda.sh -b -p $HOME/miniconda rm ~/miniconda.sh echo 'export PATH=$HOME/miniconda/bin:$PATH' >> $BASH_ENV source $BASH_ENV From e7f6596bd4bd97c385fd9c3a678cbd6ad3480a46 Mon Sep 17 00:00:00 2001 From: Nguyen Tu Anh <nguyentuanh208@gmail.com> Date: Thu, 26 Jan 2023 18:40:20 +0100 Subject: [PATCH 727/774] Generative Spoken Dialogue Language Modeling Paper Open Source (#4957) --- examples/textless_nlp/dgslm/README.md | 166 ++- .../textless_nlp/dgslm/create_code_file.py | 79 ++ examples/textless_nlp/dgslm/dgslm_utils.py | 78 ++ .../dgslm/hubert_fisher/README.md | 47 + .../textless_nlp/dgslm/sample_speech_dlm.py | 202 +++ .../dgslm/vocoder_hifigan/README.md | 47 + .../generate_stereo_waveform.py | 137 ++ .../clustering/quantize_with_kmeans.py | 20 +- .../pretrained/cpc_feature_reader.py | 22 +- .../pretrained/hubert_feature_reader.py | 23 +- .../pretrained/logmel_feature_reader.py | 8 +- .../gslm/speech2unit/pretrained/utils.py | 7 +- .../pretrained/w2v2_feature_reader.py | 22 +- fairseq/criterions/speech_dlm_criterion.py | 335 +++++ fairseq/data/__init__.py | 2 + fairseq/data/speech_dlm_dataset.py | 307 +++++ fairseq/models/speech_dlm/__init__.py | 7 + fairseq/models/speech_dlm/hub_interface.py | 192 +++ fairseq/models/speech_dlm/modules/__init__.py | 0 .../speech_dlm/modules/speech_dlm_decoder.py | 572 +++++++++ .../modules/speech_dlm_decoder_layer.py | 717 +++++++++++ .../speech_dlm/sequence_generator/__init__.py | 6 + .../sequence_generator/multichannel_search.py | 430 +++++++ .../multichannel_sequence_generator.py | 1110 +++++++++++++++++ fairseq/models/speech_dlm/speech_dlm.py | 280 +++++ fairseq/tasks/speech_dlm_task.py | 561 +++++++++ 26 files changed, 5352 insertions(+), 25 deletions(-) create mode 100644 examples/textless_nlp/dgslm/create_code_file.py create mode 100644 examples/textless_nlp/dgslm/dgslm_utils.py create mode 100644 examples/textless_nlp/dgslm/hubert_fisher/README.md create mode 100644 examples/textless_nlp/dgslm/sample_speech_dlm.py create mode 100644 examples/textless_nlp/dgslm/vocoder_hifigan/README.md create mode 100644 examples/textless_nlp/dgslm/vocoder_hifigan/generate_stereo_waveform.py create mode 100644 fairseq/criterions/speech_dlm_criterion.py create mode 100644 fairseq/data/speech_dlm_dataset.py create mode 100644 fairseq/models/speech_dlm/__init__.py create mode 100644 fairseq/models/speech_dlm/hub_interface.py create mode 100644 fairseq/models/speech_dlm/modules/__init__.py create mode 100644 fairseq/models/speech_dlm/modules/speech_dlm_decoder.py create mode 100644 fairseq/models/speech_dlm/modules/speech_dlm_decoder_layer.py create mode 100644 fairseq/models/speech_dlm/sequence_generator/__init__.py create mode 100644 fairseq/models/speech_dlm/sequence_generator/multichannel_search.py create mode 100644 fairseq/models/speech_dlm/sequence_generator/multichannel_sequence_generator.py create mode 100644 fairseq/models/speech_dlm/speech_dlm.py create mode 100644 fairseq/tasks/speech_dlm_task.py diff --git a/examples/textless_nlp/dgslm/README.md b/examples/textless_nlp/dgslm/README.md index 7a9248666b..917dbb2765 100644 --- a/examples/textless_nlp/dgslm/README.md +++ b/examples/textless_nlp/dgslm/README.md @@ -1,7 +1,171 @@ # Generative Spoken Dialogue Language Modeling [[paper]](https://arxiv.org/abs/2203.16502) [[demo samples]](https://speechbot.github.io/dgslm/index.html) [[blog]](https://ai.facebook.com/blog/generating-chit-chat-including-laughs-yawns-ums-and-other-nonverbal-cues-from-raw-audio/) -The code for the paper _Generative Spoken Dialogue Language Modeling_ will be released here very soon. +This repo contains the code and pre-trained models for the paper _Generative Spoken Dialogue Language Modeling_. +<details> + <summary>Paper abstract </summary> + +> We introduce dGSLM, the first "textless" model able to generate audio samples of naturalistic spoken dialogues. It uses recent work on unsupervised spoken unit discovery coupled with a dual-tower transformer architecture with cross-attention trained on 2000 hours of two-channel raw conversational audio (Fisher dataset) without any text or labels. We show that our model is able to generate speech, laughter and other paralinguistic signals in the two channels simultaneously and reproduces more naturalistic and fluid turn taking compared to a text-based cascaded model. + +</details> + +## [Speech-to-Unit Encoder for dGSLM: The Fisher HuBERT model](hubert_fisher/) +The [hubert_fisher](hubert_fisher/) repository contains the pre-trained models and recipies to produce discrete units for the dGSLM model. + +## [Unit-to-Speech Decoder for dGSLM](vocoder_hifigan/) +The [vocoder_hifigan](vocoder_hifigan/) repo contains the vocoder and recipies to synthesize the waveform from the discrete units. + +## Spoken Dialogue Transformer Language Model (SpeechDLM) +### Pre-trained model +We share the pre-trained model checkpoint for the best configuration in the paper (DLM-5 model, with Edge Unit Prediction & Delayed Duration Prediction objectives), dubbed as `SpeechDLM`, trained on the 2000 hours of Fisher dataset : +| Pre-trained SpeechDLM model trained on Fisher dataset | +|-----------------------------------------------| +|[model checkpoint](https://dl.fbaipublicfiles.com/textless_nlp/dgslm/checkpoints/speech_dlm/speech_dlm_base.pt) - [dictionary 1](https://dl.fbaipublicfiles.com/textless_nlp/dgslm/checkpoints/speech_dlm/dict.unitA.txt) - [dictionary 2](https://dl.fbaipublicfiles.com/textless_nlp/dgslm/checkpoints/speech_dlm/dict.unitB.txt)| +the two dictionary files correspond to the two channels, and actually have the same content. + +### Sample from a trained model +You can sample from a trained SpeechDLM model interactively : +```python +from fairseq.models.speech_dlm import SpeechDLM + +# Load SpeechDLM model +speech_dlm = SpeechDLM.from_pretrained( + model_name_or_path='/path/to/model/dir', + checkpoint_file='speech_dlm_base.pt', + data_name_or_path='/path/to/data/dir' + ) +# Disable dropout +speech_dlm.eval() +# Move model to GPU +speech_dlm.cuda() + +# Define the input sequences +input_sequences = [{ + 'unitA': '7 376 376 133 178 486 486 486 486 486 486 486 486 2 486', + 'unitB': '7 499 415 177 7 7 7 7 7 7 136 136 289 289 408' + }] + +# Sample from the SpeechDLM model +generated_units = speech_dlm.sample( + input_sequences, + max_len_a = 0, + max_len_b = 500, + sampling=True, + beam=5, + ) +# >> {'unitA': '7 376 376 133 178 486 486 486 486 486 486 486 486 2 486 486 178 486 486 2 2 376 376 486 486 486 376 376 387 387 ...', +# >> 'unitB': '7 499 415 177 7 7 7 7 7 7 136 136 289 289 408 32 428 95 356 141 331 439 350 350 192 331 445 202 104 104 ...'} +``` + +Or using the `sample_speech_dlm.py` script : +```bash +python sample_speech_dlm.py \ + --in-file $INPUT_CODE_FILE --out-file $OUTPUT_FILE \ + --ckpt $CHECKPOINT_PATH --data $DATA_DIR +``` +where each line of INPUT_CODE_FILE is a dictionary with keys `'audio', 'unitA', 'unitB'` as follows : +``` +{'audio': 'file_1', 'unitA': '8 8 ... 352 352', 'unitB': '217 8 ... 8 8'} +{'audio': 'file_2', 'unitA': '5 5 ... 65 65', 'unitB': '6 35 ... 8 9'} +... +``` +This code file can be created with the script `create_input_code.py` (using the outputs of `quantize_with_kmeans.py` [here](hubert_fisher/#encode-audio-to-discrete-units)) : +```bash +python examples/textless_nlp/dgslm/vocoder_hifigan/create_input_code.py \ + $CHANNEL1_UNITS $CHANNEL2_UNITS $OUTPUT_CODE_FILE +``` + +### Training a SpeechDLM model +#### 1) Data preparation +First, you need to prepare the raw dataset. For each `split` (train, valid), you need two files corresponding to two channels (namely `unitA` and `unitB` for example) containing the units from each channel separately. Make sure that 2 files have the same number of lines and each corresponding line has the same number of units. + +Here is an example of `.unitA` file : +``` +7 376 376 133 178 +486 486 486 +486 376 +``` +and the corresponding `.unitB` file : +``` +7 499 415 177 7 +7 7 136 +331 445 +``` +These two files can be obtained using the [example command](hubert_fisher/#encode-audio-to-discrete-units) of hubert fisher, with the `--hide-fname` option added. + +The raw dataset directory should contain the following files : +``` +train.unitA valid.unitA +train.unitB valid.unitB +``` + +Next preprocess/binarize the data with `fairseq-preprocess`, but make sure to preprocess each channel separately, and **rename** the preprocessed files under the following format `${split}.${channel}.{bin, idx}`. Each channel also needs a separate dictionary file under the name `dict.${channel}.txt` . + +Here is an example pre-processing code : + +```bash +# Preprocess the first channel (unitA) +fairseq-preprocess --source-lang unitA \ + --only-source \ + --trainpref $RAW_DATA_DIR/train \ + --validpref $RAW_DATA_DIR/valid \ + --destdir $BIN_DATA_DIR \ + --workers 20 + +# Preprocess the second channel (unitB) and reuse the dictionary from the first channel +fairseq-preprocess --source-lang unitB \ + --srcdict $BIN_DATA_DIR/dict.unitA.txt \ + --only-source \ + --trainpref $RAW_DATA_DIR/train \ + --validpref $RAW_DATA_DIR/valid \ + --destdir $BIN_DATA_DIR \ + --workers 20 + +# Rename the bin & index files +for channel in unitA unitB; do + for split in train valid; do + mv $BIN_DATA_DIR/${split}.${channel}-None.${channel}.bin $BIN_DATA_DIR/${split}.${channel}.bin + mv $BIN_DATA_DIR/${split}.${channel}-None.${channel}.idx $BIN_DATA_DIR/${split}.${channel}.idx + done +done +``` +Finally, the preprocessed (bin) dataset directory should contain the following files : +``` +dict.unitA.txt train.unitA.idx train.unitA.bin valid.unitA.idx valid.unitA.bin +dict.unitB.txt train.unitB.idx train.unitB.bin valid.unitB.idx valid.unitB.bin +``` + +#### 2) Train the model +To train the SpeechDLM (with the configuration as the pre-trained model) on 2 GPUs : +```bash +fairseq-train $BIN_DATA_DIR \ + --save-dir $CHECKPOINT_DIR \ + --tensorboard-logdir $CHECKPOINT_DIR \ + --task speech_dlm_task --channels unitA,unitB \ + --next-unit-prediction "False" --edge-unit-prediction "True" \ + --duration-prediction "True" --delayed-duration-target "True" \ + --criterion speech_dlm_criterion \ + --arch speech_dlm --decoder-cross-layers 4 \ + --share-decoder-input-output-embed \ + --dropout 0.1 --attention-dropout 0.1 \ + --optimizer adam --adam-betas "(0.9, 0.98)" --clip-norm 1.0 \ + --lr 0.0005 --lr-scheduler inverse_sqrt --warmup-init-lr 1e-07 \ + --max-tokens 18432 --tokens-per-sample 6144 --sample-break-mode none \ + --update-freq 16 --num-workers 4 --skip-invalid-size-inputs-valid-test \ + --max-update 250000 --warmup-updates 20000 \ + --save-interval-updates 10000 --keep-last-epochs 1 --no-epoch-checkpoints \ + --log-interval 50 --seed 100501 \ + --fp16 --checkpoint-activations +``` + +#### 3) Validate +The model can be validated via the `fairseq-validate` command : +```bash +fairseq-validate $BIN_DATA_DIR \ + --task speech_dlm_task \ + --path $CHECKPOINT_PATH \ + --max-tokens 6144 +``` ## Reference diff --git a/examples/textless_nlp/dgslm/create_code_file.py b/examples/textless_nlp/dgslm/create_code_file.py new file mode 100644 index 0000000000..d10f9484ad --- /dev/null +++ b/examples/textless_nlp/dgslm/create_code_file.py @@ -0,0 +1,79 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse + + +def main(): + """ + Create code file with the following format: + {'audio': 'file1', 'unitA': 'file1_chnl1_units', 'unitB': 'file1_chnl2_units'} + {'audio': 'file2', 'unitA': 'file2_chnl1_units', 'unitB': 'file2_chnl2_units'} + ... + + Given the input units files + - channel1_units_file: + file1|file1_chnl1_units + file2|file2_chnl1_units + ... + - channel2_units_file: + file1|file1_chnl2_units + file2|file2_chnl2_units + ... + """ + + parser = argparse.ArgumentParser() + parser.add_argument( + "channel1_units_file", + type=str, + help="Units of the first channel.", + ) + parser.add_argument( + "channel2_units_file", + type=str, + help="Units of the second channel.", + ) + parser.add_argument( + "output_file", + type=str, + help="Output file.", + ) + parser.add_argument( + "--channels", + type=str, + default='unitA,unitB', + help="Comma-separated list of the channel names to create in the code" + "(Default: 'unitA,unitB').", + ) + + args = parser.parse_args() + + channel_names = args.channels.split(',') + + with open(args.channel1_units_file) as funit1, \ + open(args.channel2_units_file) as funit2, \ + open(args.output_file, 'w') as fout: + for line1, line2 in zip(funit1, funit2): + fname1, units1 = line1.strip().split('|') + fname2, units2 = line2.strip().split('|') + assert len(units1.split()) == len(units2.split()), \ + f"Mismatch units length ({len(units1.split())} vs {len(units2.split())})" + base_fname1 = fname1[:-9] + base_fname2 = fname2[:-9] + assert base_fname1 == base_fname2, \ + f"Mismatch filenames ({base_fname1} vs {base_fname2}). " \ + f"Expected $filename-channel1 and $filename-channel2 in two files" + code = { + "audio" : base_fname1, + channel_names[0] : units1, + channel_names[1] : units2, + } + fout.write(str(code)) + fout.write("\n") + print(f"Codes written to {args.output_file}") + + +if __name__ == "__main__": + main() diff --git a/examples/textless_nlp/dgslm/dgslm_utils.py b/examples/textless_nlp/dgslm/dgslm_utils.py new file mode 100644 index 0000000000..8049d49793 --- /dev/null +++ b/examples/textless_nlp/dgslm/dgslm_utils.py @@ -0,0 +1,78 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import numpy as np +import torch +import json + +from fairseq import utils +from fairseq.models.text_to_speech.vocoder import CodeHiFiGANVocoder + +# from examples.hubert.simple_kmeans.dump_hubert_feature import HubertFeatureReader +from examples.textless_nlp.gslm.speech2unit.pretrained.hubert_feature_reader import HubertFeatureReader +from examples.hubert.simple_kmeans.dump_km_label import ApplyKmeans + + +# Hubert tokenizer +class HubertTokenizer: + def __init__( + self, + hubert_path, + hubert_layer, + km_path, + use_cuda=True, + ): + self.feature_extractor = HubertFeatureReader(hubert_path, hubert_layer, use_cuda=use_cuda) + self.quantizer = ApplyKmeans(km_path) + if not use_cuda: + self.quantizer.C = self.quantizer.C.cpu() + self.quantizer.Cnorm = self.quantizer.Cnorm.cpu() + + def wav2code(self, path, channel_id=1): + feat = self.feature_extractor.get_feats(path, channel_id=channel_id) + code = self.quantizer(feat) + return ' '.join(map(str, code)) + + def wav2codes(self, path): + codes = [ + self.wav2code(path, channel_id=1), + self.wav2code(path, channel_id=2) + ] + return codes + + +# Vocoder +class HifiganVocoder: + def __init__( + self, + vocoder_path, + vocoder_cfg_path, + use_cuda=True, + ): + with open(vocoder_cfg_path) as f: + cfg = json.load(f) + self.vocoder = CodeHiFiGANVocoder(vocoder_path, cfg).eval() + self.use_cuda = use_cuda + if self.use_cuda: + self.vocoder.cuda() + + def code2wav(self, code, speaker_id=0, pred_dur=False): + if isinstance(code, str): + code = list(map(int, code.split())) + inp = {"code": torch.LongTensor(code).view(1, -1)} + if self.vocoder.model.multispkr: + inp["spkr"] = torch.LongTensor([speaker_id]).view(1, 1) + if self.use_cuda: + inp = utils.move_to_cuda(inp) + return self.vocoder(inp, pred_dur).detach().cpu().numpy() + + def codes2wav(self, codes, speaker_ids=[0, 4], pred_dur=False): + if isinstance(codes, dict): + codes = list(codes.values()) + assert len(codes) == 2 + wav1 = self.code2wav(codes[0], speaker_ids[0], pred_dur) + wav2 = self.code2wav(codes[1], speaker_ids[1], pred_dur) + wav = np.stack([wav1, wav2]) + return wav diff --git a/examples/textless_nlp/dgslm/hubert_fisher/README.md b/examples/textless_nlp/dgslm/hubert_fisher/README.md new file mode 100644 index 0000000000..52c528fa1e --- /dev/null +++ b/examples/textless_nlp/dgslm/hubert_fisher/README.md @@ -0,0 +1,47 @@ +# Dialogue Speech-to-Unit Encoder for dGSLM: The Fisher HuBERT model +For the speech2unit encoder, we train a [HuBERT model](https://arxiv.org/pdf/2106.07447.pdf) on the [Fisher dataset](http://www.lrec-conf.org/proceedings/lrec2004/pdf/767.pdf) for 3 iterations (see [our paper](https://arxiv.org/pdf/2203.16502.pdf) for more details) and train a k-means model with 500 units on the layer 12 features of the HuBERT model. + +## Model checkpoints +The pre-trained HuBERT and k-means model checkpoints can be found here: + +| Fisher HuBERT model | k-means model | +|---------------------|---------------| +|[download](https://dl.fbaipublicfiles.com/textless_nlp/dgslm/checkpoints/hubert/hubert_fisher.pt)|[download](https://dl.fbaipublicfiles.com/textless_nlp/dgslm/checkpoints/hubert/hubert_fisher_km_500.bin)| + + +## Encode audio to discrete units +Below is an example command to encode a stereo dataset to discrete units using the pre-trained model checkpoints : +```bash +for CHANNEL_ID in 1 2; do + python examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py \ + --feature_type hubert \ + --kmeans_model_path path/to/hubert_fisher_km_500.bin \ + --acoustic_model_path path/to/hubert_fisher.pt \ + --layer 12 \ + --manifest_path $MANIFEST_FILE \ + --out_quantized_file_path ${OUTPUT_FILE}-channel${CHANNEL_ID} \ + --extension $EXTENSION \ + --channel_id $CHANNEL_ID +done +``` +where MANIFEST_FILE is the output of [wav2vec manifest script](https://github.com/facebookresearch/fairseq/blob/main/examples/wav2vec/wav2vec_manifest.py), which can be obtained through the following command : +``` +python examples/wav2vec/wav2vec_manifest.py --valid-percent=0.0 $AUDIO_DIR --dest=$OUTPUT_DIR --ext=$EXTENSION +``` + +Otherwise, you can encode an audio file in python interactively with the HubertTokenizer class : +```python +# Load the Hubert tokenizer +from examples.textless_nlp.dgslm.dgslm_utils import HubertTokenizer +encoder = HubertTokenizer( + hubert_path = "/path/to/hubert_ckpt.pt", + hubert_layer = 12, + km_path = "path/to/km.bin" +) + +# Encode the audio to units +path = "/path/to/stereo/audio.wav" +codes = encoder.wav2codes(path) +# > ['7 376 376 133 178 486 486 486 486 486 486 486 486 2 486', +# > '7 499 415 177 7 7 7 7 7 7 136 136 289 289 408'] +``` \ No newline at end of file diff --git a/examples/textless_nlp/dgslm/sample_speech_dlm.py b/examples/textless_nlp/dgslm/sample_speech_dlm.py new file mode 100644 index 0000000000..484cbabd3e --- /dev/null +++ b/examples/textless_nlp/dgslm/sample_speech_dlm.py @@ -0,0 +1,202 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import ast +import argparse +import logging +import torch + +from fairseq import utils +from fairseq.models.speech_dlm import SpeechDLM + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def load_data(in_file): + with open(in_file) as f: + data = [ast.literal_eval(line.strip()) for line in f] + return data + + +def write_data(out_file, data): + with open(out_file, 'w') as f: + for d in data: + f.write(str(d)) + f.write('\n') + + +def limit(codes, n): + new_codes = {} + for k, v in codes.items(): + new_codes[k] = ' '.join(v.split()[:n]) + return new_codes + + +def main(args): + logger.info(args) + + use_cuda = torch.cuda.is_available() + + # Load the data + data = load_data(args.in_file) + channels = args.channels.split(',') + unit_sequences = [{ + channels[0]: d[channels[0]], + channels[1]: d[channels[1]], + } for d in data] + fnames = [d['audio'] for d in data] + print(f"Found {len(data)} sequences from {args.in_file}") + + # Limit the prefix size + if args.prefix_size is not None: + print(f"Limit the prefix size to {args.prefix_size}") + unit_sequences = [limit(codes, args.prefix_size) for codes in unit_sequences] + + # Load model from ckpt + print(f"Loading the SpeechDLM model from {args.ckpt}") + model = SpeechDLM.from_pretrained( + model_name_or_path=os.path.dirname(args.ckpt), + checkpoint_file=os.path.basename(args.ckpt), + data_name_or_path=args.data + ) + model.eval() + if use_cuda: + model.cuda() + + # Set batch sizes + model.cfg.dataset.max_tokens = args.batch_max_tokens + model.max_positions = args.batch_max_positions + if args.batch_max_sentences is not None: + model.cfg.dataset.batch_size = args.batch_max_sentences + + # Set seed (if needed) + if args.seed is not None: + utils.set_torch_seed(args.seed) + + # Sample from the SpeechDLM model + print(f"Generating {len(unit_sequences)} sequences with SpeechDLM model...\n" + f"Generation args: sampling={(not args.beam_search)}, " + f"sampling_topk={args.sampling_topk}, sampling_topp={args.sampling_topp}, " + f"beam={args.beam_size}, min_len={args.min_len}, " + f"max_len_a={args.max_len_a}, max_len_b={args.max_len_b}, " + f"temperature={args.temperature}, dur_temperature={args.dur_temperature}, " + f"seed={args.seed}") + generated_units = model.sample( + unit_sequences, + sampling=(not args.beam_search), + sampling_topk=args.sampling_topk, + sampling_topp=args.sampling_topp, + beam=args.beam_size, + max_len_a=args.max_len_a, + max_len_b=args.max_len_b, + min_len=args.min_len, + temperature=args.temperature, + duration_temperature=args.dur_temperature, + verbose=args.verbose, + skip_invalid_size_inputs=args.skip_invalid_size_batch, + ) + + # Create the generated sequences + generated_data = [] + for fname, gen_units in zip(fnames, generated_units): + d = { + "audio" : fname+'-generated', + **gen_units + } + generated_data.append(d) + + # Write the generated sequences + print(f"Write the generated units to {args.out_file}") + if args.out_file: + os.makedirs(os.path.dirname(args.out_file), exist_ok=True) + write_data(args.out_file, generated_data) + + +def cli_main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--in-file", + type=str, + required=True, + help="Input file following the same format of the output from create_input.py", + ) + parser.add_argument( + "--ckpt", + type=str, + required=True, + help="Path to the model checkpoint." + ) + parser.add_argument( + "--data", + type=str, + required=True, + help="path to the model data dir (containing dict files)", + ) + parser.add_argument( + "--out-file", + type=str, + required=True, + help="Path of the output file.", + ) + parser.add_argument( + "--channels", + type=str, + default='unitA,unitB', + help="Comma-separated list of the channel names" + "(Default: 'unitA,unitB').", + ) + parser.add_argument("--prefix-size", type=int, default=None, + help='Limit the prefix size') + + # Batch sizes + parser.add_argument("--batch-max-tokens", type=int, default=9216, + help='maximum number of tokens considered in a batch') + parser.add_argument("--batch-max-positions", type=int, default=6144, + help='maximum number of tokens allowed for a sentence in a batch') + parser.add_argument("--batch-max-sentences", type=int, default=None, + help='maximum number of sentences considered in a batch') + parser.add_argument("--skip-invalid-size-batch", action='store_true', + help='skip sentences with more tokens than --batch-max-positions') + + # Generation args + parser.add_argument("--beam-search", action='store_true', + help='perform beam search instead of sampling') + parser.add_argument("--beam-size", type=int, default=5, + help="beam width (used in both sampling and beam search mode) " + "(default: 5)") + parser.add_argument("--sampling-topk", type=int, default=-1, + help="only sample from top-k candidates (default: -1, non applied)") + parser.add_argument("--sampling-topp", type=float, default=-1.0, + help="only sample among the smallest set of elements whose cumulative " + "probability mass exceeds p (default: -1.0, non applied)") + parser.add_argument("--max-len-a", type=int, default=0, + help="generate sequences of maximum length ax + b, " + "where x is the source length (default: 0)") + parser.add_argument("--max-len-b", type=int, default=500, + help="generate sequences of maximum length ax + b, " + "where x is the source length (default: 500 ~ 10s)") + parser.add_argument("--min-len", type=int, default=1, + help="generate sequences of maximum length ax + b, " + "where x is the source length (default: 1)") + parser.add_argument("--temperature", type=float, default=1.0, + help="temperature when generating unit tokens (default: 1.0)") + parser.add_argument("--dur-temperature", type=float, default=1.0, + help="temperature when generating duration tokens (default: 1.0)") + parser.add_argument("--verbose", action='store_true', + help="print the scores given by the model to generated sequences") + parser.add_argument("--seed", type=int, default=123, + help="seed of the generation model") + + args = parser.parse_args() + + main(args) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/textless_nlp/dgslm/vocoder_hifigan/README.md b/examples/textless_nlp/dgslm/vocoder_hifigan/README.md new file mode 100644 index 0000000000..5d4a59a9ac --- /dev/null +++ b/examples/textless_nlp/dgslm/vocoder_hifigan/README.md @@ -0,0 +1,47 @@ +# Dialogue Unit-to-Speech Decoder for dGSLM +For the unit2speech decoder, we train a [discrete unit-based HiFi-GAN vocoder](https://arxiv.org/pdf/2104.00355.pdf) on the [Fisher dataset](http://www.lrec-conf.org/proceedings/lrec2004/pdf/767.pdf). + +## Model checkpoint +The pre-trained model checkpoint can be found here : + +| HiFi-GAN vocoder based on HuBERT Fisher Units | +|-----------------------------------------------| +|[model checkpoint](https://dl.fbaipublicfiles.com/textless_nlp/dgslm/checkpoints/hifigan/hifigan_vocoder) - [config](https://dl.fbaipublicfiles.com/textless_nlp/dgslm/checkpoints/hifigan/config.json) | + +## Decode discrete units to audio +To create waveform from discrete units, use the script `generate_stereo_waveform.py` : +```bash +python examples/textless_nlp/dgslm/vocoder_hifigan/generate_stereo_waveform.py \ + --in-file $INPUT_CODE_FILE \ + --vocoder $VOCODER_PATH \ + --vocoder-cfg $VOCODER_CONFIG \ + --results-path $OUTPUT_DIR +``` +where INPUT_CODE_FILE is expected to have the following format : +``` +{'audio': 'file_1', 'unitA': '8 8 ... 352 352', 'unitB': '217 8 ... 8 8'} +{'audio': 'file_2', 'unitA': '5 5 ... 65 65', 'unitB': '6 35 ... 8 9'} +... +``` + +You can also use the HifiganVocoder class to generate waveform from the codes interactively : +```python +# Load the Hifigan vocoder +from examples.textless_nlp.dgslm.dgslm_utils import HifiganVocoder +decoder = HifiganVocoder( + vocoder_path = "/path/to/hifigan_vocoder", + vocoder_cfg_path = "/path/to/config.json", +) + +# Decode the units to waveform +codes = [ + '7 376 376 133 178 486 486 486 486 486 486 486 486 2 486', + '7 499 415 177 7 7 7 7 7 7 136 136 289 289 408', +] +wav = decoder.codes2wav(codes) +# > array of shape (2, 4800) + +# Play the waveform +import IPython.display as ipd +ipd.Audio(wav, rate=16_000) +``` diff --git a/examples/textless_nlp/dgslm/vocoder_hifigan/generate_stereo_waveform.py b/examples/textless_nlp/dgslm/vocoder_hifigan/generate_stereo_waveform.py new file mode 100644 index 0000000000..1e15f43241 --- /dev/null +++ b/examples/textless_nlp/dgslm/vocoder_hifigan/generate_stereo_waveform.py @@ -0,0 +1,137 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import ast +import argparse +import json +import logging +from pathlib import Path +import soundfile as sf +import torch + +from tqdm import tqdm + +from fairseq import utils +from fairseq.models.text_to_speech.vocoder import CodeHiFiGANVocoder + + +logging.basicConfig() +logging.root.setLevel(logging.INFO) +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +def dump_result(args, data, sample_id, pred_wav): + assert "audio" in data or args.results_path is not None + if args.results_path: + fname = Path(data["audio"]).stem + ".wav" if "audio" in data else f"{sample_id}_pred.wav" + out_file = Path(args.results_path) / fname + + sf.write( + out_file.as_posix(), + pred_wav.detach().cpu().numpy(), + args.sample_rate, + ) + + +def load_data(in_file): + with open(in_file) as f: + data = [ast.literal_eval(line.strip()) for line in f] + + return data + + +def load_vocoder(vocoder_path, vocoder_cfg_path, use_cuda=True): + with open(vocoder_cfg_path) as f: + cfg = json.load(f) + vocoder = CodeHiFiGANVocoder(vocoder_path, cfg).eval() + if use_cuda: + vocoder = vocoder.cuda() + return vocoder + + +def code2wav(vocoder, code, speaker_id, use_cuda=True): + if isinstance(code, str): + code = list(map(int, code.split())) + inp = dict() + inp["code"] = torch.LongTensor(code).view(1, -1) + if vocoder.model.multispkr: + inp["spkr"] = torch.LongTensor([speaker_id]).view(1, 1) + if use_cuda: + inp = utils.move_to_cuda(inp) + return vocoder(inp) + + +def main(args): + logger.info(args) + + use_cuda = torch.cuda.is_available() and not args.cpu + + vocoder = load_vocoder(args.vocoder, args.vocoder_cfg, use_cuda) + + data = load_data(args.in_file) + + if args.results_path: + Path(args.results_path).mkdir(exist_ok=True, parents=True) + + channels = args.channels.split(',') + speakers = [args.channel1_spk, args.channel2_spk] + + for i, d in tqdm(enumerate(data), total=len(data)): + wavs = [] + for key, speaker_id in zip(channels, speakers): + wav = code2wav(vocoder, d[key], speaker_id, use_cuda=use_cuda) + wavs.append(wav) + + wav = torch.stack(wavs, dim=-1) + if args.mix: + wav = torch.mean(wav, dim=-1) + + dump_result(args, d, i, wav) + + +def cli_main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--in-file", + type=str, + required=True, + help="Input file following the same format of the output from create_input.py", + ) + parser.add_argument( + "--vocoder", type=str, required=True, help="path to the vocoder" + ) + parser.add_argument( + "--vocoder-cfg", + type=str, + required=True, + help="path to the vocoder config", + ) + parser.add_argument( + "--channels", + type=str, + default='unitA,unitB', + help="Comma-separated list of the channel names" + "(Default: 'unitA,unitB').", + ) + parser.add_argument("--sample-rate", type=int, default=16_000) + parser.add_argument( + "--results-path", + type=str, + default=None, + help="Output directory. If not set, the audios will be stored following the 'audio' field specified in the input file", + ) + parser.add_argument("--channel1-spk", type=int, default=0, help="Speaker of the first channel",) + parser.add_argument("--channel2-spk", type=int, default=4, help="Speaker of the second channel",) + parser.add_argument("--mix", action="store_true", help="Mix the two channels to create output mono files") + parser.add_argument("--cpu", action="store_true", help="run on CPU") + + args = parser.parse_args() + + main(args) + + +if __name__ == "__main__": + cli_main() diff --git a/examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py b/examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py index 2c87445d81..dd95105232 100644 --- a/examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py +++ b/examples/textless_nlp/gslm/speech2unit/clustering/quantize_with_kmeans.py @@ -75,6 +75,16 @@ def get_parser(): parser.add_argument( "--extension", type=str, default=".flac", help="Features file path" ) + parser.add_argument( + "--channel_id", + choices=['1', '2'], + help="The audio channel to extract the units in case of stereo file.", + default=None, + ) + parser.add_argument( + "--hide-fname", action='store_true', + help="Hide file names in the output file." + ) return parser @@ -92,6 +102,7 @@ def main(args, logger): manifest_path=args.manifest_path, sample_pct=1.0, flatten=False, + channel_id=int(args.channel_id) if args.channel_id else None, ) logger.info( f"Features extracted for {len(features_batch)} utterances.\n" @@ -113,8 +124,13 @@ def main(args, logger): for i, feats in enumerate(features_batch): pred = kmeans_model.predict(feats) pred_str = " ".join(str(p) for p in pred) - base_fname = os.path.basename(fnames[i]).rstrip(args.extension) - fout.write(f"{base_fname}|{pred_str}\n") + base_fname = os.path.basename(fnames[i]).rstrip('.'+args.extension.lstrip('.')) + if args.channel_id is not None: + base_fname = base_fname+f'-channel{args.channel_id}' + if not args.hide_fname: + fout.write(f"{base_fname}|{pred_str}\n") + else: + fout.write(f"{pred_str}\n") if __name__ == "__main__": diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py index c613f52d3c..2ea3890c28 100644 --- a/examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/cpc_feature_reader.py @@ -18,15 +18,25 @@ def __init__( norm_features=False, sample_rate=16000, max_chunk=64000, + use_cuda=True, ): - self.model = load_cpc_model(checkpoint_path, layer).eval().cuda() + self.model = load_cpc_model(checkpoint_path, layer).eval() self.sample_rate = sample_rate self.max_chunk = max_chunk self.norm_features = norm_features self.use_encoder_layer = use_encoder_layer + self.use_cuda = use_cuda + if self.use_cuda: + self.model.cuda() - def read_audio(self, path, ref_len=None): + def read_audio(self, path, ref_len=None, channel_id=None): wav, sr = sf.read(path) + if channel_id is not None: + assert wav.ndim == 2, \ + f"Expected stereo input when channel_id is given ({path})" + assert channel_id in [1, 2], \ + "channel_id is expected to be in [1, 2]" + wav = wav[:, channel_id-1] if wav.ndim == 2: wav = wav.mean(-1) assert wav.ndim == 1, wav.ndim @@ -35,11 +45,13 @@ def read_audio(self, path, ref_len=None): print(f"ref {ref_len} != read {len(wav)} ({path})") return wav - def get_feats(self, file_path, ref_len=None): - x = self.read_audio(file_path, ref_len) + def get_feats(self, file_path, ref_len=None, channel_id=None): + x = self.read_audio(file_path, ref_len, channel_id) # Inspired from CPC_audio feature_loader.py with torch.no_grad(): - x = torch.from_numpy(x).float().cuda() + x = torch.from_numpy(x).float() + if self.use_cuda: + x = x.cuda() x = x.view(1, 1, -1) size = x.size(2) feat = [] diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py index 09442206e1..4fef859fb3 100644 --- a/examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/hubert_feature_reader.py @@ -15,7 +15,7 @@ class HubertFeatureReader: Helps extract features for a given audio file. """ - def __init__(self, checkpoint_path, layer, max_chunk=1600000): + def __init__(self, checkpoint_path, layer, max_chunk=1600000, use_cuda=True): ( model, cfg, @@ -23,13 +23,22 @@ def __init__(self, checkpoint_path, layer, max_chunk=1600000): ) = fairseq.checkpoint_utils.load_model_ensemble_and_task( [checkpoint_path] ) - self.model = model[0].eval().cuda() + self.model = model[0].eval() self.task = task self.layer = layer self.max_chunk = max_chunk + self.use_cuda = use_cuda + if self.use_cuda: + self.model.cuda() - def read_audio(self, path, ref_len=None): + def read_audio(self, path, ref_len=None, channel_id=None): wav, sr = sf.read(path) + if channel_id is not None: + assert wav.ndim == 2, \ + f"Expected stereo input when channel_id is given ({path})" + assert channel_id in [1, 2], \ + "channel_id is expected to be in [1, 2]" + wav = wav[:, channel_id-1] if wav.ndim == 2: wav = wav.mean(-1) assert wav.ndim == 1, wav.ndim @@ -38,10 +47,12 @@ def read_audio(self, path, ref_len=None): print(f"ref {ref_len} != read {len(wav)} ({path})") return wav - def get_feats(self, file_path, ref_len=None): - x = self.read_audio(file_path, ref_len) + def get_feats(self, file_path, ref_len=None, channel_id=None): + x = self.read_audio(file_path, ref_len, channel_id) with torch.no_grad(): - x = torch.from_numpy(x).float().cuda() + x = torch.from_numpy(x).float() + if self.use_cuda: + x = x.cuda() if self.task.cfg.normalize: x = F.layer_norm(x, x.shape) x = x.view(1, -1) diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py index 106f502476..5879da7067 100644 --- a/examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/logmel_feature_reader.py @@ -13,13 +13,17 @@ class LogMelFeatureReader: Wrapper class to run inference on HuBERT model. Helps extract features for a given audio file. """ - + def __init__(self, *args, **kwargs): self.num_mel_bins = kwargs.get("num_mel_bins", 80) self.frame_length = kwargs.get("frame_length", 25.0) - def get_feats(self, file_path): + def get_feats(self, file_path, channel_id=None): wav, sr = sf.read(file_path) + if channel_id is not None: + assert wav.ndim == 2, \ + f"Expected stereo input when channel_id is given ({file_path})" + wav = wav[:, channel_id-1] feats = torch.from_numpy(wav).float() feats = kaldi.fbank( feats.unsqueeze(0), diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/utils.py b/examples/textless_nlp/gslm/speech2unit/pretrained/utils.py index 5aaddf6421..2eca68e800 100644 --- a/examples/textless_nlp/gslm/speech2unit/pretrained/utils.py +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/utils.py @@ -39,7 +39,7 @@ def get_feature_reader(feature_type): def get_feature_iterator( - feature_type, checkpoint_path, layer, manifest_path, sample_pct + feature_type, checkpoint_path, layer, manifest_path, sample_pct, channel_id ): feature_reader_cls = get_feature_reader(feature_type) with open(manifest_path, "r") as fp: @@ -61,14 +61,14 @@ def get_feature_iterator( def iterate(): for file_path in file_path_list: - feats = reader.get_feats(file_path) + feats = reader.get_feats(file_path, channel_id=channel_id) yield feats.cpu().numpy() return iterate, num_files def get_features( - feature_type, checkpoint_path, layer, manifest_path, sample_pct, flatten + feature_type, checkpoint_path, layer, manifest_path, sample_pct, flatten, channel_id ): generator, num_files = get_feature_iterator( feature_type=feature_type, @@ -76,6 +76,7 @@ def get_features( layer=layer, manifest_path=manifest_path, sample_pct=sample_pct, + channel_id=channel_id ) iterator = generator() diff --git a/examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py b/examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py index b878321e44..9f9da6c499 100644 --- a/examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py +++ b/examples/textless_nlp/gslm/speech2unit/pretrained/w2v2_feature_reader.py @@ -14,7 +14,7 @@ class Wav2VecFeatureReader: Helps extract features for a given audio file. """ - def __init__(self, checkpoint_path, layer): + def __init__(self, checkpoint_path, layer, use_cuda=True): state = fairseq.checkpoint_utils.load_checkpoint_to_cpu( checkpoint_path ) @@ -24,22 +24,32 @@ def __init__(self, checkpoint_path, layer): model = self.task.build_model(w2v_args) model.load_state_dict(state["model"], strict=True) model.eval() - model.cuda() self.model = model self.layer = layer + self.use_cuda = use_cuda + if self.use_cuda: + self.model.cuda() - def read_audio(self, fname): + def read_audio(self, fname, channel_id=None): wav, sr = sf.read(fname) + if channel_id is not None: + assert wav.ndim == 2, \ + f"Expected stereo input when channel_id is given ({fname})" + assert channel_id in [1, 2], \ + "channel_id is expected to be in [1, 2]" + wav = wav[:, channel_id-1] if wav.ndim == 2: wav = wav.mean(-1) assert wav.ndim == 1, wav.ndim assert sr == self.task.cfg.sample_rate, sr return wav - def get_feats(self, file_path): - x = self.read_audio(file_path) + def get_feats(self, file_path, channel_id=None): + x = self.read_audio(file_path, channel_id) with torch.no_grad(): - source = torch.from_numpy(x).view(1, -1).float().cuda() + source = torch.from_numpy(x).view(1, -1).float() + if self.use_cuda: + source = source.cuda() res = self.model( source=source, mask=False, features_only=True, layer=self.layer ) diff --git a/fairseq/criterions/speech_dlm_criterion.py b/fairseq/criterions/speech_dlm_criterion.py new file mode 100644 index 0000000000..8888180114 --- /dev/null +++ b/fairseq/criterions/speech_dlm_criterion.py @@ -0,0 +1,335 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from dataclasses import dataclass, field +from typing import Optional + +import torch.nn.functional as F +from fairseq import metrics, utils +from fairseq.criterions import FairseqCriterion, register_criterion +from fairseq.dataclass import FairseqDataclass +from omegaconf import II + + +@dataclass +class SpeechDLMCriterionConfig(FairseqDataclass): + sentence_avg: bool = II("optimization.sentence_avg") + main_and_cross_weights: Optional[str] = field( + default="1,0", + metadata={ + "help": "Comma-separated list of weights of Main-channel vs Cross-channel Prediction Losses" + "(default: 1,0)" + }, + ) + general_unit_loss_weight: float = field( + default=0, + metadata={ + "help": "The weight of the General Prediction Loss (Next-step Unit Prediction Loss)" + "(default: 0)" + }, + ) + edge_unit_loss_weight: float = field( + default=1, + metadata={"help": "The weight of the Edge Unit Prediction Loss" "(default: 1)"}, + ) + duration_loss_weight: float = field( + default=1, + metadata={ + "help": "The weight of the Edge Unit Duration Prediction Loss" + "(default: 1)" + }, + ) + + +@register_criterion("speech_dlm_criterion", dataclass=SpeechDLMCriterionConfig) +class SpeechDLMCriterion(FairseqCriterion): + """Criteron for the SpeechDLM model as described in the paper: + https://arxiv.org/pdf/2203.16502.pdf + + There are 3 possible losses depending on the targets of the model: + - general_unit_loss : The next unit prediction loss, corresponding to + 'next' target + - edge_unit_loss : The edge unit prediction loss, corresponding to + 'edge' target + - duration_loss : The duration prediction loss, corresponding to + 'duration' target + """ + + def __init__( + self, + task, + sentence_avg, + main_and_cross_weights, + general_unit_loss_weight, + edge_unit_loss_weight, + duration_loss_weight, + ): + super().__init__(task) + self.sentence_avg = sentence_avg + + self.channels = task.channels + self.targets = task.targets + self.delayed_duration_target = task.delayed_duration_target + + self.main_channel_weight = float(main_and_cross_weights.split(",")[0]) + self.cross_channel_weight = float(main_and_cross_weights.split(",")[1]) + assert self.main_channel_weight >= 0 and self.cross_channel_weight >= 0 + + self.channel_weights = { + channel: weight + for channel, weight in zip(self.channels, task.channel_weights) + } + + self.target_weights = {} + for t in self.targets: + if t == "next": + self.target_weights[t] = general_unit_loss_weight + assert ( + general_unit_loss_weight > 0 + ), "Expect a positive --general-unit-loss-weight for next unit prediction" + elif t == "edge": + self.target_weights[t] = edge_unit_loss_weight + assert ( + edge_unit_loss_weight > 0 + ), "Expect a positive --edge-unit-loss-weight for edge unit prediction" + elif t == "duration": + self.target_weights[t] = duration_loss_weight + assert ( + duration_loss_weight > 0 + ), "Expect a positive --duration-loss-weight for duration prediction" + + def forward(self, model, sample, reduce=True): + """Compute the loss for the given sample. + + Returns a tuple with three elements: + 1) the loss + 2) the sample size, which is used as the denominator for the gradient + 3) logging outputs to display while training + """ + net_output = model(**sample["net_input"]) + loss_dict, stats_dict = self.compute_loss( + model, net_output, sample, reduce=reduce + ) + nsentences = sample["net_input"]["src_tokens"][self.channels[0]].size(0) + + logging_output = { + "nsentences": nsentences, + } + logging_output["nsentences"] = nsentences + + loss_all = {t: 0 for t in self.targets} + correct_all = {t: 0 for t in self.targets} + count_all = {t: 0 for t in self.targets} + ntokens_all = 0 + sample_size_all = 0 + for channel in loss_dict: + for pred_channel in loss_dict[channel]: + # Get ntokens & sample_size + ntokens = sample["net_input"]["src_tokens"][channel].numel() + sample_size = nsentences if self.sentence_avg else ntokens + prefix = "[{}-{}]".format(channel, pred_channel) + log_keys = { + "next": "general_token", + "edge": "edge_token", + "duration": "edge_duration", + } + + # Log & Update the sizes + logging_output["{}ntokens".format(prefix)] = ntokens + logging_output["{}sample_size".format(prefix)] = sample_size + ntokens_all += ntokens + sample_size_all += sample_size + + for t in self.targets: + log_key = log_keys[t] + loss = loss_dict[channel][pred_channel][t] + correct, count = stats_dict[channel][pred_channel][t] + + # Log the statistics + logging_output["{}{}_loss".format(prefix, log_key)] = loss.data + logging_output["{}{}_correct".format(prefix, log_key)] = correct + logging_output["{}{}_count".format(prefix, log_key)] = count + + # Scale the training loss by weights + target_loss = loss * self.channel_weights[channel] + if pred_channel == channel: + target_loss = target_loss * self.main_channel_weight + else: + target_loss = target_loss * self.cross_channel_weight + # Normalize the losses in the training by the number of edges + if t in ["edge", "duration"]: + target_loss = target_loss / count * sample_size + + # Update the statistics + loss_all[t] += target_loss + correct_all[t] += correct + count_all[t] += count + + # Logging the average statistics + logging_output["ntokens"] = ntokens_all + logging_output["sample_size"] = sample_size_all + for t in self.targets: + log_key = { + "next": "general_token", + "edge": "edge_token", + "duration": "edge_duration", + }[t] + logging_output["{}_loss".format(log_key)] = loss_all[t].data + logging_output["{}_correct".format(log_key)] = correct_all[t] + logging_output["{}_count".format(log_key)] = count_all[t] + + # Define the training loss + training_loss = 0 + for t in self.targets: + training_loss += loss_all[t] * self.target_weights[t] + logging_output["loss"] = training_loss.data + + return training_loss, sample_size_all, logging_output + + def compute_loss(self, model, net_output, sample, reduce=True): + # Get the model outputs and target + lprobs_dict = model.get_normalized_probs(net_output, log_probs=True) + target_dict = model.get_targets(sample, net_output) + + # Init the dictionaries + loss_dict, stats_dict = {}, {} + + for channel in lprobs_dict: + # Init the dictionaries + loss_dict[channel], stats_dict[channel] = {}, {} + + for pred_channel in lprobs_dict[channel]: + # Init the dictionaries + loss_dict[channel][pred_channel] = {} + stats_dict[channel][pred_channel] = {} + + # Get token & duration predictions + outputs = lprobs_dict[channel][pred_channel] + if not isinstance(outputs, dict): + token_lprobs = outputs + else: + token_lprobs = outputs["pred_token"] + dur_preds = outputs["pred_duration"] + dur_preds = dur_preds.view(-1) + token_lprobs = token_lprobs.view(-1, token_lprobs.size(-1)) + token_preds = token_lprobs.argmax(dim=-1) + + # Get edge indices + if "edge" in self.targets or "duration" in self.targets: + edge_indices = target_dict["edge_indices"][pred_channel] + + # Compute loss and statistics + for t in self.targets: + if t in ["next", "edge"]: + if t == "next": + target = target_dict["next"][pred_channel].view(-1) + lprobs = token_lprobs + preds = token_preds + elif t == "edge": + target = target_dict["edge"][pred_channel] + lprobs = token_lprobs[edge_indices] + preds = token_preds[edge_indices] + + loss = F.nll_loss( + lprobs, + target, + ignore_index=self.padding_idx, + reduction="sum" if reduce else "none", + ) + elif t == "duration": + target = target_dict["duration"][pred_channel] + if self.delayed_duration_target: + duration_indices = edge_indices + 1 + if duration_indices[-1] == len(dur_preds): + duration_indices = duration_indices[:-1] + target = target[:-1] + else: + duration_indices = edge_indices + preds = dur_preds[duration_indices] + + loss = F.l1_loss( + preds, + target, + reduction="sum" if reduce else "none", + ) + preds = preds.round() + + correct = (preds == target).sum().float().cpu().item() + count = float(target.size(0)) + + loss_dict[channel][pred_channel][t] = loss + stats_dict[channel][pred_channel][t] = (correct, count) + + return loss_dict, stats_dict + + @staticmethod + def reduce_metrics(logging_outputs) -> None: + """Aggregate logging outputs from data parallel training.""" + logging_keys = next(iter(logging_outputs)).keys() + channels = [item[:-7] for item in logging_keys if item.endswith("ntokens")] + target_prefixes = set( + [ + item[:-5].split("]")[-1] + for item in logging_keys + if item.endswith("_loss") + ] + ) + for channel_prefix in channels: + for target_prefix in target_prefixes: + prefix = "{}{}".format(channel_prefix, target_prefix) + count_sum = sum( + log.get("{}_count".format(prefix), 0) for log in logging_outputs + ) + correct_sum = sum( + log.get("{}_correct".format(prefix), 0) for log in logging_outputs + ) + loss_sum = sum( + log.get("{}_loss".format(prefix), 0) for log in logging_outputs + ) + + if "duration" not in target_prefix: + # we divide by log(2) to convert the loss from base e to base 2 + metrics.log_scalar( + "{}_loss".format(prefix), + loss_sum / count_sum / math.log(2), + count_sum, + round=3, + ) + metrics.log_derived( + "{}_ppl".format(prefix), + lambda meters, prefix=prefix: utils.get_perplexity( + meters["{}_loss".format(prefix)].avg + ), + ) + else: + # for duration we don't need to divide by log(2) + metrics.log_scalar( + "{}_loss".format(prefix), + loss_sum / count_sum, + count_sum, + round=3, + ) + + accuracy = 100 * correct_sum / count_sum + metrics.log_scalar("{}_pred_acc".format(prefix), accuracy, round=3) + + # Logging training loss + sample_size = sum(log.get("sample_size", 0) for log in logging_outputs) + loss_sum = sum(log.get("loss", 0) for log in logging_outputs) + + # we divide by log(2) to convert the loss from base e to base 2 + metrics.log_scalar( + "loss", loss_sum / sample_size / math.log(2), sample_size, round=3 + ) + + @staticmethod + def logging_outputs_can_be_summed() -> bool: + """ + Whether the logging outputs returned by `forward` can be summed + across workers prior to calling `reduce_metrics`. Setting this + to True will improves distributed training speed. + """ + return True diff --git a/fairseq/data/__init__.py b/fairseq/data/__init__.py index a27e3184aa..eeaae2b254 100644 --- a/fairseq/data/__init__.py +++ b/fairseq/data/__init__.py @@ -53,6 +53,7 @@ from .roll_dataset import RollDataset from .round_robin_zip_datasets import RoundRobinZipDatasets from .sort_dataset import SortDataset +from .speech_dlm_dataset import SpeechDLMDataset from .strip_token_dataset import StripTokenDataset from .subsample_dataset import SubsampleDataset from .token_block_dataset import TokenBlockDataset @@ -124,6 +125,7 @@ "SampledMultiEpochDataset", "ShardedIterator", "SortDataset", + "SpeechDLMDataset", "StripTokenDataset", "SubsampleDataset", "TokenBlockDataset", diff --git a/fairseq/data/speech_dlm_dataset.py b/fairseq/data/speech_dlm_dataset.py new file mode 100644 index 0000000000..06c4808f0a --- /dev/null +++ b/fairseq/data/speech_dlm_dataset.py @@ -0,0 +1,307 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from collections import OrderedDict + +import numpy as np +import torch + +from fairseq.data import FairseqDataset, MonolingualDataset, data_utils + + +class SpeechDLMDataset(FairseqDataset): + """The dataset used to train the SpeechDLM model as described in the paper: + https://arxiv.org/pdf/2203.16502.pdf + + The input datasets is expected to be a dict over channel names with the values + being instances of :class:`~fairseq.data.MonolingualDataset`. + + Each element of SpeechDLMDataset is a dictionary with the following keys: + - `id` (int) : index of the item + - `source` (OrderedDict[str, Tensor of shape (seq_len,)]) : dictionary over + channels with the values containing the input unit tokens + - `target_next` (OrderedDict[str, Tensor of shape (seq_len,)]) : dictionary + over channels with the values containing the next unit tokens (input + tokens shifted by 1). + Its value is None if 'next' not in self.targets + - `target_edge` (OrderedDict[str, Tensor of shape (dedup_seq_len,)]) : dictionary + over channels with the values containing the edge unit tokens (input tokens + deduplicated). + Its value is None if 'edge' not in self.targets + - `target_duration` (OrderedDict[str, Tensor of shape (dedup_seq_len,)]) : + dictionary over channels with the values being the durations of the edge units. + Its value is None if 'duration' not in targets. + - `target_edge_indices` (OrderedDict[str, Tensor of shape (dedup_seq_len,)]) : + dictionary over channels with the values being the indices of the edge units + in the source sequence. + Its value is None if neither 'edge' or 'duration in targets. + + Args: + datasets (Dict[str, ~fairseq.data.MonolingualDataset]): a dictionary of + :class:`~fairseq.data.MonolingualDataset` instances. + targets (List[str]): list of the target types that the SpeechDLM model + should predict. Can be one of "next", "edge", "duration". + shuffle (bool, optional): shuffle the elements before batching + (default: True). + """ + + def __init__( + self, datasets, targets=None, max_target_durations=None, shuffle=False + ): + super().__init__() + if isinstance(datasets, dict): + datasets = OrderedDict(datasets) + assert isinstance( + datasets, OrderedDict + ), "datasets is expected to be an instance of Dictionary or OrderedDict" + assert datasets, "datasets is None" + for dataset in datasets.values(): + assert isinstance( + dataset, MonolingualDataset + ), "Each value of datasets is expected to be an instance of MonolingualDataset" + + self.datasets = datasets + self.targets = targets + if max_target_durations is not None and max_target_durations > 0: + self.max_target_durations = max_target_durations + else: + self.max_target_durations = float("inf") + self.sizes = next(iter(datasets.values())).sizes + self.vocab = next(iter(datasets.values())).vocab + self.length = len(next(iter(datasets.values()))) + self.shuffle = shuffle + + for channel, dataset in datasets.items(): + assert ( + len(dataset) == self.length + ), "[{}] length mismatch ({} vs {})".format( + channel, len(dataset), self.length + ) + assert (dataset.sizes == self.sizes).all(), "[{}] sizes mismatch".format( + channel + ) + + assert ( + dataset.vocab.pad() == self.vocab.pad() + ), "pad token is expected to be the same" + assert ( + dataset.vocab.eos() == self.vocab.eos() + ), "eos token is expected to be the same" + assert ( + dataset.vocab.bos() == self.vocab.bos() + ), "bos token is expected to be the same" + assert ( + dataset.vocab.unk() == self.vocab.unk() + ), "unk token is expected to be the same" + + def __getitem__(self, index): + source = OrderedDict( + [ + (key, dataset[index]["source"]) + for (key, dataset) in self.datasets.items() + ] + ) + + item = { + "id": index, + "source": source, + "target_next": None, + "target_edge": None, + "target_duration": None, + "target_edge_indices": None, + } + + if self.targets is not None: + for channel in self.datasets: + target = self._get_target(index, channel) + for t in target: + if item[f"target_{t}"] is None: + item[f"target_{t}"] = OrderedDict() + item[f"target_{t}"][channel] = target[t] + + return item + + def __len__(self): + return self.length + + def _get_target(self, index, channel): + """Get target in one of ['next', 'edge', 'duration'] + - 'next' is the future unit + - 'edge' is the edge unit + - 'duration' is the duration of the edge unit + """ + if self.targets is not None: + target = {} + pad_idx = self.vocab.pad() + max_dur = self.max_target_durations + future_target = self.datasets[channel][index]["target"] + if "edge" in self.targets or "duration" in self.targets: + edge_units, edge_unit_counts = torch.unique_consecutive( + future_target, return_counts=True + ) + padding_end = edge_units[-1] == pad_idx + if padding_end: + edge_units = edge_units[:-1] + edge_unit_counts = edge_unit_counts[:-1] + edge_indices = torch.cumsum(edge_unit_counts, 0) + edge_indices = torch.cat([torch.tensor([0]), edge_indices[:-1]]) + target["edge_indices"] = edge_indices + + for t in self.targets: + if t == "next": + target[t] = future_target + elif t == "edge": + target[t] = edge_units + elif t == "duration": + # count the remaining duration of the last edge indices in the next sentence + if not padding_end and index < len(self.datasets[channel]) - 1: + i = 0 + next_sentence_target = self.datasets[channel][index + 1][ + "target" + ] + while ( + next_sentence_target[i] == edge_units[-1] + and edge_unit_counts[-1] + i < max_dur + ): + i += 1 + edge_unit_counts[-1] += i + + # cut off to the maximal threshold + if max_dur: + edge_unit_counts[edge_unit_counts > max_dur] = max_dur + + target[t] = edge_unit_counts + else: + raise Exception("invalid target " + t) + + return target + + def collater(self, samples): + """Merge a list of samples to form a mini-batch. + + Args: + samples (List[dict]): samples to collate + + Returns: + dict: a mini-batch with the following keys: + + - `id` (LongTensor): example IDs in the original input order + - `ntokens` (int): total number of tokens in the batch + - `net_input` (dict): the input to the Model, containing keys: + + - `src_tokens` (OrderedDict[str, LongTensor]): dictionary + over channel with the values being padded 2D Tensor of + samples `source` of shape `(bsz, src_len)`. + Padding will appear on the right. + - `src_lengths` (LongTensor): lengths of source sentences + in the mini-batch + + - `target` (dict): the target of the Model, containing keys: + + - `next` (OrderedDict[str, LongTensor]): dictionary + over channel with the values being padded 2D Tensor of + batch samples' `target_next` of shape `(bsz, tgt_len)`. + Padding will appear on the right. + - `edge` (OrderedDict[str, LongTensor]): dictionary + over channel with the values being the concatenated + 1D Tensor of batch samples' `target_edge` of shape + `(sum of dedup_tgt_len,)` + - `duration` (OrderedDict[str, LongTensor]): dictionary + over channel with the values being the concatenated + 1D Tensor of batch samples' `target_duration` of shape + `(sum of dedup_tgt_len,)` + - `edge_indices` (OrderedDict[str, LongTensor]): dictionary + over channel with the values being the concatenated + 1D Tensor of batch samples' `target_edge_indices` of + shape `(sum of dedup_tgt_len,)`. + The indices are added to multiplies of batch size + such that they are the actual indices in the flatten + `src_tokens` Tensor + """ + if len(samples) == 0: + return {} + + pad_idx = self.vocab.pad() + eos_idx = self.vocab.eos() + + def merge(key, max_size=None): + if samples[0][key] is None: + return None + res = OrderedDict() + for channel in samples[0][key]: + if key in ["source", "target_next"]: + # fill batch of shape: (batch_size, max_size) + res[channel] = data_utils.collate_tokens( + [s[key][channel] for s in samples], + pad_idx, + eos_idx, + left_pad=False, + ) + elif key in ["target_edge", "target_duration"]: + # concatenate the edge units/duration + res[channel] = torch.cat([s[key][channel] for s in samples]) + elif key == "target_edge_indices": + # increase the edge indices to the indices in the flatten batch + res[channel] = torch.cat( + [s[key][channel] + i * max_size for i, s in enumerate(samples)] + ) + + return res + + src_tokens = merge("source") + tgt_next = merge("target_next") + tgt_edge = merge("target_edge") + tgt_duration = merge("target_duration") + tgt_edge_indices = merge( + "target_edge_indices", max_size=next(iter(src_tokens.values())).size(-1) + ) + return { + "id": torch.LongTensor([s["id"] for s in samples]), + "nsentences": len(samples), + "ntokens": sum(len(item) for s in samples for item in s["source"].values()), + "net_input": { + "src_tokens": src_tokens, + "src_lengths": torch.LongTensor( + [next(iter(s["source"].values())).numel() for s in samples] + ), + }, + "target": { + "next": tgt_next, + "edge": tgt_edge, + "duration": tgt_duration, + "edge_indices": tgt_edge_indices, + }, + } + + def num_tokens(self, index): + """Return the number of tokens in a sample. This value is used to + enforce ``--max-tokens`` during batching.""" + return self.sizes[index] + + def size(self, index): + """Return an example's size as a float or tuple. This value is used when + filtering a dataset with ``--max-positions``.""" + return self.sizes[index] + + def ordered_indices(self): + """Return an ordered list of indices. Batches will be constructed based + on this order.""" + if self.shuffle: + order = [np.random.permutation(len(self))] + else: + order = [np.arange(len(self))] + order.append(self.sizes) + return np.lexsort(order) + + @property + def supports_prefetch(self): + return all( + getattr(dataset, "supports_prefetch", False) + for dataset in self.datasets.values() + ) + + def prefetch(self, indices): + for key, dataset in self.datasets.items(): + dataset.prefetch(indices) diff --git a/fairseq/models/speech_dlm/__init__.py b/fairseq/models/speech_dlm/__init__.py new file mode 100644 index 0000000000..6ea914d6a5 --- /dev/null +++ b/fairseq/models/speech_dlm/__init__.py @@ -0,0 +1,7 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .speech_dlm import * # noqa +from .hub_interface import * # noqa diff --git a/fairseq/models/speech_dlm/hub_interface.py b/fairseq/models/speech_dlm/hub_interface.py new file mode 100644 index 0000000000..11bc0f50bb --- /dev/null +++ b/fairseq/models/speech_dlm/hub_interface.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import copy +import logging +from typing import Any, Dict, Iterator, List + +import torch +from fairseq import utils +from omegaconf import open_dict +from torch import nn + +from tqdm import tqdm + +from fairseq.hub_utils import GeneratorHubInterface + + +logger = logging.getLogger(__name__) + + +class MultichannelGeneratorHubInterface(GeneratorHubInterface): + """Pytorch Hub interface for generating sequences from a pre-trained + multichannel language model. + """ + + def __init__(self, cfg, task, models): + super().__init__(cfg, task, models) + self.cfg = cfg + self.task = task + self.models = nn.ModuleList(models) + self.src_dicts = task.source_dictionaries + self.tgt_dicts = task.target_dictionaries + self.channels = task.channels + + # optimize model for generation + for model in self.models: + model.prepare_for_inference_(cfg) + + def sample( + self, + sentences: List[Dict[str, str]], + beam: int = 1, + verbose: bool = False, + **kwargs + ) -> List[str]: + if isinstance(sentences, dict): + return self.sample([sentences], beam=beam, verbose=verbose, **kwargs)[0] + tokenized_sentences = [self.encode(sentence) for sentence in sentences] + batched_hypos = self.generate(tokenized_sentences, beam, verbose, **kwargs) + return [self.decode(hypos[0]["tokens"]) for hypos in batched_hypos] + + def score(self, sentences: List[Dict[str, str]], **kwargs): + raise NotImplementedError( + "MultichannelGeneratorHubInterface doesn't support score() method" + ) + + def generate( + self, + tokenized_sentences: List[Dict[str, torch.LongTensor]], + beam: int = 5, + verbose: bool = False, + skip_invalid_size_inputs=False, + inference_step_args=None, + **kwargs + ) -> List[List[Dict[str, torch.Tensor]]]: + if isinstance(tokenized_sentences, dict): + return self.generate( + [tokenized_sentences], beam=beam, verbose=verbose, **kwargs + )[0] + + # build generator using current args as well as any kwargs + gen_args = copy.deepcopy(self.cfg.generation) + with open_dict(gen_args): + gen_args.beam = beam + for k, v in kwargs.items(): + setattr(gen_args, k, v) + generator = self.task.build_generator(self.models, gen_args) + + inference_step_args = inference_step_args or {} + results = [] + for batch in tqdm( + self._build_batches(tokenized_sentences, skip_invalid_size_inputs) + ): + batch = utils.apply_to_sample(lambda t: t.to(self.device), batch) + translations = self.task.inference_step( + generator, self.models, batch, **inference_step_args + ) + for id, hypos in zip(batch["id"].tolist(), translations): + # The output of the generator is supposed to be a tensor of size (bsz x max_len x n_channels) + # So we need to convert it to dictionary form + for i in range(len(hypos)): + hypos[i]["tokens"] = { + channel: hypos[i]["tokens"][..., j] + for j, channel in enumerate(self.channels) + } + results.append((id, hypos)) + + # sort output to match input order + outputs = [hypos for _, hypos in sorted(results, key=lambda x: x[0])] + + if verbose: + + def getarg(name, default): + return getattr(gen_args, name, getattr(self.cfg, name, default)) + + for source_tokens, target_hypotheses in zip(tokenized_sentences, outputs): + src_str_with_unk = { + channel: self.string(source_tokens[channel], channel) + for channel in source_tokens + } + logger.info("S\t{}".format(src_str_with_unk)) + for hypo in target_hypotheses: + hypo_str = self.decode(hypo["tokens"]) + logger.info("H\t{}\t{}".format(hypo["score"], hypo_str)) + # hypo["positional_scores"]: T x n_channels + pos_scores = {} + for c, channel in enumerate(source_tokens): + pos_scores[channel] = " ".join( + map( + lambda x: "{:.4f}".format(x), + hypo["positional_scores"][:, c].tolist(), + ) + ) + logger.info("P\t{}".format(pos_scores)) + + return outputs + + def encode(self, sentence: Dict[str, str]) -> Dict[str, torch.LongTensor]: + assert isinstance( + sentence, dict + ), "Input sentence is expected to be a dictionary over channels" + assert set(sentence.keys()) == set( + self.channels + ), "Mismatch between input sentence keys and model channels ({} vs {})".format( + set(sentence.keys()), set(self.channels) + ) + encoded_sentence = {} + for channel in sentence: + sentence_channel = sentence[channel] + sentence_channel = self.tokenize(sentence_channel) + sentence_channel = self.apply_bpe(sentence_channel) + sentence_channel = self.binarize(sentence_channel, channel) + encoded_sentence[channel] = sentence_channel + sentence_size = encoded_sentence[self.channels[0]].size() + assert all( + encoded_sentence[channel].size() == sentence_size + for channel in encoded_sentence + ), "Input tensors are expected to have the same size in all channels" + return encoded_sentence + + def decode(self, tokens: Dict[str, torch.LongTensor]) -> Dict[str, str]: + assert isinstance( + tokens, dict + ), "Input tokens are expected to be a dictionary over channels" + assert set(tokens.keys()) == set( + self.channels + ), "Mismatch between input tokens keys and model channels ({} vs {})".format( + set(tokens.keys()), set(self.channels) + ) + decoded_sentence = {} + for channel in tokens: + tokens_channel = tokens[channel] + sentence_channel = self.string(tokens_channel, channel) + sentence_channel = self.remove_bpe(sentence_channel) + sentence_channel = self.detokenize(sentence_channel) + decoded_sentence[channel] = sentence_channel + return decoded_sentence + + def binarize(self, sentence: str, channel: str) -> torch.LongTensor: + return ( + self.src_dicts[channel].encode_line(sentence, add_if_not_exist=False).long() + ) + + def string(self, tokens: torch.LongTensor, channel: str) -> str: + return self.tgt_dicts[channel].string(tokens) + + def _build_batches( + self, tokens: List[Dict[str, List[int]]], skip_invalid_size_inputs: bool + ) -> Iterator[Dict[str, Any]]: + lengths = torch.LongTensor([next(iter(d.values())).numel() for d in tokens]) + batch_iterator = self.task.get_batch_iterator( + dataset=self.task.build_dataset_for_inference(tokens, lengths), + max_tokens=self.cfg.dataset.max_tokens, + max_sentences=self.cfg.dataset.batch_size, + max_positions=self.max_positions, + ignore_invalid_inputs=skip_invalid_size_inputs, + disable_iterator_cache=True, + ).next_epoch_itr(shuffle=False) + return batch_iterator diff --git a/fairseq/models/speech_dlm/modules/__init__.py b/fairseq/models/speech_dlm/modules/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/fairseq/models/speech_dlm/modules/speech_dlm_decoder.py b/fairseq/models/speech_dlm/modules/speech_dlm_decoder.py new file mode 100644 index 0000000000..a14a1d64a8 --- /dev/null +++ b/fairseq/models/speech_dlm/modules/speech_dlm_decoder.py @@ -0,0 +1,572 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Any, Dict, List, Optional, Tuple + +import torch +import torch.nn as nn +from fairseq import utils +from fairseq.models import FairseqIncrementalDecoder +from fairseq.modules import ( + FairseqDropout, + LayerDropModuleList, + LayerNorm, + PositionalEmbedding, +) +from .speech_dlm_decoder_layer import ( + CrossChannelTransformerDecoderLayer, + StandardTransformerDecoderLayer, +) +from fairseq.modules.checkpoint_activations import checkpoint_wrapper +from fairseq.modules.quant_noise import quant_noise as apply_quant_noise_ +from torch import Tensor + + +class CrossChannelTransformerDecoder(FairseqIncrementalDecoder): + """ + Cross-channel Transformer Decoder Block for parallel spoken dialogue units + as described in the paper: https://arxiv.org/pdf/2203.16502.pdf; + consisting of *args.decoder_layers* layers. Each layer is a + :class:`StandardTransformerDecoderLayer` or + :class:`CrossChannelTransformerDecoderLayer`. + + Args: + args (argparse.Namespace): parsed command-line arguments + dictionary (~fairseq.data.Dictionary): decoding dictionary + embed_tokens (torch.nn.Embedding): output embedding + channels (list): list of channel names (string) + no_encoder_attn (bool, optional): whether to attend to encoder outputs + (default: False). + """ + + def __init__(self, args, dictionary, embed_tokens, channels, no_encoder_attn=False): + self.args = args + super().__init__(dictionary) + self.register_buffer("version", torch.Tensor([3])) + self._future_mask = torch.empty(0) + + self.dropout_module = FairseqDropout( + args.dropout, module_name=self.__class__.__name__ + ) + self.decoder_layerdrop = args.decoder_layerdrop + self.share_input_output_embed = args.share_decoder_input_output_embed + self.channels = channels + + input_embed_dim = embed_tokens.embedding_dim + embed_dim = args.decoder_embed_dim + self.embed_dim = embed_dim + self.output_embed_dim = args.decoder_output_dim + + self.padding_idx = embed_tokens.padding_idx + self.max_target_positions = args.max_target_positions + + self.embed_tokens = embed_tokens + + self.embed_scale = 1.0 if args.no_scale_embedding else math.sqrt(embed_dim) + + if args.quant_noise_pq > 0: + self.quant_noise = apply_quant_noise_( + nn.Linear(embed_dim, embed_dim, bias=False), + args.quant_noise_pq, + args.quant_noise_pq_block_size, + ) + else: + self.quant_noise = None + + self.project_in_dim = ( + nn.Linear(input_embed_dim, embed_dim, bias=False) + if embed_dim != input_embed_dim + else None + ) + self.embed_positions = ( + PositionalEmbedding( + self.max_target_positions, + embed_dim, + self.padding_idx, + learned=args.decoder_learned_pos, + ) + if not args.no_token_positional_embeddings + else None + ) + + if getattr(args, "layernorm_embedding", False): + self.layernorm_embedding = LayerNorm(embed_dim) + else: + self.layernorm_embedding = None + + self.cross_self_attention = getattr(args, "cross_self_attention", False) + + assert 0 <= args.decoder_cross_layers <= args.decoder_layers, ( + "The number of cross-channel attention decoder layers must be non-negative" + f"and not exceeds the number of decoder layers (found {args.decoder_cross_layers})" + ) + + if self.decoder_layerdrop > 0.0: + self.layers = LayerDropModuleList(p=self.decoder_layerdrop) + else: + self.layers = nn.ModuleList([]) + self.layers.extend( + [ + self.build_decoder_layer(args, no_encoder_attn) + if i < args.decoder_layers - args.decoder_cross_layers + else self.build_cross_decoder_layer(args, no_encoder_attn) + for i in range(args.decoder_layers) + ] + ) + self.num_layers = len(self.layers) + self.non_cross_layers = args.decoder_layers - args.decoder_cross_layers + + if args.decoder_normalize_before and not getattr( + args, "no_decoder_final_norm", False + ): + self.layer_norm = LayerNorm(embed_dim) + else: + self.layer_norm = None + + self.project_out_dim = ( + nn.Linear(embed_dim, self.output_embed_dim, bias=False) + if embed_dim != self.output_embed_dim + else None + ) + + self.output_projection = None + self.is_cross_prediction = bool( + float(args.main_and_cross_weights.split(",")[1]) != 0 + ) + self.n_output_projections = ( + 1 if not self.is_cross_prediction else len(self.channels) + ) + + if self.share_input_output_embed: + # Output projection is a list of projections + # where the first proj is for the main-channel, + # then roll in a cicular way. + # For example: if the main channel has index i + # the second proj is for channel i+1 (mod N_channels), etc. + self.output_projection = nn.ModuleList( + [ + nn.Linear( + embed_tokens.weight.shape[1], # embed_dim + embed_tokens.weight.shape[0], # n_dictionaries + bias=False, + ) + for _ in range(self.n_output_projections) + ] + ) + # Only share the main-channel projection + self.output_projection[0].weight = embed_tokens.weight + for i in range(1, self.n_output_projections): + nn.init.normal_( + self.output_projection[i].weight, + mean=0, + std=embed_tokens.weight.shape[1] ** -0.5, + ) + else: + self.output_projection = nn.ModuleList( + [ + nn.Linear(self.output_embed_dim, len(dictionary), bias=False) + for _ in range(self.n_output_projections) + ] + ) + for i in range(self.n_output_projections): + nn.init.normal_( + self.output_projection[i].weight, + mean=0, + std=self.output_embed_dim**-0.5, + ) + self.output_duration_prediction = ( + None + if str(args.duration_prediction).lower() == "false" + else nn.ModuleList( + [ + nn.Linear(self.output_embed_dim, 1) + for _ in range(self.n_output_projections) + ] + ) + ) + + def build_decoder_layer(self, args, no_encoder_attn=False): + layer = StandardTransformerDecoderLayer(args, no_encoder_attn) + if getattr(args, "checkpoint_activations", False): + offload_to_cpu = getattr(args, "offload_activations", False) + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + return layer + + def build_cross_decoder_layer(self, args, no_encoder_attn=False): + layer = CrossChannelTransformerDecoderLayer(args, no_encoder_attn) + if getattr(args, "checkpoint_activations", False): + offload_to_cpu = getattr(args, "offload_activations", False) + layer = checkpoint_wrapper(layer, offload_to_cpu=offload_to_cpu) + return layer + + def forward( + self, + prev_output_tokens: Dict[str, Tensor], + encoder_out: Optional[Dict[str, List[Tensor]]] = None, + incremental_state: Optional[ + List[Dict[str, Dict[str, Optional[Tensor]]]] + ] = None, + features_only: bool = False, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + src_lengths: Optional[Any] = None, + # return_all_hiddens: bool = False, + ): + """ + Args: + prev_output_tokens (dict[str, LongTensor]): previous decoder outputs, + dictionary over all channels with the values being the tensors + of shape `(batch, tgt_len)`, for teacher forcing + encoder_out (optional): output from the encoder, used for + encoder-side attention + incremental_state (dict): list of dictionaries used for storing state + during :ref:`Incremental decoding` + features_only (bool, optional): only return features without + applying output layer (default: False). + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + + Returns: + tuple: + - the decoder's output, dict over channels of tensors + of shape `(batch, tgt_len, vocab)` + - a dictionary with any model-specific outputs + """ + x, extra = self.extract_features( + prev_output_tokens, + encoder_out=encoder_out, + incremental_state=incremental_state, + full_context_alignment=full_context_alignment, + alignment_layer=alignment_layer, + alignment_heads=alignment_heads, + ) + if not features_only: + x = self.output_layer(x) + return x, extra + + def extract_features( + self, + prev_output_tokens: Dict[str, Tensor], + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[ + List[Dict[str, Dict[str, Optional[Tensor]]]] + ] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + return self.extract_features_scriptable( + prev_output_tokens, + encoder_out, + incremental_state, + full_context_alignment, + alignment_layer, + alignment_heads, + ) + + """ + A scriptable subclass of this class has an extract_features method and calls + super().extract_features, but super() is not supported in torchscript. A copy of + this function is made to be used in the subclass instead. + """ + + def extract_features_scriptable( + self, + prev_output_tokens: Dict[str, Tensor], + encoder_out: Optional[Dict[str, List[Tensor]]], + incremental_state: Optional[ + List[Dict[str, Dict[str, Optional[Tensor]]]] + ] = None, + full_context_alignment: bool = False, + alignment_layer: Optional[int] = None, + alignment_heads: Optional[int] = None, + ): + """ + The core function of *forward* but only return features. + + The input (prev_output_tokens) is a dictionary over all channels, + expected to have the following form: + { + 'channel1' : Tensor((batch x tgt_len)), + 'channel2' : Tensor((batch x tgt_len)), + } + + Args: + full_context_alignment (bool, optional): don't apply + auto-regressive mask to self-attention (default: False). + alignment_layer (int, optional): return mean alignment over + heads at this layer (default: last layer). + alignment_heads (int, optional): only average alignment over + this many heads (default: all heads). + + Returns: + tuple: + - the decoder's features, dict over channels of tensors + of shape `(batch, tgt_len, embed_dim)` + - a dictionary with any model-specific outputs + """ + if alignment_layer is None: + alignment_layer = self.num_layers - 1 + + x_list = [] + for i, channel in enumerate(self.channels): + # embed positions + positions = None + if self.embed_positions is not None: + positions = self.embed_positions( + prev_output_tokens[channel], + incremental_state=incremental_state[i] + if incremental_state is not None + else None, + ) + + if incremental_state is not None: + prev_output_tokens[channel] = prev_output_tokens[channel][:, -1:] + if positions is not None: + positions = positions[:, -1:] + + # embed tokens and positions + x = self.embed_tokens(prev_output_tokens[channel]) + + if self.project_in_dim is not None: + x = self.project_in_dim(x) + + x = self.embed_scale * x + + if self.quant_noise is not None: + x = self.quant_noise(x) + + if positions is not None: + x += positions + + if self.layernorm_embedding is not None: + x = self.layernorm_embedding(x) + + x = self.dropout_module(x) + + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + x_list.append(x) + + self_attn_padding_mask: Optional[Tensor] = None + if ( + self.cross_self_attention + or prev_output_tokens[self.channels[0]].eq(self.padding_idx).any() + ): + self_attn_padding_mask = prev_output_tokens[self.channels[0]].eq( + self.padding_idx + ) + + # decoder layers + attn: Optional[Dict[Tensor]] = None + inner_states: List[Optional[Dict[str, Tensor]]] = [ + {channel: x_list[i] for i, channel in enumerate(self.channels)} + ] + for idx, layer in enumerate(self.layers): + if incremental_state is None and not full_context_alignment: + self_attn_mask = self.buffered_future_mask(x_list[0]) + else: + self_attn_mask = None + + # need to change to tensor for the checkpoint activation to work + if isinstance(x_list, list): + x_list = torch.stack(x_list) + x_list, layer_attn_list, _ = layer( + x_list, + encoder_out["encoder_out"][0] + if (encoder_out is not None and len(encoder_out["encoder_out"]) > 0) + else None, + encoder_out["encoder_padding_mask"][0] + if ( + encoder_out is not None + and len(encoder_out["encoder_padding_mask"]) > 0 + ) + else None, + incremental_state, + self_attn_mask=self_attn_mask, + self_attn_padding_mask=self_attn_padding_mask, + need_attn=bool((idx == alignment_layer)), + need_head_weights=bool((idx == alignment_layer)), + ) + + inner_states.append( + {channel: x_list[i] for i, channel in enumerate(self.channels)} + ) + if idx == alignment_layer and all( + layer_attn is not None for layer_attn in layer_attn_list + ): + attn = { + channel: layer_attn_list[i].float().to(x_list[0]) + for i, channel in enumerate(self.channels) + } + # change back from tensor to list + if not isinstance(x_list, list): + x_list = list(torch.unbind(x_list)) + + if attn is not None: + for channel in attn: + if alignment_heads is not None: + attn[channel] = attn[channel][:alignment_heads] + + # average probabilities over heads + attn[channel] = attn[channel].mean(dim=0) + + for i, x in enumerate(x_list): + if self.layer_norm is not None: + x = self.layer_norm(x) + + # T x B x C -> B x T x C + x = x.transpose(0, 1) + + if self.project_out_dim is not None: + x = self.project_out_dim(x) + + x_list[i] = x + + x = {channel: x_list[i] for i, channel in enumerate(self.channels)} + + return x, {"attn": [attn], "inner_states": inner_states} + + def output_layer(self, features): + """Project features to the vocabulary size. + Return a dictionary of the form: + { + 'input-channel': { + 'predicted-channel': token prediction tensor of shape `(batch, tgt_len, vocab)`, + } + } + + if duration_prediction is enabled + { + 'input-channel': { + 'predicted-channel': { + 'pred_token': token prediction tensor of shape `(batch, tgt_len, vocab)`, + 'pred_duration': duration prediction tensor + } + } + } + """ + # project back to size of vocabulary + if self.output_duration_prediction is None: + if self.is_cross_prediction: + return { + channel: { + pred_channel: self.output_projection[j - i](features[channel]) + for j, pred_channel in enumerate(self.channels) + } + for i, channel in enumerate(self.channels) + } + else: + return { + channel: {channel: self.output_projection[0](features[channel])} + for i, channel in enumerate(self.channels) + } + else: + if self.is_cross_prediction: + return { + channel: { + pred_channel: { + "pred_token": self.output_projection[j - i]( + features[channel] + ), + "pred_duration": self.output_duration_prediction[j - i]( + features[channel] + ), + } + for j, pred_channel in enumerate(self.channels) + } + for i, channel in enumerate(self.channels) + } + else: + return { + channel: { + channel: { + "pred_token": self.output_projection[0](features[channel]), + "pred_duration": self.output_duration_prediction[0]( + features[channel] + ), + } + } + for i, channel in enumerate(self.channels) + } + + def max_positions(self): + """Maximum output length supported by the decoder.""" + if self.embed_positions is None: + return self.max_target_positions + return min(self.max_target_positions, self.embed_positions.max_positions) + + def buffered_future_mask(self, tensor): + dim = tensor.size(0) + # self._future_mask.device != tensor.device is not working in TorchScript. This is a workaround. + if ( + self._future_mask.size(0) == 0 + or (not self._future_mask.device == tensor.device) + or self._future_mask.size(0) < dim + ): + self._future_mask = torch.triu( + utils.fill_with_neg_inf(torch.zeros([dim, dim])), 1 + ) + self._future_mask = self._future_mask.to(tensor) + return self._future_mask[:dim, :dim] + + def get_normalized_probs_scriptable( + self, + net_output: Tuple[Tensor, Optional[Dict[str, List[Optional[Tensor]]]]], + log_probs: bool, + sample: Optional[Dict[str, Tensor]] = None, + ): + """Get normalized probabilities (or log probs) from a net's output.""" + + logits_dict = net_output[0] + out_dict = {} + for channel in logits_dict: + out_dict[channel] = {} + for pred_channel in logits_dict[channel]: + if isinstance(logits_dict[channel][pred_channel], dict): + pred_token_logits = logits_dict[channel][pred_channel]["pred_token"] + else: + pred_token_logits = logits_dict[channel][pred_channel] + if log_probs: + out = utils.log_softmax( + pred_token_logits, dim=-1, onnx_trace=self.onnx_trace + ) + else: + out = utils.softmax( + pred_token_logits, dim=-1, onnx_trace=self.onnx_trace + ) + if isinstance(logits_dict[channel][pred_channel], dict): + out_dict[channel][pred_channel] = { + "pred_token": out, + "pred_duration": logits_dict[channel][pred_channel][ + "pred_duration" + ].float(), + } # move to float32 to avoid inf loss + else: + out_dict[channel][pred_channel] = out + return out_dict + + def reorder_incremental_state_scripting( + self, + incremental_state: List[Dict[str, Dict[str, Optional[Tensor]]]], + new_order: Tensor, + ): + """Main entry point for reordering the incremental state. + + Due to limitations in TorchScript, we call this function in + :class:`fairseq.sequence_generator.SequenceGenerator` instead of + calling :func:`reorder_incremental_state` directly. + """ + for module in self.modules(): + if hasattr(module, "reorder_incremental_state"): + for i, incremental_state_channel in enumerate(incremental_state): + result = module.reorder_incremental_state( + incremental_state_channel, new_order + ) + if result is not None: + incremental_state[i] = result diff --git a/fairseq/models/speech_dlm/modules/speech_dlm_decoder_layer.py b/fairseq/models/speech_dlm/modules/speech_dlm_decoder_layer.py new file mode 100644 index 0000000000..fb65fdf810 --- /dev/null +++ b/fairseq/models/speech_dlm/modules/speech_dlm_decoder_layer.py @@ -0,0 +1,717 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, List, Tuple, Optional + +import torch +import torch.nn as nn +from fairseq import utils +from fairseq.modules import LayerNorm, MultiheadAttention +from fairseq.modules.fairseq_dropout import FairseqDropout +from fairseq.modules.quant_noise import quant_noise +from torch import Tensor + + +class CrossChannelTransformerDecoderLayer(nn.Module): + """Cross-Attention Transformer Decoder Layer block as described + in the paper: https://arxiv.org/pdf/2203.16502.pdf + + Composed of a Multi-head Self Attention block followed by a + Multi-head Cross-Attention block which attends to the self-attention + outputs of the other channels. The weights of the attention blocks + in all channels are shared. + + Args: + args (argparse.Namespace): parsed command-line arguments + no_encoder_attn (bool, optional): whether to attend to encoder outputs + (default: False). + """ + + def __init__( + self, args, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False + ): + super().__init__() + self.embed_dim = args.decoder_embed_dim + self.dropout_module = FairseqDropout( + args.dropout, module_name=self.__class__.__name__ + ) + self.quant_noise = getattr(args, "quant_noise_pq", 0) + self.quant_noise_block_size = getattr(args, "quant_noise_pq_block_size", 8) + + # This cross_self_attention is used for encoder-decoder systems, + # It's not the cross-channel attention (defined below as cross_channel_attn) + self.cross_self_attention = getattr(args, "cross_self_attention", False) + + self.self_attn = self.build_self_attention( + self.embed_dim, + args, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + self.cross_channel_attn = self.build_cross_channel_attention( + self.embed_dim, + args, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + + self.activation_fn = utils.get_activation_fn( + activation=str(args.activation_fn) + if getattr(args, "activation_fn", None) is not None + else "relu" + ) + activation_dropout_p = getattr(args, "activation_dropout", 0) or 0 + if activation_dropout_p == 0: + # for backwards compatibility with models that use args.relu_dropout + activation_dropout_p = getattr(args, "relu_dropout", 0) or 0 + self.activation_dropout_module = FairseqDropout( + float(activation_dropout_p), module_name=self.__class__.__name__ + ) + self.normalize_before = args.decoder_normalize_before + + # use layerNorm rather than FusedLayerNorm for exporting. + # char_inputs can be used to determint this. + # TODO remove this once we update apex with the fix + export = getattr(args, "char_inputs", False) + self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + self.cross_channel_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + + if no_encoder_attn: + self.encoder_attn = None + self.encoder_attn_layer_norm = None + else: + self.encoder_attn = self.build_encoder_attention(self.embed_dim, args) + self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + + self.fc1 = self.build_fc1( + self.embed_dim, + args.decoder_ffn_embed_dim, + self.quant_noise, + self.quant_noise_block_size, + ) + self.fc2 = self.build_fc2( + args.decoder_ffn_embed_dim, + self.embed_dim, + self.quant_noise, + self.quant_noise_block_size, + ) + + self.final_layer_norm = LayerNorm(self.embed_dim, export=export) + self.need_attn = True + + self.onnx_trace = False + + def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): + return quant_noise(nn.Linear(input_dim, output_dim), q_noise, qn_block_size) + + def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size): + return quant_noise(nn.Linear(input_dim, output_dim), q_noise, qn_block_size) + + def build_self_attention( + self, embed_dim, args, add_bias_kv=False, add_zero_attn=False + ): + return MultiheadAttention( + embed_dim, + args.decoder_attention_heads, + dropout=args.attention_dropout, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + self_attention=not getattr(args, "cross_self_attention", False), + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + ) + + def build_cross_channel_attention( + self, embed_dim, args, add_bias_kv=False, add_zero_attn=False + ): + return MultiheadAttention( + embed_dim, + args.decoder_attention_heads, + dropout=args.attention_dropout, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + self_attention=False, + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + ) + + def build_encoder_attention(self, embed_dim, args): + return MultiheadAttention( + embed_dim, + args.decoder_attention_heads, + kdim=getattr(args, "encoder_embed_dim", None), + vdim=getattr(args, "encoder_embed_dim", None), + dropout=args.attention_dropout, + encoder_decoder_attention=True, + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + ) + + def prepare_for_onnx_export_(self): + self.onnx_trace = True + + def residual_connection(self, x, residual): + return residual + x + + def forward( + self, + x_list_tensor: List[torch.Tensor], + encoder_out: Optional[torch.Tensor] = None, + encoder_padding_mask: Optional[torch.Tensor] = None, + incremental_state: Optional[ + List[Dict[str, Dict[str, Optional[Tensor]]]] + ] = None, + prev_self_attn_state: Optional[List[Tuple[torch.Tensor, torch.Tensor]]] = None, + prev_attn_state: Optional[List[torch.Tensor]] = None, + self_attn_mask: Optional[torch.Tensor] = None, + self_attn_padding_mask: Optional[torch.Tensor] = None, + need_attn: bool = False, + need_head_weights: bool = False, + ): + """ + Args: + x_list_tensor (List[Tensor]): list of input tensors in different channels, + each tensor is of shape `(seq_len, batch, embed_dim)` + encoder_padding_mask (ByteTensor, optional): binary + ByteTensor of shape `(batch, src_len)` where padding + elements are indicated by ``1``. + incremental_state (optional): list of incremental_state dictionaries over + different channels (sequence generation mode) + prev_self_attn_state (List[Tuple[Tensor, Tensor]], optional): list of tuples + (self_attn_state, cross_channel_attn_state) over different channels + need_attn (bool, optional): return attention weights + need_head_weights (bool, optional): return attention weights + for each head (default: return average over heads). + + Returns: + list of encoded output of shape `(seq_len, batch, embed_dim)` + """ + n_channels = len(x_list_tensor) + if need_head_weights: + need_attn = True + + # incremental_state is a list of dictionaries over different channels + if incremental_state is not None: + assert isinstance(incremental_state, list) + assert len(incremental_state) == n_channels + + # prev_self_attn_state is a list of tuples (self_attn_state, cross_channel_attn_state) over different channels + if prev_self_attn_state is not None: + assert isinstance(prev_self_attn_state, list) + assert len(prev_self_attn_state) == n_channels + for prev_self_attn_state_channel in prev_self_attn_state: + assert isinstance(prev_self_attn_state_channel, tuple) + assert len(prev_self_attn_state_channel) == 2 + + # Backup for other channels & cross channel attention + self_attn_mask_orin = self_attn_mask + self_attn_padding_mask_orin = self_attn_padding_mask + + x_list = [] + attn_list = [] + for i, x in enumerate(x_list_tensor): + residual = x + + if self.normalize_before: + x = self.self_attn_layer_norm(x) + + if prev_self_attn_state is not None: + prev_key, prev_value = prev_self_attn_state[i][0][:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_self_attn_state[i][0]) >= 3: + saved_state["prev_key_padding_mask"] = prev_self_attn_state[i][0][2] + assert incremental_state is not None + self.self_attn._set_input_buffer(incremental_state[i], saved_state) + _self_attn_input_buffer = self.self_attn._get_input_buffer( + incremental_state[i] if incremental_state is not None else None + ) + if self.cross_self_attention and not ( + incremental_state is not None + and _self_attn_input_buffer is not None + and "prev_key" in _self_attn_input_buffer + ): + if self_attn_mask_orin is not None: + assert encoder_out is not None + self_attn_mask = torch.cat( + ( + x.new_zeros(x.size(0), encoder_out.size(0)), + self_attn_mask_orin, + ), + dim=1, + ) + if self_attn_padding_mask_orin is not None: + if encoder_padding_mask is None: + assert encoder_out is not None + encoder_padding_mask = self_attn_padding_mask_orin.new_zeros( + encoder_out.size(1), encoder_out.size(0) + ) + self_attn_padding_mask = torch.cat( + (encoder_padding_mask, self_attn_padding_mask_orin), dim=1 + ) + assert encoder_out is not None + y = torch.cat((encoder_out, x), dim=0) + else: + y = x + + x, attn = self.self_attn( + query=x, + key=y, + value=y, + key_padding_mask=self_attn_padding_mask, + incremental_state=incremental_state[i] + if incremental_state is not None + else None, + need_weights=False, + attn_mask=self_attn_mask, + ) + + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) + + if self.encoder_attn is not None and encoder_out is not None: + residual = x + if self.normalize_before: + x = self.encoder_attn_layer_norm(x) + if prev_attn_state is not None: + prev_key, prev_value = prev_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_attn_state[2] + assert incremental_state is not None + self.encoder_attn._set_input_buffer( + incremental_state[i], saved_state + ) + + x, attn = self.encoder_attn( + query=x, + key=encoder_out, + value=encoder_out, + key_padding_mask=encoder_padding_mask, + incremental_state=incremental_state[i] + if incremental_state is not None + else None, + static_kv=True, + need_weights=need_attn or (not self.training and self.need_attn), + need_head_weights=need_head_weights, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.encoder_attn_layer_norm(x) + + x_list.append(x) + attn_list.append(attn) + + # Store attentions & new x(s) (bc the old x(s) are used in other channels) + x_list_new = [] + # Here comes the cross channel attention + for i, x in enumerate(x_list): + residual = x + if self.normalize_before: + x = self.cross_channel_attn_layer_norm(x) + + if prev_self_attn_state is not None: + prev_key, prev_value = prev_self_attn_state[i][1][:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_self_attn_state[i][1]) >= 3: + saved_state["prev_key_padding_mask"] = prev_self_attn_state[i][1][2] + assert incremental_state is not None + self.cross_channel_attn._set_input_buffer( + incremental_state[i], saved_state + ) + + # The cross attention is computed with the concatenation of attentions from other channels + if len(x_list) > 1: + x_other = torch.cat( + [x_list[(i + j) % len(x_list)] for j in range(1, len(x_list))], + dim=0, + ) + else: + # Self-attention when having only one channel + x_other = x_list[i] + + x, attn = self.cross_channel_attn( + query=x, + key=x_other, + value=x_other, + key_padding_mask=self_attn_padding_mask_orin, + incremental_state=incremental_state[i] + if incremental_state is not None + else None, + need_weights=False, + attn_mask=self_attn_mask_orin, + ) + + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.cross_channel_attn_layer_norm(x) + + x_list_new.append(x) + x_list = x_list_new + + for i, x in enumerate(x_list): + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) + + x_list[i] = x + # Trick for the checkpoint activation + x_list_tensor = torch.stack(x_list) + if self.onnx_trace and incremental_state is not None: + self_and_cross_attn_state_list = [] + for i in range(n_channels): + self_and_cross_attn_state = [] + for self_attn_module in [self.self_attn, self.cross_channel_attn]: + saved_state = self_attn_module._get_input_buffer( + incremental_state[i] + ) + assert saved_state is not None + if self_attn_padding_mask is not None: + self_attn_module_state = [ + saved_state["prev_key"], + saved_state["prev_value"], + saved_state["prev_key_padding_mask"], + ] + else: + self_attn_module_state = [ + saved_state["prev_key"], + saved_state["prev_value"], + ] + self_and_cross_attn_state.append(self_attn_module_state) + self_and_cross_attn_state_list.append(tuple(self_and_cross_attn_state)) + return x_list_tensor, attn_list, self_and_cross_attn_state_list + return x_list_tensor, attn_list, None + + def make_generation_fast_(self, need_attn: bool = False, **kwargs): + self.need_attn = need_attn + + +# Rewrite fairseq.modules.TransformerDecoderLayer +# to be compatible with checkpoint_activations +# (avoid forwarding model multiple times) +class StandardTransformerDecoderLayer(nn.Module): + """Rewrite fairseq.modules.TransformerDecoderLayer to avoid forwarding + model multiple times and be compatible with checkpoint_activations. + + The input is expected to be a list of tensors from different channels, + each is forwarded to the same model (shared attention weights). + + In the original paper each operation (multi-head attention, encoder + attention or FFN) is postprocessed with: `dropout -> add residual -> + layernorm`. In the tensor2tensor code they suggest that learning is more + robust when preprocessing each layer with layernorm and postprocessing with: + `dropout -> add residual`. We default to the approach in the paper, but the + tensor2tensor approach can be enabled by setting + *args.decoder_normalize_before* to ``True``. + + Args: + args (argparse.Namespace): parsed command-line arguments + no_encoder_attn (bool, optional): whether to attend to encoder outputs + (default: False). + """ + + def __init__( + self, args, no_encoder_attn=False, add_bias_kv=False, add_zero_attn=False + ): + super().__init__() + self.embed_dim = args.decoder_embed_dim + self.dropout_module = FairseqDropout( + args.dropout, module_name=self.__class__.__name__ + ) + self.quant_noise = getattr(args, "quant_noise_pq", 0) + self.quant_noise_block_size = getattr(args, "quant_noise_pq_block_size", 8) + + self.cross_self_attention = getattr(args, "cross_self_attention", False) + + self.self_attn = self.build_self_attention( + self.embed_dim, + args, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + ) + + self.activation_fn = utils.get_activation_fn( + activation=str(args.activation_fn) + if getattr(args, "activation_fn", None) is not None + else "relu" + ) + activation_dropout_p = getattr(args, "activation_dropout", 0) or 0 + if activation_dropout_p == 0: + # for backwards compatibility with models that use args.relu_dropout + activation_dropout_p = getattr(args, "relu_dropout", 0) or 0 + self.activation_dropout_module = FairseqDropout( + float(activation_dropout_p), module_name=self.__class__.__name__ + ) + self.normalize_before = args.decoder_normalize_before + + # use layerNorm rather than FusedLayerNorm for exporting. + # char_inputs can be used to determint this. + # TODO remove this once we update apex with the fix + export = getattr(args, "char_inputs", False) + self.self_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + + if no_encoder_attn: + self.encoder_attn = None + self.encoder_attn_layer_norm = None + else: + self.encoder_attn = self.build_encoder_attention(self.embed_dim, args) + self.encoder_attn_layer_norm = LayerNorm(self.embed_dim, export=export) + + self.fc1 = self.build_fc1( + self.embed_dim, + args.decoder_ffn_embed_dim, + self.quant_noise, + self.quant_noise_block_size, + ) + self.fc2 = self.build_fc2( + args.decoder_ffn_embed_dim, + self.embed_dim, + self.quant_noise, + self.quant_noise_block_size, + ) + + self.final_layer_norm = LayerNorm(self.embed_dim, export=export) + self.need_attn = True + + self.onnx_trace = False + + def build_fc1(self, input_dim, output_dim, q_noise, qn_block_size): + return quant_noise(nn.Linear(input_dim, output_dim), q_noise, qn_block_size) + + def build_fc2(self, input_dim, output_dim, q_noise, qn_block_size): + return quant_noise(nn.Linear(input_dim, output_dim), q_noise, qn_block_size) + + def build_self_attention( + self, embed_dim, args, add_bias_kv=False, add_zero_attn=False + ): + return MultiheadAttention( + embed_dim, + args.decoder_attention_heads, + dropout=args.attention_dropout, + add_bias_kv=add_bias_kv, + add_zero_attn=add_zero_attn, + self_attention=not getattr(args, "cross_self_attention", False), + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + ) + + def build_encoder_attention(self, embed_dim, args): + return MultiheadAttention( + embed_dim, + args.decoder_attention_heads, + kdim=getattr(args, "encoder_embed_dim", None), + vdim=getattr(args, "encoder_embed_dim", None), + dropout=args.attention_dropout, + encoder_decoder_attention=True, + q_noise=self.quant_noise, + qn_block_size=self.quant_noise_block_size, + ) + + def prepare_for_onnx_export_(self): + self.onnx_trace = True + + def residual_connection(self, x, residual): + return residual + x + + def forward( + self, + x_list_tensor: List[torch.Tensor], + encoder_out: Optional[torch.Tensor] = None, + encoder_padding_mask: Optional[torch.Tensor] = None, + incremental_state: Optional[ + List[Dict[str, Dict[str, Optional[Tensor]]]] + ] = None, + prev_self_attn_state: Optional[List[Tuple[torch.Tensor, torch.Tensor]]] = None, + prev_attn_state: Optional[List[torch.Tensor]] = None, + self_attn_mask: Optional[torch.Tensor] = None, + self_attn_padding_mask: Optional[torch.Tensor] = None, + need_attn: bool = False, + need_head_weights: bool = False, + ): + """ + Args: + x_list_tensor (List[Tensor]): list of input tensors in different channels, + each tensor is of shape `(seq_len, batch, embed_dim)` + encoder_padding_mask (ByteTensor, optional): binary + ByteTensor of shape `(batch, src_len)` where padding + elements are indicated by ``1``. + incremental_state (optional): list of incremental_state dictionaries over + different channels (sequence generation mode) + prev_self_attn_state (List[Tuple[Tensor, Tensor]], optional): list of tuples + (self_attn_state, cross_channel_attn_state) over different channels + need_attn (bool, optional): return attention weights + need_head_weights (bool, optional): return attention weights + for each head (default: return average over heads). + + Returns: + list of encoded output of shape `(seq_len, batch, embed_dim)` + """ + n_channels = len(x_list_tensor) + if need_head_weights: + need_attn = True + + # incremental_state is a list of dictionaries over different channels + if incremental_state is not None: + assert isinstance(incremental_state, list) + assert len(incremental_state) == n_channels + + # prev_self_attn_state is a list of self_attn_state over different channels + if prev_self_attn_state is not None: + assert isinstance(prev_self_attn_state, list) + assert len(prev_self_attn_state) == n_channels + + x_list = [] + attn_list = [] + for i, x in enumerate(x_list_tensor): + residual = x + + if self.normalize_before: + x = self.self_attn_layer_norm(x) + + if prev_self_attn_state is not None: + prev_key, prev_value = prev_self_attn_state[i][:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_self_attn_state[i]) >= 3: + saved_state["prev_key_padding_mask"] = prev_self_attn_state[2] + assert incremental_state is not None + self.self_attn._set_input_buffer(incremental_state[i], saved_state) + _self_attn_input_buffer = self.self_attn._get_input_buffer( + incremental_state + ) + if self.cross_self_attention and not ( + incremental_state is not None + and _self_attn_input_buffer is not None + and "prev_key" in _self_attn_input_buffer + ): + if self_attn_mask is not None: + assert encoder_out is not None + self_attn_mask = torch.cat( + (x.new_zeros(x.size(0), encoder_out.size(0)), self_attn_mask), + dim=1, + ) + if self_attn_padding_mask is not None: + if encoder_padding_mask is None: + assert encoder_out is not None + encoder_padding_mask = self_attn_padding_mask.new_zeros( + encoder_out.size(1), encoder_out.size(0) + ) + self_attn_padding_mask = torch.cat( + (encoder_padding_mask, self_attn_padding_mask), dim=1 + ) + assert encoder_out is not None + y = torch.cat((encoder_out, x), dim=0) + else: + y = x + + x, attn = self.self_attn( + query=x, + key=y, + value=y, + key_padding_mask=self_attn_padding_mask, + incremental_state=incremental_state[i] + if incremental_state is not None + else None, + need_weights=False, + attn_mask=self_attn_mask, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.self_attn_layer_norm(x) + + if self.encoder_attn is not None and encoder_out is not None: + residual = x + if self.normalize_before: + x = self.encoder_attn_layer_norm(x) + if prev_attn_state is not None: + prev_key, prev_value = prev_attn_state[:2] + saved_state: Dict[str, Optional[Tensor]] = { + "prev_key": prev_key, + "prev_value": prev_value, + } + if len(prev_attn_state) >= 3: + saved_state["prev_key_padding_mask"] = prev_attn_state[2] + assert incremental_state is not None + self.encoder_attn._set_input_buffer(incremental_state, saved_state) + + x, attn = self.encoder_attn( + query=x, + key=encoder_out, + value=encoder_out, + key_padding_mask=encoder_padding_mask, + incremental_state=incremental_state[i] + if incremental_state is not None + else None, + static_kv=True, + need_weights=need_attn or (not self.training and self.need_attn), + need_head_weights=need_head_weights, + ) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.encoder_attn_layer_norm(x) + + residual = x + if self.normalize_before: + x = self.final_layer_norm(x) + + x = self.activation_fn(self.fc1(x)) + x = self.activation_dropout_module(x) + x = self.fc2(x) + x = self.dropout_module(x) + x = self.residual_connection(x, residual) + if not self.normalize_before: + x = self.final_layer_norm(x) + + x_list.append(x) + attn_list.append(attn) + + # Trick for the checkpoint activation + x_list_tensor = torch.stack(x_list) + if self.onnx_trace and incremental_state is not None: + self_attn_state_list = [] + for i in range(n_channels): + saved_state = self.self_attn._get_input_buffer(incremental_state[i]) + assert saved_state is not None + if self_attn_padding_mask is not None: + self_attn_state = [ + saved_state["prev_key"], + saved_state["prev_value"], + saved_state["prev_key_padding_mask"], + ] + else: + self_attn_state = [ + saved_state["prev_key"], + saved_state["prev_value"], + ] + self_attn_state_list.append(self_attn_state) + return x_list_tensor, attn_list, self_attn_state_list + return x_list_tensor, attn_list, None + + def make_generation_fast_(self, need_attn: bool = False, **kwargs): + self.need_attn = need_attn diff --git a/fairseq/models/speech_dlm/sequence_generator/__init__.py b/fairseq/models/speech_dlm/sequence_generator/__init__.py new file mode 100644 index 0000000000..a88e144577 --- /dev/null +++ b/fairseq/models/speech_dlm/sequence_generator/__init__.py @@ -0,0 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from .multichannel_sequence_generator import * # noqa diff --git a/fairseq/models/speech_dlm/sequence_generator/multichannel_search.py b/fairseq/models/speech_dlm/sequence_generator/multichannel_search.py new file mode 100644 index 0000000000..db4b77f345 --- /dev/null +++ b/fairseq/models/speech_dlm/sequence_generator/multichannel_search.py @@ -0,0 +1,430 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from typing import Dict, Optional + +import torch +import torch.nn as nn +from torch import Tensor + + +class MultichannelSearch(nn.Module): + def __init__(self, tgt_dicts): + super().__init__() + tgt_dict = list(tgt_dicts.values())[0] + self.pad = tgt_dict.pad() + self.unk = tgt_dict.unk() + self.eos = tgt_dict.eos() + for tgt_dict in tgt_dicts.values(): + assert self.pad == tgt_dict.pad() + assert self.unk == tgt_dict.unk() + assert self.eos == tgt_dict.eos() + self.vocab_sizes = {channel: len(tgt_dicts[channel]) for channel in tgt_dicts} + self.src_lengths = torch.tensor(-1) + self.supports_constraints = False + self.stop_on_max_len = False + + def step( + self, step, lprobs, scores, prev_output_tokens=None, original_batch_idxs=None + ): + """Take a single search step. + + Args: + step: the current search step, starting at 0 + lprobs: dictionary of channels {channel : (bsz x input_beam_size x vocab_size_channel)} + the model's log-probabilities over the vocabulary at the current step + scores: {channel : (bsz x input_beam_size x step)} + the historical model scores of each hypothesis up to this point + prev_output_tokens: {channel : (bsz x step)} + the previously generated oputput tokens + original_batch_idxs: (bsz) + the tensor with the batch indices, in the range [0, bsz) + this is useful in case there has been applied a re-ordering + and we need to know the orignal indices + + Return: A tuple of (scores, indices, beams) where: + scores: {channel : (bsz x output_beam_size)} + the scores of the chosen elements; output_beam_size can be + larger than input_beam_size, e.g., we may return + 2*input_beam_size to account for EOS + indices: {channel : (bsz x output_beam_size)} + the indices of the chosen elements + beams: (bsz x output_beam_size) + the hypothesis ids of the chosen elements, in the range [0, input_beam_size) + """ + raise NotImplementedError + + @torch.jit.export + def set_src_lengths(self, src_lengths): + self.src_lengths = src_lengths + + @torch.jit.export + def init_constraints(self, batch_constraints: Optional[Tensor], beam_size: int): + """Initialize constraint states for constrained decoding (if supported). + + Args: + batch_constraints: (torch.Tensor, optional) + the list of constraints, in packed form + beam_size: (int) + the beam size + Returns: + *encoder_out* rearranged according to *new_order* + """ + pass + + def prune_sentences(self, batch_idxs: Tensor): + """ + Removes constraint states for completed sentences (if supported). + This is called from sequence_generator._generate() when sentences are + deleted from the batch. + + Args: + batch_idxs: Indices of *sentences* whose constraint state should be *kept*. + """ + pass + + def update_constraints(self, active_hypos: Tensor): + """ + Updates the constraint states by selecting the beam items that are retained. + This is called at each time step of sequence_generator._generate() when + the set of 2 * {beam_size} candidate hypotheses are reduced to the beam size. + + Args: + active_hypos: (batch size, beam size) + list of integers denoting, for each sentence, which beam candidate items + should be kept. + """ + pass + + +def unravel_index(index, shape): + out = [] + for dim in reversed(shape): + out.append(index % dim) + index = index // dim + return torch.stack(tuple(reversed(out)), dim=-1) + + +def topk_sum(lprobs_list, k): + """ + lprobs_list = [lprobs_1,...,lprobs_n], where: + lprobs_1 : (batch_size x beam_size x vocab_1) + ... + lprobs_n : (batch_size x beam_size x vocab_n) + + Return: + - topk_values : (batch_size x k) + values of the topk sum of the form : + lprobs_1[bsz, beam_idx, vocab_1_idx] + ... + lprobs_n[bsz, beam_idx, vocab_n_idx] + - topk_idxs : (batch_size x k x n+1) + each (n+1)-tensor being [beam_idx, vocab_1_idx, ..., vocab_n_idx] + """ + # Reduce all lprobs to k candidates first to reduce later complexity + # We may assume that k << vocab + lprobs_topk_list = [] + lprobs_topk_indices_list = [] + for lprobs in lprobs_list: + k_i = min(k, lprobs.size(-1)) + topk_values, topk_indices = torch.topk(lprobs, k=k_i) + # topk_values : (batch_size x beam_size x k_i) + # topk_indices : (batch_size x beam_size x k_i) + lprobs_topk_list.append(topk_values) + lprobs_topk_indices_list.append(topk_indices) + + # Compute all possible sums + sum_lprobs_topk = lprobs_topk_list[0] + for i in range(1, len(lprobs_topk_list)): + unsqueezed_lprobs = lprobs_topk_list[i] + for _ in range(i): + unsqueezed_lprobs = unsqueezed_lprobs.unsqueeze(-2) + sum_lprobs_topk = sum_lprobs_topk.unsqueeze(-1) + unsqueezed_lprobs + # sum_lprobs : (batch_size x beam_size x k_1 x ... x k_n) + + # Get the top k sums and the (transformed indices) + topk_sum_values, topk_sum_indices = torch.topk( + sum_lprobs_topk.view(sum_lprobs_topk.size(0), -1), k=k + ) + # topk_sum_values : (batch_size x k) + # topk_sum_indices : (batch_size x k) + topk_sum_indices = unravel_index(topk_sum_indices, tuple(sum_lprobs_topk.shape[1:])) + # topk_sum_indices : (batch_size x k x n+1) + + # Convert the transformed indices to the true indices + for i_batch in range(topk_sum_indices.size(0)): + for i_cand in range(topk_sum_indices.size(1)): + i_beam, *transformed_vocab_indices = topk_sum_indices[i_batch, i_cand] + true_vocab_indices = [i_beam] + for j, transformed_vocab_j_idx in enumerate(transformed_vocab_indices): + true_vocab_j_idx = lprobs_topk_indices_list[j][ + i_batch, i_beam, transformed_vocab_j_idx + ] + true_vocab_indices.append(true_vocab_j_idx) + topk_sum_indices[i_batch, i_cand] = torch.tensor(true_vocab_indices) + + topk_sum_beams = topk_sum_indices[:, :, 0] + topk_sum_indices = topk_sum_indices[:, :, 1:] + + return topk_sum_values, topk_sum_indices, topk_sum_beams + + +class MultichannelBeamSearch(MultichannelSearch): + def __init__(self, tgt_dicts): + super().__init__(tgt_dicts) + self.constraint_states = None + + @torch.jit.export + def step( + self, + step: int, + lprobs, + scores: Optional[Dict[str, Tensor]], + prev_output_tokens: Optional[Dict[str, Tensor]] = None, + original_batch_idxs: Optional[Tensor] = None, + ): + channels = list(lprobs.keys()) + bsz, beam_size, _ = lprobs[channels[0]].size() + + lprobs_list = [] + if step == 0: + # at the first step all hypotheses are equally likely, so use + # only the first beam + for channel in channels: + lprobs_list.append(lprobs[channel][:, ::beam_size, :].contiguous()) + else: + # make probs contain cumulative scores for each hypothesis + assert scores is not None + for channel in channels: + lprobs_list.append( + lprobs[channel] + scores[channel][:, :, step - 1].unsqueeze(-1) + ) + + topk_sum_values, topk_sum_indices, topk_sum_beams = topk_sum( + lprobs_list, k=beam_size * 2 + ) + + beams_buf = topk_sum_beams + scores_buf = {} + indices_buf = {} + for i, channel in enumerate(channels): + indices_buf[channel] = topk_sum_indices[:, :, i] + scores_buf[channel] = ( + torch.tensor( + [ + lprobs_list[i][i_batch, i_beam, i_index] + for i_batch in range(bsz) + for i_beam, i_index in zip( + beams_buf[i_batch], indices_buf[channel][i_batch] + ) + ] + ) + .view(bsz, -1) + .to(lprobs_list[i].device) + ) + + # At this point, beams_buf and indices_buf are single-dim and contain relative indices + return scores_buf, indices_buf, beams_buf + + +class ContiguousMultichannelBeamSearch(MultichannelSearch): + def __init__(self, tgt_dicts): + super().__init__(tgt_dicts) + self.constraint_states = None + + @torch.jit.export + def step( + self, + step: int, + lprobs, + scores: Optional[Tensor], + prev_output_tokens: Optional[Tensor] = None, + original_batch_idxs: Optional[Tensor] = None, + ): + n_channels = len(lprobs) + bsz, beam_size, _ = lprobs[0].size() + + lprobs_list = [] + if step == 0: + # at the first step all hypotheses are equally likely, so use + # only the first beam + for i in range(n_channels): + lprobs_list.append(lprobs[i][:, ::beam_size, :].contiguous()) + else: + # make probs contain cumulative scores for each hypothesis + assert scores is not None + for i in range(n_channels): + lprobs_list.append(lprobs[i] + scores[:, :, step - 1, i].unsqueeze(-1)) + + topk_sum_values, topk_sum_indices, topk_sum_beams = topk_sum( + lprobs_list, k=beam_size * 2 + ) + + beams_buf = topk_sum_beams + indices_buf = topk_sum_indices + scores_buf = ( + torch.tensor( + [ + lprobs_list[i][i_batch, i_beam, i_index] + for i in range(len(lprobs_list)) + for i_batch in range(bsz) + for i_beam, i_index in zip( + beams_buf[i_batch], indices_buf[i_batch, :, i] + ) + ] + ) + .view(len(lprobs_list), bsz, -1) + .permute(1, 2, 0) + .to(lprobs_list[0].device) + ) + + # At this point, beams_buf and indices_buf are single-dim and contain relative indices + return scores_buf, indices_buf, beams_buf + + +class ContiguousMultichannelSampling(MultichannelSearch): + sampling_topk: int + sampling_topp: float + + def __init__(self, tgt_dicts, sampling_topk=-1, sampling_topp=-1.0): + super().__init__(tgt_dicts) + self.sampling_topk = sampling_topk + self.sampling_topp = sampling_topp + + def _sample_topp(self, lprobs): + """Sample among the smallest set of elements whose cumulative probability mass exceeds p. + + See `"The Curious Case of Neural Text Degeneration" + (Holtzman et al., 2019) <https://arxiv.org/abs/1904.09751>`_. + + Args: + lprobs: (bsz x input_beam_size x vocab_size) + the model's log-probabilities over the vocabulary at the current step + + Return: A tuple of (trimed_probs, truncated_indices) where: + trimed_probs: (bsz x input_beam_size x ?) + the model's probabilities over the elements selected to sample from. The + width of the third dimension is determined by top-P. + truncated_indices: (bsz x input_beam_size x ?) + the indices of the chosen elements. + """ + probs = lprobs.exp_() + + # sort the last dimension (vocab dimension) in descending order + sorted_probs, sorted_indices = probs.sort(descending=True) + + # compute a mask to indicate the words to be included in the top-P set. + cumsum_probs = sorted_probs.cumsum(dim=2) + mask = cumsum_probs.lt(self.sampling_topp) + + # note that mask was computed by 'lt'. One more word needs to be included + # so that the cumulative probability mass can exceed p. + cumsum_mask = mask.cumsum(dim=2) + last_included = cumsum_mask[:, :, -1:] + last_included.clamp_(0, mask.size()[2] - 1) + mask = mask.scatter_(2, last_included, 1) + + # truncate unnecessary dims. + max_dim = last_included.max() + truncated_mask = mask[:, :, : max_dim + 1] + truncated_probs = sorted_probs[:, :, : max_dim + 1] + truncated_indices = sorted_indices[:, :, : max_dim + 1] + + # trim the words that are not in top-P by setting their probabilities + # to 0, so that they would not be sampled later. + trim_mask = ~truncated_mask + trimed_probs = truncated_probs.masked_fill_(trim_mask, 0) + return trimed_probs, truncated_indices + + @torch.jit.export + def step( + self, + step: int, + lprobs, + scores, + prev_output_tokens: Optional[Tensor] = None, + original_batch_idxs: Optional[Tensor] = None, + ): + n_channels = len(lprobs) + bsz, beam_size, vocab_size = lprobs[0].size() + + if step == 0: + # at the first step all hypotheses are equally likely, so use + # only the first beam + for i in range(n_channels): + lprobs[i] = lprobs[i][:, ::beam_size, :].contiguous() + + probs = [] + top_indices = [] + for i in range(n_channels): + if self.sampling_topp > 0: + # only sample from the smallest set of words whose cumulative probability mass exceeds p + probs_i, top_indices_i = self._sample_topp(lprobs[i]) + elif self.sampling_topk > 0: + # only sample from top-k candidates + lprobs[i], top_indices_i = lprobs[i].topk( + min(self.sampling_topk, lprobs[i].size(-1)) + ) + probs_i = lprobs[i].exp_() + else: + probs_i = lprobs[i].exp_() + + # dummy data to be consistent with true branch for type check + top_indices_i = torch.empty(0).to(probs_i) + probs.append(probs_i) + top_indices.append(top_indices_i) + # sample + indices_buf = [] + for i in range(n_channels): + if step == 0: + indices_buf.append( + torch.multinomial( + probs[i].view(bsz, -1), + beam_size, + replacement=True, + ).view(bsz, beam_size) + ) + else: + indices_buf.append( + torch.multinomial( + probs[i].view(bsz * beam_size, -1), + 1, + replacement=True, + ).view(bsz, beam_size) + ) + + if step == 0: + for i in range(n_channels): + # expand to beam size + probs[i] = probs[i].expand(bsz, beam_size, -1) + + # gather scores + scores_buf = [] + for i in range(n_channels): + scores_buf.append( + torch.gather(probs[i], dim=2, index=indices_buf[i].unsqueeze(-1)) + ) + scores_buf[i] = scores_buf[i].log_().view(bsz, -1) + + # remap indices if using top-k or top-P sampling + if self.sampling_topk > 0 or self.sampling_topp > 0: + for i in range(n_channels): + indices_buf[i] = torch.gather( + top_indices[i].expand(bsz, beam_size, -1), + dim=2, + index=indices_buf[i].unsqueeze(-1), + ).squeeze(2) + + if step == 0: + beams_buf = indices_buf[0].new_zeros(bsz, beam_size) + else: + beams_buf = torch.arange(0, beam_size).to(indices_buf[0]).repeat(bsz, 1) + # make scores cumulative + for i in range(n_channels): + scores_buf[i].add_( + torch.gather(scores[:, :, step - 1, i], dim=1, index=beams_buf) + ) + scores_buf = torch.stack(scores_buf, dim=-1) + indices_buf = torch.stack(indices_buf, dim=-1) + + return scores_buf, indices_buf, beams_buf diff --git a/fairseq/models/speech_dlm/sequence_generator/multichannel_sequence_generator.py b/fairseq/models/speech_dlm/sequence_generator/multichannel_sequence_generator.py new file mode 100644 index 0000000000..24807b866d --- /dev/null +++ b/fairseq/models/speech_dlm/sequence_generator/multichannel_sequence_generator.py @@ -0,0 +1,1110 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import math +from typing import Dict, List, Optional + +from omegaconf.listconfig import ListConfig +from omegaconf.dictconfig import DictConfig + +import torch +import torch.nn as nn +from fairseq.models import FairseqIncrementalDecoder +from torch import Tensor +from fairseq.ngram_repeat_block import NGramRepeatBlock +from .multichannel_search import ContiguousMultichannelBeamSearch +from fairseq.models.speech_dlm import SpeechDLM + + +class MultichannelSequenceGenerator(nn.Module): + def __init__( + self, + models, + tgt_dicts, + beam_size=1, + max_len_a=0, + max_len_b=200, + min_len=1, + normalize_scores=True, + len_penalty=1.0, + unk_penalty=0.0, + temperature=1.0, + match_source_len=False, + no_repeat_ngram_size=0, + search_strategy=None, + eos=None, + symbols_to_strip_from_output=None, + lm_model=None, + lm_weight=1.0, + duration_temperature=1.0, + ): + """Generate multi-channel parallel units with the SpeechDLM model + as described in the paper: https://arxiv.org/pdf/2203.16502.pdf; + + Args: + models (List[~fairseq.models.FairseqModel]): ensemble of models, + currently support fairseq.models.TransformerModel for scripting + beam_size (int, optional): beam width (default: 1) + max_len_a/b (int, optional): generate sequences of maximum length + ax + b, where x is the source length + min_len (int, optional): the minimum length of the generated output + (not including end-of-sentence) + normalize_scores (bool, optional): normalize scores by the length + of the output (default: True) + len_penalty (float, optional): length penalty, where <1.0 favors + shorter, >1.0 favors longer sentences (default: 1.0) + unk_penalty (float, optional): unknown word penalty, where <0 + produces more unks, >0 produces fewer (default: 0.0) + temperature (float, optional): temperature, where values + >1.0 produce more uniform samples and values <1.0 produce + sharper samples (default: 1.0) + match_source_len (bool, optional): outputs should match the source + length (default: False) + duration_temperature (float, optional): rate of the duration prediction, + higher rate induces a faster generated wav (default: 1.0) + """ + super().__init__() + if isinstance(models, MultichannelEnsembleModel): + self.model = models + else: + self.model = MultichannelEnsembleModel(models) + self.tgt_dicts = tgt_dicts + self.pad = list(tgt_dicts.values())[0].pad() + self.unk = list(tgt_dicts.values())[0].unk() + self.eos = list(tgt_dicts.values())[0].eos() if eos is None else eos + self.symbols_to_strip_from_output = ( + symbols_to_strip_from_output.union({self.eos}) + if symbols_to_strip_from_output is not None + else {self.eos} + ) + self.channels = list(tgt_dicts.keys()) + self.n_channels = len(self.channels) + self.vocab_sizes = [len(tgt_dicts[channel]) for channel in self.channels] + # the max beam size is the dictionary size - 1, since we never select pad + max_possible_beam_size = 1 + for i in self.vocab_sizes: + max_possible_beam_size *= i - 1 + self.beam_size = min(beam_size, max_possible_beam_size) + self.max_len_a = max_len_a + self.max_len_b = max_len_b + self.min_len = min_len + + self.normalize_scores = normalize_scores + self.len_penalty = len_penalty + self.unk_penalty = unk_penalty + if isinstance(temperature, (int, float)): + temperature = {channel: temperature for channel in self.channels} + elif isinstance(temperature, ListConfig) or isinstance(temperature, list): + temperature = { + channel: temperature[i] for i, channel in enumerate(self.channels) + } + assert isinstance(temperature, DictConfig) or isinstance( + temperature, dict + ), f"temperature: expected dict, but found {type(temperature)}" + self.temperature = temperature + self.match_source_len = match_source_len + + if no_repeat_ngram_size > 0: + self.repeat_ngram_blocker = NGramRepeatBlock(no_repeat_ngram_size) + else: + self.repeat_ngram_blocker = None + + for channel in temperature: + assert temperature[channel] > 0, "--temperature must be greater than 0" + + if search_strategy is None: + self.search = ContiguousMultichannelBeamSearch(tgt_dicts) + else: + self.search = search_strategy + # We only need to set src_lengths in LengthConstrainedBeamSearch. + # As a module attribute, setting it would break in multithread + # settings when the model is shared. + self.should_set_src_lengths = ( + hasattr(self.search, "needs_src_lengths") and self.search.needs_src_lengths + ) + + self.model.eval() + + self.lm_model = lm_model + self.lm_weight = lm_weight + if self.lm_model is not None: + self.lm_model.eval() + + self.duration_prediction = bool( + str(getattr(models[0].decoder.args, "duration_prediction", "false")).lower() + == "true" + ) + self.delayed_duration = bool( + str( + getattr(models[0].decoder.args, "delayed_duration_target", "false") + ).lower() + == "true" + ) + self.duration_temperature = duration_temperature + + def cuda(self): + self.model.cuda() + return self + + @torch.no_grad() + def forward( + self, + sample: Dict[str, Dict[str, Tensor]], # TODO: Modify this + prefix_tokens: Optional[Dict[str, Tensor]] = None, + bos_token: Optional[int] = None, + ): + """Generate a batch of translations. + + Args: + sample (dict): batch + prefix_tokens (dict of torch.LongTensor, optional): force decoder to begin + with these tokens + bos_token (int, optional): beginning of sentence token + (default: self.eos) + """ + return self._generate(sample, prefix_tokens, bos_token=bos_token) + + @torch.no_grad() + def generate(self, models, sample: Dict[str, Dict[str, Tensor]], **kwargs): + """Generate translations. Match the api of other fairseq generators. + + Args: + models (List[~fairseq.models.FairseqModel]): ensemble of models + sample (dict): batch + prefix_tokens (dict of torch.LongTensor, optional): force decoder to begin + with these tokens + constraints (torch.LongTensor, optional): force decoder to include + the list of constraints + bos_token (int, optional): beginning of sentence token + (default: self.eos) + """ + return self._generate(sample, **kwargs) + + def _generate( + self, + sample: Dict[str, Dict[str, Tensor]], + prefix_tokens: Optional[Dict[str, Tensor]] = None, + constraints: Optional[Tensor] = None, + bos_token: Optional[int] = None, + ): + """ + Here sample is expected to have the following form + { + 'id': index, + 'net_input': { + 'src_tokens': { + 'channel1' : tensor((batch x src_length)), + 'channel2' : tensor((batch x src_length)), + }, + ... + }, + } + and prefix_tokens + { + 'channel1' : tensor((batch x prefix_length)), + 'channel2' : tensor((batch x prefix_length)), + } + """ + if self.model.is_speech_dlm: + incremental_states = torch.jit.annotate( + List[Dict[str, Dict[str, Optional[Tensor]]]], + [ + torch.jit.annotate( + List[Dict[str, Dict[str, Optional[Tensor]]]], + [{} for _ in range(self.n_channels)], + ) + for i in range(self.model.models_size) + ], + ) + else: + incremental_states = torch.jit.annotate( + List[Dict[str, Dict[str, Optional[Tensor]]]], + [ + torch.jit.annotate(Dict[str, Dict[str, Optional[Tensor]]], {}) + for i in range(self.model.models_size) + ], + ) + net_input = sample["net_input"] + # Convert from dict to tensor form + # shape of src_tokens : (bsz x src_len x n_channels) + src_tokens = torch.stack( + [net_input["src_tokens"][channel] for channel in self.channels], dim=-1 + ) + prefix_tokens = torch.stack( + [prefix_tokens[channel] for channel in self.channels], dim=-1 + ) + # length of the source text being the character length except EndOfSentence and pad + src_lengths = ( + (src_tokens[..., 0].ne(self.eos) & src_tokens[..., 0].ne(self.pad)) + .long() + .sum(dim=1) + ) + + # bsz: total number of sentences in beam + # Note that src_tokens may have more than 2 dimensions (i.e. audio features) + bsz, src_len = src_tokens.size()[:2] + beam_size = self.beam_size + + if constraints is not None and not self.search.supports_constraints: + raise NotImplementedError( + "Target-side constraints were provided, but search method doesn't support them" + ) + + # Initialize constraints, when active + self.search.init_constraints(constraints, beam_size) + + max_len: int = -1 + if self.match_source_len: + max_len = src_lengths.max().item() + else: + max_len = min( + int(self.max_len_a * src_len + self.max_len_b), + # exclude the EOS marker + self.model.max_decoder_positions() - 1, + ) + assert ( + self.min_len <= max_len + ), "min_len cannot be larger than max_len, please adjust these!" + # compute the encoder output for each beam + encoder_outs = self.model.forward_encoder(net_input) + + # placeholder of indices for bsz * beam_size to hold tokens and accumulative scores + new_order = torch.arange(bsz).view(-1, 1).repeat(1, beam_size).view(-1) + new_order = new_order.to(src_tokens.device).long() + encoder_outs = self.model.reorder_encoder_out(encoder_outs, new_order) + # ensure encoder_outs is a List. + assert encoder_outs is not None + + # initialize buffers + # cumulative scores of hypotheses + scores = ( + torch.zeros(bsz * beam_size, max_len + 1, self.n_channels) + .to(src_tokens) + .float() + ) # +1 for eos; pad is never chosen for scoring + tokens = ( + torch.zeros(bsz * beam_size, max_len + 2, self.n_channels) + .to(src_tokens) + .long() + .fill_(self.pad) + ) # +2 for eos and pad + tokens[:, 0] = self.eos if bos_token is None else bos_token + attn: Optional[Tensor] = None + + # A list that indicates candidates that should be ignored. + # For example, suppose we're sampling and have already finalized 2/5 + # samples. Then cands_to_ignore would mark 2 positions as being ignored, + # so that we only finalize the remaining 3 samples. + cands_to_ignore = ( + torch.zeros(bsz, beam_size).to(src_tokens).eq(-1) + ) # forward and backward-compatible False mask + + # list of completed sentences + finalized = torch.jit.annotate( + List[List[Dict[str, Tensor]]], + [torch.jit.annotate(List[Dict[str, Tensor]], []) for i in range(bsz)], + ) # contains lists of dictionaries of infomation about the hypothesis being finalized at each step + + finished = [ + False for i in range(bsz) + ] # a boolean array indicating if the sentence at the index is finished or not + num_remaining_sent = bsz # number of sentences remaining + + # number of candidate hypos per step + cand_size = 2 * beam_size # 2 x beam size in case half are EOS + + # offset arrays for converting between different indexing schemes + bbsz_offsets = ( + (torch.arange(0, bsz) * beam_size) + .unsqueeze(1) + .type_as(tokens) + .to(src_tokens.device) + ) + cand_offsets = torch.arange(0, cand_size).type_as(tokens).to(src_tokens.device) + + reorder_state: Optional[Tensor] = None + batch_idxs: Optional[Tensor] = None + + original_batch_idxs: Optional[Tensor] = None + if "id" in sample and isinstance(sample["id"], Tensor): + original_batch_idxs = sample["id"] + else: + original_batch_idxs = torch.arange(0, bsz).type_as(tokens) + + if self.duration_prediction: + dur_counter = torch.ones(bsz * beam_size, self.n_channels).to(src_tokens) + # save the indice where the dur_counter just copied from dur_pred + dur_counter_jump_indices = None + + for step in range(max_len + 1): # one extra step for EOS marker + # reorder decoder internal states based on the prev choice of beams + if reorder_state is not None: + if batch_idxs is not None: + # update beam indices to take into account removed sentences + corr = batch_idxs - torch.arange(batch_idxs.numel()).type_as( + batch_idxs + ) + reorder_state.view(-1, beam_size).add_( + corr.unsqueeze(-1) * beam_size + ) + original_batch_idxs = original_batch_idxs[batch_idxs] + self.model.reorder_incremental_state(incremental_states, reorder_state) + encoder_outs = self.model.reorder_encoder_out( + encoder_outs, reorder_state + ) + + input_tokens = { + channel: tokens[:, : step + 1, i] + for i, channel in enumerate(self.channels) + } + + lprobs_dict, avg_attn_scores = self.model.forward_decoder( + input_tokens, + encoder_outs, + incremental_states, + self.temperature, + ) + + # Because the sizes of vocab is different, we cannot concat the lprobs to form a single tensor + if not self.duration_prediction: + lprobs_list = list(lprobs_dict.values()) + else: + lprobs_list = [ + net_output["pred_token"] for net_output in lprobs_dict.values() + ] + + # non-positive predicted durations + dur_preds = ( + torch.stack( + [ + net_output["pred_duration"] + for net_output in lprobs_dict.values() + ] + ) + .squeeze(-1) + .T + ) + dur_preds = dur_preds / self.duration_temperature + dur_preds = dur_preds.round().long() + dur_preds[dur_preds < 1] = 1 + + # dur_preds & dur_counter needs to be modified when there isn't an edge + if step > 0: + non_edge_indices = tokens[:, step, :] == tokens[:, step - 1, :] + if self.delayed_duration: + dur_preds[non_edge_indices] = 1 + else: + if dur_counter_jump_indices is not None: + dur_counter[dur_counter_jump_indices & non_edge_indices] = 2 + + # update dur_counter + if step > 0: + if self.delayed_duration: + dur_counter -= ( + (dur_counter == 1) + | (tokens[:, step, :] == tokens[:, step - 1, :]) + ).int() + dur_counter[dur_counter < 0] = 0 + else: + dur_counter -= ( + tokens[:, step, :] == tokens[:, step - 1, :] + ).int() + dur_counter[dur_counter < 1] = 1 + + # whether to copy previous token (ie. if the counter is still on) + # and get get the new duration + if self.delayed_duration: + dur_counter_jump_indices = dur_counter == 0 + dur_counter[dur_counter_jump_indices] = dur_preds[ + dur_counter_jump_indices + ] + + # whether to copy previous token in this step + copy_prev_token = dur_counter != 1 + if self.delayed_duration is False: + dur_counter_jump_indices = dur_counter == 1 + dur_counter[dur_counter_jump_indices] = dur_preds[ + dur_counter_jump_indices + ] + # else: + # dur_counter[dur_counter==0] = dur_preds[dur_counter==0] - 1 + # copy_prev_token = (dur_counter > 0) + + if self.lm_model is not None: + assert False, "Currently not supported in multichannelLM case" + + for i in range(self.n_channels): + lprobs_list[i][lprobs_list[i] != lprobs_list[i]] = torch.tensor( + -math.inf + ).to(lprobs_list[i]) + + lprobs_list[i][:, self.pad] = -math.inf # never select pad + lprobs_list[i][:, self.unk] -= self.unk_penalty # apply unk penalty + + # handle max length constraint + if step >= max_len: + lprobs_list[i][:, : self.eos] = -math.inf + lprobs_list[i][:, self.eos + 1 :] = -math.inf + else: + lprobs_list[i][ + :, self.eos + ] = -math.inf # quick fix for short generation + + # handle prefix tokens (possibly with different lengths) + if ( + prefix_tokens is not None + and step < prefix_tokens.size(1) + and step < max_len + ): + ( + lprobs_list[i], + tokens[..., i], + scores[..., i], + ) = self._prefix_tokens( + step, + lprobs_list[i], + scores[..., i], + tokens[..., i], + prefix_tokens[..., i], + beam_size, + ) + if self.duration_prediction: + # Can copy previous token if the prefix token is padding or unk (1-channel conditionned case) + can_copy_mask = ( + prefix_tokens[:, step, i].eq(self.pad) + | prefix_tokens[:, step, i].eq(self.unk) + ).repeat_interleave(beam_size) + copy_prev_token[:, i] &= can_copy_mask + elif step < self.min_len: + # minimum length constraint (does not apply if using prefix_tokens) + lprobs_list[i][:, self.eos] = -math.inf + + if self.duration_prediction: + if step < max_len: + for j in range(copy_prev_token.size(0)): + if copy_prev_token[j, i]: + prev_token = tokens[j, step, i] + lprobs_list[i][j, :prev_token] = -math.inf + lprobs_list[i][j, prev_token + 1 :] = -math.inf + # lprobs_list[i][j, prev_token] = 0. + # dur_counter[j,i] -= 1 + # else: + # prev_token = tokens[j, step, i] + # if not (lprobs_list[i][j,:].ne(-math.inf).nonzero() == prev_token).all(): + # lprobs_list[i][j, prev_token] = -math.inf + # dur_counter[j,i] = 0. + + # Record attention scores, only support avg_attn_scores is a Tensor + if avg_attn_scores is not None: + if attn is None: + attn = torch.empty( + bsz * beam_size, avg_attn_scores.size(1), max_len + 2 + ).to(scores) + attn[:, :, step + 1].copy_(avg_attn_scores) + + scores = scores.type_as(lprobs_list[0]) + eos_bbsz_idx = torch.empty(0).to( + tokens + ) # indices of hypothesis ending with eos (finished sentences) + eos_scores = torch.empty(0).to( + scores + ) # scores of hypothesis ending with eos (finished sentences) + + if self.should_set_src_lengths: + self.search.set_src_lengths(src_lengths) + + if self.repeat_ngram_blocker is not None: + for i in range(self.n_channels): + lprobs_list[i] = self.repeat_ngram_blocker( + tokens, lprobs_list[i], bsz, beam_size, step + ) + + # Shape: (batch, cand_size) + cand_scores, cand_indices, cand_beams = self.search.step( + step, + [ + lprobs_list[i].view(bsz, -1, self.vocab_sizes[i]) + for i in range(self.n_channels) + ], + scores.view(bsz, beam_size, -1, self.n_channels)[:, :, :step, :], + tokens[:, : step + 1], + original_batch_idxs, + ) + + # cand_bbsz_idx contains beam indices for the top candidate + # hypotheses, with a range of values: [0, bsz*beam_size), + # and dimensions: [bsz, cand_size] + cand_bbsz_idx = cand_beams.add(bbsz_offsets) + + # finalize hypotheses that end in eos + # Shape of eos_mask: (batch size, beam size) + eos_mask = cand_indices.eq(self.eos) & cand_scores.ne(-math.inf) + eos_mask = torch.any(eos_mask, dim=-1, keepdim=False) + eos_mask[:, :beam_size][cands_to_ignore] = torch.tensor(0).to(eos_mask) + + # only consider eos when it's among the top beam_size indices + # Now we know what beam item(s) to finish + # Shape: 1d list of absolute-numbered + eos_bbsz_idx = torch.masked_select( + cand_bbsz_idx[:, :beam_size], mask=eos_mask[:, :beam_size] + ) + + finalized_sents: List[int] = [] + if eos_bbsz_idx.numel() > 0: + eos_scores = torch.stack( + [ + torch.masked_select( + cand_scores[:, :beam_size, i], mask=eos_mask[:, :beam_size] + ) + for i in range(self.n_channels) + ], + dim=-1, + ) + finalized_sents = self.finalize_hypos( + step, + eos_bbsz_idx, + eos_scores, + tokens, + scores, + finalized, + finished, + beam_size, + attn, + src_lengths, + max_len, + ) + num_remaining_sent -= len(finalized_sents) + + assert num_remaining_sent >= 0 + if num_remaining_sent == 0: + break + if self.search.stop_on_max_len and step >= max_len: + break + assert step < max_len, f"{step} < {max_len}" + + # Remove finalized sentences (ones for which {beam_size} + # finished hypotheses have been generated) from the batch. + if len(finalized_sents) > 0: + new_bsz = bsz - len(finalized_sents) + + # construct batch_idxs which holds indices of batches to keep for the next pass + batch_mask = torch.ones( + bsz, dtype=torch.bool, device=cand_indices.device + ) + batch_mask[finalized_sents] = False + # TODO replace `nonzero(as_tuple=False)` after TorchScript supports it + batch_idxs = torch.arange( + bsz, device=cand_indices.device + ).masked_select(batch_mask) + + # Choose the subset of the hypothesized constraints that will continue + self.search.prune_sentences(batch_idxs) + + eos_mask = eos_mask[batch_idxs] + cand_beams = cand_beams[batch_idxs] + bbsz_offsets.resize_(new_bsz, 1) + cand_bbsz_idx = cand_beams.add(bbsz_offsets) + cand_scores = cand_scores[batch_idxs] + cand_indices = cand_indices[batch_idxs] + + if prefix_tokens is not None: + prefix_tokens = prefix_tokens[batch_idxs] + src_lengths = src_lengths[batch_idxs] + cands_to_ignore = cands_to_ignore[batch_idxs] + + scores = scores.view(bsz, -1)[batch_idxs].view( + new_bsz * beam_size, -1, self.n_channels + ) + tokens = tokens.view(bsz, -1)[batch_idxs].view( + new_bsz * beam_size, -1, self.n_channels + ) + if self.duration_prediction: + dur_counter = dur_counter.view(bsz, -1)[batch_idxs].view( + new_bsz * beam_size, self.n_channels + ) + if attn is not None: + attn = attn.view(bsz, -1)[batch_idxs].view( + new_bsz * beam_size, attn.size(1), -1 + ) + bsz = new_bsz + else: + batch_idxs = None + + # Set active_mask so that values > cand_size indicate eos hypos + # and values < cand_size indicate candidate active hypos. + # After, the min values per row are the top candidate active hypos + + # Rewrite the operator since the element wise or is not supported in torchscript. + + eos_mask[:, :beam_size] = ~((~cands_to_ignore) & (~eos_mask[:, :beam_size])) + active_mask = torch.add( + eos_mask.type_as(cand_offsets) * cand_size, + cand_offsets[: eos_mask.size(1)], + ) + + # get the top beam_size active hypotheses, which are just + # the hypos with the smallest values in active_mask. + # {active_hypos} indicates which {beam_size} hypotheses + # from the list of {2 * beam_size} candidates were + # selected. Shapes: (batch size, beam size) + new_cands_to_ignore, active_hypos = torch.topk( + active_mask, k=beam_size, dim=1, largest=False + ) + + # update cands_to_ignore to ignore any finalized hypos. + cands_to_ignore = new_cands_to_ignore.ge(cand_size)[:, :beam_size] + # Make sure there is at least one active item for each sentence in the batch. + assert (~cands_to_ignore).any(dim=1).all() + + # update cands_to_ignore to ignore any finalized hypos + # {active_bbsz_idx} denotes which beam number is continued for each new hypothesis (a beam + # can be selected more than once). + active_bbsz_idx = torch.gather(cand_bbsz_idx, dim=1, index=active_hypos) + active_bbsz_idx = active_bbsz_idx.view(-1) + + # active_scores = torch.stack([ + # torch.gather(cand_scores[...,0], dim=1, index=active_hypos) + # for i in range(self.n_channels) + # ], dim = -1) + # active_scores = active_scores.view(-1) + + # copy tokens and scores for active hypotheses + + # Set the tokens for each beam (can select the same row more than once) + tokens[:, : step + 1] = torch.index_select( + tokens[:, : step + 1], dim=0, index=active_bbsz_idx + ) + # Select the next token for each of them + for i in range(self.n_channels): + tokens.view(bsz, beam_size, -1, self.n_channels)[ + :, :, step + 1, i + ] = torch.gather(cand_indices[..., i], dim=1, index=active_hypos) + if step > 0: + scores[:, :step] = torch.index_select( + scores[:, :step], dim=0, index=active_bbsz_idx + ) + for i in range(self.n_channels): + scores.view(bsz, beam_size, -1, self.n_channels)[ + :, :, step, i + ] = torch.gather(cand_scores[..., i], dim=1, index=active_hypos) + + if self.duration_prediction: + dur_counter = torch.index_select( + dur_counter, dim=0, index=active_bbsz_idx + ) + + # Update constraints based on which candidates were selected for the next beam + self.search.update_constraints(active_hypos) + + # copy attention for active hypotheses + if attn is not None: + attn[:, :, : step + 2] = torch.index_select( + attn[:, :, : step + 2], dim=0, index=active_bbsz_idx + ) + + # reorder incremental state in decoder + reorder_state = active_bbsz_idx + + # sort by score descending + for sent in range(len(finalized)): + scores = torch.tensor( + [float(elem["score"].item()) for elem in finalized[sent]] + ) + _, sorted_scores_indices = torch.sort(scores, descending=True) + finalized[sent] = [finalized[sent][ssi] for ssi in sorted_scores_indices] + finalized[sent] = torch.jit.annotate( + List[Dict[str, Tensor]], finalized[sent] + ) + return finalized + + def _prefix_tokens( + self, step: int, lprobs, scores, tokens, prefix_tokens, beam_size: int + ): + """Handle prefix tokens""" + prefix_toks = prefix_tokens[:, step].unsqueeze(-1).repeat(1, beam_size).view(-1) + prefix_lprobs = lprobs.gather(-1, prefix_toks.unsqueeze(-1)) + prefix_mask = prefix_toks.ne(self.pad) + # used for 1-channel generation, do not force the unk token (i.e. unk tokens are changed) + prefix_mask &= prefix_toks.ne(self.unk) + # zeroing the copying tokens + # if step > 0: + # copy_mask = (prefix_tokens[:, step] == prefix_tokens[:, step-1]).unsqueeze(-1).repeat(1, beam_size).view(-1) + # prefix_lprobs[copy_mask & prefix_mask] = 0. + lprobs[prefix_mask] = torch.tensor(-math.inf).to(lprobs) + lprobs[prefix_mask] = lprobs[prefix_mask].scatter( + -1, prefix_toks[prefix_mask].unsqueeze(-1), prefix_lprobs[prefix_mask] + ) + # shouldn't stop at unk token + unk_mask = prefix_toks.eq(self.unk) + if len(lprobs[unk_mask]) > 0: + # otherwise it won't assign to lprobs, + # see: https://discuss.pytorch.org/t/how-to-mask-and-assign-a-value-to-tensor/18437 + copy_lprobs = lprobs[unk_mask][:, :] + copy_lprobs[:, self.eos] = -math.inf + lprobs[unk_mask] = copy_lprobs + # if prefix includes eos, then we should make sure tokens and + # scores are the same across all beams + eos_mask = prefix_toks.eq(self.eos) + if eos_mask.any(): + # validate that the first beam matches the prefix + first_beam = tokens[eos_mask].view(-1, beam_size, tokens.size(-1))[ + :, 0, 1 : step + 1 + ] + eos_mask_batch_dim = eos_mask.view(-1, beam_size)[:, 0] + target_prefix = prefix_tokens[eos_mask_batch_dim][:, :step] + assert (first_beam == target_prefix).all() + + # copy tokens, scores and lprobs from the first beam to all beams + tokens = self.replicate_first_beam(tokens, eos_mask_batch_dim, beam_size) + scores = self.replicate_first_beam(scores, eos_mask_batch_dim, beam_size) + lprobs = self.replicate_first_beam(lprobs, eos_mask_batch_dim, beam_size) + return lprobs, tokens, scores + + def replicate_first_beam(self, tensor, mask, beam_size: int): + tensor = tensor.view(-1, beam_size, tensor.size(-1)) + tensor[mask] = tensor[mask][:, :1, :] + return tensor.view(-1, tensor.size(-1)) + + def finalize_hypos( + self, + step: int, + bbsz_idx, + eos_scores, + tokens, + scores, + finalized: List[List[Dict[str, Tensor]]], + finished: List[bool], + beam_size: int, + attn: Optional[Tensor], + src_lengths, + max_len: int, + ): + """Finalize hypothesis, store finalized information in `finalized`, and change `finished` accordingly. + A sentence is finalized when {beam_size} finished items have been collected for it. + + Returns number of sentences (not beam items) being finalized. + These will be removed from the batch and not processed further. + Args: + bbsz_idx (Tensor): + """ + assert bbsz_idx.numel() == eos_scores.size(0) + + # clone relevant token and attention tensors. + # tokens is (batch * beam, max_len). So the index_select + # gets the newly EOS rows, then selects cols 1..{step + 2} + tokens_clone = tokens.index_select(0, bbsz_idx)[ + :, 1 : step + 2 + ] # skip the first index, which is EOS + + tokens_clone[:, step] = self.eos + attn_clone = ( + attn.index_select(0, bbsz_idx)[:, :, 1 : step + 2] + if attn is not None + else None + ) + + # compute scores per token position + pos_scores = scores.index_select(0, bbsz_idx)[:, : step + 1] + pos_scores[:, step, :] = eos_scores + # convert from cumulative to per-position scores + pos_scores[:, 1:] = pos_scores[:, 1:] - pos_scores[:, :-1] + + # normalize sentence-level scores + if self.normalize_scores: + eos_scores /= (step + 1) ** self.len_penalty + + # cum_unfin records which sentences in the batch are finished. + # It helps match indexing between (a) the original sentences + # in the batch and (b) the current, possibly-reduced set of + # sentences. + cum_unfin: List[int] = [] + prev = 0 + for f in finished: + if f: + prev += 1 + else: + cum_unfin.append(prev) + + # The keys here are of the form "{sent}_{unfin_idx}", where + # "unfin_idx" is the index in the current (possibly reduced) + # list of sentences, and "sent" is the index in the original, + # unreduced batch + # set() is not supported in script export + sents_seen: Dict[str, Optional[Tensor]] = {} + + # For every finished beam item + for i in range(bbsz_idx.size()[0]): + idx = bbsz_idx[i] + score = eos_scores[i].sum() + # sentence index in the current (possibly reduced) batch + unfin_idx = idx // beam_size + # sentence index in the original (unreduced) batch + sent = unfin_idx + cum_unfin[unfin_idx] + # Cannot create dict for key type '(int, int)' in torchscript. + # The workaround is to cast int to string + seen = str(sent.item()) + "_" + str(unfin_idx.item()) + if seen not in sents_seen: + sents_seen[seen] = None + + if self.match_source_len and step > src_lengths[unfin_idx]: + score = torch.tensor(-math.inf).to(score) + + # An input sentence (among those in a batch) is finished when + # beam_size hypotheses have been collected for it + if len(finalized[sent]) < beam_size: + if attn_clone is not None: + # remove padding tokens from attn scores + hypo_attn = attn_clone[i] + else: + hypo_attn = torch.empty(0) + + finalized[sent].append( + { + "tokens": tokens_clone[i], + "score": score, + "attention": hypo_attn, # src_len x tgt_len + "alignment": torch.empty(0), + "positional_scores": pos_scores[i], + } + ) + + newly_finished: List[int] = [] + + for seen in sents_seen.keys(): + # check termination conditions for this sentence + sent: int = int(float(seen.split("_")[0])) + unfin_idx: int = int(float(seen.split("_")[1])) + + if not finished[sent] and self.is_finished( + step, unfin_idx, max_len, len(finalized[sent]), beam_size + ): + finished[sent] = True + newly_finished.append(unfin_idx) + + return newly_finished + + def is_finished( + self, + step: int, + unfin_idx: int, + max_len: int, + finalized_sent_len: int, + beam_size: int, + ): + """ + Check whether decoding for a sentence is finished, which + occurs when the list of finalized sentences has reached the + beam size, or when we reach the maximum length. + """ + assert finalized_sent_len <= beam_size + if finalized_sent_len == beam_size or step == max_len: + return True + return False + + +class MultichannelEnsembleModel(nn.Module): + """A wrapper around an ensemble of SpeechDLM models.""" + + def __init__(self, models): + super().__init__() + self.models_size = len(models) + # method '__len__' is not supported in ModuleList for torch script + self.single_model = models[0] + self.models = nn.ModuleList(models) + + self.has_incremental: bool = False + if all( + hasattr(m, "decoder") and isinstance(m.decoder, FairseqIncrementalDecoder) + for m in models + ): + self.has_incremental = True + + if isinstance(models[0], SpeechDLM): + self.is_speech_dlm = True + # Otherwise it's a multi-channel language model (without cross-prediction outputs) + else: + self.is_speech_dlm = False + + if getattr(models[0].decoder.args, "duration_prediction", False): + self.is_duration_prediction = True + else: + self.is_duration_prediction = False + + def forward(self): + pass + + def has_encoder(self): + return hasattr(self.single_model, "encoder") + + def has_incremental_states(self): + return self.has_incremental + + def max_decoder_positions(self): + return min([m.max_decoder_positions() for m in self.models]) + + @torch.jit.export + def forward_encoder(self, net_input: Dict[str, Tensor]): + if not self.has_encoder(): + return None + return [model.encoder.forward_torchscript(net_input) for model in self.models] + + @torch.jit.export + def forward_decoder( + self, + tokens, + encoder_outs: List[Dict[str, List[Tensor]]], + incremental_states: List[Dict[str, Dict[str, Optional[Tensor]]]], + temperature: Dict[str, float] = 1.0, + ): + if isinstance(temperature, (float, int)): + temperature = {channel: temperature for channel in tokens} + log_probs = {channel: [] for channel in tokens} + avg_attn: Optional[Tensor] = None + encoder_out: Optional[Dict[str, List[Tensor]]] = None + for i, model in enumerate(self.models): + if self.has_encoder(): + encoder_out = encoder_outs[i] + # decode each model + if self.has_incremental_states(): + decoder_out = model.decoder.forward( + tokens, + encoder_out=encoder_out, + incremental_state=incremental_states[i], + ) + else: + decoder_out = model.decoder.forward(tokens, encoder_out=encoder_out) + + attn: Optional[Tensor] = None + decoder_len = len(decoder_out) + if decoder_len > 1 and decoder_out[1] is not None: + if isinstance(decoder_out[1], Tensor): + attn = decoder_out[1] + else: + attn_holder = decoder_out[1]["attn"] + if isinstance(attn_holder, Tensor): + attn = attn_holder + elif attn_holder is not None: + attn = attn_holder[0] + if attn is not None: + attn = attn[:, -1, :] + + if self.is_speech_dlm: + if self.is_duration_prediction: + decoder_out_divided_by_temperature = { + channel_src: { + channel_pred: { + "pred_token": decoder_out[0][channel_src][channel_pred][ + "pred_token" + ][:, -1:, :].div_(temperature[channel_pred]), + "pred_duration": decoder_out[0][channel_src][ + channel_pred + ]["pred_duration"][:, -1:, :], + } + for channel_pred in decoder_out[0][channel_src] + } + for channel_src in decoder_out[0] + } + else: + decoder_out_divided_by_temperature = { + channel_src: { + channel_pred: decoder_out[0][channel_src][channel_pred][ + :, -1:, : + ].div_(temperature[channel_pred]) + for channel_pred in decoder_out[0][channel_src] + } + for channel_src in decoder_out[0] + } + else: + decoder_out_divided_by_temperature = { + channel: decoder_out[0][channel][:, -1:, :].div_( + temperature[channel] + ) + for channel in decoder_out[0] + } + decoder_out_tuple = ( + decoder_out_divided_by_temperature, + None if decoder_len <= 1 else decoder_out[1], + ) + + probs = model.get_normalized_probs( + decoder_out_tuple, log_probs=True, sample=None + ) + + if self.is_speech_dlm: + if self.is_duration_prediction: + probs = { + channel: { + "pred_token": probs[channel][channel]["pred_token"][ + :, -1, : + ], + "pred_duration": probs[channel][channel]["pred_duration"][ + :, -1, : + ], + } + for channel in probs + } + else: + probs = { + channel: probs[channel][channel][:, -1, :] for channel in probs + } + else: + probs = {channel: probs[channel][:, -1, :] for channel in probs} + if self.models_size == 1: + return probs, attn + + for channel in probs: + log_probs[channel].append(probs[channel]) + if attn is not None: + if avg_attn is None: + avg_attn = attn + else: + avg_attn.add_(attn) + + avg_probs = {} + for channel in log_probs: + avg_probs[channel] = torch.logsumexp( + torch.stack(log_probs[channel], dim=0), dim=0 + ) - math.log(self.models_size) + + if avg_attn is not None: + avg_attn.div_(self.models_size) + return avg_probs, avg_attn + + @torch.jit.export + def reorder_encoder_out( + self, encoder_outs: Optional[List[Dict[str, List[Tensor]]]], new_order + ): + """ + Reorder encoder output according to *new_order*. + + Args: + encoder_out: output from the ``forward()`` method + new_order (LongTensor): desired order + + Returns: + *encoder_out* rearranged according to *new_order* + """ + new_outs: List[Dict[str, List[Tensor]]] = [] + if not self.has_encoder(): + return new_outs + for i, model in enumerate(self.models): + assert encoder_outs is not None + new_outs.append( + model.encoder.reorder_encoder_out(encoder_outs[i], new_order) + ) + return new_outs + + @torch.jit.export + def reorder_incremental_state( + self, + incremental_states: List[Dict[str, Dict[str, Optional[Tensor]]]], + new_order, + ): + if not self.has_incremental_states(): + return + for i, model in enumerate(self.models): + model.decoder.reorder_incremental_state_scripting( + incremental_states[i], new_order + ) diff --git a/fairseq/models/speech_dlm/speech_dlm.py b/fairseq/models/speech_dlm/speech_dlm.py new file mode 100644 index 0000000000..dc13f565f1 --- /dev/null +++ b/fairseq/models/speech_dlm/speech_dlm.py @@ -0,0 +1,280 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from dataclasses import dataclass, field +from typing import Optional + +from fairseq import utils +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.models import ( + FairseqLanguageModel, + register_model, + register_model_architecture, +) +from fairseq.models.transformer import Embedding +from .modules.speech_dlm_decoder import CrossChannelTransformerDecoder +from omegaconf import II + + +DEFAULT_MAX_TARGET_POSITIONS = 1024 + +logger = logging.getLogger(__name__) + + +@dataclass +class SpeechDLMConfig(FairseqDataclass): + activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( + default="relu", metadata={"help": "activation function to use"} + ) + dropout: float = field(default=0.1, metadata={"help": "dropout probability"}) + attention_dropout: float = field( + default=0.0, metadata={"help": "dropout probability for attention weights"} + ) + activation_dropout: float = field( + default=0.0, metadata={"help": "dropout probability after activation in FFN."} + ) + relu_dropout: float = field( + default=0.0, metadata={"help": "dropout probability after activation in FFN."} + ) + decoder_embed_dim: int = field( + default=512, metadata={"help": "decoder embedding dimension"} + ) + decoder_output_dim: int = field( + default=512, metadata={"help": "decoder output dimension"} + ) + decoder_input_dim: int = field( + default=512, metadata={"help": "decoder input dimension"} + ) + decoder_ffn_embed_dim: int = field( + default=2048, metadata={"help": "decoder embedding dimension for FFN"} + ) + decoder_layers: int = field(default=6, metadata={"help": "num decoder layers"}) + decoder_cross_layers: int = field( + default=-1, metadata={"help": "num self cross attention decoder layers"} + ) + decoder_attention_heads: int = field( + default=8, metadata={"help": "num decoder attention heads"} + ) + decoder_normalize_before: bool = field( + default=False, metadata={"help": "apply layernorm before each decoder block"} + ) + no_decoder_final_norm: bool = field( + default=False, + metadata={"help": "don't add an extra layernorm after the last decoder block"}, + ) + no_token_positional_embeddings: bool = field( + default=False, + metadata={ + "help": "if set, disables positional embeddings (outside self attention)" + }, + ) + share_decoder_input_output_embed: bool = field( + default=False, metadata={"help": "share decoder input and output embeddings"} + ) + decoder_learned_pos: bool = field( + default=False, + metadata={"help": "use learned positional embeddings in the decoder"}, + ) + decoder_layerdrop: float = field( + default=0.0, metadata={"help": "LayerDrop probability for decoder"} + ) + decoder_layers_to_keep: Optional[str] = field( + default=None, + metadata={ + "help": "which layers to *keep* when pruning as a comma-separated list" + }, + ) + layernorm_embedding: bool = field( + default=False, metadata={"help": "add layernorm to embedding"} + ) + no_scale_embedding: bool = field( + default=False, metadata={"help": "if True, dont scale embeddings"} + ) + checkpoint_activations: bool = field( + default=False, metadata={"help": "checkpoint activations at each layer"} + ) + offload_activations: bool = field( + default=False, + metadata={"help": "move checkpointed activations to CPU after they are used."}, + ) + quant_noise_pq: float = field( + default=0.0, + metadata={"help": "iterative PQ quantization noise at training time"}, + ) + quant_noise_pq_block_size: int = field( + default=8, + metadata={"help": "block size of quantization noise at training time"}, + ) + # TODO common var add to parent + quant_noise_scalar: float = field( + default=0.0, + metadata={ + "help": "scalar quantization noise and scalar quantization at training time" + }, + ) + add_bos_token: bool = II("task.add_bos_token") + tokens_per_sample: int = II("task.tokens_per_sample") + max_target_positions: Optional[int] = II("task.max_target_positions") + tpu: bool = II("common.tpu") + duration_prediction: str = II("task.duration_prediction") + delayed_duration_target: str = II("task.delayed_duration_target") + main_and_cross_weights: str = II("criterion.main_and_cross_weights") + + +@register_model("speech_dlm", dataclass=SpeechDLMConfig) +class SpeechDLM(FairseqLanguageModel): + """Spoken Unit-based Dialogue Language Model model (SpeechDLM) as described + in the paper: https://arxiv.org/pdf/2203.16502.pdf + """ + + def __init__(self, decoder): + super().__init__(decoder) + + @classmethod + def build_model(cls, args, task): + """Build a new model instance.""" + # make sure all arguments are present in older models + base_lm_architecture(args) + + if args.decoder_layers_to_keep: + args.decoder_layers = len(args.decoder_layers_to_keep.split(",")) + + if args.decoder_cross_layers < 0: + args.decoder_cross_layers = args.decoder_layers + + if getattr(args, "max_target_positions", None) is None: + args.max_target_positions = getattr( + args, "tokens_per_sample", DEFAULT_MAX_TARGET_POSITIONS + ) + + # Assert all dictionary to be the same + assert all( + task.source_dictionaries[channel] == task.source_dictionary + for channel in task.channels + ), "Source dictionaries of all channels are expected to be the same!!!" + assert all( + task.target_dictionaries[channel] == task.target_dictionary + for channel in task.channels + ), "Target dictionaries of all channels are expected to be the same!!!" + # Build the unit embeddings + embed_tokens = cls.build_embedding( + args, task.source_dictionary, args.decoder_input_dim + ) + + decoder = CrossChannelTransformerDecoder( + args, + task.target_dictionary, + embed_tokens, + channels=task.channels, + no_encoder_attn=True, + ) + return cls(decoder) + + @classmethod + def build_embedding(cls, args, dictionary, embed_dim, path=None): + embed_tokens = Embedding(len(dictionary), embed_dim, dictionary.pad()) + return embed_tokens + + @classmethod + def from_pretrained( + cls, + model_name_or_path, + checkpoint_file="model.pt", + data_name_or_path=".", + **kwargs, + ): + """ + Load a :class:`~fairseq.models.FairseqModel` from a pre-trained model + file. Downloads and caches the pre-trained model file if needed. + + The base implementation returns a + :class:`~fairseq.hub_utils.GeneratorHubInterface`, which can be used to + generate translations or sample from language models. The underlying + :class:`~fairseq.models.FairseqModel` can be accessed via the + *generator.models* attribute. + + This function return a class:`MultichannelGeneratorHubInterface` object, + which allows generation in multiple channels with a multichannel model. + + Args: + model_name_or_path (str): either the name of a pre-trained model to + load or a path/URL to a pre-trained model state dict + checkpoint_file (str, optional): colon-separated list of checkpoint + files in the model archive to ensemble (default: 'model.pt') + data_name_or_path (str, optional): point args.data to the archive + at the given path/URL. Can start with '.' or './' to reuse the + model archive path. + """ + from fairseq import hub_utils + from .hub_interface import MultichannelGeneratorHubInterface + + x = hub_utils.from_pretrained( + model_name_or_path, + checkpoint_file, + data_name_or_path, + archive_map=cls.hub_models(), + **kwargs, + ) + logger.info(x["args"]) + return MultichannelGeneratorHubInterface(x["args"], x["task"], x["models"]) + + @property + def supported_targets(self): + return {"next", "edge", "duration"} + + +def base_lm_architecture(args): + # backward compatibility for older model checkpoints + if hasattr(args, "decoder_final_norm"): + args.no_decoder_final_norm = not args.decoder_final_norm + + args.dropout = getattr(args, "dropout", 0.1) + args.attention_dropout = getattr(args, "attention_dropout", 0.0) + + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 512) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 2048) + args.decoder_layers = getattr(args, "decoder_layers", 6) + args.decoder_cross_layers = getattr(args, "decoder_cross_layers", 6) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 8) + args.decoder_learned_pos = getattr(args, "decoder_learned_pos", False) + args.activation_fn = getattr(args, "activation_fn", "relu") + args.decoder_layerdrop = getattr(args, "decoder_layerdrop", 0) + args.decoder_layers_to_keep = getattr(args, "decoder_layers_to_keep", None) + args.quant_noise_pq = getattr(args, "quant_noise_pq", 0) + args.quant_noise_pq_block_size = getattr(args, "quant_noise_pq_block_size", 8) + args.quant_noise_scalar = getattr(args, "quant_noise_scalar", 0) + + args.add_bos_token = getattr(args, "add_bos_token", False) + args.no_token_positional_embeddings = getattr( + args, "no_token_positional_embeddings", False + ) + args.share_decoder_input_output_embed = getattr( + args, "share_decoder_input_output_embed", False + ) + args.decoder_output_dim = getattr( + args, "decoder_output_dim", args.decoder_embed_dim + ) + args.decoder_input_dim = getattr(args, "decoder_input_dim", args.decoder_embed_dim) + + # Model training is not stable without this + args.decoder_normalize_before = True + args.no_decoder_final_norm = getattr(args, "no_decoder_final_norm", False) + args.no_scale_embedding = getattr(args, "no_scale_embedding", False) + args.layernorm_embedding = getattr(args, "layernorm_embedding", False) + args.checkpoint_activations = getattr(args, "checkpoint_activations", False) + args.offload_activations = getattr(args, "offload_activations", False) + if args.offload_activations: + args.checkpoint_activations = True + + +@register_model_architecture("speech_dlm", "speech_dlm_big") +def speech_dlm_big(args): + args.decoder_layers = getattr(args, "decoder_layers", 12) + args.decoder_cross_layers = getattr(args, "decoder_cross_layers", 12) + args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) + args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4096) + args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) + base_lm_architecture(args) diff --git a/fairseq/tasks/speech_dlm_task.py b/fairseq/tasks/speech_dlm_task.py new file mode 100644 index 0000000000..340732b928 --- /dev/null +++ b/fairseq/tasks/speech_dlm_task.py @@ -0,0 +1,561 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +import os +from dataclasses import dataclass, field +from typing import Optional +from collections import OrderedDict + +import numpy as np +import torch +from fairseq import utils +from fairseq.data import ( + AppendTokenDataset, + Dictionary, + IdDataset, + LMContextWindowDataset, + MonolingualDataset, + NestedDictionaryDataset, + NumelDataset, + PadDataset, + PrependTokenDataset, + SpeechDLMDataset, + StripTokenDataset, + TokenBlockDataset, + TruncatedDictionary, + data_utils, +) +from fairseq.data.indexed_dataset import get_available_dataset_impl +from fairseq.data.shorten_dataset import maybe_shorten_dataset +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.tasks import LegacyFairseqTask, register_task +from omegaconf import II + + +SAMPLE_BREAK_MODE_CHOICES = ChoiceEnum(["none", "complete", "complete_doc", "eos"]) +SHORTEN_METHOD_CHOICES = ChoiceEnum(["none", "truncate", "random_crop"]) +logger = logging.getLogger(__name__) + + +@dataclass +class SpeechDLMConfig(FairseqDataclass): + data: Optional[str] = field( + default=None, metadata={"help": "path to data directory"} + ) + channels: Optional[str] = field( + default=None, + metadata={ + "help": 'comma-separated list of channels to load e.g., "unitA,unitB"' + "(default: load all possible channels in the data path)" + }, + ) + channel_weights: Optional[str] = field( + default=None, + metadata={ + "help": "comma-separated list of weights for different losses" + "(default: None, which means all losses are treated equally)" + }, + ) + sample_break_mode: SAMPLE_BREAK_MODE_CHOICES = field( + default="none", + metadata={ + "help": 'If omitted or "none", fills each sample with tokens-per-sample ' + 'tokens. If set to "complete", splits samples only at the end ' + "of sentence, but may include multiple sentences per sample. " + '"complete_doc" is similar but respects doc boundaries. ' + 'If set to "eos", includes only one sentence per sample.' + }, + ) + tokens_per_sample: int = field( + default=1024, + metadata={"help": "max number of tokens per sample for LM dataset"}, + ) + output_dictionary_size: int = field( + default=-1, metadata={"help": "limit the size of output dictionary"} + ) + # str type is a workaround to put **default=True** here + next_unit_prediction: str = field( + default="False", + metadata={ + "help": "Perform Next Unit Prediction, expected str input ('True' or 'False')" + }, + ) + edge_unit_prediction: str = field( + default="True", + metadata={ + "help": "Perform Edge Unit Prediction, expected str input ('True' or 'False')" + }, + ) + duration_prediction: str = field( + default="True", + metadata={ + "help": "Perform Duration Prediction, expected str input ('True' or 'False')" + }, + ) + delayed_duration_target: str = field( + default="True", + metadata={ + "help": "Perform Delayed Duration Prediction, expected str input ('True' or 'False')" + "(default: 'True')" + }, + ) + max_target_durations: Optional[int] = field( + default=256, + metadata={"help": "max duration considered (cut off to this value)"}, + ) + add_bos_token: bool = field( + default=False, metadata={"help": "prepend beginning of sentence token (<s>)"} + ) + max_target_positions: Optional[int] = field( + default=None, metadata={"help": "max number of tokens in the target sequence"} + ) + shorten_method: SHORTEN_METHOD_CHOICES = field( + default="none", + metadata={ + "help": "if not none, shorten sequences that exceed --tokens-per-sample" + }, + ) + shorten_data_split_list: str = field( + default="", + metadata={ + "help": "comma-separated list of dataset splits to apply shortening to, " + 'e.g., "train,valid" (default: all dataset splits)' + }, + ) + # TODO common vars below add to parent + seed: int = II("common.seed") + dataset_impl: Optional[ChoiceEnum(get_available_dataset_impl())] = II( + "dataset.dataset_impl" + ) + data_buffer_size: int = II("dataset.data_buffer_size") + tpu: bool = II("common.tpu") + + +@register_task("speech_dlm_task", dataclass=SpeechDLMConfig) +class SpeechDLMTask(LegacyFairseqTask): + """Task for the SpeechDLM model as described in the paper: + https://arxiv.org/pdf/2203.16502.pdf + + It create a multi-channel dataset (SpeechDLMDataset) from multiple + dictionaries. + + Args: + dictionaries (Dict[str, ~fairseq.data.Dictionary]): the dictionaries for + each input channel of the SpeechDLM model + output_dictionaries (Dict[str, ~fairseq.data.Dictionary]): the dictionaries + for the output of each channel of the SpeechDLM model. In most cases it + will be the same as *dictionaries*. + targets (List[str]): list of the target types that the SpeechDLM model + should predict. Can be one of "next", "edge", "duration". + Defaults to "next". + + .. note:: + + The SpeechDLM task is only compatible with + :mod:`fairseq-train` and :mod:`fairseq-validate`. + To generate new samples, please refer to example codes + at examples/textless_nlp/dgslm . + """ + + def __init__(self, args, dicts, output_dicts=None, targets=None): + super().__init__(args) + self.dicts = dicts + self.output_dicts = output_dicts or dicts + + if targets is None: + targets = ["next"] + self.targets = targets + + self.channels = list(dicts.keys()) + + if args.channel_weights is not None: + self.channel_weights = [float(w) for w in args.channel_weights.split(",")] + else: + self.channel_weights = [1.0 for _ in self.channels] + assert len(self.channel_weights) == len( + self.channels + ), "number of channel_weights must be the same as number of channels" + + assert str(args.next_unit_prediction).lower() in [ + "true", + "false", + ], f"Expected to be a string of boolean, found {args.next_unit_prediction}" + assert str(args.edge_unit_prediction).lower() in [ + "true", + "false", + ], f"Expected to be a string of boolean, found {args.edge_unit_prediction}" + assert str(args.duration_prediction).lower() in [ + "true", + "false", + ], f"Expected to be a string of boolean, found {args.duration_prediction}" + assert str(args.delayed_duration_target).lower() in [ + "true", + "false", + ], f"Expected to be a string of boolean, found {args.delayed_duration_target}" + self.next_unit_prediction = bool( + str(args.next_unit_prediction).lower() == "true" + ) + self.edge_unit_prediction = bool( + str(args.edge_unit_prediction).lower() == "true" + ) + self.duration_prediction = bool(str(args.duration_prediction).lower() == "true") + self.delayed_duration_target = bool( + str(args.delayed_duration_target).lower() == "true" + ) + + self.max_target_durations = args.max_target_durations + + @classmethod + def setup_dictionary(cls, args, **kwargs): + """The dictionaries will be a dict over channel keys and values of type + ~fairseq.data.Dictionary. + """ + paths = utils.split_paths(args.data) + assert len(paths) > 0 + data_path = paths[0] + + dicts = None + output_dicts = None + if args.channels is None: + sorted_channels = sorted( + name[5:-4] + for name in os.listdir(data_path) + if name[:5] == "dict." and name[-4:] == ".txt" + ) + else: + sorted_channels = sorted(args.channels.split(",")) + logger.info("channels: {}".format(sorted_channels)) + # load dictionaries + dicts = OrderedDict() + output_dicts = OrderedDict() + for channel in sorted_channels: + dictionary = Dictionary.load( + os.path.join(data_path, "dict.{}.txt".format(channel)) + ) + logger.info("[{}] dictionary: {} types".format(channel, len(dictionary))) + output_dictionary = dictionary + if args.output_dictionary_size >= 0: + output_dictionary = TruncatedDictionary( + dictionary, args.output_dictionary_size + ) + dicts[channel] = dictionary + output_dicts[channel] = output_dictionary + if len(dicts) > 0: + assert dicts[channel].pad() == dicts[sorted_channels[0]].pad() + assert dicts[channel].bos() == dicts[sorted_channels[0]].bos() + assert dicts[channel].eos() == dicts[sorted_channels[0]].eos() + assert dicts[channel].unk() == dicts[sorted_channels[0]].unk() + return (dicts, output_dicts) + + @classmethod + def setup_task(cls, args, **kwargs): + """Setup the task (e.g., load dictionaries). + + Args: + args (argparse.Namespace): parsed command-line arguments + """ + dicts, output_dicts = cls.setup_dictionary(args, **kwargs) + + targets = [] + if str(getattr(args, "next_unit_prediction", "false")).lower() == "true": + targets.append("next") + if str(getattr(args, "edge_unit_prediction", "false")).lower() == "true": + targets.append("edge") + if str(getattr(args, "duration_prediction", "false")).lower() == "true": + targets.append("duration") + if len(targets) == 0: + # standard language modeling + targets = ["next"] + + return cls(args, dicts, output_dicts, targets=targets) + + def build_model(self, args): + model = super().build_model(args) + for target in self.targets: + if target not in model.supported_targets: + raise ValueError("Unsupported SpeechDLM target: {}".format(target)) + return model + + def load_dataset( + self, split: str, epoch=1, combine=False, **kwargs + ) -> SpeechDLMDataset: + """Load a given dataset split. + + Args: + split (str): name of the split (e.g., train, valid, test) + """ + paths = utils.split_paths(self.args.data) + assert len(paths) > 0 + + data_path = paths[(epoch - 1) % len(paths)] + + channel_datasets = {} + for channel in self.channels: + split_path = os.path.join(data_path, split + "." + channel) + dictionary = self.dicts[channel] + output_dictionary = self.output_dicts[channel] + + dataset = data_utils.load_indexed_dataset( + split_path, dictionary, self.args.dataset_impl, combine=combine + ) + + if dataset is None: + raise FileNotFoundError( + "[{}] Dataset not found: {} ({})".format(channel, split, split_path) + ) + + dataset = maybe_shorten_dataset( + dataset, + split, + self.args.shorten_data_split_list, + self.args.shorten_method, + self.args.tokens_per_sample, + self.args.seed, + ) + + dataset = TokenBlockDataset( + dataset, + dataset.sizes, + self.args.tokens_per_sample, + pad=dictionary.pad(), + eos=dictionary.eos(), + break_mode=self.args.sample_break_mode, + include_targets=True, + ) + + add_eos_for_other_targets = ( + self.args.sample_break_mode is not None + and self.args.sample_break_mode != "none" + ) + + channel_datasets[channel] = MonolingualDataset( + dataset=dataset, + sizes=dataset.sizes, + src_vocab=dictionary, + tgt_vocab=output_dictionary, + add_eos_for_other_targets=add_eos_for_other_targets, + shuffle=False, + targets=["future"], + add_bos_token=self.args.add_bos_token, + ) + + self.datasets[split] = SpeechDLMDataset( + datasets=channel_datasets, + targets=self.targets, + max_target_durations=self.max_target_durations, + shuffle=True, + ) + + def build_dataset_for_inference(self, src_tokens, src_lengths, **kwargs): + """ + Generate batches for inference. We prepend an eos token to src_tokens + (or bos if `--add-bos-token` is set) and we append a <pad> to target. + This is convenient both for generation with a prefix and LM scoring. + """ + src_datasets = {} + tgt_datasets = {} + for channel in src_tokens[0]: + dataset = StripTokenDataset( + TokenBlockDataset( + [src_tokens[i][channel] for i in range(len(src_tokens))], + src_lengths, + block_size=None, # ignored for "eos" break mode + pad=self.source_dictionaries[channel].pad(), + eos=self.source_dictionaries[channel].eos(), + break_mode="eos", + ), + # remove eos from (end of) target sequence + self.source_dictionaries[channel].eos(), + ) + src_dataset = PrependTokenDataset( + dataset, + token=( + self.source_dictionaries[channel].bos() + if getattr(self.args, "add_bos_token", False) + else self.source_dictionaries[channel].eos() + ), + ) + tgt_dataset = AppendTokenDataset( + dataset, token=self.source_dictionaries[channel].pad() + ) + + src_datasets[channel] = src_dataset + tgt_datasets[channel] = tgt_dataset + + return NestedDictionaryDataset( + { + "id": IdDataset(), + "net_input": { + "src_tokens": OrderedDict( + [ + ( + channel, + PadDataset( + src_datasets[channel], + pad_idx=self.source_dictionaries[channel].pad(), + left_pad=False, + ), + ) + for channel in src_datasets + ] + ), + "src_lengths": NumelDataset( + next(iter(src_datasets.values())), reduce=False + ), + }, + "target": OrderedDict( + [ + ( + channel, + PadDataset( + tgt_datasets[channel], + pad_idx=self.source_dictionaries[channel].pad(), + left_pad=False, + ), + ) + for channel in tgt_datasets + ] + ), + }, + sizes=[np.array(src_lengths)], + ) + + def inference_step( + self, generator, models, sample, prefix_tokens=None, constraints=None + ): + with torch.no_grad(): + # Generation will always be conditioned on bos_token + if getattr(self.args, "add_bos_token", False): + bos_token = self.source_dictionary.bos() + else: + bos_token = self.source_dictionary.eos() + + if constraints is not None: + raise NotImplementedError( + "Constrained decoding with the SpeechDLM task is not supported" + ) + # SequenceGenerator doesn't use src_tokens directly, we need to + # pass the `prefix_tokens` argument instead + if prefix_tokens is None: + prefix_tokens = {} + for channel in sample["net_input"]["src_tokens"]: + if sample["net_input"]["src_tokens"][channel].nelement(): + prefix_tokens_channel = sample["net_input"]["src_tokens"][ + channel + ] + if prefix_tokens_channel[:, 0].eq(bos_token).all(): + prefix_tokens_channel = prefix_tokens_channel[:, 1:] + prefix_tokens[channel] = prefix_tokens_channel + else: + prefix_tokens = None + break + return generator.generate( + models, sample, prefix_tokens=prefix_tokens, bos_token=bos_token + ) + + def eval_lm_dataloader( + self, + dataset, + max_tokens: Optional[int] = 36000, + batch_size: Optional[int] = None, + max_positions: Optional[int] = None, + num_shards: int = 1, + shard_id: int = 0, + num_workers: int = 1, + data_buffer_size: int = 10, + # ensures that every evaluated token has access to a context of at least + # this size, if possible + context_window: int = 0, + ): + if context_window > 0: + dataset = LMContextWindowDataset( + dataset=dataset, + tokens_per_sample=self.args.tokens_per_sample, + context_window=context_window, + pad_idx=self.source_dictionary.pad(), + ) + return self.get_batch_iterator( + dataset=dataset, + max_tokens=max_tokens, + max_sentences=batch_size, + max_positions=max_positions, + ignore_invalid_inputs=True, + num_shards=num_shards, + shard_id=shard_id, + num_workers=num_workers, + data_buffer_size=data_buffer_size, + ).next_epoch_itr(shuffle=False) + + @property + def source_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.dicts[self.channels[0]] + + @property + def target_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.output_dicts[self.channels[0]] + + @property + def source_dictionaries(self): + """Return the dict of :class:`~fairseq.data.Dictionary` for the + multichannel language model.""" + return self.dicts + + @property + def target_dictionaries(self): + """Return the dict of :class:`~fairseq.data.Dictionary` for the + multichannel language model.""" + return self.output_dicts + + def build_generator(self, models, args, extra_gen_cls_kwargs=None): + + from fairseq.models.speech_dlm.sequence_generator import ( + multichannel_search, + MultichannelSequenceGenerator, + ) + + # Choose search strategy. Defaults to Beam Search. + sampling = getattr(args, "sampling", False) + sampling_topk = getattr(args, "sampling_topk", -1) + sampling_topp = getattr(args, "sampling_topp", -1.0) + assert ( + sampling_topk < 0 or sampling + ), "--sampling-topk requires sampling (not beam search)" + assert ( + sampling_topp < 0 or sampling + ), "--sampling-topp requires sampling (not beam search)" + + if sampling: + search_strategy = multichannel_search.ContiguousMultichannelSampling( + self.target_dictionaries, sampling_topk, sampling_topp + ) + else: + search_strategy = multichannel_search.ContiguousMultichannelBeamSearch( + self.target_dictionaries + ) + + extra_gen_cls_kwargs = extra_gen_cls_kwargs or {} + + return MultichannelSequenceGenerator( + models, + self.target_dictionaries, + beam_size=getattr(args, "beam", 5), + max_len_a=getattr(args, "max_len_a", 0), + max_len_b=getattr(args, "max_len_b", 500), + min_len=getattr(args, "min_len", 1), + normalize_scores=(not getattr(args, "unnormalized", False)), + len_penalty=getattr(args, "lenpen", 1), + unk_penalty=getattr(args, "unkpen", 0), + temperature=getattr(args, "temperature", 1.0), + match_source_len=getattr(args, "match_source_len", False), + no_repeat_ngram_size=getattr(args, "no_repeat_ngram_size", 0), + search_strategy=search_strategy, + duration_temperature=getattr(args, "duration_temperature", 1.0), + **extra_gen_cls_kwargs, + ) From 83c4e49e9dff7ce438e544069706be8e87c81ef4 Mon Sep 17 00:00:00 2001 From: Pierre Andrews <mortimer@fb.com> Date: Thu, 2 Feb 2023 11:04:53 -0500 Subject: [PATCH 728/774] wav2vec2_laser (#4968) --- fairseq/models/wav2vec/__init__.py | 1 + fairseq/models/wav2vec/wav2vec2_laser.py | 39 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100755 fairseq/models/wav2vec/wav2vec2_laser.py diff --git a/fairseq/models/wav2vec/__init__.py b/fairseq/models/wav2vec/__init__.py index 06cec18183..bacbb7a95d 100644 --- a/fairseq/models/wav2vec/__init__.py +++ b/fairseq/models/wav2vec/__init__.py @@ -6,3 +6,4 @@ from .wav2vec import * # noqa from .wav2vec2 import * # noqa from .wav2vec2_asr import * # noqa +from .wav2vec2_laser import * # noqa diff --git a/fairseq/models/wav2vec/wav2vec2_laser.py b/fairseq/models/wav2vec/wav2vec2_laser.py new file mode 100755 index 0000000000..ff89759d38 --- /dev/null +++ b/fairseq/models/wav2vec/wav2vec2_laser.py @@ -0,0 +1,39 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from fairseq.models import BaseFairseqModel, register_model +from fairseq.models.wav2vec.wav2vec2_asr import ( + Wav2Vec2CtcConfig, + Wav2VecCtc, + Wav2VecEncoder, +) +from fairseq.tasks import FairseqTask + + +@register_model("wav2vec2_laser", dataclass=Wav2Vec2CtcConfig) +class Wav2VecLaser(Wav2VecCtc): + def __init__(self, cfg: Wav2Vec2CtcConfig, w2v_encoder: BaseFairseqModel): + super().__init__(cfg, w2v_encoder) + self.num_updates = 0 + self.freeze_finetune_updates = cfg.freeze_finetune_updates + + @classmethod + def build_model(cls, cfg: Wav2Vec2CtcConfig, task: FairseqTask): + """Build a new model instance.""" + w2v_encoder = Wav2VecEncoder(cfg, 1024) + return cls(cfg, w2v_encoder) + + def forward(self, **kwargs): + output = super().forward(**kwargs) + x_out = output["encoder_out"] * 0.01 + out_pad_mask = output["padding_mask"] + # Set padded outputs to -inf so they are not selected by max-pooling + if out_pad_mask is not None and out_pad_mask.any(): + x_out = ( + x_out.float() + .masked_fill_(out_pad_mask.T.unsqueeze(-1), float("-inf")) + .type_as(x_out) + ) + return x_out.max(dim=0)[0] From 214c0cbd6f6a31303fe1820a13bc24842c0af283 Mon Sep 17 00:00:00 2001 From: Ilia Kulikov <kulikov@cs.nyu.edu> Date: Thu, 2 Feb 2023 15:11:56 -0800 Subject: [PATCH 729/774] ASR BLEU tool copied from ust branch into main (#4914) --- examples/speech_to_speech/asr_bleu/README.md | 34 ++ .../speech_to_speech/asr_bleu/__init__.py | 0 .../asr_bleu/asr_model_cfgs.json | 198 ++++++++++++ .../asr_bleu/compute_asr_bleu.py | 229 +++++++++++++ .../asr_bleu/requirements.txt | 7 + examples/speech_to_speech/asr_bleu/utils.py | 306 ++++++++++++++++++ 6 files changed, 774 insertions(+) create mode 100644 examples/speech_to_speech/asr_bleu/README.md create mode 100644 examples/speech_to_speech/asr_bleu/__init__.py create mode 100644 examples/speech_to_speech/asr_bleu/asr_model_cfgs.json create mode 100644 examples/speech_to_speech/asr_bleu/compute_asr_bleu.py create mode 100644 examples/speech_to_speech/asr_bleu/requirements.txt create mode 100644 examples/speech_to_speech/asr_bleu/utils.py diff --git a/examples/speech_to_speech/asr_bleu/README.md b/examples/speech_to_speech/asr_bleu/README.md new file mode 100644 index 0000000000..b808b136dc --- /dev/null +++ b/examples/speech_to_speech/asr_bleu/README.md @@ -0,0 +1,34 @@ +# ASR-BLEU evaluation toolkit + +This toolkit provides a set of public ASR models used for evaluation of different speech-to-speech translation systems at Meta AI. It enables easier score comparisons between different system's outputs. + +The ASRGenerator wraps different CTC-based ASR models from HuggingFace and fairseq code bases. Torchaudio CTC decoder is built on top of it to decode given audio files. + +Please see `asr_model_cfgs.json` for a list of languages covered currently. + +The high-level pipeline is simple by design: given a lang tag, script loads the ASR model, transcribes model's predicted audio, and computes the BLEU score against provided reference translations using sacrebleu. + +# Dependencies + +Please see `requirements.txt`. + +# Usage examples + +This toolkit have been used with: + +* Speechmatrix project: https://github.com/facebookresearch/fairseq/tree/ust/examples/speech_matrix. + +* Hokkien speech-to-speech translation project: https://github.com/facebookresearch/fairseq/tree/ust/examples/hokkien. + +# Standalone run example + +High-level example, please substitute arguments per your case: + +```bash +python compute_asr_bleu.py --lang <LANG> \ +--audio_dirpath <PATH_TO_AUDIO_DIR> \ +--reference_path <PATH_TO_REFERENCES_FILE> \ +--reference_format txt +``` + +For more details about arguments please see the script argparser help. \ No newline at end of file diff --git a/examples/speech_to_speech/asr_bleu/__init__.py b/examples/speech_to_speech/asr_bleu/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/speech_to_speech/asr_bleu/asr_model_cfgs.json b/examples/speech_to_speech/asr_bleu/asr_model_cfgs.json new file mode 100644 index 0000000000..d0a5f3e3aa --- /dev/null +++ b/examples/speech_to_speech/asr_bleu/asr_model_cfgs.json @@ -0,0 +1,198 @@ +{ + "en": { + "oct22": { + "desc": "Wav2Vec 2.0 Large (LV-60) + Self Training from https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec#pre-trained-models", + "ckpt_path": "https://dl.fbaipublicfiles.com/fairseq/wav2vec/wav2vec_vox_960h_pl.pt", + "dict_path": "https://dl.fbaipublicfiles.com/fairseq/wav2vec/dict.ltr.txt", + "model_type": "fairseq", + "lang": "en", + "post_process": "collapse" + } + }, + "hok": { + "oct22": { + "desc": "Hokkien ASR model, for details check [TODO add paper link]", + "ckpt_path": "https://dl.fbaipublicfiles.com/ust_asr/hok/checkpoint_best.pt", + "dict_path": "https://dl.fbaipublicfiles.com/ust_asr/hok/dict.ltr.txt", + "model_type": "fairseq", + "lang": "hok", + "post_process": "none" + } + }, + "es": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-large-xlsr-53-spanish", + "model_type": "hf", + "lang": "es", + "post_process": "collapse" + } + }, + "fr": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-large-fr-voxpopuli-french", + "model_type": "hf", + "lang": "fr", + "post_process": "collapse" + } + }, + "zh": { + "oct22": { + "model_path": "ydshieh/wav2vec2-large-xlsr-53-chinese-zh-cn-gpt", + "model_type": "hf", + "lang": "zh", + "post_process": "collapse" + } + }, + "tr": { + "oct22": { + "model_path": "cahya/wav2vec2-large-xlsr-turkish-artificial-cv", + "model_type": "hf", + "lang": "tr", + "post_process": "collapse" + } + }, + "ar": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-large-xlsr-53-arabic", + "model_type": "hf", + "lang": "ar", + "post_process": "collapse" + } + }, + "vi": { + "oct22": { + "model_path": "not-tanh/wav2vec2-large-xlsr-53-vietnamese", + "model_type": "hf", + "lang": "vi", + "post_process": "collapse" + } + }, + "de": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-xls-r-1b-german", + "model_type": "hf", + "lang": "de", + "post_process": "collapse" + } + }, + "pl": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-xls-r-1b-polish", + "model_type": "hf", + "lang": "pl", + "post_process": "collapse" + } + }, + "it": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-large-xlsr-53-italian", + "model_type": "hf", + "lang": "it", + "post_process": "collapse" + } + }, + "pt": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-xls-r-1b-portuguese", + "model_type": "hf", + "lang": "pt", + "post_process": "collapse" + } + }, + "ro": { + "oct22": { + "model_path": "gigant/romanian-wav2vec2", + "model_type": "hf", + "lang": "ro", + "post_process": "collapse" + } + }, + "cs": { + "oct22": { + "model_path": "comodoro/wav2vec2-xls-r-300m-cs-250", + "model_type": "hf", + "lang": "cs", + "post_process": "collapse" + } + }, + "sk": { + "oct22": { + "model_path": "anuragshas/wav2vec2-xls-r-300m-sk-cv8-with-lm", + "model_type": "hf", + "lang": "sk", + "post_process": "collapse" + } + }, + "sl": { + "oct22": { + "model_path": "anuragshas/wav2vec2-xls-r-300m-sl-cv8-with-lm", + "model_type": "hf", + "lang": "sl", + "post_process": "collapse" + } + }, + "fi": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-large-xlsr-53-finnish", + "model_type": "hf", + "lang": "fi", + "post_process": "collapse" + } + }, + "hu": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-large-xlsr-53-hungarian", + "model_type": "hf", + "lang": "hu", + "post_process": "collapse" + } + }, + "et": { + "oct22": { + "model_path": "RASMUS/wav2vec2-xlsr-1b-et", + "model_type": "hf", + "lang": "et", + "post_process": "collapse" + } + }, + "lt": { + "oct22": { + "model_path": "sammy786/wav2vec2-xlsr-lithuanian", + "model_type": "hf", + "lang": "lt", + "post_process": "collapse" + } + }, + "nl": { + "oct22": { + "model_path": "jonatasgrosman/wav2vec2-xls-r-1b-dutch", + "model_type": "hf", + "lang": "nl", + "post_process": "collapse" + } + }, + "lv": { + "oct22": { + "model_path": "reach-vb/wav2vec2-large-xls-r-1B-common_voice7-lv-ft", + "model_type": "hf", + "lang": "lv", + "post_process": "collapse" + } + }, + "sv": { + "oct22": { + "model_path": "marinone94/xls-r-300m-sv-robust", + "model_type": "hf", + "lang": "sv", + "post_process": "collapse" + } + }, + "hr": { + "oct22": { + "model_path": "classla/wav2vec2-xls-r-parlaspeech-hr", + "model_type": "hf", + "lang": "hr", + "post_process": "collapse" + } + } +} diff --git a/examples/speech_to_speech/asr_bleu/compute_asr_bleu.py b/examples/speech_to_speech/asr_bleu/compute_asr_bleu.py new file mode 100644 index 0000000000..6aa1e87aee --- /dev/null +++ b/examples/speech_to_speech/asr_bleu/compute_asr_bleu.py @@ -0,0 +1,229 @@ +from typing import Dict, List +import sacrebleu +import pandas as pd +from glob import glob +from pathlib import Path +from utils import retrieve_asr_config, ASRGenerator +from tqdm import tqdm +from argparse import ArgumentParser + + +def merge_tailo_init_final(text): + """ + Hokkien ASR hypothesis post-processing. + """ + sps = text.strip().split() + results = [] + last_syllable = "" + for sp in sps: + if sp == "NULLINIT" or sp == "nullinit": + continue + last_syllable += sp + if sp[-1].isnumeric(): + results.append(last_syllable) + last_syllable = "" + if last_syllable != "": + results.append(last_syllable) + return " ".join(results) + + +def remove_tone(text): + """ + Used for tone-less evaluation of Hokkien + """ + return " ".join([t[:-1] for t in text.split()]) + + +def extract_audio_for_eval(audio_dirpath: str, audio_format: str): + if audio_format == "n_pred.wav": + """ + The assumption here is that pred_0.wav corresponds to the reference at line position 0 from the reference manifest + """ + audio_list = [] + audio_fp_list = glob((Path(audio_dirpath) / "*_pred.wav").as_posix()) + for i in range(len(audio_fp_list)): + try: + audio_fp = (Path(audio_dirpath) / f"{i}_pred.wav").as_posix() + assert ( + audio_fp in audio_fp_list + ), f"{Path(audio_fp).name} does not exist in {audio_dirpath}" + except AssertionError: + # check the audio with random speaker + audio_fp = Path(audio_dirpath) / f"{i}_spk*_pred.wav" + audio_fp = glob( + audio_fp.as_posix() + ) # resolve audio filepath with random speaker + assert len(audio_fp) == 1 + audio_fp = audio_fp[0] + + audio_list.append(audio_fp) + else: + raise NotImplementedError + + return audio_list + + +def extract_text_for_eval( + references_filepath: str, reference_format: str, reference_tsv_column: str = None +): + if reference_format == "txt": + reference_sentences = open(references_filepath, "r").readlines() + reference_sentences = [l.strip() for l in reference_sentences] + elif reference_format == "tsv": + tsv_df = pd.read_csv(references_filepath, sep="\t", quoting=3) + reference_sentences = tsv_df[reference_tsv_column].to_list() + reference_sentences = [l.strip() for l in reference_sentences] + else: + raise NotImplementedError + + return reference_sentences + + +def compose_eval_data( + audio_dirpath: str, + audio_format: str, + references_filepath: str, + reference_format: str, + reference_tsv_column: str = None, + save_manifest_filepath=None, +): + """ + Speech matrix decoding pipeline produces audio with the following mask "N_pred.wav" where N is the order of the corresponding input sample + """ + + reference_sentences = extract_text_for_eval( + references_filepath, reference_format, reference_tsv_column + ) + predicted_audio_fp_list = extract_audio_for_eval(audio_dirpath, audio_format) + assert len(predicted_audio_fp_list) == len(reference_sentences) + + audio_text_pairs = [ + (audio, reference) + for audio, reference in zip(predicted_audio_fp_list, reference_sentences) + ] + + tsv_manifest = pd.DataFrame(audio_text_pairs, columns=["prediction", "reference"]) + + if save_manifest_filepath is not None: + tsv_manifest.to_csv(save_manifest_filepath, sep="\t", quoting=3) + + return tsv_manifest + + +def load_eval_data_from_tsv(eval_data_filepath: str): + """ + We may load the result of `compose_eval_data` directly if needed + """ + eval_df = pd.from_csv(eval_data_filepath, sep="\t") + + return eval_df + + +def run_asr_bleu(args): + + asr_config = retrieve_asr_config( + args.lang, args.asr_version, json_path="./asr_model_cfgs.json" + ) + asr_model = ASRGenerator(asr_config) + + eval_manifest = compose_eval_data( + audio_dirpath=args.audio_dirpath, + audio_format=args.audio_format, + references_filepath=args.reference_path, + reference_format=args.reference_format, + reference_tsv_column=args.reference_tsv_column, + save_manifest_filepath=None, + ) + + prediction_transcripts = [] + for _, eval_pair in tqdm( + eval_manifest.iterrows(), + desc="Transcribing predictions", + total=len(eval_manifest), + ): + transcription = asr_model.transcribe_audiofile(eval_pair.prediction) + prediction_transcripts.append(transcription.lower()) + + if args.lang == "hok": + prediction_transcripts = [ + merge_tailo_init_final(text) for text in prediction_transcripts + ] + + references = eval_manifest["reference"].tolist() + bleu_score = sacrebleu.corpus_bleu(prediction_transcripts, [references]) + + print(bleu_score) + + return bleu_score + + +def main(): + parser = ArgumentParser( + description="This script computes the ASR-BLEU metric between model's generated audio and the text reference sequences." + ) + + parser.add_argument( + "--lang", + help="The target language used to initialize ASR model, see asr_model_cfgs.json for available languages", + type=str, + ) + parser.add_argument( + "--asr_version", + type=str, + default="oct22", + help="For future support we add and extra layer of asr versions. The current most recent version is oct22 meaning October 2022", + ) + parser.add_argument( + "--audio_dirpath", + type=str, + help="Path to the directory containing the audio predictions from the translation model", + ) + parser.add_argument( + "--reference_path", + type=str, + help="Path to the file containing reference translations in the form of normalized text (to be compared to ASR predictions", + ) + parser.add_argument( + "--reference_format", + choices=["txt", "tsv"], + help="Format of reference file. Txt means plain text format where each line represents single reference sequence", + ) + parser.add_argument( + "--reference_tsv_column", + default=None, + type=str, + help="If format is tsv, then specify the column name which contains reference sequence", + ) + parser.add_argument( + "--audio_format", + default="n_pred.wav", + choices=["n_pred.wav"], + help="Audio format n_pred.wav corresponds to names like 94_pred.wav or 94_spk7_pred.wav where spk7 is the speaker id", + ) + parser.add_argument( + "--results_dirpath", + default=None, + type=str, + help="If specified, the resulting BLEU score will be written to this file path as txt file", + ) + + args = parser.parse_args() + + bleu_score = run_asr_bleu(args) + result_filename = f"{args.reference_format}_{args.lang}_bleu.txt" + if args.results_dirpath is not None: + if not Path(args.results_dirpath).exists(): + Path(args.results_dirpath).mkdir(parents=True) + with open(Path(args.results_dirpath) / result_filename, "w") as f: + f.write(bleu_score.format(width=2)) + + +if __name__ == "__main__": + main() + + +""" +Example to load Sl audio and references, compute BLEU: + +export lang=fi; split=vp && python compute_asr_bleu.py --lang $lang --audio_dirpath /checkpoint/hygong/S2S/speech_matrix_release_ckpts/generated_waveform_release/en-$lang/test_$split/checkpoint.pt --audio_format n_pred.wav --reference_path /large_experiments/ust/hygong/S2S/SpeechEncoder/manifests/vp-vp/en-$lang/test_$split.$lang --reference_format txt --results_dirpath ./ +""" diff --git a/examples/speech_to_speech/asr_bleu/requirements.txt b/examples/speech_to_speech/asr_bleu/requirements.txt new file mode 100644 index 0000000000..cfa90f6aef --- /dev/null +++ b/examples/speech_to_speech/asr_bleu/requirements.txt @@ -0,0 +1,7 @@ +fairseq==0.12.2 +pandas==1.4.3 +sacrebleu==2.2.0 +torch==1.12.1 +torchaudio==0.12.1 +tqdm==4.64.0 +transformers==4.21.1 diff --git a/examples/speech_to_speech/asr_bleu/utils.py b/examples/speech_to_speech/asr_bleu/utils.py new file mode 100644 index 0000000000..0fed55a9b9 --- /dev/null +++ b/examples/speech_to_speech/asr_bleu/utils.py @@ -0,0 +1,306 @@ +import json +import re +import urllib.request +from pathlib import Path + +import fairseq +import torch +from fairseq.data.data_utils import lengths_to_padding_mask +from tqdm import tqdm + +try: + import torchaudio + from torchaudio.models.decoder import ctc_decoder +except ImportError: + raise ImportError("Upgrade torchaudio to 0.12 to enable CTC decoding") + + +class DownloadProgressBar(tqdm): + """A class to represent a download progress bar""" + + def update_to(self, b=1, bsize=1, tsize=None) -> None: + """ + Update the download progress + """ + if tsize is not None: + self.total = tsize + self.update(b * bsize - self.n) + + +def retrieve_asr_config(lang_key: str, asr_version: str, json_path: str) -> dict: + """ + Retrieve the asr model configs + + Args: + lang_key: the lanuage type as the key name + json_path: the path of the config json file + + Returns: + Dict of all the configs in the json file + """ + + with open(json_path, "r") as f: + asr_model_cfgs = json.load(f) + return asr_model_cfgs[lang_key][asr_version] + + +class ASRGenerator(object): + """A class to represent a ASR generator""" + + def __init__( + self, + model_cfg: dict, + cache_dirpath: str = (Path.home() / ".cache" / "ust_asr").as_posix(), + ) -> None: + """ + Construct all the necessary attributes of the ASRGenerator class + + Args: + model_cfg: the dict of the asr model config + cache_dirpath: the default cache path is "Path.home()/.cache/ust_asr" + """ + + self.cache_dirpath = Path(cache_dirpath) / model_cfg["lang"] + self.model_cfg = model_cfg + + self.use_cuda = torch.cuda.is_available() + + torchaudio.set_audio_backend("sox_io") + + if self.model_cfg["model_type"] == "hf": + self.prepare_hf_model(self.model_cfg) + elif self.model_cfg["model_type"] == "fairseq": + self.prepare_fairseq_model(self.model_cfg) + else: + raise NotImplementedError( + f"Model type {self.model_cfg['model_type']} is not supported" + ) + + if self.model_cfg["post_process"] == "collapse": + self.post_process_fn = lambda hypo: "".join(hypo).replace( + self.sil_token, " " + ) + elif self.model_cfg["post_process"] == "none": + self.post_process_fn = lambda hypo: " ".join(hypo).replace( + self.sil_token, " " + ) + else: + raise NotImplementedError + + if self.use_cuda: + self.model.cuda() + self.model.eval() + + self.decoder = ctc_decoder( + lexicon=None, + tokens=self.tokens, + lm=None, + nbest=1, + beam_size=1, + beam_size_token=None, + lm_weight=0.0, + word_score=0.0, + unk_score=float("-inf"), + sil_token=self.sil_token, + sil_score=0.0, + log_add=False, + blank_token=self.blank_token, + ) + + def prepare_hf_model(self, model_cfg: dict) -> None: + """ + Prepare the huggingface asr model + + Args: + model_cfg: dict with the relevant ASR config + """ + + def infer_silence_token(vocab: list): + """ + Different HF checkpoints have different notion of silence token + such as | or " " (space) + Important: when adding new HF asr model in, check what silence token it uses + """ + if "|" in vocab: + return "|" + elif " " in vocab: + return " " + else: + raise RuntimeError("Silence token is not found in the vocabulary") + + try: + from transformers import (AutoFeatureExtractor, AutoTokenizer, + Wav2Vec2ForCTC, Wav2Vec2Processor) + except ImportError: + raise ImportError("Install transformers to load HF wav2vec model") + + model_path = model_cfg["model_path"] + self.model = Wav2Vec2ForCTC.from_pretrained(model_path) + self.tokenizer = AutoTokenizer.from_pretrained(model_path) + self.preprocessor = AutoFeatureExtractor.from_pretrained(model_path) + self.processor = Wav2Vec2Processor.from_pretrained(model_path) + + # extra unk tokens are there to make some models work e.g. Finnish ASR has some vocab issue + vocab_list = [ + self.tokenizer.decoder.get(i, f"{self.tokenizer.unk_token}1") + for i in range(self.tokenizer.vocab_size) + ] + + self.sampling_rate = self.preprocessor.sampling_rate + self.normalize_input = self.preprocessor.do_normalize + self.tokens = vocab_list + self.sil_token = infer_silence_token(vocab_list) + self.blank_token = self.tokenizer.pad_token + + def prepare_fairseq_model(self, model_cfg: dict) -> None: + """ + Prepare the fairseq asr model + + Args: + model_cfg: the specific model config dict must have: (1) ckpt_path, (2) dict_path + """ + + def download_file(url: str, cache_dir: Path): + download_path = cache_dir / url.split("/")[-1] + if not (cache_dir / url.split("/")[-1]).exists(): + with DownloadProgressBar( + unit="B", unit_scale=True, miniters=1, desc=url.split("/")[-1] + ) as t: + cache_dir.mkdir(parents=True, exist_ok=True) + urllib.request.urlretrieve( + url, filename=download_path.as_posix(), reporthook=t.update_to + ) + else: + print(f"'{url}' exists in {cache_dir}") + + return download_path.as_posix() + + try: + ckpt_path = model_cfg["ckpt_path"] + dict_path = model_cfg["dict_path"] + except KeyError: + raise KeyError( + "Fairseq model cfg must provide (1) ckpt_path, (2) dict_path" + ) + + if re.search("^https", ckpt_path): + ckpt_path = download_file(ckpt_path, self.cache_dirpath) + if re.search("^https", dict_path): + dict_path = download_file(dict_path, self.cache_dirpath) + + model, saved_cfg, _ = fairseq.checkpoint_utils.load_model_ensemble_and_task( + [ckpt_path], + arg_overrides={ + "task": "audio_finetuning", + "data": self.cache_dirpath.as_posix(), + }, # data must have dict in it + ) + + dict_lines = open(dict_path, "r").readlines() + tokens = [l.split()[0] for l in dict_lines] + # adding default fairseq special tokens + tokens = ["<s>", "<pad>", "</s>", "<unk>"] + tokens + + self.model = model[0] + self.tokens = tokens + + if "|" in tokens: + self.sil_token = "|" + else: + self.sil_token = tokens[ + 2 + ] # use eos as silence token if | not presented e.g., Hok ASR model + print(f"Inferring silence token from the dict: {self.sil_token}") + self.blank_token = self.tokens[0] + + self.sampling_rate = saved_cfg.task.sample_rate + self.normalize_input = saved_cfg.task.normalize + + @torch.inference_mode() + def load_audiofile(self, audio_path: str) -> torch.Tensor: + """ + Load the audio files and apply resampling and normalizaion + + Args: + audio_path: the audio file path + + Returns: + audio_waveform: the audio waveform as a torch.Tensor object + """ + + audio_waveform, sampling_rate = torchaudio.load(audio_path) + if audio_waveform.dim == 2: + audio_waveform = audio_waveform.mean(-1) + if self.sampling_rate != sampling_rate: + audio_waveform = torchaudio.functional.resample( + audio_waveform, sampling_rate, self.sampling_rate + ) + if self.normalize_input: + # following fairseq raw audio dataset + audio_waveform = torch.nn.functional.layer_norm( + audio_waveform, audio_waveform.shape + ) + + return audio_waveform + + @torch.inference_mode() + def compute_emissions(self, audio_input: torch.Tensor) -> torch.Tensor: + """ + Compute the emissions for either fairseq or huggingface asr model + + Args: + audio_path: the input audio waveform + + Returns: + emissions: the logits of the encoded prediction. + """ + + if self.use_cuda: + audio_input = audio_input.to("cuda") + if isinstance(self.model, fairseq.models.wav2vec.wav2vec2_asr.Wav2VecCtc): + padding_mask = lengths_to_padding_mask(torch.tensor([audio_input.numel()])) + emissions = self.model.w2v_encoder(audio_input, padding_mask)[ + "encoder_out" + ].transpose(0, 1) + else: + emissions = self.model(audio_input).logits + + return emissions + + def decode_emissions(self, emissions: torch.Tensor) -> str: + """ + Decode the emissions and apply post process functions + + Args: + emissions: the input Tensor object + + Returns: + hypo: the str as the decoded transcriptions + """ + + emissions = emissions.cpu() + results = self.decoder(emissions) + + # assuming the lexicon-free decoder and working with tokens + hypo = self.decoder.idxs_to_tokens(results[0][0].tokens) + hypo = self.post_process_fn(hypo) + + return hypo + + def transcribe_audiofile(self, audio_path: str, lower=True) -> str: + """ + Transcribe the audio into string + + Args: + audio_path: the input audio waveform + lower: the case of the transcriptions with lowercase as the default + + Returns: + hypo: the transcription result + """ + + asr_input = self.load_audiofile(audio_path) + emissions = self.compute_emissions(asr_input) + hypo = self.decode_emissions(emissions) + + return hypo.strip().lower() if lower else hypo.strip() From ad0e69cd99e1ff884041fbd8467d1404bd09847a Mon Sep 17 00:00:00 2001 From: Xutai Ma <xutaima@gmail.com> Date: Wed, 8 Feb 2023 23:16:22 -0500 Subject: [PATCH 730/774] Add transcript option for asr-bleu (#4981) --- .../asr_bleu/compute_asr_bleu.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/examples/speech_to_speech/asr_bleu/compute_asr_bleu.py b/examples/speech_to_speech/asr_bleu/compute_asr_bleu.py index 6aa1e87aee..d5926194c1 100644 --- a/examples/speech_to_speech/asr_bleu/compute_asr_bleu.py +++ b/examples/speech_to_speech/asr_bleu/compute_asr_bleu.py @@ -1,3 +1,4 @@ +import os from typing import Dict, List import sacrebleu import pandas as pd @@ -37,10 +38,13 @@ def remove_tone(text): def extract_audio_for_eval(audio_dirpath: str, audio_format: str): if audio_format == "n_pred.wav": """ - The assumption here is that pred_0.wav corresponds to the reference at line position 0 from the reference manifest + The assumption here is that 0_pred.wav corresponds to the reference at line position 0 from the reference manifest """ audio_list = [] audio_fp_list = glob((Path(audio_dirpath) / "*_pred.wav").as_posix()) + audio_fp_list = sorted( + audio_fp_list, key=lambda x: int(os.path.basename(x).split("_")[0]) + ) for i in range(len(audio_fp_list)): try: audio_fp = (Path(audio_dirpath) / f"{i}_pred.wav").as_posix() @@ -154,7 +158,7 @@ def run_asr_bleu(args): print(bleu_score) - return bleu_score + return prediction_transcripts, bleu_score def main(): @@ -206,10 +210,16 @@ def main(): type=str, help="If specified, the resulting BLEU score will be written to this file path as txt file", ) + parser.add_argument( + "--transcripts_path", + default=None, + type=str, + help="If specified, the predicted transcripts will be written to this path as a txt file.", + ) args = parser.parse_args() - bleu_score = run_asr_bleu(args) + prediction_transcripts, bleu_score = run_asr_bleu(args) result_filename = f"{args.reference_format}_{args.lang}_bleu.txt" if args.results_dirpath is not None: if not Path(args.results_dirpath).exists(): @@ -217,6 +227,11 @@ def main(): with open(Path(args.results_dirpath) / result_filename, "w") as f: f.write(bleu_score.format(width=2)) + if args.transcripts_path is not None: + with open(args.transcripts_path, "w") as f: + for transcript in prediction_transcripts: + f.write(transcript + "\n") + if __name__ == "__main__": main() From 0338cdc3094ca7d29ff4d36d64791f7b4e4b5e6e Mon Sep 17 00:00:00 2001 From: Franz Nowak <franz.g.nowak@gmail.com> Date: Thu, 23 Feb 2023 22:18:36 +0100 Subject: [PATCH 731/774] fix imports referencing moved metrics.py file (#4840) * fix imports referencing moved metrics.py file * Make representation computation branchless in TransformerEncoderBase (#4818) Summary: We want to make the computation branchless here because fairseq code may be exported and traced for deployment purposes, and tracing mechanisms can break the correctness for a captured program if it's dependent on input data. In this diff we try to rewrite the code to remove one branch so that tracer can proceed here and preserve the correct semantics of the model. Test Plan: CI Reviewers: Subscribers: Tasks: Tags: * Fix Torchscript typing in transformer_encoder.py (#4847) * Add Generative Spoken Dialogue Language Modeling (#4879) * Update deprecated torch.qr in glow.py example (#4685) torch.qr is deprecated for a long time and is being removed by https://github.com/pytorch/pytorch/pull/70989. This PR makes the example compatible with new and old PyTorch versions. * Emotion Conversion Paper Open Source (#4895) * data2vec v2.0 (#4903) data2v2c 2.0 Co-authored-by: Arun Babu <arbabu@fb.com> Co-authored-by: Wei-Ning Hsu <wnhsu@csail.mit.edu> * remove missing config entries when loading task from checkpoint (#4905) * make apex optional (#4906) * Add file to generate manifests for stop dataset. (#4891) * Update STOP dataset README to include proper link. (#4892) * Update README.md (#4893) * using foreach to reduce kernel (#4904) * using foreach to reduce kernel * set reproducibility to looser threshold * revert optimzer * update * update * update * update * update * update * update Co-authored-by: juntengjia <juntengjia@fb.com> * Update README.md to add data2vec blog post (#4913) * Update README.md * Update config to fix circleci failure (#4949) https://app.circleci.com/pipelines/github/fairinternal/fairseq-py/12635/workflows/3befbae2-79c4-458d-9fc4-aad4484183b4/jobs/26767 * Generative Spoken Dialogue Language Modeling Paper Open Source (#4957) * wav2vec2_laser (#4968) * ASR BLEU tool copied from ust branch into main (#4914) * Add transcript option for asr-bleu (#4981) --------- Co-authored-by: zhxchen17 <zhxchen17@outlook.com> Co-authored-by: zhxchen17 <zhxchen17@fb.com> Co-authored-by: Nguyen Tu Anh <nguyentuanh208@gmail.com> Co-authored-by: Sergii Dymchenko <kit1980@gmail.com> Co-authored-by: Felix Kreuk <felixkreuk@gmail.com> Co-authored-by: Alexei Baevski <alexei.b@gmail.com> Co-authored-by: padentomasello <pdtomasello@gmail.com> Co-authored-by: Junteng Jia <juntengjia@hotmail.com> Co-authored-by: juntengjia <juntengjia@fb.com> Co-authored-by: arbabu123 <arbabu@fb.com> Co-authored-by: dianaml0 <82468439+dianaml0@users.noreply.github.com> Co-authored-by: Pierre Andrews <mortimer@fb.com> Co-authored-by: Ilia Kulikov <kulikov@cs.nyu.edu> Co-authored-by: Xutai Ma <xutaima@gmail.com> --- examples/MMPT/mmpt/losses/fairseqmmloss.py | 2 +- examples/adaptive_span/adaptive_span_loss.py | 3 ++- .../criterions/discriminative_reranking_criterion.py | 3 ++- .../tasks/discriminative_reranking_task.py | 2 +- examples/rxf/rxf_src/label_smoothed_cross_entropy_r3f.py | 3 ++- .../criterions/multi_modality_compound.py | 3 ++- .../criterions/text_guide_cross_entropy_acc.py | 3 ++- .../translation_moe/translation_moe_src/translation_moe.py | 3 ++- fairseq/criterions/adaptive_loss.py | 3 ++- fairseq/criterions/cross_entropy.py | 3 ++- fairseq/criterions/ctc.py | 4 +++- fairseq/criterions/fairseq_criterion.py | 3 ++- fairseq/criterions/fastspeech2_loss.py | 3 ++- fairseq/criterions/hubert_criterion.py | 3 ++- fairseq/criterions/label_smoothed_cross_entropy.py | 3 ++- .../label_smoothed_cross_entropy_latency_augmented.py | 3 ++- .../criterions/label_smoothed_cross_entropy_with_alignment.py | 3 ++- fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py | 3 ++- fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py | 3 ++- fairseq/criterions/legacy_masked_lm.py | 3 ++- fairseq/criterions/masked_lm.py | 3 ++- fairseq/criterions/model_criterion.py | 3 ++- fairseq/criterions/nat_loss.py | 3 ++- fairseq/criterions/sentence_prediction.py | 2 +- fairseq/criterions/sentence_ranking.py | 3 ++- fairseq/criterions/speech_to_speech_criterion.py | 3 ++- fairseq/criterions/speech_ulm_criterion.py | 2 +- fairseq/criterions/tacotron2_loss.py | 3 ++- fairseq/criterions/wav2vec_criterion.py | 3 ++- .../model_parallel/criterions/vocab_parallel_cross_entropy.py | 3 ++- fairseq/tasks/fairseq_task.py | 3 ++- fairseq/tasks/multilingual_translation.py | 3 ++- fairseq/tasks/online_backtranslation.py | 3 ++- fairseq/tasks/translation.py | 3 ++- tests/test_metrics.py | 2 +- 35 files changed, 66 insertions(+), 35 deletions(-) diff --git a/examples/MMPT/mmpt/losses/fairseqmmloss.py b/examples/MMPT/mmpt/losses/fairseqmmloss.py index c0415d1077..a95e5ecf45 100644 --- a/examples/MMPT/mmpt/losses/fairseqmmloss.py +++ b/examples/MMPT/mmpt/losses/fairseqmmloss.py @@ -8,7 +8,7 @@ """ from fairseq.criterions import FairseqCriterion, register_criterion -from fairseq import metrics +from fairseq.logging import metrics @register_criterion("mmloss") diff --git a/examples/adaptive_span/adaptive_span_loss.py b/examples/adaptive_span/adaptive_span_loss.py index 056245807e..fe95b0d949 100644 --- a/examples/adaptive_span/adaptive_span_loss.py +++ b/examples/adaptive_span/adaptive_span_loss.py @@ -7,7 +7,8 @@ from dataclasses import dataclass import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import register_criterion from fairseq.criterions.cross_entropy import CrossEntropyCriterion from fairseq.dataclass import FairseqDataclass diff --git a/examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py b/examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py index 0b02ce1877..c8f19e3858 100644 --- a/examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py +++ b/examples/discriminative_reranking_nmt/criterions/discriminative_reranking_criterion.py @@ -9,7 +9,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import ChoiceEnum, FairseqDataclass diff --git a/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py b/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py index 223f8d4294..b4ed2a69aa 100644 --- a/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py +++ b/examples/discriminative_reranking_nmt/tasks/discriminative_reranking_task.py @@ -12,7 +12,7 @@ import numpy as np import torch -from fairseq import metrics +from fairseq.logging import metrics from fairseq.data import ( ConcatDataset, ConcatSentencesDataset, diff --git a/examples/rxf/rxf_src/label_smoothed_cross_entropy_r3f.py b/examples/rxf/rxf_src/label_smoothed_cross_entropy_r3f.py index 079db13e61..6191fd55ac 100644 --- a/examples/rxf/rxf_src/label_smoothed_cross_entropy_r3f.py +++ b/examples/rxf/rxf_src/label_smoothed_cross_entropy_r3f.py @@ -7,7 +7,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.criterions.label_smoothed_cross_entropy import label_smoothed_nll_loss diff --git a/examples/speech_text_joint_to_text/criterions/multi_modality_compound.py b/examples/speech_text_joint_to_text/criterions/multi_modality_compound.py index 292f6fdf48..b3a5506a2d 100644 --- a/examples/speech_text_joint_to_text/criterions/multi_modality_compound.py +++ b/examples/speech_text_joint_to_text/criterions/multi_modality_compound.py @@ -5,7 +5,8 @@ import math from dataclasses import dataclass, field -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.criterions.ctc import CtcCriterion, CtcCriterionConfig from fairseq.criterions.label_smoothed_cross_entropy import ( diff --git a/examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py b/examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py index 0d356e5a10..fd6ff155c9 100644 --- a/examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py +++ b/examples/speech_text_joint_to_text/criterions/text_guide_cross_entropy_acc.py @@ -6,9 +6,10 @@ import torch import torch.nn.functional as F +from fairseq import utils from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.criterions.label_smoothed_cross_entropy import label_smoothed_nll_loss -from fairseq import metrics, utils +from fairseq.logging import metrics @register_criterion("guided_label_smoothed_cross_entropy_with_accuracy") diff --git a/examples/translation_moe/translation_moe_src/translation_moe.py b/examples/translation_moe/translation_moe_src/translation_moe.py index 1ee9d1b727..a829bf7dcb 100644 --- a/examples/translation_moe/translation_moe_src/translation_moe.py +++ b/examples/translation_moe/translation_moe_src/translation_moe.py @@ -7,7 +7,8 @@ import torch from omegaconf import II -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.dataclass import ChoiceEnum from fairseq.tasks import register_task from fairseq.tasks.translation import TranslationConfig, TranslationTask diff --git a/fairseq/criterions/adaptive_loss.py b/fairseq/criterions/adaptive_loss.py index 6209ceaedb..fc1ac85404 100644 --- a/fairseq/criterions/adaptive_loss.py +++ b/fairseq/criterions/adaptive_loss.py @@ -7,7 +7,8 @@ from dataclasses import dataclass import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.constants import DDP_BACKEND_CHOICES diff --git a/fairseq/criterions/cross_entropy.py b/fairseq/criterions/cross_entropy.py index fe46106471..24d6bcd612 100644 --- a/fairseq/criterions/cross_entropy.py +++ b/fairseq/criterions/cross_entropy.py @@ -7,7 +7,8 @@ from dataclasses import dataclass import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from omegaconf import II diff --git a/fairseq/criterions/ctc.py b/fairseq/criterions/ctc.py index e55e928b4f..368213cb2b 100644 --- a/fairseq/criterions/ctc.py +++ b/fairseq/criterions/ctc.py @@ -12,7 +12,9 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils + +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.data.data_utils import post_process diff --git a/fairseq/criterions/fairseq_criterion.py b/fairseq/criterions/fairseq_criterion.py index ff4beb0250..0b1e64a8e3 100644 --- a/fairseq/criterions/fairseq_criterion.py +++ b/fairseq/criterions/fairseq_criterion.py @@ -6,7 +6,8 @@ import inspect from typing import Any, Dict, List -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import gen_parser_from_dataclass from torch.nn.modules.loss import _Loss diff --git a/fairseq/criterions/fastspeech2_loss.py b/fairseq/criterions/fastspeech2_loss.py index b317409e26..ab7cd08e3b 100644 --- a/fairseq/criterions/fastspeech2_loss.py +++ b/fairseq/criterions/fastspeech2_loss.py @@ -11,7 +11,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.data.data_utils import lengths_to_mask diff --git a/fairseq/criterions/hubert_criterion.py b/fairseq/criterions/hubert_criterion.py index 83b514aeef..262874b582 100644 --- a/fairseq/criterions/hubert_criterion.py +++ b/fairseq/criterions/hubert_criterion.py @@ -10,7 +10,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass diff --git a/fairseq/criterions/label_smoothed_cross_entropy.py b/fairseq/criterions/label_smoothed_cross_entropy.py index cb43be0ca5..325679bb16 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy.py +++ b/fairseq/criterions/label_smoothed_cross_entropy.py @@ -7,7 +7,8 @@ from dataclasses import dataclass, field import torch -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from omegaconf import II diff --git a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py index d5fb390f84..6eaedab9cf 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_latency_augmented.py @@ -5,7 +5,8 @@ from dataclasses import dataclass, field import torch -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import register_criterion from fairseq.criterions.label_smoothed_cross_entropy import ( LabelSmoothedCrossEntropyCriterion, diff --git a/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py b/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py index 2ea37c16b4..b55f65e5cc 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_with_alignment.py @@ -5,7 +5,8 @@ import math -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import register_criterion from .label_smoothed_cross_entropy import ( diff --git a/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py b/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py index e98e0f7da0..f2e8cdf3bf 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_with_ctc.py @@ -9,7 +9,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import register_criterion from fairseq.criterions.label_smoothed_cross_entropy import ( LabelSmoothedCrossEntropyCriterion, diff --git a/fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py b/fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py index 80b5ea0f73..47ee263a8d 100644 --- a/fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py +++ b/fairseq/criterions/label_smoothed_cross_entropy_with_rdrop.py @@ -8,7 +8,8 @@ import torch -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import register_criterion from fairseq.criterions.label_smoothed_cross_entropy import ( LabelSmoothedCrossEntropyCriterion, diff --git a/fairseq/criterions/legacy_masked_lm.py b/fairseq/criterions/legacy_masked_lm.py index c70608c5a1..5cf70df2ab 100644 --- a/fairseq/criterions/legacy_masked_lm.py +++ b/fairseq/criterions/legacy_masked_lm.py @@ -7,7 +7,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion diff --git a/fairseq/criterions/masked_lm.py b/fairseq/criterions/masked_lm.py index 279458f317..09ddd9f3e6 100644 --- a/fairseq/criterions/masked_lm.py +++ b/fairseq/criterions/masked_lm.py @@ -8,7 +8,8 @@ from omegaconf import II import torch -from fairseq import metrics, modules, utils +from fairseq import modules, utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass diff --git a/fairseq/criterions/model_criterion.py b/fairseq/criterions/model_criterion.py index 2c9fbb2553..4c020ddbd2 100644 --- a/fairseq/criterions/model_criterion.py +++ b/fairseq/criterions/model_criterion.py @@ -9,7 +9,8 @@ import torch -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.logging.meters import safe_round diff --git a/fairseq/criterions/nat_loss.py b/fairseq/criterions/nat_loss.py index 7dac32fbaf..fc0bdaf851 100644 --- a/fairseq/criterions/nat_loss.py +++ b/fairseq/criterions/nat_loss.py @@ -7,7 +7,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from torch import Tensor diff --git a/fairseq/criterions/sentence_prediction.py b/fairseq/criterions/sentence_prediction.py index 01c2a2ba6d..298b805768 100644 --- a/fairseq/criterions/sentence_prediction.py +++ b/fairseq/criterions/sentence_prediction.py @@ -14,7 +14,7 @@ from sklearn.metrics import matthews_corrcoef as _matthews_corrcoef from scipy.stats import pearsonr, spearmanr -from fairseq import metrics +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.logging.meters import safe_round diff --git a/fairseq/criterions/sentence_ranking.py b/fairseq/criterions/sentence_ranking.py index d4c76341d4..bfb9f058f9 100644 --- a/fairseq/criterions/sentence_ranking.py +++ b/fairseq/criterions/sentence_ranking.py @@ -7,7 +7,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion diff --git a/fairseq/criterions/speech_to_speech_criterion.py b/fairseq/criterions/speech_to_speech_criterion.py index 6c663c7713..06a8252140 100644 --- a/fairseq/criterions/speech_to_speech_criterion.py +++ b/fairseq/criterions/speech_to_speech_criterion.py @@ -9,7 +9,8 @@ import torch -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import register_criterion from fairseq.criterions.ctc import CtcCriterion from fairseq.criterions.label_smoothed_cross_entropy_with_rdrop import ( diff --git a/fairseq/criterions/speech_ulm_criterion.py b/fairseq/criterions/speech_ulm_criterion.py index eae6b62f76..eea74bae26 100644 --- a/fairseq/criterions/speech_ulm_criterion.py +++ b/fairseq/criterions/speech_ulm_criterion.py @@ -7,7 +7,7 @@ from dataclasses import dataclass, field import torch.nn.functional as F -from fairseq import metrics +from fairseq.logging import metrics from fairseq.tasks import FairseqTask from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass diff --git a/fairseq/criterions/tacotron2_loss.py b/fairseq/criterions/tacotron2_loss.py index d3af9762a7..4113fdc548 100644 --- a/fairseq/criterions/tacotron2_loss.py +++ b/fairseq/criterions/tacotron2_loss.py @@ -14,7 +14,8 @@ import torch.nn.functional as F from omegaconf import II -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.data.data_utils import lengths_to_mask from fairseq.dataclass import FairseqDataclass diff --git a/fairseq/criterions/wav2vec_criterion.py b/fairseq/criterions/wav2vec_criterion.py index e37274d5a8..3975468487 100644 --- a/fairseq/criterions/wav2vec_criterion.py +++ b/fairseq/criterions/wav2vec_criterion.py @@ -9,7 +9,8 @@ import torch import torch.nn.functional as F -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion from fairseq.dataclass import FairseqDataclass from fairseq.logging.meters import safe_round diff --git a/fairseq/model_parallel/criterions/vocab_parallel_cross_entropy.py b/fairseq/model_parallel/criterions/vocab_parallel_cross_entropy.py index 35c50ee152..5ffbaa8764 100644 --- a/fairseq/model_parallel/criterions/vocab_parallel_cross_entropy.py +++ b/fairseq/model_parallel/criterions/vocab_parallel_cross_entropy.py @@ -5,7 +5,8 @@ import math -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.criterions import FairseqCriterion, register_criterion diff --git a/fairseq/tasks/fairseq_task.py b/fairseq/tasks/fairseq_task.py index 7481e0f4bf..e39d1d6848 100644 --- a/fairseq/tasks/fairseq_task.py +++ b/fairseq/tasks/fairseq_task.py @@ -10,7 +10,8 @@ from typing import Any, Callable, Dict, List import torch -from fairseq import metrics, search, tokenizer, utils +from fairseq import search, tokenizer, utils +from fairseq.logging import metrics from fairseq.data import Dictionary, FairseqDataset, data_utils, encoders, iterators from fairseq.dataclass import FairseqDataclass from fairseq.dataclass.utils import gen_parser_from_dataclass diff --git a/fairseq/tasks/multilingual_translation.py b/fairseq/tasks/multilingual_translation.py index e692b66690..cef7656691 100644 --- a/fairseq/tasks/multilingual_translation.py +++ b/fairseq/tasks/multilingual_translation.py @@ -10,7 +10,8 @@ from argparse import ArgumentError import torch -from fairseq import metrics, options, utils +from fairseq import options, utils +from fairseq.logging import metrics from fairseq.data import ( Dictionary, LanguagePairDataset, diff --git a/fairseq/tasks/online_backtranslation.py b/fairseq/tasks/online_backtranslation.py index 52ce58ced7..da24fe8981 100644 --- a/fairseq/tasks/online_backtranslation.py +++ b/fairseq/tasks/online_backtranslation.py @@ -20,7 +20,8 @@ import torch.nn.functional as F import fairseq -from fairseq import metrics, options, utils +from fairseq import options, utils +from fairseq.logging import metrics from fairseq.data import ( FairseqDataset, LanguagePairDataset, diff --git a/fairseq/tasks/translation.py b/fairseq/tasks/translation.py index 79752279a6..6897ebe116 100644 --- a/fairseq/tasks/translation.py +++ b/fairseq/tasks/translation.py @@ -13,7 +13,8 @@ from omegaconf import II import numpy as np -from fairseq import metrics, utils +from fairseq import utils +from fairseq.logging import metrics from fairseq.data import ( AppendTokenDataset, ConcatDataset, diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 2de6969cf4..fc93b48088 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -6,7 +6,7 @@ import unittest import uuid -from fairseq import metrics +from fairseq.logging import metrics class TestMetrics(unittest.TestCase): From 176cd934982212a4f75e0669ee81b834ee71dbb0 Mon Sep 17 00:00:00 2001 From: Wei-Ning Hsu <31931787+wnhsu@users.noreply.github.com> Date: Mon, 27 Mar 2023 16:57:46 -0400 Subject: [PATCH 732/774] add data2vec2 nlp model dictionary (#5045) --- examples/data2vec/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/data2vec/README.md b/examples/data2vec/README.md index 99d56cf06d..a0ff21b82a 100644 --- a/examples/data2vec/README.md +++ b/examples/data2vec/README.md @@ -25,9 +25,9 @@ data2vec Large | 960 hours | [Libri-light](https://github.com/facebookresearch/l ### NLP -Model | Fine-tuning data | Dataset | Link -|---|---|---|---| -data2vec Base | No fine-tuning | Books + Wiki | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/nlp_base.pt) +| Model | Fine-tuning data | Dataset | Link | Dict | BPE +|---|---|---|---|---|--- +data2vec Base | No fine-tuning | Books + Wiki | [download](https://dl.fbaipublicfiles.com/fairseq/data2vec2/nlp_base.pt) | [dict](https://dl.fbaipublicfiles.com/fairseq/data2vec2/dict.txt) | [encoder](https://dl.fbaipublicfiles.com/fairseq/data2vec2/encoder.json) / [vocab](https://dl.fbaipublicfiles.com/fairseq/data2vec2/vocab.bpe) [//]: # (## Data Preparation) From 3f6ba43f07a6e9e2acf957fc24e57251a7a3f55c Mon Sep 17 00:00:00 2001 From: Shuming Hu <2934295+shuminghu@users.noreply.github.com> Date: Tue, 11 Apr 2023 17:20:02 -0700 Subject: [PATCH 733/774] Fix DiverseBeamSearch so that no diversity groups will be dropped. (#5069) --- fairseq/search.py | 104 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 91 insertions(+), 13 deletions(-) diff --git a/fairseq/search.py b/fairseq/search.py index a71e78019f..c7378bbb51 100644 --- a/fairseq/search.py +++ b/fairseq/search.py @@ -4,6 +4,7 @@ # LICENSE file in the root directory of this source tree. import math + from typing import List, Optional import torch @@ -113,6 +114,7 @@ def step( scores: Optional[Tensor], prev_output_tokens: Optional[Tensor] = None, original_batch_idxs: Optional[Tensor] = None, + candidate_multiple: int = 2, ): bsz, beam_size, vocab_size = lprobs.size() @@ -128,9 +130,9 @@ def step( top_prediction = torch.topk( lprobs.view(bsz, -1), k=min( - # Take the best 2 x beam_size predictions. We'll choose the first + # Take the best `candidate_muliple`(default 2) x beam_size predictions. We'll choose the first # beam_size of these which don't predict eos to continue with. - beam_size * 2, + candidate_multiple * beam_size, lprobs.view(bsz, -1).size(1) - 1, # -1 so we never select pad ), ) @@ -554,15 +556,57 @@ class DiverseBeamSearch(Search): See "Diverse Beam Search: Decoding Diverse Solutions from Neural Sequence Models" for details. - We only implement the Hamming Diversity penalty here, which performed best - in the original paper. + We implement cumulative diversity penalty here as default, optionally provide Hamming diversity described + in the original paper, and a way to interpolate between the two through diversity_discount. + + Take the example below for illustration of cumulative diversity implemented. + A) I like dogs. + B) I like ____. + C) There are ___. + And we are at step=2, trying to fill in the blank: + + Hamming diversity: + Penalty for B from A is 1 for "dogs" and 0 for any other words like "cats". + Penalty for C from A is 1 for "dogs" and 0 for any other words like "cats". + + Cumulative diversity (default): + Penalty for B from A is 3 for "dogs" and 0 for any other words like "cats". + Penalty for C from A is 1 for "dogs" and 0 for any other words like "cats". + B and C differ because B matches with A for "I" and "like" at respective steps incurring 2 cumulative penalty. + + Using divesrity_discount to interpolate between the two: + if diverstiy_discount = 0.5, then + Penalty for B from A is 1.75 (1 + 0.5 + 0.25) for "dogs" and 0 for any other words like "cats". + Penalty for C from A is 1 for "dogs" and 0 for any other words like "cats". + "I" and "like" matched for B and A at step 0 and 1 respectively. Since "I" is two steps away and "like" is one step away, they are discounted by (0.5)^2 and 0.5 respectively. + When diversity_discount = 0, we recover Hammning diversity and when diversity_discount = 1, we recover cumulative diversity. + + NB: During beam search for each diversity group, `candidate_mutiple` is set to 1 rather than BeamSearch default(2). + This is to ensure we have final `beam_size` candidates so that no diversity groups would be dropped during final token selection in sequence generation. + For full backwards compatibility, use diversity_discount=0 and candidate_multiple=2. + """ - def __init__(self, tgt_dict, num_groups, diversity_strength): + def __init__( + self, + tgt_dict, + num_groups, + diversity_strength, + diversity_discount=1.0, + candidate_multiple=1, + ): super().__init__(tgt_dict) self.num_groups = num_groups self.diversity_strength = -diversity_strength self.beam = BeamSearch(tgt_dict) + self.diversity_discount = diversity_discount + self.candidate_multiple = candidate_multiple + + # Float tensor to keep track of overlap between groups. + # Each token shared at the same step between two groups is counted as one. + # Then token counts are discounted by `diversity_discount` for every next timestep. + # Once initialized, dimension is batch_size * num_groups * num_groups. + self.group_overlap = torch.empty(0) @torch.jit.export def step( @@ -582,13 +626,38 @@ def step( # initialize diversity penalty diversity_buf = torch.zeros(lprobs[:, 0, :].size()).to(lprobs) - scores_G, indices_G, beams_G = [], [], [] + scores_G, beams_G = [], [] + + # pre-allocating tensor for indices for all groups + indices_G_stacked = torch.empty( + bsz, + int(beam_size / self.num_groups) * self.candidate_multiple, + self.num_groups, + dtype=torch.long, + device=lprobs.device, + ) + for g in range(self.num_groups): lprobs_g = lprobs[:, g :: self.num_groups, :] scores_g = scores[:, g :: self.num_groups, :] if step > 0 else None + diversity_buf.zero_() # apply diversity penalty if g > 0: + indices_ = indices_G_stacked[:, :, :g] + if step > 0: + penalty_val = 1 + self.group_overlap[original_batch_idxs, g, :g] + penalty_val = penalty_val.unsqueeze(1) + else: + penalty_val = torch.ones(bsz, 1, 1) + diversity_buf.scatter_add_( + 1, + indices_.reshape(bsz, -1), + penalty_val.expand(indices_.size()) + .reshape(bsz, -1) + .to(diversity_buf), + ) + lprobs_g = torch.add( lprobs_g, other=diversity_buf.unsqueeze(1), @@ -598,23 +667,32 @@ def step( lprobs_g = lprobs_g.contiguous() scores_buf, indices_buf, beams_buf = self.beam.step( - step, lprobs_g, scores_g + step, lprobs_g, scores_g, candidate_multiple=self.candidate_multiple ) beams_buf.mul_(self.num_groups).add_(g) scores_G.append(scores_buf.clone()) - indices_G.append(indices_buf.clone()) beams_G.append(beams_buf.clone()) - # update diversity penalty - diversity_buf.scatter_add_( - 1, indices_buf, torch.ones(indices_buf.size()).to(diversity_buf) - ) + indices_G_stacked[:, :, g] = indices_buf # interleave results from different groups scores_buf = torch.stack(scores_G, dim=2).view(bsz, -1) - indices_buf = torch.stack(indices_G, dim=2).view(bsz, -1) + indices_buf = indices_G_stacked.view(bsz, -1) beams_buf = torch.stack(beams_G, dim=2).view(bsz, -1) + # find num of overlapped tokens for each group pair + # then discount it for next timestamp + overlap = self.diversity_discount * torch.sum( + indices_G_stacked.unsqueeze(2).eq(indices_G_stacked.unsqueeze(3)), dim=1 + ) + if step == 0: + self.group_overlap = overlap + else: + self.group_overlap[original_batch_idxs] = ( + self.group_overlap[original_batch_idxs] * self.diversity_discount + + overlap + ) + return scores_buf, indices_buf, beams_buf From b35e8efa8756d2e16c2c90fb885ce136bf2f14b2 Mon Sep 17 00:00:00 2001 From: Victoria X Lin <victorialin@fb.com> Date: Mon, 8 May 2023 12:12:23 -0700 Subject: [PATCH 734/774] XGLM paper camera-ready: add XStoryCloze data opensource (#4820) * add XStoryCloze data * upload XStoryCloze dataset files to s3 instead of git * minor fixes * minor fixes * minor fixes * minor fixes * fix broken dataset doc link --- examples/xglm/README.md | 20 +++++++++++-- examples/xglm/XStoryCloze.md | 57 ++++++++++++++++++++++++++++++++++++ examples/xglm/model_card.md | 2 +- 3 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 examples/xglm/XStoryCloze.md diff --git a/examples/xglm/README.md b/examples/xglm/README.md index fb630f6f07..dc8e24d769 100644 --- a/examples/xglm/README.md +++ b/examples/xglm/README.md @@ -138,10 +138,24 @@ for lang in ['en', 'zh', 'hi']: # hi-1 0 0 ``` -## Preprint -[Few-shot Learning with Multilingual Language Models](https://arxiv.org/abs/2112.10668). +## XStoryCloze + +We release XStoryCloze, a new multilingual dataset intended for few-shot evaluation, alongside this paper. XStoryCloze consists of professional translation of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. It is opensourced under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode), the same license as the English StoryCloze. + +You can download the dataset via [this link](https://dl.fbaipublicfiles.com/xstorycloze.zip). + +Language | ar | es | eu | hi | id | my | ru | sw | te | zh +---|---|---|---|---|---|---|---|---|---|--- +Train size | 360 | 360 | 360 | 360 | 360 | 360 | 360 | 360 | 360 | 360 +Eval size | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 | 1511 + +Please refer to [the dataset doc](XStoryCloze.md) for more information. + + +## Publication +[Few-shot Learning with Multilingual Generative Language Models](https://arxiv.org/abs/2112.10668). Xi Victoria Lin*, Todor Mihaylov, Mikel Artetxe, Tianlu Wang, Shuohui Chen, Daniel Simig, Myle Ott, Naman Goyal, Shruti Bhosale, Jingfei Du, Ramakanth Pasunuru, Sam Shleifer, Punit Singh Koura, Vishrav Chaudhary, Brian O'Horo, Jeff Wang, Luke Zettlemoyer, Zornitsa Kozareva, Mona Diab, Veselin Stoyanov, Xian Li* (* Equal Contribution). -ArXiv 2021. +EMNLP 2022. ## Citation ``` diff --git a/examples/xglm/XStoryCloze.md b/examples/xglm/XStoryCloze.md new file mode 100644 index 0000000000..3affbad38a --- /dev/null +++ b/examples/xglm/XStoryCloze.md @@ -0,0 +1,57 @@ +XStoryCloze consists of professional translation of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. This dataset is released by Meta AI alongside the paper [Few-shot Learning with Multilingual Generative Language Models. EMNLP 2022](https://arxiv.org/abs/2112.10668). + +# Languages +ru, zh (Simplified), es (Latin America), ar, hi, id, te, sw, eu, my. + +# Data Splits +This dataset is intended to be used for evaluating the zero- and few-shot learning capabilities of multlingual language models. We split the data for each language into train and test (360 vs. 1510 examples, respectively). The released data files for different languages maintain a line-by-line alignment. + +# Access English StoryCloze +Please request the original English StoryCloze dataset through the [official website](https://cs.rochester.edu/nlp/rocstories/). You can create a split of the en data following our data split scheme using the following commands: +``` +head -361 spring2016.val.tsv > spring2016.val.en.tsv.split_20_80_train.tsv + +head -1 spring2016.val.tsv > spring2016.val.en.tsv.split_20_80_eval.tsv # TSV header +tail -1511 spring2016.val.tsv >> spring2016.val.en.tsv.split_20_80_eval.tsv +``` + +# Licence +XStoryCloze is opensourced under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode), the same license as the original English StoryCloze. + +# Citation +We hope this dataset is helpful for the research and wider NLP community. If you use XStoryCloze in your work, please cite +``` +@article{DBLP:journals/corr/abs-2112-10668, + author = {Xi Victoria Lin and + Todor Mihaylov and + Mikel Artetxe and + Tianlu Wang and + Shuohui Chen and + Daniel Simig and + Myle Ott and + Naman Goyal and + Shruti Bhosale and + Jingfei Du and + Ramakanth Pasunuru and + Sam Shleifer and + Punit Singh Koura and + Vishrav Chaudhary and + Brian O'Horo and + Jeff Wang and + Luke Zettlemoyer and + Zornitsa Kozareva and + Mona T. Diab and + Veselin Stoyanov and + Xian Li}, + title = {Few-shot Learning with Multilingual Language Models}, + journal = {CoRR}, + volume = {abs/2112.10668}, + year = {2021}, + url = {https://arxiv.org/abs/2112.10668}, + eprinttype = {arXiv}, + eprint = {2112.10668}, + timestamp = {Tue, 04 Jan 2022 15:59:27 +0100}, + biburl = {https://dblp.org/rec/journals/corr/abs-2112-10668.bib}, + bibsource = {dblp computer science bibliography, https://dblp.org} +} +``` diff --git a/examples/xglm/model_card.md b/examples/xglm/model_card.md index 0cdd20fbe0..af33ba5bd8 100644 --- a/examples/xglm/model_card.md +++ b/examples/xglm/model_card.md @@ -50,7 +50,7 @@ The Cross-lingual Natural Language Inference (XNLI) corpus is the extension of t ### XStoryCloze #### Description -A new dataset created by Meta AI by translating the validation split of the English StoryCloze dataset (Mostafazadeh et al., 2016) (Spring 2016 version) to 10 other typologically diverse languages (ru, zh Simplified, es Latin America, ar, hi, id, te, sw, eu, my). +A new dataset created by Meta AI along side this work by translating the validation split of the English StoryCloze dataset (Mostafazadeh et al., 2016) (Spring 2016 version) to 10 other typologically diverse languages (ru, zh Simplified, es Latin America, ar, hi, id, te, sw, eu, my). ### XCOPA (Ponti et al., 2020) #### Description From 5ecbbf58d6e80b917340bcbf9d7bdbb539f0f92b Mon Sep 17 00:00:00 2001 From: Victoria X Lin <victorialin@fb.com> Date: Mon, 8 May 2023 14:31:22 -0700 Subject: [PATCH 735/774] update XStoryCloze dataset description (#5100) --- examples/xglm/README.md | 2 +- examples/xglm/XStoryCloze.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/xglm/README.md b/examples/xglm/README.md index dc8e24d769..914e297669 100644 --- a/examples/xglm/README.md +++ b/examples/xglm/README.md @@ -140,7 +140,7 @@ for lang in ['en', 'zh', 'hi']: ## XStoryCloze -We release XStoryCloze, a new multilingual dataset intended for few-shot evaluation, alongside this paper. XStoryCloze consists of professional translation of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. It is opensourced under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode), the same license as the English StoryCloze. +We release XStoryCloze, a new multilingual dataset intended for few-shot evaluation, alongside this paper. XStoryCloze consists of professional translation of the validation split of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. It is opensourced under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/legalcode), the same license as the English StoryCloze. You can download the dataset via [this link](https://dl.fbaipublicfiles.com/xstorycloze.zip). diff --git a/examples/xglm/XStoryCloze.md b/examples/xglm/XStoryCloze.md index 3affbad38a..d49840ab61 100644 --- a/examples/xglm/XStoryCloze.md +++ b/examples/xglm/XStoryCloze.md @@ -1,4 +1,4 @@ -XStoryCloze consists of professional translation of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. This dataset is released by Meta AI alongside the paper [Few-shot Learning with Multilingual Generative Language Models. EMNLP 2022](https://arxiv.org/abs/2112.10668). +XStoryCloze consists of professional translation of the validation split of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. This dataset is released by Meta AI alongside the paper [Few-shot Learning with Multilingual Generative Language Models. EMNLP 2022](https://arxiv.org/abs/2112.10668). # Languages ru, zh (Simplified), es (Latin America), ar, hi, id, te, sw, eu, my. From bfd9dc6d2757bdb2e8bf74c8f8f9ebd2ab3606e3 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@fb.com> Date: Thu, 18 May 2023 18:29:26 -0700 Subject: [PATCH 736/774] fix dict order (#5109) --- .../speech_recognition/new/decoders/flashlight_decoder.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/speech_recognition/new/decoders/flashlight_decoder.py b/examples/speech_recognition/new/decoders/flashlight_decoder.py index 38c7ac492f..7790fcdb82 100644 --- a/examples/speech_recognition/new/decoders/flashlight_decoder.py +++ b/examples/speech_recognition/new/decoders/flashlight_decoder.py @@ -40,6 +40,7 @@ Trie, ) from flashlight.lib.text.dictionary import create_word_dict, load_words + from flashlight.lib.text.dictionary import Dictionary as flDictionary except ImportError: warnings.warn( "flashlight python bindings are required to use this functionality. " @@ -102,8 +103,9 @@ def __init__(self, cfg: FlashlightDecoderConfig, tgt_dict: Dictionary) -> None: else: assert self.unitlm, "Lexicon-free decoding requires unit LM" - d = {w: [[w]] for w in tgt_dict.symbols} - self.word_dict = create_word_dict(d) + self.word_dict = flDictionary() + for sym in tgt_dict.symbols: + self.word_dict.add_entry(sym, tgt_dict.index(sym)) self.lm = KenLM(cfg.lmpath, self.word_dict) self.decoder_opts = LexiconFreeDecoderOptions( beam_size=cfg.beam, From 728b947019fd186753197add48c39cbb24ea43e2 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Sun, 21 May 2023 21:15:50 -0700 Subject: [PATCH 737/774] Mms release (#3948) (#5110) --- examples/mms/MODEL_CARD.md | 63 ++++ examples/mms/README.md | 175 +++++++++ examples/mms/asr/config/infer_common.yaml | 32 ++ .../mms/asr/infer/example_infer_adapter.sh | 3 + examples/mms/asr/infer/mms_infer.py | 52 +++ examples/mms/data_prep/README.md | 47 +++ examples/mms/data_prep/align_and_segment.py | 187 ++++++++++ examples/mms/data_prep/align_utils.py | 176 +++++++++ examples/mms/data_prep/norm_config.py | 277 ++++++++++++++ examples/mms/data_prep/punctuations.lst | 188 ++++++++++ examples/mms/data_prep/text_normalization.py | 92 +++++ examples/mms/lid/infer.py | 197 ++++++++++ examples/mms/tts/infer.py | 102 +++++ examples/speech_recognition/new/infer.py | 24 ++ fairseq/data/audio/raw_audio_dataset.py | 4 + fairseq/data/dictionary.py | 22 +- fairseq/models/wav2vec/__init__.py | 1 + fairseq/models/wav2vec/wav2vec2.py | 223 ++++++++++- fairseq/models/wav2vec/wav2vec2_asr.py | 45 ++- .../models/wav2vec/wav2vec2_classification.py | 348 ++++++++++++++++++ fairseq/tasks/audio_classification.py | 269 ++++++++++++++ fairseq/tasks/audio_finetuning.py | 120 ++++-- fairseq/tasks/audio_pretraining.py | 80 +++- 23 files changed, 2657 insertions(+), 70 deletions(-) create mode 100644 examples/mms/MODEL_CARD.md create mode 100644 examples/mms/README.md create mode 100644 examples/mms/asr/config/infer_common.yaml create mode 100644 examples/mms/asr/infer/example_infer_adapter.sh create mode 100644 examples/mms/asr/infer/mms_infer.py create mode 100644 examples/mms/data_prep/README.md create mode 100644 examples/mms/data_prep/align_and_segment.py create mode 100644 examples/mms/data_prep/align_utils.py create mode 100644 examples/mms/data_prep/norm_config.py create mode 100644 examples/mms/data_prep/punctuations.lst create mode 100644 examples/mms/data_prep/text_normalization.py create mode 100644 examples/mms/lid/infer.py create mode 100644 examples/mms/tts/infer.py create mode 100644 fairseq/models/wav2vec/wav2vec2_classification.py create mode 100644 fairseq/tasks/audio_classification.py diff --git a/examples/mms/MODEL_CARD.md b/examples/mms/MODEL_CARD.md new file mode 100644 index 0000000000..eccab62bd7 --- /dev/null +++ b/examples/mms/MODEL_CARD.md @@ -0,0 +1,63 @@ +# MMS Model Card + +## Model details + +**Organization developing the model** The FAIR team of Meta AI. + +**Model version** This is version 1 of the model. + +**Model type** MMS is speech model, based on the transformer architecture. The pre-trained model comes in two sizes: 300M and 1B parameters. We fine-tune the model for speech recognition and make it available in the 1B variant. We also fine-tune the 1B variant for language identification. + +**License** CC BY-NC + +**Where to send questions or comments about the model** Questions and comments about MMS can be sent via the [GitHub repository](https://github.com/pytorch/fairseq/tree/master/examples/mms) of the project , by opening an issue and tagging it as MMS. + +## Uses + +**Primary intended uses** The primary use of MMS is to perform speech processing research for many more languages and to perform tasks such as automatic speech recognition, language identification, and speech synthesis. + +**Primary intended users** The primary intended users of the model are researchers in speech processing, machine learning and artificial intelligence. + +**Out-of-scope use cases** Fine-tuning the pre-pretrained models on other labeled datasets or downstream tasks requires further risk evaluation and mitigation. + +## Bias and Risks + +The MMS models were pre-trained on a blend of data from different domains, including readings of the New Testament. In the paper, we describe two studies analyzing gender bias and the use of religious language which conclude that models perform equally well for both genders and that on average, there is little bias for religious language (section 8 of the paper). + +# Training Details + +## Training Data + +MMS is pre-trained on VoxPopuli (parliamentary speech), MLS (read audiobooks), VoxLingua-107 (YouTube speech), CommonVoice (read Wikipedia text), BABEL (telephone conversations), and MMS-lab-U (New Testament readings), MMS-unlab (various read Christian texts). +Models are fine-tuned on FLEURS, VoxLingua-107, MLS, CommonVoice, and MMS-lab. We obtained the language information for MMS-lab, MMS-lab-U and MMS-unlab from our data soucrce and did not manually verify it for every language. + +## Training Procedure + +Please refer to the research paper for details on this. + +# Evaluation + +## Testing Data, Factors & Metrics + +We evaluate the model on a different benchmarks for the downstream tasks. The evaluation details are presented in the paper. The models performance is measured using standard metrics such as character error rate, word error rate, and classification accuracy. + + +# Citation + +**BibTeX:** + +``` +@article{pratap2023mms, + title={Scaling Speech Technology to 1,000+ Languages}, + author={Vineel Pratap and Andros Tjandra and Bowen Shi and Paden Tomasello and Arun Babu and Sayani Kundu and Ali Elkahky and Zhaoheng Ni and Apoorv Vyas and Maryam Fazel-Zarandi and Alexei Baevski and Yossi Adi and Xiaohui Zhang and Wei-Ning Hsu and Alexis Conneau and Michael Auli}, + journal={arXiv}, + year={2023} +} + +``` + +# Model Card Contact + +Please reach out to the authors at: [vineelkpratap@meta.com](mailto:vineelkpratap@meta.com) [androstj@meta.com](mailto:androstj@meta.com) [bshi@meta.com](mailto:bshi@meta.com) [michaelauli@meta.com](mailto:michaelauli@gmail.com) + + diff --git a/examples/mms/README.md b/examples/mms/README.md new file mode 100644 index 0000000000..e941e4340b --- /dev/null +++ b/examples/mms/README.md @@ -0,0 +1,175 @@ +# MMS: Scaling Speech Technology to 1000+ languages + +The Massively Multilingual Speech (MMS) project expands speech technology from about 100 languages to over 1,000 by building a single multilingual speech recognition model supporting over 1,100 languages (more than 10 times as many as before), language identification models able to identify over [4,000 languages](https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html) (40 times more than before), pretrained models supporting over 1,400 languages, and text-to-speech models for over 1,100 languages. Our goal is to make it easier for people to access information and to use devices in their preferred language. + +You can find details in the paper [Scaling Speech Technology to 1000+ languages](https://research.facebook.com/publications/scaling-speech-technology-to-1000-languages/) and the [blog post](https://ai.facebook.com/blog/multilingual-speech-recognition-model/). + +An overview of the languages covered by MMS can be found [here](https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html). + + +## Pretrained models + +| Model | Link +|---|--- +MMS-300M | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_300m.pt) +MMS-1B | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_1b.pt) + +Example commands to finetune the pretrained models can be found [here](https://github.com/fairinternal/fairseq-py/tree/mms_release/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). + +## Finetuned models +### ASR + +| Model | Languages | Dataset | Model | Supported languages | +|---|---|---|---|--- +MMS-1B:FL102 | 102 | FLEURS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102_langs.html) +MMS-1B:L1107| 1107 | MMS-lab | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107_langs.html) +MMS-1B-all| 1162 | MMS-lab + FLEURS <br>+ CV + VP + MLS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all_langs.html) + +### TTS +1. Download the list of [iso codes](https://dl.fbaipublicfiles.com/mms/tts/all-tts-languages.html) of 1107 languages. +2. Find the iso code of the target language and download the checkpoint. Each folder contains 3 files: `G_100000.pth`, `config.json`, `vocab.txt`. The `G_100000.pth` is the generator trained for 100K updates, `config.json` is the training config, `vocab.txt` is the vocabulary for the TTS model. +``` +# Examples: +wget https://dl.fbaipublicfiles.com/mms/tts/eng.tar.gz # English (eng) +wget https://dl.fbaipublicfiles.com/mms/tts/azj-script_latin.tar.gz # North Azerbaijani (azj-script_latin) +``` + +### LID + +\# Languages | Dataset | Model | Dictionary | Supported languages | +|---|---|---|---|--- +126 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l126/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126_langs.html) +256 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l256.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l256/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l256_langs.html) +512 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l512.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l512/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l512_langs.html) +1024 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l1024.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l1024/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l1024_langs.html) +2048 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l2048.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l2048/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l2048_langs.html) +4017 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l4017.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l4017/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l4017_langs.html) + +## Commands to run inference + +### ASR +Run this command to transcribe one or more audio files: +```shell command +cd /path/to/fairseq-py/ +python examples/mms/asr/infer/mms_infer.py --model "/path/to/asr/model" --lang lang_code --audio "/path/to/audio_1.wav" "/path/to/audio_1.wav" +``` + +For more advance configuration and calculate CER/WER, you could prepare manifest folder by creating a folder with this format: +``` +$ ls /path/to/manifest +dev.tsv +dev.wrd +dev.ltr +dev.uid + +# dev.tsv each line contains <audio> <number_of_sample> +$ cat dev.tsv +/ +/path/to/audio_1 180000 +/path/to/audio_2 200000 + +$ cat dev.ltr +t h i s | i s | o n e | +t h i s | i s | t w o | + +$ cat dev.wrd +this is one +this is two + +$ cat dev.uid +audio_1 +audio_2 +``` + +Followed by command below: +``` +lang_code=<iso_code> + +PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=4000000 distributed_training.distributed_world_size=1 "common_eval.path='/path/to/asr/model'" task.data='/path/to/manifest' dataset.gen_subset="${lang_code}:dev" common_eval.post_process=letter + +``` +Available options: +* To get the raw character-based output, user can change to `common_eval.post_process=none` + +* To maximize GPU efficiency or avoid out-of-memory (OOM), user can tune `dataset.max_tokens=???` size + +* To run language model decoding, install flashlight python bindings using + ``` + git clone --recursive git@github.com:flashlight/flashlight.git + cd flashlight; + git checkout 035ead6efefb82b47c8c2e643603e87d38850076 + cd bindings/python + python3 setup.py install + ``` + Train a [KenLM language model](https://github.com/flashlight/wav2letter/tree/main/recipes/rasr#language-model) and prepare a lexicon file in [this](https://dl.fbaipublicfiles.com/wav2letter/rasr/tutorial/lexicon.txt) format. + ``` + LANG=<iso> # for example - 'eng', 'azj-script_latin' + PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py --config-dir=examples/mms/asr/config \ + --config-name=infer_common decoding.type=kenlm distributed_training.distributed_world_size=1 \ + decoding.unique_wer_file=true decoding.beam=500 decoding.beamsizetoken=50 \ + task.data=<MANIFEST_FOLDER_PATH> common_eval.path='<MODEL_PATH.pt>' decoding.lexicon=<LEXICON_FILE> decoding.lmpath=<LM_FILE> \ + decoding.results_path=<OUTPUT_DIR> dataset.gen_subset=${LANG}:dev decoding.lmweight=??? decoding.wordscore=??? + ``` + We typically sweep `lmweight` in the range of 0 to 5 and `wordscore` in the range of -3 to 3. The output directory will contain the reference and hypothesis outputs from decoder. + + For decoding with character-based language models, use empty lexicon file (`decoding.lexicon=`), `decoding.unitlm=True` and sweep over `decoding.silweight` instead of `wordscore`. + +### TTS +Note: clone and install [VITS](https://github.com/jaywalnut310/vits) before running inference. +```shell script +## English TTS +$ PYTHONPATH=$PYTHONPATH:/path/to/vits python examples/mms/tts/infer.py --model-dir /path/to/model/eng \ +--wav ./example.wav --txt "Expanding the language coverage of speech technology \ +has the potential to improve access to information for many more people" + +## Maithili TTS +$ PYTHONPATH=$PYTHONPATH:/path/to/vits python examples/mms/tts/infer.py --model-dir /path/to/model/mai \ +--wav ./example.wav --txt "मुदा आइ धरि ई तकनीक सौ सं किछु बेसी भाषा तक सीमित छल जे सात हजार \ +सं बेसी ज्ञात भाषाक एकटा अंश अछी" +``` +`example.wav` contains synthesized audio for the language. + + +### LID + + +Prepare two files in this format +``` +#/path/to/manifest.tsv +/ +/path/to/audio1.wav +/path/to/audio2.wav +/path/to/audio3.wav + +# /path/to/manifest.lang +eng 1 +eng 1 +eng 1 +``` + +Download model and the corresponding dictionary file for the LID model. The following command assuming there is a file named `dict.lang.txt` in `/path/to/dict/l126/`. +Use the following command to run inference - +```shell script +$ PYTHONPATH='.' python3 examples/mms/lid/infer.py /path/to/dict/l126/ --path /path/to/models/mms1b_l126.pt \ + --task audio_classification --infer-manifest /path/to/manifest.tsv --output-path <OUTDIR> +``` +`<OUTDIR>/predictions.txt` will contain the predictions from the model for the audio files in `manifest.tsv`. + + +# License + +The MMS code and model weights are released under the CC-BY-NC 4.0 license. + +# Citation + +**BibTeX:** + +``` +@article{pratap2023mms, + title={Scaling Speech Technology to 1,000+ Languages}, + author={Vineel Pratap and Andros Tjandra and Bowen Shi and Paden Tomasello and Arun Babu and Sayani Kundu and Ali Elkahky and Zhaoheng Ni and Apoorv Vyas and Maryam Fazel-Zarandi and Alexei Baevski and Yossi Adi and Xiaohui Zhang and Wei-Ning Hsu and Alexis Conneau and Michael Auli}, + journal={arXiv}, + year={2023} +} + +``` diff --git a/examples/mms/asr/config/infer_common.yaml b/examples/mms/asr/config/infer_common.yaml new file mode 100644 index 0000000000..ecc095992f --- /dev/null +++ b/examples/mms/asr/config/infer_common.yaml @@ -0,0 +1,32 @@ +# @package _global_ +# defaults: +# - hydra/launcher: submitit_slurm + +# @package _group_ + +task: + _name: audio_finetuning + data: null + labels: ltr +common_eval: + path: null + post_process: letter + # model_overrides: "{'task':{'multi_corpus_keys':None}}" +decoding: + type: viterbi + lexicon: null + unique_wer_file: false + results_path: null +distributed_training: + ddp_backend: legacy_ddp + distributed_world_size: 1 +hydra: + run: + dir: ${common_eval.results_path}/${dataset.gen_subset} + sweep: + dir: /checkpoint/${env:USER}/${env:PREFIX}/${common_eval.results_path} + subdir: ${dataset.gen_subset} +dataset: + max_tokens: 2_000_000 + gen_subset: dev + required_batch_size_multiple: 1 diff --git a/examples/mms/asr/infer/example_infer_adapter.sh b/examples/mms/asr/infer/example_infer_adapter.sh new file mode 100644 index 0000000000..90b832d2f6 --- /dev/null +++ b/examples/mms/asr/infer/example_infer_adapter.sh @@ -0,0 +1,3 @@ +#!/bin/bash +lang="$1" +PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=4000000 distributed_training.distributed_world_size=1 "common_eval.path='/fsx-wav2vec/androstj/exps/wav2vec/mms/v4/finetune/xl1b_d5_dfls_0_0.3_u300k__ft_on_d5_127_dbeta1/ft_smax_adp_common.seed:1__dataset.max_tokens:2880000__optimization.lr:[0.001]__optimization.max_update:4000__merged_ckpt/checkpoints/checkpoint_last.pt'" task.data=/fsx-wav2vec/androstj/dataset/v4/fl/fseq dataset.gen_subset="${lang}:${lang}/dev" common_eval.post_process=none diff --git a/examples/mms/asr/infer/mms_infer.py b/examples/mms/asr/infer/mms_infer.py new file mode 100644 index 0000000000..f9e06cd222 --- /dev/null +++ b/examples/mms/asr/infer/mms_infer.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import argparse +import soundfile as sf +import tempfile +from pathlib import Path +import os +import subprocess +import sys +import re + +def parser(): + parser = argparse.ArgumentParser(description="ASR inference script for MMS model") + parser.add_argument("--model", type=str, help="path to ASR model", required=True) + parser.add_argument("--audio", type=str, help="path to audio file", required=True, nargs='+') + parser.add_argument("--lang", type=str, help="audio language", required=True) + parser.add_argument("--format", type=str, choices=["none", "letter"], default="letter") + return parser.parse_args() + +def process(args): + with tempfile.TemporaryDirectory() as tmpdir: + print(">>> preparing tmp manifest dir ...", file=sys.stderr) + tmpdir = Path(tmpdir) + with open(tmpdir / "dev.tsv", "w") as fw: + fw.write("/\n") + for audio in args.audio: + nsample = sf.SoundFile(audio).frames + fw.write(f"{audio}\t{nsample}\n") + with open(tmpdir / "dev.uid", "w") as fw: + fw.write(f"{audio}\n"*len(args.audio)) + with open(tmpdir / "dev.ltr", "w") as fw: + fw.write("d u m m y | d u m m y\n"*len(args.audio)) + with open(tmpdir / "dev.wrd", "w") as fw: + fw.write("dummy dummy\n"*len(args.audio)) + cmd = f""" + PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=4000000 distributed_training.distributed_world_size=1 "common_eval.path='{args.model}'" task.data={tmpdir} dataset.gen_subset="{args.lang}:dev" common_eval.post_process={args.format} decoding.results_path={tmpdir} + """ + print(">>> loading model & running inference ...", file=sys.stderr) + subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL,) + with open(tmpdir/"hypo.word") as fr: + for ii, hypo in enumerate(fr): + hypo = re.sub("\(\S+\)$", "", hypo).strip() + print(f'===============\nInput: {args.audio[ii]}\nOutput: {hypo}') + + +if __name__ == "__main__": + args = parser() + process(args) diff --git a/examples/mms/data_prep/README.md b/examples/mms/data_prep/README.md new file mode 100644 index 0000000000..4a06e7fef9 --- /dev/null +++ b/examples/mms/data_prep/README.md @@ -0,0 +1,47 @@ +# Data Preparation + +We describe the process of aligning long audio files with their transcripts and generating shorter audio segments below. + +- Step 1: Download and install torchaudio using the nightly version. We have open sourced the CTC forced alignment algorithm described in our paper via [torchaudio](https://github.com/pytorch/audio/pull/3348). + ``` + pip install --pre torchaudio --index-url https://download.pytorch.org/whl/nightly/cu118 + ``` + +- Step 2: Download [uroman](https://github.com/isi-nlp/uroman) from Github. It is a universal romanizer which converts text in any script to the Latin alphabet. Use [this link](https://www.isi.edu/~ulf/uroman.html) to try their web interface. + ``` + git clone git@github.com:isi-nlp/uroman.git + ``` + +- Step 3: Install a few other dependencies + ``` + pip install sox + pip install dataclasses + ``` + +- Step 4: Create a text file containing the transcript for a (long) audio file. Each line in the text file will correspond to a separate audio segment that will be generated upon alignment. + + Example content of the input text file : + ``` + Text of the desired first segment + Text of the desired second segment + Text of the desired third segment + ``` + +- Step 5: Run forced alignment and segment the audio file into shorter segments. + ``` + python align_and_segment.py --audio /path/to/audio.wav --textfile /path/to/textfile --lang <iso> --outdir /path/to/output --uroman /path/to/uroman/bin + ``` + + The above code will generated the audio segments under output directory based on the content of each line in the input text file. The `manifest.json` file consisting of the of segmented audio filepaths and their corresponding transcripts. + + ``` + > head /path/to/output/manifest.json + + {"audio_start_sec": 0.0, "audio_filepath": "/path/to/output/segment1.flac", "duration": 6.8, "text": "she wondered afterwards how she could have spoken with that hard serenity how she could have", "normalized_text": "she wondered afterwards how she could have spoken with that hard serenity how she could have", "uroman_tokens": "s h e w o n d e r e d a f t e r w a r d s h o w s h e c o u l d h a v e s p o k e n w i t h t h a t h a r d s e r e n i t y h o w s h e c o u l d h a v e"} + {"audio_start_sec": 6.8, "audio_filepath": "/path/to/output/segment2.flac", "duration": 5.3, "text": "gone steadily on with story after story poem after poem till", "normalized_text": "gone steadily on with story after story poem after poem till", "uroman_tokens": "g o n e s t e a d i l y o n w i t h s t o r y a f t e r s t o r y p o e m a f t e r p o e m t i l l"} + {"audio_start_sec": 12.1, "audio_filepath": "/path/to/output/segment3.flac", "duration": 5.9, "text": "allan's grip on her hands relaxed and he fell into a heavy tired sleep", "normalized_text": "allan's grip on her hands relaxed and he fell into a heavy tired sleep", "uroman_tokens": "a l l a n ' s g r i p o n h e r h a n d s r e l a x e d a n d h e f e l l i n t o a h e a v y t i r e d s l e e p"} + ``` + + To visualize the segmented audio files, [Speech Data Explorer](https://github.com/NVIDIA/NeMo/tree/main/tools/speech_data_explorer) tool from NeMo toolkit can be used. + + As our alignment model outputs uroman tokens for input audio in any language, it also works with non-english audio and their corresponding transcripts. diff --git a/examples/mms/data_prep/align_and_segment.py b/examples/mms/data_prep/align_and_segment.py new file mode 100644 index 0000000000..732f93c3fb --- /dev/null +++ b/examples/mms/data_prep/align_and_segment.py @@ -0,0 +1,187 @@ +import os +import torch +import torchaudio +import sox +import json +import argparse + + +from examples.mms.data_prep.text_normalization import text_normalize +from examples.mms.data_prep.align_utils import ( + get_uroman_tokens, + time_to_frame, + load_model_dict, + merge_repeats, + get_spans, +) +import torchaudio.functional as F + +SAMPLING_FREQ = 16000 +EMISSION_INTERVAL = 30 +DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + +def generate_emissions(model, audio_file): + waveform, _ = torchaudio.load(audio_file) # waveform: channels X T + waveform = waveform.to(DEVICE) + total_duration = sox.file_info.duration(audio_file) + + audio_sf = sox.file_info.sample_rate(audio_file) + assert audio_sf == SAMPLING_FREQ + + emissions_arr = [] + with torch.inference_mode(): + i = 0 + while i < total_duration: + segment_start_time, segment_end_time = (i, i + EMISSION_INTERVAL) + + context = EMISSION_INTERVAL * 0.1 + input_start_time = max(segment_start_time - context, 0) + input_end_time = min(segment_end_time + context, total_duration) + waveform_split = waveform[ + :, + int(SAMPLING_FREQ * input_start_time) : int( + SAMPLING_FREQ * (input_end_time) + ), + ] + + model_outs, _ = model(waveform_split) + emissions_ = model_outs[0] + emission_start_frame = time_to_frame(segment_start_time) + emission_end_frame = time_to_frame(segment_end_time) + offset = time_to_frame(input_start_time) + + emissions_ = emissions_[ + :, emission_start_frame - offset : emission_end_frame - offset + ] + emissions_arr.append(emissions_) + i += EMISSION_INTERVAL + + emissions = torch.cat(emissions_arr, dim=1).squeeze() + emissions = torch.log_softmax(emissions, dim=-1) + + stride = float(waveform.size(1) * 1000 / emissions.size(0) / SAMPLING_FREQ) + + return emissions, stride + + +def get_alignments( + audio_file, + tokens, + model, + dictionary, + use_star, +): + # Generate emissions + emissions, stride = generate_emissions(model, audio_file) + T, N = emissions.size() + if use_star: + emissions = torch.cat([emissions, torch.zeros(T, 1).to(DEVICE)], dim=1) + + # Force Alignment + if tokens: + token_indices = [dictionary[c] for c in " ".join(tokens).split(" ") if c in dictionary] + else: + print(f"Empty transcript!!!!! for audio file {audio_file}") + token_indices = [] + + blank = dictionary["<blank>"] + + path, _ = F.force_align( + emissions, torch.Tensor(token_indices, device=DEVICE).int(), blank=blank + ) + path = path.to("cpu").tolist() + segments = merge_repeats(path, {v: k for k, v in dictionary.items()}) + return segments, stride + + +def main(args): + assert not os.path.exists( + args.outdir + ), f"Error: Output path exists already {args.outdir}" + + transcripts = [] + with open(args.text_filepath) as f: + transcripts = [line.strip() for line in f] + print("Read {} lines from {}".format(len(transcripts), args.text_filepath)) + + norm_transcripts = [text_normalize(line.strip(), args.lang) for line in transcripts] + tokens = get_uroman_tokens(norm_transcripts, args.uroman_path, args.lang) + + model, dictionary = load_model_dict() + model = model.to(DEVICE) + if args.use_star: + dictionary["<star>"] = len(dictionary) + tokens = ["<star>"] + tokens + transcripts = ["<star>"] + transcripts + norm_transcripts = ["<star>"] + norm_transcripts + + segments, stride = get_alignments( + args.audio_filepath, + tokens, + model, + dictionary, + args.use_star, + ) + # Get spans of each line in input text file + spans = get_spans(tokens, segments) + + os.makedirs(args.outdir) + with open( f"{args.outdir}/manifest.json", "w") as f: + for i, t in enumerate(transcripts): + span = spans[i] + seg_start_idx = span[0].start + seg_end_idx = span[-1].end + + output_file = f"{args.outdir}/segment{i}.flac" + + audio_start_sec = seg_start_idx * stride / 1000 + audio_end_sec = seg_end_idx * stride / 1000 + + tfm = sox.Transformer() + tfm.trim(audio_start_sec , audio_end_sec) + tfm.build_file(args.audio_filepath, output_file) + + sample = { + "audio_start_sec": audio_start_sec, + "audio_filepath": str(output_file), + "duration": audio_end_sec - audio_start_sec, + "text": t, + "normalized_text":norm_transcripts[i], + "uroman_tokens": tokens[i], + } + f.write(json.dumps(sample) + "\n") + + return segments, stride + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Align and segment long audio files") + parser.add_argument( + "-a", "--audio_filepath", type=str, help="Path to input audio file" + ) + parser.add_argument( + "-t", "--text_filepath", type=str, help="Path to input text file " + ) + parser.add_argument( + "-l", "--lang", type=str, default="eng", help="ISO code of the language" + ) + parser.add_argument( + "-u", "--uroman_path", type=str, default="eng", help="Location to uroman/bin" + ) + parser.add_argument( + "-s", + "--use_star", + action="store_true", + help="Use star at the start of transcript", + ) + parser.add_argument( + "-o", + "--outdir", + type=str, + help="Output directory to store segmented audio files", + ) + print("Using torch version:", torch.__version__) + print("Using torchaudio version:", torchaudio.__version__) + print("Using device: ", DEVICE) + args = parser.parse_args() + main(args) diff --git a/examples/mms/data_prep/align_utils.py b/examples/mms/data_prep/align_utils.py new file mode 100644 index 0000000000..e9ecc2646e --- /dev/null +++ b/examples/mms/data_prep/align_utils.py @@ -0,0 +1,176 @@ +import re +import os +import torch +import tempfile +import math +from dataclasses import dataclass +from torchaudio.models import wav2vec2_model + +# iso codes with specialized rules in uroman +special_isos_uroman = "ara, bel, bul, deu, ell, eng, fas, grc, ell, eng, heb, kaz, kir, lav, lit, mkd, mkd2, oss, pnt, pus, rus, srp, srp2, tur, uig, ukr, yid".split(",") +special_isos_uroman = [i.strip() for i in special_isos_uroman] + +def normalize_uroman(text): + text = text.lower() + text = re.sub("([^a-z' ])", " ", text) + text = re.sub(' +', ' ', text) + return text.strip() + + +def get_uroman_tokens(norm_transcripts, uroman_root_dir, iso = None): + tf = tempfile.NamedTemporaryFile() + tf2 = tempfile.NamedTemporaryFile() + with open(tf.name, "w") as f: + for t in norm_transcripts: + f.write(t + "\n") + + assert os.path.exists(f"{uroman_root_dir}/uroman.pl"), "uroman not found" + cmd = f"perl {uroman_root_dir}/uroman.pl" + if iso in special_isos_uroman: + cmd += f" -l {iso} " + cmd += f" < {tf.name} > {tf2.name}" + os.system(cmd) + outtexts = [] + with open(tf2.name) as f: + for line in f: + line = " ".join(line.strip()) + line = re.sub(r"\s+", " ", line).strip() + outtexts.append(line) + assert len(outtexts) == len(norm_transcripts) + uromans = [] + for ot in outtexts: + uromans.append(normalize_uroman(ot)) + return uromans + + + +@dataclass +class Segment: + label: str + start: int + end: int + + def __repr__(self): + return f"{self.label}: [{self.start:5d}, {self.end:5d})" + + @property + def length(self): + return self.end - self.start + + +def merge_repeats(path, idx_to_token_map): + i1, i2 = 0, 0 + segments = [] + while i1 < len(path): + while i2 < len(path) and path[i1] == path[i2]: + i2 += 1 + segments.append(Segment(idx_to_token_map[path[i1]], i1, i2 - 1)) + i1 = i2 + return segments + + +def time_to_frame(time): + stride_msec = 20 + frames_per_sec = 1000 / stride_msec + return int(time * frames_per_sec) + + + +def load_model_dict(): + model_path_name = "/tmp/ctc_alignment_mling_uroman_model.pt" + + print("Downloading model and dictionary...") + if os.path.exists(model_path_name): + print("Model path already exists. Skipping downloading....") + else: + torch.hub.download_url_to_file( + "https://dl.fbaipublicfiles.com/mms/torchaudio/ctc_alignment_mling_uroman/model.pt", + model_path_name, + ) + assert os.path.exists(model_path_name) + state_dict = torch.load(model_path_name, map_location="cpu") + + model = wav2vec2_model( + extractor_mode="layer_norm", + extractor_conv_layer_config=[ + (512, 10, 5), + (512, 3, 2), + (512, 3, 2), + (512, 3, 2), + (512, 3, 2), + (512, 2, 2), + (512, 2, 2), + ], + extractor_conv_bias=True, + encoder_embed_dim=1024, + encoder_projection_dropout=0.0, + encoder_pos_conv_kernel=128, + encoder_pos_conv_groups=16, + encoder_num_layers=24, + encoder_num_heads=16, + encoder_attention_dropout=0.0, + encoder_ff_interm_features=4096, + encoder_ff_interm_dropout=0.1, + encoder_dropout=0.0, + encoder_layer_norm_first=True, + encoder_layer_drop=0.1, + aux_num_out=31, + ) + model.load_state_dict(state_dict) + model.eval() + + dict_path_name = "/tmp/ctc_alignment_mling_uroman_model.dict" + if os.path.exists(dict_path_name): + print("Dictionary path already exists. Skipping downloading....") + else: + torch.hub.download_url_to_file( + "https://dl.fbaipublicfiles.com/mms/torchaudio/ctc_alignment_mling_uroman/dictionary.txt", + dict_path_name, + ) + assert os.path.exists(dict_path_name) + dictionary = {} + with open(dict_path_name) as f: + dictionary = {l.strip(): i for i, l in enumerate(f.readlines())} + + return model, dictionary + +def get_spans(tokens, segments): + ltr_idx = 0 + tokens_idx = 0 + intervals = [] + start, end = (0, 0) + sil = "<blank>" + for (seg_idx, seg) in enumerate(segments): + if(tokens_idx == len(tokens)): + assert(seg_idx == len(segments) - 1) + assert(seg.label == '<blank>') + continue + cur_token = tokens[tokens_idx].split(' ') + ltr = cur_token[ltr_idx] + if seg.label == "<blank>": continue + assert(seg.label == ltr) + if(ltr_idx) == 0: start = seg_idx + if ltr_idx == len(cur_token) - 1: + ltr_idx = 0 + tokens_idx += 1 + intervals.append((start, seg_idx)) + while tokens_idx < len(tokens) and len(tokens[tokens_idx]) == 0: + intervals.append((seg_idx, seg_idx)) + tokens_idx += 1 + else: + ltr_idx += 1 + spans = [] + for (idx, (start, end)) in enumerate(intervals): + span = segments[start:end + 1] + if start > 0: + prev_seg = segments[start - 1] + if prev_seg.label == sil: + pad_start = prev_seg.start if (idx == 0) else int((prev_seg.start + prev_seg.end)/2) + span = [Segment(sil, pad_start, span[0].start)] + span + if end+1 < len(segments): + next_seg = segments[end+1] + if next_seg.label == sil: + pad_end = next_seg.end if (idx == len(intervals) - 1) else math.floor((next_seg.start + next_seg.end) / 2) + span = span + [Segment(sil, span[-1].end, pad_end)] + spans.append(span) + return spans diff --git a/examples/mms/data_prep/norm_config.py b/examples/mms/data_prep/norm_config.py new file mode 100644 index 0000000000..08a3219cbe --- /dev/null +++ b/examples/mms/data_prep/norm_config.py @@ -0,0 +1,277 @@ +import os +import re + + +colon = ":" +comma = "," +exclamation_mark = "!" +period = re.escape(".") +question_mark = re.escape("?") +semicolon = ";" + +left_curly_bracket = "{" +right_curly_bracket = "}" +quotation_mark = '"' + +basic_punc = ( + period + + question_mark + + comma + + colon + + exclamation_mark + + left_curly_bracket + + right_curly_bracket +) + +# General punc unicode block (0x2000-0x206F) +zero_width_space = r"\u200B" +zero_width_nonjoiner = r"\u200C" +left_to_right_mark = r"\u200E" +right_to_left_mark = r"\u200F" +left_to_right_embedding = r"\u202A" +pop_directional_formatting = r"\u202C" + +# Here are some commonly ill-typed versions of apostrophe +right_single_quotation_mark = r"\u2019" +left_single_quotation_mark = r"\u2018" + +# Language specific definitions +# Spanish +inverted_exclamation_mark = r"\u00A1" +inverted_question_mark = r"\u00BF" + + +# Hindi +hindi_danda = u"\u0964" + +# Egyptian Arabic +# arabic_percent = r"\u066A" +arabic_comma = r"\u060C" +arabic_question_mark = r"\u061F" +arabic_semicolon = r"\u061B" +arabic_diacritics = r"\u064B-\u0652" + + +arabic_subscript_alef_and_inverted_damma = r"\u0656-\u0657" + + +# Chinese +full_stop = r"\u3002" +full_comma = r"\uFF0C" +full_exclamation_mark = r"\uFF01" +full_question_mark = r"\uFF1F" +full_semicolon = r"\uFF1B" +full_colon = r"\uFF1A" +full_parentheses = r"\uFF08\uFF09" +quotation_mark_horizontal = r"\u300C-\u300F" +quotation_mark_vertical = r"\uFF41-\uFF44" +title_marks = r"\u3008-\u300B" +wavy_low_line = r"\uFE4F" +ellipsis = r"\u22EF" +enumeration_comma = r"\u3001" +hyphenation_point = r"\u2027" +forward_slash = r"\uFF0F" +wavy_dash = r"\uFF5E" +box_drawings_light_horizontal = r"\u2500" +fullwidth_low_line = r"\uFF3F" +chinese_punc = ( + full_stop + + full_comma + + full_exclamation_mark + + full_question_mark + + full_semicolon + + full_colon + + full_parentheses + + quotation_mark_horizontal + + quotation_mark_vertical + + title_marks + + wavy_low_line + + ellipsis + + enumeration_comma + + hyphenation_point + + forward_slash + + wavy_dash + + box_drawings_light_horizontal + + fullwidth_low_line +) + +# Armenian +armenian_apostrophe = r"\u055A" +emphasis_mark = r"\u055B" +exclamation_mark = r"\u055C" +armenian_comma = r"\u055D" +armenian_question_mark = r"\u055E" +abbreviation_mark = r"\u055F" +armenian_full_stop = r"\u0589" +armenian_punc = ( + armenian_apostrophe + + emphasis_mark + + exclamation_mark + + armenian_comma + + armenian_question_mark + + abbreviation_mark + + armenian_full_stop +) + +lesser_than_symbol = r"<" +greater_than_symbol = r">" + +lesser_than_sign = r"\u003c" +greater_than_sign = r"\u003e" + +nbsp_written_form = r" " + +# Quotation marks +left_double_quotes = r"\u201c" +right_double_quotes = r"\u201d" +left_double_angle = r"\u00ab" +right_double_angle = r"\u00bb" +left_single_angle = r"\u2039" +right_single_angle = r"\u203a" +low_double_quotes = r"\u201e" +low_single_quotes = r"\u201a" +high_double_quotes = r"\u201f" +high_single_quotes = r"\u201b" + +all_punct_quotes = ( + left_double_quotes + + right_double_quotes + + left_double_angle + + right_double_angle + + left_single_angle + + right_single_angle + + low_double_quotes + + low_single_quotes + + high_double_quotes + + high_single_quotes + + right_single_quotation_mark + + left_single_quotation_mark +) +mapping_quotes = ( + "[" + + high_single_quotes + + right_single_quotation_mark + + left_single_quotation_mark + + "]" +) + + +# Digits + +english_digits = r"\u0030-\u0039" +bengali_digits = r"\u09e6-\u09ef" +khmer_digits = r"\u17e0-\u17e9" +devanagari_digits = r"\u0966-\u096f" +oriya_digits = r"\u0b66-\u0b6f" +extended_arabic_indic_digits = r"\u06f0-\u06f9" +kayah_li_digits = r"\ua900-\ua909" +fullwidth_digits = r"\uff10-\uff19" +malayam_digits = r"\u0d66-\u0d6f" +myanmar_digits = r"\u1040-\u1049" +roman_numeral = r"\u2170-\u2179" +nominal_digit_shapes = r"\u206f" + +# Load punctuations from MMS-lab data +with open(f"{os.path.dirname(__file__)}/punctuations.lst", "r") as punc_f: + punc_list = punc_f.readlines() + +punct_pattern = r"" +for punc in punc_list: + # the first character in the tab separated line is the punc to be removed + punct_pattern += re.escape(punc.split("\t")[0]) + +shared_digits = ( + english_digits + + bengali_digits + + khmer_digits + + devanagari_digits + + oriya_digits + + extended_arabic_indic_digits + + kayah_li_digits + + fullwidth_digits + + malayam_digits + + myanmar_digits + + roman_numeral + + nominal_digit_shapes +) + +shared_punc_list = ( + basic_punc + + all_punct_quotes + + greater_than_sign + + lesser_than_sign + + inverted_question_mark + + full_stop + + semicolon + + armenian_punc + + inverted_exclamation_mark + + arabic_comma + + enumeration_comma + + hindi_danda + + quotation_mark + + arabic_semicolon + + arabic_question_mark + + chinese_punc + + punct_pattern + +) + +shared_mappping = { + lesser_than_symbol: "", + greater_than_symbol: "", + nbsp_written_form: "", + r"(\S+)" + mapping_quotes + r"(\S+)": r"\1'\2", +} + +shared_deletion_list = ( + left_to_right_mark + + zero_width_nonjoiner + + arabic_subscript_alef_and_inverted_damma + + zero_width_space + + arabic_diacritics + + pop_directional_formatting + + right_to_left_mark + + left_to_right_embedding +) + +norm_config = { + "*": { + "lower_case": True, + "punc_set": shared_punc_list, + "del_set": shared_deletion_list, + "mapping": shared_mappping, + "digit_set": shared_digits, + "unicode_norm": "NFKC", + "rm_diacritics" : False, + } +} + +#=============== Mongolian ===============# + +norm_config["mon"] = norm_config["*"].copy() +# add soft hyphen to punc list to match with fleurs +norm_config["mon"]["del_set"] += r"\u00AD" + +norm_config["khk"] = norm_config["mon"].copy() + +#=============== Hebrew ===============# + +norm_config["heb"] = norm_config["*"].copy() +# add "HEBREW POINT" symbols to match with fleurs +norm_config["heb"]["del_set"] += r"\u05B0-\u05BF\u05C0-\u05CF" + +#=============== Thai ===============# + +norm_config["tha"] = norm_config["*"].copy() +# add "Zero width joiner" symbols to match with fleurs +norm_config["tha"]["punc_set"] += r"\u200D" + +#=============== Arabic ===============# +norm_config["ara"] = norm_config["*"].copy() +norm_config["ara"]["mapping"]["ٱ"] = "ا" +norm_config["arb"] = norm_config["ara"].copy() + +#=============== Javanese ===============# +norm_config["jav"] = norm_config["*"].copy() +norm_config["jav"]["rm_diacritics"] = True + diff --git a/examples/mms/data_prep/punctuations.lst b/examples/mms/data_prep/punctuations.lst new file mode 100644 index 0000000000..f002b3553c --- /dev/null +++ b/examples/mms/data_prep/punctuations.lst @@ -0,0 +1,188 @@ + 7355 INVALID UNICODE 0x81 + 5265 INVALID UNICODE 0x90 + 75 INVALID UNICODE 0x8 + 31 INVALID UNICODE 0x8d +” 3 INVALID UNICODE 0x94 + 2 INVALID UNICODE 0x8f + 2 INVALID UNICODE 0x1a + 1 INVALID UNICODE 0x9d +“ 1 INVALID UNICODE 0x93 +’ 1 INVALID UNICODE 0x92 + 8647 INVALID UNICODE 0xe295 + 6650 INVALID UNICODE 0xf21d + 6234 INVALID UNICODE 0xf62d + 4815 INVALID UNICODE 0xf173 + 4789 INVALID UNICODE 0xe514 + 4409 INVALID UNICODE 0xe293 + 3881 INVALID UNICODE 0xf523 + 3788 INVALID UNICODE 0xe233 + 2448 INVALID UNICODE 0xf50f + 2177 INVALID UNICODE 0xe232 + 1955 INVALID UNICODE 0xea7b + 1926 INVALID UNICODE 0xf172 + 973 INVALID UNICODE 0xe290 + 972 INVALID UNICODE 0xf519 + 661 INVALID UNICODE 0xe292 + 591 INVALID UNICODE 0xe328 + 509 INVALID UNICODE 0xe2fa + 458 INVALID UNICODE 0xe234 + 446 INVALID UNICODE 0xe043 + 419 INVALID UNICODE 0xe040 + 399 INVALID UNICODE 0xe2fb + 387 INVALID UNICODE 0xe32b + 381 INVALID UNICODE 0xe236 + 374 INVALID UNICODE 0xf511 + 314 INVALID UNICODE 0xe517 + 296 INVALID UNICODE 0xe2fe + 293 INVALID UNICODE 0xe492 + 291 INVALID UNICODE 0xf52d + 289 INVALID UNICODE 0xe2fc + 195 INVALID UNICODE 0xf521 + 190 INVALID UNICODE 0xe516 + 182 INVALID UNICODE 0xe041 + 178 INVALID UNICODE 0xf529 + 113 INVALID UNICODE 0xe2f9 + 87 INVALID UNICODE 0xe2d9 + 78 INVALID UNICODE 0xe32a + 76 INVALID UNICODE 0xe291 + 74 INVALID UNICODE 0xe296 + 66 INVALID UNICODE 0xe518 + 52 INVALID UNICODE 0xe32c + 46 INVALID UNICODE 0xe2db + 41 INVALID UNICODE 0xe231 + 34 INVALID UNICODE 0xf522 + 33 INVALID UNICODE 0xf518 + 32 INVALID UNICODE 0xf513 + 27 INVALID UNICODE 0xe32d + 25 INVALID UNICODE 0xe32e + 23 INVALID UNICODE 0xe06b + 15 INVALID UNICODE 0xea01 + 12 INVALID UNICODE 0xe294 + 11 INVALID UNICODE 0xe203 + 8 INVALID UNICODE 0xf218 + 7 INVALID UNICODE 0xe070 + 7 INVALID UNICODE 0xe013 + 5 INVALID UNICODE 0xe2de + 4 INVALID UNICODE 0xe493 + 3 INVALID UNICODE 0xf7e8 + 3 INVALID UNICODE 0xf7d0 + 3 INVALID UNICODE 0xe313 + 2 INVALID UNICODE 0xe329 + 2 INVALID UNICODE 0xe06d + 2 INVALID UNICODE 0xe003 + 1 INVALID UNICODE 0xf50e + 1 INVALID UNICODE 0xf171 + 1 INVALID UNICODE 0xe01d + 71 NOMINAL DIGIT SHAPES 0x206f +⁠ 3 WORD JOINER 0x2060 +― 126545 HORIZONTAL BAR 0x2015 +־ 1028 HEBREW PUNCTUATION MAQAF 0x5be +) 98429 RIGHT PARENTHESIS 0x29 +] 27108 RIGHT SQUARE BRACKET 0x5d +⌋ 1567 RIGHT FLOOR 0x230b +〕 97 RIGHT TORTOISE SHELL BRACKET 0x3015 +】 36 RIGHT BLACK LENTICULAR BRACKET 0x3011 +﴾ 14 ORNATE LEFT PARENTHESIS 0xfd3e +& 170517 AMPERSAND 0x26 +། 106330 TIBETAN MARK SHAD 0xf0d +። 90203 ETHIOPIC FULL STOP 0x1362 +፥ 60484 ETHIOPIC COLON 0x1365 +༌ 60464 TIBETAN MARK DELIMITER TSHEG BSTAR 0xf0c +။ 51567 MYANMAR SIGN SECTION 0x104b +/ 46929 SOLIDUS 0x2f +၊ 38042 MYANMAR SIGN LITTLE SECTION 0x104a +· 37985 MIDDLE DOT 0xb7 +‸ 36310 CARET 0x2038 +* 34793 ASTERISK 0x2a +۔ 32432 ARABIC FULL STOP 0x6d4 +፤ 31906 ETHIOPIC SEMICOLON 0x1364 +၏ 21519 MYANMAR SYMBOL GENITIVE 0x104f +។ 20834 KHMER SIGN KHAN 0x17d4 +꓾ 15773 LISU PUNCTUATION COMMA 0xa4fe +᙮ 13473 CANADIAN SYLLABICS FULL STOP 0x166e +꤯ 12892 KAYAH LI SIGN SHYA 0xa92f +⵰ 11478 TIFINAGH SEPARATOR MARK 0x2d70 +꓿ 11118 LISU PUNCTUATION FULL STOP 0xa4ff +॥ 10763 DEVANAGARI DOUBLE DANDA 0x965 +؞ 10403 ARABIC TRIPLE DOT PUNCTUATION MARK 0x61e +၍ 8936 MYANMAR SYMBOL COMPLETED 0x104d +· 8431 GREEK ANO TELEIA 0x387 +† 7477 DAGGER 0x2020 +၌ 6632 MYANMAR SYMBOL LOCATIVE 0x104c +፣ 5719 ETHIOPIC COMMA 0x1363 +៖ 5528 KHMER SIGN CAMNUC PII KUUH 0x17d6 +꤮ 4791 KAYAH LI SIGN CWI 0xa92e +※ 3439 REFERENCE MARK 0x203b +፦ 2727 ETHIOPIC PREFACE COLON 0x1366 +• 1749 BULLET 0x2022 +¶ 1507 PILCROW SIGN 0xb6 +၎ 1386 MYANMAR SYMBOL AFOREMENTIONED 0x104e +﹖ 1224 SMALL QUESTION MARK 0xfe56 +; 975 GREEK QUESTION MARK 0x37e +… 827 HORIZONTAL ELLIPSIS 0x2026 +% 617 PERCENT SIGN 0x25 +・ 468 KATAKANA MIDDLE DOT 0x30fb +༎ 306 TIBETAN MARK NYIS SHAD 0xf0e +‡ 140 DOUBLE DAGGER 0x2021 +# 137 NUMBER SIGN 0x23 +@ 125 COMMERCIAL AT 0x40 +፡ 121 ETHIOPIC WORDSPACE 0x1361 +៚ 55 KHMER SIGN KOOMUUT 0x17da +៕ 49 KHMER SIGN BARIYOOSAN 0x17d5 +﹐ 10 SMALL COMMA 0xfe50 +༅ 6 TIBETAN MARK CLOSING YIG MGO SGAB MA 0xf05 +༄ 6 TIBETAN MARK INITIAL YIG MGO MDUN MA 0xf04 +. 2 FULLWIDTH FULL STOP 0xff0e +﹗ 2 SMALL EXCLAMATION MARK 0xfe57 +﹕ 2 SMALL COLON 0xfe55 +‰ 2 PER MILLE SIGN 0x2030 +・ 1 HALFWIDTH KATAKANA MIDDLE DOT 0xff65 +( 98504 LEFT PARENTHESIS 0x28 +[ 27245 LEFT SQUARE BRACKET 0x5b +⌊ 1567 LEFT FLOOR 0x230a +〔 95 LEFT TORTOISE SHELL BRACKET 0x3014 +【 36 LEFT BLACK LENTICULAR BRACKET 0x3010 +﴿ 14 ORNATE RIGHT PARENTHESIS 0xfd3f +_ 4851 LOW LINE 0x5f +$ 72 DOLLAR SIGN 0x24 +€ 14 EURO SIGN 0x20ac +£ 2 POUND SIGN 0xa3 +~ 27462 TILDE 0x7e += 11450 EQUALS SIGN 0x3d +| 8430 VERTICAL LINE 0x7c +− 3971 MINUS SIGN 0x2212 +≫ 1904 MUCH GREATER-THAN 0x226b +≪ 1903 MUCH LESS-THAN 0x226a ++ 1450 PLUS SIGN 0x2b +< 345 FULLWIDTH LESS-THAN SIGN 0xff1c +> 344 FULLWIDTH GREATER-THAN SIGN 0xff1e +¬ 5 NOT SIGN 0xac +× 4 MULTIPLICATION SIGN 0xd7 +→ 2 RIGHTWARDS ARROW 0x2192 +᙭ 537 CANADIAN SYLLABICS CHI SIGN 0x166d +° 499 DEGREE SIGN 0xb0 +႟ 421 MYANMAR SYMBOL SHAN EXCLAMATION 0x109f +� 192 REPLACEMENT CHARACTER 0xfffd +⌟ 54 BOTTOM RIGHT CORNER 0x231f +⌞ 54 BOTTOM LEFT CORNER 0x231e +© 2 COPYRIGHT SIGN 0xa9 +  40 NARROW NO-BREAK SPACE 0x202f +  1 SIX-PER-EM SPACE 0x2006 +˜ 40261 SMALL TILDE 0x2dc +^ 6469 CIRCUMFLEX ACCENT 0x5e +¯ 20 MACRON 0xaf +ˇ 191442 CARON 0x2c7 +ⁿ 38144 SUPERSCRIPT LATIN SMALL LETTER N 0x207f +ـ 9440 ARABIC TATWEEL 0x640 +ๆ 6766 THAI CHARACTER MAIYAMOK 0xe46 +ៗ 3310 KHMER SIGN LEK TOO 0x17d7 +々 678 IDEOGRAPHIC ITERATION MARK 0x3005 +ໆ 430 LAO KO LA 0xec6 +ー 319 KATAKANA-HIRAGANA PROLONGED SOUND MARK 0x30fc +ⁱ 137 SUPERSCRIPT LATIN SMALL LETTER I 0x2071 +৷ 11056 BENGALI CURRENCY NUMERATOR FOUR 0x9f7 +⅓ 26 VULGAR FRACTION ONE THIRD 0x2153 +½ 26 VULGAR FRACTION ONE HALF 0xbd +¼ 4 VULGAR FRACTION ONE QUARTER 0xbc +⅟ 1 FRACTION NUMERATOR ONE 0x215f +⁄ 57 FRACTION SLASH 0x2044 diff --git a/examples/mms/data_prep/text_normalization.py b/examples/mms/data_prep/text_normalization.py new file mode 100644 index 0000000000..c588727e55 --- /dev/null +++ b/examples/mms/data_prep/text_normalization.py @@ -0,0 +1,92 @@ +import json +import re +import unicodedata + +from examples.mms.data_prep.norm_config import norm_config + + +def text_normalize(text, iso_code, lower_case=True, remove_numbers=True, remove_brackets=False): + + """Given a text, normalize it by changing to lower case, removing punctuations, removing words that only contain digits and removing extra spaces + + Args: + text : The string to be normalized + iso_code : + remove_numbers : Boolean flag to specify if words containing only digits should be removed + + Returns: + normalized_text : the string after all normalization + + """ + + config = norm_config.get(iso_code, norm_config["*"]) + + for field in ["lower_case", "punc_set","del_set", "mapping", "digit_set", "unicode_norm"]: + if field not in config: + config[field] = norm_config["*"][field] + + + text = unicodedata.normalize(config["unicode_norm"], text) + + # Convert to lower case + + if config["lower_case"] and lower_case: + text = text.lower() + + # brackets + + # always text inside brackets with numbers in them. Usually corresponds to "(Sam 23:17)" + text = re.sub(r"\([^\)]*\d[^\)]*\)", " ", text) + if remove_brackets: + text = re.sub(r"\([^\)]*\)", " ", text) + + # Apply mappings + + for old, new in config["mapping"].items(): + text = re.sub(old, new, text) + + # Replace punctutations with space + + punct_pattern = r"[" + config["punc_set"] + + punct_pattern += "]" + + normalized_text = re.sub(punct_pattern, " ", text) + + # remove characters in delete list + + delete_patten = r"[" + config["del_set"] + "]" + + normalized_text = re.sub(delete_patten, "", normalized_text) + + # Remove words containing only digits + # We check for 3 cases a)text starts with a number b) a number is present somewhere in the middle of the text c) the text ends with a number + # For each case we use lookaround regex pattern to see if the digit pattern in preceded and followed by whitespaces, only then we replace the numbers with space + # The lookaround enables overlapping pattern matches to be replaced + + if remove_numbers: + + digits_pattern = "[" + config["digit_set"] + + digits_pattern += "]+" + + complete_digit_pattern = ( + r"^" + + digits_pattern + + "(?=\s)|(?<=\s)" + + digits_pattern + + "(?=\s)|(?<=\s)" + + digits_pattern + + "$" + ) + + normalized_text = re.sub(complete_digit_pattern, " ", normalized_text) + + if config["rm_diacritics"]: + from unidecode import unidecode + normalized_text = unidecode(normalized_text) + + # Remove extra spaces + normalized_text = re.sub(r"\s+", " ", normalized_text).strip() + + return normalized_text diff --git a/examples/mms/lid/infer.py b/examples/mms/lid/infer.py new file mode 100644 index 0000000000..735edcc4c7 --- /dev/null +++ b/examples/mms/lid/infer.py @@ -0,0 +1,197 @@ +import torch +from fairseq.data.text_compressor import TextCompressionLevel, TextCompressor +from fairseq import checkpoint_utils, distributed_utils, options, utils +from fairseq import checkpoint_utils, data, options, tasks +from fairseq.data import FileAudioDataset, AddTargetDataset, Dictionary +from fairseq.tasks.audio_classification import LabelEncoder +import copy +from tqdm import tqdm +import tempfile +import numpy as np +import json + + +def subset_manifest(infer_manifest, veri_pair): + with open(infer_manifest) as ff, open(veri_pair) as gg, tempfile.NamedTemporaryFile( + "w", delete=False + ) as ww: + fnames = ff.read().strip().split("\n") + basedir = fnames[0] + needed_fname = [] + for gi in gg.read().strip().split("\n"): + _, x1, x2 = gi.split() + needed_fname.append(x1) + needed_fname.append(x2) + needed_fname = set(needed_fname) + + ww.write(basedir + "\n") + for ii in range(1, len(fnames)): + x1, x2 = fnames[ii].split() + if x1 in needed_fname: + ww.write(fnames[ii] + "\n") + print(f"| subset manifest for verification: {ww.name}") + return ww.name + + +def wrap_target_dataset(infer_manifest, dataset, task): + label_path = infer_manifest.replace(".tsv", ".lang") + text_compressor = TextCompressor(level=TextCompressionLevel.none) + with open(label_path, "r") as f: + labels = [text_compressor.compress(l) for i,l in enumerate(f)] + assert len(labels) == len(dataset) + + process_label = LabelEncoder(task.target_dictionary) + dataset = AddTargetDataset( + dataset, + labels, + pad=task.target_dictionary.pad(), + eos=task.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + add_to_input=False, + ) + return dataset + + +def resample_data(source, padding_mask, n_sample, max_sample_len): + # source: BxT + # padding_mask: BxT + B = source.shape[0] + T = source.shape[1] + sources = [] + padding_masks = [] + if B == 1: + return [source], [None] + seq_len = (~padding_mask).sum(1) + for jj in range(n_sample): + new_source = source.new_zeros(B, max_sample_len) + new_padding_mask = padding_mask.new_zeros(B, max_sample_len) + for ii in range(B): + if seq_len[ii] > max_sample_len: + start = np.random.randint(0, seq_len[ii] - max_sample_len + 1) + end = start + max_sample_len + else: + start = 0 + end = seq_len[ii] + new_source[ii, 0 : end - start] = source[ii, start:end] + new_padding_mask[ii, end - start + 1 :] = True + sources.append(new_source) + padding_masks.append(new_padding_mask) + return sources, padding_masks + + +def resample_sample(sample, n_sample, max_sample_len): + new_sources, new_padding_masks = resample_data( + sample["net_input"]["source"], + sample["net_input"]["padding_mask"], + n_sample, + max_sample_len, + ) + new_samples = [] + for ii in range(n_sample): + new_sample = copy.deepcopy(sample) + new_sample["net_input"]["source"] = new_sources[ii] + new_sample["net_input"]["padding_mask"] = new_padding_masks[ii] + new_samples.append(new_sample) + return new_samples + + +def dict_to_nparr(dd): + dict_class = [] + dict_idx = [] + for ii, jj in enumerate(dd.symbols): + dict_idx.append(ii) + dict_class.append(jj) + dict_idx = np.array(dict_idx) + dict_class = np.array(dict_class) + return dict_class, dict_idx + + +if __name__ == "__main__": + np.random.seed(123) + # Parse command-line arguments for generation + parser = options.get_generation_parser(default_task="audio_classification") + # parser.add_argument('--infer-merge', type=str, default='mean') + parser.add_argument("--infer-xtimes", type=int, default=1) + parser.add_argument("--infer-num-samples", type=int, default=None) + parser.add_argument("--top-k", type=int, default=3) + parser.add_argument( + "--infer-max-sample-size", type=int, default=5 * 16000 + ) # 5 secs + parser.add_argument("--infer-manifest", required=True, type=str) + parser.add_argument("--output-path", default="/tmp/", type=str) + + args = options.parse_args_and_arch(parser) + # Setup task + # task = tasks.setup_task(args) + use_cuda = not args.cpu + + # Load model & task + print("| loading model from {}".format(args.path)) + arg_overrides = { + "task": { + "data": args.data + }, + # 'mask_prob': 0 + #'max_sample_size': sys.maxsize, + #'min_sample_size': 0, + } + state = checkpoint_utils.load_checkpoint_to_cpu(args.path, arg_overrides) + + models, _model_args, task = checkpoint_utils.load_model_ensemble_and_task( + [args.path], arg_overrides=arg_overrides, task=None, state=state + ) + model = models[0] + model.eval() + if use_cuda: + model.cuda() + # Load dataset + + dict_class, dict_idx = dict_to_nparr(task.target_dictionary) + + infer_manifest = args.infer_manifest + infer_dataset = FileAudioDataset( + infer_manifest, + sample_rate=task.cfg.sample_rate, + max_sample_size=10**10, # task.cfg.max_sample_size, + min_sample_size=1, # task.cfg.min_sample_size, + pad=True, + normalize=task.cfg.normalize, + ) + # add target (if needed) + infer_dataset = wrap_target_dataset(infer_manifest, infer_dataset, task) + + itr = task.get_batch_iterator( + dataset=infer_dataset, + max_sentences=1, + # max_tokens=args.max_tokens, + num_workers=4, + ).next_epoch_itr(shuffle=False) + predictions = {} + with torch.no_grad(): + for _, sample in tqdm(enumerate(itr)): + # resample if needed + samples = resample_sample( + sample, args.infer_xtimes, args.infer_max_sample_size + ) + for sample in samples: + sample = utils.move_to_cuda(sample) if use_cuda else sample + try: + latent = model.forward_latent(**sample["net_input"]) + except: + latent = None + logit = model.forward(**sample["net_input"]) + logit_lsm = torch.log_softmax(logit.squeeze(), dim=-1) + scores, indices = torch.topk(logit_lsm, args.top_k, dim=-1) + scores = torch.exp(scores).to("cpu").tolist() + indices = indices.to("cpu").tolist() + assert sample["id"].numel() == 1 + sample_idx = sample["id"].to("cpu").tolist()[0] + assert sample_idx not in predictions + predictions[sample_idx] = [(task.target_dictionary[int(i)], s) for s, i in zip(scores, indices)] + + with open(f"{args.output_path}/predictions.txt", "w") as fo: + for idx in range(len(infer_dataset)): + fo.write(json.dumps(predictions[idx]) + "\n") + + print(f"Outputs will be located at - {args.output_path}/predictions.txt") diff --git a/examples/mms/tts/infer.py b/examples/mms/tts/infer.py new file mode 100644 index 0000000000..8f6f6277eb --- /dev/null +++ b/examples/mms/tts/infer.py @@ -0,0 +1,102 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import os +import glob +import json +import math +import torch +from torch import nn +from torch.nn import functional as F +from torch.utils.data import DataLoader +import numpy as np +import commons +import utils +import argparse +from data_utils import TextAudioLoader, TextAudioCollate, TextAudioSpeakerLoader, TextAudioSpeakerCollate +from models import SynthesizerTrn +from scipy.io.wavfile import write + +class TextMapper(object): + def __init__(self, vocab_file): + self.symbols = [x.replace("\n", "") for x in open(vocab_file).readlines()] + self.SPACE_ID = self.symbols.index(" ") + self._symbol_to_id = {s: i for i, s in enumerate(self.symbols)} + self._id_to_symbol = {i: s for i, s in enumerate(self.symbols)} + + def text_to_sequence(self, text, cleaner_names): + '''Converts a string of text to a sequence of IDs corresponding to the symbols in the text. + Args: + text: string to convert to a sequence + cleaner_names: names of the cleaner functions to run the text through + Returns: + List of integers corresponding to the symbols in the text + ''' + sequence = [] + clean_text = text.strip() + for symbol in clean_text: + symbol_id = self._symbol_to_id[symbol] + sequence += [symbol_id] + return sequence + + def get_text(self, text, hps): + text_norm = self.text_to_sequence(text, hps.data.text_cleaners) + if hps.data.add_blank: + text_norm = commons.intersperse(text_norm, 0) + text_norm = torch.LongTensor(text_norm) + return text_norm + + def filter_oov(self, text): + val_chars = self._symbol_to_id + txt_filt = "".join(list(filter(lambda x: x in val_chars, text))) + print(f"text after filtering OOV: {txt_filt}") + return txt_filt + +def generate(): + parser = argparse.ArgumentParser(description='TTS inference') + parser.add_argument('--model-dir', type=str, help='model checkpoint dir') + parser.add_argument('--wav', type=str, help='output wav path') + parser.add_argument('--txt', type=str, help='input text') + args = parser.parse_args() + ckpt_dir, wav_path, txt = args.model_dir, args.wav, args.txt + + vocab_file = f"{ckpt_dir}/vocab.txt" + config_file = f"{ckpt_dir}/config.json" + assert os.path.isfile(config_file), f"{config_file} doesn't exist" + hps = utils.get_hparams_from_file(config_file) + text_mapper = TextMapper(vocab_file) + net_g = SynthesizerTrn( + len(text_mapper.symbols), + hps.data.filter_length // 2 + 1, + hps.train.segment_size // hps.data.hop_length, + **hps.model) + net_g.cuda() + _ = net_g.eval() + + g_pth = f"{ckpt_dir}/G_100000.pth" + print(f"load {g_pth}") + + _ = utils.load_checkpoint(g_pth, net_g, None) + + print(f"text: {txt}") + txt = txt.lower() + txt = text_mapper.filter_oov(txt) + stn_tst = text_mapper.get_text(txt, hps) + with torch.no_grad(): + x_tst = stn_tst.unsqueeze(0).cuda() + x_tst_lengths = torch.LongTensor([stn_tst.size(0)]).cuda() + hyp = net_g.infer( + x_tst, x_tst_lengths, noise_scale=.667, + noise_scale_w=0.8, length_scale=1.0 + )[0][0,0].cpu().float().numpy() + + os.makedirs(os.path.dirname(wav_path), exist_ok=True) + print(f"wav: {wav_path}") + write(wav_path, hps.data.sampling_rate, hyp) + return + + +if __name__ == '__main__': + generate() diff --git a/examples/speech_recognition/new/infer.py b/examples/speech_recognition/new/infer.py index e45e76870f..33ed526907 100644 --- a/examples/speech_recognition/new/infer.py +++ b/examples/speech_recognition/new/infer.py @@ -10,6 +10,7 @@ import os import shutil import sys +import re from dataclasses import dataclass, field, is_dataclass from pathlib import Path from typing import Any, Dict, List, Optional, Tuple, Union @@ -101,6 +102,29 @@ def __init__(self, cfg: InferConfig) -> None: self.task = tasks.setup_task(cfg.task) models, saved_cfg = self.load_model_ensemble() + + ### LOAD ADAPTER #### + ckpt_obj = checkpoint_utils.load_checkpoint_to_cpu(self.cfg.common_eval.path) + if "adapter" in ckpt_obj: + target_lang = self.cfg.dataset.gen_subset.split(":")[0] + assert target_lang in ckpt_obj["adapter"] + + logger.info(f">>> LOADING ADAPTER: {target_lang}") + ft_obj = ckpt_obj["adapter"][target_lang] + ft_model = ft_obj["model"] + cdevice = models[0].w2v_encoder.proj.weight.device + cdtype = models[0].w2v_encoder.proj.weight.dtype + ft_proj_out, ft_proj_in = ft_model["w2v_encoder.proj.weight"].shape + ft_proj = torch.nn.Linear(ft_proj_in, ft_proj_out, bias=True) + ft_proj.to(device=cdevice, dtype=cdtype) + models[0].w2v_encoder.proj = ft_proj + with torch.no_grad(): + for kk, vv in models[0].named_parameters(): + if kk in ft_model: + vv.copy_(ft_model[kk]) + self.task.load_state_dict(ft_obj["task_state"]) + # overwrite gen_subset with master config + self.cfg.dataset.gen_subset = re.sub('^[\w-]+:', saved_cfg['task']['multi_corpus_keys']+":", self.cfg.dataset.gen_subset) self.models = models self.saved_cfg = saved_cfg self.tgt_dict = self.task.target_dictionary diff --git a/fairseq/data/audio/raw_audio_dataset.py b/fairseq/data/audio/raw_audio_dataset.py index edb307e68f..ec202d5574 100644 --- a/fairseq/data/audio/raw_audio_dataset.py +++ b/fairseq/data/audio/raw_audio_dataset.py @@ -47,6 +47,7 @@ def __init__( expand_adjacent: bool = False, mask_dropout: float = 0, non_overlapping: bool = False, + corpus_key=None, ): super().__init__() @@ -72,6 +73,7 @@ def __init__( self.expand_adjacent = expand_adjacent self.mask_dropout = mask_dropout self.non_overlapping = non_overlapping + self.corpus_key = corpus_key def __getitem__(self, index): raise NotImplementedError() @@ -144,6 +146,8 @@ def collater(self, samples): collated_sources[i] = self.crop_to_max_size(source, target_size) input = {"source": collated_sources} + if self.corpus_key is not None: + input["corpus_key"] = [self.corpus_key] * len(sources) out = {"id": torch.LongTensor([s["id"] for s in samples])} if self.pad: input["padding_mask"] = padding_mask diff --git a/fairseq/data/dictionary.py b/fairseq/data/dictionary.py index d6495389f0..7ad590a19b 100644 --- a/fairseq/data/dictionary.py +++ b/fairseq/data/dictionary.py @@ -26,19 +26,21 @@ def __init__( eos="</s>", unk="<unk>", extra_special_symbols=None, + add_special_symbols=True, ): self.bos_word, self.unk_word, self.pad_word, self.eos_word = bos, unk, pad, eos self.symbols = [] self.count = [] self.indices = {} - self.bos_index = self.add_symbol(bos) - self.pad_index = self.add_symbol(pad) - self.eos_index = self.add_symbol(eos) - self.unk_index = self.add_symbol(unk) - if extra_special_symbols: - for s in extra_special_symbols: - self.add_symbol(s) - self.nspecial = len(self.symbols) + if add_special_symbols: + self.bos_index = self.add_symbol(bos) + self.pad_index = self.add_symbol(pad) + self.eos_index = self.add_symbol(eos) + self.unk_index = self.add_symbol(unk) + if extra_special_symbols: + for s in extra_special_symbols: + self.add_symbol(s) + self.nspecial = len(self.symbols) def __eq__(self, other): return self.indices == other.indices @@ -213,7 +215,7 @@ def unk(self): return self.unk_index @classmethod - def load(cls, f): + def load(cls, f, add_special_symbols=True): """Loads the dictionary from a text file with the format: ``` @@ -222,7 +224,7 @@ def load(cls, f): ... ``` """ - d = cls() + d = cls(add_special_symbols=add_special_symbols) d.add_from_file(f) return d diff --git a/fairseq/models/wav2vec/__init__.py b/fairseq/models/wav2vec/__init__.py index bacbb7a95d..b756e4580b 100644 --- a/fairseq/models/wav2vec/__init__.py +++ b/fairseq/models/wav2vec/__init__.py @@ -7,3 +7,4 @@ from .wav2vec2 import * # noqa from .wav2vec2_asr import * # noqa from .wav2vec2_laser import * # noqa +from .wav2vec2_classification import * # noqa diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 8214bc8e7a..96b15541a1 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -17,6 +17,7 @@ from fairseq.dataclass import ChoiceEnum, FairseqDataclass from fairseq.distributed import fsdp_wrap from fairseq.models import BaseFairseqModel, register_model +from fairseq.distributed.fully_sharded_data_parallel import FullyShardedDataParallel from fairseq.modules import ( Fp32GroupNorm, Fp32LayerNorm, @@ -37,7 +38,7 @@ EXTRACTOR_MODE_CHOICES = ChoiceEnum(["default", "layer_norm"]) MASKING_DISTRIBUTION_CHOICES = ChoiceEnum(["static", "uniform", "normal", "poisson"]) -LAYER_TYPE_CHOICES = ChoiceEnum(["transformer", "conformer"]) +LAYER_TYPE_CHOICES = ChoiceEnum(["transformer", "conformer", "trf_adp"]) @dataclass @@ -289,6 +290,20 @@ class Wav2Vec2Config(FairseqDataclass): ) fp16: bool = field(default=False, metadata={"help": "If fp16 is being used"}) + # Adapter num + adp_num: int = field( + default=-1 + ) + adp_dim: int = field( + default=64 + ) + adp_act_fn: str = field( + default="relu" + ) + adp_trf_idx: str = field( + default="all", + ) + @register_model("wav2vec2", dataclass=Wav2Vec2Config) class Wav2Vec2Model(BaseFairseqModel): @@ -588,6 +603,7 @@ def forward( mask_indices=None, mask_channel_indices=None, padding_count=None, + corpus_key=None, ): if self.feature_grad_mult > 0: @@ -672,7 +688,9 @@ def forward( y = unmasked_features mask_indices = None - x, layer_results = self.encoder(x, padding_mask=padding_mask, layer=layer) + x, layer_results = self.encoder( + x, padding_mask=padding_mask, layer=layer, corpus_key=corpus_key + ) if features_only: return { @@ -774,9 +792,16 @@ def quantize(self, x): x = self.layer_norm(x) return self.quantizer.forward_idx(x) - def extract_features(self, source, padding_mask, mask=False, layer=None): + def extract_features( + self, source, padding_mask, mask=False, layer=None, corpus_key=None + ): res = self.forward( - source, padding_mask, mask=mask, features_only=True, layer=layer + source, + padding_mask, + mask=mask, + features_only=True, + layer=layer, + corpus_key=corpus_key, ) return res @@ -917,7 +942,7 @@ def make_conv_pos(e, k, g): class TransformerEncoder(nn.Module): - def build_encoder_layer(self, args: Wav2Vec2Config): + def build_encoder_layer(self, args: Wav2Vec2Config, layer_idx: int): if args.layer_type == "transformer": layer = TransformerSentenceEncoderLayer( embedding_dim=self.embedding_dim, @@ -941,6 +966,40 @@ def build_encoder_layer(self, args: Wav2Vec2Config): use_fp16=args.fp16, pos_enc_type="abs", ) + elif args.layer_type == "trf_adp": + use_adp = False + if args.adp_trf_idx == "all": + use_adp = True + else: + adp_trf_idx = list(range(*[int(g) for g in args.adp_trf_idx.split(":")])) + if layer_idx in adp_trf_idx: + use_adp = True + if use_adp: + layer = TransformerSentenceEncoderWithAdapterLayer( + embedding_dim=self.embedding_dim, + ffn_embedding_dim=args.encoder_ffn_embed_dim, + num_attention_heads=args.encoder_attention_heads, + dropout=self.dropout, + attention_dropout=args.attention_dropout, + activation_dropout=args.activation_dropout, + activation_fn=args.activation_fn, + layer_norm_first=args.layer_norm_first, + adapter_num=args.adp_num, + adapter_dim=args.adp_dim, + adapter_act_fn=args.adp_act_fn, + ) + else: + layer = TransformerSentenceEncoderLayer( + embedding_dim=self.embedding_dim, + ffn_embedding_dim=args.encoder_ffn_embed_dim, + num_attention_heads=args.encoder_attention_heads, + dropout=self.dropout, + attention_dropout=args.attention_dropout, + activation_dropout=args.activation_dropout, + activation_fn=args.activation_fn, + layer_norm_first=args.layer_norm_first, + ) + layer = fsdp_wrap(layer) if args.checkpoint_activations: layer = checkpoint_wrapper(layer) @@ -991,7 +1050,7 @@ def make_conv_block(e, k, g, l): ) self.layers = nn.ModuleList( - [self.build_encoder_layer(args) for _ in range(args.encoder_layers)] + [self.build_encoder_layer(args, ii) for ii in range(args.encoder_layers)] ) self.layer_norm_first = args.layer_norm_first self.layer_norm = LayerNorm(self.embedding_dim) @@ -999,8 +1058,10 @@ def make_conv_block(e, k, g, l): self.apply(init_bert_params) - def forward(self, x, padding_mask=None, layer=None): - x, layer_results = self.extract_features(x, padding_mask, layer) + def forward(self, x, padding_mask=None, layer=None, corpus_key=None): + x, layer_results = self.extract_features( + x, padding_mask, layer, corpus_key=corpus_key + ) if self.layer_norm_first and layer is None: x = self.layer_norm(x) @@ -1013,6 +1074,7 @@ def extract_features( padding_mask=None, tgt_layer=None, min_layer=0, + corpus_key=None, ): if padding_mask is not None: @@ -1043,12 +1105,29 @@ def extract_features( layer_results = [] r = None + for i, layer in enumerate(self.layers): dropout_probability = np.random.random() if self.layerdrop > 0 else 1 if not self.training or (dropout_probability > self.layerdrop): - x, (z, lr) = layer( - x, self_attn_padding_mask=padding_mask, need_weights=False - ) + layer_check = layer + if isinstance(layer, FullyShardedDataParallel): + layer_check = layer.unwrapped_module + if (corpus_key is None) or ( + not isinstance(layer_check, ( + TransformerSentenceEncoderWithAdapterLayer, + ) + ) + ): + x, (z, lr) = layer( + x, self_attn_padding_mask=padding_mask, need_weights=False + ) + else: + x, (z, lr) = layer( + x, + self_attn_padding_mask=padding_mask, + need_weights=False, + corpus_key=corpus_key, + ) if i >= min_layer: layer_results.append((x, z, lr)) if i == tgt_layer: @@ -1282,3 +1361,125 @@ def forward( x = self.final_layer_norm(x) return x, (attn, layer_result) + + +class AdapterFast(nn.Module): + def __init__(self, adapter_num, input_dim, hidden_dim, act_fn): + """ + Implements adapter modules directly with 3D tensor weight as parameters + and without using ModuleList orto speed up training throughput. + """ + super().__init__() + + self.adapter_num = adapter_num + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.W_a = nn.Parameter(torch.empty(adapter_num, hidden_dim, input_dim)) + self.W_b = nn.Parameter(torch.empty(adapter_num, input_dim, hidden_dim)) + self.b_a = nn.Parameter(torch.empty(adapter_num, hidden_dim)) + self.b_b = nn.Parameter(torch.empty(adapter_num, input_dim)) + + self.ln_W = nn.Parameter(torch.empty(adapter_num, input_dim)) + self.ln_b = nn.Parameter(torch.empty(adapter_num, input_dim)) + self.act_fn = nn.Identity() + if act_fn == "relu": + self.act_fn = nn.ReLU() + elif act_fn == "gelu": + self.act_fn = nn.GELU() + elif act_fn == "selu": + self.act_fn = nn.SELU() + else: + raise ValueError(f"unsupported {act_fn}") + + + self.input_dim = input_dim + self.reset_parameters() + + def reset_parameters(self): + for ii in range(self.adapter_num): + nn.init.kaiming_uniform_(self.W_a[ii], a=math.sqrt(5)) + nn.init.kaiming_uniform_(self.W_b[ii], a=math.sqrt(5)) + fan_in, _ = nn.init._calculate_fan_in_and_fan_out(self.W_a[ii]) + bound = 1 / math.sqrt(fan_in) if fan_in > 0 else 0 + nn.init.uniform_(self.b_a[ii], -bound, bound) + fan_in, _ = nn.init._calculate_fan_in_and_fan_out(self.W_b[ii]) + bound = 1 / math.sqrt(fan_in) if fan_in > 0 else 0 + nn.init.uniform_(self.b_b[ii], -bound, bound) + + nn.init.ones_(self.ln_W) + nn.init.zeros_(self.ln_b) + + def forward(self, x, adapter_id): + ii = adapter_id + h = x + h = F.layer_norm(h, (self.input_dim, ), self.ln_W[ii], self.ln_b[ii]) + h = F.linear(h, self.W_a[ii], self.b_a[ii]) + h = self.act_fn(h) + h = F.linear(h, self.W_b[ii], self.b_b[ii]) + outputs = h + return outputs + + def extra_repr(self): + return ('adapter={}, input_dim={}, hidden_dim={}'.format(self.adapter_num, self.input_dim, self.hidden_dim)) + + + +class TransformerSentenceEncoderWithAdapterLayer(TransformerSentenceEncoderLayer): + """ + Implements a Transformer Encoder Layer with adapters used in BERT/XLM style pre-trained + models. An adapter module is added along with vanilla Transformer module. + """ + + def __init__( + self, + embedding_dim: float = 768, + ffn_embedding_dim: float = 3072, + num_attention_heads: int = 8, + dropout: float = 0.1, + attention_dropout: float = 0.1, + activation_dropout: float = 0.1, + activation_fn: str = "relu", + layer_norm_first: bool = False, + adapter_num=201, + adapter_dim=64, + adapter_act_fn="relu", + ) -> None: + + super().__init__( + embedding_dim=embedding_dim, + ffn_embedding_dim=ffn_embedding_dim, + num_attention_heads=num_attention_heads, + dropout=dropout, + attention_dropout=attention_dropout, + activation_dropout=activation_dropout, + activation_fn=activation_fn, + layer_norm_first=layer_norm_first, + + ) + + self.adapter_num = adapter_num + self.adapter_dim = adapter_dim + self.adapter_layer = AdapterFast(adapter_num, self.embedding_dim, self.adapter_dim, adapter_act_fn) + + def forward( + self, + x: torch.Tensor, + self_attn_mask: torch.Tensor = None, + self_attn_padding_mask: torch.Tensor = None, + need_weights: bool = False, + att_args=None, + corpus_key=None, + ): + + x, (attn, layer_result) = super().forward( + x=x, + self_attn_mask=self_attn_mask, + self_attn_padding_mask=self_attn_padding_mask, + need_weights=need_weights, + att_args=att_args, + ) + assert corpus_key is not None + assert len(set(corpus_key)) == 1, f"corpus_key items are not same {corpus_key}" + y = self.adapter_layer(x, corpus_key[0]) + x = x + y + return x, (attn, layer_result) diff --git a/fairseq/models/wav2vec/wav2vec2_asr.py b/fairseq/models/wav2vec/wav2vec2_asr.py index bf261624e6..0403efebb9 100644 --- a/fairseq/models/wav2vec/wav2vec2_asr.py +++ b/fairseq/models/wav2vec/wav2vec2_asr.py @@ -28,7 +28,7 @@ FairseqIncrementalDecoder, register_model, ) -from fairseq.models.wav2vec.wav2vec2 import MASKING_DISTRIBUTION_CHOICES +from fairseq.models.wav2vec.wav2vec2 import MASKING_DISTRIBUTION_CHOICES, LAYER_TYPE_CHOICES, AdapterFast from fairseq.modules import LayerNorm, PositionalEmbedding, TransformerDecoderLayer from fairseq.tasks import FairseqTask @@ -178,6 +178,27 @@ class Wav2Vec2AsrConfig(FairseqDataclass): layer_decay: float = 1 + layer_type: LAYER_TYPE_CHOICES = field( + default="transformer", metadata={"help": "layer type in encoder"} + ) + # Adapter num + adp_num: int = field( + default=-1 + ) + adp_dim: int = field( + default=64 + ) + adp_act_fn: str = field( + default="relu" + ) + adp_trf_idx: str = field( + default="all", + ) + + freeze_regex: Optional[str] = field( + default=None, + ) + @dataclass class Wav2Vec2CtcConfig(Wav2Vec2AsrConfig): blank_weight: float = 0 @@ -416,6 +437,14 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): "Please check that --normalize is set or unset for both pre-training and here" ) + with open_dict(w2v_args): + args_replacement = ["checkpoint_activations", "layer_type", + "adp_num", "adp_dim", + "adp_act_fn", "adp_trf_idx"] + for _args in args_replacement: + if hasattr(cfg, _args) and getattr(cfg, _args, None) is not None: + w2v_args.model[_args] = getattr(cfg, _args, None) + if hasattr(cfg, "checkpoint_activations") and cfg.checkpoint_activations: with open_dict(w2v_args): w2v_args.model.checkpoint_activations = cfg.checkpoint_activations @@ -423,7 +452,6 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): w2v_args.task.data = cfg.data task = tasks.setup_task(w2v_args.task, from_checkpoint=True) model = task.build_model(w2v_args.model, from_checkpoint=True) - model.remove_pretraining_modules() d = w2v_args.model.encoder_embed_dim else: @@ -468,6 +496,9 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): if targ_d is not None: self.proj = Linear(d, targ_d) + if cfg.freeze_regex is not None: + self.freeze_regex(cfg.freeze_regex) + layer_decay = getattr(cfg, "layer_decay", 1) if layer_decay < 1: mod_encs = list(model.modality_encoders.values()) @@ -491,6 +522,14 @@ def __init__(self, cfg: Wav2Vec2AsrConfig, output_size=None): optim_override["optimizer"]["lr_scale"] = layer_scales[lid] p.optim_overrides = optim_override + def freeze_regex(self, pattern): + unfrozen_names = [] + for name, param in self.named_parameters(): + if re.fullmatch(pattern, name) is not None: + param.requires_grad_(False) + else: + unfrozen_names.append(name) + def load_model_weights(self, state, model, cfg): if cfg.ddp_backend == "fully_sharded": from fairseq.distributed import FullyShardedDataParallel @@ -553,6 +592,8 @@ def forward(self, source, padding_mask, **kwargs): "padding_mask": padding_mask, "mask": self.apply_mask and self.training, } + if "corpus_key" in kwargs: + w2v_args["corpus_key"] = kwargs["corpus_key"] if self.is_d2v_multi: w2v_args["mode"] = "AUDIO" diff --git a/fairseq/models/wav2vec/wav2vec2_classification.py b/fairseq/models/wav2vec/wav2vec2_classification.py new file mode 100644 index 0000000000..c9bbaab28e --- /dev/null +++ b/fairseq/models/wav2vec/wav2vec2_classification.py @@ -0,0 +1,348 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import contextlib +import logging +from argparse import Namespace +from dataclasses import dataclass, field +from typing import Any, Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F +from omegaconf import II, MISSING, open_dict + +from fairseq import checkpoint_utils, tasks, utils +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.models import BaseFairseqModel, FairseqEncoder, register_model +from fairseq.models.wav2vec.wav2vec2 import MASKING_DISTRIBUTION_CHOICES, Wav2Vec2Config +from fairseq.models.wav2vec.wav2vec2_asr import Embedding, Linear, Wav2VecEncoder, Wav2Vec2AsrConfig +from fairseq.tasks import FairseqTask + +logging.basicConfig(level=logging.DEBUG) + + +@dataclass +class Wav2Vec2ClassificationConfig(Wav2Vec2AsrConfig): + latent_embed_dim: Optional[int] = field( + default=None, metadata={"help": "latent dim (encoder w2v -> latent -> class"} + ) + pooling: str = field( + default="first_token", + metadata={"help": "pooling layer choices"}, + ) + activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( + default="gelu", metadata={"help": "activation function to use"} + ) + + +@register_model("wav2vec_classification", dataclass=Wav2Vec2ClassificationConfig) +class Wav2VecClassification(BaseFairseqModel): + # TODO: Can be shared/merged with ASR model class as w2v_encoder params are common. + def __init__( + self, + cfg: Wav2Vec2ClassificationConfig, + w2v_encoder: BaseFairseqModel, + pooling_layer, + ): + super().__init__() + self.cfg = cfg + self.w2v_encoder = w2v_encoder + self.pooling_layer = pooling_layer + + def upgrade_state_dict_named(self, state_dict, name): + super().upgrade_state_dict_named(state_dict, name) + return state_dict + + @classmethod + def build_model(cls, cfg: Wav2Vec2ClassificationConfig, task: FairseqTask): + """Build a new model instance.""" + w2v_encoder = Wav2VecEncoder(cfg, None) + pooling_layer = get_pooling_layer( + cfg, + w2v_encoder.w2v_model.encoder.layers[-1].embedding_dim, + len(task.target_dictionary), + len(w2v_encoder.w2v_model.encoder.layers), + ) + return cls(cfg, w2v_encoder, pooling_layer) + + def get_normalized_probs(self, net_output, log_probs): + """Get normalized probabilities (or log probs) from a net's output.""" + logits = net_output + + if log_probs: + return utils.log_softmax(logits.float(), dim=-1) + else: + return utils.softmax(logits.float(), dim=-1) + + def get_logits(self, net_output): + return net_output + + def forward(self, **kwargs): + encoder_out_dict = self.w2v_encoder(**kwargs) + w2v_encoder_out = encoder_out_dict["encoder_out"] # TxBxC + w2v_encoder_padding_mask = encoder_out_dict["padding_mask"] # BxT + # w2v_encoder_layer_results = encoder_out_dict["layer_results"] + return self.pooling_layer( + last_layer_feats=w2v_encoder_out, + padding_mask=w2v_encoder_padding_mask, + # all_layer_feats=w2v_encoder_layer_results, + ) + + # def forward_latent(self, **kwargs): + # encoder_out_dict = self.w2v_encoder(**kwargs) + # w2v_encoder_out = encoder_out_dict["encoder_out"] + # w2v_encoder_padding_mask = encoder_out_dict["encoder_padding_mask"] + # w2v_encoder_layer_results = encoder_out_dict["layer_results"] + # return self.pooling_layer.forward_latent( + # last_layer_feats=w2v_encoder_out, + # padding_mask=w2v_encoder_padding_mask, + # all_layer_feats=w2v_encoder_layer_results, + # ) + + +def get_pooling_layer( + cfg: Wav2Vec2ClassificationConfig, + encoder_embed_dim: int, + num_targets: int, + encoder_layers: int, +): + assert cfg.pooling == 'mean' + if cfg.pooling == "first_token": + return FirstToken(cfg, encoder_embed_dim, num_targets) + # elif cfg.pooling == "mean": + # return MeanPooling(cfg, encoder_embed_dim, num_targets) + elif cfg.pooling == "mean": + return MeanPoolingFast(cfg, encoder_embed_dim, num_targets) + elif cfg.pooling == "mean_amsoftmax": + return MeanPoolingFastAMSoftmax(cfg, encoder_embed_dim, num_targets) + elif cfg.pooling == "max": + return MaxPoolingFast(cfg, encoder_embed_dim, num_targets) + elif cfg.pooling == "elmo": + return LayerWeightedMeanPooling( + cfg, encoder_embed_dim, num_targets, encoder_layers + ) + else: + raise NotImplementedError(f"{cfg.pooling} has not been implemented yet.") + + +class Pooling(nn.Module): + def __init__( + self, + cfg: Wav2Vec2ClassificationConfig, + encoder_embed_dim: int, + num_targets: int, + ): + super().__init__() + self.projection = Linear(encoder_embed_dim, num_targets) + + def forward(self, last_layer_feats, **kwargs): + raise NotImplementedError() + + +class FirstToken(Pooling): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def forward(self, last_layer_feats, **kwargs): + return self.projection(last_layer_feats[:, 0]) + + +# class MeanPooling(Pooling): +# def __init__( +# self, +# cfg: Wav2VecClassificationConfig, +# encoder_embed_dim: int, +# num_targets: int, +# **kwargs, +# ): +# super().__init__(cfg, encoder_embed_dim, num_targets) +# self.activation_fn = utils.get_activation_fn(cfg.activation_fn) +# self.linear = Linear(encoder_embed_dim, encoder_embed_dim) + +# def forward(self, last_layer_feats, padding_mask, **kwargs): +# # last_layer_feats: [BxTxD] +# # padding_mask: [BxT] +# last_layer_feats = self.linear(self.activation_fn(last_layer_feats)) +# input_lengths = (1 - padding_mask.long()).sum(-1) +# pooled_feature_list = [] +# for i in range(len(last_layer_feats)): +# length = input_lengths[i] +# pooled_feature = torch.mean(last_layer_feats[i][:length], dim=0) +# pooled_feature_list.append(pooled_feature) +# return self.projection(torch.stack(pooled_feature_list)) + + +def fn_mean(x, mask): + """ + Args: + x: TxBxD + mask: BxT + Return: + y: BxD + """ + if mask is not None: + mask = mask.t()[:, :, None] + return (x * mask).sum(0) / mask.sum(0) + else: + return x.sum(0) / x.shape[0] + + +class MeanPoolingFast(nn.Module): + def __init__( + self, + cfg: Wav2Vec2ClassificationConfig, + encoder_embed_dim: int, + num_targets: int, + **kwargs, + ): + super().__init__() + self.activation_fn = utils.get_activation_fn(cfg.activation_fn) + self.latent_embed_dim = ( + cfg.latent_embed_dim + if cfg.latent_embed_dim is not None + else encoder_embed_dim + ) + logging.debug(f"| {self.latent_embed_dim=}") + self.linear = Linear(encoder_embed_dim, self.latent_embed_dim) + self.projection = Linear(self.latent_embed_dim, num_targets) + + def forward(self, last_layer_feats, padding_mask, **kwargs): + """ + Arguments + features - [TxBxD] Acoustic feature with shape + padding_mask - [BxT] Padding Mask + """ + if padding_mask is not None: + feat_mask = (~padding_mask).to(last_layer_feats.dtype) + else: + feat_mask = None + feat = self.linear(last_layer_feats) + feat = fn_mean(feat, feat_mask) + feat = self.activation_fn(feat) + return self.projection(feat) + + def forward_latent(self, last_layer_feats, padding_mask, **kwargs): + """ + Arguments + features - [TxBxD] Acoustic feature with shape + padding_mask - [BxT] Padding Mask + """ + if padding_mask is not None: + feat_mask = (~padding_mask).to(last_layer_feats.dtype) + else: + feat_mask = None + feat = self.linear(last_layer_feats) + feat = fn_mean(feat, feat_mask) + return feat + + +class MeanPoolingFastAMSoftmax(MeanPoolingFast): + def __init__( + self, + cfg: Wav2Vec2ClassificationConfig, + encoder_embed_dim: int, + num_targets: int, + **kwargs, + ): + super().__init__(cfg, encoder_embed_dim, num_targets, **kwargs) + self.projection = Linear(self.latent_embed_dim, num_targets, bias=False) + nn.init.xavier_normal_(self.projection.weight, gain=1) + + def forward(self, last_layer_feats, padding_mask, **kwargs): + + """ + Arguments + features - [BxTxD] Acoustic feature with shape + padding_mask - [BxT] Padding Mask + """ + feat_mask = (~padding_mask).to(last_layer_feats.dtype) # T,B -> B,T + feat = self.linear(last_layer_feats) # B,T,D + feat = fn_mean(feat, feat_mask) # B,D + feat = self.activation_fn(feat) + # normalize feat + feat_norm = F.normalize(feat, p=2, dim=-1) # B,D + weight_norm = F.normalize(self.projection.weight.t(), p=2, dim=-1) # D,K + cos_fw = feat_norm @ weight_norm + return cos_fw + + +def fn_max(x, mask): + """ + Args: + x: TxBxD + mask: BxT + Return: + y: BxD + """ + mask = mask.t()[:, :, None].to(torch.bool) + return x.masked_fill(~mask, -1e-8).max(0)[0] + + +class MaxPoolingFast(Pooling): + def __init__( + self, + cfg: Wav2Vec2ClassificationConfig, + encoder_embed_dim: int, + num_targets: int, + **kwargs, + ): + super().__init__(cfg, encoder_embed_dim, num_targets) + self.activation_fn = utils.get_activation_fn(cfg.activation_fn) + self.linear = Linear(encoder_embed_dim, encoder_embed_dim) + + def forward(self, last_layer_feats, padding_mask, **kwargs): + + """ + Arguments + features - [TxBxD] Acoustic feature with shape + padding_mask - [BxT] Padding Mask + """ + feat_mask = (~padding_mask).to(last_layer_feats.dtype) + feat = self.linear(last_layer_feats) + feat = fn_max(feat, feat_mask) + feat = self.activation_fn(feat) + return self.projection(feat) + + +class LayerWeightedMeanPooling(MeanPoolingFast): + """Elmo-style weighted average representation.""" + + def __init__( + self, + cfg: Wav2Vec2ClassificationConfig, + encoder_embed_dim: int, + num_targets: int, + encoder_layers: int, + ): + super().__init__(cfg, encoder_embed_dim, num_targets) + self.num_layers = encoder_layers + self.weights = nn.Parameter(torch.ones(encoder_layers)) + + def forward(self, last_layer_feats, padding_mask, all_layer_feats): + # last_layer_feats: [BxTxD] + # padding_mask: [BxT] + if not self.training: + msg = ( + f"Number of layers in input features = {len(all_layer_feats)}." + f" Expected {self.num_layers} layers." + ) + assert len(all_layer_feats) == self.num_layers, msg + + # Stack up all layers and reshape to (num_layers, features) + all_layer_feats_stacked = torch.stack(all_layer_feats, dim=0) + num_layers, *original_feat_shape = all_layer_feats_stacked.shape + all_layer_feats_stacked_flat = all_layer_feats_stacked.view(num_layers, -1) + + # Weighted average + normalized_weights = F.softmax(self.weights, dim=-1) + weighted_avg_features = ( + normalized_weights.unsqueeze(-1) * all_layer_feats_stacked_flat + ).sum(dim=0) + weighted_avg_features = weighted_avg_features.view(*original_feat_shape) + + # Mean Pooling on weighted average features. + return super().forward(weighted_avg_features, padding_mask) \ No newline at end of file diff --git a/fairseq/tasks/audio_classification.py b/fairseq/tasks/audio_classification.py new file mode 100644 index 0000000000..4c21d23b69 --- /dev/null +++ b/fairseq/tasks/audio_classification.py @@ -0,0 +1,269 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +from collections import OrderedDict +import itertools +import logging +import os +import sys +from dataclasses import dataclass, field +from typing import Optional + +import numpy as np +import torch +from omegaconf import II, MISSING +from sklearn import metrics as sklearn_metrics + +from fairseq.data import AddTargetDataset, Dictionary, FileAudioDataset +from fairseq.data.multi_corpus_dataset import MultiCorpusDataset +from fairseq.data.text_compressor import TextCompressionLevel, TextCompressor +from fairseq.dataclass import FairseqDataclass +from fairseq.tasks.audio_pretraining import AudioPretrainingConfig, AudioPretrainingTask +from fairseq.tasks.audio_finetuning import label_len_fn, LabelEncoder + +from .. import utils +from ..logging import metrics +from . import FairseqTask, register_task + +logger = logging.getLogger(__name__) + +@dataclass +class AudioClassificationConfig(AudioPretrainingConfig): + target_dictionary: Optional[str] = field( + default=None, metadata={"help": "override default dictionary location"} + ) + + +@register_task("audio_classification", dataclass=AudioClassificationConfig) +class AudioClassificationTask(AudioPretrainingTask): + """Task for audio classification tasks.""" + + cfg: AudioClassificationConfig + + def __init__( + self, + cfg: AudioClassificationConfig, + ): + super().__init__(cfg) + self.state.add_factory("target_dictionary", self.load_target_dictionary) + logging.info(f"=== Number of labels = {len(self.target_dictionary)}") + + def load_target_dictionary(self): + if self.cfg.labels: + target_dictionary = self.cfg.data + if self.cfg.target_dictionary: # override dict + target_dictionary = self.cfg.target_dictionary + dict_path = os.path.join(target_dictionary, f"dict.{self.cfg.labels}.txt") + logger.info("Using dict_path : {}".format(dict_path)) + return Dictionary.load(dict_path, add_special_symbols=False) + return None + + def load_dataset( + self, split: str, task_cfg: AudioClassificationConfig = None, **kwargs + ): + super().load_dataset(split, task_cfg, **kwargs) + task_cfg = task_cfg or self.cfg + assert task_cfg.labels is not None + text_compression_level = getattr( + TextCompressionLevel, str(self.cfg.text_compression_level) + ) + data_path = self.cfg.data + if task_cfg.multi_corpus_keys is None: + label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") + skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) + text_compressor = TextCompressor(level=text_compression_level) + with open(label_path, "r") as f: + labels = [ + text_compressor.compress(l) + for i, l in enumerate(f) + if i not in skipped_indices + ] + + assert len(labels) == len(self.datasets[split]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.datasets[split])}) do not match" + ) + + process_label = LabelEncoder(self.target_dictionary) + + self.datasets[split] = AddTargetDataset( + self.datasets[split], + labels, + pad=self.target_dictionary.pad(), + eos=self.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + label_len_fn=label_len_fn, + add_to_input=False, + # text_compression_level=text_compression_level, + ) + else: + target_dataset_map = OrderedDict() + + multi_corpus_keys = [ + k.strip() for k in task_cfg.multi_corpus_keys.split(",") + ] + corpus_idx_map = {k: idx for idx, k in enumerate(multi_corpus_keys)} + + data_keys = [k.split(":") for k in split.split(",")] + + multi_corpus_sampling_weights = [ + float(val.strip()) + for val in task_cfg.multi_corpus_sampling_weights.split(",") + ] + data_weights = [] + for key, file_name in data_keys: + k = key.strip() + label_path = os.path.join( + data_path, f"{file_name.strip()}.{task_cfg.labels}" + ) + skipped_indices = getattr( + self.dataset_map[split][k], "skipped_indices", set() + ) + text_compressor = TextCompressor(level=text_compression_level) + with open(label_path, "r") as f: + labels = [ + text_compressor.compress(l) + for i, l in enumerate(f) + if i not in skipped_indices + ] + + assert len(labels) == len(self.dataset_map[split][k]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.dataset_map[split][k])}) do not match" + ) + + process_label = LabelEncoder(self.target_dictionary) + + # TODO: Remove duplication of code from the if block above + target_dataset_map[k] = AddTargetDataset( + self.dataset_map[split][k], + labels, + pad=self.target_dictionary.pad(), + eos=self.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + label_len_fn=label_len_fn, + add_to_input=False, + # text_compression_level=text_compression_level, + ) + + data_weights.append(multi_corpus_sampling_weights[corpus_idx_map[k]]) + + if len(target_dataset_map) == 1: + self.datasets[split] = list(target_dataset_map.values())[0] + else: + self.datasets[split] = MultiCorpusDataset( + target_dataset_map, + distribution=data_weights, + seed=0, + sort_indices=True, + ) + + @property + def source_dictionary(self): + return None + + @property + def target_dictionary(self): + """Return the :class:`~fairseq.data.Dictionary` for the language + model.""" + return self.state.target_dictionary + + def train_step(self, sample, model, *args, **kwargs): + sample["target"] = sample["target"].to(dtype=torch.long) + loss, sample_size, logging_output = super().train_step( + sample, model, *args, **kwargs + ) + self._log_metrics(sample, model, logging_output) + return loss, sample_size, logging_output + + def valid_step(self, sample, model, criterion): + sample["target"] = sample["target"].to(dtype=torch.long) + loss, sample_size, logging_output = super().valid_step(sample, model, criterion) + self._log_metrics(sample, model, logging_output) + return loss, sample_size, logging_output + + def _log_metrics(self, sample, model, logging_output): + metrics = self._inference_with_metrics( + sample, + model, + ) + """ + logging_output["_precision"] = metrics["precision"] + logging_output["_recall"] = metrics["recall"] + logging_output["_f1"] = metrics["f1"] + logging_output["_eer"] = metrics["eer"] + logging_output["_accuracy"] = metrics["accuracy"] + """ + logging_output["_correct"] = metrics["correct"] + logging_output["_total"] = metrics["total"] + + def _inference_with_metrics(self, sample, model): + def _compute_eer(target_list, lprobs): + # from scipy.optimize import brentq + # from scipy.interpolate import interp1d + + y_one_hot = np.eye(len(self.state.target_dictionary))[target_list] + fpr, tpr, thresholds = sklearn_metrics.roc_curve( + y_one_hot.ravel(), lprobs.ravel() + ) + # Revisit the interpolation approach. + # eer = brentq(lambda x: 1.0 - x - interp1d(fpr, tpr)(x), 0.0, 1.0) + + fnr = 1 - tpr + eer = fpr[np.nanargmin(np.absolute((fnr - fpr)))] + + return eer + + with torch.no_grad(): + net_output = model(**sample["net_input"]) + lprobs = ( + model.get_normalized_probs(net_output, log_probs=True).cpu().detach() + ) + target_list = sample["target"][:, 0].detach().cpu() + predicted_list = torch.argmax(lprobs, 1).detach().cpu() # B,C->B + + metrics = { + "correct": torch.sum(target_list == predicted_list).item(), + "total": len(target_list), + } + return metrics + + def reduce_metrics(self, logging_outputs, criterion): + super().reduce_metrics(logging_outputs, criterion) + + zero = torch.scalar_tensor(0.0) + correct, total = 0, 0 + for log in logging_outputs: + correct += log.get("_correct", zero) + total += log.get("_total", zero) + metrics.log_scalar("_correct", correct) + metrics.log_scalar("_total", total) + + if total > 0: + def _fn_accuracy(meters): + if meters["_total"].sum > 0: + return utils.item(meters["_correct"].sum / meters["_total"].sum) + return float("nan") + + metrics.log_derived("accuracy", _fn_accuracy) + """ + prec_sum, recall_sum, f1_sum, acc_sum, eer_sum = 0.0, 0.0, 0.0, 0.0, 0.0 + for log in logging_outputs: + prec_sum += log.get("_precision", zero).item() + recall_sum += log.get("_recall", zero).item() + f1_sum += log.get("_f1", zero).item() + acc_sum += log.get("_accuracy", zero).item() + eer_sum += log.get("_eer", zero).item() + + metrics.log_scalar("avg_precision", prec_sum / len(logging_outputs)) + metrics.log_scalar("avg_recall", recall_sum / len(logging_outputs)) + metrics.log_scalar("avg_f1", f1_sum / len(logging_outputs)) + metrics.log_scalar("avg_accuracy", acc_sum / len(logging_outputs)) + metrics.log_scalar("avg_eer", eer_sum / len(logging_outputs)) + """ \ No newline at end of file diff --git a/fairseq/tasks/audio_finetuning.py b/fairseq/tasks/audio_finetuning.py index 77634f1bae..d79553cb86 100644 --- a/fairseq/tasks/audio_finetuning.py +++ b/fairseq/tasks/audio_finetuning.py @@ -7,12 +7,13 @@ import logging import os +from fairseq.data.multi_corpus_dataset import MultiCorpusDataset import torch import json from argparse import Namespace from dataclasses import dataclass, field -from typing import Optional, Any +from typing import Optional, Any, OrderedDict from fairseq.data import AddTargetDataset, Dictionary, encoders from fairseq.tasks.audio_pretraining import AudioPretrainingTask, AudioPretrainingConfig @@ -101,7 +102,12 @@ class AudioFinetuningConfig(AudioPretrainingConfig): }, ) rebuild_batches: bool = True - + target_dictionary: Optional[str] = field( + default=None, + metadata={ + "help": "override default dictionary location" + } + ) @register_task("audio_finetuning", dataclass=AudioFinetuningConfig) class AudioFinetuningTask(AudioPretrainingTask): @@ -120,7 +126,11 @@ def __init__( def load_target_dictionary(self): if self.cfg.labels: - dict_path = os.path.join(self.cfg.data, f"dict.{self.cfg.labels}.txt") + target_dictionary = self.cfg.data + if self.cfg.target_dictionary: # override dict + target_dictionary = self.cfg.target_dictionary + dict_path = os.path.join(target_dictionary, f"dict.{self.cfg.labels}.txt") + logger.info('Using dict_path : {}'.format(dict_path)) return Dictionary.load(dict_path) return None @@ -135,34 +145,84 @@ def load_dataset( TextCompressionLevel, str(self.cfg.text_compression_level) ) data_path = self.cfg.data - label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") - skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) - text_compressor = TextCompressor(level=text_compression_level) - with open(label_path, "r") as f: - labels = [ - text_compressor.compress(l) - for i, l in enumerate(f) - if i not in skipped_indices - ] - - assert len(labels) == len(self.datasets[split]), ( - f"labels length ({len(labels)}) and dataset length " - f"({len(self.datasets[split])}) do not match" - ) + if task_cfg.multi_corpus_keys is None: + label_path = os.path.join(data_path, f"{split}.{task_cfg.labels}") + skipped_indices = getattr(self.datasets[split], "skipped_indices", set()) + text_compressor = TextCompressor(level=text_compression_level) + with open(label_path, "r") as f: + labels = [ + text_compressor.compress(l) + for i, l in enumerate(f) + if i not in skipped_indices + ] + + assert len(labels) == len(self.datasets[split]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.datasets[split])}) do not match" + ) - process_label = LabelEncoder(self.target_dictionary) - - self.datasets[split] = AddTargetDataset( - self.datasets[split], - labels, - pad=self.target_dictionary.pad(), - eos=self.target_dictionary.eos(), - batch_targets=True, - process_label=process_label, - label_len_fn=label_len_fn, - add_to_input=task_cfg.get("autoregressive", False), - text_compression_level=text_compression_level, - ) + process_label = LabelEncoder(self.target_dictionary) + + self.datasets[split] = AddTargetDataset( + self.datasets[split], + labels, + pad=self.target_dictionary.pad(), + eos=self.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + label_len_fn=label_len_fn, + add_to_input=task_cfg.get("autoregressive", False), + text_compression_level=text_compression_level, + ) + else: + + target_dataset_map = OrderedDict() + + multi_corpus_keys = [k.strip() for k in task_cfg.multi_corpus_keys.split(",")] + corpus_idx_map = {k: idx for idx, k in enumerate(multi_corpus_keys)} + + data_keys = [k.split(":") for k in split.split(",")] + + multi_corpus_sampling_weights = [float(val.strip()) for val in task_cfg.multi_corpus_sampling_weights.split(",")] + data_weights = [] + for key, file_name in data_keys: + k = key.strip() + label_path = os.path.join(data_path, f"{file_name.strip()}.{task_cfg.labels}") + skipped_indices = getattr(self.dataset_map[split][k], "skipped_indices", set()) + text_compressor = TextCompressor(level=text_compression_level) + with open(label_path, "r") as f: + labels = [ + text_compressor.compress(l) + for i, l in enumerate(f) + if i not in skipped_indices + ] + + assert len(labels) == len(self.dataset_map[split][k]), ( + f"labels length ({len(labels)}) and dataset length " + f"({len(self.dataset_map[split][k])}) do not match" + ) + + process_label = LabelEncoder(self.target_dictionary) + + # TODO: Remove duplication of code from the if block above + target_dataset_map[k] = AddTargetDataset( + self.dataset_map[split][k], + labels, + pad=self.target_dictionary.pad(), + eos=self.target_dictionary.eos(), + batch_targets=True, + process_label=process_label, + label_len_fn=label_len_fn, + add_to_input=task_cfg.get("autoregressive", False), + text_compression_level=text_compression_level, + ) + + data_weights.append(multi_corpus_sampling_weights[corpus_idx_map[k]]) + + if len(target_dataset_map) == 1: + self.datasets[split] = list(target_dataset_map.values())[0] + else: + self.datasets[split] = MultiCorpusDataset(target_dataset_map, distribution=data_weights, seed=0, sort_indices=True) @property def target_dictionary(self): diff --git a/fairseq/tasks/audio_pretraining.py b/fairseq/tasks/audio_pretraining.py index e6de0666ad..3e91303b69 100644 --- a/fairseq/tasks/audio_pretraining.py +++ b/fairseq/tasks/audio_pretraining.py @@ -11,8 +11,9 @@ from argparse import Namespace from dataclasses import dataclass, field -from typing import Optional -from omegaconf import MISSING, II +from typing import Optional, OrderedDict +from fairseq.data.multi_corpus_dataset import MultiCorpusDataset +from omegaconf import MISSING, II, OmegaConf from fairseq.data import BinarizedAudioDataset, FileAudioDataset, SubsampleDataset from fairseq.dataclass import FairseqDataclass, ChoiceEnum @@ -44,6 +45,12 @@ class AudioPretrainingConfig(FairseqDataclass): default=None, metadata={"help": "extension of the label file to load, used for fine-tuning"}, ) + multi_corpus_keys: Optional[str] = field( + default=None, + metadata={"help": "Comma separated names for loading multi corpus datasets"}) + multi_corpus_sampling_weights: Optional[str] = field( + default=None, + metadata={"help": "Comma separated string of sampling weights corresponding to the multi_corpus_keys"}) binarized_dataset: bool = field( default=False, metadata={ @@ -121,7 +128,7 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): TextCompressionLevel, str(self.cfg.text_compression_level) ) - compute_mask = task_cfg.precompute_mask_config is not None + compute_mask = getattr(task_cfg, "precompute_mask_config", None) is not None mask_args = {} if compute_mask: mask_args = task_cfg.precompute_mask_config @@ -140,20 +147,59 @@ def load_dataset(self, split: str, task_cfg: FairseqDataclass = None, **kwargs): **mask_args, ) else: - manifest_path = os.path.join(data_path, "{}.tsv".format(split)) - - self.datasets[split] = FileAudioDataset( - manifest_path=manifest_path, - sample_rate=task_cfg.get("sample_rate", self.cfg.sample_rate), - max_sample_size=self.cfg.max_sample_size, - min_sample_size=self.cfg.min_sample_size, - pad=task_cfg.labels is not None or task_cfg.enable_padding, - normalize=task_cfg.normalize, - num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), - text_compression_level=text_compression_level, - compute_mask=compute_mask, - **mask_args, - ) + if task_cfg.multi_corpus_keys is None: + manifest_path = os.path.join(data_path, "{}.tsv".format(split)) + + self.datasets[split] = FileAudioDataset( + manifest_path=manifest_path, + sample_rate=task_cfg.get("sample_rate", self.cfg.sample_rate), + max_sample_size=self.cfg.max_sample_size, + min_sample_size=self.cfg.min_sample_size, + pad=task_cfg.labels is not None or task_cfg.enable_padding, + normalize=task_cfg.normalize, + num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), + text_compression_level=text_compression_level, + compute_mask=compute_mask, + **mask_args, + ) + else: + dataset_map = OrderedDict() + self.dataset_map = {} + multi_corpus_keys = [k.strip() for k in task_cfg.multi_corpus_keys.split(",")] + corpus_idx_map = {k: idx for idx, k in enumerate(multi_corpus_keys)} + data_keys = [k.split(":") for k in split.split(",")] + + multi_corpus_sampling_weights = [float(val.strip()) for val in task_cfg.multi_corpus_sampling_weights.split(",")] + data_weights = [] + + for key, file_name in data_keys: + + k = key.strip() + manifest_path = os.path.join(data_path, "{}.tsv".format(file_name.strip())) + + # TODO: Remove duplication of code from the if block above + dataset_map[k] = FileAudioDataset( + manifest_path=manifest_path, + sample_rate=task_cfg.get("sample_rate", self.cfg.sample_rate), + max_sample_size=self.cfg.max_sample_size, + min_sample_size=self.cfg.min_sample_size, + pad=task_cfg.labels is not None or task_cfg.enable_padding, + normalize=task_cfg.normalize, + num_buckets=self.cfg.num_batch_buckets or int(self.cfg.tpu), + text_compression_level=text_compression_level, + compute_mask=compute_mask, + corpus_key=corpus_idx_map[k], + **mask_args, + ) + + data_weights.append(multi_corpus_sampling_weights[corpus_idx_map[k]]) + + self.dataset_map[split] = dataset_map + + if len(dataset_map) == 1: + self.datasets[split] = list(dataset_map.values())[0] + else: + self.datasets[split] = MultiCorpusDataset(dataset_map, distribution=data_weights, seed=0, sort_indices=True) if getattr(task_cfg, "subsample", 1) < 1: self.datasets[split] = SubsampleDataset( From aec128cb707fe08b553deb9e1043532ae857b9f9 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Mon, 22 May 2023 12:29:19 -0700 Subject: [PATCH 738/774] Update blog post link for MMS (#5114) * Update blog post link for MMS * Update blog post link for MMS --- README.md | 1 + examples/mms/README.md | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 047e1b7686..1150c66cbe 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ We provide reference implementations of various sequence modeling papers: </p></details> ### What's New: +* May 2023 [Released models for Scaling Speech Technology to 1,000+ Languages (Pratap, et al., 2023)](examples/mms/README.md) * June 2022 [Released code for wav2vec-U 2.0 from Towards End-to-end Unsupervised Speech Recognition (Liu, et al., 2022)](examples/wav2vec/unsupervised/README.md) * May 2022 [Integration with xFormers](https://github.com/facebookresearch/xformers) * December 2021 [Released Direct speech-to-speech translation code](examples/speech_to_speech/README.md) diff --git a/examples/mms/README.md b/examples/mms/README.md index e941e4340b..5ed5d7eabc 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -2,7 +2,7 @@ The Massively Multilingual Speech (MMS) project expands speech technology from about 100 languages to over 1,000 by building a single multilingual speech recognition model supporting over 1,100 languages (more than 10 times as many as before), language identification models able to identify over [4,000 languages](https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html) (40 times more than before), pretrained models supporting over 1,400 languages, and text-to-speech models for over 1,100 languages. Our goal is to make it easier for people to access information and to use devices in their preferred language. -You can find details in the paper [Scaling Speech Technology to 1000+ languages](https://research.facebook.com/publications/scaling-speech-technology-to-1000-languages/) and the [blog post](https://ai.facebook.com/blog/multilingual-speech-recognition-model/). +You can find details in the paper [Scaling Speech Technology to 1000+ languages](https://research.facebook.com/publications/scaling-speech-technology-to-1000-languages/) and the [blog post](https://ai.facebook.com/blog/multilingual-model-speech-recognition/). An overview of the languages covered by MMS can be found [here](https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html). @@ -147,13 +147,13 @@ eng 1 eng 1 ``` -Download model and the corresponding dictionary file for the LID model. The following command assuming there is a file named `dict.lang.txt` in `/path/to/dict/l126/`. +Download model and the corresponding dictionary file for the LID model. Use the following command to run inference - ```shell script $ PYTHONPATH='.' python3 examples/mms/lid/infer.py /path/to/dict/l126/ --path /path/to/models/mms1b_l126.pt \ --task audio_classification --infer-manifest /path/to/manifest.tsv --output-path <OUTDIR> ``` -`<OUTDIR>/predictions.txt` will contain the predictions from the model for the audio files in `manifest.tsv`. +The above command assumes there is a file named `dict.lang.txt` in `/path/to/dict/l126/`. `<OUTDIR>/predictions.txt` will contain the predictions from the model for the audio files in `manifest.tsv`. # License From c7bfa9bbc3048af5f652e38a2c5c46e403273292 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Mon, 22 May 2023 12:40:22 -0700 Subject: [PATCH 739/774] Update MMS README (#5115) --- examples/mms/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/mms/README.md b/examples/mms/README.md index 5ed5d7eabc..790a5f0ad9 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -156,6 +156,11 @@ $ PYTHONPATH='.' python3 examples/mms/lid/infer.py /path/to/dict/l126/ --path The above command assumes there is a file named `dict.lang.txt` in `/path/to/dict/l126/`. `<OUTDIR>/predictions.txt` will contain the predictions from the model for the audio files in `manifest.tsv`. +## Forced Alignment Tooling + +We also developed an efficient forced alignment algorithm implemented on GPU which is able to process very long audio files. This algorithm is open sourced and we provide instructions on how to use it [here](data_prep). We also open source a multilingual alignment model trained on 31K hours of data in 1,130 languages, as well as text normalization scripts. + + # License The MMS code and model weights are released under the CC-BY-NC 4.0 license. From af12c9c6407bbcf2bca0b2f1923cf78f3db8857c Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Mon, 22 May 2023 14:16:36 -0700 Subject: [PATCH 740/774] Update README.md (#5118) --- examples/mms/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mms/README.md b/examples/mms/README.md index 790a5f0ad9..3cb629f1c6 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -14,7 +14,7 @@ An overview of the languages covered by MMS can be found [here](https://dl.fbaip MMS-300M | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_300m.pt) MMS-1B | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_1b.pt) -Example commands to finetune the pretrained models can be found [here](https://github.com/fairinternal/fairseq-py/tree/mms_release/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). +Example commands to finetune the pretrained models can be found [here](https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). ## Finetuned models ### ASR From 87d30056302d15c0cb093d46b62877512c4a0fe1 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Tue, 23 May 2023 11:35:05 -0700 Subject: [PATCH 741/774] [MMS] Fix concatenation of emissions (#5133) --- examples/mms/data_prep/align_and_segment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mms/data_prep/align_and_segment.py b/examples/mms/data_prep/align_and_segment.py index 732f93c3fb..dcaba4f5a2 100644 --- a/examples/mms/data_prep/align_and_segment.py +++ b/examples/mms/data_prep/align_and_segment.py @@ -51,12 +51,12 @@ def generate_emissions(model, audio_file): offset = time_to_frame(input_start_time) emissions_ = emissions_[ - :, emission_start_frame - offset : emission_end_frame - offset + emission_start_frame - offset : emission_end_frame - offset, : ] emissions_arr.append(emissions_) i += EMISSION_INTERVAL - emissions = torch.cat(emissions_arr, dim=1).squeeze() + emissions = torch.cat(emissions_arr, dim=0).squeeze() emissions = torch.log_softmax(emissions, dim=-1) stride = float(waveform.size(1) * 1000 / emissions.size(0) / SAMPLING_FREQ) From bc8e8b12515584356ddd29c86f70d985affa5e7b Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Tue, 23 May 2023 13:52:57 -0700 Subject: [PATCH 742/774] MMS: Fix forced alignment API usage (#5138) --- examples/mms/data_prep/align_and_segment.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/mms/data_prep/align_and_segment.py b/examples/mms/data_prep/align_and_segment.py index dcaba4f5a2..cd5045eabc 100644 --- a/examples/mms/data_prep/align_and_segment.py +++ b/examples/mms/data_prep/align_and_segment.py @@ -85,9 +85,13 @@ def get_alignments( token_indices = [] blank = dictionary["<blank>"] + + targets = torch.tensor(token_indices, dtype=torch.int32).to(DEVICE) + input_lengths = torch.tensor(emissions.shape[0]) + target_lengths = torch.tensor(targets.shape[0]) - path, _ = F.force_align( - emissions, torch.Tensor(token_indices, device=DEVICE).int(), blank=blank + path, _ = F.forced_align( + emissions, targets, input_lengths, target_lengths, blank=blank ) path = path.to("cpu").tolist() segments = merge_repeats(path, {v: k for k, v in dictionary.items()}) From 1082b61b12ec92d6c813906fcec90139b85fb039 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Tue, 23 May 2023 14:38:51 -0700 Subject: [PATCH 743/774] [MMS] Update README.md (#5137) Add dictionary files for MMS ASR models --- examples/mms/README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/mms/README.md b/examples/mms/README.md index 3cb629f1c6..d78ba4d428 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -19,11 +19,13 @@ Example commands to finetune the pretrained models can be found [here](https://g ## Finetuned models ### ASR -| Model | Languages | Dataset | Model | Supported languages | -|---|---|---|---|--- -MMS-1B:FL102 | 102 | FLEURS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102_langs.html) -MMS-1B:L1107| 1107 | MMS-lab | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107_langs.html) -MMS-1B-all| 1162 | MMS-lab + FLEURS <br>+ CV + VP + MLS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all_langs.html) +| Model | Languages | Dataset | Model | Dictionary* | Supported languages | +|---|---|---|---|---|--- +MMS-1B:FL102 | 102 | FLEURS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_fl102/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102_langs.html) +MMS-1B:L1107| 1107 | MMS-lab | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_l1107/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107_langs.html) +MMS-1B-all| 1162 | MMS-lab + FLEURS <br>+ CV + VP + MLS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_all/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all_langs.html) + +\* In the `Dictionary` column, we provide the download link for token dictionary in English language. To download token dictionary for a different language supported by the model, modify the language code in the URL appropriately. For example, to get token dictionary of FL102 model for Hindi language, use [this](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_fl102/hin.txt) link. ### TTS 1. Download the list of [iso codes](https://dl.fbaipublicfiles.com/mms/tts/all-tts-languages.html) of 1107 languages. From fea3361112b3c76f3253127501f5570d3ee9ca3b Mon Sep 17 00:00:00 2001 From: chevalierNoir <bshi@fb.com> Date: Wed, 24 May 2023 00:41:38 -0400 Subject: [PATCH 744/774] [MMS] TTS text uromanization + cpu inference (#5140) * mms tts uroman + cpu support for inference * remove mps support to accommodate all pytorch versions * add explanation to arg --------- Co-authored-by: Bowen Shi <bshi@meta.com> --- examples/mms/tts/infer.py | 46 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/examples/mms/tts/infer.py b/examples/mms/tts/infer.py index 8f6f6277eb..a51e2412f1 100644 --- a/examples/mms/tts/infer.py +++ b/examples/mms/tts/infer.py @@ -4,8 +4,10 @@ # LICENSE file in the root directory of this source tree. import os +import re import glob import json +import tempfile import math import torch from torch import nn @@ -15,6 +17,7 @@ import commons import utils import argparse +import subprocess from data_utils import TextAudioLoader, TextAudioCollate, TextAudioSpeakerLoader, TextAudioSpeakerCollate from models import SynthesizerTrn from scipy.io.wavfile import write @@ -41,6 +44,24 @@ def text_to_sequence(self, text, cleaner_names): sequence += [symbol_id] return sequence + def uromanize(self, text, uroman_pl): + iso = "xxx" + with tempfile.NamedTemporaryFile() as tf, \ + tempfile.NamedTemporaryFile() as tf2: + with open(tf.name, "w") as f: + f.write("\n".join([text])) + cmd = f"perl " + uroman_pl + cmd += f" -l {iso} " + cmd += f" < {tf.name} > {tf2.name}" + os.system(cmd) + outtexts = [] + with open(tf2.name) as f: + for line in f: + line = re.sub(r"\s+", " ", line).strip() + outtexts.append(line) + outtext = outtexts[0] + return outtext + def get_text(self, text, hps): text_norm = self.text_to_sequence(text, hps.data.text_cleaners) if hps.data.add_blank: @@ -59,9 +80,16 @@ def generate(): parser.add_argument('--model-dir', type=str, help='model checkpoint dir') parser.add_argument('--wav', type=str, help='output wav path') parser.add_argument('--txt', type=str, help='input text') + parser.add_argument('--uroman-dir', type=str, help='uroman lib dir (will download if not specified)') args = parser.parse_args() ckpt_dir, wav_path, txt = args.model_dir, args.wav, args.txt + if torch.cuda.is_available(): + device = torch.device("cuda") + else: + device = torch.device("cpu") + + print(f"Run inference with {device}") vocab_file = f"{ckpt_dir}/vocab.txt" config_file = f"{ckpt_dir}/config.json" assert os.path.isfile(config_file), f"{config_file} doesn't exist" @@ -72,7 +100,7 @@ def generate(): hps.data.filter_length // 2 + 1, hps.train.segment_size // hps.data.hop_length, **hps.model) - net_g.cuda() + net_g.to(device) _ = net_g.eval() g_pth = f"{ckpt_dir}/G_100000.pth" @@ -81,12 +109,24 @@ def generate(): _ = utils.load_checkpoint(g_pth, net_g, None) print(f"text: {txt}") + is_uroman = hps.data.training_files.split('.')[-1] == 'uroman' + if is_uroman: + with tempfile.TemporaryDirectory() as tmp_dir: + if args.uroman_dir is None: + cmd = f"git clone git@github.com:isi-nlp/uroman.git {tmp_dir}" + print(cmd) + subprocess.check_output(cmd, shell=True) + args.uroman_dir = tmp_dir + uroman_pl = os.path.join(args.uroman_dir, "bin", "uroman.pl") + print(f"uromanize") + txt = text_mapper.uromanize(txt, uroman_pl) + print(f"uroman text: {txt}") txt = txt.lower() txt = text_mapper.filter_oov(txt) stn_tst = text_mapper.get_text(txt, hps) with torch.no_grad(): - x_tst = stn_tst.unsqueeze(0).cuda() - x_tst_lengths = torch.LongTensor([stn_tst.size(0)]).cuda() + x_tst = stn_tst.unsqueeze(0).to(device) + x_tst_lengths = torch.LongTensor([stn_tst.size(0)]).to(device) hyp = net_g.infer( x_tst, x_tst_lengths, noise_scale=.667, noise_scale_w=0.8, length_scale=1.0 From b50b64935748c0d4e714eaf85d2bfada2ed89ffa Mon Sep 17 00:00:00 2001 From: Kirill <kirill.fedyanin@gmail.com> Date: Wed, 24 May 2023 17:09:01 +0400 Subject: [PATCH 745/774] Fix the MMS doc about LID manifest (#5144) --- examples/mms/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/mms/README.md b/examples/mms/README.md index d78ba4d428..48460b375b 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -135,13 +135,13 @@ $ PYTHONPATH=$PYTHONPATH:/path/to/vits python examples/mms/tts/infer.py --model- ### LID -Prepare two files in this format +Prepare two files in this format. Each manifest line contains <audio> and <number_of_sample> ``` #/path/to/manifest.tsv / -/path/to/audio1.wav -/path/to/audio2.wav -/path/to/audio3.wav +/path/to/audio1.wav 180000 +/path/to/audio2.wav 240000 +/path/to/audio3.wav 160000 # /path/to/manifest.lang eng 1 From 25c20e6a5e781e4ef05e23642f21c091ba64872e Mon Sep 17 00:00:00 2001 From: Andros Tjandra <38714605+androstj@users.noreply.github.com> Date: Wed, 24 May 2023 14:17:46 -0400 Subject: [PATCH 746/774] Fix wrong input-output ASR input utts order (#5149) Co-authored-by: Andros Tjandra <androstj@fb.com> --- examples/mms/README.md | 3 ++- examples/mms/asr/infer/mms_infer.py | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/examples/mms/README.md b/examples/mms/README.md index 48460b375b..dfd8b85fbd 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -53,7 +53,8 @@ wget https://dl.fbaipublicfiles.com/mms/tts/azj-script_latin.tar.gz # North Azer Run this command to transcribe one or more audio files: ```shell command cd /path/to/fairseq-py/ -python examples/mms/asr/infer/mms_infer.py --model "/path/to/asr/model" --lang lang_code --audio "/path/to/audio_1.wav" "/path/to/audio_1.wav" +python examples/mms/asr/infer/mms_infer.py --model "/path/to/asr/model" --lang lang_code \ + --audio "/path/to/audio_1.wav" "/path/to/audio_2.wav" "/path/to/audio_3.wav" ``` For more advance configuration and calculate CER/WER, you could prepare manifest folder by creating a folder with this format: diff --git a/examples/mms/asr/infer/mms_infer.py b/examples/mms/asr/infer/mms_infer.py index f9e06cd222..65f86b3148 100644 --- a/examples/mms/asr/infer/mms_infer.py +++ b/examples/mms/asr/infer/mms_infer.py @@ -21,28 +21,38 @@ def parser(): parser.add_argument("--format", type=str, choices=["none", "letter"], default="letter") return parser.parse_args() +def reorder_decode(hypos): + outputs = [] + for hypo in hypos: + idx = int(re.findall("\(None-(\d+)\)$", hypo)[0]) + hypo = re.sub("\(\S+\)$", "", hypo).strip() + outputs.append((idx, hypo)) + outputs = sorted(outputs) + return outputs + def process(args): with tempfile.TemporaryDirectory() as tmpdir: print(">>> preparing tmp manifest dir ...", file=sys.stderr) tmpdir = Path(tmpdir) - with open(tmpdir / "dev.tsv", "w") as fw: + with open(tmpdir / "dev.tsv", "w") as fw, open(tmpdir / "dev.uid", "w") as fu: fw.write("/\n") for audio in args.audio: nsample = sf.SoundFile(audio).frames fw.write(f"{audio}\t{nsample}\n") - with open(tmpdir / "dev.uid", "w") as fw: - fw.write(f"{audio}\n"*len(args.audio)) + fu.write(f"{audio}\n") with open(tmpdir / "dev.ltr", "w") as fw: - fw.write("d u m m y | d u m m y\n"*len(args.audio)) + fw.write("d u m m y | d u m m y |\n"*len(args.audio)) with open(tmpdir / "dev.wrd", "w") as fw: fw.write("dummy dummy\n"*len(args.audio)) cmd = f""" - PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=4000000 distributed_training.distributed_world_size=1 "common_eval.path='{args.model}'" task.data={tmpdir} dataset.gen_subset="{args.lang}:dev" common_eval.post_process={args.format} decoding.results_path={tmpdir} + PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=1440000 distributed_training.distributed_world_size=1 "common_eval.path='{args.model}'" task.data={tmpdir} dataset.gen_subset="{args.lang}:dev" common_eval.post_process={args.format} decoding.results_path={tmpdir} """ print(">>> loading model & running inference ...", file=sys.stderr) subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL,) with open(tmpdir/"hypo.word") as fr: - for ii, hypo in enumerate(fr): + hypos = fr.readlines() + outputs = reorder_decode(hypos) + for ii, hypo in outputs: hypo = re.sub("\(\S+\)$", "", hypo).strip() print(f'===============\nInput: {args.audio[ii]}\nOutput: {hypo}') From 478787b95aee24d8669873b1c63239e4ebbd8e44 Mon Sep 17 00:00:00 2001 From: Andros Tjandra <38714605+androstj@users.noreply.github.com> Date: Thu, 25 May 2023 14:08:09 -0400 Subject: [PATCH 747/774] Create MMS_ASR_Inference_Colab.ipynb (#5151) * Create MMS_ASR_Inference_Colab.ipynb Added tutorial in Google Colab IPYNB fashion with small modification. Credit to epk2112 https://github.com/epk2112/fairseq_meta_mms_Google_Colab_implementation * Add readme & ipynb * Add readme & ipynb * change colab hyperlink --------- Co-authored-by: Andros Tjandra <androstj@fb.com> --- examples/mms/README.md | 2 + .../tutorial/MMS_ASR_Inference_Colab.ipynb | 351 ++++++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb diff --git a/examples/mms/README.md b/examples/mms/README.md index dfd8b85fbd..8685a8bff2 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -56,6 +56,8 @@ cd /path/to/fairseq-py/ python examples/mms/asr/infer/mms_infer.py --model "/path/to/asr/model" --lang lang_code \ --audio "/path/to/audio_1.wav" "/path/to/audio_2.wav" "/path/to/audio_3.wav" ``` +We also provide an Ipython notebook example in inside `asr/tutorial` folder [ipynb](https://github.com/facebookresearch/fairseq/blob/androstj-patch-1/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb) or [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/facebookresearch/fairseq/blob/main/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb) + For more advance configuration and calculate CER/WER, you could prepare manifest folder by creating a folder with this format: ``` diff --git a/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb b/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb new file mode 100644 index 0000000000..a243cb1f29 --- /dev/null +++ b/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb @@ -0,0 +1,351 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU", + "gpuClass": "standard" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Running MMS-ASR inference in Colab" + ], + "metadata": { + "id": "Rhm7khm6GskV" + } + }, + { + "cell_type": "markdown", + "source": [ + "In this notebook, we will give an example on how to run simple ASR inference using MMS ASR model.\n", + "\n", + "Credit to epk2112 [(github)](https://github.com/epk2112/fairseq_meta_mms_Google_Colab_implementation)" + ], + "metadata": { + "id": "83HXBIFeJzR8" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Step 1: Clone fairseq-py and install latest version" + ], + "metadata": { + "id": "2GfxksHDGyJv" + } + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Cj2x80SegRzr", + "outputId": "6fc00051-095a-4c31-b1d7-5d6150b29c3f" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Cloning into 'fairseq'...\n", + "remote: Enumerating objects: 34665, done.\u001b[K\n", + "remote: Counting objects: 100% (122/122), done.\u001b[K\n", + "remote: Compressing objects: 100% (75/75), done.\u001b[K\n", + "remote: Total 34665 (delta 54), reused 95 (delta 43), pack-reused 34543\u001b[K\n", + "Receiving objects: 100% (34665/34665), 24.15 MiB | 17.76 MiB/s, done.\n", + "Resolving deltas: 100% (25155/25155), done.\n", + "/content\n", + "/content/fairseq\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Obtaining file:///content/fairseq\n", + " Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n", + " Checking if build backend supports build_editable ... \u001b[?25l\u001b[?25hdone\n", + " Getting requirements to build editable ... \u001b[?25l\u001b[?25hdone\n", + " Preparing editable metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: cffi in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.15.1)\n", + "Requirement already satisfied: cython in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (0.29.34)\n", + "Collecting hydra-core<1.1,>=1.0.7 (from fairseq==0.12.2)\n", + " Downloading hydra_core-1.0.7-py3-none-any.whl (123 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m123.8/123.8 kB\u001b[0m \u001b[31m8.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting omegaconf<2.1 (from fairseq==0.12.2)\n", + " Downloading omegaconf-2.0.6-py3-none-any.whl (36 kB)\n", + "Requirement already satisfied: numpy>=1.21.3 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.22.4)\n", + "Requirement already satisfied: regex in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2022.10.31)\n", + "Collecting sacrebleu>=1.4.12 (from fairseq==0.12.2)\n", + " Downloading sacrebleu-2.3.1-py3-none-any.whl (118 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m118.9/118.9 kB\u001b[0m \u001b[31m14.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: torch>=1.13 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.0.1+cu118)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (4.65.0)\n", + "Collecting bitarray (from fairseq==0.12.2)\n", + " Downloading bitarray-2.7.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (272 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m272.7/272.7 kB\u001b[0m \u001b[31m31.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: torchaudio>=0.8.0 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.0.2+cu118)\n", + "Requirement already satisfied: scikit-learn in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.2.2)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (23.1)\n", + "Collecting antlr4-python3-runtime==4.8 (from hydra-core<1.1,>=1.0.7->fairseq==0.12.2)\n", + " Downloading antlr4-python3-runtime-4.8.tar.gz (112 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m112.4/112.4 kB\u001b[0m \u001b[31m14.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: PyYAML>=5.1.* in /usr/local/lib/python3.10/dist-packages (from omegaconf<2.1->fairseq==0.12.2) (6.0)\n", + "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from omegaconf<2.1->fairseq==0.12.2) (4.5.0)\n", + "Collecting portalocker (from sacrebleu>=1.4.12->fairseq==0.12.2)\n", + " Downloading portalocker-2.7.0-py2.py3-none-any.whl (15 kB)\n", + "Requirement already satisfied: tabulate>=0.8.9 in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (0.8.10)\n", + "Collecting colorama (from sacrebleu>=1.4.12->fairseq==0.12.2)\n", + " Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n", + "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (4.9.2)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.12.0)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (1.11.1)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.1)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.1.2)\n", + "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (2.0.0)\n", + "Requirement already satisfied: cmake in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.13->fairseq==0.12.2) (3.25.2)\n", + "Requirement already satisfied: lit in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.13->fairseq==0.12.2) (16.0.5)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi->fairseq==0.12.2) (2.21)\n", + "Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (1.10.1)\n", + "Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (1.2.0)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (3.1.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch>=1.13->fairseq==0.12.2) (2.1.2)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch>=1.13->fairseq==0.12.2) (1.3.0)\n", + "Building wheels for collected packages: fairseq, antlr4-python3-runtime\n", + " Building editable for fairseq (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for fairseq: filename=fairseq-0.12.2-0.editable-cp310-cp310-linux_x86_64.whl size=9219 sha256=60586109fcfccbe70c24f4b74de99293bf152d71bdf29c9ff077fe587b6f904c\n", + " Stored in directory: /tmp/pip-ephem-wheel-cache-66_gqcet/wheels/c6/d7/db/bc419b1daa8266aa8de2a7c4d29f62dbfa814e8701fe4695a2\n", + " Building wheel for antlr4-python3-runtime (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for antlr4-python3-runtime: filename=antlr4_python3_runtime-4.8-py3-none-any.whl size=141210 sha256=093f7101c99b9c3851f9274e3810b043703665387b06cffd934c4b77c22b6506\n", + " Stored in directory: /root/.cache/pip/wheels/a7/20/bd/e1477d664f22d99989fd28ee1a43d6633dddb5cb9e801350d5\n", + "Successfully built fairseq antlr4-python3-runtime\n", + "Installing collected packages: bitarray, antlr4-python3-runtime, portalocker, omegaconf, colorama, sacrebleu, hydra-core, fairseq\n", + "Successfully installed antlr4-python3-runtime-4.8 bitarray-2.7.3 colorama-0.4.6 fairseq-0.12.2 hydra-core-1.0.7 omegaconf-2.0.6 portalocker-2.7.0 sacrebleu-2.3.1\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting tensorboardX\n", + " Downloading tensorboardX-2.6-py2.py3-none-any.whl (114 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m114.5/114.5 kB\u001b[0m \u001b[31m7.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (1.22.4)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (23.1)\n", + "Requirement already satisfied: protobuf<4,>=3.8.0 in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (3.20.3)\n", + "Installing collected packages: tensorboardX\n", + "Successfully installed tensorboardX-2.6\n" + ] + } + ], + "source": [ + "!mkdir \"temp_dir\"\n", + "!git clone https://github.com/pytorch/fairseq\n", + "\n", + "# Change current working directory\n", + "!pwd\n", + "%cd \"/content/fairseq\"\n", + "!pip install --editable ./ \n", + "!pip install tensorboardX\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## 2. Download MMS model\n", + "Un-comment to download your preferred model.\n", + "In this example, we use MMS-FL102 for demo purposes.\n", + "For better model quality and language coverage, user can use MMS-1B-ALL model instead (but it would require more RAM, so please use Colab-Pro instead of Colab-Free).\n" + ], + "metadata": { + "id": "cyk4JvZOHSw3" + } + }, + { + "cell_type": "code", + "source": [ + "# MMS-1B:FL102 model - 102 Languages - FLEURS Dataset\n", + "!wget -P ./models_new 'https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt'\n", + "\n", + "# # MMS-1B:L1107 - 1107 Languages - MMS-lab Dataset\n", + "# !wget -P ./models_new 'https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107.pt'\n", + "\n", + "# # MMS-1B-all - 1162 Languages - MMS-lab + FLEURS + CV + VP + MLS\n", + "# !wget -P ./models_new 'https://dl.fbaipublicfiles.com/mms/asr/mms1b_all.pt'" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3uZ9WG85gZId", + "outputId": "0133ddf8-a163-4afc-94b8-ff701ab6d852" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2023-05-25 17:15:24-- https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt\n", + "Resolving dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)... 13.227.219.33, 13.227.219.59, 13.227.219.10, ...\n", + "Connecting to dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)|13.227.219.33|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 4851043301 (4.5G) [binary/octet-stream]\n", + "Saving to: ‘./models_new/mms1b_fl102.pt’\n", + "\n", + "mms1b_fl102.pt 100%[===================>] 4.52G 189MB/s in 26s \n", + "\n", + "2023-05-25 17:15:51 (176 MB/s) - ‘./models_new/mms1b_fl102.pt’ saved [4851043301/4851043301]\n", + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## 3. Prepare audio file\n", + "Create a folder on path '/content/audio_samples/' and upload your .wav audio files that you need to transcribe e.g. '/content/audio_samples/audio.wav' \n", + "\n", + "Note: You need to make sure that the audio data you are using has a sample rate of 16kHz You can easily do this with FFMPEG like the example below that converts .mp3 file to .wav and fixing the audio sample rate\n", + "\n", + "Here, we use a FLEURS english MP3 audio for the example." + ], + "metadata": { + "id": "3p5-TQvKHXjO" + } + }, + { + "cell_type": "code", + "source": [ + "!wget -P ./audio_samples/ 'https://datasets-server.huggingface.co/assets/google/fleurs/--/en_us/train/0/audio/audio.mp3'\n", + "!ffmpeg -y -i ./audio_samples/audio.mp3 -ar 16000 ./audio_samples/audio.wav" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cnim4bokprbB", + "outputId": "eed691fd-d960-4964-a16c-072b44cebff8" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2023-05-25 17:15:51-- https://datasets-server.huggingface.co/assets/google/fleurs/--/en_us/train/0/audio/audio.mp3\n", + "Resolving datasets-server.huggingface.co (datasets-server.huggingface.co)... 54.165.66.147, 34.200.186.24, 44.197.252.161, ...\n", + "Connecting to datasets-server.huggingface.co (datasets-server.huggingface.co)|54.165.66.147|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 20853 (20K) [audio/mpeg]\n", + "Saving to: ‘./audio_samples/audio.mp3’\n", + "\n", + "audio.mp3 100%[===================>] 20.36K --.-KB/s in 0.09s \n", + "\n", + "2023-05-25 17:15:51 (238 KB/s) - ‘./audio_samples/audio.mp3’ saved [20853/20853]\n", + "\n", + "ffmpeg version 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developers\n", + " built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)\n", + " configuration: --prefix=/usr --extra-version=0ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared\n", + " libavutil 56. 31.100 / 56. 31.100\n", + " libavcodec 58. 54.100 / 58. 54.100\n", + " libavformat 58. 29.100 / 58. 29.100\n", + " libavdevice 58. 8.100 / 58. 8.100\n", + " libavfilter 7. 57.100 / 7. 57.100\n", + " libavresample 4. 0. 0 / 4. 0. 0\n", + " libswscale 5. 5.100 / 5. 5.100\n", + " libswresample 3. 5.100 / 3. 5.100\n", + " libpostproc 55. 5.100 / 55. 5.100\n", + "Input #0, mp3, from './audio_samples/audio.mp3':\n", + " Metadata:\n", + " encoder : Lavf58.45.100\n", + " Duration: 00:00:06.88, start: 0.069063, bitrate: 24 kb/s\n", + " Stream #0:0: Audio: mp3, 16000 Hz, mono, fltp, 24 kb/s\n", + "Stream mapping:\n", + " Stream #0:0 -> #0:0 (mp3 (mp3float) -> pcm_s16le (native))\n", + "Press [q] to stop, [?] for help\n", + "Output #0, wav, to './audio_samples/audio.wav':\n", + " Metadata:\n", + " ISFT : Lavf58.29.100\n", + " Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s\n", + " Metadata:\n", + " encoder : Lavc58.54.100 pcm_s16le\n", + "size= 213kB time=00:00:06.80 bitrate= 256.1kbits/s speed= 363x \n", + "video:0kB audio:212kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.035846%\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# 4: Run Inference and transcribe your audio(s)\n" + ], + "metadata": { + "id": "44UvHjmMI28Z" + } + }, + { + "cell_type": "markdown", + "source": [ + "In the below example, we will transcribe a sentence in English.\n", + "\n", + "To transcribe other languages: \n", + "1. Go to [MMS README ASR section](https://github.com/facebookresearch/fairseq/tree/main/examples/mms#asr)\n", + "2. Open Supported languages link\n", + "3. Find your target languages based on Language Name column\n", + "4. Copy the corresponding Iso Code\n", + "5. Replace `--lang \"eng\"` with new Iso Code\n", + "\n", + "To improve the transcription quality, user can use language-model (LM) decoding by following this instruction [ASR LM decoding](https://github.com/facebookresearch/fairseq/tree/main/examples/mms#asr)" + ], + "metadata": { + "id": "82Xpxot2wFid" + } + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "os.environ[\"TMPDIR\"] = '/content/temp_dir'\n", + "os.environ[\"PYTHONPATH\"] = \".\"\n", + "os.environ[\"PREFIX\"] = \"INFER\"\n", + "os.environ[\"HYDRA_FULL_ERROR\"] = \"1\"\n", + "os.environ[\"USER\"] = \"micro\"\n", + "\n", + "!python examples/mms/asr/infer/mms_infer.py --model \"/content/fairseq/models_new/mms1b_fl102.pt\" --lang \"eng\" --audio \"/content/fairseq/audio_samples/audio.wav\"\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "J8N1RKtBiw5V", + "outputId": "5fd67547-ec76-4ba0-b353-08e7b355673d" + }, + "execution_count": 4, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + ">>> preparing tmp manifest dir ...\n", + ">>> loading model & running inference ...\n", + "2023-05-25 17:15:58.935762: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2023-05-25 17:16:01.850306: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", + "===============\n", + "Input: /content/fairseq/audio_samples/audio.wav\n", + "Output: a tornado is a spinning colum of very low-pressure air which sucks it surrounding air inward and upward\n" + ] + } + ] + } + ] +} \ No newline at end of file From 68c52f52c6503f1129c89b38679ab8080f120af2 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Thu, 25 May 2023 11:30:14 -0700 Subject: [PATCH 748/774] [MMS] Create Colab notebook for LID inference (#5157) * [MMS] Create Colab Notebook for LID task * Update README.md * Update README.md --- examples/mms/README.md | 23 +- .../tutorial/MMS_LID_Inference_Colab.ipynb | 389 ++++++++++++++++++ 2 files changed, 401 insertions(+), 11 deletions(-) create mode 100644 examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb diff --git a/examples/mms/README.md b/examples/mms/README.md index 8685a8bff2..093facc600 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -6,16 +6,6 @@ You can find details in the paper [Scaling Speech Technology to 1000+ languages] An overview of the languages covered by MMS can be found [here](https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html). - -## Pretrained models - -| Model | Link -|---|--- -MMS-300M | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_300m.pt) -MMS-1B | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_1b.pt) - -Example commands to finetune the pretrained models can be found [here](https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). - ## Finetuned models ### ASR @@ -56,7 +46,7 @@ cd /path/to/fairseq-py/ python examples/mms/asr/infer/mms_infer.py --model "/path/to/asr/model" --lang lang_code \ --audio "/path/to/audio_1.wav" "/path/to/audio_2.wav" "/path/to/audio_3.wav" ``` -We also provide an Ipython notebook example in inside `asr/tutorial` folder [ipynb](https://github.com/facebookresearch/fairseq/blob/androstj-patch-1/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb) or [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/facebookresearch/fairseq/blob/main/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb) +We also provide an Ipython notebook example inside `asr/tutorial` folder [ipynb](https://github.com/facebookresearch/fairseq/blob/main/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb) or [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/facebookresearch/fairseq/blob/main/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb) For more advance configuration and calculate CER/WER, you could prepare manifest folder by creating a folder with this format: @@ -160,6 +150,17 @@ $ PYTHONPATH='.' python3 examples/mms/lid/infer.py /path/to/dict/l126/ --path ``` The above command assumes there is a file named `dict.lang.txt` in `/path/to/dict/l126/`. `<OUTDIR>/predictions.txt` will contain the predictions from the model for the audio files in `manifest.tsv`. +We also provide an Ipython notebook example inside `lid/tutorial` folder [ipynb](https://github.com/facebookresearch/fairseq/blob/main/examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb) or [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/facebookresearch/fairseq/blob/main/examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb) + + +## Pretrained models + +| Model | Link +|---|--- +MMS-300M | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_300m.pt) +MMS-1B | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_1b.pt) + +Example commands to finetune the pretrained models can be found [here](https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). ## Forced Alignment Tooling diff --git a/examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb b/examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb new file mode 100644 index 0000000000..59d8cf9e3d --- /dev/null +++ b/examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb @@ -0,0 +1,389 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU", + "gpuClass": "standard" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Running MMS-LID inference in Colab" + ], + "metadata": { + "id": "Rhm7khm6GskV" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Step 1: Clone fairseq-py and install latest version" + ], + "metadata": { + "id": "2GfxksHDGyJv" + } + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Cj2x80SegRzr", + "outputId": "c81e367d-ec5f-4b17-b375-6980d6291c43" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "fatal: destination path 'fairseq' already exists and is not an empty directory.\n", + "/content\n", + "/content/fairseq\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Obtaining file:///content/fairseq\n", + " Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n", + " Checking if build backend supports build_editable ... \u001b[?25l\u001b[?25hdone\n", + " Getting requirements to build editable ... \u001b[?25l\u001b[?25hdone\n", + " Preparing editable metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: cffi in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.15.1)\n", + "Requirement already satisfied: cython in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (0.29.34)\n", + "Requirement already satisfied: hydra-core<1.1,>=1.0.7 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.0.7)\n", + "Requirement already satisfied: omegaconf<2.1 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.0.6)\n", + "Requirement already satisfied: numpy>=1.21.3 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.22.4)\n", + "Requirement already satisfied: regex in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2022.10.31)\n", + "Requirement already satisfied: sacrebleu>=1.4.12 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.3.1)\n", + "Requirement already satisfied: torch>=1.13 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.0.1+cu118)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (4.65.0)\n", + "Requirement already satisfied: bitarray in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.7.3)\n", + "Requirement already satisfied: torchaudio>=0.8.0 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.0.2+cu118)\n", + "Requirement already satisfied: scikit-learn in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.2.2)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (23.1)\n", + "Requirement already satisfied: antlr4-python3-runtime==4.8 in /usr/local/lib/python3.10/dist-packages (from hydra-core<1.1,>=1.0.7->fairseq==0.12.2) (4.8)\n", + "Requirement already satisfied: PyYAML>=5.1.* in /usr/local/lib/python3.10/dist-packages (from omegaconf<2.1->fairseq==0.12.2) (6.0)\n", + "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from omegaconf<2.1->fairseq==0.12.2) (4.5.0)\n", + "Requirement already satisfied: portalocker in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (2.7.0)\n", + "Requirement already satisfied: tabulate>=0.8.9 in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (0.8.10)\n", + "Requirement already satisfied: colorama in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (0.4.6)\n", + "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (4.9.2)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.12.0)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (1.11.1)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.1)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.1.2)\n", + "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (2.0.0)\n", + "Requirement already satisfied: cmake in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.13->fairseq==0.12.2) (3.25.2)\n", + "Requirement already satisfied: lit in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.13->fairseq==0.12.2) (16.0.5)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi->fairseq==0.12.2) (2.21)\n", + "Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (1.10.1)\n", + "Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (1.2.0)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (3.1.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch>=1.13->fairseq==0.12.2) (2.1.2)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch>=1.13->fairseq==0.12.2) (1.3.0)\n", + "Building wheels for collected packages: fairseq\n", + " Building editable for fairseq (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for fairseq: filename=fairseq-0.12.2-0.editable-cp310-cp310-linux_x86_64.whl size=9219 sha256=b6289e3715902d34fd7c54490679210a5be155dd4416754f0e8c376f193b5ac4\n", + " Stored in directory: /tmp/pip-ephem-wheel-cache-o62sj_ry/wheels/c6/d7/db/bc419b1daa8266aa8de2a7c4d29f62dbfa814e8701fe4695a2\n", + "Successfully built fairseq\n", + "Installing collected packages: fairseq\n", + " Attempting uninstall: fairseq\n", + " Found existing installation: fairseq 0.12.2\n", + " Uninstalling fairseq-0.12.2:\n", + " Successfully uninstalled fairseq-0.12.2\n", + "Successfully installed fairseq-0.12.2\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: tensorboardX in /usr/local/lib/python3.10/dist-packages (2.6)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (1.22.4)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (23.1)\n", + "Requirement already satisfied: protobuf<4,>=3.8.0 in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (3.20.3)\n" + ] + } + ], + "source": [ + "import os\n", + "\n", + "!git clone https://github.com/pytorch/fairseq\n", + "\n", + "# Change current working directory\n", + "!pwd\n", + "%cd \"/content/fairseq\"\n", + "!pip install --editable ./ \n", + "!pip install tensorboardX\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## 2. Download MMS-LID model\n", + "\n" + ], + "metadata": { + "id": "cyk4JvZOHSw3" + } + }, + { + "cell_type": "code", + "source": [ + "available_models = [\"l126\", \"l256\", \"l512\", \"l1024\", \"l2048\", \"l4017\"]\n", + "\n", + "# We will use L126 model which can recognize 126 languages \n", + "model_name = available_models[0] # l126\n", + "print(f\"Using model - {model_name}\")\n", + "print(f\"Visit https://dl.fbaipublicfiles.com/mms/lid/mms1b_{model_name}_langs.html to check all the languages supported by this model.\")\n", + "\n", + "! mkdir -p /content/models_lid\n", + "!wget -P /content/models_lid/{model_name} 'https://dl.fbaipublicfiles.com/mms/lid/mms1b_{model_name}.pt'\n", + "!wget -P /content/models_lid/{model_name} 'https://dl.fbaipublicfiles.com/mms/lid/dict/l126/dict.lang.txt'\n", + "\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3uZ9WG85gZId", + "outputId": "93f456ab-7aa1-47ac-a054-c0e3417b2e5e" + }, + "execution_count": 5, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Using model - l126\n", + "Visit https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126_langs.html to check all the languages supported by this model.\n", + "--2023-05-25 18:18:45-- https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126.pt\n", + "Resolving dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)... 52.84.251.15, 52.84.251.114, 52.84.251.27, ...\n", + "Connecting to dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)|52.84.251.15|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 3856229421 (3.6G) [binary/octet-stream]\n", + "Saving to: ‘/content/models_lid/l126/mms1b_l126.pt’\n", + "\n", + "mms1b_l126.pt 100%[===================>] 3.59G 198MB/s in 24s \n", + "\n", + "2023-05-25 18:19:09 (155 MB/s) - ‘/content/models_lid/l126/mms1b_l126.pt’ saved [3856229421/3856229421]\n", + "\n", + "--2023-05-25 18:19:09-- https://dl.fbaipublicfiles.com/mms/lid/dict/l126/dict.lang.txt\n", + "Resolving dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)... 52.84.251.15, 52.84.251.114, 52.84.251.27, ...\n", + "Connecting to dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)|52.84.251.15|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 882 [text/plain]\n", + "Saving to: ‘/content/models_lid/l126/dict.lang.txt’\n", + "\n", + "dict.lang.txt 100%[===================>] 882 --.-KB/s in 0s \n", + "\n", + "2023-05-25 18:19:09 (183 MB/s) - ‘/content/models_lid/l126/dict.lang.txt’ saved [882/882]\n", + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "## 3. Prepare manifest files\n", + "Create a folder on path '/content/audio_samples/' and upload your .wav audio files that you need to recognize e.g. '/content/audio_samples/abc.wav' , '/content/audio_samples/def.wav' etc...\n", + "\n", + "Note: You need to make sure that the audio data you are using has a sample rate of 16kHz You can easily do this with FFMPEG like the example below that converts .mp3 file to .flac and fixing the audio sample rate\n", + "\n", + "Here, we use three examples - one audio file from English, Hindi, Chinese each. " + ], + "metadata": { + "id": "3p5-TQvKHXjO" + } + }, + { + "cell_type": "code", + "source": [ + "! mkdir -p /content/audio_samples/\n", + "for key in [\"en_us\", \"hi_in\", \"cmn_hans_cn\"]:\n", + " !wget -O /content/audio_samples/tmp.mp3 https://datasets-server.huggingface.co/assets/google/fleurs/--/{key}/train/0/audio/audio.mp3\n", + " !ffmpeg -hide_banner -loglevel error -y -i /content/audio_samples/tmp.mp3 -ar 16000 /content/audio_samples/{key}.wav\n", + "\n", + "! mkdir -p /content/audio_samples/\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cnim4bokprbB", + "outputId": "89026a92-0518-49c2-9c84-98f0966caeac" + }, + "execution_count": 6, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2023-05-25 18:19:09-- https://datasets-server.huggingface.co/assets/google/fleurs/--/en_us/train/0/audio/audio.mp3\n", + "Resolving datasets-server.huggingface.co (datasets-server.huggingface.co)... 34.200.186.24, 44.197.252.161, 54.165.66.147, ...\n", + "Connecting to datasets-server.huggingface.co (datasets-server.huggingface.co)|34.200.186.24|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 20853 (20K) [audio/mpeg]\n", + "Saving to: ‘/content/audio_samples/tmp.mp3’\n", + "\n", + "/content/audio_samp 100%[===================>] 20.36K 92.8KB/s in 0.2s \n", + "\n", + "2023-05-25 18:19:11 (92.8 KB/s) - ‘/content/audio_samples/tmp.mp3’ saved [20853/20853]\n", + "\n", + "--2023-05-25 18:19:12-- https://datasets-server.huggingface.co/assets/google/fleurs/--/hi_in/train/0/audio/audio.mp3\n", + "Resolving datasets-server.huggingface.co (datasets-server.huggingface.co)... 34.200.186.24, 44.197.252.161, 54.165.66.147, ...\n", + "Connecting to datasets-server.huggingface.co (datasets-server.huggingface.co)|34.200.186.24|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 26361 (26K) [audio/mpeg]\n", + "Saving to: ‘/content/audio_samples/tmp.mp3’\n", + "\n", + "/content/audio_samp 100%[===================>] 25.74K 116KB/s in 0.2s \n", + "\n", + "2023-05-25 18:19:13 (116 KB/s) - ‘/content/audio_samples/tmp.mp3’ saved [26361/26361]\n", + "\n", + "--2023-05-25 18:19:13-- https://datasets-server.huggingface.co/assets/google/fleurs/--/cmn_hans_cn/train/0/audio/audio.mp3\n", + "Resolving datasets-server.huggingface.co (datasets-server.huggingface.co)... 34.200.186.24, 44.197.252.161, 54.165.66.147, ...\n", + "Connecting to datasets-server.huggingface.co (datasets-server.huggingface.co)|34.200.186.24|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 23877 (23K) [audio/mpeg]\n", + "Saving to: ‘/content/audio_samples/tmp.mp3’\n", + "\n", + "/content/audio_samp 100%[===================>] 23.32K 105KB/s in 0.2s \n", + "\n", + "2023-05-25 18:19:14 (105 KB/s) - ‘/content/audio_samples/tmp.mp3’ saved [23877/23877]\n", + "\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "! mkdir -p /content/manifest/\n", + "import os\n", + "with open(\"/content/manifest/dev.tsv\", \"w\") as ftsv, open(\"/content/manifest/dev.lang\", \"w\") as flang:\n", + " ftsv.write(\"/\\n\")\n", + "\n", + " for fl in os.listdir(\"/content/audio_samples/\"):\n", + " if not fl.endswith(\".wav\"):\n", + " continue\n", + " audio_path = f\"/content/audio_samples/{fl}\"\n", + " # duration should be number of samples in audio. For inference, using a random value should be fine. \n", + " duration = 1234 \n", + " ftsv.write(f\"{audio_path}\\t{duration}\\n\")\n", + " flang.write(\"eng\\n\") # This is the \"true\" language for the audio. For inference, using a random value should be fine. \n" + ], + "metadata": { + "id": "C2QcjRT-BArW" + }, + "execution_count": 7, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# 4: Run Inference and transcribe your audio(s)\n" + ], + "metadata": { + "id": "44UvHjmMI28Z" + } + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "os.environ[\"PYTHONPATH\"] = \"/content/fairseq\"\n", + "os.environ[\"PREFIX\"] = \"INFER\"\n", + "os.environ[\"HYDRA_FULL_ERROR\"] = \"1\"\n", + "os.environ[\"USER\"] = \"mms_lid_user\"\n", + "\n", + "!python3 examples/mms/lid/infer.py /content/models_lid/{model_name} --path /content/models_lid/{model_name}/mms1b_l126.pt \\\n", + " --task audio_classification --infer-manifest /content/manifest/dev.tsv --output-path /content/manifest/" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "J8N1RKtBiw5V", + "outputId": "09d3fe43-26a4-4f9b-c56d-d38b6d45cdab" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "2023-05-25 18:19:19.545731: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2023-05-25 18:19:21.567795: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", + "| loading model from /content/models_lid/l126/mms1b_l126.pt\n", + "2023-05-25 18:19:29 | INFO | fairseq.tasks.audio_classification | Using dict_path : /content/models_lid/l126/dict.lang.txt\n", + "2023-05-25 18:19:29 | INFO | root | === Number of labels = 126\n", + "2023-05-25 18:20:01 | INFO | fairseq.data.audio.raw_audio_dataset | loaded 3, skipped 0 samples\n", + "2023-05-25 18:20:01 | INFO | fairseq.tasks.fairseq_task | can_reuse_epoch_itr = True\n", + "2023-05-25 18:20:01 | INFO | fairseq.tasks.fairseq_task | reuse_dataloader = True\n", + "2023-05-25 18:20:01 | INFO | fairseq.tasks.fairseq_task | rebuild_batches = True\n", + "2023-05-25 18:20:01 | INFO | fairseq.tasks.fairseq_task | batches will be rebuilt for each epoch\n", + "2023-05-25 18:20:01 | INFO | fairseq.tasks.fairseq_task | creating new batches for epoch 1\n", + "/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py:560: UserWarning: This DataLoader will create 4 worker processes in total. Our suggested max number of worker in current system is 2, which is smaller than what this DataLoader is going to create. Please be aware that excessive worker creation might get DataLoader running slow or even freeze, lower the worker number to avoid potential slowness/freeze if necessary.\n", + " warnings.warn(_create_warning_msg(\n", + "3it [00:07, 2.61s/it]\n", + "Outputs will be located at - /content/manifest//predictions.txt\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "print(\"----- INPUT FILES -----\")\n", + "! tail -n +2 /content/manifest/dev.tsv\n", + "\n", + "print(\"\\n----- TOP-K PREDICTONS WITH SCORE -----\")\n", + "! cat /content/manifest//predictions.txt" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5f7FROqiC-2z", + "outputId": "3a28ceee-dbb7-4810-f9ca-d11b14a8340b" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "----- INPUT FILES -----\n", + "/content/audio_samples/hi_in.wav\t1234\n", + "/content/audio_samples/en_us.wav\t1234\n", + "/content/audio_samples/cmn_hans_cn.wav\t1234\n", + "\n", + "----- TOP-K PREDICTONS WITH SCORE -----\n", + "[[\"hin\", 0.9931250810623169], [\"urd\", 0.005808886140584946], [\"snd\", 0.0005312535213306546]]\n", + "[[\"eng\", 0.9989539980888367], [\"fas\", 0.00036296260077506304], [\"haw\", 7.031611312413588e-05]]\n", + "[[\"cmn\", 0.9996059536933899], [\"bod\", 0.0002111078501911834], [\"kor\", 9.211552242049947e-05]]\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "TzHHmno5DZC4" + }, + "execution_count": null, + "outputs": [] + } + ] +} From 35641fb41e5e7bd49e48df37e8aab2fbac673012 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Thu, 25 May 2023 18:50:46 -0700 Subject: [PATCH 749/774] [MMS] Add a tutorial on CC LM decoding for ASR model (#5160) * Update MMS_ASR_Inference_Colab.ipynb * Update mms_infer.py --- examples/mms/asr/infer/mms_infer.py | 3 +- .../tutorial/MMS_ASR_Inference_Colab.ipynb | 1394 +++++++++++++++-- 2 files changed, 1303 insertions(+), 94 deletions(-) diff --git a/examples/mms/asr/infer/mms_infer.py b/examples/mms/asr/infer/mms_infer.py index 65f86b3148..fde92ab2d9 100644 --- a/examples/mms/asr/infer/mms_infer.py +++ b/examples/mms/asr/infer/mms_infer.py @@ -19,6 +19,7 @@ def parser(): parser.add_argument("--audio", type=str, help="path to audio file", required=True, nargs='+') parser.add_argument("--lang", type=str, help="audio language", required=True) parser.add_argument("--format", type=str, choices=["none", "letter"], default="letter") + parser.add_argument("--extra-infer-args", type=str, default="") return parser.parse_args() def reorder_decode(hypos): @@ -45,7 +46,7 @@ def process(args): with open(tmpdir / "dev.wrd", "w") as fw: fw.write("dummy dummy\n"*len(args.audio)) cmd = f""" - PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=1440000 distributed_training.distributed_world_size=1 "common_eval.path='{args.model}'" task.data={tmpdir} dataset.gen_subset="{args.lang}:dev" common_eval.post_process={args.format} decoding.results_path={tmpdir} + PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=1440000 distributed_training.distributed_world_size=1 "common_eval.path='{args.model}'" task.data={tmpdir} dataset.gen_subset="{args.lang}:dev" common_eval.post_process={args.format} decoding.results_path={tmpdir} {args.extra_infer_args} """ print(">>> loading model & running inference ...", file=sys.stderr) subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL,) diff --git a/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb b/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb index a243cb1f29..5a577e4088 100644 --- a/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb +++ b/examples/mms/asr/tutorial/MMS_ASR_Inference_Colab.ipynb @@ -29,7 +29,7 @@ { "cell_type": "markdown", "source": [ - "In this notebook, we will give an example on how to run simple ASR inference using MMS ASR model.\n", + "In this notebook, we will give an example on how to run simple ASR inference using MMS ASR model. \n", "\n", "Credit to epk2112 [(github)](https://github.com/epk2112/fairseq_meta_mms_Google_Colab_implementation)" ], @@ -48,98 +48,30 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 7, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Cj2x80SegRzr", - "outputId": "6fc00051-095a-4c31-b1d7-5d6150b29c3f" + "outputId": "00f9f833-3ff1-4736-e170-136875b88299" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ - "Cloning into 'fairseq'...\n", - "remote: Enumerating objects: 34665, done.\u001b[K\n", - "remote: Counting objects: 100% (122/122), done.\u001b[K\n", - "remote: Compressing objects: 100% (75/75), done.\u001b[K\n", - "remote: Total 34665 (delta 54), reused 95 (delta 43), pack-reused 34543\u001b[K\n", - "Receiving objects: 100% (34665/34665), 24.15 MiB | 17.76 MiB/s, done.\n", - "Resolving deltas: 100% (25155/25155), done.\n", - "/content\n", + "fatal: destination path 'fairseq' already exists and is not an empty directory.\n", + "/content/fairseq\n", "/content/fairseq\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", "Obtaining file:///content/fairseq\n", - " Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n", - " Checking if build backend supports build_editable ... \u001b[?25l\u001b[?25hdone\n", - " Getting requirements to build editable ... \u001b[?25l\u001b[?25hdone\n", - " Preparing editable metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", - "Requirement already satisfied: cffi in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.15.1)\n", - "Requirement already satisfied: cython in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (0.29.34)\n", - "Collecting hydra-core<1.1,>=1.0.7 (from fairseq==0.12.2)\n", - " Downloading hydra_core-1.0.7-py3-none-any.whl (123 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m123.8/123.8 kB\u001b[0m \u001b[31m8.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hCollecting omegaconf<2.1 (from fairseq==0.12.2)\n", - " Downloading omegaconf-2.0.6-py3-none-any.whl (36 kB)\n", - "Requirement already satisfied: numpy>=1.21.3 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.22.4)\n", - "Requirement already satisfied: regex in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2022.10.31)\n", - "Collecting sacrebleu>=1.4.12 (from fairseq==0.12.2)\n", - " Downloading sacrebleu-2.3.1-py3-none-any.whl (118 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m118.9/118.9 kB\u001b[0m \u001b[31m14.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hRequirement already satisfied: torch>=1.13 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.0.1+cu118)\n", - "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (4.65.0)\n", - "Collecting bitarray (from fairseq==0.12.2)\n", - " Downloading bitarray-2.7.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (272 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m272.7/272.7 kB\u001b[0m \u001b[31m31.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hRequirement already satisfied: torchaudio>=0.8.0 in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (2.0.2+cu118)\n", - "Requirement already satisfied: scikit-learn in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (1.2.2)\n", - "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from fairseq==0.12.2) (23.1)\n", - "Collecting antlr4-python3-runtime==4.8 (from hydra-core<1.1,>=1.0.7->fairseq==0.12.2)\n", - " Downloading antlr4-python3-runtime-4.8.tar.gz (112 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m112.4/112.4 kB\u001b[0m \u001b[31m14.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - "Requirement already satisfied: PyYAML>=5.1.* in /usr/local/lib/python3.10/dist-packages (from omegaconf<2.1->fairseq==0.12.2) (6.0)\n", - "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from omegaconf<2.1->fairseq==0.12.2) (4.5.0)\n", - "Collecting portalocker (from sacrebleu>=1.4.12->fairseq==0.12.2)\n", - " Downloading portalocker-2.7.0-py2.py3-none-any.whl (15 kB)\n", - "Requirement already satisfied: tabulate>=0.8.9 in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (0.8.10)\n", - "Collecting colorama (from sacrebleu>=1.4.12->fairseq==0.12.2)\n", - " Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n", - "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from sacrebleu>=1.4.12->fairseq==0.12.2) (4.9.2)\n", - "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.12.0)\n", - "Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (1.11.1)\n", - "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.1)\n", - "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (3.1.2)\n", - "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.10/dist-packages (from torch>=1.13->fairseq==0.12.2) (2.0.0)\n", - "Requirement already satisfied: cmake in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.13->fairseq==0.12.2) (3.25.2)\n", - "Requirement already satisfied: lit in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.13->fairseq==0.12.2) (16.0.5)\n", - "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi->fairseq==0.12.2) (2.21)\n", - "Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (1.10.1)\n", - "Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (1.2.0)\n", - "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->fairseq==0.12.2) (3.1.0)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch>=1.13->fairseq==0.12.2) (2.1.2)\n", - "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch>=1.13->fairseq==0.12.2) (1.3.0)\n", - "Building wheels for collected packages: fairseq, antlr4-python3-runtime\n", - " Building editable for fairseq (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for fairseq: filename=fairseq-0.12.2-0.editable-cp310-cp310-linux_x86_64.whl size=9219 sha256=60586109fcfccbe70c24f4b74de99293bf152d71bdf29c9ff077fe587b6f904c\n", - " Stored in directory: /tmp/pip-ephem-wheel-cache-66_gqcet/wheels/c6/d7/db/bc419b1daa8266aa8de2a7c4d29f62dbfa814e8701fe4695a2\n", - " Building wheel for antlr4-python3-runtime (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for antlr4-python3-runtime: filename=antlr4_python3_runtime-4.8-py3-none-any.whl size=141210 sha256=093f7101c99b9c3851f9274e3810b043703665387b06cffd934c4b77c22b6506\n", - " Stored in directory: /root/.cache/pip/wheels/a7/20/bd/e1477d664f22d99989fd28ee1a43d6633dddb5cb9e801350d5\n", - "Successfully built fairseq antlr4-python3-runtime\n", - "Installing collected packages: bitarray, antlr4-python3-runtime, portalocker, omegaconf, colorama, sacrebleu, hydra-core, fairseq\n", - "Successfully installed antlr4-python3-runtime-4.8 bitarray-2.7.3 colorama-0.4.6 fairseq-0.12.2 hydra-core-1.0.7 omegaconf-2.0.6 portalocker-2.7.0 sacrebleu-2.3.1\n", - "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Collecting tensorboardX\n", - " Downloading tensorboardX-2.6-py2.py3-none-any.whl (114 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m114.5/114.5 kB\u001b[0m \u001b[31m7.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hRequirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (1.22.4)\n", + " Installing build dependencies ... \u001b[?25l\u001b[?25hcanceled\u001b[31mERROR: Operation cancelled by user\u001b[0m\u001b[31m\n", + "\u001b[0mLooking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: tensorboardX in /usr/local/lib/python3.10/dist-packages (2.6)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (1.22.4)\n", "Requirement already satisfied: packaging in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (23.1)\n", - "Requirement already satisfied: protobuf<4,>=3.8.0 in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (3.20.3)\n", - "Installing collected packages: tensorboardX\n", - "Successfully installed tensorboardX-2.6\n" + "Requirement already satisfied: protobuf<4,>=3.8.0 in /usr/local/lib/python3.10/dist-packages (from tensorboardX) (3.20.3)\n" ] } ], @@ -183,7 +115,7 @@ "base_uri": "https://localhost:8080/" }, "id": "3uZ9WG85gZId", - "outputId": "0133ddf8-a163-4afc-94b8-ff701ab6d852" + "outputId": "3b13f908-aa8a-4207-9147-60c443ced571" }, "execution_count": 2, "outputs": [ @@ -191,16 +123,16 @@ "output_type": "stream", "name": "stdout", "text": [ - "--2023-05-25 17:15:24-- https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt\n", - "Resolving dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)... 13.227.219.33, 13.227.219.59, 13.227.219.10, ...\n", + "--2023-05-25 23:53:33-- https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt\n", + "Resolving dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)... 13.227.219.33, 13.227.219.59, 13.227.219.70, ...\n", "Connecting to dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)|13.227.219.33|:443... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 4851043301 (4.5G) [binary/octet-stream]\n", "Saving to: ‘./models_new/mms1b_fl102.pt’\n", "\n", - "mms1b_fl102.pt 100%[===================>] 4.52G 189MB/s in 26s \n", + "mms1b_fl102.pt 100%[===================>] 4.52G 242MB/s in 20s \n", "\n", - "2023-05-25 17:15:51 (176 MB/s) - ‘./models_new/mms1b_fl102.pt’ saved [4851043301/4851043301]\n", + "2023-05-25 23:53:53 (230 MB/s) - ‘./models_new/mms1b_fl102.pt’ saved [4851043301/4851043301]\n", "\n" ] } @@ -231,7 +163,7 @@ "base_uri": "https://localhost:8080/" }, "id": "cnim4bokprbB", - "outputId": "eed691fd-d960-4964-a16c-072b44cebff8" + "outputId": "f63ed14f-0bde-4517-ee7b-200ddcc45e5f" }, "execution_count": 3, "outputs": [ @@ -239,16 +171,16 @@ "output_type": "stream", "name": "stdout", "text": [ - "--2023-05-25 17:15:51-- https://datasets-server.huggingface.co/assets/google/fleurs/--/en_us/train/0/audio/audio.mp3\n", - "Resolving datasets-server.huggingface.co (datasets-server.huggingface.co)... 54.165.66.147, 34.200.186.24, 44.197.252.161, ...\n", - "Connecting to datasets-server.huggingface.co (datasets-server.huggingface.co)|54.165.66.147|:443... connected.\n", + "--2023-05-25 23:53:53-- https://datasets-server.huggingface.co/assets/google/fleurs/--/en_us/train/0/audio/audio.mp3\n", + "Resolving datasets-server.huggingface.co (datasets-server.huggingface.co)... 50.17.173.235, 44.197.252.161, 3.216.183.114, ...\n", + "Connecting to datasets-server.huggingface.co (datasets-server.huggingface.co)|50.17.173.235|:443... connected.\n", "HTTP request sent, awaiting response... 200 OK\n", "Length: 20853 (20K) [audio/mpeg]\n", "Saving to: ‘./audio_samples/audio.mp3’\n", "\n", "audio.mp3 100%[===================>] 20.36K --.-KB/s in 0.09s \n", "\n", - "2023-05-25 17:15:51 (238 KB/s) - ‘./audio_samples/audio.mp3’ saved [20853/20853]\n", + "2023-05-25 23:53:53 (238 KB/s) - ‘./audio_samples/audio.mp3’ saved [20853/20853]\n", "\n", "ffmpeg version 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developers\n", " built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)\n", @@ -276,7 +208,7 @@ " Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s\n", " Metadata:\n", " encoder : Lavc58.54.100 pcm_s16le\n", - "size= 213kB time=00:00:06.80 bitrate= 256.1kbits/s speed= 363x \n", + "size= 213kB time=00:00:06.80 bitrate= 256.1kbits/s speed= 398x \n", "video:0kB audio:212kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.035846%\n" ] } @@ -327,7 +259,7 @@ "base_uri": "https://localhost:8080/" }, "id": "J8N1RKtBiw5V", - "outputId": "5fd67547-ec76-4ba0-b353-08e7b355673d" + "outputId": "db5d3575-bd21-470d-bb4d-e080e8cece50" }, "execution_count": 4, "outputs": [ @@ -337,15 +269,1291 @@ "text": [ ">>> preparing tmp manifest dir ...\n", ">>> loading model & running inference ...\n", - "2023-05-25 17:15:58.935762: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "2023-05-25 23:54:02.330426: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2023-05-25 17:16:01.850306: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", + "2023-05-25 23:54:04.144981: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", "===============\n", "Input: /content/fairseq/audio_samples/audio.wav\n", "Output: a tornado is a spinning colum of very low-pressure air which sucks it surrounding air inward and upward\n" ] } ] + }, + { + "cell_type": "markdown", + "source": [ + "# 5: Beam search decoding using a Language Model and transcribe audio file(s)\n" + ], + "metadata": { + "id": "0j2t8MI4WBiy" + } + }, + { + "cell_type": "markdown", + "source": [ + "Since MMS is a CTC model, we can further improve the accuracy by running beam search decoding using a language model. \n", + "\n", + "While we have not open sourced the language models used in MMS (yet!), we have provided the details of the data and commands to used to train the LMs in the Appendix section of our paper.\n", + "\n", + "\n", + "For this tutorial, we will use a alternate English language model based on Common Crawl data which has been made publicly available through the efforts of [Likhomanenko, Tatiana, et al. \"Rethinking evaluation in asr: Are our models robust enough?.\"](https://arxiv.org/abs/2010.11745). The language model can be accessed from the GitHub repository [here](https://github.com/flashlight/wav2letter/tree/main/recipes/rasr). " + ], + "metadata": { + "id": "Yfigq1nIWJR6" + } + }, + { + "cell_type": "code", + "source": [ + "! mkdir -p /content/lmdecode \n", + "\n", + "!wget -P /content/lmdecode https://dl.fbaipublicfiles.com/wav2letter/rasr/tutorial/lm_common_crawl_small_4gram_prun0-6-15_200kvocab.bin # smaller LM \n", + "!wget -P /content/lmdecode https://dl.fbaipublicfiles.com/wav2letter/rasr/tutorial/lexicon.txt " + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "sNTd1OCuV8jG", + "outputId": "396583b9-400f-4b68-aa20-898f0194da6e" + }, + "execution_count": 10, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2023-05-26 00:16:03-- https://dl.fbaipublicfiles.com/wav2letter/rasr/tutorial/lm_common_crawl_small_4gram_prun0-6-15_200kvocab.bin\n", + "Resolving dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)... 13.227.219.33, 13.227.219.70, 13.227.219.10, ...\n", + "Connecting to dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)|13.227.219.33|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 2627163608 (2.4G) [application/octet-stream]\n", + "Saving to: ‘/content/lmdecode/lm_common_crawl_small_4gram_prun0-6-15_200kvocab.bin’\n", + "\n", + "lm_common_crawl_sma 100%[===================>] 2.45G 27.5MB/s in 94s \n", + "\n", + "2023-05-26 00:17:37 (26.8 MB/s) - ‘/content/lmdecode/lm_common_crawl_small_4gram_prun0-6-15_200kvocab.bin’ saved [2627163608/2627163608]\n", + "\n", + "--2023-05-26 00:17:37-- https://dl.fbaipublicfiles.com/wav2letter/rasr/tutorial/lexicon.txt\n", + "Resolving dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)... 13.227.219.33, 13.227.219.10, 13.227.219.70, ...\n", + "Connecting to dl.fbaipublicfiles.com (dl.fbaipublicfiles.com)|13.227.219.33|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 4965720 (4.7M) [text/plain]\n", + "Saving to: ‘/content/lmdecode/lexicon.txt’\n", + "\n", + "lexicon.txt 100%[===================>] 4.74M 5.02MB/s in 0.9s \n", + "\n", + "2023-05-26 00:17:39 (5.02 MB/s) - ‘/content/lmdecode/lexicon.txt’ saved [4965720/4965720]\n", + "\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "Install decoder bindings from [flashlight](https://github.com/flashlight/flashlight)\n" + ], + "metadata": { + "id": "8HKmVaRfhHIk" + } + }, + { + "cell_type": "code", + "source": [ + "# Taken from https://github.com/flashlight/flashlight/blob/main/scripts/colab/colab_install_deps.sh \n", + "# Install dependencies from apt\n", + "! sudo apt-get install -y libfftw3-dev libsndfile1-dev libgoogle-glog-dev libopenmpi-dev libboost-all-dev\n", + "# Install Kenlm\n", + "! cd /tmp && git clone https://github.com/kpu/kenlm && cd kenlm && mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make install -j$(nproc)\n", + "\n", + "# Install Intel MKL 2020\n", + "! cd /tmp && wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB && \\\n", + " apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB\n", + "! sh -c 'echo deb https://apt.repos.intel.com/mkl all main > /etc/apt/sources.list.d/intel-mkl.list' && \\\n", + " apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends intel-mkl-64bit-2020.0-088\n", + "# Remove existing MKL libs to avoid double linkeage\n", + "! rm -rf /usr/local/lib/libmkl*\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Kao8FS-GjR94", + "outputId": "e9d0da1e-266d-4b46-aba4-32f25350fe2b" + }, + "execution_count": 37, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Reading package lists... Done\n", + "Building dependency tree \n", + "Reading state information... Done\n", + "libboost-all-dev is already the newest version (1.71.0.0ubuntu2).\n", + "libopenmpi-dev is already the newest version (4.0.3-0ubuntu1).\n", + "libsndfile1-dev is already the newest version (1.0.28-7ubuntu0.1).\n", + "The following additional packages will be installed:\n", + " libfftw3-bin libfftw3-long3 libfftw3-quad3 libfftw3-single3 libgflags-dev\n", + " libgflags2.2 libgoogle-glog0v5\n", + "Suggested packages:\n", + " libfftw3-doc\n", + "The following NEW packages will be installed:\n", + " libfftw3-bin libfftw3-dev libfftw3-long3 libfftw3-quad3 libfftw3-single3\n", + " libgflags-dev libgflags2.2 libgoogle-glog-dev libgoogle-glog0v5\n", + "0 upgraded, 9 newly installed, 0 to remove and 35 not upgraded.\n", + "Need to get 4,289 kB of archives.\n", + "After this operation, 24.0 MB of additional disk space will be used.\n", + "Get:1 http://archive.ubuntu.com/ubuntu focal/main amd64 libfftw3-long3 amd64 3.3.8-2ubuntu1 [313 kB]\n", + "Get:2 http://archive.ubuntu.com/ubuntu focal/main amd64 libfftw3-quad3 amd64 3.3.8-2ubuntu1 [673 kB]\n", + "Get:3 http://archive.ubuntu.com/ubuntu focal/main amd64 libfftw3-single3 amd64 3.3.8-2ubuntu1 [756 kB]\n", + "Get:4 http://archive.ubuntu.com/ubuntu focal/main amd64 libfftw3-bin amd64 3.3.8-2ubuntu1 [32.2 kB]\n", + "Get:5 http://archive.ubuntu.com/ubuntu focal/main amd64 libfftw3-dev amd64 3.3.8-2ubuntu1 [2,211 kB]\n", + "Get:6 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgflags2.2 amd64 2.2.2-1build1 [78.0 kB]\n", + "Get:7 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgflags-dev amd64 2.2.2-1build1 [96.6 kB]\n", + "Get:8 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgoogle-glog0v5 amd64 0.4.0-1build1 [51.5 kB]\n", + "Get:9 http://archive.ubuntu.com/ubuntu focal/universe amd64 libgoogle-glog-dev amd64 0.4.0-1build1 [76.4 kB]\n", + "Fetched 4,289 kB in 1s (3,516 kB/s)\n", + "debconf: unable to initialize frontend: Dialog\n", + "debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76, <> line 9.)\n", + "debconf: falling back to frontend: Readline\n", + "debconf: unable to initialize frontend: Readline\n", + "debconf: (This frontend requires a controlling tty.)\n", + "debconf: falling back to frontend: Teletype\n", + "dpkg-preconfigure: unable to re-open stdin: \n", + "Selecting previously unselected package libfftw3-long3:amd64.\n", + "(Reading database ... 124889 files and directories currently installed.)\n", + "Preparing to unpack .../0-libfftw3-long3_3.3.8-2ubuntu1_amd64.deb ...\n", + "Unpacking libfftw3-long3:amd64 (3.3.8-2ubuntu1) ...\n", + "Selecting previously unselected package libfftw3-quad3:amd64.\n", + "Preparing to unpack .../1-libfftw3-quad3_3.3.8-2ubuntu1_amd64.deb ...\n", + "Unpacking libfftw3-quad3:amd64 (3.3.8-2ubuntu1) ...\n", + "Selecting previously unselected package libfftw3-single3:amd64.\n", + "Preparing to unpack .../2-libfftw3-single3_3.3.8-2ubuntu1_amd64.deb ...\n", + "Unpacking libfftw3-single3:amd64 (3.3.8-2ubuntu1) ...\n", + "Selecting previously unselected package libfftw3-bin.\n", + "Preparing to unpack .../3-libfftw3-bin_3.3.8-2ubuntu1_amd64.deb ...\n", + "Unpacking libfftw3-bin (3.3.8-2ubuntu1) ...\n", + "Selecting previously unselected package libfftw3-dev:amd64.\n", + "Preparing to unpack .../4-libfftw3-dev_3.3.8-2ubuntu1_amd64.deb ...\n", + "Unpacking libfftw3-dev:amd64 (3.3.8-2ubuntu1) ...\n", + "Selecting previously unselected package libgflags2.2.\n", + "Preparing to unpack .../5-libgflags2.2_2.2.2-1build1_amd64.deb ...\n", + "Unpacking libgflags2.2 (2.2.2-1build1) ...\n", + "Selecting previously unselected package libgflags-dev.\n", + "Preparing to unpack .../6-libgflags-dev_2.2.2-1build1_amd64.deb ...\n", + "Unpacking libgflags-dev (2.2.2-1build1) ...\n", + "Selecting previously unselected package libgoogle-glog0v5.\n", + "Preparing to unpack .../7-libgoogle-glog0v5_0.4.0-1build1_amd64.deb ...\n", + "Unpacking libgoogle-glog0v5 (0.4.0-1build1) ...\n", + "Selecting previously unselected package libgoogle-glog-dev.\n", + "Preparing to unpack .../8-libgoogle-glog-dev_0.4.0-1build1_amd64.deb ...\n", + "Unpacking libgoogle-glog-dev (0.4.0-1build1) ...\n", + "Setting up libfftw3-single3:amd64 (3.3.8-2ubuntu1) ...\n", + "Setting up libfftw3-long3:amd64 (3.3.8-2ubuntu1) ...\n", + "Setting up libfftw3-quad3:amd64 (3.3.8-2ubuntu1) ...\n", + "Setting up libgflags2.2 (2.2.2-1build1) ...\n", + "Setting up libfftw3-bin (3.3.8-2ubuntu1) ...\n", + "Setting up libgflags-dev (2.2.2-1build1) ...\n", + "Setting up libfftw3-dev:amd64 (3.3.8-2ubuntu1) ...\n", + "Setting up libgoogle-glog0v5 (0.4.0-1build1) ...\n", + "Setting up libgoogle-glog-dev (0.4.0-1build1) ...\n", + "Processing triggers for man-db (2.9.1-1) ...\n", + "Processing triggers for libc-bin (2.31-0ubuntu9.9) ...\n", + "Cloning into 'kenlm'...\n", + "remote: Enumerating objects: 14147, done.\u001b[K\n", + "remote: Counting objects: 100% (460/460), done.\u001b[K\n", + "remote: Compressing objects: 100% (319/319), done.\u001b[K\n", + "remote: Total 14147 (delta 152), reused 399 (delta 127), pack-reused 13687\u001b[K\n", + "Receiving objects: 100% (14147/14147), 5.91 MiB | 15.20 MiB/s, done.\n", + "Resolving deltas: 100% (8032/8032), done.\n", + "-- The C compiler identification is GNU 9.4.0\n", + "-- The CXX compiler identification is GNU 9.4.0\n", + "-- Detecting C compiler ABI info\n", + "-- Detecting C compiler ABI info - done\n", + "-- Check for working C compiler: /usr/bin/cc - skipped\n", + "-- Detecting C compile features\n", + "-- Detecting C compile features - done\n", + "-- Detecting CXX compiler ABI info\n", + "-- Detecting CXX compiler ABI info - done\n", + "-- Check for working CXX compiler: /usr/bin/c++ - skipped\n", + "-- Detecting CXX compile features\n", + "-- Detecting CXX compile features - done\n", + "-- Could NOT find Eigen3 (missing: Eigen3_DIR)\n", + "-- Found Boost: /usr/lib/x86_64-linux-gnu/cmake/Boost-1.71.0/BoostConfig.cmake (found suitable version \"1.71.0\", minimum required is \"1.41.0\") found components: program_options system thread unit_test_framework \n", + "-- Check if compiler accepts -pthread\n", + "-- Check if compiler accepts -pthread - yes\n", + "-- Found Threads: TRUE \n", + "-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version \"1.2.11\") \n", + "-- Found BZip2: /usr/lib/x86_64-linux-gnu/libbz2.so (found version \"1.0.8\") \n", + "-- Looking for BZ2_bzCompressInit\n", + "-- Looking for BZ2_bzCompressInit - found\n", + "-- Looking for lzma_auto_decoder in /usr/lib/x86_64-linux-gnu/liblzma.so\n", + "-- Looking for lzma_auto_decoder in /usr/lib/x86_64-linux-gnu/liblzma.so - found\n", + "-- Looking for lzma_easy_encoder in /usr/lib/x86_64-linux-gnu/liblzma.so\n", + "-- Looking for lzma_easy_encoder in /usr/lib/x86_64-linux-gnu/liblzma.so - found\n", + "-- Looking for lzma_lzma_preset in /usr/lib/x86_64-linux-gnu/liblzma.so\n", + "-- Looking for lzma_lzma_preset in /usr/lib/x86_64-linux-gnu/liblzma.so - found\n", + "-- Found LibLZMA: /usr/lib/x86_64-linux-gnu/liblzma.so (found version \"5.2.4\") \n", + "-- Looking for clock_gettime in rt\n", + "-- Looking for clock_gettime in rt - found\n", + "-- Configuring done\n", + "-- Generating done\n", + "-- Build files have been written to: /tmp/kenlm/build\n", + "[ 1%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/bignum-dtoa.cc.o\u001b[0m\n", + "[ 2%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/bignum.cc.o\u001b[0m\n", + "[ 3%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/cached-powers.cc.o\u001b[0m\n", + "[ 5%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/fast-dtoa.cc.o\u001b[0m\n", + "[ 6%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/fixed-dtoa.cc.o\u001b[0m\n", + "[ 7%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/strtod.cc.o\u001b[0m\n", + "[ 8%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/double-to-string.cc.o\u001b[0m\n", + "[ 10%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/double-conversion/string-to-double.cc.o\u001b[0m\n", + "[ 11%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/stream/chain.cc.o\u001b[0m\n", + "[ 12%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/stream/count_records.cc.o\u001b[0m\n", + "[ 13%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/stream/io.cc.o\u001b[0m\n", + "[ 15%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/stream/line_input.cc.o\u001b[0m\n", + "[ 16%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/stream/multi_progress.cc.o\u001b[0m\n", + "[ 17%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/stream/rewindable_stream.cc.o\u001b[0m\n", + "[ 18%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/bit_packing.cc.o\u001b[0m\n", + "[ 20%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/ersatz_progress.cc.o\u001b[0m\n", + "[ 21%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/exception.cc.o\u001b[0m\n", + "[ 22%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/file.cc.o\u001b[0m\n", + "[ 23%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/file_piece.cc.o\u001b[0m\n", + "[ 25%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/float_to_string.cc.o\u001b[0m\n", + "[ 26%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/integer_to_string.cc.o\u001b[0m\n", + "[ 27%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/mmap.cc.o\u001b[0m\n", + "[ 28%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/murmur_hash.cc.o\u001b[0m\n", + "[ 30%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/parallel_read.cc.o\u001b[0m\n", + "[ 31%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/pool.cc.o\u001b[0m\n", + "[ 32%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/read_compressed.cc.o\u001b[0m\n", + "[ 33%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/scoped.cc.o\u001b[0m\n", + "[ 35%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/spaces.cc.o\u001b[0m\n", + "[ 36%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/string_piece.cc.o\u001b[0m\n", + "[ 37%] \u001b[32mBuilding CXX object util/CMakeFiles/kenlm_util.dir/usage.cc.o\u001b[0m\n", + "[ 38%] \u001b[32m\u001b[1mLinking CXX static library ../lib/libkenlm_util.a\u001b[0m\n", + "[ 38%] Built target kenlm_util\n", + "[ 40%] \u001b[32mBuilding CXX object util/CMakeFiles/probing_hash_table_benchmark.dir/probing_hash_table_benchmark_main.cc.o\u001b[0m\n", + "[ 41%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/bhiksha.cc.o\u001b[0m\n", + "[ 42%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/binary_format.cc.o\u001b[0m\n", + "[ 43%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/config.cc.o\u001b[0m\n", + "[ 45%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/lm_exception.cc.o\u001b[0m\n", + "[ 46%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/model.cc.o\u001b[0m\n", + "[ 47%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/quantize.cc.o\u001b[0m\n", + "[ 48%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/read_arpa.cc.o\u001b[0m\n", + "[ 50%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/search_hashed.cc.o\u001b[0m\n", + "[ 51%] \u001b[32m\u001b[1mLinking CXX executable ../bin/probing_hash_table_benchmark\u001b[0m\n", + "[ 51%] Built target probing_hash_table_benchmark\n", + "[ 52%] \u001b[32mBuilding CXX object lm/filter/CMakeFiles/kenlm_filter.dir/arpa_io.cc.o\u001b[0m\n", + "[ 53%] \u001b[32mBuilding CXX object lm/filter/CMakeFiles/kenlm_filter.dir/phrase.cc.o\u001b[0m\n", + "[ 55%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/search_trie.cc.o\u001b[0m\n", + "[ 56%] \u001b[32mBuilding CXX object lm/filter/CMakeFiles/kenlm_filter.dir/vocab.cc.o\u001b[0m\n", + "[ 57%] \u001b[32m\u001b[1mLinking CXX static library ../../lib/libkenlm_filter.a\u001b[0m\n", + "[ 57%] Built target kenlm_filter\n", + "[ 58%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/sizes.cc.o\u001b[0m\n", + "[ 60%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/trie.cc.o\u001b[0m\n", + "[ 61%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/trie_sort.cc.o\u001b[0m\n", + "[ 62%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/value_build.cc.o\u001b[0m\n", + "[ 63%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/virtual_interface.cc.o\u001b[0m\n", + "[ 65%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/vocab.cc.o\u001b[0m\n", + "[ 66%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/common/model_buffer.cc.o\u001b[0m\n", + "[ 67%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/common/print.cc.o\u001b[0m\n", + "[ 68%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/common/renumber.cc.o\u001b[0m\n", + "[ 70%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm.dir/common/size_option.cc.o\u001b[0m\n", + "[ 71%] \u001b[32m\u001b[1mLinking CXX static library ../lib/libkenlm.a\u001b[0m\n", + "[ 71%] Built target kenlm\n", + "[ 72%] \u001b[32mBuilding CXX object lm/CMakeFiles/query.dir/query_main.cc.o\u001b[0m\n", + "[ 73%] \u001b[32mBuilding CXX object lm/CMakeFiles/fragment.dir/fragment_main.cc.o\u001b[0m\n", + "[ 75%] \u001b[32m\u001b[1mLinking CXX executable ../bin/fragment\u001b[0m\n", + "[ 75%] Built target fragment\n", + "[ 76%] \u001b[32mBuilding CXX object lm/CMakeFiles/build_binary.dir/build_binary_main.cc.o\u001b[0m\n", + "[ 77%] \u001b[32m\u001b[1mLinking CXX executable ../bin/query\u001b[0m\n", + "[ 77%] Built target query\n", + "[ 78%] \u001b[32mBuilding CXX object lm/CMakeFiles/kenlm_benchmark.dir/kenlm_benchmark_main.cc.o\u001b[0m\n", + "[ 80%] \u001b[32m\u001b[1mLinking CXX executable ../bin/build_binary\u001b[0m\n", + "[ 80%] Built target build_binary\n", + "[ 81%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/kenlm_builder.dir/adjust_counts.cc.o\u001b[0m\n", + "[ 82%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/kenlm_builder.dir/corpus_count.cc.o\u001b[0m\n", + "[ 83%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/kenlm_builder.dir/initial_probabilities.cc.o\u001b[0m\n", + "[ 85%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/kenlm_builder.dir/interpolate.cc.o\u001b[0m\n", + "[ 86%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/kenlm_builder.dir/output.cc.o\u001b[0m\n", + "[ 87%] \u001b[32m\u001b[1mLinking CXX executable ../bin/kenlm_benchmark\u001b[0m\n", + "[ 87%] Built target kenlm_benchmark\n", + "[ 88%] \u001b[32mBuilding CXX object lm/filter/CMakeFiles/filter.dir/filter_main.cc.o\u001b[0m\n", + "[ 90%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/kenlm_builder.dir/pipeline.cc.o\u001b[0m\n", + "[ 91%] \u001b[32m\u001b[1mLinking CXX static library ../../lib/libkenlm_builder.a\u001b[0m\n", + "[ 91%] Built target kenlm_builder\n", + "[ 92%] \u001b[32mBuilding CXX object lm/filter/CMakeFiles/phrase_table_vocab.dir/phrase_table_vocab_main.cc.o\u001b[0m\n", + "[ 93%] \u001b[32m\u001b[1mLinking CXX executable ../../bin/phrase_table_vocab\u001b[0m\n", + "[ 93%] Built target phrase_table_vocab\n", + "[ 95%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/lmplz.dir/lmplz_main.cc.o\u001b[0m\n", + "[ 96%] \u001b[32m\u001b[1mLinking CXX executable ../../bin/filter\u001b[0m\n", + "[ 96%] Built target filter\n", + "[ 97%] \u001b[32mBuilding CXX object lm/builder/CMakeFiles/count_ngrams.dir/count_ngrams_main.cc.o\u001b[0m\n", + "[ 98%] \u001b[32m\u001b[1mLinking CXX executable ../../bin/lmplz\u001b[0m\n", + "[ 98%] Built target lmplz\n", + "[100%] \u001b[32m\u001b[1mLinking CXX executable ../../bin/count_ngrams\u001b[0m\n", + "[100%] Built target count_ngrams\n", + "\u001b[36mInstall the project...\u001b[0m\n", + "-- Install configuration: \"Release\"\n", + "-- Installing: /usr/local/share/kenlm/cmake/kenlmTargets.cmake\n", + "-- Installing: /usr/local/share/kenlm/cmake/kenlmTargets-release.cmake\n", + "-- Installing: /usr/local/include/kenlm/util/bit_packing.hh\n", + "-- Installing: /usr/local/include/kenlm/util/ersatz_progress.hh\n", + "-- Installing: /usr/local/include/kenlm/util/exception.hh\n", + "-- Installing: /usr/local/include/kenlm/util/fake_ostream.hh\n", + "-- Installing: /usr/local/include/kenlm/util/file.hh\n", + "-- Installing: /usr/local/include/kenlm/util/file_piece.hh\n", + "-- Installing: /usr/local/include/kenlm/util/file_stream.hh\n", + "-- Installing: /usr/local/include/kenlm/util/fixed_array.hh\n", + "-- Installing: /usr/local/include/kenlm/util/float_to_string.hh\n", + "-- Installing: /usr/local/include/kenlm/util/getopt.hh\n", + "-- Installing: /usr/local/include/kenlm/util/have.hh\n", + "-- Installing: /usr/local/include/kenlm/util/integer_to_string.hh\n", + "-- Installing: /usr/local/include/kenlm/util/joint_sort.hh\n", + "-- Installing: /usr/local/include/kenlm/util/mmap.hh\n", + "-- Installing: /usr/local/include/kenlm/util/multi_intersection.hh\n", + "-- Installing: /usr/local/include/kenlm/util/murmur_hash.hh\n", + "-- Installing: /usr/local/include/kenlm/util/parallel_read.hh\n", + "-- Installing: /usr/local/include/kenlm/util/pcqueue.hh\n", + "-- Installing: /usr/local/include/kenlm/util/pool.hh\n", + "-- Installing: /usr/local/include/kenlm/util/probing_hash_table.hh\n", + "-- Installing: /usr/local/include/kenlm/util/proxy_iterator.hh\n", + "-- Installing: /usr/local/include/kenlm/util/read_compressed.hh\n", + "-- Installing: /usr/local/include/kenlm/util/scoped.hh\n", + "-- Installing: /usr/local/include/kenlm/util/sized_iterator.hh\n", + "-- Installing: /usr/local/include/kenlm/util/sorted_uniform.hh\n", + "-- Installing: /usr/local/include/kenlm/util/spaces.hh\n", + "-- Installing: /usr/local/include/kenlm/util/string_piece.hh\n", + "-- Installing: /usr/local/include/kenlm/util/string_piece_hash.hh\n", + "-- Installing: /usr/local/include/kenlm/util/string_stream.hh\n", + "-- Installing: /usr/local/include/kenlm/util/thread_pool.hh\n", + "-- Installing: /usr/local/include/kenlm/util/tokenize_piece.hh\n", + "-- Installing: /usr/local/include/kenlm/util/usage.hh\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/bignum-dtoa.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/bignum.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/cached-powers.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/diy-fp.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/double-conversion.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/double-to-string.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/fast-dtoa.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/fixed-dtoa.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/ieee.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/string-to-double.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/strtod.h\n", + "-- Installing: /usr/local/include/kenlm/util/double-conversion/utils.h\n", + "-- Installing: /usr/local/include/kenlm/util/stream/block.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/chain.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/config.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/count_records.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/io.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/line_input.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/multi_progress.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/multi_stream.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/rewindable_stream.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/sort.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/stream.hh\n", + "-- Installing: /usr/local/include/kenlm/util/stream/typed_stream.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/bhiksha.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/binary_format.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/blank.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/config.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/enumerate_vocab.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/facade.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/left.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/lm_exception.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/max_order.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/model.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/model_type.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/ngram_query.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/partial.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/quantize.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/read_arpa.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/return.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/search_hashed.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/search_trie.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/sizes.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/state.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/trie.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/trie_sort.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/value.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/value_build.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/virtual_interface.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/vocab.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/weights.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/word_index.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/adjust_counts.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/combine_counts.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/corpus_count.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/debug_print.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/discount.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/hash_gamma.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/header_info.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/initial_probabilities.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/interpolate.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/output.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/payload.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/builder/pipeline.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/compare.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/joint_order.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/model_buffer.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/ngram.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/ngram_stream.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/print.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/renumber.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/size_option.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/common/special.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/filter/arpa_io.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/filter/count_io.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/filter/format.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/filter/phrase.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/filter/thread.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/filter/vocab.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/filter/wrapper.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/backoff_matrix.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/backoff_reunification.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/bounded_sequence_encoding.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/interpolate_info.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/merge_probabilities.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/merge_vocab.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/normalize.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/pipeline.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/split_worker.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/tune_derivatives.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/tune_instances.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/tune_matrix.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/tune_weights.hh\n", + "-- Installing: /usr/local/include/kenlm/lm/interpolate/universal_vocab.hh\n", + "-- Installing: /usr/local/share/kenlm/cmake/kenlmConfig.cmake\n", + "-- Installing: /usr/local/lib/libkenlm_util.a\n", + "-- Installing: /usr/local/bin/probing_hash_table_benchmark\n", + "-- Installing: /usr/local/lib/libkenlm.a\n", + "-- Installing: /usr/local/bin/query\n", + "-- Installing: /usr/local/bin/fragment\n", + "-- Installing: /usr/local/bin/build_binary\n", + "-- Installing: /usr/local/bin/kenlm_benchmark\n", + "-- Installing: /usr/local/bin/lmplz\n", + "-- Installing: /usr/local/bin/count_ngrams\n", + "-- Installing: /usr/local/lib/libkenlm_builder.a\n", + "-- Installing: /usr/local/bin/filter\n", + "-- Installing: /usr/local/bin/phrase_table_vocab\n", + "-- Installing: /usr/local/lib/libkenlm_filter.a\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "! rm -rf flashlight\n", + "! git clone --recursive https://github.com/flashlight/flashlight.git\n", + "%cd flashlight\n", + "! git checkout 035ead6efefb82b47c8c2e643603e87d38850076 \n", + "%cd bindings/python \n", + "! python3 setup.py install\n", + "\n", + "%cd /content/fairseq " + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5LjIgBfzhQ4w", + "outputId": "5d1023c5-f6ad-46b1-9326-b51965c722c3" + }, + "execution_count": 38, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Cloning into 'flashlight'...\n", + "remote: Enumerating objects: 24032, done.\u001b[K\n", + "remote: Counting objects: 100% (150/150), done.\u001b[K\n", + "remote: Compressing objects: 100% (123/123), done.\u001b[K\n", + "remote: Total 24032 (delta 41), reused 111 (delta 24), pack-reused 23882\u001b[K\n", + "Receiving objects: 100% (24032/24032), 15.30 MiB | 2.64 MiB/s, done.\n", + "Resolving deltas: 100% (17089/17089), done.\n", + "/content/fairseq/flashlight\n", + "Note: switching to '035ead6efefb82b47c8c2e643603e87d38850076'.\n", + "\n", + "You are in 'detached HEAD' state. You can look around, make experimental\n", + "changes and commit them, and you can discard any commits you make in this\n", + "state without impacting any branches by switching back to a branch.\n", + "\n", + "If you want to create a new branch to retain commits you create, you may\n", + "do so (now or later) by using -c with the switch command. Example:\n", + "\n", + " git switch -c <new-branch-name>\n", + "\n", + "Or undo this operation with:\n", + "\n", + " git switch -\n", + "\n", + "Turn off this advice by setting config variable advice.detachedHead to false\n", + "\n", + "HEAD is now at 035ead6e AdvancedIndex fix\n", + "/content/fairseq/flashlight/bindings/python\n", + "running install\n", + "/usr/local/lib/python3.10/dist-packages/setuptools/_distutils/cmd.py:66: SetuptoolsDeprecationWarning: setup.py install is deprecated.\n", + "!!\n", + "\n", + " ********************************************************************************\n", + " Please avoid running ``setup.py`` directly.\n", + " Instead, use pypa/build, pypa/installer, pypa/build or\n", + " other standards-based tools.\n", + "\n", + " See https://blog.ganssle.io/articles/2021/10/setup-py-deprecated.html for details.\n", + " ********************************************************************************\n", + "\n", + "!!\n", + " self.initialize_options()\n", + "/usr/local/lib/python3.10/dist-packages/setuptools/_distutils/cmd.py:66: EasyInstallDeprecationWarning: easy_install command is deprecated.\n", + "!!\n", + "\n", + " ********************************************************************************\n", + " Please avoid running ``setup.py`` and ``easy_install``.\n", + " Instead, use pypa/build, pypa/installer, pypa/build or\n", + " other standards-based tools.\n", + "\n", + " See https://github.com/pypa/setuptools/issues/917 for details.\n", + " ********************************************************************************\n", + "\n", + "!!\n", + " self.initialize_options()\n", + "running bdist_egg\n", + "running egg_info\n", + "creating flashlight.egg-info\n", + "writing flashlight.egg-info/PKG-INFO\n", + "writing dependency_links to flashlight.egg-info/dependency_links.txt\n", + "writing top-level names to flashlight.egg-info/top_level.txt\n", + "writing manifest file 'flashlight.egg-info/SOURCES.txt'\n", + "reading manifest file 'flashlight.egg-info/SOURCES.txt'\n", + "reading manifest template 'MANIFEST.in'\n", + "writing manifest file 'flashlight.egg-info/SOURCES.txt'\n", + "installing library code to build/bdist.linux-x86_64/egg\n", + "running install_lib\n", + "running build_py\n", + "creating build\n", + "creating build/lib.linux-x86_64-cpython-310\n", + "creating build/lib.linux-x86_64-cpython-310/flashlight\n", + "creating build/lib.linux-x86_64-cpython-310/flashlight/lib\n", + "copying flashlight/lib/__init__.py -> build/lib.linux-x86_64-cpython-310/flashlight/lib\n", + "creating build/lib.linux-x86_64-cpython-310/flashlight/lib/audio\n", + "copying flashlight/lib/audio/feature.py -> build/lib.linux-x86_64-cpython-310/flashlight/lib/audio\n", + "creating build/lib.linux-x86_64-cpython-310/flashlight/lib/sequence\n", + "copying flashlight/lib/sequence/criterion_torch.py -> build/lib.linux-x86_64-cpython-310/flashlight/lib/sequence\n", + "copying flashlight/lib/sequence/criterion.py -> build/lib.linux-x86_64-cpython-310/flashlight/lib/sequence\n", + "creating build/lib.linux-x86_64-cpython-310/flashlight/lib/text\n", + "copying flashlight/lib/text/dictionary.py -> build/lib.linux-x86_64-cpython-310/flashlight/lib/text\n", + "copying flashlight/lib/text/decoder.py -> build/lib.linux-x86_64-cpython-310/flashlight/lib/text\n", + "running build_ext\n", + "-- The CXX compiler identification is GNU 9.4.0\n", + "-- The C compiler identification is GNU 9.4.0\n", + "-- Detecting CXX compiler ABI info\n", + "-- Detecting CXX compiler ABI info - done\n", + "-- Check for working CXX compiler: /usr/bin/c++ - skipped\n", + "-- Detecting CXX compile features\n", + "-- Detecting CXX compile features - done\n", + "-- Detecting C compiler ABI info\n", + "-- Detecting C compiler ABI info - done\n", + "-- Check for working C compiler: /usr/bin/cc - skipped\n", + "-- Detecting C compile features\n", + "-- Detecting C compile features - done\n", + "-- Performing Test COMPILER_SUPPORTS_RDYNAMIC\n", + "-- Performing Test COMPILER_SUPPORTS_RDYNAMIC - Success\n", + "-- -rdynamic supported.\n", + "-- The CUDA compiler identification is NVIDIA 11.8.89\n", + "-- Detecting CUDA compiler ABI info\n", + "-- Detecting CUDA compiler ABI info - done\n", + "-- Check for working CUDA compiler: /usr/local/cuda/bin/nvcc - skipped\n", + "-- Detecting CUDA compile features\n", + "-- Detecting CUDA compile features - done\n", + "-- Performing Test CMAKE_HAVE_LIBC_PTHREAD\n", + "-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed\n", + "-- Looking for pthread_create in pthreads\n", + "-- Looking for pthread_create in pthreads - not found\n", + "-- Looking for pthread_create in pthread\n", + "-- Looking for pthread_create in pthread - found\n", + "-- Found Threads: TRUE \n", + "-- CUDA found (library: /usr/local/cuda/lib64/libcudart_static.a;Threads::Threads;dl;/usr/lib/x86_64-linux-gnu/librt.so include: /usr/local/cuda/include)\n", + "-- CUDA architecture flags: -gencodearch=compute_35,code=sm_35-gencodearch=compute_50,code=sm_50-gencodearch=compute_52,code=sm_52-gencodearch=compute_60,code=sm_60-gencodearch=compute_61,code=sm_61-gencodearch=compute_70,code=sm_70-gencodearch=compute_75,code=sm_75-gencodearch=compute_80,code=sm_80-gencodearch=compute_80,code=compute_80\n", + "-- Will build flashlight libraries.\n", + "-- MKL_THREADING = OMP\n", + "-- Looking for sys/types.h\n", + "-- Looking for sys/types.h - found\n", + "-- Looking for stdint.h\n", + "-- Looking for stdint.h - found\n", + "-- Looking for stddef.h\n", + "-- Looking for stddef.h - found\n", + "-- Check size of void*\n", + "-- Check size of void* - done\n", + "-- Checking for [mkl_intel_lp64 - mkl_gnu_thread - mkl_core - gomp - pthread - m - dl]\n", + "-- Library mkl_intel_lp64: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so\n", + "-- Library mkl_gnu_thread: /opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so\n", + "-- Library mkl_core: /opt/intel/mkl/lib/intel64/libmkl_core.so\n", + "-- Library gomp: -fopenmp\n", + "-- Library pthread: /usr/lib/x86_64-linux-gnu/libpthread.so\n", + "-- Library m: /usr/lib/x86_64-linux-gnu/libm.so\n", + "-- Library dl: /usr/lib/x86_64-linux-gnu/libdl.so\n", + "-- Looking for cblas_sgemm\n", + "-- Looking for cblas_sgemm - found\n", + "-- MKL library found\n", + "-- CBLAS found (include: /opt/intel/mkl/include, library: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so;/opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so;/opt/intel/mkl/lib/intel64/libmkl_core.so;-fopenmp;/usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/libm.so;/usr/lib/x86_64-linux-gnu/libdl.so)\n", + "-- Could NOT find FFTW3 (missing: FFTW3_DIR)\n", + "-- Found PkgConfig: /usr/bin/pkg-config (found version \"0.29.1\") \n", + "-- FindFFTW using pkgconfig: FOUND=1 LIBRARIES=fftw3 LIBRARY_DIRS=/usr/lib/x86_64-linux-gnu LIBDIR=/usr/lib/x86_64-linux-gnu LINK_LIBRARIES=/usr/lib/x86_64-linux-gnu/libfftw3.so\n", + "-- FindFTTW using pkgconfig: INCLUDE_DIRS= INCLUDEDIR=/usr/include\n", + "-- Found FFTW3: /usr/include \n", + "-- FFTW found\n", + "-- Found OpenMP_C: -fopenmp (found version \"4.5\") \n", + "-- Found OpenMP_CXX: -fopenmp (found version \"4.5\") \n", + "-- Found OpenMP: TRUE (found version \"4.5\") \n", + "-- Looking for KenLM\n", + "-- Looking for lzma_auto_decoder in /usr/lib/x86_64-linux-gnu/liblzma.so\n", + "-- Looking for lzma_auto_decoder in /usr/lib/x86_64-linux-gnu/liblzma.so - found\n", + "-- Looking for lzma_easy_encoder in /usr/lib/x86_64-linux-gnu/liblzma.so\n", + "-- Looking for lzma_easy_encoder in /usr/lib/x86_64-linux-gnu/liblzma.so - found\n", + "-- Looking for lzma_lzma_preset in /usr/lib/x86_64-linux-gnu/liblzma.so\n", + "-- Looking for lzma_lzma_preset in /usr/lib/x86_64-linux-gnu/liblzma.so - found\n", + "-- Found LibLZMA: /usr/lib/x86_64-linux-gnu/liblzma.so (found version \"5.2.4\") \n", + "-- Found BZip2: /usr/lib/x86_64-linux-gnu/libbz2.so (found version \"1.0.8\") \n", + "-- Looking for BZ2_bzCompressInit\n", + "-- Looking for BZ2_bzCompressInit - found\n", + "-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version \"1.2.11\") \n", + "-- Using kenlm library found in /usr/local/lib/libkenlm.a\n", + "-- Using kenlm utils library found in /usr/local/lib/libkenlm_util.a\n", + "-- kenlm model.hh found in /usr/local/include/kenlm/lm\n", + "-- Found kenlm: /usr/local/include \n", + "-- Found kenlm (include: /usr/local/include, library: /usr/local/lib/libkenlm.a;/usr/local/lib/libkenlm_util.a;/usr/lib/x86_64-linux-gnu/liblzma.so;/usr/lib/x86_64-linux-gnu/libbz2.so;/usr/lib/x86_64-linux-gnu/libz.so)\n", + "-- Found PythonInterp: /usr/bin/python3 (found version \"3.10.11\") \n", + "-- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython3.10.so\n", + "-- Performing Test HAS_FLTO\n", + "-- Performing Test HAS_FLTO - Success\n", + "-- LTO enabled\n", + "-- Configuring done\n", + "\u001b[33mCMake Warning (dev) in CMakeLists.txt:\n", + " Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,\n", + " empty CUDA_ARCHITECTURES not allowed. Run \"cmake --help-policy CMP0104\"\n", + " for policy details. Use the cmake_policy command to set the policy and\n", + " suppress this warning.\n", + "\n", + " CUDA_ARCHITECTURES is empty for target \"fl-libraries\".\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\u001b[0m\n", + "-- Generating done\n", + "-- Build files have been written to: /content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310\n", + "[ 1%] \u001b[34m\u001b[1mCreating directories for 'pybind11'\u001b[0m\n", + "[ 3%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/set/Hungarian.cpp.o\u001b[0m\n", + "[ 5%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cpu/CriterionUtils.cpp.o\u001b[0m\n", + "[ 7%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cpu/ForceAlignmentCriterion.cpp.o\u001b[0m\n", + "[ 9%] \u001b[34m\u001b[1mPerforming download step (git clone) for 'pybind11'\u001b[0m\n", + "Cloning into 'pybind11'...\n", + "[ 11%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cpu/ConnectionistTemporalClassificationCriterion.cpp.o\u001b[0m\n", + "[ 13%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cpu/FullConnectionCriterion.cpp.o\u001b[0m\n", + "[ 15%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cpu/ViterbiPath.cpp.o\u001b[0m\n", + "[ 16%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/Ceplifter.cpp.o\u001b[0m\n", + "[ 18%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/Dct.cpp.o\u001b[0m\n", + "[ 20%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/Derivatives.cpp.o\u001b[0m\n", + "HEAD is now at 9a19306f bump version to 2.2.4\n", + "Submodule 'tools/clang' (https://github.com/wjakob/clang-cindex-python3) registered for path 'tools/clang'\n", + "Cloning into '/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/tools/clang'...\n", + "[ 22%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/Dither.cpp.o\u001b[0m\n", + "[ 24%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/Mfcc.cpp.o\u001b[0m\n", + "[ 26%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/Mfsc.cpp.o\u001b[0m\n", + "Submodule path 'tools/clang': checked out '6a00cbc4a9b8e68b71caf7f774b3f9c753ae84d5'\n", + "[ 28%] \u001b[34m\u001b[1mPerforming update step for 'pybind11'\u001b[0m\n", + "[ 30%] \u001b[34m\u001b[1mNo patch step for 'pybind11'\u001b[0m\n", + "[ 32%] \u001b[34m\u001b[1mNo configure step for 'pybind11'\u001b[0m\n", + "[ 33%] \u001b[34m\u001b[1mNo build step for 'pybind11'\u001b[0m\n", + "[ 35%] \u001b[34m\u001b[1mNo install step for 'pybind11'\u001b[0m\n", + "[ 37%] \u001b[34m\u001b[1mCompleted 'pybind11'\u001b[0m\n", + "[ 37%] Built target pybind11\n", + "[ 39%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/PowerSpectrum.cpp.o\u001b[0m\n", + "[ 41%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/PreEmphasis.cpp.o\u001b[0m\n", + "[ 43%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/SpeechUtils.cpp.o\u001b[0m\n", + "[ 45%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/TriFilterbank.cpp.o\u001b[0m\n", + "[ 47%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/audio/feature/Windowing.cpp.o\u001b[0m\n", + "[ 49%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/common/String.cpp.o\u001b[0m\n", + "[ 50%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/common/System.cpp.o\u001b[0m\n", + "[ 52%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/lm/ConvLM.cpp.o\u001b[0m\n", + "[ 54%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/lm/ZeroLM.cpp.o\u001b[0m\n", + "[ 56%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/lm/KenLM.cpp.o\u001b[0m\n", + "[ 58%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/LexiconDecoder.cpp.o\u001b[0m\n", + "[ 60%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/LexiconFreeDecoder.cpp.o\u001b[0m\n", + "[ 62%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/LexiconSeq2SeqDecoder.cpp.o\u001b[0m\n", + "[ 64%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/LexiconFreeSeq2SeqDecoder.cpp.o\u001b[0m\n", + "[ 66%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/Trie.cpp.o\u001b[0m\n", + "[ 67%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/decoder/Utils.cpp.o\u001b[0m\n", + "[ 69%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/dictionary/Dictionary.cpp.o\u001b[0m\n", + "[ 71%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/dictionary/Utils.cpp.o\u001b[0m\n", + "[ 73%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/tokenizer/PartialFileReader.cpp.o\u001b[0m\n", + "[ 75%] \u001b[32mBuilding CXX object CMakeFiles/fl-libraries.dir/flashlight/lib/text/tokenizer/Tokenizer.cpp.o\u001b[0m\n", + "[ 77%] \u001b[32mBuilding CUDA object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cuda/CriterionUtils.cu.o\u001b[0m\n", + "[ 79%] \u001b[32mBuilding CUDA object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cuda/ForceAlignmentCriterion.cu.o\u001b[0m\n", + "[ 81%] \u001b[32mBuilding CUDA object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cuda/FullConnectionCriterion.cu.o\u001b[0m\n", + "[ 83%] \u001b[32mBuilding CUDA object CMakeFiles/fl-libraries.dir/flashlight/lib/sequence/criterion/cuda/ViterbiPath.cu.o\u001b[0m\n", + "[ 84%] \u001b[32m\u001b[1mLinking CXX shared library /content/fairseq/flashlight/bindings/python/build/lib.linux-x86_64-cpython-310/libfl-libraries.so\u001b[0m\n", + "[ 84%] Built target fl-libraries\n", + "[ 86%] \u001b[32mBuilding CXX object CMakeFiles/flashlight_lib_audio_feature.dir/bindings/python/flashlight/lib/audio/_feature.cpp.o\u001b[0m\n", + "[ 88%] \u001b[32mBuilding CXX object CMakeFiles/flashlight_lib_sequence_criterion.dir/bindings/python/flashlight/lib/sequence/_criterion.cpp.o\u001b[0m\n", + "[ 90%] \u001b[32mBuilding CXX object CMakeFiles/flashlight_lib_text_dictionary.dir/bindings/python/flashlight/lib/text/_dictionary.cpp.o\u001b[0m\n", + "[ 92%] \u001b[32mBuilding CXX object CMakeFiles/flashlight_lib_text_decoder.dir/bindings/python/flashlight/lib/text/_decoder.cpp.o\u001b[0m\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_decoder.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:\u001b[m\u001b[K In function ‘\u001b[01m\u001b[Kpybind11::detail::internals& pybind11::detail::get_internals()\u001b[m\u001b[K’:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_decoder.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_decoder.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_decoder.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/sequence/_criterion.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:\u001b[m\u001b[K In function ‘\u001b[01m\u001b[Kpybind11::detail::internals& pybind11::detail::get_internals()\u001b[m\u001b[K’:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/sequence/_criterion.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/sequence/_criterion.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/sequence/_criterion.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_dictionary.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:\u001b[m\u001b[K In function ‘\u001b[01m\u001b[Kpybind11::detail::internals& pybind11::detail::get_internals()\u001b[m\u001b[K’:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_dictionary.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_dictionary.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/text/_dictionary.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/audio/_feature.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:\u001b[m\u001b[K In function ‘\u001b[01m\u001b[Kpybind11::detail::internals& pybind11::detail::get_internals()\u001b[m\u001b[K’:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/audio/_feature.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:16\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/audio/_feature.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/internals.h:194:28:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[Kvoid PyEval_InitThreads()\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + " 194 | PyEval_InitThreads(\u001b[01;35m\u001b[K)\u001b[m\u001b[K;\n", + " | \u001b[01;35m\u001b[K^\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/detail/common.h:112\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pytypes.h:12\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/cast.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/attr.h:13\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310/pybind11/src/pybind11/include/pybind11/pybind11.h:43\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[K/content/fairseq/flashlight/bindings/python/flashlight/lib/audio/_feature.cpp:8\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "[ 94%] \u001b[32m\u001b[1mLinking CXX shared module /content/fairseq/flashlight/bindings/python/build/lib.linux-x86_64-cpython-310/flashlight/lib/text/flashlight_lib_text_dictionary.cpython-310-x86_64-linux-gnu.so\u001b[0m\n", + "[ 96%] \u001b[32m\u001b[1mLinking CXX shared module /content/fairseq/flashlight/bindings/python/build/lib.linux-x86_64-cpython-310/flashlight/lib/sequence/flashlight_lib_sequence_criterion.cpython-310-x86_64-linux-gnu.so\u001b[0m\n", + "[ 98%] \u001b[32m\u001b[1mLinking CXX shared module /content/fairseq/flashlight/bindings/python/build/lib.linux-x86_64-cpython-310/flashlight/lib/audio/flashlight_lib_audio_feature.cpython-310-x86_64-linux-gnu.so\u001b[0m\n", + "[ 98%] Built target flashlight_lib_text_dictionary\n", + "[100%] \u001b[32m\u001b[1mLinking CXX shared module /content/fairseq/flashlight/bindings/python/build/lib.linux-x86_64-cpython-310/flashlight/lib/text/flashlight_lib_text_decoder.cpython-310-x86_64-linux-gnu.so\u001b[0m\n", + "[100%] Built target flashlight_lib_sequence_criterion\n", + "[100%] Built target flashlight_lib_audio_feature\n", + "[100%] Built target flashlight_lib_text_decoder\n", + "-- -rdynamic supported.\n", + "-- CUDA found (library: /usr/local/cuda/lib64/libcudart_static.a;Threads::Threads;dl;/usr/lib/x86_64-linux-gnu/librt.so include: /usr/local/cuda/include)\n", + "-- CUDA architecture flags: -gencodearch=compute_35,code=sm_35-gencodearch=compute_50,code=sm_50-gencodearch=compute_52,code=sm_52-gencodearch=compute_60,code=sm_60-gencodearch=compute_61,code=sm_61-gencodearch=compute_70,code=sm_70-gencodearch=compute_75,code=sm_75-gencodearch=compute_80,code=sm_80-gencodearch=compute_80,code=compute_80\n", + "-- Will build flashlight libraries.\n", + "-- MKL_THREADING = OMP\n", + "-- Checking for [mkl_intel_lp64 - mkl_gnu_thread - mkl_core - gomp - pthread - m - dl]\n", + "-- Library mkl_intel_lp64: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so\n", + "-- Library mkl_gnu_thread: /opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so\n", + "-- Library mkl_core: /opt/intel/mkl/lib/intel64/libmkl_core.so\n", + "-- Library gomp: -fopenmp\n", + "-- Library pthread: /usr/lib/x86_64-linux-gnu/libpthread.so\n", + "-- Library m: /usr/lib/x86_64-linux-gnu/libm.so\n", + "-- Library dl: /usr/lib/x86_64-linux-gnu/libdl.so\n", + "-- MKL library found\n", + "-- CBLAS found (include: /opt/intel/mkl/include, library: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so;/opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so;/opt/intel/mkl/lib/intel64/libmkl_core.so;-fopenmp;/usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/libm.so;/usr/lib/x86_64-linux-gnu/libdl.so)\n", + "-- Could NOT find FFTW3 (missing: FFTW3_DIR)\n", + "-- FindFFTW using pkgconfig: FOUND=1 LIBRARIES=fftw3 LIBRARY_DIRS=/usr/lib/x86_64-linux-gnu LIBDIR=/usr/lib/x86_64-linux-gnu LINK_LIBRARIES=/usr/lib/x86_64-linux-gnu/libfftw3.so\n", + "-- FindFTTW using pkgconfig: INCLUDE_DIRS= INCLUDEDIR=/usr/include\n", + "-- FFTW found\n", + "-- Looking for KenLM\n", + "-- Using kenlm library found in /usr/local/lib/libkenlm.a\n", + "-- Using kenlm utils library found in /usr/local/lib/libkenlm_util.a\n", + "-- kenlm model.hh found in /usr/local/include/kenlm/lm\n", + "-- Found kenlm (include: /usr/local/include, library: /usr/local/lib/libkenlm.a;/usr/local/lib/libkenlm_util.a;/usr/lib/x86_64-linux-gnu/liblzma.so;/usr/lib/x86_64-linux-gnu/libbz2.so;/usr/lib/x86_64-linux-gnu/libz.so)\n", + "-- Configuring done\n", + "\u001b[33mCMake Warning (dev) in CMakeLists.txt:\n", + " Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,\n", + " empty CUDA_ARCHITECTURES not allowed. Run \"cmake --help-policy CMP0104\"\n", + " for policy details. Use the cmake_policy command to set the policy and\n", + " suppress this warning.\n", + "\n", + " CUDA_ARCHITECTURES is empty for target \"fl-libraries\".\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\u001b[0m\n", + "-- Generating done\n", + "-- Build files have been written to: /content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310\n", + "[ 1%] \u001b[34m\u001b[1mPerforming update step for 'pybind11'\u001b[0m\n", + "[ 3%] \u001b[34m\u001b[1mNo patch step for 'pybind11'\u001b[0m\n", + "[ 5%] \u001b[34m\u001b[1mNo configure step for 'pybind11'\u001b[0m\n", + "[ 7%] \u001b[34m\u001b[1mNo build step for 'pybind11'\u001b[0m\n", + "[ 9%] \u001b[34m\u001b[1mNo install step for 'pybind11'\u001b[0m\n", + "[ 11%] \u001b[34m\u001b[1mCompleted 'pybind11'\u001b[0m\n", + "[ 15%] Built target pybind11\n", + "[ 84%] Built target fl-libraries\n", + "[ 88%] Built target flashlight_lib_sequence_criterion\n", + "[ 92%] Built target flashlight_lib_text_decoder\n", + "[ 96%] Built target flashlight_lib_audio_feature\n", + "[100%] Built target flashlight_lib_text_dictionary\n", + "-- -rdynamic supported.\n", + "-- CUDA found (library: /usr/local/cuda/lib64/libcudart_static.a;Threads::Threads;dl;/usr/lib/x86_64-linux-gnu/librt.so include: /usr/local/cuda/include)\n", + "-- CUDA architecture flags: -gencodearch=compute_35,code=sm_35-gencodearch=compute_50,code=sm_50-gencodearch=compute_52,code=sm_52-gencodearch=compute_60,code=sm_60-gencodearch=compute_61,code=sm_61-gencodearch=compute_70,code=sm_70-gencodearch=compute_75,code=sm_75-gencodearch=compute_80,code=sm_80-gencodearch=compute_80,code=compute_80\n", + "-- Will build flashlight libraries.\n", + "-- MKL_THREADING = OMP\n", + "-- Checking for [mkl_intel_lp64 - mkl_gnu_thread - mkl_core - gomp - pthread - m - dl]\n", + "-- Library mkl_intel_lp64: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so\n", + "-- Library mkl_gnu_thread: /opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so\n", + "-- Library mkl_core: /opt/intel/mkl/lib/intel64/libmkl_core.so\n", + "-- Library gomp: -fopenmp\n", + "-- Library pthread: /usr/lib/x86_64-linux-gnu/libpthread.so\n", + "-- Library m: /usr/lib/x86_64-linux-gnu/libm.so\n", + "-- Library dl: /usr/lib/x86_64-linux-gnu/libdl.so\n", + "-- MKL library found\n", + "-- CBLAS found (include: /opt/intel/mkl/include, library: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so;/opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so;/opt/intel/mkl/lib/intel64/libmkl_core.so;-fopenmp;/usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/libm.so;/usr/lib/x86_64-linux-gnu/libdl.so)\n", + "-- Could NOT find FFTW3 (missing: FFTW3_DIR)\n", + "-- FindFFTW using pkgconfig: FOUND=1 LIBRARIES=fftw3 LIBRARY_DIRS=/usr/lib/x86_64-linux-gnu LIBDIR=/usr/lib/x86_64-linux-gnu LINK_LIBRARIES=/usr/lib/x86_64-linux-gnu/libfftw3.so\n", + "-- FindFTTW using pkgconfig: INCLUDE_DIRS= INCLUDEDIR=/usr/include\n", + "-- FFTW found\n", + "-- Looking for KenLM\n", + "-- Using kenlm library found in /usr/local/lib/libkenlm.a\n", + "-- Using kenlm utils library found in /usr/local/lib/libkenlm_util.a\n", + "-- kenlm model.hh found in /usr/local/include/kenlm/lm\n", + "-- Found kenlm (include: /usr/local/include, library: /usr/local/lib/libkenlm.a;/usr/local/lib/libkenlm_util.a;/usr/lib/x86_64-linux-gnu/liblzma.so;/usr/lib/x86_64-linux-gnu/libbz2.so;/usr/lib/x86_64-linux-gnu/libz.so)\n", + "-- Configuring done\n", + "\u001b[33mCMake Warning (dev) in CMakeLists.txt:\n", + " Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,\n", + " empty CUDA_ARCHITECTURES not allowed. Run \"cmake --help-policy CMP0104\"\n", + " for policy details. Use the cmake_policy command to set the policy and\n", + " suppress this warning.\n", + "\n", + " CUDA_ARCHITECTURES is empty for target \"fl-libraries\".\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\u001b[0m\n", + "-- Generating done\n", + "-- Build files have been written to: /content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310\n", + "[ 1%] \u001b[34m\u001b[1mPerforming update step for 'pybind11'\u001b[0m\n", + "[ 3%] \u001b[34m\u001b[1mNo patch step for 'pybind11'\u001b[0m\n", + "[ 5%] \u001b[34m\u001b[1mNo configure step for 'pybind11'\u001b[0m\n", + "[ 7%] \u001b[34m\u001b[1mNo build step for 'pybind11'\u001b[0m\n", + "[ 9%] \u001b[34m\u001b[1mNo install step for 'pybind11'\u001b[0m\n", + "[ 11%] \u001b[34m\u001b[1mCompleted 'pybind11'\u001b[0m\n", + "[ 15%] Built target pybind11\n", + "[ 84%] Built target fl-libraries\n", + "[ 88%] Built target flashlight_lib_sequence_criterion\n", + "[ 92%] Built target flashlight_lib_audio_feature\n", + "[ 96%] Built target flashlight_lib_text_decoder\n", + "[100%] Built target flashlight_lib_text_dictionary\n", + "-- -rdynamic supported.\n", + "-- CUDA found (library: /usr/local/cuda/lib64/libcudart_static.a;Threads::Threads;dl;/usr/lib/x86_64-linux-gnu/librt.so include: /usr/local/cuda/include)\n", + "-- CUDA architecture flags: -gencodearch=compute_35,code=sm_35-gencodearch=compute_50,code=sm_50-gencodearch=compute_52,code=sm_52-gencodearch=compute_60,code=sm_60-gencodearch=compute_61,code=sm_61-gencodearch=compute_70,code=sm_70-gencodearch=compute_75,code=sm_75-gencodearch=compute_80,code=sm_80-gencodearch=compute_80,code=compute_80\n", + "-- Will build flashlight libraries.\n", + "-- MKL_THREADING = OMP\n", + "-- Checking for [mkl_intel_lp64 - mkl_gnu_thread - mkl_core - gomp - pthread - m - dl]\n", + "-- Library mkl_intel_lp64: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so\n", + "-- Library mkl_gnu_thread: /opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so\n", + "-- Library mkl_core: /opt/intel/mkl/lib/intel64/libmkl_core.so\n", + "-- Library gomp: -fopenmp\n", + "-- Library pthread: /usr/lib/x86_64-linux-gnu/libpthread.so\n", + "-- Library m: /usr/lib/x86_64-linux-gnu/libm.so\n", + "-- Library dl: /usr/lib/x86_64-linux-gnu/libdl.so\n", + "-- MKL library found\n", + "-- CBLAS found (include: /opt/intel/mkl/include, library: /opt/intel/mkl/lib/intel64/libmkl_intel_lp64.so;/opt/intel/mkl/lib/intel64/libmkl_gnu_thread.so;/opt/intel/mkl/lib/intel64/libmkl_core.so;-fopenmp;/usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/libm.so;/usr/lib/x86_64-linux-gnu/libdl.so)\n", + "-- Could NOT find FFTW3 (missing: FFTW3_DIR)\n", + "-- FindFFTW using pkgconfig: FOUND=1 LIBRARIES=fftw3 LIBRARY_DIRS=/usr/lib/x86_64-linux-gnu LIBDIR=/usr/lib/x86_64-linux-gnu LINK_LIBRARIES=/usr/lib/x86_64-linux-gnu/libfftw3.so\n", + "-- FindFTTW using pkgconfig: INCLUDE_DIRS= INCLUDEDIR=/usr/include\n", + "-- FFTW found\n", + "-- Looking for KenLM\n", + "-- Using kenlm library found in /usr/local/lib/libkenlm.a\n", + "-- Using kenlm utils library found in /usr/local/lib/libkenlm_util.a\n", + "-- kenlm model.hh found in /usr/local/include/kenlm/lm\n", + "-- Found kenlm (include: /usr/local/include, library: /usr/local/lib/libkenlm.a;/usr/local/lib/libkenlm_util.a;/usr/lib/x86_64-linux-gnu/liblzma.so;/usr/lib/x86_64-linux-gnu/libbz2.so;/usr/lib/x86_64-linux-gnu/libz.so)\n", + "-- Configuring done\n", + "\u001b[33mCMake Warning (dev) in CMakeLists.txt:\n", + " Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,\n", + " empty CUDA_ARCHITECTURES not allowed. Run \"cmake --help-policy CMP0104\"\n", + " for policy details. Use the cmake_policy command to set the policy and\n", + " suppress this warning.\n", + "\n", + " CUDA_ARCHITECTURES is empty for target \"fl-libraries\".\n", + "This warning is for project developers. Use -Wno-dev to suppress it.\n", + "\u001b[0m\n", + "-- Generating done\n", + "-- Build files have been written to: /content/fairseq/flashlight/bindings/python/build/temp.linux-x86_64-cpython-310\n", + "[ 1%] \u001b[34m\u001b[1mPerforming update step for 'pybind11'\u001b[0m\n", + "[ 3%] \u001b[34m\u001b[1mNo patch step for 'pybind11'\u001b[0m\n", + "[ 5%] \u001b[34m\u001b[1mNo configure step for 'pybind11'\u001b[0m\n", + "[ 7%] \u001b[34m\u001b[1mNo build step for 'pybind11'\u001b[0m\n", + "[ 9%] \u001b[34m\u001b[1mNo install step for 'pybind11'\u001b[0m\n", + "[ 11%] \u001b[34m\u001b[1mCompleted 'pybind11'\u001b[0m\n", + "[ 81%] Built target fl-libraries\n", + "[ 84%] Built target pybind11\n", + "[ 88%] Built target flashlight_lib_sequence_criterion\n", + "[ 92%] Built target flashlight_lib_audio_feature\n", + "[ 96%] Built target flashlight_lib_text_decoder\n", + "[100%] Built target flashlight_lib_text_dictionary\n", + "creating build/bdist.linux-x86_64\n", + "creating build/bdist.linux-x86_64/egg\n", + "copying build/lib.linux-x86_64-cpython-310/libfl-libraries.so -> build/bdist.linux-x86_64/egg\n", + "copying build/lib.linux-x86_64-cpython-310/libfl-libraries.so.0 -> build/bdist.linux-x86_64/egg\n", + "copying build/lib.linux-x86_64-cpython-310/libfl-libraries.so.0.3 -> build/bdist.linux-x86_64/egg\n", + "creating build/bdist.linux-x86_64/egg/flashlight\n", + "creating build/bdist.linux-x86_64/egg/flashlight/lib\n", + "creating build/bdist.linux-x86_64/egg/flashlight/lib/sequence\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/sequence/flashlight_lib_sequence_criterion.cpython-310-x86_64-linux-gnu.so -> build/bdist.linux-x86_64/egg/flashlight/lib/sequence\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/sequence/criterion_torch.py -> build/bdist.linux-x86_64/egg/flashlight/lib/sequence\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/sequence/criterion.py -> build/bdist.linux-x86_64/egg/flashlight/lib/sequence\n", + "creating build/bdist.linux-x86_64/egg/flashlight/lib/audio\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/audio/feature.py -> build/bdist.linux-x86_64/egg/flashlight/lib/audio\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/audio/flashlight_lib_audio_feature.cpython-310-x86_64-linux-gnu.so -> build/bdist.linux-x86_64/egg/flashlight/lib/audio\n", + "creating build/bdist.linux-x86_64/egg/flashlight/lib/text\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/text/flashlight_lib_text_dictionary.cpython-310-x86_64-linux-gnu.so -> build/bdist.linux-x86_64/egg/flashlight/lib/text\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/text/flashlight_lib_text_decoder.cpython-310-x86_64-linux-gnu.so -> build/bdist.linux-x86_64/egg/flashlight/lib/text\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/text/dictionary.py -> build/bdist.linux-x86_64/egg/flashlight/lib/text\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/text/decoder.py -> build/bdist.linux-x86_64/egg/flashlight/lib/text\n", + "copying build/lib.linux-x86_64-cpython-310/flashlight/lib/__init__.py -> build/bdist.linux-x86_64/egg/flashlight/lib\n", + "byte-compiling build/bdist.linux-x86_64/egg/flashlight/lib/sequence/criterion_torch.py to criterion_torch.cpython-310.pyc\n", + "byte-compiling build/bdist.linux-x86_64/egg/flashlight/lib/sequence/criterion.py to criterion.cpython-310.pyc\n", + "byte-compiling build/bdist.linux-x86_64/egg/flashlight/lib/audio/feature.py to feature.cpython-310.pyc\n", + "byte-compiling build/bdist.linux-x86_64/egg/flashlight/lib/text/dictionary.py to dictionary.cpython-310.pyc\n", + "byte-compiling build/bdist.linux-x86_64/egg/flashlight/lib/text/decoder.py to decoder.cpython-310.pyc\n", + "byte-compiling build/bdist.linux-x86_64/egg/flashlight/lib/__init__.py to __init__.cpython-310.pyc\n", + "creating build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying flashlight.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying flashlight.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying flashlight.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying flashlight.egg-info/not-zip-safe -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "copying flashlight.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO\n", + "writing build/bdist.linux-x86_64/egg/EGG-INFO/native_libs.txt\n", + "creating dist\n", + "creating 'dist/flashlight-1.0.0-py3.10-linux-x86_64.egg' and adding 'build/bdist.linux-x86_64/egg' to it\n", + "removing 'build/bdist.linux-x86_64/egg' (and everything under it)\n", + "Processing flashlight-1.0.0-py3.10-linux-x86_64.egg\n", + "creating /usr/local/lib/python3.10/dist-packages/flashlight-1.0.0-py3.10-linux-x86_64.egg\n", + "Extracting flashlight-1.0.0-py3.10-linux-x86_64.egg to /usr/local/lib/python3.10/dist-packages\n", + "Adding flashlight 1.0.0 to easy-install.pth file\n", + "\n", + "Installed /usr/local/lib/python3.10/dist-packages/flashlight-1.0.0-py3.10-linux-x86_64.egg\n", + "Processing dependencies for flashlight==1.0.0\n", + "Finished processing dependencies for flashlight==1.0.0\n", + "/content/fairseq\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Next, we download an audio file from [People's speech](https://huggingface.co/datasets/MLCommons/peoples_speech) data. We will the audio sample from their 'dirty' subset which will be more challenging for the ASR model. " + ], + "metadata": { + "id": "1ejR32MNbyf9" + } + }, + { + "cell_type": "code", + "source": [ + "!wget -O ./audio_samples/tmp.wav 'https://datasets-server.huggingface.co/assets/MLCommons/peoples_speech/--/dirty/train/0/audio/audio.wav'\n", + "!ffmpeg -y -i ./audio_samples/tmp.wav -ar 16000 ./audio_samples/audio_noisy.wav\n", + "\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "LCB_t3-fbcM6", + "outputId": "3a61229b-e4c9-4055-ac1c-c0f8159a3f00" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--2023-05-26 00:26:41-- https://datasets-server.huggingface.co/assets/MLCommons/peoples_speech/--/dirty/train/0/audio/audio.wav\n", + "Resolving datasets-server.huggingface.co (datasets-server.huggingface.co)... 34.200.186.24, 3.216.183.114, 44.197.252.161, ...\n", + "Connecting to datasets-server.huggingface.co (datasets-server.huggingface.co)|34.200.186.24|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 386924 (378K) [application/octet-stream]\n", + "Saving to: ‘./audio_samples/tmp.wav’\n", + "\n", + "./audio_samples/tmp 100%[===================>] 377.86K 1.07MB/s in 0.3s \n", + "\n", + "2023-05-26 00:26:42 (1.07 MB/s) - ‘./audio_samples/tmp.wav’ saved [386924/386924]\n", + "\n", + "ffmpeg version 4.2.7-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developers\n", + " built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)\n", + " configuration: --prefix=/usr --extra-version=0ubuntu0.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared\n", + " libavutil 56. 31.100 / 56. 31.100\n", + " libavcodec 58. 54.100 / 58. 54.100\n", + " libavformat 58. 29.100 / 58. 29.100\n", + " libavdevice 58. 8.100 / 58. 8.100\n", + " libavfilter 7. 57.100 / 7. 57.100\n", + " libavresample 4. 0. 0 / 4. 0. 0\n", + " libswscale 5. 5.100 / 5. 5.100\n", + " libswresample 3. 5.100 / 3. 5.100\n", + " libpostproc 55. 5.100 / 55. 5.100\n", + "\u001b[0;33mGuessed Channel Layout for Input Stream #0.0 : mono\n", + "\u001b[0mInput #0, wav, from './audio_samples/tmp.wav':\n", + " Duration: 00:00:12.09, bitrate: 256 kb/s\n", + " Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s\n", + "Stream mapping:\n", + " Stream #0:0 -> #0:0 (pcm_s16le (native) -> pcm_s16le (native))\n", + "Press [q] to stop, [?] for help\n", + "Output #0, wav, to './audio_samples/audio_noisy.wav':\n", + " Metadata:\n", + " ISFT : Lavf58.29.100\n", + " Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, mono, s16, 256 kb/s\n", + " Metadata:\n", + " encoder : Lavc58.54.100 pcm_s16le\n", + "size= 378kB time=00:00:12.09 bitrate= 256.1kbits/s speed= 846x \n", + "video:0kB audio:378kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.020161%\n", + "Trancript: limiting emotions that we experience pain in our childhood which stop us from living our life just open freedom i mean trust\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Let's listen to the audio file \n" + ], + "metadata": { + "id": "Iq_IWIpqc7hK" + } + }, + { + "cell_type": "code", + "source": [ + "import IPython\n", + "IPython.display.display(IPython.display.Audio(\"./audio_samples/audio_noisy.wav\"))\n", + "print(\"Trancript: limiting emotions that we experience mainly in our childhood which stop us from living our life just open freedom i mean trust and\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 93 + }, + "id": "IrqHRS0Sc_Oo", + "outputId": "a1ac89d9-30c0-4889-c3bc-1fa336cf0c79" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "<IPython.lib.display.Audio object>" + ], + "text/html": [ + "\n", + " <audio controls=\"controls\" >\n", + " <source src=\"data:audio/x-wav;base64,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GwAmAC8AGgAYADUAMAAKAAsAKAAoABoAGwAdACIAKgAgABQAFwAOAPX/9v8QABcACgAJAAkA+//1/wYAGwAbABkAIgAbAAAACQA4AEEAGQAMAB0AFQAMACkARgA6ABkABQARACYADQDL/7L/w/+v/4z/l/+b/2j/U/+L/6v/gP9f/2//dv9s/4X/sf+4/7H/1v8EAP//7P/2//v/7/8EACkAGADu//v/KAA0ACwAKwAeAP7/6v8CAEAAbQBTABoADQAcABYAFQAyADQAEAAHAB0AFAD3//j/BQAJAB4APwBBACEAAADu/+r/+P8KABAAFQAlADAAKAAbAB0AIAAQAAIAGABAAFUAWgBTADgAHgASAPP/zP/U/+7/1f+7/9j/3/+r/5b/sf+t/53/uP/I/6b/lv+x/8z/6P8LAAMA3//m/wYABwABABcAHAD5/+f/BwAmABMA7//9/ywANQAPAPf/BQAXABkAGgAkACQAEgAGABcAMAAuABkACQACAAAABQATACIAKgAjABgAEQD9/+H/4//5//f/8/8VADIAHgALABkAHAAEAPb//v8FAAAA+/8MACcAIgD///L/8//M/5v/ov/C/8D/r/+v/6//o/+Z/5r/o/+v/7D/pP+h/67/wv/W/+v//P8GAAoACQAEAAEAAAD6//T//f8QABMAAgD9/xAAHAAaACEAJwATAPz/BwAXAAsABgAhAC8AFwARADEAPgAmAB0ALQAmAAkADAAxAEIAKwATABsANAAuAA0ACQAmACkAFQAiAEAANQATABQAKgAuACcAJgAmABsACwADAAMA9//e/9D/x/+t/5j/o/+0/7D/p/+k/5//nP+e/6n/x//o/+b/2P/r/wYACQATAC4AMgAnACoAKwAfACQALgAnADIATAA2AAQACQAyADAAGAAhADAAJAAWABYAFgAPAAUA+P8BACMALAAKAPL/CgApACUAEAAOABkAFAD///3/FgAmABYABQAZAD0APQAgABMAHAAUAP3//f8XACYAHQAYACQAKQAIANz/0P/Q/6//i/+a/7P/qv+l/7T/qv+O/5T/p/+n/6z/vv+0/6X/wv/t//r//f8RACIAHgARABEAHQAgABQADgAQAAgABQAQAAwA//8NACMAIAAbAB4ACgDz/wAAEQASACIANAAkABEAGwAdABEAFwAqADEANQAxAB8AFgAdABkADQASACAAIwAeACAALQAyABoABgAYAC4AJwAsAE8AUwA0AC0AOAArAAkA5P/H/8D/w/+2/7L/y//S/7T/n/+d/5H/i/+c/6r/p/+o/7L/wP/f/wkAGgALAPz/AQAOAAwABAAJAAwAAgACABkAKgAnACYAKwAmABgADAAKAA8ADQABAPr/AAAOABsAHAATABIAEgABAPn/FAAoABQACQAbAB4ACwADAPn/5v/q//n/+f8AABsAIwAYACAAMgAtAB8AJwA6AEIAPQAwACUAFgD+/+H/xf+s/57/oP+o/6z/p/+U/3r/cf96/3z/eP+H/6j/vP+4/7b/yv/i//D//P8FAPr/8f8DABoAIAAmACkAFgAJAB4AMQAnAB8AJwAvACwAHQAEAP3/CAD+/+f/8P8GAAEA/P8PABkACAD3/wAAHAAvACoAHwAhACEAEgAMABMAGAAeACYALQA8AE0ARQAyAD4AUgBGADIAMQAyADEANQA0AC8AMAAjAPb/0P/F/7L/lf+R/57/nP+M/4L/hv+R/5j/mf+d/6f/sf++/9D/3//0/w0AFAAMABEAFQAOABkAOQA/ACoALABBAEEAOAA7ADsALwAxAEAARQA7AC8AJQAaAAwA/f/2//v/AQAFAAwADgAAAO//7v/7/wAA+//5/wEACQADAPf/+P8FAAwABgAGABIAGgARAAYABwAIAAEA/P///woAGQAgABcADAAJAPP/yf+0/7r/sf+X/5T/o/+l/6L/pv+m/53/l/+U/5j/q/+7/8D/0v/6/xQAEQAHAAMA/f/2//n/BwAUABEA///3/wcAFwAWABUAHgAdAA8ABQAMABoAHwAXAA8ADwAUAB4AMQA6ACgACgD3//P//P8NABYADgAEAAUACgANAA4AEwAYAB0AIwArADcAPwA+ADsAOgAyAB0AEQAVABAA+v/u//n//v/u/9b/vv+j/4z/j/+m/7f/t/+w/6n/ov+a/5L/jv+P/5L/l/+f/7D/y//n//r/BQAHAAAA+f/5//7/AQABAAIACAAUABoAEAADAP7/+v/3//3/CAAOABQAHwAnACUAHgAYABYAFAAQAA4AEAANAAMAAgANABEADwAUAB4AGgAIAPv//f8HAA4AEAAWACMAKwAvADcAPAAvABUABQACAP//9//z//f/+v/y/9z/wv+r/5X/gf94/33/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u//C/9P/7P8CAAsABwABAAAAAgADAP//+f/6/wIABwADAP7/AQAPABoAGAAPAAwADAAGAPn/8f/1/wMAEwAjADEAMAAcAAoAEAAnADAAIAAKAAwAKQBDAEIAMQAlACQAJAAdABIAEAAdACoAJwAfAB0AHgAcABcAEwAZACIAHgATABMAFgAJAOn/x/+6/8j/1P/D/6P/kv+S/5b/kP+G/47/rv/M/9T/0P/U/+L/9P8DABIAKAA7AEAARQBOAE0ARAA8ADIAIgAYABkAGwAeABwADgAEAAkACwD6/+X/3f/m//L/5//L/8X/3v/y/+n/0f/F/9z/DgAvADIAMQBAAFcAagBsAFsAVQBgAGEATgA5ACoAHgAPAPX/5//4/xIAGwASAAMA+P/6//z/6//U/8H/ov+A/3D/cv+E/5n/mf+H/4L/jf+Q/4X/ff+G/6P/wf/R/+L/+/8QACcARQBTAEwARwBFADsANAA2ADwATABfAGAAVwBQAEEAMAAtACYADQD+/wQACAAIAAkAAgAFABcAGQAIAAYADwAIAP3//P8EACAAOQAxACIAKAAnABYAEgAZACAALQAxACQAIAAjAAwA8P/x//3/BQAOABAADAAPAA0AAQD1/+n/1v/C/67/mv+V/6X/r/+l/5X/if+I/5H/m/+h/6n/u//P/9f/2f/k/+3/7P/w/wEAHQA1ADwAMQAkABYA///z/wEAFAAYABgAGgAgACYAGwAIAP3/8v/3/yAARAA9ACYAGAADAPj/AwAEAPj/+/8BAAEAFAA0AEcASwBEADYALgAoABMABQAaADMALwAiABgAEAAUACgAMwAtACoALQAkABUADQABAOj/y/+s/5X/nv+t/6L/lf+X/43/g/+O/5b/if+C/4j/iP+L/5n/tP/j/w4AIgAzADoAJQAYAC8ARQBEADsAKwAYABcAHAAcACYAKwAVAAYACQAAAPj/DgAoACUAEgAPABkAGwARAAQA/v/7//v/CgAkADUANQAyADEAKQAdACsAUwBnAFwAWABhAGIAWQBPAEcASQBTAFIASgBRAFkATgA0ABsABADu/9T/s/+c/5z/nv+R/4z/kf+F/2//dv+P/47/gP+Q/7P/xf/U//X/FwAkACIAHQAbACUALgAjABIAFAAgACIAHAAQAAMAAAD7/+D/x//R/+r/AAAUABcABgAHACUAPQA8ADcANQAoAAoA8f/z/wQABwACAAwAJwA8ADcAIgARAP3/7f8CACAAGQARACYALwAhAB8AIQATAAgABAD//xEAJAAXABYAKQASAOH/zf/P/8//zv/G/77/vv+3/67/t/+0/5P/iP+d/6j/uv/g//j/+v/+////+v8GAB0AIgAcABkAGAAaAB8AEQD3//f/CwAIAPn/CQAeABcAEQAdABkACgADAPj/9/8LABAADAAfACcAFQAUAB8AGgAkAD8ALQAQAB4AIAAIABAAJAAZAAgADQAeAC4ANQA4ADwANAAQAPb/AQAPABEAFAAWABIACgD0/9f/v/+g/3v/bP97/4//k/+P/4r/f/99/4v/lv+a/6X/sv+8/9r/BwAeACEAKgAoABoAGAASAAsAGwAmACIAMwBAACgAFQAWAP7/4v/s//P/8v8TACUADgAPAB0AEAAPACUAIwAeADMANQAmAC4AKgAPABMAJQAeACQAMAAQAOn/5v/o/+7/EQAnABwAIQApABQADgAgABQA9f/u//f/BwAgACIACwABAOn/tP+k/7z/sf+H/3v/kP+r/7X/qv+c/5X/hv+E/6j/vv+t/67/xP/U//H/FAAZABQAFAAJAAoALgBAACsAHgAcABoAIQAhABsALAA8ADQAMQA0ACMAEQAJAPn/9/8cADMALQAwAC0AFQAOABIABwAFABMAFAAUACIAIAALAAUABAD5//3/CQAPAB4AKwAdABMAIQAeABIAJQAyAB0AHQA2AC0ADgAIAPj/yP+r/6v/pv+e/6P/pv+d/4j/fP+I/5L/gv97/5T/qf+x/77/zf/e//j//f/2/wsAHgATABoAPQBOAE8AVABHADIAKgAYAAEACgASAAIADQAmABUAAAAQABIA9f/s//L/9P8FABYACwACAAcA+v/s/wEAHAAYABEAGgAWAAcACgAYAB8AJAAvADsAPQA1ACgAIAAlACYAFwASACAAJgAlADMAQAAuAAgA5//M/7z/rv+S/4P/jv+X/5//rf+o/5j/l/+W/43/kP+Y/6X/zf/y//P/AgAYAPz/5v8JABcAAwANAB8AFAATACMAKwAxADEAHgAZACQADwD5/wQA///w//7/CwAIABQAKgAtACgAKwAlAAwA+f8EABgAFQASAC4APAAdAAYABwAIABYAIQALAP3/DAASABEAIwAzACEABAD//w4AGQAdACYAKgATAPP/5f/T/8T/y/+//6X/s//G/7P/pP+h/5H/iv+Z/67/yf/Z/8T/u//g//D/4//z//3/6P/q//v/AwAdADoAKQD+//T/CgATAAgACQAaABsADQAUAB8ADQAAAAoACQADAAUA/P8AABcAGgAPAA0AAwD6/wEAAQD2//z/BQD//wMACgD4/+r/6v/p/wEAHwAaAB0AMQAkAAcA/v/+/wUAGwAkACAALQArAPv/0//L/8D/rf+c/5r/sv+//7b/t/+2/6D/m/+u/7n/vf/C/8r/6P8TAA8A6//r//3/AgAMABcAGgAZAAsAAAAUACUAFgASACoAMQAcAAsAAwABAAkADgAHAAUADQAKAP3/AwApAEAAJAACAAIADAAUAB4AHAALAP7/BgAeACwAHQABAOz/5//7/xUAEwAOACwAPAAdAA8AHQAKAOX/5P/8/wsADwAWABQA7v+0/5z/pP+l/5//pf+s/7P/wf+5/57/nP+o/6//w//T/83/z//k//v/CwAMAAIAAgALAA8AFAAdABUABAAFAAkABgAQAB8AHAALAAoAIwAtABEAAAAKAAIA+v8OACEAJgAwAC0AHQAjAB8A8//x/yUALQARABMAHQAgADEAMwANAN7/zP/j/xAAJwAgACIAJgAQAAMACAD+/wEAGwAaAAgAFAAmABEA3/+2/6T/nf+X/6T/wv/C/6H/m/+w/6z/n/+2/9D/wP+i/6r/1//1//7/DgAZAA4ABQAOAA0A8f/f//T/FAAdABoAHQAcAA8ACQAHAAEABgAZABsAFAAWABEABQAIABEAEgARABQAHgAnABUA8P/i//H/AgAQABQABwADAAIA7v/z/xUAEwD+/xEAIwAGAPL//v8JABkALQAjABMAGwARAPv/BAAcACIADQDc/6n/lP+W/6H/sf+w/4//ff+K/5D/jf+I/3z/hv+t/8v/2f/l/+7/8f/o/9L/0v/4/wUA8P8DACQACgD3/x0AJwAAAPT/DgAfACUAKQAiABoAEwAIAAYABgD1/+3/9P/w/+X/7P/3//H/5P/p//v/AADy/+z/9f/7/wAAEgAWAAQAAQAOAAoA/f///w4AJQA3AC4AEAAEABkALQAtACwAMAAmAAgA7P/e/9//3//R/8D/xf/E/6P/j/+i/6z/nf+Z/6H/nf+V/6L/v//Z/+v///8OAA0ABgAAAO3/4P/3/wUA5P/X//f/DQATABwADwD3//H/8f/w/wQAHwAiACAAJAAhACgAMgAiAA0AEgAhACwANAAxACIADwALAB0AKQAgACAALwAnAAQA+P8AAPj/8v8HABgACQD4/wgAHAAIAPr/HAA2ACoANABTAEwAJAAIAPP/1f/F/87/1P/I/7D/oP+d/5r/mv+h/6n/t//B/7T/tv/j/wQA8f/s/xUAIwD8/+3/FgAzAB4AAwADAP7/7P/0/xEAHAAkADEAKwAnAD8ATQA6ADoAVwBSACsAKQBFADsAHwAuAEYAKwAOACcAOwAWAPb/CgAnACQAFQAXACAAEQD8/wQAFgAUAA8AHQAoACMAEwD9//T/BwAcAB0AIgAyADEADADd/8r/yv+6/6T/o/+e/4r/if+d/6P/m/+W/4z/if+l/83/5//2/wcAHwA5AEUAOgAXAPX/+P8PABQAFgAqACsAEQALABoAEwABAAEAAgD9/wUAFgAgAB0ADgAEAAYAEwAkACoAHwAVABQAEwATABkAIwAuADoAQgA/ADgAJwAVABUAHQAVAAoABwABAPT/+P8UACoAHgADAPT/5f/Y//L/JAAvAAUA2f+//67/qv+y/7f/sP+h/5X/kf+O/4j/h/+V/6f/sP+y/77/2P/w//r/AQAPABkAFAAKAAwAGAAbAAcA8//4/wwACADn/9L/3v/r/97/3f/6/wsAAgAIABoACADf/9//AwAWABcAHQAmAC4AOAAvAAUA5//1/wEA+P8SAEUAQQAMAPn/CgAFAPn/DwAuACgACAD1//v/DwAcABYACQADAPb/6P/z/wUA7//F/77/y/+8/5z/jf+L/4r/lP+d/5D/gf+P/6P/nv+W/6//1v/m/+X/7f8AAAwACQADAAUAEAAaABkADAAGABUAIQATAP3/+v/7//f/CwAuACgABwAOADgAOAANAPf//v8BAAkAGwATAPT//f8oACgA+//v/xEAJQAmADcASQA6AB4AHAAuADoAOAAtACAAHQAeABQADgAfACwAEwD0////HQAWAPT/3f/P/7X/n/+l/7H/p/+W/5b/l/+P/47/mf+W/4n/lf+4/9D/3v/4/wwABQACABwALgAlACYAPQA/ACQAIAA/AFIAQwAwAC0AKQAiACUALQAgAAEA6f/g/+T/9f8DAPf/8P8OACkAFQD+/xgALAANAPr/GQAkAAAAAAAxADsAEgAJACoAPABAAEUAKwAAABIATgBUACkAHwAqAA8A9/8XADMAGQD//wYA8/+//7H/zv/A/4H/af+S/7n/uf+2/7j/p/+M/4X/hf9+/4n/rv/M/+f/GQA/ADEAGwAoACkA///u/xgALgAQAAwANQAzAO//zf/2/x4AGwATABQABgD4/wkAIAAgABwAHgASAAIABwAQAAkACQAYABgACQAHAAoABQAKACQANQAyADMAPAA/AD8AQAA2ACAAGQAwAFIAXAA/ABsAEgAaABcADgAPAAkA6P/J/8X/xP+r/47/gv90/1b/RP9T/2z/dv+B/5P/mf+S/5//wf/K/7n/w//x/xMAHgAyADkAEADi//D/IgBAAEgAQAAaAPT/8v8DABUAOABIABEA1v/u/yUALAAqADwAIwDe/8f/7f8MABMAFwAPAPv/+v8FAAYABgAQABwAJgAuACUAFwAaACAAFQAbAEAAUQA2ACEALgA2AB8ACAALABMACQD8//n/+P/o/9b/0P++/5H/b/+D/6b/nP93/2z/cf9s/3X/ov/I/8r/yP/X/+P/7f///wUAAwASACIAEQAEABwALgAXAAgAGQAaAP7/8P/+/w0AFgAaABQADQAQABMAFwAlACcACQDu//v/GAAlACwAMAAYAPr/CAAlABUA+P8QAD0APgAqADYARgA1ABkAFgAqADsAMwAgACsATABEABgAEQAwADQAHgAdACMADgDx/+L/3v/c/8//rP+X/6v/t/+R/3P/k//E/8z/rf+O/43/sf/g//3/CAAKAAcAFAA3AEEAIQAJABEAFgAGAAAACgAIAAIAEgAjAA0A6//z/xYAFQDx/97/5P/q//P/CQASAAIA+/8NABMAAQD7/xEAHgAPAAYAEQAOAP7/CQAqADUAKwAsACwAHAAXAB8AHQAbACYAJAAXACgAOgAWAPD/HABUAC4A3v/G/8r/sf+g/7P/uv+e/5X/q/+y/5//lf+T/4j/jP+m/7P/tf/Z/woACADq//H/FwAtADIANAA4ADsALwASAAkAIwAqABMAFwA2ADYAJwA2AEAAIQAPACYAOQA4ADcALwAhACsAQgA8ACUAIQAoACIAGAAcACYAIgAOAAIADQAgACsAOwBJADEABwAEAB8AIgAbACkAKwANAAAAEwARAPf///8iABgA4v/A/77/t/+m/5T/fv90/4H/kP+V/5//mv9y/1v/hP+w/6n/o//C/9H/xf/d/xEAHAD+//D/+v////3//f/9/wAAGQA5ADcAFAAFABEADAD7/w4AKQASAPX/DwAtABwADAAMAPb/7P8WADAADwAGACgAHQDw/wUARgBJABIA+v8MABQABQD9/w4AHQASAAsAHwAnAAoA+f8SABwA+v/n/wQAIgAeAAsA+v/g/8n/zP/a/9T/v/+u/6D/kf+O/5v/rf/A/8b/sf+X/57/tf+7/8H/1//n/+3/BgAiABkA+v/r/+f/6f/7/xoAKgAjAA0A+P/z/wQAGwAmABsABgD//wwADQD3/+r/7//n/9j/6f8LABEAAAD+/wgAAgADACkATgA4AAoADQAuACgAEQAgADQAJgAiADkAOgAfABwALwAuACUALgA9AD4AOwA6AC4ACgDa/8H/xf/E/7L/rf+4/7T/l/91/2b/df+W/6j/rP/A/9L/v/+l/7H/0P/p/wAAEwAYABcAEQAAAPb/AAAJAAgADgAbAB8AHgAZAAsABgARAA0A/f8LACQAHQAXADQAPAARAPD/9/8EABQAPABXAEcAMgAzADQAMAA3ADsAMgAoAB0ADwARACMAHgAKABMAIAAEAPT/IwBEAB0ABAAyAE0AKgALAAgA/P/z//L/2//D/8r/uf+A/3L/mf+c/4f/pf/H/6//jv+R/6D/sf/K/9X/2P/o//T/7v/2/wMA9v/n//L/+v/0//3/CwD///b/GQBDAEIALAApACkAEwACABUAMAAwACMAMABQAFIALQAcADcAPwAbAA8AMQBCACwAHgAgABwAHAAiAB4AFwAfACUADADl/+H//f8KAAUAIABKADsABgD//xsAEgDv/+r/8v/W/6b/nP+1/8H/sP+k/6D/j/+B/47/lv+L/4X/i/+Y/67/wv/K/97//P8BAPr/BQD//+r/9v8SABEACgAaAB4ADAAIAAwABgACAAIABAAWAC4AMQAhABoAGgARAAQACAASAA0ADAAhACMA+P/h/wgAJwAWAA0AHAASAPH/8v8TACAABgDs//L/DgAcAA0A/P8AAAUA9P/v/w8AGADv/+j/FgAcAPD/4f/b/6j/g/+W/57/f/9s/3T/if+c/5L/fv+M/6j/ov+S/5L/hf99/7T/BwAiAA0AAgABAPP/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JgD///H/DwAvACwAEQD//wAA/P/8/yYAVgA3AOf/yf/M/6b/d/9//53/n/+k/7z/uf+S/33/if+O/5X/xf/y/9n/uf/l/yAAHwANABYADgD0//z/HwArABwADwAPAA8ABAD5/wIADgAKABAALgA1ABEA8P/r//T/BwAbABQA+P/1/xkAOAAzACEAEwACAPv/GAAvABcAAwAfACYA/v/5/x0AGwABABwAQQAxABYAGwAfABsAMABLAD4AGQAKABcAJwAyAC8ABwC//5f/pP+z/67/t//M/9T/0f/K/7D/kP+J/5T/nf+m/7T/zP/v/wgADgAQAA8ABAAHAB4ALAA0AE0ASAAMAOn/DQAoAAgA8P8MABoAAAABADgAUgAsABkAOQA9ABsAHwBDAEMANQBIAFkARgA1ADcALAASABEAMQBDAC4AFwAeABUA4v/W/xQAPgAcAPr////5/9f/0P/w/wMA8//s/wQAFgAKAPX/2/+u/5X/s//S/8H/qv+s/6z/pP+m/6j/pf+v/8P/zP/K/8v/zv/Q/9z/AgArACkABAD5/w8AGgAbACQAGAD6/wIAIwAcAAQADQARAPX/8v8kAEEAGADk/9v/1v+//83/DgA0ACIAFgAcABAABAAWACMAIAAkABoA9v/z/xgAIAADAP3/GAArACwAJwAeACAANgBDACsACQAOACYAGwAJAC0AWgBAAAYA6v/K/4r/Zf9z/4r/mf+q/6n/kP99/4H/hv93/2L/YP9t/3r/mP/Y/wwAEgAIAAcA/v/0//r/BAAJAB0AMQApABgAFQAfACkALQAnAB4AFQASABsAKwAmABUAFwAoADEAMQAyADAAKQAaAAsABgALAA4AGgApAB4ADQAkAD4AMgAoADgAMwAOAAAAEgAlADcARwBDADYAOwBGAEMAPgBIAEwAMgATAA0ABADc/77/xf/P/8v/0v/Q/7b/sP/B/7X/mv+j/7j/qf+R/5P/pP+4/8n/z//b/+3/7f/j//X/FwAgABEACwAIAO//0//c//n/+v/n/+z//P/8////EAARAAcACgAOAAoAGAAmABgADwAfABwABQAIABUACAAAABIADgDi/8v/4v/2/+z/9f8pAEQAJgASACAAFQDy//3/JQAgAAQAFQA5ADkAKwBEAGoAUAAFAOb/8v/S/5z/sP/f/8f/oP+2/7z/ff9d/5P/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4P/N/+b/FwA1AB4A4v+//9j/AgATABYALgBXAGUANgDs/77/sv+y/7r/wf+6/67/nv+H/4f/r//G/63/pP/K/+X/1//S/+j/+/8HACgATwBQADsARABYAEQAJgAtADgAKwAvAE0AWABOAFYAagBvAGYAVwBCACYACQADAB8AOQA5ADkATgBcAEsALAAZABwAKwA3AEMATQBIADYALQA0ADoANwAuACYAKQAtACQAGwAjADMAPgA7ACUAEwAgADUALAARAPX/1//K/8//vv+R/33/k/+h/4j/Z/9k/3X/d/9k/1T/Vf9l/4H/oP+0/7n/u//J/+L/4v/C/7n/8P8zAEsASAA1AA8A+v8KAA0A6//d//7/IgAqABwA9//F/6r/tP/J/93/+f8XAB4AEAAAAO7/0v+//8z/7/8YADcAMgANAO3/5f/r//r/BAD6//P/BgALAPT/8P8DAPL/xf/B/+f/CQAhAEAAUgBDACAA9//K/6f/mv+V/4//l/+l/53/kv+c/4//Wv9M/4H/nP95/2f/j/+5/87/6v8PACAAFwAJABAALgA+ACoADAAKABwAIQAYABUAGQAfACcAMwA4ADkAQABGAEQARwBRAFEASABBAEAASABYAFYANwAhACUAJgAfACYANAA5AD0AQgBBAEQAVQBXAEQAPwBPAEwAKgATABgAHgAdAC0AQgBCADwAQgA7ABgA9v/s/+z/4//M/7T/rP+n/47/e/+M/6X/p/+o/7b/r/+X/5v/vf/Z/+z//v/0/87/wv/m/wcADQAfAEMAUAA3AAwA3P/E/+z/MgBKACsABgDv/+L/7P8PACkAHgD4/+H/9/8fACMABgD5/////v8AABgAIgACAOn/BQAtADIAKgAtACUACQACAB0ANwA3AC0AMwBJAFgAUwBSAGcAdgBmAE8AQAAqAB0ALwAuAOP/j/+T/8//5P/R/83/1P/F/7H/tP/C/83/4f/4/wQACgAXAB4AGAAXACQAJgAWAAsAHQA5ADYAGgAMABQAEAD/////DAANAAoAGAAkAB4AIAAyADYAIwAXABgAFAASACIALAAPANz/vP/B/+T/FAAxAC4AGgAJAAIABwAXACMAIwAbABEADQAgAD8ARgAnAP3/3v/O/9T/7/8IAAkA///5//D/3//I/6z/lP+c/8L/2P+//47/df9//4b/a/9J/1L/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uv/i//b//f/5/83/lP+Y/+b/LwA1AAsA8P/+/xkAKQAxADcAMQAnADQAVgBwAHEAZgBjAGsAawBdAGIAjQCxAKYAiwCAAGsASwBMAGgAXQAlAPv//f8aAEYAZQBTABsA/f8RADwAaACIAIIAWgA+AEwAYwBPABoA/v8LABcACgD8//7/AgAKABYADADt/+X/+P/4//X/IABRADEA2/+o/6H/nf+d/6H/iP9U/zr/Sf9P/zj/Mf9Z/4v/lf98/3H/kf/L//7/DADm/7D/rf/a//b/6f/e/+z/+P/y/+X/2v/b/+r/9//+/woADADx/+b/FQBFADUAEgAfADgAIwABAA4ALwApAAYA+f8OAB4AGQAYACcAJgATABgANgA+ACYAGQAjACsAHgD9/93/4f8OADMANQAxADQAJgASACAARwBWAEIAJAAOAP//7v/X/9D/7P8LAPv/zv+2/7z/xf/L/9n/5v/e/8X/v//s/yoAOAAaAA0AHwArACIAGAANAAgAJABbAH8AewBWACAA9v/+/ywAUABYAE4AMgAOAAcAHQAsACMAHQApADoAPgA+AEsAVgA+ABQAEwA3AD0AHQAZADsARQApAA8A///y//b/DwAeABMABwARACsAPAAzABsAEgAcACEAHgAbABAA9f/l/+j/5P/F/5n/e/95/5D/pv+o/6L/nP+Y/57/sv++/7//zf/d/9D/yP/s/woA7v/O/+L/8//W/8v//v8qABgA/f8RACoAEwDs//X/GQAaAAQADwArACQABwAJACMALgAiAAQA3f/P/+r/AgD+//v/+f/V/7P/zv////3/7P8HACMACADm//n/GwAUAP7/CwAsADIAIQAbABkA/f/b/9X/1//B/67/u//B/6P/hf+H/5n/pf+d/3v/Xf9r/5D/m/+X/57/nP+L/6D/3P///wEADwAXAOv/tf/O/yIATgA4ABwAGQAMAPX/BwA/AEoAEgDt/w8APQBEADoAMgAdAAoADQAVABUAEwAOAAYAEQAsAC0AGgAmAEMAMgAFAP//HAAtADkATgBLAB4A+v8NADMALgAKAAUALABHADwAMgA3ACcA/P/l//D/BAARABAA9P/J/7H/q/+o/7L/0P/b/7X/fP9i/4T/yP/n/77/iP+T/8//AwAdACYAIwAkAC4AKQAMAAMAKABQAE0ALAAaACYAQABRAFgATwAuAAUAAQAoAE4AWwBTADgAFwAYADIAMgAYABYAJAAbABAAHwAnABIABgAOAAkA+/8MADUAQQAeAO7/2v/o//z/AwAEAAoACAAFAB4ARQBIACkAGgAiACcAKwA5ADIABgDZ/8//0P+0/4v/iv+3/9D/rv+E/5H/uf/D/7f/rP+W/33/lf/f/xQAEQACAA0AHgAbAAgA9//t/+z//P8bADAAJgALAPn/9f/9/xoAQgBdAGoAbABMABUAAwAkAD8APwBJAF0AUwA0ACgAMgAzACAADAANACEAIgAPAA4AJAAmAB4AOABSADQADAAWAC8AKAAhADcASQA+AC4AKgAkAB4AKgA6ACcA6//B/8f/zP+r/5X/qf+w/43/gP+m/8T/tP+Y/43/kP+n/9H/9/8KABAADQAEAAQACgADAPT/7f/w//r/FQA1ADAA/f/Y/+7/GwAdAPP/2v/z/xUAFAADAA4AJQAOANH/tP/N/+3/9v/5////9//e/9D/5/8OABUA9P/h/+v/6f/X/+H/9f/U/5//sP/y////0f+//9//7P/S/83/9f8PAPn/5P/u//D/0v+1/6D/h/96/3//dP9p/4z/vf+z/4j/fP+A/4L/nP+4/6H/e/+T/9P/9v/6//v//f8EABoALwApAA8AAQARACwALQAbABsAHgAAAOT/AwAyACcAAgALAC4AKAAFAAEAHgAvACEADgAMABkAKQA0ADMAIgANAAMABgAVACYAJQASAAQAAAD9/wYAIgAsAA0A7f/+/ywAPgAjAPz/7P/5/woAAwDg/8T/x//T/8H/o/+b/5X/cP9T/2z/lf+d/5r/rP+6/6//rf/P//X/+f/w/wIAHgAbAA0AJABKAEoANwA5AD8APgBRAG0AbQBhAGIATAAXAAMAJwBNAFoAWgBQAD0ALwAnAB8AJwBBAFEARQAoABMAHgA8AEEANABDAFoAQwAaAB4AOAA1ACoANgBAADUAKwAmABkACgAKABgAJwAlABIAAgACAP7/8P/v//3/9f/J/6D/mP+W/3v/Yv9s/3j/Wf88/1j/iP+Y/53/qf+Y/3j/jP/I/9v/w//J//j/EQAJABEANQBIADQAFgAMAA0ADQATABsAJwA7AEwAQQAnABsAFgADAPT//f8PABwAJQAlABUABQACAA8AKABCAEsARAA5ACcADgD//wsAKQAzAB4AHQBVAIMAWwAZABgAKgAUABgAVQBmADAAFQAoACMAGwBKAGwAMgDX/7L/uv/I/9j/5//Z/7H/mP+q/9j/AgAcABsA7/+7/8L/9P8MAAsAJwBSAF0AYAB0AGwANQAMABIAEwD6//r/JQA0AA0A/f8nADwAFQABABkADgDa/9b///8FAO//6//j/9L/8v80AEAAFAD0/+P/yf/M//z/GwANAAQAEQATAAcAFAAwACsAAgDg/9n/5P///xkAEgD+/wIACwD8//P/BQABANf/t/+q/5D/e/+F/5P/h/9l/zX/GP89/43/tP+h/4f/bv9b/3f/vf/q/+7/8f/8//L/4//y/xcAIAD6/9H/2f8GACUAKAAiABEA//8IACAAGQD0/+X//v8hACYADgACABYAIgAQAAkAGwAUAPT/9f8ZACMABQDy/wYAKwAsAAAA7/8mAFkANADw/+//GAAaAAcAHwBSAFcALQAfAD8ARwAiAB4ASABAAOz/t//X/wAA8P++/6H/pv+w/6j/rP/R/+D/sP+I/7H/9P/7/97/5f8MACQAJAAyAFMAXQA3AA8AGgBIAF4ARwAdAAgAEQAlADkASwBFABoA8//6/xEAHwAuADAADwD0//z/AwAFACcAPAAIANf/9v8bAP//7v8XADIAGgAHAAgA///u/+n/7P/9/yUAOAASAOL/6v8TACUAJwA3ADQADwAJADcAQgAIANv/2f/H/6z/uf/F/5b/Y/9o/4P/jf+S/5f/l/+g/6j/l/+K/6P/yv/e/+r/+P/9//7/BQANABUAGwAWABcAKwAtABIAEAA0ADoAFAANADcAQwAjACcAXwBrACYA7P/7/xUAEgAdADkAKQADAA8ANwA7ADQAQgA4AAwA+v8HAA4AGAAuACkABQD0////CwAYAC4ANwAqABYAEAAgAEAAUABMAFMAawBrAD8ABwDw//T/7P/O/8X/1//R/7T/w//1//n/1P/M/87/qv+N/7n//v8LAPD/8P8QAB4AEgAXADoATgA2ABEABAAVADkATgA4ABUAEAATAAIACAAxADkACgDk/+z//v8FAAcABQD3/9z/xP/S/wIAFADy/97/9P8LABoANgA6AAIAx//O/wYAMgA9AC8AFQAAAP3/AwAGAAUAGQA4ADcADgD//yIAMAD6/7X/ov/A/+H/4//P/7P/iv9a/2P/s//t/9b/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\" type=\"audio/x-wav\" />\n", + " Your browser does not support the audio element.\n", + " </audio>\n", + " " + ] + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Trancript: limiting emotions that we experience mainly in our childhood which stop us from living our life just open freedom i mean trust and\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "Run inference with both greedy decoding and LM decoding" + ], + "metadata": { + "id": "ZdVDTW_yduyQ" + } + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "os.environ[\"TMPDIR\"] = '/content/temp_dir'\n", + "os.environ[\"PYTHONPATH\"] = \".\"\n", + "os.environ[\"PREFIX\"] = \"INFER\"\n", + "os.environ[\"HYDRA_FULL_ERROR\"] = \"1\"\n", + "os.environ[\"USER\"] = \"micro\"\n", + "\n", + "print(\"======= WITHOUT LM DECODING=======\")\n", + "\n", + "!python examples/mms/asr/infer/mms_infer.py --model \"/content/fairseq/models_new/mms1b_fl102.pt\" --lang \"eng\" --audio \"/content/fairseq/audio_samples/audio.wav\" \"/content/fairseq/audio_samples/audio_noisy.wav\"\n", + "\n", + "print(\"\\n\\n\\n======= WITH LM DECODING=======\")\n", + "\n", + "# Note that the lmweight, wordscore needs to tuned for each LM \n", + "# Using the same values may not be optimal\n", + "decoding_cmds = \"\"\"\n", + "decoding.type=kenlm \n", + "decoding.beam=500 \n", + "decoding.beamsizetoken=50 \n", + "decoding.lmweight=2.69\n", + "decoding.wordscore=2.8\n", + "decoding.lmpath=/content/lmdecode/lm_common_crawl_small_4gram_prun0-6-15_200kvocab.bin\n", + "decoding.lexicon=/content/lmdecode/lexicon.txt\n", + "\"\"\".replace(\"\\n\", \" \")\n", + "!python examples/mms/asr/infer/mms_infer.py --model \"/content/fairseq/models_new/mms1b_fl102.pt\" --lang \"eng\" --audio \"/content/fairseq/audio_samples/audio.wav\" \"/content/fairseq/audio_samples/audio_noisy.wav\" \\\n", + " --extra-infer-args '{decoding_cmds}'\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JlKzKBIlZqKq", + "outputId": "94da50cc-2672-418b-a941-24ea0db0339b" + }, + "execution_count": 39, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "======= WITHOUT LM DECODING=======\n", + ">>> preparing tmp manifest dir ...\n", + ">>> loading model & running inference ...\n", + "2023-05-26 01:01:58.415006: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2023-05-26 01:02:00.361210: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", + "===============\n", + "Input: /content/fairseq/audio_samples/audio.wav\n", + "Output: a tornado is a spinning colum of very low-pressure air which sucks it surrounding air inward and upward\n", + "===============\n", + "Input: /content/fairseq/audio_samples/audio_noisy.wav\n", + "Output: limiting emotions that weexperienced mainly in our childhood which stop us from living our lives in just open freedom and interust and\n", + "======= WITH LM DECODING=======\n", + ">>> preparing tmp manifest dir ...\n", + ">>> loading model & running inference ...\n", + "2023-05-26 01:03:50.066828: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX512F FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2023-05-26 01:03:52.190710: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n", + "===============\n", + "Input: /content/fairseq/audio_samples/audio.wav\n", + "Output: a tornado is a spinning column of very low pressure air which sucks at surrounding air inward and upward\n", + "===============\n", + "Input: /content/fairseq/audio_samples/audio_noisy.wav\n", + "Output: limiting emotions that we experience mainly in our childhood which stop us from living our lives in just open freedom and interest and\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "dJUXy2dye8sH" + }, + "execution_count": null, + "outputs": [] } ] -} \ No newline at end of file +} From b30980349bcb2e870481d783ac8cb3f338361601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serkan=20Day=C4=B1c=C4=B1k?= <serkandayicik@gmail.com> Date: Fri, 26 May 2023 04:51:56 +0300 Subject: [PATCH 750/774] Feature: Implement UTF-8 readfile support in MMS for TTS example (#5148) --- examples/mms/tts/infer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mms/tts/infer.py b/examples/mms/tts/infer.py index a51e2412f1..a59fac2a62 100644 --- a/examples/mms/tts/infer.py +++ b/examples/mms/tts/infer.py @@ -24,7 +24,7 @@ class TextMapper(object): def __init__(self, vocab_file): - self.symbols = [x.replace("\n", "") for x in open(vocab_file).readlines()] + self.symbols = [x.replace("\n", "") for x in open(vocab_file, encoding="utf-8").readlines()] self.SPACE_ID = self.symbols.index(" ") self._symbol_to_id = {s: i for i, s in enumerate(self.symbols)} self._id_to_symbol = {i: s for i, s in enumerate(self.symbols)} From ae59bd6d04871f6174351ad46c90992e1dca7ac7 Mon Sep 17 00:00:00 2001 From: chevalierNoir <bshi@fb.com> Date: Fri, 26 May 2023 17:43:15 -0400 Subject: [PATCH 751/774] MMS TTS Colab Notebook (#5165) * Add TTS Colab notebook --------- Co-authored-by: Bowen Shi <bshi@meta.com> --- examples/mms/README.md | 2 + .../tutorial/MMS_TTS_Inference_Colab.ipynb | 543 ++++++++++++++++++ 2 files changed, 545 insertions(+) create mode 100644 examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb diff --git a/examples/mms/README.md b/examples/mms/README.md index 093facc600..a7a1e98bfa 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -124,6 +124,8 @@ $ PYTHONPATH=$PYTHONPATH:/path/to/vits python examples/mms/tts/infer.py --model- ``` `example.wav` contains synthesized audio for the language. +We also provide an Ipython notebook example inside `tts/tutorial` folder [ipynb](https://github.com/facebookresearch/fairseq/blob/main/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb) or [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/facebookresearch/fairseq/blob/main/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb) + ### LID diff --git a/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb b/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb new file mode 100644 index 0000000000..32c9a71996 --- /dev/null +++ b/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb @@ -0,0 +1,543 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "okQdUOf2ovBS" + }, + "source": [ + "#Running MMS-TTS inference in Colab\n", + "In this notebook, we give an example on how to run text-to-speech inference using MMS TTS models. \n", + "\n", + "By default, we run inference on a GPU. If you want to perform CPU inference, go to \"Runtiime\" menu -> \"Change runtime type\" and set \"Hardware accelerator\" to \"None\" before running." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XK2jXLmEpgK5" + }, + "source": [ + "## 1. Preliminaries\n", + "This section installs necessary python packages for the other sections. Run it first." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "id": "vGyb3dGWpmks", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "outputId": "695170f4-8083-4f57-fcc1-78252e40c0f4" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Cloning into 'vits'...\n", + "remote: Enumerating objects: 81, done.\u001b[K\n", + "remote: Total 81 (delta 0), reused 0 (delta 0), pack-reused 81\u001b[K\n", + "Unpacking objects: 100% (81/81), 3.33 MiB | 3.72 MiB/s, done.\n", + "Python 3.10.11\n", + "/content/vits\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting Cython==0.29.21\n", + " Downloading Cython-0.29.21-py2.py3-none-any.whl (974 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m974.2/974.2 kB\u001b[0m \u001b[31m49.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hInstalling collected packages: Cython\n", + " Attempting uninstall: Cython\n", + " Found existing installation: Cython 0.29.34\n", + " Uninstalling Cython-0.29.34:\n", + " Successfully uninstalled Cython-0.29.34\n", + "Successfully installed Cython-0.29.21\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting librosa==0.8.0\n", + " Downloading librosa-0.8.0.tar.gz (183 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m183.9/183.9 kB\u001b[0m \u001b[31m12.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: audioread>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (3.0.0)\n", + "Requirement already satisfied: numpy>=1.15.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (1.22.4)\n", + "Requirement already satisfied: scipy>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (1.10.1)\n", + "Requirement already satisfied: scikit-learn!=0.19.0,>=0.14.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (1.2.2)\n", + "Requirement already satisfied: joblib>=0.14 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (1.2.0)\n", + "Requirement already satisfied: decorator>=3.0.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (4.4.2)\n", + "Collecting resampy>=0.2.2 (from librosa==0.8.0)\n", + " Downloading resampy-0.4.2-py3-none-any.whl (3.1 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.1/3.1 MB\u001b[0m \u001b[31m103.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: numba>=0.43.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (0.56.4)\n", + "Requirement already satisfied: soundfile>=0.9.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (0.12.1)\n", + "Requirement already satisfied: pooch>=1.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (1.6.0)\n", + "Requirement already satisfied: llvmlite<0.40,>=0.39.0dev0 in /usr/local/lib/python3.10/dist-packages (from numba>=0.43.0->librosa==0.8.0) (0.39.1)\n", + "Requirement already satisfied: setuptools in /usr/local/lib/python3.10/dist-packages (from numba>=0.43.0->librosa==0.8.0) (67.7.2)\n", + "Requirement already satisfied: appdirs>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from pooch>=1.0->librosa==0.8.0) (1.4.4)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from pooch>=1.0->librosa==0.8.0) (23.1)\n", + "Requirement already satisfied: requests>=2.19.0 in /usr/local/lib/python3.10/dist-packages (from pooch>=1.0->librosa==0.8.0) (2.27.1)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn!=0.19.0,>=0.14.0->librosa==0.8.0) (3.1.0)\n", + "Requirement already satisfied: cffi>=1.0 in /usr/local/lib/python3.10/dist-packages (from soundfile>=0.9.0->librosa==0.8.0) (1.15.1)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi>=1.0->soundfile>=0.9.0->librosa==0.8.0) (2.21)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.0->librosa==0.8.0) (1.26.15)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.0->librosa==0.8.0) (2022.12.7)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.0->librosa==0.8.0) (2.0.12)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.0->librosa==0.8.0) (3.4)\n", + "Building wheels for collected packages: librosa\n", + " Building wheel for librosa (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for librosa: filename=librosa-0.8.0-py3-none-any.whl size=201378 sha256=fa582ff086e0ed1d87d99596e59f3e8a42adbd67480b5b523c0d992b0349699c\n", + " Stored in directory: /root/.cache/pip/wheels/bf/b7/85/2f8044306ccec014930aea23ad4852fca9e2584e21c6972bc6\n", + "Successfully built librosa\n", + "Installing collected packages: resampy, librosa\n", + " Attempting uninstall: librosa\n", + " Found existing installation: librosa 0.10.0.post2\n", + " Uninstalling librosa-0.10.0.post2:\n", + " Successfully uninstalled librosa-0.10.0.post2\n", + "Successfully installed librosa-0.8.0 resampy-0.4.2\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting phonemizer==2.2.1\n", + " Downloading phonemizer-2.2.1-py3-none-any.whl (49 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.0/49.0 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: joblib in /usr/local/lib/python3.10/dist-packages (from phonemizer==2.2.1) (1.2.0)\n", + "Collecting segments (from phonemizer==2.2.1)\n", + " Downloading segments-2.2.1-py2.py3-none-any.whl (15 kB)\n", + "Requirement already satisfied: attrs>=18.1 in /usr/local/lib/python3.10/dist-packages (from phonemizer==2.2.1) (23.1.0)\n", + "Collecting clldutils>=1.7.3 (from segments->phonemizer==2.2.1)\n", + " Downloading clldutils-3.19.0-py2.py3-none-any.whl (1.7 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.7/1.7 MB\u001b[0m \u001b[31m68.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting csvw>=1.5.6 (from segments->phonemizer==2.2.1)\n", + " Downloading csvw-3.1.3-py2.py3-none-any.whl (56 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m56.7/56.7 kB\u001b[0m \u001b[31m7.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: regex in /usr/local/lib/python3.10/dist-packages (from segments->phonemizer==2.2.1) (2022.10.31)\n", + "Requirement already satisfied: python-dateutil in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (2.8.2)\n", + "Requirement already satisfied: tabulate>=0.7.7 in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (0.8.10)\n", + "Collecting colorlog (from clldutils>=1.7.3->segments->phonemizer==2.2.1)\n", + " Downloading colorlog-6.7.0-py2.py3-none-any.whl (11 kB)\n", + "Collecting pylatexenc (from clldutils>=1.7.3->segments->phonemizer==2.2.1)\n", + " Downloading pylatexenc-2.10.tar.gz (162 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m162.6/162.6 kB\u001b[0m \u001b[31m23.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: markdown in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (3.4.3)\n", + "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (4.9.2)\n", + "Requirement already satisfied: markupsafe in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (2.1.2)\n", + "Requirement already satisfied: babel in /usr/local/lib/python3.10/dist-packages (from csvw>=1.5.6->segments->phonemizer==2.2.1) (2.12.1)\n", + "Collecting colorama (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", + " Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n", + "Collecting isodate (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", + " Downloading isodate-0.6.1-py2.py3-none-any.whl (41 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.7/41.7 kB\u001b[0m \u001b[31m6.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: jsonschema in /usr/local/lib/python3.10/dist-packages (from csvw>=1.5.6->segments->phonemizer==2.2.1) (4.3.3)\n", + "Collecting language-tags (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", + " Downloading language_tags-1.2.0-py3-none-any.whl (213 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m213.4/213.4 kB\u001b[0m \u001b[31m29.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting rdflib (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", + " Downloading rdflib-6.3.2-py3-none-any.whl (528 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m528.1/528.1 kB\u001b[0m \u001b[31m60.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from csvw>=1.5.6->segments->phonemizer==2.2.1) (2.27.1)\n", + "Collecting rfc3986<2 (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", + " Downloading rfc3986-1.5.0-py2.py3-none-any.whl (31 kB)\n", + "Requirement already satisfied: uritemplate>=3.0.0 in /usr/local/lib/python3.10/dist-packages (from csvw>=1.5.6->segments->phonemizer==2.2.1) (4.1.1)\n", + "Requirement already satisfied: six in /usr/local/lib/python3.10/dist-packages (from isodate->csvw>=1.5.6->segments->phonemizer==2.2.1) (1.16.0)\n", + "Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema->csvw>=1.5.6->segments->phonemizer==2.2.1) (0.19.3)\n", + "Requirement already satisfied: pyparsing<4,>=2.1.0 in /usr/local/lib/python3.10/dist-packages (from rdflib->csvw>=1.5.6->segments->phonemizer==2.2.1) (3.0.9)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->csvw>=1.5.6->segments->phonemizer==2.2.1) (1.26.15)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->csvw>=1.5.6->segments->phonemizer==2.2.1) (2022.12.7)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.10/dist-packages (from requests->csvw>=1.5.6->segments->phonemizer==2.2.1) (2.0.12)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->csvw>=1.5.6->segments->phonemizer==2.2.1) (3.4)\n", + "Building wheels for collected packages: pylatexenc\n", + " Building wheel for pylatexenc (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for pylatexenc: filename=pylatexenc-2.10-py3-none-any.whl size=136820 sha256=b88aa9b5f5a021b6d7f72b330dcb61d0d5e7f90fc4ebca8f53cc19183b6e64dc\n", + " Stored in directory: /root/.cache/pip/wheels/d3/31/8b/e09b0386afd80cfc556c00408c9aeea5c35c4d484a9c762fd5\n", + "Successfully built pylatexenc\n", + "Installing collected packages: rfc3986, pylatexenc, language-tags, isodate, colorlog, colorama, rdflib, clldutils, csvw, segments, phonemizer\n", + "Successfully installed clldutils-3.19.0 colorama-0.4.6 colorlog-6.7.0 csvw-3.1.3 isodate-0.6.1 language-tags-1.2.0 phonemizer-2.2.1 pylatexenc-2.10 rdflib-6.3.2 rfc3986-1.5.0 segments-2.2.1\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: scipy in /usr/local/lib/python3.10/dist-packages (1.10.1)\n", + "Requirement already satisfied: numpy<1.27.0,>=1.19.5 in /usr/local/lib/python3.10/dist-packages (from scipy) (1.22.4)\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (1.22.4)\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: torch in /usr/local/lib/python3.10/dist-packages (2.0.1+cu118)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch) (3.12.0)\n", + "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from torch) (4.5.0)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch) (1.11.1)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch) (3.1)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch) (3.1.2)\n", + "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.10/dist-packages (from torch) (2.0.0)\n", + "Requirement already satisfied: cmake in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch) (3.25.2)\n", + "Requirement already satisfied: lit in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch) (16.0.5)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch) (2.1.2)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch) (1.3.0)\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: torchvision in /usr/local/lib/python3.10/dist-packages (0.15.2+cu118)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from torchvision) (1.22.4)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from torchvision) (2.27.1)\n", + "Requirement already satisfied: torch==2.0.1 in /usr/local/lib/python3.10/dist-packages (from torchvision) (2.0.1+cu118)\n", + "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /usr/local/lib/python3.10/dist-packages (from torchvision) (8.4.0)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch==2.0.1->torchvision) (3.12.0)\n", + "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from torch==2.0.1->torchvision) (4.5.0)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch==2.0.1->torchvision) (1.11.1)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch==2.0.1->torchvision) (3.1)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch==2.0.1->torchvision) (3.1.2)\n", + "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.10/dist-packages (from torch==2.0.1->torchvision) (2.0.0)\n", + "Requirement already satisfied: cmake in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch==2.0.1->torchvision) (3.25.2)\n", + "Requirement already satisfied: lit in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch==2.0.1->torchvision) (16.0.5)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->torchvision) (1.26.15)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->torchvision) (2022.12.7)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.10/dist-packages (from requests->torchvision) (2.0.12)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->torchvision) (3.4)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch==2.0.1->torchvision) (2.1.2)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy->torch==2.0.1->torchvision) (1.3.0)\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (3.7.1)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (1.0.7)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (0.11.0)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (4.39.3)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (1.4.4)\n", + "Requirement already satisfied: numpy>=1.20 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (1.22.4)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (23.1)\n", + "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (8.4.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (3.0.9)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib) (2.8.2)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\n", + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting Unidecode==1.1.1\n", + " Downloading Unidecode-1.1.1-py2.py3-none-any.whl (238 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m238.3/238.3 kB\u001b[0m \u001b[31m25.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hInstalling collected packages: Unidecode\n", + "Successfully installed Unidecode-1.1.1\n", + "/content/vits/monotonic_align\n", + "Compiling core.pyx because it changed.\n", + "[1/1] Cythonizing core.pyx\n", + "/usr/local/lib/python3.10/dist-packages/Cython/Compiler/Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: /content/vits/monotonic_align/core.pyx\n", + " tree = Parsing.p_module(s, pxd, full_module_name)\n", + "\u001b[01m\u001b[Kcore.c:\u001b[m\u001b[K In function ‘\u001b[01m\u001b[K__Pyx_InitGlobals\u001b[m\u001b[K’:\n", + "\u001b[01m\u001b[Kcore.c:16766:1:\u001b[m\u001b[K \u001b[01;35m\u001b[Kwarning: \u001b[m\u001b[K‘\u001b[01m\u001b[KPyEval_InitThreads\u001b[m\u001b[K’ is deprecated [\u001b[01;35m\u001b[K-Wdeprecated-declarations\u001b[m\u001b[K]\n", + "16766 | \u001b[01;35m\u001b[KPyEval_InitThreads\u001b[m\u001b[K();\n", + " | \u001b[01;35m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "In file included from \u001b[01m\u001b[K/usr/include/python3.10/Python.h:130\u001b[m\u001b[K,\n", + " from \u001b[01m\u001b[Kcore.c:16\u001b[m\u001b[K:\n", + "\u001b[01m\u001b[K/usr/include/python3.10/ceval.h:122:37:\u001b[m\u001b[K \u001b[01;36m\u001b[Knote: \u001b[m\u001b[Kdeclared here\n", + " 122 | Py_DEPRECATED(3.9) PyAPI_FUNC(void) \u001b[01;36m\u001b[KPyEval_InitThreads\u001b[m\u001b[K(void);\n", + " | \u001b[01;36m\u001b[K^~~~~~~~~~~~~~~~~~\u001b[m\u001b[K\n", + "/content/vits\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "'/content/vits'" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + } + }, + "metadata": {}, + "execution_count": 1 + } + ], + "source": [ + "%pwd\n", + "!git clone https://github.com/jaywalnut310/vits.git\n", + "!python --version\n", + "%cd vits/\n", + "\n", + "!pip install Cython==0.29.21\n", + "!pip install librosa==0.8.0\n", + "!pip install phonemizer==2.2.1\n", + "!pip install scipy\n", + "!pip install numpy\n", + "!pip install torch\n", + "!pip install torchvision\n", + "!pip install matplotlib\n", + "!pip install Unidecode==1.1.1\n", + "\n", + "%cd monotonic_align/\n", + "%mkdir monotonic_align\n", + "!python3 setup.py build_ext --inplace\n", + "%cd ../\n", + "%pwd" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KuBzieKbuJKN" + }, + "source": [ + "## 2. Choose a language and download its checkpoint\n", + "Find the ISO code for your target language [here](https://dl.fbaipublicfiles.com/mms/tts/all-tts-languages.html). You can find more details about the languages we currently support for TTS in this [table](https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "id": "UtEeQcmwuUaG", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "70c5e4ef-24ad-4aac-93c6-b7e022eafc49" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Download model for language: eng\n", + "Model checkpoints in ./eng: ['G_100000.pth', 'config.json', 'vocab.txt']\n" + ] + } + ], + "source": [ + "import os\n", + "import subprocess\n", + "import locale\n", + "locale.getpreferredencoding = lambda: \"UTF-8\"\n", + "\n", + "def download(lang, tgt_dir=\"./\"):\n", + " lang_fn, lang_dir = os.path.join(tgt_dir, lang+'.tar.gz'), os.path.join(tgt_dir, lang)\n", + " cmd = \";\".join([\n", + " f\"wget https://dl.fbaipublicfiles.com/mms/tts/{lang}.tar.gz -O {lang_fn}\",\n", + " f\"tar zxvf {lang_fn}\"\n", + " ])\n", + " print(f\"Download model for language: {lang}\")\n", + " subprocess.check_output(cmd, shell=True)\n", + " print(f\"Model checkpoints in {lang_dir}: {os.listdir(lang_dir)}\")\n", + " return lang_dir\n", + "\n", + "LANG = \"eng\"\n", + "ckpt_dir = download(LANG)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## 3. Load the checkpoint" + ], + "metadata": { + "id": "zexlezYiSWMb" + } + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "Sxi3CXmGqH6r", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "491e8103-03db-48e8-d388-9c4482a3f059" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Run inference with cuda\n", + "load ./eng/G_100000.pth\n" + ] + } + ], + "source": [ + "from IPython.display import Audio\n", + "import os\n", + "import re\n", + "import glob\n", + "import json\n", + "import tempfile\n", + "import math\n", + "import torch\n", + "from torch import nn\n", + "from torch.nn import functional as F\n", + "from torch.utils.data import DataLoader\n", + "import numpy as np\n", + "import commons\n", + "import utils\n", + "import argparse\n", + "import subprocess\n", + "from data_utils import TextAudioLoader, TextAudioCollate, TextAudioSpeakerLoader, TextAudioSpeakerCollate\n", + "from models import SynthesizerTrn\n", + "from scipy.io.wavfile import write\n", + "\n", + "class TextMapper(object):\n", + " def __init__(self, vocab_file):\n", + " self.symbols = [x.replace(\"\\n\", \"\") for x in open(vocab_file, encoding=\"utf-8\").readlines()]\n", + " self.SPACE_ID = self.symbols.index(\" \")\n", + " self._symbol_to_id = {s: i for i, s in enumerate(self.symbols)}\n", + " self._id_to_symbol = {i: s for i, s in enumerate(self.symbols)}\n", + "\n", + " def text_to_sequence(self, text, cleaner_names):\n", + " '''Converts a string of text to a sequence of IDs corresponding to the symbols in the text.\n", + " Args:\n", + " text: string to convert to a sequence\n", + " cleaner_names: names of the cleaner functions to run the text through\n", + " Returns:\n", + " List of integers corresponding to the symbols in the text\n", + " '''\n", + " sequence = []\n", + " clean_text = text.strip()\n", + " for symbol in clean_text:\n", + " symbol_id = self._symbol_to_id[symbol]\n", + " sequence += [symbol_id]\n", + " return sequence\n", + "\n", + " def uromanize(self, text, uroman_pl):\n", + " iso = \"xxx\"\n", + " with tempfile.NamedTemporaryFile() as tf, \\\n", + " tempfile.NamedTemporaryFile() as tf2:\n", + " with open(tf.name, \"w\") as f:\n", + " f.write(\"\\n\".join([text]))\n", + " cmd = f\"perl \" + uroman_pl\n", + " cmd += f\" -l {iso} \"\n", + " cmd += f\" < {tf.name} > {tf2.name}\"\n", + " os.system(cmd)\n", + " outtexts = []\n", + " with open(tf2.name) as f:\n", + " for line in f:\n", + " line = re.sub(r\"\\s+\", \" \", line).strip()\n", + " outtexts.append(line)\n", + " outtext = outtexts[0]\n", + " return outtext\n", + "\n", + " def get_text(self, text, hps):\n", + " text_norm = self.text_to_sequence(text, hps.data.text_cleaners)\n", + " if hps.data.add_blank:\n", + " text_norm = commons.intersperse(text_norm, 0)\n", + " text_norm = torch.LongTensor(text_norm)\n", + " return text_norm\n", + "\n", + " def filter_oov(self, text):\n", + " val_chars = self._symbol_to_id\n", + " txt_filt = \"\".join(list(filter(lambda x: x in val_chars, text)))\n", + " print(f\"text after filtering OOV: {txt_filt}\")\n", + " return txt_filt\n", + "\n", + "def preprocess_text(txt, text_mapper, hps, uroman_dir=None):\n", + " is_uroman = hps.data.training_files.split('.')[-1] == 'uroman'\n", + " if is_uroman:\n", + " with tempfile.TemporaryDirectory() as tmp_dir:\n", + " if uroman_dir is None:\n", + " cmd = f\"git clone git@github.com:isi-nlp/uroman.git {tmp_dir}\"\n", + " print(cmd)\n", + " subprocess.check_output(cmd, shell=True)\n", + " uroman_dir = tmp_dir\n", + " uroman_pl = os.path.join(uroman_dir, \"bin\", \"uroman.pl\")\n", + " print(f\"uromanize\")\n", + " txt = text_mapper.uromanize(txt, uroman_pl)\n", + " print(f\"uroman text: {txt}\")\n", + " txt = txt.lower()\n", + " txt = text_mapper.filter_oov(txt)\n", + " return txt\n", + "\n", + "if torch.cuda.is_available():\n", + " device = torch.device(\"cuda\")\n", + "else:\n", + " device = torch.device(\"cpu\")\n", + "\n", + "print(f\"Run inference with {device}\")\n", + "vocab_file = f\"{ckpt_dir}/vocab.txt\"\n", + "config_file = f\"{ckpt_dir}/config.json\"\n", + "assert os.path.isfile(config_file), f\"{config_file} doesn't exist\"\n", + "hps = utils.get_hparams_from_file(config_file)\n", + "text_mapper = TextMapper(vocab_file)\n", + "net_g = SynthesizerTrn(\n", + " len(text_mapper.symbols),\n", + " hps.data.filter_length // 2 + 1,\n", + " hps.train.segment_size // hps.data.hop_length,\n", + " **hps.model)\n", + "net_g.to(device)\n", + "_ = net_g.eval()\n", + "\n", + "g_pth = f\"{ckpt_dir}/G_100000.pth\"\n", + "print(f\"load {g_pth}\")\n", + "\n", + "_ = utils.load_checkpoint(g_pth, net_g, None)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "## 4. Generate an audio given text\n", + "Specify the sentence you want to synthesize and generate the audio" + ], + "metadata": { + "id": "fIiwaWl6SiVy" + } + }, + { + "cell_type": "code", + "source": [ + "txt = \"Expanding the language coverage of speech technology has the potential to improve access to information for many more people\"\n", + "print(f\"text: {txt}\")\n", + "txt = preprocess_text(txt, text_mapper, hps)\n", + "stn_tst = text_mapper.get_text(txt, hps)\n", + "with torch.no_grad():\n", + " x_tst = stn_tst.unsqueeze(0).to(device)\n", + " x_tst_lengths = torch.LongTensor([stn_tst.size(0)]).to(device)\n", + " hyp = net_g.infer(\n", + " x_tst, x_tst_lengths, noise_scale=.667,\n", + " noise_scale_w=0.8, length_scale=1.0\n", + " )[0][0,0].cpu().float().numpy()\n", + "\n", + "print(f\"Generated audio\") \n", + "Audio(hyp, rate=hps.data.sampling_rate)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 147 + }, + "id": "mpSvjfSCGBDm", + "outputId": "e9cd427f-7956-4d05-fba3-9cedc6fab175" + }, + "execution_count": 4, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "text: Expanding the language coverage of speech technology has the potential to improve access to information for many more people\n", + "text after filtering OOV: expanding the language coverage of speech technology has the potential to improve access to information for many more people\n", + "Generated audio\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "<IPython.lib.display.Audio object>" + ], + "text/html": [ + "\n", + " <audio controls=\"controls\" >\n", + " <source src=\"data:audio/wav;base64,UklGRiQEBABXQVZFZm10IBAAAAABAAEAgD4AAAB9AAACABAAZGF0YQAEBAABAAEAAAD+//7//P///////v/9//7/AAABAP///P/6//j//f8AAAMABAAEAAEA/f/+//////8AAAAAAwAEAAAA/f/8//3//v8AAAAAAgADAAEA///8//v//f///wAAAQADAAEAAAD///v/9v/1//7/AwAIAAsADgAKAAAA+v/8//v/AAAGAAsACgAGAAIA///+//7/AAADAAMABAAEAAEAAAAAAAIABAADAAEA///9//z/+v/5//r/+v/9////AQAAAAEABAAGAAYABwAJAAkAAQD8//3/AQAGAAMABAAJAA0ACwAFAAAA/v/7//X/8v/1//n/+P/0//L/8v/z//b/+v/+//7/+f/1//T/+v8AAAcABwAFAAcAAwAAAAAAAQADAAYABwAJAAgABAACAAAA/v///wIABQAIAAoABwADAAIAAQABAAMACQARABQAEQAJAAMAAgAGAAkABwABAP7//v/+/////v/+/wAAAQABAAAA/P/1//P/9f/4//v//f8AAAQAAgD8//r//f/8//j/9v/5//z/+f/y/+z/7v/x//L/9f/7/wIABQACAP7//P/6/wAABgAIAAsADAAJAAIA/f/9//3///8CAAgACwAMAAcAAQD+//3/+//8////BQAJAAgABAAAAPz/+f/7//3//f/7//n/+f/7/wIABwAGAAQABQADAAAA/v8AAAIAAgABAP7///8EAAQA///2//L/8v/5///////8//3///8AAAAA/v/4//X/9//9/wAA///4//j//P8CAAUAAgD9/////f///wEABAACAPz/+P/9/wUADAANAAYA///5//H/7v/w////DwAUAA8ABAD9//n/+v///wIACAAMAAcAAgD+//z//P/8/wAAAQAFAAwADwALAAQA/P/4//n/+v/5//n/+P/7/wAAAwABAAAAAAAAAP3//v8AAAEAAwAFAAQAAgABAAAA//8CAAEAAAAFABEAGAAQAAMA/f/8//7//v/+//3//f///////P/6//f/9v/5////AQD9//P/7f/w//f//v8BAAQAAwD9//j/9P/2//z/AwAFAAIA/v/7//f/9v/5/wAABQALAAoA///1//j/AAAAAAAACAAOABMAFgARAAIA+//8/wQADAAKAAIA/f/8//3///8DAAkACwACAPz//P/9//v/+/8AAAcAEAASAA4ACQAEAPz/+f/7//7////6//n/9//3//b/8P/w//L/9f/7////AAD7//T/8P/1//3/BwANAAwABwAAAPf/8f/2/wQAEgAWAA8ACAAEAAMAAAD7//r/AAAIAAkACAAGAAEA9//t/+3/9f8AAAcACAD///b/8P/v//j/DQAeAAwA7v/v/wIACQAHAAcABQADAAMAAAD8/wEAAAD3//P/+v8GAA0ACwAAAPf/+P/5//j/+v///////v8AAAIAAQAEAAMAAgABAAEAAAD9//3/AwAHAAkABwD///f/8//5/wAACAANAAYA/P/0//H/7v/w//n/BQAKAAIA/P/8//7/+//4//r/AQALAAwAAwD6//H/8v8BAA8AEgALAAQAAAD6//j/+v8EABIAEwAJAPz/9//5//v/+//7//v//P/9//z/+//8//z/+v8AAAYACAAKAP7/8v/2//3/AQAAAAAABQAHAAkABgAOABUADQD9//b/AAANABEACwADAP7/+v/5//7/AgD9//X/9f/9/wgADwANAAIA8//r//D///8HAAQA/P/3//r//v8AAAYACwAKAAcA///0//H/8f/y//L//f8AAPv//P/8//f/8f/x//j/AAAHAAkACQAHAAcAAwABAAcADgAPAAcA+v/2////DgATAAYA9v/z//v//v/7//7/BwANAAgABAAEAAYA/f/2//v/DAAYAA0AAQAFAAoAAQD2//D/9v/+/wkADgAJAAEA9//z//b/9v/6/wMABwABAPr/9P/x//P/+f///wAAAAAAAP7/9//1//r/BQALAAwADwASAAwA/f/0//v//v/9/wQAFAAVAAYA9f/r/+3/+f8KABQACQD5/+7/7f/3////AwAIAAwAEQAIAPz/8//x//n/BgATAA8AAwAAAP7//v8CAAQA/v/8/wQACgAGAPz/7v/o/+7/+f8FAAoAAQDz/+L/3//s/wEADgAOAAgABAD///r//P8BAAUABQAAAPz/9f/9/wsADAADAAAAAgD+/wAABQAEAAAA/v/7//n///8DAP7/8v/x//n/AAAJABEAFwAXAAcA8f/u//z/AgD+//f/AwATABIACAADAAAA8//p//f/DgARAAIA+f/4//r//f8BAAAAAAABAPv/+f8DAAwACQD///n/9v/7/wYAEAAJAPn/8v/0//n//f/7//z//f8AAAEAAwD+//H/6f/z/wQAEQATAA0AAADt/+n/8/8EABEADwAHAPj/7//t//T/AAALAAgAAwD9//D/6//z/wAAAgAGABIAEgAOAAoAAwD3//T//f8MABgADgD7//T/+/8BAAAAAgAGAAcA/f/y//H/+///////AwARAB4AFgAEAPv///8DAAIABQALAA8ABAD5/+//8P/4//b/+f/8/////f/5//P/8f/x//H/+f8CAAoABQD+//n/8v/s/+7/+v8RABwAGQAEAPv/AgALAAsAAwABAAgAEQAQAAgAAAD5//H/8v/4/wIADAANAAMA7//k/+r/9f8CABoAIgAAANX/4f8JABwAFAAKAP3/+v8BAAEA+//7//v/+P/9/wYADgAMAAEA9v/2//3//f/5//j/+//6//z/AAACAAIACAAIAAAA9P/1//v/AAACAAkADwAVABAAAAD1//j/BQAMAA4ADQAAAPD/6//z//f/+v///woABwD7//X/+P8AAAEAAAD//////v/4//f//P/5//3/EAAVAAYA9//x//f/AQAJAA0AEwAYAA0A/P/q/+r/9f8EAAkAAwD3/+3/7f/1/wIADQAKAAAA/P/3//f/AQD0/+X/8/8DAAkA///+/wEAAQAPAA0AFwAXAAoA+v/1/wkAGAAaAA8AAwAAAP3/+P/2//3//P/+/woAEwAOAAEA+f/4//D/6v/u//z/CQAIAAAA+/8CAAgABgAIAA0ADAAFAPb/5//o//H//P/+/wkAAwDu/+v/8P/w//D/9v8EAAoACQAEAAAAAAD/////BgAOAAsAAgD7//f/9//9/wcACAD8/+7/8v8AAAYABgAJAA4ACwD+//3/AwAJAP7/9f/7/xEAGQANAAIABAAOAAYA+//2//3/AQAIAA8ADAABAPP/8f/5//n/+f/+/wMABQAAAPT/6f/t/wAADAD+//P/+f8GAAEA9P/+/x0AIwAOAAYADgALAPT/5v///wwAAAADABUADADx/+f/8f/0//f/BAARAP3/5//j/+n/+v8QAB4AHAAIAPj/5//v/wQAEAAMAAcADQAEAAAAAAAFAA4ADQAOAAMA/f/8//3/9//x//L/8f/s//P/AwAHAO//4f/l/+3/+f8RACUAGAD2/+r/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8////wIA7P/L/7r/vf/c/+//DwAMAPT/5P/b/9j/AgApAFAAYQBQACwACAANADsAcwCHAHQAUwA/AE8AYABcADIAGwAnAEQAUQA1AB4AEwAVABIA9v/R/7f/zP/o//r/9P/h/7z/uP+f/6T/0f/Z/+v/2v/K/9L/4v/0/wMAAwAHAAwADgAYACAASgBWAF0ATABRAGUAeQB3AGgAcAB5AHMAXwBRAFEAWwBIADAAMQAfADAAJwAdABoA/v/5//j/+//s/+//AwAQAAAA2v/R/+z/9P/6/wwABgDv/9v/6f/4/xMAEgAKAPD/4//r/+P/BQASAAwAFwAGAOr/2v/u/wsAHAAbABEAGgAvABkA8v/I/9b/EwBJAGcAWwA2APn/uP/L/wIATABPACAA9f/V/9v/1P/K/8z/0f/Y/83/vf+w/5//jv+H/3z/ff+C/6b/vP+v/53/kf+F/57/rv+l/63/qv/F/9j/2//h/+b//P8GAP7/+f/6/wAADwAcACYAHAAqACMAHgASAAoAAgARABoACADh/9n/9//x/+3/7v/i/9b/sf/T/8j/rP/L/9T/2//S/8L/xv/H/8r/y//H/9L/5P/p//P/7v/z/+X/7P/w/wIAEwAaAA0AAAAJABEACwAIABUAKQAqABQABwASAB8AEAACAPn/+/8HAPr/8P/t//r/+P/5//P/+v/9//j/9f/4/xEAFwAGAAQABAAcACAAHwAaABcAIgAZAA4AFAAkADEAMAAwACsAHgAWAB0ALQAtACQAKgAsACQAIAAhACkALAAuAEAAQgA2ACAAHQAoADUANAA2AEEAKAApADMALAAgABoAIgAjABgABAAEAA8AFQAQAAYAAAAEAA0ABwD4//T/9v/3//j/+P/u/+f/6//z/wAA+//2/wAA9v/2/wkADgAkACoAEwAaABkAAgD9/xEAIwAlACAAJQAmABkAGAAiABcABwAFAAcAFgAMAAQA/f/u/xQACgD0/+n/3//l/+f/2v/c/+z/9//3/97/4P/6//b/AAABAO7/5v/x/wAA//8AAPL/9f/7/wwAEQD2//f/5P/X/93/0//W/+n/7//2/+T/6P/s/+//3f/S/97/7v/6/97/4P8NABEABAAAAOf/6//w//n/AAANABMACwAMAAAA9v8BAPz/AAAIAAoA9v/+//v/AADd/9z/5//S/97/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5//Z//b/6v+4/8z/2f/e/93/4v/q//b/6v/o/+//9v/6//r/+v8LAB4AIAAQAAAADwATAAcAEwAeAC8AJAD5//H/AgAhABgA8f/w/wUAFAD//+T/6v/+//f/3v/i/+n/7//3//X/4v/f/+b/7f/x/+f/w//f//D/AgDk/9f/6//1//f/6f/U/9v/9//s//P/8v/x/+P/8v/0/+3/5//r//D/7v/2//H/5f/t/wMA9f/8//3/AAABAOr/DgAjAAMACgADABIAJwASAAoADgAVABQACQAIAA8AEAAUAA0ABgD3//7/AQAJAAcA/f/5/wAAEQAUAAIA/P8FABQAFQABAPH/9/8MAAgA+//u//n/DwAFAOr/9f8KAAMAAwDx/+3/AAAHAP3/7//9/xIAAAD3////DgARAPf/+P/t/wUACgD7/////P8IAAcAAQD3//v/+f/6////+//1/wAABgD7//D/+P8OAA0AAAADABEAEwAJAAMABwAVABwAFwAkAAgACwApABwADAAAAAwAFQAOAAYAFAAkACAADQADAAYABQAGAP3/9f/8////9v/u/+//+//3//f/9P/4//f/9/8AAPn/+f/3/+3/8v/4//P/7v/y//j/+P8AAP///f/4//v////6//n/BAACAPn/+//9/wIA//8KAAYA/f8IABMACQD+//3//f8EAPv/9v/z//n/+v/7//n/AAAAAAMAAAD2//P/8v/6//L//f/5//7/AgAIAAwA+//3/+//7f/5//v/+P/8//r/AAAAAAEA+v/+//j/8//1//3//v/0//3/AQD0//L/+//9//3/9P/3/wEACAD///X//v8DAPr/+//+/wYABwAEAAQA/v8EAP7/+////wcABQAHAP7/BAAPABUABQD2/wAABgAQAAsAAQADAAkA/f8HABMAFQAAAP7//v8HAAoA//8DAP3/AgACAAwA+//6/wIAAwD9////AAAAAAMA/f/8//7//f8BAAoACQAAAPf/9//2//7/BQD8//r//v/+//f/AAD8/wAAAAAAAAEACQAWAAcACQAPAA4ACgARAAoABAAOAAQACgAOAAkADAD+/woABAD+/wQA/f8DAAAA+v/+//z/BgAWAAsABwAIAAsAFAAdABMAFgAQAAwAEwAHABcAHQAQAAcADQAZABkABwDx//7/CwDw//j/+f/q/+P/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egB5AHsAdgBqAFUARwBAAD0AQABCAE0ASgBEAEYATQBKADMAHgAMAAUABQAJAAgAAQD0/+f/2f/V/9r/4P/g/9z/2f/a/+D/8P/v/+f/4//e/93/4f/o//L/9f/2//f/9f/z//f/+v/5//H/8P/1/wAAAgAIAA8AFQAUABYAGQAeAB4AIAAiACkALQAwADgAOgA/AEUARQBCADUALgAfABYADwALAAwABgACAAkAFQAhACEAGwAYABoAGQAUAA0ABQD///z/+P/y/+n/6f/q//P//v8AAP7/+//z/+v/5//h/+H/3v/S/8v/yf+9/7X/tv+3/7r/u//C/8H/w//K/73/u/++/77/v//L/9b/3//u//r//////wQABwAIAAYAAwAFAAgADAAVABkAIQAkACUAJAAlACMAHgAUAA4ABQAAAPv/8//x/+v/5P/o/+j/5v/l/+j/5v/m/+j/5//q/+j/6f/n/9//3P/a/9r/3f/h/+P/6f/w//H/7//t/+3/7v/t//D/8P/0//P/8//0//X/8//4//v/AgAJAAwAFwAaABwAHgAcABkAEgAVABEAGAAgACcAKQAqAC0AMwAwAC4AKwAkABwAEwASABQAFAAWAA8ADQAKAAIA///4//b/9//4//v/+f/6//r/+f/z//H/7//y//b/+v/9/wAAAAAAAAAAAgACAAIAAAD//wIABQADAAEAAAAEAAIA///9//7/AAAGAAYACwAOAA8ADgAOABIAGQAcAB0AGwAaABYAFAAVABMAEQAVABAAEwAQABAAEQAVABYAFAAUABYAFgAXABcAFAAOAAsACQAHAAIAAQAAAP///P/7//j/+//6//r/9//2//P/8f/y/+//8f/x//X/+f/6/wEA//8EAAQABgAFAAQACAAKAAkACgALAA0ADQANAA0ADgALAAkABgADAP7//P/8//z/+v/9//z//P/7//n/9f/z//H/9P/0//T/9f/2//P/8//3//f/9v/2//f/+P/y//T/7f/r/+3/5v/k/+T/4//j/+X/5f/l/+f/6P/q/+j/6//s/+7/7//x//P/9P/3//r/+P/5//j/9//1//b/9f/0//T/9v/2//r/+//8//3//f/8/////f/9//7////////////9//z/+v/6//n/9v/2//j/+//8//7//v8AAAEAAQABAAEAAAD+//7//f/8//3//P/8//3/AAD//wAAAAACAAIAAAABAAAA/v/9//z//f/9/wEAAgAGAAgACgAKAAoACgAMAAoACQAIAAgACgAKAAsADQAMAAsABwAGAAcACAAJAAkACQAJAAkACAADAAIAAQAAAP7///8AAAIAAwADAAQABAACAAAAAAD///3//f/+//7/AAABAAMAAgAAAAEAAgAEAAQABgAIAAkABgAIAAoACwALAAkACAAIAAYAAgAAAP7///8AAAAAAQADAAIAAAAFAAIAAgABAAEAAwABAAIAAgABAAAAAQAAAP///v8AAAAAAAD//wAAAgACAAIAAwADAAIAAgAAAAAAAAD9//7//P/7//v/+f/6//j/+f/5//j/+f/6//v//f/+/wAAAQACAAIABAAFAAYABwAHAAcABwAHAAgACAAHAAcACAAGAAcACAAHAAUAAwAFAAQABAAEAAMABAADAAIAAQAAAAIAAgAAAAAAAAAAAAAAAAD+//3//f/+//7//v/+//3//P/6//r/+v/7//3//f/9//z//P/8//z//P/8//v/+//8//z//P/7//v/+//8//z//P/7//v//P/7//v/+//6//r/+//7//7////+/////////////v/9//z//f/8//3//v////////8AAAAAAQABAAAAAAAAAP3//f/9//z//P/8//3//f/+/wAAAAAAAAEAAQAAAAAAAAD//////v////7///////////////7//f/+//7//v/+//7///8AAAAAAAAAAAAAAAD+//7/AAD+//////8AAAAAAAAAAAAA//8AAAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAEAAQAAAAAA/////wAAAAAAAAAAAAAAAAEAAQABAAEAAgACAAEAAgADAAMAAgADAAMAAwADAAEAAQABAAEAAQABAAEAAgACAAEAAQABAAEAAQACAAEAAQABAAIAAgACAAEAAgACAAMAAwADAAIAAwADAAMAAgABAAIAAgACAAEAAAAAAAAAAAAAAP///v/+/////v////////8AAAAA//8AAAAAAAAAAAAAAQABAAIAAgACAAIAAgACAAIAAwADAAMAAgACAAIAAgACAAEAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP///v/+//7//v////7//v/+//3//f/9//3//f/9//3//v/9//3//f/9//7//v/+//7//v/+//3//v/+//7//v/+//7//f/9//7//f/+//7//v/+/////////////f/+//7//f/+//7//v//////AAAAAAAAAAAAAAAAAAD///7//v/+//3//v/+//7//v///wAAAAAAAAAAAAD///////////////////7//v/+/////v/////////+/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAQAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAQAAAAAAAAAAAAAAAAABAAIAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAgABAAEAAQACAAIAAgABAAIAAQACAAEAAQAAAAEAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAEAAQABAAEAAQABAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////wAA//////////8AAAAAAAD//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAQABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAAAAAAD//////////////////////////wAAAAAAAAAAAAAAAAAAAAD///////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAA==\" type=\"audio/wav\" />\n", + " Your browser does not support the audio element.\n", + " </audio>\n", + " " + ] + }, + "metadata": {}, + "execution_count": 4 + } + ] + } + ], + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file From 533644c3fb0e74c6c8aa3c1db663478bc3957bb2 Mon Sep 17 00:00:00 2001 From: chevalierNoir <bshi@fb.com> Date: Tue, 30 May 2023 11:05:01 -0700 Subject: [PATCH 752/774] MMS TTS Romanian char fix + MPS support + full checkpoint (#5168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix ț filtering in Romanian at inference * mps support + full checkpoints (discriminator+optimizer) --------- Co-authored-by: Bowen Shi <bshi@meta.com> --- examples/mms/README.md | 6 ++ examples/mms/tts/infer.py | 19 ++++++- .../tutorial/MMS_TTS_Inference_Colab.ipynb | 56 +++++++++++-------- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/examples/mms/README.md b/examples/mms/README.md index a7a1e98bfa..fa0377c2a3 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -25,6 +25,12 @@ MMS-1B-all| 1162 | MMS-lab + FLEURS <br>+ CV + VP + MLS | [download](https://dl wget https://dl.fbaipublicfiles.com/mms/tts/eng.tar.gz # English (eng) wget https://dl.fbaipublicfiles.com/mms/tts/azj-script_latin.tar.gz # North Azerbaijani (azj-script_latin) ``` +The above command downloads generator only, which is enough to run TTS inference. If you want the full model checkpoint which also includes the discriminator (`D_100000.pth`) and the optimizer states, download as follows. +``` +# Example (full checkpoint: generator + discriminator + optimizer): +wget https://dl.fbaipublicfiles.com/mms/tts/full_model/eng.tar.gz # English (eng) +``` + ### LID diff --git a/examples/mms/tts/infer.py b/examples/mms/tts/infer.py index a59fac2a62..d4f09cefc0 100644 --- a/examples/mms/tts/infer.py +++ b/examples/mms/tts/infer.py @@ -69,23 +69,36 @@ def get_text(self, text, hps): text_norm = torch.LongTensor(text_norm) return text_norm - def filter_oov(self, text): + def filter_oov(self, text, lang=None): + text = self.preprocess_char(text, lang=lang) val_chars = self._symbol_to_id txt_filt = "".join(list(filter(lambda x: x in val_chars, text))) print(f"text after filtering OOV: {txt_filt}") return txt_filt + def preprocess_char(self, text, lang=None): + """ + Special treatement of characters in certain languages + """ + if lang == "ron": + text = text.replace("ț", "ţ") + print(f"{lang} (ț -> ţ): {text}") + return text + def generate(): parser = argparse.ArgumentParser(description='TTS inference') parser.add_argument('--model-dir', type=str, help='model checkpoint dir') parser.add_argument('--wav', type=str, help='output wav path') parser.add_argument('--txt', type=str, help='input text') - parser.add_argument('--uroman-dir', type=str, help='uroman lib dir (will download if not specified)') + parser.add_argument('--uroman-dir', type=str, default=None, help='uroman lib dir (will download if not specified)') + parser.add_argument('--lang', type=str, default=None, help='language iso code (required for Romanian)') args = parser.parse_args() ckpt_dir, wav_path, txt = args.model_dir, args.wav, args.txt if torch.cuda.is_available(): device = torch.device("cuda") + elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available() and torch.backends.mps.is_built(): + device = torch.device("mps") else: device = torch.device("cpu") @@ -122,7 +135,7 @@ def generate(): txt = text_mapper.uromanize(txt, uroman_pl) print(f"uroman text: {txt}") txt = txt.lower() - txt = text_mapper.filter_oov(txt) + txt = text_mapper.filter_oov(txt, lang=args.lang) stn_tst = text_mapper.get_text(txt, hps) with torch.no_grad(): x_tst = stn_tst.unsqueeze(0).to(device) diff --git a/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb b/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb index 32c9a71996..22b7f815be 100644 --- a/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb +++ b/examples/mms/tts/tutorial/MMS_TTS_Inference_Colab.ipynb @@ -31,7 +31,7 @@ "base_uri": "https://localhost:8080/", "height": 1000 }, - "outputId": "695170f4-8083-4f57-fcc1-78252e40c0f4" + "outputId": "9825fea8-d247-48d9-b33b-dbff36e905fa" }, "outputs": [ { @@ -41,13 +41,13 @@ "Cloning into 'vits'...\n", "remote: Enumerating objects: 81, done.\u001b[K\n", "remote: Total 81 (delta 0), reused 0 (delta 0), pack-reused 81\u001b[K\n", - "Unpacking objects: 100% (81/81), 3.33 MiB | 3.72 MiB/s, done.\n", + "Unpacking objects: 100% (81/81), 3.33 MiB | 2.44 MiB/s, done.\n", "Python 3.10.11\n", "/content/vits\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", "Collecting Cython==0.29.21\n", " Downloading Cython-0.29.21-py2.py3-none-any.whl (974 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m974.2/974.2 kB\u001b[0m \u001b[31m49.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m974.2/974.2 kB\u001b[0m \u001b[31m27.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hInstalling collected packages: Cython\n", " Attempting uninstall: Cython\n", " Found existing installation: Cython 0.29.34\n", @@ -57,7 +57,7 @@ "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", "Collecting librosa==0.8.0\n", " Downloading librosa-0.8.0.tar.gz (183 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m183.9/183.9 kB\u001b[0m \u001b[31m12.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m183.9/183.9 kB\u001b[0m \u001b[31m15.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", "Requirement already satisfied: audioread>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (3.0.0)\n", "Requirement already satisfied: numpy>=1.15.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (1.22.4)\n", @@ -67,7 +67,7 @@ "Requirement already satisfied: decorator>=3.0.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (4.4.2)\n", "Collecting resampy>=0.2.2 (from librosa==0.8.0)\n", " Downloading resampy-0.4.2-py3-none-any.whl (3.1 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.1/3.1 MB\u001b[0m \u001b[31m103.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.1/3.1 MB\u001b[0m \u001b[31m101.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: numba>=0.43.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (0.56.4)\n", "Requirement already satisfied: soundfile>=0.9.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (0.12.1)\n", "Requirement already satisfied: pooch>=1.0 in /usr/local/lib/python3.10/dist-packages (from librosa==0.8.0) (1.6.0)\n", @@ -85,7 +85,7 @@ "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.0->librosa==0.8.0) (3.4)\n", "Building wheels for collected packages: librosa\n", " Building wheel for librosa (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for librosa: filename=librosa-0.8.0-py3-none-any.whl size=201378 sha256=fa582ff086e0ed1d87d99596e59f3e8a42adbd67480b5b523c0d992b0349699c\n", + " Created wheel for librosa: filename=librosa-0.8.0-py3-none-any.whl size=201378 sha256=c299b7ae3d6d527a4889716009ab27ca4018546d04f0e4de1019ea919311c0dc\n", " Stored in directory: /root/.cache/pip/wheels/bf/b7/85/2f8044306ccec014930aea23ad4852fca9e2584e21c6972bc6\n", "Successfully built librosa\n", "Installing collected packages: resampy, librosa\n", @@ -97,17 +97,17 @@ "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", "Collecting phonemizer==2.2.1\n", " Downloading phonemizer-2.2.1-py3-none-any.whl (49 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.0/49.0 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.0/49.0 kB\u001b[0m \u001b[31m6.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: joblib in /usr/local/lib/python3.10/dist-packages (from phonemizer==2.2.1) (1.2.0)\n", "Collecting segments (from phonemizer==2.2.1)\n", " Downloading segments-2.2.1-py2.py3-none-any.whl (15 kB)\n", "Requirement already satisfied: attrs>=18.1 in /usr/local/lib/python3.10/dist-packages (from phonemizer==2.2.1) (23.1.0)\n", "Collecting clldutils>=1.7.3 (from segments->phonemizer==2.2.1)\n", " Downloading clldutils-3.19.0-py2.py3-none-any.whl (1.7 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.7/1.7 MB\u001b[0m \u001b[31m68.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.7/1.7 MB\u001b[0m \u001b[31m84.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting csvw>=1.5.6 (from segments->phonemizer==2.2.1)\n", " Downloading csvw-3.1.3-py2.py3-none-any.whl (56 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m56.7/56.7 kB\u001b[0m \u001b[31m7.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m56.7/56.7 kB\u001b[0m \u001b[31m9.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: regex in /usr/local/lib/python3.10/dist-packages (from segments->phonemizer==2.2.1) (2022.10.31)\n", "Requirement already satisfied: python-dateutil in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (2.8.2)\n", "Requirement already satisfied: tabulate>=0.7.7 in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (0.8.10)\n", @@ -115,7 +115,7 @@ " Downloading colorlog-6.7.0-py2.py3-none-any.whl (11 kB)\n", "Collecting pylatexenc (from clldutils>=1.7.3->segments->phonemizer==2.2.1)\n", " Downloading pylatexenc-2.10.tar.gz (162 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m162.6/162.6 kB\u001b[0m \u001b[31m23.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m162.6/162.6 kB\u001b[0m \u001b[31m24.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", "Requirement already satisfied: markdown in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (3.4.3)\n", "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from clldutils>=1.7.3->segments->phonemizer==2.2.1) (4.9.2)\n", @@ -125,14 +125,14 @@ " Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n", "Collecting isodate (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", " Downloading isodate-0.6.1-py2.py3-none-any.whl (41 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.7/41.7 kB\u001b[0m \u001b[31m6.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.7/41.7 kB\u001b[0m \u001b[31m6.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: jsonschema in /usr/local/lib/python3.10/dist-packages (from csvw>=1.5.6->segments->phonemizer==2.2.1) (4.3.3)\n", "Collecting language-tags (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", " Downloading language_tags-1.2.0-py3-none-any.whl (213 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m213.4/213.4 kB\u001b[0m \u001b[31m29.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m213.4/213.4 kB\u001b[0m \u001b[31m29.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting rdflib (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", " Downloading rdflib-6.3.2-py3-none-any.whl (528 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m528.1/528.1 kB\u001b[0m \u001b[31m60.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m528.1/528.1 kB\u001b[0m \u001b[31m57.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from csvw>=1.5.6->segments->phonemizer==2.2.1) (2.27.1)\n", "Collecting rfc3986<2 (from csvw>=1.5.6->segments->phonemizer==2.2.1)\n", " Downloading rfc3986-1.5.0-py2.py3-none-any.whl (31 kB)\n", @@ -146,7 +146,7 @@ "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->csvw>=1.5.6->segments->phonemizer==2.2.1) (3.4)\n", "Building wheels for collected packages: pylatexenc\n", " Building wheel for pylatexenc (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for pylatexenc: filename=pylatexenc-2.10-py3-none-any.whl size=136820 sha256=b88aa9b5f5a021b6d7f72b330dcb61d0d5e7f90fc4ebca8f53cc19183b6e64dc\n", + " Created wheel for pylatexenc: filename=pylatexenc-2.10-py3-none-any.whl size=136820 sha256=e99eecd0f55e1827ac73565fc43f5565f432aca243434ea921e0a31c5827331d\n", " Stored in directory: /root/.cache/pip/wheels/d3/31/8b/e09b0386afd80cfc556c00408c9aeea5c35c4d484a9c762fd5\n", "Successfully built pylatexenc\n", "Installing collected packages: rfc3986, pylatexenc, language-tags, isodate, colorlog, colorama, rdflib, clldutils, csvw, segments, phonemizer\n", @@ -203,7 +203,7 @@ "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", "Collecting Unidecode==1.1.1\n", " Downloading Unidecode-1.1.1-py2.py3-none-any.whl (238 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m238.3/238.3 kB\u001b[0m \u001b[31m25.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m238.3/238.3 kB\u001b[0m \u001b[31m18.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hInstalling collected packages: Unidecode\n", "Successfully installed Unidecode-1.1.1\n", "/content/vits/monotonic_align\n", @@ -278,7 +278,7 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "70c5e4ef-24ad-4aac-93c6-b7e022eafc49" + "outputId": "2adfb7eb-b9a2-44c3-8571-72fbc4b60aff" }, "outputs": [ { @@ -328,7 +328,7 @@ "colab": { "base_uri": "https://localhost:8080/" }, - "outputId": "491e8103-03db-48e8-d388-9c4482a3f059" + "outputId": "24710ada-6f04-4f29-c5f2-000458784ed8" }, "outputs": [ { @@ -361,6 +361,15 @@ "from models import SynthesizerTrn\n", "from scipy.io.wavfile import write\n", "\n", + "def preprocess_char(text, lang=None):\n", + " \"\"\"\n", + " Special treatement of characters in certain languages\n", + " \"\"\"\n", + " print(lang)\n", + " if lang == 'ron':\n", + " text = text.replace(\"ț\", \"ţ\")\n", + " return text\n", + "\n", "class TextMapper(object):\n", " def __init__(self, vocab_file):\n", " self.symbols = [x.replace(\"\\n\", \"\") for x in open(vocab_file, encoding=\"utf-8\").readlines()]\n", @@ -414,7 +423,8 @@ " print(f\"text after filtering OOV: {txt_filt}\")\n", " return txt_filt\n", "\n", - "def preprocess_text(txt, text_mapper, hps, uroman_dir=None):\n", + "def preprocess_text(txt, text_mapper, hps, uroman_dir=None, lang=None):\n", + " txt = preprocess_char(txt, lang=lang)\n", " is_uroman = hps.data.training_files.split('.')[-1] == 'uroman'\n", " if is_uroman:\n", " with tempfile.TemporaryDirectory() as tmp_dir:\n", @@ -470,8 +480,9 @@ "cell_type": "code", "source": [ "txt = \"Expanding the language coverage of speech technology has the potential to improve access to information for many more people\"\n", + "\n", "print(f\"text: {txt}\")\n", - "txt = preprocess_text(txt, text_mapper, hps)\n", + "txt = preprocess_text(txt, text_mapper, hps, lang=LANG)\n", "stn_tst = text_mapper.get_text(txt, hps)\n", "with torch.no_grad():\n", " x_tst = stn_tst.unsqueeze(0).to(device)\n", @@ -487,10 +498,10 @@ "metadata": { "colab": { "base_uri": "https://localhost:8080/", - "height": 147 + "height": 165 }, "id": "mpSvjfSCGBDm", - "outputId": "e9cd427f-7956-4d05-fba3-9cedc6fab175" + "outputId": "142581f8-e9ec-4d17-d4da-413176e3cee3" }, "execution_count": 4, "outputs": [ @@ -499,6 +510,7 @@ "name": "stdout", "text": [ "text: Expanding the language coverage of speech technology has the potential to improve access to information for many more people\n", + "eng\n", "text after filtering OOV: expanding the language coverage of speech technology has the potential to improve access to information for many more people\n", "Generated audio\n" ] @@ -512,7 +524,7 @@ "text/html": [ "\n", " <audio controls=\"controls\" >\n", - " <source src=\"data:audio/wav;base64,UklGRiQEBABXQVZFZm10IBAAAAABAAEAgD4AAAB9AAACABAAZGF0YQAEBAABAAEAAAD+//7//P///////v/9//7/AAABAP///P/6//j//f8AAAMABAAEAAEA/f/+//////8AAAAAAwAEAAAA/f/8//3//v8AAAAAAgADAAEA///8//v//f///wAAAQADAAEAAAD///v/9v/1//7/AwAIAAsADgAKAAAA+v/8//v/AAAGAAsACgAGAAIA///+//7/AAADAAMABAAEAAEAAAAAAAIABAADAAEA///9//z/+v/5//r/+v/9////AQAAAAEABAAGAAYABwAJAAkAAQD8//3/AQAGAAMABAAJAA0ACwAFAAAA/v/7//X/8v/1//n/+P/0//L/8v/z//b/+v/+//7/+f/1//T/+v8AAAcABwAFAAcAAwAAAAAAAQADAAYABwAJAAgABAACAAAA/v///wIABQAIAAoABwADAAIAAQABAAMACQARABQAEQAJAAMAAgAGAAkABwABAP7//v/+/////v/+/wAAAQABAAAA/P/1//P/9f/4//v//f8AAAQAAgD8//r//f/8//j/9v/5//z/+f/y/+z/7v/x//L/9f/7/wIABQACAP7//P/6/wAABgAIAAsADAAJAAIA/f/9//3///8CAAgACwAMAAcAAQD+//3/+//8////BQAJAAgABAAAAPz/+f/7//3//f/7//n/+f/7/wIABwAGAAQABQADAAAA/v8AAAIAAgABAP7///8EAAQA///2//L/8v/5///////8//3///8AAAAA/v/4//X/9//9/wAA///4//j//P8CAAUAAgD9/////f///wEABAACAPz/+P/9/wUADAANAAYA///5//H/7v/w////DwAUAA8ABAD9//n/+v///wIACAAMAAcAAgD+//z//P/8/wAAAQAFAAwADwALAAQA/P/4//n/+v/5//n/+P/7/wAAAwABAAAAAAAAAP3//v8AAAEAAwAFAAQAAgABAAAA//8CAAEAAAAFABEAGAAQAAMA/f/8//7//v/+//3//f///////P/6//f/9v/5////AQD9//P/7f/w//f//v8BAAQAAwD9//j/9P/2//z/AwAFAAIA/v/7//f/9v/5/wAABQALAAoA///1//j/AAAAAAAACAAOABMAFgARAAIA+//8/wQADAAKAAIA/f/8//3///8DAAkACwACAPz//P/9//v/+/8AAAcAEAASAA4ACQAEAPz/+f/7//7////6//n/9//3//b/8P/w//L/9f/7////AAD7//T/8P/1//3/BwANAAwABwAAAPf/8f/2/wQAEgAWAA8ACAAEAAMAAAD7//r/AAAIAAkACAAGAAEA9//t/+3/9f8AAAcACAD///b/8P/v//j/DQAeAAwA7v/v/wIACQAHAAcABQADAAMAAAD8/wEAAAD3//P/+v8GAA0ACwAAAPf/+P/5//j/+v///////v8AAAIAAQAEAAMAAgABAAEAAAD9//3/AwAHAAkABwD///f/8//5/wAACAANAAYA/P/0//H/7v/w//n/BQAKAAIA/P/8//7/+//4//r/AQALAAwAAwD6//H/8v8BAA8AEgALAAQAAAD6//j/+v8EABIAEwAJAPz/9//5//v/+//7//v//P/9//z/+//8//z/+v8AAAYACAAKAP7/8v/2//3/AQAAAAAABQAHAAkABgAOABUADQD9//b/AAANABEACwADAP7/+v/5//7/AgD9//X/9f/9/wgADwANAAIA8//r//D///8HAAQA/P/3//r//v8AAAYACwAKAAcA///0//H/8f/y//L//f8AAPv//P/8//f/8f/x//j/AAAHAAkACQAHAAcAAwABAAcADgAPAAcA+v/2////DgATAAYA9v/z//v//v/7//7/BwANAAgABAAEAAYA/f/2//v/DAAYAA0AAQAFAAoAAQD2//D/9v/+/wkADgAJAAEA9//z//b/9v/6/wMABwABAPr/9P/x//P/+f///wAAAAAAAP7/9//1//r/BQALAAwADwASAAwA/f/0//v//v/9/wQAFAAVAAYA9f/r/+3/+f8KABQACQD5/+7/7f/3////AwAIAAwAEQAIAPz/8//x//n/BgATAA8AAwAAAP7//v8CAAQA/v/8/wQACgAGAPz/7v/o/+7/+f8FAAoAAQDz/+L/3//s/wEADgAOAAgABAD///r//P8BAAUABQAAAPz/9f/9/wsADAADAAAAAgD+/wAABQAEAAAA/v/7//n///8DAP7/8v/x//n/AAAJABEAFwAXAAcA8f/u//z/AgD+//f/AwATABIACAADAAAA8//p//f/DgARAAIA+f/4//r//f8BAAAAAAABAPv/+f8DAAwACQD///n/9v/7/wYAEAAJAPn/8v/0//n//f/7//z//f8AAAEAAwD+//H/6f/z/wQAEQATAA0AAADt/+n/8/8EABEADwAHAPj/7//t//T/AAALAAgAAwD9//D/6//z/wAAAgAGABIAEgAOAAoAAwD3//T//f8MABgADgD7//T/+/8BAAAAAgAGAAcA/f/y//H/+///////AwARAB4AFgAEAPv///8DAAIABQALAA8ABAD5/+//8P/4//b/+f/8/////f/5//P/8f/x//H/+f8CAAoABQD+//n/8v/s/+7/+v8RABwAGQAEAPv/AgALAAsAAwABAAgAEQAQAAgAAAD5//H/8v/4/wIADAANAAMA7//k/+r/9f8CABoAIgAAANX/4f8JABwAFAAKAP3/+v8BAAEA+//7//v/+P/9/wYADgAMAAEA9v/2//3//f/5//j/+//6//z/AAACAAIACAAIAAAA9P/1//v/AAACAAkADwAVABAAAAD1//j/BQAMAA4ADQAAAPD/6//z//f/+v///woABwD7//X/+P8AAAEAAAD//////v/4//f//P/5//3/EAAVAAYA9//x//f/AQAJAA0AEwAYAA0A/P/q/+r/9f8EAAkAAwD3/+3/7f/1/wIADQAKAAAA/P/3//f/AQD0/+X/8/8DAAkA///+/wEAAQAPAA0AFwAXAAoA+v/1/wkAGAAaAA8AAwAAAP3/+P/2//3//P/+/woAEwAOAAEA+f/4//D/6v/u//z/CQAIAAAA+/8CAAgABgAIAA0ADAAFAPb/5//o//H//P/+/wkAAwDu/+v/8P/w//D/9v8EAAoACQAEAAAAAAD/////BgAOAAsAAgD7//f/9//9/wcACAD8/+7/8v8AAAYABgAJAA4ACwD+//3/AwAJAP7/9f/7/xEAGQANAAIABAAOAAYA+//2//3/AQAIAA8ADAABAPP/8f/5//n/+f/+/wMABQAAAPT/6f/t/wAADAD+//P/+f8GAAEA9P/+/x0AIwAOAAYADgALAPT/5v///wwAAAADABUADADx/+f/8f/0//f/BAARAP3/5//j/+n/+v8QAB4AHAAIAPj/5//v/wQAEAAMAAcADQAEAAAAAAAFAA4ADQAOAAMA/f/8//3/9//x//L/8f/s//P/AwAHAO//4f/l/+3/+f8RACUAGAD2/+r/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8////wIA7P/L/7r/vf/c/+//DwAMAPT/5P/b/9j/AgApAFAAYQBQACwACAANADsAcwCHAHQAUwA/AE8AYABcADIAGwAnAEQAUQA1AB4AEwAVABIA9v/R/7f/zP/o//r/9P/h/7z/uP+f/6T/0f/Z/+v/2v/K/9L/4v/0/wMAAwAHAAwADgAYACAASgBWAF0ATABRAGUAeQB3AGgAcAB5AHMAXwBRAFEAWwBIADAAMQAfADAAJwAdABoA/v/5//j/+//s/+//AwAQAAAA2v/R/+z/9P/6/wwABgDv/9v/6f/4/xMAEgAKAPD/4//r/+P/BQASAAwAFwAGAOr/2v/u/wsAHAAbABEAGgAvABkA8v/I/9b/EwBJAGcAWwA2APn/uP/L/wIATABPACAA9f/V/9v/1P/K/8z/0f/Y/83/vf+w/5//jv+H/3z/ff+C/6b/vP+v/53/kf+F/57/rv+l/63/qv/F/9j/2//h/+b//P8GAP7/+f/6/wAADwAcACYAHAAqACMAHgASAAoAAgARABoACADh/9n/9//x/+3/7v/i/9b/sf/T/8j/rP/L/9T/2//S/8L/xv/H/8r/y//H/9L/5P/p//P/7v/z/+X/7P/w/wIAEwAaAA0AAAAJABEACwAIABUAKQAqABQABwASAB8AEAACAPn/+/8HAPr/8P/t//r/+P/5//P/+v/9//j/9f/4/xEAFwAGAAQABAAcACAAHwAaABcAIgAZAA4AFAAkADEAMAAwACsAHgAWAB0ALQAtACQAKgAsACQAIAAhACkALAAuAEAAQgA2ACAAHQAoADUANAA2AEEAKAApADMALAAgABoAIgAjABgABAAEAA8AFQAQAAYAAAAEAA0ABwD4//T/9v/3//j/+P/u/+f/6//z/wAA+//2/wAA9v/2/wkADgAkACoAEwAaABkAAgD9/xEAIwAlACAAJQAmABkAGAAiABcABwAFAAcAFgAMAAQA/f/u/xQACgD0/+n/3//l/+f/2v/c/+z/9//3/97/4P/6//b/AAABAO7/5v/x/wAA//8AAPL/9f/7/wwAEQD2//f/5P/X/93/0//W/+n/7//2/+T/6P/s/+//3f/S/97/7v/6/97/4P8NABEABAAAAOf/6//w//n/AAANABMACwAMAAAA9v8BAPz/AAAIAAoA9v/+//v/AADd/9z/5//S/97/zv/k/+f//f/u/8r/qv+t/7H/tf/O/9X/6P/0/+b/4P/N/87/4P/O/8b/0v/N/+P/0//T/9j/3v/S/87/yf/X/9n/y/++/7r/u//S/9f/z//L/9f/1v/P/9n/6v/3/9r/2f/l/97/7f/j/+v/9v/7//r/9v/w/+7/AAD+//f/+f8DAAcACwAEAAEACAAUAAQA5v/s/wsACgD7/wMAFAANAAAAAwAEAAMAAgD8/wAABgARABIAFQAEAA0AEQAbABAACAA3AFYAVgBNADgAPABDACMANwBTAFoAWQBlAFsATQBQAE8ASgAlAAoADgAYACgAKwAiACQAHAARAAoAAQAJABEAHwAiABcAGgA3AEMAIwAkADsAQwAjACEAGgAuACwADAAfACsAJwA+AEkAPwAmAAkAEQAZAAQAAwATACQADQAWABEAAADy//H/DAD5/wYA/f8TAAgA+v/8/wAAEwAMAAUABQAZAB4AEgAHAAsAJQAZAAIA9P/6//r//f/y/+n/4//j/9v/zv/U/8j/xv/E/8f/x//g/+v/1v+7/9P/0v+7/8//2f/c/8z/xP+x/6r/rf/K/93/2v8EAOn/+v/x/9L/AQDN/6j/wP///xcADQBkAEgAsP/P/+v/CgD1/z0AfABHAFUA+/8CAMb/kv8RADEBOwJbAswA9P4h/jf+Vv/7/+cAWAIMAxsC5//o/ev8xvzw/BX+kf/zAKoBNAEwABz/of6I/t3+mP8lAPn/wv9S/2L/8P8AANb/DQB3AJYAVQBBAE8AKQDl/9H/y////zQARwA6AGsAMAAZANj/sP+w/2z/lf8RAGcAGgDk//n/sP/N/sb+rf4p/5P//P8dAF8AcgAJADEAav/M//T/uP/M/wMA1P8QACoCZgQeBJUAIf5y/XP+MP+t/9IAegJ3ApAAeP+z/13/0f47/44A3AFGAkgBXv9D/X78if3m/psBdAKPAtoAI/6A/Br6ufr2+1D+nwCdAIEBpgBk/2f+V/2d/nf/ogDgAekCFQPCAVAAYv/O/0oAKAG5AR4CFALyASwBQAAi/2X+UP6m/lf/xf80AZACGgPrApYBd/+i/tj93P1k/j0AaQGDAXABCQErAA3/zv87ADQBwwEKA28DZAKfADz/nP7g/Z/9nf4wADMBlAEqAWIA+P5g/ur99v0X/tb+V/9B/8f/0v8nAPb/BgA8AEcAtADrAGABswHwAfgBpAEmAZkA8P8//9/+8/47/3MAbwGMAXIBxQDF/8n+4f2y/dn9l/6O/xIAhwCnABQARf/5/iD/uP/m/1cAvQAPAesA9wAwAX8BsgF+Ad8AwP8+/9H+sP6o/sz+cP8UAGEA5v/n/6H/Uv9D/2n/6P+k/8H/yP8x/0/+bf67/0UB9QIIBEkFSQQuAqb/VP0q/HD7F/yj/XD+0f6X/9D/GP/N/d78t/xF/XL+kv9rAPYAFwENAKz+D/5d/hL/VP9o/1j/cP/a/ab9eP7F/iL/7/6r/23//v56/lv9Hf1G/az93P6K/5gA5wBMAHL/4f3Y/vv/ugJlBJQFAQcHBR8D2gArADn/7/+ZAa8CoQLTAccByf9j/TH8HPzH/In+TQHiAhUCPABF/2D9f/qN+5r+uQH9Av4DGgRmAtgAHQATAJD/twCwAe0BwQEkAcIASwBXAEEALf+r/un/1QEPApsAk/8Q/7z9wfw6/AP9Ov4w/xUB6AE2AzQDDAJqAQ8CjASHBSIH6geeBzcEXv+K/Ef78PoC/Z4AJgOOBAgDeAAi/Tn85Prg+Q/85P+VAbr/l/3E+rL4AvdS+zT/igOvCEkMgAybB+kD+AG6/p783Pw5AcwDiQQ8BTAD9P+i+gr4W/gf+Qn8uPzC/Tr/VQChAQj/rv5x/oz/tP4Z/ab/tgFMBfsGLQbCAhj+9PyA+7H6ovyw/7oEEAZeBXUEpAIAAH76+/eO+t4AWQSsA/EFgAULA2n+i/fU9gv3u/mV+mP67vx6/Zb9N/nm9uv35vgZ+0r/cQRxBiYGCAM+ACb9dv2v/swA0QZDCrsJJwZZA98Bu/xd+NL46/4SBk8HXAeiCHgHPwXNAZUA6gCL/2n9ivvT+cP8WP4Y/Z77pPtr/zz/Nf4K/ZX89vwm/mP/7f+VA58GgAltCTkGHQPAADMAFP6p/Vn+2gD5BAcFeAVCAmH/tPzk+u78F/wh/SX/1P6B/rX8AP3z/cb7sfrf+GP5mPqM+xgAKwNPBMsCMwCUAZP//v2b+4D8awATBbEHSwfdBUwAIPs39/v0IvaZ+Jf+kALwA0ACOv1C+bz44Ppp/Kr/TQSaB0oIzwcnBnsFewRpBGkFOAWZBesFbARVAIr/SgHJAeT/x/6C/4b9zvwY/ToApgIsA+cCgP8F/ZL80/zk/Pb8jf+2/5D+jf1T+6z7ff0o/0sAfP+s/j0AwgBhAEAAFwDR/Qv9ofyf+yP8Vf1iAPAAnQKjBHcEVwG9/nr8E/3S/scCqwhECrMJmASb/3D+9/6iAVADnQY0DaoP3w4bCqUDd/5y+h35qfw0BPcJxAp1BxwDFv2N9y71ifWU9sn48voN/K79Qv+x/8D9E/34/Wv/KgCcAeEEZQcaCjQKqwgtBIT/5P1Z+5344fht+0z/pgBQ/kH7ZvWG7QroKugq6cHrd+8N89v5Efsx/hn/cP+VAKABtQUlB44H1wlqCa0FMQOeA+8C9QO1BuYH/wgOCsAHrQKB/vb8Cfri+Fz8wgM/Bx0HPgd7BoIE6/9Z+zX6Efn8/JMBZgYLClEKaAi9AukApgIOBAkGmwWbBvkG3wSCAVT9jPsp/qP+wP0+/ywC2ALW/zr8gfuc+t36/Pla94L3KvbC9ZT3nvmt/64AOwVvBawEfALYAfUCXwSIBlgE+gKNAg4FPQF8+iL3B/kI/E0A0wawCzUJOAIy+t/0//Qu+nH9BfzC/XsDLAjHCcIIjQTe/6X7ZvrR+or8fgB1Aa8A7/6DAFcEqwPcAKz81/tT+PT12PVu+I37B/4UAlMFTwjPBykDrPxz9yjzx/SC+ef+IgdmD+cVohQGEssMwQNS+1v1z/Jc9Zb9YAcWCh4H9wL0+0b1nfKk8zL2IfkR/H/7wf3HAKQCjAM2ARICogM9BAwF/AboCYULhwv2B7MDHgIBA3H+5fYP81Xyh/RB+BX72fux+036fvat86vyzPRP+S/+1AM6CykRLBVIEoEI5fxm9DLuiO3o9cQA+QkjEJoQZQs0A4f6jPKy6zDqOO8o93H93QJjBb0CnP7m+g338fMv9Rn58/64A4cEzgQhBV8CSgAl//r+xP5pALQBoAK+BWAG9AatBs0FVwZKBK0BUP2k/AP+QQFWAasC+QNYA1AASf9XA3kHwAw+Ev0RLQ6ODKAHFQJVAN3/s/8IBDwMKxGlEg0QQgivAcr8z/s1/y0B+AMWB7EIwAoIDcEHxf9R+SHy6u8m80r7IgSJCr0Ndw6TDEgHBgQL/3X5rvSn9Nz2ofqh/vf+Lf/2AScFiwUdA/v8ivas8vX0JfpY//kDdgWZBh8DGAPvAor/t/219afspOWV5SfvyfRv+XP8pf4GCS4VoB4dInQgIRq7ErQKYwUQBmsFsQIl/i79dgHiCM0MCAkfAy/+e/hT9GXy8vMA8knuh+yw7BjuBu/t8Ozw4+8Q8KHvlu/o8bD0x/GL7+3uUPIN9mz0e+1Z5XbeVdlz1UfSr9Jx15bcHuKo6frw7Pfh+9X6GPlm9/T4MPou+9r9gQFKBYEJMQyfDkAQGg41CQkIdQuaEdsXzhsnG38Z8xbJEiYOYAmVCdIKLQ2TEOkU1RoTHjohNh+3GgwbVht5HEoZhxP2EFoRRxPvEuQVJBdgFtgU+BETEaUReBK8DyUMdQZ1AGj6/fHc7nDuWPT8/N4FhQ7wEdARwQmD/s3zO+oD5c3jS+dt7lz4SQOQCSoKFwXm+rTwaO968uD2+P7RBBoQKB2DJYArfyt4JqEcnxKkDEcL3RImFg4YRRfTEoIQywrQAsH5BPCx5RfcxNf411DbdNxf2GTUFdNX0RzRidCb0QrUFdj23uvliO+Q+Pj70/cd8KbpouV95Kbj8OGm3zPeit2f3iHjgemk7fLwp/KD9kX7NQHABM0GaghYBXIBIP1i+gr5Evnz+vX8UwCIBD8JJQngCbAHuQcqB4YJQg1pEOETCBYjFrQTsxEmDkIKAgjiB2EH9QpxEAMWaxoFHhEfABxoGFITpw2fCM8EHwcHC7cQtBhsHTQglx5AG/wSfwx9CBoIhgyYEJkVjxVoEWwJvvyX82jt0upE7Cbum/Q4/V0JMBFZFdoV6w9gCr4EfALjAkcElgR8Aj8ChwORBvQOuxyONM5J91TvVpVOXEFeLa8VC/386Srg7to82rTbOd2r23nUbsg7urqvdqvsrAGzQr6Azsvfge/b+0UDYwUjAlr7x/Py8IzwCvH18gf1iPgz+4H7ZPda74nlSNl8z9fJb8mZzxLZrORA8Kn6wQRGDbcT4BXNFTAVhhN2FOkS8A5WCa8BO/vB9dvy5/I38pnzyfPF9uT54f7cBd8HXgjOBlgDfQFCAIkAcwG7AmcEywYnCfkMVRAJEusR3A41DPsKyAqRC80KigriCdsHbAdqBJ4DqgHt/kL+AAAdBvEMvhNeFl4V+hSQEKEMFAoWCAIIGAadBJ4FAQmADkwUlhjJGzQeyx89HbMWfw66Ao32e+4I7pj0zP/BENcqbUw2a0d8Sn6Xc61aSjTlB+XiXM5DyPfKvdBC2YPiTefT4m/T172KqYSc9Zr8pT+8vNjL83cJkRoLJkEpiiFUEon9B+pW3erYq98U60f1S/vb+fXzkeoW3uTPw8PkvCe9B8dx2UHxvAjrGeEjwiNcHKURIgQ0+Evwau/F9RICoxP3IqoqHye9GDYH/vY464zlGuYj61f0l/2+BiYNXg/CC6kBjPSB6OXiaOQK61P2ywKnDV4VUBlpGS0VGQxSAD72kO4Y7fLw1PYs/0UFvQfuB9sEZQA6/Z/5RPhR+WX8hAPkCw4UhBd4FtAS3Q15CL4DfP9P/ez7iP5aBKwNhhq4JKYsDS5bK/onnyJDHt4ajRhHGAIbpySGOrhXNW7cc9tpGFb3OqYa3/mP367PRsX8wLLF69Jq44nrq+c12v7JW7yktIe258CZ0Qnlvvk8EFEluDJVNGsohRPI+XfiRNG/yGbICcy00aXYAt/V44jj1tuQ0BLFSL4MwCvKVdww87sJuxzTKukzKDezM3cqkB0yDxoE9f3t/UQCuAYUCkoLKgmxBG/+PfZJ7sTl3+At4/Lr5/tPDtUf/is/MJYtryQnGFsG4/F84JLUh9F01YDe0erp9d/8HAAAAPn9cPt7+Uf48vfl+Bb8oQAEBccH/gUXAvf78fSc7yHseOuL7SPyafgaACkINA7bEYUSBBBkDV0LIwjrBtcFjwb1CTQNpRJ+F90bBx9DIaIjZSXnKCQskiuDKFQofTKRQ/9R8levVcRMHTwPJscQsv+t8A7hXNMezoHRlNca3SbgA+Al27zTH8+i0PXVhtuK4bbp7fasBccSEBsCHE4VBQnO+QDrK+EX2l/UTdBRzjjRq9bZ20vfVuDq3vjbN9oM3Jni3OwM+DADhw6ZGd0iySjTKYEmFx9qFJgKEgTuAMn/6gBlAQsCRAPBA78D0gE3/gD7l/id95P6jQAYCBMPnBMLFk8YixlpGH8RTAUv9+npdOCJ25HcfuLi6f/vuPSq+F/8+f0a/X76Ave89Lb0C/d1+4v/jgHjACP9S/hl8+jvtuy66tDppuor71X2/v7CBtMLeg3/DJkKaQiLB8gHbgjbB4cHAQjhDAIWlR+5KCct2S41L8gtIS20LQAxujQMOPk8+0U2U3ha01OdQGEoTxJd/r/qPtz81UnUPtF6zeLON9Zj3GfaR9ICy6HIHcuH0LzaQ+o6+q8HDxGNGdggSiJDGrAKzvnQ65ThAtsr2EnZOtuj27navNmt2ZbY6NQm0BjOGNE42Z/lePQHBUAU1R6KJa8pcCzBK3wm9R1gFecOGQsdChwKowraCgkJ8wQRAI376PfH87rvA+5A8DL3cQENDAEUuRm3HI8bWRfqELoJLwKS+L3vQesV6/XtKfJ49XL3VPeT9XPzCPJF8ULwh++B7xnxBfUp+p/+vwDY/wn8VvcV87DvSu0q7Dfsgu3B70Pzg/jL/ogD8wWsBpoGewcnCX0Lxg1cEKoSoRSIF2Qb/yGuKQkuVi5KK4opTSu8MDo5cUQiUIZU806kQhU35i6YJK0TKADy8TnqveXa4MzdBd5z3NzUiMqdxBDFV8hyyYDJr82Z1/LlQvWPAuUMbRMtFA8Qgwo4Bt8C/Pzy84/rqudk5+DnzOat4yrff9jT0KHKJ8jZya7NldKn2Vfk7fJsAgYQhBpnIXslhSapJXElbSa0J7sm3iOZIesg7SCfHiYZCRGjB8v9OPSC7OXnR+Zo5lfnjOoy8SP6kgLPB5gJcggLBZwAw/zM+qD60/uV/aT/uwHtA1UFEgUEAmT8g/XI7jTpqeV/5Evllee26qruFfPn9pn5jPof+k745/UP9KHzhfVU+NP7Qf+6AmQGwQk/DG0NbA1JDB8LKwrLCf8KUQ5tE3gZgh4qInokoCWpJT0luCRhJTcnSCqYLos1uj5/RmpJEETxOWotSiAHEycGBPxv9HDuTuiM4xThjOBF37Ta0NLIycvCxL4Ivv6/QMU5zbPWieAl6rfzT/z7AZYDqAFF/sH7Qfrx+S768Pot/N78+fy/+2n56PWo8Bbq4+JP3RHbD9yJ363kXOvn8jH6zwDBBloMAhF+FMMWVxgrGq0cmx9yIhAkICSKIrkfHhwRGLUTCA9LCqgFQwEO/Rr5dfYS9dH0Z/U49tP3Yvmz+vT68/k++F/2uvR/8/jyXvNK9K31EPeZ+A76tfq/+sL5OPhx9hv1SfS28wDzQfLG8ZzxP/J/80P1IvdI+TH7+/wH/wgB6gJfBLgFaAeMCbkLOA7wECcTjhS+FDwUnhMgE7oSlhKaEsES8BK8EjUSbRGeENAPBA+7DYoMFgzuDAUPNxK5FQIZDBuLGxcb1hl2GGEW+hPmEGwNYAp6CMEHMAf5BWADdf91+gn1r++86jjmHeJs3lHbZdnG2LrZeNtg3SPfyeBk4qHjVeSU5NnkL+XL5dPmg+iL6ubsRu9I8R7ztvS/9tT4yPpn/Kz9df7V/m//YgDBAUID3gRjBvEHgQkfC1kMIA1+DXwNVg0/DVINhg2kDccNzQ3qDTkO5w6cD8QPhA+mDlMNQAv2CKsG3wTNAxMDpQIdAnUB4wANAAn/yf2K/Fv7Yfqu+Tb59Ph1+FP4o/f39lD2BPaq9WX1afV79fb1mfbP9zj52fr6+9n8jv0U/pn+Iv/R/6AAawE4AgMDtQNTBNUEBwUDBeYEVgTuA4kDcwOSAzoEJgUwBhYH5gfkCIIJpAlSCUgJTAmOCdQJwgmrCV4J4AiKCCIIJAftBWMEzQK5AegAaAAcAEgAHAEfAiQDeARABbMFowVhBQQFhgR2BJkEVQX2BWkGwga+Bg4G4gRdA8EB6v/t/Qf8oPq1+eb42PgH+QH5r/gQ+FT3JPbn9LHz+fJE8ufx2vEo8uLyUPPc88HznPMD8zrygfHX8K7w3/By8Qvyl/If8zf0OfUf9m/3N/gi+Vv6VPuU/PX9Uv/ZACkCcQN1BAgF7wVLBqMGjgaxBh8HOgdeB/gHaQi4CDUJdAmrCdcJGQrgCc4JpwmpCbEJ3gnDCb0JtwmgCYgJiAlQCdAIWghpB60GqgXJBBIENAN3AnsBfQCP/6v+wP1D/dX8P/zU+yX7lvof+p35ivml+RX6r/rL+hb7Bfuq+ln6Gvqo+hv77ft0/IX8Hv0f/fD9uP5m//r/OwB/AHMApgD0AGYBEwKbAg8DNAMeAxoD0ALhArsCjgKtArICFANdA1QDqwOcA2kDKAOPAlsClwLhAqsDFwSeBCoFtAXhBckFtwVfBRAFpgQ3BOIDSwO0AhoCygGhAbABlQFDAdEAWwAnAOn/hv8X/+z+s/5Z/jH+3P0A/ir+SP7x/Z39uf2h/Vb9dPyn+776yPkV+Vv4g/fQ9iT2KfWX9E70zvMQ9HnzfvNP8wn0zvSZ9Qz2Ave296D4j/lR+tr6bvvW+2z8tf2H/vL+wf6V/nT+4P6t/pL/CQCpAH8B5QFAAooBWgJHA8YEpQbpB5gIXQniCIYI4wfDB9IHQAczB9oGywfbB04IhAcEB+AGdwY7BsIGAwcFByUGqAW6BNQDxwOkBCwFkAadB70IbggaB0AFrAK4AKD9xvu1+eP4Sfls+Yb5dvgL+Gj3g/ab9vj2LPff9pH3pveL+KX4nfkL+l37H/ww/nz+BP9k/yL+5/zI+6n8nP2d/qD94/0z/mT+P/8Z/1MAkgCrAV4CEAPUA1EEeQbOBhIHvwimCMsIqAleCDsINggOCOcHZgd4B+IGLwdeB6YGuAX0AzsDJgImAq0CnwPHA5ADtwK/AooCKAOIBCEGlwZlByUIyAYjBgQGIQbeBFUEhQSjAzwDbAJdAAL/O/zk+u74aPjE+DX3NfgJ+FX4Ofix9oL10PWy9az1afiS+DL41veI97f28/S09Fvzm/Po8qzzYPTa9Gr2GPfq+Bf6aPvW+7n8CPwz+/D6ofk1+j76Q/ze/QAAUQGaAusDbAPJA3wDVgNXAyECBwDsAWoDLgVSBCkF8gQHBn0G3gQsBDgDjgMZBDgFZQZ+BIsEcANpBHMFLAMoBH0DSQZwBrgGFghnBbYFlANqA88CoQLWAokCHwP/AfsDEQFGAWf+sf6J/0z+ogDK/WX+w/9W/wUAX/7E/HP/n/1D/2n9Rv00/qL90/07/P/7NPqw+tX4iPpa+zr9MPzq+lz7Cfrc+2X8Sf1u/br8yv3P/ib/6AKLAr4D9QXUBNcEfARkBDsFIwYCBk8GfAbeBPQEyQMRA4cDzgKkAgoEewMWBCwE8AL4AkIEBAQUBHwDcwKPA2MDMgQTBX4ESgWoBTwGdQYqB6sHXQgbCCIIMgcEBosEqQI8ARX/hv7y/D38MPuw+pj6W/pb+eD3fveQ9SP0p/P28hHzCfNP85nz/PLY8try4fIZ8zz0ifVJ9uH1FfUp9P30xfUW9/H4I/tk/Aj93vta/LH70PvO/Wv/fwCLAEMA2//x/l//DwC0ANkBbwIoBAQF3waZBr8FDgYJBfIEcwRdBR8GMgdyB0EH8wjLCkQKUQlgCbYIlQd9B2sGlwf6BuMHtgfKB1gFpQVvBugFbQQnA+wCZgMIBMEDfQOqAl4DOgPGA7ECrgGmAP3/qf44/N/84vup/GL8bvpa+on6l/rT+O/4yfgE+SH4mfg++ZD4uvnt9wr4rfhl+NT4OPmA+ov8Qv0z/ob+j/8N/5z95vyI/aH/QQBEARsB+ABlAfsAfQKDAyAEpwSEBOQEhQVKB3EGAwZsBakEwQRqBLgE6AU/BqYGeQfSBXIFAAUYAyYEaQN2BEsEnwRRB64IpQrPCyAP+BDWEvAT3BJRESYP9w25CyQJeggdBoAE6AMJAu8Abv/J/cP7WfkP9xP00fAF7lTrYumn6EPo1edA6HDozOfg5mXmRObo5rTomepe7HnuRfAg8RzyMPMu9Rj3j/kB/Nv9fv/GAJQAhgC6ABIBxAKQBEoGrQfhCK0JsgkfCXwI0Qd2B6QHtgi7CZoK/goyCuwIOQeBBp8GfAb4BukGPQY6B9QGugbYBf4EqgMfAssBWwFhAXMAyAAPAbsBsAGJAfYAqf/M/9r+Pv/T/+wArwHcAnYD8ARkBNsC6QPGBE4EOQS7AwYDpgLX/6b+lv0w/b38kPtd+0T6Ifpb+gf65/n8+D/55/cB95f1QPQ19YX2UfjG+DH4KPrj+Vb7oPz7/En+dP2U/Sb84Pyv/kYC2wawCKkIlgcYB7kFugPDAhEC0wPkBQQI2Ak6CiUJlgZWBDsCwgFLAugCugQ3Br0GdQb5BBMEdANPA0sDXgNFBPEFMwg8CwwP7hIiF/oZxBswHAMb4hgkFccQyAyXCcUHUQaPBfwERwMPAZP9BPoW9jrx2+vA5ofiX9552oPXKtbn1pXYV9sM32HiPOWG573o++g46QPqoutQ7sbxBPa9+uv+lQKsBbEHJAnnCe0JRQlICIIHnQacBZoE9wOsAwAE1wQTBg8HlgfTB6YH3AZ8BUAElANeA6oDkATWBSYHZgh4Cd0JFQqQCSYJgwizB8QGlwW+BNQDAgTvA+8DWgPkArsCwAFvAcMAJABd/6L+Tf17/Mr7Q/zd/dP/7wLVBMwHpQixCC8H2wWUBc8E6ATcA8ADqAPOAwoDYgItAb3/lf5E/Gz6+vdP9fjyRfAz7j3scus17GTuYPHN8yX1RvUd9KnxN/Aa7+rv1fI7+AX/0QWXC2gP0w9+DToKfQZCBGoDzATXBl4KPg20DvEOCQ0YCjsGXAP5AfoBvQKsBFIGdAhiCUoKQguIC0kMcAyPDPILcgsBC5MKNAtXDcsRwRjsIAYp7i6jMDAt7iRSGd4MuAGM+o74dvp7/8gEIwg2B/IAMvZl6NvZoc08xY7BH8LTxWrLHdH41T/ZF9ta2/Tag9qw2qXb4d1W4fjlu+vW8gH7tQNBDIITnBiIGmAZnhWAEIYLEAhdB3gJKQ6WE2UYjBpWGVcUUQz6AvH5MvNN70vvLPJw9wj9BgLNBGgFqgObAF399Pr5+Ur6W/xm/4YDkgeDC8wO6hCiEUMRiA+3DFwJ6QU1A50BhwERAwMFIQcfCL0HjAUSAhj+KPoZ9xT17fQL91T7KAFfB4gMiQ/XDykOrQqZBp4CNQC5AGIDNQgzDRERehHFDVkGcv399Iru8uqz6WHqu+tE7QrusO2668PoX+UC44HizePX5hDqUO3q7+nymvbo+pr/VQM2Bl0HbQhUCfQKwQxdDlgQuBGlExIVFRY2FW4SDg5jCekFPAWGByIMtRGoFj8aihoOGIASOwxXBvYC4QM3CQsT4R4yK1c1iTtDPDc3zSxcH/MR/geEA+0EUArQEIQU4BJbCrT7Tel41unGd7xXuJW5kL59xE3JRsslyg/Hh8Nrwa7BiMSYyUjQMNgm4dfqNvV5//0IuBDBFcMXRhc/FU0T7RJfFaAaRSEIJ5gp7CfEIXcY9g29BCj+0fod+s/6sPs9+xP5mPUB8hrvse2n7bvubPBK8qT0j/dx++3/qgTZCAUMHw6YD+8QdxIiFLcVcRYAFlMUghH1DSkKJQfOBUsGCQjaCekJVwdNAbr5FvLd7PXqFewT8JL1z/yFBCQM0hEJFIgRUwpiAZj5nvbh+BcAugloEmsXKhaADqYBnPNM6b/ln+gS7wf1g/cT9bLuc+e34bHfpuD141Hnoumc6ovqbOsR7vjzzPttA5IIFQrjCMIGZQY+CXQPuRajHOEeGh0GGLYRewyOCYgJWwubDqMROBSKFcgVcRWGE5AR3g7rDIoLjAtjDj4UzB2vKTA2cD8tQoE8EjAaIO0R3wlxCRIQUxhFHi0dfROGAcHqJtUkxV+9sbwswNvElMdPx9TDm76AuQK2lbVfuNa9QMU7zgbZIOWU8aj8MAQJB1cGjQTLBOEI6RA9Gy0lGyzTLpUsyCWlGwURQgn9BZwGiQhjCScHQgLU+6j1MfB/64DnvOT046vl9enU7/T1APvR/kYBxQJsA1cESAZ5CkwQYBc9HX8gjCCzHdAZVxXlEU8PqQ0sDE8KIQjzBDAB1vzh+ED1WvLf7y/uQe0z7QHuP+/b8ATyPPME9Sb5ygDfClMVDBwKHZQXvQ3iA9D+dQEACuMTahowGmISZgQs9Qvql+WZ5pPpM+xI7BLq0+Yg5A3j3OL141DlRua35ufn2+tP8y79+wYADcwNQwp2BvEFHgolEdAXDRvTGosYZxZwFagUbBO9D7YLEAhkB1IJZQ2hEoUWORgqFW4PhwiaBFQF9QmuEb8axCWZMCc5RjwMN9sqxBtzEXEPphShHCIiyCG5GfUK5/jh5ojYr8+ozPPMKs0DzG7Jm8V3wHS6/7TXsQ6zz7lMxSfTHuDR6b3v+/Gf8n7z7/ZO/i8JGBbIIXkpvyt0KKgh3Rm+ExkQVg6kDU4NiQyECjQGdP9l9oLsZOQe4GfgDuRC6QvuffEe86zzu/NN9KL26vvqAwkNbRVHG/Md0R0aHE4aNxnFGJcYchg/GGoXKRWUENcJcAGh+XbztfAt8OTwFfHK79PtluoC6ELm6OZz6jTwmvfV/bgCMwVUBwcKmw5pFKwY/hkCGIgVTBS6FA8W5RW5EmsMTQXW/xz8DPmt9a3x6+xR53Diat/d3n/fyuDT4QnituF+4RHjieZP7B/z4vlF/2sCLwUOCKwMaBGHFY8XVBciFoQUChT6E7EUjRSSEucO1wqyCYALZRBWFWMXkxQWDg8JfwepCTcNfhEsF2odSScdNNE/wkAeMwsgLRN+E2ccyCYXLCcopxtUCoD4behR3FfWotUo1RrSYs1JyZTE1byjs/esV63TtQXECtOm3VriiuI+4gPkveng84gAOA1vF9Ed9h+DHkUboBe0FJoSChJNE+YUmhRlED0Ihf228i/rqegu6pnsru0s7XrroOle6OHofOuV8Pj3dgBKCFAOkRIFFV4WRBfRGCQbHx6DIe4jtCN2IA4b9BSkDiYJLwVaAmL/7Pvy91PzvO106KXkpeKG4nDk2+cJ6//sO+5w77/w4vIF+OgAMQwnFtUbRBsFFggRihDpFPQZZhw7HDsaYBb7DysIggDR+Z30xvFp8Y/xxe9P6+vkn95X2vvZIt3n4WLmVemj6uvq1OvL7n/zLPlE/28FsAoiDhQPiw4nDhYQrhPGFZoU7RCRDR8LegrcDQ4UlRkAGuIVKxHtDOQKXQvSDc8Q2RJYFoob8CGSKqM09zlJMnghzhYSGxwnyy2sK74k4BpQDfH9yvHP67Ppt+aP4MTYZNIwzRDGD7wps9KwcrYEwWHLc9Em0sHPyM5h0hzbWuig9t0BWQgxC4ANDhCQEhMVPxfYGS4duCAKIrsePhe+DdcEmv5n/Eb+ZQDa/pP4n++K58nis+KZ5qrr/O9S81z2vPhP+vv79v5aA/sIzg/3FnUcdB4aHRwajhc5FwIZdRtDHN0ZdhTjDC0Fdv/K+6n5BfgC9oLzB/CF7LzpM+eK5UDlNue66pnuBPOZ95v73f6DASsEdAZFCSAN2hCREqoS5hKXE2kTMRLpEO0OdQvZBpkCDv+S+134OfWR8Wbt/un7583mp+Vz5crlSOYf51no2epq7b3wJfRl9uH4RvztAVsHPQqgCxsMhA24D1kRLxK7EHoPxQ+6EAITERUEGIYZVBchFLsQ0A8DEcoT7hZ4Fs4Wyh5jLio6yzQ4JLAW+BPHGFIeUCWYKrUndxn3BKX1W+/S7t3tsunY5Kng09uj0gnGrrvyt4q6UMCex53OhdK50JbL18hHzZTZUOnx9rn+CwG1AcICIwWjCf8QhBlqH2khMSEJICcdlBcKEYIMuQtSDVwOOgz7BQf9sPO67C/qBOwo8H3znPPg8IPtz+sA7abw2/bp/c8DFQdOCJcJ3QsSD5wSHBZzGREcOx3bGyQYnRMUEJ0NcgxzDHkMzAonBpr/8fg/87Hvke4Q7zzveu727KvrM+sf7E7u0vAy8+j1V/mc/Cj/nQF+BHoHtAmtC6wNXg/GD+gOaw3pC78KqAkzCLIFQQJU/qf6ZfcT9Qf0wPMR87vwue1L68vq6+p76/fsMPAA9Wb4a/rw+nj8/f77AAQDagQyB9sJyQoZCk4JXQtWEBoVOhgEGc8XKxZKE0MSeBLKFIAZaxydHichJyrqNB00iCU1FSAUER/TJ+4oDiYuIeAVYAU5+fn2Cvrr+gf1/eqQ4J/Y0dJ/y6fEOcLtxOXIxMkuycjHm8UxxKvGE88L2yvmdO2d783uB/CQ9j0B/wsaFGUZhBuqGsgYihi5GhEdnx2qHAsb8hhYFeIPNAnwAhH/G/5x/rX9vfor9kXxTe2966Dt4PGw9dj24vXQ9G71Avga/CEB9AWWCa4LhgzpDIAN2A56EPkR4hKDE18T6BEZD+4LwAl1CG0HzgXiAu7+ifoN9y31tvSz9O/zGvIz8MrvOvF58zf1YPZt9374SvqA/FD/1AGnAxsFUwYgCOoJ8AqrCo8JqwiAB+MFGATIAoEBG/8c/BH5Kvde9sf11fTm8SjvQO2f7Ofsg+0z8PfyXPX89ej1xPep+5sANALbABkA4QKGCJsNwxGrFKwVJRVfFGEVlxf7GWEcahzYGr8ZwhtBIP4jBSpzMtU2xi7XHRkU6BjVI3goFSWzHxYZ7w5VAtr4OPVJ9Bbypuwf5aPdvdYlzzbGQL9HvtnCpMfoyL/GHcMgwF3A8MXKz5Xa3+Pk6cLsL+6i8fn4SQJTC6sS9Rf7Gg8cZRxUHF0cmx1OICIjhiOEIAIbNhTEDTAJ3geZCL4I7QU+AMv5kPSR8ZDwFvFn8mPzQfND8g/x2PAo8sL0Nvik+5P/FgNaBYAGoQZWB24IZAp/DScQDxLVERMQMQ0WCrMIqggzCdcI2waOA/H++/qZ+HD45fkt/Pz9Jf3L+U31gvJw8rr1afthAHECcACH/ZD7u/s4/vwBZwaYCBAIXQUQAqr/CP4y/sn/tgH1ATf/CvvX9kT0ZvO+88z0MPWi9ALzFfHh72Hw5fKW9k75DPpc+an4A/l0+fX6Uf4pA3kHQAmFCkwM0w1eDoUOJxCAEvMUpxgZHSohtiX4LFw03zKNJysesiEnLm41cjMhLp8oayC4Fb0P+hAUE/AOAgXz+rbyAesg407ckde71ITS0s+DyynFZ77que25gr67xBjKU8yjywLLWM1z1E3eWujm8AL3K/sv/jgCDwiqDv0UkRoQH4Ah7SFaIYggix8qH2cgNSLCIckdFhjyEhYPWgz8ChsKMQh9BB0AW/xb+Wn3cvby9ef0EfO88TbxcPFK8srzw/UY95H31PdP+H75JvuQ/TQAQAIKA2ACeAFGAWYCRQT7BfQGhAbMBNwCSwJ/A2oFkwa1Br8FLQSwAmYC4gOyBbcGQAb1BHgDMAKXAcQBigJLA5ID9QKIAXj/If0q+1z6IftP/E78ZPqY90L1s/Po8uXycfPc8zvz5vHG8LzwHfKz8+L0IvWB9eX2pPgt+sH6Hvu1/J7/WQMcBhwHsgeOCKsKrQ3WEIITBxQSFHgUcxQVFMkWhiI1MgE4Uy1UHAYWDh2aJ94t7y/MLqMoMR7rFO4QABHSEYYQ1gtkBP/8U/es8PXmr91t2hrdVt833JLUE8u1wjK+EcAKxx3OmNDaze/IBMZIyMDPZtmS4cPm5OlT7A/vgfJg9//9dQWwDDgSqBUIFxUXLxe0GGUclSEAJkgnyCQ4ILccpBuEHOIdNB7IHC4ZQRSOD/YLiQmXByMG/ARAAwAASvuv9rLzf/JJ8hXyhvFH8Czuvusg6uDpiOqN6/vso+7j71Dw6/BQ8vDzPfXz9kr6sP4WAu8D4wQABYQEkgRtCBEQihdYGrYWchC+C7wLAxAEFXkX3hVMEXkMawggBjAFiQQJBG8C1QDV/jD8ivgp9CzyX/OQ9l745vZR84DvfO1t7hnyr/Z7+Wr5FPg799z3jfl/+1/+5QDvAq0DiQP6AxoEjAQTBWoGcQjSCQsK7Qi3BxMHjQdxCD8JrgmkCdYJOwq5C78NJQ/yDmINvgyyDZkPNxBMD0IOHg6YDvsNbQydChsJqAfwBaMEiQPvASH/x/sH+Ub3APaz9DHzPfHk7n/suOrB6TLpsOgI6HznKecr53Hnmueo59/n3OiY6l7sje0i7tXuLPAO8gD07PXC92353/o0/O/9wf9fAbIC/wN0Bd4GTwioCbAKQAuqC2AMTQ0BDkoORw4WDtcNlw1nDT4N/gyWDOIL9QoICkgJkwilB60G5gVaBbUEuAOiAsEBMwHhAKkAZADg//f++f09/Qn9M/1f/Wj9Ef15/Mr7bPug+zz85vxJ/WX9Zf2B/cT9OP7R/oX/NADcAHgB8gE0AkkCZgK5AiwDkgPUA6sD9ALdAbgAFADT/7//qv8N/xn+1Px/+236cfn4+P74F/kI+Z74TfhU+FT4mfgn+QH6A/u3+3H8Mv3u/c7+vP/6AFQCjwNoBNkEXwUiBicH6Ad3CBoJ0gmECroKlgppCpcKJQvACyoMSAzoCyoLZgoAChEKawrcCvgKRgoYCQEIYgf8Bp8GWAYXBrAFyQSJAzkC8gDi/9P+3P28/Iz7RPr/+ND3g/ZG9Rz0NvN88rHxv/C277/uFu7m7fDtPu5C7kPuFu4y7qvuPu/3767wfPEm8rzye/OZ9Oz1GPf199r4+/lv+/j8Sf5K/xgA/AD1Af4CLwRrBVgG0gYNB2gHEQjKCE4JuQnXCaYJaAlcCbcJAQrQCU4J0gidCFYI5AdbB98GcAb/BagFcAUsBaEE1wMeA8cC7wJEA5YDoANVA7sCNgIIAk8CvAIzA6ADuQOFAzkDDgMNA/4C6QLgAs4CjgJVAvoBcgG/AAEAXf+//ij+kv3p/Cf8O/tU+oH5z/g8+LT3PvfD9jb24PWo9cP1IPaM9vn2Uvee9wv4qviV+bL6rvuW/Cn92/3g/uv/PAFfAl8DMATWBEEFvwWRBmEHPwjnCC8JSAkqCfcI+QgfCSUJMwnyCGwIzAceB7QGZgYhBrsFBwUdBCwDcQLlAYcBRQEpAb4AOABt/9L+df54/rn+7P4M//H+qv6X/nX+m/4T/4//1v/o/7r/g/9k/1z/kP/G/87/vf+Y/57/ZP8E/7T+gP5F/hz+3/14/QX9g/wH/Lf7VfsB+8P6YfrU+V355fio+Hr4Xfgr+MH3Yvch9wL38PbV9rf2wvbd9vT2F/cj9zv3Y/fN9yz4j/gv+bD5MPrY+or7OPwB/cD9Wf4E/+b/xQDFAdoCxwNxBAEFnQVbBlIHUQgjCdoJigoPC14LlAvYCzYMnwz4DEENNg3lDFkM2AtsCzwL/QqSCv0JHgn/B88GrQXMBD8EowP/Ai0CAQHj/73+8P1q/QH9xvxq/MX7Lfuh+ij6+/kJ+hj6FvoD+vL5y/na+d/57vkc+m/6qvrn+vT65frw+vz6MvuT+9b7+PsC/PT74/v2+0L8o/zS/AT9Cf0o/W39rv0j/oT+6v5Y/5j/7/82ALUARwHNAV4C2wIoA3wDuAP9A2oE2wRUBbAF7wUIBgIGBwYSBjMGXwaGBngGTQYKBrYFWAUGBaIEawQmBNUDXQPoAlgCGwLIAYUBRQGlAC4Arv9T/yf/5/7a/rX+jv5z/ov+PP62/Vb9Z/2f/fz9RP44/vn96f08/oD+qv6O/nb+qP73/h//J/8W/+z+FP8p/2r/av81/+H+xv7j/gf/HP/y/of+KP7J/XL9T/1d/ST95Pym/IT8IPyx+2b7Evs0+0L7Kvv9+qz6ifp3+qn61vpJ+4b7dvvj+qD6Hfsy/LD8z/w5/cf9Cf4F/v/9f/6P/w4AQwD5/9b/nQCoAQQC3AGaAUABOAL4AfYBJQJJAhsDqwOEA+YC/gFaAnMDWQTXBKoEOASkA/gDiARKBZIFJAXiBJkENwQkBBkEZQS5BOoDWwPPAkkD+gOoA88C8gE7AkUCCwKWASQBCwFkAfQBVQFgALn+5P5GANX/E/+F/v/9lP3H/t7/6v4t/o/9R/1W/sb97Pzi/D/8KP3V/Tf+Uv/s/lP9S/1W+2f8Ov47AEgAYfxS+Wn3Sf3a/3sA7/8F/Nj90f7hAaoCs/01/3P+NQLFBWwEMQPAA7ECkANrBYwDmAWFBdUDkAPdBBsHNQf1BCsEfQLhApsDtwPUA18B3gFmAfwArwCM/6AAVQBK/zr+4v50/5v+PP2X/bv+cgAyAEr+5Pzf/cz+HP9u/5T//P4k/j3+1v45/2H/Mf9b/ov+nf+T/9P+kv1w/dv9x//D/wP/CP2d/FL9BP9h/1P9u/ws/BP95v77/RX9Pfzu/B/96PzW/f78CP3h+2T7X/7I/WL8vfxW/Qb+bPzD+6H8KP1y/Rn9nf12/WH+N/6D/UH96P7C/1X/p/7m/QwB4wDI/4P+fQBFAx4CSv4B/hgDEwWyAnIB2v9aAn0DtQMEAfH+uQT+BcMD6wCF/gQAfAMwBhQD7f9S/YT/GgO5A5cBqf9b/ub/qgHHAEgAugEKAFH+6v4w/6gApwKPAjUBrP7i+zkAUgPtA9D/EPsmAOIB4QOYAfP+RwARAv8B8gI+AsL/mP+WAl8B2AHOAWIBwgPvAWcAbwA0AMr/SAOBBZ0CvPsP/F0B4gf5BTP6l/+vAhcC+v/M+Mr9eQT7BEQGhgHw+R79wwCPBBEHfwE8+5v+aQNfAuYBEACgA0gD3gCI/qv82AJFBFsBOwB7/CAAHQJRAb8ABf50/jcBRP7wAqoCdP0U/yT8T/3HAR4Bcv/y/8P6f/4jAV8AjAEp/Ir88f+F/Pn9qP8C/Pf/+QADArT78PlTAA7/HQD4/sL4B/y7/xwEWwLg+LL1Q/5YBNwBJf7S+b386//DAXD+E/mK+k38HwIhAz4AY/uf/3oAUPwo+jn6bgLhA6UDOvzq9h39dv8zAHUBJ/t0/U3/aP+2Ae38kPm1/LoCzgM3Ax38j/vxAcr8uP4//1EBWwPMAdUD3QDt+3z61wK0BRUEqwJ7ATUASf5lAUkBiwLLBFQCsgLn/cL83ALeBwUFqP9Q+5X9KQa8CLMDrPje94v90wbuDMQEhP1M9sf9lwT2BWwDJQFJAe7/8gJkAPr1Zfz8BBUDuAEI+WL7AQP6BU0AzfhU+fACXA3TAzn8Gfuc930BGAXrBIwG7QMKAvj9rfR49m8IvBd0CsP5GvHg80YE9wgAAlH/6v4KARUBZQBkBTQAH/4K/JP45QnyCEUC6/41+0cD1gU/BAEDKweNBbMCJv9L9/QD2gaCBzwFwvwj+5kDoQhWBEH+zfm5/iUDjQlUA/v88/iY+vT+wvl7/RkDxAUrBo/8TPIn9Nj9bAWdCGgDF/sd+NX/kQYfB0YBjfYX+D4G2wsLCav/iPZQ+M36SADUBRsIBgc7+ufuae8Y+2MKdAqc+1T30fFB89L7twBMAZEALvan7wH3p/fs/zX/e/fF9sHy5Pjs/038nvkv9Fz2SwETBMkAhv2w+fj09/L4/ZQKbAymC50C6Pgd9Wz1LwIZDkoRkA1EA/3+J/xL/PIBCQxDD/4IA/zW9iQC5AuBDGIBFPaa/SwLlgvXBt8C7v7R/W3/VwLEA2ULGgprB9wDmPwf/EQEFwhwCCADzPrV+on9DgAQBSYMXgxj/eDuRu88+soGUQstBn79y/M89Ob4EP/hAVIBSftq+dz4pPry+mP9/vtn9lb6Afm3+pj+sQDE/dj3Lfd4+m8CHQN8AF7+MfhS+1EBFQClA7YGJQXlAov9m/fL+/EI3g0YDPwD1vd19mYBYw1YDEQKrgIP+yMCBASrC6wL2AFq/s0AkgXtB0QFwgR7B9cHAgKE/tH7bAMkDIsJcgfEAG7/YgB2AQQG9wIQAJb7vfnG+3gD2gXRApj64/Sh92P+9ABZAF7/Jvun/DAC9QEPARUAJQEiAigAX/83AnQHEQ2zDH8GuAGhACkERgmZC1gNYAuQB6cEYAFLAFECDwR9BO0BzP0K/IH9cP8U/n/4T/R08wv2qPgE+tH3lfKf7b3qpOvN7zr1kvkn+Urzgu0e6zrsNvPn9zT7nPxl+hf5DPdK+Bf6VP1O/7b9rv8fAsgEWAWIAbD91Pv3/RYDmgbkBw8HRwN/AXUAS/8vAQMCaAOVBKgFzQcUCdQGkQVdBQoGCgbeBAwGAQUSBQUHUQVIAtf/DACpAg8GZgbuBiYE/AIsBSMG5gVRAzwCcALwAQECqwKEBZ8IrQoiCd0GpwX9ATcBTwXPCP8MXQw9CHcDT/4q/H/8MP/rAgIDsQBb+4vzAe3T6OfnO+mw6jHr0+p96Rjl2t9n3SngHeUf6f3ri+0P7P/q1utg76b0f/pB/wACowP6BNIGngd8CIMKTw6ME0oXsRdVE9UNpArBCsYN8RG1E9gRvgzhBdj/rfud+dH8rgGVBcEGlgNG/7j7Wfhi97D6dv+/B7wPiROaEqoNoQv4DksXwiE7LAE0qDVEMjcstydqKHYrUC6ALjUsKClkJD4e/RWVC2oCa/zl+LP2V/Nz7crke9nCzufGmsTFxgzK58vbyf3Fb8IvwLjAGMQFy//TYNxg4yboLOtu7tnxwPcr/54HfxBBF1QbZxxqG+Qa5htVHiciWyUaJv8juR6sF2sQ7QqBCHYIlQhnB48DP/2k9sHwlOxZ6k/qo+ur7J/sTutD6XDnduce6RPsle+H8zD3IPob/Bb9aP5RAF8DugcUC8oMcg2VDbkNYQ3qDeIOXhAMEp4RIhCIDIMJIwhFB3cH3wfQCF4I3QbqBS0FxwVvBgcG8wPFABj+oP2F/yYCcwJPAKj8MPlL90n3hvg5+dX3GfVq8g/wv+4Z7n/t3uxG6oDnHuXM5CvmOuYi5T3jI+FV4V/j8+Yj6yPtze4J8VfyufQ4+J/8qQBiAt8CmwOvBQ8J1Qt7DMEJaQacBAAFcQjzC50Otw8PDnAMIgxYDnYRdBNhE6MR+hGoFu4eVymhNCA/5EYbSKRCMTxSOY461z3zQBlBgT4ZOQ8xHSd5GrENkQMB/Ef26vA863PkAttC0HzF8bzBuJS4urvNvnHAu8BzwDnBdMMZyFbPwdgo5NLvpvqkA0AK0w45EmMVoxkeHzUlZyp7LVAtoikXI6YbmxX0EFwN2AnyBKX+7/YS77rnPeH121/Y89Yw16PYlto83FjdXt444H3jrehn7xT3Wf9SBu4LThBaE8MWOhpIHnkhdiMYJdYkdiO1IG4cDhiMEjkNoQjJA1//PPr49Hfvbekb5arhN+Bo4DPhROPz5PrmfOkp7eXxyPX0+eX9JANMCRYRPRv/JeIuqDKDMZYsGib3IRohJCO3IxEhEhvYESQGOfn/7Q/lRt4b2unX99aF1SjTk8/uylPGtcMZxdvJatCk1+rdleJr5YDnJeok7i/0QfzSBUcPFxZjGvIbRxwbHGoaMhjsFEMSEBHrD9cOcwyjCawFlv+E+f/1UfeO/OsCmQh2C7YLJgoaCDsHRwijDBMUBR7fK7g8Qk7zWBNXg0qQOWosHSdzKTow9TRgNFUslx5LDn/9ne7M4JjUV8t9xifH38qpzvLOf8rcwt27krmevRTHINNW3wnqnvIh+tYA5AajC/4OwhFsFegaYSItKm8v7S/BKqkhChdcDVEGtwGI/hL7EfdH8vDsJufo4KPawNR00OjOZNCY1NDauuEB6MvsIvD/8hf2dPpSABQHTg7cFOQaNyDlIxkmSyZjJLMg3Rt6FyUUhRGFDyYNDwoXBfD+i/jX8eHrmeYy4/bgr99C4LrhYOTn5ermOuhJ6S3sB/DC9T78+gHkBykN7RInGDMd3yHgJLgmGSdCJ6cnsCjTKmYsqivkJrseFBUxC3QCLPsF9W7vf+kv5Mvff9yO2QrWJdIUzjTLxMpIzVfSYdgJ3hTif+Qh5jToe+u072b0Cfm8/ZkCdAc+DH8QfRPcFDwUXRIUERERCRJkEs0QJQ7/CuIHRwTu/0X80vi19r/1nPU2+Hr8sAGoBRMGfwU4BR8GqwfDCMYKZA0PElkaByZANVxDO0x5TDtDZDfiLZgp2Sg8KKgnXiU0IRsb9hKICez9ffDe4VvT3Mg2xA3FZciXyirLocmmx8DGRMctyb3Lq88r1WDcOuYY8u/+dQq4ElsXvRgUGUYalRxQHzch3SEsIV4fSx3bGlYX9xFWCgMBH/ep7sjoVeV04zziFeFw34zdWdwA3HXceN3f3hjhOOQ36Vfw3viQAT4JVw9+E2wW6hinG2QedSDcIWAiayIWInchTiC5HZIZ4xNNDaIGcQDH+0X4UvV58nfvK+1J6/np1+i2577mtuW75Tvnieoj70L0tfnP/q0DGwg4DNUPYRIQFCkVeRZoGJQbGCCFJFQnKCcgJNsedBg/EoUMQgfLAVL8LffC8lfvf+yi6SzmGeKy3avZ1tbH1Y7WmNhL20nepuHd5djqjO9T88n1efcu+Sb7If6YAX8FkgniDM0PyRFhE14UhROmEfAOsAyeCzgLqAsvDHMM0QvsCXAH/gQfA3QBhv+J/ZD8bP3x/9UChAVOBxAI9wfPBnkFZAQEBDoEqQNrAncAJABLAtQGSg1uE9AYBRzpHO0bjBlDFzwVZxN1EXkPfQ7PDrEP7Q9YDn8KLwUD/6f44PJY7hXrv+iM5qrkIuOr4gjjcuMm47/hMODL3kreA98c4Z7kuejv7PDwgvTj92f7jP7JAPcBcwLkAqoDDQXEBpgINwohC4ILcQsFC7sKOgoGCSsHAAWeAjwBcgBOAG0AYAA2AJP/9f59/m3+iP6T/mT+DP7b/SH+uf6J/3gAXAEGAk4CbwJ8AtYCUwOBA7IDcQNUA3sDygNOBJQEtwR1BBEEqgMLA30C3QEoAXQAu//e/nj+Sf5i/r/+vf6J/v39bv0h/Rr9W/2O/cn9//1a/uf+rf+LAA0BZwGJAYIBygEwAsgCZQOZA9kDGQRlBA0FmwUcBhkGlQVbBJkC/QCs/wX/wP4E/vv8mPtL+jr52/ed9mr1NfQx86LytvJi8/LzjfTo9Av1KfV59VL2SPeC+GX5n/qB+578ZP4kAC4CsANqBa8GmgePCIYJnwo7CyQL7gpSCvYJTAp4ClgKmwn0COoH+QZtBrkFTAWWBKkDxwIdAmgBNgHmAFwA6v8U/yz+h/1P/Tb9tf2e/sL/lQGXA1sGtQnkDEwPgRCYENQP7Q4eDtgN8w1SDoAOOw6aDeoMHwzqCmoJFQcpBOcAjv2O+jX4bva19GbzRPLy8NXvyO4g7q3tW+3n7LXsxexA7YTu/u+Y8RDzZfR39Uj2+/bK90v4kPjO+Cf5xPmM+rL72vy//Tb+of7H/tX+Gf95/x0A2wChAU4C7gKGA2UEGAWuBR8GawaoBroG5gbIBq8GvwZ8BjsGEAYNBg8GCgZSBUAEHwP+AQQBJgBc/8f+tv4s/oH9k/wS/FH7pvsZ/N38+vx4/GX8VPx5/Cz8WfzJ+7n8KP3o/Vz+Cf/2/9b/KQAnAJQAngBIASICqgL0A30E1gTlBG4EfgRUBDYEqASJBBEEBgPrASIBfwCd/0n+hP2l/PX7o/vj+rn6EPsZ+zj7+foD+2T76/sV/E/8Ev2e/V7+L/7J/Rr+NP6N/iX/x/5i/qP9Y/2u/Wf9Zf4g/z0AQgEbAd4AZwAeAPn/eQDGAEwBagKuArYDTQRFBEwEWATkBEYFDAakBlcGDweNBpQGmAbRB2MIbQjhByAG8AV4BQEGtwVMBGsEoAP6Am0CHwEfAWcA/f7p/fz70/s6/G/8Vf10/bL9TP0//Xn9yP1d/XL9Y/08/ZP+Hv+3ADECnAPSBAcFSwXiBNYEoATIA0ADlALWAtwC3gKbAuYCwQIrAjACigEGAHn/Bf++/l7/sP9+AHIAgQB6AMz/VP/E/j/9gfyy+9X7Afx0+0f7Bfs5+7j6u/mb+Nn3WvdA9yb3Wfds91r4Ufgn+LH3kfd095r3fPjV+Df55flO+g37FPyH/aT+2v96ACQBKALmAu4C7gIsAwIE1QR3BT4Gqwb+Bs0GSAdSB4EHRwcaB+8GGwYNBowFZAU/BeMEMASFA0QDWwJDAqABdwDn/7n+c/73/aD9zv00/Q78UfwA+y/7lPsY+wz7Mvxj+wH7z/ur+v364fn6+Rf6mvlC+8D6Y/vz+k/7RPuZ+p38Kf3f/SH9C/3//eD9y//r/oP/DwBYANECmQJLA2oDlgOcBJYECQaPBfEFhQY6B8AGQQb/BlYHkwZDBZUEewOdA0kE2QMVBIEEBAUmBXQEGwOgAvUBuAHQACcAhgBtAHsBZQIHAvEAvv8yALMBdAFVAFn/s/6N/rn+zv5K////aABNACv/Sv4M/53+F/40/YD9sf5u/28Axf7X/Yf9lf36/L38Nv5S/wkB5gALATEB7gDWAFD/t/9IAK8BUAH0AQwDBwObAi4BcwCr/63+M/72/VX+8v26/hgAUgEOAYX/Ov8kABkAcv83/qb90f08/0wA9f+h/4b/cADwAPIAlgAbAMUAHgEOAuMAjf/LAPsBZQFT/7b/wv0BALf/8f9T/i/+qf1R/Q3+n/0M/vD9C/7C/kX+2v2C/Zb9vf3N/t/+hv0g/6/+9//lADkA5ABaAaACXQK5AdcALgDZAKIAJAFbA2wEDQQ3A+gCrAI9ASIBTQCRALkAzwD8AHQBnQGc/lL92f7G/5f/r/w8+5f9mf4B/2n/Avx4/Ff7JPxG+xP6d/lI+mX8vPx3/lv+E/2h+6z6wfoF/Sb+5P2o/iT/sv5r/fT/OwL6AIj/TAE6/wcA1gCkAnEEHAQxAcYAIQBgBWEFTQOPAjIBYAI2A7sC4AG4/3cCmQLcAzYDdwGFA4sCOAF9ARkBzQGsAzYEugOnAZoApwHwABEF7QHt/o3+8PxrAXwAPv/G/gIAswBcAUYA2P0fAGf+m/65/p7+HwL0A+ICcAEi/rD9d/zA/7j/yf9f/or6DAAs/wQCeQFh/Kv3d/fC/TUBrgHY/pX+hv9j/+z/+f8UAX4BbgFAAX8CmgLvAlEFEwS6BEABgwITAXQCGQTuAXsCSAPhApkC0ADQ/d0AMwM7BUgCsv5e/SL+lP7j+nv7svmF/Ab9w/z6/R38dPvi+AX5tPzk/QT/hfxz/O/9vQGJASj/mP6z/iMCvgGf/of9Zv83/1kAQgMZAmX+H/8iAsQERwVy/m7+1PkfAF0BRgEo/Sf5J/5E/7sCAADfADj+ZQAP/7/83v02/oYCaQMoAlUCYwKEAc8ApAEZ/An7Z/6pAEAFCAGrAXUBKwJ1ASr/Zvzo/Z8B6gAgA/3/UQJ5/0AAEwLrAMH8PP0yASkGjAP2/hT83/8gBDoD+f3t/H78ZgGUBZQDCgEG/pYBNANrAugAdfrL+4gC7AQZBTID/P0d/Wr+fAItBK76EPy//YsAkQLzAuwA9P4j/Kr/4QEIAyD8D/lA/u0CNAN0/B75B/gaBM8DHfzi+jj85QQaBj0ACPlJ+dT/dARaAun8wABWBTcK5gO8+sb4LvstBd8DhP/c+Wv+eQcIB7YDwfuq9hT97wGOBPv8HvuD/FoDDgXKBFT+Pfpn+nT97f9n+S38av8QBh4LvwdrAfD5C/tD/RcAtf19/af/RQaeB+YGiwFW/lb98vgM/gj+bwKzA5UDsQTNAhQCZfml9rD5jgJBBMIDNQHt/T8BrQADAA377PIT9/T73giaBc3+0/qu/bQAaQMsAOT7gvh1/R4E4AIlAZ77VQH6Ba79Ffrd+Xf9ov8IACgAdQXxBZj/ffyF/68CGAGy+HP84QOSBp8CAf70ABUD8wP9ATf6xAGYBFEGMv6D/eb/YgjsAB0Cb/yi/RACdABaBM79MfuP/4AEcAikA7r9zPvs+2MEQf93/sj/+ASW/en6x/3NAugCRgG7/eD6aAC5/ToAKALsAGgB3f+s/LL/kf/vAbYA5wEZ/wsB7QGI/ZID0/9v/bP47Pmx/iUJ0wAU/LL4hP2jB5P+5vmJ+7oG5gRb/YH57gSOAm8Ckf4H/XIEAPzn+nEA4AmHA6T5afWgBT4MlwB995r0vgf/BiwDR/kS+V//3wHOBrwDF/yd+rX8JwsfAhv88PqBADEJ4gDO+v331QXKCCwEU/to95ABpAUMAxz+d/ii/IgGqwNRA2j6Hv28/hQFCgMX/KH67v9ECmsCXvsm+mn+ZgXHBKL8l/iyAF0HqgZh/dD8IP0OCPsDx/gL9mb9LgnwCkj9DfS5/qUEkwV2+ff0+P8PBDIDjv6z+Kj//AnnAXwAs/Rw+S0ENgXIA4L45ffWBDkHjgO89wn/OP7LBJsCmQHL+vjzvwkHBJ0HIPan9fz8BQH9CNb9Uvxj+mwDwgWDBlT4IgDsATsFiAfp/JEF4QD3BOQAA/we/u4DsAGfAGwBXQUGAZIDxAFQ/w0FIP3M/UICUgl1AmgA5/6V/yj/OALAAJYAEf78+qgHO/2ZAUX8YP7O/ib+LgUzAPf9Nf4ZAb3/4Pxb/XH7QP/NBCn69QP3+60CYAJd/Uf6mgSu+23/nPxb+sYFffet/vb+E/zt/2P6A/+PARz+WgO89hL+6P01BM//2vddBNQAhA3y/tf8kAWoBBwICgLcAccFh/+2BC4Dl/+UAOcAFQPNBMoB/wGcADP6pwVO+a8ERQMKArgCkvY5BPz7fAgf/MH/PAG+/dYDRvn/Atz/awZ//j39S/4KAWr/ovld+sf/zQLJ/xT7XfzH/w7+p/su/KT/Y/z6/eP7OgI0/6j8EgMr/ZL+aP21AlcHdf3j/ob/UQcI//X6LPp4BbUG3vw2AJj9QQIABBD7KACw/OkGOwM3/EAD4wJTBDT+nAHW/LwGX/yp/bsCPAX2AjX8A/9G/4wEyPtc/9D9fQAMAeH9eAHdAfABPwKS/zL/HPtn+3ICM/7+AHf+KfwfAcv94AO4/K3/nf6i/8L7eP1bBPEAgQJP+8b/oQWH/cgCSP2lAA0BVP9g/AQCGwZxAOr/yvpmAFcEjQEF/kcCRgTn/zD+l/8X/0AEvAQD/wv8BvjmBAUIN/2z/Z36+QPCB8v8pQD1+SMCP/7/+/H9RwMQAs/9JAMbAGEG6PY5+g0BbP11CHX9d/u4/ZQCVAsP+5f7tvwt/+sGsvuI+xYBMQO6CGz7IvlQAfAAHQNH+wj/f/8+AfABef0UAED+qgTKAjT6z/tL/OgJ0wPy//b8E/oWBw0FFf4c/Bv8YQnHA3MCQvvyAxIEX/0f/Xn7mwIiBUwAk/+d/zAE5wJ3+MD+q/6oBh78Z/l7BcEGZgMU+Tv6gAGTBcD4bPq9+6oGUwdB/ZD8CQGMBPoBIvq58loBoAUUBNQBYvfT+yQEQggM/4/2P/efA6oF+AF1/5D67AIOBhIGDf6S9Jz9jAPPBrn/bfnWB5QHtwP++pH48AlwALj+RfxuBPQI9/9F/DwBEgQq/b/6hQSbA7kAT/k89d0K1gOaBg32kfcsBm8FSwTp9MX3UQjCDYr3tPQp+i8PwQ1a9Cj1svuLC0oEDfNV+YsH/wMXAsj3Rvw/BRQBTf+L/d3/uP3MB8b8HQDI+Y0DVAiq/wkBcPeKARcEcwoA9hX+iv6yCPoGD/ZSCIr4ngVc/6/80QW5+/QBEgJtAWQCyf1P/TMAt/5I/ngAQgB+/vb4igJGASgBhvYq+n4FOAnIAYf4/PifA/UF4ADu95f9AQWtA9H9F/c5CHQG/QYY8+f5agT9CogBvPWKAqX/4/8vAo/9MgGo+NX8WQSE/tABRfm3BRAAiwGa+W//zQA6Ai0I2vkr/+z8pAas/JcALwRR/rYCIPypBMf6qwS9AG0AiP5Y+EgE8AJd/7v9Df4qCDAB5P2k+/UAHAX9+77+b/h2Bq0ByQNU/+P3XARrAE8G5vzr+PoBjgNsCwz+zPpu+5kD0wgg/VYA6PtmA8r/8AFg/r35+v+HAYUD5/zVALAApQMkAUz75v/8/XsEWgUR/F77+fmCBRAGUwM89pn2Swe3BScE2fnT+iUEGgIAATT8ufhnBU770wGnAuwBewUI/aoBA/8oApz5eP2u/iIG4waN+a/70QC8CgQAQfUx/mcBHAts+wz87AFEBrAIbvg89/z9ZAhzBlz7hPuN/TgIWgO0ABH50fx6/84CGAUU+7MBdwB0/88Afvui/Uf/vQGQAev+2/wOAHADlQTA/0v8kgC+/q/9tPwP/zMDiAE+AL78hv41AEcANAKp/nv7Gf6RBHgGLAAm+/L7FgLfA2L/Vf4DAGgFxgOp/vb58v2D/w8CtgJ7AJH9Sv81AlkCMvzL+kj9wP+MAdv/xv7SAgcCJQFs/HD+H/+LA18CW/9r/gEAcQNQ/+X+bf61AB0GOPxa/on4SwMhA3ECfv31/WMCLf1P//T/MwaKAnD9cPtOAQcFSgAVAsL/IQIi/3b+WwGfA0EC1P8LAMwA1v4V/5H9CQBGAQAAffzw/qgCDAP6/x/9h/0TAK7/bQI7AUwACQLp/XADof6w/zr/WQB3AMv8dP9vAHQBOAEc/jMAbP9SAdMCkf8d/2f6cf7D/c8CJwH+/uP7Hv8ZBB4Brf8Z/CX/Gv89AJj/qv7J/SAAJABeAFUBDQAn/9T8A//s/sf+M/3M/dj+VgO0BCcCy/s++wb+WgNCA4b+Wftd/vsD+QWVAjz9H/zr/1EB/gICAhgDmQDX/lT/4f/pARcCav1d/QP9nQAfAqUDHQA1/jX9PwDQAqgBPQD+/cQA8v8OAp3/ewCE//X9vP8M/t/+VgEHAhMDVv0i/gj9sQF2BG0Eof96+yz7BACUA3IDMgBu/LD8HQHxAXMCDwIV/a/8yfvT/j0DmQOsAjL//P2Y/Z7+iABSA/ABiQACAMj/1f+uAokEXAKO/hL63fz8/+wEGwUeA7MBp/9gAC0ApgBwAVEB8AC/AFQBUwJMAkgBUP+H/kz+fv8jAB8AXgDz/8QA7v+8/in/W/+W/gb9rf0GAMUBwQBU/zj+Zv59/+H/gf+v/4X/FADY/zL/FACHAAsB+/9BAHwAzwBBAHYA1v/a/8P/ZwDXABUApv9W/wz/MP+O/yz/tf44/sv+G/7a/eP9s/2p/ZH91P1v/Yf9sf28/cH9Tf3+/X3+TP47/oL+1v4h/zn/aP9Q/4b/s//F/yEA5P/+/1UAQwBTAGoA3ADnAN0AcgAeAXkBggHsAPP/qwArAdMB3QHUACoBcQG9AVwBvgGFAZ0BiQGkAYsBGQHUAO0AHAFAAQABtgCKAIsAuAA+AFkAZwCCAIMAQQD7/wAAcQBQABYAl//7/4AAjgAxAPD/GQB/AFsAKAAZACQAJQCeAOUAlAAGAFMAYgCzAGsADAA5AMQA1wApACwAeACQAI8ALwAuAEcAMwCOAHQA5P8nAJz/NwBOABAA1f8XADAA6/9//3X/GQAeAH3/OP/I/z8AKQALAKj/2P+//1//m/9w/4r/lf9y/6D/N/8f/0H/5f/9/5P/Tf9F/zb/eP9k/wj/Af9X/7b/p/9+/6//pP9V/9v+Lv91/8T/uv/K/3D/k/+3/+n/2v+9/7r/yP8mANv/rP/B/zAAUQDm/8P/zP8TAC8ACgDT/4D/tv/I/9v/AgDc/8j/qf/E/8f/xv/N/7D/t/+7/43/kP/X/7H/lP8j/z3/rP+y/1b/hv+I/4b/fv8m/6T/uv/k/3D/YP/C//r/7v/c/7D/DADr//j/yv+5/+7/FABNAEoAYACKAIMAZAAqACcANgB0AIkAeAB9AHAAnAC1AHQAeQB/AI4AjQB7AHMAdQCGAHkAXABNAFsAgABvALf/6v9fAIQAMADp//X/6v/P/7f/qv+0/7r/rv///6z/xf/e//L/CADX//3/mP/e//7/MwDz/9n/MADP/2QAvv/S/wsACwBKAP3/BQAlAC0AWgCLAB8AyP/p/x4AVQAbABoAOgBaAEoAQQA1ADYAXgCFAF4AOQBAAAMAZABrAGkAPwDz/0EASAA8ABIA6v8CABIAKQDV/6X/9/8UAPz/uv+t/+P/MQAJAKf/jP+g/7j/z//Y/+H/yP/s/6v/3v/M//P/7P+o/+b/6/8eACcACwBGACkACgAAAPv/CAAbAA0AEwAsACMABQAAABwAJQD//9//7P8JAAIA/f/w/8z/8v/9/wUA3P/a////GgANAPD/1//u//7/5v/X/8H/6f8BABIA3f/H/9//DQAbAOz/yf/F//n/NQAFANH/+P8iACUACwDk//L/GwAIACIA/v/5/xkALQAPAO3/CgAYAC0AIwAYACYALAA+ACUACADw/wkAMQArABkA/P8nAB8ADwADAOv/JwAUADUAOwAlABMAAwAdAEgAKwD7/+D/DwA0ABcAAADZ//r/7f/x/9j/x//e//f/4f/Q/6n/zv/o/+P/0/+n/7T/wv/C/8//vP+x/9X/8P/9//v/+//v//z/BQAIAPv/5/8LACUAHgAiACgAMwAnACcADQAQAAEABgA2AAAA5P/r/w8AFwDb/8H/8f8cAAkAwf/P/+r/1f+3/8r/1P/U/+T/9v8GAPb/4f+2/93/8v/b/7j/tv8TAOn/3v+x/7r/+f/G/7r/tf/P/wEACAD1//v/BQD+//H/5//+/xAAHwAJAAMADwAhABwACQAFABIAIQAcAA8A7v8LAB0ABgAAAPX/AwABAP7/EgAgABUA+f8AAAUADAAWAAQA5v8GACsAPwAcAOz/1//3/xYA4f/j/9f/GQAyAAwA3//Q//L/DAAaAPP/8f8CABgAPgAgAAcA6//6/xUAGAAQAAkAMwBGACQA//8FAB8AEQD3/+7/+P8vADMAAgD0/+//AAAeABIAAQDp/wQAJAAsAAwA/v/9/xYADwDy/+r/9/8tACIAAgDo//7/GwAhAAQA6/8GABUAFgD0/+f/5/8SAPX/x//k/97/CwD//9D/2//m/wAA8//d/+P/AgAdAAoA9f/v/wIAFgAVAAkA+f8IABUAHgAVAPf/BgAIABUABwACAB8AFwA+ACEA//8BAAIAEgAKAAsAGQAgAAkA+//7/wIACgD3/9n/4f8NACQAAQDY/9v/9f/t/+v/3P/t//T/4P/p/93/4//N/7//5P/z/+v/z//E/+P/8f/f/7P/u//W/+f/8//b/9j/5v8AAPD/2//V/9f/AwD2//z/7P/z/xUACwAFAP7//v8NAB0ABwAFABUAKgAYAAoAEwAmACgAFgAQABoAIQATAAIABwAOAAAABgATAP7/9v/t/w4AAgDM/+T/5P/3/+b/0v/t//z//f/h/87/4f/4//T/3P/c//X/AAD5/9//5v/7/wUA8P/e/+//AAD9/+//7//2/wYABgD0/+7/AAAAAAQABQABAAYABAAGAA0AFAAHAA8AGQAXABUAFgAfACQAHwD//w8ALAAxADYACQAWAC8AKQAlAAQAAgAMACMAJgAcAAkA+/8QABIADQDw/+T/+/8SAA8A9/8HAAsA7f/f//L/BgDo/+L/9v/+/xUAAwDw//P/7v/0/wgAAQABAPP/9/8TABoA/v/v//j/GwAUAPb/9v8MADAAJgASAAMAEwAiADQAFwAJACIAKgA7AAUAFwANADkAJwDv/x4ABQAvACYADwAUAA0AHgAVABMADQALABgAHQAWAAUA/f8LABQACgD5//L/+v8JAAUA5f/h/+L/8v/m/8r/5//Z//b/6v+4/8z/2f/e/93/4v/q//b/6v/o/+//9v/6//r/+v8LAB4AIAAQAAAADwATAAcAEwAeAC8AJAD5//H/AgAhABgA8f/w/wUAFAD//+T/6v/+//f/3v/i/+n/7//3//X/4v/f/+b/7f/x/+f/w//f//D/AgDk/9f/6//1//f/6f/U/9v/9//s//P/8v/x/+P/8v/0/+3/5//r//D/7v/2//H/5f/t/wMA9f/8//3/AAABAOr/DgAjAAMACgADABIAJwASAAoADgAVABQACQAIAA8AEAAUAA0ABgD3//7/AQAJAAcA/f/5/wAAEQAUAAIA/P8FABQAFQABAPH/9/8MAAgA+//u//n/DwAFAOr/9f8KAAMAAwDx/+3/AAAHAP3/7//9/xIAAAD3////DgARAPf/+P/t/wUACgD7/////P8IAAcAAQD3//v/+f/6////+//1/wAABgD7//D/+P8OAA0AAAADABEAEwAJAAMABwAVABwAFwAkAAgACwApABwADAAAAAwAFQAOAAYAFAAkACAADQADAAYABQAGAP3/9f/8////9v/u/+//+//3//f/9P/4//f/9/8AAPn/+f/3/+3/8v/4//P/7v/y//j/+P8AAP///f/4//v////6//n/BAACAPn/+//9/wIA//8KAAYA/f8IABMACQD+//3//f8EAPv/9v/z//n/+v/7//n/AAAAAAMAAAD2//P/8v/6//L//f/5//7/AgAIAAwA+//3/+//7f/5//v/+P/8//r/AAAAAAEA+v/+//j/8//1//3//v/0//3/AQD0//L/+//9//3/9P/3/wEACAD///X//v8DAPr/+//+/wYABwAEAAQA/v8EAP7/+////wcABQAHAP7/BAAPABUABQD2/wAABgAQAAsAAQADAAkA/f8HABMAFQAAAP7//v8HAAoA//8DAP3/AgACAAwA+//6/wIAAwD9////AAAAAAMA/f/8//7//f8BAAoACQAAAPf/9//2//7/BQD8//r//v/+//f/AAD8/wAAAAAAAAEACQAWAAcACQAPAA4ACgARAAoABAAOAAQACgAOAAkADAD+/woABAD+/wQA/f8DAAAA+v/+//z/BgAWAAsABwAIAAsAFAAdABMAFgAQAAwAEwAHABcAHQAQAAcADQAZABkABwDx//7/CwDw//j/+f/q/+P/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egB5AHsAdgBqAFUARwBAAD0AQABCAE0ASgBEAEYATQBKADMAHgAMAAUABQAJAAgAAQD0/+f/2f/V/9r/4P/g/9z/2f/a/+D/8P/v/+f/4//e/93/4f/o//L/9f/2//f/9f/z//f/+v/5//H/8P/1/wAAAgAIAA8AFQAUABYAGQAeAB4AIAAiACkALQAwADgAOgA/AEUARQBCADUALgAfABYADwALAAwABgACAAkAFQAhACEAGwAYABoAGQAUAA0ABQD///z/+P/y/+n/6f/q//P//v8AAP7/+//z/+v/5//h/+H/3v/S/8v/yf+9/7X/tv+3/7r/u//C/8H/w//K/73/u/++/77/v//L/9b/3//u//r//////wQABwAIAAYAAwAFAAgADAAVABkAIQAkACUAJAAlACMAHgAUAA4ABQAAAPv/8//x/+v/5P/o/+j/5v/l/+j/5v/m/+j/5//q/+j/6f/n/9//3P/a/9r/3f/h/+P/6f/w//H/7//t/+3/7v/t//D/8P/0//P/8//0//X/8//4//v/AgAJAAwAFwAaABwAHgAcABkAEgAVABEAGAAgACcAKQAqAC0AMwAwAC4AKwAkABwAEwASABQAFAAWAA8ADQAKAAIA///4//b/9//4//v/+f/6//r/+f/z//H/7//y//b/+v/9/wAAAAAAAAAAAgACAAIAAAD//wIABQADAAEAAAAEAAIA///9//7/AAAGAAYACwAOAA8ADgAOABIAGQAcAB0AGwAaABYAFAAVABMAEQAVABAAEwAQABAAEQAVABYAFAAUABYAFgAXABcAFAAOAAsACQAHAAIAAQAAAP///P/7//j/+//6//r/9//2//P/8f/y/+//8f/x//X/+f/6/wEA//8EAAQABgAFAAQACAAKAAkACgALAA0ADQANAA0ADgALAAkABgADAP7//P/8//z/+v/9//z//P/7//n/9f/z//H/9P/0//T/9f/2//P/8//3//f/9v/2//f/+P/y//T/7f/r/+3/5v/k/+T/4//j/+X/5f/l/+f/6P/q/+j/6//s/+7/7//x//P/9P/3//r/+P/5//j/9//1//b/9f/0//T/9v/2//r/+//8//3//f/8/////f/9//7////////////9//z/+v/6//n/9v/2//j/+//8//7//v8AAAEAAQABAAEAAAD+//7//f/8//3//P/8//3/AAD//wAAAAACAAIAAAABAAAA/v/9//z//f/9/wEAAgAGAAgACgAKAAoACgAMAAoACQAIAAgACgAKAAsADQAMAAsABwAGAAcACAAJAAkACQAJAAkACAADAAIAAQAAAP7///8AAAIAAwADAAQABAACAAAAAAD///3//f/+//7/AAABAAMAAgAAAAEAAgAEAAQABgAIAAkABgAIAAoACwALAAkACAAIAAYAAgAAAP7///8AAAAAAQADAAIAAAAFAAIAAgABAAEAAwABAAIAAgABAAAAAQAAAP///v8AAAAAAAD//wAAAgACAAIAAwADAAIAAgAAAAAAAAD9//7//P/7//v/+f/6//j/+f/5//j/+f/6//v//f/+/wAAAQACAAIABAAFAAYABwAHAAcABwAHAAgACAAHAAcACAAGAAcACAAHAAUAAwAFAAQABAAEAAMABAADAAIAAQAAAAIAAgAAAAAAAAAAAAAAAAD+//3//f/+//7//v/+//3//P/6//r/+v/7//3//f/9//z//P/8//z//P/8//v/+//8//z//P/7//v/+//8//z//P/7//v//P/7//v/+//6//r/+//7//7////+/////////////v/9//z//f/8//3//v////////8AAAAAAQABAAAAAAAAAP3//f/9//z//P/8//3//f/+/wAAAAAAAAEAAQAAAAAAAAD//////v////7///////////////7//f/+//7//v/+//7///8AAAAAAAAAAAAAAAD+//7/AAD+//////8AAAAAAAAAAAAA//8AAAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAEAAQAAAAAA/////wAAAAAAAAAAAAAAAAEAAQABAAEAAgACAAEAAgADAAMAAgADAAMAAwADAAEAAQABAAEAAQABAAEAAgACAAEAAQABAAEAAQACAAEAAQABAAIAAgACAAEAAgACAAMAAwADAAIAAwADAAMAAgABAAIAAgACAAEAAAAAAAAAAAAAAP///v/+/////v////////8AAAAA//8AAAAAAAAAAAAAAQABAAIAAgACAAIAAgACAAIAAwADAAMAAgACAAIAAgACAAEAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP///v/+//7//v////7//v/+//3//f/9//3//f/9//3//v/9//3//f/9//7//v/+//7//v/+//3//v/+//7//v/+//7//f/9//7//f/+//7//v/+/////////////f/+//7//f/+//7//v//////AAAAAAAAAAAAAAAAAAD///7//v/+//3//v/+//7//v///wAAAAAAAAAAAAD///////////////////7//v/+/////v/////////+/////////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAQAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAQAAAAAAAAAAAAAAAAABAAIAAgABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQABAAEAAgABAAEAAQACAAIAAgABAAIAAQACAAEAAQAAAAEAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAEAAQABAAEAAQABAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAP///////wAA//////////8AAAAAAAD//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAQABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAAAAAAD//////////////////////////wAAAAAAAAAAAAAAAAAAAAD///////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAA==\" type=\"audio/wav\" />\n", + " <source src=\"data:audio/wav;base64,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SwA2ADIAPgBNAFkAXwBbAFIAOwAgAAIA3P++/63/p/+h/5n/jP+A/3H/av9s/3n/hf+O/5H/i/+B/3j/df92/3r/gv+K/47/k/+e/6b/rP+w/67/qv+t/7L/w//X/+T/8//4//7///8AAAIABAAGAAkADwAXABoAIQAkACwAOABFAFAAVwBfAGoAbwBzAG4AXwBUAE8ASgBFAEsAUwBaAGIAXgBWAEoAOQAhABUAEAADAPj/4//G/7z/t/+o/6T/nv+f/7//4f///xwAMQBBAEcAQQA0ABUA+v/o/9j/y//J/8f/yf/K/8n/zP/P/9j/5//y//v/AAAHAAgAAwAGAAMA/f/8//b/AAD//wAABAAIAAoADgAPABEAFAAfAC0AMwA3AEQATgBUAFEATgBOAE4AVABTAFQASABCAD8ANQA6ADcAOwA5ACoAHgAcABMADgAIAPv/7//o/9z/0f/P/8f/uv+9/8X/zP/O/9X/3v/g/97/3P/e/97/5P/t//X/+P/7//3/+v/9///////7//n/+v/8//j/+P/x/+7/8v/y/+3/7//w/+v/5v/p/+z/8f///wEABQAPABkAGQATABYAEQAPAAwADAAJAAgAAQD9//b/8f/s/+z/5v/g/9j/0P/O/9D/zf/F/7//uf+3/73/yP/R/9H/zv/O/8//0f/O/9T/zv/I/9T/2v/j/+b/6v/p/+j/6f/v//r/AgAHAA4ADgARAAsACwAEAAEA//8DAAgADQARABQAGQAYABMAEgAOAAsADQAQAA8AEAAPABQAEgAUABYAFgAcAB8AIgAnACgAKQAiACMAGQAYABoAGgATABEADwARAAwABgACAP3/8//j/9v/1P/R/9L/zv/V/9r/zf/O/8b/v//C/8f/y//X/+H/6P/y//f/+//3//f/+f/7//z//f/+/wEAAAAFAAwAEQAMAAsAEQATAA0ADAAOABIAEAAMAAgABQAEAAcABwAKAAoACwAJAAkADgAWAB0AIgAlACsAKwAsACsAKgAoADEAKQAnACQAIwAjACIAHwAaABMADwANAAoACAADAP7/+f/0//L/7f/u/+z/7f/q/+3/7P/z//b/+f/5//r/+//8/////v8AAAIACAANAA4AGQAXAB0AIAAiACAAHgAgAB4AGgAYABcAFwAUABIAEQARAA8ADAAIAAMA/v/5//b/9//2//r/+//8//3/+v/0//H/7f/u/+z/7P/v//L/7f/w//X/9P/y//L/9P/z//D/8v/s/+z/8P/o/+f/6v/r/+z/7//t/+7/8f/z//j/+P/9//z//v////7//v/8//3/AAD8//z/+v/1//D/8P/u/+v/5//m/+X/6P/q/+n/6//t/+v/8P/w//P/8v/2//f/9v/5//v/+v/4//r/+v/3//b/9//7//z//P/7////AAACAAIAAQAAAP7//v/9//r/+//4//f/+P/6//n/+v/6//7//f/4//z/+//4//j/9//5//f//P/7/wAABAAIAAkACgANABMADwANAA4ADAAJAAoADAAPABIAFwAQABAAEgALAA4ADAAJAAgACwAKAAYABQAFAAUAAQABAAIABgAIAAgACAAGAAQAAwAEAAUABQACAP//+////wMAAgABAP7/AAACAAMAAQACAAUACAAEAAMAAgADAAIAAAADAAkACQAGAAMABwAGAAcADQAMAA0AFQASABsAGgAXABcAGQAYABUAFAAVABUAEgAQAAsABwAEAAUABAAAAP///f/9//r/+v/4//v/+v/4//b/9P/0//L/9P/z//T/9P/4//z/+/8EAAIABgAGAAkABwAGAAoACwAJAAgACwAOAA0ADQANAA0ACQAGAAQAAwABAAEAAgAEAAIAAwAAAAAA///9//n/9//5////AAAAAAAAAAD7//j/+//6//n/9f/1//X/7//w/+v/7f/x/+3/7f/t/+7/7//w/+7/7v/u/+//8v/x//L/8v/y//H/8v/x//H/8v/y/+//8f/y//L/8f/0//T/9f/2//r/+v/8//z//P/8//z/AAACAP//AQABAAEA//////7//P/8//r//P/9//z/+v/7//3//v/9//3//f/8//j/9//3//X/9f/3//j/+v/8//3//v/+/wAA///9//r/+//8//r/+v/6//n/+P/4//n/+v/+//7////+/wAAAAAAAAAAAAAAAAEAAwAGAAgACgAJAAkABwAFAAQAAQADAAgACQALAAwACgAJAAcAAQACAAUABAACAAQACAAKAAsACAAGAAUABAAAAAAA/v/9//7/AQADAAQAAwAFAAQAAAD//wAAAgAGAAkACwAMAAkACAAHAAcABgAEAAUABwAGAAUABgADAAMABAAEAAYABwADAP7/BwAGAAQAAwABAAIAAQABAAEAAAD//wAA///7//z//v8BAAEAAAACAAQABgAGAAgABwAGAAcABwAIAAgABQAIAAQAAgAEAAAA///9//3/+//7//r/+v/6//v/+v/6//z//P/7//z//f/+////AAAAAAEAAwAEAAUABAAEAAYABgAHAAkACAAFAAMABgAFAAUABgAEAAQABAADAAIAAQACAAMAAQAAAAEAAQAEAAEAAAD+//7/AAAAAAAAAAABAP///P/7//r//P/9////AAD//////f/8//v/+f/4//n/+v/8//v/+v/5//n/+v/5//j/+P/3//f/+P/1//f/9f/0//T/9v/+//z//P/9//v//f/9//v/+v/6//v/+//9//7///////7//////wEAAAAAAAAAAAD///3//P/6//r/+v/6//v//f///wAAAQACAAIAAAAAAAAAAAAAAAAAAQAAAAEAAAAAAAAAAAD+//z//P/9//3//f/+//3//v///////v///////P/8//7/+v/9//3//v8AAAIAAgABAP//AAD///////8AAAIABAAEAAUAAgABAAAAAQAAAAEAAQABAAAAAAACAAMAAgD///3//v8AAAAAAAACAAMAAwACAAIAAQABAAEAAwAFAAcABQAEAAQAAwABAAIAAAAAAAIAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAgABAAAAAAACAAIAAQACAAMAAgADAAIAAgACAAIAAgABAAAAAAD//wAA///9//v//P/8//v//f/7//z//f/9//3//f8AAAAAAAAAAAEAAgADAAIABAAFAAUABAAFAAUABQAGAAUABgAFAAUABAADAAMAAwACAAEAAQACAAEAAQAAAAAAAAD//wAAAAABAAAAAAAAAP/////+////AAD//////v/9//3//f/9//3//P/9//7//P/8//z//P/9//3//v///wAA/////////////////v////7///////7//v/+/////////wAAAAD///3//v/+//z//f///wAAAAAAAAAAAQAAAAAAAAAAAAAAAAABAAAA///9//3//v/+//7/AAAAAAAAAAAAAAAA///+////////////AAD///7//v/+//3//f/+//7//f/+//7//v///wAAAAAAAAAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAA//////////8AAAAAAAABAAEAAAAAAAAAAAAAAP//AAAAAAAAAAABAAAAAAAAAAIAAQAAAAAAAAAAAAAAAQACAAIAAQAAAAAAAAD/////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIAAgAAAAEAAgABAAIAAQABAAEAAgABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAgABAAEAAQABAAEAAQABAAEAAAAAAAAAAAAAAAAA//8AAP/////+//7//v/+//7//v/+//7//v/+//7//v///////v8AAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAEAAgABAAEAAQAAAAAAAAABAAIAAgABAAEAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAA/////////////wAA////////AAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////AAD//wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/////+//7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAAAAAAA//8AAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAABAAEAAQABAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQABAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAP//AQABAAAA\" type=\"audio/wav\" />\n", " Your browser does not support the audio element.\n", " </audio>\n", " " From 456ffcfe4c8da07e606516f2e0f9903b7af3ec94 Mon Sep 17 00:00:00 2001 From: Andros Tjandra <38714605+androstj@users.noreply.github.com> Date: Wed, 31 May 2023 13:03:41 -0400 Subject: [PATCH 753/774] fix missing extra args in ConformerLayer (#5176) * fix missing extra args in ConformerLayer * fix extra args issue --------- Co-authored-by: Andros Tjandra <androstj@fb.com> --- fairseq/models/wav2vec/wav2vec2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index 96b15541a1..be0cb4f536 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -942,7 +942,7 @@ def make_conv_pos(e, k, g): class TransformerEncoder(nn.Module): - def build_encoder_layer(self, args: Wav2Vec2Config, layer_idx: int): + def build_encoder_layer(self, args: Wav2Vec2Config, **kwargs): if args.layer_type == "transformer": layer = TransformerSentenceEncoderLayer( embedding_dim=self.embedding_dim, @@ -972,7 +972,7 @@ def build_encoder_layer(self, args: Wav2Vec2Config, layer_idx: int): use_adp = True else: adp_trf_idx = list(range(*[int(g) for g in args.adp_trf_idx.split(":")])) - if layer_idx in adp_trf_idx: + if kwargs.get("layer_idx", None) in adp_trf_idx: use_adp = True if use_adp: layer = TransformerSentenceEncoderWithAdapterLayer( @@ -1050,7 +1050,7 @@ def make_conv_block(e, k, g, l): ) self.layers = nn.ModuleList( - [self.build_encoder_layer(args, ii) for ii in range(args.encoder_layers)] + [self.build_encoder_layer(args, layer_idx=ii) for ii in range(args.encoder_layers)] ) self.layer_norm_first = args.layer_norm_first self.layer_norm = LayerNorm(self.embedding_dim) From b2d5b78ffed607ddf4521c73ed43e5aefc94a907 Mon Sep 17 00:00:00 2001 From: Patrick von Platen <patrick.v.platen@gmail.com> Date: Sun, 4 Jun 2023 05:35:26 +0100 Subject: [PATCH 754/774] Add transformers MMS checkpoints to docs (#5186) * Add transformers MMS checkpoints to docs * Apply suggestions from code review * Apply suggestions from code review * Update examples/mms/README.md * Apply suggestions from code review Co-authored-by: Sanchit Gandhi <93869735+sanchit-gandhi@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Sanchit Gandhi <93869735+sanchit-gandhi@users.noreply.github.com> --------- Co-authored-by: Sanchit Gandhi <93869735+sanchit-gandhi@users.noreply.github.com> --- examples/mms/README.md | 83 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/examples/mms/README.md b/examples/mms/README.md index fa0377c2a3..4760fef12e 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -6,6 +6,11 @@ You can find details in the paper [Scaling Speech Technology to 1000+ languages] An overview of the languages covered by MMS can be found [here](https://dl.fbaipublicfiles.com/mms/misc/language_coverage_mms.html). +## 🤗 Transformers + +MMS has been added to Transformers. For more information, please refer to [Transformers' MMS docs](https://huggingface.co/docs/transformers/main/en/model_doc/mms). +[Click here](https://huggingface.co/models?other=mms) to find all MMS checkpoints on the Hub. + ## Finetuned models ### ASR @@ -17,6 +22,84 @@ MMS-1B-all| 1162 | MMS-lab + FLEURS <br>+ CV + VP + MLS | [download](https://dl \* In the `Dictionary` column, we provide the download link for token dictionary in English language. To download token dictionary for a different language supported by the model, modify the language code in the URL appropriately. For example, to get token dictionary of FL102 model for Hindi language, use [this](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_fl102/hin.txt) link. +**🤗 Transformers** + +First, we install transformers and some other libraries +``` +pip install torch datasets[audio] +pip install --upgrade transformers +```` + +**Note**: In order to use MMS you need to have at least `transformers >= 4.30` installed. If the `4.30` version +is not yet available [on PyPI](https://pypi.org/project/transformers/) make sure to install `transformers` from +source: +``` +pip install git+https://github.com/huggingface/transformers.git +``` + +Next, we load a couple of audio samples via `datasets`. Make sure that the audio data is sampled to 16000 kHz. + +```py +from datasets import load_dataset, Audio + +# English +stream_data = load_dataset("mozilla-foundation/common_voice_13_0", "en", split="test", streaming=True) +stream_data = stream_data.cast_column("audio", Audio(sampling_rate=16000)) +en_sample = next(iter(stream_data))["audio"]["array"] + +# Swahili +stream_data = load_dataset("mozilla-foundation/common_voice_13_0", "sw", split="test", streaming=True) +stream_data = stream_data.cast_column("audio", Audio(sampling_rate=16000)) +sw_sample = next(iter(stream_data))["audio"]["array"] +``` + +Next, we load the model and processor + +```py +from transformers import Wav2Vec2ForCTC, AutoProcessor +import torch + +model_id = "facebook/mms-1b-all" + +processor = AutoProcessor.from_pretrained(model_id) +model = Wav2Vec2ForCTC.from_pretrained(model_id) +``` + +Now we process the audio data, pass the processed audio data to the model and transcribe the model output, just like we usually do for Wav2Vec2 models such as [facebook/wav2vec2-base-960h](https://huggingface.co/facebook/wav2vec2-base-960h) + +```py +inputs = processor(en_sample, sampling_rate=16_000, return_tensors="pt") + +with torch.no_grad(): + outputs = model(**inputs).logits + +ids = torch.argmax(outputs, dim=-1)[0] +transcription = processor.decode(ids) +# 'joe keton disapproved of films and buster also had reservations about the media' +``` + +We can now keep the same model in memory and simply switch out the language adapters by calling the convenient [`load_adapter()`]() function for the model and [`set_target_lang()`]() for the tokenizer. We pass the target language as an input - "swh" for Swahili. + +```py +processor.tokenizer.set_target_lang("swh") +model.load_adapter("swh") + +inputs = processor(sw_sample, sampling_rate=16_000, return_tensors="pt") + +with torch.no_grad(): + outputs = model(**inputs).logits + +ids = torch.argmax(outputs, dim=-1)[0] +transcription = processor.decode(ids) +# 'wachambuzi wa soka wanamtaja mesi kama nyota hatari zaidi duniani' +# => In English: "soccer analysts describe Messi as the most dangerous player in the world" +``` + +In the same way the language can be switched out for all other supported languages. Please have a look at: +```py +processor.tokenizer.vocab.keys() +``` + ### TTS 1. Download the list of [iso codes](https://dl.fbaipublicfiles.com/mms/tts/all-tts-languages.html) of 1107 languages. 2. Find the iso code of the target language and download the checkpoint. Each folder contains 3 files: `G_100000.pth`, `config.json`, `vocab.txt`. The `G_100000.pth` is the generator trained for 100K updates, `config.json` is the training config, `vocab.txt` is the vocabulary for the TTS model. From 91c364b7ceef8032099363cb10ba19a85b050c1c Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Wed, 14 Jun 2023 07:09:42 -0700 Subject: [PATCH 755/774] Update MMS README.md (#5202) --- examples/mms/README.md | 120 ++++++++--------------------------------- 1 file changed, 23 insertions(+), 97 deletions(-) diff --git a/examples/mms/README.md b/examples/mms/README.md index 4760fef12e..814ef707c7 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -9,97 +9,22 @@ An overview of the languages covered by MMS can be found [here](https://dl.fbaip ## 🤗 Transformers MMS has been added to Transformers. For more information, please refer to [Transformers' MMS docs](https://huggingface.co/docs/transformers/main/en/model_doc/mms). -[Click here](https://huggingface.co/models?other=mms) to find all MMS checkpoints on the Hub. + +[Click here](https://huggingface.co/models?other=mms) to find all MMS checkpoints on the Hub. + +Checkout the demo here [![Open In HF Spaces](https://huggingface.co/datasets/huggingface/badges/raw/main/open-in-hf-spaces-sm-dark.svg)](https://huggingface.co/spaces/facebook/MMS) ## Finetuned models ### ASR -| Model | Languages | Dataset | Model | Dictionary* | Supported languages | -|---|---|---|---|---|--- -MMS-1B:FL102 | 102 | FLEURS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_fl102/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102_langs.html) -MMS-1B:L1107| 1107 | MMS-lab | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_l1107/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107_langs.html) -MMS-1B-all| 1162 | MMS-lab + FLEURS <br>+ CV + VP + MLS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_all/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all_langs.html) +| Model | Languages | Dataset | Model | Dictionary* | Supported languages | | +|---|---|---|---|---|---|--- +MMS-1B:FL102 | 102 | FLEURS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_fl102/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_fl102_langs.html) | [🤗 Hub](https://huggingface.co/facebook/mms-1b-fl102) +MMS-1B:L1107| 1107 | MMS-lab | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_l1107/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_l1107_langs.html) | [🤗 Hub](https://huggingface.co/facebook/mms-1b-l1107) +MMS-1B-all| 1162 | MMS-lab + FLEURS <br>+ CV + VP + MLS | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all.pt) | [download](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_all/eng.txt) | [download](https://dl.fbaipublicfiles.com/mms/asr/mms1b_all_langs.html) | [🤗 Hub](https://huggingface.co/facebook/mms-1b-all) \* In the `Dictionary` column, we provide the download link for token dictionary in English language. To download token dictionary for a different language supported by the model, modify the language code in the URL appropriately. For example, to get token dictionary of FL102 model for Hindi language, use [this](https://dl.fbaipublicfiles.com/mms/asr/dict/mms1b_fl102/hin.txt) link. -**🤗 Transformers** - -First, we install transformers and some other libraries -``` -pip install torch datasets[audio] -pip install --upgrade transformers -```` - -**Note**: In order to use MMS you need to have at least `transformers >= 4.30` installed. If the `4.30` version -is not yet available [on PyPI](https://pypi.org/project/transformers/) make sure to install `transformers` from -source: -``` -pip install git+https://github.com/huggingface/transformers.git -``` - -Next, we load a couple of audio samples via `datasets`. Make sure that the audio data is sampled to 16000 kHz. - -```py -from datasets import load_dataset, Audio - -# English -stream_data = load_dataset("mozilla-foundation/common_voice_13_0", "en", split="test", streaming=True) -stream_data = stream_data.cast_column("audio", Audio(sampling_rate=16000)) -en_sample = next(iter(stream_data))["audio"]["array"] - -# Swahili -stream_data = load_dataset("mozilla-foundation/common_voice_13_0", "sw", split="test", streaming=True) -stream_data = stream_data.cast_column("audio", Audio(sampling_rate=16000)) -sw_sample = next(iter(stream_data))["audio"]["array"] -``` - -Next, we load the model and processor - -```py -from transformers import Wav2Vec2ForCTC, AutoProcessor -import torch - -model_id = "facebook/mms-1b-all" - -processor = AutoProcessor.from_pretrained(model_id) -model = Wav2Vec2ForCTC.from_pretrained(model_id) -``` - -Now we process the audio data, pass the processed audio data to the model and transcribe the model output, just like we usually do for Wav2Vec2 models such as [facebook/wav2vec2-base-960h](https://huggingface.co/facebook/wav2vec2-base-960h) - -```py -inputs = processor(en_sample, sampling_rate=16_000, return_tensors="pt") - -with torch.no_grad(): - outputs = model(**inputs).logits - -ids = torch.argmax(outputs, dim=-1)[0] -transcription = processor.decode(ids) -# 'joe keton disapproved of films and buster also had reservations about the media' -``` - -We can now keep the same model in memory and simply switch out the language adapters by calling the convenient [`load_adapter()`]() function for the model and [`set_target_lang()`]() for the tokenizer. We pass the target language as an input - "swh" for Swahili. - -```py -processor.tokenizer.set_target_lang("swh") -model.load_adapter("swh") - -inputs = processor(sw_sample, sampling_rate=16_000, return_tensors="pt") - -with torch.no_grad(): - outputs = model(**inputs).logits - -ids = torch.argmax(outputs, dim=-1)[0] -transcription = processor.decode(ids) -# 'wachambuzi wa soka wanamtaja mesi kama nyota hatari zaidi duniani' -# => In English: "soccer analysts describe Messi as the most dangerous player in the world" -``` - -In the same way the language can be switched out for all other supported languages. Please have a look at: -```py -processor.tokenizer.vocab.keys() -``` - ### TTS 1. Download the list of [iso codes](https://dl.fbaipublicfiles.com/mms/tts/all-tts-languages.html) of 1107 languages. 2. Find the iso code of the target language and download the checkpoint. Each folder contains 3 files: `G_100000.pth`, `config.json`, `vocab.txt`. The `G_100000.pth` is the generator trained for 100K updates, `config.json` is the training config, `vocab.txt` is the vocabulary for the TTS model. @@ -117,14 +42,14 @@ wget https://dl.fbaipublicfiles.com/mms/tts/full_model/eng.tar.gz # English (eng ### LID -\# Languages | Dataset | Model | Dictionary | Supported languages | -|---|---|---|---|--- -126 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l126/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126_langs.html) -256 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l256.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l256/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l256_langs.html) -512 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l512.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l512/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l512_langs.html) -1024 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l1024.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l1024/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l1024_langs.html) -2048 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l2048.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l2048/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l2048_langs.html) -4017 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l4017.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l4017/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l4017_langs.html) +\# Languages | Dataset | Model | Dictionary | Supported languages | | +|---|---|---|---|---|--- +126 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l126/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l126_langs.html) | [🤗 Hub](https://huggingface.co/facebook/mms-lid-126) +256 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l256.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l256/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l256_langs.html) | [🤗 Hub](https://huggingface.co/facebook/mms-lid-256) +512 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l512.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l512/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l512_langs.html)| [🤗 Hub](https://huggingface.co/facebook/mms-lid-512) +1024 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l1024.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l1024/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l1024_langs.html)| [🤗 Hub](https://huggingface.co/facebook/mms-lid-1024) +2048 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l2048.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l2048/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l2048_langs.html)| [🤗 Hub](https://huggingface.co/facebook/mms-lid-2048) +4017 | FLEURS + VL + MMS-lab-U + MMS-unlab | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l4017.pt) | [download](https://dl.fbaipublicfiles.com/mms/lid/dict/l4017/dict.lang.txt) | [download](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l4017_langs.html)| [🤗 Hub](https://huggingface.co/facebook/mms-lid-4017) ## Commands to run inference @@ -185,7 +110,8 @@ Available options: cd bindings/python python3 setup.py install ``` - Train a [KenLM language model](https://github.com/flashlight/wav2letter/tree/main/recipes/rasr#language-model) and prepare a lexicon file in [this](https://dl.fbaipublicfiles.com/wav2letter/rasr/tutorial/lexicon.txt) format. + Train a [KenLM language model](https://github.com/flashlight/wav2letter/tree/main/recipes/rasr#language-model) and prepare a lexicon file in [this](https://dl.fbaipublicfiles.com/wav2letter/rasr/tutorial/lexicon.txt) format. Pretrained languages models from our paper can be found in [🤗 Hub](https://huggingface.co/facebook/mms-cclms/). + ``` LANG=<iso> # for example - 'eng', 'azj-script_latin' PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py --config-dir=examples/mms/asr/config \ @@ -246,10 +172,10 @@ We also provide an Ipython notebook example inside `lid/tutorial` folder [ipynb] ## Pretrained models -| Model | Link -|---|--- -MMS-300M | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_300m.pt) -MMS-1B | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_1b.pt) +| Model | Link | | +|---|---|--- +MMS-300M | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_300m.pt) | [🤗 Hub](https://huggingface.co/facebook/mms-300m) +MMS-1B | [download](https://dl.fbaipublicfiles.com/mms/pretraining/base_1b.pt) | [🤗 Hub](https://huggingface.co/facebook/mms-1b) Example commands to finetune the pretrained models can be found [here](https://github.com/facebookresearch/fairseq/tree/main/examples/wav2vec#fine-tune-a-pre-trained-model-with-ctc). From 8deb43af8c54d6840e5ba6e057acf715c4491f9c Mon Sep 17 00:00:00 2001 From: Andros Tjandra <38714605+androstj@users.noreply.github.com> Date: Sat, 17 Jun 2023 16:43:16 -0400 Subject: [PATCH 756/774] add new instructions on how to get manifest *.tsv file (#5207) Co-authored-by: Andros Tjandra <androstj@fb.com> --- examples/mms/README.md | 6 ++++-- examples/mms/misc/get_sample_size.py | 29 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 examples/mms/misc/get_sample_size.py diff --git a/examples/mms/README.md b/examples/mms/README.md index 814ef707c7..df673a4dbd 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -72,10 +72,12 @@ dev.ltr dev.uid # dev.tsv each line contains <audio> <number_of_sample> +# if user don't have this information, please run misc/get_sample_size.py + $ cat dev.tsv / -/path/to/audio_1 180000 -/path/to/audio_2 200000 +/path/to/audio_1.wav 180000 +/path/to/audio_2.wav 200000 $ cat dev.ltr t h i s | i s | o n e | diff --git a/examples/mms/misc/get_sample_size.py b/examples/mms/misc/get_sample_size.py new file mode 100644 index 0000000000..916647d1e3 --- /dev/null +++ b/examples/mms/misc/get_sample_size.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python -u +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +""" +Usage: + $ python misc/get_sample_size.py <input_file> > <output_file> + + <input_file> contains list of wav files + $ cat <input_file> + /path/to/audio_1.wav + /path/to/audio_2.wav + + <output_file> contains list of wav files paired with their number of samples + $ cat <output_file> + /path/to/audio_1.wav 180000 + /path/to/audio_2.wav 120000 +""" +import sys +import soundfile as sf + +if __name__ == "__main__": + files = sys.argv[1] + with open(files) as fr: + for fi in fr: + fi = fi.strip() + print(f'{fi}\t{sf.SoundFile(fi).frames}') From a29952ce6d313a4daf3e90647f8bf84cc6d4df6d Mon Sep 17 00:00:00 2001 From: Patrick von Platen <patrick.v.platen@gmail.com> Date: Tue, 20 Jun 2023 19:15:05 +0200 Subject: [PATCH 757/774] Update README.md (#5211) --- examples/mms/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/mms/README.md b/examples/mms/README.md index df673a4dbd..8790ac529a 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -170,7 +170,13 @@ $ PYTHONPATH='.' python3 examples/mms/lid/infer.py /path/to/dict/l126/ --path The above command assumes there is a file named `dict.lang.txt` in `/path/to/dict/l126/`. `<OUTDIR>/predictions.txt` will contain the predictions from the model for the audio files in `manifest.tsv`. We also provide an Ipython notebook example inside `lid/tutorial` folder [ipynb](https://github.com/facebookresearch/fairseq/blob/main/examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb) or [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/facebookresearch/fairseq/blob/main/examples/mms/lid/tutorial/MMS_LID_Inference_Colab.ipynb) - + +## Fine-tuning + +### ASR + +MMS Adapter fine-tuning has been added to the official 🤗 Transformers examples [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/speech-recognition#connectionist-temporal-classification-with-adapters). +For a more step-by-step explanation of how to fine-tune MMS, please have a look at the blog [**Fine-tuning MMS Adapter Models for Multi-Lingual ASR**](https://huggingface.co/blog/mms_adapters) on 🤗 blogs. ## Pretrained models From 31fba013a070eaff69dec8642e68e7134d60ab0f Mon Sep 17 00:00:00 2001 From: "Yun Wang (Maigo)" <yunwang@meta.com> Date: Fri, 23 Jun 2023 10:31:52 -0700 Subject: [PATCH 758/774] Register `weights` as a non-persistent buffer of `SinusoidalPositionalEmbedding` (#5213) --- .../pipeline_parallel_transformer/model.py | 10 -------- fairseq/models/masked_lm.py | 6 ----- .../models/transformer/transformer_decoder.py | 8 ------- .../transformer/transformer_decoder_aug.py | 8 ------- .../models/transformer/transformer_encoder.py | 8 ------- .../sinusoidal_positional_embedding.py | 24 ++++++++++++------- 6 files changed, 15 insertions(+), 49 deletions(-) diff --git a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py index 7bb0c9ada8..7873ac6791 100644 --- a/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py +++ b/fairseq/model_parallel/models/pipeline_parallel_transformer/model.py @@ -441,7 +441,6 @@ def convert_to_pipeline_parallel_state_dict(self, state_dict): # fmt: off if isinstance(module, TransformerEncoderEmbedding): new_state_dict[f'model.partitions.{pid}.{mid}.embed_tokens.weight'] = state_dict['encoder.embed_tokens.weight'] - new_state_dict[f'model.partitions.{pid}.{mid}.embed_positions._float_tensor'] = state_dict['encoder.embed_positions._float_tensor'] if isinstance(module, TransformerEncoderLayer): for suffix in encoder_key_suffixes: new_state_dict[f'model.partitions.{pid}.{mid}.{suffix}'] = state_dict[f'encoder.layers.{encoder_layer_idx}.{suffix}'] @@ -456,7 +455,6 @@ def convert_to_pipeline_parallel_state_dict(self, state_dict): new_state_dict[f'model.partitions.{pid}.{mid}.layer_norm.bias'] = state_dict['encoder.layer_norm.bias'] if isinstance(module, TransformerDecoderEmbedding): new_state_dict[f'model.partitions.{pid}.{mid}.embed_tokens.weight'] = state_dict['decoder.embed_tokens.weight'] - new_state_dict[f'model.partitions.{pid}.{mid}.embed_positions._float_tensor'] = state_dict['decoder.embed_positions._float_tensor'] if isinstance(module, TransformerDecoderOutputLayer): new_state_dict[f'model.partitions.{pid}.{mid}.output_projection.weight'] = state_dict['decoder.output_projection.weight'] # fmt: on @@ -741,14 +739,6 @@ def buffered_future_mask(self, tensor): def upgrade_state_dict_named(self, state_dict, name): """Upgrade a (possibly old) state dict for new versions of fairseq.""" - if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): - weights_key = "{}.embed_positions.weights".format(name) - if weights_key in state_dict: - del state_dict[weights_key] - state_dict[ - "{}.embed_positions._float_tensor".format(name) - ] = torch.FloatTensor(1) - for i in range(len(self.layers)): # update layer norms layer_norm_map = { diff --git a/fairseq/models/masked_lm.py b/fairseq/models/masked_lm.py index 5cb49dd77c..b71254cef8 100644 --- a/fairseq/models/masked_lm.py +++ b/fairseq/models/masked_lm.py @@ -294,12 +294,6 @@ def max_positions(self): return self.max_positions def upgrade_state_dict_named(self, state_dict, name): - if isinstance( - self.sentence_encoder.embed_positions, SinusoidalPositionalEmbedding - ): - state_dict[ - name + ".sentence_encoder.embed_positions._float_tensor" - ] = torch.FloatTensor(1) if not self.load_softmax: for k in list(state_dict.keys()): if ( diff --git a/fairseq/models/transformer/transformer_decoder.py b/fairseq/models/transformer/transformer_decoder.py index c22e5625d4..744c73f4f8 100644 --- a/fairseq/models/transformer/transformer_decoder.py +++ b/fairseq/models/transformer/transformer_decoder.py @@ -399,14 +399,6 @@ def buffered_future_mask(self, tensor): def upgrade_state_dict_named(self, state_dict, name): """Upgrade a (possibly old) state dict for new versions of fairseq.""" - if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): - weights_key = "{}.embed_positions.weights".format(name) - if weights_key in state_dict: - del state_dict[weights_key] - state_dict[ - "{}.embed_positions._float_tensor".format(name) - ] = torch.FloatTensor(1) - if f"{name}.output_projection.weight" not in state_dict: if self.share_input_output_embed: embed_out_key = f"{name}.embed_tokens.weight" diff --git a/fairseq/models/transformer/transformer_decoder_aug.py b/fairseq/models/transformer/transformer_decoder_aug.py index c5e7101794..b73c06e02a 100644 --- a/fairseq/models/transformer/transformer_decoder_aug.py +++ b/fairseq/models/transformer/transformer_decoder_aug.py @@ -305,14 +305,6 @@ def extract_features_scriptable( def upgrade_state_dict_named(self, state_dict, name): """Upgrade a (possibly old) state dict for new versions of fairseq.""" - if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): - weights_key = "{}.embed_positions.weights".format(name) - if weights_key in state_dict: - del state_dict[weights_key] - state_dict[ - "{}.embed_positions._float_tensor".format(name) - ] = torch.FloatTensor(1) - if f"{name}.output_projection.weight" not in state_dict: if self.share_input_output_embed: embed_out_key = f"{name}.embed_tokens.weight" diff --git a/fairseq/models/transformer/transformer_encoder.py b/fairseq/models/transformer/transformer_encoder.py index 17369ec8dc..a684fcb448 100644 --- a/fairseq/models/transformer/transformer_encoder.py +++ b/fairseq/models/transformer/transformer_encoder.py @@ -331,14 +331,6 @@ def max_positions(self): def upgrade_state_dict_named(self, state_dict, name): """Upgrade a (possibly old) state dict for new versions of fairseq.""" - if isinstance(self.embed_positions, SinusoidalPositionalEmbedding): - weights_key = "{}.embed_positions.weights".format(name) - if weights_key in state_dict: - print("deleting {0}".format(weights_key)) - del state_dict[weights_key] - state_dict[ - "{}.embed_positions._float_tensor".format(name) - ] = torch.FloatTensor(1) for i in range(self.num_layers): # update layer norms self.layers[i].upgrade_state_dict_named( diff --git a/fairseq/modules/sinusoidal_positional_embedding.py b/fairseq/modules/sinusoidal_positional_embedding.py index 4793ecfb52..e7ecd0f2c8 100644 --- a/fairseq/modules/sinusoidal_positional_embedding.py +++ b/fairseq/modules/sinusoidal_positional_embedding.py @@ -9,7 +9,7 @@ import torch import torch.onnx.operators from fairseq import utils -from torch import Tensor, nn +from torch import nn, Tensor class SinusoidalPositionalEmbedding(nn.Module): @@ -22,16 +22,23 @@ def __init__(self, embedding_dim, padding_idx, init_size=1024): super().__init__() self.embedding_dim = embedding_dim self.padding_idx = padding_idx if padding_idx is not None else 0 - self.weights = SinusoidalPositionalEmbedding.get_embedding( + self.register_buffer("weights", SinusoidalPositionalEmbedding.get_embedding( init_size, embedding_dim, padding_idx - ) - self.onnx_trace = False - self.register_buffer("_float_tensor", torch.FloatTensor(1)) + ), persistent=False) self.max_positions = int(1e5) + self.onnx_trace = False def prepare_for_onnx_export_(self): self.onnx_trace = True + def _load_from_state_dict(self, state_dict, prefix, *args, **kwargs): + # Ignore some deprecated keys that were used in older versions + deprecated_keys = ["weights", "_float_tensor"] + for key in deprecated_keys: + if prefix + key in state_dict: + del state_dict[prefix + key] + super()._load_from_state_dict(state_dict, prefix, *args, **kwargs) + @staticmethod def get_embedding( num_embeddings: int, embedding_dim: int, padding_idx: Optional[int] = None @@ -68,12 +75,11 @@ def forward( bspair = torch.onnx.operators.shape_as_tensor(input) bsz, seq_len = bspair[0], bspair[1] max_pos = self.padding_idx + 1 + seq_len - if self.weights is None or max_pos > self.weights.size(0): - # recompute/expand embeddings if needed + if max_pos > self.weights.size(0): + # expand embeddings if needed self.weights = SinusoidalPositionalEmbedding.get_embedding( max_pos, self.embedding_dim, self.padding_idx - ) - self.weights = self.weights.to(self._float_tensor) + ).to(self.weights) if incremental_state is not None: # positions is the same for every token when decoding a single step From 100cd91db19bb27277a06a25eb4154c805b10189 Mon Sep 17 00:00:00 2001 From: Egor Lakomkin <egor.lakomkin@gmail.com> Date: Fri, 7 Jul 2023 08:08:01 +0200 Subject: [PATCH 759/774] Make RotaryPositionalEmbedding jit-compatible (#5237) --- .../modules/rotary_positional_embedding.py | 15 +++++++------ tests/test_rotary_positional_embedding.py | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/fairseq/modules/rotary_positional_embedding.py b/fairseq/modules/rotary_positional_embedding.py index 84b88984ea..b74028b011 100644 --- a/fairseq/modules/rotary_positional_embedding.py +++ b/fairseq/modules/rotary_positional_embedding.py @@ -14,27 +14,26 @@ def __init__(self, dim, base=10000, precision=torch.half): super().__init__() inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim)) self.register_buffer("inv_freq", inv_freq) - self.seq_len_cached = None - self.cos_cached = None - self.sin_cached = None + self.seq_len_cached = 0 + self.cos_cached = torch.empty(self.seq_len_cached, 1, 1, dim) + self.sin_cached = torch.empty(self.seq_len_cached, 1, 1, dim) self.precision = precision - def forward(self, x, seq_len=None): + def forward(self, x, seq_len: int = 0): """ Args: x: Input x with T X B X C seq_len: Sequence length of input x """ - if seq_len != self.seq_len_cached: + if seq_len > self.seq_len_cached: self.seq_len_cached = seq_len t = torch.arange(seq_len, device=x.device).type_as(self.inv_freq) freqs = torch.einsum("i,j->ij", t, self.inv_freq) emb = torch.cat((freqs, freqs), dim=-1).to(x.device) - self.cos_cached = emb.cos()[:, None, None, :] - self.sin_cached = emb.sin()[:, None, None, :] + self.cos_cached = emb.cos().view(emb.size(0), 1, 1, emb.size(1)) + self.sin_cached = emb.sin().view(emb.size(0), 1, 1, emb.size(1)) return self.cos_cached, self.sin_cached - # rotary pos emb helpers: def rotate_half(x): x1, x2 = x[..., : x.shape[-1] // 2], x[..., x.shape[-1] // 2 :] diff --git a/tests/test_rotary_positional_embedding.py b/tests/test_rotary_positional_embedding.py index ea9f0bee12..7c44e86d5d 100644 --- a/tests/test_rotary_positional_embedding.py +++ b/tests/test_rotary_positional_embedding.py @@ -59,6 +59,27 @@ def test_apply_rotary_pos_emb(self): ) ) + def test_jit_compile_rope_module(self): + module_scripted = torch.jit.script(self.rope_pos_emd) + apply_rotary_scripted = torch.jit.script(apply_rotary_pos_emb) + # Test several different lengths + for T in [3, 5, 10]: + sample = torch.randn(T, self.B, self.C) + # Run forward pass with the original module + cos_original, sin_original = self.rope_pos_emd(sample, T) + query = sample.view(T, self.B, 1, self.C) + new_query, new_key = apply_rotary_pos_emb(query, query, cos_original, sin_original) + + # Run forward pass with the scripted module + cos_scripted, sin_scripted = module_scripted(sample, T) + new_query_scripted, new_key_scripted = apply_rotary_scripted(query, query, cos_scripted, sin_scripted) + + # Ensure the outputs are the same + self.assertTrue(torch.allclose(cos_original, cos_scripted)) + self.assertTrue(torch.allclose(sin_original, sin_scripted)) + self.assertTrue(torch.allclose(new_query, new_query_scripted)) + self.assertTrue(torch.allclose(new_key, new_key_scripted)) + if __name__ == "__main__": unittest.main() From 4db264940f281a6f47558d17387b1455d4abd8d9 Mon Sep 17 00:00:00 2001 From: Nguyen Tu Anh <nguyentuanh208@gmail.com> Date: Fri, 18 Aug 2023 17:10:40 +0200 Subject: [PATCH 760/774] Add batchnorm option to hubert/wav2vec2 positional convolution layer for hubert bf16 models (#5285) * add conv_batch_norm for hubert to support bf16 * linting Co-authored-by: Bowen Shi <bshi@meta.com> --- fairseq/models/hubert/hubert.py | 6 ++++++ fairseq/models/wav2vec/wav2vec2.py | 19 +++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/fairseq/models/hubert/hubert.py b/fairseq/models/hubert/hubert.py index 0c0349eb2f..cc3b777efd 100644 --- a/fairseq/models/hubert/hubert.py +++ b/fairseq/models/hubert/hubert.py @@ -191,6 +191,12 @@ class HubertConfig(FairseqDataclass): default=16, metadata={"help": "number of groups for convolutional positional embedding"}, ) + conv_pos_batch_norm: bool = field( + default=False, + metadata={ + "help": "use batch norm instead of weight norm in conv_pos (for bf16 models)" + }, + ) latent_temp: Tuple[float, float, float] = field( default=(2, 0.5, 0.999995), diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index be0cb4f536..f8dc6a8f5d 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -922,7 +922,7 @@ def forward(self, x): return x -def make_conv_pos(e, k, g): +def make_conv_pos(e, k, g, is_batch_norm=False): pos_conv = nn.Conv1d( e, e, @@ -935,8 +935,12 @@ def make_conv_pos(e, k, g): nn.init.normal_(pos_conv.weight, mean=0, std=std) nn.init.constant_(pos_conv.bias, 0) - pos_conv = nn.utils.weight_norm(pos_conv, name="weight", dim=2) - pos_conv = nn.Sequential(pos_conv, SamePad(k), nn.GELU()) + if not is_batch_norm: + pos_conv = nn.utils.weight_norm(pos_conv, name="weight", dim=2) + pos_conv = nn.Sequential(pos_conv, SamePad(k), nn.GELU()) + else: + batch_norm = nn.BatchNorm1d(e) + pos_conv = nn.Sequential(batch_norm, pos_conv, SamePad(k), nn.GELU()) return pos_conv @@ -1047,6 +1051,9 @@ def make_conv_block(e, k, g, l): self.embedding_dim, args.conv_pos, args.conv_pos_groups, + is_batch_norm=args.conv_pos_batch_norm + if hasattr(args, "conv_pos_batch_norm") + else False, ) self.layers = nn.ModuleList( @@ -1370,7 +1377,7 @@ def __init__(self, adapter_num, input_dim, hidden_dim, act_fn): and without using ModuleList orto speed up training throughput. """ super().__init__() - + self.adapter_num = adapter_num self.input_dim = input_dim self.hidden_dim = hidden_dim @@ -1405,7 +1412,7 @@ def reset_parameters(self): fan_in, _ = nn.init._calculate_fan_in_and_fan_out(self.W_b[ii]) bound = 1 / math.sqrt(fan_in) if fan_in > 0 else 0 nn.init.uniform_(self.b_b[ii], -bound, bound) - + nn.init.ones_(self.ln_W) nn.init.zeros_(self.ln_b) @@ -1418,7 +1425,7 @@ def forward(self, x, adapter_id): h = F.linear(h, self.W_b[ii], self.b_b[ii]) outputs = h return outputs - + def extra_repr(self): return ('adapter={}, input_dim={}, hidden_dim={}'.format(self.adapter_num, self.input_dim, self.hidden_dim)) From b5d89cddc9e4a0af831d2aafc1ba7dbf0f1b10d0 Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Thu, 7 Sep 2023 11:25:28 -0700 Subject: [PATCH 761/774] Update align_and_segment.py (#5317) Fix MMS alignment code --- examples/mms/data_prep/align_and_segment.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/mms/data_prep/align_and_segment.py b/examples/mms/data_prep/align_and_segment.py index cd5045eabc..de45d757bd 100644 --- a/examples/mms/data_prep/align_and_segment.py +++ b/examples/mms/data_prep/align_and_segment.py @@ -87,13 +87,14 @@ def get_alignments( blank = dictionary["<blank>"] targets = torch.tensor(token_indices, dtype=torch.int32).to(DEVICE) - input_lengths = torch.tensor(emissions.shape[0]) - target_lengths = torch.tensor(targets.shape[0]) - + + input_lengths = torch.tensor(emissions.shape[0]).unsqueeze(-1) + target_lengths = torch.tensor(targets.shape[0]).unsqueeze(-1) path, _ = F.forced_align( - emissions, targets, input_lengths, target_lengths, blank=blank + emissions.unsqueeze(0), targets.unsqueeze(0), input_lengths, target_lengths, blank=blank ) - path = path.to("cpu").tolist() + path = path.squeeze().to("cpu").tolist() + segments = merge_repeats(path, {v: k for k, v in dictionary.items()}) return segments, stride From e29f53bfea67fd9e81c3da374daac4b472ba6bda Mon Sep 17 00:00:00 2001 From: Piyush Kansal <piyush.kansal@gmail.com> Date: Fri, 15 Sep 2023 12:01:49 -0700 Subject: [PATCH 762/774] initial revision (#5328) --- fairseq/checkpoint_utils.py | 20 +- tests/test_checkpoint_utils.py | 2 - ...ckpoint_utils_for_task_level_attributes.py | 172 ++++++++++++++++++ 3 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 tests/test_checkpoint_utils_for_task_level_attributes.py diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index fb9a6679ba..4eff7807e2 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -104,7 +104,20 @@ def is_better(a, b): "checkpoint_last{}.pt".format(suffix) ] = not cfg.no_last_checkpoints - extra_state = {"train_iterator": epoch_itr.state_dict(), "val_loss": val_loss} + extra_state = { + "train_iterator": epoch_itr.state_dict(), + "val_loss": val_loss, + } + + # Going forward, different tasks could expose an API like this to dump all + # the checkpoint worthy attributes in a dictionary which then will be + # merged with the parent dictionary to create the "extra_state". This + # allows for an extensible yet simple design to checkpoint task level + # attributes + if hasattr(trainer.task, "get_checkpoint_dict"): + extra_state = {**extra_state, **trainer.task.get_checkpoint_dict()} + logger.info(f"{trainer.task.__class__} checkpoint worthy attributes are ready to be persisted with the checkpoint") + if hasattr(save_checkpoint, "best"): extra_state.update({"best": save_checkpoint.best}) @@ -275,6 +288,11 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): epoch=itr_state["epoch"], load_dataset=True, **passthrough_args ) epoch_itr.load_state_dict(itr_state) + + # Preload the observer stats for Supernet + supernet_cp_dict = extra_state.get("supernet", {}) + if supernet_cp_dict and hasattr(trainer.task, "set_checkpoint_dict"): + trainer.task.set_checkpoint_dict(supernet_cp_dict) else: epoch_itr = trainer.get_train_iterator( epoch=1, load_dataset=True, **passthrough_args diff --git a/tests/test_checkpoint_utils.py b/tests/test_checkpoint_utils.py index 0bc85562c7..f8cd943cfa 100644 --- a/tests/test_checkpoint_utils.py +++ b/tests/test_checkpoint_utils.py @@ -11,8 +11,6 @@ from io import StringIO from unittest.mock import patch -from omegaconf import OmegaConf - from fairseq import checkpoint_utils from tests.utils import ( create_dummy_data, diff --git a/tests/test_checkpoint_utils_for_task_level_attributes.py b/tests/test_checkpoint_utils_for_task_level_attributes.py new file mode 100644 index 0000000000..ed7ba59110 --- /dev/null +++ b/tests/test_checkpoint_utils_for_task_level_attributes.py @@ -0,0 +1,172 @@ +#!/usr/bin/env fbpython +# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +import contextlib +import logging +import unittest +from io import StringIO +from unittest.mock import MagicMock, patch + +import torch +from fairseq import checkpoint_utils, data +from omegaconf import OmegaConf + + +def mock_trainer(epoch, num_updates, iterations_in_epoch): + trainer = MagicMock() + trainer.load_checkpoint.return_value = { + "train_iterator": { + "epoch": epoch, + "iterations_in_epoch": iterations_in_epoch, + "shuffle": False, + }, + "supernet": checkpoint_dict()["supernet"], + } + trainer.get_num_updates.return_value = num_updates + trainer.task.get_checkpoint_dict.return_value = checkpoint_dict() + trainer.task.set_checkpoint_dict = MagicMock() + + return trainer + + +def checkpoint_dict(): + return { + "supernet": { + "observer_stats": { + ( + 4, + 16, + "MovingAveragePerChannelMinMax", + "MovingAveragePerChannelMinMax", + ): {"mod1": 1, "mod2": 2, "mod3": 3} + } + } + } + + +def mock_dict(): + d = MagicMock() + d.pad.return_value = 1 + d.eos.return_value = 2 + d.unk.return_value = 3 + return d + + +def get_trainer_and_epoch_itr(epoch, epoch_size, num_updates, iterations_in_epoch): + tokens = torch.LongTensor(list(range(epoch_size))).view(1, -1) + tokens_ds = data.TokenBlockDataset( + tokens, + sizes=[tokens.size(-1)], + block_size=1, + pad=0, + eos=1, + include_targets=False, + ) + trainer = mock_trainer(epoch, num_updates, iterations_in_epoch) + dataset = data.LanguagePairDataset( + tokens_ds, tokens_ds.sizes, mock_dict(), shuffle=False + ) + epoch_itr = data.EpochBatchIterator( + dataset=dataset, + collate_fn=dataset.collater, + batch_sampler=[[i] for i in range(epoch_size)], + ) + return trainer, epoch_itr + + +def get_mock_cfg(finetune_from_model): + cfg_mock = OmegaConf.create( + { + "checkpoint": { + "save_dir": None, + "optimizer_overrides": "{}", + "reset_dataloader": False, + "reset_meters": False, + "reset_optimizer": False, + "reset_lr_scheduler": False, + "finetune_from_model": finetune_from_model, + "model_parallel_size": 1, + "restore_file": "checkpoint_last.pt", + "no_save": False, + "save_interval_updates": 0, + "no_last_checkpoints": False, + "keep_interval_updates": 0, + "keep_last_epochs": 0, + "keep_best_checkpoints": 0, + }, + "common": { + "model_parallel_size": 1, + }, + } + ) + return cfg_mock + + +class TestCheckpointsForTaskLevelAttributes(unittest.TestCase): + def setUp(self) -> None: + self.cfg_mock = get_mock_cfg(None) + self.patches = { + "os.makedirs": MagicMock(), + "os.path.join": MagicMock(), + "os.path.isfile": MagicMock(return_value=True), + "os.path.isabs": MagicMock(return_value=False), + "fairseq.file_io.PathManager.exists": MagicMock(return_value=False), + } + self.applied_patches = [patch(p, d) for p, d in self.patches.items()] + [p.start() for p in self.applied_patches] + logging.disable(logging.CRITICAL) + + self.trainer, self.epoch_itr = get_trainer_and_epoch_itr(2, 150, 200, 50) + self.trainer.get_train_iterator = MagicMock(return_value=self.epoch_itr) + self.epoch_itr.next_epoch_itr(shuffle=False) + + checkpoint_utils.save_checkpoint( + self.cfg_mock.checkpoint, self.trainer, self.epoch_itr, None + ) + + def tearDown(self): + patch.stopall() + logging.disable(logging.NOTSET) + + def test_verify_checkpoint(self) -> None: + cp_dict = self.trainer.task.get_checkpoint_dict() + self.assertTrue(len(cp_dict) == 1) + self.assertTrue("supernet" in cp_dict) + self.assertTrue("observer_stats" in cp_dict["supernet"]) + self.assertTrue(len(cp_dict["supernet"]["observer_stats"]) == 1) + self.assertTrue( + ( + 4, + 16, + "MovingAveragePerChannelMinMax", + "MovingAveragePerChannelMinMax", + ) + in cp_dict["supernet"]["observer_stats"] + ) + self.assertTrue( + cp_dict["supernet"]["observer_stats"][ + ( + 4, + 16, + "MovingAveragePerChannelMinMax", + "MovingAveragePerChannelMinMax", + ) + ] + == {"mod1": 1, "mod2": 2, "mod3": 3} + ) + + def test_load_checkpoint(self) -> None: + with contextlib.redirect_stdout(StringIO()): + # Now, load checkpoint to ensure the respective logic works as expected + _, epoch_itr = checkpoint_utils.load_checkpoint( + self.cfg_mock.checkpoint, self.trainer + ) + + self.trainer.task.set_checkpoint_dict.assert_called_once_with( + checkpoint_dict()["supernet"] + ) + + +if __name__ == "__main__": + unittest.main() + From 7409af7f9a7b6ddac4cbfe7cafccc715b3c1b21e Mon Sep 17 00:00:00 2001 From: Piyush Kansal <piyush.kansal@gmail.com> Date: Fri, 15 Sep 2023 16:15:19 -0700 Subject: [PATCH 763/774] Keep task level checkpoint key name generic (#5330) --- fairseq/checkpoint_utils.py | 10 +++++----- ...eckpoint_utils_for_task_level_attributes.py | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/fairseq/checkpoint_utils.py b/fairseq/checkpoint_utils.py index 4eff7807e2..e3f316b9e7 100644 --- a/fairseq/checkpoint_utils.py +++ b/fairseq/checkpoint_utils.py @@ -116,7 +116,7 @@ def is_better(a, b): # attributes if hasattr(trainer.task, "get_checkpoint_dict"): extra_state = {**extra_state, **trainer.task.get_checkpoint_dict()} - logger.info(f"{trainer.task.__class__} checkpoint worthy attributes are ready to be persisted with the checkpoint") + logger.info(f"State of {trainer.task.__class__.__name__} is ready to be persisted with the checkpoint") if hasattr(save_checkpoint, "best"): extra_state.update({"best": save_checkpoint.best}) @@ -289,10 +289,10 @@ def load_checkpoint(cfg: CheckpointConfig, trainer, **passthrough_args): ) epoch_itr.load_state_dict(itr_state) - # Preload the observer stats for Supernet - supernet_cp_dict = extra_state.get("supernet", {}) - if supernet_cp_dict and hasattr(trainer.task, "set_checkpoint_dict"): - trainer.task.set_checkpoint_dict(supernet_cp_dict) + # Preload the checkpoint for the task + task_cp_dict = extra_state.get(trainer.task.__class__.__name__, {}) + if task_cp_dict and hasattr(trainer.task, "set_checkpoint_dict"): + trainer.task.set_checkpoint_dict(task_cp_dict) else: epoch_itr = trainer.get_train_iterator( epoch=1, load_dataset=True, **passthrough_args diff --git a/tests/test_checkpoint_utils_for_task_level_attributes.py b/tests/test_checkpoint_utils_for_task_level_attributes.py index ed7ba59110..53ab401f03 100644 --- a/tests/test_checkpoint_utils_for_task_level_attributes.py +++ b/tests/test_checkpoint_utils_for_task_level_attributes.py @@ -20,9 +20,10 @@ def mock_trainer(epoch, num_updates, iterations_in_epoch): "iterations_in_epoch": iterations_in_epoch, "shuffle": False, }, - "supernet": checkpoint_dict()["supernet"], + "FakeTask": checkpoint_dict()["FakeTask"], } trainer.get_num_updates.return_value = num_updates + trainer.task.__class__.__name__ = "FakeTask" trainer.task.get_checkpoint_dict.return_value = checkpoint_dict() trainer.task.set_checkpoint_dict = MagicMock() @@ -31,7 +32,7 @@ def mock_trainer(epoch, num_updates, iterations_in_epoch): def checkpoint_dict(): return { - "supernet": { + "FakeTask": { "observer_stats": { ( 4, @@ -131,9 +132,9 @@ def tearDown(self): def test_verify_checkpoint(self) -> None: cp_dict = self.trainer.task.get_checkpoint_dict() self.assertTrue(len(cp_dict) == 1) - self.assertTrue("supernet" in cp_dict) - self.assertTrue("observer_stats" in cp_dict["supernet"]) - self.assertTrue(len(cp_dict["supernet"]["observer_stats"]) == 1) + self.assertTrue("FakeTask" in cp_dict) + self.assertTrue("observer_stats" in cp_dict["FakeTask"]) + self.assertTrue(len(cp_dict["FakeTask"]["observer_stats"]) == 1) self.assertTrue( ( 4, @@ -141,10 +142,10 @@ def test_verify_checkpoint(self) -> None: "MovingAveragePerChannelMinMax", "MovingAveragePerChannelMinMax", ) - in cp_dict["supernet"]["observer_stats"] + in cp_dict["FakeTask"]["observer_stats"] ) self.assertTrue( - cp_dict["supernet"]["observer_stats"][ + cp_dict["FakeTask"]["observer_stats"][ ( 4, 16, @@ -163,10 +164,9 @@ def test_load_checkpoint(self) -> None: ) self.trainer.task.set_checkpoint_dict.assert_called_once_with( - checkpoint_dict()["supernet"] + checkpoint_dict()["FakeTask"] ) if __name__ == "__main__": unittest.main() - From c7c478b92fe135838a2b9ec8341495c732a92401 Mon Sep 17 00:00:00 2001 From: Junteng Jia <juntengjia@hotmail.com> Date: Mon, 9 Oct 2023 14:13:06 -0700 Subject: [PATCH 764/774] fix iterator when loading from checkpoint (#5344) Co-authored-by: Junteng Jia <juntengjia@fb.com> --- fairseq/data/iterators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fairseq/data/iterators.py b/fairseq/data/iterators.py index a488265137..6a5a42a9cf 100644 --- a/fairseq/data/iterators.py +++ b/fairseq/data/iterators.py @@ -524,7 +524,7 @@ def _get_iterator_for_epoch( # TODO: Below is a lazy implementation which discard the final batch regardless # of whether it is a full batch or not. - total_num_itrs = len(self.epoch_batch_sampler) - 1 + total_num_itrs = len(itr) - 1 itr.take(total_num_itrs) logger.info(f"skip final residual batch, total_num_itrs = {total_num_itrs}") From da8fb630880d529ab47e53381c30ddc8ad235216 Mon Sep 17 00:00:00 2001 From: Can Balioglu <cbalioglu@users.noreply.github.com> Date: Tue, 10 Oct 2023 13:36:53 -0400 Subject: [PATCH 765/774] Change Meta AI to FAIR (#5346) --- examples/mms/MODEL_CARD.md | 2 +- examples/moe_lm/data_card.md | 10 +++++----- examples/moe_lm/model_card.md | 4 ++-- examples/speech_to_speech/asr_bleu/README.md | 4 ++-- examples/xglm/XStoryCloze.md | 2 +- examples/xglm/model_card.md | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/mms/MODEL_CARD.md b/examples/mms/MODEL_CARD.md index eccab62bd7..63f997fb4d 100644 --- a/examples/mms/MODEL_CARD.md +++ b/examples/mms/MODEL_CARD.md @@ -2,7 +2,7 @@ ## Model details -**Organization developing the model** The FAIR team of Meta AI. +**Organization developing the model** The FAIR team **Model version** This is version 1 of the model. diff --git a/examples/moe_lm/data_card.md b/examples/moe_lm/data_card.md index a69cdc974b..54e694b620 100644 --- a/examples/moe_lm/data_card.md +++ b/examples/moe_lm/data_card.md @@ -6,12 +6,12 @@ We follow the recommendations of Gebru et al. (2018) and provide a datacard for ## Motivation * **For what purpose was the dataset created? Was there a specific task in mind? Was there a specific gap that needed to be filled? Please provide a description.** The pre-training data for training the 1.1 T model was created by a union of six English language datasets, including five datasets used by RoBERTa (Liu et al 2019) and the English subset of CC 100. These purpose of creating this dataset was to pre-train the language model. - + * **Who created the dataset (e.g., which team, research group) and on behalf of which entity (e.g., company, institution, organization)?** -Meta AI. - +FAIR (Fundamental Artificial Intelligence Research) + * **Who funded the creation of the dataset? If there is an associated grant, please provide the name of the grantor and the grant name and number.** -Meta AI. +FAIR (Fundamental Artificial Intelligence Research) * **Any other comments?** No. @@ -183,7 +183,7 @@ No. ## Maintenance * **Who is supporting/hosting/maintaining the dataset?** -Meta AI. +FAIR (Fundamental Artificial Intelligence Research) * **How can the owner/curator/manager of the dataset be contacted (e.g., email address)?** Refer to the main document. diff --git a/examples/moe_lm/model_card.md b/examples/moe_lm/model_card.md index 22cd551f8d..a1cd68116a 100644 --- a/examples/moe_lm/model_card.md +++ b/examples/moe_lm/model_card.md @@ -2,7 +2,7 @@ ## Version 1.0.0 ### Model developer -Meta AI +FAIR (Fundamental Artificial Intelligence Research) ### Model type An autoregressive English language model trained on a union of six English language models. We explore dense and sparse (MoE based) architectures in the paper. @@ -132,7 +132,7 @@ A dataset extracted from CommonCrawl snapshots between January 2018 and December The 1.1T parameter model was evaluated on the StereoSet and CrowS pairs dataset for inherent bias in the model, and bias as a result of the data. Similar to StereoSet, we observe that both the dense and MoE models get worse in terms of the Stereotype Score (SS) with scale. ### Privacy and security -The 1.1T model did not have any special Privacy and Security considerations. The training data and evaluation data were both public and went through standard Meta AI Privacy and licensing procedures. +The 1.1T model did not have any special Privacy and Security considerations. The training data and evaluation data were both public and went through standard Meta privacy and licensing procedures. ### Transparency and control In the spirit of transparency and accountability we have created this model card for the 1.1T parameter model and a data card for the training data (referenced in Artetxe et al. (2021)). diff --git a/examples/speech_to_speech/asr_bleu/README.md b/examples/speech_to_speech/asr_bleu/README.md index b808b136dc..6a7ea7fcef 100644 --- a/examples/speech_to_speech/asr_bleu/README.md +++ b/examples/speech_to_speech/asr_bleu/README.md @@ -1,6 +1,6 @@ # ASR-BLEU evaluation toolkit -This toolkit provides a set of public ASR models used for evaluation of different speech-to-speech translation systems at Meta AI. It enables easier score comparisons between different system's outputs. +This toolkit provides a set of public ASR models used for evaluation of different speech-to-speech translation systems at FAIR. It enables easier score comparisons between different system's outputs. The ASRGenerator wraps different CTC-based ASR models from HuggingFace and fairseq code bases. Torchaudio CTC decoder is built on top of it to decode given audio files. @@ -31,4 +31,4 @@ python compute_asr_bleu.py --lang <LANG> \ --reference_format txt ``` -For more details about arguments please see the script argparser help. \ No newline at end of file +For more details about arguments please see the script argparser help. diff --git a/examples/xglm/XStoryCloze.md b/examples/xglm/XStoryCloze.md index d49840ab61..9b0fce0715 100644 --- a/examples/xglm/XStoryCloze.md +++ b/examples/xglm/XStoryCloze.md @@ -1,4 +1,4 @@ -XStoryCloze consists of professional translation of the validation split of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. This dataset is released by Meta AI alongside the paper [Few-shot Learning with Multilingual Generative Language Models. EMNLP 2022](https://arxiv.org/abs/2112.10668). +XStoryCloze consists of professional translation of the validation split of the [English StoryCloze dataset](https://cs.rochester.edu/nlp/rocstories/) (Spring 2016 version) to 10 other languages. This dataset is released by FAIR (Fundamental Artificial Intelligence Research) alongside the paper [Few-shot Learning with Multilingual Generative Language Models. EMNLP 2022](https://arxiv.org/abs/2112.10668). # Languages ru, zh (Simplified), es (Latin America), ar, hi, id, te, sw, eu, my. diff --git a/examples/xglm/model_card.md b/examples/xglm/model_card.md index af33ba5bd8..2656ec5d63 100644 --- a/examples/xglm/model_card.md +++ b/examples/xglm/model_card.md @@ -2,7 +2,7 @@ ## Version 1.0.0 ### Model developer -Meta AI +FAIR (Fundamental Artificial Intelligence Research) ### Model type A family of multilingual autoregressive language models (ranging from 564 million to 7.5 billion parameters) trained on a balanced corpus of a diverse set of languages. The language model can learn tasks from natural language descriptions and a few examples. @@ -31,7 +31,7 @@ The model was evaluated on hate speech detection and occupation identification. ## Metrics ### Model performance measures The XGLM model was primarily evaluated on -1. Zero shot and few shot learning by looking at per-language performance on tasks spanning commonsense reasoning (XCOPA, XWinograd), natural language inference (XNLI) and paraphrasing (PAWS-X). The model is also evaluated on XStoryCloze, a new dataset created by Meta AI. +1. Zero shot and few shot learning by looking at per-language performance on tasks spanning commonsense reasoning (XCOPA, XWinograd), natural language inference (XNLI) and paraphrasing (PAWS-X). The model is also evaluated on XStoryCloze, a new dataset created by FAIR (Fundamental Artificial Intelligence Research). 2. Cross lingual transfer through templates and few-shot examples. 3. Knowledge probing - Evaluate to what extent the XGLM model can effectively store factual knowledge in different languages using the mLAMA benchmark. 4. Translation - We report machine translation results on WMT benchmarks and a subset of FLORES-101 in the main paper. @@ -50,7 +50,7 @@ The Cross-lingual Natural Language Inference (XNLI) corpus is the extension of t ### XStoryCloze #### Description -A new dataset created by Meta AI along side this work by translating the validation split of the English StoryCloze dataset (Mostafazadeh et al., 2016) (Spring 2016 version) to 10 other typologically diverse languages (ru, zh Simplified, es Latin America, ar, hi, id, te, sw, eu, my). +A new dataset created by FAIR along side this work by translating the validation split of the English StoryCloze dataset (Mostafazadeh et al., 2016) (Spring 2016 version) to 10 other typologically diverse languages (ru, zh Simplified, es Latin America, ar, hi, id, te, sw, eu, my). ### XCOPA (Ponti et al., 2020) #### Description @@ -85,7 +85,7 @@ More details on the CC100-XL dataset can be found in the Appendix section of the The XGLM model was evaluated on Hate speech and bias identification datasets. For hate speech, we observe that across the 5 languages in the dataset, in context learning results are only slightly better than random (50%). Another interesting observation is that most few shot results are worse than zero-shot, which indicates that the model is not able to utilize examples using the templates described in the paper. For bias identification, the XGLM (6.7B) English only model achieves the best performance on English and Spanish, while the GPT-3 model of comparable size (6.7B) model achieves the best in French. On certain occupations (e.g. model and teacher), XGLM 6.7B En only model and GPT-3 (6.7B) have very significant bias while XGLM 7.5B is much less biased. ### Privacy and security -The XGLM model did not have any special Privacy and Security considerations. The training data and evaluation data were both public and went through standard Meta AI Privacy and licensing procedures. +The XGLM model did not have any special Privacy and Security considerations. The training data and evaluation data were both public and went through standard Meta privacy and licensing procedures. ### Transparency and control In the spirit of transparency and accountability we have created this model card and a data card for the CC100-XL which can be found in the Appendix section of the paper. From fad2c4d1ebe14d974876de52dcb06db6d99b0b4a Mon Sep 17 00:00:00 2001 From: Yoach Lacombe <52246514+ylacombe@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:38:14 +0100 Subject: [PATCH 766/774] Update README.md (#5407) --- examples/mms/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/mms/README.md b/examples/mms/README.md index 8790ac529a..0460dd5f93 100644 --- a/examples/mms/README.md +++ b/examples/mms/README.md @@ -177,6 +177,10 @@ We also provide an Ipython notebook example inside `lid/tutorial` folder [ipynb] MMS Adapter fine-tuning has been added to the official 🤗 Transformers examples [here](https://github.com/huggingface/transformers/tree/main/examples/pytorch/speech-recognition#connectionist-temporal-classification-with-adapters). For a more step-by-step explanation of how to fine-tune MMS, please have a look at the blog [**Fine-tuning MMS Adapter Models for Multi-Lingual ASR**](https://huggingface.co/blog/mms_adapters) on 🤗 blogs. + +### TTS + +For a guide on how to fine-tune MMS TTS checkpoints using the 🤗 Transformer implementation, please have a look at this [repository](https://github.com/ylacombe/finetune-hf-vits). ## Pretrained models From 3f0f20f2d12403629224347664b3e75c13b2c8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Merx?= <raphaelmerx@users.noreply.github.com> Date: Thu, 25 Jan 2024 02:54:38 +0800 Subject: [PATCH 767/774] MMS alignment README fixes (#5432) * Mention sox install through apt, on top of the Python wrapper * Fix argument name in example command --- examples/mms/data_prep/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/mms/data_prep/README.md b/examples/mms/data_prep/README.md index 4a06e7fef9..ccc3e5bbe1 100644 --- a/examples/mms/data_prep/README.md +++ b/examples/mms/data_prep/README.md @@ -14,8 +14,8 @@ We describe the process of aligning long audio files with their transcripts and - Step 3: Install a few other dependencies ``` - pip install sox - pip install dataclasses + apt install sox + pip install sox dataclasses ``` - Step 4: Create a text file containing the transcript for a (long) audio file. Each line in the text file will correspond to a separate audio segment that will be generated upon alignment. @@ -29,7 +29,7 @@ We describe the process of aligning long audio files with their transcripts and - Step 5: Run forced alignment and segment the audio file into shorter segments. ``` - python align_and_segment.py --audio /path/to/audio.wav --textfile /path/to/textfile --lang <iso> --outdir /path/to/output --uroman /path/to/uroman/bin + python align_and_segment.py --audio /path/to/audio.wav --text_filepath /path/to/textfile --lang <iso> --outdir /path/to/output --uroman /path/to/uroman/bin ``` The above code will generated the audio segments under output directory based on the content of each line in the input text file. The `manifest.json` file consisting of the of segmented audio filepaths and their corresponding transcripts. From 34973a94d09ecc12092a5ecc8afece5e536b7692 Mon Sep 17 00:00:00 2001 From: Jiatong <728307998@qq.com> Date: Mon, 26 Feb 2024 15:15:44 -0500 Subject: [PATCH 768/774] Multires hubert (#5363) * multires hubert core * update core codebase on multiresolution hubert * add examples * adding entries to pretrained models (not finished) * add other abalation models * add multilinugal * add decode.sh train.sh finetune.sh and update links for README.md * fix readme * clean the codebase --------- Co-authored-by: Anna Sun <13106449+annasun28@users.noreply.github.com> --- examples/mr_hubert/README.md | 187 +++ examples/mr_hubert/config/decode/infer.yaml | 30 + .../mr_hubert/config/decode/infer_lm.yaml | 37 + .../config/decode/run/submitit_slurm.yaml | 17 + .../decode/run/submitit_slurm_8gpu.yaml | 17 + .../mr_hubert/config/finetune/base_100h.yaml | 97 ++ .../config/finetune/base_100h_large.yaml | 97 ++ .../mr_hubert/config/finetune/base_10h.yaml | 101 ++ .../config/finetune/base_10h_large.yaml | 101 ++ .../mr_hubert/config/finetune/base_1h.yaml | 100 ++ .../config/finetune/base_1h_large.yaml | 99 ++ .../pretrain/mrhubert_base_librispeech.yaml | 103 ++ .../pretrain/mrhubert_large_librilight.yaml | 107 ++ .../config/pretrain/run/submitit_reg.yaml | 20 + examples/mr_hubert/decode.sh | 46 + examples/mr_hubert/finetune.sh | 46 + examples/mr_hubert/simple_kmeans | 1 + examples/mr_hubert/train.sh | 45 + fairseq/models/multires_hubert/__init__.py | 2 + .../models/multires_hubert/multires_hubert.py | 1231 +++++++++++++++++ .../multires_hubert/multires_hubert_asr.py | 376 +++++ fairseq/models/wav2vec/wav2vec2.py | 19 +- fairseq/tasks/multires_hubert_pretraining.py | 204 +++ 23 files changed, 3077 insertions(+), 6 deletions(-) create mode 100644 examples/mr_hubert/README.md create mode 100644 examples/mr_hubert/config/decode/infer.yaml create mode 100644 examples/mr_hubert/config/decode/infer_lm.yaml create mode 100644 examples/mr_hubert/config/decode/run/submitit_slurm.yaml create mode 100644 examples/mr_hubert/config/decode/run/submitit_slurm_8gpu.yaml create mode 100644 examples/mr_hubert/config/finetune/base_100h.yaml create mode 100644 examples/mr_hubert/config/finetune/base_100h_large.yaml create mode 100644 examples/mr_hubert/config/finetune/base_10h.yaml create mode 100644 examples/mr_hubert/config/finetune/base_10h_large.yaml create mode 100644 examples/mr_hubert/config/finetune/base_1h.yaml create mode 100644 examples/mr_hubert/config/finetune/base_1h_large.yaml create mode 100644 examples/mr_hubert/config/pretrain/mrhubert_base_librispeech.yaml create mode 100644 examples/mr_hubert/config/pretrain/mrhubert_large_librilight.yaml create mode 100644 examples/mr_hubert/config/pretrain/run/submitit_reg.yaml create mode 100755 examples/mr_hubert/decode.sh create mode 100755 examples/mr_hubert/finetune.sh create mode 120000 examples/mr_hubert/simple_kmeans create mode 100755 examples/mr_hubert/train.sh create mode 100644 fairseq/models/multires_hubert/__init__.py create mode 100644 fairseq/models/multires_hubert/multires_hubert.py create mode 100644 fairseq/models/multires_hubert/multires_hubert_asr.py create mode 100644 fairseq/tasks/multires_hubert_pretraining.py diff --git a/examples/mr_hubert/README.md b/examples/mr_hubert/README.md new file mode 100644 index 0000000000..e72c09c047 --- /dev/null +++ b/examples/mr_hubert/README.md @@ -0,0 +1,187 @@ +# MR-HuBERT + +## Pre-trained models + +### Main models +Model | Pretraining Data | Model | Paper Reference +|---|---|---|--- +MR-HuBERT Base (~97M) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/mono_base/mrhubert_mono_base.pt) | mono\_base +MR-HuBERT Base (~321M) | [Libri-Light](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/mono_large/mrhubert_mono_large.pt) | mono\_large +Multilingual MR-HuBERT Base (~97M) | [Voxpopuli](https://github.com/facebookresearch/voxpopuli) 100k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/multi_base/multi_base.pt) | multi\_base +Multilingual MR-HuBERT Large (~321M) | [Voxpopuli](https://github.com/facebookresearch/voxpopuli) 100k hr | [download 400k steps](https://dl.fbaipublicfiles.com/mrhubert/multi_large/multi_large_400k.pt) or [download 600k steps](https://dl.fbaipublicfiles.com/mrhubert/multi_large/multi_large_600k.pt) | Not in the paper + + +### Abalation models +Model | Pretraining Data | Model | Paper Reference +|---|---|---|--- +MR-HuBERT Base (2-4-6 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b1-a/b1-a.pt) | (B.1)-a +MR-HuBERT Base (5-2-5 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b1-b/b1-b.pt) | (B.1)-b +MR-HuBERT Base (6-4-2 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b1-c/b1-c.pt) | (B.1)-c +MR-HuBERT Base (3res 3-2-2-2-3 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b2-a/b2-a.pt) | (B.2)-a +MR-HuBERT Base (3res 2-2-4-2-2 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b2-b/b2-b.pt) | (B.2)-b +MR-HuBERT Base (3res 2-2-2-2-2 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b2-c/b2-c.pt) | (B.2)-c +MR-HuBERT Base (Simple sampling) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b3-a/b3-a.pt) | (B.3)-a +MR-HuBERT Base (Single target) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b4-a/b4-a.pt) | (B.4)-a +MR-HuBERT Base (Simple Sampling + single target) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b4-b/b4-b.pt) | (B.4)-b +MR-HuBERT Base (Mono-resolution 20ms) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b5-a/b5-a.pt) | (B.5)-a +MR-HuBERT Base (3-3-3 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b6-a/b6-a.pt) | (B.6)-a +MR-HuBERT Base (Mono-resolution 20ms, 3-3-3 lyrs) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b6-b/b6-b.pt) | (B.6)-b +MR-HuBERT Base (HuBERT 20ms&40ms units) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b7-a/b7-a.pt) | (B.7)-a +MR-HuBERT Base (Encodec 50Hz unit) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b7-b/b7-b.pt) | (B.7)-b +MR-HuBERT Base (Encodec 50Hz units and 25Hz units) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b7-c/b7-c.pt) | (B.7)-c +MR-HuBERT Base (Encodec 50Hz units stream 0&1 ) | [Librispeech](http://www.openslr.org/12) 960 hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b7-d/b7-d.pt) | (B.7)-d +MR-HuBERT Large (no audio norm) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-a/b8-a.pt) | (B.8)-a +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-b/b8-b.pt) | (B.8)-b +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-c/b8-c.pt) | (B.8)-c +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-d/b8-d.pt) | (B.8)-d +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-e/b8-e.pt) | (B.8)-e +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-f/b8-f.pt) | (B.8)-f +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-g/b8-g.pt) | (B.8)-g +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-h/b8-h.pt) | (B.8)-h +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-i/b8-i.pt) | (B.8)-i +MR-HuBERT Large (check paper ) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/b8-j/b8-j.pt) | (B.8)-j +Multilingual MR-HuBERT Large (Simple sampling) | [Voxpopuli](https://github.com/facebookresearch/voxpopuli) 100k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/multi_large_simple/multi_large_simple.pt) | Not in paper +MR-HuBERT xLarge (from HuBERT-base label) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/mono_xlarge/v1.pt) | Not in paper +MR-HuBERT xLarge (from HuBERT-large label) | [LibriLight](https://github.com/facebookresearch/libri-light) 60k hr | [download](https://dl.fbaipublicfiles.com/mrhubert/mono_xlarge/v2.pt) | Not in paper + +## Load a model +``` +ckpt_path = "/path/to/the/checkpoint.pt" +models, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path]) +model = models[0] +``` + +## Train a new model + +### Data preparation + +Follow the steps in `./simple_kmeans` to create: +- `{train,valid}.tsv` waveform list files with length information +``` +/path/to/your/audio/files +file1.wav\t160000 +file2.wav\t154600 +... +filen.wav\t54362 +``` +- `{train,valid}.km` frame-aligned pseudo label files (the order is the same as wavefiles in the tsv file). +``` +44 44 44 48 48 962 962 962 962 962 962 962 962 967 967 967 967 967 967 967 967 370 852 370 ... 18 18 745 745 +44 44 44 48 48 962 962 962 147 147 147 147 147 147 147 147 147 147 147 147 176 176 271 271 ... 27 27 745 745 +... +44 44 44 48 962 962 962 962 962 962 377 377 377 77 77 852 696 694 433 578 578 82 740 622 ... 27 27 745 745 +``` +- `dict.km.txt` a dummy dictionary (first column is id, the second is dummy one) +``` +0 1 +1 1 +2 1 +... +999 1 +``` + +The `label_rate` is the same as the feature frame rate used for clustering, +which is 100Hz for MFCC features and 50Hz for HuBERT features by default. + +### Pre-train a MR-HuBERT model + +Suppose `{train,valid}.tsv` are saved at `/path/to/data`, `{train,valid}.km` +are saved at `/path/to/labels`, and the label rate is 100Hz. + +To train a base model (12 layer transformer), run: +```sh +$ python fairseq_cli/hydra_train.py \ + --config-dir /path/to/fairseq-py/examples/mr_hubert/config/pretrain \ + --config-name mrhubert_base_librispeech \ + task.data=/path/to/data task.label_dir=/path/to/labels \ + task.labels='["km"]' model.label_rate=100 \ + task.label_rate_ratios='[1, 2]' \ +``` + +Please see sample pre-training scripts `train.sh` for an example script. + +### Fine-tune a MR-HuBERT model with a CTC loss + +Suppose `{train,valid}.tsv` are saved at `/path/to/data`, and their +corresponding character transcripts `{train,valid}.ltr` are saved at +`/path/to/trans`. A typical ltr file is with the same order of tsv waveform files as +``` +HOW | ARE | YOU +... +THANK | YOU +``` + +To fine-tune a pre-trained MR-HuBERT model at `/path/to/checkpoint`, run +```sh +$ python fairseq_cli/hydra_train.py \ + --config-dir /path/to/fairseq-py/examples/mr_hubert/config/finetune \ + --config-name base_10h \ + task.data=/path/to/data task.label_dir=/path/to/trans \ + model.w2v_path=/path/to/checkpoint +``` + +Please see sample fine-tuning scripts `finetune.sh` for an example script. + +### Decode a MR-HuBERT model + +Suppose the `test.tsv` and `test.ltr` are the waveform list and transcripts of +the split to be decoded, saved at `/path/to/data`, and the fine-tuned model is +saved at `/path/to/checkpoint`. + + +We support three decoding modes: +- Viterbi decoding: greedy decoding without a language model +- KenLM decoding: decoding with an arpa-format KenLM n-gram language model +- Fairseq-LM deocding: decoding with a Fairseq neural language model (not fully tested) + + +#### Viterbi decoding + +`task.normalize` needs to be consistent with the value used during fine-tuning. +Decoding results will be saved at +`/path/to/experiment/directory/decode/viterbi/test`. + +```sh +$ python examples/speech_recognition/new/infer.py \ + --config-dir /path/to/fairseq-py/examples/mr_hubert/config/decode \ + --config-name infer \ + task.data=/path/to/data \ + task.normalize=[true|false] \ + decoding.exp_dir=/path/to/experiment/directory \ + common_eval.path=/path/to/checkpoint + dataset.gen_subset=test \ +``` + +#### KenLM / Fairseq-LM decoding + +Suppose the pronunciation lexicon and the n-gram LM are saved at +`/path/to/lexicon` and `/path/to/arpa`, respectively. Decoding results will be +saved at `/path/to/experiment/directory/decode/kenlm/test`. + +```sh +$ python examples/speech_recognition/new/infer.py \ + --config-dir /path/to/fairseq-py/examples/mr_hubert/config/decode \ + --config-name infer_lm \ + task.data=/path/to/data \ + task.normalize=[true|false] \ + decoding.exp_dir=/path/to/experiment/directory \ + common_eval.path=/path/to/checkpoint + dataset.gen_subset=test \ + decoding.decoder.lexicon=/path/to/lexicon \ + decoding.decoder.lmpath=/path/to/arpa +``` + +The command above uses the default decoding hyperparameter, which can be found +in `examples/speech_recognition/hydra/decoder.py`. These parameters can be +configured from the command line. For example, to search with a beam size of +500, we can append the command above with `decoding.decoder.beam=500`. +Important parameters include: +- decoding.decoder.beam +- decoding.decoder.beamthreshold +- decoding.decoder.lmweight +- decoding.decoder.wordscore +- decoding.decoder.silweight + +To decode with a Fairseq LM, you may check the usage examples in wav2vec2 or hubert examples. + +Please see sample decoding scripts `decode.sh` for an example script. diff --git a/examples/mr_hubert/config/decode/infer.yaml b/examples/mr_hubert/config/decode/infer.yaml new file mode 100644 index 0000000000..eff39802e7 --- /dev/null +++ b/examples/mr_hubert/config/decode/infer.yaml @@ -0,0 +1,30 @@ +# @package _group_ + +defaults: + - model: null + +hydra: + run: + dir: ${common_eval.results_path}/viterbi + sweep: + dir: ${common_eval.results_path} + subdir: viterbi + +task: + _name: multires_hubert_pretraining + single_target: true + fine_tuning: true + label_rate_ratios: ??? + data: ??? + normalize: false + +decoding: + type: viterbi + unique_wer_file: true +common_eval: + results_path: ??? + path: ??? + post_process: letter +dataset: + max_tokens: 1100000 + gen_subset: ??? diff --git a/examples/mr_hubert/config/decode/infer_lm.yaml b/examples/mr_hubert/config/decode/infer_lm.yaml new file mode 100644 index 0000000000..535b950775 --- /dev/null +++ b/examples/mr_hubert/config/decode/infer_lm.yaml @@ -0,0 +1,37 @@ +# @package _group_ + +defaults: + - model: null + +hydra: + run: + dir: ${common_eval.results_path}/beam${decoding.beam}_th${decoding.beamthreshold}_lmw${decoding.lmweight}_wrd${decoding.wordscore}_sil${decoding.silweight} + sweep: + dir: ${common_eval.results_path} + subdir: beam${decoding.beam}_th${decoding.beamthreshold}_lmw${decoding.lmweight}_wrd${decoding.wordscore}_sil${decoding.silweight} + +task: + _name: multires_hubert_pretraining + single_target: true + fine_tuning: true + data: ??? + label_rate_ratios: ??? + normalize: ??? + +decoding: + type: kenlm + lexicon: ??? + lmpath: ??? + beamthreshold: 100 + beam: 500 + lmweight: 1.5 + wordscore: -1 + silweight: 0 + unique_wer_file: true +common_eval: + results_path: ??? + path: ??? + post_process: letter +dataset: + max_tokens: 1100000 + gen_subset: ??? diff --git a/examples/mr_hubert/config/decode/run/submitit_slurm.yaml b/examples/mr_hubert/config/decode/run/submitit_slurm.yaml new file mode 100644 index 0000000000..0b8065832e --- /dev/null +++ b/examples/mr_hubert/config/decode/run/submitit_slurm.yaml @@ -0,0 +1,17 @@ +# @package _global_ +hydra: + launcher: + cpus_per_task: ${distributed_training.distributed_world_size} + gpus_per_node: ${distributed_training.distributed_world_size} + tasks_per_node: ${hydra.launcher.gpus_per_node} + nodes: 1 + mem_gb: 200 + timeout_min: 4320 + max_num_timeout: 50 + name: ${hydra.job.config_name} + submitit_folder: ${hydra.sweep.dir}/submitit + +distributed_training: + distributed_world_size: 1 + distributed_no_spawn: true + distributed_port: 29761 diff --git a/examples/mr_hubert/config/decode/run/submitit_slurm_8gpu.yaml b/examples/mr_hubert/config/decode/run/submitit_slurm_8gpu.yaml new file mode 100644 index 0000000000..2f669f3763 --- /dev/null +++ b/examples/mr_hubert/config/decode/run/submitit_slurm_8gpu.yaml @@ -0,0 +1,17 @@ +# @package _global_ +hydra: + launcher: + cpus_per_task: ${distributed_training.distributed_world_size} + gpus_per_node: ${distributed_training.distributed_world_size} + tasks_per_node: ${hydra.launcher.gpus_per_node} + nodes: 1 + mem_gb: 200 + timeout_min: 4320 + max_num_timeout: 50 + name: ${hydra.job.config_name} + submitit_folder: ${hydra.sweep.dir}/submitit + +distributed_training: + distributed_world_size: 8 + distributed_no_spawn: true + distributed_port: 29761 diff --git a/examples/mr_hubert/config/finetune/base_100h.yaml b/examples/mr_hubert/config/finetune/base_100h.yaml new file mode 100644 index 0000000000..c52a118cb8 --- /dev/null +++ b/examples/mr_hubert/config/finetune/base_100h.yaml @@ -0,0 +1,97 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tblog + seed: 1337 + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +distributed_training: + ddp_backend: c10d + find_unused_parameters: true + distributed_world_size: 8 + distributed_port: 29671 + nprocs_per_node: 8 + +task: + _name: multires_hubert_pretraining + data: ??? + fine_tuning: true + label_dir: ??? + label_rate_ratios: ??? + normalize: false # must be consistent with pre-training + labels: ["ltr"] + single_target: true + +dataset: + num_workers: 0 + max_tokens: 3200000 + validate_after_updates: ${model.freeze_finetune_updates} + validate_interval: 5 + train_subset: train_100h + valid_subset: dev_other + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 80000 + lr: [3e-5] + sentence_avg: true + update_freq: [1] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: multires_hubert_ctc + multires_hubert_path: ??? + apply_mask: true + mask_selection: static + mask_length: 10 + mask_other: 0 + mask_prob: 0.75 + mask_channel_selection: static + mask_channel_length: 64 + mask_channel_other: 0 + mask_channel_prob: 0.5 + layerdrop: 0.1 + dropout: 0.0 + activation_dropout: 0.1 + attention_dropout: 0.0 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + - model.multires_hubert_path + - dataset.train_subset + - dataset.valid_subset + - criterion.wer_kenlm_model + - criterion.wer_lexicon + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/mr_hubert/config/finetune/base_100h_large.yaml b/examples/mr_hubert/config/finetune/base_100h_large.yaml new file mode 100644 index 0000000000..1d0c0da3db --- /dev/null +++ b/examples/mr_hubert/config/finetune/base_100h_large.yaml @@ -0,0 +1,97 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tblog + seed: 1337 + +checkpoint: + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +distributed_training: + ddp_backend: c10d + find_unused_parameters: true + distributed_world_size: 8 + distributed_port: 29671 + nprocs_per_node: 8 + +task: + _name: multires_hubert_pretraining + data: ??? + fine_tuning: true + label_dir: ??? + label_rate_ratios: ??? + normalize: true # must be consistent with pre-training + labels: ["ltr"] + single_target: true + +dataset: + num_workers: 0 + max_tokens: 1600000 + validate_after_updates: ${model.freeze_finetune_updates} + validate_interval: 5 + train_subset: train_100h + valid_subset: dev_other + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 80000 + lr: [3e-5] + sentence_avg: true + update_freq: [2] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: multires_hubert_ctc + multires_hubert_path: ??? + apply_mask: true + mask_selection: static + mask_length: 10 + mask_other: 0 + mask_prob: 0.75 + mask_channel_selection: static + mask_channel_length: 64 + mask_channel_other: 0 + mask_channel_prob: 0.5 + layerdrop: 0.1 + dropout: 0.0 + activation_dropout: 0.1 + attention_dropout: 0.0 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + - model.multires_hubert_path + - dataset.train_subset + - dataset.valid_subset + - criterion.wer_kenlm_model + - criterion.wer_lexicon + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/mr_hubert/config/finetune/base_10h.yaml b/examples/mr_hubert/config/finetune/base_10h.yaml new file mode 100644 index 0000000000..25123e4481 --- /dev/null +++ b/examples/mr_hubert/config/finetune/base_10h.yaml @@ -0,0 +1,101 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tblog + seed: 1337 + +checkpoint: + save_interval: 5 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +distributed_training: + ddp_backend: c10d + find_unused_parameters: true + distributed_world_size: 8 + distributed_port: 29671 + nprocs_per_node: 8 + +task: + _name: multires_hubert_pretraining + data: ??? + fine_tuning: true + label_dir: ??? + label_rate_ratios: ??? + normalize: false # must be consistent with pre-training + labels: ["ltr"] + single_target: true + +dataset: + num_workers: 0 + max_tokens: 3200000 + validate_after_updates: ${model.freeze_finetune_updates} + validate_interval: 5 + train_subset: train_10h + valid_subset: dev + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 25000 + lr: [2e-5] + sentence_avg: true + update_freq: [1] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 72000 + final_lr_scale: 0.05 + +model: + _name: multires_hubert_ctc + multires_hubert_path: ??? + apply_mask: true + mask_selection: static + mask_length: 10 + mask_other: 0 + mask_prob: 0.75 + mask_channel_selection: static + mask_channel_length: 64 + mask_channel_other: 0 + mask_channel_prob: 0.5 + layerdrop: 0.1 + dropout: 0.0 + activation_dropout: 0.1 + attention_dropout: 0.0 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + - model.multires_hubert_path + - dataset.train_subset + - dataset.valid_subset + - criterion.wer_kenlm_model + - criterion.wer_lexicon + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/mr_hubert/config/finetune/base_10h_large.yaml b/examples/mr_hubert/config/finetune/base_10h_large.yaml new file mode 100644 index 0000000000..65448c7722 --- /dev/null +++ b/examples/mr_hubert/config/finetune/base_10h_large.yaml @@ -0,0 +1,101 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tblog + seed: 1337 + +checkpoint: + save_interval: 5 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +distributed_training: + ddp_backend: c10d + find_unused_parameters: true + distributed_world_size: 8 + distributed_port: 29671 + nprocs_per_node: 8 + +task: + _name: multires_hubert_pretraining + data: ??? + fine_tuning: true + label_dir: ??? + label_rate_ratios: ??? + normalize: true # must be consistent with pre-training + labels: ["ltr"] + single_target: true + +dataset: + num_workers: 0 + max_tokens: 3200000 + validate_after_updates: ${model.freeze_finetune_updates} + validate_interval: 5 + train_subset: train_10h + valid_subset: dev + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 25000 + lr: [2e-5] + sentence_avg: true + update_freq: [1] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + warmup_steps: 8000 + hold_steps: 0 + decay_steps: 72000 + final_lr_scale: 0.05 + +model: + _name: multires_hubert_ctc + multires_hubert_path: ??? + apply_mask: true + mask_selection: static + mask_length: 10 + mask_other: 0 + mask_prob: 0.75 + mask_channel_selection: static + mask_channel_length: 64 + mask_channel_other: 0 + mask_channel_prob: 0.5 + layerdrop: 0.1 + dropout: 0.0 + activation_dropout: 0.1 + attention_dropout: 0.0 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + - model.multires_hubert_path + - dataset.train_subset + - dataset.valid_subset + - criterion.wer_kenlm_model + - criterion.wer_lexicon + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/mr_hubert/config/finetune/base_1h.yaml b/examples/mr_hubert/config/finetune/base_1h.yaml new file mode 100644 index 0000000000..7459c3fc4c --- /dev/null +++ b/examples/mr_hubert/config/finetune/base_1h.yaml @@ -0,0 +1,100 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tblog + seed: 1337 + +checkpoint: + save_interval: 50 + keep_interval_updates: 1 + save_interval_updates: 1000 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +distributed_training: + ddp_backend: c10d + find_unused_parameters: true + distributed_world_size: 8 + distributed_port: 29671 + nprocs_per_node: 8 + +task: + _name: multires_hubert_pretraining + data: ??? + fine_tuning: true + label_dir: ??? + label_rate_ratios: ??? + normalize: false # must be consistent with pre-training + labels: ["ltr"] + single_target: true + +dataset: + num_workers: 0 + max_tokens: 3200000 + validate_after_updates: ${model.freeze_finetune_updates} + validate_interval: 1000 + train_subset: train_1h + valid_subset: dev_other + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 13000 + lr: [5e-5] + sentence_avg: true + update_freq: [4] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: multires_hubert_ctc + multires_hubert_path: ??? + apply_mask: true + mask_selection: static + mask_length: 10 + mask_other: 0 + mask_prob: 0.75 + mask_channel_selection: static + mask_channel_length: 64 + mask_channel_other: 0 + mask_channel_prob: 0.5 + layerdrop: 0.1 + dropout: 0.0 + activation_dropout: 0.1 + attention_dropout: 0.0 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + - model.multires_hubert_path + - dataset.train_subset + - dataset.valid_subset + - criterion.wer_kenlm_model + - criterion.wer_lexicon + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/mr_hubert/config/finetune/base_1h_large.yaml b/examples/mr_hubert/config/finetune/base_1h_large.yaml new file mode 100644 index 0000000000..34ef4dc19d --- /dev/null +++ b/examples/mr_hubert/config/finetune/base_1h_large.yaml @@ -0,0 +1,99 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + tensorboard_logdir: tblog + seed: 1337 + +checkpoint: + save_interval: 1000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + best_checkpoint_metric: wer + +distributed_training: + ddp_backend: c10d + find_unused_parameters: true + distributed_world_size: 8 + distributed_port: 29671 + nprocs_per_node: 8 + +task: + _name: multires_hubert_pretraining + data: ??? + fine_tuning: true + label_dir: ??? + label_rate_ratios: ??? + normalize: true # must be consistent with pre-training + labels: ["ltr"] + single_target: true + +dataset: + num_workers: 0 + max_tokens: 1280000 + validate_after_updates: ${model.freeze_finetune_updates} + validate_interval: 5 + train_subset: train_10h + valid_subset: dev + +criterion: + _name: ctc + zero_infinity: true + +optimization: + max_update: 25000 + lr: [3e-4] + sentence_avg: true + update_freq: [5] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-08 + +lr_scheduler: + _name: tri_stage + phase_ratio: [0.1, 0.4, 0.5] + final_lr_scale: 0.05 + +model: + _name: multires_hubert_ctc + multires_hubert_path: ??? + apply_mask: true + mask_selection: static + mask_length: 10 + mask_other: 0 + mask_prob: 0.75 + mask_channel_selection: static + mask_channel_length: 64 + mask_channel_other: 0 + mask_channel_prob: 0.5 + layerdrop: 0.1 + dropout: 0.0 + activation_dropout: 0.1 + attention_dropout: 0.0 + feature_grad_mult: 0.0 + freeze_finetune_updates: 10000 + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + - task.label_dir + - model.multires_hubert_path + - dataset.train_subset + - dataset.valid_subset + - criterion.wer_kenlm_model + - criterion.wer_lexicon + run: + dir: ??? + sweep: + dir: ??? + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/mr_hubert/config/pretrain/mrhubert_base_librispeech.yaml b/examples/mr_hubert/config/pretrain/mrhubert_base_librispeech.yaml new file mode 100644 index 0000000000..16a35d340a --- /dev/null +++ b/examples/mr_hubert/config/pretrain/mrhubert_base_librispeech.yaml @@ -0,0 +1,103 @@ +# @package _group_ + +common: + fp16: true + log_format: json + log_interval: 200 + seed: 1337 + tensorboard_logdir: tblog + min_loss_scale: 1e-8 + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + +distributed_training: + ddp_backend: no_c10d + distributed_backend: 'nccl' + distributed_world_size: 32 + distributed_port: 29671 + nprocs_per_node: 8 + find_unused_parameters: true + +task: + _name: multires_hubert_pretraining + data: ??? + label_dir: ??? + labels: ??? + label_rate: ${model.label_rate} + label_rate_ratios: ??? + sample_rate: 16000 + max_sample_size: 250000 + min_sample_size: 32000 + pad_audio: false + random_crop: true + normalize: false # must be consistent with extractor + # max_keep_size: 300000 + # max_keep_size: 50000 + + +dataset: + num_workers: 0 + max_tokens: 1000000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + validate_interval_updates: 10000 + +criterion: + _name: hubert + pred_masked_weight: 1.0 + pred_nomask_weight: 0.0 + loss_weights: [10,] + +optimization: + max_update: 400000 + lr: [0.0005] + clip_norm: 10.0 + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: multires_hubert + label_rate: ??? + label_rate_ratios: ${task.label_rate_ratios} + skip_masked: false + skip_nomask: false + mask_prob: 0.80 + extractor_mode: default + conv_feature_layers: '[(512,10,5)] + [(512,3,2)] * 4 + [(512,2,2)] * 2' + final_dim: 256 + encoder_layers: 4 + encoder_layerdrop: 0.05 + dropout_input: 0.1 + dropout_features: 0.1 + dropout: 0.1 + attention_dropout: 0.1 + feature_grad_mult: 0.1 + untie_final_proj: true + activation_dropout: 0.0 + conv_adapator_kernal: 1 + use_single_target: true + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '/' + exclude_keys: + - run + - task.data + - task.label_dir + - common.min_loss_scale + - common.log_interval + - optimization.clip_norm diff --git a/examples/mr_hubert/config/pretrain/mrhubert_large_librilight.yaml b/examples/mr_hubert/config/pretrain/mrhubert_large_librilight.yaml new file mode 100644 index 0000000000..423f3b25c2 --- /dev/null +++ b/examples/mr_hubert/config/pretrain/mrhubert_large_librilight.yaml @@ -0,0 +1,107 @@ +# @package _group_ + +common: + memory_efficient_fp16: true + log_format: json + log_interval: 200 + seed: 1337 + tensorboard_logdir: tblog + +checkpoint: + save_interval_updates: 25000 + keep_interval_updates: 1 + no_epoch_checkpoints: true + + +distributed_training: + ddp_backend: no_c10d + distributed_backend: 'nccl' + distributed_world_size: 128 + distributed_port: 29671 + nprocs_per_node: 8 + find_unused_parameters: true + +task: + _name: multires_hubert_pretraining + data: ??? + label_dir: ??? + labels: ??? + label_rate: ${model.label_rate} + label_rate_ratios: ??? + sample_rate: 16000 + max_sample_size: 250000 + min_sample_size: 32000 + pad_audio: false + random_crop: true + normalize: true # must be consistent with extractor + # max_keep_size: 50000 + +dataset: + num_workers: 0 + max_tokens: 300000 + skip_invalid_size_inputs_valid_test: true + validate_interval: 5 + validate_interval_updates: 10000 + +criterion: + _name: hubert + pred_masked_weight: 1.0 + pred_nomask_weight: 0.0 + loss_weights: [10,] + +optimization: + max_update: 400000 + lr: [0.0015] + clip_norm: 1.0 + update_freq: [3] + +optimizer: + _name: adam + adam_betas: (0.9,0.98) + adam_eps: 1e-06 + weight_decay: 0.01 + +lr_scheduler: + _name: polynomial_decay + warmup_updates: 32000 + +model: + _name: multires_hubert + label_rate: ??? + label_rate_ratios: ${task.label_rate_ratios} + encoder_layers: 8 + encoder_embed_dim: 1024 + encoder_ffn_embed_dim: 4096 + encoder_attention_heads: 16 + final_dim: 768 + skip_masked: false + skip_nomask: false + mask_prob: 0.80 + extractor_mode: layer_norm + conv_feature_layers: '[(512,10,5)] + [(512,3,2)] * 4 + [(512,2,2)] * 2' + encoder_layerdrop: 0.0 + dropout_input: 0.0 + dropout_features: 0.0 + dropout: 0.0 + attention_dropout: 0.0 + layer_norm_first: true + feature_grad_mult: 1.0 + untie_final_proj: true + activation_dropout: 0.0 + conv_adapator_kernal: 1 + use_single_target: true + +hydra: + job: + config: + override_dirname: + kv_sep: '-' + item_sep: '__' + exclude_keys: + - run + - task.data + run: + dir: /checkpoint/wnhsu/w2v/hubert_final/hydra_pt + sweep: + dir: /checkpoint/wnhsu/w2v/hubert_final/hydra_pt + subdir: ${hydra.job.config_name}__${hydra.job.override_dirname} diff --git a/examples/mr_hubert/config/pretrain/run/submitit_reg.yaml b/examples/mr_hubert/config/pretrain/run/submitit_reg.yaml new file mode 100644 index 0000000000..46c979cd28 --- /dev/null +++ b/examples/mr_hubert/config/pretrain/run/submitit_reg.yaml @@ -0,0 +1,20 @@ +# @package _global_ + +hydra: + launcher: + cpus_per_task: 8 + gpus_per_node: 8 + tasks_per_node: ${hydra.launcher.gpus_per_node} + nodes: 4 + comment: null + mem_gb: 384 + timeout_min: 4320 + max_num_timeout: 100 + constraint: volta32gb + name: ${hydra.job.config_name}/${hydra.job.override_dirname} + submitit_folder: ${hydra.sweep.dir}/submitit/%j + +distributed_training: + distributed_world_size: 32 + distributed_port: 29671 + nprocs_per_node: 8 diff --git a/examples/mr_hubert/decode.sh b/examples/mr_hubert/decode.sh new file mode 100755 index 0000000000..1ff423a84c --- /dev/null +++ b/examples/mr_hubert/decode.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +FAIRSEQ= # Setup your fairseq directory + +config_dir=${FAIRSEQ}/examples/mr_hubert/config +config_name=mr_hubert_base_librispeech + + +# Prepared Data Directory + +data_dir=librispeech +# -- data_dir +# -- test.tsv +# -- test.ltr +# -- dict.ltr.txt + + +exp_dir=exp # Target experiments directory (where you have your pre-trained model with checkpoint_best.pt) +ratios="[1, 2]" # Default label rate ratios + +_opts= + +# If use slurm, uncomment this line and modify the job submission at +# _opts="${_opts} hydra/launcher=submitit_slurm +hydra.launcher.partition=${your_slurm_partition} +run=submitit_reg" + +# If want to set additional experiment tag, uncomment this line +# _opts="${_opts} hydra.sweep.subdir=${your_experiment_tag}" + +# If use un-normalized audio, uncomment this line +# _opts="${_opts} task.normalize=false" + + + +PYTHONPATH=${FAIRSEQ} +python examples/speech_recognition/new/infer.py \ + --config-dir ${config_dir} \ + --config-name infer_multires \ + ${_opts} \ + task.data=${data_dir} \ + task.label_rate_ratios='${ratios}' \ + common_eval.results_path=${exp_dir} \ + common_eval.path=${exp_dir}/checkpoint_best.pt \ + dataset.max_tokens=2000000 \ + dataset.gen_subset=test \ + dataset.skip_invalid_size_inputs_valid_test=true + diff --git a/examples/mr_hubert/finetune.sh b/examples/mr_hubert/finetune.sh new file mode 100755 index 0000000000..31ba645560 --- /dev/null +++ b/examples/mr_hubert/finetune.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +FAIRSEQ= # Setup your fairseq directory + +config_dir=${FAIRSEQ}/examples/mr_hubert/config +config_name=mr_hubert_base_librispeech + +# override configs if need +max_tokens=3200000 +max_sample_size=1000000 +max_update=50000 + + +# Prepared Data Directory + +data_dir=librispeech +# -- data_dir +# -- train.tsv +# -- train.ltr +# -- valid.tsv +# -- valid.ltr +# -- dict.ltr.txt + + +exp_dir=exp # Target experiments directory +ratios="[1, 2]" # Default label rate ratios +hubert_path=/path/of/your/hubert.pt + +_opts= + +# If use slurm, uncomment this line and modify the job submission at +# _opts="${_opts} hydra/launcher=submitit_slurm +hydra.launcher.partition=${your_slurm_partition} +run=submitit_reg" + +# If want to set additional experiment tag, uncomment this line +# _opts="${_opts} hydra.sweep.subdir=${your_experiment_tag}" + + +python ${FAIRSEQ}/fairseq_cli/hydra_train.py \ + -m --config-dir ${config_dir} --config-name ${config_name} ${_opts} \ + task.data=${data_dir} +task.max_sample_size=${max_sample_size} \ + task.label_dir=${data_dir} \ + task.label_rate_ratios='${ratios}' \ + dataset.max_tokens=${max_tokens} \ + optimization.max_update=${max_update} \ + model.multires_hubert_path=${hubert_path} \ + hydra.sweep.dir=${exp_dir} & diff --git a/examples/mr_hubert/simple_kmeans b/examples/mr_hubert/simple_kmeans new file mode 120000 index 0000000000..4f95545122 --- /dev/null +++ b/examples/mr_hubert/simple_kmeans @@ -0,0 +1 @@ +../hubert/simple_kmeans \ No newline at end of file diff --git a/examples/mr_hubert/train.sh b/examples/mr_hubert/train.sh new file mode 100755 index 0000000000..da561eb171 --- /dev/null +++ b/examples/mr_hubert/train.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +FAIRSEQ= # Setup your fairseq directory + +config_dir=${FAIRSEQ}/examples/mr_hubert/config +config_name=mr_hubert_base_librispeech + +# Prepared Data Directory +data_dir=librispeech +# -- data_dir +# -- train.tsv +# -- valid.tsv + +label_dir=labels +# -- label_dir +# -- train.km +# -- valid.km +# -- dict.km.txt + + +exp_dir=exp # Target experiments directory +ratios="[1, 2]" # Default label rate ratios +label_rate=50 # Base label rate + + +_opts= + +# If use slurm, uncomment this line and modify the job submission at +# _opts="${_opts} hydra/launcher=submitit_slurm +hydra.launcher.partition=${your_slurm_partition} +run=submitit_reg" + +# If want to set additional experiment tag, uncomment this line +# _opts="${_opts} hydra.sweep.subdir=${your_experiment_tag}" + + +python ${FAIRSEQ}/fairseq_cli/hydra_train.py \ + -m --config-dir ${config_dir} --config-name ${config_name} ${_opts} \ + task.data=${data_dir} \ + task.label_dir=${label_dir} \ + task.labels='["km"]' \ + model.label_rate=${label_rate} \ + task.label_rate_ratios='${ratios}' \ + hydra.sweep.dir=${exp_dir} & + + + diff --git a/fairseq/models/multires_hubert/__init__.py b/fairseq/models/multires_hubert/__init__.py new file mode 100644 index 0000000000..ec36505b08 --- /dev/null +++ b/fairseq/models/multires_hubert/__init__.py @@ -0,0 +1,2 @@ +from .multires_hubert import * # noqa +from .multires_hubert_asr import * # noqa diff --git a/fairseq/models/multires_hubert/multires_hubert.py b/fairseq/models/multires_hubert/multires_hubert.py new file mode 100644 index 0000000000..eacb29e5fe --- /dev/null +++ b/fairseq/models/multires_hubert/multires_hubert.py @@ -0,0 +1,1231 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import logging +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Tuple + +import numpy as np +import torch +import math +import torch.nn as nn +from omegaconf import II +from fairseq.models.wav2vec.wav2vec import norm_block + +from fairseq import utils +from fairseq.data.data_utils import compute_mask_indices +from fairseq.data.dictionary import Dictionary +from fairseq.dataclass import ChoiceEnum, FairseqDataclass +from fairseq.models import BaseFairseqModel, register_model +from fairseq.models.wav2vec.wav2vec2 import ( + EXTRACTOR_MODE_CHOICES, + MASKING_DISTRIBUTION_CHOICES, + LAYER_TYPE_CHOICES, + ConvFeatureExtractionModel, + TransformerEncoder, +) +from omegaconf import II, MISSING, open_dict +from fairseq.modules import GradMultiply, LayerNorm +from fairseq.tasks.multires_hubert_pretraining import ( + MultiresHubertPretrainingConfig, + MultiresHubertPretrainingTask, +) + +logger = logging.getLogger(__name__) + + +@dataclass +class MultiresHubertConfig(FairseqDataclass): + label_rate: float = II("task.label_rate") + # label_rate: 1,2,2,5 + # (imply (1,2), (2,5)) + # if base label_rate = 50 + # (1,2), (2,5) --> label rates 50, 25, 10 + label_rate_ratios: List[int] = field( + default=MISSING, metadata={"help": "tuple for label rates e.g., [(1,2), (2,5)]"} + ) + + extractor_mode: EXTRACTOR_MODE_CHOICES = field( + default="default", + metadata={ + "help": "mode for feature extractor. default has a single group " + "norm with d groups in the first conv block, whereas layer_norm " + "has layer norms in every block (meant to use with normalize=True)" + }, + ) + # the blocks for each label rate + encoder_layers: int = field( + default="2", + metadata={ + "help": "num encoder layers in the each block (one sub module of the U-net)" + }, + ) + override_encoder_layers: str = field( + default="", + metadata={ + "help": "specific layer numbers for each block (one sub module of the U-net) for the training" + }, + ) + encoder_embed_dim: int = field( + default=768, metadata={"help": "encoder embedding dimension"} + ) + encoder_ffn_embed_dim: int = field( + default=3072, metadata={"help": "encoder embedding dimension for FFN"} + ) + encoder_attention_heads: int = field( + default=12, metadata={"help": "num encoder attention heads"} + ) + activation_fn: ChoiceEnum(utils.get_available_activation_fns()) = field( + default="gelu", metadata={"help": "activation function to use"} + ) + layer_type: LAYER_TYPE_CHOICES = field( + default="transformer", metadata={"help": "layer type in encoder"} + ) + conv_adapator_kernal: int = field( + default=7, metadata={"help": "kernal size for conv adaptor"} + ) + use_plain_updownsample: bool = field( + default=False, metadata={"help": "whether to use plain up downsample"} + ) + + # dropouts + dropout: float = field( + default=0.1, + metadata={"help": "dropout probability for the transformer"}, + ) + attention_dropout: float = field( + default=0.1, + metadata={"help": "dropout probability for attention weights"}, + ) + activation_dropout: float = field( + default=0.0, + metadata={"help": "dropout probability after activation in FFN"}, + ) + encoder_layerdrop: float = field( + default=0.0, + metadata={"help": "probability of dropping a tarnsformer layer"}, + ) + dropout_input: float = field( + default=0.0, + metadata={"help": "dropout to apply to the input (after feat extr)"}, + ) + dropout_features: float = field( + default=0.0, + metadata={"help": "dropout to apply to the features (after feat extr)"}, + ) + + final_dim: int = field( + default=0, + metadata={ + "help": "project final representations and targets to this many " + "dimensions. set to encoder_embed_dim is <= 0" + }, + ) + untie_final_proj: bool = field( + default=True, + metadata={"help": "use separate projection for each target"}, + ) + layer_norm_first: bool = field( + default=False, + metadata={"help": "apply layernorm first in the transformer"}, + ) + conv_feature_layers: str = field( + default="[(512,10,5)] + [(512,3,2)] * 4 + [(512,2,2)] * 2", + metadata={ + "help": "string describing convolutional feature extraction " + "layers in form of a python list that contains " + "[(dim, kernel_size, stride), ...]" + }, + ) + conv_bias: bool = field( + default=False, metadata={"help": "include bias in conv encoder"} + ) + logit_temp: float = field( + default=0.1, metadata={"help": "temperature to divide logits by"} + ) + target_glu: bool = field( + default=False, metadata={"help": "adds projection + glu to targets"} + ) + feature_grad_mult: float = field( + default=1.0, + metadata={"help": "multiply feature extractor var grads by this"}, + ) + use_single_target: bool = field( + default=False, + metadata={ + "help": "whether to use single data (in that case, we will compute with the fixed label rate)" + }, + ) + use_single_prediction: bool = field( + default=False, + metadata={ + "help": "if true, we will not conduct mlm prediction in low resolution in the middle" + }, + ) + use_multi_stream: bool = field( + default=False, + metadata={ + "help": "whether to use multi-stream setting (in this setting, we have multiple streams with the same resolution)" + }, + ) + + # masking + mask_length: int = field(default=10, metadata={"help": "mask length"}) + mask_prob: float = field( + default=0.65, + metadata={"help": "probability of replacing a token with mask"}, + ) + mask_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose mask length"} + ) + mask_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indicesh" + }, + ) + no_mask_overlap: bool = field( + default=False, metadata={"help": "whether to allow masks to overlap"} + ) + mask_min_space: int = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + + # channel masking + mask_channel_length: int = field( + default=10, + metadata={"help": "length of the mask for features (channels)"}, + ) + mask_channel_prob: float = field( + default=0.0, + metadata={"help": "probability of replacing a feature with 0"}, + ) + mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", + metadata={"help": "how to choose mask length for channel masking"}, + ) + mask_channel_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indicesh" + }, + ) + no_mask_channel_overlap: bool = field( + default=False, + metadata={"help": "whether to allow channel masks to overlap"}, + ) + mask_channel_min_space: int = field( + default=1, + metadata={"help": "min space between spans (if no overlap is enabled)"}, + ) + + # positional embeddings + conv_pos: int = field( + default=128, + metadata={"help": "number of filters for convolutional positional embeddings"}, + ) + conv_pos_groups: int = field( + default=16, + metadata={"help": "number of groups for convolutional positional embedding"}, + ) + + latent_temp: Tuple[float, float, float] = field( + default=(2, 0.5, 0.999995), + metadata={"help": "legacy (to be removed)"}, + ) + + # loss computation + skip_masked: bool = field( + default=False, + metadata={"help": "skip computing losses over masked frames"}, + ) + skip_nomask: bool = field( + default=False, + metadata={"help": "skip computing losses over unmasked frames"}, + ) + + checkpoint_activations: bool = field( + default=False, + metadata={"help": "recompute activations and save memory for extra compute"}, + ) + + # FP16 optimization + required_seq_len_multiple: int = field( + default=2, + metadata={ + "help": "pad the input to encoder such that the sequence length is divisible by multiple" + }, + ) + + # Conformer + depthwise_conv_kernel_size: int = field( + default=31, + metadata={ + "help": "depthwise-conv-kernel-size for convolution in conformer layer" + }, + ) + attn_type: str = field( + default="", + metadata={"help": "if espnet use ESPNET MHA"}, + ) + pos_enc_type: str = field( + default="abs", + metadata={"help": "Positional encoding type to use in conformer"}, + ) + fp16: bool = field(default=False, metadata={"help": "If fp16 is being used"}) + + +@register_model("multires_hubert", dataclass=MultiresHubertConfig) +class MultiresHubertModel(BaseFairseqModel): + def __init__( + self, + cfg: MultiresHubertConfig, + task_cfg: MultiresHubertPretrainingConfig, + dictionaries: List[Dictionary], + ) -> None: + super().__init__() + logger.info(f"MultiresHubertModel Config: {cfg}") + + feature_enc_layers = eval(cfg.conv_feature_layers) # noqa + self.embed = feature_enc_layers[-1][0] + + self.feature_extractor = ConvFeatureExtractionModel( + conv_layers=feature_enc_layers, + dropout=0.0, + mode=cfg.extractor_mode, + conv_bias=cfg.conv_bias, + ) + self.post_extract_proj = ( + nn.Linear(self.embed, cfg.encoder_embed_dim) + if self.embed != cfg.encoder_embed_dim + else None + ) + + # Estimate label rates + assert ( + cfg.label_rate_ratios != "None" + ), "without ratios, the model is exactly as the Hubert model" + self.label_rate_ratios = [] + self.base_rate = cfg.label_rate + self.label_rates = [] + self.downsample_modules = nn.ModuleList() + self.upsample_modules = nn.ModuleList() + self.encoders = nn.ModuleList() + self.decoders = nn.ModuleList() + self.use_single_target = cfg.use_single_target + self.use_single_prediction = cfg.use_single_prediction + self.use_plain_updownsample = cfg.use_plain_updownsample + + # For decide the override encoder layers, so that the layer number is not equally distributed + if cfg.override_encoder_layers != "": + self.override_encoder_layers = eval(cfg.override_encoder_layers) + assert ( + len(self.override_encoder_layers) % 2 == 1 + ), "must be odd number of layers if specify detailed layers" + assert ( + len(self.override_encoder_layers) // 2 + == len(cfg.label_rate_ratios) // 2 + ), "number of override encoder layers must match the label rate ratios information" + self.len_encoder_modules = len(self.override_encoder_layers) + else: + self.override_encoder_layers = None + self.len_encoder_modules = None + + # use different layers instead of equally distributed ones + middle_override_encoder_layer = ( + self.override_encoder_layers[self.len_encoder_modules // 2] + if self.override_encoder_layers is not None + else None + ) + skip_middle_pos_conv = False if len(cfg.label_rate_ratios) < 2 else True + + self.middle_encoder = TransformerEncoder( + cfg, + skip_pos_conv=skip_middle_pos_conv, + override_encoder_layer=middle_override_encoder_layer, + ) + + first_pos_conv = False # only enable pos_conv for the first encoder + raw_label_rate_ratios = cfg.label_rate_ratios + for i in range(len(raw_label_rate_ratios) // 2): + # check if have override encoder layers + if self.override_encoder_layers is not None: + override_encoder_layer = self.override_encoder_layers[i] + override_decoder_layer = self.override_encoder_layers[ + self.len_encoder_modules - 1 - i + ] + else: + override_encoder_layer, override_decoder_layer = None, None + + self.label_rate_ratios.append( + (raw_label_rate_ratios[i * 2], raw_label_rate_ratios[i * 2 + 1]) + ) + if self.use_plain_updownsample: + self.downsample_modules.append( + ConvDownsampler( + k=cfg.conv_adapator_kernal, + label_rate=( + ( + raw_label_rate_ratios[i * 2], + raw_label_rate_ratios[i * 2 + 1], + ) + ), + dropout=0.0, + channels=cfg.encoder_embed_dim, + activation=nn.GELU(), + log_compression=False, + skip_connections=True, + highway=True, + residual_scale=0.4, + ) + ) + else: + self.downsample_modules.append( + ConvAdapter( + k=cfg.conv_adapator_kernal, + label_rate=( + ( + raw_label_rate_ratios[i * 2], + raw_label_rate_ratios[i * 2 + 1], + ) + ), + dropout=0.0, + channels=cfg.encoder_embed_dim, + activation=nn.GELU(), + log_compression=False, + skip_connections=True, + highway=True, + residual_scale=0.4, + ) + ) + if not first_pos_conv: + self.encoders.append( + TransformerEncoder( + cfg, override_encoder_layer=override_encoder_layer + ) + ) # TODO(jiatong): add conformer options + first_pos_conv = True + else: + self.encoders.append( + TransformerEncoder( + cfg, + skip_pos_conv=True, + override_encoder_layer=override_encoder_layer, + ) + ) + if self.use_plain_updownsample: + self.upsample_modules.append( + ConvUpsampler( + k=cfg.conv_adapator_kernal, + label_rate=( + ( + raw_label_rate_ratios[i * 2 + 1], + raw_label_rate_ratios[i * 2], + ) + ), + dropout=0.0, + channels=cfg.encoder_embed_dim, + activation=nn.GELU(), + log_compression=False, + skip_connections=True, + highway=True, + residual_scale=0.4, + ) + ) + else: + self.upsample_modules.append( + ConvAdapter( + k=cfg.conv_adapator_kernal, + label_rate=( + ( + raw_label_rate_ratios[i * 2 + 1], + raw_label_rate_ratios[i * 2], + ) + ), + dropout=0.0, + channels=cfg.encoder_embed_dim, + activation=nn.GELU(), + log_compression=False, + skip_connections=True, + highway=True, + residual_scale=0.4, + ) + ) + self.decoders.append( + TransformerEncoder( + cfg, + skip_pos_conv=True, + override_encoder_layer=override_decoder_layer, + ) + ) + + base_ds_rate = np.prod([s for _, _, s in feature_enc_layers]) + self.feature_ds_rates = [base_ds_rate] + running_rate = self.base_rate + + if cfg.use_single_target or cfg.use_multi_stream: + self.label_rates = self.base_rate + else: + self.label_rates.append(self.base_rate) + + for label_rate_ratio in self.label_rate_ratios: + upsample_rate, downsample_rate = label_rate_ratio + if (base_ds_rate * upsample_rate) % downsample_rate != 0: + logger.warning( + "base rate: {} cannot be ideally processed with downsample rate {}".format( + base_ds_rate, downsample_rate + ) + ) + + base_ds_rate = base_ds_rate * downsample_rate // upsample_rate + self.feature_ds_rates.append(base_ds_rate) + + if not cfg.use_single_target and not cfg.use_multi_stream: + running_rate = running_rate * upsample_rate // downsample_rate + self.label_rates.append(running_rate) + self.label_nums = len( + self.feature_ds_rates + ) # the number of labels for prediction (activate at iter 2) + + if type(self.label_rates) == float: + self.feat2tar_ratios = [ + self.feature_ds_rates[i] * self.label_rates / task_cfg.sample_rate + for i in range(len(self.feature_ds_rates)) + ] + else: + self.feat2tar_ratios = [ + self.feature_ds_rates[i] * self.label_rates[i] / task_cfg.sample_rate + for i in range(len(self.feature_ds_rates)) + ] + + # self.feat2tar_ratios = self.feat2tar_ratios[::-1] + + # An running example of the label rate: + # base_ds_rate = 320 + # self.label_rate_ratios = [(1, 2)] + # self.feature_ds_rates = [320, 640] + # self.label_rates = [50, 25] + # self.feat2tar_ratios = [1, 1] + + # Another running example of the label rate: + # base_ds_rate = 320 + # self.label_rate_ratios = [(1, 2)] + # self.feature_ds_rates = [320, 640] + # self.label_rates = 100 + # self.feat2tar_ratios = [4, 2] + # self.use_sinlge_target = True + + logging.info( + "ds_rates: {}, label_rates: {}, feat2tar_ratios: {}".format( + self.feature_ds_rates, self.label_rates, self.feat2tar_ratios + ) + ) + + self.mask_prob = cfg.mask_prob + self.mask_selection = cfg.mask_selection + self.mask_other = cfg.mask_other + self.mask_length = cfg.mask_length + self.no_mask_overlap = cfg.no_mask_overlap + self.mask_min_space = cfg.mask_min_space + + self.mask_channel_prob = cfg.mask_channel_prob + self.mask_channel_selection = cfg.mask_channel_selection + self.mask_channel_other = cfg.mask_channel_other + self.mask_channel_length = cfg.mask_channel_length + self.no_mask_channel_overlap = cfg.no_mask_channel_overlap + self.mask_channel_min_space = cfg.mask_channel_min_space + + self.dropout_input = nn.Dropout(cfg.dropout_input) + self.dropout_features = nn.Dropout(cfg.dropout_features) + + self.feature_grad_mult = cfg.feature_grad_mult + self.logit_temp = cfg.logit_temp + self.skip_masked = cfg.skip_masked + self.skip_nomask = cfg.skip_nomask + + # Note(jiatong): different from hubert, we just set the final dim as encoder_embed_dim + final_dim = cfg.final_dim if cfg.final_dim > 0 else cfg.encoder_embed_dim + + self.mask_emb = nn.Parameter( + torch.FloatTensor(cfg.encoder_embed_dim).uniform_() + ) + + self.layer_norm = LayerNorm(self.embed) + + self.predictor_head_num = 1 if self.use_single_prediction else self.label_nums + + self.target_glu = None + if cfg.target_glu: + self.target_glus = nn.ModuleList() + for i in range(self.predictor_head_num): + self.target_glus.append( + nn.Sequential(nn.Linear(final_dim, final_dim * 2), nn.GLU()) + ) + + self.untie_final_proj = cfg.untie_final_proj + self.final_projs = nn.ModuleList() + + # Note(jiatong): we do not have untie cases for multires hubert + for i in range(self.predictor_head_num): + self.final_projs.append(nn.Linear(cfg.encoder_embed_dim, final_dim)) + + # modules below are not needed during fine-tuning + self.multires_classes = [] + self.label_embs_concat = nn.ParameterList() + + for i in range(self.predictor_head_num): + if self.use_single_target: + num_classes = len(dictionaries[0]) + else: + num_classes = len(dictionaries[i]) + self.multires_classes.append(num_classes) + self.label_embs_concat.append( + nn.Parameter(torch.FloatTensor(num_classes, final_dim)) + ) + nn.init.uniform_(self.label_embs_concat[i]) + + def upgrade_state_dict_named(self, state_dict, name): + """Upgrade a (possibly old) state dict for new versions of fairseq.""" + + super().upgrade_state_dict_named(state_dict, name) + return state_dict + + @classmethod + def build_model( + cls, cfg: MultiresHubertConfig, task: MultiresHubertPretrainingTask + ): + """Build a new model instance.""" + + model = MultiresHubertModel(cfg, task.cfg, task.dictionaries) + return model + + def apply_mask(self, x, padding_mask, target_list): + B, T, C = x.shape + if self.mask_prob > 0: + mask_indices = compute_mask_indices( + (B, T), + padding_mask, + self.mask_prob, + self.mask_length, + self.mask_selection, + self.mask_other, + min_masks=2, + no_overlap=self.no_mask_overlap, + min_space=self.mask_min_space, + ) + mask_indices = torch.from_numpy(mask_indices).to(x.device) + x[mask_indices] = self.mask_emb + else: + mask_indices = None + + if self.mask_channel_prob > 0: + mask_channel_indices = compute_mask_indices( + (B, C), + None, + self.mask_channel_prob, + self.mask_channel_length, + self.mask_channel_selection, + self.mask_channel_other, + no_overlap=self.no_mask_channel_overlap, + min_space=self.mask_channel_min_space, + ) + mask_channel_indices = ( + torch.from_numpy(mask_channel_indices) + .to(x.device) + .unsqueeze(1) + .expand(-1, T, -1) + ) + x[mask_channel_indices] = 0 + + return x, mask_indices + + def compute_nce(self, x, pos, negs): + neg_is_pos = (pos == negs).all(-1) + pos = pos.unsqueeze(0) + targets = torch.cat([pos, negs], dim=0) + + logits = torch.cosine_similarity(x.float(), targets.float(), dim=-1).type_as(x) + logits /= self.logit_temp + if neg_is_pos.any(): + logits[1:][neg_is_pos] = float("-inf") + logits = logits.transpose(0, 1) # (num_x, num_cls+1) + return logits + + def forward_features(self, source: torch.Tensor) -> torch.Tensor: + if self.feature_grad_mult > 0: + features = self.feature_extractor(source) + if self.feature_grad_mult != 1.0: + features = GradMultiply.apply(features, self.feature_grad_mult) + else: + with torch.no_grad(): + features = self.feature_extractor(source) + return features + + def forward_targets( + self, + features: torch.Tensor, + target: torch.Tensor, + feat2tar_ratio: float, + ) -> Tuple[torch.Tensor, torch.Tensor]: + # Trim features to ensure labels exist and then get aligned labels + + feat_tsz = features.size(1) + + # skip if no target is provided + if target is None: + return features, None, None + targ_tsz = target.size(1) + if feat2tar_ratio * feat_tsz > targ_tsz: + feat_tsz = int(targ_tsz / feat2tar_ratio) + features = features[:, :feat_tsz] + target_inds = torch.arange(feat_tsz).float() * feat2tar_ratio + target = target[:, target_inds.long()] + return features, target + + def forward_padding_mask( + self, + features: torch.Tensor, + padding_mask: torch.Tensor, + ) -> torch.Tensor: + extra = padding_mask.size(1) % features.size(1) + if extra > 0: + padding_mask = padding_mask[:, :-extra] + padding_mask = padding_mask.view(padding_mask.size(0), features.size(1), -1) + padding_mask = padding_mask.all(-1) + return padding_mask + + def forward( + self, + source: torch.Tensor, + target_list: Optional[List[torch.Tensor]] = None, + padding_mask: Optional[torch.Tensor] = None, + mask: bool = True, + features_only: bool = False, + output_layer: Optional[int] = None, + ) -> Dict[str, torch.Tensor]: + """output layer is 1-based""" + features = self.forward_features(source) + + features_pen = features.float().pow(2).mean() + + features = features.transpose(1, 2) + features = self.layer_norm(features) + unmasked_features = features.clone() + + if padding_mask is not None: + padding_mask = self.forward_padding_mask(features, padding_mask) + + if self.post_extract_proj is not None: + features = self.post_extract_proj(features) + + features = self.dropout_input(features) + unmasked_features = self.dropout_features(unmasked_features) + + if mask: + x, mask_indices = self.apply_mask(features, padding_mask, target_list) + else: + x = features + mask_indices = None + + # feature: (B, T, D), float + # target: (B, T), long + # x: (B, T, D), float + # padding_mask: (B, T), bool + # mask_indices: (B, T), bool + + def align_size_sum(feat1, pad1, feat2): + assert ( + abs(feat1.size(1) - feat2.size(1)) < 10 + ), "misaligned results for feat1 and feat2 of size {} - {}".format( + feat1.size(1), feat2.size(1) + ) + common_size = min(feat1.size(1), feat2.size(1)) + + return ( + feat1[:, :common_size] + feat2[:, :common_size], + pad1[:, :common_size], + ) + + # process encoders + res_outputs = [] # final output for different resolution + multi_mask_indices = [] # mask indices for different resolution + residuals = [] # record the x in encoders + padding_masks = [] # final padding masks + # The encoder has (self.label_nums - 1) blocks + for i in range(self.label_nums - 1): + x, _ = self.encoders[i](x, padding_mask=padding_mask, layer=None) + residuals.append(x) + x, padding_mask, mask_indices = self.downsample_modules[i]( + x, padding=padding_mask, mask_indices=mask_indices + ) + + residual = self.middle_encoder(x, padding_mask=padding_mask, layer=None)[0] + x = x + residual + res_outputs.append(x) + + # process decoders + # The encoder has (self.label_nums - 1) blocks + padding_masks.append(padding_mask) + multi_mask_indices.append(mask_indices) + residuals.reverse() # NOTE(jiatong): reverse res_output to match corresponding input + for i in range(self.label_nums - 1): + x, padding_mask, mask_indices = self.upsample_modules[ + self.label_nums - 2 - i + ](x, padding=padding_mask, mask_indices=mask_indices) + x, _ = self.decoders[i](x, padding_mask=padding_mask, layer=None) + x, padding_mask = align_size_sum(x, padding_mask, residuals[i]) + res_outputs.append(x) + padding_masks.append(padding_mask) + multi_mask_indices.append(mask_indices) + + # NOTE(jiatong): need reverse of target list to allow matched target-representation + res_outputs.reverse() + padding_masks.reverse() + multi_mask_indices.reverse() + if target_list is not None: + new_target_list = [] + for i in range(self.label_nums): + if self.use_single_target: + res_outputs[i], reformat_target_list = self.forward_targets( + res_outputs[i], target_list[0], self.feat2tar_ratios[i] + ) + new_target_list.append(reformat_target_list) + else: + if target_list[i] is not None: + res_outputs[i], reformat_target_list = self.forward_targets( + res_outputs[i], target_list[i], self.feat2tar_ratios[i] + ) + new_target_list.append(reformat_target_list) + else: + # Append a None target list then it won't be used to calculate loss + new_target_list.append(None) + if padding_masks[i] is not None: + padding_masks[i] = self.forward_padding_mask( + res_outputs[i], padding_masks[i] + ) + if multi_mask_indices[i] is not None: + multi_mask_indices[i] = self.forward_padding_mask( + res_outputs[i], multi_mask_indices[i] + ) + + + if features_only: + # NOTE(jiatong): need to reverse back + res_outputs.reverse() + return { + "x": res_outputs, + "padding_mask": padding_masks[0], + "features": features, + } + + def compute_pred(proj_x, target, label_embs): + # compute logits for the i-th label set + y = torch.index_select(label_embs, 0, target.long()) + negs = label_embs.unsqueeze(1).expand(-1, proj_x.size(0), -1) + if self.target_glu: + y = self.target_glu(y) + negs = self.target_glu(negs) + # proj_x: (S, D) + # y: (S, D) + # negs: (Neg, S, D) + return self.compute_nce(proj_x, y, negs) + + logit_m_list, logit_u_list = [], [] + for j in range(self.label_nums): + if new_target_list[j] is None: + continue # skip empty targets + label_embs_list = self.label_embs_concat[j].split( + [self.multires_classes[j]], 0 + ) + # set the variables (after the set, the procedure is the same as hubert) + # all the elements are list with only one element (to simulate the normal hubert process) + x = res_outputs[j] + target = new_target_list[j] + padding_mask = padding_masks[j] + mask_indices = multi_mask_indices[j] + final_proj = self.final_projs[j] + + if not self.skip_masked: + masked_indices = torch.logical_and(~padding_mask, mask_indices) + proj_x_m = final_proj(x[masked_indices]) + logit_m_list.append( + compute_pred(proj_x_m, target[masked_indices], label_embs_list[0]) + ) + else: + logit_m_list.append(None) + + if not self.skip_nomask: + nomask_indices = torch.logical_and(~padding_mask, ~mask_indices) + proj_x_u = final_proj(x[nomask_indices]) + logit_u_list.append( + compute_pred(proj_x_u, target[nomask_indices], label_embs_list[0]) + ) + else: + logit_u_list.append(None) + + # if we only want one prediction, we can exit now + if self.predictor_head_num == 1: + break + + result = { + "logit_m_list": logit_m_list, + "logit_u_list": logit_u_list, + "padding_mask": padding_mask, + "features_pen": features_pen, + } + return result + + def extract_features( + self, + source: torch.Tensor, + padding_mask: Optional[torch.Tensor] = None, + mask: bool = False, + ret_conv: bool = False, + output_layer: Optional[int] = None, + last_layer: Optional[bool] = False, + ) -> Tuple[torch.Tensor, torch.Tensor]: + res = self.forward( + source, + padding_mask=padding_mask, + mask=mask, + features_only=True, + output_layer=output_layer, + ) + feature = res["features"] if ret_conv else res["x"] + if last_layer: + feature = feature[-1] + return feature, res["padding_mask"] + + def get_logits(self, net_output, is_masked=True): + if is_masked: + logits_list = net_output["logit_m_list"] + else: + logits_list = net_output["logit_u_list"] + logits_list = [x.float() for x in logits_list if x is not None] + return logits_list + + def get_targets(self, net_output, is_masked=True): + logits_list = self.get_logits(net_output, is_masked) + targets_list = [x.new_zeros(x.size(0), dtype=torch.long) for x in logits_list] + return targets_list + + def get_extra_losses(self, net_output): + extra_losses = [] + names = [] + + if "features_pen" in net_output: + extra_losses.append(net_output["features_pen"]) + names.append("features_pen") + + return extra_losses, names + + def remove_pretraining_modules(self): + self.target_glu = None + self.final_proj = None + + +class ConvAdapter(nn.Module): + """Conv adapter that combines two modules with different label rate with downsample or upsample. + To allow different ratios than integer, two convs are utilized with first to upsample (numerator) + and the second to downsample (denominator)""" + + def __init__( + self, + k, + label_rate, + dropout, + channels, + activation, + log_compression=False, + skip_connections=True, + highway=True, + residual_scale=0.4, + non_affine_group_norm=False, + ): + super().__init__() + + def downsample_block(channel, k, stride): + return nn.Sequential( + # with padding (k - 1) // 2 to keep the same size + nn.Conv1d( + channel, + channel, + k, + stride=stride, + bias=False, + padding=(k - 1) // 2, + ), + nn.Dropout(p=dropout), + norm_block( + is_layer_norm=False, dim=channel, affine=not non_affine_group_norm + ), + activation, + ) + + def upsample_block(channel, k, stride): + return nn.Sequential( + # with padding (k - 1) // 2 to keep the same size + nn.ConvTranspose1d( + channel, + channel, + k, + stride=stride, + bias=False, + padding=0, # padding=(k - 1) // 2, + output_padding=(stride - 1), + ), + nn.Dropout(p=dropout), + norm_block( + is_layer_norm=False, dim=channel, affine=not non_affine_group_norm + ), + activation, + ) + + assert len(label_rate) == 2, "label_rate should be sized two to apply fusion" + # Lout =(Lin~H~R1)~Wstride~H~R2~Wpadding+dilation~W(kernel_size~H~R1)+output_padding+1 + self.upsample_conv = upsample_block(channels, k, label_rate[0]) + self.downsample_conv = downsample_block(channels, k, label_rate[1]) + + self.upsample_rate, self.downsample_rate = label_rate + self.log_compression = log_compression + self.skip_connections = skip_connections + self.highway = highway + self.residual_scale = math.sqrt(residual_scale) + + def forward(self, x, padding=None, mask_indices=None): + # Assume x1 = (B, T, C) as input + x = x.permute(0, 2, 1) + residual_before_upsample = x + x = self.upsample_conv(x) + upsample_size = x.size(2) + + # conduct upsample + if self.skip_connections: + residual_upsample = torch.repeat_interleave( + residual_before_upsample, self.upsample_rate, dim=2 + ) + upsample_size = min(upsample_size, residual_upsample.size(2)) + x = ( + x[..., :upsample_size] + residual_upsample[..., :upsample_size] + ) * self.residual_scale + + residual_before_downsample = x + x = self.downsample_conv(x) + downsample_size = x.size(2) + + if self.skip_connections: + residual_downsample = residual_before_downsample[ + ..., :: self.downsample_rate + ] + downsample_size = min(x.size(2), residual_downsample.size(2)) + x = ( + x[..., :downsample_size] + residual_downsample[..., :downsample_size] + ) * self.residual_scale + + if self.highway: + residual_after_sample = residual_upsample[..., :: self.downsample_rate] + final_size = min(x.size(2), residual_after_sample.size(2)) + x = ( + x[..., :final_size] + residual_after_sample[..., :final_size] + ) * self.residual_scale + + if self.log_compression: + x = x.abs() + x = x + 1 + x = x.log() + + x = x.permute(0, 2, 1) + + # process padding + if padding is not None: + padding = torch.repeat_interleave(padding, self.upsample_rate, dim=1) + padding = padding[..., :: self.downsample_rate] + padding = padding[..., : x.size(1)] + + # process mask indices + if mask_indices is not None: + mask_indices = torch.repeat_interleave( + mask_indices, self.upsample_rate, dim=1 + ) + mask_indices = mask_indices[..., :: self.downsample_rate] + mask_indices = mask_indices[..., : x.size(1)] + return x, padding, mask_indices + + +class ConvDownsampler(nn.Module): + """Conv downsampler that combines two modules with different label rate with downsample or upsample. + To allow different ratios than integer, two convs are utilized with first to upsample (numerator) + and the second to downsample (denominator)""" + + def __init__( + self, + k, + label_rate, + dropout, + channels, + activation, + log_compression=False, + skip_connections=True, + highway=True, + residual_scale=0.4, + non_affine_group_norm=False, + ): + super().__init__() + + def downsample_block(channel, k, stride): + return nn.Sequential( + # with padding (k - 1) // 2 to keep the same size + nn.Conv1d( + channel, + channel, + k, + stride=stride, + bias=False, + padding=(k - 1) // 2, + ), + nn.Dropout(p=dropout), + norm_block( + is_layer_norm=False, dim=channel, affine=not non_affine_group_norm + ), + activation, + ) + + assert len(label_rate) == 2, "label_rate should be sized two to apply fusion" + self.downsample_conv = downsample_block(channels, k, label_rate[1]) + + upsample_rate, self.downsample_rate = label_rate + assert upsample_rate == 1, "must be 1 to perform downsample only" + self.log_compression = log_compression + self.skip_connections = skip_connections + self.highway = highway # Useless as placeholder + self.residual_scale = math.sqrt(residual_scale) + + def forward(self, x, padding=None, mask_indices=None): + # Assume x1 = (B, T, C) as input + x = x.permute(0, 2, 1) + + residual_before_downsample = x + x = self.downsample_conv(x) + downsample_size = x.size(2) + + if self.skip_connections: + residual_downsample = residual_before_downsample[ + ..., :: self.downsample_rate + ] + downsample_size = min(x.size(2), residual_downsample.size(2)) + x = ( + x[..., :downsample_size] + residual_downsample[..., :downsample_size] + ) * self.residual_scale + + if self.log_compression: + x = x.abs() + x = x + 1 + x = x.log() + + x = x.permute(0, 2, 1) + + # process padding + if padding is not None: + padding = padding[..., :: self.downsample_rate] + padding = padding[..., : x.size(1)] + + # process mask indices + if mask_indices is not None: + mask_indices = mask_indices[..., :: self.downsample_rate] + mask_indices = mask_indices[..., : x.size(1)] + return x, padding, mask_indices + + +class ConvUpsampler(nn.Module): + """Conv upsampler that combines two modules with different label rate with downsample or upsample. + To allow different ratios than integer, two convs are utilized with first to upsample (numerator) + and the second to downsample (denominator)""" + + def __init__( + self, + k, + label_rate, + dropout, + channels, + activation, + log_compression=False, + skip_connections=True, + highway=True, + residual_scale=0.4, + non_affine_group_norm=False, + ): + super().__init__() + + def upsample_block(channel, k, stride): + return nn.Sequential( + # with padding (k - 1) // 2 to keep the same size + nn.ConvTranspose1d( + channel, + channel, + k, + stride=stride, + bias=False, + padding=0, # padding=(k - 1) // 2, + output_padding=(stride - 1), + ), + nn.Dropout(p=dropout), + norm_block( + is_layer_norm=False, dim=channel, affine=not non_affine_group_norm + ), + activation, + ) + + assert len(label_rate) == 2, "label_rate should be sized two to apply fusion" + # Lout =(Lin~H~R1)~Wstride~H~R2~Wpadding+dilation~W(kernel_size~H~R1)+output_padding+1 + self.upsample_conv = upsample_block(channels, k, label_rate[0]) + + self.upsample_rate, downsample_rate = label_rate + assert downsample_rate == 1, "must be 1 to perform downsample only" + self.log_compression = log_compression + self.skip_connections = skip_connections + self.highway = highway # Useless + self.residual_scale = math.sqrt(residual_scale) + + def forward(self, x, padding=None, mask_indices=None): + # Assume x1 = (B, T, C) as input + x = x.permute(0, 2, 1) + residual_before_upsample = x + x = self.upsample_conv(x) + upsample_size = x.size(2) + + # conduct upsample + if self.skip_connections: + residual_upsample = torch.repeat_interleave( + residual_before_upsample, self.upsample_rate, dim=2 + ) + upsample_size = min(upsample_size, residual_upsample.size(2)) + x = ( + x[..., :upsample_size] + residual_upsample[..., :upsample_size] + ) * self.residual_scale + + if self.log_compression: + x = x.abs() + x = x + 1 + x = x.log() + + x = x.permute(0, 2, 1) + + # process padding + if padding is not None: + padding = torch.repeat_interleave(padding, self.upsample_rate, dim=1) + padding = padding[..., : x.size(1)] + + # process mask indices + if mask_indices is not None: + mask_indices = torch.repeat_interleave( + mask_indices, self.upsample_rate, dim=1 + ) + mask_indices = mask_indices[..., : x.size(1)] + return x, padding, mask_indices diff --git a/fairseq/models/multires_hubert/multires_hubert_asr.py b/fairseq/models/multires_hubert/multires_hubert_asr.py new file mode 100644 index 0000000000..2e7ad99ce1 --- /dev/null +++ b/fairseq/models/multires_hubert/multires_hubert_asr.py @@ -0,0 +1,376 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import contextlib +from argparse import Namespace +from dataclasses import dataclass, field +from typing import Any + +import torch +import torch.nn as nn +from omegaconf import II, MISSING + +from fairseq import checkpoint_utils, tasks, utils +from fairseq.dataclass import FairseqDataclass +from fairseq.dataclass.utils import convert_namespace_to_omegaconf +from fairseq.models import BaseFairseqModel, FairseqEncoder, register_model +from fairseq.models.hubert.hubert import MASKING_DISTRIBUTION_CHOICES +from fairseq.tasks import FairseqTask + + +@dataclass +class MultiresHubertAsrConfig(FairseqDataclass): + multires_hubert_path: str = field( + default=MISSING, metadata={"help": "path to multires_hubert model"} + ) + no_pretrained_weights: bool = field( + default=False, + metadata={"help": "if true, does not load pretrained weights"}, + ) + dropout_input: float = field( + default=0.0, + metadata={"help": "dropout to apply to the input (after feat extr)"}, + ) + final_dropout: float = field( + default=0.0, + metadata={"help": "dropout after transformer and before final projection"}, + ) + dropout: float = field( + default=0.0, + metadata={"help": "dropout probability inside hubert model"}, + ) + attention_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability for attention weights " "inside hubert model" + }, + ) + activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN " "inside hubert model" + }, + ) + + # masking + apply_mask: bool = field( + default=False, metadata={"help": "apply masking during fine-tuning"} + ) + mask_length: int = field( + default=10, metadata={"help": "repeat the mask indices multiple times"} + ) + mask_prob: float = field( + default=0.5, + metadata={ + "help": "probability of replacing a token with mask " + "(normalized by length)" + }, + ) + mask_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", metadata={"help": "how to choose masks"} + ) + mask_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indices" + }, + ) + no_mask_overlap: bool = field( + default=False, metadata={"help": "whether to allow masks to overlap"} + ) + + # channel masking + mask_channel_length: int = field( + default=10, + metadata={"help": "length of the mask for features (channels)"}, + ) + mask_channel_prob: float = field( + default=0.0, + metadata={"help": "probability of replacing a feature with 0"}, + ) + mask_channel_selection: MASKING_DISTRIBUTION_CHOICES = field( + default="static", + metadata={"help": "how to choose mask length for channel masking"}, + ) + mask_channel_other: float = field( + default=0, + metadata={ + "help": "secondary mask argument " + "(used for more complex distributions), " + "see help in compute_mask_indices" + }, + ) + no_mask_channel_overlap: bool = field( + default=False, + metadata={"help": "whether to allow channel masks to overlap"}, + ) + freeze_finetune_updates: int = field( + default=0, + metadata={"help": "dont finetune hubert for this many updates"}, + ) + feature_grad_mult: float = field( + default=0.0, + metadata={"help": "reset feature grad mult in hubert to this"}, + ) + layerdrop: float = field( + default=0.0, + metadata={"help": "probability of dropping a layer in hubert"}, + ) + normalize: bool = II("task.normalize") + data: str = II("task.data") + + # this holds the loaded hubert args + multires_hubert_args: Any = None + + +@dataclass +class MultiresHubertCtcConfig(MultiresHubertAsrConfig): + pass + + +@register_model("multires_hubert_ctc", dataclass=MultiresHubertAsrConfig) +class MultiresHubertCtc(BaseFairseqModel): + def __init__( + self, cfg: MultiresHubertAsrConfig, multireshubert_encoder: BaseFairseqModel + ): + super().__init__() + self.cfg = cfg + self.multireshubert_encoder = multireshubert_encoder + + def upgrade_state_dict_named(self, state_dict, name): + super().upgrade_state_dict_named(state_dict, name) + return state_dict + + @classmethod + def build_model(cls, cfg: MultiresHubertAsrConfig, task: FairseqTask): + """Build a new model instance.""" + multireshubert_encoder = MultiresHubertEncoder(cfg, task) + return cls(cfg, multireshubert_encoder) + + def get_normalized_probs(self, net_output, log_probs, sample=None): + """Get normalized probabilities (or log probs) from a net's output.""" + + logits = net_output["encoder_out"] + if log_probs: + return utils.log_softmax(logits.float(), dim=-1) + else: + return utils.softmax(logits.float(), dim=-1) + + def get_logits(self, net_output): + logits = net_output["encoder_out"] + padding = net_output["encoder_padding_mask"] + if padding is not None and padding.any(): + padding = padding.T + logits[padding][..., 0] = 0 + logits[padding][..., 1:] = float("-inf") + + return logits + + def forward(self, **kwargs): + x = self.multireshubert_encoder(**kwargs) + return x + + +@dataclass +class MultiresHubertSeq2SeqConfig(MultiresHubertAsrConfig): + decoder_embed_dim: int = field( + default=768, metadata={"help": "decoder embedding dimension"} + ) + decoder_ffn_embed_dim: int = field( + default=3072, metadata={"help": "decoder embedding dimension for FFN"} + ) + decoder_layers: int = field(default=6, metadata={"help": "num of decoder layers"}) + decoder_layerdrop: float = field( + default=0.0, metadata={"help": "decoder layerdrop chance"} + ) + decoder_attention_heads: int = field( + default=4, metadata={"help": "num decoder attention heads"} + ) + decoder_learned_pos: bool = field( + default=False, + metadata={"help": "use learned positional embeddings in the decoder"}, + ) + decoder_normalize_before: bool = field( + default=False, + metadata={"help": "apply layernorm before each decoder block"}, + ) + no_token_positional_embeddings: bool = field( + default=False, + metadata={ + "help": "if set, disables positional embeddings " "(outside self attention)" + }, + ) + decoder_dropout: float = field( + default=0.0, metadata={"help": "dropout probability in the decoder"} + ) + decoder_attention_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability for attention weights " "inside the decoder" + }, + ) + decoder_activation_dropout: float = field( + default=0.0, + metadata={ + "help": "dropout probability after activation in FFN " "inside the decoder" + }, + ) + max_target_positions: int = field( + default=2048, metadata={"help": "max target positions"} + ) + share_decoder_input_output_embed: bool = field( + default=False, + metadata={"help": "share decoder input and output embeddings"}, + ) + + +class MultiresHubertEncoder(FairseqEncoder): + def __init__(self, cfg: MultiresHubertAsrConfig, task): + self.apply_mask = cfg.apply_mask + + arg_overrides = { + "dropout": cfg.dropout, + "activation_dropout": cfg.activation_dropout, + "dropout_input": cfg.dropout_input, + "attention_dropout": cfg.attention_dropout, + "mask_length": cfg.mask_length, + "mask_prob": cfg.mask_prob, + "mask_selection": cfg.mask_selection, + "mask_other": cfg.mask_other, + "no_mask_overlap": cfg.no_mask_overlap, + "mask_channel_length": cfg.mask_channel_length, + "mask_channel_prob": cfg.mask_channel_prob, + "mask_channel_selection": cfg.mask_channel_selection, + "mask_channel_other": cfg.mask_channel_other, + "no_mask_channel_overlap": cfg.no_mask_channel_overlap, + "encoder_layerdrop": cfg.layerdrop, + "feature_grad_mult": cfg.feature_grad_mult, + } + + if cfg.multires_hubert_args is None: + state = checkpoint_utils.load_checkpoint_to_cpu( + cfg.multires_hubert_path, arg_overrides + ) + multires_hubert_args = state.get("cfg", None) + if multires_hubert_args is None: + multires_hubert_args = convert_namespace_to_omegaconf(state["args"]) + cfg.multires_hubert_args = multires_hubert_args + else: + state = None + multires_hubert_args = cfg.multires_hubert_args + if isinstance(multires_hubert_args, Namespace): + cfg.multires_hubert_args = ( + multires_hubert_args + ) = convert_namespace_to_omegaconf(multires_hubert_args) + + assert cfg.normalize == multires_hubert_args.task.normalize, ( + "Fine-tuning works best when data normalization is the same. " + "Please check that --normalize is set or unset for " + "both pre-training and here" + ) + + multires_hubert_args.task.data = cfg.data + pretrain_task = tasks.setup_task(multires_hubert_args.task) + if state is not None and "task_state" in state: + # This will load the stored "dictionaries" object + pretrain_task.load_state_dict(state["task_state"]) + else: + pretrain_task.load_state_dict(task.state_dict()) + + model = pretrain_task.build_model( + multires_hubert_args.model, from_checkpoint=True + ) + if state is not None and not cfg.no_pretrained_weights: + # set strict=False because we omit some modules + model.load_state_dict(state["model"], strict=False) + + model.remove_pretraining_modules() + + super().__init__(pretrain_task.source_dictionary) + + d = multires_hubert_args.model.encoder_embed_dim + + self.multires_hubert_model = model + + self.final_dropout = nn.Dropout(cfg.final_dropout) + self.freeze_finetune_updates = cfg.freeze_finetune_updates + self.num_updates = 0 + + if task.target_dictionary is not None: + self.proj = Linear(d, len(task.target_dictionary)) + elif getattr(cfg, "decoder_embed_dim", d) != d: + self.proj = Linear(d, cfg.decoder_embed_dim) + else: + self.proj = None + + def set_num_updates(self, num_updates): + """Set the number of parameters updates.""" + super().set_num_updates(num_updates) + self.num_updates = num_updates + + def forward(self, source, padding_mask, tbc=True, **kwargs): + multires_hubert_args = { + "source": source, + "padding_mask": padding_mask, + "mask": self.apply_mask and self.training, + "last_layer": True, + } + + ft = self.freeze_finetune_updates <= self.num_updates + + with torch.no_grad() if not ft else contextlib.ExitStack(): + x, padding_mask = self.multires_hubert_model.extract_features( + **multires_hubert_args + ) + + if tbc: + # B x T x C -> T x B x C + x = x.transpose(0, 1) + + x = self.final_dropout(x) + + if self.proj: + x = self.proj(x) + + return { + "encoder_out": x, # T x B x C + "encoder_padding_mask": padding_mask, # B x T + "padding_mask": padding_mask, + } + + def reorder_encoder_out(self, encoder_out, new_order): + if encoder_out["encoder_out"] is not None: + encoder_out["encoder_out"] = encoder_out["encoder_out"].index_select( + 1, new_order + ) + if encoder_out["encoder_padding_mask"] is not None: + encoder_out["encoder_padding_mask"] = encoder_out[ + "encoder_padding_mask" + ].index_select(0, new_order) + return encoder_out + + def max_positions(self): + """Maximum input length supported by the encoder.""" + return None + + def upgrade_state_dict_named(self, state_dict, name): + return state_dict + + +def Embedding(num_embeddings, embedding_dim, padding_idx): + m = nn.Embedding(num_embeddings, embedding_dim, padding_idx=padding_idx) + nn.init.normal_(m.weight, mean=0, std=embedding_dim**-0.5) + nn.init.constant_(m.weight[padding_idx], 0) + return m + + +def Linear(in_features, out_features, bias=True): + m = nn.Linear(in_features, out_features, bias) + nn.init.xavier_uniform_(m.weight) + if bias: + nn.init.constant_(m.bias, 0.0) + return m diff --git a/fairseq/models/wav2vec/wav2vec2.py b/fairseq/models/wav2vec/wav2vec2.py index f8dc6a8f5d..0faba77f8b 100644 --- a/fairseq/models/wav2vec/wav2vec2.py +++ b/fairseq/models/wav2vec/wav2vec2.py @@ -1009,7 +1009,7 @@ def build_encoder_layer(self, args: Wav2Vec2Config, **kwargs): layer = checkpoint_wrapper(layer) return layer - def __init__(self, args: Wav2Vec2Config): + def __init__(self, args: Wav2Vec2Config, skip_pos_conv: bool = False, override_encoder_layer: int = None): super().__init__() self.dropout = args.dropout @@ -1045,7 +1045,8 @@ def make_conv_block(e, k, g, l): self.pos_conv = make_conv_block( self.embedding_dim, k, args.conv_pos_groups, num_layers ) - + elif skip_pos_conv: + self.pos_conv = None else: self.pos_conv = make_conv_pos( self.embedding_dim, @@ -1056,8 +1057,13 @@ def make_conv_block(e, k, g, l): else False, ) + if override_encoder_layer is None: + encoder_layers = args.encoder_layers + else: + encoder_layers = override_encoder_layer + self.layers = nn.ModuleList( - [self.build_encoder_layer(args, layer_idx=ii) for ii in range(args.encoder_layers)] + [self.build_encoder_layer(args, layer_idx=ii) for ii in range(encoder_layers)] ) self.layer_norm_first = args.layer_norm_first self.layer_norm = LayerNorm(self.embedding_dim) @@ -1087,9 +1093,10 @@ def extract_features( if padding_mask is not None: x = index_put(x, padding_mask, 0) - x_conv = self.pos_conv(x.transpose(1, 2)) - x_conv = x_conv.transpose(1, 2) - x = x + x_conv + if self.pos_conv is not None: + x_conv = self.pos_conv(x.transpose(1, 2)) + x_conv = x_conv.transpose(1, 2) + x = x + x_conv if not self.layer_norm_first: x = self.layer_norm(x) diff --git a/fairseq/tasks/multires_hubert_pretraining.py b/fairseq/tasks/multires_hubert_pretraining.py new file mode 100644 index 0000000000..cfed147cb5 --- /dev/null +++ b/fairseq/tasks/multires_hubert_pretraining.py @@ -0,0 +1,204 @@ +# Copyright (c) 2017-present, Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the license found in the LICENSE file in +# the root directory of this source tree. An additional grant of patent rights +# can be found in the PATENTS file in the same directory. + +import logging +import os +import sys +from typing import Dict, List, Optional, Tuple + +import numpy as np + +from dataclasses import dataclass, field +from fairseq.data import Dictionary, HubertDataset +from fairseq.dataclass.configs import FairseqDataclass +from fairseq.tasks import register_task +from fairseq.tasks.fairseq_task import FairseqTask +from omegaconf import MISSING + +logger = logging.getLogger(__name__) + + +class LabelEncoder(object): + def __init__(self, dictionary: Dictionary) -> None: + self.dictionary = dictionary + + def __call__(self, label: str) -> List[str]: + return self.dictionary.encode_line( + label, + append_eos=False, + add_if_not_exist=False, + ) + + +@dataclass +class MultiresHubertPretrainingConfig(FairseqDataclass): + data: str = field(default=MISSING, metadata={"help": "path to data directory"}) + fine_tuning: bool = field( + default=False, metadata={"help": "set to true if fine-tuning Hubert"} + ) + labels: List[str] = field( + default_factory=lambda: ["ltr50", "ltr25"], + metadata={ + "help": ( + "extension of the label files to load, frame-level labels for" + " pre-training, and sequence-level label for fine-tuning" + ) + }, + ) + label_dir: Optional[str] = field( + default=None, + metadata={ + "help": "if set, looks for labels in this directory instead", + }, + ) + label_rate: float = field( + default=-1.0, + metadata={"help": "label frame rate. -1.0 for sequence label"}, + ) + # label_rate: 1,2,2,5 + # (imply (1,2), (2,5)) + # if base label_rate = 50 + # (1,2), (2,5) --> label rates 50, 25, 10 + label_rate_ratios: List[int] = field(default=MISSING, metadata={"help": "tuple for label rates e.g., [(1,2), (2,5)]"}) + sample_rate: int = field( + default=16_000, + metadata={ + "help": "target sample rate. audio files will be up/down " + "sampled to this rate" + }, + ) + normalize: bool = field( + default=False, + metadata={"help": "if set, normalizes input to have 0 mean and unit variance"}, + ) + enable_padding: bool = field( + default=False, + metadata={"help": "pad shorter samples instead of cropping"}, + ) + max_keep_size: Optional[int] = field( + default=None, + metadata={"help": "exclude sample longer than this"}, + ) + max_sample_size: Optional[int] = field( + default=None, + metadata={"help": "max sample size to crop to for batching"}, + ) + min_sample_size: Optional[int] = field( + default=None, + metadata={"help": "min sample size to crop to for batching"}, + ) + random_crop: Optional[bool] = field( + default=True, + metadata={"help": "always crop from the beginning if false"}, + ) + pad_audio: Optional[bool] = field( + default=False, + metadata={"help": "pad audio to the longest one in the batch if true"}, + ) + + +@register_task("multires_hubert_pretraining", dataclass=MultiresHubertPretrainingConfig) +class MultiresHubertPretrainingTask(FairseqTask): + """ + Multiresolution HuBERT Pretraining Task. + The task is based on `HubertPretrainingTask` but extended to multiresolution. + """ + + cfg: MultiresHubertPretrainingConfig + + def __init__( + self, + cfg: MultiresHubertPretrainingConfig, + ) -> None: + super().__init__(cfg) + + logger.info(f"current directory is {os.getcwd()}") + logger.info(f"MultiresHubertPretrainingTask Config {cfg}") + + self.cfg = cfg + self.fine_tuning = cfg.fine_tuning + + if cfg.fine_tuning: + self.state.add_factory("target_dictionary", self.load_dictionaries) + self.res_number = 1 + else: + self.state.add_factory("dictionaries", self.load_dictionaries) + + self.blank_symbol = "<s>" + + @property + def source_dictionary(self) -> Optional[Dictionary]: + return None + + @property + def target_dictionary(self) -> Optional[Dictionary]: + return self.state.target_dictionary + + @property + def dictionaries(self) -> List[Dictionary]: + return self.state.dictionaries + + @classmethod + def setup_task( + cls, cfg: MultiresHubertPretrainingConfig, **kwargs + ) -> "MultiresHubertPretrainingTask": + return cls(cfg) + + def load_dictionaries(self): + label_dir = self.cfg.data if self.cfg.label_dir is None else self.cfg.label_dir + self.res_number = len(label_dir) + dictionaries = [ (Dictionary.load(f"{label_dir}/dict.{label}.txt") if label is not "" else None ) for label in self.cfg.labels] + return dictionaries[0] if self.cfg.fine_tuning else dictionaries + + def get_label_dir(self) -> str: + if self.cfg.label_dir is None: + return self.cfg.data + return self.cfg.label_dir + + def load_dataset(self, split: str, **kwargs) -> None: + manifest = f"{self.cfg.data}/{split}.tsv" + dicts = [self.target_dictionary] if self.cfg.fine_tuning else self.dictionaries + pad_list = [(dict.pad() if dict is not None else None) for dict in dicts] + eos_list = [(dict.eos() if dict is not None else None) for dict in dicts] + procs = [LabelEncoder(dict) for dict in dicts] + paths = [(f"{self.get_label_dir()}/{split}.{l}" if l != "" else None) for l in self.cfg.labels] + + base_rate = self.cfg.label_rate + self.label_rates = [base_rate] + label_rate_ratios = self.cfg.label_rate_ratios + self.label_rate_ratios = [] + for i in range(len(label_rate_ratios) // 2): + + upsample_rate, downsample_rate = label_rate_ratios[i * 2], label_rate_ratios[i * 2 + 1] + # parse label rate ratios + self.label_rate_ratios.append((upsample_rate, downsample_rate)) + base_rate = base_rate * upsample_rate // downsample_rate + self.label_rates.append(base_rate) + + # hubert v1: pad_audio=True, random_crop=False; + self.datasets[split] = HubertDataset( + manifest, + sample_rate=self.cfg.sample_rate, + label_paths=paths, + label_rates=self.label_rates, + pad_list=pad_list, + eos_list=eos_list, + label_processors=procs, + max_keep_sample_size=self.cfg.max_keep_size, + min_keep_sample_size=self.cfg.min_sample_size, + max_sample_size=self.cfg.max_sample_size, + pad_audio=self.cfg.pad_audio, + normalize=self.cfg.normalize, + store_labels=False, + random_crop=self.cfg.random_crop, + ) + + def max_positions(self) -> Tuple[int, int]: + return (sys.maxsize, sys.maxsize) + + def filter_indices_by_size(self, indices: np.array, *args, **kwargs) -> np.array: + return indices From bedb259bf34a9fc22073c13a1cee23192fa70ef3 Mon Sep 17 00:00:00 2001 From: Jon Janzen <jonjanzen@meta.com> Date: Wed, 13 Mar 2024 09:24:17 -0400 Subject: [PATCH 769/774] Delete .circleci directory (#5458) --- .circleci/config.yml | 128 ------------------------------------------- 1 file changed, 128 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 7710c78c2f..0000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,128 +0,0 @@ -# Use 2.1 for orbs -version: 2.1 - -# ------------------------------------------------------------------------------------- -# Environments to run the jobs in -# ------------------------------------------------------------------------------------- -gpu: &gpu - environment: - CUDA_VERSION: "11.2" - machine: - image: ubuntu-2004-cuda-11.2:202103-01 - resource_class: gpu.nvidia.medium.multi - - -# ------------------------------------------------------------------------------------- -# Re-usable commands -# ------------------------------------------------------------------------------------- -cache_key: &cache_key cache-key-{{ .Environment.CIRCLE_JOB }}-{{ checksum ".circleci/config.yml" }}-{{ checksum "setup.py"}} - -install_dep_pt1_10: &install_dep_pt1_10 - - run: - name: Install Pytorch Dependencies - command: | - source activate fairseq - pip install --upgrade setuptools - pip install torch==1.10.1+cu111 torchaudio==0.10.1+cu111 -f https://download.pytorch.org/whl/torch_stable.html - python -c 'import torch; print("Torch version:", torch.__version__)' - -install_dep_pt1_12: &install_dep_pt1_12 - - run: - name: Install Pytorch Dependencies - command: | - source activate fairseq - pip install --upgrade setuptools - pip install torch==1.12.1+cu116 torchaudio==0.12.1+cu116 -f https://download.pytorch.org/whl/torch_stable.html - python -c 'import torch; print("Torch version:", torch.__version__)' - -install_repo: &install_repo - - run: - name: Install Repository - command: | - source activate fairseq - python -m pip install fairscale - python -m pip install -e '.[dev,docs]' - python -c 'import torch; print("Torch version:", torch.__version__)' - -run_unittests: &run_unittests - - run: - name: Run Unit Tests - command: | - source activate fairseq - pytest tests/gpu/test_binaries_gpu.py - -check_nvidia_driver: &check_nvidia_driver - - run: - name: Check NVIDIA Driver - working_directory: ~/ - command: | - pyenv versions - nvidia-smi - -create_conda_env: &create_conda_env - - run: - name: Install and Create Conda Environment - command: | - curl -o ~/miniconda.sh -O https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh - chmod +x ~/miniconda.sh - bash ~/miniconda.sh -b -p $HOME/miniconda - rm ~/miniconda.sh - echo 'export PATH=$HOME/miniconda/bin:$PATH' >> $BASH_ENV - source $BASH_ENV - if [ ! -d ~/miniconda/envs/fairseq ] - then - conda create -y -n fairseq python=3.8 - fi - source activate fairseq - python --version - pip install --upgrade pip -# ------------------------------------------------------------------------------------- -# Jobs to run -# ------------------------------------------------------------------------------------- - -jobs: - - gpu_tests_pt1_10: - <<: *gpu - - working_directory: ~/fairseq-py - - steps: - - checkout - - <<: *check_nvidia_driver - - <<: *create_conda_env - - restore_cache: - key: *cache_key - - <<: *install_dep_pt1_10 - - save_cache: - paths: - - ~/miniconda/ - key: *cache_key - - <<: *install_repo - - <<: *run_unittests - - gpu_tests_pt1_12: - <<: *gpu - - working_directory: ~/fairseq-py - - steps: - - checkout - - <<: *check_nvidia_driver - - <<: *create_conda_env - - restore_cache: - key: *cache_key - - <<: *install_dep_pt1_12 - - save_cache: - paths: - - ~/miniconda/ - key: *cache_key - - <<: *install_repo - - <<: *run_unittests - -workflows: - version: 2 - build: - jobs: - - gpu_tests_pt1_12 - - gpu_tests_pt1_10 From d9a627082fd03ec72a27a31a4e56289bfcb2e4e4 Mon Sep 17 00:00:00 2001 From: Jon Janzen <jonjanzen@meta.com> Date: Thu, 30 May 2024 22:44:49 +0100 Subject: [PATCH 770/774] Create depreview.yml (#5501) --- .github/workflows/depreview.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .github/workflows/depreview.yml diff --git a/.github/workflows/depreview.yml b/.github/workflows/depreview.yml new file mode 100644 index 0000000000..032eddef5f --- /dev/null +++ b/.github/workflows/depreview.yml @@ -0,0 +1,14 @@ +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v4 + - name: Dependency Review + uses: actions/dependency-review-action@v4 From 920a548ca770fb1a951f7f4289b4d3a0c1bc226f Mon Sep 17 00:00:00 2001 From: Vineel Pratap <vineelkpratap@gmail.com> Date: Mon, 22 Jul 2024 10:17:18 +0200 Subject: [PATCH 771/774] Create README.md (#5529) MMS Zero-shot release --- examples/mms/zero_shot/README.md | 77 ++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 examples/mms/zero_shot/README.md diff --git a/examples/mms/zero_shot/README.md b/examples/mms/zero_shot/README.md new file mode 100644 index 0000000000..7adf492b81 --- /dev/null +++ b/examples/mms/zero_shot/README.md @@ -0,0 +1,77 @@ +# MMS Zero-shot Speech Recognition + +This project builds a single multilingual speech recognition for almost **all** languages spoken in the world by leveraging uroman text as intermediate representation. The model is pre-trained on supervised data in over 1000 languages. At inference time, one only needs to build lexicon and and optional N-gram language models for the unseen language. + +You can download the zero-shot uroman model [here](https://dl.fbaipublicfiles.com/mms/zeroshot/model.pt) and dictionary [here](https://dl.fbaipublicfiles.com/mms/zeroshot/tokens.txt) + +Checkout the demo here [![Open In HF Spaces](https://huggingface.co/datasets/huggingface/badges/raw/main/open-in-hf-spaces-sm-dark.svg)](https://huggingface.co/spaces/mms-meta/mms-zeroshot) + +## Commands to run inference + +1. Prepare uroman-based lexicon: build a lexicon file by applying [uroman](https://github.com/isi-nlp/uroman) over your file or words. Refer to the format below. +``` +abiikira a b i i k i r a | +úwangaba u w a n g a b a | +banakana b a n a k a n a | +... +... +``` + +Each uroman token in the spelling of the final lexicon should appear in the token dictionary of the model. + +2. [Optional] Prepare N-gram language model: build LMs with [KenLM](https://github.com/kpu/kenlm). We found using even 1-gram LMs can produce very good results. + +Inference command example + +``` +# lexicon only + +model_path= # place the downloaded uroman model here +data_path= # path containing your tsv and wrd files +subset= # subset in your data path +lex_filepath= # your uroman lexicon +lm_filepath= # any n-gram lm as a placeholder; not used +wrdscore=-3.5 # can be tuned on your data +res_path= +bs=2000 # bs=500 is good too + +PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=kenlm dataset.max_tokens=2000000 distributed_training.distributed_world_size=1 "common_eval.path=${model_path}" task.data=${data_path} dataset.gen_subset=mms_eng:${subset} decoding.lexicon=${lex_filepath} decoding.lmpath=${lm_filepath} decoding.lmweight=0 decoding.wordscore=${wrdscore} decoding.silweight=0 decoding.results_path=${res_path} decoding.beam=${beam} +``` + + +``` +# n-gram lm + +model_path= # place the downloaded uroman model here +data_path= # path containing your tsv and wrd files +subset= # subset in your data path +lex_filepath= # your uroman lexicon +lm_filepath= # your kenlm +wrdscore=-0.18 # wrdscore and lmweight can be tuned together on your data +lmweight=1.48 +res_path= +bs=2000 + +PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=kenlm dataset.max_tokens=2000000 distributed_training.distributed_world_size=1 "common_eval.path=${model_path}" task.data=${data_path} dataset.gen_subset=mms_eng:${subset} decoding.lexicon=${lex_filepath} decoding.lmpath=${lm_filepath} decoding.lmweight=${lmweight} decoding.wordscore=${wrdscore} decoding.silweight=0 decoding.results_path=${res_path} decoding.beam=${bs} + +``` + +Note that the commands won't give proper CER directly, as they don't handle your reference file properly if your script is not included the dictionary. You will need to calculate CER yourself after generation is done. + +# License + +The MMS Zero shot code and model weights are released under the CC-BY-NC 4.0 license. + +# Citation + +**BibTeX:** + +``` +@article{zhao2024zeroshot, + title={Scaling a Simple Approach to Zero-shot Speech Recognition}, + author={Jinming Zhao, Vineel Pratap and Michael Auli}, + journal={arXiv}, + year={2024} +} + +``` From c2145111e77312cb09df1d61114bb9a902afe57b Mon Sep 17 00:00:00 2001 From: Brian Yan <brianyan918@gmail.com> Date: Thu, 26 Sep 2024 19:13:41 -0700 Subject: [PATCH 772/774] Add LID rerank for MMS (#5545) * init lid rerank * init lid rerank * add greedy ctc score --- examples/mms/lid_rerank/README.md | 115 +++++++++ examples/mms/lid_rerank/cer_langs.txt | 11 + examples/mms/lid_rerank/mala/infer.py | 55 ++++ examples/mms/lid_rerank/mms-zs/falign.py | 87 +++++++ examples/mms/lid_rerank/mms-zs/lib.py | 239 ++++++++++++++++++ examples/mms/lid_rerank/mms-zs/uromanize.py | 69 +++++ .../mms/make_parallel_single_runs.py | 22 ++ examples/mms/lid_rerank/mms/merge_by_lang.py | 33 +++ examples/mms/lid_rerank/mms/prep_wav_list.py | 22 ++ .../mms/lid_rerank/mms/run_single_lang.py | 65 +++++ examples/mms/lid_rerank/mms/split_by_lang.py | 90 +++++++ examples/mms/lid_rerank/nllb/infer.py | 46 ++++ examples/mms/lid_rerank/requirements.txt | 10 + examples/mms/lid_rerank/rerank/rerank.py | 132 ++++++++++ .../lid_rerank/rerank/tune_coefficients.py | 138 ++++++++++ examples/mms/lid_rerank/whisper/infer_asr.py | 71 ++++++ examples/mms/lid_rerank/whisper/infer_lid.py | 65 +++++ .../mms/lid_rerank/whisper/lid_mapping.txt | 99 ++++++++ .../new/decoders/viterbi_decoder.py | 6 +- examples/speech_recognition/new/infer.py | 5 +- 20 files changed, 1376 insertions(+), 4 deletions(-) create mode 100644 examples/mms/lid_rerank/README.md create mode 100644 examples/mms/lid_rerank/cer_langs.txt create mode 100755 examples/mms/lid_rerank/mala/infer.py create mode 100755 examples/mms/lid_rerank/mms-zs/falign.py create mode 100755 examples/mms/lid_rerank/mms-zs/lib.py create mode 100755 examples/mms/lid_rerank/mms-zs/uromanize.py create mode 100755 examples/mms/lid_rerank/mms/make_parallel_single_runs.py create mode 100755 examples/mms/lid_rerank/mms/merge_by_lang.py create mode 100755 examples/mms/lid_rerank/mms/prep_wav_list.py create mode 100755 examples/mms/lid_rerank/mms/run_single_lang.py create mode 100755 examples/mms/lid_rerank/mms/split_by_lang.py create mode 100755 examples/mms/lid_rerank/nllb/infer.py create mode 100644 examples/mms/lid_rerank/requirements.txt create mode 100755 examples/mms/lid_rerank/rerank/rerank.py create mode 100755 examples/mms/lid_rerank/rerank/tune_coefficients.py create mode 100755 examples/mms/lid_rerank/whisper/infer_asr.py create mode 100755 examples/mms/lid_rerank/whisper/infer_lid.py create mode 100755 examples/mms/lid_rerank/whisper/lid_mapping.txt diff --git a/examples/mms/lid_rerank/README.md b/examples/mms/lid_rerank/README.md new file mode 100644 index 0000000000..3fa599f08a --- /dev/null +++ b/examples/mms/lid_rerank/README.md @@ -0,0 +1,115 @@ +# N-best Re-ranking for Multilingual LID+ASR +This project provides N-best re-ranking, a simple inference procedure, for improving multilingual speech recognition (ASR) "in the wild" where models are expected to first predict language identity (LID) before transcribing. Our method considers N-best LID predictions for each utterance, runs the corresponding ASR in N different languages, and then uses external features over the candidate transcriptions to determine re-rank. + +The workflow is as follows: 1) run LID+ASR inference (MMS and Whisper are supported), 2) compute external re-ranking features, 3) tune feature coefficients on dev set, and 4) apply on test set. + +For more information about our method, please refer to the paper: "Improving Multilingual ASR in the Wild Using Simple N-best Re-ranking". + +## 1) Commands to Run LID+ASR Inference + +### Data Prep +Prepare a text file with one path to a wav file in each line: +``` +#/path/to/wav/list +/path/to/audio1.wav +/path/to/audio2.wav +/path/to/audio3.wav +``` + +The following workflow also assumes that LID and ASR references are available (at least for the dev set). We use [3-letter iso codes](https://dl.fbaipublicfiles.com/mms/lid/mms1b_l4017_langs.html) for both Whisper and MMS. + +Next run either Whisper or MMS based LID+ASR. + +### Whisper +Refer to the [Whisper documentation](https://github.com/openai/whisper) for installation instructions. + +First run LID: +``` +python whisper/infer_lid.py --wavs "path/to/wav/list" --dst "path/to/lid/results" --model large-v2 --n 10 +``` +Note that the size of the N-best list is set as 10 here. + +Then run ASR, using the top-N LID predictions: +``` +python whisper/infer_asr.py --wavs "path/to/wav/list" --lids "path/to/lid/results"/nbest_lid --dst "path/to/asr/results" --model large-v2 +``` + +### MMS +Refer to the [Fairseq documentation](https://github.com/facebookresearch/fairseq/tree/main) for installation instructions. + +Prepare data and models following the [instructions from the MMS repository](https://github.com/facebookresearch/fairseq/tree/main/examples/mms). Note that the MMS backend expects a slightly different wav list format, which can be obtained via: +``` +python mms/format_wav_list.py --src "/path/to/wav/list" --dst "/path/to/wav/manifest.tsv" +``` +Note that MMS also expects LID references in a file named `"/path/to/wav/manifest.lang"`. + +Then run LID: +``` +cd "path/to/fairseq/dir" +PYTHONPATH='.' python3 examples/mms/lid/infer.py "path/to/dict/dir" --path "path/to/model" --task audio_classification --infer-manifest "path/to/wav/manifest.tsv" --output-path "path/to/lid/results" --top-k 10 +``` +Note that the size of the N-best list is set as 10 here. + +Then run ASR, using the top-N LID predictions. Since MMS uses language-specific parameters, we've parallelized inference across languages: +``` +#Split data by language +python mms/split_by_lang.py --wavs_tsv "/path/to/wav/manifest.tsv" --lid_preds "path/to/lid/results"predictions.txt --dst "path/to/data/split" + +#Write language-specific ASR python commands to an executable file +mms/make_parallel_single_runs.py --dump "path/to/data/split" --model "path/to/model" --dst "path/to/asr/results" --fairseq_dir "path/to/fairseq/dir" > run.sh + +#Running each language sequentially (you can also parallelize this) +. ./run.sh + +#Merge language-specific results back to original order +python mms/merge_by_run.py --dump "path/to/data/split" --exp "path/to/asr/results" +``` + +## 2) Commands to Compute External Re-ranking Features + +### MaLA - Large Language Model +``` +python mala/infer.py --txt "path/to/asr/results"/nbest_asr_hyp --dst "path/to/lm/results" +``` + +### NLLB - Written LID Model +Download the model from the [official source](https://github.com/facebookresearch/fairseq/tree/nllb#lid-model). + +``` +python nllb/infer.py --txt "path/to/asr/results"/nbest_asr_hyp --dst "path/to/wlid/results" --model "path/to/nllb/model" +``` + +### MMS-Zeroshot - U-roman Acoustic Model +Download the model from the [official source](https://huggingface.co/spaces/mms-meta/mms-zeroshot/tree/main). + +First run u-romanization on the N-best ASR hypotheses: +``` +python mms-zs/uromanize.py --txt "path/to/asr/results"/nbest_asr_hyp --lid "path/to/lid/results"/nbest_lid --dst "path/to/uasr/results" --model "path/to/mms-zeroshot" +``` + +Then compute the forced alignment score using the MMS-Zeroshot model: +``` +python mms-zs/falign.py --uroman_txt "path/to/uasr/results"/nbest_asr_hyp_uroman --wav "path/to/wav/list" --dst "path/to/uasr/results" --model "path/to/mms-zeroshot" +``` + +## 3) Commands to Tune Feature Coefficients +``` +python rerank/tune_coefficients.py --slid "path/to/lid/results"/slid_score --asr "path/to/asr/results"/asr_score --wlid "path/to/wlid/results"/wlid_score --lm "path/to/lm/results"/lm_score --uasr "path/to/uasr/results"/uasr_score --dst "path/to/rerank/results" --ref_lid "ground-truth/lid" --nbest_lid "path/to/lid/results"/nbest_lid --ref_asr "ground-truth/asr" --nbest_asr "path/to/asr/results"/nbest_asr_hyp +``` + +## 4) Commands to Apply on Test Set +``` +python rerank/rerank.py --slid "path/to/lid/results"/slid_score --asr "path/to/asr/results"/asr_score --wlid "path/to/wlid/results"/wlid_score --lm "path/to/lm/results"/lm_score --uasr "path/to/uasr/results"/uasr_score --dst "path/to/rerank/results" --ref_lid "ground-truth/lid" --nbest_lid "path/to/lid/results"/nbest_lid --ref_asr "ground-truth/asr" --nbest_asr "path/to/asr/results"/nbest_asr_hyp --w "path/to/rerank/results"/best_coefficients +``` + +The re-ranked LID and ASR will be in `"path/to/rerank/results"/reranked_1best_lid` and `"path/to/rerank/results"/reranked_1best_asr_hyp` respectively. + +# Citation +``` +@article{yan2024wild, + title={Improving Multilingual ASR in the Wild Using Simple N-best Re-ranking}, + author={Brian Yan, Vineel Pratap, Shinji Watanabe, Michael Auli}, + journal={arXiv}, + year={2024} +} +``` \ No newline at end of file diff --git a/examples/mms/lid_rerank/cer_langs.txt b/examples/mms/lid_rerank/cer_langs.txt new file mode 100644 index 0000000000..ca012967cd --- /dev/null +++ b/examples/mms/lid_rerank/cer_langs.txt @@ -0,0 +1,11 @@ +adx +bod +cmn +dzo +jpn +khg +khm +lao +mya +tha +yue diff --git a/examples/mms/lid_rerank/mala/infer.py b/examples/mms/lid_rerank/mala/infer.py new file mode 100755 index 0000000000..60acc164dc --- /dev/null +++ b/examples/mms/lid_rerank/mala/infer.py @@ -0,0 +1,55 @@ +from transformers import AutoTokenizer, AutoModelForCausalLM +from peft import PeftModel +from tqdm import tqdm +import argparse +import os +import torch + +parser = argparse.ArgumentParser() +parser.add_argument("--txt", type=str) +parser.add_argument("--dst", type=str) +parser.add_argument("--gpu", type=int, default=1) +args = parser.parse_args() + +if __name__ == "__main__": + if not os.path.exists(args.dst): + os.makedirs(args.dst) + + base_model = AutoModelForCausalLM.from_pretrained('meta-llama/Llama-2-7b-hf') + base_model.resize_token_embeddings(260164) + tokenizer = AutoTokenizer.from_pretrained('MaLA-LM/mala-500') + if args.gpu == 1: + model = PeftModel.from_pretrained(base_model, 'MaLA-LM/mala-500').to("cuda") + else: + model = PeftModel.from_pretrained(base_model, 'MaLA-LM/mala-500') + model.eval() + + txts = [x.strip() for x in open(args.txt, "r").readlines()] + + with open(args.dst + "/lm_score", "w", buffering=1) as f: + for t in tqdm(txts): + input_tokens = tokenizer("", add_special_tokens=True, return_tensors='pt').input_ids + if len(t) > 0: + output_tokens = tokenizer(t, add_special_tokens=False, return_tensors='pt').input_ids + tokens = torch.cat([input_tokens, output_tokens], dim=1) + length = output_tokens.shape[-1] + else: + tokens = input_tokens + length = 0 + + if args.gpu == 1: + tokens = tokens.to("cuda") + + with torch.no_grad(): + outputs = model(tokens) + logits = outputs.logits + + log_sum = 0 + for i in range(tokens.shape[-1] - 1): + past_tok, current_tok = i, i + 1 + token_logit = logits[0, past_tok, :] + token_log_probs = torch.nn.functional.log_softmax(token_logit, dim=-1) + log_token_prob = token_log_probs[tokens[0, current_tok]].item() + log_sum += log_token_prob + + f.write(str(log_sum) + "\n") \ No newline at end of file diff --git a/examples/mms/lid_rerank/mms-zs/falign.py b/examples/mms/lid_rerank/mms-zs/falign.py new file mode 100755 index 0000000000..bb170b7e99 --- /dev/null +++ b/examples/mms/lid_rerank/mms-zs/falign.py @@ -0,0 +1,87 @@ +import os +import tempfile +import re +import librosa +import torch +import json +import numpy as np +import argparse +from tqdm import tqdm +import math + +from transformers import Wav2Vec2ForCTC, AutoProcessor + +from lib import falign_ext + +parser = argparse.ArgumentParser() +parser.add_argument("--uroman_txt", type=str) +parser.add_argument("--wav", type=str) +parser.add_argument("--dst", type=str) +parser.add_argument("--model", type=str) +parser.add_argument("--n", type=int, default=10) +args = parser.parse_args() + +ASR_SAMPLING_RATE = 16_000 + +MODEL_ID = "/upload/mms_zs" + +processor = AutoProcessor.from_pretrained(args.model+MODEL_ID) +model = Wav2Vec2ForCTC.from_pretrained(args.model+MODEL_ID) + +token_file = args.model+"/upload/mms_zs/tokens.txt" + +if __name__ == "__main__": + if not os.path.exists(args.dst): + os.makedirs(args.dst) + + tokens = [x.strip() for x in open(token_file, "r").readlines()] + + txts = [x.strip() for x in open(args.uroman_txt, "r").readlines()] + wavs = [x.strip() for x in open(args.wav, "r").readlines()] + assert len(txts) == args.n * len(wavs) + + if torch.cuda.is_available(): + device = torch.device("cuda") + elif ( + hasattr(torch.backends, "mps") + and torch.backends.mps.is_available() + and torch.backends.mps.is_built() + ): + device = torch.device("mps") + else: + device = torch.device("cpu") + + model.to(device) + + # clear it + with open(args.dst + "/uasr_score", "w") as f1: + pass + + for i, w in tqdm(enumerate(wavs)): + assert isinstance(w, str) + audio_samples = librosa.load(w, sr=ASR_SAMPLING_RATE, mono=True)[0] + + inputs = processor( + audio_samples, sampling_rate=ASR_SAMPLING_RATE, return_tensors="pt" + ) + inputs = inputs.to(device) + + with torch.no_grad(): + outputs = model(**inputs).logits + + emissions = outputs.log_softmax(dim=-1).squeeze() + + for j in range(args.n): + idx = (args.n * i) + j + chars = txts[idx].split() + token_sequence = [tokens.index(x) for x in chars] + + try: + _, alphas, _ = falign_ext.falign(emissions, torch.tensor(token_sequence, device=device).int(), False) + aligned_alpha = max(alphas[-1]).item() + except: + aligned_alpha = math.log(0.000000001) + + with open(args.dst + "/uasr_score", "a") as f1: + f1.write(str(aligned_alpha) + "\n") + f1.flush() \ No newline at end of file diff --git a/examples/mms/lid_rerank/mms-zs/lib.py b/examples/mms/lid_rerank/mms-zs/lib.py new file mode 100755 index 0000000000..def3b82096 --- /dev/null +++ b/examples/mms/lid_rerank/mms-zs/lib.py @@ -0,0 +1,239 @@ +import os +from dataclasses import dataclass +import torch +import torch.utils.cpp_extension + +cuda_source = """ + +#include <ATen/core/TensorAccessor.h> +#include <ATen/cuda/CUDAContext.h> +#include <torch/extension.h> +#include <vector> +#include <limits.h> +#include <cub/cub.cuh> +#include <iostream> + +using namespace torch::indexing; + +constexpr int kNumThreads = 1024; +constexpr float kNegInfinity = -std::numeric_limits<float>::infinity(); +constexpr int kBlankIdx = 0; + +__global__ void +falign_cuda_step_kernel( + const torch::PackedTensorAccessor32<float, 2, torch::RestrictPtrTraits> + emissions_a, + const torch::PackedTensorAccessor32<int32_t, 1, torch::RestrictPtrTraits> + target_a, + const int T, const int L, const int N, const int R, const int t, int start, + int end, torch::PackedTensorAccessor32<float, 2, torch::RestrictPtrTraits> + runningAlpha_a, + torch::PackedTensorAccessor32<int32_t, 1, torch::RestrictPtrTraits> + backtrack_a, const bool normalize) +{ + int S = 2 * L + 1; + + int idx1 = (t % 2); // current time step frame for alpha + int idx2 = ((t - 1) % 2); // previous time step frame for alpha + + // reset alpha and backtrack values + for (int i = threadIdx.x; i < S; i += blockDim.x) { + runningAlpha_a[idx1][i] = kNegInfinity; + backtrack_a[i] = -1; + } + // This could potentially be removed through careful indexing inside each thread + // for the above for loop. But this is okay for now. + __syncthreads(); + + if (t == 0) { + for (int i = start + threadIdx.x; i < end; i += blockDim.x) { + int labelIdx = (i % 2 == 0) ? kBlankIdx : target_a[i / 2]; + runningAlpha_a[idx1][i] = emissions_a[0][labelIdx]; + } + return; + } + + using BlockReduce = cub::BlockReduce<float, kNumThreads>; + __shared__ typename BlockReduce::TempStorage tempStorage; + __shared__ float maxValue; + + float threadMax; + + int startloop = start; + + threadMax = kNegInfinity; + + if (start == 0 && threadIdx.x == 0) { + runningAlpha_a[idx1][0] = + runningAlpha_a[idx2][0] + emissions_a[t][kBlankIdx]; + threadMax = max(threadMax, runningAlpha_a[idx1][0]); + + backtrack_a[0] = 0; + // startloop += 1; // startloop is threadlocal meaning it would only be changed for threads entering this loop (ie threadIdx == 0) + } + if(start == 0) { + startloop += 1; + } + + for (int i = startloop + threadIdx.x; i < end; i += blockDim.x) { + float x0 = runningAlpha_a[idx2][i]; + float x1 = runningAlpha_a[idx2][i - 1]; + float x2 = kNegInfinity; + + int labelIdx = (i % 2 == 0) ? kBlankIdx : target_a[i / 2]; + + if (i % 2 != 0 && i != 1 && target_a[i / 2] != target_a[i / 2 - 1]) { + x2 = runningAlpha_a[idx2][i - 2]; + } + + float result = 0.0; + if (x2 > x1 && x2 > x0) { + result = x2; + backtrack_a[i] = 2; + } else if (x1 > x0 && x1 > x2) { + result = x1; + backtrack_a[i] = 1; + } else { + result = x0; + backtrack_a[i] = 0; + } + + runningAlpha_a[idx1][i] = result + emissions_a[t][labelIdx]; + threadMax = max(threadMax, runningAlpha_a[idx1][i]); + } + + float maxResult = BlockReduce(tempStorage).Reduce(threadMax, cub::Max()); + if (threadIdx.x == 0) { + maxValue = maxResult; + } + + __syncthreads(); + // normalize alpha values so that they don't overflow for large T + if(normalize) { + for (int i = threadIdx.x; i < S; i += blockDim.x) { + runningAlpha_a[idx1][i] -= maxValue; + } + } +} + +std::tuple<std::vector<int>, torch::Tensor, torch::Tensor> +falign_cuda(const torch::Tensor& emissions, const torch::Tensor& target, const bool normalize=false) +{ + TORCH_CHECK(emissions.is_cuda(), "need cuda tensors"); + TORCH_CHECK(target.is_cuda(), "need cuda tensors"); + TORCH_CHECK(target.device() == emissions.device(), + "need tensors on same cuda device"); + TORCH_CHECK(emissions.dim() == 2 && target.dim() == 1, "invalid sizes"); + TORCH_CHECK(target.sizes()[0] > 0, "target size cannot be empty"); + + + + int T = emissions.sizes()[0]; // num frames + int N = emissions.sizes()[1]; // alphabet size + int L = target.sizes()[0]; // label length + const int S = 2 * L + 1; + + + auto targetCpu = target.to(torch::kCPU); + + + // backtrack stores the index offset fthe best path at current position + // We copy the values to CPU after running every time frame. + + auto backtrack = torch::zeros({ S }, torch::kInt32).to(emissions.device()); + auto backtrackCpu = torch::zeros( + { T, S }, torch::TensorOptions().dtype(torch::kInt32).device(torch::kCPU)); + TORCH_CHECK(backtrack.is_cuda(), "need cuda tensors"); + TORCH_CHECK(!backtrackCpu.is_cuda(), "need cpu tensors"); + + + + // we store only two time frames for alphas + // alphas for compute current timeframe can be computed only from previous time frame. + + auto runningAlpha = + torch::zeros( + { 2, S }, + torch::TensorOptions().dtype(torch::kFloat).device(emissions.device())); + auto alphaCpu = + torch::zeros( + { T, S }, + torch::TensorOptions().dtype(torch::kFloat).device(torch::kCPU)); + TORCH_CHECK(runningAlpha.is_cuda(), "need cuda tensors"); + TORCH_CHECK(!alphaCpu.is_cuda(), "need cpu tensors"); + + auto stream = at::cuda::getCurrentCUDAStream(); + + // CUDA accessors + auto emissions_a = emissions.packed_accessor32<float, 2, torch::RestrictPtrTraits>(); + auto target_a = target.packed_accessor32<int32_t, 1, torch::RestrictPtrTraits>(); + auto runningAlpha_a = + runningAlpha.packed_accessor32<float, 2, torch::RestrictPtrTraits>(); + auto backtrack_a = + backtrack.packed_accessor32<int32_t, 1, torch::RestrictPtrTraits>(); + + + // CPU accessors + auto targetCpu_a = targetCpu.accessor<int32_t, 1>(); + auto backtrackCpu_a = backtrackCpu.accessor<int32_t, 2>(); + auto aphaCpu_a = alphaCpu.accessor<float, 2>(); + + // count the number of repeats in label + int R = 0; + for (int i = 1; i < L; ++i) { + if (targetCpu_a[i] == targetCpu_a[i - 1]) { + ++R; + } + } + TORCH_CHECK(T >= (L + R), "invalid sizes 2"); + + + int start = (T - (L + R)) > 0 ? 0 : 1; + int end = (S == 1) ? 1 : 2; + for (int t = 0; t < T; ++t) { + if (t > 0) { + if (T - t <= L + R) { + if ((start % 2 == 1) && + (targetCpu_a[start / 2] != targetCpu_a[start / 2 + 1])) { + start = start + 1; + } + start = start + 1; + } + if (t <= L + R) { + if ((end % 2 == 0) && (end < 2 * L) && + (targetCpu_a[end / 2 - 1] != targetCpu_a[end / 2])) { + end = end + 1; + } + end = end + 1; + } + } + falign_cuda_step_kernel<<<1, kNumThreads, 0, stream>>>( + emissions_a, target_a, T, L, N, R, t, start, end, runningAlpha_a, + backtrack_a, normalize); + + backtrackCpu.index_put_({ t, Slice()}, backtrack.to(torch::kCPU)); + alphaCpu.index_put_({ t, Slice()}, runningAlpha.slice(0, t % 2, t % 2 + 1).to(torch::kCPU)); + } + + int idx1 = ((T - 1) % 2); + int ltrIdx = runningAlpha[idx1][S - 1].item<float>() > + runningAlpha[idx1][S - 2].item<float>() + ? S - 1 + : S - 2; + + std::vector<int> path(T); + for (int t = T - 1; t >= 0; --t) { + path[t] = (ltrIdx % 2 == 0) ? 0 : targetCpu_a[ltrIdx / 2]; + ltrIdx -= backtrackCpu_a[t][ltrIdx]; + } + + // returning runningAlpha, backtrackCpu for debugging purposes + return std::make_tuple(path, alphaCpu, backtrackCpu); +} + +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) +{ + m.def("falign", &falign_cuda, "falign cuda"); +} +""" +falign_ext = torch.utils.cpp_extension.load_inline("falign", cpp_sources="", cuda_sources=cuda_source, extra_cflags=['-O3'], verbose=True ) \ No newline at end of file diff --git a/examples/mms/lid_rerank/mms-zs/uromanize.py b/examples/mms/lid_rerank/mms-zs/uromanize.py new file mode 100755 index 0000000000..5615901eef --- /dev/null +++ b/examples/mms/lid_rerank/mms-zs/uromanize.py @@ -0,0 +1,69 @@ +import os +import tempfile +import re +import argparse +from tqdm import tqdm + +parser = argparse.ArgumentParser() +parser.add_argument("--txt", type=str) +parser.add_argument("--lid", type=str) +parser.add_argument("--dst", type=str) +parser.add_argument("--model", type=str) +args = parser.parse_args() + +UROMAN_PL = args.model + "uroman/bin/uroman.pl" + +def norm_uroman(text): + text = text.lower() + text = text.replace("’", "'") + text = re.sub("([^a-z' ])", " ", text) + text = re.sub(" +", " ", text) + return text.strip() + +def uromanize(words): + iso = "xxx" + with tempfile.NamedTemporaryFile() as tf, tempfile.NamedTemporaryFile() as tf2: + with open(tf.name, "w") as f: + f.write("\n".join(words)) + cmd = f"perl " + UROMAN_PL + cmd += f" -l {iso} " + cmd += f" < {tf.name} > {tf2.name}" + os.system(cmd) + lexicon = {} + with open(tf2.name) as f: + for idx, line in enumerate(f): + if not line.strip(): + continue + line = re.sub(r"\s+", "", norm_uroman(line)).strip() + lexicon[words[idx]] = " ".join(line) + " |" + return lexicon + +def convert_sent(txt, char_lang=False): + if char_lang: + words = txt + else: + words = txt.split(" ") + lexicon = uromanize(words) + pron = [] + pron_no_sp = [] + for w in words: + if w in lexicon: + pron.append(lexicon[w]) + pron_no_sp.append(lexicon[w].replace(" |", "")) + + return " ".join(pron), " ".join(pron_no_sp) + +if __name__ == "__main__": + if not os.path.exists(args.dst): + os.makedirs(args.dst) + + txts = [x.strip() for x in open(args.txt, "r").readlines()] + langs = [x.strip() for x in open(args.lid, "r").readlines()] + assert len(txts) == len(langs) + + cer_langs = [x.strip() for x in open("cer_langs.txt", "r").readlines()] + + with open(args.dst + "/nbest_asr_hyp_uroman", "w", buffering=1) as f: + for t, l in tqdm(zip(txts,langs), total=len(txts)): + pron, _ = convert_sent(t, l in cer_langs) + f.write(pron + "\n") diff --git a/examples/mms/lid_rerank/mms/make_parallel_single_runs.py b/examples/mms/lid_rerank/mms/make_parallel_single_runs.py new file mode 100755 index 0000000000..e015b14f4c --- /dev/null +++ b/examples/mms/lid_rerank/mms/make_parallel_single_runs.py @@ -0,0 +1,22 @@ +import argparse +import json +from collections import defaultdict +import os +from tqdm import tqdm +import sys +import subprocess +import re + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Example argument parser') + parser.add_argument('--dump', type=str) + parser.add_argument('--model', type=str) + parser.add_argument('--dst', type=str) + parser.add_argument('--fairseq_dir', type=str) + args = parser.parse_args() + + langs = [d for d in os.listdir(args.dump) if os.path.isdir(os.path.join(args.dump, d))] + + for lang in langs: + print(f"python mms/run_single_lang.py --dump {os.path.abspath(args.dump)} --lang {lang} --model {os.path.abspath(args.model)} --dst {os.path.abspath(args.dst)} --fairseq_dir {os.path.abspath(args.fairseq_dir)}") + \ No newline at end of file diff --git a/examples/mms/lid_rerank/mms/merge_by_lang.py b/examples/mms/lid_rerank/mms/merge_by_lang.py new file mode 100755 index 0000000000..9a643b9289 --- /dev/null +++ b/examples/mms/lid_rerank/mms/merge_by_lang.py @@ -0,0 +1,33 @@ +import argparse +import json +from collections import defaultdict +import os +import soundfile as sf +from tqdm import tqdm + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Example argument parser') + parser.add_argument('--exp', type=str) + parser.add_argument('--dump', type=str) + args = parser.parse_args() + + langs = [d for d in os.listdir(args.dump) if os.path.isdir(os.path.join(args.dump, d))] + + data = {} + + for lang in langs: + ids = [int(x.strip()) for x in open(args.dump + "/" + lang + "/ids.txt", "r").readlines()] + word_hyps = [x.strip() for x in open(args.exp + "/" + lang + "/hypo.word.reord", "r").readlines()] + scores = [x.strip() for x in open(args.exp + "/" + lang + "/asr_score.reord", "r").readlines()] + assert len(ids) == len(word_hyps) + assert len(ids) == len(scores) + for id, word_hyp, s in zip(ids, word_hyps, scores): + if id in data: + print("Duplicate ID found") + import pdb;pdb.set_trace() + data[id] = (word_hyp, s) + + with open(args.exp + "/nbest_asr_hyp", "w") as f1, open(args.exp + "/asr_score", "w") as f2: + for i in range(len(data.keys())): + f1.write(data[i][0] + "\n") + f2.write(data[i][1] + "\n") \ No newline at end of file diff --git a/examples/mms/lid_rerank/mms/prep_wav_list.py b/examples/mms/lid_rerank/mms/prep_wav_list.py new file mode 100755 index 0000000000..725274fcbe --- /dev/null +++ b/examples/mms/lid_rerank/mms/prep_wav_list.py @@ -0,0 +1,22 @@ +import soundfile as sf +import argparse + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Example argument parser') + parser.add_argument('--src', type=str) + args = parser.parse_args() + + wavs = [x.strip() for x in open(args.src, "r").readlines()] + + new_lines = ["/"] + for wav in wavs: + # Read the wav file + data, sample_rate = sf.read(wav) + + # Number of samples is the length of the data array + num_samples = len(data) + + new_lines.append(wav+"\t"+str(num_samples)) + + with open(args.dst, "w") as f: + f.writelines([x+"\n" for x in new_lines]) diff --git a/examples/mms/lid_rerank/mms/run_single_lang.py b/examples/mms/lid_rerank/mms/run_single_lang.py new file mode 100755 index 0000000000..aeebb17120 --- /dev/null +++ b/examples/mms/lid_rerank/mms/run_single_lang.py @@ -0,0 +1,65 @@ +import argparse +import json +from collections import defaultdict +import os +from tqdm import tqdm +import sys +import subprocess +import re + +mapping = {"cmn":"cmn-script_simplified", "srp":"srp-script_latin", "urd":"urd-script_arabic", "uzb":"uzb-script_latin", "yue":"yue-script_traditional", "aze":"azj-script_latin", "kmr":"kmr-script_latin"} + +def reorder_decode(hypos): + outputs = [] + for hypo in hypos: + idx = int(re.findall("\(None-(\d+)\)$", hypo)[0]) + hypo = re.sub("\(\S+\)$", "", hypo).strip() + outputs.append((idx, hypo)) + outputs = sorted(outputs) + return outputs + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Example argument parser') + parser.add_argument('--dump', type=str) + parser.add_argument('--model', type=str) + parser.add_argument('--fairseq_dir', type=str) + parser.add_argument('--dst', type=str) + parser.add_argument('--lang', type=str) + args = parser.parse_args() + + if not os.path.exists(args.dst): + os.makedirs(args.dst) + lang = args.lang + dst = args.dst + "/" + lang + if not os.path.exists(dst): + os.makedirs(dst) + dump = args.dump + "/" + lang + if lang in mapping: + lang_code = mapping[lang] + else: + lang_code = lang + + cmd = f""" + cd {args.fairseq_dir}/ &&\ + PYTHONPATH=. PREFIX=INFER HYDRA_FULL_ERROR=1 python examples/speech_recognition/new/infer.py -m --config-dir examples/mms/asr/config/ --config-name infer_common decoding.type=viterbi dataset.max_tokens=1440000 distributed_training.distributed_world_size=1 "common_eval.path='{args.model}'" task.data={dump} dataset.gen_subset="{lang_code}:test" common_eval.post_process=letter decoding.results_path={dst} &&\ + cd - + """ + + print(cmd, file=sys.stderr) + print(f">>> {lang}", file=sys.stderr) + try: + subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL,) + with open(dst + "/hypo.word") as fr, open(dst + "/hypo.word.reord", "w") as fw: + hypos = fr.readlines() + outputs = reorder_decode(hypos) + fw.writelines([re.sub("\(\S+\)$", "", hypo).strip() + "\n" for ii,hypo in outputs]) + with open(dst + "/asr_score") as fr, open(dst + "/asr_score.reord", "w") as fw: + hypos = fr.readlines() + outputs = reorder_decode(hypos) + fw.writelines([re.sub("\(\S+\)$", "", hypo).strip() + "\n" for ii,hypo in outputs]) + except: + print(f"Something went wrong with {lang}. If {lang} is not supported by the ASR model, then this is expected and OK. If it is supported, then something else has gone wrong unexpectedly.", file=sys.stderr) + with open(dst + "/hypo.word.reord", "w") as fw: + fw.writelines(["\n"] * len(open(dump+"/ids.txt", "r").readlines())) + with open(dst + "/asr_score.reord", "w") as fw: + fw.writelines(["\n"] * len(open(dump+"/ids.txt", "r").readlines())) \ No newline at end of file diff --git a/examples/mms/lid_rerank/mms/split_by_lang.py b/examples/mms/lid_rerank/mms/split_by_lang.py new file mode 100755 index 0000000000..b123e406f2 --- /dev/null +++ b/examples/mms/lid_rerank/mms/split_by_lang.py @@ -0,0 +1,90 @@ +import argparse +import json +from collections import defaultdict +import os +import soundfile as sf +from tqdm import tqdm + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Example argument parser') + parser.add_argument('--wavs_tsv', type=str) + parser.add_argument('--lid_preds', type=str) + parser.add_argument('--dst', type=str) + parser.add_argument('--refs', type=str, default=None) + parser.add_argument('--langs', type=str, default=None) + parser.add_argument('--confs', type=str, default=None) + args = parser.parse_args() + + # split wavs into dst/lang/wav.txt and dst/lang/ids.txt + # uses lid_preds to create topk asr; 1 wav has k different lid + + wavs_tsv = [x for x in open(args.wavs_tsv, "r").readlines()] + root = wavs_tsv[0] + wavs = wavs_tsv[1:] + lid_preds = [eval(x) for x in open(args.lid_preds, "r").readlines()] + if args.refs is not None: + refs = [x.strip() for x in open(args.refs, "r").readlines()] + assert len(wavs) == len(refs) + refs_filt = [] + if args.langs is not None: + langs = [x.strip() for x in open(args.langs, "r").readlines()] + assert len(wavs) == len(langs) + langs_filt = [] + if args.confs is not None: + confs = [x.strip() for x in open(args.confs, "r").readlines()] + assert len(wavs) == len(confs) + confs_filt = [] + + assert len(wavs) == len(lid_preds) + + topk_wavs = [] + topk_langs = [] + + for i, (w, p) in enumerate(zip(wavs, lid_preds)): + if p == "n/a": + continue + + assert len(p) == len(lid_preds[0]) + + for l, _ in p: + topk_wavs.append(w) + topk_langs.append(l) + + if args.refs is not None: + refs_filt.append(refs[i]) + if args.langs is not None: + langs_filt.append(langs[i]) + if args.confs is not None: + confs_filt.append(confs[i]) + + lang_split = defaultdict(list) + for id, (wav,lid) in enumerate(zip(topk_wavs, topk_langs)): + lang_split[lid].append((id, wav)) + + for lang in tqdm(lang_split.keys()): + if not os.path.exists(args.dst + "/" + lang): + os.makedirs(args.dst + "/" + lang) + + with open(args.dst + "/" + lang + "/test.tsv", "w") as f1, \ + open(args.dst + "/" + lang + "/ids.txt", "w") as f2: + f1.write(root) + f1.writelines([x[1] for x in lang_split[lang]]) + f2.writelines([str(x[0]) + "\n" for x in lang_split[lang]]) + + with open(args.dst + "/" + lang + "/test.ltr", "w") as fw: + fw.write("d u m m y | d u m m y |\n"*len(lang_split[lang])) + with open(args.dst + "/" + lang + "/test.wrd", "w") as fw: + fw.write("dummy dummy\n"*len(lang_split[lang])) + + with open(args.dst + "/lid.txt", "w") as f: + f.writelines([x+"\n" for x in topk_langs]) + + if args.refs is not None: + with open(args.dst + "/refs.txt", "w") as f: + f.writelines([x+"\n" for x in refs_filt]) + if args.langs is not None: + with open(args.dst + "/langs.txt", "w") as f: + f.writelines([x+"\n" for x in langs_filt]) + if args.confs is not None: + with open(args.dst + "/confs.txt", "w") as f: + f.writelines([x+"\n" for x in confs_filt]) \ No newline at end of file diff --git a/examples/mms/lid_rerank/nllb/infer.py b/examples/mms/lid_rerank/nllb/infer.py new file mode 100755 index 0000000000..1f4d69a907 --- /dev/null +++ b/examples/mms/lid_rerank/nllb/infer.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# -*- encoding: utf8 -*- +import fasttext +from tqdm import tqdm +import argparse +import os +import math + +parser = argparse.ArgumentParser() +parser.add_argument("--txt", type=str) +parser.add_argument("--dst", type=str) +parser.add_argument("--model", type=str) +parser.add_argument('--lid', type=str) +args = parser.parse_args() + +mapping = {"arb":"ara", "azj":"aze", "pes":"fas", "fuv":"ful", "lvs":"lav", "khk":"mon", "zsm":"zlm", "gaz":"orm", "pbt":"pus", "uzn":"uzb", "zho":"cmn"} + +def fix_code(x): + code = x.split("_")[-2] + if code in mapping: + code = mapping[code] + return code + +if __name__ == "__main__": + if not os.path.exists(args.dst): + os.makedirs(args.dst) + + pretrained_lang_model = args.model + model = fasttext.load_model(pretrained_lang_model) + + txts = [x.strip() for x in open(args.txt, "r").readlines()] + lids = [x.strip() for x in open(args.lid, "r").readlines()] + assert len(txts) == len(lids) + + with open(args.dst + "/wlid_score", "w") as f: + for t,l in tqdm(zip(txts, lids)): + predictions = model.predict(t, k=218) # max 218 + predictions = [(fix_code(x), y) for x, y in zip(predictions[0], predictions[1])] + + try: + pred_langs = [x[0] for x in predictions] + idx = pred_langs.index(l) + score = math.log(predictions[idx][-1]) + except: + score = -1000 + f.write(str(score) + "\n") \ No newline at end of file diff --git a/examples/mms/lid_rerank/requirements.txt b/examples/mms/lid_rerank/requirements.txt new file mode 100644 index 0000000000..459c37ee20 --- /dev/null +++ b/examples/mms/lid_rerank/requirements.txt @@ -0,0 +1,10 @@ +transformers +peft +protobuf +blobfile +sentencepiece +fasttext +numpy<=1.26.4 +librosa +ninja +editdistance \ No newline at end of file diff --git a/examples/mms/lid_rerank/rerank/rerank.py b/examples/mms/lid_rerank/rerank/rerank.py new file mode 100755 index 0000000000..beea3e6a77 --- /dev/null +++ b/examples/mms/lid_rerank/rerank/rerank.py @@ -0,0 +1,132 @@ +import argparse +import json +from collections import defaultdict +import os +from tqdm import tqdm +import sys +import subprocess +import re +import math +import numpy as np +import editdistance +from sklearn.preprocessing import StandardScaler +from multiprocessing import Pool +from functools import partial +import random + +cer_langs = [x.strip() for x in open("cer_langs.txt", "r").readlines()] + +def select(w, feats, ref_lid, nbest_lid, ref_asr, nbest_asr, n=10, exclude=None): + assert len(w) == len(feats[0]) + scores = [] + for f in feats: + s = 0 + for i in range(len(w)): + s += w[i]*f[i] + scores.append(s) + + lid_correct = 0 + lid_total = 0 + asr_err = 0 + asr_total = 0 + text = [] + lang = [] + + for i in range(len(ref_lid)): + if exclude is not None: + if ref_lid[i] in exclude: + continue + + start_idx = i * n + end_idx = start_idx + n + cand_scores = scores[start_idx:end_idx] + max_idx, max_val = max(enumerate(cand_scores), key=lambda x: x[1]) + + cand_feats = feats[start_idx:end_idx] + + lang.append(nbest_lid[start_idx:end_idx][max_idx]) + if ref_lid[i] == nbest_lid[start_idx:end_idx][max_idx]: + lid_correct += 1 + lid_total += 1 + + hyp = nbest_asr[start_idx:end_idx][max_idx] + text.append(hyp) + ref = ref_asr[i] + hyp = hyp.lower() + ref = ref.lower() + hyp = hyp.replace(".", "").replace(",", "").replace("?", "").replace("!", "").replace(":", "").replace(")", "").replace("(", "").replace("-", "") + ref = ref.replace(".", "").replace(",", "").replace("?", "").replace("!", "").replace(":", "").replace(")", "").replace("(", "").replace("-", "") + if ref_lid[i] in cer_langs: + hyp = " ".join(hyp) + ref = " ".join(ref) + + hyp_words = hyp.split() + tgt_words = ref.split() + errs = editdistance.eval(hyp_words, tgt_words) + asr_err += errs + asr_total += len(tgt_words) + + results = {"lid_acc": lid_correct / lid_total, "asr_wer": asr_err / asr_total, "weights": w} + + return results, text, lang + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Example argument parser') + parser.add_argument('--slid', type=str) + parser.add_argument('--wlid', type=str) + parser.add_argument('--asr', type=str) + parser.add_argument('--lm', type=str) + parser.add_argument('--uasr', type=str) + parser.add_argument('--n', type=int, default=10) + parser.add_argument('--dst', type=str) + parser.add_argument('--ref_lid', type=str) + parser.add_argument('--nbest_lid', type=str) + parser.add_argument('--ref_asr', type=str) + parser.add_argument('--nbest_asr', type=str) + parser.add_argument('--w', type=str) + parser.add_argument('--tag', type=str, default = None) + parser.add_argument('--exclude', nargs="*", default=None) # exclude langs + args = parser.parse_args() + + slid = [float(x.strip()) for x in open(args.slid, "r").readlines()] + wlid = [float(x.strip()) for x in open(args.wlid, "r").readlines()] + asr = [float(x.strip()) for x in open(args.asr, "r").readlines()] + lm = [float(x.strip()) for x in open(args.lm, "r").readlines()] + uasr = [float(x.strip()) for x in open(args.uasr, "r").readlines()] + + assert len(slid) == len(wlid) + assert len(wlid) == len(asr) + assert len(asr) == len(lm) + assert len(lm) == len(uasr) + + ref_lid = [x.strip() for x in open(args.ref_lid, "r").readlines()] + nbest_lid= [x.strip() for x in open(args.nbest_lid, "r").readlines()] + ref_asr = [x.strip() for x in open(args.ref_asr, "r").readlines()] + nbest_asr = [x.strip() for x in open(args.nbest_asr, "r").readlines()] + + assert len(ref_lid) * args.n == len(nbest_lid) + assert len(ref_asr) * args.n == len(nbest_asr) + assert len(ref_lid) == len(ref_asr) + + lengths = [len(x) for x in nbest_asr] + + feats = [[s, w, a, l, u, le] for s,w,a,l,u,le in zip(slid, wlid, asr, lm, uasr, lengths)] + + weight = eval(open(args.w, "r").read())['weights'] + + results, text, lang = select(weight, feats, ref_lid, nbest_lid, ref_asr, nbest_asr, n=args.n, exclude=args.exclude) + + if args.tag is not None: + tag_text = "." + args.tag + else: + tag_text = "" + + with open(args.dst + "/reranked_1best_asr_hyp" + tag_text, "w") as f_out: + f_out.writelines([x+"\n" for x in text]) + + with open(args.dst + "/reranked_1best_lid" + tag_text, "w") as f_out: + f_out.writelines([x+"\n" for x in lang]) + + with open(args.dst + "/text.result" + tag_text, "w") as f_out: + for k in results.keys(): + f_out.write(k + "\t" + str(results[k]) + "\n") diff --git a/examples/mms/lid_rerank/rerank/tune_coefficients.py b/examples/mms/lid_rerank/rerank/tune_coefficients.py new file mode 100755 index 0000000000..fc15f650a7 --- /dev/null +++ b/examples/mms/lid_rerank/rerank/tune_coefficients.py @@ -0,0 +1,138 @@ +import argparse +import os +from tqdm import tqdm +import numpy as np +import editdistance +from multiprocessing import Pool +from functools import partial + +cer_langs = [x.strip() for x in open("cer_langs.txt", "r").readlines()] + +def compute(w, feats, ref_lid, nbest_lid, ref_asr, nbest_asr, n=10, exclude=None): + assert len(w) == len(feats[0]) + scores = [] + for f in feats: + s = 0 + for i in range(len(w)): + s += w[i]*f[i] + scores.append(s) + + lid_correct = 0 + lid_total = 0 + asr_err = 0 + asr_total = 0 + + for i in range(len(ref_lid)): + if exclude is not None: + if ref_lid[i] in exclude: + continue + + start_idx = i * n + end_idx = start_idx + n + cand_scores = scores[start_idx:end_idx] + max_idx, max_val = max(enumerate(cand_scores), key=lambda x: x[1]) + + if ref_lid[i] == nbest_lid[start_idx:end_idx][max_idx]: + lid_correct += 1 + lid_total += 1 + + hyp = nbest_asr[start_idx:end_idx][max_idx] + ref = ref_asr[i] + hyp = hyp.lower() + ref = ref.lower() + hyp = hyp.replace(".", "").replace(",", "").replace("?", "").replace("!", "").replace(":", "").replace(")", "").replace("(", "").replace("-", "") + ref = ref.replace(".", "").replace(",", "").replace("?", "").replace("!", "").replace(":", "").replace(")", "").replace("(", "").replace("-", "") + if ref_lid[i] in cer_langs: + hyp = " ".join(hyp) + ref = " ".join(ref) + + hyp_words = hyp.split() + tgt_words = ref.split() + errs = editdistance.eval(hyp_words, tgt_words) + asr_err += errs + asr_total += len(tgt_words) + + return {"lid_acc": lid_correct / lid_total, "asr_wer": asr_err / asr_total, "weights": w} + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Example argument parser') + parser.add_argument('--slid', type=str) + parser.add_argument('--wlid', type=str) + parser.add_argument('--asr', type=str) + parser.add_argument('--lm', type=str) + parser.add_argument('--uasr', type=str) + parser.add_argument('--n', type=int, default=10) + parser.add_argument('--dst', type=str) + parser.add_argument('--ref_lid', type=str) + parser.add_argument('--nbest_lid', type=str) + parser.add_argument('--ref_asr', type=str) + parser.add_argument('--nbest_asr', type=str) + parser.add_argument('--iters', type=int, default=10000) + parser.add_argument('--slid_scale', type=int, default = 100) + parser.add_argument('--wlid_scale', type=int, default = 100) + parser.add_argument('--asr_scale', type=int, default = 10) + parser.add_argument('--lm_scale', type=int, default = 10) + parser.add_argument('--uasr_scale', type=int, default = 10) + parser.add_argument('--len_scale', type=int, default = 1) + parser.add_argument('--num_jobs', type=int, default = 64) + parser.add_argument('--exclude', nargs="*", default=None) # exclude langs + args = parser.parse_args() + + slid = [float(x.strip()) for x in open(args.slid, "r").readlines()] + wlid = [float(x.strip()) for x in open(args.wlid, "r").readlines()] + asr = [float(x.strip()) for x in open(args.asr, "r").readlines()] + lm = [float(x.strip()) for x in open(args.lm, "r").readlines()] + uasr = [float(x.strip()) for x in open(args.uasr, "r").readlines()] + + assert len(slid) == len(wlid) + assert len(wlid) == len(asr) + assert len(asr) == len(lm) + assert len(lm) == len(uasr) + + ref_lid = [x.strip() for x in open(args.ref_lid, "r").readlines()] + nbest_lid= [x.strip() for x in open(args.nbest_lid, "r").readlines()] + ref_asr = [x.strip() for x in open(args.ref_asr, "r").readlines()] + nbest_asr = [x.strip() for x in open(args.nbest_asr, "r").readlines()] + + assert len(ref_lid) * args.n == len(nbest_lid) + assert len(ref_asr) * args.n == len(nbest_asr) + assert len(ref_lid) == len(ref_asr) + + lengths = [len(x) for x in nbest_asr] + + feats = [[s, w, a, l, u, le] for s,w,a,l,u,le in zip(slid, wlid, asr, lm, uasr, lengths)] + + weights = [] + for i in range(args.iters): + s_w = np.random.rand() * args.slid_scale + w_w = np.random.rand() * args.wlid_scale + a_w = np.random.rand() * args.asr_scale + l_w = np.random.rand() * args.lm_scale + u_w = np.random.rand() * args.uasr_scale + le_w = (np.random.rand() -0.5) * args.len_scale + weights.append([s_w, w_w, a_w, l_w, u_w, le_w]) + + num_tries = len(weights) + print("Total number of search points", num_tries) + threads = args.num_jobs + pool = Pool(threads) + compute_fxn = partial(compute, feats=feats, ref_lid=ref_asr, nbest_lid=nbest_lid, ref_asr=ref_asr, nbest_asr=nbest_asr, n=args.n, exclude=args.exclude) + results = pool.map(compute_fxn, weights) + pool.close() + pool.join() + + assert len(results) == len(weights) + + wer_best = 100 + best = "" + if not os.path.exists(args.dst): + os.makedirs(args.dst) + with open(args.dst + "/results.all", "w") as f_out: + for result in results: + f_out.write(str(result)+"\n") + if result["asr_wer"] < wer_best: + wer_best = result["asr_wer"] + best = result + + with open(args.dst + "/best_coefficients", "w") as f_out: + f_out.write(str(best)+"\n") \ No newline at end of file diff --git a/examples/mms/lid_rerank/whisper/infer_asr.py b/examples/mms/lid_rerank/whisper/infer_asr.py new file mode 100755 index 0000000000..0df16d0e45 --- /dev/null +++ b/examples/mms/lid_rerank/whisper/infer_asr.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# -*- encoding: utf8 -*- +import argparse +import itertools +import os +import re +import sys +from pathlib import Path + +import whisper +from tqdm import tqdm + + +parser = argparse.ArgumentParser() +parser.add_argument("--wavs", type=str) +parser.add_argument("--lids", type=str) +parser.add_argument("--dst", type=str) +parser.add_argument("--beam_size", type=int, default=1) +parser.add_argument("--model", type=str) +parser.add_argument("--mapping", type=str, default="whisper/lid_mapping.txt") +parser.add_argument("--n", type=int, default=10) + +args = parser.parse_args() + +if __name__ == "__main__": + model = whisper.load_model(args.model) + + print(args) + + wavs = [y for y in [x.strip() for x in open(args.wavs, "r").readlines()] for _ in range(args.n)] + lids = [x.strip() for x in open(args.lids, "r").readlines()] + assert len(wavs) == len(lids) + + if args.mapping is not None: + # mms_lid_code:whisper_lid_code + mapping = {x[1]:x[0] for x in [l.strip().split(";", 1) for l in open(args.mapping, "r").readlines()]} + else: + mapping = None + + if not os.path.exists(args.dst): + os.makedirs(args.dst) + + # clear it + with open(args.dst + "/nbest_asr_hyp", "w") as f1, open(args.dst + "/asr_score", "w") as f2: + pass + + for wav, lang in tqdm(zip(wavs, lids)): + # load audio and pad/trim it to fit 30 seconds + audio = whisper.load_audio(wav) + audio = whisper.pad_or_trim(audio) + + # make log-Mel spectrogram and move to the same device as the model + mel = whisper.log_mel_spectrogram(audio).to(model.device) + + if mapping is not None and lang in mapping.keys(): + lang_code = mapping[lang] + else: + lang_code = lang + + # decode the audio + options = whisper.DecodingOptions(beam_size=args.beam_size, language=lang_code) + output = whisper.decode(model, mel, options) + result = output.text + length = len(output.tokens) + score = output.avg_logprob * length + + with open(args.dst + "/nbest_asr_hyp", "a") as f1, open(args.dst + "/asr_score", "a") as f2: + f1.write(result + "\n") + f2.write(str(score) + "\n") + f1.flush() + f2.flush() \ No newline at end of file diff --git a/examples/mms/lid_rerank/whisper/infer_lid.py b/examples/mms/lid_rerank/whisper/infer_lid.py new file mode 100755 index 0000000000..150e0bbcca --- /dev/null +++ b/examples/mms/lid_rerank/whisper/infer_lid.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# -*- encoding: utf8 -*- +import argparse +import itertools +import os +import re +import sys +from pathlib import Path +import math + +import whisper +from tqdm import tqdm + + +parser = argparse.ArgumentParser() +parser.add_argument("--wavs", type=str) +parser.add_argument("--dst", type=str) +parser.add_argument("--model", type=str) +parser.add_argument("--n", type=int, default=10) +parser.add_argument("--mapping", type=str, default="whisper/lid_mapping.txt") +args = parser.parse_args() + +if __name__ == "__main__": + model = whisper.load_model(args.model) + + print(args) + + wavs = [x.strip() for x in open(args.wavs, "r").readlines()] + if not os.path.exists(args.dst): + os.makedirs(args.dst) + + if args.mapping is not None: + #whisper_lid_code:mms_lid_code + mapping = {x[0]:x[1] for x in [l.strip().split(";", 1) for l in open(args.mapping, "r").readlines()]} + else: + mapping = None + + with open(args.dst + "/predictions", "w") as f: + for wav in tqdm(wavs): + # load audio and pad/trim it to fit 30 seconds + audio = whisper.load_audio(wav) + audio = whisper.pad_or_trim(audio) + + # make log-Mel spectrogram and move to the same device as the model + mel = whisper.log_mel_spectrogram(audio).to(model.device) + + _, probs = model.detect_language(mel) + result = sorted(probs.items(), key=lambda x:x[1], reverse=True)[:args.n] + f.write(str(result) + "\n") + + lid_preds = [eval(x) for x in open(args.dst + "/predictions", "r").readlines()] + lids = [] + scores = [] + for p in lid_preds: + assert len(p) == len(lid_preds[0]) + for l, s in p: + if args.mapping is not None: + lids.append(mapping[l]) + else: + lids.append(l) + scores.append(math.log(s)) + with open(args.dst + "/nbest_lid", "w") as f: + f.writelines([x+"\n" for x in lids]) + with open(args.dst + "/slid_score", "w") as f: + f.writelines([str(x)+"\n" for x in scores]) \ No newline at end of file diff --git a/examples/mms/lid_rerank/whisper/lid_mapping.txt b/examples/mms/lid_rerank/whisper/lid_mapping.txt new file mode 100755 index 0000000000..ea676fece2 --- /dev/null +++ b/examples/mms/lid_rerank/whisper/lid_mapping.txt @@ -0,0 +1,99 @@ +en;eng +zh;cmn +de;deu +es;spa +ru;rus +ko;kor +fr;fra +ja;jpn +pt;por +tr;tuk +pl;pol +ca;cat +nl;nld +ar;ara +sv;swe +it;ita +id;ind +hi;hin +fi;fin +vi;vie +he;heb +uk;ukr +el;ell +ms;zlm +cs;cez +ro;ron +da;dan +hu;hun +ta;tam +no;nob +th;tha +ur;urd +hr;hrv +bg;bul +lt;lit +la;lat +mi;mri +ml;mal +cy;cym +sk;slk +te;tel +fa;fas +lv;lav +bn;ben +sr;srp +az;aze +sl;slv +kn;kan +et;est +mk;mkd +br;bre +eu;eus +is;isl +hy;hye +ne;npi +mn;mon +bs;bos +kk;kaz +sq;sqi +sw;swh +gl;glg +mr;mar +pa;pan +si;sin +km;khm +sn;sna +yo;yor +so;som +af;afr +oc;oci +ka;kat +be;bel +tg;tgk +sd;snd +gu;guj +am;amh +yi;yid +lo;lao +uz;uzb +fo;fao +ht;hat +ps;pus +tk;tuk +nn;nno +mt;mlk +sa;san +lb;ltz +my;mya +bo;bod +tl;tgl +mg;mlg +as;asm +tt;tat +haw;haw +ln;lin +ha;hau +ba;bak +jw;jav +su;sun diff --git a/examples/speech_recognition/new/decoders/viterbi_decoder.py b/examples/speech_recognition/new/decoders/viterbi_decoder.py index b1c47868fa..a35d95e146 100644 --- a/examples/speech_recognition/new/decoders/viterbi_decoder.py +++ b/examples/speech_recognition/new/decoders/viterbi_decoder.py @@ -18,7 +18,7 @@ def decode( emissions: torch.FloatTensor, ) -> List[List[Dict[str, torch.LongTensor]]]: def get_pred(e): + score = e.log_softmax(dim=-1).max(dim=-1)[0].sum() toks = e.argmax(dim=-1).unique_consecutive() - return toks[toks != self.blank] - - return [[{"tokens": get_pred(x), "score": 0}] for x in emissions] + return {"tokens":toks[toks != self.blank], "score":score} + return [[get_pred(x)] for x in emissions] diff --git a/examples/speech_recognition/new/infer.py b/examples/speech_recognition/new/infer.py index 33ed526907..ca5cea4a7c 100644 --- a/examples/speech_recognition/new/infer.py +++ b/examples/speech_recognition/new/infer.py @@ -144,6 +144,7 @@ def __init__(self, cfg: InferConfig) -> None: self.hypo_units_file = None self.ref_words_file = None self.ref_units_file = None + self.score_file = None self.progress_bar = self.build_progress_bar() @@ -153,6 +154,7 @@ def __enter__(self) -> "InferenceProcessor": self.hypo_units_file = self.get_res_file("hypo.units") self.ref_words_file = self.get_res_file("ref.word") self.ref_units_file = self.get_res_file("ref.units") + self.score_file = self.get_res_file("asr_score") return self def __exit__(self, *exc) -> bool: @@ -161,6 +163,7 @@ def __exit__(self, *exc) -> bool: self.hypo_units_file.close() self.ref_words_file.close() self.ref_units_file.close() + self.score_file.close() return False def __iter__(self) -> Any: @@ -290,7 +293,6 @@ def process_sentence( batch_id: int, ) -> Tuple[int, int]: speaker = None # Speaker can't be parsed from dataset. - if "target_label" in sample: toks = sample["target_label"] else: @@ -314,6 +316,7 @@ def process_sentence( print(f"{hyp_words} ({speaker}-{sid})", file=self.hypo_words_file) print(f"{tgt_pieces} ({speaker}-{sid})", file=self.ref_units_file) print(f"{tgt_words} ({speaker}-{sid})", file=self.ref_words_file) + print(f"{hypo['score'].item()} ({speaker}-{sid})", file=self.score_file) if not self.cfg.common_eval.quiet: logger.info(f"HYPO: {hyp_words}") From 018621f3cca02ca9de945dc082c3fb1a7f9f2deb Mon Sep 17 00:00:00 2001 From: Brian Yan <brianyan918@gmail.com> Date: Thu, 3 Oct 2024 08:50:44 -0700 Subject: [PATCH 773/774] update paper link + bug fix (#5547) --- examples/mms/lid_rerank/README.md | 4 ++-- examples/mms/lid_rerank/mms/prep_wav_list.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/mms/lid_rerank/README.md b/examples/mms/lid_rerank/README.md index 3fa599f08a..977f15de13 100644 --- a/examples/mms/lid_rerank/README.md +++ b/examples/mms/lid_rerank/README.md @@ -3,7 +3,7 @@ This project provides N-best re-ranking, a simple inference procedure, for impro The workflow is as follows: 1) run LID+ASR inference (MMS and Whisper are supported), 2) compute external re-ranking features, 3) tune feature coefficients on dev set, and 4) apply on test set. -For more information about our method, please refer to the paper: "Improving Multilingual ASR in the Wild Using Simple N-best Re-ranking". +For more information about our method, please refer to the paper: ["Improving Multilingual ASR in the Wild Using Simple N-best Re-ranking"](https://arxiv.org/abs/2409.18428). ## 1) Commands to Run LID+ASR Inference @@ -112,4 +112,4 @@ The re-ranked LID and ASR will be in `"path/to/rerank/results"/reranked_1best_li journal={arXiv}, year={2024} } -``` \ No newline at end of file +``` diff --git a/examples/mms/lid_rerank/mms/prep_wav_list.py b/examples/mms/lid_rerank/mms/prep_wav_list.py index 725274fcbe..455ee25ec0 100755 --- a/examples/mms/lid_rerank/mms/prep_wav_list.py +++ b/examples/mms/lid_rerank/mms/prep_wav_list.py @@ -4,6 +4,7 @@ if __name__ == "__main__": parser = argparse.ArgumentParser(description='Example argument parser') parser.add_argument('--src', type=str) + parser.add_argument('--dst', type=str) args = parser.parse_args() wavs = [x.strip() for x in open(args.src, "r").readlines()] From ecbf110e1eb43861214b05fa001eff584954f65a Mon Sep 17 00:00:00 2001 From: "Yun Wang (Maigo)" <yunwang@meta.com> Date: Fri, 18 Oct 2024 09:40:02 -0700 Subject: [PATCH 774/774] Add an `auto_expand` option to `SinusoidalPositionalEmbedding` (#5555) --- fairseq/modules/positional_embedding.py | 2 ++ .../sinusoidal_positional_embedding.py | 35 ++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/fairseq/modules/positional_embedding.py b/fairseq/modules/positional_embedding.py index 97cd474b51..fbc13d80ac 100644 --- a/fairseq/modules/positional_embedding.py +++ b/fairseq/modules/positional_embedding.py @@ -14,6 +14,7 @@ def PositionalEmbedding( embedding_dim: int, padding_idx: int, learned: bool = False, + auto_expand: bool = True, ): if learned: # if padding_idx is specified then offset the embedding ids by @@ -31,5 +32,6 @@ def PositionalEmbedding( embedding_dim, padding_idx, init_size=num_embeddings + padding_idx + 1, + auto_expand=auto_expand, ) return m diff --git a/fairseq/modules/sinusoidal_positional_embedding.py b/fairseq/modules/sinusoidal_positional_embedding.py index e7ecd0f2c8..dd93ddc397 100644 --- a/fairseq/modules/sinusoidal_positional_embedding.py +++ b/fairseq/modules/sinusoidal_positional_embedding.py @@ -18,14 +18,19 @@ class SinusoidalPositionalEmbedding(nn.Module): Padding symbols are ignored. """ - def __init__(self, embedding_dim, padding_idx, init_size=1024): + def __init__(self, embedding_dim, padding_idx, init_size=1024, auto_expand=True): super().__init__() self.embedding_dim = embedding_dim self.padding_idx = padding_idx if padding_idx is not None else 0 - self.register_buffer("weights", SinusoidalPositionalEmbedding.get_embedding( - init_size, embedding_dim, padding_idx - ), persistent=False) + self.register_buffer( + "weights", + SinusoidalPositionalEmbedding.get_embedding( + init_size, embedding_dim, padding_idx + ), + persistent=False, + ) self.max_positions = int(1e5) + self.auto_expand = auto_expand self.onnx_trace = False def prepare_for_onnx_export_(self): @@ -75,28 +80,36 @@ def forward( bspair = torch.onnx.operators.shape_as_tensor(input) bsz, seq_len = bspair[0], bspair[1] max_pos = self.padding_idx + 1 + seq_len + weights = self.weights + if max_pos > self.weights.size(0): - # expand embeddings if needed - self.weights = SinusoidalPositionalEmbedding.get_embedding( + # If the input is longer than the number of pre-computed embeddings, + # compute the extra embeddings on the fly. + # Only store the expanded embeddings if auto_expand=True. + # In multithreading environments, mutating the weights of a module + # may cause trouble. Set auto_expand=False if this happens. + weights = SinusoidalPositionalEmbedding.get_embedding( max_pos, self.embedding_dim, self.padding_idx ).to(self.weights) + if self.auto_expand: + self.weights = weights if incremental_state is not None: # positions is the same for every token when decoding a single step pos = timestep.view(-1)[0] + 1 if timestep is not None else seq_len if self.onnx_trace: return ( - self.weights.index_select(index=self.padding_idx + pos, dim=0) + weights.index_select(index=self.padding_idx + pos, dim=0) .unsqueeze(1) .repeat(bsz, 1, 1) ) - return self.weights[self.padding_idx + pos, :].expand(bsz, 1, -1) + return weights[self.padding_idx + pos, :].expand(bsz, 1, -1) positions = utils.make_positions( input, self.padding_idx, onnx_trace=self.onnx_trace ) if self.onnx_trace: - flat_embeddings = self.weights.detach().index_select(0, positions.view(-1)) + flat_embeddings = weights.detach().index_select(0, positions.view(-1)) embedding_shape = torch.cat( (bsz.view(1), seq_len.view(1), torch.tensor([-1], dtype=torch.long)) ) @@ -105,7 +118,5 @@ def forward( ) return embeddings return ( - self.weights.index_select(0, positions.view(-1)) - .view(bsz, seq_len, -1) - .detach() + weights.index_select(0, positions.view(-1)).view(bsz, seq_len, -1).detach() )